From 20520df4c9e5ea243ed664bd310743f7d4bf8282 Mon Sep 17 00:00:00 2001 From: yangxuguang-huawei Date: Mon, 30 Mar 2026 10:15:10 +0800 Subject: [PATCH] feat: register/update/delete AgentCard part 3 Co-Authored-By: Agent Signed-off-by: yangxuguang-huawei --- .../frameworks/js/napi/BUILD.gn | 1 + .../js/napi/agent_constant/BUILD.gn | 44 +++ .../agent_constant/agent_constant_module.cpp | 76 ++++ .../agent_manager/include/js_agent_manager.h | 12 + .../include/js_agent_manager_utils.h | 6 + .../agent_manager/src/js_agent_manager.cpp | 127 ++++++ .../src/js_agent_manager_utils.cpp | 368 ++++++++++++++++++ .../ability_business_error.cpp | 12 + .../ability_business_error.h | 9 + .../ability_business_error_test.cpp | 6 + 10 files changed, 661 insertions(+) create mode 100644 agent_runtime_framework/frameworks/js/napi/agent_constant/BUILD.gn create mode 100644 agent_runtime_framework/frameworks/js/napi/agent_constant/agent_constant_module.cpp diff --git a/agent_runtime_framework/frameworks/js/napi/BUILD.gn b/agent_runtime_framework/frameworks/js/napi/BUILD.gn index 1bcd89d75e..f94060e888 100644 --- a/agent_runtime_framework/frameworks/js/napi/BUILD.gn +++ b/agent_runtime_framework/frameworks/js/napi/BUILD.gn @@ -16,6 +16,7 @@ import("//foundation/ability/ability_runtime/ability_runtime.gni") group("agent_runtime_napi_packages") { deps = [ + "${agent_runtime_framework_path}/frameworks/js/napi/agent_constant:agentconstant_napi", "${agent_runtime_framework_path}/frameworks/js/napi/agent_extension_ability:agentextensionability", "${agent_runtime_framework_path}/frameworks/js/napi/agent_extension_ability:js_agent_extension", "${agent_runtime_framework_path}/frameworks/js/napi/agent_extension_context:agentextensioncontext_napi", diff --git a/agent_runtime_framework/frameworks/js/napi/agent_constant/BUILD.gn b/agent_runtime_framework/frameworks/js/napi/agent_constant/BUILD.gn new file mode 100644 index 0000000000..beeb3680cd --- /dev/null +++ b/agent_runtime_framework/frameworks/js/napi/agent_constant/BUILD.gn @@ -0,0 +1,44 @@ +# 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. + +import("//build/ohos.gni") +import("//foundation/ability/ability_runtime/ability_runtime.gni") + +ohos_shared_library("agentconstant_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" + + include_dirs = [ "${agent_runtime_framework_path}/interfaces/inner_api/include" ] + + sources = [ "agent_constant_module.cpp" ] + + deps = [ "${agent_runtime_framework_path}/interfaces/inner_api:agent_fwk" ] + + external_deps = [ + "c_utils:utils", + "json:nlohmann_json_static", + "napi:ace_napi", + ] + + relative_install_dir = "module/app/agent" + subsystem_name = "ability" + part_name = "ability_runtime" +} diff --git a/agent_runtime_framework/frameworks/js/napi/agent_constant/agent_constant_module.cpp b/agent_runtime_framework/frameworks/js/napi/agent_constant/agent_constant_module.cpp new file mode 100644 index 0000000000..dd7386648a --- /dev/null +++ b/agent_runtime_framework/frameworks/js/napi/agent_constant/agent_constant_module.cpp @@ -0,0 +1,76 @@ +/* + * 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 "agent_card.h" +#include "napi/native_api.h" +#include "napi/native_common.h" + +namespace OHOS { +namespace AgentRuntime { +namespace { +static napi_status SetEnumItem(napi_env env, napi_value object, const char *name, int32_t value) +{ + napi_status status; + napi_value itemName = nullptr; + napi_value itemValue = nullptr; + + NAPI_CALL_BASE(env, status = napi_create_string_utf8(env, name, NAPI_AUTO_LENGTH, &itemName), status); + NAPI_CALL_BASE(env, status = napi_create_int32(env, value, &itemValue), status); + NAPI_CALL_BASE(env, status = napi_set_property(env, object, itemName, itemValue), status); + NAPI_CALL_BASE(env, status = napi_set_property(env, object, itemValue, itemName), status); + return napi_ok; +} + +static napi_value InitAgentCardTypeObject(napi_env env) +{ + napi_value object = nullptr; + NAPI_CALL(env, napi_create_object(env, &object)); + NAPI_CALL(env, SetEnumItem(env, object, "APP", static_cast(AgentCardType::APP))); + NAPI_CALL(env, SetEnumItem(env, object, "LOW_CODE", static_cast(AgentCardType::LOW_CODE))); + NAPI_CALL(env, SetEnumItem(env, object, "ATOMIC_SERVICE", static_cast(AgentCardType::ATOMIC_SERVICE))); + return object; +} +} + +static napi_value AgentConstantInit(napi_env env, napi_value exports) +{ + napi_value agentCardType = InitAgentCardTypeObject(env); + NAPI_ASSERT(env, agentCardType != nullptr, "failed to create AgentCardType object"); + + napi_property_descriptor exportObjs[] = { + DECLARE_NAPI_PROPERTY("AgentCardType", agentCardType), + }; + + napi_status status = napi_define_properties(env, exports, sizeof(exportObjs) / sizeof(exportObjs[0]), exportObjs); + NAPI_ASSERT(env, status == napi_ok, "failed to define properties for exports"); + return exports; +} + +static napi_module _module = { + .nm_version = 1, + .nm_flags = 0, + .nm_filename = nullptr, + .nm_register_func = AgentConstantInit, + .nm_modname = "app.agent.agentConstant", + .nm_priv = (static_cast(0)), + .reserved = {0} +}; + +extern "C" __attribute__((constructor)) void RegisterModule(void) +{ + napi_module_register(&_module); +} +} // namespace AgentRuntime +} // namespace OHOS diff --git a/agent_runtime_framework/frameworks/js/napi/agent_manager/include/js_agent_manager.h b/agent_runtime_framework/frameworks/js/napi/agent_manager/include/js_agent_manager.h index b29265cb9e..f5dff4616c 100644 --- a/agent_runtime_framework/frameworks/js/napi/agent_manager/include/js_agent_manager.h +++ b/agent_runtime_framework/frameworks/js/napi/agent_manager/include/js_agent_manager.h @@ -79,6 +79,12 @@ public: */ static napi_value GetAgentCardByAgentId(napi_env env, napi_callback_info info); + static napi_value RegisterAgentCard(napi_env env, napi_callback_info info); + + static napi_value UpdateAgentCard(napi_env env, napi_callback_info info); + + static napi_value DeleteAgentCard(napi_env env, napi_callback_info info); + /** * @brief Native method for connecting to an agent extension. * @@ -128,6 +134,12 @@ private: */ napi_value OnGetAgentCardByAgentId(napi_env env, size_t argc, napi_value *argv); + napi_value OnRegisterAgentCard(napi_env env, size_t argc, napi_value *argv); + + napi_value OnUpdateAgentCard(napi_env env, size_t argc, napi_value *argv); + + napi_value OnDeleteAgentCard(napi_env env, size_t argc, napi_value *argv); + /** * @brief Implementation for connecting to an agent extension. * diff --git a/agent_runtime_framework/frameworks/js/napi/agent_manager/include/js_agent_manager_utils.h b/agent_runtime_framework/frameworks/js/napi/agent_manager/include/js_agent_manager_utils.h index 86583ade88..7e38b0b507 100644 --- a/agent_runtime_framework/frameworks/js/napi/agent_manager/include/js_agent_manager_utils.h +++ b/agent_runtime_framework/frameworks/js/napi/agent_manager/include/js_agent_manager_utils.h @@ -30,6 +30,12 @@ JS_AGENT_MANAGER_UTILS_EXPORT napi_value CreateJsAgentSkillArray( napi_env env, const std::vector> &skills); JS_AGENT_MANAGER_UTILS_EXPORT napi_value CreateJsAgentCard(napi_env env, const AgentCard &card); JS_AGENT_MANAGER_UTILS_EXPORT napi_value CreateJsAgentCardArray(napi_env env, const std::vector &cards); +JS_AGENT_MANAGER_UTILS_EXPORT bool ParseJsAgentProvider(napi_env env, napi_value value, AgentProvider &provider); +JS_AGENT_MANAGER_UTILS_EXPORT bool ParseJsAgentCapabilities( + napi_env env, napi_value value, AgentCapabilities &capabilities); +JS_AGENT_MANAGER_UTILS_EXPORT bool ParseJsAgentSkill(napi_env env, napi_value value, AgentSkill &skill); +JS_AGENT_MANAGER_UTILS_EXPORT bool ParseJsAgentAppInfo(napi_env env, napi_value value, AgentAppInfo &appInfo); +JS_AGENT_MANAGER_UTILS_EXPORT bool ParseJsAgentCard(napi_env env, napi_value value, AgentCard &card); } // namespace AgentRuntime } // namespace OHOS #endif // OHOS_AGENT_RUNTIME_JS_AGENT_MANAGER_UTILS_H diff --git a/agent_runtime_framework/frameworks/js/napi/agent_manager/src/js_agent_manager.cpp b/agent_runtime_framework/frameworks/js/napi/agent_manager/src/js_agent_manager.cpp index 606f5b8c95..92ca841ad3 100644 --- a/agent_runtime_framework/frameworks/js/napi/agent_manager/src/js_agent_manager.cpp +++ b/agent_runtime_framework/frameworks/js/napi/agent_manager/src/js_agent_manager.cpp @@ -123,6 +123,21 @@ napi_value JsAgentManager::GetAgentCardByAgentId(napi_env env, napi_callback_inf GET_CB_INFO_AND_CALL(env, info, JsAgentManager, OnGetAgentCardByAgentId); } +napi_value JsAgentManager::RegisterAgentCard(napi_env env, napi_callback_info info) +{ + GET_CB_INFO_AND_CALL(env, info, JsAgentManager, OnRegisterAgentCard); +} + +napi_value JsAgentManager::UpdateAgentCard(napi_env env, napi_callback_info info) +{ + GET_CB_INFO_AND_CALL(env, info, JsAgentManager, OnUpdateAgentCard); +} + +napi_value JsAgentManager::DeleteAgentCard(napi_env env, napi_callback_info info) +{ + GET_CB_INFO_AND_CALL(env, info, JsAgentManager, OnDeleteAgentCard); +} + napi_value JsAgentManager::ConnectAgentExtensionAbility(napi_env env, napi_callback_info info) { GET_CB_INFO_AND_CALL(env, info, JsAgentManager, OnConnectAgentExtensionAbility); @@ -234,6 +249,115 @@ napi_value JsAgentManager::OnGetAgentCardByAgentId(napi_env env, size_t argc, na return result; } +napi_value JsAgentManager::OnRegisterAgentCard(napi_env env, size_t argc, napi_value *argv) +{ + if (argc < ARGC_ONE) { + ThrowTooFewParametersError(env); + return CreateJsUndefined(env); + } + + auto card = std::make_shared(); + if (!ParseJsAgentCard(env, argv[ARG_INDEX_0], *card)) { + TAG_LOGE(AAFwkTag::SER_ROUTER, "parse card failed"); + ThrowInvalidParamError(env, "Parse param card failed."); + return CreateJsUndefined(env); + } + + auto innerErrorCode = std::make_shared(ERR_OK); + NapiAsyncTask::ExecuteCallback execute = [card, innerErrorCode]() { + *innerErrorCode = AgentManagerClient::GetInstance().RegisterAgentCard(*card); + }; + + NapiAsyncTask::CompleteCallback complete = [innerErrorCode](napi_env env, NapiAsyncTask &task, int32_t status) { + if (*innerErrorCode != ERR_OK) { + TAG_LOGE(AAFwkTag::SER_ROUTER, "error: %{public}d", *innerErrorCode); + task.Reject(env, CreateJsErrorByNativeErr(env, *innerErrorCode)); + return; + } + task.ResolveWithNoError(env, CreateJsUndefined(env)); + }; + + napi_value result = nullptr; + NapiAsyncTask::Schedule("JsAgentManager::OnRegisterAgentCard", env, + CreateAsyncTaskWithLastParam(env, nullptr, std::move(execute), std::move(complete), &result)); + return result; +} + +napi_value JsAgentManager::OnUpdateAgentCard(napi_env env, size_t argc, napi_value *argv) +{ + if (argc < ARGC_ONE) { + ThrowTooFewParametersError(env); + return CreateJsUndefined(env); + } + + auto card = std::make_shared(); + if (!ParseJsAgentCard(env, argv[ARG_INDEX_0], *card)) { + TAG_LOGE(AAFwkTag::SER_ROUTER, "parse card failed"); + ThrowInvalidParamError(env, "Parse param card failed."); + return CreateJsUndefined(env); + } + + auto innerErrorCode = std::make_shared(ERR_OK); + NapiAsyncTask::ExecuteCallback execute = [card, innerErrorCode]() { + *innerErrorCode = AgentManagerClient::GetInstance().UpdateAgentCard(*card); + }; + + NapiAsyncTask::CompleteCallback complete = [innerErrorCode](napi_env env, NapiAsyncTask &task, int32_t status) { + if (*innerErrorCode != ERR_OK) { + TAG_LOGE(AAFwkTag::SER_ROUTER, "error: %{public}d", *innerErrorCode); + task.Reject(env, CreateJsErrorByNativeErr(env, *innerErrorCode)); + return; + } + task.ResolveWithNoError(env, CreateJsUndefined(env)); + }; + + napi_value result = nullptr; + NapiAsyncTask::Schedule("JsAgentManager::OnUpdateAgentCard", env, + CreateAsyncTaskWithLastParam(env, nullptr, std::move(execute), std::move(complete), &result)); + return result; +} + +napi_value JsAgentManager::OnDeleteAgentCard(napi_env env, size_t argc, napi_value *argv) +{ + if (argc < ARGC_TWO) { + ThrowTooFewParametersError(env); + return CreateJsUndefined(env); + } + + std::string bundleName; + if (!ConvertFromJsValue(env, argv[ARG_INDEX_0], bundleName)) { + TAG_LOGE(AAFwkTag::SER_ROUTER, "bundleName not string"); + ThrowInvalidParamError(env, "Parse param bundleName failed, must be a string."); + return CreateJsUndefined(env); + } + + std::string agentId; + if (!ConvertFromJsValue(env, argv[ARG_INDEX_1], agentId)) { + TAG_LOGE(AAFwkTag::SER_ROUTER, "agentId not string"); + ThrowInvalidParamError(env, "Parse param agentId failed, must be a string."); + return CreateJsUndefined(env); + } + + auto innerErrorCode = std::make_shared(ERR_OK); + NapiAsyncTask::ExecuteCallback execute = [bundleName, agentId, innerErrorCode]() { + *innerErrorCode = AgentManagerClient::GetInstance().DeleteAgentCard(bundleName, agentId); + }; + + NapiAsyncTask::CompleteCallback complete = [innerErrorCode](napi_env env, NapiAsyncTask &task, int32_t status) { + if (*innerErrorCode != ERR_OK) { + TAG_LOGE(AAFwkTag::SER_ROUTER, "error: %{public}d", *innerErrorCode); + task.Reject(env, CreateJsErrorByNativeErr(env, *innerErrorCode)); + return; + } + task.ResolveWithNoError(env, CreateJsUndefined(env)); + }; + + napi_value result = nullptr; + NapiAsyncTask::Schedule("JsAgentManager::OnDeleteAgentCard", env, + CreateAsyncTaskWithLastParam(env, nullptr, std::move(execute), std::move(complete), &result)); + return result; +} + napi_value JsAgentManager::OnConnectAgentExtensionAbility(napi_env env, size_t argc, napi_value *argv) { // 1. Validate parameters and extract want, agentId, callback @@ -441,6 +565,9 @@ napi_value JsAgentManagerInit(napi_env env, napi_value exportObj) BindNativeFunction(env, exportObj, "getAgentCardsByBundleName", moduleName, JsAgentManager::GetAgentCardsByBundleName); BindNativeFunction(env, exportObj, "getAgentCardByAgentId", moduleName, JsAgentManager::GetAgentCardByAgentId); + BindNativeFunction(env, exportObj, "registerAgentCard", moduleName, JsAgentManager::RegisterAgentCard); + BindNativeFunction(env, exportObj, "updateAgentCard", moduleName, JsAgentManager::UpdateAgentCard); + BindNativeFunction(env, exportObj, "deleteAgentCard", moduleName, JsAgentManager::DeleteAgentCard); BindNativeFunction(env, exportObj, "connectAgentExtensionAbility", moduleName, JsAgentManager::ConnectAgentExtensionAbility); BindNativeFunction(env, exportObj, "disconnectAgentExtensionAbility", moduleName, diff --git a/agent_runtime_framework/frameworks/js/napi/agent_manager/src/js_agent_manager_utils.cpp b/agent_runtime_framework/frameworks/js/napi/agent_manager/src/js_agent_manager_utils.cpp index b01fd5fe0b..554041de12 100644 --- a/agent_runtime_framework/frameworks/js/napi/agent_manager/src/js_agent_manager_utils.cpp +++ b/agent_runtime_framework/frameworks/js/napi/agent_manager/src/js_agent_manager_utils.cpp @@ -16,6 +16,7 @@ #include "js_agent_manager_utils.h" #include +#include #include "hilog_tag_wrapper.h" #include "js_runtime_utils.h" @@ -24,6 +25,139 @@ using namespace OHOS::AbilityRuntime; namespace OHOS { namespace AgentRuntime { +namespace { +bool IsValidAgentCardTypeValue(int32_t type) +{ + return type >= static_cast(AgentCardType::APP) && + type <= static_cast(AgentCardType::ATOMIC_SERVICE); +} + +bool IsObject(napi_env env, napi_value value) +{ + if (value == nullptr) { + TAG_LOGE(AAFwkTag::SER_ROUTER, "null value"); + return false; + } + napi_valuetype type = napi_undefined; + if (napi_typeof(env, value, &type) != napi_ok) { + TAG_LOGE(AAFwkTag::SER_ROUTER, "typeof failed"); + return false; + } + if (type != napi_object) { + TAG_LOGE(AAFwkTag::SER_ROUTER, "not object"); + return false; + } + return true; +} + +bool GetNamedProperty(napi_env env, napi_value object, const char *name, napi_value &value) +{ + bool hasProperty = false; + if (napi_has_named_property(env, object, name, &hasProperty) != napi_ok) { + TAG_LOGE(AAFwkTag::SER_ROUTER, "has %{public}s failed", name); + return false; + } + if (!hasProperty) { + TAG_LOGE(AAFwkTag::SER_ROUTER, "missing %{public}s", name); + return false; + } + if (napi_get_named_property(env, object, name, &value) != napi_ok) { + TAG_LOGE(AAFwkTag::SER_ROUTER, "get %{public}s failed", name); + return false; + } + if (value == nullptr) { + TAG_LOGE(AAFwkTag::SER_ROUTER, "%{public}s is null", name); + return false; + } + return true; +} + +bool ParseRequiredStringProperty(napi_env env, napi_value object, const char *name, std::string &value) +{ + napi_value property = nullptr; + if (!GetNamedProperty(env, object, name, property)) { + TAG_LOGE(AAFwkTag::SER_ROUTER, "get %{public}s failed", name); + return false; + } + if (!ConvertFromJsValue(env, property, value)) { + TAG_LOGE(AAFwkTag::SER_ROUTER, "bad %{public}s", name); + return false; + } + if (value.empty()) { + TAG_LOGE(AAFwkTag::SER_ROUTER, "empty %{public}s", name); + return false; + } + return true; +} + +bool ParseOptionalStringProperty(napi_env env, napi_value object, const char *name, std::string &value) +{ + napi_value property = nullptr; + if (!GetNamedProperty(env, object, name, property)) { + return true; + } + if (!ConvertFromJsValue(env, property, value)) { + TAG_LOGE(AAFwkTag::SER_ROUTER, "bad %{public}s", name); + return false; + } + return true; +} + +bool ParseOptionalBoolProperty(napi_env env, napi_value object, const char *name, bool &value) +{ + napi_value property = nullptr; + if (!GetNamedProperty(env, object, name, property)) { + return true; + } + if (!ConvertFromJsValue(env, property, value)) { + TAG_LOGE(AAFwkTag::SER_ROUTER, "bad %{public}s", name); + return false; + } + return true; +} + +bool ParseOptionalInt32Property(napi_env env, napi_value object, const char *name, int32_t &value) +{ + napi_value property = nullptr; + if (!GetNamedProperty(env, object, name, property)) { + return true; + } + if (!ConvertFromJsValue(env, property, value)) { + TAG_LOGE(AAFwkTag::SER_ROUTER, "bad %{public}s", name); + return false; + } + return true; +} + +bool ParseStringArray(napi_env env, napi_value value, std::vector &out) +{ + bool isArray = false; + if (napi_is_array(env, value, &isArray) != napi_ok || !isArray) { + TAG_LOGE(AAFwkTag::SER_ROUTER, "not array"); + return false; + } + uint32_t length = 0; + if (napi_get_array_length(env, value, &length) != napi_ok) { + TAG_LOGE(AAFwkTag::SER_ROUTER, "get length failed"); + return false; + } + for (uint32_t i = 0; i < length; ++i) { + napi_value element = nullptr; + if (napi_get_element(env, value, i, &element) != napi_ok) { + TAG_LOGE(AAFwkTag::SER_ROUTER, "get item %{public}u failed", i); + return false; + } + std::string item; + if (!ConvertFromJsValue(env, element, item) || item.empty()) { + TAG_LOGE(AAFwkTag::SER_ROUTER, "bad item %{public}u", i); + return false; + } + out.emplace_back(item); + } + return true; +} +} // namespace + napi_value CreateJsAgentProvider(napi_env env, const AgentProvider &provider) { TAG_LOGD(AAFwkTag::SER_ROUTER, "create provider"); @@ -141,6 +275,7 @@ napi_value CreateJsAgentCard(napi_env env, const AgentCard &card) return nullptr; } napi_set_named_property(env, object, "agentId", CreateJsValue(env, card.agentId)); + napi_set_named_property(env, object, "type", CreateJsValue(env, static_cast(card.type))); napi_set_named_property(env, object, "name", CreateJsValue(env, card.name)); napi_set_named_property(env, object, "description", CreateJsValue(env, card.description)); napi_set_named_property(env, object, "version", CreateJsValue(env, card.version)); @@ -189,5 +324,238 @@ napi_value CreateJsAgentCardArray(napi_env env, const std::vector &ca TAG_LOGD(AAFwkTag::SER_ROUTER, "end"); return object; } + +bool ParseJsAgentProvider(napi_env env, napi_value value, AgentProvider &provider) +{ + if (!IsObject(env, value)) { + TAG_LOGE(AAFwkTag::SER_ROUTER, "provider not object"); + return false; + } + if (!ParseRequiredStringProperty(env, value, "organization", provider.organization)) { + TAG_LOGE(AAFwkTag::SER_ROUTER, "bad provider.organization"); + return false; + } + if (!ParseRequiredStringProperty(env, value, "url", provider.url)) { + TAG_LOGE(AAFwkTag::SER_ROUTER, "bad provider.url"); + return false; + } + return true; +} + +bool ParseJsAgentCapabilities(napi_env env, napi_value value, AgentCapabilities &capabilities) +{ + if (!IsObject(env, value)) { + TAG_LOGE(AAFwkTag::SER_ROUTER, "capabilities not object"); + return false; + } + if (!ParseOptionalBoolProperty(env, value, "streaming", capabilities.streaming)) { + TAG_LOGE(AAFwkTag::SER_ROUTER, "bad capabilities.streaming"); + return false; + } + if (!ParseOptionalBoolProperty(env, value, "pushNotifications", capabilities.pushNotifications)) { + TAG_LOGE(AAFwkTag::SER_ROUTER, "bad capabilities.pushNotifications"); + return false; + } + if (!ParseOptionalBoolProperty(env, value, "stateTransitionHistory", capabilities.stateTransitionHistory)) { + TAG_LOGE(AAFwkTag::SER_ROUTER, "bad capabilities.stateTransitionHistory"); + return false; + } + if (!ParseOptionalBoolProperty(env, value, "extendedAgentCard", capabilities.extendedAgentCard)) { + TAG_LOGE(AAFwkTag::SER_ROUTER, "bad capabilities.extendedAgentCard"); + return false; + } + if (!ParseOptionalStringProperty(env, value, "extension", capabilities.extension)) { + TAG_LOGE(AAFwkTag::SER_ROUTER, "bad capabilities.extension"); + return false; + } + return true; +} + +bool ParseJsAgentSkill(napi_env env, napi_value value, AgentSkill &skill) +{ + if (!IsObject(env, value)) { + TAG_LOGE(AAFwkTag::SER_ROUTER, "skill not object"); + return false; + } + + napi_value property = nullptr; + if (!ParseRequiredStringProperty(env, value, "id", skill.id)) { + TAG_LOGE(AAFwkTag::SER_ROUTER, "bad skill.id"); + return false; + } + if (!ParseRequiredStringProperty(env, value, "name", skill.name)) { + TAG_LOGE(AAFwkTag::SER_ROUTER, "bad skill.name"); + return false; + } + if (!ParseRequiredStringProperty(env, value, "description", skill.description)) { + TAG_LOGE(AAFwkTag::SER_ROUTER, "bad skill.description"); + return false; + } + if (!GetNamedProperty(env, value, "tags", property) || !ParseStringArray(env, property, skill.tags)) { + TAG_LOGE(AAFwkTag::SER_ROUTER, "bad skill.tags"); + return false; + } + if (GetNamedProperty(env, value, "examples", property) && !ParseStringArray(env, property, skill.examples)) { + TAG_LOGE(AAFwkTag::SER_ROUTER, "bad skill.examples"); + return false; + } + if (GetNamedProperty(env, value, "inputModes", property) && !ParseStringArray(env, property, skill.inputModes)) { + TAG_LOGE(AAFwkTag::SER_ROUTER, "bad skill.inputModes"); + return false; + } + if (GetNamedProperty(env, value, "outputModes", property) && + !ParseStringArray(env, property, skill.outputModes)) { + TAG_LOGE(AAFwkTag::SER_ROUTER, "bad skill.outputModes"); + return false; + } + if (!ParseOptionalStringProperty(env, value, "extension", skill.extension)) { + TAG_LOGE(AAFwkTag::SER_ROUTER, "bad skill.extension"); + return false; + } + return true; +} + +bool ParseJsAgentAppInfo(napi_env env, napi_value value, AgentAppInfo &appInfo) +{ + if (!IsObject(env, value)) { + TAG_LOGE(AAFwkTag::SER_ROUTER, "appInfo not object"); + return false; + } + + napi_value property = nullptr; + if (!ParseRequiredStringProperty(env, value, "bundleName", appInfo.bundleName)) { + TAG_LOGE(AAFwkTag::SER_ROUTER, "bad appInfo.bundleName"); + return false; + } + if (!ParseRequiredStringProperty(env, value, "abilityName", appInfo.abilityName)) { + TAG_LOGE(AAFwkTag::SER_ROUTER, "bad appInfo.abilityName"); + return false; + } + if (!ParseOptionalStringProperty(env, value, "moduleName", appInfo.moduleName)) { + TAG_LOGE(AAFwkTag::SER_ROUTER, "bad appInfo.moduleName"); + return false; + } + if (!ParseOptionalStringProperty(env, value, "minAppVersion", appInfo.minAppVersion)) { + TAG_LOGE(AAFwkTag::SER_ROUTER, "bad appInfo.minAppVersion"); + return false; + } + if (GetNamedProperty(env, value, "deviceTypes", property) && + !ParseStringArray(env, property, appInfo.deviceTypes)) { + TAG_LOGE(AAFwkTag::SER_ROUTER, "bad appInfo.deviceTypes"); + return false; + } + return true; +} + +bool ParseJsAgentCard(napi_env env, napi_value value, AgentCard &card) +{ + if (!IsObject(env, value)) { + TAG_LOGE(AAFwkTag::SER_ROUTER, "card not object"); + return false; + } + + napi_value property = nullptr; + if (!ParseRequiredStringProperty(env, value, "agentId", card.agentId)) { + TAG_LOGE(AAFwkTag::SER_ROUTER, "bad card.agentId"); + return false; + } + if (!ParseRequiredStringProperty(env, value, "name", card.name)) { + TAG_LOGE(AAFwkTag::SER_ROUTER, "bad card.name"); + return false; + } + if (!ParseRequiredStringProperty(env, value, "description", card.description)) { + TAG_LOGE(AAFwkTag::SER_ROUTER, "bad card.description"); + return false; + } + if (!ParseRequiredStringProperty(env, value, "version", card.version)) { + TAG_LOGE(AAFwkTag::SER_ROUTER, "bad card.version"); + return false; + } + if (!ParseRequiredStringProperty(env, value, "category", card.category)) { + TAG_LOGE(AAFwkTag::SER_ROUTER, "bad card.category"); + return false; + } + int32_t typeValue = static_cast(AgentCardType::APP); + if (!ParseOptionalInt32Property(env, value, "type", typeValue)) { + TAG_LOGE(AAFwkTag::SER_ROUTER, "bad card.type"); + return false; + } + if (!IsValidAgentCardTypeValue(typeValue)) { + TAG_LOGE(AAFwkTag::SER_ROUTER, "invalid card.type %{public}d", typeValue); + return false; + } + card.type = static_cast(typeValue); + if (!GetNamedProperty(env, value, "defaultInputModes", property) || + !ParseStringArray(env, property, card.defaultInputModes)) { + TAG_LOGE(AAFwkTag::SER_ROUTER, "bad card.defaultInputModes"); + return false; + } + if (!GetNamedProperty(env, value, "defaultOutputModes", property) || + !ParseStringArray(env, property, card.defaultOutputModes)) { + TAG_LOGE(AAFwkTag::SER_ROUTER, "bad card.defaultOutputModes"); + return false; + } + if (!GetNamedProperty(env, value, "skills", property)) { + TAG_LOGE(AAFwkTag::SER_ROUTER, "missing card.skills"); + return false; + } + bool isArray = false; + if (napi_is_array(env, property, &isArray) != napi_ok || !isArray) { + TAG_LOGE(AAFwkTag::SER_ROUTER, "card.skills not array"); + return false; + } + uint32_t length = 0; + if (napi_get_array_length(env, property, &length) != napi_ok) { + TAG_LOGE(AAFwkTag::SER_ROUTER, "get card.skills length failed"); + return false; + } + for (uint32_t i = 0; i < length; ++i) { + napi_value skillValue = nullptr; + if (napi_get_element(env, property, i, &skillValue) != napi_ok) { + TAG_LOGE(AAFwkTag::SER_ROUTER, "get skill %{public}u failed", i); + return false; + } + auto skill = std::make_shared(); + if (!ParseJsAgentSkill(env, skillValue, *skill)) { + TAG_LOGE(AAFwkTag::SER_ROUTER, "bad skill %{public}u", i); + return false; + } + card.skills.emplace_back(skill); + } + + if (GetNamedProperty(env, value, "provider", property)) { + auto provider = std::make_shared(); + if (!ParseJsAgentProvider(env, property, *provider)) { + TAG_LOGE(AAFwkTag::SER_ROUTER, "bad card.provider"); + return false; + } + card.provider = provider; + } + if (GetNamedProperty(env, value, "capabilities", property)) { + auto capabilities = std::make_shared(); + if (!ParseJsAgentCapabilities(env, property, *capabilities)) { + TAG_LOGE(AAFwkTag::SER_ROUTER, "bad card.capabilities"); + return false; + } + card.capabilities = capabilities; + } + if (!ParseOptionalStringProperty(env, value, "documentationUrl", card.documentationUrl) || + !ParseOptionalStringProperty(env, value, "iconUrl", card.iconUrl) || + !ParseOptionalStringProperty(env, value, "extension", card.extension)) { + TAG_LOGE(AAFwkTag::SER_ROUTER, "bad card optional string"); + return false; + } + if (!GetNamedProperty(env, value, "appInfo", property)) { + TAG_LOGE(AAFwkTag::SER_ROUTER, "missing card.appInfo"); + return false; + } + auto appInfo = std::make_shared(); + if (!ParseJsAgentAppInfo(env, property, *appInfo)) { + TAG_LOGE(AAFwkTag::SER_ROUTER, "bad card.appInfo"); + return false; + } + card.appInfo = appInfo; + return true; +} } // namespace AgentRuntime } // namespace OHOS diff --git a/frameworks/native/ability/native/ability_business_error/ability_business_error.cpp b/frameworks/native/ability/native/ability_business_error/ability_business_error.cpp index c21aac9a7f..dc65f86525 100644 --- a/frameworks/native/ability/native/ability_business_error/ability_business_error.cpp +++ b/frameworks/native/ability/native/ability_business_error/ability_business_error.cpp @@ -113,6 +113,12 @@ constexpr const char* ERROR_MSG_CALLER_NOT_ATOMIC_SERVICE = "The caller is not an atomic service."; constexpr const char* ERROR_MSG_AGENT_ID_NOT_EXIST = "The specified agentId does not exist."; +constexpr const char* ERROR_MSG_AGENT_CARD_VERSION_TOO_OLD = + "The specified agent card version is older than the existing version."; +constexpr const char* ERROR_MSG_AGENT_CARD_VERSION_INVALID = + "The specified agent card version is invalid."; +constexpr const char* ERROR_MSG_AGENT_CARD_DUPLICATE_REGISTER = + "The specified agent card has already been registered. Use updateAgentCard instead."; constexpr const char* ERROR_MSG_MAX_CONNECTIONS_REACHED = "Maximum connections from the same caller have been reached. " "Please disconnect at least one agent extension beforehand."; @@ -241,6 +247,9 @@ static std::unordered_map ERR_CODE_MAP = { { AbilityErrorCode::ERROR_CODE_TARGET_NOT_STARTED, ERROR_TARGET_NOT_STARTED}, { AbilityErrorCode::ERROR_CODE_CALLER_NOT_ATOMIC_SERVICE, ERROR_MSG_CALLER_NOT_ATOMIC_SERVICE}, { AbilityErrorCode::ERROR_CODE_AGENT_ID_NOT_EXIST, ERROR_MSG_AGENT_ID_NOT_EXIST}, + { AbilityErrorCode::ERROR_CODE_AGENT_CARD_VERSION_TOO_OLD, ERROR_MSG_AGENT_CARD_VERSION_TOO_OLD}, + { AbilityErrorCode::ERROR_CODE_AGENT_CARD_VERSION_INVALID, ERROR_MSG_AGENT_CARD_VERSION_INVALID}, + { AbilityErrorCode::ERROR_CODE_AGENT_CARD_DUPLICATE_REGISTER, ERROR_MSG_AGENT_CARD_DUPLICATE_REGISTER}, { AbilityErrorCode::ERROR_CODE_MAX_CONNECTIONS_REACHED, ERROR_MSG_MAX_CONNECTIONS_REACHED }, { AbilityErrorCode::ERROR_CODE_NOT_UI_ABILITY_CONTEXT, ERROR_MSG_NOT_UI_ABILITY_CONTEXT}, { AbilityErrorCode::ERROR_CODE_INVALID_MAIN_ELEMENT_TYPE, ERROR_MSG_INVALID_MAIN_ELEMENT_TYPE}, @@ -357,6 +366,9 @@ static std::unordered_map INNER_TO_JS_ERROR_CODE_MAP {ERR_CALLER_NOT_ATOMIC_SERVICE, AbilityErrorCode::ERROR_CODE_CALLER_NOT_ATOMIC_SERVICE}, {ERR_INVALID_AGENT_CARD_ID, AbilityErrorCode::ERROR_CODE_AGENT_ID_NOT_EXIST}, {ERR_MAX_AGENT_CONNECTIONS_REACHED, AbilityErrorCode::ERROR_CODE_MAX_CONNECTIONS_REACHED}, + {ERR_AGENT_CARD_VERSION_TOO_OLD, AbilityErrorCode::ERROR_CODE_AGENT_CARD_VERSION_TOO_OLD}, + {ERR_INVALID_AGENT_CARD_VERSION, AbilityErrorCode::ERROR_CODE_AGENT_CARD_VERSION_INVALID}, + {ERR_AGENT_CARD_DUPLICATE_REGISTER, AbilityErrorCode::ERROR_CODE_AGENT_CARD_DUPLICATE_REGISTER}, {ERR_INVALID_MAIN_ELEMENT_TYPE, AbilityErrorCode::ERROR_CODE_INVALID_MAIN_ELEMENT_TYPE}, {ERR_CHANGE_KEEP_ALIVE, AbilityErrorCode::ERROR_CODE_CHANGE_KEEP_ALIVE}, {ERR_NO_U1, AbilityErrorCode::ERROR_CODE_NO_U1}, diff --git a/interfaces/kits/native/ability/native/ability_business_error/ability_business_error.h b/interfaces/kits/native/ability/native/ability_business_error/ability_business_error.h index 374b43398f..414b0ab820 100644 --- a/interfaces/kits/native/ability/native/ability_business_error/ability_business_error.h +++ b/interfaces/kits/native/ability/native/ability_business_error/ability_business_error.h @@ -221,6 +221,15 @@ enum class AbilityErrorCode { // Maximum connections from the same caller have been reached. ERROR_CODE_MAX_CONNECTIONS_REACHED = 35600003, + // The specified agent card version is older than the existing version. + ERROR_CODE_AGENT_CARD_VERSION_TOO_OLD = 35600004, + + // The specified agent card version is invalid. + ERROR_CODE_AGENT_CARD_VERSION_INVALID = 35600005, + + // The specified agent card has already been registered. + ERROR_CODE_AGENT_CARD_DUPLICATE_REGISTER = 35600006, + // invalid caller. ERROR_CODE_INVALID_CALLER = 16200001, diff --git a/test/unittest/ability_business_error_test/ability_business_error_test.cpp b/test/unittest/ability_business_error_test/ability_business_error_test.cpp index 970b577976..f99161e344 100644 --- a/test/unittest/ability_business_error_test/ability_business_error_test.cpp +++ b/test/unittest/ability_business_error_test/ability_business_error_test.cpp @@ -74,6 +74,12 @@ HWTEST_F(AbilityBusinessErrorTest, GetJsErrorCodeByNativeError_0100, TestSize.Le result = GetJsErrorCodeByNativeError(AAFwk::ERR_MAX_AGENT_CONNECTIONS_REACHED); EXPECT_TRUE(result == AbilityErrorCode::ERROR_CODE_MAX_CONNECTIONS_REACHED); + + result = GetJsErrorCodeByNativeError(OHOS::AAFwk::ERR_INVALID_AGENT_CARD_VERSION); + EXPECT_TRUE(result == AbilityErrorCode::ERROR_CODE_AGENT_CARD_VERSION_INVALID); + + result = GetJsErrorCodeByNativeError(OHOS::AAFwk::ERR_AGENT_CARD_DUPLICATE_REGISTER); + EXPECT_TRUE(result == AbilityErrorCode::ERROR_CODE_AGENT_CARD_DUPLICATE_REGISTER); } } // namespace AAFwk } // namespace OHOS