ADB(一)_概况了解
前面我们对ADB从整体上进行了简单的概括梳理,我们对adb的了解应该比日常开发了解的更多了。现在就需要从局部对adb进行分析,了解它组成部分的具体工作原理是怎么样的,相互之间又是怎么进行交互的。
在上一篇内容里我们知道adbd主要作用是连接ADB Server 和android device或者仿真器并为在开发者主机上的client提供一些服务.那我们就先从运行在Android device、Emulator上面的adbd程序入手。
由于程序是由C++在底层编写的。那我们就从它的main()函数入口来了解adbd的启动流程是怎样的。
这里还是先摆出Android.mk文件中adbd的编译部分。也为接下来的代码追踪提供线索。
# adbd device daemon
# =========================================================
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
daemon/main.cpp \
daemon/mdns.cpp \
services.cpp \
file_sync_service.cpp \
framebuffer_service.cpp \
remount_service.cpp \
set_verity_enable_state_service.cpp \
shell_service.cpp \
shell_service_protocol.cpp \
LOCAL_CFLAGS := \
$(ADB_COMMON_CFLAGS) \
$(ADB_COMMON_linux_CFLAGS) \
-DADB_HOST=0 \
-D_GNU_SOURCE \
-Wno-deprecated-declarations \
LOCAL_CFLAGS += -DALLOW_ADBD_NO_AUTH=$(if $(filter userdebug eng,$(TARGET_BUILD_VARIANT)),1,0)
ifneq (,$(filter userdebug eng,$(TARGET_BUILD_VARIANT)))
LOCAL_CFLAGS += -DALLOW_ADBD_DISABLE_VERITY=1
LOCAL_CFLAGS += -DALLOW_ADBD_ROOT=1
endif
LOCAL_MODULE := adbd
LOCAL_FORCE_STATIC_EXECUTABLE := true
LOCAL_SANITIZE := $(adb_target_sanitize)
LOCAL_STRIP_MODULE := keep_symbols
LOCAL_STATIC_LIBRARIES := \
libadbd \
libasyncio \
libavb_user \
...
include $(BUILD_EXECUTABLE)
虽然有Android.mk明确了adb和adbd分别编译的代码文件。但是有一些文件是adb和adbd共同使用的,也就是说在同一份代码既需要在adb中使用,也需要在adbd中使用,这时候,C++就使出了它常用的宏定义的方法了。利用ADB_HOST
标志【ADB_HOST说明是在主机端运行,不在Android devices运行】来选择了,我们在源码中也常会看见以下这样的宏定义:
...
#if ADB_HOST
...//代码块①
#endif
...
如果ADB_HOST为真,那么接下来要走的就是代码块①,否则就不走代码块①。
在main()函数的一开始,就出现一个getopt_long()函数,这是一个解析命令行的函数,然后就会调用close_stdin(),用来关闭标准输入;
int main(int argc, char** argv) {
...
int c = getopt_long(argc, argv, "", opts, &option_index);
...
close_stdin();
debuggerd_init(nullptr);
adb_trace_init(argv);
D("Handling main()");
return adbd_main(DEFAULT_ADB_PORT);
}
如上图所示,就是adbd的main()函数的调用流程;下面就上述的函数调用来梳理一下adbd启动时做了哪些事:
首先这个getopt_long()函数是系统提供的,主要作用就是用来解析命令行参数,主要是根据命令行参数给root_seclabel
和adb_device_banner
这两个变量赋值,root_seclabel是可以理解为安全标签的意思,是adbd的权限说明,adb_device_banner可以理解为是说明设备是android设备还是主机。
...
case 's':
root_seclabel = optarg;
break;
case 'b':
adb_device_banner = optarg;
break;
...
close_stdin()函数内部的实现如下代码所示,
...
constexpr char kNullFileName[] = "/dev/null";
#endif
void close_stdin() {
int fd = unix_open(kNullFileName, O_RDONLY);
if (fd == -1) {
fatal_errno("failed to open %s", kNullFileName);
}
if (TEMP_FAILURE_RETRY(dup2(fd, STDIN_FILENO)) == -1) {
fatal_errno("failed to redirect stdin to %s", kNullFileName);
}
unix_close(fd);
}
...
在这里,我们主要关注一下这个dup2()函数;这个dup2()函数原型是int dup2(int oldfd, int newfd);
/* Standard file descriptors. */
#define STDIN_FILENO 0 /* Standard input. */
#define STDOUT_FILENO 1 /* Standard output. */
#define STDERR_FILENO 2 /* Standard error output. */
在这里dup2(fd, STDIN_FILENO)的意思是,newfd指向oldfd句柄指向的文件描述符结构,即原本是指向标准输出文件描述结构体的STDIN_FILENO
指向标准输出文件指向了"/dev/null",这样一来,原本从显示器终端输入文件输入的数据从改从/dev/null
文件输入了;
Android 提供了一个程序异常退出的诊断daemon debuggerd。此进程可以侦测到程序崩溃,并将崩溃时的进程状态信息输出到文件和串口中,以供开发人员分析调试使用。具体的工作原理此处就不深入,知道这是用于分析调试的就行。
adbd的adb_trace_init()函数的内部实现如下所示(这里我已经剔除了非adbd的代码部分):
std::string get_trace_setting() {
return android::base::GetProperty("persist.adb.trace_mask", "");
}
....
void adb_trace_init(char** argv) {
...
// Don't open log file if no tracing, since this will block
// the crypto unmount of /data
if (!get_trace_setting().empty()) {
if (unix_isatty(STDOUT_FILENO) == 0) {
start_device_log();
}
}
...
android::base::InitLogging(argv, &AdbLogger);
setup_trace_mask();
VLOG(ADB) << adb_version();
}
在adbd的adb_trace_init(0函数中,首先通过获取系统设置来决定时候开始设备的log。然后调用setup_trace_mask()设置trace掩码;adb的trace设置来自adb_trace环境变量,而adbd来自系统属性persist.adb.trace_mask。就是说通过获取Android系统属性来设置trace。
#define DEFAULT_ADB_PORT 5037
adbd的默认通信端口是5037,adb_main()函数是main()函数最后调用,综合main()函数之前的调用,我们可以判断adbd的绝大部分工作应该都在adbd的adb_main()函数中。
如需进一步了解,请继续阅读:
ADB(三)_ADBD_adbd_main()函数代码梳理