Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 695597cb authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Refactor adbd_auth to allow better testing" into main

parents d1359d56 db925135
Loading
Loading
Loading
Loading
+458 −542
Original line number Diff line number Diff line
@@ -18,78 +18,17 @@

#include "include/adbd_auth.h"

#include <inttypes.h>
#include <sys/epoll.h>
#include <sys/eventfd.h>
#include <sys/uio.h>

#include <atomic>
#include <chrono>
#include <deque>
#include <optional>
#include <set>
#include <string>
#include <string_view>
#include <tuple>
#include <unordered_map>
#include <utility>
#include <variant>
#include <vector>

#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/macros.h>
#include <android-base/strings.h>
#include <android-base/thread_annotations.h>
#include <android-base/unique_fd.h>
#include <cutils/sockets.h>
#include "adbd_auth_internal.h"

using android::base::unique_fd;

static constexpr uint32_t kAuthVersion = 2;

static std::set<AdbdAuthFeature> supported_features = {AdbdAuthFeature::WifiLifeCycle};
static std::set<AdbdAuthFeature> supported_features = {
    AdbdAuthFeature::WifiLifeCycle};

struct AdbdAuthPacketAuthenticated {
    std::string public_key;
};

struct AdbdAuthPacketDisconnected {
    std::string public_key;
};

struct AdbdAuthPacketRequestAuthorization {
    std::string public_key;
};

struct AdbdPacketTlsDeviceConnected {
    uint8_t transport_type;
    std::string public_key;
};

struct AdbdPacketTlsDeviceDisconnected {
    uint8_t transport_type;
    std::string public_key;
};

struct AdbdPacketTlsServerPort {
  uint16_t port;
};

using AdbdAuthPacket = std::variant<AdbdAuthPacketAuthenticated,
                                    AdbdAuthPacketDisconnected,
                                    AdbdAuthPacketRequestAuthorization,
                                    AdbdPacketTlsDeviceConnected,
                                    AdbdPacketTlsDeviceDisconnected,
                                    AdbdPacketTlsServerPort>;

struct AdbdAuthContext {
    static constexpr uint64_t kEpollConstSocket = 0;
    static constexpr uint64_t kEpollConstEventFd = 1;
    static constexpr uint64_t kEpollConstFramework = 2;

public:
  explicit AdbdAuthContext(AdbdAuthCallbacksV1* callbacks) : next_id_(0), callbacks_(*callbacks) {
AdbdAuthContext::AdbdAuthContext(AdbdAuthCallbacksV1* callbacks)
    : next_id_(0), callbacks_(*callbacks) {
  epoll_fd_.reset(epoll_create1(EPOLL_CLOEXEC));
  if (epoll_fd_ == -1) {
    PLOG(FATAL) << "adbd_auth: failed to create epoll fd";
@@ -105,29 +44,23 @@ public:
    PLOG(ERROR) << "adbd_auth: failed to get adbd authentication socket";
  } else {
    if (fcntl(sock_fd_.get(), F_SETFD, FD_CLOEXEC) != 0) {
                PLOG(FATAL) << "adbd_auth: failed to make adbd authentication socket cloexec";
      PLOG(FATAL)
          << "adbd_auth: failed to make adbd authentication socket cloexec";
    }

    if (fcntl(sock_fd_.get(), F_SETFL, O_NONBLOCK) != 0) {
                PLOG(FATAL) << "adbd_auth: failed to make adbd authentication socket nonblocking";
      PLOG(FATAL)
          << "adbd_auth: failed to make adbd authentication socket nonblocking";
    }

    if (listen(sock_fd_.get(), 4) != 0) {
                PLOG(FATAL) << "adbd_auth: failed to listen on adbd authentication socket";
      PLOG(FATAL)
          << "adbd_auth: failed to listen on adbd authentication socket";
    }
  }
}

    virtual ~AdbdAuthContext(){}

    AdbdAuthContext(const AdbdAuthContext& copy) = delete;
    AdbdAuthContext(AdbdAuthContext&& move) = delete;
    AdbdAuthContext& operator=(const AdbdAuthContext& copy) = delete;
    AdbdAuthContext& operator=(AdbdAuthContext&& move) = delete;

    uint64_t NextId() { return next_id_++; }

    void DispatchPendingPrompt() REQUIRES(mutex_) {
void AdbdAuthContext::DispatchPendingPrompt() REQUIRES(mutex_) {
  if (dispatched_prompt_) {
    LOG(INFO) << "adbd_auth: prompt currently pending, skipping";
    return;
@@ -149,10 +82,10 @@ public:
  dispatched_prompt_ = std::make_tuple(id, public_key, arg);
}

    void UpdateFrameworkWritable() REQUIRES(mutex_) {
        // This might result in redundant calls to EPOLL_CTL_MOD if, for example, we get notified
        // at the same time as a framework connection, but that's unlikely and this doesn't need to
        // be fast anyway.
void AdbdAuthContext::UpdateFrameworkWritable() REQUIRES(mutex_) {
  // This might result in redundant calls to EPOLL_CTL_MOD if, for example, we
  // get notified at the same time as a framework connection, but that's
  // unlikely and this doesn't need to be fast anyway.
  if (framework_fd_ != -1) {
    struct epoll_event event;
    event.events = EPOLLIN;
@@ -161,11 +94,12 @@ public:
      event.events |= EPOLLOUT;
    }
    event.data.u64 = kEpollConstFramework;
            CHECK_EQ(0, epoll_ctl(epoll_fd_.get(), EPOLL_CTL_MOD, framework_fd_.get(), &event));
    CHECK_EQ(0, epoll_ctl(epoll_fd_.get(), EPOLL_CTL_MOD, framework_fd_.get(),
                          &event));
  }
}

    void ReplaceFrameworkFd(unique_fd new_fd) REQUIRES(mutex_) {
void AdbdAuthContext::ReplaceFrameworkFd(unique_fd new_fd) REQUIRES(mutex_) {
  LOG(INFO) << "adbd_auth: received new framework fd " << new_fd.get()
            << " (current = " << framework_fd_.get() << ")";

@@ -173,7 +107,8 @@ public:
  if (framework_fd_ != -1) {
    output_queue_.clear();
    dispatched_prompt_.reset();
            CHECK_EQ(0, epoll_ctl(epoll_fd_.get(), EPOLL_CTL_DEL, framework_fd_.get(), nullptr));
    CHECK_EQ(0, epoll_ctl(epoll_fd_.get(), EPOLL_CTL_DEL, framework_fd_.get(),
                          nullptr));
    framework_fd_.reset();
  }

@@ -185,12 +120,13 @@ public:
      event.events |= EPOLLOUT;
    }
    event.data.u64 = kEpollConstFramework;
            CHECK_EQ(0, epoll_ctl(epoll_fd_.get(), EPOLL_CTL_ADD, new_fd.get(), &event));
    CHECK_EQ(0,
             epoll_ctl(epoll_fd_.get(), EPOLL_CTL_ADD, new_fd.get(), &event));
    framework_fd_ = std::move(new_fd);
  }
}

    void HandlePacket(std::string_view packet) EXCLUDES(mutex_) {
void AdbdAuthContext::HandlePacket(std::string_view packet) EXCLUDES(mutex_) {
  LOG(INFO) << "adbd_auth: received packet: " << packet;

  if (packet.size() < 2) {
@@ -214,20 +150,22 @@ public:
  }
}

    void AllowUsbDevice(std::string_view buf) EXCLUDES(mutex_) {
void AdbdAuthContext::AllowUsbDevice(std::string_view buf) EXCLUDES(mutex_) {
  std::lock_guard<std::mutex> lock(mutex_);
  CHECK(buf.empty());

  if (dispatched_prompt_.has_value()) {
            // It's possible for the framework to send us a response without our having sent a
            // request to it: e.g. if adbd restarts while we have a pending request.
    // It's possible for the framework to send us a response without our having
    // sent a request to it: e.g. if adbd restarts while we have a pending
    // request.
    auto& [id, key, arg] = *dispatched_prompt_;
    keys_.emplace(id, std::move(key));

    callbacks_.key_authorized(arg, id);
    dispatched_prompt_ = std::nullopt;
  } else {
            LOG(WARNING) << "adbd_auth: received authorization for unknown prompt, ignoring";
    LOG(WARNING)
        << "adbd_auth: received authorization for unknown prompt, ignoring";
  }

  // We need to dispatch pending prompts here upon success as well,
@@ -235,7 +173,7 @@ public:
  DispatchPendingPrompt();
}

    void DenyUsbDevice(std::string_view buf) EXCLUDES(mutex_) {
void AdbdAuthContext::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?
@@ -243,12 +181,12 @@ public:
  DispatchPendingPrompt();
}

    void KeyRemoved(std::string_view buf) EXCLUDES(mutex_) {
void AdbdAuthContext::KeyRemoved(std::string_view buf) EXCLUDES(mutex_) {
  CHECK(!buf.empty());
  callbacks_.key_removed(buf.data(), buf.size());
}

    bool SendPacket() REQUIRES(mutex_) {
bool AdbdAuthContext::SendPacket() REQUIRES(mutex_) {
  if (output_queue_.empty()) {
    return false;
  }
@@ -269,7 +207,8 @@ public:
    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<AdbdAuthPacketRequestAuthorization>(&packet)) {
  } else if (auto* p =
                 std::get_if<AdbdAuthPacketRequestAuthorization>(&packet)) {
    iovs[0].iov_base = const_cast<char*>("PK");
    iovs[0].iov_len = 2;
    iovs[1].iov_base = p->public_key.data();
@@ -300,7 +239,8 @@ public:
    LOG(FATAL) << "adbd_auth: unhandled packet type?";
  }

        LOG(INFO) << "adbd_auth: sending packet: " << std::string((const char*)iovs[0].iov_base, 2);
  LOG(INFO) << "adbd_auth: sending packet: "
            << std::string((const char*)iovs[0].iov_base, 2);

  ssize_t rc = writev(framework_fd_.get(), iovs, iovcnt);
  output_queue_.pop_front();
@@ -313,21 +253,23 @@ public:
  return true;
}

    void Run() {
void AdbdAuthContext::Run() {
  if (sock_fd_ == -1) {
    LOG(ERROR) << "adbd_auth: socket unavailable, disabling user prompts";
  } else {
    struct epoll_event event;
    event.events = EPOLLIN;
    event.data.u64 = kEpollConstSocket;
            CHECK_EQ(0, epoll_ctl(epoll_fd_.get(), EPOLL_CTL_ADD, sock_fd_.get(), &event));
    CHECK_EQ(0,
             epoll_ctl(epoll_fd_.get(), EPOLL_CTL_ADD, sock_fd_.get(), &event));
  }

  {
    struct epoll_event event;
    event.events = EPOLLIN;
    event.data.u64 = kEpollConstEventFd;
            CHECK_EQ(0, epoll_ctl(epoll_fd_.get(), EPOLL_CTL_ADD, event_fd_.get(), &event));
    CHECK_EQ(
        0, epoll_ctl(epoll_fd_.get(), EPOLL_CTL_ADD, event_fd_.get(), &event));
  }

  while (true) {
@@ -367,10 +309,11 @@ public:
        case kEpollConstEventFd: {
          // We were woken up to write something.
          uint64_t dummy;
                        int rc = TEMP_FAILURE_RETRY(read(event_fd_.get(), &dummy, sizeof(dummy)));
          int rc =
              TEMP_FAILURE_RETRY(read(event_fd_.get(), &dummy, sizeof(dummy)));
          if (rc != 8) {
                            PLOG(FATAL)
                                    << "adbd_auth: failed to read from eventfd (rc = " << rc << ")";
            PLOG(FATAL) << "adbd_auth: failed to read from eventfd (rc = " << rc
                        << ")";
          }

          std::lock_guard<std::mutex> lock(mutex_);
@@ -381,7 +324,8 @@ public:
        case kEpollConstFramework: {
          char buf[4096];
          if (event.events & EPOLLIN) {
                            int rc = TEMP_FAILURE_RETRY(read(framework_fd_.get(), buf, sizeof(buf)));
            int rc =
                TEMP_FAILURE_RETRY(read(framework_fd_.get(), buf, sizeof(buf)));
            if (rc == -1) {
              PLOG(FATAL) << "adbd_auth: failed to read from framework fd";
            } else if (rc == 0) {
@@ -412,7 +356,9 @@ public:
    {"/adb_keys", true /* follow symlinks */},
    {"/data/misc/adb/adb_keys", false /* don't follow symlinks */},
};
    void IteratePublicKeys(bool (*callback)(void*, const char*, size_t), void* opaque) {
void AdbdAuthContext::IteratePublicKeys(bool (*callback)(void*, const char*,
                                                         size_t),
                                        void* opaque) {
  for (const auto& [path, follow_symlinks] : key_paths) {
    if (access(path, R_OK) == 0) {
      LOG(INFO) << "adbd_auth: loading keys from " << path;
@@ -430,7 +376,8 @@ public:
  }
}

    uint64_t PromptUser(std::string_view public_key, void* arg) EXCLUDES(mutex_) {
uint64_t AdbdAuthContext::PromptUser(std::string_view public_key, void* arg)
    EXCLUDES(mutex_) {
  uint64_t id = NextId();

  std::lock_guard<std::mutex> lock(mutex_);
@@ -440,7 +387,8 @@ public:
  return id;
}

    uint64_t NotifyAuthenticated(std::string_view public_key) EXCLUDES(mutex_) {
uint64_t AdbdAuthContext::NotifyAuthenticated(std::string_view public_key)
    EXCLUDES(mutex_) {
  uint64_t id = NextId();
  std::lock_guard<std::mutex> lock(mutex_);
  keys_.emplace(id, public_key);
@@ -449,34 +397,40 @@ public:
  return id;
}

    void NotifyDisconnected(uint64_t id) EXCLUDES(mutex_) {
void AdbdAuthContext::NotifyDisconnected(uint64_t id) EXCLUDES(mutex_) {
  std::lock_guard<std::mutex> lock(mutex_);
  auto it = keys_.find(id);
  if (it == keys_.end()) {
            LOG(DEBUG) << "adbd_auth: couldn't find public key to notify disconnection, skipping";
    LOG(DEBUG) << "adbd_auth: couldn't find public key to notify "
                  "disconnection, skipping";
    return;
  }
        output_queue_.emplace_back(AdbdAuthPacketDisconnected{.public_key = std::move(it->second)});
  output_queue_.emplace_back(
      AdbdAuthPacketDisconnected{.public_key = std::move(it->second)});
  keys_.erase(it);
}

    uint64_t NotifyTlsDeviceConnected(AdbTransportType type,
                                      std::string_view public_key) EXCLUDES(mutex_) {
uint64_t AdbdAuthContext::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),
  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_) {
void AdbdAuthContext::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) << "adbd_auth: couldn't find public key to notify disconnection of tls "
    LOG(DEBUG)
        << "adbd_auth: couldn't find public key to notify disconnection of tls "
           "device, skipping";
    return;
  }
@@ -487,16 +441,14 @@ public:
  Interrupt();
}

    void SendTLSServerPort(uint16_t port) {
void AdbdAuthContext::SendTLSServerPort(uint16_t port) {
  std::lock_guard<std::mutex> lock(mutex_);
        output_queue_.emplace_back(AdbdPacketTlsServerPort{
          .port = port
        });
  output_queue_.emplace_back(AdbdPacketTlsServerPort{.port = port});
  Interrupt();
}

// Interrupt the worker thread to do some work.
    void Interrupt() {
void AdbdAuthContext::Interrupt() {
  uint64_t value = 1;
  ssize_t rc = write(event_fd_.get(), &value, sizeof(value));
  if (rc == -1) {
@@ -506,95 +458,63 @@ public:
  }
}

    virtual void InitFrameworkHandlers() {
void AdbdAuthContext::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)});
      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)});
      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)});
      FrameworkPktHandler{.code = "NO",
                          .cb = std::bind(&AdbdAuthContext::DenyUsbDevice, this,
                                          std::placeholders::_1)});
}

    unique_fd epoll_fd_;
    unique_fd event_fd_;
    unique_fd sock_fd_;
    unique_fd framework_fd_;

    std::atomic<uint64_t> next_id_;
    AdbdAuthCallbacksV1 callbacks_;

    std::mutex mutex_;
    std::unordered_map<uint64_t, std::string> keys_ GUARDED_BY(mutex_);

    // 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_ 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_);
AdbdAuthContextV2::AdbdAuthContextV2(AdbdAuthCallbacksV2* callbacks)
    : AdbdAuthContext(callbacks), callbacks_v2_(*callbacks) {}

    // 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_;
};

class AdbdAuthContextV2 : public AdbdAuthContext {
 public:
  explicit AdbdAuthContextV2(AdbdAuthCallbacksV2* callbacks) : AdbdAuthContext(callbacks),
                                                               callbacks_v2_(*callbacks) {}

  virtual void InitFrameworkHandlers() {
void AdbdAuthContextV2::InitFrameworkHandlers() {
  AdbdAuthContext::InitFrameworkHandlers();
  // Framework requires ADB Wifi to start
  framework_handlers_.emplace_back(
                FrameworkPktHandler{
                    .code = "W1",
                    .cb = std::bind(&AdbdAuthContextV2::StartAdbWifi, this, std::placeholders::_1)});
      FrameworkPktHandler{.code = "W1",
                          .cb = std::bind(&AdbdAuthContextV2::StartAdbWifi,
                                          this, std::placeholders::_1)});

  // Framework requires ADB Wifi to stop
  framework_handlers_.emplace_back(
                FrameworkPktHandler{
                     .code = "W0",
                     .cb = std::bind(&AdbdAuthContextV2::StopAdbWifi, this, std::placeholders::_1)});
      FrameworkPktHandler{.code = "W0",
                          .cb = std::bind(&AdbdAuthContextV2::StopAdbWifi, this,
                                          std::placeholders::_1)});
}


  void StartAdbWifi(std::string_view buf) EXCLUDES(mutex_) {
void AdbdAuthContextV2::StartAdbWifi(std::string_view buf) EXCLUDES(mutex_) {
  CHECK(buf.empty());
  callbacks_v2_.start_adbd_wifi();
}

    void StopAdbWifi(std::string_view buf) EXCLUDES(mutex_) {
void AdbdAuthContextV2::StopAdbWifi(std::string_view buf) EXCLUDES(mutex_) {
  CHECK(buf.empty());
  callbacks_v2_.stop_adbd_wifi();
}

 private:
  AdbdAuthCallbacksV2 callbacks_v2_;
};

AdbdAuthContext* adbd_auth_new(AdbdAuthCallbacks* callbacks) {
  switch (callbacks->version) {
    case 1: {
        AdbdAuthContext* ctx = new AdbdAuthContext (reinterpret_cast<AdbdAuthCallbacksV1*>(callbacks));
      AdbdAuthContext* ctx = new AdbdAuthContext(
          reinterpret_cast<AdbdAuthCallbacksV1*>(callbacks));
      ctx->InitFrameworkHandlers();
      return ctx;
    }
    case kAuthVersion: {
        AdbdAuthContextV2* ctx2 = new AdbdAuthContextV2(reinterpret_cast<AdbdAuthCallbacksV2*>(callbacks));
      AdbdAuthContextV2* ctx2 = new AdbdAuthContextV2(
          reinterpret_cast<AdbdAuthCallbacksV2*>(callbacks));
      ctx2->InitFrameworkHandlers();
      return ctx2;
    }
@@ -606,21 +526,20 @@ AdbdAuthContext* adbd_auth_new(AdbdAuthCallbacks* callbacks) {
  }
}

void adbd_auth_delete(AdbdAuthContext* ctx) {
    delete ctx;
}
void adbd_auth_delete(AdbdAuthContext* ctx) { delete ctx; }

void adbd_auth_run(AdbdAuthContext* ctx) {
    return ctx->Run();
}
void adbd_auth_run(AdbdAuthContext* ctx) { return ctx->Run(); }

void adbd_auth_get_public_keys(AdbdAuthContext* ctx,
                               bool (*callback)(void* opaque, const char* public_key, size_t len),
                               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) {
uint64_t adbd_auth_notify_auth(AdbdAuthContext* ctx, const char* public_key,
                               size_t len) {
  return ctx->NotifyAuthenticated(std::string_view(public_key, len));
}

@@ -628,32 +547,29 @@ void adbd_auth_notify_disconnect(AdbdAuthContext* ctx, uint64_t id) {
  return ctx->NotifyDisconnected(id);
}

void adbd_auth_prompt_user(AdbdAuthContext* ctx, const char* public_key, size_t len,
                           void* opaque) {
void adbd_auth_prompt_user(AdbdAuthContext* ctx, const char* public_key,
                           size_t len, void* opaque) {
  adbd_auth_prompt_user_with_id(ctx, public_key, len, opaque);
}

uint64_t adbd_auth_prompt_user_with_id(AdbdAuthContext* ctx, const char* public_key, size_t len,
uint64_t adbd_auth_prompt_user_with_id(AdbdAuthContext* ctx,
                                       const char* public_key, size_t len,
                                       void* opaque) {
  return ctx->PromptUser(std::string_view(public_key, len), opaque);
}

uint64_t adbd_auth_tls_device_connected(AdbdAuthContext* ctx,
                                        AdbTransportType type,
                                        const char* public_key,
                                        size_t len) {
                                        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) {
                                       AdbTransportType type, uint64_t id) {
  ctx->NotifyTlsDeviceDisconnected(type, id);
}

uint32_t adbd_auth_get_max_version() {
    return kAuthVersion;
}
uint32_t adbd_auth_get_max_version() { return kAuthVersion; }

bool adbd_auth_supports_feature(AdbdAuthFeature f) {
  return supported_features.contains(f);
+151 −0

File added.

Preview size limit exceeded, changes collapsed.