adb: add reconnect command.
Add reconnect command for debugging. `reconnect` kicks a transport
from the host side, `reconnect device` kicks a transport from
the device side. They can be used to produce transport errors.
Bug: 25935458
Change-Id: I47daa338796b561941e7aba44a51a6dd117d1e98
diff --git a/adb/adb.cpp b/adb/adb.cpp
index cb54d04..e0c0503 100644
--- a/adb/adb.cpp
+++ b/adb/adb.cpp
@@ -1134,6 +1134,13 @@
/* 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 d29c08e..a27dd47 100644
--- a/adb/adb_client.cpp
+++ b/adb/adb_client.cpp
@@ -158,7 +158,8 @@
}
}
- 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 @@
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 a856672..323b9d3 100644
--- a/adb/commandline.cpp
+++ b/adb/commandline.cpp
@@ -239,6 +239,9 @@
" - 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 @@
}
}
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 d5e963b..3c1aab8 100644
--- a/adb/services.cpp
+++ b/adb/services.cpp
@@ -184,6 +184,13 @@
adb_close(fd);
}
+static void reconnect_service(int fd, void* arg) {
+ WriteFdExactly(fd, "done");
+ adb_close(fd);
+ atransport* t = static_cast<atransport*>(arg);
+ kick_transport(t);
+}
+
int reverse_service(const char* command) {
int s[2];
if (adb_socketpair(s)) {
@@ -345,6 +352,8 @@
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<atransport*>(transport));
#endif
}
if (ret >= 0) {
diff --git a/adb/transport.cpp b/adb/transport.cpp
index e3340af..aaab21d 100644
--- a/adb/transport.cpp
+++ b/adb/transport.cpp
@@ -305,7 +305,11 @@
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);
}