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 "bundle_active_config_reader.h"
17 #include "config_policy_utils.h"
18 #include "bundle_active_log.h"
19 #include <fstream>
20 #include <iostream>
21 
22 using namespace std;
23 namespace OHOS {
24 namespace DeviceUsageStats {
25 const char* CONFIG_PATH = "etc/device_usage_statistics/device_usage_statistics_config.json";
26 const std::string APPLICATION_USE_PERIODICALLY_KEY = "application_use_periodically";
27 const std::string MIN_USE_TIMES = "MinUseTimes";
28 const std::string MAX_USE_TIMES = "MaxUseTimes";
29 const std::string MIN_USE_DAYS = "MinUseDays";
30 const int32_t DEFAULT_MIN_USE_TIMES = 1;
31 const int32_t DEFAULT_MAX_USE_TIMES = 10;
32 const int32_t DEFAULT_MIN_USE_DAYS = 3;
33 const int32_t MAX_BUFFER = 2048;
34 
35 
LoadConfig()36 void BundleActiveConfigReader::LoadConfig()
37 {
38     appUsePeriodicallyConfig_ = { DEFAULT_MIN_USE_TIMES, DEFAULT_MAX_USE_TIMES, DEFAULT_MIN_USE_DAYS};
39     auto cfgFiles = GetCfgFiles(CONFIG_PATH);
40     if (!cfgFiles) {
41         BUNDLE_ACTIVE_LOGE("GetCfgFiles failed");
42         return;
43     }
44     for (const auto& filePath : cfgFiles->paths) {
45         LoadApplicationUsePeriodically(filePath);
46     }
47     BUNDLE_ACTIVE_LOGI("appUsePeriodicallyConfig minUseTimes:%{public}d, maxUseTimes:%{public}d,"
48         "minUseDays:%{public}d", appUsePeriodicallyConfig_.minUseTimes,
49         appUsePeriodicallyConfig_.maxUseTimes, appUsePeriodicallyConfig_.minUseDays);
50     FreeCfgFiles(cfgFiles);
51 };
52 
LoadApplicationUsePeriodically(const char * filePath)53 void BundleActiveConfigReader::LoadApplicationUsePeriodically(const char *filePath)
54 {
55     if (!filePath) {
56         return;
57     }
58     Json::Value root;
59     if (!GetJsonFromFile(filePath, root) || root.empty()) {
60         BUNDLE_ACTIVE_LOGE("file is empty %{private}s", filePath);
61         return;
62     }
63     if (!root.isMember(APPLICATION_USE_PERIODICALLY_KEY)) {
64         BUNDLE_ACTIVE_LOGE("not have application_use_periodically key");
65         return;
66     }
67     Json::Value appUsePeriodicallyRoot = root[APPLICATION_USE_PERIODICALLY_KEY];
68     if (appUsePeriodicallyRoot.empty() || !appUsePeriodicallyRoot.isObject()) {
69         BUNDLE_ACTIVE_LOGE("application_use_periodically content is empty");
70         return;
71     }
72     if (appUsePeriodicallyRoot[MIN_USE_TIMES].empty() || !appUsePeriodicallyRoot[MIN_USE_TIMES].isInt()) {
73         BUNDLE_ACTIVE_LOGE("not have MinUseTimes key");
74         return;
75     }
76     int32_t minUseTimes = appUsePeriodicallyRoot[MIN_USE_TIMES].asInt();
77     if (appUsePeriodicallyRoot[MAX_USE_TIMES].empty() || !appUsePeriodicallyRoot[MAX_USE_TIMES].isInt()) {
78         BUNDLE_ACTIVE_LOGE("not have MaxUseTimes key");
79         return;
80     }
81     int32_t maxUseTimes = appUsePeriodicallyRoot[MAX_USE_TIMES].asInt();
82     if (appUsePeriodicallyRoot[MIN_USE_DAYS].empty() || !appUsePeriodicallyRoot[MIN_USE_DAYS].isInt()) {
83         BUNDLE_ACTIVE_LOGE("not have MinUseDays key");
84         return;
85     }
86     int32_t minUseDays = appUsePeriodicallyRoot[MIN_USE_DAYS].asInt();
87     appUsePeriodicallyConfig_ = { minUseTimes, maxUseTimes, minUseDays};
88 };
89 
GetJsonFromFile(const char * filePath,Json::Value & root)90 bool BundleActiveConfigReader::GetJsonFromFile(const char *filePath, Json::Value &root)
91 {
92     ifstream fin;
93     std::string realPath;
94     if (!BundleActiveConfigReader::ConvertFullPath(filePath, realPath)) {
95         BUNDLE_ACTIVE_LOGE("Get real path failed %{private}s", filePath);
96         return false;
97     }
98     BUNDLE_ACTIVE_LOGD("Read from %{private}s", realPath.c_str());
99     fin.open(realPath, ios::in);
100     if (!fin.is_open()) {
101         BUNDLE_ACTIVE_LOGE("cannot open file %{private}s", realPath.c_str());
102         return false;
103     }
104     char buffer[MAX_BUFFER];
105     ostringstream os;
106     while (fin.getline(buffer, MAX_BUFFER)) {
107         os << buffer;
108     }
109     string data = os.str();
110     JSONCPP_STRING errs;
111     Json::CharReaderBuilder readerBuilder;
112     const unique_ptr<Json::CharReader> jsonReader(readerBuilder.newCharReader());
113     bool res = jsonReader->parse(data.c_str(), data.c_str() + data.length(), &root, &errs);
114     fin.close();
115     if (!res || !errs.empty()) {
116         BUNDLE_ACTIVE_LOGE("parse %{private}s json error", realPath.c_str());
117         return false;
118     }
119     return true;
120 }
121 
ConvertFullPath(const std::string & partialPath,std::string & fullPath)122 bool BundleActiveConfigReader::ConvertFullPath(const std::string& partialPath, std::string& fullPath)
123 {
124     if (partialPath.empty() || partialPath.length() >= PATH_MAX) {
125         return false;
126     }
127     char tmpPath[PATH_MAX] = {0};
128     if (realpath(partialPath.c_str(), tmpPath) == nullptr) {
129         return false;
130     }
131     fullPath = tmpPath;
132     return true;
133 }
134 
GetApplicationUsePeriodicallyConfig()135 AppUsePeriodicallyConfig BundleActiveConfigReader::GetApplicationUsePeriodicallyConfig()
136 {
137     return appUsePeriodicallyConfig_;
138 };
139 
140 }  // namespace DeviceUsageStats
141 }  // namespace OHOS
142 
143