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