1 /*
2 * Copyright (c) 2021-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 "bundle_util.h"
17
18 #include <cinttypes>
19 #include <dirent.h>
20 #include <fcntl.h>
21 #include <fstream>
22 #include <sstream>
23 #include <sys/sendfile.h>
24 #include <sys/statfs.h>
25
26 #include "bundle_service_constants.h"
27 #ifdef CONFIG_POLOCY_ENABLE
28 #include "config_policy_utils.h"
29 #endif
30 #include "directory_ex.h"
31 #include "hitrace_meter.h"
32 #include "installd_client.h"
33 #include "ipc_skeleton.h"
34 #include "parameter.h"
35 #include "string_ex.h"
36 #ifdef BUNDLE_FRAMEWORK_UDMF_ENABLED
37 #include "type_descriptor.h"
38 #include "utd_client.h"
39 #endif
40
41 namespace OHOS {
42 namespace AppExecFwk {
43 namespace {
44 const std::string::size_type EXPECT_SPLIT_SIZE = 2;
45 const size_t ORIGIN_STRING_LENGTH = 32;
46 constexpr char UUID_SEPARATOR = '-';
47 const std::vector<int32_t> SEPARATOR_POSITIONS { 8, 13, 18, 23};
48 const int64_t HALF_GB = 1024 * 1024 * 512; // 0.5GB
49 const int64_t SPACE_NEED_DOUBLE = 2;
50 const uint32_t UUID_LENGTH_MAX = 512;
51 static std::string g_deviceUdid;
52 static std::mutex g_mutex;
53 // hmdfs and sharefs config
54 constexpr const char* BUNDLE_ID_FILE = "appid";
55 // single max hap size
56 constexpr int64_t ONE_GB = 1024 * 1024 * 1024;
57 constexpr int64_t MAX_HAP_SIZE = ONE_GB * 4; // 4GB
58 constexpr const char* ABC_FILE_PATH = "abc_files";
59 constexpr const char* PGO_FILE_PATH = "pgo_files";
60 const std::string EMPTY_STRING = "";
61 constexpr int64_t DISK_REMAINING_SIZE_LIMIT = 1024 * 1024 * 10; // 10M
62 #ifdef CONFIG_POLOCY_ENABLE
63 const char* NO_DISABLING_CONFIG_PATH = "/etc/ability_runtime/resident_process_in_extreme_memory.json";
64 #endif
65 const char* NO_DISABLING_CONFIG_PATH_DEFAULT =
66 "/system/etc/ability_runtime/resident_process_in_extreme_memory.json";
67 }
68
69 std::mutex BundleUtil::g_mutex;
70
CheckFilePath(const std::string & bundlePath,std::string & realPath)71 ErrCode BundleUtil::CheckFilePath(const std::string &bundlePath, std::string &realPath)
72 {
73 if (!CheckFileName(bundlePath)) {
74 APP_LOGE("bundle file path invalid");
75 return ERR_APPEXECFWK_INSTALL_FILE_PATH_INVALID;
76 }
77 if (!CheckFileType(bundlePath, ServiceConstants::INSTALL_FILE_SUFFIX) &&
78 !CheckFileType(bundlePath, ServiceConstants::HSP_FILE_SUFFIX) &&
79 !CheckFileType(bundlePath, ServiceConstants::QUICK_FIX_FILE_SUFFIX) &&
80 !CheckFileType(bundlePath, ServiceConstants::CODE_SIGNATURE_FILE_SUFFIX)) {
81 APP_LOGE("file is not hap, hsp, hqf or sig");
82 return ERR_APPEXECFWK_INSTALL_INVALID_HAP_NAME;
83 }
84 if (!PathToRealPath(bundlePath, realPath)) {
85 APP_LOGE("file is not real path");
86 return ERR_APPEXECFWK_INSTALL_FILE_PATH_INVALID;
87 }
88 if (access(realPath.c_str(), F_OK) != 0) {
89 APP_LOGE("not access the bundle file path: %{public}s, errno:%{public}d", realPath.c_str(), errno);
90 return ERR_APPEXECFWK_INSTALL_INVALID_BUNDLE_FILE;
91 }
92 if (!CheckFileSize(realPath, MAX_HAP_SIZE)) {
93 APP_LOGE("file size larger than max hap size Max size is: %{public}" PRId64, MAX_HAP_SIZE);
94 return ERR_APPEXECFWK_INSTALL_INVALID_HAP_SIZE;
95 }
96 return ERR_OK;
97 }
98
CheckFilePath(const std::vector<std::string> & bundlePaths,std::vector<std::string> & realPaths)99 ErrCode BundleUtil::CheckFilePath(const std::vector<std::string> &bundlePaths, std::vector<std::string> &realPaths)
100 {
101 HITRACE_METER_NAME(HITRACE_TAG_APP, __PRETTY_FUNCTION__);
102 // there are three cases for bundlePaths:
103 // 1. one bundle direction in the bundlePaths, some hap files under this bundle direction.
104 // 2. one hap direction in the bundlePaths.
105 // 3. some hap file directions in the bundlePaths.
106 APP_LOGD("check file path");
107 if (bundlePaths.empty()) {
108 APP_LOGE("bundle file paths invalid");
109 return ERR_APPEXECFWK_INSTALL_FILE_PATH_INVALID;
110 }
111 ErrCode ret = ERR_OK;
112
113 if (bundlePaths.size() == 1) {
114 struct stat s;
115 std::string bundlePath = bundlePaths.front();
116 if (stat(bundlePath.c_str(), &s) == 0) {
117 std::string realPath = "";
118 // it is a direction
119 if ((s.st_mode & S_IFDIR) && !GetHapFilesFromBundlePath(bundlePath, realPaths)) {
120 APP_LOGE("GetHapFilesFromBundlePath failed with bundlePath:%{public}s", bundlePaths.front().c_str());
121 return ERR_APPEXECFWK_INSTALL_FILE_PATH_INVALID;
122 }
123 // it is a file
124 if ((s.st_mode & S_IFREG) && (ret = CheckFilePath(bundlePaths.front(), realPath)) == ERR_OK) {
125 realPaths.emplace_back(realPath);
126 }
127 return ret;
128 } else {
129 APP_LOGE("bundlePath not existed with :%{public}s", bundlePaths.front().c_str());
130 return ERR_APPEXECFWK_INSTALL_FILE_PATH_INVALID;
131 }
132 } else {
133 for (const std::string& bundlePath : bundlePaths) {
134 std::string realPath = "";
135 ret = CheckFilePath(bundlePath, realPath);
136 if (ret != ERR_OK) {
137 return ret;
138 }
139 realPaths.emplace_back(realPath);
140 }
141 }
142 APP_LOGD("finish check file path");
143 return ret;
144 }
145
CheckFileType(const std::string & fileName,const std::string & extensionName)146 bool BundleUtil::CheckFileType(const std::string &fileName, const std::string &extensionName)
147 {
148 APP_LOGD("path is %{public}s, support suffix is %{public}s", fileName.c_str(), extensionName.c_str());
149 if (!CheckFileName(fileName)) {
150 return false;
151 }
152
153 auto position = fileName.rfind('.');
154 if (position == std::string::npos) {
155 APP_LOGE("filename no extension name");
156 return false;
157 }
158
159 std::string suffixStr = fileName.substr(position);
160 return LowerStr(suffixStr) == extensionName;
161 }
162
CheckFileName(const std::string & fileName)163 bool BundleUtil::CheckFileName(const std::string &fileName)
164 {
165 if (fileName.empty()) {
166 APP_LOGE("the file name is empty");
167 return false;
168 }
169 if (fileName.size() > ServiceConstants::PATH_MAX_SIZE) {
170 APP_LOGE("bundle file path length %{public}zu too long", fileName.size());
171 return false;
172 }
173 return true;
174 }
175
CheckFileSize(const std::string & bundlePath,const int64_t fileSize)176 bool BundleUtil::CheckFileSize(const std::string &bundlePath, const int64_t fileSize)
177 {
178 APP_LOGD("fileSize is %{public}" PRId64, fileSize);
179 struct stat fileInfo = { 0 };
180 if (stat(bundlePath.c_str(), &fileInfo) != 0) {
181 APP_LOGE("call stat error:%{public}d", errno);
182 return false;
183 }
184 if (fileInfo.st_size > fileSize) {
185 return false;
186 }
187 return true;
188 }
189
CheckSystemSize(const std::string & bundlePath,const std::string & diskPath)190 bool BundleUtil::CheckSystemSize(const std::string &bundlePath, const std::string &diskPath)
191 {
192 struct statfs diskInfo = { 0 };
193 if (statfs(diskPath.c_str(), &diskInfo) != 0) {
194 APP_LOGE("call statfs error:%{public}d", errno);
195 return false;
196 }
197 int64_t freeSize = static_cast<int64_t>(diskInfo.f_bavail * diskInfo.f_bsize);
198 APP_LOGD("left free size in the disk path is %{public}" PRId64, freeSize);
199 struct stat fileInfo = { 0 };
200 if (stat(bundlePath.c_str(), &fileInfo) != 0) {
201 APP_LOGE("call stat error:%{public}d", errno);
202 return false;
203 }
204 if (std::max(fileInfo.st_size * SPACE_NEED_DOUBLE, HALF_GB) > freeSize) {
205 return false;
206 }
207 return true;
208 }
209
CheckSystemFreeSize(const std::string & path,int64_t size)210 bool BundleUtil::CheckSystemFreeSize(const std::string &path, int64_t size)
211 {
212 struct statfs diskInfo = { 0 };
213 if (statfs(path.c_str(), &diskInfo) != 0) {
214 APP_LOGE("call statfs error:%{public}d", errno);
215 return false;
216 }
217 int64_t freeSize = static_cast<int64_t>(diskInfo.f_bavail * diskInfo.f_bsize);
218 return freeSize >= size;
219 }
220
CheckSystemSizeAndHisysEvent(const std::string & path,const std::string & fileName)221 bool BundleUtil::CheckSystemSizeAndHisysEvent(const std::string &path, const std::string &fileName)
222 {
223 struct statfs diskInfo = { 0 };
224 if (statfs(path.c_str(), &diskInfo) != 0) {
225 APP_LOGE("call statfs error:%{public}d", errno);
226 return false;
227 }
228 int64_t freeSize = static_cast<int64_t>(diskInfo.f_bavail * diskInfo.f_bsize);
229 return freeSize < DISK_REMAINING_SIZE_LIMIT;
230 }
231
GetHapFilesFromBundlePath(const std::string & currentBundlePath,std::vector<std::string> & hapFileList)232 bool BundleUtil::GetHapFilesFromBundlePath(const std::string& currentBundlePath, std::vector<std::string>& hapFileList)
233 {
234 APP_LOGD("GetHapFilesFromBundlePath with path is %{public}s", currentBundlePath.c_str());
235 if (currentBundlePath.empty()) {
236 return false;
237 }
238 DIR* dir = opendir(currentBundlePath.c_str());
239 if (dir == nullptr) {
240 char errMsg[256] = {0};
241 strerror_r(errno, errMsg, sizeof(errMsg));
242 APP_LOGE("GetHapFilesFromBundlePath open bundle dir:%{public}s failed due to %{public}s, errno:%{public}d",
243 currentBundlePath.c_str(), errMsg, errno);
244 return false;
245 }
246 std::string bundlePath = currentBundlePath;
247 if (bundlePath.back() != ServiceConstants::FILE_SEPARATOR_CHAR) {
248 bundlePath.append(ServiceConstants::PATH_SEPARATOR);
249 }
250 struct dirent *entry = nullptr;
251 while ((entry = readdir(dir)) != nullptr) {
252 if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
253 continue;
254 }
255 const std::string hapFilePath = bundlePath + entry->d_name;
256 std::string realPath = "";
257 if (CheckFilePath(hapFilePath, realPath) != ERR_OK) {
258 APP_LOGE("find invalid hap path %{public}s", hapFilePath.c_str());
259 closedir(dir);
260 return false;
261 }
262 hapFileList.emplace_back(realPath);
263 APP_LOGD("find hap path %{public}s", realPath.c_str());
264
265 if (!hapFileList.empty() && (hapFileList.size() > ServiceConstants::MAX_HAP_NUMBER)) {
266 APP_LOGE("reach the max hap number 128, stop to add more");
267 closedir(dir);
268 return false;
269 }
270 }
271 closedir(dir);
272 return true;
273 }
274
GetCurrentTime()275 int64_t BundleUtil::GetCurrentTime()
276 {
277 int64_t time =
278 std::chrono::duration_cast<std::chrono::seconds>(std::chrono::system_clock::now().time_since_epoch())
279 .count();
280 APP_LOGD("the current time in seconds is %{public}" PRId64, time);
281 return time;
282 }
283
GetCurrentTimeMs()284 int64_t BundleUtil::GetCurrentTimeMs()
285 {
286 int64_t time =
287 std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch())
288 .count();
289 APP_LOGD("the current time in milliseconds is %{public}" PRId64, time);
290 return time;
291 }
292
GetCurrentTimeNs()293 int64_t BundleUtil::GetCurrentTimeNs()
294 {
295 int64_t time =
296 std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::system_clock::now().time_since_epoch())
297 .count();
298 APP_LOGD("the current time in nanoseconds is %{public}" PRId64, time);
299 return time;
300 }
301
DeviceAndNameToKey(const std::string & deviceId,const std::string & bundleName,std::string & key)302 void BundleUtil::DeviceAndNameToKey(
303 const std::string &deviceId, const std::string &bundleName, std::string &key)
304 {
305 key.append(deviceId);
306 key.append(Constants::FILE_UNDERLINE);
307 key.append(bundleName);
308 APP_LOGD("bundleName = %{public}s", bundleName.c_str());
309 }
310
KeyToDeviceAndName(const std::string & key,std::string & deviceId,std::string & bundleName)311 bool BundleUtil::KeyToDeviceAndName(
312 const std::string &key, std::string &deviceId, std::string &bundleName)
313 {
314 bool ret = false;
315 std::vector<std::string> splitStrs;
316 OHOS::SplitStr(key, Constants::FILE_UNDERLINE, splitStrs);
317 // the expect split size should be 2.
318 // key rule is <deviceId>_<bundleName>
319 if (splitStrs.size() == EXPECT_SPLIT_SIZE) {
320 deviceId = splitStrs[0];
321 bundleName = splitStrs[1];
322 ret = true;
323 }
324 APP_LOGD("bundleName = %{public}s", bundleName.c_str());
325 return ret;
326 }
327
GetUserIdByCallingUid()328 int32_t BundleUtil::GetUserIdByCallingUid()
329 {
330 int32_t uid = IPCSkeleton::GetCallingUid();
331 APP_LOGD("get calling uid(%{public}d)", uid);
332 return GetUserIdByUid(uid);
333 }
334
GetUserIdByUid(int32_t uid)335 int32_t BundleUtil::GetUserIdByUid(int32_t uid)
336 {
337 if (uid <= Constants::INVALID_UID) {
338 APP_LOGE("uid illegal: %{public}d", uid);
339 return Constants::INVALID_USERID;
340 }
341
342 return uid / Constants::BASE_USER_RANGE;
343 }
344
MakeFsConfig(const std::string & bundleName,int32_t bundleId,const std::string & configPath)345 void BundleUtil::MakeFsConfig(const std::string &bundleName, int32_t bundleId, const std::string &configPath)
346 {
347 std::string bundleDir = configPath + ServiceConstants::PATH_SEPARATOR + bundleName;
348 if (access(bundleDir.c_str(), F_OK) != 0) {
349 APP_LOGD("fail to access error:%{public}d", errno);
350 if (mkdir(bundleDir.c_str(), S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) != 0) {
351 APP_LOGE("make bundle dir error:%{public}d", errno);
352 return;
353 }
354 }
355
356 std::string realBundleDir;
357 if (!PathToRealPath(bundleDir, realBundleDir)) {
358 APP_LOGE("bundleIdFile is not real path");
359 return;
360 }
361
362 realBundleDir += (ServiceConstants::PATH_SEPARATOR + BUNDLE_ID_FILE);
363
364 int32_t bundleIdFd = open(realBundleDir.c_str(), O_WRONLY | O_TRUNC);
365 if (bundleIdFd > 0) {
366 std::string bundleIdStr = std::to_string(bundleId);
367 if (write(bundleIdFd, bundleIdStr.c_str(), bundleIdStr.size()) < 0) {
368 APP_LOGE("write bundleId error:%{public}d", errno);
369 }
370 }
371 close(bundleIdFd);
372 }
373
RemoveFsConfig(const std::string & bundleName,const std::string & configPath)374 void BundleUtil::RemoveFsConfig(const std::string &bundleName, const std::string &configPath)
375 {
376 std::string bundleDir = configPath + ServiceConstants::PATH_SEPARATOR + bundleName;
377 std::string realBundleDir;
378 if (!PathToRealPath(bundleDir, realBundleDir)) {
379 APP_LOGE("bundleDir is not real path");
380 return;
381 }
382 if (rmdir(realBundleDir.c_str()) != 0) {
383 APP_LOGE("remove hmdfs bundle dir error:%{public}d", errno);
384 }
385 }
386
CreateTempDir(const std::string & tempDir)387 std::string BundleUtil::CreateTempDir(const std::string &tempDir)
388 {
389 if (!OHOS::ForceCreateDirectory(tempDir)) {
390 APP_LOGE("mkdir %{public}s failed", tempDir.c_str());
391 return "";
392 }
393 if (chown(tempDir.c_str(), Constants::FOUNDATION_UID, ServiceConstants::BMS_GID) != 0) {
394 APP_LOGE("fail to change %{public}s ownership errno:%{public}d", tempDir.c_str(), errno);
395 return "";
396 }
397 mode_t mode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
398 if (!OHOS::ChangeModeFile(tempDir, mode)) {
399 APP_LOGE("change mode failed, temp install dir : %{public}s", tempDir.c_str());
400 return "";
401 }
402 return tempDir;
403 }
404
CreateInstallTempDir(uint32_t installerId,const DirType & type)405 std::string BundleUtil::CreateInstallTempDir(uint32_t installerId, const DirType &type)
406 {
407 std::time_t curTime = std::time(0);
408 std::string tempDir = ServiceConstants::HAP_COPY_PATH;
409 if (type == DirType::STREAM_INSTALL_DIR) {
410 tempDir += ServiceConstants::PATH_SEPARATOR + ServiceConstants::STREAM_INSTALL_PATH;
411 } else if (type == DirType::QUICK_FIX_DIR) {
412 tempDir += ServiceConstants::PATH_SEPARATOR + ServiceConstants::QUICK_FIX_PATH;
413 } else if (type == DirType::SIG_FILE_DIR) {
414 tempDir += ServiceConstants::PATH_SEPARATOR + ServiceConstants::SIGNATURE_FILE_PATH;
415 } else if (type == DirType::PGO_FILE_DIR) {
416 tempDir += ServiceConstants::PATH_SEPARATOR + PGO_FILE_PATH;
417 } else if (type == DirType::ABC_FILE_DIR) {
418 tempDir += ServiceConstants::PATH_SEPARATOR + ABC_FILE_PATH;
419 } else if (type == DirType::EXT_RESOURCE_FILE_DIR) {
420 tempDir += ServiceConstants::PATH_SEPARATOR + ServiceConstants::EXT_RESOURCE_FILE_PATH;
421 } else {
422 return "";
423 }
424
425 if (CreateTempDir(tempDir).empty()) {
426 APP_LOGE("create tempDir failed");
427 return "";
428 }
429
430 tempDir += ServiceConstants::PATH_SEPARATOR + std::to_string(curTime) +
431 std::to_string(installerId) + ServiceConstants::PATH_SEPARATOR;
432 return CreateTempDir(tempDir);
433 }
434
CreateSharedBundleTempDir(uint32_t installerId,uint32_t index)435 std::string BundleUtil::CreateSharedBundleTempDir(uint32_t installerId, uint32_t index)
436 {
437 std::time_t curTime = std::time(0);
438 std::string tempDir = ServiceConstants::HAP_COPY_PATH;
439 tempDir += ServiceConstants::PATH_SEPARATOR + ServiceConstants::STREAM_INSTALL_PATH;
440 tempDir += ServiceConstants::PATH_SEPARATOR + std::to_string(curTime) + std::to_string(installerId)
441 + Constants::FILE_UNDERLINE + std::to_string(index)+ ServiceConstants::PATH_SEPARATOR;
442 return CreateTempDir(tempDir);
443 }
444
CreateFileDescriptor(const std::string & bundlePath,long long offset)445 int32_t BundleUtil::CreateFileDescriptor(const std::string &bundlePath, long long offset)
446 {
447 int fd = -1;
448 if (bundlePath.length() > ServiceConstants::PATH_MAX_SIZE) {
449 APP_LOGE("the length of the bundlePath exceeds maximum limitation");
450 return fd;
451 }
452 if ((fd = open(bundlePath.c_str(), O_CREAT | O_RDWR, S_IRUSR | S_IWUSR)) < 0) {
453 APP_LOGE("open bundlePath %{public}s failed errno:%{public}d", bundlePath.c_str(), errno);
454 return fd;
455 }
456 if (offset > 0) {
457 lseek(fd, offset, SEEK_SET);
458 }
459 return fd;
460 }
461
CreateFileDescriptorForReadOnly(const std::string & bundlePath,long long offset)462 int32_t BundleUtil::CreateFileDescriptorForReadOnly(const std::string &bundlePath, long long offset)
463 {
464 int fd = -1;
465 if (bundlePath.length() > ServiceConstants::PATH_MAX_SIZE) {
466 APP_LOGE("the length of the bundlePath exceeds maximum limitation");
467 return fd;
468 }
469 std::string realPath;
470 if (!PathToRealPath(bundlePath, realPath)) {
471 APP_LOGE("file is not real path");
472 return fd;
473 }
474
475 if ((fd = open(realPath.c_str(), O_RDONLY)) < 0) {
476 APP_LOGE("open bundlePath %{public}s failed errno:%{public}d", realPath.c_str(), errno);
477 return fd;
478 }
479 if (offset > 0) {
480 lseek(fd, offset, SEEK_SET);
481 }
482 return fd;
483 }
484
CloseFileDescriptor(std::vector<int32_t> & fdVec)485 void BundleUtil::CloseFileDescriptor(std::vector<int32_t> &fdVec)
486 {
487 for_each(fdVec.begin(), fdVec.end(), [](const auto &fd) {
488 if (fd > 0) {
489 close(fd);
490 }
491 });
492 fdVec.clear();
493 }
494
IsExistFile(const std::string & path)495 bool BundleUtil::IsExistFile(const std::string &path)
496 {
497 if (path.empty()) {
498 return false;
499 }
500
501 struct stat buf = {};
502 if (stat(path.c_str(), &buf) != 0) {
503 APP_LOGE("fail stat errno:%{public}d", errno);
504 return false;
505 }
506
507 return S_ISREG(buf.st_mode);
508 }
509
IsExistFileNoLog(const std::string & path)510 bool BundleUtil::IsExistFileNoLog(const std::string &path)
511 {
512 if (path.empty()) {
513 return false;
514 }
515
516 struct stat buf = {};
517 if (stat(path.c_str(), &buf) != 0) {
518 return false;
519 }
520
521 return S_ISREG(buf.st_mode);
522 }
523
IsExistDir(const std::string & path)524 bool BundleUtil::IsExistDir(const std::string &path)
525 {
526 if (path.empty()) {
527 return false;
528 }
529
530 struct stat buf = {};
531 if (stat(path.c_str(), &buf) != 0) {
532 APP_LOGE("fail stat errno:%{public}d", errno);
533 return false;
534 }
535
536 return S_ISDIR(buf.st_mode);
537 }
538
IsExistDirNoLog(const std::string & path)539 bool BundleUtil::IsExistDirNoLog(const std::string &path)
540 {
541 if (path.empty()) {
542 return false;
543 }
544
545 struct stat buf = {};
546 if (stat(path.c_str(), &buf) != 0) {
547 return false;
548 }
549
550 return S_ISDIR(buf.st_mode);
551 }
552
CalculateFileSize(const std::string & bundlePath)553 int64_t BundleUtil::CalculateFileSize(const std::string &bundlePath)
554 {
555 struct stat fileInfo = { 0 };
556 if (stat(bundlePath.c_str(), &fileInfo) != 0) {
557 APP_LOGE("call stat error:%{public}d", errno);
558 return 0;
559 }
560
561 return static_cast<int64_t>(fileInfo.st_size);
562 }
563
RenameFile(const std::string & oldPath,const std::string & newPath)564 bool BundleUtil::RenameFile(const std::string &oldPath, const std::string &newPath)
565 {
566 if (oldPath.empty() || newPath.empty()) {
567 APP_LOGE("oldPath or newPath is empty");
568 return false;
569 }
570
571 if (!DeleteDir(newPath)) {
572 APP_LOGE("delete newPath failed");
573 return false;
574 }
575
576 return rename(oldPath.c_str(), newPath.c_str()) == 0;
577 }
578
DeleteDir(const std::string & path)579 bool BundleUtil::DeleteDir(const std::string &path)
580 {
581 if (IsExistFile(path)) {
582 return OHOS::RemoveFile(path);
583 }
584
585 if (IsExistDir(path)) {
586 return OHOS::ForceRemoveDirectory(path);
587 }
588
589 return true;
590 }
591
IsUtd(const std::string & param)592 bool BundleUtil::IsUtd(const std::string ¶m)
593 {
594 #ifdef BUNDLE_FRAMEWORK_UDMF_ENABLED
595 bool isUtd = false;
596 auto ret = UDMF::UtdClient::GetInstance().IsUtd(param, isUtd);
597 return ret == ERR_OK && isUtd;
598 #else
599 return false;
600 #endif
601 }
602
IsSpecificUtd(const std::string & param)603 bool BundleUtil::IsSpecificUtd(const std::string ¶m)
604 {
605 if (!IsUtd(param)) {
606 return false;
607 }
608 #ifdef BUNDLE_FRAMEWORK_UDMF_ENABLED
609 std::shared_ptr<UDMF::TypeDescriptor> typeDescriptor;
610 auto ret = UDMF::UtdClient::GetInstance().GetTypeDescriptor(param, typeDescriptor);
611 if (ret != ERR_OK || typeDescriptor == nullptr) {
612 return false;
613 }
614 std::vector<std::string> mimeTypes = typeDescriptor->GetMimeTypes();
615 std::vector<std::string> filenameExtensions = typeDescriptor->GetFilenameExtensions();
616 return !mimeTypes.empty() || !filenameExtensions.empty();
617 #else
618 return false;
619 #endif
620 }
621
GetUtdVectorByMimeType(const std::string & mimeType)622 std::vector<std::string> BundleUtil::GetUtdVectorByMimeType(const std::string &mimeType)
623 {
624 #ifdef BUNDLE_FRAMEWORK_UDMF_ENABLED
625 std::vector<std::string> utdVector;
626 auto ret = UDMF::UtdClient::GetInstance().GetUniformDataTypesByMIMEType(mimeType, utdVector);
627 if (ret != ERR_OK || utdVector.empty()) {
628 return {};
629 }
630 return utdVector;
631 #else
632 return {};
633 #endif
634 }
635
GetBoolStrVal(bool val)636 std::string BundleUtil::GetBoolStrVal(bool val)
637 {
638 return val ? "true" : "false";
639 }
640
CopyFile(const std::string & sourceFile,const std::string & destinationFile)641 bool BundleUtil::CopyFile(
642 const std::string &sourceFile, const std::string &destinationFile)
643 {
644 if (sourceFile.empty() || destinationFile.empty()) {
645 APP_LOGE("Copy file failed due to sourceFile or destinationFile is empty");
646 return false;
647 }
648
649 std::ifstream in(sourceFile);
650 if (!in.is_open()) {
651 APP_LOGE("Copy file failed due to open sourceFile failed errno:%{public}d", errno);
652 return false;
653 }
654
655 std::ofstream out(destinationFile);
656 if (!out.is_open()) {
657 APP_LOGE("Copy file failed due to open destinationFile failed errno:%{public}d", errno);
658 in.close();
659 return false;
660 }
661
662 out << in.rdbuf();
663 in.close();
664 out.close();
665 return true;
666 }
667
CopyFileFast(const std::string & sourcePath,const std::string & destPath)668 bool BundleUtil::CopyFileFast(const std::string &sourcePath, const std::string &destPath)
669 {
670 APP_LOGI("sourcePath : %{public}s, destPath : %{public}s", sourcePath.c_str(), destPath.c_str());
671 if (sourcePath.empty() || destPath.empty()) {
672 APP_LOGE("invalid path");
673 return false;
674 }
675
676 int32_t sourceFd = open(sourcePath.c_str(), O_RDONLY);
677 if (sourceFd == -1) {
678 APP_LOGE("sourcePath open failed, errno : %{public}d", errno);
679 return CopyFile(sourcePath, destPath);
680 }
681
682 struct stat sourceStat;
683 if (fstat(sourceFd, &sourceStat) == -1) {
684 APP_LOGE("fstat failed, errno : %{public}d", errno);
685 close(sourceFd);
686 return CopyFile(sourcePath, destPath);
687 }
688 if (sourceStat.st_size < 0) {
689 APP_LOGE("invalid st_size");
690 close(sourceFd);
691 return CopyFile(sourcePath, destPath);
692 }
693
694 int32_t destFd = open(
695 destPath.c_str(), O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
696 if (destFd == -1) {
697 APP_LOGE("destPath open failed, errno : %{public}d", errno);
698 close(sourceFd);
699 return CopyFile(sourcePath, destPath);
700 }
701
702 size_t buffer = 524288; // 0.5M
703 size_t transferCount = 0;
704 ssize_t singleTransfer = 0;
705 while ((singleTransfer = sendfile(destFd, sourceFd, nullptr, buffer)) > 0) {
706 transferCount += static_cast<size_t>(singleTransfer);
707 }
708
709 if (singleTransfer == -1 || transferCount != static_cast<size_t>(sourceStat.st_size)) {
710 APP_LOGE("sendfile failed, errno : %{public}d, send count : %{public}zu , file size : %{public}zu",
711 errno, transferCount, static_cast<size_t>(sourceStat.st_size));
712 close(sourceFd);
713 close(destFd);
714 return CopyFile(sourcePath, destPath);
715 }
716
717 close(sourceFd);
718 close(destFd);
719 APP_LOGD("sendfile success");
720 return true;
721 }
722
GetResource(const std::string & bundleName,const std::string & moduleName,uint32_t resId)723 Resource BundleUtil::GetResource(const std::string &bundleName, const std::string &moduleName, uint32_t resId)
724 {
725 Resource resource;
726 resource.bundleName = bundleName;
727 resource.moduleName = moduleName;
728 resource.id = resId;
729 return resource;
730 }
731
CreateDir(const std::string & dir)732 bool BundleUtil::CreateDir(const std::string &dir)
733 {
734 if (dir.empty()) {
735 APP_LOGE("path is empty");
736 return false;
737 }
738
739 if (IsExistFile(dir)) {
740 return true;
741 }
742
743 if (!OHOS::ForceCreateDirectory(dir)) {
744 APP_LOGE("mkdir %{public}s failed", dir.c_str());
745 return false;
746 }
747
748 if (chown(dir.c_str(), Constants::FOUNDATION_UID, ServiceConstants::BMS_GID) != 0) {
749 APP_LOGE("fail change %{public}s ownership, errno:%{public}d", dir.c_str(), errno);
750 return false;
751 }
752
753 mode_t mode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
754 if (!OHOS::ChangeModeFile(dir, mode)) {
755 APP_LOGE("change mode failed, temp install dir : %{public}s", dir.c_str());
756 return false;
757 }
758 return true;
759 }
760
RevertToRealPath(const std::string & sandBoxPath,const std::string & bundleName,std::string & realPath)761 bool BundleUtil::RevertToRealPath(const std::string &sandBoxPath, const std::string &bundleName, std::string &realPath)
762 {
763 if (sandBoxPath.empty() || bundleName.empty() ||
764 sandBoxPath.find(ServiceConstants::SANDBOX_DATA_PATH) == std::string::npos) {
765 APP_LOGE("input sandboxPath or bundleName invalid");
766 return false;
767 }
768
769 realPath = sandBoxPath;
770 std::string relaDataPath = ServiceConstants::REAL_DATA_PATH + ServiceConstants::PATH_SEPARATOR
771 + std::to_string(BundleUtil::GetUserIdByCallingUid()) + ServiceConstants::BASE + bundleName;
772 realPath.replace(realPath.find(ServiceConstants::SANDBOX_DATA_PATH),
773 std::string(ServiceConstants::SANDBOX_DATA_PATH).size(), relaDataPath);
774 return true;
775 }
776
StartWith(const std::string & source,const std::string & prefix)777 bool BundleUtil::StartWith(const std::string &source, const std::string &prefix)
778 {
779 if (source.empty() || prefix.empty()) {
780 return false;
781 }
782
783 return source.find(prefix) == 0;
784 }
785
EndWith(const std::string & source,const std::string & suffix)786 bool BundleUtil::EndWith(const std::string &source, const std::string &suffix)
787 {
788 if (source.empty() || suffix.empty()) {
789 return false;
790 }
791
792 auto position = source.rfind(suffix);
793 if (position == std::string::npos) {
794 return false;
795 }
796
797 std::string suffixStr = source.substr(position);
798 return suffixStr == suffix;
799 }
800
GetFileSize(const std::string & filePath)801 int64_t BundleUtil::GetFileSize(const std::string &filePath)
802 {
803 struct stat fileInfo = { 0 };
804 if (stat(filePath.c_str(), &fileInfo) != 0) {
805 APP_LOGE("call stat error:%{public}d", errno);
806 return 0;
807 }
808 return fileInfo.st_size;
809 }
810
CopyFileToSecurityDir(const std::string & filePath,const DirType & dirType,std::vector<std::string> & toDeletePaths)811 std::string BundleUtil::CopyFileToSecurityDir(const std::string &filePath, const DirType &dirType,
812 std::vector<std::string> &toDeletePaths)
813 {
814 APP_LOGD("the original dir is %{public}s", filePath.c_str());
815 std::string destination = "";
816 std::string subStr = "";
817 destination.append(ServiceConstants::HAP_COPY_PATH).append(ServiceConstants::PATH_SEPARATOR);
818 if (dirType == DirType::STREAM_INSTALL_DIR) {
819 subStr = ServiceConstants::STREAM_INSTALL_PATH;
820 destination.append(ServiceConstants::SECURITY_STREAM_INSTALL_PATH);
821 mode_t mode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
822 if (InstalldClient::GetInstance()->Mkdir(
823 destination, mode, Constants::FOUNDATION_UID, ServiceConstants::BMS_GID) != ERR_OK) {
824 APP_LOGW("installd mkdir %{private}s failed", destination.c_str());
825 }
826 }
827 if (dirType == DirType::SIG_FILE_DIR) {
828 subStr = ServiceConstants::SIGNATURE_FILE_PATH;
829 destination.append(ServiceConstants::SECURITY_SIGNATURE_FILE_PATH);
830 }
831 destination.append(ServiceConstants::PATH_SEPARATOR).append(std::to_string(GetCurrentTimeNs()));
832 destination = CreateTempDir(destination);
833 auto pos = filePath.find(subStr);
834 if (pos == std::string::npos) { // this circumstance could not be considered laterly
835 auto lastPathSeperator = filePath.rfind(ServiceConstants::PATH_SEPARATOR);
836 if ((lastPathSeperator != std::string::npos) && (lastPathSeperator != filePath.length() - 1)) {
837 toDeletePaths.emplace_back(destination);
838 destination.append(filePath.substr(lastPathSeperator));
839 }
840 } else {
841 auto secondLastPathSep = filePath.find(ServiceConstants::PATH_SEPARATOR, pos);
842 if ((secondLastPathSep == std::string::npos) || (secondLastPathSep == filePath.length() - 1)) {
843 return "";
844 }
845 auto thirdLastPathSep =
846 filePath.find(ServiceConstants::PATH_SEPARATOR, secondLastPathSep + 1);
847 if ((thirdLastPathSep == std::string::npos) || (thirdLastPathSep == filePath.length() - 1)) {
848 return "";
849 }
850 toDeletePaths.emplace_back(destination);
851 std::string innerSubstr =
852 filePath.substr(secondLastPathSep, thirdLastPathSep - secondLastPathSep + 1);
853 destination = CreateTempDir(destination.append(innerSubstr));
854 destination.append(filePath.substr(thirdLastPathSep + 1));
855 }
856 APP_LOGD("the destination dir is %{public}s", destination.c_str());
857 if (destination.empty()) {
858 return "";
859 }
860 if (!CopyFileFast(filePath, destination)) {
861 APP_LOGE("copy file from %{public}s to %{public}s failed", filePath.c_str(), destination.c_str());
862 return "";
863 }
864 return destination;
865 }
866
DeleteTempDirs(const std::vector<std::string> & tempDirs)867 void BundleUtil::DeleteTempDirs(const std::vector<std::string> &tempDirs)
868 {
869 for (const auto &tempDir : tempDirs) {
870 APP_LOGD("the temp hap dir %{public}s needs to be deleted", tempDir.c_str());
871 BundleUtil::DeleteDir(tempDir);
872 }
873 }
874
GetHexHash(const std::string & s)875 std::string BundleUtil::GetHexHash(const std::string &s)
876 {
877 std::hash<std::string> hasher;
878 size_t hash = hasher(s);
879
880 std::stringstream ss;
881 ss << std::hex << hash;
882
883 std::string hash_str = ss.str();
884 return hash_str;
885 }
886
RecursiveHash(std::string & s)887 void BundleUtil::RecursiveHash(std::string& s)
888 {
889 if (s.size() >= ORIGIN_STRING_LENGTH) {
890 s = s.substr(s.size() - ORIGIN_STRING_LENGTH);
891 return;
892 }
893 std::string hash = GetHexHash(s);
894 s += hash;
895 RecursiveHash(s);
896 }
897
GenerateUuid()898 std::string BundleUtil::GenerateUuid()
899 {
900 std::lock_guard<std::mutex> lock(g_mutex);
901 auto currentTime = std::chrono::system_clock::now();
902 auto timestampNanoseconds =
903 std::chrono::duration_cast<std::chrono::nanoseconds>(currentTime.time_since_epoch()).count();
904
905 // convert nanosecond timestamps to string
906 std::string s = std::to_string(timestampNanoseconds);
907 std::string timeStr = GetHexHash(s);
908
909 char deviceId[UUID_LENGTH_MAX] = { 0 };
910 auto ret = GetDevUdid(deviceId, UUID_LENGTH_MAX);
911 std::string deviceUdid;
912 std::string deviceStr;
913 if (ret != 0) {
914 APP_LOGW("GetDevUdid failed");
915 } else {
916 deviceUdid = std::string{ deviceId };
917 deviceStr = GetHexHash(deviceUdid);
918 }
919
920 std::string uuid = timeStr + deviceStr;
921 RecursiveHash(uuid);
922
923 for (int32_t index : SEPARATOR_POSITIONS) {
924 uuid.insert(index, 1, UUID_SEPARATOR);
925 }
926 return uuid;
927 }
928
GenerateUuidByKey(const std::string & key)929 std::string BundleUtil::GenerateUuidByKey(const std::string &key)
930 {
931 std::string keyHash = GetHexHash(key);
932
933 char deviceId[UUID_LENGTH_MAX] = { 0 };
934 auto ret = GetDevUdid(deviceId, UUID_LENGTH_MAX);
935 std::string deviceUdid;
936 std::string deviceStr;
937 if (ret != 0) {
938 APP_LOGW("GetDevUdid failed");
939 } else {
940 deviceUdid = std::string{ deviceId };
941 deviceStr = GetHexHash(deviceUdid);
942 }
943
944 std::string uuid = keyHash + deviceStr;
945 RecursiveHash(uuid);
946
947 for (int32_t index : SEPARATOR_POSITIONS) {
948 uuid.insert(index, 1, UUID_SEPARATOR);
949 }
950 return uuid;
951 }
952
ExtractGroupIdByDevelopId(const std::string & developerId)953 std::string BundleUtil::ExtractGroupIdByDevelopId(const std::string &developerId)
954 {
955 std::string::size_type dot_position = developerId.find('.');
956 if (dot_position == std::string::npos) {
957 // If cannot find '.' , the input string is developerId, return developerId
958 return developerId;
959 }
960 if (dot_position == 0) {
961 // if'.' In the first place, then groupId is empty, return developerId
962 return developerId.substr(1);
963 }
964 // If '.' If it is not the first place, there is a groupId, and the groupId is returned
965 return developerId.substr(0, dot_position);
966 }
967
ToString(const std::vector<std::string> & vector)968 std::string BundleUtil::ToString(const std::vector<std::string> &vector)
969 {
970 std::string ret;
971 for (const std::string &item : vector) {
972 ret.append(item).append(",");
973 }
974 return ret;
975 }
976
GetNoDisablingConfigPath()977 std::string BundleUtil::GetNoDisablingConfigPath()
978 {
979 #ifdef CONFIG_POLOCY_ENABLE
980 char buf[MAX_PATH_LEN] = { 0 };
981 char *configPath = GetOneCfgFile(NO_DISABLING_CONFIG_PATH, buf, MAX_PATH_LEN);
982 if (configPath == nullptr || configPath[0] == '\0' || strlen(configPath) > MAX_PATH_LEN) {
983 return NO_DISABLING_CONFIG_PATH_DEFAULT;
984 }
985 return configPath;
986 #else
987 return NO_DISABLING_CONFIG_PATH_DEFAULT;
988 #endif
989 }
990 } // namespace AppExecFwk
991 } // namespace OHOS
992