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