1 /*
2 * Copyright (c) 2024 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
16 #include "hicollie.h"
17
18 #include <unistd.h>
19 #include <string>
20 #include <sys/syscall.h>
21 #include "watchdog.h"
22 #include "report_data.h"
23 #include "xcollie_utils.h"
24 #include "iservice_registry.h"
25 #include "iremote_object.h"
26
27 namespace OHOS {
28 namespace HiviewDFX {
29 DECLARE_INTERFACE_DESCRIPTOR(u"ohos.appexecfwk.AppMgr");
30
31 #ifdef SUPPORT_ASAN
32 constexpr uint32_t CHECK_INTERVAL_TIME = 45000;
33 #else
34 constexpr uint32_t CHECK_INTERVAL_TIME = 3000;
35 #endif
36 constexpr uint32_t INI_TIMER_FIRST_SECOND = 10000;
37 constexpr uint32_t NOTIFY_APP_FAULT = 38;
38 constexpr uint32_t APP_MGR_SERVICE_ID = 501;
39
40 static int32_t g_bussinessTid = 0;
41
IsAppMainThread()42 bool IsAppMainThread()
43 {
44 static int pid = getpid();
45 static uint64_t uid = getuid();
46 if (pid == gettid() && uid >= MIN_APP_UID) {
47 return true;
48 }
49 return false;
50 }
51
NotifyAppFault(const OHOS::HiviewDFX::ReportData & reportData)52 int32_t NotifyAppFault(const OHOS::HiviewDFX::ReportData &reportData)
53 {
54 XCOLLIE_LOGD("called.");
55 auto systemAbilityMgr = OHOS::SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
56 if (systemAbilityMgr == nullptr) {
57 XCOLLIE_LOGE("ReportData failed to get system ability manager.");
58 return -1;
59 }
60 auto appMgrService = systemAbilityMgr->GetSystemAbility(APP_MGR_SERVICE_ID);
61 if (appMgrService == nullptr) {
62 XCOLLIE_LOGE("ReportData failed to find APP_MGR_SERVICE_ID.");
63 return -1;
64 }
65 OHOS::MessageParcel data;
66 OHOS::MessageParcel reply;
67 OHOS::MessageOption option;
68 if (!data.WriteInterfaceToken(GetDescriptor())) {
69 XCOLLIE_LOGE("ReportData failed to WriteInterfaceToken.");
70 return -1;
71 }
72 if (!data.WriteParcelable(&reportData)) {
73 XCOLLIE_LOGE("ReportData write reportData failed.");
74 return -1;
75 }
76 auto ret = appMgrService->SendRequest(NOTIFY_APP_FAULT, data, reply, option);
77 if (ret != OHOS::NO_ERROR) {
78 XCOLLIE_LOGE("ReportData Send request failed with error code: %{public}d", ret);
79 return -1;
80 }
81 return reply.ReadInt32();
82 }
83
Report(bool * isSixSecond)84 int Report(bool* isSixSecond)
85 {
86 OHOS::HiviewDFX::ReportData reportData;
87 reportData.errorObject.message = "Bussiness thread is not response!";
88 reportData.faultType = OHOS::HiviewDFX::FaultDataType::APP_FREEZE;
89
90 if (*isSixSecond) {
91 reportData.errorObject.name = "BUSSINESS_THREAD_BLOCK_6S";
92 reportData.forceExit = true;
93 *isSixSecond = false;
94 } else {
95 reportData.errorObject.name = "BUSSINESS_THREAD_BLOCK_3S";
96 reportData.forceExit = false;
97 *isSixSecond = true;
98 }
99 reportData.timeoutMarkers = "";
100 reportData.errorObject.stack = "";
101 reportData.notifyApp = false;
102 reportData.waitSaveState = false;
103 reportData.tid = g_bussinessTid;
104 auto result = NotifyAppFault(reportData);
105 XCOLLIE_LOGI("OH_HiCollie_Report result: %{public}d, bussinessTid: %{public}d", result, reportData.tid);
106 return result;
107 }
108 } // end of namespace HiviewDFX
109 } // end of namespace OHOS
110
OH_HiCollie_Init_StuckDetection(OH_HiCollie_Task task)111 HiCollie_ErrorCode OH_HiCollie_Init_StuckDetection(OH_HiCollie_Task task)
112 {
113 if (OHOS::HiviewDFX::IsAppMainThread()) {
114 return HICOLLIE_WRONG_THREAD_CONTEXT;
115 }
116 if (!task) {
117 OHOS::HiviewDFX::Watchdog::GetInstance().RemovePeriodicalTask("BussinessWatchdog");
118 } else {
119 OHOS::HiviewDFX::g_bussinessTid = syscall(SYS_gettid);
120 OHOS::HiviewDFX::Watchdog::GetInstance().RunPeriodicalTask("BussinessWatchdog", task,
121 OHOS::HiviewDFX::CHECK_INTERVAL_TIME, OHOS::HiviewDFX::INI_TIMER_FIRST_SECOND);
122 OHOS::HiviewDFX::Watchdog::GetInstance().RemovePeriodicalTask("AppkitWatchdog");
123 }
124 return HICOLLIE_SUCCESS;
125 }
126
OH_HiCollie_Init_JankDetection(OH_HiCollie_BeginFunc * beginFunc,OH_HiCollie_EndFunc * endFunc,HiCollie_DetectionParam param)127 HiCollie_ErrorCode OH_HiCollie_Init_JankDetection(OH_HiCollie_BeginFunc* beginFunc,
128 OH_HiCollie_EndFunc* endFunc, HiCollie_DetectionParam param)
129 {
130 if (OHOS::HiviewDFX::IsAppMainThread()) {
131 return HICOLLIE_WRONG_THREAD_CONTEXT;
132 }
133 if ((!beginFunc && endFunc) || (beginFunc && !endFunc)) {
134 return HICOLLIE_INVALID_ARGUMENT;
135 }
136 OHOS::HiviewDFX::Watchdog::GetInstance().InitMainLooperWatcher(beginFunc, endFunc);
137 return HICOLLIE_SUCCESS;
138 }
139
OH_HiCollie_Report(bool * isSixSecond)140 HiCollie_ErrorCode OH_HiCollie_Report(bool* isSixSecond)
141 {
142 if (OHOS::HiviewDFX::IsAppMainThread()) {
143 return HICOLLIE_WRONG_THREAD_CONTEXT;
144 }
145 if (isSixSecond == nullptr) {
146 return HICOLLIE_INVALID_ARGUMENT;
147 }
148 if (OHOS::HiviewDFX::Watchdog::GetInstance().GetAppDebug()) {
149 XCOLLIE_LOGD("Bussiness: Get appDebug state is true");
150 return HICOLLIE_SUCCESS;
151 }
152 if (OHOS::HiviewDFX::Report(isSixSecond) != 0) {
153 return HICOLLIE_REMOTE_FAILED;
154 }
155 return HICOLLIE_SUCCESS;
156 }
157