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的通信传输的内容基本一致。
前面我们对ABD的adbd部分整个进行了一个大概的梳理,具体可以参考上面给出的链接;今天我们就针对ADB在host端的adb进行源码的梳理,看看host端的adb是怎么工作的. 这里为了叙述方便,将在host端的adb 统称为adb.
host端的专有的逻辑代码主要在client
中;
/system/core/adb/client
我们看到有些文件名称有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
分析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()函数
这个函数的主要内容就是我们输入到终端上的"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是怎样个处理流程:
} 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()中的主要执行逻辑。
经过上面的简单的逻辑梳理,我们的思路就会清晰好多,我们很自然的发现:后两步的任务主要就是将第一步获取的fd中的信息读取和输出。所以我们就需要重点看看这个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()函数,两者的不同是参数不一样,
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;
}
我们就围绕第一次调用_adb_connect(“host:version”, error);先来分析一下会有什么样的情况[具体实现在下面会分析];
当_adb_connect(“host:version”, error)函数执行成功后,
ADB_SERVER_VERSION + 1【因为创建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的请求都会得到响应。
我们了解到在上面的额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()函数的实现往下看:
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()函数,并没有做什么特别的转换和处理.
取到上面读取的文件后.就需要进行数据的显示了.我们一般在终端键入"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
说明没有仿真器或者物理设备连接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_server
和adbkill-server
]