1 /*
2 * Copyright (c) 2023 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 "appfreeze_manager.h"
16
17 #include <fcntl.h>
18 #include <sys/time.h>
19 #include <sys/wait.h>
20 #include <sys/types.h>
21 #include <sys/syscall.h>
22 #include <sys/stat.h>
23
24 #include "faultloggerd_client.h"
25 #include "file_ex.h"
26 #include "dfx_dump_catcher.h"
27 #include "directory_ex.h"
28 #include "hisysevent.h"
29 #include "hitrace_meter.h"
30 #include "parameter.h"
31 #include "singleton.h"
32
33 #include "app_mgr_client.h"
34 #include "hilog_wrapper.h"
35
36 namespace OHOS {
37 namespace AppExecFwk {
38 namespace {
39 constexpr char EVENT_UID[] = "UID";
40 constexpr char EVENT_PID[] = "PID";
41 constexpr char EVENT_MESSAGE[] = "MSG";
42 constexpr char EVENT_PACKAGE_NAME[] = "PACKAGE_NAME";
43 constexpr char EVENT_PROCESS_NAME[] = "PROCESS_NAME";
44 constexpr char EVENT_STACK[] = "STACK";
45 constexpr char BINDER_INFO[] = "BINDER_INFO";
46 constexpr int MAX_LAYER = 8;
47 }
48 std::shared_ptr<AppfreezeManager> AppfreezeManager::instance_ = nullptr;
49 ffrt::mutex AppfreezeManager::singletonMutex_;
50
AppfreezeManager()51 AppfreezeManager::AppfreezeManager()
52 {
53 name_ = "AppfreezeManager" + std::to_string(GetMilliseconds());
54 }
55
~AppfreezeManager()56 AppfreezeManager::~AppfreezeManager()
57 {
58 }
59
GetInstance()60 std::shared_ptr<AppfreezeManager> AppfreezeManager::GetInstance()
61 {
62 if (instance_ == nullptr) {
63 std::lock_guard<ffrt::mutex> lock(singletonMutex_);
64 if (instance_ == nullptr) {
65 instance_ = std::make_shared<AppfreezeManager>();
66 }
67 }
68 return instance_;
69 }
70
DestroyInstance()71 void AppfreezeManager::DestroyInstance()
72 {
73 std::lock_guard<ffrt::mutex> lock(singletonMutex_);
74 if (instance_ != nullptr) {
75 instance_.reset();
76 instance_ = nullptr;
77 }
78 }
79
GetMilliseconds()80 uint64_t AppfreezeManager::GetMilliseconds()
81 {
82 auto now = std::chrono::system_clock::now();
83 auto millisecs = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch());
84 return millisecs.count();
85 }
86
IsHandleAppfreeze(const std::string & bundleName)87 bool AppfreezeManager::IsHandleAppfreeze(const std::string& bundleName)
88 {
89 if (bundleName.empty()) {
90 return true;
91 }
92 return !DelayedSingleton<AppExecFwk::AppMgrClient>::GetInstance()->IsAttachDebug(bundleName);
93 }
94
AppfreezeHandle(const FaultData & faultData,const AppfreezeManager::AppInfo & appInfo)95 int AppfreezeManager::AppfreezeHandle(const FaultData& faultData, const AppfreezeManager::AppInfo& appInfo)
96 {
97 HILOG_DEBUG("called %{public}s, bundleName %{public}s, name_ %{public}s",
98 faultData.errorObject.name.c_str(), appInfo.bundleName.c_str(), name_.c_str());
99 if (!IsHandleAppfreeze(appInfo.bundleName)) {
100 return -1;
101 }
102 HITRACE_METER_FMT(HITRACE_TAG_APP, "AppfreezeHandler:%{public}s bundleName:%{public}s",
103 faultData.errorObject.name.c_str(), appInfo.bundleName.c_str());
104 if (faultData.errorObject.name == AppFreezeType::APP_INPUT_BLOCK) {
105 AcquireStack(faultData, appInfo);
106 } else {
107 NotifyANR(faultData, appInfo, "");
108 }
109 return 0;
110 }
111
AppfreezeHandleWithStack(const FaultData & faultData,const AppfreezeManager::AppInfo & appInfo)112 int AppfreezeManager::AppfreezeHandleWithStack(const FaultData& faultData, const AppfreezeManager::AppInfo& appInfo)
113 {
114 HILOG_DEBUG("called %{public}s, bundleName %{public}s, name_ %{public}s",
115 faultData.errorObject.name.c_str(), appInfo.bundleName.c_str(), name_.c_str());
116 if (!IsHandleAppfreeze(appInfo.bundleName)) {
117 return -1;
118 }
119 FaultData faultNotifyData;
120 faultNotifyData.errorObject.name = faultData.errorObject.name;
121 faultNotifyData.errorObject.message = faultData.errorObject.message;
122 faultNotifyData.errorObject.stack = faultData.errorObject.stack;
123 faultNotifyData.faultType = FaultDataType::APP_FREEZE;
124
125 HITRACE_METER_FMT(HITRACE_TAG_APP, "AppfreezeHandleWithStack pid:%d-name:%s",
126 appInfo.pid, faultData.errorObject.name.c_str());
127
128 if (faultData.errorObject.name == AppFreezeType::LIFECYCLE_HALF_TIMEOUT
129 || faultData.errorObject.name == AppFreezeType::LIFECYCLE_TIMEOUT) {
130 faultNotifyData.errorObject.stack += CatcherStacktrace(appInfo.pid);
131 } else {
132 faultNotifyData.errorObject.stack += CatchJsonStacktrace(appInfo.pid);
133 }
134
135 if (faultNotifyData.errorObject.name == AppFreezeType::APP_INPUT_BLOCK) {
136 AcquireStack(faultNotifyData, appInfo);
137 } else {
138 NotifyANR(faultNotifyData, appInfo, "");
139 }
140 return 0;
141 }
142
LifecycleTimeoutHandle(const ParamInfo & info,std::unique_ptr<FreezeUtil::LifecycleFlow> flow)143 int AppfreezeManager::LifecycleTimeoutHandle(const ParamInfo& info, std::unique_ptr<FreezeUtil::LifecycleFlow> flow)
144 {
145 if (info.typeId != AppfreezeManager::TypeAttribute::CRITICAL_TIMEOUT) {
146 return -1;
147 }
148 if (!IsHandleAppfreeze(info.bundleName)) {
149 return -1;
150 }
151 if (info.eventName != AppFreezeType::LIFECYCLE_TIMEOUT &&
152 info.eventName != AppFreezeType::LIFECYCLE_HALF_TIMEOUT) {
153 return -1;
154 }
155 HILOG_DEBUG("LifecycleTimeoutHandle called %{public}s, name_ %{public}s",
156 info.bundleName.c_str(), name_.c_str());
157 HITRACE_METER_FMT(HITRACE_TAG_APP, "LifecycleTimeoutHandle:%{public}s bundleName:%{public}s",
158 info.eventName.c_str(), info.bundleName.c_str());
159 AppFaultDataBySA faultDataSA;
160 faultDataSA.errorObject.name = info.eventName;
161 faultDataSA.errorObject.message = info.msg;
162 faultDataSA.faultType = FaultDataType::APP_FREEZE;
163 faultDataSA.timeoutMarkers = "notifyFault" +
164 std::to_string(info.pid) +
165 "-" + std::to_string(GetMilliseconds());
166 faultDataSA.pid = info.pid;
167 if (flow != nullptr && flow->state != AbilityRuntime::FreezeUtil::TimeoutState::UNKNOWN) {
168 faultDataSA.token = flow->token;
169 faultDataSA.state = static_cast<uint32_t>(flow->state);
170 }
171 DelayedSingleton<AppExecFwk::AppMgrClient>::GetInstance()->NotifyAppFaultBySA(faultDataSA);
172 return 0;
173 }
174
AcquireStack(const FaultData & faultData,const AppfreezeManager::AppInfo & appInfo)175 int AppfreezeManager::AcquireStack(const FaultData& faultData, const AppfreezeManager::AppInfo& appInfo)
176 {
177 int ret = 0;
178 int pid = appInfo.pid;
179 FaultData faultNotifyData;
180 faultNotifyData.errorObject.name = faultData.errorObject.name;
181 faultNotifyData.errorObject.message = faultData.errorObject.message;
182 faultNotifyData.errorObject.stack = faultData.errorObject.stack;
183 faultNotifyData.faultType = FaultDataType::APP_FREEZE;
184 std::string binderInfo;
185 std::set<int> pids = GetBinderPeerPids(binderInfo, pid);
186 if (pids.empty()) {
187 binderInfo += "PeerBinder pids is empty\n";
188 }
189 for (auto& pidTemp : pids) {
190 HILOG_INFO("pidTemp pids:%{public}d", pidTemp);
191 if (pidTemp != pid) {
192 std::string content = "PeerBinder catcher stacktrace for pid : " + std::to_string(pidTemp) + "\n";
193 content += CatcherStacktrace(pidTemp);
194 binderInfo += content;
195 }
196 }
197
198 ret = NotifyANR(faultNotifyData, appInfo, binderInfo);
199 return ret;
200 }
201
NotifyANR(const FaultData & faultData,const AppfreezeManager::AppInfo & appInfo,const std::string & binderInfo)202 int AppfreezeManager::NotifyANR(const FaultData& faultData, const AppfreezeManager::AppInfo& appInfo,
203 const std::string& binderInfo)
204 {
205 int ret = HiSysEventWrite(OHOS::HiviewDFX::HiSysEvent::Domain::AAFWK, faultData.errorObject.name,
206 OHOS::HiviewDFX::HiSysEvent::EventType::FAULT, EVENT_UID, appInfo.uid,
207 EVENT_PID, appInfo.pid, EVENT_PACKAGE_NAME, appInfo.bundleName,
208 EVENT_PROCESS_NAME, appInfo.processName, EVENT_MESSAGE,
209 faultData.errorObject.message, EVENT_STACK, faultData.errorObject.stack, BINDER_INFO, binderInfo);
210
211 HILOG_INFO("reportEvent:%{public}s, pid:%{public}d, bundleName:%{public}s, "
212 "hisysevent write ret = %{public}d.",
213 faultData.errorObject.name.c_str(), appInfo.pid, appInfo.bundleName.c_str(), ret);
214 return 0;
215 }
216
BinderParser(std::ifstream & fin,std::string & stack) const217 std::map<int, std::set<int>> AppfreezeManager::BinderParser(std::ifstream& fin, std::string& stack) const
218 {
219 std::map<int, std::set<int>> binderInfo;
220 const int decimal = 10;
221 std::string line;
222 bool isBinderMatchup = false;
223 HILOG_INFO("start");
224 stack += "BinderCatcher --\n\n";
225 while (getline(fin, line)) {
226 stack += line + "\n";
227 if (isBinderMatchup) {
228 continue;
229 }
230
231 if (line.find("async") != std::string::npos) {
232 continue;
233 }
234
235 std::istringstream lineStream(line);
236 std::vector<std::string> strList;
237 std::string tmpstr;
238 while (lineStream >> tmpstr) {
239 strList.push_back(tmpstr);
240 }
241
242 auto SplitPhase = [](const std::string& str, uint16_t index) -> std::string {
243 std::vector<std::string> strings;
244 SplitStr(str, ":", strings);
245 if (index < strings.size()) {
246 return strings[index];
247 }
248 return "";
249 };
250
251 if (strList.size() == 7) { // 7: valid array size
252 // 2: peer id,
253 std::string server = SplitPhase(strList[2], 0);
254 // 0: local id,
255 std::string client = SplitPhase(strList[0], 0);
256 // 5: wait time, s
257 std::string wait = SplitPhase(strList[5], 1);
258 if (server == "" || client == "" || wait == "") {
259 continue;
260 }
261 int serverNum = std::strtol(server.c_str(), nullptr, decimal);
262 int clientNum = std::strtol(client.c_str(), nullptr, decimal);
263 int waitNum = std::strtol(wait.c_str(), nullptr, decimal);
264 HILOG_INFO("server:%{public}d, client:%{public}d, wait:%{public}d", serverNum, clientNum, waitNum);
265 binderInfo[clientNum].insert(serverNum);
266 }
267 if (line.find("context") != line.npos) {
268 isBinderMatchup = true;
269 }
270 }
271 HILOG_INFO("binderInfo size: %{public}zu", binderInfo.size());
272 return binderInfo;
273 }
274
GetBinderPeerPids(std::string & stack,int pid) const275 std::set<int> AppfreezeManager::GetBinderPeerPids(std::string& stack, int pid) const
276 {
277 std::set<int> pids;
278 std::ifstream fin;
279 std::string path = LOGGER_DEBUG_PROC_PATH;
280 char resolvePath[PATH_MAX] = {0};
281 if (realpath(path.c_str(), resolvePath) == nullptr) {
282 HILOG_ERROR("GetBinderPeerPids realpath error");
283 return pids;
284 }
285 fin.open(resolvePath);
286 if (!fin.is_open()) {
287 HILOG_ERROR("open file failed, %{public}s.", resolvePath);
288 stack += "open file failed :" + path + "\r\n";
289 return pids;
290 }
291
292 stack += "\n\nPeerBinderCatcher -- pid==" + std::to_string(pid) + "\n\n";
293 std::map<int, std::set<int>> binderInfo = BinderParser(fin, stack);
294 fin.close();
295
296 if (binderInfo.size() == 0 || binderInfo.find(pid) == binderInfo.end()) {
297 return pids;
298 }
299
300 ParseBinderPids(binderInfo, pids, pid, 0);
301 for (auto& each : pids) {
302 HILOG_DEBUG("each pids:%{public}d", each);
303 }
304 return pids;
305 }
306
ParseBinderPids(const std::map<int,std::set<int>> & binderInfo,std::set<int> & pids,int pid,int layer) const307 void AppfreezeManager::ParseBinderPids(const std::map<int, std::set<int>>& binderInfo,
308 std::set<int>& pids, int pid, int layer) const
309 {
310 auto it = binderInfo.find(pid);
311 layer++;
312 if (layer >= MAX_LAYER) {
313 return;
314 }
315 if (it != binderInfo.end()) {
316 for (auto& each : it->second) {
317 pids.insert(each);
318 ParseBinderPids(binderInfo, pids, each, layer);
319 }
320 }
321 }
322
CatchJsonStacktrace(int pid) const323 std::string AppfreezeManager::CatchJsonStacktrace(int pid) const
324 {
325 HITRACE_METER_FMT(HITRACE_TAG_APP, "CatchJsonStacktrace pid:%d", pid);
326 HiviewDFX::DfxDumpCatcher dumplog;
327 std::string ret;
328 std::string msg;
329 size_t defaultMaxFaultNum = 256;
330 if (!dumplog.DumpCatch(pid, 0, msg, defaultMaxFaultNum, true)) {
331 ret = "Failed to dump stacktrace for " + std::to_string(pid) + "\n" + msg;
332 } else {
333 ret = msg;
334 }
335 return ret;
336 }
337
CatcherStacktrace(int pid) const338 std::string AppfreezeManager::CatcherStacktrace(int pid) const
339 {
340 HITRACE_METER_FMT(HITRACE_TAG_APP, "CatcherStacktrace pid:%d", pid);
341 HiviewDFX::DfxDumpCatcher dumplog;
342 std::string ret;
343 std::string msg;
344 if (!dumplog.DumpCatch(pid, 0, msg)) {
345 ret = "Failed to dump stacktrace for " + std::to_string(pid) + "\n" + msg;
346 } else {
347 ret = msg;
348 }
349 return ret;
350 }
351
IsProcessDebug(int32_t pid,std::string processName)352 bool AppfreezeManager::IsProcessDebug(int32_t pid, std::string processName)
353 {
354 const int buffSize = 128;
355 char param[buffSize] = {0};
356 std::string filter = "hiviewdfx.freeze.filter." + processName;
357 GetParameter(filter.c_str(), "", param, buffSize - 1);
358 int32_t debugPid = atoi(param);
359 if (debugPid == pid) {
360 return true;
361 }
362 return false;
363 }
364 } // namespace AAFwk
365 } // namespace OHOS