OSDN Git Service

lshal: Put more description to output
authorYifan Hong <elsk@google.com>
Fri, 3 Mar 2017 03:19:29 +0000 (19:19 -0800)
committerYifan Hong <elsk@google.com>
Fri, 3 Mar 2017 03:21:15 +0000 (19:21 -0800)
Split the output by three parts according to the source of information.
Describe each part before the table.

--sort will be applied to each table individually.

Bug: 35803917
Test: lshal
Change-Id: Ief0dae21fdeb58ebaed46d2aa68f298b8b75218d

cmds/lshal/Lshal.cpp
cmds/lshal/Lshal.h
cmds/lshal/TableEntry.h

index 2140471..7646feb 100644 (file)
@@ -159,19 +159,32 @@ 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,
@@ -207,72 +220,74 @@ 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) {
-            // 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;
-        }
+            std::string fqInstanceName = entry.interfaceName;
 
-        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);
 }
 
@@ -306,20 +321,36 @@ static Architecture fromBaseArchitecture(::android::hidl::base::V1_0::DebugInfo:
     }
 }
 
-void Lshal::dumpTable() const {
-    mOut << "All services:" << std::endl;
-    mOut << std::left;
-    printLine("Interface", "Transport", "Arch", "Server", "Server CMD", "PTR", "Clients", "Clients CMD");
-    for (const auto &entry : mTable) {
-        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, ";"));
-    }
+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() {
@@ -336,8 +367,21 @@ 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) {
@@ -355,12 +399,11 @@ Status Lshal::fetchAllLibraries(const sp<IServiceManager> &manager) {
                 .serverPid = NO_PID,
                 .serverObjectAddress = NO_PTR,
                 .clientPids = {},
-                .arch = ARCH_UNKNOWN,
-                .source = LIST_DLLIB
+                .arch = ARCH_UNKNOWN
             }).first->second.arch |= fromBaseArchitecture(info.arch);
         }
         for (auto &&pair : entries) {
-            putEntry(std::move(pair.second));
+            putEntry(LIST_DLLIB, std::move(pair.second));
         }
     });
     if (!ret.isOk()) {
@@ -378,7 +421,7 @@ Status Lshal::fetchPassthrough(const sp<IServiceManager> &manager) {
     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()},
@@ -386,8 +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,
-                .arch = fromBaseArchitecture(info.arch),
-                .source = PTSERVICEMANAGER_REG_CLIENT
+                .arch = fromBaseArchitecture(info.arch)
             });
         }
     });
@@ -464,19 +506,18 @@ 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 = {},
-                .arch = ARCH_UNKNOWN,
-                .source = HWSERVICEMANAGER_LIST
+                .arch = ARCH_UNKNOWN
             });
             continue;
         }
         const DebugInfo &info = it->second;
-        putEntry({
+        putEntry(HWSERVICEMANAGER_LIST, {
             .interfaceName = fqInstanceName,
             .transport = mode,
             .serverPid = info.pid,
@@ -484,7 +525,6 @@ Status Lshal::fetchBinderized(const sp<IServiceManager> &manager) {
             .clientPids = info.pid == NO_PID || info.ptr == NO_PTR
                     ? Pids{} : allPids[info.pid][info.ptr],
             .arch = fromBaseArchitecture(info.arch),
-            .source = HWSERVICEMANAGER_LIST
         });
     }
     return status;
@@ -515,7 +555,7 @@ Status Lshal::fetch() {
 void Lshal::usage() const {
     mErr
         << "usage: lshal" << std::endl
-        << "           Dump all hals with default ordering and columns [-itpc]." << 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
@@ -623,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;
 }
index a1bc3b0..c9c6660 100644 (file)
@@ -53,13 +53,13 @@ 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,
@@ -74,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;
index 8154cb2..2407b42 100644 (file)
@@ -51,7 +51,6 @@ 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) {
@@ -62,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 {