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 <dlfcn.h>
17 #include <fstream>
18 #include <regex>
19
20 #include "static_capability_loader.h"
21
22 #include "config_policy_utils.h"
23 #include "content_sensor_manager_utils.h"
24 #include "distributed_device_profile_constants.h"
25 #include "distributed_device_profile_enums.h"
26 #include "distributed_device_profile_errors.h"
27 #include "i_static_capability_collector.h"
28 #include "profile_utils.h"
29
30 namespace OHOS {
31 namespace DistributedDeviceProfile {
32 IMPLEMENT_SINGLE_INSTANCE(StaticCapabilityLoader);
33 namespace {
34 const std::string TAG = "StaticCapabilityLoader";
35 }
36 using StaticCapabilityHandler = IStaticCapabilityCollector *(*)();
Init()37 int32_t StaticCapabilityLoader::Init()
38 {
39 HILOGI("call!");
40 return DP_SUCCESS;
41 }
42
UnInit()43 int32_t StaticCapabilityLoader::UnInit()
44 {
45 HILOGI("call!");
46 return DP_SUCCESS;
47 }
48
LoadStaticCapability(std::string & staticCapability)49 int32_t StaticCapabilityLoader::LoadStaticCapability(std::string& staticCapability)
50 {
51 HILOGD("call!");
52 std::string fileContent = "";
53 int32_t loadJsonResult = LoadJsonFile(STATIC_CAPABILITY_PATH, fileContent);
54 if (loadJsonResult != DP_SUCCESS) {
55 HILOGE("Load json failed, result: %{public}d!", loadJsonResult);
56 return loadJsonResult;
57 }
58 cJSON* staticCapabilityJson = cJSON_Parse(fileContent.c_str());
59 if (!cJSON_IsObject(staticCapabilityJson)) {
60 HILOGE("Static capability json parse failed!");
61 cJSON_Delete(staticCapabilityJson);
62 return DP_LOAD_STATIC_CAP_FAIL;
63 }
64 int32_t getCapResult = GetStaticCapability(staticCapabilityJson, staticCapability);
65 if (getCapResult != DP_SUCCESS) {
66 HILOGE("Get static capability result %{public}d!", getCapResult);
67 cJSON_Delete(staticCapabilityJson);
68 return getCapResult;
69 }
70 HILOGI("success!");
71 cJSON_Delete(staticCapabilityJson);
72 return DP_SUCCESS;
73 }
74
GetStaticCapability(const cJSON * const staticCapabilityJson,std::string & staticCapability)75 int32_t StaticCapabilityLoader::GetStaticCapability(const cJSON* const staticCapabilityJson,
76 std::string& staticCapability)
77 {
78 HILOGD("call!");
79 if (!cJSON_IsObject(staticCapabilityJson)) {
80 HILOGE("staticInfoJson is json object!");
81 return DP_INVALID_PARAM;
82 }
83 cJSON* staticCapabilities = cJSON_GetObjectItem(staticCapabilityJson, STATIC_CAPABILITY_ATTRIBUTE.c_str());
84 if (!cJSON_IsArray(staticCapabilities)) {
85 HILOGE("StaticCapabilities is not Array!");
86 return DP_PARSE_STATIC_CAP_FAIL;
87 }
88 int32_t capabilityNum = static_cast<int32_t>(cJSON_GetArraySize(staticCapabilities));
89 if (capabilityNum == 0 || capabilityNum > MAX_STATIC_CAPABILITY_SIZE) {
90 HILOGE("CapabilityNum is invalid, nums: %{public}d!", capabilityNum);
91 return DP_PARSE_STATIC_CAP_FAIL;
92 }
93 InitStaticCapability(capabilityNum, staticCapability);
94 SetStaticCapability(staticCapabilities, staticCapability);
95 return DP_SUCCESS;
96 }
97
GetStaticInfo(const cJSON * const staticInfoJson,const std::string & staticCapability,std::string & staticVersion,std::unordered_map<std::string,CharacteristicProfile> & charProfiles)98 int32_t StaticCapabilityLoader::GetStaticInfo(const cJSON* const staticInfoJson, const std::string& staticCapability,
99 std::string& staticVersion, std::unordered_map<std::string, CharacteristicProfile>& charProfiles)
100 {
101 HILOGD("call!");
102 if (!cJSON_IsObject(staticInfoJson)) {
103 HILOGE("staticInfoJson is json object!");
104 return DP_INVALID_PARAM;
105 }
106 cJSON* lastStaticInfoJson = GetLatestStaticInfoJson(staticInfoJson);
107 if (lastStaticInfoJson == NULL) {
108 HILOGE("lastStaticInfo is nullptr!");
109 return DP_GET_STATIC_INFO_FAIL;
110 }
111 GetStaticVersion(lastStaticInfoJson, staticVersion);
112 std::string localDeviceId = ContentSensorManagerUtils::GetInstance().ObtainLocalUdid();
113 GenerateStaticProfiles(localDeviceId, staticCapability, lastStaticInfoJson, charProfiles);
114 return DP_SUCCESS;
115 }
116
GetStaticInfoByVersion(const std::string & deviceId,const std::string & staticCapability,const cJSON * const staticInfoJson,const std::string & staticVersion,std::unordered_map<std::string,CharacteristicProfile> & charProfiles)117 int32_t StaticCapabilityLoader::GetStaticInfoByVersion(const std::string& deviceId,
118 const std::string& staticCapability, const cJSON* const staticInfoJson,
119 const std::string& staticVersion, std::unordered_map<std::string, CharacteristicProfile>& charProfiles)
120 {
121 HILOGD("call!");
122 if (deviceId.empty() || deviceId.size() > MAX_STRING_LEN) {
123 HILOGE("deviceId is invalid!");
124 return DP_INVALID_PARAM;
125 }
126 if (!cJSON_IsObject(staticInfoJson)) {
127 HILOGE("staticInfoJson is json object!");
128 return DP_INVALID_PARAM;
129 }
130 if (staticVersion.empty() || staticVersion.size() > MAX_STRING_LEN) {
131 HILOGE("staticVersion is invalid!");
132 return DP_INVALID_PARAM;
133 }
134 cJSON* json = GetStaticInfoJsonByVersion(staticInfoJson, staticVersion);
135 if (json == NULL) {
136 HILOGE("staticInfoJson is nullptr!");
137 return DP_GET_STATIC_INFO_FAIL;
138 }
139 GenerateStaticProfiles(deviceId, staticCapability, json, charProfiles);
140 return DP_SUCCESS;
141 }
142
GetLatestStaticInfoJson(const cJSON * const staticInfoJson)143 cJSON* StaticCapabilityLoader::GetLatestStaticInfoJson(const cJSON* const staticInfoJson)
144 {
145 HILOGD("call!");
146 if (!cJSON_IsObject(staticInfoJson)) {
147 HILOGE("staticInfoJson is not object!");
148 return NULL;
149 }
150 cJSON* staticInfos = cJSON_GetObjectItem(staticInfoJson, STATIC_INFO.c_str());
151 if (!cJSON_IsArray(staticInfos)) {
152 HILOGE("StaticInfos is not Array!");
153 return NULL;
154 }
155 int32_t staticInfoNum = static_cast<int32_t>(cJSON_GetArraySize(staticInfos));
156 if (staticInfoNum == 0 || staticInfoNum > MAX_STATIC_CAPABILITY_SIZE) {
157 HILOGE("staticInfoNum is invalid, nums: %{public}d!", staticInfoNum);
158 return NULL;
159 }
160 return cJSON_GetArrayItem(staticInfos, staticInfoNum - 1);
161 }
162
GetStaticInfoJsonByVersion(const cJSON * const staticInfoJson,const std::string & staticVersion)163 cJSON* StaticCapabilityLoader::GetStaticInfoJsonByVersion(const cJSON* const staticInfoJson,
164 const std::string& staticVersion)
165 {
166 HILOGD("call!");
167 if (!cJSON_IsObject(staticInfoJson)) {
168 HILOGE("staticInfoJson is not object!");
169 return NULL;
170 }
171 if (staticVersion.empty() || staticVersion.size() > MAX_STRING_LEN) {
172 HILOGE("staticVersion is invalid!");
173 return NULL;
174 }
175 cJSON* staticInfos = cJSON_GetObjectItem(staticInfoJson, STATIC_INFO.c_str());
176 if (!cJSON_IsArray(staticInfos)) {
177 HILOGE("StaticInfos is not Array!");
178 return NULL;
179 }
180 int32_t staticInfoNum = static_cast<int32_t>(cJSON_GetArraySize(staticInfos));
181 if (staticInfoNum == 0 || staticInfoNum > MAX_STATIC_CAPABILITY_SIZE) {
182 HILOGE("staticInfoNum is invalid, nums: %{public}d!", staticInfoNum);
183 return NULL;
184 }
185 cJSON *item = NULL;
186 cJSON_ArrayForEach(item, staticInfos) {
187 if (!cJSON_IsObject(item)) {
188 HILOGE("Item is not object!");
189 continue;
190 }
191 cJSON* versionItem = cJSON_GetObjectItemCaseSensitive(item, DP_VERSION.c_str());
192 if (!cJSON_IsString(versionItem) || versionItem->valuestring == NULL) {
193 HILOGE("Get DP_Version fail!");
194 continue;
195 }
196 std::string version = versionItem->valuestring;
197 if (StaticVersionCheck(staticVersion, version)) {
198 HILOGI("Get staticInfoJson Success!");
199 return item;
200 }
201 }
202 HILOGE("staticInfoJson not found");
203 return NULL;
204 }
205
GetStaticVersion(const cJSON * const lastStaticInfo,std::string & staticVersion)206 int32_t StaticCapabilityLoader::GetStaticVersion(const cJSON* const lastStaticInfo, std::string& staticVersion)
207 {
208 HILOGD("call!");
209 if (!cJSON_IsObject(lastStaticInfo)) {
210 HILOGE("LastStaticInfoItem is not object!");
211 return DP_GET_STATIC_INFO_FAIL;
212 }
213 cJSON* dpVersionJson = cJSON_GetObjectItemCaseSensitive(lastStaticInfo, DP_VERSION.c_str());
214 if (!cJSON_IsString(dpVersionJson) || dpVersionJson->valuestring == NULL) {
215 HILOGE("dpVersionJson is invalid!");
216 return DP_GET_STATIC_INFO_FAIL;
217 }
218 staticVersion = dpVersionJson->valuestring;
219 return DP_SUCCESS;
220 }
221
GenerateStaticProfiles(const std::string & deviceId,const std::string & staticCapability,const cJSON * const staticInfoJson,std::unordered_map<std::string,CharacteristicProfile> & charProfiles)222 int32_t StaticCapabilityLoader::GenerateStaticProfiles(const std::string& deviceId, const std::string& staticCapability,
223 const cJSON* const staticInfoJson, std::unordered_map<std::string, CharacteristicProfile>& charProfiles)
224 {
225 HILOGD("call!");
226 if (deviceId.empty() || deviceId.size() > MAX_STRING_LEN) {
227 HILOGE("deviceId is invalid!");
228 return DP_INVALID_PARAM;
229 }
230 if (!cJSON_IsObject(staticInfoJson)) {
231 HILOGE("staticInfoJson is not object!");
232 return DP_GET_STATIC_INFO_FAIL;
233 }
234 cJSON* abilitiesJson = cJSON_GetObjectItemCaseSensitive(staticInfoJson, ABILITIES.c_str());
235 if (!cJSON_IsArray(abilitiesJson)) {
236 HILOGE("abilitiesJson is not array!");
237 return DP_GET_STATIC_INFO_FAIL;
238 }
239 cJSON* abilityItem = NULL;
240 cJSON_ArrayForEach(abilityItem, abilitiesJson) {
241 if (!cJSON_IsObject(abilityItem)) {
242 HILOGE("abilityItem is not object!");
243 continue;
244 }
245 cJSON* abilityKeyItem = cJSON_GetObjectItemCaseSensitive(abilityItem, ABILITY_KEY.c_str());
246 if (!cJSON_IsString(abilityKeyItem) || abilityKeyItem->valuestring == NULL) {
247 HILOGE("Get abilityKeyItem fail!");
248 continue;
249 }
250 cJSON* abilityValueItem = cJSON_GetObjectItemCaseSensitive(abilityItem, ABILITY_VALUE.c_str());
251 if (!cJSON_IsObject(abilityValueItem)) {
252 HILOGE("Get abilityValueItem fail!");
253 continue;
254 }
255 std::string serviceId = abilityKeyItem->valuestring;
256 if (!HasStaticCapability(serviceId, staticCapability)) {
257 HILOGW("service: %{public}s does not have static capability", serviceId.c_str());
258 continue;
259 }
260 HILOGD("service: %{public}s has static capability", serviceId.c_str());
261 char* abilityValue = cJSON_Print(abilityValueItem);
262 if (abilityValue == NULL) {
263 HILOGE("Get abilityValue fail!");
264 continue;
265 }
266 std::string charValue = abilityValue;
267 cJSON_free(abilityValue);
268 CharacteristicProfile characteristicProfile(deviceId, serviceId, STATIC_CHARACTERISTIC_KEY, charValue);
269 charProfiles[ProfileUtils::GenerateCharProfileKey(deviceId, serviceId, STATIC_CHARACTERISTIC_KEY)] =
270 characteristicProfile;
271 }
272 return DP_SUCCESS;
273 }
274
LoadStaticInfo(const std::string & staticCapability,std::string & staticVersion,std::unordered_map<std::string,CharacteristicProfile> & charProfiles)275 int32_t StaticCapabilityLoader::LoadStaticInfo(const std::string& staticCapability, std::string& staticVersion,
276 std::unordered_map<std::string, CharacteristicProfile>& charProfiles)
277 {
278 HILOGD("call!");
279 if (staticCapability.empty() || staticCapability.size() > MAX_STRING_LEN) {
280 HILOGE("staticCapability is invalid!");
281 return DP_INVALID_PARAM;
282 }
283 std::string fileContent = "";
284 int32_t loadJsonResult = LoadJsonFile(STATIC_INFO_PATH, fileContent);
285 if (loadJsonResult != DP_SUCCESS) {
286 HILOGE("Load staticInfo json failed, result: %{public}d!", loadJsonResult);
287 return loadJsonResult;
288 }
289 cJSON* staticInfoJson = cJSON_Parse(fileContent.c_str());
290 if (!cJSON_IsObject(staticInfoJson)) {
291 HILOGE("Static info json parse failed!");
292 cJSON_Delete(staticInfoJson);
293 return DP_PARSE_STATIC_INFO_FAIL;
294 }
295 int32_t getInfoResult = GetStaticInfo(staticInfoJson, staticCapability, staticVersion, charProfiles);
296 if (getInfoResult != DP_SUCCESS) {
297 HILOGE("Get static info result %{public}d!", getInfoResult);
298 cJSON_Delete(staticInfoJson);
299 return getInfoResult;
300 }
301 HILOGI("success!");
302 cJSON_Delete(staticInfoJson);
303 return DP_SUCCESS;
304 }
305
LoadStaticProfiles(const std::string & deviceId,const std::string & staticCapability,const std::string & staticVersion,std::unordered_map<std::string,CharacteristicProfile> & charProfiles)306 int32_t StaticCapabilityLoader::LoadStaticProfiles(const std::string& deviceId, const std::string& staticCapability,
307 const std::string& staticVersion, std::unordered_map<std::string, CharacteristicProfile>& charProfiles)
308 {
309 HILOGD("call!");
310 if (deviceId.empty() || deviceId.size() > MAX_STRING_LEN) {
311 HILOGE("deviceId is invalid!");
312 return DP_INVALID_PARAM;
313 }
314 if (staticCapability.empty() || staticCapability.size() > MAX_STRING_LEN) {
315 HILOGE("staticCapability is invalid!");
316 return DP_INVALID_PARAM;
317 }
318 if (staticVersion.empty() || staticVersion.size() > MAX_STRING_LEN) {
319 HILOGE("staticVersion is invalid!");
320 return DP_INVALID_PARAM;
321 }
322 std::string fileContent = "";
323 int32_t loadJsonResult = LoadJsonFile(STATIC_INFO_PATH, fileContent);
324 if (loadJsonResult != DP_SUCCESS) {
325 HILOGE("Load staticInfo json failed, result: %{public}d!", loadJsonResult);
326 return loadJsonResult;
327 }
328 cJSON* staticInfoJson = cJSON_Parse(fileContent.c_str());
329 if (!cJSON_IsObject(staticInfoJson)) {
330 HILOGE("Static info json parse failed!");
331 cJSON_Delete(staticInfoJson);
332 return DP_PARSE_STATIC_INFO_FAIL;
333 }
334 int32_t getInfoResult = GetStaticInfoByVersion(deviceId, staticCapability, staticInfoJson,
335 staticVersion, charProfiles);
336 if (getInfoResult != DP_SUCCESS) {
337 HILOGE("Get static info result %{public}d!", getInfoResult);
338 cJSON_Delete(staticInfoJson);
339 return getInfoResult;
340 }
341 HILOGI("success!");
342 cJSON_Delete(staticInfoJson);
343 return DP_SUCCESS;
344 }
345
InitStaticCapability(int32_t size,std::string & staticCapability)346 void StaticCapabilityLoader::InitStaticCapability(int32_t size, std::string& staticCapability)
347 {
348 HILOGI("InitStaticCapability size %{public}d!", size);
349 staticCapability = EMPTY_STRING;
350 for (int32_t i = 0; i < size; i++) {
351 staticCapability += DEFAULT_STATIC_VAL;
352 }
353 HILOGI("InitStaticCapability value %{public}s!", staticCapability.c_str());
354 }
355
SetStaticCapability(const cJSON * const staticCapabilityItems,std::string & staticCapability)356 void StaticCapabilityLoader::SetStaticCapability(const cJSON* const staticCapabilityItems,
357 std::string& staticCapability)
358 {
359 HILOGD("call!");
360 if (!cJSON_IsArray(staticCapabilityItems)) {
361 HILOGE("staticCapabilityItems is not json array!");
362 return;
363 }
364 cJSON *item = NULL;
365 cJSON_ArrayForEach(item, staticCapabilityItems) {
366 if (!cJSON_IsObject(item)) {
367 HILOGE("Item is not object!");
368 continue;
369 }
370 cJSON* nameItem = cJSON_GetObjectItemCaseSensitive(item, STATIC_CAP_HANDLER_NAME.c_str());
371 if (!cJSON_IsString(nameItem) || nameItem->valuestring == NULL) {
372 HILOGE("Get handler_name fail!");
373 continue;
374 }
375 cJSON* locItem = cJSON_GetObjectItemCaseSensitive(item, STATIC_CAP_HANDLER_LOC.c_str());
376 if (!cJSON_IsString(locItem) || locItem->valuestring == NULL) {
377 HILOGE("Get handler_loc fail!");
378 continue;
379 }
380 std::string handlerName = nameItem->valuestring;
381 std::string handlerLoc = locItem->valuestring;
382 SetStaticCapabilityFlag(handlerName, handlerLoc, staticCapability);
383 }
384 }
385
SetStaticCapabilityFlag(const std::string & handlerName,const std::string & handlerLoc,std::string & staticCapability)386 void StaticCapabilityLoader::SetStaticCapabilityFlag(const std::string& handlerName, const std::string& handlerLoc,
387 std::string& staticCapability)
388 {
389 HILOGD("call!");
390 if (handlerName.empty() || handlerName.size() > MAX_STRING_LEN) {
391 HILOGE("handlerName is invalid!");
392 return;
393 }
394 if (handlerLoc.empty() || handlerLoc.size() > MAX_STRING_LEN) {
395 HILOGE("handlerLoc is invalid!");
396 return;
397 }
398 if (CAPABILITY_FLAG_MAP.count(handlerName) == 0) {
399 HILOGE("SetStaticCapabilityFlag fail, handlerName: %{public}s!", handlerName.c_str());
400 return;
401 }
402 int32_t capabilityFlag = static_cast<int32_t>(CAPABILITY_FLAG_MAP.at(handlerName));
403 if (capabilityFlag >= static_cast<int32_t>(staticCapability.size())) {
404 HILOGE("SetStaticCapabilityFlag fail, handlerName: %{public}s!", handlerName.c_str());
405 return;
406 }
407 char capabilityValue = GetStaticCapabilityValue(handlerLoc) ? SUPPORT_STATIC_VAL : NOT_SUPPORT_STATIC_VAL;
408 staticCapability[capabilityFlag] = capabilityValue;
409 HILOGI("handlerName: %{public}s, staticCapability: %{public}c", handlerName.c_str(), capabilityValue);
410 }
411
GetStaticCapabilityValue(const std::string & handlerLoc)412 bool StaticCapabilityLoader::GetStaticCapabilityValue(const std::string& handlerLoc)
413 {
414 HILOGD("call!");
415 if (handlerLoc.length() == 0 || handlerLoc.length() > PATH_MAX) {
416 HILOGE("File canonicalization failed!");
417 return false;
418 }
419 void *so_handler = dlopen(handlerLoc.c_str(), RTLD_LAZY | RTLD_NODELETE);
420 if (so_handler == nullptr) {
421 HILOGE("%{public}s handler load failed, failed reason : %{public}s", handlerLoc.c_str(), dlerror());
422 return false;
423 }
424 auto func = (StaticCapabilityHandler)dlsym(so_handler, "GetStaticCapabilityCollector");
425 if (func == nullptr) {
426 dlclose(so_handler);
427 HILOGE("Get StaticCapabilityHandler is null, failed reason : %{public}s", dlerror());
428 return false;
429 }
430 bool isSupportStaticCapability = func();
431 HILOGI("GetStaticCapabilityValue %{public}d", isSupportStaticCapability);
432 dlclose(so_handler);
433 return isSupportStaticCapability;
434 }
435
HasStaticCapability(const std::string & serviceId,const std::string & staticCapability)436 bool StaticCapabilityLoader::HasStaticCapability(const std::string& serviceId, const std::string& staticCapability)
437 {
438 HILOGD("call!");
439 if (CAPABILITY_FLAG_MAP.find(serviceId) == CAPABILITY_FLAG_MAP.end()) {
440 HILOGE("serviceId doesn't exist map, serviceId: %{public}s",
441 ProfileUtils::GetAnonyString(serviceId).c_str());
442 return false;
443 }
444 int32_t capabilityFlag = static_cast<int32_t>(CAPABILITY_FLAG_MAP.at(serviceId));
445 if (capabilityFlag >= static_cast<int32_t>(staticCapability.size())) {
446 HILOGE("HasStaticCapability fail, capabilityFlag is out of range, serviceId: %{public}s",
447 ProfileUtils::GetAnonyString(serviceId).c_str());
448 return false;
449 }
450 return staticCapability[capabilityFlag] == SUPPORT_STATIC_VAL;
451 }
452
StaticVersionCheck(const std::string & peerVersion,const std::string & localVersion)453 bool StaticCapabilityLoader::StaticVersionCheck(const std::string& peerVersion, const std::string& localVersion)
454 {
455 HILOGD("call!");
456 if (peerVersion == localVersion) {
457 HILOGI("staticVersion equal");
458 return true;
459 }
460 if (!IsValidVersion(peerVersion) || !IsValidVersion(localVersion)) {
461 HILOGE("Params are valid");
462 return false;
463 }
464 return true;
465 }
466
IsValidVersion(const std::string & version)467 bool StaticCapabilityLoader::IsValidVersion(const std::string& version)
468 {
469 std::regex rule(STATIC_VERSION_RULES);
470 return std::regex_match(version, rule);
471 }
472
473 } // namespace DistributedDeviceProfile
474 } // namespace OHOS
475