1 /*
2 * Copyright (c) 2024-2025 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_constant.h"
19 #include "bundle_active_log.h"
20 #include "file_ex.h"
21
22 using namespace std;
23 namespace OHOS {
24 namespace DeviceUsageStats {
25 const static char* CONFIG_PATH = "etc/device_usage_statistics/device_usage_statistics_config.json";
26 const static char* APPLICATION_USE_PERIODICALLY_KEY = "application_use_periodically";
27 const static char* MIN_USE_TIMES = "MinUseTimes";
28 const static char* MAX_USE_TIMES = "MaxUseTimes";
29 const static char* MIN_USE_DAYS = "MinUseDays";
30 const static char* MAX_DATA_SIZE = "MaxDataSize";
31 const static char* APPLICATION_USE_HIGH_FREQUENCY_JUDGE_THRESHOLD =
32 "application_use_high_frequency_judge_threshold";
33 const static char* MIN_TOTAL_USE_DAYS = "MinTotalUseDays";
34 const static char* MIN_TOP_USE_HOURS_LIMIT = "MinTopUseHoursLimit";
35 const static char* MIN_HOUR_USE_DAYS = "MinHourUseDays";
36 const static char* MAX_HIGH_FREQUENCY_HOUR_NUM = "MaxHighFrequencyHourNum";
37 const int32_t DEFAULT_MIN_USE_TIMES = 1;
38 const int32_t DEFAULT_MAX_USE_TIMES = 10;
39 const int32_t DEFAULT_MIN_USE_DAYS = 3;
40 const int32_t DEFAULT_MIN_TOTAL_USE_DAYS = 4;
41 const int32_t DEFAULT_TOP_USE_HOURS_LIMIT = 6;
42 const int32_t DEFAULT_MIN_HOUR_USE_DAYS = 4;
43 const int32_t DEFAULT_MAX_HIGH_FREQUENCY_HOUR_NUM = 3;
44 const int32_t MAX_BUFFER = 2048;
45 const uint64_t DEFAULT_MAX_DATA_SIZE = 5 * 1024 * 1024;
46
47
LoadConfig()48 void BundleActiveConfigReader::LoadConfig()
49 {
50 appUsePeriodicallyConfig_ = {DEFAULT_MIN_USE_TIMES, DEFAULT_MAX_USE_TIMES, DEFAULT_MIN_USE_DAYS};
51 appHighFreqPeriodThresholdConfig_ = {DEFAULT_MIN_TOTAL_USE_DAYS,
52 DEFAULT_TOP_USE_HOURS_LIMIT,
53 DEFAULT_MIN_HOUR_USE_DAYS,
54 DEFAULT_MAX_HIGH_FREQUENCY_HOUR_NUM};
55 auto cfgFiles = GetCfgFiles(CONFIG_PATH);
56 // LCOV_EXCL_START
57 if (!cfgFiles) {
58 BUNDLE_ACTIVE_LOGE("GetCfgFiles failed");
59 return;
60 }
61 // LCOV_EXCL_STOP
62 for (const auto& filePath : cfgFiles->paths) {
63 LoadConfigFile(filePath);
64 }
65 BUNDLE_ACTIVE_LOGI("appUsePeriodicallyConfig minUseTimes:%{public}d, maxUseTimes:%{public}d,"
66 "minUseDays:%{public}d maxDataSize:%{public}lu", appUsePeriodicallyConfig_.minUseTimes,
67 appUsePeriodicallyConfig_.maxUseTimes, appUsePeriodicallyConfig_.minUseDays,
68 static_cast<unsigned long>(maxDataSize_));
69 BUNDLE_ACTIVE_LOGI("appHighFreqPeriodThresholdConfig minTotalUseDays:%{public}d, minTopUseHoursLimit:%{public}d,"
70 "minHourUseDays:%{public}d,"
71 "maxHighFreqHourNum:%{public}d",
72 appHighFreqPeriodThresholdConfig_.minTotalUseDays,
73 appHighFreqPeriodThresholdConfig_.minTopUseHoursLimit,
74 appHighFreqPeriodThresholdConfig_.minHourUseDays,
75 appHighFreqPeriodThresholdConfig_.maxHighFreqHourNum);
76 FreeCfgFiles(cfgFiles);
77 }
78
LoadConfigFile(const char * filePath)79 void BundleActiveConfigReader::LoadConfigFile(const char *filePath)
80 {
81 if (!filePath) {
82 BUNDLE_ACTIVE_LOGE("file does no exit");
83 return;
84 }
85 cJSON *root = nullptr;
86 if (!GetJsonFromFile(filePath, root) || !root) {
87 BUNDLE_ACTIVE_LOGE("file is empty %{private}s", filePath);
88 return;
89 }
90 // LCOV_EXCL_START
91 LoadApplicationUsePeriodically(root);
92 LoadAppHighFreqPeriodThresholdConfig(root);
93 LoadMaxDataSize(root);
94 cJSON_Delete(root);
95 // LCOV_EXCL_STOP
96 }
97
98 // LCOV_EXCL_START
LoadApplicationUsePeriodically(cJSON * root)99 void BundleActiveConfigReader::LoadApplicationUsePeriodically(cJSON* root)
100 {
101 cJSON *appUsePeriodicallyRoot = cJSON_GetObjectItem(root, APPLICATION_USE_PERIODICALLY_KEY);
102 if (!IsValidObject(appUsePeriodicallyRoot)) {
103 BUNDLE_ACTIVE_LOGE("application_use_periodically content is empty");
104 return;
105 }
106
107 int32_t minUseTimes =
108 GetIntValue(appUsePeriodicallyRoot, MIN_USE_TIMES, MINIMUM_LIMIT, INT32_MAX, DEFAULT_MIN_USE_TIMES);
109 int32_t maxUseTimes =
110 GetIntValue(appUsePeriodicallyRoot, MAX_USE_TIMES, MINIMUM_LIMIT, INT32_MAX, DEFAULT_MAX_USE_TIMES);
111 int32_t minUseDays =
112 GetIntValue(appUsePeriodicallyRoot, MIN_USE_DAYS, MINIMUM_LIMIT, INT32_MAX, DEFAULT_MIN_USE_DAYS);
113
114 appUsePeriodicallyConfig_ = {minUseTimes, maxUseTimes, minUseDays};
115 }
116
LoadAppHighFreqPeriodThresholdConfig(cJSON * root)117 void BundleActiveConfigReader::LoadAppHighFreqPeriodThresholdConfig(cJSON* root)
118 {
119 cJSON* appHighFreqPeriodThresholdConfigRoot =
120 cJSON_GetObjectItem(root, APPLICATION_USE_HIGH_FREQUENCY_JUDGE_THRESHOLD);
121 if (!IsValidObject(appHighFreqPeriodThresholdConfigRoot)) {
122 BUNDLE_ACTIVE_LOGE("application_use_high_frequency_judge_threshold content is empty");
123 return;
124 }
125 int32_t minTotalUseDays = GetIntValue(appHighFreqPeriodThresholdConfigRoot,
126 MIN_TOTAL_USE_DAYS,
127 MINIMUM_LIMIT,
128 NUM_DAY_ONE_WEEK,
129 DEFAULT_MIN_TOTAL_USE_DAYS);
130
131 int32_t minTopUseHoursLimit = GetIntValue(appHighFreqPeriodThresholdConfigRoot,
132 MIN_TOP_USE_HOURS_LIMIT,
133 MINIMUM_LIMIT,
134 NUM_HOUR_ONE_DAY,
135 DEFAULT_TOP_USE_HOURS_LIMIT);
136 int32_t minHourUseDays = GetIntValue(appHighFreqPeriodThresholdConfigRoot,
137 MIN_HOUR_USE_DAYS,
138 MINIMUM_LIMIT,
139 NUM_DAY_ONE_WEEK,
140 DEFAULT_MIN_HOUR_USE_DAYS);
141 int32_t maxHighFreqHourNum = GetIntValue(appHighFreqPeriodThresholdConfigRoot,
142 MAX_HIGH_FREQUENCY_HOUR_NUM,
143 MINIMUM_LIMIT,
144 NUM_HOUR_ONE_DAY,
145 DEFAULT_MAX_HIGH_FREQUENCY_HOUR_NUM);
146
147 appHighFreqPeriodThresholdConfig_ = {minTotalUseDays, minTopUseHoursLimit, minHourUseDays, maxHighFreqHourNum};
148 }
149
LoadMaxDataSize(cJSON * root)150 void BundleActiveConfigReader::LoadMaxDataSize(cJSON* root)
151 {
152 cJSON *maxDataSizeItem = cJSON_GetObjectItem(root, MAX_DATA_SIZE);
153 if (!IsValidNumber(maxDataSizeItem)) {
154 BUNDLE_ACTIVE_LOGE("not have max data size key");
155 return;
156 }
157 maxDataSize_ = static_cast<uint64_t>(maxDataSizeItem->valueint);
158 }
159 // LCOV_EXCL_STOP
160
GetJsonFromFile(const char * filePath,cJSON * & root)161 bool BundleActiveConfigReader::GetJsonFromFile(const char *filePath, cJSON *&root)
162 {
163 std::string realPath;
164 if (!BundleActiveConfigReader::ConvertFullPath(filePath, realPath)) {
165 BUNDLE_ACTIVE_LOGE("Get real path failed %{private}s", filePath);
166 return false;
167 }
168 BUNDLE_ACTIVE_LOGD("Read from %{private}s", realPath.c_str());
169 std::string data;
170 if (!LoadStringFromFile(realPath.c_str(), data)) {
171 BUNDLE_ACTIVE_LOGE("load string from %{private}s failed", realPath.c_str());
172 return false;
173 }
174 // LCOV_EXCL_START
175 if (data.empty()) {
176 return false;
177 }
178 root = cJSON_Parse(data.c_str());
179 if (!root) {
180 BUNDLE_ACTIVE_LOGE("parse %{private}s json error", realPath.c_str());
181 return false;
182 }
183 return true;
184 // LCOV_EXCL_STOP
185 }
186
ConvertFullPath(const std::string & partialPath,std::string & fullPath)187 bool BundleActiveConfigReader::ConvertFullPath(const std::string& partialPath, std::string& fullPath)
188 {
189 // LCOV_EXCL_START
190 if (partialPath.empty() || partialPath.length() >= PATH_MAX) {
191 return false;
192 }
193 // LCOV_EXCL_STOP
194 char tmpPath[PATH_MAX] = {0};
195 if (realpath(partialPath.c_str(), tmpPath) == nullptr) {
196 return false;
197 }
198 fullPath = tmpPath;
199 return true;
200 }
201
GetApplicationUsePeriodicallyConfig()202 AppUsePeriodicallyConfig BundleActiveConfigReader::GetApplicationUsePeriodicallyConfig()
203 {
204 return appUsePeriodicallyConfig_;
205 }
206
GetAppHighFrequencyPeriodThresholdConfig()207 AppHighFrequencyPeriodThresholdConfig BundleActiveConfigReader::GetAppHighFrequencyPeriodThresholdConfig()
208 {
209 return appHighFreqPeriodThresholdConfig_;
210 }
211 // LCOV_EXCL_START
GetMaxDataSize()212 uint64_t BundleActiveConfigReader::GetMaxDataSize()
213 {
214 if (maxDataSize_ == 0) {
215 return DEFAULT_MAX_DATA_SIZE;
216 }
217 return maxDataSize_;
218 }
219
GetIntValue(cJSON * root,const char * parameterName,int32_t minLimit,int32_t maxLimit,int32_t defaultValue)220 int32_t BundleActiveConfigReader::GetIntValue(
221 cJSON* root, const char* parameterName, int32_t minLimit, int32_t maxLimit, int32_t defaultValue)
222 {
223 cJSON* item = cJSON_GetObjectItem(root, parameterName);
224 if (!IsValidNumber(item)) {
225 BUNDLE_ACTIVE_LOGE("Configuration parameter %{private}s error", parameterName);
226 return defaultValue;
227 }
228 int32_t value = static_cast<int32_t>(item->valueint);
229 if (value < minLimit || value > maxLimit) {
230 BUNDLE_ACTIVE_LOGE("Configuration parameter %{private}s is invalid value", parameterName);
231 return defaultValue;
232 }
233 return value;
234 }
235
IsValidObject(cJSON * item)236 bool BundleActiveConfigReader::IsValidObject(cJSON* item)
237 {
238 return item != nullptr && cJSON_IsObject(item);
239 }
240
IsValidNumber(cJSON * item)241 bool BundleActiveConfigReader::IsValidNumber(cJSON* item)
242 {
243 return item != nullptr && cJSON_IsNumber(item);
244 }
245 // LCOV_EXCL_STOP
246 } // namespace DeviceUsageStats
247 } // namespace OHOS