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

Commit 704494b0 authored by Josh Gao's avatar Josh Gao
Browse files

adb: add authorizing, connecting states to transport.

Add two states: connecting and authorizing, to disambiguate the offline
and unauthorized states, respectively.

Previously, devices would transition as follows:

  offline -> unauthorized -> offline -> online
  offline -> unauthorized (when actually unauthorized)

With this patch:

  connecting -> authorizing -> online
  connecting -> authorizing -> unauthorized (when actually unauthorized)

This allows test automation and the like to distinguish between offline
devices, unauthorized devices, and working devices without having to
do retry loops with arbitrary sleeps on their end.

Bug: http://b/79257434
Test: adb_test
Test: adbd_test
Test: manually plugging in a device with `while true; do adb shell echo foo; done`
Change-Id: I036d9b593b51a27a59ac3fc57da966fd52658567
parent 48cf760b
Loading
Loading
Loading
Loading
+6 −9
Original line number Diff line number Diff line
@@ -365,8 +365,8 @@ void handle_packet(apacket *p, atransport *t)
        switch (p->msg.arg0) {
#if ADB_HOST
            case ADB_AUTH_TOKEN:
                if (t->GetConnectionState() == kCsOffline) {
                    t->SetConnectionState(kCsUnauthorized);
                if (t->GetConnectionState() != kCsAuthorizing) {
                    t->SetConnectionState(kCsAuthorizing);
                }
                send_auth_response(p->payload.data(), p->msg.data_length, t);
                break;
@@ -1103,14 +1103,11 @@ int handle_host_request(const char* service, TransportType type, const char* ser
    if (!strcmp(service, "reconnect-offline")) {
        std::string response;
        close_usb_devices([&response](const atransport* transport) {
            switch (transport->GetConnectionState()) {
                case kCsOffline:
                case kCsUnauthorized:
            if (!ConnectionStateIsOnline(transport->GetConnectionState())) {
                response += "reconnecting " + transport->serial_name() + "\n";
                return true;
                default:
                    return false;
            }
            return false;
        });
        if (!response.empty()) {
            response.resize(response.size() - 1);
+20 −3
Original line number Diff line number Diff line
@@ -95,16 +95,33 @@ enum TransportType {

enum ConnectionState {
    kCsAny = -1,
    kCsOffline = 0,

    kCsConnecting = 0,  // Haven't received a response from the device yet.
    kCsAuthorizing,     // Authorizing with keys from ADB_VENDOR_KEYS.
    kCsUnauthorized,    // ADB_VENDOR_KEYS exhausted, fell back to user prompt.
    kCsNoPerm,          // Insufficient permissions to communicate with the device.
    kCsOffline,

    kCsBootloader,
    kCsDevice,
    kCsHost,
    kCsRecovery,
    kCsNoPerm,  // Insufficient permissions to communicate with the device.
    kCsSideload,
    kCsUnauthorized,
};

inline bool ConnectionStateIsOnline(ConnectionState state) {
    switch (state) {
        case kCsBootloader:
        case kCsDevice:
        case kCsHost:
        case kCsRecovery:
        case kCsSideload:
            return true;
        default:
            return false;
    }
}

void print_packet(const char* label, apacket* p);

// These use the system (v)fprintf, not the adb prefixed ones defined in sysdeps.h, so they
+1 −0
Original line number Diff line number Diff line
@@ -464,6 +464,7 @@ void send_auth_response(const char* token, size_t token_size, atransport* t) {
    std::shared_ptr<RSA> key = t->NextKey();
    if (key == nullptr) {
        // No more private keys to try, send the public key.
        t->SetConnectionState(kCsUnauthorized);
        send_auth_publickey(t);
        return;
    }
+1 −1
Original line number Diff line number Diff line
@@ -750,7 +750,7 @@ static int smart_socket_enqueue(asocket* s, apacket::payload_type data) {
    if (!s->transport) {
        SendFail(s->peer->fd, "device offline (no transport)");
        goto fail;
    } else if (s->transport->GetConnectionState() == kCsOffline) {
    } else if (!ConnectionStateIsOnline(s->transport->GetConnectionState())) {
        /* if there's no remote we fail the connection
         ** right here and terminate it
         */
+39 −16
Original line number Diff line number Diff line
@@ -708,8 +708,22 @@ atransport* acquire_one_transport(TransportType type, const char* serial, Transp
    }
    lock.unlock();

    // Don't return unauthorized devices; the caller can't do anything with them.
    if (result && result->GetConnectionState() == kCsUnauthorized && !accept_any_state) {
    if (result && !accept_any_state) {
        // The caller requires an active transport.
        // Make sure that we're actually connected.
        ConnectionState state = result->GetConnectionState();
        switch (state) {
            case kCsConnecting:
                *error_out = "device still connecting";
                result = nullptr;
                break;

            case kCsAuthorizing:
                *error_out = "device still authorizing";
                result = nullptr;
                break;

            case kCsUnauthorized: {
                *error_out = "device unauthorized.\n";
                char* ADB_VENDOR_KEYS = getenv("ADB_VENDOR_KEYS");
                *error_out += "This adb server's $ADB_VENDOR_KEYS is ";
@@ -718,12 +732,17 @@ atransport* acquire_one_transport(TransportType type, const char* serial, Transp
                *error_out += "Try 'adb kill-server' if that seems wrong.\n";
                *error_out += "Otherwise check for a confirmation dialog on your device.";
                result = nullptr;
                break;
            }

    // Don't return offline devices; the caller can't do anything with them.
    if (result && result->GetConnectionState() == kCsOffline && !accept_any_state) {
            case kCsOffline:
                *error_out = "device offline";
                result = nullptr;
                break;

            default:
                break;
        }
    }

    if (result) {
@@ -802,6 +821,10 @@ std::string atransport::connection_state_name() const {
            return "sideload";
        case kCsUnauthorized:
            return "unauthorized";
        case kCsAuthorizing:
            return "authorizing";
        case kCsConnecting:
            return "connecting";
        default:
            return "unknown";
    }
@@ -1080,7 +1103,7 @@ void kick_all_tcp_devices() {

void register_usb_transport(usb_handle* usb, const char* serial, const char* devpath,
                            unsigned writeable) {
    atransport* t = new atransport((writeable ? kCsOffline : kCsNoPerm));
    atransport* t = new atransport((writeable ? kCsConnecting : kCsNoPerm));

    D("transport: %p init'ing for usb_handle %p (sn='%s')", t, usb, serial ? serial : "");
    init_usb_transport(t, usb);
Loading