Merge "Revert "Reland "adbd: don't close ep0 until we receive FUNCTIONFS_UNBIND.""" am: efc0c3b3ec
am: 72d24dd547

Change-Id: Iafcc88c0441225d9279ff145c718be77851d639b
diff --git a/adb.cpp b/adb.cpp
index 24d4292..d5e7be1 100644
--- a/adb.cpp
+++ b/adb.cpp
@@ -337,9 +337,12 @@
             case ADB_AUTH_SIGNATURE: {
                 // TODO: Switch to string_view.
                 std::string signature(p->payload.begin(), p->payload.end());
-                if (adbd_auth_verify(t->token, sizeof(t->token), signature)) {
+                std::string auth_key;
+                if (adbd_auth_verify(t->token, sizeof(t->token), signature, &auth_key)) {
                     adbd_auth_verified(t);
                     t->failed_auth_attempts = 0;
+                    t->auth_key = auth_key;
+                    adbd_notify_framework_connected_key(t);
                 } else {
                     if (t->failed_auth_attempts++ > 256) std::this_thread::sleep_for(1s);
                     send_auth_request(t);
@@ -348,7 +351,8 @@
             }
 
             case ADB_AUTH_RSAPUBLICKEY:
-                adbd_auth_confirm_key(p->payload.data(), p->msg.data_length, t);
+                t->auth_key = std::string(p->payload.data());
+                adbd_auth_confirm_key(t);
                 break;
 #endif
             default:
diff --git a/adb.h b/adb.h
index 3a6f059..9324cee 100644
--- a/adb.h
+++ b/adb.h
@@ -33,6 +33,7 @@
 
 constexpr size_t MAX_PAYLOAD_V1 = 4 * 1024;
 constexpr size_t MAX_PAYLOAD = 1024 * 1024;
+constexpr size_t MAX_FRAMEWORK_PAYLOAD = 64 * 1024;
 
 constexpr size_t LINUX_MAX_SOCKET_SIZE = 4194304;
 
diff --git a/adb_auth.h b/adb_auth.h
index 2fc8478..2be9a76 100644
--- a/adb_auth.h
+++ b/adb_auth.h
@@ -50,8 +50,10 @@
 void adbd_auth_verified(atransport *t);
 
 void adbd_cloexec_auth_socket();
-bool adbd_auth_verify(const char* token, size_t token_size, const std::string& sig);
-void adbd_auth_confirm_key(const char* data, size_t len, atransport* t);
+bool adbd_auth_verify(const char* token, size_t token_size, const std::string& sig,
+                      std::string* auth_key);
+void adbd_auth_confirm_key(atransport* t);
+void adbd_notify_framework_connected_key(atransport* t);
 
 void send_auth_request(atransport *t);
 
diff --git a/daemon/auth.cpp b/daemon/auth.cpp
index 1800f84..a18afa4 100644
--- a/daemon/auth.cpp
+++ b/daemon/auth.cpp
@@ -18,6 +18,7 @@
 
 #include "adb.h"
 #include "adb_auth.h"
+#include "adb_io.h"
 #include "fdevent.h"
 #include "sysdeps.h"
 #include "transport.h"
@@ -25,7 +26,9 @@
 #include <resolv.h>
 #include <stdio.h>
 #include <string.h>
+#include <iomanip>
 
+#include <algorithm>
 #include <memory>
 
 #include <android-base/file.h>
@@ -37,22 +40,24 @@
 
 static fdevent* listener_fde = nullptr;
 static fdevent* framework_fde = nullptr;
-static int framework_fd = -1;
+static auto& framework_mutex = *new std::mutex();
+static int framework_fd GUARDED_BY(framework_mutex) = -1;
+static auto& connected_keys GUARDED_BY(framework_mutex) = *new std::vector<std::string>;
 
-static void usb_disconnected(void* unused, atransport* t);
-static struct adisconnect usb_disconnect = { usb_disconnected, nullptr};
-static atransport* usb_transport;
+static void adb_disconnected(void* unused, atransport* t);
+static struct adisconnect adb_disconnect = {adb_disconnected, nullptr};
+static atransport* adb_transport;
 static bool needs_retry = false;
 
 bool auth_required = true;
 
-bool adbd_auth_verify(const char* token, size_t token_size, const std::string& sig) {
+bool adbd_auth_verify(const char* token, size_t token_size, const std::string& sig,
+                      std::string* auth_key) {
     static constexpr const char* key_paths[] = { "/adb_keys", "/data/misc/adb/adb_keys", nullptr };
 
     for (const auto& path : key_paths) {
         if (access(path, R_OK) == 0) {
             LOG(INFO) << "Loading keys from " << path;
-
             std::string content;
             if (!android::base::ReadFileToString(path, &content)) {
                 PLOG(ERROR) << "Couldn't read " << path;
@@ -60,6 +65,8 @@
             }
 
             for (const auto& line : android::base::Split(content, "\n")) {
+                if (line.empty()) continue;
+                *auth_key = line;
                 // TODO: do we really have to support both ' ' and '\t'?
                 char* sep = strpbrk(const_cast<char*>(line.c_str()), " \t");
                 if (sep) *sep = '\0';
@@ -87,9 +94,31 @@
             }
         }
     }
+    auth_key->clear();
     return false;
 }
 
+static bool adbd_send_key_message_locked(std::string_view msg_type, std::string_view key)
+        REQUIRES(framework_mutex) {
+    if (framework_fd < 0) {
+        LOG(ERROR) << "Client not connected to send msg_type " << msg_type;
+        return false;
+    }
+    std::string msg = std::string(msg_type) + std::string(key);
+    int msg_len = msg.length();
+    if (msg_len >= static_cast<int>(MAX_FRAMEWORK_PAYLOAD)) {
+        LOG(ERROR) << "Key too long (" << msg_len << ")";
+        return false;
+    }
+
+    LOG(DEBUG) << "Sending '" << msg << "'";
+    if (!WriteFdExactly(framework_fd, msg.c_str(), msg_len)) {
+        PLOG(ERROR) << "Failed to write " << msg_type;
+        return false;
+    }
+    return true;
+}
+
 static bool adbd_auth_generate_token(void* token, size_t token_size) {
     FILE* fp = fopen("/dev/urandom", "re");
     if (!fp) return false;
@@ -98,17 +127,28 @@
     return okay;
 }
 
-static void usb_disconnected(void* unused, atransport* t) {
-    LOG(INFO) << "USB disconnect";
-    usb_transport = nullptr;
+static void adb_disconnected(void* unused, atransport* t) {
+    LOG(INFO) << "ADB disconnect";
+    adb_transport = nullptr;
     needs_retry = false;
+    {
+        std::lock_guard<std::mutex> lock(framework_mutex);
+        if (framework_fd >= 0) {
+            adbd_send_key_message_locked("DC", t->auth_key);
+        }
+        connected_keys.erase(std::remove(connected_keys.begin(), connected_keys.end(), t->auth_key),
+                             connected_keys.end());
+    }
 }
 
 static void framework_disconnected() {
     LOG(INFO) << "Framework disconnect";
     if (framework_fde) {
         fdevent_destroy(framework_fde);
-        framework_fd = -1;
+        {
+            std::lock_guard<std::mutex> lock(framework_mutex);
+            framework_fd = -1;
+        }
     }
 }
 
@@ -119,41 +159,28 @@
         if (ret <= 0) {
             framework_disconnected();
         } else if (ret == 2 && response[0] == 'O' && response[1] == 'K') {
-            if (usb_transport) {
-                adbd_auth_verified(usb_transport);
+            if (adb_transport) {
+                adbd_auth_verified(adb_transport);
             }
         }
     }
 }
 
-void adbd_auth_confirm_key(const char* key, size_t len, atransport* t) {
-    if (!usb_transport) {
-        usb_transport = t;
-        t->AddDisconnect(&usb_disconnect);
+void adbd_auth_confirm_key(atransport* t) {
+    if (!adb_transport) {
+        adb_transport = t;
+        t->AddDisconnect(&adb_disconnect);
     }
 
-    if (framework_fd < 0) {
-        LOG(ERROR) << "Client not connected";
-        needs_retry = true;
-        return;
-    }
+    {
+        std::lock_guard<std::mutex> lock(framework_mutex);
+        if (framework_fd < 0) {
+            LOG(ERROR) << "Client not connected";
+            needs_retry = true;
+            return;
+        }
 
-    if (key[len - 1] != '\0') {
-        LOG(ERROR) << "Key must be a null-terminated string";
-        return;
-    }
-
-    char msg[MAX_PAYLOAD_V1];
-    int msg_len = snprintf(msg, sizeof(msg), "PK%s", key);
-    if (msg_len >= static_cast<int>(sizeof(msg))) {
-        LOG(ERROR) << "Key too long (" << msg_len << ")";
-        return;
-    }
-    LOG(DEBUG) << "Sending '" << msg << "'";
-
-    if (unix_write(framework_fd, msg, msg_len) == -1) {
-        PLOG(ERROR) << "Failed to write PK";
-        return;
+        adbd_send_key_message_locked("PK", t->auth_key);
     }
 }
 
@@ -164,18 +191,46 @@
         return;
     }
 
-    if (framework_fd >= 0) {
-        LOG(WARNING) << "adb received framework auth socket connection again";
-        framework_disconnected();
+    {
+        std::lock_guard<std::mutex> lock(framework_mutex);
+        if (framework_fd >= 0) {
+            LOG(WARNING) << "adb received framework auth socket connection again";
+            framework_disconnected();
+        }
+
+        framework_fd = s;
+        framework_fde = fdevent_create(framework_fd, adbd_auth_event, nullptr);
+        fdevent_add(framework_fde, FDE_READ);
+
+        if (needs_retry) {
+            needs_retry = false;
+            send_auth_request(adb_transport);
+        }
+
+        // if a client connected before the framework was available notify the framework of the
+        // connected key now.
+        if (!connected_keys.empty()) {
+            for (const auto& key : connected_keys) {
+                adbd_send_key_message_locked("CK", key);
+            }
+        }
     }
+}
 
-    framework_fd = s;
-    framework_fde = fdevent_create(framework_fd, adbd_auth_event, nullptr);
-    fdevent_add(framework_fde, FDE_READ);
-
-    if (needs_retry) {
-        needs_retry = false;
-        send_auth_request(usb_transport);
+void adbd_notify_framework_connected_key(atransport* t) {
+    if (!adb_transport) {
+        adb_transport = t;
+        t->AddDisconnect(&adb_disconnect);
+    }
+    {
+        std::lock_guard<std::mutex> lock(framework_mutex);
+        if (std::find(connected_keys.begin(), connected_keys.end(), t->auth_key) ==
+            connected_keys.end()) {
+            connected_keys.push_back(t->auth_key);
+        }
+        if (framework_fd >= 0) {
+            adbd_send_key_message_locked("CK", t->auth_key);
+        }
     }
 }
 
diff --git a/transport.h b/transport.h
index f4490ed..3473ca2 100644
--- a/transport.h
+++ b/transport.h
@@ -274,6 +274,9 @@
     std::string device;
     std::string devpath;
 
+    // Used to provide the key to the framework.
+    std::string auth_key;
+
     bool IsTcpDevice() const { return type == kTransportLocal; }
 
 #if ADB_HOST