Loading cmds/lshal/ListCommand.cpp +89 −60 Original line number Diff line number Diff line Loading @@ -44,6 +44,7 @@ #include "Timeout.h" #include "utils.h" using ::android::hardware::hidl_array; using ::android::hardware::hidl_string; using ::android::hardware::hidl_vec; using ::android::hidl::base::V1_0::DebugInfo; Loading Loading @@ -523,19 +524,23 @@ Status ListCommand::fetchAllLibraries(const sp<IServiceManager> &manager) { using namespace ::android::hidl::manager::V1_0; using namespace ::android::hidl::base::V1_0; using std::literals::chrono_literals::operator""s; auto ret = timeoutIPC(10s, manager, &IServiceManager::debugDump, [&] (const auto &infos) { std::map<std::string, TableEntry> entries; // The lambda function may be executed asynchrounously because it is passed to timeoutIPC, // even though the interface function call is synchronous. // However, there's no need to lock because if ret.isOk(), the background thread has // already ended, so it is safe to dereference entries. auto entries = std::make_shared<std::map<std::string, TableEntry>>(); auto ret = timeoutIPC(10s, manager, &IServiceManager::debugDump, [entries](const auto& infos) { for (const auto &info : infos) { std::string interfaceName = std::string{info.interfaceName.c_str()} + "/" + std::string{info.instanceName.c_str()}; entries.emplace(interfaceName, TableEntry{ entries->emplace(interfaceName, TableEntry{ .interfaceName = interfaceName, .transport = vintf::Transport::PASSTHROUGH, .clientPids = info.clientPids, }).first->second.arch |= fromBaseArchitecture(info.arch); } for (auto &&pair : entries) { putEntry(HalType::PASSTHROUGH_LIBRARIES, std::move(pair.second)); }) .first->second.arch |= fromBaseArchitecture(info.arch); } }); if (!ret.isOk()) { Loading @@ -543,6 +548,9 @@ Status ListCommand::fetchAllLibraries(const sp<IServiceManager> &manager) { << ret.description() << std::endl; return DUMP_ALL_LIBS_ERROR; } for (auto&& pair : *entries) { putEntry(HalType::PASSTHROUGH_LIBRARIES, std::move(pair.second)); } return OK; } Loading @@ -553,20 +561,25 @@ Status ListCommand::fetchPassthrough(const sp<IServiceManager> &manager) { using namespace ::android::hardware::details; using namespace ::android::hidl::manager::V1_0; using namespace ::android::hidl::base::V1_0; auto ret = timeoutIPC(manager, &IServiceManager::debugDump, [&] (const auto &infos) { // The lambda function may be executed asynchrounously because it is passed to timeoutIPC, // even though the interface function call is synchronous. // However, there's no need to lock because if ret.isOk(), the background thread has // already ended, so it is safe to dereference entries. auto entries = std::make_shared<std::vector<TableEntry>>(); auto ret = timeoutIPC(manager, &IServiceManager::debugDump, [entries](const auto& infos) { for (const auto &info : infos) { if (info.clientPids.size() <= 0) { continue; } putEntry(HalType::PASSTHROUGH_CLIENTS, { .interfaceName = std::string{info.interfaceName.c_str()} + "/" + entries->emplace_back( TableEntry{.interfaceName = std::string{info.interfaceName.c_str()} + "/" + std::string{info.instanceName.c_str()}, .transport = vintf::Transport::PASSTHROUGH, .serverPid = info.clientPids.size() == 1 ? info.clientPids[0] : NO_PID, .serverPid = info.clientPids.size() == 1 ? info.clientPids[0] : NO_PID, .clientPids = info.clientPids, .arch = fromBaseArchitecture(info.arch) }); .arch = fromBaseArchitecture(info.arch)}); } }); if (!ret.isOk()) { Loading @@ -574,6 +587,9 @@ Status ListCommand::fetchPassthrough(const sp<IServiceManager> &manager) { << ret.description() << std::endl; return DUMP_PASSTHROUGH_ERROR; } for (auto&& entry : *entries) { putEntry(HalType::PASSTHROUGH_CLIENTS, std::move(entry)); } return OK; } Loading @@ -583,11 +599,14 @@ Status ListCommand::fetchBinderized(const sp<IServiceManager> &manager) { if (!shouldFetchHalType(HalType::BINDERIZED_SERVICES)) { return OK; } const vintf::Transport mode = vintf::Transport::HWBINDER; hidl_vec<hidl_string> fqInstanceNames; // copying out for timeoutIPC auto listRet = timeoutIPC(manager, &IServiceManager::list, [&] (const auto &names) { fqInstanceNames = names; }); // The lambda function may be executed asynchrounously because it is passed to timeoutIPC, // even though the interface function call is synchronous. // However, there's no need to lock because if listRet.isOk(), the background thread has // already ended, so it is safe to dereference fqInstanceNames. auto fqInstanceNames = std::make_shared<hidl_vec<hidl_string>>(); auto listRet = timeoutIPC(manager, &IServiceManager::list, [fqInstanceNames](const auto& names) { *fqInstanceNames = names; }); if (!listRet.isOk()) { err() << "Error: Failed to list services for " << mode << ": " << listRet.description() << std::endl; Loading @@ -596,7 +615,7 @@ Status ListCommand::fetchBinderized(const sp<IServiceManager> &manager) { Status status = OK; std::map<std::string, TableEntry> allTableEntries; for (const auto &fqInstanceName : fqInstanceNames) { for (const auto& fqInstanceName : *fqInstanceNames) { // create entry and default assign all fields. TableEntry& entry = allTableEntries[fqInstanceName]; entry.interfaceName = fqInstanceName; Loading Loading @@ -637,30 +656,33 @@ Status ListCommand::fetchBinderizedEntry(const sp<IServiceManager> &manager, // getDebugInfo do { DebugInfo debugInfo; auto debugRet = timeoutIPC(service, &IBase::getDebugInfo, [&] (const auto &received) { debugInfo = received; }); // The lambda function may be executed asynchrounously because it is passed to timeoutIPC, // even though the interface function call is synchronous. // However, there's no need to lock because if debugRet.isOk(), the background thread has // already ended, so it is safe to dereference debugInfo. auto debugInfo = std::make_shared<DebugInfo>(); auto debugRet = timeoutIPC(service, &IBase::getDebugInfo, [debugInfo](const auto& received) { *debugInfo = received; }); if (!debugRet.isOk()) { handleError(TRANSACTION_ERROR, "debugging information cannot be retrieved: " + debugRet.description()); break; // skip getPidInfo } entry->serverPid = debugInfo.pid; entry->serverObjectAddress = debugInfo.ptr; entry->arch = fromBaseArchitecture(debugInfo.arch); entry->serverPid = debugInfo->pid; entry->serverObjectAddress = debugInfo->ptr; entry->arch = fromBaseArchitecture(debugInfo->arch); if (debugInfo.pid != NO_PID) { const BinderPidInfo* pidInfo = getPidInfoCached(debugInfo.pid); if (debugInfo->pid != NO_PID) { const BinderPidInfo* pidInfo = getPidInfoCached(debugInfo->pid); if (pidInfo == nullptr) { handleError(IO_ERROR, "no information for PID " + std::to_string(debugInfo.pid) + "no information for PID " + std::to_string(debugInfo->pid) + ", are you root?"); break; } if (debugInfo.ptr != NO_PTR) { auto it = pidInfo->refPids.find(debugInfo.ptr); if (debugInfo->ptr != NO_PTR) { auto it = pidInfo->refPids.find(debugInfo->ptr); if (it != pidInfo->refPids.end()) { entry->clientPids = it->second; } Loading @@ -672,11 +694,14 @@ Status ListCommand::fetchBinderizedEntry(const sp<IServiceManager> &manager, // hash do { ssize_t hashIndex = -1; auto ifaceChainRet = timeoutIPC(service, &IBase::interfaceChain, [&] (const auto& c) { // The lambda function may be executed asynchrounously because it is passed to timeoutIPC, // even though the interface function call is synchronous. auto hashIndexStore = std::make_shared<ssize_t>(-1); auto ifaceChainRet = timeoutIPC(service, &IBase::interfaceChain, [hashIndexStore, serviceName](const auto& c) { for (size_t i = 0; i < c.size(); ++i) { if (serviceName == c[i]) { hashIndex = static_cast<ssize_t>(i); *hashIndexStore = static_cast<ssize_t>(i); break; } } Loading @@ -686,24 +711,28 @@ Status ListCommand::fetchBinderizedEntry(const sp<IServiceManager> &manager, "interfaceChain fails: " + ifaceChainRet.description()); break; // skip getHashChain } // if ifaceChainRet.isOk(), the background thread has already ended, so it is safe to // dereference hashIndex without any locking. auto hashIndex = *hashIndexStore; if (hashIndex < 0) { handleError(BAD_IMPL, "Interface name does not exist in interfaceChain."); break; // skip getHashChain } auto hashRet = timeoutIPC(service, &IBase::getHashChain, [&] (const auto& hashChain) { if (static_cast<size_t>(hashIndex) >= hashChain.size()) { // See comments about hashIndex above. auto hashChain = std::make_shared<hidl_vec<hidl_array<uint8_t, 32>>>(); auto hashRet = timeoutIPC(service, &IBase::getHashChain, [hashChain](const auto& ret) { *hashChain = std::move(ret); }); if (!hashRet.isOk()) { handleError(TRANSACTION_ERROR, "getHashChain failed: " + hashRet.description()); } if (static_cast<size_t>(hashIndex) >= hashChain->size()) { handleError(BAD_IMPL, "interfaceChain indicates position " + std::to_string(hashIndex) + " but getHashChain returns " + std::to_string(hashChain.size()) + " but getHashChain returns " + std::to_string(hashChain->size()) + " hashes"); return; } auto&& hashArray = hashChain[hashIndex]; } else { auto&& hashArray = (*hashChain)[hashIndex]; entry->hash = android::base::HexString(hashArray.data(), hashArray.size()); }); if (!hashRet.isOk()) { handleError(TRANSACTION_ERROR, "getHashChain failed: " + hashRet.description()); } } while (0); if (status == OK) { Loading Loading
cmds/lshal/ListCommand.cpp +89 −60 Original line number Diff line number Diff line Loading @@ -44,6 +44,7 @@ #include "Timeout.h" #include "utils.h" using ::android::hardware::hidl_array; using ::android::hardware::hidl_string; using ::android::hardware::hidl_vec; using ::android::hidl::base::V1_0::DebugInfo; Loading Loading @@ -523,19 +524,23 @@ Status ListCommand::fetchAllLibraries(const sp<IServiceManager> &manager) { using namespace ::android::hidl::manager::V1_0; using namespace ::android::hidl::base::V1_0; using std::literals::chrono_literals::operator""s; auto ret = timeoutIPC(10s, manager, &IServiceManager::debugDump, [&] (const auto &infos) { std::map<std::string, TableEntry> entries; // The lambda function may be executed asynchrounously because it is passed to timeoutIPC, // even though the interface function call is synchronous. // However, there's no need to lock because if ret.isOk(), the background thread has // already ended, so it is safe to dereference entries. auto entries = std::make_shared<std::map<std::string, TableEntry>>(); auto ret = timeoutIPC(10s, manager, &IServiceManager::debugDump, [entries](const auto& infos) { for (const auto &info : infos) { std::string interfaceName = std::string{info.interfaceName.c_str()} + "/" + std::string{info.instanceName.c_str()}; entries.emplace(interfaceName, TableEntry{ entries->emplace(interfaceName, TableEntry{ .interfaceName = interfaceName, .transport = vintf::Transport::PASSTHROUGH, .clientPids = info.clientPids, }).first->second.arch |= fromBaseArchitecture(info.arch); } for (auto &&pair : entries) { putEntry(HalType::PASSTHROUGH_LIBRARIES, std::move(pair.second)); }) .first->second.arch |= fromBaseArchitecture(info.arch); } }); if (!ret.isOk()) { Loading @@ -543,6 +548,9 @@ Status ListCommand::fetchAllLibraries(const sp<IServiceManager> &manager) { << ret.description() << std::endl; return DUMP_ALL_LIBS_ERROR; } for (auto&& pair : *entries) { putEntry(HalType::PASSTHROUGH_LIBRARIES, std::move(pair.second)); } return OK; } Loading @@ -553,20 +561,25 @@ Status ListCommand::fetchPassthrough(const sp<IServiceManager> &manager) { using namespace ::android::hardware::details; using namespace ::android::hidl::manager::V1_0; using namespace ::android::hidl::base::V1_0; auto ret = timeoutIPC(manager, &IServiceManager::debugDump, [&] (const auto &infos) { // The lambda function may be executed asynchrounously because it is passed to timeoutIPC, // even though the interface function call is synchronous. // However, there's no need to lock because if ret.isOk(), the background thread has // already ended, so it is safe to dereference entries. auto entries = std::make_shared<std::vector<TableEntry>>(); auto ret = timeoutIPC(manager, &IServiceManager::debugDump, [entries](const auto& infos) { for (const auto &info : infos) { if (info.clientPids.size() <= 0) { continue; } putEntry(HalType::PASSTHROUGH_CLIENTS, { .interfaceName = std::string{info.interfaceName.c_str()} + "/" + entries->emplace_back( TableEntry{.interfaceName = std::string{info.interfaceName.c_str()} + "/" + std::string{info.instanceName.c_str()}, .transport = vintf::Transport::PASSTHROUGH, .serverPid = info.clientPids.size() == 1 ? info.clientPids[0] : NO_PID, .serverPid = info.clientPids.size() == 1 ? info.clientPids[0] : NO_PID, .clientPids = info.clientPids, .arch = fromBaseArchitecture(info.arch) }); .arch = fromBaseArchitecture(info.arch)}); } }); if (!ret.isOk()) { Loading @@ -574,6 +587,9 @@ Status ListCommand::fetchPassthrough(const sp<IServiceManager> &manager) { << ret.description() << std::endl; return DUMP_PASSTHROUGH_ERROR; } for (auto&& entry : *entries) { putEntry(HalType::PASSTHROUGH_CLIENTS, std::move(entry)); } return OK; } Loading @@ -583,11 +599,14 @@ Status ListCommand::fetchBinderized(const sp<IServiceManager> &manager) { if (!shouldFetchHalType(HalType::BINDERIZED_SERVICES)) { return OK; } const vintf::Transport mode = vintf::Transport::HWBINDER; hidl_vec<hidl_string> fqInstanceNames; // copying out for timeoutIPC auto listRet = timeoutIPC(manager, &IServiceManager::list, [&] (const auto &names) { fqInstanceNames = names; }); // The lambda function may be executed asynchrounously because it is passed to timeoutIPC, // even though the interface function call is synchronous. // However, there's no need to lock because if listRet.isOk(), the background thread has // already ended, so it is safe to dereference fqInstanceNames. auto fqInstanceNames = std::make_shared<hidl_vec<hidl_string>>(); auto listRet = timeoutIPC(manager, &IServiceManager::list, [fqInstanceNames](const auto& names) { *fqInstanceNames = names; }); if (!listRet.isOk()) { err() << "Error: Failed to list services for " << mode << ": " << listRet.description() << std::endl; Loading @@ -596,7 +615,7 @@ Status ListCommand::fetchBinderized(const sp<IServiceManager> &manager) { Status status = OK; std::map<std::string, TableEntry> allTableEntries; for (const auto &fqInstanceName : fqInstanceNames) { for (const auto& fqInstanceName : *fqInstanceNames) { // create entry and default assign all fields. TableEntry& entry = allTableEntries[fqInstanceName]; entry.interfaceName = fqInstanceName; Loading Loading @@ -637,30 +656,33 @@ Status ListCommand::fetchBinderizedEntry(const sp<IServiceManager> &manager, // getDebugInfo do { DebugInfo debugInfo; auto debugRet = timeoutIPC(service, &IBase::getDebugInfo, [&] (const auto &received) { debugInfo = received; }); // The lambda function may be executed asynchrounously because it is passed to timeoutIPC, // even though the interface function call is synchronous. // However, there's no need to lock because if debugRet.isOk(), the background thread has // already ended, so it is safe to dereference debugInfo. auto debugInfo = std::make_shared<DebugInfo>(); auto debugRet = timeoutIPC(service, &IBase::getDebugInfo, [debugInfo](const auto& received) { *debugInfo = received; }); if (!debugRet.isOk()) { handleError(TRANSACTION_ERROR, "debugging information cannot be retrieved: " + debugRet.description()); break; // skip getPidInfo } entry->serverPid = debugInfo.pid; entry->serverObjectAddress = debugInfo.ptr; entry->arch = fromBaseArchitecture(debugInfo.arch); entry->serverPid = debugInfo->pid; entry->serverObjectAddress = debugInfo->ptr; entry->arch = fromBaseArchitecture(debugInfo->arch); if (debugInfo.pid != NO_PID) { const BinderPidInfo* pidInfo = getPidInfoCached(debugInfo.pid); if (debugInfo->pid != NO_PID) { const BinderPidInfo* pidInfo = getPidInfoCached(debugInfo->pid); if (pidInfo == nullptr) { handleError(IO_ERROR, "no information for PID " + std::to_string(debugInfo.pid) + "no information for PID " + std::to_string(debugInfo->pid) + ", are you root?"); break; } if (debugInfo.ptr != NO_PTR) { auto it = pidInfo->refPids.find(debugInfo.ptr); if (debugInfo->ptr != NO_PTR) { auto it = pidInfo->refPids.find(debugInfo->ptr); if (it != pidInfo->refPids.end()) { entry->clientPids = it->second; } Loading @@ -672,11 +694,14 @@ Status ListCommand::fetchBinderizedEntry(const sp<IServiceManager> &manager, // hash do { ssize_t hashIndex = -1; auto ifaceChainRet = timeoutIPC(service, &IBase::interfaceChain, [&] (const auto& c) { // The lambda function may be executed asynchrounously because it is passed to timeoutIPC, // even though the interface function call is synchronous. auto hashIndexStore = std::make_shared<ssize_t>(-1); auto ifaceChainRet = timeoutIPC(service, &IBase::interfaceChain, [hashIndexStore, serviceName](const auto& c) { for (size_t i = 0; i < c.size(); ++i) { if (serviceName == c[i]) { hashIndex = static_cast<ssize_t>(i); *hashIndexStore = static_cast<ssize_t>(i); break; } } Loading @@ -686,24 +711,28 @@ Status ListCommand::fetchBinderizedEntry(const sp<IServiceManager> &manager, "interfaceChain fails: " + ifaceChainRet.description()); break; // skip getHashChain } // if ifaceChainRet.isOk(), the background thread has already ended, so it is safe to // dereference hashIndex without any locking. auto hashIndex = *hashIndexStore; if (hashIndex < 0) { handleError(BAD_IMPL, "Interface name does not exist in interfaceChain."); break; // skip getHashChain } auto hashRet = timeoutIPC(service, &IBase::getHashChain, [&] (const auto& hashChain) { if (static_cast<size_t>(hashIndex) >= hashChain.size()) { // See comments about hashIndex above. auto hashChain = std::make_shared<hidl_vec<hidl_array<uint8_t, 32>>>(); auto hashRet = timeoutIPC(service, &IBase::getHashChain, [hashChain](const auto& ret) { *hashChain = std::move(ret); }); if (!hashRet.isOk()) { handleError(TRANSACTION_ERROR, "getHashChain failed: " + hashRet.description()); } if (static_cast<size_t>(hashIndex) >= hashChain->size()) { handleError(BAD_IMPL, "interfaceChain indicates position " + std::to_string(hashIndex) + " but getHashChain returns " + std::to_string(hashChain.size()) + " but getHashChain returns " + std::to_string(hashChain->size()) + " hashes"); return; } auto&& hashArray = hashChain[hashIndex]; } else { auto&& hashArray = (*hashChain)[hashIndex]; entry->hash = android::base::HexString(hashArray.data(), hashArray.size()); }); if (!hashRet.isOk()) { handleError(TRANSACTION_ERROR, "getHashChain failed: " + hashRet.description()); } } while (0); if (status == OK) { Loading