OSDN Git Service

lshal: Allow selecting columns and sorting by column.
authorYifan Hong <elsk@google.com>
Tue, 14 Feb 2017 01:51:59 +0000 (17:51 -0800)
committerYifan Hong <elsk@google.com>
Wed, 15 Feb 2017 03:25:27 +0000 (19:25 -0800)
Examples: see tests below.

Test: lshal
Test: lshal -intpac
Test: lshal --sort=i
Test: lshal --sort=p

Bug: 34984175

Change-Id: Ia09823776a206868a5d58a2ede153a4538147756

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

index e6d10bf..d213fd3 100644 (file)
@@ -35,20 +35,6 @@ using ::android::hidl::manager::V1_0::IServiceManager;
 namespace android {
 namespace lshal {
 
-template <typename A, typename C, typename D, typename E, typename F>
-void printColumn(std::ostream &stream,
-        const A &a, const C &c, const D &d, const E &, const F &f) {
-    using namespace ::std;
-    stream << left
-           << setw(80) << a << "\t"
-           << setw(10) << c << "\t"
-           << setw(5)  << d << "\t"
-           // 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;
@@ -133,11 +119,35 @@ bool Lshal::getReferencedPids(
     return true;
 }
 
+void Lshal::postprocess() {
+    if (mSortColumn) {
+        std::sort(mTable.begin(), mTable.end(), mSortColumn);
+    }
+}
+
+void Lshal::printLine(
+        const std::string &interfaceName,
+        const std::string &transport, const std::string &server,
+        const std::string &address, const std::string &clients) const {
+    if (mSelectedColumns & ENABLE_INTERFACE_NAME)
+        mOut << std::setw(80) << interfaceName << "\t";
+    if (mSelectedColumns & ENABLE_TRANSPORT)
+        mOut << std::setw(10) << transport << "\t";
+    if (mSelectedColumns & ENABLE_SERVER_PID)
+        mOut << std::setw(5)  << server << "\t";
+    if (mSelectedColumns & ENABLE_SERVER_ADDR)
+        mOut << std::setw(16) << address << "\t";
+    if (mSelectedColumns & ENABLE_CLIENT_PIDS)
+        mOut << std::setw(0)  << clients;
+    mOut << std::endl;
+}
+
 void Lshal::dump() const {
     mOut << "All services:" << std::endl;
-    printColumn(mOut, "Interface", "Transport", "Server", "PTR", "Clients");
+    mOut << std::left;
+    printLine("Interface", "Transport", "Server", "PTR", "Clients");
     for (const auto &entry : mTable) {
-        printColumn(mOut, entry.interfaceName,
+        printLine(entry.interfaceName,
                 entry.transport,
                 entry.serverPid == NO_PID ? "N/A" : std::to_string(entry.serverPid),
                 entry.serverObjectAddress == NO_PTR ? "N/A" : toHexString(entry.serverObjectAddress),
@@ -305,16 +315,35 @@ Status Lshal::fetch() {
 void Lshal::usage() const {
     mErr
         << "usage: lshal" << std::endl
-        << "           To dump all hals." << std::endl
-        << "or:" << std::endl
+        << "           Dump all hals with default ordering and columns [-itpc]." << std::endl
+        << "       lshal [--interface|-i] [--transport|-t]" << std::endl
+        << "             [--pid|-p] [--address|-a] [--clients|-c] [--cmdline|-m]" << std::endl
+        << "             [--sort={interface|i|pid|p}]" << 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
+        << "           -p, --pid: print the server PID column" << std::endl
+        << "           -a, --address: print the server object address column" << std::endl
+        << "           -c, --clients: print the client PIDs column" << std::endl
+        << "           --sort=i, --sort=interface: sort by interface name" << std::endl
+        << "           --sort=p, --sort=pid: sort by server pid" << std::endl
         << "       lshal [-h|--help]" << std::endl
         << "           -h, --help: show this help information." << std::endl;
 }
 
 Status Lshal::parseArgs(int argc, char **argv) {
     static struct option longOptions[] = {
-        {"help", no_argument, 0, 'h' },
-        { 0,               0, 0,  0  }
+        // long options with short alternatives
+        {"help",      no_argument,       0, 'h' },
+        {"interface", no_argument,       0, 'i' },
+        {"transport", no_argument,       0, 't' },
+        {"pid",       no_argument,       0, 'p' },
+        {"address",   no_argument,       0, 'a' },
+        {"clients",   no_argument,       0, 'c' },
+
+        // long options without short alternatives
+        {"sort",      required_argument, 0, 's' },
+        { 0,          0,                 0,  0  }
     };
 
     int optionIndex;
@@ -322,17 +351,54 @@ 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, "h", longOptions, &optionIndex);
+        c = getopt_long(argc, argv, "hitpac", longOptions, &optionIndex);
         if (c == -1) {
             break;
         }
         switch (c) {
+        case 's': {
+            if (strcmp(optarg, "interface") == 0 || strcmp(optarg, "i") == 0) {
+                mSortColumn = TableEntry::sortByInterfaceName;
+            } else if (strcmp(optarg, "pid") == 0 || strcmp(optarg, "p") == 0) {
+                mSortColumn = TableEntry::sortByServerPid;
+            } else {
+                mErr << "Unrecognized sorting column: " << optarg << std::endl;
+                usage();
+                return USAGE;
+            }
+            break;
+        }
+        case 'i': {
+            mSelectedColumns |= ENABLE_INTERFACE_NAME;
+            break;
+        }
+        case 't': {
+            mSelectedColumns |= ENABLE_TRANSPORT;
+            break;
+        }
+        case 'p': {
+            mSelectedColumns |= ENABLE_SERVER_PID;
+            break;
+        }
+        case 'a': {
+            mSelectedColumns |= ENABLE_SERVER_ADDR;
+            break;
+        }
+        case 'c': {
+            mSelectedColumns |= ENABLE_CLIENT_PIDS;
+            break;
+        }
         case 'h': // falls through
         default: // see unrecognized options
             usage();
             return USAGE;
         }
     }
+
+    if (mSelectedColumns == 0) {
+        mSelectedColumns = ENABLE_INTERFACE_NAME
+                | ENABLE_TRANSPORT | ENABLE_SERVER_PID | ENABLE_CLIENT_PIDS;
+    }
     return OK;
 }
 
@@ -342,6 +408,7 @@ int Lshal::main(int argc, char **argv) {
         return status;
     }
     status = fetch();
+    postprocess();
     dump();
     return status;
 }
index c87ebc3..d7bcab2 100644 (file)
@@ -48,6 +48,7 @@ public:
 private:
     Status parseArgs(int argc, char **argv);
     Status fetch();
+    void postprocess();
     void dump() const;
     void usage() const;
     void putEntry(TableEntry &&entry);
@@ -56,11 +57,16 @@ private:
     Status fetchAllLibraries(const sp<::android::hidl::manager::V1_0::IServiceManager> &manager);
     bool getReferencedPids(
         pid_t serverPid, std::map<uint64_t, Pids> *objects) const;
+    void printLine(
+            const std::string &interfaceName,
+            const std::string &transport, const std::string &server,
+            const std::string &address, const std::string &clients) const;
 
-
-    Table mTable;
+    Table mTable{};
     std::ostream &mErr = std::cerr;
     std::ostream &mOut = std::cout;
+    TableEntryCompare mSortColumn = nullptr;
+    TableEntrySelect mSelectedColumns = 0;
 };
 
 
index 484df3f..864b41b 100644 (file)
@@ -21,6 +21,7 @@
 
 #include <string>
 #include <vector>
+#include <iostream>
 
 namespace android {
 namespace lshal {
@@ -33,9 +34,27 @@ struct TableEntry {
     int32_t serverPid;
     uint64_t serverObjectAddress;
     Pids clientPids;
+
+    static bool sortByInterfaceName(const TableEntry &a, const TableEntry &b) {
+        return a.interfaceName < b.interfaceName;
+    };
+    static bool sortByServerPid(const TableEntry &a, const TableEntry &b) {
+        return a.serverPid < b.serverPid;
+    };
 };
 
 using Table = std::vector<TableEntry>;
+using TableEntryCompare = std::function<bool(const TableEntry &, const TableEntry &)>;
+
+enum : unsigned int {
+    ENABLE_INTERFACE_NAME = 1 << 0,
+    ENABLE_TRANSPORT      = 1 << 1,
+    ENABLE_SERVER_PID     = 1 << 2,
+    ENABLE_SERVER_ADDR    = 1 << 3,
+    ENABLE_CLIENT_PIDS    = 1 << 4
+};
+
+using TableEntrySelect = unsigned int;
 
 enum {
     NO_PID = -1,