Establish a new connection to a device, connected via transport.

    Args:
      transport: A transport to use for reads/writes from/to the device,
        usually an instance of UsbHandle, but really it can be anything with
        read() and write() methods.
      rsa_keys: List of AuthSigner subclass instances to be used for
        authentication. The device can either accept one of these via the sign
        method, or we will send the result of get_public_key from the first one
        if the device doesn't accept any of them.
      timeout_ms: Timeout to wait for the device to respond to our CNXN
        request.  Actual timeout may take longer if the transport object passed
        has a longer default timeout than timeout_ms, or if auth_timeout_ms is
        longer than timeout_ms and public key auth is used.  This argument may
        be a PolledTimeout object.
      auth_timeout_ms: Timeout to wait for when sending a new public key. This
        is only relevant when we send a new public key. The device shows a
        dialog and this timeout is how long to wait for that dialog. If used
        in automation, this should be low to catch such a case as a failure
        quickly; while in interactive settings it should be high to allow
        users to accept the dialog. We default to automation here, so it's low
        by default.  This argument may be a PolledTimeout object.

    Returns:
      An instance of AdbConnection that is connected to the device.

    Raises:
      usb_exceptions.DeviceAuthError: When the device expects authentication,
        but we weren't given any valid keys.
      usb_exceptions.AdbProtocolError: When the device does authentication in an
        unexpected way, or fails to respond appropriately to our CNXN request.

def connect(cls, transport, rsa_keys=None, timeout_ms=1000,
              auth_timeout_ms=100):
    """Establish a new connection to a device, connected via transport.

    Args:
      transport: A transport to use for reads/writes from/to the device,
        usually an instance of UsbHandle, but really it can be anything with
        read() and write() methods.
      rsa_keys: List of AuthSigner subclass instances to be used for
        authentication. The device can either accept one of these via the sign
        method, or we will send the result of get_public_key from the first one
        if the device doesn't accept any of them.
      timeout_ms: Timeout to wait for the device to respond to our CNXN
        request.  Actual timeout may take longer if the transport object passed
        has a longer default timeout than timeout_ms, or if auth_timeout_ms is
        longer than timeout_ms and public key auth is used.  This argument may
        be a PolledTimeout object.
      auth_timeout_ms: Timeout to wait for when sending a new public key. This
        is only relevant when we send a new public key. The device shows a
        dialog and this timeout is how long to wait for that dialog. If used
        in automation, this should be low to catch such a case as a failure
        quickly; while in interactive settings it should be high to allow
        users to accept the dialog. We default to automation here, so it's low
        by default.  This argument may be a PolledTimeout object.

    Returns:
      An instance of AdbConnection that is connected to the device.

    Raises:
      usb_exceptions.DeviceAuthError: When the device expects authentication,
        but we weren't given any valid keys.
      usb_exceptions.AdbProtocolError: When the device does authentication in an
        unexpected way, or fails to respond appropriately to our CNXN request.
    """
    timeout = timeouts.PolledTimeout.from_millis(timeout_ms)
    if ADB_MESSAGE_LOG:
      adb_transport = adb_message.DebugAdbTransportAdapter(transport)
    else:
      adb_transport = adb_message.AdbTransportAdapter(transport)
    adb_transport.write_message(
        adb_message.AdbMessage(
            command='CNXN', arg0=ADB_VERSION, arg1=MAX_ADB_DATA,
            data='host::%s\0' % ADB_BANNER),
        timeout)

    msg = adb_transport.read_until(('AUTH', 'CNXN'), timeout)
    if msg.command == 'CNXN':
      return cls(adb_transport, msg.arg1, msg.data)

    # We got an AUTH response, so we have to try to authenticate.
    if not rsa_keys:
      raise usb_exceptions.DeviceAuthError(
          'Device authentication required, no keys available.')

    # Loop through our keys, signing the last 'banner' or token.
    for rsa_key in rsa_keys:
      if msg.arg0 != cls.AUTH_TOKEN:
        raise usb_exceptions.AdbProtocolError('Bad AUTH response: %s', msg)

      signed_token = rsa_key.sign(msg.data)
      adb_transport.write_message(
          adb_message.AdbMessage(
              command='AUTH', arg0=cls.AUTH_SIGNATURE, arg1=0,
              data=signed_token),
          timeout)

      msg = adb_transport.read_until(('AUTH', 'CNXN'), timeout)
      if msg.command == 'CNXN':
        return cls(adb_transport, msg.arg1, msg.data)

    # None of the keys worked, so send a public key.
    adb_transport.write_message(
        adb_message.AdbMessage(
            command='AUTH', arg0=cls.AUTH_RSAPUBLICKEY, arg1=0,
            data=rsa_keys[0].get_public_key() + '\0'),
        timeout)
    try:
      msg = adb_transport.read_until(
          ('CNXN',), timeouts.PolledTimeout.from_millis(auth_timeout_ms))
    except usb_exceptions.UsbReadFailedError as exception:
      if exception.is_timeout():
        exceptions.reraise(usb_exceptions.DeviceAuthError,
                           'Accept auth key on device, then retry.')
      raise

    # The read didn't time-out, so we got a CNXN response.
    return cls(adb_transport, msg.arg1, msg.data)