/* * Copyright (c) 2026 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "arkts_script.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "bundle_mgr_helper.h" #include "hilog_tag_wrapper.h" #include "js_arkts_script.h" #include "nlohmann/json.hpp" namespace OHOS { namespace ArktsScript { using OHOS::AbilityRuntime::JsRuntime; namespace { constexpr uint64_t SIGNAL_VALUE = 1; constexpr int MAX_EVENTS = 1; constexpr size_t CALL_ARGC = 1; constexpr char ABC_PATH_OPTION[] = "--abcPath"; constexpr char SCRIPT_PATH_OPTION[] = "--scriptPath"; constexpr char FUNCTION_NAME_OPTION[] = "--functionName"; constexpr char ARGS_OPTION[] = "--args"; constexpr char ARG_NAME_PREFIX[] = "arg"; constexpr size_t ARG_NAME_PREFIX_LENGTH = sizeof(ARG_NAME_PREFIX) - 1; constexpr size_t SINGLE_QUOTE_WRAP_LENGTH = 2; constexpr int32_t SCRIPT_CONTEXT_BUNDLE_INFO_FLAGS = static_cast(AppExecFwk::GetBundleInfoFlag::GET_BUNDLE_INFO_WITH_APPLICATION); const std::string HELP_MSG = "ohos-arktsScript - ArkTS script execution tool for loading ABC files and invoking target functions\n\n" "Usage:\n" " ohos-arktsScript [options]\n\n" "Parameters:\n" " --abcPath ABC file path to load (required)\n" " --scriptPath Script file or class name used to locate the target module (optional)\n" " --functionName Function or method name to execute (required)\n" " --args JSON object arguments passed to the function " "(optional, keys must be argN, such as {\"arg0\":10,\"arg1\":20})\n" " --help Display this help message\n\n" "Examples:\n" " # Execute an exported function from an ABC file\n" " ohos-arktsScript --abcPath /data/test/module.abc --functionName run\n\n" " # Execute a method from a specified script class\n" " ohos-arktsScript --abcPath /data/test/module.abc --scriptPath TestScript.ets " "--functionName calculate --args '{\"arg0\":10,\"arg1\":20}'\n\n" " # Execute with JSON object and array arguments\n" " ohos-arktsScript --abcPath /data/test/module.abc --functionName parseValues " "--args '{\"arg0\":{\"name\":\"tool\"},\"arg1\":[\"a\",\"b\"]}'\n"; struct StringOptionBinding { const char* optionName; std::string ScriptArgs::*field; }; constexpr std::array STRING_OPTION_BINDINGS = {{ { ABC_PATH_OPTION, &ScriptArgs::abcPath }, { SCRIPT_PATH_OPTION, &ScriptArgs::scriptName }, { FUNCTION_NAME_OPTION, &ScriptArgs::funName }, }}; bool InitScriptContextFromBundleInfo(const std::shared_ptr& scriptContext, const AppExecFwk::BundleInfo& bundleInfo) { if (scriptContext == nullptr) { return false; } if (bundleInfo.applicationInfo.name.empty() && bundleInfo.applicationInfo.bundleName.empty()) { TAG_LOGE(AAFwkTag::APPKIT, "caller applicationInfo empty"); return false; } scriptContext->SetApplicationInfo(std::make_shared(bundleInfo.applicationInfo)); scriptContext->SetProcessName(bundleInfo.applicationInfo.process); TAG_LOGD(AAFwkTag::APPKIT, "script context initialized from bundleName=%{public}s", bundleInfo.applicationInfo.bundleName.c_str()); return true; } bool InitScriptContextFromCaller(const std::shared_ptr& scriptContext) { auto bundleMgrHelper = DelayedSingleton::GetInstance(); if (bundleMgrHelper == nullptr) { TAG_LOGE(AAFwkTag::APPKIT, "bundleMgrHelper nullptr"); return false; } AppExecFwk::BundleInfo bundleInfo; ErrCode ret = bundleMgrHelper->GetBundleInfoForSelf(SCRIPT_CONTEXT_BUNDLE_INFO_FLAGS, bundleInfo); if (ret != ERR_OK) { TAG_LOGE(AAFwkTag::APPKIT, "getBundleInfo failed ret=%{public}d", ret); return false; } return InitScriptContextFromBundleInfo(scriptContext, bundleInfo); } bool IsArgName(const std::string& name) { if (name.size() <= ARG_NAME_PREFIX_LENGTH || name.compare(0, ARG_NAME_PREFIX_LENGTH, ARG_NAME_PREFIX) != 0) { return false; } return std::all_of(name.begin() + ARG_NAME_PREFIX_LENGTH, name.end(), [](unsigned char ch) { return std::isdigit(ch) != 0; }); } bool ParseArgNameIndex(const std::string& name, uint32_t& index) { if (!IsArgName(name)) { return false; } const std::string indexText = name.substr(ARG_NAME_PREFIX_LENGTH); auto ret = std::from_chars(indexText.data(), indexText.data() + indexText.size(), index); return ret.ec == std::errc() && ret.ptr == indexText.data() + indexText.size(); } bool ParseJsonValueToScriptArg(const nlohmann::json& value, ScriptArg& arg) { if (value.is_string()) { arg.type = ScriptArgType::STRING; arg.value = value.get(); return true; } if (value.is_boolean()) { arg.type = ScriptArgType::BOOLEAN; arg.value = value.get() ? "1" : "0"; return true; } if (value.is_number_integer()) { if (value.is_number_unsigned()) { uint64_t number = value.get(); if (number <= static_cast(std::numeric_limits::max())) { arg.type = ScriptArgType::INT32; } else { arg.type = ScriptArgType::DOUBLE; } } else { int64_t number = value.get(); if (number >= std::numeric_limits::min() && number <= std::numeric_limits::max()) { arg.type = ScriptArgType::INT32; } else { arg.type = ScriptArgType::DOUBLE; } } arg.value = value.dump(); return true; } if (value.is_number_float()) { arg.type = ScriptArgType::DOUBLE; arg.value = value.dump(); return true; } if (value.is_object() || value.is_array()) { arg.type = ScriptArgType::JSON_VALUE; arg.value = value.dump(); return true; } return false; } bool ParseArgsJson(const std::string& rawValue, std::map& indexedArgs) { std::string jsonText = rawValue; // remove outer single quotes if (jsonText.size() >= SINGLE_QUOTE_WRAP_LENGTH && jsonText.front() == '\'' && jsonText.back() == '\'') { jsonText = jsonText.substr(1, jsonText.size() - SINGLE_QUOTE_WRAP_LENGTH); } auto argsJson = nlohmann::json::parse(jsonText, nullptr, false); if (argsJson.is_discarded() || !argsJson.is_object()) { TAG_LOGE(AAFwkTag::APPKIT, "parse args json failed, invalid json object, rawValue: %{public}s", rawValue.c_str()); return false; } for (auto it = argsJson.begin(); it != argsJson.end(); ++it) { uint32_t argIndex = 0; if (!ParseArgNameIndex(it.key(), argIndex)) { TAG_LOGE(AAFwkTag::APPKIT, "parse args json failed, invalid arg name: %{public}s", it.key().c_str()); return false; } ScriptArg arg; if (!ParseJsonValueToScriptArg(it.value(), arg)) { TAG_LOGE(AAFwkTag::APPKIT, "parse args json failed, invalid arg value, key: %{public}s", it.key().c_str()); return false; } if (!indexedArgs.emplace(argIndex, std::move(arg)).second) { TAG_LOGE(AAFwkTag::APPKIT, "parse args json failed, duplicate arg index: %{public}u", argIndex); return false; } } return true; } bool ReadOptionValue(int argc, char* argv[], int& index, std::string& value) { if (index + 1 >= argc || argv[index + 1] == nullptr) { return false; } value = argv[++index]; return true; } bool ReadAndAssignStringOption(int argc, char* argv[], int& index, std::string& target, const char* optionName) { std::string value; if (!ReadOptionValue(argc, argv, index, value)) { TAG_LOGE(AAFwkTag::APPKIT, "Missing value for %{public}s", optionName); return false; } target = value; return true; } bool HandleStringOption(const std::string& option, int argc, char* argv[], int& index, ScriptArgs& args) { for (const auto& binding : STRING_OPTION_BINDINGS) { if (option == binding.optionName) { return ReadAndAssignStringOption(argc, argv, index, args.*(binding.field), binding.optionName); } } return false; } bool HandleArgsOption(int argc, char* argv[], int& index, std::map& indexedArgs, bool& hasArgsJson) { std::string value; if (hasArgsJson || !ReadOptionValue(argc, argv, index, value)) { TAG_LOGE(AAFwkTag::APPKIT, "Invalid --args option"); return false; } if (!ParseArgsJson(value, indexedArgs)) { TAG_LOGE(AAFwkTag::APPKIT, "Invalid value for --args"); return false; } hasArgsJson = true; return true; } } // namespace bool ArktsScript::ParseHelpOption(int argc, char* argv[], ScriptArgs& args) { for (int i = 1; i < argc; i++) { if (argv[i] == nullptr) { continue; } if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--help") == 0) { PrintUsage(); args.showHelp = true; return true; } } return false; } bool ArktsScript::ParseScriptOption(int argc, char* argv[], int& index, ScriptArgs& args, std::map& indexedArgs, bool& hasArgsJson) { std::string option = argv[index]; if (HandleStringOption(option, argc, argv, index, args)) { return true; } if (option == ARGS_OPTION) { return HandleArgsOption(argc, argv, index, indexedArgs, hasArgsJson); } if (option == ABC_PATH_OPTION || option == SCRIPT_PATH_OPTION || option == FUNCTION_NAME_OPTION) { // Matched a known string option but failed while reading its value. // HandleStringOption already emitted the exact error message. return false; } TAG_LOGE(AAFwkTag::APPKIT, "Unknown option: %{public}s", option.c_str()); return false; } bool ArktsScript::FinalizeParsedArguments(const std::map& indexedArgs, ScriptArgs& args) { if (args.abcPath.empty()) { TAG_LOGE(AAFwkTag::APPKIT, "Missing --abcPath option"); return false; } if (args.funName.empty()) { TAG_LOGE(AAFwkTag::APPKIT, "Missing --functionName option"); return false; } args.arguments.clear(); if (!indexedArgs.empty()) { const uint32_t maxArgIndex = indexedArgs.rbegin()->first; args.arguments.resize(static_cast(maxArgIndex) + 1); for (const auto& item : indexedArgs) { args.arguments[item.first] = item.second; } } TAG_LOGD(AAFwkTag::APPKIT, "parsed arguments, abcPath: %{public}s, scriptName: %{public}s, functionName: %{public}s, argc: %{public}zu", args.abcPath.c_str(), args.scriptName.c_str(), args.funName.c_str(), args.arguments.size()); return true; } bool ArktsScript::ParseFunctionAndArguments(int argc, char* argv[], int& index, ScriptArgs& args) { std::map indexedArgs; bool hasArgsJson = false; while (index < argc) { if (argv[index] != nullptr && !ParseScriptOption(argc, argv, index, args, indexedArgs, hasArgsJson)) { return false; } index++; } return FinalizeParsedArguments(indexedArgs, args); } void ArktsScript::PrintUsage() { std::cout << HELP_MSG << std::endl; fflush(stdout); } bool ArktsScript::ParseArguments(int argc, char* argv[], ScriptArgs& args) { if (argc <= 0 || argv == nullptr || argv[0] == nullptr) { return false; } if (ParseHelpOption(argc, argv, args)) { return true; } int i = 1; if (argc <= i) { TAG_LOGE(AAFwkTag::APPKIT, "Missing arguments"); return false; } return ParseFunctionAndArguments(argc, argv, i, args); } std::shared_ptr ArktsScript::CreateScriptContext() { auto scriptContext = std::make_shared(); if (scriptContext == nullptr) { TAG_LOGE(AAFwkTag::APPKIT, "failed to allocate ContextImpl"); return nullptr; } if (!InitScriptContextFromCaller(scriptContext)) { TAG_LOGE(AAFwkTag::APPKIT, "failed to initialize script context from caller"); return nullptr; } return scriptContext; } std::unique_ptr ArktsScript::CreateJsRuntime(const std::shared_ptr& context) { AbilityRuntime::Runtime::Options options; options.lang = AbilityRuntime::Runtime::Language::JS; options.isBundle = true; options.isStageModel = true; if (context != nullptr) { options.bundleName = context->GetBundleName(); options.codePath = context->GetBundleCodePath(); options.bundleCodeDir = context->GetBundleCodeDir(); } auto runtime = JsRuntime::Create(options); if (runtime == nullptr) { TAG_LOGE(AAFwkTag::APPKIT, "Failed to create JsRuntime"); return nullptr; } TAG_LOGD(AAFwkTag::APPKIT, "create JsRuntime result: %{public}d", static_cast(runtime != nullptr)); return runtime; } bool ArktsScript::LoadAbcFile(JsRuntime* runtime, const std::string& path) { if (runtime == nullptr) { TAG_LOGE(AAFwkTag::APPKIT, "runtime is null when loading abc"); return false; } bool loaded = runtime->RunScript(path, "", false); TAG_LOGI(AAFwkTag::APPKIT, "RunScript isLoaded: %{public}d, runScriptPath: %{public}s, targetPath: %{public}s", static_cast(loaded), path.c_str(), path.c_str()); return loaded; } void ArktsScript::OutputResult(const std::string& result) { std::cout << result << std::endl; fflush(stdout); } void ArktsScript::OutputError(const ScriptError& error) { nlohmann::json errorOutput; errorOutput["success"] = false; errorOutput["errorType"] = error.type.empty() ? "EXECUTION_ERROR" : error.type; errorOutput["error"] = error.message; std::cerr << errorOutput.dump() << std::endl; fflush(stderr); } void ArktsScript::ExitFromMonitor(const CompletionChannel& channel, int exitCode) { CompletionChannel localChannel = channel; CloseCompletionChannel(localChannel); _exit(exitCode); } bool ArktsScript::CreateCompletionChannel(CompletionChannel& channel) { channel.eventFd = eventfd(0, EFD_CLOEXEC); if (channel.eventFd < 0) { TAG_LOGE(AAFwkTag::APPKIT, "failed to create eventfd, errno=%{public}d", errno); return false; } channel.epollFd = epoll_create1(EPOLL_CLOEXEC); if (channel.epollFd < 0) { TAG_LOGE(AAFwkTag::APPKIT, "failed to create epoll fd, errno=%{public}d", errno); close(channel.eventFd); channel.eventFd = -1; return false; } epoll_event event {}; event.events = EPOLLIN; event.data.fd = channel.eventFd; if (epoll_ctl(channel.epollFd, EPOLL_CTL_ADD, channel.eventFd, &event) != 0) { TAG_LOGE(AAFwkTag::APPKIT, "failed to register eventfd into epoll, errno=%{public}d", errno); close(channel.epollFd); close(channel.eventFd); channel.epollFd = -1; channel.eventFd = -1; return false; } return true; } void ArktsScript::CloseCompletionChannel(CompletionChannel& channel) { if (channel.epollFd >= 0) { close(channel.epollFd); channel.epollFd = -1; } if (channel.eventFd >= 0) { close(channel.eventFd); channel.eventFd = -1; } } bool ArktsScript::SignalCompletion(int eventFd) { if (eventFd < 0) { return false; } ssize_t ret = -1; do { ret = write(eventFd, &SIGNAL_VALUE, sizeof(SIGNAL_VALUE)); } while (ret < 0 && errno == EINTR); if (ret != static_cast(sizeof(SIGNAL_VALUE))) { TAG_LOGE(AAFwkTag::APPKIT, "failed to signal eventfd, errno=%{public}d", errno); return false; } return true; } bool ArktsScript::PublishResult(const std::shared_ptr& execContext, int eventFd, const std::string& result) { if (execContext == nullptr) { return false; } { std::lock_guard lock(execContext->mutex); if (execContext->resultReady.load(std::memory_order_acquire)) { TAG_LOGW(AAFwkTag::APPKIT, "duplicate result ignored"); return false; } execContext->result = result; execContext->error = {}; execContext->resultReady.store(true, std::memory_order_release); } if (!SignalCompletion(eventFd)) { TAG_LOGE(AAFwkTag::APPKIT, "result recorded but signal failed"); } return true; } bool ArktsScript::PublishFailure(const std::shared_ptr& execContext, int eventFd, const ScriptError& error) { if (execContext == nullptr) { return false; } { std::lock_guard lock(execContext->mutex); if (!execContext->error.message.empty()) { TAG_LOGW(AAFwkTag::APPKIT, "duplicate failure ignored"); return false; } execContext->result.clear(); execContext->error = error; execContext->scriptDone.store(true, std::memory_order_release); } if (!SignalCompletion(eventFd)) { TAG_LOGE(AAFwkTag::APPKIT, "failure recorded but signal failed"); } return true; } bool ArktsScript::MarkScriptDone(const std::shared_ptr& execContext, int eventFd) { if (execContext == nullptr) { return false; } execContext->scriptDone.store(true, std::memory_order_release); if (!SignalCompletion(eventFd)) { TAG_LOGE(AAFwkTag::APPKIT, "scriptDone recorded but signal failed"); } return true; } void ArktsScript::ReadCompletionSignal(const CompletionChannel& channel) { uint64_t count = 0; ssize_t readSize = -1; do { readSize = read(channel.eventFd, &count, sizeof(count)); } while (readSize < 0 && errno == EINTR); if (readSize < 0 && errno != EAGAIN) { TAG_LOGE(AAFwkTag::APPKIT, "failed to read eventfd, errno=%{public}d", errno); ArktsScript::OutputError({"failed to read completion signal", "SYSTEM_ERROR"}); ExitFromMonitor(channel, EXIT_FAILURE); } } ExecutionSnapshot ArktsScript::TakeExecutionSnapshot(const std::shared_ptr& execContext) { ExecutionSnapshot snapshot; if (execContext == nullptr) { return snapshot; } std::lock_guard lock(execContext->mutex); snapshot.result = execContext->result; snapshot.error = execContext->error; snapshot.resultReady = execContext->resultReady.load(std::memory_order_acquire); snapshot.scriptDone = execContext->scriptDone.load(std::memory_order_acquire); return snapshot; } void ArktsScript::HandleExecutionSnapshot(const ExecutionSnapshot& snapshot, const CompletionChannel& channel) { if (!snapshot.error.message.empty()) { ArktsScript::OutputError(snapshot.error); ExitFromMonitor(channel, EXIT_FAILURE); } if (snapshot.resultReady && snapshot.scriptDone) { ArktsScript::OutputResult(snapshot.result); ExitFromMonitor(channel, EXIT_SUCCESS); } } void ArktsScript::MonitorCompletion(ExitState state, CompletionChannel channel) { epoll_event events[MAX_EVENTS] {}; while (channel.epollFd >= 0 && channel.eventFd >= 0) { int readyCount = epoll_wait(channel.epollFd, events, MAX_EVENTS, -1); if (readyCount < 0) { if (errno == EINTR) { continue; } TAG_LOGE(AAFwkTag::APPKIT, "epoll_wait failed, errno=%{public}d", errno); ArktsScript::OutputError({"failed to wait completion signal", "SYSTEM_ERROR"}); ExitFromMonitor(channel, EXIT_FAILURE); } if (readyCount == 0 || events[0].data.fd != channel.eventFd) { continue; } ReadCompletionSignal(channel); HandleExecutionSnapshot(TakeExecutionSnapshot(state.execContext), channel); } } bool ArktsScript::StartMonitor(CompletionChannel& channel, std::shared_ptr& execContext, std::thread& monitorThread) { if (!CreateCompletionChannel(channel)) { ArktsScript::OutputError({"failed to create completion channel", "SYSTEM_ERROR"}); return false; } execContext = std::make_shared(); ExitState exitState { execContext }; monitorThread = std::thread(MonitorCompletion, exitState, channel); TAG_LOGD(AAFwkTag::APPKIT, "completion monitor started"); return true; } int ArktsScript::FinalizeAndJoin(const std::shared_ptr& execContext, CompletionChannel& channel, std::thread& monitorThread, const ScriptError& error) { if (execContext != nullptr) { PublishFailure(execContext, channel.eventFd, error); } if (monitorThread.joinable()) { monitorThread.join(); } return EXIT_FAILURE; } ResultCallback ArktsScript::CreateCompleteCallback(const std::shared_ptr& execContext, CompletionChannel channel) { return [execContext, channel](bool success, const std::string& result, const ScriptError& error) { if (success) { PublishResult(execContext, channel.eventFd, result); return; } PublishFailure(execContext, channel.eventFd, error); }; } bool ArktsScript::PrepareRuntimeEnvironment(const ResultCallback& completeCallback, std::shared_ptr& context, std::unique_ptr& runtimeOwner, ScriptError& error) { context = ArktsScript::CreateScriptContext(); if (context == nullptr) { error.message = "failed to create script context"; error.type = "CONTEXT_ERROR"; return false; } runtimeOwner = ArktsScript::CreateJsRuntime(context); if (runtimeOwner == nullptr) { error.message = "failed to create js runtime"; error.type = "RUNTIME_ERROR"; return false; } napi_env env = runtimeOwner->GetNapiEnv(); if (env == nullptr) { error.message = "failed to get napi_env"; error.type = "ENV_ERROR"; return false; } if (!JsArktsScript::BindContextToGlobal(env, context)) { error.message = "failed to bind context to globalThis"; error.type = "BIND_ERROR"; return false; } if (!JsArktsScript::BindCompletearktsScript(env, completeCallback)) { error.message = "failed to bind CompletearktsScript"; error.type = "BIND_ERROR"; return false; } TAG_LOGD(AAFwkTag::APPKIT, "runtime environment prepared"); return true; } bool ArktsScript::LoadScriptFile(const ScriptArgs& args, JsRuntime* runtime, ScriptError& error) { if (!ArktsScript::LoadAbcFile(runtime, args.abcPath)) { error.message = "failed to load ABC file, runScriptPath: " + args.abcPath + ", targetPath: " + args.abcPath; error.type = "LOAD_ERROR"; return false; } return true; } bool ArktsScript::ResolveScriptFunction(const ScriptArgs& args, JsRuntime* runtime, napi_value& receiver, napi_value& func, ScriptError& error) { napi_env env = runtime != nullptr ? runtime->GetNapiEnv() : nullptr; bool isResolved = JsArktsScript::ResolveFunction(runtime, env, args.abcPath, args.scriptName, args.funName, receiver, func); TAG_LOGI(AAFwkTag::APPKIT, "ResolveFunction isResolved: %{public}d, functionName: %{public}s", static_cast(isResolved), args.funName.c_str()); if (!isResolved) { error.message = "failed to resolve function: " + args.funName + ", loaded abcPath: " + args.abcPath + ", targetPath: " + args.abcPath + ", scriptName: " + args.scriptName; error.type = "FUNCTION_ERROR"; return false; } return true; } bool ArktsScript::CallResolvedFunction(const ScriptArgs& args, napi_env env, napi_value receiver, napi_value func, ScriptError& error) { napi_value argsArray = JsArktsScript::ConvertArgumentsToNapi(env, args.arguments); if (argsArray == nullptr) { TAG_LOGE(AAFwkTag::APPKIT, "call resolved function failed, failed to convert arguments"); error.message = "failed to convert arguments"; error.type = "ARGUMENT_ERROR"; return false; } napi_value callResult = nullptr; napi_status status = napi_call_function(env, receiver, func, CALL_ARGC, &argsArray, &callResult); if (status != napi_ok) { TAG_LOGE(AAFwkTag::APPKIT, "CallResolvedFunction status: %{public}d, functionName: %{public}s", static_cast(status), args.funName.c_str()); error.message = "failed to call function: " + args.funName + ", napi_status: " + std::to_string(status); error.type = "CALL_ERROR"; return false; } TAG_LOGI(AAFwkTag::APPKIT, "CallResolvedFunction status: %{public}d, functionName: %{public}s", static_cast(status), args.funName.c_str()); return true; } int ArktsScript::RunArkTsScript(int argc, char* argv[]) { ScriptArgs args; if (!ArktsScript::ParseArguments(argc, argv, args)) { ArktsScript::OutputError({"failed to parse arguments", "ARGUMENT_ERROR"}); return EXIT_FAILURE; } if (args.showHelp) { return EXIT_SUCCESS; } CompletionChannel channel; std::shared_ptr execContext; std::thread monitorThread; if (!StartMonitor(channel, execContext, monitorThread)) { return EXIT_FAILURE; } ScriptError error; std::shared_ptr context; std::unique_ptr runtimeOwner; ResultCallback completeCallback = CreateCompleteCallback(execContext, channel); if (!PrepareRuntimeEnvironment(completeCallback, context, runtimeOwner, error)) { return FinalizeAndJoin(execContext, channel, monitorThread, error); } napi_env env = runtimeOwner->GetNapiEnv(); napi_value receiver = nullptr; napi_value func = nullptr; if (!LoadScriptFile(args, runtimeOwner.get(), error) || !ResolveScriptFunction(args, runtimeOwner.get(), receiver, func, error) || !CallResolvedFunction(args, env, receiver, func, error)) { return FinalizeAndJoin(execContext, channel, monitorThread, error); } MarkScriptDone(execContext, channel.eventFd); if (monitorThread.joinable()) { monitorThread.join(); } return EXIT_FAILURE; } } // namespace ArktsScript } // namespace OHOS