Steven Moreland | fe66b73 | 2019-02-01 14:29:45 -0800 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2016 The Android Open Source Project |
| 3 | * |
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | * you may not use this file except in compliance with the License. |
| 6 | * You may obtain a copy of the License at |
| 7 | * |
| 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | * |
| 10 | * Unless required by applicable law or agreed to in writing, software |
| 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | * See the License for the specific language governing permissions and |
| 14 | * limitations under the License. |
| 15 | */ |
| 16 | |
Steven Moreland | 2173d3c | 2016-11-09 15:00:58 -0800 | [diff] [blame] | 17 | #define LOG_TAG "hwservicemanager" |
| 18 | #include "HidlService.h" |
| 19 | |
| 20 | #include <android-base/logging.h> |
Steven Moreland | 6f4fbe1 | 2017-07-21 18:07:42 -0700 | [diff] [blame] | 21 | #include <hidl/HidlTransportSupport.h> |
Steven Moreland | d853620 | 2018-09-26 10:56:19 -0700 | [diff] [blame] | 22 | #include <hwbinder/BpHwBinder.h> |
Steven Moreland | 2173d3c | 2016-11-09 15:00:58 -0800 | [diff] [blame] | 23 | #include <sstream> |
| 24 | |
Steven Moreland | d853620 | 2018-09-26 10:56:19 -0700 | [diff] [blame] | 25 | using ::android::hardware::interfacesEqual; |
| 26 | |
Steven Moreland | 2173d3c | 2016-11-09 15:00:58 -0800 | [diff] [blame] | 27 | namespace android { |
| 28 | namespace hidl { |
| 29 | namespace manager { |
Steven Moreland | 2173d3c | 2016-11-09 15:00:58 -0800 | [diff] [blame] | 30 | namespace implementation { |
| 31 | |
Peter Kalauskas | 3b27ec5 | 2019-01-17 14:47:24 -0800 | [diff] [blame] | 32 | static constexpr int kNoClientRepeatLimit = 2; |
| 33 | |
Steven Moreland | 2173d3c | 2016-11-09 15:00:58 -0800 | [diff] [blame] | 34 | HidlService::HidlService( |
Steven Moreland | d544cf6 | 2017-01-04 15:24:32 -0800 | [diff] [blame] | 35 | const std::string &interfaceName, |
| 36 | const std::string &instanceName, |
Steven Moreland | cdf9472 | 2017-03-21 12:16:31 -0700 | [diff] [blame] | 37 | const sp<IBase> &service, |
| 38 | pid_t pid) |
Steven Moreland | d544cf6 | 2017-01-04 15:24:32 -0800 | [diff] [blame] | 39 | : mInterfaceName(interfaceName), |
| 40 | mInstanceName(instanceName), |
Steven Moreland | cdf9472 | 2017-03-21 12:16:31 -0700 | [diff] [blame] | 41 | mService(service), |
| 42 | mPid(pid) |
Steven Moreland | 2173d3c | 2016-11-09 15:00:58 -0800 | [diff] [blame] | 43 | {} |
| 44 | |
Yifan Hong | b3a90f0 | 2016-11-23 12:58:04 -0800 | [diff] [blame] | 45 | sp<IBase> HidlService::getService() const { |
Steven Moreland | 2173d3c | 2016-11-09 15:00:58 -0800 | [diff] [blame] | 46 | return mService; |
| 47 | } |
Steven Moreland | cdf9472 | 2017-03-21 12:16:31 -0700 | [diff] [blame] | 48 | void HidlService::setService(sp<IBase> service, pid_t pid) { |
Steven Moreland | 2173d3c | 2016-11-09 15:00:58 -0800 | [diff] [blame] | 49 | mService = service; |
Steven Moreland | cdf9472 | 2017-03-21 12:16:31 -0700 | [diff] [blame] | 50 | mPid = pid; |
Steven Moreland | 2173d3c | 2016-11-09 15:00:58 -0800 | [diff] [blame] | 51 | |
Steven Moreland | d853620 | 2018-09-26 10:56:19 -0700 | [diff] [blame] | 52 | mClientCallbacks.clear(); |
Steven Moreland | 573e532 | 2019-01-24 19:00:04 -0800 | [diff] [blame] | 53 | mHasClients = false; |
| 54 | mGuaranteeClient = false; |
Steven Moreland | 9cd9e88 | 2019-02-01 18:55:42 -0800 | [diff] [blame] | 55 | mNoClientsCounter = 0; |
Steven Moreland | d853620 | 2018-09-26 10:56:19 -0700 | [diff] [blame] | 56 | |
Steven Moreland | 2173d3c | 2016-11-09 15:00:58 -0800 | [diff] [blame] | 57 | sendRegistrationNotifications(); |
| 58 | } |
Steven Moreland | cdf9472 | 2017-03-21 12:16:31 -0700 | [diff] [blame] | 59 | |
Steven Moreland | 7185a89 | 2019-01-09 18:00:05 -0800 | [diff] [blame] | 60 | pid_t HidlService::getDebugPid() const { |
Steven Moreland | cdf9472 | 2017-03-21 12:16:31 -0700 | [diff] [blame] | 61 | return mPid; |
| 62 | } |
Steven Moreland | d544cf6 | 2017-01-04 15:24:32 -0800 | [diff] [blame] | 63 | const std::string &HidlService::getInterfaceName() const { |
| 64 | return mInterfaceName; |
Steven Moreland | 2173d3c | 2016-11-09 15:00:58 -0800 | [diff] [blame] | 65 | } |
Steven Moreland | d544cf6 | 2017-01-04 15:24:32 -0800 | [diff] [blame] | 66 | const std::string &HidlService::getInstanceName() const { |
Steven Moreland | 2173d3c | 2016-11-09 15:00:58 -0800 | [diff] [blame] | 67 | return mInstanceName; |
| 68 | } |
Steven Moreland | 2173d3c | 2016-11-09 15:00:58 -0800 | [diff] [blame] | 69 | |
| 70 | void HidlService::addListener(const sp<IServiceNotification> &listener) { |
Steven Moreland | 2173d3c | 2016-11-09 15:00:58 -0800 | [diff] [blame] | 71 | if (mService != nullptr) { |
Steven Moreland | 30acc22 | 2017-01-26 11:44:38 -0800 | [diff] [blame] | 72 | auto ret = listener->onRegistration( |
| 73 | mInterfaceName, mInstanceName, true /* preexisting */); |
Martijn Coenen | 7fafc14 | 2017-03-06 16:17:51 +0100 | [diff] [blame] | 74 | if (!ret.isOk()) { |
| 75 | LOG(ERROR) << "Not adding listener for " << mInterfaceName << "/" |
| 76 | << mInstanceName << ": transport error when sending " |
| 77 | << "notification for already registered instance."; |
| 78 | return; |
| 79 | } |
Steven Moreland | 2173d3c | 2016-11-09 15:00:58 -0800 | [diff] [blame] | 80 | } |
Martijn Coenen | 7fafc14 | 2017-03-06 16:17:51 +0100 | [diff] [blame] | 81 | mListeners.push_back(listener); |
| 82 | } |
| 83 | |
| 84 | bool HidlService::removeListener(const wp<IBase>& listener) { |
| 85 | bool found = false; |
| 86 | |
| 87 | for (auto it = mListeners.begin(); it != mListeners.end();) { |
Steven Moreland | 6f4fbe1 | 2017-07-21 18:07:42 -0700 | [diff] [blame] | 88 | if (interfacesEqual(*it, listener.promote())) { |
Martijn Coenen | 7fafc14 | 2017-03-06 16:17:51 +0100 | [diff] [blame] | 89 | it = mListeners.erase(it); |
| 90 | found = true; |
| 91 | } else { |
| 92 | ++it; |
| 93 | } |
| 94 | } |
| 95 | |
| 96 | return found; |
Steven Moreland | 2173d3c | 2016-11-09 15:00:58 -0800 | [diff] [blame] | 97 | } |
| 98 | |
Yifan Hong | ee531a8 | 2017-02-03 15:10:18 -0800 | [diff] [blame] | 99 | void HidlService::registerPassthroughClient(pid_t pid) { |
| 100 | mPassthroughClients.insert(pid); |
| 101 | } |
| 102 | |
| 103 | const std::set<pid_t> &HidlService::getPassthroughClients() const { |
| 104 | return mPassthroughClients; |
| 105 | } |
| 106 | |
Steven Moreland | 105c58b | 2020-04-06 16:18:50 -0700 | [diff] [blame] | 107 | void HidlService::addClientCallback(const sp<IClientCallback>& callback, size_t knownClientCount) { |
Steven Moreland | e7cf142 | 2019-02-01 20:17:25 -0800 | [diff] [blame] | 108 | if (mHasClients) { |
| 109 | // we have this kernel feature, so make sure we're in an updated state |
Steven Moreland | 105c58b | 2020-04-06 16:18:50 -0700 | [diff] [blame] | 110 | forceHandleClientCallbacks(false /*onInterval*/, knownClientCount); |
Steven Moreland | e7cf142 | 2019-02-01 20:17:25 -0800 | [diff] [blame] | 111 | } |
Steven Moreland | 2fa0f55 | 2019-02-01 19:27:33 -0800 | [diff] [blame] | 112 | |
| 113 | if (mHasClients) { |
Steven Moreland | e7cf142 | 2019-02-01 20:17:25 -0800 | [diff] [blame] | 114 | // make sure this callback is in the same state as all of the rest |
Steven Moreland | 2fa0f55 | 2019-02-01 19:27:33 -0800 | [diff] [blame] | 115 | sendClientCallbackNotification(callback, true /*hasClients*/); |
| 116 | } |
| 117 | |
Steven Moreland | d853620 | 2018-09-26 10:56:19 -0700 | [diff] [blame] | 118 | mClientCallbacks.push_back(callback); |
| 119 | } |
| 120 | |
| 121 | bool HidlService::removeClientCallback(const sp<IClientCallback>& callback) { |
| 122 | bool found = false; |
| 123 | |
| 124 | for (auto it = mClientCallbacks.begin(); it != mClientCallbacks.end();) { |
| 125 | if (interfacesEqual(*it, callback)) { |
| 126 | it = mClientCallbacks.erase(it); |
| 127 | found = true; |
| 128 | } else { |
| 129 | ++it; |
| 130 | } |
| 131 | } |
| 132 | |
| 133 | return found; |
| 134 | } |
| 135 | |
Steven Moreland | 105c58b | 2020-04-06 16:18:50 -0700 | [diff] [blame] | 136 | bool HidlService::handleClientCallbacks(bool isCalledOnInterval, size_t knownClientCount) { |
Steven Moreland | e7cf142 | 2019-02-01 20:17:25 -0800 | [diff] [blame] | 137 | if (!mClientCallbacks.empty()) { |
Steven Moreland | 105c58b | 2020-04-06 16:18:50 -0700 | [diff] [blame] | 138 | return forceHandleClientCallbacks(isCalledOnInterval, knownClientCount); |
Steven Moreland | e7cf142 | 2019-02-01 20:17:25 -0800 | [diff] [blame] | 139 | } |
| 140 | |
Steven Moreland | 105c58b | 2020-04-06 16:18:50 -0700 | [diff] [blame] | 141 | return false; |
Steven Moreland | e7cf142 | 2019-02-01 20:17:25 -0800 | [diff] [blame] | 142 | } |
| 143 | |
Steven Moreland | 105c58b | 2020-04-06 16:18:50 -0700 | [diff] [blame] | 144 | bool HidlService::forceHandleClientCallbacks(bool isCalledOnInterval, size_t knownClientCount) { |
Steven Moreland | 501bc8e | 2019-02-01 16:21:46 -0800 | [diff] [blame] | 145 | ssize_t count = getNodeStrongRefCount(); |
Steven Moreland | d853620 | 2018-09-26 10:56:19 -0700 | [diff] [blame] | 146 | |
| 147 | // binder driver doesn't support this feature |
Steven Moreland | 105c58b | 2020-04-06 16:18:50 -0700 | [diff] [blame] | 148 | if (count < 0) return false; |
Steven Moreland | d853620 | 2018-09-26 10:56:19 -0700 | [diff] [blame] | 149 | |
Steven Moreland | 105c58b | 2020-04-06 16:18:50 -0700 | [diff] [blame] | 150 | bool hasClients = (size_t)count > knownClientCount; |
Steven Moreland | d853620 | 2018-09-26 10:56:19 -0700 | [diff] [blame] | 151 | |
Steven Moreland | 9cd9e88 | 2019-02-01 18:55:42 -0800 | [diff] [blame] | 152 | if (mGuaranteeClient) { |
| 153 | // we have no record of this client |
| 154 | if (!mHasClients && !hasClients) { |
| 155 | sendClientCallbackNotifications(true); |
| 156 | } |
| 157 | |
| 158 | // guarantee is temporary |
| 159 | mGuaranteeClient = false; |
| 160 | } |
| 161 | |
| 162 | if (hasClients && !mHasClients) { |
| 163 | // client was retrieved in some other way |
| 164 | sendClientCallbackNotifications(true); |
Steven Moreland | 98db829 | 2018-12-07 13:08:25 -0800 | [diff] [blame] | 165 | } |
Steven Moreland | d853620 | 2018-09-26 10:56:19 -0700 | [diff] [blame] | 166 | |
Peter Kalauskas | 3b27ec5 | 2019-01-17 14:47:24 -0800 | [diff] [blame] | 167 | // there are no more clients, but the callback has not been called yet |
Steven Moreland | 9cd9e88 | 2019-02-01 18:55:42 -0800 | [diff] [blame] | 168 | if (!hasClients && mHasClients && isCalledOnInterval) { |
Peter Kalauskas | 3b27ec5 | 2019-01-17 14:47:24 -0800 | [diff] [blame] | 169 | mNoClientsCounter++; |
Steven Moreland | 9cd9e88 | 2019-02-01 18:55:42 -0800 | [diff] [blame] | 170 | |
| 171 | if (mNoClientsCounter >= kNoClientRepeatLimit) { |
| 172 | sendClientCallbackNotifications(false); |
| 173 | } |
Steven Moreland | d853620 | 2018-09-26 10:56:19 -0700 | [diff] [blame] | 174 | } |
| 175 | |
Steven Moreland | 105c58b | 2020-04-06 16:18:50 -0700 | [diff] [blame] | 176 | return mHasClients; |
Steven Moreland | 98db829 | 2018-12-07 13:08:25 -0800 | [diff] [blame] | 177 | } |
| 178 | |
| 179 | void HidlService::guaranteeClient() { |
| 180 | mGuaranteeClient = true; |
Steven Moreland | d853620 | 2018-09-26 10:56:19 -0700 | [diff] [blame] | 181 | } |
| 182 | |
Steven Moreland | 2173d3c | 2016-11-09 15:00:58 -0800 | [diff] [blame] | 183 | std::string HidlService::string() const { |
| 184 | std::stringstream ss; |
Steven Moreland | d544cf6 | 2017-01-04 15:24:32 -0800 | [diff] [blame] | 185 | ss << mInterfaceName << "/" << mInstanceName; |
Steven Moreland | 2173d3c | 2016-11-09 15:00:58 -0800 | [diff] [blame] | 186 | return ss.str(); |
| 187 | } |
| 188 | |
Steven Moreland | 501bc8e | 2019-02-01 16:21:46 -0800 | [diff] [blame] | 189 | ssize_t HidlService::getNodeStrongRefCount() { |
| 190 | using ::android::hardware::toBinder; |
| 191 | using ::android::hardware::BpHwBinder; |
| 192 | using ::android::hardware::IBinder; |
| 193 | |
| 194 | if (mService == nullptr) return -1; |
| 195 | |
| 196 | // this justifies the bp cast below, no in-process HALs need this |
| 197 | if (!mService->isRemote()) return -1; |
| 198 | |
| 199 | sp<IBinder> binder = toBinder(mService); |
| 200 | if (binder == nullptr) return -1; |
| 201 | |
| 202 | sp<BpHwBinder> bpBinder = static_cast<BpHwBinder*>(binder.get()); |
| 203 | return bpBinder->getNodeStrongRefCount(); |
| 204 | } |
| 205 | |
Martijn Coenen | 72103a0 | 2017-01-18 16:06:34 +0100 | [diff] [blame] | 206 | void HidlService::sendRegistrationNotifications() { |
Steven Moreland | 2173d3c | 2016-11-09 15:00:58 -0800 | [diff] [blame] | 207 | if (mListeners.size() == 0 || mService == nullptr) { |
| 208 | return; |
| 209 | } |
| 210 | |
Steven Moreland | d544cf6 | 2017-01-04 15:24:32 -0800 | [diff] [blame] | 211 | hidl_string iface = mInterfaceName; |
Steven Moreland | 2173d3c | 2016-11-09 15:00:58 -0800 | [diff] [blame] | 212 | hidl_string name = mInstanceName; |
| 213 | |
Martijn Coenen | 72103a0 | 2017-01-18 16:06:34 +0100 | [diff] [blame] | 214 | for (auto it = mListeners.begin(); it != mListeners.end();) { |
| 215 | auto ret = (*it)->onRegistration(iface, name, false /* preexisting */); |
| 216 | if (ret.isOk()) { |
| 217 | ++it; |
| 218 | } else { |
Martijn Coenen | 7fafc14 | 2017-03-06 16:17:51 +0100 | [diff] [blame] | 219 | LOG(ERROR) << "Dropping registration callback for " << iface << "/" << name |
| 220 | << ": transport error."; |
Martijn Coenen | 72103a0 | 2017-01-18 16:06:34 +0100 | [diff] [blame] | 221 | it = mListeners.erase(it); |
| 222 | } |
Steven Moreland | 2173d3c | 2016-11-09 15:00:58 -0800 | [diff] [blame] | 223 | } |
| 224 | } |
| 225 | |
Steven Moreland | 98db829 | 2018-12-07 13:08:25 -0800 | [diff] [blame] | 226 | void HidlService::sendClientCallbackNotifications(bool hasClients) { |
Steven Moreland | 9cd9e88 | 2019-02-01 18:55:42 -0800 | [diff] [blame] | 227 | CHECK(hasClients != mHasClients) << "Record shows: " << mHasClients |
| 228 | << " so we can't tell clients again that we have client: " << hasClients; |
| 229 | |
Steven Moreland | 98db829 | 2018-12-07 13:08:25 -0800 | [diff] [blame] | 230 | LOG(INFO) << "Notifying " << string() << " they have clients: " << hasClients; |
| 231 | |
| 232 | for (const auto& cb : mClientCallbacks) { |
Steven Moreland | 2fa0f55 | 2019-02-01 19:27:33 -0800 | [diff] [blame] | 233 | sendClientCallbackNotification(cb, hasClients); |
Steven Moreland | 98db829 | 2018-12-07 13:08:25 -0800 | [diff] [blame] | 234 | } |
Peter Kalauskas | 3b27ec5 | 2019-01-17 14:47:24 -0800 | [diff] [blame] | 235 | |
| 236 | mNoClientsCounter = 0; |
| 237 | mHasClients = hasClients; |
Steven Moreland | 98db829 | 2018-12-07 13:08:25 -0800 | [diff] [blame] | 238 | } |
| 239 | |
Steven Moreland | 2fa0f55 | 2019-02-01 19:27:33 -0800 | [diff] [blame] | 240 | void HidlService::sendClientCallbackNotification(const sp<IClientCallback>& callback, bool hasClients) { |
| 241 | Return<void> ret = callback->onClients(getService(), hasClients); |
| 242 | if (!ret.isOk()) { |
| 243 | LOG(WARNING) << "onClients callback failed for " << string() << ": " << ret.description(); |
| 244 | } |
| 245 | } |
| 246 | |
Steven Moreland | 98db829 | 2018-12-07 13:08:25 -0800 | [diff] [blame] | 247 | |
Steven Moreland | 2173d3c | 2016-11-09 15:00:58 -0800 | [diff] [blame] | 248 | } // namespace implementation |
Steven Moreland | 2173d3c | 2016-11-09 15:00:58 -0800 | [diff] [blame] | 249 | } // namespace manager |
| 250 | } // namespace hidl |
Yifan Hong | b3a90f0 | 2016-11-23 12:58:04 -0800 | [diff] [blame] | 251 | } // namespace android |