diff options
author | 2025-01-06 11:02:36 -0800 | |
---|---|---|
committer | 2025-01-06 11:02:36 -0800 | |
commit | 9bf3e87d645649bc7f29a3e46d9cad090a6d2ce2 (patch) | |
tree | 6be718e0d838dcc3877a6d2eb6e5f91dc7e50c15 | |
parent | 8d575700879e0fcccd22adbb4e56512453fc2572 (diff) | |
parent | 6c0cd2764f3d4ccea813a95750420232c0ca3a31 (diff) |
Merge changes from topic "no_sm_proc" into main am: 03cb1fd21d am: 6c0cd2764f
Original change: https://android-review.googlesource.com/c/platform/frameworks/native/+/3365276
Change-Id: I9bc4e6ea692ea63ea257017232cce70d6d78d86d
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
-rw-r--r-- | libs/binder/BackendUnifiedServiceManager.cpp | 142 | ||||
-rw-r--r-- | libs/binder/BackendUnifiedServiceManager.h | 4 | ||||
-rw-r--r-- | libs/binder/IServiceManager.cpp | 19 | ||||
-rw-r--r-- | libs/binder/include/binder/IServiceManager.h | 8 | ||||
-rw-r--r-- | libs/binder/rust/src/system_only.rs | 26 | ||||
-rw-r--r-- | libs/binder/tests/binderLibTest.cpp | 57 | ||||
-rw-r--r-- | libs/binder/tests/binderRpcTest.cpp | 103 |
7 files changed, 313 insertions, 46 deletions
diff --git a/libs/binder/BackendUnifiedServiceManager.cpp b/libs/binder/BackendUnifiedServiceManager.cpp index 34d5a09948..ee3d6af742 100644 --- a/libs/binder/BackendUnifiedServiceManager.cpp +++ b/libs/binder/BackendUnifiedServiceManager.cpp @@ -15,6 +15,7 @@ */ #include "BackendUnifiedServiceManager.h" +#include <android-base/strings.h> #include <android/os/IAccessor.h> #include <android/os/IServiceManager.h> #include <binder/RpcSession.h> @@ -47,6 +48,9 @@ using AidlServiceManager = android::os::IServiceManager; using android::os::IAccessor; using binder::Status; +static const char* kUnsupportedOpNoServiceManager = + "Unsupported operation without a kernel binder servicemanager process"; + static const char* kStaticCachableList[] = { // go/keep-sorted start "accessibility", @@ -220,7 +224,10 @@ Status BackendUnifiedServiceManager::getService2(const ::std::string& name, os:: return Status::ok(); } os::Service service; - Status status = mTheRealServiceManager->getService2(name, &service); + Status status = Status::ok(); + if (mTheRealServiceManager) { + status = mTheRealServiceManager->getService2(name, &service); + } if (status.isOk()) { status = toBinderService(name, service, _out); @@ -237,7 +244,10 @@ Status BackendUnifiedServiceManager::checkService(const ::std::string& name, os: return Status::ok(); } - Status status = mTheRealServiceManager->checkService(name, &service); + Status status = Status::ok(); + if (mTheRealServiceManager) { + status = mTheRealServiceManager->checkService(name, &service); + } if (status.isOk()) { status = toBinderService(name, service, _out); if (status.isOk()) { @@ -315,66 +325,156 @@ Status BackendUnifiedServiceManager::toBinderService(const ::std::string& name, Status BackendUnifiedServiceManager::addService(const ::std::string& name, const sp<IBinder>& service, bool allowIsolated, int32_t dumpPriority) { - Status status = mTheRealServiceManager->addService(name, service, allowIsolated, dumpPriority); - // mEnableAddServiceCache is true by default. - if (kUseCacheInAddService && mEnableAddServiceCache && status.isOk()) { - return updateCache(name, service, - dumpPriority & android::os::IServiceManager::FLAG_IS_LAZY_SERVICE); + if (mTheRealServiceManager) { + Status status = + mTheRealServiceManager->addService(name, service, allowIsolated, dumpPriority); + // mEnableAddServiceCache is true by default. + if (kUseCacheInAddService && mEnableAddServiceCache && status.isOk()) { + return updateCache(name, service, + dumpPriority & android::os::IServiceManager::FLAG_IS_LAZY_SERVICE); + } + return status; } - return status; + return Status::fromExceptionCode(Status::EX_UNSUPPORTED_OPERATION, + kUnsupportedOpNoServiceManager); } Status BackendUnifiedServiceManager::listServices(int32_t dumpPriority, ::std::vector<::std::string>* _aidl_return) { - return mTheRealServiceManager->listServices(dumpPriority, _aidl_return); + Status status = Status::ok(); + if (mTheRealServiceManager) { + status = mTheRealServiceManager->listServices(dumpPriority, _aidl_return); + } + if (!status.isOk()) return status; + + appendInjectedAccessorServices(_aidl_return); + + return status; } Status BackendUnifiedServiceManager::registerForNotifications( const ::std::string& name, const sp<os::IServiceCallback>& callback) { - return mTheRealServiceManager->registerForNotifications(name, callback); + if (mTheRealServiceManager) { + return mTheRealServiceManager->registerForNotifications(name, callback); + } + return Status::fromExceptionCode(Status::EX_UNSUPPORTED_OPERATION, + kUnsupportedOpNoServiceManager); } Status BackendUnifiedServiceManager::unregisterForNotifications( const ::std::string& name, const sp<os::IServiceCallback>& callback) { - return mTheRealServiceManager->unregisterForNotifications(name, callback); + if (mTheRealServiceManager) { + return mTheRealServiceManager->unregisterForNotifications(name, callback); + } + return Status::fromExceptionCode(Status::EX_UNSUPPORTED_OPERATION, + kUnsupportedOpNoServiceManager); } Status BackendUnifiedServiceManager::isDeclared(const ::std::string& name, bool* _aidl_return) { - return mTheRealServiceManager->isDeclared(name, _aidl_return); + Status status = Status::ok(); + if (mTheRealServiceManager) { + status = mTheRealServiceManager->isDeclared(name, _aidl_return); + } + if (!status.isOk()) return status; + + if (!*_aidl_return) { + forEachInjectedAccessorService([&](const std::string& instance) { + if (name == instance) { + *_aidl_return = true; + } + }); + } + + return status; } Status BackendUnifiedServiceManager::getDeclaredInstances( const ::std::string& iface, ::std::vector<::std::string>* _aidl_return) { - return mTheRealServiceManager->getDeclaredInstances(iface, _aidl_return); + Status status = Status::ok(); + if (mTheRealServiceManager) { + status = mTheRealServiceManager->getDeclaredInstances(iface, _aidl_return); + } + if (!status.isOk()) return status; + + forEachInjectedAccessorService([&](const std::string& instance) { + // Declared instances have the format + // <interface>/instance like foo.bar.ISomething/instance + // If it does not have that format, consider the instance to be "" + std::string_view name(instance); + if (base::ConsumePrefix(&name, iface + "/")) { + _aidl_return->emplace_back(name); + } else if (iface == instance) { + _aidl_return->push_back(""); + } + }); + + return status; } Status BackendUnifiedServiceManager::updatableViaApex( const ::std::string& name, ::std::optional<::std::string>* _aidl_return) { - return mTheRealServiceManager->updatableViaApex(name, _aidl_return); + if (mTheRealServiceManager) { + return mTheRealServiceManager->updatableViaApex(name, _aidl_return); + } + return Status::fromExceptionCode(Status::EX_UNSUPPORTED_OPERATION, + kUnsupportedOpNoServiceManager); } Status BackendUnifiedServiceManager::getUpdatableNames(const ::std::string& apexName, ::std::vector<::std::string>* _aidl_return) { - return mTheRealServiceManager->getUpdatableNames(apexName, _aidl_return); + if (mTheRealServiceManager) { + return mTheRealServiceManager->getUpdatableNames(apexName, _aidl_return); + } + return Status::fromExceptionCode(Status::EX_UNSUPPORTED_OPERATION, + kUnsupportedOpNoServiceManager); } Status BackendUnifiedServiceManager::getConnectionInfo( const ::std::string& name, ::std::optional<os::ConnectionInfo>* _aidl_return) { - return mTheRealServiceManager->getConnectionInfo(name, _aidl_return); + if (mTheRealServiceManager) { + return mTheRealServiceManager->getConnectionInfo(name, _aidl_return); + } + return Status::fromExceptionCode(Status::EX_UNSUPPORTED_OPERATION, + kUnsupportedOpNoServiceManager); } Status BackendUnifiedServiceManager::registerClientCallback( const ::std::string& name, const sp<IBinder>& service, const sp<os::IClientCallback>& callback) { - return mTheRealServiceManager->registerClientCallback(name, service, callback); + if (mTheRealServiceManager) { + return mTheRealServiceManager->registerClientCallback(name, service, callback); + } + return Status::fromExceptionCode(Status::EX_UNSUPPORTED_OPERATION, + kUnsupportedOpNoServiceManager); } Status BackendUnifiedServiceManager::tryUnregisterService(const ::std::string& name, const sp<IBinder>& service) { - return mTheRealServiceManager->tryUnregisterService(name, service); + if (mTheRealServiceManager) { + return mTheRealServiceManager->tryUnregisterService(name, service); + } + return Status::fromExceptionCode(Status::EX_UNSUPPORTED_OPERATION, + kUnsupportedOpNoServiceManager); } Status BackendUnifiedServiceManager::getServiceDebugInfo( ::std::vector<os::ServiceDebugInfo>* _aidl_return) { - return mTheRealServiceManager->getServiceDebugInfo(_aidl_return); + if (mTheRealServiceManager) { + return mTheRealServiceManager->getServiceDebugInfo(_aidl_return); + } + return Status::fromExceptionCode(Status::EX_UNSUPPORTED_OPERATION, + kUnsupportedOpNoServiceManager); } [[clang::no_destroy]] static std::once_flag gUSmOnce; [[clang::no_destroy]] static sp<BackendUnifiedServiceManager> gUnifiedServiceManager; +static bool hasOutOfProcessServiceManager() { +#ifndef BINDER_WITH_KERNEL_IPC + return false; +#else +#if defined(__BIONIC__) && !defined(__ANDROID_VNDK__) + return android::base::GetBoolProperty("servicemanager.installed", true); +#else + return true; +#endif +#endif // BINDER_WITH_KERNEL_IPC +} + sp<BackendUnifiedServiceManager> getBackendUnifiedServiceManager() { std::call_once(gUSmOnce, []() { #if defined(__BIONIC__) && !defined(__ANDROID_VNDK__) - /* wait for service manager */ { + /* wait for service manager */ + if (hasOutOfProcessServiceManager()) { using std::literals::chrono_literals::operator""s; using android::base::WaitForProperty; while (!WaitForProperty("servicemanager.ready", "true", 1s)) { @@ -384,7 +484,7 @@ sp<BackendUnifiedServiceManager> getBackendUnifiedServiceManager() { #endif sp<AidlServiceManager> sm = nullptr; - while (sm == nullptr) { + while (hasOutOfProcessServiceManager() && sm == nullptr) { sm = interface_cast<AidlServiceManager>( ProcessState::self()->getContextObject(nullptr)); if (sm == nullptr) { diff --git a/libs/binder/BackendUnifiedServiceManager.h b/libs/binder/BackendUnifiedServiceManager.h index 6a0d06a079..2496f62503 100644 --- a/libs/binder/BackendUnifiedServiceManager.h +++ b/libs/binder/BackendUnifiedServiceManager.h @@ -167,5 +167,9 @@ private: sp<BackendUnifiedServiceManager> getBackendUnifiedServiceManager(); android::binder::Status getInjectedAccessor(const std::string& name, android::os::Service* service); +void appendInjectedAccessorServices(std::vector<std::string>* list); +// Do not call any other service manager APIs that might take the accessor +// mutex because this will be holding it! +void forEachInjectedAccessorService(const std::function<void(const std::string&)>& f); } // namespace android diff --git a/libs/binder/IServiceManager.cpp b/libs/binder/IServiceManager.cpp index 53435c357b..5c72ed3197 100644 --- a/libs/binder/IServiceManager.cpp +++ b/libs/binder/IServiceManager.cpp @@ -304,6 +304,25 @@ android::binder::Status getInjectedAccessor(const std::string& name, return android::binder::Status::ok(); } +void appendInjectedAccessorServices(std::vector<std::string>* list) { + LOG_ALWAYS_FATAL_IF(list == nullptr, + "Attempted to get list of services from Accessors with nullptr"); + std::lock_guard<std::mutex> lock(gAccessorProvidersMutex); + for (const auto& entry : gAccessorProviders) { + list->insert(list->end(), entry.mProvider->instances().begin(), + entry.mProvider->instances().end()); + } +} + +void forEachInjectedAccessorService(const std::function<void(const std::string&)>& f) { + std::lock_guard<std::mutex> lock(gAccessorProvidersMutex); + for (const auto& entry : gAccessorProviders) { + for (const auto& instance : entry.mProvider->instances()) { + f(instance); + } + } +} + sp<IServiceManager> defaultServiceManager() { std::call_once(gSmOnce, []() { diff --git a/libs/binder/include/binder/IServiceManager.h b/libs/binder/include/binder/IServiceManager.h index 7d79baa34d..d248f22e89 100644 --- a/libs/binder/include/binder/IServiceManager.h +++ b/libs/binder/include/binder/IServiceManager.h @@ -80,6 +80,14 @@ public: /** * Register a service. + * + * Note: + * This status_t return value may be an exception code from an underlying + * Status type that doesn't have a representive error code in + * utils/Errors.h. + * One example of this is a return value of -7 + * (Status::Exception::EX_UNSUPPORTED_OPERATION) when the service manager + * process is not installed on the device when addService is called. */ // NOLINTNEXTLINE(google-default-arguments) virtual status_t addService(const String16& name, const sp<IBinder>& service, diff --git a/libs/binder/rust/src/system_only.rs b/libs/binder/rust/src/system_only.rs index 288c54bab9..50aa336641 100644 --- a/libs/binder/rust/src/system_only.rs +++ b/libs/binder/rust/src/system_only.rs @@ -23,7 +23,7 @@ use std::ffi::{c_void, CStr, CString}; use std::os::raw::c_char; use libc::{sockaddr, sockaddr_un, sockaddr_vm, socklen_t}; -use std::sync::Arc; +use std::boxed::Box; use std::{mem, ptr}; /// Rust wrapper around ABinderRpc_Accessor objects for RPC binder service management. @@ -65,7 +65,7 @@ impl Accessor { where F: Fn(&str) -> Option<ConnectionInfo> + Send + Sync + 'static, { - let callback: *mut c_void = Arc::into_raw(Arc::new(callback)) as *mut c_void; + let callback: *mut c_void = Box::into_raw(Box::new(callback)) as *mut c_void; let inst = CString::new(instance).unwrap(); // Safety: The function pointer is a valid connection_info callback. @@ -149,7 +149,7 @@ impl Accessor { /// the string within isize::MAX from the pointer. The memory must not be mutated for /// the duration of this function call and must be valid for reads from the pointer /// to the null terminator. - /// - The `cookie` parameter must be the cookie for an `Arc<F>` and + /// - The `cookie` parameter must be the cookie for a `Box<F>` and /// the caller must hold a ref-count to it. unsafe extern "C" fn connection_info<F>( instance: *const c_char, @@ -162,7 +162,7 @@ impl Accessor { log::error!("Cookie({cookie:p}) or instance({instance:p}) is null!"); return ptr::null_mut(); } - // Safety: The caller promises that `cookie` is for an Arc<F>. + // Safety: The caller promises that `cookie` is for a Box<F>. let callback = unsafe { (cookie as *const F).as_ref().unwrap() }; // Safety: The caller in libbinder_ndk will have already verified this is a valid @@ -207,19 +207,19 @@ impl Accessor { } } - /// Callback that decrements the ref-count. + /// Callback that drops the `Box<F>`. /// This is invoked from C++ when a binder is unlinked. /// /// # Safety /// - /// - The `cookie` parameter must be the cookie for an `Arc<F>` and + /// - The `cookie` parameter must be the cookie for a `Box<F>` and /// the owner must give up a ref-count to it. unsafe extern "C" fn cookie_decr_refcount<F>(cookie: *mut c_void) where F: Fn(&str) -> Option<ConnectionInfo> + Send + Sync + 'static, { - // Safety: The caller promises that `cookie` is for an Arc<F>. - unsafe { Arc::decrement_strong_count(cookie as *const F) }; + // Safety: The caller promises that `cookie` is for a Box<F>. + unsafe { std::mem::drop(Box::from_raw(cookie as *mut F)) }; } } @@ -296,7 +296,7 @@ impl AccessorProvider { where F: Fn(&str) -> Option<Accessor> + Send + Sync + 'static, { - let callback: *mut c_void = Arc::into_raw(Arc::new(provider)) as *mut c_void; + let callback: *mut c_void = Box::into_raw(Box::new(provider)) as *mut c_void; let c_str_instances: Vec<CString> = instances.iter().map(|s| CString::new(s.as_bytes()).unwrap()).collect(); let mut c_instances: Vec<*const c_char> = @@ -346,7 +346,7 @@ impl AccessorProvider { log::error!("Cookie({cookie:p}) or instance({instance:p}) is null!"); return ptr::null_mut(); } - // Safety: The caller promises that `cookie` is for an Arc<F>. + // Safety: The caller promises that `cookie` is for a Box<F>. let callback = unsafe { (cookie as *const F).as_ref().unwrap() }; let inst = { @@ -377,14 +377,14 @@ impl AccessorProvider { /// /// # Safety /// - /// - The `cookie` parameter must be the cookie for an `Arc<F>` and + /// - The `cookie` parameter must be the cookie for a `Box<F>` and /// the owner must give up a ref-count to it. unsafe extern "C" fn accessor_cookie_decr_refcount<F>(cookie: *mut c_void) where F: Fn(&str) -> Option<Accessor> + Send + Sync + 'static, { - // Safety: The caller promises that `cookie` is for an Arc<F>. - unsafe { Arc::decrement_strong_count(cookie as *const F) }; + // Safety: The caller promises that `cookie` is for a Box<F>. + unsafe { std::mem::drop(Box::from_raw(cookie as *mut F)) }; } } diff --git a/libs/binder/tests/binderLibTest.cpp b/libs/binder/tests/binderLibTest.cpp index c038c95b07..891c0a290c 100644 --- a/libs/binder/tests/binderLibTest.cpp +++ b/libs/binder/tests/binderLibTest.cpp @@ -44,6 +44,7 @@ #include <processgroup/processgroup.h> #include <utils/Flattenable.h> #include <utils/SystemClock.h> +#include "binder/IServiceManagerUnitTestHelper.h" #include <linux/sched.h> #include <sys/epoll.h> @@ -585,14 +586,14 @@ TEST_F(BinderLibTest, AddManagerToManager) { EXPECT_EQ(NO_ERROR, sm->addService(String16("binderLibTest-manager"), binder)); } +class LocalRegistrationCallbackImpl : public virtual IServiceManager::LocalRegistrationCallback { + void onServiceRegistration(const String16&, const sp<IBinder>&) override {} + virtual ~LocalRegistrationCallbackImpl() {} +}; + TEST_F(BinderLibTest, RegisterForNotificationsFailure) { auto sm = defaultServiceManager(); - using LocalRegistrationCallback = IServiceManager::LocalRegistrationCallback; - class LocalRegistrationCallbackImpl : public virtual LocalRegistrationCallback { - void onServiceRegistration(const String16&, const sp<IBinder>&) override {} - virtual ~LocalRegistrationCallbackImpl() {} - }; - sp<LocalRegistrationCallback> cb = sp<LocalRegistrationCallbackImpl>::make(); + sp<IServiceManager::LocalRegistrationCallback> cb = sp<LocalRegistrationCallbackImpl>::make(); EXPECT_EQ(BAD_VALUE, sm->registerForNotifications(String16("ValidName"), nullptr)); EXPECT_EQ(UNKNOWN_ERROR, sm->registerForNotifications(String16("InvalidName!$"), cb)); @@ -600,12 +601,7 @@ TEST_F(BinderLibTest, RegisterForNotificationsFailure) { TEST_F(BinderLibTest, UnregisterForNotificationsFailure) { auto sm = defaultServiceManager(); - using LocalRegistrationCallback = IServiceManager::LocalRegistrationCallback; - class LocalRegistrationCallbackImpl : public virtual LocalRegistrationCallback { - void onServiceRegistration(const String16&, const sp<IBinder>&) override {} - virtual ~LocalRegistrationCallbackImpl() {} - }; - sp<LocalRegistrationCallback> cb = sp<LocalRegistrationCallbackImpl>::make(); + sp<IServiceManager::LocalRegistrationCallback> cb = sp<LocalRegistrationCallbackImpl>::make(); EXPECT_EQ(OK, sm->registerForNotifications(String16("ValidName"), cb)); @@ -1788,6 +1784,43 @@ TEST(ServiceNotifications, Unregister) { EXPECT_EQ(sm->unregisterForNotifications(String16("RogerRafa"), cb), OK); } +// Make sure all IServiceManager APIs will function without an AIDL service +// manager registered on the device. +TEST(ServiceManagerNoAidlServer, SanityCheck) { + String16 kServiceName("no_services_exist"); + // This is what clients will see when there is no servicemanager process + // that registers itself as context object 0. + // Can't use setDefaultServiceManager() here because these test cases run in + // the same process and will abort when called twice or before/after + // defaultServiceManager(). + sp<IServiceManager> sm = getServiceManagerShimFromAidlServiceManagerForTests(nullptr); + auto status = sm->addService(kServiceName, sp<BBinder>::make()); + // CppBackendShim returns Status::exceptionCode as the status_t + EXPECT_EQ(status, Status::Exception::EX_UNSUPPORTED_OPERATION) << statusToString(status); + auto service = sm->checkService(String16("no_services_exist")); + EXPECT_TRUE(service == nullptr); + auto list = sm->listServices(android::IServiceManager::DUMP_FLAG_PRIORITY_ALL); + EXPECT_TRUE(list.isEmpty()); + bool declared = sm->isDeclared(kServiceName); + EXPECT_FALSE(declared); + list = sm->getDeclaredInstances(kServiceName); + EXPECT_TRUE(list.isEmpty()); + auto updatable = sm->updatableViaApex(kServiceName); + EXPECT_EQ(updatable, std::nullopt); + list = sm->getUpdatableNames(kServiceName); + EXPECT_TRUE(list.isEmpty()); + auto conInfo = sm->getConnectionInfo(kServiceName); + EXPECT_EQ(conInfo, std::nullopt); + auto cb = sp<LocalRegistrationCallbackImpl>::make(); + status = sm->registerForNotifications(kServiceName, cb); + EXPECT_EQ(status, UNKNOWN_ERROR) << statusToString(status); + status = sm->unregisterForNotifications(kServiceName, cb); + EXPECT_EQ(status, BAD_VALUE) << statusToString(status); + auto dbgInfos = sm->getServiceDebugInfo(); + EXPECT_TRUE(dbgInfos.empty()); + sm->enableAddServiceCache(true); +} + TEST_F(BinderLibTest, ThreadPoolAvailableThreads) { Parcel data, reply; sp<IBinder> server = addServer(); diff --git a/libs/binder/tests/binderRpcTest.cpp b/libs/binder/tests/binderRpcTest.cpp index da5a8e3881..9f656ec96c 100644 --- a/libs/binder/tests/binderRpcTest.cpp +++ b/libs/binder/tests/binderRpcTest.cpp @@ -1328,6 +1328,109 @@ TEST_P(BinderRpcAccessor, InjectNoSockaddrProvided) { EXPECT_EQ(status, OK); } +class BinderRpcAccessorNoConnection : public ::testing::Test {}; + +TEST_F(BinderRpcAccessorNoConnection, listServices) { + const String16 kInstanceName("super.cool.service/better_than_default"); + const String16 kInstanceName2("super.cool.service/better_than_default2"); + + auto receipt = + addAccessorProvider({String8(kInstanceName).c_str(), String8(kInstanceName2).c_str()}, + [&](const String16&) -> sp<IBinder> { return nullptr; }); + EXPECT_FALSE(receipt.expired()); + Vector<String16> list = + defaultServiceManager()->listServices(IServiceManager::DUMP_FLAG_PRIORITY_ALL); + bool name1 = false; + bool name2 = false; + for (auto name : list) { + if (name == kInstanceName) name1 = true; + if (name == kInstanceName2) name2 = true; + } + EXPECT_TRUE(name1); + EXPECT_TRUE(name2); + status_t status = removeAccessorProvider(receipt); + EXPECT_EQ(status, OK); +} + +TEST_F(BinderRpcAccessorNoConnection, isDeclared) { + const String16 kInstanceName("super.cool.service/default"); + const String16 kInstanceName2("still_counts_as_declared"); + + auto receipt = + addAccessorProvider({String8(kInstanceName).c_str(), String8(kInstanceName2).c_str()}, + [&](const String16&) -> sp<IBinder> { return nullptr; }); + EXPECT_FALSE(receipt.expired()); + EXPECT_TRUE(defaultServiceManager()->isDeclared(kInstanceName)); + EXPECT_TRUE(defaultServiceManager()->isDeclared(kInstanceName2)); + EXPECT_FALSE(defaultServiceManager()->isDeclared(String16("doesnt_exist"))); + status_t status = removeAccessorProvider(receipt); + EXPECT_EQ(status, OK); +} + +TEST_F(BinderRpcAccessorNoConnection, getDeclaredInstances) { + const String16 kInstanceName("super.cool.service.IFoo/default"); + const String16 kInstanceName2("super.cool.service.IFoo/extra/default"); + const String16 kInstanceName3("super.cool.service.IFoo"); + + auto receipt = + addAccessorProvider({String8(kInstanceName).c_str(), String8(kInstanceName2).c_str(), + String8(kInstanceName3).c_str()}, + [&](const String16&) -> sp<IBinder> { return nullptr; }); + EXPECT_FALSE(receipt.expired()); + Vector<String16> list = + defaultServiceManager()->getDeclaredInstances(String16("super.cool.service.IFoo")); + // We would prefer ASSERT_EQ here, but we must call removeAccessorProvider + EXPECT_EQ(list.size(), 3u); + if (list.size() == 3) { + bool name1 = false; + bool name2 = false; + bool name3 = false; + for (auto name : list) { + if (name == String16("default")) name1 = true; + if (name == String16("extra/default")) name2 = true; + if (name == String16()) name3 = true; + } + EXPECT_TRUE(name1) << String8(list[0]); + EXPECT_TRUE(name2) << String8(list[1]); + EXPECT_TRUE(name3) << String8(list[2]); + } + + status_t status = removeAccessorProvider(receipt); + EXPECT_EQ(status, OK); +} + +TEST_F(BinderRpcAccessorNoConnection, getDeclaredWrongInstances) { + const String16 kInstanceName("super.cool.service.IFoo"); + + auto receipt = addAccessorProvider({String8(kInstanceName).c_str()}, + [&](const String16&) -> sp<IBinder> { return nullptr; }); + EXPECT_FALSE(receipt.expired()); + Vector<String16> list = defaultServiceManager()->getDeclaredInstances(String16("unknown")); + EXPECT_TRUE(list.empty()); + + status_t status = removeAccessorProvider(receipt); + EXPECT_EQ(status, OK); +} + +TEST_F(BinderRpcAccessorNoConnection, getDeclaredInstancesSlash) { + // This is treated as if there were no '/' and the declared instance is "" + const String16 kInstanceName("super.cool.service.IFoo/"); + + auto receipt = addAccessorProvider({String8(kInstanceName).c_str()}, + [&](const String16&) -> sp<IBinder> { return nullptr; }); + EXPECT_FALSE(receipt.expired()); + Vector<String16> list = + defaultServiceManager()->getDeclaredInstances(String16("super.cool.service.IFoo")); + bool name1 = false; + for (auto name : list) { + if (name == String16("")) name1 = true; + } + EXPECT_TRUE(name1); + + status_t status = removeAccessorProvider(receipt); + EXPECT_EQ(status, OK); +} + constexpr const char* kARpcInstance = "some.instance.name.IFoo/default"; const char* kARpcSupportedServices[] = { kARpcInstance, |