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 <type_traits> 24 #include <utility> 25 #include <vector> 26 27 #include <android-base/logging.h> 28 29 #include "fdevent/fdevent.h" 30 #include "sysdeps/uio.h" 31 32 // Essentially std::vector<char>, except without zero initialization or reallocation. 33 struct Block { 34 using iterator = char*; 35 36 Block() = default; 37 BlockBlock38 explicit Block(size_t size) { allocate(size); } 39 40 template <typename Iterator> BlockBlock41 Block(Iterator begin, Iterator end) : Block(end - begin) { 42 std::copy(begin, end, data_.get()); 43 } 44 45 Block(const Block& copy) = delete; BlockBlock46 Block(Block&& move) noexcept 47 : data_(std::exchange(move.data_, nullptr)), 48 capacity_(std::exchange(move.capacity_, 0)), 49 size_(std::exchange(move.size_, 0)) {} 50 51 Block& operator=(const Block& copy) = delete; 52 Block& operator=(Block&& move) noexcept { 53 clear(); 54 data_ = std::exchange(move.data_, nullptr); 55 capacity_ = std::exchange(move.capacity_, 0); 56 size_ = std::exchange(move.size_, 0); 57 return *this; 58 } 59 60 ~Block() = default; 61 resizeBlock62 void resize(size_t new_size) { 63 if (!data_) { 64 allocate(new_size); 65 } else { 66 CHECK_GE(capacity_, new_size); 67 size_ = new_size; 68 } 69 } 70 71 template <typename InputIt> assignBlock72 void assign(InputIt begin, InputIt end) { 73 clear(); 74 allocate(end - begin); 75 std::copy(begin, end, data_.get()); 76 } 77 clearBlock78 void clear() { 79 data_.reset(); 80 capacity_ = 0; 81 size_ = 0; 82 } 83 capacityBlock84 size_t capacity() const { return capacity_; } sizeBlock85 size_t size() const { return size_; } emptyBlock86 bool empty() const { return size() == 0; } 87 dataBlock88 char* data() { return data_.get(); } dataBlock89 const char* data() const { return data_.get(); } 90 beginBlock91 char* begin() { return data_.get(); } beginBlock92 const char* begin() const { return data_.get(); } 93 endBlock94 char* end() { return data() + size_; } endBlock95 const char* end() const { return data() + size_; } 96 97 char& operator[](size_t idx) { return data()[idx]; } 98 const char& operator[](size_t idx) const { return data()[idx]; } 99 100 bool operator==(const Block& rhs) const { 101 static_assert(std::is_standard_layout<decltype(data())>()); 102 return size() == rhs.size() && memcmp(data(), rhs.data(), size()) == 0; 103 } 104 105 private: allocateBlock106 void allocate(size_t size) { 107 CHECK(data_ == nullptr); 108 CHECK_EQ(0ULL, capacity_); 109 CHECK_EQ(0ULL, size_); 110 if (size != 0) { 111 // This isn't std::make_unique because that's equivalent to `new char[size]()`, which 112 // value-initializes the array instead of leaving it uninitialized. As an optimization, 113 // call new without parentheses to avoid this costly initialization. 114 data_.reset(new char[size]); 115 capacity_ = size; 116 size_ = size; 117 } 118 } 119 120 std::unique_ptr<char[]> data_; 121 size_t capacity_ = 0; 122 size_t size_ = 0; 123 }; 124 125 struct amessage { 126 uint32_t command; /* command identifier constant */ 127 uint32_t arg0; /* first argument */ 128 uint32_t arg1; /* second argument */ 129 uint32_t data_length; /* length of payload (0 is allowed) */ 130 uint32_t data_check; /* checksum of data payload */ 131 uint32_t magic; /* command ^ 0xffffffff */ 132 }; 133 134 struct apacket { 135 using payload_type = Block; 136 amessage msg; 137 payload_type payload; 138 }; 139 140 struct IOVector { 141 using value_type = char; 142 using block_type = Block; 143 using size_type = size_t; 144 145 IOVector() = default; 146 IOVectorIOVector147 explicit IOVector(block_type&& block) { append(std::move(block)); } 148 149 IOVector(const IOVector& copy) = delete; IOVectorIOVector150 IOVector(IOVector&& move) noexcept : IOVector() { *this = std::move(move); } 151 152 IOVector& operator=(const IOVector& copy) = delete; 153 IOVector& operator=(IOVector&& move) noexcept; 154 front_dataIOVector155 const value_type* front_data() const { 156 if (chain_.empty()) { 157 return nullptr; 158 } 159 160 return chain_[start_index_].data() + begin_offset_; 161 } 162 front_sizeIOVector163 size_type front_size() const { 164 if (chain_.empty()) { 165 return 0; 166 } 167 168 return chain_[start_index_].size() - begin_offset_; 169 } 170 sizeIOVector171 size_type size() const { return chain_length_ - begin_offset_; } emptyIOVector172 bool empty() const { return size() == 0; } 173 174 // Return the last block so the caller can still reuse its allocated capacity 175 // or it can be simply ignored. 176 block_type clear(); 177 178 void drop_front(size_type len); 179 180 // Split the first |len| bytes out of this chain into its own. 181 IOVector take_front(size_type len); 182 183 // Add a nonempty block to the chain. appendIOVector184 void append(block_type&& block) { 185 if (block.size() == 0) { 186 return; 187 } 188 CHECK_NE(0ULL, block.size()); 189 chain_length_ += block.size(); 190 chain_.emplace_back(std::move(block)); 191 } 192 193 void trim_front(); 194 195 private: 196 void trim_chain_front(); 197 198 // Drop the front block from the chain, and update chain_length_ appropriately. 199 void pop_front_block(); 200 201 // Iterate over the blocks with a callback with an operator()(const char*, size_t). 202 template <typename Fn> iterate_blocksIOVector203 void iterate_blocks(Fn&& callback) const { 204 if (size() == 0) { 205 return; 206 } 207 208 for (size_t i = start_index_; i < chain_.size(); ++i) { 209 const auto& block = chain_[i]; 210 const char* begin = block.data(); 211 size_t length = block.size(); 212 213 if (i == start_index_) { 214 CHECK_GE(block.size(), begin_offset_); 215 begin += begin_offset_; 216 length -= begin_offset_; 217 } 218 callback(begin, length); 219 } 220 } 221 222 public: 223 // Copy all of the blocks into a single block. 224 template <typename CollectionType = block_type> coalesceIOVector225 CollectionType coalesce() const& { 226 CollectionType result; 227 if (size() == 0) { 228 return result; 229 } 230 231 result.resize(size()); 232 233 size_t offset = 0; 234 iterate_blocks([&offset, &result](const char* data, size_t len) { 235 static_assert(std::is_standard_layout<decltype(result)>()); 236 memcpy(&result[offset], data, len); 237 offset += len; 238 }); 239 240 return result; 241 } 242 243 block_type coalesce() &&; 244 245 template <typename FunctionType> coalescedIOVector246 auto coalesced(FunctionType&& f) const { 247 if (chain_.size() == start_index_ + 1) { 248 // If we only have one block, we can use it directly. 249 return f(chain_[start_index_].data() + begin_offset_, size()); 250 } else { 251 // Otherwise, copy to a single block. 252 auto data = coalesce(); 253 return f(data.data(), data.size()); 254 } 255 } 256 257 // Get a list of iovecs that can be used to write out all of the blocks. 258 std::vector<adb_iovec> iovecs() const; 259 260 private: 261 // Total length of all of the blocks in the chain. 262 size_t chain_length_ = 0; 263 264 size_t begin_offset_ = 0; 265 size_t start_index_ = 0; 266 std::vector<block_type> chain_; 267 }; 268 269 // An implementation of weak pointers tied to the fdevent run loop. 270 // 271 // This allows for code to submit a request for an object, and upon receiving 272 // a response, know whether the object is still alive, or has been destroyed 273 // because of other reasons. We keep a list of living weak_ptrs in each object, 274 // and clear the weak_ptrs when the object is destroyed. This is safe, because 275 // we require that both the destructor of the referent and the get method on 276 // the weak_ptr are executed on the main thread. 277 template <typename T> 278 struct enable_weak_from_this; 279 280 template <typename T> 281 struct weak_ptr { 282 weak_ptr() = default; weak_ptrweak_ptr283 explicit weak_ptr(T* ptr) { reset(ptr); } weak_ptrweak_ptr284 weak_ptr(const weak_ptr& copy) { reset(copy.get()); } 285 weak_ptrweak_ptr286 weak_ptr(weak_ptr&& move) { 287 reset(move.get()); 288 move.reset(); 289 } 290 ~weak_ptrweak_ptr291 ~weak_ptr() { reset(); } 292 293 weak_ptr& operator=(const weak_ptr& copy) { 294 if (© == this) { 295 return *this; 296 } 297 298 reset(copy.get()); 299 return *this; 300 } 301 302 weak_ptr& operator=(weak_ptr&& move) { 303 if (&move == this) { 304 return *this; 305 } 306 307 reset(move.get()); 308 move.reset(); 309 return *this; 310 } 311 getweak_ptr312 T* get() const { 313 fdevent_check_looper(); 314 return ptr_; 315 } 316 317 void reset(T* ptr = nullptr) { 318 fdevent_check_looper(); 319 320 if (ptr == ptr_) { 321 return; 322 } 323 324 if (ptr_) { 325 ptr_->weak_ptrs_.erase( 326 std::remove(ptr_->weak_ptrs_.begin(), ptr_->weak_ptrs_.end(), this)); 327 } 328 329 ptr_ = ptr; 330 if (ptr_) { 331 ptr_->weak_ptrs_.push_back(this); 332 } 333 } 334 335 private: 336 friend struct enable_weak_from_this<T>; 337 T* ptr_ = nullptr; 338 }; 339 340 template <typename T> 341 struct enable_weak_from_this { 342 ~enable_weak_from_this() { 343 if (!weak_ptrs_.empty()) { 344 fdevent_check_looper(); 345 for (auto& weak : weak_ptrs_) { 346 weak->ptr_ = nullptr; 347 } 348 weak_ptrs_.clear(); 349 } 350 } 351 352 weak_ptr<T> weak() { return weak_ptr<T>(static_cast<T*>(this)); } 353 354 void schedule_deletion() { 355 fdevent_run_on_looper([this]() { delete static_cast<T*>(this); }); 356 } 357 358 private: 359 friend struct weak_ptr<T>; 360 std::vector<weak_ptr<T>*> weak_ptrs_; 361 }; 362