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 (&copy == 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