diff options
| author | 2017-03-03 17:49:54 +0000 | |
|---|---|---|
| committer | 2017-03-03 17:49:54 +0000 | |
| commit | 2eaf6b8eaeae9df0f54fda968a242b04197c461a (patch) | |
| tree | 0f6601330d84f5c1d792f9eb467c3f009dd0688b | |
| parent | ad79651822dc32b8ac1a76bd5259c9eca917b07f (diff) | |
| parent | a3b8709a5dfc57d6d6bcc0ee89bbeb4aed3e908c (diff) | |
Merge changes from topic 'lshal_32'
* changes:
lshal: Put more description to output
lshal: also list libraries in 32-bit.
| -rw-r--r-- | cmds/lshal/Lshal.cpp | 291 | ||||
| -rw-r--r-- | cmds/lshal/Lshal.h | 15 | ||||
| -rw-r--r-- | cmds/lshal/TableEntry.h | 25 |
3 files changed, 224 insertions, 107 deletions
diff --git a/cmds/lshal/Lshal.cpp b/cmds/lshal/Lshal.cpp index e953dedea2..7646febd51 100644 --- a/cmds/lshal/Lshal.cpp +++ b/cmds/lshal/Lshal.cpp @@ -159,22 +159,37 @@ bool Lshal::getReferencedPids( return true; } -void Lshal::postprocess() { - if (mSortColumn) { - std::sort(mTable.begin(), mTable.end(), mSortColumn); +void Lshal::forEachTable(const std::function<void(Table &)> &f) { + for (const Table &table : {mServicesTable, mPassthroughRefTable, mImplementationsTable}) { + f(const_cast<Table &>(table)); } - for (TableEntry &entry : mTable) { - entry.serverCmdline = getCmdline(entry.serverPid); - removeDeadProcesses(&entry.clientPids); - for (auto pid : entry.clientPids) { - entry.clientCmdlines.push_back(this->getCmdline(pid)); - } +} +void Lshal::forEachTable(const std::function<void(const Table &)> &f) const { + for (const Table &table : {mServicesTable, mPassthroughRefTable, mImplementationsTable}) { + f(table); } } +void Lshal::postprocess() { + forEachTable([this](Table &table) { + if (mSortColumn) { + std::sort(table.begin(), table.end(), mSortColumn); + } + for (TableEntry &entry : table) { + entry.serverCmdline = getCmdline(entry.serverPid); + removeDeadProcesses(&entry.clientPids); + for (auto pid : entry.clientPids) { + entry.clientCmdlines.push_back(this->getCmdline(pid)); + } + } + }); +} + void Lshal::printLine( const std::string &interfaceName, - const std::string &transport, const std::string &server, + const std::string &transport, + const std::string &arch, + const std::string &server, const std::string &serverCmdline, const std::string &address, const std::string &clients, const std::string &clientCmdlines) const { @@ -182,6 +197,8 @@ void Lshal::printLine( mOut << std::setw(80) << interfaceName << "\t"; if (mSelectedColumns & ENABLE_TRANSPORT) mOut << std::setw(10) << transport << "\t"; + if (mSelectedColumns & ENABLE_ARCH) + mOut << std::setw(5) << arch << "\t"; if (mSelectedColumns & ENABLE_SERVER_PID) { if (mEnableCmdlines) { mOut << std::setw(15) << serverCmdline << "\t"; @@ -203,90 +220,139 @@ void Lshal::printLine( void Lshal::dumpVintf() const { vintf::HalManifest manifest; - for (const TableEntry &entry : mTable) { + forEachTable([this, &manifest] (const Table &table) { + for (const TableEntry &entry : table) { - std::string fqInstanceName = entry.interfaceName; + std::string fqInstanceName = entry.interfaceName; - if (entry.source == LIST_DLLIB) { - // Quick hack to work around *'s - replaceAll(&fqInstanceName, '*', 'D'); - } - auto splittedFqInstanceName = splitFirst(fqInstanceName, '/'); - FQName fqName(splittedFqInstanceName.first); - if (!fqName.isValid()) { - mErr << "Warning: '" << splittedFqInstanceName.first - << "' is not a valid FQName." << std::endl; - continue; - } - // Strip out system libs. - // TODO(b/34772739): might want to add other framework HAL packages - if (fqName.inPackage("android.hidl")) { - continue; - } - std::string interfaceName = - entry.source == LIST_DLLIB ? "" : fqName.name(); - std::string instanceName = - entry.source == LIST_DLLIB ? "" : splittedFqInstanceName.second; - - vintf::Transport transport; - if (entry.transport == "hwbinder") { - transport = vintf::Transport::HWBINDER; - } else if (entry.transport == "passthrough") { - transport = vintf::Transport::PASSTHROUGH; - } else { - mErr << "Warning: '" << entry.transport << "' is not a valid transport." << std::endl; - continue; - } - - vintf::ManifestHal *hal = manifest.getHal(fqName.package()); - if (hal == nullptr) { - if (!manifest.add(vintf::ManifestHal{ - .format = vintf::HalFormat::HIDL, - .name = fqName.package(), - .impl = {.implLevel = vintf::ImplLevel::GENERIC, .impl = ""}, - .transport = transport - })) { - mErr << "Warning: cannot add hal '" << fqInstanceName << "'" << std::endl; + if (&table == &mImplementationsTable) { + // Quick hack to work around *'s + replaceAll(&fqInstanceName, '*', 'D'); + } + auto splittedFqInstanceName = splitFirst(fqInstanceName, '/'); + FQName fqName(splittedFqInstanceName.first); + if (!fqName.isValid()) { + mErr << "Warning: '" << splittedFqInstanceName.first + << "' is not a valid FQName." << std::endl; continue; } - hal = manifest.getHal(fqName.package()); - } - if (hal == nullptr) { - mErr << "Warning: cannot get hal '" << fqInstanceName - << "' after adding it" << std::endl; - continue; - } - vintf::Version version{fqName.getPackageMajorVersion(), fqName.getPackageMinorVersion()}; - if (std::find(hal->versions.begin(), hal->versions.end(), version) == hal->versions.end()) { - hal->versions.push_back(version); - } - if (entry.source != LIST_DLLIB) { - auto it = hal->interfaces.find(interfaceName); - if (it == hal->interfaces.end()) { - hal->interfaces.insert({interfaceName, {interfaceName, {{instanceName}}}}); + // Strip out system libs. + // TODO(b/34772739): might want to add other framework HAL packages + if (fqName.inPackage("android.hidl")) { + continue; + } + std::string interfaceName = + &table == &mImplementationsTable ? "" : fqName.name(); + std::string instanceName = + &table == &mImplementationsTable ? "" : splittedFqInstanceName.second; + + vintf::Transport transport; + if (entry.transport == "hwbinder") { + transport = vintf::Transport::HWBINDER; + } else if (entry.transport == "passthrough") { + transport = vintf::Transport::PASSTHROUGH; } else { - it->second.instances.insert(instanceName); + mErr << "Warning: '" << entry.transport << "' is not a valid transport." << std::endl; + continue; + } + + vintf::ManifestHal *hal = manifest.getHal(fqName.package()); + if (hal == nullptr) { + if (!manifest.add(vintf::ManifestHal{ + .format = vintf::HalFormat::HIDL, + .name = fqName.package(), + .impl = {.implLevel = vintf::ImplLevel::GENERIC, .impl = ""}, + .transport = transport + })) { + mErr << "Warning: cannot add hal '" << fqInstanceName << "'" << std::endl; + continue; + } + hal = manifest.getHal(fqName.package()); + } + if (hal == nullptr) { + mErr << "Warning: cannot get hal '" << fqInstanceName + << "' after adding it" << std::endl; + continue; + } + vintf::Version version{fqName.getPackageMajorVersion(), fqName.getPackageMinorVersion()}; + if (std::find(hal->versions.begin(), hal->versions.end(), version) == hal->versions.end()) { + hal->versions.push_back(version); + } + if (&table != &mImplementationsTable) { + auto it = hal->interfaces.find(interfaceName); + if (it == hal->interfaces.end()) { + hal->interfaces.insert({interfaceName, {interfaceName, {{instanceName}}}}); + } else { + it->second.instances.insert(instanceName); + } } } - } + }); mOut << vintf::gHalManifestConverter(manifest); } -void Lshal::dumpTable() const { - mOut << "All services:" << std::endl; - mOut << std::left; - printLine("Interface", "Transport", "Server", "Server CMD", "PTR", "Clients", "Clients CMD"); - for (const auto &entry : mTable) { - printLine(entry.interfaceName, - entry.transport, - entry.serverPid == NO_PID ? "N/A" : std::to_string(entry.serverPid), - entry.serverCmdline, - entry.serverObjectAddress == NO_PTR ? "N/A" : toHexString(entry.serverObjectAddress), - join(entry.clientPids, " "), - join(entry.clientCmdlines, ";")); +static const std::string &getArchString(Architecture arch) { + static const std::string sStr64 = "64"; + static const std::string sStr32 = "32"; + static const std::string sStrBoth = "64&32"; + static const std::string sStrUnknown = ""; + switch (arch) { + case ARCH64: + return sStr64; + case ARCH32: + return sStr32; + case ARCH_BOTH: + return sStrBoth; + case ARCH_UNKNOWN: // fall through + default: + return sStrUnknown; + } +} + +static Architecture fromBaseArchitecture(::android::hidl::base::V1_0::DebugInfo::Architecture a) { + switch (a) { + case ::android::hidl::base::V1_0::DebugInfo::Architecture::IS_64BIT: + return ARCH64; + case ::android::hidl::base::V1_0::DebugInfo::Architecture::IS_32BIT: + return ARCH32; + case ::android::hidl::base::V1_0::DebugInfo::Architecture::UNKNOWN: // fallthrough + default: + return ARCH_UNKNOWN; } } +void Lshal::dumpTable() { + mServicesTable.description = + "All binderized services (registered services through hwservicemanager)"; + mPassthroughRefTable.description = + "All interfaces that getService() has ever return a passthrough interface;\n" + "PIDs / processes shown below might be inaccurate because the process\n" + "might have relinquish the interface or might have died.\n" + "The Server / Server CMD column can be ignored.\n" + "The Clients / Clients CMD column shows all process that have ever dlopen the library\n" + "and successfully fetch the passthrough implementation."; + mImplementationsTable.description = + "All available passthrough implementations (all -impl.so files)"; + forEachTable([this] (const Table &table) { + mOut << table.description << std::endl; + mOut << std::left; + printLine("Interface", "Transport", "Arch", "Server", "Server CMD", + "PTR", "Clients", "Clients CMD"); + for (const auto &entry : table) { + printLine(entry.interfaceName, + entry.transport, + getArchString(entry.arch), + entry.serverPid == NO_PID ? "N/A" : std::to_string(entry.serverPid), + entry.serverCmdline, + entry.serverObjectAddress == NO_PTR ? "N/A" : toHexString(entry.serverObjectAddress), + join(entry.clientPids, " "), + join(entry.clientCmdlines, ";")); + } + mOut << std::endl; + }); + +} + void Lshal::dump() { if (mVintf) { dumpVintf(); @@ -301,24 +367,43 @@ void Lshal::dump() { } } -void Lshal::putEntry(TableEntry &&entry) { - mTable.push_back(std::forward<TableEntry>(entry)); +void Lshal::putEntry(TableEntrySource source, TableEntry &&entry) { + Table *table = nullptr; + switch (source) { + case HWSERVICEMANAGER_LIST : + table = &mServicesTable; break; + case PTSERVICEMANAGER_REG_CLIENT : + table = &mPassthroughRefTable; break; + case LIST_DLLIB : + table = &mImplementationsTable; break; + default: + mErr << "Error: Unknown source of entry " << source << std::endl; + } + if (table) { + table->entries.push_back(std::forward<TableEntry>(entry)); + } } Status Lshal::fetchAllLibraries(const sp<IServiceManager> &manager) { using namespace ::android::hardware; using namespace ::android::hidl::manager::V1_0; using namespace ::android::hidl::base::V1_0; - auto ret = timeoutIPC(manager, &IServiceManager::list, [&] (const auto &fqInstanceNames) { - for (const auto &fqInstanceName : fqInstanceNames) { - putEntry({ - .interfaceName = fqInstanceName, + auto ret = timeoutIPC(manager, &IServiceManager::debugDump, [&] (const auto &infos) { + std::map<std::string, TableEntry> entries; + for (const auto &info : infos) { + std::string interfaceName = std::string{info.interfaceName.c_str()} + "/" + + std::string{info.instanceName.c_str()}; + entries.emplace(std::string{interfaceName}, TableEntry{ + .interfaceName = interfaceName, .transport = "passthrough", .serverPid = NO_PID, .serverObjectAddress = NO_PTR, .clientPids = {}, - .source = LIST_DLLIB - }); + .arch = ARCH_UNKNOWN + }).first->second.arch |= fromBaseArchitecture(info.arch); + } + for (auto &&pair : entries) { + putEntry(LIST_DLLIB, std::move(pair.second)); } }); if (!ret.isOk()) { @@ -331,11 +416,12 @@ Status Lshal::fetchAllLibraries(const sp<IServiceManager> &manager) { Status Lshal::fetchPassthrough(const sp<IServiceManager> &manager) { using namespace ::android::hardware; + 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) { for (const auto &info : infos) { - putEntry({ + putEntry(PTSERVICEMANAGER_REG_CLIENT, { .interfaceName = std::string{info.interfaceName.c_str()} + "/" + std::string{info.instanceName.c_str()}, @@ -343,7 +429,7 @@ Status Lshal::fetchPassthrough(const sp<IServiceManager> &manager) { .serverPid = info.clientPids.size() == 1 ? info.clientPids[0] : NO_PID, .serverObjectAddress = NO_PTR, .clientPids = info.clientPids, - .source = PTSERVICEMANAGER_REG_CLIENT + .arch = fromBaseArchitecture(info.arch) }); } }); @@ -420,25 +506,25 @@ Status Lshal::fetchBinderized(const sp<IServiceManager> &manager) { for (const auto &fqInstanceName : fqInstanceNames) { auto it = allDebugInfos.find(fqInstanceName); if (it == allDebugInfos.end()) { - putEntry({ + putEntry(HWSERVICEMANAGER_LIST, { .interfaceName = fqInstanceName, .transport = mode, .serverPid = NO_PID, .serverObjectAddress = NO_PTR, .clientPids = {}, - .source = HWSERVICEMANAGER_LIST + .arch = ARCH_UNKNOWN }); continue; } const DebugInfo &info = it->second; - putEntry({ + putEntry(HWSERVICEMANAGER_LIST, { .interfaceName = fqInstanceName, .transport = mode, .serverPid = info.pid, .serverObjectAddress = info.ptr, .clientPids = info.pid == NO_PID || info.ptr == NO_PTR ? Pids{} : allPids[info.pid][info.ptr], - .source = HWSERVICEMANAGER_LIST + .arch = fromBaseArchitecture(info.arch), }); } return status; @@ -469,13 +555,14 @@ Status Lshal::fetch() { void Lshal::usage() const { mErr << "usage: lshal" << std::endl - << " Dump all hals with default ordering and columns [-itpc]." << std::endl - << " lshal [--interface|-i] [--transport|-t]" << std::endl + << " Dump all hals with default ordering and columns [-ipc]." << std::endl + << " lshal [--interface|-i] [--transport|-t] [-r|--arch]" << std::endl << " [--pid|-p] [--address|-a] [--clients|-c] [--cmdline|-m]" << std::endl << " [--sort={interface|i|pid|p}] [--init-vintf[=path]]" << std::endl << " -i, --interface: print the interface name column" << std::endl << " -n, --instance: print the instance name column" << std::endl << " -t, --transport: print the transport mode column" << std::endl + << " -r, --arch: print if the HAL is in 64-bit or 32-bit" << std::endl << " -p, --pid: print the server PID, or server cmdline if -m is set" << std::endl << " -a, --address: print the server object address column" << std::endl << " -c, --clients: print the client PIDs, or client cmdlines if -m is set" @@ -495,6 +582,7 @@ Status Lshal::parseArgs(int argc, char **argv) { {"help", no_argument, 0, 'h' }, {"interface", no_argument, 0, 'i' }, {"transport", no_argument, 0, 't' }, + {"arch", no_argument, 0, 'r' }, {"pid", no_argument, 0, 'p' }, {"address", no_argument, 0, 'a' }, {"clients", no_argument, 0, 'c' }, @@ -511,7 +599,7 @@ Status Lshal::parseArgs(int argc, char **argv) { optind = 1; for (;;) { // using getopt_long in case we want to add other options in the future - c = getopt_long(argc, argv, "hitpacm", longOptions, &optionIndex); + c = getopt_long(argc, argv, "hitrpacm", longOptions, &optionIndex); if (c == -1) { break; } @@ -547,6 +635,10 @@ Status Lshal::parseArgs(int argc, char **argv) { mSelectedColumns |= ENABLE_TRANSPORT; break; } + case 'r': { + mSelectedColumns |= ENABLE_ARCH; + break; + } case 'p': { mSelectedColumns |= ENABLE_SERVER_PID; break; @@ -571,8 +663,7 @@ Status Lshal::parseArgs(int argc, char **argv) { } if (mSelectedColumns == 0) { - mSelectedColumns = ENABLE_INTERFACE_NAME - | ENABLE_TRANSPORT | ENABLE_SERVER_PID | ENABLE_CLIENT_PIDS; + mSelectedColumns = ENABLE_INTERFACE_NAME | ENABLE_SERVER_PID | ENABLE_CLIENT_PIDS; } return OK; } diff --git a/cmds/lshal/Lshal.h b/cmds/lshal/Lshal.h index 1c30908189..c9c66605f9 100644 --- a/cmds/lshal/Lshal.h +++ b/cmds/lshal/Lshal.h @@ -53,17 +53,19 @@ private: void postprocess(); void dump(); void usage() const; - void putEntry(TableEntry &&entry); + void putEntry(TableEntrySource source, TableEntry &&entry); Status fetchPassthrough(const sp<::android::hidl::manager::V1_0::IServiceManager> &manager); Status fetchBinderized(const sp<::android::hidl::manager::V1_0::IServiceManager> &manager); Status fetchAllLibraries(const sp<::android::hidl::manager::V1_0::IServiceManager> &manager); bool getReferencedPids( pid_t serverPid, std::map<uint64_t, Pids> *objects) const; - void dumpTable() const; + void dumpTable(); void dumpVintf() const; void printLine( const std::string &interfaceName, - const std::string &transport, const std::string &server, + const std::string &transport, + const std::string &arch, + const std::string &server, const std::string &serverCmdline, const std::string &address, const std::string &clients, const std::string &clientCmdlines) const ; @@ -72,8 +74,13 @@ private: // Call getCmdline on all pid in pids. If it returns empty string, the process might // have died, and the pid is removed from pids. void removeDeadProcesses(Pids *pids); + void forEachTable(const std::function<void(Table &)> &f); + void forEachTable(const std::function<void(const Table &)> &f) const; + + Table mServicesTable{}; + Table mPassthroughRefTable{}; + Table mImplementationsTable{}; - Table mTable{}; NullableOStream<std::ostream> mErr = std::cerr; NullableOStream<std::ostream> mOut = std::cout; NullableOStream<std::ofstream> mFileOutput = nullptr; diff --git a/cmds/lshal/TableEntry.h b/cmds/lshal/TableEntry.h index e55806e2b6..2407b42cdf 100644 --- a/cmds/lshal/TableEntry.h +++ b/cmds/lshal/TableEntry.h @@ -35,6 +35,14 @@ enum : unsigned int { }; using TableEntrySource = unsigned int; +enum : unsigned int { + ARCH_UNKNOWN = 0, + ARCH64 = 1 << 0, + ARCH32 = 1 << 1, + ARCH_BOTH = ARCH32 | ARCH64 +}; +using Architecture = unsigned int; + struct TableEntry { std::string interfaceName; std::string transport; @@ -43,7 +51,7 @@ struct TableEntry { uint64_t serverObjectAddress; Pids clientPids; std::vector<std::string> clientCmdlines; - TableEntrySource source; + Architecture arch; static bool sortByInterfaceName(const TableEntry &a, const TableEntry &b) { return a.interfaceName < b.interfaceName; @@ -53,7 +61,17 @@ struct TableEntry { }; }; -using Table = std::vector<TableEntry>; +struct Table { + using Entries = std::vector<TableEntry>; + std::string description; + Entries entries; + + Entries::iterator begin() { return entries.begin(); } + Entries::const_iterator begin() const { return entries.begin(); } + Entries::iterator end() { return entries.end(); } + Entries::const_iterator end() const { return entries.end(); } +}; + using TableEntryCompare = std::function<bool(const TableEntry &, const TableEntry &)>; enum : unsigned int { @@ -61,7 +79,8 @@ enum : unsigned int { ENABLE_TRANSPORT = 1 << 1, ENABLE_SERVER_PID = 1 << 2, ENABLE_SERVER_ADDR = 1 << 3, - ENABLE_CLIENT_PIDS = 1 << 4 + ENABLE_CLIENT_PIDS = 1 << 4, + ENABLE_ARCH = 1 << 5 }; using TableEntrySelect = unsigned int; |