diff options
author | Yifan Hong <elsk@google.com> | 2017-02-13 19:32:37 +0000 |
---|---|---|
committer | Gerrit Code Review <noreply-gerritcodereview@google.com> | 2017-02-13 19:32:38 +0000 |
commit | c9bc03729be6aff621f68afd70174076cbafb981 (patch) | |
tree | 53cccd9724585b68855f0a67b6d74c263f7ec22c | |
parent | 270fff6a7c6c80ad24c20be9fbf152fcfdf61758 (diff) | |
parent | b7ddc9e5cba5a0a287993b5b3124a75d67d9557c (diff) | |
download | native-c9bc03729be6aff621f68afd70174076cbafb981.tar.gz |
Merge changes from topic 'lshal'
* changes:
Dump client PIDs for passthrough HALs.
Fix permissions for lshal
-rw-r--r-- | cmds/dumpsys/tests/dumpsys_test.cpp | 2 | ||||
-rw-r--r-- | cmds/lshal/lshal.cpp | 224 |
2 files changed, 178 insertions, 48 deletions
diff --git a/cmds/dumpsys/tests/dumpsys_test.cpp b/cmds/dumpsys/tests/dumpsys_test.cpp index 01a2fa3b22..a596a67403 100644 --- a/cmds/dumpsys/tests/dumpsys_test.cpp +++ b/cmds/dumpsys/tests/dumpsys_test.cpp @@ -79,6 +79,8 @@ class HardwareServiceManagerMock : public HServiceManager { const hidl_string&, const sp<IServiceNotification>&)); MOCK_METHOD1(debugDump, R<void>(debugDump_cb)); + MOCK_METHOD3(registerPassthroughClient, R<void>( + const hidl_string&, const hidl_string&, int32_t)); }; diff --git a/cmds/lshal/lshal.cpp b/cmds/lshal/lshal.cpp index bc5eaf24c5..9998a462a3 100644 --- a/cmds/lshal/lshal.cpp +++ b/cmds/lshal/lshal.cpp @@ -28,31 +28,60 @@ #include <android/hidl/manager/1.0/IServiceManager.h> #include <hidl/ServiceManagement.h> -template <typename A, typename B, typename C, typename D, typename E> +using ::android::sp; +using ::android::hardware::hidl_string; +using ::android::hidl::manager::V1_0::IServiceManager; + +template <typename A, typename B, typename C, typename D, typename E, typename F> void printColumn(std::stringstream &stream, - const A &a, const B &b, const C &c, const D &d, const E &e) { + const A &a, const B &b, const C &c, const D &d, const E &, const F &f) { using namespace ::std; stream << left << setw(70) << a << "\t" << setw(20) << b << "\t" << setw(10) << c << "\t" << setw(5) << d << "\t" - << setw(0) << e + // TODO(b/34984175): enable selecting columns + // << setw(16) << e << "\t" + << setw(0) << f << endl; } +template <typename A> +std::string join(const A &components, const std::string &separator) { + std::stringstream out; + bool first = true; + for (const auto &component : components) { + if (!first) { + out << separator; + } + out << component; + + first = false; + } + return out.str(); +} + std::string toHexString(uint64_t t) { std::ostringstream os; os << std::hex << std::setfill('0') << std::setw(16) << t; return os.str(); } -::android::status_t getReferencedPids( +std::pair<hidl_string, hidl_string> split(const hidl_string &s, char c) { + const char *pos = strchr(s.c_str(), c); + if (pos == nullptr) { + return {s, {}}; + } + return {hidl_string(s.c_str(), pos - s.c_str()), hidl_string(pos + 1)}; +} + +bool getReferencedPids( pid_t serverPid, std::map<uint64_t, std::string> *objects) { std::ifstream ifs("/d/binder/proc/" + std::to_string(serverPid)); if (!ifs.is_open()) { - return ::android::PERMISSION_DENIED; + return false; } static const std::regex prefix("^\\s*node \\d+:\\s+u([0-9a-f]+)\\s+c([0-9a-f]+)\\s+"); @@ -77,66 +106,165 @@ std::string toHexString(uint64_t t) { (*objects)[ptr] += line.substr(pos + proc.size()); } } - return ::android::OK; + return true; } - -int dump() { +void dumpAllLibraries(std::stringstream &stream, const std::string &mode, + const sp<IServiceManager> &manager) { using namespace ::std; using namespace ::android::hardware; using namespace ::android::hidl::manager::V1_0; + using namespace ::android::hidl::base::V1_0; + auto ret = manager->list([&] (const auto &fqInstanceNames) { + for (const auto &fqInstanceName : fqInstanceNames) { + const auto pair = split(fqInstanceName, '/'); + const auto &serviceName = pair.first; + const auto &instanceName = pair.second; + printColumn(stream, + serviceName, + instanceName, + mode, + "N/A", + "N/A", + "N/A"); + } + }); + if (!ret.isOk()) { + cerr << "Error: Failed to call debugDump on defaultServiceManager(): " + << ret.description() << endl; + } +} - std::map<std::string, ::android::sp<IServiceManager>> mapping = { - {"hwbinder", defaultServiceManager()}, - {"passthrough", getPassthroughServiceManager()} - }; - - std::stringstream stream; - - stream << "All services:" << endl; - stream << left; - printColumn(stream, "Interface", "Instance", "Transport", "Server", "Clients"); - - for (const auto &pair : mapping) { - const std::string &mode = pair.first; - const ::android::sp<IServiceManager> &manager = pair.second; +void dumpPassthrough(std::stringstream &stream, const std::string &mode, + const sp<IServiceManager> &manager) { + using namespace ::std; + using namespace ::android::hardware; + using namespace ::android::hidl::manager::V1_0; + using namespace ::android::hidl::base::V1_0; + auto ret = manager->debugDump([&] (const auto &infos) { + for (const auto &info : infos) { - if (manager == nullptr) { - cerr << "Failed to get IServiceManager for " << mode << "!" << endl; - continue; + printColumn(stream, + info.interfaceName, + info.instanceName, + mode, + info.clientPids.size() == 1 ? std::to_string(info.clientPids[0]) : "N/A", + "N/A", + join(info.clientPids, " ")); } + }); + if (!ret.isOk()) { + cerr << "Error: Failed to call debugDump on defaultServiceManager(): " + << ret.description() << endl; + } +} - auto ret = manager->debugDump([&](const auto ®istered) { - // server pid, .ptr value of binder object, child pids - std::map<pid_t, std::map<uint64_t, std::string>> allPids; - for (const auto &info : registered) { - if (info.pid < 0) { - continue; - } - pid_t serverPid = info.pid; - allPids[serverPid].clear(); +void dumpBinderized(std::stringstream &stream, const std::string &mode, + const sp<IServiceManager> &manager) { + using namespace ::std; + using namespace ::android::hardware; + using namespace ::android::hidl::manager::V1_0; + using namespace ::android::hidl::base::V1_0; + auto listRet = manager->list([&] (const auto &fqInstanceNames) { + // server pid, .ptr value of binder object, child pids + std::map<std::string, DebugInfo> allDebugInfos; + std::map<pid_t, std::map<uint64_t, std::string>> allPids; + for (const auto &fqInstanceName : fqInstanceNames) { + const auto pair = split(fqInstanceName, '/'); + const auto &serviceName = pair.first; + const auto &instanceName = pair.second; + auto getRet = manager->get(serviceName, instanceName); + if (!getRet.isOk()) { + cerr << "Warning: Skipping \"" << fqInstanceName << "\": " + << "cannot be fetched from service manager:" + << getRet.description() << endl; + continue; + } + sp<IBase> service = getRet; + if (service == nullptr) { + cerr << "Warning: Skipping \"" << fqInstanceName << "\": " + << "cannot be fetched from service manager (null)"; + continue; } - for (auto &pair : allPids) { - pid_t serverPid = pair.first; - if (getReferencedPids(serverPid, &allPids[serverPid]) != ::android::OK) { - std::cerr << "Warning: no information for PID " << serverPid - << ", are you root?" << std::endl; + auto debugRet = service->getDebugInfo([&] (const auto &debugInfo) { + allDebugInfos[fqInstanceName] = debugInfo; + if (debugInfo.pid >= 0) { + allPids[static_cast<pid_t>(debugInfo.pid)].clear(); } + }); + if (!debugRet.isOk()) { + cerr << "Warning: Skipping \"" << fqInstanceName << "\": " + << "debugging information cannot be retrieved:" + << debugRet.description() << endl; } - for (const auto &info : registered) { + } + for (auto &pair : allPids) { + pid_t serverPid = pair.first; + if (!getReferencedPids(serverPid, &allPids[serverPid])) { + std::cerr << "Warning: no information for PID " << serverPid + << ", are you root?" << std::endl; + } + } + for (const auto &fqInstanceName : fqInstanceNames) { + const auto pair = split(fqInstanceName, '/'); + const auto &serviceName = pair.first; + const auto &instanceName = pair.second; + auto it = allDebugInfos.find(fqInstanceName); + if (it == allDebugInfos.end()) { printColumn(stream, - info.interfaceName, - info.instanceName.empty() ? "N/A" : info.instanceName, + serviceName, + instanceName, mode, - info.pid < 0 ? "N/A" : std::to_string(info.pid), - info.pid < 0 || info.ptr == 0 ? "" : allPids[info.pid][info.ptr]); + "N/A", + "N/A", + "" + ); + continue; } - }); - if (!ret.isOk()) { - cerr << "Failed to list services for " << mode << ": " - << ret.description() << endl; + const DebugInfo &info = it->second; + printColumn(stream, + serviceName, + instanceName, + mode, + info.pid < 0 ? "N/A" : std::to_string(info.pid), + info.ptr == 0 ? "N/A" : toHexString(info.ptr), + info.pid < 0 || info.ptr == 0 ? "" : allPids[info.pid][info.ptr] + ); } + + }); + if (!listRet.isOk()) { + cerr << "Error: Failed to list services for " << mode << ": " + << listRet.description() << endl; } +} + +int dump() { + using namespace ::std; + using namespace ::android::hardware; + + std::stringstream stream; + + stream << "All services:" << endl; + stream << left; + printColumn(stream, "Interface", "Instance", "Transport", "Server", "PTR", "Clients"); + + auto bManager = defaultServiceManager(); + if (bManager == nullptr) { + cerr << "Failed to get defaultServiceManager()!" << endl; + } else { + dumpBinderized(stream, "hwbinder", bManager); + // Passthrough PIDs are registered to the binderized manager as well. + dumpPassthrough(stream, "passthrough", bManager); + } + + auto pManager = getPassthroughServiceManager(); + if (pManager == nullptr) { + cerr << "Failed to get getPassthroughServiceManager()!" << endl; + } else { + dumpAllLibraries(stream, "passthrough", pManager); + } + cout << stream.rdbuf(); return 0; } |