/* * Copyright (C) 2024 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. */ #include #include #include #include #include #include #include #include "fakeservicemanager/FakeServiceManager.h" #include #include using namespace android; #ifdef LIBBINDER_CLIENT_CACHE constexpr bool kUseLibbinderCache = true; #else constexpr bool kUseLibbinderCache = false; #endif #ifdef LIBBINDER_ADDSERVICE_CACHE constexpr bool kUseCacheInAddService = true; #else constexpr bool kUseCacheInAddService = false; #endif #ifdef LIBBINDER_REMOVE_CACHE_STATIC_LIST constexpr bool kRemoveStaticList = true; #else constexpr bool kRemoveStaticList = false; #endif // A service name which is in the static list of cachable services const String16 kCachedServiceName = String16("isub"); #define EXPECT_OK(status) \ do { \ binder::Status stat = (status); \ EXPECT_TRUE(stat.isOk()) << stat; \ } while (false) const String16 kServerName = String16("binderCacheUnitTest"); class FooBar : public BBinder { public: status_t onTransact(uint32_t, const Parcel&, Parcel*, uint32_t) { // exit the server std::thread([] { exit(EXIT_FAILURE); }).detach(); return OK; } void killServer(sp binder) { Parcel data, reply; binder->transact(0, data, &reply, 0); } }; class MockAidlServiceManager : public os::IServiceManagerDefault { public: MockAidlServiceManager() : innerSm() {} binder::Status checkService(const ::std::string& name, os::Service* _out) override { os::ServiceWithMetadata serviceWithMetadata = os::ServiceWithMetadata(); serviceWithMetadata.service = innerSm.getService(String16(name.c_str())); serviceWithMetadata.isLazyService = false; *_out = os::Service::make(serviceWithMetadata); return binder::Status::ok(); } binder::Status addService(const std::string& name, const sp& service, bool allowIsolated, int32_t dumpPriority) override { return binder::Status::fromStatusT( innerSm.addService(String16(name.c_str()), service, allowIsolated, dumpPriority)); } void clearServices() { innerSm.clear(); } FakeServiceManager innerSm; }; // Returns services with isLazyService flag as true. class MockAidlServiceManager2 : public os::IServiceManagerDefault { public: MockAidlServiceManager2() : innerSm() {} binder::Status checkService(const ::std::string& name, os::Service* _out) override { os::ServiceWithMetadata serviceWithMetadata = os::ServiceWithMetadata(); serviceWithMetadata.service = innerSm.getService(String16(name.c_str())); serviceWithMetadata.isLazyService = true; *_out = os::Service::make(serviceWithMetadata); return binder::Status::ok(); } binder::Status addService(const std::string& name, const sp& service, bool allowIsolated, int32_t dumpPriority) override { return binder::Status::fromStatusT( innerSm.addService(String16(name.c_str()), service, allowIsolated, dumpPriority)); } void clearServices() { innerSm.clear(); } FakeServiceManager innerSm; }; class LibbinderCacheRemoveStaticList : public ::testing::Test { protected: void SetUp() override { fakeServiceManager = sp::make(); mServiceManager = getServiceManagerShimFromAidlServiceManagerForTests(fakeServiceManager); mServiceManager->enableAddServiceCache(true); } void TearDown() override {} public: void cacheAddServiceAndConfirmCacheMiss(const sp& binder1) { // Add a service. This shouldn't cache it. EXPECT_EQ(OK, mServiceManager->addService(kCachedServiceName, binder1, /*allowIsolated = */ false, android::os::IServiceManager::FLAG_IS_LAZY_SERVICE)); // Try to populate cache. Cache shouldn't be updated. EXPECT_EQ(binder1, mServiceManager->checkService(kCachedServiceName)); fakeServiceManager->clearServices(); EXPECT_EQ(nullptr, mServiceManager->checkService(kCachedServiceName)); } sp fakeServiceManager; sp mServiceManager; }; TEST_F(LibbinderCacheRemoveStaticList, AddLocalServiceAndConfirmCacheMiss) { if (!kRemoveStaticList) { GTEST_SKIP() << "Skipping as feature is not enabled"; return; } sp binder1 = sp::make(); cacheAddServiceAndConfirmCacheMiss(binder1); } TEST_F(LibbinderCacheRemoveStaticList, AddRemoteServiceAndConfirmCacheMiss) { if (!kRemoveStaticList) { GTEST_SKIP() << "Skipping as feature is not enabled"; return; } sp binder1 = defaultServiceManager()->checkService(kServerName); ASSERT_NE(binder1, nullptr); cacheAddServiceAndConfirmCacheMiss(binder1); } class LibbinderCacheAddServiceTest : public ::testing::Test { protected: void SetUp() override { fakeServiceManager = sp::make(); mServiceManager = getServiceManagerShimFromAidlServiceManagerForTests(fakeServiceManager); mServiceManager->enableAddServiceCache(true); } void TearDown() override {} public: void cacheAddServiceAndConfirmCacheHit(const sp& binder1) { // Add a service. This also caches it. EXPECT_EQ(OK, mServiceManager->addService(kCachedServiceName, binder1)); // remove services from fakeservicemanager fakeServiceManager->clearServices(); sp result = mServiceManager->checkService(kCachedServiceName); if (kUseCacheInAddService && kUseLibbinderCache) { // If cache is enabled, we should get the binder. EXPECT_EQ(binder1, result); } else { // If cache is disabled, then we should get the null binder EXPECT_EQ(nullptr, result); } } sp fakeServiceManager; sp mServiceManager; }; TEST_F(LibbinderCacheAddServiceTest, AddLocalServiceAndConfirmCacheHit) { sp binder1 = sp::make(); cacheAddServiceAndConfirmCacheHit(binder1); } TEST_F(LibbinderCacheAddServiceTest, AddRemoteServiceAndConfirmCacheHit) { sp binder1 = defaultServiceManager()->checkService(kServerName); ASSERT_NE(binder1, nullptr); cacheAddServiceAndConfirmCacheHit(binder1); } class LibbinderCacheTest : public ::testing::Test { protected: void SetUp() override { fakeServiceManager = sp::make(); mServiceManager = getServiceManagerShimFromAidlServiceManagerForTests(fakeServiceManager); mServiceManager->enableAddServiceCache(false); } void TearDown() override {} public: void cacheAndConfirmCacheHit(const sp& binder1, const sp& binder2) { // Add a service EXPECT_EQ(OK, mServiceManager->addService(kCachedServiceName, binder1)); // Get the service. This caches it. sp result = mServiceManager->checkService(kCachedServiceName); ASSERT_EQ(binder1, result); // Add the different binder and replace the service. // The cache should still hold the original binder. EXPECT_EQ(OK, mServiceManager->addService(kCachedServiceName, binder2)); result = mServiceManager->checkService(kCachedServiceName); if (kUseLibbinderCache) { // If cache is enabled, we should get the binder to Service Manager. EXPECT_EQ(binder1, result); } else { // If cache is disabled, then we should get the newer binder EXPECT_EQ(binder2, result); } } sp fakeServiceManager; sp mServiceManager; }; TEST_F(LibbinderCacheTest, AddLocalServiceAndConfirmCacheHit) { sp binder1 = sp::make(); sp binder2 = sp::make(); cacheAndConfirmCacheHit(binder1, binder2); } TEST_F(LibbinderCacheTest, AddRemoteServiceAndConfirmCacheHit) { sp binder1 = defaultServiceManager()->checkService(kServerName); ASSERT_NE(binder1, nullptr); sp binder2 = IInterface::asBinder(mServiceManager); cacheAndConfirmCacheHit(binder1, binder2); } TEST_F(LibbinderCacheTest, RemoveFromCacheOnServerDeath) { sp binder1 = defaultServiceManager()->checkService(kServerName); FooBar foo = FooBar(); EXPECT_EQ(OK, mServiceManager->addService(kCachedServiceName, binder1)); // Check Service, this caches the binder sp result = mServiceManager->checkService(kCachedServiceName); ASSERT_EQ(binder1, result); // Kill the server, this should remove from cache. pid_t pid; ASSERT_EQ(OK, binder1->getDebugPid(&pid)); foo.killServer(binder1); system(("kill -9 " + std::to_string(pid)).c_str()); sp binder2 = sp::make(); // Add new service with the same name. // This will replace the service in FakeServiceManager. EXPECT_EQ(OK, mServiceManager->addService(kCachedServiceName, binder2)); // Confirm that new service is returned instead of old. int retry_count = 20; sp result2; do { std::this_thread::sleep_for(std::chrono::milliseconds(50)); if (retry_count-- == 0) { break; } result2 = mServiceManager->checkService(kCachedServiceName); } while (result2 != binder2); ASSERT_EQ(binder2, result2); } TEST_F(LibbinderCacheTest, NullBinderNotCached) { sp binder1 = nullptr; sp binder2 = sp::make(); // Check for a cacheble service which isn't registered. // FakeServiceManager should return nullptr. // This shouldn't be cached. sp result = mServiceManager->checkService(kCachedServiceName); ASSERT_EQ(binder1, result); // Add the same service EXPECT_EQ(OK, mServiceManager->addService(kCachedServiceName, binder2)); // This should return the newly added service. result = mServiceManager->checkService(kCachedServiceName); EXPECT_EQ(binder2, result); } // TODO(b/333854840): Remove this test removing the static list TEST_F(LibbinderCacheTest, DoNotCacheServiceNotInList) { if (kRemoveStaticList) { GTEST_SKIP() << "Skipping test as static list is disabled"; return; } sp binder1 = sp::make(); sp binder2 = sp::make(); String16 serviceName = String16("NewLibbinderCacheTest"); // Add a service EXPECT_EQ(OK, mServiceManager->addService(serviceName, binder1)); // Get the service. This shouldn't caches it. sp result = mServiceManager->checkService(serviceName); ASSERT_EQ(binder1, result); // Add the different binder and replace the service. EXPECT_EQ(OK, mServiceManager->addService(serviceName, binder2)); // Confirm that we get the new service result = mServiceManager->checkService(serviceName); EXPECT_EQ(binder2, result); } int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); if (fork() == 0) { prctl(PR_SET_PDEATHSIG, SIGHUP); // Start a FooBar service and add it to the servicemanager. sp server = new FooBar(); defaultServiceManager()->addService(kServerName, server); IPCThreadState::self()->joinThreadPool(true); exit(1); // should not reach } status_t err = ProcessState::self()->setThreadPoolMaxThreadCount(3); ProcessState::self()->startThreadPool(); CHECK_EQ(ProcessState::self()->isThreadPoolStarted(), true); CHECK_GT(ProcessState::self()->getThreadPoolMaxTotalThreadCount(), 0); auto binder = defaultServiceManager()->waitForService(kServerName); CHECK_NE(nullptr, binder.get()); return RUN_ALL_TESTS(); }