Android开发工具——ADB(Android Debug Bridge) <三>DalvikVM之jdwp线程
2015-04-17 11:09
447 查看
jdwp(java debug wire protocol)是dalvik VM的一个线程,可以建立在adb或者tcp基础上,与DDMS或debugger进行通信。
代码位置
dalvik/vm/jdwp
frameworks/base/core/jni
java虚拟机初始化后,或者每次“zygote fork”出一个新进程时,会启动jdwp线程。关于虚拟机的初始化参考我的博客/article/1839411.html。
主要调用路径:dvmStartup->dvmInitAfterZygote->dvmInitJDWP
dvmInitJDWP线程启动之前会可能会阻塞VM,依赖于配置suspend=n,所以dvmInitJDWP放在dvmStartup的最后步骤来执行。
dvmInitJDWP首先判断jdwp是否允许并且已经配置好,如果是,则读取jdwp的配置,这些配置是AndroidRuntime::startVm中配置的,
[cpp] view
plaincopy
/* 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交换数据,
[cpp] view
plaincopy
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(¶ms);
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
[cpp] view
plaincopy
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。
[cpp] view
plaincopy
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名称
[cpp] view
plaincopy
#define kJdwpControlName "\0jdwp-control"
这个socket名称已经被adbd绑定。
然后,调用dvmCreateInternalThread启动jdwp线程,dvmCreateInternalThread是pthread_create的包装,最终线程的执行函数是jdwpThreadStart,
在jdwpThreadStart中,会调用dvmJdwpEstablishConnection与adbd建立连接。在dvmJdwpEstablishConnection中,会一直等待与adbd的连接,直到连接成功
[cpp] view
plaincopy
int ret = connect(netState->controlSock,
&netState->controlAddr.controlAddrPlain,
netState->controlAddrLen);
如果执行connect成功,则将pid发送给adbd,
[cpp] view
plaincopy
snprintf(buff, sizeof(buff), "%04x", getpid());
buff[4] = 0;
do {
ret = send( netState->controlSock, buff, 4, 0 );
} while (ret < 0 && errno == EINTR);
接着,jdwp等待adbd返回一个客户文件描述符,
[cpp] view
plaincopy
netState->clientSock = receiveClientFd(netState);
如果返回成功,这个clientSock将用来直接与debugger或DDMS通信。可以想象,这里的clientSock就是TCP:5037对应的client描述符。
这样acceptConnection也成功返回了,回到jdwp线程处理函数jdwpThreadStart,接着进入一个while循环从adbd读取并处理握手消息。
[cpp] view
plaincopy
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
[cpp] view
plaincopy
typedef struct {
u1 cmdSet;
u1 cmd;
JdwpRequestHandler func;
const char* descr;
} JdwpHandlerMap;
write讲结果,写回给adbd,adbd处理之后在发回给HOST端。
代码位置
dalvik/vm/jdwp
frameworks/base/core/jni
java虚拟机初始化后,或者每次“zygote fork”出一个新进程时,会启动jdwp线程。关于虚拟机的初始化参考我的博客/article/1839411.html。
主要调用路径:dvmStartup->dvmInitAfterZygote->dvmInitJDWP
dvmInitJDWP线程启动之前会可能会阻塞VM,依赖于配置suspend=n,所以dvmInitJDWP放在dvmStartup的最后步骤来执行。
dvmInitJDWP首先判断jdwp是否允许并且已经配置好,如果是,则读取jdwp的配置,这些配置是AndroidRuntime::startVm中配置的,
[cpp] view
plaincopy
/* 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交换数据,
[cpp] view
plaincopy
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(¶ms);
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
[cpp] view
plaincopy
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。
[cpp] view
plaincopy
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名称
[cpp] view
plaincopy
#define kJdwpControlName "\0jdwp-control"
这个socket名称已经被adbd绑定。
然后,调用dvmCreateInternalThread启动jdwp线程,dvmCreateInternalThread是pthread_create的包装,最终线程的执行函数是jdwpThreadStart,
在jdwpThreadStart中,会调用dvmJdwpEstablishConnection与adbd建立连接。在dvmJdwpEstablishConnection中,会一直等待与adbd的连接,直到连接成功
[cpp] view
plaincopy
int ret = connect(netState->controlSock,
&netState->controlAddr.controlAddrPlain,
netState->controlAddrLen);
如果执行connect成功,则将pid发送给adbd,
[cpp] view
plaincopy
snprintf(buff, sizeof(buff), "%04x", getpid());
buff[4] = 0;
do {
ret = send( netState->controlSock, buff, 4, 0 );
} while (ret < 0 && errno == EINTR);
接着,jdwp等待adbd返回一个客户文件描述符,
[cpp] view
plaincopy
netState->clientSock = receiveClientFd(netState);
如果返回成功,这个clientSock将用来直接与debugger或DDMS通信。可以想象,这里的clientSock就是TCP:5037对应的client描述符。
这样acceptConnection也成功返回了,回到jdwp线程处理函数jdwpThreadStart,接着进入一个while循环从adbd读取并处理握手消息。
[cpp] view
plaincopy
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
[cpp] view
plaincopy
typedef struct {
u1 cmdSet;
u1 cmd;
JdwpRequestHandler func;
const char* descr;
} JdwpHandlerMap;
write讲结果,写回给adbd,adbd处理之后在发回给HOST端。
相关文章推荐
- Android开发工具——ADB(Android Debug Bridge) <三>DalvikVM之jdwp线程
- (转)Android开发工具——ADB(Android Debug Bridge) <三>DalvikVM之jdwp线程
- Android开发工具——ADB(Android Debug Bridge) <一>概览
- Android开发工具——ADB(Android Debug Bridge) <二>HOST端
- Android开发工具——ADB(Android Debug Bridge) <四>Device端
- Android开发工具——ADB(Android Debug Bridge) <一>概览
- Android开发工具——ADB(Android Debug Bridge) <二>HOST端
- (转)Android开发工具——ADB(Android Debug Bridge) <一>概览
- (转)Android开发工具——ADB(Android Debug Bridge) <二>HOST端
- Android开发工具ADB教程之三:Dalvik虚拟机之jdwp线程
- adb(android debug bridge)工具的使用方法  -  棒槌网@Android开发论坛 - Powered by phpwind
- Android开发工具—ADB(Android Debug Bridge) 3 - DalvikVM之jdwp线程
- Android开发工具—ADB(Android Debug Bridge) 1 - 概览
- Android开发工具—ADB(Android Debug Bridge) 2 - HOST端
- Android开发工具—ADB(Android Debug Bridge) 4 - Device端
- Android开发-API指南-<provider>[原创译文]
- JPA开发总结<三>--一对多双向关联
- 74个Android开发开源项目汇总<转载>
- 【android】NDK开发编译C++文件出现Type 'jint' could not be resolved和Unresolved inclusion: <jni.h>的解决办法
- <转>Android开发:用Drawable XML绘制带阴影效果的圆形按钮