diff --git a/bundle.json b/bundle.json index 9dffe1375c3cbaf40c1609e97ccdf2429a6136e2..429d2f1f9ea4756f7a227a49aadead69d3e8b62a 100644 --- a/bundle.json +++ b/bundle.json @@ -353,6 +353,7 @@ "header_base": "//foundation/ability/ability_runtime/frameworks/ets/ani/ani_common/include", "header_files": [ "ani_common_ability_state_data.h", + "ani_common_child_process_param.h", "ani_common_start_options.h", "ani_common_want.h", "ets_native_reference.h" diff --git a/frameworks/ets/ani/BUILD.gn b/frameworks/ets/ani/BUILD.gn index 07051afaec8e5ccdd25d003cd2ed57805d429709..d7901ce93c69a7fe544120564e20be0e2f585276 100644 --- a/frameworks/ets/ani/BUILD.gn +++ b/frameworks/ets/ani/BUILD.gn @@ -34,6 +34,7 @@ group("ani_packages") { "${ability_runtime_path}/frameworks/ets/ani/auto_fill_manager:ability_auto_fill_manager_ani_kit", "${ability_runtime_path}/frameworks/ets/ani/business_ability_router:businessabilityrouter_ani", "${ability_runtime_path}/frameworks/ets/ani/caller_complex:caller_complex_ani", + "${ability_runtime_path}/frameworks/ets/ani/child_process_manager:ability_child_process_manager_ani_kit", "${ability_runtime_path}/frameworks/ets/ani/dialog_session:dialog_session_ani_kit", "${ability_runtime_path}/frameworks/ets/ani/featureAbility:featureability_ani", "${ability_runtime_path}/frameworks/ets/ani/insight_intent/insight_intent_driver:insight_intent_driver_ani_kit", diff --git a/frameworks/ets/ani/ani_common/BUILD.gn b/frameworks/ets/ani/ani_common/BUILD.gn index 4fa80817e6165cd9271d588f16e1fcd069a9ffd9..0fc3dccb38d6559c0c8911df4d8974f85c0f3d33 100644 --- a/frameworks/ets/ani/ani_common/BUILD.gn +++ b/frameworks/ets/ani/ani_common/BUILD.gn @@ -45,6 +45,7 @@ ohos_shared_library("ani_common") { "src/ani_common_ability_result.cpp", "src/ani_common_ability_state_data.cpp", "src/ani_common_cache_mgr.cpp", + "src/ani_common_child_process_param.cpp", "src/ani_common_configuration.cpp", "src/ani_common_execute_param.cpp", "src/ani_common_execute_result.cpp", diff --git a/frameworks/ets/ani/ani_common/include/ani_common_child_process_param.h b/frameworks/ets/ani/ani_common/include/ani_common_child_process_param.h new file mode 100644 index 0000000000000000000000000000000000000000..10b9ed80fd09eb27481837d4867f663b6785a4cc --- /dev/null +++ b/frameworks/ets/ani/ani_common/include/ani_common_child_process_param.h @@ -0,0 +1,33 @@ +/* + * 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 perns and + * limitations under the License. + */ + +#ifndef OHOS_ABILITY_RUNTIME_ANI_COMMON_CHILD_PROCESS_PARAM +#define OHOS_ABILITY_RUNTIME_ANI_COMMON_CHILD_PROCESS_PARAM + +#include "ani.h" +#include "child_process_args.h" +#include "child_process_options.h" + +namespace OHOS { +namespace AppExecFwk { +bool UnwrapChildProcessArgs(ani_env* env, ani_object object, ChildProcessArgs &args, + std::string &errorMsg); +bool UnwrapChildProcessFds(ani_env* env, ani_object object, std::map &map, std::string &errorMsg); +ani_object WrapChildProcessArgs(ani_env* env, ChildProcessArgs &args); +bool UnwrapChildProcessOptions(ani_env* env, ani_object object, ChildProcessOptions &options, + std::string &errorMsg); +} // namespace AppExecFwk +} // namespace OHOS +#endif // OHOS_ABILITY_RUNTIME_ANI_COMMON_CHILD_PROCESS_PARAM \ No newline at end of file diff --git a/frameworks/ets/ani/ani_common/include/ani_common_util.h b/frameworks/ets/ani/ani_common/include/ani_common_util.h index 482c2e18adf1f5dfef3a750101f240384a5403fc..d1e8b528d1afcc932610770658c9cad5408a9068 100644 --- a/frameworks/ets/ani/ani_common/include/ani_common_util.h +++ b/frameworks/ets/ani/ani_common/include/ani_common_util.h @@ -70,6 +70,7 @@ ani_object CreateEmptyArray(ani_env *env); bool IsExistsProperty(ani_env *env, ani_object param, const char *name); bool GetStringProperty(ani_env *env, ani_object param, const char *name, std::string &value); bool GetStringArrayProperty(ani_env *env, ani_object param, const char *name, std::vector &value); +bool GetStringOrUndefined(ani_env *env, ani_object param, const char *name, std::string &res); bool GetDoublePropertyObject(ani_env *env, ani_object param, const char *name, double &value); bool GetIntPropertyObject(ani_env *env, ani_object param, const char *name, ani_int &value); bool GetLongPropertyObject(ani_env *env, ani_object param, const char *name, ani_long &value); diff --git a/frameworks/ets/ani/ani_common/src/ani_common_child_process_param.cpp b/frameworks/ets/ani/ani_common/src/ani_common_child_process_param.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0f4fefc84b3795142ec303f297e9947b8b9e8698 --- /dev/null +++ b/frameworks/ets/ani/ani_common/src/ani_common_child_process_param.cpp @@ -0,0 +1,231 @@ +/* + * 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. + */ + +#include "ani_common_child_process_param.h" + +#include "ani_common_util.h" +#include "hilog_tag_wrapper.h" + +namespace OHOS { +namespace AppExecFwk { +namespace { +constexpr const char* CLASSNAME_CHILDPROCESSARGS = "L@ohos/app/ability/ChildProcessArgs/ChildProcessArgsImpl;"; +constexpr const char* RECORD_CLASS_NAME = "Lescompat/Record;"; +} + +void SetFds(ani_env* env, ani_object object, std::map &fds) +{ + if (env == nullptr) { + TAG_LOGE(AAFwkTag::PROCESSMGR, "null aniEnv"); + return; + } + ani_status status = ANI_ERROR; + ani_class recordCls = nullptr; + status = env->FindClass(RECORD_CLASS_NAME, &recordCls); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::PROCESSMGR, "FindClass failed status: %{public}d", status); + return; + } + ani_method recordGetMethod = nullptr; + status = env->Class_FindMethod(recordCls, "$_get", "Lstd/core/Object;:Lstd/core/Object;", &recordGetMethod); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::PROCESSMGR, "Class_FindMethod failed status: %{public}d", status); + return; + } + ani_method recordSetMethod = nullptr; + status = env->Class_FindMethod(recordCls, "$_set", "Lstd/core/Object;Lstd/core/Object;:V", &recordSetMethod); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::PROCESSMGR, "Class_FindMethod failed status: %{public}d", status); + return; + } + ani_ref fdsRef = nullptr; + status = env->Object_CallMethodByName_Ref(object, "fds", ":Lescompat/Record;", &fdsRef); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::PROCESSMGR, "Object_CallMethodByName_Ref failed status: %{public}d", status); + return; + } + ani_object fdsObject = static_cast(fdsRef); + for (auto iter = fds.begin(); iter != fds.end(); ++iter) { + std::string key = iter->first; + ani_string aniKey = GetAniString(env, key); + int32_t value = iter->second; + ani_double aniValue = ani_double(value); + status = env->Object_CallMethod_Void(fdsObject, recordSetMethod, aniKey, aniValue); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::PROCESSMGR, "Object_CallMethod_Void failed status: %{public}d", status); + return; + } + } +} + +void GetFds(ani_env* env, ani_string aniKey, ani_object aniValue, std::map &map) +{ + std::string mapKey = ""; + if (!GetStdString(env, aniKey, mapKey)) { + TAG_LOGE(AAFwkTag::PROCESSMGR, "GetStdString failed"); + return; + } + ani_double value; + ani_status status = env->Object_CallMethodByName_Double(aniValue, "unboxed", nullptr, &value); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::PROCESSMGR, "Object_CallMethodByName_Double failed status: %{public}d", status); + return; + } + auto mapValue = static_cast(value); + map.emplace(mapKey, mapValue); +} + +bool UnwrapChildProcessArgs(ani_env* env, ani_object object, ChildProcessArgs &args, + std::string &errorMsg) +{ + if (env == nullptr) { + TAG_LOGE(AAFwkTag::PROCESSMGR, "env null"); + return false; + } + if (!GetStringOrUndefined(env, object, "entryParams", args.entryParams)) { + TAG_LOGI(AAFwkTag::PROCESSMGR, "parameter error"); + errorMsg = "Parameter error. The type of args.entryParams must be string."; + return false; + } + ani_ref fdsRef; + if (GetRefProperty(env, object, "fds", fdsRef)) { + ani_object fdsObject = static_cast(fdsRef); + if (fdsObject == nullptr) { + TAG_LOGE(AAFwkTag::PROCESSMGR, "fds must be Record"); + errorMsg = "The type of args.fds must be Record."; + return false; + } + if (!UnwrapChildProcessFds(env, fdsObject, args.fds, errorMsg)) { + return false; + } + } + return true; +} + +bool UnwrapChildProcessFds(ani_env* env, ani_object object, std::map &map, std::string &errorMsg) +{ + if (env == nullptr) { + TAG_LOGE(AAFwkTag::PROCESSMGR, "env null"); + return false; + } + ani_ref iter; + ani_status status = ANI_ERROR; + status = env->Object_CallMethodByName_Ref(object, "$_iterator", nullptr, &iter); + if (ANI_OK != status) { + TAG_LOGE(AAFwkTag::PROCESSMGR, "Failed to get keys iterator status: %{public}d", status); + return false; + } + ani_ref next; + ani_boolean done; + while (ANI_OK == env->Object_CallMethodByName_Ref(static_cast(iter), "next", nullptr, &next)) { + status = env->Object_GetFieldByName_Boolean(static_cast(next), "done", &done); + if (ANI_OK != status) { + TAG_LOGE(AAFwkTag::PROCESSMGR, "Failed to check iterator done status: %{public}d", status); + return false; + } + if (done) { + TAG_LOGD(AAFwkTag::PROCESSMGR, "[forEachMapEntry] done break"); + return true; + } + ani_ref keyValue; + status = env->Object_GetFieldByName_Ref(static_cast(next), "value", &keyValue); + if (ANI_OK != status) { + TAG_LOGE(AAFwkTag::PROCESSMGR, "Failed to get key value status: %{public}d", status); + return false; + } + ani_ref aniKey; + status = env->TupleValue_GetItem_Ref(static_cast(keyValue), 0, &aniKey); + if (ANI_OK != status) { + TAG_LOGE(AAFwkTag::PROCESSMGR, "Failed to get key Item status: %{public}d", status); + return false; + } + ani_ref aniVal; + status = env->TupleValue_GetItem_Ref(static_cast(keyValue), 1, &aniVal); + if (ANI_OK != status) { + TAG_LOGE(AAFwkTag::PROCESSMGR, "Failed to get key Item status: %{public}d", status); + return false; + } + GetFds(env, static_cast(aniKey), static_cast(aniVal), map); + } + return true; +} + +ani_object WrapChildProcessArgs(ani_env* env, ChildProcessArgs &args) +{ + if (env == nullptr) { + TAG_LOGE(AAFwkTag::PROCESSMGR, "env null"); + return nullptr; + } + ani_status status = ANI_ERROR; + ani_class className = nullptr; + status = env->FindClass(CLASSNAME_CHILDPROCESSARGS, &className); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::PROCESSMGR, "FindClass failed status: %{public}d", status); + return nullptr; + } + ani_method method = nullptr; + status = env->Class_FindMethod(className, "", ":V", &method); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::PROCESSMGR, "find method failed status: %{public}d", status); + return nullptr; + } + ani_object object = nullptr; + status = env->Object_New(className, method, &object); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::PROCESSMGR, "new object failed status: %{public}d", status); + return nullptr; + } + status = env->Object_SetPropertyByName_Ref(object, "entryParams", GetAniString(env, args.entryParams)); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::PROCESSMGR, "set property failed status: %{public}d", status); + return nullptr; + } + SetFds(env, object, args.fds); + return object; +} + +bool UnwrapChildProcessOptions(ani_env* env, ani_object object, ChildProcessOptions &options, std::string &errorMsg) +{ + if (env == nullptr) { + TAG_LOGE(AAFwkTag::PROCESSMGR, "env null"); + return false; + } + ani_ref propRef = nullptr; + ani_status status = env->Object_GetPropertyByName_Ref(object, "isolationMode", &propRef); + if (status != ANI_OK || propRef == nullptr) { + options.isolationMode = false; + return true; + } + ani_boolean isUndefined = false; + status = env->Reference_IsUndefined(propRef, &isUndefined); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::PROCESSMGR, "Failed to check undefined for 'isolationMode', status: %{public}d", status); + return false; + } + if (isUndefined) { + options.isolationMode = false; + return true; + } + ani_boolean flag = false; + status = env->Object_CallMethodByName_Boolean(reinterpret_cast(propRef), "valueOf", ":Z", &flag); + if (status != ANI_OK) { + errorMsg = "Failed to get boolean value for isolationMode."; + return false; + } + options.isolationMode = flag; + return true; +} +} // namespace AppExecFwk +} // namespace OHOS \ No newline at end of file diff --git a/frameworks/ets/ani/child_process_manager/BUILD.gn b/frameworks/ets/ani/child_process_manager/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..9af1248a78604e608f2d81784c40f34dc1169eca --- /dev/null +++ b/frameworks/ets/ani/child_process_manager/BUILD.gn @@ -0,0 +1,71 @@ +# 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. + +import("//build/ohos.gni") +import("//foundation/ability/ability_runtime/ability_runtime.gni") + +ohos_shared_library("ability_child_process_manager_ani_kit") { + branch_protector_ret = "pac_ret" + sanitize = { + cfi = true + cfi_cross_dso = true + cfi_vcall_icall_only = true + debug = false + } + + include_dirs = [ + "./include", + "${ability_runtime_path}/frameworks/ets/ani/enum_convert", + ] + + configs = [] + + public_configs = [] + + sources = [] + + cflags = [] + if (target_cpu == "arm") { + cflags += [ "-DBINDER_IPC_32BIT" ] + } + + deps = [ + "${ability_runtime_innerkits_path}/app_manager:app_manager", + "${ability_runtime_innerkits_path}/runtime:runtime", + "${ability_runtime_native_path}/ability/native:abilitykit_native", + "${ability_runtime_path}/frameworks/ets/ani/ani_common:ani_common", + "${ability_runtime_innerkits_path}/child_process_manager:child_process_manager", + ] + + external_deps = [ + "ability_base:base", + "bundle_framework:libappexecfwk_common", + "c_utils:utils", + "hilog:libhilog", + "ipc:ipc_capi", + "runtime_core:ani", + ] + + if (ability_runtime_child_process) { + sources += [ "./src/ets_child_process_manager.cpp" ] + deps += [ "${ability_runtime_innerkits_path}/child_process_manager:child_process_manager" ] + } + + if (ability_runtime_graphics) { + external_deps += [ "image_framework:image" ] + } + + innerapi_tags = [ "platformsdk" ] + subsystem_name = "ability" + part_name = "ability_runtime" +} \ No newline at end of file diff --git a/frameworks/ets/ani/child_process_manager/include/ets_child_process_manager.h b/frameworks/ets/ani/child_process_manager/include/ets_child_process_manager.h new file mode 100644 index 0000000000000000000000000000000000000000..1f0fa1dc995b34b8f546daf0566e2b26c46bd0d0 --- /dev/null +++ b/frameworks/ets/ani/child_process_manager/include/ets_child_process_manager.h @@ -0,0 +1,26 @@ +/* + * 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_CHILD_PROCESS_MANAGER_H +#define OHOS_ABILITY_RUNTIME_ETS_CHILD_PROCESS_MANAGER_H + +#include "ets_runtime.h" + +namespace OHOS { +namespace ChildProcessManagerEts { +void EtsChildProcessManagerInit(ani_env *env); +} // namespace ChildProcessManagerEts +} // namespace OHOS +#endif // OHOS_ABILITY_RUNTIME_ETS_CHILD_PROCESS_MANAGER_H \ No newline at end of file diff --git a/frameworks/ets/ani/child_process_manager/src/ets_child_process_manager.cpp b/frameworks/ets/ani/child_process_manager/src/ets_child_process_manager.cpp new file mode 100644 index 0000000000000000000000000000000000000000..96d764b9f3fa890245872c361bc985dd235b8a5c --- /dev/null +++ b/frameworks/ets/ani/child_process_manager/src/ets_child_process_manager.cpp @@ -0,0 +1,359 @@ +/* + * 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. + */ + +#include "ets_child_process_manager.h" + +#include "ani_common_child_process_param.h" +#include "ani_common_util.h" +#include "ani_enum_convert.h" +#include "child_process_manager.h" +#include "hilog_tag_wrapper.h" +#include "ets_error_utils.h" + +namespace OHOS { +namespace ChildProcessManagerEts { +namespace { +constexpr const char* CHILD_PROCESS_MANAGER_NAME_SPACE = "L@ohos/app/ability/childProcessManager/childProcessManager;"; +enum { + MODE_SELF_FORK = 0, + MODE_APP_SPAWN_FORK = 1, +}; +struct ChildProcessAniParam { + std::string srcEntry; + AppExecFwk::ChildProcessArgs args; + AppExecFwk::ChildProcessOptions options; + int32_t childProcessType; +}; +} + +class EtsChildProcessManager { +public: + EtsChildProcessManager() = default; + ~EtsChildProcessManager() = default; + + static EtsChildProcessManager &GetInstance() + { + static EtsChildProcessManager instance; + return instance; + } + + static void StartChildProcess(ani_env *env, ani_string etsSrcEntry, ani_enum_item etsStartMode, + ani_object callback) + { + GetInstance().OnStartChildProcess(env, etsSrcEntry, etsStartMode, callback); + } + + static void StartArkChildProcess(ani_env *env, ani_string etsSrcEntry, ani_object ChildProcessArgs, + ani_object ChildProcessOptions, ani_object callback) + { + GetInstance().OnStartArkChildProcess(env, etsSrcEntry, ChildProcessArgs, ChildProcessOptions, callback); + } + + static void StartNativeChildProcess(ani_env *env, ani_string etsSrcEntry, ani_object ChildProcessArgs, + ani_object ChildProcessOptions, ani_object callback) + { + GetInstance().OnStartNativeChildProcess(env, etsSrcEntry, ChildProcessArgs, ChildProcessOptions, callback); + } + +private: + void OnStartChildProcess(ani_env *env, ani_string etsSrcEntry, ani_enum_item etsStartMode, ani_object callback) + { + TAG_LOGD(AAFwkTag::PROCESSMGR, "called"); + if (env == nullptr) { + TAG_LOGE(AAFwkTag::PROCESSMGR, "env is null"); + return; + } + if (AbilityRuntime::ChildProcessManager::GetInstance().IsChildProcess()) { + TAG_LOGE(AAFwkTag::PROCESSMGR, "Already in child process"); + AbilityRuntime::EtsErrorUtil::ThrowError(env, + AbilityRuntime::AbilityErrorCode::ERROR_CODE_OPERATION_NOT_SUPPORTED); + return; + } + std::string srcEntry; + if (!AppExecFwk::GetStdString(env, etsSrcEntry, srcEntry)) { + TAG_LOGE(AAFwkTag::PROCESSMGR, "Parse srcEntry failed"); + AbilityRuntime::EtsErrorUtil::ThrowInvalidParamError(env, + "Parse param srcEntry failed, must be a valid string."); + return; + } + TAG_LOGD(AAFwkTag::PROCESSMGR, "srcEntry %{public}s", srcEntry.c_str()); + ani_int startMode; + if (!AAFwk::AniEnumConvertUtil::EnumConvert_EtsToNative(env, etsStartMode, startMode)) { + TAG_LOGE(AAFwkTag::PROCESSMGR, "Parse startMode failed"); + AbilityRuntime::EtsErrorUtil::ThrowInvalidParamError(env, + "Unsupported startMode, must be StartMode.SELF_FORK or StartMode.APP_SPAWN_FORK."); + return; + } + TAG_LOGD(AAFwkTag::PROCESSMGR, "startMode %{public}d", startMode); + if (startMode != MODE_SELF_FORK && startMode != MODE_APP_SPAWN_FORK) { + TAG_LOGE(AAFwkTag::PROCESSMGR, "Invalid StartMode"); + AbilityRuntime::EtsErrorUtil::ThrowInvalidParamError(env, + "Unsupported startMode, must be StartMode.SELF_FORK or StartMode.APP_SPAWN_FORK."); + return; + } + if (startMode == MODE_SELF_FORK) { + StartChildProcessSelfForkTask(env, srcEntry, callback); + } else { + StartChildProcessAppSpawnForkTask(env, srcEntry, callback); + } + } + + static void StartChildProcessSelfForkTask(ani_env *env, std::string &etsSrcEntry, ani_object callback) + { + pid_t pid = 0; + AbilityRuntime::ChildProcessManagerErrorCode errorCode = + AbilityRuntime::ChildProcessManager::GetInstance().StartChildProcessBySelfFork(etsSrcEntry, pid); + TAG_LOGD(AAFwkTag::PROCESSMGR, "StartChildProcessBySelfFork errorCode: %{public}d, pid: %{public}d", + errorCode, pid); + if (errorCode != AbilityRuntime::ChildProcessManagerErrorCode::ERR_OK) { + TAG_LOGE(AAFwkTag::PROCESSMGR, "StartChildProcessBySelfFork failed, errorCode is %{public}d", errorCode); + AppExecFwk::AsyncCallback(env, callback, AbilityRuntime::EtsErrorUtil::CreateError(env, + AbilityRuntime::ChildProcessManagerErrorUtil::GetAbilityErrorCode(errorCode)), nullptr); + return; + } + AppExecFwk::AsyncCallback(env, callback, AbilityRuntime::EtsErrorUtil::CreateError(env, + AbilityRuntime::ChildProcessManagerErrorUtil::GetAbilityErrorCode(errorCode)), + AppExecFwk::CreateDouble(env, static_cast(pid))); + } + + static void StartChildProcessAppSpawnForkTask(ani_env *env, std::string &etsSrcEntry, ani_object callback) + { + auto innerErrorCode = std::make_shared( + AbilityRuntime::ChildProcessManagerErrorCode::ERR_OK); + auto pid = std::make_shared(ERR_INVALID_VALUE); + if (!pid || !innerErrorCode) { + TAG_LOGE(AAFwkTag::PROCESSMGR, "null innerErrorCode or pid"); + return; + } + *innerErrorCode = + AbilityRuntime::ChildProcessManager::GetInstance().StartChildProcessByAppSpawnFork(etsSrcEntry, *pid); + TAG_LOGD(AAFwkTag::PROCESSMGR, "StartChildProcessByAppSpawnFork errorCode: %{public}d, pid: %{public}d", + *innerErrorCode, *pid); + if (!pid || !innerErrorCode) { + TAG_LOGE(AAFwkTag::PROCESSMGR, "null innerErrorCode or pid"); + AppExecFwk::AsyncCallback(env, callback, AbilityRuntime::EtsErrorUtil::CreateError(env, + AbilityRuntime::AbilityErrorCode::ERROR_CODE_INNER), nullptr); + return; + } + if (*innerErrorCode != AbilityRuntime::ChildProcessManagerErrorCode::ERR_OK) { + TAG_LOGE(AAFwkTag::PROCESSMGR, "StartChildProcessByAppSpawnFork failed, errorCode is %{public}d", + *innerErrorCode); + AppExecFwk::AsyncCallback(env, callback, AbilityRuntime::EtsErrorUtil::CreateError(env, + AbilityRuntime::ChildProcessManagerErrorUtil::GetAbilityErrorCode(*innerErrorCode)), nullptr); + return; + } + AppExecFwk::AsyncCallback(env, callback, AbilityRuntime::EtsErrorUtil::CreateError(env, + AbilityRuntime::ChildProcessManagerErrorUtil::GetAbilityErrorCode(*innerErrorCode)), + AppExecFwk::CreateDouble(env, static_cast(*pid))); + } + + void OnStartArkChildProcess(ani_env *env, ani_string etsSrcEntry, ani_object ChildProcessArgs, + ani_object ChildProcessOptions, ani_object callback) + { + TAG_LOGD(AAFwkTag::PROCESSMGR, "OnStartArkChildProcess Call"); + if (env == nullptr) { + TAG_LOGE(AAFwkTag::PROCESSMGR, "env is null"); + return; + } + if (AbilityRuntime::ChildProcessManager::GetInstance().IsChildProcessBySelfFork()) { + TAG_LOGE(AAFwkTag::PROCESSMGR, "Already in child process"); + AbilityRuntime::EtsErrorUtil::ThrowError(env, + AbilityRuntime::AbilityErrorCode::ERROR_CODE_OPERATION_NOT_SUPPORTED); + return; + } + std::string srcEntry; + if (!AppExecFwk::GetStdString(env, etsSrcEntry, srcEntry)) { + TAG_LOGE(AAFwkTag::PROCESSMGR, "Parse srcEntry failed"); + AbilityRuntime::EtsErrorUtil::ThrowInvalidParamError(env, + "Parse param srcEntry failed, must be a valid string."); + return; + } + if (srcEntry.empty()) { + TAG_LOGE(AAFwkTag::PROCESSMGR, "param srcEntry cannot be empty"); + AbilityRuntime::EtsErrorUtil::ThrowInvalidParamError(env, + "Param srcEntry cannot be empty."); + return; + } + TAG_LOGD(AAFwkTag::PROCESSMGR, "srcEntry: %{public}s", srcEntry.c_str()); + AppExecFwk::ChildProcessArgs args; + AppExecFwk::ChildProcessOptions options; + if (!ParseArgsAndOptions(env, ChildProcessArgs, ChildProcessOptions, args, options)) { + return; + } + ChildProcessAniParam param; + param.srcEntry = srcEntry; + param.args = args; + param.options = options; + param.childProcessType = AppExecFwk::CHILD_PROCESS_TYPE_ARK; + StartChildProcessWithArgsTask(env, param, callback); + } + + void OnStartNativeChildProcess(ani_env *env, ani_string etsEntryPoint, ani_object ChildProcessArgs, + ani_object ChildProcessOptions, ani_object callback) + { + TAG_LOGD(AAFwkTag::PROCESSMGR, "OnStartNativeChildProcess Call"); + if (env == nullptr) { + TAG_LOGE(AAFwkTag::PROCESSMGR, "env is null"); + return; + } + if (AbilityRuntime::ChildProcessManager::GetInstance().IsChildProcessBySelfFork()) { + TAG_LOGE(AAFwkTag::PROCESSMGR, "Already in child process"); + AbilityRuntime::EtsErrorUtil::ThrowError(env, + AbilityRuntime::AbilityErrorCode::ERROR_CODE_OPERATION_NOT_SUPPORTED); + return; + } + std::string entryPoint; + if (!AppExecFwk::GetStdString(env, etsEntryPoint, entryPoint)) { + TAG_LOGE(AAFwkTag::PROCESSMGR, "Parse param entryPoint failed"); + AbilityRuntime::EtsErrorUtil::ThrowInvalidParamError(env, + "Parse param entryPoint failed, must be a valid string."); + return; + } + if (entryPoint.empty()) { + TAG_LOGE(AAFwkTag::PROCESSMGR, "Param entryPoint cannot be empty"); + AbilityRuntime::EtsErrorUtil::ThrowInvalidParamError(env, + "Param entryPoint cannot be empty."); + return; + } + if (entryPoint.find(":") == std::string::npos) { + TAG_LOGE(AAFwkTag::PROCESSMGR, + "Param entryPoint must contain a colon to separate library name and entry function."); + AbilityRuntime::EtsErrorUtil::ThrowInvalidParamError(env, + "Param entryPoint must contain a colon to separate library name and entry function."); + return; + } + AppExecFwk::ChildProcessArgs args; + AppExecFwk::ChildProcessOptions options; + if (!ParseArgsAndOptions(env, ChildProcessArgs, ChildProcessOptions, args, options)) { + return; + } + ChildProcessAniParam param; + param.srcEntry = entryPoint; + param.args = args; + param.options = options; + param.childProcessType = AppExecFwk::CHILD_PROCESS_TYPE_NATIVE_ARGS; + StartChildProcessWithArgsTask(env, param, callback); + } + + static bool ParseArgsAndOptions(ani_env *env, ani_object ChildProcessArgs, ani_object ChildProcessOptions, + AppExecFwk::ChildProcessArgs &args, AppExecFwk::ChildProcessOptions &options) + { + if (env == nullptr) { + TAG_LOGE(AAFwkTag::PROCESSMGR, "env is null"); + return false; + } + std::string errorMsg; + if (!AppExecFwk::UnwrapChildProcessArgs(env, ChildProcessArgs, args, errorMsg)) { + TAG_LOGE(AAFwkTag::PROCESSMGR, "parse param args failed: %{private}s", errorMsg.c_str()); + AbilityRuntime::EtsErrorUtil::ThrowInvalidParamError(env, errorMsg); + return false; + } + if (!AppExecFwk::UnwrapChildProcessOptions(env, ChildProcessOptions, options, errorMsg)) { + TAG_LOGE(AAFwkTag::PROCESSMGR, "parse param options failed: %{private}s", errorMsg.c_str()); + AbilityRuntime::EtsErrorUtil::ThrowInvalidParamError(env, errorMsg); + return false; + } + return true; + } + + static void StartChildProcessWithArgsTask(ani_env *env, const ChildProcessAniParam ¶m, ani_object callback) + { + pid_t pid = -1; + TAG_LOGD(AAFwkTag::PROCESSMGR, + "StartChildProcessWithArgs, childProcessType:%{public}d, srcEntry:%{private}s, " + "args.entryParams size:%{public}zu, args.fds size:%{public}zu, options.isolationMode:%{public}d", + param.childProcessType, param.srcEntry.c_str(), param.args.entryParams.length(), + param.args.fds.size(), param.options.isolationMode); + AbilityRuntime::ChildProcessManagerErrorCode errorCode = + AbilityRuntime::ChildProcessManager::GetInstance().StartChildProcessWithArgs( + param.srcEntry, pid, param.childProcessType, param.args, param.options); + if (errorCode != AbilityRuntime::ChildProcessManagerErrorCode::ERR_OK) { + TAG_LOGE(AAFwkTag::PROCESSMGR, "StartChildProcessWithArgs failed, errorCode: %{public}d", errorCode); + AppExecFwk::AsyncCallback(env, callback, + AbilityRuntime::EtsErrorUtil::CreateErrorByNativeErr(env, static_cast(errorCode)), nullptr); + return; + } + AppExecFwk::AsyncCallback(env, callback, AbilityRuntime::EtsErrorUtil::CreateError(env, + AbilityRuntime::AbilityErrorCode::ERROR_OK), AppExecFwk::CreateDouble(env, static_cast(pid))); + } +}; + +void EtsChildProcessManagerInit(ani_env *env) +{ + TAG_LOGD(AAFwkTag::PROCESSMGR, "EtsChildProcessManagerInit call"); + if (env == nullptr) { + TAG_LOGE(AAFwkTag::PROCESSMGR, "null env"); + return; + } + if (env->ResetError() != ANI_OK) { + TAG_LOGE(AAFwkTag::PROCESSMGR, "ResetError failed"); + } + ani_status status = ANI_ERROR; + ani_namespace ns; + status = env->FindNamespace(CHILD_PROCESS_MANAGER_NAME_SPACE, &ns); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::PROCESSMGR, "FindNamespace childProcessManager failed status : %{public}d", status); + return; + } + std::array kitFunctions = { + ani_native_function {"nativeStartChildProcess", + "Lstd/core/String;L@ohos/app/ability/childProcessManager/childProcessManager/StartMode;" + "Lutils/AbilityUtils/AsyncCallbackWrapper;:V", + reinterpret_cast(EtsChildProcessManager::StartChildProcess)}, + ani_native_function {"nativeStartArkChildProcess", + "Lstd/core/String;L@ohos/app/ability/ChildProcessArgs/ChildProcessArgs;" + "L@ohos/app/ability/ChildProcessOptions/ChildProcessOptions;" + "Lutils/AbilityUtils/AsyncCallbackWrapper;:V", + reinterpret_cast(EtsChildProcessManager::StartArkChildProcess)}, + ani_native_function {"nativeStartNativeChildProcess", + "Lstd/core/String;L@ohos/app/ability/ChildProcessArgs/ChildProcessArgs;" + "L@ohos/app/ability/ChildProcessOptions/ChildProcessOptions;" + "Lutils/AbilityUtils/AsyncCallbackWrapper;:V", + reinterpret_cast(EtsChildProcessManager::StartNativeChildProcess)} + }; + status = env->Namespace_BindNativeFunctions(ns, kitFunctions.data(), kitFunctions.size()); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::PROCESSMGR, "Namespace_BindNativeFunctions failed status : %{public}d", status); + } + if (env->ResetError() != ANI_OK) { + TAG_LOGE(AAFwkTag::PROCESSMGR, "ResetError failed"); + } + TAG_LOGD(AAFwkTag::PROCESSMGR, "EtsChildProcessManagerInit end"); +} + +extern "C" { +ANI_EXPORT ani_status ANI_Constructor(ani_vm *vm, uint32_t *result) +{ + TAG_LOGD(AAFwkTag::PROCESSMGR, "in ChildProcessManagerEts.ANI_Constructor"); + if (vm == nullptr || result == nullptr) { + TAG_LOGE(AAFwkTag::PROCESSMGR, "null vm or result"); + return ANI_INVALID_ARGS; + } + + ani_env *env = nullptr; + ani_status status = ANI_ERROR; + status = vm->GetEnv(ANI_VERSION_1, &env); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::PROCESSMGR, "GetEnv failed, status=%{public}d", status); + return ANI_NOT_FOUND; + } + EtsChildProcessManagerInit(env); + *result = ANI_VERSION_1; + TAG_LOGD(AAFwkTag::PROCESSMGR, "ChildProcessManagerEts.ANI_Constructor finished"); + return ANI_OK; +} +} +} // namespace ChildProcessManagerEts +} // namespace OHOS \ No newline at end of file diff --git a/frameworks/ets/ets/@ohos.app.ability.ChildProcess.ets b/frameworks/ets/ets/@ohos.app.ability.ChildProcess.ets new file mode 100644 index 0000000000000000000000000000000000000000..87b5779eb301f2aad1973dede3e6faf869afcadc --- /dev/null +++ b/frameworks/ets/ets/@ohos.app.ability.ChildProcess.ets @@ -0,0 +1,20 @@ +/* + * 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. + */ + +import { ChildProcessArgs } from './@ohos.app.ability.ChildProcessArgs'; + +export default class ChildProcess { + onStart(args?: ChildProcessArgs): void {}; +} \ No newline at end of file diff --git a/frameworks/ets/ets/@ohos.app.ability.ChildProcessArgs.ets b/frameworks/ets/ets/@ohos.app.ability.ChildProcessArgs.ets new file mode 100644 index 0000000000000000000000000000000000000000..c127a4f025e682099fd63ffe828d9bdac577ef4c --- /dev/null +++ b/frameworks/ets/ets/@ohos.app.ability.ChildProcessArgs.ets @@ -0,0 +1,24 @@ +/* + * 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. + */ + +export interface ChildProcessArgs { + entryParams?: string; + fds?: Record; +} + +class ChildProcessArgsImpl implements ChildProcessArgs { + public entryParams?: string; + public fds?: Record; +} \ No newline at end of file diff --git a/frameworks/ets/ets/@ohos.app.ability.ChildProcessOptions.ets b/frameworks/ets/ets/@ohos.app.ability.ChildProcessOptions.ets new file mode 100644 index 0000000000000000000000000000000000000000..1d2c40d26fb1c83d3e7582a59b28d48ab69868e8 --- /dev/null +++ b/frameworks/ets/ets/@ohos.app.ability.ChildProcessOptions.ets @@ -0,0 +1,22 @@ +/* + * 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. + */ + +export interface ChildProcessOptions { + isolationMode?: boolean; +} + +class ChildProcessOptionsImpl implements ChildProcessOptions { + public isolationMode?: boolean; +} \ No newline at end of file diff --git a/frameworks/ets/ets/@ohos.app.ability.childProcessManager.ets b/frameworks/ets/ets/@ohos.app.ability.childProcessManager.ets new file mode 100644 index 0000000000000000000000000000000000000000..c7ede95c09e4ef06d52f7f258d6eb714cba63d60 --- /dev/null +++ b/frameworks/ets/ets/@ohos.app.ability.childProcessManager.ets @@ -0,0 +1,99 @@ +/* + * 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. + */ + +import { BusinessError, AsyncCallback } from '@ohos.base'; +import AsyncCallbackWrapper from './utils/AbilityUtils'; +import { ChildProcessArgs } from './@ohos.app.ability.ChildProcessArgs'; +import { ChildProcessOptions } from './@ohos.app.ability.ChildProcessOptions'; + +namespace childProcessManager { + loadLibrary("ability_child_process_manager_ani_kit.z") + + export const enum StartMode { + SELF_FORK = 0, + APP_SPAWN_FORK = 1, + } + + export native function nativeStartChildProcess(srcEntry: string, startMode: StartMode, + callback: AsyncCallbackWrapper): void; + export native function nativeStartArkChildProcess(srcEntry: string, args: ChildProcessArgs, + options: ChildProcessOptions, callback: AsyncCallbackWrapper): void; + export native function nativeStartNativeChildProcess(entryPoint: string, args: ChildProcessArgs, + options: ChildProcessOptions, callback: AsyncCallbackWrapper): void; + + export function startChildProcess(srcEntry: string, startMode: StartMode): Promise { + let p = new Promise((resolve: (data: int) => void, reject: (err: BusinessError) => void): void => { + let myCall = new AsyncCallbackWrapper((err: BusinessError | null, data: int | undefined) => { + if (err == null || err.code == 0) { + resolve(data as int); + } else { + reject(err); + } + }); + taskpool.execute((): void => { + childProcessManager.nativeStartChildProcess(srcEntry, startMode, myCall); + }).catch((err: Error): void => { + reject(err as BusinessError); + }); + }); + return p; + } + export function startChildProcess(srcEntry: string, startMode: StartMode, callback: AsyncCallback): void { + let myCall = new AsyncCallbackWrapper(callback); + taskpool.execute((): void => { + childProcessManager.nativeStartChildProcess(srcEntry, startMode, myCall); + }); + } + + export function startArkChildProcess(srcEntry: string, args: ChildProcessArgs, + options: ChildProcessOptions): Promise { + let p = new Promise((resolve: (data: int) => void, reject: (err: BusinessError) => void): void => { + let myCall = new AsyncCallbackWrapper((err: BusinessError | null, data: int | undefined) => { + if (err == null || err.code == 0) { + resolve(data as int); + } else { + reject(err); + } + }); + taskpool.execute((): void => { + childProcessManager.nativeStartArkChildProcess(srcEntry, args, options, myCall); + }).catch((err: Error): void => { + reject(err as BusinessError); + }); + }); + return p; + } + + export function startNativeChildProcess(entryPoint: string, args: ChildProcessArgs, + options: ChildProcessOptions): Promise { + let p = new Promise((resolve: (data: int) => void, reject: (err: BusinessError) => void): void => { + let myCall = new AsyncCallbackWrapper((err: BusinessError | null, data: int | undefined) => { + if (err == null || err.code == 0) { + resolve(data as int); + } else { + reject(err); + } + }); + taskpool.execute((): void => { + childProcessManager.nativeStartNativeChildProcess(entryPoint, args, options, myCall); + }).catch((err: Error): void => { + reject(err as BusinessError); + }); + }); + return p; + } +} + +export default childProcessManager; \ No newline at end of file diff --git a/frameworks/ets/ets/BUILD.gn b/frameworks/ets/ets/BUILD.gn index e446b37c357a7870369507c4cc0f1174c6f0f66c..d33e714e6dbfeb3dab30501c91d6f7c051e411bf 100644 --- a/frameworks/ets/ets/BUILD.gn +++ b/frameworks/ets/ets/BUILD.gn @@ -197,6 +197,70 @@ ohos_prebuilt_etc("ability_runtime_extension_context_abc_etc") { deps = [ ":ability_runtime_extension_context_abc" ] } +generate_static_abc("ability_runtime_child_process_abc") { + base_url = "./" + files = [ "./@ohos.app.ability.ChildProcess.ets" ] + + is_boot_abc = "True" + device_dst_file = "/system/framework/ability_runtime_child_process_abc.abc" +} + +ohos_prebuilt_etc("ability_runtime_child_process_abc_etc") { + source = "$target_out_dir/ability_runtime_child_process_abc.abc" + module_install_dir = "framework" + subsystem_name = "ability" + part_name = "ability_runtime" + deps = [ ":ability_runtime_child_process_abc" ] +} + +generate_static_abc("ability_runtime_child_process_args_abc") { + base_url = "./" + files = [ "./@ohos.app.ability.ChildProcessArgs.ets" ] + + is_boot_abc = "True" + device_dst_file = "/system/framework/ability_runtime_child_process_args_abc.abc" +} + +ohos_prebuilt_etc("ability_runtime_child_process_args_abc_etc") { + source = "$target_out_dir/ability_runtime_child_process_args_abc.abc" + module_install_dir = "framework" + subsystem_name = "ability" + part_name = "ability_runtime" + deps = [ ":ability_runtime_child_process_args_abc" ] +} + +generate_static_abc("ability_runtime_child_process_manager_abc") { + base_url = "./" + files = [ "./@ohos.app.ability.childProcessManager.ets" ] + + is_boot_abc = "True" + device_dst_file = "/system/framework/ability_runtime_child_process_manager_abc.abc" +} + +ohos_prebuilt_etc("ability_runtime_child_process_manager_abc_etc") { + source = "$target_out_dir/ability_runtime_child_process_manager_abc.abc" + module_install_dir = "framework" + subsystem_name = "ability" + part_name = "ability_runtime" + deps = [ ":ability_runtime_child_process_manager_abc" ] +} + +generate_static_abc("ability_runtime_child_process_options_abc") { + base_url = "./" + files = [ "./@ohos.app.ability.ChildProcessOptions.ets" ] + + is_boot_abc = "True" + device_dst_file = "/system/framework/ability_runtime_child_process_options_abc.abc" +} + +ohos_prebuilt_etc("ability_runtime_child_process_options_abc_etc") { + source = "$target_out_dir/ability_runtime_child_process_options_abc.abc" + module_install_dir = "framework" + subsystem_name = "ability" + part_name = "ability_runtime" + deps = [ ":ability_runtime_child_process_options_abc" ] +} + generate_static_abc("ability_runtime_configuration_abc") { base_url = "./" files = [ "./@ohos.app.ability.Configuration.ets" ] @@ -1601,6 +1665,10 @@ group("ets_packages") { ":ability_runtime_application_state_change_callback_abc_etc", ":ability_runtime_base_context_abc_etc", ":ability_runtime_caller_callee_abc_etc", + ":ability_runtime_child_process_abc_etc", + ":ability_runtime_child_process_args_abc_etc", + ":ability_runtime_child_process_manager_abc_etc", + ":ability_runtime_child_process_options_abc_etc", ":ability_runtime_completion_handler_abc_etc", ":ability_runtime_configuration_abc_etc", ":ability_runtime_configuration_constant_abc_etc", diff --git a/frameworks/native/ability/native/child_process_manager/child_process.cpp b/frameworks/native/ability/native/child_process_manager/child_process.cpp index b2c87b8c0bf20cd04a52525dd4f6cf65c5be6b9a..955388731338477682d84d56f6f813e54358068a 100644 --- a/frameworks/native/ability/native/child_process_manager/child_process.cpp +++ b/frameworks/native/ability/native/child_process_manager/child_process.cpp @@ -16,6 +16,7 @@ #include "child_process.h" #include "js_child_process.h" +#include "ets_child_process.h" namespace OHOS { namespace AbilityRuntime { @@ -27,6 +28,8 @@ std::shared_ptr ChildProcess::Create(const std::unique_ptrGetLanguage()) { case AbilityRuntime::Runtime::Language::JS: return AbilityRuntime::JsChildProcess::Create(runtime); + case AbilityRuntime::Runtime::Language::ETS: + return AbilityRuntime::EtsChildProcess::Create(runtime); default: return std::make_shared(); } 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 b2d0d72271145201ed75af4b8a4cea2a878e8ea1..757830c615eedbc08bdd7859baa40cc8933ef3f9 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 @@ -404,6 +404,11 @@ std::unique_ptr ChildProcessManager::CreateRuntime(cons fromAppSpawn ? AppExecFwk::EventRunner::GetMainEventRunner() : AppExecFwk::EventRunner::Create(); options.eventRunner = eventRunner; + if (hapModuleInfo.moduleArkTSMode == AbilityRuntime::CODE_LANGUAGE_ARKTS_HYBRID || + hapModuleInfo.moduleArkTSMode == AbilityRuntime::CODE_LANGUAGE_ARKTS_1_2) { + options.lang = Runtime::Language::ETS; + } + return AbilityRuntime::Runtime::Create(options); } diff --git a/frameworks/native/ability/native/child_process_manager/ets_child_process.cpp b/frameworks/native/ability/native/child_process_manager/ets_child_process.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4392d3c220a6daf3a1008a7bf57db53fcd413017 --- /dev/null +++ b/frameworks/native/ability/native/child_process_manager/ets_child_process.cpp @@ -0,0 +1,121 @@ +/* + * 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. + */ + +#include "ets_child_process.h" + +#include "ani_common_child_process_param.h" +#include "ets_native_reference.h" +#include "hilog_tag_wrapper.h" + +namespace OHOS { +namespace AbilityRuntime { +std::shared_ptr EtsChildProcess::Create(const std::unique_ptr& runtime) +{ + return std::make_shared(static_cast(*runtime)); +} + +EtsChildProcess::EtsChildProcess(ETSRuntime &etsRuntime) : etsRuntime_(etsRuntime) {} + +EtsChildProcess::~EtsChildProcess() {} + +bool EtsChildProcess::Init(const std::shared_ptr &info) +{ + TAG_LOGI(AAFwkTag::PROCESSMGR, "EtsChildProcess::Init Call"); + if (info == nullptr) { + TAG_LOGE(AAFwkTag::PROCESSMGR, "null info"); + return false; + } + bool ret = ChildProcess::Init(info); + if (!ret) { + TAG_LOGE(AAFwkTag::PROCESSMGR, "ChildProcess init failed"); + return false; + } + if (info->srcEntry.empty()) { + TAG_LOGE(AAFwkTag::PROCESSMGR, "Empty info srcEntry"); + return false; + } + std::string srcPath = info->srcEntry; + if (srcPath.rfind(".") != std::string::npos) { + srcPath.erase(srcPath.rfind(".")); + } + srcPath.append(".abc"); + std::string moduleName(info->moduleName); + moduleName.append("::").append(info->name); + + etsChildProcessObj_ = etsRuntime_.LoadModule(moduleName, srcPath, info->hapPath, info->isEsModule, false, ""); + if (etsChildProcessObj_ == nullptr) { + TAG_LOGE(AAFwkTag::PROCESSMGR, "null etsChildProcessObj_"); + return false; + } + return true; +} + +void EtsChildProcess::OnStart() +{ + TAG_LOGI(AAFwkTag::PROCESSMGR, "EtsChildProcess OnStart Call"); + ChildProcess::OnStart(); + auto env = etsRuntime_.GetAniEnv(); + if (env == nullptr) { + TAG_LOGE(AAFwkTag::PROCESSMGR, "env null"); + return; + } + ani_ref undefinedRef; + ani_status status = env->GetUndefined(&undefinedRef); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::PROCESSMGR, "GetUndefined failed status: %{public}d", status); + return; + } + CallObjectMethod(env, "onStart", static_cast(undefinedRef)); +} + +void EtsChildProcess::OnStart(std::shared_ptr args) +{ + TAG_LOGI(AAFwkTag::PROCESSMGR, "EtsChildProcess OnStart args Call"); + if (!args) { + TAG_LOGE(AAFwkTag::PROCESSMGR, "null args"); + return; + } + ChildProcess::OnStart(args); + auto env = etsRuntime_.GetAniEnv(); + if (env == nullptr) { + TAG_LOGE(AAFwkTag::PROCESSMGR, "env null"); + return; + } + + ani_object etsArgs = WrapChildProcessArgs(env, *args); + CallObjectMethod(env, "onStart", etsArgs); +} + +void EtsChildProcess::CallObjectMethod(ani_env* env, const char *name, ani_object etsArgs) +{ + TAG_LOGD(AAFwkTag::PROCESSMGR, "CallObjectMethod Call, name:%{public}s", name); + if (env == nullptr) { + TAG_LOGE(AAFwkTag::PROCESSMGR, "env null"); + return; + } + ani_method method {}; + ani_status status = ANI_ERROR; + if ((status = env->Class_FindMethod(etsChildProcessObj_->aniCls, name, + "L@ohos/app/ability/ChildProcessArgs/ChildProcessArgs;:V", &method)) != ANI_OK) { + TAG_LOGE(AAFwkTag::APPKIT, "Class_FindMethod status: %{public}d", status); + return; + } + if ((status = env->Object_CallMethod_Void(etsChildProcessObj_->aniObj, method, etsArgs)) != ANI_OK) { + TAG_LOGE(AAFwkTag::APPKIT, "Object_CallMethod_Void status: %{public}d", status); + return; + } +} +} // namespace AbilityRuntime +} // namespace OHOS \ No newline at end of file diff --git a/interfaces/inner_api/child_process_manager/BUILD.gn b/interfaces/inner_api/child_process_manager/BUILD.gn index 0e50d438a49db914ac99adaf8f1c03fc93e1c5d1..3f1d4935743a57fe3759a4929d7d0cba43c915f0 100644 --- a/interfaces/inner_api/child_process_manager/BUILD.gn +++ b/interfaces/inner_api/child_process_manager/BUILD.gn @@ -37,6 +37,7 @@ ohos_shared_library("child_process_manager") { "${ability_runtime_innerkits_path}/runtime:runtime", "${ability_runtime_napi_path}/inner/napi_common:napi_common", "${ability_runtime_native_path}/appkit:app_context", + "${ability_runtime_path}/frameworks/ets/ani/ani_common:ani_common", "${ability_runtime_services_path}/common:app_util", ] @@ -51,6 +52,7 @@ ohos_shared_library("child_process_manager") { "ipc:ipc_capi", "ipc:ipc_core", "napi:ace_napi", + "runtime_core:ani", "samgr:samgr_proxy", ] @@ -61,6 +63,7 @@ ohos_shared_library("child_process_manager") { "${ability_runtime_native_path}/ability/native/child_process_manager/child_process.cpp", "${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/ets_child_process.cpp", "${ability_runtime_native_path}/ability/native/child_process_manager/js_child_process.cpp", "${ability_runtime_native_path}/ability/native/child_process_manager/native_args_child_process.cpp", "${ability_runtime_native_path}/ability/native/child_process_manager/native_child_ipc_process.cpp", diff --git a/interfaces/inner_api/child_process_manager/include/ets_child_process.h b/interfaces/inner_api/child_process_manager/include/ets_child_process.h new file mode 100644 index 0000000000000000000000000000000000000000..84c295e404b5dd4da5224806c79cbbb6f6266333 --- /dev/null +++ b/interfaces/inner_api/child_process_manager/include/ets_child_process.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_CHILD_PROCESS_H +#define OHOS_ABILITY_RUNTIME_ETS_CHILD_PROCESS_H + +#include "ani.h" +#include "child_process.h" +#include "ets_runtime.h" + +namespace OHOS { +namespace AbilityRuntime { +class EtsChildProcess : public ChildProcess { +public: + explicit EtsChildProcess(ETSRuntime &jsRuntime); + ~EtsChildProcess() override; + + static std::shared_ptr Create(const std::unique_ptr &runtime); + + bool Init(const std::shared_ptr &info) override; + void OnStart() override; + void OnStart(std::shared_ptr args) override; + +private: + void CallObjectMethod(ani_env* env, const char *name, ani_object etsArgs); + ETSRuntime &etsRuntime_; + std::shared_ptr etsChildProcessObj_; +}; +} // namespace AbilityRuntime +} // namespace OHOS +#endif // OHOS_ABILITY_RUNTIME_ETS_CHILD_PROCESS_H \ No newline at end of file