diff options
author | Pierre Langlois <pierre.langlois@arm.com> | 2015-02-12 14:48:59 +0000 |
---|---|---|
committer | Pierre Langlois <pierre.langlois@arm.com> | 2016-03-04 17:53:25 +0000 |
commit | 25d2e4fc2e54160c320f10ee3c04c36cebb2d21a (patch) | |
tree | ab780d1de2bfa9a7622a8444ae98643fe79ff0ed | |
parent | 1fdea7e32d0d8fdbc1c4cb60279531b7cacc141b (diff) | |
download | kdbinder-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.h | 69 | ||||
-rw-r--r-- | include/kdbinder/binder/ProcessState.h | 26 | ||||
-rw-r--r-- | include/kdbinder/private/binder/Static.h | 4 | ||||
-rw-r--r-- | libs/kdbinder/Android.mk | 1 | ||||
-rw-r--r-- | libs/kdbinder/binder/IServiceManager.cpp | 125 | ||||
-rw-r--r-- | libs/kdbinder/binder/ProcessState.cpp | 24 | ||||
-rw-r--r-- | libs/kdbinder/binder/Static.cpp | 3 |
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 |