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 33namespace OHOS { 34namespace 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" 41constexpr int BASE_TAG = 10; 42constexpr uint64_t ALLOWED_RULE = Rule::RULE_CHECK_ARKUI_PERFORMANCE; 43 44std::mutex HiChecker::mutexLock_; 45volatile bool HiChecker::checkMode_; 46volatile uint64_t HiChecker::processRules_; 47thread_local uint64_t HiChecker::threadLocalRules_; 48 49void 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 62void 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 75uint64_t HiChecker::GetRule() 76{ 77 std::lock_guard<std::mutex> lock(mutexLock_); 78 return (threadLocalRules_ | processRules_); 79} 80 81bool 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 90void 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 102void 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 114void HiChecker::NotifyAbilityConnectionLeak(const Caution& caution) 115{ 116 if ((processRules_ & Rule::RULE_CHECK_ABILITY_CONNECTION_LEAK) == 0) { 117 return; 118 } 119 HandleCaution(caution); 120} 121 122void 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 150void 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 165void 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 179void HiChecker::OnProcessCautionFound(CautionDetail& cautionDetail) 180{ 181 OnThreadCautionFound(cautionDetail); 182} 183 184void 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 192void 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 201bool HiChecker::NeedCheckSlowEvent() 202{ 203 return checkMode_; 204} 205 206bool HiChecker::HasCautionRule(uint64_t rules) 207{ 208 return (rules & Rule::ALL_CAUTION_RULES); 209} 210 211void 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 219bool 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 228void 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 & ALLOWED_RULE); 254 return; 255} 256} // HiviewDFX 257} // OHOS 258