From 567d5c62dd0a64633e846f660b3b04cae290472f Mon Sep 17 00:00:00 2001 From: z30034863 Date: Sat, 2 Aug 2025 18:32:12 +0800 Subject: [PATCH] support app load so with ns Signed-off-by: z30034863 --- .../ets_environment/src/ets_environment.cpp | 6 + .../interfaces/inner_api/ets_interface.h | 4 + frameworks/native/appkit/app/main_thread.cpp | 6 +- .../native/runtime/ets_native_lib_util.cpp | 166 ++++++++++++++++++ frameworks/native/runtime/ets_runtime.cpp | 55 +++++- interfaces/inner_api/runtime/BUILD.gn | 1 + .../runtime/include/ets_native_lib_util.h | 43 +++++ .../inner_api/runtime/include/ets_runtime.h | 3 +- .../runtime_test/ets_runtime_test.cpp | 3 +- 9 files changed, 283 insertions(+), 4 deletions(-) create mode 100644 frameworks/native/runtime/ets_native_lib_util.cpp create mode 100644 interfaces/inner_api/runtime/include/ets_native_lib_util.h diff --git a/ets_environment/frameworks/ets_environment/src/ets_environment.cpp b/ets_environment/frameworks/ets_environment/src/ets_environment.cpp index d12f6697d77..2b697fe55a8 100644 --- a/ets_environment/frameworks/ets_environment/src/ets_environment.cpp +++ b/ets_environment/frameworks/ets_environment/src/ets_environment.cpp @@ -24,6 +24,8 @@ #include #include +#include "static_core/plugins/ets/runtime/ets_namespace_manager.h" + #include "ets_ani_expo.h" #ifdef LIKELY #undef LIKELY @@ -540,6 +542,10 @@ ETSEnvFuncs *ETSEnvironment::RegisterFuncs() void *&obj, void *&ref) { return ETSEnvironment::GetInstance()->LoadModule(modulePath, srcEntrance, cls, obj, ref); }, + .SetAppLibPath = [](const std::map &abcPathsToBundleModuleNameMap, + std::function &cb) { + ark::ets::EtsNamespaceManager::SetAppLibPaths(abcPathsToBundleModuleNameMap, cb); + }, .FinishPreload = []() { ETSEnvironment::GetInstance()->FinishPreload(); }, diff --git a/ets_environment/interfaces/inner_api/ets_interface.h b/ets_environment/interfaces/inner_api/ets_interface.h index c9fa1d258ae..9c89ad82f78 100644 --- a/ets_environment/interfaces/inner_api/ets_interface.h +++ b/ets_environment/interfaces/inner_api/ets_interface.h @@ -16,6 +16,8 @@ #ifndef OHOS_ABILITY_RUNTIME_ETS_INTERFACE_H #define OHOS_ABILITY_RUNTIME_ETS_INTERFACE_H +#include +#include #include #include "ets_exception_callback.h" #include "ets_native_reference.h" @@ -34,6 +36,8 @@ struct ETSEnvFuncs { bool (*PreloadModule)(const std::string &modulePath) = nullptr; bool (*LoadModule)(const std::string &modulePath, const std::string &srcEntrance, void *&cls, void *&obj, void *&ref) = nullptr; + void (*SetAppLibPath)(const std::map &abcPathsToBundleModuleNameMap, + std::function &cb) = nullptr; void (*FinishPreload)() = nullptr; void (*PostFork)(void *napiEnv, const std::string &aotPath) = nullptr; }; diff --git a/frameworks/native/appkit/app/main_thread.cpp b/frameworks/native/appkit/app/main_thread.cpp index 6ffa3095bfa..7f1679152e6 100644 --- a/frameworks/native/appkit/app/main_thread.cpp +++ b/frameworks/native/appkit/app/main_thread.cpp @@ -83,6 +83,7 @@ #include "cj_runtime.h" #endif #include "native_lib_util.h" +#include "ets_native_lib_util.h" #include "native_startup_task.h" #include "nlohmann/json.hpp" #include "ohos_application.h" @@ -1655,7 +1656,10 @@ void MainThread::HandleLaunchApplication(const AppLaunchData &appLaunchData, con } else { #endif if (IsEtsAPP(appInfo)) { - AbilityRuntime::ETSRuntime::SetAppLibPath(appLibPaths); + AppLibPathMap etsAppLibPaths {}; + std::map abcPathsToBundleModuleNameMap {}; + GetEtsNativeLibPath(bundleInfo, hspList, etsAppLibPaths, abcPathsToBundleModuleNameMap); + AbilityRuntime::ETSRuntime::SetAppLibPath(etsAppLibPaths, abcPathsToBundleModuleNameMap, isSystemApp); } else { AbilityRuntime::JsRuntime::SetAppLibPath(appLibPaths, isSystemApp); } diff --git a/frameworks/native/runtime/ets_native_lib_util.cpp b/frameworks/native/runtime/ets_native_lib_util.cpp new file mode 100644 index 00000000000..96481e51789 --- /dev/null +++ b/frameworks/native/runtime/ets_native_lib_util.cpp @@ -0,0 +1,166 @@ +/* + * 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 "ets_native_lib_util.h" + +#include "constants.h" +#include "hilog_tag_wrapper.h" + +namespace OHOS { +namespace AppExecFwk { +constexpr char APP_ABC_LIB_PATH_KEY_PREFIX[] = "/data/storage/el1/bundle/"; +constexpr char APP_ABC_LIB_PATH_KEY_SUFFIX[] = "/ets/modules_static.abc"; + +std::string GetEtsLibPath(const std::string &hapPath, bool isPreInstallApp) +{ + std::string libPath = AbilityBase::Constants::LOCAL_CODE_PATH; + if (isPreInstallApp) { + auto pos = hapPath.rfind("/"); + libPath = hapPath.substr(0, pos); + } + return libPath; +} + +void GetEtsHapSoPath(const HapModuleInfo &hapInfo, AppLibPathMap &appLibPaths, bool isPreInstallApp, + std::map &abcPathsToBundleModuleNameMap) +{ + if (hapInfo.nativeLibraryPath.empty()) { + TAG_LOGD(AAFwkTag::APPKIT, "Lib path of %{public}s is empty, lib isn't isolated or compressed", + hapInfo.moduleName.c_str()); + return; + } + + std::string appLibPathKey = hapInfo.bundleName + "/" + hapInfo.moduleName; + std::string libPath = AbilityBase::Constants::LOCAL_CODE_PATH; + if (!hapInfo.compressNativeLibs) { + TAG_LOGD(AAFwkTag::APPKIT, "Lib of %{public}s will not be extracted from hap", hapInfo.moduleName.c_str()); + libPath = GetEtsLibPath(hapInfo.hapPath, isPreInstallApp); + } + + libPath += (libPath.back() == '/') ? hapInfo.nativeLibraryPath : "/" + hapInfo.nativeLibraryPath; + TAG_LOGD( + AAFwkTag::APPKIT, "appLibPathKey: %{private}s, lib path: %{private}s", appLibPathKey.c_str(), libPath.c_str()); + appLibPaths[appLibPathKey].emplace_back(libPath); + + std::string appLibAbcPathKey = APP_ABC_LIB_PATH_KEY_PREFIX + hapInfo.moduleName + APP_ABC_LIB_PATH_KEY_SUFFIX; + abcPathsToBundleModuleNameMap[appLibAbcPathKey] = appLibPathKey; +} + +void GetEtsHspNativeLibPath(const BaseSharedBundleInfo &hspInfo, AppLibPathMap &appLibPaths, bool isPreInstallApp, + const std::string &appBundleName, std::map &abcPathsToBundleModuleNameMap) +{ + if (hspInfo.nativeLibraryPath.empty()) { + return; + } + + std::string appLibPathKey = hspInfo.bundleName + "/" + hspInfo.moduleName; + std::string libPath = AbilityBase::Constants::LOCAL_CODE_PATH; + if (!hspInfo.compressNativeLibs) { + libPath = GetEtsLibPath(hspInfo.hapPath, isPreInstallApp); + libPath = libPath.back() == '/' ? libPath : libPath + "/"; + if (isPreInstallApp) { + libPath += hspInfo.nativeLibraryPath; + } else { + libPath += hspInfo.bundleName + "/" + hspInfo.moduleName + "/" + hspInfo.nativeLibraryPath; + } + } else { + libPath = libPath.back() == '/' ? libPath : libPath + "/"; + libPath += hspInfo.bundleName + "/" + hspInfo.nativeLibraryPath; + } + + TAG_LOGD( + AAFwkTag::APPKIT, "appLibPathKey: %{private}s, libPath: %{private}s", appLibPathKey.c_str(), libPath.c_str()); + appLibPaths[appLibPathKey].emplace_back(libPath); + + if (!appBundleName.empty()) { + const bool isInternalHsp = (hspInfo.bundleName == appBundleName); + const std::string name = isInternalHsp ? hspInfo.moduleName : hspInfo.bundleName + "/" + hspInfo.moduleName; + const std::string appLibAbcPathKey = APP_ABC_LIB_PATH_KEY_PREFIX + name + APP_ABC_LIB_PATH_KEY_SUFFIX; + abcPathsToBundleModuleNameMap[appLibAbcPathKey] = appLibPathKey; + } +} + +void GetEtsPatchNativeLibPath(const HapModuleInfo &hapInfo, std::string &patchNativeLibraryPath, + AppLibPathMap &appLibPaths, std::map &abcPathsToBundleModuleNameMap) +{ + if (hapInfo.isLibIsolated) { + patchNativeLibraryPath = hapInfo.hqfInfo.nativeLibraryPath; + } + + if (patchNativeLibraryPath.empty()) { + TAG_LOGD(AAFwkTag::APPKIT, "Patch lib path of %{public}s is empty", hapInfo.moduleName.c_str()); + return; + } + + if (hapInfo.compressNativeLibs && !hapInfo.isLibIsolated) { + TAG_LOGD(AAFwkTag::APPKIT, "Lib of %{public}s has compressed and isn't isolated, no need to set", + hapInfo.moduleName.c_str()); + return; + } + + std::string appLibPathKey = hapInfo.bundleName + "/" + hapInfo.moduleName; + std::string patchLibPath = AbilityBase::Constants::LOCAL_CODE_PATH; + patchLibPath += (patchLibPath.back() == '/') ? patchNativeLibraryPath : "/" + patchNativeLibraryPath; + TAG_LOGD(AAFwkTag::APPKIT, "appLibPathKey: %{public}s, patch lib path: %{private}s", appLibPathKey.c_str(), + patchLibPath.c_str()); + appLibPaths[appLibPathKey].emplace_back(patchLibPath); + std::string appLibAbcPathKey = APP_ABC_LIB_PATH_KEY_PREFIX + hapInfo.moduleName + APP_ABC_LIB_PATH_KEY_SUFFIX; + abcPathsToBundleModuleNameMap[appLibAbcPathKey] = appLibPathKey; +} + +void GetEtsNativeLibPath(const BundleInfo &bundleInfo, const std::vector &hspList, + AppLibPathMap &appLibPaths, std::map &abcPathsToBundleModuleNameMap) +{ + std::string patchNativeLibraryPath = bundleInfo.applicationInfo.appQuickFix.deployedAppqfInfo.nativeLibraryPath; + abcPathsToBundleModuleNameMap["default"] = "default"; + if (!patchNativeLibraryPath.empty()) { + // libraries in patch lib path has a higher priority when loading. + std::string patchLibPath = AbilityBase::Constants::LOCAL_CODE_PATH; + patchLibPath += (patchLibPath.back() == '/') ? patchNativeLibraryPath : "/" + patchNativeLibraryPath; + TAG_LOGD(AAFwkTag::APPKIT, "lib path = %{private}s", patchLibPath.c_str()); + appLibPaths["default"].emplace_back(patchLibPath); + } + + std::string nativeLibraryPath = bundleInfo.applicationInfo.nativeLibraryPath; + if (!nativeLibraryPath.empty()) { + if (nativeLibraryPath.back() == '/') { + nativeLibraryPath.pop_back(); + } + std::string libPath = AbilityBase::Constants::LOCAL_CODE_PATH; + libPath += (libPath.back() == '/') ? nativeLibraryPath : "/" + nativeLibraryPath; + TAG_LOGD(AAFwkTag::APPKIT, "lib path = %{private}s", libPath.c_str()); + appLibPaths["default"].emplace_back(libPath); + } else { + TAG_LOGI(AAFwkTag::APPKIT, "nativeLibraryPath is empty"); + } + + for (auto &hapInfo : bundleInfo.hapModuleInfos) { + TAG_LOGD(AAFwkTag::APPKIT, + "moduleName: %{public}s, isLibIsolated: %{public}d, compressNativeLibs: %{public}d.", + hapInfo.moduleName.c_str(), hapInfo.isLibIsolated, hapInfo.compressNativeLibs); + GetEtsPatchNativeLibPath(hapInfo, patchNativeLibraryPath, appLibPaths, abcPathsToBundleModuleNameMap); + GetEtsHapSoPath(hapInfo, appLibPaths, hapInfo.hapPath.find(AbilityBase::Constants::ABS_CODE_PATH), + abcPathsToBundleModuleNameMap); + } + + for (auto &hspInfo : hspList) { + TAG_LOGD(AAFwkTag::APPKIT, "bundle:%s, module:%s, nativeLibraryPath:%s", hspInfo.bundleName.c_str(), + hspInfo.moduleName.c_str(), hspInfo.nativeLibraryPath.c_str()); + GetEtsHspNativeLibPath(hspInfo, appLibPaths, hspInfo.hapPath.find(AbilityBase::Constants::ABS_CODE_PATH) != 0u, + bundleInfo.applicationInfo.bundleName, abcPathsToBundleModuleNameMap); + } +} +} // AppExecFwk +} // namespace OHOS \ No newline at end of file diff --git a/frameworks/native/runtime/ets_runtime.cpp b/frameworks/native/runtime/ets_runtime.cpp index 5350fec3d6e..7cfc9aff669 100644 --- a/frameworks/native/runtime/ets_runtime.cpp +++ b/frameworks/native/runtime/ets_runtime.cpp @@ -28,6 +28,7 @@ #include "file_path_utils.h" #include "hilog_tag_wrapper.h" #include "hybrid_js_module_reader.h" +#include "nocopyable.h" #ifdef SUPPORT_SCREEN #include "ace_forward_compatibility.h" @@ -80,6 +81,41 @@ bool RegisterETSEnvFuncs() g_etsEnvFuncs = func(); return true; } + +class EtsAppLibNamespaceMgr : public std::enable_shared_from_this, public NoCopyable { +public: + EtsAppLibNamespaceMgr(const AppLibPathMap& appLibPaths, bool isSystemApp) + : isSystemApp_(isSystemApp), appLibPathMap_(appLibPaths) + { + } + + bool CreateNamespace(const std::string& bundleModuleName, std::string &nsName) + { + TAG_LOGD(AAFwkTag::ETSRUNTIME, "Create app ns: %{public}s", bundleModuleName.c_str()); + if (bundleModuleName.empty()) { + TAG_LOGE(AAFwkTag::ETSRUNTIME, "empty bundleModuleName"); + return false; + } + auto appLibPath = appLibPathMap_.find(bundleModuleName); + if (appLibPath == appLibPathMap_.end()) { + TAG_LOGE(AAFwkTag::ETSRUNTIME, "not found app lib path: %{public}s", bundleModuleName.c_str()); + return false; + } + + auto moduleManager = NativeModuleManager::GetInstance(); + if (moduleManager == nullptr) { + TAG_LOGE(AAFwkTag::ETSRUNTIME, "null moduleManager"); + return false; + } + moduleManager->SetAppLibPath(appLibPath->first, appLibPath->second, isSystemApp_); + return moduleManager->GetLdNamespaceName(appLibPath->first, nsName); + } + +private: + bool isSystemApp_ = false; + AppLibPathMap appLibPathMap_; +}; +std::shared_ptr g_etsAppLibNamespaceMgr; } // namespace std::unique_ptr ETSRuntime::PreFork(const Options &options, std::unique_ptr &jsRuntime) @@ -158,7 +194,8 @@ std::unique_ptr ETSRuntime::Create(const Options &options, std::uniq return instance; } -void ETSRuntime::SetAppLibPath(const AppLibPathMap &appLibPaths) +void ETSRuntime::SetAppLibPath(const AppLibPathMap& appLibPaths, + const std::map& abcPathsToBundleModuleNameMap, bool isSystemApp) { TAG_LOGD(AAFwkTag::ETSRUNTIME, "SetAppLibPath called"); if (!RegisterETSEnvFuncs()) { @@ -182,6 +219,22 @@ void ETSRuntime::SetAppLibPath(const AppLibPathMap &appLibPaths) return; } g_etsEnvFuncs->InitETSSysNS(ETS_SYSLIB_PATH); + + if (g_etsEnvFuncs->SetAppLibPath == nullptr) { + TAG_LOGE(AAFwkTag::ETSRUNTIME, "null SetAppLibPath"); + return; + } + g_etsAppLibNamespaceMgr = std::make_shared(appLibPaths, isSystemApp); + std::function cb = + [weak = std::weak_ptr(g_etsAppLibNamespaceMgr)](const std::string &bundleModuleName, std::string &nsName) { + auto appLibNamespaceMgr = weak.lock(); + if (appLibNamespaceMgr == nullptr) { + TAG_LOGE(AAFwkTag::ETSRUNTIME, "null appLibNamespaceMgr"); + return false; + } + return appLibNamespaceMgr->CreateNamespace(bundleModuleName, nsName); + }; + g_etsEnvFuncs->SetAppLibPath(abcPathsToBundleModuleNameMap, cb); } bool ETSRuntime::Initialize(const Options &options, std::unique_ptr &jsRuntime) diff --git a/interfaces/inner_api/runtime/BUILD.gn b/interfaces/inner_api/runtime/BUILD.gn index 27d21868979..18ef4f73c9e 100644 --- a/interfaces/inner_api/runtime/BUILD.gn +++ b/interfaces/inner_api/runtime/BUILD.gn @@ -61,6 +61,7 @@ ohos_shared_library("runtime") { sources = [ "${ability_runtime_native_path}/appkit/ability_bundle_manager_helper/bundle_mgr_helper.cpp", + "${ability_runtime_native_path}/runtime/ets_native_lib_util.cpp", "${ability_runtime_native_path}/runtime/ets_runtime.cpp", "${ability_runtime_native_path}/runtime/hdc_register.cpp", "${ability_runtime_native_path}/runtime/hybrid_js_module_reader.cpp", diff --git a/interfaces/inner_api/runtime/include/ets_native_lib_util.h b/interfaces/inner_api/runtime/include/ets_native_lib_util.h new file mode 100644 index 00000000000..449d45676f7 --- /dev/null +++ b/interfaces/inner_api/runtime/include/ets_native_lib_util.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2025 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 OHOS_ABILITY_RUNTIME_ETS_NATIVE_LIB_UTIL_H +#define OHOS_ABILITY_RUNTIME_ETS_NATIVE_LIB_UTIL_H + +#include + +#include "base_shared_bundle_info.h" +#include "hap_module_info.h" +#include "js_runtime.h" +#include "bundle_info.h" + +namespace OHOS { +namespace AppExecFwk { +std::string GetEtsLibPath(const std::string &hapPath, bool isPreInstallApp); + +void GetEtsHapSoPath(const HapModuleInfo &hapInfo, AppLibPathMap &appLibPaths, bool isPreInstallApp, + std::map &abcPathsToBundleModuleNameMap); + +void GetEtsHspNativeLibPath(const BaseSharedBundleInfo &hspInfo, AppLibPathMap &appLibPaths, bool isPreInstallApp, + const std::string &appBundleName, std::map &abcPathsToBundleModuleNameMap); + +void GetEtsPatchNativeLibPath(const HapModuleInfo &hapInfo, std::string &patchNativeLibraryPath, + AppLibPathMap &appLibPaths, std::map &abcPathsToBundleModuleNameMap); + +void GetEtsNativeLibPath(const BundleInfo &bundleInfo, const std::vector &hspList, + AppLibPathMap &appLibPaths, std::map &abcPathsToBundleModuleNameMap); +} // namespace AppExecFwk +} // namespace OHOS +#endif // OHOS_ABILITY_RUNTIME_ETS_NATIVE_LIB_UTIL_H diff --git a/interfaces/inner_api/runtime/include/ets_runtime.h b/interfaces/inner_api/runtime/include/ets_runtime.h index 31629699438..80857cce6ca 100644 --- a/interfaces/inner_api/runtime/include/ets_runtime.h +++ b/interfaces/inner_api/runtime/include/ets_runtime.h @@ -46,7 +46,8 @@ namespace AbilityRuntime { class ETSRuntime : public Runtime { public: static std::unique_ptr Create(const Options &options, std::unique_ptr &jsRuntime); - static void SetAppLibPath(const AppLibPathMap &appLibPaths); + static void SetAppLibPath(const AppLibPathMap& appLibPaths, + const std::map& abcPathsToBundleModuleNameMap, bool isSystemApp); ~ETSRuntime() override; Language GetLanguage() const override { diff --git a/test/unittest/runtime_test/ets_runtime_test.cpp b/test/unittest/runtime_test/ets_runtime_test.cpp index 0e1e4760f5f..32c251c79d5 100644 --- a/test/unittest/runtime_test/ets_runtime_test.cpp +++ b/test/unittest/runtime_test/ets_runtime_test.cpp @@ -100,8 +100,9 @@ HWTEST_F(EtsRuntimeTest, SetAppLibPath_100, TestSize.Level1) std::map> testPathMap; testPathMap["com.example.app"] = { "/data/abc", "/data/def" }; testPathMap["com.example.demo"] = { "/data/demo/es", "/data/demo/ts" }; + std::map abcPathsToBundleModuleNameMap; std::unique_ptr etsRuntime = std::make_unique(); - etsRuntime->SetAppLibPath(testPathMap); + etsRuntime->SetAppLibPath(testPathMap, abcPathsToBundleModuleNameMap, false); EXPECT_NE(testPathMap.size(), 0); } -- Gitee