Merge "Delete vdex file in delete_odex."
diff --git a/cmds/lshal/ListCommand.cpp b/cmds/lshal/ListCommand.cpp
index 38b406c..2eb58ae 100644
--- a/cmds/lshal/ListCommand.cpp
+++ b/cmds/lshal/ListCommand.cpp
@@ -73,46 +73,92 @@
}), pids->end());
}
-bool ListCommand::getReferencedPids(
- pid_t serverPid, std::map<uint64_t, Pids> *objects) const {
-
- std::ifstream ifs("/d/binder/proc/" + std::to_string(serverPid));
+bool scanBinderContext(pid_t pid,
+ const std::string &contextName,
+ std::function<void(const std::string&)> eachLine) {
+ std::ifstream ifs("/d/binder/proc/" + std::to_string(pid));
if (!ifs.is_open()) {
return false;
}
- static const std::regex prefix("^\\s*node \\d+:\\s+u([0-9a-f]+)\\s+c([0-9a-f]+)\\s+");
+ static const std::regex kContextLine("^context (\\w+)$");
+ bool isDesiredContext = false;
std::string line;
std::smatch match;
while(getline(ifs, line)) {
- if (!std::regex_search(line, match, prefix)) {
- // the line doesn't start with the correct prefix
+ if (std::regex_search(line, match, kContextLine)) {
+ isDesiredContext = match.str(1) == contextName;
continue;
}
- std::string ptrString = "0x" + match.str(2); // use number after c
- uint64_t ptr;
- if (!::android::base::ParseUint(ptrString.c_str(), &ptr)) {
- // Should not reach here, but just be tolerant.
- mErr << "Could not parse number " << ptrString << std::endl;
+
+ if (!isDesiredContext) {
continue;
}
- const std::string proc = " proc ";
- auto pos = line.rfind(proc);
- if (pos != std::string::npos) {
- for (const std::string &pidStr : split(line.substr(pos + proc.size()), ' ')) {
- int32_t pid;
- if (!::android::base::ParseInt(pidStr, &pid)) {
- mErr << "Could not parse number " << pidStr << std::endl;
- continue;
- }
- (*objects)[ptr].push_back(pid);
- }
- }
+
+ eachLine(line);
}
return true;
}
+bool ListCommand::getPidInfo(
+ pid_t serverPid, PidInfo *pidInfo) const {
+ static const std::regex kReferencePrefix("^\\s*node \\d+:\\s+u([0-9a-f]+)\\s+c([0-9a-f]+)\\s+");
+ static const std::regex kThreadPrefix("^\\s*thread \\d+:\\s+l\\s+(\\d)(\\d)");
+
+ std::smatch match;
+ return scanBinderContext(serverPid, "hwbinder", [&](const std::string& line) {
+ if (std::regex_search(line, match, kReferencePrefix)) {
+ const std::string &ptrString = "0x" + match.str(2); // use number after c
+ uint64_t ptr;
+ if (!::android::base::ParseUint(ptrString.c_str(), &ptr)) {
+ // Should not reach here, but just be tolerant.
+ mErr << "Could not parse number " << ptrString << std::endl;
+ return;
+ }
+ const std::string proc = " proc ";
+ auto pos = line.rfind(proc);
+ if (pos != std::string::npos) {
+ for (const std::string &pidStr : split(line.substr(pos + proc.size()), ' ')) {
+ int32_t pid;
+ if (!::android::base::ParseInt(pidStr, &pid)) {
+ mErr << "Could not parse number " << pidStr << std::endl;
+ return;
+ }
+ pidInfo->refPids[ptr].push_back(pid);
+ }
+ }
+
+ return;
+ }
+
+ if (std::regex_search(line, match, kThreadPrefix)) {
+ // "1" is waiting in binder driver
+ // "2" is poll. It's impossible to tell if these are in use.
+ // and HIDL default code doesn't use it.
+ bool isInUse = match.str(1) != "1";
+ // "0" is a thread that has called into binder
+ // "1" is looper thread
+ // "2" is main looper thread
+ bool isHwbinderThread = match.str(2) != "0";
+
+ if (!isHwbinderThread) {
+ return;
+ }
+
+ if (isInUse) {
+ pidInfo->threadUsage++;
+ }
+
+ pidInfo->threadCount++;
+ return;
+ }
+
+ // not reference or thread line
+ return;
+ });
+}
+
// Must process hwbinder services first, then passthrough services.
void ListCommand::forEachTable(const std::function<void(Table &)> &f) {
f(mServicesTable);
@@ -164,9 +210,11 @@
const std::string &interfaceName,
const std::string &transport,
const std::string &arch,
+ const std::string &threadUsage,
const std::string &server,
const std::string &serverCmdline,
- const std::string &address, const std::string &clients,
+ const std::string &address,
+ const std::string &clients,
const std::string &clientCmdlines) const {
if (mSelectedColumns & ENABLE_INTERFACE_NAME)
mOut << std::setw(80) << interfaceName << "\t";
@@ -174,6 +222,9 @@
mOut << std::setw(10) << transport << "\t";
if (mSelectedColumns & ENABLE_ARCH)
mOut << std::setw(5) << arch << "\t";
+ if (mSelectedColumns & ENABLE_THREADS) {
+ mOut << std::setw(8) << threadUsage << "\t";
+ }
if (mSelectedColumns & ENABLE_SERVER_PID) {
if (mEnableCmdlines) {
mOut << std::setw(15) << serverCmdline << "\t";
@@ -349,14 +400,15 @@
}
mOut << std::left;
if (!mNeat) {
- printLine("Interface", "Transport", "Arch", "Server", "Server CMD",
- "PTR", "Clients", "Clients CMD");
+ printLine("Interface", "Transport", "Arch", "Thread Use", "Server",
+ "Server CMD", "PTR", "Clients", "Clients CMD");
}
for (const auto &entry : table) {
printLine(entry.interfaceName,
entry.transport,
getArchString(entry.arch),
+ entry.getThreadUsage(),
entry.serverPid == NO_PID ? "N/A" : std::to_string(entry.serverPid),
entry.serverCmdline,
entry.serverObjectAddress == NO_PTR ? "N/A" : toHexString(entry.serverObjectAddress),
@@ -492,7 +544,7 @@
Status status = OK;
// server pid, .ptr value of binder object, child pids
std::map<std::string, DebugInfo> allDebugInfos;
- std::map<pid_t, std::map<uint64_t, Pids>> allPids;
+ std::map<pid_t, PidInfo> allPids;
for (const auto &fqInstanceName : fqInstanceNames) {
const auto pair = splitFirst(fqInstanceName, '/');
const auto &serviceName = pair.first;
@@ -516,7 +568,7 @@
auto debugRet = timeoutIPC(service, &IBase::getDebugInfo, [&] (const auto &debugInfo) {
allDebugInfos[fqInstanceName] = debugInfo;
if (debugInfo.pid >= 0) {
- allPids[static_cast<pid_t>(debugInfo.pid)].clear();
+ allPids[static_cast<pid_t>(debugInfo.pid)] = PidInfo();
}
});
if (!debugRet.isOk()) {
@@ -526,9 +578,10 @@
status |= DUMP_BINDERIZED_ERROR;
}
}
+
for (auto &pair : allPids) {
pid_t serverPid = pair.first;
- if (!getReferencedPids(serverPid, &allPids[serverPid])) {
+ if (!getPidInfo(serverPid, &allPids[serverPid])) {
mErr << "Warning: no information for PID " << serverPid
<< ", are you root?" << std::endl;
status |= DUMP_BINDERIZED_ERROR;
@@ -543,18 +596,23 @@
.serverPid = NO_PID,
.serverObjectAddress = NO_PTR,
.clientPids = {},
+ .threadUsage = 0,
+ .threadCount = 0,
.arch = ARCH_UNKNOWN
});
continue;
}
const DebugInfo &info = it->second;
+ bool writePidInfo = info.pid != NO_PID && info.ptr != NO_PTR;
+
putEntry(HWSERVICEMANAGER_LIST, {
.interfaceName = fqInstanceName,
.transport = mode,
.serverPid = info.pid,
.serverObjectAddress = info.ptr,
- .clientPids = info.pid == NO_PID || info.ptr == NO_PTR
- ? Pids{} : allPids[info.pid][info.ptr],
+ .clientPids = writePidInfo ? allPids[info.pid].refPids[info.ptr] : Pids{},
+ .threadUsage = writePidInfo ? allPids[info.pid].threadUsage : 0,
+ .threadCount = writePidInfo ? allPids[info.pid].threadCount : 0,
.arch = fromBaseArchitecture(info.arch),
});
}
@@ -593,6 +651,7 @@
{"pid", no_argument, 0, 'p' },
{"address", no_argument, 0, 'a' },
{"clients", no_argument, 0, 'c' },
+ {"threads", no_argument, 0, 'e' },
{"cmdline", no_argument, 0, 'm' },
{"debug", optional_argument, 0, 'd' },
@@ -609,7 +668,7 @@
for (;;) {
// using getopt_long in case we want to add other options in the future
c = getopt_long(arg.argc, arg.argv,
- "hitrpacmd", longOptions, &optionIndex);
+ "hitrpacmde", longOptions, &optionIndex);
if (c == -1) {
break;
}
@@ -661,6 +720,10 @@
mSelectedColumns |= ENABLE_CLIENT_PIDS;
break;
}
+ case 'e': {
+ mSelectedColumns |= ENABLE_THREADS;
+ break;
+ }
case 'm': {
mEnableCmdlines = true;
break;
@@ -695,7 +758,7 @@
}
if (mSelectedColumns == 0) {
- mSelectedColumns = ENABLE_INTERFACE_NAME | ENABLE_SERVER_PID | ENABLE_CLIENT_PIDS;
+ mSelectedColumns = ENABLE_INTERFACE_NAME | ENABLE_SERVER_PID | ENABLE_CLIENT_PIDS | ENABLE_THREADS;
}
return OK;
}
diff --git a/cmds/lshal/ListCommand.h b/cmds/lshal/ListCommand.h
index f367d7f..a75db04 100644
--- a/cmds/lshal/ListCommand.h
+++ b/cmds/lshal/ListCommand.h
@@ -48,18 +48,26 @@
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;
+
+ struct PidInfo {
+ std::map<uint64_t, Pids> refPids; // pids that are referenced
+ uint32_t threadUsage; // number of threads in use
+ uint32_t threadCount; // number of threads total
+ };
+ bool getPidInfo(pid_t serverPid, PidInfo *info) const;
+
void dumpTable();
void dumpVintf() const;
void printLine(
const std::string &interfaceName,
const std::string &transport,
const std::string &arch,
+ const std::string &threadUsage,
const std::string &server,
const std::string &serverCmdline,
- const std::string &address, const std::string &clients,
- const std::string &clientCmdlines) const ;
+ 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
diff --git a/cmds/lshal/Lshal.cpp b/cmds/lshal/Lshal.cpp
index 9db42f1..e2d5f6d 100644
--- a/cmds/lshal/Lshal.cpp
+++ b/cmds/lshal/Lshal.cpp
@@ -66,7 +66,7 @@
" List all hals with default ordering and columns (`lshal list -ipc`)\n"
" lshal list [-h|--help]\n"
" -h, --help: Print help message for list (`lshal help list`)\n"
- " lshal [list] [--interface|-i] [--transport|-t] [-r|--arch]\n"
+ " lshal [list] [--interface|-i] [--transport|-t] [-r|--arch] [-e|--threads]\n"
" [--pid|-p] [--address|-a] [--clients|-c] [--cmdline|-m]\n"
" [--sort={interface|i|pid|p}] [--init-vintf[=<output file>]]\n"
" [--debug|-d[=<output file>]]\n"
@@ -74,6 +74,8 @@
" -n, --instance: print the instance name column\n"
" -t, --transport: print the transport mode column\n"
" -r, --arch: print if the HAL is in 64-bit or 32-bit\n"
+ " -e, --threads: print currently used/available threads\n"
+ " (note, available threads created lazily)\n"
" -p, --pid: print the server PID, or server cmdline if -m is set\n"
" -a, --address: print the server object address column\n"
" -c, --clients: print the client PIDs, or client cmdlines if -m is set\n"
diff --git a/cmds/lshal/TableEntry.h b/cmds/lshal/TableEntry.h
index 9ae8f78..e04c3ca 100644
--- a/cmds/lshal/TableEntry.h
+++ b/cmds/lshal/TableEntry.h
@@ -47,6 +47,8 @@
std::string interfaceName;
std::string transport;
int32_t serverPid;
+ uint32_t threadUsage;
+ uint32_t threadCount;
std::string serverCmdline;
uint64_t serverObjectAddress;
Pids clientPids;
@@ -59,6 +61,14 @@
static bool sortByServerPid(const TableEntry &a, const TableEntry &b) {
return a.serverPid < b.serverPid;
};
+
+ std::string getThreadUsage() const {
+ if (threadCount == 0) {
+ return "N/A";
+ }
+
+ return std::to_string(threadUsage) + "/" + std::to_string(threadCount);
+ }
};
struct Table {
@@ -80,7 +90,8 @@
ENABLE_SERVER_PID = 1 << 2,
ENABLE_SERVER_ADDR = 1 << 3,
ENABLE_CLIENT_PIDS = 1 << 4,
- ENABLE_ARCH = 1 << 5
+ ENABLE_ARCH = 1 << 5,
+ ENABLE_THREADS = 1 << 6,
};
using TableEntrySelect = unsigned int;