安卓 v8 静态库调试

本文所讲v8版本为3.17版本。了解此版本的同学,应该知道,这个版本被UC进行优化,在weex中进行了使用。

概述

本文所讲的内容是:在chrome端远程调试安卓端用v8加载的js。

如果要在安卓客户端进行js动态加载,通过js渲染界面,这就必须要通过v8进行解析,v8解析过js之后,就会将js的对象,包装成一个个的C++对象,可以通过v8提供的接口,在native端获取这些对象,从而对其进行使用。这种方式,基本上是所有动态化框架的基础。weex就是这种方式,reactnative(以下简称RN)也是这种方式,不过解析js使用的引擎不相同而已,RN使用的是iOS平台的javascriptcore。而weex在安卓上也是使用的v8。通过这种方式,js一次编写,就可以同时运行在web端,安卓端,iOS端。(iOS端在此不作介绍。)这种动态加载,可以应对业务变化很快的app,比如淘宝,页面需要经常变动,只是更改一下界面,业务逻辑,就要重新发布新版本,是一件很没有意思的事情。所以,这种基于v8的动态化框架,就成为了趋势。

众所周知,在web端调试js很容易,而在安卓端通过webview调试js也很容易,而直接通过v8调试js,却很困难。首先,v8协议在不断的发生改变,而v8所使用的调试协议和chrome所使用的v8调试协议完全不一样。前面有一篇文章,记录了本文所介绍的3.17版本的v8调试协议,chrome的调试协议比较稳定,google一下,就可以找到。你可以进行对比,他们是完全不一样的。这就意味着,要进行调试,就必须要做协议转换。(注意:谷歌自从5.6版本起,就自带了调试客户端,内部自己转换了协议,而且可以直接和chrome进行连接,只需要调用相关的方法就可以。可以参考v8 github上的wiki。如果使用的是5.6及以上版本,本文可以直接忽略不看。

安卓客户端工作

主要有以下三个重点

1、客户端首先需要注册一个handler。在v8-debug.h中有这样一个方法:

static void SetMessageHandler2(MessageHandler2 handler);
//MessageHandler2的定义如下:
typedef void (*MessageHandler2)(const Message& message);

将自己的MessageHandler2set进去之后,就可以接收到来自v8的message类型数据。

//通过这种方式,可以得到json数据。
message.GetJSON();

获得了消息之后,传递到服务端,进行协议转换。

2、那么被服务端转换之后的chrome消息怎么处理呢?在v8-debug.h文件中,有如下一个方法:

// If no isolate is provided the default isolate is used.
static void SendCommand(const uint16_t* command, int length,
                      ClientData* client_data = NULL,
                      Isolate* isolate = NULL);

通过这个方法,可以将转换之后的消息发送给v8进行处理,v8通过处理,就会将消息通过步骤1的方式传递结果。

3、有一些情况下,发送到v8的调试信息可能没有返回,可以尝试下面的方法:

/**
 * Makes V8 process all pending debug messages.
 *
 * From V8 point of view all debug messages come   asynchronously (e.g. from
 * remote debugger) but they all must be handled synchronously: V8 cannot
 * do 2 things at one time so normal script execution must be interrupted
 * for a while.
 *
 * Generally when message arrives V8 may be in one of 3 states:
 * 1. V8 is running script; V8 will automatically interrupt and process all
 * pending messages (however auto_break flag should be enabled);
 * 2. V8 is suspended on debug breakpoint; in this state V8 is dedicated
 * to reading and processing debug messages;
 * 3. V8 is not running at all or has called some long-working C++ function;
 * by default it means that processing of all debug messages will be deferred
 * until V8 gets control again; however, embedding application may improve
 * this by manually calling this method.
 *
 * It makes sense to call this method whenever a new debug message arrived and
 * V8 is not already running. Method v8::Debug::SetDebugMessageDispatchHandler
 * should help with the former condition.
 *
 * Technically this method in many senses is equivalent to executing empty
 * script:
 * 1. It does nothing except for processing all pending debug messages.
 * 2. It should be invoked with the same precautions and from the same context
 * as V8 script would be invoked from, because:
 *   a. with "evaluate" command it can do whatever normal script can do,
 *   including all native calls;
 *   b. no other thread should call V8 while this method is running
 *   (v8::Locker may be used here).
 *
 * "Evaluate" debug command behavior currently is not specified in scope
 * of this method.
 */
static void ProcessDebugMessages();

文档介绍很多,主要意思是如果命令是Evaluate,有些情况下v8是不会返回的,这时可以尝试调用此方法,催促v8返回。通常情况下,此方法可以不用调用。

3、v8加载运行js很快,这就需要我们每次打开调试的时候,js都断点在第0行第0列等我们来运行。

// Schedule a debugger break to happen when JavaScript code is run
// in the given isolate. If no isolate is provided the default
// isolate is used.
static void DebugBreak(Isolate* isolate = NULL);

在比较靠前的时候,调用此方法,就可以将v8暂停在0行0列,直到给出了下一步或者中断之后,才会继续加载js。

服务端工作

所有的消息都是通过socket或者websocket进行传输。推荐websocket,实现简单,双向通信。而且和chrome的调试连接必须使用websocket。接下来看看几个步骤:
1、处理v8发送过来的消息
v8发送过来的消息是一个json格式的数据,而chrome需要的也是一个json格式的数据。举两个例子,首先看看chrome的协议:

{
    "method": "Console.messageAdded",
    "params": {
        "message": {
        "source": "console-api",
        "level": "log",
        "text": "a=x",
        "type": "log"
        }
    }
}

接下来看看v8的协议:

{
    "seq": 1,
    "type": "request",
    "command": "setexceptionbreak",
    "arguments": {
        "type": "all",
        "enabled": false,
        "maxStringLength": -1
     }
}

可以看到,他们的协议格式是不相同的。在此,我们都知道nodejs,他也是基于v8进行开发的,想必他的调试也会进行协议转换,就这条线索,找到了node-inspector这个项目,发现其中确实对协议进行了转换。将其协议转换的部分,抽取出来,大部分都可以正常使用。需要更改的有几个要点:

  • 脚本获取方式需要进行修改。nodejs直接在桌面,可以通过路径获取文件,而安卓的是远程调试,所以方式不同。
  • 他的console输出是注入了一个库,而我们不能注入这个库,所以他的console输出模块也是不可用的。

注意点:

  • 获取脚本,v8执行js时,会首先进行编译,然后运行,他会发送一个 afterCompile 事件,当服务端发送getResourceTree命令的时候,需要将这个消息一并返回过去,接下来就是正常的流程。
  • console的log输出,由于v8中并没有console这样一个对象,需要将全局的console进行一个包装,映射为一个v8对象,设置到js的执行环境中,于是,js执行环境中就会拥有console.log,console.warn等属性,设置好之后,在对应的回调函数中,需要手动编写调试后的消息,可以直接变为chrome所需要的调试协议格式,不经转换,直接发送chrome端即可。获取到消息后,可以直接在控制台上输出。

chrome端

chrome端使用的源码中的devtool文件,协议会发生改变,所以确保使用的协议是低于chrome55版本的,以上可能不支持。从这些低版本中抽取出devtool工程。当然,也可以自己修改,升级升上去。

连接起来

以上所讲都是一个个单独的部分,如果需要使用,就需要将其连接起来。我的方案是通过websocket连接起来,起一个nodejs后台服务,处理这些websocket交互。建立对应的session,就会非常简单。

结束

以上只是粗略讲了一下其中的一些重点部分,具体实践起来还是有大量的工作需要去做的。比如多v8的调试,session管理等等,都是比较复杂的。
v8内核能量巨大,未来如何,拭目以待。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,980评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,178评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,868评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,498评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,492评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,521评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,910评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,569评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,793评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,559评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,639评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,342评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,931评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,904评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,144评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,833评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,350评论 2 342

推荐阅读更多精彩内容