Skip to main content
Version: next

Handshake and authenticate

Authenticate with device

Once a connection and a credential store is ready, use adbDaemonAuthenticate function to initiate the handshake and authenticate with the device.

type AdbDaemonConnection = ReadableWritablePair<
AdbPacketData,
Consumable<AdbPacketInit>
>;

interface AdbDaemonAuthenticateOptions {
/**
* The serial number of the device to connect to.
*/
serial: string;

/**
* The ADB daemon connection to use for communication.
*/
connection: AdbDaemonConnection;

/**
* The list of features to send to the device during handshake.
* @default AdbDeviceFeatures
*/
features?: readonly AdbFeature[];

/**
* The number of bytes the device can send before receiving an ack packet.
* Setting this to 0 or a negative number will disable Delayed Ack.
* @default ADB_DAEMON_DEFAULT_INITIAL_PAYLOAD_SIZE
*/
initialDelayedAckBytes?: number;

/**
* Whether to preserve the connection when the transport is closed.
* @default false
*/
preserveConnection?: boolean;

/**
* Time limit for reading from the connection, in milliseconds.
* @default undefined
*/
readTimeLimit?: number;
} & (
| AdbDaemonDefaultAuthProcessorInit // Shortcut to use default authentication processor with credential store
| { processor: AdbDaemonAuthProcessor } // Use a custom authentication processor
);

/**
* Authenticates an `AdbDaemonConnection` using an `AdbDaemonAuthProcessor`.
*/
declare function adbDaemonAuthenticate(
options: AdbDaemonAuthenticateOptions
): Promise<AdbDaemonTransport>;

serial

The serial field is not used by Tango, it helps you to identify the device associated with the transport. You can use any string to represent the device.

connection

A pair of ReadableStream<AdbPacketData> and WritableStream<Consumable<AdbPacketInit>> is used to send and receive ADB packets. You can use any stream implementation that conforms to the interface.

features

An optional list of AdbFeature to send to the device in handshake. ADB Features are flags that can be used to enable or disable certain features in the ADB protocol. The default value contains all features supported by Tango.

initialDelayedAckBytes

On Android 14 and newer, the Delayed Acknowledgement feature is added to improve performance, especially for high-latency connections like ADB over Wi-Fi. For more details on how this feature works internally, see Delayed Acknowledgment in ADB.

This optional field specifies The number of bytes the device can send before receiving an ack packet.

Setting this parameter to 0 or a negative number will disable Delayed Ack.

preserveConnection

When set to true, the transport will not close the connection when the close method is called.

This is useful when you want to reconnect to the device later without re-authenticating.

The default value is false.

info

If the authentication process fails, the connection will always be kept open, regardless of this option.

readTimeLimit

When set, the transport will throw an error when one of the socket readable stalls for this amount of milliseconds.

This option is helpful to detect bugs in the client code that causes child processes to hang or future commands not executed.

When set to undefined, the transport will not enforce a time limit.

The default value is undefined.

Authentication Options

The adbDaemonAuthenticate function requires exactly one of two authentication approaches, specified through mutually exclusive options:

  1. Pass credentialManager as part of AdbDaemonDefaultAuthProcessorInit, which creates a default authentication processor using the provided credential manager. This is the standard authentication flow for most use cases.
  2. Pass a custom processor option with your own implementation of AdbDaemonAuthProcessor. This allows for completely custom authentication logic.

AdbDaemonDefaultAuthProcessorInit

When using the default authentication flow, you can provide these options:

interface AdbDaemonDefaultAuthProcessorInit {
/**
* An AdbCredentialManager implementation to store and retrieve private keys.
* Used to provide authentication keys during the handshake.
*/
credentialManager: AdbCredentialManager;

/**
* An optional callback that gets invoked when a key fails to load from the credential manager.
*/
onKeyLoadError?: ((error: Error) => void) | undefined;

/**
* An optional callback that gets invoked when signature authentication is attempted with a key.
*/
onSignatureAuthentication?: ((key: AdbKeyInfo) => void) | undefined;

/**
* An optional callback that gets invoked when a signature is rejected by the device.
*/
onSignatureRejected?: ((key: AdbKeyInfo) => void) | undefined;

/**
* An optional callback that gets invoked when public key authentication is initiated.
*/
onPublicKeyAuthentication?: ((key: AdbKeyInfo) => void) | undefined;
}
info

These fields are passed directly into adbDaemonAuthenticate, not as a separate object. For example, { serial, connection, credentialManager, onKeyLoadError } instead of { serial, connection, authProcessor: { credentialManager, onKeyLoadError } }.

credentialManager

An AdbCredentialManager implementation is used to store and retrieve the private key. You can use any store that conforms to the interface.

Passing credentialManager is a shortcut that creates a default authentication processor internally. This is the common case for standard authentication flows.

onKeyLoadError

An optional callback that gets invoked when a key fails to load from the credential manager. This allows for handling errors during key iteration without stopping the entire authentication process.

onSignatureAuthentication

An optional callback that gets invoked when signature authentication is attempted with a key. Provides information about the key being used.

onSignatureRejected

An optional callback that gets invoked when a signature is rejected by the device. This indicates that the key hasn't been trusted by the user yet.

onPublicKeyAuthentication

An optional callback that gets invoked when public key authentication is initiated. This typically happens when the device doesn't trust any of the available keys.

Example

When using the default authentication flow with a credential manager:

import type { AdbPacketData, AdbPacketInit } from "@yume-chan/adb";
import type { Consumable, ReadableWritablePair } from "@yume-chan/stream-extra";
import { adbDaemonAuthenticate, AdbWebCryptoCredentialManager } from "@yume-chan/adb";
import { AdbDaemonWebUsbDevice } from "@yume-chan/adb-daemon-webusb";
import { TangoLocalStorage } from "@yume-chan/adb-credential-web";

declare const device: AdbDaemonWebUsbDevice;
declare const connection: ReadableWritablePair<AdbPacketData, Consumable<AdbPacketInit>>;
declare const CredentialManager: AdbWebCryptoCredentialManager;

const transport: AdbDaemonTransport = await adbDaemonAuthenticate({
serial: device.serial,
connection,
credentialManager: CredentialManager,
});

If the private key is not yet trusted by the device, a dialog will be shown on device screen to let users confirm the connection.

processor

A custom AdbDaemonAuthProcessor implementation to handle the authentication process. When provided, this overrides the default authentication processor that would be created from credentialManager.

Use this option when you need custom authentication logic that differs from the standard flow.

Example

When using a custom authentication processor:

import type { AdbPacketData, AdbPacketInit } from "@yume-chan/adb";
import type { Consumable, ReadableWritablePair } from "@yume-chan/stream-extra";
import { adbDaemonAuthenticate, AdbDaemonAuthProcessor } from "@yume-chan/adb";
import { AdbDaemonWebUsbDevice } from "@yume-chan/adb-daemon-webusb";

declare const device: AdbDaemonWebUsbDevice;
declare const connection: ReadableWritablePair<AdbPacketData, Consumable<AdbPacketInit>>;
declare const customAuthProcessor: AdbDaemonAuthProcessor;

const transport: AdbDaemonTransport = await adbDaemonAuthenticate({
serial: device.serial,
connection,
processor: customAuthProcessor,
});

This approach allows for completely custom authentication logic when the default flow is insufficient.

Create an Adb instance

The transport object only contains the lower-level logic to communicate with devices, the Adb class provides a higher-level abstraction over ADB protocol and ADB commands.

This step only initialize some internal states, but does not actually send any packets to the device.

import { Adb } from "@yume-chan/adb";

const adb: Adb = new Adb(transport);
Next Step

See API section for all supported ADB commands.