Merge "audioserver: do not prefetch audioserver services" into main
diff --git a/media/libaudioclient/AudioSystem.cpp b/media/libaudioclient/AudioSystem.cpp
index d511dc2..e3a96f5 100644
--- a/media/libaudioclient/AudioSystem.cpp
+++ b/media/libaudioclient/AudioSystem.cpp
@@ -35,6 +35,7 @@
 #include <media/TypeConverter.h>
 #include <mediautils/ServiceSingleton.h>
 #include <math.h>
+#include <private/android_filesystem_config.h>
 
 #include <system/audio.h>
 #include <android/media/GetInputForAttrResponse.h>
@@ -169,9 +170,14 @@
             if (!mDisableThreadPoolStart) {
                 ProcessState::self()->startThreadPool();
             }
-            mediautils::initService<media::IAudioFlingerService, AudioFlingerServiceTraits>();
-            mWaitMs = std::chrono::milliseconds(
-                property_get_int32(kServiceWaitProperty, kServiceClientWaitMs));
+            if (multiuser_get_app_id(getuid()) == AID_AUDIOSERVER) {
+                mediautils::skipService<media::IAudioFlingerService>(mediautils::SkipMode::kWait);
+                mWaitMs = std::chrono::milliseconds(INT32_MAX);
+            } else {
+                mediautils::initService<media::IAudioFlingerService, AudioFlingerServiceTraits>();
+                mWaitMs = std::chrono::milliseconds(
+                        property_get_int32(kServiceWaitProperty, kServiceClientWaitMs));
+            }
             init = true;
         }
         if (mValid) return mService;
@@ -1015,9 +1021,14 @@
             if (!mDisableThreadPoolStart) {
                 ProcessState::self()->startThreadPool();
             }
-            mediautils::initService<IAudioPolicyService, AudioPolicyServiceTraits>();
-            mWaitMs = std::chrono::milliseconds(
-                    property_get_int32(kServiceWaitProperty, kServiceClientWaitMs));
+            if (multiuser_get_app_id(getuid()) == AID_AUDIOSERVER) {
+                mediautils::skipService<IAudioPolicyService>(mediautils::SkipMode::kWait);
+                mWaitMs = std::chrono::milliseconds(INT32_MAX);
+            } else {
+                mediautils::initService<IAudioPolicyService, AudioPolicyServiceTraits>();
+                mWaitMs = std::chrono::milliseconds(
+                        property_get_int32(kServiceWaitProperty, kServiceClientWaitMs));
+            }
             init = true;
         }
         if (mValid) return mService;
diff --git a/media/utils/include/mediautils/ServiceSingleton.h b/media/utils/include/mediautils/ServiceSingleton.h
index f3208cb..177c3ba 100644
--- a/media/utils/include/mediautils/ServiceSingleton.h
+++ b/media/utils/include/mediautils/ServiceSingleton.h
@@ -57,12 +57,20 @@
  */
 namespace android::mediautils {
 
-enum ServiceOptions {
+enum class ServiceOptions {
     kNone = 0,
     kNonNull = (1 << 0),  // don't return a null interface unless disabled.
                           // partially implemented and experimental.
 };
 
+enum class SkipMode {
+    kNone = 0,       // do not skip the cache (normal behavior for caching services).
+    kImmediate = 1,  // do not cache or find the service, return null to the caller immediately,
+                     // which is the normal behavior for skipping the service cache.
+    kWait = 2,       // do not cache or find the service, but block the caller;
+                     // this is used for cases where a local service override is desired.
+};
+
 // Traits may come through a constexpr static function collection.
 // This participates in small buffer optimization SBO in std::function impl.
 template <typename Service>
@@ -135,7 +143,7 @@
         std::swap(oldTraits, mTraits);
         const bool existing = oldTraits != nullptr;
         mTraits = std::move(traits);
-        mSkip = false;
+        mSkipMode = SkipMode::kNone;
         return existing;
     }
 
@@ -154,7 +162,8 @@
         audio_utils::unique_lock ul(mMutex);
         auto& service = std::get<BaseInterfaceType<Service>>(mService);
 
-        if (mSkip || (service && mValid)) return service;  // early check.
+        // early check.
+        if (mSkipMode == SkipMode::kImmediate || (service && mValid)) return service;
 
         // clamp to avoid numeric overflow.  INT64_MAX / 2 is effectively forever for a device.
         std::chrono::nanoseconds kWaitLimitNs(
@@ -164,39 +173,44 @@
 
         for (bool first = true; true; first = false) {
             // we may have released mMutex, so see if service has been obtained.
-            if (mSkip || (service && mValid))  return service;
+            if (mSkipMode == SkipMode::kImmediate || (service && mValid))  return service;
 
-            const auto traits = getTraits_l<Service>();
+            int options = 0;
+            if (mSkipMode == SkipMode::kNone) {
+                const auto traits = getTraits_l<Service>();
 
-            // first time or not using callback, check the service.
-            if (first || !useCallback) {
-                auto service_new = checkServicePassThrough<Service>(
-                        traits->getServiceName());
-                if (service_new) {
-                    mValid = true;
-                    service = std::move(service_new);
-                    // service is a reference, so we copy to service_fixed as
-                    // we're releasing the mutex.
-                    const auto service_fixed = service;
-                    ul.unlock();
-                    traits->onNewService(interfaceFromBase<Service>(service_fixed));
-                    ul.lock();
-                    setDeathNotifier_l<Service>(service_fixed);
-                    ul.unlock();
-                    mCv.notify_all();
-                    return service_fixed;
+                // first time or not using callback, check the service.
+                if (first || !useCallback) {
+                    auto service_new = checkServicePassThrough<Service>(
+                            traits->getServiceName());
+                    if (service_new) {
+                        mValid = true;
+                        service = std::move(service_new);
+                        // service is a reference, so we copy to service_fixed as
+                        // we're releasing the mutex.
+                        const auto service_fixed = service;
+                        ul.unlock();
+                        traits->onNewService(interfaceFromBase<Service>(service_fixed));
+                        ul.lock();
+                        setDeathNotifier_l<Service>(service_fixed);
+                        ul.unlock();
+                        mCv.notify_all();
+                        return service_fixed;
+                    }
                 }
-            }
-
-            // install service callback if needed.
-            if (useCallback && !mServiceNotificationHandle) {
-                setServiceNotifier_l<Service>();
+                // install service callback if needed.
+                if (useCallback && !mServiceNotificationHandle) {
+                    setServiceNotifier_l<Service>();
+                }
+                options = static_cast<int>(traits->options());
             }
 
             // check time expiration.
             const auto now = std::chrono::steady_clock::now();
-            if (now >= end
-                && (service || !(traits->options() & ServiceOptions::kNonNull))) {
+            if (now >= end &&
+                    (service
+                    || mSkipMode != SkipMode::kNone  // skip is set.
+                    || !(options & static_cast<int>(ServiceOptions::kNonNull)))) { // null allowed
                 return service;
             }
 
@@ -241,11 +255,16 @@
      *
      * All notifiers removed.
      * Service pointer is released.
+     *
+     * If skipMode is kNone,      then cache management is immediately reenabled.
+     * If skipMode is kImmediate, then any new waiters will return null immediately.
+     * If skipMode is kWait,      then any new waiters will be blocked until an update occurs
+     *                            or the timeout expires.
      */
     template<typename Service>
-    void skip() {
+    void skip(SkipMode skipMode) {
         audio_utils::unique_lock ul(mMutex);
-        mSkip = true;
+        mSkipMode = skipMode;
         // remove notifiers.  OK to hold lock as presuming notifications one-way
         // or manually triggered outside of lock.
         mDeathNotificationHandle.reset();
@@ -274,7 +293,8 @@
         mDeathNotificationHandle.reset();
         const auto traits = getTraits_l<Service>();
         mValid = false;
-        if (!(traits->options() & ServiceOptions::kNonNull) || mSkip) {
+        if (!(static_cast<int>(traits->options()) & static_cast<int>(ServiceOptions::kNonNull))
+                || mSkipMode != SkipMode::kNone) {
             auto &service = std::get<BaseInterfaceType<Service>>(mService);
             service = nullptr;
         }
@@ -380,8 +400,10 @@
     // mValid is true iff the service is non-null and alive.
     bool mValid GUARDED_BY(mMutex) = false;
 
-    // mSkip indicates that the service is not cached.
-    bool mSkip GUARDED_BY(mMutex) = false;
+    // mSkipMode indicates the service cache state:
+    //
+    // one may either wait (blocked) until the service is reinitialized.
+    SkipMode mSkipMode GUARDED_BY(mMutex) = SkipMode::kNone;
 };
 
 } // details
@@ -474,9 +496,9 @@
  * another initService() can be called seamlessly.
  */
 template<typename Service>
-void skipService() {
+void skipService(SkipMode skipMode = SkipMode::kImmediate) {
     const auto serviceHandler = details::ServiceHandler::getInstance(Service::descriptor);
-    serviceHandler->template skip<Service>();
+    serviceHandler->template skip<Service>(skipMode);
 }
 
 } // namespace android::mediautils
diff --git a/media/utils/tests/service_singleton_tests.cpp b/media/utils/tests/service_singleton_tests.cpp
index 18d7f3d..3e389a4 100644
--- a/media/utils/tests/service_singleton_tests.cpp
+++ b/media/utils/tests/service_singleton_tests.cpp
@@ -299,6 +299,42 @@
     EXPECT_EQ(4, sServiceDied);
     EXPECT_EQ(4, listenerServiceCreated);  // our listener picks it up.
 
+    {
+        // in default mode (kNull) a null is returned when the service is skipped and
+        // wait time is ignored.
+
+        const auto ref1 = std::chrono::steady_clock::now();
+        auto service = mediautils::getService<IServiceSingletonTest>(std::chrono::seconds(2));
+        EXPECT_FALSE(service);
+        const auto ref2 = std::chrono::steady_clock::now();
+        EXPECT_LT(ref2 - ref1, std::chrono::seconds(1));
+
+        auto service2 = mediautils::getService<aidl::IServiceSingletonTest>(
+                std::chrono::seconds(2));
+        EXPECT_FALSE(service2);
+        const auto ref3 = std::chrono::steady_clock::now();
+        EXPECT_LT(ref3 - ref2, std::chrono::seconds(1));
+    }
+
+    // Cancel the singleton cache but use wait mode.
+    mediautils::skipService<IServiceSingletonTest>(mediautils::SkipMode::kWait);
+    mediautils::skipService<aidl::IServiceSingletonTest>(mediautils::SkipMode::kWait);
+
+    {
+        // in wait mode, the timeouts are respected
+        const auto ref1 = std::chrono::steady_clock::now();
+        auto service = mediautils::getService<IServiceSingletonTest>(std::chrono::seconds(1));
+        EXPECT_FALSE(service);
+        const auto ref2 = std::chrono::steady_clock::now();
+        EXPECT_GT(ref2 - ref1, std::chrono::seconds(1));
+
+        auto service2 = mediautils::getService<aidl::IServiceSingletonTest>(
+                std::chrono::seconds(1));
+        EXPECT_FALSE(service2);
+        const auto ref3 = std::chrono::steady_clock::now();
+        EXPECT_GT(ref3 - ref2, std::chrono::seconds(1));
+    }
+
     // remove service
     remoteWorker->putc('b');
     EXPECT_EQ('b', remoteWorker->getc());