@yume-chan/android-bin 0.0.24 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/bug-report.ts CHANGED
@@ -32,15 +32,15 @@ export interface BugReportZOptions {
32
32
  }
33
33
 
34
34
  export class BugReport extends AdbCommandBase {
35
- static VERSION_REGEX = /(\d+)\.(\d+)/;
35
+ static VERSION_REGEX: RegExp = /(\d+)\.(\d+)/;
36
36
 
37
- static BEGIN_REGEX = /BEGIN:(.*)/;
37
+ static BEGIN_REGEX: RegExp = /BEGIN:(.*)/;
38
38
 
39
- static PROGRESS_REGEX = /PROGRESS:(.*)\/(.*)/;
39
+ static PROGRESS_REGEX: RegExp = /PROGRESS:(.*)\/(.*)/;
40
40
 
41
- static OK_REGEX = /OK:(.*)/;
41
+ static OK_REGEX: RegExp = /OK:(.*)/;
42
42
 
43
- static FAIL_REGEX = /FAIL:(.*)/;
43
+ static FAIL_REGEX: RegExp = /FAIL:(.*)/;
44
44
 
45
45
  /**
46
46
  * Queries the device's bugreport capabilities.
@@ -101,7 +101,7 @@ export class BugReport extends AdbCommandBase {
101
101
  *
102
102
  * Should be `true` for Android version <= 11.
103
103
  */
104
- get supportsBugReport() {
104
+ get supportsBugReport(): boolean {
105
105
  return this.#supportsBugReport;
106
106
  }
107
107
 
@@ -111,7 +111,7 @@ export class BugReport extends AdbCommandBase {
111
111
  *
112
112
  * Will be `undefined` if BugReportZ is not supported.
113
113
  */
114
- get bugReportZVersion() {
114
+ get bugReportZVersion(): string | undefined {
115
115
  return this.#bugReportZVersion;
116
116
  }
117
117
 
@@ -121,7 +121,7 @@ export class BugReport extends AdbCommandBase {
121
121
  *
122
122
  * Should be `true` for Android version >= 7.
123
123
  */
124
- get supportsBugReportZ() {
124
+ get supportsBugReportZ(): boolean {
125
125
  return this.#supportsBugReportZ;
126
126
  }
127
127
 
@@ -131,7 +131,7 @@ export class BugReport extends AdbCommandBase {
131
131
  *
132
132
  * Should be `true` for Android version >= 8.
133
133
  */
134
- get supportsBugReportZProgress() {
134
+ get supportsBugReportZProgress(): boolean {
135
135
  return this.#supportsBugReportZProgress;
136
136
  }
137
137
 
@@ -141,7 +141,7 @@ export class BugReport extends AdbCommandBase {
141
141
  *
142
142
  * Should be `true` for Android version >= 12.
143
143
  */
144
- get supportsBugReportZStream() {
144
+ get supportsBugReportZStream(): boolean {
145
145
  return this.#supportsBugReportZStream;
146
146
  }
147
147
 
@@ -185,7 +185,7 @@ export class BugReport extends AdbCommandBase {
185
185
  */
186
186
  async bugReportZ(options?: BugReportZOptions): Promise<string> {
187
187
  if (options?.signal?.aborted) {
188
- throw options?.signal.reason ?? new Error("Aborted");
188
+ throw options?.signal.reason as Error;
189
189
  }
190
190
 
191
191
  if (!this.#supportsBugReportZ) {
@@ -211,37 +211,33 @@ export class BugReport extends AdbCommandBase {
211
211
  let filename: string | undefined;
212
212
  let error: string | undefined;
213
213
 
214
- await process.stdout
214
+ for await (const line of process.stdout
215
215
  .pipeThrough(new TextDecoderStream())
216
- .pipeThrough(new SplitStringStream("\n"))
217
- .pipeTo(
218
- new WritableStream<string>({
219
- write(line) {
220
- // `BEGIN:` and `PROGRESS:` only appear when `-p` is specified.
221
- let match = line.match(BugReport.PROGRESS_REGEX);
222
- if (match) {
223
- options?.onProgress?.(match[1]!, match[2]!);
224
- }
225
-
226
- match = line.match(BugReport.BEGIN_REGEX);
227
- if (match) {
228
- filename = match[1]!;
229
- }
230
-
231
- match = line.match(BugReport.OK_REGEX);
232
- if (match) {
233
- filename = match[1];
234
- }
235
-
236
- match = line.match(BugReport.FAIL_REGEX);
237
- if (match) {
238
- // Don't report error now
239
- // We want to gather all output.
240
- error = match[1];
241
- }
242
- },
243
- }),
244
- );
216
+ // Each chunk should contain one or several full lines
217
+ .pipeThrough(new SplitStringStream("\n"))) {
218
+ // `BEGIN:` and `PROGRESS:` only appear when `-p` is specified.
219
+ let match = line.match(BugReport.PROGRESS_REGEX);
220
+ if (match) {
221
+ options?.onProgress?.(match[1]!, match[2]!);
222
+ }
223
+
224
+ match = line.match(BugReport.BEGIN_REGEX);
225
+ if (match) {
226
+ filename = match[1]!;
227
+ }
228
+
229
+ match = line.match(BugReport.OK_REGEX);
230
+ if (match) {
231
+ filename = match[1];
232
+ }
233
+
234
+ match = line.match(BugReport.FAIL_REGEX);
235
+ if (match) {
236
+ // Don't report error now
237
+ // We want to gather all output.
238
+ error = match[1];
239
+ }
240
+ }
245
241
 
246
242
  if (error) {
247
243
  throw new Error(error);
package/src/cmd.ts CHANGED
@@ -14,22 +14,22 @@ import { ConcatStringStream, TextDecoderStream } from "@yume-chan/stream-extra";
14
14
 
15
15
  export class Cmd extends AdbCommandBase {
16
16
  #supportsShellV2: boolean;
17
- get supportsShellV2() {
17
+ get supportsShellV2(): boolean {
18
18
  return this.#supportsShellV2;
19
19
  }
20
20
 
21
21
  #supportsCmd: boolean;
22
- get supportsCmd() {
22
+ get supportsCmd(): boolean {
23
23
  return this.#supportsCmd;
24
24
  }
25
25
 
26
26
  #supportsAbb: boolean;
27
- get supportsAbb() {
27
+ get supportsAbb(): boolean {
28
28
  return this.#supportsAbb;
29
29
  }
30
30
 
31
31
  #supportsAbbExec: boolean;
32
- get supportsAbbExec() {
32
+ get supportsAbbExec(): boolean {
33
33
  return this.#supportsAbbExec;
34
34
  }
35
35
 
package/src/dumpsys.ts CHANGED
@@ -31,7 +31,32 @@ const BatteryDumpFields: Record<
31
31
  current: { type: "number", field: "current" },
32
32
  };
33
33
 
34
+ const Status = {
35
+ Unknown: 1,
36
+ Charging: 2,
37
+ Discharging: 3,
38
+ NotCharging: 4,
39
+ Full: 5,
40
+ } as const;
41
+
42
+ const Health = {
43
+ Unknown: 1,
44
+ Good: 2,
45
+ Overheat: 3,
46
+ Dead: 4,
47
+ OverVoltage: 5,
48
+ UnspecifiedFailure: 6,
49
+ Cold: 7,
50
+ } as const;
51
+
52
+ const Battery = {
53
+ Status,
54
+ Health,
55
+ };
56
+
34
57
  export class DumpSys extends AdbCommandBase {
58
+ static readonly Battery = Battery;
59
+
35
60
  async diskStats() {
36
61
  const output = await this.adb.subprocess.spawnAndWaitLegacy([
37
62
  "dumpsys",
@@ -65,7 +90,7 @@ export class DumpSys extends AdbCommandBase {
65
90
  };
66
91
  }
67
92
 
68
- async battery() {
93
+ async battery(): Promise<DumpSys.Battery.Info> {
69
94
  const output = await this.adb.subprocess.spawnAndWaitLegacy([
70
95
  "dumpsys",
71
96
  "battery",
@@ -113,6 +138,9 @@ export class DumpSys extends AdbCommandBase {
113
138
 
114
139
  export namespace DumpSys {
115
140
  export namespace Battery {
141
+ export type Status = (typeof Status)[keyof typeof Status];
142
+ export type Health = (typeof Health)[keyof typeof Health];
143
+
116
144
  export interface Info {
117
145
  acPowered: boolean;
118
146
  usbPowered: boolean;
@@ -131,23 +159,5 @@ export namespace DumpSys {
131
159
  technology?: string;
132
160
  current?: number;
133
161
  }
134
-
135
- export enum Status {
136
- Unknown = 1,
137
- Charging,
138
- Discharging,
139
- NotCharging,
140
- Full,
141
- }
142
-
143
- export enum Health {
144
- Unknown = 1,
145
- Good,
146
- Overheat,
147
- Dead,
148
- OverVoltage,
149
- UnspecifiedFailure,
150
- Cold,
151
- }
152
162
  }
153
163
  }
package/src/intent.ts CHANGED
@@ -5,6 +5,7 @@ export class IntentBuilder {
5
5
  #component: string | undefined;
6
6
  #data: string | undefined;
7
7
  #type: string | undefined;
8
+ #stringExtras = new Map<string, string>();
8
9
 
9
10
  setAction(action: string): this {
10
11
  this.#action = action;
@@ -31,6 +32,11 @@ export class IntentBuilder {
31
32
  return this;
32
33
  }
33
34
 
35
+ addStringExtra(key: string, value: string): this {
36
+ this.#stringExtras.set(key, value);
37
+ return this;
38
+ }
39
+
34
40
  build(): string[] {
35
41
  const result: string[] = [];
36
42
 
@@ -58,6 +64,10 @@ export class IntentBuilder {
58
64
  result.push("-t", this.#type);
59
65
  }
60
66
 
67
+ for (const [key, value] of this.#stringExtras) {
68
+ result.push("--es", key, value);
69
+ }
70
+
61
71
  return result;
62
72
  }
63
73
  }
package/src/logcat.ts CHANGED
@@ -8,39 +8,47 @@ import {
8
8
  SplitStringStream,
9
9
  TextDecoderStream,
10
10
  WrapReadableStream,
11
- WritableStream,
12
11
  } from "@yume-chan/stream-extra";
13
- import type { AsyncExactReadable } from "@yume-chan/struct";
14
- import Struct, { decodeUtf8 } from "@yume-chan/struct";
12
+ import type { AsyncExactReadable, StructValue } from "@yume-chan/struct";
13
+ import { decodeUtf8, struct, u16, u32 } from "@yume-chan/struct";
15
14
 
16
15
  // `adb logcat` is an alias to `adb shell logcat`
17
16
  // so instead of adding to core library, it's implemented here
18
17
 
19
18
  // https://cs.android.com/android/platform/superproject/+/master:system/logging/liblog/include/android/log.h;l=141;drc=82b5738732161dbaafb2e2f25cce19cd26b9157d
20
- export enum LogId {
21
- All = -1,
22
- Main,
23
- Radio,
24
- Events,
25
- System,
26
- Crash,
27
- Stats,
28
- Security,
29
- Kernel,
30
- }
19
+ export const LogId = {
20
+ All: -1,
21
+ Main: 0,
22
+ Radio: 1,
23
+ Events: 2,
24
+ System: 3,
25
+ Crash: 4,
26
+ Stats: 5,
27
+ Security: 6,
28
+ Kernel: 7,
29
+ } as const;
30
+
31
+ export type LogId = (typeof LogId)[keyof typeof LogId];
32
+
33
+ const LogIdName =
34
+ /* #__PURE__ */
35
+ (() => Object.fromEntries(Object.entries(LogId).map(([k, v]) => [v, k])))();
31
36
 
32
37
  // https://cs.android.com/android/platform/superproject/+/master:system/logging/liblog/include/android/log.h;l=73;drc=82b5738732161dbaafb2e2f25cce19cd26b9157d
33
- export enum AndroidLogPriority {
34
- Unknown,
35
- Default,
36
- Verbose,
37
- Debug,
38
- Info,
39
- Warn,
40
- Error,
41
- Fatal,
42
- Silent,
43
- }
38
+ export const AndroidLogPriority = {
39
+ Unknown: 0,
40
+ Default: 1,
41
+ Verbose: 2,
42
+ Debug: 3,
43
+ Info: 4,
44
+ Warn: 5,
45
+ Error: 6,
46
+ Fatal: 7,
47
+ Silent: 8,
48
+ } as const;
49
+
50
+ export type AndroidLogPriority =
51
+ (typeof AndroidLogPriority)[keyof typeof AndroidLogPriority];
44
52
 
45
53
  // https://cs.android.com/android/platform/superproject/+/master:system/logging/liblog/logprint.cpp;l=140;drc=8dbf3b2bb6b6d1652d9797e477b9abd03278bb79
46
54
  export const AndroidLogPriorityToCharacter: Record<AndroidLogPriority, string> =
@@ -56,16 +64,18 @@ export const AndroidLogPriorityToCharacter: Record<AndroidLogPriority, string> =
56
64
  [AndroidLogPriority.Silent]: "S",
57
65
  };
58
66
 
59
- export enum LogcatFormat {
60
- Brief,
61
- Process,
62
- Tag,
63
- Thread,
64
- Raw,
65
- Time,
66
- ThreadTime,
67
- Long,
68
- }
67
+ export const LogcatFormat = {
68
+ Brief: 0,
69
+ Process: 1,
70
+ Tag: 2,
71
+ Thread: 3,
72
+ Raw: 4,
73
+ Time: 5,
74
+ ThreadTime: 6,
75
+ Long: 7,
76
+ } as const;
77
+
78
+ export type LogcatFormat = (typeof LogcatFormat)[keyof typeof LogcatFormat];
69
79
 
70
80
  export interface LogcatFormatModifiers {
71
81
  microseconds?: boolean;
@@ -85,28 +95,34 @@ export interface LogcatOptions {
85
95
  ids?: LogId[];
86
96
  }
87
97
 
88
- const NANOSECONDS_PER_SECOND = BigInt(1e9);
98
+ const NANOSECONDS_PER_SECOND = /* #__PURE__ */ BigInt(1e9);
89
99
 
90
100
  // https://cs.android.com/android/platform/superproject/+/master:system/logging/liblog/include/log/log_read.h;l=39;drc=82b5738732161dbaafb2e2f25cce19cd26b9157d
91
- export const LoggerEntry = new Struct({ littleEndian: true })
92
- .uint16("payloadSize")
93
- .uint16("headerSize")
94
- .int32("pid")
95
- .uint32("tid")
96
- .uint32("seconds")
97
- .uint32("nanoseconds")
98
- .uint32("logId")
99
- .uint32("uid")
100
- .extra({
101
- get timestamp() {
102
- return (
103
- BigInt(this.seconds) * NANOSECONDS_PER_SECOND +
104
- BigInt(this.nanoseconds)
105
- );
101
+ export const LoggerEntry = struct(
102
+ {
103
+ payloadSize: u16,
104
+ headerSize: u16,
105
+ pid: u32,
106
+ tid: u32,
107
+ seconds: u32,
108
+ nanoseconds: u32,
109
+ logId: u32,
110
+ uid: u32,
111
+ },
112
+ {
113
+ littleEndian: true,
114
+ extra: {
115
+ get timestamp(): bigint {
116
+ return (
117
+ BigInt(this.seconds) * NANOSECONDS_PER_SECOND +
118
+ BigInt(this.nanoseconds)
119
+ );
120
+ },
106
121
  },
107
- });
122
+ },
123
+ );
108
124
 
109
- export type LoggerEntry = (typeof LoggerEntry)["TDeserializeResult"];
125
+ export type LoggerEntry = StructValue<typeof LoggerEntry>;
110
126
 
111
127
  // https://cs.android.com/android/platform/superproject/+/master:system/logging/liblog/logprint.cpp;drc=bbe77d66e7bee8bd1f0bc7e5492b5376b0207ef6;bpv=0
112
128
  export interface AndroidLogEntry extends LoggerEntry {
@@ -385,7 +401,7 @@ export interface LogSize {
385
401
 
386
402
  export class Logcat extends AdbCommandBase {
387
403
  static logIdToName(id: LogId): string {
388
- return LogId[id];
404
+ return LogIdName[id]!;
389
405
  }
390
406
 
391
407
  static logNameToId(name: string): LogId {
@@ -404,12 +420,12 @@ export class Logcat extends AdbCommandBase {
404
420
 
405
421
  // TODO: logcat: Support output format before Android 10
406
422
  // ref https://android-review.googlesource.com/c/platform/system/core/+/748128
407
- static readonly LOG_SIZE_REGEX_10 =
423
+ static readonly LOG_SIZE_REGEX_10: RegExp =
408
424
  /(.*): ring buffer is (.*) (.*)B \((.*) (.*)B consumed\), max entry is (.*) B, max payload is (.*) B/;
409
425
 
410
426
  // Android 11 added `readable` part
411
427
  // ref https://android-review.googlesource.com/c/platform/system/core/+/1390940
412
- static readonly LOG_SIZE_REGEX_11 =
428
+ static readonly LOG_SIZE_REGEX_11: RegExp =
413
429
  /(.*): ring buffer is (.*) (.*)B \((.*) (.*)B consumed, (.*) (.*)B readable\), max entry is (.*) B, max payload is (.*) B/;
414
430
 
415
431
  async getLogSize(ids?: LogId[]): Promise<LogSize[]> {
@@ -420,58 +436,53 @@ export class Logcat extends AdbCommandBase {
420
436
  ]);
421
437
 
422
438
  const result: LogSize[] = [];
423
- await stdout
439
+ for await (const line of stdout
424
440
  .pipeThrough(new TextDecoderStream())
425
- .pipeThrough(new SplitStringStream("\n"))
426
- .pipeTo(
427
- new WritableStream({
428
- write(chunk) {
429
- let match = chunk.match(Logcat.LOG_SIZE_REGEX_11);
430
- if (match) {
431
- result.push({
432
- id: Logcat.logNameToId(match[1]!),
433
- size: Logcat.parseSize(
434
- Number.parseInt(match[2]!, 10),
435
- match[3]!,
436
- ),
437
- readable: Logcat.parseSize(
438
- Number.parseInt(match[6]!, 10),
439
- match[7]!,
440
- ),
441
- consumed: Logcat.parseSize(
442
- Number.parseInt(match[4]!, 10),
443
- match[5]!,
444
- ),
445
- maxEntrySize: parseInt(match[8]!, 10),
446
- maxPayloadSize: parseInt(match[9]!, 10),
447
- });
448
- return;
449
- }
450
-
451
- match = chunk.match(Logcat.LOG_SIZE_REGEX_10);
452
- if (match) {
453
- result.push({
454
- id: Logcat.logNameToId(match[1]!),
455
- size: Logcat.parseSize(
456
- Number.parseInt(match[2]!, 10),
457
- match[3]!,
458
- ),
459
- consumed: Logcat.parseSize(
460
- Number.parseInt(match[4]!, 10),
461
- match[5]!,
462
- ),
463
- maxEntrySize: parseInt(match[6]!, 10),
464
- maxPayloadSize: parseInt(match[7]!, 10),
465
- });
466
- }
467
- },
468
- }),
469
- );
441
+ .pipeThrough(new SplitStringStream("\n"))) {
442
+ let match = line.match(Logcat.LOG_SIZE_REGEX_11);
443
+ if (match) {
444
+ result.push({
445
+ id: Logcat.logNameToId(match[1]!),
446
+ size: Logcat.parseSize(
447
+ Number.parseInt(match[2]!, 10),
448
+ match[3]!,
449
+ ),
450
+ readable: Logcat.parseSize(
451
+ Number.parseInt(match[6]!, 10),
452
+ match[7]!,
453
+ ),
454
+ consumed: Logcat.parseSize(
455
+ Number.parseInt(match[4]!, 10),
456
+ match[5]!,
457
+ ),
458
+ maxEntrySize: parseInt(match[8]!, 10),
459
+ maxPayloadSize: parseInt(match[9]!, 10),
460
+ });
461
+ break;
462
+ }
463
+
464
+ match = line.match(Logcat.LOG_SIZE_REGEX_10);
465
+ if (match) {
466
+ result.push({
467
+ id: Logcat.logNameToId(match[1]!),
468
+ size: Logcat.parseSize(
469
+ Number.parseInt(match[2]!, 10),
470
+ match[3]!,
471
+ ),
472
+ consumed: Logcat.parseSize(
473
+ Number.parseInt(match[4]!, 10),
474
+ match[5]!,
475
+ ),
476
+ maxEntrySize: parseInt(match[6]!, 10),
477
+ maxPayloadSize: parseInt(match[7]!, 10),
478
+ });
479
+ }
480
+ }
470
481
 
471
482
  return result;
472
483
  }
473
484
 
474
- async clear(ids?: LogId[]) {
485
+ async clear(ids?: LogId[]): Promise<void> {
475
486
  const args = ["logcat", "-c"];
476
487
  if (ids && ids.length > 0) {
477
488
  args.push("-b", Logcat.joinLogId(ids));
@@ -36,7 +36,7 @@ export class OverlayDisplay extends AdbCommandBase {
36
36
  p.literal("/"),
37
37
  { name: "density", format: p.digits() },
38
38
  ),
39
- 1,
39
+ { min: 1 },
40
40
  ),
41
41
  },
42
42
  {
@@ -81,7 +81,7 @@ export class OverlayDisplay extends AdbCommandBase {
81
81
  }));
82
82
  }
83
83
 
84
- async set(devices: OverlayDisplayDevice[]) {
84
+ async set(devices: OverlayDisplayDevice[]): Promise<void> {
85
85
  await this.#settings.put(
86
86
  "global",
87
87
  OverlayDisplay.SETTING_KEY,