diff options
author | Yifan Hong <elsk@google.com> | 2017-02-13 17:51:59 -0800 |
---|---|---|
committer | Yifan Hong <elsk@google.com> | 2017-02-14 19:25:27 -0800 |
commit | 38d53e0327f200a8a16f99d1e1a09e33c2be8e81 (patch) | |
tree | a404e1519c22613191e775dab4d88dca31289dec | |
parent | b0dde932ad8989a393fad148c17817bcb2ff7a43 (diff) | |
download | native-38d53e0327f200a8a16f99d1e1a09e33c2be8e81.tar.gz |
lshal: Allow selecting columns and sorting by column.
Examples: see tests below.
Test: lshal
Test: lshal -intpac
Test: lshal --sort=i
Test: lshal --sort=p
Bug: 34984175
Change-Id: Ia09823776a206868a5d58a2ede153a4538147756
-rw-r--r-- | cmds/lshal/Lshal.cpp | 109 | ||||
-rw-r--r-- | cmds/lshal/Lshal.h | 10 | ||||
-rw-r--r-- | cmds/lshal/TableEntry.h | 19 |
3 files changed, 115 insertions, 23 deletions
diff --git a/cmds/lshal/Lshal.cpp b/cmds/lshal/Lshal.cpp index e6d10bfc06..d213fd314f 100644 --- a/cmds/lshal/Lshal.cpp +++ b/cmds/lshal/Lshal.cpp @@ -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; } diff --git a/cmds/lshal/Lshal.h b/cmds/lshal/Lshal.h index c87ebc3b98..d7bcab2929 100644 --- a/cmds/lshal/Lshal.h +++ b/cmds/lshal/Lshal.h @@ -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; }; diff --git a/cmds/lshal/TableEntry.h b/cmds/lshal/TableEntry.h index 484df3fbf2..864b41b3f2 100644 --- a/cmds/lshal/TableEntry.h +++ b/cmds/lshal/TableEntry.h @@ -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, |