From e47f98f225d847ee09fc5b3a5cfe0445bdff93ca Mon Sep 17 00:00:00 2001 From: liuzongze Date: Fri, 10 Apr 2026 12:45:09 +0800 Subject: [PATCH] LibrarySupportDirectory Signed-off-by: liuzongze Change-Id: I8e70f42fe399c1d33b4c54dc9b4a6af8bf3b3e67 --- frameworks/native/appkit/app/main_thread.cpp | 1 + .../native/appkit/app/native_lib_util.cpp | 27 ++ .../native/runtime/ets_native_lib_util.cpp | 27 ++ .../runtime/include/ets_native_lib_util.h | 4 + .../kits/native/appkit/app/native_lib_util.h | 5 + .../BUILD.gn | 38 +++ .../ets_native_lib_util_test.cpp | 242 ++++++++++++++++++ .../native_lib_util_test.cpp | 202 ++++++++++++++- 8 files changed, 541 insertions(+), 5 deletions(-) create mode 100644 test/unittest/frameworks_kits_appkit_native_test/ets_native_lib_util_test.cpp diff --git a/frameworks/native/appkit/app/main_thread.cpp b/frameworks/native/appkit/app/main_thread.cpp index 62b1da0c80..1cacdc65d8 100644 --- a/frameworks/native/appkit/app/main_thread.cpp +++ b/frameworks/native/appkit/app/main_thread.cpp @@ -256,6 +256,7 @@ void MainThread::GetNativeLibPath(const BundleInfo &bundleInfo, const HspList &h } else { TAG_LOGI(AAFwkTag::APPKIT, "NativeLibPath empty"); } + GetLibrarySupportDirectory(bundleInfo.hapModuleInfos, nativeLibraryPath, appLibPaths); for (auto &hapInfo : bundleInfo.hapModuleInfos) { TAG_LOGD(AAFwkTag::APPKIT, diff --git a/frameworks/native/appkit/app/native_lib_util.cpp b/frameworks/native/appkit/app/native_lib_util.cpp index 152562ab11..4b49b22224 100644 --- a/frameworks/native/appkit/app/native_lib_util.cpp +++ b/frameworks/native/appkit/app/native_lib_util.cpp @@ -75,6 +75,14 @@ void GetHspNativeLibPath(const BaseSharedBundleInfo &hspInfo, AppLibPathMap &app TAG_LOGD( AAFwkTag::APPKIT, "appLibPathKey: %{private}s, libPath: %{private}s", appLibPathKey.c_str(), libPath.c_str()); appLibPaths[appLibPathKey].emplace_back(libPath); + + if (!hspInfo.librarySupportDirectory.empty()) { + for (const auto &dir : hspInfo.librarySupportDirectory) { + std::string supportLibPath = libPath + "/" + dir; + TAG_LOGD(AAFwkTag::APPKIT, "supportLibPath: %{public}s", supportLibPath.c_str()); + appLibPaths["default"].emplace_back(supportLibPath); + } + } } void GetPatchNativeLibPath(const HapModuleInfo &hapInfo, std::string &patchNativeLibraryPath, @@ -102,5 +110,24 @@ void GetPatchNativeLibPath(const HapModuleInfo &hapInfo, std::string &patchNativ patchLibPath.c_str()); appLibPaths[appLibPathKey].emplace_back(patchLibPath); } + +void GetLibrarySupportDirectory( + const std::vector &hapModuleInfos, + const std::string nativeLibraryPath, + AppLibPathMap &appLibPaths) +{ + std::string libPath = AbilityBase::Constants::LOCAL_CODE_PATH; + libPath += (libPath.back() == '/') ? nativeLibraryPath : "/" + nativeLibraryPath; + for (auto &hapInfo : hapModuleInfos) { + if (hapInfo.librarySupportDirectory.empty()) { + continue; + } + for (const auto &dir : hapInfo.librarySupportDirectory) { + std::string supportLibPath = libPath + "/" + dir; + TAG_LOGD(AAFwkTag::APPKIT, "supportLibPath: %{public}s", supportLibPath.c_str()); + appLibPaths["default"].emplace_back(supportLibPath); + } + } +} } // AppExecFwk } // namespace OHOS \ No newline at end of file diff --git a/frameworks/native/runtime/ets_native_lib_util.cpp b/frameworks/native/runtime/ets_native_lib_util.cpp index d73236e0d2..a44b38817d 100644 --- a/frameworks/native/runtime/ets_native_lib_util.cpp +++ b/frameworks/native/runtime/ets_native_lib_util.cpp @@ -83,6 +83,13 @@ void GetEtsHspNativeLibPath(const BaseSharedBundleInfo &hspInfo, AppLibPathMap & TAG_LOGD( AAFwkTag::APPKIT, "appLibPathKey: %{private}s, libPath: %{private}s", appLibPathKey.c_str(), libPath.c_str()); appLibPaths[appLibPathKey].emplace_back(libPath); + if (!hspInfo.librarySupportDirectory.empty()) { + for (const auto &dir : hspInfo.librarySupportDirectory) { + std::string supportLibPath = libPath + "/" + dir; + TAG_LOGD(AAFwkTag::APPKIT, "supportLibPath: %{public}s", supportLibPath.c_str()); + appLibPaths["default"].emplace_back(supportLibPath); + } + } if (!appBundleName.empty()) { const bool isInternalHsp = (hspInfo.bundleName == appBundleName); @@ -142,6 +149,7 @@ void GetEtsNativeLibPath(const BundleInfo &bundleInfo, const std::vector &hapModuleInfos, + const std::string nativeLibraryPath, + AppLibPathMap &appLibPaths) +{ + std::string libPath = AbilityBase::Constants::LOCAL_CODE_PATH; + libPath += (libPath.back() == '/') ? nativeLibraryPath : "/" + nativeLibraryPath; + for (auto &hapInfo : hapModuleInfos) { + if (hapInfo.librarySupportDirectory.empty()) { + continue; + } + for (const auto &dir : hapInfo.librarySupportDirectory) { + std::string supportLibPath = libPath + "/" + dir; + TAG_LOGD(AAFwkTag::APPKIT, "supportLibPath: %{public}s", supportLibPath.c_str()); + appLibPaths["default"].emplace_back(supportLibPath); + } + } +} } // AppExecFwk } // namespace OHOS \ No newline at end of file diff --git a/interfaces/inner_api/runtime/include/ets_native_lib_util.h b/interfaces/inner_api/runtime/include/ets_native_lib_util.h index 449d45676f..63007c8228 100644 --- a/interfaces/inner_api/runtime/include/ets_native_lib_util.h +++ b/interfaces/inner_api/runtime/include/ets_native_lib_util.h @@ -38,6 +38,10 @@ void GetEtsPatchNativeLibPath(const HapModuleInfo &hapInfo, std::string &patchNa void GetEtsNativeLibPath(const BundleInfo &bundleInfo, const std::vector &hspList, AppLibPathMap &appLibPaths, std::map &abcPathsToBundleModuleNameMap); +void GetLibrarySupportDirectory( + const std::vector &hapModuleInfos, + const std::string nativeLibraryPath, + AppLibPathMap &appLibPaths); } // namespace AppExecFwk } // namespace OHOS #endif // OHOS_ABILITY_RUNTIME_ETS_NATIVE_LIB_UTIL_H diff --git a/interfaces/kits/native/appkit/app/native_lib_util.h b/interfaces/kits/native/appkit/app/native_lib_util.h index 2bfd80626b..4391f91362 100644 --- a/interfaces/kits/native/appkit/app/native_lib_util.h +++ b/interfaces/kits/native/appkit/app/native_lib_util.h @@ -32,6 +32,11 @@ void GetHspNativeLibPath(const BaseSharedBundleInfo &hspInfo, AppLibPathMap &app void GetPatchNativeLibPath(const HapModuleInfo &hapInfo, std::string &patchNativeLibraryPath, AppLibPathMap &appLibPaths); + +void GetLibrarySupportDirectory( + const std::vector &hapModuleInfos, + const std::string nativeLibraryPath, + AppLibPathMap &appLibPaths); } // namespace AppExecFwk } // namespace OHOS #endif // OHOS_ABILITY_RUNTIME_NATIVE_LIB_UTIL_H diff --git a/test/unittest/frameworks_kits_appkit_native_test/BUILD.gn b/test/unittest/frameworks_kits_appkit_native_test/BUILD.gn index 1e664cd616..c95a3b42ef 100644 --- a/test/unittest/frameworks_kits_appkit_native_test/BUILD.gn +++ b/test/unittest/frameworks_kits_appkit_native_test/BUILD.gn @@ -1137,6 +1137,43 @@ ohos_unittest("native_lib_util_test") { ] } +ohos_unittest("ets_native_lib_util_test") { + sanitize = { + cfi = true + cfi_cross_dso = true + debug = false + blocklist = "../../cfi_blocklist.txt" + } + include_dirs = [] + module_out_path = module_output_path + + sources = [ + "${ability_runtime_native_path}/runtime/ets_native_lib_util.cpp", + "ets_native_lib_util_test.cpp", + ] + + configs = [ ":module_context_config" ] + + deps = [ + "${ability_runtime_innerkits_path}/app_manager:app_manager", + "${ability_runtime_innerkits_path}/runtime:runtime", + "${ability_runtime_napi_path}/inner/napi_common:napi_common", + "${ability_runtime_native_path}/appkit:appkit_native", + "${ability_runtime_services_path}/common:app_util", + ] + + external_deps = [ + "ability_base:extractresourcemanager", + "c_utils:utils", + "faultloggerd:libfaultloggerd", + "googletest:gtest_main", + "hilog:libhilog", + "hisysevent:libhisysevent", + "ipc:ipc_core", + "napi:ace_napi", + ] +} + ohos_unittest("application_cleaner_test") { sanitize = { cfi = true @@ -1374,6 +1411,7 @@ group("unittest") { ":idle_time_test", ":js_environment_callback_test", ":native_lib_util_test", + ":ets_native_lib_util_test", ":overlay_event_subscriber_test", ":startup_manager_mock_test", ":startup_manager_test", diff --git a/test/unittest/frameworks_kits_appkit_native_test/ets_native_lib_util_test.cpp b/test/unittest/frameworks_kits_appkit_native_test/ets_native_lib_util_test.cpp new file mode 100644 index 0000000000..6264518f0f --- /dev/null +++ b/test/unittest/frameworks_kits_appkit_native_test/ets_native_lib_util_test.cpp @@ -0,0 +1,242 @@ +/* + * Copyright (c) 2026 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 + +#include "ets_native_lib_util.h" + +using namespace testing::ext; + +namespace OHOS { +namespace AppExecFwk { +class EtsNativeLibUtilTest : public testing::Test { +public: + EtsNativeLibUtilTest() + {} + ~EtsNativeLibUtilTest() + {} + static void SetUpTestCase(void); + static void TearDownTestCase(void); + void SetUp(); + void TearDown(); +}; + +void EtsNativeLibUtilTest::SetUpTestCase(void) +{} + +void EtsNativeLibUtilTest::TearDownTestCase(void) +{} + +void EtsNativeLibUtilTest::SetUp(void) +{} + +void EtsNativeLibUtilTest::TearDown(void) +{} + +/** + * @tc.number: EtsGetLibrarySupportDirectory_0100 + * @tc.name: GetLibrarySupportDirectory for ets + * @tc.desc: Test with empty hapModuleInfos, no paths should be added. + */ +HWTEST_F(EtsNativeLibUtilTest, EtsGetLibrarySupportDirectory_0100, TestSize.Level1) +{ + std::vector hapModuleInfos; + std::string nativeLibraryPath = "libs/arm"; + AppLibPathMap appLibPaths; + GetLibrarySupportDirectory(hapModuleInfos, nativeLibraryPath, appLibPaths); + EXPECT_TRUE(appLibPaths.empty()); +} + +/** + * @tc.number: EtsGetLibrarySupportDirectory_0200 + * @tc.name: GetLibrarySupportDirectory for ets + * @tc.desc: Test with hapModuleInfo that has empty librarySupportDirectory, no paths should be added. + */ +HWTEST_F(EtsNativeLibUtilTest, EtsGetLibrarySupportDirectory_0200, TestSize.Level1) +{ + std::vector hapModuleInfos; + HapModuleInfo hapInfo; + hapInfo.librarySupportDirectory = {}; + hapModuleInfos.push_back(hapInfo); + std::string nativeLibraryPath = "libs/arm"; + AppLibPathMap appLibPaths; + GetLibrarySupportDirectory(hapModuleInfos, nativeLibraryPath, appLibPaths); + EXPECT_TRUE(appLibPaths.empty()); +} + +/** + * @tc.number: EtsGetLibrarySupportDirectory_0300 + * @tc.name: GetLibrarySupportDirectory for ets + * @tc.desc: Test with a single hapModuleInfo that has one librarySupportDirectory entry, + * verify exact path value. + */ +HWTEST_F(EtsNativeLibUtilTest, EtsGetLibrarySupportDirectory_0300, TestSize.Level1) +{ + std::vector hapModuleInfos; + HapModuleInfo hapInfo; + hapInfo.librarySupportDirectory = {"subdir1"}; + hapModuleInfos.push_back(hapInfo); + std::string nativeLibraryPath = "libs/arm"; + AppLibPathMap appLibPaths; + GetLibrarySupportDirectory(hapModuleInfos, nativeLibraryPath, appLibPaths); + + ASSERT_EQ(appLibPaths.count("default"), 1u); + ASSERT_EQ(appLibPaths["default"].size(), 1u); + EXPECT_EQ(appLibPaths["default"][0], "/data/storage/el1/bundle/libs/arm/subdir1"); +} + +/** + * @tc.number: EtsGetLibrarySupportDirectory_0400 + * @tc.name: GetLibrarySupportDirectory for ets + * @tc.desc: Test with a single hapModuleInfo that has multiple librarySupportDirectory entries, + * verify exact path values. + */ +HWTEST_F(EtsNativeLibUtilTest, EtsGetLibrarySupportDirectory_0400, TestSize.Level1) +{ + std::vector hapModuleInfos; + HapModuleInfo hapInfo; + hapInfo.librarySupportDirectory = {"subdir1", "subdir2", "subdir3"}; + hapModuleInfos.push_back(hapInfo); + std::string nativeLibraryPath = "libs/arm"; + AppLibPathMap appLibPaths; + GetLibrarySupportDirectory(hapModuleInfos, nativeLibraryPath, appLibPaths); + + ASSERT_EQ(appLibPaths.count("default"), 1u); + ASSERT_EQ(appLibPaths["default"].size(), 3u); + EXPECT_EQ(appLibPaths["default"][0], "/data/storage/el1/bundle/libs/arm/subdir1"); + EXPECT_EQ(appLibPaths["default"][1], "/data/storage/el1/bundle/libs/arm/subdir2"); + EXPECT_EQ(appLibPaths["default"][2], "/data/storage/el1/bundle/libs/arm/subdir3"); +} + +/** + * @tc.number: EtsGetLibrarySupportDirectory_0500 + * @tc.name: GetLibrarySupportDirectory for ets + * @tc.desc: Test with multiple hapModuleInfos. Only those with non-empty librarySupportDirectory + * should contribute paths. Verify exact count and path content. + */ +HWTEST_F(EtsNativeLibUtilTest, EtsGetLibrarySupportDirectory_0500, TestSize.Level1) +{ + std::vector hapModuleInfos; + HapModuleInfo hapInfo1; + hapInfo1.librarySupportDirectory = {"dirA"}; + hapModuleInfos.push_back(hapInfo1); + + HapModuleInfo hapInfo2; + hapInfo2.librarySupportDirectory = {}; + hapModuleInfos.push_back(hapInfo2); + + HapModuleInfo hapInfo3; + hapInfo3.librarySupportDirectory = {"dirB", "dirC"}; + hapModuleInfos.push_back(hapInfo3); + + std::string nativeLibraryPath = "libs/arm"; + AppLibPathMap appLibPaths; + GetLibrarySupportDirectory(hapModuleInfos, nativeLibraryPath, appLibPaths); + + ASSERT_EQ(appLibPaths.count("default"), 1u); + ASSERT_EQ(appLibPaths["default"].size(), 3u); + EXPECT_EQ(appLibPaths["default"][0], "/data/storage/el1/bundle/libs/arm/dirA"); + EXPECT_EQ(appLibPaths["default"][1], "/data/storage/el1/bundle/libs/arm/dirB"); + EXPECT_EQ(appLibPaths["default"][2], "/data/storage/el1/bundle/libs/arm/dirC"); +} + +/** + * @tc.number: EtsGetLibrarySupportDirectory_0600 + * @tc.name: GetLibrarySupportDirectory for ets + * @tc.desc: Test that generated path equals expected full path. + */ +HWTEST_F(EtsNativeLibUtilTest, EtsGetLibrarySupportDirectory_0600, TestSize.Level1) +{ + std::vector hapModuleInfos; + HapModuleInfo hapInfo; + hapInfo.librarySupportDirectory = {"support"}; + hapModuleInfos.push_back(hapInfo); + std::string nativeLibraryPath = "libs/arm"; + AppLibPathMap appLibPaths; + GetLibrarySupportDirectory(hapModuleInfos, nativeLibraryPath, appLibPaths); + + ASSERT_EQ(appLibPaths["default"].size(), 1u); + EXPECT_EQ(appLibPaths["default"][0], "/data/storage/el1/bundle/libs/arm/support"); +} + +/** + * @tc.number: EtsGetHspNativeLibPath_WithSupportDirectory_0700 + * @tc.name: GetEtsHspNativeLibPath with librarySupportDirectory + * @tc.desc: Test that GetEtsHspNativeLibPath adds support directory paths under "default" key + * when librarySupportDirectory is set. + */ +HWTEST_F(EtsNativeLibUtilTest, EtsGetHspNativeLibPath_WithSupportDirectory_0700, TestSize.Level1) +{ + BaseSharedBundleInfo hspInfo; + AppLibPathMap appLibPaths; + bool isPreInstallApp = true; + std::string appBundleName = "com.test.app"; + std::map abcPathsToBundleModuleNameMap; + + hspInfo.bundleName = "com.test.hspbundle"; + hspInfo.moduleName = "hsplib"; + hspInfo.hapPath = "/data/storage/el1/bundle/com.test.hspbundle/hsplib.hsp"; + hspInfo.nativeLibraryPath = "libs/arm"; + hspInfo.compressNativeLibs = false; + hspInfo.librarySupportDirectory = {"support1", "support2"}; + + GetEtsHspNativeLibPath(hspInfo, appLibPaths, isPreInstallApp, appBundleName, abcPathsToBundleModuleNameMap); + + // Verify the main HSP lib path exists + std::string key = "com.test.hspbundle/hsplib"; + ASSERT_EQ(appLibPaths.count(key), 1u); + ASSERT_EQ(appLibPaths[key].size(), 1u); + EXPECT_EQ(appLibPaths[key][0], "/data/storage/el1/bundle/com.test.hspbundle/libs/arm"); + + // Verify "default" has exactly 2 support directory paths + ASSERT_EQ(appLibPaths.count("default"), 1u); + ASSERT_EQ(appLibPaths["default"].size(), 2u); + EXPECT_EQ(appLibPaths["default"][0], + "/data/storage/el1/bundle/com.test.hspbundle/libs/arm/support1"); + EXPECT_EQ(appLibPaths["default"][1], + "/data/storage/el1/bundle/com.test.hspbundle/libs/arm/support2"); +} + +/** + * @tc.number: EtsGetHspNativeLibPath_NoSupportDirectory_0800 + * @tc.name: GetEtsHspNativeLibPath without librarySupportDirectory + * @tc.desc: Test that GetEtsHspNativeLibPath does not add "default" entry + * when librarySupportDirectory is empty. + */ +HWTEST_F(EtsNativeLibUtilTest, EtsGetHspNativeLibPath_NoSupportDirectory_0800, TestSize.Level1) +{ + BaseSharedBundleInfo hspInfo; + AppLibPathMap appLibPaths; + bool isPreInstallApp = true; + std::string appBundleName = "com.test.app"; + std::map abcPathsToBundleModuleNameMap; + + hspInfo.bundleName = "com.test.hspbundle"; + hspInfo.moduleName = "hsplib"; + hspInfo.hapPath = "/data/storage/el1/bundle/com.test.hspbundle/hsplib.hsp"; + hspInfo.nativeLibraryPath = "libs/arm"; + hspInfo.compressNativeLibs = false; + hspInfo.librarySupportDirectory = {}; + + GetEtsHspNativeLibPath(hspInfo, appLibPaths, isPreInstallApp, appBundleName, abcPathsToBundleModuleNameMap); + + std::string key = "com.test.hspbundle/hsplib"; + ASSERT_EQ(appLibPaths.count(key), 1u); + ASSERT_EQ(appLibPaths[key].size(), 1u); + EXPECT_EQ(appLibPaths[key][0], "/data/storage/el1/bundle/com.test.hspbundle/libs/arm"); + EXPECT_EQ(appLibPaths.count("default"), 0u); +} +} // namespace AppExecFwk +} // namespace OHOS diff --git a/test/unittest/frameworks_kits_appkit_native_test/native_lib_util_test.cpp b/test/unittest/frameworks_kits_appkit_native_test/native_lib_util_test.cpp index e85fb12e0f..b961f2ed42 100644 --- a/test/unittest/frameworks_kits_appkit_native_test/native_lib_util_test.cpp +++ b/test/unittest/frameworks_kits_appkit_native_test/native_lib_util_test.cpp @@ -92,7 +92,7 @@ HWTEST_F(NativeLibUtilTest, GetHspNativeLibPath_0300, TestSize.Level1) hspInfo.nativeLibraryPath = ""; AppExecFwk::GetHspNativeLibPath(hspInfo, appLibPaths, isPreInstallApp); EXPECT_EQ(appLibPaths.empty(), true); - + hspInfo.nativeLibraryPath = "/data/test/nativeLibraryPath"; hspInfo.bundleName = "nativeLibraryTest"; hspInfo.moduleName = "library"; @@ -105,7 +105,7 @@ HWTEST_F(NativeLibUtilTest, GetHspNativeLibPath_0300, TestSize.Level1) isPreInstallApp = false; AppExecFwk::GetHspNativeLibPath(hspInfo, appLibPaths, isPreInstallApp); EXPECT_EQ(appLibPaths.empty(), false); - + appLibPaths.clear(); hspInfo.compressNativeLibs = true; AppExecFwk::GetHspNativeLibPath(hspInfo, appLibPaths, isPreInstallApp); @@ -122,12 +122,12 @@ HWTEST_F(NativeLibUtilTest, GetPatchNativeLibPath_0400, TestSize.Level1) AppExecFwk::HapModuleInfo hapInfo; std::string patchNativeLibraryPath = ""; AppLibPathMap appLibPaths; - + hapInfo.hapPath = "/data/test/NativeLibUtilTest.hap"; hapInfo.isLibIsolated = false; AppExecFwk::GetPatchNativeLibPath(hapInfo, patchNativeLibraryPath, appLibPaths); EXPECT_EQ(patchNativeLibraryPath, ""); - + hapInfo.compressNativeLibs = true; patchNativeLibraryPath = "/data/test/patchNativeLibraryPath"; AppExecFwk::GetPatchNativeLibPath(hapInfo, patchNativeLibraryPath, appLibPaths); @@ -141,5 +141,197 @@ HWTEST_F(NativeLibUtilTest, GetPatchNativeLibPath_0400, TestSize.Level1) AppExecFwk::GetPatchNativeLibPath(hapInfo, patchNativeLibraryPath, appLibPaths); EXPECT_EQ(appLibPaths.empty(), false); } -} // namespace AbilityRuntime + +/** + * @tc.number: GetLibrarySupportDirectory_0100 + * @tc.name: GetLibrarySupportDirectory + * @tc.desc: Test with empty hapModuleInfos, no paths should be added. + */ +HWTEST_F(NativeLibUtilTest, GetLibrarySupportDirectory_0100, TestSize.Level1) +{ + std::vector hapModuleInfos; + std::string nativeLibraryPath = "libs/arm"; + AppLibPathMap appLibPaths; + AppExecFwk::GetLibrarySupportDirectory(hapModuleInfos, nativeLibraryPath, appLibPaths); + EXPECT_TRUE(appLibPaths.empty()); +} + +/** + * @tc.number: GetLibrarySupportDirectory_0200 + * @tc.name: GetLibrarySupportDirectory + * @tc.desc: Test with hapModuleInfo that has empty librarySupportDirectory, no paths should be added. + */ +HWTEST_F(NativeLibUtilTest, GetLibrarySupportDirectory_0200, TestSize.Level1) +{ + std::vector hapModuleInfos; + AppExecFwk::HapModuleInfo hapInfo; + hapInfo.librarySupportDirectory = {}; + hapModuleInfos.push_back(hapInfo); + std::string nativeLibraryPath = "libs/arm"; + AppLibPathMap appLibPaths; + AppExecFwk::GetLibrarySupportDirectory(hapModuleInfos, nativeLibraryPath, appLibPaths); + EXPECT_TRUE(appLibPaths.empty()); +} + +/** + * @tc.number: GetLibrarySupportDirectory_0300 + * @tc.name: GetLibrarySupportDirectory + * @tc.desc: Test with a single hapModuleInfo that has one librarySupportDirectory entry, + * verify exact path value. + */ +HWTEST_F(NativeLibUtilTest, GetLibrarySupportDirectory_0300, TestSize.Level1) +{ + std::vector hapModuleInfos; + AppExecFwk::HapModuleInfo hapInfo; + hapInfo.librarySupportDirectory = {"subdir1"}; + hapModuleInfos.push_back(hapInfo); + std::string nativeLibraryPath = "libs/arm"; + AppLibPathMap appLibPaths; + AppExecFwk::GetLibrarySupportDirectory(hapModuleInfos, nativeLibraryPath, appLibPaths); + + ASSERT_EQ(appLibPaths.count("default"), 1u); + ASSERT_EQ(appLibPaths["default"].size(), 1u); + EXPECT_EQ(appLibPaths["default"][0], "/data/storage/el1/bundle/libs/arm/subdir1"); +} + +/** + * @tc.number: GetLibrarySupportDirectory_0400 + * @tc.name: GetLibrarySupportDirectory + * @tc.desc: Test with a single hapModuleInfo that has multiple librarySupportDirectory entries, + * verify exact path values. + */ +HWTEST_F(NativeLibUtilTest, GetLibrarySupportDirectory_0400, TestSize.Level1) +{ + std::vector hapModuleInfos; + AppExecFwk::HapModuleInfo hapInfo; + hapInfo.librarySupportDirectory = {"subdir1", "subdir2", "subdir3"}; + hapModuleInfos.push_back(hapInfo); + std::string nativeLibraryPath = "libs/arm"; + AppLibPathMap appLibPaths; + AppExecFwk::GetLibrarySupportDirectory(hapModuleInfos, nativeLibraryPath, appLibPaths); + + ASSERT_EQ(appLibPaths.count("default"), 1u); + ASSERT_EQ(appLibPaths["default"].size(), 3u); + EXPECT_EQ(appLibPaths["default"][0], "/data/storage/el1/bundle/libs/arm/subdir1"); + EXPECT_EQ(appLibPaths["default"][1], "/data/storage/el1/bundle/libs/arm/subdir2"); + EXPECT_EQ(appLibPaths["default"][2], "/data/storage/el1/bundle/libs/arm/subdir3"); +} + +/** + * @tc.number: GetLibrarySupportDirectory_0500 + * @tc.name: GetLibrarySupportDirectory + * @tc.desc: Test with multiple hapModuleInfos. Only those with non-empty librarySupportDirectory + * should contribute paths. Verify exact count and path content. + */ +HWTEST_F(NativeLibUtilTest, GetLibrarySupportDirectory_0500, TestSize.Level1) +{ + std::vector hapModuleInfos; + AppExecFwk::HapModuleInfo hapInfo1; + hapInfo1.librarySupportDirectory = {"dirA"}; + hapModuleInfos.push_back(hapInfo1); + + AppExecFwk::HapModuleInfo hapInfo2; + hapInfo2.librarySupportDirectory = {}; + hapModuleInfos.push_back(hapInfo2); + + AppExecFwk::HapModuleInfo hapInfo3; + hapInfo3.librarySupportDirectory = {"dirB", "dirC"}; + hapModuleInfos.push_back(hapInfo3); + + std::string nativeLibraryPath = "libs/arm"; + AppLibPathMap appLibPaths; + AppExecFwk::GetLibrarySupportDirectory(hapModuleInfos, nativeLibraryPath, appLibPaths); + + ASSERT_EQ(appLibPaths.count("default"), 1u); + ASSERT_EQ(appLibPaths["default"].size(), 3u); + EXPECT_EQ(appLibPaths["default"][0], "/data/storage/el1/bundle/libs/arm/dirA"); + // Second module with support dirs: libPath appends nativeLibraryPath again + EXPECT_EQ(appLibPaths["default"][1], "/data/storage/el1/bundle/libs/arm/dirB"); + EXPECT_EQ(appLibPaths["default"][2], "/data/storage/el1/bundle/libs/arm/dirC"); +} + +/** + * @tc.number: GetLibrarySupportDirectory_0600 + * @tc.name: GetLibrarySupportDirectory + * @tc.desc: Test that generated path starts with LOCAL_CODE_PATH and ends with support dir name. + */ +HWTEST_F(NativeLibUtilTest, GetLibrarySupportDirectory_0600, TestSize.Level1) +{ + std::vector hapModuleInfos; + AppExecFwk::HapModuleInfo hapInfo; + hapInfo.librarySupportDirectory = {"support"}; + hapModuleInfos.push_back(hapInfo); + std::string nativeLibraryPath = "libs/arm"; + AppLibPathMap appLibPaths; + AppExecFwk::GetLibrarySupportDirectory(hapModuleInfos, nativeLibraryPath, appLibPaths); + + ASSERT_EQ(appLibPaths["default"].size(), 1u); + const std::string &path = appLibPaths["default"][0]; + EXPECT_EQ(path, "/data/storage/el1/bundle/libs/arm/support"); +} + +/** + * @tc.number: GetHspNativeLibPath_WithSupportDirectory_0700 + * @tc.name: GetHspNativeLibPath with librarySupportDirectory + * @tc.desc: Test that GetHspNativeLibPath adds support directory paths under "default" key + * when librarySupportDirectory is set. + */ +HWTEST_F(NativeLibUtilTest, GetHspNativeLibPath_WithSupportDirectory_0700, TestSize.Level1) +{ + AppExecFwk::BaseSharedBundleInfo hspInfo; + AppLibPathMap appLibPaths; + bool isPreInstallApp = true; + + hspInfo.bundleName = "com.test.hspbundle"; + hspInfo.moduleName = "hsplib"; + hspInfo.hapPath = "/data/storage/el1/bundle/com.test.hspbundle/hsplib.hsp"; + hspInfo.nativeLibraryPath = "libs/arm"; + hspInfo.compressNativeLibs = false; + hspInfo.librarySupportDirectory = {"support1", "support2"}; + + AppExecFwk::GetHspNativeLibPath(hspInfo, appLibPaths, isPreInstallApp); + + // Verify the main HSP lib path exists + std::string key = "com.test.hspbundle/hsplib"; + ASSERT_EQ(appLibPaths.count(key), 1u); + ASSERT_EQ(appLibPaths[key].size(), 1u); + EXPECT_EQ(appLibPaths[key][0], "/data/storage/el1/bundle/com.test.hspbundle/libs/arm"); + + // Verify "default" has exactly 2 support directory paths + ASSERT_EQ(appLibPaths.count("default"), 1u); + ASSERT_EQ(appLibPaths["default"].size(), 2u); + EXPECT_EQ(appLibPaths["default"][0], + "/data/storage/el1/bundle/com.test.hspbundle/libs/arm/support1"); + EXPECT_EQ(appLibPaths["default"][1], + "/data/storage/el1/bundle/com.test.hspbundle/libs/arm/support2"); +} + +/** + * @tc.number: GetHspNativeLibPath_NoSupportDirectory_0800 + * @tc.name: GetHspNativeLibPath without librarySupportDirectory + * @tc.desc: Test that GetHspNativeLibPath does not add "default" entry + * when librarySupportDirectory is empty. + */ +HWTEST_F(NativeLibUtilTest, GetHspNativeLibPath_NoSupportDirectory_0800, TestSize.Level1) +{ + AppExecFwk::BaseSharedBundleInfo hspInfo; + AppLibPathMap appLibPaths; + bool isPreInstallApp = true; + + hspInfo.bundleName = "com.test.hspbundle"; + hspInfo.moduleName = "hsplib"; + hspInfo.hapPath = "/data/storage/el1/bundle/com.test.hspbundle/hsplib.hsp"; + hspInfo.nativeLibraryPath = "libs/arm"; + hspInfo.compressNativeLibs = false; + hspInfo.librarySupportDirectory = {}; + + AppExecFwk::GetHspNativeLibPath(hspInfo, appLibPaths, isPreInstallApp); + + std::string key = "com.test.hspbundle/hsplib"; + ASSERT_EQ(appLibPaths.count(key), 1u); + ASSERT_EQ(appLibPaths[key].size(), 1u); + EXPECT_EQ(appLibPaths[key][0], "/data/storage/el1/bundle/com.test.hspbundle/libs/arm"); + EXPECT_EQ(appLibPaths.count("default"), 0u); +} +} // namespace AppExecFwk } // namespace OHOS