• 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 /**
18  * @addtogroup NdkBinder
19  * @{
20  */
21 
22 /**
23  * @file binder_auto_utils.h
24  * @brief These objects provide a more C++-like thin interface to the binder.
25  */
26 
27 #pragma once
28 
29 #include <android/binder_ibinder.h>
30 #include <android/binder_internal_logging.h>
31 #include <android/binder_parcel.h>
32 #include <android/binder_status.h>
33 
34 #include <assert.h>
35 
36 #include <unistd.h>
37 #include <cstddef>
38 #include <string>
39 
40 namespace ndk {
41 
42 /**
43  * Represents one strong pointer to an AIBinder object.
44  */
45 class SpAIBinder {
46    public:
47     /**
48      * Default constructor.
49      */
SpAIBinder()50     SpAIBinder() : mBinder(nullptr) {}
51 
52     /**
53      * Takes ownership of one strong refcount of binder.
54      */
SpAIBinder(AIBinder * binder)55     explicit SpAIBinder(AIBinder* binder) : mBinder(binder) {}
56 
57     /**
58      * Convenience operator for implicitly constructing an SpAIBinder from nullptr. This is not
59      * explicit because it is not taking ownership of anything.
60      */
SpAIBinder(std::nullptr_t)61     SpAIBinder(std::nullptr_t) : SpAIBinder() {}  // NOLINT(google-explicit-constructor)
62 
63     /**
64      * This will delete the underlying object if it exists. See operator=.
65      */
SpAIBinder(const SpAIBinder & other)66     SpAIBinder(const SpAIBinder& other) { *this = other; }
67 
68     /**
69      * This deletes the underlying object if it exists. See set.
70      */
~SpAIBinder()71     ~SpAIBinder() { set(nullptr); }
72 
73     /**
74      * This takes ownership of a binder from another AIBinder object but it does not affect the
75      * ownership of that other object.
76      */
77     SpAIBinder& operator=(const SpAIBinder& other) {
78         if (this == &other) {
79             return *this;
80         }
81         AIBinder_incStrong(other.mBinder);
82         set(other.mBinder);
83         return *this;
84     }
85 
86     /**
87      * Takes ownership of one strong refcount of binder
88      */
set(AIBinder * binder)89     void set(AIBinder* binder) {
90         AIBinder* old = *const_cast<AIBinder* volatile*>(&mBinder);
91         if (old != nullptr) AIBinder_decStrong(old);
92         if (old != *const_cast<AIBinder* volatile*>(&mBinder)) {
93             __assert(__FILE__, __LINE__, "Race detected.");
94         }
95         mBinder = binder;
96     }
97 
98     /**
99      * This returns the underlying binder object for transactions. If it is used to create another
100      * SpAIBinder object, it should first be incremented.
101      */
get()102     AIBinder* get() const { return mBinder; }
103 
104     /**
105      * This allows the value in this class to be set from beneath it. If you call this method and
106      * then change the value of T*, you must take ownership of the value you are replacing and add
107      * ownership to the object that is put in here.
108      *
109      * Recommended use is like this:
110      *   SpAIBinder a;  // will be nullptr
111      *   SomeInitFunction(a.getR());  // value is initialized with refcount
112      *
113      * Other usecases are discouraged.
114      *
115      */
getR()116     AIBinder** getR() { return &mBinder; }
117 
118     bool operator!=(const SpAIBinder& rhs) const { return get() != rhs.get(); }
119     bool operator<(const SpAIBinder& rhs) const { return get() < rhs.get(); }
120     bool operator<=(const SpAIBinder& rhs) const { return get() <= rhs.get(); }
121     bool operator==(const SpAIBinder& rhs) const { return get() == rhs.get(); }
122     bool operator>(const SpAIBinder& rhs) const { return get() > rhs.get(); }
123     bool operator>=(const SpAIBinder& rhs) const { return get() >= rhs.get(); }
124 
125    private:
126     AIBinder* mBinder = nullptr;
127 };
128 
129 namespace impl {
130 
131 /**
132  * This baseclass owns a single object, used to make various classes RAII.
133  */
134 template <typename T, void (*Destroy)(T), T DEFAULT>
135 class ScopedAResource {
136    public:
137     /**
138      * Takes ownership of t.
139      */
mT(t)140     explicit ScopedAResource(T t = DEFAULT) : mT(t) {}
141 
142     /**
143      * This deletes the underlying object if it exists. See set.
144      */
~ScopedAResource()145     ~ScopedAResource() { set(DEFAULT); }
146 
147     /**
148      * Takes ownership of t.
149      */
set(T t)150     void set(T t) {
151         Destroy(mT);
152         mT = t;
153     }
154 
155     /**
156      * This returns the underlying object to be modified but does not affect ownership.
157      */
get()158     T get() { return mT; }
159 
160     /**
161      * This returns the const underlying object but does not affect ownership.
162      */
get()163     const T get() const { return mT; }
164 
165     /**
166      * Release the underlying resource.
167      */
release()168     [[nodiscard]] T release() {
169         T a = mT;
170         mT = DEFAULT;
171         return a;
172     }
173 
174     /**
175      * This allows the value in this class to be set from beneath it. If you call this method and
176      * then change the value of T*, you must take ownership of the value you are replacing and add
177      * ownership to the object that is put in here.
178      *
179      * Recommended use is like this:
180      *   ScopedAResource<T> a; // will be nullptr
181      *   SomeInitFunction(a.getR()); // value is initialized with refcount
182      *
183      * Other usecases are discouraged.
184      *
185      */
getR()186     T* getR() { return &mT; }
187 
188     // copy-constructing/assignment is disallowed
189     ScopedAResource(const ScopedAResource&) = delete;
190     ScopedAResource& operator=(const ScopedAResource&) = delete;
191 
192     // move-constructing/assignment is okay
ScopedAResource(ScopedAResource && other)193     ScopedAResource(ScopedAResource&& other) noexcept : mT(std::move(other.mT)) {
194         other.mT = DEFAULT;
195     }
196     ScopedAResource& operator=(ScopedAResource&& other) noexcept {
197         set(other.mT);
198         other.mT = DEFAULT;
199         return *this;
200     }
201 
202    private:
203     T mT;
204 };
205 
206 }  // namespace impl
207 
208 /**
209  * Convenience wrapper. See AParcel.
210  */
211 class ScopedAParcel : public impl::ScopedAResource<AParcel*, AParcel_delete, nullptr> {
212    public:
213     /**
214      * Takes ownership of a.
215      */
ScopedAResource(a)216     explicit ScopedAParcel(AParcel* a = nullptr) : ScopedAResource(a) {}
~ScopedAParcel()217     ~ScopedAParcel() {}
218     ScopedAParcel(ScopedAParcel&&) = default;
219     ScopedAParcel& operator=(ScopedAParcel&&) = default;
220 
221     bool operator!=(const ScopedAParcel& rhs) const { return get() != rhs.get(); }
222     bool operator<(const ScopedAParcel& rhs) const { return get() < rhs.get(); }
223     bool operator<=(const ScopedAParcel& rhs) const { return get() <= rhs.get(); }
224     bool operator==(const ScopedAParcel& rhs) const { return get() == rhs.get(); }
225     bool operator>(const ScopedAParcel& rhs) const { return get() > rhs.get(); }
226     bool operator>=(const ScopedAParcel& rhs) const { return get() >= rhs.get(); }
227 };
228 
229 /**
230  * Convenience wrapper. See AStatus.
231  */
232 class ScopedAStatus : public impl::ScopedAResource<AStatus*, AStatus_delete, nullptr> {
233    public:
234     /**
235      * Takes ownership of a.
236      *
237      * WARNING: this constructor is only expected to be used when reading a
238      *     status value. Use `ScopedAStatus::ok()` instead.
239      */
ScopedAResource(a)240     explicit ScopedAStatus(AStatus* a = nullptr) : ScopedAResource(a) {}
~ScopedAStatus()241     ~ScopedAStatus() {}
242     ScopedAStatus(ScopedAStatus&&) = default;
243     ScopedAStatus& operator=(ScopedAStatus&&) = default;
244 
245     /**
246      * See AStatus_isOk.
247      */
isOk()248     bool isOk() const { return get() != nullptr && AStatus_isOk(get()); }
249 
250     /**
251      * See AStatus_getExceptionCode
252      */
getExceptionCode()253     binder_exception_t getExceptionCode() const { return AStatus_getExceptionCode(get()); }
254 
255     /**
256      * See AStatus_getServiceSpecificError
257      */
getServiceSpecificError()258     int32_t getServiceSpecificError() const { return AStatus_getServiceSpecificError(get()); }
259 
260     /**
261      * See AStatus_getStatus
262      */
getStatus()263     binder_status_t getStatus() const { return AStatus_getStatus(get()); }
264 
265     /**
266      * See AStatus_getMessage
267      */
getMessage()268     const char* getMessage() const { return AStatus_getMessage(get()); }
269 
getDescription()270     std::string getDescription() const {
271 #ifdef __ANDROID_UNAVAILABLE_SYMBOLS_ARE_WEAK__
272         if (__builtin_available(android 30, *)) {
273 #else
274         if (__ANDROID_API__ >= 30) {
275 #endif
276             const char* cStr = AStatus_getDescription(get());
277             std::string ret = cStr;
278             AStatus_deleteDescription(cStr);
279             return ret;
280         }
281         binder_exception_t exception = getExceptionCode();
282         std::string desc = std::to_string(exception);
283         if (exception == EX_SERVICE_SPECIFIC) {
284             desc += " (" + std::to_string(getServiceSpecificError()) + ")";
285         } else if (exception == EX_TRANSACTION_FAILED) {
286             desc += " (" + std::to_string(getStatus()) + ")";
287         }
288         if (const char* msg = getMessage(); msg != nullptr) {
289             desc += ": ";
290             desc += msg;
291         }
292         return desc;
293     }
294 
295     /**
296      * Convenience methods for creating scoped statuses.
297      */
298     static ScopedAStatus ok() { return ScopedAStatus(AStatus_newOk()); }
299     static ScopedAStatus fromExceptionCode(binder_exception_t exception) {
300         return ScopedAStatus(AStatus_fromExceptionCode(exception));
301     }
302     static ScopedAStatus fromExceptionCodeWithMessage(binder_exception_t exception,
303                                                       const char* message) {
304         return ScopedAStatus(AStatus_fromExceptionCodeWithMessage(exception, message));
305     }
306     static ScopedAStatus fromServiceSpecificError(int32_t serviceSpecific) {
307         return ScopedAStatus(AStatus_fromServiceSpecificError(serviceSpecific));
308     }
309     static ScopedAStatus fromServiceSpecificErrorWithMessage(int32_t serviceSpecific,
310                                                              const char* message) {
311         return ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(serviceSpecific, message));
312     }
313     static ScopedAStatus fromStatus(binder_status_t status) {
314         return ScopedAStatus(AStatus_fromStatus(status));
315     }
316 };
317 
318 /**
319  * Convenience wrapper. See AIBinder_DeathRecipient.
320  */
321 class ScopedAIBinder_DeathRecipient
322     : public impl::ScopedAResource<AIBinder_DeathRecipient*, AIBinder_DeathRecipient_delete,
323                                    nullptr> {
324    public:
325     /**
326      * Takes ownership of a.
327      */
328     explicit ScopedAIBinder_DeathRecipient(AIBinder_DeathRecipient* a = nullptr)
ScopedAResource(a)329         : ScopedAResource(a) {}
~ScopedAIBinder_DeathRecipient()330     ~ScopedAIBinder_DeathRecipient() {}
331     ScopedAIBinder_DeathRecipient(ScopedAIBinder_DeathRecipient&&) = default;
332     ScopedAIBinder_DeathRecipient& operator=(ScopedAIBinder_DeathRecipient&&) = default;
333 };
334 
335 /**
336  * Convenience wrapper. See AIBinder_Weak.
337  */
338 class ScopedAIBinder_Weak
339     : public impl::ScopedAResource<AIBinder_Weak*, AIBinder_Weak_delete, nullptr> {
340    public:
341     /**
342      * Takes ownership of a.
343      */
ScopedAResource(a)344     explicit ScopedAIBinder_Weak(AIBinder_Weak* a = nullptr) : ScopedAResource(a) {}
~ScopedAIBinder_Weak()345     ~ScopedAIBinder_Weak() {}
346     ScopedAIBinder_Weak(ScopedAIBinder_Weak&&) = default;
347     ScopedAIBinder_Weak& operator=(ScopedAIBinder_Weak&&) = default;
348 
349     /**
350      * See AIBinder_Weak_promote.
351      */
promote()352     SpAIBinder promote() { return SpAIBinder(AIBinder_Weak_promote(get())); }
353 };
354 
355 namespace internal {
356 
closeWithError(int fd)357 static void closeWithError(int fd) {
358     if (fd == -1) return;
359     int ret = close(fd);
360     if (ret != 0) {
361         syslog(LOG_ERR, "Could not close FD %d: %s", fd, strerror(errno));
362     }
363 }
364 
365 }  // namespace internal
366 
367 /**
368  * Convenience wrapper for a file descriptor.
369  */
370 class ScopedFileDescriptor : public impl::ScopedAResource<int, internal::closeWithError, -1> {
371    public:
372     /**
373      * Takes ownership of a.
374      */
ScopedFileDescriptor()375     ScopedFileDescriptor() : ScopedFileDescriptor(-1) {}
ScopedFileDescriptor(int a)376     explicit ScopedFileDescriptor(int a) : ScopedAResource(a) {}
~ScopedFileDescriptor()377     ~ScopedFileDescriptor() {}
378     ScopedFileDescriptor(ScopedFileDescriptor&&) = default;
379     ScopedFileDescriptor& operator=(ScopedFileDescriptor&&) = default;
380 
dup()381     ScopedFileDescriptor dup() const { return ScopedFileDescriptor(::dup(get())); }
382 
383     bool operator!=(const ScopedFileDescriptor& rhs) const { return get() != rhs.get(); }
384     bool operator<(const ScopedFileDescriptor& rhs) const { return get() < rhs.get(); }
385     bool operator<=(const ScopedFileDescriptor& rhs) const { return get() <= rhs.get(); }
386     bool operator==(const ScopedFileDescriptor& rhs) const { return get() == rhs.get(); }
387     bool operator>(const ScopedFileDescriptor& rhs) const { return get() > rhs.get(); }
388     bool operator>=(const ScopedFileDescriptor& rhs) const { return get() >= rhs.get(); }
389 };
390 
391 }  // namespace ndk
392 
393 /** @} */
394