1 /*
2 * Copyright (C) 2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15 #include "peer_binder_catcher.h"
16
17 #include "securec.h"
18
19 #include "common_utils.h"
20 #include "file_util.h"
21 #include "log_catcher_utils.h"
22 #include "logger.h"
23 #include "string_util.h"
24
25 #include "open_stacktrace_catcher.h"
26 namespace OHOS {
27 namespace HiviewDFX {
28 DEFINE_LOG_LABEL(0xD002D01, "EventLogger-PeerBinderCatcher");
PeerBinderCatcher()29 PeerBinderCatcher::PeerBinderCatcher() : EventLogCatcher()
30 {
31 name_ = "PeerBinderCatcher";
32 }
33
Initialize(const std::string & strParam1,int pid,int layer)34 bool PeerBinderCatcher::Initialize(const std::string& strParam1, int pid, int layer)
35 {
36 pid_ = pid;
37 layer_ = layer;
38 char buf[BUF_SIZE_512] = {0};
39 int ret = snprintf_s(buf, BUF_SIZE_512, BUF_SIZE_512 - 1,
40 "PeerBinderCatcher -- pid==%d layer_ == %d\n", pid_, layer_);
41 if (ret > 0) {
42 description_ = buf;
43 }
44 return true;
45 }
46
Init(std::shared_ptr<SysEvent> event,const std::string & filePath)47 void PeerBinderCatcher::Init(std::shared_ptr<SysEvent> event, const std::string& filePath)
48 {
49 event_ = event;
50 if ((filePath != "") && FileUtil::FileExists(filePath)) {
51 binderPath_ = filePath;
52 }
53 }
54
Catch(int fd)55 int PeerBinderCatcher::Catch(int fd)
56 {
57 if (pid_ <= 0) {
58 return -1;
59 }
60
61 auto originSize = GetFdSize(fd);
62
63 if (!FileUtil::FileExists(binderPath_)) {
64 std::string content = binderPath_ + " : file isn't exists\r\n";
65 FileUtil::SaveStringToFd(fd, content);
66 return -1;
67 }
68
69 std::set<int> pids = GetBinderPeerPids(fd);
70 if (pids.empty()) {
71 std::string content = "PeerBinder pids is empty\r\n";
72 FileUtil::SaveStringToFd(fd, content);
73 }
74
75 std::string pidStr = "";
76 for (auto pidTemp : pids) {
77 if (pidTemp != pid_) {
78 CatcherStacktrace(fd, pidTemp);
79 pidStr += "," + std::to_string(pidTemp);
80 }
81 }
82
83 if (event_ != nullptr) {
84 event_->SetValue(LOGGER_EVENT_PEERBINDER, StringUtil::TrimStr(pidStr, ','));
85 }
86
87 logSize_ = GetFdSize(fd) - originSize;
88 return logSize_;
89 }
90
BinderInfoParser(std::ifstream & fin,int fd) const91 std::map<int, std::list<PeerBinderCatcher::BinderInfo>> PeerBinderCatcher::BinderInfoParser(
92 std::ifstream& fin, int fd) const
93 {
94 std::map<int, std::list<BinderInfo>> manager;
95 const int DECIMAL = 10;
96 std::string line;
97 bool findBinderHeader = false;
98 FileUtil::SaveStringToFd(fd, "\nBinderCatcher --\n\n");
99 while (getline(fin, line)) {
100 FileUtil::SaveStringToFd(fd, line + "\n");
101 if (findBinderHeader) {
102 continue;
103 }
104
105 if (line.find("async") != std::string::npos) {
106 continue;
107 }
108
109 std::istringstream lineStream(line);
110 std::vector<std::string> strList;
111 std::string tmpstr;
112 while (lineStream >> tmpstr) {
113 strList.push_back(tmpstr);
114 }
115
116 auto stringSplit = [](const std::string& str, uint16_t index) -> std::string {
117 std::vector<std::string> strings;
118 StringUtil::SplitStr(str, ":", strings);
119 if (index < strings.size()) {
120 return strings[index];
121 }
122 return "";
123 };
124
125 if (strList.size() == 7) { // 7: valid array size
126 BinderInfo info = {0};
127 // 2: binder peer id,
128 std::string server = stringSplit(strList[2], 0);
129 // 0: binder local id,
130 std::string client = stringSplit(strList[0], 0);
131 // 5: binder wait time, s
132 std::string wait = stringSplit(strList[5], 1);
133 if (server == "" || client == "" || wait == "") {
134 continue;
135 }
136 info.server = std::strtol(server.c_str(), nullptr, DECIMAL);
137 info.client = std::strtol(client.c_str(), nullptr, DECIMAL);
138 info.wait = std::strtol(wait.c_str(), nullptr, DECIMAL);
139 HIVIEW_LOGI("server:%{public}d, client:%{public}d, wait:%{public}d", info.server, info.client, info.wait);
140 manager[info.client].push_back(info);
141 }
142 if (line.find("context") != line.npos) {
143 findBinderHeader = true;
144 }
145 }
146 FileUtil::SaveStringToFd(fd, "\n\nPeerBinder Stacktrace --\n\n");
147 HIVIEW_LOGI("manager size: %{public}zu", manager.size());
148 return manager;
149 }
150
GetBinderPeerPids(int fd) const151 std::set<int> PeerBinderCatcher::GetBinderPeerPids(int fd) const
152 {
153 std::set<int> pids;
154 std::ifstream fin;
155 std::string path = binderPath_;
156 fin.open(path.c_str());
157 if (!fin.is_open()) {
158 HIVIEW_LOGE("open binder file failed, %{public}s.", path.c_str());
159 std::string content = "open binder file failed :" + path + "\r\n";
160 FileUtil::SaveStringToFd(fd, content);
161 return pids;
162 }
163
164 std::map<int, std::list<PeerBinderCatcher::BinderInfo>> manager = BinderInfoParser(fin, fd);
165 fin.close();
166
167 if (manager.size() == 0 || manager.find(pid_) == manager.end()) {
168 return pids;
169 }
170
171 if (layer_ == LOGGER_BINDER_STACK_ONE) {
172 for (auto each : manager[pid_]) {
173 pids.insert(each.server);
174 }
175 } else if (layer_ == LOGGER_BINDER_STACK_ALL) {
176 ParseBinderCallChain(manager, pids, pid_);
177 }
178 return pids;
179 }
180
ParseBinderCallChain(std::map<int,std::list<PeerBinderCatcher::BinderInfo>> & manager,std::set<int> & pids,int pid) const181 void PeerBinderCatcher::ParseBinderCallChain(std::map<int, std::list<PeerBinderCatcher::BinderInfo>>& manager,
182 std::set<int>& pids, int pid) const
183 {
184 for (auto& each : manager[pid]) {
185 if (pids.find(each.server) != pids.end()) {
186 continue;
187 }
188 pids.insert(each.server);
189 ParseBinderCallChain(manager, pids, each.server);
190 }
191 }
192
CatcherStacktrace(int fd,int pid) const193 void PeerBinderCatcher::CatcherStacktrace(int fd, int pid) const
194 {
195 std::string content = "PeerBinderCatcher start catcher stacktrace for pid : " + std::to_string(pid) + "\r\n";
196 FileUtil::SaveStringToFd(fd, content);
197
198 LogCatcherUtils::DumpStacktrace(fd, pid);
199 }
200 } // namespace HiviewDFX
201 } // namespace OHOS