上篇博客最后讲到在output_thread中。读取了adb驱动的数据后。就调用write_packet(t->fd, t->serial, &p)函数,把数据网socketpair的一側写。

这会导致socketpair的还有一側有数据,还有一側有数据会调用transport_socket_events函数来处理数据。

一、处理驱动读取的数据

我们如今来看看transport_socket_events函数:

static void transport_socket_events(int fd, unsigned events, void *_t)
{
atransport *t = reinterpret_cast<atransport*>(_t);
D("transport_socket_events(fd=%d, events=%04x,...)\n", fd, events);
if(events & FDE_READ){
apacket *p = 0;
if(read_packet(fd, t->serial, &p)){
D("%s: failed to read packet from transport socket on fd %d\n", t->serial, fd);
} else {
handle_packet(p, (atransport *) _t);
}
}
}

我们先把socketpair一端的数据读取出来,然后调用handle_packet来处理。

void handle_packet(apacket *p, atransport *t)
{
asocket *s; switch(p->msg.command){//依据从驱动读取内容msg的命令
...... case A_OPEN: /* OPEN(local-id, 0, "destination") */
if (t->online && p->msg.arg0 != 0 && p->msg.arg1 == 0) {
char *name = (char*) p->data;
name[p->msg.data_length > 0 ? p->msg.data_length - 1 : 0] = 0;
s = create_local_service_socket(name);//创建一个本地的socket
if(s == 0) {
send_close(0, p->msg.arg0, t);
} else {
s->peer = create_remote_socket(p->msg.arg0, t);
s->peer->peer = s;
send_ready(s->id, s->peer->id, t);
s->ready(s);
}
}
break;
...... case A_WRTE: /* WRITE(local-id, remote-id, <data>) */
if (t->online && p->msg.arg0 != 0 && p->msg.arg1 != 0) {
if((s = find_local_socket(p->msg.arg1, p->msg.arg0))) {
unsigned rid = p->msg.arg0;
p->len = p->msg.data_length; if(s->enqueue(s, p) == 0) {
D("Enqueue the socket\n");
send_ready(s->id, rid, t);
}
return;
}
}
break; default:
printf("handle_packet: what is %08x? !\n", p->msg.command);
}
put_apacket(p);
}

上面是处理驱动的数据。我们先来看下处理open命令中一个create_local_service_socket函数

asocket *create_local_service_socket(const char *name)
{
#if !ADB_HOST
if (!strcmp(name,"jdwp")) {
return create_jdwp_service_socket();
}
if (!strcmp(name,"track-jdwp")) {
return create_jdwp_tracker_service_socket();
}
#endif
int fd = service_to_fd(name);//获取fd
if(fd < 0) return 0; asocket* s = create_local_socket(fd);//创建socket
D("LS(%d): bound to '%s' via %d\n", s->id, name, fd); #if !ADB_HOST
char debug[PROPERTY_VALUE_MAX];
if (!strncmp(name, "root:", 5))
property_get("ro.debuggable", debug, ""); if ((!strncmp(name, "root:", 5) && getuid() != 0 && strcmp(debug, "1") == 0)
|| (!strncmp(name, "unroot:", 7) && getuid() == 0)
|| !strncmp(name, "usb:", 4)
|| !strncmp(name, "tcpip:", 6)) {
D("LS(%d): enabling exit_on_close\n", s->id);
s->exit_on_close = 1;
}
#endif return s;
}

我们先来看看service_to_fd函数:

int service_to_fd(const char *name)
{
int ret = -1; if(!strncmp(name, "tcp:", 4)) {
int port = atoi(name + 4);
name = strchr(name + 4, ':');
if(name == 0) {
ret = socket_loopback_client(port, SOCK_STREAM);
if (ret >= 0)
disable_tcp_nagle(ret);
} else {
#if ADB_HOST
ret = socket_network_client(name + 1, port, SOCK_STREAM);
#else
return -1;
#endif
}
#ifndef HAVE_WINSOCK /* winsock doesn't implement unix domain sockets */
} else if(!strncmp(name, "local:", 6)) {
ret = socket_local_client(name + 6,
ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM);
} else if(!strncmp(name, "localreserved:", 14)) {
ret = socket_local_client(name + 14,
ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM);
} else if(!strncmp(name, "localabstract:", 14)) {
ret = socket_local_client(name + 14,
ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM);
} else if(!strncmp(name, "localfilesystem:", 16)) {
ret = socket_local_client(name + 16,
ANDROID_SOCKET_NAMESPACE_FILESYSTEM, SOCK_STREAM);
#endif
#if !ADB_HOST
} else if(!strncmp("dev:", name, 4)) {
ret = unix_open(name + 4, O_RDWR | O_CLOEXEC);
} else if(!strncmp(name, "framebuffer:", 12)) {
ret = create_service_thread(framebuffer_service, 0);
} else if (!strncmp(name, "jdwp:", 5)) {
ret = create_jdwp_connection_fd(atoi(name+5));
} else if(!HOST && !strncmp(name, "shell:", 6)) {//adb shell
ret = create_subproc_thread(name + 6, SUBPROC_PTY);
} else if(!HOST && !strncmp(name, "exec:", 5)) {
ret = create_subproc_thread(name + 5, SUBPROC_RAW);
} else if(!strncmp(name, "sync:", 5)) {
D("kangchen service_to_fd file_sync_service");
ret = create_service_thread(file_sync_service, NULL);
} else if(!strncmp(name, "remount:", 8)) {
ret = create_service_thread(remount_service, NULL);
} else if(!strncmp(name, "reboot:", 7)) {
void* arg = strdup(name + 7);
if (arg == NULL) return -1;
ret = create_service_thread(reboot_service, arg);
} else if(!strncmp(name, "root:", 5)) {//adb root
ret = create_service_thread(restart_root_service, NULL);

这里我们主要看下adb root和adb shell,其它的以后自己慢慢研究:

1.2 adb root的处理过程

我们先来看下adb root的处理过程,serverice_to_fd函数先调用了create_service_thread函数:

static int create_service_thread(void (*func)(int, void *), void *cookie)
{
int s[2];
if (adb_socketpair(s)) {//建立一对socketpair
printf("cannot create service socket pair\n");
return -1;
}
D("socketpair: (%d,%d)", s[0], s[1]); stinfo* sti = reinterpret_cast<stinfo*>(malloc(sizeof(stinfo)));
if (sti == nullptr) {
fatal("cannot allocate stinfo");
}
sti->func = func;
sti->cookie = cookie;
sti->fd = s[1]; adb_thread_t t;
if (adb_thread_create(&t, service_bootstrap_func, sti)) {
free(sti);
adb_close(s[0]);
adb_close(s[1]);
printf("cannot create service thread\n");
return -1;
} D("service thread started, %d:%d\n",s[0], s[1]);
return s[0];//返回一端的socketpair
}

我们再来看看service_bootstrap_func函数:

void *service_bootstrap_func(void *x)
{
stinfo* sti = reinterpret_cast<stinfo*>(x);
sti->func(sti->fd, sti->cookie);
free(sti);
return 0;
}

终于还是调用了create_service_thread传进来的func函数

而adb root传入的是restart_root_service函数:

void restart_root_service(int fd, void *cookie) {
if (getuid() == 0) {//已经root
WriteFdExactly(fd, "adbd is already running as root\n");
adb_close(fd);
} else {
D("kangchen restart_root_service.\n");
char value[PROPERTY_VALUE_MAX];
property_get("ro.debuggable", value, "");
if (strcmp(value, "1") != 0) {
WriteFdExactly(fd, "adbd cannot run as root in production builds\n");
adb_close(fd);
return;
} property_set("service.adb.root", "1");//设置root
WriteFdExactly(fd, "restarting adbd as root\n");//这是写入pc端的数据
adb_close(fd);
}
}

由于前面是sockpair。那这边写入的数据,会在另外一端的sockpair有反应。

而另外一端的sockpair终于是作为service_to_fd函数的返回值,那我们继续看下create_local_service_socket函数

asocket *create_local_service_socket(const char *name)
{
#if !ADB_HOST
if (!strcmp(name,"jdwp")) {
return create_jdwp_service_socket();
}
if (!strcmp(name,"track-jdwp")) {
return create_jdwp_tracker_service_socket();
}
#endif
int fd = service_to_fd(name);//得到sockpair的一端
if(fd < 0) return 0; asocket* s = create_local_socket(fd);//创建localsocket
D("LS(%d): bound to '%s' via %d\n", s->id, name, fd); #if !ADB_HOST
char debug[PROPERTY_VALUE_MAX];
if (!strncmp(name, "root:", 5))
property_get("ro.debuggable", debug, ""); if ((!strncmp(name, "root:", 5) && getuid() != 0 && strcmp(debug, "1") == 0)
|| (!strncmp(name, "unroot:", 7) && getuid() == 0)
|| !strncmp(name, "usb:", 4)
|| !strncmp(name, "tcpip:", 6)) {
D("LS(%d): enabling exit_on_close\n", s->id);
s->exit_on_close = 1;
}
#endif return s;
}

我们再来看看create_local_socket函数

asocket *create_local_socket(int fd)
{
asocket *s = reinterpret_cast<asocket*>(calloc(1, sizeof(asocket)));
if (s == NULL) fatal("cannot allocate socket");
s->fd = fd;
s->enqueue = local_socket_enqueue;
s->ready = local_socket_ready;
s->shutdown = NULL;
s->close = local_socket_close;
install_local_socket(s); fdevent_install(&s->fde, fd, local_socket_event_func, s);
D("LS(%d): created (fd=%d)\n", s->id, s->fd);
return s;
}

这个函数也是给socket赋各种函数等,然后当socket的这个fd有数据,这个fd就是前面service_to_fd返回的fd,当这个fd有数据会触发local_socket_func函数,我们来看下这个函数:

static void local_socket_event_func(int fd, unsigned ev, void* _s)
{
asocket* s = reinterpret_cast<asocket*>(_s);
D("LS(%d): event_func(fd=%d(==%d), ev=%04x)\n", s->id, s->fd, fd, ev); ..... if (ev & FDE_READ) {
apacket *p = get_apacket();
unsigned char *x = p->data;
size_t avail = MAX_PAYLOAD;
int r;
int is_eof = 0; while (avail > 0) {
r = adb_read(fd, x, avail);//获取从sockpair一側传来的数据
D("LS(%d): post adb_read(fd=%d,...) r=%d (errno=%d) avail=%zu\n",
s->id, s->fd, r, r < 0 ? errno : 0, avail);
if (r == -1) {
if (errno == EAGAIN) {
break;
}
} else if (r > 0) {
avail -= r;
x += r;
continue;
} /* r = 0 or unhandled error */
is_eof = 1;
break;
}
D("LS(%d): fd=%d post avail loop. r=%d is_eof=%d forced_eof=%d\n",
s->id, s->fd, r, is_eof, s->fde.force_eof);
if ((avail == MAX_PAYLOAD) || (s->peer == 0)) {
put_apacket(p);
} else {
p->len = MAX_PAYLOAD - avail; r = s->peer->enqueue(s->peer, p);//往t->transport_socket的一端写值,这样input_thread线程就有数据读取了
D("LS(%d): fd=%d post peer->enqueue(). r=%d\n", s->id, s->fd,
r); if (r < 0) {
/* error return means they closed us as a side-effect
** and we must return immediately.
**
** note that if we still have buffered packets, the
** socket will be placed on the closing socket list.
** this handler function will be called again
** to process FDE_WRITE events.
*/
return;
} if (r > 0) {
/* if the remote cannot accept further events,
** we disable notification of READs. They'll
** be enabled again when we get a call to ready()
*/
fdevent_del(&s->fde, FDE_READ);
}
}
/* Don't allow a forced eof if data is still there */
if ((s->fde.force_eof && !r) || is_eof) {
D(" closing because is_eof=%d r=%d s->fde.force_eof=%d\n",
is_eof, r, s->fde.force_eof);
s->close(s);
}
} ......
}

比方当我们adb root 处理之后,会发送类似adb restart root之类的信息给adb 驱动,这时候就会触发local_socket_event_func函数。这个函数先去读取你要发的信息。然后往t->transport_socket的一端写值。这样input_thread线程就有数据读取了。而这个是通过s->peer->enqueue来实现的。

我们再来看看这块。

在处理open命令的之后,还创建了remotesocket

    case A_OPEN: /* OPEN(local-id, 0, "destination") */
if (t->online && p->msg.arg0 != 0 && p->msg.arg1 == 0) {
char *name = (char*) p->data;
name[p->msg.data_length > 0 ? p->msg.data_length - 1 : 0] = 0;
s = create_local_service_socket(name);
if(s == 0) {
send_close(0, p->msg.arg0, t);
} else {
s->peer = create_remote_socket(p->msg.arg0, t);
s->peer->peer = s;
send_ready(s->id, s->peer->id, t);
s->ready(s);
}
}
break;

我们来看看create_remote_socket函数

asocket *create_remote_socket(unsigned id, atransport *t)
{
if (id == 0) fatal("invalid remote socket id (0)");
asocket* s = reinterpret_cast<asocket*>(calloc(1, sizeof(aremotesocket)));
adisconnect* dis = &reinterpret_cast<aremotesocket*>(s)->disconnect; if (s == NULL) fatal("cannot allocate socket");
s->id = id;
s->enqueue = remote_socket_enqueue;
s->ready = remote_socket_ready;
s->shutdown = remote_socket_shutdown;
s->close = remote_socket_close;
s->transport = t; dis->func = remote_socket_disconnect;
dis->opaque = s;
add_transport_disconnect( t, dis );
D("RS(%d): created\n", s->id);
return s;
}

这里我们主要看下remote_socket_enqueue函数:

static int remote_socket_enqueue(asocket *s, apacket *p)
{
D("kangchen entered remote_socket_enqueue RS(%d) WRITE fd=%d peer.fd=%d\n",
s->id, s->fd, s->peer->fd);
p->msg.command = A_WRTE;
p->msg.arg0 = s->peer->id;
p->msg.arg1 = s->id;
p->msg.data_length = p->len;
send_packet(p, s->transport);
return 1;
}

再来看看send_packet函数

void send_packet(apacket *p, atransport *t)
{
unsigned char *x;
unsigned sum;
unsigned count; p->msg.magic = p->msg.command ^ 0xffffffff; count = p->msg.data_length;
x = (unsigned char *) p->data;
sum = 0;
while(count-- > 0){
sum += *x++;
}
p->msg.data_check = sum; print_packet("send", p); if (t == NULL) {
D("Transport is null \n");
// Zap errno because print_packet() and other stuff have errno effect.
errno = 0;
fatal_errno("Transport is null");
}
if(write_packet(t->transport_socket, t->serial, &p)){
fatal_errno("cannot enqueue packet on transport socket");
}
}

send_packet函数终于是往t->transport_socket写入,这也意味着input_thread会从socketpair的还有一側读取数据,最后再往adb驱动写入数据。

这样整个adb root就比較清楚了。

static void *input_thread(void *_t)
{
atransport *t = reinterpret_cast<atransport*>(_t);
apacket *p;
int active = 0; D("%s: starting transport input thread, reading from fd %d\n",
t->serial, t->fd); for(;;){
if(read_packet(t->fd, t->serial, &p)) {//读取socket数据
D("%s: failed to read apacket from transport on fd %d\n",
t->serial, t->fd );
LOG("%s:%s: failed to read apacket from transport on fd %d\n", __FUNCTION__, t->serial, t->fd );
break;
}
if(p->msg.command == A_SYNC){
if(p->msg.arg0 == 0) {
D("%s: transport SYNC offline\n", t->serial);
put_apacket(p);
LOG("%s:%s: transport SYNC offline\n", __FUNCTION__, t->serial);
break;
} else {
if(p->msg.arg1 == t->sync_token) {
D("%s: transport SYNC online\n", t->serial);
LOG("%s:%s: transport SYNC online\n", __FUNCTION__, t->serial);
active = 1;
} else {
D("%s: transport ignoring SYNC %d != %d\n",
t->serial, p->msg.arg1, t->sync_token);
LOG("%s:%s: transport ignoring SYNC\n", __FUNCTION__, t->serial);
}
}
} else {
if(active) {
D("%s: transport got packet, sending to remote\n", t->serial);
t->write_to_remote(p, t);//写入adb驱动
} else {
D("%s: transport ignoring packet while offline\n", t->serial);
}
} put_apacket(p);
}

1.2 adb shell 流程

以下我们再来看下adb shell的流程,会和adb root有点不一样。也会更复杂些。

相同adb shell的处理流程也是先到handle _packet函数:

    case A_OPEN: /* OPEN(local-id, 0, "destination") */
if (t->online && p->msg.arg0 != 0 && p->msg.arg1 == 0) {
char *name = (char*) p->data;
name[p->msg.data_length > 0 ? p->msg.data_length - 1 : 0] = 0;
s = create_local_service_socket(name);
if(s == 0) {
send_close(0, p->msg.arg0, t);
} else {
s->peer = create_remote_socket(p->msg.arg0, t);
s->peer->peer = s;
send_ready(s->id, s->peer->id, t);
s->ready(s);
}
}
break;

一样的我们就直接看service_to_fd函数了,当中截取以下这段代码:

    } else if(!HOST && !strncmp(name, "shell:", 6)) {
ret = create_subproc_thread(name + 6, SUBPROC_PTY);

我们来看看create_subproc_thread函数:

static int create_subproc_thread(const char *name, const subproc_mode mode)
{
adb_thread_t t;
int ret_fd;
pid_t pid = -1; const char *arg0, *arg1;
if (name == 0 || *name == 0) {
arg0 = "-"; arg1 = 0;
} else {
arg0 = "-c"; arg1 = name;
} switch (mode) {
case SUBPROC_PTY:
ret_fd = create_subproc_pty(SHELL_COMMAND, arg0, arg1, &pid);//我们是调用了这函数
break;
case SUBPROC_RAW:
ret_fd = create_subproc_raw(SHELL_COMMAND, arg0, arg1, &pid);
break;
default:
fprintf(stderr, "invalid subproc_mode %d\n", mode);
return -1;
}
D("create_subproc ret_fd=%d pid=%d\n", ret_fd, pid); stinfo* sti = reinterpret_cast<stinfo*>(malloc(sizeof(stinfo)));
if(sti == 0) fatal("cannot allocate stinfo");
sti->func = subproc_waiter_service;
sti->cookie = (void*) (uintptr_t) pid;
sti->fd = ret_fd; if (adb_thread_create(&t, service_bootstrap_func, sti)) {
free(sti);
adb_close(ret_fd);
fprintf(stderr, "cannot create service thread\n");
return -1;
} D("service thread started, fd=%d pid=%d\n", ret_fd, pid);
return ret_fd;
}

我们先来看看create_subproc_pty函数:

static int create_subproc_pty(const char *cmd, const char *arg0, const char *arg1, pid_t *pid)
{
int ptm; ptm = unix_open("/dev/ptmx", O_RDWR | O_CLOEXEC); // | O_NOCTTY);//返回的fd
if(ptm < 0){
printf("[ cannot open /dev/ptmx - %s ]\n",strerror(errno));
return -1;
} char devname[64];
if(grantpt(ptm) || unlockpt(ptm) || ptsname_r(ptm, devname, sizeof(devname)) != 0) {
printf("[ trouble with /dev/ptmx - %s ]\n", strerror(errno));
adb_close(ptm);
return -1;
} *pid = fork();//fork进程
if(*pid < 0) {
printf("- fork failed: %s -\n", strerror(errno));
adb_close(ptm);
return -1;
} if (*pid == 0) {//子进程
init_subproc_child(); int pts = unix_open(devname, O_RDWR | O_CLOEXEC);
if (pts < 0) {
fprintf(stderr, "child failed to open pseudo-term slave: %s\n", devname);
exit(-1);
} dup2(pts, STDIN_FILENO);//标准输入、输出、错误都指向这个fd
dup2(pts, STDOUT_FILENO);
dup2(pts, STDERR_FILENO); adb_close(pts);
adb_close(ptm); execl(cmd, cmd, arg0, arg1, NULL);//然后应该一直运行system/bin/shell命令
D("kangchen create_subproc_pty(cmd=%s, arg0=%s, arg1=%s)\n", cmd, arg0, arg1);
fprintf(stderr, "- exec '%s' failed: %s (%d) -\n",
cmd, strerror(errno), errno);
exit(-1);
} else {
return ptm;
}
#endif /* !defined(_WIN32) */
}

这个函数中,ptm和pts两个节点肯定有某种联系。pts然后把标准输入、输出、错误都指向了它。也就是当有输入、输出、错误数据都会到pts这个fd。终于肯定回到ptm这个fd。

也就是当外面有数据来的时候,ptm这个fd会有值,然后到pts,再到标准输入。经过dup2后进程A的不论什么目标为STDOUT_FILENO的I/O操作如printf等。其数据都将流入pts这个fd中。

而标准输入有值,会到pts。然后到ptm。最后数据就到input_thread了。事实上这个pts和ptm类似socketpair的一对。

我们再来看看subproc_waiter_service

static void subproc_waiter_service(int fd, void *cookie)
{
pid_t pid = (pid_t) (uintptr_t) cookie; D("entered. fd=%d of pid=%d\n", fd, pid);
while (true) {
int status;
pid_t p = waitpid(pid, &status, 0);
if (p == pid) {
D("fd=%d, post waitpid(pid=%d) status=%04x\n", fd, p, status);
if (WIFSIGNALED(status)) {
D("*** Killed by signal %d\n", WTERMSIG(status));
break;
} else if (!WIFEXITED(status)) {
D("*** Didn't exit!!. status %d\n", status);
break;
} else if (WEXITSTATUS(status) >= 0) {
D("*** Exit code %d\n", WEXITSTATUS(status));
break;
}
}
}
D("shell exited fd=%d of pid=%d err=%d\n", fd, pid, errno);
if (SHELL_EXIT_NOTIFY_FD >=0) {
int res;
res = WriteFdExactly(SHELL_EXIT_NOTIFY_FD, &fd, sizeof(fd)) ? 0 : -1;
D("notified shell exit via fd=%d for pid=%d res=%d errno=%d\n",
SHELL_EXIT_NOTIFY_FD, pid, res, errno);
}
}

这个函数开启了一线线程,仅仅是在一直waitpid的出错信号。

当adb shell有命令进来比方“ls”,它先到handle_packet函数的A_WRTE命令

    case A_WRTE: /* WRITE(local-id, remote-id, <data>) */
if (t->online && p->msg.arg0 != 0 && p->msg.arg1 != 0) {
if((s = find_local_socket(p->msg.arg1, p->msg.arg0))) {//先找到local_socket
unsigned rid = p->msg.arg0;
p->len = p->msg.data_length; if(s->enqueue(s, p) == 0) {//调用enqueue函数
D("Enqueue the socket\n");
send_ready(s->id, rid, t);
}
return;
}
}
break;

enqueue函数就是local_socket_enqueue函数,这个函数就是往service_to_fd写数据

static int local_socket_enqueue(asocket *s, apacket *p)
{
D("LS(%d): enqueue %d\n", s->id, p->len); p->ptr = p->data; /* if there is already data queue'd, we will receive
** events when it's time to write. just add this to
** the tail
*/
if(s->pkt_first) {
goto enqueue;
} /* write as much as we can, until we
** would block or there is an error/eof
*/
while(p->len > 0) {
int r = adb_write(s->fd, p->ptr, p->len);
if(r > 0) {
p->len -= r;
p->ptr += r;
continue;
}
if((r == 0) || (errno != EAGAIN)) {
D( "LS(%d): not ready, errno=%d: %s\n", s->id, errno, strerror(errno) );
s->close(s);
return 1; /* not ready (error) */
} else {
break;
}
} if(p->len == 0) {
put_apacket(p);
return 0; /* ready for more data */
} enqueue:
p->next = 0;
if(s->pkt_first) {
s->pkt_last->next = p;
} else {
s->pkt_first = p;
}
s->pkt_last = p; /* make sure we are notified when we can drain the queue */
fdevent_add(&s->fde, FDE_WRITE); return 1; /* not ready (backlog) */
}

比方"ls"命令就往service_to_fd写。这样create_subproc_pty函数的子进程就标准输入就有数据了,就能够运行cmd命令了

        dup2(pts, STDIN_FILENO);
dup2(pts, STDOUT_FILENO);
dup2(pts, STDERR_FILENO); adb_close(pts);
adb_close(ptm); execl(cmd, cmd, arg0, arg1, NULL);

运行命令后,又有输出。就到ptm的fd中,也就是service_to_fd中。最后再到Input_thread中读取。

事实上create_subproc_raw函数,使用socketpair更好理解。

static int create_subproc_raw(const char *cmd, const char *arg0, const char *arg1, pid_t *pid)
{
D("create_subproc_raw(cmd=%s, arg0=%s, arg1=%s)\n", cmd, arg0, arg1);
#if defined(_WIN32)
fprintf(stderr, "error: create_subproc_raw not implemented on Win32 (%s %s %s)\n", cmd, arg0, arg1);
return -1;
#else // 0 is parent socket, 1 is child socket
int sv[2];
if (adb_socketpair(sv) < 0) {
printf("[ cannot create socket pair - %s ]\n", strerror(errno));
return -1;
}
D("socketpair: (%d,%d)", sv[0], sv[1]); *pid = fork();
if (*pid < 0) {
printf("- fork failed: %s -\n", strerror(errno));
adb_close(sv[0]);
adb_close(sv[1]);
return -1;
} if (*pid == 0) {
adb_close(sv[0]);
init_subproc_child(); dup2(sv[1], STDIN_FILENO);
dup2(sv[1], STDOUT_FILENO);
dup2(sv[1], STDERR_FILENO); adb_close(sv[1]); execl(cmd, cmd, arg0, arg1, NULL); D("kangchen create_subproc_raw(cmd=%s, arg0=%s, arg1=%s)\n", cmd, arg0, arg1); fprintf(stderr, "- exec '%s' failed: %s (%d) -\n",
cmd, strerror(errno), errno);
exit(-1);
} else {
adb_close(sv[1]);
return sv[0];
}
#endif /* !defined(_WIN32) */
}

二、Input_thread读取local socket的数据,再写入adb驱动

service_to_fd有数据后,会触发函数local_socket_event_func。在这个函数中调用了s->peer->enqueue。然后调用remote_socket_enqueue函数

static int remote_socket_enqueue(asocket *s, apacket *p)
{
p->msg.command = A_WRTE;
p->msg.arg0 = s->peer->id;
p->msg.arg1 = s->id;
p->msg.data_length = p->len;
send_packet(p, s->transport);
return 1;
}

终于调用send_packet函数

void send_packet(apacket *p, atransport *t)
{
unsigned char *x;
unsigned sum;
unsigned count; p->msg.magic = p->msg.command ^ 0xffffffff; count = p->msg.data_length;
x = (unsigned char *) p->data;
sum = 0;
while(count-- > 0){
sum += *x++;
}
p->msg.data_check = sum; print_packet("send", p); if (t == NULL) {
D("Transport is null \n");
// Zap errno because print_packet() and other stuff have errno effect.
errno = 0;
fatal_errno("Transport is null");
}
if(write_packet(t->transport_socket, t->serial, &p)){
fatal_errno("cannot enqueue packet on transport socket");
}
}

终于还是往transport_socket写数据,然后我们再来看看input_thread线程。

static void *input_thread(void *_t)
{
atransport *t = reinterpret_cast<atransport*>(_t);
apacket *p;
int active = 0; D("%s: starting transport input thread, reading from fd %d\n",
t->serial, t->fd); for(;;){
if(read_packet(t->fd, t->serial, &p)) {//transport_socket的还有一端读取数据
D("%s: failed to read apacket from transport on fd %d\n",
t->serial, t->fd );//出错直接跳出循环,线程结束
break;
}
if(p->msg.command == A_SYNC){
if(p->msg.arg0 == 0) {
D("%s: transport SYNC offline\n", t->serial);
put_apacket(p);
break;
} else {
if(p->msg.arg1 == t->sync_token) {
D("%s: transport SYNC online\n", t->serial);
active = 1;
} else {
D("%s: transport ignoring SYNC %d != %d\n",
t->serial, p->msg.arg1, t->sync_token);
}
}
} else {
if(active) {
t->write_to_remote(p, t);//往驱动写
} else {
D("%s: transport ignoring packet while offline\n", t->serial);
}
} put_apacket(p);
} // this is necessary to avoid a race condition that occured when a transport closes
// while a client socket is still active.
close_all_sockets(t); D("%s: transport input thread is exiting, fd %d\n", t->serial, t->fd);
kick_transport(t);
transport_unref(t);
return 0;
}

write_to_remote调用的是remote_write函数。来看下remote_write函数:

static int remote_write(apacket *p, atransport *t)
{
unsigned size = p->msg.data_length; if(usb_write(t->usb, &p->msg, sizeof(amessage))) {
D("remote usb: 1 - write terminated\n");
return -1;
}
if(p->msg.data_length == 0) return 0; if(usb_write(t->usb, &p->data, size)) {
D("remote usb: 2 - write terminated\n");
return -1;
} return 0;
}

usb_write函数

int usb_write(usb_handle *h, const void *data, int len)
{
return h->write(h, data, len);
}

然后调用的是usb_adb_write函数:

static int usb_adb_write(usb_handle *h, const void *data, int len)
{
int n; D("about to write (fd=%d, len=%d)\n", h->fd, len);
n = adb_write(h->fd, data, len);
if(n != len) {
D("ERROR: fd = %d, n = %d, errno = %d (%s)\n",
h->fd, n, errno, strerror(errno));
return -1;
}
D("[ done fd=%d ]\n", h->fd);
return 0;
}

终于就写入的adb节点的驱动中去了。

三、总结

这篇博客分析了,处理pc端过来的数据,adb驱动中的数据。以及adb root 、adb shell这两个过程。最后再由input_thread写入adb 驱动发送到pc端。

android6.0 adbd深入分析(二)adb驱动数据的处理、写数据到adb驱动节点的更多相关文章

  1. Android6.0 init 深入分析

    之前写过一篇关于android5.0 init的介绍,这篇博客是介绍android6.0init,之前有的代码介绍不详细.而且分析 解析init.rc那块代码也没有结合init.rc介绍. 一. ma ...

  2. SpringMVC的数据响应-回写数据

    1.直接返回字符串 其他具体代码请访问chilianjie @RequestMapping("/report5") public String save5(HttpServletR ...

  3. (原创)android6.0系统 PowerManager深入分析(很具体)

    概述 一直以来,电源管理是电子产品设计中很重要的环节.也是不论什么电子设备中最为重要的系统模块之中的一个,优秀的电源管理方案.可以提供持久的续航能力,良好的用户体验.更能提升电子产品的竞争力. 移动设 ...

  4. android6.0、7.0、8.0新特性总结之开发应用时加以考虑的一些主要变更。

    android6.0 参考一:简书Android 6.0 新特性详解 参考二:关于Android6.0以上系统的权限问题 参考三:值得你关注的Android6.0上的重要变化(一) 参考四:值得你关注 ...

  5. Android6.0中PowerManagerService分析

    转自:http://blog.chinaunix.net/xmlrpc.php?r=blog/article&uid=30510400&id=5569393 概述 一直以来,电源管理是 ...

  6. java jxl 向Excel中追加数据而不覆盖原来数据的例子

    向先原来就有数据的Excel写数据是不会覆盖原有的数据,只是在追加数据. public class Excel {     public Excel() {     }     public void ...

  7. Servlet 3.0 规范(二)注解驱动和异步请求

    Servlet 3.0 规范(二)注解驱动和异步请求 在 Servlet 3.0 时支持注解启动,不再需要 web.xml 配制文件. 一.Servlet 3.0 组件 Servlet 容器的组件大致 ...

  8. Android6.0源码下载编译刷入真机

    编译环境是Ubuntu12.04.手机nexus 5,编译安卓6.0.1源码并烧录到真机. 源码用的是科大的镜像:http://mirrors.ustc.edu.cn/aosp-monthly/,下载 ...

  9. Android6.0权限大全和权限分类

    本文转载至: https://blog.csdn.net/qq_26440221/article/details/53097868 自从出了Android6.0权限管理之后,再也不能像以前那样粘贴复制 ...

随机推荐

  1. ONVIF-WSDL

    http://www.onvif.org/onvif/ver10/device/wsdl/devicemgmt.wsdl http://www.onvif.org/onvif/ver10/event/ ...

  2. ORA-01219:数据库未打开:仅允许在固定表/视图中查询

    好久没有登陆到Oracle的服务器了,把密码都忘记了.sql>conn sys/sys as sysdba;sql>alter user system identified by *;结果 ...

  3. Hibernate原生SQL查询数据转换为HQL查询数据方法

    HQL形式:(构造方法不支持timestamp类型) public List<Device> queryByMatherBoardId(String matherBoardId) { St ...

  4. [Angular] Extract Implementation Details of ngrx from an Angular Application with the Facade Pattern

    Extracting away the implementation details of ngrx from your components using the facade pattern cre ...

  5. 十分钟使用ionic Framework开发一个跨平台移动应用

    Ionic是一个前端的框架,帮助开发人员使用HTML5, CSS3和JavaScript做出原生应用. ionic的理念类似前端开发的BootStrap,目标是封装HTML5移动跨平台开发的最佳实践. ...

  6. hookup_2.10-0.2.3.jar包下载

    hookup_2.10-0.2.3.jar包下载地址,自己也做一个记录.同一时候也给须要的朋友提供一个方便,希望对大家有所帮助.下载地址:http://www.59biye.com/jar/cont/ ...

  7. C 输入一串数字,去掉当中含7的和能被7整除的数

    C 输入一串数字,去掉当中含7的和能被7整除的数,每一个数小于10000,数字个数小于100 输入样例:1,7,56,77,87,2,45,42,97,9977 输出:1,2,45 注意:输入个数不确 ...

  8. 关于comet

    Comet是彗星的意思,这一技术之所以借用这个名字,是因为这里的每一次请求都有一个长长的“尾巴”.这个长尾巴就是我们感兴趣的长连接. 因为长连接的实现,Comet可以不需要安装浏览器插件就可以向客户端 ...

  9. JavaMelody、prob系统监控工具使用配置

    分类: 工具 2014-04-23 14:41 1857人阅读 评论(1) 收藏 举报 目录(?)[+] 项 目开发结束了,需要做一下压力测试,就使用apache自带的ab程序进行压力测试,300个并 ...

  10. 利用socket.io+nodejs打造简单聊天室

    代码地址如下:http://www.demodashi.com/demo/11579.html 界面展示: 首先展示demo的结果界面,只是简单消息的发送和接收,包括发送文字和发送图片. ws说明: ...