From 1392221025ed3860d77c25e615bdec1584f71f38 Mon Sep 17 00:00:00 2001 From: liangshenglin1 Date: Tue, 7 Sep 2021 19:53:22 +0800 Subject: [PATCH] implement ipc js interfaces Signed-off-by: liangshenglin1 --- interfaces/kits/js/declaration/BUILD.gn | 24 + .../kits/js/declaration/api/@ohos.rpc.d.ts | 452 ++++ interfaces/kits/js/napi/BUILD.gn | 64 + interfaces/kits/js/napi/rpc.js | 217 ++ .../src/napi/include/napi_message_option.h | 45 + .../src/napi/include/napi_message_parcel.h | 106 + .../src/napi/include/napi_remote_object.h | 91 + .../src/napi/src/napi_message_option.cpp | 106 + .../src/napi/src/napi_message_parcel.cpp | 1974 +++++++++++++++++ .../src/napi/src/napi_remote_object.cpp | 1405 ++++++++++++ .../src/napi/src/napi_rpc_native_module.cpp | 69 + ohos.build | 17 + 12 files changed, 4570 insertions(+) create mode 100644 interfaces/kits/js/declaration/BUILD.gn create mode 100644 interfaces/kits/js/declaration/api/@ohos.rpc.d.ts create mode 100644 interfaces/kits/js/napi/BUILD.gn create mode 100644 interfaces/kits/js/napi/rpc.js create mode 100644 ipc/native/src/napi/include/napi_message_option.h create mode 100644 ipc/native/src/napi/include/napi_message_parcel.h create mode 100644 ipc/native/src/napi/include/napi_remote_object.h create mode 100644 ipc/native/src/napi/src/napi_message_option.cpp create mode 100644 ipc/native/src/napi/src/napi_message_parcel.cpp create mode 100644 ipc/native/src/napi/src/napi_remote_object.cpp create mode 100644 ipc/native/src/napi/src/napi_rpc_native_module.cpp diff --git a/interfaces/kits/js/declaration/BUILD.gn b/interfaces/kits/js/declaration/BUILD.gn new file mode 100644 index 00000000..bbd7f75a --- /dev/null +++ b/interfaces/kits/js/declaration/BUILD.gn @@ -0,0 +1,24 @@ +# Copyright (C) 2021 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/ohos/rules.gni") +import("//build/ohos.gni") +import("//build/ohos/ace/ace.gni") + +ohos_copy("rpc_declaration") { + part_name = "ipc_js" + sources = [ "./api/@ohos.rpc.d.ts" ] + outputs = [ target_out_dir + "/$target_name/" ] + module_source_dir = target_out_dir + "/$target_name" + module_install_name = "" +} diff --git a/interfaces/kits/js/declaration/api/@ohos.rpc.d.ts b/interfaces/kits/js/declaration/api/@ohos.rpc.d.ts new file mode 100644 index 00000000..538bda03 --- /dev/null +++ b/interfaces/kits/js/declaration/api/@ohos.rpc.d.ts @@ -0,0 +1,452 @@ +declare namespace rpc { + class MessageParcel { + static create(): MessageParcel; + reclaim(): void; + writeRemoteObject(object: IRemoteObject): boolean; + readRemoteObject(): IRemoteObject; + writeInterfaceToken(token: string): boolean; + readInterfaceToken(): string; + getSize(): number; + getCapacity(): number; + setSize(size: number): boolean; + setCapacity(size: number): boolean; + getWritableBytes(): number; + getReadableBytes(): number; + getReadPosition(): number; + getWritePosition(): number; + rewindRead(pos: number): boolean; + rewindWrite(pos: number): boolean; + writeByte(val: number): boolean; + writeShort(val: number): boolean; + writeInt(val: number): boolean; + writeLong(val: number): boolean; + writeFloat(val: number): boolean; + writeDouble(val: number): boolean; + writeBoolean(val: boolean): boolean; + writeChar(val: number): boolean; + writeString(val: string): boolean; + writeSequenceable(val: Sequenceable): boolean; + writeByteArray(byteArray: number[]): boolean; + writeShortArray(shortArray: number[]): boolean; + writeIntArray(intArray: number[]): boolean; + writeLongArray(longArray: number[]): boolean; + writeFloatArray(floatArray: number[]): boolean; + writeDoubleArray(doubleArray: number[]): boolean; + writeBooleanArray(booleanArray: boolean[]): boolean; + writeCharArray(charArray: number[]): boolean; + writeStringArray(stringArray: string[]): boolean; + writeSequenceableArray(sequenceableArray: Sequenceable[]): boolean; + readByte(): number; + readShort(): number; + readInt(): number; + readLong(): number; + readFloat(): number; + readDouble(): number; + readBoolean(): boolean; + readChar(): number; + readString(): string; + readSequenceable(dataIn: Sequenceable) : boolean; + readByteArray(dataIn: number[]) : void; + readByteArray(): number[]; + readShortArray(dataIn: number[]) : void; + readShortArray(): number[]; + readIntArray(dataIn: number[]) : void; + readIntArray(): number[]; + readLongArray(dataIn: number[]) : void; + readLongArray(): number[]; + readFloatArray(dataIn: number[]) : void; + readFloatArray(): number[]; + readDoubleArray(dataIn: number[]) : void; + readDoubleArray(): number[]; + readBooleanArray(dataIn: boolean[]) : void; + readBooleanArray(): boolean[]; + readCharArray(dataIn: boolean[]) : void; + readCharArray(): boolean[]; + readStringArray(dataIn: string[]) : void; + readStringArray(): string[]; + } + + interface Sequenceable { + hasFileDescriptor(): boolean; + marshalling(dataOut: MessageParcel): boolean; + unmarshalling(dataIn: MessageParcel) : boolean; + } + + enum IRemoteObject { + /** + * Indicates the message code for a Ping operation. + */ + PING_TRANSACTION = ('_' << 24) | ('P' << 16) | ('N' << 8) | 'G', + + /** + * Indicates the message code for a dump operation. + */ + DUMP_TRANSACTION = ('_' << 24) | ('D' << 16) | ('M' << 8) | 'P', + + /** + * Indicates the message code for a transmission. + */ + INTERFACE_TRANSACTION = ('_' << 24) | ('N' << 16) | ('T' << 8) | 'F', + + /** + * Indicates the minimum value of a valid message code. + * + *

This constant is used to check the validity of an operation. + */ + MIN_TRANSACTION_ID = 0x1, + + /** + * Indicates the maximum value of a valid message code. + * + *

This constant is used to check the validity of an operation. + */ + MAX_TRANSACTION_ID = 0x00FFFFFF, + } + + interface IRemoteObject { + /** + * Queries the description of an interface. + * + *

A valid {@link IRemoteBroker} object is returned for an interface used by the service provider; + * {@code null} is returned for an interface used by the service user, + * indicating that the interface is not a local one. + * + * @param descriptor Indicates a string of the interface descriptor. + * @return Returns the {@link IRemoteBroker} object bound to the specified interface descriptor. + * @since 1 + */ + queryLocalInterface(descriptor: string): IRemoteBroker; + + /** + * Sends a {@link MessageParcel} message to the peer process in synchronous or asynchronous mode. + * + *

If asynchronous mode is set for {@code option}, a response is returned immediately. + * If synchronous mode is set for {@code option}, the interface will wait for a response from the peer process + * until the request times out. The user must prepare {@code reply} for receiving the execution result + * given by the peer process. + * + * @param code Indicates the message code, which is determined by both sides of the communication. + * If the interface is generated by the IDL tool, the message code is automatically generated by IDL. + * @param data Indicates the {@link MessageParcel} object sent to the peer process. + * @param reply Indicates the {@link MessageParcel} object returned by the peer process. + * @param option Indicates the synchronous or asynchronous mode to send messages. + * @return Returns {@code true} if the method is called successfully; returns {@code false} otherwise. + * @throws RemoteException Throws this exception if the method fails to be called. + * @since 1 + */ + sendRequest(code: number, data: MessageParcel, reply: MessageParcel, option: MessageOption): boolean; + + /** + * Registers a callback used to receive notifications of the death of a remote object. + * + *

This method is called if the remote object process matching the {@link RemoteProxy} object dies. + * + * @param recipient Indicates the callback to be registered. + * @param flags Indicates the flag of the death notification. + * @return Returns {@code true} if the callback is registered successfully; returns {@code false} otherwise. + * @since 1 + */ + addDeathRecipient(recipient: DeathRecipient, flags: number): boolean; + + /** + * Deregisters a callback used to receive notifications of the death of a remote object. + * + * @param recipient Indicates the callback to be deregistered. + * @param flags Indicates the flag of the death notification. + * @return Returns {@code true} if the callback is deregistered successfully; returns {@code false} otherwise. + * @since 1 + */ + removeDeathRecipient(recipient: DeathRecipient, flags: number): boolean; + + /** + * Obtains the interface descriptor of an object. + * + *

The interface descriptor is a character string. + * + * @return Returns the interface descriptor. + * @since 1 + */ + getInterfaceDescriptor(): string; + + /** + * Checks whether an object is dead. + * + * @return Returns {@code true} if the object is dead; returns {@code false} otherwise. + * @since 1 + */ + isObjectDead(): boolean; + } + + interface IRemoteBroker { + asObject(): IRemoteObject; + } + + interface DeathRecipient { + onRemoteDied(): void; + } + + enum MessageOption { + TF_SYNC = 0, + TF_ASYNC = 1, + TF_ACCEPT_FDS = 0x10, + TF_WAIT_TIME = 4, + MAX_WAIT_TIME = 3000, + } + + interface MessageOption { + flags: number; + waitTime: number; + } + + class RemoteObject implements IRemoteObject { + descriptor: string; + interface: IRemoteObject; + + /** + * Queries a remote object using an interface descriptor. + * + * @param descriptor Indicates the interface descriptor used to query the remote object. + * @return Returns the remote object matching the interface descriptor; returns null + * if no such remote object is found. + * @since 1 + */ + queryLocalInterface(interface: string): IRemoteObject; + + /** + * Queries an interface descriptor. + * + * @return Returns the interface descriptor. + * @since 1 + */ + getInterfaceDescriptor(): string; + + /** + * Sets an entry for receiving requests. + * + *

This method is implemented by the remote service provider. You need to override this method with + * your own service logic when you are using IPC. + * + * @param code Indicates the service request code sent from the peer end. + * @param data Indicates the {@link MessageParcel} object sent from the peer end. + * @param reply Indicates the response message object sent from the remote service. + * The local service writes the response data to the {@link MessageParcel} object. + * @param option Indicates whether the operation is synchronous or asynchronous. + * @return Returns {@code true} if the operation succeeds; returns {@code false} otherwise. + * @throws RemoteException Throws this exception if a remote service error occurs. + * @since 1 + */ + onRemoteRequest(code: number, data: MessageParcel, reply: MessageParcel, option: MessageOption): boolean; + + /** + * Sends a request to the peer object. + * + *

If the peer object and {@code RemoteObject} are on the same device, the request is sent by the IPC driver. + * If they are on different devices, the request is sent by the socket driver. + * + * @param code Indicates the message code of the request. + * @param data Indicates the {@link MessageParcel} object storing the data to be sent. + * @param reply Indicates the {@link MessageParcel} object receiving the response data. + * @param option Indicates a synchronous (default) or asynchronous request. + * @return Returns {@code true} if the operation succeeds; returns {@code false} otherwise. + * @since 1 + */ + sendRequest(code: number, data: MessageParcel, reply: MessageParcel, option: MessageOption): boolean; + + /** + * Obtains the PID of the {@link RemoteProxy} object. + * + * @return Returns the PID of the {@link RemoteProxy} object. + * @since 1 + */ + getCallingPid(): number; + + /** + * Obtains the UID of the {@link RemoteProxy} object. + * + * @return Returns the UID of the {@link RemoteProxy} object. + * @since 1 + */ + getCallingUid(): number; + + /** + * Modifies the description of the current {@code RemoteObject}. + * + *

This method is used to change the default descriptor specified during the creation of {@code RemoteObject}. + * + * @param localInterface Indicates the {@code RemoteObject} whose descriptor is to be changed. + * @param descriptor Indicates the new descriptor of the {@code RemoteObject}. + * @since 1 + */ + attachLocalInterface(localInterface: IRemoteBroker, descriptor: string): void; + } + + class RemoteProxy implements IRemoteObject { + /** + * Queries a local interface with a specified descriptor. + * + * @param descriptor Indicates the descriptor of the interface to query. + * @return Returns null by default, indicating a proxy interface. + * @since 1 + */ + queryLocalInterface(interface: string): IRemoteObject; + + /** + * Registers a callback used to receive death notifications of a remote object. + * + * @param recipient Indicates the callback to be registered. + * @param flags Indicates the flag of the death notification. This is a reserved parameter. Set it to {@code 0}. + * @return Returns {@code true} if the callback is registered successfully; returns {@code false} otherwise. + * @since 1 + */ + addDeathRecipient(recipient: DeathRecipient, flags: number): boolean; + + /** + * Deregisters a callback used to receive death notifications of a remote object. + * + * @param recipient Indicates the callback to be deregistered. + * @param flags Indicates the flag of the death notification. This is a reserved parameter. Set it to {@code 0}. + * @return Returns {@code true} if the callback is deregistered successfully; returns {@code false} otherwise. + * @since 1 + */ + removeDeathRecipient(recipient: DeathRecipient, flags: number): boolean; + + /** + * Queries the interface descriptor of remote object. + * + * @return Returns the interface descriptor. + * @since 1 + */ + getInterfaceDescriptor(): string; + + /** + * Sends a request to the peer object. + * + *

If the peer object and {@code RemoteProxy} are on the same device, the request is sent by the IPC driver. + * If they are on different devices, the request is sent by the socket driver. + * + * @param code Indicates the message code of the request. + * @param data Indicates the {@link MessageParcel} object storing the data to be sent. + * @param reply Indicates the {@link MessageParcel} object receiving the response data. + * @param option Indicates a synchronous (default) or asynchronous request. + * @return Returns {@code true} if the operation succeeds; returns {@code false} otherwise. + * @throws RemoteException Throws this exception if a remote object exception occurs. + * @since 1 + */ + sendRequest(code: number, data: MessageParcel, reply: MessageParcel, option: MessageOption): boolean; + + /** + * Checks whether the {@code RemoteObject} corresponding to a {@code RemoteProxy} is dead. + * + * @return Returns {@code true} if the {@code RemoteObject} is dead; returns {@code false} otherwise. + * @since 1 + */ + isObjectDead(): boolean; + } + + class IPCSkeleton { + /** + * Obtains a local {@link IRemoteObject} reference of a registered service. + * + *

This method is static. + * + * @return Returns an {@link IRemoteObject} reference of the registered service. + * @since 1 + */ + static getContextObject(): IRemoteObject; + + /** + * Obtains the PID of a proxy. + * + *

This method is static. The PID is a positive integer during the communication between + * the {@link RemoteProxy} object and {@link RemoteObject} object, and resumes to {@code 0} + * when the communication ends. If this method is called from the {@link RemoteProxy} object, + * {@code 0} is returned; if this method is called from the {@link RemoteObject} object, + * the PID of the corresponding {@link RemoteProxy} object is returned. + * + * @return Returns the PID of the proxy. + * @since 1 + */ + static getCallingPid(): number; + + /** + * Obtains the UID of a proxy. + * + *

This method is static. The UID is a positive integer during the communication between + * the {@link RemoteProxy} object and {@link RemoteObject} object, and resumes to {@code 0} + * when the communication ends. If this method is called from the {@link RemoteProxy} object, + * {@code 0} is returned; if this method is called from the {@link RemoteObject} object, + * the UID of the corresponding {@link RemoteProxy} object is returned. + * + * @return Returns the UID of the proxy. + * @since 1 + */ + static getCallingUid(): number; + + /** + * Obtains the ID of the device where the peer process resides. + * + *

This method is static. + * + * @return Returns the ID of the device where the peer process resides. + * @since 1 + */ + static getCallingDeviceID(): string; + + /** + * Obtains the ID of the local device. + * + *

This method is static. + * + * @return Returns the ID of the local device. + * @since 1 + */ + static getLocalDeviceID(): string; + + /** + * Checks whether a call is made on the same device. + * + *

This method is static. + * + * @return Returns {@code true} if the call is made on the same device; returns {@code false} otherwise. + * @since 1 + */ + static isLocalCalling(): boolean; + + /** + * Flushes all pending commands from a specified {@link RemoteProxy} to the corresponding {@link RemoteObject}. + * + *

This method is static. You are advised to call this method before performing any time-sensitive operations. + * + * @param object Indicates the specified {@link RemoteProxy}. + * @return Returns {@code 0} if the operation succeeds; returns an error code if the input object is empty + * or {@link RemoteObject}, or the operation fails. + * @since 1 + */ + static flushCommands(object: IRemoteObject): number; + + /** + * Replaces the UID and PID of the remote user with those of the local user. + * + *

This method is static. It can be used in scenarios like authentication. + * + * @return Returns a string containing the UID and PID of the remote user. + * @since 1 + */ + static resetCallingIdentity(): string; + + /** + * Restores the UID and PID to those of the remote user. + * + *

This method is static. It is usually called after {@code resetCallingIdentity} is used + * and requires the UID and PID of the remote user returned by {@code resetCallingIdentity}. + * + * @param identity Indicates the string containing the UID and PID of the remote user, + * which is returned by {@code resetCallingIdentity}. + * @return Returns {@code true} if the operation succeeds; returns {@code false} otherwise. + * @since 1 + */ + static setCallingIdentity(identity: string): boolean; + } +} + +export default rpc; diff --git a/interfaces/kits/js/napi/BUILD.gn b/interfaces/kits/js/napi/BUILD.gn new file mode 100644 index 00000000..fbca183b --- /dev/null +++ b/interfaces/kits/js/napi/BUILD.gn @@ -0,0 +1,64 @@ +# Copyright (c) 2021 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") + +SUBSYSTEM_DIR = "//foundation/communication/ipc" + +base_output_path = get_label_info(":rpc_js", "target_out_dir") +ipc_js_obj_path = base_output_path + "/rpc.o" + +gen_js_obj("rpc_js") { + input = "//foundation/communication/ipc/interfaces/kits/js/napi/rpc.js" + output = ipc_js_obj_path +} + +config("rpc_public_config") { + visibility = [ ":*" ] + include_dirs = [ "$SUBSYSTEM_DIR/ipc/native/src/napi/include" ] +} + +ohos_shared_library("rpc") { + include_dirs = [ + "$SUBSYSTEM_DIR/utils/include", + "//foundation/ace/napi/interfaces/kits", + "//utils/system/safwk/native/include", + ] + public_configs = [ ":rpc_public_config" ] + + sources = [ + "$SUBSYSTEM_DIR/ipc/native/src/napi/src/napi_message_option.cpp", + "$SUBSYSTEM_DIR/ipc/native/src/napi/src/napi_message_parcel.cpp", + "$SUBSYSTEM_DIR/ipc/native/src/napi/src/napi_remote_object.cpp", + "$SUBSYSTEM_DIR/ipc/native/src/napi/src/napi_rpc_native_module.cpp", + ] + + deps = [ + ":rpc_js", + "//foundation/ace/napi:ace_napi", + "//third_party/libuv:uv_static", + "//utils/native/base:utils", + ] + + external_deps = [ + "hiviewdfx_hilog_native:libhilog", + "ipc:ipc_core", + "safwk:system_ability_fwk", + "samgr_L2:samgr_proxy", + ] + + relative_install_dir = "module" + + subsystem_name = "communication" + part_name = "ipc_js" +} diff --git a/interfaces/kits/js/napi/rpc.js b/interfaces/kits/js/napi/rpc.js new file mode 100644 index 00000000..f49e33e8 --- /dev/null +++ b/interfaces/kits/js/napi/rpc.js @@ -0,0 +1,217 @@ +const rpcSo = requireInternal("rpc"); + +// 定义异常类型常量 +const EXC_INSECURITY = -1; +const EXC_ILLEGAL_ARGUMENT = -3; +const EXC_NULL_POINTER = -4; +const EXC_ILLEGAL_STATE = -5; +const EXC_UNSUPPORTED_OPERATION = -7; +const EXC_INDEX_OUTOF_BOUNDS = -10; +const EXC_NEGATIVE_ARRAY_SIZE = -11; +const EXC_ARRAY_STORE = -12; +const EXC_CLASS_CAST = -13; +const EXC_PARCEL_CAPACITY_ERROR = -14; +const EXC_REMOTE_TRANSACTION_FAILED = -200; + +let MessageParcel = rpcSo.MessageParcel; +let IPCSkeleton = rpcSo.IPCSkeleton; +let RemoteObject = rpcSo.RemoteObject; +let RemoteProxy = rpcSo.RemoteProxy; +let MessageOption = rpcSo.MessageOption; + +class Exception { + message; + constructor(msg) { + this.message = msg; + } + + getMessage() { + return this.message; + } +} + +class NullPointerException extends Exception {} +class SecurityException extends Exception {} +class IllegalArgumentException extends Exception {} +class IllegalStateException extends Exception {} +class UnsupportedOperationException extends Exception {} +class IndexOutOfBoundsException extends Exception {} +class NegativeArraySizeException extends Exception {} +class ArrayStoreException extends Exception {} +class ClassCastException extends Exception {} +class RemoteException extends Exception {} +class ParcelException extends Exception {} +class RuntimeException extends Exception {} + + +// MessageParcel的附加功能 +MessageParcel.prototype.createException = function(code, msg) { + switch (code) { + case EXC_INSECURITY: { + return new SecurityException(msg); + } + case EXC_ILLEGAL_ARGUMENT: { + return new IllegalArgumentException(msg); + } + case EXC_NULL_POINTER: { + return new NullPointerException(msg); + } + case EXC_ILLEGAL_STATE: { + return new IllegalStateException(msg); + } + case EXC_UNSUPPORTED_OPERATION: { + return new UnsupportedOperationException(msg); + } + case EXC_INDEX_OUTOF_BOUNDS: { + return new IndexOutOfBoundsException(msg); + } + case EXC_NEGATIVE_ARRAY_SIZE: { + return new NegativeArraySizeException(msg); + } + case EXC_ARRAY_STORE: { + return new ArrayStoreException(msg); + } + case EXC_CLASS_CAST: { + return new ClassCastException(msg); + } + case EXC_REMOTE_TRANSACTION_FAILED: { + return new RemoteException(msg); + } + case EXC_PARCEL_CAPACITY_ERROR: { + return new ParcelException(msg); + } + default: { + return new RuntimeException("Unknown exception code: " + code + " msg " + msg); + } + } +} + +MessageParcel.prototype.writeException = function(exception) { + let code = 0; + if (exception instanceof SecurityException) { + code = EXC_INSECURITY; + } else if (exception instanceof IllegalArgumentException) { + code = EXC_ILLEGAL_ARGUMENT; + } else if (exception instanceof NullPointerException) { + code = EXC_NULL_POINTER; + } else if (exception instanceof IllegalStateException) { + code = EXC_ILLEGAL_STATE; + } else if (exception instanceof UnsupportedOperationException) { + code = EXC_UNSUPPORTED_OPERATION; + } else if (exception instanceof IndexOutOfBoundsException) { + code = EXC_INDEX_OUTOF_BOUNDS; + } else if (exception instanceof NegativeArraySizeException) { + code = EXC_NEGATIVE_ARRAY_SIZE; + } else if (exception instanceof ArrayStoreException) { + code = EXC_ARRAY_STORE; + } else if (exception instanceof ClassCastException) { + code = EXC_CLASS_CAST; + } else if (exception instanceof RemoteException) { + code = EXC_REMOTE_TRANSACTION_FAILED; + } else if (exception instanceof ParcelException) { + code = EXC_PARCEL_CAPACITY_ERROR; + } else { + code = 0; + } + // Todo + this.writeInt(code); + if (code === 0) { + if (exception instanceof RuntimeException) { + throw new RuntimeException(exception.getMessage()); + } + throw new RuntimeException(exception.getMessage()); + } + // TODO + this.writeString(exception.getMessage()); +} + +MessageParcel.prototype.writeNoException = function() { + this.writeInt(0); +} + +MessageParcel.prototype.readException = function() { + let code = this.readInt(); + if (code === 0) { + return; + } + let msg = this.readString(); + let exception = this.createException(code, msg); + return exception; +} + +MessageParcel.prototype.createRemoteObjectArray = function() { + let num = this.readInt(); + if (num <= 0) { + return null; + } + let list = new Array(num); + for (let i = 0; i < num; i++) { + list[i] = this.readRemoteObject(); + } + return list; +} + +MessageParcel.prototype.writeRemoteObjectArray = function(objects) { + if (objects === null || objects.length <= 0 ) { + this.writeInt(-1); + return false; + } + + let num = objects.length; + this.writeInt(num); + for (let i = 0; i < num; i ++) { + this.writeRemoteObject(objects[i]); + } + return true; +} + +// 传入的对象是一个数组[] +MessageParcel.prototype.readRemoteObjectArray = function(objects) { + if (objects === null) { + return; + } + + let num = this.readInt(); + if (num !== objects.length) { + return; + } + for (let i = 0; i < num; i ++) { + objects[i] = this.readRemoteObject(); + } +} + +// 定义RemoteObject中N_API中不存在的方法 +// proxy实现,stub端不实现 +RemoteObject.prototype.addDeathRecipient = function(recipient, flags) { + return false; +} + +// proxy实现,stub端不实现 +RemoteObject.prototype.removeDeathRecipient = function(recipient, flags) { + return false; +} + +// proxy实现,stub端不实现 +RemoteObject.prototype.isObjectDead = function() { + return false; +} + +export default { + MessageParcel: MessageParcel, + IPCSkeleton: IPCSkeleton, + RemoteObject: RemoteObject, + RemoteProxy: RemoteProxy, + MessageOption: MessageOption, + NullPointerException: NullPointerException, + SecurityException: SecurityException, + IllegalArgumentException: IllegalArgumentException, + IllegalStateException: IllegalStateException, + UnsupportedOperationException: UnsupportedOperationException, + IndexOutOfBoundsException: IndexOutOfBoundsException, + NegativeArraySizeException: NegativeArraySizeException, + ArrayStoreException: ArrayStoreException, + ClassCastException: ClassCastException, + RemoteException: RemoteException, + ParcelException: ParcelException, + RuntimeException: RuntimeException +} \ No newline at end of file diff --git a/ipc/native/src/napi/include/napi_message_option.h b/ipc/native/src/napi/include/napi_message_option.h new file mode 100644 index 00000000..f03e8e60 --- /dev/null +++ b/ipc/native/src/napi/include/napi_message_option.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2021 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 NAPI_IPC_OHOS_MESSAGE_OPTION_H +#define NAPI_IPC_OHOS_MESSAGE_OPTION_H + +#include "napi/native_api.h" +#include "napi/native_common.h" +#include "napi/native_node_api.h" +#include "message_option.h" + +namespace OHOS { +/* + * Get flags field from ohos.rpc.MessageOption. + */ +napi_value NAPI_ohos_rpc_message_option_get_flags(napi_env env, napi_callback_info info); + +/* + * Set flags to ohos.rpc.MessageOption + */ +napi_value NAPI_ohos_rpc_message_option_set_flags(napi_env env, napi_callback_info info); + +/* + * Get wait time field from ohos.rpc.MessageOption. + */ +napi_value NAPI_ohos_rpc_message_option_get_waitTime(napi_env env, napi_callback_info info); + +/* + * Set wait time to ohos.rpc.MessageOption + */ +napi_value NAPI_ohos_rpc_message_option_set_waitTime(napi_env env, napi_callback_info info); +} // namespace OHOS +#endif // NAPI_IPC_OHOS_MESSAGE_OPTION_H \ No newline at end of file diff --git a/ipc/native/src/napi/include/napi_message_parcel.h b/ipc/native/src/napi/include/napi_message_parcel.h new file mode 100644 index 00000000..5275b481 --- /dev/null +++ b/ipc/native/src/napi/include/napi_message_parcel.h @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2021 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 NAPI_IPC_OHOS_MESSAGE_PARCEL_H +#define NAPI_IPC_OHOS_MESSAGE_PARCEL_H + +#include "securec.h" +#include "napi/native_api.h" +#include "napi/native_common.h" +#include "napi/native_node_api.h" +#include "message_parcel.h" +#include "ipc_skeleton.h" + +namespace OHOS { +class NAPI_MessageParcel { +public: + NAPI_MessageParcel(napi_env env, napi_value thisVar, MessageParcel *parcel); + virtual ~NAPI_MessageParcel(); + MessageParcel *getMessageParcel(); + static napi_value Export(napi_env env, napi_value exports); + static napi_ref getParcelConsRef(); +private: + // Napi methods and properties + static napi_value JS_Constructor(napi_env env, napi_callback_info cbinfo); + static napi_value JS_create(napi_env env, napi_callback_info cbinfo); + static napi_value JS_reclaim(napi_env env, napi_callback_info cbinfo); + static napi_value JS_writeRemoteObject(napi_env env, napi_callback_info cbinfo); + static napi_value JS_readRemoteObject(napi_env env, napi_callback_info cbinfo); + static napi_value JS_writeInterfaceToken(napi_env env, napi_callback_info cbinfo); + static napi_value JS_readInterfaceToken(napi_env env, napi_callback_info cbinfo); + static napi_value JS_getSize(napi_env env, napi_callback_info cbinfo); + static napi_value JS_getCapacity(napi_env env, napi_callback_info cbinfo); + static napi_value JS_setSize(napi_env env, napi_callback_info cbinfo); + static napi_value JS_setCapacity(napi_env env, napi_callback_info cbinfo); + static napi_value JS_getWritableBytes(napi_env env, napi_callback_info cbinfo); + static napi_value JS_getReadableBytes(napi_env env, napi_callback_info cbinfo); + static napi_value JS_getReadPosition(napi_env env, napi_callback_info cbinfo); + static napi_value JS_getWritePosition(napi_env env, napi_callback_info cbinfo); + static napi_value JS_rewindWrite(napi_env env, napi_callback_info cbinfo); + static napi_value JS_rewindRead(napi_env env, napi_callback_info cbinfo); + + static napi_value JS_writeByte(napi_env env, napi_callback_info cbinfo); + static napi_value JS_writeShort(napi_env env, napi_callback_info cbinfo); + static napi_value JS_writeInt(napi_env env, napi_callback_info cbinfo); + static napi_value JS_writeLong(napi_env env, napi_callback_info cbinfo); + static napi_value JS_writeFloat(napi_env env, napi_callback_info cbinfo); + static napi_value JS_writeDouble(napi_env env, napi_callback_info cbinfo); + static napi_value JS_writeBoolean(napi_env env, napi_callback_info cbinfo); + static napi_value JS_writeChar(napi_env env, napi_callback_info cbinfo); + static napi_value JS_writeStringWithLength(napi_env env, napi_callback_info cbinfo); + static napi_value JS_writeString(napi_env env, napi_callback_info cbinfo); + static napi_value JS_writeSequenceable(napi_env env, napi_callback_info cbinfo); + static napi_value JS_writeByteArray(napi_env env, napi_callback_info cbinfo); + static napi_value JS_writeShortArray(napi_env env, napi_callback_info cbinfo); + static napi_value JS_writeIntArray(napi_env env, napi_callback_info cbinfo); + static napi_value JS_writeLongArray(napi_env env, napi_callback_info cbinfo); + static napi_value JS_writeFloatArray(napi_env env, napi_callback_info cbinfo); + static napi_value JS_writeDoubleArray(napi_env env, napi_callback_info cbinfo); + static napi_value JS_writeBooleanArray(napi_env env, napi_callback_info cbinfo); + static napi_value JS_writeCharArray(napi_env env, napi_callback_info cbinfo); + static napi_value JS_writeStringArray(napi_env env, napi_callback_info cbinfo); + static napi_value JS_writeSequenceableArray(napi_env env, napi_callback_info cbinfo); + + static napi_value JS_readByte(napi_env env, napi_callback_info cbinfo); + static napi_value JS_readShort(napi_env env, napi_callback_info cbinfo); + static napi_value JS_readInt(napi_env env, napi_callback_info cbinfo); + static napi_value JS_readLong(napi_env env, napi_callback_info cbinfo); + static napi_value JS_readFloat(napi_env env, napi_callback_info cbinfo); + static napi_value JS_readDouble(napi_env env, napi_callback_info cbinfo); + static napi_value JS_readBoolean(napi_env env, napi_callback_info cbinfo); + static napi_value JS_readChar(napi_env env, napi_callback_info cbinfo); + static napi_value JS_readString(napi_env env, napi_callback_info cbinfo); + static napi_value JS_readSequenceable(napi_env env, napi_callback_info cbinfo); + static napi_value JS_readByteArray(napi_env env, napi_callback_info cbinfo); + static napi_value JS_readShortArray(napi_env env, napi_callback_info cbinfo); + static napi_value JS_readIntArray(napi_env env, napi_callback_info cbinfo); + static napi_value JS_readLongArray(napi_env env, napi_callback_info cbinfo); + static napi_value JS_readFloatArray(napi_env env, napi_callback_info cbinfo); + static napi_value JS_readDoubleArray(napi_env env, napi_callback_info cbinfo); + static napi_value JS_readBooleanArray(napi_env env, napi_callback_info cbinfo); + static napi_value JS_readCharArray(napi_env env, napi_callback_info cbinfo); + static napi_value JS_readStringArray(napi_env env, napi_callback_info cbinfo); + + napi_env env_ = nullptr; + MessageParcel *nativeParcel_ = nullptr; + size_t maxCapacityToWrite_; + bool owner; +}; +namespace { + napi_value g_messageParcelConstructor = nullptr; + napi_ref g_messageParcelConsRef = nullptr; +} +} // namespace OHOS +#endif // NAPI_IPC_OHOS_MESSAGE_PARCEL_H diff --git a/ipc/native/src/napi/include/napi_remote_object.h b/ipc/native/src/napi/include/napi_remote_object.h new file mode 100644 index 00000000..fa95bfa6 --- /dev/null +++ b/ipc/native/src/napi/include/napi_remote_object.h @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2021 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 NAPI_IPC_OHOS_REMOTE_OBJECT_H +#define NAPI_IPC_OHOS_REMOTE_OBJECT_H + +#include "napi/native_common.h" +#include "napi/native_node_api.h" +#include "refbase.h" +#include "iremote_object.h" +#include "system_ability_manager_proxy.h" +#include "iservice_registry.h" + +namespace OHOS { +EXTERN_C_START + napi_value NAPIIPCSkeletonExport(napi_env env, napi_value exports); + napi_value NAPIRemoteProxyExport(napi_env env, napi_value exports); + napi_value NAPIRemoteObjectExport(napi_env env, napi_value exports); + napi_value NAPIMessageOptionExport(napi_env env, napi_value exports); +EXTERN_C_END + + // IPCSkeleton napi methods + // test for get ability + napi_value N_API_GetLocalAbility(napi_env env, napi_callback_info info); + + napi_value NAPI_IPCSkeleton_getContextObject(napi_env env, napi_callback_info info); + + napi_value NAPI_IPCSkeleton_getCallingPid(napi_env env, napi_callback_info info); + + napi_value NAPI_IPCSkeleton_getCallingUid(napi_env env, napi_callback_info info); + + napi_value NAPI_IPCSkeleton_getCallingDeviceID(napi_env env, napi_callback_info info); + + napi_value NAPI_IPCSkeleton_getLocalDeviceID(napi_env env, napi_callback_info info); + + napi_value NAPI_IPCSkeleton_isLocalCalling(napi_env env, napi_callback_info info); + + napi_value NAPI_IPCSkeleton_flushCommands(napi_env env, napi_callback_info info); + + napi_value NAPI_IPCSkeleton_resetCallingIdentity(napi_env env, napi_callback_info info); + + napi_value NAPI_IPCSkeleton_setCallingIdentity(napi_env env, napi_callback_info info); + + // RemoteObject napi methods + napi_value NAPI_RemoteObject_getCallingPid(napi_env env, napi_callback_info info); + + napi_value NAPI_RemoteObject_getCallingUid(napi_env env, napi_callback_info info); + + // RemoteProxy napi methods + napi_value SendRequestPromise(napi_env env, sptr target, uint32_t code, MessageParcel& data, MessageParcel& reply, MessageOption& option); + + napi_value NAPI_RemoteProxy_sendRequest(napi_env env, napi_callback_info info); + + napi_value NAPI_RemoteProxy_addDeathRecipient(napi_env env, napi_callback_info info); + + napi_value NAPI_RemoteProxy_removeDeathRecipient(napi_env env, napi_callback_info info); + + napi_value NAPI_RemoteProxy_getInterfaceDescriptor(napi_env env, napi_callback_info info); + + napi_value NAPI_RemoteProxy_isObjectDead(napi_env env, napi_callback_info info); + + napi_value NAPI_RemoteProxy_getHandle(napi_env env, napi_callback_info info); + + sptr NAPI_ohos_rpc_getNativeRemoteObject(napi_env env, napi_value object); + + napi_value NAPI_ohos_rpc_CreateJsRemoteObject(napi_env env, const sptr target); + + struct SendRequestParam { + sptr target; + uint32_t code; + MessageParcel& data; + MessageParcel& reply; + MessageOption& option; + napi_async_work asyncWork; + napi_deferred deferred; + int errCode; + }; +} // namespace OHOS +#endif // NAPI_IPC_OHOS_REMOTE_OBJECT_H \ No newline at end of file diff --git a/ipc/native/src/napi/src/napi_message_option.cpp b/ipc/native/src/napi/src/napi_message_option.cpp new file mode 100644 index 00000000..df43fff5 --- /dev/null +++ b/ipc/native/src/napi/src/napi_message_option.cpp @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2021 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_message_option.h" +#include "ipc_debug.h" +#include "log_tags.h" + +namespace OHOS { +/* + * Get flags field from ohos.rpc.MessageOption. + */ +napi_value NAPI_ohos_rpc_message_option_get_flags(napi_env env, napi_callback_info info) +{ + napi_value thisVar = nullptr; + napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr); + NAPI_ASSERT(env, thisVar != nullptr, "failed to get js message option object"); + MessageOption *option = nullptr; + napi_status status = napi_unwrap(env, thisVar, (void**)&option); + NAPI_ASSERT(env, option != nullptr, "failed to get native message option"); + int flags = option->GetFlags(); + napi_value result = nullptr; + status = napi_create_int32(env, flags, &result); + NAPI_ASSERT(env, status == napi_ok, "failed to create int32 value"); + return result; +} + +/* + * Set flags to ohos.rpc.MessageOption + */ +napi_value NAPI_ohos_rpc_message_option_set_flags(napi_env env, napi_callback_info info) +{ + napi_value thisVar = nullptr; + size_t argc; + napi_value argv[1] = { 0 }; + napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr); + NAPI_ASSERT(env, thisVar != nullptr, "failed to get js message option object"); + napi_valuetype valueType; + napi_typeof(env, argv[0], &valueType); + NAPI_ASSERT(env, valueType == napi_number, "type mismatch for parameter 1"); + int32_t flags = 0; + napi_status status = napi_get_value_int32(env, argv[0], &flags); + NAPI_ASSERT(env, status == napi_ok, "failed to get int32 value"); + MessageOption *option = nullptr; + status = napi_unwrap(env, thisVar, (void**)&option); + NAPI_ASSERT(env, option != nullptr, "failed to get native message option"); + option->SetFlags(flags); + napi_value result = nullptr; + napi_get_undefined(env, &result); + return result; +} + +/* + * Get wait time field from ohos.rpc.MessageOption. + */ +napi_value NAPI_ohos_rpc_message_option_get_waitTime(napi_env env, napi_callback_info info) +{ + napi_value thisVar = nullptr; + napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr); + NAPI_ASSERT(env, thisVar != nullptr, "failed to get js message option object"); + MessageOption *option = nullptr; + napi_status status = napi_unwrap(env, thisVar, (void**)&option); + NAPI_ASSERT(env, option != nullptr, "failed to get native message option"); + int flags = option->GetWaitTime(); + napi_value result = nullptr; + status = napi_create_int32(env, flags, &result); + NAPI_ASSERT(env, status == napi_ok, "failed to create int32 value"); + return result; +} + +/* + * Set wait time to ohos.rpc.MessageOption + */ +napi_value NAPI_ohos_rpc_message_option_set_waitTime(napi_env env, napi_callback_info info) +{ + napi_value thisVar = nullptr; + size_t argc; + napi_value argv[1] = { 0 }; + napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr); + NAPI_ASSERT(env, thisVar != nullptr, "failed to get js message option object"); + napi_valuetype valueType; + napi_typeof(env, argv[0], &valueType); + NAPI_ASSERT(env, valueType == napi_number, "type mismatch for parameter 1"); + int32_t waittime = 0; + napi_status status = napi_get_value_int32(env, argv[0], &waittime); + NAPI_ASSERT(env, status == napi_ok, "failed to get int32 value"); + MessageOption *option = nullptr; + status = napi_unwrap(env, thisVar, (void**)&option); + NAPI_ASSERT(env, option != nullptr, "failed to get native message option"); + option->SetFlags(waittime); + napi_value result = nullptr; + napi_get_undefined(env, &result); + return result; +} +} // namespace OHOS \ No newline at end of file diff --git a/ipc/native/src/napi/src/napi_message_parcel.cpp b/ipc/native/src/napi/src/napi_message_parcel.cpp new file mode 100644 index 00000000..76490952 --- /dev/null +++ b/ipc/native/src/napi/src/napi_message_parcel.cpp @@ -0,0 +1,1974 @@ +/* + * Copyright (c) 2021 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_message_parcel.h" +#include +#include +#include +#include +#include "napi_remote_object.h" +#include "hilog/log.h" +#include "log_tags.h" +#include "string_ex.h" + + +namespace OHOS { +using namespace OHOS::HiviewDFX; +constexpr size_t MAX_CAPACITY_TO_WRITE = 200 * 1024; +constexpr size_t BYTE_SIZE_32 = 4; +constexpr size_t BYTE_SIZE_64 = 8; + +static constexpr OHOS::HiviewDFX::HiLogLabel LOG_LABEL = { LOG_CORE, LOG_ID_IPC, "napi_messageParcel" }; +#ifndef TITLE +#define TITLE __PRETTY_FUNCTION__ +#endif +#define DBINDER_LOGE(fmt, args...) \ + (void)OHOS::HiviewDFX::HiLog::Error(LOG_LABEL, "%{public}s %{public}d: " fmt, TITLE, __LINE__, ##args) +#define DBINDER_LOGI(fmt, args...) \ + (void)OHOS::HiviewDFX::HiLog::Info(LOG_LABEL, "%{public}s %{public}d: " fmt, TITLE, __LINE__, ##args) + +#define CHECK_WRITE_CAPACITY(env, lenToWrite, napiParcel) \ + size_t cap = napiParcel->maxCapacityToWrite_ - napiParcel->nativeParcel_->GetWritePosition(); \ + if (cap < lenToWrite) { \ + DBINDER_LOGI("No enough capacity to write"); \ + napi_throw_range_error(env, nullptr, "No enough capacity to write"); \ + } + +#define REWIND_IF_WRITE_CHECK_FAIL(env, lenToWrite, pos, napiParcel) \ + size_t cap = napiParcel->maxCapacityToWrite_ - napiParcel->nativeParcel_->GetWritePosition(); \ + if (cap < lenToWrite) { \ + DBINDER_LOGI("No enough capacity to write"); \ + napiParcel->nativeParcel_->RewindWrite(pos); \ + napi_throw_range_error(env, nullptr, "No enough capacity to write"); \ + } + +#define CHECK_READ_LENGTH(env, arrayLength, typeSize, napiParcel) \ + size_t remainSize = napiParcel->nativeParcel_->GetDataSize() - napiParcel->nativeParcel_->GetReadPosition(); \ + if ((arrayLength < 0) || (arrayLength > remainSize) || ((arrayLength * typeSize) > remainSize)) { \ + DBINDER_LOGI("No enough data to read"); \ + napi_throw_range_error(env, nullptr, "No enough data to read"); \ + } + +NAPI_MessageParcel::NAPI_MessageParcel(napi_env env, napi_value thisVar, MessageParcel *parcel) +{ + DBINDER_LOGI("NAPI_MessageParcel::constructor"); + env_ = env; + maxCapacityToWrite_ = MAX_CAPACITY_TO_WRITE; + // do NOT reference js parcel here + if (parcel == nullptr) { + nativeParcel_ = new MessageParcel(); + owner = true; + } else { + nativeParcel_ = parcel; + owner = false; + } +} + +NAPI_MessageParcel::~NAPI_MessageParcel() +{ + DBINDER_LOGI("NAPI_MessageParcel::Destructor"); + if (owner) { + delete nativeParcel_; + } + nativeParcel_ = nullptr; + env_ = nullptr; +} + +MessageParcel *NAPI_MessageParcel::getMessageParcel() +{ + return nativeParcel_; +} + +napi_value NAPI_MessageParcel::JS_writeByte(napi_env env, napi_callback_info info) +{ + size_t argc = 1; + napi_value argv[1] = {0}; + napi_value thisVar = nullptr; + napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr); + NAPI_ASSERT(env, argc == 1, "requires 1 parameter"); + + napi_valuetype valueType; + napi_typeof(env, argv[0], &valueType); + NAPI_ASSERT(env, valueType == napi_number, "type mismatch for parameter 1"); + + int32_t value = 0; + napi_get_value_int32(env, argv[0], &value); + + NAPI_MessageParcel *napiParcel = nullptr; + napi_unwrap(env, thisVar, (void **)&napiParcel); + NAPI_ASSERT(env, napiParcel != nullptr, "napiParcel is null"); + CHECK_WRITE_CAPACITY(env, BYTE_SIZE_32, napiParcel); + bool result = napiParcel->nativeParcel_->WriteInt8(static_cast(value)); + napi_value napiValue = nullptr; + NAPI_CALL(env, napi_get_boolean(env, result, &napiValue)); + return napiValue; +} + +napi_value NAPI_MessageParcel::JS_writeShort(napi_env env, napi_callback_info info) +{ + size_t argc = 1; + napi_value argv[1] = {0}; + napi_value thisVar = nullptr; + napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr); + NAPI_ASSERT(env, argc == 1, "requires 1 parameter"); + + napi_valuetype valueType; + napi_typeof(env, argv[0], &valueType); + NAPI_ASSERT(env, valueType == napi_number, "type mismatch for parameter 1"); + + int32_t value = 0; + napi_get_value_int32(env, argv[0], &value); + + NAPI_MessageParcel *napiParcel = nullptr; + napi_unwrap(env, thisVar, (void **)&napiParcel); + NAPI_ASSERT(env, napiParcel != nullptr, "napiParcel is null"); + CHECK_WRITE_CAPACITY(env, BYTE_SIZE_32, napiParcel); + bool result = napiParcel->nativeParcel_->WriteInt16(static_cast(value)); + napi_value napiValue = nullptr; + NAPI_CALL(env, napi_get_boolean(env, result, &napiValue)); + return napiValue; +} + +napi_value NAPI_MessageParcel::JS_writeInt(napi_env env, napi_callback_info info) +{ + size_t argc = 1; + napi_value argv[1] = {0}; + napi_value thisVar = nullptr; + napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr); + NAPI_ASSERT(env, argc == 1, "requires 1 parameter"); + + napi_valuetype valueType; + napi_typeof(env, argv[0], &valueType); + NAPI_ASSERT(env, valueType == napi_number, "type mismatch for parameter 1"); + + int32_t value = 0; + napi_get_value_int32(env, argv[0], &value); + + NAPI_MessageParcel *napiParcel = nullptr; + napi_unwrap(env, thisVar, (void **)&napiParcel); + NAPI_ASSERT(env, napiParcel != nullptr, "napiParcel is null"); + CHECK_WRITE_CAPACITY(env, BYTE_SIZE_32, napiParcel); + bool result = napiParcel->nativeParcel_->WriteInt32(value); + napi_value napiValue = nullptr; + NAPI_CALL(env, napi_get_boolean(env, result, &napiValue)); + return napiValue; +} + +napi_value NAPI_MessageParcel::JS_writeLong(napi_env env, napi_callback_info info) +{ + size_t argc = 1; + napi_value argv[1] = {0}; + napi_value thisVar = nullptr; + napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr); + NAPI_ASSERT(env, argc == 1, "requires 1 parameter"); + + napi_valuetype valueType; + napi_typeof(env, argv[0], &valueType); + NAPI_ASSERT(env, valueType == napi_number, "type mismatch for parameter 1"); + + int64_t value = 0; + napi_get_value_int64(env, argv[0], &value); + + NAPI_MessageParcel *napiParcel = nullptr; + napi_unwrap(env, thisVar, (void **)&napiParcel); + NAPI_ASSERT(env, napiParcel != nullptr, "napiParcel is null"); + CHECK_WRITE_CAPACITY(env, BYTE_SIZE_64, napiParcel); + bool result = napiParcel->nativeParcel_->WriteInt64(value); + napi_value napiValue = nullptr; + NAPI_CALL(env, napi_get_boolean(env, result, &napiValue)); + return napiValue; +} + +napi_value NAPI_MessageParcel::JS_writeFloat(napi_env env, napi_callback_info info) +{ + size_t argc = 1; + napi_value argv[1] = {0}; + napi_value thisVar = nullptr; + napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr); + NAPI_ASSERT(env, argc == 1, "requires 1 parameter"); + + napi_valuetype valueType; + napi_typeof(env, argv[0], &valueType); + NAPI_ASSERT(env, valueType == napi_number, "type mismatch for parameter 1"); + + double value = 0; + napi_get_value_double(env, argv[0], &value); + + NAPI_MessageParcel *napiParcel = nullptr; + napi_unwrap(env, thisVar, (void **)&napiParcel); + NAPI_ASSERT(env, napiParcel != nullptr, "napiParcel is null"); + // bool result = napiParcel->nativeParcel_->WriteFloat(static_cast(value)); + CHECK_WRITE_CAPACITY(env, sizeof(double), napiParcel); + bool result = napiParcel->nativeParcel_->WriteDouble(value); + napi_value napiValue = nullptr; + NAPI_CALL(env, napi_get_boolean(env, result, &napiValue)); + return napiValue; +} + +napi_value NAPI_MessageParcel::JS_writeDouble(napi_env env, napi_callback_info info) +{ + size_t argc = 1; + napi_value argv[1] = {0}; + napi_value thisVar = nullptr; + napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr); + NAPI_ASSERT(env, argc == 1, "requires 1 parameter"); + + napi_valuetype valueType; + napi_typeof(env, argv[0], &valueType); + NAPI_ASSERT(env, valueType == napi_number, "type mismatch for parameter 1"); + + double value = 0; + napi_get_value_double(env, argv[0], &value); + + NAPI_MessageParcel *napiParcel = nullptr; + napi_unwrap(env, thisVar, (void **)&napiParcel); + NAPI_ASSERT(env, napiParcel != nullptr, "napiParcel is null"); + CHECK_WRITE_CAPACITY(env, sizeof(double), napiParcel); + bool result = napiParcel->nativeParcel_->WriteDouble(value); + napi_value napiValue = nullptr; + NAPI_CALL(env, napi_get_boolean(env, result, &napiValue)); + return napiValue; +} + +napi_value NAPI_MessageParcel::JS_writeBoolean(napi_env env, napi_callback_info info) +{ + size_t argc = 1; + napi_value argv[1] = {0}; + napi_value thisVar = nullptr; + napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr); + NAPI_ASSERT(env, argc == 1, "requires 1 parameter"); + + napi_valuetype valueType; + napi_typeof(env, argv[0], &valueType); + NAPI_ASSERT(env, valueType == napi_boolean, "type mismatch for parameter 1"); + + bool value = 0; + napi_get_value_bool(env, argv[0], &value); + + NAPI_MessageParcel *napiParcel = nullptr; + napi_unwrap(env, thisVar, (void **)&napiParcel); + NAPI_ASSERT(env, napiParcel != nullptr, "napiParcel is null"); + CHECK_WRITE_CAPACITY(env, BYTE_SIZE_32, napiParcel); + bool result = napiParcel->nativeParcel_->WriteInt8(static_cast(value)); + napi_value napiValue = nullptr; + NAPI_CALL(env, napi_get_boolean(env, result, &napiValue)); + return napiValue; +} + +napi_value NAPI_MessageParcel::JS_writeChar(napi_env env, napi_callback_info info) +{ + size_t argc = 1; + napi_value argv[1] = {0}; + napi_value thisVar = nullptr; + napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr); + NAPI_ASSERT(env, argc == 1, "requires 1 parameter"); + + napi_valuetype valueType; + napi_typeof(env, argv[0], &valueType); + NAPI_ASSERT(env, valueType == napi_string, "type mismatch for parameter 1"); + + size_t bufferSize = 0; + size_t strLength = 0; + napi_get_value_string_utf8(env, argv[0], nullptr, 0, &bufferSize); + DBINDER_LOGI("messageparcel writeChar bufferSize = %{public}d", (int)bufferSize); + char buffer[bufferSize + 1]; + napi_get_value_string_utf8(env, argv[0], buffer, bufferSize + 1, &strLength); + + NAPI_MessageParcel *napiParcel = nullptr; + napi_unwrap(env, thisVar, (void **)&napiParcel); + NAPI_ASSERT(env, napiParcel != nullptr, "napiParcel is null"); + CHECK_WRITE_CAPACITY(env, BYTE_SIZE_32, napiParcel); + std::string parcelString = buffer; + auto value = reinterpret_cast(to_utf16(parcelString).data()); + bool result = napiParcel->nativeParcel_->WriteUint16(*value); + + napi_value napiValue = nullptr; + NAPI_CALL(env, napi_get_boolean(env, result, &napiValue)); + return napiValue; +} + +napi_value NAPI_MessageParcel::JS_writeStringWithLength(napi_env env, napi_callback_info info) +{ + size_t argc = 2; + napi_value argv[2] = {0}; + napi_value thisVar = nullptr; + napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr); + NAPI_ASSERT(env, argc == 2, "requires 2 parameter"); + + NAPI_MessageParcel *napiParcel = nullptr; + napi_unwrap(env, thisVar, (void **)&napiParcel); + NAPI_ASSERT(env, napiParcel != nullptr, "napiParcel is null"); + + napi_valuetype valueType; + napi_typeof(env, argv[0], &valueType); + NAPI_ASSERT(env, valueType == napi_string, "type mismatch for parameter 1"); + + napi_typeof(env, argv[1], &valueType); + NAPI_ASSERT(env, valueType == napi_number, "type mismatch for parameter 2"); + + uint32_t stringLength = 0; + napi_get_value_uint32(env, argv[1], &stringLength); + // TODO 40960 definition + NAPI_ASSERT(env, stringLength < 40960, "string length too large"); + + char stringValue[stringLength + 1]; + size_t jsStringLength = 0; + napi_get_value_string_utf8(env, argv[0], stringValue, stringLength + 1, &jsStringLength); + NAPI_ASSERT(env, jsStringLength == stringLength, "string length wrong"); + + CHECK_WRITE_CAPACITY(env, BYTE_SIZE_32 * stringLength, napiParcel); + std::string parcelString = stringValue; + bool result = napiParcel->nativeParcel_->WriteString16(to_utf16(parcelString)); + + napi_value napiValue = nullptr; + NAPI_CALL(env, napi_get_boolean(env, result, &napiValue)); + return napiValue; +} + +napi_value NAPI_MessageParcel::JS_writeByteArray(napi_env env, napi_callback_info info) +{ + size_t argc = 1; + napi_value argv[1] = {0}; + napi_value thisVar = nullptr; + napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr); + NAPI_ASSERT(env, argc == 1, "requires 1 parameter"); + + bool isTypedArray; + napi_is_typedarray(env, argv[0], &isTypedArray); + NAPI_ASSERT(env, isTypedArray == true, "type mismatch for parameter 1"); + + napi_typedarray_type typedarrayType; + size_t typedarrayLength = 0; + void *typedarrayBufferPtr = nullptr; + napi_value tmpArrayBuffer = nullptr; + size_t byteOffset = 0; + napi_get_typedarray_info(env, argv[0], &typedarrayType, &typedarrayLength, &typedarrayBufferPtr, + &tmpArrayBuffer, &byteOffset); + + NAPI_ASSERT(env, typedarrayType == napi_int8_array, "array type mismatch for parameter 1"); + DBINDER_LOGI("messageparcel WriteBuffer typedarrayLength = %{public}d", (int)(typedarrayLength)); + + NAPI_MessageParcel *napiParcel = nullptr; + napi_unwrap(env, thisVar, (void **)&napiParcel); + NAPI_ASSERT(env, napiParcel != nullptr, "napiParcel is null"); + size_t len = (typedarrayLength / 4) + (typedarrayLength % 4 == 0 ? 0 : 1); + DBINDER_LOGI("messageparcel WriteBuffer len = %{public}d", (int)(len)); + CHECK_WRITE_CAPACITY(env, BYTE_SIZE_32 * (len + 1), napiParcel); + napiParcel->nativeParcel_->WriteUint32(typedarrayLength); + bool result = napiParcel->nativeParcel_->WriteBuffer(typedarrayBufferPtr, typedarrayLength); + napi_value napiValue = nullptr; + NAPI_CALL(env, napi_get_boolean(env, result, &napiValue)); + return napiValue; +} + +napi_value NAPI_MessageParcel::JS_writeShortArray(napi_env env, napi_callback_info info) +{ + size_t argc = 1; + napi_value argv[1] = { 0 }; + napi_value thisVar = nullptr; + void *data = nullptr; + napi_get_cb_info(env, info, &argc, argv, &thisVar, &data); + NAPI_ASSERT(env, argc == 1, "requires 1 parameter"); + + bool isArray; + napi_is_array(env, argv[0], &isArray); + NAPI_ASSERT(env, isArray == true, "type mismatch for parameter 1"); + + uint32_t arrayLength = 0; + napi_get_array_length(env, argv[0], &arrayLength); + + NAPI_MessageParcel *napiParcel = nullptr; + napi_unwrap(env, thisVar, (void**)&napiParcel); + NAPI_ASSERT(env, napiParcel != nullptr, "napiParcel is null"); + + CHECK_WRITE_CAPACITY(env, BYTE_SIZE_32 * (arrayLength + 1), napiParcel); + size_t pos = napiParcel->nativeParcel_->GetWritePosition(); + napiParcel->nativeParcel_->WriteUint32(arrayLength); + bool result = false; + for (size_t i = 0; i < arrayLength; i++) { + bool hasElement = false; + napi_has_element(env, argv[0], i, &hasElement); + NAPI_ASSERT(env, hasElement == true, "parameter check error"); + + napi_value element = nullptr; + napi_get_element(env, argv[0], i, &element); + + int32_t value = 0; + napi_get_value_int32(env, element, &value); + result = napiParcel->nativeParcel_->WriteInt16(static_cast(value)); + if (!result) { + napiParcel->nativeParcel_->RewindWrite(pos); + break; + } + } + + napi_value napiValue = nullptr; + NAPI_CALL(env, napi_get_boolean(env, result, &napiValue)); + return napiValue; +} + +napi_value NAPI_MessageParcel::JS_writeIntArray(napi_env env, napi_callback_info info) +{ + size_t argc = 1; + napi_value argv[1] = { 0 }; + napi_value thisVar = nullptr; + void *data = nullptr; + napi_get_cb_info(env, info, &argc, argv, &thisVar, &data); + NAPI_ASSERT(env, argc == 1, "requires 1 parameter"); + + bool isArray; + napi_is_array(env, argv[0], &isArray); + NAPI_ASSERT(env, isArray == true, "type mismatch for parameter 1"); + + uint32_t arrayLength = 0; + napi_get_array_length(env, argv[0], &arrayLength); + + NAPI_MessageParcel *napiParcel = nullptr; + napi_unwrap(env, thisVar, (void**)&napiParcel); + NAPI_ASSERT(env, napiParcel != nullptr, "napiParcel is null"); + + CHECK_WRITE_CAPACITY(env, BYTE_SIZE_32 * (arrayLength + 1), napiParcel); + size_t pos = napiParcel->nativeParcel_->GetWritePosition(); + napiParcel->nativeParcel_->WriteUint32(arrayLength); + bool result = false; + for (size_t i = 0; i < arrayLength; i++) { + bool hasElement = false; + napi_has_element(env, argv[0], i, &hasElement); + NAPI_ASSERT(env, hasElement == true, "parameter check error"); + + napi_value element = nullptr; + napi_get_element(env, argv[0], i, &element); + + napi_valuetype valueType; + napi_typeof(env, element, &valueType); + NAPI_ASSERT(env, valueType == napi_number, "type mismatch element"); + + int32_t value = 0; + napi_get_value_int32(env, element, &value); + result = napiParcel->nativeParcel_->WriteInt32(value); + if (!result) { + napiParcel->nativeParcel_->RewindWrite(pos); + break; + } + } + + napi_value napiValue = nullptr; + NAPI_CALL(env, napi_get_boolean(env, result, &napiValue)); + return napiValue; +} + +napi_value NAPI_MessageParcel::JS_writeLongArray(napi_env env, napi_callback_info info) +{ + size_t argc = 1; + napi_value argv[1] = { 0 }; + napi_value thisVar = nullptr; + void *data = nullptr; + napi_get_cb_info(env, info, &argc, argv, &thisVar, &data); + NAPI_ASSERT(env, argc == 1, "requires 1 parameter"); + + bool isArray; + napi_is_array(env, argv[0], &isArray); + NAPI_ASSERT(env, isArray == true, "type mismatch for parameter 1"); + + uint32_t arrayLength = 0; + napi_get_array_length(env, argv[0], &arrayLength); + DBINDER_LOGI("messageparcel WriteBuffer typedarrayLength = %{public}d", (int)(arrayLength)); + + NAPI_MessageParcel *napiParcel = nullptr; + napi_unwrap(env, thisVar, (void**)&napiParcel); + NAPI_ASSERT(env, napiParcel != nullptr, "napiParcel is null"); + + CHECK_WRITE_CAPACITY(env, BYTE_SIZE_32 + BYTE_SIZE_64 * arrayLength, napiParcel); + size_t pos = napiParcel->nativeParcel_->GetWritePosition(); + napiParcel->nativeParcel_->WriteUint32(arrayLength); + bool result = false; + for (size_t i = 0; i < arrayLength; i++) { + bool hasElement = false; + napi_has_element(env, argv[0], i, &hasElement); + NAPI_ASSERT(env, hasElement == true, "parameter check error"); + + napi_value element = nullptr; + napi_get_element(env, argv[0], i, &element); + + int64_t value = 0; + napi_get_value_int64(env, element, &value); + //DBINDER_LOGI("messageparcel WriteBuffer typedarrayLength = %{public}d", (int)(value)); + + result = napiParcel->nativeParcel_->WriteInt64(value); + if (!result) { + napiParcel->nativeParcel_->RewindWrite(pos); + break; + } + } + + napi_value napiValue = nullptr; + NAPI_CALL(env, napi_get_boolean(env, result, &napiValue)); + return napiValue; +} + +napi_value NAPI_MessageParcel::JS_writeFloatArray(napi_env env, napi_callback_info info) +{ + size_t argc = 1; + napi_value argv[1] = { 0 }; + napi_value thisVar = nullptr; + void *data = nullptr; + napi_get_cb_info(env, info, &argc, argv, &thisVar, &data); + NAPI_ASSERT(env, argc == 1, "requires 1 parameter"); + + bool isArray; + napi_is_array(env, argv[0], &isArray); + NAPI_ASSERT(env, isArray == true, "type mismatch for parameter 1"); + + uint32_t arrayLength = 0; + napi_get_array_length(env, argv[0], &arrayLength); + + NAPI_MessageParcel *napiParcel = nullptr; + napi_unwrap(env, thisVar, (void**)&napiParcel); + NAPI_ASSERT(env, napiParcel != nullptr, "napiParcel is null"); + + CHECK_WRITE_CAPACITY(env, BYTE_SIZE_32 + sizeof(double) * arrayLength, napiParcel); + size_t pos = napiParcel->nativeParcel_->GetWritePosition(); + napiParcel->nativeParcel_->WriteUint32(arrayLength); + bool result = false; + for (size_t i = 0; i < arrayLength; i++) { + bool hasElement = false; + napi_has_element(env, argv[0], i, &hasElement); + NAPI_ASSERT(env, hasElement == true, "parameter check error"); + + napi_value element = nullptr; + napi_get_element(env, argv[0], i, &element); + + double value = 0; + napi_get_value_double(env, element, &value); + + // result = napiParcel->nativeParcel_->WriteFloat(static_cast(value)); + result = napiParcel->nativeParcel_->WriteDouble(value); + if (!result) { + napiParcel->nativeParcel_->RewindWrite(pos); + break; + } + } + + napi_value napiValue = nullptr; + NAPI_CALL(env, napi_get_boolean(env, result, &napiValue)); + return napiValue; +} + +napi_value NAPI_MessageParcel::JS_writeDoubleArray(napi_env env, napi_callback_info info) +{ + size_t argc = 1; + napi_value argv[1] = { 0 }; + napi_value thisVar = nullptr; + void *data = nullptr; + napi_get_cb_info(env, info, &argc, argv, &thisVar, &data); + NAPI_ASSERT(env, argc == 1, "requires 1 parameter"); + + bool isArray; + napi_is_array(env, argv[0], &isArray); + NAPI_ASSERT(env, isArray == true, "type mismatch for parameter 1"); + + uint32_t arrayLength = 0; + napi_get_array_length(env, argv[0], &arrayLength); + + NAPI_MessageParcel *napiParcel = nullptr; + napi_unwrap(env, thisVar, (void**)&napiParcel); + NAPI_ASSERT(env, napiParcel != nullptr, "napiParcel is null"); + + CHECK_WRITE_CAPACITY(env, BYTE_SIZE_32 + sizeof(double) * arrayLength, napiParcel); + size_t pos = napiParcel->nativeParcel_->GetWritePosition(); + napiParcel->nativeParcel_->WriteUint32(arrayLength); + bool result = false; + for (size_t i = 0; i < arrayLength; i++) { + bool hasElement = false; + napi_has_element(env, argv[0], i, &hasElement); + NAPI_ASSERT(env, hasElement == true, "parameter check error"); + + napi_value element = nullptr; + napi_get_element(env, argv[0], i, &element); + + double value = 0; + napi_get_value_double(env, element, &value); + + result = napiParcel->nativeParcel_->WriteDouble(value); + if (!result) { + napiParcel->nativeParcel_->RewindWrite(pos); + break; + } + } + + napi_value napiValue = nullptr; + NAPI_CALL(env, napi_get_boolean(env, result, &napiValue)); + return napiValue; +} + +napi_value NAPI_MessageParcel::JS_writeBooleanArray(napi_env env, napi_callback_info info) +{ + size_t argc = 1; + napi_value argv[1] = { 0 }; + napi_value thisVar = nullptr; + void *data = nullptr; + napi_get_cb_info(env, info, &argc, argv, &thisVar, &data); + NAPI_ASSERT(env, argc == 1, "requires 1 parameter"); + + bool isArray; + napi_is_array(env, argv[0], &isArray); + NAPI_ASSERT(env, isArray == true, "type mismatch for parameter 1"); + + uint32_t arrayLength = 0; + napi_get_array_length(env, argv[0], &arrayLength); + + NAPI_MessageParcel *napiParcel = nullptr; + napi_unwrap(env, thisVar, (void**)&napiParcel); + NAPI_ASSERT(env, napiParcel != nullptr, "napiParcel is null"); + + CHECK_WRITE_CAPACITY(env, BYTE_SIZE_32 * (arrayLength + 1), napiParcel); + size_t pos = napiParcel->nativeParcel_->GetWritePosition(); + napiParcel->nativeParcel_->WriteUint32(arrayLength); + bool result = false; + for (size_t i = 0; i < arrayLength; i++) { + bool hasElement = false; + napi_has_element(env, argv[0], i, &hasElement); + NAPI_ASSERT(env, hasElement == true, "parameter check error"); + + napi_value element = nullptr; + napi_get_element(env, argv[0], i, &element); + + bool value = 0; + napi_get_value_bool(env, element, &value); + + result = napiParcel->nativeParcel_->WriteInt8(static_cast(value)); + if (!result) { + napiParcel->nativeParcel_->RewindWrite(pos); + break; + } + } + + napi_value napiValue = nullptr; + NAPI_CALL(env, napi_get_boolean(env, result, &napiValue)); + return napiValue; +} + +napi_value NAPI_MessageParcel::JS_writeCharArray(napi_env env, napi_callback_info info) +{ + size_t argc = 1; + napi_value argv[1] = { 0 }; + napi_value thisVar = nullptr; + void *data = nullptr; + napi_get_cb_info(env, info, &argc, argv, &thisVar, &data); + NAPI_ASSERT(env, argc == 1, "requires 1 parameter"); + + bool isArray; + napi_is_array(env, argv[0], &isArray); + NAPI_ASSERT(env, isArray == true, "type mismatch for parameter 1"); + + uint32_t arrayLength = 0; + napi_get_array_length(env, argv[0], &arrayLength); + + NAPI_MessageParcel *napiParcel = nullptr; + napi_unwrap(env, thisVar, (void**)&napiParcel); + NAPI_ASSERT(env, napiParcel != nullptr, "napiParcel is null"); + + CHECK_WRITE_CAPACITY(env, BYTE_SIZE_32 * (arrayLength + 1), napiParcel); + size_t pos = napiParcel->nativeParcel_->GetWritePosition(); + napiParcel->nativeParcel_->WriteUint32(arrayLength); + bool result = false; + for (size_t i = 0; i < arrayLength; i++) { + bool hasElement = false; + napi_has_element(env, argv[0], i, &hasElement); + NAPI_ASSERT(env, hasElement == true, "parameter check error"); + + napi_value element = nullptr; + napi_get_element(env, argv[0], i, &element); + + // uint32_t value = 0; + // napi_get_value_uint32(env, element, &value); + // DBINDER_LOGI("messageparcel WriteBuffer typedarrayLength = %{public}d", (int)(value)); + size_t bufferSize = 0; + size_t strLength = 0; + napi_get_value_string_utf8(env, element, nullptr, 0, &bufferSize); + DBINDER_LOGI("messageparcel writeChar bufferSize = %{public}d", (int)bufferSize); + char buffer[bufferSize + 1]; + napi_get_value_string_utf8(env, element, buffer, bufferSize + 1, &strLength); + DBINDER_LOGI("messageparcel writeChar strLength = %{public}d", (int)strLength); + + std::string parcelString = buffer; + auto value = reinterpret_cast(to_utf16(parcelString).data()); + result = napiParcel->nativeParcel_->WriteUint16(*value); + + // result = napiParcel->nativeParcel_->WriteUint16(static_cast(value)); + if (!result) { + napiParcel->nativeParcel_->RewindWrite(pos); + break; + } + } + + napi_value napiValue = nullptr; + NAPI_CALL(env, napi_get_boolean(env, result, &napiValue)); + return napiValue; +} + +napi_value NAPI_MessageParcel::JS_writeString(napi_env env, napi_callback_info info) +{ + size_t argc = 1; + napi_value argv[1] = {0}; + napi_value thisVar = nullptr; + void *data = nullptr; + napi_get_cb_info(env, info, &argc, argv, &thisVar, &data); + NAPI_ASSERT(env, argc == 1, "requires 2 parameter"); + + NAPI_MessageParcel *napiParcel = nullptr; + napi_unwrap(env, thisVar, (void **)&napiParcel); + NAPI_ASSERT(env, napiParcel != nullptr, "napiParcel is null"); + + napi_valuetype valueType; + napi_typeof(env, argv[0], &valueType); + NAPI_ASSERT(env, valueType == napi_string, "type mismatch for parameter 1"); + + size_t bufferSize = 0; + napi_get_value_string_utf8(env, argv[0], nullptr, 0, &bufferSize); + NAPI_ASSERT(env, bufferSize < 40960, "string length too large"); + + char stringValue[bufferSize + 1]; + size_t jsStringLength = 0; + napi_get_value_string_utf8(env, argv[0], stringValue, bufferSize + 1, &jsStringLength); + NAPI_ASSERT(env, jsStringLength == bufferSize, "string length wrong"); + + CHECK_WRITE_CAPACITY(env, BYTE_SIZE_32 * bufferSize, napiParcel); + std::string parcelString = stringValue; + bool result = napiParcel->nativeParcel_->WriteString16(to_utf16(parcelString)); + + napi_value napiValue = nullptr; + NAPI_CALL(env, napi_get_boolean(env, result, &napiValue)); + return napiValue; +} + +napi_value NAPI_MessageParcel::JS_writeStringArray(napi_env env, napi_callback_info info) +{ + size_t argc = 1; + napi_value argv[1] = { 0 }; + napi_value thisVar = nullptr; + void *data = nullptr; + napi_get_cb_info(env, info, &argc, argv, &thisVar, &data); + NAPI_ASSERT(env, argc == 1, "requires 1 parameter"); + + bool isArray; + napi_is_array(env, argv[0], &isArray); + NAPI_ASSERT(env, isArray == true, "type mismatch for parameter 1"); + + uint32_t arrayLength = 0; + napi_get_array_length(env, argv[0], &arrayLength); + + NAPI_MessageParcel *napiParcel = nullptr; + napi_unwrap(env, thisVar, (void**)&napiParcel); + NAPI_ASSERT(env, napiParcel != nullptr, "napiParcel is null"); + + size_t pos = napiParcel->nativeParcel_->GetWritePosition(); + napiParcel->nativeParcel_->WriteUint32(arrayLength); + bool result = false; + for (size_t i = 0; i < arrayLength; i++) { + bool hasElement = false; + napi_has_element(env, argv[0], i, &hasElement); + NAPI_ASSERT(env, hasElement == true, "parameter check error"); + + napi_value element = nullptr; + napi_get_element(env, argv[0], i, &element); + + size_t bufferSize = 0; + napi_get_value_string_utf8(env, element, nullptr, 0, &bufferSize); + NAPI_ASSERT(env, bufferSize < 40960, "string length too large"); + + char stringValue[bufferSize + 1]; + size_t jsStringLength = 0; + napi_get_value_string_utf8(env, element, stringValue, bufferSize + 1, &jsStringLength); + NAPI_ASSERT(env, jsStringLength == bufferSize, "string length wrong"); + + REWIND_IF_WRITE_CHECK_FAIL(env, BYTE_SIZE_32 * bufferSize, pos, napiParcel); + std::string parcelString = stringValue; + result = napiParcel->nativeParcel_->WriteString16(to_utf16(parcelString)); + + if (!result) { + napiParcel->nativeParcel_->RewindWrite(pos); + break; + } + } + + napi_value napiValue = nullptr; + NAPI_CALL(env, napi_get_boolean(env, result, &napiValue)); + return napiValue; +} + +napi_value NAPI_MessageParcel::JS_writeSequenceable(napi_env env, napi_callback_info info) +{ + size_t argc = 1; + napi_value argv[1] = { 0 }; + napi_value thisVar = nullptr; + void *data = nullptr; + napi_get_cb_info(env, info, &argc, argv, &thisVar, &data); + NAPI_ASSERT(env, argc == 1, "requires 1 parameter"); + + NAPI_MessageParcel *napiParcel = nullptr; + napi_unwrap(env, thisVar, (void**)&napiParcel); + NAPI_ASSERT(env, napiParcel != nullptr, "napiParcel is null"); + + size_t pos = napiParcel->nativeParcel_->GetWritePosition(); + napiParcel->nativeParcel_->WriteInt32(1); + napi_value propKey = nullptr; + const char *propKeyStr = "marshalling"; + napi_create_string_utf8(env, propKeyStr, strlen(propKeyStr), &propKey); + napi_value prop = nullptr; + napi_get_property(env, argv[0], propKey, &prop); + + napi_value funcArg[1] = { thisVar }; + napi_value callResult = nullptr; + bool result = napi_call_function(env, thisVar, prop, 1, funcArg, &callResult); + bool isExceptionPending = false; + napi_is_exception_pending(env, &isExceptionPending); + if (isExceptionPending) { + napiParcel->nativeParcel_->RewindWrite(pos); + } + + napi_value napiValue = nullptr; + NAPI_CALL(env, napi_get_boolean(env, result, &napiValue)); + return napiValue; +} + +napi_value NAPI_MessageParcel::JS_writeSequenceableArray(napi_env env, napi_callback_info info) +{ + size_t argc = 1; + napi_value argv[1] = { 0 }; + napi_value thisVar = nullptr; + void *data = nullptr; + napi_get_cb_info(env, info, &argc, argv, &thisVar, &data); + NAPI_ASSERT(env, argc == 1, "requires 1 parameter"); + + bool isArray; + napi_is_array(env, argv[0], &isArray); + NAPI_ASSERT(env, isArray == true, "type mismatch for parameter 1"); + + uint32_t arrayLength = 0; + napi_get_array_length(env, argv[0], &arrayLength); + + NAPI_MessageParcel *napiParcel = nullptr; + napi_unwrap(env, thisVar, (void**)&napiParcel); + NAPI_ASSERT(env, napiParcel != nullptr, "napiParcel is null"); + + size_t pos = napiParcel->nativeParcel_->GetWritePosition(); + napiParcel->nativeParcel_->WriteUint32(arrayLength); + bool result = false; + for (size_t i = 0; i < arrayLength; i++) { + bool hasElement = false; + napi_has_element(env, argv[0], i, &hasElement); + NAPI_ASSERT(env, hasElement == true, "parameter check error"); + + napi_value element = nullptr; + napi_get_element(env, argv[0], i, &element); + + napi_value propKey = nullptr; + const char* propKeyStr = "marshalling"; + napi_create_string_utf8(env, propKeyStr, strlen(propKeyStr), &propKey); + napi_value prop = nullptr; + napi_get_property(env, element, propKey, &prop); + + napi_value funcArg[1] = { thisVar }; + napi_value callResult = nullptr; + result = napi_call_function(env, thisVar, prop, 1, funcArg, &callResult); + + bool isExceptionPending = false; + napi_is_exception_pending(env, &isExceptionPending); + if (!result || isExceptionPending) { + napiParcel->nativeParcel_->RewindWrite(pos); + break; + } + } + + napi_value napiValue = nullptr; + NAPI_CALL(env, napi_get_boolean(env, result, &napiValue)); + return napiValue; +} + +napi_value NAPI_MessageParcel::JS_readByte(napi_env env, napi_callback_info info) +{ + size_t argc = 0; + napi_value thisVar = nullptr; + napi_get_cb_info(env, info, &argc, nullptr, &thisVar, nullptr); + NAPI_MessageParcel *napiParcel = nullptr; + napi_unwrap(env, thisVar, (void **)&napiParcel); + NAPI_ASSERT_BASE(env, napiParcel != nullptr, "napiParcel is null", 0); + + int8_t value = napiParcel->nativeParcel_->ReadInt8(); + napi_value napiValue = nullptr; + NAPI_CALL(env, napi_create_int32(env, value, &napiValue)); + return napiValue; +} + +napi_value NAPI_MessageParcel::JS_readShort(napi_env env, napi_callback_info info) +{ + size_t argc = 0; + napi_value thisVar = nullptr; + napi_get_cb_info(env, info, &argc, nullptr, &thisVar, nullptr); + NAPI_MessageParcel *napiParcel = nullptr; + napi_unwrap(env, thisVar, (void **)&napiParcel); + NAPI_ASSERT_BASE(env, napiParcel != nullptr, "napiParcel is null", 0); + + int16_t value = napiParcel->nativeParcel_->ReadInt16(); + napi_value napiValue = nullptr; + NAPI_CALL(env, napi_create_int32(env, value, &napiValue)); + return napiValue; +} + +napi_value NAPI_MessageParcel::JS_readInt(napi_env env, napi_callback_info info) +{ + size_t argc = 0; + napi_value thisVar = nullptr; + napi_get_cb_info(env, info, &argc, nullptr, &thisVar, nullptr); + NAPI_MessageParcel *napiParcel = nullptr; + napi_unwrap(env, thisVar, (void **)&napiParcel); + NAPI_ASSERT_BASE(env, napiParcel != nullptr, "napiParcel is null", 0); + + int32_t value = napiParcel->nativeParcel_->ReadInt32(); + napi_value napiValue = nullptr; + NAPI_CALL(env, napi_create_int32(env, value, &napiValue)); + return napiValue; +} + +napi_value NAPI_MessageParcel::JS_readLong(napi_env env, napi_callback_info info) +{ + size_t argc = 0; + napi_value thisVar = nullptr; + napi_get_cb_info(env, info, &argc, nullptr, &thisVar, nullptr); + NAPI_MessageParcel *napiParcel = nullptr; + napi_unwrap(env, thisVar, (void **)&napiParcel); + NAPI_ASSERT_BASE(env, napiParcel != nullptr, "napiParcel is null", 0); + + int64_t value = napiParcel->nativeParcel_->ReadInt64(); + napi_value napiValue = nullptr; + NAPI_CALL(env, napi_create_int64(env, value, &napiValue)); + return napiValue; +} + +napi_value NAPI_MessageParcel::JS_readFloat(napi_env env, napi_callback_info info) +{ + size_t argc = 0; + napi_value thisVar = nullptr; + napi_get_cb_info(env, info, &argc, nullptr, &thisVar, nullptr); + NAPI_MessageParcel *napiParcel = nullptr; + napi_unwrap(env, thisVar, (void **)&napiParcel); + NAPI_ASSERT_BASE(env, napiParcel != nullptr, "napiParcel is null", 0); + + // float value = napiParcel->nativeParcel_->ReadFloat(); + double value = napiParcel->nativeParcel_->ReadDouble(); + napi_value napiValue = nullptr; + NAPI_CALL(env, napi_create_double(env, value, &napiValue)); + return napiValue; +} + +napi_value NAPI_MessageParcel::JS_readDouble(napi_env env, napi_callback_info info) +{ + size_t argc = 0; + napi_value thisVar = nullptr; + napi_get_cb_info(env, info, &argc, nullptr, &thisVar, nullptr); + NAPI_MessageParcel *napiParcel = nullptr; + napi_unwrap(env, thisVar, (void **)&napiParcel); + NAPI_ASSERT_BASE(env, napiParcel != nullptr, "napiParcel is null", 0); + + double value = napiParcel->nativeParcel_->ReadDouble(); + napi_value napiValue = nullptr; + NAPI_CALL(env, napi_create_double(env, value, &napiValue)); + return napiValue; +} + +napi_value NAPI_MessageParcel::JS_readBoolean(napi_env env, napi_callback_info info) +{ + size_t argc = 0; + napi_value thisVar = nullptr; + napi_get_cb_info(env, info, &argc, nullptr, &thisVar, nullptr); + NAPI_MessageParcel *napiParcel = nullptr; + napi_unwrap(env, thisVar, (void **)&napiParcel); + NAPI_ASSERT_BASE(env, napiParcel != nullptr, "napiParcel is null", 0); + + int8_t value = napiParcel->nativeParcel_->ReadInt8(); + napi_value napiValue = nullptr; + NAPI_CALL(env, napi_get_boolean(env, value, &napiValue)); + return napiValue; +} + +napi_value NAPI_MessageParcel::JS_readChar(napi_env env, napi_callback_info info) +{ + size_t argc = 0; + napi_value thisVar = nullptr; + napi_get_cb_info(env, info, &argc, nullptr, &thisVar, nullptr); + NAPI_MessageParcel *napiParcel = nullptr; + napi_unwrap(env, thisVar, (void **)&napiParcel); + NAPI_ASSERT_BASE(env, napiParcel != nullptr, "napiParcel is null", 0); + + uint16_t value = napiParcel->nativeParcel_->ReadUint16(); + napi_value napiValue = nullptr; + NAPI_CALL(env, napi_create_uint32(env, value, &napiValue)); + return napiValue; +} + +napi_value NAPI_MessageParcel::JS_readString(napi_env env, napi_callback_info info) +{ + size_t argc = 0; + napi_value thisVar = nullptr; + napi_get_cb_info(env, info, &argc, nullptr, &thisVar, nullptr); + NAPI_MessageParcel *napiParcel = nullptr; + napi_unwrap(env, thisVar, (void **)&napiParcel); + NAPI_ASSERT_BASE(env, napiParcel != nullptr, "napiParcel is null", 0); + + std::u16string parcelString = napiParcel->nativeParcel_->ReadString16(); + std::string outString = Str16ToStr8(parcelString.c_str()); + napi_value napiValue = nullptr; + napi_create_string_utf8(env, outString.c_str(), outString.length(), &napiValue); + return napiValue; +} + +napi_value NAPI_MessageParcel::JS_getSize(napi_env env, napi_callback_info info) +{ + size_t argc = 0; + napi_value thisVar = nullptr; + napi_get_cb_info(env, info, &argc, nullptr, &thisVar, nullptr); + + NAPI_MessageParcel *napiParcel = nullptr; + napi_unwrap(env, thisVar, (void **)&napiParcel); + NAPI_ASSERT_BASE(env, napiParcel != nullptr, "napiParcel is null", 0); + + size_t value = napiParcel->nativeParcel_->GetDataSize(); + napi_value napiValue = nullptr; + NAPI_CALL(env, napi_create_uint32(env, static_cast(value), &napiValue)); + return napiValue; +} + +napi_value NAPI_MessageParcel::JS_getCapacity(napi_env env, napi_callback_info info) +{ + size_t argc = 0; + napi_value thisVar = nullptr; + napi_get_cb_info(env, info, &argc, nullptr, &thisVar, nullptr); + + NAPI_MessageParcel *napiParcel = nullptr; + napi_unwrap(env, thisVar, (void **)&napiParcel); + NAPI_ASSERT_BASE(env, napiParcel != nullptr, "napiParcel is null", 0); + + size_t value = napiParcel->nativeParcel_->GetDataCapacity(); + napi_value napiValue = nullptr; + NAPI_CALL(env, napi_create_uint32(env, static_cast(value), &napiValue)); + return napiValue; +} + +napi_value NAPI_MessageParcel::JS_setSize(napi_env env, napi_callback_info info) +{ + size_t argc = 1; + napi_value argv[1] = {0}; + napi_value thisVar = nullptr; + void *data = nullptr; + napi_get_cb_info(env, info, &argc, argv, &thisVar, &data); + NAPI_ASSERT(env, argc == 1, "requires 1 parameter"); + + napi_valuetype valueType; + napi_typeof(env, argv[0], &valueType); + NAPI_ASSERT(env, valueType == napi_number, "type mismatch for parameter 1"); + + uint32_t value = 0; + napi_get_value_uint32(env, argv[0], &value); + + NAPI_MessageParcel *napiParcel = nullptr; + napi_unwrap(env, thisVar, (void **)&napiParcel); + NAPI_ASSERT(env, napiParcel != nullptr, "napiParcel is null"); + + bool result = napiParcel->nativeParcel_->SetDataSize(static_cast(value)); + napi_value napiValue = nullptr; + NAPI_CALL(env, napi_get_boolean(env, result, &napiValue)); + return napiValue; +} + +napi_value NAPI_MessageParcel::JS_setCapacity(napi_env env, napi_callback_info info) +{ + size_t argc = 1; + napi_value argv[1] = {0}; + napi_value thisVar = nullptr; + void *data = nullptr; + napi_get_cb_info(env, info, &argc, argv, &thisVar, &data); + NAPI_ASSERT(env, argc == 1, "requires 1 parameter"); + + napi_valuetype valueType; + napi_typeof(env, argv[0], &valueType); + NAPI_ASSERT(env, valueType == napi_number, "type mismatch for parameter 1"); + + uint32_t value = 0; + napi_get_value_uint32(env, argv[0], &value); + + NAPI_MessageParcel *napiParcel = nullptr; + napi_unwrap(env, thisVar, (void **)&napiParcel); + NAPI_ASSERT(env, napiParcel != nullptr, "napiParcel is null"); + + bool result = napiParcel->nativeParcel_->SetDataCapacity(static_cast(value)); + if (result) { + napiParcel->maxCapacityToWrite_ = value; + } + napi_value napiValue = nullptr; + NAPI_CALL(env, napi_get_boolean(env, result, &napiValue)); + return napiValue; +} + +napi_value NAPI_MessageParcel::JS_getWritableBytes(napi_env env, napi_callback_info info) +{ + size_t argc = 0; + napi_value thisVar = nullptr; + napi_get_cb_info(env, info, &argc, nullptr, &thisVar, nullptr); + + NAPI_MessageParcel *napiParcel = nullptr; + napi_unwrap(env, thisVar, (void **)&napiParcel); + NAPI_ASSERT_BASE(env, napiParcel != nullptr, "napiParcel is null", 0); + + size_t value = napiParcel->nativeParcel_->GetWritableBytes(); + napi_value napiValue = nullptr; + NAPI_CALL(env, napi_create_uint32(env, static_cast(value), &napiValue)); + return napiValue; +} + +napi_value NAPI_MessageParcel::JS_getReadableBytes(napi_env env, napi_callback_info info) +{ + size_t argc = 0; + napi_value thisVar = nullptr; + napi_get_cb_info(env, info, &argc, nullptr, &thisVar, nullptr); + + NAPI_MessageParcel *napiParcel = nullptr; + napi_unwrap(env, thisVar, (void **)&napiParcel); + NAPI_ASSERT_BASE(env, napiParcel != nullptr, "napiParcel is null", 0); + + size_t value = napiParcel->nativeParcel_->GetReadableBytes(); + napi_value napiValue = nullptr; + NAPI_CALL(env, napi_create_uint32(env, static_cast(value), &napiValue)); + return napiValue; +} + +napi_value NAPI_MessageParcel::JS_getReadPosition(napi_env env, napi_callback_info info) +{ + size_t argc = 0; + napi_value thisVar = nullptr; + napi_get_cb_info(env, info, &argc, nullptr, &thisVar, nullptr); + + NAPI_MessageParcel *napiParcel = nullptr; + napi_unwrap(env, thisVar, (void **)&napiParcel); + NAPI_ASSERT_BASE(env, napiParcel != nullptr, "napiParcel is null", 0); + + size_t value = napiParcel->nativeParcel_->GetReadPosition(); + napi_value napiValue = nullptr; + NAPI_CALL(env, napi_create_uint32(env, value, &napiValue)); + return napiValue; +} + +napi_value NAPI_MessageParcel::JS_rewindRead(napi_env env, napi_callback_info info) +{ + size_t argc = 1; + napi_value argv[1] = {0}; + napi_value thisVar = nullptr; + void *data = nullptr; + napi_get_cb_info(env, info, &argc, argv, &thisVar, &data); + NAPI_ASSERT(env, argc == 1, "requires 1 parameter"); + + napi_valuetype valueType; + napi_typeof(env, argv[0], &valueType); + NAPI_ASSERT(env, valueType == napi_number, "type mismatch for parameter 1"); + + uint32_t pos = 0; + napi_get_value_uint32(env, argv[0], &pos); + + NAPI_MessageParcel *napiParcel = nullptr; + napi_unwrap(env, thisVar, (void **)&napiParcel); + NAPI_ASSERT(env, napiParcel != nullptr, "napiParcel is null"); + + bool result = napiParcel->nativeParcel_->RewindRead(static_cast(pos)); + napi_value napiValue = nullptr; + NAPI_CALL(env, napi_get_boolean(env, result, &napiValue)); + return napiValue; +} + +napi_value NAPI_MessageParcel::JS_getWritePosition(napi_env env, napi_callback_info info) +{ + size_t argc = 0; + napi_value thisVar = nullptr; + napi_get_cb_info(env, info, &argc, nullptr, &thisVar, nullptr); + + NAPI_MessageParcel *napiParcel = nullptr; + napi_unwrap(env, thisVar, (void **)&napiParcel); + NAPI_ASSERT_BASE(env, napiParcel != nullptr, "napiParcel is null", 0); + + size_t value = napiParcel->nativeParcel_->GetWritePosition(); + napi_value napiValue = nullptr; + NAPI_CALL(env, napi_create_uint32(env, value, &napiValue)); + return napiValue; +} + +napi_value NAPI_MessageParcel::JS_rewindWrite(napi_env env, napi_callback_info info) +{ + size_t argc = 1; + napi_value argv[1] = {0}; + napi_value thisVar = nullptr; + void *data = nullptr; + napi_get_cb_info(env, info, &argc, argv, &thisVar, &data); + NAPI_ASSERT(env, argc == 1, "requires 1 parameter"); + + napi_valuetype valueType; + napi_typeof(env, argv[0], &valueType); + NAPI_ASSERT(env, valueType == napi_number, "type mismatch for parameter 1"); + + uint32_t pos = 0; + napi_get_value_uint32(env, argv[0], &pos); + + NAPI_MessageParcel *napiParcel = nullptr; + napi_unwrap(env, thisVar, (void **)&napiParcel); + NAPI_ASSERT(env, napiParcel != nullptr, "napiParcel is null"); + + bool result = napiParcel->nativeParcel_->RewindWrite(static_cast(pos)); + napi_value napiValue = nullptr; + NAPI_CALL(env, napi_get_boolean(env, result, &napiValue)); + return napiValue; +} + +napi_value NAPI_MessageParcel::JS_readByteArray(napi_env env, napi_callback_info info) +{ + size_t argc = 0; + napi_value thisVar = nullptr; + napi_get_cb_info(env, info, &argc, nullptr, &thisVar, nullptr); + + + NAPI_MessageParcel *napiParcel = nullptr; + napi_unwrap(env, thisVar, (void **)&napiParcel); + NAPI_ASSERT(env, napiParcel != nullptr, "napiParcel is null"); + + uint32_t arrayBufferLength = napiParcel->nativeParcel_->ReadUint32(); + NAPI_ASSERT(env, arrayBufferLength < 40960, "byte array length too large"); + size_t len = (arrayBufferLength / 4) + (arrayBufferLength % 4 == 0 ? 0 : 1); + DBINDER_LOGI("messageparcel WriteBuffer typedarrayLength = %{public}d", (int)(len)); + + if (argc > 0) { + NAPI_ASSERT(env, argc == 1, "type mismatch for parameter 1"); + CHECK_READ_LENGTH(env, len, BYTE_SIZE_32, napiParcel); + napi_value argv[1] = {0}; + void *data = nullptr; + napi_get_cb_info(env, info, &argc, argv, &thisVar, &data); + + bool isTypedArray; + napi_is_typedarray(env, argv[0], &isTypedArray); + NAPI_ASSERT(env, isTypedArray == true, "type mismatch for parameter 1"); + + napi_typedarray_type arrayType; + size_t arrayLength = 0; + void *arrayBufferPtr = nullptr; + napi_value tmpArrayBuffer = nullptr; + size_t byteOffset = 0; + napi_get_typedarray_info(env, argv[0], &arrayType, &arrayLength, &arrayBufferPtr, + &tmpArrayBuffer, &byteOffset); + NAPI_ASSERT(env, arrayType == napi_int8_array, "array type mismatch for parameter 1"); + NAPI_ASSERT(env, arrayLength == arrayBufferLength, "array size mismatch for length"); + + const uint8_t *arrayAddr = napiParcel->nativeParcel_->ReadUnpadBuffer(arrayBufferLength); + NAPI_ASSERT(env, arrayAddr != nullptr, "buffer is nullptr"); + errno_t status = memcpy_s(arrayBufferPtr, arrayBufferLength, arrayAddr, arrayBufferLength); + NAPI_ASSERT(env, status == EOK, "memcpy_s is failed"); + + napi_value napiValue = nullptr; + NAPI_CALL(env, napi_get_boolean(env, true, &napiValue)); + return napiValue; + } + + CHECK_READ_LENGTH(env, len, BYTE_SIZE_32, napiParcel); + napi_value arrayBuffer = nullptr; + void *arrayBufferPtr = nullptr; + napi_create_arraybuffer(env, arrayBufferLength, &arrayBufferPtr, &arrayBuffer); + napi_value typedarray = nullptr; + napi_create_typedarray(env, napi_int8_array, arrayBufferLength, arrayBuffer, 0, &typedarray); + if (arrayBufferLength == 0) { + return typedarray; + } + + const uint8_t *arrayAddr = napiParcel->nativeParcel_->ReadUnpadBuffer(arrayBufferLength); + NAPI_ASSERT(env, arrayAddr != nullptr, "buffer is nullptr"); + errno_t status = memcpy_s(arrayBufferPtr, arrayBufferLength, arrayAddr, arrayBufferLength); + NAPI_ASSERT(env, status == EOK, "memcpy_s is failed"); + return typedarray; +} + +napi_value NAPI_MessageParcel::JS_readShortArray(napi_env env, napi_callback_info info) +{ + size_t argc = 0; + napi_value thisVar = nullptr; + napi_get_cb_info(env, info, &argc, nullptr, &thisVar, nullptr); + + NAPI_MessageParcel *napiParcel = nullptr; + napi_unwrap(env, thisVar, (void **)&napiParcel); + NAPI_ASSERT(env, napiParcel != nullptr, "napiParcel is null"); + + int32_t arrayLength = napiParcel->nativeParcel_->ReadInt32(); + if (argc > 0) { + NAPI_ASSERT(env, argc == 1, "type mismatch for parameter 1"); + CHECK_READ_LENGTH(env, (size_t)arrayLength, BYTE_SIZE_32, napiParcel) + napi_value argv[1] = {0}; + void *data = nullptr; + napi_get_cb_info(env, info, &argc, argv, &thisVar, &data); + + bool isArray; + napi_is_array(env, argv[0], &isArray); + NAPI_ASSERT(env, isArray == true, "type mismatch for parameter 1"); + + for (int32_t i = 0; i < arrayLength; i++) { + int16_t val = napiParcel->nativeParcel_->ReadInt16(); + napi_value num = nullptr; + napi_create_int32(env, val, &num); + napi_set_element(env, argv[0], i, num); + } + napi_value napiValue = nullptr; + NAPI_CALL(env, napi_get_boolean(env, true, &napiValue)); + return napiValue; + } + + if (arrayLength <= 0) { + napi_value result = nullptr; + napi_create_array(env, &result); + return result; + } + CHECK_READ_LENGTH(env, (size_t)arrayLength, BYTE_SIZE_32, napiParcel) + napi_value result = nullptr; + napi_create_array_with_length(env, arrayLength, &result); + + for (int32_t i = 0; i < arrayLength; i++) { + int16_t val = napiParcel->nativeParcel_->ReadInt16(); + napi_value num = nullptr; + napi_create_int32(env, val, &num); + napi_set_element(env, result, i, num); + } + return result; +} + +napi_value NAPI_MessageParcel::JS_readIntArray(napi_env env, napi_callback_info info) +{ + size_t argc = 0; + napi_value thisVar = nullptr; + napi_get_cb_info(env, info, &argc, nullptr, &thisVar, nullptr); + + NAPI_MessageParcel *napiParcel = nullptr; + napi_unwrap(env, thisVar, (void **)&napiParcel); + NAPI_ASSERT(env, napiParcel != nullptr, "napiParcel is null"); + + int32_t arrayLength = napiParcel->nativeParcel_->ReadInt32(); + if (argc > 0) { + NAPI_ASSERT(env, argc == 1, "type mismatch for parameter 1"); + CHECK_READ_LENGTH(env, (size_t)arrayLength, BYTE_SIZE_32, napiParcel) + napi_value argv[1] = {0}; + void *data = nullptr; + napi_get_cb_info(env, info, &argc, argv, &thisVar, &data); + + bool isArray; + napi_is_array(env, argv[0], &isArray); + NAPI_ASSERT(env, isArray == true, "type mismatch for parameter 1"); + + for (int32_t i = 0; i < arrayLength; i++) { + int32_t val = napiParcel->nativeParcel_->ReadInt32(); + napi_value num = nullptr; + napi_create_int32(env, val, &num); + napi_set_element(env, argv[0], i, num); + } + napi_value napiValue = nullptr; + NAPI_CALL(env, napi_get_boolean(env, true, &napiValue)); + return napiValue; + } + + if (arrayLength <= 0) { + napi_value result = nullptr; + napi_create_array(env, &result); + return result; + } + CHECK_READ_LENGTH(env, (size_t)arrayLength, BYTE_SIZE_32, napiParcel) + napi_value result = nullptr; + napi_create_array_with_length(env, arrayLength, &result); + + for (int32_t i = 0; i < arrayLength; i++) { + int32_t val = napiParcel->nativeParcel_->ReadInt32(); + napi_value num = nullptr; + napi_create_int32(env, val, &num); + napi_set_element(env, result, i, num); + } + return result; +} + +napi_value NAPI_MessageParcel::JS_readLongArray(napi_env env, napi_callback_info info) +{ + size_t argc = 0; + napi_value thisVar = nullptr; + napi_get_cb_info(env, info, &argc, nullptr, &thisVar, nullptr); + + NAPI_MessageParcel *napiParcel = nullptr; + napi_unwrap(env, thisVar, (void **)&napiParcel); + NAPI_ASSERT(env, napiParcel != nullptr, "napiParcel is null"); + + int32_t arrayLength = napiParcel->nativeParcel_->ReadInt32(); + if (argc > 0) { + NAPI_ASSERT(env, argc == 1, "type mismatch for parameter 1"); + CHECK_READ_LENGTH(env, (size_t)arrayLength, BYTE_SIZE_64, napiParcel) + napi_value argv[1] = {0}; + void *data = nullptr; + napi_get_cb_info(env, info, &argc, argv, &thisVar, &data); + + bool isArray; + napi_is_array(env, argv[0], &isArray); + NAPI_ASSERT(env, isArray == true, "type mismatch for parameter 1"); + + for (int32_t i = 0; i < arrayLength; i++) { + int64_t val = napiParcel->nativeParcel_->ReadInt64(); + napi_value num = nullptr; + napi_create_int64(env, val, &num); + napi_set_element(env, argv[0], i, num); + } + napi_value napiValue = nullptr; + NAPI_CALL(env, napi_get_boolean(env, true, &napiValue)); + return napiValue; + } + + if (arrayLength <= 0) { + napi_value result = nullptr; + napi_create_array(env, &result); + return result; + } + CHECK_READ_LENGTH(env, (size_t)arrayLength, BYTE_SIZE_64, napiParcel) + napi_value result = nullptr; + napi_create_array_with_length(env, arrayLength, &result); + + for (int32_t i = 0; i < arrayLength; i++) { + int64_t val = napiParcel->nativeParcel_->ReadInt64(); + napi_value num = nullptr; + napi_create_int64(env, val, &num); + napi_set_element(env, result, i, num); + } + return result; +} + +napi_value NAPI_MessageParcel::JS_readFloatArray(napi_env env, napi_callback_info info) +{ + size_t argc = 0; + napi_value thisVar = nullptr; + napi_get_cb_info(env, info, &argc, nullptr, &thisVar, nullptr); + + NAPI_MessageParcel *napiParcel = nullptr; + napi_unwrap(env, thisVar, (void **)&napiParcel); + NAPI_ASSERT(env, napiParcel != nullptr, "napiParcel is null"); + + int32_t arrayLength = napiParcel->nativeParcel_->ReadInt32(); + if (argc > 0) { + NAPI_ASSERT(env, argc == 1, "type mismatch for parameter 1"); + CHECK_READ_LENGTH(env, (size_t)arrayLength, sizeof(double), napiParcel) + napi_value argv[1] = {0}; + void *data = nullptr; + napi_get_cb_info(env, info, &argc, argv, &thisVar, &data); + + bool isArray; + napi_is_array(env, argv[0], &isArray); + NAPI_ASSERT(env, isArray == true, "type mismatch for parameter 1"); + + for (int32_t i = 0; i < arrayLength; i++) { + // float val = napiParcel->nativeParcel_->ReadFloat(); + double val = napiParcel->nativeParcel_->ReadDouble(); + napi_value num = nullptr; + napi_create_double(env, val, &num); + napi_set_element(env, argv[0], i, num); + } + napi_value napiValue = nullptr; + NAPI_CALL(env, napi_get_boolean(env, true, &napiValue)); + return napiValue; + } + + if (arrayLength <= 0) { + napi_value result = nullptr; + napi_create_array(env, &result); + return result; + } + CHECK_READ_LENGTH(env, (size_t)arrayLength, sizeof(double), napiParcel) + napi_value result = nullptr; + napi_create_array_with_length(env, arrayLength, &result); + + for (int32_t i = 0; i < arrayLength; i++) { + // float val = napiParcel->nativeParcel_->ReadFloat(); + double val = napiParcel->nativeParcel_->ReadDouble(); + napi_value num = nullptr; + napi_create_double(env, val, &num); + napi_set_element(env, result, i, num); + } + return result; +} + +napi_value NAPI_MessageParcel::JS_readDoubleArray(napi_env env, napi_callback_info info) +{ + size_t argc = 0; + napi_value thisVar = nullptr; + napi_get_cb_info(env, info, &argc, nullptr, &thisVar, nullptr); + + NAPI_MessageParcel *napiParcel = nullptr; + napi_unwrap(env, thisVar, (void **)&napiParcel); + NAPI_ASSERT(env, napiParcel != nullptr, "napiParcel is null"); + + int32_t arrayLength = napiParcel->nativeParcel_->ReadInt32(); + if (argc > 0) { + NAPI_ASSERT(env, argc == 1, "type mismatch for parameter 1"); + CHECK_READ_LENGTH(env, (size_t)arrayLength, sizeof(double), napiParcel) + napi_value argv[1] = {0}; + void *data = nullptr; + napi_get_cb_info(env, info, &argc, argv, &thisVar, &data); + + bool isArray; + napi_is_array(env, argv[0], &isArray); + NAPI_ASSERT(env, isArray == true, "type mismatch for parameter 1"); + + for (int32_t i = 0; i < arrayLength; i++) { + double val = napiParcel->nativeParcel_->ReadDouble(); + napi_value num = nullptr; + napi_create_double(env, val, &num); + napi_set_element(env, argv[0], i, num); + } + napi_value napiValue = nullptr; + NAPI_CALL(env, napi_get_boolean(env, true, &napiValue)); + return napiValue; + } + + if (arrayLength <= 0) { + napi_value result = nullptr; + napi_create_array(env, &result); + return result; + } + CHECK_READ_LENGTH(env, (size_t)arrayLength, sizeof(double), napiParcel) + napi_value result = nullptr; + napi_create_array_with_length(env, arrayLength, &result); + + for (int32_t i = 0; i < arrayLength; i++) { + double val = napiParcel->nativeParcel_->ReadDouble(); + napi_value num = nullptr; + napi_create_double(env, val, &num); + napi_set_element(env, result, i, num); + } + return result; +} + +napi_value NAPI_MessageParcel::JS_readBooleanArray(napi_env env, napi_callback_info info) +{ + size_t argc = 0; + napi_value thisVar = nullptr; + napi_get_cb_info(env, info, &argc, nullptr, &thisVar, nullptr); + + NAPI_MessageParcel *napiParcel = nullptr; + napi_unwrap(env, thisVar, (void **)&napiParcel); + NAPI_ASSERT(env, napiParcel != nullptr, "napiParcel is null"); + + int32_t arrayLength = napiParcel->nativeParcel_->ReadInt32(); + if (argc > 0) { + NAPI_ASSERT(env, argc == 1, "type mismatch for parameter 1"); + CHECK_READ_LENGTH(env, (size_t)arrayLength, BYTE_SIZE_32, napiParcel) + napi_value argv[1] = {0}; + void *data = nullptr; + napi_get_cb_info(env, info, &argc, argv, &thisVar, &data); + + bool isArray; + napi_is_array(env, argv[0], &isArray); + NAPI_ASSERT(env, isArray == true, "type mismatch for parameter 1"); + + for (int32_t i = 0; i < arrayLength; i++) { + int8_t val = napiParcel->nativeParcel_->ReadInt8(); + napi_value boolean = nullptr; + napi_get_boolean(env, val, &boolean); + napi_set_element(env, argv[0], i, boolean); + } + napi_value napiValue = nullptr; + NAPI_CALL(env, napi_get_boolean(env, true, &napiValue)); + return napiValue; + } + + if (arrayLength <= 0) { + napi_value result = nullptr; + napi_create_array(env, &result); + return result; + } + + CHECK_READ_LENGTH(env, (size_t)arrayLength, BYTE_SIZE_32, napiParcel) + napi_value result = nullptr; + napi_create_array_with_length(env, arrayLength, &result); + + for (int32_t i = 0; i < arrayLength; i++) { + int8_t val = napiParcel->nativeParcel_->ReadInt8(); + napi_value boolean = nullptr; + napi_get_boolean(env, val, &boolean); + napi_set_element(env, result, i, boolean); + } + return result; +} + +napi_value NAPI_MessageParcel::JS_readCharArray(napi_env env, napi_callback_info info) +{ + size_t argc = 0; + napi_value thisVar = nullptr; + napi_get_cb_info(env, info, &argc, nullptr, &thisVar, nullptr); + + NAPI_MessageParcel *napiParcel = nullptr; + napi_unwrap(env, thisVar, (void **)&napiParcel); + NAPI_ASSERT(env, napiParcel != nullptr, "napiParcel is null"); + + int32_t arrayLength = napiParcel->nativeParcel_->ReadInt32(); + if (argc > 0) { + NAPI_ASSERT(env, argc == 1, "type mismatch for parameter 1"); + CHECK_READ_LENGTH(env, (size_t)arrayLength, BYTE_SIZE_32, napiParcel) + napi_value argv[1] = {0}; + void *data = nullptr; + napi_get_cb_info(env, info, &argc, argv, &thisVar, &data); + + bool isArray; + napi_is_array(env, argv[0], &isArray); + NAPI_ASSERT(env, isArray == true, "type mismatch for parameter 1"); + + for (int32_t i = 0; i < arrayLength; i++) { + uint16_t val = napiParcel->nativeParcel_->ReadUint16(); + napi_value num = nullptr; + napi_create_uint32(env, val, &num); + napi_set_element(env, argv[0], i, num); + } + napi_value napiValue = nullptr; + NAPI_CALL(env, napi_get_boolean(env, true, &napiValue)); + return napiValue; + } + + if (arrayLength <= 0) { + napi_value result = nullptr; + napi_create_array(env, &result); + return result; + } + CHECK_READ_LENGTH(env, (size_t)arrayLength, BYTE_SIZE_32, napiParcel) + napi_value result = nullptr; + napi_create_array_with_length(env, arrayLength, &result); + + for (int32_t i = 0; i < arrayLength; i++) { + uint16_t val = napiParcel->nativeParcel_->ReadUint16(); + napi_value num = nullptr; + napi_create_uint32(env, val, &num); + napi_set_element(env, result, i, num); + } + return result; +} + +napi_value NAPI_MessageParcel::JS_readStringArray(napi_env env, napi_callback_info info) +{ + size_t argc = 0; + napi_value thisVar = nullptr; + napi_get_cb_info(env, info, &argc, nullptr, &thisVar, nullptr); + + NAPI_MessageParcel *napiParcel = nullptr; + napi_unwrap(env, thisVar, (void **)&napiParcel); + NAPI_ASSERT(env, napiParcel != nullptr, "napiParcel is null"); + + int32_t arrayLength = napiParcel->nativeParcel_->ReadInt32(); + if (argc > 0) { + NAPI_ASSERT(env, argc == 1, "type mismatch for parameter 1"); + CHECK_READ_LENGTH(env, (size_t)arrayLength, BYTE_SIZE_32, napiParcel) + napi_value argv[1] = {0}; + void *data = nullptr; + napi_get_cb_info(env, info, &argc, argv, &thisVar, &data); + + bool isArray; + napi_is_array(env, argv[0], &isArray); + NAPI_ASSERT(env, isArray == true, "type mismatch for parameter 1"); + + for (int32_t i = 0; i < arrayLength; i++) { + if (napiParcel->nativeParcel_->GetReadableBytes() <= 0) { + break; + } + std::u16string parcelString = napiParcel->nativeParcel_->ReadString16(); + std::string outString = Str16ToStr8(parcelString.c_str()); + napi_value val = nullptr; + napi_create_string_utf8(env, outString.c_str(), outString.length(), &val); + napi_set_element(env, argv[0], i, val); + } + napi_value napiValue = nullptr; + NAPI_CALL(env, napi_get_boolean(env, true, &napiValue)); + return napiValue; + } + + CHECK_READ_LENGTH(env, (size_t)arrayLength, BYTE_SIZE_32, napiParcel) + napi_value result = nullptr; + napi_create_array(env, &result); + for (int32_t i = 0; i < arrayLength; i++) { + if (napiParcel->nativeParcel_->GetReadableBytes() <= 0) { + break; + } + std::u16string parcelString = napiParcel->nativeParcel_->ReadString16(); + std::string outString = Str16ToStr8(parcelString.c_str()); + napi_value val = nullptr; + napi_create_string_utf8(env, outString.c_str(), outString.length(), &val); + napi_set_element(env, result, i, val); + } + return result; +} + +napi_value NAPI_MessageParcel::JS_readSequenceable(napi_env env, napi_callback_info info) +{ + size_t argc = 1; + napi_value argv[1] = {0}; + napi_value thisVar = nullptr; + void *data = nullptr; + napi_get_cb_info(env, info, &argc, argv, &thisVar, &data); + NAPI_ASSERT(env, argc == 1, "requires 1 parameter"); + + NAPI_MessageParcel *napiParcel = nullptr; + napi_unwrap(env, thisVar, (void **)&napiParcel); + NAPI_ASSERT_BASE(env, napiParcel != nullptr, "napiParcel is null", 0); + + int32_t len = napiParcel->nativeParcel_->ReadInt32(); + bool result = false; + if (len > 0) { + napi_value propKey = nullptr; + const char* propKeyStr = "unmarshalling"; + napi_create_string_utf8(env, propKeyStr, strlen(propKeyStr), &propKey); + napi_value prop = nullptr; + napi_get_property(env, argv[0], propKey, &prop); + + napi_value funcArg[1] = {thisVar}; + napi_value callResult = nullptr; + result = napi_call_function(env, thisVar, prop, 1, funcArg, &callResult); + } + + napi_value napiValue = nullptr; + NAPI_CALL(env, napi_get_boolean(env, result, &napiValue)); + return napiValue; +} + +napi_value NAPI_MessageParcel::JS_create(napi_env env, napi_callback_info info) +{ + // new native parcel object + napi_value constructor = nullptr; + napi_status status = napi_get_reference_value(env, g_messageParcelConsRef, &constructor); + NAPI_ASSERT(env, constructor != nullptr, "failed to get js MessageParcel constructor"); + napi_value jsMessageParcel; + status = napi_new_instance(env, constructor, 0, nullptr, &jsMessageParcel); + NAPI_ASSERT(env, status == napi_ok, "failed to construct js MessageParcel"); + return jsMessageParcel; +} + +napi_value NAPI_MessageParcel::JS_reclaim(napi_env env, napi_callback_info info) +{ + size_t argc = 0; + napi_value thisVar = nullptr; + napi_get_cb_info(env, info, &argc, nullptr, &thisVar, nullptr); + + NAPI_MessageParcel *napiParcel = nullptr; + napi_remove_wrap(env, thisVar, (void**)&napiParcel); + NAPI_ASSERT(env, napiParcel != nullptr, "napiParcel is null"); + delete napiParcel; + // napiParcel->nativeParcel_->FlushBuffer(); + + napi_value result = nullptr; + napi_get_undefined(env, &result); + return result; +} + +napi_value NAPI_MessageParcel::JS_writeRemoteObject(napi_env env, napi_callback_info info) +{ + size_t argc = 1; + napi_value argv[1] = { 0 }; + napi_value thisVar = nullptr; + void *data = nullptr; + napi_get_cb_info(env, info, &argc, argv, &thisVar, &data); + NAPI_ASSERT(env, argc == 1, "requires 1 parameter"); + + napi_value napiValue = nullptr; + sptr remoteObject = NAPI_ohos_rpc_getNativeRemoteObject(env, argv[0]); + if (remoteObject == nullptr) { + NAPI_CALL(env, napi_get_boolean(env, false, &napiValue)); + return napiValue; + } + NAPI_MessageParcel *napiParcel = nullptr; + napi_unwrap(env, thisVar, (void**)&napiParcel); + NAPI_ASSERT(env, napiParcel != nullptr, "napiParcel is null"); + //sptr remoteObject = sptr(reinterpret_cast(value)); + bool result = napiParcel->nativeParcel_->WriteRemoteObject(remoteObject); + NAPI_CALL(env, napi_get_boolean(env, result, &napiValue)); + return napiValue; +} + +napi_value NAPI_MessageParcel::JS_readRemoteObject(napi_env env, napi_callback_info info) +{ + size_t argc = 0; + napi_value thisVar = nullptr; + napi_get_cb_info(env, info, &argc, nullptr, &thisVar, nullptr); + + NAPI_MessageParcel *napiParcel = nullptr; + napi_unwrap(env, thisVar, (void**)&napiParcel); + NAPI_ASSERT_BASE(env, napiParcel != nullptr, "napiParcel is null", 0); + + sptr value = napiParcel->nativeParcel_->ReadRemoteObject(); + napi_value napiValue = NAPI_ohos_rpc_CreateJsRemoteObject(env, value); + //NAPI_CALL(env, napi_create_external(env, (void*)value.GetRefPtr(), nullptr, nullptr, &napiValue)); + return napiValue; +} + +napi_value NAPI_MessageParcel::JS_writeInterfaceToken(napi_env env, napi_callback_info info) +{ + size_t argc = 1; + napi_value argv[1] = { 0 }; + napi_value thisVar = nullptr; + void *data = nullptr; + napi_get_cb_info(env, info, &argc, argv, &thisVar, &data); + NAPI_ASSERT(env, argc == 1, "requires 1 parameter"); + + napi_valuetype valueType; + napi_typeof(env, argv[0], &valueType); + NAPI_ASSERT(env, valueType == napi_string, "type mismatch for parameter"); + + size_t bufferSize = 0; + napi_get_value_string_utf8(env, argv[0], nullptr, 0, &bufferSize); + NAPI_ASSERT(env, bufferSize < 40960, "string length too large"); + + char stringValue[bufferSize + 1]; + size_t jsStringLength = 0; + napi_get_value_string_utf8(env, argv[0], stringValue, bufferSize + 1, &jsStringLength); + NAPI_ASSERT(env, jsStringLength == bufferSize, "string length wrong"); + + NAPI_MessageParcel *napiParcel = nullptr; + napi_unwrap(env, thisVar, (void**)&napiParcel); + NAPI_ASSERT(env, napiParcel != nullptr, "napiParcel is null"); + + std::string parcelString = stringValue; + bool result = napiParcel->nativeParcel_->WriteInterfaceToken(to_utf16(parcelString)); + + napi_value napiValue = nullptr; + NAPI_CALL(env, napi_get_boolean(env, result, &napiValue)); + return napiValue; +} + +napi_value NAPI_MessageParcel::JS_readInterfaceToken(napi_env env, napi_callback_info info) +{ + size_t argc = 0; + napi_value thisVar = nullptr; + napi_get_cb_info(env, info, &argc, nullptr, &thisVar, nullptr); + + NAPI_MessageParcel *napiParcel = nullptr; + napi_unwrap(env, thisVar, (void**)&napiParcel); + NAPI_ASSERT_BASE(env, napiParcel != nullptr, "napiParcel is null", 0); + + std::u16string parcelString = napiParcel->nativeParcel_->ReadInterfaceToken(); + std::string outString = Str16ToStr8(parcelString.c_str()); + napi_value napiValue = nullptr; + napi_create_string_utf8(env, outString.c_str(), outString.length(), &napiValue); + return napiValue; +} + +napi_value NAPI_MessageParcel::Export(napi_env env, napi_value exports) +{ + const std::string className = "MessageParcel"; + napi_property_descriptor properties[] = { + DECLARE_NAPI_STATIC_FUNCTION("create", NAPI_MessageParcel::JS_create), + DECLARE_NAPI_FUNCTION("reclaim", NAPI_MessageParcel::JS_reclaim), + DECLARE_NAPI_FUNCTION("writeByte", NAPI_MessageParcel::JS_writeByte), + DECLARE_NAPI_FUNCTION("writeShort", NAPI_MessageParcel::JS_writeShort), + DECLARE_NAPI_FUNCTION("writeInt", NAPI_MessageParcel::JS_writeInt), + DECLARE_NAPI_FUNCTION("writeLong", NAPI_MessageParcel::JS_writeLong), + DECLARE_NAPI_FUNCTION("writeFloat", NAPI_MessageParcel::JS_writeFloat), + DECLARE_NAPI_FUNCTION("writeDouble", NAPI_MessageParcel::JS_writeDouble), + DECLARE_NAPI_FUNCTION("writeBoolean", NAPI_MessageParcel::JS_writeBoolean), + DECLARE_NAPI_FUNCTION("writeChar", NAPI_MessageParcel::JS_writeChar), + DECLARE_NAPI_FUNCTION("writeStringWithLength", NAPI_MessageParcel::JS_writeStringWithLength), + DECLARE_NAPI_FUNCTION("writeString", NAPI_MessageParcel::JS_writeString), + DECLARE_NAPI_FUNCTION("writeByteArray", NAPI_MessageParcel::JS_writeByteArray), + DECLARE_NAPI_FUNCTION("readByte", NAPI_MessageParcel::JS_readByte), + DECLARE_NAPI_FUNCTION("readShort", NAPI_MessageParcel::JS_readShort), + DECLARE_NAPI_FUNCTION("readInt", NAPI_MessageParcel::JS_readInt), + DECLARE_NAPI_FUNCTION("readLong", NAPI_MessageParcel::JS_readLong), + DECLARE_NAPI_FUNCTION("readFloat", NAPI_MessageParcel::JS_readFloat), + DECLARE_NAPI_FUNCTION("readDouble", NAPI_MessageParcel::JS_readDouble), + DECLARE_NAPI_FUNCTION("readBoolean", NAPI_MessageParcel::JS_readBoolean), + DECLARE_NAPI_FUNCTION("readChar", NAPI_MessageParcel::JS_readChar), + DECLARE_NAPI_FUNCTION("readString", NAPI_MessageParcel::JS_readString), + DECLARE_NAPI_FUNCTION("writeRemoteObject", NAPI_MessageParcel::JS_writeRemoteObject), + DECLARE_NAPI_FUNCTION("readRemoteObject", NAPI_MessageParcel::JS_readRemoteObject), + DECLARE_NAPI_FUNCTION("writeInterfaceToken", NAPI_MessageParcel::JS_writeInterfaceToken), + DECLARE_NAPI_FUNCTION("readInterfaceToken", NAPI_MessageParcel::JS_readInterfaceToken), + DECLARE_NAPI_FUNCTION("getSize", NAPI_MessageParcel::JS_getSize), + DECLARE_NAPI_FUNCTION("getCapacity", NAPI_MessageParcel::JS_getCapacity), + DECLARE_NAPI_FUNCTION("setSize", NAPI_MessageParcel::JS_setSize), + DECLARE_NAPI_FUNCTION("setCapacity", NAPI_MessageParcel::JS_setCapacity), + DECLARE_NAPI_FUNCTION("getWritableBytes", NAPI_MessageParcel::JS_getWritableBytes), + DECLARE_NAPI_FUNCTION("getReadableBytes", NAPI_MessageParcel::JS_getReadableBytes), + DECLARE_NAPI_FUNCTION("getReadPosition", NAPI_MessageParcel::JS_getReadPosition), + DECLARE_NAPI_FUNCTION("getWritePosition", NAPI_MessageParcel::JS_getWritePosition), + DECLARE_NAPI_FUNCTION("rewindWrite", NAPI_MessageParcel::JS_rewindWrite), + DECLARE_NAPI_FUNCTION("rewindRead", NAPI_MessageParcel::JS_rewindRead), + DECLARE_NAPI_FUNCTION("writeSequenceable", NAPI_MessageParcel::JS_writeSequenceable), + DECLARE_NAPI_FUNCTION("writeShortArray", NAPI_MessageParcel::JS_writeShortArray), + DECLARE_NAPI_FUNCTION("writeIntArray", NAPI_MessageParcel::JS_writeIntArray), + DECLARE_NAPI_FUNCTION("writeLongArray", NAPI_MessageParcel::JS_writeLongArray), + DECLARE_NAPI_FUNCTION("writeFloatArray", NAPI_MessageParcel::JS_writeFloatArray), + DECLARE_NAPI_FUNCTION("writeDoubleArray", NAPI_MessageParcel::JS_writeDoubleArray), + DECLARE_NAPI_FUNCTION("writeBooleanArray", NAPI_MessageParcel::JS_writeBooleanArray), + DECLARE_NAPI_FUNCTION("writeCharArray", NAPI_MessageParcel::JS_writeCharArray), + DECLARE_NAPI_FUNCTION("writeStringArray", NAPI_MessageParcel::JS_writeStringArray), + DECLARE_NAPI_FUNCTION("writeSequenceableArray", NAPI_MessageParcel::JS_writeSequenceableArray), + DECLARE_NAPI_FUNCTION("readSequenceable", NAPI_MessageParcel::JS_readSequenceable), + DECLARE_NAPI_FUNCTION("readByteArray", NAPI_MessageParcel::JS_readByteArray), + DECLARE_NAPI_FUNCTION("readShortArray", NAPI_MessageParcel::JS_readShortArray), + DECLARE_NAPI_FUNCTION("readIntArray", NAPI_MessageParcel::JS_readIntArray), + DECLARE_NAPI_FUNCTION("readLongArray", NAPI_MessageParcel::JS_readLongArray), + DECLARE_NAPI_FUNCTION("readFloatArray", NAPI_MessageParcel::JS_readFloatArray), + DECLARE_NAPI_FUNCTION("readDoubleArray", NAPI_MessageParcel::JS_readDoubleArray), + DECLARE_NAPI_FUNCTION("readBooleanArray", NAPI_MessageParcel::JS_readBooleanArray), + DECLARE_NAPI_FUNCTION("readCharArray", NAPI_MessageParcel::JS_readCharArray), + DECLARE_NAPI_FUNCTION("readStringArray", NAPI_MessageParcel::JS_readStringArray), + }; + napi_define_class(env, className.c_str(), className.length(), JS_Constructor, nullptr, + sizeof(properties) / sizeof(properties[0]), properties, &g_messageParcelConstructor); + NAPI_ASSERT(env, g_messageParcelConstructor != nullptr, "define js class MessageParcel failed"); + napi_status status = napi_set_named_property(env, exports, "MessageParcel", g_messageParcelConstructor); + NAPI_ASSERT(env, status == napi_ok, "set property MessageParcel failed"); + status = napi_create_reference(env, g_messageParcelConstructor, 1, &g_messageParcelConsRef); + NAPI_ASSERT(env, status == napi_ok, "create ref to js MessageParcel constructor failed"); + return exports; +} + +napi_value NAPI_MessageParcel::JS_Constructor(napi_env env, napi_callback_info info) +{ + napi_value thisVar = nullptr; + size_t argc = 1; + napi_value argv[1] = { 0 }; + napi_status status = napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr); + NAPI_ASSERT(env, status == napi_ok, "napi get callback info failed"); + MessageParcel* parcel = nullptr; + if (argv[0] != nullptr) { + int64_t tmp = 0; + napi_get_value_int64(env, argv[0], &tmp); + parcel = reinterpret_cast(tmp); + DBINDER_LOGI("parcel addr:%{public}p, %{public}p", parcel, (void*)(tmp)); + NAPI_ASSERT(env, parcel != nullptr, "parcel is null"); + } + // new native parcel object + auto messageParcel = new NAPI_MessageParcel(env, thisVar, parcel); + // connect native object to js thisVar + status = napi_wrap( + env, thisVar, messageParcel, + [](napi_env env, void *data, void *hint) { + DBINDER_LOGI("NAPI_MessageParcel:%{public}p destructed by js callback", data); + delete (reinterpret_cast(data)); + }, + nullptr, nullptr); + NAPI_ASSERT(env, status == napi_ok, "napi wrap message parcel failed"); + return thisVar; +} + +napi_ref NAPI_MessageParcel::getParcelConsRef() +{ + return g_messageParcelConsRef; +} +} // namespace OHOS diff --git a/ipc/native/src/napi/src/napi_remote_object.cpp b/ipc/native/src/napi/src/napi_remote_object.cpp new file mode 100644 index 00000000..631c3327 --- /dev/null +++ b/ipc/native/src/napi/src/napi_remote_object.cpp @@ -0,0 +1,1405 @@ +/* + * Copyright (c) 2021 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_remote_object.h" +#include +#include +#include +#include +#include +#include +#include +#include "napi_message_parcel.h" +#include "napi_message_option.h" +#include "hilog/log.h" +#include "log_tags.h" +#include "ipc_object_stub.h" +#include "ipc_object_proxy.h" +#include "ipc_thread_skeleton.h" +#include "ipc_skeleton.h" +#include "ipc_types.h" +#include "string_ex.h" +//#include "dnetwork_adapter.h" + +namespace OHOS { +static constexpr OHOS::HiviewDFX::HiLogLabel LOG_LABEL = { LOG_CORE, LOG_ID_IPC, "napi_remoteObject" }; +#ifndef TITLE +#define TITLE __PRETTY_FUNCTION__ +#endif +#define DBINDER_LOGE(fmt, args...) \ + (void)OHOS::HiviewDFX::HiLog::Error(LOG_LABEL, "%{public}s %{public}d: " fmt, TITLE, __LINE__, ##args) +#define DBINDER_LOGI(fmt, args...) \ + (void)OHOS::HiviewDFX::HiLog::Info(LOG_LABEL, "%{public}s %{public}d: " fmt, TITLE, __LINE__, ##args) + +/* + * The native DeathRecipient container. + * As an recipient of obituary of service death, + * and pass the message to js Layer. + */ +class NAPIDeathRecipient : public IRemoteObject::DeathRecipient { +public: + explicit NAPIDeathRecipient(napi_env env, napi_value jsRecipient); + + void OnRemoteDied(const wptr &object) override; + + bool Matches(napi_value jsRecipient); + +protected: + virtual ~NAPIDeathRecipient(); + +private: + std::mutex mutex_; + napi_env env_ = nullptr; + napi_ref deathRecipientRef_ = nullptr; +}; + +NAPIDeathRecipient::NAPIDeathRecipient(napi_env env, napi_value jsDeathRecipient) +{ + env_ = env; + napi_status status = napi_create_reference(env_, jsDeathRecipient, 1, &deathRecipientRef_); + NAPI_ASSERT_RETURN_VOID(env, status == napi_ok, "failed to create ref to js death recipient"); +} + +NAPIDeathRecipient::~NAPIDeathRecipient() +{ + if (env_ != nullptr) { + if (deathRecipientRef_ != nullptr) { + napi_status status = napi_delete_reference(env_, deathRecipientRef_); + NAPI_ASSERT_RETURN_VOID(env_, status == napi_ok, "failed to delete ref to js death recipient"); + deathRecipientRef_ = nullptr; + } + } +} + +void NAPIDeathRecipient::OnRemoteDied(const wptr &object) +{ + DBINDER_LOGI("OnRemoteDied called"); + if (deathRecipientRef_ == nullptr) { + DBINDER_LOGE("js death recipient has already removed"); + return; + } + napi_value jsDeathRecipient = nullptr; + napi_get_reference_value(env_, deathRecipientRef_, &jsDeathRecipient); + NAPI_ASSERT_RETURN_VOID(env_, jsDeathRecipient != nullptr, "failed to get js death recipient"); + napi_value onRemoteDied = nullptr; + napi_get_named_property(env_, jsDeathRecipient, "onRemoteDied", &onRemoteDied); + NAPI_ASSERT_RETURN_VOID(env_, onRemoteDied != nullptr, "failed to get property onRemoteDied"); + napi_value return_val = nullptr; + napi_status status = napi_call_function(env_, jsDeathRecipient, onRemoteDied, 0, nullptr, &return_val); + NAPI_ASSERT_RETURN_VOID(env_, status == napi_ok, "failed to call function onRemoteDied"); + + std::lock_guard lockGuard(mutex_); + napi_delete_reference(env_, deathRecipientRef_); + deathRecipientRef_ = nullptr; +} + +bool NAPIDeathRecipient::Matches(napi_value object) +{ + bool result = false; + if (object != nullptr) { + std::lock_guard lockGuard(mutex_); + if (deathRecipientRef_ != nullptr) { + napi_value jsDeathRecipient = nullptr; + napi_get_reference_value(env_, deathRecipientRef_, &jsDeathRecipient); + napi_status status = napi_strict_equals(env_, object, jsDeathRecipient, &result); + if (status != napi_ok) { + DBINDER_LOGI("compares death recipients failed"); + } + } + } + return result; +} + +/* + * List of native NAPIDeathRecipient + */ +class NAPIDeathRecipientList : public RefBase { +public: + NAPIDeathRecipientList(); + + ~NAPIDeathRecipientList(); + + bool Add(const sptr &recipient); + + bool Remove(const sptr &recipient); + + sptr Find(napi_value jsRecipient); +private: + std::mutex mutex_; + std::set> set_; +}; + +NAPIDeathRecipientList::NAPIDeathRecipientList() {} + +NAPIDeathRecipientList::~NAPIDeathRecipientList() +{ + std::lock_guard lockGuard(mutex_); + set_.clear(); +} + +bool NAPIDeathRecipientList::Add(const sptr &recipient) +{ + std::lock_guard lockGuard(mutex_); + auto ret = set_.insert(recipient); + return ret.second; +} + +bool NAPIDeathRecipientList::Remove(const sptr &recipient) +{ + std::lock_guard lockGuard(mutex_); + return (set_.erase(recipient) > 0); +} + +sptr NAPIDeathRecipientList::Find(napi_value jsRecipient) +{ + std::lock_guard lockGuard(mutex_); + for (auto it = set_.begin(); it != set_.end(); it++) { + if ((*it)->Matches(jsRecipient)) { + return *it; + } + } + return nullptr; +} + +class NAPIRemoteProxyHolder { +public: + NAPIRemoteProxyHolder(); + ~NAPIRemoteProxyHolder(); + sptr list_; + sptr object_; +}; + +NAPIRemoteProxyHolder::NAPIRemoteProxyHolder() : list_(nullptr), object_(nullptr) {} + +NAPIRemoteProxyHolder::~NAPIRemoteProxyHolder() +{ + list_ = nullptr; + object_ = nullptr; +} + +namespace { + napi_value g_remoteStubConstructor = nullptr; + napi_ref g_remoteStubConsRef = nullptr; + napi_value g_remoteProxyConstructor = nullptr; + napi_ref g_remoteProxyConsRef = nullptr; + napi_value g_messageOptionConstructor = nullptr; + napi_ref g_messageOptionConsRef = nullptr; +} + +napi_value RemoteProxy_JS_Constructor(napi_env env, napi_callback_info info) +{ + napi_value thisVar = nullptr; + napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr); + // new napi proxy holder instance + auto proxyHolder = new NAPIRemoteProxyHolder(); + // connect native object to js thisVar + napi_status status = napi_wrap( + env, thisVar, proxyHolder, + [](napi_env env, void *data, void *hint) { + DBINDER_LOGI("proxy holder destructed by js callback"); + delete (reinterpret_cast(data)); + }, + nullptr, nullptr); + NAPI_ASSERT(env, status == napi_ok, "wrap js RemoteProxy and native holder failed"); + return thisVar; +} + +EXTERN_C_START +/* + * function for module exports + */ +napi_value NAPIRemoteProxyExport(napi_env env, napi_value exports) +{ + const std::string className = "RemoteProxy"; + napi_property_descriptor properties[] = { + DECLARE_NAPI_FUNCTION("sendRequest", NAPI_RemoteProxy_sendRequest), + DECLARE_NAPI_FUNCTION("addDeathRecipient", NAPI_RemoteProxy_addDeathRecipient), + DECLARE_NAPI_FUNCTION("removeDeathRecipient", NAPI_RemoteProxy_removeDeathRecipient), + DECLARE_NAPI_FUNCTION("getInterfaceDescriptor", NAPI_RemoteProxy_getInterfaceDescriptor), + DECLARE_NAPI_FUNCTION("isObjectDead", NAPI_RemoteProxy_isObjectDead), + DECLARE_NAPI_FUNCTION("getHandle", NAPI_RemoteProxy_getHandle), + }; + napi_define_class(env, className.c_str(), className.length(), RemoteProxy_JS_Constructor, nullptr, + sizeof(properties) / sizeof(properties[0]), properties, &g_remoteProxyConstructor); + NAPI_ASSERT(env, g_remoteProxyConstructor != nullptr, "define js class RemoteProxy failed"); + napi_status status = napi_set_named_property(env, exports, "RemoteProxy", g_remoteProxyConstructor); + NAPI_ASSERT(env, status == napi_ok, "set property RemoteProxy to exports failed"); + status = napi_create_reference(env, g_remoteProxyConstructor, 1, &g_remoteProxyConsRef); + NAPI_ASSERT(env, status == napi_ok, "create ref to js RemoteProxy constructor failed"); + return exports; +} +EXTERN_C_END + +/* + * The native NAPIRemoteObject act as bridger between js and native. + * It received the request from client and pass it js Layer. + */ +class NAPIRemoteObject : public IPCObjectStub { +public: + NAPIRemoteObject(napi_env env, napi_value thisVar, const std::u16string &descriptor); + + ~NAPIRemoteObject() override; + + bool CheckObjectLegality() const override; + + int OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) override; + + napi_ref GetJsObjectRef() const; +private: + napi_env env_ = nullptr; + napi_value thisVar_ = nullptr; + napi_ref thisVarRef_ = nullptr; + struct ThreadLockInfo { + std::mutex mutex; + std::condition_variable condition; + bool ready = false; + }; + struct CallbackParam { + napi_env env; + napi_ref thisVarRef; + uint32_t code; + MessageParcel *data; + MessageParcel *reply; + MessageOption *option; + pid_t callingPid; + pid_t callingUid; + std::string callingDeviceID; + std::string localDeviceID; + ThreadLockInfo *lockInfo; + int result; + }; + void OnJsRemoteRequest(CallbackParam *param); +}; + +/* + * To ensure a better consistency of the life time of + * js RemoteObject and native object, we designed + * a container to save the native object. + */ +class NAPIRemoteObjectHolder : public RefBase { +public: + explicit NAPIRemoteObjectHolder(napi_env env, const std::u16string &descriptor); + ~NAPIRemoteObjectHolder(); + sptr Get(napi_value object); + +private: + std::mutex mutex_; + napi_env env_ = nullptr; + std::u16string descriptor_; + sptr cachedObject_; +}; + +NAPIRemoteObjectHolder::NAPIRemoteObjectHolder(napi_env env, const std::u16string &descriptor) + : env_(env), descriptor_(descriptor), cachedObject_(nullptr) +{} + +NAPIRemoteObjectHolder::~NAPIRemoteObjectHolder() +{ + // free the reference of object. + cachedObject_ = nullptr; +} + +sptr NAPIRemoteObjectHolder::Get(napi_value jsRemoteObject) +{ + std::lock_guard lockGuard(mutex_); + // grab an strong reference to the object, + // so it will not be freed util this reference released. + sptr remoteObject = nullptr; + if (cachedObject_ != nullptr) { + remoteObject = cachedObject_; + } + + if (remoteObject == nullptr) { + remoteObject = new NAPIRemoteObject(env_, jsRemoteObject, descriptor_); + cachedObject_ = remoteObject; + } + return remoteObject; +} + +napi_value RemoteObject_JS_Constructor(napi_env env, napi_callback_info info) +{ + // new napi remote object + size_t argc = 2; + napi_value argv[2] = { 0 }; + napi_value thisVar = nullptr; + napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr); + NAPI_ASSERT(env, argc == 2, "requires 2 parameter"); + + napi_valuetype valueType; + napi_typeof(env, argv[0], &valueType); + NAPI_ASSERT(env, valueType == napi_string, "type mismatch for parameter 1"); + + napi_typeof(env, argv[1], &valueType); + NAPI_ASSERT(env, valueType == napi_number, "type mismatch for parameter 2"); + + uint32_t stringLength = 0; + napi_get_value_uint32(env, argv[1], &stringLength); + NAPI_ASSERT(env, stringLength < 40960, "string length too large"); + + char stringValue[stringLength]; + size_t jsStringLength = 0; + napi_get_value_string_utf8(env, argv[0], stringValue, stringLength, &jsStringLength); + NAPI_ASSERT(env, jsStringLength == stringLength, "string length wrong"); + std::string descriptor = stringValue; + + auto holder = new NAPIRemoteObjectHolder(env, to_utf16(descriptor)); + // connect native object to js thisVar + napi_status status = napi_wrap( + env, thisVar, holder, + [](napi_env env, void *data, void *hint) { + DBINDER_LOGI("NAPIRemoteObjectHolder destructed by js callback"); + delete (reinterpret_cast(data)); + }, + nullptr, nullptr); + NAPI_ASSERT(env, status == napi_ok, "wrap js RemoteObject and native holder failed"); + return thisVar; +} + +EXTERN_C_START +/* + * function for module exports + */ +napi_value NAPIRemoteObjectExport(napi_env env, napi_value exports) +{ + const std::string className = "RemoteObject"; + napi_property_descriptor properties[] = { + DECLARE_NAPI_FUNCTION("getCallingPid", NAPI_RemoteObject_getCallingPid), + DECLARE_NAPI_FUNCTION("getCallingUid", NAPI_RemoteObject_getCallingUid), + }; + napi_define_class(env, className.c_str(), className.length(), RemoteObject_JS_Constructor, nullptr, + sizeof(properties)/sizeof(properties[0]), properties, &g_remoteStubConstructor); + NAPI_ASSERT(env, g_remoteStubConstructor != nullptr, "define js class RemoteObject failed"); + napi_status status = napi_set_named_property(env, exports, "RemoteObject", g_remoteStubConstructor); + NAPI_ASSERT(env, status == napi_ok, "set property RemoteObject to exports failed"); + status = napi_create_reference(env, g_remoteStubConstructor, 1, &g_remoteStubConsRef); + NAPI_ASSERT(env, status == napi_ok, "create ref to js RemoteObject constructor failed"); + return exports; +} +EXTERN_C_END + +NAPIRemoteObject::NAPIRemoteObject(napi_env env, napi_value thisVar, const std::u16string &descriptor) : IPCObjectStub(descriptor) +{ + env_ = env; + thisVar_ = thisVar; + napi_create_reference(env, thisVar_, 1, &thisVarRef_); + NAPI_ASSERT_RETURN_VOID(env, thisVarRef_ != nullptr, "failed to create ref to js RemoteObject"); +} + +NAPIRemoteObject::~NAPIRemoteObject() +{ + DBINDER_LOGI("NAPIRemoteObject Destructor"); + if (thisVarRef_ != nullptr) { + napi_status status = napi_delete_reference(env_, thisVarRef_); + NAPI_ASSERT_RETURN_VOID(env_, status == napi_ok, "failed to delete ref to js RemoteObject"); + thisVarRef_ = nullptr; + } +} + +bool NAPIRemoteObject::CheckObjectLegality() const +{ + return true; +} + +napi_ref NAPIRemoteObject::GetJsObjectRef() const +{ + return thisVarRef_; +} + +int NAPIRemoteObject::OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) +{ + + DBINDER_LOGI("enter OnRemoteRequest"); + if (code == DUMP_TRANSACTION) { + DBINDER_LOGE("DUMP_TRANSACTION data size:%zu", data.GetReadableBytes()); + } + pid_t callingPid = IPCSkeleton::GetCallingPid(); + pid_t callingUid = IPCSkeleton::GetCallingUid(); + std::string callingDeviceID = IPCSkeleton::GetCallingDeviceID(); + std::string localDeviceID = IPCSkeleton::GetLocalDeviceID(); + DBINDER_LOGI("callingPid:%{public}u, callingUid:%{public}u, callingDeviceID:%{public}s, localDeviceId:%{public}s", + callingPid, callingUid, callingDeviceID.c_str(), localDeviceID.c_str()); + std::shared_ptr lockInfo = std::make_shared(); + CallbackParam* param = new (std::nothrow) CallbackParam{ .env = env_, .thisVarRef = thisVarRef_, .code = code, .data = &data, + .reply = &reply, .option = &option, .lockInfo = lockInfo.get(), .callingPid = callingPid, .callingUid = callingUid, + .callingDeviceID = callingDeviceID, .localDeviceID = localDeviceID, .result = 0 }; + OnJsRemoteRequest(param); + DBINDER_LOGI("OnJsRemoteRequest done"); + int ret = param->result; + delete param; + return ret; +} + +void NAPIRemoteObject::OnJsRemoteRequest(CallbackParam *jsParam) +{ + uv_loop_s *loop = nullptr; + napi_get_uv_event_loop(env_, &loop); + + uv_work_t *work = new(std::nothrow) uv_work_t; + if (work == nullptr) { + DBINDER_LOGE("failed to new uv_work_t"); + // delete jsCb; + jsParam->result = -1; + return ; + } + work->data = reinterpret_cast(jsParam); + DBINDER_LOGI("start nv queue work loop"); + uv_queue_work(loop, work, [](uv_work_t *work) {}, [](uv_work_t *work, int status) { + DBINDER_LOGI("enter thread pool"); + // Js Thread + CallbackParam *param = reinterpret_cast(work->data); + napi_value onRemoteRequest = nullptr; + napi_value thisVar = nullptr; + napi_get_reference_value(param->env, param->thisVarRef, &thisVar); + if (thisVar == nullptr) { + DBINDER_LOGE("thisVar is null"); + param->result = -1; + std::unique_lock lock(param->lockInfo->mutex); + param->lockInfo->ready = true; + param->lockInfo->condition.notify_all(); + return; + } + napi_get_named_property(param->env, thisVar, "onRemoteRequest", &onRemoteRequest); + if (onRemoteRequest == nullptr) { + DBINDER_LOGE("get founction onRemoteRequest failed"); + param->result = -1; + std::unique_lock lock(param->lockInfo->mutex); + param->lockInfo->ready = true; + param->lockInfo->condition.notify_all(); + return; + } + // create jsCode + napi_value jsCode; + napi_create_uint32(param->env, param->code, &jsCode); + + // create jsOption + napi_value jsOptionConstructor = nullptr; + napi_get_reference_value(param->env, g_messageOptionConsRef, &jsOptionConstructor); + if (jsOptionConstructor == nullptr) { + DBINDER_LOGE("jsOption constructor is null"); + param->result = -1; + std::unique_lock lock(param->lockInfo->mutex); + param->lockInfo->ready = true; + param->lockInfo->condition.notify_all(); + return; + } + napi_value jsOption; + size_t argc = 2; + napi_value flags = nullptr; + napi_create_int32(param->env, param->option->GetFlags(), &flags); + napi_value waittime = nullptr; + napi_create_int32(param->env, param->option->GetWaitTime(), &waittime); + napi_value argv[2] = { flags, waittime }; + napi_new_instance(param->env, jsOptionConstructor, argc, argv, &jsOption); + if (jsOption == nullptr) { + DBINDER_LOGE("new jsOption failed"); + param->result = -1; + std::unique_lock lock(param->lockInfo->mutex); + param->lockInfo->ready = true; + param->lockInfo->condition.notify_all(); + return; + } + + // create message parcel + napi_value jsParcelConstructor = nullptr; + napi_ref ref = NAPI_MessageParcel::getParcelConsRef(); + napi_get_reference_value(param->env, ref, &jsParcelConstructor); + if (jsParcelConstructor == nullptr) { + DBINDER_LOGE("jsParcel constructor is null"); + param->result = -1; + std::unique_lock lock(param->lockInfo->mutex); + param->lockInfo->ready = true; + param->lockInfo->condition.notify_all(); + return; + } + napi_value jsData; + DBINDER_LOGI("native data parcel:%{public}p", param->data); + napi_value dataParcel; + napi_create_int64(param->env, reinterpret_cast(param->data), &dataParcel); + if (dataParcel == nullptr) { + DBINDER_LOGE("create js object for data parcel address failed"); + param->result = -1; + std::unique_lock lock(param->lockInfo->mutex); + param->lockInfo->ready = true; + param->lockInfo->condition.notify_all(); + return; + } + size_t argc3 = 1; + napi_value argv3[1] = { dataParcel }; + napi_new_instance(param->env, jsParcelConstructor, argc3, argv3, &jsData); + if (jsData == nullptr) { + DBINDER_LOGE("create js data parcel failed"); + param->result = -1; + std::unique_lock lock(param->lockInfo->mutex); + param->lockInfo->ready = true; + param->lockInfo->condition.notify_all(); + return; + } + DBINDER_LOGI("native reply parcel:%{public}p", param->reply); + napi_value jsReply; + napi_value replyParcel; + napi_create_int64(param->env, reinterpret_cast(param->reply), &replyParcel); + if (replyParcel == nullptr) { + DBINDER_LOGE("create js object for reply parcel address failed"); + param->result = -1; + std::unique_lock lock(param->lockInfo->mutex); + param->lockInfo->ready = true; + param->lockInfo->condition.notify_all(); + return; + } + size_t argc4 = 1; + napi_value argv4[1] = { replyParcel }; + napi_new_instance(param->env, jsParcelConstructor, argc4, argv4, &jsReply); + if (jsReply == nullptr) { + DBINDER_LOGE("create js reply parcel failed"); + param->result = -1; + std::unique_lock lock(param->lockInfo->mutex); + param->lockInfo->ready = true; + param->lockInfo->condition.notify_all(); + return; + } + // save old calling pid, uid, device id + napi_value global; + napi_get_global(param->env, &global); + napi_value oldPid; + napi_get_named_property(param->env, global, "callingPid_", &oldPid); + napi_value oldUid; + napi_get_named_property(param->env, global, "callingUid_", &oldUid); + napi_value oldCallingDeviceID; + napi_get_named_property(param->env, global, "callingDeviceID_", &oldCallingDeviceID); + napi_value oldLocalDeviceID; + napi_get_named_property(param->env, global, "localDeviceID_", &oldLocalDeviceID); + + // set new calling pid, uid, device id + napi_value newPid; + napi_create_int32(param->env, static_cast(param->callingPid), &newPid); + napi_set_named_property(param->env, global, "callingPid_", newPid); + napi_value newUid; + napi_create_int32(param->env, static_cast(param->callingUid), &newUid); + napi_set_named_property(param->env, global, "callingUid_", newUid); + napi_value newDeviceID; + napi_create_string_utf8(param->env, param->callingDeviceID.c_str(), param->callingDeviceID.length(), &newDeviceID); + napi_set_named_property(param->env, global, "callingDeviceID_", newDeviceID); + napi_value newLocalDeviceID; + napi_create_string_utf8(param->env, param->localDeviceID.c_str(), param->localDeviceID.length(), &newLocalDeviceID); + napi_set_named_property(param->env, global, "localDeviceID_", newLocalDeviceID); + + // start to call onRemoteRequest + size_t argc2 = 4; + napi_value argv2[] = { jsCode, jsData, jsReply, jsOption }; + napi_value return_val; + napi_status ret = napi_call_function(param->env, thisVar, onRemoteRequest, argc2, argv2, &return_val); + DBINDER_LOGI("call js onRemoteRequest done"); + if (ret != napi_ok) { + DBINDER_LOGE("OnRemoteRequest got exception"); + param->result = ERR_UNKNOWN_TRANSACTION; + } else { + bool result; + napi_get_value_bool(param->env, return_val, &result); + if (!result) { + DBINDER_LOGE("OnRemoteRequest res:%{public}s", result ? "true" : "false"); + param->result = ERR_UNKNOWN_TRANSACTION; + } else { + param->result = ERR_NONE; + } + } + + // reset calling pid, uid, device id + napi_set_named_property(param->env, global, "callingPid_", oldPid); + napi_set_named_property(param->env, global, "callingUid_", oldUid); + napi_set_named_property(param->env, global, "callingDeviceID_", oldCallingDeviceID); + napi_set_named_property(param->env, global, "localDeviceID_", oldLocalDeviceID); + + // notify waiting binder thread + std::unique_lock lock(param->lockInfo->mutex); + param->lockInfo->ready = true; + param->lockInfo->condition.notify_all(); + + /*if (param->code == SYSPROPS_TRANSACTION) { + int result = IPCObjectStub::OnRemoteRequest(param->code, param->data, param->reply, param->option); + if (result != ERR_NONE) { + DBINDER_LOGE("OnRemoteRequest res:%{public}d", result); + param->result = ERR_INVALID_DATA; + return; + } + }*/ + + //delete event; + //delete work; + }); + std::unique_lock lock(jsParam->lockInfo->mutex); + jsParam->lockInfo->condition.wait(lock, [&jsParam] { return jsParam->lockInfo->ready; }); + //std::this_thread::sleep_for(std::chrono::milliseconds(3000)); + DBINDER_LOGI("onJsRemoteRequestDone"); +} + +NAPIRemoteProxyHolder *NAPI_ohos_rpc_getRemoteProxyHolder(napi_env env, napi_value jsRemoteProxy) +{ + NAPIRemoteProxyHolder *proxyHolder = nullptr; + napi_unwrap(env, jsRemoteProxy, (void**)&proxyHolder); + NAPI_ASSERT(env, proxyHolder != nullptr, "failed to get napi remote proxy holder"); + return proxyHolder; +} + +napi_value NAPI_ohos_rpc_CreateJsRemoteObject(napi_env env, const sptr target) +{ + if (target == nullptr) { + DBINDER_LOGE("RemoteObject is null"); + return nullptr; + } + + if (target->CheckObjectLegality()) { + DBINDER_LOGI("napi create js remote object"); + auto object = static_cast(target.GetRefPtr()); + napi_ref ref = object->GetJsObjectRef(); + napi_value jsRemoteObject; + napi_get_reference_value(env, ref, &jsRemoteObject); + NAPI_ASSERT(env, jsRemoteObject != nullptr, "failed to get js RemoteObject"); + return jsRemoteObject; + } + + napi_value constructor = nullptr; + napi_status status = napi_get_reference_value(env, g_remoteProxyConsRef, &constructor); + NAPI_ASSERT(env, constructor != nullptr, "failed to get js RemoteProxy constructor"); + napi_value jsRemoteProxy; + status = napi_new_instance(env, constructor, 0, nullptr, &jsRemoteProxy); + NAPI_ASSERT(env, status == napi_ok, "failed to construct js RemoteProxy"); + NAPIRemoteProxyHolder *proxyHolder = NAPI_ohos_rpc_getRemoteProxyHolder(env, jsRemoteProxy); + proxyHolder->object_ = target; + proxyHolder->list_ = new NAPIDeathRecipientList(); + + return jsRemoteProxy; +} + +sptr NAPI_ohos_rpc_getNativeRemoteObject(napi_env env, napi_value object) +{ + if (object != nullptr) { + bool instanceOfStub = false; + napi_status status = napi_instanceof(env, object, g_remoteStubConstructor, &instanceOfStub); + NAPI_ASSERT(env, status == napi_ok, "failed to check js object type"); + if (instanceOfStub) { + NAPIRemoteObjectHolder *holder = nullptr; + napi_unwrap(env, object, (void**)&holder); + NAPI_ASSERT(env, holder != nullptr, "failed to get napi remote object holder"); + return holder != nullptr ? holder->Get(object) : nullptr; + } + + bool instanceOfProxy = false; + status = napi_instanceof(env, object, g_remoteProxyConstructor, &instanceOfProxy); + NAPI_ASSERT(env, status == napi_ok, "failed to check js object type"); + if (instanceOfProxy) { + NAPIRemoteProxyHolder *holder = NAPI_ohos_rpc_getRemoteProxyHolder(env, object); + return holder != nullptr ? holder->object_ : nullptr; + } + } + return nullptr; +} + +napi_value NAPI_IPCSkeleton_getContextObject(napi_env env, napi_callback_info info) +{ + sptr object = IPCSkeleton::GetContextObject(); + if (object == nullptr) { + DBINDER_LOGE("fatal error, could not get registry object"); + return nullptr; + } + return NAPI_ohos_rpc_CreateJsRemoteObject(env, object); +} + +napi_value NAPI_IPCSkeleton_getCallingPid(napi_env env, napi_callback_info info) +{ + napi_value global; + napi_get_global(env, &global); + napi_value callingPid; + napi_get_named_property(env, global, "callingPid_", &callingPid); + return callingPid; +} + +napi_value NAPI_IPCSkeleton_getCallingUid(napi_env env, napi_callback_info info) +{ + napi_value global; + napi_get_global(env, &global); + napi_value callingUid; + napi_get_named_property(env, global, "callingUid_", &callingUid); + return callingUid; +} + +napi_value NAPI_IPCSkeleton_getCallingDeviceID(napi_env env, napi_callback_info info) +{ + napi_value global; + napi_get_global(env, &global); + napi_value callingDeviceID; + napi_get_named_property(env, global, "callingDeviceID_", &callingDeviceID); + return callingDeviceID; +} + +napi_value NAPI_IPCSkeleton_getLocalDeviceID(napi_env env, napi_callback_info info) +{ + napi_value global; + napi_get_global(env, &global); + napi_value localDeviceID; + napi_get_named_property(env, global, "localDeviceID_", &localDeviceID); + return localDeviceID; +} + +napi_value NAPI_IPCSkeleton_isLocalCalling(napi_env env, napi_callback_info info) +{ + bool isLocal = IPCSkeleton::IsLocalCalling(); + napi_value napiValue = nullptr; + NAPI_CALL(env, napi_get_boolean(env, isLocal, &napiValue)); + return napiValue; +} + +napi_value NAPI_IPCSkeleton_flushCommands(napi_env env, napi_callback_info info) +{ + size_t argc = 1; + napi_value argv[1] = {0}; + napi_value thisVar = nullptr; + void *data = nullptr; + napi_get_cb_info(env, info, &argc, argv, &thisVar, &data); + NAPI_ASSERT(env, argc == 1, "requires 1 parameter"); + + napi_valuetype valueType; + napi_typeof(env, argv[0], &valueType); + NAPI_ASSERT(env, valueType == napi_object, "type mismatch for parameter 1"); + + sptr target = NAPI_ohos_rpc_getNativeRemoteObject(env, argv[0]); + int32_t result = IPCSkeleton::FlushCommands(target); + napi_value napiValue = nullptr; + NAPI_CALL(env, napi_create_int32(env, result, &napiValue)); + return napiValue; +} + +napi_value NAPI_IPCSkeleton_resetCallingIdentity(napi_env env, napi_callback_info info) +{ + std::string identity = IPCSkeleton::ResetCallingIdentity(); + napi_value napiValue = nullptr; + NAPI_CALL(env, napi_create_string_utf8(env, identity.c_str(), identity.length(), &napiValue)); + return napiValue; +} + +napi_value NAPI_IPCSkeleton_setCallingIdentity(napi_env env, napi_callback_info info) +{ + size_t argc = 2; + napi_value argv[2] = {0}; + napi_value thisVar = nullptr; + void *data = nullptr; + napi_get_cb_info(env, info, &argc, argv, &thisVar, &data); + NAPI_ASSERT(env, argc == 2, "requires 2 parameter"); + + napi_valuetype valueType; + napi_typeof(env, argv[0], &valueType); + NAPI_ASSERT(env, valueType == napi_string, "type mismatch for parameter 1"); + + napi_typeof(env, argv[1], &valueType); + NAPI_ASSERT(env, valueType == napi_number, "type mismatch for parameter 2"); + + uint32_t stringLength = 0; + napi_get_value_uint32(env, argv[1], &stringLength); + NAPI_ASSERT(env, stringLength < 40960, "string length too large"); + + char stringValue[stringLength]; + size_t jsStringLength = 0; + napi_get_value_string_utf8(env, argv[0], stringValue, stringLength, &jsStringLength); + NAPI_ASSERT(env, jsStringLength == stringLength, "string length wrong"); + std::string identity = stringValue; + bool result = IPCSkeleton::SetCallingIdentity(identity); + napi_value napiValue = nullptr; + NAPI_CALL(env, napi_get_boolean(env, result, &napiValue)); + return napiValue; +} + +napi_value NAPI_RemoteObject_getCallingPid(napi_env env, napi_callback_info info) +{ + napi_value result; + napi_value thisVar = nullptr; + napi_get_cb_info(env, info, 0, nullptr, &thisVar, nullptr); + sptr nativeObject = NAPI_ohos_rpc_getNativeRemoteObject(env, thisVar); + if ((nativeObject != nullptr) && (!nativeObject->IsProxyObject())) { + IPCObjectStub *target = reinterpret_cast(nativeObject.GetRefPtr()); + uint32_t pid = target->GetCallingPid(); + napi_create_uint32(env, pid, &result); + return result; + } + uint32_t pid = getpid(); + napi_create_uint32(env, pid, &result); + return result; +} + +napi_value NAPI_RemoteObject_getCallingUid(napi_env env, napi_callback_info info) +{ + napi_value result; + napi_value thisVar = nullptr; + napi_get_cb_info(env, info, 0, nullptr, &thisVar, nullptr); + sptr nativeObject = NAPI_ohos_rpc_getNativeRemoteObject(env, thisVar); + if ((nativeObject != nullptr) && (!nativeObject->IsProxyObject())) { + IPCObjectStub *target = reinterpret_cast(nativeObject.GetRefPtr()); + uint32_t uid = target->GetCallingUid(); + napi_create_uint32(env, uid, &result); + return result; + } + uint32_t uid = getuid(); + napi_create_uint32(env, uid, &result); + return result; +} + +// This method runs on a worker thread, no access to the JavaScript +void ExecuteSendRequest(napi_env env, void* data) +{ + SendRequestParam* param = reinterpret_cast(data); + param->errCode = param->target->SendRequest(param->code, param->data, param->reply, param->option); + DBINDER_LOGI("sendRequest done, errCode:%{public}d", param->errCode); +} + +// This method runs on the main thread after 'ExecuteSendRequest' exits +void SendRequestComplete(napi_env env, napi_status status, void* data) +{ + SendRequestParam* param = reinterpret_cast(data); + napi_value result = nullptr; + napi_create_int32(env, param->errCode, &result); + DBINDER_LOGI("sendRequest complete, errCode:%{public}d", param->errCode); + if (param->errCode == 0) { + napi_resolve_deferred(env, param->deferred, result); + } else { + napi_reject_deferred(env, param->deferred, result); + } + napi_delete_async_work(env, param->asyncWork); + delete param; +} + +napi_value SendRequestPromise(napi_env env, sptr target, uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) +{ + napi_deferred deferred = nullptr; + napi_value promise = nullptr; + NAPI_CALL(env, napi_create_promise(env, &deferred, &promise)); + SendRequestParam *sendRquestParam = new SendRequestParam{ + .target = target, + .code = code, + .data = data, + .reply = reply, + .option = option, + .deferred = deferred, + .errCode = -1, + .asyncWork = nullptr + }; + napi_value resourceName = nullptr; + NAPI_CALL(env, napi_create_string_utf8(env, __func__, NAPI_AUTO_LENGTH, &resourceName)); + NAPI_CALL(env, napi_create_async_work(env, nullptr, resourceName, ExecuteSendRequest, SendRequestComplete, + (void*)sendRquestParam, &sendRquestParam->asyncWork)); + NAPI_CALL(env, napi_queue_async_work(env, sendRquestParam->asyncWork)); + DBINDER_LOGI("sendRequest and returns promise"); + return promise; + +} + +napi_value NAPI_RemoteProxy_sendRequest(napi_env env, napi_callback_info info) +{ + DBINDER_LOGI("send request starts"); + size_t argc = 4; + napi_value argv[4] = { 0 }; + napi_value thisVar = nullptr; + napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr); + NAPI_ASSERT(env, argc == 4, "requires 4 parameter"); + napi_valuetype valueType; + napi_typeof(env, argv[0], &valueType); + NAPI_ASSERT(env, valueType == napi_number, "type mismatch for parameter 1"); + napi_typeof(env, argv[1], &valueType); + NAPI_ASSERT(env, valueType == napi_object, "type mismatch for parameter 2"); + napi_typeof(env, argv[2], &valueType); + NAPI_ASSERT(env, valueType == napi_object, "type mismatch for parameter 3"); + napi_typeof(env, argv[3], &valueType); + NAPI_ASSERT(env, valueType == napi_object, "type mismatch for parameter 4"); + + NAPI_MessageParcel *data = nullptr; + napi_status status = napi_unwrap(env, argv[1], (void**)&data); + NAPI_ASSERT(env, status == napi_ok, "failed t0 get data message parcel"); + NAPI_MessageParcel *reply = nullptr; + status = napi_unwrap(env, argv[2], (void**)&reply); + NAPI_ASSERT(env, status == napi_ok, "failed t0 get reply message parcel"); + MessageOption *option = nullptr; + status = napi_unwrap(env, argv[3], (void**)&option); + NAPI_ASSERT(env, option != nullptr, "failed to get message option"); + + int32_t code = 0; + napi_get_value_int32(env, argv[0], &code); + + NAPIRemoteProxyHolder *proxyHolder = nullptr; + status = napi_unwrap(env, thisVar, (void**)&proxyHolder); + NAPI_ASSERT(env, status == napi_ok, "failed to get proxy holder"); + if (proxyHolder == nullptr) { + DBINDER_LOGE("proxy holder is null"); + napi_value undefined; + napi_get_undefined(env, &undefined); + return undefined; + } + + sptr target = proxyHolder->object_; + if (target == nullptr) { + DBINDER_LOGE("Invalid proxy object"); + napi_value undefined; + napi_get_undefined(env, &undefined); + return undefined; + } + return SendRequestPromise(env, target, code, *(data->getMessageParcel()), *(reply->getMessageParcel()), *option); +} + +napi_value NAPI_RemoteProxy_addDeathRecipient(napi_env env, napi_callback_info info) +{ + DBINDER_LOGI("add death recipient"); + size_t argc = 2; + napi_value argv[2] = { 0 }; + napi_value thisVar = nullptr; + void *data = nullptr; + napi_get_cb_info(env, info, &argc, argv, &thisVar, &data); + NAPI_ASSERT(env, argc == 2, "requires 2 parameter"); + napi_valuetype valueType; + napi_typeof(env, argv[0], &valueType); + NAPI_ASSERT(env, valueType == napi_object, "type mismatch for parameter 1"); + napi_typeof(env, argv[1], &valueType); + NAPI_ASSERT(env, valueType == napi_number, "type mismatch for parameter 2"); + int32_t flag = 0; + napi_get_value_int32(env, argv[1], &flag); + + napi_value result; + if (argv[0] == nullptr) { + //JniHelperThrowNullPointerException(env, "the recipient is null"); + napi_get_boolean(env, false, &result); + return result; + } + + NAPIRemoteProxyHolder *proxyHolder = nullptr; + napi_status status = napi_unwrap(env, thisVar, (void**)&proxyHolder); + NAPI_ASSERT(env, status == napi_ok, "failed to get proxy holder"); + if (proxyHolder == nullptr) { + //JniHelperThrowIllegalStateException(env, "Proxy has been finalized!"); + napi_get_boolean(env, false, &result); + return result; + } + sptr target = proxyHolder->object_; + if ((target == nullptr) || !target->IsProxyObject()) { + DBINDER_LOGE("could not add recipient from invalid target"); + napi_get_boolean(env, false, &result); + return result; + } + + sptr nativeRecipient = new NAPIDeathRecipient(env, argv[0]); + if (target->AddDeathRecipient(nativeRecipient)) { + NAPIDeathRecipientList *list = proxyHolder->list_; + if (list->Add(nativeRecipient)) { + napi_get_boolean(env, true, &result); + return result; + } + } + napi_get_boolean(env, false, &result); + return result; +} + +napi_value NAPI_RemoteProxy_removeDeathRecipient(napi_env env, napi_callback_info info) +{ + DBINDER_LOGI("remove death recipient"); + size_t argc = 2; + napi_value argv[2] = { 0 }; + napi_value thisVar = nullptr; + void *data = nullptr; + napi_get_cb_info(env, info, &argc, argv, &thisVar, &data); + NAPI_ASSERT(env, argc == 2, "requires 2 parameter"); + napi_valuetype valueType; + napi_typeof(env, argv[0], &valueType); + NAPI_ASSERT(env, valueType == napi_object, "type mismatch for parameter 1"); + napi_typeof(env, argv[1], &valueType); + NAPI_ASSERT(env, valueType == napi_number, "type mismatch for parameter 2"); + napi_value result; + if (argv[0] == nullptr) { + //JniHelperThrowNullPointerException(env, "the recipient is null"); + napi_get_boolean(env, false, &result); + return result; + } + int32_t flag = 0; + napi_get_value_int32(env, argv[1], &flag); + + NAPIRemoteProxyHolder *proxyHolder = nullptr; + napi_status status = napi_unwrap(env, thisVar, (void**)&proxyHolder); + NAPI_ASSERT(env, status == napi_ok, "failed to get proxy holder"); + if (proxyHolder == nullptr) { + //JniHelperThrowIllegalStateException(env, "Proxy has been finalized!"); + napi_get_boolean(env, false, &result); + return result; + } + sptr target = proxyHolder->object_; + if ((target == nullptr) || !target->IsProxyObject()) { + DBINDER_LOGE("could not remove recipient from invalid target"); + napi_get_boolean(env, false, &result); + return result; + } + // list should not be null here, it should be alloc at create proxy object. + sptr list = proxyHolder->list_; + sptr nativeRecipient = list->Find(argv[0]); + if (nativeRecipient == nullptr) { + DBINDER_LOGE("recipient not found"); + napi_get_boolean(env, false, &result); + return result; + } + target->RemoveDeathRecipient(nativeRecipient); + if (list->Remove(nativeRecipient)) { + napi_get_boolean(env, true, &result); + return result; + } else { + napi_get_boolean(env, false, &result); + return result; + } +} + +napi_value NAPI_RemoteProxy_getInterfaceDescriptor(napi_env env, napi_callback_info info) +{ + DBINDER_LOGI("get inteface descriptor"); + napi_value thisVar = nullptr; + napi_get_cb_info(env, info, 0, 0, &thisVar, nullptr); + NAPIRemoteProxyHolder *holder = nullptr; + napi_status status = napi_unwrap(env, thisVar, (void**)&holder); + NAPI_ASSERT(env, status == napi_ok, "failed to get proxy holder"); + napi_value result; + if (holder == nullptr) { + //JniHelperThrowIllegalStateException(env, "Proxy has been finalized!"); + napi_create_string_utf8(env, "", 0, &result); + return result; + } + IPCObjectProxy *target = reinterpret_cast(holder->object_.GetRefPtr()); + if (target == nullptr) { + DBINDER_LOGE("Invalid proxy object"); + napi_create_string_utf8(env, "", 0, &result); + return result; + } + std::u16string remoteDescriptor = target->GetInterfaceDescriptor(); + napi_create_string_utf8(env, Str16ToStr8(remoteDescriptor).c_str(), NAPI_AUTO_LENGTH, &result); + return result; +} + +napi_value NAPI_RemoteProxy_isObjectDead(napi_env env, napi_callback_info info) +{ + DBINDER_LOGI("call isObjectDead"); + napi_value thisVar = nullptr; + napi_get_cb_info(env, info, 0, 0, &thisVar, nullptr); + NAPIRemoteProxyHolder *holder = nullptr; + napi_status status = napi_unwrap(env, thisVar, (void**)&holder); + NAPI_ASSERT(env, status == napi_ok, "failed to get proxy holder"); + napi_value result; + if (holder == nullptr) { + //JniHelperThrowIllegalStateException(env, "Proxy has been finalized!"); + napi_get_boolean(env, false, &result); + return result; + } + IPCObjectProxy *target = reinterpret_cast(holder->object_.GetRefPtr()); + if (target == nullptr) { + DBINDER_LOGE("Invalid proxy object"); + napi_get_boolean(env, false, &result); + return result; + } + + if (target->IsObjectDead()) { + napi_get_boolean(env, true, &result); + return result; + } else { + napi_get_boolean(env, false, &result); + return result; + } +} + +napi_value NAPI_RemoteProxy_getHandle(napi_env env, napi_callback_info info) +{ + DBINDER_LOGI("call get handle"); + napi_value thisVar = nullptr; + napi_get_cb_info(env, info, 0, 0, &thisVar, nullptr); + NAPIRemoteProxyHolder *holder = nullptr; + napi_status status = napi_unwrap(env, thisVar, (void**)&holder); + NAPI_ASSERT(env, status == napi_ok, "failed to get proxy holder"); + napi_value result; + if (holder == nullptr) { + //JniHelperThrowIllegalStateException(env, "Proxy has been finalized!"); + napi_create_uint32(env, 0, &result); + return result; + } + IPCObjectProxy *target = reinterpret_cast(holder->object_.GetRefPtr()); + if (target == nullptr) { + DBINDER_LOGE("Invalid proxy object"); + napi_create_uint32(env, 0, &result); + return result; + } + uint32_t handle = target->GetHandle(); + napi_create_uint32(env, handle, &result); + return result; +} + +napi_value NAPIIPCSkeleton_JS_Constructor(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; +} + +// get rpc test proxy +napi_value N_API_GetLocalAbility(napi_env env, napi_callback_info info) { + auto samgrProxy = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager(); + sptr object = samgrProxy->GetSystemAbility(1108); + if (object == nullptr) { + DBINDER_LOGE("fatal error, could not get registry object"); + return nullptr; + } + return NAPI_ohos_rpc_CreateJsRemoteObject(env, object); +} + +// get remote rpc test proxy +napi_value N_API_GetRemoteAbility(napi_env env, napi_callback_info info) { + size_t argc = 2; + napi_value argv[2] = { 0 }; + napi_value thisVar = nullptr; + void* data = nullptr; + napi_get_cb_info(env, info, &argc, argv, &thisVar, &data); + NAPI_ASSERT(env, argc == 2, "requires 2 parameter"); + + napi_valuetype valueType; + napi_typeof(env, argv[0], &valueType); + NAPI_ASSERT(env, valueType == napi_string, "type mismatch for parameter 1"); + + napi_typeof(env, argv[1], &valueType); + NAPI_ASSERT(env, valueType == napi_number, "type mismatch for parameter 2"); + + uint32_t stringLength = 0; + napi_get_value_uint32(env, argv[1], &stringLength); + NAPI_ASSERT(env, stringLength < 40960, "string length too large"); + + char stringValue[stringLength]; + size_t jsStringLength = 0; + napi_get_value_string_utf8(env, argv[0], stringValue, stringLength, &jsStringLength); + NAPI_ASSERT(env, jsStringLength == stringLength, "string length wrong"); + std::string remoteDeviceId = stringValue; + DBINDER_LOGI("RpcTest: device id is %{public}s", remoteDeviceId.c_str()); + auto samgrProxy = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager(); + // TODO + sptr object = samgrProxy->GetSystemAbility(1108, remoteDeviceId); + if (object == nullptr) { + DBINDER_LOGE("RpcTest: fatal error, could not get registry object"); + return nullptr; + } + return NAPI_ohos_rpc_CreateJsRemoteObject(env, object); +} + +napi_value N_API_AddLocalAbility(napi_env env, napi_callback_info info) { + size_t argc = 1; + napi_value argv[1] = { 0 }; + napi_value thisVar = nullptr; + napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr); + NAPI_ASSERT(env, argc == 1, "requires 1 parameter"); + + napi_valuetype valueType; + napi_typeof(env, argv[0], &valueType); + NAPI_ASSERT(env, valueType == napi_object, "type mismatch for parameter 1"); + sptr stub = NAPI_ohos_rpc_getNativeRemoteObject(env, argv[0]); + if (stub == nullptr) { + DBINDER_LOGE("fatal error, could not get registry object"); + return nullptr; + } + auto samgrProxy = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager(); + int ret = samgrProxy->AddSystemAbility(1108, stub); + napi_value result = nullptr; + napi_status status; + status = napi_create_int32(env, ret, &result); + NAPI_ASSERT(env, status == napi_ok, "failed to create int32 value"); + return result; +} + +//napi_value N_API_GetRemoteNodeBasicInfo(napi_env env, napi_callback_info info) { +// +// napi_value emptyStringValue; +// napi_create_string_utf8(env, "", 0, &emptyStringValue); +// std::shared_ptr mDnetworkAdapter = Communication::DnetworkAdapter::GetInstance(); +// if (mDnetworkAdapter == nullptr) { +// DBINDER_LOGE("RpcTest: DnetworkAdapter mDnetworkAdapter is null"); +// return emptyStringValue; +// } +// //get remote node list +// std::list> nodesBasicInfo = mDnetworkAdapter->GetRemoteNodesBasicInfo(); +// if (nodesBasicInfo.size() <= 0) { +// DBINDER_LOGE("RpcTest: RemoteList is null"); +// return emptyStringValue; +// } +// // get first node from list +// std::shared_ptr nodeBasicInfo = nodesBasicInfo.front(); +// if (nodeBasicInfo == nullptr) { +// DBINDER_LOGE("RpcTest: nodeBasicInfo is null"); +// return emptyStringValue; +// } +// +// std::string remoteDeviceId = nodeBasicInfo->GetNodeId(); +// napi_value napiValue = nullptr; +// NAPI_CALL(env, napi_create_string_utf8(env, remoteDeviceId.c_str(), remoteDeviceId.length(), &napiValue)); +// return napiValue; +//} + +//napi_value N_API_GetLocalNodeBasicInfo(napi_env env, napi_callback_info info) { +// +// napi_value emptyStringValue; +// napi_create_string_utf8(env, "", 0, &emptyStringValue); +// std::shared_ptr mDnetworkAdapter = Communication::DnetworkAdapter::GetInstance(); +// if (mDnetworkAdapter == nullptr) { +// DBINDER_LOGE("RpcTest: DnetworkAdapter mDnetworkAdapter is null"); +// return emptyStringValue; +// } +// //get local node +// std::shared_ptr nodeInfo = mDnetworkAdapter->GetLocalBasicInfo(); +// if (nodeInfo == nullptr) { +// DBINDER_LOGE("RpcTest: local node is null"); +// return emptyStringValue; +// } +// +// std::string localDeviceId = nodeInfo->GetNodeId(); +// napi_value napiValue = nullptr; +// NAPI_CALL(env, napi_create_string_utf8(env, localDeviceId.c_str(), localDeviceId.length(), &napiValue)); +// return napiValue; +//} + +napi_value N_API_AddRemoteAbility(napi_env env, napi_callback_info info) { + + size_t argc = 1; + napi_value argv[1] = { 0 }; + napi_value thisVar = nullptr; + napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr); + NAPI_ASSERT(env, argc == 1, "requires 1 parameter"); + + napi_valuetype valueType; + napi_typeof(env, argv[0], &valueType); + NAPI_ASSERT(env, valueType == napi_object, "type mismatch for parameter 1"); + sptr stub = NAPI_ohos_rpc_getNativeRemoteObject(env, argv[0]); + if (stub == nullptr) { + DBINDER_LOGE("RpcServer: fatal error, could not registry object"); + return nullptr; + } + auto samgrProxy = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager(); + ISystemAbilityManager::SAExtraProp saExtra; + saExtra.isDistributed = true; + int ret = samgrProxy->AddSystemAbility(1108, stub, saExtra); + napi_value result = nullptr; + napi_status status; + status = napi_create_int32(env, ret, &result); + NAPI_ASSERT(env, status == napi_ok, "failed to create int32 value"); + return result; +} + +EXTERN_C_START +/* + * function for module exports + */ +napi_value NAPIIPCSkeletonExport(napi_env env, napi_value exports) +{ + DBINDER_LOGI("napi_moudule IPCSkeleton Init start..."); + napi_property_descriptor desc[] = { + DECLARE_NAPI_STATIC_FUNCTION("getContextObject", NAPI_IPCSkeleton_getContextObject), + DECLARE_NAPI_STATIC_FUNCTION("getCallingPid", NAPI_IPCSkeleton_getCallingPid), + DECLARE_NAPI_STATIC_FUNCTION("getCallingUid", NAPI_IPCSkeleton_getCallingUid), + DECLARE_NAPI_STATIC_FUNCTION("getCallingDeviceID", NAPI_IPCSkeleton_getCallingDeviceID), + DECLARE_NAPI_STATIC_FUNCTION("getLocalDeviceID", NAPI_IPCSkeleton_getLocalDeviceID), + DECLARE_NAPI_STATIC_FUNCTION("isLocalCalling", NAPI_IPCSkeleton_isLocalCalling), + DECLARE_NAPI_STATIC_FUNCTION("flushCommands", NAPI_IPCSkeleton_flushCommands), + DECLARE_NAPI_STATIC_FUNCTION("resetCallingIdentity", NAPI_IPCSkeleton_resetCallingIdentity), + DECLARE_NAPI_STATIC_FUNCTION("setCallingIdentity", NAPI_IPCSkeleton_setCallingIdentity), + DECLARE_NAPI_STATIC_FUNCTION("getLocalAbility", N_API_GetLocalAbility), + DECLARE_NAPI_STATIC_FUNCTION("addLocalAbility", N_API_AddLocalAbility), + //DECLARE_NAPI_STATIC_FUNCTION("getRemoteNodesBasicInfo", N_API_GetRemoteNodeBasicInfo), + //DECLARE_NAPI_STATIC_FUNCTION("getLocalNodeBasicInfo", N_API_GetLocalNodeBasicInfo), + DECLARE_NAPI_STATIC_FUNCTION("getRemoteAbility", N_API_GetRemoteAbility), + DECLARE_NAPI_STATIC_FUNCTION("addRemoteAbility", N_API_AddRemoteAbility), + }; + NAPI_CALL(env, napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc)); + napi_value result = nullptr; + napi_define_class(env, "IPCSkeleton", NAPI_AUTO_LENGTH, NAPIIPCSkeleton_JS_Constructor, nullptr, + sizeof(desc) / sizeof(desc[0]), desc, &result); + napi_status status = napi_set_named_property(env, exports, "IPCSkeleton", result); + NAPI_ASSERT(env, status == napi_ok, "create ref to js RemoteObject constructor failed"); + DBINDER_LOGI("napi_moudule IPCSkeleton Init end..."); + return exports; +} +EXTERN_C_END + + +napi_value NAPIMessageOption_JS_Constructor(napi_env env, napi_callback_info info) { + size_t argc = 2; + napi_value argv[2] = { 0 }; + napi_value thisVar = nullptr; + napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr); + NAPI_ASSERT(env, argc >= 0, "invalid parameter number"); + int flags = 0; + int waittime = 0; + if (argc == 0) { + flags = MessageOption::TF_SYNC; + waittime = MessageOption::TF_WAIT_TIME; + } else if (argc == 1) { + napi_valuetype valueType; + napi_typeof(env, argv[0], &valueType); + NAPI_ASSERT(env, valueType == napi_number, "type mismatch for parameter 1"); + int32_t jsFlags = 0; + napi_get_value_int32(env, argv[1], &jsFlags); + flags = jsFlags; + waittime = MessageOption::TF_WAIT_TIME; + } else { + napi_valuetype valueType; + napi_typeof(env, argv[0], &valueType); + NAPI_ASSERT(env, valueType == napi_number, "type mismatch for parameter 1"); + napi_typeof(env, argv[1], &valueType); + NAPI_ASSERT(env, valueType == napi_number, "type mismatch for parameter 2"); + int32_t jsFlags = 0; + napi_get_value_int32(env, argv[0], &jsFlags); + int32_t jsWaittime = 0; + napi_get_value_int32(env, argv[1], &jsWaittime); + flags = jsFlags; + waittime = jsWaittime; + } + + auto messageOption = new MessageOption(flags, waittime); + // connect native message option to js thisVar + napi_status status = napi_wrap( + env, thisVar, messageOption, + [](napi_env env, void *data, void *hint) { + DBINDER_LOGI("NAPIMessageOption destructed by js callback"); + delete (reinterpret_cast(data)); + }, + nullptr, nullptr); + NAPI_ASSERT(env, status == napi_ok, "wrap js MessageOption and native option failed"); + return thisVar; +} + +EXTERN_C_START +/* + * function for module exports + */ +napi_value NAPIMessageOptionExport(napi_env env, napi_value exports) +{ + const std::string className = "MessageOption"; + napi_property_descriptor properties[] = { + DECLARE_NAPI_FUNCTION("getFlags", NAPI_ohos_rpc_message_option_get_flags), + DECLARE_NAPI_FUNCTION("setFlags", NAPI_ohos_rpc_message_option_set_flags), + DECLARE_NAPI_FUNCTION("getWaitTime", NAPI_ohos_rpc_message_option_get_waitTime), + DECLARE_NAPI_FUNCTION("setWaitTime", NAPI_ohos_rpc_message_option_set_waitTime), + }; + napi_define_class(env, className.c_str(), className.length(), NAPIMessageOption_JS_Constructor, nullptr, + sizeof(properties) / sizeof(properties[0]), properties, &g_messageOptionConstructor); + NAPI_ASSERT(env, g_messageOptionConstructor != nullptr, "define js class MessageOption failed"); + napi_status status = napi_set_named_property(env, exports, "MessageOption", g_messageOptionConstructor); + NAPI_ASSERT(env, status == napi_ok, "set property MessageOption to exports failed"); + status = napi_create_reference(env, g_messageOptionConstructor, 1, &g_messageOptionConsRef); + NAPI_ASSERT(env, status == napi_ok, "create ref to js MessageOption constructor failed"); + return exports; +} +EXTERN_C_END + +} // namespace OHOS diff --git a/ipc/native/src/napi/src/napi_rpc_native_module.cpp b/ipc/native/src/napi/src/napi_rpc_native_module.cpp new file mode 100644 index 00000000..890ef539 --- /dev/null +++ b/ipc/native/src/napi/src/napi_rpc_native_module.cpp @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2021 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_remote_object.h" +#include +#include +#include +#include "napi/native_api.h" +#include "napi/native_node_api.h" +#include "hilog/log.h" +#include "log_tags.h" +#include "napi_message_parcel.h" + +extern const char _binary_rpc_js_start[]; +extern const char _binary_rpc_js_end[]; + +namespace OHOS { +EXTERN_C_START +static napi_value RPCExport(napi_env env, napi_value exports) { + NAPI_MessageParcel::Export(env, exports); + NAPIIPCSkeletonExport(env, exports); + NAPIRemoteObjectExport(env, exports); + NAPIRemoteProxyExport(env, exports); + NAPIMessageOptionExport(env, exports); + return exports; +} +EXTERN_C_END + +extern "C" __attribute__((visibility("default"))) void NAPI_rpc_GetJSCode(const char **buf, int *bufLen) +{ + if (buf != nullptr) { + *buf = _binary_rpc_js_start; + } + + if (bufLen != nullptr) { + *bufLen = _binary_rpc_js_end - _binary_rpc_js_start; + } +} + +static napi_module RPCModule_ = { + .nm_version = 1, + .nm_flags = 0, + .nm_filename = nullptr, + .nm_register_func = RPCExport, + .nm_modname = "rpc", + .nm_priv = ((void*)0), + .reserved = { 0 } +}; + +/* + * Module register function + */ +extern "C" __attribute__((constructor)) void RegisterModule(void) +{ + napi_module_register(&RPCModule_); +} +} // namesapce OHOS diff --git a/ohos.build b/ohos.build index 07b476a4..5fc6afb0 100755 --- a/ohos.build +++ b/ohos.build @@ -68,6 +68,23 @@ "//foundation/communication/ipc/ipc/test:moduletest", "//foundation/communication/ipc/ipc/native/test:unittest" ] + }, + "ipc_js": { + "module_list": [ + "//foundation/communication/ipc/interfaces/kits/js/napi:rpc" + ], + "inner_kits": [ + { + "type": "so", + "name": "//foundation/communication/ipc/interfaces/kits/js/napi:rpc", + "header": { + "header_files": [ + "napi_remote_object.h" + ], + "header_base": "//foundation/communication/ipc/ipc/native/src/napi/include" + } + } + ] } } } -- Gitee