編輯:關於Android編程
這會導致socketpair的另一側有數據,另一側有數據會調用transport_socket_events函數來處理數據。
我們現在來看看transport_socket_events函數:
static void transport_socket_events(int fd, unsigned events, void *_t) { atransport *t = reinterpret_cast(_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, ) */ 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,其他的以後自己慢慢研究:
我們先來看下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(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(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(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(_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(calloc(1, sizeof(aremotesocket))); adisconnect* dis = &reinterpret_cast(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就比較清楚了。
下面我們再來看下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(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; }
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, ) */ 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) */ }
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(_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端。
一、配置NDK環境第一步:在AndroidStudio中配置ndk環境需要下載ndk包,在AndroidStudio中File-->ProjectStructure
在我們的日常開發中自定義控件還是用的挺多的,設計師或者產品為了更好的漂亮,美觀,交互都會做一寫牛逼的ui效果圖,但是最後實現的還是我們程序員啊。所以說 自定義view你還
根據Android官方提供給我們的Sample例子實實在在的分析Bitmap使用時候的注意點。在分析Bitmap的使用之前先簡單的了解下BitmapFactory 類,B
render進程中 一.webkit模塊 webkit引擎會為網頁內容同時創建Dom tree, Render tree和RenderLayer tree. 這三棵樹之間