当前位置: 首页 > news >正文

ADB(五)_host端adb server相关的代码梳理

在前一篇的文章中,我们对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()函数内部函数调用的时序图

1

然后看看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. NOLINTNEXTLINELOG(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_HOSTreturn false;
#elsestatic 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);
#endiffor (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()函数代码梳理

](https://blog.csdn.net/weixin_38140931/article/details/103972409)

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的请求并进行处理,返回处理结果。

http://www.sczhlp.com/news/7702/

相关文章:

  • ADB(四)_host端的启动流程代码梳理
  • 权值线段树 学习笔记
  • 2013年10月安全更新:IE、Windows内核驱动及.NET框架关键漏洞修复
  • JDK源码之Object
  • 常用输入输出小技巧
  • ADB(三)_ADBD_adbd_main()函数代码梳理
  • WinForm 实现的珠宝收银台界面
  • 零基础入门:20美元学习道德黑客技术
  • AI Compass前沿速览:Claude Opus 4.1、MiniMax-Speech 2.5、Qwen-Flash、Jules – 谷歌AI编程智能体
  • 2025年8月7日
  • Python 错误处理详解
  • 练习cf1490B. Balanced Remainders
  • 后缀
  • 六边形架构模式深度解析
  • 线段树之单侧递归
  • MySQL之InnoDB索引结构
  • fft
  • 技能特长总结2 - Charon
  • NetEase 4000纪念
  • InfluxDB 订阅(Subscription)
  • 8.7总结
  • 软考系统分析师每日学习卡 | [日期:2025-08-07] | [今日主题:位示图]
  • qt报错
  • wrk:高性能HTTPS压力测试工具使用指南
  • 自动化推理技术入门指南
  • 最高 600 万现金激励!鸿蒙 2025 开发者计划来袭,手把手教你参与
  • 进行jpeg库的移植之后,参照example.c编写的main函数,已编译通过
  • 【ganesha】函数nfs4_op_open解析
  • day1 python
  • P10255