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