Maintains socket forward connections.
host-side socket_forward_proxy will keep a thread running that monitors
the adb connection to localhost:6520 + offset. If the connection is lost
due to adb daemon dying or the device not showing up in the adb devices
response, it will reconnect.
Bug: 79117228
Test: boot with host-adbd running and see the device appear in adb
devices. adb kill-server and wait for device to reappear in adb devices
Change-Id: Ia52fa04f19a2f2ca6b8496ff2f3e8f8f328cbe4f
diff --git a/common/frontend/socket_forward_proxy/Android.bp b/common/frontend/socket_forward_proxy/Android.bp
index caad62b..4def7bf 100644
--- a/common/frontend/socket_forward_proxy/Android.bp
+++ b/common/frontend/socket_forward_proxy/Android.bp
@@ -36,6 +36,7 @@
host: {
static_libs: [
"libcuttlefish_host_config",
+ "libadb_connection_maintainer",
],
},
},
diff --git a/common/frontend/socket_forward_proxy/main.cpp b/common/frontend/socket_forward_proxy/main.cpp
index ed4196e..a04c601 100644
--- a/common/frontend/socket_forward_proxy/main.cpp
+++ b/common/frontend/socket_forward_proxy/main.cpp
@@ -34,6 +34,7 @@
#ifdef CUTTLEFISH_HOST
#include "host/libs/config/host_config.h"
+#include "host/libs/adb_connection_maintainer/adb_connection_maintainer.h"
#endif
using vsoc::socket_forward::Packet;
@@ -148,13 +149,11 @@
SocketForwardRegionView::Receiver>
conn,
cvd::SharedFD socket) {
- // TODO create the SocketSender/Receivers in their respective threads?
- std::thread threads[] = {
- std::thread(SocketToShm, SocketReceiver{socket}, std::move(conn.first)),
- std::thread(ShmToSocket, SocketSender{socket}, std::move(conn.second))};
- for (auto&& t : threads) {
- t.detach();
- }
+ // TODO create the SocketSender/Receiver in their respective threads?
+ std::thread(
+ SocketToShm, SocketReceiver{socket}, std::move(conn.first)).detach();
+ std::thread(
+ ShmToSocket, SocketSender{socket}, std::move(conn.second)).detach();
}
#ifdef CUTTLEFISH_HOST
@@ -163,6 +162,10 @@
int host_port;
};
+void LaunchConnectionMaintainer(int port) {
+ std::thread(cvd::EstablishAndMaintainConnection, port).detach();
+}
+
[[noreturn]] void host_impl(SocketForwardRegionView* shm,
std::vector<PortPair> ports, std::size_t index) {
@@ -178,6 +181,7 @@
<< " for guest port " << guest_port;
auto server = cvd::SharedFD::SocketLocalServer(host_port, SOCK_STREAM);
CHECK(server->IsOpen()) << "Could not start server on port " << host_port;
+ LaunchConnectionMaintainer(host_port);
while (true) {
auto client_socket = cvd::SharedFD::Accept(*server);
CHECK(client_socket->IsOpen()) << "error creating client socket";
diff --git a/host/libs/Android.bp b/host/libs/Android.bp
index c7aa2ec..12fde97 100644
--- a/host/libs/Android.bp
+++ b/host/libs/Android.bp
@@ -14,6 +14,7 @@
// limitations under the License.
subdirs = [
+ "adb_connection_maintainer",
"config",
"monitor",
"ivserver",
diff --git a/host/libs/adb_connection_maintainer/Android.bp b/host/libs/adb_connection_maintainer/Android.bp
new file mode 100644
index 0000000..4a89da3
--- /dev/null
+++ b/host/libs/adb_connection_maintainer/Android.bp
@@ -0,0 +1,28 @@
+//
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_library_host_static {
+ name: "libadb_connection_maintainer",
+ srcs: [
+ "adb_connection_maintainer.cpp",
+ ],
+ header_libs: [
+ "cuttlefish_glog",
+ ],
+ shared_libs: [
+ "libbase",
+ ],
+ defaults: ["cuttlefish_host_only"],
+}
diff --git a/host/libs/adb_connection_maintainer/adb_connection_maintainer.cpp b/host/libs/adb_connection_maintainer/adb_connection_maintainer.cpp
new file mode 100644
index 0000000..22db608
--- /dev/null
+++ b/host/libs/adb_connection_maintainer/adb_connection_maintainer.cpp
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <iomanip>
+#include <sstream>
+#include <string>
+#include <memory>
+#include <glog/logging.h>
+
+#include <unistd.h>
+
+#include "common/libs/fs/shared_fd.h"
+#include "host/libs/adb_connection_maintainer/adb_connection_maintainer.h"
+
+namespace {
+
+std::string MakeMessage(const std::string& user_message) {
+ static constexpr char kPrefix[] = "host:";
+ static constexpr std::size_t kPrefixLen = sizeof kPrefix - 1;
+ std::ostringstream ss;
+ ss << std::setfill('0') << std::setw(4) << std::hex
+ << (kPrefixLen + user_message.size()) << kPrefix << user_message;
+ return ss.str();
+}
+
+std::string MakeIPAndPort(int port) {
+ static constexpr char kLocalHostPrefix[] = "127.0.0.1:";
+ return kLocalHostPrefix + std::to_string(port);
+}
+
+std::string MakeConnectMessage(int port) {
+ static constexpr char kConnectPrefix[] = "connect:";
+ return MakeMessage(kConnectPrefix + MakeIPAndPort(port));
+}
+
+// returns true if successfully sent the whole message
+bool SendAll(cvd::SharedFD sock, const std::string& msg) {
+ ssize_t total_written{};
+ while (total_written < static_cast<ssize_t>(msg.size())) {
+ if (!sock->IsOpen()) {
+ return false;
+ }
+ auto just_written = sock->Send(msg.c_str() + total_written,
+ msg.size() - total_written, MSG_NOSIGNAL);
+ if (just_written <= 0) {
+ return false;
+ }
+ total_written += just_written;
+ }
+ return true;
+}
+
+std::string RecvAll(cvd::SharedFD sock, const size_t count) {
+ size_t total_read{};
+ std::unique_ptr<char[]> data(new char[count]);
+ while (total_read < count) {
+ auto just_read = sock->Read(data.get() + total_read, count - total_read);
+ if (just_read <= 0) {
+ return {};
+ }
+ total_read += just_read;
+ }
+ return {data.get(), count};
+}
+
+// Response will either be OKAY or FAIL
+constexpr char kAdbOkayStatusResponse[] = "OKAY";
+constexpr std::size_t kAdbStatusResponseLength =
+ sizeof kAdbOkayStatusResponse - 1;
+// adb sends the length of what is to follow as a 4 characters string of hex
+// digits
+constexpr std::size_t kAdbMessageLengthLength = 4;
+
+constexpr int kAdbDaemonPort = 5037;
+
+bool AdbConnect(cvd::SharedFD sock, int port) {
+ if (!SendAll(sock, MakeConnectMessage(port))) {
+ return false;
+ }
+ return RecvAll(sock, kAdbStatusResponseLength) == kAdbOkayStatusResponse;
+}
+
+// assumes the OKAY/FAIL status has already been read
+std::string RecvAdbResponse(cvd::SharedFD sock) {
+ auto length_as_hex_str = RecvAll(sock, kAdbMessageLengthLength);
+ auto length = std::stoi(length_as_hex_str, nullptr, 16);
+ return RecvAll(sock, length);
+}
+
+void EstablishConnection(int port) {
+ while (true) {
+ LOG(INFO) << "Attempting to connect to device on port " << port;
+ auto sock = cvd::SharedFD::SocketLocalClient(kAdbDaemonPort, SOCK_STREAM);
+ if (sock->IsOpen() && AdbConnect(sock, port)) {
+ LOG(INFO) << "connected to device on port " << port << '\n';
+ break;
+ }
+ sleep(2);
+ }
+}
+
+void WaitForAdbDisconnection(int port) {
+ LOG(INFO) << "Watching for disconnect on port " << port;
+ while (true) {
+ auto sock = cvd::SharedFD::SocketLocalClient(kAdbDaemonPort, SOCK_STREAM);
+ if (!SendAll(sock, MakeMessage("devices"))) {
+ break;
+ }
+ if (RecvAll(sock, 4) != kAdbOkayStatusResponse) {
+ break;
+ }
+ auto devices_str = RecvAdbResponse(sock);
+ if (devices_str.find(MakeIPAndPort(port)) == std::string::npos) {
+ break;
+ }
+ sleep(2);
+ }
+}
+
+} // namespace
+
+[[noreturn]] void cvd::EstablishAndMaintainConnection(int port) {
+ while (true) {
+ EstablishConnection(port);
+ WaitForAdbDisconnection(port);
+ }
+}
diff --git a/host/libs/adb_connection_maintainer/adb_connection_maintainer.h b/host/libs/adb_connection_maintainer/adb_connection_maintainer.h
new file mode 100644
index 0000000..d3378ce
--- /dev/null
+++ b/host/libs/adb_connection_maintainer/adb_connection_maintainer.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+namespace cvd {
+
+[[noreturn]] void EstablishAndMaintainConnection(int port);
+
+} // namespace cvd