• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.h"
24 #include "xcollie_define.h"
25 #include "xcollie_utils.h"
26 #include "iservice_registry.h"
27 #include "iremote_object.h"
28 
29 namespace OHOS {
30 namespace HiviewDFX {
31 DECLARE_INTERFACE_DESCRIPTOR(u"ohos.appexecfwk.AppMgr");
32 
33 #ifdef SUPPORT_ASAN
34 constexpr uint32_t CHECK_INTERVAL_TIME = 45000;
35 #else
36 constexpr uint32_t CHECK_INTERVAL_TIME = 3000;
37 #endif
38 constexpr uint32_t INI_TIMER_FIRST_SECOND = 10000;
39 constexpr uint32_t NOTIFY_APP_FAULT = 38;
40 constexpr uint32_t APP_MGR_SERVICE_ID = 501;
41 constexpr uint32_t TIME_S_TO_MS = 1000;
42 constexpr uint32_t MAX_TIMEOUT = 15000;
43 constexpr uint32_t RATIO = 2;
44 
45 static int32_t g_bussinessTid = 0;
46 static uint32_t g_stuckTimeout = 0;
47 
IsAppMainThread()48 bool IsAppMainThread()
49 {
50     static int pid = getpid();
51     static uint64_t uid = getuid();
52     if (pid == gettid() && uid >= MIN_APP_UID) {
53         return true;
54     }
55     return false;
56 }
57 
NotifyAppFault(const OHOS::HiviewDFX::ReportData & reportData)58 int32_t NotifyAppFault(const OHOS::HiviewDFX::ReportData &reportData)
59 {
60     XCOLLIE_LOGD("called.");
61     auto systemAbilityMgr = OHOS::SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
62     if (systemAbilityMgr == nullptr) {
63         XCOLLIE_LOGE("ReportData failed to get system ability manager.");
64         return -1;
65     }
66     auto appMgrService = systemAbilityMgr->GetSystemAbility(APP_MGR_SERVICE_ID);
67     if (appMgrService == nullptr) {
68         XCOLLIE_LOGE("ReportData failed to find APP_MGR_SERVICE_ID.");
69         return -1;
70     }
71     OHOS::MessageParcel data;
72     OHOS::MessageParcel reply;
73     OHOS::MessageOption option;
74     if (!data.WriteInterfaceToken(GetDescriptor())) {
75         XCOLLIE_LOGE("ReportData failed to WriteInterfaceToken.");
76         return -1;
77     }
78     if (!data.WriteParcelable(&reportData)) {
79         XCOLLIE_LOGE("ReportData write reportData failed.");
80         return -1;
81     }
82     auto ret = appMgrService->SendRequest(NOTIFY_APP_FAULT, data, reply, option);
83     if (ret != OHOS::NO_ERROR) {
84         XCOLLIE_LOGE("ReportData Send request failed with error code: %{public}d", ret);
85         return -1;
86     }
87     return reply.ReadInt32();
88 }
89 
Report(bool * isSixSecond)90 int Report(bool* isSixSecond)
91 {
92     OHOS::HiviewDFX::ReportData reportData;
93     reportData.faultType = OHOS::HiviewDFX::FaultDataType::APP_FREEZE;
94 
95     if (*isSixSecond) {
96         reportData.errorObject.name = "BUSSINESS_THREAD_BLOCK_6S";
97         reportData.forceExit = true;
98         *isSixSecond = false;
99         g_stuckTimeout = g_stuckTimeout * RATIO;
100     } else {
101         reportData.errorObject.name = "BUSSINESS_THREAD_BLOCK_3S";
102         reportData.forceExit = false;
103         *isSixSecond = true;
104     }
105     std::string timeStamp = "\nFaultTime:" + FormatTime("%Y-%m-%d %H:%M:%S") + "\n";
106     reportData.errorObject.message = timeStamp +
107         "Bussiness thread is not response, timeout " + std::to_string(g_stuckTimeout) + "ms.\n";
108     reportData.timeoutMarkers = "";
109     reportData.errorObject.stack = "";
110     reportData.notifyApp = false;
111     reportData.waitSaveState = false;
112     reportData.stuckTimeout = g_stuckTimeout;
113     reportData.tid = g_bussinessTid > 0 ? g_bussinessTid : getpid();
114     auto result = NotifyAppFault(reportData);
115     XCOLLIE_LOGI("OH_HiCollie_Report result: %{public}d, current tid: %{public}d, timeout: %{public}u",
116         result, reportData.tid, reportData.stuckTimeout);
117     return result;
118 }
119 } // end of namespace HiviewDFX
120 } // end of namespace OHOS
121 
InitStuckDetection(OH_HiCollie_Task task,uint32_t timeout)122 inline HiCollie_ErrorCode InitStuckDetection(OH_HiCollie_Task task, uint32_t timeout)
123 {
124     if (OHOS::HiviewDFX::IsAppMainThread()) {
125         return HICOLLIE_WRONG_THREAD_CONTEXT;
126     }
127     if (!task) {
128         OHOS::HiviewDFX::g_stuckTimeout = 0;
129         OHOS::HiviewDFX::g_bussinessTid = 0;
130         OHOS::HiviewDFX::Watchdog::GetInstance().RemovePeriodicalTask("BussinessWatchdog");
131     } else {
132         if (OHOS::HiviewDFX::g_stuckTimeout != 0) {
133             OHOS::HiviewDFX::Watchdog::GetInstance().RemovePeriodicalTask("BussinessWatchdog");
134         }
135         OHOS::HiviewDFX::g_stuckTimeout = timeout;
136         OHOS::HiviewDFX::g_bussinessTid = syscall(SYS_gettid);
137         OHOS::HiviewDFX::Watchdog::GetInstance().RunPeriodicalTask("BussinessWatchdog", task,
138             timeout, OHOS::HiviewDFX::INI_TIMER_FIRST_SECOND);
139         OHOS::HiviewDFX::Watchdog::GetInstance().RemovePeriodicalTask("AppkitWatchdog");
140     }
141     return HICOLLIE_SUCCESS;
142 }
143 
OH_HiCollie_Init_StuckDetection(OH_HiCollie_Task task)144 HiCollie_ErrorCode OH_HiCollie_Init_StuckDetection(OH_HiCollie_Task task)
145 {
146     return InitStuckDetection(task, OHOS::HiviewDFX::CHECK_INTERVAL_TIME);
147 }
148 
OH_HiCollie_Init_StuckDetectionWithTimeout(OH_HiCollie_Task task,uint32_t timeout)149 HiCollie_ErrorCode OH_HiCollie_Init_StuckDetectionWithTimeout(OH_HiCollie_Task task, uint32_t timeout)
150 {
151     timeout = timeout * OHOS::HiviewDFX::TIME_S_TO_MS;
152     if (timeout < OHOS::HiviewDFX::CHECK_INTERVAL_TIME || timeout > OHOS::HiviewDFX::MAX_TIMEOUT) {
153         return HICOLLIE_INVALID_ARGUMENT;
154     }
155     return InitStuckDetection(task, timeout);
156 }
157 
OH_HiCollie_Init_JankDetection(OH_HiCollie_BeginFunc * beginFunc,OH_HiCollie_EndFunc * endFunc,HiCollie_DetectionParam param)158 HiCollie_ErrorCode OH_HiCollie_Init_JankDetection(OH_HiCollie_BeginFunc* beginFunc,
159     OH_HiCollie_EndFunc* endFunc, HiCollie_DetectionParam param)
160 {
161     if (OHOS::HiviewDFX::IsAppMainThread()) {
162         return HICOLLIE_WRONG_THREAD_CONTEXT;
163     }
164     if ((!beginFunc && endFunc) || (beginFunc && !endFunc)) {
165         return HICOLLIE_INVALID_ARGUMENT;
166     }
167     OHOS::HiviewDFX::Watchdog::GetInstance().InitMainLooperWatcher(beginFunc, endFunc);
168     return HICOLLIE_SUCCESS;
169 }
170 
OH_HiCollie_Report(bool * isSixSecond)171 HiCollie_ErrorCode OH_HiCollie_Report(bool* isSixSecond)
172 {
173     if (OHOS::HiviewDFX::IsAppMainThread()) {
174         return HICOLLIE_WRONG_THREAD_CONTEXT;
175     }
176     if (isSixSecond == nullptr) {
177         return HICOLLIE_INVALID_ARGUMENT;
178     }
179     if (OHOS::HiviewDFX::Watchdog::GetInstance().GetAppDebug()) {
180         XCOLLIE_LOGD("Bussiness: Get appDebug state is true");
181         return HICOLLIE_SUCCESS;
182     }
183     if (OHOS::HiviewDFX::Report(isSixSecond) != 0) {
184         return HICOLLIE_REMOTE_FAILED;
185     }
186     return HICOLLIE_SUCCESS;
187 }
188 
OH_HiCollie_SetTimer(HiCollie_SetTimerParam param,int * id)189 HiCollie_ErrorCode OH_HiCollie_SetTimer(HiCollie_SetTimerParam param, int *id)
190 {
191     if (param.name == nullptr) {
192         XCOLLIE_LOGE("timer name is nullptr");
193         return HICOLLIE_INVALID_TIMER_NAME;
194     }
195     std::string timerName = param.name;
196     if (timerName.empty()) {
197         XCOLLIE_LOGE("timer name is empty");
198         return HICOLLIE_INVALID_TIMER_NAME;
199     }
200     if (param.timeout == 0) {
201         XCOLLIE_LOGE("invalid timeout value");
202         return HICOLLIE_INVALID_TIMEOUT_VALUE;
203     }
204     if (id == nullptr) {
205         XCOLLIE_LOGE("wrong timer id output param");
206         return HICOLLIE_WRONG_TIMER_ID_OUTPUT_PARAM;
207     }
208 
209     int timerId = OHOS::HiviewDFX::XCollie::GetInstance().SetTimer(timerName, param.timeout, param.func, param.arg,
210         param.flag);
211     if (timerId == OHOS::HiviewDFX::INVALID_ID) {
212         XCOLLIE_LOGE("wrong process context, process is in appspawn or nativespawn");
213         return HICOLLIE_WRONG_PROCESS_CONTEXT;
214     }
215     if (timerId == 0) {
216         XCOLLIE_LOGE("task quque size exceed max");
217         return HICOLLIE_WRONG_TIMER_ID_OUTPUT_PARAM;
218     }
219 
220     *id = timerId;
221     return HICOLLIE_SUCCESS;
222 }
223 
OH_HiCollie_CancelTimer(int id)224 void OH_HiCollie_CancelTimer(int id)
225 {
226     if (id <= 0) {
227         XCOLLIE_LOGE("invalid timer id, cancel timer failed");
228         return;
229     }
230     OHOS::HiviewDFX::XCollie::GetInstance().CancelTimer(id);
231 }