• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 (&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 
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