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
25namespace OHOS {
26namespace DistributedSchedule {
27
28using namespace Constants;
29
30namespace {
31const std::string TAG = "DmsVersionManager";
32const int32_t DMS_VERSION_LENGTH = 3;
33const int32_t DMS_MAJOR_VERSION_INDEX = 0;
34const int32_t DMS_MINOR_VERSION_INDEX = 1;
35const int32_t DMS_FEATURE_VERSION_INDEX = 2;
36}
37
38bool 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
49int32_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
78int32_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
92int32_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
115int32_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
137bool 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
164bool 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