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 <unistd.h>
35
36 #include <cstddef>
37 #include <iostream>
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 #endif
274
275 #if defined(__ANDROID_UNAVAILABLE_SYMBOLS_ARE_WEAK__) || __ANDROID_API__ >= 30
276 const char* cStr = AStatus_getDescription(get());
277 std::string ret = cStr;
278 AStatus_deleteDescription(cStr);
279 return ret;
280 #endif
281
282 #ifdef __ANDROID_UNAVAILABLE_SYMBOLS_ARE_WEAK__
283 }
284 #endif
285
286 binder_exception_t exception = getExceptionCode();
287 std::string desc = std::to_string(exception);
288 if (exception == EX_SERVICE_SPECIFIC) {
289 desc += " (" + std::to_string(getServiceSpecificError()) + ")";
290 } else if (exception == EX_TRANSACTION_FAILED) {
291 desc += " (" + std::to_string(getStatus()) + ")";
292 }
293 if (const char* msg = getMessage(); msg != nullptr) {
294 desc += ": ";
295 desc += msg;
296 }
297 return desc;
298 }
299
300 /**
301 * Convenience methods for creating scoped statuses.
302 */
ok()303 static ScopedAStatus ok() { return ScopedAStatus(AStatus_newOk()); }
fromExceptionCode(binder_exception_t exception)304 static ScopedAStatus fromExceptionCode(binder_exception_t exception) {
305 return ScopedAStatus(AStatus_fromExceptionCode(exception));
306 }
fromExceptionCodeWithMessage(binder_exception_t exception,const char * message)307 static ScopedAStatus fromExceptionCodeWithMessage(binder_exception_t exception,
308 const char* message) {
309 return ScopedAStatus(AStatus_fromExceptionCodeWithMessage(exception, message));
310 }
fromServiceSpecificError(int32_t serviceSpecific)311 static ScopedAStatus fromServiceSpecificError(int32_t serviceSpecific) {
312 return ScopedAStatus(AStatus_fromServiceSpecificError(serviceSpecific));
313 }
fromServiceSpecificErrorWithMessage(int32_t serviceSpecific,const char * message)314 static ScopedAStatus fromServiceSpecificErrorWithMessage(int32_t serviceSpecific,
315 const char* message) {
316 return ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(serviceSpecific, message));
317 }
fromStatus(binder_status_t status)318 static ScopedAStatus fromStatus(binder_status_t status) {
319 return ScopedAStatus(AStatus_fromStatus(status));
320 }
321 };
322
323 static inline std::ostream& operator<<(std::ostream& os, const ScopedAStatus& status) {
324 return os << status.getDescription();
325 return os;
326 }
327
328 /**
329 * Convenience wrapper. See AIBinder_DeathRecipient.
330 */
331 class ScopedAIBinder_DeathRecipient
332 : public impl::ScopedAResource<AIBinder_DeathRecipient*, AIBinder_DeathRecipient_delete,
333 nullptr> {
334 public:
335 /**
336 * Takes ownership of a.
337 */
338 explicit ScopedAIBinder_DeathRecipient(AIBinder_DeathRecipient* a = nullptr)
ScopedAResource(a)339 : ScopedAResource(a) {}
~ScopedAIBinder_DeathRecipient()340 ~ScopedAIBinder_DeathRecipient() {}
341 ScopedAIBinder_DeathRecipient(ScopedAIBinder_DeathRecipient&&) = default;
342 ScopedAIBinder_DeathRecipient& operator=(ScopedAIBinder_DeathRecipient&&) = default;
343 };
344
345 /**
346 * Convenience wrapper. See AIBinder_Weak.
347 */
348 class ScopedAIBinder_Weak
349 : public impl::ScopedAResource<AIBinder_Weak*, AIBinder_Weak_delete, nullptr> {
350 public:
351 /**
352 * Takes ownership of a.
353 */
ScopedAResource(a)354 explicit ScopedAIBinder_Weak(AIBinder_Weak* a = nullptr) : ScopedAResource(a) {}
~ScopedAIBinder_Weak()355 ~ScopedAIBinder_Weak() {}
356 ScopedAIBinder_Weak(ScopedAIBinder_Weak&&) = default;
357 ScopedAIBinder_Weak& operator=(ScopedAIBinder_Weak&&) = default;
358
359 /**
360 * See AIBinder_Weak_promote.
361 */
promote()362 SpAIBinder promote() const { return SpAIBinder(AIBinder_Weak_promote(get())); }
363 };
364
365 namespace internal {
366
closeWithError(int fd)367 static void closeWithError(int fd) {
368 if (fd == -1) return;
369 int ret = close(fd);
370 if (ret != 0) {
371 syslog(LOG_ERR, "Could not close FD %d: %s", fd, strerror(errno));
372 }
373 }
374
375 } // namespace internal
376
377 /**
378 * Convenience wrapper for a file descriptor.
379 */
380 class ScopedFileDescriptor : public impl::ScopedAResource<int, internal::closeWithError, -1> {
381 public:
382 /**
383 * Takes ownership of a.
384 */
ScopedFileDescriptor()385 ScopedFileDescriptor() : ScopedFileDescriptor(-1) {}
ScopedFileDescriptor(int a)386 explicit ScopedFileDescriptor(int a) : ScopedAResource(a) {}
~ScopedFileDescriptor()387 ~ScopedFileDescriptor() {}
388 ScopedFileDescriptor(ScopedFileDescriptor&&) = default;
389 ScopedFileDescriptor& operator=(ScopedFileDescriptor&&) = default;
390
dup()391 ScopedFileDescriptor dup() const { return ScopedFileDescriptor(::dup(get())); }
392
393 bool operator!=(const ScopedFileDescriptor& rhs) const { return get() != rhs.get(); }
394 bool operator<(const ScopedFileDescriptor& rhs) const { return get() < rhs.get(); }
395 bool operator<=(const ScopedFileDescriptor& rhs) const { return get() <= rhs.get(); }
396 bool operator==(const ScopedFileDescriptor& rhs) const { return get() == rhs.get(); }
397 bool operator>(const ScopedFileDescriptor& rhs) const { return get() > rhs.get(); }
398 bool operator>=(const ScopedFileDescriptor& rhs) const { return get() >= rhs.get(); }
399 };
400
401 } // namespace ndk
402
403 /** @} */
404