1/* 2 * Copyright (c) 2021 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 "rule_cluster.h" 17 18#include <sstream> 19#include <sys/stat.h> 20#include <unistd.h> 21 22#include "hiview_logger.h" 23 24namespace OHOS { 25namespace HiviewDFX { 26DEFINE_LOG_LABEL(0xD002D01, "FreezeDetector"); 27namespace { 28 static constexpr const char* const DEFAULT_RULE_FILE = "/system/etc/hiview/freeze_rules.xml"; 29 static constexpr const char* const TAG_FREEZE = "freeze"; 30 static constexpr const char* const TAG_RULES = "rules"; 31 static constexpr const char* const TAG_RULE = "rule"; 32 static constexpr const char* const TAG_LINKS = "links"; 33 static constexpr const char* const TAG_EVENT = "event"; 34 static constexpr const char* const TAG_RESULT = "result"; 35 static constexpr const char* const TAG_RELEVANCE = "relevance"; 36 static constexpr const char* const ATTRIBUTE_ID = "id"; 37 static constexpr const char* const ATTRIBUTE_WINDOW = "window"; 38 static constexpr const char* const ATTRIBUTE_DOMAIN = "domain"; 39 static constexpr const char* const ATTRIBUTE_STRINGID = "stringid"; 40 static constexpr const char* const ATTRIBUTE_TYPE = "type"; 41 static constexpr const char* const ATTRIBUTE_USER = "user"; 42 static constexpr const char* const ATTRIBUTE_WATCHPOINT = "watchpoint"; 43 static constexpr const char* const ATTRIBUTE_CODE = "code"; 44 static constexpr const char* const ATTRIBUTE_SCOPE = "scope"; 45 static constexpr const char* const ATTRIBUTE_SAME_PACKAGE = "samePackage"; 46 static constexpr const char* const ATTRIBUTE_ACTION = "action"; 47 static constexpr const char* const ATTRIBUTE_APPLICATION = "application"; 48 static constexpr const char* const ATTRIBUTE_SYSTEM = "system"; 49 static const int MAX_FILE_SIZE = 512 * 1024; 50} 51 52FreezeRuleCluster::FreezeRuleCluster() 53{ 54 rules_.clear(); 55} 56 57FreezeRuleCluster::~FreezeRuleCluster() 58{ 59 rules_.clear(); 60} 61 62bool FreezeRuleCluster::Init() 63{ 64 if (access(DEFAULT_RULE_FILE, R_OK) != 0) { 65 HIVIEW_LOGE("cannot access rule file."); 66 return false; 67 } 68 69 if (CheckFileSize(DEFAULT_RULE_FILE) == false) { 70 HIVIEW_LOGE("bad rule file size."); 71 return false; 72 } 73 74 if (ParseRuleFile(DEFAULT_RULE_FILE) == false) { 75 HIVIEW_LOGE("failed to parse rule file."); 76 return false; 77 } 78 79 if (rules_.size() == 0) { 80 HIVIEW_LOGE("no rule in rule file."); 81 return false; 82 } 83 84 return true; 85} 86 87bool FreezeRuleCluster::CheckFileSize(const std::string& path) 88{ 89 struct stat st; 90 if (stat(path.c_str(), &st) != 0) { 91 return false; 92 } 93 if (st.st_size > MAX_FILE_SIZE) { 94 return false; 95 } 96 return true; 97} 98 99bool FreezeRuleCluster::ParseRuleFile(const std::string& file) 100{ 101 xmlDoc* doc = xmlReadFile(file.c_str(), nullptr, 0); 102 if (doc == nullptr) { 103 HIVIEW_LOGE("failed to read rule file."); 104 return false; 105 } 106 107 xmlNode* root = xmlDocGetRootElement(doc); 108 if (root == nullptr) { 109 HIVIEW_LOGE("failed to get root element in rule file."); 110 xmlFreeDoc(doc); 111 doc = nullptr; 112 return false; 113 } 114 115 for (xmlNode* node = root; node; node = node->next) { 116 if (node->type != XML_ELEMENT_NODE) { 117 continue; 118 } 119 if (TAG_FREEZE == std::string((char*)(node->name))) { 120 ParseTagFreeze(node); 121 break; 122 } 123 } 124 125 xmlFreeDoc(doc); 126 doc = nullptr; 127 return true; 128} 129 130void FreezeRuleCluster::ParseTagFreeze(xmlNode* tag) 131{ 132 for (xmlNode* node = tag->children; node; node = node->next) { 133 if (TAG_RULES == std::string((char*)(node->name))) { 134 ParseTagRules(node); 135 } 136 } 137} 138 139void FreezeRuleCluster::ParseTagRules(xmlNode* tag) 140{ 141 for (xmlNode* node = tag->children; node; node = node->next) { 142 if (TAG_RULE == std::string((char*)(node->name))) { 143 ParseTagRule(node); 144 } 145 } 146} 147 148void FreezeRuleCluster::ParseTagRule(xmlNode* tag) 149{ 150 std::string domain = GetAttributeValue<std::string>(tag, ATTRIBUTE_DOMAIN); 151 if (domain == "") { 152 HIVIEW_LOGE("null rule attribute:domain."); 153 return; 154 } 155 std::string stringId = GetAttributeValue<std::string>(tag, ATTRIBUTE_STRINGID); 156 if (stringId == "") { 157 HIVIEW_LOGE("null rule attribute:stringid."); 158 return; 159 } 160 161 FreezeRule rule = FreezeRule(domain, stringId); 162 163 for (xmlNode* node = tag->children; node; node = node->next) { 164 if (TAG_LINKS == std::string((char*)(node->name))) { 165 ParseTagLinks(node, rule); 166 } 167 } 168 169 if (rules_.find(domain + stringId) != rules_.end()) { 170 HIVIEW_LOGE("skip duplicated rule, stringid:%{public}s.", stringId.c_str()); 171 return; 172 } 173 174 rules_[domain + stringId] = rule; 175} 176 177void FreezeRuleCluster::ParseTagLinks(xmlNode* tag, FreezeRule& rule) 178{ 179 for (xmlNode* node = tag->children; node; node = node->next) { 180 if (TAG_EVENT == std::string((char*)(node->name))) { 181 std::string domain = GetAttributeValue<std::string>(node, ATTRIBUTE_DOMAIN); 182 if (domain == "") { 183 HIVIEW_LOGE("null event attribute:domain."); 184 return; 185 } 186 std::string stringId = GetAttributeValue<std::string>(node, ATTRIBUTE_STRINGID); 187 if (stringId == "") { 188 HIVIEW_LOGE("null event attribute:stringid."); 189 return; 190 } 191 192 long window = GetAttributeValue<long>(node, ATTRIBUTE_WINDOW); 193 194 FreezeResult result = FreezeResult(window, domain, stringId); 195 ParseTagEvent(node, result); 196 rule.AddResult(domain, stringId, result); 197 198 bool principalPoint = false; 199 if (rule.GetDomain() == domain && rule.GetStringId() == stringId) { 200 principalPoint = true; 201 } 202 if (result.GetScope() == "app") { 203 applicationPairs_[stringId] = std::pair<std::string, bool>(domain, principalPoint); 204 } else if (result.GetScope() == "sys") { 205 systemPairs_[stringId] = std::pair<std::string, bool>(domain, principalPoint); 206 } else { 207 sysWarningPairs_[stringId] = std::pair<std::string, bool>(domain, principalPoint); 208 } 209 } 210 } 211} 212 213void FreezeRuleCluster::ParseTagEvent(xmlNode* tag, FreezeResult& result) 214{ 215 for (xmlNode* node = tag->children; node; node = node->next) { 216 if (TAG_RESULT == std::string((char*)(node->name))) { 217 ParseTagResult(node, result); 218 break; 219 } 220 } 221} 222 223void FreezeRuleCluster::ParseTagResult(xmlNode* tag, FreezeResult& result) 224{ 225 unsigned long code = GetAttributeValue<unsigned long>(tag, ATTRIBUTE_CODE); 226 std::string scope = GetAttributeValue<std::string>(tag, ATTRIBUTE_SCOPE); 227 std::string samePackage = GetAttributeValue<std::string>(tag, ATTRIBUTE_SAME_PACKAGE); 228 std::string action = GetAttributeValue<std::string>(tag, ATTRIBUTE_ACTION); 229 230 result.SetId(code); 231 result.SetScope(scope); 232 result.SetSamePackage(samePackage); 233 result.SetAction(action); 234} 235 236template<typename T> 237T FreezeRuleCluster::GetAttributeValue(xmlNode* node, const std::string& name) 238{ 239 xmlChar* prop = xmlGetProp(node, (xmlChar*)(name.c_str())); 240 std::string propa = ""; 241 if (prop != nullptr) { 242 propa = (char*)prop; 243 } 244 std::istringstream istr(propa); 245 T value; 246 istr >> value; 247 xmlFree(prop); 248 return value; 249} 250 251bool FreezeRuleCluster::GetResult(const WatchPoint& watchPoint, std::vector<FreezeResult>& list) 252{ 253 std::string domain = watchPoint.GetDomain(); 254 std::string stringId = watchPoint.GetStringId(); 255 if (rules_.find(domain + stringId) == rules_.end()) { 256 return false; 257 } 258 auto map = rules_[domain + stringId].GetMap(); 259 for (auto& i : map) { 260 list.push_back(i.second); 261 } 262 263 if (list.empty()) { 264 return false; 265 } 266 return true; 267} 268 269std::map<std::string, std::pair<std::string, bool>> FreezeRuleCluster::GetApplicationPairs() const 270{ 271 return applicationPairs_; 272} 273 274std::map<std::string, std::pair<std::string, bool>> FreezeRuleCluster::GetSystemPairs() const 275{ 276 return systemPairs_; 277} 278 279std::map<std::string, std::pair<std::string, bool>> FreezeRuleCluster::GetSysWarningPairs() const 280{ 281 return sysWarningPairs_; 282} 283 284std::string FreezeResult::GetDomain() const 285{ 286 return domain_; 287} 288 289std::string FreezeResult::GetStringId() const 290{ 291 return stringId_; 292} 293 294unsigned long FreezeResult::GetId() const 295{ 296 return code_; 297} 298 299void FreezeResult::SetId(unsigned long code) 300{ 301 code_ = code; 302} 303 304std::string FreezeResult::GetScope() const 305{ 306 return scope_; 307} 308 309void FreezeResult::SetScope(const std::string& scope) 310{ 311 scope_ = scope; 312} 313 314long FreezeResult::GetWindow() const 315{ 316 return window_; 317} 318 319std::string FreezeResult::GetSamePackage() const 320{ 321 return samePackage_; 322} 323 324void FreezeResult::SetSamePackage(const std::string& samePackage) 325{ 326 samePackage_ = samePackage; 327} 328 329std::string FreezeResult::GetAction() const 330{ 331 return action_; 332} 333 334void FreezeResult::SetAction(const std::string& action) 335{ 336 action_ = action; 337} 338 339std::string FreezeRule::GetDomain() const 340{ 341 return domain_; 342} 343 344void FreezeRule::SetDomain(const std::string& domain) 345{ 346 domain_ = domain; 347} 348 349std::string FreezeRule::GetStringId() const 350{ 351 return stringId_; 352} 353 354void FreezeRule::SetStringId(const std::string& stringId) 355{ 356 stringId_ = stringId; 357} 358 359std::map<std::string, FreezeResult> FreezeRule::GetMap() const 360{ 361 return results_; 362} 363 364void FreezeRule::AddResult(const std::string& domain, const std::string& stringId, const FreezeResult& result) 365{ 366 if (results_.find(domain + stringId) != results_.end()) { 367 HIVIEW_LOGE("skip duplicated event tag, stringid:%{public}s.", stringId.c_str()); 368 return; 369 } 370 371 results_[domain + stringId] = result; 372} 373 374bool FreezeRule::GetResult(const std::string& domain, const std::string& stringId, FreezeResult& result) 375{ 376 if (results_.find(domain + stringId) == results_.end()) { 377 HIVIEW_LOGE("failed to find rule result, domain:%{public}s stringid:%{public}s.", 378 domain.c_str(), stringId.c_str()); 379 return false; 380 } 381 382 result = results_[domain + stringId]; // take result back 383 return true; 384} 385} // namespace HiviewDFX 386} // namespace OHOS 387