1020a203aSopenharmony_ci/*
2020a203aSopenharmony_ci * Copyright (c) 2021 Huawei Device Co., Ltd.
3020a203aSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
4020a203aSopenharmony_ci * you may not use this file except in compliance with the License.
5020a203aSopenharmony_ci * You may obtain a copy of the License at
6020a203aSopenharmony_ci *
7020a203aSopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
8020a203aSopenharmony_ci *
9020a203aSopenharmony_ci * Unless required by applicable law or agreed to in writing, software
10020a203aSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
11020a203aSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12020a203aSopenharmony_ci * See the License for the specific language governing permissions and
13020a203aSopenharmony_ci * limitations under the License.
14020a203aSopenharmony_ci */
15020a203aSopenharmony_ci
16020a203aSopenharmony_ci#include "rule_cluster.h"
17020a203aSopenharmony_ci
18020a203aSopenharmony_ci#include <sstream>
19020a203aSopenharmony_ci#include <sys/stat.h>
20020a203aSopenharmony_ci#include <unistd.h>
21020a203aSopenharmony_ci
22020a203aSopenharmony_ci#include "hiview_logger.h"
23020a203aSopenharmony_ci
24020a203aSopenharmony_cinamespace OHOS {
25020a203aSopenharmony_cinamespace HiviewDFX {
26020a203aSopenharmony_ciDEFINE_LOG_LABEL(0xD002D01, "FreezeDetector");
27020a203aSopenharmony_cinamespace {
28020a203aSopenharmony_ci    static constexpr const char* const DEFAULT_RULE_FILE = "/system/etc/hiview/freeze_rules.xml";
29020a203aSopenharmony_ci    static constexpr const char* const TAG_FREEZE = "freeze";
30020a203aSopenharmony_ci    static constexpr const char* const TAG_RULES = "rules";
31020a203aSopenharmony_ci    static constexpr const char* const TAG_RULE = "rule";
32020a203aSopenharmony_ci    static constexpr const char* const TAG_LINKS = "links";
33020a203aSopenharmony_ci    static constexpr const char* const TAG_EVENT = "event";
34020a203aSopenharmony_ci    static constexpr const char* const TAG_RESULT = "result";
35020a203aSopenharmony_ci    static constexpr const char* const TAG_RELEVANCE = "relevance";
36020a203aSopenharmony_ci    static constexpr const char* const ATTRIBUTE_ID = "id";
37020a203aSopenharmony_ci    static constexpr const char* const ATTRIBUTE_WINDOW = "window";
38020a203aSopenharmony_ci    static constexpr const char* const ATTRIBUTE_DOMAIN = "domain";
39020a203aSopenharmony_ci    static constexpr const char* const ATTRIBUTE_STRINGID = "stringid";
40020a203aSopenharmony_ci    static constexpr const char* const ATTRIBUTE_TYPE = "type";
41020a203aSopenharmony_ci    static constexpr const char* const ATTRIBUTE_USER = "user";
42020a203aSopenharmony_ci    static constexpr const char* const ATTRIBUTE_WATCHPOINT = "watchpoint";
43020a203aSopenharmony_ci    static constexpr const char* const ATTRIBUTE_CODE = "code";
44020a203aSopenharmony_ci    static constexpr const char* const ATTRIBUTE_SCOPE = "scope";
45020a203aSopenharmony_ci    static constexpr const char* const ATTRIBUTE_SAME_PACKAGE = "samePackage";
46020a203aSopenharmony_ci    static constexpr const char* const ATTRIBUTE_ACTION = "action";
47020a203aSopenharmony_ci    static constexpr const char* const ATTRIBUTE_APPLICATION = "application";
48020a203aSopenharmony_ci    static constexpr const char* const ATTRIBUTE_SYSTEM = "system";
49020a203aSopenharmony_ci    static const int MAX_FILE_SIZE = 512 * 1024;
50020a203aSopenharmony_ci}
51020a203aSopenharmony_ci
52020a203aSopenharmony_ciFreezeRuleCluster::FreezeRuleCluster()
53020a203aSopenharmony_ci{
54020a203aSopenharmony_ci    rules_.clear();
55020a203aSopenharmony_ci}
56020a203aSopenharmony_ci
57020a203aSopenharmony_ciFreezeRuleCluster::~FreezeRuleCluster()
58020a203aSopenharmony_ci{
59020a203aSopenharmony_ci    rules_.clear();
60020a203aSopenharmony_ci}
61020a203aSopenharmony_ci
62020a203aSopenharmony_cibool FreezeRuleCluster::Init()
63020a203aSopenharmony_ci{
64020a203aSopenharmony_ci    if (access(DEFAULT_RULE_FILE, R_OK) != 0) {
65020a203aSopenharmony_ci        HIVIEW_LOGE("cannot access rule file.");
66020a203aSopenharmony_ci        return false;
67020a203aSopenharmony_ci    }
68020a203aSopenharmony_ci
69020a203aSopenharmony_ci    if (CheckFileSize(DEFAULT_RULE_FILE) == false) {
70020a203aSopenharmony_ci        HIVIEW_LOGE("bad rule file size.");
71020a203aSopenharmony_ci        return false;
72020a203aSopenharmony_ci    }
73020a203aSopenharmony_ci
74020a203aSopenharmony_ci    if (ParseRuleFile(DEFAULT_RULE_FILE) == false) {
75020a203aSopenharmony_ci        HIVIEW_LOGE("failed to parse rule file.");
76020a203aSopenharmony_ci        return false;
77020a203aSopenharmony_ci    }
78020a203aSopenharmony_ci
79020a203aSopenharmony_ci    if (rules_.size() == 0) {
80020a203aSopenharmony_ci        HIVIEW_LOGE("no rule in rule file.");
81020a203aSopenharmony_ci        return false;
82020a203aSopenharmony_ci    }
83020a203aSopenharmony_ci
84020a203aSopenharmony_ci    return true;
85020a203aSopenharmony_ci}
86020a203aSopenharmony_ci
87020a203aSopenharmony_cibool FreezeRuleCluster::CheckFileSize(const std::string& path)
88020a203aSopenharmony_ci{
89020a203aSopenharmony_ci    struct stat st;
90020a203aSopenharmony_ci    if (stat(path.c_str(), &st) != 0) {
91020a203aSopenharmony_ci        return false;
92020a203aSopenharmony_ci    }
93020a203aSopenharmony_ci    if (st.st_size > MAX_FILE_SIZE) {
94020a203aSopenharmony_ci        return false;
95020a203aSopenharmony_ci    }
96020a203aSopenharmony_ci    return true;
97020a203aSopenharmony_ci}
98020a203aSopenharmony_ci
99020a203aSopenharmony_cibool FreezeRuleCluster::ParseRuleFile(const std::string& file)
100020a203aSopenharmony_ci{
101020a203aSopenharmony_ci    xmlDoc* doc = xmlReadFile(file.c_str(), nullptr, 0);
102020a203aSopenharmony_ci    if (doc == nullptr) {
103020a203aSopenharmony_ci        HIVIEW_LOGE("failed to read rule file.");
104020a203aSopenharmony_ci        return false;
105020a203aSopenharmony_ci    }
106020a203aSopenharmony_ci
107020a203aSopenharmony_ci    xmlNode* root = xmlDocGetRootElement(doc);
108020a203aSopenharmony_ci    if (root == nullptr) {
109020a203aSopenharmony_ci        HIVIEW_LOGE("failed to get root element in rule file.");
110020a203aSopenharmony_ci        xmlFreeDoc(doc);
111020a203aSopenharmony_ci        doc = nullptr;
112020a203aSopenharmony_ci        return false;
113020a203aSopenharmony_ci    }
114020a203aSopenharmony_ci
115020a203aSopenharmony_ci    for (xmlNode* node = root; node; node = node->next) {
116020a203aSopenharmony_ci        if (node->type != XML_ELEMENT_NODE) {
117020a203aSopenharmony_ci            continue;
118020a203aSopenharmony_ci        }
119020a203aSopenharmony_ci        if (TAG_FREEZE == std::string((char*)(node->name))) {
120020a203aSopenharmony_ci            ParseTagFreeze(node);
121020a203aSopenharmony_ci            break;
122020a203aSopenharmony_ci        }
123020a203aSopenharmony_ci    }
124020a203aSopenharmony_ci
125020a203aSopenharmony_ci    xmlFreeDoc(doc);
126020a203aSopenharmony_ci    doc = nullptr;
127020a203aSopenharmony_ci    return true;
128020a203aSopenharmony_ci}
129020a203aSopenharmony_ci
130020a203aSopenharmony_civoid FreezeRuleCluster::ParseTagFreeze(xmlNode* tag)
131020a203aSopenharmony_ci{
132020a203aSopenharmony_ci    for (xmlNode* node = tag->children; node; node = node->next) {
133020a203aSopenharmony_ci        if (TAG_RULES == std::string((char*)(node->name))) {
134020a203aSopenharmony_ci            ParseTagRules(node);
135020a203aSopenharmony_ci        }
136020a203aSopenharmony_ci    }
137020a203aSopenharmony_ci}
138020a203aSopenharmony_ci
139020a203aSopenharmony_civoid FreezeRuleCluster::ParseTagRules(xmlNode* tag)
140020a203aSopenharmony_ci{
141020a203aSopenharmony_ci    for (xmlNode* node = tag->children; node; node = node->next) {
142020a203aSopenharmony_ci        if (TAG_RULE == std::string((char*)(node->name))) {
143020a203aSopenharmony_ci            ParseTagRule(node);
144020a203aSopenharmony_ci        }
145020a203aSopenharmony_ci    }
146020a203aSopenharmony_ci}
147020a203aSopenharmony_ci
148020a203aSopenharmony_civoid FreezeRuleCluster::ParseTagRule(xmlNode* tag)
149020a203aSopenharmony_ci{
150020a203aSopenharmony_ci    std::string domain = GetAttributeValue<std::string>(tag, ATTRIBUTE_DOMAIN);
151020a203aSopenharmony_ci    if (domain == "") {
152020a203aSopenharmony_ci        HIVIEW_LOGE("null rule attribute:domain.");
153020a203aSopenharmony_ci        return;
154020a203aSopenharmony_ci    }
155020a203aSopenharmony_ci    std::string stringId = GetAttributeValue<std::string>(tag, ATTRIBUTE_STRINGID);
156020a203aSopenharmony_ci    if (stringId == "") {
157020a203aSopenharmony_ci        HIVIEW_LOGE("null rule attribute:stringid.");
158020a203aSopenharmony_ci        return;
159020a203aSopenharmony_ci    }
160020a203aSopenharmony_ci
161020a203aSopenharmony_ci    FreezeRule rule = FreezeRule(domain, stringId);
162020a203aSopenharmony_ci
163020a203aSopenharmony_ci    for (xmlNode* node = tag->children; node; node = node->next) {
164020a203aSopenharmony_ci        if (TAG_LINKS == std::string((char*)(node->name))) {
165020a203aSopenharmony_ci            ParseTagLinks(node, rule);
166020a203aSopenharmony_ci        }
167020a203aSopenharmony_ci    }
168020a203aSopenharmony_ci
169020a203aSopenharmony_ci    if (rules_.find(domain + stringId) != rules_.end()) {
170020a203aSopenharmony_ci        HIVIEW_LOGE("skip duplicated rule, stringid:%{public}s.", stringId.c_str());
171020a203aSopenharmony_ci        return;
172020a203aSopenharmony_ci    }
173020a203aSopenharmony_ci
174020a203aSopenharmony_ci    rules_[domain + stringId] = rule;
175020a203aSopenharmony_ci}
176020a203aSopenharmony_ci
177020a203aSopenharmony_civoid FreezeRuleCluster::ParseTagLinks(xmlNode* tag, FreezeRule& rule)
178020a203aSopenharmony_ci{
179020a203aSopenharmony_ci    for (xmlNode* node = tag->children; node; node = node->next) {
180020a203aSopenharmony_ci        if (TAG_EVENT == std::string((char*)(node->name))) {
181020a203aSopenharmony_ci            std::string domain = GetAttributeValue<std::string>(node, ATTRIBUTE_DOMAIN);
182020a203aSopenharmony_ci            if (domain == "") {
183020a203aSopenharmony_ci                HIVIEW_LOGE("null event attribute:domain.");
184020a203aSopenharmony_ci                return;
185020a203aSopenharmony_ci            }
186020a203aSopenharmony_ci            std::string stringId = GetAttributeValue<std::string>(node, ATTRIBUTE_STRINGID);
187020a203aSopenharmony_ci            if (stringId == "") {
188020a203aSopenharmony_ci                HIVIEW_LOGE("null event attribute:stringid.");
189020a203aSopenharmony_ci                return;
190020a203aSopenharmony_ci            }
191020a203aSopenharmony_ci
192020a203aSopenharmony_ci            long window = GetAttributeValue<long>(node, ATTRIBUTE_WINDOW);
193020a203aSopenharmony_ci
194020a203aSopenharmony_ci            FreezeResult result = FreezeResult(window, domain, stringId);
195020a203aSopenharmony_ci            ParseTagEvent(node, result);
196020a203aSopenharmony_ci            rule.AddResult(domain, stringId, result);
197020a203aSopenharmony_ci
198020a203aSopenharmony_ci            bool principalPoint = false;
199020a203aSopenharmony_ci            if (rule.GetDomain() == domain && rule.GetStringId() == stringId) {
200020a203aSopenharmony_ci                principalPoint = true;
201020a203aSopenharmony_ci            }
202020a203aSopenharmony_ci            if (result.GetScope() == "app") {
203020a203aSopenharmony_ci                applicationPairs_[stringId] = std::pair<std::string, bool>(domain, principalPoint);
204020a203aSopenharmony_ci            } else if (result.GetScope() == "sys") {
205020a203aSopenharmony_ci                systemPairs_[stringId] = std::pair<std::string, bool>(domain, principalPoint);
206020a203aSopenharmony_ci            } else {
207020a203aSopenharmony_ci                sysWarningPairs_[stringId] = std::pair<std::string, bool>(domain, principalPoint);
208020a203aSopenharmony_ci            }
209020a203aSopenharmony_ci        }
210020a203aSopenharmony_ci    }
211020a203aSopenharmony_ci}
212020a203aSopenharmony_ci
213020a203aSopenharmony_civoid FreezeRuleCluster::ParseTagEvent(xmlNode* tag, FreezeResult& result)
214020a203aSopenharmony_ci{
215020a203aSopenharmony_ci    for (xmlNode* node = tag->children; node; node = node->next) {
216020a203aSopenharmony_ci        if (TAG_RESULT == std::string((char*)(node->name))) {
217020a203aSopenharmony_ci            ParseTagResult(node, result);
218020a203aSopenharmony_ci            break;
219020a203aSopenharmony_ci        }
220020a203aSopenharmony_ci    }
221020a203aSopenharmony_ci}
222020a203aSopenharmony_ci
223020a203aSopenharmony_civoid FreezeRuleCluster::ParseTagResult(xmlNode* tag, FreezeResult& result)
224020a203aSopenharmony_ci{
225020a203aSopenharmony_ci    unsigned long code = GetAttributeValue<unsigned long>(tag, ATTRIBUTE_CODE);
226020a203aSopenharmony_ci    std::string scope = GetAttributeValue<std::string>(tag, ATTRIBUTE_SCOPE);
227020a203aSopenharmony_ci    std::string samePackage = GetAttributeValue<std::string>(tag, ATTRIBUTE_SAME_PACKAGE);
228020a203aSopenharmony_ci    std::string action = GetAttributeValue<std::string>(tag, ATTRIBUTE_ACTION);
229020a203aSopenharmony_ci
230020a203aSopenharmony_ci    result.SetId(code);
231020a203aSopenharmony_ci    result.SetScope(scope);
232020a203aSopenharmony_ci    result.SetSamePackage(samePackage);
233020a203aSopenharmony_ci    result.SetAction(action);
234020a203aSopenharmony_ci}
235020a203aSopenharmony_ci
236020a203aSopenharmony_citemplate<typename T>
237020a203aSopenharmony_ciT FreezeRuleCluster::GetAttributeValue(xmlNode* node, const std::string& name)
238020a203aSopenharmony_ci{
239020a203aSopenharmony_ci    xmlChar* prop = xmlGetProp(node, (xmlChar*)(name.c_str()));
240020a203aSopenharmony_ci    std::string propa = "";
241020a203aSopenharmony_ci    if (prop != nullptr) {
242020a203aSopenharmony_ci        propa = (char*)prop;
243020a203aSopenharmony_ci    }
244020a203aSopenharmony_ci    std::istringstream istr(propa);
245020a203aSopenharmony_ci    T value;
246020a203aSopenharmony_ci    istr >> value;
247020a203aSopenharmony_ci    xmlFree(prop);
248020a203aSopenharmony_ci    return value;
249020a203aSopenharmony_ci}
250020a203aSopenharmony_ci
251020a203aSopenharmony_cibool FreezeRuleCluster::GetResult(const WatchPoint& watchPoint, std::vector<FreezeResult>& list)
252020a203aSopenharmony_ci{
253020a203aSopenharmony_ci    std::string domain = watchPoint.GetDomain();
254020a203aSopenharmony_ci    std::string stringId = watchPoint.GetStringId();
255020a203aSopenharmony_ci    if (rules_.find(domain + stringId) == rules_.end()) {
256020a203aSopenharmony_ci        return false;
257020a203aSopenharmony_ci    }
258020a203aSopenharmony_ci    auto map = rules_[domain + stringId].GetMap();
259020a203aSopenharmony_ci    for (auto& i : map) {
260020a203aSopenharmony_ci        list.push_back(i.second);
261020a203aSopenharmony_ci    }
262020a203aSopenharmony_ci
263020a203aSopenharmony_ci    if (list.empty()) {
264020a203aSopenharmony_ci        return false;
265020a203aSopenharmony_ci    }
266020a203aSopenharmony_ci    return true;
267020a203aSopenharmony_ci}
268020a203aSopenharmony_ci
269020a203aSopenharmony_cistd::map<std::string, std::pair<std::string, bool>> FreezeRuleCluster::GetApplicationPairs() const
270020a203aSopenharmony_ci{
271020a203aSopenharmony_ci    return applicationPairs_;
272020a203aSopenharmony_ci}
273020a203aSopenharmony_ci
274020a203aSopenharmony_cistd::map<std::string, std::pair<std::string, bool>> FreezeRuleCluster::GetSystemPairs() const
275020a203aSopenharmony_ci{
276020a203aSopenharmony_ci    return systemPairs_;
277020a203aSopenharmony_ci}
278020a203aSopenharmony_ci
279020a203aSopenharmony_cistd::map<std::string, std::pair<std::string, bool>> FreezeRuleCluster::GetSysWarningPairs() const
280020a203aSopenharmony_ci{
281020a203aSopenharmony_ci    return sysWarningPairs_;
282020a203aSopenharmony_ci}
283020a203aSopenharmony_ci
284020a203aSopenharmony_cistd::string FreezeResult::GetDomain() const
285020a203aSopenharmony_ci{
286020a203aSopenharmony_ci    return domain_;
287020a203aSopenharmony_ci}
288020a203aSopenharmony_ci
289020a203aSopenharmony_cistd::string FreezeResult::GetStringId() const
290020a203aSopenharmony_ci{
291020a203aSopenharmony_ci    return stringId_;
292020a203aSopenharmony_ci}
293020a203aSopenharmony_ci
294020a203aSopenharmony_ciunsigned long FreezeResult::GetId() const
295020a203aSopenharmony_ci{
296020a203aSopenharmony_ci    return code_;
297020a203aSopenharmony_ci}
298020a203aSopenharmony_ci
299020a203aSopenharmony_civoid FreezeResult::SetId(unsigned long code)
300020a203aSopenharmony_ci{
301020a203aSopenharmony_ci    code_ = code;
302020a203aSopenharmony_ci}
303020a203aSopenharmony_ci
304020a203aSopenharmony_cistd::string FreezeResult::GetScope() const
305020a203aSopenharmony_ci{
306020a203aSopenharmony_ci    return scope_;
307020a203aSopenharmony_ci}
308020a203aSopenharmony_ci
309020a203aSopenharmony_civoid FreezeResult::SetScope(const std::string& scope)
310020a203aSopenharmony_ci{
311020a203aSopenharmony_ci    scope_ = scope;
312020a203aSopenharmony_ci}
313020a203aSopenharmony_ci
314020a203aSopenharmony_cilong FreezeResult::GetWindow() const
315020a203aSopenharmony_ci{
316020a203aSopenharmony_ci    return window_;
317020a203aSopenharmony_ci}
318020a203aSopenharmony_ci
319020a203aSopenharmony_cistd::string FreezeResult::GetSamePackage() const
320020a203aSopenharmony_ci{
321020a203aSopenharmony_ci    return samePackage_;
322020a203aSopenharmony_ci}
323020a203aSopenharmony_ci
324020a203aSopenharmony_civoid FreezeResult::SetSamePackage(const std::string& samePackage)
325020a203aSopenharmony_ci{
326020a203aSopenharmony_ci    samePackage_ = samePackage;
327020a203aSopenharmony_ci}
328020a203aSopenharmony_ci
329020a203aSopenharmony_cistd::string FreezeResult::GetAction() const
330020a203aSopenharmony_ci{
331020a203aSopenharmony_ci    return action_;
332020a203aSopenharmony_ci}
333020a203aSopenharmony_ci
334020a203aSopenharmony_civoid FreezeResult::SetAction(const std::string& action)
335020a203aSopenharmony_ci{
336020a203aSopenharmony_ci    action_ = action;
337020a203aSopenharmony_ci}
338020a203aSopenharmony_ci
339020a203aSopenharmony_cistd::string FreezeRule::GetDomain() const
340020a203aSopenharmony_ci{
341020a203aSopenharmony_ci    return domain_;
342020a203aSopenharmony_ci}
343020a203aSopenharmony_ci
344020a203aSopenharmony_civoid FreezeRule::SetDomain(const std::string& domain)
345020a203aSopenharmony_ci{
346020a203aSopenharmony_ci    domain_ = domain;
347020a203aSopenharmony_ci}
348020a203aSopenharmony_ci
349020a203aSopenharmony_cistd::string FreezeRule::GetStringId() const
350020a203aSopenharmony_ci{
351020a203aSopenharmony_ci    return stringId_;
352020a203aSopenharmony_ci}
353020a203aSopenharmony_ci
354020a203aSopenharmony_civoid FreezeRule::SetStringId(const std::string& stringId)
355020a203aSopenharmony_ci{
356020a203aSopenharmony_ci    stringId_ = stringId;
357020a203aSopenharmony_ci}
358020a203aSopenharmony_ci
359020a203aSopenharmony_cistd::map<std::string, FreezeResult> FreezeRule::GetMap() const
360020a203aSopenharmony_ci{
361020a203aSopenharmony_ci    return results_;
362020a203aSopenharmony_ci}
363020a203aSopenharmony_ci
364020a203aSopenharmony_civoid FreezeRule::AddResult(const std::string& domain, const std::string& stringId, const FreezeResult& result)
365020a203aSopenharmony_ci{
366020a203aSopenharmony_ci    if (results_.find(domain + stringId) != results_.end()) {
367020a203aSopenharmony_ci        HIVIEW_LOGE("skip duplicated event tag, stringid:%{public}s.", stringId.c_str());
368020a203aSopenharmony_ci        return;
369020a203aSopenharmony_ci    }
370020a203aSopenharmony_ci
371020a203aSopenharmony_ci    results_[domain + stringId] = result;
372020a203aSopenharmony_ci}
373020a203aSopenharmony_ci
374020a203aSopenharmony_cibool FreezeRule::GetResult(const std::string& domain, const std::string& stringId, FreezeResult& result)
375020a203aSopenharmony_ci{
376020a203aSopenharmony_ci    if (results_.find(domain + stringId) == results_.end()) {
377020a203aSopenharmony_ci        HIVIEW_LOGE("failed to find rule result, domain:%{public}s stringid:%{public}s.",
378020a203aSopenharmony_ci            domain.c_str(), stringId.c_str());
379020a203aSopenharmony_ci        return false;
380020a203aSopenharmony_ci    }
381020a203aSopenharmony_ci
382020a203aSopenharmony_ci    result = results_[domain + stringId]; // take result back
383020a203aSopenharmony_ci    return true;
384020a203aSopenharmony_ci}
385020a203aSopenharmony_ci} // namespace HiviewDFX
386020a203aSopenharmony_ci} // namespace OHOS
387