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 
17 #define LOG_TAG "hwservicemanager"
18 #include "HidlService.h"
19 
20 #include <android-base/logging.h>
21 #include <hidl/HidlTransportSupport.h>
22 #include <hwbinder/BpHwBinder.h>
23 #include <sstream>
24 
25 using ::android::hardware::interfacesEqual;
26 
27 namespace android {
28 namespace hidl {
29 namespace manager {
30 namespace implementation {
31 
32 static constexpr int kNoClientRepeatLimit = 2;
33 
34 HidlService::HidlService(
35     const std::string &interfaceName,
36     const std::string &instanceName,
37     const sp<IBase> &service,
38     pid_t pid)
39 : mInterfaceName(interfaceName),
40   mInstanceName(instanceName),
41   mService(service),
42   mPid(pid)
43 {}
44 
45 sp<IBase> HidlService::getService() const {
46     return mService;
47 }
48 void HidlService::setService(sp<IBase> service, pid_t pid) {
49     mService = service;
50     mPid = pid;
51 
52     mClientCallbacks.clear();
53     mHasClients = false;
54     mGuaranteeClient = false;
55     mNoClientsCounter = 0;
56 
57     sendRegistrationNotifications();
58 }
59 
60 pid_t HidlService::getDebugPid() const {
61     return mPid;
62 }
63 const std::string &HidlService::getInterfaceName() const {
64     return mInterfaceName;
65 }
66 const std::string &HidlService::getInstanceName() const {
67     return mInstanceName;
68 }
69 
70 void HidlService::addListener(const sp<IServiceNotification> &listener) {
71     if (mService != nullptr) {
72         auto ret = listener->onRegistration(
73             mInterfaceName, mInstanceName, true /* preexisting */);
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         }
80     }
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();) {
88         if (interfacesEqual(*it, listener.promote())) {
89             it = mListeners.erase(it);
90             found = true;
91         } else {
92             ++it;
93         }
94     }
95 
96     return found;
97 }
98 
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 
107 void HidlService::addClientCallback(const sp<IClientCallback>& callback, size_t knownClientCount) {
108     if (mHasClients) {
109         // we have this kernel feature, so make sure we're in an updated state
110         forceHandleClientCallbacks(false /*onInterval*/, knownClientCount);
111     }
112 
113     if (mHasClients) {
114         // make sure this callback is in the same state as all of the rest
115         sendClientCallbackNotification(callback, true /*hasClients*/);
116     }
117 
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 
136 bool HidlService::handleClientCallbacks(bool isCalledOnInterval, size_t knownClientCount) {
137     if (!mClientCallbacks.empty()) {
138         return forceHandleClientCallbacks(isCalledOnInterval, knownClientCount);
139     }
140 
141     return false;
142 }
143 
144 bool HidlService::forceHandleClientCallbacks(bool isCalledOnInterval, size_t knownClientCount) {
145     ssize_t count = getNodeStrongRefCount();
146 
147     // binder driver doesn't support this feature
148     if (count < 0) return false;
149 
150     bool hasClients = (size_t)count > knownClientCount;
151 
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);
165     }
166 
167     // there are no more clients, but the callback has not been called yet
168     if (!hasClients && mHasClients && isCalledOnInterval) {
169         mNoClientsCounter++;
170 
171         if (mNoClientsCounter >= kNoClientRepeatLimit) {
172             sendClientCallbackNotifications(false);
173         }
174     }
175 
176     return mHasClients;
177 }
178 
179 void HidlService::guaranteeClient() {
180     mGuaranteeClient = true;
181 }
182 
183 std::string HidlService::string() const {
184     std::stringstream ss;
185     ss << mInterfaceName << "/" << mInstanceName;
186     return ss.str();
187 }
188 
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 
206 void HidlService::sendRegistrationNotifications() {
207     if (mListeners.size() == 0 || mService == nullptr) {
208         return;
209     }
210 
211     hidl_string iface = mInterfaceName;
212     hidl_string name = mInstanceName;
213 
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 {
219             LOG(ERROR) << "Dropping registration callback for " << iface << "/" << name
220                        << ": transport error.";
221             it = mListeners.erase(it);
222         }
223     }
224 }
225 
226 void HidlService::sendClientCallbackNotifications(bool hasClients) {
227     CHECK(hasClients != mHasClients) << "Record shows: " << mHasClients
228         << " so we can't tell clients again that we have client: " << hasClients;
229 
230     LOG(INFO) << "Notifying " << string() << " they have clients: " << hasClients;
231 
232     for (const auto& cb : mClientCallbacks) {
233         sendClientCallbackNotification(cb, hasClients);
234     }
235 
236     mNoClientsCounter = 0;
237     mHasClients = hasClients;
238 }
239 
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 
247 
248 }  // namespace implementation
249 }  // namespace manager
250 }  // namespace hidl
251 }  // namespace android
252