From c83aefbb108ea86b531567bfdde953a63a05d07d Mon Sep 17 00:00:00 2001 From: hechaofan Date: Sun, 13 Jul 2025 16:09:16 +0800 Subject: [PATCH] =?UTF-8?q?0702=E5=90=8C=E6=AD=A5master?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: hechaofan Change-Id: Ifbccf58146775415a3063c7f1a5fca9e175a7ca9 --- bundle.json | 5 +- frameworks/BUILD.gn | 3 + .../js/ani/driver_extension_ability/BUILD.gn | 90 +++ ...hos.app.ability.DriverExtensionAbility.ets | 86 +++ .../native/include/ani_driver_extension.h | 56 ++ .../native/include/ani_utils.h | 309 +++++++++ .../native/src/ani_driver_extension.cpp | 307 +++++++++ frameworks/js/taihe/BUILD.gn | 99 +++ .../taihe/driver_extension_context/BUILD.gn | 107 +++ .../idl/DriverExtensionContext.taihe | 29 + .../include/DriverExtensionContext_ani.h | 33 + .../include/ani_utils.h | 310 +++++++++ .../src/DriverExtensionContext.impl.cpp | 88 +++ .../src/ani_constructor.cpp | 30 + .../taihe/idl/ohos.driver.deviceManager.taihe | 104 +++ .../include/ohos.driver.deviceManager.impl.h | 69 ++ frameworks/js/taihe/src/ani_constructor.cpp | 54 ++ .../src/ohos.driver.deviceManager.impl.cpp | 623 ++++++++++++++++++ frameworks/js/taihe/test/xts/module.json5 | 57 ++ .../test/xts/src/test/DeviceManager.test.ets | 430 ++++++++++++ .../test/DeviceManagerNoPermission.test.ets | 152 +++++ .../src/test/DeviceManagerNormalApp.test.ets | 103 +++ .../js/taihe/test/xts/src/test/List.test.ets | 24 + .../js/taihe/test/xts/src/test/Util.test.ets | 24 + 24 files changed, 3190 insertions(+), 2 deletions(-) create mode 100644 frameworks/js/ani/driver_extension_ability/BUILD.gn create mode 100644 frameworks/js/ani/driver_extension_ability/ets/@ohos.app.ability.DriverExtensionAbility.ets create mode 100644 frameworks/js/ani/driver_extension_ability/native/include/ani_driver_extension.h create mode 100644 frameworks/js/ani/driver_extension_ability/native/include/ani_utils.h create mode 100644 frameworks/js/ani/driver_extension_ability/native/src/ani_driver_extension.cpp create mode 100644 frameworks/js/taihe/BUILD.gn create mode 100644 frameworks/js/taihe/driver_extension_context/BUILD.gn create mode 100644 frameworks/js/taihe/driver_extension_context/idl/DriverExtensionContext.taihe create mode 100644 frameworks/js/taihe/driver_extension_context/include/DriverExtensionContext_ani.h create mode 100644 frameworks/js/taihe/driver_extension_context/include/ani_utils.h create mode 100644 frameworks/js/taihe/driver_extension_context/src/DriverExtensionContext.impl.cpp create mode 100644 frameworks/js/taihe/driver_extension_context/src/ani_constructor.cpp create mode 100644 frameworks/js/taihe/idl/ohos.driver.deviceManager.taihe create mode 100644 frameworks/js/taihe/include/ohos.driver.deviceManager.impl.h create mode 100644 frameworks/js/taihe/src/ani_constructor.cpp create mode 100644 frameworks/js/taihe/src/ohos.driver.deviceManager.impl.cpp create mode 100644 frameworks/js/taihe/test/xts/module.json5 create mode 100644 frameworks/js/taihe/test/xts/src/test/DeviceManager.test.ets create mode 100644 frameworks/js/taihe/test/xts/src/test/DeviceManagerNoPermission.test.ets create mode 100644 frameworks/js/taihe/test/xts/src/test/DeviceManagerNormalApp.test.ets create mode 100644 frameworks/js/taihe/test/xts/src/test/List.test.ets create mode 100644 frameworks/js/taihe/test/xts/src/test/Util.test.ets diff --git a/bundle.json b/bundle.json index faf8f1e..a820693 100644 --- a/bundle.json +++ b/bundle.json @@ -52,10 +52,11 @@ "relational_store", "drivers_interface_input", "cJSON", - "selinux_adapter", "distributed_notification_service", "i18n", - "image_framework" + "image_framework", + "runtime_core", + "selinux_adapter" ] }, "build": { diff --git a/frameworks/BUILD.gn b/frameworks/BUILD.gn index 270ead7..9136de1 100644 --- a/frameworks/BUILD.gn +++ b/frameworks/BUILD.gn @@ -14,6 +14,9 @@ group("ext_devmgr_frameworks") { deps = [ "ddk:ddk", + "js/ani/driver_extension_ability:driver_extensionAbility_ani", "js/napi:napi_packages", + "js/taihe:device_manager_taihe", + "js/taihe/driver_extension_context:driverExtensionContext_taihe", ] } diff --git a/frameworks/js/ani/driver_extension_ability/BUILD.gn b/frameworks/js/ani/driver_extension_ability/BUILD.gn new file mode 100644 index 0000000..7324ec7 --- /dev/null +++ b/frameworks/js/ani/driver_extension_ability/BUILD.gn @@ -0,0 +1,90 @@ +# 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/ets2abc_config.gni") +import("//build/ohos.gni") +import("//build/templates/abc/ohos_abc.gni") +native_path = "../../../../services/native" +taihe_path = "../../taihe" + +generate_static_abc("driver_extension_ability_abc") { + base_url = "./ets" + files = [ "./ets/@ohos.app.ability.DriverExtensionAbility.ets" ] + dst_file = "$target_out_dir/driverExtensionAbility.abc" + out_puts = [ "$target_out_dir/driverExtensionAbility.abc" ] + is_boot_abc = "True" + device_dst_file = "/system/framework/driverExtensionAbility.abc" +} + +ohos_shared_library("driverextension_ani") { + include_dirs = [ + "native/include", + "$native_path/driver_extension/include", + "$taihe_path/driver_extension_context/include", + ] + sources = [ "native/src/ani_driver_extension.cpp" ] + + deps = [ + "$native_path/driver_extension:driver_extension", + "$taihe_path/driver_extension_context:driverExtensionContext_taihe", + ] + + external_deps = [ + "ability_base:want", + "ability_runtime:ability_connect_callback_stub", + "ability_runtime:ability_context_native", + "ability_runtime:ability_manager", + "ability_runtime:abilitykit_native", + "ability_runtime:ani_common", + "ability_runtime:app_context", + "ability_runtime:extensionkit_native", + "ability_runtime:napi_common", + "ability_runtime:runtime", + "c_utils:utils", + "eventhandler:libeventhandler", + "hilog:libhilog", + "hitrace:hitrace_meter", + "ipc:ipc_core", + "ipc:ipc_napi", + "ipc:rpc_ani", + "runtime_core:ani", + ] + + sanitize = { + integer_overflow = true + ubsan = true + boundary_sanitize = true + cfi = true + cfi_cross_dso = true + debug = false + } + + subsystem_name = "hdf" + part_name = "external_device_manager" + output_extension = "so" +} + +ohos_prebuilt_etc("driver_extension_ability_abc_etc") { + source = "$target_out_dir/driverExtensionAbility.abc" + module_install_dir = "framework" + subsystem_name = "hdf" + part_name = "external_device_manager" + deps = [ ":driver_extension_ability_abc" ] +} + +group("driver_extensionAbility_ani") { + deps = [ + ":driver_extension_ability_abc_etc", + ":driverextension_ani", + ] +} diff --git a/frameworks/js/ani/driver_extension_ability/ets/@ohos.app.ability.DriverExtensionAbility.ets b/frameworks/js/ani/driver_extension_ability/ets/@ohos.app.ability.DriverExtensionAbility.ets new file mode 100644 index 0000000..b3c887c --- /dev/null +++ b/frameworks/js/ani/driver_extension_ability/ets/@ohos.app.ability.DriverExtensionAbility.ets @@ -0,0 +1,86 @@ +/* + * 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. + */ +/** + * @file + * @kit DriverDevelopmentKit + */ +import type rpc from '@ohos.rpc'; +import type Want from '@ohos.app.ability.Want'; +import DriverExtensionContext from 'application.DriverExtensionContext'; +import hilog from '@ohos.hilog'; + +class MyService extends rpc.RemoteObject { + constructor(descriptor: string) { + super(descriptor); + } + + public onRemoteMessageRequest( + code: number, + data: rpc.MessageSequence, + reply: rpc.MessageSequence, + options: rpc.MessageOption + ): boolean | Promise { + return false; + } +} + +export default class DriverExtensionAbility { + private callOnConnect(want: Want): rpc.RemoteObject { + let p = this.onConnect(want); + if (p instanceof Promise) { + this.isOnConnectAsync = true; + return await(p as Promise); + } else { + this.isOnConnectAsync = false; + return p; + } + } + private callOnDisConnect(want: Want) : void { + let p = this.onDisconnect(want); + if (p instanceof Promise) { + this.isOnDisconnectAsync = true; + return await(p as Promise); + } else { + this.isOnDisconnectAsync = false; + return; + } + } + onInit(want: Want): void { + hilog.info(0x0000, 'testTag', `onInit`); + } + onRelease(): void { + hilog.info(0x0000, 'testTag', `onRelease`); + } + onConnect(want: Want): rpc.RemoteObject | Promise { + hilog.info(0x0000, 'testTag', `onConnect`); + let myService: rpc.RemoteObject = new MyService("onConnect"); + return myService; + } + onDisconnect(want: Want): undefined | Promise { + hilog.info(0x0000, 'testTag', `onDisconnect`); + return undefined; + } + onDump(params: Array): Array { + hilog.info(0x0000, 'testTag', `onDump`); + return ['params']; + } + + private connectCbInfo: long = 0; + private disConnectCbInfo: long = 0; + private isOnDisconnectAsync: boolean = true; + private isOnConnectAsync: boolean = true; + remoteObject: rpc.RemoteObject | null = null; + context: DriverExtensionContext = new DriverExtensionContext(); +} diff --git a/frameworks/js/ani/driver_extension_ability/native/include/ani_driver_extension.h b/frameworks/js/ani/driver_extension_ability/native/include/ani_driver_extension.h new file mode 100644 index 0000000..e0bff16 --- /dev/null +++ b/frameworks/js/ani/driver_extension_ability/native/include/ani_driver_extension.h @@ -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. + */ + +#ifndef OHOS_ABILITY_RUNTIME_ANI_DRIVER_EXTENSION_H +#define OHOS_ABILITY_RUNTIME_ANI_DRIVER_EXTENSION_H + +#include "ani.h" +#include "driver_extension.h" +#include "driver_extension_context.h" +#include "runtime.h" +#include "ets_runtime.h" + +class ETSRuntime; + +namespace OHOS { +namespace AbilityRuntime { +class AniDriverExtension : public DriverExtension, public std::enable_shared_from_this { +public: + explicit AniDriverExtension(ETSRuntime &stsRuntime); + virtual ~AniDriverExtension() override; + static AniDriverExtension *Create(const std::unique_ptr &runtime); + virtual void Init(const std::shared_ptr &record, + const std::shared_ptr &application, + std::shared_ptr &handler, const sptr &token) override; + virtual void OnStart(const AAFwk::Want &want) override; + virtual sptr OnConnect(const AAFwk::Want &want) override; + virtual sptr OnConnect(const AAFwk::Want &want, + AppExecFwk::AbilityTransactionCallbackInfo> *callbackInfo, bool &isAsyncCallback) override; + virtual void OnDisconnect(const AAFwk::Want &want) override; + void OnDisconnect(const AAFwk::Want &want, AppExecFwk::AbilityTransactionCallbackInfo<> *callbackInfo, + bool &isAsyncCallback) override; + virtual void OnStop() override; + ani_array_ref ToAniStringList(ani_env *env, const std::vector ¶ms, const uint32_t length); + virtual void Dump(const std::vector ¶ms, std::vector &info) override; + void BindContext( + ani_env *env, std::shared_ptr want, const std::shared_ptr &application); + +private: + std::unique_ptr stsObj_; + ETSRuntime &stsRuntime_; +}; +} // namespace AbilityRuntime +} // namespace OHOS +#endif // OHOS_ABILITY_RUNTIME_ANI_DRIVER_EXTENSION_H \ No newline at end of file diff --git a/frameworks/js/ani/driver_extension_ability/native/include/ani_utils.h b/frameworks/js/ani/driver_extension_ability/native/include/ani_utils.h new file mode 100644 index 0000000..76ce63e --- /dev/null +++ b/frameworks/js/ani/driver_extension_ability/native/include/ani_utils.h @@ -0,0 +1,309 @@ +/* + * 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 ANI_UTILS_H +#define ANI_UTILS_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "hilog_wrapper.h" + +class AniObjectUtils { +public: + static ani_object Create(ani_env *env, const char *nsName, const char *clsName, ...) + { + ani_object nullobj {}; + + ani_namespace ns; + if (ANI_OK != env->FindNamespace(nsName, &ns)) { + HILOG_ERROR("[ANI] Not found namespace %{public}s", nsName); + return nullobj; + } + + ani_class cls; + if (ANI_OK != env->Namespace_FindClass(ns, clsName, &cls)) { + HILOG_ERROR("[ANI] Not found class %{public}s", clsName); + return nullobj; + } + + ani_method ctor; + if (ANI_OK != env->Class_FindMethod(cls, "", nullptr, &ctor)) { + HILOG_ERROR("[ANI] Not found for class %{public}s", clsName); + return nullobj; + } + + ani_object obj; + va_list args; + va_start(args, clsName); + ani_status status = env->Object_New_V(cls, ctor, &obj, args); + va_end(args); + if (ANI_OK != status) { + HILOG_ERROR("[ANI] Failed to Object_New for class %{public}s", clsName); + return nullobj; + } + return obj; + } + + static ani_object Create(ani_env *env, const char *clsName, ...) + { + ani_object nullobj {}; + + ani_class cls; + if (ANI_OK != env->FindClass(clsName, &cls)) { + HILOG_ERROR("[ANI] Not found class %{public}s", clsName); + return nullobj; + } + + ani_method ctor; + if (ANI_OK != env->Class_FindMethod(cls, "", nullptr, &ctor)) { + HILOG_ERROR("[ANI] Not found for class %{public}s", clsName); + return nullobj; + } + + ani_object obj; + va_list args; + va_start(args, clsName); + ani_status status = env->Object_New_V(cls, ctor, &obj, args); + va_end(args); + if (ANI_OK != status) { + HILOG_ERROR("[ANI] Failed to Object_New for class %{public}s", clsName); + return nullobj; + } + return obj; + } + + static ani_object Create(ani_env *env, ani_class cls, ...) + { + ani_object nullobj {}; + + ani_method ctor; + if (ANI_OK != env->Class_FindMethod(cls, "", nullptr, &ctor)) { + HILOG_ERROR("[ANI] Not found for class"); + return nullobj; + } + + ani_object obj; + va_list args; + va_start(args, cls); + ani_status status = env->Object_New_V(cls, ctor, &obj, args); + va_end(args); + if (ANI_OK != status) { + HILOG_ERROR("[ANI] Failed to Object_New for class 1"); + return nullobj; + } + return obj; + } + + template + static ani_status Wrap(ani_env *env, ani_object object, T *nativePtr, const char *propName = "nativePtr") + { + return env->Object_SetFieldByName_Long(object, propName, reinterpret_cast(nativePtr)); + } + + template + static T *Unwrap(ani_env *env, ani_object object, const char *propName = "nativePtr") + { + ani_long nativePtr; + if (ANI_OK != env->Object_GetFieldByName_Long(object, propName, &nativePtr)) { + return nullptr; + } + return reinterpret_cast(nativePtr); + } +}; + +class AniStringUtils { +public: + static std::string ToStd(ani_env *env, ani_string ani_str) + { + ani_size strSize; + env->String_GetUTF8Size(ani_str, &strSize); + + std::vector buffer(strSize + 1); // +1 for null terminator + char *utf8_buffer = buffer.data(); + + // String_GetUTF8 Supportted by https://gitee.com/openharmony/arkcompiler_runtime_core/pulls/3416 + ani_size bytes_written = 0; + env->String_GetUTF8(ani_str, utf8_buffer, strSize + 1, &bytes_written); + + utf8_buffer[bytes_written] = '\0'; + std::string content = std::string(utf8_buffer); + return content; + } + + static ani_string ToAni(ani_env *env, const std::string &str) + { + ani_string aniStr = nullptr; + if (ANI_OK != env->String_NewUTF8(str.data(), str.size(), &aniStr)) { + HILOG_ERROR("[ANI] Unsupported ANI_VERSION_1"); + return nullptr; + } + return aniStr; + } +}; + +class UnionAccessor { +public: + UnionAccessor(ani_env *env, ani_object &obj) : env_(env), obj_(obj) {} + + bool IsInstanceOf(const std::string &cls_name) + { + ani_class cls; + env_->FindClass(cls_name.c_str(), &cls); + + ani_boolean ret; + env_->Object_InstanceOf(obj_, cls, &ret); + return ret; + } + + template + bool IsInstanceOfType(); + + template + bool TryConvert(T &value); + + template + bool TryConvertArray(std::vector &value); + +private: + ani_env *env_; + ani_object obj_; +}; + +template <> +inline bool UnionAccessor::IsInstanceOfType() +{ + return IsInstanceOf("Lstd/core/Boolean;"); +} + +template <> +inline bool UnionAccessor::IsInstanceOfType() +{ + return IsInstanceOf("Lstd/core/Int;"); +} + +template <> +inline bool UnionAccessor::IsInstanceOfType() +{ + return IsInstanceOf("Lstd/core/Double;"); +} + +template <> +inline bool UnionAccessor::IsInstanceOfType() +{ + return IsInstanceOf("Lstd/core/String;"); +} + +template <> +inline bool UnionAccessor::TryConvert(bool &value) +{ + if (!IsInstanceOfType()) { + return false; + } + + ani_boolean aniValue; + auto ret = env_->Object_CallMethodByName_Boolean(obj_, "unboxed", nullptr, &aniValue); + if (ret != ANI_OK) { + return false; + } + value = static_cast(aniValue); + return true; +} + +template <> +inline bool UnionAccessor::TryConvert(int &value) +{ + if (!IsInstanceOfType()) { + return false; + } + + ani_int aniValue; + auto ret = env_->Object_CallMethodByName_Int(obj_, "unboxed", nullptr, &aniValue); + if (ret != ANI_OK) { + return false; + } + value = static_cast(aniValue); + return true; +} + +template <> +inline bool UnionAccessor::TryConvert(double &value) +{ + if (!IsInstanceOfType()) { + return false; + } + + ani_double aniValue; + auto ret = env_->Object_CallMethodByName_Double(obj_, "unboxed", nullptr, &aniValue); + if (ret != ANI_OK) { + return false; + } + value = static_cast(aniValue); + return true; +} + +template <> +inline bool UnionAccessor::TryConvert(std::string &value) +{ + if (!IsInstanceOfType()) { + return false; + } + + value = AniStringUtils::ToStd(env_, static_cast(obj_)); + return true; +} + +class OptionalAccessor { +public: + OptionalAccessor(ani_env *env, ani_object &obj) : env_(env), obj_(obj) {} + + bool IsUndefined() + { + ani_boolean isUndefined; + env_->Reference_IsUndefined(obj_, &isUndefined); + return isUndefined; + } + + template + std::optional Convert(); + +private: + ani_env *env_; + ani_object obj_; +}; + +template <> +inline std::optional OptionalAccessor::Convert() +{ + if (IsUndefined()) { + return std::nullopt; + } + + ani_double aniValue; + auto ret = env_->Object_CallMethodByName_Double(obj_, "doubleValue", nullptr, &aniValue); + if (ret != ANI_OK) { + return std::nullopt; + } + auto value = static_cast(aniValue); + return value; +} + +#endif diff --git a/frameworks/js/ani/driver_extension_ability/native/src/ani_driver_extension.cpp b/frameworks/js/ani/driver_extension_ability/native/src/ani_driver_extension.cpp new file mode 100644 index 0000000..f46b76d --- /dev/null +++ b/frameworks/js/ani/driver_extension_ability/native/src/ani_driver_extension.cpp @@ -0,0 +1,307 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "ani_driver_extension.h" + +#include "ability_info.h" +#include "ani_common_want.h" +#include "ani_remote_object.h" +#include "ani_utils.h" +#include "DriverExtensionContext_ani.h" +#include "hitrace_meter.h" +#include "hilog_wrapper.h" +#include "ets_native_reference.h" + +constexpr const char* DRIVER_EXTENSION_CLS = "L@ohos/app/ability/DriverExtensionAbility/DriverExtensionAbility;"; +namespace OHOS { +namespace AbilityRuntime { +using namespace OHOS::AppExecFwk; +AniDriverExtension::AniDriverExtension(ETSRuntime& aniRuntime) : stsRuntime_(aniRuntime) {} +AniDriverExtension::~AniDriverExtension() = default; + +AniDriverExtension* AniDriverExtension::Create(const std::unique_ptr& runtime) +{ + return new AniDriverExtension(static_cast(*runtime)); +} + +void AniDriverExtension::Init(const std::shared_ptr &record, + const std::shared_ptr &application, std::shared_ptr &handler, + const sptr &token) +{ + HILOG_DEBUG("%{public}s begin.", __func__); + DriverExtension::Init(record, application, handler, token); + if (Extension::abilityInfo_ == nullptr || Extension::abilityInfo_->srcEntrance.empty()) { + HILOG_ERROR("DriverExtensionAbility Init abilityInfo error"); + return; + } + std::string srcPath(Extension::abilityInfo_->moduleName + "/"); + srcPath.append(Extension::abilityInfo_->srcEntrance); + auto pos = srcPath.rfind("."); + if (pos != std::string::npos) { + srcPath.erase(pos); + srcPath.append(".abc"); + } + std::string moduleName(Extension::abilityInfo_->moduleName); + moduleName.append("::").append(abilityInfo_->name); + stsObj_ = stsRuntime_.LoadModule(moduleName, srcPath, abilityInfo_->hapPath, + abilityInfo_->compileMode == AppExecFwk::CompileMode::ES_MODULE, false, + abilityInfo_->srcEntrance); + if (stsObj_ == nullptr) { + HILOG_ERROR("Failed to get etsObj"); + return; + } + auto env = stsRuntime_.GetAniEnv(); + BindContext(env, record->GetWant(), application); + HILOG_DEBUG("%{public}s end.", __func__); +} + +void AniDriverExtension::BindContext(ani_env *env, std::shared_ptr want, + const std::shared_ptr &application) +{ + HILOG_DEBUG("StsServiceExtension BindContext Call"); + if (env == nullptr || want == nullptr) { + HILOG_ERROR("Want info is null or env is null"); + return; + } + auto context = GetContext(); + if (context == nullptr) { + HILOG_ERROR("Failed to get context"); + return; + } + ani_object contextObj = CreateAniDriverExtensionContext(env, context, application); + if (contextObj == nullptr) { + HILOG_ERROR("null contextObj"); + return; + } + ani_field contextField; + ani_class cls = nullptr; + if ((env->FindClass(DRIVER_EXTENSION_CLS, &cls)) != ANI_OK) { + HILOG_ERROR("FindClass err: %{public}s", DRIVER_EXTENSION_CLS); + return; + } + auto status = env->Class_FindField(cls, "context", &contextField); + if (status != ANI_OK) { + HILOG_ERROR("Class_GetField context failed"); + return; + } + ani_ref contextRef = nullptr; + if (env->GlobalReference_Create(contextObj, &contextRef) != ANI_OK) { + HILOG_ERROR("GlobalReference_Create contextObj failed"); + return; + } + if (env->Object_SetField_Ref(stsObj_->aniObj, contextField, contextRef) != ANI_OK) { + HILOG_ERROR("Object_SetField_Ref contextObj failed"); + return; + } + HILOG_DEBUG("BindContext end"); +} + +void AniDriverExtension::OnStart(const AAFwk::Want &want) +{ + HILOG_DEBUG("%{public}s begin.", __func__); + Extension::OnStart(want); + auto env = stsRuntime_.GetAniEnv(); + ani_object ani_want = OHOS::AppExecFwk::WrapWant(env, want); + if (ANI_OK != env->Object_CallMethodByName_Void(stsObj_->aniObj, "onInit", nullptr, ani_want)) { + HILOG_ERROR("Failed to call the method: onInit"); + return; + } + HILOG_DEBUG("%{public}s end.", __func__); +} + +void AniDriverExtension::OnStop() +{ + HILOG_DEBUG("%{public}s begin.", __func__); + DriverExtension::OnStop(); + auto env = stsRuntime_.GetAniEnv(); + if (ANI_OK != env->Object_CallMethodByName_Void(stsObj_->aniObj, "onRelease", nullptr)) { + HILOG_ERROR("Failed to call the method: onRelease"); + return; + } + HILOG_DEBUG("%{public}s end.", __func__); +} + +sptr AniDriverExtension::OnConnect(const AAFwk::Want &want) +{ + HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, __PRETTY_FUNCTION__); + HILOG_DEBUG("%{public}s begin.", __func__); + Extension::OnConnect(want); + ani_ref result = nullptr; + auto env = stsRuntime_.GetAniEnv(); + ani_object ani_want = OHOS::AppExecFwk::WrapWant(env, want); + if (ANI_OK != env->Object_CallMethodByName_Ref(stsObj_->aniObj, "onConnect", nullptr, &result, ani_want)) { + HILOG_ERROR("Failed to call the method: onConnect"); + return nullptr; + } + if (result == nullptr) { + HILOG_ERROR("Failed to call onConnect : result == nullptr"); + return nullptr; + } + HILOG_DEBUG("%{public}s end.", __func__); + auto obj = reinterpret_cast(result); + auto remoteObj = AniGetNativeRemoteObject(env, obj); + if (remoteObj == nullptr) { + HILOG_ERROR("remoteObj null"); + return nullptr; + } + HILOG_DEBUG("end"); + return remoteObj; +} + +sptr AniDriverExtension::OnConnect(const AAFwk::Want &want, + AppExecFwk::AbilityTransactionCallbackInfo> *callbackInfo, bool &isAsyncCallback) +{ + HILOG_DEBUG("%{public}s begin.", __func__); + if (callbackInfo == nullptr) { + HILOG_DEBUG("%{public}s is not AsyncCallback.", __func__); + isAsyncCallback = false; + return this->OnConnect(want); + } + Extension::OnConnect(want); + ani_boolean isAsync = false; + auto env = stsRuntime_.GetAniEnv(); + if (ANI_OK != env->Object_SetFieldByName_Long(stsObj_->aniObj, "connectCbInfo", + reinterpret_cast(callbackInfo))) { + HILOG_ERROR("Failed to Set the connectCbInfo"); + return nullptr; + } + ani_ref wantRef = OHOS::AppExecFwk::WrapWant(env, want); + ani_ref result = nullptr; + if (ANI_OK != + env->Object_CallMethodByName_Ref(stsObj_->aniObj, "callOnConnect", nullptr, &result, wantRef)) { + HILOG_ERROR("2 Failed to call the method: callOnConnect"); + return nullptr; + } + auto obj = reinterpret_cast(result); + auto remoteObj = AniGetNativeRemoteObject(env, obj); + if (remoteObj == nullptr) { + HILOG_ERROR("remoteObj null"); + return nullptr; + } + if (ANI_OK != env->Object_GetFieldByName_Boolean(stsObj_->aniObj, "isOnConnectAsync", &isAsync)) { + HILOG_ERROR("Failed to Get the isOnConnectAsync"); + return nullptr; + } + if (isAsync) { + isAsyncCallback = true; + callbackInfo->Call(remoteObj); + AppExecFwk::AbilityTransactionCallbackInfo>::Destroy(callbackInfo); + return nullptr; + } + HILOG_DEBUG("%{public}s end.", __func__); + return remoteObj; +} + +void AniDriverExtension::OnDisconnect(const AAFwk::Want &want) +{ + HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, __PRETTY_FUNCTION__); + HILOG_DEBUG("%{public}s begin.", __func__); + Extension::OnDisconnect(want); + auto env = stsRuntime_.GetAniEnv(); + ani_object ani_want = OHOS::AppExecFwk::WrapWant(env, want); + if (ANI_OK != env->Object_CallMethodByName_Void(stsObj_->aniObj, "callOnDisConnect", nullptr, ani_want)) { + HILOG_ERROR("Failed to call the method: onDisconnect"); + return; + } + HILOG_DEBUG("%{public}s end.", __func__); +} + +void AniDriverExtension::OnDisconnect(const AAFwk::Want &want, + AppExecFwk::AbilityTransactionCallbackInfo<> *callbackInfo, bool &isAsyncCallback) +{ + HILOG_DEBUG("%{public}s begin.", __func__); + if (callbackInfo == nullptr) { + this->OnDisconnect(want); + return; + } + auto env = stsRuntime_.GetAniEnv(); + Extension::OnDisconnect(want); + if (ANI_OK != env->Object_SetFieldByName_Long(stsObj_->aniObj, "disConnectCbInfo", + reinterpret_cast(callbackInfo))) { + HILOG_ERROR("Failed to Set the disConnectCbInfo"); + return; + } + ani_object ani_want = OHOS::AppExecFwk::WrapWant(env, want); + if (ANI_OK != env->Object_CallMethodByName_Void(stsObj_->aniObj, "callOnDisConnect", nullptr, ani_want)) { + HILOG_ERROR("Failed to call the method: callOnDisConnect"); + return; + } + ani_boolean isAsync = false; + if (ANI_OK != env->Object_GetFieldByName_Boolean(stsObj_->aniObj, "isOnDisconnectAsync", &isAsync)) { + HILOG_ERROR("Failed to Get the isOnDisconnectAsync"); + return; + } + if (isAsync) { + isAsyncCallback = true; + callbackInfo->Call(); + AppExecFwk::AbilityTransactionCallbackInfo<>::Destroy(callbackInfo); + return; + } + HILOG_DEBUG("%{public}s end.", __func__); +} + +ani_array_ref AniDriverExtension::ToAniStringList(ani_env *env, + const std::vector ¶ms, const uint32_t length) +{ + HILOG_DEBUG("%{public}s begin.", __func__); + if (env == nullptr) { + return nullptr; + } + ani_array_ref result = nullptr; + ani_class stringCls = nullptr; + if (ANI_OK != env->FindClass("Lstd/core/String;", &stringCls)) { + HILOG_ERROR("FindClass Lstd/core/String Failed"); + return result; + } + if (env->Array_New_Ref(stringCls, length, nullptr, &result) != ANI_OK) { + return result; + } + for (auto i = 0; i < length; ++i) { + if (ANI_OK != env->Array_Set_Ref(result, i, AniStringUtils::ToAni(env, params[i]))) { + return result; + } + } + HILOG_DEBUG("%{public}s end.", __func__); + return result; +} + +void AniDriverExtension::Dump(const std::vector ¶ms, std::vector &info) +{ + HILOG_DEBUG("%{public}s begin.", __func__); + Extension::Dump(params, info); + auto env = stsRuntime_.GetAniEnv(); + ani_array_ref params_ = ToAniStringList(env, params, params.size()); + ani_ref result = nullptr; + if (ANI_OK != env->Object_CallMethodByName_Ref(stsObj_->aniObj, "onDump", nullptr, &result, params_)) { + HILOG_ERROR("Failed to call the method: Dump"); + return; + } + ani_double length; + if (ANI_OK != env->Object_GetPropertyByName_Double(static_cast(result), "length", &length)) { + HILOG_ERROR("Object_GetPropertyByName_Double length Failed"); + return; + } + for (int i = 0; i < int(length); i++) { + ani_ref stringEntryRef; + if (ANI_OK != env->Object_CallMethodByName_Ref(static_cast(result), "$_get", + "I:Lstd/core/Object;", &stringEntryRef, (ani_int)i)) { + HILOG_ERROR("Object_CallMethodByName_Ref get Failed"); + return; + } + info.push_back(AniStringUtils::ToStd(env, static_cast(stringEntryRef))); + } + HILOG_DEBUG("%{public}s end.", __func__); +} +} // AbilityRuntime +} // OHOS \ No newline at end of file diff --git a/frameworks/js/taihe/BUILD.gn b/frameworks/js/taihe/BUILD.gn new file mode 100644 index 0000000..f574b54 --- /dev/null +++ b/frameworks/js/taihe/BUILD.gn @@ -0,0 +1,99 @@ +# Copyright (c) 2025 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build/config/components/ets_frontend/ets2abc_config.gni") +import("//build/ohos.gni") +import("//build/ohos/taihe_idl/taihe.gni") +import("//drivers/external_device_manager/extdevmgr.gni") + +copy_taihe_idl("copy_deviceManager") { + sources = [ "idl/ohos.driver.deviceManager.taihe" ] + external_deps = [] +} + +subsystem_name = "hdf" +part_name = "external_device_manager" + +taihe_generated_file_path = "$taihe_file_path/out/$subsystem_name/$part_name" +ohos_taihe("run_taihe") { + taihe_generated_file_path = "$taihe_generated_file_path" + deps = [ ":copy_deviceManager" ] + outputs = [ + "$taihe_generated_file_path/src/ohos.driver.deviceManager.abi.c", + "$taihe_generated_file_path/src/ohos.driver.deviceManager.ani.cpp", + ] +} + +taihe_shared_library("device_manager_taihe_native") { + taihe_generated_file_path = "$taihe_generated_file_path" + part_name = "$part_name" + subsystem_name = "$subsystem_name" + sources = get_target_outputs(":run_taihe") + include_dirs = [ + "./include/", + "${utils_path}/include/", + "${ext_mgr_path}/interfaces/innerkits/", + ] + + sources += [ + "${ext_mgr_path}/services/native/driver_extension_manager/src/driver_ext_mgr_types.cpp", + "src/ani_constructor.cpp", + "src/ohos.driver.deviceManager.impl.cpp", + ] + deps = [ + ":run_taihe", + "${ext_mgr_path}/interfaces/innerkits:driver_ext_mgr_client", + ] + + external_deps = [ + "bundle_framework:appexecfwk_base", + "bundle_framework:appexecfwk_core", + "c_utils:utils", + "eventhandler:libeventhandler", + "hilog:libhilog", + "ipc:ipc_single", + "ipc:rpc_ani", + "runtime_core:ani", + ] +} + +generate_static_abc("device_manager_abc") { + base_url = "$taihe_generated_file_path" + files = [ "$taihe_generated_file_path/@ohos.driver.deviceManager.ets" ] + is_boot_abc = "True" + device_dst_file = "/system/framework/device_manager_abc.abc" + dependencies = [ ":run_taihe" ] +} + +ohos_prebuilt_etc("device_manager_etc") { + source = "$target_out_dir/device_manager_abc.abc" + module_install_dir = "framework" + part_name = "$part_name" + subsystem_name = "$subsystem_name" + deps = [ ":device_manager_abc" ] +} + +# generate_static_abc("device_manager_test") { +# base_url = "$taihe_generated_file_path" +# files = [ "$taihe_generated_file_path/@ohos.driver.deviceManager.ets" ] +# is_boot_abc = "True" +# device_dst_file = "/system/framework/device_manager_abc.abc" +# dependencies = [ ":run_taihe" ] +# } + +group("device_manager_taihe") { + deps = [ + ":device_manager_etc", + ":device_manager_taihe_native", + ] +} diff --git a/frameworks/js/taihe/driver_extension_context/BUILD.gn b/frameworks/js/taihe/driver_extension_context/BUILD.gn new file mode 100644 index 0000000..a39cb3f --- /dev/null +++ b/frameworks/js/taihe/driver_extension_context/BUILD.gn @@ -0,0 +1,107 @@ +# 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/ets2abc_config.gni") +import("//build/ohos.gni") +import("//build/ohos/taihe_idl/taihe.gni") + +copy_taihe_idl("copy_driverExtensionContext") { + sources = [ "idl/DriverExtensionContext.taihe" ] + #external_deps = [] +} + +subsystem_name = "hdf" +part_name = "external_device_manager" +taihe_application_file_path = "$taihe_file_path/out/$subsystem_name/$part_name" +taihe_generated_file_path = + "$taihe_file_path/out/$subsystem_name/$part_name/application" +native_path = "../../../../services/native" + +ohos_taihe("run_taihe") { + taihe_generated_file_path = "$taihe_generated_file_path" + deps = [ ":copy_driverExtensionContext" ] + outputs = [ + "$taihe_generated_file_path/src/DriverExtensionContext.ani.cpp", + "$taihe_generated_file_path/src/DriverExtensionContext.abi.c", + ] +} + +taihe_shared_library("DriverExtensionContext_native") { + sanitize = { + integer_overflow = true + ubsan = true + boundary_sanitize = true + cfi = true + cfi_cross_dso = true + debug = false + } + taihe_generated_file_path = "$taihe_generated_file_path" + part_name = "$part_name" + subsystem_name = "$subsystem_name" + sources = get_target_outputs(":run_taihe") + include_dirs = [ + "include", + "$native_path/driver_extension/include", + ] + sources += [ + "$native_path/driver_extension/src/driver_extension_context.cpp", + "src/DriverExtensionContext.impl.cpp", + "src/ani_constructor.cpp", + ] + + deps = [ ":run_taihe" ] + + external_deps = [ + "ability_runtime:ability_connect_callback_stub", + "ability_runtime:ability_context_native", + "ability_runtime:ability_manager", + "ability_runtime:abilitykit_native", + "ability_runtime:ani_common", + "ability_runtime:app_context", + "ability_runtime:extensionkit_native", + "ability_runtime:napi_common", + "ability_runtime:runtime", + "bundle_framework:bms_ani_common", + "c_utils:utils", + "hilog:libhilog", + "hitrace:hitrace_meter", + "ipc:ipc_core", + "ipc:ipc_napi", + "ipc:rpc_ani", + "runtime_core:ani", + ] +} + +generate_static_abc("driverExtensionContext_abc") { + base_url = "$taihe_application_file_path" + files = [ "$taihe_generated_file_path/DriverExtensionContext.ets" ] + is_boot_abc = "True" + device_dst_file = "/system/framework/driverExtensionContext_abc.abc" + dependencies = [ ":run_taihe" ] +} + +ohos_prebuilt_etc("driverExtensionContext_etc") { + source = "$target_out_dir/driverExtensionContext_abc.abc" + module_install_dir = "framework" + part_name = "$part_name" + subsystem_name = "$subsystem_name" + deps = [ ":driverExtensionContext_abc" ] +} + +group("driverExtensionContext_taihe") { + deps = [ + ":DriverExtensionContext_native", + ":driverExtensionContext_etc", + ] + #deps = [":run_taihe"] +} diff --git a/frameworks/js/taihe/driver_extension_context/idl/DriverExtensionContext.taihe b/frameworks/js/taihe/driver_extension_context/idl/DriverExtensionContext.taihe new file mode 100644 index 0000000..4905b1e --- /dev/null +++ b/frameworks/js/taihe/driver_extension_context/idl/DriverExtensionContext.taihe @@ -0,0 +1,29 @@ +/* + * 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. + */ + +@!sts_inject_into_module("import ExtensionContext from 'application.ExtensionContext';") + +@!sts_inject(""" +export default class DriverExtensionContext extends ExtensionContext { + constructor() { + super(); + } + updateDriverState(): void { + this.UpdateDriverState(); + } + native UpdateDriverState(): void; + private nativePtr: long = 0; +} +""") \ No newline at end of file diff --git a/frameworks/js/taihe/driver_extension_context/include/DriverExtensionContext_ani.h b/frameworks/js/taihe/driver_extension_context/include/DriverExtensionContext_ani.h new file mode 100644 index 0000000..23d7192 --- /dev/null +++ b/frameworks/js/taihe/driver_extension_context/include/DriverExtensionContext_ani.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef OHOS_ABILITY_RUNTIME_ANI_DRIVER_EXTENSION_CONTEXT_H +#define OHOS_ABILITY_RUNTIME_ANI_DRIVER_EXTENSION_CONTEXT_H + +#include "ability_connect_callback.h" +#include "driver_extension_context.h" +#include "event_handler.h" +#include "js_free_install_observer.h" +#include "native_engine/native_engine.h" +#include "ohos_application.h" +#include + +namespace OHOS { +namespace AbilityRuntime { +ani_object CreateAniDriverExtensionContext(ani_env *env, std::shared_ptr context, + const std::shared_ptr &application); +} // namespace AbilityRuntime +} // namespace OHOS +#endif // OHOS_ABILITY_RUNTIME_JS_DRIVER_EXTENSION_CONTEXT_H \ No newline at end of file diff --git a/frameworks/js/taihe/driver_extension_context/include/ani_utils.h b/frameworks/js/taihe/driver_extension_context/include/ani_utils.h new file mode 100644 index 0000000..03cbc44 --- /dev/null +++ b/frameworks/js/taihe/driver_extension_context/include/ani_utils.h @@ -0,0 +1,310 @@ +/* + * 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 ANI_UTILS_H +#define ANI_UTILS_H + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +class AniObjectUtils { +public: + static ani_object Create(ani_env *env, const char *nsName, const char *clsName, ...) + { + ani_object nullobj {}; + + ani_namespace ns; + if (ANI_OK != env->FindNamespace(nsName, &ns)) { + std::cerr << "[ANI] Not found namespace " << nsName << std::endl; + return nullobj; + } + + ani_class cls; + if (ANI_OK != env->Namespace_FindClass(ns, clsName, &cls)) { + std::cerr << "[ANI] Not found class " << clsName << std::endl; + return nullobj; + } + + ani_method ctor; + if (ANI_OK != env->Class_FindMethod(cls, "", nullptr, &ctor)) { + std::cerr << "[ANI] Not found for class " << clsName << std::endl; + return nullobj; + } + + std::cerr << "[ANI] AniObjectUtils Object_New_V " << clsName << std::endl; + ani_object obj; + va_list args; + va_start(args, clsName); + ani_status status = env->Object_New_V(cls, ctor, &obj, args); + va_end(args); + if (ANI_OK != status) { + std::cerr << "[ANI] Failed to Object_New for class " << cls << std::endl; + return nullobj; + } + return obj; + } + + static ani_object Create(ani_env *env, const char *clsName, ...) + { + ani_object nullobj {}; + + ani_class cls; + if (ANI_OK != env->FindClass(clsName, &cls)) { + std::cerr << "[ANI] Not found class " << clsName << std::endl; + return nullobj; + } + + ani_method ctor; + if (ANI_OK != env->Class_FindMethod(cls, "", nullptr, &ctor)) { + std::cerr << "[ANI] Not found for class " << clsName << std::endl; + return nullobj; + } + + ani_object obj; + va_list args; + va_start(args, clsName); + ani_status status = env->Object_New_V(cls, ctor, &obj, args); + va_end(args); + if (ANI_OK != status) { + std::cerr << "[ANI] Failed to Object_New for class " << cls << std::endl; + return nullobj; + } + return obj; + } + + static ani_object Create(ani_env *env, ani_class cls, ...) + { + ani_object nullobj {}; + + ani_method ctor; + if (ANI_OK != env->Class_FindMethod(cls, "", nullptr, &ctor)) { + std::cerr << "[ANI] Not found for class" << std::endl; + return nullobj; + } + + ani_object obj; + va_list args; + va_start(args, cls); + ani_status status = env->Object_New_V(cls, ctor, &obj, args); + va_end(args); + if (ANI_OK != status) { + std::cerr << "[ANI] Failed to Object_New for class " << cls << std::endl; + return nullobj; + } + return obj; + } + + template + static ani_status Wrap(ani_env *env, ani_object object, T *nativePtr, const char *propName = "nativePtr") + { + return env->Object_SetFieldByName_Long(object, propName, reinterpret_cast(nativePtr)); + } + + template + static T *Unwrap(ani_env *env, ani_object object, const char *propName = "nativePtr") + { + ani_long nativePtr; + if (ANI_OK != env->Object_GetFieldByName_Long(object, propName, &nativePtr)) { + return nullptr; + } + return reinterpret_cast(nativePtr); + } +}; + +class AniStringUtils { +public: + static std::string ToStd(ani_env *env, ani_string ani_str) + { + ani_size strSize; + env->String_GetUTF8Size(ani_str, &strSize); + + std::vector buffer(strSize + 1); // +1 for null terminator + char *utf8_buffer = buffer.data(); + + // String_GetUTF8 Supportted by https://gitee.com/openharmony/arkcompiler_runtime_core/pulls/3416 + ani_size bytes_written = 0; + env->String_GetUTF8(ani_str, utf8_buffer, strSize + 1, &bytes_written); + + utf8_buffer[bytes_written] = '\0'; + std::string content = std::string(utf8_buffer); + return content; + } + + static ani_string ToAni(ani_env *env, const std::string &str) + { + ani_string aniStr = nullptr; + if (ANI_OK != env->String_NewUTF8(str.data(), str.size(), &aniStr)) { + std::cerr << "[ANI] Unsupported ANI_VERSION_1" << std::endl; + return nullptr; + } + return aniStr; + } +}; + +class UnionAccessor { +public: + UnionAccessor(ani_env *env, ani_object &obj) : env_(env), obj_(obj) {} + + bool IsInstanceOf(const std::string &cls_name) + { + ani_class cls; + env_->FindClass(cls_name.c_str(), &cls); + + ani_boolean ret; + env_->Object_InstanceOf(obj_, cls, &ret); + return ret; + } + + template + bool IsInstanceOfType(); + + template + bool TryConvert(T &value); + + template + bool TryConvertArray(std::vector &value); + +private: + ani_env *env_; + ani_object obj_; +}; + +template <> +inline bool UnionAccessor::IsInstanceOfType() +{ + return IsInstanceOf("Lstd/core/Boolean;"); +} + +template <> +inline bool UnionAccessor::IsInstanceOfType() +{ + return IsInstanceOf("Lstd/core/Int;"); +} + +template <> +inline bool UnionAccessor::IsInstanceOfType() +{ + return IsInstanceOf("Lstd/core/Double;"); +} + +template <> +inline bool UnionAccessor::IsInstanceOfType() +{ + return IsInstanceOf("Lstd/core/String;"); +} + +template <> +inline bool UnionAccessor::TryConvert(bool &value) +{ + if (!IsInstanceOfType()) { + return false; + } + + ani_boolean aniValue; + auto ret = env_->Object_CallMethodByName_Boolean(obj_, "unboxed", nullptr, &aniValue); + if (ret != ANI_OK) { + return false; + } + value = static_cast(aniValue); + return true; +} + +template <> +inline bool UnionAccessor::TryConvert(int &value) +{ + if (!IsInstanceOfType()) { + return false; + } + + ani_int aniValue; + auto ret = env_->Object_CallMethodByName_Int(obj_, "unboxed", nullptr, &aniValue); + if (ret != ANI_OK) { + return false; + } + value = static_cast(aniValue); + return true; +} + +template <> +inline bool UnionAccessor::TryConvert(double &value) +{ + if (!IsInstanceOfType()) { + return false; + } + + ani_double aniValue; + auto ret = env_->Object_CallMethodByName_Double(obj_, "unboxed", nullptr, &aniValue); + if (ret != ANI_OK) { + return false; + } + value = static_cast(aniValue); + return true; +} + +template <> +inline bool UnionAccessor::TryConvert(std::string &value) +{ + if (!IsInstanceOfType()) { + return false; + } + + value = AniStringUtils::ToStd(env_, static_cast(obj_)); + return true; +} + +class OptionalAccessor { +public: + OptionalAccessor(ani_env *env, ani_object &obj) : env_(env), obj_(obj) {} + + bool IsUndefined() + { + ani_boolean isUndefined; + env_->Reference_IsUndefined(obj_, &isUndefined); + return isUndefined; + } + + template + std::optional Convert(); + +private: + ani_env *env_; + ani_object obj_; +}; + +template <> +inline std::optional OptionalAccessor::Convert() +{ + if (IsUndefined()) { + return std::nullopt; + } + + ani_double aniValue; + auto ret = env_->Object_CallMethodByName_Double(obj_, "doubleValue", nullptr, &aniValue); + if (ret != ANI_OK) { + return std::nullopt; + } + auto value = static_cast(aniValue); + return value; +} + +#endif diff --git a/frameworks/js/taihe/driver_extension_context/src/DriverExtensionContext.impl.cpp b/frameworks/js/taihe/driver_extension_context/src/DriverExtensionContext.impl.cpp new file mode 100644 index 0000000..a13fba8 --- /dev/null +++ b/frameworks/js/taihe/driver_extension_context/src/DriverExtensionContext.impl.cpp @@ -0,0 +1,88 @@ +/* + * 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 "DriverExtensionContext.impl.hpp" +#include "DriverExtensionContext.proj.hpp" +#include "stdexcept" +#include "taihe/runtime.hpp" + +#include "DriverExtensionContext_ani.h" +#include "ani_utils.h" +#include "ets_extension_context.h" +#include "hilog_wrapper.h" + +namespace OHOS { +namespace AbilityRuntime { +constexpr const char *DRIVER_EXTENSION_CONTEXT_CLS = "Lapplication/DriverExtensionContext/DriverExtensionContext;"; +void UpdateDriverState([[maybe_unused]] ani_env *env, [[maybe_unused]] ani_object object) +{ + HILOG_DEBUG("UpdateDriverState begin"); + DriverExtensionContext *driverExtensionContext = AniObjectUtils::Unwrap(env, object); + if (driverExtensionContext == nullptr) { + return; + } + ErrCode innerErrorCode = driverExtensionContext->UpdateDriverState(); + if (innerErrorCode != ANI_OK) { + HILOG_ERROR("UpdateDriverState error"); + return; + } + HILOG_DEBUG("UpdateDriverState end"); +} + +ani_object CreateAniDriverExtensionContext(ani_env *env, std::shared_ptr context, + const std::shared_ptr &application) +{ + HILOG_DEBUG("CreateAniDriverExtensionContext begin"); + ani_class cls = nullptr; + ani_status status = ANI_ERROR; + if ((env->FindClass(DRIVER_EXTENSION_CONTEXT_CLS, &cls)) != ANI_OK) { + HILOG_ERROR("FindClass err: %{public}s", DRIVER_EXTENSION_CONTEXT_CLS); + return nullptr; + } + ani_object contextObj = AniObjectUtils::Create(env, cls); + std::array methods = { + ani_native_function {"UpdateDriverState", nullptr, reinterpret_cast(UpdateDriverState)}, + }; + if (ANI_OK != env->Class_BindNativeMethods(cls, methods.data(), methods.size())) { + HILOG_ERROR("Cannot bind native methods to %{public}s", DRIVER_EXTENSION_CONTEXT_CLS); + return nullptr; + } + if (ANI_OK != AniObjectUtils::Wrap(env, contextObj, context.get())) { + HILOG_ERROR("Cannot wrap native object"); + return nullptr; + } + ani_field field = nullptr; + if ((status = env->Class_FindField(cls, "nativeContext", &field)) != ANI_OK) { + HILOG_ERROR("status: %{public}d", status); + return nullptr; + } + ani_long nativeContextLong = (ani_long)context.get(); + if ((status = env->Object_SetField_Long(contextObj, field, nativeContextLong)) != ANI_OK) { + HILOG_ERROR("status: %{public}d", status); + return nullptr; + } + if (application == nullptr) { + HILOG_ERROR("application null"); + return nullptr; + } + OHOS::AbilityRuntime::CreateEtsExtensionContext(env, cls, contextObj, context, context->GetAbilityInfo()); + HILOG_DEBUG("CreateAniDriverExtensionContext end"); + return contextObj; +} +} // namespace AbilityRuntime +} // namespace OHOS +// Since these macros are auto-generate, lint will cause false positive. +// NOLINTBEGIN +// NOLINTEND diff --git a/frameworks/js/taihe/driver_extension_context/src/ani_constructor.cpp b/frameworks/js/taihe/driver_extension_context/src/ani_constructor.cpp new file mode 100644 index 0000000..947099e --- /dev/null +++ b/frameworks/js/taihe/driver_extension_context/src/ani_constructor.cpp @@ -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. + */ + +#include "taihe/runtime.hpp" +#include "DriverExtensionContext.ani.hpp" +ANI_EXPORT ani_status ANI_Constructor(ani_vm *vm, uint32_t *result) +{ + ani_env *env; + if (ANI_OK != vm->GetEnv(ANI_VERSION_1, &env)) { + return ANI_ERROR; + } + if (ANI_OK != DriverExtensionContext::ANIRegister(env)) { + std::cerr << "Error from DriverExtensionContext::ANIRegister" << std::endl; + return ANI_ERROR; + } + *result = ANI_VERSION_1; + return ANI_OK; +} diff --git a/frameworks/js/taihe/idl/ohos.driver.deviceManager.taihe b/frameworks/js/taihe/idl/ohos.driver.deviceManager.taihe new file mode 100644 index 0000000..e920f4c --- /dev/null +++ b/frameworks/js/taihe/idl/ohos.driver.deviceManager.taihe @@ -0,0 +1,104 @@ +/* + * 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. + */ + +@!sts_inject_into_module("import type { AsyncCallback } from '@ohos.base';") +@!sts_inject_into_module("import type rpc from '@ohos.rpc';") + +@!namespace("@ohos.driver.deviceManager", "deviceManager") + +@!sts_inject(""" +static { loadLibrary("device_manager_taihe_native.z") } +""") + +function queryDevices(busType: Optional): Array; + +function queryDeviceInfo(deviceId: Optional): Array; + +function queryDriverInfo(driverUid: Optional): Array; + +@!sts_inject("export native function bindDriverWithDeviceId(deviceId: long, onDisconnect: AsyncCallback): Promise;") +@gen_promise("unbindDriverWithDeviceId") +function UnbindDriverWithDeviceIdSync(deviceId: u64): i32; + +enum BusType : i32 { + USB = 1, +} + +struct Device { + busType: BusType; + deviceId: u64; + description: String; +} + +struct USBDevice { + @extends base: Device; + vendorId: i32; + productId: i32; +} + +union DeviceUnion { + t1: USBDevice; + t: Device; +} + +struct RemoteDeviceDriver { + deviceId: u64; + remote: @sts_type("rpc.IRemoteObject") Opaque; +} + +struct USBInterfaceDesc { + bInterfaceNumber: i32; + bClass: i32; + bSubClass: i32; + bProtocol: i32; +} + +struct DeviceInfo { + deviceId: u64; + isDriverMatched: bool; + driverUid: Optional; +} + +struct USBDeviceInfo { + @extends base: DeviceInfo; + vendorId: i32; + productId: i32; + interfaceDescList: Array; +} + +union DeviceInfoUnion { + t1: USBDeviceInfo; + t: DeviceInfo; +} + +struct DriverInfo { + busType: BusType; + driverUid: String; + driverName: String; + driverVersion: String; + driverSize: String; + description: String; +} + +struct USBDriverInfo { + @extends base: DriverInfo; + productIdList: Array; + vendorIdList: Array; +} + +union DriverInfoUnion { + t1: USBDriverInfo; + t: DriverInfo; +} diff --git a/frameworks/js/taihe/include/ohos.driver.deviceManager.impl.h b/frameworks/js/taihe/include/ohos.driver.deviceManager.impl.h new file mode 100644 index 0000000..b3b3b9d --- /dev/null +++ b/frameworks/js/taihe/include/ohos.driver.deviceManager.impl.h @@ -0,0 +1,69 @@ +/* + * 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_DRIVER_DEVICE_MANAGER_IMPL_H +#define OHOS_DRIVER_DEVICE_MANAGER_IMPL_H + +#include + +#include "hilog_wrapper.h" +#include "idriver_ext_mgr_callback.h" +#include "driver_ext_mgr_callback_stub.h" +#include "driver_ext_mgr_client.h" +#include "event_handler.h" +#include + +namespace OHOS { +namespace ExternalDeviceManager { +enum ErrorCode : int32_t { + PERMISSION_DENIED = 201, // Use this error code when permission is denied. + PERMISSION_NOT_SYSTEM_APP = 202, + PARAMETER_ERROR = 401, // Use this error code when the input parameter type or range does not match. + SERVICE_EXCEPTION = 22900001, // Use this error code when the service is exception. + SERVICE_EXCEPTION_NEW = 26300001, // Use this error code when the service is exception. + SERVICE_NOT_ALLOW_ACCESS = 26300002, // Use this error code when the service does not allow access. + SERVICE_NOT_BOUND = 26300003, // Use this error code when the service has no binding relationship. +}; + +ani_object BindDriverWithDeviceIdSync([[maybe_unused]] ani_env *env, ani_long deviceId, ani_object onDisconnect); + +class AsyncData : public RefBase { + public: + uint64_t deviceId; + ani_vm *vm = nullptr; + ani_env *env = nullptr; + ani_ref onDisconnect; + ani_resolver bindDeferred; + ErrMsg unBindErrMsg; + + void DeleteNapiRef(); + AsyncData(ani_vm *vm, ani_env *env): vm(vm), env(env) {} + ~AsyncData() + { + EDM_LOGE(MODULE_DEV_MGR, "Release callback data: %{public}016" PRIX64, deviceId); + DeleteNapiRef(); + } +}; + +class DeviceManagerCallback : public DriverExtMgrCallbackStub { +public: + ErrCode OnConnect(uint64_t deviceId, const sptr &drvExtObj, const ErrMsg &errMsg) override; + + ErrCode OnDisconnect(uint64_t deviceId, const ErrMsg &errMsg) override; + + ErrCode OnUnBind(uint64_t deviceId, const ErrMsg &errMsg) override; +}; +} +} +#endif diff --git a/frameworks/js/taihe/src/ani_constructor.cpp b/frameworks/js/taihe/src/ani_constructor.cpp new file mode 100644 index 0000000..405e0d3 --- /dev/null +++ b/frameworks/js/taihe/src/ani_constructor.cpp @@ -0,0 +1,54 @@ +/* + * 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 "taihe/runtime.hpp" +#include "ohos.driver.deviceManager.ani.hpp" +#include "hilog_wrapper.h" +#include "ohos.driver.deviceManager.impl.h" + +using namespace OHOS::ExternalDeviceManager; + +ANI_EXPORT ani_status ANI_Constructor(ani_vm *vm, uint32_t *result) +{ + ani_env *env; + if (ANI_OK != vm->GetEnv(ANI_VERSION_1, &env)) { + return ANI_ERROR; + } + if (ANI_OK != ohos::driver::deviceManager::ANIRegister(env)) { + EDM_LOGE(MODULE_DEV_MGR, "Error from ohos::driver::deviceManager::ANIRegister"); + return ANI_ERROR; + } + + static const char *namespaceName = "L@ohos/driver/deviceManager/deviceManager;"; + ani_namespace ns; + if (ANI_OK != env->FindNamespace(namespaceName, &ns)) { + EDM_LOGE(MODULE_DEV_MGR, "Not found '%{public}s'", namespaceName); + return ANI_NOT_FOUND; + } + + std::array methods = { + ani_native_function {"bindDriverWithDeviceId", nullptr, + reinterpret_cast(OHOS::ExternalDeviceManager::BindDriverWithDeviceIdSync)}, + }; + + if (ANI_OK != env->Namespace_BindNativeFunctions(ns, methods.data(), methods.size())) { + EDM_LOGE(MODULE_DEV_MGR, "Cannot bind native methods to '%{public}s'", namespaceName); + return ANI_NOT_FOUND; + }; + + *result = ANI_VERSION_1; + return ANI_OK; +} + diff --git a/frameworks/js/taihe/src/ohos.driver.deviceManager.impl.cpp b/frameworks/js/taihe/src/ohos.driver.deviceManager.impl.cpp new file mode 100644 index 0000000..52c5bdc --- /dev/null +++ b/frameworks/js/taihe/src/ohos.driver.deviceManager.impl.cpp @@ -0,0 +1,623 @@ +/* + * 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 + +#include "ohos.driver.deviceManager.impl.hpp" +#include "ani_remote_object.h" +#include "ohos.driver.deviceManager.impl.h" +#include "ohos.driver.deviceManager.proj.hpp" +#include "stdexcept" +#include "taihe/runtime.hpp" +#include "edm_errors.h" + +using namespace taihe; +using namespace ohos::driver::deviceManager; +namespace OHOS { +namespace ExternalDeviceManager { +constexpr int32_t ANI_SCOPE_SIZE = 16; +constexpr uint16_t TWO_PARAMETERS = 2; + +static const std::map ERROR_MESSAGES = { + {SERVICE_EXCEPTION, "ExternalDeviceManager service exception."}, + {PERMISSION_DENIED, "Permission denied."}, + {PERMISSION_NOT_SYSTEM_APP, "Permission denied. A non-system application cannot call a system API."}, + {PARAMETER_ERROR, "The parameter check failed."}, + {SERVICE_EXCEPTION_NEW, "ExternalDeviceManager service exception."}, + {SERVICE_NOT_ALLOW_ACCESS, "Driver does not allow application access."}, + {SERVICE_NOT_BOUND, "There is no binding relationship between the application and the driver."} +}; +static std::mutex mapMutex; +static std::map> g_callbackMap = {}; +static OHOS::ExternalDeviceManager::DriverExtMgrClient &g_edmClient = + OHOS::ExternalDeviceManager::DriverExtMgrClient::GetInstance(); +static OHOS::sptr g_edmCallback = new (std::nothrow) DeviceManagerCallback {}; +static thread_local std::shared_ptr mainHandler = nullptr; + +static bool SendEventToMainThread(const std::function func) +{ + EDM_LOGD(MODULE_DEV_MGR, "SendEventToMainThread begin"); + if (func == nullptr) { + EDM_LOGE(MODULE_DEV_MGR, "func is nullptr!"); + return false; + } + + if (!mainHandler) { + auto runner = OHOS::AppExecFwk::EventRunner::GetMainEventRunner(); + if (!runner) { + EDM_LOGE(MODULE_DEV_MGR, "get main event runner failed!"); + return false; + } + mainHandler = std::make_shared(runner); + } + mainHandler->PostTask(func, "", 0, OHOS::AppExecFwk::EventQueue::Priority::HIGH, {}); + EDM_LOGD(MODULE_DEV_MGR, "SendEventToMainThread end"); + return true; +} + +void AsyncData::DeleteNapiRef() +{ + if (env == nullptr) { + return; + } + sptr guard(this); + + auto task = [guard]() { + EDM_LOGD(MODULE_DEV_MGR, "DeleteNapiRef async task is run."); + + AsyncData* data = guard.GetRefPtr(); + ani_env *taskEnv = nullptr; + + bool attached = false; + ani_options aniArgs {0, nullptr}; + if (ANI_ERROR == data->vm->AttachCurrentThread(&aniArgs, ANI_VERSION_1, &taskEnv)) { + if (ANI_OK != data->vm->GetEnv(ANI_VERSION_1, &taskEnv)) { + EDM_LOGE(MODULE_DEV_MGR, "GetEnv failed"); + return; + } + } else { + attached = true; + } + if (data->onDisconnect != nullptr) { + taskEnv->GlobalReference_Delete(data->onDisconnect); + data->onDisconnect = nullptr; + } + if (attached) { + data->vm->DetachCurrentThread(); + } + data->env = nullptr; + data->vm = nullptr; + }; + if (!SendEventToMainThread(task)) { + EDM_LOGE(MODULE_DEV_MGR, "delete napi ref send event failed."); + guard = nullptr; + } +} + +static ani_object GetCallbackResult(ani_env *env, uint64_t deviceId, const sptr &drvExtObj) +{ + ani_long id = deviceId; + ani_ref remoteObj; + if (drvExtObj == nullptr) { + env->GetUndefined(&remoteObj); + EDM_LOGE(MODULE_DEV_MGR, "Remote obj is null."); + } else { + EDM_LOGI(MODULE_DEV_MGR, "Remote obj create."); + remoteObj = ANI_ohos_rpc_CreateJsRemoteObject(env, drvExtObj); + } + + ani_object result {}; + static const char *namespaceName = "L@ohos/driver/deviceManager/deviceManager;"; + ani_namespace ns; + if (ANI_OK != env->FindNamespace(namespaceName, &ns)) { + EDM_LOGE(MODULE_DEV_MGR, "Not found '%{public}s'", namespaceName); + return result; + } + + ani_class cls; + if (ANI_OK != env->Namespace_FindClass(ns, "LRemoteDeviceDriver_inner;", &cls)) { + EDM_LOGE(MODULE_DEV_MGR, "FindClass \"LRemoteDeviceDriver_inner;\" failed"); + return result; + } + + ani_method ctor; + if (ANI_OK != env->Class_FindMethod(cls, "", nullptr, &ctor)) { + EDM_LOGE(MODULE_DEV_MGR, "Class_FindMethod 'constructor' failed"); + return result; + } + + if (ANI_OK != env->Object_New(cls, ctor, &result, id, remoteObj)) { + EDM_LOGE(MODULE_DEV_MGR, "Object_New failed"); + return result; + } + return result; +} + +static std::optional GetNapiError(int32_t errorCode) +{ + auto iter = ERROR_MESSAGES.find(errorCode); + if (iter != ERROR_MESSAGES.end()) { + return iter->second; + } + return std::nullopt; +} + +static ani_object ConvertToBusinessError(ani_env *env, const ErrMsg &errMsg) +{ + ani_ref businessError = nullptr; + if (errMsg.IsOk()) { + env->GetUndefined(&businessError); + return reinterpret_cast(businessError); + } + + auto msgString = GetNapiError(SERVICE_EXCEPTION); + if (!msgString) { + env->GetUndefined(&businessError); + return reinterpret_cast(businessError); + } + + ani_object errorObject = nullptr; + EDM_LOGD(MODULE_DEV_MGR, "Begin ThrowBusinessError."); + static const char *errorClsName = "L@ohos/base/BusinessError;"; + ani_class cls {}; + if (ANI_OK != env->FindClass(errorClsName, &cls)) { + EDM_LOGE(MODULE_DEV_MGR, "find class BusinessError %{public}s failed", errorClsName); + return errorObject; + } + ani_method ctor; + if (ANI_OK != env->Class_FindMethod(cls, "", ":V", &ctor)) { + EDM_LOGE(MODULE_DEV_MGR, "find method BusinessError.constructor failed"); + return errorObject; + } + + if (ANI_OK != env->Object_New(cls, ctor, &errorObject)) { + EDM_LOGE(MODULE_DEV_MGR, "create BusinessError object failed"); + return errorObject; + } + + ani_double aniErrCode = static_cast(SERVICE_EXCEPTION); + ani_string errMsgStr; + if (ANI_OK != env->String_NewUTF8(msgString->c_str(), msgString->size(), &errMsgStr)) { + EDM_LOGE(MODULE_DEV_MGR, "convert errMsg to ani_string failed"); + return errorObject; + } + if (ANI_OK != env->Object_SetFieldByName_Double(errorObject, "code", aniErrCode)) { + EDM_LOGE(MODULE_DEV_MGR, "set error code failed"); + return errorObject; + } + if (ANI_OK != env->Object_SetPropertyByName_Ref(errorObject, "message", errMsgStr)) { + EDM_LOGE(MODULE_DEV_MGR, "set error message failed"); + return errorObject; + } + + return errorObject; +} + +static ani_object ConvertToObjectDeviceId(ani_env *env, const uint64_t deviceId) +{ + ani_object retObject = nullptr; + ani_long aniDeviceId = deviceId; + ani_class cls {}; + if (ANI_OK != env->FindClass("Lstd/core/Long;", &cls)) { + EDM_LOGE(MODULE_DEV_MGR, "find class Long Lstd/core/Long failed"); + return retObject; + } + ani_method ctor; + if (ANI_OK != env->Class_FindMethod(cls, "", nullptr, &ctor)) { + EDM_LOGE(MODULE_DEV_MGR, "find method Long.constructor failed"); + return retObject; + } + if (ANI_OK != env->Object_New(cls, ctor, &retObject, aniDeviceId)) { + EDM_LOGE(MODULE_DEV_MGR, "create Long object failed"); + } + return retObject; +} + +ErrCode DeviceManagerCallback::OnConnect(uint64_t deviceId, const sptr &drvExtObj, const ErrMsg &errMsg) +{ + EDM_LOGI(MODULE_DEV_MGR, "bind device callback: %{public}016" PRIX64, deviceId); + std::lock_guard mapLock(mapMutex); + if (g_callbackMap.count(deviceId) == 0) { + EDM_LOGE(MODULE_DEV_MGR, "device OnConnect is null"); + return EDM_NOK; + } + + auto data = g_callbackMap[deviceId]; + if (!errMsg.IsOk()) { + g_callbackMap.erase(deviceId); + } + auto task = [data, drvExtObj, errMsg]() { + EDM_LOGE(MODULE_DEV_MGR, "OnConnect async task is run."); + ani_env *env = nullptr; + ani_options aniArgs {0, nullptr}; + int32_t ret = data->vm->AttachCurrentThread(&aniArgs, ANI_VERSION_1, &env); + if (ANI_ERROR == ret) { + if (ANI_OK != data->vm->GetEnv(ANI_VERSION_1, &env)) { + EDM_LOGE(MODULE_DEV_MGR, "GetEnv failed"); + } + } + if (ANI_OK != env->CreateLocalScope(ANI_SCOPE_SIZE)) { + EDM_LOGE(MODULE_DEV_MGR, "CreateLocalScope failed"); + if (ret == ANI_OK) { + data->vm->DetachCurrentThread(); + } + } + ani_object result = GetCallbackResult(env, data->deviceId, drvExtObj); + ani_object err = ConvertToBusinessError(env, errMsg); + if (data->bindDeferred != nullptr) { + if (errMsg.IsOk()) { + env->PromiseResolver_Resolve(data->bindDeferred, result); + } else { + env->PromiseResolver_Reject(data->bindDeferred, reinterpret_cast(err)); + } + EDM_LOGD(MODULE_DEV_MGR, "bind device promise finish."); + } + env->DestroyLocalScope(); + if (ret == ANI_OK) { + data->vm->DetachCurrentThread(); + } + }; + if (!SendEventToMainThread(task)) { + EDM_LOGE(MODULE_DEV_MGR, "OnConnect send event failed."); + return EDM_NOK; + } + return EDM_OK; +} + +ErrCode DeviceManagerCallback::OnDisconnect(uint64_t deviceId, const ErrMsg &errMsg) +{ + EDM_LOGI(MODULE_DEV_MGR, "device onDisconnect: %{public}016" PRIX64, deviceId); + std::lock_guard mapLock(mapMutex); + if (g_callbackMap.count(deviceId) == 0) { + EDM_LOGE(MODULE_DEV_MGR, "device callback map is null"); + return EDM_NOK; + } + + auto data = g_callbackMap[deviceId]; + g_callbackMap.erase(deviceId); + if (data->onDisconnect == nullptr) { + EDM_LOGE(MODULE_DEV_MGR, "device callback is null"); + return EDM_NOK; + } + data->IncStrongRef(nullptr); + auto task = [data, errMsg]() { + EDM_LOGD(MODULE_DEV_MGR, "OnDisconnect async task is run."); + ani_env *env = nullptr; + ani_options aniArgs {0, nullptr}; + int32_t ret = data->vm->AttachCurrentThread(&aniArgs, ANI_VERSION_1, &env); + if (ret != ANI_OK && data->vm->GetEnv(ANI_VERSION_1, &env) != ANI_OK) { + EDM_LOGE(MODULE_DEV_MGR, "Failed to get JNI environment."); + data->DecStrongRef(nullptr); + } + if (ANI_OK != env->CreateLocalScope(ANI_SCOPE_SIZE)) { + EDM_LOGE(MODULE_DEV_MGR, "Failed to create local scope."); + data->DecStrongRef(nullptr); + if (ret == ANI_OK) { + data->vm->DetachCurrentThread(); + } + } + ani_ref argv[] = {ConvertToBusinessError(env, errMsg), ConvertToObjectDeviceId(env, data->deviceId)}; + ani_ref result; + auto fnObj = reinterpret_cast(data->onDisconnect); + auto callRet = env->FunctionalObject_Call(fnObj, TWO_PARAMETERS, argv, &result); + EDM_LOGD(MODULE_DEV_MGR, "OnDisconnect callback finish ret: %{public}u", callRet); + env->DestroyLocalScope(); + data->DecStrongRef(nullptr); + if (ret == ANI_OK) { + data->vm->DetachCurrentThread(); + } + }; + if (!SendEventToMainThread(task)) { + EDM_LOGE(MODULE_DEV_MGR, "OnDisconnect send event failed."); + data->DecStrongRef(nullptr); + return EDM_NOK; + } + return EDM_OK; +} + +ErrCode DeviceManagerCallback::OnUnBind(uint64_t deviceId, const ErrMsg &errMsg) +{ + EDM_LOGI(MODULE_DEV_MGR, "unbind device callback: %{public}016" PRIX64, deviceId); + std::lock_guard mapLock(mapMutex); + if (g_callbackMap.count(deviceId) == 0) { + EDM_LOGE(MODULE_DEV_MGR, "device unbind map is null"); + return EDM_NOK; + } + + auto asyncData = g_callbackMap[deviceId]; + if (asyncData == nullptr) { + EDM_LOGE(MODULE_DEV_MGR, "device unbind is null"); + return EDM_NOK; + } + asyncData->unBindErrMsg = errMsg; + return EDM_OK; +} + +static ohos::driver::deviceManager::DeviceUnion ConvertToDevice(std::shared_ptr &deviceData) +{ + if (deviceData->busType == OHOS::ExternalDeviceManager::BusType::BUS_TYPE_USB) { + std::shared_ptr usb = + std::static_pointer_cast(deviceData); + auto taiheUsbDevice = ohos::driver::deviceManager::USBDevice{ + { + std::move(ohos::driver::deviceManager::BusType::key_t::USB), + std::move(deviceData->deviceId), + std::move(deviceData->descripton) + }, + std::move(usb->vendorId), + std::move(usb->productId) + }; + return ohos::driver::deviceManager::DeviceUnion( + ::taihe::static_tag<::ohos::driver::deviceManager::DeviceUnion::tag_t::t1>, taiheUsbDevice); + } else { + auto taiheDevice = ohos::driver::deviceManager::Device{ + std::move(ohos::driver::deviceManager::BusType::key_t::USB), + std::move(deviceData->deviceId), + std::move(deviceData->descripton) + }; + return ohos::driver::deviceManager::DeviceUnion( + ::taihe::static_tag<::ohos::driver::deviceManager::DeviceUnion::tag_t::t>, taiheDevice); + } +} +array queryDevices(optional_view busType) +{ + EDM_LOGI(MODULE_DEV_MGR, "queryDevices start"); + bool isBusTypeSet = busType.has_value(); + int32_t busTypeVal = isBusTypeSet ? busType.value() : OHOS::ExternalDeviceManager::BusType::BUS_TYPE_USB; + EDM_LOGI(MODULE_DEV_MGR, "bus type is %{public}d", busTypeVal); + std::vector> devices; + std::vector resultArray; + UsbErrCode retCode = g_edmClient.QueryDevice(busTypeVal, devices); + if (retCode != UsbErrCode::EDM_OK) { + if (retCode == UsbErrCode::EDM_ERR_NO_PERM) { + set_business_error(PERMISSION_DENIED, "queryDevice: no permission"); + } else { + EDM_LOGD(MODULE_DEV_MGR, "queryDevices error code: %{public}d", retCode); + set_business_error(SERVICE_EXCEPTION, "Query device service fail"); + } + return array(resultArray); + } + for (auto &deviceItem : devices) { + resultArray.push_back(ConvertToDevice(deviceItem)); + } + EDM_LOGI(MODULE_DEV_MGR, "query device finish"); + return array(resultArray); +} + +static ohos::driver::deviceManager::USBInterfaceDesc ParseToUSBInterfaceDesc( + std::shared_ptr &usbInterfaceDesc) +{ + return { + .bInterfaceNumber = usbInterfaceDesc->bInterfaceNumber, + .bClass = usbInterfaceDesc->bClass, + .bSubClass = usbInterfaceDesc->bSubClass, + .bProtocol = usbInterfaceDesc->bProtocol, + }; +} + +static ohos::driver::deviceManager::DeviceInfoUnion ConvertToDeviceInfo(std::shared_ptr &deviceInfoData) +{ + EDM_LOGD(MODULE_DEV_MGR, "ConvertToDeviceInfo start"); + auto busType = DeviceInfoData::GetBusTypeByDeviceId(deviceInfoData->deviceId); + if (busType == OHOS::ExternalDeviceManager::BusType::BUS_TYPE_USB) { + std::shared_ptr usbDeviceInfo = std::static_pointer_cast(deviceInfoData); + optional driverUid; + if (deviceInfoData->isDriverMatched) { + driverUid = optional(std::in_place, deviceInfoData->driverUid); + } else { + driverUid = optional(std::nullopt); + } + std::vector taiheInterfaceDesc; + for (auto &interfaceDesc : usbDeviceInfo->interfaceDescList) { + taiheInterfaceDesc.push_back(ParseToUSBInterfaceDesc(interfaceDesc)); + } + array<::ohos::driver::deviceManager::USBInterfaceDesc> structDescList(taiheInterfaceDesc); + auto taiheDeviceInfoData = ohos::driver::deviceManager::USBDeviceInfo{ + { + std::move(deviceInfoData->deviceId), + std::move(deviceInfoData->isDriverMatched), + std::move(driverUid), + }, + std::move(usbDeviceInfo->vendorId), + std::move(usbDeviceInfo->productId), + std::move(structDescList), + }; + return ohos::driver::deviceManager::DeviceInfoUnion( + ::taihe::static_tag<::ohos::driver::deviceManager::DeviceInfoUnion::tag_t::t1>, taiheDeviceInfoData); + } else { + auto driverUid = deviceInfoData->driverUid.empty() ? optional(std::nullopt) : + optional(std::in_place_t{}, deviceInfoData->driverUid); + auto taiheDeviceInfoData = ohos::driver::deviceManager::DeviceInfo{ + std::move(deviceInfoData->deviceId), + std::move(deviceInfoData->isDriverMatched), + std::move(driverUid) + }; + return ohos::driver::deviceManager::DeviceInfoUnion( + ::taihe::static_tag<::ohos::driver::deviceManager::DeviceInfoUnion::tag_t::t>, taiheDeviceInfoData); + } +} + +array queryDeviceInfo(optional_view deviceId) +{ + EDM_LOGD(MODULE_DEV_MGR, "queryDeviceInfo start"); + std::vector> deviceInfos; + int32_t ret; + bool isDeviceIdSet = deviceId.has_value(); + if (isDeviceIdSet) { + ret = g_edmClient.QueryDeviceInfo(deviceId.value(), deviceInfos); + } else { + ret = g_edmClient.QueryDeviceInfo(deviceInfos); + } + std::vector resultArray; + if (ret != UsbErrCode::EDM_OK) { + if (ret == UsbErrCode::EDM_ERR_NOT_SYSTEM_APP) { + set_business_error(PERMISSION_NOT_SYSTEM_APP, "queryDeviceInfo: none system app"); + } else if (ret == UsbErrCode::EDM_ERR_NO_PERM) { + set_business_error(PERMISSION_DENIED, "queryDeviceInfo: no permission"); + } else { + set_business_error(SERVICE_EXCEPTION_NEW, "Query device info service fail"); + } + return array(resultArray); + } + + for (auto &deviceInfoItem : deviceInfos) { + resultArray.push_back(ConvertToDeviceInfo(deviceInfoItem)); + } + + return array(resultArray); +} + +static ohos::driver::deviceManager::DriverInfoUnion ConvertToDriverInfo(std::shared_ptr &driverInfoData) +{ + EDM_LOGD(MODULE_DEV_MGR, "ConvertToDriverInfo start"); + if (driverInfoData->busType == OHOS::ExternalDeviceManager::BusType::BUS_TYPE_USB) { + std::shared_ptr usbDriverInfo = std::static_pointer_cast(driverInfoData); + + std::vector pids; + for (auto pidItem : usbDriverInfo->pids) { + pids.push_back(pidItem); + } + array pidList(pids); + + std::vector vids; + for (auto vidItem : usbDriverInfo->vids) { + vids.push_back(vidItem); + } + array vidList(vids); + + auto taiheUSBDriverInfoData = ohos::driver::deviceManager::USBDriverInfo{ + { + std::move(ohos::driver::deviceManager::BusType::key_t::USB), + std::move(driverInfoData->driverUid), + std::move(driverInfoData->driverName), + std::move(driverInfoData->version), + std::move(driverInfoData->bundleSize), + std::move(driverInfoData->description), + }, + std::move(pidList), + std::move(vidList), + }; + return ohos::driver::deviceManager::DriverInfoUnion( + ::taihe::static_tag<::ohos::driver::deviceManager::DriverInfoUnion::tag_t::t1>, taiheUSBDriverInfoData); + } else { + auto taiheDriverInfoData = ohos::driver::deviceManager::DriverInfo{ + std::move(ohos::driver::deviceManager::BusType::key_t::USB), + std::move(driverInfoData->driverUid), + std::move(driverInfoData->driverName), + std::move(driverInfoData->version), + std::move(driverInfoData->bundleSize), + std::move(driverInfoData->description), + }; + return ohos::driver::deviceManager::DriverInfoUnion( + ::taihe::static_tag<::ohos::driver::deviceManager::DriverInfoUnion::tag_t::t>, taiheDriverInfoData); + } +} + +array queryDriverInfo(optional_view driverUid) +{ + EDM_LOGD(MODULE_DEV_MGR, "queryDriverInfo start"); + std::vector> driverInfos; + std::vector resultArray; + int32_t ret; + bool isDriverUidSet = driverUid.has_value(); + if (isDriverUidSet) { + ret = g_edmClient.QueryDriverInfo(driverUid.value().c_str(), driverInfos); + } else { + ret = g_edmClient.QueryDriverInfo(driverInfos); + } + + if (ret != UsbErrCode::EDM_OK) { + if (ret == UsbErrCode::EDM_ERR_NOT_SYSTEM_APP) { + set_business_error(PERMISSION_NOT_SYSTEM_APP, "queryDriverInfo: none system app"); + } else if (ret == UsbErrCode::EDM_ERR_NO_PERM) { + set_business_error(PERMISSION_DENIED, "queryDriverInfo: no permission"); + } else { + set_business_error(SERVICE_EXCEPTION_NEW, "Query driver info service fail"); + } + return array(resultArray); + } + + for (auto &driverInfoItem : driverInfos) { + resultArray.push_back(ConvertToDriverInfo(driverInfoItem)); + } + return array(resultArray); +} + +ani_object BindDriverWithDeviceIdSync([[maybe_unused]] ani_env *env, ani_long deviceId, ani_object onDisconnect) +{ + EDM_LOGI(MODULE_DEV_MGR, "Enter BindDriverWithDeviceIdSync:%{public}016" PRIX64, static_cast(deviceId)); + std::lock_guard mapLock(mapMutex); + UsbErrCode retCode = g_edmClient.BindDriverWithDeviceId(deviceId, g_edmCallback); + if (retCode != UsbErrCode::EDM_OK) { + if (retCode == UsbErrCode::EDM_ERR_NO_PERM) { + set_business_error(PERMISSION_DENIED, "bindDevice: no permission"); + } else if (retCode == UsbErrCode::EDM_ERR_SERVICE_NOT_ALLOW_ACCESS) { + set_business_error(SERVICE_NOT_ALLOW_ACCESS, "bindDevice: service not allowed"); + } else { + set_business_error(SERVICE_EXCEPTION_NEW, "bindDevice service failed"); + } + return nullptr; + } + + ani_vm *vm = nullptr; + if (ANI_OK != env->GetVM(&vm)) { + EDM_LOGE(MODULE_DEV_MGR, "GetVM failed."); + return nullptr; + } + sptr data = new (std::nothrow) AsyncData(vm, env); + if (data == nullptr) { + set_business_error(PARAMETER_ERROR, "malloc callback data fail"); + return nullptr; + } + + data->env = env; + data->deviceId = deviceId; + if (ANI_OK != env->GlobalReference_Create(reinterpret_cast(onDisconnect), &data->onDisconnect)) { + set_business_error(PARAMETER_ERROR, "GlobalReference_Create failed"); + return nullptr; + } + + ani_object promise; + env->Promise_New(&data->bindDeferred, &promise); + g_callbackMap[data->deviceId] = data; + return promise; +} + +int32_t UnbindDriverWithDeviceIdSync(uint64_t deviceId) +{ + EDM_LOGI(MODULE_DEV_MGR, "Enter unbindDevice:%{public}016" PRIX64, deviceId); + UsbErrCode retCode = g_edmClient.UnbindDriverWithDeviceId(deviceId); + if (retCode != UsbErrCode::EDM_OK) { + if (retCode == UsbErrCode::EDM_ERR_NO_PERM) { + set_business_error(PERMISSION_DENIED, "unbindDevice: no permission"); + } else if (retCode == UsbErrCode::EDM_ERR_SERVICE_NOT_BOUND) { + set_business_error(SERVICE_NOT_BOUND, "unbindDevice: there is no binding relationship"); + } else { + set_business_error(SERVICE_EXCEPTION_NEW, "unbindDevice service failed"); + } + } + return retCode; +} +} +} // namespace + +// Since these macros are auto-generate, lint will cause false positive. +// NOLINTBEGIN +TH_EXPORT_CPP_API_queryDevices(OHOS::ExternalDeviceManager::queryDevices); +TH_EXPORT_CPP_API_queryDeviceInfo(OHOS::ExternalDeviceManager::queryDeviceInfo); +TH_EXPORT_CPP_API_queryDriverInfo(OHOS::ExternalDeviceManager::queryDriverInfo); +TH_EXPORT_CPP_API_UnbindDriverWithDeviceIdSync(OHOS::ExternalDeviceManager::UnbindDriverWithDeviceIdSync); +// NOLINTEND diff --git a/frameworks/js/taihe/test/xts/module.json5 b/frameworks/js/taihe/test/xts/module.json5 new file mode 100644 index 0000000..a26bfe6 --- /dev/null +++ b/frameworks/js/taihe/test/xts/module.json5 @@ -0,0 +1,57 @@ +/* + * 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. + */ + +{ + "module": { + "name": "entry", + "type": "entry", + "description": "$string:module_desc", + "mainElement": "EntryAbility", + "deviceTypes": [], + "deliveryWithInstall": true, + "installationFree": false, + "requestPermissions": [ + { + "name": "ohos.permission.ACCESS_EXTENSIONAL_DEVICE_DRIVER" + }, + { + "name": "ohos.permission.ACCESS_DDK_DRIVERS" + } + ], + "pages": "$profile:main_pages", + "abilities": [ + { + "name": "EntryAbility", + "srcEntry": "./ets/entryability/EntryAbility.ets", + "description": "$string:EntryAbility_desc", + "icon": "$media:layered_image", + "label": "$string:EntryAbility_label", + "startWindowIcon": "$media:startIcon", + "startWindowBackground": "$color:start_window_background", + "exported": true, + "skills": [ + { + "entities": [ + "entity.system.home" + ], + "actions": [ + "action.system.home" + ] + } + ] + } + ] + } +} diff --git a/frameworks/js/taihe/test/xts/src/test/DeviceManager.test.ets b/frameworks/js/taihe/test/xts/src/test/DeviceManager.test.ets new file mode 100644 index 0000000..759d28d --- /dev/null +++ b/frameworks/js/taihe/test/xts/src/test/DeviceManager.test.ets @@ -0,0 +1,430 @@ +/* + * 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 { describe, it, expect, TestType, Size, Level, beforeAll, beforeEach, afterEach, afterAll } from "../../index"; +import hilog from '@ohos.hilog'; +import deviceManager from '@ohos.driver.deviceManager'; +import { BusinessError } from '@ohos.base'; +import Utils from './Util.test'; + +const TAG = 0x0000; + +function isUsbDevice(deviceId : long) { + return (deviceId & 0x00000000FFFFFFFF) === deviceManager.BusType.USB; +} + +function assertInterfaceDesc(interfaceDesc : deviceManager.USBInterfaceDesc) { + hilog.info(TAG, 'testTag', 'interfaceDesc.bInterfaceNumber:' + interfaceDesc.bInterfaceNumber); + expect(typeof(interfaceDesc.bInterfaceNumber)).assertEqual('number'); + hilog.info(TAG, 'testTag', 'interfaceDesc.bClass:' + interfaceDesc.bClass); + expect(typeof(interfaceDesc.bClass)).assertEqual('number'); + hilog.info(TAG, 'testTag', 'interfaceDesc.bSubClass:' + interfaceDesc.bSubClass); + expect(typeof(interfaceDesc.bSubClass)).assertEqual('number'); + hilog.info(TAG, 'testTag', 'interfaceDesc.bProtocol:' + interfaceDesc.bProtocol); + expect(typeof(interfaceDesc.bProtocol)).assertEqual('number'); +} + +function assertUsbDeviceInfoExt(usbDeviceInfo : deviceManager.USBDeviceInfo) { + hilog.info(TAG, 'testTag', 'usbDeviceInfo.vendorId:' + usbDeviceInfo.vendorId); + expect(typeof(usbDeviceInfo.vendorId)).assertEqual('number'); + hilog.info(TAG, 'testTag', 'usbDeviceInfo.productId:' + usbDeviceInfo.productId); + expect(typeof(usbDeviceInfo.productId)).assertEqual('number'); + expect(Array.isArray(usbDeviceInfo.interfaceDescList)).assertTrue(); + for (const desc of usbDeviceInfo.interfaceDescList) { + assertInterfaceDesc(desc); + } +} + +function assertDeviceInfo(deviceInfo : deviceManager.DeviceInfo) { + hilog.info(TAG, 'testTag', 'deviceInfo.deviceId:' + deviceInfo.deviceId); + expect(typeof(deviceInfo.deviceId)).assertEqual('number'); + hilog.info(TAG, 'testTag', 'deviceInfo.isDriverMatched:' + deviceInfo.isDriverMatched); + expect(typeof(deviceInfo.isDriverMatched)).assertEqual('boolean'); + if (deviceInfo.isDriverMatched) { + hilog.info(TAG, 'testTag', 'deviceInfo.driverUid:' + deviceInfo.driverUid); + expect(typeof(deviceInfo.driverUid)).assertEqual('string'); + } + if (isUsbDevice(deviceInfo.deviceId)) { + let deviceUsb = deviceInfo as deviceManager.USBDeviceInfo + assertUsbDeviceInfoExt(deviceUsb) + } +} + +function assertDriverInfo(driverInfo : deviceManager.DriverInfo) { + hilog.info(TAG, 'testTag', 'driverInfo.busType:' + driverInfo.busType); + expect(typeof(driverInfo.busType)).assertEqual('number'); + hilog.info(TAG, 'testTag', 'driverInfo.driverUid:' + driverInfo.driverUid); + expect(typeof(driverInfo.driverUid)).assertEqual('string'); + hilog.info(TAG, 'testTag', 'driverInfo.driverName:' + driverInfo.driverName); + expect(typeof(driverInfo.driverName)).assertEqual('string'); + hilog.info(TAG, 'testTag', 'driverInfo.driverVersion:' + driverInfo.driverVersion); + expect(typeof(driverInfo.driverVersion)).assertEqual('string'); + hilog.info(TAG, 'testTag', 'driverInfo.driverSize:' + driverInfo.driverSize); + expect(typeof(driverInfo.driverSize)).assertEqual('string'); + hilog.info(TAG, 'testTag', 'driverInfo.description:' + driverInfo.description); + expect(typeof(driverInfo.description)).assertEqual('string'); + if (driverInfo.busType === deviceManager.BusType.USB) { + let driverInfoUsb = driverInfo as deviceManager.USBDriverInfo + hilog.info(TAG, 'testTag', 'driverInfo.productIdList:' + JSON.stringify(driverInfoUsb.productIdList)); + expect(Array.isArray(driverInfoUsb.productIdList)).assertTrue(); + hilog.info(TAG, 'testTag', 'driverInfo.vendorIdList:' + JSON.stringify(driverInfoUsb.vendorIdList)); + expect(Array.isArray(driverInfoUsb.vendorIdList)).assertTrue(); + for (const productId of driverInfoUsb.productIdList) { + expect(typeof(productId)).assertEqual('number'); + } + for (const vendorId of driverInfoUsb.vendorIdList) { + expect(typeof(vendorId)).assertEqual('number'); + } + } +} + +export default function DeviceManagerJsTest() { + describe("DeviceManagerJsTest", ():void => { + let deviceId: long = 0; + beforeAll(() => { + hilog.info(TAG, 'testTag', 'beforeAll called'); + try { + let devices = deviceManager.queryDevices(deviceManager.BusType.USB); + if (devices != null && devices.length > 0 && devices[0] != null) { + deviceId = devices[0].deviceId; + hilog.info(TAG, 'testTag', 'deviceId: ' + devices[0].deviceId); + hilog.info(TAG, 'testTag', 'busType: ' + devices[0].busType); + hilog.info(TAG, 'testTag', 'description: ' + devices[0].description); + } else { + hilog.info(TAG, 'testTag', 'No devices found.'); + } + } catch (err) { + hilog.info(TAG, 'testTag', 'err: ' + err); + } + + if (deviceId == 0) { + hilog.info(TAG, 'testTag', 'Device ID has not been set.'); + } + hilog.info(TAG, 'testTag', 'beforeAll called end'); + }) + afterAll(() => { + hilog.info(TAG, 'testTag', 'afterAll called'); + }) + + beforeEach(() => { + hilog.info(TAG, 'testTag', 'beforeEach called'); + }) + + afterEach(() => { + hilog.info(TAG, 'testTag', 'afterEach called'); + }) + const PARAMETER_ERROR_CODE = 401 + const SERVICE_EXCEPTION_CODE = 22900001 + const SERVICE_EXCEPTION_CODE_NEW = 26300001 + const SERVICE_NOT_ALLOW_ACCESS = 26300002 + const SERVICE_NOT_BOUND = 26300003 + + /* + * @tc.number : SUB_Driver_Ext_DeviceManagerAPIFunc_0101 + * @tc.name : testQueryDevices001 + * @tc.desc : verify queryDevice result + */ + it("testQueryDevices001", TestType.FUNCTION | Size.MEDIUMTEST | Level.LEVEL3, ():void => { + hilog.info(TAG, 'testTag', '----------------------testQueryDevices001---------------------------'); + if (deviceId == 0) { + hilog.info(TAG, 'testTag', 'Device ID has not been set.'); + expect(true).assertTrue(); + return; + } + try { + let devices = deviceManager.queryDevices(deviceManager.BusType.USB); + hilog.info(TAG, 'testTag', 'Test case testQueryDevices001 ret : ' + JSON.stringify(devices)); + expect(devices != null).assertEqual(true); + expect(devices.length > 0).assertEqual(true); + let deviceUsb = devices[0] as deviceManager.USBDevice; + expect(deviceUsb != null).assertEqual(true); + expect(deviceUsb.deviceId != null).assertEqual(true); + expect(deviceUsb.description != null).assertEqual(true); + expect(deviceUsb.vendorId != null).assertEqual(true); + expect(deviceUsb.productId != null).assertEqual(true); + } catch (err: BusinessError) { + hilog.info(TAG, 'testTag', 'Test case testQueryDevices001 catch err: ' + JSON.stringify(err)); + expect().assertFail(); + } + }) + + /* + * @tc.number : SUB_Driver_Ext_DeviceManagerAPIFunc_0102 + * @tc.name : testQueryDevices002 + * @tc.desc : verify queryDevice no param result + */ + it('testQueryDevices002', TestType.FUNCTION | Size.MEDIUMTEST | Level.LEVEL3, ():void => { + hilog.info(TAG, 'testTag', '----------------------testQueryDevices002---------------------------'); + if (deviceId == 0) { + hilog.info(TAG, 'testTag', 'Device ID has not been set.'); + expect(true).assertTrue(); + return; + } + try { + let devices = deviceManager.queryDevices(); + hilog.info(TAG, 'testTag', 'Test case testQueryDevices002 ret : ' + JSON.stringify(devices)); + expect(devices != null).assertEqual(true); + expect(devices[0].deviceId != null).assertTrue(); + } catch (err: BusinessError) { + hilog.info(TAG, 'testTag', 'Test case testQueryDevices002 catch err: ' + JSON.stringify(err)); + expect().assertFail(); + } + }) + + /* + * @tc.number : SUB_Driver_Ext_DeviceManagerAPIFunc_0103 + * @tc.name : testQueryDevices003 + * @tc.desc : verify queryDevice param is 12345 + */ + it('testQueryDevices003', TestType.FUNCTION | Size.MEDIUMTEST | Level.LEVEL3, ():void => { + hilog.info(TAG, 'testTag', '----------------------testQueryDevices003---------------------------'); + try { + let devices = deviceManager.queryDevices(12345); + hilog.info(TAG, 'testTag', 'Test case testQueryDevices003 ret : ', JSON.stringify(devices)); + expect(devices.length == 0).assertTrue(); + } catch (err: BusinessError) { + hilog.info(TAG, 'testTag', 'Test case testQueryDevices003 catch err : ' + JSON.stringify(err)); + expect(err.code).assertEqual(SERVICE_EXCEPTION_CODE); + } + }) + + /* + * @tc.number : SUB_Driver_Ext_DeviceManagerAPIFunc_0104 + * @tc.name : testQueryDevices004 + * @tc.desc : verify queryDevice errcode 22900001 + */ + it('testQueryDevices004', TestType.FUNCTION | Size.MEDIUMTEST | Level.LEVEL3, ():void => { + hilog.info(TAG, 'testTag', '----------------------testQueryDevices004---------------------------'); + if (deviceId != 0) { + hilog.info(TAG, 'testTag', 'Device ID has been set.'); + expect(true).assertTrue(); + return; + } + try { + let devices = deviceManager.queryDevices(); + hilog.info(TAG, 'testTag', 'Test case testQueryDevices004 ret : ' + JSON.stringify(devices)); + } catch (err: BusinessError) { + hilog.info(TAG, 'testTag', 'Test case testQueryDevices004 catch err : ' + JSON.stringify(err)); + expect(err.code).assertEqual(SERVICE_EXCEPTION_CODE); + } + }) + + /* + * @tc.number : SUB_Driver_Ext_DeviceManagerAPIFunc_0201 + * @tc.name : testBindDriverWithDeviceId001 + * @tc.desc : verify bindDriverWithDeviceId promise + */ + it("testBindDriverWithDeviceId001", TestType.FUNCTION | Size.MEDIUMTEST | Level.LEVEL0, + async (done:()=>void) : Promise => { + hilog.info(TAG, 'testTag', '----------------------testBindDriverWithDeviceId001---------------------------'); + try { + deviceManager.bindDriverWithDeviceId(12345, (error, data) => { + expect(false).assertTrue(); + done(); + }).then(data => { + expect(false).assertTrue(); + done(); + }, error => { + expect(false).assertTrue(); + done(); + }); + expect(false).assertTrue(); + done(); + } catch (error: BusinessError) { + hilog.info(TAG, 'testTag', 'Test case testBindDriverWithDeviceId001 catch err : ' + JSON.stringify(error)); + expect(error.code).assertEqual(SERVICE_EXCEPTION_CODE_NEW); + expect(error.code != SERVICE_NOT_ALLOW_ACCESS).assertTrue(); + done(); + } + }) + + /* + * @tc.number : SUB_Driver_Ext_DeviceManagerAPIFunc_0202 + * @tc.name : testBindDriverWithDeviceId002 + * @tc.desc : verify bindDriverWithDeviceId promise success + */ + it("testBindDriverWithDeviceId002", TestType.FUNCTION | Size.MEDIUMTEST | Level.LEVEL0, + async (done:()=>void) : Promise => { + hilog.info(TAG, 'testTag', '----------------------testBindDriverWithDeviceId002---------------------------'); + if (deviceId == 0) { + hilog.info(TAG, 'testTag', 'Device ID has not been set.'); + expect(true).assertTrue(); + return done(); + } + try { + let data: deviceManager.RemoteDeviceDriver = await deviceManager.bindDriverWithDeviceId(deviceId, + (err: BusinessError|null, data: long|undefined) => { + hilog.info(TAG, 'testTag', 'unbindDriverWithDeviceId callback success'); + }); + expect(true).assertTrue(); + hilog.info(0, 'testTag ui', 'bindDevice success:' + data.deviceId); + hilog.info(0, 'testTag ui', 'bindDevice success:' + JSON.stringify(data.remote)); + done(); + } catch (error: BusinessError) { + hilog.info(TAG, 'testTag', 'Test case testBindDriverWithDeviceId002 catch err : ' + JSON.stringify(error)); + expect(false).assertTrue(); + done(); + } + }) + + /* + * @tc.number : SUB_Driver_Ext_DeviceManagerAPIFunc_0301 + * @tc.name : testUnbindDriverWithDeviceId001 + * @tc.desc : verify unbindDriverWithDeviceId promise success + */ + it("testUnbindDriverWithDeviceId001", TestType.FUNCTION | Size.MEDIUMTEST | Level.LEVEL0, + async (done:()=>void) : Promise => { + hilog.info(TAG, 'testTag', '----------------------testUnbindDriverWithDeviceId001---------------------------'); + if (deviceId == 0) { + hilog.info(TAG, 'testTag', 'Device ID has not been set.'); + expect(true).assertTrue(); + return done(); + } + try { + await deviceManager.unbindDriverWithDeviceId(deviceId); + expect(true).assertTrue(); + await Utils.msSleep(2000); + done(); + } catch (error: BusinessError) { + hilog.info(TAG, 'testTag', 'Test case testUnbindDriverWithDeviceId001 catch err :' + JSON.stringify(error)); + expect(false).assertTrue(); + done(); + } + }) + + /* + * @tc.number : SUB_Driver_Ext_DeviceManagerAPIFunc_0302 + * @tc.name : testUnbindDriverWithDeviceId002 + * @tc.desc : verify unbindDriverWithDeviceId promise and no binding relationship + */ + it("testUnbindDriverWithDeviceId002", TestType.FUNCTION | Size.MEDIUMTEST | Level.LEVEL0, + async (done:()=>void) : Promise => { + hilog.info(TAG, 'testTag', '----------------------testUnbindDriverWithDeviceId002---------------------------'); + if (deviceId == 0) { + hilog.info(TAG, 'testTag', 'Device ID has not been set.'); + expect(true).assertTrue(); + return done(); + } + try { + await deviceManager.unbindDriverWithDeviceId(deviceId).then(data => { + expect(false).assertTrue(); + done(); + }); + done(); + } catch (error: BusinessError) { + hilog.info(TAG, 'testTag', 'Test case testUnbindDriverWithDeviceId002 catch err :' + JSON.stringify(error)); + expect(error.code).assertEqual(SERVICE_NOT_BOUND); + done(); + } + }) + + /* + * @tc.number : SUB_Driver_Ext_DeviceManagerAPIFunc_0303 + * @tc.name : testUnbindDriverWithDeviceId003 + * @tc.desc : verify unbindDriverWithDeviceId promise + */ + it("testUnbindDriverWithDeviceId003", TestType.FUNCTION | Size.MEDIUMTEST | Level.LEVEL0, + async (done:()=>void) : Promise => { + hilog.info(TAG, 'testTag', '----------------------testUnbindDriverWithDeviceId003---------------------------'); + try { + await deviceManager.unbindDriverWithDeviceId(12345).then(data => { + expect(false).assertTrue(); + done(); + }); + done(); + } catch (error: BusinessError) { + hilog.info(TAG, 'testTag', 'Test case testUnbindDriverWithDeviceId003 catch err :' + JSON.stringify(error)); + expect(error.code).assertEqual(SERVICE_EXCEPTION_CODE_NEW); + done(); + } + }) + + /* + * @tc.number : SUB_Driver_Ext_DeviceManagerAPIFunc_0401 + * @tc.name : testQueryDeviceInfo001 + * @tc.desc : verify queryDeviceInfo none deviceId + */ + it("testQueryDeviceInfo001", TestType.FUNCTION | Size.MEDIUMTEST | Level.LEVEL0, async () : Promise => { + hilog.info(TAG, 'testTag', '----------------------testQueryDeviceInfo001---------------------------'); + try { + const deviceInfos = deviceManager.queryDeviceInfo(); + expect(Array.isArray(deviceInfos)).assertTrue(); + for (const deviceInfo of deviceInfos) { + assertDeviceInfo(deviceInfo); + } + } catch (error: BusinessError) { + hilog.info(TAG, 'testTag', 'Test case testQueryDeviceInfo001 catch err :' + JSON.stringify(error)); + expect(error.code).assertEqual(SERVICE_EXCEPTION_CODE_NEW); + } + }) + + /* + * @tc.number : SUB_Driver_Ext_DeviceManagerAPIFunc_0402 + * @tc.name : testQueryDeviceInfo002 + * @tc.desc : verify queryDeviceInfo has deviceId + */ + it("testQueryDeviceInfo002", TestType.FUNCTION | Size.MEDIUMTEST | Level.LEVEL0, async () : Promise => { + hilog.info(TAG, 'testTag', '----------------------testQueryDeviceInfo002---------------------------'); + try { + const deviceInfos = deviceManager.queryDeviceInfo(12345); + expect(Array.isArray(deviceInfos)).assertTrue(); + for (const deviceInfo of deviceInfos) { + assertDeviceInfo(deviceInfo); + } + } catch (error: BusinessError) { + hilog.info(TAG, 'testTag', 'Test case testQueryDeviceInfo002 catch err :' + JSON.stringify(error)); + expect(error.code).assertEqual(SERVICE_EXCEPTION_CODE_NEW); + } + }) + + /* + * @tc.number : SUB_Driver_Ext_DeviceManagerAPIFunc_0501 + * @tc.name : testQueryDriverInfo001 + * @tc.desc : verify queryDriverInfo none driverUid + */ + it("testQueryDriverInfo001", TestType.FUNCTION | Size.MEDIUMTEST | Level.LEVEL0, async () : Promise => { + hilog.info(TAG, 'testTag', '----------------------testQueryDriverInfo001---------------------------'); + try { + let driverInfos = deviceManager.queryDriverInfo(); + expect(Array.isArray(driverInfos)).assertTrue(); + for (const driverInfo of driverInfos) { + assertDriverInfo(driverInfo); + } + } catch (error: BusinessError) { + hilog.info(TAG, 'testTag', 'Test case testQueryDriverInfo001 catch err :' + JSON.stringify(error)); + expect(error.code).assertEqual(SERVICE_EXCEPTION_CODE_NEW); + } + }) + + /* + * @tc.number : SUB_Driver_Ext_DeviceManagerAPIFunc_0502 + * @tc.name : testQueryDriverInfo002 + * @tc.desc : verify queryDriverInfo none driverUid + */ + it("testQueryDriverInfo002", TestType.FUNCTION | Size.MEDIUMTEST | Level.LEVEL0, async () : Promise => { + hilog.info(TAG, 'testTag', '----------------------testQueryDriverInfo002---------------------------'); + try { + const driverInfos = deviceManager.queryDriverInfo('driver-12345'); + expect(Array.isArray(driverInfos)).assertTrue(); + for (const driverInfo of driverInfos) { + assertDriverInfo(driverInfo); + } + } catch (error: BusinessError) { + hilog.info(TAG, 'testTag', 'Test case testQueryDriverInfo002 catch err :' + JSON.stringify(error)); + expect(error.code).assertEqual(SERVICE_EXCEPTION_CODE_NEW); + } + }) + }) +} diff --git a/frameworks/js/taihe/test/xts/src/test/DeviceManagerNoPermission.test.ets b/frameworks/js/taihe/test/xts/src/test/DeviceManagerNoPermission.test.ets new file mode 100644 index 0000000..95d511d --- /dev/null +++ b/frameworks/js/taihe/test/xts/src/test/DeviceManagerNoPermission.test.ets @@ -0,0 +1,152 @@ +/* + * 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 { describe, it, expect, TestType, Size, Level, beforeAll, beforeEach, afterEach, afterAll } from "../../index"; +import hilog from '@ohos.hilog' +import deviceManager from '@ohos.driver.deviceManager' +import { BusinessError } from '@ohos.base'; + +const TAG = 0x0000; + +export default function PermissionJsTest(){ + describe("PermissionJsTest", ():void => { + let deviceId: double = 0; + const PERMISSION_DENIED_CODE = 201; + const TEST_DEVICE_ID = 0; + const TEST_DRIVER_UID = 'testDriverUid'; + + beforeAll(() => { + hilog.info(TAG, 'testTag', 'beforeAll called'); + try { + let devices = deviceManager.queryDevices(deviceManager.BusType.USB); + if (devices != null && devices.length > 0 && devices[0] != null) { + deviceId = devices[0].deviceId; + hilog.info(TAG, 'testTag', 'deviceId: ' + devices[0].deviceId); + hilog.info(TAG, 'testTag', 'busType: ' + devices[0].busType); + hilog.info(TAG, 'testTag', 'description: ' + devices[0].description); + } else { + hilog.info(TAG, 'testTag', 'No devices found.'); + } + } catch (err) { + hilog.info(TAG, 'testTag', 'err: ' + err); + } + + if (deviceId == 0) { + hilog.info(TAG, 'testTag', 'Device ID has not been set.'); + } + hilog.info(TAG, 'testTag', 'beforeAll called end'); + }) + afterAll(() => { + hilog.info(TAG, 'testTag', 'afterAll called'); + }) + + beforeEach(() => { + hilog.info(TAG, 'testTag', 'beforeEach called'); + }) + + afterEach(() => { + hilog.info(TAG, 'testTag', 'afterEach called'); + }) + + /* + * @tc.number:SUB_Driver_Ext_DeviceManagerAPIFunc_0203 + * @tc.name:Permission_bindDriverWithDeviceId_001 + * @tc.desc:verify permission of bindDriverWithDeviceId + */ + it("Permission_bindDriverWithDeviceId_001", TestType.FUNCTION | Size.MEDIUMTEST | Level.LEVEL0, + async (done:()=>void) : Promise => { + hilog.info(TAG, 'testTag', '-------------------Permission_bindDriverWithDeviceId_001-------------------------'); + try { + await deviceManager.bindDriverWithDeviceId(TEST_DEVICE_ID, (error, data) => { + hilog.info(TAG, 'testTag', 'Test function is called'); + done(); + }); + expect(false).assertTrue(); + done(); + } catch (error: BusinessError) { + hilog.info(TAG, 'testTag', + 'Test case Permission_bindDriverWithDeviceId_001 catch err : ' + JSON.stringify(error)); + expect(error.code).assertEqual(PERMISSION_DENIED_CODE); + done(); + } + }) + + /* + * @tc.number:SUB_Driver_Ext_DeviceManagerAPIFunc_0304 + * @tc.name:Permission_unbindDriverWithDeviceId_001 + * @tc.desc:verify permission of unbindDriverWithDeviceId + */ + it("Permission_unbindDriverWithDeviceId", 0, async (done:()=>void) : Promise => { + hilog.info(TAG, 'testTag', '----------------------Permission_unbindDriverWithDeviceId--------------------------'); + try { + await deviceManager.unbindDriverWithDeviceId(TEST_DEVICE_ID); + expect(false).assertTrue(); + done(); + } catch (error: BusinessError) { + hilog.info(TAG, 'testTag', 'Test case Permission_unbindDriverWithDeviceId catch err :' + JSON.stringify(error)); + expect(error.code).assertEqual(PERMISSION_DENIED_CODE); + done(); + } + }) + + /* + * @tc.number:SUB_Driver_Ext_DeviceManagerAPIFunc_0105 + * @tc.name:Permission_queryDevices_001 + * @tc.desc:verify permission of queryDevices + */ + it("Permission_queryDevices_001", 0, ():void => { + hilog.info(TAG, 'testTag', '----------------------Permission_queryDevices_001---------------------------'); + try { + deviceManager.queryDevices(); + expect(false).assertTrue(); + } catch (err: BusinessError) { + hilog.info(TAG, 'testTag', 'Test case Permission_queryDevices_001 catch err: ' + JSON.stringify(err)); + expect(err.code).assertEqual(PERMISSION_DENIED_CODE); + } + }); + + /* + * @tc.number:SUB_Driver_Ext_DeviceManagerAPIFunc_0403 + * @tc.name:Permission_queryDeviceInfo_001 + * @tc.desc:verify permission of queryDeviceInfo + */ + it("Permission_queryDeviceInfo_001", 0, async () : Promise => { + hilog.info(TAG, 'testTag', '----------------------Permission_queryDeviceInfo_001---------------------------'); + try { + deviceManager.queryDeviceInfo(TEST_DEVICE_ID); + expect(false).assertTrue(); + } catch (err: BusinessError) { + hilog.info(TAG, 'testTag', 'Test case Permission_queryDeviceInfo_001 catch err: ' + JSON.stringify(err)); + expect(err.code).assertEqual(PERMISSION_DENIED_CODE); + } + }); + + /* + * @tc.number:SUB_Driver_Ext_DeviceManagerAPIFunc_0503 + * @tc.name:Permission_queryDriverInfo_001 + * @tc.desc:verify permission of queryDriverInfo + */ + it("Permission_queryDriverInfo_001", 0, async () : Promise => { + hilog.info(TAG, 'testTag', '----------------------Permission_queryDriverInfo_001---------------------------'); + try { + deviceManager.queryDriverInfo(TEST_DRIVER_UID); + expect(false).assertTrue(); + } catch (err: BusinessError) { + hilog.info(TAG, 'testTag', 'Test case Permission_queryDriverInfo_001 catch err: ' + JSON.stringify(err)); + expect(err.code).assertEqual(PERMISSION_DENIED_CODE); + } + }); + }) +} \ No newline at end of file diff --git a/frameworks/js/taihe/test/xts/src/test/DeviceManagerNormalApp.test.ets b/frameworks/js/taihe/test/xts/src/test/DeviceManagerNormalApp.test.ets new file mode 100644 index 0000000..4c5d6be --- /dev/null +++ b/frameworks/js/taihe/test/xts/src/test/DeviceManagerNormalApp.test.ets @@ -0,0 +1,103 @@ +/* + * 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 { describe, it, expect, TestType, Size, Level, beforeAll, beforeEach, afterEach, afterAll } from "../../index"; +import hilog from '@ohos.hilog' +import deviceManager from '@ohos.driver.deviceManager' +import { BusinessError } from '@ohos.base'; + +const TAG = 0x0000; + +export default function DeviceManagerJsNormalTest(){ + describe("DeviceManagerJsNormalTest", ():void => { + let deviceId: double = 0; + const SYSTEMAPI_DENIED_CODE = 202; + + beforeAll(() => { + hilog.info(TAG, 'testTag', 'beforeAll called'); + try { + let devices = deviceManager.queryDevices(deviceManager.BusType.USB); + if (devices != null && devices.length > 0 && devices[0] != null) { + deviceId = devices[0].deviceId; + hilog.info(TAG, 'testTag', 'deviceId: ' + devices[0].deviceId); + hilog.info(TAG, 'testTag', 'busType: ' + devices[0].busType); + hilog.info(TAG, 'testTag', 'description: ' + devices[0].description); + } else { + hilog.info(TAG, 'testTag', 'No devices found.'); + } + } catch (err) { + hilog.info(TAG, 'testTag', 'err: ' + err); + } + if (deviceId == 0) { + hilog.info(TAG, 'testTag', 'Device ID has not been set.'); + } + hilog.info(TAG, 'testTag', 'beforeAll called end'); + }) + + afterAll(() => { + hilog.info(TAG, 'testTag', 'afterAll called'); + }) + + beforeEach(() => { + hilog.info(TAG, 'testTag', 'beforeEach called'); + }) + + afterEach(() => { + hilog.info(TAG, 'testTag', 'afterEach called'); + }) + + /* + * @tc.number : SUB_Driver_Ext_DeviceManagerAPIFunc_0404 + * @tc.name : testNormalQueryDriverInfo001 + * @tc.desc : verify queryDeviceInfo none deviceId for normal app + */ + it("testNormalQueryDeviceInfo001", TestType.FUNCTION | Size.MEDIUMTEST | Level.LEVEL0, async () : Promise => { + hilog.info(TAG, 'testTag', '----------------------testNormalQueryDeviceInfo001---------------------------'); + if (deviceId == 0) { + hilog.info(TAG, 'testTag', 'Device ID has not been set.'); + expect(true).assertTrue(); + return Promise.resolve(); + } + try { + const deviceInfos = deviceManager.queryDeviceInfo(); + expect(false).assertTrue(); + } catch (error: BusinessError) { + hilog.info(TAG, 'testTag', 'Test case testNormalQueryDeviceInfo001 catch err :' + JSON.stringify(error)); + expect(error.code).assertEqual(SYSTEMAPI_DENIED_CODE); + } + }) + + /* + * @tc.number : SUB_Driver_Ext_DeviceManagerAPIFunc_0504 + * @tc.name : testNormalQueryDriverInfo001 + * @tc.desc : verify queryDriverInfo none driverUid for normal app + */ + it("testNormalQueryDriverInfo001", TestType.FUNCTION | Size.MEDIUMTEST | Level.LEVEL0, async () : Promise => { + hilog.info(TAG, 'testTag', '----------------------testNormalQueryDriverInfo001---------------------------'); + if (deviceId == 0) { + hilog.info(TAG, 'testTag', 'Device ID has not been set.'); + expect(true).assertTrue(); + return Promise.resolve(); + } + try { + let driverInfos = deviceManager.queryDriverInfo(); + expect(false).assertTrue(); + } catch (error: BusinessError) { + hilog.info(TAG, 'testTag', 'Test case testNormalQueryDriverInfo001 catch err :' + JSON.stringify(error)); + expect(error.code).assertEqual(SYSTEMAPI_DENIED_CODE); + } + }) + }) +} \ No newline at end of file diff --git a/frameworks/js/taihe/test/xts/src/test/List.test.ets b/frameworks/js/taihe/test/xts/src/test/List.test.ets new file mode 100644 index 0000000..0ce876c --- /dev/null +++ b/frameworks/js/taihe/test/xts/src/test/List.test.ets @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import DeviceManagerJsTest from "./DeviceManager.test"; +import DeviceManagerJsNoPermissionTest from "./DeviceManagerNoPermission.test"; +import DeviceManagerJsNormalTest from "./DeviceManagerNormalApp.test"; + +export default function testsuite() { + DeviceManagerJsTest(); + DeviceManagerJsNoPermissionTest(); + DeviceManagerJsNormalTest(); +} diff --git a/frameworks/js/taihe/test/xts/src/test/Util.test.ets b/frameworks/js/taihe/test/xts/src/test/Util.test.ets new file mode 100644 index 0000000..41315a0 --- /dev/null +++ b/frameworks/js/taihe/test/xts/src/test/Util.test.ets @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export default class Utils{ + static async msSleep(count:int) : Promise { + return new Promise((resolve, reject) => { + setTimeout(() => { + resolve(0) + }, count) + }) + } +} \ No newline at end of file -- Gitee