Loading cmds/servicemanager/ServiceManager.cpp +97 −0 Original line number Diff line number Diff line Loading @@ -28,6 +28,13 @@ ServiceManager::ServiceManager(std::unique_ptr<Access>&& access) : mAccess(std:: ServiceManager::~ServiceManager() { // this should only happen in tests for (const auto& [name, callbacks] : mNameToCallback) { CHECK(!callbacks.empty()) << name; for (const auto& callback : callbacks) { CHECK(callback != nullptr) << name; } } for (const auto& [name, service] : mNameToService) { CHECK(service.binder != nullptr) << name; } Loading Loading @@ -117,6 +124,14 @@ Status ServiceManager::addService(const std::string& name, const sp<IBinder>& bi .dumpPriority = dumpPriority, }; auto it = mNameToCallback.find(name); if (it != mNameToCallback.end()) { for (const sp<IServiceCallback>& cb : it->second) { // permission checked in registerForNotifications cb->onRegistration(name, binder); } } return Status::ok(); } Loading Loading @@ -146,6 +161,84 @@ Status ServiceManager::listServices(int32_t dumpPriority, std::vector<std::strin return Status::ok(); } Status ServiceManager::registerForNotifications( const std::string& name, const sp<IServiceCallback>& callback) { auto ctx = mAccess->getCallingContext(); if (!mAccess->canFind(ctx, name)) { return Status::fromExceptionCode(Status::EX_SECURITY); } if (!isValidServiceName(name)) { LOG(ERROR) << "Invalid service name: " << name; return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT); } if (callback == nullptr) { return Status::fromExceptionCode(Status::EX_NULL_POINTER); } if (OK != IInterface::asBinder(callback)->linkToDeath(this)) { LOG(ERROR) << "Could not linkToDeath when adding " << name; return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE); } mNameToCallback[name].push_back(callback); if (auto it = mNameToService.find(name); it != mNameToService.end()) { const sp<IBinder>& binder = it->second.binder; // never null if an entry exists CHECK(binder != nullptr) << name; callback->onRegistration(name, binder); } return Status::ok(); } Status ServiceManager::unregisterForNotifications( const std::string& name, const sp<IServiceCallback>& callback) { auto ctx = mAccess->getCallingContext(); if (!mAccess->canFind(ctx, name)) { return Status::fromExceptionCode(Status::EX_SECURITY); } bool found = false; auto it = mNameToCallback.find(name); if (it != mNameToCallback.end()) { removeCallback(IInterface::asBinder(callback), &it, &found); } if (!found) { LOG(ERROR) << "Trying to unregister callback, but none exists " << name; return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE); } return Status::ok(); } void ServiceManager::removeCallback(const wp<IBinder>& who, CallbackMap::iterator* it, bool* found) { std::vector<sp<IServiceCallback>>& listeners = (*it)->second; for (auto lit = listeners.begin(); lit != listeners.end();) { if (IInterface::asBinder(*lit) == who) { if(found) *found = true; lit = listeners.erase(lit); } else { ++lit; } } if (listeners.empty()) { *it = mNameToCallback.erase(*it); } else { it++; } } void ServiceManager::binderDied(const wp<IBinder>& who) { for (auto it = mNameToService.begin(); it != mNameToService.end();) { if (who == it->second.binder) { Loading @@ -154,6 +247,10 @@ void ServiceManager::binderDied(const wp<IBinder>& who) { ++it; } } for (auto it = mNameToCallback.begin(); it != mNameToCallback.end();) { removeCallback(who, &it, nullptr /*found*/); } } } // namespace android cmds/servicemanager/ServiceManager.h +22 −3 Original line number Diff line number Diff line Loading @@ -17,11 +17,14 @@ #pragma once #include <android/os/BnServiceManager.h> #include <android/os/IServiceCallback.h> #include "Access.h" namespace android { using os::IServiceCallback; class ServiceManager : public os::BnServiceManager, public IBinder::DeathRecipient { public: ServiceManager(std::unique_ptr<Access>&& access); Loading @@ -29,19 +32,35 @@ public: binder::Status getService(const std::string& name, sp<IBinder>* outBinder) override; binder::Status checkService(const std::string& name, sp<IBinder>* outBinder) override; binder::Status addService(const std::string& name, const sp<IBinder>& binder, bool allowIsolated, int32_t dumpPriority) override; binder::Status addService(const std::string& name, const sp<IBinder>& binder, bool allowIsolated, int32_t dumpPriority) override; binder::Status listServices(int32_t dumpPriority, std::vector<std::string>* outList) override; binder::Status registerForNotifications(const std::string& name, const sp<IServiceCallback>& callback) override; binder::Status unregisterForNotifications(const std::string& name, const sp<IServiceCallback>& callback) override; void binderDied(const wp<IBinder>& who) override; private: struct Service { sp<IBinder> binder; sp<IBinder> binder; // not null bool allowIsolated; int32_t dumpPriority; }; std::map<std::string, Service> mNameToService; using CallbackMap = std::map<std::string, std::vector<sp<IServiceCallback>>>; using ServiceMap = std::map<std::string, Service>; // removes a callback from mNameToCallback, removing it if the vector is empty // this updates iterator to the next location void removeCallback(const wp<IBinder>& who, CallbackMap::iterator* it, bool* found); CallbackMap mNameToCallback; ServiceMap mNameToService; std::unique_ptr<Access> mAccess; }; Loading cmds/servicemanager/test_sm.cpp +163 −7 Original line number Diff line number Diff line Loading @@ -14,7 +14,10 @@ * limitations under the License. */ #include <android/os/BnServiceCallback.h> #include <binder/Binder.h> #include <binder/ProcessState.h> #include <binder/IServiceManager.h> #include <cutils/android_filesystem_config.h> #include <gtest/gtest.h> #include <gmock/gmock.h> Loading @@ -24,8 +27,11 @@ using android::sp; using android::Access; using android::BBinder; using android::IBinder; using android::ServiceManager; using android::binder::Status; using android::os::BnServiceCallback; using android::os::IServiceManager; using testing::_; using testing::ElementsAre; Loading @@ -33,9 +39,14 @@ using testing::NiceMock; using testing::Return; static sp<IBinder> getBinder() { // It doesn't matter what remote binder it is, we just need one so that linkToDeath will work. // The context manager (servicemanager) is easy to get and is in another process. return android::ProcessState::self()->getContextObject(nullptr); class LinkableBinder : public BBinder { android::status_t linkToDeath(const sp<DeathRecipient>&, void*, uint32_t) override { // let SM linkToDeath return android::OK; } }; return new LinkableBinder; } class MockAccess : public Access { Loading Loading @@ -132,12 +143,14 @@ TEST(AddService, NoPermissions) { TEST(GetService, HappyHappy) { auto sm = getPermissiveServiceManager(); EXPECT_TRUE(sm->addService("foo", getBinder(), false /*allowIsolated*/, sp<IBinder> service = getBinder(); EXPECT_TRUE(sm->addService("foo", service, false /*allowIsolated*/, IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()); sp<IBinder> out; EXPECT_TRUE(sm->getService("foo", &out).isOk()); EXPECT_EQ(getBinder(), out); EXPECT_EQ(service, out); } TEST(GetService, NonExistant) { Loading Loading @@ -181,12 +194,13 @@ TEST(GetService, AllowedFromIsolated) { sp<ServiceManager> sm = new ServiceManager(std::move(access)); EXPECT_TRUE(sm->addService("foo", getBinder(), true /*allowIsolated*/, sp<IBinder> service = getBinder(); EXPECT_TRUE(sm->addService("foo", service, true /*allowIsolated*/, IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()); sp<IBinder> out; EXPECT_TRUE(sm->getService("foo", &out).isOk()); EXPECT_EQ(getBinder(), out.get()); EXPECT_EQ(service, out.get()); } TEST(GetService, NotAllowedFromIsolated) { Loading Loading @@ -265,3 +279,145 @@ TEST(ListServices, CriticalServices) { // all there and in the right order EXPECT_THAT(out, ElementsAre("sa")); } class CallbackHistorian : public BnServiceCallback { Status onRegistration(const std::string& name, const sp<IBinder>& binder) override { registrations.push_back(name); binders.push_back(binder); return Status::ok(); } android::status_t linkToDeath(const sp<DeathRecipient>&, void*, uint32_t) override { // let SM linkToDeath return android::OK; } public: std::vector<std::string> registrations; std::vector<sp<IBinder>> binders; }; TEST(ServiceNotifications, NoPermissionsRegister) { std::unique_ptr<MockAccess> access = std::make_unique<NiceMock<MockAccess>>(); EXPECT_CALL(*access, getCallingContext()).WillOnce(Return(Access::CallingContext{})); EXPECT_CALL(*access, canFind(_,_)).WillOnce(Return(false)); sp<ServiceManager> sm = new ServiceManager(std::move(access)); sp<CallbackHistorian> cb = new CallbackHistorian; EXPECT_EQ(sm->registerForNotifications("foofoo", cb).exceptionCode(), Status::EX_SECURITY); } TEST(ServiceNotifications, NoPermissionsUnregister) { std::unique_ptr<MockAccess> access = std::make_unique<NiceMock<MockAccess>>(); EXPECT_CALL(*access, getCallingContext()).WillOnce(Return(Access::CallingContext{})); EXPECT_CALL(*access, canFind(_,_)).WillOnce(Return(false)); sp<ServiceManager> sm = new ServiceManager(std::move(access)); sp<CallbackHistorian> cb = new CallbackHistorian; // should always hit security error first EXPECT_EQ(sm->unregisterForNotifications("foofoo", cb).exceptionCode(), Status::EX_SECURITY); } TEST(ServiceNotifications, InvalidName) { auto sm = getPermissiveServiceManager(); sp<CallbackHistorian> cb = new CallbackHistorian; EXPECT_EQ(sm->registerForNotifications("foo@foo", cb).exceptionCode(), Status::EX_ILLEGAL_ARGUMENT); } TEST(ServiceNotifications, NullCallback) { auto sm = getPermissiveServiceManager(); EXPECT_EQ(sm->registerForNotifications("foofoo", nullptr).exceptionCode(), Status::EX_NULL_POINTER); } TEST(ServiceNotifications, Unregister) { auto sm = getPermissiveServiceManager(); sp<CallbackHistorian> cb = new CallbackHistorian; EXPECT_TRUE(sm->registerForNotifications("foofoo", cb).isOk()); EXPECT_EQ(sm->unregisterForNotifications("foofoo", cb).exceptionCode(), 0); } TEST(ServiceNotifications, UnregisterWhenNoRegistrationExists) { auto sm = getPermissiveServiceManager(); sp<CallbackHistorian> cb = new CallbackHistorian; EXPECT_EQ(sm->unregisterForNotifications("foofoo", cb).exceptionCode(), Status::EX_ILLEGAL_STATE); } TEST(ServiceNotifications, NoNotification) { auto sm = getPermissiveServiceManager(); sp<CallbackHistorian> cb = new CallbackHistorian; EXPECT_TRUE(sm->registerForNotifications("foofoo", cb).isOk()); EXPECT_TRUE(sm->addService("otherservice", getBinder(), false /*allowIsolated*/, IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()); EXPECT_THAT(cb->registrations, ElementsAre()); EXPECT_THAT(cb->binders, ElementsAre()); } TEST(ServiceNotifications, GetNotification) { auto sm = getPermissiveServiceManager(); sp<CallbackHistorian> cb = new CallbackHistorian; sp<IBinder> service = getBinder(); EXPECT_TRUE(sm->registerForNotifications("asdfasdf", cb).isOk()); EXPECT_TRUE(sm->addService("asdfasdf", service, false /*allowIsolated*/, IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()); EXPECT_THAT(cb->registrations, ElementsAre("asdfasdf")); EXPECT_THAT(cb->binders, ElementsAre(service)); } TEST(ServiceNotifications, GetNotificationForAlreadyRegisteredService) { auto sm = getPermissiveServiceManager(); sp<CallbackHistorian> cb = new CallbackHistorian; sp<IBinder> service = getBinder(); EXPECT_TRUE(sm->addService("asdfasdf", service, false /*allowIsolated*/, IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()); EXPECT_TRUE(sm->registerForNotifications("asdfasdf", cb).isOk()); EXPECT_THAT(cb->registrations, ElementsAre("asdfasdf")); EXPECT_THAT(cb->binders, ElementsAre(service)); } TEST(ServiceNotifications, GetMultipleNotification) { auto sm = getPermissiveServiceManager(); sp<CallbackHistorian> cb = new CallbackHistorian; sp<IBinder> binder1 = getBinder(); sp<IBinder> binder2 = getBinder(); EXPECT_TRUE(sm->registerForNotifications("asdfasdf", cb).isOk()); EXPECT_TRUE(sm->addService("asdfasdf", binder1, false /*allowIsolated*/, IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()); EXPECT_TRUE(sm->addService("asdfasdf", binder2, false /*allowIsolated*/, IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()); EXPECT_THAT(cb->registrations, ElementsAre("asdfasdf", "asdfasdf")); EXPECT_THAT(cb->registrations, ElementsAre("asdfasdf", "asdfasdf")); } libs/binder/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -145,6 +145,7 @@ filegroup { name: "libbinder_aidl", srcs: [ "aidl/android/content/pm/IPackageManagerNative.aidl", "aidl/android/os/IServiceCallback.aidl", "aidl/android/os/IServiceManager.aidl", ], path: "aidl", Loading libs/binder/aidl/android/os/IServiceCallback.aidl 0 → 100644 +30 −0 Original line number Diff line number Diff line /* * Copyright (C) 2019 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.os; /** * @hide */ oneway interface IServiceCallback { /** * Called when a service is registered. * * @param name the service name that has been registered with * @param binder the binder that is registered */ void onRegistration(@utf8InCpp String name, IBinder binder); } Loading
cmds/servicemanager/ServiceManager.cpp +97 −0 Original line number Diff line number Diff line Loading @@ -28,6 +28,13 @@ ServiceManager::ServiceManager(std::unique_ptr<Access>&& access) : mAccess(std:: ServiceManager::~ServiceManager() { // this should only happen in tests for (const auto& [name, callbacks] : mNameToCallback) { CHECK(!callbacks.empty()) << name; for (const auto& callback : callbacks) { CHECK(callback != nullptr) << name; } } for (const auto& [name, service] : mNameToService) { CHECK(service.binder != nullptr) << name; } Loading Loading @@ -117,6 +124,14 @@ Status ServiceManager::addService(const std::string& name, const sp<IBinder>& bi .dumpPriority = dumpPriority, }; auto it = mNameToCallback.find(name); if (it != mNameToCallback.end()) { for (const sp<IServiceCallback>& cb : it->second) { // permission checked in registerForNotifications cb->onRegistration(name, binder); } } return Status::ok(); } Loading Loading @@ -146,6 +161,84 @@ Status ServiceManager::listServices(int32_t dumpPriority, std::vector<std::strin return Status::ok(); } Status ServiceManager::registerForNotifications( const std::string& name, const sp<IServiceCallback>& callback) { auto ctx = mAccess->getCallingContext(); if (!mAccess->canFind(ctx, name)) { return Status::fromExceptionCode(Status::EX_SECURITY); } if (!isValidServiceName(name)) { LOG(ERROR) << "Invalid service name: " << name; return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT); } if (callback == nullptr) { return Status::fromExceptionCode(Status::EX_NULL_POINTER); } if (OK != IInterface::asBinder(callback)->linkToDeath(this)) { LOG(ERROR) << "Could not linkToDeath when adding " << name; return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE); } mNameToCallback[name].push_back(callback); if (auto it = mNameToService.find(name); it != mNameToService.end()) { const sp<IBinder>& binder = it->second.binder; // never null if an entry exists CHECK(binder != nullptr) << name; callback->onRegistration(name, binder); } return Status::ok(); } Status ServiceManager::unregisterForNotifications( const std::string& name, const sp<IServiceCallback>& callback) { auto ctx = mAccess->getCallingContext(); if (!mAccess->canFind(ctx, name)) { return Status::fromExceptionCode(Status::EX_SECURITY); } bool found = false; auto it = mNameToCallback.find(name); if (it != mNameToCallback.end()) { removeCallback(IInterface::asBinder(callback), &it, &found); } if (!found) { LOG(ERROR) << "Trying to unregister callback, but none exists " << name; return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE); } return Status::ok(); } void ServiceManager::removeCallback(const wp<IBinder>& who, CallbackMap::iterator* it, bool* found) { std::vector<sp<IServiceCallback>>& listeners = (*it)->second; for (auto lit = listeners.begin(); lit != listeners.end();) { if (IInterface::asBinder(*lit) == who) { if(found) *found = true; lit = listeners.erase(lit); } else { ++lit; } } if (listeners.empty()) { *it = mNameToCallback.erase(*it); } else { it++; } } void ServiceManager::binderDied(const wp<IBinder>& who) { for (auto it = mNameToService.begin(); it != mNameToService.end();) { if (who == it->second.binder) { Loading @@ -154,6 +247,10 @@ void ServiceManager::binderDied(const wp<IBinder>& who) { ++it; } } for (auto it = mNameToCallback.begin(); it != mNameToCallback.end();) { removeCallback(who, &it, nullptr /*found*/); } } } // namespace android
cmds/servicemanager/ServiceManager.h +22 −3 Original line number Diff line number Diff line Loading @@ -17,11 +17,14 @@ #pragma once #include <android/os/BnServiceManager.h> #include <android/os/IServiceCallback.h> #include "Access.h" namespace android { using os::IServiceCallback; class ServiceManager : public os::BnServiceManager, public IBinder::DeathRecipient { public: ServiceManager(std::unique_ptr<Access>&& access); Loading @@ -29,19 +32,35 @@ public: binder::Status getService(const std::string& name, sp<IBinder>* outBinder) override; binder::Status checkService(const std::string& name, sp<IBinder>* outBinder) override; binder::Status addService(const std::string& name, const sp<IBinder>& binder, bool allowIsolated, int32_t dumpPriority) override; binder::Status addService(const std::string& name, const sp<IBinder>& binder, bool allowIsolated, int32_t dumpPriority) override; binder::Status listServices(int32_t dumpPriority, std::vector<std::string>* outList) override; binder::Status registerForNotifications(const std::string& name, const sp<IServiceCallback>& callback) override; binder::Status unregisterForNotifications(const std::string& name, const sp<IServiceCallback>& callback) override; void binderDied(const wp<IBinder>& who) override; private: struct Service { sp<IBinder> binder; sp<IBinder> binder; // not null bool allowIsolated; int32_t dumpPriority; }; std::map<std::string, Service> mNameToService; using CallbackMap = std::map<std::string, std::vector<sp<IServiceCallback>>>; using ServiceMap = std::map<std::string, Service>; // removes a callback from mNameToCallback, removing it if the vector is empty // this updates iterator to the next location void removeCallback(const wp<IBinder>& who, CallbackMap::iterator* it, bool* found); CallbackMap mNameToCallback; ServiceMap mNameToService; std::unique_ptr<Access> mAccess; }; Loading
cmds/servicemanager/test_sm.cpp +163 −7 Original line number Diff line number Diff line Loading @@ -14,7 +14,10 @@ * limitations under the License. */ #include <android/os/BnServiceCallback.h> #include <binder/Binder.h> #include <binder/ProcessState.h> #include <binder/IServiceManager.h> #include <cutils/android_filesystem_config.h> #include <gtest/gtest.h> #include <gmock/gmock.h> Loading @@ -24,8 +27,11 @@ using android::sp; using android::Access; using android::BBinder; using android::IBinder; using android::ServiceManager; using android::binder::Status; using android::os::BnServiceCallback; using android::os::IServiceManager; using testing::_; using testing::ElementsAre; Loading @@ -33,9 +39,14 @@ using testing::NiceMock; using testing::Return; static sp<IBinder> getBinder() { // It doesn't matter what remote binder it is, we just need one so that linkToDeath will work. // The context manager (servicemanager) is easy to get and is in another process. return android::ProcessState::self()->getContextObject(nullptr); class LinkableBinder : public BBinder { android::status_t linkToDeath(const sp<DeathRecipient>&, void*, uint32_t) override { // let SM linkToDeath return android::OK; } }; return new LinkableBinder; } class MockAccess : public Access { Loading Loading @@ -132,12 +143,14 @@ TEST(AddService, NoPermissions) { TEST(GetService, HappyHappy) { auto sm = getPermissiveServiceManager(); EXPECT_TRUE(sm->addService("foo", getBinder(), false /*allowIsolated*/, sp<IBinder> service = getBinder(); EXPECT_TRUE(sm->addService("foo", service, false /*allowIsolated*/, IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()); sp<IBinder> out; EXPECT_TRUE(sm->getService("foo", &out).isOk()); EXPECT_EQ(getBinder(), out); EXPECT_EQ(service, out); } TEST(GetService, NonExistant) { Loading Loading @@ -181,12 +194,13 @@ TEST(GetService, AllowedFromIsolated) { sp<ServiceManager> sm = new ServiceManager(std::move(access)); EXPECT_TRUE(sm->addService("foo", getBinder(), true /*allowIsolated*/, sp<IBinder> service = getBinder(); EXPECT_TRUE(sm->addService("foo", service, true /*allowIsolated*/, IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()); sp<IBinder> out; EXPECT_TRUE(sm->getService("foo", &out).isOk()); EXPECT_EQ(getBinder(), out.get()); EXPECT_EQ(service, out.get()); } TEST(GetService, NotAllowedFromIsolated) { Loading Loading @@ -265,3 +279,145 @@ TEST(ListServices, CriticalServices) { // all there and in the right order EXPECT_THAT(out, ElementsAre("sa")); } class CallbackHistorian : public BnServiceCallback { Status onRegistration(const std::string& name, const sp<IBinder>& binder) override { registrations.push_back(name); binders.push_back(binder); return Status::ok(); } android::status_t linkToDeath(const sp<DeathRecipient>&, void*, uint32_t) override { // let SM linkToDeath return android::OK; } public: std::vector<std::string> registrations; std::vector<sp<IBinder>> binders; }; TEST(ServiceNotifications, NoPermissionsRegister) { std::unique_ptr<MockAccess> access = std::make_unique<NiceMock<MockAccess>>(); EXPECT_CALL(*access, getCallingContext()).WillOnce(Return(Access::CallingContext{})); EXPECT_CALL(*access, canFind(_,_)).WillOnce(Return(false)); sp<ServiceManager> sm = new ServiceManager(std::move(access)); sp<CallbackHistorian> cb = new CallbackHistorian; EXPECT_EQ(sm->registerForNotifications("foofoo", cb).exceptionCode(), Status::EX_SECURITY); } TEST(ServiceNotifications, NoPermissionsUnregister) { std::unique_ptr<MockAccess> access = std::make_unique<NiceMock<MockAccess>>(); EXPECT_CALL(*access, getCallingContext()).WillOnce(Return(Access::CallingContext{})); EXPECT_CALL(*access, canFind(_,_)).WillOnce(Return(false)); sp<ServiceManager> sm = new ServiceManager(std::move(access)); sp<CallbackHistorian> cb = new CallbackHistorian; // should always hit security error first EXPECT_EQ(sm->unregisterForNotifications("foofoo", cb).exceptionCode(), Status::EX_SECURITY); } TEST(ServiceNotifications, InvalidName) { auto sm = getPermissiveServiceManager(); sp<CallbackHistorian> cb = new CallbackHistorian; EXPECT_EQ(sm->registerForNotifications("foo@foo", cb).exceptionCode(), Status::EX_ILLEGAL_ARGUMENT); } TEST(ServiceNotifications, NullCallback) { auto sm = getPermissiveServiceManager(); EXPECT_EQ(sm->registerForNotifications("foofoo", nullptr).exceptionCode(), Status::EX_NULL_POINTER); } TEST(ServiceNotifications, Unregister) { auto sm = getPermissiveServiceManager(); sp<CallbackHistorian> cb = new CallbackHistorian; EXPECT_TRUE(sm->registerForNotifications("foofoo", cb).isOk()); EXPECT_EQ(sm->unregisterForNotifications("foofoo", cb).exceptionCode(), 0); } TEST(ServiceNotifications, UnregisterWhenNoRegistrationExists) { auto sm = getPermissiveServiceManager(); sp<CallbackHistorian> cb = new CallbackHistorian; EXPECT_EQ(sm->unregisterForNotifications("foofoo", cb).exceptionCode(), Status::EX_ILLEGAL_STATE); } TEST(ServiceNotifications, NoNotification) { auto sm = getPermissiveServiceManager(); sp<CallbackHistorian> cb = new CallbackHistorian; EXPECT_TRUE(sm->registerForNotifications("foofoo", cb).isOk()); EXPECT_TRUE(sm->addService("otherservice", getBinder(), false /*allowIsolated*/, IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()); EXPECT_THAT(cb->registrations, ElementsAre()); EXPECT_THAT(cb->binders, ElementsAre()); } TEST(ServiceNotifications, GetNotification) { auto sm = getPermissiveServiceManager(); sp<CallbackHistorian> cb = new CallbackHistorian; sp<IBinder> service = getBinder(); EXPECT_TRUE(sm->registerForNotifications("asdfasdf", cb).isOk()); EXPECT_TRUE(sm->addService("asdfasdf", service, false /*allowIsolated*/, IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()); EXPECT_THAT(cb->registrations, ElementsAre("asdfasdf")); EXPECT_THAT(cb->binders, ElementsAre(service)); } TEST(ServiceNotifications, GetNotificationForAlreadyRegisteredService) { auto sm = getPermissiveServiceManager(); sp<CallbackHistorian> cb = new CallbackHistorian; sp<IBinder> service = getBinder(); EXPECT_TRUE(sm->addService("asdfasdf", service, false /*allowIsolated*/, IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()); EXPECT_TRUE(sm->registerForNotifications("asdfasdf", cb).isOk()); EXPECT_THAT(cb->registrations, ElementsAre("asdfasdf")); EXPECT_THAT(cb->binders, ElementsAre(service)); } TEST(ServiceNotifications, GetMultipleNotification) { auto sm = getPermissiveServiceManager(); sp<CallbackHistorian> cb = new CallbackHistorian; sp<IBinder> binder1 = getBinder(); sp<IBinder> binder2 = getBinder(); EXPECT_TRUE(sm->registerForNotifications("asdfasdf", cb).isOk()); EXPECT_TRUE(sm->addService("asdfasdf", binder1, false /*allowIsolated*/, IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()); EXPECT_TRUE(sm->addService("asdfasdf", binder2, false /*allowIsolated*/, IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()); EXPECT_THAT(cb->registrations, ElementsAre("asdfasdf", "asdfasdf")); EXPECT_THAT(cb->registrations, ElementsAre("asdfasdf", "asdfasdf")); }
libs/binder/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -145,6 +145,7 @@ filegroup { name: "libbinder_aidl", srcs: [ "aidl/android/content/pm/IPackageManagerNative.aidl", "aidl/android/os/IServiceCallback.aidl", "aidl/android/os/IServiceManager.aidl", ], path: "aidl", Loading
libs/binder/aidl/android/os/IServiceCallback.aidl 0 → 100644 +30 −0 Original line number Diff line number Diff line /* * Copyright (C) 2019 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.os; /** * @hide */ oneway interface IServiceCallback { /** * Called when a service is registered. * * @param name the service name that has been registered with * @param binder the binder that is registered */ void onRegistration(@utf8InCpp String name, IBinder binder); }