Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d6346073 authored by Andy Hung's avatar Andy Hung
Browse files

audioserver: do not prefetch audioserver services

ServiceManager may provide stale audioserver service handles
to the new audioserver instance when it is reinitializing.

Flag: EXEMPT bugfix
Test: for run in {1..100}; do (sleep 8; echo $run; adb shell pkill audioserver); done
Test: atest service_singleton_tests
Test: atest CtsMediaAudioTestCases
Bug: 379427790
Change-Id: Ifc237bdfecca308f8a7c5be1b82612293df8aed9
parent 44581dda
Loading
Loading
Loading
Loading
+17 −6
Original line number Diff line number Diff line
@@ -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 @@ public:
            if (!mDisableThreadPoolStart) {
                ProcessState::self()->startThreadPool();
            }
            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 @@ public:
            if (!mDisableThreadPoolStart) {
                ProcessState::self()->startThreadPool();
            }
            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;
+60 −38
Original line number Diff line number Diff line
@@ -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 @@ public:
        std::swap(oldTraits, mTraits);
        const bool existing = oldTraits != nullptr;
        mTraits = std::move(traits);
        mSkip = false;
        mSkipMode = SkipMode::kNone;
        return existing;
    }

@@ -154,7 +162,8 @@ public:
        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,8 +173,10 @@ public:

        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;

            int options = 0;
            if (mSkipMode == SkipMode::kNone) {
                const auto traits = getTraits_l<Service>();

                // first time or not using callback, check the service.
@@ -187,16 +198,19 @@ public:
                        return service_fixed;
                    }
                }

                // 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 @@ public:
     *
     * 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 @@ private:
        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 @@ private:
    // 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 @@ void setService(const InterfaceType<Service>& service) {
 * 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
+36 −0
Original line number Diff line number Diff line
@@ -299,6 +299,42 @@ TEST(service_singleton_tests, one_and_only) {
    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());