# 使用JSVM-API接å£è¿›è¡Œè™šæ‹Ÿæœºå¿«ç…§ç›¸å…³å¼€å‘ ## 简介 JavaScript虚拟机(JSVM)的快照创建功能,将当å‰è¿è¡Œæ—¶çš„JavaScript程åºçŠ¶æ€ä¿å˜ä¸ºä¸€ä¸ªå¿«ç…§æ–‡ä»¶ï¼Œè¿™ä¸ªå¿«ç…§æ–‡ä»¶åŒ…å«äº†å½“å‰çš„å †å†…å˜ã€æ‰§è¡Œä¸Šä¸‹æ–‡ã€å‡½æ•°é—包ç‰ä¿¡æ¯ã€‚ ## 基本概念 - **虚拟机å¯åŠ¨å¿«ç…§**:虚拟机在æŸä¸ªç‰¹å®šæ—¶é—´ç‚¹çš„状æ€å¿«ç…§ï¼ŒåŒ…å«äº†å½“å‰è™šæ‹Ÿæœºçš„所有内部状æ€å’Œæ•°æ®ã€‚通过创建一个å¯åŠ¨å¿«ç…§ï¼Œå¯ä»¥åœ¨ä¹‹åŽçš„时间点æ¢å¤è™šæ‹Ÿæœºåˆ°ç›¸åŒçš„状æ€ã€‚ 创建虚拟机å¯åŠ¨å¿«ç…§å¯ä»¥ç®€åŒ–一些å¤æ‚的编程任务,使得在JSVMä¸ç®¡ç†å’Œç»´æŠ¤è™šæ‹Ÿæœºæ›´åŠ 便æ·ï¼Œä½¿ç¨‹åºæ›´åŠ çµæ´»ä¸Žç¨³å®šã€‚ ## 接å£è¯´æ˜Ž | æŽ¥å£ | 功能说明 | |----------------------------|-------------------------------| | OH_JSVM_CreateSnapshot | 用于创建虚拟机的å¯åŠ¨å¿«ç…§ | |OH_JSVM_CreateEnvFromSnapshot| 基于虚拟机的起始快照,创建一个新的环境 | ## 使用示例 ### OH_JSVM_CreateSnapshot & OH_JSVM_CreateEnvFromSnapshot 用于创建和使用虚拟机的å¯åŠ¨å¿«ç…§ã€‚ cpp部分代ç **注æ„事项**: 需è¦åœ¨OH_JSVM_Init的时候,将JSVM对外部的ä¾èµ–注册到initOptions.externalReferencesä¸ã€‚ ```cpp // hello.cpp #include "napi/native_api.h" #include "ark_runtime/jsvm.h" #include <hilog/log.h> #include <fstream> #define LOG_DEMAIN 0x0202 #define LOG_TAG "TEST_TAG" static int g_aa = 0; #define CHECK_RET(theCall) \ do { \ JSVM_Status cond = theCall; \ if ((cond) != JSVM_OK) { \ const JSVM_ExtendedErrorInfo *info; \ OH_JSVM_GetLastErrorInfo(env, &info); \ OH_LOG_ERROR(LOG_APP, "jsvm fail file: %{public}s line: %{public}d ret = %{public}d message = %{public}s", \ __FILE__, __LINE__, cond, info != nullptr ? info->errorMessage : ""); \ return -1; \ } \ } while (0) #define CHECK(theCall) \ do { \ JSVM_Status cond = theCall; \ if ((cond) != JSVM_OK) { \ OH_LOG_ERROR(LOG_APP, "jsvm fail file: %{public}s line: %{public}d ret = %{public}d", __FILE__, __LINE__, \ cond); \ return -1; \ } \ } while (0) // 用于调用theCall并检查其返回值是å¦ä¸ºJSVM_OK。 // 如果ä¸æ˜¯ï¼Œåˆ™è°ƒç”¨GET_AND_THROW_LAST_ERROR处ç†é”™è¯¯å¹¶è¿”回retVal。 #define JSVM_CALL_BASE(env, theCall, retVal) \ do { \ JSVM_Status cond = theCall; \ if (cond != JSVM_OK) { \ const JSVM_ExtendedErrorInfo *info; \ OH_JSVM_GetLastErrorInfo(env, &info); \ OH_LOG_ERROR(LOG_APP, "jsvm fail file: %{public}s line: %{public}d ret = %{public}d message = %{public}s", \ __FILE__, __LINE__, cond, info != nullptr ? info->errorMessage : ""); \ return retVal; \ } \ } while (0) // JSVM_CALL_BASE的简化版本,返回nullptr #define JSVM_CALL(theCall) JSVM_CALL_BASE(env, theCall, nullptr) static const int MAX_BUFFER_SIZE = 128; // CreateHelloString()函数需绑定到JSVM虚拟机, 用于OH_JSVM_CreateSnapshot虚拟机快照的æ£å¸¸åˆ›å»º static JSVM_Value CreateHelloString(JSVM_Env env, JSVM_CallbackInfo info) { JSVM_Value outPut; OH_JSVM_CreateStringUtf8(env, "Hello world!", JSVM_AUTO_LENGTH, &outPut); return outPut; } // æ供外部引用的方å¼ä»¥ä¾¿JavaScript环境å¯ä»¥è°ƒç”¨ç»‘定的函数 static JSVM_CallbackStruct helloCb = {CreateHelloString, nullptr}; static intptr_t externals[] = { (intptr_t)&helloCb, 0, }; static JSVM_Value RunVMScript(JSVM_Env env, std::string &src) { // 打开handleScope作用域 JSVM_HandleScope handleScope; OH_JSVM_OpenHandleScope(env, &handleScope); JSVM_Value jsStr = nullptr; OH_JSVM_CreateStringUtf8(env, src.c_str(), src.size(), &jsStr); // 编译JavaScript代ç JSVM_Script script; OH_JSVM_CompileScript(env, jsStr, nullptr, 0, true, nullptr, &script); // 执行JavaScript代ç JSVM_Value result = nullptr; OH_JSVM_RunScript(env, script, &result); // å…³é—handleScope作用域 OH_JSVM_CloseHandleScope(env, handleScope); return result; } // OH_JSVM_CreateSnapshotçš„æ ·ä¾‹æ–¹æ³• static void CreateVMSnapshot() { // 创建JavaScript虚拟机实例,打开虚拟机作用域 JSVM_VM vm; JSVM_CreateVMOptions vmOptions; memset(&vmOptions, 0, sizeof(vmOptions)); // isForSnapshotting设置该虚拟机是å¦ç”¨äºŽåˆ›å»ºå¿«ç…§ vmOptions.isForSnapshotting = true; OH_JSVM_CreateVM(&vmOptions, &vm); JSVM_VMScope vmScope; OH_JSVM_OpenVMScope(vm, &vmScope); // 创建JavaScript环境,打开环境作用域 JSVM_Env env; // å°†native函数注册æˆJavaScriptå¯è°ƒç”¨çš„方法 JSVM_PropertyDescriptor descriptor[] = { {"createHelloString", nullptr, &helloCb, nullptr, nullptr, nullptr, JSVM_DEFAULT}, }; OH_JSVM_CreateEnv(vm, 1, descriptor, &env); JSVM_EnvScope envScope; OH_JSVM_OpenEnvScope(env, &envScope); // 使用OH_JSVM_CreateSnapshot创建虚拟机的å¯åŠ¨å¿«ç…§ const char *blobData = nullptr; size_t blobSize = 0; JSVM_Env envs[1] = {env}; OH_JSVM_CreateSnapshot(vm, 1, envs, &blobData, &blobSize); // å°†snapshotä¿å˜åˆ°æ–‡ä»¶ä¸ // ä¿å˜å¿«ç…§æ•°æ®ï¼Œ/data/storage/el2/base/files/test_blob.bin为沙箱路径 // 以包å为com.example.jsvm为例,实际文件会ä¿å˜åˆ°/data/app/el2/100/base/com.example.jsvm/files/test_blob.bin std::ofstream file("/data/storage/el2/base/files/test_blob.bin", std::ios::out | std::ios::binary | std::ios::trunc); file.write(blobData, blobSize); file.close(); // å…³é—并销æ¯çŽ¯å¢ƒå’Œè™šæ‹Ÿæœº OH_JSVM_CloseEnvScope(env, envScope); OH_JSVM_DestroyEnv(env); OH_JSVM_CloseVMScope(vm, vmScope); OH_JSVM_DestroyVM(vm); } static void RunVMSnapshot() { // blobData的生命周期ä¸èƒ½çŸäºŽvm的生命周期 // 从文件ä¸è¯»å–snapshot std::vector<char> blobData; std::ifstream file("/data/storage/el2/base/files/test_blob.bin", std::ios::in | std::ios::binary | std::ios::ate); size_t blobSize = file.tellg(); blobData.resize(blobSize); file.seekg(0, std::ios::beg); file.read(blobData.data(), blobSize); file.close(); OH_LOG_INFO(LOG_APP, "Test JSVM RunVMSnapshot read file blobSize = : %{public}ld", blobSize); // 使用快照数æ®åˆ›å»ºè™šæ‹Ÿæœºå®žä¾‹ JSVM_VM vm; JSVM_CreateVMOptions vmOptions; memset(&vmOptions, 0, sizeof(vmOptions)); vmOptions.snapshotBlobData = blobData.data(); vmOptions.snapshotBlobSize = blobSize; OH_JSVM_CreateVM(&vmOptions, &vm); JSVM_VMScope vmScope; OH_JSVM_OpenVMScope(vm, &vmScope); // 从快照ä¸åˆ›å»ºçŽ¯å¢ƒenv JSVM_Env env; OH_JSVM_CreateEnvFromSnapshot(vm, 0, &env); JSVM_EnvScope envScope; OH_JSVM_OpenEnvScope(env, &envScope); // 执行js脚本,快照记录的envä¸å®šä¹‰äº†createHelloString() std::string src = "createHelloString()"; JSVM_Value result = RunVMScript(env, src); // 环境关é—å‰æ£€æŸ¥è„šæœ¬è¿è¡Œç»“æžœ char str[MAX_BUFFER_SIZE]; OH_JSVM_GetValueStringUtf8(env, result, str, MAX_BUFFER_SIZE, nullptr); if (strcmp(str, "Hello world!") !=0) { OH_LOG_ERROR(LOG_APP, "jsvm fail file: %{public}s line: %{public}d", __FILE__, __LINE__); } // å…³é—并销æ¯çŽ¯å¢ƒå’Œè™šæ‹Ÿæœº OH_JSVM_CloseEnvScope(env, envScope); OH_JSVM_DestroyEnv(env); OH_JSVM_CloseVMScope(vm, vmScope); OH_JSVM_DestroyVM(vm); return; } static JSVM_Value AdjustExternalMemory(JSVM_Env env, JSVM_CallbackInfo info) { // 在创建虚拟机快照时,如果å˜åœ¨å¯¹å¤–部的ä¾èµ–,需è¦åœ¨OH_JSVM_Init时,将外部ä¾èµ–注册到initOptions.externalReferencesä¸ // 创建虚拟机快照并将快照ä¿å˜åˆ°æ–‡ä»¶ä¸ CreateVMSnapshot(); // snapshotå¯ä»¥è®°å½•ä¸‹ç‰¹å®šçš„js执行环境,å¯ä»¥è·¨è¿›ç¨‹é€šè¿‡snapshot快速还原出js执行上下文环境 RunVMSnapshot(); JSVM_Value result = nullptr; OH_JSVM_CreateInt32(env, 0, &result); return result; } static JSVM_CallbackStruct param[] = { {.data = nullptr, .callback = AdjustExternalMemory}, }; static JSVM_CallbackStruct *method = param; // AdjustExternalMemory方法别å,供JS调用 static JSVM_PropertyDescriptor descriptor[] = { {"adjustExternalMemory", nullptr, method, nullptr, nullptr, nullptr, JSVM_DEFAULT}, }; // æ ·ä¾‹æµ‹è¯•JS const char *srcCallNative = R"JS(adjustExternalMemory();)JS"; static int32_t TestJSVM() { JSVM_InitOptions initOptions = {0}; JSVM_VM vm; JSVM_Env env = nullptr; JSVM_VMScope vmScope; JSVM_EnvScope envScope; JSVM_HandleScope handleScope; JSVM_Value result; // åˆå§‹åŒ–JavaScript引擎实例 if (g_aa == 0) { g_aa++; initOptions.externalReferences = externals; int argc = 0; char **argv = nullptr; initOptions.argc = &argc; initOptions.argv = argv; CHECK(OH_JSVM_Init(&initOptions)); } // 创建JSVM环境 CHECK(OH_JSVM_CreateVM(nullptr, &vm)); CHECK(OH_JSVM_CreateEnv(vm, sizeof(descriptor) / sizeof(descriptor[0]), descriptor, &env)); CHECK(OH_JSVM_OpenVMScope(vm, &vmScope)); CHECK_RET(OH_JSVM_OpenEnvScope(env, &envScope)); CHECK_RET(OH_JSVM_OpenHandleScope(env, &handleScope)); // 通过script调用测试函数 JSVM_Script script; JSVM_Value jsSrc; CHECK_RET(OH_JSVM_CreateStringUtf8(env, srcCallNative, JSVM_AUTO_LENGTH, &jsSrc)); CHECK_RET(OH_JSVM_CompileScript(env, jsSrc, nullptr, 0, true, nullptr, &script)); CHECK_RET(OH_JSVM_RunScript(env, script, &result)); // 销æ¯JSVM环境 CHECK_RET(OH_JSVM_CloseHandleScope(env, handleScope)); CHECK_RET(OH_JSVM_CloseEnvScope(env, envScope)); CHECK(OH_JSVM_CloseVMScope(vm, vmScope)); CHECK(OH_JSVM_DestroyEnv(env)); CHECK(OH_JSVM_DestroyVM(vm)); return 0; } static napi_value RunTest(napi_env env, napi_callback_info info) { TestJSVM(); return nullptr; } EXTERN_C_START static napi_value Init(napi_env env, napi_value exports) { OH_LOG_INFO(LOG_APP, "JSVM Init"); napi_property_descriptor desc[] = {{"runTest", nullptr, RunTest, nullptr, nullptr, nullptr, napi_default, nullptr}, }; napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc); return exports; } EXTERN_C_END static napi_module demoModule = { .nm_version = 1, .nm_flags = 0, .nm_filename = nullptr, .nm_register_func = Init, .nm_modname = "entry", .nm_priv = ((void *)0), .reserved = {0}, }; extern "C" __attribute__((constructor)) void RegisterEntryModule(void) { napi_module_register(&demoModule); } ``` ArkTS侧示例代ç ```ts @Entry @Component struct Index { @State message: string = 'Hello World'; build() { Row() { Column() { Text(this.message) .fontSize(50) .fontWeight(FontWeight.Bold) .onClick(() => { // runtest napitest.runTest(); }) } .width('100%') } .height('100%') } } ``` 执行结果 在LOGä¸è¾“出:Test JSVM RunVMSnapshot read file blobSize = : 300064