diff options
author | Yifan Hong <elsk@google.com> | 2017-02-14 17:33:50 -0800 |
---|---|---|
committer | Yifan Hong <elsk@google.com> | 2017-02-15 16:30:35 -0800 |
commit | ae09a3ddfec51c82257e338346e39ee472470061 (patch) | |
tree | 89d7657e868047708dfd5eae424575ecfac3bf34 | |
parent | e2dadf0c4f132d3a39309f4e274f1a35f7caaaed (diff) | |
download | native-ae09a3ddfec51c82257e338346e39ee472470061.tar.gz |
lshal: Add option to print cmd lines instead of pids.
Add -m to arguments of lshal. When this flag is set,
/proc/{pid}/cmdline is printed instead of a plain PID.
If the file doesn't exist, it will be striped out from
the PID column as well (the process is considered died
and won't hold a reference to the binder object.)
Test: lshal -icm
Bug: 35160832
Change-Id: I4345bf06112a1f87ce91bec6f6f787703e46cd17
-rw-r--r-- | cmds/lshal/Lshal.cpp | 74 | ||||
-rw-r--r-- | cmds/lshal/Lshal.h | 15 | ||||
-rw-r--r-- | cmds/lshal/TableEntry.h | 2 |
3 files changed, 80 insertions, 11 deletions
diff --git a/cmds/lshal/Lshal.cpp b/cmds/lshal/Lshal.cpp index a2dabce90f..ce058c8a47 100644 --- a/cmds/lshal/Lshal.cpp +++ b/cmds/lshal/Lshal.cpp @@ -81,6 +81,32 @@ static std::vector<std::string> split(const std::string &s, char c) { return components; } +std::string getCmdline(pid_t pid) { + std::ifstream ifs("/proc/" + std::to_string(pid) + "/cmdline"); + std::string cmdline; + if (!ifs.is_open()) { + return ""; + } + ifs >> cmdline; + return cmdline; +} + +const std::string &Lshal::getCmdline(pid_t pid) { + auto pair = mCmdlines.find(pid); + if (pair != mCmdlines.end()) { + return pair->second; + } + mCmdlines[pid] = ::android::lshal::getCmdline(pid); + return mCmdlines[pid]; +} + +void Lshal::removeDeadProcesses(Pids *pids) { + static const pid_t myPid = getpid(); + std::remove_if(pids->begin(), pids->end(), [this](auto pid) { + return pid == myPid || this->getCmdline(pid).empty(); + }); +} + bool Lshal::getReferencedPids( pid_t serverPid, std::map<uint64_t, Pids> *objects) const { @@ -125,35 +151,56 @@ void Lshal::postprocess() { if (mSortColumn) { std::sort(mTable.begin(), mTable.end(), mSortColumn); } + 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::printLine( const std::string &interfaceName, const std::string &transport, const std::string &server, - const std::string &address, const std::string &clients) const { + const std::string &serverCmdline, + const std::string &address, const std::string &clients, + const std::string &clientCmdlines) 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_PID) { + if (mEnableCmdlines) { + mOut << std::setw(15) << serverCmdline << "\t"; + } else { + 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; + if (mSelectedColumns & ENABLE_CLIENT_PIDS) { + if (mEnableCmdlines) { + mOut << std::setw(0) << clientCmdlines; + } else { + mOut << std::setw(0) << clients; + } + } mOut << std::endl; } void Lshal::dump() const { mOut << "All services:" << std::endl; mOut << std::left; - printLine("Interface", "Transport", "Server", "PTR", "Clients"); + 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.clientPids, " "), + join(entry.clientCmdlines, ";")); } } @@ -324,9 +371,11 @@ void Lshal::usage() const { << " -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 + << " -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 column" << std::endl + << " -c, --clients: print the client PIDs, or client cmdlines if -m is set" + << std::endl + << " -m, --cmdline: print cmdline instead of PIDs" << 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 @@ -342,6 +391,7 @@ Status Lshal::parseArgs(int argc, char **argv) { {"pid", no_argument, 0, 'p' }, {"address", no_argument, 0, 'a' }, {"clients", no_argument, 0, 'c' }, + {"cmdline", no_argument, 0, 'm' }, // long options without short alternatives {"sort", required_argument, 0, 's' }, @@ -353,7 +403,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, "hitpac", longOptions, &optionIndex); + c = getopt_long(argc, argv, "hitpacm", longOptions, &optionIndex); if (c == -1) { break; } @@ -390,6 +440,10 @@ Status Lshal::parseArgs(int argc, char **argv) { mSelectedColumns |= ENABLE_CLIENT_PIDS; break; } + case 'm': { + mEnableCmdlines = true; + break; + } case 'h': // falls through default: // see unrecognized options usage(); diff --git a/cmds/lshal/Lshal.h b/cmds/lshal/Lshal.h index d7bcab2929..ead99dc068 100644 --- a/cmds/lshal/Lshal.h +++ b/cmds/lshal/Lshal.h @@ -60,13 +60,26 @@ private: void printLine( const std::string &interfaceName, const std::string &transport, const std::string &server, - const std::string &address, const std::string &clients) const; + const std::string &serverCmdline, + const std::string &address, const std::string &clients, + const std::string &clientCmdlines) const ; + // Return /proc/{pid}/cmdline if it exists, else empty string. + const std::string &getCmdline(pid_t pid); + // 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); Table mTable{}; std::ostream &mErr = std::cerr; std::ostream &mOut = std::cout; TableEntryCompare mSortColumn = nullptr; TableEntrySelect mSelectedColumns = 0; + // If true, cmdlines will be printed instead of pid. + bool mEnableCmdlines; + // If an entry does not exist, need to ask /proc/{pid}/cmdline to get it. + // If an entry exist but is an empty string, process might have died. + // If an entry exist and not empty, it contains the cached content of /proc/{pid}/cmdline. + std::map<pid_t, std::string> mCmdlines; }; diff --git a/cmds/lshal/TableEntry.h b/cmds/lshal/TableEntry.h index 864b41b3f2..4ec3a0ced1 100644 --- a/cmds/lshal/TableEntry.h +++ b/cmds/lshal/TableEntry.h @@ -32,8 +32,10 @@ struct TableEntry { std::string interfaceName; std::string transport; int32_t serverPid; + std::string serverCmdline; uint64_t serverObjectAddress; Pids clientPids; + std::vector<std::string> clientCmdlines; static bool sortByInterfaceName(const TableEntry &a, const TableEntry &b) { return a.interfaceName < b.interfaceName; |