From 7bf990579ccd5dc08f901fe06806d4ce8c179ad8 Mon Sep 17 00:00:00 2001 From: heguokai <275503077@qq.com> Date: Fri, 25 Jul 2025 21:20:59 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BB=A3=E7=A0=81=E7=A7=BB=E6=A4=8Dmaster?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: heguokai <275503077@qq.com> --- bundle.json | 4 +- frameworks/BUILD.gn | 15 +- .../{ani/event_emitter => emitter}/BUILD.gn | 154 +- .../ani}/ets/@ohos.events.emitter.ets | 358 ++-- .../emitter/ani/ets/@ohos.events.json.ets | 214 +++ .../ani/include/ani_emitter.h} | 165 +- .../emitter/ani/include/ani_serialize.h | 51 + .../ani/include/sts_events_json_common.h | 50 + .../ani/src/ani_emitter.cpp} | 935 ++++------ frameworks/emitter/ani/src/ani_serialize.cpp | 99 ++ .../ani/src/sts_events_json_common.cpp | 538 ++++++ .../base/include/ani_async_callback_manager.h | 113 ++ .../emitter/base/include/ani_deserialize.h | 51 + .../base/include/aync_callback_manager.h | 108 ++ .../include/napi_async_callback_manager.h | 99 ++ frameworks/emitter/base/include/serialize.h | 43 + .../base/src/ani_async_callback_manager.cpp | 302 ++++ .../emitter/base/src/ani_deserialize.cpp | 81 + .../base/src/async_callback_manager.cpp | 94 + .../base/src/napi_async_callback_manager.cpp | 154 ++ frameworks/emitter/napi/include/napi_agent.h | 25 + .../emitter/napi/include/napi_emitter.h | 40 + .../emitter/napi/include/napi_serialize.h | 52 + frameworks/emitter/napi/src/napi_emitter.cpp | 358 ++++ .../emitter/napi/src/napi_serialize.cpp | 76 + .../lib_event_handler_event_queue_test.cpp | 32 - frameworks/napi/BUILD.gn | 163 +- frameworks/napi/include/events_emitter.h | 164 +- frameworks/napi/include/interops.h | 87 + .../{ani/BUILD.gn => napi/libemitter.map} | 53 +- frameworks/napi/src/events_emitter.cpp | 1568 +++++++++-------- frameworks/napi/src/init.cpp | 88 +- frameworks/napi/src/interops.cpp | 50 + interfaces/inner_api/inner_event.h | 18 + 34 files changed, 4545 insertions(+), 1857 deletions(-) rename frameworks/{ani/event_emitter => emitter}/BUILD.gn (48%) rename frameworks/{ani/event_emitter => emitter/ani}/ets/@ohos.events.emitter.ets (51%) create mode 100644 frameworks/emitter/ani/ets/@ohos.events.json.ets rename frameworks/{ani/event_emitter/include/sts_events_emitter.h => emitter/ani/include/ani_emitter.h} (40%) create mode 100644 frameworks/emitter/ani/include/ani_serialize.h create mode 100644 frameworks/emitter/ani/include/sts_events_json_common.h rename frameworks/{ani/event_emitter/src/sts_events_emitter.cpp => emitter/ani/src/ani_emitter.cpp} (39%) create mode 100644 frameworks/emitter/ani/src/ani_serialize.cpp create mode 100644 frameworks/emitter/ani/src/sts_events_json_common.cpp create mode 100644 frameworks/emitter/base/include/ani_async_callback_manager.h create mode 100644 frameworks/emitter/base/include/ani_deserialize.h create mode 100644 frameworks/emitter/base/include/aync_callback_manager.h create mode 100644 frameworks/emitter/base/include/napi_async_callback_manager.h create mode 100644 frameworks/emitter/base/include/serialize.h create mode 100644 frameworks/emitter/base/src/ani_async_callback_manager.cpp create mode 100644 frameworks/emitter/base/src/ani_deserialize.cpp create mode 100644 frameworks/emitter/base/src/async_callback_manager.cpp create mode 100644 frameworks/emitter/base/src/napi_async_callback_manager.cpp create mode 100644 frameworks/emitter/napi/include/napi_agent.h create mode 100644 frameworks/emitter/napi/include/napi_emitter.h create mode 100644 frameworks/emitter/napi/include/napi_serialize.h create mode 100644 frameworks/emitter/napi/src/napi_emitter.cpp create mode 100644 frameworks/emitter/napi/src/napi_serialize.cpp create mode 100644 frameworks/napi/include/interops.h rename frameworks/{ani/BUILD.gn => napi/libemitter.map} (59%) create mode 100644 frameworks/napi/src/interops.cpp diff --git a/bundle.json b/bundle.json index 4678fab..21f8346 100644 --- a/bundle.json +++ b/bundle.json @@ -43,9 +43,9 @@ ], "fwk_group": [ "//base/notification/eventhandler/frameworks/eventhandler:libeventhandler", + "//base/notification/eventhandler/frameworks:emitter_packages", "//base/notification/eventhandler/frameworks:eventhandler_native_target", - "//base/notification/eventhandler/frameworks:napi_packages", - "//base/notification/eventhandler/frameworks/ani:ani_event_emitter_packages" + "//base/notification/eventhandler/frameworks:napi_packages" ], "service_group": [ diff --git a/frameworks/BUILD.gn b/frameworks/BUILD.gn index 5f38ed7..011e786 100644 --- a/frameworks/BUILD.gn +++ b/frameworks/BUILD.gn @@ -14,13 +14,22 @@ group("napi_packages") { deps = [] if (support_jsapi) { - deps += [ - "cj:cj_emitter_ffi", + deps += [ "cj:cj_emitter_ffi" ] + } +} + +group("emitter_packages") { + if (support_jsapi) { + deps = [ + "emitter:eventEmitter", + "emitter:event_emitter_abc_etc", + "emitter:event_json_abc_etc", "napi:emitter", + "napi:emitter_interops", ] } } group("eventhandler_native_target") { deps = [ "native:eventhandler_native" ] -} +} \ No newline at end of file diff --git a/frameworks/ani/event_emitter/BUILD.gn b/frameworks/emitter/BUILD.gn similarity index 48% rename from frameworks/ani/event_emitter/BUILD.gn rename to frameworks/emitter/BUILD.gn index c4e4209..5ef3e06 100644 --- a/frameworks/ani/event_emitter/BUILD.gn +++ b/frameworks/emitter/BUILD.gn @@ -1,62 +1,92 @@ -# 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/ace/ace.gni") -import("../../../eventhandler.gni") - -ohos_shared_library("eventEmitter") { - sanitize = { - integer_overflow = true - ubsan = true - boundary_sanitize = true - cfi = true - cfi_cross_dso = true - debug = false - } - branch_protector_ret = "pac_ret" - - include_dirs = [ - "include", - "${inner_api_path}", - ] - - sources = [ "src/sts_events_emitter.cpp" ] - - deps = [ "${frameworks_path}/eventhandler:libeventhandler" ] - - external_deps = [ - "c_utils:utils", - "hilog:libhilog", - "runtime_core:ani", - ] - - subsystem_name = "notification" - part_name = "eventhandler" -} - -generate_static_abc("event_emitter_abc") { - base_url = "./ets" - files = [ "./ets/@ohos.events.emitter.ets" ] - is_boot_abc = "True" - device_dst_file = "/system/framework/event_emitter_abc.abc" -} - -ohos_prebuilt_etc("event_emitter_abc_etc") { - source = "$target_out_dir/event_emitter_abc.abc" - module_install_dir = "framework" - subsystem_name = "notification" - part_name = "eventhandler" - deps = [ ":event_emitter_abc" ] -} +# Copyright (c) 2025 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build/ohos.gni") +import("//build/ohos/ace/ace.gni") +import("//build/config/components/ets_frontend/ets2abc_config.gni") +import("../../eventhandler.gni") + +ohos_shared_library("eventEmitter") { + sanitize = { + integer_overflow = true + ubsan = true + boundary_sanitize = true + cfi = true + cfi_cross_dso = true + debug = false + } + branch_protector_ret = "pac_ret" + + include_dirs = [ + "${frameworks_path}/emitter/ani/include", + "${frameworks_path}/emitter/napi/include", + "${frameworks_path}/emitter/base/include", + ] + + sources = [ + "${frameworks_path}/emitter/ani/src/ani_emitter.cpp", + "${frameworks_path}/emitter/ani/src/ani_serialize.cpp", + "${frameworks_path}/emitter/ani/src/sts_events_json_common.cpp", + "${frameworks_path}/emitter/base/src/ani_async_callback_manager.cpp", + "${frameworks_path}/emitter/base/src/ani_deserialize.cpp", + "${frameworks_path}/emitter/base/src/async_callback_manager.cpp", + "${frameworks_path}/emitter/base/src/napi_async_callback_manager.cpp", + "${frameworks_path}/emitter/napi/src/napi_emitter.cpp", + "${frameworks_path}/emitter/napi/src/napi_serialize.cpp", + ] + + deps = [ + "${frameworks_path}/eventhandler:libeventhandler", + "${frameworks_path}/napi:emitter_interops", + ] + + external_deps = [ + "c_utils:utils", + "hilog:libhilog", + "napi:ace_napi", + "runtime_core:ani", + ] + + subsystem_name = "notification" + part_name = "eventhandler" +} + +generate_static_abc("event_emitter_abc") { + base_url = "${frameworks_path}/emitter/ani/ets" + files = [ "${frameworks_path}/emitter/ani/ets/@ohos.events.emitter.ets" ] + is_boot_abc = "True" + device_dst_file = "/system/framework/event_emitter_abc.abc" +} + +ohos_prebuilt_etc("event_emitter_abc_etc") { + source = "$target_out_dir/event_emitter_abc.abc" + module_install_dir = "framework" + subsystem_name = "notification" + part_name = "eventhandler" + deps = [ ":event_emitter_abc" ] +} + +generate_static_abc("event_json_abc") { + base_url = "${frameworks_path}/emitter/ani/ets" + files = [ "${frameworks_path}/emitter/ani/ets/@ohos.events.json.ets" ] + is_boot_abc = "True" + device_dst_file = "/system/framework/event_json_abc.abc" +} + +ohos_prebuilt_etc("event_json_abc_etc") { + source = "$target_out_dir/event_json_abc.abc" + module_install_dir = "framework" + subsystem_name = "notification" + part_name = "eventhandler" + deps = [ ":event_json_abc" ] +} \ No newline at end of file diff --git a/frameworks/ani/event_emitter/ets/@ohos.events.emitter.ets b/frameworks/emitter/ani/ets/@ohos.events.emitter.ets similarity index 51% rename from frameworks/ani/event_emitter/ets/@ohos.events.emitter.ets rename to frameworks/emitter/ani/ets/@ohos.events.emitter.ets index 1d05072..8b51a6d 100644 --- a/frameworks/ani/event_emitter/ets/@ohos.events.emitter.ets +++ b/frameworks/emitter/ani/ets/@ohos.events.emitter.ets @@ -1,136 +1,222 @@ -/* - * 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 { Callback } from '@ohos.base'; - -namespace emitter { - loadLibrary("eventEmitter.z"); - export interface EventData { - data?: Record; - } - - class EventDataInner implements EventData { - public data?: Record | undefined; - } - - export interface GenericEventData { - data?: T; - } - - class GenericEventDataInner implements GenericEventData { - public data?: T | undefined; - } - - export enum EventPriority { - IMMEDIATE = 0, - HIGH = 1, - LOW = 2, - IDLE = 3, - } - - export interface InnerEvent { - eventId: number; - priority?: EventPriority; - } - - class InnerEventInner implements InnerEvent { - public eventId: number = 0; - public priority?: EventPriority | undefined; - } - - export interface Options { - priority?: EventPriority; - } - - class OptionsInner implements Options { - public priority?: EventPriority | undefined; - } - - export native function OffStringSync(eventId: string, callback: Callback): void; - export native function OffGenericEventSync(eventId: string, callback: Callback>): void; - export native function OffNumberSync(eventId: number): void; - export native function OffNumberCallbackSync(eventId: number, callback: Callback): void; - export native function OnOrOnceStringSync(eventId: string, once: boolean, callback: Callback, dataType: string): void; - export native function OnOrOnceGenericEventSync(eventId: string, once : boolean, callback: Callback>, dataType: string): void; - export native function OnOrOnceSync(eventId: number, once: boolean, callback: Callback, dataType: string): void; - export native function getListenerCountSync(eventId: number): number; - export native function getListenerCountStringSync(eventId: string): number; - export native function EmitInnerEventSync(eventId: InnerEvent): void; - export native function EmitInnerEventDataSync(eventId: InnerEvent, data: EventData): void; - export native function EmitStringSync(eventId: string): void; - export native function EmitStringDataSync(eventId: string, data: EventData): void; - export native function EmitStringGenericSync(eventId: string, data: GenericEventData): void; - - export function on(event: InnerEvent, callback: Callback): void { - if (event.eventId) { - emitter.OnOrOnceSync(event.eventId, false, callback, "eventData"); - } - } - - export function off(eventId: string, callback: Callback | Callback>): void { - if (callback instanceof Callback) { - emitter.OffStringSync(eventId, callback as Callback); - } else { - emitter.OffGenericEventSync(eventId, callback as Callback>); - } - } - - export function off(eventId: number): void { - emitter.OffNumberSync(eventId); - } - - export function off(eventId: number, callback: Callback): void { - emitter.OffNumberCallbackSync(eventId, callback); - } - - export function on(eventId: string, callback: Callback | Callback>): void { - if (callback instanceof Callback) { - emitter.OnOrOnceStringSync(eventId, false, callback as Callback, "eventData"); - } else { - emitter.OnOrOnceGenericEventSync(eventId, false, callback as Callback>, "genericEventData"); - } - } - - export function emit(eventId: string, data?: EventData | GenericEventData): void { - if (data != undefined) { - if (data instanceof EventData) { - emitter.EmitStringDataSync(eventId, data as EventData); - } else { - emitter.EmitStringGenericSync(eventId, data as GenericEventData); - } - } else { - emitter.EmitStringSync(eventId); - } - } - - export function emit(event: InnerEvent, data?: EventData): void { - if (data != undefined) { - emitter.EmitInnerEventDataSync(event, data); - } else { - emitter.EmitInnerEventSync(event); - } - } - - export function getListenerCount(eventId: number | string): number { - let count : number = 1; - if (typeof eventId === "number") { - count = emitter.getListenerCountSync(eventId as number); - } else { - count = emitter.getListenerCountStringSync(eventId as string); - } - return count; - } -} -export default emitter; +/* + * 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 { Callback } from '@ohos.base'; + +namespace emitter { + loadLibrary("eventEmitter.z"); + + export interface EventData { + data?: Record; + } + + class EventDataInner implements EventData { + public data?: Record | undefined; + } + + export interface GenericEventData { + data?: T; + } + + class GenericEventDataInner implements GenericEventData { + public data?: T | undefined; + } + + export enum EventPriority { + IMMEDIATE = 0, + HIGH = 1, + LOW = 2, + IDLE = 3, + } + + export interface InnerEvent { + eventId: number; + priority?: EventPriority; + } + + class InnerEventInner implements InnerEvent { + public eventId: number = 0; + public priority?: EventPriority | undefined; + } + + export interface Options { + priority?: EventPriority; + } + + class OptionsInner implements Options { + public priority?: EventPriority | undefined; + } + + export native function OffStringIdSync(eventId: string): void; + export native function OffStringSync(eventId: string, callback: Callback): void; + export native function OffGenericEventSync(eventId: string, callback: Callback>): void; + export native function OffNumberSync(eventId: number): void; + export native function OffNumberCallbackSync(eventId: number, callback: Callback): void; + export native function OnOrOnceStringSync(eventId: string, once: boolean, callback: Callback, dataType: string): void; + export native function OnOrOnceGenericEventSync(eventId: string, once : boolean, callback: Callback>, dataType: string): void; + export native function OnOrOnceSync(eventId: number, once: boolean, callback: Callback, dataType: string): void; + export native function getListenerCountSync(eventId: number): number; + export native function getListenerCountStringSync(eventId: string): number; + export native function EmitInnerEventSync(eventId: InnerEvent): void; + export native function EmitInnerEventDataSync(eventId: InnerEvent, data: EventData): void; + export native function EmitStringSync(eventId: string): void; + export native function EmitStringDataSync(eventId: string, data: EventData): void; + export native function EmitStringGenericSync(eventId: string, data: GenericEventData): void; + export native function EmitStringOptionsDataSync(eventId: string, options: Options, data: EventData): void; + export native function EmitStringOptionsGenericSync(eventId: string, options: Options, data: GenericEventData): void; + export native function EmitStringOptionsSync(eventId:string, options: Options): void; + + export function on(event: InnerEvent, callback: Callback): void { + if (event.eventId) { + OnOrOnceSync(event.eventId, false, callback, "eventData"); + } + } + + export function once(event: InnerEvent, callback: Callback): void { + if (event.eventId) { + OnOrOnceSync(event.eventId, true, callback, "eventData"); + } + } + + export function on(eventId: string, callback: Callback): void { + if (eventId === '') { + return; + } + emitter.OnOrOnceStringSync(eventId, false, callback, "eventData"); + } + + export function once(eventId: string, callback: Callback): void { + if (eventId === '') { + return; + } + OnOrOnceStringSync(eventId, true, callback, "eventData"); + } + + export function off(eventId: string): void { + if (eventId === '') { + return; + } + OffStringIdSync(eventId); + } + + export function off(eventId: string, callback: Callback): void { + if (eventId === '') { + return; + } + emitter.OffStringSync(eventId, callback); + } + + export function off(eventId: string, callback: Callback | Callback>): void { + if (eventId === '') { + return; + } + if (callback instanceof Callback) { + OffStringSync(eventId, callback as Callback); + } else { + OffGenericEventSync(eventId, callback as Callback>); + } + } + + export function off(eventId: number): void { + OffNumberSync(eventId); + } + + export function off(eventId: number, callback: Callback): void { + if (callback == null) { + return; + } + OffNumberCallbackSync(eventId, callback); + } + + export function on(eventId: string, callback: Callback | Callback>): void { + if (eventId === '') { + return; + } + if (callback instanceof Callback) { + OnOrOnceStringSync(eventId, false, callback as Callback, "eventData"); + } else { + OnOrOnceGenericEventSync(eventId, false, callback as Callback>, "genericEventData"); + } + } + + export function emit(eventId: string, options: Options, data?: EventData): void { + if (eventId === '') { + return; + } + if (data != undefined) { + EmitStringOptionsDataSync(eventId, options, data as EventData); + } else { + EmitStringOptionsSync(eventId, options); + } + } + + export function emit(eventId: string, options: Options, data?: GenericEventData): void { + if (eventId === '') { + return; + } + if (data != undefined) { + EmitStringOptionsGenericSync(eventId, options, data as GenericEventData); + } else { + EmitStringOptionsSync(eventId, options); + } + } + + export function emit(eventId: string, data?: EventData): void { + if (eventId === '') { + return; + } + if (data != undefined) { + EmitStringDataSync(eventId, data as EventData); + } else { + EmitStringSync(eventId); + } + } + + export function emit(eventId: string, data?: GenericEventData): void { + if (eventId === '') { + return; + } + if (data != undefined) { + EmitStringGenericSync(eventId, data as GenericEventData); + } else { + EmitStringSync(eventId); + } + } + + export function emit(event: InnerEvent, data?: EventData): void { + if (event == null) { + return; + } + if (data != undefined) { + EmitInnerEventDataSync(event, data); + } else { + EmitInnerEventSync(event); + } + } + + export function getListenerCount(eventId: number | string): number { + let count : number = 0; + if (typeof eventId === "number") { + count = getListenerCountSync(eventId as number); + } else { + if (eventId === '') { + return count; + } + count = getListenerCountStringSync(eventId as string); + } + return count; + } +} +export default emitter; \ No newline at end of file diff --git a/frameworks/emitter/ani/ets/@ohos.events.json.ets b/frameworks/emitter/ani/ets/@ohos.events.json.ets new file mode 100644 index 0000000..4e9a205 --- /dev/null +++ b/frameworks/emitter/ani/ets/@ohos.events.json.ets @@ -0,0 +1,214 @@ +/* + * 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. + */ + +type valueType = NullishType; + +class RecordWriter { + private buffer = new StringBuilder(); + private store = new Set(); + + public write(obj: Object): String { + this.writeObject(obj); + return this.buffer.toString(); + } + + private writeObject(obj: NullishType): void { + if (obj === null) { + this.buffer.append('null'); + } else if (obj === undefined) { + this.buffer.append('undefined'); + } else if (obj instanceof String) { + this.buffer.append(JSON.stringify(obj as String)); + } else if (this.writeValueType(obj as int)) { + // nothing to do + } else if (obj instanceof Array) { + this.writeArray(obj as Object as Array); + } else if (obj instanceof Record) { + this.writeRecord(obj as Object as Record); + } else { + const objType = Type.of(obj); + if (objType instanceof ArrayType) { + this.writeBuildArray(obj as int, Value.of(obj) as ArrayValue); + } else { + this.buffer.append('null'); + } + } + } + + private writeValueType(obj: Object): boolean { + if (obj instanceof Boolean) { + this.buffer.append(JSON.stringify(obj.unboxed())); + return true; + } else if (obj instanceof Byte) { + this.buffer.append(JSON.stringify(obj.unboxed())); + return true; + } else if (obj instanceof Char) { + this.buffer.append(JSON.stringify(obj.unboxed())); + return true; + } else if (obj instanceof Short) { + this.buffer.append(JSON.stringify(obj.unboxed())); + return true; + } else if (obj instanceof Int) { + this.buffer.append(JSON.stringify(obj.unboxed())); + return true; + } else if (obj instanceof Long) { + this.buffer.append(JSON.stringify(obj.unboxed())); + return true; + } else if (obj instanceof Float) { + this.buffer.append(JSON.stringify(obj.unboxed())); + return true; + } else if (obj instanceof Double) { + this.buffer.append(JSON.stringify(obj.unboxed())); + return true; + } else if (obj instanceof BigInt) { + this.buffer.append(JSON.stringify(obj)); + return true; + } else { + return false; + } + } + + private writeArray(arr: Array): void { + this.buffer.append('['); + const length = arr.length.toInt(); + this.checkReferencesCycle(arr); + this.store.add(arr); + for (let idx = 0; idx < length; idx++) { + if (arr[idx] == null) { + this.buffer.append('null'); + } else { + this.writeObject(arr[idx]); + } + if (idx < length - 1) { + this.buffer.append(','); + } + } + this.store.delete(arr); + this.buffer.append(']'); + } + + private writeBuildArray(arr: Object, arrayValue: ArrayValue): void { + this.buffer.append('['); + const length = arrayValue.getLength().toInt(); + this.checkReferencesCycle(arr); + this.store.add(arr); + for (let idx = 0; idx < length; idx++) { + let member = arrayValue.getElement(idx).getData(); + if (member == null) { + this.buffer.append('null'); + } else { + this.writeObject(member); + } + if (idx < length - 1) { + this.buffer.append(','); + } + } + this.store.delete(arr); + this.buffer.append(']'); + } + + private writeRecord(rec: Record): void { + this.buffer.append('{'); + this.checkReferencesCycle(rec); + this.store.add(rec); + let isFirst = true; + for (let key of rec.keys()) { + if (rec[key] !== undefined) { + if (!isFirst) { + this.buffer.append(','); + } else { + isFirst = false; + } + this.buffer.append(JSON.stringify(key as String)); + this.buffer.append(':'); + this.writeObject(rec[key]); + } + } + this.store.delete(rec); + this.buffer.append('}'); + } + + private checkReferencesCycle(obj: Object): void { + if (this.store.has(obj)) { + throw new TypeError('cyclic object value'); + } + } +} + +export class RecordSerializeTool { + public static stringifyNoThrow(obj: Record): String { + try { + return RecordSerializeTool.stringify(obj as Object as Record); + } catch (err) { + return err.toString(); + } + } + + public static parseNoThrow(text: string): Record { + try { + return RecordSerializeTool.parse(text) as Object as Record; + } catch (err) { + console.log('err: ' + err.toString()); + return new Record(); + } + } + + public static stringify(obj: Record): String { + return new RecordWriter().write(obj); + } + + public static parse(text: string): Record { + let jsonValue = JSONParser.parse(text); + let res = RecordSerializeTool.jsonValue2Object(jsonValue); + if (!(res instanceof Record)) { + throw new TypeError('RecordSerializeTool parse only used for Record'); + } + return res as Record; + } + + private static jsonValue2Object(value: JSONValue): string | number | boolean | null | + Array | Record { + if (value instanceof JSONString) { + return value.value; + } else if (value instanceof JSONNumber) { + return new Double(value.value); + } else if (value instanceof JSONTrue) { + return new Boolean(true); + } else if (value instanceof JSONFalse) { + return new Boolean(false); + } else if (value instanceof JSONNull) { + return null; + } else if (value instanceof JSONArray) { + let obj = value as JSONArray; + let values = obj.values; + let result: Array = new Array(); + for (let i: int = 0; i < values.length; i++) { + result.push(RecordSerializeTool.jsonValue2Object(values[i])); + } + return result; + } else if (value instanceof JSONObject) { + let obj = value as JSONObject; + let keys: Array = obj.keys_; + let values: Array = obj.values; + let result: Record = new Record(); + for (let i: int = 0; i < keys.length; i++) { + result[keys[i].value] = RecordSerializeTool.jsonValue2Object(values[i]); + } + return result; + } else { + throw new TypeError('unknown JSONValue'); + } + } +} diff --git a/frameworks/ani/event_emitter/include/sts_events_emitter.h b/frameworks/emitter/ani/include/ani_emitter.h similarity index 40% rename from frameworks/ani/event_emitter/include/sts_events_emitter.h rename to frameworks/emitter/ani/include/ani_emitter.h index 482ed99..bc0955e 100644 --- a/frameworks/ani/event_emitter/include/sts_events_emitter.h +++ b/frameworks/emitter/ani/include/ani_emitter.h @@ -1,72 +1,93 @@ -/* - * 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 STS_EVENTS_EMITTER_H -#define STS_EVENTS_EMITTER_H - -#include -#include -#include "ani.h" -#include "../../../interfaces/inner_api/inner_event.h" -#include "event_queue.h" -#include "event_handler.h" - -namespace OHOS { -namespace AppExecFwk { - -using Priority = EventQueue::Priority; -using EventDataAni = std::shared_ptr; -struct AniAsyncCallbackInfo { - ani_env* env; - std::atomic once = false; - std::atomic isDeleted = false; - ani_object data = nullptr; - std::string dataType; - ani_ref callback = 0; - InnerEvent::EventId eventId; - ~AniAsyncCallbackInfo(); -}; - -class EventsEmitter { -public: - static std::string GetStdString(ani_env *env, ani_string str); - static std::shared_ptr SearchCallbackInfo( - ani_env *env, const InnerEvent::EventId &eventIdValue, ani_ref callback); - static void ReleaseCallbackInfo(ani_env *env, AniAsyncCallbackInfo* callbackInfo); - static void UpdateOnceFlag(std::shared_ptrcallbackInfo, bool once); - static void DeleteCallbackInfo(ani_env *env, const InnerEvent::EventId &eventIdValue, ani_ref callback); - static void OnOrOnce(ani_env *env, InnerEvent::EventId eventId, bool once, ani_ref callback, ani_string dataType); - static void OffEmitterInstances(InnerEvent::EventId eventId); - static void AniWrap(ani_env *env, ani_ref callback); - static ani_double GetListenerCount(InnerEvent::EventId eventId); - static bool IsExistValidCallback(const InnerEvent::EventId &eventId, ani_object eventData); - static void EmitWithEventId(ani_env *env, ani_object innerEvent, ani_object eventData); - static void EmitWithEventIdString( - ani_env *env, ani_string eventId, ani_object eventData, ani_enum_item enumItem); - static void ThreadFunction(ani_env* env, ani_ref callback, ani_object data, std::string dataType); -}; - -class EventsEmitterInstance : public EventHandler { -public: - EventsEmitterInstance(const std::shared_ptr& runner); - static std::shared_ptr GetInstance(); - void ProcessEvent(const InnerEvent::Pointer& event) override; - std::unordered_set> GetAsyncCallbackInfo(const InnerEvent::EventId &eventId); - ~EventsEmitterInstance(); -}; -} -} - -#endif // STS_EVENTS_EMITTER_H \ No newline at end of file +/* + * 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 BASE_EVENTHANDLER_FRAMEWORKS_ANI_EMITTER_H +#define BASE_EVENTHANDLER_FRAMEWORKS_ANI_EMITTER_H + +#include +#include "inner_event.h" +#include "event_queue.h" +#include "ani.h" +#include "ani_serialize.h" + +namespace OHOS { +namespace AppExecFwk { + +using Priority = EventQueue::Priority; +using EventDataAni = std::shared_ptr; + +class EventsEmitter { +public: + /** + * Convert ani_string to std::string. + * + * @param env A pointer to the environment structure. + * @param str An ani_string to be converted. + * @return Returns a std::string of input str. + */ + static std::string GetStdString(ani_env *env, ani_string str); + + /** + * Subscribe an event of given event id. + * + * @param env A pointer to the environment structure. + * @param eventId Event id. + * @param once Whether subscribe once. if true, subscribe once. + * @param callback Event's callback. + * @param dataType Data type of callback's parameter. + */ + static void OnOrOnce(ani_env *env, InnerEvent::EventId eventId, bool once, ani_ref callback, ani_string dataType); + + /** + * Unsubscribe all of given event id. + * + * @param eventId Event id. + */ + static void OffEmitterInstances(InnerEvent::EventId eventId); + + /** + * Get all listener counts of given event id. + * + * @param eventId Event id. + * @return Returns all listener counts of given event id. + */ + static ani_double GetListenerCount(InnerEvent::EventId eventId); + + /** + * Emit an event of given event id. + * + * @param env A pointer to the environment structure. + * @param innerEvent An event structure including event id. + * @param eventData Data to be emitted. + */ + static void EmitWithEventId(ani_env *env, ani_object innerEvent, ani_object eventData); + + /** + * Emit an event of given event id. + * + * @param env A pointer to the environment structure. + * @param eventId Event id. + * @param eventData Data to be emitted. + * @param enumItem Prority of event. + */ + static void EmitWithEventIdString(ani_env *env, ani_string eventId, ani_object eventData, ani_enum_item enumItem); + +private: + static std::shared_ptr GetSharedSerializeData(ani_env *env); +}; + +} // namespace AppExecFwk +} // namespace OHOS +#endif // BASE_EVENTHANDLER_FRAMEWORKS_ANI_EMITTER_H \ No newline at end of file diff --git a/frameworks/emitter/ani/include/ani_serialize.h b/frameworks/emitter/ani/include/ani_serialize.h new file mode 100644 index 0000000..2c2016f --- /dev/null +++ b/frameworks/emitter/ani/include/ani_serialize.h @@ -0,0 +1,51 @@ +/* + * 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 BASE_EVENTHANDLER_FRAMEWORKS_ANI_SERIALIZE_H +#define BASE_EVENTHANDLER_FRAMEWORKS_ANI_SERIALIZE_H + +#include +#include "serialize.h" + +namespace OHOS { +namespace AppExecFwk { + +class AniSerialize { +public: + /** + * Serialize from ani to ani. + * + * @param env A pointer to the environment structure. + * @param argv Object to be serialized. + * @param serializeData Object to store serialized data. + * @return Returns true if serialize successfully. + */ + static bool PeerSerialize(ani_env* env, ani_object argv, std::shared_ptr serializeData); + + /** + * Serialize from ani to napi. + * + * @param env A pointer to the environment structure. + * @param argv Object to be serialized. + * @param serializeData Object to store serialized data. + * @return Returns true if serialize successfully. + */ + static bool CrossSerialize(ani_env* env, ani_object argv, std::shared_ptr serializeData); +}; + +} // namespace AppExecFwk +} // namespace OHOS + +#endif // BASE_EVENTHANDLER_FRAMEWORKS_ANI_SERIALIZE_H \ No newline at end of file diff --git a/frameworks/emitter/ani/include/sts_events_json_common.h b/frameworks/emitter/ani/include/sts_events_json_common.h new file mode 100644 index 0000000..0dd68a8 --- /dev/null +++ b/frameworks/emitter/ani/include/sts_events_json_common.h @@ -0,0 +1,50 @@ +/* + * 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_EVENTS_JSON_COMMON_H +#define OHOS_EVENTS_JSON_COMMON_H + +#include +#include "ani.h" + +namespace OHOS { +namespace AppExecFwk { + +bool GetDoubleOrUndefined(ani_env *env, ani_object param, const char *name, ani_double &value); +bool GetBoolOrUndefined(ani_env *env, ani_object param, const char *name); +bool GetStringOrUndefined(ani_env *env, ani_object param, const char *name, std::string &res); +bool GetIntByName(ani_env *env, ani_object param, const char *name, int &value); +bool GetStringArrayOrUndefined(ani_env *env, ani_object param, const char *name, std::vector &res); + +bool GetStdString(ani_env *env, ani_string str, std::string &res); + +ani_string GetAniString(ani_env *env, const std::string &str); +ani_array_ref GetAniArrayString(ani_env *env, const std::vector &values); +bool GetRefPropertyByName(ani_env *env, ani_object param, const char *name, ani_ref &ref); + +ani_object createDouble(ani_env *env, ani_double value); +ani_object createBoolean(ani_env *env, ani_boolean value); + +bool SetFieldString(ani_env *env, ani_class cls, ani_object object, + const std::string &fieldName, const std::string &value); +bool SetFieldDouble(ani_env *env, ani_class cls, ani_object object, const std::string &fieldName, double value); +bool SetFieldBoolean(ani_env *env, ani_class cls, ani_object object, const std::string &fieldName, bool value); +bool SetFieldInt(ani_env *env, ani_class cls, ani_object object, const std::string &fieldName, int value); +bool SetFieldArrayString(ani_env *env, ani_class cls, ani_object object, const std::string &fieldName, + const std::vector &values); +bool SetFieldRef(ani_env *env, ani_class cls, ani_object object, const std::string &fieldName, ani_ref value); +} // namespace AppExecFwk +} // namespace OHOS +#endif // OHOS_EVENTS_JSON_COMMON_H \ No newline at end of file diff --git a/frameworks/ani/event_emitter/src/sts_events_emitter.cpp b/frameworks/emitter/ani/src/ani_emitter.cpp similarity index 39% rename from frameworks/ani/event_emitter/src/sts_events_emitter.cpp rename to frameworks/emitter/ani/src/ani_emitter.cpp index 701b34c..1eeec4e 100644 --- a/frameworks/ani/event_emitter/src/sts_events_emitter.cpp +++ b/frameworks/emitter/ani/src/ani_emitter.cpp @@ -1,565 +1,372 @@ -/* - * 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 "sts_events_emitter.h" - -#include -#include -#include -#include -#include -#include -#include "event_logger.h" -#include "event_handler.h" - -namespace OHOS { -namespace AppExecFwk { - -namespace { - DEFINE_EH_HILOG_LABEL("EventsEmitter"); - constexpr const char* EVENT_DATA = "eventData"; - constexpr const char* GENERIC_EVENT_DATA = "genericEventData"; -} - -static std::mutex g_eventsEmitterInsMutex; -static std::map>> eventsEmitterInstances; -std::shared_ptr eventHandler; - -AniAsyncCallbackInfo::~AniAsyncCallbackInfo() -{ - env = nullptr; -} - -EventsEmitterInstance::EventsEmitterInstance(const std::shared_ptr& runner): EventHandler(runner) -{ - HILOGI("EventHandlerInstance constructed"); -} -EventsEmitterInstance::~EventsEmitterInstance() -{ -} - -std::shared_ptr EventsEmitterInstance::GetInstance() -{ - static auto runner = EventRunner::Create("OS_eventsEmtr", ThreadMode::FFRT); - if (runner.get() == nullptr) { - HILOGE("failed to create EventRunner events_emitter"); - return nullptr; - } - static auto instance = std::make_shared(runner); - return instance; -} - -void EventsEmitterInstance::ProcessEvent(const InnerEvent::Pointer& event) -{ - InnerEvent::EventId eventId = event->GetInnerEventIdEx(); - auto callbackInfos = GetAsyncCallbackInfo(eventId); - if (callbackInfos.size() <= 0) { - HILOGW("ProcessEvent has no valid callback"); - return; - } - for (auto it = callbackInfos.begin(); it != callbackInfos.end(); ++it) { - HILOGI("callbackInfo begin\n"); - if (*it == nullptr) { - HILOGE("*it is empty\n"); - continue; - } - - auto t = std::thread(EventsEmitter::ThreadFunction, (*it)->env, (*it)->callback, (*it)->data, (*it)->dataType); - t.join(); - HILOGD("callbackInfo end\n"); - } -} - -std::unordered_set> EventsEmitterInstance::GetAsyncCallbackInfo( - const InnerEvent::EventId &eventId) -{ - std::lock_guard lock(g_eventsEmitterInsMutex); - auto iter = eventsEmitterInstances.find(eventId); - if (iter == eventsEmitterInstances.end()) { - std::unordered_set> result; - HILOGW("ProcessEvent has no callback"); - return result; - } - for (auto it = iter->second.begin(); it != iter->second.end();) { - if ((*it)->isDeleted == true || (*it)->env == nullptr) { - it = iter->second.erase(it); - continue; - } - ++it; - } - return iter->second; -} - -std::string EventsEmitter::GetStdString(ani_env *env, ani_string str) -{ - std::string result; - ani_size sz {}; - env->String_GetUTF8Size(str, &sz); - result.resize(sz + 1); - env->String_GetUTF8SubString(str, 0, sz, result.data(), result.size(), &sz); - result.resize(sz); - return result; -} - -std::shared_ptr EventsEmitter::SearchCallbackInfo( - ani_env *env, const InnerEvent::EventId &eventIdValue, ani_ref callback) -{ - auto subscribe = eventsEmitterInstances.find(eventIdValue); - if (subscribe == eventsEmitterInstances.end()) { - return nullptr; - } - for (auto callbackInfo : subscribe->second) { - if (callbackInfo->isDeleted) { - continue; - } - if (callbackInfo->env != env) { - continue; - } - ani_boolean isEq = false; - env->Reference_StrictEquals(callback, callbackInfo->callback, &isEq); - if (!isEq) { - continue; - } - return callbackInfo; - } - return nullptr; -} - -void EventsEmitter::ReleaseCallbackInfo(ani_env *env, AniAsyncCallbackInfo* callbackInfo) -{ - if (callbackInfo != nullptr) { - callbackInfo->env->GlobalReference_Delete(callbackInfo->callback); - delete callbackInfo; - callbackInfo = nullptr; - } -} - -void EventsEmitter::UpdateOnceFlag(std::shared_ptrcallbackInfo, bool once) -{ - if (!once) { - if (callbackInfo->once) { - HILOGD("JS_On change once to on"); - callbackInfo->once = false; - } else { - HILOGD("JS_On already on"); - } - } else { - if (callbackInfo->once) { - HILOGD("JS_Once already once"); - } else { - HILOGD("JS_Once change on to once"); - callbackInfo->once = true; - } - } -} - -void EventsEmitter::DeleteCallbackInfo(ani_env *env, const InnerEvent::EventId &eventIdValue, ani_ref callback) -{ - std::lock_guard lock(g_eventsEmitterInsMutex); - auto iter = eventsEmitterInstances.find(eventIdValue); - if (iter == eventsEmitterInstances.end()) { - return; - } - for (auto callbackInfo = iter->second.begin(); callbackInfo != iter->second.end();) { - if ((*callbackInfo)->env != env) { - ++callbackInfo; - continue; - } - HILOGD("DeleteCallbackInfo env equal"); - ani_boolean isEq = false; - env->Reference_StrictEquals(callback, (*callbackInfo)->callback, &isEq); - if (!isEq) { - ++callbackInfo; - continue; - } - HILOGD("DeleteCallbackInfo callback equal"); - (*callbackInfo)->isDeleted = true; - callbackInfo = iter->second.erase(callbackInfo); - HILOGD("DeleteCallbackInfo success"); - return; - } -} - -void EventsEmitter::OffEmitterInstances(InnerEvent::EventId eventIdValue) -{ - HILOGD("offeventsEmitterInstances begin"); - std::lock_guard lock(g_eventsEmitterInsMutex); - auto subscribe = eventsEmitterInstances.find(eventIdValue); - if (subscribe != eventsEmitterInstances.end()) { - HILOGD("offeventsEmitterInstances_find"); - for (auto callbackInfo : subscribe->second) { - callbackInfo->isDeleted = true; - } - } - eventsEmitterInstances.erase(eventIdValue); -} - -void EventsEmitter::AniWrap(ani_env *env, ani_ref callback) -{ - static const char *nameSpace = "L@ohos/events/emitter/emitter;"; - ani_namespace cls; - if (ANI_OK != env->FindNamespace(nameSpace, &cls)) { - HILOGE("Not found '%{public}s'", nameSpace); - return; - } -} - -void EventsEmitter::OnOrOnce( - ani_env *env, InnerEvent::EventId eventId, bool once, ani_ref callback, ani_string dataType) -{ - HILOGD("onOrOncebegin\n"); - std::lock_guard lock(g_eventsEmitterInsMutex); - auto callbackInfo = SearchCallbackInfo(env, eventId, callback); - if (callbackInfo != nullptr) { - UpdateOnceFlag(callbackInfo, once); - } else { - callbackInfo = std::shared_ptr(new (std::nothrow) AniAsyncCallbackInfo(), - [env](AniAsyncCallbackInfo* callbackInfo) { - ReleaseCallbackInfo(env, callbackInfo); - }); - if (!callbackInfo) { - HILOGE("new object failed"); - return; - } - callbackInfo->env = env; - callbackInfo->once = once; - callbackInfo->eventId = eventId; - env->GlobalReference_Create(callback, &callbackInfo->callback); - callbackInfo->dataType = EventsEmitter::GetStdString(env, dataType); - AniWrap(env, callback); - eventsEmitterInstances[eventId].insert(callbackInfo); - HILOGD("onOrOnceEnd\n"); - } -} - -ani_double EventsEmitter::GetListenerCount(InnerEvent::EventId eventId) -{ - ani_double cnt = 0; - std::lock_guard lock(g_eventsEmitterInsMutex); - auto subscribe = eventsEmitterInstances.find(eventId); - if (subscribe != eventsEmitterInstances.end()) { - for (auto it = subscribe->second.begin(); it != subscribe->second.end();) { - if ((*it)->isDeleted == true || (*it)->env == nullptr) { - it = subscribe->second.erase(it); - continue; - } - ++it; - ++cnt; - } - } - return cnt; -} - -bool EventsEmitter::IsExistValidCallback(const InnerEvent::EventId &eventId, ani_object eventData) -{ - HILOGI("IsExistValidCallback begin"); - std::lock_guard lock(g_eventsEmitterInsMutex); - auto subscribe = eventsEmitterInstances.find(eventId); - if (subscribe == eventsEmitterInstances.end()) { - HILOGW("Emit has no callback"); - return false; - } - if (subscribe->second.size() != 0) { - for (auto it = subscribe->second.begin(); it != subscribe->second.end(); ++it) { - if (*it != nullptr && eventData != nullptr) { - (*it)->env->GlobalReference_Create(eventData, reinterpret_cast(&(*it)->data)); - } - } - return true; - } - return false; -} - -void EventsEmitter::EmitWithEventId(ani_env *env, ani_object InnerEvent, ani_object eventData) -{ - HILOGI("EmitWithEventId begin"); - ani_double eventId = 0; - ani_status status = ANI_ERROR; - if ((status = env->Object_GetPropertyByName_Double(InnerEvent, "eventId", &eventId)) != ANI_OK) { - HILOGE("eventId not find"); - return; - } - HILOGI("EmitWithEventId eventId: %f\n", eventId); - InnerEvent::EventId id = (uint32_t)eventId; - if (!IsExistValidCallback(id, eventData)) { - HILOGW("Emit has no callback"); - return; - } - - ani_ref obj; - ani_boolean isUndefined = true; - status = ANI_ERROR; - Priority priority = Priority::LOW; - if ((status = env->Object_GetPropertyByName_Ref(InnerEvent, "priority", &obj)) == ANI_OK) { - HILOGD("get priority"); - if ((status = env->Reference_IsUndefined(obj, &isUndefined)) == ANI_OK) { - HILOGD("get priority isUndefined success"); - if (!isUndefined) { - HILOGD("get priority not undefined"); - ani_int res; - env->EnumItem_GetValue_Int(reinterpret_cast(obj), &res); - HILOGD("priority is %{public}d", res); - priority = static_cast(res); - } - } - } - HILOGD("get priority end"); - auto event = InnerEvent::Get(id, std::make_unique()); - eventHandler->SendEvent(event, 0, priority); - HILOGD("EmitWithEventId end"); -} - -void EventsEmitter::EmitWithEventIdString( - ani_env *env, ani_string eventId, ani_object eventData, ani_enum_item enumItem) -{ - InnerEvent::EventId id = GetStdString(env, eventId); - if (!IsExistValidCallback(id, eventData)) { - HILOGI("Emit has no callback"); - return; - } - Priority priority = Priority::LOW; - - if (enumItem !=nullptr) { - ani_int res; - env->EnumItem_GetValue_Int(enumItem, &res); - HILOGD("priority is %{public}d", res); - priority = static_cast(res); - return; - } - - auto event = InnerEvent::Get(id, std::make_unique()); - eventHandler->SendEvent(event, 0, priority); -} - -void EventsEmitter::ThreadFunction(ani_env *env, ani_ref callback, ani_object data, std::string dataType) -{ - HILOGD("threadFunciton begin"); - ani_vm *etsVm; - ani_env *etsEnv; - [[maybe_unused]] int res = env->GetVM(&etsVm); - if (res != ANI_OK) { - return; - } - HILOGD("threadFunciton GetVM success"); - ani_option interopEnabled {"--interop=disable", nullptr}; - ani_options aniArgs {1, &interopEnabled}; - if (ANI_OK != etsVm->AttachCurrentThread(&aniArgs, ANI_VERSION_1, &etsEnv)) { - return; - } - HILOGD("threadFunciton AttachCurrentThread success"); - auto fnObj = reinterpret_cast(callback); - if (fnObj == nullptr) { - HILOGE("threadFunciton fnObj is nullptr"); - etsVm->DetachCurrentThread(); - return; - } - std::vector args; - if (data == nullptr) { - HILOGD("threadFunciton data is nullptr"); - ani_class cls; - ani_status status = ANI_ERROR; - if (dataType == EVENT_DATA) { - status = etsEnv->FindClass("L@ohos/events/emitter/emitter/EventDataInner;", &cls); - } else if (dataType == GENERIC_EVENT_DATA) { - status = etsEnv->FindClass("L@ohos/events/emitter/emitter/GenericEventDataInner;", &cls); - } - if (status != ANI_OK) { - HILOGE("threadFunciton FindClass error%{public}d", status); - etsVm->DetachCurrentThread(); - return; - } - ani_method ctor1; - status = etsEnv->Class_FindMethod(cls, "", ":V", &ctor1); - if (status != ANI_OK) { - HILOGE("threadFunciton Class_FindMethod error%{public}d", status); - etsVm->DetachCurrentThread(); - return; - } - ani_object obj1; - status = etsEnv->Object_New(cls, ctor1, &obj1); - if (status != ANI_OK) { - HILOGE("threadFunciton Object_New error%{public}d", status); - etsVm->DetachCurrentThread(); - return; - } - HILOGD("threadFunciton Object_New create"); - args.push_back(reinterpret_cast(obj1)); - } else { - args.push_back(reinterpret_cast(data)); - } - ani_ref result; - if (ANI_OK != etsEnv->FunctionalObject_Call(fnObj, args.size(), args.data(), &result)) { - etsVm->DetachCurrentThread(); - return; - } - - HILOGD("hello thread"); - if (ANI_OK != etsVm->DetachCurrentThread()) { - return; - } -} - -static void OnOrOnceSync(ani_env *env, ani_double eventId, ani_boolean once, ani_ref callback, ani_string dataType) -{ - HILOGD("OnOrOnceSync begin"); - InnerEvent::EventId id = (uint32_t)eventId; - EventsEmitter::OnOrOnce(env, id, once, callback, dataType); -} - -static void OnOrOnceStringSync( - ani_env *env, ani_string eventId, ani_boolean once, ani_ref callback, ani_string dataType) -{ - HILOGD("OnOrOnceStringSync begin"); - InnerEvent::EventId id = EventsEmitter::GetStdString(env, eventId); - EventsEmitter::OnOrOnce(env, id, once, callback, dataType); -} - -static void OnOrOnceGenericEventSync( - ani_env *env, ani_string eventId, ani_boolean once, ani_ref callback, ani_string dataType) -{ - HILOGD("OnOrOnceGenericEventSync begin"); - InnerEvent::EventId id = EventsEmitter::GetStdString(env, eventId); - EventsEmitter::OnOrOnce(env, id, once, callback, dataType); -} - -static void OffStringSync(ani_env *env, ani_string eventId, ani_ref callback) -{ - HILOGD("OffStringSync begin"); - InnerEvent::EventId id = EventsEmitter::GetStdString(env, eventId); - EventsEmitter::DeleteCallbackInfo(env, id, callback); -} - -static void OffGenericEventSync(ani_env *env, ani_string eventId, ani_ref callback) -{ - HILOGD("OffGenericEventSync begin"); - InnerEvent::EventId id = EventsEmitter::GetStdString(env, eventId); - EventsEmitter::DeleteCallbackInfo(env, id, callback); -} - -static void OffNumberSync(ani_env *env, ani_double eventId) -{ - HILOGD("OffNumberSync begin"); - InnerEvent::EventId id = (uint32_t)eventId; - EventsEmitter::OffEmitterInstances(id); -} - -static void OffNumberCallbackSync(ani_env *env, ani_double eventId, ani_ref callback) -{ - HILOGD("OffNumberCallbackSync begin"); - InnerEvent::EventId id = (uint32_t)eventId; - EventsEmitter::DeleteCallbackInfo(env, id, callback); -} - -static ani_double getListenerCountNumber(ani_env *env, ani_double eventId) -{ - HILOGD("getListenerCountNumber begin"); - InnerEvent::EventId id = (uint32_t)eventId; - return EventsEmitter::GetListenerCount(id); -} - -static ani_double getListenerCountString(ani_env *env, ani_string eventId) -{ - HILOGD("getListenerCountString begin"); - InnerEvent::EventId id = EventsEmitter::GetStdString(env, eventId); - return EventsEmitter::GetListenerCount(id); -} - -static void EmitStringSync(ani_env *env, ani_string eventId) -{ - HILOGD("EmitStringSync begin"); - EventsEmitter::EmitWithEventIdString(env, eventId, nullptr, nullptr); -} - -static void EmitStringDataSync(ani_env *env, ani_string eventId, ani_string EventData) -{ - HILOGD("EmitStringDataSync begin"); - EventsEmitter::EmitWithEventIdString(env, eventId, EventData, nullptr); -} - -static void EmitStringGenericSync(ani_env *env, ani_string eventId, ani_object GenericEventData) -{ - HILOGD("EmitStringGenericSync begin"); - EventsEmitter::EmitWithEventIdString(env, eventId, GenericEventData, nullptr); -} - -static void EmitInnerEventSync(ani_env *env, ani_object InnerEvent) -{ - HILOGD("EmitInnerEventSync begin"); - EventsEmitter::EmitWithEventId(env, InnerEvent, nullptr); -} - -static void EmitInnerEventDataSync(ani_env *env, ani_object InnerEvent, ani_object EventData) -{ - HILOGD("EmitInnerEventDataSync begin"); - EventsEmitter::EmitWithEventId(env, InnerEvent, EventData); -} - -extern "C" { -ANI_EXPORT ani_status ANI_Constructor(ani_vm *vm, uint32_t *result) -{ - HILOGD("ANI_Constructor begin"); - eventHandler = EventsEmitterInstance::GetInstance(); - ani_status status = ANI_ERROR; - ani_env *env; - if (ANI_OK != vm->GetEnv(ANI_VERSION_1, &env)) { - HILOGE("Unsupported ANI_VERSION_1."); - return ANI_ERROR; - } - - ani_namespace kitNs; - status = env->FindNamespace("L@ohos/events/emitter/emitter;", &kitNs); - if (status != ANI_OK) { - HILOGE("Not found ani_namespace L@ohos/events/emitter/emitter"); - return ANI_INVALID_ARGS; - } - - std::array methods = { - ani_native_function{"OnOrOnceSync", nullptr, reinterpret_cast(OnOrOnceSync)}, - ani_native_function{"OnOrOnceStringSync", nullptr, reinterpret_cast(OnOrOnceStringSync)}, - ani_native_function{"OnOrOnceGenericEventSync", nullptr, reinterpret_cast(OnOrOnceGenericEventSync)}, - ani_native_function{"OffStringSync", nullptr, reinterpret_cast(OffStringSync)}, - ani_native_function{"OffGenericEventSync", nullptr, reinterpret_cast(OffGenericEventSync)}, - ani_native_function{"OffNumberSync", "D:V", reinterpret_cast(OffNumberSync)}, - ani_native_function{"OffNumberCallbackSync", nullptr, reinterpret_cast(OffNumberCallbackSync)}, - ani_native_function{"getListenerCountSync", "D:D", reinterpret_cast(getListenerCountNumber)}, - ani_native_function{"getListenerCountStringSync", - "Lstd/core/String;:D", reinterpret_cast(getListenerCountString)}, - ani_native_function{"EmitInnerEventSync", "L@ohos/events/emitter/emitter/InnerEvent;:V", - reinterpret_cast(EmitInnerEventSync)}, - ani_native_function{"EmitInnerEventDataSync", - "L@ohos/events/emitter/emitter/InnerEvent;L@ohos/events/emitter/emitter/EventData;:V", - reinterpret_cast(EmitInnerEventDataSync)}, - ani_native_function{"EmitStringSync", "Lstd/core/String;:V", reinterpret_cast(EmitStringSync)}, - ani_native_function{"EmitStringDataSync", - "Lstd/core/String;L@ohos/events/emitter/emitter/EventData;:V", - reinterpret_cast(EmitStringDataSync)}, - ani_native_function{"EmitStringGenericSync", - "Lstd/core/String;L@ohos/events/emitter/emitter/GenericEventData;:V", - reinterpret_cast(EmitStringGenericSync)}, - }; - - status = env->Namespace_BindNativeFunctions(kitNs, methods.data(), methods.size()); - if (status != ANI_OK) { - HILOGE("Cannot bind native methods to L@ohos/events/emitter/emitter"); - return ANI_INVALID_TYPE; - } - - *result = ANI_VERSION_1; - return ANI_OK; -} -} - -} // namespace AppExecFwk +/* + * 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_emitter.h" + +#include "event_logger.h" +#include "aync_callback_manager.h" +#include "interops.h" +#include "napi_agent.h" + +namespace OHOS { +namespace AppExecFwk { + +namespace { +DEFINE_EH_HILOG_LABEL("EventsEmitter"); +} +std::string EventsEmitter::GetStdString(ani_env *env, ani_string str) +{ + std::string result; + ani_size sz {}; + env->String_GetUTF8Size(str, &sz); + result.resize(sz + 1); + env->String_GetUTF8SubString(str, 0, sz, result.data(), result.size(), &sz); + result.resize(sz); + return result; +} + +void EventsEmitter::OnOrOnce( + ani_env *env, InnerEvent::EventId eventId, bool once, ani_ref callback, ani_string dataType) +{ + AsyncCallbackManager::GetInstance().InsertCallbackInfo(env, eventId, once, callback, dataType); +} + +void EventsEmitter::OffEmitterInstances(InnerEvent::EventId eventIdValue) +{ + AsyncCallbackManager::GetInstance().DeleteCallbackInfoByEventId(eventIdValue); +} + +std::shared_ptr EventsEmitter::GetSharedSerializeData(ani_env *env) +{ + auto serializeDataPtr = new (std::nothrow) SerializeData(); + if (serializeDataPtr == nullptr) { + HILOGE("memory allocation failed"); + return nullptr; + } + ani_vm* vm = nullptr; + auto status = env->GetVM(&vm); + if (vm == nullptr) { + HILOGE("Get vm failed. status: %{public}d", status); + return nullptr; + } + std::shared_ptr serializeData(serializeDataPtr, [vm](SerializeData* data) { + if (data == nullptr) { + return; + } + if (std::holds_alternative(data->peerData)) { + ani_env *env; + ani_status status = ANI_OK; + status = vm->GetEnv(ANI_VERSION_1, &env); + if (status == ANI_OK) { + status = env->GlobalReference_Delete(std::get(data->peerData)); + delete data; + data = nullptr; + return; + } + ani_option interopEnabled {"--interop=disable", nullptr}; + ani_options aniArgs {1, &interopEnabled}; + status = vm->AttachCurrentThread(&aniArgs, ANI_VERSION_1, &env); + if (status != ANI_OK) { + HILOGE("attach thread failed"); + delete data; + data = nullptr; + return; + } + status = env->GlobalReference_Delete(std::get(data->peerData)); + vm->DetachCurrentThread(); + } + delete data; + data = nullptr; + }); + serializeData->envType = EnvType::ANI; + return serializeData; +} + +void EventsEmitter::EmitWithEventId(ani_env *env, ani_object InnerEvent, ani_object eventData) +{ + ani_double eventId = 0; + ani_status status = ANI_ERROR; + if ((status = env->Object_GetPropertyByName_Double(InnerEvent, "eventId", &eventId)) != ANI_OK) { + HILOGE("eventId not find"); + return; + } + InnerEvent::EventId id = static_cast(eventId); + if (!AsyncCallbackManager::GetInstance().IsExistValidCallback(id)) { + HILOGI("Emit has no callback"); + return; + } + ani_ref obj; + ani_boolean isUndefined = true; + status = ANI_ERROR; + Priority priority = Priority::LOW; + if ((status = env->Object_GetPropertyByName_Ref(InnerEvent, "priority", &obj)) == ANI_OK) { + if ((status = env->Reference_IsUndefined(obj, &isUndefined)) == ANI_OK) { + if (!isUndefined) { + ani_int res; + env->EnumItem_GetValue_Int(reinterpret_cast(obj), &res); + priority = static_cast(res); + } + } + } + auto serializeData = EventsEmitter::GetSharedSerializeData(env); + if (serializeData == nullptr) { + return; + } + if (!AniSerialize::PeerSerialize(env, eventData, serializeData)) { + return; + } + if (AsyncCallbackManager::GetInstance().IsCrossRuntime(id, EnvType::ANI)) { + serializeData->isCrossRuntime = true; + if (!AniSerialize::CrossSerialize(env, eventData, serializeData)) { + return; + } + } + auto event = InnerEvent::Get(id, serializeData); + event->SetIsEnhanced(true); + EventHandlerInstance::GetInstance()->SendEvent(event, 0, priority); +} + +void EventsEmitter::EmitWithEventIdString( + ani_env *env, ani_string eventId, ani_object eventData, ani_enum_item enumItem) +{ + InnerEvent::EventId id = GetStdString(env, eventId); + if (!AsyncCallbackManager::GetInstance().IsExistValidCallback(id)) { + HILOGI("Emit has no callback"); + return; + } + Priority priority = Priority::LOW; + if (enumItem != nullptr) { + ani_int res; + env->EnumItem_GetValue_Int(enumItem, &res); + priority = static_cast(res); + } + auto serializeData = EventsEmitter::GetSharedSerializeData(env); + if (serializeData == nullptr) { + return; + } + if (!AniSerialize::PeerSerialize(env, eventData, serializeData)) { + return; + } + if (AsyncCallbackManager::GetInstance().IsCrossRuntime(id, EnvType::ANI)) { + serializeData->isCrossRuntime = true; + if (!AniSerialize::CrossSerialize(env, eventData, serializeData)) { + return; + } + } + auto event = InnerEvent::Get(id, serializeData); + event->SetIsEnhanced(true); + EventHandlerInstance::GetInstance()->SendEvent(event, 0, priority); +} + +ani_double EventsEmitter::GetListenerCount(InnerEvent::EventId eventId) +{ + return AsyncCallbackManager::GetInstance().GetListenerCountByEventId(eventId); +} + +static void OnOrOnceSync(ani_env *env, ani_double eventId, ani_boolean once, ani_ref callback, ani_string dataType) +{ + InnerEvent::EventId id = static_cast(eventId); + EventsEmitter::OnOrOnce(env, id, once, callback, dataType); +} + +static void OnOrOnceStringSync( + ani_env *env, ani_string eventId, ani_boolean once, ani_ref callback, ani_string dataType) +{ + InnerEvent::EventId id = EventsEmitter::GetStdString(env, eventId); + EventsEmitter::OnOrOnce(env, id, once, callback, dataType); +} + +static void OnOrOnceGenericEventSync( + ani_env *env, ani_string eventId, ani_boolean once, ani_ref callback, ani_string dataType) +{ + InnerEvent::EventId id = EventsEmitter::GetStdString(env, eventId); + EventsEmitter::OnOrOnce(env, id, once, callback, dataType); +} + +static void OffStringIdSync(ani_env *env, ani_string eventId) +{ + InnerEvent::EventId id = EventsEmitter::GetStdString(env, eventId); + EventsEmitter::OffEmitterInstances(id); +} + +static void OffStringSync(ani_env *env, ani_string eventId, ani_ref callback) +{ + InnerEvent::EventId id = EventsEmitter::GetStdString(env, eventId); + AsyncCallbackManager::GetInstance().DeleteCallbackInfo(env, id, callback); +} + +static void OffGenericEventSync(ani_env *env, ani_string eventId, ani_ref callback) +{ + InnerEvent::EventId id = EventsEmitter::GetStdString(env, eventId); + AsyncCallbackManager::GetInstance().DeleteCallbackInfo(env, id, callback); +} + +static void OffNumberSync(ani_env *env, ani_double eventId) +{ + InnerEvent::EventId id = static_cast(eventId); + EventsEmitter::OffEmitterInstances(id); +} + +static void OffNumberCallbackSync(ani_env *env, ani_double eventId, ani_ref callback) +{ + InnerEvent::EventId id = static_cast(eventId); + AsyncCallbackManager::GetInstance().DeleteCallbackInfo(env, id, callback); +} + +static ani_double getListenerCountNumber(ani_env *env, ani_double eventId) +{ + InnerEvent::EventId id = static_cast(eventId); + return EventsEmitter::GetListenerCount(id); +} + +static ani_double getListenerCountString(ani_env *env, ani_string eventId) +{ + InnerEvent::EventId id = EventsEmitter::GetStdString(env, eventId); + return EventsEmitter::GetListenerCount(id); +} + +static void EmitStringSync(ani_env *env, ani_string eventId) +{ + EventsEmitter::EmitWithEventIdString(env, eventId, nullptr, nullptr); +} + +static void EmitStringDataSync(ani_env *env, ani_string eventId, ani_string EventData) +{ + EventsEmitter::EmitWithEventIdString(env, eventId, EventData, nullptr); +} + +static void EmitStringGenericSync(ani_env *env, ani_string eventId, ani_object GenericEventData) +{ + EventsEmitter::EmitWithEventIdString(env, eventId, GenericEventData, nullptr); +} + +static void EmitInnerEventSync(ani_env *env, ani_object InnerEvent) +{ + EventsEmitter::EmitWithEventId(env, InnerEvent, nullptr); +} + +static void EmitInnerEventDataSync(ani_env *env, ani_object InnerEvent, ani_object EventData) +{ + EventsEmitter::EmitWithEventId(env, InnerEvent, EventData); +} + +static ani_status GetPriority(ani_env *env, ani_object options, ani_enum_item &priority) +{ + ani_ref obj; + ani_boolean isUndefined = true; + ani_status status = env->Object_GetPropertyByName_Ref(options, "priority", &obj); + if (status == ANI_OK) { + status = env->Reference_IsUndefined(obj, &isUndefined); + if (status == ANI_OK) { + if (!isUndefined) { + priority = reinterpret_cast(obj); + } + } + } + return status; +} + +static void EmitStringOptionsSync(ani_env *env, ani_string eventId, ani_object options) +{ + ani_enum_item priority = nullptr; + GetPriority(env, options, priority); + EventsEmitter::EmitWithEventIdString(env, eventId, nullptr, priority); +} + +static void EmitStringOptionsGenericSync(ani_env *env, + ani_string eventId, ani_object options, ani_object GenericEventData) +{ + ani_enum_item priority = nullptr; + GetPriority(env, options, priority); + EventsEmitter::EmitWithEventIdString(env, eventId, GenericEventData, priority); +} + +static void EmitStringOptionsDataSync(ani_env *env, + ani_string eventId, ani_object options, ani_object EventData) +{ + ani_enum_item priority = nullptr; + GetPriority(env, options, priority); + EventsEmitter::EmitWithEventIdString(env, eventId, EventData, priority); +} + +ani_status init(ani_env *env, ani_namespace kitNs) +{ + std::array methods = { + ani_native_function{"OnOrOnceSync", nullptr, reinterpret_cast(OnOrOnceSync)}, + ani_native_function{"OnOrOnceStringSync", nullptr, reinterpret_cast(OnOrOnceStringSync)}, + ani_native_function{"OnOrOnceGenericEventSync", nullptr, reinterpret_cast(OnOrOnceGenericEventSync)}, + ani_native_function{"OffStringIdSync", nullptr, reinterpret_cast(OffStringIdSync)}, + ani_native_function{"OffStringSync", nullptr, reinterpret_cast(OffStringSync)}, + ani_native_function{"OffGenericEventSync", nullptr, reinterpret_cast(OffGenericEventSync)}, + ani_native_function{"OffNumberSync", "D:V", reinterpret_cast(OffNumberSync)}, + ani_native_function{"OffNumberCallbackSync", nullptr, reinterpret_cast(OffNumberCallbackSync)}, + ani_native_function{"getListenerCountSync", "D:D", reinterpret_cast(getListenerCountNumber)}, + ani_native_function{"getListenerCountStringSync", + "Lstd/core/String;:D", reinterpret_cast(getListenerCountString)}, + ani_native_function{"EmitInnerEventSync", "L@ohos/events/emitter/emitter/InnerEvent;:V", + reinterpret_cast(EmitInnerEventSync)}, + ani_native_function{"EmitInnerEventDataSync", + "L@ohos/events/emitter/emitter/InnerEvent;L@ohos/events/emitter/emitter/EventData;:V", + reinterpret_cast(EmitInnerEventDataSync)}, + ani_native_function{"EmitStringSync", "Lstd/core/String;:V", reinterpret_cast(EmitStringSync)}, + ani_native_function{"EmitStringDataSync", + "Lstd/core/String;L@ohos/events/emitter/emitter/EventData;:V", + reinterpret_cast(EmitStringDataSync)}, + ani_native_function{"EmitStringGenericSync", + "Lstd/core/String;L@ohos/events/emitter/emitter/GenericEventData;:V", + reinterpret_cast(EmitStringGenericSync)}, + ani_native_function{"EmitStringOptionsSync", + "Lstd/core/String;L@ohos/events/emitter/emitter/Options;:V", + reinterpret_cast(EmitStringOptionsSync)}, + ani_native_function{"EmitStringOptionsGenericSync", + "Lstd/core/String;L@ohos/events/emitter/emitter/Options;L@ohos/events/emitter/emitter/GenericEventData;:V", + reinterpret_cast(EmitStringOptionsGenericSync)}, + ani_native_function{"EmitStringOptionsDataSync", + "Lstd/core/String;L@ohos/events/emitter/emitter/Options;L@ohos/events/emitter/emitter/EventData;:V", + reinterpret_cast(EmitStringOptionsDataSync)}, + }; + AgentInit(); + return env->Namespace_BindNativeFunctions(kitNs, methods.data(), methods.size()); +} + +extern "C" { +ANI_EXPORT ani_status ANI_Constructor(ani_vm *vm, uint32_t *result) +{ + HILOGD("ANI_Constructor begin"); + ani_status status = ANI_ERROR; + ani_env *env; + if (ANI_OK != vm->GetEnv(ANI_VERSION_1, &env)) { + HILOGE("Unsupported ANI_VERSION_1."); + return ANI_ERROR; + } + + ani_namespace kitNs; + status = env->FindNamespace("L@ohos/events/emitter/emitter;", &kitNs); + if (status != ANI_OK) { + HILOGE("Not found ani_namespace L@ohos/events/emitter/emitter"); + return ANI_INVALID_ARGS; + } + status = init(env, kitNs); + if (status != ANI_OK) { + HILOGE("Cannot bind native methods to L@ohos/events/emitter/emitter"); + return ANI_INVALID_TYPE; + } + + *result = ANI_VERSION_1; + return ANI_OK; +} +} +} // namespace AppExecFwk } // namespace OHOS \ No newline at end of file diff --git a/frameworks/emitter/ani/src/ani_serialize.cpp b/frameworks/emitter/ani/src/ani_serialize.cpp new file mode 100644 index 0000000..cd07f0d --- /dev/null +++ b/frameworks/emitter/ani/src/ani_serialize.cpp @@ -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. + */ + +#include "ani_serialize.h" +#include "sts_events_json_common.h" +#include "event_logger.h" + +namespace OHOS { +namespace AppExecFwk { +namespace { +DEFINE_EH_HILOG_LABEL("EventsEmitter"); +} + +bool AniSerialize::PeerSerialize(ani_env* env, ani_object argv, std::shared_ptr serializeData) +{ + if (argv == nullptr) { + // emit with no data + return true; + } + ani_ref record = nullptr; + if (GetRefPropertyByName(env, argv, "data", record)) { + if (record == nullptr) { + return false; + } + ani_ref peerData = nullptr; + if (env->GlobalReference_Create(record, &peerData) != ANI_OK) { + HILOGI("Json stringify failed"); + return false; + } + serializeData->peerData = peerData; + return true; + } + return false; +} + +bool AniSerialize::CrossSerialize(ani_env* env, ani_object argv, std::shared_ptr serializeData) +{ + if (argv == nullptr) { + // emit with no data + return true; + } + ani_ref record = nullptr; + if (GetRefPropertyByName(env, argv, "data", record)) { + if (record == nullptr) { + return false; + } + ani_status status = ANI_OK; + ani_namespace ns {}; + status = env->FindNamespace("L@ohos/util/json/json;", &ns); + if (status != ANI_OK) { + HILOGI("Failed to find namespace"); + return false; + } + ani_function fnStringify {}; + status = env->Namespace_FindFunction(ns, "stringify", nullptr, &fnStringify); + if (status != ANI_OK) { + HILOGI("Failed to find stringify"); + return false; + } + ani_ref ref {}; + ani_value args[] = {{.r = record}, {.r = nullptr}, {.r = nullptr}}; + status = env->Function_Call_Ref_A(fnStringify, &ref, args); + if (status != ANI_OK) { + HILOGI("Failed to call stringify"); + return false; + } + ani_size sz {}; + ani_string str = static_cast(ref); + if (env->String_GetUTF8Size(str, &sz) != ANI_OK) { + HILOGI("Failed to get string size"); + return false; + } + serializeData->crossData.resize(sz + 1); + status = env->String_GetUTF8SubString( + str, 0, sz, serializeData->crossData.data(), serializeData->crossData.size(), &sz); + if (status != ANI_OK) { + HILOGI("Failed to convert ani string to c++ string"); + return false; + } + serializeData->crossData.resize(sz); + return true; + } + return false; +} + +} // namespace AppExecFwk +} // namespace OHOS \ No newline at end of file diff --git a/frameworks/emitter/ani/src/sts_events_json_common.cpp b/frameworks/emitter/ani/src/sts_events_json_common.cpp new file mode 100644 index 0000000..b3d867f --- /dev/null +++ b/frameworks/emitter/ani/src/sts_events_json_common.cpp @@ -0,0 +1,538 @@ +/* + * 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 "sts_events_json_common.h" +#include +#include "event_logger.h" +#include "securec.h" + +namespace OHOS { +namespace AppExecFwk { +namespace { +DEFINE_EH_HILOG_LABEL("EventsEmitter"); +} +constexpr const char* CLASSNAME_DOUBLE = "Lstd/core/Double;"; +constexpr const char* CLASSNAME_BOOLEAN = "Lstd/core/Boolean;"; + +bool GetIntByName(ani_env *env, ani_object param, const char *name, int32_t &value) +{ + ani_int res = 0; + auto status = env->Object_GetFieldByName_Int(param, name, &res); + if (status != ANI_OK) { + HILOGI("status : %{public}d", status); + return false; + } + + value = static_cast(res); + return true; +} + +bool GetDoubleOrUndefined(ani_env *env, ani_object param, const char *name, ani_double &value) +{ + ani_ref obj = nullptr; + ani_boolean isUndefined = true; + ani_status status = ANI_ERROR; + + if ((status = env->Object_GetFieldByName_Ref(param, name, &obj)) != ANI_OK) { + HILOGI("status : %{public}d", status); + return false; + } + if ((status = env->Reference_IsUndefined(obj, &isUndefined)) != ANI_OK) { + HILOGI("status : %{public}d", status); + return false; + } + if (isUndefined) { + HILOGI("%{public}s : undefined", name); + return false; + } + if ((status = env->Object_CallMethodByName_Double( + reinterpret_cast(obj), "unboxed", nullptr, &value)) != ANI_OK) { + HILOGI("status : %{public}d", status); + return false; + } + return true; +} + +bool GetBoolOrUndefined(ani_env *env, ani_object param, const char *name) +{ + ani_ref obj = nullptr; + ani_boolean isUndefined = true; + ani_status status = ANI_ERROR; + ani_boolean res = 0.0; + + if ((status = env->Object_GetFieldByName_Ref(param, name, &obj)) != ANI_OK) { + HILOGI("status : %{public}d", status); + return res; + } + if ((status = env->Reference_IsUndefined(obj, &isUndefined)) != ANI_OK) { + HILOGI("status : %{public}d", status); + return res; + } + if (isUndefined) { + HILOGI("%{public}s : undefined", name); + return res; + } + if ((status = env->Object_CallMethodByName_Boolean( + reinterpret_cast(obj), "booleanValue", nullptr, &res)) != ANI_OK) { + HILOGI("status : %{public}d", status); + return res; + } + return res; +} + +bool GetStringOrUndefined(ani_env *env, ani_object param, const char *name, std::string &res) +{ + ani_ref obj = nullptr; + ani_boolean isUndefined = true; + ani_status status = ANI_ERROR; + + if ((status = env->Object_GetFieldByName_Ref(param, name, &obj)) != ANI_OK) { + HILOGI("status : %{public}d", status); + return false; + } + if ((status = env->Reference_IsUndefined(obj, &isUndefined)) != ANI_OK) { + HILOGI("status : %{public}d", status); + return false; + } + if (isUndefined) { + HILOGI("%{public}s : undefined", name); + return false; + } + if (!GetStdString(env, reinterpret_cast(obj), res)) { + HILOGI("GetStdString failed"); + return false; + } + return true; +} + +bool GetFixedStringArrayOrUndefined(ani_env *env, ani_object param, const char *name, std::vector &res) +{ + ani_ref obj = nullptr; + ani_status status; + + if ((status = env->Object_GetFieldByName_Ref(param, name, &obj)) != ANI_OK) { + HILOGI("status : %{public}d", status); + return false; + } + ani_boolean isUndefined = true; + if ((status = env->Reference_IsUndefined(obj, &isUndefined)) != ANI_OK) { + HILOGI("status : %{public}d", status); + return false; + } + if (isUndefined) { + HILOGI("%{public}s : undefined", name); + return false; + } + + ani_size size = 0; + if ((status = env->Array_GetLength(reinterpret_cast(obj), &size)) != ANI_OK) { + HILOGI("status : %{public}d", status); + return false; + } + + ani_ref ref = nullptr; + for (ani_size index = 0; index < size; index++) { + if ((status = env->Array_Get_Ref(reinterpret_cast(obj), index, &ref)) != ANI_OK) { + HILOGI("status : %{public}d, index: %{public}zu", status, index); + return false; + } + + std::string strItem = ""; + if (!GetStdString(env, reinterpret_cast(ref), strItem)) { + HILOGI("GetStdString failed, index: %{public}zu", index); + return false; + } + + res.push_back(strItem); + } + + return true; +} + +bool SetFieldFixedArrayString(ani_env *env, ani_class cls, ani_object object, const std::string &fieldName, + const std::vector &values) +{ + ani_field field = nullptr; + ani_status status = env->Class_FindField(cls, fieldName.c_str(), &field); + if (status != ANI_OK) { + HILOGI("status : %{public}d", status); + return false; + } + + ani_class stringCls = nullptr; + status = env->FindClass("Lstd/core/String;", &stringCls); + if (status != ANI_OK) { + HILOGI("status : %{public}d", status); + return false; + } + + ani_ref undefinedRef = nullptr; + status = env->GetUndefined(&undefinedRef); + if (status != ANI_OK) { + HILOGI("status : %{public}d", status); + return false; + } + + ani_array_ref array = nullptr; + status = env->Array_New_Ref(stringCls, values.size(), undefinedRef, &array); + if (status != ANI_OK) { + HILOGI("status : %{public}d", status); + return false; + } + + for (size_t i = 0; i < values.size(); ++i) { + ani_string strItem = nullptr; + status = env->String_NewUTF8(values[i].c_str(), values[i].size(), &strItem); + if (status != ANI_OK) { + HILOGI("status : %{public}d", status); + return false; + } + status = env->Array_Set_Ref(array, i, strItem); + if (status != ANI_OK) { + HILOGI("status : %{public}d", status); + return false; + } + } + status = env->Object_SetField_Ref(object, field, array); + if (status != ANI_OK) { + HILOGI("status : %{public}d", status); + return false; + } + return true; +} + +bool GetStringArrayOrUndefined(ani_env *env, ani_object param, const char *name, std::vector &res) +{ + ani_ref arrayObj = nullptr; + ani_boolean isUndefined = true; + ani_status status = ANI_OK; + ani_double length; + + if ((status = env->Object_GetFieldByName_Ref(param, name, &arrayObj)) != ANI_OK) { + HILOGI("status : %{public}d", status); + return false; + } + if ((status = env->Reference_IsUndefined(arrayObj, &isUndefined)) != ANI_OK) { + HILOGI("status : %{public}d", status); + return false; + } + if (isUndefined) { + HILOGI("%{public}s : undefined", name); + return false; + } + + status = env->Object_GetPropertyByName_Double(reinterpret_cast(arrayObj), "length", &length); + if (status != ANI_OK) { + HILOGI("status : %{public}d", status); + return false; + } + + for (int32_t index = 0; index < static_cast(length); index++) { + ani_ref stringEntryRef; + status = env->Object_CallMethodByName_Ref(reinterpret_cast(arrayObj), + "$_get", "I:Lstd/core/Object;", &stringEntryRef, static_cast(index)); + if (status != ANI_OK) { + HILOGI("status : %{public}d, index: %{public}d", status, index); + return false; + } + + std::string str = ""; + if (!GetStdString(env, reinterpret_cast(stringEntryRef), str)) { + HILOGI("GetStdString failed, index: %{public}d", index); + return false; + } + + res.push_back(str); + } + + return true; +} + + +bool SetFieldArrayString(ani_env *env, ani_class cls, ani_object object, const std::string &fieldName, + const std::vector &values) +{ + ani_field field = nullptr; + ani_class arrayCls = nullptr; + ani_method arrayCtor; + ani_object arrayObj; + + ani_status status = env->Class_FindField(cls, fieldName.c_str(), &field); + if (status != ANI_OK) { + HILOGI("status : %{public}d", status); + return false; + } + + status = env->FindClass("Lescompat/Array;", &arrayCls); + if (status != ANI_OK) { + HILOGI("status : %{public}d", status); + return false; + } + + status = env->Class_FindMethod(arrayCls, "", "I:V", &arrayCtor); + if (status != ANI_OK) { + HILOGI("status : %{public}d", status); + return false; + } + + status = env->Object_New(arrayCls, arrayCtor, &arrayObj, values.size()); + if (status != ANI_OK) { + HILOGI("status : %{public}d", status); + return false; + } + + for (size_t i = 0; i < values.size(); i++) { + ani_string strItem = nullptr; + status = env->String_NewUTF8(values[i].c_str(), values[i].size(), &strItem); + if (status != ANI_OK) { + HILOGI("status : %{public}d", status); + return false; + } + + status = env->Object_CallMethodByName_Void(arrayObj, "$_set", "ILstd/core/Object;:V", i, strItem); + if (status != ANI_OK) { + HILOGI("status : %{public}d", status); + return false; + } + } + status = env->Object_SetField_Ref(object, field, arrayObj); + if (status != ANI_OK) { + HILOGI("status : %{public}d", status); + return false; + } + + return true; +} + +bool GetStdString(ani_env *env, ani_string str, std::string &res) +{ + ani_size sz {}; + ani_status status = ANI_ERROR; + if ((status = env->String_GetUTF8Size(str, &sz)) != ANI_OK) { + HILOGW("status : %{public}d", status); + return false; + } + res.resize(sz + 1); + if ((status = env->String_GetUTF8SubString(str, 0, sz, res.data(), res.size(), &sz)) != ANI_OK) { + HILOGI("status : %{public}d", status); + return false; + } + res.resize(sz); + return true; +} + +ani_string GetAniString(ani_env *env, const std::string &str) +{ + ani_string aniStr = nullptr; + ani_status status = env->String_NewUTF8(str.c_str(), str.size(), &aniStr); + if (status != ANI_OK) { + HILOGI("status : %{public}d", status); + return nullptr; + } + return aniStr; +} + +ani_array_ref GetAniArrayString(ani_env *env, const std::vector &values) +{ + ani_array_ref aArrayRef = nullptr; + return aArrayRef; +} + +bool GetRefPropertyByName(ani_env *env, ani_object param, const char *name, ani_ref &ref) +{ + ani_status status = ANI_ERROR; + if ((status = env->Object_GetPropertyByName_Ref(param, name, &ref)) != ANI_OK) { + HILOGI("Object_GetFieldByName_Ref failed, status : %{public}d", status); + return false; + } + + ani_boolean isUndefined = true; + if ((status = env->Reference_IsUndefined(ref, &isUndefined)) != ANI_OK) { + HILOGI("Reference_IsUndefined failed, status : %{public}d", status); + return false; + } + if (isUndefined) { + HILOGI("wantParams is undefined"); + return false; + } + isUndefined = true; + + if ((status = env->Reference_IsNull(ref, &isUndefined)) != ANI_OK) { + HILOGI("Reference_IsNull failed, status : %{public}d", status); + return false; + } + + if (isUndefined) { + HILOGI("wantParams is null"); + return false; + } + isUndefined = true; + + if ((status = env->Reference_IsNullishValue(ref, &isUndefined)) != ANI_OK) { + HILOGI("Reference_IsNullishValue failed, status : %{public}d", status); + return false; + } + + if (isUndefined) { + HILOGI("wantParams is nullish"); + return false; + } + return true; +} + +ani_object createDouble(ani_env *env, ani_double value) +{ + ani_class persion_cls; + ani_status status = ANI_ERROR; + if ((status = env->FindClass(CLASSNAME_DOUBLE, &persion_cls)) != ANI_OK) { + HILOGI("status : %{public}d", status); + return nullptr; + } + ani_method personInfoCtor; + if ((status = env->Class_FindMethod(persion_cls, "", "D:V", &personInfoCtor)) != ANI_OK) { + HILOGI("status : %{public}d", status); + return nullptr; + } + ani_object personInfoObj; + if ((status = env->Object_New(persion_cls, personInfoCtor, &personInfoObj, value)) != ANI_OK) { + HILOGI("status : %{public}d", status); + return nullptr; + } + return personInfoObj; +} + +ani_object createBoolean(ani_env *env, ani_boolean value) +{ + ani_class persion_cls; + ani_status status = ANI_ERROR; + if ((status = env->FindClass(CLASSNAME_BOOLEAN, &persion_cls)) != ANI_OK) { + HILOGI("status : %{public}d", status); + return nullptr; + } + ani_method personInfoCtor; + if ((status = env->Class_FindMethod(persion_cls, "", "Z:V", &personInfoCtor)) != ANI_OK) { + HILOGI("status : %{public}d", status); + return nullptr; + } + ani_object personInfoObj; + if ((status = env->Object_New(persion_cls, personInfoCtor, &personInfoObj, value)) != ANI_OK) { + HILOGI("status : %{public}d", status); + return nullptr; + } + return personInfoObj; +} + +bool SetFieldString(ani_env *env, ani_class cls, ani_object object, + const std::string &fieldName, const std::string &value) +{ + ani_field field = nullptr; + ani_status status = env->Class_FindField(cls, fieldName.c_str(), &field); + if (status != ANI_OK) { + HILOGI("status : %{public}d", status); + return false; + } + + if (value.empty()) { + ani_ref nullRef = nullptr; + if ((status = env->GetNull(&nullRef)) != ANI_OK) { + HILOGI("status : %{public}d", status); + return false; + } + if ((status = env->Object_SetField_Ref(object, field, nullRef)) != ANI_OK) { + HILOGI("status : %{public}d", status); + return false; + } + return true; + } + + ani_string strItem = nullptr; + if ((status = env->String_NewUTF8(value.c_str(), value.size(), &strItem)) != ANI_OK) { + HILOGI("status : %{public}d", status); + return false; + } + + if ((status = env->Object_SetField_Ref(object, field, strItem)) != ANI_OK) { + HILOGI("status : %{public}d", status); + return false; + } + return true; +} + +bool SetFieldDouble(ani_env *env, ani_class cls, ani_object object, const std::string &fieldName, double value) +{ + ani_field field = nullptr; + ani_status status = env->Class_FindField(cls, fieldName.c_str(), &field); + if (status != ANI_OK) { + HILOGI("status : %{public}d", status); + return false; + } + + status = env->Object_SetField_Double(object, field, value); + if (status != ANI_OK) { + HILOGI("status : %{public}d", status); + return false; + } + return true; +} + +bool SetFieldBoolean(ani_env *env, ani_class cls, ani_object object, const std::string &fieldName, bool value) +{ + ani_field field = nullptr; + ani_status status = env->Class_FindField(cls, fieldName.c_str(), &field); + if (status != ANI_OK) { + HILOGI("status : %{public}d", status); + return false; + } + status = env->Object_SetField_Boolean(object, field, value); + if (status != ANI_OK) { + HILOGI("status : %{public}d", status); + return false; + } + return true; +} + +bool SetFieldInt(ani_env *env, ani_class cls, ani_object object, const std::string &fieldName, int32_t value) +{ + ani_field field = nullptr; + ani_status status = env->Class_FindField(cls, fieldName.c_str(), &field); + if (status != ANI_OK) { + HILOGI("status : %{public}d, field name: %{public}s", status, fieldName.c_str()); + return false; + } + status = env->Object_SetField_Int(object, field, value); + if (status != ANI_OK) { + HILOGI("status : %{public}d, field name: %{public}s", status, fieldName.c_str()); + return false; + } + return true; +} + +bool SetFieldRef(ani_env *env, ani_class cls, ani_object object, const std::string &fieldName, ani_ref value) +{ + ani_field field = nullptr; + ani_status status = env->Class_FindField(cls, fieldName.c_str(), &field); + if (status != ANI_OK) { + HILOGI("FindField %{public}s failed, status: %{public}d", fieldName.c_str(), status); + return false; + } + status = env->Object_SetField_Ref(object, field, value); + if (status != ANI_OK) { + HILOGI("SetField_Ref %{public}s failed, status: %{public}d", fieldName.c_str(), status); + return false; + } + return true; +} +} // namespace AppExecFwk +} // namespace OHOS \ No newline at end of file diff --git a/frameworks/emitter/base/include/ani_async_callback_manager.h b/frameworks/emitter/base/include/ani_async_callback_manager.h new file mode 100644 index 0000000..c5680a9 --- /dev/null +++ b/frameworks/emitter/base/include/ani_async_callback_manager.h @@ -0,0 +1,113 @@ +/* + * 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 BASE_EVENTHANDLER_FRAMEWORKS_ANI_ASYNC_CALLBACK_MANAGER_H +#define BASE_EVENTHANDLER_FRAMEWORKS_ANI_ASYNC_CALLBACK_MANAGER_H + +#include +#include +#include +#include + +#include "inner_event.h" +#include "ani.h" +#include "serialize.h" + +namespace OHOS { +namespace AppExecFwk { + +struct AniAsyncCallbackInfo { + ani_vm* vm = nullptr; + std::string dataType; + ani_ref callback = 0; + std::atomic once = false; + std::atomic isDeleted = false; + InnerEvent::EventId eventId; + + ~AniAsyncCallbackInfo(); + void ProcessEvent([[maybe_unused]] const InnerEvent::Pointer& event); + static void ThreadFunction( + ani_vm* vm, ani_ref callback, std::string dataType, std::shared_ptr serializeData); + static ani_status GetCallbackArgs( + ani_env *env, std::string& dataType, std::vector& args, std::shared_ptr serializeData); +}; + +class AniAsyncCallbackManager { +public: + /** + * Delete all callback info of given event id. + * + * @param eventIdValue event id. + */ + void AniDeleteCallbackInfoByEventId(const InnerEvent::EventId &eventIdValue); + + /** + * Get all callback info counts of given event id. + * + * @param eventId event id. + * @return Counts of callback info. + */ + uint32_t AniGetListenerCountByEventId(const InnerEvent::EventId &eventId); + + /** + * Find whether exists valid callback. + * + * @param eventId event id. + * @return Returns true if exists valid callback. + */ + bool AniIsExistValidCallback(const InnerEvent::EventId &eventId); + + /** + * Insert callback. + * + * @param env A pointer to the environment structure. + * @param eventId Event id. + * @param once Whether subscribe once. if true, subscribe once. + * @param callback Event's callback. + * @param dataType Data type of callback's parameter. + */ + void AniInsertCallbackInfo( + ani_env *env, InnerEvent::EventId eventId, bool once, ani_ref callback, ani_string dataType); + + /** + * Delete callback of given event id and callback object. + * + * @param env A pointer to the environment structure. + * @param eventIdValue Event id. + * @param callback Event's callback. + */ + void AniDeleteCallbackInfo(ani_env *env, const InnerEvent::EventId &eventIdValue, ani_ref callback); + + /** + * Execute callback. + * + * @param event Event Emitted by user. + */ + void AniDoCallback(const InnerEvent::Pointer& event); + +private: + std::unordered_set> AniGetAsyncCallbackInfo( + const InnerEvent::EventId &eventId); + static void AniReleaseCallbackInfo(AniAsyncCallbackInfo* callbackInfo); + std::string AniGetStdString(ani_env *env, ani_string str); + +private: + std::mutex aniAsyncCallbackContainerMutex_; + std::map>> + aniAsyncCallbackContainer_; +}; +} // namespace AppExecFwk +} // namespace OHOS +#endif // BASE_EVENTHANDLER_FRAMEWORKS_ANI_ASYNC_CALLBACK_MANAGER_H \ No newline at end of file diff --git a/frameworks/emitter/base/include/ani_deserialize.h b/frameworks/emitter/base/include/ani_deserialize.h new file mode 100644 index 0000000..389892c --- /dev/null +++ b/frameworks/emitter/base/include/ani_deserialize.h @@ -0,0 +1,51 @@ +/* + * 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 BASE_EVENTHANDLER_FRAMEWORKS_ANI_DESERIALIZE_H +#define BASE_EVENTHANDLER_FRAMEWORKS_ANI_DESERIALIZE_H + +#include +#include "serialize.h" + +namespace OHOS { +namespace AppExecFwk { + +class AniDeserialize { +public: + /** + * Deserialize from ani to ani. + * + * @param env A pointer to the environment structure. + * @param peerData Object to store deserialized data. + * @param serializeData Object to store serialized data. + * @return Returns true if deserialize successfully. + */ + static bool PeerDeserialize(ani_env* env, ani_ref* peerData, std::shared_ptr serializeData); + + /** + * Deserialize from napi to ani. + * + * @param env A pointer to the environment structure. + * @param crossData Object to store deserialized data. + * @param serializeData Object to store serialized data. + * @return Returns true if deserialize successfully. + */ + static bool CrossDeserialize(ani_env* env, ani_ref* crossData, std::shared_ptr serializeData); +}; + +} // namespace AppExecFwk +} // namespace OHOS + +#endif // BASE_EVENTHANDLER_FRAMEWORKS_ANI_DESERIALIZE_H \ No newline at end of file diff --git a/frameworks/emitter/base/include/aync_callback_manager.h b/frameworks/emitter/base/include/aync_callback_manager.h new file mode 100644 index 0000000..b638bc3 --- /dev/null +++ b/frameworks/emitter/base/include/aync_callback_manager.h @@ -0,0 +1,108 @@ +/* + * 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 BASE_EVENTHANDLER_FRAMEWORKS_ASYNC_CALLBACK_MANAGER_H +#define BASE_EVENTHANDLER_FRAMEWORKS_ASYNC_CALLBACK_MANAGER_H + +#include "napi_async_callback_manager.h" +#include "ani_async_callback_manager.h" + +namespace OHOS { +namespace AppExecFwk { + +class AsyncCallbackManager { +public: + DISALLOW_COPY_AND_MOVE(AsyncCallbackManager); + static AsyncCallbackManager& GetInstance(); + + /** + * Delete all callback info of given event id. + * + * @param eventIdValue event id. + */ + void DeleteCallbackInfoByEventId(const InnerEvent::EventId &eventIdValue); + + /** + * Get all callback info counts of given event id. + * + * @param eventId event id. + * @return Counts of callback info. + */ + uint32_t GetListenerCountByEventId(const InnerEvent::EventId &eventId); + + /** + * Find whether exists valid callback. + * + * @param eventId event id. + * @return Returns true if exists valid callback. + */ + bool IsExistValidCallback(const InnerEvent::EventId &eventId); + + /** + * Insert callback. + * + * @param env A pointer to the environment structure. + * @param eventId Event id. + * @param once Whether subscribe once. if true, subscribe once. + * @param callback Event's callback. + * @param dataType Data type of callback's parameter. + */ + void InsertCallbackInfo( + ani_env *env, InnerEvent::EventId eventId, bool once, ani_ref callback, ani_string dataType); + + /** + * Delete callback of given event id and callback object. + * + * @param env A pointer to the environment structure. + * @param eventIdValue Event id. + * @param argv Event's callback. + */ + void DeleteCallbackInfo(napi_env env, const InnerEvent::EventId &eventIdValue, napi_value argv); + + /** + * Delete callback of given event id and callback object. + * + * @param env A pointer to the environment structure. + * @param eventIdValue Event id. + * @param callback Event's callback. + */ + void DeleteCallbackInfo(ani_env *env, const InnerEvent::EventId &eventIdValue, ani_ref callback); + + /** + * Execute callback. + * + * @param event Event Emitted by user. + */ + void DoCallback(const InnerEvent::Pointer& event); + + /** + * Whether needs to cross runtime. + * + * @param eventId event id. + * @param envType The type of runtime environment. + * @return Returns true if needs to cross runtime. + */ + bool IsCrossRuntime(const InnerEvent::EventId &eventId, EnvType envType); +private: + AsyncCallbackManager() = default; + +private: + AniAsyncCallbackManager aniAsyncCallbackManager_; + NapiAsyncCallbackManager napiAsyncCallbackManager_; +}; + +} // namespace AppExecFwk +} // namespace OHOS + +#endif // BASE_EVENTHANDLER_FRAMEWORKS_ASYNC_CALLBACK_MANAGER_H \ No newline at end of file diff --git a/frameworks/emitter/base/include/napi_async_callback_manager.h b/frameworks/emitter/base/include/napi_async_callback_manager.h new file mode 100644 index 0000000..9eea082 --- /dev/null +++ b/frameworks/emitter/base/include/napi_async_callback_manager.h @@ -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. + */ +#ifndef BASE_EVENTHANDLER_FRAMEWORKS_NAPI_ASYNC_CALLBACK_MANAGER_H +#define BASE_EVENTHANDLER_FRAMEWORKS_NAPI_ASYNC_CALLBACK_MANAGER_H + +#include +#include +#include +#include + +#include "nocopyable.h" +#include "inner_event.h" +#include "napi/native_api.h" +#include "js_native_api_types.h" +#include "napi/native_node_api.h" +#include "serialize.h" +#include "interops.h" + +namespace OHOS { +namespace AppExecFwk { + +struct NapiEventDataWorker { + std::shared_ptr serializeData; + std::shared_ptr callbackInfo; + int type; +}; + +class NapiAsyncCallbackManager { +using AsyncCallbackInfoContainer = + std::map>>; +public: + NapiAsyncCallbackManager( + std::mutex& containerMutex = GetAsyncCallbackInfoContainerMutex(), + AsyncCallbackInfoContainer& callbackInfoContainer = GetAsyncCallbackInfoContainer() + ) : napiAsyncCallbackContainerMutex_(containerMutex), napiAsyncCallbackContainer_(callbackInfoContainer) {} + + /** + * Delete all callback info of given event id. + * + * @param eventIdValue event id. + */ + void NapiDeleteCallbackInfoByEventId(const InnerEvent::EventId &eventIdValue); + + /** + * Get all callback info counts of given event id. + * + * @param eventId event id. + * @return Counts of callback info. + */ + uint32_t NapiGetListenerCountByEventId(const InnerEvent::EventId &eventId); + + /** + * Find whether exists valid callback. + * + * @param eventId event id. + * @return Returns true if exists valid callback. + */ + bool NapiIsExistValidCallback(const InnerEvent::EventId &eventId); + + /** + * Delete callback of given event id and callback object. + * + * @param env A pointer to the environment structure. + * @param eventIdValue Event id. + * @param argv Event's callback. + */ + void NapiDeleteCallbackInfo(napi_env env, const InnerEvent::EventId &eventIdValue, napi_value argv); + + /** + * Execute callback. + * + * @param event Event Emitted by user. + */ + void NapiDoCallback(const InnerEvent::Pointer& event); + +private: + std::unordered_set> NapiGetAsyncCallbackInfo( + const InnerEvent::EventId &eventId); +private: + std::mutex& napiAsyncCallbackContainerMutex_; + AsyncCallbackInfoContainer& napiAsyncCallbackContainer_; +}; + +} // namespace AppExecFwk +} // namespace OHOS + +#endif // BASE_EVENTHANDLER_FRAMEWORKS_NAPI_ASYNC_CALLBACK_MANAGER_H \ No newline at end of file diff --git a/frameworks/emitter/base/include/serialize.h b/frameworks/emitter/base/include/serialize.h new file mode 100644 index 0000000..f9b0dff --- /dev/null +++ b/frameworks/emitter/base/include/serialize.h @@ -0,0 +1,43 @@ +/* + * 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 BASE_EVENTHANDLER_FRAMEWORKS_SERIALIZE_H +#define BASE_EVENTHANDLER_FRAMEWORKS_SERIALIZE_H + +#include + +#include "ani.h" +#include "napi/native_api.h" +#include "js_native_api_types.h" +#include "napi/native_node_api.h" + +namespace OHOS { +namespace AppExecFwk { + +enum EnvType { + NAPI, + ANI +}; + +struct SerializeData { + std::variant peerData {}; + std::string crossData {}; + EnvType envType {EnvType::NAPI}; + bool isCrossRuntime {false}; +}; + +} // namespace AppExecFwk +} // namespace OHOS +#endif // BASE_EVENTHANDLER_FRAMEWORKS_SERIALIZE_H \ No newline at end of file diff --git a/frameworks/emitter/base/src/ani_async_callback_manager.cpp b/frameworks/emitter/base/src/ani_async_callback_manager.cpp new file mode 100644 index 0000000..db46110 --- /dev/null +++ b/frameworks/emitter/base/src/ani_async_callback_manager.cpp @@ -0,0 +1,302 @@ +/* + * 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_async_callback_manager.h" +#include "event_logger.h" +#include "ani_deserialize.h" + +namespace OHOS { +namespace AppExecFwk { +namespace { +DEFINE_EH_HILOG_LABEL("EventsEmitter"); +constexpr const char* EVENT_DATA = "eventData"; +constexpr const char* GENERIC_EVENT_DATA = "genericEventData"; +} + +AniAsyncCallbackInfo::~AniAsyncCallbackInfo() +{ + vm = nullptr; +} + +void AniAsyncCallbackInfo::ProcessEvent([[maybe_unused]] const InnerEvent::Pointer& event) +{ + if (vm == nullptr) { + return; + } + auto serializeData = event->GetSharedObject(); + auto t = std::thread(ThreadFunction, vm, callback, dataType, serializeData); + t.join(); + if (once) { + isDeleted = true; + } +} + +ani_status AniAsyncCallbackInfo::GetCallbackArgs( + ani_env *env, std::string& dataType, std::vector& args, std::shared_ptr serializeData) +{ + ani_ref eventData; + bool isDeserializeSuccess = false; + if (serializeData->envType == EnvType::ANI) { + isDeserializeSuccess = AniDeserialize::PeerDeserialize(env, &eventData, serializeData); + } else { + if (serializeData->isCrossRuntime) { + isDeserializeSuccess = AniDeserialize::CrossDeserialize(env, &eventData, serializeData); + } + } + if (!isDeserializeSuccess) { + return ANI_INVALID_ARGS; + } + + ani_status status = ANI_OK; + ani_class cls; + if (dataType == EVENT_DATA) { + status = env->FindClass("L@ohos/events/emitter/emitter/EventDataInner;", &cls); + } else if (dataType == GENERIC_EVENT_DATA) { + status = env->FindClass("L@ohos/events/emitter/emitter/GenericEventDataInner;", &cls); + } else { + return status; + } + if (status != ANI_OK) { + HILOGE("threadFunciton FindClass error%{public}d", status); + return status; + } + ani_method ctor; + status = env->Class_FindMethod(cls, "", ":V", &ctor); + if (status != ANI_OK) { + HILOGE("threadFunciton Class_FindMethod error%{public}d", status); + return status; + } + ani_object obj; + status = env->Object_New(cls, ctor, &obj); + if (status != ANI_OK) { + HILOGE("threadFunciton Object_New error%{public}d", status); + return status; + } + + env->Object_SetPropertyByName_Ref(obj, "data", eventData); + args.push_back(reinterpret_cast(obj)); + return status; +} + +void AniAsyncCallbackInfo::ThreadFunction( + ani_vm* vm, ani_ref callback, std::string dataType, std::shared_ptr serializeData) +{ + ani_env *env; + ani_status status = ANI_OK; + ani_option interopEnabled {"--interop=disable", nullptr}; + ani_options aniArgs {1, &interopEnabled}; + status = vm->AttachCurrentThread(&aniArgs, ANI_VERSION_1, &env); + if (ANI_OK != status) { + HILOGE("vm GetEnv error %{public}d", status); + return; + } + + auto fnObj = reinterpret_cast(callback); + if (fnObj == nullptr) { + HILOGE("threadFunciton fnObj is nullptr"); + vm->DetachCurrentThread(); + return; + } + std::vector args; + ani_ref result; + status = AniAsyncCallbackInfo::GetCallbackArgs(env, dataType, args, serializeData); + if (status != ANI_OK) { + HILOGI("Get callback args failed. error %{public}d", status); + vm->DetachCurrentThread(); + return; + } + status = env->FunctionalObject_Call(fnObj, args.size(), args.data(), &result); + if (ANI_OK != status) { + HILOGI("ANI call function failed. error %{public}d", status); + } + + vm->DetachCurrentThread(); +} + +void AniAsyncCallbackManager::AniDeleteCallbackInfoByEventId(const InnerEvent::EventId &eventIdValue) +{ + std::lock_guard lock(aniAsyncCallbackContainerMutex_); + auto iter = aniAsyncCallbackContainer_.find(eventIdValue); + if (iter != aniAsyncCallbackContainer_.end()) { + for (auto callbackInfo : iter->second) { + callbackInfo->isDeleted = true; + } + } + aniAsyncCallbackContainer_.erase(eventIdValue); +} + +uint32_t AniAsyncCallbackManager::AniGetListenerCountByEventId(const InnerEvent::EventId &eventId) +{ + uint32_t cnt = 0u; + std::lock_guard lock(aniAsyncCallbackContainerMutex_); + auto subscribe = aniAsyncCallbackContainer_.find(eventId); + if (subscribe != aniAsyncCallbackContainer_.end()) { + for (auto it = subscribe->second.begin(); it != subscribe->second.end();) { + if ((*it)->isDeleted == true || (*it)->vm == nullptr) { + it = subscribe->second.erase(it); + continue; + } + ++it; + ++cnt; + } + } + return cnt; +} + +bool AniAsyncCallbackManager::AniIsExistValidCallback(const InnerEvent::EventId &eventId) +{ + std::lock_guard lock(aniAsyncCallbackContainerMutex_); + auto subscribe = aniAsyncCallbackContainer_.find(eventId); + if (subscribe == aniAsyncCallbackContainer_.end()) { + return false; + } + if (subscribe->second.size() != 0) { + return true; + } + return false; +} + +void AniAsyncCallbackManager::AniInsertCallbackInfo( + ani_env *env, InnerEvent::EventId eventId, bool once, ani_ref callback, ani_string dataType) +{ + std::lock_guard lock(aniAsyncCallbackContainerMutex_); + ani_ref globalRefCallback; + env->GlobalReference_Create(callback, &globalRefCallback); + auto subscriber = aniAsyncCallbackContainer_.find(eventId); + if (subscriber != aniAsyncCallbackContainer_.end()) { + for (auto callbackInfo : subscriber->second) { + if (callbackInfo->isDeleted) { + continue; + } + ani_boolean isEq = false; + env->Reference_StrictEquals(globalRefCallback, callbackInfo->callback, &isEq); + if (!isEq) { + continue; + } + callbackInfo->once = once; + return; + } + } + auto callbackInfoPtr = new (std::nothrow) AniAsyncCallbackInfo(); + if (!callbackInfoPtr) { + HILOGE("new object failed"); + return; + } + std::shared_ptr callbackInfo(callbackInfoPtr, [](AniAsyncCallbackInfo* callbackInfo) { + AniReleaseCallbackInfo(callbackInfo); + }); + auto status = env->GetVM(&callbackInfo->vm); + if (callbackInfo->vm == nullptr) { + HILOGE("Get vm failed. status: %{public}d", status); + return; + } + callbackInfo->once = once; + callbackInfo->eventId = eventId; + callbackInfo->callback = globalRefCallback; + callbackInfo->dataType = AniGetStdString(env, dataType); + aniAsyncCallbackContainer_[eventId].insert(callbackInfo); +} + +void AniAsyncCallbackManager::AniDeleteCallbackInfo( + ani_env *env, const InnerEvent::EventId &eventIdValue, ani_ref callback) +{ + std::lock_guard lock(aniAsyncCallbackContainerMutex_); + auto iter = aniAsyncCallbackContainer_.find(eventIdValue); + if (iter == aniAsyncCallbackContainer_.end()) { + return; + } + for (auto callbackInfo = iter->second.begin(); callbackInfo != iter->second.end();) { + ani_boolean isEq = false; + env->Reference_StrictEquals(callback, (*callbackInfo)->callback, &isEq); + if (!isEq) { + ++callbackInfo; + continue; + } + (*callbackInfo)->isDeleted = true; + callbackInfo = iter->second.erase(callbackInfo); + return; + } +} + +std::unordered_set> AniAsyncCallbackManager::AniGetAsyncCallbackInfo( + const InnerEvent::EventId &eventId) +{ + std::lock_guard lock(aniAsyncCallbackContainerMutex_); + auto iter = aniAsyncCallbackContainer_.find(eventId); + if (iter == aniAsyncCallbackContainer_.end()) { + std::unordered_set> result; + return result; + } + for (auto it = iter->second.begin(); it != iter->second.end();) { + if (*it == nullptr || (*it)->isDeleted == true || (*it)->vm == nullptr) { + it = iter->second.erase(it); + continue; + } + ++it; + } + return iter->second; +} + +void AniAsyncCallbackManager::AniDoCallback(const InnerEvent::Pointer& event) +{ + auto aniCallbackInfos = AniGetAsyncCallbackInfo(event->GetInnerEventIdEx()); + for (auto it = aniCallbackInfos.begin(); it != aniCallbackInfos.end(); ++it) { + (*it)->ProcessEvent(event); + } +} + +void AniAsyncCallbackManager::AniReleaseCallbackInfo(AniAsyncCallbackInfo* callbackInfo) +{ + if (callbackInfo != nullptr) { + ani_env *MyEnv; + if (ANI_OK != callbackInfo->vm->GetEnv(ANI_VERSION_1, &MyEnv)) { + ani_status status = ANI_OK; + ani_option interopEnabled {"--interop=disable", nullptr}; + ani_options aniArgs {1, &interopEnabled}; + status = callbackInfo->vm->AttachCurrentThread(&aniArgs, ANI_VERSION_1, &MyEnv); + if (ANI_OK != status) { + HILOGE("attach thread failed"); + delete callbackInfo; + callbackInfo = nullptr; + return; + } + status = MyEnv->GlobalReference_Delete(callbackInfo->callback); + if (status != ANI_OK) { + HILOGE("delete reference failed"); + } + callbackInfo->vm->DetachCurrentThread(); + delete callbackInfo; + callbackInfo = nullptr; + return; + } + MyEnv->GlobalReference_Delete(callbackInfo->callback); + delete callbackInfo; + callbackInfo = nullptr; + } +} + +std::string AniAsyncCallbackManager::AniGetStdString(ani_env *env, ani_string str) +{ + std::string result; + ani_size sz {}; + env->String_GetUTF8Size(str, &sz); + result.resize(sz + 1); + env->String_GetUTF8SubString(str, 0, sz, result.data(), result.size(), &sz); + result.resize(sz); + return result; +} + +} // namespace AppExecFwk +} // namespace OHOS \ No newline at end of file diff --git a/frameworks/emitter/base/src/ani_deserialize.cpp b/frameworks/emitter/base/src/ani_deserialize.cpp new file mode 100644 index 0000000..8e07b53 --- /dev/null +++ b/frameworks/emitter/base/src/ani_deserialize.cpp @@ -0,0 +1,81 @@ +/* + * 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_deserialize.h" +#include "event_logger.h" + +namespace OHOS { +namespace AppExecFwk { +namespace { + DEFINE_EH_HILOG_LABEL("EventsEmitter"); +} +static ani_ref JsonParse(ani_env *env, std::string jsonStr) +{ + ani_status status = ANI_ERROR; + ani_class cls = nullptr; + if ((status = env->FindClass("L@ohos/events/json/RecordSerializeTool;", &cls)) != ANI_OK) { + HILOGI("FindClass RecordSerializeTool failed, status : %{public}d", status); + return nullptr; + } + if (cls == nullptr) { + HILOGI("RecordSerializeTool class null"); + return nullptr; + } + ani_static_method parseNoThrowMethod = nullptr; + status = env->Class_FindStaticMethod(cls, "parseNoThrow", nullptr, &parseNoThrowMethod); + if (status != ANI_OK) { + HILOGI("failed to get parseNoThrow method, status : %{public}d", status); + return nullptr; + } + + ani_string aniString; + status = env->String_NewUTF8(jsonStr.c_str(), jsonStr.length(), &aniString); + if (status != ANI_OK) { + HILOGI("String_NewUTF8 wantParamsString failed, status : %{public}d", status); + return nullptr; + } + + ani_ref aniResult = nullptr; + status = env->Class_CallStaticMethod_Ref(cls, parseNoThrowMethod, &aniResult, aniString); + if (status != ANI_OK) { + HILOGI("failed to call parseNoThrow method, status : %{public}d", status); + return nullptr; + } + return aniResult; +} + +bool AniDeserialize::PeerDeserialize(ani_env* env, ani_ref* peerData, std::shared_ptr serializeData) +{ + if (std::holds_alternative(serializeData->peerData)) { + *peerData = std::get(serializeData->peerData); + } + return true; +} + +bool AniDeserialize::CrossDeserialize(ani_env* env, ani_ref* crossData, std::shared_ptr serializeData) +{ + if (serializeData->crossData.empty()) { + return true; + } + *crossData = JsonParse(env, serializeData->crossData); + if (*crossData == nullptr) { + HILOGI("json parse failed"); + return false; + } + return true; +} + +} // namespace AppExecFwk +} // namespace OHOS \ No newline at end of file diff --git a/frameworks/emitter/base/src/async_callback_manager.cpp b/frameworks/emitter/base/src/async_callback_manager.cpp new file mode 100644 index 0000000..47eb00b --- /dev/null +++ b/frameworks/emitter/base/src/async_callback_manager.cpp @@ -0,0 +1,94 @@ +/* + * 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 "aync_callback_manager.h" +#include "event_logger.h" + +namespace OHOS { +namespace AppExecFwk { +namespace { +DEFINE_EH_HILOG_LABEL("EventsEmitter"); +} +AsyncCallbackManager& AsyncCallbackManager::GetInstance() +{ + static AsyncCallbackManager instance; + return instance; +} + +void AsyncCallbackManager::DeleteCallbackInfoByEventId(const InnerEvent::EventId &eventIdValue) +{ + aniAsyncCallbackManager_.AniDeleteCallbackInfoByEventId(eventIdValue); + napiAsyncCallbackManager_.NapiDeleteCallbackInfoByEventId(eventIdValue); +} + +uint32_t AsyncCallbackManager::GetListenerCountByEventId(const InnerEvent::EventId &eventId) +{ + uint32_t cnt = 0u; + cnt += aniAsyncCallbackManager_.AniGetListenerCountByEventId(eventId); + cnt += napiAsyncCallbackManager_.NapiGetListenerCountByEventId(eventId); + return cnt; +} + +bool AsyncCallbackManager::IsExistValidCallback(const InnerEvent::EventId &eventId) +{ + auto ret = napiAsyncCallbackManager_.NapiIsExistValidCallback(eventId) || + aniAsyncCallbackManager_.AniIsExistValidCallback(eventId); + if (!ret) { + if (eventId.index() == OHOS::AppExecFwk::TYPE_U32_INDEX) { + HILOGE("Event id: %{public}u has no callback", std::get(eventId)); + } else { + HILOGE("Event id: %{public}s has no callback", std::get(eventId).c_str()); + } + } + return ret; +} + +void AsyncCallbackManager::InsertCallbackInfo( + ani_env *env, InnerEvent::EventId eventId, bool once, ani_ref callback, ani_string dataType) +{ + aniAsyncCallbackManager_.AniInsertCallbackInfo(env, eventId, once, callback, dataType); +} + +void AsyncCallbackManager::DeleteCallbackInfo( + napi_env env, const InnerEvent::EventId &eventIdValue, napi_value argv) +{ + napiAsyncCallbackManager_.NapiDeleteCallbackInfo(env, eventIdValue, argv); +} + +void AsyncCallbackManager::DeleteCallbackInfo( + ani_env *env, const InnerEvent::EventId &eventIdValue, ani_ref callback) +{ + aniAsyncCallbackManager_.AniDeleteCallbackInfo(env, eventIdValue, callback); +} + +void AsyncCallbackManager::DoCallback(const InnerEvent::Pointer& event) +{ + napiAsyncCallbackManager_.NapiDoCallback(event); + aniAsyncCallbackManager_.AniDoCallback(event); +} + +bool AsyncCallbackManager::IsCrossRuntime(const InnerEvent::EventId &eventId, EnvType envType) +{ + if (envType == EnvType::NAPI) { + return aniAsyncCallbackManager_.AniIsExistValidCallback(eventId); + } + + if (envType == EnvType::ANI) { + return napiAsyncCallbackManager_.NapiIsExistValidCallback(eventId); + } + return false; +} +} +} \ No newline at end of file diff --git a/frameworks/emitter/base/src/napi_async_callback_manager.cpp b/frameworks/emitter/base/src/napi_async_callback_manager.cpp new file mode 100644 index 0000000..d060620 --- /dev/null +++ b/frameworks/emitter/base/src/napi_async_callback_manager.cpp @@ -0,0 +1,154 @@ +/* + * 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 "napi_async_callback_manager.h" +#include +#include "event_logger.h" +#include "serialize.h" +namespace OHOS { +namespace AppExecFwk { +namespace { +DEFINE_EH_HILOG_LABEL("EventsEmitter"); +} + +void NapiAsyncCallbackManager::NapiDeleteCallbackInfoByEventId(const InnerEvent::EventId &eventIdValue) +{ + std::lock_guard lock(napiAsyncCallbackContainerMutex_); + auto iter = napiAsyncCallbackContainer_.find(eventIdValue); + if (iter != napiAsyncCallbackContainer_.end()) { + for (auto callbackInfo : iter->second) { + callbackInfo->isDeleted = true; + } + } + napiAsyncCallbackContainer_.erase(eventIdValue); +} + +uint32_t NapiAsyncCallbackManager::NapiGetListenerCountByEventId(const InnerEvent::EventId &eventId) +{ + uint32_t cnt = 0u; + std::lock_guard lock(napiAsyncCallbackContainerMutex_); + auto subscribe = napiAsyncCallbackContainer_.find(eventId); + if (subscribe != napiAsyncCallbackContainer_.end()) { + for (auto it = subscribe->second.begin(); it != subscribe->second.end();) { + if ((*it)->isDeleted == true || (*it)->env == nullptr) { + it = subscribe->second.erase(it); + continue; + } + ++it; + ++cnt; + } + } + return cnt; +} + +bool NapiAsyncCallbackManager::NapiIsExistValidCallback(const InnerEvent::EventId &eventId) +{ + std::lock_guard lock(napiAsyncCallbackContainerMutex_); + auto subscribe = napiAsyncCallbackContainer_.find(eventId); + if (subscribe == napiAsyncCallbackContainer_.end()) { + return false; + } + if (subscribe->second.size() != 0) { + return true; + } + return false; +} + +void NapiAsyncCallbackManager::NapiDeleteCallbackInfo( + napi_env env, const InnerEvent::EventId &eventIdValue, napi_value argv) +{ + std::lock_guard lock(napiAsyncCallbackContainerMutex_); + auto iter = napiAsyncCallbackContainer_.find(eventIdValue); + if (iter == napiAsyncCallbackContainer_.end()) { + return; + } + for (auto callbackInfo = iter->second.begin(); callbackInfo != iter->second.end();) { + napi_value callback = nullptr; + if ((*callbackInfo)->env != env) { + ++callbackInfo; + continue; + } + napi_get_reference_value((*callbackInfo)->env, (*callbackInfo)->callback, &callback); + bool isEq = false; + napi_strict_equals(env, argv, callback, &isEq); + if (!isEq) { + ++callbackInfo; + continue; + } + (*callbackInfo)->isDeleted = true; + callbackInfo = iter->second.erase(callbackInfo); + return; + } + return; +} + +std::unordered_set> NapiAsyncCallbackManager::NapiGetAsyncCallbackInfo( + const InnerEvent::EventId &eventId) +{ + std::lock_guard lock(napiAsyncCallbackContainerMutex_); + auto iter = napiAsyncCallbackContainer_.find(eventId); + if (iter == napiAsyncCallbackContainer_.end()) { + std::unordered_set> result; + return result; + } + for (auto it = iter->second.begin(); it != iter->second.end();) { + if ((*it)->isDeleted == true || (*it)->env == nullptr) { + it = iter->second.erase(it); + continue; + } + ++it; + } + return iter->second; +} + +void NapiAsyncCallbackManager::NapiDoCallback(const InnerEvent::Pointer& event) +{ + auto napiCallbackInfos = NapiGetAsyncCallbackInfo(event->GetInnerEventIdEx()); + auto serializeData = event->GetSharedObject(); + auto deleter = [](napi_value* data) { + if (data != nullptr) { + delete data; + } + }; + for (auto it = napiCallbackInfos.begin(); it != napiCallbackInfos.end(); ++it) { + if (*it == nullptr || (*it)->env == nullptr || (*it)->isDeleted) { + HILOGE("napiCallbackInfo is unavailable"); + continue; + } + EventDataWorker* eventDataWorker = new (std::nothrow) EventDataWorker(); + if (!eventDataWorker) { + HILOGE("new object failed"); + return; + } + if (serializeData->envType == EnvType::NAPI) { + auto napiValue = std::get(serializeData->peerData); + + auto* heapValue = new napi_value(napiValue); + eventDataWorker->data = std::shared_ptr(heapValue, deleter); + + eventDataWorker->isCrossRuntime = false; + eventDataWorker->callbackInfo = *it; + } else { + eventDataWorker->crossRuntimeData = serializeData->crossData; + eventDataWorker->isCrossRuntime = true; + eventDataWorker->callbackInfo = *it; + } + napi_acquire_threadsafe_function((*it)->tsfn); + napi_call_threadsafe_function((*it)->tsfn, eventDataWorker, napi_tsfn_nonblocking); + napi_release_threadsafe_function((*it)->tsfn, napi_tsfn_release); + } +} +} // namespace AppExecFwk +} // namespace OHOS \ No newline at end of file diff --git a/frameworks/emitter/napi/include/napi_agent.h b/frameworks/emitter/napi/include/napi_agent.h new file mode 100644 index 0000000..ba7dd4d --- /dev/null +++ b/frameworks/emitter/napi/include/napi_agent.h @@ -0,0 +1,25 @@ +/* + * 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 BASE_EVENTHANDLER_FRAMEWORKS_NAPI_AGENT_H +#define BASE_EVENTHANDLER_FRAMEWORKS_NAPI_AGENT_H + +namespace OHOS { +namespace AppExecFwk { +void AgentInit(); +} // namespace AppExecFwk +} // namespace OHOS + +#endif // BASE_EVENTHANDLER_FRAMEWORKS_NAPI_AGENT_H \ No newline at end of file diff --git a/frameworks/emitter/napi/include/napi_emitter.h b/frameworks/emitter/napi/include/napi_emitter.h new file mode 100644 index 0000000..33048f7 --- /dev/null +++ b/frameworks/emitter/napi/include/napi_emitter.h @@ -0,0 +1,40 @@ +/* + * 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 BASE_EVENTHANDLER_FRAMEWORKS_NAPI_EMITTER_H +#define BASE_EVENTHANDLER_FRAMEWORKS_NAPI_EMITTER_H + +#include "event_queue.h" +#include "napi/native_api.h" +#include "napi/native_node_api.h" + +namespace OHOS { +namespace AppExecFwk { +using Priority = EventQueue::Priority; + +napi_value JS_Off(napi_env env, napi_callback_info cbinfo); +napi_value JS_Emit(napi_env env, napi_callback_info cbinfo); +void ProcessEvent(const InnerEvent::Pointer& event); + +static inline napi_valuetype GetNapiType(napi_env env, napi_value param) +{ + napi_valuetype type; + napi_typeof(env, param, &type); + return type; +} +} // namespace AppExecFwk +} // namespace OHOS + +#endif // BASE_EVENTHANDLER_FRAMEWORKS_NAPI_EMITTER_H \ No newline at end of file diff --git a/frameworks/emitter/napi/include/napi_serialize.h b/frameworks/emitter/napi/include/napi_serialize.h new file mode 100644 index 0000000..2c9296d --- /dev/null +++ b/frameworks/emitter/napi/include/napi_serialize.h @@ -0,0 +1,52 @@ +/* + * 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 BASE_EVENTHANDLER_FRAMEWORKS_NAPI_SERIALIZE_H +#define BASE_EVENTHANDLER_FRAMEWORKS_NAPI_SERIALIZE_H + +#include "napi/native_api.h" +#include "napi/native_node_api.h" +#include "serialize.h" + +namespace OHOS { +namespace AppExecFwk { + +class NapiSerialize { +public: + /** + * Serialize from napi to napi. + * + * @param env A pointer to the environment structure. + * @param argv Object to be serialized. + * @param serializeData Object to store serialized data. + * @return Returns true if serialize successfully. + */ + static bool PeerSerialize(napi_env env, napi_value argv, std::shared_ptr serializeData); + + /** + * Serialize from napi to ani. + * + * @param env A pointer to the environment structure. + * @param argv Object to be serialized. + * @param serializeData Object to store serialized data. + * @return Returns true if serialize successfully. + */ + static bool CrossSerialize(napi_env env, napi_value argv, std::shared_ptr serializeData); +}; + +} // namespace AppExecFwk +} // namespace OHOS + +#endif // BASE_EVENTHANDLER_FRAMEWORKS_NAPI_SERIALIZE_H \ No newline at end of file diff --git a/frameworks/emitter/napi/src/napi_emitter.cpp b/frameworks/emitter/napi/src/napi_emitter.cpp new file mode 100644 index 0000000..c7b5447 --- /dev/null +++ b/frameworks/emitter/napi/src/napi_emitter.cpp @@ -0,0 +1,358 @@ +/* + * 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 "napi_emitter.h" + +#include +#include +#include "event_logger.h" +#include "js_native_api_types.h" +#include "aync_callback_manager.h" +#include "napi_serialize.h" +#include "interops.h" +#include "napi_agent.h" + +using namespace std; +namespace OHOS { +namespace AppExecFwk { +namespace { +DEFINE_EH_HILOG_LABEL("EventsEmitter"); +constexpr static uint32_t ARGC_ONE = 1u; +static const int32_t ARGC_NUM = 2; +static const int32_t NAPI_VALUE_STRING_LEN = 10240; +} + +bool GetEventIdWithNumberOrString( + napi_env env, napi_value argv, napi_valuetype eventValueType, InnerEvent::EventId &eventId) +{ + if (eventValueType == napi_string) { + auto valueCStr = std::make_unique(NAPI_VALUE_STRING_LEN + 1); + size_t valueStrLength = 0; + napi_get_value_string_utf8(env, argv, valueCStr.get(), NAPI_VALUE_STRING_LEN, &valueStrLength); + std::string id(valueCStr.get(), valueStrLength); + if (id.empty()) { + return false; + } + eventId = id; + HILOGD("Event id value:%{public}s", id.c_str()); + } else { + uint32_t id = 0u; + napi_get_value_uint32(env, argv, &id); + eventId = id; + HILOGD("Event id value:%{public}u", id); + } + return true; +} + +napi_value JS_Off(napi_env env, napi_callback_info cbinfo) +{ + HILOGD("JS_Off enter"); + size_t argc = ARGC_NUM; + napi_value argv[ARGC_NUM] = {0}; + NAPI_CALL(env, napi_get_cb_info(env, cbinfo, &argc, argv, NULL, NULL)); + if (argc < 1) { + HILOGE("requires at least 1 parameter"); + return nullptr; + } + + napi_valuetype eventValueType; + napi_typeof(env, argv[0], &eventValueType); + if (eventValueType != napi_number && eventValueType != napi_string) { + HILOGE("type mismatch for parameter 1"); + return nullptr; + } + + InnerEvent::EventId eventId = 0u; + bool ret = GetEventIdWithNumberOrString(env, argv[0], eventValueType, eventId); + if (!ret) { + HILOGE("Event id is empty for parameter 1."); + return nullptr; + } + + if (argc == ARGC_NUM) { + napi_valuetype eventHandleType; + napi_typeof(env, argv[1], &eventHandleType); + if (eventHandleType != napi_function) { + HILOGE("type mismatch for parameter 2"); + return nullptr; + } + AsyncCallbackManager::GetInstance().DeleteCallbackInfo(env, eventId, argv[1]); + return nullptr; + } + AsyncCallbackManager::GetInstance().DeleteCallbackInfoByEventId(eventId); + return nullptr; +} + +bool EmitWithEventData(napi_env env, napi_value argv, const InnerEvent::EventId &eventId, Priority priority) +{ + HILOGD("EmitWithEventData enter"); + napi_valuetype dataType; + napi_typeof(env, argv, &dataType); + if (dataType != napi_object) { + HILOGE("type mismatch for parameter 2"); + return false; + } + + auto serializeDataPtr = new (std::nothrow) SerializeData(); + if (serializeDataPtr == nullptr) { + HILOGE("memory allocation failed"); + return false; + } + std::shared_ptr serializeData(serializeDataPtr, [env](SerializeData* data) { + if (env != nullptr && std::get(data->peerData)) { + napi_delete_serialization_data(env, std::get(data->peerData)); + } + delete data; + data = nullptr; + }); + serializeData->envType = EnvType::NAPI; + if (!NapiSerialize::PeerSerialize(env, argv, serializeData)) { + return false; + } + if (AsyncCallbackManager::GetInstance().IsCrossRuntime(eventId, EnvType::NAPI)) { + serializeData->isCrossRuntime = true; + if (!NapiSerialize::CrossSerialize(env, argv, serializeData)) { + return false; + } + } + auto event = InnerEvent::Get(eventId, serializeData); + event->SetIsEnhanced(true); + EventHandlerInstance::GetInstance()->SendEvent(event, 0, priority); + return true; +} + +void EmitWithDefaultData(InnerEvent::EventId eventId, Priority priority) +{ + auto serializeData = make_shared(); + serializeData->envType = EnvType::NAPI; + if (AsyncCallbackManager::GetInstance().IsCrossRuntime(eventId, EnvType::NAPI)) { + serializeData->isCrossRuntime = true; + } + auto event = InnerEvent::Get(eventId, serializeData); + event->SetIsEnhanced(true); + EventHandlerInstance::GetInstance()->SendEvent(event, 0, priority); +} + +napi_value EmitWithEventIdUint32(napi_env env, size_t argc, napi_value argv[]) +{ + InnerEvent::EventId eventId = 0u; + bool hasEventId = false; + napi_value value = nullptr; + napi_has_named_property(env, argv[0], "eventId", &hasEventId); + if (hasEventId == false) { + HILOGE("Wrong argument 1 does not have event id"); + return nullptr; + } + + napi_get_named_property(env, argv[0], "eventId", &value); + uint32_t id = 0u; + napi_get_value_uint32(env, value, &id); + eventId = id; + HILOGD("Event id value:%{public}u", id); + + if (!AsyncCallbackManager::GetInstance().IsExistValidCallback(eventId)) { + EH_LOGE_LIMIT("Invalid callback"); + return nullptr; + } + + bool hasPriority = false; + napi_has_named_property(env, argv[0], "priority", &hasPriority); + Priority priority = Priority::LOW; + if (hasPriority) { + napi_get_named_property(env, argv[0], "priority", &value); + uint32_t priorityValue = 0u; + napi_get_value_uint32(env, value, &priorityValue); + HILOGD("Event priority:%{public}d", priorityValue); + priority = static_cast(priorityValue); + } + + if (argc == ARGC_NUM && EmitWithEventData(env, argv[1], eventId, priority)) { + return nullptr; + } else { + EmitWithDefaultData(eventId, priority); + } + return nullptr; +} + +napi_value EmitWithEventIdString(napi_env env, size_t argc, napi_value argv[]) +{ + InnerEvent::EventId eventId = 0u; + auto valueCStr = std::make_unique(NAPI_VALUE_STRING_LEN + 1); + size_t valueStrLength = 0; + napi_get_value_string_utf8(env, argv[0], valueCStr.get(), NAPI_VALUE_STRING_LEN, &valueStrLength); + std::string id(valueCStr.get(), valueStrLength); + if (id.empty()) { + HILOGE("Invalid event id:%{public}s", id.c_str()); + return nullptr; + } + eventId = id; + HILOGD("Event id value:%{public}s", id.c_str()); + + if (!AsyncCallbackManager::GetInstance().IsExistValidCallback(eventId)) { + EH_LOGE_LIMIT("Invalid callback"); + return nullptr; + } + Priority priority = Priority::LOW; + if (argc < ARGC_NUM) { + EmitWithDefaultData(eventId, priority); + return nullptr; + } + bool hasPriority = false; + napi_value value = nullptr; + napi_has_named_property(env, argv[1], "priority", &hasPriority); + if (!hasPriority) { + if (!EmitWithEventData(env, argv[1], eventId, priority)) { + EmitWithDefaultData(eventId, priority); + } + return nullptr; + } + + napi_get_named_property(env, argv[1], "priority", &value); + uint32_t priorityValue = 0u; + napi_get_value_uint32(env, value, &priorityValue); + HILOGD("Event priority:%{public}d", priorityValue); + priority = static_cast(priorityValue); + + if (argc > ARGC_NUM && EmitWithEventData(env, argv[ARGC_NUM], eventId, priority)) { + return nullptr; + } else { + EmitWithDefaultData(eventId, priority); + } + return nullptr; +} + +napi_value JS_Emit(napi_env env, napi_callback_info cbinfo) +{ + HILOGD("JS_Emit enter"); + size_t argc = ARGC_NUM + ARGC_ONE; + napi_value argv[ARGC_NUM + ARGC_ONE] = {0}; + NAPI_CALL(env, napi_get_cb_info(env, cbinfo, &argc, argv, NULL, NULL)); + if (argc < ARGC_ONE) { + HILOGE("Requires more than 1 parameter"); + return nullptr; + } + napi_valuetype eventValueType; + napi_typeof(env, argv[0], &eventValueType); + if (eventValueType != napi_object && eventValueType != napi_string) { + HILOGE("Type mismatch for parameter 1"); + return nullptr; + } + if (eventValueType == napi_string) { + return EmitWithEventIdString(env, argc, argv); + } + return EmitWithEventIdUint32(env, argc, argv); +} + +napi_value CreateJsUndefined(napi_env env) +{ + napi_value result = nullptr; + napi_get_undefined(env, &result); + return result; +} + +napi_value CreateJsNumber(napi_env env, uint32_t value) +{ + napi_value result = nullptr; + napi_create_uint32(env, value, &result); + return result; +} + +napi_value JS_GetListenerCount(napi_env env, napi_callback_info cbinfo) +{ + HILOGD("JS_GetListenerCount enter"); + size_t argc = ARGC_NUM; + napi_value argv[ARGC_NUM] = {0}; + NAPI_CALL(env, napi_get_cb_info(env, cbinfo, &argc, argv, NULL, NULL)); + if (argc < ARGC_ONE) { + HILOGE("Requires more than 1 parameter"); + return CreateJsUndefined(env); + } + + napi_valuetype eventValueType; + napi_typeof(env, argv[0], &eventValueType); + if (eventValueType != napi_number && eventValueType != napi_string) { + HILOGE("Type mismatch for parameter 1"); + return CreateJsUndefined(env); + } + + InnerEvent::EventId eventId = 0u; + bool ret = GetEventIdWithNumberOrString(env, argv[0], eventValueType, eventId); + if (!ret) { + HILOGE("Event id is empty for parameter 1"); + return CreateJsUndefined(env); + } + + uint32_t cnt = AsyncCallbackManager::GetInstance().GetListenerCountByEventId(eventId); + return CreateJsNumber(env, cnt); +} + +napi_value EnumEventClassConstructor(napi_env env, napi_callback_info info) +{ + napi_value thisArg = nullptr; + void *data = nullptr; + + napi_get_cb_info(env, info, nullptr, nullptr, &thisArg, &data); + + napi_value global = nullptr; + napi_get_global(env, &global); + + return thisArg; +} + +napi_value CreateEnumEventPriority(napi_env env, napi_value exports) +{ + napi_value immediate = nullptr; + napi_value high = nullptr; + napi_value low = nullptr; + napi_value idle = nullptr; + + napi_create_uint32(env, static_cast(Priority::IMMEDIATE), &immediate); + napi_create_uint32(env, static_cast(Priority::HIGH), &high); + napi_create_uint32(env, static_cast(Priority::LOW), &low); + napi_create_uint32(env, static_cast(Priority::IDLE), &idle); + + napi_property_descriptor desc[] = { + DECLARE_NAPI_STATIC_PROPERTY("IMMEDIATE", immediate), + DECLARE_NAPI_STATIC_PROPERTY("HIGH", high), + DECLARE_NAPI_STATIC_PROPERTY("LOW", low), + DECLARE_NAPI_STATIC_PROPERTY("IDLE", idle), + }; + napi_value result = nullptr; + napi_define_class(env, "EventPriority", NAPI_AUTO_LENGTH, EnumEventClassConstructor, nullptr, + sizeof(desc) / sizeof(*desc), desc, &result); + + napi_set_named_property(env, exports, "EventPriority", result); + + return exports; +} + +void ProcessEvent(const InnerEvent::Pointer& event) +{ + AsyncCallbackManager::GetInstance().DoCallback(event); +} + +void AgentInit() +{ + EmitterEnhancedApi api = { + .JS_Off = &JS_Off, + .JS_Emit = &JS_Emit, + .JS_GetListenerCount = &JS_GetListenerCount, + .ProcessEvent = &ProcessEvent + }; + + GetEmitterEnhancedApiRegister().Register(api); +} +} // namespace AppExecFwk +} // namespace OHOS \ No newline at end of file diff --git a/frameworks/emitter/napi/src/napi_serialize.cpp b/frameworks/emitter/napi/src/napi_serialize.cpp new file mode 100644 index 0000000..160e232 --- /dev/null +++ b/frameworks/emitter/napi/src/napi_serialize.cpp @@ -0,0 +1,76 @@ +/* + * 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 "napi_serialize.h" +#include "event_logger.h" + +namespace OHOS { +namespace AppExecFwk { +namespace { +DEFINE_EH_HILOG_LABEL("EventsEmitter"); +} +bool NapiSerialize::PeerSerialize(napi_env env, napi_value argv, std::shared_ptr serializeData) +{ + bool hasData = false; + void* result = nullptr; + napi_has_named_property(env, argv, "data", &hasData); + if (hasData) { + napi_value data = nullptr; + napi_get_named_property(env, argv, "data", &data); + napi_status serializeResult = napi_ok; + napi_value undefined = nullptr; + napi_get_undefined(env, &undefined); + bool defaultTransfer = false; + bool defaultCloneSendable = false; + serializeResult = napi_serialize_inner(env, data, undefined, undefined, + defaultTransfer, defaultCloneSendable, &result); + if (serializeResult != napi_ok || result == nullptr) { + HILOGE("Napi PeerSerialize fail"); + return false; + } + } + serializeData->peerData = reinterpret_cast(result); + return true; +} + +bool NapiSerialize::CrossSerialize(napi_env env, napi_value argv, std::shared_ptr serializeData) +{ + bool hasData = false; + napi_has_named_property(env, argv, "data", &hasData); + if (hasData) { + napi_value data = nullptr; + napi_get_named_property(env, argv, "data", &data); + napi_value globalValue; + napi_get_global(env, &globalValue); + napi_value jsonValue; + napi_get_named_property(env, globalValue, "JSON", &jsonValue); + napi_value stringifyValue; + napi_get_named_property(env, jsonValue, "stringify", &stringifyValue); + napi_value funcArgv[1] = { data }; + napi_value returnValue; + if (napi_call_function(env, jsonValue, stringifyValue, 1, funcArgv, &returnValue) != napi_ok) { + HILOGE("Napi CrossSerialize fail"); + return false; + } + size_t len = 0; + napi_get_value_string_utf8(env, returnValue, nullptr, 0, &len); + std::unique_ptr paramsChar = std::make_unique(len + 1); + napi_get_value_string_utf8(env, returnValue, paramsChar.get(), len + 1, &len); + serializeData->crossData = paramsChar.get(); + } + return true; +} +} // namespace AppExecFwk +} // namespace OHOS \ No newline at end of file diff --git a/frameworks/eventhandler/test/unittest/lib_event_handler_event_queue_test.cpp b/frameworks/eventhandler/test/unittest/lib_event_handler_event_queue_test.cpp index 6b792ad..0db823b 100644 --- a/frameworks/eventhandler/test/unittest/lib_event_handler_event_queue_test.cpp +++ b/frameworks/eventhandler/test/unittest/lib_event_handler_event_queue_test.cpp @@ -30,9 +30,7 @@ #include "epoll_io_waiter.h" #include "event_handler.h" #include "event_queue.h" -#define private public #include "event_queue_base.h" -#undef private #include "event_runner.h" #include "inner_event.h" #include "event_queue_ffrt.h" @@ -2864,34 +2862,4 @@ HWTEST_F(LibEventHandlerEventQueueTest, SetUsableTest_002, TestSize.Level1) auto event = InnerEvent::Get(f, "event"); auto result = queue.Insert(event); EXPECT_EQ(false, result); -} - -/* - * @tc.name: InsertTest - * @tc.desc: InsertTest_003 test, change event list have nullptr - * @tc.type: FUNC - */ -HWTEST_F(LibEventHandlerEventQueueTest, InsertTest_003, TestSize.Level1) -{ - auto now = InnerEvent::Clock::now(); - EventQueueBase queue; - queue.Prepare(); - uint32_t eventId = 0; - queue.idleEvents_.clear(); - queue.idleEvents_.push_back( - std::unique_ptr(nullptr, nullptr)); - - auto event = InnerEvent::Get(eventId); - event->SetSendTime(now); - event->SetHandleTime(now); - queue.Insert(event, EventQueue::Priority::IDLE); - - for (int i = 0; i < queue.idleEvents_.size(); i++) { - auto event = queue.GetEvent(); - if (event == nullptr) { - continue; - } - auto id = event->GetInnerEventId(); - EXPECT_EQ(eventId, id); - } } \ No newline at end of file diff --git a/frameworks/napi/BUILD.gn b/frameworks/napi/BUILD.gn index c5ab5fc..248b79e 100644 --- a/frameworks/napi/BUILD.gn +++ b/frameworks/napi/BUILD.gn @@ -1,65 +1,98 @@ -# Copyright (c) 2021-2024 Huawei Device Co., Ltd. -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import("//build/ohos.gni") -import("//build/ohos/ace/ace.gni") -import("../../eventhandler.gni") -if (is_arkui_x) { - import("//plugins/events/eventhandler.gni") - ohos_source_set("emitter") { - include_dirs = [ - "include", - "//third_party/node/src", - "//third_party/libuv/include", - ] - include_dirs += emitter_include - sources = [ - "src/events_emitter.cpp", - "src/init.cpp", - ] - } -} else { - ohos_shared_library("emitter") { - sanitize = { - integer_overflow = true - ubsan = true - boundary_sanitize = true - cfi = true - cfi_cross_dso = true - debug = false - } - branch_protector_ret = "pac_ret" - - include_dirs = [ - "include", - "${inner_api_path}", - ] - - sources = [ - "src/events_emitter.cpp", - "src/init.cpp", - ] - - deps = [ "${frameworks_path}/eventhandler:libeventhandler" ] - - external_deps = [ - "c_utils:utils", - "hilog:libhilog", - "napi:ace_napi", - ] - - relative_install_dir = "module/events" - subsystem_name = "notification" - part_name = "eventhandler" - } -} +# Copyright (c) 2021-2024 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build/ohos.gni") +import("//build/ohos/ace/ace.gni") +import("../../eventhandler.gni") + +config("public_emitter_config") { + include_dirs = [ "include" ] +} + +if (is_arkui_x) { + import("//plugins/events/eventhandler.gni") + ohos_source_set("emitter") { + include_dirs = [ + "include", + "//third_party/node/src", + "//third_party/libuv/include", + ] + include_dirs += emitter_include + sources = [ + "src/events_emitter.cpp", + "src/init.cpp", + ] + } +} else { + ohos_shared_library("emitter") { + sanitize = { + integer_overflow = true + ubsan = true + boundary_sanitize = true + cfi = true + cfi_cross_dso = true + debug = false + } + branch_protector_ret = "pac_ret" + + sources = [ + "src/init.cpp", + ] + + deps = [ "${frameworks_path}/napi:emitter_interops" ] + + external_deps = [ + "napi:ace_napi", + ] + + relative_install_dir = "module/events" + subsystem_name = "notification" + part_name = "eventhandler" + } +} + +ohos_shared_library("emitter_interops") { + sanitize = { + integer_overflow = true + ubsan = true + boundary_sanitize = true + cfi = true + cfi_cross_dso = true + debug = false + } + branch_protector_ret = "pac_ret" + version_script = "libemitter.map" + + include_dirs = [ + "include", + "${inner_api_path}", + ] + + public_configs = [ ":public_emitter_config" ] + + sources = [ + "src/events_emitter.cpp", + "src/interops.cpp" + ] + + deps = [ "${frameworks_path}/eventhandler:libeventhandler" ] + + external_deps = [ + "c_utils:utils", + "hilog:libhilog", + "napi:ace_napi", + ] + + subsystem_name = "notification" + part_name = "eventhandler" +} \ No newline at end of file diff --git a/frameworks/napi/include/events_emitter.h b/frameworks/napi/include/events_emitter.h index e06491c..6a4d261 100644 --- a/frameworks/napi/include/events_emitter.h +++ b/frameworks/napi/include/events_emitter.h @@ -1,95 +1,69 @@ -/* - * Copyright (c) 2021-2022 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 BASE_EVENTHANDLER_FRAMEWORKS_NAPI_INCLUDE_JS_EMITTER_H -#define BASE_EVENTHANDLER_FRAMEWORKS_NAPI_INCLUDE_JS_EMITTER_H - -#include -#include -#include -#include - -#include "event_handler.h" -#include "event_runner.h" -#include "event_queue.h" -#include "inner_event.h" -#include -#include "napi/native_api.h" -#include "napi/native_node_api.h" - -namespace OHOS { -namespace AppExecFwk { -using Priority = EventQueue::Priority; -static const int32_t ARGC_NUM = 2; -static const int32_t NAPI_VALUE_STRING_LEN = 10240; -struct AsyncCallbackInfo; -class EventHandlerInstance : public EventHandler { -public: - EventHandlerInstance(const std::shared_ptr& runner); - static std::shared_ptr GetInstance(); - ~EventHandlerInstance(); - void ProcessEvent(const InnerEvent::Pointer& event) override; - std::unordered_set> GetAsyncCallbackInfo(const InnerEvent::EventId &eventId); - napi_env deleteEnv = nullptr; -}; - -enum class DataType: uint32_t { - BOOL = 0, - INT, - STRING, -}; - -struct Val { - DataType type; - - union { - bool bValue; - int32_t nValue; - char cValue[NAPI_VALUE_STRING_LEN] = {0}; - } value; -}; - -struct AsyncCallbackInfo { - std::atomic env; - std::atomic once = false; - std::atomic isDeleted = false; - napi_ref callback = 0; - napi_threadsafe_function tsfn = nullptr; - InnerEvent::EventId eventId; - ~AsyncCallbackInfo(); -}; - -using EventData = std::shared_ptr; -struct EventDataWorker { - EventData data; - std::shared_ptr callbackInfo; -}; - -napi_value EmitterInit(napi_env env, napi_value exports); -napi_value JS_On(napi_env env, napi_callback_info cbinfo); -napi_value JS_Off(napi_env env, napi_callback_info cbinfo); -napi_value JS_Once(napi_env env, napi_callback_info cbinfo); -napi_value JS_Emit(napi_env env, napi_callback_info cbinfo); - -static inline napi_valuetype GetNapiType(napi_env env, napi_value param) -{ - napi_valuetype type; - napi_typeof(env, param, &type); - return type; -} -} // namespace AppExecFwk -} // namespace OHOS - -#endif // BASE_EVENTHANDLER_FRAMEWORKS_NAPI_INCLUDE_JS_EMITTER_H +/* + * Copyright (c) 2021-2022 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 BASE_EVENTHANDLER_FRAMEWORKS_NAPI_INCLUDE_JS_EMITTER_H +#define BASE_EVENTHANDLER_FRAMEWORKS_NAPI_INCLUDE_JS_EMITTER_H + +#include +#include +#include +#include + +#include "event_handler.h" +#include "event_runner.h" +#include "event_queue.h" +#include "inner_event.h" +#include +#include "napi/native_api.h" +#include "napi/native_node_api.h" + +namespace OHOS { +namespace AppExecFwk { +using Priority = EventQueue::Priority; +static const int32_t ARGC_NUM = 2; +static const int32_t NAPI_VALUE_STRING_LEN = 10240; + +enum class DataType: uint32_t { + BOOL = 0, + INT, + STRING, +}; + +struct Val { + DataType type; + + union { + bool bValue; + int32_t nValue; + char cValue[NAPI_VALUE_STRING_LEN] = {0}; + } value; +}; + +napi_value EmitterInit(napi_env env, napi_value exports); +napi_value JS_On(napi_env env, napi_callback_info cbinfo); +napi_value JS_Off(napi_env env, napi_callback_info cbinfo); +napi_value JS_Once(napi_env env, napi_callback_info cbinfo); +napi_value JS_Emit(napi_env env, napi_callback_info cbinfo); + +static inline napi_valuetype GetNapiType(napi_env env, napi_value param) +{ + napi_valuetype type; + napi_typeof(env, param, &type); + return type; +} +} // namespace AppExecFwk +} // namespace OHOS + +#endif // BASE_EVENTHANDLER_FRAMEWORKS_NAPI_INCLUDE_JS_EMITTER_H diff --git a/frameworks/napi/include/interops.h b/frameworks/napi/include/interops.h new file mode 100644 index 0000000..daa052b --- /dev/null +++ b/frameworks/napi/include/interops.h @@ -0,0 +1,87 @@ +/* + * 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 BASE_EVENTHANDLER_FRAMEWORKS_INTEROPS_H +#define BASE_EVENTHANDLER_FRAMEWORKS_INTEROPS_H + +#include +#include +#include +#include + +#include "inner_event.h" +#include "event_handler.h" +#include "napi/native_api.h" +#include "napi/native_node_api.h" + +namespace OHOS { +namespace AppExecFwk { + +struct AsyncCallbackInfo { + std::atomic env; + std::atomic once = false; + std::atomic isDeleted = false; + napi_ref callback = 0; + napi_threadsafe_function tsfn = nullptr; + InnerEvent::EventId eventId; + ~AsyncCallbackInfo(); +}; + +class EventHandlerInstance : public EventHandler { +public: + EventHandlerInstance(const std::shared_ptr& runner); + static std::shared_ptr GetInstance(); + ~EventHandlerInstance(); + void ProcessEvent(const InnerEvent::Pointer& event) override; + std::unordered_set> GetAsyncCallbackInfo(const InnerEvent::EventId &eventId); + napi_env deleteEnv = nullptr; +}; + +using AsyncCallbackInfoContainer = + std::map>>; +AsyncCallbackInfoContainer& GetAsyncCallbackInfoContainer(); +std::mutex& GetAsyncCallbackInfoContainerMutex(); + +struct EmitterEnhancedApi { + napi_value (*JS_Off)(napi_env env, napi_callback_info cbinfo) = nullptr; + napi_value (*JS_Emit)(napi_env env, napi_callback_info cbinfo) = nullptr; + napi_value (*JS_GetListenerCount)(napi_env env, napi_callback_info cbinfo) = nullptr; + void (*ProcessEvent)(const InnerEvent::Pointer& event) = nullptr; +}; + +class EmitterEnhancedApiRegister { +public: + EmitterEnhancedApiRegister(); + void Register(const EmitterEnhancedApi& api); + bool IsInit() const; + std::shared_ptr GetEnhancedApi() const; + +private: + std::shared_ptr enhancedApi_; + std::atomic isInit_{false}; +}; + +EmitterEnhancedApiRegister& GetEmitterEnhancedApiRegister(); + +using EventData = std::shared_ptr; +struct AsyncCallbackInfo; +struct EventDataWorker { + EventData data{nullptr}; + std::shared_ptr callbackInfo{nullptr}; + std::string crossRuntimeData{}; + bool isCrossRuntime{false}; +}; +} +} +#endif // BASE_EVENTHANDLER_FRAMEWORKS_INTEROPS_H \ No newline at end of file diff --git a/frameworks/ani/BUILD.gn b/frameworks/napi/libemitter.map similarity index 59% rename from frameworks/ani/BUILD.gn rename to frameworks/napi/libemitter.map index e91c227..fe316fc 100644 --- a/frameworks/ani/BUILD.gn +++ b/frameworks/napi/libemitter.map @@ -1,26 +1,27 @@ -# Copyright (c) 2025 Huawei Device Co., Ltd. -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import("//build/ohos.gni") -import("../../eventhandler.gni") - -group("ani_event_emitter_packages") { - if (support_jsapi) { - deps = [ - "${frameworks_path}/ani/event_emitter:eventEmitter", - "${frameworks_path}/ani/event_emitter:event_emitter_abc_etc", - ] - } else { - deps = [] - } -} +# 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. + +1.0 { + global: + *GetAsyncCallbackInfoContainer*; + *GetAsyncCallbackInfoContainerMutex*; + *GetEmitterEnhancedApiRegister*; + *EmitterInit*; + extern "C++" { + *EventHandlerInstance::*; + *AsyncCallbackInfo::*; + *EmitterEnhancedApiRegister::*; + }; + local: + *; +}; \ No newline at end of file diff --git a/frameworks/napi/src/events_emitter.cpp b/frameworks/napi/src/events_emitter.cpp index 488ccc2..f10f060 100644 --- a/frameworks/napi/src/events_emitter.cpp +++ b/frameworks/napi/src/events_emitter.cpp @@ -1,756 +1,812 @@ -/* - * Copyright (c) 2021-2023 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 "events_emitter.h" - -#include -#include -#include -#include -#include -#include -#include "event_logger.h" -#include "js_native_api_types.h" -#include "napi/native_node_api.h" - -using namespace std; -namespace OHOS { -namespace AppExecFwk { -namespace { - DEFINE_EH_HILOG_LABEL("EventsEmitter"); - constexpr static uint32_t ARGC_ONE = 1u; -} - static std::mutex g_emitterInsMutex; - static map>> emitterInstances; - std::shared_ptr eventHandler; - AsyncCallbackInfo::~AsyncCallbackInfo() - { - env = nullptr; - } - EventHandlerInstance::EventHandlerInstance(const std::shared_ptr& runner): EventHandler(runner) - { - HILOGD("EventHandlerInstance constructed"); - } - EventHandlerInstance::~EventHandlerInstance() - { - HILOGD("EventHandlerInstance de-constructed"); - } - std::shared_ptr EventHandlerInstance::GetInstance() - { - static auto runner = EventRunner::Create("OS_eventsEmtr", ThreadMode::FFRT); - if (runner.get() == nullptr) { - HILOGE("failed to create EventRunner events_emitter"); - return nullptr; - } - static auto instance = std::make_shared(runner); - return instance; - } - - void ProcessCallback(const EventDataWorker* eventDataInner) - { - HILOGD("emit ProcessCallback enter"); - - std::shared_ptr callbackInner = eventDataInner->callbackInfo; - napi_value resultData = nullptr; - if (eventDataInner->data != nullptr && *(eventDataInner->data) != nullptr) { - if (napi_deserialize(callbackInner->env, *(eventDataInner->data), &resultData) != napi_ok || - resultData == nullptr) { - HILOGE("Deserialize fail."); - return; - } - } - napi_value event = nullptr; - napi_create_object(callbackInner->env, &event); - napi_set_named_property(callbackInner->env, event, "data", resultData); - napi_value callback = nullptr; - napi_value returnVal = nullptr; - napi_get_reference_value(callbackInner->env, callbackInner->callback, &callback); - napi_call_function(callbackInner->env, nullptr, callback, 1, &event, &returnVal); - if (callbackInner->once) { - HILOGD("ProcessEvent delete once"); - std::lock_guard lock(g_emitterInsMutex); - auto iter = emitterInstances.find(callbackInner->eventId); - if (iter != emitterInstances.end()) { - auto callback = iter->second.find(callbackInner); - if (callback != iter->second.end()) { - iter->second.erase(callback); - } - } - } - } - - void OutPutEventIdLog(const InnerEvent::EventId &eventId) - { - if (eventId.index() == TYPE_U32_INDEX) { - HILOGD("Event id value:%{public}u", std::get(eventId)); - } else { - HILOGD("Event id value:%{public}s", std::get(eventId).c_str()); - } - } - - void ThreadSafeCallback(napi_env env, napi_value jsCallback, void* context, void* data) - { - napi_handle_scope scope; - EventDataWorker* eventDataInner = static_cast(data); - if (eventDataInner != nullptr) { - auto callbackInfoInner = eventDataInner->callbackInfo; - if (callbackInfoInner && !(callbackInfoInner->isDeleted)) { - napi_open_handle_scope(callbackInfoInner->env, &scope); - if (scope == nullptr) { - HILOGD("Scope is null"); - return; - } - ProcessCallback(eventDataInner); - napi_close_handle_scope(callbackInfoInner->env, scope); - } - } - delete eventDataInner; - eventDataInner = nullptr; - data = nullptr; - } - - std::unordered_set> EventHandlerInstance::GetAsyncCallbackInfo( - const InnerEvent::EventId &eventId) - { - std::lock_guard lock(g_emitterInsMutex); - auto iter = emitterInstances.find(eventId); - if (iter == emitterInstances.end()) { - std::unordered_set> result; - HILOGW("ProcessEvent has no callback"); - return result; - } - for (auto it = iter->second.begin(); it != iter->second.end();) { - if ((*it)->isDeleted == true || (*it)->env == nullptr) { - it = iter->second.erase(it); - continue; - } - ++it; - } - return iter->second; - } - - void EventHandlerInstance::ProcessEvent([[maybe_unused]] const InnerEvent::Pointer& event) - { - InnerEvent::EventId eventId = event->GetInnerEventIdEx(); - OutPutEventIdLog(eventId); - auto callbackInfos = GetAsyncCallbackInfo(eventId); - if (callbackInfos.size() <= 0) { - HILOGW("ProcessEvent has no valid callback"); - return; - } - - size_t callbackSize = callbackInfos.size(); - HILOGD("size = %{public}zu", callbackSize); - auto value = event->GetUniqueObject(); - std::shared_ptr eventData(value.release(), [this](napi_value* pData) { - if (pData != nullptr && (*pData) != nullptr && deleteEnv != nullptr) { - napi_delete_serialization_data(deleteEnv, *pData); - } else { - HILOGW("EventData delete release failed."); - } - }); - for (auto it = callbackInfos.begin(); it != callbackInfos.end(); ++it) { - callbackSize--; - EventDataWorker* eventDataWorker = new (std::nothrow) EventDataWorker(); - if (!eventDataWorker) { - HILOGE("new object failed"); - if (callbackSize == 0) { - HILOGW("EventData maybe release at process %{public}zu", callbackInfos.size()); - } - continue; - } - if ((*it)->env == nullptr || (*it)->isDeleted) { - HILOGE("env is release"); - if (callbackSize == 0) { - HILOGW("EventData maybe release at nullptr %{public}zu", callbackInfos.size()); - } - delete eventDataWorker; - continue; - } - deleteEnv = (*it)->env; - eventDataWorker->data = eventData; - if (callbackSize == 0) { - eventData.reset(); - } - eventDataWorker->callbackInfo = (*it); - napi_acquire_threadsafe_function((*it)->tsfn); - napi_call_threadsafe_function((*it)->tsfn, eventDataWorker, napi_tsfn_nonblocking); - napi_release_threadsafe_function((*it)->tsfn, napi_tsfn_release); - } - } - - static void UpdateOnceFlag(std::shared_ptrcallbackInfo, bool once) - { - if (!once) { - if (callbackInfo->once) { - HILOGD("JS_On change once to on"); - callbackInfo->once = false; - } else { - HILOGD("JS_On already on"); - } - } else { - if (callbackInfo->once) { - HILOGD("JS_Once already once"); - } else { - HILOGD("JS_Once change on to once"); - callbackInfo->once = true; - } - } - } - - void DeleteCallbackInfo(napi_env env, const InnerEvent::EventId &eventIdValue, napi_value argv) - { - std::lock_guard lock(g_emitterInsMutex); - auto iter = emitterInstances.find(eventIdValue); - if (iter == emitterInstances.end()) { - return; - } - for (auto callbackInfo = iter->second.begin(); callbackInfo != iter->second.end();) { - napi_value callback = nullptr; - if ((*callbackInfo)->env != env) { - ++callbackInfo; - continue; - } - napi_get_reference_value((*callbackInfo)->env, (*callbackInfo)->callback, &callback); - bool isEq = false; - napi_strict_equals(env, argv, callback, &isEq); - if (!isEq) { - ++callbackInfo; - continue; - } - (*callbackInfo)->isDeleted = true; - callbackInfo = iter->second.erase(callbackInfo); - return; - } - return; - } - - std::shared_ptr SearchCallbackInfo(napi_env env, const InnerEvent::EventId &eventIdValue, - napi_value argv) - { - auto subscribe = emitterInstances.find(eventIdValue); - if (subscribe == emitterInstances.end()) { - return nullptr; - } - for (auto callbackInfo : subscribe->second) { - napi_value callback = nullptr; - if (callbackInfo->isDeleted) { - continue; - } - if (callbackInfo->env != env) { - continue; - } - napi_get_reference_value(callbackInfo->env, callbackInfo->callback, &callback); - bool isEq = false; - napi_strict_equals(env, argv, callback, &isEq); - if (!isEq) { - continue; - } - return callbackInfo; - } - return nullptr; - } - - bool GetEventIdWithObjectOrString( - napi_env env, napi_value argv, napi_valuetype eventValueType, InnerEvent::EventId &eventId) - { - if (eventValueType == napi_string) { - auto valueCStr = std::make_unique(NAPI_VALUE_STRING_LEN + 1); - size_t valueStrLength = 0; - napi_get_value_string_utf8(env, argv, valueCStr.get(), NAPI_VALUE_STRING_LEN, &valueStrLength); - std::string id(valueCStr.get(), valueStrLength); - if (id.empty()) { - HILOGE("Event id is empty for argument 1."); - return false; - } - eventId = id; - HILOGD("Event id value:%{public}s", id.c_str()); - } else { - bool hasEventId = false; - napi_has_named_property(env, argv, "eventId", &hasEventId); - if (!hasEventId) { - HILOGE("Argument 1 does not have event id."); - return false; - } - - napi_value eventIdValue = nullptr; - napi_get_named_property(env, argv, "eventId", &eventIdValue); - uint32_t id = 0u; - napi_get_value_uint32(env, eventIdValue, &id); - eventId = id; - HILOGD("Event id value:%{public}u", id); - } - return true; - } - - void ThreadFinished(napi_env env, void* data, [[maybe_unused]] void* context) - { - HILOGD("ThreadFinished"); - } - - void ReleaseCallbackInfo(AsyncCallbackInfo* callbackInfo) - { - if (callbackInfo != nullptr) { - uv_loop_s *loop = nullptr; - if (napi_get_uv_event_loop(callbackInfo->env, &loop) != napi_ok) { - delete callbackInfo; - callbackInfo = nullptr; - return; - } - uv_work_t *work = new (std::nothrow) uv_work_t; - if (work == nullptr) { - delete callbackInfo; - callbackInfo = nullptr; - return; - } - work->data = reinterpret_cast(callbackInfo); - auto ret = uv_queue_work_with_qos(loop, work, [](uv_work_t* work) {}, - [](uv_work_t *work, int status) { - AsyncCallbackInfo* callbackInfo = reinterpret_cast(work->data); - if (napi_delete_reference(callbackInfo->env, callbackInfo->callback) != napi_ok) { - HILOGE("napi_delete_reference fail."); - } - napi_release_threadsafe_function(callbackInfo->tsfn, napi_tsfn_release); - delete callbackInfo; - callbackInfo = nullptr; - delete work; - work = nullptr; - }, uv_qos_user_initiated); - if (ret != napi_ok) { - delete callbackInfo; - callbackInfo = nullptr; - delete work; - work = nullptr; - } - } - } - - napi_value OnOrOnce(napi_env env, napi_callback_info cbinfo, bool once) - { - size_t argc = ARGC_NUM; - napi_value argv[ARGC_NUM] = {0}; - NAPI_CALL(env, napi_get_cb_info(env, cbinfo, &argc, argv, NULL, NULL)); - if (argc < ARGC_NUM) { - HILOGE("requires 2 parameter"); - return nullptr; - } - - napi_valuetype eventValueType = GetNapiType(env, argv[0]); - if (eventValueType != napi_object && eventValueType != napi_string) { - HILOGE("type mismatch for parameter 1"); - return nullptr; - } - - if (GetNapiType(env, argv[1]) != napi_function) { - HILOGE("type mismatch for parameter 2"); - return nullptr; - } - - InnerEvent::EventId eventIdValue = 0u; - bool ret = GetEventIdWithObjectOrString(env, argv[0], eventValueType, eventIdValue); - if (!ret) { - return nullptr; - } - std::lock_guard lock(g_emitterInsMutex); - auto callbackInfo = SearchCallbackInfo(env, eventIdValue, argv[1]); - if (callbackInfo != nullptr) { - UpdateOnceFlag(callbackInfo, once); - } else { - callbackInfo = std::shared_ptr(new (std::nothrow) AsyncCallbackInfo(), - [](AsyncCallbackInfo* callbackInfo) { - ReleaseCallbackInfo(callbackInfo); - }); - if (!callbackInfo) { - HILOGE("new object failed"); - return nullptr; - } - callbackInfo->env = env; - callbackInfo->once = once; - callbackInfo->eventId = eventIdValue; - napi_create_reference(env, argv[1], 1, &callbackInfo->callback); - napi_wrap(env, argv[1], new (std::nothrow) std::weak_ptr(callbackInfo), - [](napi_env env, void* data, void* hint) { - auto callbackInfoPtr = static_cast*>(data); - if (callbackInfoPtr != nullptr && (*callbackInfoPtr).lock() != nullptr) { - (*callbackInfoPtr).lock()->isDeleted = true; - (*callbackInfoPtr).lock()->env = nullptr; - } - }, nullptr, nullptr); - napi_value resourceName = nullptr; - napi_create_string_utf8(env, "Call thread-safe function", NAPI_AUTO_LENGTH, &resourceName); - napi_create_threadsafe_function(env, argv[1], nullptr, resourceName, 0, 1, nullptr, ThreadFinished, - nullptr, ThreadSafeCallback, &(callbackInfo->tsfn)); - emitterInstances[eventIdValue].insert(callbackInfo); - } - return nullptr; - } - - bool GetEventIdWithNumberOrString( - napi_env env, napi_value argv, napi_valuetype eventValueType, InnerEvent::EventId &eventId) - { - if (eventValueType == napi_string) { - auto valueCStr = std::make_unique(NAPI_VALUE_STRING_LEN + 1); - size_t valueStrLength = 0; - napi_get_value_string_utf8(env, argv, valueCStr.get(), NAPI_VALUE_STRING_LEN, &valueStrLength); - std::string id(valueCStr.get(), valueStrLength); - if (id.empty()) { - return false; - } - eventId = id; - HILOGD("Event id value:%{public}s", id.c_str()); - } else { - uint32_t id = 0u; - napi_get_value_uint32(env, argv, &id); - eventId = id; - HILOGD("Event id value:%{public}u", id); - } - return true; - } - - napi_value JS_On(napi_env env, napi_callback_info cbinfo) - { - HILOGD("JS_On enter"); - return OnOrOnce(env, cbinfo, false); - } - - napi_value JS_Once(napi_env env, napi_callback_info cbinfo) - { - HILOGD("JS_Once enter"); - return OnOrOnce(env, cbinfo, true); - } - - napi_value JS_Off(napi_env env, napi_callback_info cbinfo) - { - HILOGD("JS_Off enter"); - size_t argc = ARGC_NUM; - napi_value argv[ARGC_NUM] = {0}; - NAPI_CALL(env, napi_get_cb_info(env, cbinfo, &argc, argv, NULL, NULL)); - if (argc < 1) { - HILOGE("requires at least 1 parameter"); - return nullptr; - } - - napi_valuetype eventValueType; - napi_typeof(env, argv[0], &eventValueType); - if (eventValueType != napi_number && eventValueType != napi_string) { - HILOGE("type mismatch for parameter 1"); - return nullptr; - } - - InnerEvent::EventId eventId = 0u; - bool ret = GetEventIdWithNumberOrString(env, argv[0], eventValueType, eventId); - if (!ret) { - HILOGE("Event id is empty for parameter 1."); - return nullptr; - } - - if (argc == ARGC_NUM) { - napi_valuetype eventHandleType; - napi_typeof(env, argv[1], &eventHandleType); - if (eventHandleType != napi_function) { - HILOGE("type mismatch for parameter 2"); - return nullptr; - } - DeleteCallbackInfo(env, eventId, argv[1]); - return nullptr; - } - std::lock_guard lock(g_emitterInsMutex); - auto iter = emitterInstances.find(eventId); - if (iter != emitterInstances.end()) { - for (auto callbackInfo : iter->second) { - callbackInfo->isDeleted = true; - } - } - emitterInstances.erase(eventId); - return nullptr; - } - - bool EmitWithEventData(napi_env env, napi_value argv, const InnerEvent::EventId &eventId, Priority priority) - { - HILOGD("EmitWithEventData enter"); - napi_valuetype dataType; - napi_typeof(env, argv, &dataType); - if (dataType != napi_object) { - HILOGE("type mismatch for parameter 2"); - return false; - } - bool hasData = false; - void* serializeData = nullptr; - napi_has_named_property(env, argv, "data", &hasData); - if (hasData) { - napi_value data = nullptr; - napi_get_named_property(env, argv, "data", &data); - napi_status serializeResult = napi_ok; - napi_value undefined = nullptr; - napi_get_undefined(env, &undefined); - bool defaultTransfer = false; - bool defaultCloneSendable = false; - serializeResult = napi_serialize_inner(env, data, undefined, undefined, - defaultTransfer, defaultCloneSendable, &serializeData); - if (serializeResult != napi_ok || serializeData == nullptr) { - HILOGE("Serialize fail."); - return false; - } - } - OutPutEventIdLog(eventId); - auto event = InnerEvent::Get(eventId, make_unique(reinterpret_cast(serializeData))); - eventHandler->SendEvent(event, 0, priority); - return true; - } - - bool IsExistValidCallback(napi_env env, const InnerEvent::EventId &eventId) - { - std::lock_guard lock(g_emitterInsMutex); - auto subscribe = emitterInstances.find(eventId); - if (subscribe == emitterInstances.end()) { - EH_LOGW_LIMIT("JS_Emit has no callback"); - return false; - } - if (subscribe->second.size() != 0) { - return true; - } - EH_LOGE_LIMIT("Invalid callback"); - return false; - } - - napi_value EmitWithEventIdUint32(napi_env env, size_t argc, napi_value argv[]) - { - InnerEvent::EventId eventId = 0u; - bool hasEventId = false; - napi_value value = nullptr; - napi_has_named_property(env, argv[0], "eventId", &hasEventId); - if (hasEventId == false) { - HILOGE("Wrong argument 1 does not have event id."); - return nullptr; - } - - napi_get_named_property(env, argv[0], "eventId", &value); - uint32_t id = 0u; - napi_get_value_uint32(env, value, &id); - eventId = id; - HILOGD("Event id value:%{public}u", id); - - if (!IsExistValidCallback(env, eventId)) { - return nullptr; - } - - bool hasPriority = false; - napi_has_named_property(env, argv[0], "priority", &hasPriority); - Priority priority = Priority::LOW; - if (hasPriority) { - napi_get_named_property(env, argv[0], "priority", &value); - uint32_t priorityValue = 0u; - napi_get_value_uint32(env, value, &priorityValue); - HILOGD("Event priority:%{public}d", priorityValue); - priority = static_cast(priorityValue); - } - - if (argc == ARGC_NUM && EmitWithEventData(env, argv[1], eventId, priority)) { - return nullptr; - } else { - auto event = InnerEvent::Get(eventId, make_unique()); - eventHandler->SendEvent(event, 0, priority); - } - return nullptr; - } - - napi_value EmitWithEventIdString(napi_env env, size_t argc, napi_value argv[]) - { - InnerEvent::EventId eventId = 0u; - auto valueCStr = std::make_unique(NAPI_VALUE_STRING_LEN + 1); - size_t valueStrLength = 0; - napi_get_value_string_utf8(env, argv[0], valueCStr.get(), NAPI_VALUE_STRING_LEN, &valueStrLength); - std::string id(valueCStr.get(), valueStrLength); - if (id.empty()) { - HILOGE("Invalid event id:%{public}s", id.c_str()); - return nullptr; - } - eventId = id; - HILOGD("Event id value:%{public}s", id.c_str()); - - if (!IsExistValidCallback(env, eventId)) { - return nullptr; - } - - Priority priority = Priority::LOW; - if (argc < ARGC_NUM) { - auto event = InnerEvent::Get(eventId, make_unique()); - eventHandler->SendEvent(event, 0, priority); - return nullptr; - } - - bool hasPriority = false; - napi_value value = nullptr; - napi_has_named_property(env, argv[1], "priority", &hasPriority); - if (!hasPriority) { - if (!EmitWithEventData(env, argv[1], eventId, priority)) { - auto event = InnerEvent::Get(eventId, make_unique()); - eventHandler->SendEvent(event, 0, priority); - } - return nullptr; - } - - napi_get_named_property(env, argv[1], "priority", &value); - uint32_t priorityValue = 0u; - napi_get_value_uint32(env, value, &priorityValue); - HILOGD("Event priority:%{public}d", priorityValue); - priority = static_cast(priorityValue); - - if (argc > ARGC_NUM && EmitWithEventData(env, argv[ARGC_NUM], eventId, priority)) { - return nullptr; - } else { - auto event = InnerEvent::Get(eventId, make_unique()); - eventHandler->SendEvent(event, 0, priority); - } - return nullptr; - } - - napi_value JS_Emit(napi_env env, napi_callback_info cbinfo) - { - HILOGD("JS_Emit enter"); - size_t argc = ARGC_NUM + ARGC_ONE; - napi_value argv[ARGC_NUM + ARGC_ONE] = {0}; - NAPI_CALL(env, napi_get_cb_info(env, cbinfo, &argc, argv, NULL, NULL)); - if (argc < ARGC_ONE) { - HILOGE("Requires more than 1 parameter"); - return nullptr; - } - - napi_valuetype eventValueType; - napi_typeof(env, argv[0], &eventValueType); - if (eventValueType != napi_object && eventValueType != napi_string) { - HILOGE("Type mismatch for parameter 1"); - return nullptr; - } - - if (eventValueType == napi_string) { - return EmitWithEventIdString(env, argc, argv); - } - return EmitWithEventIdUint32(env, argc, argv); - } - - napi_value EnumEventClassConstructor(napi_env env, napi_callback_info info) - { - napi_value thisArg = nullptr; - void *data = nullptr; - - napi_get_cb_info(env, info, nullptr, nullptr, &thisArg, &data); - - napi_value global = nullptr; - napi_get_global(env, &global); - - return thisArg; - } - - napi_value CreateEnumEventPriority(napi_env env, napi_value exports) - { - napi_value immediate = nullptr; - napi_value high = nullptr; - napi_value low = nullptr; - napi_value idle = nullptr; - - napi_create_uint32(env, (uint32_t)Priority::IMMEDIATE, &immediate); - napi_create_uint32(env, (uint32_t)Priority::HIGH, &high); - napi_create_uint32(env, (uint32_t)Priority::LOW, &low); - napi_create_uint32(env, (uint32_t)Priority::IDLE, &idle); - - napi_property_descriptor desc[] = { - DECLARE_NAPI_STATIC_PROPERTY("IMMEDIATE", immediate), - DECLARE_NAPI_STATIC_PROPERTY("HIGH", high), - DECLARE_NAPI_STATIC_PROPERTY("LOW", low), - DECLARE_NAPI_STATIC_PROPERTY("IDLE", idle), - }; - napi_value result = nullptr; - napi_define_class(env, "EventPriority", NAPI_AUTO_LENGTH, EnumEventClassConstructor, nullptr, - sizeof(desc) / sizeof(*desc), desc, &result); - - napi_set_named_property(env, exports, "EventPriority", result); - - return exports; - } - - napi_value CreateJsUndefined(napi_env env) - { - napi_value result = nullptr; - napi_get_undefined(env, &result); - return result; - } - - napi_value CreateJsNumber(napi_env env, uint32_t value) - { - napi_value result = nullptr; - napi_create_uint32(env, value, &result); - return result; - } - - napi_value JS_GetListenerCount(napi_env env, napi_callback_info cbinfo) - { - HILOGD("JS_GetListenerCount enter"); - size_t argc = ARGC_NUM; - napi_value argv[ARGC_NUM] = {0}; - NAPI_CALL(env, napi_get_cb_info(env, cbinfo, &argc, argv, NULL, NULL)); - if (argc < ARGC_ONE) { - HILOGE("Requires more than 1 parameter"); - return CreateJsUndefined(env); - } - - napi_valuetype eventValueType; - napi_typeof(env, argv[0], &eventValueType); - if (eventValueType != napi_number && eventValueType != napi_string) { - HILOGE("Type mismatch for parameter 1"); - return CreateJsUndefined(env); - } - - uint32_t cnt = 0u; - InnerEvent::EventId eventId = 0u; - bool ret = GetEventIdWithNumberOrString(env, argv[0], eventValueType, eventId); - if (!ret) { - HILOGE("Event id is empty for parameter 1."); - return CreateJsUndefined(env); - } - std::lock_guard lock(g_emitterInsMutex); - auto subscribe = emitterInstances.find(eventId); - if (subscribe != emitterInstances.end()) { - for (auto it = subscribe->second.begin(); it != subscribe->second.end();) { - if ((*it)->isDeleted == true || (*it)->env == nullptr) { - it = subscribe->second.erase(it); - continue; - } - ++it; - ++cnt; - } - } - return CreateJsNumber(env, cnt); - } - - napi_value EmitterInit(napi_env env, napi_value exports) - { - HILOGD("EmitterInit enter"); - napi_property_descriptor desc[] = { - DECLARE_NAPI_FUNCTION("on", JS_On), - DECLARE_NAPI_FUNCTION("once", JS_Once), - DECLARE_NAPI_FUNCTION("off", JS_Off), - DECLARE_NAPI_FUNCTION("emit", JS_Emit), - DECLARE_NAPI_FUNCTION("getListenerCount", JS_GetListenerCount), - }; - NAPI_CALL(env, napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc)); - - CreateEnumEventPriority(env, exports); - - eventHandler = EventHandlerInstance::GetInstance(); - return exports; - } -} // namespace AppExecFwk -} // namespace OHOS +/* + * Copyright (c) 2021-2023 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 "events_emitter.h" + +#include +#include +#include +#include +#include +#include +#include "event_logger.h" +#include "js_native_api_types.h" +#include "napi/native_node_api.h" +#include "interops.h" + +using namespace std; +namespace OHOS { +namespace AppExecFwk { +namespace { + DEFINE_EH_HILOG_LABEL("EventsEmitter"); + constexpr static uint32_t ARGC_ONE = 1u; + bool StringToNapiValue(napi_env env, napi_value* napiValue, std::string strValue) + { + if (strValue.length() > 0) { + napi_value globalValue; + napi_get_global(env, &globalValue); + napi_value jsonValue; + napi_get_named_property(env, globalValue, "JSON", &jsonValue); + napi_value parseValue; + napi_get_named_property(env, jsonValue, "parse", &parseValue); + napi_value paramsNApi; + napi_create_string_utf8(env, strValue.c_str(), NAPI_AUTO_LENGTH, ¶msNApi); + napi_value funcArgv[1] = { paramsNApi }; + auto status = napi_call_function(env, jsonValue, parseValue, 1, funcArgv, napiValue); + if (status != napi_ok) { + HILOGE("StringToNapiValue Stringify Failed"); + return false; + } + } + return true; + } +} + static std::mutex g_emitterInsMutex; + static std::map>> emitterInstances; + AsyncCallbackInfoContainer& GetAsyncCallbackInfoContainer() + { + return emitterInstances; + } + + std::mutex& GetAsyncCallbackInfoContainerMutex() + { + return g_emitterInsMutex; + } + + std::shared_ptr eventHandler; + AsyncCallbackInfo::~AsyncCallbackInfo() + { + env = nullptr; + } + EventHandlerInstance::EventHandlerInstance(const std::shared_ptr& runner): EventHandler(runner) + { + HILOGD("EventHandlerInstance constructed"); + } + EventHandlerInstance::~EventHandlerInstance() + { + HILOGD("EventHandlerInstance de-constructed"); + } + std::shared_ptr EventHandlerInstance::GetInstance() + { + static auto runner = EventRunner::Create("OS_eventsEmtr", ThreadMode::FFRT); + if (runner.get() == nullptr) { + HILOGE("failed to create EventRunner events_emitter"); + return nullptr; + } + static auto instance = std::make_shared(runner); + return instance; + } + + void ProcessCallback(const EventDataWorker* eventDataInner) + { + HILOGD("emit ProcessCallback enter"); + + std::shared_ptr callbackInner = eventDataInner->callbackInfo; + napi_value resultData = nullptr; + if (eventDataInner->isCrossRuntime) { + bool ret = StringToNapiValue(callbackInner->env, &resultData, eventDataInner->crossRuntimeData); + if (!ret) { + return; + } + } else { + if (eventDataInner->data != nullptr && *(eventDataInner->data) != nullptr) { + if (napi_deserialize(callbackInner->env, *(eventDataInner->data), &resultData) != napi_ok || + resultData == nullptr) { + HILOGE("Deserialize fail."); + return; + } + } + } + napi_value event = nullptr; + napi_create_object(callbackInner->env, &event); + napi_set_named_property(callbackInner->env, event, "data", resultData); + napi_value callback = nullptr; + napi_value returnVal = nullptr; + napi_get_reference_value(callbackInner->env, callbackInner->callback, &callback); + napi_call_function(callbackInner->env, nullptr, callback, 1, &event, &returnVal); + if (callbackInner->once) { + HILOGD("ProcessEvent delete once"); + std::lock_guard lock(g_emitterInsMutex); + auto iter = emitterInstances.find(callbackInner->eventId); + if (iter != emitterInstances.end()) { + auto callback = iter->second.find(callbackInner); + if (callback != iter->second.end()) { + iter->second.erase(callback); + } + } + } + } + + void OutPutEventIdLog(const InnerEvent::EventId &eventId) + { + if (eventId.index() == TYPE_U32_INDEX) { + HILOGD("Event id value:%{public}u", std::get(eventId)); + } else { + HILOGD("Event id value:%{public}s", std::get(eventId).c_str()); + } + } + + void ThreadSafeCallback(napi_env env, napi_value jsCallback, void* context, void* data) + { + napi_handle_scope scope; + EventDataWorker* eventDataInner = static_cast(data); + if (eventDataInner != nullptr) { + auto callbackInfoInner = eventDataInner->callbackInfo; + if (callbackInfoInner && !(callbackInfoInner->isDeleted)) { + napi_open_handle_scope(callbackInfoInner->env, &scope); + if (scope == nullptr) { + HILOGD("Scope is null"); + return; + } + ProcessCallback(eventDataInner); + napi_close_handle_scope(callbackInfoInner->env, scope); + } + } + delete eventDataInner; + eventDataInner = nullptr; + data = nullptr; + } + + std::unordered_set> EventHandlerInstance::GetAsyncCallbackInfo( + const InnerEvent::EventId &eventId) + { + std::lock_guard lock(g_emitterInsMutex); + auto iter = emitterInstances.find(eventId); + if (iter == emitterInstances.end()) { + std::unordered_set> result; + HILOGW("ProcessEvent has no callback"); + return result; + } + for (auto it = iter->second.begin(); it != iter->second.end();) { + if ((*it)->isDeleted == true || (*it)->env == nullptr) { + it = iter->second.erase(it); + continue; + } + ++it; + } + return iter->second; + } + + void EventHandlerInstance::ProcessEvent([[maybe_unused]] const InnerEvent::Pointer& event) + { + if (event->IsEnhanced() && GetEmitterEnhancedApiRegister().IsInit() && + GetEmitterEnhancedApiRegister().GetEnhancedApi()->ProcessEvent != nullptr) { + GetEmitterEnhancedApiRegister().GetEnhancedApi()->ProcessEvent(event); + return; + } + InnerEvent::EventId eventId = event->GetInnerEventIdEx(); + OutPutEventIdLog(eventId); + auto callbackInfos = GetAsyncCallbackInfo(eventId); + if (callbackInfos.size() <= 0) { + HILOGW("ProcessEvent has no valid callback"); + return; + } + + size_t callbackSize = callbackInfos.size(); + HILOGD("size = %{public}zu", callbackSize); + auto value = event->GetUniqueObject(); + std::shared_ptr eventData(value.release(), [this](napi_value* pData) { + if (pData != nullptr && (*pData) != nullptr && deleteEnv != nullptr) { + napi_delete_serialization_data(deleteEnv, *pData); + } else { + HILOGW("EventData delete release failed."); + } + }); + for (auto it = callbackInfos.begin(); it != callbackInfos.end(); ++it) { + callbackSize--; + EventDataWorker* eventDataWorker = new (std::nothrow) EventDataWorker(); + if (!eventDataWorker) { + HILOGE("new object failed"); + if (callbackSize == 0) { + HILOGW("EventData maybe release at process %{public}zu", callbackInfos.size()); + } + continue; + } + if ((*it)->env == nullptr || (*it)->isDeleted) { + HILOGE("env is release"); + if (callbackSize == 0) { + HILOGW("EventData maybe release at nullptr %{public}zu", callbackInfos.size()); + } + delete eventDataWorker; + continue; + } + deleteEnv = (*it)->env; + eventDataWorker->data = eventData; + if (callbackSize == 0) { + eventData.reset(); + } + eventDataWorker->callbackInfo = (*it); + napi_acquire_threadsafe_function((*it)->tsfn); + napi_call_threadsafe_function((*it)->tsfn, eventDataWorker, napi_tsfn_nonblocking); + napi_release_threadsafe_function((*it)->tsfn, napi_tsfn_release); + } + } + + static void UpdateOnceFlag(std::shared_ptrcallbackInfo, bool once) + { + if (!once) { + if (callbackInfo->once) { + HILOGD("JS_On change once to on"); + callbackInfo->once = false; + } else { + HILOGD("JS_On already on"); + } + } else { + if (callbackInfo->once) { + HILOGD("JS_Once already once"); + } else { + HILOGD("JS_Once change on to once"); + callbackInfo->once = true; + } + } + } + + void DeleteCallbackInfo(napi_env env, const InnerEvent::EventId &eventIdValue, napi_value argv) + { + std::lock_guard lock(g_emitterInsMutex); + auto iter = emitterInstances.find(eventIdValue); + if (iter == emitterInstances.end()) { + return; + } + for (auto callbackInfo = iter->second.begin(); callbackInfo != iter->second.end();) { + napi_value callback = nullptr; + if ((*callbackInfo)->env != env) { + ++callbackInfo; + continue; + } + napi_get_reference_value((*callbackInfo)->env, (*callbackInfo)->callback, &callback); + bool isEq = false; + napi_strict_equals(env, argv, callback, &isEq); + if (!isEq) { + ++callbackInfo; + continue; + } + (*callbackInfo)->isDeleted = true; + callbackInfo = iter->second.erase(callbackInfo); + return; + } + return; + } + + std::shared_ptr SearchCallbackInfo(napi_env env, const InnerEvent::EventId &eventIdValue, + napi_value argv) + { + auto subscribe = emitterInstances.find(eventIdValue); + if (subscribe == emitterInstances.end()) { + return nullptr; + } + for (auto callbackInfo : subscribe->second) { + napi_value callback = nullptr; + if (callbackInfo->isDeleted) { + continue; + } + if (callbackInfo->env != env) { + continue; + } + napi_get_reference_value(callbackInfo->env, callbackInfo->callback, &callback); + bool isEq = false; + napi_strict_equals(env, argv, callback, &isEq); + if (!isEq) { + continue; + } + return callbackInfo; + } + return nullptr; + } + + bool GetEventIdWithObjectOrString( + napi_env env, napi_value argv, napi_valuetype eventValueType, InnerEvent::EventId &eventId) + { + if (eventValueType == napi_string) { + auto valueCStr = std::make_unique(NAPI_VALUE_STRING_LEN + 1); + size_t valueStrLength = 0; + napi_get_value_string_utf8(env, argv, valueCStr.get(), NAPI_VALUE_STRING_LEN, &valueStrLength); + std::string id(valueCStr.get(), valueStrLength); + if (id.empty()) { + HILOGE("Event id is empty for argument 1."); + return false; + } + eventId = id; + HILOGD("Event id value:%{public}s", id.c_str()); + } else { + bool hasEventId = false; + napi_has_named_property(env, argv, "eventId", &hasEventId); + if (!hasEventId) { + HILOGE("Argument 1 does not have event id."); + return false; + } + + napi_value eventIdValue = nullptr; + napi_get_named_property(env, argv, "eventId", &eventIdValue); + uint32_t id = 0u; + napi_get_value_uint32(env, eventIdValue, &id); + eventId = id; + HILOGD("Event id value:%{public}u", id); + } + return true; + } + + void ThreadFinished(napi_env env, void* data, [[maybe_unused]] void* context) + { + HILOGD("ThreadFinished"); + } + + void ReleaseCallbackInfo(AsyncCallbackInfo* callbackInfo) + { + if (callbackInfo != nullptr) { + uv_loop_s *loop = nullptr; + if (napi_get_uv_event_loop(callbackInfo->env, &loop) != napi_ok) { + delete callbackInfo; + callbackInfo = nullptr; + return; + } + uv_work_t *work = new (std::nothrow) uv_work_t; + if (work == nullptr) { + delete callbackInfo; + callbackInfo = nullptr; + return; + } + work->data = reinterpret_cast(callbackInfo); + auto ret = uv_queue_work_with_qos(loop, work, [](uv_work_t* work) {}, + [](uv_work_t *work, int status) { + AsyncCallbackInfo* callbackInfo = reinterpret_cast(work->data); + if (napi_delete_reference(callbackInfo->env, callbackInfo->callback) != napi_ok) { + HILOGE("napi_delete_reference fail."); + } + napi_release_threadsafe_function(callbackInfo->tsfn, napi_tsfn_release); + delete callbackInfo; + callbackInfo = nullptr; + delete work; + work = nullptr; + }, uv_qos_user_initiated); + if (ret != napi_ok) { + delete callbackInfo; + callbackInfo = nullptr; + delete work; + work = nullptr; + } + } + } + + napi_value OnOrOnce(napi_env env, napi_callback_info cbinfo, bool once) + { + size_t argc = ARGC_NUM; + napi_value argv[ARGC_NUM] = {0}; + NAPI_CALL(env, napi_get_cb_info(env, cbinfo, &argc, argv, NULL, NULL)); + if (argc < ARGC_NUM) { + HILOGE("requires 2 parameter"); + return nullptr; + } + + napi_valuetype eventValueType = GetNapiType(env, argv[0]); + if (eventValueType != napi_object && eventValueType != napi_string) { + HILOGE("type mismatch for parameter 1"); + return nullptr; + } + + if (GetNapiType(env, argv[1]) != napi_function) { + HILOGE("type mismatch for parameter 2"); + return nullptr; + } + + InnerEvent::EventId eventIdValue = 0u; + bool ret = GetEventIdWithObjectOrString(env, argv[0], eventValueType, eventIdValue); + if (!ret) { + return nullptr; + } + std::lock_guard lock(g_emitterInsMutex); + auto callbackInfo = SearchCallbackInfo(env, eventIdValue, argv[1]); + if (callbackInfo != nullptr) { + UpdateOnceFlag(callbackInfo, once); + } else { + callbackInfo = std::shared_ptr(new (std::nothrow) AsyncCallbackInfo(), + [](AsyncCallbackInfo* callbackInfo) { + ReleaseCallbackInfo(callbackInfo); + }); + if (!callbackInfo) { + HILOGE("new object failed"); + return nullptr; + } + callbackInfo->env = env; + callbackInfo->once = once; + callbackInfo->eventId = eventIdValue; + napi_create_reference(env, argv[1], 1, &callbackInfo->callback); + napi_wrap(env, argv[1], new (std::nothrow) std::weak_ptr(callbackInfo), + [](napi_env env, void* data, void* hint) { + auto callbackInfoPtr = static_cast*>(data); + if (callbackInfoPtr != nullptr && (*callbackInfoPtr).lock() != nullptr) { + (*callbackInfoPtr).lock()->isDeleted = true; + (*callbackInfoPtr).lock()->env = nullptr; + } + }, nullptr, nullptr); + napi_value resourceName = nullptr; + napi_create_string_utf8(env, "Call thread-safe function", NAPI_AUTO_LENGTH, &resourceName); + napi_create_threadsafe_function(env, argv[1], nullptr, resourceName, 0, 1, nullptr, ThreadFinished, + nullptr, ThreadSafeCallback, &(callbackInfo->tsfn)); + emitterInstances[eventIdValue].insert(callbackInfo); + } + return nullptr; + } + + bool GetEventIdWithNumberOrString( + napi_env env, napi_value argv, napi_valuetype eventValueType, InnerEvent::EventId &eventId) + { + if (eventValueType == napi_string) { + auto valueCStr = std::make_unique(NAPI_VALUE_STRING_LEN + 1); + size_t valueStrLength = 0; + napi_get_value_string_utf8(env, argv, valueCStr.get(), NAPI_VALUE_STRING_LEN, &valueStrLength); + std::string id(valueCStr.get(), valueStrLength); + if (id.empty()) { + return false; + } + eventId = id; + HILOGD("Event id value:%{public}s", id.c_str()); + } else { + uint32_t id = 0u; + napi_get_value_uint32(env, argv, &id); + eventId = id; + HILOGD("Event id value:%{public}u", id); + } + return true; + } + + napi_value JS_On(napi_env env, napi_callback_info cbinfo) + { + HILOGD("JS_On enter"); + return OnOrOnce(env, cbinfo, false); + } + + napi_value JS_Once(napi_env env, napi_callback_info cbinfo) + { + HILOGD("JS_Once enter"); + return OnOrOnce(env, cbinfo, true); + } + + napi_value JS_Off(napi_env env, napi_callback_info cbinfo) + { + if (GetEmitterEnhancedApiRegister().IsInit() && + GetEmitterEnhancedApiRegister().GetEnhancedApi()->JS_Off != nullptr) { + return GetEmitterEnhancedApiRegister().GetEnhancedApi()->JS_Off(env, cbinfo); + } + HILOGD("JS_Off enter"); + size_t argc = ARGC_NUM; + napi_value argv[ARGC_NUM] = {0}; + NAPI_CALL(env, napi_get_cb_info(env, cbinfo, &argc, argv, NULL, NULL)); + if (argc < 1) { + HILOGE("requires at least 1 parameter"); + return nullptr; + } + + napi_valuetype eventValueType; + napi_typeof(env, argv[0], &eventValueType); + if (eventValueType != napi_number && eventValueType != napi_string) { + HILOGE("type mismatch for parameter 1"); + return nullptr; + } + + InnerEvent::EventId eventId = 0u; + bool ret = GetEventIdWithNumberOrString(env, argv[0], eventValueType, eventId); + if (!ret) { + HILOGE("Event id is empty for parameter 1."); + return nullptr; + } + + if (argc == ARGC_NUM) { + napi_valuetype eventHandleType; + napi_typeof(env, argv[1], &eventHandleType); + if (eventHandleType != napi_function) { + HILOGE("type mismatch for parameter 2"); + return nullptr; + } + DeleteCallbackInfo(env, eventId, argv[1]); + return nullptr; + } + std::lock_guard lock(g_emitterInsMutex); + auto iter = emitterInstances.find(eventId); + if (iter != emitterInstances.end()) { + for (auto callbackInfo : iter->second) { + callbackInfo->isDeleted = true; + } + } + emitterInstances.erase(eventId); + return nullptr; + } + + bool EmitWithEventData(napi_env env, napi_value argv, const InnerEvent::EventId &eventId, Priority priority) + { + HILOGD("EmitWithEventData enter"); + napi_valuetype dataType; + napi_typeof(env, argv, &dataType); + if (dataType != napi_object) { + HILOGE("type mismatch for parameter 2"); + return false; + } + bool hasData = false; + void* serializeData = nullptr; + napi_has_named_property(env, argv, "data", &hasData); + if (hasData) { + napi_value data = nullptr; + napi_get_named_property(env, argv, "data", &data); + napi_status serializeResult = napi_ok; + napi_value undefined = nullptr; + napi_get_undefined(env, &undefined); + bool defaultTransfer = false; + bool defaultCloneSendable = false; + serializeResult = napi_serialize_inner(env, data, undefined, undefined, + defaultTransfer, defaultCloneSendable, &serializeData); + if (serializeResult != napi_ok || serializeData == nullptr) { + HILOGE("Serialize fail."); + return false; + } + } + OutPutEventIdLog(eventId); + auto event = InnerEvent::Get(eventId, make_unique(reinterpret_cast(serializeData))); + eventHandler->SendEvent(event, 0, priority); + return true; + } + + bool IsExistValidCallback(napi_env env, const InnerEvent::EventId &eventId) + { + std::lock_guard lock(g_emitterInsMutex); + auto subscribe = emitterInstances.find(eventId); + if (subscribe == emitterInstances.end()) { + EH_LOGW_LIMIT("JS_Emit has no callback"); + return false; + } + if (subscribe->second.size() != 0) { + return true; + } + return false; + } + + napi_value EmitWithEventIdUint32(napi_env env, size_t argc, napi_value argv[]) + { + InnerEvent::EventId eventId = 0u; + bool hasEventId = false; + napi_value value = nullptr; + napi_has_named_property(env, argv[0], "eventId", &hasEventId); + if (hasEventId == false) { + HILOGE("Wrong argument 1 does not have event id."); + return nullptr; + } + + napi_get_named_property(env, argv[0], "eventId", &value); + uint32_t id = 0u; + napi_get_value_uint32(env, value, &id); + eventId = id; + HILOGD("Event id value:%{public}u", id); + + if (!IsExistValidCallback(env, eventId)) { + EH_LOGE_LIMIT("Invalid callback"); + return nullptr; + } + + bool hasPriority = false; + napi_has_named_property(env, argv[0], "priority", &hasPriority); + Priority priority = Priority::LOW; + if (hasPriority) { + napi_get_named_property(env, argv[0], "priority", &value); + uint32_t priorityValue = 0u; + napi_get_value_uint32(env, value, &priorityValue); + HILOGD("Event priority:%{public}d", priorityValue); + priority = static_cast(priorityValue); + } + + if (argc == ARGC_NUM && EmitWithEventData(env, argv[1], eventId, priority)) { + return nullptr; + } else { + auto event = InnerEvent::Get(eventId, make_unique()); + eventHandler->SendEvent(event, 0, priority); + } + return nullptr; + } + + napi_value EmitWithEventIdString(napi_env env, size_t argc, napi_value argv[]) + { + InnerEvent::EventId eventId = 0u; + auto valueCStr = std::make_unique(NAPI_VALUE_STRING_LEN + 1); + size_t valueStrLength = 0; + napi_get_value_string_utf8(env, argv[0], valueCStr.get(), NAPI_VALUE_STRING_LEN, &valueStrLength); + std::string id(valueCStr.get(), valueStrLength); + if (id.empty()) { + HILOGE("Invalid event id:%{public}s", id.c_str()); + return nullptr; + } + eventId = id; + HILOGD("Event id value:%{public}s", id.c_str()); + + if (!IsExistValidCallback(env, eventId)) { + EH_LOGE_LIMIT("Invalid callback"); + return nullptr; + } + + Priority priority = Priority::LOW; + if (argc < ARGC_NUM) { + auto event = InnerEvent::Get(eventId, make_unique()); + eventHandler->SendEvent(event, 0, priority); + return nullptr; + } + + bool hasPriority = false; + napi_value value = nullptr; + napi_has_named_property(env, argv[1], "priority", &hasPriority); + if (!hasPriority) { + if (!EmitWithEventData(env, argv[1], eventId, priority)) { + auto event = InnerEvent::Get(eventId, make_unique()); + eventHandler->SendEvent(event, 0, priority); + } + return nullptr; + } + + napi_get_named_property(env, argv[1], "priority", &value); + uint32_t priorityValue = 0u; + napi_get_value_uint32(env, value, &priorityValue); + HILOGD("Event priority:%{public}d", priorityValue); + priority = static_cast(priorityValue); + + if (argc > ARGC_NUM && EmitWithEventData(env, argv[ARGC_NUM], eventId, priority)) { + return nullptr; + } else { + auto event = InnerEvent::Get(eventId, make_unique()); + eventHandler->SendEvent(event, 0, priority); + } + return nullptr; + } + + napi_value JS_Emit(napi_env env, napi_callback_info cbinfo) + { + if (GetEmitterEnhancedApiRegister().IsInit() && + GetEmitterEnhancedApiRegister().GetEnhancedApi()->JS_Emit != nullptr) { + return GetEmitterEnhancedApiRegister().GetEnhancedApi()->JS_Emit(env, cbinfo); + } + HILOGD("JS_Emit enter"); + size_t argc = ARGC_NUM + ARGC_ONE; + napi_value argv[ARGC_NUM + ARGC_ONE] = {0}; + NAPI_CALL(env, napi_get_cb_info(env, cbinfo, &argc, argv, NULL, NULL)); + if (argc < ARGC_ONE) { + HILOGE("Requires more than 1 parameter"); + return nullptr; + } + + napi_valuetype eventValueType; + napi_typeof(env, argv[0], &eventValueType); + if (eventValueType != napi_object && eventValueType != napi_string) { + HILOGE("Type mismatch for parameter 1"); + return nullptr; + } + + if (eventValueType == napi_string) { + return EmitWithEventIdString(env, argc, argv); + } + return EmitWithEventIdUint32(env, argc, argv); + } + + napi_value EnumEventClassConstructor(napi_env env, napi_callback_info info) + { + napi_value thisArg = nullptr; + void *data = nullptr; + + napi_get_cb_info(env, info, nullptr, nullptr, &thisArg, &data); + + napi_value global = nullptr; + napi_get_global(env, &global); + + return thisArg; + } + + napi_value CreateEnumEventPriority(napi_env env, napi_value exports) + { + napi_value immediate = nullptr; + napi_value high = nullptr; + napi_value low = nullptr; + napi_value idle = nullptr; + + napi_create_uint32(env, (uint32_t)Priority::IMMEDIATE, &immediate); + napi_create_uint32(env, (uint32_t)Priority::HIGH, &high); + napi_create_uint32(env, (uint32_t)Priority::LOW, &low); + napi_create_uint32(env, (uint32_t)Priority::IDLE, &idle); + + napi_property_descriptor desc[] = { + DECLARE_NAPI_STATIC_PROPERTY("IMMEDIATE", immediate), + DECLARE_NAPI_STATIC_PROPERTY("HIGH", high), + DECLARE_NAPI_STATIC_PROPERTY("LOW", low), + DECLARE_NAPI_STATIC_PROPERTY("IDLE", idle), + }; + napi_value result = nullptr; + napi_define_class(env, "EventPriority", NAPI_AUTO_LENGTH, EnumEventClassConstructor, nullptr, + sizeof(desc) / sizeof(*desc), desc, &result); + + napi_set_named_property(env, exports, "EventPriority", result); + + return exports; + } + + napi_value CreateJsUndefined(napi_env env) + { + napi_value result = nullptr; + napi_get_undefined(env, &result); + return result; + } + + napi_value CreateJsNumber(napi_env env, uint32_t value) + { + napi_value result = nullptr; + napi_create_uint32(env, value, &result); + return result; + } + + napi_value JS_GetListenerCount(napi_env env, napi_callback_info cbinfo) + { + if (GetEmitterEnhancedApiRegister().IsInit() && + GetEmitterEnhancedApiRegister().GetEnhancedApi()->JS_GetListenerCount != nullptr) { + return GetEmitterEnhancedApiRegister().GetEnhancedApi()->JS_GetListenerCount(env, cbinfo); + } + HILOGD("JS_GetListenerCount enter"); + size_t argc = ARGC_NUM; + napi_value argv[ARGC_NUM] = {0}; + NAPI_CALL(env, napi_get_cb_info(env, cbinfo, &argc, argv, NULL, NULL)); + if (argc < ARGC_ONE) { + HILOGE("Requires more than 1 parameter"); + return CreateJsUndefined(env); + } + + napi_valuetype eventValueType; + napi_typeof(env, argv[0], &eventValueType); + if (eventValueType != napi_number && eventValueType != napi_string) { + HILOGE("Type mismatch for parameter 1"); + return CreateJsUndefined(env); + } + + uint32_t cnt = 0u; + InnerEvent::EventId eventId = 0u; + bool ret = GetEventIdWithNumberOrString(env, argv[0], eventValueType, eventId); + if (!ret) { + HILOGE("Event id is empty for parameter 1."); + return CreateJsUndefined(env); + } + std::lock_guard lock(g_emitterInsMutex); + auto subscribe = emitterInstances.find(eventId); + if (subscribe != emitterInstances.end()) { + for (auto it = subscribe->second.begin(); it != subscribe->second.end();) { + if ((*it)->isDeleted == true || (*it)->env == nullptr) { + it = subscribe->second.erase(it); + continue; + } + ++it; + ++cnt; + } + } + return CreateJsNumber(env, cnt); + } + + napi_value EmitterInit(napi_env env, napi_value exports) + { + HILOGD("EmitterInit enter"); + napi_property_descriptor desc[] = { + DECLARE_NAPI_FUNCTION("on", JS_On), + DECLARE_NAPI_FUNCTION("once", JS_Once), + DECLARE_NAPI_FUNCTION("off", JS_Off), + DECLARE_NAPI_FUNCTION("emit", JS_Emit), + DECLARE_NAPI_FUNCTION("getListenerCount", JS_GetListenerCount), + }; + NAPI_CALL(env, napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc)); + + CreateEnumEventPriority(env, exports); + + eventHandler = EventHandlerInstance::GetInstance(); + return exports; + } +} // namespace AppExecFwk +} // namespace OHOS diff --git a/frameworks/napi/src/init.cpp b/frameworks/napi/src/init.cpp index ed59aaf..9f0f5ba 100644 --- a/frameworks/napi/src/init.cpp +++ b/frameworks/napi/src/init.cpp @@ -1,44 +1,44 @@ -/* - * Copyright (c) 2021-2022 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 "events_emitter.h" - -#include "napi/native_api.h" -#include "napi/native_node_api.h" -namespace OHOS { -namespace AppExecFwk { -EXTERN_C_START -static napi_value Init(napi_env env, napi_value exports) -{ - EmitterInit(env, exports); - return exports; -} -EXTERN_C_END - -static napi_module _module = { - .nm_version = 1, - .nm_flags = 0, - .nm_filename = nullptr, - .nm_register_func = Init, - .nm_modname = "events.emitter", - .nm_priv = ((void *)0), - .reserved = {0} -}; - -extern "C" __attribute__((constructor)) void RegisterModule(void) -{ - napi_module_register(&_module); -} -} // namespace AppExecFwk -} // namespace OHOS +/* + * Copyright (c) 2021-2022 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 "events_emitter.h" + +#include "napi/native_api.h" +#include "napi/native_node_api.h" +namespace OHOS { +namespace AppExecFwk { +EXTERN_C_START +static napi_value Init(napi_env env, napi_value exports) +{ + EmitterInit(env, exports); + return exports; +} +EXTERN_C_END + +static napi_module _module = { + .nm_version = 1, + .nm_flags = 0, + .nm_filename = nullptr, + .nm_register_func = Init, + .nm_modname = "events.emitter", + .nm_priv = ((void *)0), + .reserved = {0} +}; + +extern "C" __attribute__((constructor)) void RegisterModule(void) +{ + napi_module_register(&_module); +} +} // namespace AppExecFwk +} // namespace OHOS diff --git a/frameworks/napi/src/interops.cpp b/frameworks/napi/src/interops.cpp new file mode 100644 index 0000000..cfee953 --- /dev/null +++ b/frameworks/napi/src/interops.cpp @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2021-2022 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 "interops.h" + +namespace OHOS { +namespace AppExecFwk { +EmitterEnhancedApiRegister::EmitterEnhancedApiRegister() +{ + enhancedApi_ = std::make_shared(); +} + +void EmitterEnhancedApiRegister::Register(const EmitterEnhancedApi& api) +{ + enhancedApi_->JS_Off = api.JS_Off; + enhancedApi_->JS_Emit = api.JS_Emit; + enhancedApi_->JS_GetListenerCount = api.JS_GetListenerCount; + enhancedApi_->ProcessEvent = api.ProcessEvent; + isInit_.store(true, std::memory_order_release); +} + +bool EmitterEnhancedApiRegister::IsInit() const +{ + return isInit_.load(std::memory_order_acquire); +} + +std::shared_ptr EmitterEnhancedApiRegister::GetEnhancedApi() const +{ + return enhancedApi_; +} + +EmitterEnhancedApiRegister& GetEmitterEnhancedApiRegister() +{ + static EmitterEnhancedApiRegister emitterEnhancedApiRegister; + return emitterEnhancedApiRegister; +} +} +} \ No newline at end of file diff --git a/interfaces/inner_api/inner_event.h b/interfaces/inner_api/inner_event.h index 75dbe9f..c02045d 100644 --- a/interfaces/inner_api/inner_event.h +++ b/interfaces/inner_api/inner_event.h @@ -779,6 +779,22 @@ public: return isBarrier_; } + /** + * Mark the event sent by enhanced api. + */ + inline void SetIsEnhanced(const bool isEnhanced) + { + isEnhanced_ = isEnhanced; + } + + /** + * Check the event whether sent by enhanced api. + */ + inline bool IsEnhanced() + { + return isEnhanced_; + } + private: using SmartPtrDestructor = void (*)(void *); @@ -928,6 +944,8 @@ private: std::string ownerId_; int64_t delayTime_ = 0; + + bool isEnhanced_ = false; }; } // namespace AppExecFwk } // namespace OHOS -- Gitee