diff --git a/ability_runtime.gni b/ability_runtime.gni index e7848c2544..729ad0ef0f 100644 --- a/ability_runtime.gni +++ b/ability_runtime.gni @@ -18,6 +18,7 @@ ability_runtime_napi_path = "${ability_runtime_path}/frameworks/js/napi" ability_base_path = "//foundation/ability/ability_base" form_fwk_path = "//foundation/ability/form_fwk" ability_runtime_innerkits_path = "${ability_runtime_path}/interfaces/inner_api" +ability_runtime_ndk_path = "${ability_runtime_path}/interfaces/kits/c" ability_runtime_native_path = "${ability_runtime_path}/frameworks/native" ability_runtime_services_path = "${ability_runtime_path}/services" ability_runtime_abilitymgr_path = "${ability_runtime_services_path}/abilitymgr" diff --git a/bundle.json b/bundle.json index 19dca40645..a4f62beeb9 100644 --- a/bundle.json +++ b/bundle.json @@ -104,6 +104,7 @@ "//foundation/ability/ability_runtime/interfaces/inner_api:innerkits_target", "//foundation/ability/ability_runtime/frameworks/native/ability/native:ability_thread", "//foundation/ability/ability_runtime/frameworks/native/ability/native:extension_module", + "//foundation/ability/ability_runtime/frameworks/native/child_process:child_process", "//foundation/ability/ability_runtime/frameworks/native/insight_intent:insight_intent_innerkits", "//foundation/ability/ability_runtime/frameworks/js/napi:napi_packages", "//foundation/ability/ability_runtime/cj_environment/frameworks/cj_environment:cj_environment", @@ -312,6 +313,15 @@ }, "name": "//foundation/ability/ability_runtime/frameworks/native/appkit:app_context" }, + { + "header": { + "header_base": "//foundation/ability/ability_runtime/interfaces/kits/c/ability/ability_runtime/child_process", + "header_files": [ + "native_child_process.h" + ] + }, + "name": "//foundation/ability/ability_runtime/frameworks/native/child_process:child_process" + }, { "header": { "header_base": "//foundation/ability/ability_runtime/interfaces/inner_api/uri_permission/include/", diff --git a/frameworks/native/ability/native/child_process_manager/child_process_manager.cpp b/frameworks/native/ability/native/child_process_manager/child_process_manager.cpp index c377797192..28de904cb1 100644 --- a/frameworks/native/ability/native/child_process_manager/child_process_manager.cpp +++ b/frameworks/native/ability/native/child_process_manager/child_process_manager.cpp @@ -29,6 +29,7 @@ #include "bundle_info.h" #include "bundle_mgr_interface.h" #include "child_process.h" +#include "native_child_ipc_process.h" #include "child_process_manager_error_utils.h" #include "child_process_start_info.h" #include "constants.h" @@ -115,6 +116,37 @@ ChildProcessManagerErrorCode ChildProcessManager::StartChildProcessByAppSpawnFor return ChildProcessManagerErrorCode::ERR_OK; } +ChildProcessManagerErrorCode ChildProcessManager::StartNativeChildProcessByAppSpawnFork( + const std::string &libName, const sptr &callbackStub) +{ + TAG_LOGI(AAFwkTag::PROCESSMGR, "called, libName:%{private}s", libName.c_str()); + ChildProcessManagerErrorCode errorCode = PreCheckNativeProcess(); + if (errorCode != ChildProcessManagerErrorCode::ERR_OK) { + return errorCode; + } + + sptr appMgr = GetAppMgr(); + if (appMgr == nullptr) { + TAG_LOGE(AAFwkTag::PROCESSMGR, "GetAppMgr for native child process failed."); + return ChildProcessManagerErrorCode::ERR_GET_APP_MGR_FAILED; + } + + auto ret = appMgr->StartNativeChildProcess(libName, childProcessCount_, callbackStub); + TAG_LOGD(AAFwkTag::PROCESSMGR, "AppMgr StartNativeChildProcess ret:%{public}d", ret); + + if (ret != ERR_OK) { + TAG_LOGE(AAFwkTag::PROCESSMGR, "AppMgr StartNativeChildProcess failed, ret:%{public}d", ret); + if (ret == ERR_OVERFLOW) { + TAG_LOGE(AAFwkTag::PROCESSMGR, "Max native child processes readched"); + return ChildProcessManagerErrorCode::ERR_MAX_NATIVE_CHILD_PROCESSES; + } + return ChildProcessManagerErrorCode::ERR_GET_APP_MGR_START_PROCESS_FAILED; + } + + ++childProcessCount_; + return ChildProcessManagerErrorCode::ERR_OK; +} + void ChildProcessManager::RegisterSignal() { if (!signalRegistered_) { @@ -144,6 +176,21 @@ ChildProcessManagerErrorCode ChildProcessManager::PreCheck() return ChildProcessManagerErrorCode::ERR_OK; } +ChildProcessManagerErrorCode ChildProcessManager::PreCheckNativeProcess() +{ + ChildProcessManagerErrorCode errCode = PreCheck(); + if (errCode != ChildProcessManagerErrorCode::ERR_OK) { + return errCode; + } + + if (!AAFwk::AppUtils::GetInstance().IsSupportNativeChildProcess()) { + TAG_LOGE(AAFwkTag::PROCESSMGR, "Unsupport native child process"); + return ChildProcessManagerErrorCode::ERR_UNSUPPORT_NATIVE_CHILD_PROCESS; + } + + return ChildProcessManagerErrorCode::ERR_OK; +} + bool ChildProcessManager::IsChildProcess() { return isChildProcessBySelfFork_ || hasChildProcessRecord(); @@ -207,6 +254,28 @@ bool ChildProcessManager::LoadJsFile(const std::string &srcEntry, const AppExecF return true; } +bool ChildProcessManager::LoadNativeLib(const std::string &libPath, const sptr &mainProcessCb) +{ + auto childProcess = NativeChildIpcProcess::Create(); + if (childProcess == nullptr) { + TAG_LOGE(AAFwkTag::PROCESSMGR, "Failed create NativeChildIpcProcess"); + return false; + } + + std::shared_ptr processStartInfo = std::make_shared(); + processStartInfo->name = std::filesystem::path(libPath).stem(); + processStartInfo->srcEntry = libPath; + processStartInfo->ipcObj = mainProcessCb; + if (!childProcess->Init(processStartInfo)) { + TAG_LOGE(AAFwkTag::PROCESSMGR, "NativeChildIpcProcess init failed."); + return false; + } + + childProcess->OnStart(); + TAG_LOGD(AAFwkTag::PROCESSMGR, "LoadNativeLib end."); + return true; +} + std::unique_ptr ChildProcessManager::CreateRuntime(const AppExecFwk::BundleInfo &bundleInfo, const AppExecFwk::HapModuleInfo &hapModuleInfo, const bool fromAppSpawn, const bool jitEnabled) { diff --git a/frameworks/native/ability/native/child_process_manager/native_child_ipc_process.cpp b/frameworks/native/ability/native/child_process_manager/native_child_ipc_process.cpp new file mode 100644 index 0000000000..905c32a4b9 --- /dev/null +++ b/frameworks/native/ability/native/child_process_manager/native_child_ipc_process.cpp @@ -0,0 +1,146 @@ +/* + * 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 "native_child_ipc_process.h" +#include +#include +#include +#include "hilog_tag_wrapper.h" +#include "hilog_wrapper.h" +#include "child_process_manager_error_utils.h" + +namespace OHOS { +namespace AbilityRuntime { + +std::shared_ptr NativeChildIpcProcess::Create() +{ + return std::make_shared(); +} + +NativeChildIpcProcess::~NativeChildIpcProcess() +{ + UnloadNativeLib(); +} + +bool NativeChildIpcProcess::Init(const std::shared_ptr &info) +{ + TAG_LOGD(AAFwkTag::PROCESSMGR, "NativeChildIpcProcess init"); + if (info == nullptr || info->ipcObj == nullptr) { + TAG_LOGE(AAFwkTag::PROCESSMGR, "info or ipc callback is null"); + return false; + } + + if (!ChildProcess::Init(info)) { + TAG_LOGE(AAFwkTag::PROCESSMGR, "Base class init failed."); + return false; + } + + auto iNotify = iface_cast(info->ipcObj); + if (iNotify == nullptr) { + TAG_LOGE(AAFwkTag::PROCESSMGR, "Faild cvt interface to INativeChildNotify"); + return false; + } + + if (!LoadNativeLib(info)) { + iNotify->OnError(static_cast(ChildProcessManagerErrorCode::ERR_NATIVE_CHILD_PROCESS_LOAD_LIB)); + return false; + } + + mainProcessCb_ = iNotify; + return true; +} + +void NativeChildIpcProcess::OnStart() +{ + if (funcNativeLibOnConnect_ == nullptr || funcNativeLibMainProc_ == nullptr || mainProcessCb_ == nullptr) { + TAG_LOGE(AAFwkTag::PROCESSMGR, "No init"); + return; + } + + ChildProcess::OnStart(); + OHIPCRemoteStub *ipcStub = funcNativeLibOnConnect_(); + if (ipcStub == nullptr || ipcStub->remote == nullptr) { + TAG_LOGE(AAFwkTag::PROCESSMGR, "Native lib OnConnect function return null stub"); + mainProcessCb_->OnError(static_cast(ChildProcessManagerErrorCode::ERR_NATIVE_CHILD_PROCESS_CONNECT)); + return; + } + + std::thread cbThread([this, childIpcStub = std::move(ipcStub->remote)] () -> void { + // Wait MainProc run first + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + TAG_LOGI(AAFwkTag::PROCESSMGR, "Notify native child process started"); + mainProcessCb_->OnNativeChildStarted(childIpcStub); + }); + + TAG_LOGI(AAFwkTag::PROCESSMGR, "Enter native lib MainProc"); + funcNativeLibMainProc_(); + TAG_LOGI(AAFwkTag::PROCESSMGR, "Native lib MainProc returned"); + + if (cbThread.joinable()) { + cbThread.join(); + } +} + +bool NativeChildIpcProcess::LoadNativeLib(const std::shared_ptr &info) +{ + if (nativeLibHandle_ != nullptr) { + TAG_LOGE(AAFwkTag::PROCESSMGR, "Native lib already loaded"); + return false; + } + + void *libHandle = dlopen(info->srcEntry.c_str(), RTLD_LAZY); + if (libHandle == nullptr) { + TAG_LOGE(AAFwkTag::PROCESSMGR, "Load lib file %{private}s failed, err %{public}s", + info->srcEntry.c_str(), dlerror()); + return false; + } + + do { + NativeChildProcess_OnConnect funcOnConnect = + reinterpret_cast(dlsym(libHandle, "NativeChildProcess_OnConnect")); + if (funcOnConnect == nullptr) { + TAG_LOGE(AAFwkTag::PROCESSMGR, "Get OnConnect function address failed, err %{public}s", dlerror()); + break; + } + + NativeChildProcess_MainProc funcMainProc = + reinterpret_cast(dlsym(libHandle, "NativeChildProcess_MainProc")); + if (funcMainProc == nullptr) { + TAG_LOGE(AAFwkTag::PROCESSMGR, "Get MainProc function address failed, err %{public}s", dlerror()); + break; + } + + funcNativeLibOnConnect_ = funcOnConnect; + funcNativeLibMainProc_ = funcMainProc; + nativeLibHandle_ = libHandle; + return true; + } while (false); + + dlclose(libHandle); + return false; +} + +void NativeChildIpcProcess::UnloadNativeLib() +{ + if (nativeLibHandle_ != nullptr) { + dlclose(nativeLibHandle_); + nativeLibHandle_ = nullptr; + funcNativeLibOnConnect_ = nullptr; + funcNativeLibMainProc_ = nullptr; + } +} + +} // namespace AbilityRuntime +} // namespace OHOS diff --git a/frameworks/native/appkit/app/child_main_thread.cpp b/frameworks/native/appkit/app/child_main_thread.cpp index 004d0cca2b..a6030e6d93 100644 --- a/frameworks/native/appkit/app/child_main_thread.cpp +++ b/frameworks/native/appkit/app/child_main_thread.cpp @@ -14,7 +14,7 @@ */ #include "child_main_thread.h" - +#include #include "bundle_mgr_proxy.h" #include "child_process_manager.h" #include "constants.h" @@ -172,7 +172,12 @@ void ChildMainThread::InitNativeLib(const BundleInfo &bundleInfo) GetNativeLibPath(bundleInfo, appLibPaths); bool isSystemApp = bundleInfo.applicationInfo.isSystemApp; TAG_LOGD(AAFwkTag::APPKIT, "the application isSystemApp: %{public}d", isSystemApp); - AbilityRuntime::JsRuntime::SetAppLibPath(appLibPaths, isSystemApp); + + if (processInfo_->processType != CHILD_PROCESS_TYPE_NATIVE) { + AbilityRuntime::JsRuntime::SetAppLibPath(appLibPaths, isSystemApp); + } else { + UpdateNativeChildLibPath(appLibPaths); + } } void ChildMainThread::ExitProcessSafely() @@ -222,6 +227,67 @@ void ChildMainThread::HandleExitProcessSafely() } } +bool ChildMainThread::ScheduleRunNativeProc(const sptr &mainProcessCb) +{ + TAG_LOGD(AAFwkTag::APPKIT, "ScheduleRunNativeProc"); + if (mainProcessCb == nullptr) { + TAG_LOGE(AAFwkTag::APPKIT, "Main process callback is null"); + return false; + } + + if (mainHandler_ == nullptr) { + TAG_LOGE(AAFwkTag::APPKIT, "mainHandler_ is null"); + return false; + } + + auto task = [weak = wptr(this), callback = sptr(mainProcessCb)]() { + auto childMainThread = weak.promote(); + if (childMainThread == nullptr) { + TAG_LOGE(AAFwkTag::APPKIT, "childMainThread is nullptr, ScheduleRunNativeProc failed."); + return; + } + childMainThread->HandleRunNativeProc(callback); + }; + if (!mainHandler_->PostTask(task, "ChildMainThread::HandleRunNativeProc")) { + TAG_LOGE(AAFwkTag::APPKIT, "HandleRunNativeProc PostTask task failed."); + return false; + } + return true; +} + +void ChildMainThread::HandleRunNativeProc(const sptr &mainProcessCb) +{ + TAG_LOGD(AAFwkTag::APPKIT, "HandleRunNativeProc called start."); + if (!processInfo_) { + TAG_LOGE(AAFwkTag::APPKIT, "processInfo is null."); + return; + } + + ChildProcessManager &childProcessMgr = ChildProcessManager::GetInstance(); + childProcessMgr.LoadNativeLib(processInfo_->srcEntry, mainProcessCb); + TAG_LOGD(AAFwkTag::APPKIT, "HandleRunNativeProc end."); + ExitProcessSafely(); +} + +void ChildMainThread::UpdateNativeChildLibPath(const AppLibPathMap &appLibPaths) +{ + std::string nativeLibPath; + for (const auto &libPathPair : appLibPaths) { + for (const auto &libDir : libPathPair.second) { + nativeLibPath = libDir; + if (!nativeLibPath.empty() && nativeLibPath.back() != '/') { + nativeLibPath += '/'; + } + + nativeLibPath += processInfo_->srcEntry; + if (access(nativeLibPath.c_str(), F_OK) == 0) { + processInfo_->srcEntry = nativeLibPath; + break; + } + } + } +} + void ChildMainThread::GetNativeLibPath(const BundleInfo &bundleInfo, AppLibPathMap &appLibPaths) { std::string nativeLibraryPath = bundleInfo.applicationInfo.nativeLibraryPath; diff --git a/frameworks/native/child_process/BUILD.gn b/frameworks/native/child_process/BUILD.gn new file mode 100644 index 0000000000..4d5fe5006a --- /dev/null +++ b/frameworks/native/child_process/BUILD.gn @@ -0,0 +1,66 @@ +# 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. + +import("//build/ohos.gni") +import("//foundation/ability/ability_runtime/ability_runtime.gni") + +config("child_process_ndk_config") { + include_dirs = + [ "${ability_runtime_ndk_path}/ability/ability_runtime/child_process" ] + + if (target_cpu == "arm") { + cflags = [ "-DBINDER_IPC_32BIT" ] + } +} + +ohos_shared_library("child_process") { + sanitize = { + integer_overflow = true + ubsan = true + boundary_sanitize = true + cfi = true + cfi_cross_dso = true + cfi_vcall_icall_only = true + debug = false + } + branch_protector_ret = "pac_ret" + + include_dirs = [ "include" ] + + configs = [ "${ability_runtime_services_path}/common:common_config" ] + public_configs = [ ":child_process_ndk_config" ] + + sources = [ + "${ability_runtime_native_path}/child_process/src/native_child_callback.cpp", + "${ability_runtime_native_path}/child_process/src/native_child_process.cpp", + ] + + deps = [ + "${ability_runtime_innerkits_path}/app_manager:app_manager", + "${ability_runtime_innerkits_path}/child_process_manager:child_process_manager", + "${ability_runtime_native_path}/ability/native:ability_business_error", + ] + + external_deps = [ + "c_utils:utils", + "hilog:libhilog", + "ipc:ipc_capi", + "ipc:ipc_core", + ] + + output_extension = "so" + innerapi_tags = [ "ndk" ] + install_images = [ "system" ] + subsystem_name = "ability" + part_name = "ability_runtime" +} diff --git a/frameworks/native/child_process/include/native_child_callback.h b/frameworks/native/child_process/include/native_child_callback.h new file mode 100644 index 0000000000..b0be67b876 --- /dev/null +++ b/frameworks/native/child_process/include/native_child_callback.h @@ -0,0 +1,40 @@ +/* + * 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 OHOS_ABILITY_RUNTIME_NATIVE_CHILD_CALLBACK_H +#define OHOS_ABILITY_RUNTIME_NATIVE_CHILD_CALLBACK_H + +#include "native_child_notify_stub.h" +#include "native_child_process.h" + +namespace OHOS { +namespace AbilityRuntime { + +class NativeChildCallback : public OHOS::AppExecFwk::NativeChildNotifyStub { +public: + explicit NativeChildCallback(OH_Ability_OnNativeChildProcessStarted cb); + ~NativeChildCallback() = default; + + void OnNativeChildStarted(const sptr &nativeChild) override; + void OnError(int32_t errCode) override; + +private: + OH_Ability_OnNativeChildProcessStarted callback_ = nullptr; +}; + +} // namespace AbilityRuntime +} // namespace OHOS + +#endif // OHOS_ABILITY_RUNTIME_NATIVE_CHILD_CALLBACK_H diff --git a/frameworks/native/child_process/src/native_child_callback.cpp b/frameworks/native/child_process/src/native_child_callback.cpp new file mode 100644 index 0000000000..1102c8b3fb --- /dev/null +++ b/frameworks/native/child_process/src/native_child_callback.cpp @@ -0,0 +1,66 @@ +/* + * 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 "native_child_callback.h" +#include "hilog_tag_wrapper.h" +#include "hilog_wrapper.h" +#include "ipc_inner_object.h" +#include "child_process_manager_error_utils.h" + +namespace OHOS { +namespace AbilityRuntime { + +NativeChildCallback::NativeChildCallback(OH_Ability_OnNativeChildProcessStarted cb) + : NativeChildNotifyStub(), callback_(cb) +{ +} + +void NativeChildCallback::OnNativeChildStarted(const sptr &nativeChild) +{ + if (callback_ == nullptr) { + TAG_LOGE(AAFwkTag::PROCESSMGR, "Native child process started, but callback is null?"); + return; + } + + if (!nativeChild) { + TAG_LOGE(AAFwkTag::PROCESSMGR, "Native child process ipc object is null"); + return; + } + + TAG_LOGI(AAFwkTag::PROCESSMGR, "Native child process started"); + sptr ipcRemote = nativeChild; + OHIPCRemoteProxy *ipcProxy = CreateIPCRemoteProxy(ipcRemote); + if (ipcProxy == nullptr) { + TAG_LOGE(AAFwkTag::PROCESSMGR, "Convert inner ipc object to OHIPCRemoteProxy point failed"); + callback_(NCP_ERR_INTERNAL, nullptr); + return; + } + + callback_(static_cast(ChildProcessManagerErrorCode::ERR_OK), ipcProxy); +} + +void NativeChildCallback::OnError(int32_t errCode) +{ + if (callback_ == nullptr) { + TAG_LOGE(AAFwkTag::PROCESSMGR, "Native child process start failed, but callback is null?"); + return; + } + + TAG_LOGI(AAFwkTag::PROCESSMGR, "Native child process start failed, err %{public}d", errCode); + callback_(errCode, nullptr); +} + +} // namespace AbilityRuntime +} // namespace OHOS diff --git a/frameworks/native/child_process/src/native_child_process.cpp b/frameworks/native/child_process/src/native_child_process.cpp new file mode 100644 index 0000000000..d5036d7b8e --- /dev/null +++ b/frameworks/native/child_process/src/native_child_process.cpp @@ -0,0 +1,104 @@ +/* + * 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 "native_child_process.h" +#include +#include +#include "hilog_tag_wrapper.h" +#include "hilog_wrapper.h" +#include "native_child_callback.h" +#include "child_process_manager.h" + +using namespace OHOS; +using namespace OHOS::AbilityRuntime; + +namespace { + +std::mutex g_MutexCallBackObj; +sptr g_CallbackStub; +OH_Ability_OnNativeChildProcessStarted g_Callback = nullptr; + +const std::map CPM_ERRCODE_MAP = { + { ChildProcessManagerErrorCode::ERR_OK, NCP_NOERROR }, + { ChildProcessManagerErrorCode::ERR_MULTI_PROCESS_MODEL_DISABLED, NCP_ERR_MULTI_PROCESS_DISABLED }, + { ChildProcessManagerErrorCode::ERR_ALREADY_IN_CHILD_PROCESS, NCP_ERR_ALREADY_IN_CHILD }, + { ChildProcessManagerErrorCode::ERR_GET_APP_MGR_FAILED, NCP_ERR_SERVICE }, + { ChildProcessManagerErrorCode::ERR_GET_APP_MGR_START_PROCESS_FAILED, NCP_ERR_SERVICE }, + { ChildProcessManagerErrorCode::ERR_UNSUPPORT_NATIVE_CHILD_PROCESS, NCP_ERR_NOT_SUPPORTED }, + { ChildProcessManagerErrorCode::ERR_MAX_NATIVE_CHILD_PROCESSES, NCP_ERR_MAX_CHILD_PROCESSES_REACHED }, + { ChildProcessManagerErrorCode::ERR_NATIVE_CHILD_PROCESS_LOAD_LIB, NCP_ERR_CHILD_PROCESS_LOAD_LIB }, + { ChildProcessManagerErrorCode::ERR_NATIVE_CHILD_PROCESS_CONNECT, NCP_ERR_CHILD_PROCESS_CONNECT }, +}; + +int CvtChildProcessManagerErrCode(ChildProcessManagerErrorCode cpmErr) +{ + auto it = CPM_ERRCODE_MAP.find(cpmErr); + if (it == CPM_ERRCODE_MAP.end()) { + return NCP_ERR_INTERNAL; + } + + return it->second; +} + +void OnNativeChildProcessStartedWapper(int errCode, OHIPCRemoteProxy *ipcProxy) +{ + std::unique_lock autoLock(g_MutexCallBackObj); + if (g_Callback != nullptr) { + g_Callback(CvtChildProcessManagerErrCode(static_cast(errCode)), ipcProxy); + g_Callback = nullptr; + } else { + TAG_LOGW(AAFwkTag::PROCESSMGR, "Remote call twice?"); + } + + g_CallbackStub.clear(); +} + +} // Anonymous namespace + +int OH_Ability_CreateNativeChildProcess(const char* libName, OH_Ability_OnNativeChildProcessStarted onProcessStarted) +{ + if (libName == nullptr || *libName == '\0' || onProcessStarted == nullptr) { + TAG_LOGE(AAFwkTag::PROCESSMGR, "Invalid libname or callback"); + return NCP_ERR_INVALID_PARAM; + } + + std::string strLibName(libName); + if (strLibName.find("../") != std::string::npos) { + TAG_LOGE(AAFwkTag::PROCESSMGR, "Do not allow use relative path"); + return NCP_ERR_INVALID_PARAM; + } + + std::unique_lock autoLock(g_MutexCallBackObj); + if (g_Callback != nullptr || g_CallbackStub != nullptr) { + TAG_LOGW(AAFwkTag::PROCESSMGR, "Another native process process starting, try again later"); + return NCP_ERR_BUSY; + } + + sptr callbackStub(new (std::nothrow) NativeChildCallback(OnNativeChildProcessStartedWapper)); + if (!callbackStub) { + TAG_LOGE(AAFwkTag::PROCESSMGR, "Alloc callback ipc stub object faild."); + return NCP_ERR_INTERNAL; + } + + ChildProcessManager &mgr = ChildProcessManager::GetInstance(); + auto cpmErr = mgr.StartNativeChildProcessByAppSpawnFork(strLibName, callbackStub); + if (cpmErr != ChildProcessManagerErrorCode::ERR_OK) { + return CvtChildProcessManagerErrCode(cpmErr); + } + + g_Callback = onProcessStarted; + g_CallbackStub = callbackStub; + return NCP_NOERROR; +} diff --git a/interfaces/inner_api/app_manager/BUILD.gn b/interfaces/inner_api/app_manager/BUILD.gn index c489963183..09330b5ac3 100644 --- a/interfaces/inner_api/app_manager/BUILD.gn +++ b/interfaces/inner_api/app_manager/BUILD.gn @@ -88,6 +88,8 @@ ohos_shared_library("app_manager") { "src/appmgr/configuration_observer_stub.cpp", "src/appmgr/fault_data.cpp", "src/appmgr/memory_level_info.cpp", + "src/appmgr/native_child_notify_proxy.cpp", + "src/appmgr/native_child_notify_stub.cpp", "src/appmgr/page_state_data.cpp", "src/appmgr/priority_object.cpp", "src/appmgr/process_data.cpp", diff --git a/interfaces/inner_api/app_manager/include/appmgr/app_mgr_interface.h b/interfaces/inner_api/app_manager/include/appmgr/app_mgr_interface.h index 723d2a714b..5bd33cabd4 100644 --- a/interfaces/inner_api/app_manager/include/appmgr/app_mgr_interface.h +++ b/interfaces/inner_api/app_manager/include/appmgr/app_mgr_interface.h @@ -652,6 +652,16 @@ public: } virtual int32_t SetSupportedProcessCacheSelf(bool isSupport) = 0; + + /** + * Start native child process, callde by ChildProcessManager. + * @param libName lib file name to be load in child process + * @param childProcessCount current started child process count + * @param callback callback for notify start result + * @return Returns ERR_OK on success, others on failure. + */ + virtual int32_t StartNativeChildProcess(const std::string &libName, int32_t childProcessCount, + const sptr &callback) = 0; }; } // namespace AppExecFwk } // namespace OHOS diff --git a/interfaces/inner_api/app_manager/include/appmgr/app_mgr_ipc_interface_code.h b/interfaces/inner_api/app_manager/include/appmgr/app_mgr_ipc_interface_code.h index abc01de315..3bf4423786 100644 --- a/interfaces/inner_api/app_manager/include/appmgr/app_mgr_ipc_interface_code.h +++ b/interfaces/inner_api/app_manager/include/appmgr/app_mgr_ipc_interface_code.h @@ -99,6 +99,7 @@ enum class AppMgrInterfaceCode { PRELOAD_APPLICATION = 73, SET_SUPPORTED_PROCESS_CACHE_SELF = 74, APP_GET_RUNNING_PROCESSES_BY_BUNDLE_TYPE = 75, + START_NATIVE_CHILD_PROCESS = 76, }; } // AppExecFwk } // OHOS diff --git a/interfaces/inner_api/app_manager/include/appmgr/app_mgr_proxy.h b/interfaces/inner_api/app_manager/include/appmgr/app_mgr_proxy.h index 3b5c4feebc..0d7b7c98e6 100644 --- a/interfaces/inner_api/app_manager/include/appmgr/app_mgr_proxy.h +++ b/interfaces/inner_api/app_manager/include/appmgr/app_mgr_proxy.h @@ -568,6 +568,17 @@ public: virtual int32_t NotifyMemorySizeStateChanged(bool isMemorySizeSufficent) override; int32_t SetSupportedProcessCacheSelf(bool isSupport) override; + + /** + * Start native child process, callde by ChildProcessManager. + * @param libName lib file name to be load in child process + * @param childProcessCount current started child process count + * @param callback callback for notify start result + * @return Returns ERR_OK on success, others on failure. + */ + int32_t StartNativeChildProcess(const std::string &libName, int32_t childProcessCount, + const sptr &callback) override; + private: bool SendTransactCmd(AppMgrInterfaceCode code, MessageParcel &data, MessageParcel &reply); bool WriteInterfaceToken(MessageParcel &data); diff --git a/interfaces/inner_api/app_manager/include/appmgr/app_mgr_stub.h b/interfaces/inner_api/app_manager/include/appmgr/app_mgr_stub.h index 51de220229..e9a7da927e 100644 --- a/interfaces/inner_api/app_manager/include/appmgr/app_mgr_stub.h +++ b/interfaces/inner_api/app_manager/include/appmgr/app_mgr_stub.h @@ -135,6 +135,7 @@ private: int32_t HandleGetAllUIExtensionProviderPid(MessageParcel &data, MessageParcel &reply); int32_t HandleNotifyMemorySizeStateChanged(MessageParcel &data, MessageParcel &reply); int32_t HandleSetSupportedProcessCacheSelf(MessageParcel &data, MessageParcel &reply); + int32_t HandleStartNativeChildProcess(MessageParcel &data, MessageParcel &reply); using AppMgrFunc = int32_t (AppMgrStub::*)(MessageParcel &data, MessageParcel &reply); std::map memberFuncMap_; diff --git a/interfaces/inner_api/app_manager/include/appmgr/child_process_info.h b/interfaces/inner_api/app_manager/include/appmgr/child_process_info.h index 89b4706190..cb5352d12e 100644 --- a/interfaces/inner_api/app_manager/include/appmgr/child_process_info.h +++ b/interfaces/inner_api/app_manager/include/appmgr/child_process_info.h @@ -22,10 +22,15 @@ namespace OHOS { namespace AppExecFwk { + +constexpr int32_t CHILD_PROCESS_TYPE_JS = 0; +constexpr int32_t CHILD_PROCESS_TYPE_NATIVE = 1; + struct ChildProcessInfo : public Parcelable { std::int32_t pid; std::int32_t hostPid; std::int32_t uid; + std::int32_t processType; std::string bundleName; std::string processName; std::string srcEntry; diff --git a/interfaces/inner_api/app_manager/include/appmgr/child_scheduler_interface.h b/interfaces/inner_api/app_manager/include/appmgr/child_scheduler_interface.h index beaa93d6a9..89fbfc623f 100644 --- a/interfaces/inner_api/app_manager/include/appmgr/child_scheduler_interface.h +++ b/interfaces/inner_api/app_manager/include/appmgr/child_scheduler_interface.h @@ -34,9 +34,16 @@ public: */ virtual bool ScheduleExitProcessSafely() = 0; + /** + * Notify child process run main proc from shared lib. + * @param mainProcessCb Main process callback ipc object + */ + virtual bool ScheduleRunNativeProc(const sptr &mainProcessCb) = 0; + enum class Message { SCHEDULE_LOAD_JS = 0, SCHEDULE_EXIT_PROCESS_SAFELY = 1, + SCHEDULE_RUN_NATIVE_PROC = 2, }; }; } // namespace AppExecFwk diff --git a/interfaces/inner_api/app_manager/include/appmgr/child_scheduler_proxy.h b/interfaces/inner_api/app_manager/include/appmgr/child_scheduler_proxy.h index 355dd1398a..f5cd00d0f1 100644 --- a/interfaces/inner_api/app_manager/include/appmgr/child_scheduler_proxy.h +++ b/interfaces/inner_api/app_manager/include/appmgr/child_scheduler_proxy.h @@ -29,6 +29,7 @@ public: bool ScheduleLoadJs() override; bool ScheduleExitProcessSafely() override; + bool ScheduleRunNativeProc(const sptr &mainProcessCb) override; private: bool WriteInterfaceToken(MessageParcel &data); diff --git a/interfaces/inner_api/app_manager/include/appmgr/child_scheduler_stub.h b/interfaces/inner_api/app_manager/include/appmgr/child_scheduler_stub.h index 6a73ccbf03..a6ecf59dce 100644 --- a/interfaces/inner_api/app_manager/include/appmgr/child_scheduler_stub.h +++ b/interfaces/inner_api/app_manager/include/appmgr/child_scheduler_stub.h @@ -36,6 +36,7 @@ public: private: int32_t HandleScheduleLoadJs(MessageParcel &data, MessageParcel &reply); int32_t HandleScheduleExitProcessSafely(MessageParcel &data, MessageParcel &reply); + int32_t HandleScheduleRunNativeProc(MessageParcel &data, MessageParcel &reply); using ChildSchedulerFunc = int32_t (ChildSchedulerStub::*)(MessageParcel &data, MessageParcel &reply); std::map memberFuncMap_; diff --git a/interfaces/inner_api/app_manager/include/appmgr/native_child_notify_interface.h b/interfaces/inner_api/app_manager/include/appmgr/native_child_notify_interface.h new file mode 100644 index 0000000000..b901b6c107 --- /dev/null +++ b/interfaces/inner_api/app_manager/include/appmgr/native_child_notify_interface.h @@ -0,0 +1,50 @@ +/* + * 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 OHOS_ABILITY_RUNTIME_NATIVE_CHILD_NOTIFY_INTERFACE_H +#define OHOS_ABILITY_RUNTIME_NATIVE_CHILD_NOTIFY_INTERFACE_H + +#include "iremote_broker.h" + +namespace OHOS { +namespace AppExecFwk { + +class INativeChildNotify : public IRemoteBroker { +public: + DECLARE_INTERFACE_DESCRIPTOR(u"ohos.appexecfwk.NativeChildNotify"); + + /** + * Notify native child process started. + * + * @param nativeChild child process ipc object + */ + virtual void OnNativeChildStarted(const sptr &nativeChild) = 0; + + /** + * Notify native child process start failed. + * + * @param errCode failed error code + */ + virtual void OnError(int32_t errCode) = 0; + +protected: + static constexpr uint32_t IPC_ID_ON_NATIVE_CHILD_STARTED = 0; + static constexpr uint32_t IPC_ID_ON_ERROR = 1; +}; + +} // OHOS +} // AppExecFwk + +#endif // OHOS_ABILITY_RUNTIME_NATIVE_CHILD_NOTIFY_INTERFACE_H \ No newline at end of file diff --git a/interfaces/inner_api/app_manager/include/appmgr/native_child_notify_proxy.h b/interfaces/inner_api/app_manager/include/appmgr/native_child_notify_proxy.h new file mode 100644 index 0000000000..fabd51a855 --- /dev/null +++ b/interfaces/inner_api/app_manager/include/appmgr/native_child_notify_proxy.h @@ -0,0 +1,43 @@ +/* + * 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 OHOS_ABILITY_RUNTIME_NATIVE_CHILD_NOTIFY_PROXY_H +#define OHOS_ABILITY_RUNTIME_NATIVE_CHILD_NOTIFY_PROXY_H + +#include "native_child_notify_interface.h" +#include "iremote_proxy.h" + +namespace OHOS { +namespace AppExecFwk { + +class NativeChildNotifyProxy : public IRemoteProxy { +public: + explicit NativeChildNotifyProxy(const sptr &impl); + virtual ~NativeChildNotifyProxy() = default; + + void OnNativeChildStarted(const sptr &nativeChild) override; + void OnError(int32_t errCode) override; + +private: + bool WriteInterfaceToken(MessageParcel &data); + int32_t SendRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption& option); + + static inline BrokerDelegator delegator_; +}; + +} // OHOS +} // AppExecFwk + +#endif // OHOS_ABILITY_RUNTIME_NATIVE_CHILD_NOTIFY_PROXY_H \ No newline at end of file diff --git a/interfaces/inner_api/app_manager/include/appmgr/native_child_notify_stub.h b/interfaces/inner_api/app_manager/include/appmgr/native_child_notify_stub.h new file mode 100644 index 0000000000..a77580f3a0 --- /dev/null +++ b/interfaces/inner_api/app_manager/include/appmgr/native_child_notify_stub.h @@ -0,0 +1,41 @@ +/* + * 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 OHOS_ABILITY_RUNTIME_NATIVE_CHILD_NOTIFY_STUB_H +#define OHOS_ABILITY_RUNTIME_NATIVE_CHILD_NOTIFY_STUB_H + +#include "native_child_notify_interface.h" +#include "iremote_stub.h" + +namespace OHOS { +namespace AppExecFwk { + +class NativeChildNotifyStub : public IRemoteStub { +public: + NativeChildNotifyStub() = default; + virtual ~NativeChildNotifyStub() = default; + + int OnRemoteRequest( + uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) override; + +private: + int32_t HandleOnNativeChildStarted(MessageParcel &data, MessageParcel &reply); + int32_t HandleOnError(MessageParcel &data, MessageParcel &reply); +}; + +} // OHOS +} // AppExecFwk + +#endif // OHOS_ABILITY_RUNTIME_NATIVE_CHILD_NOTIFY_STUB_H \ No newline at end of file diff --git a/interfaces/inner_api/app_manager/src/appmgr/app_mgr_proxy.cpp b/interfaces/inner_api/app_manager/src/appmgr/app_mgr_proxy.cpp index aec1f49eb8..7273f64b0e 100644 --- a/interfaces/inner_api/app_manager/src/appmgr/app_mgr_proxy.cpp +++ b/interfaces/inner_api/app_manager/src/appmgr/app_mgr_proxy.cpp @@ -1989,5 +1989,46 @@ int32_t AppMgrProxy::SetSupportedProcessCacheSelf(bool isSupport) } return reply.ReadInt32(); } + +int32_t AppMgrProxy::StartNativeChildProcess(const std::string &libName, int32_t childProcessCount, + const sptr &callback) +{ + TAG_LOGD(AAFwkTag::APPMGR, "Called."); + if (libName.empty() || !callback) { + TAG_LOGE(AAFwkTag::APPMGR, "Invalid params, libName:%{private}s", libName.c_str()); + return ERR_INVALID_VALUE; + } + + MessageParcel data; + if (!WriteInterfaceToken(data)) { + TAG_LOGE(AAFwkTag::APPMGR, "Write interface token failed."); + return IPC_PROXY_ERR; + } + + if (!data.WriteString(libName)) { + TAG_LOGE(AAFwkTag::APPMGR, "Write lib name failed."); + return IPC_PROXY_ERR; + } + + if (!data.WriteInt32(childProcessCount)) { + TAG_LOGE(AAFwkTag::APPMGR, "Write param childProcessCount failed."); + return IPC_PROXY_ERR; + } + + if (!data.WriteRemoteObject(callback)) { + TAG_LOGE(AAFwkTag::APPMGR, "Write call back ipc object failed."); + return IPC_PROXY_ERR; + } + + MessageParcel reply; + MessageOption option; + auto error = SendRequest(AppMgrInterfaceCode::START_NATIVE_CHILD_PROCESS, data, reply, option); + if (error != NO_ERROR) { + TAG_LOGE(AAFwkTag::APPMGR, "Send request error: %{public}d", error); + return error; + } + return reply.ReadInt32(); +} + } // namespace AppExecFwk } // namespace OHOS diff --git a/interfaces/inner_api/app_manager/src/appmgr/app_mgr_stub.cpp b/interfaces/inner_api/app_manager/src/appmgr/app_mgr_stub.cpp index b1c3946e05..ed1995161a 100644 --- a/interfaces/inner_api/app_manager/src/appmgr/app_mgr_stub.cpp +++ b/interfaces/inner_api/app_manager/src/appmgr/app_mgr_stub.cpp @@ -190,6 +190,8 @@ AppMgrStub::AppMgrStub() &AppMgrStub::HandleSetSupportedProcessCacheSelf; memberFuncMap_[static_cast(AppMgrInterfaceCode::APP_GET_RUNNING_PROCESSES_BY_BUNDLE_TYPE)] = &AppMgrStub::HandleGetRunningProcessesByBundleType; + memberFuncMap_[static_cast(AppMgrInterfaceCode::START_NATIVE_CHILD_PROCESS)] = + &AppMgrStub::HandleStartNativeChildProcess; } AppMgrStub::~AppMgrStub() @@ -1312,5 +1314,21 @@ int32_t AppMgrStub::HandleSetSupportedProcessCacheSelf(MessageParcel &data, Mess } return NO_ERROR; } + +int32_t AppMgrStub::HandleStartNativeChildProcess(MessageParcel &data, MessageParcel &reply) +{ + TAG_LOGD(AAFwkTag::APPMGR, "Called."); + std::string libName = data.ReadString(); + int32_t childCount = data.ReadInt32(); + sptr callback = data.ReadRemoteObject(); + int32_t result = StartNativeChildProcess(libName, childCount, callback); + if (!reply.WriteInt32(result)) { + TAG_LOGE(AAFwkTag::APPMGR, "Write ret error."); + return IPC_STUB_ERR; + } + + return NO_ERROR; +} + } // namespace AppExecFwk } // namespace OHOS diff --git a/interfaces/inner_api/app_manager/src/appmgr/child_process_info.cpp b/interfaces/inner_api/app_manager/src/appmgr/child_process_info.cpp index 490bbe820b..9790eeba07 100644 --- a/interfaces/inner_api/app_manager/src/appmgr/child_process_info.cpp +++ b/interfaces/inner_api/app_manager/src/appmgr/child_process_info.cpp @@ -37,6 +37,8 @@ bool ChildProcessInfo::ReadFromParcel(Parcel &parcel) READ_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, uidData); uid = static_cast(uidData); + READ_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, processType); + bundleName = Str16ToStr8(parcel.ReadString16()); processName = Str16ToStr8(parcel.ReadString16()); srcEntry = Str16ToStr8(parcel.ReadString16()); @@ -64,6 +66,7 @@ bool ChildProcessInfo::Marshalling(Parcel &parcel) const WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, static_cast(pid)); WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, static_cast(hostPid)); WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, static_cast(uid)); + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, static_cast(processType)); WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(String16, parcel, Str8ToStr16(bundleName)); WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(String16, parcel, Str8ToStr16(processName)); WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(String16, parcel, Str8ToStr16(srcEntry)); diff --git a/interfaces/inner_api/app_manager/src/appmgr/child_scheduler_proxy.cpp b/interfaces/inner_api/app_manager/src/appmgr/child_scheduler_proxy.cpp index edf650c809..e14eaa5e71 100644 --- a/interfaces/inner_api/app_manager/src/appmgr/child_scheduler_proxy.cpp +++ b/interfaces/inner_api/app_manager/src/appmgr/child_scheduler_proxy.cpp @@ -84,5 +84,39 @@ bool ChildSchedulerProxy::ScheduleExitProcessSafely() TAG_LOGD(AAFwkTag::APPMGR, "ScheduleExitProcessSafely end."); return true; } + +bool ChildSchedulerProxy::ScheduleRunNativeProc(const sptr &mainProcessCb) +{ + TAG_LOGD(AAFwkTag::APPMGR, "ScheduleRunNativeProc start."); + MessageParcel data; + MessageParcel reply; + MessageOption option(MessageOption::TF_ASYNC); + if (!WriteInterfaceToken(data)) { + TAG_LOGE(AAFwkTag::APPMGR, "Write interface token failed."); + return false; + } + + if (!data.WriteRemoteObject(mainProcessCb)) { + TAG_LOGE(AAFwkTag::APPMGR, "Write main process callback ipc object failed."); + return false; + } + + sptr remote = Remote(); + if (remote == nullptr) { + TAG_LOGE(AAFwkTag::APPMGR, "Remote() is null."); + return false; + } + + int32_t ret = remote->SendRequest( + static_cast(IChildScheduler::Message::SCHEDULE_RUN_NATIVE_PROC), data, reply, option); + if (ret != NO_ERROR) { + TAG_LOGE(AAFwkTag::APPMGR, "SendRequest is failed, error code: %{public}d.", ret); + return false; + } + + TAG_LOGD(AAFwkTag::APPMGR, "ScheduleRunNativeProc end."); + return true; +} + } // namespace AppExecFwk } // namespace OHOS diff --git a/interfaces/inner_api/app_manager/src/appmgr/child_scheduler_stub.cpp b/interfaces/inner_api/app_manager/src/appmgr/child_scheduler_stub.cpp index 1fda7ab84c..b434032513 100644 --- a/interfaces/inner_api/app_manager/src/appmgr/child_scheduler_stub.cpp +++ b/interfaces/inner_api/app_manager/src/appmgr/child_scheduler_stub.cpp @@ -27,6 +27,8 @@ ChildSchedulerStub::ChildSchedulerStub() &ChildSchedulerStub::HandleScheduleLoadJs; memberFuncMap_[static_cast(IChildScheduler::Message::SCHEDULE_EXIT_PROCESS_SAFELY)] = &ChildSchedulerStub::HandleScheduleExitProcessSafely; + memberFuncMap_[static_cast(IChildScheduler::Message::SCHEDULE_RUN_NATIVE_PROC)] = + &ChildSchedulerStub::HandleScheduleRunNativeProc; } ChildSchedulerStub::~ChildSchedulerStub() @@ -68,5 +70,13 @@ int32_t ChildSchedulerStub::HandleScheduleExitProcessSafely(MessageParcel &data, ScheduleExitProcessSafely(); return ERR_NONE; } + +int32_t ChildSchedulerStub::HandleScheduleRunNativeProc(MessageParcel &data, MessageParcel &reply) +{ + sptr cb = data.ReadRemoteObject(); + ScheduleRunNativeProc(cb); + return ERR_NONE; +} + } // namespace AppExecFwk } // namespace OHOS \ No newline at end of file diff --git a/interfaces/inner_api/app_manager/src/appmgr/native_child_notify_proxy.cpp b/interfaces/inner_api/app_manager/src/appmgr/native_child_notify_proxy.cpp new file mode 100644 index 0000000000..e97ec17658 --- /dev/null +++ b/interfaces/inner_api/app_manager/src/appmgr/native_child_notify_proxy.cpp @@ -0,0 +1,94 @@ +/* + * 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 "native_child_notify_proxy.h" +#include "hilog_tag_wrapper.h" +#include "hilog_wrapper.h" +#include "ipc_types.h" + +namespace OHOS { +namespace AppExecFwk { + +NativeChildNotifyProxy::NativeChildNotifyProxy(const sptr &impl) + : IRemoteProxy(impl) +{ +} + +bool NativeChildNotifyProxy::WriteInterfaceToken(MessageParcel &data) +{ + if (!data.WriteInterfaceToken(NativeChildNotifyProxy::GetDescriptor())) { + TAG_LOGE(AAFwkTag::APPMGR, "NativeChildNotifyProxy write interface token failed"); + return false; + } + + return true; +} + +int32_t NativeChildNotifyProxy::SendRequest(uint32_t code, MessageParcel &data, + MessageParcel &reply, MessageOption& option) +{ + sptr remote = Remote(); + if (!remote) { + TAG_LOGE(AAFwkTag::APPMGR, "NativeChildNotifyProxy get remote object failed"); + return ERR_NULL_OBJECT; + } + + int32_t ret = remote->SendRequest(code, data, reply, option); + if (ret != NO_ERROR) { + TAG_LOGE(AAFwkTag::APPMGR, "NativeChildNotifyProxy SendRequest failed(%{public}d)", ret); + return ret; + } + + return NO_ERROR; +} + +void NativeChildNotifyProxy::OnNativeChildStarted(const sptr &nativeChild) +{ + TAG_LOGD(AAFwkTag::APPMGR, "NativeChildNotifyProxy OnNativeChildStarted"); + MessageParcel data; + MessageParcel reply; + MessageOption option(MessageOption::TF_ASYNC); + if (!WriteInterfaceToken(data)) { + return; + } + + if (!data.WriteRemoteObject(nativeChild)) { + TAG_LOGE(AAFwkTag::APPMGR, "NativeChildNotifyProxy write native child ipc object failed."); + return; + } + + SendRequest(INativeChildNotify::IPC_ID_ON_NATIVE_CHILD_STARTED, data, reply, option); +} + +void NativeChildNotifyProxy::OnError(int32_t errCode) +{ + TAG_LOGD(AAFwkTag::APPMGR, "NativeChildNotifyProxy OnError(%{public}d)", errCode); + MessageParcel data; + MessageParcel reply; + MessageOption option(MessageOption::TF_ASYNC); + if (!WriteInterfaceToken(data)) { + return; + } + + if (!data.WriteInt32(errCode)) { + TAG_LOGE(AAFwkTag::APPMGR, "NativeChildNotifyProxy write error code failed."); + return; + } + + SendRequest(INativeChildNotify::IPC_ID_ON_ERROR, data, reply, option); +} + +} // OHOS +} // AppExecFwk \ No newline at end of file diff --git a/interfaces/inner_api/app_manager/src/appmgr/native_child_notify_stub.cpp b/interfaces/inner_api/app_manager/src/appmgr/native_child_notify_stub.cpp new file mode 100644 index 0000000000..63ad1fb4e2 --- /dev/null +++ b/interfaces/inner_api/app_manager/src/appmgr/native_child_notify_stub.cpp @@ -0,0 +1,71 @@ +/* + * 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 "native_child_notify_stub.h" +#include "hilog_tag_wrapper.h" +#include "hilog_wrapper.h" +#include "ipc_types.h" + +namespace OHOS { +namespace AppExecFwk { + +int NativeChildNotifyStub::OnRemoteRequest(uint32_t code, MessageParcel &data, + MessageParcel &reply, MessageOption &option) +{ + TAG_LOGD(AAFwkTag::APPMGR, "NativeChildNotifyStub::OnRemoteRequest, code=%{public}u, flags=%{public}d.", + code, option.GetFlags()); + std::u16string descriptor = NativeChildNotifyStub::GetDescriptor(); + std::u16string remoteDesc = data.ReadInterfaceToken(); + if (descriptor != remoteDesc) { + TAG_LOGE(AAFwkTag::APPMGR, "A local descriptor is not equivalent to a remote"); + return ERR_INVALID_STATE; + } + + int32_t ret; + switch (code) { + case INativeChildNotify::IPC_ID_ON_NATIVE_CHILD_STARTED: + ret = HandleOnNativeChildStarted(data, reply); + break; + + case INativeChildNotify::IPC_ID_ON_ERROR: + ret = HandleOnError(data, reply); + break; + + default: + TAG_LOGW(AAFwkTag::APPMGR, "NativeChildNotifyStub Unknow ipc call(%{public}u)", code); + ret = IPCObjectStub::OnRemoteRequest(code, data, reply, option); + break; + } + + TAG_LOGD(AAFwkTag::APPMGR, "NativeChildNotifyStub::OnRemoteRequest end"); + return ret; +} + +int32_t NativeChildNotifyStub::HandleOnNativeChildStarted(MessageParcel &data, MessageParcel &reply) +{ + sptr cb = data.ReadRemoteObject(); + OnNativeChildStarted(cb); + return ERR_NONE; +} + +int32_t NativeChildNotifyStub::HandleOnError(MessageParcel &data, MessageParcel &reply) +{ + int32_t err = data.ReadInt32(); + OnError(err); + return ERR_NONE; +} + +} // OHOS +} // AppExecFwk diff --git a/interfaces/inner_api/child_process_manager/BUILD.gn b/interfaces/inner_api/child_process_manager/BUILD.gn index e9bd88528e..bbd9caaebe 100644 --- a/interfaces/inner_api/child_process_manager/BUILD.gn +++ b/interfaces/inner_api/child_process_manager/BUILD.gn @@ -32,6 +32,7 @@ ohos_shared_library("child_process_manager") { "${ability_runtime_native_path}/ability/native/child_process_manager/child_process_manager.cpp", "${ability_runtime_native_path}/ability/native/child_process_manager/child_process_manager_error_utils.cpp", "${ability_runtime_native_path}/ability/native/child_process_manager/js_child_process.cpp", + "${ability_runtime_native_path}/ability/native/child_process_manager/native_child_ipc_process.cpp", ] deps = [ @@ -50,6 +51,7 @@ ohos_shared_library("child_process_manager") { "eventhandler:libeventhandler", "hilog:libhilog", "init:libbegetutil", + "ipc:ipc_capi", "ipc:ipc_core", "napi:ace_napi", "samgr:samgr_proxy", diff --git a/interfaces/inner_api/child_process_manager/include/child_process_manager.h b/interfaces/inner_api/child_process_manager/include/child_process_manager.h index 3bf2137fe4..f9fbf3c654 100644 --- a/interfaces/inner_api/child_process_manager/include/child_process_manager.h +++ b/interfaces/inner_api/child_process_manager/include/child_process_manager.h @@ -25,6 +25,7 @@ #include "child_process_manager_error_utils.h" #include "hap_module_info.h" #include "runtime.h" +#include "iremote_object.h" namespace OHOS { namespace AbilityRuntime { @@ -41,12 +42,15 @@ public: bool IsChildProcess(); ChildProcessManagerErrorCode StartChildProcessBySelfFork(const std::string &srcEntry, pid_t &pid); ChildProcessManagerErrorCode StartChildProcessByAppSpawnFork(const std::string &srcEntry, pid_t &pid); + ChildProcessManagerErrorCode StartNativeChildProcessByAppSpawnFork( + const std::string &libName, const sptr &callbackStub); bool GetBundleInfo(AppExecFwk::BundleInfo &bundleInfo); bool GetHapModuleInfo(const AppExecFwk::BundleInfo &bundleInfo, AppExecFwk::HapModuleInfo &hapModuleInfo); std::unique_ptr CreateRuntime(const AppExecFwk::BundleInfo &bundleInfo, const AppExecFwk::HapModuleInfo &hapModuleInfo, const bool fromAppSpawn, const bool jitEnabled); bool LoadJsFile(const std::string &srcEntry, const AppExecFwk::HapModuleInfo &hapModuleInfo, std::unique_ptr &runtime); + bool LoadNativeLib(const std::string &libPath, const sptr &mainProcessCb); void SetForkProcessJITEnabled(bool jitEnabled); void SetForkProcessDebugOption(const std::string bundleName, const bool isStartWithDebug, const bool isDebugApp, const bool isStartWithNative); @@ -55,6 +59,7 @@ private: ChildProcessManager(); ChildProcessManagerErrorCode PreCheck(); + ChildProcessManagerErrorCode PreCheckNativeProcess(); void RegisterSignal(); void HandleChildProcessBySelfFork(const std::string &srcEntry, const AppExecFwk::BundleInfo &bundleInfo); bool hasChildProcessRecord(); diff --git a/interfaces/inner_api/child_process_manager/include/child_process_manager_error_utils.h b/interfaces/inner_api/child_process_manager/include/child_process_manager_error_utils.h index 3bd4893d87..18c572d1ea 100644 --- a/interfaces/inner_api/child_process_manager/include/child_process_manager_error_utils.h +++ b/interfaces/inner_api/child_process_manager/include/child_process_manager_error_utils.h @@ -31,6 +31,10 @@ enum class ChildProcessManagerErrorCode { ERR_GET_BUNDLE_INFO_FAILED = 5, ERR_GET_APP_MGR_FAILED = 6, ERR_GET_APP_MGR_START_PROCESS_FAILED = 7, + ERR_UNSUPPORT_NATIVE_CHILD_PROCESS = 8, + ERR_MAX_NATIVE_CHILD_PROCESSES = 9, + ERR_NATIVE_CHILD_PROCESS_LOAD_LIB = 10, + ERR_NATIVE_CHILD_PROCESS_CONNECT = 11, }; const std::map INTERNAL_ERR_CODE_MAP = { diff --git a/interfaces/inner_api/child_process_manager/include/child_process_start_info.h b/interfaces/inner_api/child_process_manager/include/child_process_start_info.h index 75cbfabd60..07828eae1b 100644 --- a/interfaces/inner_api/child_process_manager/include/child_process_start_info.h +++ b/interfaces/inner_api/child_process_manager/include/child_process_start_info.h @@ -17,6 +17,7 @@ #define OHOS_ABILITY_RUNTIME_CHILD_PROCESS_START_INFO_H #include +#include "iremote_object.h" namespace OHOS { namespace AbilityRuntime { @@ -26,6 +27,7 @@ struct ChildProcessStartInfo { std::string srcEntry; std::string hapPath; bool isEsModule = true; + sptr ipcObj; }; } // namespace AbilityRuntime } // namespace OHOS diff --git a/interfaces/inner_api/child_process_manager/include/native_child_ipc_process.h b/interfaces/inner_api/child_process_manager/include/native_child_ipc_process.h new file mode 100644 index 0000000000..5a007069e8 --- /dev/null +++ b/interfaces/inner_api/child_process_manager/include/native_child_ipc_process.h @@ -0,0 +1,53 @@ +/* + * 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 OHOS_ABILITY_RUNTIME_NATIVE_CHILD_IPC_PROCESS_H +#define OHOS_ABILITY_RUNTIME_NATIVE_CHILD_IPC_PROCESS_H + +#include +#include "child_process.h" +#include "native_child_notify_interface.h" +#include "ipc_inner_object.h" + +namespace OHOS { +namespace AbilityRuntime { + +class NativeChildIpcProcess : public ChildProcess { +public: + NativeChildIpcProcess() = default; + ~NativeChildIpcProcess(); + + static std::shared_ptr Create(); + + bool Init(const std::shared_ptr &info) override; + void OnStart() override; + +private: + bool LoadNativeLib(const std::shared_ptr &info); + void UnloadNativeLib(); + + typedef OHIPCRemoteStub* (*NativeChildProcess_OnConnect)(); + typedef void (*NativeChildProcess_MainProc)(); + + sptr mainProcessCb_; + void *nativeLibHandle_ = nullptr; + NativeChildProcess_OnConnect funcNativeLibOnConnect_ = nullptr; + NativeChildProcess_MainProc funcNativeLibMainProc_ = nullptr; +}; + +} // namespace AbilityRuntime +} // namespace OHOS + +#endif // OHOS_ABILITY_RUNTIME_NATIVE_CHILD_IPC_PROCESS_H \ No newline at end of file diff --git a/interfaces/kits/c/ability/ability_runtime/child_process/native_child_process.h b/interfaces/kits/c/ability/ability_runtime/child_process/native_child_process.h new file mode 100644 index 0000000000..85301c6a59 --- /dev/null +++ b/interfaces/kits/c/ability/ability_runtime/child_process/native_child_process.h @@ -0,0 +1,144 @@ +/* + * 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 OHOS_C_ABILITY_RUNTIME_NATIVE_CHILD_PROCESS_H +#define OHOS_C_ABILITY_RUNTIME_NATIVE_CHILD_PROCESS_H + +#include "ipc_cparcel.h" + +/** + * @file native_child_process.h + * + * @brief Defines the functions for native child process management. + * @library libchild_process.so + * @syscap SystemCapability.Ability.AbilityRuntime.Core + * @since 12 + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief native child process error code + * @since 12 + */ +enum Ability_NativeChildProcess_ErrCode { + /** + * @error The operation completed successfully + */ + NCP_NOERROR = 0, + + /** + * @error Invalid param + */ + NCP_ERR_INVALID_PARAM = 401, + + /** + * @error Unsupport start native process + */ + NCP_ERR_NOT_SUPPORTED = 801, + + /** + * @error Internal error + */ + NCP_ERR_INTERNAL = 16000050, + + /** + * @error Can not start another during child process startup, try again after current child process started + */ + NCP_ERR_BUSY = 16010001, + + /** + * @error Start native child time out + */ + NCP_ERR_TIMEOUT = 16010002, + + /** + * @error Service process error + */ + NCP_ERR_SERVICE = 16010003, + + /** + * @error Multi process disabled, can not start child process + */ + NCP_ERR_MULTI_PROCESS_DISABLED = 16010004, + + /** + * @error Already in child process, only main process can start child + */ + NCP_ERR_ALREADY_IN_CHILD = 16010005, + + /** + * @error Max native child processes reached, can not start another + */ + NCP_ERR_MAX_CHILD_PROCESSES_REACHED = 16010006, + + /** + * @error Child process load library failed + */ + NCP_ERR_CHILD_PROCESS_LOAD_LIB = 16010007, + + /** + * @error Faild to invoke OnConnect method in library + */ + NCP_ERR_CHILD_PROCESS_CONNECT = 16010008, +}; + + +/** + * @brief callback function for notify the child process start result, see OH_Ability_CreateNativeChildProcess + * + * @param errCode Zero if successful, an error otherwise, see Ability_NativeChildProcess_ErrCode for detail + * @param remoteProxy IPC object implemented in the sharded lib loaded by child process; will be nullptr when failed + * @since 12 + */ +typedef void (*OH_Ability_OnNativeChildProcessStarted)(int errCode, OHIPCRemoteProxy *remoteProxy); + +/** + * @brief Create native child process for app and load shared library specified by param, + * process startup result is asynchronously notified via callback + * Lib file must be implemented and exported follow functions: + * 1. OHIPCRemoteStub* NativeChildProcess_OnConnect() + * 2. void NativeChildProcess_MainProc() + * + * Processing logic be like follows: + * Main Process: + * 1. Call OH_Ability_CreateNativeChildProcess(libName, onProcessStartedCallback) + * Child Process: + * 2. dlopen(libName) + * 3. dlsym("NativeChildProcess_OnConnect") & dlsym("NativeChildProcess_MainProc") + * 4. ipcRemote = NativeChildProcess_OnConnect() + * 5. NativeChildProcess_MainProc() + * Main Process: + * 6. onProcessStartedCallback(ipcRemote, errCode) + * Child Process: + * 7. Process exit after NativeChildProcess_MainProc() method returned + * + * @param libName Name of the library file loaded by child process, can not be nullptr + * @param onProcessStarted Callback for notify the child process start result + * @return Zero if successful, an error otherwise, see Ability_NativeChildProcess_ErrCode for detail + * @see OH_Ability_OnNativeChildProcessStarted + * @since 12 + */ +int OH_Ability_CreateNativeChildProcess(const char* libName, + OH_Ability_OnNativeChildProcessStarted onProcessStarted); + + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // OHOS_C_ABILITY_RUNTIME_NATIVE_CHILD_PROCESS_H diff --git a/interfaces/kits/native/appkit/app/child_main_thread.h b/interfaces/kits/native/appkit/app/child_main_thread.h index ca6d337866..73a1abf9de 100644 --- a/interfaces/kits/native/appkit/app/child_main_thread.h +++ b/interfaces/kits/native/appkit/app/child_main_thread.h @@ -39,6 +39,7 @@ public: static void Start(const ChildProcessInfo &processInfo); bool ScheduleLoadJs() override; bool ScheduleExitProcessSafely() override; + bool ScheduleRunNativeProc(const sptr &mainProcessCb) override; private: bool Init(const std::shared_ptr &runner, const ChildProcessInfo &processInfo); @@ -49,6 +50,8 @@ private: void ExitProcessSafely(); void GetNativeLibPath(const BundleInfo &bundleInfo, AppLibPathMap &appLibPaths); void GetHapSoPath(const HapModuleInfo &hapInfo, AppLibPathMap &appLibPaths, bool isPreInstallApp); + void HandleRunNativeProc(const sptr &mainProcessCb); + void UpdateNativeChildLibPath(const AppLibPathMap &appLibPaths); std::string GetLibPath(const std::string &hapPath, bool isPreInstallApp); sptr appMgr_ = nullptr; diff --git a/services/appmgr/include/app_mgr_service.h b/services/appmgr/include/app_mgr_service.h index 8d16a88ba9..397362bf81 100644 --- a/services/appmgr/include/app_mgr_service.h +++ b/services/appmgr/include/app_mgr_service.h @@ -503,6 +503,17 @@ public: int32_t NotifyMemorySizeStateChanged(bool isMemorySizeSufficent) override; int32_t SetSupportedProcessCacheSelf(bool isSupport) override; + + /** + * Start native child process, callde by ChildProcessManager. + * @param libName lib file name to be load in child process + * @param childProcessCount current started child process count + * @param callback callback for notify start result + * @return Returns ERR_OK on success, others on failure. + */ + int32_t StartNativeChildProcess(const std::string &libName, int32_t childProcessCount, + const sptr &callback) override; + private: /** * Init, Initialize application services. diff --git a/services/appmgr/include/app_mgr_service_inner.h b/services/appmgr/include/app_mgr_service_inner.h index cd7138a8f9..874feb29af 100644 --- a/services/appmgr/include/app_mgr_service_inner.h +++ b/services/appmgr/include/app_mgr_service_inner.h @@ -995,6 +995,17 @@ public: */ virtual void ExitChildProcessSafelyByChildPid(const pid_t pid); + /** + * Start native child process, callde by ChildProcessManager. + * @param hostPid Host process pid. + * @param childProcessCount current started child process count + * @param libName lib file name to be load in child process + * @param callback callback for notify start result + * @return Returns ERR_OK on success, others on failure. + */ + virtual int32_t StartNativeChildProcess(const pid_t hostPid, + const std::string &libName, int32_t childProcessCount, const sptr &callback); + /** * Whether the current application process is the last surviving process. * @param bundleName To query the bundle name of a process. diff --git a/services/appmgr/include/child_process_record.h b/services/appmgr/include/child_process_record.h index bb3565a946..dd3690b9e2 100644 --- a/services/appmgr/include/child_process_record.h +++ b/services/appmgr/include/child_process_record.h @@ -22,6 +22,7 @@ #include "app_death_recipient.h" #include "child_scheduler_interface.h" +#include "child_process_info.h" namespace OHOS { namespace AppExecFwk { @@ -31,10 +32,15 @@ class ChildProcessRecord { public: ChildProcessRecord(pid_t hostPid, const std::string &srcEntry, const std::shared_ptr hostRecord, int32_t childProcessCount, bool isStartWithDebug); + ChildProcessRecord(pid_t hostPid, const std::string &libName, const std::shared_ptr hostRecord, + const sptr &mainProcessCb, int32_t childProcessCount, bool isStartWithDebug); virtual ~ChildProcessRecord(); static std::shared_ptr CreateChildProcessRecord(pid_t hostPid, const std::string &srcEntry, const std::shared_ptr hostRecord, int32_t childProcessCount, bool isStartWithDebug); + static std::shared_ptr CreateNativeChildProcessRecord(pid_t hostPid, const std::string &libName, + const std::shared_ptr hostRecord, const sptr &mainProcessCb, + int32_t childProcessCount, bool isStartWithDebug); void SetPid(pid_t pid); pid_t GetPid() const; @@ -51,6 +57,9 @@ public: void RemoveDeathRecipient(); void ScheduleExitProcessSafely(); bool isStartWithDebug(); + int32_t GetProcessType() const; + sptr GetMainProcessCallback() const; + void ClearMainProcessCallback(); private: void MakeProcessName(const std::shared_ptr hostRecord); @@ -58,11 +67,13 @@ private: pid_t hostPid_ = 0; int32_t uid_ = 0; int32_t childProcessCount_ = 0; + int32_t childProcessType_ = CHILD_PROCESS_TYPE_JS; std::string processName_; std::string srcEntry_; std::weak_ptr hostRecord_; sptr scheduler_ = nullptr; sptr deathRecipient_ = nullptr; + sptr mainProcessCb_ = nullptr; bool isStartWithDebug_; }; } // namespace AppExecFwk diff --git a/services/appmgr/src/app_mgr_service.cpp b/services/appmgr/src/app_mgr_service.cpp index 03ed44a33f..bb007b78fe 100644 --- a/services/appmgr/src/app_mgr_service.cpp +++ b/services/appmgr/src/app_mgr_service.cpp @@ -1441,5 +1441,19 @@ int32_t AppMgrService::SetSupportedProcessCacheSelf(bool isSupport) } return appMgrServiceInner_->SetSupportedProcessCacheSelf(isSupport); } + +int32_t AppMgrService::StartNativeChildProcess(const std::string &libName, int32_t childProcessCount, + const sptr &callback) +{ + TAG_LOGI(AAFwkTag::APPMGR, "Called"); + if (!IsReady()) { + TAG_LOGE(AAFwkTag::APPMGR, "Not ready."); + return ERR_INVALID_OPERATION; + } + + return appMgrServiceInner_->StartNativeChildProcess( + IPCSkeleton::GetCallingPid(), libName, childProcessCount, callback); +} + } // namespace AppExecFwk } // namespace OHOS diff --git a/services/appmgr/src/app_mgr_service_inner.cpp b/services/appmgr/src/app_mgr_service_inner.cpp index a23bc16617..273ab73f22 100644 --- a/services/appmgr/src/app_mgr_service_inner.cpp +++ b/services/appmgr/src/app_mgr_service_inner.cpp @@ -5896,6 +5896,7 @@ int32_t AppMgrServiceInner::GetChildProcessInfo(const std::shared_ptrGetPid(); info.hostPid = childProcessRecord->GetHostPid(); info.uid = childProcessRecord->GetUid(); + info.processType = childProcessRecord->GetProcessType(); info.bundleName = appRecord->GetBundleName(); info.processName = childProcessRecord->GetProcessName(); info.srcEntry = childProcessRecord->GetSrcEntry(); @@ -5944,7 +5945,12 @@ void AppMgrServiceInner::AttachChildProcess(const pid_t pid, const sptrSetDeathRecipient(appDeathRecipient); childRecord->RegisterDeathRecipient(); - childScheduler->ScheduleLoadJs(); + if (childRecord->GetProcessType() != CHILD_PROCESS_TYPE_NATIVE) { + childScheduler->ScheduleLoadJs(); + } else { + childScheduler->ScheduleRunNativeProc(childRecord->GetMainProcessCallback()); + childRecord->ClearMainProcessCallback(); + } } void AppMgrServiceInner::OnChildProcessRemoteDied(const wptr &remote) @@ -6539,5 +6545,48 @@ void AppMgrServiceInner::OnAppCacheStateChanged(const std::shared_ptr::GetInstance()->OnAppCacheStateChanged(appRecord); } + +int32_t AppMgrServiceInner::StartNativeChildProcess(const pid_t hostPid, const std::string &libName, + int32_t childProcessCount, const sptr &callback) +{ + TAG_LOGI(AAFwkTag::APPMGR, "StartNativeChildProcess, hostPid:%{public}d", hostPid); + if (hostPid <= 0 || libName.empty() || !callback) { + TAG_LOGE(AAFwkTag::APPMGR, "Invalid param: hostPid:%{public}d libName:%{private}s", + hostPid, libName.c_str()); + return ERR_INVALID_VALUE; + } + + if (!AAFwk::AppUtils::GetInstance().IsSupportNativeChildProcess()) { + TAG_LOGE(AAFwkTag::APPMGR, "Unsupport native child process"); + return ERR_INVALID_OPERATION; + } + + int32_t errCode = StartChildProcessPreCheck(hostPid); + if (errCode != ERR_OK) { + return errCode; + } + + auto appRecord = GetAppRunningRecordByPid(hostPid); + if (!appRecord) { + TAG_LOGI(AAFwkTag::APPMGR, "Get app runnning record(hostPid:%{public}d) failed.", hostPid); + return ERR_INVALID_OPERATION; + } + + auto childRecordMap = appRecord->GetChildProcessRecordMap(); + auto itNativeChildInfo = find_if(childRecordMap.begin(), childRecordMap.end(), [] (const auto &pair) -> bool { + return pair.second->GetProcessType() == CHILD_PROCESS_TYPE_NATIVE; + }); + + if (itNativeChildInfo != childRecordMap.end()) { + TAG_LOGI(AAFwkTag::APPMGR, "Native child process still alive(hostPid:%{public}d childPid:%{public}d)", + hostPid, itNativeChildInfo->second->GetPid()); + return ERR_OVERFLOW; + } + + pid_t dummyChildPid = 0; + auto nativeChildRecord = ChildProcessRecord::CreateNativeChildProcessRecord( + hostPid, libName, appRecord, callback, childProcessCount, false); + return StartChildProcessImpl(nativeChildRecord, appRecord, dummyChildPid); +} } // namespace AppExecFwk -} // namespace OHOS +} // namespace OHOS \ No newline at end of file diff --git a/services/appmgr/src/child_process_record.cpp b/services/appmgr/src/child_process_record.cpp index 2bf2e9f341..a5a3b9d828 100644 --- a/services/appmgr/src/child_process_record.cpp +++ b/services/appmgr/src/child_process_record.cpp @@ -29,6 +29,15 @@ ChildProcessRecord::ChildProcessRecord(pid_t hostPid, const std::string &srcEntr MakeProcessName(hostRecord); } +ChildProcessRecord::ChildProcessRecord(pid_t hostPid, const std::string &libName, + const std::shared_ptr hostRecord, const sptr &mainProcessCb, + int32_t childProcessCount, bool isStartWithDebug) + : hostPid_(hostPid), childProcessCount_(childProcessCount), childProcessType_(CHILD_PROCESS_TYPE_NATIVE), + srcEntry_(libName), hostRecord_(hostRecord), mainProcessCb_(mainProcessCb), isStartWithDebug_(isStartWithDebug) +{ + MakeProcessName(hostRecord); +} + ChildProcessRecord::~ChildProcessRecord() { TAG_LOGD(AAFwkTag::APPMGR, "Called."); @@ -46,6 +55,19 @@ std::shared_ptr ChildProcessRecord::CreateChildProcessRecord return std::make_shared(hostPid, srcEntry, hostRecord, childProcessCount, isStartWithDebug); } +std::shared_ptr ChildProcessRecord::CreateNativeChildProcessRecord( + pid_t hostPid, const std::string &libName, const std::shared_ptr hostRecord, + const sptr &mainProcessCb, int32_t childProcessCount, bool isStartWithDebug) +{ + TAG_LOGD(AAFwkTag::APPMGR, "hostPid: %{public}d, libName: %{public}s", hostPid, libName.c_str()); + if (hostPid <= 0 || libName.empty() || !hostRecord || !mainProcessCb) { + TAG_LOGE(AAFwkTag::APPMGR, "Invalid parameter."); + return nullptr; + } + return std::make_shared(hostPid, libName, hostRecord, mainProcessCb, + childProcessCount, isStartWithDebug); +} + void ChildProcessRecord::SetPid(pid_t pid) { pid_ = pid; @@ -148,6 +170,10 @@ void ChildProcessRecord::MakeProcessName(const std::shared_ptr std::string filename = std::filesystem::path(srcEntry_).stem(); if (!filename.empty()) { processName_.append(":"); + if (childProcessType_ == CHILD_PROCESS_TYPE_NATIVE) { + processName_.append("Native_"); + } + processName_.append(filename); } processName_.append(std::to_string(childProcessCount_)); @@ -158,5 +184,21 @@ bool ChildProcessRecord::isStartWithDebug() { return isStartWithDebug_; } + +int32_t ChildProcessRecord::GetProcessType() const +{ + return childProcessType_; +} + +sptr ChildProcessRecord::GetMainProcessCallback() const +{ + return mainProcessCb_; +} + +void ChildProcessRecord::ClearMainProcessCallback() +{ + mainProcessCb_.clear(); +} + } // namespace AppExecFwk } // namespace OHOS diff --git a/services/common/BUILD.gn b/services/common/BUILD.gn index 42c58bcd42..451de687bc 100644 --- a/services/common/BUILD.gn +++ b/services/common/BUILD.gn @@ -30,6 +30,7 @@ config("common_config") { "${ability_runtime_innerkits_path}/*", "${ability_runtime_napi_path}/*", "${ability_runtime_native_path}/ability/native/*", + "${ability_runtime_native_path}/child_process/*", "${ability_runtime_path}/frameworks/simulator/ability_simulator/*", "${ability_runtime_path}/tools/aa/*", "${ability_runtime_services_path}/common/*", diff --git a/services/common/include/app_utils.h b/services/common/include/app_utils.h index b1203d9394..509ab97bbf 100644 --- a/services/common/include/app_utils.h +++ b/services/common/include/app_utils.h @@ -47,6 +47,7 @@ public: bool IsStartOptionsWithProcessOptions(); bool EnableMoveUIAbilityToBackgroundApi(); bool IsLaunchEmbededUIAbility(); + bool IsSupportNativeChildProcess(); private: AppUtils(); @@ -65,6 +66,7 @@ private: volatile DeviceConfiguration isStartOptionsWithProcessOptions_ = {false, false}; volatile DeviceConfiguration enableMoveUIAbilityToBackgroundApi_ = {false, true}; volatile DeviceConfiguration isLaunchEmbededUIAbility_ = {false, false}; + volatile DeviceConfiguration isSupportNativeChildProcess_ = {false, false}; DISALLOW_COPY_AND_MOVE(AppUtils); }; } // namespace AAFwk diff --git a/services/common/src/app_utils.cpp b/services/common/src/app_utils.cpp index 7d47ade7dd..a044a0620e 100644 --- a/services/common/src/app_utils.cpp +++ b/services/common/src/app_utils.cpp @@ -41,7 +41,9 @@ const std::string START_OPTIONS_WITH_PROCESS_OPTION = "persist.sys.abilityms.sta const std::string MOVE_UI_ABILITY_TO_BACKGROUND_API_ENABLE = "persist.sys.abilityms.move_ui_ability_to_background_api_enable"; const std::string LAUNCH_EMBEDED_UI_ABILITY = "const.abilityms.launch_embeded_ui_ability"; +const std::string SUPPROT_NATIVE_CHILD_PROCESS = "persist.sys.abilityms.start_native_child_process"; } + AppUtils::~AppUtils() {} AppUtils::AppUtils() @@ -207,5 +209,16 @@ bool AppUtils::IsLaunchEmbededUIAbility() TAG_LOGI(AAFwkTag::DEFAULT, "isLaunchEmbededUIAbility_ is %{public}d", isLaunchEmbededUIAbility_.value); return isLaunchEmbededUIAbility_.value; } + +bool AppUtils::IsSupportNativeChildProcess() +{ + if (!isSupportNativeChildProcess_.isLoaded) { + isSupportNativeChildProcess_.value = system::GetBoolParameter(SUPPROT_NATIVE_CHILD_PROCESS, false); + isSupportNativeChildProcess_.isLoaded = true; + } + TAG_LOGI(AAFwkTag::DEFAULT, "isSupportNativeChildProcess_ is %{public}d", isSupportNativeChildProcess_.value); + return isSupportNativeChildProcess_.value; +} + } // namespace AAFwk } // namespace OHOS diff --git a/test/mock/frameworks_kits_appkit_test/include/mock_app_mgr_service.h b/test/mock/frameworks_kits_appkit_test/include/mock_app_mgr_service.h index fac765766e..4bdd670d5b 100644 --- a/test/mock/frameworks_kits_appkit_test/include/mock_app_mgr_service.h +++ b/test/mock/frameworks_kits_appkit_test/include/mock_app_mgr_service.h @@ -84,6 +84,8 @@ public: MOCK_METHOD1(UnregisterRenderStateObserver, int32_t(const sptr &observer)); MOCK_METHOD2(UpdateRenderState, int32_t(pid_t renderPid, int32_t state)); MOCK_METHOD1(SetSupportedProcessCacheSelf, int32_t(bool isSupported)); + MOCK_METHOD3(StartNativeChildProcess, int32_t(const std::string &libName, int32_t childProcessCount, + const sptr &callback)); void AttachApplication(const sptr& app) { diff --git a/test/mock/mock_appmgr_service/include/mock_app_mgr_service_inner.h b/test/mock/mock_appmgr_service/include/mock_app_mgr_service_inner.h index 88b8e33737..12e5464304 100644 --- a/test/mock/mock_appmgr_service/include/mock_app_mgr_service_inner.h +++ b/test/mock/mock_appmgr_service/include/mock_app_mgr_service_inner.h @@ -65,6 +65,8 @@ public: int32_t childProcessCount, bool inStartWithDebug)); MOCK_METHOD1(GetChildProcessInfoForSelf, int32_t(ChildProcessInfo &info)); MOCK_METHOD4(PreloadApplication, int32_t(const std::string&, int32_t, AppExecFwk::PreloadMode, int32_t)); + MOCK_METHOD4(StartNativeChildProcess, int32_t(const pid_t hostPid, const std::string &libName, + int32_t childProcessCount, const sptr &callback)); void StartSpecifiedAbility(const AAFwk::Want&, const AppExecFwk::AbilityInfo&, int32_t) {} diff --git a/test/mock/services_appmgr_test/include/mock_app_mgr_service.h b/test/mock/services_appmgr_test/include/mock_app_mgr_service.h index 228775be2e..ec96bfa7c2 100644 --- a/test/mock/services_appmgr_test/include/mock_app_mgr_service.h +++ b/test/mock/services_appmgr_test/include/mock_app_mgr_service.h @@ -101,6 +101,8 @@ public: MOCK_METHOD0(IsFinalAppProcess, bool()); MOCK_METHOD1(SetSupportedProcessCacheSelf, int32_t(bool isSupport)); + MOCK_METHOD3(StartNativeChildProcess, int32_t(const std::string &libName, int32_t childProcessCount, + const sptr &callback)); virtual int StartUserTestProcess( const AAFwk::Want &want, const sptr &observer, const BundleInfo &bundleInfo, int32_t userId) { diff --git a/test/mock/services_appmgr_test/include/mock_app_mgr_service_inner.h b/test/mock/services_appmgr_test/include/mock_app_mgr_service_inner.h index 6b0f773cd9..f672f7d0f7 100644 --- a/test/mock/services_appmgr_test/include/mock_app_mgr_service_inner.h +++ b/test/mock/services_appmgr_test/include/mock_app_mgr_service_inner.h @@ -71,6 +71,8 @@ public: MOCK_METHOD1(IsWaitingDebugApp, bool(const std::string &bundleName)); MOCK_METHOD0(ClearNonPersistWaitingDebugFlag, void()); MOCK_METHOD0(IsMemorySizeSufficent, bool()); + MOCK_METHOD4(StartNativeChildProcess, int32_t(const pid_t hostPid, + const std::string &libName, int32_t childProcessCount, const sptr &callback)); void StartSpecifiedAbility(const AAFwk::Want&, const AppExecFwk::AbilityInfo&, int32_t) {} diff --git a/test/unittest/BUILD.gn b/test/unittest/BUILD.gn index 23fd0224e9..986f650204 100644 --- a/test/unittest/BUILD.gn +++ b/test/unittest/BUILD.gn @@ -48,6 +48,8 @@ ohos_source_set("appmgr_test_source") { "${ability_runtime_innerkits_path}/app_manager/src/appmgr/app_state_callback_proxy.cpp", "${ability_runtime_innerkits_path}/app_manager/src/appmgr/app_task_info.cpp", "${ability_runtime_innerkits_path}/app_manager/src/appmgr/fault_data.cpp", + "${ability_runtime_innerkits_path}/app_manager/src/appmgr/native_child_notify_proxy.cpp", + "${ability_runtime_innerkits_path}/app_manager/src/appmgr/native_child_notify_stub.cpp", "${ability_runtime_innerkits_path}/app_manager/src/appmgr/process_info.cpp", "${ability_runtime_innerkits_path}/app_manager/src/appmgr/profile.cpp", "${ability_runtime_innerkits_path}/app_manager/src/appmgr/render_scheduler_host.cpp", @@ -417,6 +419,7 @@ group("unittest") { "bundle_mgr_helper_test:unittest", "cache_process_manager_test:unittest", "call_record_test:unittest", + "child_process_capi_test:unittest", "child_process_manager_test:unittest", "completed_dispatcher_test:unittest", "configuration_test:unittest", diff --git a/test/unittest/app_mgr_service_test/app_mgr_service_test.cpp b/test/unittest/app_mgr_service_test/app_mgr_service_test.cpp index 30ecef7802..88061ed2d6 100644 --- a/test/unittest/app_mgr_service_test/app_mgr_service_test.cpp +++ b/test/unittest/app_mgr_service_test/app_mgr_service_test.cpp @@ -1731,5 +1731,31 @@ HWTEST_F(AppMgrServiceTest, SetSupportedProcessCacheSelf_002, TestSize.Level0) res = appMgrService->SetSupportedProcessCacheSelf(false); EXPECT_EQ(res, AAFwk::ERR_SET_SUPPORTED_PROCESS_CACHE_AGAIN); } + +/** + * @tc.name: StartNativeChildProcess_0100 + * @tc.desc: Start native child process. + * @tc.type: FUNC + */ +HWTEST_F(AppMgrServiceTest, StartNativeChildProcess_0100, TestSize.Level1) +{ + TAG_LOGD(AAFwkTag::TEST, "StartNativeChildProcess_0100 called."); + sptr appMgrService = new (std::nothrow) AppMgrService(); + ASSERT_NE(appMgrService, nullptr); + + appMgrService->SetInnerService(mockAppMgrServiceInner_); + appMgrService->taskHandler_ = taskHandler_; + appMgrService->eventHandler_ = eventHandler_; + + EXPECT_CALL(*mockAppMgrServiceInner_, StartNativeChildProcess(_, _, _, _)) + .Times(1) + .WillOnce(Return(ERR_OK)); + + pid_t pid = 0; + sptr callback; + int32_t res = appMgrService->StartNativeChildProcess("test.so", 1, callback); + EXPECT_EQ(res, ERR_OK); +} + } // namespace AppExecFwk } // namespace OHOS diff --git a/test/unittest/appkit/child_main_thread_test/child_main_thread_test.cpp b/test/unittest/appkit/child_main_thread_test/child_main_thread_test.cpp index fd8b9929d4..9bfcea64c4 100644 --- a/test/unittest/appkit/child_main_thread_test/child_main_thread_test.cpp +++ b/test/unittest/appkit/child_main_thread_test/child_main_thread_test.cpp @@ -170,5 +170,26 @@ HWTEST_F(ChildMainThreadTest, ScheduleExitProcessSafely_0100, TestSize.Level0) auto ret = thread->ScheduleExitProcessSafely(); EXPECT_TRUE(ret); } + +/** + * @tc.number: ScheduleRunNativeProc_0100 + * @tc.desc: Test ScheduleRunNativeProc works + * @tc.type: FUNC + */ +HWTEST_F(ChildMainThreadTest, ScheduleRunNativeProc_0100, TestSize.Level0) +{ + TAG_LOGD(AAFwkTag::TEST, "ScheduleRunNativeProc_0100 called."); + sptr thread = sptr(new (std::nothrow) ChildMainThread()); + ASSERT_NE(thread, nullptr); + + std::shared_ptr runner = EventRunner::GetMainEventRunner(); + std::shared_ptr handler = std::make_shared(runner); + thread->mainHandler_ = handler; + + sptr mainPorcessCb = nullptr; + auto ret = thread->ScheduleRunNativeProc(mainPorcessCb); + EXPECT_FALSE(ret); +} + } // namespace AppExecFwk } // namespace OHOS diff --git a/test/unittest/child_process_capi_test/BUILD.gn b/test/unittest/child_process_capi_test/BUILD.gn new file mode 100644 index 0000000000..ab3e96a9bd --- /dev/null +++ b/test/unittest/child_process_capi_test/BUILD.gn @@ -0,0 +1,52 @@ +# 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. + +import("//build/test.gni") +import("//foundation/ability/ability_runtime/ability_runtime.gni") + +module_output_path = "ability_runtime/child_process_capi" + +ohos_unittest("child_process_capi_test") { + module_out_path = module_output_path + + configs = [ "${ability_runtime_services_path}/common:common_config" ] + + if (target_cpu == "arm") { + cflags = [ "-DBINDER_IPC_32BIT" ] + } + + include_dirs = [ + "include", + "${ability_runtime_test_path}/mock/services_appmgr_test/include", + ] + + sources = [ "child_process_capi_test.cpp" ] + + deps = [ + "${ability_runtime_native_path}/child_process:child_process", + "${ability_runtime_services_path}/common:app_util", + "//third_party/googletest:gmock_main", + "//third_party/googletest:gtest_main", + ] + + external_deps = [ + "c_utils:utils", + "hilog:libhilog", + "ipc:ipc_capi", + ] +} + +group("unittest") { + testonly = true + deps = [ ":child_process_capi_test" ] +} diff --git a/test/unittest/child_process_capi_test/child_process_capi_test.cpp b/test/unittest/child_process_capi_test/child_process_capi_test.cpp new file mode 100644 index 0000000000..8ad66cbce4 --- /dev/null +++ b/test/unittest/child_process_capi_test/child_process_capi_test.cpp @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2023 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 +#include "native_child_process.h" +#include "app_utils.h" + +namespace OHOS { +namespace AbilityRuntime { + +using namespace testing; +using namespace testing::ext; + +class ChildProcessCapiTest : public testing::Test { +public: + static void SetUpTestCase(void); + static void TearDownTestCase(void); + + static void OnNativeChildProcessStarted(int errCode, OHIPCRemoteProxy *remoteProxy); + + void SetUp(); + void TearDown(); +}; + +void ChildProcessCapiTest::SetUpTestCase(void) +{} + +void ChildProcessCapiTest::TearDownTestCase(void) +{} + +void ChildProcessCapiTest::SetUp(void) +{} + +void ChildProcessCapiTest::TearDown(void) +{} + +void ChildProcessCapiTest::OnNativeChildProcessStarted(int errCode, OHIPCRemoteProxy *remoteProxy) +{ +} + +/** + * @tc.number: OH_Ability_CreateNativeChildProcess_001 + * @tc.desc: Test API OH_Ability_CreateNativeChildProcess works + * @tc.type: FUNC + */ +HWTEST_F(ChildProcessCapiTest, OH_Ability_CreateNativeChildProcess_001, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "OH_Ability_CreateNativeChildProcess_001 begin"; + int ret = OH_Ability_CreateNativeChildProcess(nullptr, ChildProcessCapiTest::OnNativeChildProcessStarted); + EXPECT_EQ(ret, NCP_ERR_INVALID_PARAM); + + ret = OH_Ability_CreateNativeChildProcess("test.so", nullptr); + EXPECT_EQ(ret, NCP_ERR_INVALID_PARAM); + + ret = OH_Ability_CreateNativeChildProcess("test.so", ChildProcessCapiTest::OnNativeChildProcessStarted); + if (!AAFwk::AppUtils::GetInstance().IsMultiProcessModel()) { + EXPECT_EQ(ret, NCP_ERR_MULTI_PROCESS_DISABLED); + return; + } else if (!AAFwk::AppUtils::GetInstance().IsSupportNativeChildProcess()) { + EXPECT_EQ(ret, NCP_ERR_NOT_SUPPORTED); + return; + } + + GTEST_LOG_(INFO) << "OH_Ability_CreateNativeChildProcess return " << ret; + EXPECT_NE(ret, NCP_ERR_NOT_SUPPORTED); +} + +} // namespace AbilityRuntime +} // namespace OHOS diff --git a/test/unittest/child_process_manager_test/child_process_manager_test.cpp b/test/unittest/child_process_manager_test/child_process_manager_test.cpp index 1eaf3f3076..da364c8298 100644 --- a/test/unittest/child_process_manager_test/child_process_manager_test.cpp +++ b/test/unittest/child_process_manager_test/child_process_manager_test.cpp @@ -45,6 +45,8 @@ void ChildProcessManagerTest::SetUpTestCase() { AAFwk::AppUtils::GetInstance().isMultiProcessModel_.isLoaded = true; AAFwk::AppUtils::GetInstance().isMultiProcessModel_.value = true; + AAFwk::AppUtils::GetInstance().isSupportNativeChildProcess_.isLoaded = true; + AAFwk::AppUtils::GetInstance().isSupportNativeChildProcess_.value = true; sptr bundleMgrService = sptr(new (std::nothrow) AppExecFwk::BundleMgrService()); sptr mockAppMgrService = sptr(new (std::nothrow) AppExecFwk::MockAppMgrService()); @@ -61,6 +63,8 @@ void ChildProcessManagerTest::TearDownTestCase() { AAFwk::AppUtils::GetInstance().isMultiProcessModel_.isLoaded = false; AAFwk::AppUtils::GetInstance().isMultiProcessModel_.value = false; + AAFwk::AppUtils::GetInstance().isSupportNativeChildProcess_.isLoaded = false; + AAFwk::AppUtils::GetInstance().isSupportNativeChildProcess_.value = false; } void ChildProcessManagerTest::SetUp() @@ -226,5 +230,19 @@ AbilityRuntime::Runtime::DebugOption debugOption; ChildProcessManager::GetInstance().SetForkProcessDebugOption("test", false, false, false); EXPECT_TRUE(true); } + +/** + * @tc.number: StartNativeChildProcessByAppSpawnFork_0100 + * @tc.desc: Test StartNativeChildProcessByAppSpawnFork works. + * @tc.type: FUNC + */ +HWTEST_F(ChildProcessManagerTest, StartNativeChildProcessByAppSpawnFork_0100, TestSize.Level0) +{ + TAG_LOGD(AAFwkTag::TEST, "StartNativeChildProcessByAppSpawnFork_0100 called."); + sptr callback; + auto ret = ChildProcessManager::GetInstance().StartNativeChildProcessByAppSpawnFork("test.so", callback); + EXPECT_NE(ret, ChildProcessManagerErrorCode::ERR_FORK_FAILED); +} + } // namespace AbilityRuntime } // namespace OHOS \ No newline at end of file