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