1 /* 2 * Copyright (C) 2018 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #pragma once 18 19 #include <string.h> 20 21 #include <algorithm> 22 #include <memory> 23 #include <utility> 24 #include <vector> 25 26 #include <android-base/logging.h> 27 28 #include "fdevent/fdevent.h" 29 #include "sysdeps/uio.h" 30 31 // Essentially std::vector<char>, except without zero initialization or reallocation. 32 struct Block { 33 using iterator = char*; 34 35 Block() = default; 36 BlockBlock37 explicit Block(size_t size) { allocate(size); } 38 39 template <typename Iterator> BlockBlock40 Block(Iterator begin, Iterator end) : Block(end - begin) { 41 std::copy(begin, end, data_.get()); 42 } 43 44 Block(const Block& copy) = delete; BlockBlock45 Block(Block&& move) noexcept 46 : data_(std::exchange(move.data_, nullptr)), 47 capacity_(std::exchange(move.capacity_, 0)), 48 size_(std::exchange(move.size_, 0)) {} 49 50 Block& operator=(const Block& copy) = delete; 51 Block& operator=(Block&& move) noexcept { 52 clear(); 53 data_ = std::exchange(move.data_, nullptr); 54 capacity_ = std::exchange(move.capacity_, 0); 55 size_ = std::exchange(move.size_, 0); 56 return *this; 57 } 58 59 ~Block() = default; 60 resizeBlock61 void resize(size_t new_size) { 62 if (!data_) { 63 allocate(new_size); 64 } else { 65 CHECK_GE(capacity_, new_size); 66 size_ = new_size; 67 } 68 } 69 70 template <typename InputIt> assignBlock71 void assign(InputIt begin, InputIt end) { 72 clear(); 73 allocate(end - begin); 74 std::copy(begin, end, data_.get()); 75 } 76 clearBlock77 void clear() { 78 data_.reset(); 79 capacity_ = 0; 80 size_ = 0; 81 } 82 capacityBlock83 size_t capacity() const { return capacity_; } sizeBlock84 size_t size() const { return size_; } emptyBlock85 bool empty() const { return size() == 0; } 86 dataBlock87 char* data() { return data_.get(); } dataBlock88 const char* data() const { return data_.get(); } 89 beginBlock90 char* begin() { return data_.get(); } beginBlock91 const char* begin() const { return data_.get(); } 92 endBlock93 char* end() { return data() + size_; } endBlock94 const char* end() const { return data() + size_; } 95 96 char& operator[](size_t idx) { return data()[idx]; } 97 const char& operator[](size_t idx) const { return data()[idx]; } 98 99 bool operator==(const Block& rhs) const { 100 return size() == rhs.size() && memcmp(data(), rhs.data(), size()) == 0; 101 } 102 103 private: allocateBlock104 void allocate(size_t size) { 105 CHECK(data_ == nullptr); 106 CHECK_EQ(0ULL, capacity_); 107 CHECK_EQ(0ULL, size_); 108 if (size != 0) { 109 // This isn't std::make_unique because that's equivalent to `new char[size]()`, which 110 // value-initializes the array instead of leaving it uninitialized. As an optimization, 111 // call new without parentheses to avoid this costly initialization. 112 data_.reset(new char[size]); 113 capacity_ = size; 114 size_ = size; 115 } 116 } 117 118 std::unique_ptr<char[]> data_; 119 size_t capacity_ = 0; 120 size_t size_ = 0; 121 }; 122 123 struct amessage { 124 uint32_t command; /* command identifier constant */ 125 uint32_t arg0; /* first argument */ 126 uint32_t arg1; /* second argument */ 127 uint32_t data_length; /* length of payload (0 is allowed) */ 128 uint32_t data_check; /* checksum of data payload */ 129 uint32_t magic; /* command ^ 0xffffffff */ 130 }; 131 132 struct apacket { 133 using payload_type = Block; 134 amessage msg; 135 payload_type payload; 136 }; 137 138 struct IOVector { 139 using value_type = char; 140 using block_type = Block; 141 using size_type = size_t; 142 143 IOVector() = default; 144 IOVectorIOVector145 explicit IOVector(block_type&& block) { append(std::move(block)); } 146 147 IOVector(const IOVector& copy) = delete; IOVectorIOVector148 IOVector(IOVector&& move) noexcept : IOVector() { *this = std::move(move); } 149 150 IOVector& operator=(const IOVector& copy) = delete; 151 IOVector& operator=(IOVector&& move) noexcept; 152 front_dataIOVector153 const value_type* front_data() const { 154 if (chain_.empty()) { 155 return nullptr; 156 } 157 158 return chain_[start_index_].data() + begin_offset_; 159 } 160 front_sizeIOVector161 size_type front_size() const { 162 if (chain_.empty()) { 163 return 0; 164 } 165 166 return chain_[start_index_].size() - begin_offset_; 167 } 168 sizeIOVector169 size_type size() const { return chain_length_ - begin_offset_; } emptyIOVector170 bool empty() const { return size() == 0; } 171 172 // Return the last block so the caller can still reuse its allocated capacity 173 // or it can be simply ignored. 174 block_type clear(); 175 176 void drop_front(size_type len); 177 178 // Split the first |len| bytes out of this chain into its own. 179 IOVector take_front(size_type len); 180 181 // Add a nonempty block to the chain. appendIOVector182 void append(block_type&& block) { 183 if (block.size() == 0) { 184 return; 185 } 186 CHECK_NE(0ULL, block.size()); 187 chain_length_ += block.size(); 188 chain_.emplace_back(std::move(block)); 189 } 190 191 void trim_front(); 192 193 private: 194 void trim_chain_front(); 195 196 // Drop the front block from the chain, and update chain_length_ appropriately. 197 void pop_front_block(); 198 199 // Iterate over the blocks with a callback with an operator()(const char*, size_t). 200 template <typename Fn> iterate_blocksIOVector201 void iterate_blocks(Fn&& callback) const { 202 if (size() == 0) { 203 return; 204 } 205 206 for (size_t i = start_index_; i < chain_.size(); ++i) { 207 const auto& block = chain_[i]; 208 const char* begin = block.data(); 209 size_t length = block.size(); 210 211 if (i == start_index_) { 212 CHECK_GE(block.size(), begin_offset_); 213 begin += begin_offset_; 214 length -= begin_offset_; 215 } 216 callback(begin, length); 217 } 218 } 219 220 public: 221 // Copy all of the blocks into a single block. 222 template <typename CollectionType = block_type> coalesceIOVector223 CollectionType coalesce() const& { 224 CollectionType result; 225 if (size() == 0) { 226 return result; 227 } 228 229 result.resize(size()); 230 231 size_t offset = 0; 232 iterate_blocks([&offset, &result](const char* data, size_t len) { 233 memcpy(&result[offset], data, len); 234 offset += len; 235 }); 236 237 return result; 238 } 239 240 block_type coalesce() &&; 241 242 template <typename FunctionType> coalescedIOVector243 auto coalesced(FunctionType&& f) const { 244 if (chain_.size() == start_index_ + 1) { 245 // If we only have one block, we can use it directly. 246 return f(chain_[start_index_].data() + begin_offset_, size()); 247 } else { 248 // Otherwise, copy to a single block. 249 auto data = coalesce(); 250 return f(data.data(), data.size()); 251 } 252 } 253 254 // Get a list of iovecs that can be used to write out all of the blocks. 255 std::vector<adb_iovec> iovecs() const; 256 257 private: 258 // Total length of all of the blocks in the chain. 259 size_t chain_length_ = 0; 260 261 size_t begin_offset_ = 0; 262 size_t start_index_ = 0; 263 std::vector<block_type> chain_; 264 }; 265 266 // An implementation of weak pointers tied to the fdevent run loop. 267 // 268 // This allows for code to submit a request for an object, and upon receiving 269 // a response, know whether the object is still alive, or has been destroyed 270 // because of other reasons. We keep a list of living weak_ptrs in each object, 271 // and clear the weak_ptrs when the object is destroyed. This is safe, because 272 // we require that both the destructor of the referent and the get method on 273 // the weak_ptr are executed on the main thread. 274 template <typename T> 275 struct enable_weak_from_this; 276 277 template <typename T> 278 struct weak_ptr { 279 weak_ptr() = default; weak_ptrweak_ptr280 explicit weak_ptr(T* ptr) { reset(ptr); } weak_ptrweak_ptr281 weak_ptr(const weak_ptr& copy) { reset(copy.get()); } 282 weak_ptrweak_ptr283 weak_ptr(weak_ptr&& move) { 284 reset(move.get()); 285 move.reset(); 286 } 287 ~weak_ptrweak_ptr288 ~weak_ptr() { reset(); } 289 290 weak_ptr& operator=(const weak_ptr& copy) { 291 if (© == this) { 292 return *this; 293 } 294 295 reset(copy.get()); 296 return *this; 297 } 298 299 weak_ptr& operator=(weak_ptr&& move) { 300 if (&move == this) { 301 return *this; 302 } 303 304 reset(move.get()); 305 move.reset(); 306 return *this; 307 } 308 getweak_ptr309 T* get() { 310 check_main_thread(); 311 return ptr_; 312 } 313 314 void reset(T* ptr = nullptr) { 315 check_main_thread(); 316 317 if (ptr == ptr_) { 318 return; 319 } 320 321 if (ptr_) { 322 ptr_->weak_ptrs_.erase( 323 std::remove(ptr_->weak_ptrs_.begin(), ptr_->weak_ptrs_.end(), this)); 324 } 325 326 ptr_ = ptr; 327 if (ptr_) { 328 ptr_->weak_ptrs_.push_back(this); 329 } 330 } 331 332 private: 333 friend struct enable_weak_from_this<T>; 334 T* ptr_ = nullptr; 335 }; 336 337 template <typename T> 338 struct enable_weak_from_this { 339 ~enable_weak_from_this() { 340 if (!weak_ptrs_.empty()) { 341 check_main_thread(); 342 for (auto& weak : weak_ptrs_) { 343 weak->ptr_ = nullptr; 344 } 345 weak_ptrs_.clear(); 346 } 347 } 348 349 weak_ptr<T> weak() { return weak_ptr<T>(static_cast<T*>(this)); } 350 351 void schedule_deletion() { 352 fdevent_run_on_main_thread([this]() { delete this; }); 353 } 354 355 private: 356 friend struct weak_ptr<T>; 357 std::vector<weak_ptr<T>*> weak_ptrs_; 358 }; 359