• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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