1# 使用JSVM-API接口进行虚拟机快照相关开发 2 3## 简介 4 5JavaScript虚拟机(JSVM)的快照创建功能,将当前运行时的JavaScript程序状态保存为一个快照文件,这个快照文件包含了当前的堆内存、执行上下文、函数闭包等信息。 6 7## 基本概念 8 9- **虚拟机启动快照**:虚拟机在某个特定时间点的状态快照,包含了当前虚拟机的所有内部状态和数据。通过创建一个启动快照,可以在之后的时间点恢复虚拟机到相同的状态。 10 11创建虚拟机启动快照可以简化一些复杂的编程任务,使得在JSVM中管理和维护虚拟机更加便捷,使程序更加灵活与稳定。 12 13## 接口说明 14 15| 接口 | 功能说明 | 16|----------------------------|-------------------------------| 17| OH_JSVM_CreateSnapshot | 用于创建虚拟机的启动快照 | 18|OH_JSVM_CreateEnvFromSnapshot| 基于虚拟机的起始快照,创建一个新的环境 | 19## 使用示例 20 21JSVM-API接口开发流程参考[使用JSVM-API实现JS与C/C++语言交互开发流程](use-jsvm-process.md),本文仅对接口对应C++及ArkTS相关代码进行展示。 22 23### OH_JSVM_CreateSnapshot 24 25用于创建和使用虚拟机的启动快照。 26 27cpp部分代码 28 29```cpp 30// hello.cpp 31#include "napi/native_api.h" 32#include "ark_runtime/jsvm.h" 33#include <hilog/log.h> 34#include <fstream> 35 36// CreateAndUseSnapshot注册回调 37static JSVM_CallbackStruct param[] = { 38 {.data = nullptr, .callback = CreateAndUseSnapshot}, 39}; 40static JSVM_CallbackStruct *method = param; 41// CreateAndUseSnapshot方法别名,供JS调用 42static JSVM_PropertyDescriptor descriptor[] = { 43 {"createAndUseSnapshot", nullptr, method++, nullptr, nullptr, nullptr, JSVM_DEFAULT}, 44}; 45 46static const int MAX_BUFFER_SIZE = 128; 47// CreateHelloString()函数需绑定到JSVM虚拟机, 用于OH_JSVM_CreateSnapshot虚拟机快照的正常创建 48static JSVM_Value CreateHelloString(JSVM_Env env, JSVM_CallbackInfo info) 49{ 50 JSVM_Value outPut; 51 OH_JSVM_CreateStringUtf8(env, "Hello world!", JSVM_AUTO_LENGTH, &outPut); 52 return outPut; 53} 54// 提供外部引用的方式以便JavaScript环境可以调用绑定的函数 55static JSVM_CallbackStruct helloCb = {CreateHelloString, nullptr}; 56// 外部引用 57static intptr_t externals[] = { 58 (intptr_t)&helloCb, 59 0, 60}; 61 62static JSVM_Value RunVMScript(JSVM_Env env, std::string &src) 63{ 64 // 打开handleScope作用域 65 JSVM_HandleScope handleScope; 66 OH_JSVM_OpenHandleScope(env, &handleScope); 67 JSVM_Value jsStr = nullptr; 68 OH_JSVM_CreateStringUtf8(env, src.c_str(), src.size(), &jsStr); 69 // 编译JavaScript代码 70 JSVM_Script script; 71 OH_JSVM_CompileScript(env, jsStr, nullptr, 0, true, nullptr, &script); 72 // 执行JavaScript代码 73 JSVM_Value result = nullptr; 74 OH_JSVM_RunScript(env, script, &result); 75 // 关闭handleScope作用域 76 OH_JSVM_CloseHandleScope(env, handleScope); 77 return result; 78} 79// OH_JSVM_CreateSnapshot的样例方法 80static void CreateVMSnapshot() { 81 // 创建JavaScript虚拟机实例,打开虚拟机作用域 82 JSVM_VM vm; 83 JSVM_CreateVMOptions vmOptions; 84 memset(&vmOptions, 0, sizeof(vmOptions)); 85 // isForSnapshotting设置该虚拟机是否用于创建快照 86 vmOptions.isForSnapshotting = true; 87 OH_JSVM_CreateVM(&vmOptions, &vm); 88 JSVM_VMScope vmScope; 89 OH_JSVM_OpenVMScope(vm, &vmScope); 90 // 创建JavaScript环境,打开环境作用域 91 JSVM_Env env; 92 // 将native函数注册成JavaScript可调用的方法 93 JSVM_PropertyDescriptor descriptor[] = { 94 {"createHelloString", nullptr, &helloCb, nullptr, nullptr, nullptr, JSVM_DEFAULT}, 95 }; 96 OH_JSVM_CreateEnv(vm, 1, descriptor, &env); 97 JSVM_EnvScope envScope; 98 OH_JSVM_OpenEnvScope(env, &envScope); 99 // 使用OH_JSVM_CreateSnapshot创建虚拟机的启动快照 100 const char *blobData = nullptr; 101 size_t blobSize = 0; 102 JSVM_Env envs[1] = {env}; 103 JSVM_Status status = OH_JSVM_CreateSnapshot(vm, 1, envs, &blobData, &blobSize); 104 if (status == JSVM_OK) { 105 OH_LOG_INFO(LOG_APP, "Test JSVM OH_JSVM_CreateSnapshot success, blobSize = : %{public}ld", blobSize); 106 } 107 // 将snapshot保存到文件中 108 // 保存快照数据,/data/storage/el2/base/files/test_blob.bin为沙箱路径 109 // 以包名为com.example.jsvm为例,实际文件会保存到/data/app/el2/100/base/com.example.jsvm/files/test_blob.bin 110 std::ofstream file("/data/storage/el2/base/files/test_blob.bin", 111 std::ios::out | std::ios::binary | std::ios::trunc); 112 file.write(blobData, blobSize); 113 file.close(); 114 // 关闭并销毁环境和虚拟机 115 OH_JSVM_CloseEnvScope(env, envScope); 116 OH_JSVM_DestroyEnv(env); 117 OH_JSVM_CloseVMScope(vm, vmScope); 118 OH_JSVM_DestroyVM(vm); 119} 120static void RunVMSnapshot() { 121 // blobData的生命周期不能短于vm的生命周期 122 // 从文件中读取snapshot 123 std::vector<char> blobData; 124 std::ifstream file("/data/storage/el2/base/files/test_blob.bin", std::ios::in | std::ios::binary | std::ios::ate); 125 size_t blobSize = file.tellg(); 126 blobData.resize(blobSize); 127 file.seekg(0, std::ios::beg); 128 file.read(blobData.data(), blobSize); 129 file.close(); 130 OH_LOG_INFO(LOG_APP, "Test JSVM RunVMSnapshot read file blobSize = : %{public}ld", blobSize); 131 // 使用快照数据创建虚拟机实例 132 JSVM_VM vm; 133 JSVM_CreateVMOptions vmOptions; 134 memset(&vmOptions, 0, sizeof(vmOptions)); 135 vmOptions.snapshotBlobData = blobData.data(); 136 vmOptions.snapshotBlobSize = blobSize; 137 OH_JSVM_CreateVM(&vmOptions, &vm); 138 JSVM_VMScope vmScope; 139 OH_JSVM_OpenVMScope(vm, &vmScope); 140 // 从快照中创建环境env 141 JSVM_Env env; 142 OH_JSVM_CreateEnvFromSnapshot(vm, 0, &env); 143 JSVM_EnvScope envScope; 144 OH_JSVM_OpenEnvScope(env, &envScope); 145 // 执行js脚本,快照记录的env中定义了createHelloString() 146 std::string src = "createHelloString()"; 147 JSVM_Value result = RunVMScript(env, src); 148 // 环境关闭前检查脚本运行结果 149 if (result == nullptr) { 150 OH_JSVM_ThrowError(env, nullptr, "Test JSVM RunVMSnapshot-RunVMScript result is nullptr"); 151 return; 152 } 153 char str[MAX_BUFFER_SIZE]; 154 OH_JSVM_GetValueStringUtf8(env, result, str, MAX_BUFFER_SIZE, nullptr); 155 OH_LOG_INFO(LOG_APP, "Test JSVM RunVMSnapshot-RunVMScript result is: %{public}s", str); 156 // 关闭并销毁环境和虚拟机 157 OH_JSVM_CloseEnvScope(env, envScope); 158 OH_JSVM_DestroyEnv(env); 159 OH_JSVM_CloseVMScope(vm, vmScope); 160 OH_JSVM_DestroyVM(vm); 161 return; 162} 163 164static JSVM_Value CreateAndUseSnapshot(JSVM_Env env, JSVM_CallbackInfo info) 165{ 166 // OH_JSVM_Init(&initOptions)需在开发流程中的RunJsVm()中第一次初始化(只能初始化一次) 167 // JSVM_InitOptions initOptions 赋值是在开发流程中完成的 168 // 创建虚拟机快照并将快照保存到文件中 169 CreateVMSnapshot(); 170 // snapshot可以记录下特定的js执行环境,可以跨进程通过snapshot快速还原出js执行上下文环境 171 RunVMSnapshot(); 172 JSVM_Value result = nullptr; 173 OH_JSVM_CreateInt32(env, 0, &result); 174 return result; 175} 176``` 177 178ArkTS侧示例代码 179 180```ts 181import hilog from "@ohos.hilog" 182// 通过import的方式,引入Native能力。 183import napitest from "libentry.so" 184let script: string = ` 185 createAndUseSnapshot() 186` 187try { 188 let result = napitest.runJsVm(script); 189 hilog.info(0x0000, 'testJSVM', 'Test JSVM createAndUseSnapshot: %{public}s', result); 190} catch (error) { 191 hilog.error(0x0000, 'testJSVM', 'Test JSVM createAndUseSnapshot error: %{public}s', error.message); 192} 193``` 194