1 /*
2  * Copyright (c) 2023 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 "standby_config_manager.h"
17 
18 #include <functional>
19 #include <string>
20 #include <sstream>
21 #include <unistd.h>
22 #include <dlfcn.h>
23 
24 #ifdef STANDBY_CONFIG_POLICY_ENABLE
25 #include "config_policy_utils.h"
26 #endif
27 #include "json_utils.h"
28 #include "standby_service_log.h"
29 
30 namespace OHOS {
31 namespace DevStandbyMgr {
32 namespace {
33     const std::string DEFAULT_CONFIG_ROOT_DIR = "/system";
34     const std::string STANDBY_CONFIG_PATH = "/etc/standby_service/device_standby_config.json";
35     const int32_t STANDBY_CONFIG_INDEX = 5;
36     const std::string STRATEGY_CONFIG_PATH = "/etc/standby_service/standby_strategy_config.json";
37     const int32_t STRATEGY_CONFIG_INDEX = 6;
38     const int32_t CLOUD_CONFIG_INDEX = 7;
39     const char* EXT_CONFIG_LIB = "libsuspend_manager_service.z.so";
40     const std::string TAG_PLUGIN_NAME = "plugin_name";
41     const std::string TAG_STANDBY = "standby";
42     const std::string TAG_MAINTENANCE_LIST = "maintenance_list";
43     const std::string TAG_DETECT_LIST = "detect_list";
44     const std::string TAG_STRATEGY_LIST = "strategy_list";
45     const std::string TAG_HALFHOUR_SWITCH_SETTING = "halfhour_switch_setting";
46 
47     const std::string TAG_SETTING_LIST = "setting_list";
48     const std::string TAG_VER = "version";
49     const int VERSION_LEN = 4;
50     const int DEC = 10;
51     const char VERSION_DELIM = '.';
52     const std::string TAG_CONDITION = "condition";
53     const std::string TAG_ACTION = "action";
54     const std::string TAG_ALLOW = "allow";
55     const std::string TAG_PROCESSES = "processes";
56     const std::string TAG_APPS = "apps";
57     const std::string TAG_PROCESSES_LIMIT = "processes_limit";
58     const std::string TAG_TIME_CLOCK_APPS = "time_clock_apps";
59     const std::string TAG_APPS_LIMIT = "apps_limit";
60     const std::string TAG_NAME = "name";
61     const std::string TAG_MAX_DURATION_LIM = "duration";
62 
63     const std::string TAG_TIMER = "TIMER";
64     const std::string TAG_TIMER_CLOCK = "timer_clock";
65     const std::string TAG_TIMER_PERIOD = "timer_period";
66 
67     const char TAG_CONDITION_DELIM = '&';
68     const std::string TAG_DAY_STANDBY = "day_standby";
69     const std::string TAG_NIGHT_STANDBY = "night_standby";
70     const std::string TAG_SCREENOFF = "screenoff";
71     const std::string TAG_SCREENOFF_HALFHOUR = "screenoff_halfhour";
72     const std::unordered_map<std::string, ConditionType::Type> conditionMap = {
73         {TAG_DAY_STANDBY, ConditionType::DAY_STANDBY},
74         {TAG_NIGHT_STANDBY, ConditionType::NIGHT_STANDBY},
75     };
76 }
77 
78 IMPLEMENT_SINGLE_INSTANCE(StandbyConfigManager);
79 
StandbyConfigManager()80 StandbyConfigManager::StandbyConfigManager() {}
81 
~StandbyConfigManager()82 StandbyConfigManager::~StandbyConfigManager() {}
83 
Init()84 ErrCode StandbyConfigManager::Init()
85 {
86     STANDBYSERVICE_LOGI("start to read config");
87     LoadGetExtConfigFunc();
88     GetAndParseStandbyConfig();
89     GetAndParseStrategyConfig();
90     if (NeedsToReadCloudConfig()) {
91         GetCloudConfig();
92     }
93     return ERR_OK;
94 }
95 
GetAndParseStandbyConfig()96 void StandbyConfigManager::GetAndParseStandbyConfig()
97 {
98     std::vector<std::string> configContentList;
99     if (getExtConfigFunc_ != nullptr && getExtConfigFunc_(STANDBY_CONFIG_INDEX, configContentList) == ERR_OK) {
100         for (const auto& content : configContentList) {
101             nlohmann::json devStandbyConfigRoot;
102             if (!JsonUtils::LoadJsonValueFromContent(devStandbyConfigRoot, content)) {
103                 STANDBYSERVICE_LOGE("load config failed");
104                 continue;
105             }
106             if (!ParseDeviceStanbyConfig(devStandbyConfigRoot)) {
107                 STANDBYSERVICE_LOGE("parse config failed");
108             }
109         }
110     } else {
111         std::vector<std::string> configFileList = GetConfigFileList(STANDBY_CONFIG_PATH);
112         for (const auto& configFile : configFileList) {
113             nlohmann::json devStandbyConfigRoot;
114             // if failed to load one json file, read next config file
115             if (!JsonUtils::LoadJsonValueFromFile(devStandbyConfigRoot, configFile)) {
116                 STANDBYSERVICE_LOGE("load config file %{public}s failed", configFile.c_str());
117                 continue;
118             }
119             if (!ParseDeviceStanbyConfig(devStandbyConfigRoot)) {
120                 STANDBYSERVICE_LOGE("parse config file %{public}s failed", configFile.c_str());
121             }
122         }
123     }
124     UpdateStrategyList();
125 }
126 
GetAndParseStrategyConfig()127 void StandbyConfigManager::GetAndParseStrategyConfig()
128 {
129     std::vector<std::string> configContentList;
130     if (getExtConfigFunc_ != nullptr && getExtConfigFunc_(STRATEGY_CONFIG_INDEX, configContentList) == ERR_OK) {
131         for (const auto& content : configContentList) {
132             nlohmann::json resCtrlConfigRoot;
133             if (!JsonUtils::LoadJsonValueFromContent(resCtrlConfigRoot, content)) {
134                 STANDBYSERVICE_LOGE("load config failed");
135                 continue;
136             }
137             if (!ParseResCtrlConfig(resCtrlConfigRoot)) {
138                 STANDBYSERVICE_LOGE("parse config failed");
139             }
140         }
141     } else {
142         std::vector<std::string> configFileList = GetConfigFileList(STRATEGY_CONFIG_PATH);
143         for (const auto& configFile : configFileList) {
144             nlohmann::json resCtrlConfigRoot;
145             if (!JsonUtils::LoadJsonValueFromFile(resCtrlConfigRoot, configFile)) {
146                 STANDBYSERVICE_LOGE("load config file %{public}s failed", configFile.c_str());
147                 continue;
148             }
149             if (!ParseResCtrlConfig(resCtrlConfigRoot)) {
150                 STANDBYSERVICE_LOGE("parse config file %{public}s failed", configFile.c_str());
151             }
152         }
153     }
154 }
155 
GetCloudConfig()156 void StandbyConfigManager::GetCloudConfig()
157 {
158     if (getSingleExtConfigFunc_ == nullptr) {
159         return;
160     }
161     std::string configCloud;
162     int32_t returnCode = getSingleExtConfigFunc_(CLOUD_CONFIG_INDEX, configCloud);
163     if (returnCode == ERR_OK) {
164         nlohmann::json ConfigRoot;
165         JsonUtils::LoadJsonValueFromContent(ConfigRoot, configCloud);
166         ParseCloudConfig(ConfigRoot);
167     } else {
168         STANDBYSERVICE_LOGE("Decrypt errcode: %{public}d.", returnCode);
169     }
170     UpdateStrategyList();
171 }
172 
ParseCloudConfig(const nlohmann::json & devConfigRoot)173 void StandbyConfigManager::ParseCloudConfig(const nlohmann::json& devConfigRoot)
174 {
175     nlohmann::json settingConfig;
176     nlohmann::json listConfig;
177 
178     if (JsonUtils::GetObjFromJsonValue(devConfigRoot, TAG_SETTING_LIST, settingConfig) &&
179         !ParseStandbyConfig(settingConfig)) {
180         STANDBYSERVICE_LOGW("Failed to parse cloud config in %{public}s", TAG_SETTING_LIST.c_str());
181     }
182     if (JsonUtils::GetObjFromJsonValue(devConfigRoot, TAG_STRATEGY_LIST, listConfig) &&
183         !ParseStrategyListConfig(listConfig)) {
184         STANDBYSERVICE_LOGW("Failed to parse cloud config in %{public}s", TAG_STRATEGY_LIST.c_str());
185     }
186     if (!ParseResCtrlConfig(devConfigRoot)) {
187         STANDBYSERVICE_LOGW("Failed to parse cloud config in standby strategy.");
188     }
189 }
190 
LoadGetExtConfigFunc()191 void StandbyConfigManager::LoadGetExtConfigFunc()
192 {
193     auto handle = dlopen(EXT_CONFIG_LIB, RTLD_NOW);
194     if (!handle) {
195         STANDBYSERVICE_LOGE("not find lib");
196         return;
197     }
198     getExtConfigFunc_ = reinterpret_cast<GetExtConfigFunc>(dlsym(handle, "GetExtMultiConfig"));
199     getSingleExtConfigFunc_ = reinterpret_cast<GetSingleExtConfigFunc>(dlsym(handle, "GetExtConfig"));
200     if (!getSingleExtConfigFunc_) {
201         STANDBYSERVICE_LOGE("Failed to load GetExtConfig.");
202     }
203     if (!getExtConfigFunc_) {
204         STANDBYSERVICE_LOGE("get func failed");
205         dlclose(handle);
206     }
207 }
208 
NeedsToReadCloudConfig()209 bool StandbyConfigManager::NeedsToReadCloudConfig()
210 {
211     std::string cloudConfigVer;
212     std::string deviceConfigVer;
213     std::string strategyConfigVer;
214     if (!GetParamVersion(STANDBY_CONFIG_INDEX, deviceConfigVer)) {
215         STANDBYSERVICE_LOGE("failed to get the version of fileIndex: %{public}d", STANDBY_CONFIG_INDEX);
216     }
217     if (!GetParamVersion(STRATEGY_CONFIG_INDEX, strategyConfigVer)) {
218         STANDBYSERVICE_LOGE("failed to get the version of fileIndex: %{public}d", STRATEGY_CONFIG_INDEX);
219     }
220     if (!GetCloudVersion(CLOUD_CONFIG_INDEX, cloudConfigVer)) {
221         STANDBYSERVICE_LOGE("failed to get the version of fileIndex: %{public}d", CLOUD_CONFIG_INDEX);
222     }
223     std::string temp;
224     int result = CompareVersion(deviceConfigVer, strategyConfigVer);
225     if (result < 0) {
226         STANDBYSERVICE_LOGI("do not need to read cloud config.");
227         return false;
228     } else {
229         temp = (result > 0)? deviceConfigVer : strategyConfigVer;
230     }
231     bool ret = CompareVersion(cloudConfigVer, temp) > 0;
232     STANDBYSERVICE_LOGI("cloud config:%{public}d, cloud:%{public}s, device:%{public}s, strategy:%{public}s",
233         ret, cloudConfigVer.c_str(), deviceConfigVer.c_str(), strategyConfigVer.c_str());
234     return ret;
235 }
236 
CompareVersion(const std::string & configVerA,const std::string & configVerB)237 int StandbyConfigManager::CompareVersion(const std::string& configVerA, const std::string& configVerB)
238 {
239     if (!configVerA.empty() && configVerB.empty()) {
240         return 1;
241     }
242     if (configVerA.empty() && !configVerB.empty()) {
243         return 0;
244     }
245     if (configVerA.empty() && configVerB.empty()) {
246         return -1;
247     }
248     std::vector<std::string> segA = JsonUtils::SplitVersion(configVerA, VERSION_DELIM);
249     if (segA.size() != VERSION_LEN) {
250         STANDBYSERVICE_LOGE("segment size error: %{public}s", configVerA.c_str());
251         return -1;
252     }
253     std::vector<std::string> segB = JsonUtils::SplitVersion(configVerB, VERSION_DELIM);
254     if (segB.size() != VERSION_LEN) {
255         STANDBYSERVICE_LOGE("segment size error: %{public}s", configVerB.c_str());
256         return -1;
257     }
258     for (int i = 0; i < VERSION_LEN; i++) {
259         if (!isdigit(segA[i][0]) || !isdigit(segB[i][0])) {
260             STANDBYSERVICE_LOGE("segment not digit");
261             return -1;
262         }
263         if (segB[i] != segA[i]) {
264             int ret = (strtol(segB[i].c_str(), nullptr, DEC) < strtol(segA[i].c_str(), nullptr, DEC)) ? 1 : 0;
265             return ret;
266         }
267     }
268     return 1;
269 }
270 
GetParamVersion(const int32_t & fileIndex,std::string & version)271 bool StandbyConfigManager::GetParamVersion(const int32_t& fileIndex, std::string& version)
272 {
273     if (getExtConfigFunc_ == nullptr) {
274         return true;
275     }
276     if (fileIndex != STANDBY_CONFIG_INDEX && fileIndex != STRATEGY_CONFIG_INDEX) {
277         STANDBYSERVICE_LOGE("invalid input when getting version.");
278         return false;
279     }
280     std::vector<std::string> configContentList;
281     int32_t returnCode = getExtConfigFunc_(fileIndex, configContentList);
282     if (returnCode != ERR_OK) {
283         STANDBYSERVICE_LOGE("Decrypt fail.");
284         return false;
285     }
286     std::string tempVersion;
287     for (const auto& content : configContentList) {
288         nlohmann::json devStandbyConfigRoot;
289         if (!JsonUtils::LoadJsonValueFromContent(devStandbyConfigRoot, content)) {
290             continue;
291         }
292         if (!JsonUtils::GetStringFromJsonValue(devStandbyConfigRoot, TAG_VER, tempVersion)) {
293             STANDBYSERVICE_LOGE("failed to get version");
294             continue;
295         }
296         if (CompareVersion(tempVersion, version)) {
297             version = tempVersion;
298         }
299     }
300     return true;
301 }
302 
GetCloudVersion(const int32_t & fileIndex,std::string & version)303 bool StandbyConfigManager::GetCloudVersion(const int32_t& fileIndex, std::string& version)
304 {
305     if (getSingleExtConfigFunc_ == nullptr) {
306         return true;
307     }
308     if (fileIndex != CLOUD_CONFIG_INDEX) {
309         STANDBYSERVICE_LOGE("invalid input when getting version.");
310         return false;
311     }
312     std::string configCloud;
313     int32_t returnCode = getSingleExtConfigFunc_(fileIndex, configCloud);
314     if (returnCode != ERR_OK) {
315         STANDBYSERVICE_LOGE("Decrypt fail.");
316         return false;
317     }
318     nlohmann::json devStandbyConfigRoot;
319     JsonUtils::LoadJsonValueFromContent(devStandbyConfigRoot, configCloud);
320     if (!JsonUtils::GetStringFromJsonValue(devStandbyConfigRoot, TAG_VER, version)) {
321         STANDBYSERVICE_LOGE("failed to get version");
322     }
323     return true;
324 }
325 
GetConfigFileList(const std::string & relativeConfigPath)326 std::vector<std::string> StandbyConfigManager::GetConfigFileList(const std::string& relativeConfigPath)
327 {
328     std::list<std::string> rootDirList;
329 #ifdef STANDBY_CONFIG_POLICY_ENABLE
330         auto cfgDirList = GetCfgDirList();
331         if (cfgDirList != nullptr) {
332             for (const auto &cfgDir : cfgDirList->paths) {
333                 if (cfgDir == nullptr) {
334                     continue;
335                 }
336                 STANDBYSERVICE_LOGD("cfgDir: %{public}s ", cfgDir);
337                 rootDirList.emplace_back(cfgDir);
338             }
339             FreeCfgDirList(cfgDirList);
340         }
341 #endif
342     if (std::find(rootDirList.begin(), rootDirList.end(), DEFAULT_CONFIG_ROOT_DIR)
343         == rootDirList.end()) {
344         rootDirList.emplace_front(DEFAULT_CONFIG_ROOT_DIR);
345     }
346     std::string baseRealPath;
347     std::vector<std::string> configFilesList;
348     for (auto configDir : rootDirList) {
349         if (JsonUtils::GetRealPath(configDir + relativeConfigPath, baseRealPath)
350             && access(baseRealPath.c_str(), F_OK) == ERR_OK) {
351             STANDBYSERVICE_LOGD("Get valid base config file: %{public}s", baseRealPath.c_str());
352             configFilesList.emplace_back(baseRealPath);
353         }
354     }
355     return configFilesList;
356 }
357 
GetPluginName()358 const std::string& StandbyConfigManager::GetPluginName()
359 {
360     return pluginName_;
361 }
362 
GetStandbySwitch(const std::string & switchName)363 bool StandbyConfigManager::GetStandbySwitch(const std::string& switchName)
364 {
365     return GetConfigWithName(switchName, standbySwitchMap_);
366 }
367 
GetStandbyParam(const std::string & paramName)368 int32_t StandbyConfigManager::GetStandbyParam(const std::string& paramName)
369 {
370     return GetConfigWithName(paramName, standbyParaMap_);
371 }
372 
GetStrategySwitch(const std::string & switchName)373 bool StandbyConfigManager::GetStrategySwitch(const std::string& switchName)
374 {
375     return GetConfigWithName(switchName, strategySwitchMap_);
376 }
377 
GetHalfHourSwitch(const std::string & switchName)378 bool StandbyConfigManager::GetHalfHourSwitch(const std::string& switchName)
379 {
380     return GetConfigWithName(switchName, halfhourSwitchMap_);
381 }
382 
GetResCtrlConfig(const std::string & switchName)383 std::shared_ptr<std::vector<DefaultResourceConfig>> StandbyConfigManager::GetResCtrlConfig(const
384     std::string& switchName)
385 {
386     return GetConfigWithName(switchName, defaultResourceConfigMap_);
387 }
388 
389 template<typename T>
GetConfigWithName(const std::string & switchName,std::unordered_map<std::string,T> & configMap)390 T StandbyConfigManager::GetConfigWithName(const std::string& switchName,
391     std::unordered_map<std::string, T>& configMap)
392 {
393     std::lock_guard<std::mutex> lock(configMutex_);
394     auto iter = configMap.find(switchName);
395     if (iter == configMap.end()) {
396         STANDBYSERVICE_LOGW("failed to find config %{public}s", switchName.c_str());
397         return T{};
398     }
399     return iter->second;
400 }
401 
GetTimerResConfig()402 const std::vector<TimerResourceConfig>& StandbyConfigManager::GetTimerResConfig()
403 {
404     return timerResConfigList_;
405 }
406 
GetStrategyConfigList(const std::string & switchName)407 bool StandbyConfigManager::GetStrategyConfigList(const std::string& switchName)
408 {
409     return GetConfigWithName(switchName, strategyListMap_);
410 }
411 
GetStrategyConfigList()412 const std::vector<std::string>& StandbyConfigManager::GetStrategyConfigList()
413 {
414     return strategyList_;
415 }
416 
GetStandbyDurationList(const std::string & switchName)417 std::vector<int32_t> StandbyConfigManager::GetStandbyDurationList(const std::string& switchName)
418 {
419     return GetConfigWithName(switchName, intervalListMap_);
420 }
421 
GetMaxDuration(const std::string & name,const std::string & paramName,uint32_t condition,bool isApp)422 int32_t StandbyConfigManager::GetMaxDuration(const std::string& name, const std::string& paramName,
423     uint32_t condition, bool isApp)
424 {
425     auto eligibleAllowTimeList = GetEligibleAllowTimeConfig(paramName, condition, true, isApp);
426     auto findConfigTask = [&name](const auto& it) { return it.name_ == name; };
427     auto it = std::find_if(eligibleAllowTimeList.begin(), eligibleAllowTimeList.end(), findConfigTask);
428     if (it == eligibleAllowTimeList.end()) {
429         return 0;
430     } else {
431         return it->maxDurationLim_;
432     }
433 }
434 
GetEligibleAllowConfig(const std::string & paramName,uint32_t condition,bool isAllow,bool isApp,const std::function<void (bool,std::set<T> &,const DefaultResourceConfig &)> & func)435 template<typename T> std::set<T> StandbyConfigManager::GetEligibleAllowConfig(const std::string& paramName,
436     uint32_t condition, bool isAllow, bool isApp, const std::function<void(bool, std::set<T>&,
437     const DefaultResourceConfig&)>& func)
438 {
439     if (defaultResourceConfigMap_.find(paramName) == defaultResourceConfigMap_.end()) {
440         return {};
441     }
442     std::set<T> eligibleResCtrlConfig;
443     const auto& resCtrlConfig = *(defaultResourceConfigMap_.find(paramName)->second);
444     STANDBYSERVICE_LOGD("find duration from %{public}s, size is %{public}d",
445         paramName.c_str(), static_cast<int32_t>(resCtrlConfig.size()));
446     for (const auto& config : resCtrlConfig) {
447         if (config.isAllow_ != isAllow) {
448             continue;
449         }
450         bool isEligiable {false};
451         for (const auto configCondition : config.conditions_) {
452             if ((condition & configCondition) == configCondition) {
453                 isEligiable = true;
454                 break;
455             }
456         }
457         if (!isEligiable) {
458             continue;
459         }
460         func(isApp, eligibleResCtrlConfig, config);
461     }
462     STANDBYSERVICE_LOGD("eligibleResCtrlConfig size is %{public}d",
463         static_cast<int32_t>(eligibleResCtrlConfig.size()));
464     return eligibleResCtrlConfig;
465 }
466 
GetEligibleAllowTimeConfig(const std::string & paramName,uint32_t condition,bool isAllow,bool isApp)467 std::set<TimeLtdProcess> StandbyConfigManager::GetEligibleAllowTimeConfig(const std::string& paramName,
468     uint32_t condition, bool isAllow, bool isApp)
469 {
470     auto func = [](bool isApp, std::set<TimeLtdProcess>& eligibleResCtrlConfig,
471         const DefaultResourceConfig& config) {
472         if (isApp) {
473             eligibleResCtrlConfig.insert(config.timeLtdApps_.begin(), config.timeLtdApps_.end());
474         } else {
475             eligibleResCtrlConfig.insert(config.timeLtdProcesses_.begin(), config.timeLtdProcesses_.end());
476         }
477         STANDBYSERVICE_LOGD("after calculate, eligible size is %{public}d",
478             static_cast<int32_t>(eligibleResCtrlConfig.size()));
479     };
480     return GetEligibleAllowConfig<TimeLtdProcess>(paramName, condition, isAllow, isApp, func);
481 }
482 
GetEligiblePersistAllowConfig(const std::string & paramName,uint32_t condition,bool isAllow,bool isApp)483 std::set<std::string> StandbyConfigManager::GetEligiblePersistAllowConfig(const std::string& paramName,
484     uint32_t condition, bool isAllow, bool isApp)
485 {
486     auto func = [](bool isApp, std::set<std::string>& eligibleResCtrlConfig,
487         const DefaultResourceConfig& config) {
488         if (isApp) {
489             eligibleResCtrlConfig.insert(config.apps_.begin(), config.apps_.end());
490         } else {
491             eligibleResCtrlConfig.insert(config.processes_.begin(), config.processes_.end());
492         }
493     };
494     return GetEligibleAllowConfig<std::string>(paramName, condition, isAllow, isApp, func);
495 }
496 
ParseDeviceStanbyConfig(const nlohmann::json & devStandbyConfigRoot)497 bool StandbyConfigManager::ParseDeviceStanbyConfig(const nlohmann::json& devStandbyConfigRoot)
498 {
499     nlohmann::json standbyConfig;
500     nlohmann::json detectlist;
501     nlohmann::json standbySwitchConfig;
502     nlohmann::json standbyListConfig;
503     nlohmann::json standbyIntervalList;
504 
505     JsonUtils::GetStringFromJsonValue(devStandbyConfigRoot, TAG_PLUGIN_NAME, pluginName_);
506     if (JsonUtils::GetObjFromJsonValue(devStandbyConfigRoot, TAG_STANDBY, standbyConfig) &&
507         !ParseStandbyConfig(standbyConfig)) {
508         STANDBYSERVICE_LOGW("failed to parse standby config in %{public}s", STANDBY_CONFIG_PATH.c_str());
509         return false;
510     }
511     if (JsonUtils::GetObjFromJsonValue(devStandbyConfigRoot, TAG_DETECT_LIST, detectlist) &&
512         !ParseStandbyConfig(detectlist)) {
513         STANDBYSERVICE_LOGW("failed to parse detect list in %{public}s", STANDBY_CONFIG_PATH.c_str());
514         return false;
515     }
516     if (JsonUtils::GetObjFromJsonValue(devStandbyConfigRoot, TAG_MAINTENANCE_LIST, standbyIntervalList) &&
517         !ParseIntervalList(standbyIntervalList)) {
518         STANDBYSERVICE_LOGW("failed to parse standby interval list in %{public}s", STANDBY_CONFIG_PATH.c_str());
519         return false;
520     }
521     if (JsonUtils::GetObjFromJsonValue(devStandbyConfigRoot, TAG_STRATEGY_LIST, standbyListConfig) &&
522         !ParseStrategyListConfig(standbyListConfig)) {
523         STANDBYSERVICE_LOGW("failed to parse strategy list config in %{public}s", STANDBY_CONFIG_PATH.c_str());
524         return false;
525     }
526 
527     if (JsonUtils::GetObjFromJsonValue(devStandbyConfigRoot, TAG_HALFHOUR_SWITCH_SETTING, standbyConfig)) {
528         if (!ParseHalfHourSwitchConfig(standbyConfig)) {
529             STANDBYSERVICE_LOGW("failed to parse halfhour config");
530             return false;
531         }
532     }
533     return true;
534 }
535 
ParseStandbyConfig(const nlohmann::json & standbyConfig)536 bool StandbyConfigManager::ParseStandbyConfig(const nlohmann::json& standbyConfig)
537 {
538     bool ret = true;
539     for (const auto& element : standbyConfig.items()) {
540         if (!element.value().is_primitive()) {
541             STANDBYSERVICE_LOGW("there is unexpected type of key in standby config %{public}s", element.key().c_str());
542             ret = false;
543             continue;
544         }
545         if (element.value().is_boolean()) {
546             standbySwitchMap_[element.key()] = element.value().get<bool>();
547         } else if (element.value().is_number_integer()) {
548             if (element.value().get<int32_t>() < 0) {
549                 STANDBYSERVICE_LOGW("there is negative value in standby config %{public}s", element.key().c_str());
550                 ret = false;
551                 continue;
552             }
553             standbyParaMap_[element.key()] = element.value().get<int32_t>();
554         }
555     }
556     return ret;
557 }
558 
ParseIntervalList(const nlohmann::json & standbyIntervalList)559 bool StandbyConfigManager::ParseIntervalList(const nlohmann::json& standbyIntervalList)
560 {
561     bool ret = true;
562     for (const auto& element : standbyIntervalList.items()) {
563         if (!element.value().is_array()) {
564             STANDBYSERVICE_LOGW("there is unexpected value of %{public}s in standby interval list",
565                 element.key().c_str());
566             ret = false;
567             continue;
568         }
569         std::vector<int32_t> intervalList;
570         for (const int32_t interval : element.value()) {
571             intervalList.emplace_back(interval);
572         }
573         intervalListMap_.emplace(element.key(), std::move(intervalList));
574     }
575     return ret;
576 }
577 
ParseStrategyListConfig(const nlohmann::json & standbyListConfig)578 bool StandbyConfigManager::ParseStrategyListConfig(const nlohmann::json& standbyListConfig)
579 {
580     bool ret = true;
581     for (const auto& element : standbyListConfig.items()) {
582         if (!element.value().is_boolean()) {
583             STANDBYSERVICE_LOGW("there is unexpected type of value in half hour standby switch config %{public}s",
584                 element.key().c_str());
585             ret = false;
586             continue;
587         }
588         strategyListMap_[element.key()] = element.value().get<bool>();
589     }
590     return ret;
591 }
592 
UpdateStrategyList()593 void StandbyConfigManager::UpdateStrategyList()
594 {
595     strategyList_.clear();
596     for (const auto& it : strategyListMap_) {
597         if (it.second) {
598             strategyList_.emplace_back(it.first);
599         }
600     }
601     if (strategyList_.empty()) {
602         STANDBYSERVICE_LOGI("No strategy is set to true.");
603     }
604 }
605 
ParseHalfHourSwitchConfig(const nlohmann::json & halfHourSwitchConfig)606 bool StandbyConfigManager::ParseHalfHourSwitchConfig(const nlohmann::json& halfHourSwitchConfig)
607 {
608     bool ret = true;
609     for (const auto& element : halfHourSwitchConfig.items()) {
610         if (!element.value().is_boolean()) {
611             STANDBYSERVICE_LOGW("there is unexpected type of value in half hour standby switch config %{public}s",
612                 element.key().c_str());
613             ret = false;
614             return ret;
615         }
616         halfhourSwitchMap_[element.key()] = element.value().get<bool>();
617     }
618     return ret;
619 }
620 
ParseResCtrlConfig(const nlohmann::json & resCtrlConfigRoot)621 bool StandbyConfigManager::ParseResCtrlConfig(const nlohmann::json& resCtrlConfigRoot)
622 {
623     bool ret = true;
624     for (const auto& element : resCtrlConfigRoot.items()) {
625         if (!element.value().is_array()) {
626             STANDBYSERVICE_LOGW("there is unexpected type of value in resource control config %{public}s",
627                 element.key().c_str());
628             ret = false;
629             continue;
630         }
631         std::string resCtrlKey = element.key();
632         if (!ParseDefaultResCtrlConfig(resCtrlKey, element.value())) {
633             STANDBYSERVICE_LOGW("there is error in config of %{public}s", resCtrlKey.c_str());
634             ret = false;
635             continue;
636         }
637         // parse exemption config of timer resource
638         if (resCtrlKey == TAG_TIMER && !ParseTimerResCtrlConfig(element.value())) {
639             STANDBYSERVICE_LOGW("there is error in config of %{public}s", resCtrlKey.c_str());
640             ret = false;
641             continue;
642         }
643     }
644     return ret;
645 }
646 
ParseTimerResCtrlConfig(const nlohmann::json & resConfigArray)647 bool StandbyConfigManager::ParseTimerResCtrlConfig(const nlohmann::json& resConfigArray)
648 {
649     if (!resConfigArray.is_array()) {
650         STANDBYSERVICE_LOGW("the value of timer config should be an array");
651         return false;
652     }
653     timerResConfigList_.clear();
654     for (const auto &singleConfigItem : resConfigArray) {
655         TimerResourceConfig timerResourceConfig;
656         if (!singleConfigItem.contains(TAG_TIME_CLOCK_APPS) || !singleConfigItem.at(TAG_TIME_CLOCK_APPS).is_array()) {
657             timerResConfigList_.emplace_back(std::move(timerResourceConfig));
658             continue;
659         }
660         const nlohmann::json& limitedAppItems = singleConfigItem.at(TAG_TIME_CLOCK_APPS);
661         for (const auto &singleLtdAppItem : limitedAppItems) {
662             TimerClockApp timerClockApp;
663             if (!JsonUtils::GetStringFromJsonValue(singleLtdAppItem, TAG_NAME, timerClockApp.name_) ||
664                 (!JsonUtils::GetBoolFromJsonValue(singleLtdAppItem, TAG_TIMER_CLOCK, timerClockApp.isTimerClock_) &&
665                 !JsonUtils::GetInt32FromJsonValue(singleLtdAppItem, TAG_TIMER_PERIOD, timerClockApp.timerPeriod_))) {
666                 STANDBYSERVICE_LOGW("there is error in timer clock config");
667                 return false;
668             }
669             timerResourceConfig.timerClockApps_.emplace_back(std::move(timerClockApp));
670         }
671         timerResConfigList_.emplace_back(std::move(timerResourceConfig));
672     }
673     return true;
674 }
675 
ParseDefaultResCtrlConfig(const std::string & resCtrlKey,const nlohmann::json & resConfigArray)676 bool StandbyConfigManager::ParseDefaultResCtrlConfig(const std::string& resCtrlKey,
677     const nlohmann::json& resConfigArray)
678 {
679     if (!resConfigArray.is_array()) {
680         STANDBYSERVICE_LOGW("the value of %{public}s should be an array", resCtrlKey.c_str());
681         return false;
682     }
683     auto defaultResConfigPtr = std::make_shared<std::vector<DefaultResourceConfig>>();
684     for (const auto &singleConfigItem : resConfigArray) {
685         DefaultResourceConfig defaultResourceConfig;
686         if (!ParseCommonResCtrlConfig(singleConfigItem, defaultResourceConfig)) {
687             STANDBYSERVICE_LOGW("the value of %{public}s can not be parsed", resCtrlKey.c_str());
688             return false;
689         }
690         defaultResConfigPtr->emplace_back(std::move(defaultResourceConfig));
691     }
692     defaultResourceConfigMap_[resCtrlKey] = defaultResConfigPtr;
693     STANDBYSERVICE_LOGI("succeed to parse the config of %{public}s", resCtrlKey.c_str());
694     return true;
695 }
696 
ParseCommonResCtrlConfig(const nlohmann::json & singleConfigItem,DefaultResourceConfig & resCtrlConfig)697 bool StandbyConfigManager::ParseCommonResCtrlConfig(const nlohmann::json& singleConfigItem,
698     DefaultResourceConfig& resCtrlConfig)
699 {
700     if (!singleConfigItem.contains(TAG_ACTION) || !singleConfigItem.contains(TAG_CONDITION)) {
701         STANDBYSERVICE_LOGW("there is no necessary field %{public}s or %{public}s",
702             TAG_ACTION.c_str(), TAG_CONDITION.c_str());
703         return false;
704     }
705     std::string resCtrlAction;
706     std::vector<std::string> conditionItemArray {};
707     if (!JsonUtils::GetStringFromJsonValue(singleConfigItem, TAG_ACTION, resCtrlAction) ||
708         !JsonUtils::GetStrArrFromJsonValue(singleConfigItem, TAG_CONDITION, conditionItemArray)) {
709         STANDBYSERVICE_LOGW("get necessary field %{public}s or %{public}s config failed",
710             TAG_ACTION.c_str(), TAG_CONDITION.c_str());
711         return false;
712     }
713     resCtrlConfig.isAllow_ = resCtrlAction == TAG_ALLOW;
714 
715     for (const auto &singleConditionItem : conditionItemArray) {
716         uint32_t conditionValue = ParseCondition(singleConditionItem);
717         if (conditionValue > 0) {
718             resCtrlConfig.conditions_.emplace_back(conditionValue);
719         }
720     }
721 
722     JsonUtils::GetStrArrFromJsonValue(singleConfigItem, TAG_PROCESSES, resCtrlConfig.processes_);
723     JsonUtils::GetStrArrFromJsonValue(singleConfigItem, TAG_APPS, resCtrlConfig.apps_);
724     ParseTimeLimitedConfig(singleConfigItem, TAG_PROCESSES_LIMIT, resCtrlConfig.timeLtdProcesses_);
725     ParseTimeLimitedConfig(singleConfigItem, TAG_APPS_LIMIT, resCtrlConfig.timeLtdApps_);
726     return true;
727 }
728 
ParseTimeLimitedConfig(const nlohmann::json & singleConfigItem,const std::string & key,std::vector<TimeLtdProcess> & timeLimitedConfig)729 void StandbyConfigManager::ParseTimeLimitedConfig(const nlohmann::json& singleConfigItem,
730     const std::string& key, std::vector<TimeLtdProcess>& timeLimitedConfig)
731 {
732     nlohmann::json timeLimitedItems;
733     if (!JsonUtils::GetArrayFromJsonValue(singleConfigItem, key, timeLimitedItems)) {
734         return;
735     }
736     for (const auto &singleLtdItem : timeLimitedItems) {
737         std::string name {};
738         int32_t duration {0};
739         if (!JsonUtils::GetStringFromJsonValue(singleLtdItem, TAG_NAME, name) ||
740             !JsonUtils::GetInt32FromJsonValue(singleLtdItem, TAG_MAX_DURATION_LIM, duration)) {
741             STANDBYSERVICE_LOGW("there is error in %{public}s config", key.c_str());
742             continue;
743         }
744         timeLimitedConfig.emplace_back(TimeLtdProcess{name, duration});
745     }
746 }
747 
ParseCondition(const std::string & conditionStr)748 uint32_t StandbyConfigManager::ParseCondition(const std::string& conditionStr)
749 {
750     uint32_t conditionValue = 0;
751     std::stringstream ss(conditionStr);
752     std::string conditionSubstr;
753     while (std::getline(ss, conditionSubstr, TAG_CONDITION_DELIM)) {
754         auto iter = conditionMap.find(conditionSubstr);
755         if (iter == conditionMap.end()) {
756             continue;
757         }
758         conditionValue |= iter->second;
759     }
760     return conditionValue;
761 }
762 
DumpSetDebugMode(bool debugMode)763 void StandbyConfigManager::DumpSetDebugMode(bool debugMode)
764 {
765     std::lock_guard<std::mutex> lock(configMutex_);
766     if (debugMode) {
767         backStandbySwitchMap_ = standbySwitchMap_;
768         backStandbyParaMap_ = standbyParaMap_;
769     } else {
770         standbySwitchMap_ = backStandbySwitchMap_;
771         standbyParaMap_ = backStandbyParaMap_;
772         backStandbySwitchMap_.clear();
773         backStandbyParaMap_.clear();
774     }
775 }
776 
DumpSetSwitch(const std::string & switchName,bool switchStatus,std::string & result)777 void StandbyConfigManager::DumpSetSwitch(const std::string& switchName, bool switchStatus, std::string& result)
778 {
779     std::lock_guard<std::mutex> lock(configMutex_);
780     auto iter = standbySwitchMap_.find(switchName);
781     if (iter == standbySwitchMap_.end()) {
782         result += switchName + " not exist\n";
783         return;
784     }
785     iter->second = switchStatus;
786 }
787 
DumpSetParameter(const std::string & paramName,int32_t paramValue,std::string & result)788 void StandbyConfigManager::DumpSetParameter(const std::string& paramName, int32_t paramValue, std::string& result)
789 {
790     std::lock_guard<std::mutex> lock(configMutex_);
791     auto iter = standbyParaMap_.find(paramName);
792     if (iter == standbyParaMap_.end()) {
793         result += paramName + " not exist\n";
794         return;
795     }
796     iter->second = paramValue;
797 }
798 
DumpStandbyConfigInfo(std::string & result)799 void StandbyConfigManager::DumpStandbyConfigInfo(std::string& result)
800 {
801     std::lock_guard<std::mutex> lock(configMutex_);
802     std::stringstream stream;
803     for (const auto& [switchName, switchVal] : standbySwitchMap_) {
804         stream << switchName << ": " << (switchVal ? "true" : "false") << "\n";
805     }
806     for (const auto& [paraName, paraVal] : standbyParaMap_) {
807         stream << paraName << ": " << paraVal << "\n";
808     }
809     for (const auto& [strategyName, strategyVal] : strategySwitchMap_) {
810         stream << strategyName << ": " << (strategyVal ? "true" : "false") << "\n";
811     }
812     for (const auto& [strategyListName, strategyListVal] : strategyListMap_) {
813         stream << strategyListName << ": " << (strategyListVal ? "true" : "false") << "\n";
814     }
815     stream << "\n";
816     auto printConditions = [&stream](const int32_t& condition) { stream << "\t\t" << condition << " "; };
817     auto printProceses = [&stream](const std::string& process) { stream << "\t\t" << process << "\n"; };
818     auto printLtdProceses = [&stream](const TimeLtdProcess& timeLtdProcess) {
819         stream << "\t\t" << timeLtdProcess.name_ << " " << timeLtdProcess.maxDurationLim_ << "\n";
820         };
821     for (const auto& [resCtrlKey, resConfigVec] : defaultResourceConfigMap_) {
822         for (const auto& resConfig : *resConfigVec) {
823             stream << resCtrlKey << ": \n";
824             stream << "\tisAllow: " << resConfig.isAllow_ << "\n";
825             DumpResCtrlConfig<uint32_t>("conditions", resConfig.conditions_, stream, printConditions);
826             stream << "\n";
827             DumpResCtrlConfig<std::string>("processes", resConfig.processes_, stream, printProceses);
828             DumpResCtrlConfig<std::string>("apps", resConfig.apps_, stream, printProceses);
829             DumpResCtrlConfig<TimeLtdProcess>("timeLtdProcesses", resConfig.timeLtdProcesses_,
830                 stream, printLtdProceses);
831             DumpResCtrlConfig<TimeLtdProcess>("timeLtdApps", resConfig.timeLtdApps_, stream, printLtdProceses);
832         }
833     }
834     result += stream.str();
835     stream.str("");
836     stream.clear();
837 }
838 
DumpResCtrlConfig(const char * name,const std::vector<T> & configArray,std::stringstream & stream,const std::function<void (const T &)> & func)839 template<typename T> void StandbyConfigManager::DumpResCtrlConfig(const char* name, const std::vector<T>& configArray,
840     std::stringstream& stream, const std::function<void(const T&)>& func)
841 {
842     if (configArray.empty()) {
843         return;
844     }
845     stream << "\t" << name << ":\n";
846     for_each(configArray.begin(), configArray.end(), func);
847 }
848 }  // namespace DevStandbyMgr
849 }  // namespace OHOS