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