@yume-chan/android-bin 0.0.20 → 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 (60) hide show
  1. package/CHANGELOG.json +30 -0
  2. package/CHANGELOG.md +14 -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 +187 -53
  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 +36 -21
  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 +17 -0
  21. package/esm/dumpsys.d.ts.map +1 -1
  22. package/esm/dumpsys.js +78 -0
  23. package/esm/dumpsys.js.map +1 -1
  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 +1 -0
  29. package/esm/logcat.d.ts.map +1 -1
  30. package/esm/logcat.js +15 -13
  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 +50 -25
  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 +234 -68
  51. package/src/cmd.ts +64 -30
  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 +39 -37
  56. package/src/overlay-display.ts +82 -85
  57. package/src/pm.ts +149 -27
  58. package/src/settings.ts +93 -43
  59. package/src/string-format.ts +199 -0
  60. 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
@@ -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
  }
@@ -148,7 +149,7 @@ function formatSeconds(seconds: number, modifiers: LogcatFormatModifiers) {
148
149
 
149
150
  function formatNanoseconds(
150
151
  nanoseconds: number,
151
- modifiers: LogcatFormatModifiers
152
+ modifiers: LogcatFormatModifiers,
152
153
  ) {
153
154
  if (modifiers.nanoseconds) {
154
155
  return padZero(nanoseconds, 9);
@@ -186,7 +187,7 @@ function formatTimezone(seconds: number, modifiers: LogcatFormatModifiers) {
186
187
  function formatTime(
187
188
  seconds: number,
188
189
  nanoseconds: number,
189
- modifiers: LogcatFormatModifiers
190
+ modifiers: LogcatFormatModifiers,
190
191
  ) {
191
192
  const secondsString = formatSeconds(seconds, modifiers);
192
193
  const nanosecondsString = formatNanoseconds(nanoseconds, modifiers);
@@ -197,7 +198,7 @@ function formatTime(
197
198
  function formatUid(
198
199
  uid: number,
199
200
  modifiers: LogcatFormatModifiers,
200
- suffix: string
201
+ suffix: string,
201
202
  ) {
202
203
  return modifiers.uid ? `${uid.toString().padStart(5)}${suffix}` : "";
203
204
  }
@@ -205,7 +206,7 @@ function formatUid(
205
206
  function getFormatPrefix(
206
207
  entry: AndroidLogEntry,
207
208
  format: LogcatFormat,
208
- modifiers: LogcatFormatModifiers
209
+ modifiers: LogcatFormatModifiers,
209
210
  ) {
210
211
  // https://cs.android.com/android/platform/superproject/+/master:system/logging/liblog/logprint.cpp;l=1415;drc=8dbf3b2bb6b6d1652d9797e477b9abd03278bb79
211
212
  switch (format) {
@@ -294,7 +295,7 @@ function getFormatSuffix(entry: AndroidLogEntry, format: LogcatFormat) {
294
295
  function formatEntryWrapLine(
295
296
  entry: AndroidLogEntry,
296
297
  format: LogcatFormat,
297
- modifiers: LogcatFormatModifiers
298
+ modifiers: LogcatFormatModifiers,
298
299
  ) {
299
300
  const prefix = getFormatPrefix(entry, format, modifiers);
300
301
  const suffix = getFormatSuffix(entry, format);
@@ -306,7 +307,7 @@ function formatEntryWrapLine(
306
307
  function AndroidLogEntryToString(
307
308
  this: AndroidLogEntry,
308
309
  format: LogcatFormat = LogcatFormat.ThreadTime,
309
- modifiers: LogcatFormatModifiers = {}
310
+ modifiers: LogcatFormatModifiers = {},
310
311
  ) {
311
312
  switch (format) {
312
313
  case LogcatFormat.Long:
@@ -348,7 +349,7 @@ function findTagEnd(payload: Uint8Array) {
348
349
  }
349
350
 
350
351
  export async function deserializeAndroidLogEntry(
351
- stream: AsyncExactReadable
352
+ stream: AsyncExactReadable,
352
353
  ): Promise<AndroidLogEntry> {
353
354
  const entry = (await LoggerEntry.deserialize(stream)) as AndroidLogEntry;
354
355
  if (entry.headerSize !== LoggerEntry.size) {
@@ -382,35 +383,35 @@ export interface LogSize {
382
383
  }
383
384
 
384
385
  export class Logcat extends AdbCommandBase {
385
- public static logIdToName(id: LogId): string {
386
+ static logIdToName(id: LogId): string {
386
387
  return LogId[id]!;
387
388
  }
388
389
 
389
- public static logNameToId(name: string): LogId {
390
+ static logNameToId(name: string): LogId {
390
391
  const key = name[0]!.toUpperCase() + name.substring(1);
391
392
  return LogId[key as keyof typeof LogId];
392
393
  }
393
394
 
394
- public static joinLogId(ids: LogId[]): string {
395
+ static joinLogId(ids: LogId[]): string {
395
396
  return ids.map((id) => Logcat.logIdToName(id)).join(",");
396
397
  }
397
398
 
398
- public static parseSize(value: number, multiplier: string): number {
399
+ static parseSize(value: number, multiplier: string): number {
399
400
  const MULTIPLIERS = ["", "Ki", "Mi", "Gi"];
400
401
  return value * 1024 ** (MULTIPLIERS.indexOf(multiplier) || 0);
401
402
  }
402
403
 
403
404
  // TODO: logcat: Support output format before Android 10
404
405
  // ref https://android-review.googlesource.com/c/platform/system/core/+/748128
405
- public static readonly LOG_SIZE_REGEX_10 =
406
+ static readonly LOG_SIZE_REGEX_10 =
406
407
  /(.*): ring buffer is (.*) (.*)B \((.*) (.*)B consumed\), max entry is (.*) B, max payload is (.*) B/;
407
408
 
408
409
  // Android 11 added `readable` part
409
410
  // ref https://android-review.googlesource.com/c/platform/system/core/+/1390940
410
- public static readonly LOG_SIZE_REGEX_11 =
411
+ static readonly LOG_SIZE_REGEX_11 =
411
412
  /(.*): ring buffer is (.*) (.*)B \((.*) (.*)B consumed, (.*) (.*)B readable\), max entry is (.*) B, max payload is (.*) B/;
412
413
 
413
- public async getLogSize(ids?: LogId[]): Promise<LogSize[]> {
414
+ async getLogSize(ids?: LogId[]): Promise<LogSize[]> {
414
415
  const { stdout } = await this.adb.subprocess.spawn([
415
416
  "logcat",
416
417
  "-g",
@@ -430,15 +431,15 @@ export class Logcat extends AdbCommandBase {
430
431
  id: Logcat.logNameToId(match[1]!),
431
432
  size: Logcat.parseSize(
432
433
  Number.parseInt(match[2]!, 10),
433
- match[3]!
434
+ match[3]!,
434
435
  ),
435
436
  readable: Logcat.parseSize(
436
437
  Number.parseInt(match[6]!, 10),
437
- match[7]!
438
+ match[7]!,
438
439
  ),
439
440
  consumed: Logcat.parseSize(
440
441
  Number.parseInt(match[4]!, 10),
441
- match[5]!
442
+ match[5]!,
442
443
  ),
443
444
  maxEntrySize: parseInt(match[8]!, 10),
444
445
  maxPayloadSize: parseInt(match[9]!, 10),
@@ -452,24 +453,24 @@ export class Logcat extends AdbCommandBase {
452
453
  id: Logcat.logNameToId(match[1]!),
453
454
  size: Logcat.parseSize(
454
455
  Number.parseInt(match[2]!, 10),
455
- match[3]!
456
+ match[3]!,
456
457
  ),
457
458
  consumed: Logcat.parseSize(
458
459
  Number.parseInt(match[4]!, 10),
459
- match[5]!
460
+ match[5]!,
460
461
  ),
461
462
  maxEntrySize: parseInt(match[6]!, 10),
462
463
  maxPayloadSize: parseInt(match[7]!, 10),
463
464
  });
464
465
  }
465
466
  },
466
- })
467
+ }),
467
468
  );
468
469
 
469
470
  return result;
470
471
  }
471
472
 
472
- public async clear(ids?: LogId[]) {
473
+ async clear(ids?: LogId[]) {
473
474
  await this.adb.subprocess.spawnAndWait([
474
475
  "logcat",
475
476
  "-c",
@@ -477,29 +478,30 @@ export class Logcat extends AdbCommandBase {
477
478
  ]);
478
479
  }
479
480
 
480
- public binary(options?: LogcatOptions): ReadableStream<AndroidLogEntry> {
481
+ binary(options?: LogcatOptions): ReadableStream<AndroidLogEntry> {
481
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
+
482
494
  // TODO: make `spawn` return synchronously with streams pending
483
495
  // so it's easier to chain them.
484
- const { stdout } = await this.adb.subprocess.spawn(
485
- [
486
- "logcat",
487
- "-B",
488
- ...(options?.pid ? ["--pid", options.pid.toString()] : []),
489
- ...(options?.ids
490
- ? ["-b", Logcat.joinLogId(options.ids)]
491
- : []),
492
- ],
493
- {
494
- // PERF: None protocol is 150% faster then Shell protocol
495
- protocols: [AdbSubprocessNoneProtocol],
496
- }
497
- );
496
+ const { stdout } = await this.adb.subprocess.spawn(args, {
497
+ // PERF: None protocol is 150% faster then Shell protocol
498
+ protocols: [AdbSubprocessNoneProtocol],
499
+ });
498
500
  return stdout;
499
501
  }).pipeThrough(
500
502
  new BufferedTransformStream((stream) => {
501
503
  return deserializeAndroidLogEntry(stream);
502
- })
504
+ }),
503
505
  );
504
506
  }
505
507
  }