blob: cd08ed8b4f4115f633e44ed1c20ac3b516e49c18 [file] [log] [blame]
Josh Gaocd2a5292018-03-07 16:52:28 -08001/*
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
Anatol Pomazau45a25182019-08-08 14:37:59 -070019#include <string.h>
20
Josh Gaocd2a5292018-03-07 16:52:28 -080021#include <algorithm>
Luis Hector Chavezb4edbdf2018-07-18 21:18:27 -070022#include <memory>
Josh Gaocd2a5292018-03-07 16:52:28 -080023#include <utility>
Josh Gao9f155db2018-04-03 14:37:11 -070024#include <vector>
Josh Gaocd2a5292018-03-07 16:52:28 -080025
26#include <android-base/logging.h>
27
Josh Gaoe490fbb2019-12-09 15:44:57 -080028#include "fdevent/fdevent.h"
Josh Gao9f155db2018-04-03 14:37:11 -070029#include "sysdeps/uio.h"
Josh Gaocd2a5292018-03-07 16:52:28 -080030
31// Essentially std::vector<char>, except without zero initialization or reallocation.
32struct Block {
33 using iterator = char*;
34
Yurii Zubrytskyie5e6b0d2019-07-12 14:11:54 -070035 Block() = default;
Josh Gaocd2a5292018-03-07 16:52:28 -080036
37 explicit Block(size_t size) { allocate(size); }
38
39 template <typename Iterator>
40 Block(Iterator begin, Iterator end) : Block(end - begin) {
Luis Hector Chavezb4edbdf2018-07-18 21:18:27 -070041 std::copy(begin, end, data_.get());
Josh Gaocd2a5292018-03-07 16:52:28 -080042 }
43
44 Block(const Block& copy) = delete;
Yurii Zubrytskyie5e6b0d2019-07-12 14:11:54 -070045 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)) {}
Josh Gaocd2a5292018-03-07 16:52:28 -080049
50 Block& operator=(const Block& copy) = delete;
Chih-Hung Hsieh3c99c392018-09-25 11:16:22 -070051 Block& operator=(Block&& move) noexcept {
Josh Gaocd2a5292018-03-07 16:52:28 -080052 clear();
Yurii Zubrytskyie5e6b0d2019-07-12 14:11:54 -070053 data_ = std::exchange(move.data_, nullptr);
54 capacity_ = std::exchange(move.capacity_, 0);
55 size_ = std::exchange(move.size_, 0);
Josh Gaocd2a5292018-03-07 16:52:28 -080056 return *this;
57 }
58
Yurii Zubrytskyie5e6b0d2019-07-12 14:11:54 -070059 ~Block() = default;
Josh Gaocd2a5292018-03-07 16:52:28 -080060
61 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>
71 void assign(InputIt begin, InputIt end) {
72 clear();
73 allocate(end - begin);
Luis Hector Chavezb4edbdf2018-07-18 21:18:27 -070074 std::copy(begin, end, data_.get());
Josh Gaocd2a5292018-03-07 16:52:28 -080075 }
76
77 void clear() {
Luis Hector Chavezb4edbdf2018-07-18 21:18:27 -070078 data_.reset();
Josh Gaocd2a5292018-03-07 16:52:28 -080079 capacity_ = 0;
80 size_ = 0;
81 }
82
83 size_t capacity() const { return capacity_; }
84 size_t size() const { return size_; }
85 bool empty() const { return size() == 0; }
86
Luis Hector Chavezb4edbdf2018-07-18 21:18:27 -070087 char* data() { return data_.get(); }
88 const char* data() const { return data_.get(); }
Josh Gaocd2a5292018-03-07 16:52:28 -080089
Luis Hector Chavezb4edbdf2018-07-18 21:18:27 -070090 char* begin() { return data_.get(); }
91 const char* begin() const { return data_.get(); }
Josh Gaocd2a5292018-03-07 16:52:28 -080092
93 char* end() { return data() + size_; }
94 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:
104 void allocate(size_t size) {
105 CHECK(data_ == nullptr);
106 CHECK_EQ(0ULL, capacity_);
107 CHECK_EQ(0ULL, size_);
108 if (size != 0) {
Josh Gao5b470822018-11-12 13:44:38 -0800109 // 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]);
Josh Gaocd2a5292018-03-07 16:52:28 -0800113 capacity_ = size;
114 size_ = size;
115 }
116 }
117
Luis Hector Chavezb4edbdf2018-07-18 21:18:27 -0700118 std::unique_ptr<char[]> data_;
Josh Gaocd2a5292018-03-07 16:52:28 -0800119 size_t capacity_ = 0;
120 size_t size_ = 0;
121};
122
123struct 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
132struct apacket {
133 using payload_type = Block;
134 amessage msg;
135 payload_type payload;
136};
137
Josh Gao9f155db2018-04-03 14:37:11 -0700138struct IOVector {
139 using value_type = char;
140 using block_type = Block;
141 using size_type = size_t;
Josh Gaocd2a5292018-03-07 16:52:28 -0800142
Yurii Zubrytskyie5e6b0d2019-07-12 14:11:54 -0700143 IOVector() = default;
Josh Gaocd2a5292018-03-07 16:52:28 -0800144
Yurii Zubrytskyie5e6b0d2019-07-12 14:11:54 -0700145 explicit IOVector(block_type&& block) { append(std::move(block)); }
Josh Gaocd2a5292018-03-07 16:52:28 -0800146
Josh Gao9f155db2018-04-03 14:37:11 -0700147 IOVector(const IOVector& copy) = delete;
Chih-Hung Hsieh3c99c392018-09-25 11:16:22 -0700148 IOVector(IOVector&& move) noexcept : IOVector() { *this = std::move(move); }
Josh Gao9f155db2018-04-03 14:37:11 -0700149
150 IOVector& operator=(const IOVector& copy) = delete;
Yurii Zubrytskyie5e6b0d2019-07-12 14:11:54 -0700151 IOVector& operator=(IOVector&& move) noexcept;
Josh Gao9f155db2018-04-03 14:37:11 -0700152
Josh Gao2f0f9eb2020-03-04 19:34:08 -0800153 const value_type* front_data() const {
154 if (chain_.empty()) {
155 return nullptr;
156 }
157
Josh Gaod11b5092020-03-31 01:53:01 -0700158 return chain_[start_index_].data() + begin_offset_;
Josh Gao2f0f9eb2020-03-04 19:34:08 -0800159 }
160
161 size_type front_size() const {
162 if (chain_.empty()) {
163 return 0;
164 }
165
Josh Gaod11b5092020-03-31 01:53:01 -0700166 return chain_[start_index_].size() - begin_offset_;
Josh Gao2f0f9eb2020-03-04 19:34:08 -0800167 }
168
Yurii Zubrytskyie5e6b0d2019-07-12 14:11:54 -0700169 size_type size() const { return chain_length_ - begin_offset_; }
Josh Gaocd2a5292018-03-07 16:52:28 -0800170 bool empty() const { return size() == 0; }
171
Yurii Zubrytskyie5e6b0d2019-07-12 14:11:54 -0700172 // 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);
Josh Gaocd2a5292018-03-07 16:52:28 -0800177
Josh Gao9f155db2018-04-03 14:37:11 -0700178 // Split the first |len| bytes out of this chain into its own.
Yurii Zubrytskyie5e6b0d2019-07-12 14:11:54 -0700179 IOVector take_front(size_type len);
Josh Gaocd2a5292018-03-07 16:52:28 -0800180
Josh Gao9f155db2018-04-03 14:37:11 -0700181 // Add a nonempty block to the chain.
Yurii Zubrytskyie5e6b0d2019-07-12 14:11:54 -0700182 void append(block_type&& block) {
183 if (block.size() == 0) {
Josh Gao15fa1332019-04-03 12:56:22 -0700184 return;
185 }
Yurii Zubrytskyie5e6b0d2019-07-12 14:11:54 -0700186 CHECK_NE(0ULL, block.size());
187 chain_length_ += block.size();
Josh Gao9f155db2018-04-03 14:37:11 -0700188 chain_.emplace_back(std::move(block));
189 }
Josh Gaocd2a5292018-03-07 16:52:28 -0800190
Yurii Zubrytskyie5e6b0d2019-07-12 14:11:54 -0700191 void trim_front();
Josh Gao9f155db2018-04-03 14:37:11 -0700192
193 private:
Yurii Zubrytskyie5e6b0d2019-07-12 14:11:54 -0700194 void trim_chain_front();
Josh Gao9f155db2018-04-03 14:37:11 -0700195
196 // Drop the front block from the chain, and update chain_length_ appropriately.
Yurii Zubrytskyie5e6b0d2019-07-12 14:11:54 -0700197 void pop_front_block();
Josh Gao9f155db2018-04-03 14:37:11 -0700198
199 // Iterate over the blocks with a callback with an operator()(const char*, size_t).
200 template <typename Fn>
201 void iterate_blocks(Fn&& callback) const {
Yurii Zubrytskyie5e6b0d2019-07-12 14:11:54 -0700202 if (size() == 0) {
Josh Gao9f155db2018-04-03 14:37:11 -0700203 return;
204 }
205
Yurii Zubrytskyie5e6b0d2019-07-12 14:11:54 -0700206 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();
Josh Gao9f155db2018-04-03 14:37:11 -0700210
Yurii Zubrytskyie5e6b0d2019-07-12 14:11:54 -0700211 if (i == start_index_) {
212 CHECK_GE(block.size(), begin_offset_);
Josh Gao9f155db2018-04-03 14:37:11 -0700213 begin += begin_offset_;
214 length -= begin_offset_;
215 }
Josh Gao9f155db2018-04-03 14:37:11 -0700216 callback(begin, length);
217 }
218 }
219
220 public:
221 // Copy all of the blocks into a single block.
222 template <typename CollectionType = block_type>
Yurii Zubrytskyie5e6b0d2019-07-12 14:11:54 -0700223 CollectionType coalesce() const& {
Josh Gao9f155db2018-04-03 14:37:11 -0700224 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
Yurii Zubrytskyie5e6b0d2019-07-12 14:11:54 -0700240 block_type coalesce() &&;
241
Josh Gao9f155db2018-04-03 14:37:11 -0700242 template <typename FunctionType>
Yurii Zubrytskyie5e6b0d2019-07-12 14:11:54 -0700243 auto coalesced(FunctionType&& f) const {
244 if (chain_.size() == start_index_ + 1) {
Josh Gao9f155db2018-04-03 14:37:11 -0700245 // If we only have one block, we can use it directly.
Yurii Zubrytskyie5e6b0d2019-07-12 14:11:54 -0700246 return f(chain_[start_index_].data() + begin_offset_, size());
Josh Gao9f155db2018-04-03 14:37:11 -0700247 } 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.
Yurii Zubrytskyie5e6b0d2019-07-12 14:11:54 -0700255 std::vector<adb_iovec> iovecs() const;
Josh Gao9f155db2018-04-03 14:37:11 -0700256
257 private:
258 // Total length of all of the blocks in the chain.
259 size_t chain_length_ = 0;
260
Josh Gaocd2a5292018-03-07 16:52:28 -0800261 size_t begin_offset_ = 0;
Yurii Zubrytskyie5e6b0d2019-07-12 14:11:54 -0700262 size_t start_index_ = 0;
263 std::vector<block_type> chain_;
Josh Gaocd2a5292018-03-07 16:52:28 -0800264};
Josh Gaoe490fbb2019-12-09 15:44:57 -0800265
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.
274template <typename T>
275struct enable_weak_from_this;
276
277template <typename T>
278struct weak_ptr {
279 weak_ptr() = default;
280 explicit weak_ptr(T* ptr) { reset(ptr); }
281 weak_ptr(const weak_ptr& copy) { reset(copy.get()); }
282
283 weak_ptr(weak_ptr&& move) {
284 reset(move.get());
285 move.reset();
286 }
287
288 ~weak_ptr() { reset(); }
289
290 weak_ptr& operator=(const weak_ptr& copy) {
291 if (&copy == 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
Josh Gao85407e32021-05-20 19:15:15 -0700309 T* get() const {
Josh Gaoe490fbb2019-12-09 15:44:57 -0800310 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
337template <typename T>
338struct 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() {
Josh Gao85407e32021-05-20 19:15:15 -0700352 fdevent_run_on_main_thread([this]() { delete static_cast<T*>(this); });
Josh Gaoe490fbb2019-12-09 15:44:57 -0800353 }
354
355 private:
356 friend struct weak_ptr<T>;
357 std::vector<weak_ptr<T>*> weak_ptrs_;
358};