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

Commit f676c282 authored by Android Build Coastguard Worker's avatar Android Build Coastguard Worker
Browse files

Snap for 13659452 from 8e95fe85 to 25Q4-release

Change-Id: I496d47fb25a2299154ef9d00c0e608d7f208af07
parents 415d36bb 8e95fe85
Loading
Loading
Loading
Loading
+0 −1
Original line number Diff line number Diff line
@@ -68,7 +68,6 @@ cc_test {
        "liblog",
    ],
    test_suites: [
        "cts",
        "general-tests",
    ],
}
+7 −0
Original line number Diff line number Diff line
{
  "presubmit": [
    {
      "name": "libadbd_auth_test"
    }
  ]
}
 No newline at end of file
+26 −13
Original line number Diff line number Diff line
@@ -27,19 +27,24 @@ static constexpr uint32_t kAuthVersion = 2;
static std::set<AdbdAuthFeature> supported_features = {
    AdbdAuthFeature::WifiLifeCycle};

AdbdAuthContext::AdbdAuthContext(AdbdAuthCallbacksV1* callbacks)
AdbdAuthContext::AdbdAuthContext(const AdbdAuthCallbacksV1* callbacks, std::optional<int> server_fd)
    : 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";
  }

  event_fd_.reset(eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK));
  if (event_fd_ == -1) {
    PLOG(FATAL) << "adbd_auth: failed to create eventfd";
  interrupt_fd_.reset(eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK));
  if (interrupt_fd_ == -1) {
    PLOG(FATAL) << "adbd_auth: failed to create interrupt_fd";
  }

  if (server_fd.has_value()) {
    sock_fd_.reset(server_fd.value());
  } else {
    sock_fd_.reset(android_get_control_socket("adbd"));
  }

  if (sock_fd_ == -1) {
    PLOG(ERROR) << "adbd_auth: failed to get adbd authentication socket";
  } else {
@@ -129,6 +134,7 @@ void AdbdAuthContext::ReplaceFrameworkFd(unique_fd new_fd) REQUIRES(mutex_) {
void AdbdAuthContext::HandlePacket(std::string_view packet) EXCLUDES(mutex_) {
  LOG(INFO) << "adbd_auth: received packet: " << packet;

  received_packets_++;
  if (packet.size() < 2) {
    LOG(ERROR) << "adbd_auth: received packet of invalid length";
    std::lock_guard<std::mutex> lock(mutex_);
@@ -269,10 +275,12 @@ void AdbdAuthContext::Run() {
    event.events = EPOLLIN;
    event.data.u64 = kEpollConstEventFd;
    CHECK_EQ(
        0, epoll_ctl(epoll_fd_.get(), EPOLL_CTL_ADD, event_fd_.get(), &event));
        0, epoll_ctl(epoll_fd_.get(), EPOLL_CTL_ADD, interrupt_fd_.get(), &event));
  }

  while (true) {
  running_ = true;

  while (running_) {
    struct epoll_event events[3];
    int rc = TEMP_FAILURE_RETRY(epoll_wait(epoll_fd_.get(), events, 3, -1));
    if (rc == -1) {
@@ -310,7 +318,7 @@ void AdbdAuthContext::Run() {
          // We were woken up to write something.
          uint64_t dummy;
          int rc =
              TEMP_FAILURE_RETRY(read(event_fd_.get(), &dummy, sizeof(dummy)));
              TEMP_FAILURE_RETRY(read(interrupt_fd_.get(), &dummy, sizeof(dummy)));
          if (rc != 8) {
            PLOG(FATAL) << "adbd_auth: failed to read from eventfd (rc = " << rc
                        << ")";
@@ -352,6 +360,11 @@ void AdbdAuthContext::Run() {
  }
}

void AdbdAuthContext::Stop() {
  running_ = false;
  Interrupt();
}

static constexpr std::pair<const char*, bool> key_paths[] = {
    {"/adb_keys", true /* follow symlinks */},
    {"/data/misc/adb/adb_keys", false /* don't follow symlinks */},
@@ -450,11 +463,11 @@ void AdbdAuthContext::SendTLSServerPort(uint16_t port) {
// Interrupt the worker thread to do some work.
void AdbdAuthContext::Interrupt() {
  uint64_t value = 1;
  ssize_t rc = write(event_fd_.get(), &value, sizeof(value));
  ssize_t rc = write(interrupt_fd_.get(), &value, sizeof(value));
  if (rc == -1) {
    PLOG(FATAL) << "adbd_auth: write to eventfd failed";
    PLOG(FATAL) << "adbd_auth: write to interrupt_fd failed";
  } else if (rc != sizeof(value)) {
    LOG(FATAL) << "adbd_auth: write to eventfd returned short (" << rc << ")";
    LOG(FATAL) << "adbd_auth: write to interrupt_fd returned short (" << rc << ")";
  }
}

@@ -476,8 +489,8 @@ void AdbdAuthContext::InitFrameworkHandlers() {
                                          std::placeholders::_1)});
}

AdbdAuthContextV2::AdbdAuthContextV2(AdbdAuthCallbacksV2* callbacks)
    : AdbdAuthContext(callbacks), callbacks_v2_(*callbacks) {}
AdbdAuthContextV2::AdbdAuthContextV2(const AdbdAuthCallbacksV2* callbacks, std::optional<int> server_fd)
    : AdbdAuthContext(callbacks, server_fd), callbacks_v2_(*callbacks) {}

void AdbdAuthContextV2::InitFrameworkHandlers() {
  AdbdAuthContext::InitFrameworkHandlers();
+39 −4
Original line number Diff line number Diff line
@@ -31,6 +31,7 @@
#include <atomic>
#include <chrono>
#include <deque>
#include <memory>
#include <optional>
#include <set>
#include <string>
@@ -79,8 +80,14 @@ struct AdbdAuthContext {
  static constexpr uint64_t kEpollConstFramework = 2;

 public:
  explicit AdbdAuthContext(AdbdAuthCallbacksV1* callbacks);
  virtual ~AdbdAuthContext() {}

  // For testing purposes, this method accepts a server_fd. This will make the Context use that
  // server socket instead of retrieving init created "adbd" socket. This socket should use
  // SOCK_SEQPACKET to respect message boundaries.
  explicit AdbdAuthContext(const AdbdAuthCallbacksV1* callbacks, std::optional<int> server_fd = {});
  virtual ~AdbdAuthContext() {
    Stop();
  }

  AdbdAuthContext(const AdbdAuthContext& copy) = delete;
  AdbdAuthContext(AdbdAuthContext&& move) = delete;
@@ -110,13 +117,36 @@ struct AdbdAuthContext {
  void Interrupt();
  virtual void InitFrameworkHandlers();

  void Stop();

  bool IsRunning() {
    return running_;
  }

  size_t ReceivedPackets() {
    return received_packets_;
  }

 protected:
  // The file descriptor from epoll_create().
  android::base::unique_fd epoll_fd_;
  android::base::unique_fd event_fd_;

  // Interrupt server_socket to make epoll_wait return when we have something to write.
  android::base::unique_fd interrupt_fd_;

  // Server socket. Created when the context is created and never changes.
  android::base::unique_fd sock_fd_;

  // The "active" socket when frameworks connects to the server socket.
  // This is where we read/write adbd/Framework messages.
  android::base::unique_fd framework_fd_;

  // Response/Request are matched thanks to a counter. We take outgoing request
  // with this counter id.
  std::atomic<uint64_t> next_id_;

  // Message received from Framework end in a callback. This is were where store
  // the callback targets.
  AdbdAuthCallbacksV1 callbacks_;

  std::mutex mutex_;
@@ -130,6 +160,8 @@ struct AdbdAuthContext {
  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_);

  std::atomic<bool> running_ = false;

  // This is a list of commands that the framework could send to us.
  using FrameworkHandlerCb = std::function<void(std::string_view)>;
  struct FrameworkPktHandler {
@@ -137,11 +169,14 @@ struct AdbdAuthContext {
    FrameworkHandlerCb cb;
  };
  std::vector<FrameworkPktHandler> framework_handlers_;

  std::atomic<size_t> received_packets_ = 0;
};

class AdbdAuthContextV2 : public AdbdAuthContext {
 public:
  explicit AdbdAuthContextV2(AdbdAuthCallbacksV2* callbacks);
  explicit AdbdAuthContextV2(const AdbdAuthCallbacksV2* callbacks, std::optional<int> server_fd = {});
  virtual ~AdbdAuthContextV2() = default;
  virtual void InitFrameworkHandlers();
  void StartAdbWifi(std::string_view buf) EXCLUDES(mutex_);
  void StopAdbWifi(std::string_view buf) EXCLUDES(mutex_);
+224 −16
Original line number Diff line number Diff line
@@ -16,32 +16,240 @@

#include <gtest/gtest.h>

#include <assert.h>
#include <stddef.h>
#include <stdint.h>
#include <memory>
#include <thread>
#include <string.h>
#include <unistd.h>

#include <sys/socket.h>
#include <sys/un.h>
#include <android-base/unique_fd.h>

#include "adbd_auth.h"
#include "adbd_auth_internal.h"

void Log(const std::string& msg) {
  LOG(INFO) << "(" << gettid() << "): " << msg;
}

using namespace std::string_view_literals;
using namespace std::string_literals;
using namespace std::chrono_literals;

constexpr std::string_view kUdsName = "\0adb_auth_test_uds"sv;
static_assert(kUdsName.size() <= sizeof(reinterpret_cast<sockaddr_un*>(0)->sun_path));

void start_wifi() {}
void stop_wifi() {}

class AdbAuthTest: public ::testing::Test {
// A convenient struct that will stop the context and wait for the context runner thread to
// return when it is destroyed.
struct ContextRunner {
 public:
    void SetUp() {
        AdbdAuthCallbacksV2 callbacks;
        callbacks.version = 2;
        callbacks.start_adbd_wifi = start_wifi;
        callbacks.stop_adbd_wifi = stop_wifi;
        context = adbd_auth_new(&callbacks);
  explicit ContextRunner(std::unique_ptr<AdbdAuthContext> context)  : context_(std::move(context)) {
    thread_ = std::thread([raw_context = context_.get()]() {
      raw_context->Run();
    });

    // Wait until the context has started running.
    while (!context_->IsRunning()) {
      std::this_thread::sleep_for(10ms);
    }
  }

    void TearDown() {
      adbd_auth_delete(context);
  ~ContextRunner() {
    context_->Stop();
    thread_.join();
  }

 protected:
  AdbdAuthContext* context;
  AdbdAuthContext* Context() {
    return context_.get();
  }
 private:
  std::thread thread_;
  std::unique_ptr<AdbdAuthContext> context_;
};

TEST_F(AdbAuthTest, SendTcpPort) {
  adbd_auth_send_tls_server_port(context, 1);
// Emulate android_get_control_socket which adbauth uses to get the Unix Domain Socket
// to communicate with Framework.
std::optional<int> CreateServerSocket() {
  int sockfd = socket(AF_UNIX, SOCK_SEQPACKET, 0);
  if (sockfd == -1) {
    Log("Failed to create server socket");
    return {};
  }

  struct sockaddr_un addr{};
  addr.sun_family = AF_UNIX;
  memset(addr.sun_path, 0, sizeof(addr.sun_path));
  strncpy(addr.sun_path, kUdsName.data(), kUdsName.size());

  if (bind(sockfd, (struct sockaddr*) &addr, sizeof(sockaddr_un)) == -1) {
    Log("Failed to bind socket server to abstract namespace");
    return {};
  }

  if (listen(sockfd, 1) == -1) {
    Log("Failed to listen on socket server");
    return {};
  }

  return sockfd;
}

// Workaround to fail from anywhere. FAIL macro can only be called from a function
// returning void.
void fail(const std::string& msg) {
  FAIL() << msg;
}

// This class behaves like AdbDebuggingManager.
//   - Open the UDS created by our adb_auth emulation layer
//   - Allow to send messages
//   - Allow to recv messages
class Framework {
 public:
  Framework() {
    socket_ = Connect();
  }

  ~Framework() {
    close(socket_);
  }

  std::string Recv() const {
    char msg[256];
    auto num_bytes_read = read(socket_, msg, sizeof(msg));
    if (num_bytes_read < 0) {
      Log("Framework could not read: "s + strerror(errno));
      return "";
    }

    Log("Framework read "s + std::to_string(num_bytes_read) + " bytes");
    return std::string(msg, num_bytes_read);
  }

  int Send(const std::string& msg) const {
    return write(socket_, msg.data(), msg.size());
  }

  void SendAndWaitContext(const std::string& msg, ContextRunner* runner) {
    auto packet_id = runner->Context()->ReceivedPackets();
    Send(msg);

    while(runner->Context()->ReceivedPackets() < packet_id + 1) {
      std::this_thread::sleep_for(10ms);
    }
  }

 private:
  int socket_;

  int Connect() {
    int fd = socket(AF_UNIX, SOCK_SEQPACKET, 0);
    if (fd == -1) {
      fail("Cannot create client socket");
    }


    sockaddr_un addr = { .sun_family = AF_UNIX };
    strncpy(addr.sun_path, kUdsName.data(), kUdsName.size());

    auto res = connect(fd, (struct sockaddr*) &addr, sizeof(addr));
    if (res == -1) {
      fail("Cannot connect client socket");
    }

    return fd;
  }
};

std::unique_ptr<ContextRunner> CreateContextRunner(const AdbdAuthCallbacks& cb) {
  auto server_socket = CreateServerSocket();
  if (!server_socket.has_value()) {
    Log("Cannot create context");
    return {};
  }

  std::unique_ptr<AdbdAuthContext> context;
  switch (cb.version) {
    case 1: {
      context = std::make_unique<AdbdAuthContext>(&reinterpret_cast<const AdbdAuthCallbacksV1&>(cb),
                                            server_socket.value());
      break;
    }
    case 2: {
      context = std::make_unique<AdbdAuthContextV2>(&reinterpret_cast<const AdbdAuthCallbacksV2&>(cb),
                                              server_socket.value());
      break;
    }
    default: {
      fail("Unable to create AuthContext for version="s + std::to_string(cb.version));
    }
  }
  context->InitFrameworkHandlers();

  return std::make_unique<ContextRunner>(std::move(context));
}

TEST(AdbAuthTest, SendTcpPort) {
  AdbdAuthCallbacksV1 callbacks{};
  callbacks.version = 1;
  auto runner = CreateContextRunner(callbacks);
  Framework framework{};

  // Send TLS to framework
  const uint8_t port = 19;
  adbd_auth_send_tls_server_port(runner->Context(), port);

  // Check that Framework received it.
  std::string msg = framework.Recv();
  ASSERT_EQ(4, msg.size());
  ASSERT_EQ(msg[0], 'T');
  ASSERT_EQ(msg[1], 'P');
  ASSERT_EQ(msg[2], port);
  ASSERT_EQ(msg[3], 0);
}

// If user forget to set callbacks, adbauth should not crash. Instead, it should
// discard messages and issue a warning.
TEST(AdbAuthTest, UnsetCallbacks) {
    AdbdAuthCallbacksV2 callbacks{};
    callbacks.version = 2;
    auto runner= CreateContextRunner(callbacks);
    Framework framework{};

    // We did not set the callback "start ADB Wifi". This should not crash if
    // the message is properly dispatched.
    framework.Send("W1");
    // We did not set the callback "stop ADB Wifi". This should not crash if.
    // the message is properly dispatched.
    framework.Send("W0");
}

// Test Wifi lifecycle callbacks
TEST(AdbAuthTest, WifiLifeCycle) {
    AdbdAuthCallbacksV2 callbacks{};
    callbacks.version = 2;

    static bool start_message_received = false;
    callbacks.start_adbd_wifi = [] {
       start_message_received= true;
    };

    static bool stop_message_received = false;
    callbacks.stop_adbd_wifi = [] {
       stop_message_received= true;
    };


    auto runner= CreateContextRunner(callbacks);
    Framework framework{};

    framework.SendAndWaitContext("W1", runner.get());
    ASSERT_EQ(start_message_received,true);

    framework.SendAndWaitContext("W0", runner.get());
    ASSERT_EQ(stop_message_received,true);
}
Loading