Adb 框架
Android Adb 一共分为三个部分:adb、adb server、adbd,源码路径:system/core/adb。
- adb和adb server 是运行在PC端,adb就是大家所熟悉的控制台命令adb,adb server是由adb fork出的一个常驻后台的子进程大家再看到
* daemon not running. starting it now on port 5037 *
* daemon started successfully *
的时候就是adb在启动 adb server,adb与adb server 通过local socket进行通信。
- adbd运行在Android端,是在内核初始化完毕之后,init进程启动
service adbd /sbin/adbd --root_seclabel=u:r:su:s0 --device_banner=recovery
disabled
socket adbd stream 660 system system
seclabel u:r:adbd:s0
adbd是一个linux程序,不依赖Android framework,通过tcp或者usb与PC端的adb server通信,调用logcat shell 等等程序实现各种功能。
1. 初始化
adbd main 入口在system/core/adb/daemon/main.cpp中,main函数获取selinux标签、banner名称、版本信息参数以及设置一些调试信息后,调用adbd_main函数:
int adbd_main(int server_port) {
umask(0);
signal(SIGPIPE, SIG_IGN);
init_transport_registration();
// We need to call this even if auth isn't enabled because the file
// descriptor will always be open.
adbd_cloexec_auth_socket();
if (ALLOW_ADBD_NO_AUTH && !android::base::GetBoolProperty("ro.adb.secure", false)) {
auth_required = false;
}
adbd_auth_init();
// Our external storage path may be different than apps, since
// we aren't able to bind mount after dropping root.
const char* adb_external_storage = getenv("ADB_EXTERNAL_STORAGE");
if (adb_external_storage != nullptr) {
setenv("EXTERNAL_STORAGE", adb_external_storage, 1);
} else {
D("Warning: ADB_EXTERNAL_STORAGE is not set. Leaving EXTERNAL_STORAGE"
" unchanged.\n");
}
drop_privileges(server_port);
bool is_usb = false;
if (access(USB_FFS_ADB_EP0, F_OK) == 0) {
// Listen on USB.
usb_init();
is_usb = true;
}
// If one of these properties is set, also listen on that port.
// If one of the properties isn't set and we couldn't listen on usb, listen
// on the default port.
std::string prop_port = android::base::GetProperty("service.adb.tcp.port", "");
if (prop_port.empty()) {
prop_port = android::base::GetProperty("persist.adb.tcp.port", "");
}
int port;
if (sscanf(prop_port.c_str(), "%d", &port) == 1 && port > 0) {
D("using port=%d", port);
// Listen on TCP port specified by service.adb.tcp.port property.
setup_port(port);
} else if (!is_usb) {
// Listen on default port.
setup_port(DEFAULT_ADB_LOCAL_TRANSPORT_PORT);
}
D("adbd_main(): pre init_jdwp()");
init_jdwp();
D("adbd_main(): post init_jdwp()");
D("Event loop starting");
fdevent_loop();
return 0;
}
- init_transport_registration 函数完成adbd接受PC端adb server连接功能的初始化工作
- adbd_auth_init 函数负责完成对连入的PC端身份验证功能的初始化工作
- drop_privileges 函数负责是否要去掉adbd的root权限,降级为shell权限
- usb_init 如果可以usb调试,初始化usb,等待连接
- setup_port 如果开启了网络调试,初始化端口,等待连接
- init_jdwp 初始化 java 调试框架
- fdevent_loop 对监听的fd进行消息处理(死循环)
这里我们重点看一下 init_transport_registration 函数
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);
}
通过adb_socketpair 函数建立了一个管道,并且把管道的一头放入fdevent中进行读监听,当有数据可读时候调用transport_registration_func 函数
static void transport_registration_func(int _fd, unsigned ev, void* data) {
tmsg m;
int s[2];
atransport* t;
if (!(ev & FDE_READ)) {
return;
}
if (transport_read_action(_fd, &m)) {
fatal_errno("cannot read transport registration socket");
}
t = m.transport;
if (m.action == 0) {
D("transport: %s removing and free'ing %d", t->serial, t->transport_socket);
/* IMPORTANT: the remove closes one half of the
** socket pair. The close closes the other half.
*/
fdevent_remove(&(t->transport_fde));
adb_close(t->fd);
{
std::lock_guard lock(transport_lock);
transport_list.remove(t);
}
if (t->product) free(t->product);
if (t->serial) free(t->serial);
if (t->model) free(t->model);
if (t->device) free(t->device);
if (t->devpath) free(t->devpath);
delete t;
update_transports();
return;
}
/* don't create transport threads for inaccessible devices */
if (t->GetConnectionState() != kCsNoPerm) {
/* initial references are the two threads */
t->ref_count = 2;
if (adb_socketpair(s)) {
fatal_errno("cannot open transport socketpair");
}
D("transport: %s socketpair: (%d,%d) starting", t->serial, s[0], s[1]);
t->transport_socket = s[0];
t->fd = s[1];
fdevent_install(&(t->transport_fde), t->transport_socket, transport_socket_events, t);
fdevent_set(&(t->transport_fde), FDE_READ);
std::thread(write_transport_thread, t).detach();
std::thread(read_transport_thread, t).detach();
}
{
std::lock_guard lock(transport_lock);
pending_list.remove(t);
transport_list.push_front(t);
}
update_transports();
}
1.建立连接(adb connect ip举例)
adb入口函数system/core/adb/client/main.cpp,在启动时候会调用adb_commandline函数,如果命令能adb进程处理就直接处理返回,如果不能处理则尝试连接adb server,adb server如果未启动则fork出adb server
调用adb_server_main 完成各种初始化工作(类似adbd初始化),adb server启动后发起命令"host:connect:"经过smart_socket_enqueue 最终调用
else if (!strncmp(name, "connect:", 8)) {
char* host = strdup(name + 8);
int fd = create_service_thread("connect", connect_service, host);
if (fd == -1) {
free(host);
}
return create_local_socket(fd);
}
调用
void connect_device(const std::string& address, std::string* response) {
if (address.empty()) {
*response = "empty address";
return;
}
std::string serial;
std::string host;
int port = DEFAULT_ADB_LOCAL_TRANSPORT_PORT;
if (!android::base::ParseNetAddress(address, &host, &port, &serial, response)) {
return;
}
std::string error;
int fd = network_connect(host.c_str(), port, SOCK_STREAM, 10, &error);
if (fd == -1) {
*response = android::base::StringPrintf("unable to connect to %s: %s",
serial.c_str(), error.c_str());
return;
}
D("client: connected %s remote on fd %d", serial.c_str(), fd);
close_on_exec(fd);
disable_tcp_nagle(fd);
// Send a TCP keepalive ping to the device every second so we can detect disconnects.
if (!set_tcp_keepalive(fd, 1)) {
D("warning: failed to configure TCP keepalives (%s)", strerror(errno));
}
int ret = register_socket_transport(fd, serial.c_str(), port, 0);
if (ret < 0) {
adb_close(fd);
*response = android::base::StringPrintf("already connected to %s", serial.c_str());
} else {
*response = android::base::StringPrintf("connected to %s", serial.c_str());
}
}
至此通过network_connect发起tcp连接请求并返回fd通过register_socket_transport注册到transport列表中。
而adbd端
static void server_socket_thread(int port) {
int serverfd, fd;
adb_thread_setname("server socket");
D("transport: server_socket_thread() starting");
serverfd = -1;
for(;;) {
if(serverfd == -1) {
std::string error;
serverfd = network_inaddr_any_server(port, SOCK_STREAM, &error);
if(serverfd < 0) {
D("server: cannot bind socket yet: %s", error.c_str());
std::this_thread::sleep_for(1s);
continue;
}
close_on_exec(serverfd);
}
D("server: trying to get new connection from %d", port);
fd = adb_socket_accept(serverfd, nullptr, nullptr);
if(fd >= 0) {
D("server: new connection on fd %d", fd);
close_on_exec(fd);
disable_tcp_nagle(fd);
std::string serial = android::base::StringPrintf("host-%d", fd);
if (register_socket_transport(fd, serial.c_str(), port, 1) != 0) {
adb_close(fd);
}
}
}
D("transport: server_socket_thread() exiting");
}
接收到TCP连接请求,调用register_transport函数
至此adb server和adbd物理连接建立完成
2. 消息流转
当register_transport函数被调用,管道一端被写入tmsg消息
static void register_transport(atransport* transport) {
tmsg m;
m.transport = transport;
m.action = 1;
D("transport: %s registered", transport->serial);
if (transport_write_action(transport_registration_send, &m)) {
fatal_errno("cannot write transport registration socket\n");
}
}
触发transport_registration_func 函数从管道另一端读取tmsg消息同时再建立了一条管道和两个线程并把tmsg中的atransport记录到传输队列中,atransport记录了三个文件描述符 sfd、fd、transport_socket,他们的关系如图
图中的apacket为各种消息载体。
struct amessage {
uint32_t command; /* command identifier constant */
uint32_t arg0; /* first argument */
uint32_t arg1; /* second argument */
uint32_t data_length; /* length of payload (0 is allowed) */
uint32_t data_check; /* checksum of data payload */
uint32_t magic; /* command ^ 0xffffffff */
};
struct apacket {
amessage msg;
std::string payload;
};
3. 消息处理
重点看handle_packet 函数
void handle_packet(apacket *p, atransport *t)
{
D("handle_packet() %c%c%c%c", ((char*) (&(p->msg.command)))[0],
((char*) (&(p->msg.command)))[1],
((char*) (&(p->msg.command)))[2],
((char*) (&(p->msg.command)))[3]);
print_packet("recv", p);
CHECK_EQ(p->payload.size(), p->msg.data_length);
switch(p->msg.command){
case A_SYNC:
if (p->msg.arg0){
send_packet(p, t);
#if ADB_HOST
send_connect(t);
#endif
} else {
t->SetConnectionState(kCsOffline);
handle_offline(t);
send_packet(p, t);
}
return;
case A_CNXN: // CONNECT(version, maxdata, "system-id-string")
handle_new_connection(t, p);
break;
case A_AUTH:
switch (p->msg.arg0) {
#if ADB_HOST
case ADB_AUTH_TOKEN:
if (t->GetConnectionState() == kCsOffline) {
t->SetConnectionState(kCsUnauthorized);
}
send_auth_response(p->payload.data(), p->msg.data_length, t);
break;
#else
case ADB_AUTH_SIGNATURE:
if (adbd_auth_verify(t->token, sizeof(t->token), p->payload)) {
adbd_auth_verified(t);
t->failed_auth_attempts = 0;
} else {
if (t->failed_auth_attempts++ > 256) std::this_thread::sleep_for(1s);
send_auth_request(t);
}
break;
case ADB_AUTH_RSAPUBLICKEY:
adbd_auth_confirm_key(p->payload.data(), p->msg.data_length, t);
break;
#endif
default:
t->SetConnectionState(kCsOffline);
handle_offline(t);
break;
}
break;
case A_OPEN: /* OPEN(local-id, 0, "destination") */
if (t->online && p->msg.arg0 != 0 && p->msg.arg1 == 0) {
asocket* s = create_local_service_socket(p->payload.c_str(), t);
if (s == nullptr) {
send_close(0, p->msg.arg0, t);
} else {
s->peer = create_remote_socket(p->msg.arg0, t);
s->peer->peer = s;
send_ready(s->id, s->peer->id, t);
s->ready(s);
}
}
break;
case A_OKAY: /* READY(local-id, remote-id, "") */
if (t->online && p->msg.arg0 != 0 && p->msg.arg1 != 0) {
asocket* s = find_local_socket(p->msg.arg1, 0);
if (s) {
if(s->peer == 0) {
/* On first READY message, create the connection. */
s->peer = create_remote_socket(p->msg.arg0, t);
s->peer->peer = s;
s->ready(s);
} else if (s->peer->id == p->msg.arg0) {
/* Other READY messages must use the same local-id */
s->ready(s);
} else {
D("Invalid A_OKAY(%d,%d), expected A_OKAY(%d,%d) on transport %s",
p->msg.arg0, p->msg.arg1, s->peer->id, p->msg.arg1, t->serial);
}
} else {
// When receiving A_OKAY from device for A_OPEN request, the host server may
// have closed the local socket because of client disconnection. Then we need
// to send A_CLSE back to device to close the service on device.
send_close(p->msg.arg1, p->msg.arg0, t);
}
}
break;
case A_CLSE: /* CLOSE(local-id, remote-id, "") or CLOSE(0, remote-id, "") */
if (t->online && p->msg.arg1 != 0) {
asocket* s = find_local_socket(p->msg.arg1, p->msg.arg0);
if (s) {
/* According to protocol.txt, p->msg.arg0 might be 0 to indicate
* a failed OPEN only. However, due to a bug in previous ADB
* versions, CLOSE(0, remote-id, "") was also used for normal
* CLOSE() operations.
*
* This is bad because it means a compromised adbd could
* send packets to close connections between the host and
* other devices. To avoid this, only allow this if the local
* socket has a peer on the same transport.
*/
if (p->msg.arg0 == 0 && s->peer && s->peer->transport != t) {
D("Invalid A_CLSE(0, %u) from transport %s, expected transport %s",
p->msg.arg1, t->serial, s->peer->transport->serial);
} else {
s->close(s);
}
}
}
break;
case A_WRTE: /* WRITE(local-id, remote-id, ) */
if (t->online && p->msg.arg0 != 0 && p->msg.arg1 != 0) {
asocket* s = find_local_socket(p->msg.arg1, p->msg.arg0);
if (s) {
unsigned rid = p->msg.arg0;
if (s->enqueue(s, std::move(p->payload)) == 0) {
D("Enqueue the socket");
send_ready(s->id, rid, t);
}
}
}
break;
default:
printf("handle_packet: what is %08x?!\n", p->msg.command);
}
put_apacket(p);
}
这部分代码是adb server和adbd共用的,通过ADB_HOST宏来控制是否编译,我们先看apacket命令种类
- A_SYNC 握手命令,当PC开始连接建立时交换SYNC字段,其意义类似于TCP协议的握手
- A_CNXN adb server握手完成后直接发送A_CNXN 协商版本、最大负载等信息,adbd收到A_CNXN后还会判断是够要对adb server进行认证,认证通过之后才会发送A_CNXN 协商版本、最大负载等信息
- A_AUTH adbd对adb server进行验证
以上均完成之后,adb连接完全建立,PC端查看adb devices命令devices显示device
- A_OPEN 当需要流完成的命令(例如:logat)需要通知接收方建立一个套接字,local-id用来标识套接字
- A_OKAY 通知发送方已经准备好了接收流
- A_CLSE 通知接收方关闭套接字
- A_WRTE 发送的流消息
再重点看一下A_OPEN流程,在接收到A_OPEN后,先创建一个本地的套接字(create_local_service_socket),成功后再创建一个远程套接字(create_remote_socket),并关联两个
套接字互为peer,完成后通知远端A_OKAY。
远端收到A_OKAY后同时也会关联对方的套接字。
大家可能已经看出来了,这里所谓的本地套接字远程套接字并非真的套接字,而是通过local-id字段在逻辑上建立相关联的一个结构(peer),具体参见sockets.cpp。
至此针对不同服务(logcat、shell等)的链接就建立完成了。
在services.cpp文件中
int service_to_fd(const char* name, atransport* transport) {
int ret = -1;
if (is_socket_spec(name)) {
std::string error;
ret = socket_spec_connect(name, &error);
if (ret < 0) {
LOG(ERROR) << "failed to connect to socket '" << name << "': " << error;
}
#if !ADB_HOST
} else if(!strncmp("dev:", name, 4)) {
ret = unix_open(name + 4, O_RDWR | O_CLOEXEC);
} else if(!strncmp(name, "framebuffer:", 12)) {
ret = create_service_thread("fb", framebuffer_service, nullptr);
} else if (!strncmp(name, "jdwp:", 5)) {
ret = create_jdwp_connection_fd(atoi(name+5));
} else if(!strncmp(name, "shell", 5)) {
ret = ShellService(name + 5, transport);
} else if(!strncmp(name, "exec:", 5)) {
ret = StartSubprocess(name + 5, nullptr, SubprocessType::kRaw, SubprocessProtocol::kNone);
} else if(!strncmp(name, "sync:", 5)) {
ret = create_service_thread("sync", file_sync_service, nullptr);
} else if(!strncmp(name, "remount:", 8)) {
ret = create_service_thread("remount", remount_service, nullptr);
} else if(!strncmp(name, "reboot:", 7)) {
void* arg = strdup(name + 7);
if (arg == NULL) return -1;
ret = create_service_thread("reboot", reboot_service, arg);
if (ret < 0) free(arg);
} else if(!strncmp(name, "root:", 5)) {
ret = create_service_thread("root", restart_root_service, nullptr);
} else if(!strncmp(name, "unroot:", 7)) {
ret = create_service_thread("unroot", restart_unroot_service, nullptr);
} else if(!strncmp(name, "backup:", 7)) {
ret = StartSubprocess(android::base::StringPrintf("/system/bin/bu backup %s",
(name + 7)).c_str(),
nullptr, SubprocessType::kRaw, SubprocessProtocol::kNone);
} else if(!strncmp(name, "restore:", 8)) {
ret = StartSubprocess("/system/bin/bu restore", nullptr, SubprocessType::kRaw,
SubprocessProtocol::kNone);
} else if(!strncmp(name, "tcpip:", 6)) {
int port;
if (sscanf(name + 6, "%d", &port) != 1) {
return -1;
}
ret = create_service_thread("tcp", restart_tcp_service, reinterpret_cast(port));
} else if(!strncmp(name, "usb:", 4)) {
ret = create_service_thread("usb", restart_usb_service, nullptr);
} else if (!strncmp(name, "reverse:", 8)) {
ret = reverse_service(name + 8, transport);
} else if(!strncmp(name, "disable-verity:", 15)) {
ret = create_service_thread("verity-on", set_verity_enabled_state_service,
reinterpret_cast(0));
} else if(!strncmp(name, "enable-verity:", 15)) {
ret = create_service_thread("verity-off", set_verity_enabled_state_service,
reinterpret_cast(1));
} else if (!strcmp(name, "reconnect")) {
ret = create_service_thread("reconnect", reconnect_service, transport);
#endif
}
if (ret >= 0) {
close_on_exec(ret);
}
return ret;
}
可以看到各种各样的命令是如何执行的,这里命令分为两类,一类是adbd本身可以处理的,例如adb reboot 、adb remount、adb root等等;一类是adbd不能处理的,需要通过调用StartSubprocess函数来执行其他二进制程序或者脚本来完成,例如adb logcat 、adb shell等。