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#include "reclaim_priority_constants.h"
16#include "memmgr_log.h"
17#include "xml_helper.h"
18#include "kill_config.h"
19
20namespace OHOS {
21namespace Memory {
22namespace {
23    const std::string TAG = "KillConfig";
24    const unsigned int KILL_LEVEL_ITEMS__MAX_COUNT = 10;
25}
26
27void KillConfig::ClearKillLevelsMap()
28{
29    killLevelsMap_.clear();
30}
31
32void KillConfig::ParseConfig(const xmlNodePtr &rootNodePtr)
33{
34    if (!XmlHelper::CheckNode(rootNodePtr) || !XmlHelper::HasChild(rootNodePtr)) {
35        HILOGD("Node exsist:%{public}d,has child node:%{public}d",
36               XmlHelper::CheckNode(rootNodePtr), XmlHelper::HasChild(rootNodePtr));
37        return;
38    }
39    for (xmlNodePtr currNode = rootNodePtr->xmlChildrenNode; currNode != nullptr; currNode = currNode->next) {
40        std::map<std::string, std::string> param;
41        XmlHelper::GetModuleParam(currNode, param);
42        if (!ParseKillLevelNode(currNode, param) || killLevelsMap_.size() > KILL_LEVEL_ITEMS__MAX_COUNT) {
43            /* if has error, clear set */
44            killLevelsMap_.clear();
45            break;
46        }
47    }
48    if (killLevelsMap_.empty()) {
49        return;
50    }
51    /* check if <memoryMB, minPriority> is increasing, if not, invalid. */
52    int lastPriority = RECLAIM_PRIORITY_MIN - 1;
53    for (auto it = killLevelsMap_.begin(); it != killLevelsMap_.end(); it++) {
54        HILOGD("KillConfig: memory:%{public}u prio:%{public}d lastPrio:%{public}d",
55               it->first, it->second, lastPriority);
56        if (it->second <= lastPriority) {
57            /* Priority list must be decreasing, if not, clear set */
58            HILOGE("KillConfig: memory:%{public}u prio:%{public}d invalid", it->first, it->second);
59            killLevelsMap_.clear();
60            break;
61        }
62        lastPriority = it->second;
63    }
64}
65
66const KillConfig::KillLevelsMap& KillConfig::GetKillLevelsMap()
67{
68    return killLevelsMap_;
69}
70
71bool KillConfig::ParseKillLevelNode(const xmlNodePtr &currNodePtr,
72                                    std::map<std::string, std::string> &param)
73{
74    std::string name = std::string(reinterpret_cast<const char *>(currNodePtr->name));
75    if (name.compare("comment") == 0) {
76        HILOGD("%{public}s comment skip :<%{public}s>", __func__, name.c_str());
77        return true;
78    }
79    if (name.compare("killLevel") != 0) {
80        HILOGW("%{public}s unknown node :<%{public}s>", __func__, name.c_str());
81        return false;
82    }
83    unsigned int memoryMB;
84    int minPriority;
85    XmlHelper::SetUnsignedIntParam(param, "memoryMB", memoryMB, 0);
86    XmlHelper::SetIntParam(param, "minPriority", minPriority, RECLAIM_PRIORITY_MAX + 1);
87    /* if read from xml fail, error */
88    if (memoryMB == 0 || minPriority == (RECLAIM_PRIORITY_MAX + 1)) {
89        HILOGE("node:<%{public}s> <%{public}u, %{public}d> read fail", name.c_str(), memoryMB, minPriority);
90        return false;
91    }
92    if ((memoryMB * KB_PER_MB) > UINT_MAX) {
93        HILOGE("<%{public}s> %{public}u MB to KB > UINT_MAX", name.c_str(), memoryMB);
94        return false;
95    }
96    unsigned int memoryKB = memoryMB * KB_PER_MB; /* MB to KB */
97    if (killLevelsMap_.count(memoryKB) > 0) { /* if key @memoryKB has exist, error */
98        HILOGE("node:<%{public}s> <%{public}u, %{public}d> key has exist, mapSize:%{public}zu",
99               name.c_str(), memoryKB, minPriority, killLevelsMap_.size());
100        return false;
101    }
102    killLevelsMap_.insert(std::make_pair(memoryKB, minPriority));
103    return true;
104}
105
106void KillConfig::Dump(int fd)
107{
108    dprintf(fd, "KillConfig:   \n");
109    for (auto it = killLevelsMap_.begin(); it != killLevelsMap_.end(); it++) {
110        dprintf(fd, "                   memory:%u  ---->  prio:%d \n", it->first, it->second);
111    }
112}
113} // namespace Memory
114} // namespace OHOS
115