ADB(四)_host端的启动流程代码梳理

前言

前文

ADB(一)_概况了解
ADB(二)_ADBD_main()函数代码梳理
ADB(三)_ADBD_adbd_main()函数代码梳理

host端的ADB,就是我们平常开发在电脑终端上运行的adb,从构成上来说,host端的ADB分为两个部分,一部分是adb server,一部分是adb client;server处理来自client的请求,client主要就是想server发送请求和接受回应的作用。
我们在终端键入的“adb XXX"命令,就是adb client向 adb server发送的请求指令。

host端的adb和设备端的adbd共用部分代码,所以adb和adbd的通信传输的内容基本一致。

1. adb的代码

前面我们对ABD的adbd部分整个进行了一个大概的梳理,具体可以参考上面给出的链接;今天我们就针对ADB在host端的adb进行源码的梳理,看看host端的adb是怎么工作的. 这里为了叙述方便,将在host端的adb 统称为adb.
host端的专有的逻辑代码主要在client中;
/system/core/adb/client
ADB(四)_host端的启动流程代码梳理_第1张图片
我们看到有些文件名称有windows linux相关的字眼,这是什么呢?这主要是因为我们使用的主机系统不一样,相关的系统api是不同的(比如常见的Windows操作系统和linux操作系统),所以这里需要在一套代码中都要实现,具体根据实际情况来编译出相应的可执行程序. 当前我使用的是Ubuntu ,所以有和系统先关的函数的话都会根据Linux的来分析.
这里还是先摆出Android.mk文件中adb的编译部分。

# adb host tool
# =========================================================
include $(CLEAR_VARS)

LOCAL_LDLIBS_linux := -lrt -ldl -lpthread

LOCAL_LDLIBS_darwin := -lpthread -framework CoreFoundation -framework IOKit -framework Carbon -lobjc

# Use wmain instead of main
LOCAL_LDFLAGS_windows := -municode
LOCAL_LDLIBS_windows := -lws2_32 -lgdi32
LOCAL_SHARED_LIBRARIES_windows := AdbWinApi
LOCAL_REQUIRED_MODULES_windows := AdbWinUsbApi

LOCAL_SRC_FILES := \
    adb_client.cpp \
    bugreport.cpp \
    client/main.cpp \
    console.cpp \
    commandline.cpp \
    file_sync_client.cpp \
    line_printer.cpp \
    services.cpp \
    shell_service_protocol.cpp \

LOCAL_CFLAGS += \
    $(ADB_COMMON_CFLAGS) \
    -D_GNU_SOURCE \
    -DADB_HOST=1 \

LOCAL_CFLAGS_windows := \
    $(ADB_COMMON_windows_CFLAGS)

LOCAL_CFLAGS_linux := \
    $(ADB_COMMON_linux_CFLAGS) \

LOCAL_CFLAGS_darwin := \
    $(ADB_COMMON_darwin_CFLAGS) \
    -Wno-sizeof-pointer-memaccess -Wno-unused-parameter \

LOCAL_MODULE := adb
LOCAL_MODULE_TAGS := debug
LOCAL_MODULE_HOST_OS := darwin linux windows

LOCAL_SANITIZE := $(adb_host_sanitize)
LOCAL_STATIC_LIBRARIES := \
    libadb \
    libbase \
    libcrypto_utils \
    libcrypto \
    libdiagnose_usb \
    liblog \
    libmdnssd \
    libusb \

# Don't use libcutils on Windows.
LOCAL_STATIC_LIBRARIES_darwin := libcutils
LOCAL_STATIC_LIBRARIES_linux := libcutils

LOCAL_CXX_STL := libc++_static

# Don't add anything here, we don't want additional shared dependencies
# on the host adb tool, and shared libraries that link against libc++
# will violate ODR
LOCAL_SHARED_LIBRARIES :=

include $(BUILD_HOST_EXECUTABLE)

$(call dist-for-goals,dist_files sdk win_sdk,$(LOCAL_BUILT_MODULE))
ifdef HOST_CROSS_OS
# Archive adb.exe for win_sdk build.
$(call dist-for-goals,win_sdk,$(ALL_MODULES.host_cross_adb.BUILT))
endif

2.adb的初始化

分析adb,首先我们就要看看它的main入口函数。

int main(int argc, char** argv) {
    // 初始化trace
    adb_trace_init(argv);
    // 根据adb命令参数进行处理
    return adb_commandline(argc - 1, const_cast<const char**>(argv + 1));
}

这里我们可以看到到adb的初始化相对adbd要简介一些,首先就是初始化trace;然后就是根据adb 命令行参数进行处理;我们接下来主要关注这个adb_commandline()函数

3. adb_commandline()

这个函数的主要内容就是我们输入到终端上的"adb XXX"命令参数的解析,然后调用相应的函数进行梳理,当然也不全是终端键入的命令参数,更加准确的说应该是启动host 端的adb时输入的参数。然后会进行一些初始化设置

int adb_commandline(int argc, const char** argv) { 
	// 以下三个变量均和adb server相关,标志adb server是否存在和
    int no_daemon = 0;  
    int is_daemon = 0; 
    int is_server = 0;  
    int r;
    TransportType transport_type = kTransportAny;  // 传输类型,默认是kTransportAny
    int ack_reply_fd = -1;

#if !defined(_WIN32)
    // We'd rather have EPIPE than SIGPIPE.
    signal(SIGPIPE, SIG_IGN);
#endif

    const char* server_host_str = nullptr;    // adb server的名称,默认是localhost
    const char* server_port_str = nullptr;    // adb sercer监听的端口号,默认是 5037
    const char* server_socket_str = nullptr;  // adb server监听的socket信息,默认是tcp:localhost:5037

    // We need to check for -d and -e before we look at $ANDROID_SERIAL.
    const char* serial = nullptr;
    TransportId transport_id = 0;

    while (argc > 0) {
        if (!strcmp(argv[0], "server")) { 
             is_server = 1;
             ...
             /* 众多的参数,对应不同的处理*/
             ...
        } else if (!strcmp(argv[0], "root") || !strcmp(argv[0], "unroot")) {
            return adb_root(argv[0]) ? 0 : 1;
        }
    }
    ...
    return 1;
}      

如上所示,adb_commandline()函数的处理逻辑大致就是这些【中间很多类似参数处理以及相关处理函数的调用,为了方便理解,那些代码就先省略。不adb_commandline()函数并不是处理“adb server"和“adb root”这几个参数情况。】

下面我们就简单的以其中的一个,也是很常执行的一个命令"adb root "来看看adb是怎样个处理流程:

3.1 adb_root

 } else if (!strcmp(argv[0], "root") || !strcmp(argv[0], "unroot")) {
            return adb_root(argv[0]) ? 0 : 1;
        }

在adb_commandline()函数中,判断参数,如果当前的参数是“root”和“unroot”,那么就会调用adb_root()函数,可见,"adb root"和"adb unroot"的执行情况是一样的。
接下来我们就到adb_root()函数中看看其中的实现:

static bool adb_root(const char* command) {
    std::string error;
    unique_fd fd(adb_connect(android::base::StringPrintf("%s:", command), &error));
    if (fd < 0) {
        fprintf(stderr, "adb: unable to connect for %s: %s\n", command, error.c_str());
        return false;
    }
    // Figure out whether we actually did anything.
    char buf[256];
    char* cur = buf;
    ssize_t bytes_left = sizeof(buf);
    while (bytes_left > 0) {
        ssize_t bytes_read = adb_read(fd, cur, bytes_left);
        if (bytes_read == 0) {
            break;
        } else if (bytes_read < 0) {
            fprintf(stderr, "adb: error while reading for %s: %s\n", command, strerror(errno));
            return false;
        }
        cur += bytes_read;
        bytes_left -= bytes_read;
    }

    if (bytes_left == 0) {
        fprintf(stderr, "adb: unexpected output length for %s\n", command);
        return false;
    }

    fflush(stdout);
    WriteFdExactly(STDOUT_FILENO, buf, sizeof(buf) - bytes_left);
    if (cur != buf && strstr(buf, "restarting") == nullptr) {
        return true;
    }

    // Give adbd some time to kill itself and come back up.
    // We can't use wait-for-device because devices (e.g. adb over network) might not come back.
    std::this_thread::sleep_for(3s);
    return true;
}

根据以上源码,我们先整理一下adb_root()中的主要执行逻辑。

  • 首先会调用adb_connect()函数,传入的参数一个是从adb_rootI()函数传入的参数,在这里是“root”或者“unroot”;然后是error,adb_connect()函数在执行错误时会返回错误的类型。返回一个fd.
  • 然后调用adb_read()函数从上面的fd中读取数据。
  • 最后再调用WriteFdExactly()函数将上一步的数据写入到标准输出上,【这就是我们在终端上会显示的信息】

经过上面的简单的逻辑梳理,我们的思路就会清晰好多,我们很自然的发现:后两步的任务主要就是将第一步获取的fd中的信息读取和输出。所以我们就需要重点看看这个adb_connect()函数是如何得到处理数据的。

3.1.1 adb_connect

int adb_connect(const std::string& service, std::string* error) {
    // first query the adb server's version
    int fd = _adb_connect("host:version", error);
    if (fd == -2 && !is_local_socket_spec(__adb_server_socket_spec)) {
        fprintf(stderr, "* cannot start server on remote host\n");
        // error is the original network connection error
        return fd;
    } else if (fd == -2) {
        fprintf(stderr, "* daemon not running; starting now at %s\n", __adb_server_socket_spec);
    start_server:
        if (launch_server(__adb_server_socket_spec)) {
            fprintf(stderr, "* failed to start daemon\n");
            // launch_server() has already printed detailed error info, so just
            // return a generic error string about the overall adb_connect()
            // that the caller requested.
            *error = "cannot connect to daemon";
            return -1;
        } else {
            fprintf(stderr, "* daemon started successfully\n");
        }
        // The server will wait until it detects all of its connected devices before acking.
        // Fall through to _adb_connect.
    } else {
        // If a server is already running, check its version matches.
        int version = ADB_SERVER_VERSION - 1;

        // If we have a file descriptor, then parse version result.
        if (fd >= 0) {
            std::string version_string;
            if (!ReadProtocolString(fd, &version_string, error)) {
                adb_close(fd);
                return -1;
            }

            ReadOrderlyShutdown(fd);
            adb_close(fd);

            if (sscanf(&version_string[0], "%04x", &version) != 1) {
                *error = android::base::StringPrintf("cannot parse version string: %s",
                                                     version_string.c_str());
                return -1;
            }
        } else {
            // If fd is -1 check for "unknown host service" which would
            // indicate a version of adb that does not support the
            // version command, in which case we should fall-through to kill it.
            if (*error != "unknown host service") {
                return fd;
            }
        }

        if (version != ADB_SERVER_VERSION) {
            fprintf(stderr, "adb server version (%d) doesn't match this client (%d); killing...\n",
                    version, ADB_SERVER_VERSION);
            adb_kill_server();
            goto start_server;
        }
    }

    // if the command is start-server, we are done.
    if (service == "host:start-server") {
        return 0;
    }

    fd = _adb_connect(service, error);
    if (fd == -1) {
        D("_adb_connect error: %s", error->c_str());
    } else if (fd == -2) {
        fprintf(stderr, "* daemon still not running\n");
    }
    D("adb_connect: return fd %d", fd);

    return fd;
}

以上就是adb_connect()函数的实现,在adb_connect()中,我们需要注意一下,会两次调用_adb_connect()函数,两者的不同是参数不一样,

  • 第一次调用是,传入的是"host:version",这是固定的字符串,就是说任何其他情况下调用adb_connect()函数都是同样的操作,
  • 第二次调用传入的是service,这个service是根据我们前面的命令参数不同而有所改变的。

先看看第一次调用_adb_connect(),注解告诉了我们。这是要请求得到adb server的版本信息。
对于版本信息,代码中有一个宏ADB_SERVER_VERSION:他在我们创建新的adb server时就会增大。

// Increment this when we want to force users to start a new adb server.
#define ADB_SERVER_VERSION 40
...
// first query the adb server's version
int fd = _adb_connect("host:version", error);
...
start_server:
  launch_server(__adb_server_socket_spec)
  ...
if (version != ADB_SERVER_VERSION) {
            fprintf(stderr, "adb server version (%d) doesn't match this client (%d); killing...\n",
                    version, ADB_SERVER_VERSION);
            adb_kill_server();
            goto start_server;
        }

3.1.1.1_adb_connect(“host:version”, error);

我们就围绕第一次调用_adb_connect(“host:version”, error);先来分析一下会有什么样的情况[具体实现在下面会分析];
当_adb_connect(“host:version”, error)函数执行成功后,

  • 如果当前的adb server存在,则当前的version应该比原始的等于ADB_SERVER_VERSION + 1【因为创建adb server后,版本就会增加】
  • 如果当前版本不对,那么就说明adb server还没有启动,就会通过goto start_server去重启启动adb server.

这里简单的把,启动adb server代码说一下:

int launch_server(const std::string& socket_spec) {
...
pid_t pid = fork();
    if (pid < 0) return -1;

    if (pid == 0) {
        // child side of the fork
        adb_close(fd[0]);
        char reply_fd[30];
        snprintf(reply_fd, sizeof(reply_fd), "%d", fd[1]);
        // child process
        int result = execl(path.c_str(), "adb", "-L", socket_spec.c_str(), "fork-server", "server",
                           "--reply-fd", reply_fd, NULL);
...
}

adb server本身上就是在一个单独的进程当中,这个进程是谁创建的呢?答案就在上面的代码中:
launch_server()函数就是用来启动adb server的,他主要是通过调用fork()函数来创建一个新的进程,然后在新的进程中调用execl()函数,传入adb 的代码路径【path.c_str()】,和一些参数。–>这就相当于重新从adb的main()函数走了一遍,并且根据当前传入的新的参数进行不同的处理。

每次adb运行都会连接server.保证server是永远存活的,所有的client的请求都会得到响应。

3.1.1.2 _adb_connect(service, error);

我们了解到在上面的额adb_connect()函数的前半部分第一次调用_adb_connect(“host:version”, error)函数的作用,接下来就会第二次调用_adb_connect()函数,这次调用的参数就会是封装我们adb进程运行时一开始就传入的参数了.
这一次_adb_connect(service, error)函数的调用就会根据不同的场景返回不同的结果,但是函数内部的调用流程是一样的,毕竟是同一个函数,也没有重载和重写操作;接下来我们就进入_adb_connect()函数内部看看它的具体实现:

static int _adb_connect(const std::string& service, std::string* error) {
    ...
    std::string reason;
    int fd = socket_spec_connect(__adb_server_socket_spec, &reason);
    ...
    if (memcmp(&service[0], "host", 4) != 0 && switch_socket_transport(fd, error)) {
        return -1;
    }
    ...
    if (!SendProtocolString(fd, service)) {
        *error = perror_str("write failure during connection");
        adb_close(fd);
        return -1;
    }
    ...
    return fd;
}

如上所示;我们就_adb_connect()的内部实现来看看.首先会调用socket_spec_connect()函数创建与adb server的连接,其中的参数__adb_server_socket_spec默认为5037,即adb client和adb server的连接的默认端口,返回一个fd;然后调用switch_socket_transport()函数选择传输方式;传输方式有四种类型,在adb.h中定义:
system/core/adb/adb.h

// A transport object models the connection to a remote device or emulator there
// is one transport per connected device/emulator. A "local transport" connects
// through TCP (for the emulator), while a "usb transport" through USB (for real
// devices).
//
// Note that kTransportHost doesn't really correspond to a real transport
// object, it's a special value used to indicate that a client wants to connect
// to a service implemented within the ADB server itself.
enum TransportType {
    kTransportUsb,
    kTransportLocal,
    kTransportAny,
    kTransportHost,
};

最后,调用SendProtocolString()函数将请求的"service"写入到上面得到的fd;然后adb_connect()函数就返回第二次调用_adb_connect()函数返回的fd;到这里,代码就会回到adb_root()函数中;我们接着顺着adb_root()函数的实现往下看:

3.1.2 adb_read:

adb_root()函数在得到adb_connect()函数返回的fd后,就会调用adb_read()函数来对fd中的数据进行读取和展示;我们先看看它是怎么进行读取的,那就看看adb_read()函数的实现:

static __inline__  int  adb_read(int  fd, void*  buf, size_t  len)
{
    return TEMP_FAILURE_RETRY( read( fd, buf, len ) );
}

哈哈,这个就是很简单了,adb_read()函数就是直接调用了系统的read()函数,并没有做什么特别的转换和处理.

3.1.3 WriteFdExactly(STDOUT_FILENO, buf, sizeof(buf) - bytes_left);

取到上面读取的文件后.就需要进行数据的显示了.我们一般在终端键入"adb root"命令后,都会返回如下结果:

  • restarting adbd as root# 说明有root权限 ,
  • 若是adbd cannot run as root in production builds 则说明没有root权限
  • 或者adb: unable to connect for root: no devices/emulators found 说明没有仿真器或者物理设备连接
    这些事情是谁干的那?其实这里直接是使用标准输出将adb_read()函数读取的数据后,在调用WriteFdExactly()函数通过标准输出来[STDOUT_FILENO 就是可以理解成我们的电脑的终端]显示.

adb_root()函数到这之后,会让线程睡三秒,主要是等待设备重新以root权限重启启动并和host连接:

static bool adb_root(const char* command) { 
  ...
  std::this_thread::sleep_for(3s);
  return true;
  }

最后adb_root()函数会返回true,到此,当前的进程就结束了,不过在这过程中启动的server进程还是存活的,作为server本就应该要长期存活,不能每次用的时候在启动呀.

总结

1.每次在终端键入"adb XXX"命令后,就是在手动启动一个adb client
2. 每次在执行任何adb 的命令时, adb client都需要和adb server连接.如果adb server不存在就会重新创建一个新的进程做server.
3. 上一次的adb client进程执行完成相应的代码后就会自行结束,所以每次adb client进程都是新的进程.具体的请求处理是通过adb server或者远程的adbd来完成的.
4.adb client可以启动 adb server,也可以杀死adb server[adb start_serveradbkill-server]

你可能感兴趣的:(Android_ADB,C/C++,Linux)