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