blob: 19395c2dcd362e671693c2b184e34e20c9988e73 [file] [log] [blame] [edit]
/*
* 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 <gtest/gtest.h>
#include <android-base/logging.h>
#include <android/os/IServiceManager.h>
#include <binder/IBinder.h>
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
#include <binder/IServiceManagerUnitTestHelper.h>
#include "fakeservicemanager/FakeServiceManager.h"
#include <sys/prctl.h>
#include <thread>
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<IBinder> 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<os::Service::Tag::serviceWithMetadata>(serviceWithMetadata);
return binder::Status::ok();
}
binder::Status addService(const std::string& name, const sp<IBinder>& 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<os::Service::Tag::serviceWithMetadata>(serviceWithMetadata);
return binder::Status::ok();
}
binder::Status addService(const std::string& name, const sp<IBinder>& 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<MockAidlServiceManager2>::make();
mServiceManager = getServiceManagerShimFromAidlServiceManagerForTests(fakeServiceManager);
mServiceManager->enableAddServiceCache(true);
}
void TearDown() override {}
public:
void cacheAddServiceAndConfirmCacheMiss(const sp<IBinder>& 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<MockAidlServiceManager2> fakeServiceManager;
sp<android::IServiceManager> mServiceManager;
};
TEST_F(LibbinderCacheRemoveStaticList, AddLocalServiceAndConfirmCacheMiss) {
if (!kRemoveStaticList) {
GTEST_SKIP() << "Skipping as feature is not enabled";
return;
}
sp<IBinder> binder1 = sp<BBinder>::make();
cacheAddServiceAndConfirmCacheMiss(binder1);
}
TEST_F(LibbinderCacheRemoveStaticList, AddRemoteServiceAndConfirmCacheMiss) {
if (!kRemoveStaticList) {
GTEST_SKIP() << "Skipping as feature is not enabled";
return;
}
sp<IBinder> binder1 = defaultServiceManager()->checkService(kServerName);
ASSERT_NE(binder1, nullptr);
cacheAddServiceAndConfirmCacheMiss(binder1);
}
class LibbinderCacheAddServiceTest : public ::testing::Test {
protected:
void SetUp() override {
fakeServiceManager = sp<MockAidlServiceManager>::make();
mServiceManager = getServiceManagerShimFromAidlServiceManagerForTests(fakeServiceManager);
mServiceManager->enableAddServiceCache(true);
}
void TearDown() override {}
public:
void cacheAddServiceAndConfirmCacheHit(const sp<IBinder>& binder1) {
// Add a service. This also caches it.
EXPECT_EQ(OK, mServiceManager->addService(kCachedServiceName, binder1));
// remove services from fakeservicemanager
fakeServiceManager->clearServices();
sp<IBinder> 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<MockAidlServiceManager> fakeServiceManager;
sp<android::IServiceManager> mServiceManager;
};
TEST_F(LibbinderCacheAddServiceTest, AddLocalServiceAndConfirmCacheHit) {
sp<IBinder> binder1 = sp<BBinder>::make();
cacheAddServiceAndConfirmCacheHit(binder1);
}
TEST_F(LibbinderCacheAddServiceTest, AddRemoteServiceAndConfirmCacheHit) {
sp<IBinder> binder1 = defaultServiceManager()->checkService(kServerName);
ASSERT_NE(binder1, nullptr);
cacheAddServiceAndConfirmCacheHit(binder1);
}
class LibbinderCacheTest : public ::testing::Test {
protected:
void SetUp() override {
fakeServiceManager = sp<MockAidlServiceManager>::make();
mServiceManager = getServiceManagerShimFromAidlServiceManagerForTests(fakeServiceManager);
mServiceManager->enableAddServiceCache(false);
}
void TearDown() override {}
public:
void cacheAndConfirmCacheHit(const sp<IBinder>& binder1, const sp<IBinder>& binder2) {
// Add a service
EXPECT_EQ(OK, mServiceManager->addService(kCachedServiceName, binder1));
// Get the service. This caches it.
sp<IBinder> 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<MockAidlServiceManager> fakeServiceManager;
sp<android::IServiceManager> mServiceManager;
};
TEST_F(LibbinderCacheTest, AddLocalServiceAndConfirmCacheHit) {
sp<IBinder> binder1 = sp<BBinder>::make();
sp<IBinder> binder2 = sp<BBinder>::make();
cacheAndConfirmCacheHit(binder1, binder2);
}
TEST_F(LibbinderCacheTest, AddRemoteServiceAndConfirmCacheHit) {
sp<IBinder> binder1 = defaultServiceManager()->checkService(kServerName);
ASSERT_NE(binder1, nullptr);
sp<IBinder> binder2 = IInterface::asBinder(mServiceManager);
cacheAndConfirmCacheHit(binder1, binder2);
}
TEST_F(LibbinderCacheTest, RemoveFromCacheOnServerDeath) {
sp<IBinder> binder1 = defaultServiceManager()->checkService(kServerName);
FooBar foo = FooBar();
EXPECT_EQ(OK, mServiceManager->addService(kCachedServiceName, binder1));
// Check Service, this caches the binder
sp<IBinder> 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<IBinder> binder2 = sp<BBinder>::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<IBinder> 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<IBinder> binder1 = nullptr;
sp<IBinder> binder2 = sp<BBinder>::make();
// Check for a cacheble service which isn't registered.
// FakeServiceManager should return nullptr.
// This shouldn't be cached.
sp<IBinder> 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<IBinder> binder1 = sp<BBinder>::make();
sp<IBinder> binder2 = sp<BBinder>::make();
String16 serviceName = String16("NewLibbinderCacheTest");
// Add a service
EXPECT_EQ(OK, mServiceManager->addService(serviceName, binder1));
// Get the service. This shouldn't caches it.
sp<IBinder> 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<IBinder> 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();
}