Add adbd tls APIs to adbd_auth library.

Bug: 111434128

Test: mmm -j frameworks/native/libs/adbd_auth
Change-Id: Id285763c2c2dba1666040581d1d2d56e69ff54cb
diff --git a/libs/adbd_auth/Android.bp b/libs/adbd_auth/Android.bp
index 8ac044c..8883c04 100644
--- a/libs/adbd_auth/Android.bp
+++ b/libs/adbd_auth/Android.bp
@@ -27,7 +27,7 @@
 
     version_script: "libadbd_auth.map.txt",
     stubs: {
-        versions: ["1"],
+        versions: ["30"],
         symbol_file: "libadbd_auth.map.txt",
     },
 
diff --git a/libs/adbd_auth/adbd_auth.cpp b/libs/adbd_auth/adbd_auth.cpp
index a9c2311..5a0d3f6 100644
--- a/libs/adbd_auth/adbd_auth.cpp
+++ b/libs/adbd_auth/adbd_auth.cpp
@@ -43,6 +43,8 @@
 
 using android::base::unique_fd;
 
+static constexpr uint32_t kAuthVersion = 1;
+
 struct AdbdAuthPacketAuthenticated {
     std::string public_key;
 };
@@ -55,8 +57,21 @@
     std::string public_key;
 };
 
-using AdbdAuthPacket = std::variant<AdbdAuthPacketAuthenticated, AdbdAuthPacketDisconnected,
-                                    AdbdAuthPacketRequestAuthorization>;
+struct AdbdPacketTlsDeviceConnected {
+    uint8_t transport_type;
+    std::string public_key;
+};
+
+struct AdbdPacketTlsDeviceDisconnected {
+    uint8_t transport_type;
+    std::string public_key;
+};
+
+using AdbdAuthPacket = std::variant<AdbdAuthPacketAuthenticated,
+                                    AdbdAuthPacketDisconnected,
+                                    AdbdAuthPacketRequestAuthorization,
+                                    AdbdPacketTlsDeviceConnected,
+                                    AdbdPacketTlsDeviceDisconnected>;
 
 struct AdbdAuthContext {
     static constexpr uint64_t kEpollConstSocket = 0;
@@ -65,6 +80,7 @@
 
 public:
     explicit AdbdAuthContext(AdbdAuthCallbacksV1* callbacks) : next_id_(0), callbacks_(*callbacks) {
+        InitFrameworkHandlers();
         epoll_fd_.reset(epoll_create1(EPOLL_CLOEXEC));
         if (epoll_fd_ == -1) {
             PLOG(FATAL) << "failed to create epoll fd";
@@ -163,34 +179,56 @@
         }
     }
 
-    void HandlePacket(std::string_view packet) REQUIRES(mutex_) {
+    void HandlePacket(std::string_view packet) EXCLUDES(mutex_) {
         LOG(INFO) << "received packet: " << packet;
 
-        if (packet.length() < 2) {
-          LOG(ERROR) << "received packet of invalid length";
-          ReplaceFrameworkFd(unique_fd());
+        if (packet.size() < 2) {
+            LOG(ERROR) << "received packet of invalid length";
+            std::lock_guard<std::mutex> lock(mutex_);
+            ReplaceFrameworkFd(unique_fd());
         }
 
-        if (packet[0] == 'O' && packet[1] == 'K') {
-          CHECK(this->dispatched_prompt_.has_value());
-          auto& [id, key, arg] = *this->dispatched_prompt_;
-          keys_.emplace(id, std::move(key));
-
-          this->callbacks_.key_authorized(arg, id);
-          this->dispatched_prompt_ = std::nullopt;
-
-          // We need to dispatch pending prompts here upon success as well,
-          // since we might have multiple queued prompts.
-          DispatchPendingPrompt();
-        } else if (packet[0] == 'N' && packet[1] == 'O') {
-          CHECK_EQ(2UL, packet.length());
-          // TODO: Do we want a callback if the key is denied?
-          this->dispatched_prompt_ = std::nullopt;
-          DispatchPendingPrompt();
-        } else {
-          LOG(ERROR) << "unhandled packet: " << packet;
-          ReplaceFrameworkFd(unique_fd());
+        bool handled_packet = false;
+        for (size_t i = 0; i < framework_handlers_.size(); ++i) {
+            if (android::base::ConsumePrefix(&packet, framework_handlers_[i].code)) {
+                framework_handlers_[i].cb(packet);
+                handled_packet = true;
+                break;
+            }
         }
+        if (!handled_packet) {
+            LOG(ERROR) << "unhandled packet: " << packet;
+            std::lock_guard<std::mutex> lock(mutex_);
+            ReplaceFrameworkFd(unique_fd());
+        }
+    }
+
+    void AllowUsbDevice(std::string_view buf) EXCLUDES(mutex_) {
+        std::lock_guard<std::mutex> lock(mutex_);
+        CHECK(buf.empty());
+        CHECK(dispatched_prompt_.has_value());
+        auto& [id, key, arg] = *dispatched_prompt_;
+        keys_.emplace(id, std::move(key));
+
+        callbacks_.key_authorized(arg, id);
+        dispatched_prompt_ = std::nullopt;
+
+        // We need to dispatch pending prompts here upon success as well,
+        // since we might have multiple queued prompts.
+        DispatchPendingPrompt();
+    }
+
+    void DenyUsbDevice(std::string_view buf) EXCLUDES(mutex_) {
+        std::lock_guard<std::mutex> lock(mutex_);
+        CHECK(buf.empty());
+        // TODO: Do we want a callback if the key is denied?
+        dispatched_prompt_ = std::nullopt;
+        DispatchPendingPrompt();
+    }
+
+    void KeyRemoved(std::string_view buf) EXCLUDES(mutex_) {
+        CHECK(!buf.empty());
+        callbacks_.key_removed(buf.data(), buf.size());
     }
 
     bool SendPacket() REQUIRES(mutex_) {
@@ -201,7 +239,8 @@
         CHECK_NE(-1, framework_fd_.get());
 
         auto& packet = output_queue_.front();
-        struct iovec iovs[2];
+        struct iovec iovs[3];
+        int iovcnt = 2;
         if (auto* p = std::get_if<AdbdAuthPacketAuthenticated>(&packet)) {
             iovs[0].iov_base = const_cast<char*>("CK");
             iovs[0].iov_len = 2;
@@ -217,13 +256,29 @@
             iovs[0].iov_len = 2;
             iovs[1].iov_base = p->public_key.data();
             iovs[1].iov_len = p->public_key.size();
+        } else if (auto* p = std::get_if<AdbdPacketTlsDeviceConnected>(&packet)) {
+            iovcnt = 3;
+            iovs[0].iov_base = const_cast<char*>("WE");
+            iovs[0].iov_len = 2;
+            iovs[1].iov_base = &p->transport_type;
+            iovs[1].iov_len = 1;
+            iovs[2].iov_base = p->public_key.data();
+            iovs[2].iov_len = p->public_key.size();
+        } else if (auto* p = std::get_if<AdbdPacketTlsDeviceDisconnected>(&packet)) {
+            iovcnt = 3;
+            iovs[0].iov_base = const_cast<char*>("WF");
+            iovs[0].iov_len = 2;
+            iovs[1].iov_base = &p->transport_type;
+            iovs[1].iov_len = 1;
+            iovs[2].iov_base = p->public_key.data();
+            iovs[2].iov_len = p->public_key.size();
         } else {
             LOG(FATAL) << "unhandled packet type?";
         }
 
         output_queue_.pop_front();
 
-        ssize_t rc = writev(framework_fd_.get(), iovs, 2);
+        ssize_t rc = writev(framework_fd_.get(), iovs, iovcnt);
         if (rc == -1 && errno != EAGAIN && errno != EWOULDBLOCK) {
             PLOG(ERROR) << "failed to write to framework fd";
             ReplaceFrameworkFd(unique_fd());
@@ -308,7 +363,6 @@
                                 std::lock_guard<std::mutex> lock(mutex_);
                                 ReplaceFrameworkFd(unique_fd());
                             } else {
-                                std::lock_guard<std::mutex> lock(mutex_);
                                 HandlePacket(std::string_view(buf, rc));
                             }
                         }
@@ -329,7 +383,7 @@
     }
 
     static constexpr const char* key_paths[] = {"/adb_keys", "/data/misc/adb/adb_keys"};
-    void IteratePublicKeys(bool (*callback)(const char*, size_t, void*), void* arg) {
+    void IteratePublicKeys(bool (*callback)(void*, const char*, size_t), void* opaque) {
         for (const auto& path : key_paths) {
             if (access(path, R_OK) == 0) {
                 LOG(INFO) << "Loading keys from " << path;
@@ -339,7 +393,7 @@
                     continue;
                 }
                 for (const auto& line : android::base::Split(content, "\n")) {
-                    if (!callback(line.data(), line.size(), arg)) {
+                    if (!callback(opaque, line.data(), line.size())) {
                         return;
                     }
                 }
@@ -361,7 +415,7 @@
         std::lock_guard<std::mutex> lock(mutex_);
         keys_.emplace(id, public_key);
         output_queue_.emplace_back(
-                AdbdAuthPacketDisconnected{.public_key = std::string(public_key)});
+                AdbdAuthPacketAuthenticated{.public_key = std::string(public_key)});
         return id;
     }
 
@@ -376,6 +430,32 @@
         keys_.erase(it);
     }
 
+    uint64_t NotifyTlsDeviceConnected(AdbTransportType type,
+                                      std::string_view public_key) EXCLUDES(mutex_) {
+        uint64_t id = NextId();
+        std::lock_guard<std::mutex> lock(mutex_);
+        keys_.emplace(id, public_key);
+        output_queue_.emplace_back(AdbdPacketTlsDeviceConnected{
+                .transport_type = static_cast<uint8_t>(type),
+                .public_key = std::string(public_key)});
+        Interrupt();
+        return id;
+    }
+
+    void NotifyTlsDeviceDisconnected(AdbTransportType type, uint64_t id) EXCLUDES(mutex_) {
+        std::lock_guard<std::mutex> lock(mutex_);
+        auto it = keys_.find(id);
+        if (it == keys_.end()) {
+            LOG(DEBUG) << "couldn't find public key to notify disconnection of tls device, skipping";
+            return;
+        }
+        output_queue_.emplace_back(AdbdPacketTlsDeviceDisconnected{
+                .transport_type = static_cast<uint8_t>(type),
+                .public_key = std::move(it->second)});
+        keys_.erase(it);
+        Interrupt();
+    }
+
     // Interrupt the worker thread to do some work.
     void Interrupt() {
         uint64_t value = 1;
@@ -387,6 +467,24 @@
         }
     }
 
+    void InitFrameworkHandlers() {
+        // Framework wants to disconnect from a secured wifi device
+        framework_handlers_.emplace_back(
+                FrameworkPktHandler{
+                    .code = "DD",
+                    .cb = std::bind(&AdbdAuthContext::KeyRemoved, this, std::placeholders::_1)});
+        // Framework allows USB debugging for the device
+        framework_handlers_.emplace_back(
+                FrameworkPktHandler{
+                    .code = "OK",
+                    .cb = std::bind(&AdbdAuthContext::AllowUsbDevice, this, std::placeholders::_1)});
+        // Framework denies USB debugging for the device
+        framework_handlers_.emplace_back(
+                FrameworkPktHandler{
+                    .code = "NO",
+                    .cb = std::bind(&AdbdAuthContext::DenyUsbDevice, this, std::placeholders::_1)});
+    }
+
     unique_fd epoll_fd_;
     unique_fd event_fd_;
     unique_fd sock_fd_;
@@ -400,19 +498,27 @@
 
     // We keep two separate queues: one to handle backpressure from the socket (output_queue_)
     // and one to make sure we only dispatch one authrequest at a time (pending_prompts_).
-    std::deque<AdbdAuthPacket> output_queue_;
+    std::deque<AdbdAuthPacket> output_queue_ GUARDED_BY(mutex_);
 
     std::optional<std::tuple<uint64_t, std::string, void*>> dispatched_prompt_ GUARDED_BY(mutex_);
     std::deque<std::tuple<uint64_t, std::string, void*>> pending_prompts_ GUARDED_BY(mutex_);
+
+    // This is a list of commands that the framework could send to us.
+    using FrameworkHandlerCb = std::function<void(std::string_view)>;
+    struct FrameworkPktHandler {
+        const char* code;
+        FrameworkHandlerCb cb;
+    };
+    std::vector<FrameworkPktHandler> framework_handlers_;
 };
 
 AdbdAuthContext* adbd_auth_new(AdbdAuthCallbacks* callbacks) {
-    if (callbacks->version != 1) {
+    if (callbacks->version == 1) {
+        return new AdbdAuthContext(reinterpret_cast<AdbdAuthCallbacksV1*>(callbacks));
+    } else {
       LOG(ERROR) << "received unknown AdbdAuthCallbacks version " << callbacks->version;
       return nullptr;
     }
-
-    return new AdbdAuthContext(&callbacks->callbacks.v1);
 }
 
 void adbd_auth_delete(AdbdAuthContext* ctx) {
@@ -424,9 +530,9 @@
 }
 
 void adbd_auth_get_public_keys(AdbdAuthContext* ctx,
-                               bool (*callback)(const char* public_key, size_t len, void* arg),
-                               void* arg) {
-    ctx->IteratePublicKeys(callback, arg);
+                               bool (*callback)(void* opaque, const char* public_key, size_t len),
+                               void* opaque) {
+    ctx->IteratePublicKeys(callback, opaque);
 }
 
 uint64_t adbd_auth_notify_auth(AdbdAuthContext* ctx, const char* public_key, size_t len) {
@@ -438,10 +544,28 @@
 }
 
 void adbd_auth_prompt_user(AdbdAuthContext* ctx, const char* public_key, size_t len,
-                               void* arg) {
-    ctx->PromptUser(std::string_view(public_key, len), arg);
+                           void* opaque) {
+    ctx->PromptUser(std::string_view(public_key, len), opaque);
 }
 
-bool adbd_auth_supports_feature(AdbdAuthFeature) {
+uint64_t adbd_auth_tls_device_connected(AdbdAuthContext* ctx,
+                                        AdbTransportType type,
+                                        const char* public_key,
+                                        size_t len) {
+    return ctx->NotifyTlsDeviceConnected(type, std::string_view(public_key, len));
+}
+
+void adbd_auth_tls_device_disconnected(AdbdAuthContext* ctx,
+                                       AdbTransportType type,
+                                       uint64_t id) {
+    ctx->NotifyTlsDeviceDisconnected(type, id);
+}
+
+uint32_t adbd_auth_get_max_version() {
+    return kAuthVersion;
+}
+
+bool adbd_auth_supports_feature(AdbdAuthFeature f) {
+    UNUSED(f);
     return false;
 }
diff --git a/libs/adbd_auth/include/adbd_auth.h b/libs/adbd_auth/include/adbd_auth.h
index b7c1cb8..6ee3166 100644
--- a/libs/adbd_auth/include/adbd_auth.h
+++ b/libs/adbd_auth/include/adbd_auth.h
@@ -18,48 +18,159 @@
 
 #include <stdbool.h>
 #include <stdint.h>
+#include <sys/cdefs.h>
 #include <sys/types.h>
 
-extern "C" {
+#if !defined(__INTRODUCED_IN)
+#define __INTRODUCED_IN(__api_level) /* nothing */
+#endif
 
-struct AdbdAuthCallbacksV1 {
-    // Callback for a successful user authorization.
-    void (*key_authorized)(void* arg, uint64_t id);
+__BEGIN_DECLS
+#if !defined(__ANDROID__) || __ANDROID_API__ >= 30
+
+// The transport type of the device connection.
+enum AdbTransportType : int32_t {
+    kAdbTransportTypeUsb = 0,
+    kAdbTransportTypeWifi,
 };
+static_assert(sizeof(AdbTransportType) == sizeof(int32_t), "Unexpected AdbTransportType size");
 
 struct AdbdAuthCallbacks {
     uint32_t version;
-    union {
-        AdbdAuthCallbacksV1 v1;
-    } callbacks;
+};
+
+struct AdbdAuthCallbacksV1 : AdbdAuthCallbacks {
+    // Callback for a successful user authorization.
+    void (*key_authorized)(void* opaque, uint64_t id);
+    // The framework removed the key from the keystore. This callback notifies
+    // adbd so it can take the appropriate actions (e.g. disconnect all devices
+    // using that key).
+    void (*key_removed)(const char* public_key, size_t length);
 };
 
 struct AdbdAuthContext;
+typedef struct AdbdAuthContext AdbdAuthContext;
 
-AdbdAuthContext* adbd_auth_new(AdbdAuthCallbacks* callbacks);
-void adbd_auth_delete(AdbdAuthContext* ctx);
+/**
+ * Creates a new AdbdAuthContext.
+ *
+ * @param callbacks a set of user-provided callbacks used internally (see
+ * #AdbdAuthCallbacksV1
+ * @return a new AdbdAuthContext instance. Caller is responsible for destroying
+ * the context with #adbd_auth_delete.
+ */
+AdbdAuthContext* adbd_auth_new(AdbdAuthCallbacks* callbacks) __INTRODUCED_IN(30);
 
-void adbd_auth_run(AdbdAuthContext* ctx);
+/**
+ * Destroys the AdbdAuthContext.
+ *
+ * @param ctx the AdbdAuthContext to destroy.
+ */
+void adbd_auth_delete(AdbdAuthContext* ctx) __INTRODUCED_IN(30);
 
-// Iterate through the list of authorized public keys.
-// Return false from the callback to stop iteration.
+/**
+ * Starts the AdbdAuthContext.
+ *
+ * The caller may want to run this on a different thread, as this
+ * runs indefinitely.
+ *
+ * @param ctx the AdbdAuthContext
+ */
+void adbd_auth_run(AdbdAuthContext* ctx) __INTRODUCED_IN(30);
+
+/**
+ * Iterate through the list of authorized public keys.
+ *
+ * @param ctx the AdbdAuthContext
+ * @param callback a callback which will get called for every known adb public
+ * key in its keystore. To stop iteration of the keys, return false in the
+ * callback. Otherwise, return true to continue the iteration.
+ * @param opaque an opaque userdata argument
+ */
 void adbd_auth_get_public_keys(AdbdAuthContext* ctx,
-                               bool (*callback)(const char* public_key, size_t len, void* arg),
-                               void* arg);
+                               bool (*callback)(void* opaque, const char* public_key, size_t len),
+                               void* opaque) __INTRODUCED_IN(30);
 
-// Let system_server know that a key has been successfully used for authentication.
-uint64_t adbd_auth_notify_auth(AdbdAuthContext* ctx, const char* public_key, size_t len);
+/**
+ * Let system_server know that a key has been successfully used for authentication.
+ *
+ * @param ctx the AdbdAuthContext
+ * @param public_key the RSA key that was authorized using the AUTH protocol
+ * @param len the length of the public_key argument
+ * @return an id corresponding to the new connection
+ */
+uint64_t adbd_auth_notify_auth(AdbdAuthContext* ctx,
+                               const char* public_key,
+                               size_t len) __INTRODUCED_IN(30);
 
-// Let system_server know that a connection has been closed.
-void adbd_auth_notify_disconnect(AdbdAuthContext* ctx, uint64_t id);
+/**
+ * Let system_server know that an AUTH connection has been closed.
+ *
+ * @param ctx the AdbdAuthContext
+ * @param id the id of the disconnected device
+ */
+void adbd_auth_notify_disconnect(AdbdAuthContext* ctx,
+                                 uint64_t id) __INTRODUCED_IN(30);
 
-// Prompt the user to authorize a public key.
-// When this happens, a callback will be run on the auth thread with the result.
-void adbd_auth_prompt_user(AdbdAuthContext* ctx, const char* public_key, size_t len, void* arg);
+/**
+ * Prompt the user to authorize a public key.
+ *
+ * When this happens, a callback will be run on the auth thread with the result.
+ *
+ * @param ctx the AdbdAuthContext
+ * @param public_key the RSA public key to prompt user with
+ * @param len the length of the public_key argument
+ * @param arg an opaque userdata argument
+ */
+void adbd_auth_prompt_user(AdbdAuthContext* ctx,
+                           const char* public_key,
+                           size_t len, void* opaque) __INTRODUCED_IN(30);
 
-enum AdbdAuthFeature {
+/**
+ * Let system_server know that a TLS device has connected.
+ *
+ * @param ctx the AdbdAuthContext
+ * @param type the transport type of the connection (see #AdbTransportType)
+ * @param public_key the RSA public key used to establish the connection
+ * @param len the length of the public_key argument
+ * @return an id corresponding to the new connection
+ */
+uint64_t adbd_auth_tls_device_connected(AdbdAuthContext* ctx,
+                                        AdbTransportType type,
+                                        const char* public_key,
+                                        size_t len) __INTRODUCED_IN(30);
+
+/**
+ * Let system_server know that a TLS device has disconnected.
+ *
+ * @param ctx the AdbdAuthContext
+ * @param type the transport type of the connection (see #AdbTransportType)
+ * @param the id of the disconnected device (see #adbd_tls_device_connected)
+ */
+void adbd_auth_tls_device_disconnected(AdbdAuthContext* ctx,
+                                       AdbTransportType type,
+                                       uint64_t id) __INTRODUCED_IN(30);
+
+/**
+ * Returns the max #AdbdAuthCallbacks version.
+ *
+ * The version starts at 1, with version 1 corresponding to the
+ * #AdbdAuthCallbacksV1 struct.
+ *
+ * @return the max #AdbdAuthCallbacks version.
+ */
+uint32_t adbd_auth_get_max_version(void) __INTRODUCED_IN(30);
+
+enum AdbdAuthFeature : int32_t {
 };
 
-bool adbd_auth_supports_feature(AdbdAuthFeature f);
+/**
+ * Checks if a feature is supported by the framework. See #AdbdAuthFeature.
+ *
+ * @param feature the feature to check for support
+ * @return true if the feature is supported
+ */
+bool adbd_auth_supports_feature(AdbdAuthFeature feature);
 
-}
+#endif  //!__ANDROID__ || __ANDROID_API__ >= 30
+__END_DECLS
diff --git a/libs/adbd_auth/libadbd_auth.map.txt b/libs/adbd_auth/libadbd_auth.map.txt
index d01233c..5857ecb 100644
--- a/libs/adbd_auth/libadbd_auth.map.txt
+++ b/libs/adbd_auth/libadbd_auth.map.txt
@@ -1,13 +1,16 @@
 LIBADBD_AUTH {
   global:
-    adbd_auth_new; # apex
-    adbd_auth_delete; # apex
-    adbd_auth_run; # apex
-    adbd_auth_get_public_keys; #apex
-    adbd_auth_notify_auth; # apex
-    adbd_auth_notify_disconnect; # apex
-    adbd_auth_prompt_user; # apex
-    adbd_auth_supports_feature; # apex
+    adbd_auth_new; # apex introduced=30
+    adbd_auth_delete; # apex introduced=30
+    adbd_auth_run; # apex introduced=30
+    adbd_auth_get_public_keys; #apex introduced=30
+    adbd_auth_notify_auth; # apex introduced=30
+    adbd_auth_notify_disconnect; # apex introduced=30
+    adbd_auth_prompt_user; # apex introduced=30
+    adbd_auth_tls_device_connected; # apex introduced=30
+    adbd_auth_tls_device_disconnected; # apex introduced=30
+    adbd_auth_get_max_version; # apex introduced=30
+    adbd_auth_supports_feature; # apex introduced=30
   local:
     *;
 };