diff --git a/frameworks/js/napi/BUILD.gn b/frameworks/js/napi/BUILD.gn index a1db6c7131..dd8c251590 100644 --- a/frameworks/js/napi/BUILD.gn +++ b/frameworks/js/napi/BUILD.gn @@ -69,6 +69,7 @@ group("napi_packages") { "${ability_runtime_napi_path}/inner/napi_wantagent_common:napi_wantagent_common", "${ability_runtime_napi_path}/insight_intent/insight_intent:insightintent_napi", "${ability_runtime_napi_path}/insight_intent/insight_intent_driver:insightintentdriver_napi", + "${ability_runtime_napi_path}/insight_intent/insight_intent_entry_executor:insightintententryexecutor_napi", "${ability_runtime_napi_path}/insight_intent/insight_intent_executor:insightintentexecutor_napi", "${ability_runtime_napi_path}/insight_intent_context:insightintentcontext_napi", "${ability_runtime_napi_path}/js_dialog_request:dialogrequest_napi", diff --git a/frameworks/js/napi/insight_intent/insight_intent_entry_executor/BUILD.gn b/frameworks/js/napi/insight_intent/insight_intent_entry_executor/BUILD.gn new file mode 100644 index 0000000000..fdb1fcdb63 --- /dev/null +++ b/frameworks/js/napi/insight_intent/insight_intent_entry_executor/BUILD.gn @@ -0,0 +1,61 @@ +# 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/config/components/ets_frontend/es2abc_config.gni") +import("//build/ohos.gni") + +es2abc_gen_abc("gen_insight_intent_entry_executor_abc") { + src_js = rebase_path("insight_intent_entry_executor.js") + dst_file = rebase_path(target_out_dir + "/insight_intent_entry_executor.abc") + in_puts = [ "insight_intent_entry_executor.js" ] + out_puts = [ target_out_dir + "/insight_intent_entry_executor.abc" ] + extra_args = [ "--module" ] +} + +gen_js_obj("insight_intent_entry_executor_js") { + input = "insight_intent_entry_executor.js" + output = target_out_dir + "/insight_intent_entry_executor.o" +} + +gen_js_obj("insight_intent_entry_executor_abc") { + input = get_label_info(":gen_insight_intent_entry_executor_abc", "target_out_dir") + + "/insight_intent_entry_executor.abc" + output = target_out_dir + "/insight_intent_entry_executor_abc.o" + dep = ":gen_insight_intent_entry_executor_abc" +} + +ohos_shared_library("insightintententryexecutor_napi") { + 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" + + sources = [ "insight_intent_entry_module.cpp" ] + + deps = [ + ":insight_intent_entry_executor_abc", + ":insight_intent_entry_executor_js", + ] + + external_deps = [ "napi:ace_napi" ] + + relative_install_dir = "module/app/ability" + subsystem_name = "ability" + part_name = "ability_runtime" +} diff --git a/frameworks/js/napi/insight_intent/insight_intent_entry_executor/insight_intent_entry_executor.js b/frameworks/js/napi/insight_intent/insight_intent_entry_executor/insight_intent_entry_executor.js new file mode 100644 index 0000000000..5020bf361a --- /dev/null +++ b/frameworks/js/napi/insight_intent/insight_intent_entry_executor/insight_intent_entry_executor.js @@ -0,0 +1,30 @@ +/* + * 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. + */ + +let hilog = requireNapi('hilog'); + +let domainID = 0xD001323; +let TAG = 'Intent'; + +export default class InsightIntentEntryExecutor { + constructor() {} + + onExecute() { + hilog.sLogI(domainID, TAG, 'onExecute'); + return { + 'code': 0 + }; + } +} diff --git a/frameworks/js/napi/insight_intent/insight_intent_entry_executor/insight_intent_entry_module.cpp b/frameworks/js/napi/insight_intent/insight_intent_entry_executor/insight_intent_entry_module.cpp new file mode 100644 index 0000000000..1f04daedda --- /dev/null +++ b/frameworks/js/napi/insight_intent/insight_intent_entry_executor/insight_intent_entry_module.cpp @@ -0,0 +1,56 @@ +/* + * 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 "native_engine/native_engine.h" + +extern const char _binary_insight_intent_entry_executor_js_start[]; +extern const char _binary_insight_intent_entry_executor_js_end[]; +extern const char _binary_insight_intent_entry_executor_abc_start[]; +extern const char _binary_insight_intent_entry_executor_abc_end[]; + +static napi_module _module = { + .nm_version = 0, + .nm_filename = "app/ability/insightintententryexecutor_napi.so/insight_intent_entry_executor.js", + .nm_modname = "app.ability.InsightIntentEntryExecutor", +}; + +extern "C" __attribute__((constructor)) +void NAPI_app_ability_InsightIntentEntryExecutor_AutoRegister() +{ + napi_module_register(&_module); +} + +extern "C" __attribute__((visibility("default"))) +void NAPI_app_ability_InsightIntentEntryExecutor_GetJSCode(const char **buf, int *bufLen) +{ + if (buf != nullptr) { + *buf = _binary_insight_intent_entry_executor_js_start; + } + + if (bufLen != nullptr) { + *bufLen = _binary_insight_intent_entry_executor_js_end - _binary_insight_intent_entry_executor_js_start; + } +} + +extern "C" __attribute__((visibility("default"))) +void NAPI_app_ability_InsightIntentEntryExecutor_GetABCCode(const char **buf, int *buflen) +{ + if (buf != nullptr) { + *buf = _binary_insight_intent_entry_executor_abc_start; + } + if (buflen != nullptr) { + *buflen = _binary_insight_intent_entry_executor_abc_end - _binary_insight_intent_entry_executor_abc_start; + } +} diff --git a/frameworks/native/ability/native/insight_intent_executor/js_insight_intent_entry.cpp b/frameworks/native/ability/native/insight_intent_executor/js_insight_intent_entry.cpp new file mode 100644 index 0000000000..d359b10a06 --- /dev/null +++ b/frameworks/native/ability/native/insight_intent_executor/js_insight_intent_entry.cpp @@ -0,0 +1,448 @@ +/* + * 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 "js_insight_intent_entry.h" + +#include + +#include "hilog_tag_wrapper.h" +#include "insight_intent_constant.h" +#include "insight_intent_execute_result.h" +#include "js_insight_intent_context.h" +#include "js_insight_intent_utils.h" +#include "js_runtime.h" +#include "js_runtime_utils.h" +#include "napi_common_execute_result.h" +#include "napi_common_util.h" +#include "napi_common_want.h" +#include "native_reference.h" + +#undef STATE_PATTERN_NAIVE_H +#define STATE_PATTERN_NAIVE_STATE state_ +#include "state_pattern_naive.h" + +#define TMP_NAPI_ANONYMOUS_FUNC "_" + +namespace OHOS{ +namespace AbilityRuntime { +std::shared_ptr JsInsightIntentEntry::Create(JsRuntime& runtime) +{ + std::shared_ptr ptr(new (std::nothrow) JsInsightIntentEntry(runtime)); + return ptr; +} + +JsInsightIntentEntry::JsInsightIntentEntry(JsRuntime& runtime) : runtime_(runtime) +{ + TAG_LOGD(AAFwkTag::INTENT, "constructor"); +} + +JsInsightIntentEntry::~JsInsightIntentEntry() +{ + state_ = State::DESTROYED; + TAG_LOGI(AAFwkTag::INTENT, "destructor"); +} + +bool JsInsightIntentEntry::Init(const InsightIntentExecutorInfo& insightIntentInfo) +{ + TAG_LOGD(AAFwkTag::INTENT, "Init"); + STATE_PATTERN_NAIVE_ACCEPT(State::CREATED, false); + state_ = State::INITIALIZED; + InsightIntentExecutor::Init(insightIntentInfo); + + HandleScope handleScope(runtime_); + jsObj_ = JsInsightIntentEntry::LoadJsCode(insightIntentInfo, runtime_); + if (jsObj_ == nullptr) { + TAG_LOGE(AAFwkTag::INTENT, "load js failed"); + STATE_PATTERN_NAIVE_STATE_SET_AND_RETURN(State::INVALID, false); + } + + auto env = runtime_.GetNapiEnv(); + if (env == nullptr) { + TAG_LOGE(AAFwkTag::INTENT, "null env"); + STATE_PATTERN_NAIVE_STATE_SET_AND_RETURN(State::INVALID, false); + } + + auto context = GetContext(); + if (context == nullptr) { + TAG_LOGE(AAFwkTag::INTENT, "null Context"); + STATE_PATTERN_NAIVE_STATE_SET_AND_RETURN(State::INVALID, false); + } + + napi_value contextObj = CreateJsInsightIntentContext(env, context); + contextObj_ = JsRuntime::LoadSystemModuleByEngine(env, "app.ability.InsightIntentContext", &contextObj, 1); + if (contextObj_ == nullptr) { + TAG_LOGE(AAFwkTag::INTENT, "null contextObj_"); + STATE_PATTERN_NAIVE_STATE_SET_AND_RETURN(State::INVALID, false); + } + + auto executorNapiVal = jsObj_->GetNapiValue(); + auto contextNapiVal = contextObj_->GetNapiValue(); + if (!CheckTypeForNapiValue(env, executorNapiVal, napi_object) || + !CheckTypeForNapiValue(env, contextNapiVal, napi_object) || + napi_set_named_property(env, executorNapiVal, "context", contextNapiVal) != napi_ok) { + TAG_LOGE(AAFwkTag::INTENT, "set context property failed"); + STATE_PATTERN_NAIVE_STATE_SET_AND_RETURN(State::INVALID, false); + } + + return true; +} + +bool JsInsightIntentEntry::HandleExecuteIntent( + std::shared_ptr executeParam, + const std::shared_ptr& pageLoader, + std::unique_ptr callback, + bool& isAsync) +{ + STATE_PATTERN_NAIVE_ACCEPT(State::INITIALIZED, false); + state_ = State::EXECUTING; + + if (callback == nullptr || callback->IsEmpty()) { + TAG_LOGE(AAFwkTag::INTENT, "null callback"); + STATE_PATTERN_NAIVE_STATE_SET_AND_RETURN(State::INVALID, false); + } + + if (executeParam == nullptr || executeParam->insightIntentParam_ == nullptr) { + TAG_LOGE(AAFwkTag::INTENT, "invalid execute param"); + STATE_PATTERN_NAIVE_STATE_SET_AND_RETURN(State::INVALID, false); + } + + callback_ = std::move(callback); + auto name = executeParam->insightIntentName_; + TAG_LOGD(AAFwkTag::INTENT, "Execute Intent %{public}s", name.c_str()); + + // Check parameter + InsightIntentExecuteMode mode = static_cast(executeParam->executeMode_); + if (!PrepareParameters(mode, pageLoader)) { + return ExecuteIntentCheckError(); + } + + bool successful = ExecuteInsightIntent(name, *executeParam->insightIntentParam_, pageLoader); + isAsync = isAsync_; + return successful; +} + +std::unique_ptr JsInsightIntentEntry::LoadJsCode( + const InsightIntentExecutorInfo& info, + JsRuntime& runtime) +{ + TAG_LOGD(AAFwkTag::INTENT, "load module"); + auto executeParam = info.executeParam; + if (executeParam == nullptr) { + TAG_LOGE(AAFwkTag::INTENT, "null executeParam"); + return std::unique_ptr(); + } + + std::string moduleName(executeParam->moduleName_); + std::string srcPath(executeParam->moduleName_ + "/" + info.srcEntry); + auto pos = srcPath.rfind('.'); + if (pos == std::string::npos) { + TAG_LOGE(AAFwkTag::INTENT, "srcEntry invalid"); + return nullptr; + } + srcPath.erase(pos); + srcPath.append(".abc"); + + // info.srcEntry is a ohmurl type, it has export default + std::unique_ptr jsCode(runtime.LoadModule(moduleName, srcPath, info.hapPath, info.esmodule, + false, info.srcEntry)); + return jsCode; +} + +bool JsInsightIntentEntry::CallJsFunctionWithResultInner( + const char* funcName, + size_t argc, + const napi_value* argv, + napi_value& result) +{ + TAG_LOGD(AAFwkTag::INTENT, "call js function"); + auto* env = runtime_.GetNapiEnv(); + napi_value obj = jsObj_->GetNapiValue(); + if (!CheckTypeForNapiValue(env, obj, napi_valuetype::napi_object)) { + TAG_LOGE(AAFwkTag::INTENT, "call js function type error"); + return false; + } + return JsInsightIntentUtils::CallJsFunctionWithResult(env, obj, funcName, argc, argv, result); +} + +void JsInsightIntentEntry::ReplyFailedInner(InsightIntentInnerErr innerErr) +{ + TAG_LOGD(AAFwkTag::INTENT, "reply failed"); + state_ = State::INVALID; + auto* callback = callback_.release(); + JsInsightIntentUtils::ReplyFailed(callback, innerErr); +} + +void JsInsightIntentEntry::ReplySucceededInner(std::shared_ptr resultCpp) +{ + TAG_LOGD(AAFwkTag::INTENT, "reply succeed"); + state_ = State::EXECUTATION_DONE; + auto* callback = callback_.release(); + JsInsightIntentUtils::ReplySucceeded(callback, resultCpp); +} + +bool JsInsightIntentEntry::HandleResultReturnedFromJsFunc(napi_value resultJs) +{ + TAG_LOGD(AAFwkTag::INTENT, "handle result returned"); + auto* env = runtime_.GetNapiEnv(); + if (resultJs == nullptr) { + return ExecuteIntentCheckError(); + } + + bool isPromise = false; + NAPI_CALL_BASE(env, napi_is_promise(env, resultJs, &isPromise), ExecuteIntentCheckError()); + isAsync_ = isPromise; + + if (!isPromise) { + // onExecute only support promise + TAG_LOGW(AAFwkTag::INTENT, "no promise, don't support for now"); + return ExecuteIntentCheckError(); + } + + TAG_LOGI(AAFwkTag::INTENT, "Is promise"); + auto* callback = callback_.release(); + + napi_value then = nullptr; + NAPI_CALL_BASE(env, napi_get_named_property(env, resultJs, "then", &then), ExecuteIntentCheckError()); + napi_value resolveCbJs = nullptr; + NAPI_CALL_BASE(env, napi_create_function(env, TMP_NAPI_ANONYMOUS_FUNC, strlen(TMP_NAPI_ANONYMOUS_FUNC), + JsInsightIntentUtils::ResolveCbCpp, callback, &resolveCbJs), ExecuteIntentCheckError()); + constexpr size_t argcThen = 1; + napi_value argvThen[argcThen] = { resolveCbJs }; + NAPI_CALL_BASE(env, napi_call_function(env, resultJs, then, argcThen, argvThen, nullptr), + ExecuteIntentCheckError()); + + napi_value promiseCatch = nullptr; + NAPI_CALL_BASE(env, napi_get_named_property(env, resultJs, "catch", &promiseCatch), ExecuteIntentCheckError()); + napi_value rejectCbJs = nullptr; + NAPI_CALL_BASE(env, napi_create_function(env, TMP_NAPI_ANONYMOUS_FUNC, strlen(TMP_NAPI_ANONYMOUS_FUNC), + JsInsightIntentUtils::RejectCbCpp, callback, &rejectCbJs), ExecuteIntentCheckError()); + constexpr size_t argcCatch = 1; + napi_value argvCatch[argcCatch] = { rejectCbJs }; + NAPI_CALL_BASE(env, napi_call_function(env, resultJs, promiseCatch, argcCatch, argvCatch, nullptr), + ExecuteIntentCheckError()); + + return true; +} + +bool JsInsightIntentEntry::ExecuteIntentCheckError() +{ + ReplyFailedInner(); + STATE_PATTERN_NAIVE_STATE_SET_AND_RETURN(State::INVALID, false); +} + +bool JsInsightIntentEntry::ExecuteInsightIntent( + const std::string& name, + const AAFwk::WantParams& param, + const std::shared_ptr& windowStageJs) +{ + TAG_LOGD(AAFwkTag::INTENT, "execute insight intent %{public}s", name.c_str()); + HandleScope handleScope(runtime_); + auto env = runtime_.GetNapiEnv(); + if (env == nullptr) { + TAG_LOGE(AAFwkTag::INTENT, "null env"); + return ExecuteIntentCheckError(); + } + + if (!AssignObject(env, param)) { + TAG_LOGE(AAFwkTag::INTENT, "assign object failed"); + return ExecuteIntentCheckError(); + } + + napi_value result = nullptr; + if (!CallJsFunctionWithResultInner("onExecute", 0, nullptr, result)) { + // error log has printed + return ExecuteIntentCheckError(); + } + + return HandleResultReturnedFromJsFunc(result); +} + +bool JsInsightIntentEntry::PrepareParameters(InsightIntentExecuteMode mode, + const std::shared_ptr& pageLoader) +{ + auto env = runtime_.GetNapiEnv(); + if (env == nullptr) { + TAG_LOGE(AAFwkTag::INTENT, "null env"); + return false; + } + + switch (mode) { + case InsightIntentExecuteMode::UIABILITY_FOREGROUND: + return PrepareParametersUIAbilityForeground(env, pageLoader); + case InsightIntentExecuteMode::UIABILITY_BACKGROUND: + return PrepareParametersUIAbilityBackground(env); + case InsightIntentExecuteMode::UIEXTENSION_ABILITY: + return PrepareParametersUIExtension(env, pageLoader); + case InsightIntentExecuteMode::SERVICE_EXTENSION_ABILITY: + return PrepareParametersServiceExtension(env); + default: + TAG_LOGE(AAFwkTag::INTENT, "InsightIntentExecuteMode not supported yet"); + return false; + } + + return true; +} + +bool JsInsightIntentEntry::PrepareParametersUIAbilityForeground(napi_env env, + const std::shared_ptr& pageLoader) +{ + // check pageloader and jsObj_ + if (pageLoader == nullptr || jsObj_ == nullptr) { + TAG_LOGE(AAFwkTag::INTENT, "page loader or object invalid"); + return false; + } + + // assign ability pageloader + auto executorNapiVal = jsObj_->GetNapiValue(); + auto pageLoaderNapiVal = pageLoader->GetNapiValue(); + if (!CheckTypeForNapiValue(env, executorNapiVal, napi_object) || + !CheckTypeForNapiValue(env, pageLoaderNapiVal, napi_object) || + napi_set_named_property(env, executorNapiVal, "windowStage", pageLoaderNapiVal) != napi_ok) { + TAG_LOGE(AAFwkTag::INTENT, "set windowStage property failed"); + return false; + } + + // assign execute mode + auto mode = InsightIntentExecuteMode::UIABILITY_FOREGROUND; + auto modeNapiVal = AppExecFwk::WrapInt32ToJS(env, static_cast(mode)); + auto status = napi_set_named_property(env, executorNapiVal, "executeMode", modeNapiVal); + if (status != napi_ok) { + TAG_LOGE(AAFwkTag::INTENT, "set executeMode property failed with %{public}d", status); + return false; + } + + return true; +} + +bool JsInsightIntentEntry::PrepareParametersUIAbilityBackground(napi_env env) +{ + if (jsObj_ == nullptr) { + TAG_LOGE(AAFwkTag::INTENT, "js object null"); + return false; + } + + auto executorNapiVal = jsObj_->GetNapiValue(); + if (!CheckTypeForNapiValue(env, executorNapiVal, napi_object)) { + TAG_LOGE(AAFwkTag::INTENT, "js object invalid"); + return false; + } + + auto mode = InsightIntentExecuteMode::UIABILITY_BACKGROUND; + auto modeNapiVal = AppExecFwk::WrapInt32ToJS(env, static_cast(mode)); + auto status = napi_set_named_property(env, executorNapiVal, "executeMode", modeNapiVal); + if (status != napi_ok) { + TAG_LOGE(AAFwkTag::INTENT, "set executeMode property failed with %{public}d", status); + return false; + } + + return true; +} + +bool JsInsightIntentEntry::PrepareParametersUIExtension(napi_env env, + const std::shared_ptr& pageLoader) +{ + // check pageloader and jsObj_ + if (pageLoader == nullptr || jsObj_ == nullptr) { + TAG_LOGE(AAFwkTag::INTENT, "page loader or object invalid"); + return false; + } + + // assign ability pageloader + auto executorNapiVal = jsObj_->GetNapiValue(); + auto pageLoaderNapiVal = pageLoader->GetNapiValue(); + if (!CheckTypeForNapiValue(env, executorNapiVal, napi_object) || + !CheckTypeForNapiValue(env, pageLoaderNapiVal, napi_object) || + napi_set_named_property(env, executorNapiVal, "uiExtensionSession", pageLoaderNapiVal) != napi_ok) { + TAG_LOGE(AAFwkTag::INTENT, "set uiExtensionSession property failed"); + return false; + } + + // assign execute mode + auto mode = InsightIntentExecuteMode::UIEXTENSION_ABILITY; + auto modeNapiVal = AppExecFwk::WrapInt32ToJS(env, static_cast(mode)); + auto status = napi_set_named_property(env, executorNapiVal, "executeMode", modeNapiVal); + if (status != napi_ok) { + TAG_LOGE(AAFwkTag::INTENT, "set executeMode property failed with %{public}d", status); + return false; + } + + return true; +} + +bool JsInsightIntentEntry::PrepareParametersServiceExtension(napi_env env) +{ + if (jsObj_ == nullptr) { + TAG_LOGE(AAFwkTag::INTENT, "js object null"); + return false; + } + + auto executorNapiVal = jsObj_->GetNapiValue(); + if (!CheckTypeForNapiValue(env, executorNapiVal, napi_object)) { + TAG_LOGE(AAFwkTag::INTENT, "js object invalid"); + return false; + } + + auto mode = InsightIntentExecuteMode::SERVICE_EXTENSION_ABILITY; + auto modeNapiVal = AppExecFwk::WrapInt32ToJS(env, static_cast(mode)); + auto status = napi_set_named_property(env, executorNapiVal, "executeMode", modeNapiVal); + if (status != napi_ok) { + TAG_LOGE(AAFwkTag::INTENT, "set executeMode property failed with %{public}d", status); + return false; + } + + return true; +} + +bool JsInsightIntentEntry::AssignObject(napi_env env, const AAFwk::WantParams &wantParams) +{ + AAFwk::WantParamWrapper wrapper(wantParams); + std::string parametersString = wrapper.ToString(); + TAG_LOGD(AAFwkTag::INTENT, "param string %{public}s", parametersString.c_str()); + + auto executorNapiVal = jsObj_->GetNapiValue(); + if (!CheckTypeForNapiValue(env, executorNapiVal, napi_object)) { + TAG_LOGE(AAFwkTag::INTENT, "check type failed"); + return false; + } + + napi_value srcObj = AppExecFwk::WrapWantParams(env, wantParams); + + // Get all property + napi_value propertys; + NAPI_CALL_BASE(env, napi_get_property_names(env, srcObj, &propertys), false); + + uint32_t propCnt; + NAPI_CALL_BASE(env, napi_get_array_length(env, propertys, &propCnt), false); + + for (uint32_t i = 0; i < propCnt; i++) { + napi_value propKey; + NAPI_CALL_BASE(env, napi_get_element(env, propertys, i, &propKey), false); + + std::string propName; + if (!ConvertFromJsValue(env, propKey, propName)) { + TAG_LOGE(AAFwkTag::INTENT, "convert napi value failed"); + return false; + } + TAG_LOGD(AAFwkTag::INTENT, "param %{public}s", propName.c_str()); + + napi_value propValue; + NAPI_CALL_BASE(env, napi_get_property(env, srcObj, propKey, &propValue), false); + NAPI_CALL_BASE(env, napi_set_property(env, executorNapiVal, propKey, propValue), false); + } + + return true; +} +} // namespace AbilityRuntime +} // namespace OHOS diff --git a/interfaces/kits/native/ability/native/insight_intent_executor/js_insight_intent_entry.h b/interfaces/kits/native/ability/native/insight_intent_executor/js_insight_intent_entry.h new file mode 100644 index 0000000000..f94c9c7c34 --- /dev/null +++ b/interfaces/kits/native/ability/native/insight_intent_executor/js_insight_intent_entry.h @@ -0,0 +1,111 @@ +/* + * 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_JS_INSIGHT_INTENT_ENTRY_H +#define OHOS_ABILITY_RUNTIME_JS_INSIGHT_INTENT_ENTRY_H + +#include "insight_intent_executor.h" + +#include "insight_intent_execute_result.h" +#include "js_insight_intent_utils.h" +#include "js_runtime.h" +#include "native_reference.h" + +namespace OHOS { +namespace AbilityRuntime { +using State = JsInsightIntentUtils::State; + +class JsInsightIntentEntry final : public InsightIntentExecutor, + public std::enable_shared_from_this { +public: + JsInsightIntentEntry(const JsInsightIntentEntry&) = delete; + JsInsightIntentEntry(const JsInsightIntentEntry&&) = delete; + JsInsightIntentEntry& operator=(const JsInsightIntentEntry&) = delete; + JsInsightIntentEntry& operator=(const JsInsightIntentEntry&&) = delete; + ~JsInsightIntentEntry() override; + + /** + * @brief Create insight intent executor, intent type is entry. + * + * @param runtime The JsRuntime. + */ + static std::shared_ptr Create(JsRuntime& runtime); + + /** + * @brief Init insight intent executor and insight intent context. + * + * @param insightIntentInfo The insight intent executor information. + */ + bool Init(const InsightIntentExecutorInfo& insightIntentInfo) override; + + /** + * @brief Handling the insight intent execute. + * + * @param executeParam The execute params. + * @param pageLoader The page loader. + * @param callback The async callback. + * @param isAsync Indicates the target function is promise or not. + */ + bool HandleExecuteIntent( + std::shared_ptr executeParam, + const std::shared_ptr& pageLoader, + std::unique_ptr callback, + bool& isAsync) override; + +private: + explicit JsInsightIntentEntry(JsRuntime& runtime); + + static std::unique_ptr LoadJsCode( + const InsightIntentExecutorInfo& insightIntentInfo, + JsRuntime& runtime); + + bool CallJsFunctionWithResultInner( + const char* funcName, + size_t argc, + const napi_value* argv, + napi_value& result + ); + + void ReplyFailedInner(InsightIntentInnerErr innerErr = InsightIntentInnerErr::INSIGHT_INTENT_EXECUTE_REPLY_FAILED); + + void ReplySucceededInner(std::shared_ptr resultCpp); + + bool HandleResultReturnedFromJsFunc(napi_value resultJs); + + bool ExecuteIntentCheckError(); + + bool ExecuteInsightIntent( + const std::string& name, + const AAFwk::WantParams& param, + const std::shared_ptr& pageLoader); + + bool PrepareParameters(InsightIntentExecuteMode mode, const std::shared_ptr& pageLoader); + bool PrepareParametersUIAbilityForeground(napi_env env, const std::shared_ptr& pageLoader); + bool PrepareParametersUIAbilityBackground(napi_env env); + bool PrepareParametersUIExtension(napi_env env, const std::shared_ptr& pageLoader); + bool PrepareParametersServiceExtension(napi_env env); + + bool AssignObject(napi_env env, const AAFwk::WantParams &wantParams); + + JsRuntime& runtime_; + State state_ = State::CREATED; + std::unique_ptr jsObj_ = nullptr; + std::unique_ptr contextObj_ = nullptr; + std::unique_ptr callback_; + bool isAsync_ = false; +}; +} // namespace AbilityRuntime +} // namespace OHOS +#endif // OHOS_ABILITY_RUNTIME_JS_INSIGHT_INTENT_ENTRY_H diff --git a/test/unittest/insight_intent/js_insight_intent_entry_test/BUILD.gn b/test/unittest/insight_intent/js_insight_intent_entry_test/BUILD.gn new file mode 100644 index 0000000000..763432724e --- /dev/null +++ b/test/unittest/insight_intent/js_insight_intent_entry_test/BUILD.gn @@ -0,0 +1,61 @@ +# 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("//build/test.gni") +import("//foundation/ability/ability_runtime/ability_runtime.gni") + +ohos_unittest("js_insight_intent_entry_test") { + module_out_path = "ability_runtime/ability_runtime/insight_intent" + + cflags_cc = [] + + include_dirs = [] + + sources = [ "js_insight_intent_entry_test.cpp" ] + + configs = [ "${ability_runtime_services_path}/abilitymgr:abilityms_config" ] + + cflags = [] + if (target_cpu == "arm") { + cflags += [ "-DBINDER_IPC_32BIT" ] + } + + deps = [ + "${ability_runtime_innerkits_path}/runtime:runtime", + "${ability_runtime_native_path}/ability/native:insight_intent_executor", + "${ability_runtime_native_path}/insight_intent/insight_intent_context:insightintentcontext", + "${ability_runtime_path}/js_environment/frameworks/js_environment:js_environment", + ] + + external_deps = [ + "ability_base:base", + "ability_base:want", + "ability_base:zuri", + "ability_runtime:ability_deps_wrapper", + "ability_runtime:ability_manager", + "bundle_framework:libappexecfwk_common", + "c_utils:utils", + "ffrt:libffrt", + "googletest:gmock_main", + "googletest:gtest_main", + "hilog:libhilog", + "ipc:ipc_core", + "napi:ace_napi", + ] +} + +group("unittest") { + testonly = true + deps = [ ":js_insight_intent_entry_test" ] +} diff --git a/test/unittest/insight_intent/js_insight_intent_entry_test/js_insight_intent_entry_test.cpp b/test/unittest/insight_intent/js_insight_intent_entry_test/js_insight_intent_entry_test.cpp new file mode 100644 index 0000000000..587d785b58 --- /dev/null +++ b/test/unittest/insight_intent/js_insight_intent_entry_test/js_insight_intent_entry_test.cpp @@ -0,0 +1,148 @@ +/* + * 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 + +#include "ability_transaction_callback_info.h" +#include "hilog_tag_wrapper.h" +#include "insight_intent_executor.h" +#include "js_insight_intent_entry.h" +#include "js_insight_intent_utils.h" +#include "js_runtime.h" +#include "want_params.h" +#include "string_wrapper.h" + +using namespace testing; +using namespace testing::ext; + +namespace OHOS { +namespace AbilityRuntime { +class JsInsightIntentEntryTest : public testing::Test { +public: + static void SetUpTestCase(); + static void TearDownTestCase(); + void SetUp() override; + void TearDown() override; +}; + +static std::unique_ptr runtime_; + +void JsInsightIntentEntryTest::SetUpTestCase(void) +{ + std::shared_ptr jsEnv = nullptr; + AbilityRuntime::Runtime::Options options; + runtime_ = JsRuntime::Create(options); +} + +void JsInsightIntentEntryTest::TearDownTestCase(void) +{} + +void JsInsightIntentEntryTest::SetUp() +{} + +void JsInsightIntentEntryTest::TearDown() +{} + +/** + * @tc.name: CreateAndInit_0100 + * @tc.desc: basic function test of Create and Init. + * @tc.type: FUNC + * @tc.require: issueIC77WL + */ +HWTEST_F(JsInsightIntentEntryTest, CreateAndInit_0100, TestSize.Level1) +{ + TAG_LOGI(AAFwkTag::TEST, "testcase begin"); + ASSERT_NE(runtime_, nullptr); + + std::shared_ptr executor = JsInsightIntentEntry::Create(*runtime_); + ASSERT_NE(executor, nullptr); + + InsightIntentExecutorInfo info; + auto ret = executor->Init(info); + EXPECT_EQ(ret, false); + TAG_LOGI(AAFwkTag::TEST, "testcase end"); +} + +/** + * @tc.name: HandleExecuteIntent_0100 + * @tc.desc: basic function test of HandleExecuteIntent. + * @tc.type: FUNC + * @tc.require: issueIC77WL + */ +HWTEST_F(JsInsightIntentEntryTest, HandleExecuteIntent_0100, TestSize.Level1) +{ + TAG_LOGI(AAFwkTag::TEST, "testcase begin"); + ASSERT_NE(runtime_, nullptr); + + std::shared_ptr executor = JsInsightIntentEntry::Create(*runtime_); + ASSERT_NE(executor, nullptr); + + InsightIntentExecutorInfo info; + auto ret = executor->Init(info); + EXPECT_EQ(ret, false); + + auto executeParam = std::make_shared(); + executeParam->insightIntentParam_ = std::make_shared(); + auto callback = std::make_unique(); + auto asyncCallback = [](AppExecFwk::InsightIntentExecuteResult result) { + TAG_LOGD(AAFwkTag::INTENT, "execute insightIntent finished"); + }; + callback->Push(asyncCallback); + bool isAsync = false; + ret = executor->HandleExecuteIntent(executeParam, nullptr, std::move(callback), isAsync); + EXPECT_EQ(ret, false); + EXPECT_EQ(isAsync, false); + TAG_LOGI(AAFwkTag::TEST, "testcase end"); +} + +/** + * @tc.name: HandleExecuteIntent_0200 + * @tc.desc: basic function test of HandleExecuteIntent. + * @tc.type: FUNC + * @tc.require: issueIC77WL + */ +HWTEST_F(JsInsightIntentEntryTest, HandleExecuteIntent_0200, TestSize.Level1) +{ + TAG_LOGI(AAFwkTag::TEST, "testcase begin"); + ASSERT_NE(runtime_, nullptr); + + std::shared_ptr executor = JsInsightIntentEntry::Create(*runtime_); + ASSERT_NE(executor, nullptr); + + InsightIntentExecutorInfo info; + auto ret = executor->Init(info); + EXPECT_EQ(ret, false); + + auto wantParams = std::make_shared(); + wantParams->SetParam("key1", AAFwk::String::Box("value1")); + wantParams->SetParam("key2", AAFwk::String::Box("value2")); + auto executeParam = std::make_shared(); + executeParam->insightIntentParam_ = wantParams; + executeParam->insightIntentName_ = "intentName"; + executeParam->srcEntrance_ = "srcEntrance"; + executeParam->executeMode_ = 1; + auto callback = std::make_unique(); + auto asyncCallback = [](AppExecFwk::InsightIntentExecuteResult result) { + TAG_LOGD(AAFwkTag::INTENT, "execute insightIntent finished"); + }; + callback->Push(asyncCallback); + bool isAsync = false; + ret = executor->HandleExecuteIntent(executeParam, nullptr, std::move(callback), isAsync); + EXPECT_EQ(ret, false); + EXPECT_EQ(isAsync, false); + TAG_LOGI(AAFwkTag::TEST, "testcase end"); +} +} // namespace AbilityRuntime +} // namespace OHOS