!18767 merge feat/register-agent-card-3 into master

feat: register/update/delete AgentCard part 3

Created-by: yangxuguang-huawei
Commit-by: yangxuguang-huawei
Merged-by: openharmony_ci
Description: **IssueNo**:
https://gitcode.com/openharmony/ability_ability_runtime/issues/14824

**Description**:

**稳定性自检:**
| 自检项                                                       | 自检结果  |
| ------------------------------------------------------------ | -------- |
| 涉及跨进程调用的相关操作需要抛至主线程或加锁防止并发              |          ok|
| 成员变量进行赋值或创建需要排查并发                               |          ok|
| 谨慎在lambda表达式中使用引用捕获                                |          ok|
| 谨慎在未经拷贝的情况下使用外部传入的string、C字符串               |          ok|
| map\vector\list\set等stl模板类使用时需要排查并发                |          ok|
| 谨慎考虑加锁范围                                               |          ok|
| 在IPC通信中谨慎使用同步通信方式                                 |          ok|
| 禁止传递this指针至其他模块或线程(特别是eventhandler任务)        |          ok|
| 禁止将外部传入的裸指针在内部直接构造智能指针                      |          ok|
| 禁止多个独立创建的智能指针管理同一地址                           |          ok|
| 禁止在析构函数中抛异步任务                                      |          ok|
| 禁止js对象在非js线程(例如在IPC线程)创建、使用或销毁             |          ok|
| 禁止在对外接口中未经判空直接使用外部传入的指针                    |          ok|
| 禁止接口返回局部变量引用                                        |          ok|
| 禁止在信号函数中加锁                                            |          ok|
| 禁止在关键流程(SA启动、应用启动等主流程)执行耗时的操作           |          ok|
| 禁止将同一个cpp编译在不同的so中                                 |          ok|

**安全编码自检:**
| 自检项                                                          | 自检结果 |
| -------------------------------------------------------------- | -------- |
| 裸指针避免通过隐式转换构造为sptr                                 |          ok|
| json对象在取值之前必须先判断类型,避免类型不匹配                   |          ok|
| 序列化时必须对传入的数组大小进行校验,避免出现超大数组              |       ok   |
| 避免使用未明确位宽的整型,选择使用int8_t、uint8_t等类型            |          ok|
| 外部传入的路径要做规范化校验,对路径中的.、..、../等特殊字符严格校验 | ok         |
| 指针变量、表示资源描述符的变量、bool变量必须赋初值                  |          ok|
| readParcelable获取的对象使用前需要判空                            |          ok|
| 分配和释放内存的函数需要成对出现                                   |          ok|
| 申请内存后异常退出前需要及时进行内存释放                            |    ok      |
| 内存申请前必须对内存大小进行合法性校验                              |          ok|
| 内存分配后必须判断是否成功                                         |          ok|
| 禁止使用realloc、alloca函数                                       |          ok|
| 禁止打印文件路径、口令等敏感信息,如有需要,使用private修饰          |          ok|
| 禁止打印内存地址                                                  |          ok|
| 整数之间运算时必须严格检查,确保不会出现溢出、反转、除0               |          ok|
| 禁止对有符号整数进行位操作符运算                                    |          ok|
| 禁止对指针进行逻辑或位运算                                         |          ok|
| 循环次数如果收外部数据控制,需要检验其合法性                         |          ok|
| 禁止使用内存操作类危险函数,需要使用安全函数                         |          ok|
| 谨慎使用不可重入函数                                               |          ok|
| 必须检查安全函数的返回值,并进行正确处理                             |          ok|
| 禁止仅通过TokenType类型判断绕过权限校验                             |          ok|

**TDD Result**:
已验证OK

**XTS Result**:
已验证OK

### 是否已执行L0用例
- [x] 已验证
- [ ] 不涉及。如不涉及,请写明理由


See merge request: openharmony/ability_ability_runtime!18767
This commit is contained in:
openharmony_ci
2026-03-31 20:59:31 +08:00
10 changed files with 661 additions and 0 deletions
@@ -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",
@@ -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"
}
@@ -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<int32_t>(AgentCardType::APP)));
NAPI_CALL(env, SetEnumItem(env, object, "LOW_CODE", static_cast<int32_t>(AgentCardType::LOW_CODE)));
NAPI_CALL(env, SetEnumItem(env, object, "ATOMIC_SERVICE", static_cast<int32_t>(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<void *>(0)),
.reserved = {0}
};
extern "C" __attribute__((constructor)) void RegisterModule(void)
{
napi_module_register(&_module);
}
} // namespace AgentRuntime
} // namespace OHOS
@@ -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.
*
@@ -30,6 +30,12 @@ JS_AGENT_MANAGER_UTILS_EXPORT napi_value CreateJsAgentSkillArray(
napi_env env, const std::vector<std::shared_ptr<AgentSkill>> &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<AgentCard> &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
@@ -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<AgentCard>();
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<int32_t>(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<AgentCard>();
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<int32_t>(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<int32_t>(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,
@@ -16,6 +16,7 @@
#include "js_agent_manager_utils.h"
#include <cstdint>
#include <memory>
#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<int32_t>(AgentCardType::APP) &&
type <= static_cast<int32_t>(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<std::string> &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<int32_t>(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<AgentCard> &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<int32_t>(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<AgentCardType>(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<AgentSkill>();
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<AgentProvider>();
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<AgentCapabilities>();
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<AgentAppInfo>();
if (!ParseJsAgentAppInfo(env, property, *appInfo)) {
TAG_LOGE(AAFwkTag::SER_ROUTER, "bad card.appInfo");
return false;
}
card.appInfo = appInfo;
return true;
}
} // namespace AgentRuntime
} // namespace OHOS
@@ -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<AbilityErrorCode, const char*> 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<int32_t, AbilityErrorCode> 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},
@@ -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,
@@ -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