@yume-chan/android-bin 0.0.19 → 0.0.21

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.
Files changed (61) hide show
  1. package/CHANGELOG.json +36 -0
  2. package/CHANGELOG.md +19 -1
  3. package/LICENSE +21 -0
  4. package/esm/bu.d.ts +20 -7
  5. package/esm/bu.d.ts.map +1 -1
  6. package/esm/bu.js +47 -8
  7. package/esm/bu.js.map +1 -1
  8. package/esm/bug-report.d.ts +82 -21
  9. package/esm/bug-report.d.ts.map +1 -1
  10. package/esm/bug-report.js +189 -55
  11. package/esm/bug-report.js.map +1 -1
  12. package/esm/cmd.d.ts +4 -6
  13. package/esm/cmd.d.ts.map +1 -1
  14. package/esm/cmd.js +39 -24
  15. package/esm/cmd.js.map +1 -1
  16. package/esm/demo-mode.d.ts +3 -3
  17. package/esm/demo-mode.d.ts.map +1 -1
  18. package/esm/demo-mode.js +14 -15
  19. package/esm/demo-mode.js.map +1 -1
  20. package/esm/dumpsys.d.ts +21 -0
  21. package/esm/dumpsys.d.ts.map +1 -0
  22. package/esm/dumpsys.js +82 -0
  23. package/esm/dumpsys.js.map +1 -0
  24. package/esm/index.d.ts +3 -0
  25. package/esm/index.d.ts.map +1 -1
  26. package/esm/index.js +3 -0
  27. package/esm/index.js.map +1 -1
  28. package/esm/logcat.d.ts +3 -2
  29. package/esm/logcat.d.ts.map +1 -1
  30. package/esm/logcat.js +34 -24
  31. package/esm/logcat.js.map +1 -1
  32. package/esm/overlay-display.d.ts +20 -3
  33. package/esm/overlay-display.d.ts.map +1 -1
  34. package/esm/overlay-display.js +34 -61
  35. package/esm/overlay-display.js.map +1 -1
  36. package/esm/pm.d.ts +25 -2
  37. package/esm/pm.d.ts.map +1 -1
  38. package/esm/pm.js +88 -17
  39. package/esm/pm.js.map +1 -1
  40. package/esm/settings.d.ts +21 -8
  41. package/esm/settings.d.ts.map +1 -1
  42. package/esm/settings.js +55 -19
  43. package/esm/settings.js.map +1 -1
  44. package/esm/string-format.d.ts +40 -0
  45. package/esm/string-format.d.ts.map +1 -0
  46. package/esm/string-format.js +153 -0
  47. package/esm/string-format.js.map +1 -0
  48. package/package.json +13 -8
  49. package/src/bu.ts +68 -14
  50. package/src/bug-report.ts +236 -70
  51. package/src/cmd.ts +67 -33
  52. package/src/demo-mode.ts +47 -43
  53. package/src/dumpsys.ts +91 -0
  54. package/src/index.ts +3 -0
  55. package/src/logcat.ts +63 -74
  56. package/src/overlay-display.ts +82 -85
  57. package/src/pm.ts +149 -27
  58. package/src/settings.ts +99 -50
  59. package/src/string-format.ts +199 -0
  60. package/tsconfig.build.json +11 -0
  61. package/tsconfig.build.tsbuildinfo +1 -1
package/src/demo-mode.ts CHANGED
@@ -52,57 +52,65 @@ export const DemoModeStatusBarModes = [
52
52
  export type DemoModeStatusBarMode = (typeof DemoModeStatusBarModes)[number];
53
53
 
54
54
  export class DemoMode extends AdbCommandBase {
55
- private settings: Settings;
55
+ #settings: Settings;
56
56
 
57
57
  constructor(adb: Adb) {
58
58
  super(adb);
59
- this.settings = new Settings(adb);
59
+ this.#settings = new Settings(adb);
60
60
  }
61
61
 
62
- public static readonly AllowedSettingKey = "sysui_demo_allowed";
62
+ static readonly ALLOWED_SETTING_KEY = "sysui_demo_allowed";
63
63
 
64
64
  // Demo Mode actually doesn't have a setting indicates its enablement
65
65
  // However Developer Mode menu uses this key
66
66
  // So we can only try our best to guess if it's enabled
67
- public static readonly EnabledSettingKey = "sysui_tuner_demo_on";
67
+ static readonly ENABLED_SETTING_KEY = "sysui_tuner_demo_on";
68
68
 
69
- public async getAllowed(): Promise<boolean> {
70
- const output = await this.settings.get(
69
+ async getAllowed(): Promise<boolean> {
70
+ const output = await this.#settings.get(
71
71
  "global",
72
- DemoMode.AllowedSettingKey
72
+ DemoMode.ALLOWED_SETTING_KEY,
73
73
  );
74
- return output.trim() === "1";
74
+ return output === "1";
75
75
  }
76
76
 
77
- public async setAllowed(value: boolean): Promise<void> {
77
+ async setAllowed(value: boolean): Promise<void> {
78
78
  if (value) {
79
- await this.settings.put("global", DemoMode.AllowedSettingKey, "1");
79
+ await this.#settings.put(
80
+ "global",
81
+ DemoMode.ALLOWED_SETTING_KEY,
82
+ "1",
83
+ );
80
84
  } else {
81
85
  await this.setEnabled(false);
82
- await this.settings.delete("global", DemoMode.AllowedSettingKey);
86
+ await this.#settings.delete("global", DemoMode.ALLOWED_SETTING_KEY);
83
87
  }
84
88
  }
85
89
 
86
- public async getEnabled(): Promise<boolean> {
87
- const result = await this.settings.get(
90
+ async getEnabled(): Promise<boolean> {
91
+ const result = await this.#settings.get(
88
92
  "global",
89
- DemoMode.EnabledSettingKey
93
+ DemoMode.ENABLED_SETTING_KEY,
90
94
  );
91
- return result.trim() === "1";
95
+ return result === "1";
92
96
  }
93
97
 
94
- public async setEnabled(value: boolean): Promise<void> {
98
+ async setEnabled(value: boolean): Promise<void> {
95
99
  if (value) {
96
- await this.settings.put("global", DemoMode.EnabledSettingKey, "1");
100
+ await this.#settings.put(
101
+ "global",
102
+ DemoMode.ENABLED_SETTING_KEY,
103
+ "1",
104
+ );
97
105
  } else {
98
- await this.settings.delete("global", DemoMode.EnabledSettingKey);
106
+ await this.#settings.delete("global", DemoMode.ENABLED_SETTING_KEY);
99
107
  await this.broadcast("exit");
100
108
  }
101
109
  }
102
110
 
103
- public async broadcast(
111
+ async broadcast(
104
112
  command: string,
105
- extra?: Record<string, string>
113
+ extra?: Record<string, string>,
106
114
  ): Promise<void> {
107
115
  await this.adb.subprocess.spawnAndWaitLegacy([
108
116
  "am",
@@ -122,31 +130,27 @@ export class DemoMode extends AdbCommandBase {
122
130
  ]);
123
131
  }
124
132
 
125
- public async setBatteryLevel(level: number): Promise<void> {
133
+ async setBatteryLevel(level: number): Promise<void> {
126
134
  await this.broadcast("battery", { level: level.toString() });
127
135
  }
128
136
 
129
- public async setBatteryCharging(value: boolean): Promise<void> {
137
+ async setBatteryCharging(value: boolean): Promise<void> {
130
138
  await this.broadcast("battery", { plugged: value.toString() });
131
139
  }
132
140
 
133
- public async setPowerSaveMode(value: boolean): Promise<void> {
141
+ async setPowerSaveMode(value: boolean): Promise<void> {
134
142
  await this.broadcast("battery", { powersave: value.toString() });
135
143
  }
136
144
 
137
- public async setAirplaneMode(show: boolean): Promise<void> {
145
+ async setAirplaneMode(show: boolean): Promise<void> {
138
146
  await this.broadcast("network", { airplane: show ? "show" : "hide" });
139
147
  }
140
148
 
141
- public async setWifiSignalStrength(
142
- value: DemoModeSignalStrength
143
- ): Promise<void> {
149
+ async setWifiSignalStrength(value: DemoModeSignalStrength): Promise<void> {
144
150
  await this.broadcast("network", { wifi: "show", level: value });
145
151
  }
146
152
 
147
- public async setMobileDataType(
148
- value: DemoModeMobileDataType
149
- ): Promise<void> {
153
+ async setMobileDataType(value: DemoModeMobileDataType): Promise<void> {
150
154
  for (let i = 0; i < 2; i += 1) {
151
155
  await this.broadcast("network", {
152
156
  mobile: "show",
@@ -164,60 +168,60 @@ export class DemoMode extends AdbCommandBase {
164
168
  }
165
169
  }
166
170
 
167
- public async setMobileSignalStrength(
168
- value: DemoModeSignalStrength
171
+ async setMobileSignalStrength(
172
+ value: DemoModeSignalStrength,
169
173
  ): Promise<void> {
170
174
  await this.broadcast("network", { mobile: "show", level: value });
171
175
  }
172
176
 
173
- public async setNoSimCardIcon(show: boolean): Promise<void> {
177
+ async setNoSimCardIcon(show: boolean): Promise<void> {
174
178
  await this.broadcast("network", { nosim: show ? "show" : "hide" });
175
179
  }
176
180
 
177
- public async setStatusBarMode(mode: DemoModeStatusBarMode): Promise<void> {
181
+ async setStatusBarMode(mode: DemoModeStatusBarMode): Promise<void> {
178
182
  await this.broadcast("bars", { mode });
179
183
  }
180
184
 
181
- public async setVibrateModeEnabled(value: boolean): Promise<void> {
185
+ async setVibrateModeEnabled(value: boolean): Promise<void> {
182
186
  // https://cs.android.com/android/platform/superproject/+/master:frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java;l=103
183
187
  await this.broadcast("status", { volume: value ? "vibrate" : "hide" });
184
188
  }
185
189
 
186
- public async setBluetoothConnected(value: boolean): Promise<void> {
190
+ async setBluetoothConnected(value: boolean): Promise<void> {
187
191
  // https://cs.android.com/android/platform/superproject/+/master:frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java;l=114
188
192
  await this.broadcast("status", {
189
193
  bluetooth: value ? "connected" : "hide",
190
194
  });
191
195
  }
192
196
 
193
- public async setLocatingIcon(show: boolean): Promise<void> {
197
+ async setLocatingIcon(show: boolean): Promise<void> {
194
198
  await this.broadcast("status", { location: show ? "show" : "hide" });
195
199
  }
196
200
 
197
- public async setAlarmIcon(show: boolean): Promise<void> {
201
+ async setAlarmIcon(show: boolean): Promise<void> {
198
202
  await this.broadcast("status", { alarm: show ? "show" : "hide" });
199
203
  }
200
204
 
201
- public async setSyncingIcon(show: boolean): Promise<void> {
205
+ async setSyncingIcon(show: boolean): Promise<void> {
202
206
  await this.broadcast("status", { sync: show ? "show" : "hide" });
203
207
  }
204
208
 
205
- public async setMuteIcon(show: boolean): Promise<void> {
209
+ async setMuteIcon(show: boolean): Promise<void> {
206
210
  await this.broadcast("status", { mute: show ? "show" : "hide" });
207
211
  }
208
212
 
209
- public async setSpeakerPhoneIcon(show: boolean): Promise<void> {
213
+ async setSpeakerPhoneIcon(show: boolean): Promise<void> {
210
214
  await this.broadcast("status", {
211
215
  speakerphone: show ? "show" : "hide",
212
216
  });
213
217
  }
214
218
 
215
- public async setNotificationsVisibility(show: boolean): Promise<void> {
219
+ async setNotificationsVisibility(show: boolean): Promise<void> {
216
220
  // https://cs.android.com/android/platform/superproject/+/master:frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java;l=3131
217
221
  await this.broadcast("notifications", { visible: show.toString() });
218
222
  }
219
223
 
220
- public async setTime(hour: number, minute: number): Promise<void> {
224
+ async setTime(hour: number, minute: number): Promise<void> {
221
225
  await this.broadcast("clock", {
222
226
  // cspell: disable-next-line
223
227
  hhmm:
package/src/dumpsys.ts ADDED
@@ -0,0 +1,91 @@
1
+ import { AdbCommandBase } from "@yume-chan/adb";
2
+
3
+ export class DumpSys extends AdbCommandBase {
4
+ async diskStats() {
5
+ const output = await this.adb.subprocess.spawnAndWaitLegacy([
6
+ "dumpsys",
7
+ "diskstats",
8
+ ]);
9
+
10
+ function getSize(name: string) {
11
+ const match = output.match(
12
+ new RegExp(`${name}-Free: (\\d+)K / (\\d+)K`),
13
+ );
14
+ if (!match) {
15
+ return [0, 0];
16
+ }
17
+ return [
18
+ Number.parseInt(match[1]!, 10) * 1024,
19
+ Number.parseInt(match[2]!, 10) * 1024,
20
+ ];
21
+ }
22
+
23
+ const [dataFree, dataTotal] = getSize("Data");
24
+ const [cacheFree, cacheTotal] = getSize("Cache");
25
+ const [systemFree, systemTotal] = getSize("System");
26
+
27
+ return {
28
+ dataFree,
29
+ dataTotal,
30
+ cacheFree,
31
+ cacheTotal,
32
+ systemFree,
33
+ systemTotal,
34
+ };
35
+ }
36
+
37
+ async battery() {
38
+ const output = await this.adb.subprocess.spawnAndWaitLegacy([
39
+ "dumpsys",
40
+ "battery",
41
+ ]);
42
+
43
+ let acPowered = false;
44
+ let usbPowered = false;
45
+ let wirelessPowered = false;
46
+ let level: number | undefined;
47
+ let scale: number | undefined;
48
+ let voltage: number | undefined;
49
+ let current: number | undefined;
50
+ for (const line of output) {
51
+ const parts = line.split(":");
52
+ if (parts.length !== 2) {
53
+ continue;
54
+ }
55
+
56
+ switch (parts[0]!.trim()) {
57
+ case "AC powered":
58
+ acPowered = parts[1]!.trim() === "true";
59
+ break;
60
+ case "USB powered":
61
+ usbPowered = parts[1]!.trim() === "true";
62
+ break;
63
+ case "Wireless powered":
64
+ wirelessPowered = parts[1]!.trim() === "true";
65
+ break;
66
+ case "level":
67
+ level = Number.parseInt(parts[1]!.trim(), 10);
68
+ break;
69
+ case "scale":
70
+ scale = Number.parseInt(parts[1]!.trim(), 10);
71
+ break;
72
+ case "voltage":
73
+ voltage = Number.parseInt(parts[1]!.trim(), 10);
74
+ break;
75
+ case "current now":
76
+ current = Number.parseInt(parts[1]!.trim(), 10);
77
+ break;
78
+ }
79
+ }
80
+
81
+ return {
82
+ acPowered,
83
+ usbPowered,
84
+ wirelessPowered,
85
+ level,
86
+ scale,
87
+ voltage,
88
+ current,
89
+ };
90
+ }
91
+ }
package/src/index.ts CHANGED
@@ -1,8 +1,11 @@
1
1
  // cspell: ignore logcat
2
2
 
3
+ export * from "./bu.js";
3
4
  export * from "./bug-report.js";
4
5
  export * from "./cmd.js";
5
6
  export * from "./demo-mode.js";
7
+ export * from "./dumpsys.js";
6
8
  export * from "./logcat.js";
9
+ export * from "./overlay-display.js";
7
10
  export * from "./pm.js";
8
11
  export * from "./settings.js";
package/src/logcat.ts CHANGED
@@ -10,7 +10,7 @@ import {
10
10
  WrapReadableStream,
11
11
  WritableStream,
12
12
  } from "@yume-chan/stream-extra";
13
- import type { StructAsyncDeserializeStream } from "@yume-chan/struct";
13
+ import type { AsyncExactReadable } from "@yume-chan/struct";
14
14
  import Struct, { decodeUtf8 } from "@yume-chan/struct";
15
15
 
16
16
  // `adb logcat` is an alias to `adb shell logcat`
@@ -80,6 +80,7 @@ export interface LogcatFormatModifiers {
80
80
  }
81
81
 
82
82
  export interface LogcatOptions {
83
+ dump?: boolean;
83
84
  pid?: number;
84
85
  ids?: LogId[];
85
86
  }
@@ -116,61 +117,49 @@ export interface AndroidLogEntry extends LoggerEntry {
116
117
  toString(format?: LogcatFormat, modifiers?: LogcatFormatModifiers): string;
117
118
  }
118
119
 
120
+ function padZero(number: number, length: number) {
121
+ return number.toString().padStart(length, "0");
122
+ }
123
+
119
124
  function formatSeconds(seconds: number, modifiers: LogcatFormatModifiers) {
120
125
  if (modifiers.monotonic) {
121
- return seconds.toString().padStart(6);
126
+ return padZero(seconds, 6);
122
127
  }
123
128
 
124
129
  if (modifiers.epoch) {
125
- return seconds.toString().padStart(19);
130
+ return padZero(seconds, 19);
126
131
  }
127
132
 
128
133
  const date = new Date(seconds * 1000);
129
134
 
135
+ const month = padZero(date.getMonth() + 1, 2);
136
+ const day = padZero(date.getDate(), 2);
137
+ const hour = padZero(date.getHours(), 2);
138
+ const minute = padZero(date.getMinutes(), 2);
139
+ const second = padZero(date.getSeconds(), 2);
140
+ const result = `${month}-${day} ${hour}:${minute}:${second}`;
141
+
130
142
  if (modifiers.year) {
131
- // prettier-ignore
132
- return `${
133
- date.getFullYear().toString().padStart(4, "0")
134
- }-${
135
- (date.getMonth() + 1).toString().padStart(2, "0")
136
- }-${
137
- date.getDate().toString().padStart(2, "0")
138
- } ${
139
- date.getHours().toString().padStart(2, "0")
140
- }:${
141
- date.getMinutes().toString().padStart(2, "0")
142
- }:${
143
- date.getSeconds().toString().padStart(2, "0")
144
- }`;
143
+ const year = padZero(date.getFullYear(), 4);
144
+ return `${year}-${result}`;
145
145
  }
146
146
 
147
- // prettier-ignore
148
- return `${
149
- (date.getMonth() + 1).toString().padStart(2, "0")
150
- }-${
151
- date.getDate().toString().padStart(2, "0")
152
- } ${
153
- date.getHours().toString().padStart(2, "0")
154
- }:${
155
- date.getMinutes().toString().padStart(2, "0")
156
- }:${
157
- date.getSeconds().toString().padStart(2, "0")
158
- }`;
147
+ return result;
159
148
  }
160
149
 
161
150
  function formatNanoseconds(
162
151
  nanoseconds: number,
163
- modifiers: LogcatFormatModifiers
152
+ modifiers: LogcatFormatModifiers,
164
153
  ) {
165
154
  if (modifiers.nanoseconds) {
166
- return nanoseconds.toString().padStart(9, "0");
155
+ return padZero(nanoseconds, 9);
167
156
  }
168
157
 
169
158
  if (modifiers.microseconds) {
170
- return ((nanoseconds / 1000) | 0).toString().padStart(6, "0");
159
+ return padZero(nanoseconds / 1000, 6);
171
160
  }
172
161
 
173
- return ((nanoseconds / 1000000) | 0).toString().padStart(3, "0");
162
+ return padZero(nanoseconds / 1000000, 3);
174
163
  }
175
164
 
176
165
  function formatTimezone(seconds: number, modifiers: LogcatFormatModifiers) {
@@ -198,7 +187,7 @@ function formatTimezone(seconds: number, modifiers: LogcatFormatModifiers) {
198
187
  function formatTime(
199
188
  seconds: number,
200
189
  nanoseconds: number,
201
- modifiers: LogcatFormatModifiers
190
+ modifiers: LogcatFormatModifiers,
202
191
  ) {
203
192
  const secondsString = formatSeconds(seconds, modifiers);
204
193
  const nanosecondsString = formatNanoseconds(nanoseconds, modifiers);
@@ -209,7 +198,7 @@ function formatTime(
209
198
  function formatUid(
210
199
  uid: number,
211
200
  modifiers: LogcatFormatModifiers,
212
- suffix: string
201
+ suffix: string,
213
202
  ) {
214
203
  return modifiers.uid ? `${uid.toString().padStart(5)}${suffix}` : "";
215
204
  }
@@ -217,7 +206,7 @@ function formatUid(
217
206
  function getFormatPrefix(
218
207
  entry: AndroidLogEntry,
219
208
  format: LogcatFormat,
220
- modifiers: LogcatFormatModifiers
209
+ modifiers: LogcatFormatModifiers,
221
210
  ) {
222
211
  // https://cs.android.com/android/platform/superproject/+/master:system/logging/liblog/logprint.cpp;l=1415;drc=8dbf3b2bb6b6d1652d9797e477b9abd03278bb79
223
212
  switch (format) {
@@ -306,7 +295,7 @@ function getFormatSuffix(entry: AndroidLogEntry, format: LogcatFormat) {
306
295
  function formatEntryWrapLine(
307
296
  entry: AndroidLogEntry,
308
297
  format: LogcatFormat,
309
- modifiers: LogcatFormatModifiers
298
+ modifiers: LogcatFormatModifiers,
310
299
  ) {
311
300
  const prefix = getFormatPrefix(entry, format, modifiers);
312
301
  const suffix = getFormatSuffix(entry, format);
@@ -318,7 +307,7 @@ function formatEntryWrapLine(
318
307
  function AndroidLogEntryToString(
319
308
  this: AndroidLogEntry,
320
309
  format: LogcatFormat = LogcatFormat.ThreadTime,
321
- modifiers: LogcatFormatModifiers = {}
310
+ modifiers: LogcatFormatModifiers = {},
322
311
  ) {
323
312
  switch (format) {
324
313
  case LogcatFormat.Long:
@@ -360,15 +349,14 @@ function findTagEnd(payload: Uint8Array) {
360
349
  }
361
350
 
362
351
  export async function deserializeAndroidLogEntry(
363
- stream: StructAsyncDeserializeStream
352
+ stream: AsyncExactReadable,
364
353
  ): Promise<AndroidLogEntry> {
365
- const entry = (await LoggerEntry.deserialize(
366
- stream
367
- )) as unknown as AndroidLogEntry;
354
+ const entry = (await LoggerEntry.deserialize(stream)) as AndroidLogEntry;
368
355
  if (entry.headerSize !== LoggerEntry.size) {
369
- await stream.read(entry.headerSize - LoggerEntry.size);
356
+ await stream.readExactly(entry.headerSize - LoggerEntry.size);
370
357
  }
371
- let payload = await stream.read(entry.payloadSize);
358
+
359
+ let payload = await stream.readExactly(entry.payloadSize);
372
360
 
373
361
  // https://cs.android.com/android/platform/superproject/+/master:system/logging/logcat/logcat.cpp;l=193-194;drc=bbe77d66e7bee8bd1f0bc7e5492b5376b0207ef6
374
362
  // TODO: payload for some log IDs are in binary format.
@@ -395,35 +383,35 @@ export interface LogSize {
395
383
  }
396
384
 
397
385
  export class Logcat extends AdbCommandBase {
398
- public static logIdToName(id: LogId): string {
386
+ static logIdToName(id: LogId): string {
399
387
  return LogId[id]!;
400
388
  }
401
389
 
402
- public static logNameToId(name: string): LogId {
390
+ static logNameToId(name: string): LogId {
403
391
  const key = name[0]!.toUpperCase() + name.substring(1);
404
392
  return LogId[key as keyof typeof LogId];
405
393
  }
406
394
 
407
- public static joinLogId(ids: LogId[]): string {
395
+ static joinLogId(ids: LogId[]): string {
408
396
  return ids.map((id) => Logcat.logIdToName(id)).join(",");
409
397
  }
410
398
 
411
- public static parseSize(value: number, multiplier: string): number {
399
+ static parseSize(value: number, multiplier: string): number {
412
400
  const MULTIPLIERS = ["", "Ki", "Mi", "Gi"];
413
401
  return value * 1024 ** (MULTIPLIERS.indexOf(multiplier) || 0);
414
402
  }
415
403
 
416
404
  // TODO: logcat: Support output format before Android 10
417
405
  // ref https://android-review.googlesource.com/c/platform/system/core/+/748128
418
- public static readonly LOG_SIZE_REGEX_10 =
406
+ static readonly LOG_SIZE_REGEX_10 =
419
407
  /(.*): ring buffer is (.*) (.*)B \((.*) (.*)B consumed\), max entry is (.*) B, max payload is (.*) B/;
420
408
 
421
409
  // Android 11 added `readable` part
422
410
  // ref https://android-review.googlesource.com/c/platform/system/core/+/1390940
423
- public static readonly LOG_SIZE_REGEX_11 =
411
+ static readonly LOG_SIZE_REGEX_11 =
424
412
  /(.*): ring buffer is (.*) (.*)B \((.*) (.*)B consumed, (.*) (.*)B readable\), max entry is (.*) B, max payload is (.*) B/;
425
413
 
426
- public async getLogSize(ids?: LogId[]): Promise<LogSize[]> {
414
+ async getLogSize(ids?: LogId[]): Promise<LogSize[]> {
427
415
  const { stdout } = await this.adb.subprocess.spawn([
428
416
  "logcat",
429
417
  "-g",
@@ -443,15 +431,15 @@ export class Logcat extends AdbCommandBase {
443
431
  id: Logcat.logNameToId(match[1]!),
444
432
  size: Logcat.parseSize(
445
433
  Number.parseInt(match[2]!, 10),
446
- match[3]!
434
+ match[3]!,
447
435
  ),
448
436
  readable: Logcat.parseSize(
449
437
  Number.parseInt(match[6]!, 10),
450
- match[7]!
438
+ match[7]!,
451
439
  ),
452
440
  consumed: Logcat.parseSize(
453
441
  Number.parseInt(match[4]!, 10),
454
- match[5]!
442
+ match[5]!,
455
443
  ),
456
444
  maxEntrySize: parseInt(match[8]!, 10),
457
445
  maxPayloadSize: parseInt(match[9]!, 10),
@@ -465,24 +453,24 @@ export class Logcat extends AdbCommandBase {
465
453
  id: Logcat.logNameToId(match[1]!),
466
454
  size: Logcat.parseSize(
467
455
  Number.parseInt(match[2]!, 10),
468
- match[3]!
456
+ match[3]!,
469
457
  ),
470
458
  consumed: Logcat.parseSize(
471
459
  Number.parseInt(match[4]!, 10),
472
- match[5]!
460
+ match[5]!,
473
461
  ),
474
462
  maxEntrySize: parseInt(match[6]!, 10),
475
463
  maxPayloadSize: parseInt(match[7]!, 10),
476
464
  });
477
465
  }
478
466
  },
479
- })
467
+ }),
480
468
  );
481
469
 
482
470
  return result;
483
471
  }
484
472
 
485
- public async clear(ids?: LogId[]) {
473
+ async clear(ids?: LogId[]) {
486
474
  await this.adb.subprocess.spawnAndWait([
487
475
  "logcat",
488
476
  "-c",
@@ -490,29 +478,30 @@ export class Logcat extends AdbCommandBase {
490
478
  ]);
491
479
  }
492
480
 
493
- public binary(options?: LogcatOptions): ReadableStream<AndroidLogEntry> {
481
+ binary(options?: LogcatOptions): ReadableStream<AndroidLogEntry> {
494
482
  return new WrapReadableStream(async () => {
483
+ const args = ["logcat", "-B"];
484
+ if (options?.dump) {
485
+ args.push("-d");
486
+ }
487
+ if (options?.pid) {
488
+ args.push("--pid", options.pid.toString());
489
+ }
490
+ if (options?.ids) {
491
+ args.push("-b", Logcat.joinLogId(options.ids));
492
+ }
493
+
495
494
  // TODO: make `spawn` return synchronously with streams pending
496
495
  // so it's easier to chain them.
497
- const { stdout } = await this.adb.subprocess.spawn(
498
- [
499
- "logcat",
500
- "-B",
501
- ...(options?.pid ? ["--pid", options.pid.toString()] : []),
502
- ...(options?.ids
503
- ? ["-b", Logcat.joinLogId(options.ids)]
504
- : []),
505
- ],
506
- {
507
- // PERF: None protocol is 150% faster then Shell protocol
508
- protocols: [AdbSubprocessNoneProtocol],
509
- }
510
- );
496
+ const { stdout } = await this.adb.subprocess.spawn(args, {
497
+ // PERF: None protocol is 150% faster then Shell protocol
498
+ protocols: [AdbSubprocessNoneProtocol],
499
+ });
511
500
  return stdout;
512
501
  }).pipeThrough(
513
502
  new BufferedTransformStream((stream) => {
514
503
  return deserializeAndroidLogEntry(stream);
515
- })
504
+ }),
516
505
  );
517
506
  }
518
507
  }