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

Commit c41f708e authored by Steven Moreland's avatar Steven Moreland Committed by android-build-merger
Browse files

Merge changes from topic "wait-for-aidl" into stage-aosp-master am: c53bc399

am: 2941ff2c

Change-Id: Idc541561aacff37a5d0858d97bbcf266b68fc066
parents a122d867 2941ff2c
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -53,7 +53,7 @@ class ServiceManagerMock : public IServiceManager {
    MOCK_CONST_METHOD1(checkService, sp<IBinder>(const String16&));
    MOCK_METHOD4(addService, status_t(const String16&, const sp<IBinder>&, bool, int));
    MOCK_METHOD1(listServices, Vector<String16>(int));

    MOCK_METHOD1(waitForService, sp<IBinder>(const String16&));
  protected:
    MOCK_METHOD0(onAsBinder, IBinder*());
};
+59 −0
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@

#include <binder/IServiceManager.h>

#include <android/os/BnServiceCallback.h>
#include <android/os/IServiceManager.h>
#include <utils/Log.h>
#include <binder/IPCThreadState.h>
@@ -212,6 +213,64 @@ public:
        return res;
    }

    sp<IBinder> waitForService(const String16& name16) override {
        class Waiter : public android::os::BnServiceCallback {
            Status onRegistration(const std::string& /*name*/,
                                  const sp<IBinder>& binder) override {
                std::unique_lock<std::mutex> lock(mMutex);
                mBinder = binder;
                lock.unlock();
                mCv.notify_one();
                return Status::ok();
            }
        public:
            sp<IBinder> mBinder;
            std::mutex mMutex;
            std::condition_variable mCv;
        };

        const std::string name = String8(name16).c_str();

        sp<IBinder> out;
        if(!mTheRealServiceManager->checkService(name, &out).isOk()) {
            return nullptr;
        }
        if(out != nullptr) return out;

        sp<Waiter> waiter = new Waiter;
        if (!mTheRealServiceManager->registerForNotifications(
                name, waiter).isOk()) {
            return nullptr;
        }

        while(true) {
            {
                std::unique_lock<std::mutex> lock(waiter->mMutex);
                using std::literals::chrono_literals::operator""s;
                waiter->mCv.wait_for(lock, 1s, [&] {
                    return waiter->mBinder != nullptr;
                });
                if (waiter->mBinder != nullptr) return waiter->mBinder;
            }

            // Handle race condition for lazy services. Here is what can happen:
            // - the service dies (not processed by init yet).
            // - sm processes death notification.
            // - sm gets checkService and calls init to start service.
            // - init gets the start signal, but the service already appears
            //   started, so it does nothing.
            // - init gets death signal, but doesn't know it needs to restart
            //   the service
            // - we need to request service again to get it to start
            if(!mTheRealServiceManager->checkService(name, &out).isOk()) {
                return nullptr;
            }
            if(out != nullptr) return out;

            ALOGW("Waited one second for %s", name.c_str());
        }
    }

private:
    sp<AidlServiceManager> mTheRealServiceManager;
};
+13 −0
Original line number Diff line number Diff line
@@ -71,10 +71,23 @@ public:
     */
    // NOLINTNEXTLINE(google-default-arguments)
    virtual Vector<String16> listServices(int dumpsysFlags = DUMP_FLAG_PRIORITY_ALL) = 0;

    /**
     * Efficiently wait for a service.
     *
     * Returns nullptr only for permission problem or fatal error.
     */
    virtual sp<IBinder> waitForService(const String16& name) = 0;
};

sp<IServiceManager> defaultServiceManager();

template<typename INTERFACE>
sp<INTERFACE> waitForService(const String16& name) {
    const sp<IServiceManager> sm = defaultServiceManager();
    return interface_cast<INTERFACE>(sm->waitForService(name));
}

template<typename INTERFACE>
status_t getService(const String16& name, sp<INTERFACE>* outService)
{