• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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