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