blob: 3e54740f2fc812964badfb47274712fd3c03393a [file] [log] [blame]
#define LOG_TAG "hwservicemanager"
#include "ServiceManager.h"
#include <android-base/logging.h>
#include <hidl/HidlSupport.h>
#include <regex>
#include <sstream>
namespace android {
namespace hidl {
namespace manager {
namespace V1_0 {
namespace implementation {
void ServiceManager::serviceDied(uint64_t /*cookie*/, const wp<IBase>& who) {
// TODO(b/32837397)
remove(who);
}
ServiceManager::InstanceMap &ServiceManager::PackageInterfaceMap::getInstanceMap() {
return mInstanceMap;
}
const ServiceManager::InstanceMap &ServiceManager::PackageInterfaceMap::getInstanceMap() const {
return mInstanceMap;
}
const HidlService *ServiceManager::PackageInterfaceMap::lookupSupporting(
const std::string &name,
const hidl_version &version) const {
auto range = mInstanceMap.equal_range(name);
for (auto it = range.first; it != range.second; ++it) {
const std::unique_ptr<HidlService> &service = it->second;
if (service->supportsVersion(version)) {
return service.get();
}
}
return nullptr;
}
HidlService *ServiceManager::PackageInterfaceMap::lookupSupporting(
const std::string &name,
const hidl_version &version) {
return const_cast<HidlService*>(
const_cast<const PackageInterfaceMap*>(this)->lookupSupporting(name, version));
}
HidlService *ServiceManager::PackageInterfaceMap::lookupExact(
const std::string &name,
const hidl_version &version) {
auto range = mInstanceMap.equal_range(name);
for (auto it = range.first; it != range.second; ++it) {
std::unique_ptr<HidlService> &service = it->second;
if (service->getVersion() == version) {
return service.get();
}
}
return nullptr;
}
void ServiceManager::PackageInterfaceMap::insertService(
std::unique_ptr<HidlService> &&service) {
hidl_string iface = service->fqName();
hidl_string instanceName = service->getName();
mInstanceMap.insert({service->getName(), std::move(service)});
}
void ServiceManager::PackageInterfaceMap::sendPackageRegistrationNotification(
const hidl_string &fqName,
const hidl_string &instanceName) const {
for (const auto &listener : mPackageListeners) {
auto ret = listener->onRegistration(fqName, instanceName, false /* preexisting */);
ret.isOk(); // ignore
}
}
void ServiceManager::PackageInterfaceMap::addPackageListener(sp<IServiceNotification> listener) {
mPackageListeners.push_back(listener);
for (const auto &instanceMapping : mInstanceMap) {
const std::unique_ptr<HidlService> &service = instanceMapping.second;
if (service->getService() == nullptr) {
continue;
}
listener->onRegistration(service->fqName(), service->getName(), true /* preexisting */);
}
}
// Methods from ::android::hidl::manager::V1_0::IServiceManager follow.
Return<sp<IBase>> ServiceManager::get(const hidl_string& fqName,
const hidl_string& name) {
std::unique_ptr<HidlService> desired = HidlService::make(fqName, name);
if (desired == nullptr) {
return nullptr;
}
auto ifaceIt = mServiceMap.find(desired->packageInterface());
if (ifaceIt == mServiceMap.end()) {
return nullptr;
}
const PackageInterfaceMap &ifaceMap = ifaceIt->second;
const HidlService *hidlService
= ifaceMap.lookupSupporting(desired->getName(), desired->getVersion());
if (hidlService != nullptr) {
return hidlService->getService();
} else {
return nullptr;
}
}
Return<bool> ServiceManager::add(const hidl_vec<hidl_string>& interfaceChain,
const hidl_string& name,
const sp<IBase>& service) {
if (interfaceChain.size() == 0 || service == nullptr) {
return false;
}
for(size_t i = 0; i < interfaceChain.size(); i++) {
std::string fqName = interfaceChain[i];
// TODO: keep track of what the actual underlying child is
std::unique_ptr<HidlService> adding = HidlService::make(fqName, name, service);
if (adding == nullptr) {
return false;
}
PackageInterfaceMap &ifaceMap = mServiceMap[adding->packageInterface()];
HidlService *hidlService
= ifaceMap.lookupExact(adding->getName(), adding->getVersion());
if (hidlService == nullptr) {
ifaceMap.insertService(std::move(adding));
} else {
if (hidlService->getService() != nullptr) {
auto ret = hidlService->getService()->unlinkToDeath(this);
ret.isOk(); // Ignore result
}
hidlService->setService(adding->getService());
}
ifaceMap.sendPackageRegistrationNotification(fqName, name);
}
auto ret = service->linkToDeath(this, 0 /*cookie*/);
ret.isOk(); // Ignore result
return true;
}
Return<void> ServiceManager::list(list_cb _hidl_cb) {
size_t total = 0;
for (const auto &interfaceMapping : mServiceMap) {
const auto &instanceMap = interfaceMapping.second.getInstanceMap();
total += instanceMap.size();
}
hidl_vec<hidl_string> list;
list.resize(total);
size_t idx = 0;
for (const auto &interfaceMapping : mServiceMap) {
const auto &instanceMap = interfaceMapping.second.getInstanceMap();
for (const auto &instanceMapping : instanceMap) {
const std::unique_ptr<HidlService> &service = instanceMapping.second;
list[idx++] = service->string();
}
}
_hidl_cb(list);
return Void();
}
Return<void> ServiceManager::listByInterface(const hidl_string& fqName,
listByInterface_cb _hidl_cb) {
std::unique_ptr<HidlService> desired = HidlService::make(fqName, "");
if (desired == nullptr) {
_hidl_cb(hidl_vec<hidl_string>());
return Void();
}
auto ifaceIt = mServiceMap.find(desired->packageInterface());
if (ifaceIt == mServiceMap.end()) {
_hidl_cb(hidl_vec<hidl_string>());
return Void();
}
size_t total = 0;
const auto &instanceMap = ifaceIt->second.getInstanceMap();
for (const auto &instanceMapping : instanceMap) {
const std::unique_ptr<HidlService> &service = instanceMapping.second;
if (service->supportsVersion(desired->getVersion())) {
total += 1;
}
}
hidl_vec<hidl_string> list;
list.resize(total);
size_t idx = 0;
for (const auto &serviceMapping : instanceMap) {
const std::unique_ptr<HidlService> &service = serviceMapping.second;
if (service->supportsVersion(desired->getVersion())) {
list[idx++] = service->getName();
}
}
_hidl_cb(list);
return Void();
}
Return<bool> ServiceManager::registerForNotifications(const hidl_string& fqName,
const hidl_string& name,
const sp<IServiceNotification>& callback) {
if (callback == nullptr) {
return false;
}
std::unique_ptr<HidlService> desired = HidlService::make(fqName, name);
if (desired == nullptr) {
return false;
}
// TODO(b/31632518) (link to death/automatically deregister)
PackageInterfaceMap &ifaceMap = mServiceMap[desired->packageInterface()];
if (name.empty()) {
ifaceMap.addPackageListener(callback);
return true;
}
HidlService *service =
ifaceMap.lookupSupporting(desired->getName(), desired->getVersion());
if (service == nullptr) {
desired->addListener(callback);
ifaceMap.insertService(std::move(desired));
} else {
service->addListener(callback);
}
return true;
}
bool ServiceManager::remove(const wp<IBase>& who) {
bool found = false;
for (auto &interfaceMapping : mServiceMap) {
auto &instanceMap = interfaceMapping.second.getInstanceMap();
for (auto it = instanceMap.begin(); it != instanceMap.end(); it++) {
const std::unique_ptr<HidlService> &service = it->second;
if (service->getService() == who) {
service->setService(nullptr);
found = true;
}
}
}
return found;
}
} // namespace implementation
} // namespace V1_0
} // namespace manager
} // namespace hidl
} // namespace android