Skip to content

Commit

Permalink
feat(adb): allow killing subprocess using an AbortSignal
Browse files Browse the repository at this point in the history
  • Loading branch information
yume-chan committed Feb 22, 2025
1 parent 029d72e commit 0af5280
Show file tree
Hide file tree
Showing 6 changed files with 35 additions and 16 deletions.
10 changes: 6 additions & 4 deletions libraries/adb/src/commands/subprocess/command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,13 @@ export interface AdbSubprocessOptions {
* @default [AdbSubprocessShellProtocol, AdbSubprocessNoneProtocol]
*/
protocols: AdbSubprocessProtocolConstructor[];

signal?: AbortSignal;
}

const DEFAULT_OPTIONS: AdbSubprocessOptions = {
const DEFAULT_OPTIONS = {
protocols: [AdbSubprocessShellProtocol, AdbSubprocessNoneProtocol],
};
} satisfies AdbSubprocessOptions;

export interface AdbSubprocessWaitResult {
stdout: string;
Expand All @@ -42,7 +44,7 @@ export class AdbSubprocess extends AdbCommandBase {
command?: string | string[],
options?: Partial<AdbSubprocessOptions>,
): Promise<AdbSubprocessProtocol> {
const { protocols } = { ...DEFAULT_OPTIONS, ...options };
const { protocols, signal } = { ...DEFAULT_OPTIONS, ...options };

let Constructor: AdbSubprocessProtocolConstructor | undefined;
for (const item of protocols) {
Expand All @@ -63,7 +65,7 @@ export class AdbSubprocess extends AdbCommandBase {
// spawn the default shell
command = "";
}
return await Constructor[mode](this.adb, command);
return await Constructor[mode](this.adb, command, signal);
}

/**
Expand Down
11 changes: 8 additions & 3 deletions libraries/adb/src/commands/subprocess/protocols/none.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,19 @@ export class AdbSubprocessNoneProtocol implements AdbSubprocessProtocol {
return true;
}

static async pty(adb: Adb, command: string) {
static async pty(adb: Adb, command: string, signal?: AbortSignal) {
return new AdbSubprocessNoneProtocol(
await adb.createSocket(`shell:${command}`),
signal,
);
}

static async raw(adb: Adb, command: string) {
static async raw(adb: Adb, command: string, signal?: AbortSignal) {
// `shell,raw:${command}` also triggers raw mode,
// But is not supported on Android version <7.
return new AdbSubprocessNoneProtocol(
await adb.createSocket(`exec:${command}`),
signal,
);
}

Expand Down Expand Up @@ -59,8 +61,11 @@ export class AdbSubprocessNoneProtocol implements AdbSubprocessProtocol {
return this.#exit;
}

constructor(socket: AdbSocket) {
constructor(socket: AdbSocket, signal?: AbortSignal) {
signal?.throwIfAborted();

this.#socket = socket;
signal?.addEventListener("abort", () => void this.kill());

this.#stderr = new ReadableStream({
start: async (controller) => {
Expand Down
11 changes: 8 additions & 3 deletions libraries/adb/src/commands/subprocess/protocols/shell.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,16 +55,18 @@ export class AdbSubprocessShellProtocol implements AdbSubprocessProtocol {
return adb.canUseFeature(AdbFeature.ShellV2);
}

static async pty(adb: Adb, command: string) {
static async pty(adb: Adb, command: string, signal?: AbortSignal) {
// TODO: AdbShellSubprocessProtocol: Support setting `XTERM` environment variable
return new AdbSubprocessShellProtocol(
await adb.createSocket(`shell,v2,pty:${command}`),
signal,
);
}

static async raw(adb: Adb, command: string) {
static async raw(adb: Adb, command: string, signal?: AbortSignal) {
return new AdbSubprocessShellProtocol(
await adb.createSocket(`shell,v2,raw:${command}`),
signal,
);
}

Expand All @@ -91,8 +93,11 @@ export class AdbSubprocessShellProtocol implements AdbSubprocessProtocol {
return this.#exit.promise;
}

constructor(socket: AdbSocket) {
constructor(socket: AdbSocket, signal?: AbortSignal) {
signal?.throwIfAborted();

this.#socket = socket;
signal?.addEventListener("abort", () => void this.kill());

let stdoutController!: PushReadableStreamController<Uint8Array>;
let stderrController!: PushReadableStreamController<Uint8Array>;
Expand Down
12 changes: 10 additions & 2 deletions libraries/adb/src/commands/subprocess/protocols/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,18 @@ export interface AdbSubprocessProtocolConstructor {
isSupported(adb: Adb): MaybePromiseLike<boolean>;

/** Spawns an executable in PTY (interactive) mode. */
pty(adb: Adb, command: string): MaybePromiseLike<AdbSubprocessProtocol>;
pty: (
adb: Adb,
command: string,
signal?: AbortSignal,
) => MaybePromiseLike<AdbSubprocessProtocol>;

/** Spawns an executable and pipe the output. */
raw(adb: Adb, command: string): MaybePromiseLike<AdbSubprocessProtocol>;
raw(
adb: Adb,
command: string,
signal?: AbortSignal,
): MaybePromiseLike<AdbSubprocessProtocol>;

/** Creates a new `AdbShell` by attaching to an exist `AdbSocket` */
new (socket: AdbSocket): AdbSubprocessProtocol;
Expand Down
2 changes: 0 additions & 2 deletions libraries/android-bin/src/logcat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,13 +80,11 @@ export type LogcatFormat = (typeof LogcatFormat)[keyof typeof LogcatFormat];
export interface LogcatFormatModifiers {
microseconds?: boolean;
nanoseconds?: boolean;
printable?: boolean;
year?: boolean;
timezone?: boolean;
epoch?: boolean;
monotonic?: boolean;
uid?: boolean;
descriptive?: boolean;
}

export interface LogcatOptions {
Expand Down
5 changes: 3 additions & 2 deletions libraries/scrcpy/src/android/key-event.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,9 @@ export type AndroidKeyEventMeta =
(typeof AndroidKeyEventMeta)[keyof typeof AndroidKeyEventMeta];

// https://cs.android.com/android/platform/superproject/+/master:frameworks/base/core/java/android/view/KeyEvent.java;l=97;drc=95c1165bb895dd844e1793460710f7163dd330a3
// Most names follow Web API `KeyboardEvent.code`,
// Android-only (not exist in HID keyboard standard) keys are prefixed by `Android`.
// Android key code to Chrome key code: https://source.chromium.org/chromium/chromium/src/+/main:ui/events/keycodes/keyboard_code_conversion_android.cc
// Chrome key code to DOM key code: https://source.chromium.org/chromium/chromium/src/+/main:ui/events/keycodes/dom/dom_code_data.inc
// Some keys are not mapped to `KeyboardEvent.code`, only to `KeyboardEvent.key`: https://source.chromium.org/chromium/chromium/src/+/main:ui/events/keycodes/dom/dom_key_data.inc
export const AndroidKeyCode = {
AndroidHome: 3,
AndroidBack: 4,
Expand Down

0 comments on commit 0af5280

Please sign in to comment.