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 <string> 24 #include <type_traits> 25 #include <utility> 26 #include <vector> 27 28 #include <android-base/logging.h> 29 30 #include "fdevent/fdevent.h" 31 #include "sysdeps/uio.h" 32 33 // Essentially std::vector<char>, except without zero initialization or reallocation. 34 // Features a position attribute to allow sequential read/writes for copying between Blocks. 35 struct Block { 36 using iterator = char*; 37 38 Block() = default; 39 BlockBlock40 explicit Block(size_t size) { allocate(size); } 41 BlockBlock42 explicit Block(const std::string& s) : Block(s.begin(), s.end()) {} 43 44 template <typename Iterator> BlockBlock45 Block(Iterator begin, Iterator end) : Block(end - begin) { 46 std::copy(begin, end, data_.get()); 47 } 48 49 Block(const Block& copy) = delete; BlockBlock50 Block(Block&& move) noexcept 51 : data_(std::exchange(move.data_, nullptr)), 52 capacity_(std::exchange(move.capacity_, 0)), 53 size_(std::exchange(move.size_, 0)), 54 position_(std::exchange(move.position_, 0)) {} 55 56 Block& operator=(const Block& copy) = delete; 57 Block& operator=(Block&& move) noexcept { 58 clear(); 59 data_ = std::exchange(move.data_, nullptr); 60 capacity_ = std::exchange(move.capacity_, 0); 61 size_ = std::exchange(move.size_, 0); 62 position_ = std::exchange(move.size_, 0); 63 return *this; 64 } 65 66 ~Block() = default; 67 resizeBlock68 void resize(size_t new_size) { 69 if (!data_) { 70 allocate(new_size); 71 } else { 72 CHECK_GE(capacity_, new_size); 73 size_ = new_size; 74 } 75 } 76 77 template <typename InputIt> assignBlock78 void assign(InputIt begin, InputIt end) { 79 clear(); 80 allocate(end - begin); 81 std::copy(begin, end, data_.get()); 82 } 83 clearBlock84 void clear() { 85 data_.reset(); 86 capacity_ = 0; 87 size_ = 0; 88 position_ = 0; 89 } 90 is_fullBlock91 bool is_full() const { return remaining() == 0; } 92 remainingBlock93 size_t remaining() const { return size_ - position_; } 94 fillFromBlock95 size_t fillFrom(Block& from) { 96 size_t size = std::min(remaining(), from.remaining()); 97 memcpy(&data_[position_], &from.data_[from.position_], size); 98 position_ += size; 99 from.position_ += size; 100 return size; 101 } 102 rewindBlock103 void rewind() { position_ = 0; } positionBlock104 size_t position() const { return position_; } 105 capacityBlock106 size_t capacity() const { return capacity_; } sizeBlock107 size_t size() const { return size_; } emptyBlock108 bool empty() const { return size() == 0; } 109 dataBlock110 char* data() { return data_.get(); } dataBlock111 const char* data() const { return data_.get(); } 112 beginBlock113 char* begin() { return data_.get(); } beginBlock114 const char* begin() const { return data_.get(); } 115 endBlock116 char* end() { return data() + size_; } endBlock117 const char* end() const { return data() + size_; } 118 119 char& operator[](size_t idx) { return data()[idx]; } 120 const char& operator[](size_t idx) const { return data()[idx]; } 121 122 bool operator==(const Block& rhs) const { 123 static_assert(std::is_standard_layout<decltype(data())>()); 124 return size() == rhs.size() && memcmp(data(), rhs.data(), size()) == 0; 125 } 126 127 private: allocateBlock128 void allocate(size_t size) { 129 CHECK(data_ == nullptr); 130 CHECK_EQ(0ULL, capacity_); 131 CHECK_EQ(0ULL, size_); 132 if (size != 0) { 133 // This isn't std::make_unique because that's equivalent to `new char[size]()`, which 134 // value-initializes the array instead of leaving it uninitialized. As an optimization, 135 // call new without parentheses to avoid this costly initialization. 136 data_.reset(new char[size]); 137 capacity_ = size; 138 size_ = size; 139 } 140 } 141 142 std::unique_ptr<char[]> data_; 143 size_t capacity_ = 0; 144 size_t size_ = 0; 145 size_t position_ = 0; 146 }; 147 148 struct amessage { 149 uint32_t command; /* command identifier constant */ 150 uint32_t arg0; /* first argument */ 151 uint32_t arg1; /* second argument */ 152 uint32_t data_length; /* length of payload (0 is allowed) */ 153 uint32_t data_check; /* checksum of data payload */ 154 uint32_t magic; /* command ^ 0xffffffff */ 155 }; 156 157 struct apacket { 158 using payload_type = Block; 159 amessage msg; 160 payload_type payload; 161 }; 162 163 struct IOVector { 164 using value_type = char; 165 using block_type = Block; 166 using size_type = size_t; 167 168 IOVector() = default; 169 IOVectorIOVector170 explicit IOVector(block_type&& block) { append(std::move(block)); } 171 172 IOVector(const IOVector& copy) = delete; IOVectorIOVector173 IOVector(IOVector&& move) noexcept : IOVector() { *this = std::move(move); } 174 175 IOVector& operator=(const IOVector& copy) = delete; 176 IOVector& operator=(IOVector&& move) noexcept; 177 front_dataIOVector178 const value_type* front_data() const { 179 if (chain_.empty()) { 180 return nullptr; 181 } 182 183 return chain_[start_index_].data() + begin_offset_; 184 } 185 front_sizeIOVector186 size_type front_size() const { 187 if (chain_.empty()) { 188 return 0; 189 } 190 191 return chain_[start_index_].size() - begin_offset_; 192 } 193 sizeIOVector194 size_type size() const { return chain_length_ - begin_offset_; } emptyIOVector195 bool empty() const { return size() == 0; } 196 197 // Return the last block so the caller can still reuse its allocated capacity 198 // or it can be simply ignored. 199 block_type clear(); 200 201 void drop_front(size_type len); 202 203 // Split the first |len| bytes out of this chain into its own. 204 IOVector take_front(size_type len); 205 206 // Add a nonempty block to the chain. appendIOVector207 void append(block_type&& block) { 208 if (block.size() == 0) { 209 return; 210 } 211 CHECK_NE(0ULL, block.size()); 212 chain_length_ += block.size(); 213 chain_.emplace_back(std::move(block)); 214 } 215 216 void trim_front(); 217 218 private: 219 void trim_chain_front(); 220 221 // Drop the front block from the chain, and update chain_length_ appropriately. 222 void pop_front_block(); 223 224 // Iterate over the blocks with a callback with an operator()(const char*, size_t). 225 template <typename Fn> iterate_blocksIOVector226 void iterate_blocks(Fn&& callback) const { 227 if (size() == 0) { 228 return; 229 } 230 231 for (size_t i = start_index_; i < chain_.size(); ++i) { 232 const auto& block = chain_[i]; 233 const char* begin = block.data(); 234 size_t length = block.size(); 235 236 if (i == start_index_) { 237 CHECK_GE(block.size(), begin_offset_); 238 begin += begin_offset_; 239 length -= begin_offset_; 240 } 241 callback(begin, length); 242 } 243 } 244 245 public: 246 // Copy all of the blocks into a single block. 247 template <typename CollectionType = block_type> coalesceIOVector248 CollectionType coalesce() const& { 249 CollectionType result; 250 if (size() == 0) { 251 return result; 252 } 253 254 result.resize(size()); 255 256 size_t offset = 0; 257 iterate_blocks([&offset, &result](const char* data, size_t len) { 258 static_assert(std::is_standard_layout<decltype(result)>()); 259 memcpy(&result[offset], data, len); 260 offset += len; 261 }); 262 263 return result; 264 } 265 266 block_type coalesce() &&; 267 268 template <typename FunctionType> coalescedIOVector269 auto coalesced(FunctionType&& f) const { 270 if (chain_.size() == start_index_ + 1) { 271 // If we only have one block, we can use it directly. 272 return f(chain_[start_index_].data() + begin_offset_, size()); 273 } else { 274 // Otherwise, copy to a single block. 275 auto data = coalesce(); 276 return f(data.data(), data.size()); 277 } 278 } 279 280 // Get a list of iovecs that can be used to write out all of the blocks. 281 std::vector<adb_iovec> iovecs() const; 282 283 private: 284 // Total length of all of the blocks in the chain. 285 size_t chain_length_ = 0; 286 287 size_t begin_offset_ = 0; 288 size_t start_index_ = 0; 289 std::vector<block_type> chain_; 290 }; 291 292 // An implementation of weak pointers tied to the fdevent run loop. 293 // 294 // This allows for code to submit a request for an object, and upon receiving 295 // a response, know whether the object is still alive, or has been destroyed 296 // because of other reasons. We keep a list of living weak_ptrs in each object, 297 // and clear the weak_ptrs when the object is destroyed. This is safe, because 298 // we require that both the destructor of the referent and the get method on 299 // the weak_ptr are executed on the main thread. 300 template <typename T> 301 struct enable_weak_from_this; 302 303 template <typename T> 304 struct weak_ptr { 305 weak_ptr() = default; weak_ptrweak_ptr306 explicit weak_ptr(T* ptr) { reset(ptr); } weak_ptrweak_ptr307 weak_ptr(const weak_ptr& copy) { reset(copy.get()); } 308 weak_ptrweak_ptr309 weak_ptr(weak_ptr&& move) { 310 reset(move.get()); 311 move.reset(); 312 } 313 ~weak_ptrweak_ptr314 ~weak_ptr() { reset(); } 315 316 weak_ptr& operator=(const weak_ptr& copy) { 317 if (© == this) { 318 return *this; 319 } 320 321 reset(copy.get()); 322 return *this; 323 } 324 325 weak_ptr& operator=(weak_ptr&& move) { 326 if (&move == this) { 327 return *this; 328 } 329 330 reset(move.get()); 331 move.reset(); 332 return *this; 333 } 334 getweak_ptr335 T* get() const { 336 fdevent_check_looper(); 337 return ptr_; 338 } 339 340 void reset(T* ptr = nullptr) { 341 fdevent_check_looper(); 342 343 if (ptr == ptr_) { 344 return; 345 } 346 347 if (ptr_) { 348 ptr_->weak_ptrs_.erase( 349 std::remove(ptr_->weak_ptrs_.begin(), ptr_->weak_ptrs_.end(), this)); 350 } 351 352 ptr_ = ptr; 353 if (ptr_) { 354 ptr_->weak_ptrs_.push_back(this); 355 } 356 } 357 358 private: 359 friend struct enable_weak_from_this<T>; 360 T* ptr_ = nullptr; 361 }; 362 363 template <typename T> 364 struct enable_weak_from_this { 365 ~enable_weak_from_this() { 366 if (!weak_ptrs_.empty()) { 367 fdevent_check_looper(); 368 for (auto& weak : weak_ptrs_) { 369 weak->ptr_ = nullptr; 370 } 371 weak_ptrs_.clear(); 372 } 373 } 374 375 weak_ptr<T> weak() { return weak_ptr<T>(static_cast<T*>(this)); } 376 377 void schedule_deletion() { 378 fdevent_run_on_looper([this]() { delete static_cast<T*>(this); }); 379 } 380 381 private: 382 friend struct weak_ptr<T>; 383 std::vector<weak_ptr<T>*> weak_ptrs_; 384 }; 385