Android开发工具——ADB(Android Debug Bridge) <三>DalvikVM之jdwp线程

2023-05-16

jdwp(java debug wire protocol)是dalvik VM的一个线程,可以建立在adb或者tcp基础上,与DDMS或debugger进行通信。

代码位置

dalvik/vm/jdwp

frameworks/base/core/jni

java虚拟机初始化后,或者每次“zygote fork”出一个新进程时,会启动jdwp线程。关于虚拟机的初始化参考我的博客http://blog.csdn.net/yinlijun2004/article/details/6065979

主要调用路径:dvmStartup->dvmInitAfterZygote->dvmInitJDWP

dvmInitJDWP线程启动之前会可能会阻塞VM,依赖于配置suspend=n,所以dvmInitJDWP放在dvmStartup的最后步骤来执行。
dvmInitJDWP首先判断jdwp是否允许并且已经配置好,如果是,则读取jdwp的配置,这些配置是AndroidRuntime::startVm中配置的,
    /* enable debugging; set suspend=y to pause during VM init */
#ifdef HAVE_ANDROID_OS
    /* use android ADB transport */
    opt.optionString =
        "-agentlib:jdwp=transport=dt_android_adb,suspend=n,server=y";
#else
    /* use TCP socket; address=0 means start at port 8000 and probe up */
    LOGI("Using TCP socket for JDWP\n");
    opt.optionString =
        "-agentlib:jdwp=transport=dt_socket,suspend=n,server=y,address=0";
#endif


这些配置保存在虚拟机全局变量gDvm中,gDvm是DvmGlobals变量,需要读取的配置包括transport,负责与ADB或TCP交换数据,
    if (gDvm.jdwpAllowed && gDvm.jdwpConfigured) {
        JdwpStartupParams params;


        if (gDvm.jdwpHost != NULL) {
            if (strlen(gDvm.jdwpHost) >= sizeof(params.host)-1) {
                LOGE("ERROR: hostname too long: '%s'\n", gDvm.jdwpHost);
                return false;
            }
            strcpy(params.host, gDvm.jdwpHost);
        } else {
            params.host[0] = '\0';
        }
        params.transport = gDvm.jdwpTransport;
        params.server = gDvm.jdwpServer;
        params.suspend = gDvm.jdwpSuspend;
        params.port = gDvm.jdwpPort;


        gDvm.jdwpState = dvmJdwpStartup(&params);
        if (gDvm.jdwpState == NULL) {
            LOGW("WARNING: debugger thread failed to initialize\n");
            /* TODO: ignore? fail? need to mimic "expected" behavior */
        }
    }


其中gDvm.jdwpAllowed在dalvik_system_Zygote.c中配置
        gDvm.jdwpAllowed = ((debugFlags & DEBUG_ENABLE_DEBUGGER) != 0);
gDvm.jdwpConfigured在调用dvmStartup->dvmProcessOptions->parseJdwpOptions时配置。

参考上面的参数,对照Init.c的handleJdwpOption的函数,可知gDvm.jdwpTransport为kJdwpTransportAndroidAdb,gDvm.jdwpServer为true,gDvm.jdwpSuspend为false,gDvm.jdwpPort没有配置,这些参数保存到dvmJdwpStartup的参数里面。

再看dvmJdwpStartup,在里面,创建jdwp相关的结构体JdwpState,是先初始化一些互斥锁和条件锁,初始化transport
    switch (pParams->transport) {
    case kJdwpTransportSocket:
        // LOGD("prepping for JDWP over TCP\n");
        state->transport = dvmJdwpSocketTransport();
        break;
    case kJdwpTransportAndroidAdb:
        // LOGD("prepping for JDWP over ADB\n");
        state->transport = dvmJdwpAndroidAdbTransport();
        /* TODO */
        break;
    default:
        LOGE("Unknown transport %d\n", pParams->transport);
        assert(false);
        goto fail;
    }


由上文可知,这里执行dvmJdwpAndroidAdbTransport,返回一个JdwpTransport的接口指针结构体,这些在ADB和TCP上各有一套实现方法,对应不同类型的transport。
typedef struct JdwpTransport {
    bool (*startup)(struct JdwpState* state, const JdwpStartupParams* pParams);
    bool (*accept)(struct JdwpState* state);
    bool (*establish)(struct JdwpState* state);
    void (*close)(struct JdwpState* state);
    void (*shutdown)(struct JdwpState* state);
    void (*free)(struct JdwpState* state);
    bool (*isConnected)(struct JdwpState* state);
    bool (*awaitingHandshake)(struct JdwpState* state);
    bool (*processIncoming)(struct JdwpState* state);
    bool (*sendRequest)(struct JdwpState* state, ExpandBuf* pReq);
    bool (*sendBufferedRequest)(struct JdwpState* state,
        const struct iovec* iov, int iovcnt);
} JdwpTransport;


然后,调用dvmJdwpNetStartup,在里面实际执行JdwpTransport在ADB上的startup接口。在JdwpADB.c的start函数内,初始化与adb有关的一些网络参数,比如socket名称
#define kJdwpControlName    "\0jdwp-control"  

这个socket名称已经被adbd绑定。
然后,调用dvmCreateInternalThread启动jdwp线程,dvmCreateInternalThread是pthread_create的包装,最终线程的执行函数是jdwpThreadStart,
在jdwpThreadStart中,会调用dvmJdwpEstablishConnection与adbd建立连接。在dvmJdwpEstablishConnection中,会一直等待与adbd的连接,直到连接成功
            int  ret = connect(netState->controlSock,                         
                               &netState->controlAddr.controlAddrPlain,       
                               netState->controlAddrLen);           

如果执行connect成功,则将pid发送给adbd,
        snprintf(buff, sizeof(buff), "%04x", getpid());
        buff[4] = 0;
                do {                                                          
                    ret = send( netState->controlSock, buff, 4, 0 );          
                } while (ret < 0 && errno == EINTR);     


接着,jdwp等待adbd返回一个客户文件描述符,
netState->clientSock = receiveClientFd(netState);

如果返回成功,这个clientSock将用来直接与debugger或DDMS通信。可以想象,这里的clientSock就是TCP:5037对应的client描述符。
这样acceptConnection也成功返回了,回到jdwp线程处理函数jdwpThreadStart,接着进入一个while循环从adbd读取并处理握手消息。
        while (true) {
            // sanity check -- shouldn't happen?
            if (dvmThreadSelf()->status != THREAD_VMWAIT) {
                LOGE("JDWP thread no longer in VMWAIT (now %d); resetting\n",
                    dvmThreadSelf()->status);
                dvmDbgThreadWaiting();
            }


            if (!dvmJdwpProcessIncoming(state))     /* blocking read */
                break;


            if (first && !dvmJdwpAwaitingHandshake(state)) {
                /* handshake worked, tell the interpreter that we're active */
                first = false;


                /* set thread ID; requires object registry to be active */
                state->debugThreadId = dvmDbgGetThreadSelfId();


                /* wake anybody who's waiting for us */
                dvmDbgLockMutex(&state->attachLock);
                dvmDbgCondBroadcast(&state->attachCond);
                dvmDbgUnlockMutex(&state->attachLock);
            }
        }


先看dvmJdwpProcessIncoming函数,在里面执行select,可能会收到三种数据,对应三个文件描述被set,其中wakeFds是定时唤醒作用,丢弃,controlSock的set也忽略,因为不需要接收第二个debugger文件描述服。之后收到debugger的数据,也就是clientSock被set的时候调用read读取数据,如果不一个单位数据包长度,则dvmJdwpProcessIncoming返回。否则,调用handlePacket处理数据包,
handlePacket->dvmJdwpProcessRequest->write
handlePacket从讲包中的数据还原成JdwpReqHeader和数据起始指针,送给dvmJdwpProcessRequest处理,dvmJdwpProcessRequest从gHandlerMap调出处理函数func
typedef struct {                                                              
    u1  cmdSet;                                                               
    u1  cmd;
    JdwpRequestHandler  func;                                                 
    const char* descr;                                                        
} JdwpHandlerMap;  

write讲结果,写回给adbd,adbd处理之后在发回给HOST端。



本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Android开发工具——ADB(Android Debug Bridge) <三>DalvikVM之jdwp线程 的相关文章

随机推荐

  • mysql 5.7Expression #1 of ORDER BY clause is not in SELECT list

    java sql SQLException Expression 1 of ORDER BY clause is not in SELECT list references column 39 amc ti create time 39 w
  • Android 源码系统添加系统服务

    以下内容基于Android12 源码进行整理 下面内容是基于Camera升降机服务添加过程整理 1 在Context java 中添加服务名称 Context java 在源码中位置 frameworks base core java an
  • sun.misc.Launcher 找不到

    问题 xff1a sun misc Launcher 找不到 xff0c 报错 xff1a Access restriction The type Launcher is not API restriction on required li
  • ubuntu 设置不了分辨率 解决方法

    要设置xorg conf xff0c ubuntu12 04默认没有这个文件 xff0c 所以要生成它 先ctrl xff0b alt xff0b f1切到文字模式 xff0c 停掉Xwindow服务 xff0c 执行 sudo etc i
  • Android Banner2.1.0

    由于最近更新了studio xff0c 好多东西需要更新 xff0c 那就彻底一点吧 xff0c banner原来用的1 4 9的 xff0c 新版的更新了好多 xff0c 之前的方法不能用了 xff0c 不多说直接上代码 依赖 xff1a
  • Ubuntu:如何显示系统托盘图标(systray)

    1 问题说明 Ubuntu 11版本开始 xff0c 默认关闭了托盘图标的显示 xff0c 需要手动执行命令或额外工具配置 xff0c 添加到白名单 Ubuntu 13 04更彻底 xff0c 默认配置根本没有托盘图标 xff0c 除了ja
  • 火锅店连锁企业使用哪款生鲜管理系统软件比较好呢?

    到目前为止 xff0c 餐饮行业的发展越来越好 xff0c 不管是节假日还是平常的日子里 xff0c 基本上餐馆总是会有很多人 xff0c 相比较来说连锁店铺的管理对于一般店铺来说更加的繁琐 xff0c 那是因为大多数的商品都是由总部统一配
  • 2021-10-26OriginPro 2021 v9.8如何修改为中文

    OriginPro 2021 v9 8如何修改为中文 xff1f 知乎 zhihu com https zhuanlan zhihu com p 376311895 按照这个方法亲测有效
  • Android 启动模式singleTask和onNewIntent什么时候调用

    设置启动模式我们不仅可以节省内存的使用 xff0c 还能达到更好的体验 如果IntentActivity处于任务栈的顶端 xff0c 也就是说之前打开过的Activity xff0c 现在处于 onPause onStop 状态的话 其他应
  • Centos7里在gnome桌面创建文件夹快捷方式

    需求 我的home文件夹特别小 xff0c 空间都分配在 data里 xff0c 所以我平常都是到 data路径下 所以我想在桌面上放一个可以直接到 data路径下的快捷键 STEP1 首先是到一个合适的地方 我放在了 data syste
  • 硬盘被格式化重装系统,以前的文件还能恢复吗

    硬盘被格式化重装系统 以前的文件还能恢复吗 今天早上起来就发现电脑有点问题 xff0c 一直提示我有中毒的迹象 xff0c 但是杀毒软件却一直提示我没有问题 xff0c 不知道是不是病毒太过新颖 xff0c 还是免费的杀毒软件不够好用 一阵
  • 聊聊mac系统的 secoclient和iTerm2

    secoclient是啥 xff0c 就是华为出品的VPN网络设置工具 可以连接其他公司的服务器 下载地址 xff1a https secoclient updatestar com 网上百度secoclient下载 xff0c 有很多 x
  • Android Selinux介绍,如何添加selinux 权限

    Selinux简介 SELinux是安全增强型 Linux xff08 Security Enhanced Linux xff09 简称 SELinux 它是一个 Linux 内核模块 xff0c 也是 Linux 的一个安全子系统 优势
  • android 启动app event log

    pid 951 为system server 进程 1 冷启动 Time pid TAG Messag 01 20 33 418 951 wm stack created 22 01 20 33 421 951 wm task create
  • ASP.NET 实现主题切换实例

    通常我们经常看到网页 xff0c 一些软件提供换肤功能 xff0c 各种主题间切换 ASP NET 2 0 中可以用Theme和skin以及CSS轻松实现这个功能 首先简单介绍一下三种技术 xff1a 主题 xff08 Theme xff0
  • MacBook远程控制工具VNC Viewer_亲测使用

    MacBook远程控制工具VNC Viewer 亲测使用 官方下载地址 https www realvnc com en connect download viewer MacBook远程桌面Windows使用Microsoft Remot
  • Android注解(annotation)介绍及其应用

    我的新书 Android App开发入门与实战 已于2020年8月由人民邮电出版社出版 xff0c 欢迎购买 点击进入详情 文章目录 介绍自定义注解注解的应用 xff1a 反射注解的应用 xff1a APT其它 介绍 Annotation
  • Maven配置本地仓库 Maven项目使用本地仓库

    Maven配置本地仓库 Maven项目使用本地仓库 项目部署或开发环境没有外网的情况下 需要配置本地仓库 由于是在内网环境 xff0c maven无法连接互联网 xff0c 所以只能事先将jar下载到本地 xff0c 然后通过配置pom文件
  • Shell脚本

    做 Java 的肯定都接触过 Linux 系统 xff0c 那么很多时候我们在开发的过程中都是把我们项目打成一个jar包 xff0c 或者是war包的形式 xff0c 然后通过 XFTP 上传到我们服务器的指定目录 xff0c 然后运行一端
  • Android开发工具——ADB(Android Debug Bridge) <三>DalvikVM之jdwp线程

    jdwp java debug wire protocol 是dalvik VM的一个线程 xff0c 可以建立在adb或者tcp基础上 xff0c 与DDMS或debugger进行通信 代码位置 dalvik vm jdwp framew