From 706efb0f297f05695358bac0d3acce70597ea0fd Mon Sep 17 00:00:00 2001 From: lanhaoyu Date: Mon, 8 Sep 2025 10:31:58 +0800 Subject: [PATCH] bm app Signed-off-by: lanhaoyu --- bundle.json | 3 +- frameworks/BUILD.gn | 1 + frameworks/include/bundle_command.h | 7 +- frameworks/src/bundle_command.cpp | 245 ++++++++++++++++++++++++++++ test/moduletest/bm/BUILD.gn | 3 + test/unittest/bm/BUILD.gn | 7 + 6 files changed, 262 insertions(+), 4 deletions(-) diff --git a/bundle.json b/bundle.json index 9ffd410..1f8e384 100644 --- a/bundle.json +++ b/bundle.json @@ -37,7 +37,8 @@ "access_token", "appverify", "ffrt", - "kv_store" + "kv_store", + "zlib" ], "third_party": [] }, diff --git a/frameworks/BUILD.gn b/frameworks/BUILD.gn index 93eb295..74a9ae8 100644 --- a/frameworks/BUILD.gn +++ b/frameworks/BUILD.gn @@ -71,6 +71,7 @@ ohos_source_set("tools_bm_source_set") { "ipc:ipc_core", "os_account:os_account_innerkits", "samgr:samgr_proxy", + "zlib:shared_libz", ] public_external_deps = [ diff --git a/frameworks/include/bundle_command.h b/frameworks/include/bundle_command.h index 3900073..ee21b84 100644 --- a/frameworks/include/bundle_command.h +++ b/frameworks/include/bundle_command.h @@ -66,10 +66,11 @@ const std::string HELP_MSG_INSTALL = "usage: bm install \n" "options list:\n" " -h, --help list available commands\n" - " -p, --bundle-path install a hap or hsp by a specified path\n" - " -p, --bundle-path ... install one bundle by some hap or hsp paths\n" + " -p, --bundle-path install a hap, hsp or app by a specified path\n" + " -p, --bundle-path ... install one bundle by some hap,\n" + " hsp or app paths\n" " -p, --bundle-path install one bundle by a direction,\n" - " under which are some hap or hsp files\n" + " under which are some hap, hsp or app files\n" " -r -p replace an existing bundle\n" " -r --bundle-path replace an existing bundle\n" " -s, --shared-bundle-dir-path install inter-application hsp files\n" diff --git a/frameworks/src/bundle_command.cpp b/frameworks/src/bundle_command.cpp index 5e5f7b5..d78ea1c 100644 --- a/frameworks/src/bundle_command.cpp +++ b/frameworks/src/bundle_command.cpp @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -28,12 +29,14 @@ #include "bundle_mgr_client.h" #include "bundle_mgr_proxy.h" #include "clean_cache_callback_host.h" +#include "contrib/minizip/unzip.h" #include "json_serializer.h" #include "nlohmann/json.hpp" #include "parameter.h" #include "parameters.h" #include "quick_fix_command.h" #include "quick_fix_status_callback_host_impl.h" +#include "scope_guard.h" #include "status_receiver_impl.h" #include "string_ex.h" #include "app_mgr_client.h" @@ -50,6 +53,11 @@ const std::string SHARED_BUNDLE_INFO = "sharedBundleInfo"; const std::string DEPENDENCIES = "dependencies"; const char* IS_ROOT_MODE_PARAM = "const.debuggable"; const std::string IS_DEVELOPER_MODE_PARAM = "const.security.developermode.state"; +constexpr const char APP_PATH[] = "/data/service/el1/public/bms/bundle_manager_service"; +constexpr const char PACK_INFO[] = "pack.info"; +constexpr const char* APP_FILE_SUFFIX = "app"; +const char FILE_SEPARATOR_CHAR = '/'; +constexpr const char* PATH_SEPARATOR = "/"; const int32_t ROOT_MODE = 1; const int32_t USER_MODE = 0; const int32_t INDEX_OFFSET = 2; @@ -60,6 +68,9 @@ const int32_t MAX_OVERLAY_ARGUEMENTS_NUMBER = 8; const int32_t MINIMUM_WAITTING_TIME = 180; // 3 mins const int32_t MAXIMUM_WAITTING_TIME = 600; // 10 mins const int32_t INITIAL_SANDBOX_APP_INDEX = 1000; +const int32_t SUB_LENGTH = 3; +const int32_t ZIP_MAX_PATH = 256; +const int32_t ZIP_BUF_SIZE = 8192; const std::string SHORT_OPTIONS_COMPILE = "hm:r:"; const struct option LONG_OPTIONS_COMPILE[] = { @@ -566,6 +577,194 @@ ErrCode BundleManagerShellCommand::RunAsCompileCommand() return result; } +static bool CheckAppFilePath(const std::string &filePath) +{ + int length = filePath.length(); + std::string suffix = filePath.substr(length > SUB_LENGTH ? length - SUB_LENGTH : 0); + if (suffix == APP_FILE_SUFFIX) { + return true; + } + return false; +} + +static void GetAppFilesFromBundlePath(const std::string ¤tBundlePath, std::vector &appFileList) +{ + if (currentBundlePath.empty()) { + return; + } + + DIR* dir = opendir(currentBundlePath.c_str()); + if (dir == nullptr) { + char errMsg[256] = {0}; + strerror_r(errno, errMsg, sizeof(errMsg)); + APP_LOGE("open %{public}s failure due to %{public}s errno %{public}d", + currentBundlePath.c_str(), errMsg, errno); + return; + } + + ScopeGuard dirGuard([&dir]() { + closedir(dir); + }); + + std::string bundlePath = currentBundlePath; + if (bundlePath.back() != FILE_SEPARATOR_CHAR) { + bundlePath.append(PATH_SEPARATOR); + } + + struct dirent *entry = nullptr; + while ((entry = readdir(dir)) != nullptr) { + if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) { + continue; + } + + const std::string hapFilePath = bundlePath + entry->d_name; + if (!CheckAppFilePath(hapFilePath)) { + APP_LOGE("invalid hap path %{public}s", hapFilePath.c_str()); + return; + } + + if (std::find(appFileList.begin(), appFileList.end(), hapFilePath) == appFileList.end()) { + appFileList.emplace_back(hapFilePath); + } + } +} + +static bool ExtractFileFromZip(unzFile zipFile, const std::string &outFilePath, + const char* filename, std::vector &filePaths) +{ + std::string fullPath = outFilePath + "/" + std::string(filename); + if (strcmp(filename, PACK_INFO) == 0) { + return true; + } + filePaths.emplace_back(fullPath); + + if (unzOpenCurrentFile(zipFile) != UNZ_OK) { + APP_LOGE("Failed to open file in zip: %{public}s", filename); + return false; + } + + ScopeGuard zipGuard([&zipFile]() { + unzCloseCurrentFile(zipFile); + }); + + FILE *outFile = fopen(fullPath.c_str(), "wb"); + if (!outFile) { + APP_LOGE("Failed to create output file: %{public}s", fullPath.c_str()); + unzCloseCurrentFile(zipFile); + return false; + } + + ScopeGuard fileGuard([&outFile]() { + if (fclose(outFile) != 0) { + APP_LOGE("Failed to close file"); + } + }); + + std::string buffer; + buffer.reserve(ZIP_BUF_SIZE); + buffer.resize(ZIP_BUF_SIZE - 1); + size_t bytesRead; + while ((bytesRead = unzReadCurrentFile(zipFile, &(buffer[0]), ZIP_BUF_SIZE)) > 0) { + if (fwrite(&(buffer[0]), 1, bytesRead, outFile) != bytesRead) { + APP_LOGE("Failed to write file"); + return false; + } + } + return true; +} + +static bool DecompressToFile(const std::string &zipFilePath, const std::string &outFilePath, + std::vector &filePaths) +{ + mode_t rootMode = 0777; + struct stat st; + if (stat(outFilePath.c_str(), &st) != 0) { + if (mkdir(outFilePath.c_str(), rootMode) != 0) { + APP_LOGE("Failed to create directory: %{public}s", outFilePath.c_str()); + return false; + } + } + + unzFile zipFile = unzOpen(zipFilePath.c_str()); + if (!zipFile) { + APP_LOGE("Failed to open zip file: %{public}s", zipFilePath.c_str()); + return false; + } + + ScopeGuard zipGuard([&zipFile]() { + unzClose(zipFile); + }); + + unz_global_info globalInfo = {}; + if (unzGetGlobalInfo(zipFile, &globalInfo) != UNZ_OK) { + APP_LOGE("Failed to get global info from zip file: %{public}s", zipFilePath.c_str()); + unzClose(zipFile); + return false; + } + + bool result = true; + for (uLong i = 0; i < globalInfo.number_entry; i++) { + char filename[ZIP_MAX_PATH] = {}; + unz_file_info fileInfo = {}; + if (unzGetCurrentFileInfo(zipFile, &fileInfo, filename, sizeof(filename) - 1, nullptr, 0, nullptr, 0) != + UNZ_OK) { + APP_LOGE("Failed to get file info"); + result = false; + break; + } + + if (!ExtractFileFromZip(zipFile, outFilePath, filename, filePaths)) { + result = false; + break; + } + + if ((i + 1) < globalInfo.number_entry) { + if (unzGoToNextFile(zipFile) != UNZ_OK) { + APP_LOGE("Failed to go to next file"); + result = false; + break; + } + } + } + return result; +} + +static bool RemoveDirectory(const std::string &dirPath) +{ + DIR *dir = opendir(dirPath.c_str()); + if (dir == nullptr) { + APP_LOGE("Failed to open directory: %{public}s", dirPath.c_str()); + return false; + } + + ScopeGuard dirGuard([&dir]() { + closedir(dir); + }); + + struct dirent *entry; + while ((entry = readdir(dir)) != nullptr) { + if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) { + continue; + } + + std::string fullPath = dirPath + "/" + std::string(entry->d_name); + struct stat statBuf; + if (stat(fullPath.c_str(), &statBuf) == 0) { + if (unlink(fullPath.c_str()) != 0) { + APP_LOGE("Failed to delete file: %{public}s", fullPath.c_str()); + closedir(dir); + return false; + } + } + } + + if (rmdir(dirPath.c_str()) != 0) { + APP_LOGE("Failed to remove directory: %{public}s", dirPath.c_str()); + return false; + } + return true; +} + ErrCode BundleManagerShellCommand::RunAsInstallCommand() { APP_LOGI("begin to RunAsInstallCommand"); @@ -736,6 +935,48 @@ ErrCode BundleManagerShellCommand::RunAsInstallCommand() } } + std::vector appPaths; + for (auto &path : bundlePath) { + if (CheckAppFilePath(path) && (std::find(appPaths.begin(), appPaths.end(), path) == appPaths.end())) { + appPaths.emplace_back(path); + continue; + } + GetAppFilesFromBundlePath(path, appPaths); + } + + std::vector tempPaths; + for (auto &appPath : appPaths) { + bundlePath.erase(std::remove(bundlePath.begin(), bundlePath.end(), appPath), bundlePath.end()); + auto timestamp = std::chrono::duration_cast( + std::chrono::high_resolution_clock::now().time_since_epoch()).count(); + std::string tempPath; + if (appPath.find("/") != std::string::npos) { + tempPath = std::string(APP_PATH) + appPath.substr(appPath.rfind("/")) + "_" + std::to_string(timestamp); + } else { + tempPath = std::string(APP_PATH) + "/" + appPath + "_" + std::to_string(timestamp); + } + tempPaths.emplace_back(tempPath); + std::vector filePaths; + if (!DecompressToFile(appPath, tempPath, filePaths)) { + continue; + } + for (auto path : filePaths) { + BundleInfo bundleInfo; + if (!bundleMgrProxy_->GetBundleArchiveInfo(path, + static_cast(GetBundleInfoFlag::GET_BUNDLE_INFO_WITH_APPLICATION), bundleInfo)) { + continue; + } + if (bundleMgrProxy_->CheckDeviceType(bundleInfo) != OHOS::ERR_OK) { + continue; + } + if (bundleInfo.applicationInfo.bundleType == BundleType::SHARED) { + sharedBundleDirPaths.emplace_back(path); + continue; + } + bundlePath.emplace_back(path); + } + } + for (auto &path : bundlePath) { APP_LOGD("install hap path %{private}s", path.c_str()); } @@ -778,6 +1019,10 @@ ErrCode BundleManagerShellCommand::RunAsInstallCommand() resultReceiver_ = warning + resultReceiver_; } } + + for (auto path : tempPaths) { + RemoveDirectory(path); + } APP_LOGI("end"); return result; } diff --git a/test/moduletest/bm/BUILD.gn b/test/moduletest/bm/BUILD.gn index ebd5dae..26a2204 100644 --- a/test/moduletest/bm/BUILD.gn +++ b/test/moduletest/bm/BUILD.gn @@ -71,6 +71,7 @@ ohos_moduletest("bm_command_dump_module_test") { "kv_store:distributeddata_inner", "os_account:os_account_innerkits", "samgr:samgr_proxy", + "zlib:shared_libz", ] external_deps += bm_install_external_deps @@ -122,6 +123,7 @@ ohos_moduletest("bm_command_install_module_test") { "kv_store:distributeddata_inner", "os_account:os_account_innerkits", "samgr:samgr_proxy", + "zlib:shared_libz", ] external_deps += bm_install_external_deps @@ -173,6 +175,7 @@ ohos_moduletest("bm_command_uninstall_module_test") { "kv_store:distributeddata_inner", "os_account:os_account_innerkits", "samgr:samgr_proxy", + "zlib:shared_libz", ] external_deps += bm_install_external_deps diff --git a/test/unittest/bm/BUILD.gn b/test/unittest/bm/BUILD.gn index aeed852..638cc56 100644 --- a/test/unittest/bm/BUILD.gn +++ b/test/unittest/bm/BUILD.gn @@ -77,6 +77,7 @@ ohos_unittest("bm_command_dump_test") { "os_account:os_account_innerkits", "relational_store:native_rdb", "samgr:samgr_proxy", + "zlib:shared_libz", ] external_deps += bm_install_external_deps @@ -129,6 +130,7 @@ ohos_unittest("bm_command_dump_dependencies_test") { "os_account:os_account_innerkits", "relational_store:native_rdb", "samgr:samgr_proxy", + "zlib:shared_libz", ] external_deps += bm_install_external_deps @@ -183,6 +185,7 @@ ohos_unittest("bm_command_install_test") { "os_account:os_account_innerkits", "relational_store:native_rdb", "samgr:samgr_proxy", + "zlib:shared_libz", ] external_deps += bm_install_external_deps @@ -237,6 +240,7 @@ ohos_unittest("bm_command_test") { "os_account:os_account_innerkits", "relational_store:native_rdb", "samgr:samgr_proxy", + "zlib:shared_libz", ] external_deps += bm_install_external_deps @@ -296,6 +300,7 @@ ohos_unittest("bm_command_uninstall_test") { "os_account:os_account_innerkits", "relational_store:native_rdb", "samgr:samgr_proxy", + "zlib:shared_libz", ] external_deps += bm_install_external_deps @@ -348,6 +353,7 @@ ohos_unittest("bm_command_quickfix_test") { "os_account:os_account_innerkits", "relational_store:native_rdb", "samgr:samgr_proxy", + "zlib:shared_libz", ] external_deps += bm_install_external_deps @@ -402,6 +408,7 @@ ohos_unittest("bm_command_overlay_test") { "os_account:os_account_innerkits", "relational_store:native_rdb", "samgr:samgr_proxy", + "zlib:shared_libz", ] external_deps += bm_install_external_deps -- Gitee