1 /*
2 * Copyright (C) 2024 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 #pragma once
18
19 #include <android/binder_auto_utils.h>
20 #include <android/binder_interface_utils.h>
21 #include <android/binder_manager.h>
22 #include <binder/IServiceManager.h>
23
24 namespace android::mediautils {
25 // General Template Binder Utilities.
26 //
27 // In order to write generic Template methods, we need to have utility methods
28 // that provide seamless template overload resolution between NDK and CPP variants.
29 //
30
31 // Returns true or false based on whether the Interface is a NDK Interface.
32 template<typename Interface>
33 inline constexpr bool is_ndk = std::derived_from<Interface, ::ndk::ICInterface>;
34
35 // Returns the Interface ptr type (shared_ptr or sp) based on the Interface.
36 template<typename Interface>
37 using InterfaceType =
38 std::conditional_t <is_ndk<Interface>, std::shared_ptr<Interface>, sp<Interface>>;
39
40 template<typename Interface>
41 using BaseInterfaceType = std::conditional_t <is_ndk<Interface>,
42 std::shared_ptr<::ndk::ICInterface>, sp<::android::IInterface>>;
43
44 /**
45 * Returns either a sp<IBinder> or an SpAIBinder object
46 * for the AIDL interface given.
47 *
48 * A -cpp interface will return sp<IBinder>.
49 * A -ndk interface will return SpAIBinder
50 */
51 template<typename Interface>
binderFromInterface(const sp<Interface> & interface)52 sp<IBinder> binderFromInterface(const sp<Interface> &interface) {
53 return IInterface::asBinder(interface);
54 }
55
56 template<typename Interface>
binderFromInterface(const std::shared_ptr<Interface> & interface)57 ::ndk::SpAIBinder binderFromInterface(const std::shared_ptr<Interface> &interface) {
58 return interface->asBinder();
59 }
60
61 /**
62 * Returns true if two interfaces pointer-match, or represent identical binder objects.
63 *
64 * C++ with C++ and NDK with NDK interfaces may be compared.
65 *
66 * It currently isn't possible through the NDK public interface to extract
67 * the underlying C++ binder object, so we don't allow NDK and C++ interfaces to
68 * be cross-checked even though they might be backed by the same binder object.
69 */
isSameInterface(const sp<IInterface> & a,const sp<IInterface> & b)70 static inline bool isSameInterface(const sp<IInterface>& a, const sp<IInterface>& b) {
71 return a == b || (a && b && IInterface::asBinder(a) == IInterface::asBinder(b));
72 }
73
isSameInterface(const std::shared_ptr<::ndk::ICInterface> & a,const std::shared_ptr<::ndk::ICInterface> & b)74 static inline bool isSameInterface(const std::shared_ptr<::ndk::ICInterface>& a,
75 const std::shared_ptr<::ndk::ICInterface>& b) {
76 return a == b || (a && b && a->asBinder() == b->asBinder());
77 }
78
79 /**
80 * Returns either a sp<Interface> or a std::shared_ptr<Interface> from a Binder object.
81 *
82 * A -cpp interface will return sp<Interface>.
83 * A -ndk interface will return std::shared_ptr<Interface>
84 */
85 template<typename Interface>
interfaceFromBinder(const sp<IBinder> & binder)86 sp<Interface> interfaceFromBinder(const sp<IBinder> &binder) {
87 return interface_cast<Interface>(binder);
88 }
89
90 template<typename Interface>
interfaceFromBinder(const::ndk::SpAIBinder & binder)91 std::shared_ptr<Interface> interfaceFromBinder(const ::ndk::SpAIBinder &binder) {
92 return Interface::fromBinder(binder);
93 }
94
95 /**
96 * Returns either a sp<Interface> or a std::shared_ptr<Interface> from
97 * the NDK/CPP base interface class.
98 */
99 template<typename Interface>
interfaceFromBase(const sp<::android::IInterface> & interface)100 sp<Interface> interfaceFromBase(const sp<::android::IInterface> &interface) {
101 // this is unvalidated, though could verify getInterfaceDescriptor() == Interface::descriptor
102 return sp<Interface>::cast(interface);
103 }
104
105 template<typename Interface>
interfaceFromBase(const std::shared_ptr<::ndk::ICInterface> & interface)106 std::shared_ptr<Interface> interfaceFromBase(
107 const std::shared_ptr<::ndk::ICInterface> &interface) {
108 // this is unvalidated, though could verify
109 // !strcmp(AIBinder_Class_getDescriptor(AIBinder_getClass(...), Interface::descriptor)
110 return std::static_pointer_cast<Interface>(interface);
111 }
112
113 /**
114 * Returns a fully qualified service name.
115 *
116 * @param name
117 * If name is empty, it returns the name from the Service descriptor.
118 * If name starts with '/', it appends the name as a version to the Service descriptor,
119 * e.g. "/default".
120 * Otherwise the name is assumed to be the full Service name, overriding the
121 * Service descriptor.
122 */
123 template<typename Service>
fullyQualifiedServiceName(const char * const name)124 auto fullyQualifiedServiceName(const char* const name) {
125 using StringType = std::conditional_t<is_ndk<Service>, std::string, String16>;
126 return name == nullptr ? StringType(Service::descriptor)
127 : name[0] != 0 && name[0] != '/' ? StringType(name)
128 : StringType(Service::descriptor) + StringType(name);
129 }
130
131 /**
132 * Returns either a std::shared_ptr<Interface> or sp<Interface>
133 * for the AIDL interface given.
134 *
135 * A -cpp interface will return sp<Service>.
136 * A -ndk interface will return std::shared_ptr<Service>
137 *
138 * @param name if non-empty should contain either a suffix if it starts
139 * with a '/' such as "/default", or the full service name.
140 */
141 template<typename Service>
142 auto checkServicePassThrough(const char *const name = "") {
143 if constexpr(is_ndk<Service>)
144 {
145 const auto serviceName = fullyQualifiedServiceName<Service>(name);
146 return Service::fromBinder(
147 ::ndk::SpAIBinder(AServiceManager_checkService(serviceName.c_str())));
148 } else /* constexpr */ {
149 const auto serviceName = fullyQualifiedServiceName<Service>(name);
150 auto binder = defaultServiceManager()->checkService(serviceName);
151 return interface_cast<Service>(binder);
152 }
153 }
154
155 template<typename Service>
addService(const std::shared_ptr<Service> & service)156 void addService(const std::shared_ptr<Service> &service) {
157 AServiceManager_addService(binderFromInterface(service), Service::descriptor);
158 }
159
160 template<typename Service>
addService(const sp<Service> & service)161 void addService(const sp<Service> &service) {
162 defaultServiceManager()->addService(Service::descriptor, binderFromInterface(service));
163 }
164
165 namespace details {
166
167 // Use the APIs below, not the details here.
168
169 /**
170 * RequestServiceManagerCallback(Cpp|Ndk) is a RAII class that
171 * requests a ServiceManager callback.
172 *
173 * Note the ServiceManager is a single threaded "apartment" and only one
174 * transaction is active, hence:
175 *
176 * 1) After the RequestServiceManagerCallback object is destroyed no
177 * calls to the onBinder function is pending or will occur.
178 * 2) To prevent deadlock, do not construct or destroy the class with
179 * a lock held that the onService function also requires.
180 */
181 template<typename Service>
182 class RequestServiceManagerCallbackCpp {
183 public:
184 explicit RequestServiceManagerCallbackCpp(
185 std::function<void(const sp<Service> &)> &&onService,
186 const char *const serviceName = ""
187 )
188 : mServiceName{fullyQualifiedServiceName<Service>(serviceName)},
189 mWaiter{sp<Waiter>::make(std::move(onService))},
190 mStatus{defaultServiceManager()->registerForNotifications(mServiceName,
191 mWaiter)} {
192 }
193
~RequestServiceManagerCallbackCpp()194 ~RequestServiceManagerCallbackCpp() {
195 if (mStatus == OK) {
196 defaultServiceManager()->unregisterForNotifications(mServiceName, mWaiter);
197 }
198 }
199
getStatus()200 status_t getStatus() const {
201 return mStatus;
202 }
203
204 private:
205 const String16 mServiceName;
206 const sp<IServiceManager::LocalRegistrationCallback> mWaiter;
207 const status_t mStatus;
208
209 // With some work here, we could make this a singleton to improve
210 // performance and reduce binder clutter.
211 class Waiter : public IServiceManager::LocalRegistrationCallback {
212 public:
Waiter(std::function<void (const sp<Service> &)> && onService)213 explicit Waiter(std::function<void(const sp<Service> &)> &&onService)
214 : mOnService{std::move(onService)} {}
215
216 private:
onServiceRegistration(const String16 &,const sp<IBinder> & binder)217 void onServiceRegistration(
218 const String16 & /*name*/, const sp<IBinder> &binder) final {
219 mOnService(interface_cast<Service>(binder));
220 }
221
222 const std::function<void(const sp<Service> &)> mOnService;
223 };
224 };
225
226 template<typename Service>
227 class RequestServiceManagerCallbackNdk {
228 public:
229 explicit RequestServiceManagerCallbackNdk(
230 std::function<void(const std::shared_ptr<Service> &)> &&onService,
231 const char *const serviceName = ""
232 )
233 : mServiceName{fullyQualifiedServiceName<Service>(serviceName)},
234 mOnService{std::move(onService)},
235 mWaiter{AServiceManager_registerForServiceNotifications(
236 mServiceName.c_str(),
237 onRegister, this)} // must be registered after mOnService.
238 {}
239
~RequestServiceManagerCallbackNdk()240 ~RequestServiceManagerCallbackNdk() {
241 if (mWaiter) {
242 AServiceManager_NotificationRegistration_delete(mWaiter);
243 }
244 }
245
getStatus()246 status_t getStatus() const {
247 return mWaiter != nullptr ? OK : INVALID_OPERATION;
248 }
249
250 private:
251 const std::string mServiceName; // must keep a local copy.
252 const std::function<void(const std::shared_ptr<Service> &)> mOnService;
253 AServiceManager_NotificationRegistration *const mWaiter; // last.
254
onRegister(const char * instance,AIBinder * registered,void * cookie)255 static void onRegister(const char *instance, AIBinder *registered, void *cookie) {
256 (void) instance;
257 auto *callbackHandler = static_cast<RequestServiceManagerCallbackNdk<Service> *>(cookie);
258 callbackHandler->mOnService(Service::fromBinder(::ndk::SpAIBinder(registered)));
259 }
260 };
261
262 /**
263 * RequestDeathNotification(Cpp|Ndk) is a RAII class that
264 * requests a death notification.
265 *
266 * Note the ServiceManager is a single threaded "apartment" and only one
267 * transaction is active, hence:
268 *
269 * 1) After the RequestDeathNotification object is destroyed no
270 * calls to the onBinder function is pending or will occur.
271 * 2) To prevent deadlock, do not construct or destroy the class with
272 * a lock held that the onBinderDied function also requires.
273 */
274
275 class RequestDeathNotificationCpp {
276 class DeathRecipientHelper : public IBinder::DeathRecipient {
277 public:
DeathRecipientHelper(std::function<void ()> && onBinderDied)278 explicit DeathRecipientHelper(std::function<void()> &&onBinderDied)
279 : mOnBinderDied{std::move(onBinderDied)} {
280 }
281
binderDied(const wp<IBinder> & weakBinder)282 void binderDied(const wp<IBinder> &weakBinder) final {
283 (void) weakBinder;
284 mOnBinderDied();
285 }
286
287 private:
288 const std::function<void()> mOnBinderDied;
289 };
290
291 public:
RequestDeathNotificationCpp(const sp<IBinder> & binder,std::function<void ()> && onBinderDied)292 RequestDeathNotificationCpp(const sp<IBinder> &binder,
293 std::function<void()> &&onBinderDied)
294 : mHelper{sp<DeathRecipientHelper>::make(std::move(onBinderDied))},
295 mWeakBinder{binder}, mStatus{binder->linkToDeath(mHelper)} {
296 ALOGW_IF(mStatus != OK, "%s: linkToDeath status:%d", __func__, mStatus);
297 }
298
~RequestDeathNotificationCpp()299 ~RequestDeathNotificationCpp() {
300 if (mStatus == OK) {
301 const auto binder = mWeakBinder.promote();
302 if (binder) binder->unlinkToDeath(mHelper);
303 }
304 }
305
getStatus()306 status_t getStatus() const {
307 return mStatus;
308 }
309
310 private:
311 const sp<DeathRecipientHelper> mHelper;
312 const wp<IBinder> mWeakBinder;
313 const status_t mStatus;
314 };
315
316 class RequestDeathNotificationNdk {
317 public:
RequestDeathNotificationNdk(const::ndk::SpAIBinder & binder,std::function<void ()> && onBinderDied)318 RequestDeathNotificationNdk(
319 const ::ndk::SpAIBinder &binder, std::function<void()>&& onBinderDied)
320 : mRecipient(::AIBinder_DeathRecipient_new(OnBinderDiedStatic),
321 &AIBinder_DeathRecipient_delete),
322 mStatus{(AIBinder_DeathRecipient_setOnUnlinked( // sets cookie deleter
323 mRecipient.get(), OnBinderDiedUnlinkedStatic),
324 AIBinder_linkToDeath( // registers callback
325 binder.get(), mRecipient.get(),
326 // we create functional cookie ptr which may outlive this object.
327 new std::function<void()>(std::move(onBinderDied))))} {
328 ALOGW_IF(mStatus != OK, "%s: AIBinder_linkToDeath status:%d", __func__, mStatus);
329 }
330
~RequestDeathNotificationNdk()331 ~RequestDeathNotificationNdk() {
332 // mRecipient's unique_ptr calls AIBinder_DeathRecipient_delete to unlink the recipient.
333 // Then OnBinderDiedUnlinkedStatic eventually deletes the cookie.
334 }
335
getStatus()336 status_t getStatus() const {
337 return mStatus;
338 }
339
340 private:
OnBinderDiedUnlinkedStatic(void * cookie)341 static void OnBinderDiedUnlinkedStatic(void* cookie) {
342 delete reinterpret_cast<std::function<void()>*>(cookie);
343 }
344
OnBinderDiedStatic(void * cookie)345 static void OnBinderDiedStatic(void* cookie) {
346 (*reinterpret_cast<std::function<void()>*>(cookie))();
347 }
348
349 const std::unique_ptr<AIBinder_DeathRecipient, decltype(
350 &AIBinder_DeathRecipient_delete)>
351 mRecipient;
352 const status_t mStatus; // binder_status_t is a limited subset of status_t
353 };
354
355 } // details
356
357 /**
358 * Requests a notification that service is available.
359 *
360 * An opaque handle is returned - after clearing it is guaranteed that
361 * no callback will occur.
362 *
363 * The callback will be of form:
364 * onService(const sp<Service>& service);
365 * onService(const std::shared_ptr<Service>& service);
366 */
367 template<typename Service, typename F>
368 std::shared_ptr<void> requestServiceNotification(
369 F onService, const char *const serviceName = "") {
370 // the following are used for callbacks but placed here for invalidate.
371 using RequestServiceManagerCallback = std::conditional_t<is_ndk<Service>,
372 details::RequestServiceManagerCallbackNdk<Service>,
373 details::RequestServiceManagerCallbackCpp<Service>>;
374 const auto ptr = std::make_shared<RequestServiceManagerCallback>(
375 onService, serviceName);
376 const auto status = ptr->getStatus();
377 return status == OK ? ptr : nullptr;
378 }
379
380 /**
381 * Requests a death notification.
382 *
383 * An opaque handle is returned. If the service is already dead, the
384 * handle will be null.
385 *
386 * Implementation detail: A callback may occur after the handle is released
387 * if a death notification is in progress.
388 *
389 * The callback will be of form void onBinderDied();
390 */
391 template<typename Service>
requestDeathNotification(const sp<Service> & service,std::function<void ()> && onBinderDied)392 std::shared_ptr<void> requestDeathNotification(
393 const sp<Service> &service, std::function<void()> &&onBinderDied) {
394 const auto ptr = std::make_shared<details::RequestDeathNotificationCpp>(
395 binderFromInterface(service), std::move(onBinderDied));
396 const auto status = ptr->getStatus();
397 return status == OK ? ptr : nullptr;
398 }
399
400 template<typename Service>
requestDeathNotification(const std::shared_ptr<Service> & service,std::function<void ()> && onBinderDied)401 std::shared_ptr<void> requestDeathNotification(
402 const std::shared_ptr<Service> &service, std::function<void()> &&onBinderDied) {
403 const auto ptr = std::make_shared<details::RequestDeathNotificationNdk>(
404 binderFromInterface(service), std::move(onBinderDied));
405 const auto status = ptr->getStatus();
406 return status == OK ? ptr : nullptr;
407 }
408
409 } // namespace android::mediautils
410