Merge "Cleanup: remove VNDK APEX exception from binder"
diff --git a/cmds/servicemanager/ServiceManager.cpp b/cmds/servicemanager/ServiceManager.cpp
index ae74ac3..abe6436 100644
--- a/cmds/servicemanager/ServiceManager.cpp
+++ b/cmds/servicemanager/ServiceManager.cpp
@@ -423,11 +423,12 @@
void ServiceManager::handleClientCallbacks() {
for (const auto& [name, service] : mNameToService) {
- handleServiceClientCallback(name);
+ handleServiceClientCallback(name, true);
}
}
-ssize_t ServiceManager::handleServiceClientCallback(const std::string& serviceName) {
+ssize_t ServiceManager::handleServiceClientCallback(const std::string& serviceName,
+ bool isCalledOnInterval) {
auto serviceIt = mNameToService.find(serviceName);
if (serviceIt == mNameToService.end() || mNameToClientCallback.count(serviceName) < 1) {
return -1;
@@ -451,14 +452,17 @@
service.guaranteeClient = false;
}
- if (hasClients && !service.hasClients) {
- // client was retrieved in some other way
- sendClientCallbackNotifications(serviceName, true);
- }
+ // only send notifications if this was called via the interval checking workflow
+ if (isCalledOnInterval) {
+ if (hasClients && !service.hasClients) {
+ // client was retrieved in some other way
+ sendClientCallbackNotifications(serviceName, true);
+ }
- // there are no more clients, but the callback has not been called yet
- if (!hasClients && service.hasClients) {
- sendClientCallbackNotifications(serviceName, false);
+ // there are no more clients, but the callback has not been called yet
+ if (!hasClients && service.hasClients) {
+ sendClientCallbackNotifications(serviceName, false);
+ }
}
return count;
@@ -518,7 +522,7 @@
return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE);
}
- int clients = handleServiceClientCallback(name);
+ int clients = handleServiceClientCallback(name, false);
// clients < 0: feature not implemented or other error. Assume clients.
// Otherwise:
@@ -527,7 +531,7 @@
// So, if clients > 2, then at least one other service on the system must hold a refcount.
if (clients < 0 || clients > 2) {
// client callbacks are either disabled or there are other clients
- LOG(INFO) << "Tried to unregister " << name << " but there are clients: " << clients;
+ LOG(INFO) << "Tried to unregister " << name << ", but there are clients: " << clients;
return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE);
}
diff --git a/cmds/servicemanager/ServiceManager.h b/cmds/servicemanager/ServiceManager.h
index 77f5250..a2fc5a8 100644
--- a/cmds/servicemanager/ServiceManager.h
+++ b/cmds/servicemanager/ServiceManager.h
@@ -75,7 +75,7 @@
void removeRegistrationCallback(const wp<IBinder>& who,
ServiceCallbackMap::iterator* it,
bool* found);
- ssize_t handleServiceClientCallback(const std::string& serviceName);
+ ssize_t handleServiceClientCallback(const std::string& serviceName, bool isCalledOnInterval);
// Also updates mHasClients (of what the last callback was)
void sendClientCallbackNotifications(const std::string& serviceName, bool hasClients);
// removes a callback from mNameToClientCallback, deleting the entry if the vector is empty
diff --git a/libs/adbd_auth/Android.bp b/libs/adbd_auth/Android.bp
index 9cf0143..8ac044c 100644
--- a/libs/adbd_auth/Android.bp
+++ b/libs/adbd_auth/Android.bp
@@ -20,11 +20,14 @@
"-Wthread-safety",
"-Werror",
],
+ stl: "libc++_static",
+
srcs: ["adbd_auth.cpp"],
export_include_dirs: ["include"],
version_script: "libadbd_auth.map.txt",
stubs: {
+ versions: ["1"],
symbol_file: "libadbd_auth.map.txt",
},
@@ -36,7 +39,7 @@
}
},
- shared_libs: [
+ static_libs: [
"libbase",
"libcutils",
"liblog",
diff --git a/libs/binder/BpBinder.cpp b/libs/binder/BpBinder.cpp
index 238c9dc..f16c39c 100644
--- a/libs/binder/BpBinder.cpp
+++ b/libs/binder/BpBinder.cpp
@@ -435,7 +435,8 @@
Vector<Obituary>* obits = mObituaries;
if(obits != nullptr) {
if (!obits->isEmpty()) {
- ALOGI("onLastStrongRef automatically unlinking death recipients");
+ ALOGI("onLastStrongRef automatically unlinking death recipients: %s",
+ mDescriptorCache.size() ? String8(mDescriptorCache).c_str() : "<uncached descriptor>");
}
if (ipc) ipc->clearDeathNotification(mHandle, this);
diff --git a/libs/binder/BufferedTextOutput.cpp b/libs/binder/BufferedTextOutput.cpp
index fb424fd..856a178 100644
--- a/libs/binder/BufferedTextOutput.cpp
+++ b/libs/binder/BufferedTextOutput.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#include <binder/BufferedTextOutput.h>
+#include "BufferedTextOutput.h"
#include <binder/Debug.h>
#include <cutils/atomic.h>
diff --git a/libs/binder/include/binder/BufferedTextOutput.h b/libs/binder/BufferedTextOutput.h
similarity index 100%
rename from libs/binder/include/binder/BufferedTextOutput.h
rename to libs/binder/BufferedTextOutput.h
diff --git a/libs/binder/IServiceManager.cpp b/libs/binder/IServiceManager.cpp
index 5ca9156..328653a 100644
--- a/libs/binder/IServiceManager.cpp
+++ b/libs/binder/IServiceManager.cpp
@@ -85,10 +85,11 @@
sp<AidlServiceManager> mTheRealServiceManager;
};
+static Mutex gDefaultServiceManagerLock;
+static sp<IServiceManager> gDefaultServiceManager;
+
sp<IServiceManager> defaultServiceManager()
{
- static Mutex gDefaultServiceManagerLock;
- static sp<IServiceManager> gDefaultServiceManager;
if (gDefaultServiceManager != nullptr) return gDefaultServiceManager;
@@ -106,6 +107,11 @@
return gDefaultServiceManager;
}
+void setDefaultServiceManager(const sp<IServiceManager>& sm) {
+ AutoMutex _l(gDefaultServiceManagerLock);
+ gDefaultServiceManager = sm;
+}
+
#if !defined(__ANDROID_VNDK__) && defined(__ANDROID__)
// IPermissionController is not accessible to vendors
diff --git a/libs/binder/LazyServiceRegistrar.cpp b/libs/binder/LazyServiceRegistrar.cpp
index dc9482c..f064bd7 100644
--- a/libs/binder/LazyServiceRegistrar.cpp
+++ b/libs/binder/LazyServiceRegistrar.cpp
@@ -53,14 +53,13 @@
struct Service {
sp<IBinder> service;
- std::string name;
bool allowIsolated;
int dumpFlags;
};
/**
- * Number of services that have been registered.
+ * Map of registered names and services
*/
- std::vector<Service> mRegisteredServices;
+ std::map<std::string, Service> mRegisteredServices;
};
bool ClientCounterCallback::registerService(const sp<IBinder>& service, const std::string& name,
@@ -68,20 +67,24 @@
auto manager = interface_cast<AidlServiceManager>(
ProcessState::self()->getContextObject(nullptr));
- ALOGI("Registering service %s", name.c_str());
+ bool reRegister = mRegisteredServices.count(name) > 0;
+ std::string regStr = (reRegister) ? "Re-registering" : "Registering";
+ ALOGI("%s service %s", regStr.c_str(), name.c_str());
if (!manager->addService(name.c_str(), service, allowIsolated, dumpFlags).isOk()) {
ALOGE("Failed to register service %s", name.c_str());
return false;
}
- if (!manager->registerClientCallback(name, service, this).isOk())
- {
- ALOGE("Failed to add client callback for service %s", name.c_str());
- return false;
+ if (!manager->registerClientCallback(name, service, this).isOk()) {
+ ALOGE("Failed to add client callback for service %s", name.c_str());
+ return false;
}
- mRegisteredServices.push_back({service, name, allowIsolated, dumpFlags});
+ if (!reRegister) {
+ // Only add this when a service is added for the first time, as it is not removed
+ mRegisteredServices[name] = {service, allowIsolated, dumpFlags};
+ }
return true;
}
@@ -119,10 +122,11 @@
for (; unRegisterIt != mRegisteredServices.end(); ++unRegisterIt) {
auto& entry = (*unRegisterIt);
- bool success = manager->tryUnregisterService(entry.name, entry.service).isOk();
+ bool success = manager->tryUnregisterService(entry.first, entry.second.service).isOk();
+
if (!success) {
- ALOGI("Failed to unregister service %s", entry.name.c_str());
+ ALOGI("Failed to unregister service %s", entry.first.c_str());
break;
}
}
@@ -137,7 +141,8 @@
auto& entry = (*reRegisterIt);
// re-register entry
- if (!registerService(entry.service, entry.name, entry.allowIsolated, entry.dumpFlags)) {
+ if (!registerService(entry.second.service, entry.first, entry.second.allowIsolated,
+ entry.second.dumpFlags)) {
// Must restart. Otherwise, clients will never be able to get a hold of this service.
ALOGE("Bad state: could not re-register services");
}
diff --git a/libs/binder/Static.cpp b/libs/binder/Static.cpp
index bd40536..7a77f6d 100644
--- a/libs/binder/Static.cpp
+++ b/libs/binder/Static.cpp
@@ -19,7 +19,7 @@
#include "Static.h"
-#include <binder/BufferedTextOutput.h>
+#include "BufferedTextOutput.h"
#include <binder/IPCThreadState.h>
#include <utils/Log.h>
diff --git a/libs/binder/TEST_MAPPING b/libs/binder/TEST_MAPPING
index 55419eb..7489afa 100644
--- a/libs/binder/TEST_MAPPING
+++ b/libs/binder/TEST_MAPPING
@@ -23,6 +23,9 @@
},
{
"name": "CtsNdkBinderTestCases"
+ },
+ {
+ "name": "aidl_lazy_test"
}
]
}
diff --git a/libs/binder/include/binder/IServiceManager.h b/libs/binder/include/binder/IServiceManager.h
index 2c43263..31f022d 100644
--- a/libs/binder/include/binder/IServiceManager.h
+++ b/libs/binder/include/binder/IServiceManager.h
@@ -100,6 +100,11 @@
sp<IServiceManager> defaultServiceManager();
+/**
+ * Directly set the default service manager. Only used for testing.
+ */
+void setDefaultServiceManager(const sp<IServiceManager>& sm);
+
template<typename INTERFACE>
sp<INTERFACE> waitForService(const String16& name) {
const sp<IServiceManager> sm = defaultServiceManager();
diff --git a/libs/binder/ndk/test/Android.bp b/libs/binder/ndk/test/Android.bp
index e598eec..513d8c2 100644
--- a/libs/binder/ndk/test/Android.bp
+++ b/libs/binder/ndk/test/Android.bp
@@ -59,6 +59,9 @@
name: "libbinder_ndk_unit_test",
defaults: ["test_libbinder_ndk_test_defaults"],
srcs: ["libbinder_ndk_unit_test.cpp"],
+ static_libs: [
+ "IBinderNdkUnitTest-ndk_platform",
+ ],
test_suites: ["general-tests"],
require_root: true,
@@ -93,3 +96,11 @@
"IBinderVendorDoubleLoadTest.aidl",
],
}
+
+aidl_interface {
+ name: "IBinderNdkUnitTest",
+ srcs: [
+ "IBinderNdkUnitTest.aidl",
+ "IEmpty.aidl",
+ ],
+}
diff --git a/libs/binder/ndk/test/IBinderNdkUnitTest.aidl b/libs/binder/ndk/test/IBinderNdkUnitTest.aidl
new file mode 100644
index 0000000..6e8e463
--- /dev/null
+++ b/libs/binder/ndk/test/IBinderNdkUnitTest.aidl
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+// This AIDL is to test things that can't be tested in CtsNdkBinderTestCases
+// because it requires libbinder_ndk implementation details or APIs not
+// available to apps. Please prefer adding tests to CtsNdkBinderTestCases
+// over here.
+
+import IEmpty;
+
+interface IBinderNdkUnitTest {
+ void takeInterface(IEmpty test);
+ void forceFlushCommands();
+}
diff --git a/libs/binder/ndk/test/IEmpty.aidl b/libs/binder/ndk/test/IEmpty.aidl
new file mode 100644
index 0000000..95e4341
--- /dev/null
+++ b/libs/binder/ndk/test/IEmpty.aidl
@@ -0,0 +1,17 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+interface IEmpty { }
diff --git a/libs/binder/ndk/test/libbinder_ndk_unit_test.cpp b/libs/binder/ndk/test/libbinder_ndk_unit_test.cpp
index 8aba411..51dd169 100644
--- a/libs/binder/ndk/test/libbinder_ndk_unit_test.cpp
+++ b/libs/binder/ndk/test/libbinder_ndk_unit_test.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#include <aidl/BnBinderNdkUnitTest.h>
+#include <aidl/BnEmpty.h>
#include <android-base/logging.h>
#include <android/binder_ibinder_jni.h>
#include <android/binder_manager.h>
@@ -21,6 +23,10 @@
#include <gtest/gtest.h>
#include <iface/iface.h>
+// warning: this is assuming that libbinder_ndk is using the same copy
+// of libbinder that we are.
+#include <binder/IPCThreadState.h>
+
#include <sys/prctl.h>
#include <chrono>
#include <condition_variable>
@@ -29,7 +35,38 @@
using ::android::sp;
constexpr char kExistingNonNdkService[] = "SurfaceFlinger";
+constexpr char kBinderNdkUnitTestService[] = "BinderNdkUnitTest";
+class MyBinderNdkUnitTest : public aidl::BnBinderNdkUnitTest {
+ ndk::ScopedAStatus takeInterface(const std::shared_ptr<aidl::IEmpty>& empty) {
+ (void)empty;
+ return ndk::ScopedAStatus::ok();
+ }
+ ndk::ScopedAStatus forceFlushCommands() {
+ // warning: this is assuming that libbinder_ndk is using the same copy
+ // of libbinder that we are.
+ android::IPCThreadState::self()->flushCommands();
+ return ndk::ScopedAStatus::ok();
+ }
+};
+
+int generatedService() {
+ ABinderProcess_setThreadPoolMaxThreadCount(0);
+
+ auto service = ndk::SharedRefBase::make<MyBinderNdkUnitTest>();
+ binder_status_t status =
+ AServiceManager_addService(service->asBinder().get(), kBinderNdkUnitTestService);
+
+ if (status != STATUS_OK) {
+ LOG(FATAL) << "Could not register: " << status << " " << kBinderNdkUnitTestService;
+ }
+
+ ABinderProcess_joinThreadPool();
+
+ return 1; // should not return
+}
+
+// manually-written parceling class considered bad practice
class MyFoo : public IFoo {
binder_status_t doubleNumber(int32_t in, int32_t* out) override {
*out = 2 * in;
@@ -43,7 +80,7 @@
}
};
-int service(const char* instance) {
+int manualService(const char* instance) {
ABinderProcess_setThreadPoolMaxThreadCount(0);
// Strong reference to MyFoo kept by service manager.
@@ -225,16 +262,54 @@
EXPECT_EQ(IFoo::getService(kInstanceName1), IFoo::getService(kInstanceName2));
}
+TEST(NdkBinder, SentAidlBinderCanBeDestroyed) {
+ static volatile bool destroyed = false;
+ static std::mutex dMutex;
+ static std::condition_variable cv;
+
+ class MyEmpty : public aidl::BnEmpty {
+ virtual ~MyEmpty() {
+ destroyed = true;
+ cv.notify_one();
+ }
+ };
+
+ std::shared_ptr<MyEmpty> empty = ndk::SharedRefBase::make<MyEmpty>();
+
+ ndk::SpAIBinder binder(AServiceManager_getService(kBinderNdkUnitTestService));
+ std::shared_ptr<aidl::IBinderNdkUnitTest> service =
+ aidl::IBinderNdkUnitTest::fromBinder(binder);
+
+ EXPECT_FALSE(destroyed);
+
+ service->takeInterface(empty);
+ service->forceFlushCommands();
+ empty = nullptr;
+
+ // give other binder thread time to process commands
+ {
+ using namespace std::chrono_literals;
+ std::unique_lock<std::mutex> lk(dMutex);
+ cv.wait_for(lk, 1s, [] { return destroyed; });
+ }
+
+ EXPECT_TRUE(destroyed);
+}
+
int main(int argc, char* argv[]) {
::testing::InitGoogleTest(&argc, argv);
if (fork() == 0) {
prctl(PR_SET_PDEATHSIG, SIGHUP);
- return service(IFoo::kInstanceNameToDieFor);
+ return manualService(IFoo::kInstanceNameToDieFor);
}
if (fork() == 0) {
prctl(PR_SET_PDEATHSIG, SIGHUP);
- return service(IFoo::kSomeInstanceName);
+ return manualService(IFoo::kSomeInstanceName);
+ }
+ if (fork() == 0) {
+ prctl(PR_SET_PDEATHSIG, SIGHUP);
+ return generatedService();
}
ABinderProcess_setThreadPoolMaxThreadCount(1); // to recieve death notifications/callbacks
diff --git a/libs/fakeservicemanager/Android.bp b/libs/fakeservicemanager/Android.bp
new file mode 100644
index 0000000..de32ff4
--- /dev/null
+++ b/libs/fakeservicemanager/Android.bp
@@ -0,0 +1,25 @@
+cc_defaults {
+ name: "fakeservicemanager_defaults",
+ srcs: [
+ "ServiceManager.cpp",
+ ],
+
+ shared_libs: [
+ "libbinder",
+ "libutils",
+ ],
+}
+
+cc_library {
+ name: "libfakeservicemanager",
+ defaults: ["fakeservicemanager_defaults"],
+}
+
+cc_test_host {
+ name: "fakeservicemanager_test",
+ defaults: ["fakeservicemanager_defaults"],
+ srcs: [
+ "test_sm.cpp",
+ ],
+ static_libs: ["libgmock"],
+}
diff --git a/libs/fakeservicemanager/ServiceManager.cpp b/libs/fakeservicemanager/ServiceManager.cpp
new file mode 100644
index 0000000..6964324
--- /dev/null
+++ b/libs/fakeservicemanager/ServiceManager.cpp
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2020 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 "ServiceManager.h"
+
+namespace android {
+
+ServiceManager::ServiceManager() {}
+
+sp<IBinder> ServiceManager::getService( const String16& name) const {
+ // Servicemanager is single-threaded and cannot block. This method exists for legacy reasons.
+ return checkService(name);
+}
+
+sp<IBinder> ServiceManager::checkService( const String16& name) const {
+ auto it = mNameToService.find(name);
+ if (it == mNameToService.end()) {
+ return nullptr;
+ }
+ return it->second;
+}
+
+status_t ServiceManager::addService(const String16& name, const sp<IBinder>& service,
+ bool /*allowIsolated*/,
+ int /*dumpsysFlags*/) {
+ mNameToService[name] = service;
+ return NO_ERROR;
+}
+
+Vector<String16> ServiceManager::listServices(int /*dumpsysFlags*/) {
+ Vector<String16> services;
+ for (auto const& [name, service] : mNameToService) {
+ (void) service;
+ services.push_back(name);
+ }
+ return services;
+}
+
+IBinder* ServiceManager::onAsBinder() {
+ return nullptr;
+}
+
+sp<IBinder> ServiceManager::waitForService(const String16& name) {
+ return checkService(name);
+}
+
+bool ServiceManager::isDeclared(const String16& name) {
+ return mNameToService.find(name) != mNameToService.end();
+}
+
+} // namespace android
diff --git a/libs/fakeservicemanager/ServiceManager.h b/libs/fakeservicemanager/ServiceManager.h
new file mode 100644
index 0000000..62311d4
--- /dev/null
+++ b/libs/fakeservicemanager/ServiceManager.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#pragma once
+
+#include <binder/IServiceManager.h>
+
+#include <map>
+
+namespace android {
+
+/**
+ * A local host simple implementation of IServiceManager, that does not
+ * communicate over binder.
+*/
+class ServiceManager : public IServiceManager {
+public:
+ ServiceManager();
+
+ /**
+ * Equivalent of checkService.
+ */
+ sp<IBinder> getService( const String16& name) const override;
+
+ /**
+ * Retrieve an existing service, non-blocking.
+ */
+ sp<IBinder> checkService( const String16& name) const override;
+
+ /**
+ * Register a service.
+ */
+ status_t addService(const String16& name, const sp<IBinder>& service,
+ bool allowIsolated = false,
+ int dumpsysFlags = DUMP_FLAG_PRIORITY_DEFAULT) override;
+
+ /**
+ * Return list of all existing services.
+ */
+ Vector<String16> listServices(int dumpsysFlags = 0) override;
+
+ IBinder* onAsBinder() override;
+
+ /**
+ * Effectively no-oped in this implementation - equivalent to checkService.
+ */
+ sp<IBinder> waitForService(const String16& name) override;
+
+ /**
+ * Check if a service is declared (e.g. VINTF manifest).
+ *
+ * If this returns true, waitForService should always be able to return the
+ * service.
+ */
+ bool isDeclared(const String16& name) override;
+
+private:
+ std::map<String16, sp<IBinder>> mNameToService;
+};
+
+} // namespace android
diff --git a/libs/fakeservicemanager/test_sm.cpp b/libs/fakeservicemanager/test_sm.cpp
new file mode 100644
index 0000000..71e5abe
--- /dev/null
+++ b/libs/fakeservicemanager/test_sm.cpp
@@ -0,0 +1,126 @@
+/*
+ * 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.
+ */
+
+#include <gtest/gtest.h>
+#include <gmock/gmock.h>
+
+#include <binder/Binder.h>
+#include <binder/ProcessState.h>
+#include <binder/IServiceManager.h>
+
+#include "ServiceManager.h"
+
+using android::sp;
+using android::BBinder;
+using android::IBinder;
+using android::OK;
+using android::status_t;
+using android::ServiceManager;
+using android::String16;
+using android::IServiceManager;
+using testing::ElementsAre;
+
+static sp<IBinder> getBinder() {
+ class LinkableBinder : public BBinder {
+ status_t linkToDeath(const sp<DeathRecipient>&, void*, uint32_t) override {
+ // let SM linkToDeath
+ return OK;
+ }
+ };
+
+ return new LinkableBinder;
+}
+
+TEST(AddService, HappyHappy) {
+ auto sm = new ServiceManager();
+ EXPECT_EQ(sm->addService(String16("foo"), getBinder(), false /*allowIsolated*/,
+ IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT), OK);
+}
+
+TEST(AddService, HappyOverExistingService) {
+ auto sm = new ServiceManager();
+ EXPECT_EQ(sm->addService(String16("foo"), getBinder(), false /*allowIsolated*/,
+ IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT), OK);
+ EXPECT_EQ(sm->addService(String16("foo"), getBinder(), false /*allowIsolated*/,
+ IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT), OK);
+}
+
+TEST(GetService, HappyHappy) {
+ auto sm = new ServiceManager();
+ sp<IBinder> service = getBinder();
+
+ EXPECT_EQ(sm->addService(String16("foo"), service, false /*allowIsolated*/,
+ IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT), OK);
+
+ EXPECT_EQ(sm->getService(String16("foo")), service);
+}
+
+TEST(GetService, NonExistant) {
+ auto sm = new ServiceManager();
+
+ EXPECT_EQ(sm->getService(String16("foo")), nullptr);
+}
+
+TEST(ListServices, AllServices) {
+ auto sm = new ServiceManager();
+
+ EXPECT_EQ(sm->addService(String16("sd"), getBinder(), false /*allowIsolated*/,
+ IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT), OK);
+ EXPECT_EQ(sm->addService(String16("sc"), getBinder(), false /*allowIsolated*/,
+ IServiceManager::DUMP_FLAG_PRIORITY_NORMAL), OK);
+ EXPECT_EQ(sm->addService(String16("sb"), getBinder(), false /*allowIsolated*/,
+ IServiceManager::DUMP_FLAG_PRIORITY_HIGH), OK);
+ EXPECT_EQ(sm->addService(String16("sa"), getBinder(), false /*allowIsolated*/,
+ IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL), OK);
+
+ android::Vector<String16> out = sm->listServices(IServiceManager::DUMP_FLAG_PRIORITY_ALL);
+
+ // all there and in the right order
+ EXPECT_THAT(out, ElementsAre(String16("sa"), String16("sb"), String16("sc"),
+ String16("sd")));
+}
+
+TEST(WaitForService, NonExistant) {
+ auto sm = new ServiceManager();
+
+ EXPECT_EQ(sm->waitForService(String16("foo")), nullptr);
+}
+
+TEST(WaitForService, HappyHappy) {
+ auto sm = new ServiceManager();
+ sp<IBinder> service = getBinder();
+
+ EXPECT_EQ(sm->addService(String16("foo"), service, false /*allowIsolated*/,
+ IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT), OK);
+
+ EXPECT_EQ(sm->waitForService(String16("foo")), service);
+}
+
+TEST(IsDeclared, NonExistant) {
+ auto sm = new ServiceManager();
+
+ EXPECT_FALSE(sm->isDeclared(String16("foo")));
+}
+
+TEST(IsDeclared, HappyHappy) {
+ auto sm = new ServiceManager();
+ sp<IBinder> service = getBinder();
+
+ EXPECT_EQ(sm->addService(String16("foo"), service, false /*allowIsolated*/,
+ IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT), OK);
+
+ EXPECT_TRUE(sm->isDeclared(String16("foo")));
+}