diff --git a/adb/adb.cpp b/adb/adb.cpp index cb54d04e0..e0c05039d 100644 --- a/adb/adb.cpp +++ b/adb/adb.cpp @@ -1134,6 +1134,13 @@ int handle_host_request(const char* service, TransportType type, /* we don't even need to send a reply */ return 0; } + + if (!strcmp(service, "reconnect")) { + if (s->transport != nullptr) { + kick_transport(s->transport); + } + return SendOkay(reply_fd, "done"); + } #endif // ADB_HOST int ret = handle_forward_request(service, type, serial, reply_fd); diff --git a/adb/adb_client.cpp b/adb/adb_client.cpp index d29c08e83..a27dd4750 100644 --- a/adb/adb_client.cpp +++ b/adb/adb_client.cpp @@ -158,7 +158,8 @@ int _adb_connect(const std::string& service, std::string* error) { } } - if (memcmp(&service[0],"host",4) != 0 && switch_socket_transport(fd, error)) { + if ((memcmp(&service[0],"host",4) != 0 || service == "host:reconnect") && + switch_socket_transport(fd, error)) { return -1; } @@ -168,9 +169,11 @@ int _adb_connect(const std::string& service, std::string* error) { return -1; } - if (!adb_status(fd, error)) { - adb_close(fd); - return -1; + if (service != "reconnect") { + if (!adb_status(fd, error)) { + adb_close(fd); + return -1; + } } D("_adb_connect: return fd %d", fd); diff --git a/adb/commandline.cpp b/adb/commandline.cpp index a856672eb..323b9d399 100644 --- a/adb/commandline.cpp +++ b/adb/commandline.cpp @@ -239,6 +239,9 @@ static void help() { " - If it is \"system\", \"vendor\", \"oem\" or \"data\", only the corresponding partition\n" " is updated.\n" "\n" + "internal debugging:\n" + " adb reconnect Kick current connection from host side and make it reconnect.\n" + " adb reconnect device Kick current connection from device side and make it reconnect.\n" "environment variables:\n" " ADB_TRACE - Print debug information. A comma separated list of the following values\n" " 1 or all, adb, sockets, packets, rwx, usb, sync, sysdeps, transport, jdwp\n" @@ -1905,6 +1908,14 @@ int adb_commandline(int argc, const char **argv) { } } return 0; + } else if (!strcmp(argv[0], "reconnect")) { + if (argc == 1) { + return adb_query_command("host:reconnect"); + } else if (argc == 2 && !strcmp(argv[1], "device")) { + std::string err; + adb_connect("reconnect", &err); + return 0; + } } usage(); diff --git a/adb/services.cpp b/adb/services.cpp index d5e963b72..3c1aab8ae 100644 --- a/adb/services.cpp +++ b/adb/services.cpp @@ -184,6 +184,13 @@ void reboot_service(int fd, void* arg) adb_close(fd); } +static void reconnect_service(int fd, void* arg) { + WriteFdExactly(fd, "done"); + adb_close(fd); + atransport* t = static_cast(arg); + kick_transport(t); +} + int reverse_service(const char* command) { int s[2]; if (adb_socketpair(s)) { @@ -345,6 +352,8 @@ int service_to_fd(const char* name, const atransport* transport) { ret = create_service_thread(set_verity_enabled_state_service, (void*)0); } else if(!strncmp(name, "enable-verity:", 15)) { ret = create_service_thread(set_verity_enabled_state_service, (void*)1); + } else if (!strcmp(name, "reconnect")) { + ret = create_service_thread(reconnect_service, const_cast(transport)); #endif } if (ret >= 0) { diff --git a/adb/transport.cpp b/adb/transport.cpp index e3340afb3..aaab21daa 100644 --- a/adb/transport.cpp +++ b/adb/transport.cpp @@ -305,7 +305,11 @@ static void kick_transport_locked(atransport* t) { void kick_transport(atransport* t) { adb_mutex_lock(&transport_lock); - kick_transport_locked(t); + // As kick_transport() can be called from threads without guarantee that t is valid, + // check if the transport is in transport_list first. + if (std::find(transport_list.begin(), transport_list.end(), t) != transport_list.end()) { + kick_transport_locked(t); + } adb_mutex_unlock(&transport_lock); }