aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPierre Langlois <pierre.langlois@arm.com>2015-02-12 14:48:59 +0000
committerPierre Langlois <pierre.langlois@arm.com>2016-03-04 17:53:25 +0000
commit25d2e4fc2e54160c320f10ee3c04c36cebb2d21a (patch)
treeab780d1de2bfa9a7622a8444ae98643fe79ff0ed
parent1fdea7e32d0d8fdbc1c4cb60279531b7cacc141b (diff)
downloadkdbinder-25d2e4fc2e54160c320f10ee3c04c36cebb2d21a.tar.gz
libkdbinder: implement the IServiceManager API
This commit implements the following API. The implementation differs a lot from Binder due to the fact that KDBUS handles named connections. Therefore we do not need another process to keep track of services. * IServiceManager API: - sp<IServiceManager> defaultServiceManager() Return the default service manager binder object satisfying the IServiceManager interface. Binder implements this by returning a remote Binder object corresponding to the service manager. We do not have a service manager so we can simply return a local Binder object instead. Note that this object is only here so we can provide the same interface as libbinder, it is not actually used for anything. - sp<IBinder> BpServiceManager::getService(const String16& name) const Call checkService 5 times every seconds untill it suceeds. - sp<IBinder> BpServiceManager::checkService(const String16& name) const Probe the bus for the given name and return a remote Binder object. All we need to do is find the connection ID of the given name and make if the handle of BpBinder. - Vector<String16> BpServiceManager::listServices() Return the list services, which is nothing more that the registered names on the bus. - status_t BpServiceManager::addService(const String16& name, const sp<IBinder>& service, bool allowIsolated) Add the given Binder object to the current process as a service. libbinder implements this by sending the Binder object to the service manager. Since we do not have a service manager, we simply register it with the current process by calling: ~~~ ProcessState::self()->registerService(service, name); ~~~ * Registering a new service This commit adds a table to each process' ProcessState object. This table contains entries with a local Binder object and its associated kdbus::Connection. The connection needs to be given a well-known name so it can be discovered by other processes calling getService. Here is how registerService is implemented: ~~~ // Create a new connection to the bus. auto connection = kdbus::Connection::hello( "0-services", String8(name).string()); // Give it a name. connection->acquire_name("service." + std::string(String8(name).string())); // Add it to the process' table. { // add binder to table. AutoMutex _l(mServiceLock); mServiceTable.emplace_back(std::move(connection_for_binder), binder); } ~~~ Change-Id: I668077683784c2759f82cfa603892aecf46e29d5
-rw-r--r--include/kdbinder/binder/IServiceManager.h69
-rw-r--r--include/kdbinder/binder/ProcessState.h26
-rw-r--r--include/kdbinder/private/binder/Static.h4
-rw-r--r--libs/kdbinder/Android.mk1
-rw-r--r--libs/kdbinder/binder/IServiceManager.cpp125
-rw-r--r--libs/kdbinder/binder/ProcessState.cpp24
-rw-r--r--libs/kdbinder/binder/Static.cpp3
7 files changed, 252 insertions, 0 deletions
diff --git a/include/kdbinder/binder/IServiceManager.h b/include/kdbinder/binder/IServiceManager.h
new file mode 100644
index 0000000..3114884
--- /dev/null
+++ b/include/kdbinder/binder/IServiceManager.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+
+#ifndef INCLUDE_KDBINDER_BINDER_ISERVICEMANAGER_H_
+#define INCLUDE_KDBINDER_BINDER_ISERVICEMANAGER_H_
+
+#include <binder/IInterface.h>
+#include <binder/IPermissionController.h>
+#include <utils/Vector.h>
+#include <utils/String16.h>
+
+namespace android {
+
+class IServiceManager : public IInterface {
+ public:
+ DECLARE_META_INTERFACE(ServiceManager);
+
+ /**
+ * Retrieve an existing service, blocking for a few seconds
+ * if it doesn't yet exist.
+ */
+ virtual sp<IBinder> getService(const String16& name) const = 0;
+
+ /**
+ * Retrieve an existing service, non-blocking.
+ */
+ virtual sp<IBinder> checkService(const String16& name) const = 0;
+
+ /**
+ * Register a service.
+ */
+ virtual status_t addService(const String16& name,
+ const sp<IBinder>& service,
+ bool allowIsolated = false) = 0;
+
+ /**
+ * Return list of all existing services.
+ */
+ virtual Vector<String16> listServices() = 0;
+};
+
+sp<IServiceManager> defaultServiceManager();
+
+template<typename INTERFACE>
+status_t getService(const String16& name, sp<INTERFACE>* outService) {
+ const sp<IServiceManager> sm = defaultServiceManager();
+ if (sm != NULL) {
+ *outService = interface_cast<INTERFACE>(sm->getService(name));
+ if ((*outService) != NULL) return NO_ERROR;
+ }
+ return NAME_NOT_FOUND;
+}
+
+} // namespace android
+
+#endif // INCLUDE_KDBINDER_BINDER_ISERVICEMANAGER_H_
diff --git a/include/kdbinder/binder/ProcessState.h b/include/kdbinder/binder/ProcessState.h
index e2fe43d..04ce310 100644
--- a/include/kdbinder/binder/ProcessState.h
+++ b/include/kdbinder/binder/ProcessState.h
@@ -19,8 +19,14 @@
#include <binder/IBinder.h>
+#include <kdbinder/kdbus/KDBinder.h>
+
#include <utils/RefBase.h>
#include <utils/Mutex.h>
+#include <utils/String16.h>
+
+#include <memory>
+#include <vector>
namespace android {
@@ -38,6 +44,8 @@ class ProcessState : public virtual RefBase {
private:
friend class IPCThreadState;
+ // BpServiceManager needs to call registerService.
+ friend class BpServiceManager;
ProcessState();
~ProcessState() = default;
@@ -45,9 +53,27 @@ class ProcessState : public virtual RefBase {
ProcessState(const ProcessState& o);
ProcessState& operator=(const ProcessState& o);
+ // Add the given Binder object in mServiceTable.
+ int32_t registerService(sp<IBinder> binder, String16 name);
+
+ // Each Binder object managed by ProcessState need a kdbus::Connection
+ // associated with them.
+ struct binder_entry {
+ binder_entry(std::unique_ptr<kdbus::Connection> connection,
+ sp<IBinder> binder)
+ : connection(std::move(connection)),
+ binder(binder) {}
+
+ std::shared_ptr<kdbus::Connection> connection;
+ sp<IBinder> binder;
+ };
+
mutable Mutex mLock; // protects everything below.
bool mThreadPoolStarted;
volatile int32_t mThreadPoolSeq;
+
+ mutable Mutex mServiceLock;
+ std::vector<struct binder_entry> mServiceTable;
};
} // namespace android
diff --git a/include/kdbinder/private/binder/Static.h b/include/kdbinder/private/binder/Static.h
index fb5743d..f95994e 100644
--- a/include/kdbinder/private/binder/Static.h
+++ b/include/kdbinder/private/binder/Static.h
@@ -23,12 +23,16 @@
#include <binder/ProcessState.h>
#include <utils/Mutex.h>
+#include <binder/IServiceManager.h>
namespace android {
extern Mutex gProcessMutex;
extern sp<ProcessState> gProcess;
+extern Mutex gDefaultServiceManagerLock;
+extern sp<IServiceManager> gDefaultServiceManager;
+
} // namespace android
#endif // INCLUDE_PRIVATE_KDBINDER_STATIC_H_
diff --git a/libs/kdbinder/Android.mk b/libs/kdbinder/Android.mk
index 545b17d..e96b640 100644
--- a/libs/kdbinder/Android.mk
+++ b/libs/kdbinder/Android.mk
@@ -20,6 +20,7 @@ kdbinder_sources := \
binder/IPCThreadState.cpp \
binder/Static.cpp \
binder/Parcel.cpp \
+ binder/IServiceManager.cpp \
kdbus/bus.cpp \
kdbus/connection.cpp \
kdbus/iterable.cpp \
diff --git a/libs/kdbinder/binder/IServiceManager.cpp b/libs/kdbinder/binder/IServiceManager.cpp
new file mode 100644
index 0000000..bbf1b54
--- /dev/null
+++ b/libs/kdbinder/binder/IServiceManager.cpp
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+#define LOG_TAG "ServiceManager"
+
+#include <binder/IBinder.h>
+#include <binder/Binder.h>
+#include <binder/BpBinder.h>
+#include <binder/IInterface.h>
+#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
+#include <binder/Parcel.h>
+
+#include <kdbinder/kdbus/KDBinder.h>
+
+#include <private/binder/Static.h>
+
+#include <utils/String8.h>
+#include <utils/String16.h>
+#include <string>
+
+namespace android {
+
+class BpServiceManager : public BpInterface<IServiceManager> {
+ public:
+ explicit BpServiceManager(const sp<IBinder>& impl)
+ : BpInterface<IServiceManager>(impl) {
+ }
+
+ sp<IBinder> getService(const String16& name) const override {
+ unsigned n;
+ for (n = 0; n < 5; n++) {
+ sp<IBinder> svc = checkService(name);
+ if (svc != NULL) return svc;
+ ALOGI("Waiting for service %s...\n", String8(name).string());
+ sleep(1);
+ }
+ return NULL;
+ }
+
+ sp<IBinder> checkService(const String16& name) const override {
+ // Service names are prepended with "service." because KDBUS forces
+ // you to have a hierarchy.
+ std::string real_name = "service." + std::string(String8(name).string());
+
+ // Probe the bus with all connections with well-known names.
+ auto connection = kdbus::Connection::hello("0-services", "checkService");
+ auto list = connection->name_list(kdbus::Connection::Names);
+
+ // Find the service in the list of names.
+ auto it = std::find_if(list.cbegin(), list.cend(),
+ [&real_name](const kdbus::NameInfo& n) {
+ return n.name == real_name;
+ });
+
+ if (it == list.cend()) {
+ return NULL;
+ } else {
+ // A remote Binder object contains the connection ID as its
+ // handle.
+ return new BpBinder(it->owner_id);
+ }
+ }
+
+ status_t addService(const String16& name, const sp<IBinder>& service,
+ bool /*allowIsolated*/) override {
+ // Prepend the name with "service." to make sure we have at least
+ // one level of hierarchy. Otherwise KDBUS will reject it.
+ String16 real_name = String16("service.");
+ real_name.append(name);
+
+ // Register the service with the calling process.
+ ProcessState::self()->registerService(service, real_name);
+
+ return NO_ERROR;
+ }
+
+ Vector<String16> listServices() override {
+ auto connection = kdbus::Connection::hello("0-services", "listServices");
+
+ // Probe the bus for the list of well-known names.
+ auto list = connection->name_list(kdbus::Connection::Names);
+
+ Vector<String16> result;
+
+ for (const auto& n : list) {
+ // Service names are all prefixed with "service.".
+ auto pos = n.name.find(".");
+ std::string name = n.name.substr(pos + 1);
+
+ result.push(String16(name.c_str()));
+ }
+
+ return result;
+ }
+};
+
+sp<IServiceManager> defaultServiceManager() {
+ if (gDefaultServiceManager != NULL) return gDefaultServiceManager;
+
+ {
+ AutoMutex _l(gDefaultServiceManagerLock);
+ // The service manager is nothing more than a dummy Binder object
+ // implementing the IServiceManager interface.
+ gDefaultServiceManager = interface_cast<IServiceManager>(new BBinder());
+ }
+
+ return gDefaultServiceManager;
+}
+
+IMPLEMENT_META_INTERFACE(ServiceManager, "android.os.IServiceManager");
+
+} // namespace android
diff --git a/libs/kdbinder/binder/ProcessState.cpp b/libs/kdbinder/binder/ProcessState.cpp
index 225fb01..3097d3e 100644
--- a/libs/kdbinder/binder/ProcessState.cpp
+++ b/libs/kdbinder/binder/ProcessState.cpp
@@ -19,6 +19,9 @@
#include <binder/ProcessState.h>
#include <binder/IPCThreadState.h>
+#include <utils/String8.h>
+#include <string>
+
namespace android {
ProcessState::ProcessState() : mThreadPoolStarted(false) {
@@ -56,4 +59,25 @@ status_t ProcessState::setThreadPoolMaxThreadCount(size_t /*maxThreads*/) {
return NO_ERROR;
}
+int32_t ProcessState::registerService(sp<IBinder> binder, String16 name) {
+ // Create a new connection for the Binder object.
+ auto connection_for_binder = kdbus::Connection::hello(
+ "0-services",
+ String8(name).string());
+
+ // Give it a well-known name. This will allow it to be discovered by
+ // other processes.
+ connection_for_binder->acquire_name(std::string(String8(name).string()));
+
+ int32_t handle = connection_for_binder->id;
+
+ // Add the service to the table.
+ {
+ AutoMutex _l(mServiceLock);
+ mServiceTable.emplace_back(std::move(connection_for_binder), binder);
+ }
+
+ return handle;
+}
+
} // namespace android
diff --git a/libs/kdbinder/binder/Static.cpp b/libs/kdbinder/binder/Static.cpp
index 7c87a69..27e15f4 100644
--- a/libs/kdbinder/binder/Static.cpp
+++ b/libs/kdbinder/binder/Static.cpp
@@ -24,4 +24,7 @@ namespace android {
Mutex gProcessMutex;
sp<ProcessState> gProcess;
+Mutex gDefaultServiceManagerLock;
+sp<IServiceManager> gDefaultServiceManager;
+
} // namespace android