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.h b/adb/adb.h index 59644d43e..ea208004d 100644 --- a/adb/adb.h +++ b/adb/adb.h @@ -50,7 +50,7 @@ constexpr size_t MAX_PAYLOAD = MAX_PAYLOAD_V2; std::string adb_version(); // Increment this when we want to force users to start a new adb server. -#define ADB_SERVER_VERSION 35 +#define ADB_SERVER_VERSION 36 class atransport; struct usb_handle; 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 b828c41fc..0c5be84e2 100644 --- a/adb/commandline.cpp +++ b/adb/commandline.cpp @@ -242,6 +242,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" @@ -1934,6 +1937,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 67e8e414b..3b212e9c8 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/sysdeps_test.cpp b/adb/sysdeps_test.cpp index 78efea8ad..f0c334ef2 100644 --- a/adb/sysdeps_test.cpp +++ b/adb/sysdeps_test.cpp @@ -215,3 +215,32 @@ TEST_F(sysdeps_poll, disconnect) { // Linux returns POLLIN | POLLHUP, Windows returns just POLLHUP. EXPECT_EQ(POLLHUP, pfd.revents & POLLHUP); } + +TEST_F(sysdeps_poll, fd_count) { + // https://code.google.com/p/android/issues/detail?id=12141 + static constexpr int num_sockets = 512; + std::vector sockets; + std::vector pfds; + sockets.resize(num_sockets * 2); + for (int32_t i = 0; i < num_sockets; ++i) { + ASSERT_EQ(0, adb_socketpair(&sockets[i * 2])) << strerror(errno); + ASSERT_TRUE(WriteFdExactly(sockets[i * 2], &i, sizeof(i))); + adb_pollfd pfd; + pfd.events = POLLIN; + pfd.fd = sockets[i * 2 + 1]; + pfds.push_back(pfd); + } + + ASSERT_EQ(num_sockets, adb_poll(pfds.data(), pfds.size(), 0)); + for (int i = 0; i < num_sockets; ++i) { + ASSERT_NE(0, pfds[i].revents & POLLIN); + + int32_t buf[2] = { -1, -1 }; + ASSERT_EQ(adb_read(pfds[i].fd, buf, sizeof(buf)), static_cast(sizeof(int32_t))); + ASSERT_EQ(i, buf[0]); + } + + for (int fd : sockets) { + adb_close(fd); + } +} diff --git a/adb/sysdeps_win32.cpp b/adb/sysdeps_win32.cpp index a2f34fbb4..bc09fdcfb 100644 --- a/adb/sysdeps_win32.cpp +++ b/adb/sysdeps_win32.cpp @@ -191,7 +191,7 @@ typedef struct FHRec_ #define fh_socket u.socket #define WIN32_FH_BASE 2048 -#define WIN32_MAX_FHS 128 +#define WIN32_MAX_FHS 2048 static adb_mutex_t _win32_lock; static FHRec _win32_fhs[ WIN32_MAX_FHS ]; diff --git a/adb/transport.cpp b/adb/transport.cpp index f86a222b4..413b36203 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); }