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 "BinderGenericUtils.h"
20
21 #include <android-base/thread_annotations.h>
22 #include <audio_utils/mutex.h>
23 #include <chrono>
24 #include <map>
25 #include <mutex>
26 #include <utils/Log.h>
27 #include <utils/Timers.h>
28
29 /**
30 * ServiceSingleton provides a non-blocking NDK/CPP compatible service cache.
31 *
32 * This is a specialized cache that allows per-service configuration.
33 *
34 * Features:
35 *
36 * 1) Seamless compatibility with NDK and CPP based interfaces.
37 * 2) Time-out based service acquisition.
38 * Set the maximum time to wait for any service.
39 * 3) Service prefetch:
40 * Reduce start-up by prefetching service in advance (not on demand).
41 * Prefetch is automatically installed by getService().
42 * 4) Manual interface setting for test and non-service manager acquisition support.
43 *
44 * If both NDK and CPP interfaces are available, we prefer the CPP version
45 * for the following reasons:
46 * 1) Established sp<> reference counting avoids mistakes. NDK tends to be error-prone.
47 * 2) Possible reduced binder object clutter by a singleton notification binder object.
48 * Fewer binder objects are more efficient for the binder driver and ServiceManager.
49 * For example, fewer binder deaths means less ServiceManager (linear time) cleanup.
50 * A single binder object also offers binder access serialization.
51 * 3) CPP offers slightly better efficiency as it is closer to the
52 * actual implementation, a minor detail and effect.
53 *
54 * We use a per-service ServiceHandler object to collect methods and implementation details.
55 * Currently this is separate for NDK and CPP interfaces to the same service;
56 * unification is possible by using ibinder_internals.h.
57 */
58 namespace android::mediautils {
59
60 enum class ServiceOptions {
61 kNone = 0,
62 kNonNull = (1 << 0), // don't return a null interface unless disabled.
63 // partially implemented and experimental.
64 };
65
66 enum class SkipMode {
67 kNone = 0, // do not skip the cache (normal behavior for caching services).
68 kImmediate = 1, // do not cache or find the service, return null to the caller immediately,
69 // which is the normal behavior for skipping the service cache.
70 kWait = 2, // do not cache or find the service, but block the caller;
71 // this is used for cases where a local service override is desired.
72 };
73
74 // Traits may come through a constexpr static function collection.
75 // This participates in small buffer optimization SBO in std::function impl.
76 template <typename Service>
77 struct DefaultServiceTraits {
78 // getServiceName() returns the name associated with Service.
79 //
80 // If name is empty, it returns the name from the Service descriptor.
81 // If name starts with '/', it appends the name as a version to the Service descriptor,
82 // e.g. "/default".
83 // Otherwise the name is assumed to be the Service name.
getServiceNameDefaultServiceTraits84 static constexpr const char* getServiceName() { return "/default"; }
85
86 // This callback is called when a new service is received.
87 // The callback requires at least one thread in the Binder threadpool.
onNewServiceDefaultServiceTraits88 static constexpr void onNewService(const InterfaceType<Service>&) {}
89
90 // This callback is called if the service has died.
91 // The callback requires at least one thread in the Binder threadpool.
onServiceDiedDefaultServiceTraits92 static constexpr void onServiceDied(const InterfaceType<Service>&) {}
93
94 // ServiceOptions configured for the Service.
optionsDefaultServiceTraits95 static constexpr ServiceOptions options() { return ServiceOptions::kNone; }
96 };
97
98 // We store the traits as functors.
99 template <typename Service>
100 struct FunctionalServiceTraits {
101 template <typename ServiceTraits>
FunctionalServiceTraitsFunctionalServiceTraits102 explicit FunctionalServiceTraits(const ServiceTraits& serviceTraits)
103 : getServiceName{serviceTraits.getServiceName}
104 , onNewService{serviceTraits.onNewService}
105 , onServiceDied{serviceTraits.onServiceDied}
106 , options{serviceTraits.options} {
107 }
108 std::function<const char*()> getServiceName;
109 std::function<void(const InterfaceType<Service>& service)> onNewService;
110 std::function<void(const InterfaceType<Service>& service)> onServiceDied;
111 std::function<ServiceOptions()> options;
112 };
113
114 namespace details {
115
116 class ServiceHandler
117 {
118 public:
119 /**
120 * Returns a ServiceHandler, templated type T is String16 for the native type
121 * of the CPP service descriptors and const char* for the native type of the NDK
122 * service descriptors.
123 */
124 template<typename T>
125 requires (std::is_same_v<T, const char*> || std::is_same_v<T, String16>)
126 static std::shared_ptr<ServiceHandler> getInstance(const T& name);
127
128 /**
129 * Initializes the service handler with new service traits
130 * (methods that are triggered on service events).
131 *
132 * This is optional. Default construction of traits is allowed for
133 * services that do not require special handling.
134 *
135 * @param serviceTraits
136 * @return true if the service handler had been previously initialized.
137 */
138 template<typename Service, typename ServiceTraits>
init(const ServiceTraits & serviceTraits)139 bool init(const ServiceTraits& serviceTraits) {
140 auto traits = std::make_shared<FunctionalServiceTraits<Service>>(serviceTraits);
141 std::shared_ptr<void> oldTraits;
142 std::lock_guard l(mMutex);
143 std::swap(oldTraits, mTraits);
144 const bool existing = oldTraits != nullptr;
145 mTraits = std::move(traits);
146 mSkipMode = SkipMode::kNone;
147 return existing;
148 }
149
150 /**
151 * Returns the service based on a timeout.
152 *
153 * @param waitNs the time to wait, internally clamped to (0, INT64_MAX / 2) to
154 * avoid numeric overflow.
155 * @param useCallback installs a callback instead of polling.
156 * the Callback persists if the call timeouts. A Callback requires
157 * at least one thread in the threadpool.
158 * @return Service interface.
159 */
160 template <typename Service>
get(std::chrono::nanoseconds waitNs,bool useCallback)161 auto get(std::chrono::nanoseconds waitNs, bool useCallback) {
162 audio_utils::unique_lock ul(mMutex);
163 auto& service = std::get<BaseInterfaceType<Service>>(mService);
164
165 // early check.
166 if (mSkipMode == SkipMode::kImmediate || (service && mValid)) return service;
167
168 // clamp to avoid numeric overflow. INT64_MAX / 2 is effectively forever for a device.
169 std::chrono::nanoseconds kWaitLimitNs(
170 std::numeric_limits<decltype(waitNs.count())>::max() / 2);
171 waitNs = std::clamp(waitNs, decltype(waitNs)(0), kWaitLimitNs);
172 const auto end = std::chrono::steady_clock::now() + waitNs;
173
174 for (bool first = true; true; first = false) {
175 // we may have released mMutex, so see if service has been obtained.
176 if (mSkipMode == SkipMode::kImmediate || (service && mValid)) return service;
177
178 int options = 0;
179 if (mSkipMode == SkipMode::kNone) {
180 const auto traits = getTraits_l<Service>();
181
182 // first time or not using callback, check the service.
183 if (first || !useCallback) {
184 auto service_new = checkServicePassThrough<Service>(
185 traits->getServiceName());
186 if (service_new) {
187 mValid = true;
188 service = std::move(service_new);
189 // service is a reference, so we copy to service_fixed as
190 // we're releasing the mutex.
191 const auto service_fixed = service;
192 ul.unlock();
193 traits->onNewService(interfaceFromBase<Service>(service_fixed));
194 ul.lock();
195 setDeathNotifier_l<Service>(service_fixed);
196 ul.unlock();
197 mCv.notify_all();
198 return service_fixed;
199 }
200 }
201 // install service callback if needed.
202 if (useCallback && !mServiceNotificationHandle) {
203 setServiceNotifier_l<Service>();
204 }
205 options = static_cast<int>(traits->options());
206 }
207
208 // check time expiration.
209 const auto now = std::chrono::steady_clock::now();
210 if (now >= end &&
211 (service
212 || mSkipMode != SkipMode::kNone // skip is set.
213 || !(options & static_cast<int>(ServiceOptions::kNonNull)))) { // null allowed
214 return service;
215 }
216
217 // compute time to wait, then wait.
218 if (mServiceNotificationHandle) {
219 mCv.wait_until(ul, end);
220 } else {
221 const auto target = now + kPollTime;
222 mCv.wait_until(ul, std::min(target, end));
223 }
224 // loop back to see if we have any state change.
225 }
226 }
227
228 /**
229 * Sets an externally provided service override.
230 *
231 * @param Service
232 * @param service_new
233 */
234 template<typename Service>
set(const InterfaceType<Service> & service_new)235 void set(const InterfaceType<Service>& service_new) {
236 audio_utils::unique_lock ul(mMutex);
237 auto& service = std::get<BaseInterfaceType<Service>>(mService);
238 const auto traits = getTraits_l<Service>();
239 if (service) {
240 auto orig_service = service;
241 invalidateService_l<Service>();
242 ul.unlock();
243 traits->onServiceDied(interfaceFromBase<Service>(orig_service));
244 }
245 service = service_new;
246 ul.unlock();
247 // should we set the death notifier? It could be a local service.
248 if (service_new) traits->onNewService(service_new);
249 mCv.notify_all();
250 }
251
252 /**
253 * Disables cache management in the ServiceHandler. init() needs to be
254 * called to restart.
255 *
256 * All notifiers removed.
257 * Service pointer is released.
258 *
259 * If skipMode is kNone, then cache management is immediately reenabled.
260 * If skipMode is kImmediate, then any new waiters will return null immediately.
261 * If skipMode is kWait, then any new waiters will be blocked until an update occurs
262 * or the timeout expires.
263 */
264 template<typename Service>
skip(SkipMode skipMode)265 void skip(SkipMode skipMode) {
266 audio_utils::unique_lock ul(mMutex);
267 mSkipMode = skipMode;
268 // remove notifiers. OK to hold lock as presuming notifications one-way
269 // or manually triggered outside of lock.
270 mDeathNotificationHandle.reset();
271 mServiceNotificationHandle.reset();
272 auto& service = std::get<BaseInterfaceType<Service>>(mService);
273 const auto traits = getTraits_l<Service>();
274 std::shared_ptr<void> oldTraits;
275 std::swap(oldTraits, mTraits); // destroyed outside of lock.
276 if (service) {
277 auto orig_service = service; // keep reference to service to manually notify death.
278 invalidateService_l<Service>(); // sets service to nullptr
279 ul.unlock();
280 traits->onServiceDied(interfaceFromBase<Service>(orig_service));
281 } else {
282 ul.unlock();
283 }
284 mCv.notify_all();
285 }
286
287 private:
288
289 // invalidateService_l is called to remove the old death notifier,
290 // invalidate the service, and optionally clear the service pointer.
291 template <typename Service>
invalidateService_l()292 void invalidateService_l() REQUIRES(mMutex) {
293 mDeathNotificationHandle.reset();
294 const auto traits = getTraits_l<Service>();
295 mValid = false;
296 if (!(static_cast<int>(traits->options()) & static_cast<int>(ServiceOptions::kNonNull))
297 || mSkipMode != SkipMode::kNone) {
298 auto &service = std::get<BaseInterfaceType<Service>>(mService);
299 service = nullptr;
300 }
301 }
302
303 // gets the traits set by init(), initializes with default if init() not called.
304 template <typename Service>
getTraits_l()305 std::shared_ptr<FunctionalServiceTraits<Service>> getTraits_l() REQUIRES(mMutex) {
306 if (!mTraits) {
307 mTraits = std::make_shared<FunctionalServiceTraits<Service>>(
308 DefaultServiceTraits<Service>{});
309 }
310 return std::static_pointer_cast<FunctionalServiceTraits<Service>>(mTraits);
311 }
312
313 // sets the service notification
314 template <typename Service>
setServiceNotifier_l()315 void setServiceNotifier_l() REQUIRES(mMutex) {
316 const auto traits = getTraits_l<Service>();
317 mServiceNotificationHandle = requestServiceNotification<Service>(
318 [traits, this](const InterfaceType<Service>& service) {
319 audio_utils::unique_lock ul(mMutex);
320 auto originalService = std::get<BaseInterfaceType<Service>>(mService);
321 // we suppress equivalent services from being set
322 // where either the pointers match or the binder objects match.
323 if (!mediautils::isSameInterface(originalService, service)) {
324 if (originalService != nullptr) {
325 invalidateService_l<Service>();
326 }
327 mService = service;
328 mValid = true;
329 ul.unlock();
330 if (originalService != nullptr) {
331 traits->onServiceDied(interfaceFromBase<Service>(originalService));
332 }
333 traits->onNewService(service);
334 ul.lock();
335 setDeathNotifier_l<Service>(service);
336 } else {
337 ALOGW("%s: ignoring duplicated service: %p",
338 __func__, originalService.get());
339 }
340 ul.unlock();
341 mCv.notify_all();
342 }, traits->getServiceName());
343 ALOGW_IF(!mServiceNotificationHandle, "%s: cannot register service notification %s"
344 " (do we have permission?)",
345 __func__, toString(Service::descriptor).c_str());
346 }
347
348 // sets the death notifier for mService (mService must be non-null).
349 template <typename Service>
setDeathNotifier_l(const BaseInterfaceType<Service> & base)350 void setDeathNotifier_l(const BaseInterfaceType<Service>& base) REQUIRES(mMutex) {
351 // here the pointer match should be identical to binder object match
352 // since we use a cached service.
353 if (base != std::get<BaseInterfaceType<Service>>(mService)) {
354 ALOGW("%s: service has changed for %s, skipping death notification registration",
355 __func__, toString(Service::descriptor).c_str());
356 return;
357 }
358 auto service = interfaceFromBase<Service>(base);
359 const auto binder = binderFromInterface(service);
360 if (binder.get()) {
361 auto traits = getTraits_l<Service>();
362 mDeathNotificationHandle = requestDeathNotification(
363 base, [traits, service, this]() {
364 // as only one death notification is dispatched,
365 // we do not need to generation count.
366 {
367 std::lock_guard l(mMutex);
368 const auto currentService =
369 std::get<BaseInterfaceType<Service>>(mService);
370 if (currentService != service) {
371 ALOGW("%s: ignoring death as current service "
372 "%p != registered death service %p", __func__,
373 currentService.get(), service.get());
374 return;
375 }
376 invalidateService_l<Service>();
377 }
378 traits->onServiceDied(service);
379 });
380 // Implementation detail: if the service has already died,
381 // we do not call the death notification, but log the issue here.
382 ALOGW_IF(!mDeathNotificationHandle, "%s: cannot register death notification %s"
383 " (already died?)",
384 __func__, toString(Service::descriptor).c_str());
385 }
386 }
387
388 // initializes the variant for NDK use (called on first creation in the cache map).
init_ndk()389 void init_ndk() EXCLUDES(mMutex) {
390 std::lock_guard l(mMutex);
391 mService = std::shared_ptr<::ndk::ICInterface>{};
392 }
393
394 // initializes the variant for CPP use (called on first creation in the cache map).
init_cpp()395 void init_cpp() EXCLUDES(mMutex) {
396 std::lock_guard l(mMutex);
397 mService = sp<::android::IInterface>{};
398 }
399
toString(const std::string & s)400 static std::string toString(const std::string& s) { return s; }
toString(const String16 & s)401 static std::string toString(const String16& s) { return String8(s).c_str(); }
402
403 mutable std::mutex mMutex;
404 std::condition_variable mCv;
405 static constexpr auto kPollTime = std::chrono::seconds(1);
406
407 std::variant<std::shared_ptr<::ndk::ICInterface>,
408 sp<::android::IInterface>> mService GUARDED_BY(mMutex);
409 // aesthetically we place these last, but a ServiceHandler is never deleted in
410 // current operation, so there is no deadlock on destruction.
411 std::shared_ptr<void> mDeathNotificationHandle GUARDED_BY(mMutex);
412 std::shared_ptr<void> mServiceNotificationHandle GUARDED_BY(mMutex);
413 std::shared_ptr<void> mTraits GUARDED_BY(mMutex);
414
415 // mValid is true iff the service is non-null and alive.
416 bool mValid GUARDED_BY(mMutex) = false;
417
418 // mSkipMode indicates the service cache state:
419 //
420 // one may either wait (blocked) until the service is reinitialized.
421 SkipMode mSkipMode GUARDED_BY(mMutex) = SkipMode::kNone;
422 };
423
424 } // details
425
426 //----------------------------------
427 // ServiceSingleton API
428 //
429
430 /*
431 * Implementation detail:
432 *
433 * Each CPP or NDK service interface has a unique ServiceHandler that
434 * is stored in a singleton cache. The cache key is based on the service descriptor string
435 * so only one version can be chosen. (The particular version may be changed using
436 * ServiceTraits.getName()).
437 */
438
439 /**
440 * Sets the service trait parameters for acquiring the Service interface.
441 *
442 * If this is not set before the first service fetch, then default service traits are used.
443 *
444 * @return true if there is a preexisting (including prior default set) traits.
445 */
446 template<typename Service, typename ServiceTraits>
447 bool initService(const ServiceTraits& serviceTraits = {}) {
448 const auto serviceHandler = details::ServiceHandler::getInstance(Service::descriptor);
449 return serviceHandler->template init<Service>(serviceTraits);
450 }
451
452 /**
453 * Returns either a std::shared_ptr<Interface> or sp<Interface>
454 * for the AIDL service. If the service is not available within waitNs,
455 * the method will return nullptr
456 * (or the previous invalidated service if Service.options() & kNonNull).
457 *
458 * This method installs a callback to obtain the service, so with waitNs == 0, it may be used to
459 * prefetch the service before it is actually needed.
460 *
461 * @param waitNs wait time for the service to become available.
462 * @return
463 * a sp<> for a CPP interface
464 * a std::shared_ptr<> for a NDK interface
465 *
466 */
467 template<typename Service>
468 auto getService(std::chrono::nanoseconds waitNs = {}) {
469 const auto serviceHandler = details::ServiceHandler::getInstance(Service::descriptor);
470 return interfaceFromBase<Service>(serviceHandler->template get<Service>(
471 waitNs, true /* useCallback */));
472 }
473
474 /**
475 * Returns either a std::shared_ptr<Interface> or sp<Interface>
476 * for the AIDL service. If the service is not available within waitNs,
477 * the method will return nullptr
478 * (or the previous invalidated service if Service.options() & kNonNull).
479 *
480 * This method polls to obtain the service, which
481 * is useful if the service is restricted due to permissions or
482 * one is concerned about ThreadPool starvation.
483 *
484 * @param waitNs wait time for the service to become available.
485 * @return
486 * a sp<> for a CPP interface
487 * a std::shared_ptr<> for a NDK interface
488 */
489 template<typename Service>
490 auto checkService(std::chrono::nanoseconds waitNs = {}) {
491 const auto serviceHandler = details::ServiceHandler::getInstance(Service::descriptor);
492 return interfaceFromBase<Service>(serviceHandler->template get<Service>(
493 waitNs, false /* useCallback */));
494 }
495
496 /**
497 * Sets a service implementation override, replacing any fetched service from ServiceManager.
498 *
499 * An empty service clears the cache.
500 */
501 template<typename Service>
setService(const InterfaceType<Service> & service)502 void setService(const InterfaceType<Service>& service) {
503 const auto serviceHandler = details::ServiceHandler::getInstance(Service::descriptor);
504 serviceHandler->template set<Service>(service);
505 }
506
507 /**
508 * Disables the service cache.
509 *
510 * This releases any service and notification callbacks. After this,
511 * another initService() can be called seamlessly.
512 */
513 template<typename Service>
514 void skipService(SkipMode skipMode = SkipMode::kImmediate) {
515 const auto serviceHandler = details::ServiceHandler::getInstance(Service::descriptor);
516 serviceHandler->template skip<Service>(skipMode);
517 }
518
519 } // namespace android::mediautils
520