• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <android-base/parseint.h>
18 #include <android-base/strings.h>
19 #include <binder/Binder.h>
20 #include <sys/types.h>
21 #include <fstream>
22 #include <regex>
23 
24 #include <binderdebug/BinderDebug.h>
25 
26 namespace android {
27 
contextToString(BinderDebugContext context)28 static std::string contextToString(BinderDebugContext context) {
29     switch (context) {
30         case BinderDebugContext::BINDER:
31             return "binder";
32         case BinderDebugContext::HWBINDER:
33             return "hwbinder";
34         case BinderDebugContext::VNDBINDER:
35             return "vndbinder";
36         default:
37             return std::string();
38     }
39 }
40 
scanBinderContext(pid_t pid,const std::string & contextName,std::function<void (const std::string &)> eachLine)41 static status_t scanBinderContext(pid_t pid, const std::string& contextName,
42                                   std::function<void(const std::string&)> eachLine) {
43     std::ifstream ifs("/dev/binderfs/binder_logs/proc/" + std::to_string(pid));
44     if (!ifs.is_open()) {
45         ifs.open("/d/binder/proc/" + std::to_string(pid));
46         if (!ifs.is_open()) {
47             return -errno;
48         }
49     }
50     static const std::regex kContextLine("^context (\\w+)$");
51 
52     bool isDesiredContext = false;
53     std::string line;
54     std::smatch match;
55     while (getline(ifs, line)) {
56         if (std::regex_search(line, match, kContextLine)) {
57             isDesiredContext = match.str(1) == contextName;
58             continue;
59         }
60         if (!isDesiredContext) {
61             continue;
62         }
63         eachLine(line);
64     }
65     return OK;
66 }
67 
getBinderPidInfo(BinderDebugContext context,pid_t pid,BinderPidInfo * pidInfo)68 status_t getBinderPidInfo(BinderDebugContext context, pid_t pid, BinderPidInfo* pidInfo) {
69     std::smatch match;
70     static const std::regex kReferencePrefix("^\\s*node \\d+:\\s+u([0-9a-f]+)\\s+c([0-9a-f]+)\\s+");
71     static const std::regex kThreadPrefix("^\\s*thread \\d+:\\s+l\\s+(\\d)(\\d)");
72     std::string contextStr = contextToString(context);
73     status_t ret = scanBinderContext(pid, contextStr, [&](const std::string& line) {
74         if (std::regex_search(line, match, kReferencePrefix)) {
75             const std::string& ptrString = "0x" + match.str(2); // use number after c
76             uint64_t ptr;
77             if (!::android::base::ParseUint(ptrString.c_str(), &ptr)) {
78                 // Should not reach here, but just be tolerant.
79                 return;
80             }
81             const std::string proc = " proc ";
82             auto pos = line.rfind(proc);
83             if (pos != std::string::npos) {
84                 for (const std::string& pidStr : base::Split(line.substr(pos + proc.size()), " ")) {
85                     int32_t pid;
86                     if (!::android::base::ParseInt(pidStr, &pid)) {
87                         return;
88                     }
89                     pidInfo->refPids[ptr].push_back(pid);
90                 }
91             }
92 
93             return;
94         }
95         if (std::regex_search(line, match, kThreadPrefix)) {
96             // "1" is waiting in binder driver
97             // "2" is poll. It's impossible to tell if these are in use.
98             //     and HIDL default code doesn't use it.
99             bool isInUse = match.str(1) != "1";
100             // "0" is a thread that has called into binder
101             // "1" is looper thread
102             // "2" is main looper thread
103             bool isBinderThread = match.str(2) != "0";
104             if (!isBinderThread) {
105                 return;
106             }
107             if (isInUse) {
108                 pidInfo->threadUsage++;
109             }
110 
111             pidInfo->threadCount++;
112             return;
113         }
114         return;
115     });
116     return ret;
117 }
118 
119 } // namespace  android
120