1 /*
2  * Copyright (c) 2022 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 "hichecker.h"
17 
18 #include <csignal>
19 #include <cerrno>
20 #include <sys/types.h>
21 #include <unistd.h>
22 #include <cstring>
23 #include <cstdio>
24 #include <cstdlib>
25 #include <parameter.h>
26 
27 #include "securec.h"
28 
29 #include "dfx_dump_catcher.h"
30 #include "hilog/log_c.h"
31 #include "hilog/log_cpp.h"
32 
33 namespace OHOS {
34 namespace HiviewDFX {
35 #define PARAM_BUF_LEN 128
36 #define QUERYNAME_LEN 80
37 #undef LOG_DOMAIN
38 #define LOG_DOMAIN 0xD002D0B
39 #undef LOG_TAG
40 #define LOG_TAG "HICHECKER"
41 constexpr int BASE_TAG = 10;
42 constexpr uint64_t ALLOWED_RULE = Rule::RULE_CHECK_ARKUI_PERFORMANCE;
43 
44 std::mutex HiChecker::mutexLock_;
45 volatile bool HiChecker::checkMode_;
46 volatile uint64_t HiChecker::processRules_;
47 thread_local uint64_t HiChecker::threadLocalRules_;
48 
AddRule(uint64_t rule)49 void HiChecker::AddRule(uint64_t rule)
50 {
51     std::lock_guard<std::mutex> lock(mutexLock_);
52     if (!CheckRule(rule)) {
53         return;
54     }
55     if ((Rule::RULE_CHECK_SLOW_EVENT & rule)) {
56         checkMode_ = true;
57     }
58     threadLocalRules_ |= (Rule::ALL_THREAD_RULES | Rule::ALL_CAUTION_RULES) & rule;
59     processRules_ |= (Rule::ALL_PROCESS_RULES | Rule::ALL_CAUTION_RULES) & rule;
60 }
61 
RemoveRule(uint64_t rule)62 void HiChecker::RemoveRule(uint64_t rule)
63 {
64     std::lock_guard<std::mutex> lock(mutexLock_);
65     if (!CheckRule(rule)) {
66         return;
67     }
68     if ((Rule::RULE_CHECK_SLOW_EVENT & rule)) {
69         checkMode_ = false;
70     }
71     threadLocalRules_ ^= threadLocalRules_ & rule;
72     processRules_ ^= processRules_ & rule;
73 }
74 
GetRule()75 uint64_t HiChecker::GetRule()
76 {
77     std::lock_guard<std::mutex> lock(mutexLock_);
78     return (threadLocalRules_ | processRules_);
79 }
80 
Contains(uint64_t rule)81 bool HiChecker::Contains(uint64_t rule)
82 {
83     std::lock_guard<std::mutex> lock(mutexLock_);
84     if (!CheckRule(rule)) {
85         return false;
86     }
87     return rule == (rule & (threadLocalRules_ | processRules_));
88 }
89 
NotifySlowProcess(const std::string & tag)90 void HiChecker::NotifySlowProcess(const std::string& tag)
91 {
92     if ((threadLocalRules_ & Rule::RULE_THREAD_CHECK_SLOW_PROCESS) == 0) {
93         return;
94     }
95     std::string stackTrace;
96     DumpStackTrace(stackTrace);
97     Caution caution(Rule::RULE_THREAD_CHECK_SLOW_PROCESS,
98         "trigger:RULE_THREAD_CHECK_SLOW_PROCESS," + tag, stackTrace);
99     HandleCaution(caution);
100 }
101 
NotifySlowEvent(const std::string & tag)102 void HiChecker::NotifySlowEvent(const std::string& tag)
103 {
104     if ((processRules_ & Rule::RULE_CHECK_SLOW_EVENT) == 0) {
105         return;
106     }
107     std::string stackTrace;
108     DumpStackTrace(stackTrace);
109     Caution caution(Rule::RULE_CHECK_SLOW_EVENT,
110         "trigger:RULE_CHECK_SLOW_EVENT," + tag, stackTrace);
111     HandleCaution(caution);
112 }
113 
NotifyAbilityConnectionLeak(const Caution & caution)114 void HiChecker::NotifyAbilityConnectionLeak(const Caution& caution)
115 {
116     if ((processRules_ & Rule::RULE_CHECK_ABILITY_CONNECTION_LEAK) == 0) {
117         return;
118     }
119     HandleCaution(caution);
120 }
121 
NotifyCaution(uint64_t rule,const std::string & tag,Caution & caution)122 void HiChecker::NotifyCaution(uint64_t rule, const std::string& tag, Caution& caution)
123 {
124     if ((threadLocalRules_ & rule) == 0 && (processRules_ & rule) == 0) {
125         return;
126     }
127     std::string msg;
128     switch (rule) {
129         case Rule::RULE_THREAD_CHECK_SLOW_PROCESS:
130             msg = "trigger:RULE_THREAD_CHECK_SLOW_PROCESS," + tag;
131             break;
132         case Rule::RULE_CHECK_SLOW_EVENT:
133             msg = "trigger:RULE_CHECK_SLOW_EVENT," + tag;
134             break;
135         case Rule::RULE_CHECK_ARKUI_PERFORMANCE:
136             msg = "trigger:RULE_CHECK_ARKUI_PERFORMANCE," + tag;
137             break;
138         default:
139             break;
140     }
141     if (Rule::RULE_CHECK_ABILITY_CONNECTION_LEAK != rule) {
142         std::string stackTrace;
143         DumpStackTrace(stackTrace);
144         caution.SetCautionMsg(msg);
145         caution.SetStackTrace(stackTrace);
146     }
147     HandleCaution(caution);
148 }
149 
HandleCaution(const Caution & caution)150 void HiChecker::HandleCaution(const Caution& caution)
151 {
152     uint64_t triggerRule = caution.GetTriggerRule();
153     if ((threadLocalRules_ & triggerRule)) {
154         CautionDetail cautionDetail(caution, threadLocalRules_);
155         OnThreadCautionFound(cautionDetail);
156         return;
157     }
158     if ((processRules_ & triggerRule)) {
159         CautionDetail cautionDetail(caution, processRules_);
160         OnProcessCautionFound(cautionDetail);
161         return;
162     }
163 }
164 
OnThreadCautionFound(CautionDetail & cautionDetail)165 void HiChecker::OnThreadCautionFound(CautionDetail& cautionDetail)
166 {
167     if ((cautionDetail.rules_ & Rule::ALL_CAUTION_RULES) == 0) {
168         cautionDetail.rules_ |= Rule::RULE_CAUTION_PRINT_LOG;
169     }
170     if (cautionDetail.CautionEnable(Rule::RULE_CAUTION_PRINT_LOG)
171         && !cautionDetail.CautionEnable(Rule::RULE_CAUTION_TRIGGER_CRASH)) {
172         PrintLog(cautionDetail);
173     }
174     if (cautionDetail.CautionEnable(Rule::RULE_CAUTION_TRIGGER_CRASH)) {
175         TriggerCrash(cautionDetail);
176     }
177 }
178 
OnProcessCautionFound(CautionDetail & cautionDetail)179 void HiChecker::OnProcessCautionFound(CautionDetail& cautionDetail)
180 {
181     OnThreadCautionFound(cautionDetail);
182 }
183 
PrintLog(const CautionDetail & cautionDetail)184 void HiChecker::PrintLog(const CautionDetail& cautionDetail)
185 {
186     HILOG_INFO(LOG_CORE,
187         "HiChecker caution with RULE_CAUTION_PRINT_LOG.\nCautionMsg:%{public}s\nStackTrace:\n%{public}s",
188         cautionDetail.caution_.GetCautionMsg().c_str(),
189         cautionDetail.caution_.GetStackTrace().c_str());
190 }
191 
TriggerCrash(const CautionDetail & cautionDetail)192 void HiChecker::TriggerCrash(const CautionDetail& cautionDetail)
193 {
194     HILOG_INFO(LOG_CORE,
195         "HiChecker caution with RULE_CAUTION_TRIGGER_CRASH; exit.\nCautionMsg:%{public}s\nStackTrace:\n%{public}s",
196         cautionDetail.caution_.GetCautionMsg().c_str(),
197         cautionDetail.caution_.GetStackTrace().c_str());
198     kill(getpid(), SIGABRT);
199 }
200 
NeedCheckSlowEvent()201 bool HiChecker::NeedCheckSlowEvent()
202 {
203     return checkMode_;
204 }
205 
HasCautionRule(uint64_t rules)206 bool HiChecker::HasCautionRule(uint64_t rules)
207 {
208     return (rules & Rule::ALL_CAUTION_RULES);
209 }
210 
DumpStackTrace(std::string & msg)211 void HiChecker::DumpStackTrace(std::string& msg)
212 {
213     DfxDumpCatcher dumplog;
214     if (!dumplog.DumpCatch(getpid(), gettid(), msg)) {
215         HILOG_INFO(LOG_CORE, "HiChecker DumpStackTrace fail.");
216     }
217 }
218 
CheckRule(uint64_t rule)219 bool HiChecker::CheckRule(uint64_t rule)
220 {
221     if (rule <= 0 || Rule::ALL_RULES != (Rule::ALL_RULES | rule)) {
222         HILOG_INFO(LOG_CORE, "input rule is not exist,please check.");
223         return false;
224     }
225     return true;
226 }
227 
InitHicheckerParam(const char * processName)228 void HiChecker::InitHicheckerParam(const char *processName)
229 {
230     char checkerName[QUERYNAME_LEN] = "hiviewdfx.hichecker.";
231     errno_t err = 0;
232     err = strcat_s(checkerName, sizeof(checkerName), processName);
233     if (err != EOK) {
234         HILOG_INFO(LOG_CORE, "checker strcat_s query name failed.");
235         return;
236     }
237 
238     char paramOutBuf[PARAM_BUF_LEN] = { 0 };
239     char defStrValue[PARAM_BUF_LEN] = { 0 };
240     int retLen = GetParameter(checkerName, defStrValue, paramOutBuf, PARAM_BUF_LEN);
241     if (retLen <= 0 || retLen > PARAM_BUF_LEN - 1) {
242         HILOG_INFO(LOG_CORE, "hichecker param is empty.");
243         return;
244     }
245     paramOutBuf[retLen] = '\0';
246     HILOG_INFO(LOG_CORE, "hichecker param value is %{public}s", paramOutBuf);
247     char *endPtr = nullptr;
248     uint64_t rule = strtoull(paramOutBuf, &endPtr, BASE_TAG);
249     if (!(rule & ALLOWED_RULE)) {
250         HILOG_ERROR(LOG_CORE, "not allowed param.");
251         return;
252     }
253     AddRule(rule);
254     return;
255 }
256 } // HiviewDFX
257 } // OHOS
258