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
24 namespace OHOS {
25 namespace HiviewDFX {
26 DEFINE_LOG_LABEL(0xD002D01, "FreezeDetector");
27 namespace {
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
FreezeRuleCluster()52 FreezeRuleCluster::FreezeRuleCluster()
53 {
54 rules_.clear();
55 }
56
~FreezeRuleCluster()57 FreezeRuleCluster::~FreezeRuleCluster()
58 {
59 rules_.clear();
60 }
61
Init()62 bool 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
CheckFileSize(const std::string& path)87 bool 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
ParseRuleFile(const std::string& file)99 bool 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
ParseTagFreeze(xmlNode* tag)130 void 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
ParseTagRules(xmlNode* tag)139 void 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
ParseTagRule(xmlNode* tag)148 void 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
ParseTagLinks(xmlNode* tag, FreezeRule& rule)177 void 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
ParseTagEvent(xmlNode* tag, FreezeResult& result)213 void 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
ParseTagResult(xmlNode* tag, FreezeResult& result)223 void 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
236 template<typename T>
GetAttributeValue(xmlNode* node, const std::string& name)237 T 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
GetResult(const WatchPoint& watchPoint, std::vector<FreezeResult>& list)251 bool 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
GetApplicationPairs() const269 std::map<std::string, std::pair<std::string, bool>> FreezeRuleCluster::GetApplicationPairs() const
270 {
271 return applicationPairs_;
272 }
273
GetSystemPairs() const274 std::map<std::string, std::pair<std::string, bool>> FreezeRuleCluster::GetSystemPairs() const
275 {
276 return systemPairs_;
277 }
278
GetSysWarningPairs() const279 std::map<std::string, std::pair<std::string, bool>> FreezeRuleCluster::GetSysWarningPairs() const
280 {
281 return sysWarningPairs_;
282 }
283
GetDomain() const284 std::string FreezeResult::GetDomain() const
285 {
286 return domain_;
287 }
288
GetStringId() const289 std::string FreezeResult::GetStringId() const
290 {
291 return stringId_;
292 }
293
GetId() const294 unsigned long FreezeResult::GetId() const
295 {
296 return code_;
297 }
298
SetId(unsigned long code)299 void FreezeResult::SetId(unsigned long code)
300 {
301 code_ = code;
302 }
303
GetScope() const304 std::string FreezeResult::GetScope() const
305 {
306 return scope_;
307 }
308
SetScope(const std::string& scope)309 void FreezeResult::SetScope(const std::string& scope)
310 {
311 scope_ = scope;
312 }
313
GetWindow() const314 long FreezeResult::GetWindow() const
315 {
316 return window_;
317 }
318
GetSamePackage() const319 std::string FreezeResult::GetSamePackage() const
320 {
321 return samePackage_;
322 }
323
SetSamePackage(const std::string& samePackage)324 void FreezeResult::SetSamePackage(const std::string& samePackage)
325 {
326 samePackage_ = samePackage;
327 }
328
GetAction() const329 std::string FreezeResult::GetAction() const
330 {
331 return action_;
332 }
333
SetAction(const std::string& action)334 void FreezeResult::SetAction(const std::string& action)
335 {
336 action_ = action;
337 }
338
GetDomain() const339 std::string FreezeRule::GetDomain() const
340 {
341 return domain_;
342 }
343
SetDomain(const std::string& domain)344 void FreezeRule::SetDomain(const std::string& domain)
345 {
346 domain_ = domain;
347 }
348
GetStringId() const349 std::string FreezeRule::GetStringId() const
350 {
351 return stringId_;
352 }
353
SetStringId(const std::string& stringId)354 void FreezeRule::SetStringId(const std::string& stringId)
355 {
356 stringId_ = stringId;
357 }
358
GetMap() const359 std::map<std::string, FreezeResult> FreezeRule::GetMap() const
360 {
361 return results_;
362 }
363
AddResult(const std::string& domain, const std::string& stringId, const FreezeResult& result)364 void 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
GetResult(const std::string& domain, const std::string& stringId, FreezeResult& result)374 bool 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