android2.3-adb源碼分析

android2.3-adb源碼分析


ADB是android debug bridge的縮寫,負責計算機與Android設備的幾乎所有通信和協作,可以認爲是連接兩者的橋樑。

其完整源代碼路徑:system\core\adb

1、首先查看其Android.mk文件,確認會生成哪此文件。

可執行進程由兩部分組成:


LOCAL_MODULE := adb

include $(BUILD_HOST_EXECUTABLE)
adb或adb.exe,運行於PC端,包括Linux、Windows、Mac OS等系統之中,通常是x86架構上

LOCAL_MODULE := adbd
ifeq ($(TARGET_SIMULATOR),true)
include $(BUILD_HOST_EXECUTABLE)
else
include $(BUILD_EXECUTABLE)
endif
adbd,運行於Android設備的底層Linux平臺上,或者運行於虛擬機平臺上


盒子上如此運行:init.rc 腳本添加:
service adbd /sbin/adbd
    disabled


利用ADB_HOST宏定義編譯不同的代碼


2、主體介紹一下
現在分析一下整個adb通訊由哪些模塊或組件構成呢?

一、adb server 服務端:
這是一個守護進程長期運行於後臺(runs on the host machine),沒有控制檯界面.
其主要工作有兩部分:


1):管理PC中的Android模擬器,以及通過USB線連接到PC的Android設備,負責維持運行於其中的
    adbd進程與自身的數據通道;
2):實現PC與設備/模擬器之間的數據拷貝。

主要代碼文件:

二、adb client 客戶端:
提供給用戶的命令行工具,對用戶暴露了上述install、push、shell等接口,與用戶交互
其主要工作是解析這些命令的參數,做必要預處理,然後轉移爲指令或數據,發送給adb服務端。
adb服務端再將指令數據轉發到模擬器或設備中,由adbd處理,產生結果,再通過adb服務端接收回來。


三、adb service 服務:
由此服務給adbd提供功能,即由這個模塊完成,主要分爲Host Services及 Local Services兩類


四、ADB daemon (adbd) 守護進程
作爲後臺進程運行於Android device or emulated system,提供連接 ADB server的功能
(through USB for devices, through TCP for emulators)

其通訊典型結構如下:

3、以常用命令爲實例
常用的指令如下:
adb push <local> <remote>    - copy file/dir to device
adb pull <remote> [<local>]  - copy file/dir from device
adb shell                    - run remote shell interactively
adb install [-l] [-r] [-s] <file> - push this package file to the device and install it
adb kill-server              - kill the server if it is running
connect <host>[:<port>]      - connect to a device via TCP/IP
                               Port 5555 is used by default if no port number is specified.


所有這些cmd處理函數都在:\system\core\adb\Commandline.c 中:
int adb_commandline(int argc, char **argv)

爲了更好的理解這些命令,有必須找到代碼理解一下這些命令的處理主要函數:

函數啓動點: adb.c 中的main函數,根據ADB_HOST決定執行哪些代碼:
int main(int argc, char **argv)
{
...
adb_trace_init();
#if ADB_HOST
    adb_sysdeps_init();
    return adb_commandline(argc - 1, argv + 1);  //這裏運行PC端,用於命令發送
#else
    start_device_log();
    return adb_main(0, DEFAULT_ADB_PORT);  //運行於android系統的盒子或設備上,用於命令接收及反饋
#endif
}

先分析PC端這邊:
a、首先建立adb server:
   有兩種方式,
手工建立:adb fork-server server 調用:adb_main(is_daemon, server_port); 
默認5037端口,也可以設置:service.adb.tcp.port 這個屬性獲取
自動建立:調用 launch_server(server_port),利用 CreateProcess 或者fork建立後臺進程進行運行
// child process
     int result = execl(path, "adb", "fork-server", "server", NULL);
這個進程利用fdevent_loop();處理所有數據及消息
     
b、ADB command-line client即發送命令界面:
主要處理函數:int adb_commandline(int argc, char **argv)
主要利用如下幾個函數:
adb_query  查詢
adb_connect 連接
adb_status 獲取狀態

命令發送格式:
1. A 4-byte hexadecimal string giving the length of the payload
2. Followed by the payload itself.


服務端收到後回覆:
1. For success, the 4-byte "OKAY" string
2. For failure, the 4-byte "FAIL" string, followed by a
   4-byte hex length, followed by a string giving the reason
   for failure.
3. As a special exception, for 'host:version', a 4-byte
   hex string corresponding to the server's internal version number

以上兩者通訊利用socket進行數據傳遞

然後分析設備服務端:
主要集中在函數:fdevent_loop();


主要分析一下數據transport這塊,文件Transport.c

void init_transport_registration(void)
{
adb_socketpair(s) //創建socket pair用於處理異步註冊事件
 
    transport_registration_send = s[0];
    transport_registration_recv = s[1];


// 在transport_registration_recv上安裝一個transport_registration_func異步事情回調函數
    fdevent_install(&transport_registration_fde,
                    transport_registration_recv,
                    transport_registration_func,
                    0);
                    
    ...
}

異步如何觸發的呢?
register_transport
-->transport_write_action(transport_registration_send, &m)

remove_transport
-->transport_write_action(transport_registration_send, &m)


此時會將事件寫入socket pair的寫入端,而接收端:

void fdevent_loop()
{
 ...
 
 for(;;) {
 
while((fde = fdevent_plist_dequeue())) {
       unsigned events = fde->events;
       fde->events = 0;
       fde->state &= (~FDE_PENDING);
       dump_fde(fde, "callback");
       
       //這個回調函數是在:fdevent_install 函數中註冊的:fde->func = func;
       fde->func(fde->fd, events, fde->arg);
  }
}
}

然後利用transport_read_action讀取異步事情,那麼數據處理在哪裏呢?

transport_registration_func
-->
 /* don't create transport threads for inaccessible devices */
    if (t->connection_state != CS_NOPERM) {

        if(adb_thread_create(&input_thread_ptr, input_thread, t)){
            fatal_errno("cannot create input thread");
        }


        if(adb_thread_create(&output_thread_ptr, output_thread, t)){
            fatal_errno("cannot create output thread");
        }
    }
    
在這裏會創建兩個線程 output thread和 input thread用於做異步 IO,    
=============================================================================
根據 adb的文檔說明, output線程和 input線程的引人主要是爲了解決 USB endpoint不支持非
阻塞讀寫,所以就專門爲 usb讀操作開一個output線程,爲usb寫操作創建一個input線程。
所以,數據流方向是遠程連接->output線程->主線程->input線程->遠程連接。剛開始時,
output線程會發一個 SYNC消息給input線程,啓動這個transport。


static void *input_thread(void *_t)
{
D("to_remote: starting input_thread for %p, reading from fd %d\n",t, t->fd);
for(;;){
read_packet(t->fd, &p);

t->write_to_remote(p, t);
}
}


static void *output_thread(void *_t)
{
D("from_remote: data pump  for transport %p\n", t);
    for(;;) {
        p = get_apacket();

t->read_from_remote(p, t);

write_packet(t->fd, &p);
}
}
=============================================================================

說一下我開始疑惑的問題解決:
adb shell 命令處理:
if(!strcmp(argv[0], "shell")) {
if(argc < 2) {
       return interactive_shell();
    }
}


int interactive_shell(void)
{
fd = adb_connect("shell:");

adb_thread_create(&thr, stdin_read_thread, fds);
}


而服務端處理:

#if ADB_HOST
#define SHELL_COMMAND "/bin/sh"
#else
#define SHELL_COMMAND "/system/bin/sh"
#endif

int service_to_fd(const char *name)
{
if(!HOST && !strncmp(name, "shell:", 6)) {
 if(name[6]) {
     ret = create_subprocess(SHELL_COMMAND, "-c", name + 6);
 } else {
     ret = create_subprocess(SHELL_COMMAND, "-", 0);
 }
}

...
}


單獨創建出一個進程進行處理shell命令
static int create_subprocess(const char *cmd, const char *arg0, const char *arg1)
{
pid = fork();

if(pid == 0){
execl(cmd, cmd, arg0, arg1, NULL);
}else
...
}


adb install xxx.apk 處理方式:
    if(!strcmp(argv[0], "install")) {
        if (argc < 2) return usage();
        return install_app(ttype, serial, argc, argv);
    }


    if(!strcmp(argv[0], "uninstall")) {
        if (argc < 2) return usage();
        return uninstall_app(ttype, serial, argc, argv);
    }
    
安裝apk:
int install_app(transport_type transport, char* serial, int argc, char** argv)
{
//下載路徑
    const char *const DATA_DEST = "/data/local/tmp/%s";
    const char *const SD_DEST = "/sdcard/tmp/%s";
    const char* where = DATA_DEST;


//將apk文件寫入到to目錄下
    if (!(err = do_sync_push(filename, to, 1 /* verify APK */))) {
        /* file in place; tell the Package Manager to install it */
        argv[argc - 1] = to;       /* destination name, not source location */
        pm_command(transport, serial, argc, argv);
        delete_file(transport, serial, to);
    }
...
}

通知android系統進行安裝apk包
static int pm_command(transport_type transport, char* serial,
                      int argc, char** argv)
{
snprintf(buf, sizeof(buf), "shell:pm");

//通知包管理器安裝apk應用,即使用pm命令安裝應用
send_shellcommand(transport, serial, buf);
return 0;
}

usage: pm [list|path|install|uninstall]
       pm list packages [-f]
       pm list permission-groups
       pm list permissions [-g] [-f] [-d] [-u] [GROUP]
       pm list instrumentation [-f] [TARGET-PACKAGE]
       pm list features
       pm path PACKAGE
       pm install [-l] [-r] [-t] [-i INSTALLER_PACKAGE_NAME] [-s] [-f] PATH
       pm uninstall [-k] PACKAGE
       pm enable PACKAGE_OR_COMPONENT
       pm disable PACKAGE_OR_COMPONENT
       pm setInstallLocation [0/auto] [1/internal] [2/external]

最後:

源碼的OVERVIEW.txt文件中對它們的關係進行了描述。而protocol.txt描述了各模塊之間通信協作的協議格式。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章