1/*
2 * Copyright (c) 2024 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 "parser_util.h"
17
18#include <fstream>
19#include <unistd.h>
20
21#include "config_policy_utils.h"
22#include "hilog_tag_wrapper.h"
23
24namespace OHOS {
25namespace AbilityRuntime {
26namespace {
27constexpr const char *DEFAULT_PRE_BUNDLE_ROOT_DIR = "/system";
28constexpr const char *PRODUCT_SUFFIX = "/etc/app";
29constexpr const char *INSTALL_LIST_CAPABILITY_CONFIG = "/install_list_capability.json";
30constexpr const char *INSTALL_LIST = "install_list";
31constexpr const char *BUNDLE_NAME = "bundleName";
32constexpr const char *KEEP_ALIVE = "keepAlive";
33constexpr const char *KEEP_ALIVE_ENABLE = "keepAliveEnable";
34constexpr const char *KEEP_ALIVE_CONFIGURED_LIST = "keepAliveConfiguredList";
35
36} // namespace
37ParserUtil &ParserUtil::GetInstance()
38{
39    static ParserUtil instance;
40    return instance;
41}
42
43void ParserUtil::GetResidentProcessRawData(std::vector<std::tuple<std::string, std::string, std::string>> &list)
44{
45    std::vector<std::string> rootDirList;
46    GetPreInstallRootDirList(rootDirList);
47
48    for (auto &root : rootDirList) {
49        auto fileDir = root.append(PRODUCT_SUFFIX).append(INSTALL_LIST_CAPABILITY_CONFIG);
50        TAG_LOGD(AAFwkTag::ABILITYMGR, "Search file dir : %{public}s", fileDir.c_str());
51        ParsePreInstallAbilityConfig(fileDir, list);
52    }
53}
54
55void ParserUtil::ParsePreInstallAbilityConfig(
56    const std::string &filePath, std::vector<std::tuple<std::string, std::string, std::string>> &list)
57{
58    nlohmann::json jsonBuf;
59    if (!ReadFileIntoJson(filePath, jsonBuf)) {
60        return;
61    }
62
63    if (jsonBuf.is_discarded()) {
64        return;
65    }
66
67    FilterInfoFromJson(jsonBuf, list);
68}
69
70bool ParserUtil::FilterInfoFromJson(
71    nlohmann::json &jsonBuf, std::vector<std::tuple<std::string, std::string, std::string>> &list)
72{
73    if (jsonBuf.is_discarded()) {
74        TAG_LOGE(AAFwkTag::ABILITYMGR, "format error");
75        return false;
76    }
77
78    if (jsonBuf.find(INSTALL_LIST) == jsonBuf.end()) {
79        TAG_LOGE(AAFwkTag::ABILITYMGR, "installList absent");
80        return false;
81    }
82
83    auto arrays = jsonBuf.at(INSTALL_LIST);
84    if (!arrays.is_array() || arrays.empty()) {
85        TAG_LOGE(AAFwkTag::ABILITYMGR, "not found");
86        return false;
87    }
88
89    std::string bundleName;
90    std::string KeepAliveEnable = "1";
91    std::string KeepAliveConfiguredList;
92    for (const auto &array : arrays) {
93        if (!array.is_object()) {
94            continue;
95        }
96
97        // Judgment logic exists, not found, not bool, not resident process
98        if (!(array.find(KEEP_ALIVE) != array.end() && array.at(KEEP_ALIVE).is_boolean() &&
99                array.at(KEEP_ALIVE).get<bool>())) {
100            continue;
101        }
102
103        if (!(array.find(BUNDLE_NAME) != array.end() && array.at(BUNDLE_NAME).is_string())) {
104            continue;
105        }
106
107        bundleName = array.at(BUNDLE_NAME).get<std::string>();
108
109        if (array.find(KEEP_ALIVE_ENABLE) != array.end() && array.at(KEEP_ALIVE_ENABLE).is_boolean()) {
110            auto val = array.at(KEEP_ALIVE_ENABLE).get<bool>();
111            KeepAliveEnable = std::to_string(val);
112        }
113
114        if (array.find(KEEP_ALIVE_CONFIGURED_LIST) != array.end() && array.at(KEEP_ALIVE_CONFIGURED_LIST).is_array()) {
115            // Save directly in the form of an array and parse it when in use
116            KeepAliveConfiguredList = array.at(KEEP_ALIVE_CONFIGURED_LIST).dump();
117        }
118
119        list.emplace_back(std::make_tuple(bundleName, KeepAliveEnable, KeepAliveConfiguredList));
120        bundleName.clear();
121        KeepAliveEnable = "1";
122        KeepAliveConfiguredList.clear();
123    }
124
125    return true;
126}
127
128void ParserUtil::GetPreInstallRootDirList(std::vector<std::string> &rootDirList)
129{
130    auto cfgDirList = GetCfgDirList();
131    if (cfgDirList != nullptr) {
132        for (const auto &cfgDir : cfgDirList->paths) {
133            if (cfgDir == nullptr) {
134                continue;
135            }
136            rootDirList.emplace_back(cfgDir);
137        }
138
139        FreeCfgDirList(cfgDirList);
140    }
141    bool ret = std::find(rootDirList.begin(), rootDirList.end(), DEFAULT_PRE_BUNDLE_ROOT_DIR) != rootDirList.end();
142    if (!ret) {
143        rootDirList.emplace_back(DEFAULT_PRE_BUNDLE_ROOT_DIR);
144    }
145}
146
147bool ParserUtil::ReadFileIntoJson(const std::string &filePath, nlohmann::json &jsonBuf)
148{
149    if (access(filePath.c_str(), F_OK) != 0) {
150        TAG_LOGE(AAFwkTag::ABILITYMGR, "path not exist");
151        return false;
152    }
153
154    if (filePath.empty()) {
155        TAG_LOGE(AAFwkTag::ABILITYMGR, "empty path");
156        return false;
157    }
158
159    char path[PATH_MAX] = {0};
160    if (realpath(filePath.c_str(), path) == nullptr) {
161        TAG_LOGE(AAFwkTag::ABILITYMGR, "realpath error:%{public}d", errno);
162        return false;
163    }
164
165    std::ifstream fin(path);
166    if (!fin.is_open()) {
167        TAG_LOGE(AAFwkTag::ABILITYMGR, "path exception");
168        return false;
169    }
170
171    fin.seekg(0, std::ios::end);
172    int64_t size = fin.tellg();
173    if (size <= 0) {
174        TAG_LOGE(AAFwkTag::ABILITYMGR, "empty file");
175        fin.close();
176        return false;
177    }
178
179    fin.seekg(0, std::ios::beg);
180    jsonBuf = nlohmann::json::parse(fin, nullptr, false);
181    fin.close();
182    if (jsonBuf.is_discarded()) {
183        TAG_LOGE(AAFwkTag::ABILITYMGR, "bad profile");
184        return false;
185    }
186    return true;
187}
188} // namespace AbilityRuntime
189} // namespace OHOS