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