diff --git a/arkoala-arkts/.gitlab-ci.yml b/arkoala-arkts/.gitlab-ci.yml index 2f836098fb20404832f277050cdd7855e5109f7d..6adcdf502acabe7938d08c93ea446263e14e4aca 100644 --- a/arkoala-arkts/.gitlab-ci.yml +++ b/arkoala-arkts/.gitlab-ci.yml @@ -313,7 +313,7 @@ install node modules (arkoala-arkts): - !reference [.setup, script] - npm run panda:sdk:install --prefix arkoala-arkts script: - - npm run har-arm32 --prefix arkoala-arkts/user + - npm run har-arm32 --prefix arkoala-arkts/trivial/user - mv arkoala-arkts/user/app/user/build/default/outputs/default/user.har user-arm32.har artifacts: paths: diff --git a/arkoala-arkts/arkui/src/Application.ts b/arkoala-arkts/arkui/src/Application.ts index 07c54f37eeaa2969331cc814428673b687cb0c1d..df0f3e77354200f04518068900dffaae8561aff6 100644 --- a/arkoala-arkts/arkui/src/Application.ts +++ b/arkoala-arkts/arkui/src/Application.ts @@ -24,6 +24,7 @@ import { ClickEvent, ClickEventInternal } from "./generated/ArkClickEventMateria import { checkEvents, setCustomEventsChecker } from "./generated/Events" import { checkArkoalaCallbacks } from "./generated/peers/CallbacksChecker" import { setUIDetachedRootCreator } from "./generated/peers/CallbackTransformer" +import { enterForeignContext, leaveForeignContext } from "./handwritten" setCustomEventsChecker(checkArkoalaCallbacks) @@ -255,8 +256,9 @@ export class Application { private render() { if (this.withLog) InteropNativeModule._NativeLog("ARKTS: render") } - - enter(arg0: int32, arg1: int32): boolean { + enter(arg0: int32, arg1: int32, foreignContext: pointer): boolean { + // TODO: maybe + enterForeignContext(foreignContext) if (this.withLog) UserView.startNativeLog(1) if (this.currentCrash) { @@ -269,6 +271,7 @@ export class Application { } catch (error) { if (error instanceof Error) { if (error.stack) { + leaveForeignContext() InteropNativeModule._NativeLog(error.stack!.toString()) return true } @@ -287,6 +290,7 @@ export class Application { } } } + leaveForeignContext() return this.exitApp } diff --git a/arkoala-arkts/arkui/src/handwritten/ForeignFunctions.ts b/arkoala-arkts/arkui/src/handwritten/ForeignFunctions.ts new file mode 100644 index 0000000000000000000000000000000000000000..eff5fabb00001a463b0e902142cd8a17ba0cd117 --- /dev/null +++ b/arkoala-arkts/arkui/src/handwritten/ForeignFunctions.ts @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { int32 } from "@koalaui/common" +import { pointer, nullptr, InteropNativeModule, SerializerBase } from "@koalaui/interop" + +let foreignContext: pointer = nullptr + +export function enterForeignContext(context: pointer) { + foreignContext = context +} + +export function leaveForeignContext() { + foreignContext = nullptr +} + +export function setTimeoutForeign(code: () => void, delay: int32): int32 { + if (foreignContext == nullptr) throw new Error("null foreign VM context") + let serializer = new SerializerBase() + serializer.writeInt32(1) + serializer.holdAndWriteCallback(code) + serializer.writeInt32(delay) + let rv = InteropNativeModule._CallForeignVM(foreignContext, 3, serializer.asArray(), serializer.length()) + serializer.release() + return rv +} diff --git a/arkoala-arkts/arkui/src/handwritten/index.ts b/arkoala-arkts/arkui/src/handwritten/index.ts index 51e7b1472a50e0470041b5400ad44cf38fcc60ee..bbf766e8fe7f7611134a9b56eeb19f10e08ece87 100644 --- a/arkoala-arkts/arkui/src/handwritten/index.ts +++ b/arkoala-arkts/arkui/src/handwritten/index.ts @@ -1,6 +1,7 @@ export * from "./ArkPageTransition" export * from "./ArkPageTransitionData" export * from "./Router" +export * from "./ForeignFunctions" // TODO: implement this diff --git a/arkoala-arkts/loader/src/loader.ts b/arkoala-arkts/loader/src/loader.ts index c59eab18a468b4c3cb54c9a4fe291bd8ad5bbe27..8936e229e7ea669915fc0c9c0b484149afd0acc5 100644 --- a/arkoala-arkts/loader/src/loader.ts +++ b/arkoala-arkts/loader/src/loader.ts @@ -37,6 +37,8 @@ export interface LoaderOps { _LoadVirtualMachine(vmKind: int32, appClassPath: string, appLibPath: string): int32 _StartApplication(appUrl: string, appParams: string): KPointer _RunApplication(arg0: int32, arg1: int32): boolean + _SetCallbackDispatcher(dispather: Object): void + _CallCallbackSync(kind: int32, data: Uint8Array, length: int32): void } export interface NativeControl extends LoaderOps { @@ -47,6 +49,14 @@ export interface NativeControl extends LoaderOps { _EmitEvent(type: int32, target: int32, arg0: int32, arg1: int32): void } +function callCallback(id: int32, args: KUint8ArrayPtr, length: int32): int32 { + console.log(`callCallback: ${id} data is ${length} bytes`) + if (id == 3) { + // TODO: implement setTimeout here. + } + return 0 +} + let theModule: NativeControl | undefined = undefined declare const LOAD_NATIVE: object @@ -60,6 +70,7 @@ export function nativeModule(): NativeControl { for (const moduleName of Object.keys(modules)) { Object.assign(theModule, modules[moduleName]) // TODO freeze? } + theModule._SetCallbackDispatcher(callCallback) return theModule } diff --git a/arkoala-arkts/package.json b/arkoala-arkts/package.json index 9ffcaff2a173d6db36aba3097f360148520d0d4c..2210b901374568511a41f72ba248fb90c9ebbef7 100644 --- a/arkoala-arkts/package.json +++ b/arkoala-arkts/package.json @@ -82,7 +82,7 @@ "trivial:node": "npm run build:user && npm run build:loader:node && npm run run:node:user", "shopping:all:node": "npm run compile:native:node-host && npm run build:arkoala && npm run build:shopping && npm run build:loader:node && npm run run:node:shopping", "shopping:node": "npm run build:user && npm run build:loader:node && npm run run:node:shopping", - "clean:shopping": "npm run clean --prefix shopping", + "clean:shopping": "npm run clean:all --prefix shopping/user", "trivial:all:node:ci": "npm run compile:native:node-host && npm run build:arkoala && npm run build:user && npm run build:loader:node && npm run run:node:ci", "arkoala:har-arm32": "npm run compile:native:hzvm-ohos-arm32 && npm run build:arkoala && npm run har-arm32 --prefix har", "arkoala:har-arm64": "npm run compile:native:hzvm-ohos-arm64 && npm run build:arkoala && npm run har-arm64 --prefix har", diff --git a/arkoala/framework/src/Application.ts b/arkoala/framework/src/Application.ts index 85be4230c057ada3510531397e72eba46b7791dc..07af09551bd7b36dee6ade5e81ab74adbdada820 100644 --- a/arkoala/framework/src/Application.ts +++ b/arkoala/framework/src/Application.ts @@ -21,7 +21,6 @@ import { ArkoalaControlImpl } from "./ArkoalaControl" import { withString, KPointer } from "@koalaui/interop" import { PeerNode } from "./PeerNode" import { int32 } from "@koalaui/common" -import { ArkUINodeId } from "./ArkUINodeType" import { loadNative } from "./load_native" // import { initInteropModule } from "./generated/NativeModule" diff --git a/interop/src/arkts/InteropNativeModule.sts b/interop/src/arkts/InteropNativeModule.sts index 35ddcfb8121c7c4ec98dac6a30d59d2cc2fd463b..9b74e2e839b506c42da1ccc6a87858de9affd7eb 100644 --- a/interop/src/arkts/InteropNativeModule.sts +++ b/interop/src/arkts/InteropNativeModule.sts @@ -10,32 +10,33 @@ export class InteropNativeModule { static callCallbackFromNative(id: KInt, args: KUint8ArrayPtr, length: KInt): KInt { return callCallback(id, args, length) } - native static _GetGroupedLog(index: int32): KPointer - native static _StartGroupedLog(index: int32): void - native static _StopGroupedLog(index: int32): void - native static _AppendGroupedLog(index: int32, message: string): void - native static _PrintGroupedLog(index: int32): void - native static _GetStringFinalizer(): KPointer - native static _InvokeFinalizer(ptr1: KPointer, ptr2: KPointer): void - native static _GetPtrVectorElement(ptr1: KPointer, arg: int32): KPointer - native static _StringLength(ptr1: KPointer): int32 - native static _StringData(ptr1: KPointer, arr: KUint8ArrayPtr, i: int32): void - native static _StringMake(str1: string): KPointer - native static _GetPtrVectorSize(ptr1: KPointer): int32 - native static _ManagedStringWrite(str1: string, arr: KUint8ArrayPtr, arg: int32): int32 - native static _NativeLog(str1: string): void - native static _Utf8ToString(data: KUint8ArrayPtr, offset: int32, length: int32): string - native static _StdStringToString(cstring: KPointer): string + native static _GetGroupedLog(index: int32): KPointer + native static _StartGroupedLog(index: int32): void + native static _StopGroupedLog(index: int32): void + native static _AppendGroupedLog(index: int32, message: string): void + native static _PrintGroupedLog(index: int32): void + native static _GetStringFinalizer(): KPointer + native static _InvokeFinalizer(ptr1: KPointer, ptr2: KPointer): void + native static _GetPtrVectorElement(ptr1: KPointer, arg: int32): KPointer + native static _StringLength(ptr1: KPointer): int32 + native static _StringData(ptr1: KPointer, arr: KUint8ArrayPtr, i: int32): void + native static _StringMake(str1: string): KPointer + native static _GetPtrVectorSize(ptr1: KPointer): int32 + native static _ManagedStringWrite(str1: string, arr: KUint8ArrayPtr, arg: int32): int32 + native static _NativeLog(str1: string): void + native static _Utf8ToString(data: KUint8ArrayPtr, offset: int32, length: int32): string + native static _StdStringToString(cstring: KPointer): string native static _CheckCallbackEvent(buffer: KUint8ArrayPtr, bufferLength: int32): int32 native static _HoldCallbackResource(resourceId: int32): void native static _ReleaseCallbackResource(resourceId: int32): void - native static _CallCallback(callbackKind: int32, args: KUint8ArrayPtr, argsSize: int32): void - native static _CallCallbackSync(callbackKind: int32, args: KUint8ArrayPtr, argsSize: int32): void - native static _CallCallbackResourceHolder(holder: KPointer, resourceId: int32): void - native static _CallCallbackResourceReleaser(releaser: KPointer, resourceId: int32): void - native static _LoadVirtualMachine(arg0: int32, arg1: string, arg2: string): int32 - native static _RunApplication(arg0: int32, arg1: int32): boolean - native static _StartApplication(appUrl: string, appParams: string): KPointer - native static _EmitEvent(eventType: int32, target: int32, arg0: int32, arg1: int32): void + native static _CallCallback(callbackKind: int32, args: KUint8ArrayPtr, argsSize: int32): void + native static _CallCallbackSync(callbackKind: int32, args: KUint8ArrayPtr, argsSize: int32): void + native static _CallCallbackResourceHolder(holder: KPointer, resourceId: int32): void + native static _CallCallbackResourceReleaser(releaser: KPointer, resourceId: int32): void + native static _LoadVirtualMachine(arg0: int32, arg1: string, arg2: string): int32 + native static _RunApplication(arg0: int32, arg1: int32): boolean + native static _StartApplication(appUrl: string, appParams: string): KPointer + native static _EmitEvent(eventType: int32, target: int32, arg0: int32, arg1: int32): void + native static _CallForeignVM(context:KPointer, callback: int32, data: KUint8ArrayPtr, dataLength: int32): int32 } diff --git a/interop/src/cpp/common-interop.cc b/interop/src/cpp/common-interop.cc index 7c4008643b0b9b4fbf0627735038ad3e1eb944fd..6a7160f65b0510a55347e9534ee44b8462511607 100644 --- a/interop/src/cpp/common-interop.cc +++ b/interop/src/cpp/common-interop.cc @@ -244,7 +244,19 @@ void impl_PrintGroupedLog(KInt index) { } KOALA_INTEROP_V1(PrintGroupedLog, KInt) -typedef KInt (*LoadVirtualMachine_t)(KInt vmKind, const char* classPath, const char* libraryPath, void* currentVMContext); +int32_t callCallback(KVMContext context, int32_t methodId, uint8_t* argsData, int32_t argsLength) { +#if KOALA_USE_NODE_VM || KOALA_USE_HZ_VM || KOALA_USE_PANDA_VM || KOALA_USE_JAVA_VM || KOALA_CJ + KOALA_INTEROP_CALL_INT(context, methodId, argsLength, argsData); +#else + return 0; +#endif +} + +struct ForeignVMContext { + KVMContext vmContext; + int32_t (*callSync)(KVMContext vmContext, int32_t callback, uint8_t* data, int32_t length); +}; +typedef KInt (*LoadVirtualMachine_t)(KInt vmKind, const char* classPath, const char* libraryPath, const struct ForeignVMContext* foreignVM); typedef KNativePointer (*StartApplication_t)(const char* appUrl, const char* appParams); typedef KBoolean (*RunApplication_t)(const KInt arg0, const KInt arg1); typedef void (*EmitEvent_t)(const KInt type, const KInt target, const KInt arg0, const KInt arg1); @@ -276,7 +288,10 @@ KInt impl_LoadVirtualMachine(KVMContext vmContext, KInt vmKind, const KStringPtr static LoadVirtualMachine_t impl = nullptr; if (!impl) impl = reinterpret_cast(getImpl(nativeLibPath, "LoadVirtualMachine")); if (!impl) KOALA_INTEROP_THROW_STRING(vmContext, "Cannot load VM", -1); - return impl(vmKind, appClassPath, nativeLibPath, vmContext); + const ForeignVMContext foreignVM = { + vmContext, &callCallback + }; + return impl(vmKind, appClassPath, nativeLibPath, &foreignVM); } KOALA_INTEROP_CTX_3(LoadVirtualMachine, KInt, KInt, KStringPtr, KStringPtr) @@ -335,6 +350,18 @@ void impl_CallCallbackResourceReleaser(KNativePointer releaser, KInt resourceId) } KOALA_INTEROP_V2(CallCallbackResourceReleaser, KNativePointer, KInt) +KInt impl_CallForeignVM(KNativePointer foreignContextRaw, KInt function, KByte* data, KInt length) { + const ForeignVMContext* foreignContext = (const ForeignVMContext*)foreignContextRaw; + // TODO: set actuall callbacks caller/holder/releaser. + /* + *(int64_t*)(data + 8) = impl_CallCallbackSync; + *(int64_t*)(data + 16) = 0; + *(int64_t*)(data + 24) = 0; */ + return foreignContext->callSync(foreignContext->vmContext, function, data, length); +} +KOALA_INTEROP_4(CallForeignVM, KInt, KNativePointer, KInt, KByte*, KInt) + + #define __QUOTE(x) #x #define QUOTE(x) __QUOTE(x) @@ -349,13 +376,6 @@ void impl_NativeLog(const KStringPtr& str) { KOALA_INTEROP_V1(NativeLog, KStringPtr) -int32_t callCallback(KVMContext context, int32_t methodId, uint8_t* argsData, int32_t argsLength) { -#if KOALA_USE_NODE_VM || KOALA_USE_HZ_VM || KOALA_USE_PANDA_VM || KOALA_USE_JAVA_VM || KOALA_CJ - KOALA_INTEROP_CALL_INT(context, methodId, argsLength, argsData); -#else - return 0; -#endif -} void resolveDeferred(KVMDeferred* deferred, uint8_t* argsData, int32_t argsLength) { #ifdef KOALA_NAPI diff --git a/interop/src/cpp/napi/convertors-napi.cc b/interop/src/cpp/napi/convertors-napi.cc index a9b16c83e4b9c4c8d367889a64573865d5d5a4bb..0ae25c213397e73ad5a68a1269d396a8fd34c3c7 100644 --- a/interop/src/cpp/napi/convertors-napi.cc +++ b/interop/src/cpp/napi/convertors-napi.cc @@ -305,6 +305,8 @@ static napi_ref g_koalaNapiCallbackDispatcher = nullptr; // TODO: shall we pass name in globalThis instead of object reference? napi_value Node_SetCallbackDispatcher(napi_env env, napi_callback_info cbinfo) { + fprintf(stderr, "Node_SetCallbackDispatcher!\n"); + CallbackInfo info(env, cbinfo); napi_value dispatcher = info[0]; napi_value result = makeVoid(env); diff --git a/interop/src/cpp/vmloader.cc b/interop/src/cpp/vmloader.cc index f35f1fe7d2d3e71dd2191dffe9337311b61df31f..dcd9bd6e2ec69ecbd3e881d167396ce183cc233d 100644 --- a/interop/src/cpp/vmloader.cc +++ b/interop/src/cpp/vmloader.cc @@ -129,21 +129,21 @@ struct VMInitArgs { #define PANDA_VM_KIND 2 #define ES2PANDA_KIND 3 +struct ForeignVMContext { + void* currentVMContext; + int32_t (*callSync)(void* vmContext, int32_t callback, int8_t* data, int32_t length); +}; + struct VMEntry { int vmKind; void* env; void* app; void* enter; void* emitEvent; - - VMEntry() { - vmKind = 0; - app = nullptr; - enter = nullptr; - } + ForeignVMContext foreignVMContext; }; -VMEntry g_vmEntry; +VMEntry g_vmEntry = {}; typedef int (*createVM_t)(void** pVM, void** pEnv, void* vmInitArgs); typedef int (*getVMs_t)(void** pVM, int32_t bufLen, int32_t* nVMs); @@ -164,7 +164,7 @@ static int ArkMobileLog(int id, int level, const char *component, const char *fm return 0; } -extern "C" DLL_EXPORT KInt LoadVirtualMachine(KInt vmKind, const char* appClassPath, const char* appLibPath, void* currentVMContext) { +extern "C" DLL_EXPORT KInt LoadVirtualMachine(KInt vmKind, const char* appClassPath, const char* appLibPath, const ForeignVMContext* foreignVMContext) { if (vmKind == ES2PANDA_KIND) { return loadES2Panda(appClassPath, appLibPath); } @@ -281,6 +281,7 @@ extern "C" DLL_EXPORT KInt LoadVirtualMachine(KInt vmKind, const char* appClassP return result; } g_vmEntry.env = env; + g_vmEntry.foreignVMContext = *foreignVMContext; return 0; } @@ -304,7 +305,7 @@ const AppInfo javaAppInfo = { "start", "()J", "enter", - "(II)Z", + "(IIJ)Z", "emitEvent", "(IIII)V", }; @@ -318,7 +319,7 @@ const AppInfo pandaAppInfo = { "start", ":J", "enter", - "II:Z", + "IIJ:Z", "emitEvent", "IIII:V", }; @@ -397,7 +398,11 @@ extern "C" DLL_EXPORT KNativePointer StartApplication(const char* appUrl, const #else auto useNativeLog = false; #endif - auto app = etsEnv->NewGlobalRef(etsEnv->CallStaticObjectMethod(appClass, create, etsEnv->NewStringUTF(appUrl), etsEnv->NewStringUTF(appParams), useNativeLog)); + auto app = etsEnv->NewGlobalRef(etsEnv->CallStaticObjectMethod( + appClass, create, + etsEnv->NewStringUTF(appUrl), etsEnv->NewStringUTF(appParams), + useNativeLog + )); if (!app) { LOGE("createApplication returned null"); if (etsEnv->ErrorCheck()) { @@ -441,7 +446,8 @@ extern "C" DLL_EXPORT KBoolean RunApplication(const KInt arg0, const KInt arg1) (jobject)(g_vmEntry.app), (jmethodID)(g_vmEntry.enter), (jint)arg0, - (jint)arg1 + (jint)arg1, + (int64_t)(intptr_t)(&g_vmEntry.foreignVMContext) ); if (jEnv->ExceptionCheck()) { jEnv->ExceptionDescribe(); @@ -461,7 +467,8 @@ extern "C" DLL_EXPORT KBoolean RunApplication(const KInt arg0, const KInt arg1) (ets_object)(g_vmEntry.app), (ets_method)(g_vmEntry.enter), (ets_int)arg0, - (ets_int)arg1 + (ets_int)arg1, + (int64_t)(intptr_t)(&g_vmEntry.foreignVMContext) ); if (etsEnv->ErrorCheck()) { LOGE("Calling enter() method gave an error"); diff --git a/interop/src/interop/InteropNativeModule.ts b/interop/src/interop/InteropNativeModule.ts index 138d28470a95c25dd96b094ffabfa4a090f05b20..b9b177453c3704359b7d3ce6181445ac354c40f9 100644 --- a/interop/src/interop/InteropNativeModule.ts +++ b/interop/src/interop/InteropNativeModule.ts @@ -36,6 +36,7 @@ export class InteropNativeModule { public static _RunApplication(arg0: int32, arg1: int32): number { throw "method not loaded" } public static _StartApplication(appUrl: string, appParams: string): KPointer { throw "method not loaded" } public static _EmitEvent(eventType: int32, target: int32, arg0: int32, arg1: int32): void { throw "method not loaded" } + public static _CallForeignVM(foreignContext: KPointer, kind: int32, args: Uint8Array, argsSize: int32): int32 { throw "method not loaded" } } export function loadInteropNativeModule() {