ADB 原理(第一篇:基本工作过程)
https://developer.android.com/studio/command-line/adb后悔没早点学Linux啊,尼玛 设备文件分为两种:块设备文件(b)和字符设备文件(c)1:adbserver发送cmd(命令)到手机2:adbd(adbdaemon)的outputthread从/dev/android_usb读取到cmd并解析(adbd进程和内...
前言
不是闲的蛋疼研究adb,而是你经常使用adb,万一那天碰见个疑难杂症,一时半会儿解决不了可就麻烦了,一旦你知道了原理,不仅能解决项目中遇到的问题,而且还能温习adb的知识点,一箭多叼,还有最重要的是你可以拿来装13(玩笑)
adb作为Android的内部工具,名字起的那是相当的洒脱,adb这个名字就像微信、qq的名字一样,只不过adb是给开发者使用的工具,所以直接google开发者直接使用Android Debug Bridge的首字母adb作为工具的名字了……这样工程师们交流起来简单多了,开口就是adb、adb、adb、而不用说长长的Android Debug Bridge。就像你有个朋友叫做xxxxx,它一定会有个短的外号是吧,哈哈!!
adb架构
adb采用客户端-服务端程序架构,简称C-S架构,从进程角度看,adb由3个进程组成,3个进程分布在不同的端上,请继续听我bb,往下看
电脑上:2个进程,分别称为adb client和adb server
手机上:1个进程,进程名是adbd,就被称为adbd
往下看我画的一张简图,是不是思路更清晰了呢
电脑上参与的进程有2个,详细说说
1、命令行客户端,这个进程称为adb client
当我们在命令行输入adb命令时,实际启动的是这个进程,比如我们在命令行输入一个adb devices,adb client进程创建并执行
2、另一个Server进程,这个进程称为adb server,它是一个守护进程(常驻在电脑内存中)
adb client进程使用时,如果没有在5037端口找到adb server进程,它就会告知启动一个adb server进程,启动后的adb server进程会一直监听在5037端口上(默认),等待着adb client进程与它通信,当adb server进程启动后,adb client进程每次都会与adb server进程建立TCP连接(Network Socket),然后将具体的命令传给adb server,adb server收到adb client的命令,一般会有两个出方案,要么自己直接处理,要么通过usb或者tcp发送给手机上的adbd进程进行处理,比如我们在命令行输入adb devices,此时的devices是作为“命令”传给adb server进程(这里有点坑哦,adb client进程可能自己也会处理一些业务逻辑,看来还得看adb的源码去)
手机上的1个adbd进程(开机自启),再聊1分钟
1、手机启动后,启动一个称为adbd的进程,它由init进程fork出来。 为啥adbd会被启动呢?这是由于内核启动后,会首先创建init进程,而init进程在启动过程中会读取一个init.rc文件,在init.rc文件中有一个Service List,表示需要启动的进程列表,里面记录着需要init进程启动的守护进程,其中有adbd进程
通信过程
下图为adb server进程与adbd进程的通信,图是我借的,哪位大哥来认领一下?
1、adb client进程通过Socket(网络Socket)告知adb server进程需要执行的动作
2、adb server进程发送cmd(命令)到手机(写到Usb Driver文件中,Linux中一切都是文件,usb驱动程序操作的是文件)
3、adbd(adb daemon)的output thread(1根线程)会一直从/dev/android_usb文件中读取发送过来的cmd(命令)
备注:由于adbd进程读取了/dev/android_usb(设备结点文件),此时相当于和Linux内核中的usb driver驱动程序进行数据交互!
4、adbd中的output thread将解析到的cmd(命令)写到1个socketpair的A端(这是Unix Domain Socket通信,简称UDS)
5、fdevent_loop(文件描述符事件循环线程,看来到处都是事件循序)会不断的通过使用Linux内核提供的select()系统调用(IO多路复用机制) ,在socketpair的B端读取到cmd(命令)
6、fdevent_loop发出的命令会在adbd的子进程中执行,子进程返回的结果往往是标准输出和标准错误,此时的结果会再写到socketpair的B端
7、Input thread(一个读线程)一直阻塞式(没有数据,只会休眠阻塞在这里,并不占用cpu时间片)读取socketpair的A端
8、Input thread从socketpair的A端读取到数据后,写入设备结点文件/dev/android_usb
9、此时usb driver驱动程序发现设备结点文件改变,会再将response发给pc端的adb server进程
10、adb server进程收到响应后,会再将响应返回给adb client进程,此时你就能在命令行看到命令的输出了(标准输出和标准错误)
技术栈备注:进程间的通信、进程间的同步、线程间的通信、线程间的同步!!大写的牛逼!!
adb devices的工作过程讲解(待求证,仅举例)
1、在命令行输入adb devices
2、adb client进程创建并开始执行,它先根据约定好的标准去本地的5037端口,检查adb Server进程是否已经启动,发现5037端口并没有进程绑定,此时的adb Client进程会去启动一个守护进程,即adb Server进程(备注:不确定adb Server是先与adbd建立关系,还是先和adb client建立连接,但我觉得它的线程一直在读取usb的情况)
3、接着adb client进程与adb server进程建立TCP连接(网络Socket)
4、adb client进程会将devices命令(字符串)传送到adb server进程中,adb server进程与adbd可以建立usbable连接或者TCP连接
5、devices命令(字符串)到达adbd进程后,adbd发起处理,根据命令的不同分为两种情况,内部处理或者交给Android内部的bash处理,处理结束后会再将消息告知adb server进程,adb server进程再把结果告诉adb client进程,结果一般是某个命令的标准输出与标准错误(向屏幕写入的内容),devices应该算时个内部处理的命令,不用交给bash处理
6、adb client进程将收到的adb server返回的结果展示到标准输出上,就在你的黑窗口上(屏幕),同时adb client进程也会结束掉,同时断掉于adbserver的TCP连接
备注:TCP连接,内核中的标准称为Network Socket,不同主机之间的进程可以建立,本机中的不同进程间也可以建立!
补充知识:聊一聊Linux内核中的socketpair()函数
socketpair()函数可以创建1对无名、相互连接的Socket,也被称为Unix Domain Socket,简称UDS,如果socketpair()函数执行成功,则返回值为0(0代表成功,也称退出状态码),创建好的Socket分别是sv[0]和sv[1];执行失败则会返回-1,错误码保存在标准错误中
1. 这一对Socket支持全双工通信,每一个Socket在同一时刻即可读也可写
2. 读、写操作可以是位于同一个进程的不同线程,或者位于不同的进程。如父子进程、兄弟进程(注意:UDS只能用于具有血缘关系的进程,跟PIPE一样,但socketpair全双工)
若是父子进程,一般会做功能分离,一个进程读,另一个进程写。因为文件描述符sv[0]和sv[1]为进程共享,所以读进程需关闭写描述符, 反之,写进程需关闭读描述符
补充知识:UDS与Network Socket
两种socket进程通信方式
1、Unix Domain Socket:UDS只能在单机中通信,操作的双方可以是同一个进程的不同线程,也可以是不同的进程
2、Network Socket:Network Socket能在不同的主机中通信,也能在同一个主机中的不同进程间使用
adb命令到底是谁来处理的
一共就3种可能性
1、adb client 自己就处理了,比如adb version
2、adb client交给adb server,adb server自行处理
3、adb client交给adb server,再有adb server交给手机上的adbd处理
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)