• 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      * This allows the value in this class to be set from beneath it. If you call this method and
167      * then change the value of T*, you must take ownership of the value you are replacing and add
168      * ownership to the object that is put in here.
169      *
170      * Recommended use is like this:
171      *   ScopedAResource<T> a; // will be nullptr
172      *   SomeInitFunction(a.getR()); // value is initialized with refcount
173      *
174      * Other usecases are discouraged.
175      *
176      */
getR()177     T* getR() { return &mT; }
178 
179     // copy-constructing/assignment is disallowed
180     ScopedAResource(const ScopedAResource&) = delete;
181     ScopedAResource& operator=(const ScopedAResource&) = delete;
182 
183     // move-constructing/assignment is okay
ScopedAResource(ScopedAResource && other)184     ScopedAResource(ScopedAResource&& other) noexcept : mT(std::move(other.mT)) {
185         other.mT = DEFAULT;
186     }
187     ScopedAResource& operator=(ScopedAResource&& other) noexcept {
188         set(other.mT);
189         other.mT = DEFAULT;
190         return *this;
191     }
192 
193    private:
194     T mT;
195 };
196 
197 }  // namespace impl
198 
199 /**
200  * Convenience wrapper. See AParcel.
201  */
202 class ScopedAParcel : public impl::ScopedAResource<AParcel*, AParcel_delete, nullptr> {
203    public:
204     /**
205      * Takes ownership of a.
206      */
ScopedAResource(a)207     explicit ScopedAParcel(AParcel* a = nullptr) : ScopedAResource(a) {}
~ScopedAParcel()208     ~ScopedAParcel() {}
209     ScopedAParcel(ScopedAParcel&&) = default;
210     ScopedAParcel& operator=(ScopedAParcel&&) = default;
211 
212     bool operator!=(const ScopedAParcel& rhs) const { return get() != rhs.get(); }
213     bool operator<(const ScopedAParcel& rhs) const { return get() < rhs.get(); }
214     bool operator<=(const ScopedAParcel& rhs) const { return get() <= rhs.get(); }
215     bool operator==(const ScopedAParcel& rhs) const { return get() == rhs.get(); }
216     bool operator>(const ScopedAParcel& rhs) const { return get() > rhs.get(); }
217     bool operator>=(const ScopedAParcel& rhs) const { return get() >= rhs.get(); }
218 };
219 
220 /**
221  * Convenience wrapper. See AStatus.
222  */
223 class ScopedAStatus : public impl::ScopedAResource<AStatus*, AStatus_delete, nullptr> {
224    public:
225     /**
226      * Takes ownership of a.
227      *
228      * WARNING: this constructor is only expected to be used when reading a
229      *     status value. Use `ScopedAStatus::ok()` instead.
230      */
ScopedAResource(a)231     explicit ScopedAStatus(AStatus* a = nullptr) : ScopedAResource(a) {}
~ScopedAStatus()232     ~ScopedAStatus() {}
233     ScopedAStatus(ScopedAStatus&&) = default;
234     ScopedAStatus& operator=(ScopedAStatus&&) = default;
235 
236     /**
237      * See AStatus_isOk.
238      */
isOk()239     bool isOk() const { return get() != nullptr && AStatus_isOk(get()); }
240 
241     /**
242      * See AStatus_getExceptionCode
243      */
getExceptionCode()244     binder_exception_t getExceptionCode() const { return AStatus_getExceptionCode(get()); }
245 
246     /**
247      * See AStatus_getServiceSpecificError
248      */
getServiceSpecificError()249     int32_t getServiceSpecificError() const { return AStatus_getServiceSpecificError(get()); }
250 
251     /**
252      * See AStatus_getStatus
253      */
getStatus()254     binder_status_t getStatus() const { return AStatus_getStatus(get()); }
255 
256     /**
257      * See AStatus_getMessage
258      */
getMessage()259     const char* getMessage() const { return AStatus_getMessage(get()); }
260 
getDescription()261     std::string getDescription() const {
262         if (__builtin_available(android 30, *)) {
263             const char* cStr = AStatus_getDescription(get());
264             std::string ret = cStr;
265             AStatus_deleteDescription(cStr);
266             return ret;
267         }
268         binder_exception_t exception = getExceptionCode();
269         std::string desc = std::to_string(exception);
270         if (exception == EX_SERVICE_SPECIFIC) {
271             desc += " (" + std::to_string(getServiceSpecificError()) + ")";
272         } else if (exception == EX_TRANSACTION_FAILED) {
273             desc += " (" + std::to_string(getStatus()) + ")";
274         }
275         if (const char* msg = getMessage(); msg != nullptr) {
276             desc += ": ";
277             desc += msg;
278         }
279         return desc;
280     }
281 
282     /**
283      * Convenience methods for creating scoped statuses.
284      */
ok()285     static ScopedAStatus ok() { return ScopedAStatus(AStatus_newOk()); }
fromExceptionCode(binder_exception_t exception)286     static ScopedAStatus fromExceptionCode(binder_exception_t exception) {
287         return ScopedAStatus(AStatus_fromExceptionCode(exception));
288     }
fromExceptionCodeWithMessage(binder_exception_t exception,const char * message)289     static ScopedAStatus fromExceptionCodeWithMessage(binder_exception_t exception,
290                                                       const char* message) {
291         return ScopedAStatus(AStatus_fromExceptionCodeWithMessage(exception, message));
292     }
fromServiceSpecificError(int32_t serviceSpecific)293     static ScopedAStatus fromServiceSpecificError(int32_t serviceSpecific) {
294         return ScopedAStatus(AStatus_fromServiceSpecificError(serviceSpecific));
295     }
fromServiceSpecificErrorWithMessage(int32_t serviceSpecific,const char * message)296     static ScopedAStatus fromServiceSpecificErrorWithMessage(int32_t serviceSpecific,
297                                                              const char* message) {
298         return ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(serviceSpecific, message));
299     }
fromStatus(binder_status_t status)300     static ScopedAStatus fromStatus(binder_status_t status) {
301         return ScopedAStatus(AStatus_fromStatus(status));
302     }
303 };
304 
305 /**
306  * Convenience wrapper. See AIBinder_DeathRecipient.
307  */
308 class ScopedAIBinder_DeathRecipient
309     : public impl::ScopedAResource<AIBinder_DeathRecipient*, AIBinder_DeathRecipient_delete,
310                                    nullptr> {
311    public:
312     /**
313      * Takes ownership of a.
314      */
315     explicit ScopedAIBinder_DeathRecipient(AIBinder_DeathRecipient* a = nullptr)
ScopedAResource(a)316         : ScopedAResource(a) {}
~ScopedAIBinder_DeathRecipient()317     ~ScopedAIBinder_DeathRecipient() {}
318     ScopedAIBinder_DeathRecipient(ScopedAIBinder_DeathRecipient&&) = default;
319     ScopedAIBinder_DeathRecipient& operator=(ScopedAIBinder_DeathRecipient&&) = default;
320 };
321 
322 /**
323  * Convenience wrapper. See AIBinder_Weak.
324  */
325 class ScopedAIBinder_Weak
326     : public impl::ScopedAResource<AIBinder_Weak*, AIBinder_Weak_delete, nullptr> {
327    public:
328     /**
329      * Takes ownership of a.
330      */
ScopedAResource(a)331     explicit ScopedAIBinder_Weak(AIBinder_Weak* a = nullptr) : ScopedAResource(a) {}
~ScopedAIBinder_Weak()332     ~ScopedAIBinder_Weak() {}
333     ScopedAIBinder_Weak(ScopedAIBinder_Weak&&) = default;
334     ScopedAIBinder_Weak& operator=(ScopedAIBinder_Weak&&) = default;
335 
336     /**
337      * See AIBinder_Weak_promote.
338      */
promote()339     SpAIBinder promote() { return SpAIBinder(AIBinder_Weak_promote(get())); }
340 };
341 
342 namespace internal {
343 
closeWithError(int fd)344 static void closeWithError(int fd) {
345     if (fd == -1) return;
346     int ret = close(fd);
347     if (ret != 0) {
348         syslog(LOG_ERR, "Could not close FD %d: %s", fd, strerror(errno));
349     }
350 }
351 
352 }  // namespace internal
353 
354 /**
355  * Convenience wrapper for a file descriptor.
356  */
357 class ScopedFileDescriptor : public impl::ScopedAResource<int, internal::closeWithError, -1> {
358    public:
359     /**
360      * Takes ownership of a.
361      */
ScopedFileDescriptor()362     ScopedFileDescriptor() : ScopedFileDescriptor(-1) {}
ScopedFileDescriptor(int a)363     explicit ScopedFileDescriptor(int a) : ScopedAResource(a) {}
~ScopedFileDescriptor()364     ~ScopedFileDescriptor() {}
365     ScopedFileDescriptor(ScopedFileDescriptor&&) = default;
366     ScopedFileDescriptor& operator=(ScopedFileDescriptor&&) = default;
367 
368     bool operator!=(const ScopedFileDescriptor& rhs) const { return get() != rhs.get(); }
369     bool operator<(const ScopedFileDescriptor& rhs) const { return get() < rhs.get(); }
370     bool operator<=(const ScopedFileDescriptor& rhs) const { return get() <= rhs.get(); }
371     bool operator==(const ScopedFileDescriptor& rhs) const { return get() == rhs.get(); }
372     bool operator>(const ScopedFileDescriptor& rhs) const { return get() > rhs.get(); }
373     bool operator>=(const ScopedFileDescriptor& rhs) const { return get() >= rhs.get(); }
374 };
375 
376 }  // namespace ndk
377 
378 /** @} */
379