android2.3-adb源码分析

来自:http://www.apkbus.com/android-20594-1-1.html


 

3、以常用命令为实例

常用的指令如下:

  1. adb push <local> <remote>    - copy file/dir to device
  2. adb pull <remote> [<local>]  - copy file/dir from device
  3. adb shell                    - run remote shell interactively
  4. adb install [-l] [-r] [-s] <file> - push this package file to the device and install it
  5. adb kill-server              - kill the server if it is running
  6. connect <host>[:<port>]      - connect to a device via TCP/IP
  7.                                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决定执行哪些代码:

  1. int main(int argc, char **argv)
  2. {
  3. ...
  4. adb_trace_init();
  5. #if ADB_HOST
  6.     adb_sysdeps_init();
  7.     return adb_commandline(argc - 1, argv + 1);  //这里运行PC端,用于命令发送
  8. #else
  9.     start_device_log();
  10.     return adb_main(0, DEFAULT_ADB_PORT);  //运行于android系统的盒子或设备上,用于命令接收及反馈
  11. #endif
  12. }
复制代码

先分析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进行数据传递


然后分析设备服务端:

主要集中在函数:
  1. fdevent_loop();


  2. 主要分析一下数据transport这块,文件Transport.c

  3. void init_transport_registration(void)
  4. {
  5. adb_socketpair(s) //创建socket pair用于处理异步注册事件

  6.     transport_registration_send = s[0];
  7.     transport_registration_recv = s[1];


  8. // 在transport_registration_recv上安装一个transport_registration_func异步事情回调函数
  9.     fdevent_install(&transport_registration_fde,
  10.                     transport_registration_recv,
  11.                     transport_registration_func,
  12.                     0);
  13.                     
  14.     ... 
  15. }
复制代码


异步如何触发的呢?

  1. register_transport
  2. -->transport_write_action(transport_registration_send, &m)

  3. remove_transport
  4. -->transport_write_action(transport_registration_send, &m)
复制代码



此时会将事件写入socket pair的写入端,而接收端:


  1. void fdevent_loop()
  2. {
  3. ...

  4. for(;;) {

  5. while((fde = fdevent_plist_dequeue())) {
  6.        unsigned events = fde->events;
  7.        fde->events = 0;
  8.        fde->state &= (~FDE_PENDING);
  9.        dump_fde(fde, "callback");
  10.        
  11.        //这个回调函数是在:fdevent_install 函数中注册的:fde->func = func;
  12.        fde->func(fde->fd, events, fde->arg);
  13.   }
  14. }
  15. }
复制代码


然后利用transport_read_action读取异步事情,那么数据处理在哪里呢?


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

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


  8.         if(adb_thread_create(&output_thread_ptr, output_thread, t)){
  9.             fatal_errno("cannot create output thread");
  10.         }
  11.     }
  12.    
复制代码


在这里会创建两个线程 output thread和 input thread用于做异步 IO,   

=============================================================================

根据 adb的文档说明, output线程和 input线程的引人主要是为了解决 USB endpoint不支持非

阻塞读写,所以就专门为 usb读操作开一个output线程,为usb写操作创建一个input线程。

所以,数据流方向是远程连接->output线程->主线程->input线程->远程连接。刚开始时,

output线程会发一个 SYNC消息给input线程,启动这个transport。



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

  6. t->write_to_remote(p, t);

  7. }
  8. }


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

  14. t->read_from_remote(p, t);

  15. write_packet(t->fd, &p);
  16. }
  17. }
复制代码


=============================================================================


说一下我开始疑惑的问题解决:

adb shell 命令处理:

  1. if(!strcmp(argv[0], "shell")) {
  2. if(argc < 2) {
  3.        return interactive_shell();
  4.     } 
  5. }


  6. int interactive_shell(void)
  7. {
  8. fd = adb_connect("shell:");

  9. adb_thread_create(&thr, stdin_read_thread, fds);
  10. }
复制代码



而服务端处理:


  1. #if ADB_HOST
  2. #define SHELL_COMMAND "/bin/sh"
  3. #else
  4. #define SHELL_COMMAND "/system/bin/sh"
  5. #endif

  6. int service_to_fd(const char *name)
  7. {
  8. if(!HOST && !strncmp(name, "shell:", 6)) {
  9. if(name[6]) {
  10.      ret = create_subprocess(SHELL_COMMAND, "-c", name + 6);
  11. } else {
  12.      ret = create_subprocess(SHELL_COMMAND, "-", 0);
  13. }
  14. }

  15. ...
  16. }
复制代码



单独创建出一个进程进行处理shell命令

  1. static int create_subprocess(const char *cmd, const char *arg0, const char *arg1)
  2. {
  3. pid = fork();

  4. if(pid == 0){
  5. execl(cmd, cmd, arg0, arg1, NULL);
  6. }else
  7. ...
  8. }
复制代码


adb install xxx.apk 处理方式:

  1.     if(!strcmp(argv[0], "install")) {
  2.         if (argc < 2) return usage();
  3.         return install_app(ttype, serial, argc, argv);
  4.     }


  5.     if(!strcmp(argv[0], "uninstall")) {
  6.         if (argc < 2) return usage();
  7.         return uninstall_app(ttype, serial, argc, argv);
  8.     }
  9.     
复制代码

安装apk:

  1. int install_app(transport_type transport, char* serial, int argc, char** argv)
  2. {
  3. //下载路径
  4.     const char *const DATA_DEST = "/data/local/tmp/%s";
  5.     const char *const SD_DEST = "/sdcard/tmp/%s";
  6.     const char* where = DATA_DEST;


  7. //将apk文件写入到to目录下
  8.     if (!(err = do_sync_push(filename, to, 1 /* verify APK */))) {
  9.         /* file in place; tell the Package Manager to install it */
  10.         argv[argc - 1] = to;       /* destination name, not source location */
  11.         pm_command(transport, serial, argc, argv);
  12.         delete_file(transport, serial, to);
  13.     }
  14. ...
  15. }

  16. 通知android系统进行安装apk包
  17. static int pm_command(transport_type transport, char* serial,
  18.                       int argc, char** argv)
  19. {
  20. snprintf(buf, sizeof(buf), "shell:pm");

  21. //通知包管理器安装apk应用,即使用pm命令安装应用
  22. send_shellcommand(transport, serial, buf);
  23. return 0;
  24. }
复制代码

  1. usage: pm [list|path|install|uninstall]
  2.        pm list packages [-f]
  3.        pm list permission-groups
  4.        pm list permissions [-g] [-f] [-d] [-u] [GROUP]
  5.        pm list instrumentation [-f] [TARGET-PACKAGE]
  6.        pm list features
  7.        pm path PACKAGE
  8.        pm install [-l] [-r] [-t] [-i INSTALLER_PACKAGE_NAME] [-s] [-f] PATH
  9.        pm uninstall [-k] PACKAGE
  10.        pm enable PACKAGE_OR_COMPONENT
  11.        pm disable PACKAGE_OR_COMPONENT
  12.        pm setInstallLocation [0/auto] [1/internal] [2/external]
复制代码

最后:

源码的OVERVIEW.txt文件中对它们的关系进行了描述。而protocol.txt描述了各模块之间通信协作的协议格式。

你可能感兴趣的:(thread,android,shell,command,output,subprocess)