blob: 663c6b5744083602e1f8a6f2fff97e2e06dddbe0 [file] [log] [blame]
Steven Moreland5d5ef7f2016-10-20 19:19:55 -07001/*
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 "ServiceManagement"
18
Yifan Hong9a22d1d2017-01-25 14:19:26 -080019#include <condition_variable>
20#include <dlfcn.h>
21#include <dirent.h>
Steven Morelandcd4dbdf2017-04-07 20:31:22 -070022#include <fstream>
23#include <pthread.h>
Yifan Hong9a22d1d2017-01-25 14:19:26 -080024#include <unistd.h>
25
26#include <mutex>
27#include <regex>
Yifan Hongbd0d8f72017-05-24 19:43:51 -070028#include <set>
Yifan Hong9a22d1d2017-01-25 14:19:26 -080029
Martijn Coenen12f04d92016-12-07 17:29:41 +010030#include <hidl/HidlBinderSupport.h>
Steven Moreland5d5ef7f2016-10-20 19:19:55 -070031#include <hidl/ServiceManagement.h>
Steven Moreland5d5ef7f2016-10-20 19:19:55 -070032#include <hidl/Status.h>
33
Steven Moreland337e6b62017-01-18 17:25:13 -080034#include <android-base/logging.h>
Steven Morelandc1cee2c2017-03-24 16:23:11 +000035#include <android-base/properties.h>
Steven Moreland5d5ef7f2016-10-20 19:19:55 -070036#include <hwbinder/IPCThreadState.h>
37#include <hwbinder/Parcel.h>
Steven Moreland5d5ef7f2016-10-20 19:19:55 -070038
39#include <android/hidl/manager/1.0/IServiceManager.h>
Yifan Hong4e925992017-01-09 17:47:17 -080040#include <android/hidl/manager/1.0/BpHwServiceManager.h>
41#include <android/hidl/manager/1.0/BnHwServiceManager.h>
Steven Moreland5d5ef7f2016-10-20 19:19:55 -070042
Yifan Hong9a22d1d2017-01-25 14:19:26 -080043#define RE_COMPONENT "[a-zA-Z_][a-zA-Z_0-9]*"
44#define RE_PATH RE_COMPONENT "(?:[.]" RE_COMPONENT ")*"
45static const std::regex gLibraryFileNamePattern("(" RE_PATH "@[0-9]+[.][0-9]+)-impl(.*?).so");
46
Steven Morelandc1cee2c2017-03-24 16:23:11 +000047using android::base::WaitForProperty;
48
Steven Moreland5d5ef7f2016-10-20 19:19:55 -070049using android::hidl::manager::V1_0::IServiceManager;
Steven Moreland337e6b62017-01-18 17:25:13 -080050using android::hidl::manager::V1_0::IServiceNotification;
Yifan Hong4e925992017-01-09 17:47:17 -080051using android::hidl::manager::V1_0::BpHwServiceManager;
52using android::hidl::manager::V1_0::BnHwServiceManager;
Steven Moreland5d5ef7f2016-10-20 19:19:55 -070053
54namespace android {
55namespace hardware {
56
Yifan Hong953e6b02017-03-16 14:52:40 -070057namespace details {
58extern Mutex gDefaultServiceManagerLock;
59extern sp<android::hidl::manager::V1_0::IServiceManager> gDefaultServiceManager;
60} // namespace details
61
Steven Morelandc1cee2c2017-03-24 16:23:11 +000062static const char* kHwServicemanagerReadyProperty = "hwservicemanager.ready";
63
64void waitForHwServiceManager() {
65 using std::literals::chrono_literals::operator""s;
66
67 while (!WaitForProperty(kHwServicemanagerReadyProperty, "true", 1s)) {
68 LOG(WARNING) << "Waited for hwservicemanager.ready for a second, waiting another...";
69 }
70}
71
Steven Morelandcd4dbdf2017-04-07 20:31:22 -070072bool endsWith(const std::string &in, const std::string &suffix) {
73 return in.size() >= suffix.size() &&
74 in.substr(in.size() - suffix.size()) == suffix;
75}
Steven Moreland5d5ef7f2016-10-20 19:19:55 -070076
Steven Morelandcd4dbdf2017-04-07 20:31:22 -070077bool startsWith(const std::string &in, const std::string &prefix) {
78 return in.size() >= prefix.size() &&
79 in.substr(0, prefix.size()) == prefix;
80}
81
82std::string binaryName() {
83 std::ifstream ifs("/proc/self/cmdline");
84 std::string cmdline;
85 if (!ifs.is_open()) {
86 return "";
87 }
88 ifs >> cmdline;
89
90 size_t idx = cmdline.rfind("/");
91 if (idx != std::string::npos) {
92 cmdline = cmdline.substr(idx + 1);
93 }
94
95 return cmdline;
96}
97
98void tryShortenProcessName(const std::string &packageName) {
99 std::string processName = binaryName();
100
101 if (!startsWith(processName, packageName)) {
102 return;
103 }
104
105 // e.x. android.hardware.module.foo@1.0 -> foo@1.0
106 size_t lastDot = packageName.rfind('.');
107 size_t secondDot = packageName.rfind('.', lastDot - 1);
108
109 if (secondDot == std::string::npos) {
110 return;
111 }
112
113 std::string newName = processName.substr(secondDot + 1,
114 16 /* TASK_COMM_LEN */ - 1);
115 ALOGI("Removing namespace from process name %s to %s.",
116 processName.c_str(), newName.c_str());
117
118 int rc = pthread_setname_np(pthread_self(), newName.c_str());
119 ALOGI_IF(rc != 0, "Removing namespace from process name %s failed.",
120 processName.c_str());
121}
122
123namespace details {
124
125void onRegistration(const std::string &packageName,
126 const std::string& /* interfaceName */,
127 const std::string& /* instanceName */) {
128 tryShortenProcessName(packageName);
129}
130
131} // details
132
133sp<IServiceManager> defaultServiceManager() {
Steven Moreland5d5ef7f2016-10-20 19:19:55 -0700134 {
Yifan Hong953e6b02017-03-16 14:52:40 -0700135 AutoMutex _l(details::gDefaultServiceManagerLock);
136 if (details::gDefaultServiceManager != NULL) {
137 return details::gDefaultServiceManager;
Yifan Hong8fb656b2017-03-16 14:30:40 -0700138 }
Steven Morelandcd4dbdf2017-04-07 20:31:22 -0700139
Yifan Hong8fb656b2017-03-16 14:30:40 -0700140 if (access("/dev/hwbinder", F_OK|R_OK|W_OK) != 0) {
141 // HwBinder not available on this device or not accessible to
142 // this process.
143 return nullptr;
144 }
Steven Morelandc1cee2c2017-03-24 16:23:11 +0000145
146 waitForHwServiceManager();
147
Yifan Hong953e6b02017-03-16 14:52:40 -0700148 while (details::gDefaultServiceManager == NULL) {
149 details::gDefaultServiceManager =
Yifan Hong8fb656b2017-03-16 14:30:40 -0700150 fromBinder<IServiceManager, BpHwServiceManager, BnHwServiceManager>(
151 ProcessState::self()->getContextObject(NULL));
Yifan Hong953e6b02017-03-16 14:52:40 -0700152 if (details::gDefaultServiceManager == NULL) {
Steven Morelandc1cee2c2017-03-24 16:23:11 +0000153 LOG(ERROR) << "Waited for hwservicemanager, but got nullptr.";
Steven Moreland5d5ef7f2016-10-20 19:19:55 -0700154 sleep(1);
Yifan Hong8fb656b2017-03-16 14:30:40 -0700155 }
Steven Moreland5d5ef7f2016-10-20 19:19:55 -0700156 }
157 }
158
Yifan Hong953e6b02017-03-16 14:52:40 -0700159 return details::gDefaultServiceManager;
Steven Moreland5d5ef7f2016-10-20 19:19:55 -0700160}
161
Steven Moreland0091c092017-01-20 23:15:18 +0000162std::vector<std::string> search(const std::string &path,
163 const std::string &prefix,
164 const std::string &suffix) {
165 std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(path.c_str()), closedir);
166 if (!dir) return {};
167
168 std::vector<std::string> results{};
169
170 dirent* dp;
171 while ((dp = readdir(dir.get())) != nullptr) {
172 std::string name = dp->d_name;
173
Steven Morelandda8e6172017-04-06 17:24:22 -0700174 if (startsWith(name, prefix) &&
175 endsWith(name, suffix)) {
Steven Moreland0091c092017-01-20 23:15:18 +0000176 results.push_back(name);
177 }
178 }
179
180 return results;
181}
182
Yifan Hongbd0d8f72017-05-24 19:43:51 -0700183bool matchPackageName(const std::string& lib, std::string* matchedName, std::string* implName) {
Yifan Hong9a22d1d2017-01-25 14:19:26 -0800184 std::smatch match;
185 if (std::regex_match(lib, match, gLibraryFileNamePattern)) {
186 *matchedName = match.str(1) + "::I*";
Yifan Hongbd0d8f72017-05-24 19:43:51 -0700187 *implName = match.str(2);
Yifan Hong9a22d1d2017-01-25 14:19:26 -0800188 return true;
189 }
190 return false;
191}
192
Yifan Hong7f49f592017-02-03 15:11:44 -0800193static void registerReference(const hidl_string &interfaceName, const hidl_string &instanceName) {
194 sp<IServiceManager> binderizedManager = defaultServiceManager();
195 if (binderizedManager == nullptr) {
196 LOG(WARNING) << "Could not registerReference for "
197 << interfaceName << "/" << instanceName
198 << ": null binderized manager.";
199 return;
200 }
Martijn Coenenbf13ad02017-04-27 09:41:13 -0700201 auto ret = binderizedManager->registerPassthroughClient(interfaceName, instanceName);
Yifan Hong7f49f592017-02-03 15:11:44 -0800202 if (!ret.isOk()) {
203 LOG(WARNING) << "Could not registerReference for "
204 << interfaceName << "/" << instanceName
205 << ": " << ret.description();
Steven Moreland0aeaa782017-03-22 08:11:07 -0700206 return;
Yifan Hong7f49f592017-02-03 15:11:44 -0800207 }
Steven Morelande681aa52017-02-15 16:22:37 -0800208 LOG(VERBOSE) << "Successfully registerReference for "
209 << interfaceName << "/" << instanceName;
Yifan Hong7f49f592017-02-03 15:11:44 -0800210}
211
Yifan Hongbd0d8f72017-05-24 19:43:51 -0700212using InstanceDebugInfo = hidl::manager::V1_0::IServiceManager::InstanceDebugInfo;
213static inline void fetchPidsForPassthroughLibraries(
214 std::map<std::string, InstanceDebugInfo>* infos) {
215 static const std::string proc = "/proc/";
216
217 std::map<std::string, std::set<pid_t>> pids;
218 std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(proc.c_str()), closedir);
219 if (!dir) return;
220 dirent* dp;
221 while ((dp = readdir(dir.get())) != nullptr) {
222 pid_t pid = strtoll(dp->d_name, NULL, 0);
223 if (pid == 0) continue;
224 std::string mapsPath = proc + dp->d_name + "/maps";
225 std::ifstream ifs{mapsPath};
226 if (!ifs.is_open()) continue;
227
228 for (std::string line; std::getline(ifs, line);) {
229 // The last token of line should look like
230 // vendor/lib64/hw/android.hardware.foo@1.0-impl-extra.so
231 // Use some simple filters to ignore bad lines before extracting libFileName
232 // and checking the key in info to make parsing faster.
233 if (line.back() != 'o') continue;
234 if (line.rfind('@') == std::string::npos) continue;
235
236 auto spacePos = line.rfind(' ');
237 if (spacePos == std::string::npos) continue;
238 auto libFileName = line.substr(spacePos + 1);
239 auto it = infos->find(libFileName);
240 if (it == infos->end()) continue;
241 pids[libFileName].insert(pid);
242 }
243 }
244 for (auto& pair : *infos) {
245 pair.second.clientPids =
246 std::vector<pid_t>{pids[pair.first].begin(), pids[pair.first].end()};
247 }
248}
249
Steven Moreland337e6b62017-01-18 17:25:13 -0800250struct PassthroughServiceManager : IServiceManager {
Steven Moreland519306f2017-06-06 17:14:12 -0700251 static void openLibs(const std::string& fqName,
252 std::function<bool /* continue */(void* /* handle */,
253 const std::string& /* lib */, const std::string& /* sym */)> eachLib) {
Steven Morelandda8e6172017-04-06 17:24:22 -0700254 //fqName looks like android.hardware.foo@1.0::IFoo
Steven Moreland519306f2017-06-06 17:14:12 -0700255 size_t idx = fqName.find("::");
Steven Morelandda8e6172017-04-06 17:24:22 -0700256
257 if (idx == std::string::npos ||
Steven Moreland519306f2017-06-06 17:14:12 -0700258 idx + strlen("::") + 1 >= fqName.size()) {
Steven Moreland337e6b62017-01-18 17:25:13 -0800259 LOG(ERROR) << "Invalid interface name passthrough lookup: " << fqName;
Steven Moreland519306f2017-06-06 17:14:12 -0700260 return;
Steven Moreland337e6b62017-01-18 17:25:13 -0800261 }
262
Steven Moreland519306f2017-06-06 17:14:12 -0700263 std::string packageAndVersion = fqName.substr(0, idx);
264 std::string ifaceName = fqName.substr(idx + strlen("::"));
Steven Morelandda8e6172017-04-06 17:24:22 -0700265
266 const std::string prefix = packageAndVersion + "-impl";
267 const std::string sym = "HIDL_FETCH_" + ifaceName;
Steven Moreland348802d2017-02-23 12:48:55 -0800268
Steven Moreland337e6b62017-01-18 17:25:13 -0800269 const int dlMode = RTLD_LAZY;
270 void *handle = nullptr;
271
Steven Morelanda29905c2017-03-01 10:42:35 -0800272 dlerror(); // clear
273
Steven Morelandf7dea692017-07-14 12:49:28 -0700274 std::vector<std::string> paths = {HAL_LIBRARY_PATH_ODM, HAL_LIBRARY_PATH_VENDOR,
275 HAL_LIBRARY_PATH_SYSTEM};
276#ifdef LIBHIDL_TARGET_DEBUGGABLE
277 const char* env = std::getenv("TREBLE_TESTING_OVERRIDE");
278 const bool trebleTestingOverride = env && !strcmp(env, "true");
279 if (trebleTestingOverride) {
280 const char* vtsRootPath = std::getenv("VTS_ROOT_PATH");
281 if (vtsRootPath && strlen(vtsRootPath) > 0) {
282 const std::string halLibraryPathVtsOverride =
283 std::string(vtsRootPath) + HAL_LIBRARY_PATH_SYSTEM;
284 paths.push_back(halLibraryPathVtsOverride);
285 }
286 }
287#endif
288 for (const std::string& path : paths) {
Steven Moreland0091c092017-01-20 23:15:18 +0000289 std::vector<std::string> libs = search(path, prefix, ".so");
290
Steven Moreland0091c092017-01-20 23:15:18 +0000291 for (const std::string &lib : libs) {
Steven Moreland348802d2017-02-23 12:48:55 -0800292 const std::string fullPath = path + lib;
293
294 handle = dlopen(fullPath.c_str(), dlMode);
295 if (handle == nullptr) {
296 const char* error = dlerror();
297 LOG(ERROR) << "Failed to dlopen " << lib << ": "
298 << (error == nullptr ? "unknown error" : error);
299 continue;
Steven Moreland0091c092017-01-20 23:15:18 +0000300 }
Steven Moreland348802d2017-02-23 12:48:55 -0800301
Steven Moreland519306f2017-06-06 17:14:12 -0700302 if (!eachLib(handle, lib, sym)) {
303 return;
Steven Moreland348802d2017-02-23 12:48:55 -0800304 }
Steven Moreland337e6b62017-01-18 17:25:13 -0800305 }
306 }
Steven Moreland519306f2017-06-06 17:14:12 -0700307 }
Steven Moreland337e6b62017-01-18 17:25:13 -0800308
Steven Moreland519306f2017-06-06 17:14:12 -0700309 Return<sp<IBase>> get(const hidl_string& fqName,
310 const hidl_string& name) override {
311 sp<IBase> ret = nullptr;
312
313 openLibs(fqName, [&](void* handle, const std::string &lib, const std::string &sym) {
314 IBase* (*generator)(const char* name);
315 *(void **)(&generator) = dlsym(handle, sym.c_str());
316 if(!generator) {
317 const char* error = dlerror();
318 LOG(ERROR) << "Passthrough lookup opened " << lib
319 << " but could not find symbol " << sym << ": "
320 << (error == nullptr ? "unknown error" : error);
321 dlclose(handle);
322 return true;
323 }
324
325 ret = (*generator)(name.c_str());
326
327 if (ret == nullptr) {
328 dlclose(handle);
329 return true; // this module doesn't provide this instance name
330 }
331
332 registerReference(fqName, name);
333 return false;
334 });
335
336 return ret;
Steven Moreland337e6b62017-01-18 17:25:13 -0800337 }
338
Martijn Coenen67a02492017-03-06 13:04:48 +0100339 Return<bool> add(const hidl_string& /* name */,
Steven Moreland337e6b62017-01-18 17:25:13 -0800340 const sp<IBase>& /* service */) override {
341 LOG(FATAL) << "Cannot register services with passthrough service manager.";
342 return false;
343 }
344
Steven Moreland330e3e22017-04-06 09:26:07 -0700345 Return<Transport> getTransport(const hidl_string& /* fqName */,
346 const hidl_string& /* name */) {
347 LOG(FATAL) << "Cannot getTransport with passthrough service manager.";
348 return Transport::EMPTY;
349 }
350
Yifan Hong705e5da2017-03-02 16:59:39 -0800351 Return<void> list(list_cb /* _hidl_cb */) override {
352 LOG(FATAL) << "Cannot list services with passthrough service manager.";
Steven Moreland337e6b62017-01-18 17:25:13 -0800353 return Void();
354 }
355 Return<void> listByInterface(const hidl_string& /* fqInstanceName */,
356 listByInterface_cb /* _hidl_cb */) override {
357 // TODO: add this functionality
358 LOG(FATAL) << "Cannot list services with passthrough service manager.";
359 return Void();
360 }
361
362 Return<bool> registerForNotifications(const hidl_string& /* fqName */,
363 const hidl_string& /* name */,
364 const sp<IServiceNotification>& /* callback */) override {
365 // This makes no sense.
366 LOG(FATAL) << "Cannot register for notifications with passthrough service manager.";
367 return false;
368 }
369
Yifan Hong705e5da2017-03-02 16:59:39 -0800370 Return<void> debugDump(debugDump_cb _hidl_cb) override {
371 using Arch = ::android::hidl::base::V1_0::DebugInfo::Architecture;
Yifan Hongbd0d8f72017-05-24 19:43:51 -0700372 using std::literals::string_literals::operator""s;
Yifan Hong705e5da2017-03-02 16:59:39 -0800373 static std::vector<std::pair<Arch, std::vector<const char *>>> sAllPaths{
374 {Arch::IS_64BIT, {HAL_LIBRARY_PATH_ODM_64BIT,
375 HAL_LIBRARY_PATH_VENDOR_64BIT,
376 HAL_LIBRARY_PATH_SYSTEM_64BIT}},
377 {Arch::IS_32BIT, {HAL_LIBRARY_PATH_ODM_32BIT,
378 HAL_LIBRARY_PATH_VENDOR_32BIT,
379 HAL_LIBRARY_PATH_SYSTEM_32BIT}}
380 };
Yifan Hongbd0d8f72017-05-24 19:43:51 -0700381 std::map<std::string, InstanceDebugInfo> map;
Yifan Hong705e5da2017-03-02 16:59:39 -0800382 for (const auto &pair : sAllPaths) {
383 Arch arch = pair.first;
384 for (const auto &path : pair.second) {
385 std::vector<std::string> libs = search(path, "", ".so");
386 for (const std::string &lib : libs) {
387 std::string matchedName;
Yifan Hongbd0d8f72017-05-24 19:43:51 -0700388 std::string implName;
389 if (matchPackageName(lib, &matchedName, &implName)) {
390 std::string instanceName{"* ("s + path + ")"s};
391 if (!implName.empty()) instanceName += " ("s + implName + ")"s;
392 map.emplace(path + lib, InstanceDebugInfo{.interfaceName = matchedName,
393 .instanceName = instanceName,
394 .clientPids = {},
395 .arch = arch});
Yifan Hong705e5da2017-03-02 16:59:39 -0800396 }
397 }
398 }
399 }
Yifan Hongbd0d8f72017-05-24 19:43:51 -0700400 fetchPidsForPassthroughLibraries(&map);
401 hidl_vec<InstanceDebugInfo> vec;
402 vec.resize(map.size());
403 size_t idx = 0;
404 for (auto&& pair : map) {
405 vec[idx++] = std::move(pair.second);
406 }
Yifan Hong705e5da2017-03-02 16:59:39 -0800407 _hidl_cb(vec);
Yifan Hong7f49f592017-02-03 15:11:44 -0800408 return Void();
409 }
410
Martijn Coenenbf13ad02017-04-27 09:41:13 -0700411 Return<void> registerPassthroughClient(const hidl_string &, const hidl_string &) override {
Yifan Hong7f49f592017-02-03 15:11:44 -0800412 // This makes no sense.
413 LOG(FATAL) << "Cannot call registerPassthroughClient on passthrough service manager. "
414 << "Call it on defaultServiceManager() instead.";
Yifan Hong9a22d1d2017-01-25 14:19:26 -0800415 return Void();
416 }
417
Steven Moreland337e6b62017-01-18 17:25:13 -0800418};
419
420sp<IServiceManager> getPassthroughServiceManager() {
421 static sp<PassthroughServiceManager> manager(new PassthroughServiceManager());
422 return manager;
423}
424
Steven Morelandcbefd352017-01-23 20:29:05 -0800425namespace details {
426
Steven Moreland519306f2017-06-06 17:14:12 -0700427void preloadPassthroughService(const std::string &descriptor) {
428 PassthroughServiceManager::openLibs(descriptor,
429 [&](void* /* handle */, const std::string& /* lib */, const std::string& /* sym */) {
430 // do nothing
431 return true; // open all libs
432 });
433}
434
Steven Morelandcbefd352017-01-23 20:29:05 -0800435struct Waiter : IServiceNotification {
436 Return<void> onRegistration(const hidl_string& /* fqName */,
437 const hidl_string& /* name */,
438 bool /* preexisting */) override {
439 std::unique_lock<std::mutex> lock(mMutex);
440 if (mRegistered) {
441 return Void();
442 }
443 mRegistered = true;
444 lock.unlock();
445
446 mCondition.notify_one();
447 return Void();
448 }
449
Steven Morelandf1e14f22017-03-28 09:33:06 -0700450 void wait(const std::string &interface, const std::string &instanceName) {
451 using std::literals::chrono_literals::operator""s;
452
Steven Morelandcbefd352017-01-23 20:29:05 -0800453 std::unique_lock<std::mutex> lock(mMutex);
Steven Morelandf1e14f22017-03-28 09:33:06 -0700454 while(true) {
455 mCondition.wait_for(lock, 1s, [this]{
456 return mRegistered;
457 });
458
459 if (mRegistered) {
460 break;
461 }
462
463 LOG(WARNING) << "Waited one second for "
464 << interface << "/" << instanceName
465 << ". Waiting another...";
466 }
Steven Morelandcbefd352017-01-23 20:29:05 -0800467 }
468
469private:
470 std::mutex mMutex;
471 std::condition_variable mCondition;
472 bool mRegistered = false;
473};
474
475void waitForHwService(
476 const std::string &interface, const std::string &instanceName) {
477 const sp<IServiceManager> manager = defaultServiceManager();
478
479 if (manager == nullptr) {
480 LOG(ERROR) << "Could not get default service manager.";
481 return;
482 }
483
484 sp<Waiter> waiter = new Waiter();
485 Return<bool> ret = manager->registerForNotifications(interface, instanceName, waiter);
486
487 if (!ret.isOk()) {
488 LOG(ERROR) << "Transport error, " << ret.description()
489 << ", during notification registration for "
490 << interface << "/" << instanceName << ".";
491 return;
492 }
493
494 if (!ret) {
495 LOG(ERROR) << "Could not register for notifications for "
496 << interface << "/" << instanceName << ".";
497 return;
498 }
499
Steven Morelandf1e14f22017-03-28 09:33:06 -0700500 waiter->wait(interface, instanceName);
Steven Morelandcbefd352017-01-23 20:29:05 -0800501}
502
503}; // namespace details
504
Steven Moreland5d5ef7f2016-10-20 19:19:55 -0700505}; // namespace hardware
506}; // namespace android