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