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

10 篇文章 2 订阅
8 篇文章 13 订阅

前言

前文

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

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值