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

Commit eadd0434 authored by Devin Moore's avatar Devin Moore
Browse files

Replace binderdebug regex

It's incredibly slow!
Walking through the text using android-base/strings.h and std::string
operations is much faster.
We are making the same assumptions about the format of the files as we
were with regex, but we have fewer hard requirements for the format now.

See bug for detailed timing results with simpleperf.

Test: atest binderdebug_tests
Bug: 270596767
Change-Id: I674414504050371083aad7a93714114190e8a2b4
parent f492c1a4
Loading
Loading
Loading
Loading
+96 −70
Original line number Original line Diff line number Diff line
@@ -48,14 +48,12 @@ static status_t scanBinderContext(pid_t pid, const std::string& contextName,
            return -errno;
            return -errno;
        }
        }
    }
    }
    static const std::regex kContextLine("^context (\\w+)$");


    bool isDesiredContext = false;
    bool isDesiredContext = false;
    std::string line;
    std::string line;
    std::smatch match;
    while (getline(ifs, line)) {
    while (getline(ifs, line)) {
        if (std::regex_search(line, match, kContextLine)) {
        if (base::StartsWith(line, "context")) {
            isDesiredContext = match.str(1) == contextName;
            isDesiredContext = base::Split(line, " ").back() == contextName;
            continue;
            continue;
        }
        }
        if (!isDesiredContext) {
        if (!isDesiredContext) {
@@ -66,42 +64,55 @@ static status_t scanBinderContext(pid_t pid, const std::string& contextName,
    return OK;
    return OK;
}
}


// Examples of what we are looking at:
// node 66730: u00007590061890e0 c0000759036130950 pri 0:120 hs 1 hw 1 ls 0 lw 0 is 2 iw 2 tr 1 proc 2300 1790
// thread 2999: l 00 need_return 1 tr 0
status_t getBinderPidInfo(BinderDebugContext context, pid_t pid, BinderPidInfo* pidInfo) {
status_t getBinderPidInfo(BinderDebugContext context, pid_t pid, BinderPidInfo* pidInfo) {
    std::smatch match;
    std::smatch match;
    static const std::regex kReferencePrefix("^\\s*node \\d+:\\s+u([0-9a-f]+)\\s+c([0-9a-f]+)\\s+");
    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)");
    static const std::regex kThreadPrefix("^\\s*thread \\d+:\\s+l\\s+(\\d)(\\d)");
    std::string contextStr = contextToString(context);
    std::string contextStr = contextToString(context);
    status_t ret = scanBinderContext(pid, contextStr, [&](const std::string& line) {
    status_t ret = scanBinderContext(pid, contextStr, [&](const std::string& line) {
        if (std::regex_search(line, match, kReferencePrefix)) {
        if (base::StartsWith(line, "  node")) {
            const std::string& ptrString = "0x" + match.str(2); // use number after c
            std::vector<std::string> splitString = base::Tokenize(line, " ");
            uint64_t ptr;
            bool pids = false;
            uint64_t ptr = 0;
            for (const auto& token : splitString) {
                if (base::StartsWith(token, "u")) {
                    const std::string ptrString = "0x" + token.substr(1);
                    if (!::android::base::ParseUint(ptrString.c_str(), &ptr)) {
                    if (!::android::base::ParseUint(ptrString.c_str(), &ptr)) {
                // Should not reach here, but just be tolerant.
                        LOG(ERROR) << "Failed to parse pointer: " << ptrString;
                        return;
                        return;
                    }
                    }
            const std::string proc = " proc ";
                } else {
            auto pos = line.rfind(proc);
                    // The last numbers in the line after "proc" are all client PIDs
            if (pos != std::string::npos) {
                    if (token == "proc") {
                for (const std::string& pidStr : base::Split(line.substr(pos + proc.size()), " ")) {
                        pids = true;
                    } else if (pids) {
                        int32_t pid;
                        int32_t pid;
                    if (!::android::base::ParseInt(pidStr, &pid)) {
                        if (!::android::base::ParseInt(token, &pid)) {
                            LOG(ERROR) << "Failed to parse pid int: " << token;
                            return;
                        }
                        if (ptr == 0) {
                            LOG(ERROR) << "We failed to parse the pointer, so we can't add the refPids";
                            return;
                            return;
                        }
                        }
                        pidInfo->refPids[ptr].push_back(pid);
                        pidInfo->refPids[ptr].push_back(pid);
                    }
                    }
                }
                }

            return;
            }
            }
        if (std::regex_search(line, match, kThreadPrefix)) {
        } else if (base::StartsWith(line, "  thread")) {
            auto pos = line.find("l ");
            if (pos != std::string::npos) {
                // "1" is waiting in binder driver
                // "1" is waiting in binder driver
                // "2" is poll. It's impossible to tell if these are in use.
                // "2" is poll. It's impossible to tell if these are in use.
                //     and HIDL default code doesn't use it.
                //     and HIDL default code doesn't use it.
            bool isInUse = match.str(1) != "1";
                bool isInUse = line.at(pos + 2) != '1';
                // "0" is a thread that has called into binder
                // "0" is a thread that has called into binder
                // "1" is looper thread
                // "1" is looper thread
                // "2" is main looper thread
                // "2" is main looper thread
            bool isBinderThread = match.str(2) != "0";
                bool isBinderThread = line.at(pos + 3) != '0';
                if (!isBinderThread) {
                if (!isBinderThread) {
                    return;
                    return;
                }
                }
@@ -110,13 +121,15 @@ status_t getBinderPidInfo(BinderDebugContext context, pid_t pid, BinderPidInfo*
                }
                }


                pidInfo->threadCount++;
                pidInfo->threadCount++;
            return;
            }
            }
        return;
        }
    });
    });
    return ret;
    return ret;
}
}


// Examples of what we are looking at:
// ref 52493: desc 910 node 52492 s 1 w 1 d 0000000000000000
// node 29413: u00007803fc982e80 c000078042c982210 pri 0:139 hs 1 hw 1 ls 0 lw 0 is 2 iw 2 tr 1 proc 488 683
status_t getBinderClientPids(BinderDebugContext context, pid_t pid, pid_t servicePid,
status_t getBinderClientPids(BinderDebugContext context, pid_t pid, pid_t servicePid,
                             int32_t handle, std::vector<pid_t>* pids) {
                             int32_t handle, std::vector<pid_t>* pids) {
    std::smatch match;
    std::smatch match;
@@ -124,51 +137,64 @@ status_t getBinderClientPids(BinderDebugContext context, pid_t pid, pid_t servic
    std::string contextStr = contextToString(context);
    std::string contextStr = contextToString(context);
    int32_t node;
    int32_t node;
    status_t ret = scanBinderContext(pid, contextStr, [&](const std::string& line) {
    status_t ret = scanBinderContext(pid, contextStr, [&](const std::string& line) {
        if (std::regex_search(line, match, kNodeNumber)) {
        if (!base::StartsWith(line, "  ref")) return;
            const std::string& descString = match.str(1);

            int32_t desc;
        std::vector<std::string> splitString = base::Tokenize(line, " ");
            if (!::android::base::ParseInt(descString.c_str(), &desc)) {
        if (splitString.size() < 12) {
                LOG(ERROR) << "Failed to parse desc int: " << descString;
            LOG(ERROR) << "Failed to parse binder_logs ref entry. Expecting size greater than 11, but got: " << splitString.size();
            return;
            return;
        }
        }
            if (handle != desc) {
        int32_t desc;
        if (!::android::base::ParseInt(splitString[3].c_str(), &desc)) {
            LOG(ERROR) << "Failed to parse desc int: " << splitString[3];
            return;
            return;
        }
        }
            const std::string& nodeString = match.str(2);
        if (handle != desc) {
            if (!::android::base::ParseInt(nodeString.c_str(), &node)) {
                LOG(ERROR) << "Failed to parse node int: " << nodeString;
            return;
            return;
        }
        }
        if (!::android::base::ParseInt(splitString[5].c_str(), &node)) {
            LOG(ERROR) << "Failed to parse node int: " << splitString[5];
            return;
            return;
        }
        }
        return;
        LOG(INFO) << "Parsed the node: " << node;
    });
    });
    if (ret != OK) {
    if (ret != OK) {
        return ret;
        return ret;
    }
    }
    static const std::regex kClients("^\\s+node\\s+(\\d+).*proc\\s+([\\d+\\s*]*)");

    ret = scanBinderContext(servicePid, contextStr, [&](const std::string& line) {
    ret = scanBinderContext(servicePid, contextStr, [&](const std::string& line) {
        if (std::regex_search(line, match, kClients)) {
        if (!base::StartsWith(line, "  node")) return;
            const std::string nodeString = match.str(1);

        std::vector<std::string> splitString = base::Tokenize(line, " ");
        if (splitString.size() < 21) {
            LOG(ERROR) << "Failed to parse binder_logs node entry. Expecting size greater than 20, but got: " << splitString.size();
            return;
        }

        // remove the colon
        const std::string nodeString = splitString[1].substr(0, splitString[1].size() - 1);
        int32_t matchedNode;
        int32_t matchedNode;
        if (!::android::base::ParseInt(nodeString.c_str(), &matchedNode)) {
        if (!::android::base::ParseInt(nodeString.c_str(), &matchedNode)) {
            LOG(ERROR) << "Failed to parse node int: " << nodeString;
            LOG(ERROR) << "Failed to parse node int: " << nodeString;
            return;
            return;
        }
        }

        if (node != matchedNode) {
        if (node != matchedNode) {
            return;
            return;
        }
        }
            const std::string clients = match.str(2);
        bool pidsSection = false;
            for (const std::string& pidStr : base::Split(clients, " ")) {
        for (const auto& token : splitString) {
            if (token == "proc") {
                pidsSection = true;
            } else if (pidsSection == true) {
                int32_t pid;
                int32_t pid;
                if (!::android::base::ParseInt(pidStr, &pid)) {
                if (!::android::base::ParseInt(token.c_str(), &pid)) {
                    LOG(ERROR) << "Failed to parse PID int: " << token;
                    return;
                    return;
                }
                }
                pids->push_back(pid);
                pids->push_back(pid);
            }
            }
            return;
        }
        }
        return;
    });
    });
    return ret;
    return ret;
}
}