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 "distributed_sched_utils.h"
17
18 #include <algorithm>
19 #include <cstdlib>
20 #include <filesystem>
21 #include <fstream>
22 #include <iostream>
23 #include <vector>
24
25 #include "ability_manager_client.h"
26 #include "config_policy_utils.h"
27 #include "securec.h"
28
29 #include "dms_constant.h"
30 #include "dtbschedmgr_log.h"
31
32 namespace OHOS {
33 namespace DistributedSchedule {
34 using namespace OHOS::DistributedSchedule::Constants;
35
36 const std::string TAG = "DistributedSchedUtils";
37 const std::string CONTINUE_CONFIG_RELATIVE_PATH = "etc/distributedhardware/dms/continue_config.json";
38 const std::string ALLOW_APP_LIST_KEY = "allow_applist";
39 constexpr int32_t MAX_CONFIG_PATH_LEN = 1024;
40 constexpr size_t INT32_SHORT_ID_LEN = 20;
41 constexpr size_t INT32_MIN_ID_LEN = 6;
42 constexpr size_t INT32_PLAINTEXT_LEN = 4;
43
44 constexpr uint32_t OFFSET2 = 2;
45 constexpr uint32_t OFFSET4 = 4;
46 constexpr uint32_t OFFSET6 = 6;
47 constexpr uint8_t PARAM_FC = 0xfc;
48 constexpr uint8_t PARAM_03 = 0x03;
49 constexpr uint8_t PARAM_F0 = 0xf0;
50 constexpr uint8_t PARAM_0F = 0x0f;
51 constexpr uint8_t PARAM_C0 = 0xc0;
52 constexpr uint8_t PARAM_3F = 0x3f;
53 constexpr uint32_t INDEX_FIRST = 0;
54 constexpr uint32_t INDEX_SECOND = 1;
55 constexpr uint32_t INDEX_THIRD = 2;
56 constexpr uint32_t INDEX_FORTH = 3;
57
58 static std::atomic<bool> g_isMissContinueCfg = false;
59 static std::string g_continueCfgFullPath = "";
60 static std::vector<std::string> g_allowAppList;
61 std::mutex g_allowAppListMtx;
62
63 using JsonTypeCheckFunc = bool (*)(const cJSON *paramValue);
64 std::map<std::string, JsonTypeCheckFunc> jsonTypeCheckMap = {
65 std::map<std::string, JsonTypeCheckFunc>::value_type(PARAM_KEY_OS_TYPE, &DistributedSchedule::IsInt32),
66 std::map<std::string, JsonTypeCheckFunc>::value_type(PARAM_KEY_OS_VERSION, &DistributedSchedule::IsString),
67 };
68
IsValidPath(const std::string & inFilePath,std::string & realFilePath)69 bool IsValidPath(const std::string &inFilePath, std::string &realFilePath)
70 {
71 char path[PATH_MAX + 1] = { 0 };
72 if (inFilePath.empty() || inFilePath.length() > PATH_MAX || inFilePath.length() + 1 > MAX_CONFIG_PATH_LEN ||
73 realpath(inFilePath.c_str(), path) == nullptr) {
74 HILOGE("Get continue config file real path fail, inFilePath %{public}s.", GetAnonymStr(inFilePath).c_str());
75 return false;
76 }
77
78 realFilePath = std::string(path);
79 if (realFilePath.empty()) {
80 HILOGE("Real file path is empty.");
81 return false;
82 }
83 if (!std::filesystem::exists(realFilePath)) {
84 HILOGE("The real file path %{public}s does not exist in the file system.", GetAnonymStr(realFilePath).c_str());
85 realFilePath = "";
86 return false;
87 }
88 HILOGI("The real file path %{public}s exist in the file system.", GetAnonymStr(realFilePath).c_str());
89 return true;
90 }
91
UpdateAllowAppList(const std::string & cfgJsonStr)92 bool UpdateAllowAppList(const std::string &cfgJsonStr)
93 {
94 cJSON *inJson = nullptr;
95 cJSON *allowList = nullptr;
96 bool isSuccess = false;
97 do {
98 inJson = cJSON_Parse(cfgJsonStr.c_str());
99 if (inJson == nullptr) {
100 HILOGE("parse continue config json file stream to json fail.");
101 break;
102 }
103
104 allowList = cJSON_GetObjectItem(inJson, ALLOW_APP_LIST_KEY.c_str());
105 if (allowList == nullptr || !cJSON_IsArray(allowList)) {
106 HILOGE("allow app list array is not in continue config json file.");
107 break;
108 }
109
110 std::lock_guard<std::mutex> lock(g_allowAppListMtx);
111 for (int32_t i = 0; i < cJSON_GetArraySize(allowList); i++) {
112 cJSON *iAllowAppJson = cJSON_GetArrayItem(allowList, i);
113 if (!cJSON_IsString(iAllowAppJson)) {
114 HILOGE("allow app list [%{public}d] is not string.", i);
115 continue;
116 }
117
118 std::string iAllowAppStr = std::string(cJSON_GetStringValue(iAllowAppJson));
119 HILOGI("allow app list show [%{public}d] : [%{public}s].", i, iAllowAppStr.c_str());
120 g_allowAppList.push_back(iAllowAppStr);
121 }
122 isSuccess = true;
123 } while (false);
124
125 if (inJson != nullptr) {
126 cJSON_Delete(inJson);
127 inJson = nullptr;
128 }
129 return isSuccess;
130 }
131
LoadContinueConfig()132 int32_t LoadContinueConfig()
133 {
134 HILOGI("Load continue config, isMissContinueCfg %{public}d, ContinueCfgFullPath %{public}s.",
135 g_isMissContinueCfg.load(), GetAnonymStr(g_continueCfgFullPath).c_str());
136 std::string tempPath = g_continueCfgFullPath;
137 if (!g_isMissContinueCfg.load() &&
138 (g_continueCfgFullPath.empty() || !IsValidPath(tempPath, g_continueCfgFullPath))) {
139 char cfgPathBuf[MAX_CONFIG_PATH_LEN] = { 0 };
140 char *filePath = GetOneCfgFile(CONTINUE_CONFIG_RELATIVE_PATH.c_str(), cfgPathBuf, MAX_CONFIG_PATH_LEN);
141 if (filePath == nullptr || filePath != cfgPathBuf) {
142 HILOGI("Not find continue config file, relative path %{public}s.",
143 GetAnonymStr(CONTINUE_CONFIG_RELATIVE_PATH).c_str());
144 g_isMissContinueCfg.store(true);
145 g_continueCfgFullPath = "";
146 return ERR_OK;
147 }
148 g_isMissContinueCfg.store(false);
149 g_continueCfgFullPath = std::string(filePath);
150 HILOGI("Get Continue config file full path success, cfgFullPath %{public}s.",
151 GetAnonymStr(g_continueCfgFullPath).c_str());
152 }
153 if (g_isMissContinueCfg.load()) {
154 HILOGI("Current device does not carry continue config file.");
155 return ERR_OK;
156 }
157 tempPath = g_continueCfgFullPath;
158 std::string anonymPath = GetAnonymStr(g_continueCfgFullPath);
159 if (!IsValidPath(tempPath, g_continueCfgFullPath)) {
160 HILOGE("Continue config full path is invalid, cfgFullPath %{public}s.", anonymPath.c_str());
161 return DMS_PERMISSION_DENIED;
162 }
163 std::ifstream in;
164 in.open(g_continueCfgFullPath.c_str(), std::ios::binary | std::ios::in);
165 if (!in.is_open()) {
166 HILOGE("Open continue config json file fail, cfgFullPath %{public}s.", anonymPath.c_str());
167 return DMS_PERMISSION_DENIED;
168 }
169
170 std::string cfgFileContent;
171 in.seekg(0, std::ios::end);
172 cfgFileContent.resize(in.tellg());
173 in.seekg(0, std::ios::beg);
174 in.rdbuf()->sgetn(&cfgFileContent[0], cfgFileContent.size());
175 in.close();
176
177 if (!UpdateAllowAppList(cfgFileContent)) {
178 HILOGE("Update allow app list fail, cfgFullPath %{public}s.", anonymPath.c_str());
179 return DMS_PERMISSION_DENIED;
180 }
181 HILOGI("Load continue config success, isMissContinueCfg %{public}d, cfgFullPath %{public}s.",
182 g_isMissContinueCfg.load(), anonymPath.c_str());
183 return ERR_OK;
184 }
185
CheckBundleContinueConfig(const std::string & bundleName)186 bool CheckBundleContinueConfig(const std::string &bundleName)
187 {
188 if (g_isMissContinueCfg.load()) {
189 HILOGI("Current device does not carry continue config file.");
190 return true;
191 }
192
193 std::lock_guard<std::mutex> lock(g_allowAppListMtx);
194 auto it = std::find(g_allowAppList.begin(), g_allowAppList.end(), bundleName);
195 if (it == g_allowAppList.end()) {
196 HILOGE("Current app is not allow to continue in config file, bundleName %{public}s, cfgPath %{public}s.",
197 bundleName.c_str(), GetAnonymStr(g_continueCfgFullPath).c_str());
198 return false;
199 }
200
201 HILOGI("Current app is allow to continue in config file, bundleName %{public}s, cfgPath %{public}s.",
202 bundleName.c_str(), GetAnonymStr(g_continueCfgFullPath).c_str());
203 return true;
204 }
205
GetCurrentMissionId()206 int32_t GetCurrentMissionId()
207 {
208 HILOGI("GetCurrentMission begin");
209 sptr<IRemoteObject> token;
210 int ret = AAFwk::AbilityManagerClient::GetInstance()->GetTopAbility(token);
211 if (ret != ERR_OK || token == nullptr) {
212 HILOGE("GetTopAbility failed, ret: %{public}d", ret);
213 return INVALID_MISSION_ID;
214 }
215 int32_t missionId = INVALID_MISSION_ID;
216 if (AAFwk::AbilityManagerClient::GetInstance()->GetMissionIdByToken(token, missionId) != ERR_OK) {
217 HILOGE("GetMissionIdByToken failed");
218 return INVALID_MISSION_ID;
219 }
220 return missionId;
221 }
222
ParcelToBase64Str(const Parcel & parcel)223 std::string ParcelToBase64Str(const Parcel& parcel)
224 {
225 auto parcelSize = parcel.GetDataSize();
226 return Base64Encode(reinterpret_cast<const unsigned char *>(parcel.GetData()), parcelSize);
227 }
228
Base64StrToParcel(const std::string & rawStr,Parcel & parcel)229 int32_t Base64StrToParcel(const std::string& rawStr, Parcel& parcel)
230 {
231 std::string str = Base64Decode(rawStr);
232 auto parcelSize = str.size();
233 if (!parcel.SetDataCapacity(parcelSize)) {
234 return INVALID_PARAMETERS_ERR;
235 }
236 auto ret = memcpy_s((void *)parcel.GetData(), parcel.GetMaxCapacity(), &str[0], parcelSize);
237 if (ret != ERR_OK || !parcel.SetDataSize(parcelSize)) {
238 return INVALID_PARAMETERS_ERR;
239 }
240 return ERR_OK;
241 }
242
Base64Encode(const unsigned char * toEncode,unsigned int len)243 std::string Base64Encode(const unsigned char *toEncode, unsigned int len)
244 {
245 std::string ret = "";
246 if (len == 0 || toEncode == nullptr) {
247 HILOGE("toEncode is null or len is zero.");
248 return ret;
249 }
250 uint32_t length = len;
251 uint32_t i = 0;
252 unsigned char charArray3[3];
253 unsigned char charArray4[4];
254
255 while (length > 0) {
256 charArray3[i++] = *(toEncode++);
257 if (i == sizeof(charArray3)) {
258 charArray4[INDEX_FIRST] = (charArray3[INDEX_FIRST] & PARAM_FC) >> OFFSET2;
259 charArray4[INDEX_SECOND] = ((charArray3[INDEX_FIRST] & PARAM_03) << OFFSET4) +
260 ((charArray3[INDEX_SECOND] & PARAM_F0) >> OFFSET4);
261 charArray4[INDEX_THIRD] = ((charArray3[INDEX_SECOND] & PARAM_0F) << OFFSET2) +
262 ((charArray3[INDEX_THIRD] & PARAM_C0) >> OFFSET6);
263 charArray4[INDEX_FORTH] = charArray3[INDEX_THIRD] & PARAM_3F;
264 for (i = 0; i < sizeof(charArray4); i++) {
265 ret += BASE_64_CHARS[charArray4[i]];
266 }
267 i = 0;
268 }
269 length--;
270 }
271
272 if (i > 0) {
273 uint32_t j = 0;
274 for (j = i; j < sizeof(charArray3); j++) {
275 charArray3[j] = '\0';
276 }
277 charArray4[INDEX_FIRST] = (charArray3[INDEX_FIRST] & PARAM_FC) >> OFFSET2;
278 charArray4[INDEX_SECOND] = ((charArray3[INDEX_FIRST] & PARAM_03) << OFFSET4) +
279 ((charArray3[INDEX_SECOND] & PARAM_F0) >> OFFSET4);
280 charArray4[INDEX_THIRD] = ((charArray3[INDEX_SECOND] & PARAM_0F) << OFFSET2) +
281 ((charArray3[INDEX_THIRD] & PARAM_C0) >> OFFSET6);
282 charArray4[INDEX_FORTH] = charArray3[INDEX_THIRD] & PARAM_3F;
283 for (j = 0; j < i + 1; j++) {
284 ret += BASE_64_CHARS[charArray4[j]];
285 }
286 while (i++ < sizeof(charArray3)) {
287 ret += '=';
288 }
289 }
290 return ret;
291 }
292
Base64Decode(const std::string & basicString)293 std::string Base64Decode(const std::string& basicString)
294 {
295 std::string ret = "";
296 if (basicString.empty()) {
297 HILOGE("basicString is empty.");
298 return ret;
299 }
300 uint32_t i = 0;
301 int index = 0;
302 int len = static_cast<int>(basicString.size());
303 unsigned char charArray3[3];
304 unsigned char charArray4[4];
305
306 while (len-- && (basicString[index] != '=') && IsBase64(basicString[index])) {
307 charArray4[i++] = basicString[index];
308 index++;
309 if (i == sizeof(charArray4)) {
310 for (i = 0; i < sizeof(charArray4); i++) {
311 charArray4[i] = BASE_64_CHARS.find(charArray4[i]);
312 }
313 charArray3[INDEX_FIRST] = (charArray4[INDEX_FIRST] << OFFSET2) +
314 ((charArray4[INDEX_SECOND] & 0x30) >> OFFSET4);
315 charArray3[INDEX_SECOND] = ((charArray4[INDEX_SECOND] & 0xf) << OFFSET4) +
316 ((charArray4[INDEX_THIRD] & 0x3c) >> OFFSET2);
317 charArray3[INDEX_THIRD] = ((charArray4[INDEX_THIRD] & 0x3) << OFFSET6) + charArray4[INDEX_FORTH];
318 for (i = 0; i < sizeof(charArray3); i++) {
319 ret += charArray3[i];
320 }
321 i = 0;
322 }
323 }
324
325 if (i > 0) {
326 uint32_t j = 0;
327 for (j = i; j < sizeof(charArray4); j++) {
328 charArray4[j] = 0;
329 }
330 for (j = 0; j < sizeof(charArray4); j++) {
331 charArray4[j] = BASE_64_CHARS.find(charArray4[j]);
332 }
333 charArray3[INDEX_FIRST] = (charArray4[INDEX_FIRST] << OFFSET2) +
334 ((charArray4[INDEX_SECOND] & 0x30) >> OFFSET4);
335 charArray3[INDEX_SECOND] = ((charArray4[INDEX_SECOND] & 0xf) << OFFSET4) +
336 ((charArray4[INDEX_THIRD] & 0x3c) >> OFFSET2);
337 charArray3[INDEX_THIRD] = ((charArray4[INDEX_THIRD] & 0x3) << OFFSET6) + charArray4[INDEX_FORTH];
338 for (j = 0; j < i - 1; j++) {
339 ret += charArray3[j];
340 }
341 }
342 return ret;
343 }
344
IsBase64(unsigned char c)345 bool IsBase64(unsigned char c)
346 {
347 return (isalnum(c) || (c == '+') || (c == '/'));
348 }
349
GetAnonymStr(const std::string & value)350 std::string GetAnonymStr(const std::string &value)
351 {
352 std::string res;
353 std::string tmpStr("******");
354 size_t strLen = value.length();
355 if (strLen < INT32_MIN_ID_LEN) {
356 return tmpStr;
357 }
358
359 if (strLen <= INT32_SHORT_ID_LEN) {
360 res += value[0];
361 res += tmpStr;
362 res += value[strLen - 1];
363 } else {
364 res.append(value, 0, INT32_PLAINTEXT_LEN);
365 res += tmpStr;
366 res.append(value, strLen - INT32_PLAINTEXT_LEN, INT32_PLAINTEXT_LEN);
367 }
368
369 return res;
370 }
371
GetAnonymInt32(const int32_t value)372 std::string GetAnonymInt32(const int32_t value)
373 {
374 std::string tmpStr = std::to_string(value);
375 return GetAnonymStr(tmpStr);
376 }
377
IsInt32(const cJSON * paramValue)378 bool IsInt32(const cJSON *paramValue)
379 {
380 if (paramValue == nullptr) {
381 HILOGE("JSON parameter is invalid.");
382 return false;
383 }
384
385 if (!cJSON_IsNumber(paramValue)) {
386 HILOGE("JSON parameter is not number.");
387 return false;
388 }
389
390 int32_t value = paramValue->valueint;
391 if (!(INT32_MIN <= value && value <= INT32_MAX)) {
392 HILOGE("JSON parameter number is outside the int32_t range.");
393 return false;
394 }
395 return true;
396 }
397
IsString(const cJSON * paramValue)398 bool IsString(const cJSON *paramValue)
399 {
400 if (paramValue == nullptr) {
401 HILOGE("JSON parameter is invalid.");
402 return false;
403 }
404
405 if (!cJSON_IsString(paramValue)) {
406 HILOGE("JSON parameter is not string.");
407 return false;
408 }
409 return true;
410 }
411
CJsonParamCheck(const cJSON * jsonObj,const std::initializer_list<std::string> & keys)412 bool CJsonParamCheck(const cJSON *jsonObj, const std::initializer_list<std::string> &keys)
413 {
414 if (jsonObj == nullptr || !cJSON_IsObject(jsonObj)) {
415 HILOGE("JSON parameter is invalid.");
416 return false;
417 }
418
419 for (auto it = keys.begin(); it != keys.end(); it++) {
420 cJSON *paramValue = cJSON_GetObjectItemCaseSensitive(jsonObj, (*it).c_str());
421 if (paramValue == nullptr) {
422 HILOGE("JSON parameter does not contain key: %{public}s", (*it).c_str());
423 return false;
424 }
425 auto iter = jsonTypeCheckMap.find(*it);
426 if (iter == jsonTypeCheckMap.end()) {
427 HILOGE("Check is not supported yet, key %{public}s.", (*it).c_str());
428 return false;
429 }
430 if (iter->second == nullptr) {
431 HILOGE("JsonTypeCheckFunc for key %{public}s is nullptr.", (*it).c_str());
432 return false;
433 }
434 JsonTypeCheckFunc &func = iter->second;
435 bool res = (*func)(paramValue);
436 if (!res) {
437 HILOGE("The key %{public}s value format in JSON is illegal.", (*it).c_str());
438 return false;
439 }
440 }
441 return true;
442 }
443
GetOsInfoFromDM(const std::string & dmInfoEx,int32_t & osType,std::string & osVersion)444 bool GetOsInfoFromDM(const std::string &dmInfoEx, int32_t &osType, std::string &osVersion)
445 {
446 cJSON *dataJson = nullptr;
447 bool isSuccess = false;
448 do {
449 dataJson = cJSON_Parse(dmInfoEx.c_str());
450 if (dataJson == nullptr) {
451 HILOGE("Parse device info extra data to json fail.");
452 break;
453 }
454
455 if (!CJsonParamCheck(dataJson, {PARAM_KEY_OS_TYPE, PARAM_KEY_OS_VERSION})) {
456 HILOGE("Check OS type and version from device extra data json fail.");
457 break;
458 }
459
460 osType = cJSON_GetObjectItemCaseSensitive(dataJson, PARAM_KEY_OS_TYPE)->valueint;
461 osVersion = std::string(cJSON_GetObjectItemCaseSensitive(dataJson, PARAM_KEY_OS_VERSION)->valuestring);
462 isSuccess = true;
463 } while (false);
464
465 if (dataJson != nullptr) {
466 cJSON_Delete(dataJson);
467 dataJson = nullptr;
468 }
469 return isSuccess;
470 }
471 } // namespace DistributedSchedule
472 } // namespace OHOS
473