• 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/logging.h>
18 #include <android-base/parseint.h>
19 #include <android-base/strings.h>
20 #include <binder/Binder.h>
21 #include <sys/types.h>
22 #include <fstream>
23 #include <regex>
24 
25 #include <binderdebug/BinderDebug.h>
26 
27 namespace android {
28 
contextToString(BinderDebugContext context)29 static std::string contextToString(BinderDebugContext context) {
30     switch (context) {
31         case BinderDebugContext::BINDER:
32             return "binder";
33         case BinderDebugContext::HWBINDER:
34             return "hwbinder";
35         case BinderDebugContext::VNDBINDER:
36             return "vndbinder";
37         default:
38             return std::string();
39     }
40 }
41 
scanBinderContext(pid_t pid,const std::string & contextName,std::function<void (const std::string &)> eachLine)42 static status_t scanBinderContext(pid_t pid, const std::string& contextName,
43                                   std::function<void(const std::string&)> eachLine) {
44     std::ifstream ifs("/dev/binderfs/binder_logs/proc/" + std::to_string(pid));
45     if (!ifs.is_open()) {
46         ifs.open("/d/binder/proc/" + std::to_string(pid));
47         if (!ifs.is_open()) {
48             return -errno;
49         }
50     }
51     static const std::regex kContextLine("^context (\\w+)$");
52 
53     bool isDesiredContext = false;
54     std::string line;
55     std::smatch match;
56     while (getline(ifs, line)) {
57         if (std::regex_search(line, match, kContextLine)) {
58             isDesiredContext = match.str(1) == contextName;
59             continue;
60         }
61         if (!isDesiredContext) {
62             continue;
63         }
64         eachLine(line);
65     }
66     return OK;
67 }
68 
getBinderPidInfo(BinderDebugContext context,pid_t pid,BinderPidInfo * pidInfo)69 status_t getBinderPidInfo(BinderDebugContext context, pid_t pid, BinderPidInfo* pidInfo) {
70     std::smatch match;
71     static const std::regex kReferencePrefix("^\\s*node \\d+:\\s+u([0-9a-f]+)\\s+c([0-9a-f]+)\\s+");
72     static const std::regex kThreadPrefix("^\\s*thread \\d+:\\s+l\\s+(\\d)(\\d)");
73     std::string contextStr = contextToString(context);
74     status_t ret = scanBinderContext(pid, contextStr, [&](const std::string& line) {
75         if (std::regex_search(line, match, kReferencePrefix)) {
76             const std::string& ptrString = "0x" + match.str(2); // use number after c
77             uint64_t ptr;
78             if (!::android::base::ParseUint(ptrString.c_str(), &ptr)) {
79                 // Should not reach here, but just be tolerant.
80                 return;
81             }
82             const std::string proc = " proc ";
83             auto pos = line.rfind(proc);
84             if (pos != std::string::npos) {
85                 for (const std::string& pidStr : base::Split(line.substr(pos + proc.size()), " ")) {
86                     int32_t pid;
87                     if (!::android::base::ParseInt(pidStr, &pid)) {
88                         return;
89                     }
90                     pidInfo->refPids[ptr].push_back(pid);
91                 }
92             }
93 
94             return;
95         }
96         if (std::regex_search(line, match, kThreadPrefix)) {
97             // "1" is waiting in binder driver
98             // "2" is poll. It's impossible to tell if these are in use.
99             //     and HIDL default code doesn't use it.
100             bool isInUse = match.str(1) != "1";
101             // "0" is a thread that has called into binder
102             // "1" is looper thread
103             // "2" is main looper thread
104             bool isBinderThread = match.str(2) != "0";
105             if (!isBinderThread) {
106                 return;
107             }
108             if (isInUse) {
109                 pidInfo->threadUsage++;
110             }
111 
112             pidInfo->threadCount++;
113             return;
114         }
115         return;
116     });
117     return ret;
118 }
119 
getBinderClientPids(BinderDebugContext context,pid_t pid,pid_t servicePid,int32_t handle,std::vector<pid_t> * pids)120 status_t getBinderClientPids(BinderDebugContext context, pid_t pid, pid_t servicePid,
121                              int32_t handle, std::vector<pid_t>* pids) {
122     std::smatch match;
123     static const std::regex kNodeNumber("^\\s+ref \\d+:\\s+desc\\s+(\\d+)\\s+node\\s+(\\d+).*");
124     std::string contextStr = contextToString(context);
125     int32_t node;
126     status_t ret = scanBinderContext(pid, contextStr, [&](const std::string& line) {
127         if (std::regex_search(line, match, kNodeNumber)) {
128             const std::string& descString = match.str(1);
129             int32_t desc;
130             if (!::android::base::ParseInt(descString.c_str(), &desc)) {
131                 LOG(ERROR) << "Failed to parse desc int: " << descString;
132                 return;
133             }
134             if (handle != desc) {
135                 return;
136             }
137             const std::string& nodeString = match.str(2);
138             if (!::android::base::ParseInt(nodeString.c_str(), &node)) {
139                 LOG(ERROR) << "Failed to parse node int: " << nodeString;
140                 return;
141             }
142             return;
143         }
144         return;
145     });
146     if (ret != OK) {
147         return ret;
148     }
149     static const std::regex kClients("^\\s+node\\s+(\\d+).*proc\\s+([\\d+\\s*]*)");
150     ret = scanBinderContext(servicePid, contextStr, [&](const std::string& line) {
151         if (std::regex_search(line, match, kClients)) {
152             const std::string nodeString = match.str(1);
153             int32_t matchedNode;
154             if (!::android::base::ParseInt(nodeString.c_str(), &matchedNode)) {
155                 LOG(ERROR) << "Failed to parse node int: " << nodeString;
156                 return;
157             }
158             if (node != matchedNode) {
159                 return;
160             }
161             const std::string clients = match.str(2);
162             for (const std::string& pidStr : base::Split(clients, " ")) {
163                 int32_t pid;
164                 if (!::android::base::ParseInt(pidStr, &pid)) {
165                     return;
166                 }
167                 pids->push_back(pid);
168             }
169             return;
170         }
171         return;
172     });
173     return ret;
174 }
175 
176 } // namespace  android
177