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 if (originalService != service) {
322 if (originalService != nullptr) {
323 invalidateService_l<Service>();
324 }
325 mService = service;
326 mValid = true;
327 ul.unlock();
328 if (originalService != nullptr) {
329 traits->onServiceDied(interfaceFromBase<Service>(originalService));
330 }
331 traits->onNewService(service);
332 ul.lock();
333 setDeathNotifier_l<Service>(service);
334 }
335 ul.unlock();
336 mCv.notify_all();
337 }, traits->getServiceName());
338 ALOGW_IF(!mServiceNotificationHandle, "%s: cannot register service notification %s"
339 " (do we have permission?)",
340 __func__, toString(Service::descriptor).c_str());
341 }
342
343 // sets the death notifier for mService (mService must be non-null).
344 template <typename Service>
setDeathNotifier_l(const BaseInterfaceType<Service> & base)345 void setDeathNotifier_l(const BaseInterfaceType<Service>& base) REQUIRES(mMutex) {
346 if (base != std::get<BaseInterfaceType<Service>>(mService)) {
347 ALOGW("%s: service has changed for %s, skipping death notification registration",
348 __func__, toString(Service::descriptor).c_str());
349 return;
350 }
351 auto service = interfaceFromBase<Service>(base);
352 const auto binder = binderFromInterface(service);
353 if (binder.get()) {
354 auto traits = getTraits_l<Service>();
355 mDeathNotificationHandle = requestDeathNotification(
356 base, [traits, service, this]() {
357 // as only one death notification is dispatched,
358 // we do not need to generation count.
359 {
360 std::lock_guard l(mMutex);
361 invalidateService_l<Service>();
362 }
363 traits->onServiceDied(service);
364 });
365 // Implementation detail: if the service has already died,
366 // we do not call the death notification, but log the issue here.
367 ALOGW_IF(!mDeathNotificationHandle, "%s: cannot register death notification %s"
368 " (already died?)",
369 __func__, toString(Service::descriptor).c_str());
370 }
371 }
372
373 // initializes the variant for NDK use (called on first creation in the cache map).
init_ndk()374 void init_ndk() EXCLUDES(mMutex) {
375 std::lock_guard l(mMutex);
376 mService = std::shared_ptr<::ndk::ICInterface>{};
377 }
378
379 // initializes the variant for CPP use (called on first creation in the cache map).
init_cpp()380 void init_cpp() EXCLUDES(mMutex) {
381 std::lock_guard l(mMutex);
382 mService = sp<::android::IInterface>{};
383 }
384
toString(const std::string & s)385 static std::string toString(const std::string& s) { return s; }
toString(const String16 & s)386 static std::string toString(const String16& s) { return String8(s).c_str(); }
387
388 mutable std::mutex mMutex;
389 std::condition_variable mCv;
390 static constexpr auto kPollTime = std::chrono::seconds(1);
391
392 std::variant<std::shared_ptr<::ndk::ICInterface>,
393 sp<::android::IInterface>> mService GUARDED_BY(mMutex);
394 // aesthetically we place these last, but a ServiceHandler is never deleted in
395 // current operation, so there is no deadlock on destruction.
396 std::shared_ptr<void> mDeathNotificationHandle GUARDED_BY(mMutex);
397 std::shared_ptr<void> mServiceNotificationHandle GUARDED_BY(mMutex);
398 std::shared_ptr<void> mTraits GUARDED_BY(mMutex);
399
400 // mValid is true iff the service is non-null and alive.
401 bool mValid GUARDED_BY(mMutex) = false;
402
403 // mSkipMode indicates the service cache state:
404 //
405 // one may either wait (blocked) until the service is reinitialized.
406 SkipMode mSkipMode GUARDED_BY(mMutex) = SkipMode::kNone;
407 };
408
409 } // details
410
411 //----------------------------------
412 // ServiceSingleton API
413 //
414
415 /*
416 * Implementation detail:
417 *
418 * Each CPP or NDK service interface has a unique ServiceHandler that
419 * is stored in a singleton cache. The cache key is based on the service descriptor string
420 * so only one version can be chosen. (The particular version may be changed using
421 * ServiceTraits.getName()).
422 */
423
424 /**
425 * Sets the service trait parameters for acquiring the Service interface.
426 *
427 * If this is not set before the first service fetch, then default service traits are used.
428 *
429 * @return true if there is a preexisting (including prior default set) traits.
430 */
431 template<typename Service, typename ServiceTraits>
432 bool initService(const ServiceTraits& serviceTraits = {}) {
433 const auto serviceHandler = details::ServiceHandler::getInstance(Service::descriptor);
434 return serviceHandler->template init<Service>(serviceTraits);
435 }
436
437 /**
438 * Returns either a std::shared_ptr<Interface> or sp<Interface>
439 * for the AIDL service. If the service is not available within waitNs,
440 * the method will return nullptr
441 * (or the previous invalidated service if Service.options() & kNonNull).
442 *
443 * This method installs a callback to obtain the service, so with waitNs == 0, it may be used to
444 * prefetch the service before it is actually needed.
445 *
446 * @param waitNs wait time for the service to become available.
447 * @return
448 * a sp<> for a CPP interface
449 * a std::shared_ptr<> for a NDK interface
450 *
451 */
452 template<typename Service>
453 auto getService(std::chrono::nanoseconds waitNs = {}) {
454 const auto serviceHandler = details::ServiceHandler::getInstance(Service::descriptor);
455 return interfaceFromBase<Service>(serviceHandler->template get<Service>(
456 waitNs, true /* useCallback */));
457 }
458
459 /**
460 * Returns either a std::shared_ptr<Interface> or sp<Interface>
461 * for the AIDL service. If the service is not available within waitNs,
462 * the method will return nullptr
463 * (or the previous invalidated service if Service.options() & kNonNull).
464 *
465 * This method polls to obtain the service, which
466 * is useful if the service is restricted due to permissions or
467 * one is concerned about ThreadPool starvation.
468 *
469 * @param waitNs wait time for the service to become available.
470 * @return
471 * a sp<> for a CPP interface
472 * a std::shared_ptr<> for a NDK interface
473 */
474 template<typename Service>
475 auto checkService(std::chrono::nanoseconds waitNs = {}) {
476 const auto serviceHandler = details::ServiceHandler::getInstance(Service::descriptor);
477 return interfaceFromBase<Service>(serviceHandler->template get<Service>(
478 waitNs, false /* useCallback */));
479 }
480
481 /**
482 * Sets a service implementation override, replacing any fetched service from ServiceManager.
483 *
484 * An empty service clears the cache.
485 */
486 template<typename Service>
setService(const InterfaceType<Service> & service)487 void setService(const InterfaceType<Service>& service) {
488 const auto serviceHandler = details::ServiceHandler::getInstance(Service::descriptor);
489 serviceHandler->template set<Service>(service);
490 }
491
492 /**
493 * Disables the service cache.
494 *
495 * This releases any service and notification callbacks. After this,
496 * another initService() can be called seamlessly.
497 */
498 template<typename Service>
499 void skipService(SkipMode skipMode = SkipMode::kImmediate) {
500 const auto serviceHandler = details::ServiceHandler::getInstance(Service::descriptor);
501 serviceHandler->template skip<Service>(skipMode);
502 }
503
504 } // namespace android::mediautils
505