ADB(一)_概况了解
ADB(二)_ADBD_main()函数代码梳理
ADB(三)_ADBD_adbd_main()函数代码梳理
ADB(四)_host端的启动流程代码梳理
ADB(五)_host端adb server相关的代码梳理
ADB(六)_调试ADB(ADB设置自身日志的代码梳理和设置ADB自身日志可见)
首先,我们知道,开发中在使用ADB的时经常使用的是USB连接Android开发设备。我们今天就主要对USB通信进行分析;不过我们不会对USB本身的协议、原理、实现等方面进行说明,那些不在我们讨论的范围内,我们只是就USB通信在ADB的的使用进行源代码层面的梳理。
我们的USB通信是连接host端的adb程序和Android端的adbd程序,所以我们需要分别对adb 和adbd 的运行过程有所了解,具体可以参考前面讨论过的文章;
在adbd的初始化流程中,我们在adbd_main()函数中看到有调用usb_init()函数,usb_init()函数就是usb初始化的入口。我们先看看usb_init()函数是如何被调用的:
bool is_usb = false;
if (access(USB_FFS_ADB_EP0, F_OK) == 0) {
// Listen on USB.
usb_init();
is_usb = true;
}
首先,会有个判断,主要是通过调用access()函数,这个access()函数是用于检查调用进程是否可以对指定的文件执行某种操作
。这里简单的先把这个函数介绍一下:
函数定义在:unistd.h中,
/* Test for access to NAME using the real UID and real GID. */
extern int access (const char *__name, int __type) __THROW __nonnull ((1));
。。。
/* Values for the second argument to access.
These may be OR'd together. */
#define R_OK 4 /* Test for read permission. */
#define W_OK 2 /* Test for write permission. */
#define X_OK 1 /* Test for execute permission. */
#define F_OK 0 /* Test for existence. */
在当前的程序代码中,access()函数的需要检测的参数是USB_FFS_ADB_EP0
,这USB_FFS_ADB_EP0又是什么呢?
我们就从定义出看看:/system/core/adb/adb.h
...
#if !ADB_HOST
#define USB_FFS_ADB_PATH "/dev/usb-ffs/adb/"
#define USB_FFS_ADB_EP(x) USB_FFS_ADB_PATH #x
#define USB_FFS_ADB_EP0 USB_FFS_ADB_EP(ep0)
...
经过上述的宏定义,我们知道USB_FFS_ADB_EP0等价于/dev/usb-ffs/adb/ep0
;所以判断当前/dev/usb-ffs/adb/ep0
文件【USB节点】是否存在,如果存在就调用usb_init()函数:
void usb_init() {
...
usb_ffs_init();
}
usb_init()函数里面主要通过调用usb_ffs_init()函数,我们就需要到usb_ffs_init()中去,
static void usb_ffs_init() {
D("[ usb_init - using FunctionFS ]");
usb_handle* h = new usb_handle();
if (android::base::GetBoolProperty("sys.usb.ffs.aio_compat", false)) {
// Devices on older kernels (< 3.18) will not have aio support for ffs
// unless backported. Fall back on the non-aio functions instead.
h->write = usb_ffs_write;
h->read = usb_ffs_read;
} else {
h->write = usb_ffs_aio_write;
h->read = usb_ffs_aio_read;
aio_block_init(&h->read_aiob);
aio_block_init(&h->write_aiob);
}
h->kick = usb_ffs_kick;
h->close = usb_ffs_close;
D("[ usb_init - starting thread ]");
std::thread(usb_ffs_open_thread, h).detach();
}
如上所示是usb_ffs_init()函数的定义,在一开始,我们首先创建一个usb_handle的,这个usb_handle是个与USB连接先关的struct。
struct usb_handle {
usb_handle() : kicked(false) {
}
std::condition_variable notify;
std::mutex lock;
std::atomic<bool> kicked;
bool open_new_connection = true;
int (*write)(usb_handle* h, const void* data, int len);
int (*read)(usb_handle* h, void* data, int len);
void (*kick)(usb_handle* h);
void (*close)(usb_handle* h);
// FunctionFS
int control = -1;
int bulk_out = -1; /* "out" from the host's perspective => source for adbd */
int bulk_in = -1; /* "in" from the host's perspective => sink for adbd */
// Access to these blocks is very not thread safe. Have one block for both the
// read and write threads.
struct aio_block read_aiob;
struct aio_block write_aiob;
};
在常见一个新的usb_handle后,程序会获取Android系统属性sys.usb.ffs.aio_compat
判断,根据属性值分别对usb_handle内部的变量进行赋值;
紧接着,就会创建并启动一个新的线程去执行sb_ffs_open_thread()函数,并把前面创建的并赋值好变量的结构体usb_handle传进去;我们跳转到usb_ffs_open_thread()中继续分析:
std::thread(usb_ffs_open_thread, h).detach();
static void usb_ffs_open_thread(void* x) {
struct usb_handle* usb = (struct usb_handle*)x;
adb_thread_setname("usb ffs open");
while (true) {
// wait until the USB device needs opening
std::unique_lock<std::mutex> lock(usb->lock);
while (!usb->open_new_connection) {
usb->notify.wait(lock);
}
usb->open_new_connection = false;
lock.unlock();
while (true) {
if (init_functionfs(usb)) {
LOG(INFO) << "functionfs successfully initialized";
break;
}
std::this_thread::sleep_for(1s);
}
LOG(INFO) << "registering usb transport";
register_usb_transport(usb, 0, 0, 1);
}
// never gets here
abort();
}
如上所述,usb_ffs_open_thread()函数会进入一个while死循环,在外面大的while循环中:
在usb初始化完成后,会调用register_usb_transport()函数来注册usb传输;
void register_usb_transport(usb_handle* usb, const char* serial, const char* devpath,
unsigned writeable) {
atransport* t = new atransport((writeable ? kCsOffline : kCsNoPerm));
init_usb_transport(t, usb);
...
{
std::lock_guard<std::recursive_mutex> lock(transport_lock);
pending_list.push_front(t);
}
register_transport(t);
}
register_usb_transport()函数中首先创建一个新的atransport实例,当前的writeable=1,所以类atransport的成员变量connection_state_ = kCsOffline;
紧接着调用init_usb_transport()函数;
void init_usb_transport(atransport* t, usb_handle* h) {
D("transport: usb");
t->connection.reset(new UsbConnection(h));
t->sync_token = 1;
t->type = kTransportUsb;
}
init_usb_transport()函数主要就是将atransport内部的相关成员变量初始化;然后将当前的atransport示例装到pending_list列表中,只要是保存待处理消息的。pending_list定义如下:
static auto& pending_list = *new std::list<atransport*>();
最后会调用register_transport().方法,进行注册传输.
/* the fdevent select pump is single threaded */
static void register_transport(atransport* transport) {
tmsg m;
m.transport = transport;
m.action = 1;
D("transport: %s registered", transport->serial);
if (transport_write_action(transport_registration_send, &m)) {
fatal_errno("cannot write transport registration socket\n");
}
}
register_transport()函数主要作用就是封装起一个tmsg,然后通过transport_write_action()函数写入到transport_registration_send中,然后在程序中的另一端进行处理:
程序利用poll()机制,可以很方便的监听众多的fd.一旦当前的transport_registration_send中有数据的写入,poll()就会通知程序去处理;
接下来,我们需要把重点放到transport_registration_send
中去,看看它是怎么将当前分行装好的消息传递到相关的函数中进行处理的.
我们先回到 adbd_main()函数中,在调用usb_init()函数前调用了init_transport_registration()函数;我们来看看:
void init_transport_registration(void) {
int s[2];
if (adb_socketpair(s)) {
fatal_errno("cannot open transport registration socketpair");
}
D("socketpair: (%d,%d)", s[0], s[1]);
transport_registration_send = s[0];
transport_registration_recv = s[1];
fdevent_install(&transport_registration_fde, transport_registration_recv,
transport_registration_func, 0);
fdevent_set(&transport_registration_fde, FDE_READ);
}
这个函数我们在前篇的文章中遇到过,这里为了更好的理解,我再次再简单说一下流程.
这就是处理s[1]中数据的函数
】封装到transport_registration_fde【fdevent】; 紧接着就会将transport_registration_fde以transport_registration_recv为key,PollNode(fde)为value装到g_poll_node_map中去。void fdevent_install(fdevent* fde, int fd, fd_func func, void* arg) {
...
memset(fde, 0, sizeof(fdevent));
fde->state = FDE_ACTIVE;
fde->fd = fd;
fde->func = func;
fde->arg = arg;
...
auto pair = g_poll_node_map.emplace(fde->fd, PollNode(fde));
...
}
经过前面的分析,我们就知道了, **5. register_transport(t)**中的消息将会在transport_registration_func()函数中进行处理;我们就来看看是怎么进行处理的吧:
static void transport_registration_func(int _fd, unsigned ev, void* data) {
tmsg m;
int s[2];
atransport* t;
...
if (transport_read_action(_fd, &m)) {
fatal_errno("cannot read transport registration socket");
}
t = m.transport;
...
/* don't create transport threads for inaccessible devices */
if (t->GetConnectionState() != kCsNoPerm) {
/* initial references are the two threads */
t->ref_count = 2;
if (adb_socketpair(s)) {
fatal_errno("cannot open transport socketpair");
}
D("transport: %s socketpair: (%d,%d) starting", t->serial, s[0], s[1]);
t->transport_socket = s[0];
t->fd = s[1];
fdevent_install(&(t->transport_fde), t->transport_socket, transport_socket_events, t);
fdevent_set(&(t->transport_fde), FDE_READ);
std::thread(write_transport_thread, t).detach();
std::thread(read_transport_thread, t).detach();
}
{
std::lock_guard<std::recursive_mutex> lock(transport_lock);
pending_list.remove(t);
transport_list.push_front(t);
}
update_transports();
}
这里我先概括一下transport_registration_func()函数的逻辑:
transport_read_action(_fd, &m)
来实现的fdevent_install(&(t->transport_fde), t->transport_socket, transport_socket_events, t);
这次封装的处理函数是transport_socket_events(),我们就要看看当usb传输通道中有数据时,会怎么进行处理的;
static void transport_socket_events(int fd, unsigned events, void* _t) {
atransport* t = reinterpret_cast<atransport*>(_t);
D("transport_socket_events(fd=%d, events=%04x,...)", 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", t->serial, fd);
return;
}
handle_packet(p, (atransport*)_t);
}
}
static int read_packet(int fd, const char* name, apacket** ppacket) {
...
char* p = reinterpret_cast<char*>(ppacket); /* really read a packet address */
int len = sizeof(apacket*);
while (len > 0) {
int r = adb_read(fd, p, len);
...
return 0;
}
read_packet()很简单,就是从发生t->transport_socket
中读取出数据,并转换成为消息;在这之后,就会调用handle_packet()来处理usb传输通道中的消息了,我们进入handle_packet()函数中看看:
void handle_packet(apacket *p, atransport *t)
{
...
switch(p->msg.command){
case A_SYNC:
...
case A_CNXN: // CONNECT(version, maxdata, "system-id-string")
...
case A_AUTH:
switch (p->msg.arg0) {
...
case ADB_AUTH_SIGNATURE:
...
case ADB_AUTH_RSAPUBLICKEY:
...
}
case A_OPEN: /* OPEN(local-id, 0, "destination") */
...
case A_OKAY: /* READY(local-id, remote-id, "") */
...
case A_CLSE: /* CLOSE(local-id, remote-id, "") or CLOSE(0, remote-id, "") */
...
case A_WRTE: /* WRITE(local-id, remote-id, ) */
if (t->online && p->msg.arg0 != 0 && p->msg.arg1 != 0) {
...
default:
printf("handle_packet: what is %08x?!\n", p->msg.command);
}
put_apacket(p);
}
handle_packet()内部处理逻辑也是很清晰,
首先根据消息的组成,逐步解析,【USB传输的消息的组成如下所示】;根据不同的command和来调用相应的函数进行不同的处理。,在消息处理完后,就会调用put_apacket()函数将当前消息清除,清空内存空间。
struct amessage {
uint32_t command; /* command identifier constant */
uint32_t arg0; /* first argument */
uint32_t arg1; /* second argument */
uint32_t data_length; /* length of payload (0 is allowed) */
uint32_t data_check; /* checksum of data payload */
uint32_t magic; /* command ^ 0xffffffff */
};
到此,我们终于弄明白了Android设备端的usb通信的初始化和usb消息的处理流程,
在梳理完Android端的USB初始化后,我们就着手看看host端,首先我们还是要从程序的启动流程开始说起,同样我们先来到host端的adb的adb_server_main()方法中,
}
int adb_server_main(int is_daemon, const std::string& socket_spec, int ack_reply_fd) {
...
usb_init();
...
return 0;
}
在adb_server_main()函数中调用了usb_init()函数来初始化usb,我们就跳转到usb_init()中去看看:
void usb_init() {
if (should_use_libusb()) {
LOG(DEBUG) << "using libusb backend";
libusb::usb_init();
} else {
LOG(DEBUG) << "using native backend";
native::usb_init();
}
}
usb_init()函数中首先根据环境决定最后调用那个初始化方案,这里通过 should_use_libusb()函数来判断的
bool should_use_libusb() {
#if !ADB_HOST
return false;
#else
static bool enable = getenv("ADB_LIBUSB") && strcmp(getenv("ADB_LIBUSB"), "1") == 0;
return enable;
#endif
}
在should_use_libusb()函数中,首先是通过宏ADB_HOST来确定当前代码运行的环境,因为当前在host端,所以这里的!ADB_HOST
为false,程序就不直接返回,而是根据环境变量"ADB_LIBUSB"是否存在并且环境变量设置的值为"1"来返回一个bool值.由于当前host并没有设置"ADB_LIBUSB",所以我们返回的是false.
再回到usb_init()中,should_use_libusb()应该返回的是false,那么就会调用native::usb_init(); 所以我们就会调用native命名空间中的usb_init()函数.
【说明:不同的host端系统的native命名空间不一样,对应的函数也不相同,当前系统是linux,我们就会选择usb_linux.cpp
中的的native命名空间】
void usb_init() {
struct sigaction actions;
memset(&actions, 0, sizeof(actions));
sigemptyset(&actions.sa_mask);
actions.sa_flags = 0;
actions.sa_handler = [](int) {};
sigaction(SIGALRM, &actions, nullptr);
std::thread(device_poll_thread).detach();
}
这里顺便了解一下 sigaction:
struct sigaction {
void (*sa_handler)(int);
void (*sa_sigaction)(int, siginfo_t *, void *);
sigset_t sa_mask;
int sa_flags;
void (*sa_restorer)(void);
}
sigaction()函数主要:进程在接受到相应的信号后会改变处理动作,
#include
int sigaction(int signum, const struct sigaction *act,
struct sigaction *oldact);
这里的sigaction()函数主要是对SIGALRM修信号修改新的处理动做,
usb_init()最后是通过创建一个子线程,传入device_poll_thread()函数来处理usb初始化的,我们就要到找这个device_poll_thread()函数中一窥究竟.
static void device_poll_thread() {
...
while (true) {
// TODO: Use inotify.
find_usb_device("/dev/bus/usb", register_device);
kick_disconnected_devices();
std::this_thread::sleep_for(1s);
}
}
device_poll_thread()函数内部是一个死循环,并且没有设置退出,所以我们就可以猜到,host端对于usb的状态应该是实时跟新的,我们就先抱着猜想去代码中验证一下吧:
首先都会调用find_usb_device()函数,传入一个路径和一个函数指针,find_usb_devic()函数内部实现代码较多,具体实现细节就不赘述,主要就是做了以下两件事:
接下来我们就要看最后发现设备后调用的register_device()函数:
首先,我们从函数内部的注解中了解到:linux系统在设备打开之后是不会在重新分配设备ID的,所以我们呢这里可以创建一个list用于存放已经打开的设备,在设备关闭时将其从列表中删除.并且这里我们会列表中匹配的打开的设备分配一个相应的usb处理:
static void register_device(const char* dev_name, const char* dev_path, unsigned char ep_in,
unsigned char ep_out, int interface, int serial_index,
unsigned zero_mask, size_t max_packet_size) {
...
std::unique_ptr<usb_handle> usb(new usb_handle);
usb->path = dev_name;
usb->ep_in = ep_in;
usb->ep_out = ep_out;
usb->zero_mask = zero_mask;
usb->max_packet_size = max_packet_size;
//对 usb_handl进行初始化设置
...
// Read the device's serial number.
std::string serial_path = android::base::StringPrintf(
"/sys/bus/usb/devices/%s/serial", dev_path + 4);
//从传入的路径下读取usb设备信息
..
// Add to the end of the active handles.
usb_handle* done_usb = usb.release();
{
std::lock_guard<std::mutex> lock(g_usb_handles_mutex);
g_usb_handles.push_back(done_usb);
//g_usb_handles列表会在设备关闭时删除当前添加的usb_handle
}
//最后调用register_usb_transport()函数,
register_usb_transport(done_usb, serial.c_str(), dev_path, done_usb->writeable);
}
register_device()函数的处理步骤为:
顺着程序代码往下走,接下来我们就要看看这个register_usb_transport()函数:
void register_usb_transport(usb_handle* usb, const char* serial, const char* devpath,
unsigned writeable) {
atransport* t = new atransport((writeable ? kCsOffline : kCsNoPerm));
D("transport: %p init'ing for usb_handle %p (sn='%s')", t, usb, serial ? serial : "");
init_usb_transport(t, usb);
...
{
std::lock_guard<std::recursive_mutex> lock(transport_lock);
pending_list.push_front(t);
}
register_transport(t);
}
如上述代码所示,这个register_usb_transport()函数
/* the fdevent select pump is single threaded */
static void register_transport(atransport* transport) {
tmsg m;
m.transport = transport;
m.action = 1;
D("transport: %s registered", transport->serial);
if (transport_write_action(transport_registration_send, &m)) {
fatal_errno("cannot write transport registration socket\n");
}
}
在前面的register_usb_transport()函数中,最后会调用调用register_transport()注册传输事件,register_transport()函数中,将atranspor封装成tmsg,然后就是调用transport_write_action()函数将tmsg写入到transport_registration_send中去,和Android设备端类似,我们就需要看看在host端的transport_registration_send是在哪里创建和使用的;
我们在host端的代码中,发现在usb_init()函数调用之前,也会调用init_transport_registration()函数,在Android端的的分析中,我们就说到过这个init_transport_registration;辞旧不在赘述.
int adb_server_main(int is_daemon, const std::string& socket_spec, int ack_reply_fd) {
...
init_transport_registration();
...
usb_init();
...
return 0;
}
分析到这里,我们会发现host端的USB初始函数调用和Android设备端的usb初始化的调用的函数相同了,具体可参考文章上半部分的Android设备端的usb初始化和usb消息处理流程 6. init_transport_registration ()函数及以后的分析梳理