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