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