前言
前文
ADB(一)_概况了解
ADB(二)_ADBD_main()函数代码梳理
ADB(三)_ADBD_adbd_main()函数代码梳理
ADB(四)_host端的启动流程代码梳理
在前一篇的文章中,我们对ADB在host端上的运行的代码进行了一个简单的梳理,一篇文章肯定是不能把host端的ADB讲清楚,所以只是以“adb root”命令的执行情况来进行简单的梳理,其中涉及的其他内容就不能深入。可以说前一篇其实主要就是对adb client的大致流程了【没错,adb client就是这么简单】。那么今天我们就对前一篇提到但没有过多涉及的adb server的相关代码进行单独的梳理。
一. adb server启动流程预览
:start_server:
|->launch_server(__adb_server_socket_spec)
|->pipe(fd)
|->pid_t pid = fork()
|-> int result = execl(path.c_str(), "adb", "-L", socket_spec.c_str(), "fork-server", "server", "--reply-fd", reply_fd, NULL);
|->adb_server_main()
|-> // 各种初始化设置
|->fdevent_loop(); // 最后进入loop循环,保持 adb server常驻
我们知道,adb server是由adb client创建运行的,上面的函数调用基本就是启动adb server 的全部内容了;重点我们要放在execl()函数传递进去的参数;
- path.c_str(),“adb” : 表示我们adb可执行程序的路径和程序
- “-L”, socket_spec.c_str() :制定adb server监听的端口,默认是5037;
- “fork-server”:一个指代adb client 创建adb server的标识,随后的函数解析后,就会将
is_daemon 赋值为1
; - “server” :类似与fork-server,随后的参数解析后,就会将
is_server 赋值为1
; - “–reply-fd”, reply_fd : 这是一个
管道的写端
,用于将adb server的请求写入的;
从上面的执行参数知道,在接下来的重新执行adb的过程中,is_server =1,is_daemon=1;ack_reply_fd != 1;所以,函数就会走到adb_server_main();
if (is_server) {
if (no_daemon || is_daemon) {
if (is_daemon && (ack_reply_fd == -1)) {
fprintf(stderr, "reply fd for adb server to client communication not specified.\n");
return 1;
}
r = adb_server_main(is_daemon, server_socket_str, ack_reply_fd);
} else {
r = launch_server(server_socket_str);
}
if (r) {
fprintf(stderr, "* could not start server *\n");
}
return r;
}
看名称,我们也可以猜到这就是adb server的代码入口了,接下来,带着我们的猜想去看看adb_server_main()的内部实现::
首先我们看看adb_server_main()函数内部函数调用的时序图
然后看看adb_server_main()函数的源码实现【说明:以下仅为linux平台代码,】:
int adb_server_main(int is_daemon, const std::string& socket_spec, int ack_reply_fd) {
D("dww--[%s,%d]",__func__,__LINE__);
signal(SIGINT, [](int) {
fdevent_run_on_main_thread([]() { exit(0); });
});
char* leak = getenv("ADB_LEAK");
if (leak && strcmp(leak, "1") == 0) {
intentionally_leak();
}
if (is_daemon) {
close_stdin();
setup_daemon_logging();
}
atexit(adb_server_cleanup);
init_transport_registration();
init_mdns_transport_discovery();
usb_init();
local_init(DEFAULT_ADB_LOCAL_TRANSPORT_PORT);
std::string error;
auto start = std::chrono::steady_clock::now();
// If we told a previous adb server to quit because of version mismatch, we can get to this
// point before it's finished exiting. Retry for a while to give it some time.
while (install_listener(socket_spec, "*smartsocket*", nullptr, 0, nullptr, &error) !=
INSTALL_STATUS_OK) {
if (std::chrono::steady_clock::now() - start > 0.5s) {
fatal("could not install *smartsocket* listener: %s", error.c_str());
}
std::this_thread::sleep_for(100ms);
}
adb_auth_init();
if (is_daemon) {
// Wait for the USB scan to complete before notifying the parent that we're up.
// We need to perform this in a thread, because we would otherwise block the event loop.
std::thread notify_thread([ack_reply_fd]() {
adb_wait_for_device_initialization();
if (!android::base::WriteStringToFd("OK\n", ack_reply_fd)) {
fatal_errno("error writing ACK to fd %d", ack_reply_fd);
}
unix_close(ack_reply_fd);
});
notify_thread.detach();
}
D("Event loop starting");
fdeve nt_loop();
return 0;
}
经过上面的图例和代码,相信已经对adb server可以有一个概括性的认识了,那么接下来,我们就需要对其中的代码部分进行简单的说明。
二. adb server启动流程梳理
1. signal(SIGINT, )
我们经常会由于各种各样的情况来终端当前的程序,如果在程序中不作出相应的处理,有可能会造成程序的无法退出或者会有其他的异常的变现。这点abd 的开发人员已经想到了,当程序收到SIGINT
信号【中断信号】,程序就会进行处理:
signal(SIGINT, [](int) {
fdevent_run_on_main_thread([]() { exit(0); });
});
...
void fdevent_run_on_main_thread(std::function<void()> fn) {
std::lock_guard<std::mutex> lock(run_queue_mutex);
run_queue.push_back(std::move(fn));
...
int rc = adb_write(run_queue_notify_fd.get(), "", 1);
...
}
这里的处理方法很简单;就是将exit(0)函数通过fdevent_run_on_main_thread()保存到run_queue中;【这个run_queue
是一个双向链表】然后通过向run_queue_notify_fd中写入数据,run_queue_notify_fd就可以来刷新队列的唤起对exit(0)函数的执行,最后成功退出;
2. geten(“ADB_LEAK”);
接下来,程序会通过geten()函数来获取环境变量"ADB_LEAK",如果获取的结果为“1”,则说明,此处需要进行内存泄露的检查;【具体实现原理就不深究,我们要把重点放在当前流程梳理上面】
char* leak = getenv("ADB_LEAK");
if (leak && strcmp(leak, "1") == 0) {
intentionally_leak();
}
...
static void intentionally_leak() {
void* p = ::operator new(1);
// The analyzer is upset about this leaking. NOLINTNEXTLINE
LOG(INFO) << "leaking pointer " << p;
}
3. close_stdin() ;setup_daemon_logging()
if (is_daemon) {
close_stdin();
setup_daemon_logging();
}
然后,程序会判断is_daemon变量,我们之前说过,在client启动server的时候传入的参数"fork-server" ,在处理参数"fork-server"后,is_daemon就会赋值为1.。所以对is_daemon的判断肯定为真。那么程序就会调用close_stdin()来关闭标准输入【我们的终端输入就会无效】和setup_daemon_logging()函数来初始化adb server的log信息。
4. atexit(adb_server_cleanup)
atexit是linux系统api,主要是用来注册一些函数,当exit()函数调用后,atexit注册的函数就会被回调;还记的程序中有对中断信号的处理,就会调用exit(0);现在,当程序遇到exit()函数后,系统会回调adb_server_cleanup()函数做一些清理工作。我们可以从下面的注解中了解,程序做了哪些的清理工作
void adb_server_cleanup() {
// Upon exit, we want to clean up in the following order:
// 1. close_smartsockets, so that we don't get any new clients
// 2. kick_all_transports, to avoid writing only part of a packet to a transport.
// 3. usb_cleanup, to tear down the USB stack.
close_smartsockets();
kick_all_transports();
usb_cleanup();
}
5.init_transport_registration
init_transport_registration()函数,看名称,我们可以了解这应该是初始化传输的,同样,我们在前篇ADB(三)_ADBD_adbd_main()函数代码梳理的1.3节中一样,可以移步去前面看看。此处就不赘述。
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);
}
6. init_mdns_transport_discovery
在初始化传输完成之后就会调用init_mdns_transport_discovery()函数来进行有关传输的域名解析服务的初始化,这主要是用与adb tcp连接的相关操作。
void init_mdns_transport_discovery_thread(void) {
DNSServiceErrorType errorCode = DNSServiceBrowse(&service_ref, 0, 0, kADBServiceType, nullptr,
register_mdns_transport, nullptr);
if (errorCode != kDNSServiceErr_NoError) {
D("Got %d initiating mDNS browse.", errorCode);
return;
}
fdevent_run_on_main_thread([]() {
fdevent_install(&service_ref_fde, adb_DNSServiceRefSockFD(service_ref), pump_service_ref,
&service_ref);
fdevent_set(&service_ref_fde, FDE_READ);
});
}
void init_mdns_transport_discovery(void) {
std::thread(init_mdns_transport_discovery_thread).detach();
}
7. usb_init();
ADB的使用过程中,通过会使用usb连接host和device,那么就需要对usb进行相关的设置;我们这里是调用usb_init()函数来说实现的,我们看看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();
}
}
...
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
}
如上所示,在usb_init()函数中首先会should_use_libusb()返回值的判断。这里主要是有序adb host端的代码和adbd通用一套代码,这里做个区分的作用,所以如代码所示,我们的usb_init() 会根据环境比变量ADB_LIBUSB来判断使用libusb::usb_init()
;是native::usb_init()
来初始化usb的相关设置。
8. local_init(DEFAULT_ADB_LOCAL_TRANSPORT_PORT);
void local_init(int port)
{
void (*func)(int);
const char* debug_name = "";
func = client_socket_thread;
debug_name = "client";
D("transport: local %s init", debug_name);
std::thread(func, port).detach();
}
DEFAULT_ADB_LOCAL_TRANSPORT_PORT默认为5555,是server和emulator/android device通信的的默认端口。local_init()函数主要是用来server和仿真器通信初始化,emulator不是我们讨论的重点这里就不深入。
9. install_listener
install_listener()函数的功能主要是安装传输监听器的作用,返回安装状态,一种有五种状态,其中INSTALL_STATUS_OK表示传输监听器安装成功,可以进行正常通信传输。此处的install_listener()主要功能是尝试建立adb client 和adb server 的通信连接【socket_spec默认为5037】
// error/status codes for install_listener.
enum InstallStatus {
INSTALL_STATUS_OK = 0,
INSTALL_STATUS_INTERNAL_ERROR = -1,
INSTALL_STATUS_CANNOT_BIND = -2,
INSTALL_STATUS_CANNOT_REBIND = -3,
INSTALL_STATUS_LISTENER_NOT_FOUND = -4,
};
10. adb_auth_init
adb_auth_init()函数和adbd端的adbd_auth_init()作用类似。用于身份验证功能的初始化工作的,函数实现如下:
void adb_auth_init() {
if (!get_user_key()) {
LOG(ERROR) << "Failed to get user key";
return;
}
const auto& key_paths = get_vendor_keys();
#if defined(__linux__)
adb_auth_inotify_init(key_paths);
#endif
for (const std::string& path : key_paths) {
read_keys(path.c_str());
}
}
...
static void adb_auth_inotify_init(const std::set<std::string>& paths) {
LOG(INFO) << "adb_auth_inotify_init...";
int infd = inotify_init1(IN_CLOEXEC | IN_NONBLOCK);
if (infd < 0) {
PLOG(ERROR) << "failed to create inotify fd";
return;
}
for (const std::string& path : paths) {
int wd = inotify_add_watch(infd, path.c_str(), IN_CREATE | IN_MOVED_TO);
if (wd < 0) {
PLOG(ERROR) << "failed to inotify_add_watch on path '" << path;
continue;
}
g_monitored_paths[wd] = path;
LOG(INFO) << "watch descriptor " << wd << " registered for " << path;
}
fdevent* event = fdevent_create(infd, adb_auth_inotify_update, nullptr);
fdevent_add(event, FDE_READ);
}
这里注意一下adb_auth_inotify_init()中使用了inotify,他可以监控文件系统操作,并且及时向专门的应用程序发出相关的事件,程序会根据发生的事件做出相应的处理【这里会在我们的秘钥文件发生修改时来随时做出更新】
11. notify_thread
notify_thread()是一个线程,主要是起到一个通知client ,server启动完成了。
做了两件主要的事情,
- 一件是等待host连接的usb扫描结束主要是调用adb_wait_for_device_initialization()函数;
- 另一件是调用android::base::WriteStringToFd(“OK\n”, ack_reply_fd)函数向client通知server已经启动成功。
11.1 adb_wait_for_device_initialization
adb_wait_for_device_initialization()的实现比较简单,主要就是利用init_mutex
锁将当前线程阻塞起来。等到usb扫描结束后唤醒。
void adb_wait_for_device_initialization() {
std::unique_lock<std::mutex> lock(init_mutex);
init_cv.wait_for(lock, 3s, []() { return device_scan_complete && transports_ready; });
}
12. fdevent_loop
server在启动完成后,因为要常驻不死,所以最后肯定会进入到一个循环当中,然后等待事件发生并进行处理,这里和adbd端一模一样,可以在参考前篇。ADB(三)_ADBD_adbd_main()函数代码梳理
void fdevent_loop() {
set_main_thread();
fdevent_run_setup();
while (true) {
if (terminate_loop) {
return;
}
D("--- --- waiting for events");
fdevent_process();
while (!g_pending_list.empty()) {
fdevent* fde = g_pending_list.front();
g_pending_list.pop_front();
fdevent_call_fdfunc(fde);
}
}
}
到此,我们的adb server就已经启动完成,再不出现意外的情况下,server会接收client的请求并进行处理,返回处理结果。