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