summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYifan Hong <elsk@google.com>2017-02-14 17:33:50 -0800
committerYifan Hong <elsk@google.com>2017-02-15 16:30:35 -0800
commitae09a3ddfec51c82257e338346e39ee472470061 (patch)
tree89d7657e868047708dfd5eae424575ecfac3bf34
parente2dadf0c4f132d3a39309f4e274f1a35f7caaaed (diff)
downloadnative-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.cpp74
-rw-r--r--cmds/lshal/Lshal.h15
-rw-r--r--cmds/lshal/TableEntry.h2
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;