ADB 源码分析

ADB 源码分析(一) ——ADB模块简述


1、Adb 源码路径(system/core/adb)。

2、要想很快的了解一个模块的基本情况,最直接的就是查看该模块的Android.mk文件,下面就来看看adb模块的Android.mk文件:

  ……

  ifeq ($(HOST_OS),linux) //用HOST_OS这个宏来兼容不同的操作系统的adb可执行程序(windows、Linux……)

   USB_SRCS := usb_linux.c

   EXTRA_SRCS := get_my_path_linux.c

   LOCAL_LDLIBS += -lrt -lncurses -lpthread

  endif

  ……

  LOCAL_MODULE := adb  //编译生成adb可执行程序。运行于PC端,通过HOST_OS这个宏来兼容不同的操作系统

  ……

  include $(BUILD_HOST_EXECUTABLE)

  ……

  ……

  LOCAL_MODULE := adbd //运行在手机端或模拟器等终端设备的adbd daemon进程

  LOCAL_FORCE_STATIC_EXECUTABLE := true

  LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT_SBIN)

  LOCAL_UNSTRIPPED_PATH := $(TARGET_ROOT_OUT_SBIN_UNSTRIPPED)

  LOCAL_STATIC_LIBRARIES := libcutils libc

  include $(BUILD_EXECUTABLE)

  ……

  ifneq ($(SDK_ONLY),true)

  LOCAL_MODULE := adb //编译sdk时生成一个adb可执行程序sdk/platform-tools/adb

  LOCAL_STATIC_LIBRARIES := libzipfile libunz libcutils

  include $(BUILD_EXECUTABLE)。

  通过查看system/core/adb模块的Android.mk文件,我们队adb有了一个初步的印象: “adb的工作是由两个可执行文件完成的”。

  a)、adb/adb.exe:运行于PC端(包括Linux、Windows、MacOS等操作系统之中),通常是x86架构之上。也就是我们常用的Android开发工具 

 SDK中(platform/tools/adb),我们在命令提示行执行adb命令时,就是通过这个adb程序执行的。

  b)、adbd:运行于Android设备的底层Linux之中,ARMv5架构上。构建不同文件,通过传入Android.mk的$(BUILD_SIMULATOR)变量是否为真。

 源码中由ADB_HOST宏用来区分本地主机(adb)和目标机(adbd)。区分不同OS,通过传入Android.mk的$(HOST_OS)。它的有效取值包括linux、   

 darwin、freebsd和windows。不同平台的主要差异是USB的控制方法和文件路径。

3、直接编译该模块,可以看到会生成如下一些内容:

   编译生成的也就是我们上面讲到的adb模块的两个可执行文件(adb和adbd daemon)。我们进入adb shell下,在sbin/目录下存在一个adbd可执行程序,这就是就是ADB模块编译生成的这个adbd可执行程序。而我们在安装Android开发环境的时候有指定过sdk的环境变量,因此我们在命令行下面输入的adb命令,就是通过sdk中的adb这个可执行程序进行响应的。 我们通过ps命令可以看到adb和adbd也分别运行于PC端和Adb设备中,也就是说我们执行的所有的adb命令都是通过adb进程与adbd 守护进程之间进行数据交换的结果。

4、 通过上面的介绍,相信我们对ADB模块已经有了一个初步的印象了,要想更进一步了解adb模块,就需要深入的去分析一些整个adb模块的实现的方式了。在分析整个模块代码之前,我们先看一下Google对整个ADB模块的介绍(在system/core/adb目录下有一个OVERVIEW.txt文件),这个文件介绍了这个adb模块的工作过程。英文好的同学可以详细的阅读一下OVERVIEW.txt这个文件,这个文件对整个ADB模块的工作原理讲的比较透彻。  

 简单的看看这个文件的描述,整个ADB模块由如下几个模块组成:

a)、The ADB server(adb): 运行在PC端的一个后台应用程序,用来检测Android Devices的连接或去除。ADB Server是一个时刻协调交换Client、Services和Android devices之间的数据。

b)、The ADB daemon (adbd) : 运行于一个Android Devices/Emulator的后台守护进程,该进程主要是用来连接ADB Server通过USB(模拟器通过TCP协议)为adb clients提供一些运行于PC端的services。

c)、The ADB command-line client: 执行adb 命令的终端,它会找出PC端的运行的adb server如果没有找到就会自动的启动adb server,然后向adb server发送请求命令。

d)、Services: 由此服务给adbd提供功能,即由这个模块完成,主要分为Host Services及 Local Services两类

     Host Services: 运行于ADB Server,不需要和devices进行数据交换。典型的就是执行adb devices命令时,只需要adb server端返回当前的adb devices的状态即可。

     Local Services: 运行于adbd守护进程,ADB Server 在adb clients和Local Services之间复用Streams。Local Services 用来初始化传递数据的连接。

ADB 通讯模型图(欲了解更详细的情况可以查看system/core/adb/transports.txt文件中的介绍)

                

                                     (adb 通讯模型图)

                                 

5、要想进一步了解adb命令的工作方式,就需要我们进一步研究adb模块的源码。Adb运行的入口在system/core/adb/adb.c中,下面来初步看看adb.c的main()方法:

int main(int argc, char **argv)

{

#if ADB_HOST //前面讲到在Android.mk中定义了这个宏,如果编译adb ADB_HOST = 1否则ADB_HOST = 0

    adb_sysdeps_init();

    adb_trace_init();

    D("Handling commandline()\n");

    return adb_commandline(argc - 1, argv + 1); //运行PC端的adb/adb.exe可执行程序

#else

    /* If adbd runs inside the emulator this will enable adb tracing via

     * adb-debug qemud service in the emulator. */

    adb_qemu_trace_init();

    if((argc > 1) && (!strcmp(argv[1],"recovery"))) {

        adb_device_banner = "recovery";

        recovery_mode = 1;

    }

    start_device_log();

    D("Handling main()\n");

    return adb_main(0, DEFAULT_ADB_PORT); //运行Android devices/emulator 的adbd可执行程序

#endif

}。

小结:本篇文档主要讲解了以下内容:

1、adb模块的源码路径,源码编译生成的结果。

2、adb模块分为adb client、adb server、services、adbd daemon几个模块。

3、adb通讯模型。

4、adb与 adbd daemon的入口函数

                                        ADB源码分析(二)——adb sever的启动

1、 ADB Server的启动

前面我们讲到adb模块的源码在system/core/adb下面,通过查看Android.mk文件我们了解到这个adb

模块回编译生成连个可执行文件adbadbd,源码通过ADB_HOST这个宏来控制编译的是adb还是adbd。首先我们来看看这个运行于PC端的adb——ADB Server

下面我们就来看看ADB Server的启动adb.csystem/core/adb/):

 

    接着来看看adb_commandline()(system/core/adb/commandline.c)的实现,它用来接收adb client输入的adb命令。(OVERVIEW.txt中有如下一段描述:是说adb server是通过adb client来启动的。 

      

    下面就以adb shell命令为例来看看adb client是如何来启动adb server的。

       

       

       

此时由于ADB Server没有启动,因此socket_loopback_client的返回值为-1_adb_connect()的返回值就为-2。下面就能看到adb client是如何启动ADB Server的了。

       

至此,我们需要再重新查看adb_commandline()方法了,此时我们执行的是adb fork-server server命令,因此is_server = 1, is_daemon = 1

      

    在adb_main中通过ADB_HOST这个宏来控制ADB Serveradbd daemonAndroid.mk文件中可以看出编译adb server的时候ADB_HOST这个宏为1,而编译adbd_daemonADB_HOST0

       

    接下来我们来依次看看ADB Server启动时都做了哪些事情?

    a)init_transport_registration():

        

上面讲到transport_registration_func这个回调函数会在transport_registration_send这个Socket执行写操作时,会被调用,那什么时候会执行写操作呢?后面再来解答这个问题。

    b)、下面再来看看usb_init(),初始化usb设备监听。

        

        

此处我们就解答了上面的疑惑transport_register_func()什么时候会被调用。再来看看transport_register_func()又做了些什么呢?

         

        

3local_init()

        

4install_listener()

        

5、fdevent_loop();//通过IO多路选择机制来选择出要执行的fdevent,并执行它的毁掉函数。

        

上面我们详细的讲解了ADB Server的启动过程,那么ADB Server启动后又是如何与adb client以及adbd daemon进行通信的呢?下面我们在来看看。

 

     下面我们继续来以adb shell为例来分析:

       

此时fd = socket_loopback_client(__adb_server_port, SOCK_STREAM); 此时5037端口已经被监听,返回值fd 5037端口的Socket

       

此时ADB Server端已经启动,fdevent_install(&l->fde, l->fd, ss_listener_event_func, l); ss_listener_event_func这个回调函数就会执行(后面再来看这个函数做了些什么)

       

同时在interactive_shell()方法中,还创建了一个线程,用来读取client端输入的命令以及将该命令发送到ADB Server端进行处理。

       

通过上面这个thread就会将终端输入的命令发送到adb server端了。上面还讲到client端会发送一个tmp消息给ADB Server端,然后等待ADB Server端的响应OKAY/FAIL,那么ADB Server端又是如何响应的呢?下面我们在来进一步分析。

 

     先来看看ss_listener_event_func

               

至此ADB Server端与adb client端的Socket建立完成了。上面在_adb_connect会向adb server端写一个字符串,此时ADB Server端的local_socket_event_func方法将会被执行。

        

        

下面来看一下transport_sockets_events()

        

        

对于adb shell命令具体是如何操作的不是我们的重点,我们的重点是介绍adb的通信流程,因此在此就不再详细分析。下面再来看看是如何将adb shell命令发送到adbd daemon的。

启动adb server的时候创建了两个线程,input_threadoutput_threadinput_thread一直监听5037端口,因此会接收到client端输入的adb shell命令。然后通过 t->write_to_remote(p, t);发送到adbd daemon.

前面在初始化usb的时候(init_usb_transport())     

t->read_from_remote = remote_read;

t->write_to_remote = remote_write;

再来看看ADB Server是如何通过remote_writeADB Server端的命令发送到adbd daemon的。

        

至此,我们已经了解了adb shell命令是如何发送到adbd daemon那边的了。下面再来看看adbd daemon是如何处理这些命令的。

ADB 源码分析(三)——adbd daemon

1、adbd daemon的启动:

   adbd daemon是adb devices/emulator后台运行的一个守护进程,它是由init进程启动的。在init.rc中可以看出adbd daemon在系统一开机就已经启动,而且即使被杀掉,系统也会重新启动该进程。

     

    前面讲到Adb Server与 adbd daemon是由同一套代码,通过一个ADB_HOST宏来控制的。也就是说,adbd daemon的入口函数依然是adb.c的main方法。下面继续来看adb.c的main方法。

     

    从上面的分析来看,这个和Adb Server启动时的流程基本上是一致的。不过从Android.mk文件中就可以看到,Adb Server与adbd daemon编译时的文件与Adb Server有一些差别。下面就简单讲讲adbd daemon与ADB Server启动的差别之处,相同之处在此就不再分析了。

    我们都知道我们手机版本有user版本和eng版本,这两个版本的一些区别想必大家都有所了解,而对于我们开发人员最直接的区别就是user版本无法执行adb remount操作,也就是user版本没有root权限。那user版本为什么会没有root权限了,想必肯定会与adbd daemon有一定的关系,下面简单看看。

      

      

      如果是usr版本,adbd daemon启动时会执行如下代码。

      /* then switch user and group to "shell" */

       if (setgid(AID_SHELL) != 0) {

           exit(1);

        }

       if (setuid(AID_SHELL) != 0) {

          exit(1);

        }

//原来在执行上述代码之前,adbd daemon还是root权限,在执行完上述代码之后,adbd daemon就运行于shell权限了

    这样一来usr版本就存在一个漏洞,执行这段代码之前运行于root权限,执行这段代码之后运行于shell权限,那么只要在系统启动时想办法屏蔽这段代码,那么就可以adbd daemon就可以一直运行于root权限了。用户可以利用这个漏洞来进行破解获取root权限,目前市场上通用的root user版本来获取root权限,基本上就是基于这个漏洞来进行的。具体的实现方法网上有很多很多,有兴趣的同学可以自行尝试。

   下面继续看看Adb Server与adbd daemon启动的差异usb_init()(system/core/usb_linux_client.c)此处的usb_init和 ADB Server

端的usb_init不是同一个方法。

        

    后面执行register_usb_transport(usb, 0, 1)的过程和ADB Server端启动的方式是一样的。

2、adbd daemon与Adb Server数据的传递

    那么我们直接来看看adbd daemon接收ADB Server端数据的过程,继续以adb shell命令为例来分析。前面讲到Adb Server启动时会创建两个线程input_thread、output_thread, 同样在adbd daemon中也会创建这样两个线程,用来处理Adb Server端发送的数据,并将响应结果返回给Adb Server端。

     

    当adbd daemon进程接收到ADB Server发送过来的shell命令时,output_thread线程会执行read_from_remote()方法接收ADB Server端的命令,然后执行write_packet()方法,此时会触发transports_socket_events()方法。这些步骤和ADB Server端的处理是同样的,唯一不同的是: 

adbd daemon端会启动一个新的进程来专门处理adb shell命令,在这个进程中会执行/system/bin/目录下的sh可执行文件(我们也可以在

adb shell下直接执行以下这个sh文件,来看看这个执行结果)。

      

      在adb shell下,我们到system/bin/目录下也可以找到sh这个可执行文件。

小结:本片文档主要讲解了以下几个部分

     1、adbd daemon 的启动流程。

     2、user版本的adbd daemon运行于shell权限的原因,root user版本的基本原理。

     3、adbd daemon与adb server之间通信。

     4、“adb shell”命令的执行流程。


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值