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 errno %{public}d", bundlePaths.front().c_str(), errno);
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  
IsPathInformationConsistent(const std::string & path,int32_t uid,int32_t gid)553  bool BundleUtil::IsPathInformationConsistent(const std::string &path, int32_t uid, int32_t gid)
554  {
555      if (path.empty()) {
556          return false;
557      }
558      struct stat buf = {};
559      if (stat(path.c_str(), &buf) != 0) {
560          return false;
561      }
562      if ((static_cast<int32_t>(buf.st_uid) != uid) || ((static_cast<int32_t>(buf.st_gid) != gid))) {
563          APP_LOGE("path uid or gid is not same");
564          return false;
565      }
566      return true;
567  }
568  
CalculateFileSize(const std::string & bundlePath)569  int64_t BundleUtil::CalculateFileSize(const std::string &bundlePath)
570  {
571      struct stat fileInfo = { 0 };
572      if (stat(bundlePath.c_str(), &fileInfo) != 0) {
573          APP_LOGE("call stat error:%{public}d", errno);
574          return 0;
575      }
576  
577      return static_cast<int64_t>(fileInfo.st_size);
578  }
579  
RenameFile(const std::string & oldPath,const std::string & newPath)580  bool BundleUtil::RenameFile(const std::string &oldPath, const std::string &newPath)
581  {
582      if (oldPath.empty() || newPath.empty()) {
583          APP_LOGE("oldPath or newPath is empty");
584          return false;
585      }
586  
587      if (!DeleteDir(newPath)) {
588          APP_LOGE("delete newPath failed");
589          return false;
590      }
591  
592      return rename(oldPath.c_str(), newPath.c_str()) == 0;
593  }
594  
DeleteDir(const std::string & path)595  bool BundleUtil::DeleteDir(const std::string &path)
596  {
597      if (IsExistFile(path)) {
598          return OHOS::RemoveFile(path);
599      }
600  
601      if (IsExistDir(path)) {
602          return OHOS::ForceRemoveDirectory(path);
603      }
604  
605      return true;
606  }
607  
IsUtd(const std::string & param)608  bool BundleUtil::IsUtd(const std::string &param)
609  {
610  #ifdef BUNDLE_FRAMEWORK_UDMF_ENABLED
611      bool isUtd = false;
612      auto ret = UDMF::UtdClient::GetInstance().IsUtd(param, isUtd);
613      return ret == ERR_OK && isUtd;
614  #else
615      return false;
616  #endif
617  }
618  
IsSpecificUtd(const std::string & param)619  bool BundleUtil::IsSpecificUtd(const std::string &param)
620  {
621      if (!IsUtd(param)) {
622          return false;
623      }
624  #ifdef BUNDLE_FRAMEWORK_UDMF_ENABLED
625      std::shared_ptr<UDMF::TypeDescriptor> typeDescriptor;
626      auto ret = UDMF::UtdClient::GetInstance().GetTypeDescriptor(param, typeDescriptor);
627      if (ret != ERR_OK || typeDescriptor == nullptr) {
628          return false;
629      }
630      std::vector<std::string> mimeTypes = typeDescriptor->GetMimeTypes();
631      std::vector<std::string> filenameExtensions = typeDescriptor->GetFilenameExtensions();
632      return !mimeTypes.empty() || !filenameExtensions.empty();
633  #else
634      return false;
635  #endif
636  }
637  
GetUtdVectorByMimeType(const std::string & mimeType)638  std::vector<std::string> BundleUtil::GetUtdVectorByMimeType(const std::string &mimeType)
639  {
640  #ifdef BUNDLE_FRAMEWORK_UDMF_ENABLED
641      std::vector<std::string> utdVector;
642      auto ret = UDMF::UtdClient::GetInstance().GetUniformDataTypesByMIMEType(mimeType, utdVector);
643      if (ret != ERR_OK || utdVector.empty()) {
644          return {};
645      }
646      return utdVector;
647  #else
648      return {};
649  #endif
650  }
651  
GetBoolStrVal(bool val)652  std::string BundleUtil::GetBoolStrVal(bool val)
653  {
654      return val ? "true" : "false";
655  }
656  
CopyFile(const std::string & sourceFile,const std::string & destinationFile)657  bool BundleUtil::CopyFile(
658      const std::string &sourceFile, const std::string &destinationFile)
659  {
660      if (sourceFile.empty() || destinationFile.empty()) {
661          APP_LOGE("Copy file failed due to sourceFile or destinationFile is empty");
662          return false;
663      }
664  
665      std::ifstream in(sourceFile);
666      if (!in.is_open()) {
667          APP_LOGE("Copy file failed due to open sourceFile failed errno:%{public}d", errno);
668          return false;
669      }
670  
671      std::ofstream out(destinationFile);
672      if (!out.is_open()) {
673          APP_LOGE("Copy file failed due to open destinationFile failed errno:%{public}d", errno);
674          in.close();
675          return false;
676      }
677  
678      out << in.rdbuf();
679      in.close();
680      out.close();
681      return true;
682  }
683  
CopyFileFast(const std::string & sourcePath,const std::string & destPath)684  bool BundleUtil::CopyFileFast(const std::string &sourcePath, const std::string &destPath)
685  {
686      APP_LOGI("sourcePath : %{public}s, destPath : %{public}s", sourcePath.c_str(), destPath.c_str());
687      if (sourcePath.empty() || destPath.empty()) {
688          APP_LOGE("invalid path");
689          return false;
690      }
691  
692      int32_t sourceFd = open(sourcePath.c_str(), O_RDONLY);
693      if (sourceFd == -1) {
694          APP_LOGE("sourcePath open failed, errno : %{public}d", errno);
695          return CopyFile(sourcePath, destPath);
696      }
697  
698      struct stat sourceStat;
699      if (fstat(sourceFd, &sourceStat) == -1) {
700          APP_LOGE("fstat failed, errno : %{public}d", errno);
701          close(sourceFd);
702          return CopyFile(sourcePath, destPath);
703      }
704      if (sourceStat.st_size < 0) {
705          APP_LOGE("invalid st_size");
706          close(sourceFd);
707          return CopyFile(sourcePath, destPath);
708      }
709  
710      int32_t destFd = open(
711          destPath.c_str(), O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
712      if (destFd == -1) {
713          APP_LOGE("destPath open failed, errno : %{public}d", errno);
714          close(sourceFd);
715          return CopyFile(sourcePath, destPath);
716      }
717  
718      size_t buffer = 524288; // 0.5M
719      size_t transferCount = 0;
720      ssize_t singleTransfer = 0;
721      while ((singleTransfer = sendfile(destFd, sourceFd, nullptr, buffer)) > 0) {
722          transferCount += static_cast<size_t>(singleTransfer);
723      }
724  
725      if (singleTransfer == -1 || transferCount != static_cast<size_t>(sourceStat.st_size)) {
726          APP_LOGE("sendfile failed, errno : %{public}d, send count : %{public}zu , file size : %{public}zu",
727              errno, transferCount, static_cast<size_t>(sourceStat.st_size));
728          close(sourceFd);
729          close(destFd);
730          return CopyFile(sourcePath, destPath);
731      }
732  
733      close(sourceFd);
734      close(destFd);
735      APP_LOGD("sendfile success");
736      return true;
737  }
738  
GetResource(const std::string & bundleName,const std::string & moduleName,uint32_t resId)739  Resource BundleUtil::GetResource(const std::string &bundleName, const std::string &moduleName, uint32_t resId)
740  {
741      Resource resource;
742      resource.bundleName = bundleName;
743      resource.moduleName = moduleName;
744      resource.id = resId;
745      return resource;
746  }
747  
CreateDir(const std::string & dir)748  bool BundleUtil::CreateDir(const std::string &dir)
749  {
750      if (dir.empty()) {
751          APP_LOGE("path is empty");
752          return false;
753      }
754  
755      if (IsExistFile(dir)) {
756          return true;
757      }
758  
759      if (!OHOS::ForceCreateDirectory(dir)) {
760          APP_LOGE("mkdir %{public}s failed", dir.c_str());
761          return false;
762      }
763  
764      if (chown(dir.c_str(), Constants::FOUNDATION_UID, ServiceConstants::BMS_GID) != 0) {
765          APP_LOGE("fail change %{public}s ownership, errno:%{public}d", dir.c_str(), errno);
766          return false;
767      }
768  
769      mode_t mode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
770      if (!OHOS::ChangeModeFile(dir, mode)) {
771          APP_LOGE("change mode failed, temp install dir : %{public}s", dir.c_str());
772          return false;
773      }
774      return true;
775  }
776  
RevertToRealPath(const std::string & sandBoxPath,const std::string & bundleName,std::string & realPath)777  bool BundleUtil::RevertToRealPath(const std::string &sandBoxPath, const std::string &bundleName, std::string &realPath)
778  {
779      if (sandBoxPath.empty() || bundleName.empty() ||
780          (sandBoxPath.find(ServiceConstants::SANDBOX_DATA_PATH) == std::string::npos &&
781          sandBoxPath.find(ServiceConstants::APP_INSTALL_SANDBOX_PATH) == std::string::npos)) {
782          APP_LOGE("input sandboxPath or bundleName invalid");
783          return false;
784      }
785  
786      realPath = sandBoxPath;
787      if (sandBoxPath.find(ServiceConstants::SANDBOX_DATA_PATH) == 0) {
788          std::string relaDataPath = std::string(ServiceConstants::REAL_DATA_PATH) + ServiceConstants::PATH_SEPARATOR
789              + std::to_string(BundleUtil::GetUserIdByCallingUid()) + ServiceConstants::BASE + bundleName;
790          realPath.replace(realPath.find(ServiceConstants::SANDBOX_DATA_PATH),
791              std::string(ServiceConstants::SANDBOX_DATA_PATH).size(), relaDataPath);
792      } else if (sandBoxPath.find(ServiceConstants::APP_INSTALL_SANDBOX_PATH) == 0) {
793          std::string relaDataPath = std::string(ServiceConstants::BUNDLE_MANAGER_SERVICE_PATH) +
794              ServiceConstants::GALLERY_DOWNLOAD_PATH + std::to_string(BundleUtil::GetUserIdByCallingUid());
795          realPath.replace(realPath.find(ServiceConstants::APP_INSTALL_SANDBOX_PATH),
796              std::string(ServiceConstants::APP_INSTALL_SANDBOX_PATH).size(), relaDataPath);
797      } else {
798          APP_LOGE("input sandboxPath invalid");
799          return false;
800      }
801      return true;
802  }
803  
StartWith(const std::string & source,const std::string & prefix)804  bool BundleUtil::StartWith(const std::string &source, const std::string &prefix)
805  {
806      if (source.empty() || prefix.empty()) {
807          return false;
808      }
809  
810      return source.find(prefix) == 0;
811  }
812  
EndWith(const std::string & source,const std::string & suffix)813  bool BundleUtil::EndWith(const std::string &source, const std::string &suffix)
814  {
815      if (source.empty() || suffix.empty()) {
816          return false;
817      }
818  
819      auto position = source.rfind(suffix);
820      if (position == std::string::npos) {
821          return false;
822      }
823  
824      std::string suffixStr = source.substr(position);
825      return suffixStr == suffix;
826  }
827  
GetFileSize(const std::string & filePath)828  int64_t BundleUtil::GetFileSize(const std::string &filePath)
829  {
830      struct stat fileInfo = { 0 };
831      if (stat(filePath.c_str(), &fileInfo) != 0) {
832          APP_LOGE("call stat error:%{public}d", errno);
833          return 0;
834      }
835      return fileInfo.st_size;
836  }
837  
CopyFileToSecurityDir(const std::string & filePath,const DirType & dirType,std::vector<std::string> & toDeletePaths,bool rename)838  std::string BundleUtil::CopyFileToSecurityDir(const std::string &filePath, const DirType &dirType,
839      std::vector<std::string> &toDeletePaths, bool rename)
840  {
841      APP_LOGD("the original dir is %{public}s", filePath.c_str());
842      std::string destination = "";
843      std::string subStr = "";
844      destination.append(ServiceConstants::HAP_COPY_PATH).append(ServiceConstants::PATH_SEPARATOR);
845      if (dirType == DirType::STREAM_INSTALL_DIR) {
846          subStr = ServiceConstants::STREAM_INSTALL_PATH;
847          destination.append(ServiceConstants::SECURITY_STREAM_INSTALL_PATH);
848          mode_t mode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
849          if (InstalldClient::GetInstance()->Mkdir(
850              destination, mode, Constants::FOUNDATION_UID, ServiceConstants::BMS_GID) != ERR_OK) {
851              APP_LOGW("installd mkdir %{private}s failed", destination.c_str());
852          }
853      }
854      if (dirType == DirType::SIG_FILE_DIR) {
855          subStr = ServiceConstants::SIGNATURE_FILE_PATH;
856          destination.append(ServiceConstants::SECURITY_SIGNATURE_FILE_PATH);
857      }
858      destination.append(ServiceConstants::PATH_SEPARATOR).append(std::to_string(GetCurrentTimeNs()));
859      destination = CreateTempDir(destination);
860      auto pos = filePath.find(subStr);
861      if (pos == std::string::npos) { // this circumstance could not be considered laterly
862          auto lastPathSeperator = filePath.rfind(ServiceConstants::PATH_SEPARATOR);
863          if ((lastPathSeperator != std::string::npos) && (lastPathSeperator != filePath.length() - 1)) {
864              toDeletePaths.emplace_back(destination);
865              destination.append(filePath.substr(lastPathSeperator));
866          }
867      } else {
868          auto secondLastPathSep = filePath.find(ServiceConstants::PATH_SEPARATOR, pos);
869          if ((secondLastPathSep == std::string::npos) || (secondLastPathSep == filePath.length() - 1)) {
870              return "";
871          }
872          auto thirdLastPathSep =
873              filePath.find(ServiceConstants::PATH_SEPARATOR, secondLastPathSep + 1);
874          if ((thirdLastPathSep == std::string::npos) || (thirdLastPathSep == filePath.length() - 1)) {
875              return "";
876          }
877          toDeletePaths.emplace_back(destination);
878          std::string innerSubstr =
879              filePath.substr(secondLastPathSep, thirdLastPathSep - secondLastPathSep + 1);
880          destination = CreateTempDir(destination.append(innerSubstr));
881          destination.append(filePath.substr(thirdLastPathSep + 1));
882      }
883      APP_LOGD("the destination dir is %{public}s", destination.c_str());
884      if (destination.empty()) {
885          return "";
886      }
887      if (rename) {
888          APP_LOGD("rename file from %{public}s to %{public}s", filePath.c_str(), destination.c_str());
889          if (!RenameFile(filePath, destination)) {
890              APP_LOGE("rename file from %{public}s to %{public}s failed", filePath.c_str(), destination.c_str());
891              return "";
892          }
893      } else {
894          if (!CopyFileFast(filePath, destination)) {
895              APP_LOGE("copy file from %{public}s to %{public}s failed", filePath.c_str(), destination.c_str());
896              return "";
897          }
898      }
899      return destination;
900  }
901  
DeleteTempDirs(const std::vector<std::string> & tempDirs)902  void BundleUtil::DeleteTempDirs(const std::vector<std::string> &tempDirs)
903  {
904      for (const auto &tempDir : tempDirs) {
905          APP_LOGD("the temp hap dir %{public}s needs to be deleted", tempDir.c_str());
906          BundleUtil::DeleteDir(tempDir);
907      }
908  }
909  
GetHexHash(const std::string & s)910  std::string BundleUtil::GetHexHash(const std::string &s)
911  {
912      std::hash<std::string> hasher;
913      size_t hash = hasher(s);
914  
915      std::stringstream ss;
916      ss << std::hex << hash;
917  
918      std::string hash_str = ss.str();
919      return hash_str;
920  }
921  
RecursiveHash(std::string & s)922  void BundleUtil::RecursiveHash(std::string& s)
923  {
924      if (s.size() >= ORIGIN_STRING_LENGTH) {
925          s = s.substr(s.size() - ORIGIN_STRING_LENGTH);
926          return;
927      }
928      std::string hash = GetHexHash(s);
929      s += hash;
930      RecursiveHash(s);
931  }
932  
GenerateUuid()933  std::string BundleUtil::GenerateUuid()
934  {
935      std::lock_guard<std::mutex> lock(g_mutex);
936      auto currentTime = std::chrono::system_clock::now();
937      auto timestampNanoseconds =
938          std::chrono::duration_cast<std::chrono::nanoseconds>(currentTime.time_since_epoch()).count();
939  
940      // convert nanosecond timestamps to string
941      std::string s = std::to_string(timestampNanoseconds);
942      std::string timeStr = GetHexHash(s);
943  
944      char deviceId[UUID_LENGTH_MAX] = { 0 };
945      auto ret = GetDevUdid(deviceId, UUID_LENGTH_MAX);
946      std::string deviceUdid;
947      std::string deviceStr;
948      if (ret != 0) {
949          APP_LOGW("GetDevUdid failed");
950      } else {
951          deviceUdid = std::string{ deviceId };
952          deviceStr = GetHexHash(deviceUdid);
953      }
954  
955      std::string uuid = timeStr + deviceStr;
956      RecursiveHash(uuid);
957  
958      for (int32_t index : SEPARATOR_POSITIONS) {
959          uuid.insert(index, 1, UUID_SEPARATOR);
960      }
961      return uuid;
962  }
963  
GenerateUuidByKey(const std::string & key)964  std::string BundleUtil::GenerateUuidByKey(const std::string &key)
965  {
966      std::string keyHash = GetHexHash(key);
967  
968      char deviceId[UUID_LENGTH_MAX] = { 0 };
969      auto ret = GetDevUdid(deviceId, UUID_LENGTH_MAX);
970      std::string deviceUdid;
971      std::string deviceStr;
972      if (ret != 0) {
973          APP_LOGW("GetDevUdid failed");
974      } else {
975          deviceUdid = std::string{ deviceId };
976          deviceStr = GetHexHash(deviceUdid);
977      }
978  
979      std::string uuid = keyHash + deviceStr;
980      RecursiveHash(uuid);
981  
982      for (int32_t index : SEPARATOR_POSITIONS) {
983          uuid.insert(index, 1, UUID_SEPARATOR);
984      }
985      return uuid;
986  }
987  
ExtractGroupIdByDevelopId(const std::string & developerId)988  std::string BundleUtil::ExtractGroupIdByDevelopId(const std::string &developerId)
989  {
990      std::string::size_type dot_position = developerId.find('.');
991      if (dot_position == std::string::npos) {
992          // If cannot find '.' , the input string is developerId, return developerId
993          return developerId;
994      }
995      if (dot_position == 0) {
996          // if'.' In the first place, then groupId is empty, return developerId
997          return developerId.substr(1);
998      }
999      // If '.' If it is not the first place, there is a groupId, and the groupId is returned
1000      return developerId.substr(0, dot_position);
1001  }
1002  
ToString(const std::vector<std::string> & vector)1003  std::string BundleUtil::ToString(const std::vector<std::string> &vector)
1004  {
1005      std::string ret;
1006      for (const std::string &item : vector) {
1007          ret.append(item).append(",");
1008      }
1009      return ret;
1010  }
1011  
GetNoDisablingConfigPath()1012  std::string BundleUtil::GetNoDisablingConfigPath()
1013  {
1014  #ifdef CONFIG_POLOCY_ENABLE
1015      char buf[MAX_PATH_LEN] = { 0 };
1016      char *configPath = GetOneCfgFile(NO_DISABLING_CONFIG_PATH, buf, MAX_PATH_LEN);
1017      if (configPath == nullptr || configPath[0] == '\0') {
1018          APP_LOGE("BundleUtil GetOneCfgFile failed");
1019          return NO_DISABLING_CONFIG_PATH_DEFAULT;
1020      }
1021      if (strlen(configPath) > MAX_PATH_LEN) {
1022          APP_LOGE("length exceeds");
1023          return NO_DISABLING_CONFIG_PATH_DEFAULT;
1024      }
1025      return configPath;
1026  #else
1027      return NO_DISABLING_CONFIG_PATH_DEFAULT;
1028  #endif
1029  }
1030  }  // namespace AppExecFwk
1031  }  // namespace OHOS
1032