Loading cmds/lshal/Lshal.cpp +191 −100 Original line number Diff line number Diff line Loading @@ -159,22 +159,37 @@ bool Lshal::getReferencedPids( return true; } void Lshal::forEachTable(const std::function<void(Table &)> &f) { for (const Table &table : {mServicesTable, mPassthroughRefTable, mImplementationsTable}) { f(const_cast<Table &>(table)); } } 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(mTable.begin(), mTable.end(), mSortColumn); std::sort(table.begin(), table.end(), mSortColumn); } for (TableEntry &entry : mTable) { 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 { Loading @@ -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"; Loading @@ -203,11 +220,12 @@ 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; if (entry.source == LIST_DLLIB) { if (&table == &mImplementationsTable) { // Quick hack to work around *'s replaceAll(&fqInstanceName, '*', 'D'); } Loading @@ -224,9 +242,9 @@ void Lshal::dumpVintf() const { continue; } std::string interfaceName = entry.source == LIST_DLLIB ? "" : fqName.name(); &table == &mImplementationsTable ? "" : fqName.name(); std::string instanceName = entry.source == LIST_DLLIB ? "" : splittedFqInstanceName.second; &table == &mImplementationsTable ? "" : splittedFqInstanceName.second; vintf::Transport transport; if (entry.transport == "hwbinder") { Loading Loading @@ -260,7 +278,7 @@ void Lshal::dumpVintf() const { if (std::find(hal->versions.begin(), hal->versions.end(), version) == hal->versions.end()) { hal->versions.push_back(version); } if (entry.source != LIST_DLLIB) { if (&table != &mImplementationsTable) { auto it = hal->interfaces.find(interfaceName); if (it == hal->interfaces.end()) { hal->interfaces.insert({interfaceName, {interfaceName, {{instanceName}}}}); Loading @@ -269,22 +287,70 @@ void Lshal::dumpVintf() const { } } } }); mOut << vintf::gHalManifestConverter(manifest); } void Lshal::dumpTable() const { mOut << "All services:" << std::endl; 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", "Server", "Server CMD", "PTR", "Clients", "Clients CMD"); for (const auto &entry : mTable) { 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() { Loading @@ -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()) { Loading @@ -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()}, Loading @@ -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) }); } }); Loading Loading @@ -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; Loading Loading @@ -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" Loading @@ -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' }, Loading @@ -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; } Loading Loading @@ -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; Loading @@ -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; } Loading cmds/lshal/Lshal.h +11 −4 Original line number Diff line number Diff line Loading @@ -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 ; Loading @@ -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; Loading cmds/lshal/TableEntry.h +22 −3 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading @@ -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 { Loading @@ -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; Loading Loading
cmds/lshal/Lshal.cpp +191 −100 Original line number Diff line number Diff line Loading @@ -159,22 +159,37 @@ bool Lshal::getReferencedPids( return true; } void Lshal::forEachTable(const std::function<void(Table &)> &f) { for (const Table &table : {mServicesTable, mPassthroughRefTable, mImplementationsTable}) { f(const_cast<Table &>(table)); } } 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(mTable.begin(), mTable.end(), mSortColumn); std::sort(table.begin(), table.end(), mSortColumn); } for (TableEntry &entry : mTable) { 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 { Loading @@ -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"; Loading @@ -203,11 +220,12 @@ 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; if (entry.source == LIST_DLLIB) { if (&table == &mImplementationsTable) { // Quick hack to work around *'s replaceAll(&fqInstanceName, '*', 'D'); } Loading @@ -224,9 +242,9 @@ void Lshal::dumpVintf() const { continue; } std::string interfaceName = entry.source == LIST_DLLIB ? "" : fqName.name(); &table == &mImplementationsTable ? "" : fqName.name(); std::string instanceName = entry.source == LIST_DLLIB ? "" : splittedFqInstanceName.second; &table == &mImplementationsTable ? "" : splittedFqInstanceName.second; vintf::Transport transport; if (entry.transport == "hwbinder") { Loading Loading @@ -260,7 +278,7 @@ void Lshal::dumpVintf() const { if (std::find(hal->versions.begin(), hal->versions.end(), version) == hal->versions.end()) { hal->versions.push_back(version); } if (entry.source != LIST_DLLIB) { if (&table != &mImplementationsTable) { auto it = hal->interfaces.find(interfaceName); if (it == hal->interfaces.end()) { hal->interfaces.insert({interfaceName, {interfaceName, {{instanceName}}}}); Loading @@ -269,22 +287,70 @@ void Lshal::dumpVintf() const { } } } }); mOut << vintf::gHalManifestConverter(manifest); } void Lshal::dumpTable() const { mOut << "All services:" << std::endl; 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", "Server", "Server CMD", "PTR", "Clients", "Clients CMD"); for (const auto &entry : mTable) { 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() { Loading @@ -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()) { Loading @@ -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()}, Loading @@ -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) }); } }); Loading Loading @@ -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; Loading Loading @@ -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" Loading @@ -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' }, Loading @@ -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; } Loading Loading @@ -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; Loading @@ -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; } Loading
cmds/lshal/Lshal.h +11 −4 Original line number Diff line number Diff line Loading @@ -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 ; Loading @@ -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; Loading
cmds/lshal/TableEntry.h +22 −3 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading @@ -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 { Loading @@ -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; Loading