1 /*
2 * Copyright (C) 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 "device/device_profile_adapter.h"
17
18 #include "device_manager.h"
19 #include "dfs_error.h"
20 #include "ipc/i_daemon.h"
21 #include "nlohmann/json.hpp"
22 #include "string_ex.h"
23 #include "utils_log.h"
24
25 #ifdef SUPPORT_DEVICE_PROFILE
26 #include "distributed_device_profile_client.h"
27 #endif
28
29 namespace OHOS {
30 namespace Storage {
31 namespace DistributedFile {
32 using namespace std;
33 using namespace OHOS::FileManagement;
34
35 #ifdef SUPPORT_DEVICE_PROFILE
36 using namespace OHOS::DistributedDeviceProfile;
37
38 namespace {
39 constexpr const char *DFS_SERVICE_ID = "distributedfiledaemon";
40 constexpr const char *DMS_SERVICE_ID = "dmsfwk_svr_id";
41 constexpr const char *DFS_CHAR_ID = "static_capability";
42 constexpr const char *PACKAGE_NAMES = "packageNames";
43 constexpr const char *VERSIONS = "versions";
44 constexpr const char *SWITCH_ID = "SwitchStatus_Distributed_Super_Manager";
45 constexpr const char *CHARACTER_ID = "SwitchStatus";
46 constexpr const char *STATUS_ENABLE = "1";
47 constexpr const char *STATUS_DISABLE = "0";
48 const static int32_t DFS_VERSION_LENGTH = 3;
49 const static int32_t DFS_MAJOR_VERSION_INDEX = 0;
50 const static int32_t DFS_MINOR_VERSION_INDEX = 1;
51 const static int32_t DFS_FEATURE_VERSION_INDEX = 2;
52 const static DfsVersion NO_VERSION = {0, 0, 0};
53 const static int32_t MAX_JSON_SIZE = 9999;
54 }
55
Bool2Str(bool value)56 static inline std::string Bool2Str(bool value)
57 {
58 return value ? STATUS_ENABLE : STATUS_DISABLE;
59 }
60
Str2Bool(const std::string & value)61 static inline bool Str2Bool(const std::string &value)
62 {
63 return value == STATUS_ENABLE;
64 }
65 #endif
66
IsRemoteDfsVersionLower(const std::string & remoteNetworkId,VersionPackageName packageName)67 bool DeviceProfileAdapter::IsRemoteDfsVersionLower(const std::string &remoteNetworkId,
68 VersionPackageName packageName)
69 {
70 #ifdef SUPPORT_DEVICE_PROFILE
71 LOGI("remoteDevice.networkId: %{public}.5s", remoteNetworkId.c_str());
72 DfsVersion localDfsVersion;
73 int32_t ret = GetLocalDfsVersion(packageName, localDfsVersion);
74 if (ret != FileManagement::ERR_OK) {
75 LOGE("GetLocalDfsVersion failed, ret=%{public}d", ret);
76 return false;
77 }
78 return IsRemoteDfsVersionLower(remoteNetworkId, localDfsVersion, packageName);
79 #else
80 return false;
81 #endif
82 }
83
84 // Comparison of version numbers later than the current version number is not supported.
IsRemoteDfsVersionLower(const std::string & remoteNetworkId,const DfsVersion & thresholdDfsVersion,VersionPackageName packageName)85 bool DeviceProfileAdapter::IsRemoteDfsVersionLower(const std::string &remoteNetworkId,
86 const DfsVersion &thresholdDfsVersion, VersionPackageName packageName)
87 {
88 #ifdef SUPPORT_DEVICE_PROFILE
89 LOGI("remoteDevice.networkId: %{public}.5s", remoteNetworkId.c_str());
90 if (remoteNetworkId.empty()) {
91 LOGE("remoteNetworkId is empty");
92 return false;
93 }
94 DfsVersion remoteDfsVersion;
95 int32_t ret = GetDfsVersionFromNetworkId(remoteNetworkId, remoteDfsVersion, packageName);
96 if (ret != FileManagement::ERR_OK) {
97 LOGE("GetDfsVersionFromNetworkId failed, ret=%{public}d", ret);
98 return false;
99 }
100 return CompareDfsVersion(remoteDfsVersion, thresholdDfsVersion);
101 #else
102 return false;
103 #endif
104 }
105
GetDeviceStatus(const std::string & networkId,bool & status)106 int32_t DeviceProfileAdapter::GetDeviceStatus(const std::string &networkId, bool &status)
107 {
108 #ifdef SUPPORT_DEVICE_PROFILE
109 auto udid = GetUdidByNetworkId(networkId);
110 if (udid.empty()) {
111 LOGE("remote GetUdidByNetworkId failed");
112 return ERR_GET_UDID;
113 }
114
115 CharacteristicProfile profile;
116 int32_t ret = DistributedDeviceProfileClient::GetInstance().GetCharacteristicProfile(udid,
117 SWITCH_ID, CHARACTER_ID, profile);
118 if (ret != DistributedDeviceProfile::DP_SUCCESS) {
119 LOGE("GetDeviceStatus failed, ret=%{public}d, udid=%{public}.5s, status=%{public}d", ret, udid.c_str(),
120 status);
121 return ret;
122 }
123 std::string enabledStatus = profile.GetCharacteristicValue();
124 status = Str2Bool(enabledStatus);
125 LOGI("GetDeviceStatus success, udid=%{public}.5s, status=%{public}d", udid.c_str(), status);
126 #endif
127 return FileManagement::ERR_OK;
128 }
129
PutDeviceStatus(bool status)130 int32_t DeviceProfileAdapter::PutDeviceStatus(bool status)
131 {
132 #ifdef SUPPORT_DEVICE_PROFILE
133 DistributedHardware::DmDeviceInfo localDeviceInfo{};
134 auto &deviceManager = DistributedHardware::DeviceManager::GetInstance();
135 int ret = deviceManager.GetLocalDeviceInfo(IDaemon::SERVICE_NAME, localDeviceInfo);
136 if (ret != FileManagement::ERR_OK) {
137 LOGE("GetLocalDeviceInfo failed, errCode = %{public}d", ret);
138 return ret;
139 }
140 LOGD("GetLocalDeviceInfo success, localDeviceInfo.networkId = %{public}.5s", localDeviceInfo.networkId);
141 auto udid = GetUdidByNetworkId(localDeviceInfo.networkId);
142 if (udid.empty()) {
143 LOGE("remote GetUdidByNetworkId failed");
144 return ERR_GET_UDID;
145 }
146
147 std::string enabledStatus = Bool2Str(status);
148 CharacteristicProfile profile;
149 profile.SetDeviceId(udid);
150 profile.SetServiceName(SWITCH_ID);
151 profile.SetCharacteristicKey(CHARACTER_ID);
152 profile.SetCharacteristicValue(enabledStatus);
153
154 ret = DistributedDeviceProfileClient::GetInstance().PutCharacteristicProfile(profile);
155 if (ret != DistributedDeviceProfile::DP_SUCCESS) {
156 LOGE("PutDeviceStatus failed, ret=%{public}d, udid=%{public}.5s, status=%{public}d", ret, udid.c_str(), status);
157 return ret;
158 }
159 LOGI("PutDeviceStatus success, udid=%{public}.5s, status=%{public}d", udid.c_str(), status);
160 #endif
161 return FileManagement::ERR_OK;
162 }
163
164 #ifdef SUPPORT_DEVICE_PROFILE
GetLocalDfsVersion(VersionPackageName packageName,DfsVersion & dfsVersion)165 int32_t DeviceProfileAdapter::GetLocalDfsVersion(VersionPackageName packageName, DfsVersion &dfsVersion)
166 {
167 DistributedHardware::DmDeviceInfo localDeviceInfo{};
168 auto &deviceManager = DistributedHardware::DeviceManager::GetInstance();
169 int ret = deviceManager.GetLocalDeviceInfo(IDaemon::SERVICE_NAME, localDeviceInfo);
170 if (ret != FileManagement::ERR_OK) {
171 LOGE("GetLocalDeviceInfo failed, errCode = %{public}d", ret);
172 return ret;
173 }
174 LOGD("GetLocalDeviceInfo success, localDeviceInfo.networkId=%{public}.5s", localDeviceInfo.networkId);
175 auto udid = GetUdidByNetworkId(localDeviceInfo.networkId);
176 if (udid.empty()) {
177 LOGE("remote GetUdidByNetworkId failed, networkId=%{public}.5s", localDeviceInfo.networkId);
178 return ERR_GET_UDID;
179 }
180 return GetDfsVersion(udid, packageName, dfsVersion, false);
181 }
182 #endif
183
GetDfsVersionFromNetworkId(const std::string & networkId,DfsVersion & dfsVersion,VersionPackageName packageName)184 int32_t DeviceProfileAdapter::GetDfsVersionFromNetworkId(
185 const std::string &networkId, DfsVersion &dfsVersion, VersionPackageName packageName)
186 {
187 #ifdef SUPPORT_DEVICE_PROFILE
188 if (networkId.empty()) {
189 LOGE("networkId: %{public}.5s is empty", networkId.c_str());
190 return ERR_NULLPTR;
191 }
192 auto udid = GetUdidByNetworkId(networkId);
193 if (udid.empty()) {
194 LOGE("remote GetUdidByNetworkId failed, networkId=%{public}.5s ", networkId.c_str());
195 return ERR_GET_UDID;
196 }
197 return GetDfsVersion(udid, packageName, dfsVersion, true);
198 #else
199 return FileManagement::ERR_OK;
200 #endif
201 }
202
203 #ifdef SUPPORT_DEVICE_PROFILE
GetDfsVersion(const std::string & udid,VersionPackageName packageName,DfsVersion & dfsVersion,bool IsVerifyCode)204 int32_t DeviceProfileAdapter::GetDfsVersion(const std::string &udid,
205 VersionPackageName packageName, DfsVersion &dfsVersion, bool IsVerifyCode)
206 {
207 std::string appInfoJsonData;
208 int32_t ret = GetAppInfoFromDP(udid, DFS_SERVICE_ID, appInfoJsonData);
209 if (ret == DistributedDeviceProfile::DP_NOT_FOUND_FAIL) {
210 auto dmsResult = GetAppInfoFromDP(udid, DMS_SERVICE_ID, appInfoJsonData);
211 if (IsVerifyCode && dmsResult == DistributedDeviceProfile::DP_NOT_FOUND_FAIL) {
212 LOGW("The DP version of the remote device is later, return local dfsVersion.");
213 GetLocalDfsVersion(packageName, dfsVersion);
214 return FileManagement::ERR_OK;
215 } else if (dmsResult != DistributedDeviceProfile::DP_SUCCESS) {
216 LOGE("get app info failed, result: %{public}d!", dmsResult);
217 return dmsResult;
218 }
219 LOGW("The dfs version number has not been added to the remote device.");
220 dfsVersion = NO_VERSION;
221 return FileManagement::ERR_OK;
222 } else if (ret != DistributedDeviceProfile::DP_SUCCESS) {
223 LOGE("get app info failed, result: %{public}d!", ret);
224 return ret;
225 }
226
227 std::string packageNamesData;
228 std::string versionsData;
229 ret = ParseAppInfo(appInfoJsonData, packageNamesData, versionsData);
230 if (ret != FileManagement::ERR_OK) {
231 LOGE("parse app info failed ret=%{public}d, appInfoJsonData=%{public}s", ret, appInfoJsonData.c_str());
232 return ret;
233 }
234
235 std::string dfsVersionData;
236 ret = GetDfsVersionDataFromAppInfo(packageNamesData, versionsData, packageName, dfsVersionData);
237 if (ret != FileManagement::ERR_OK) {
238 if (ret == ERR_NO_FIND_PACKAGE_NAME) {
239 LOGW("not find packageName: %{public}d, %{public}s", static_cast<int>(packageName), dfsVersionData.c_str());
240 dfsVersion = NO_VERSION;
241 return FileManagement::ERR_OK;
242 }
243 LOGE("get dfs version data failed, result: %{public}d!", ret);
244 return ret;
245 }
246
247 if (!ParseDfsVersion(dfsVersionData, dfsVersion)) {
248 LOGE("parse dfs version failed, dfsVersionData=%{public}s", dfsVersionData.c_str());
249 return ERR_DFS_VERSION_PARSE_EXCEPTION;
250 }
251 LOGI("GetDfsVersion success, %{public}s", dfsVersion.dump().c_str());
252 return FileManagement::ERR_OK;
253 }
254
ParseDfsVersion(const std::string & dfsVersionData,DfsVersion & dfsVersion)255 bool DeviceProfileAdapter::ParseDfsVersion(const std::string &dfsVersionData, DfsVersion &dfsVersion)
256 {
257 std::vector<std::string> versionNumList;
258 SplitStr(dfsVersionData, ".", versionNumList);
259 if (versionNumList.size() != DFS_VERSION_LENGTH) {
260 return false;
261 }
262 int32_t majorVersionNum = -1;
263 if (!OHOS::StrToInt(versionNumList[DFS_MAJOR_VERSION_INDEX], majorVersionNum) || majorVersionNum < 0) {
264 return false;
265 }
266 dfsVersion.majorVersionNum = static_cast<uint32_t>(majorVersionNum);
267
268 int32_t minorVersionNum = -1;
269 if (!OHOS::StrToInt(versionNumList[DFS_MINOR_VERSION_INDEX], minorVersionNum) || minorVersionNum < 0) {
270 return false;
271 }
272 dfsVersion.minorVersionNum = static_cast<uint32_t>(minorVersionNum);
273
274 int32_t featureVersionNum = -1;
275 if (!OHOS::StrToInt(versionNumList[DFS_FEATURE_VERSION_INDEX], featureVersionNum) || featureVersionNum < 0) {
276 return false;
277 }
278 dfsVersion.featureVersionNum = static_cast<uint32_t>(featureVersionNum);
279 return true;
280 }
281
ParseAppInfo(const std::string & appInfoJsonData,std::string & packageNamesData,std::string & versionsData)282 int32_t DeviceProfileAdapter::ParseAppInfo(const std::string &appInfoJsonData, std::string &packageNamesData,
283 std::string &versionsData)
284 {
285 if (appInfoJsonData.empty() || appInfoJsonData.size() > MAX_JSON_SIZE) {
286 return ERR_DFS_VERSION_EMPTY;
287 }
288 nlohmann::json appInfoJson = nlohmann::json::parse(appInfoJsonData.c_str(), nullptr, false);
289 if (appInfoJson.is_discarded()) {
290 return ERR_DFS_VERSION_EMPTY;
291 }
292 if (appInfoJson.find(PACKAGE_NAMES) == appInfoJson.end() || !appInfoJson.at(PACKAGE_NAMES).is_string()) {
293 return ERR_DFS_VERSION_EMPTY;
294 }
295 appInfoJson.at(PACKAGE_NAMES).get_to(packageNamesData);
296
297 if (appInfoJson.find(VERSIONS) == appInfoJson.end() || !appInfoJson.at(VERSIONS).is_string()) {
298 return ERR_DFS_VERSION_EMPTY;
299 }
300 appInfoJson.at(VERSIONS).get_to(versionsData);
301
302 return FileManagement::ERR_OK;
303 }
304
GetDfsVersionDataFromAppInfo(const std::string & packageNamesData,const std::string & versionsData,VersionPackageName packageName,std::string & dfsVersionData)305 int32_t DeviceProfileAdapter::GetDfsVersionDataFromAppInfo(const std::string &packageNamesData,
306 const std::string &versionsData, VersionPackageName packageName, std::string &dfsVersionData)
307 {
308 std::string packageNameString = GetPackageName(packageName);
309 if (packageNamesData.empty() || versionsData.empty() || packageNameString.empty()) {
310 return ERR_DFS_VERSION_EMPTY;
311 }
312
313 std::vector<std::string> packageNameList;
314 std::vector<std::string> versionsList;
315 SplitStr(packageNamesData, ",", packageNameList);
316 SplitStr(versionsData, ",", versionsList);
317 if (packageNameList.size() != versionsList.size()) {
318 return ERR_DFS_VERSION_PARSE_EXCEPTION;
319 }
320 for (std::size_t i = 0; i < packageNameList.size(); i++) {
321 if (packageNameList[i] == packageNameString) {
322 dfsVersionData = versionsList[i];
323 return FileManagement::ERR_OK;
324 }
325 }
326 return ERR_NO_FIND_PACKAGE_NAME;
327 }
328
GetAppInfoFromDP(const std::string & udid,const std::string & serviceName,std::string & appInfoJsonData)329 int32_t DeviceProfileAdapter::GetAppInfoFromDP(const std::string &udid,
330 const std::string &serviceName, std::string &appInfoJsonData)
331 {
332 DistributedDeviceProfile::CharacteristicProfile profile;
333 int32_t ret = DistributedDeviceProfileClient::GetInstance().GetCharacteristicProfile(
334 udid, serviceName, DFS_CHAR_ID, profile);
335 if (ret != DistributedDeviceProfile::DP_SUCCESS) {
336 return ret;
337 }
338 appInfoJsonData = profile.GetCharacteristicValue();
339 return FileManagement::ERR_OK;
340 }
341
CompareDfsVersion(const DfsVersion & dfsVersion,const DfsVersion & thresholdDfsVersion)342 bool DeviceProfileAdapter::CompareDfsVersion(const DfsVersion &dfsVersion, const DfsVersion &thresholdDfsVersion)
343 {
344 if (dfsVersion.majorVersionNum != thresholdDfsVersion.majorVersionNum) {
345 return dfsVersion.majorVersionNum < thresholdDfsVersion.majorVersionNum;
346 }
347 if (dfsVersion.minorVersionNum != thresholdDfsVersion.minorVersionNum) {
348 return dfsVersion.minorVersionNum < thresholdDfsVersion.minorVersionNum;
349 }
350 return dfsVersion.featureVersionNum < thresholdDfsVersion.featureVersionNum;
351 }
352
GetUdidByNetworkId(const std::string & networkId)353 std::string DeviceProfileAdapter::GetUdidByNetworkId(const std::string &networkId)
354 {
355 std::string udid;
356 auto &deviceManager = DistributedHardware::DeviceManager::GetInstance();
357 auto ret = deviceManager.GetUdidByNetworkId(IDaemon::SERVICE_NAME, networkId, udid);
358 if (ret != FileManagement::ERR_OK) {
359 LOGE("GetUdidByNetworkId failed, ret = %{public}d", ret);
360 return "";
361 }
362 return udid;
363 }
364 #endif
365 } // namespace DistributedFile
366 } // namespace Storage
367 } // namespace OHOS
368