You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
252 lines
7.1 KiB
252 lines
7.1 KiB
/*
|
|
* Copyright (C) 2016 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 "hwservicemanager"
|
|
#include "HidlService.h"
|
|
|
|
#include <android-base/logging.h>
|
|
#include <hidl/HidlTransportSupport.h>
|
|
#include <hwbinder/BpHwBinder.h>
|
|
#include <sstream>
|
|
|
|
using ::android::hardware::interfacesEqual;
|
|
|
|
namespace android {
|
|
namespace hidl {
|
|
namespace manager {
|
|
namespace implementation {
|
|
|
|
static constexpr int kNoClientRepeatLimit = 2;
|
|
|
|
HidlService::HidlService(
|
|
const std::string &interfaceName,
|
|
const std::string &instanceName,
|
|
const sp<IBase> &service,
|
|
pid_t pid)
|
|
: mInterfaceName(interfaceName),
|
|
mInstanceName(instanceName),
|
|
mService(service),
|
|
mPid(pid)
|
|
{}
|
|
|
|
sp<IBase> HidlService::getService() const {
|
|
return mService;
|
|
}
|
|
void HidlService::setService(sp<IBase> service, pid_t pid) {
|
|
mService = service;
|
|
mPid = pid;
|
|
|
|
mClientCallbacks.clear();
|
|
mHasClients = false;
|
|
mGuaranteeClient = false;
|
|
mNoClientsCounter = 0;
|
|
|
|
sendRegistrationNotifications();
|
|
}
|
|
|
|
pid_t HidlService::getDebugPid() const {
|
|
return mPid;
|
|
}
|
|
const std::string &HidlService::getInterfaceName() const {
|
|
return mInterfaceName;
|
|
}
|
|
const std::string &HidlService::getInstanceName() const {
|
|
return mInstanceName;
|
|
}
|
|
|
|
void HidlService::addListener(const sp<IServiceNotification> &listener) {
|
|
if (mService != nullptr) {
|
|
auto ret = listener->onRegistration(
|
|
mInterfaceName, mInstanceName, true /* preexisting */);
|
|
if (!ret.isOk()) {
|
|
LOG(ERROR) << "Not adding listener for " << mInterfaceName << "/"
|
|
<< mInstanceName << ": transport error when sending "
|
|
<< "notification for already registered instance.";
|
|
return;
|
|
}
|
|
}
|
|
mListeners.push_back(listener);
|
|
}
|
|
|
|
bool HidlService::removeListener(const wp<IBase>& listener) {
|
|
bool found = false;
|
|
|
|
for (auto it = mListeners.begin(); it != mListeners.end();) {
|
|
if (interfacesEqual(*it, listener.promote())) {
|
|
it = mListeners.erase(it);
|
|
found = true;
|
|
} else {
|
|
++it;
|
|
}
|
|
}
|
|
|
|
return found;
|
|
}
|
|
|
|
void HidlService::registerPassthroughClient(pid_t pid) {
|
|
mPassthroughClients.insert(pid);
|
|
}
|
|
|
|
const std::set<pid_t> &HidlService::getPassthroughClients() const {
|
|
return mPassthroughClients;
|
|
}
|
|
|
|
void HidlService::addClientCallback(const sp<IClientCallback>& callback, size_t knownClientCount) {
|
|
if (mHasClients) {
|
|
// we have this kernel feature, so make sure we're in an updated state
|
|
forceHandleClientCallbacks(false /*onInterval*/, knownClientCount);
|
|
}
|
|
|
|
if (mHasClients) {
|
|
// make sure this callback is in the same state as all of the rest
|
|
sendClientCallbackNotification(callback, true /*hasClients*/);
|
|
}
|
|
|
|
mClientCallbacks.push_back(callback);
|
|
}
|
|
|
|
bool HidlService::removeClientCallback(const sp<IClientCallback>& callback) {
|
|
bool found = false;
|
|
|
|
for (auto it = mClientCallbacks.begin(); it != mClientCallbacks.end();) {
|
|
if (interfacesEqual(*it, callback)) {
|
|
it = mClientCallbacks.erase(it);
|
|
found = true;
|
|
} else {
|
|
++it;
|
|
}
|
|
}
|
|
|
|
return found;
|
|
}
|
|
|
|
bool HidlService::handleClientCallbacks(bool isCalledOnInterval, size_t knownClientCount) {
|
|
if (!mClientCallbacks.empty()) {
|
|
return forceHandleClientCallbacks(isCalledOnInterval, knownClientCount);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool HidlService::forceHandleClientCallbacks(bool isCalledOnInterval, size_t knownClientCount) {
|
|
ssize_t count = getNodeStrongRefCount();
|
|
|
|
// binder driver doesn't support this feature
|
|
if (count < 0) return false;
|
|
|
|
bool hasClients = (size_t)count > knownClientCount;
|
|
|
|
if (mGuaranteeClient) {
|
|
// we have no record of this client
|
|
if (!mHasClients && !hasClients) {
|
|
sendClientCallbackNotifications(true);
|
|
}
|
|
|
|
// guarantee is temporary
|
|
mGuaranteeClient = false;
|
|
}
|
|
|
|
if (hasClients && !mHasClients) {
|
|
// client was retrieved in some other way
|
|
sendClientCallbackNotifications(true);
|
|
}
|
|
|
|
// there are no more clients, but the callback has not been called yet
|
|
if (!hasClients && mHasClients && isCalledOnInterval) {
|
|
mNoClientsCounter++;
|
|
|
|
if (mNoClientsCounter >= kNoClientRepeatLimit) {
|
|
sendClientCallbackNotifications(false);
|
|
}
|
|
}
|
|
|
|
return mHasClients;
|
|
}
|
|
|
|
void HidlService::guaranteeClient() {
|
|
mGuaranteeClient = true;
|
|
}
|
|
|
|
std::string HidlService::string() const {
|
|
std::stringstream ss;
|
|
ss << mInterfaceName << "/" << mInstanceName;
|
|
return ss.str();
|
|
}
|
|
|
|
ssize_t HidlService::getNodeStrongRefCount() {
|
|
using ::android::hardware::toBinder;
|
|
using ::android::hardware::BpHwBinder;
|
|
using ::android::hardware::IBinder;
|
|
|
|
if (mService == nullptr) return -1;
|
|
|
|
// this justifies the bp cast below, no in-process HALs need this
|
|
if (!mService->isRemote()) return -1;
|
|
|
|
sp<IBinder> binder = toBinder(mService);
|
|
if (binder == nullptr) return -1;
|
|
|
|
sp<BpHwBinder> bpBinder = static_cast<BpHwBinder*>(binder.get());
|
|
return bpBinder->getNodeStrongRefCount();
|
|
}
|
|
|
|
void HidlService::sendRegistrationNotifications() {
|
|
if (mListeners.size() == 0 || mService == nullptr) {
|
|
return;
|
|
}
|
|
|
|
hidl_string iface = mInterfaceName;
|
|
hidl_string name = mInstanceName;
|
|
|
|
for (auto it = mListeners.begin(); it != mListeners.end();) {
|
|
auto ret = (*it)->onRegistration(iface, name, false /* preexisting */);
|
|
if (ret.isOk()) {
|
|
++it;
|
|
} else {
|
|
LOG(ERROR) << "Dropping registration callback for " << iface << "/" << name
|
|
<< ": transport error.";
|
|
it = mListeners.erase(it);
|
|
}
|
|
}
|
|
}
|
|
|
|
void HidlService::sendClientCallbackNotifications(bool hasClients) {
|
|
CHECK(hasClients != mHasClients) << "Record shows: " << mHasClients
|
|
<< " so we can't tell clients again that we have client: " << hasClients;
|
|
|
|
LOG(INFO) << "Notifying " << string() << " they have clients: " << hasClients;
|
|
|
|
for (const auto& cb : mClientCallbacks) {
|
|
sendClientCallbackNotification(cb, hasClients);
|
|
}
|
|
|
|
mNoClientsCounter = 0;
|
|
mHasClients = hasClients;
|
|
}
|
|
|
|
void HidlService::sendClientCallbackNotification(const sp<IClientCallback>& callback, bool hasClients) {
|
|
Return<void> ret = callback->onClients(getService(), hasClients);
|
|
if (!ret.isOk()) {
|
|
LOG(WARNING) << "onClients callback failed for " << string() << ": " << ret.description();
|
|
}
|
|
}
|
|
|
|
|
|
} // namespace implementation
|
|
} // namespace manager
|
|
} // namespace hidl
|
|
} // namespace android
|