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

Commit ce7e4aa4 authored by Andy Hung's avatar Andy Hung Committed by Android (Google) Code Review
Browse files

Merge "ServiceSingleton: prevent recaching an equivalent interface" into main

parents 07922917 37d5d6ba
Loading
Loading
Loading
Loading
+18 −0
Original line number Diff line number Diff line
@@ -58,6 +58,24 @@ template<typename Interface>
    return interface->asBinder();
}

/**
 * Returns true if two interfaces pointer-match, or represent identical binder objects.
 *
 * C++ with C++ and NDK with NDK interfaces may be compared.
 *
 * It currently isn't possible through the NDK public interface to extract
 * the underlying C++ binder object, so we don't allow NDK and C++ interfaces to
 * be cross-checked even though they might be backed by the same binder object.
 */
static inline bool isSameInterface(const sp<IInterface>& a, const sp<IInterface>& b) {
    return a == b || (a && b && IInterface::asBinder(a) == IInterface::asBinder(b));
}

static inline bool isSameInterface(const std::shared_ptr<::ndk::ICInterface>& a,
        const std::shared_ptr<::ndk::ICInterface>& b) {
    return a == b || (a && b && a->asBinder() == b->asBinder());
}

/**
 * Returns either a sp<Interface> or a std::shared_ptr<Interface> from a Binder object.
 *
+5 −1
Original line number Diff line number Diff line
@@ -318,7 +318,9 @@ private:
                [traits, this](const InterfaceType<Service>& service) {
                    audio_utils::unique_lock ul(mMutex);
                    auto originalService = std::get<BaseInterfaceType<Service>>(mService);
                    if (originalService != service) {
                    // we suppress equivalent services from being set
                    // where either the pointers match or the binder objects match.
                    if (!mediautils::isSameInterface(originalService, service)) {
                        if (originalService != nullptr) {
                            invalidateService_l<Service>();
                        }
@@ -346,6 +348,8 @@ private:
    // sets the death notifier for mService (mService must be non-null).
    template <typename Service>
    void setDeathNotifier_l(const BaseInterfaceType<Service>& base) REQUIRES(mMutex) {
        // here the pointer match should be identical to binder object match
        // since we use a cached service.
        if (base != std::get<BaseInterfaceType<Service>>(mService)) {
            ALOGW("%s: service has changed for %s, skipping death notification registration",
                    __func__, toString(Service::descriptor).c_str());
+26 −0
Original line number Diff line number Diff line
@@ -251,9 +251,35 @@ TEST(service_singleton_tests, one_and_only) {
        auto service = mediautils::getService<IServiceSingletonTest>();
        EXPECT_TRUE(service);

        // mediautils::getService<> is a cached service.
        // pointer equality is preserved for subsequent requests.
        auto service_equal = mediautils::getService<IServiceSingletonTest>();
        EXPECT_EQ(service, service_equal);
        EXPECT_TRUE(mediautils::isSameInterface(service, service_equal));

        // we can create an alias to the service by requesting it outside of the cache.
        // this is a different pointer, but same underlying binder object.
        auto service_equivalent =
                mediautils::checkServicePassThrough<IServiceSingletonTest>();
        EXPECT_NE(service, service_equivalent);
        EXPECT_TRUE(mediautils::isSameInterface(service, service_equivalent));

        auto service2 = mediautils::getService<aidl::IServiceSingletonTest>();
        EXPECT_TRUE(service2);

        // mediautils::getService<> is a cached service.
        // pointer equality is preserved for subsequent requests.
        auto service2_equal = mediautils::getService<aidl::IServiceSingletonTest>();
        EXPECT_EQ(service2, service2_equal);
        EXPECT_TRUE(mediautils::isSameInterface(service2, service2_equal));

        // we can create an alias to the service by requesting it outside of the cache.
        // this is a different pointer, but same underlying binder object.
        auto service2_equivalent =
                mediautils::checkServicePassThrough<aidl::IServiceSingletonTest>();
        EXPECT_NE(service2, service2_equivalent);
        EXPECT_TRUE(mediautils::isSameInterface(service2, service2_equivalent));

        keepAlive = service2;

        // we can also request our own death notifications (outside of the service traits).