Merge "adb: add option to disable kill-server."
diff --git a/adb/adb.cpp b/adb/adb.cpp
index 6c03f74..0518e9d 100644
--- a/adb/adb.cpp
+++ b/adb/adb.cpp
@@ -1071,19 +1071,25 @@
     return 0;
 }
 
+static bool g_reject_kill_server = false;
+void adb_set_reject_kill_server(bool value) {
+    g_reject_kill_server = value;
+}
+
 HostRequestResult handle_host_request(std::string_view service, TransportType type,
                                       const char* serial, TransportId transport_id, int reply_fd,
                                       asocket* s) {
     if (service == "kill") {
-        fprintf(stderr, "adb server killed by remote request\n");
-        fflush(stdout);
+        if (g_reject_kill_server) {
+            LOG(WARNING) << "adb server ignoring kill-server";
+            SendFail(reply_fd, "kill-server rejected by remote server");
+        } else {
+            fprintf(stderr, "adb server killed by remote request\n");
+            SendOkay(reply_fd);
 
-        // Send a reply even though we don't read it anymore, so that old versions
-        // of adb that do read it don't spew error messages.
-        SendOkay(reply_fd);
-
-        // Rely on process exit to close the socket for us.
-        exit(0);
+            // Rely on process exit to close the socket for us.
+            exit(0);
+        }
     }
 
     LOG(DEBUG) << "handle_host_request(" << service << ")";
diff --git a/adb/adb.h b/adb/adb.h
index 7bc60fc..476ed9b 100644
--- a/adb/adb.h
+++ b/adb/adb.h
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-#ifndef __ADB_H
-#define __ADB_H
+#pragma once
 
 #include <limits.h>
 #include <stdint.h>
@@ -237,6 +236,7 @@
 
 void parse_banner(const std::string&, atransport* t);
 
+#if ADB_HOST
 // On startup, the adb server needs to wait until all of the connected devices are ready.
 // To do this, we need to know when the scan has identified all of the potential new transports, and
 // when each transport becomes ready.
@@ -250,6 +250,12 @@
 
 // Wait until device scan has completed and every transport is ready, or a timeout elapses.
 void adb_wait_for_device_initialization();
+#endif  // ADB_HOST
+
+#if ADB_HOST
+// When ssh-forwarding to a remote adb server, kill-server is almost never what you actually want,
+// and unfortunately, many other tools issue it. This adds a knob to reject kill-servers.
+void adb_set_reject_kill_server(bool reject);
+#endif
 
 void usb_init();
-#endif
diff --git a/adb/client/adb_client.cpp b/adb/client/adb_client.cpp
index f724cb5..c859d75 100644
--- a/adb/client/adb_client.cpp
+++ b/adb/client/adb_client.cpp
@@ -204,9 +204,25 @@
         return false;
     }
 
-    // The server might send OKAY, so consume that.
     char buf[4];
-    ReadFdExactly(fd.get(), buf, 4);
+    if (!ReadFdExactly(fd.get(), buf, 4)) {
+        fprintf(stderr, "error: failed to read response from server\n");
+        return false;
+    }
+
+    if (memcmp(buf, "OKAY", 4) == 0) {
+        // Nothing to do.
+    } else if (memcmp(buf, "FAIL", 4) == 0) {
+        std::string output, error;
+        if (!ReadProtocolString(fd.get(), &output, &error)) {
+            fprintf(stderr, "error: %s\n", error.c_str());
+            return false;
+        }
+
+        fprintf(stderr, "error: %s\n", output.c_str());
+        return false;
+    }
+
     // Now that no more data is expected, wait for socket orderly shutdown or error, indicating
     // server death.
     ReadOrderlyShutdown(fd.get());
diff --git a/adb/client/main.cpp b/adb/client/main.cpp
index 4a9eadc..05e210f 100644
--- a/adb/client/main.cpp
+++ b/adb/client/main.cpp
@@ -105,7 +105,12 @@
         fdevent_run_on_main_thread([]() { exit(0); });
     });
 
-    char* leak = getenv("ADB_LEAK");
+    const char* reject_kill_server = getenv("ADB_REJECT_KILL_SERVER");
+    if (reject_kill_server && strcmp(reject_kill_server, "1") == 0) {
+        adb_set_reject_kill_server(true);
+    }
+
+    const char* leak = getenv("ADB_LEAK");
     if (leak && strcmp(leak, "1") == 0) {
         intentionally_leak();
     }