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

Commit c9cf150e authored by Steven Moreland's avatar Steven Moreland Committed by Automerger Merge Worker
Browse files

Merge "libbinder_ndk: service notifications" am: c92d8747

parents 346212d1 c92d8747
Loading
Loading
Loading
Loading
+61 −0
Original line number Original line Diff line number Diff line
@@ -108,6 +108,67 @@ binder_status_t AServiceManager_registerLazyService(AIBinder* binder, const char
__attribute__((warn_unused_result)) AIBinder* AServiceManager_waitForService(const char* instance)
__attribute__((warn_unused_result)) AIBinder* AServiceManager_waitForService(const char* instance)
        __INTRODUCED_IN(31);
        __INTRODUCED_IN(31);


/**
 * Function to call when a service is registered. The instance is passed as well as
 * ownership of the binder named 'registered'.
 *
 * WARNING: a lock is held when this method is called in order to prevent races with
 * AServiceManager_NotificationRegistration_delete. Do not make synchronous binder calls when
 * implementing this method to avoid deadlocks.
 *
 * \param instance instance name of service registered
 * \param registered ownership-passed instance of service registered
 * \param cookie data passed during registration for notifications
 */
typedef void (*AServiceManager_onRegister)(const char* instance, AIBinder* registered,
                                           void* cookie);

/**
 * Represents a registration to servicemanager which can be cleared anytime.
 */
struct AServiceManager_NotificationRegistration;

/**
 * Get notifications when a service is registered. If the service is already registered,
 * you will immediately get a notification.
 *
 * WARNING: it is strongly recommended to use AServiceManager_waitForService API instead.
 * That API will wait synchronously, which is what you usually want in cases, including
 * using some feature or during boot up. There is a history of bugs where waiting for
 * notifications like this races with service startup. Also, when this API is used, a service
 * bug will result in silent failure (rather than a debuggable deadlock). Furthermore, there
 * is a history of this API being used to know when a service is up as a proxy for whethre
 * that service should be started. This should only be used if you are intending to get
 * ahold of the service as a client. For lazy services, whether a service is registered
 * should not be used as a proxy for when it should be registered, which is only known
 * by the real client.
 *
 * WARNING: if you use this API, you must also ensure that you check missing services are
 * started and crash otherwise. If service failures are ignored, the system rots.
 *
 * \param instance name of service to wait for notifications about
 * \param onRegister callback for when service is registered
 * \param cookie data associated with this callback
 *
 * \return the token for this registration. Deleting this token will unregister.
 */
__attribute__((warn_unused_result)) AServiceManager_NotificationRegistration*
AServiceManager_registerForServiceNotifications(const char* instance,
                                                AServiceManager_onRegister onRegister, void* cookie)
        __INTRODUCED_IN(34);

/**
 * Unregister for notifications and delete the object.
 *
 * After this method is called, the callback is guaranteed to no longer be invoked. This will block
 * until any in-progress onRegister callbacks have completed. It is therefore safe to immediately
 * destroy the void* cookie that was registered when this method returns.
 *
 * \param notification object to dismiss
 */
void AServiceManager_NotificationRegistration_delete(
        AServiceManager_NotificationRegistration* notification) __INTRODUCED_IN(34);

/**
/**
 * Check if a service is declared (e.g. VINTF manifest).
 * Check if a service is declared (e.g. VINTF manifest).
 *
 *
+2 −0
Original line number Original line Diff line number Diff line
@@ -155,6 +155,8 @@ LIBBINDER_NDK33 { # introduced=33
LIBBINDER_NDK34 { # introduced=UpsideDownCake
LIBBINDER_NDK34 { # introduced=UpsideDownCake
  global:
  global:
    AServiceManager_getUpdatableApexName; # systemapi
    AServiceManager_getUpdatableApexName; # systemapi
    AServiceManager_registerForServiceNotifications; # systemapi llndk
    AServiceManager_NotificationRegistration_delete; # systemapi llndk
};
};


LIBBINDER_NDK_PLATFORM {
LIBBINDER_NDK_PLATFORM {
+62 −0
Original line number Original line Diff line number Diff line
@@ -28,6 +28,7 @@ using ::android::IBinder;
using ::android::IServiceManager;
using ::android::IServiceManager;
using ::android::sp;
using ::android::sp;
using ::android::status_t;
using ::android::status_t;
using ::android::statusToString;
using ::android::String16;
using ::android::String16;
using ::android::String8;
using ::android::String8;


@@ -86,6 +87,67 @@ AIBinder* AServiceManager_waitForService(const char* instance) {
    AIBinder_incStrong(ret.get());
    AIBinder_incStrong(ret.get());
    return ret.get();
    return ret.get();
}
}
typedef void (*AServiceManager_onRegister)(const char* instance, AIBinder* registered,
                                           void* cookie);

struct AServiceManager_NotificationRegistration
    : public IServiceManager::LocalRegistrationCallback {
    std::mutex m;
    const char* instance = nullptr;
    void* cookie = nullptr;
    AServiceManager_onRegister onRegister = nullptr;

    virtual void onServiceRegistration(const String16& smInstance, const sp<IBinder>& binder) {
        std::lock_guard<std::mutex> l(m);
        if (onRegister == nullptr) return;

        CHECK_EQ(String8(smInstance), instance);

        sp<AIBinder> ret = ABpBinder::lookupOrCreateFromBinder(binder);
        AIBinder_incStrong(ret.get());

        onRegister(instance, ret.get(), cookie);
    }

    void clear() {
        std::lock_guard<std::mutex> l(m);
        instance = nullptr;
        cookie = nullptr;
        onRegister = nullptr;
    }
};

__attribute__((warn_unused_result)) AServiceManager_NotificationRegistration*
AServiceManager_registerForServiceNotifications(const char* instance,
                                                AServiceManager_onRegister onRegister,
                                                void* cookie) {
    CHECK_NE(instance, nullptr);
    CHECK_NE(onRegister, nullptr) << instance;
    // cookie can be nullptr

    auto cb = sp<AServiceManager_NotificationRegistration>::make();
    cb->instance = instance;
    cb->onRegister = onRegister;
    cb->cookie = cookie;

    sp<IServiceManager> sm = defaultServiceManager();
    if (status_t res = sm->registerForNotifications(String16(instance), cb); res != STATUS_OK) {
        LOG(ERROR) << "Failed to register for service notifications for " << instance << ": "
                   << statusToString(res);
        return nullptr;
    }

    cb->incStrong(nullptr);
    return cb.get();
}

void AServiceManager_NotificationRegistration_delete(
        AServiceManager_NotificationRegistration* notification) {
    CHECK_NE(notification, nullptr);
    notification->clear();
    notification->decStrong(nullptr);
}

bool AServiceManager_isDeclared(const char* instance) {
bool AServiceManager_isDeclared(const char* instance) {
    if (instance == nullptr) {
    if (instance == nullptr) {
        return false;
        return false;
+41 −0
Original line number Original line Diff line number Diff line
@@ -254,6 +254,47 @@ TEST(NdkBinder, CheckServiceThatDoesExist) {
    AIBinder_decStrong(binder);
    AIBinder_decStrong(binder);
}
}


struct ServiceData {
    std::string instance;
    ndk::SpAIBinder binder;

    static void fillOnRegister(const char* instance, AIBinder* binder, void* cookie) {
        ServiceData* d = reinterpret_cast<ServiceData*>(cookie);
        d->instance = instance;
        d->binder = ndk::SpAIBinder(binder);
    }
};

TEST(NdkBinder, RegisterForServiceNotificationsNonExisting) {
    ServiceData data;
    auto* notif = AServiceManager_registerForServiceNotifications(
            "DOES_NOT_EXIST", ServiceData::fillOnRegister, (void*)&data);
    ASSERT_NE(notif, nullptr);

    sleep(1);  // give us a chance to fail
    AServiceManager_NotificationRegistration_delete(notif);

    // checking after deleting to avoid needing a mutex over the data - otherwise
    // in an environment w/ multiple threads, you would need to guard access
    EXPECT_EQ(data.instance, "");
    EXPECT_EQ(data.binder, nullptr);
}

TEST(NdkBinder, RegisterForServiceNotificationsExisting) {
    ServiceData data;
    auto* notif = AServiceManager_registerForServiceNotifications(
            kExistingNonNdkService, ServiceData::fillOnRegister, (void*)&data);
    ASSERT_NE(notif, nullptr);

    sleep(1);  // give us a chance to fail
    AServiceManager_NotificationRegistration_delete(notif);

    // checking after deleting to avoid needing a mutex over the data - otherwise
    // in an environment w/ multiple threads, you would need to guard access
    EXPECT_EQ(data.instance, kExistingNonNdkService);
    EXPECT_EQ(data.binder, ndk::SpAIBinder(AServiceManager_checkService(kExistingNonNdkService)));
}

TEST(NdkBinder, UnimplementedDump) {
TEST(NdkBinder, UnimplementedDump) {
    sp<IFoo> foo = IFoo::getService(IFoo::kSomeInstanceName);
    sp<IFoo> foo = IFoo::getService(IFoo::kSomeInstanceName);
    ASSERT_NE(foo, nullptr);
    ASSERT_NE(foo, nullptr);