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