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