当前位置:   article > 正文

鸿蒙(API 12 Beta2版)NDK开发【JSVM-API调试&定位】

鸿蒙(API 12 Beta2版)NDK开发【JSVM-API调试&定位】

JSVM,既标准JS引擎,是严格遵守Ecmascript规范的JavaScript代码执行引擎。

基于JSVM的JS代码调试调优能力包括:Debugger、CPU Profiler、Heap Snapshot、Heap Statistics。涉及以下接口:

接口名接口功能
OH_JSVM_GetVM将检索给定环境的虚拟机实例。
OH_JSVM_GetHeapStatistics返回一组虚拟机堆的统计数据。
OH_JSVM_StartCpuProfiler创建并启动一个CPU profiler。
OH_JSVM_StopCpuProfiler停止CPU profiler并将结果输出到流。
OH_JSVM_TakeHeapSnapshot获取当前堆快照并将其输出到流。
OH_JSVM_OpenInspector在指定的主机和端口上激活inspector,将用来调试JS代码。
OH_JSVM_CloseInspector尝试关闭剩余的所有inspector连接。
OH_JSVM_WaitForDebugger等待主机与inspector建立socket连接,连接建立后程序将继续运行。发送Runtime.runIfWaitingForDebugger命令。

本文将介绍调试、CPU Profiler、Heap Snapshot的使用方法。

调试能力使用方法

调试步骤

  1. 在应用工程配置文件module.json中配置网络权限:
"requestPermissions": [{
  "name": "ohos.permission.INTERNET",
  "reason": "$string:app_name",
  "usedScene": {
    "abilities": [
      "FromAbility"
    ],
    "when": "inuse"
  }
}]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  1. 为避免debugger过程中的暂停被误报为无响应异常,可以[开启DevEco Studio的Debug模式](无需设置断点),或者可以在非主线程的其他线程中运行JSVM。
  2. 在执行JS代码之前,调用OH_JSVM_OpenInspector在指定的主机和端口上激活inspector,创建socket。例如OH_JSVM_OpenInspector(env, “localhost”, 9225),在端侧本机端口9225创建socket。
  3. 调用OH_JSVM_WaitForDebugger,等待建立socket连接。
  4. 检查端侧端口是否打开成功。hdc shell “netstat -anp | grep 9225”。结果为9225端口状态为“LISTEN"即可。
  5. 转发端口。hdc fport tcp:9229 tcp:9225。转发PC侧端口9229到端侧端口9225。结果为"Forwardport result:OK"即可。
  6. 在chrome浏览器地址栏输入"localhost:9229/json",回车。获取端口连接信息。拷贝"devtoolsFrontendUrl"字段url内容到地址栏,回车,进入DevTools源码页,将看到在应用中通过OH_JSVM_RunScript执行的JS源码,此时暂停在第一行JS源码处。
  7. 用户可在源码页打断点,通过按钮发出各种调试命令控制JS代码执行,并查看变量。
  8. 调用OH_JSVM_CloseInspector关闭inspector,结束socket连接。

示例代码

#include "ark_runtime/jsvm.h"

#include <string>

using namespace std;

// 待调试的JS源码
static string srcDebugger = R"JS(
const concat = (...args) => args.reduce((a, b) => a + b);
var dialogue = concat('"What ', 'is ', 'your ', 'name ', '?"');
dialogue = concat(dialogue, ' --', '"My ', 'name ', 'is ', 'Bob ', '."');
)JS";

// 开启debugger
static void EnableInspector(JSVM_Env env) {
    // 在指定的主机和端口上激活inspector,创建socket。
    OH_JSVM_OpenInspector(env, "localhost", 9225);
    // 等待建立socket连接。
    OH_JSVM_WaitForDebugger(env, true);
}

// 关闭debugger
static void CloseInspector(JSVM_Env env) {
    // 关闭inspector,结束socket连接。
    OH_JSVM_CloseInspector(env);
}

static void RunScript(JSVM_Env env) {
    JSVM_HandleScope handleScope;
    OH_JSVM_OpenHandleScope(env, &handleScope);
    
    JSVM_Value jsSrc;
    OH_JSVM_CreateStringUtf8(env, srcDebugger.c_str(), srcDebugger.size(), &jsSrc);
    
    JSVM_Script script;
    OH_JSVM_CompileScript(env, jsSrc, nullptr, 0, true, nullptr, &script);
    
    JSVM_Value result;
    OH_JSVM_RunScript(env, script, &result);
    
    OH_JSVM_CloseHandleScope(env, handleScope);
}

void RunDemo() {
    JSVM_InitOptions initOptions{};
    OH_JSVM_Init(&initOptions);
    
    JSVM_VM vm;
    OH_JSVM_CreateVM(nullptr, &vm);
    JSVM_VMScope vmScope;
    OH_JSVM_OpenVMScope(vm, &vmScope);
    
    JSVM_Env env;
    OH_JSVM_CreateEnv(vm, 0, nullptr, &env);
    // 执行JS代码之前打开debugger。
    EnableInspector(env);
    JSVM_EnvScope envScope;
    OH_JSVM_OpenEnvScope(env, &envScope);

    // 执行JS代码。
    RunScript(env);

    OH_JSVM_CloseEnvScope(env, envScope);
    // 执行JS代码之后关闭debugger。
    CloseInspector(env);
    OH_JSVM_DestroyEnv(env);
    OH_JSVM_CloseVMScope(vm, vmScope);
    OH_JSVM_DestroyVM(vm);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69

CPU Profiler及Heap Snapshot使用方法

CPU Profiler接口使用方法

  1. 在执行JS代码之前,调用OH_JSVM_StartCpuProfiler开始采样并返回JSVM_CpuProfiler。
  2. 在执行JS代码后,调用OH_JSVM_StopCpuProfiler,传入1中返回的JSVM_CpuProfiler,传入输出流回调及输出流指针。数据将会写入指定的输出流中。
  3. 输出数据为JSON字符串。可存入.cpuprofile文件中。该文件类型可导入Chrome浏览器-DevTools-JavaScript Profiler工具中解析成性能分析视图。

Heap Snapshot接口使用方法

1.为分析某段JS代码的堆对象创建情况。可在执行JS代码前后,分别调用一次OH_JSVM_TakeHeapSnapshot。传入输出流回调及输出流指针。数据将会写入指定的输出流中。

2.输出数据可存入.heapsnapshot文件中。该文件类型可导入Chrome浏览器-DevTools-Memory工具中解析成内存分析视图。

示例代码

#include "ark_runtime/jsvm.h"

#include <fstream>
#include <iostream>

using namespace std;

// 待调优的JS代码。
static string srcProf = R"JS(
function sleep(delay) {
    var start = (new Date()).getTime();
    while ((new Date()).getTime() - start < delay) {
        continue;
    }
}
function work3() {
    sleep(300);
}
function work2() {
    work3();
    sleep(200);
}
function work1() {
    work2();
    sleep(100);
}
work1();
)JS";

// 数据输出流回调,用户自定义,处理返回的调优数据,此处以写入文件为例。
static bool OutputStream(const char *data, int size, void *streamData) {
    auto &os = *reinterpret_cast<ofstream *>(streamData);
    if (data) {
        os.write(data, size);
    } else {
        os.close();
    }
    return true;
}

static JSVM_CpuProfiler ProfilingBegin(JSVM_VM vm) {
    // 文件输出流,保存调优数据,/data/storage/el2/base/files为沙箱路径。以包名为com.example.helloworld为例。
    // 实际文件会保存到/data/app/el2/100/base/com.example.helloworld/files/heap-snapshot-begin.heapsnapshot。
    ofstream heapSnapshot("/data/storage/el2/base/files/heap-snapshot-begin.heapsnapshot",
                          ios::out | ios:: binary | ios::trunc);
    // 执行JS前获取一次Heap Snapshot数据。
    OH_JSVM_TakeHeapSnapshot(vm, OutputStream, &heapSnapshot);
    JSVM_CpuProfiler cpuProfiler;
    // 开启CPU Profiler。
    OH_JSVM_StartCpuProfiler(vm, &cpuProfiler);
    return cpuProfiler;
}

// 关闭调优数据采集工具
static void ProfilingEnd(JSVM_VM vm, JSVM_CpuProfiler cpuProfiler) {
    // 文件输出流,保存调优数据,/data/storage/el2/base/files为沙箱路径。以包名为com.example.helloworld为例。
    // 实际文件会保存到/data/app/el2/100/base/com.example.helloworld/files/cpu-profile.cpuprofile。
    ofstream cpuProfile("/data/storage/el2/base/files/cpu-profile.cpuprofile",
                        ios::out | ios:: binary | ios::trunc);
    // 关闭CPU Profiler,获取数据。
    OH_JSVM_StopCpuProfiler(vm, cpuProfiler, OutputStream, &cpuProfile);
    ofstream heapSnapshot("/data/storage/el2/base/files/heap-snapshot-end.heapsnapshot",
                              ios::out | ios:: binary | ios::trunc);
    // 执行JS后再获取一次Heap Snapshot数据,与执行前数据作对比,以分析内存问题或者进行内存调优。
    OH_JSVM_TakeHeapSnapshot(vm, OutputStream, &heapSnapshot);
}

static void RunScriptWithStatistics(JSVM_Env env) {
    JSVM_VM vm;
    OH_JSVM_GetVM(env, &vm);

    // 开始调优。
    auto cpuProfiler = ProfilingBegin(vm);
    
    JSVM_HandleScope handleScope;
    OH_JSVM_OpenHandleScope(env, &handleScope);
    
    JSVM_Value jsSrc;
    OH_JSVM_CreateStringUtf8(env, srcProf.c_str(), srcProf.size(), &jsSrc);
    
    JSVM_Script script;
    OH_JSVM_CompileScript(env, jsSrc, nullptr, 0, true, nullptr, &script);

    JSVM_Value result;
    // 执行JS代码。
    OH_JSVM_RunScript(env, script, &result);
    
    OH_JSVM_CloseHandleScope(env, handleScope);

    // 结束调优。
    ProfilingEnd(vm, cpuProfiler);
}

void RunDemo() {
    JSVM_InitOptions initOptions{};
    OH_JSVM_Init(&initOptions);
    
    JSVM_VM vm;
    OH_JSVM_CreateVM(nullptr, &vm);
    JSVM_VMScope vmScope;
    OH_JSVM_OpenVMScope(vm, &vmScope);
    
    JSVM_Env env;
    OH_JSVM_CreateEnv(vm, 0, nullptr, &env);
    JSVM_EnvScope envScope;
    OH_JSVM_OpenEnvScope(env, &envScope);
    
    RunScriptWithStatistics(env);
    
    OH_JSVM_CloseEnvScope(env, envScope);
    OH_JSVM_DestroyEnv(env);
    OH_JSVM_CloseVMScope(vm, vmScope);
    OH_JSVM_DestroyVM(vm);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114

最后呢

很多开发朋友不知道需要学习那些鸿蒙技术?鸿蒙开发岗位需要掌握那些核心技术点?为此鸿蒙的开发学习必须要系统性的进行。

而网上有关鸿蒙的开发资料非常的少,假如你想学好鸿蒙的应用开发与系统底层开发。你可以参考这份资料,少走很多弯路,节省没必要的麻烦。由两位前阿里高级研发工程师联合打造的《鸿蒙NEXT星河版OpenHarmony开发文档》里面内容包含了(ArkTS、ArkUI开发组件、Stage模型、多端部署、分布式应用开发、音频、视频、WebGL、OpenHarmony多媒体技术、Napi组件、OpenHarmony内核、Harmony南向开发、鸿蒙项目实战等等)鸿蒙(Harmony NEXT)技术知识点

如果你是一名Android、Java、前端等等开发人员,想要转入鸿蒙方向发展。可以直接领取这份资料辅助你的学习。下面是鸿蒙开发的学习路线图。

在这里插入图片描述

针对鸿蒙成长路线打造的鸿蒙学习文档。话不多说,我们直接看详细鸿蒙(OpenHarmony )手册(共计1236页)与鸿蒙(OpenHarmony )开发入门视频,帮助大家在技术的道路上更进一步。

  • 《鸿蒙 (OpenHarmony)开发学习视频》
  • 《鸿蒙生态应用开发V2.0白皮书》
  • 《鸿蒙 (OpenHarmony)开发基础到实战手册》
  • OpenHarmony北向、南向开发环境搭建
  • 《鸿蒙开发基础》
  • 《鸿蒙开发进阶》
  • 《鸿蒙开发实战》

在这里插入图片描述

总结

鸿蒙—作为国家主力推送的国产操作系统。部分的高校已经取消了安卓课程,从而开设鸿蒙课程;企业纷纷跟进启动了鸿蒙研发。

并且鸿蒙是完全具备无与伦比的机遇和潜力的;预计到年底将有 5,000 款的应用完成原生鸿蒙开发,未来将会支持 50 万款的应用。那么这么多的应用需要开发,也就意味着需要有更多的鸿蒙人才。鸿蒙开发工程师也将会迎来爆发式的增长,学习鸿蒙势在必行! 自↓↓↓拿

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/喵喵爱编程/article/detail/940891
推荐阅读
相关标签
  

闽ICP备14008679号