/* * 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 "ServiceManagement" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define RE_COMPONENT "[a-zA-Z_][a-zA-Z_0-9]*" #define RE_PATH RE_COMPONENT "(?:[.]" RE_COMPONENT ")*" static const std::regex gLibraryFileNamePattern("(" RE_PATH "@[0-9]+[.][0-9]+)-impl(.*?).so"); extern "C" { android_namespace_t* android_get_exported_namespace(const char*); } using android::base::WaitForProperty; using android::hidl::manager::V1_0::IServiceManager; using android::hidl::manager::V1_0::IServiceNotification; using android::hidl::manager::V1_0::BpHwServiceManager; using android::hidl::manager::V1_0::BnHwServiceManager; namespace android { namespace hardware { namespace details { extern Mutex gDefaultServiceManagerLock; extern sp gDefaultServiceManager; } // namespace details static const char* kHwServicemanagerReadyProperty = "hwservicemanager.ready"; void waitForHwServiceManager() { using std::literals::chrono_literals::operator""s; while (!WaitForProperty(kHwServicemanagerReadyProperty, "true", 1s)) { LOG(WARNING) << "Waited for hwservicemanager.ready for a second, waiting another..."; } } bool endsWith(const std::string &in, const std::string &suffix) { return in.size() >= suffix.size() && in.substr(in.size() - suffix.size()) == suffix; } bool startsWith(const std::string &in, const std::string &prefix) { return in.size() >= prefix.size() && in.substr(0, prefix.size()) == prefix; } std::string binaryName() { std::ifstream ifs("/proc/self/cmdline"); std::string cmdline; if (!ifs.is_open()) { return ""; } ifs >> cmdline; size_t idx = cmdline.rfind("/"); if (idx != std::string::npos) { cmdline = cmdline.substr(idx + 1); } return cmdline; } void tryShortenProcessName(const std::string &packageName) { std::string processName = binaryName(); if (!startsWith(processName, packageName)) { return; } // e.x. android.hardware.module.foo@1.0 -> foo@1.0 size_t lastDot = packageName.rfind('.'); size_t secondDot = packageName.rfind('.', lastDot - 1); if (secondDot == std::string::npos) { return; } std::string newName = processName.substr(secondDot + 1, 16 /* TASK_COMM_LEN */ - 1); ALOGI("Removing namespace from process name %s to %s.", processName.c_str(), newName.c_str()); int rc = pthread_setname_np(pthread_self(), newName.c_str()); ALOGI_IF(rc != 0, "Removing namespace from process name %s failed.", processName.c_str()); } namespace details { void onRegistration(const std::string &packageName, const std::string& /* interfaceName */, const std::string& /* instanceName */) { tryShortenProcessName(packageName); } } // details sp defaultServiceManager() { { AutoMutex _l(details::gDefaultServiceManagerLock); if (details::gDefaultServiceManager != NULL) { return details::gDefaultServiceManager; } if (access("/dev/hwbinder", F_OK|R_OK|W_OK) != 0) { // HwBinder not available on this device or not accessible to // this process. return nullptr; } waitForHwServiceManager(); while (details::gDefaultServiceManager == NULL) { details::gDefaultServiceManager = fromBinder( ProcessState::self()->getContextObject(NULL)); if (details::gDefaultServiceManager == NULL) { LOG(ERROR) << "Waited for hwservicemanager, but got nullptr."; sleep(1); } } } return details::gDefaultServiceManager; } std::vector search(const std::string &path, const std::string &prefix, const std::string &suffix) { std::unique_ptr dir(opendir(path.c_str()), closedir); if (!dir) return {}; std::vector results{}; dirent* dp; while ((dp = readdir(dir.get())) != nullptr) { std::string name = dp->d_name; if (startsWith(name, prefix) && endsWith(name, suffix)) { results.push_back(name); } } return results; } bool matchPackageName(const std::string &lib, std::string *matchedName) { std::smatch match; if (std::regex_match(lib, match, gLibraryFileNamePattern)) { *matchedName = match.str(1) + "::I*"; return true; } return false; } static void registerReference(const hidl_string &interfaceName, const hidl_string &instanceName) { sp binderizedManager = defaultServiceManager(); if (binderizedManager == nullptr) { LOG(WARNING) << "Could not registerReference for " << interfaceName << "/" << instanceName << ": null binderized manager."; return; } auto ret = binderizedManager->registerPassthroughClient(interfaceName, instanceName); if (!ret.isOk()) { LOG(WARNING) << "Could not registerReference for " << interfaceName << "/" << instanceName << ": " << ret.description(); return; } LOG(VERBOSE) << "Successfully registerReference for " << interfaceName << "/" << instanceName; } struct PassthroughServiceManager : IServiceManager { Return> get(const hidl_string& fqName, const hidl_string& name) override { std::string stdFqName(fqName.c_str()); //fqName looks like android.hardware.foo@1.0::IFoo size_t idx = stdFqName.find("::"); if (idx == std::string::npos || idx + strlen("::") + 1 >= stdFqName.size()) { LOG(ERROR) << "Invalid interface name passthrough lookup: " << fqName; return nullptr; } std::string packageAndVersion = stdFqName.substr(0, idx); std::string ifaceName = stdFqName.substr(idx + strlen("::")); const std::string prefix = packageAndVersion + "-impl"; const std::string sym = "HIDL_FETCH_" + ifaceName; const android_namespace_t* sphal_namespace = android_get_exported_namespace("sphal"); const int dlMode = RTLD_LAZY; void *handle = nullptr; // TODO: lookup in VINTF instead // TODO(b/34135607): Remove HAL_LIBRARY_PATH_SYSTEM dlerror(); // clear for (const std::string &path : { HAL_LIBRARY_PATH_ODM, HAL_LIBRARY_PATH_VENDOR, HAL_LIBRARY_PATH_SYSTEM }) { std::vector libs = search(path, prefix, ".so"); for (const std::string &lib : libs) { const std::string fullPath = path + lib; // If sphal namespace is available, try to load from the // namespace first. If it fails, fall back to the original // dlopen, which loads from the current namespace. if (sphal_namespace != nullptr && path != HAL_LIBRARY_PATH_SYSTEM) { const android_dlextinfo dlextinfo = { .flags = ANDROID_DLEXT_USE_NAMESPACE, // const_cast is dirty but required because // library_namespace field is non-const. .library_namespace = const_cast(sphal_namespace), }; handle = android_dlopen_ext(fullPath.c_str(), dlMode, &dlextinfo); if (handle == nullptr) { const char* error = dlerror(); LOG(WARNING) << "Failed to dlopen " << lib << " from sphal namespace:" << (error == nullptr ? "unknown error" : error); } else { LOG(DEBUG) << lib << " loaded from sphal namespace."; } } if (handle == nullptr) { handle = dlopen(fullPath.c_str(), dlMode); } if (handle == nullptr) { const char* error = dlerror(); LOG(ERROR) << "Failed to dlopen " << lib << ": " << (error == nullptr ? "unknown error" : error); continue; } IBase* (*generator)(const char* name); *(void **)(&generator) = dlsym(handle, sym.c_str()); if(!generator) { const char* error = dlerror(); LOG(ERROR) << "Passthrough lookup opened " << lib << " but could not find symbol " << sym << ": " << (error == nullptr ? "unknown error" : error); dlclose(handle); continue; } IBase *interface = (*generator)(name.c_str()); if (interface == nullptr) { dlclose(handle); continue; // this module doesn't provide this instance name } registerReference(fqName, name); return interface; } } return nullptr; } Return add(const hidl_string& /* name */, const sp& /* service */) override { LOG(FATAL) << "Cannot register services with passthrough service manager."; return false; } Return getTransport(const hidl_string& /* fqName */, const hidl_string& /* name */) { LOG(FATAL) << "Cannot getTransport with passthrough service manager."; return Transport::EMPTY; } Return list(list_cb /* _hidl_cb */) override { LOG(FATAL) << "Cannot list services with passthrough service manager."; return Void(); } Return listByInterface(const hidl_string& /* fqInstanceName */, listByInterface_cb /* _hidl_cb */) override { // TODO: add this functionality LOG(FATAL) << "Cannot list services with passthrough service manager."; return Void(); } Return registerForNotifications(const hidl_string& /* fqName */, const hidl_string& /* name */, const sp& /* callback */) override { // This makes no sense. LOG(FATAL) << "Cannot register for notifications with passthrough service manager."; return false; } Return debugDump(debugDump_cb _hidl_cb) override { using Arch = ::android::hidl::base::V1_0::DebugInfo::Architecture; static std::vector>> sAllPaths{ {Arch::IS_64BIT, {HAL_LIBRARY_PATH_ODM_64BIT, HAL_LIBRARY_PATH_VENDOR_64BIT, HAL_LIBRARY_PATH_SYSTEM_64BIT}}, {Arch::IS_32BIT, {HAL_LIBRARY_PATH_ODM_32BIT, HAL_LIBRARY_PATH_VENDOR_32BIT, HAL_LIBRARY_PATH_SYSTEM_32BIT}} }; std::vector vec; for (const auto &pair : sAllPaths) { Arch arch = pair.first; for (const auto &path : pair.second) { std::vector libs = search(path, "", ".so"); for (const std::string &lib : libs) { std::string matchedName; if (matchPackageName(lib, &matchedName)) { vec.push_back({ .interfaceName = matchedName, .instanceName = "*", .clientPids = {}, .arch = arch }); } } } } _hidl_cb(vec); return Void(); } Return registerPassthroughClient(const hidl_string &, const hidl_string &) override { // This makes no sense. LOG(FATAL) << "Cannot call registerPassthroughClient on passthrough service manager. " << "Call it on defaultServiceManager() instead."; return Void(); } }; sp getPassthroughServiceManager() { static sp manager(new PassthroughServiceManager()); return manager; } namespace details { struct Waiter : IServiceNotification { Return onRegistration(const hidl_string& /* fqName */, const hidl_string& /* name */, bool /* preexisting */) override { std::unique_lock lock(mMutex); if (mRegistered) { return Void(); } mRegistered = true; lock.unlock(); mCondition.notify_one(); return Void(); } void wait(const std::string &interface, const std::string &instanceName) { using std::literals::chrono_literals::operator""s; std::unique_lock lock(mMutex); while(true) { mCondition.wait_for(lock, 1s, [this]{ return mRegistered; }); if (mRegistered) { break; } LOG(WARNING) << "Waited one second for " << interface << "/" << instanceName << ". Waiting another..."; } } private: std::mutex mMutex; std::condition_variable mCondition; bool mRegistered = false; }; void waitForHwService( const std::string &interface, const std::string &instanceName) { const sp manager = defaultServiceManager(); if (manager == nullptr) { LOG(ERROR) << "Could not get default service manager."; return; } sp waiter = new Waiter(); Return ret = manager->registerForNotifications(interface, instanceName, waiter); if (!ret.isOk()) { LOG(ERROR) << "Transport error, " << ret.description() << ", during notification registration for " << interface << "/" << instanceName << "."; return; } if (!ret) { LOG(ERROR) << "Could not register for notifications for " << interface << "/" << instanceName << "."; return; } waiter->wait(interface, instanceName); } }; // namespace details }; // namespace hardware }; // namespace android