1 /*
2  * Copyright (c) 2022-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 "dms_version_manager.h"
17 
18 #include "distributed_device_profile_client.h"
19 #include "dms_constant.h"
20 #include "dtbschedmgr_device_info_storage.h"
21 #include "dtbschedmgr_log.h"
22 #include "nlohmann/json.hpp"
23 #include "string_ex.h"
24 
25 namespace OHOS {
26 namespace DistributedSchedule {
27 
28 using namespace Constants;
29 
30 namespace {
31 const std::string TAG = "DmsVersionManager";
32 const int32_t DMS_VERSION_LENGTH = 3;
33 const int32_t DMS_MAJOR_VERSION_INDEX = 0;
34 const int32_t DMS_MINOR_VERSION_INDEX = 1;
35 const int32_t DMS_FEATURE_VERSION_INDEX = 2;
36 }
37 
IsRemoteDmsVersionLower(const std::string & remoteDeviceId,const DmsVersion & thresholdDmsVersion)38 bool DmsVersionManager::IsRemoteDmsVersionLower(const std::string& remoteDeviceId,
39     const DmsVersion& thresholdDmsVersion)
40 {
41     DmsVersion dmsVersion;
42     int32_t result = GetRemoteDmsVersion(remoteDeviceId, dmsVersion);
43     if (result != ERR_OK) {
44         return false;
45     }
46     return CompareDmsVersion(dmsVersion, thresholdDmsVersion);
47 }
48 
GetRemoteDmsVersion(const std::string & deviceId,DmsVersion & dmsVersion)49 int32_t DmsVersionManager::GetRemoteDmsVersion(const std::string& deviceId, DmsVersion& dmsVersion)
50 {
51     std::string appInfoJsonData;
52     int32_t result = GetAppInfoFromDP(deviceId, appInfoJsonData);
53     if (result != ERR_OK) {
54         HILOGI("get app info failed, result: %{public}d!", result);
55         return result;
56     }
57     std::string packageNamesData;
58     std::string versionsData;
59     result = ParseAppInfo(appInfoJsonData, packageNamesData, versionsData);
60     if (result != ERR_OK) {
61         HILOGI("parse app info failed");
62         return result;
63     }
64 
65     std::string dmsVersionData;
66     result = GetDmsVersionDataFromAppInfo(packageNamesData, versionsData, dmsVersionData);
67     if (result != ERR_OK) {
68         HILOGW("get dms version data failed, result: %{public}d!", result);
69         return result;
70     }
71     if (!ParseDmsVersion(dmsVersionData, dmsVersion)) {
72         HILOGE("parse dms version failed");
73         return DMS_VERSION_PARSE_EXCEPTION;
74     }
75     return ERR_OK;
76 }
77 
GetAppInfoFromDP(const std::string & deviceId,std::string & appInfoJsonData)78 int32_t DmsVersionManager::GetAppInfoFromDP(const std::string& deviceId, std::string& appInfoJsonData)
79 {
80     DistributedDeviceProfile::CharacteristicProfile profile;
81     std::string udid = "";
82     udid = DtbschedmgrDeviceInfoStorage::GetInstance().GetUdidByNetworkId(deviceId);
83     int32_t result = DistributedDeviceProfile::DistributedDeviceProfileClient::GetInstance().GetCharacteristicProfile(
84         udid, DMS_SERVICE_ID, DMS_CHAR_ID, profile);
85     if (result != ERR_OK) {
86         return result;
87     }
88     appInfoJsonData = profile.GetCharacteristicValue();
89     return ERR_OK;
90 }
91 
ParseAppInfo(const std::string & appInfoJsonData,std::string & packageNamesData,std::string & versionsData)92 int32_t DmsVersionManager::ParseAppInfo(const std::string& appInfoJsonData, std::string& packageNamesData,
93     std::string& versionsData)
94 {
95     if (appInfoJsonData.empty()) {
96         return DMS_VERSION_EMPTY;
97     }
98     nlohmann::json appInfoJson = nlohmann::json::parse(appInfoJsonData.c_str(), nullptr, false);
99     if (appInfoJson.is_discarded()) {
100         return DMS_VERSION_EMPTY;
101     }
102     if (appInfoJson.find(PACKAGE_NAMES) == appInfoJson.end() || !appInfoJson.at(PACKAGE_NAMES).is_string()) {
103         return DMS_VERSION_EMPTY;
104     }
105     appInfoJson.at(PACKAGE_NAMES).get_to(packageNamesData);
106 
107     if (appInfoJson.find(VERSIONS) == appInfoJson.end() || !appInfoJson.at(VERSIONS).is_string()) {
108         return DMS_VERSION_EMPTY;
109     }
110     appInfoJson.at(VERSIONS).get_to(versionsData);
111 
112     return ERR_OK;
113 }
114 
GetDmsVersionDataFromAppInfo(const std::string & packageNamesData,const std::string & versionsData,std::string & dmsVersionData)115 int32_t DmsVersionManager::GetDmsVersionDataFromAppInfo(const std::string& packageNamesData,
116     const std::string& versionsData, std::string& dmsVersionData)
117 {
118     if (packageNamesData.empty() || versionsData.empty()) {
119         return DMS_VERSION_EMPTY;
120     }
121     std::vector<std::string> packageNameList;
122     std::vector<std::string> versionsList;
123     SplitStr(packageNamesData, ",", packageNameList);
124     SplitStr(versionsData, ",", versionsList);
125     if (packageNameList.size() != versionsList.size()) {
126         return DMS_VERSION_PARSE_EXCEPTION;
127     }
128     for (std::size_t i = 0; i < packageNameList.size(); i++) {
129         if (packageNameList[i] == DMS_NAME) {
130             dmsVersionData = versionsList[i];
131             return ERR_OK;
132         }
133     }
134     return DMS_VERSION_EMPTY;
135 }
136 
ParseDmsVersion(const std::string & dmsVersionData,DmsVersion & dmsVersion)137 bool DmsVersionManager::ParseDmsVersion(const std::string& dmsVersionData, DmsVersion& dmsVersion)
138 {
139     std::vector<std::string> versionNumList;
140     SplitStr(dmsVersionData, ".", versionNumList);
141     if (versionNumList.size() != DMS_VERSION_LENGTH) {
142         return false;
143     }
144     int32_t majorVersionNum = -1;
145     if (!OHOS::StrToInt(versionNumList[DMS_MAJOR_VERSION_INDEX], majorVersionNum) || majorVersionNum < 0) {
146         return false;
147     }
148     dmsVersion.majorVersionNum = static_cast<uint32_t>(majorVersionNum);
149 
150     int32_t minorVersionNum = -1;
151     if (!OHOS::StrToInt(versionNumList[DMS_MINOR_VERSION_INDEX], minorVersionNum) || minorVersionNum < 0) {
152         return false;
153     }
154     dmsVersion.minorVersionNum = static_cast<uint32_t>(minorVersionNum);
155 
156     int32_t featureVersionNum = -1;
157     if (!OHOS::StrToInt(versionNumList[DMS_FEATURE_VERSION_INDEX], featureVersionNum) || featureVersionNum < 0) {
158         return false;
159     }
160     dmsVersion.featureVersionNum = static_cast<uint32_t>(featureVersionNum);
161     return true;
162 }
163 
CompareDmsVersion(const DmsVersion & dmsVersion,const DmsVersion & thresholdDmsVersion)164 bool DmsVersionManager::CompareDmsVersion(const DmsVersion& dmsVersion, const DmsVersion& thresholdDmsVersion)
165 {
166     if (dmsVersion.majorVersionNum < thresholdDmsVersion.majorVersionNum) {
167         return true;
168     }
169     if (dmsVersion.majorVersionNum == thresholdDmsVersion.majorVersionNum &&
170         dmsVersion.minorVersionNum < thresholdDmsVersion.minorVersionNum) {
171         return true;
172     }
173     if (dmsVersion.majorVersionNum == thresholdDmsVersion.majorVersionNum &&
174         dmsVersion.minorVersionNum == thresholdDmsVersion.minorVersionNum &&
175         dmsVersion.featureVersionNum < thresholdDmsVersion.featureVersionNum) {
176         return true;
177     }
178     return false;
179 }
180 } // namespace DistributedSchedule
181 } // namespace OHOS
182