Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ae09a3dd authored by Yifan Hong's avatar Yifan Hong
Browse files

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
parent e2dadf0c
Loading
Loading
Loading
Loading
+64 −10
Original line number Diff line number Diff line
@@ -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)
    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)
    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();
+14 −1
Original line number Diff line number Diff line
@@ -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;
};


+2 −0
Original line number Diff line number Diff line
@@ -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;