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