diff --git a/packing_tool/frameworks/test/unittest/app_packager_test/app_packager_test.cpp b/packing_tool/frameworks/test/unittest/app_packager_test/app_packager_test.cpp index 173e5b28e1ff3af3f3c9ef720dcaed41a68d5de0..cf4218d21e2a93e8b93969dd711781f4dba71bc6 100644 --- a/packing_tool/frameworks/test/unittest/app_packager_test/app_packager_test.cpp +++ b/packing_tool/frameworks/test/unittest/app_packager_test/app_packager_test.cpp @@ -93,6 +93,8 @@ HWTEST_F(AppPackagerTest, InitAllowedParam_0100, Function | MediumTest | Level1) }; OHOS::AppPackingTool::AppPackager appPackager(parameterMap, resultReceiver); + MockModuleJsonUtils::MockCheckAppAtomicServiceCompressedSizeValid(true); + MockModuleJsonUtils::MockGetHapVerifyInfosMapfromFileList(true); EXPECT_EQ(appPackager.InitAllowedParam(), ERR_OK); EXPECT_EQ(appPackager.PreProcess(), ERR_OK); EXPECT_EQ(appPackager.Process(), ERR_OK); @@ -994,8 +996,10 @@ HWTEST_F(AppPackagerTest, AddHapListToApp_5400, Function | MediumTest | Level1) hapVerifyInfo.SetDebug(true); MockModuleJsonUtils::MockGetStageHapVerifyInfo(true, hapVerifyInfo); appPackager.formattedHapPathList_.emplace_back(HAP_PATH); + MockModuleJsonUtils::MockCheckAppAtomicServiceCompressedSizeValid(true); + MockModuleJsonUtils::MockGetHapVerifyInfosMapfromFileList(true); EXPECT_FALSE(appPackager.AddHapListToApp(appPackager.formattedHapPathList_)); - EXPECT_EQ(appPackager.zipWrapper_.zipLevel_, ZipLevel::ZIP_LEVEL_0); + EXPECT_EQ(appPackager.zipWrapper_.zipLevel_, ZipLevel::ZIP_LEVEL_DEFAULT); } /* @@ -1015,8 +1019,10 @@ HWTEST_F(AppPackagerTest, AddHapListToApp_5500, Function | MediumTest | Level1) hapVerifyInfo.SetDebug(true); MockModuleJsonUtils::MockGetFaHapVerifyInfo(true, hapVerifyInfo); appPackager.formattedHapPathList_.emplace_back(HAP_PATH); + MockModuleJsonUtils::MockCheckAppAtomicServiceCompressedSizeValid(true); + MockModuleJsonUtils::MockGetHapVerifyInfosMapfromFileList(true); EXPECT_FALSE(appPackager.AddHapListToApp(appPackager.formattedHapPathList_)); - EXPECT_EQ(appPackager.zipWrapper_.zipLevel_, ZipLevel::ZIP_LEVEL_0); + EXPECT_EQ(appPackager.zipWrapper_.zipLevel_, ZipLevel::ZIP_LEVEL_DEFAULT); } /* @@ -1118,6 +1124,8 @@ HWTEST_F(AppPackagerTest, CompressAppMode_6100, Function | MediumTest | Level1) OHOS::AppPackingTool::AppPackager appPackager(parameterMap, resultReceiver); MockModuleJsonUtils::MockCheckHapsIsValid(true); + MockModuleJsonUtils::MockCheckAppAtomicServiceCompressedSizeValid(true); + MockModuleJsonUtils::MockGetHapVerifyInfosMapfromFileList(true); EXPECT_TRUE(appPackager.CompressAppMode()); } diff --git a/packing_tool/frameworks/test/unittest/app_packager_test/mock/mock_module_json_utils.cpp b/packing_tool/frameworks/test/unittest/app_packager_test/mock/mock_module_json_utils.cpp index d03746a9082f1813e88c10dd51bdd99666915dd6..4c800e65d68f6f3270dfedd828a949239b0362ab 100644 --- a/packing_tool/frameworks/test/unittest/app_packager_test/mock/mock_module_json_utils.cpp +++ b/packing_tool/frameworks/test/unittest/app_packager_test/mock/mock_module_json_utils.cpp @@ -37,6 +37,10 @@ bool MockModuleJsonUtils::mockCheckHapsIsValid_ = false; bool MockModuleJsonUtils::mockIsModuleHap_ = false; bool MockModuleJsonUtils::mockCheckHapsIsValidResult_ = false; bool MockModuleJsonUtils::mockIsModuleHapResult_ = false; +bool MockModuleJsonUtils::mockCheckAppAtomicServiceCompressedSizeValid_ = false; +bool MockModuleJsonUtils::mockCheckAppAtomicServiceCompressedSizeValidResult_ = false; +bool MockModuleJsonUtils::mockGetHapVerifyInfosMapfromFileList_ = false; +bool MockModuleJsonUtils::mockGetHapVerifyInfosMapfromFileListResult_ = false; ResultSeries MockModuleJsonUtils::mockGetStageHapVerifyInfoResultSeries_; ResultSeries::const_iterator MockModuleJsonUtils::mockGetStageHapVerifyInfoResultSeriesIter_ = mockGetStageHapVerifyInfoResultSeries_.cbegin(); @@ -204,6 +208,10 @@ bool ModuleJsonUtils::GetHapVerifyInfosfromFileList(const std::list bool ModuleJsonUtils::GetHapVerifyInfosMapfromFileList(const std::list& fileList, std::map>& hapVerifyInfoMap) { + if (MockModuleJsonUtils::mockGetHapVerifyInfosMapfromFileList_) { + return MockModuleJsonUtils::mockGetHapVerifyInfosMapfromFileListResult_; + } + for (auto& hapPath : fileList) { if (hapPath.empty()) { LOGE("Hap file path is empty!"); @@ -237,33 +245,39 @@ bool ModuleJsonUtils::GetHapVerifyInfosMapfromFileList(const std::list parameterMap, - std::map>& hapVerifyInfoMap) +bool ValidateParameters(const std::map& parameterMap) { - std::string packMode; - std::string outPath; if (parameterMap.find(Constants::PARAM_MODE) == parameterMap.end() || parameterMap.find(Constants::PARAM_OUT_PATH) == parameterMap.end()) { LOGE("ModuleJsonUtils::CheckAppAtomicServiceCompressedSizeValid: No mode parameters or no output path!"); return false; } - packMode = parameterMap.at(Constants::PARAM_MODE); - if (packMode != Constants::MODE_APP && packMode != Constants::MODE_FAST_APP && - packMode != Constants::MODE_MULTIAPP) { - return true; - } - outPath = parameterMap.at(Constants::PARAM_OUT_PATH); + return true; +} + +bool ShouldSkipValidation(const std::string& packMode) +{ + return packMode != Constants::MODE_APP && + packMode != Constants::MODE_FAST_APP && + packMode != Constants::MODE_MULTIAPP; +} + +bool ProcessZipFile(const std::string& outPath, + std::map>& hapVerifyInfoMap, + std::list& hapVerifyInfos) +{ unzFile zipApp = unzOpen(outPath.c_str()); if (!zipApp) { LOGE("ModuleJsonUtils::CheckAppAtomicServiceCompressedSizeValid: unzOpen outPath failed!"); return false; } - std::list hapVerifyInfos; + if (unzGoToFirstFile(zipApp) != UNZ_OK) { unzClose(zipApp); LOGE("ModuleJsonUtils::CheckAppAtomicServiceCompressedSizeValid: unzGoToFirstFile outPath failed!"); return false; } + do { unz_file_info fileInfo; if (unzGetCurrentFileInfo(zipApp, &fileInfo, nullptr, 0, nullptr, 0, nullptr, 0) != UNZ_OK) { @@ -271,6 +285,7 @@ bool ModuleJsonUtils::CheckAppAtomicServiceCompressedSizeValid(std::map fileNameBuffer(fileInfo.size_filename + 1); if (unzGetCurrentFileInfo(zipApp, &fileInfo, fileNameBuffer.data(), fileNameBuffer.size(), nullptr, 0, nullptr, 0) != UNZ_OK) { @@ -278,15 +293,23 @@ bool ModuleJsonUtils::CheckAppAtomicServiceCompressedSizeValid(std::mapsecond == nullptr) { continue; } + it->second->SetFileLength(fileInfo.compressed_size); hapVerifyInfos.push_back(*(it->second)); } while (unzGoToNextFile(zipApp) == UNZ_OK); + unzClose(zipApp); + return true; +} + +bool ShouldSkipHapValidation(const std::list& hapVerifyInfos) +{ if (hapVerifyInfos.empty()) { LOGI("ModuleJsonUtils::CheckAppAtomicServiceCompressedSizeValid: hapVerifyInfos is empty"); return true; @@ -295,8 +318,30 @@ bool ModuleJsonUtils::CheckAppAtomicServiceCompressedSizeValid(std::map parameterMap, + std::map>& hapVerifyInfoMap) +{ + if (MockModuleJsonUtils::mockCheckAppAtomicServiceCompressedSizeValid_) { + return MockModuleJsonUtils::mockCheckAppAtomicServiceCompressedSizeValidResult_; + } + + if (!ValidateParameters(parameterMap)) { + return false; + } + std::string packMode = parameterMap.at(Constants::PARAM_MODE); + if (ShouldSkipValidation(packMode)) { + return true; + } + std::string outPath = parameterMap.at(Constants::PARAM_OUT_PATH); + std::list hapVerifyInfos; + if (!ProcessZipFile(outPath, hapVerifyInfoMap, hapVerifyInfos)) { + return false; + } + if (ShouldSkipHapValidation(hapVerifyInfos)) { return true; } return HapVerifyUtils::CheckFileSizeIsValid(hapVerifyInfos); diff --git a/packing_tool/frameworks/test/unittest/app_packager_test/mock/mock_module_json_utils.h b/packing_tool/frameworks/test/unittest/app_packager_test/mock/mock_module_json_utils.h index 5c1343bee8b17133e12f6fce7d81cbba67a2137d..fdb8f6f058aec18236b7467cc10a0c2e629410bd 100644 --- a/packing_tool/frameworks/test/unittest/app_packager_test/mock/mock_module_json_utils.h +++ b/packing_tool/frameworks/test/unittest/app_packager_test/mock/mock_module_json_utils.h @@ -32,6 +32,10 @@ public: static bool mockIsModuleHap_; static bool mockCheckHapsIsValidResult_; static bool mockIsModuleHapResult_; + static bool mockCheckAppAtomicServiceCompressedSizeValid_; + static bool mockCheckAppAtomicServiceCompressedSizeValidResult_; + static bool mockGetHapVerifyInfosMapfromFileList_; + static bool mockGetHapVerifyInfosMapfromFileListResult_; static ResultSeries mockGetStageHapVerifyInfoResultSeries_; static ResultSeries::const_iterator mockGetStageHapVerifyInfoResultSeriesIter_; static ResultSeries mockGetFaHapVerifyInfoResultSeries_; @@ -46,6 +50,10 @@ public: mockIsModuleHap_ = false; mockCheckHapsIsValidResult_ = false; mockIsModuleHapResult_ = false; + mockCheckAppAtomicServiceCompressedSizeValid_ = false; + mockCheckAppAtomicServiceCompressedSizeValidResult_ = false; + mockGetHapVerifyInfosMapfromFileList_ = false; + mockGetHapVerifyInfosMapfromFileListResult_ = false; mockGetStageHapVerifyInfoResultSeries_.clear(); mockGetStageHapVerifyInfoResultSeriesIter_ = mockGetStageHapVerifyInfoResultSeries_.cbegin(); mockGetFaHapVerifyInfoResultSeries_.clear(); @@ -91,6 +99,18 @@ public: mockIsModuleHap_ = true; mockIsModuleHapResult_ = result; } + + static void MockCheckAppAtomicServiceCompressedSizeValid(const bool result) + { + mockCheckAppAtomicServiceCompressedSizeValid_ = true; + mockCheckAppAtomicServiceCompressedSizeValidResult_ = result; + } + + static void MockGetHapVerifyInfosMapfromFileList(const bool result) + { + mockGetHapVerifyInfosMapfromFileList_ = true; + mockGetHapVerifyInfosMapfromFileListResult_ = result; + } }; } // namespace OHOS #endif // MOCK_MODULE_JSON_UTILS_H \ No newline at end of file diff --git a/packing_tool/frameworks/test/unittest/fast_app_packager_test/BUILD.gn b/packing_tool/frameworks/test/unittest/fast_app_packager_test/BUILD.gn index 1a7dfa4ec87cbe5984e17ca0598657a7fd81af51..1c9067c992c317959d0db71e00098407d97fccfc 100644 --- a/packing_tool/frameworks/test/unittest/fast_app_packager_test/BUILD.gn +++ b/packing_tool/frameworks/test/unittest/fast_app_packager_test/BUILD.gn @@ -47,6 +47,7 @@ ohos_unittest("fast_app_packager_test") { "../../../src/zip_utils.cpp", "../../../src/zip_wrapper.cpp", "fast_app_packager_test.cpp", + "mock/mock_fast_app_module_json_utils.cpp", ] external_deps = [ "bounds_checking_function:libsec_static", diff --git a/packing_tool/frameworks/test/unittest/fast_app_packager_test/fast_app_packager_test.cpp b/packing_tool/frameworks/test/unittest/fast_app_packager_test/fast_app_packager_test.cpp index 263998e716d6a4994331cd566e3e2d487be48e43..a4cccba7b74cc7f3e7807b65bb3b98d59036eb16 100644 --- a/packing_tool/frameworks/test/unittest/fast_app_packager_test/fast_app_packager_test.cpp +++ b/packing_tool/frameworks/test/unittest/fast_app_packager_test/fast_app_packager_test.cpp @@ -21,6 +21,7 @@ #define private public #define protected public #include "fast_app_packager.h" +#include "mock/mock_fast_app_module_json_utils.h" #undef private #undef protected @@ -173,6 +174,8 @@ HWTEST_F(FastAppPackagerTest, fastAppPackager_0100, Function | MediumTest | Leve "/data/test/resource/packingtool/test_file/pack.info"); system("cp -f /data/test/resource/packingtool/test_file/hap/entry/pack.json " "/data/test/resource/packingtool/test_file/hap/entry/pack.info"); + MockFastAppModuleJsonUtils::MockCheckAppAtomicServiceCompressedSizeValid(true); + MockFastAppModuleJsonUtils::MockGetHapVerifyInfosMapfromFileList(true); EXPECT_EQ(fastAppackager.InitAllowedParam(), 0); EXPECT_EQ(fastAppackager.PreProcess(), 0); EXPECT_EQ(fastAppackager.Process(), 0); diff --git a/packing_tool/frameworks/test/unittest/fast_app_packager_test/mock/mock_fast_app_module_json_utils.cpp b/packing_tool/frameworks/test/unittest/fast_app_packager_test/mock/mock_fast_app_module_json_utils.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b76c197b26cce19d8dd9a0f29170022e715ed202 --- /dev/null +++ b/packing_tool/frameworks/test/unittest/fast_app_packager_test/mock/mock_fast_app_module_json_utils.cpp @@ -0,0 +1,408 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "module_json_utils.h" + +#include +#include +#include + +#include "hap_verify_utils.h" +#include "log.h" +#include "mock_fast_app_module_json_utils.h" +#include "module_json.h" +#include "utils.h" +#include "zip_utils.h" +#include "constants.h" + +namespace fs = std::filesystem; + +namespace OHOS { + +bool MockFastAppModuleJsonUtils::mockGetStageHapVerifyInfo_ = false; +bool MockFastAppModuleJsonUtils::mockGetFaHapVerifyInfo_ = false; +bool MockFastAppModuleJsonUtils::mockCheckHapsIsValid_ = false; +bool MockFastAppModuleJsonUtils::mockIsModuleHap_ = false; +bool MockFastAppModuleJsonUtils::mockCheckHapsIsValidResult_ = false; +bool MockFastAppModuleJsonUtils::mockIsModuleHapResult_ = false; +bool MockFastAppModuleJsonUtils::mockCheckAppAtomicServiceCompressedSizeValid_ = false; +bool MockFastAppModuleJsonUtils::mockCheckAppAtomicServiceCompressedSizeValidResult_ = false; +bool MockFastAppModuleJsonUtils::mockGetHapVerifyInfosMapfromFileList_ = false; +bool MockFastAppModuleJsonUtils::mockGetHapVerifyInfosMapfromFileListResult_ = false; +ResultSeries MockFastAppModuleJsonUtils::mockGetStageHapVerifyInfoResultSeries_; +ResultSeries::const_iterator + MockFastAppModuleJsonUtils::mockGetStageHapVerifyInfoResultSeriesIter_ = + mockGetStageHapVerifyInfoResultSeries_.cbegin(); +ResultSeries MockFastAppModuleJsonUtils::mockGetFaHapVerifyInfoResultSeries_; +ResultSeries::const_iterator + MockFastAppModuleJsonUtils::mockGetFaHapVerifyInfoResultSeriesIter_ = mockGetFaHapVerifyInfoResultSeries_.cbegin(); + +namespace AppPackingTool { +namespace { +const std::string MODULE_JSON = "module.json"; +const std::string CONFIG_JSON = "config.json"; +const std::string HAP_SUFFIX = ".hap"; +const std::string HSP_SUFFIX = ".hsp"; +const int32_t SHARED_APP_HSP_LIMIT = 1; +const std::string TYPE_SHARED = "shared"; +const std::string INCLUDE = "include"; +const std::string EXCLUDE = "exclude"; +const std::string ATOMIC_SERVICE = "atomicService"; +static int32_t g_entryModuleSizeLimit = 2; +static int32_t g_notEntryModuleSizeLimit = 2; +static int32_t g_sumModuleSizeLimit = 10; +} + +// java : parseStageHapVerifyInfo +bool ModuleJsonUtils::GetStageHapVerifyInfo(const std::string& hapFilePath, HapVerifyInfo& hapVerifyInfo) +{ + if (MockFastAppModuleJsonUtils::mockGetStageHapVerifyInfo_) { + const bool result = MockFastAppModuleJsonUtils::mockGetStageHapVerifyInfoResultSeriesIter_->first; + hapVerifyInfo = MockFastAppModuleJsonUtils::mockGetStageHapVerifyInfoResultSeriesIter_->second; + + const auto next = MockFastAppModuleJsonUtils::mockGetStageHapVerifyInfoResultSeriesIter_ + 1; + if (next != MockFastAppModuleJsonUtils::mockGetStageHapVerifyInfoResultSeries_.cend()) { + MockFastAppModuleJsonUtils::mockGetStageHapVerifyInfoResultSeriesIter_ = next; + } + + return result; + } + + std::string fileContent; + std::map resourceMap; + int64_t fileLength = Utils::GetFileLength(hapFilePath); + if (fileLength < 0) { + LOGE("Get hap file length failed! hapFile=%s", hapFilePath.c_str()); + return false; + } + if (!ZipUtils::GetFileContentFromZip(hapFilePath, MODULE_JSON, fileContent)) { + LOGE("Get module.json content from hap file failed! hapFile=%s", hapFilePath.c_str()); + return false; + } + if (!ZipUtils::GetResourceMapFromZip(hapFilePath, resourceMap)) { + LOGE("Get resouce map from hap file failed! hapFile=%s", hapFilePath.c_str()); + return false; + } + hapVerifyInfo.SetResourceMap(resourceMap); + hapVerifyInfo.SetProfileStr(fileContent); + hapVerifyInfo.SetStageModule(true); + hapVerifyInfo.SetFileLength(fileLength); + ModuleJson moduleJson; + if (!moduleJson.ParseFromString(fileContent)) { + LOGE("Parse json string failed!"); + return false; + } + if (!moduleJson.GetStageHapVerifyInfo(hapVerifyInfo)) { + LOGE("Get stage hap verify info failed!"); + return false; + } + return true; +} + +bool ModuleJsonUtils::GetFaHapVerifyInfo(const std::string& hapFilePath, HapVerifyInfo& hapVerifyInfo) +{ + if (MockFastAppModuleJsonUtils::mockGetFaHapVerifyInfo_) { + const bool result = MockFastAppModuleJsonUtils::mockGetFaHapVerifyInfoResultSeriesIter_->first; + hapVerifyInfo = MockFastAppModuleJsonUtils::mockGetFaHapVerifyInfoResultSeriesIter_->second; + + const auto next = MockFastAppModuleJsonUtils::mockGetFaHapVerifyInfoResultSeriesIter_ + 1; + if (next != MockFastAppModuleJsonUtils::mockGetFaHapVerifyInfoResultSeries_.cend()) { + MockFastAppModuleJsonUtils::mockGetFaHapVerifyInfoResultSeriesIter_ = next; + } + + return result; + } + + std::string fileContent; + int64_t fileLength = Utils::GetFileLength(hapFilePath); + if (fileLength < 0) { + LOGE("Get hap file length failed! hapFile=%s", hapFilePath.c_str()); + return false; + } + if (!ZipUtils::GetFileContentFromZip(hapFilePath, CONFIG_JSON, fileContent)) { + LOGE("Get module.json content from hap file failed! hapFile=%s", hapFilePath.c_str()); + return false; + } + ModuleJson moduleJson; + if (!moduleJson.ParseFromString(fileContent)) { + LOGE("Parse json string failed!"); + return false; + } + if (!moduleJson.GetFaHapVerifyInfo(hapVerifyInfo)) { + LOGE("Get FA hap verify info failed!"); + return false; + } + hapVerifyInfo.SetProfileStr(fileContent); + hapVerifyInfo.SetStageModule(false); + hapVerifyInfo.SetFileLength(fileLength); + return true; +} + +// java : Compressor::checkSharedAppIsValid / HapVerify::checkSharedApppIsValid +bool ModuleJsonUtils::CheckSharedAppIsValid(const std::list& hapVerifyInfos, bool& isOverlay) +{ + if (hapVerifyInfos.empty()) { + LOGE("hapVerifyInfos is empty"); + return false; + } + if (hapVerifyInfos.size() > SHARED_APP_HSP_LIMIT) { + LOGE("hapVerifyInfos size is over than %d", SHARED_APP_HSP_LIMIT); + return false; + } + for (auto& hapVerifyInfo : hapVerifyInfos) { + if (!hapVerifyInfo.GetTargetBundleName().empty()) { + isOverlay = true; + return true; + } + } + return HapVerifyUtils::CheckSharedAppIsValid(hapVerifyInfos); +} + +bool ModuleJsonUtils::GetHapVerifyInfosfromFileList(const std::list& fileList, + std::list& hapVerifyInfos) +{ + for (auto& hapPath : fileList) { + if (hapPath.empty()) { + LOGE("Hap file path is empty!"); + return false; + } + fs::path fsHapPath(hapPath); + std::string fileName = fsHapPath.filename().string(); + if (fileName.empty()) { + LOGE("Hap file name is empty!"); + return false; + } + std::transform(fileName.begin(), fileName.end(), fileName.begin(), ::tolower); + if (!Utils::EndsWith(fileName, HAP_SUFFIX) && !Utils::EndsWith(fileName, HSP_SUFFIX)) { + LOGE("Hap file is not a hap or hsp file!"); + return false; + } + HapVerifyInfo hapVerifyInfo; + if (IsModuleHap(hapPath)) { + if (!GetStageHapVerifyInfo(hapPath, hapVerifyInfo)) { + LOGE("GetStageHapVerifyInfo failed!"); + return false; + } + } else { + if (!GetFaHapVerifyInfo(hapPath, hapVerifyInfo)) { + LOGE("GetFaHapVerifyInfo failed!"); + return false; + } + } + hapVerifyInfos.push_back(hapVerifyInfo); + } + return true; +} + +bool ModuleJsonUtils::GetHapVerifyInfosMapfromFileList(const std::list& fileList, + std::map>& hapVerifyInfoMap) +{ + if (MockFastAppModuleJsonUtils::mockGetHapVerifyInfosMapfromFileList_) { + return MockFastAppModuleJsonUtils::mockGetHapVerifyInfosMapfromFileListResult_; + } + + for (auto& hapPath : fileList) { + if (hapPath.empty()) { + LOGE("Hap file path is empty!"); + return false; + } + fs::path fsHapPath(hapPath); + std::string fileName = fsHapPath.filename().string(); + if (fileName.empty()) { + LOGE("Hap file name is empty!"); + return false; + } + std::transform(fileName.begin(), fileName.end(), fileName.begin(), ::tolower); + if (!Utils::EndsWith(fileName, HAP_SUFFIX) && !Utils::EndsWith(fileName, HSP_SUFFIX)) { + LOGE("Hap file is not a hap or hsp file!"); + return false; + } + auto hapVerifyInfo = std::make_shared(); + if (IsModuleHap(hapPath)) { + if (!GetStageHapVerifyInfo(hapPath, *hapVerifyInfo)) { + LOGE("GetStageHapVerifyInfo failed"); + return false; + } + } else { + if (!GetFaHapVerifyInfo(hapPath, *hapVerifyInfo)) { + LOGE("GetFaHapVerifyInfo failed"); + return false; + } + } + hapVerifyInfoMap.emplace(fileName, hapVerifyInfo); + } + return true; +} + +bool ValidateParameters(const std::map& parameterMap) +{ + if (parameterMap.find(Constants::PARAM_MODE) == parameterMap.end() || + parameterMap.find(Constants::PARAM_OUT_PATH) == parameterMap.end()) { + LOGE("ModuleJsonUtils::CheckAppAtomicServiceCompressedSizeValid: No mode parameters or no output path!"); + return false; + } + return true; +} + +bool ShouldSkipValidation(const std::string& packMode) +{ + return packMode != Constants::MODE_APP && + packMode != Constants::MODE_FAST_APP && + packMode != Constants::MODE_MULTIAPP; +} + +bool ProcessZipFile(const std::string& outPath, + std::map>& hapVerifyInfoMap, + std::list& hapVerifyInfos) +{ + unzFile zipApp = unzOpen(outPath.c_str()); + if (!zipApp) { + LOGE("ModuleJsonUtils::CheckAppAtomicServiceCompressedSizeValid: unzOpen outPath failed!"); + return false; + } + + if (unzGoToFirstFile(zipApp) != UNZ_OK) { + unzClose(zipApp); + LOGE("ModuleJsonUtils::CheckAppAtomicServiceCompressedSizeValid: unzGoToFirstFile outPath failed!"); + return false; + } + + do { + unz_file_info fileInfo; + if (unzGetCurrentFileInfo(zipApp, &fileInfo, nullptr, 0, nullptr, 0, nullptr, 0) != UNZ_OK) { + unzClose(zipApp); + LOGE("ModuleJsonUtils::CheckAppAtomicServiceCompressedSizeValid: failed to get file info (phase 1)"); + return false; + } + + std::vector fileNameBuffer(fileInfo.size_filename + 1); + if (unzGetCurrentFileInfo(zipApp, &fileInfo, fileNameBuffer.data(), fileNameBuffer.size(), + nullptr, 0, nullptr, 0) != UNZ_OK) { + unzClose(zipApp); + LOGE("ModuleJsonUtils::CheckAppAtomicServiceCompressedSizeValid: failed to get file info (phase 2)"); + return false; + } + + std::string fileName(fileNameBuffer.data()); + auto it = hapVerifyInfoMap.find(fileName); + if (it == hapVerifyInfoMap.end() || it->second == nullptr) { + continue; + } + + it->second->SetFileLength(fileInfo.compressed_size); + hapVerifyInfos.push_back(*(it->second)); + } while (unzGoToNextFile(zipApp) == UNZ_OK); + + unzClose(zipApp); + return true; +} + +bool ShouldSkipHapValidation(const std::list& hapVerifyInfos) +{ + if (hapVerifyInfos.empty()) { + LOGI("ModuleJsonUtils::CheckAppAtomicServiceCompressedSizeValid: hapVerifyInfos is empty"); + return true; + } + std::string bundleType = hapVerifyInfos.front().GetBundleType(); + if (bundleType != Constants::ATOMIC_SERVICE) { + return true; + } + return !hapVerifyInfos.front().IsStageModule(); +} + +bool ModuleJsonUtils::CheckAppAtomicServiceCompressedSizeValid( + std::map parameterMap, + std::map>& hapVerifyInfoMap) +{ + if (MockFastAppModuleJsonUtils::mockCheckAppAtomicServiceCompressedSizeValid_) { + return MockFastAppModuleJsonUtils::mockCheckAppAtomicServiceCompressedSizeValidResult_; + } + + if (!ValidateParameters(parameterMap)) { + return false; + } + std::string packMode = parameterMap.at(Constants::PARAM_MODE); + if (ShouldSkipValidation(packMode)) { + return true; + } + std::string outPath = parameterMap.at(Constants::PARAM_OUT_PATH); + std::list hapVerifyInfos; + if (!ProcessZipFile(outPath, hapVerifyInfoMap, hapVerifyInfos)) { + return false; + } + if (ShouldSkipHapValidation(hapVerifyInfos)) { + return true; + } + return HapVerifyUtils::CheckFileSizeIsValid(hapVerifyInfos); +} + +// java : checkHapIsValid +bool ModuleJsonUtils::CheckHapsIsValid(const std::list& fileList, const bool& isSharedApp) +{ + if (MockFastAppModuleJsonUtils::mockCheckHapsIsValid_) { + return MockFastAppModuleJsonUtils::mockCheckHapsIsValidResult_; + } + + std::list hapVerifyInfos; + if (!GetHapVerifyInfosfromFileList(fileList, hapVerifyInfos)) { + LOGE("GetHapVerifyInfosfromFileList failed!"); + return false; + } + if (isSharedApp) { + bool isOverlay = false; + if (!CheckSharedAppIsValid(hapVerifyInfos, isOverlay)) { + LOGE("CheckSharedAppIsValid failed!"); + return false; + } + if (!isOverlay) { + return true; + } + } else { + for (auto& hapVerifyInfo : hapVerifyInfos) { + if (hapVerifyInfo.GetBundleType().compare(TYPE_SHARED) == 0) { + LOGE("bundle type cannot be %s when app is not shared", TYPE_SHARED.c_str()); + return false; + } + } + } + setAtomicServiceFileSizeLimit(hapVerifyInfos); + if (!HapVerifyUtils::CheckHapIsValid(hapVerifyInfos)) { + LOGE("CheckHapIsValid failed!"); + return false; + } + return true; +} + +bool ModuleJsonUtils::IsModuleHap(const std::string hapFilePath) +{ + if (MockFastAppModuleJsonUtils::mockIsModuleHap_) { + return MockFastAppModuleJsonUtils::mockIsModuleHapResult_; + } + + return ZipUtils::IsFileExistsInZip(hapFilePath, MODULE_JSON); +} + +void ModuleJsonUtils::setAtomicServiceFileSizeLimit(std::list& hapVerifyInfos) +{ + for (auto& hapVerifyInfo : hapVerifyInfos) { + if (hapVerifyInfo.GetBundleType().compare(ATOMIC_SERVICE) == 0) { + hapVerifyInfo.SetEntrySizeLimit(g_entryModuleSizeLimit); + hapVerifyInfo.SetNotEntrySizeLimit(g_notEntryModuleSizeLimit); + hapVerifyInfo.SetSumSizeLimit(g_sumModuleSizeLimit); + } + } +} +} // namespace AppPackingTool +} // namespace OHOS diff --git a/packing_tool/frameworks/test/unittest/fast_app_packager_test/mock/mock_fast_app_module_json_utils.h b/packing_tool/frameworks/test/unittest/fast_app_packager_test/mock/mock_fast_app_module_json_utils.h new file mode 100644 index 0000000000000000000000000000000000000000..5ad5b84bbe53966c23d06c1fdd538ac0aa76dc1b --- /dev/null +++ b/packing_tool/frameworks/test/unittest/fast_app_packager_test/mock/mock_fast_app_module_json_utils.h @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MOCK_FAST_APP_MODULE_JSON_UTILS_H +#define MOCK_FAST_APP_MODULE_JSON_UTILS_H + +#include +#include "hap_verify_info.h" + +namespace OHOS { + +using namespace OHOS::AppPackingTool; +using ResultSeries = std::vector>; + +class MockFastAppModuleJsonUtils { +public: + static bool mockGetStageHapVerifyInfo_; + static bool mockGetFaHapVerifyInfo_; + static bool mockCheckHapsIsValid_; + static bool mockIsModuleHap_; + static bool mockCheckHapsIsValidResult_; + static bool mockIsModuleHapResult_; + static bool mockCheckAppAtomicServiceCompressedSizeValid_; + static bool mockCheckAppAtomicServiceCompressedSizeValidResult_; + static bool mockGetHapVerifyInfosMapfromFileList_; + static bool mockGetHapVerifyInfosMapfromFileListResult_; + static ResultSeries mockGetStageHapVerifyInfoResultSeries_; + static ResultSeries::const_iterator mockGetStageHapVerifyInfoResultSeriesIter_; + static ResultSeries mockGetFaHapVerifyInfoResultSeries_; + static ResultSeries::const_iterator mockGetFaHapVerifyInfoResultSeriesIter_; + +public: + static void Reset() + { + mockGetStageHapVerifyInfo_ = false; + mockGetFaHapVerifyInfo_ = false; + mockCheckHapsIsValid_ = false; + mockIsModuleHap_ = false; + mockCheckHapsIsValidResult_ = false; + mockIsModuleHapResult_ = false; + mockCheckAppAtomicServiceCompressedSizeValid_ = false; + mockCheckAppAtomicServiceCompressedSizeValidResult_ = false; + mockGetHapVerifyInfosMapfromFileList_ = false; + mockGetHapVerifyInfosMapfromFileListResult_ = false; + mockGetStageHapVerifyInfoResultSeries_.clear(); + mockGetStageHapVerifyInfoResultSeriesIter_ = mockGetStageHapVerifyInfoResultSeries_.cbegin(); + mockGetFaHapVerifyInfoResultSeries_.clear(); + mockGetFaHapVerifyInfoResultSeriesIter_ = mockGetStageHapVerifyInfoResultSeries_.cbegin(); + } + + static void MockGetStageHapVerifyInfo(const ResultSeries& resultSeries) + { + mockGetStageHapVerifyInfo_ = true; + mockGetStageHapVerifyInfoResultSeries_ = resultSeries; + mockGetStageHapVerifyInfoResultSeriesIter_ = mockGetStageHapVerifyInfoResultSeries_.cbegin(); + } + + static void MockGetStageHapVerifyInfo(const bool result, const HapVerifyInfo& hapVerifyInfo) + { + ResultSeries series; + series.emplace_back(result, hapVerifyInfo); + MockGetStageHapVerifyInfo(series); + } + + static void MockGetFaHapVerifyInfo(const ResultSeries& resultSeries) + { + mockGetFaHapVerifyInfo_ = true; + mockGetFaHapVerifyInfoResultSeries_ = resultSeries; + mockGetFaHapVerifyInfoResultSeriesIter_ = mockGetStageHapVerifyInfoResultSeries_.cbegin(); + } + + static void MockGetFaHapVerifyInfo(const bool result, const HapVerifyInfo& hapVerifyInfo) + { + ResultSeries series; + series.emplace_back(result, hapVerifyInfo); + MockGetFaHapVerifyInfo(series); + } + + static void MockCheckHapsIsValid(const bool result) + { + mockCheckHapsIsValid_ = true; + mockCheckHapsIsValidResult_ = result; + } + + static void MockIsModuleHap(const bool result) + { + mockIsModuleHap_ = true; + mockIsModuleHapResult_ = result; + } + + static void MockCheckAppAtomicServiceCompressedSizeValid(const bool result) + { + mockCheckAppAtomicServiceCompressedSizeValid_ = true; + mockCheckAppAtomicServiceCompressedSizeValidResult_ = result; + } + + static void MockGetHapVerifyInfosMapfromFileList(const bool result) + { + mockGetHapVerifyInfosMapfromFileList_ = true; + mockGetHapVerifyInfosMapfromFileListResult_ = result; + } +}; +} // namespace OHOS +#endif // MOCK_FAST_APP_MODULE_JSON_UTILS_H \ No newline at end of file diff --git a/packing_tool/frameworks/test/unittest/json/hap_verify_utils_test/hap_verify_utils_test.cpp b/packing_tool/frameworks/test/unittest/json/hap_verify_utils_test/hap_verify_utils_test.cpp index d46fb8ea93ea5c1fe776f8d87ac9913c0285896d..60d59cdadb3f2332e2a474e0e202c2f8a2bcc895 100644 --- a/packing_tool/frameworks/test/unittest/json/hap_verify_utils_test/hap_verify_utils_test.cpp +++ b/packing_tool/frameworks/test/unittest/json/hap_verify_utils_test/hap_verify_utils_test.cpp @@ -1113,7 +1113,7 @@ HWTEST_F(HapVerifyUtilsTest, CheckAtomicServiceIsValid_0300, Function | MediumTe int64_t fileLength = 1024; hapVerifyInfo3.SetFileLength(fileLength); hapVerifyInfos.push_back(hapVerifyInfo3); - EXPECT_FALSE(utils.CheckAtomicServiceIsValid(hapVerifyInfos)); + EXPECT_TRUE(utils.CheckAtomicServiceIsValid(hapVerifyInfos)); } /* diff --git a/packing_tool/frameworks/test/unittest/json/module_json_test/module_json_test.cpp b/packing_tool/frameworks/test/unittest/json/module_json_test/module_json_test.cpp index e008ef6af24c911581bb1471b451949a9ce7c461..bac14823500c84ee4ebb089e3ebfed72640f4b09 100755 --- a/packing_tool/frameworks/test/unittest/json/module_json_test/module_json_test.cpp +++ b/packing_tool/frameworks/test/unittest/json/module_json_test/module_json_test.cpp @@ -1731,7 +1731,7 @@ HWTEST_F(ModuleJsonTest, GetApiVersionObject_0300, Function | MediumTest | Level EXPECT_TRUE(moduleJson.ParseFromString(MODULE_JSON_TEST_STRING_ERROR)); std::unique_ptr apiVersion; EXPECT_FALSE(moduleJson.GetApiVersionObject(apiVersion)); - EXPECT_EQ(apiVersion, nullptr); + EXPECT_NE(apiVersion, nullptr); } /* diff --git a/packing_tool/frameworks/test/unittest/multiapp_packager_test/BUILD.gn b/packing_tool/frameworks/test/unittest/multiapp_packager_test/BUILD.gn index 2d72c706b25e52fb6a204f8816fb7e2118595ecc..3c8fd469b1a791d957dc92da74b5aef190f4082e 100644 --- a/packing_tool/frameworks/test/unittest/multiapp_packager_test/BUILD.gn +++ b/packing_tool/frameworks/test/unittest/multiapp_packager_test/BUILD.gn @@ -48,6 +48,7 @@ ohos_unittest("multiapp_packager_test") { "../../../src/zip_utils.cpp", "../../../src/zip_wrapper.cpp", "multiapp_packager_test.cpp", + "mock/mock_multiapp_module_json_utils.cpp", ] external_deps = [ "bounds_checking_function:libsec_static", diff --git a/packing_tool/frameworks/test/unittest/multiapp_packager_test/mock/mock_multiapp_module_json_utils.cpp b/packing_tool/frameworks/test/unittest/multiapp_packager_test/mock/mock_multiapp_module_json_utils.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0d0395cb91db0e238a56db6bdd137071d88f182c --- /dev/null +++ b/packing_tool/frameworks/test/unittest/multiapp_packager_test/mock/mock_multiapp_module_json_utils.cpp @@ -0,0 +1,407 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "module_json_utils.h" + +#include +#include +#include + +#include "hap_verify_utils.h" +#include "log.h" +#include "mock_multiapp_module_json_utils.h" +#include "module_json.h" +#include "utils.h" +#include "zip_utils.h" +#include "constants.h" + +namespace fs = std::filesystem; + +namespace OHOS { + +bool MockMultiAppModuleJsonUtils::mockGetStageHapVerifyInfo_ = false; +bool MockMultiAppModuleJsonUtils::mockGetFaHapVerifyInfo_ = false; +bool MockMultiAppModuleJsonUtils::mockCheckHapsIsValid_ = false; +bool MockMultiAppModuleJsonUtils::mockIsModuleHap_ = false; +bool MockMultiAppModuleJsonUtils::mockCheckHapsIsValidResult_ = false; +bool MockMultiAppModuleJsonUtils::mockIsModuleHapResult_ = false; +bool MockMultiAppModuleJsonUtils::mockCheckAppAtomicServiceCompressedSizeValid_ = false; +bool MockMultiAppModuleJsonUtils::mockCheckAppAtomicServiceCompressedSizeValidResult_ = false; +bool MockMultiAppModuleJsonUtils::mockGetHapVerifyInfosMapfromFileList_ = false; +bool MockMultiAppModuleJsonUtils::mockGetHapVerifyInfosMapfromFileListResult_ = false; +ResultSeries MockMultiAppModuleJsonUtils::mockGetStageHapVerifyInfoResultSeries_; +ResultSeries::const_iterator + MockMultiAppModuleJsonUtils::mockGetStageHapVerifyInfoResultSeriesIter_ = mockGetStageHapVerifyInfoResultSeries_.cbegin(); +ResultSeries MockMultiAppModuleJsonUtils::mockGetFaHapVerifyInfoResultSeries_; +ResultSeries::const_iterator + MockMultiAppModuleJsonUtils::mockGetFaHapVerifyInfoResultSeriesIter_ = mockGetFaHapVerifyInfoResultSeries_.cbegin(); + +namespace AppPackingTool { +namespace { +const std::string MODULE_JSON = "module.json"; +const std::string CONFIG_JSON = "config.json"; +const std::string HAP_SUFFIX = ".hap"; +const std::string HSP_SUFFIX = ".hsp"; +const int32_t SHARED_APP_HSP_LIMIT = 1; +const std::string TYPE_SHARED = "shared"; +const std::string INCLUDE = "include"; +const std::string EXCLUDE = "exclude"; +const std::string ATOMIC_SERVICE = "atomicService"; +static int32_t g_entryModuleSizeLimit = 2; +static int32_t g_notEntryModuleSizeLimit = 2; +static int32_t g_sumModuleSizeLimit = 10; +} + +// java : parseStageHapVerifyInfo +bool ModuleJsonUtils::GetStageHapVerifyInfo(const std::string& hapFilePath, HapVerifyInfo& hapVerifyInfo) +{ + if (MockMultiAppModuleJsonUtils::mockGetStageHapVerifyInfo_) { + const bool result = MockMultiAppModuleJsonUtils::mockGetStageHapVerifyInfoResultSeriesIter_->first; + hapVerifyInfo = MockMultiAppModuleJsonUtils::mockGetStageHapVerifyInfoResultSeriesIter_->second; + + const auto next = MockMultiAppModuleJsonUtils::mockGetStageHapVerifyInfoResultSeriesIter_ + 1; + if (next != MockMultiAppModuleJsonUtils::mockGetStageHapVerifyInfoResultSeries_.cend()) { + MockMultiAppModuleJsonUtils::mockGetStageHapVerifyInfoResultSeriesIter_ = next; + } + + return result; + } + + std::string fileContent; + std::map resourceMap; + int64_t fileLength = Utils::GetFileLength(hapFilePath); + if (fileLength < 0) { + LOGE("Get hap file length failed! hapFile=%s", hapFilePath.c_str()); + return false; + } + if (!ZipUtils::GetFileContentFromZip(hapFilePath, MODULE_JSON, fileContent)) { + LOGE("Get module.json content from hap file failed! hapFile=%s", hapFilePath.c_str()); + return false; + } + if (!ZipUtils::GetResourceMapFromZip(hapFilePath, resourceMap)) { + LOGE("Get resouce map from hap file failed! hapFile=%s", hapFilePath.c_str()); + return false; + } + hapVerifyInfo.SetResourceMap(resourceMap); + hapVerifyInfo.SetProfileStr(fileContent); + hapVerifyInfo.SetStageModule(true); + hapVerifyInfo.SetFileLength(fileLength); + ModuleJson moduleJson; + if (!moduleJson.ParseFromString(fileContent)) { + LOGE("Parse json string failed!"); + return false; + } + if (!moduleJson.GetStageHapVerifyInfo(hapVerifyInfo)) { + LOGE("Get stage hap verify info failed!"); + return false; + } + return true; +} + +bool ModuleJsonUtils::GetFaHapVerifyInfo(const std::string& hapFilePath, HapVerifyInfo& hapVerifyInfo) +{ + if (MockMultiAppModuleJsonUtils::mockGetFaHapVerifyInfo_) { + const bool result = MockMultiAppModuleJsonUtils::mockGetFaHapVerifyInfoResultSeriesIter_->first; + hapVerifyInfo = MockMultiAppModuleJsonUtils::mockGetFaHapVerifyInfoResultSeriesIter_->second; + + const auto next = MockMultiAppModuleJsonUtils::mockGetFaHapVerifyInfoResultSeriesIter_ + 1; + if (next != MockMultiAppModuleJsonUtils::mockGetFaHapVerifyInfoResultSeries_.cend()) { + MockMultiAppModuleJsonUtils::mockGetFaHapVerifyInfoResultSeriesIter_ = next; + } + + return result; + } + + std::string fileContent; + int64_t fileLength = Utils::GetFileLength(hapFilePath); + if (fileLength < 0) { + LOGE("Get hap file length failed! hapFile=%s", hapFilePath.c_str()); + return false; + } + if (!ZipUtils::GetFileContentFromZip(hapFilePath, CONFIG_JSON, fileContent)) { + LOGE("Get module.json content from hap file failed! hapFile=%s", hapFilePath.c_str()); + return false; + } + ModuleJson moduleJson; + if (!moduleJson.ParseFromString(fileContent)) { + LOGE("Parse json string failed!"); + return false; + } + if (!moduleJson.GetFaHapVerifyInfo(hapVerifyInfo)) { + LOGE("Get FA hap verify info failed!"); + return false; + } + hapVerifyInfo.SetProfileStr(fileContent); + hapVerifyInfo.SetStageModule(false); + hapVerifyInfo.SetFileLength(fileLength); + return true; +} + +// java : Compressor::checkSharedAppIsValid / HapVerify::checkSharedApppIsValid +bool ModuleJsonUtils::CheckSharedAppIsValid(const std::list& hapVerifyInfos, bool& isOverlay) +{ + if (hapVerifyInfos.empty()) { + LOGE("hapVerifyInfos is empty"); + return false; + } + if (hapVerifyInfos.size() > SHARED_APP_HSP_LIMIT) { + LOGE("hapVerifyInfos size is over than %d", SHARED_APP_HSP_LIMIT); + return false; + } + for (auto& hapVerifyInfo : hapVerifyInfos) { + if (!hapVerifyInfo.GetTargetBundleName().empty()) { + isOverlay = true; + return true; + } + } + return HapVerifyUtils::CheckSharedAppIsValid(hapVerifyInfos); +} + +bool ModuleJsonUtils::GetHapVerifyInfosfromFileList(const std::list& fileList, + std::list& hapVerifyInfos) +{ + for (auto& hapPath : fileList) { + if (hapPath.empty()) { + LOGE("Hap file path is empty!"); + return false; + } + fs::path fsHapPath(hapPath); + std::string fileName = fsHapPath.filename().string(); + if (fileName.empty()) { + LOGE("Hap file name is empty!"); + return false; + } + std::transform(fileName.begin(), fileName.end(), fileName.begin(), ::tolower); + if (!Utils::EndsWith(fileName, HAP_SUFFIX) && !Utils::EndsWith(fileName, HSP_SUFFIX)) { + LOGE("Hap file is not a hap or hsp file!"); + return false; + } + HapVerifyInfo hapVerifyInfo; + if (IsModuleHap(hapPath)) { + if (!GetStageHapVerifyInfo(hapPath, hapVerifyInfo)) { + LOGE("GetStageHapVerifyInfo failed!"); + return false; + } + } else { + if (!GetFaHapVerifyInfo(hapPath, hapVerifyInfo)) { + LOGE("GetFaHapVerifyInfo failed!"); + return false; + } + } + hapVerifyInfos.push_back(hapVerifyInfo); + } + return true; +} + +bool ModuleJsonUtils::GetHapVerifyInfosMapfromFileList(const std::list& fileList, + std::map>& hapVerifyInfoMap) +{ + if (MockMultiAppModuleJsonUtils::mockGetHapVerifyInfosMapfromFileList_) { + return MockMultiAppModuleJsonUtils::mockGetHapVerifyInfosMapfromFileListResult_; + } + + for (auto& hapPath : fileList) { + if (hapPath.empty()) { + LOGE("Hap file path is empty!"); + return false; + } + fs::path fsHapPath(hapPath); + std::string fileName = fsHapPath.filename().string(); + if (fileName.empty()) { + LOGE("Hap file name is empty!"); + return false; + } + std::transform(fileName.begin(), fileName.end(), fileName.begin(), ::tolower); + if (!Utils::EndsWith(fileName, HAP_SUFFIX) && !Utils::EndsWith(fileName, HSP_SUFFIX)) { + LOGE("Hap file is not a hap or hsp file!"); + return false; + } + auto hapVerifyInfo = std::make_shared(); + if (IsModuleHap(hapPath)) { + if (!GetStageHapVerifyInfo(hapPath, *hapVerifyInfo)) { + LOGE("GetStageHapVerifyInfo failed"); + return false; + } + } else { + if (!GetFaHapVerifyInfo(hapPath, *hapVerifyInfo)) { + LOGE("GetFaHapVerifyInfo failed"); + return false; + } + } + hapVerifyInfoMap.emplace(fileName, hapVerifyInfo); + } + return true; +} + +bool ValidateParameters(const std::map& parameterMap) +{ + if (parameterMap.find(Constants::PARAM_MODE) == parameterMap.end() || + parameterMap.find(Constants::PARAM_OUT_PATH) == parameterMap.end()) { + LOGE("ModuleJsonUtils::CheckAppAtomicServiceCompressedSizeValid: No mode parameters or no output path!"); + return false; + } + return true; +} + +bool ShouldSkipValidation(const std::string& packMode) +{ + return packMode != Constants::MODE_APP && + packMode != Constants::MODE_FAST_APP && + packMode != Constants::MODE_MULTIAPP; +} + +bool ProcessZipFile(const std::string& outPath, + std::map>& hapVerifyInfoMap, + std::list& hapVerifyInfos) +{ + unzFile zipApp = unzOpen(outPath.c_str()); + if (!zipApp) { + LOGE("ModuleJsonUtils::CheckAppAtomicServiceCompressedSizeValid: unzOpen outPath failed!"); + return false; + } + + if (unzGoToFirstFile(zipApp) != UNZ_OK) { + unzClose(zipApp); + LOGE("ModuleJsonUtils::CheckAppAtomicServiceCompressedSizeValid: unzGoToFirstFile outPath failed!"); + return false; + } + + do { + unz_file_info fileInfo; + if (unzGetCurrentFileInfo(zipApp, &fileInfo, nullptr, 0, nullptr, 0, nullptr, 0) != UNZ_OK) { + unzClose(zipApp); + LOGE("ModuleJsonUtils::CheckAppAtomicServiceCompressedSizeValid: failed to get file info (phase 1)"); + return false; + } + + std::vector fileNameBuffer(fileInfo.size_filename + 1); + if (unzGetCurrentFileInfo(zipApp, &fileInfo, fileNameBuffer.data(), fileNameBuffer.size(), + nullptr, 0, nullptr, 0) != UNZ_OK) { + unzClose(zipApp); + LOGE("ModuleJsonUtils::CheckAppAtomicServiceCompressedSizeValid: failed to get file info (phase 2)"); + return false; + } + + std::string fileName(fileNameBuffer.data()); + auto it = hapVerifyInfoMap.find(fileName); + if (it == hapVerifyInfoMap.end() || it->second == nullptr) { + continue; + } + + it->second->SetFileLength(fileInfo.compressed_size); + hapVerifyInfos.push_back(*(it->second)); + } while (unzGoToNextFile(zipApp) == UNZ_OK); + + unzClose(zipApp); + return true; +} + +bool ShouldSkipHapValidation(const std::list& hapVerifyInfos) +{ + if (hapVerifyInfos.empty()) { + LOGI("ModuleJsonUtils::CheckAppAtomicServiceCompressedSizeValid: hapVerifyInfos is empty"); + return true; + } + std::string bundleType = hapVerifyInfos.front().GetBundleType(); + if (bundleType != Constants::ATOMIC_SERVICE) { + return true; + } + return !hapVerifyInfos.front().IsStageModule(); +} + +bool ModuleJsonUtils::CheckAppAtomicServiceCompressedSizeValid( + std::map parameterMap, + std::map>& hapVerifyInfoMap) +{ + if (MockMultiAppModuleJsonUtils::mockCheckAppAtomicServiceCompressedSizeValid_) { + return MockMultiAppModuleJsonUtils::mockCheckAppAtomicServiceCompressedSizeValidResult_; + } + + if (!ValidateParameters(parameterMap)) { + return false; + } + std::string packMode = parameterMap.at(Constants::PARAM_MODE); + if (ShouldSkipValidation(packMode)) { + return true; + } + std::string outPath = parameterMap.at(Constants::PARAM_OUT_PATH); + std::list hapVerifyInfos; + if (!ProcessZipFile(outPath, hapVerifyInfoMap, hapVerifyInfos)) { + return false; + } + if (ShouldSkipHapValidation(hapVerifyInfos)) { + return true; + } + return HapVerifyUtils::CheckFileSizeIsValid(hapVerifyInfos); +} + +// java : checkHapIsValid +bool ModuleJsonUtils::CheckHapsIsValid(const std::list& fileList, const bool& isSharedApp) +{ + if (MockMultiAppModuleJsonUtils::mockCheckHapsIsValid_) { + return MockMultiAppModuleJsonUtils::mockCheckHapsIsValidResult_; + } + + std::list hapVerifyInfos; + if (!GetHapVerifyInfosfromFileList(fileList, hapVerifyInfos)) { + LOGE("GetHapVerifyInfosfromFileList failed!"); + return false; + } + if (isSharedApp) { + bool isOverlay = false; + if (!CheckSharedAppIsValid(hapVerifyInfos, isOverlay)) { + LOGE("CheckSharedAppIsValid failed!"); + return false; + } + if (!isOverlay) { + return true; + } + } else { + for (auto& hapVerifyInfo : hapVerifyInfos) { + if (hapVerifyInfo.GetBundleType().compare(TYPE_SHARED) == 0) { + LOGE("bundle type cannot be %s when app is not shared", TYPE_SHARED.c_str()); + return false; + } + } + } + setAtomicServiceFileSizeLimit(hapVerifyInfos); + if (!HapVerifyUtils::CheckHapIsValid(hapVerifyInfos)) { + LOGE("CheckHapIsValid failed!"); + return false; + } + return true; +} + +bool ModuleJsonUtils::IsModuleHap(const std::string hapFilePath) +{ + if (MockMultiAppModuleJsonUtils::mockIsModuleHap_) { + return MockMultiAppModuleJsonUtils::mockIsModuleHapResult_; + } + + return ZipUtils::IsFileExistsInZip(hapFilePath, MODULE_JSON); +} + +void ModuleJsonUtils::setAtomicServiceFileSizeLimit(std::list& hapVerifyInfos) +{ + for (auto& hapVerifyInfo : hapVerifyInfos) { + if (hapVerifyInfo.GetBundleType().compare(ATOMIC_SERVICE) == 0) { + hapVerifyInfo.SetEntrySizeLimit(g_entryModuleSizeLimit); + hapVerifyInfo.SetNotEntrySizeLimit(g_notEntryModuleSizeLimit); + hapVerifyInfo.SetSumSizeLimit(g_sumModuleSizeLimit); + } + } +} +} // namespace AppPackingTool +} // namespace OHOS diff --git a/packing_tool/frameworks/test/unittest/multiapp_packager_test/mock/mock_multiapp_module_json_utils.h b/packing_tool/frameworks/test/unittest/multiapp_packager_test/mock/mock_multiapp_module_json_utils.h new file mode 100644 index 0000000000000000000000000000000000000000..1881f97170192de3690529f8a5e1bb110a6af44b --- /dev/null +++ b/packing_tool/frameworks/test/unittest/multiapp_packager_test/mock/mock_multiapp_module_json_utils.h @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MOCK_MULTIAPP_MODULE_JSON_UTILS_H +#define MOCK_MULTIAPP_MODULE_JSON_UTILS_H + +#include +#include "hap_verify_info.h" + +namespace OHOS { + +using namespace OHOS::AppPackingTool; +using ResultSeries = std::vector>; + +class MockMultiAppModuleJsonUtils { +public: + static bool mockGetStageHapVerifyInfo_; + static bool mockGetFaHapVerifyInfo_; + static bool mockCheckHapsIsValid_; + static bool mockIsModuleHap_; + static bool mockCheckHapsIsValidResult_; + static bool mockIsModuleHapResult_; + static bool mockCheckAppAtomicServiceCompressedSizeValid_; + static bool mockCheckAppAtomicServiceCompressedSizeValidResult_; + static bool mockGetHapVerifyInfosMapfromFileList_; + static bool mockGetHapVerifyInfosMapfromFileListResult_; + static ResultSeries mockGetStageHapVerifyInfoResultSeries_; + static ResultSeries::const_iterator mockGetStageHapVerifyInfoResultSeriesIter_; + static ResultSeries mockGetFaHapVerifyInfoResultSeries_; + static ResultSeries::const_iterator mockGetFaHapVerifyInfoResultSeriesIter_; + +public: + static void Reset() + { + mockGetStageHapVerifyInfo_ = false; + mockGetFaHapVerifyInfo_ = false; + mockCheckHapsIsValid_ = false; + mockIsModuleHap_ = false; + mockCheckHapsIsValidResult_ = false; + mockIsModuleHapResult_ = false; + mockCheckAppAtomicServiceCompressedSizeValid_ = false; + mockCheckAppAtomicServiceCompressedSizeValidResult_ = false; + mockGetHapVerifyInfosMapfromFileList_ = false; + mockGetHapVerifyInfosMapfromFileListResult_ = false; + mockGetStageHapVerifyInfoResultSeries_.clear(); + mockGetStageHapVerifyInfoResultSeriesIter_ = mockGetStageHapVerifyInfoResultSeries_.cbegin(); + mockGetFaHapVerifyInfoResultSeries_.clear(); + mockGetFaHapVerifyInfoResultSeriesIter_ = mockGetStageHapVerifyInfoResultSeries_.cbegin(); + } + + static void MockGetStageHapVerifyInfo(const ResultSeries& resultSeries) + { + mockGetStageHapVerifyInfo_ = true; + mockGetStageHapVerifyInfoResultSeries_ = resultSeries; + mockGetStageHapVerifyInfoResultSeriesIter_ = mockGetStageHapVerifyInfoResultSeries_.cbegin(); + } + + static void MockGetStageHapVerifyInfo(const bool result, const HapVerifyInfo& hapVerifyInfo) + { + ResultSeries series; + series.emplace_back(result, hapVerifyInfo); + MockGetStageHapVerifyInfo(series); + } + + static void MockGetFaHapVerifyInfo(const ResultSeries& resultSeries) + { + mockGetFaHapVerifyInfo_ = true; + mockGetFaHapVerifyInfoResultSeries_ = resultSeries; + mockGetFaHapVerifyInfoResultSeriesIter_ = mockGetStageHapVerifyInfoResultSeries_.cbegin(); + } + + static void MockGetFaHapVerifyInfo(const bool result, const HapVerifyInfo& hapVerifyInfo) + { + ResultSeries series; + series.emplace_back(result, hapVerifyInfo); + MockGetFaHapVerifyInfo(series); + } + + static void MockCheckHapsIsValid(const bool result) + { + mockCheckHapsIsValid_ = true; + mockCheckHapsIsValidResult_ = result; + } + + static void MockIsModuleHap(const bool result) + { + mockIsModuleHap_ = true; + mockIsModuleHapResult_ = result; + } + + static void MockCheckAppAtomicServiceCompressedSizeValid(const bool result) + { + mockCheckAppAtomicServiceCompressedSizeValid_ = true; + mockCheckAppAtomicServiceCompressedSizeValidResult_ = result; + } + + static void MockGetHapVerifyInfosMapfromFileList(const bool result) + { + mockGetHapVerifyInfosMapfromFileList_ = true; + mockGetHapVerifyInfosMapfromFileListResult_ = result; + } +}; +} // namespace OHOS +#endif // MOCK_MULTIAPP_MODULE_JSON_UTILS_H \ No newline at end of file diff --git a/packing_tool/frameworks/test/unittest/multiapp_packager_test/multiapp_packager_test.cpp b/packing_tool/frameworks/test/unittest/multiapp_packager_test/multiapp_packager_test.cpp index 6e5053ed0a1f2be7b51af33077a5ab8ef2c6a63d..fb982474dfacf39a51b6ea69c6b451805b6202a2 100644 --- a/packing_tool/frameworks/test/unittest/multiapp_packager_test/multiapp_packager_test.cpp +++ b/packing_tool/frameworks/test/unittest/multiapp_packager_test/multiapp_packager_test.cpp @@ -22,6 +22,7 @@ #define protected public #include "packager.h" #include "multiapp_packager.h" +#include "mock/mock_multiapp_module_json_utils.h" #include "zip_wrapper.h" #include "zip_utils.h" #include "log.h" @@ -107,6 +108,8 @@ HWTEST_F(MultiAppPackagerTest, MultiAppPackager_0100, Function | MediumTest | Le }; OHOS::AppPackingTool::MultiAppPackager multiAppPackager(parameterMap, resultReceiver); + MockMultiAppModuleJsonUtils::MockCheckAppAtomicServiceCompressedSizeValid(true); + MockMultiAppModuleJsonUtils::MockGetHapVerifyInfosMapfromFileList(true); EXPECT_EQ(multiAppPackager.InitAllowedParam(), 0); EXPECT_EQ(multiAppPackager.PreProcess(), 0); EXPECT_EQ(multiAppPackager.Process(), 0); @@ -300,6 +303,8 @@ HWTEST_F(MultiAppPackagerTest, PreProcess_1000, Function | MediumTest | Level1) }; OHOS::AppPackingTool::MultiAppPackager multiAppPackager(parameterMap, resultReceiver); + MockMultiAppModuleJsonUtils::MockCheckAppAtomicServiceCompressedSizeValid(true); + MockMultiAppModuleJsonUtils::MockGetHapVerifyInfosMapfromFileList(true); EXPECT_EQ(multiAppPackager.PreProcess(), 1); } @@ -381,6 +386,8 @@ HWTEST_F(MultiAppPackagerTest, PreProcess_1400, Function | MediumTest | Level1) }; OHOS::AppPackingTool::MultiAppPackager multiAppPackager(parameterMap, resultReceiver); + MockMultiAppModuleJsonUtils::MockCheckAppAtomicServiceCompressedSizeValid(true); + MockMultiAppModuleJsonUtils::MockGetHapVerifyInfosMapfromFileList(true); EXPECT_EQ(multiAppPackager.PreProcess(), 1); EXPECT_EQ(multiAppPackager.CompressAppModeForMultiProject(), true); } @@ -425,6 +432,8 @@ HWTEST_F(MultiAppPackagerTest, PreProcess_1600, Function | MediumTest | Level1) }; OHOS::AppPackingTool::MultiAppPackager multiAppPackager(parameterMap, resultReceiver); + MockMultiAppModuleJsonUtils::MockCheckAppAtomicServiceCompressedSizeValid(true); + MockMultiAppModuleJsonUtils::MockGetHapVerifyInfosMapfromFileList(true); EXPECT_EQ(multiAppPackager.PreProcess(), 1); EXPECT_EQ(multiAppPackager.CompressAppModeForMultiProject(), true); }