UNPKG

promise-android-tools

Version:

A wrapper for adb, fastboot, and heimdall that returns convenient promises.

435 lines (426 loc) 17.5 kB
import { ExecException, ChildProcess } from 'node:child_process'; import { Writable, Readable } from 'node:stream'; import { EventEmitter } from 'node:events'; declare class HierarchicalAbortController { controller: AbortController; signal: AbortSignal; constructor(...abortSignals: AbortSignal[]); abort(): void; listen(...abortSignals: AbortSignal[]): void; } /** HACK upstream definitions are incomplete */ declare var AbortSignal$1: { prototype: AbortSignal$1; new (): AbortSignal$1; timeout(msecs: number): AbortSignal$1; abort(): AbortSignal$1; }; interface Interface extends EventEmitter, HierarchicalAbortController { on(eventName: "exec", listener: (e: { cmd: string[]; error?: Error; stdout?: string; stderr?: string; }) => void): this; on(eventName: "spawn:start", listener: (e: { cmd: string[]; }) => void): this; on(eventName: "spawn:exit", listener: (e: { cmd: string[]; error?: Error; }) => void): this; on(eventName: "spawn:error", listener: (e: { cmd: string[]; error: Error; }) => void): this; } declare class Interface extends HierarchicalAbortController { this: Interface; /** returns clone listening to additional AbortSignals */ _withSignals(...signals: AbortSignal$1[]): this; /** returns clone that will time out after the spelistening to an additional timeout abortSignal */ _withTimeout(msecs?: number): this; /** * returns clone with variation in env vars * @virtual */ protected _withEnv?(env: NodeJS.ProcessEnv): this; /** * Find out if a device can be seen * @virtual */ protected hasAccess(): Promise<boolean>; /** * Wait for a device * @virtual */ protected wait?(): Promise<string | any>; /** * Resolve device name * @virtual */ protected getDeviceName?(): Promise<string>; } type Mutable<T> = { -readonly [P in keyof T]: T[P]; }; type ProgressCallback = (percentage: number) => void; /** executable in PATH or path to an executable */ type ToolString = "adb" | "fastboot" | "heimdall" | string; interface ToolOptions { tool: ToolString; /** error class */ Error: typeof ToolError; /** extra cli args */ extraArgs?: string[]; /** extra environment variables */ extraEnv?: NodeJS.ProcessEnv; /** set PATH environment variable */ setPath?: boolean; /** tool configuration */ config?: ToolConfig; /** object describing arguments */ argsModel?: ArgsModel; /** signals to listen to */ signals?: AbortSignal[]; /** additional properties */ [propName: string]: any; } /** tool configuration */ interface ToolConfig { [propName: string]: any; } type Arg = [string, any?, any?, string?]; /** object describing arguments */ interface ArgsModel { [propName: string]: Arg; } type RawError = Partial<ExecException & Mutable<DOMException | Error>>; type ToolErrorMessage = "aborted" | "no device" | "more than one device" | "unauthorized" | "device offline" | "bootloader locked" | "enable unlocking" | "low battery" | "failed to boot"; interface ToolError extends Error, Partial<DOMException> { } declare class ToolError extends Error implements ExecException, ToolError { get message(): ToolErrorMessage | string; get name(): string; cause?: RawError; stdout?: string; stderr?: string; get cmd(): string | undefined; get killed(): boolean; constructor( /** error returned by exec() */ error?: RawError, /** standard output */ stdout?: string, /** standard error */ stderr?: string); } /** * generic tool class */ declare abstract class Tool extends Interface { #private; /** bundled tool, executable in PATH, or path to an executable */ tool: ToolString; /** path to a bundled executable if it has been resolved in bundle */ executable: ToolString | string; /** error class */ Error: typeof ToolError; /** extra cli args */ extraArgs: string[]; /** extra environment variables */ extraEnv: NodeJS.ProcessEnv; /** tool configuration */ abstract config: ToolConfig; /** object describing arguments */ protected argsModel: ArgsModel; /** environment variables */ get env(): NodeJS.ProcessEnv; /** cli arguments */ get args(): string[]; constructor({ tool, Error, signals, extraArgs, extraEnv, setPath, config, argsModel, ...options }: ToolOptions); /** return a clone with a specified variation in the config options */ _withConfig(config: ToolConfig): this; /** returns clone with variation in env vars */ _withEnv(env: NodeJS.ProcessEnv): this; /** helper functions */ [key: `__${keyof typeof this.argsModel}`]: (val?: any) => this; /** apply config options to the tool instance */ applyConfig(config: ToolConfig): void; /** filter nullish and empty-string arguments */ constructArgs(args: any[]): string[]; /** Execute a command. Used for quick operations that do not require real-time data access. Output is trimmed. */ exec(...args: (string | number | null | undefined)[]): Promise<string>; /** Spawn a child process. Used for long-running operations that require real-time data access. */ spawn(...args: (string | number | null | undefined)[]): ChildProcess & { stdin: Writable; stdout: Readable; stderr: Readable; }; /** Parse and simplify errors */ protected error(error: RawError, stdout?: string, stderr?: string): RawError; /** Wait for a device */ wait(): Promise<string | any>; } interface UbuntuBackupMetadata { codename: string; comment: string; dir: string; serialno: string | number; size: string | number; time: string; restorations?: { codename: string; serialno: string; time: string; }[]; } interface AdbConfig { /** -a listen on all network interfaces, not just localhost */ allInterfaces: boolean; /** -d use USB device (error if multiple devices connected) */ useUsb: boolean; /** -e use TCP/IP device (error if multiple TCP/IP devices available) */ useTcpIp: boolean; /** -s SERIAL use device with given serial (overrides $ANDROID_SERIAL) */ serialno?: string; /** -t ID use device with given transport id */ transportId?: string; /** -H name of adb server host [default=localhost] */ host: string | "localhost"; /** -P port of adb server [default=5037] */ port: string | number | 5037; /** transport-level protocol */ protocol: "tcp" | "udp"; /** -L SOCKET listen on given socket for adb server [default=tcp:localhost:5037] */ socket: string | "tcp:localhost:5037"; /** --exit-on-write-error exit if stdout is closed */ exitOnWriteError: boolean; } type AdbOptions = AdbConfig | ToolOptions | {}; type DeviceState = "device" | "recovery" | "bootloader"; type ActualDeviceState = DeviceState | "offline"; type RebootState = DeviceState | "download" | "edl" | "sideload" | "sideload-auto-reboot"; type WaitState = "any" | DeviceState | "rescue" | "sideload" | "disconnect"; interface Device { serialno: string; mode: string; transport_id: string | number; model?: string; device?: string; product?: string; } declare class AdbError extends ToolError { get message(): string; } /** Android Debug Bridge (ADB) module */ declare class Adb extends Tool { config: AdbConfig; constructor(options?: AdbOptions); /** Kill all adb servers and start a new one to rule them all */ startServer( /** new config options to apply */ options?: AdbOptions, /** applies the --one-device SERIAL|USB flag, server will only connect to one USB device, specified by a serial number or USB device address */ serialOrUsbId?: string | number): Promise<void>; /** Kill all running servers */ killServer(): Promise<void>; /** Specifically connect to a device (tcp) */ connect(address: string): Promise<ActualDeviceState>; /** kick connection from host side to force reconnect */ reconnect(modifier?: "device" | "offline"): Promise<ActualDeviceState>; /** kick connection from device side to force reconnect */ reconnectDevice(): Promise<string>; /** reset offline/unauthorized devices to force reconnect */ reconnectOffline(): Promise<string>; /** list devices */ devices(): Promise<Device[]>; /** Get the devices serial number */ getSerialno(): Promise<string>; /** run remote shell command and resolve stdout */ shell(...args: (string | number)[]): Promise<string>; /** determine child_process.spawn() result */ private onCpExit; /** extract chunk size from logging */ private parseChunkSize; /** calculate progress from current/total */ private normalizeProgress; private spawnFileTransfer; /** copy local files/directories to device */ push(files: string[] | undefined, dest: string, progress?: ProgressCallback): Promise<void>; /** sideload an ota package */ sideload(file: string, progress?: ProgressCallback): Promise<void>; /** * Reboot to a state * reboot the device; defaults to booting system image but * supports bootloader and recovery too. sideload reboots * into recovery and automatically starts sideload mode, * sideload-auto-reboot is the same but reboots after sideloading. */ reboot(state?: RebootState): Promise<void>; /** Return the status of the device */ getState(): Promise<ActualDeviceState>; /** Reboot to a requested state, if not already in it */ ensureState(state: DeviceState): Promise<ActualDeviceState>; /** read property from getprop or, failing that, the default.prop file */ getprop(prop: string): Promise<string>; /** get device codename from getprop or by reading the default.prop file */ getDeviceName(): Promise<string>; /** resolves true if recovery is system-image capable, false otherwise */ getSystemImageCapability(): Promise<boolean>; /** Find out what operating system the device is running (currently android and ubuntu touch) */ getOs(): Promise<"ubuntutouch" | "android">; /** Find out if a device can be seen by adb */ hasAccess(): Promise<boolean>; /** wait for a device, optionally limiting to specific states or transport types */ wait(state?: WaitState, transport?: "any" | "usb" | "local"): Promise<ActualDeviceState>; /** Format partition */ format(partition: string): Promise<void>; /** Format cache if possible and rm -rf its contents */ wipeCache(): Promise<void>; /** Find the partition associated with a mountpoint in an fstab */ private findPartitionInFstab; /** Find a partition and verify its type */ verifyPartitionType(partition: string, type: string): Promise<boolean>; /** size of a file or directory */ getFileSize(file: string): Promise<number>; /** available size of a partition */ getAvailablePartitionSize(partition: string): Promise<number>; /** total size of a partition */ getTotalPartitionSize(partition: string): Promise<number>; } interface FastbootFlashImage { /** partition to flash */ partition: string; /** path to an image file */ file: string; /** use `fastboot flash:raw` instead of `fastboot flash` */ raw?: boolean; /** additional cli-flags like --force and --disable-verification */ flags?: string[]; } interface FastbootConfig { wipe: boolean; device?: string | number; maxSize?: string; force: boolean; slot?: "all" | "current" | "other"; skipSecondary: boolean; skipReboot: boolean; disableVerity: boolean; disableVerification: boolean; fsOptions?: string; unbuffered: boolean; } type FastbootOptions = ToolOptions | FastbootConfig | {}; declare class FastbootError extends ToolError { get message(): string; } /** fastboot android flashing and booting utility */ declare class Fastboot extends Tool { config: FastbootConfig; constructor(options?: FastbootOptions); /** Write a file to a flash partition */ flash(images: FastbootFlashImage[], progress?: ProgressCallback): Promise<void>; /** Download and boot kernel */ boot(image: string): Promise<void>; /** Reflash device from update.zip and set the flashed slot as active */ update(image: string, wipe?: string | boolean): Promise<void>; /** Reboot device into bootloader */ rebootBootloader(): Promise<void>; /** * Reboot device into userspace fastboot (fastbootd) mode * Note: this only works on devices that support dynamic partitions. */ rebootFastboot(): Promise<void>; /** Reboot device into recovery */ rebootRecovery(): Promise<void>; /** Reboot device */ reboot(): Promise<void>; /** Continue with autoboot */ continue(): Promise<void>; /** Format a flash partition. Can override the fs type and/or size the bootloader reports */ format(partition: string, type?: string, size?: string | number): Promise<void>; /** Erase a flash partition */ erase(partition: string): Promise<void>; /** Sets the active slot */ setActive(slot: string): Promise<void>; /** Create a logical partition with the given name and size, in the super partition */ createLogicalPartition(partition: string, size: string | number): Promise<void>; /** Resize a logical partition with the given name and final size, in the super partition */ resizeLogicalPartition(partition: string, size: string | number): Promise<void>; /** Delete a logical partition with the given name */ deleteLogicalPartition(partition: string): Promise<void>; /** Wipe the super partition and reset the partition layout */ wipeSuper(image: string): Promise<void>; /** Lift OEM lock */ oemUnlock( /** optional unlock code (including 0x if necessary) */ code?: string | number): Promise<void>; /** Enforce OEM lock */ oemLock(): Promise<void>; /** unlock partitions for flashing */ flashingUnlock(): Promise<void>; /** lock partitions for flashing */ flashingLock(): Promise<void>; /** unlock 'critical' bootloader partitions */ flashingUnlockCritical(): Promise<void>; /** lock 'critical' bootloader partitions */ flashingLockCritical(): Promise<void>; /** Find out if a device can be flashing-unlocked */ getUnlockAbility(): Promise<boolean>; /** Find out if a device can be seen by fastboot */ hasAccess(): Promise<boolean>; /** wait for a device */ wait(): Promise<"bootloader">; /** get bootloader var */ getvar(variable: string): Promise<string>; /** get device codename from product bootloader var */ getDeviceName(): Promise<string>; } type HeimdallOptions = ToolOptions | {}; interface HeimdallConfig { } declare class HeimdallError extends ToolError { get message(): string; } /** heimdall: flash firmware on samsung devices */ declare class Heimdall extends Tool { config: HeimdallConfig; constructor(options?: HeimdallOptions); /** Find out if a device in download mode can be seen by heimdall */ detect(): Promise<boolean>; /** Find out if a device in download mode can be seen by heimdall */ hasAccess(): Promise<boolean>; /** Wait for a device */ wait(): Promise<"download">; /** Prints the contents of a PIT file in a human readable format. If a filename is not provided then Heimdall retrieves the PIT file from the connected device. */ printPit(file?: string): Promise<string[]>; /** get partitions from pit file */ getPartitions(): Promise<{}[]>; /** Flash firmware files to partitions (names or identifiers) */ flash(images: { partition: string; file: string; }[]): Promise<void>; } interface DeviceToolsOptions { adbOptions?: AdbOptions; fastbootOptions?: FastbootOptions; heimdallOptions?: HeimdallOptions; signals?: AbortSignal[]; } /** A wrapper for Adb, Fastboot, and Heimall that returns convenient promises. */ declare class DeviceTools extends Interface { adb: Adb; fastboot: Fastboot; heimdall: Heimdall; constructor({ adbOptions, fastbootOptions, heimdallOptions, signals }: DeviceToolsOptions); /** returns clone with variation in env vars */ _withEnv(env: NodeJS.ProcessEnv): this; /** Wait for a device */ wait(): Promise<ActualDeviceState | "bootloader" | "download">; /** Resolve device name */ getDeviceName(): Promise<string>; } export { AbortSignal$1 as AbortSignal, type ActualDeviceState, Adb, type AdbConfig, AdbError, type AdbOptions, type Arg, type ArgsModel, type Device, type DeviceState, DeviceTools, type DeviceToolsOptions, Fastboot, type FastbootConfig, FastbootError, type FastbootFlashImage, type FastbootOptions, Heimdall, type HeimdallConfig, HeimdallError, type HeimdallOptions, HierarchicalAbortController, Interface, type Mutable, type ProgressCallback, type RawError, type RebootState, Tool, type ToolConfig, ToolError, type ToolErrorMessage, type ToolOptions, type ToolString, type UbuntuBackupMetadata, type WaitState };