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

Commit 2eaf6b8e authored by Yifan Hong's avatar Yifan Hong Committed by Gerrit Code Review
Browse files

Merge changes from topic 'lshal_32'

* changes:
  lshal: Put more description to output
  lshal: also list libraries in 32-bit.
parents ad796518 a3b8709a
Loading
Loading
Loading
Loading
+191 −100
Original line number Diff line number Diff line
@@ -159,22 +159,37 @@ bool Lshal::getReferencedPids(
    return true;
}

void Lshal::forEachTable(const std::function<void(Table &)> &f) {
    for (const Table &table : {mServicesTable, mPassthroughRefTable, mImplementationsTable}) {
        f(const_cast<Table &>(table));
    }
}
void Lshal::forEachTable(const std::function<void(const Table &)> &f) const {
    for (const Table &table : {mServicesTable, mPassthroughRefTable, mImplementationsTable}) {
        f(table);
    }
}

void Lshal::postprocess() {
    forEachTable([this](Table &table) {
        if (mSortColumn) {
        std::sort(mTable.begin(), mTable.end(), mSortColumn);
            std::sort(table.begin(), table.end(), mSortColumn);
        }
    for (TableEntry &entry : mTable) {
        for (TableEntry &entry : table) {
            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 &transport,
        const std::string &arch,
        const std::string &server,
        const std::string &serverCmdline,
        const std::string &address, const std::string &clients,
        const std::string &clientCmdlines) const {
@@ -182,6 +197,8 @@ void Lshal::printLine(
        mOut << std::setw(80) << interfaceName << "\t";
    if (mSelectedColumns & ENABLE_TRANSPORT)
        mOut << std::setw(10) << transport << "\t";
    if (mSelectedColumns & ENABLE_ARCH)
        mOut << std::setw(5) << arch << "\t";
    if (mSelectedColumns & ENABLE_SERVER_PID) {
        if (mEnableCmdlines) {
            mOut << std::setw(15) << serverCmdline << "\t";
@@ -203,11 +220,12 @@ void Lshal::printLine(

void Lshal::dumpVintf() const {
    vintf::HalManifest manifest;
    for (const TableEntry &entry : mTable) {
    forEachTable([this, &manifest] (const Table &table) {
        for (const TableEntry &entry : table) {

            std::string fqInstanceName = entry.interfaceName;

        if (entry.source == LIST_DLLIB) {
            if (&table == &mImplementationsTable) {
                // Quick hack to work around *'s
                replaceAll(&fqInstanceName, '*', 'D');
            }
@@ -224,9 +242,9 @@ void Lshal::dumpVintf() const {
                continue;
            }
            std::string interfaceName =
                entry.source == LIST_DLLIB ? "" : fqName.name();
                    &table == &mImplementationsTable ? "" : fqName.name();
            std::string instanceName =
                entry.source == LIST_DLLIB ? "" : splittedFqInstanceName.second;
                    &table == &mImplementationsTable ? "" : splittedFqInstanceName.second;

            vintf::Transport transport;
            if (entry.transport == "hwbinder") {
@@ -260,7 +278,7 @@ void Lshal::dumpVintf() const {
            if (std::find(hal->versions.begin(), hal->versions.end(), version) == hal->versions.end()) {
                hal->versions.push_back(version);
            }
        if (entry.source != LIST_DLLIB) {
            if (&table != &mImplementationsTable) {
                auto it = hal->interfaces.find(interfaceName);
                if (it == hal->interfaces.end()) {
                    hal->interfaces.insert({interfaceName, {interfaceName, {{instanceName}}}});
@@ -269,22 +287,70 @@ void Lshal::dumpVintf() const {
                }
            }
        }
    });
    mOut << vintf::gHalManifestConverter(manifest);
}

void Lshal::dumpTable() const {
    mOut << "All services:" << std::endl;
static const std::string &getArchString(Architecture arch) {
    static const std::string sStr64 = "64";
    static const std::string sStr32 = "32";
    static const std::string sStrBoth = "64&32";
    static const std::string sStrUnknown = "";
    switch (arch) {
        case ARCH64:
            return sStr64;
        case ARCH32:
            return sStr32;
        case ARCH_BOTH:
            return sStrBoth;
        case ARCH_UNKNOWN: // fall through
        default:
            return sStrUnknown;
    }
}

static Architecture fromBaseArchitecture(::android::hidl::base::V1_0::DebugInfo::Architecture a) {
    switch (a) {
        case ::android::hidl::base::V1_0::DebugInfo::Architecture::IS_64BIT:
            return ARCH64;
        case ::android::hidl::base::V1_0::DebugInfo::Architecture::IS_32BIT:
            return ARCH32;
        case ::android::hidl::base::V1_0::DebugInfo::Architecture::UNKNOWN: // fallthrough
        default:
            return ARCH_UNKNOWN;
    }
}

void Lshal::dumpTable() {
    mServicesTable.description =
            "All binderized services (registered services through hwservicemanager)";
    mPassthroughRefTable.description =
            "All interfaces that getService() has ever return a passthrough interface;\n"
            "PIDs / processes shown below might be inaccurate because the process\n"
            "might have relinquish the interface or might have died.\n"
            "The Server / Server CMD column can be ignored.\n"
            "The Clients / Clients CMD column shows all process that have ever dlopen the library\n"
            "and successfully fetch the passthrough implementation.";
    mImplementationsTable.description =
            "All available passthrough implementations (all -impl.so files)";
    forEachTable([this] (const Table &table) {
        mOut << table.description << std::endl;
        mOut << std::left;
    printLine("Interface", "Transport", "Server", "Server CMD", "PTR", "Clients", "Clients CMD");
    for (const auto &entry : mTable) {
        printLine("Interface", "Transport", "Arch", "Server", "Server CMD",
                  "PTR", "Clients", "Clients CMD");
        for (const auto &entry : table) {
            printLine(entry.interfaceName,
                    entry.transport,
                    getArchString(entry.arch),
                    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.clientCmdlines, ";"));
        }
        mOut << std::endl;
    });

}

void Lshal::dump() {
@@ -301,24 +367,43 @@ void Lshal::dump() {
    }
}

void Lshal::putEntry(TableEntry &&entry) {
    mTable.push_back(std::forward<TableEntry>(entry));
void Lshal::putEntry(TableEntrySource source, TableEntry &&entry) {
    Table *table = nullptr;
    switch (source) {
        case HWSERVICEMANAGER_LIST :
            table = &mServicesTable; break;
        case PTSERVICEMANAGER_REG_CLIENT :
            table = &mPassthroughRefTable; break;
        case LIST_DLLIB :
            table = &mImplementationsTable; break;
        default:
            mErr << "Error: Unknown source of entry " << source << std::endl;
    }
    if (table) {
        table->entries.push_back(std::forward<TableEntry>(entry));
    }
}

Status Lshal::fetchAllLibraries(const sp<IServiceManager> &manager) {
    using namespace ::android::hardware;
    using namespace ::android::hidl::manager::V1_0;
    using namespace ::android::hidl::base::V1_0;
    auto ret = timeoutIPC(manager, &IServiceManager::list, [&] (const auto &fqInstanceNames) {
        for (const auto &fqInstanceName : fqInstanceNames) {
            putEntry({
                .interfaceName = fqInstanceName,
    auto ret = timeoutIPC(manager, &IServiceManager::debugDump, [&] (const auto &infos) {
        std::map<std::string, TableEntry> entries;
        for (const auto &info : infos) {
            std::string interfaceName = std::string{info.interfaceName.c_str()} + "/" +
                    std::string{info.instanceName.c_str()};
            entries.emplace(std::string{interfaceName}, TableEntry{
                .interfaceName = interfaceName,
                .transport = "passthrough",
                .serverPid = NO_PID,
                .serverObjectAddress = NO_PTR,
                .clientPids = {},
                .source = LIST_DLLIB
            });
                .arch = ARCH_UNKNOWN
            }).first->second.arch |= fromBaseArchitecture(info.arch);
        }
        for (auto &&pair : entries) {
            putEntry(LIST_DLLIB, std::move(pair.second));
        }
    });
    if (!ret.isOk()) {
@@ -331,11 +416,12 @@ Status Lshal::fetchAllLibraries(const sp<IServiceManager> &manager) {

Status Lshal::fetchPassthrough(const sp<IServiceManager> &manager) {
    using namespace ::android::hardware;
    using namespace ::android::hardware::details;
    using namespace ::android::hidl::manager::V1_0;
    using namespace ::android::hidl::base::V1_0;
    auto ret = timeoutIPC(manager, &IServiceManager::debugDump, [&] (const auto &infos) {
        for (const auto &info : infos) {
            putEntry({
            putEntry(PTSERVICEMANAGER_REG_CLIENT, {
                .interfaceName =
                        std::string{info.interfaceName.c_str()} + "/" +
                        std::string{info.instanceName.c_str()},
@@ -343,7 +429,7 @@ Status Lshal::fetchPassthrough(const sp<IServiceManager> &manager) {
                .serverPid = info.clientPids.size() == 1 ? info.clientPids[0] : NO_PID,
                .serverObjectAddress = NO_PTR,
                .clientPids = info.clientPids,
                .source = PTSERVICEMANAGER_REG_CLIENT
                .arch = fromBaseArchitecture(info.arch)
            });
        }
    });
@@ -420,25 +506,25 @@ Status Lshal::fetchBinderized(const sp<IServiceManager> &manager) {
    for (const auto &fqInstanceName : fqInstanceNames) {
        auto it = allDebugInfos.find(fqInstanceName);
        if (it == allDebugInfos.end()) {
            putEntry({
            putEntry(HWSERVICEMANAGER_LIST, {
                .interfaceName = fqInstanceName,
                .transport = mode,
                .serverPid = NO_PID,
                .serverObjectAddress = NO_PTR,
                .clientPids = {},
                .source = HWSERVICEMANAGER_LIST
                .arch = ARCH_UNKNOWN
            });
            continue;
        }
        const DebugInfo &info = it->second;
        putEntry({
        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],
            .source = HWSERVICEMANAGER_LIST
            .arch = fromBaseArchitecture(info.arch),
        });
    }
    return status;
@@ -469,13 +555,14 @@ Status Lshal::fetch() {
void Lshal::usage() const {
    mErr
        << "usage: lshal" << std::endl
        << "           Dump all hals with default ordering and columns [-itpc]." << std::endl
        << "       lshal [--interface|-i] [--transport|-t]" << std::endl
        << "           Dump all hals with default ordering and columns [-ipc]." << std::endl
        << "       lshal [--interface|-i] [--transport|-t] [-r|--arch]" << std::endl
        << "             [--pid|-p] [--address|-a] [--clients|-c] [--cmdline|-m]" << std::endl
        << "             [--sort={interface|i|pid|p}] [--init-vintf[=path]]" << 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
        << "           -r, --arch: print if the HAL is in 64-bit or 32-bit" << 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, or client cmdlines if -m is set"
@@ -495,6 +582,7 @@ Status Lshal::parseArgs(int argc, char **argv) {
        {"help",      no_argument,       0, 'h' },
        {"interface", no_argument,       0, 'i' },
        {"transport", no_argument,       0, 't' },
        {"arch",      no_argument,       0, 'r' },
        {"pid",       no_argument,       0, 'p' },
        {"address",   no_argument,       0, 'a' },
        {"clients",   no_argument,       0, 'c' },
@@ -511,7 +599,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, "hitpacm", longOptions, &optionIndex);
        c = getopt_long(argc, argv, "hitrpacm", longOptions, &optionIndex);
        if (c == -1) {
            break;
        }
@@ -547,6 +635,10 @@ Status Lshal::parseArgs(int argc, char **argv) {
            mSelectedColumns |= ENABLE_TRANSPORT;
            break;
        }
        case 'r': {
            mSelectedColumns |= ENABLE_ARCH;
            break;
        }
        case 'p': {
            mSelectedColumns |= ENABLE_SERVER_PID;
            break;
@@ -571,8 +663,7 @@ Status Lshal::parseArgs(int argc, char **argv) {
    }

    if (mSelectedColumns == 0) {
        mSelectedColumns = ENABLE_INTERFACE_NAME
                | ENABLE_TRANSPORT | ENABLE_SERVER_PID | ENABLE_CLIENT_PIDS;
        mSelectedColumns = ENABLE_INTERFACE_NAME | ENABLE_SERVER_PID | ENABLE_CLIENT_PIDS;
    }
    return OK;
}
+11 −4
Original line number Diff line number Diff line
@@ -53,17 +53,19 @@ private:
    void postprocess();
    void dump();
    void usage() const;
    void putEntry(TableEntry &&entry);
    void putEntry(TableEntrySource source, TableEntry &&entry);
    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;
    void dumpTable() const;
    void dumpTable();
    void dumpVintf() const;
    void printLine(
            const std::string &interfaceName,
            const std::string &transport, const std::string &server,
            const std::string &transport,
            const std::string &arch,
            const std::string &server,
            const std::string &serverCmdline,
            const std::string &address, const std::string &clients,
            const std::string &clientCmdlines) const ;
@@ -72,8 +74,13 @@ private:
    // 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);
    void forEachTable(const std::function<void(Table &)> &f);
    void forEachTable(const std::function<void(const Table &)> &f) const;

    Table mServicesTable{};
    Table mPassthroughRefTable{};
    Table mImplementationsTable{};

    Table mTable{};
    NullableOStream<std::ostream> mErr = std::cerr;
    NullableOStream<std::ostream> mOut = std::cout;
    NullableOStream<std::ofstream> mFileOutput = nullptr;
+22 −3
Original line number Diff line number Diff line
@@ -35,6 +35,14 @@ enum : unsigned int {
};
using TableEntrySource = unsigned int;

enum : unsigned int {
    ARCH_UNKNOWN = 0,
    ARCH64       = 1 << 0,
    ARCH32       = 1 << 1,
    ARCH_BOTH    = ARCH32 | ARCH64
};
using Architecture = unsigned int;

struct TableEntry {
    std::string interfaceName;
    std::string transport;
@@ -43,7 +51,7 @@ struct TableEntry {
    uint64_t serverObjectAddress;
    Pids clientPids;
    std::vector<std::string> clientCmdlines;
    TableEntrySource source;
    Architecture arch;

    static bool sortByInterfaceName(const TableEntry &a, const TableEntry &b) {
        return a.interfaceName < b.interfaceName;
@@ -53,7 +61,17 @@ struct TableEntry {
    };
};

using Table = std::vector<TableEntry>;
struct Table {
    using Entries = std::vector<TableEntry>;
    std::string description;
    Entries entries;

    Entries::iterator begin() { return entries.begin(); }
    Entries::const_iterator begin() const { return entries.begin(); }
    Entries::iterator end() { return entries.end(); }
    Entries::const_iterator end() const { return entries.end(); }
};

using TableEntryCompare = std::function<bool(const TableEntry &, const TableEntry &)>;

enum : unsigned int {
@@ -61,7 +79,8 @@ enum : unsigned int {
    ENABLE_TRANSPORT      = 1 << 1,
    ENABLE_SERVER_PID     = 1 << 2,
    ENABLE_SERVER_ADDR    = 1 << 3,
    ENABLE_CLIENT_PIDS    = 1 << 4
    ENABLE_CLIENT_PIDS    = 1 << 4,
    ENABLE_ARCH           = 1 << 5
};

using TableEntrySelect = unsigned int;