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 "switch_status_collector.h"
17 #include <fstream>
18 #include "cJSON.h"
19 #include "config_policy_utils.h"
20 #include "content_sensor_manager_utils.h"
21 #include "distributed_device_profile_constants.h"
22 #include "distributed_device_profile_errors.h"
23 #include "distributed_device_profile_log.h"
24 #include "profile_cache.h"
25 #include "profile_utils.h"
26 #include "switch_profile_manager.h"
27 
28 namespace OHOS {
29 namespace DistributedDeviceProfile {
30 namespace {
31 const std::string TAG = "SwitchStatusCollector";
32 const std::string APP_ID = "distributed_device_profile_service";
33 }
34 
ConvertToProfile(std::vector<CharacteristicProfile> & charProfileList)35 bool SwitchStatusCollector::ConvertToProfile(std::vector<CharacteristicProfile>& charProfileList)
36 {
37     HILOGI("call!");
38     std::string fileContent = "";
39     int32_t loadJsonResult = LoadJsonFile(SWITCH_CAPABILITY_PATH, fileContent);
40     if (loadJsonResult != DP_SUCCESS) {
41         HILOGE("Load json failed, result: %{public}d!", loadJsonResult);
42         return false;
43     }
44     cJSON* switchCapabilityJson = cJSON_Parse(fileContent.c_str());
45     if (!cJSON_IsObject(switchCapabilityJson)) {
46         HILOGE("Switch capability json parse failed!");
47         cJSON_Delete(switchCapabilityJson);
48         return false;
49     }
50     // the charProfileList will be write to dynamic kv_store by ContentSensorManager
51     // so, create anther vector of ChararcteristicProfile
52     std::vector<CharacteristicProfile> switchCharProfileList;
53     int32_t generateProfilesRes = GenerateSwitchProfiles(switchCapabilityJson, switchCharProfileList);
54     if (generateProfilesRes != DP_SUCCESS) {
55         HILOGE("Generate switch profiles result %{public}d!", generateProfilesRes);
56         cJSON_Delete(switchCapabilityJson);
57         return false;
58     }
59     HILOGI("Convert to profile success!");
60     cJSON_Delete(switchCapabilityJson);
61     AddSwitchStatusToDB(switchCharProfileList);
62     return true;
63 }
64 
LoadJsonFile(const std::string & filePath,std::string & fileContent)65 int32_t SwitchStatusCollector::LoadJsonFile(const std::string& filePath, std::string& fileContent)
66 {
67     HILOGI("call!");
68     if (filePath.empty() || filePath.size() > MAX_STRING_LEN) {
69         HILOGE("filePath is invalid!");
70         return DP_INVALID_PARAM;
71     }
72     char buf[MAX_PATH_LEN] = {0};
73     char targetPath[PATH_MAX + 1] = {0x00};
74     char *srcPath = GetOneCfgFile(filePath.c_str(), buf, MAX_PATH_LEN);
75     if (srcPath == nullptr) {
76         HILOGE("srcPath is invalid!");
77         return DP_LOAD_JSON_FILE_FAIL;
78     }
79     if (strlen(srcPath) == 0 || strlen(srcPath) > PATH_MAX || realpath(srcPath, targetPath) == nullptr) {
80         HILOGE("File canonicalization failed!");
81         return DP_LOAD_JSON_FILE_FAIL;
82     }
83     std::ifstream ifs(targetPath);
84     if (!ifs.is_open()) {
85         HILOGE("load json file failed");
86         return DP_LOAD_JSON_FILE_FAIL;
87     }
88     fileContent = std::string(std::istreambuf_iterator<char>{ifs}, std::istreambuf_iterator<char>{});
89     ifs.close();
90     return DP_SUCCESS;
91 }
92 
GenerateSwitchProfiles(const cJSON * const staticInfoJson,std::vector<CharacteristicProfile> & charProfileList)93 int32_t SwitchStatusCollector::GenerateSwitchProfiles(const cJSON* const staticInfoJson,
94     std::vector<CharacteristicProfile>& charProfileList)
95 {
96     if (!cJSON_IsObject(staticInfoJson)) {
97         HILOGE("staticInfoJson is not object!");
98         return DP_GET_SWITCH_INFO_FAIL;
99     }
100     cJSON* abilitiesJson = cJSON_GetObjectItemCaseSensitive(staticInfoJson, SWITCH_CALLERS.c_str());
101     if (!cJSON_IsArray(abilitiesJson)) {
102         HILOGE("abilitiesJson is not array!");
103         return DP_GET_SWITCH_INFO_FAIL;
104     }
105     cJSON* abilityItem = NULL;
106     cJSON_ArrayForEach(abilityItem, abilitiesJson) {
107         if (!cJSON_IsObject(abilityItem)) {
108             HILOGE("abilityItem is not object!");
109             continue;
110         }
111         cJSON* abilityKeyItem = cJSON_GetObjectItemCaseSensitive(abilityItem, SWITCH_SERVICE_NAMES.c_str());
112         if (!cJSON_IsString(abilityKeyItem) || abilityKeyItem->valuestring == NULL) {
113             HILOGE("get abilityKeyItem fail!");
114             continue;
115         }
116         cJSON* abilityValueItem = cJSON_GetObjectItemCaseSensitive(abilityItem, SWITCH_STATUS.c_str());
117         if (!cJSON_IsString(abilityValueItem)) {
118             HILOGE("get abilityValueItem fail!");
119             continue;
120         }
121         std::string deviceId = ContentSensorManagerUtils::GetInstance().ObtainLocalUdid();
122         std::string serviceId = abilityKeyItem->valuestring;
123         std::string charKey = ProfileUtils::GenerateCharProfileKey(deviceId, serviceId, SWITCH_STATUS);
124         std::string charValue = abilityValueItem->valuestring;
125         if (charValue != SWITCH_ON && charValue != SWITCH_OFF) {
126             HILOGE("switch status invaild");
127             continue;
128         }
129         CharacteristicProfile characteristicProfile(deviceId, serviceId, SWITCH_STATUS, charValue);
130         charProfileList.push_back(characteristicProfile);
131     }
132     return DP_SUCCESS;
133 }
134 
AddSwitchStatusToDB(std::vector<CharacteristicProfile> & charProfileList)135 void SwitchStatusCollector::AddSwitchStatusToDB(std::vector<CharacteristicProfile>& charProfileList)
136 {
137     if (charProfileList.empty()) {
138         HILOGW("charProfileList is empty");
139         return;
140     }
141     // get switch from db
142     uint32_t switchFromDB;
143     uint32_t switchLength;
144     int32_t ret = SwitchProfileManager::GetInstance().GetLocalSwitchFromDB(switchFromDB, switchLength);
145     if (switchLength > SWITCH_LENGTH_MAX) {
146         HILOGE("switchLength is invalid");
147         return;
148     }
149     if (ret == DP_SUCCESS && charProfileList.size() == switchLength) {
150         HILOGW("switch length equal");
151         return;
152     }
153     std::string localUdid = ContentSensorManagerUtils::GetInstance().ObtainLocalUdid();
154     std::map<std::string, CharacteristicProfile> oldProfileMap;
155     for (uint32_t i = 0; i < switchLength; ++i) {
156         std::string serviceName;
157         std::string itemSwitchValue = std::to_string((switchFromDB >> i) & NUM_1);
158         if (ProfileCache::GetInstance().GetServiceNameByPos(i, SWITCH_SERVICE_MAP, serviceName) != DP_SUCCESS ||
159             serviceName.empty()) {
160             HILOGE("GetServiceNameByPos failed, pos:%{public}d", i);
161             continue;
162         }
163         const CharacteristicProfile oldSwitchProfile = {localUdid, serviceName, SWITCH_STATUS, itemSwitchValue};
164         std::string charKey = ProfileUtils::GenerateCharProfileKey(localUdid, serviceName, SWITCH_STATUS);
165         oldProfileMap[charKey] = oldSwitchProfile;
166     }
167     for (auto& profile : charProfileList) {
168         std::string charKey = ProfileUtils::GenerateCharProfileKey(profile.GetDeviceId(), profile.GetServiceName(),
169             profile.GetCharacteristicKey());
170         auto iter = oldProfileMap.find(charKey);
171         if (iter == oldProfileMap.end() || iter->second.GetCharacteristicValue() == profile.GetCharacteristicValue()) {
172             continue;
173         }
174         profile.SetCharacteristicValue(iter->second.GetCharacteristicValue());
175     }
176     ret = SwitchProfileManager::GetInstance().PutCharacteristicProfileBatch(charProfileList);
177     if (ret != DP_SUCCESS) {
178         HILOGE("collect switch status error");
179     }
180 }
181 } // namespace DeviceProfile
182 } // namespace OHOS