@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.
- package/CHANGELOG.json +36 -0
- package/CHANGELOG.md +19 -1
- package/LICENSE +21 -0
- package/esm/bu.d.ts +20 -7
- package/esm/bu.d.ts.map +1 -1
- package/esm/bu.js +47 -8
- package/esm/bu.js.map +1 -1
- package/esm/bug-report.d.ts +82 -21
- package/esm/bug-report.d.ts.map +1 -1
- package/esm/bug-report.js +189 -55
- package/esm/bug-report.js.map +1 -1
- package/esm/cmd.d.ts +4 -6
- package/esm/cmd.d.ts.map +1 -1
- package/esm/cmd.js +39 -24
- package/esm/cmd.js.map +1 -1
- package/esm/demo-mode.d.ts +3 -3
- package/esm/demo-mode.d.ts.map +1 -1
- package/esm/demo-mode.js +14 -15
- package/esm/demo-mode.js.map +1 -1
- package/esm/dumpsys.d.ts +21 -0
- package/esm/dumpsys.d.ts.map +1 -0
- package/esm/dumpsys.js +82 -0
- package/esm/dumpsys.js.map +1 -0
- package/esm/index.d.ts +3 -0
- package/esm/index.d.ts.map +1 -1
- package/esm/index.js +3 -0
- package/esm/index.js.map +1 -1
- package/esm/logcat.d.ts +3 -2
- package/esm/logcat.d.ts.map +1 -1
- package/esm/logcat.js +34 -24
- package/esm/logcat.js.map +1 -1
- package/esm/overlay-display.d.ts +20 -3
- package/esm/overlay-display.d.ts.map +1 -1
- package/esm/overlay-display.js +34 -61
- package/esm/overlay-display.js.map +1 -1
- package/esm/pm.d.ts +25 -2
- package/esm/pm.d.ts.map +1 -1
- package/esm/pm.js +88 -17
- package/esm/pm.js.map +1 -1
- package/esm/settings.d.ts +21 -8
- package/esm/settings.d.ts.map +1 -1
- package/esm/settings.js +55 -19
- package/esm/settings.js.map +1 -1
- package/esm/string-format.d.ts +40 -0
- package/esm/string-format.d.ts.map +1 -0
- package/esm/string-format.js +153 -0
- package/esm/string-format.js.map +1 -0
- package/package.json +13 -8
- package/src/bu.ts +68 -14
- package/src/bug-report.ts +236 -70
- package/src/cmd.ts +67 -33
- package/src/demo-mode.ts +47 -43
- package/src/dumpsys.ts +91 -0
- package/src/index.ts +3 -0
- package/src/logcat.ts +63 -74
- package/src/overlay-display.ts +82 -85
- package/src/pm.ts +149 -27
- package/src/settings.ts +99 -50
- package/src/string-format.ts +199 -0
- package/tsconfig.build.json +11 -0
- 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
|
-
|
|
55
|
+
#settings: Settings;
|
|
56
56
|
|
|
57
57
|
constructor(adb: Adb) {
|
|
58
58
|
super(adb);
|
|
59
|
-
this
|
|
59
|
+
this.#settings = new Settings(adb);
|
|
60
60
|
}
|
|
61
61
|
|
|
62
|
-
|
|
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
|
-
|
|
67
|
+
static readonly ENABLED_SETTING_KEY = "sysui_tuner_demo_on";
|
|
68
68
|
|
|
69
|
-
|
|
70
|
-
const output = await this
|
|
69
|
+
async getAllowed(): Promise<boolean> {
|
|
70
|
+
const output = await this.#settings.get(
|
|
71
71
|
"global",
|
|
72
|
-
DemoMode.
|
|
72
|
+
DemoMode.ALLOWED_SETTING_KEY,
|
|
73
73
|
);
|
|
74
|
-
return output
|
|
74
|
+
return output === "1";
|
|
75
75
|
}
|
|
76
76
|
|
|
77
|
-
|
|
77
|
+
async setAllowed(value: boolean): Promise<void> {
|
|
78
78
|
if (value) {
|
|
79
|
-
await this
|
|
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
|
|
86
|
+
await this.#settings.delete("global", DemoMode.ALLOWED_SETTING_KEY);
|
|
83
87
|
}
|
|
84
88
|
}
|
|
85
89
|
|
|
86
|
-
|
|
87
|
-
const result = await this
|
|
90
|
+
async getEnabled(): Promise<boolean> {
|
|
91
|
+
const result = await this.#settings.get(
|
|
88
92
|
"global",
|
|
89
|
-
DemoMode.
|
|
93
|
+
DemoMode.ENABLED_SETTING_KEY,
|
|
90
94
|
);
|
|
91
|
-
return result
|
|
95
|
+
return result === "1";
|
|
92
96
|
}
|
|
93
97
|
|
|
94
|
-
|
|
98
|
+
async setEnabled(value: boolean): Promise<void> {
|
|
95
99
|
if (value) {
|
|
96
|
-
await this
|
|
100
|
+
await this.#settings.put(
|
|
101
|
+
"global",
|
|
102
|
+
DemoMode.ENABLED_SETTING_KEY,
|
|
103
|
+
"1",
|
|
104
|
+
);
|
|
97
105
|
} else {
|
|
98
|
-
await this
|
|
106
|
+
await this.#settings.delete("global", DemoMode.ENABLED_SETTING_KEY);
|
|
99
107
|
await this.broadcast("exit");
|
|
100
108
|
}
|
|
101
109
|
}
|
|
102
110
|
|
|
103
|
-
|
|
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
|
-
|
|
133
|
+
async setBatteryLevel(level: number): Promise<void> {
|
|
126
134
|
await this.broadcast("battery", { level: level.toString() });
|
|
127
135
|
}
|
|
128
136
|
|
|
129
|
-
|
|
137
|
+
async setBatteryCharging(value: boolean): Promise<void> {
|
|
130
138
|
await this.broadcast("battery", { plugged: value.toString() });
|
|
131
139
|
}
|
|
132
140
|
|
|
133
|
-
|
|
141
|
+
async setPowerSaveMode(value: boolean): Promise<void> {
|
|
134
142
|
await this.broadcast("battery", { powersave: value.toString() });
|
|
135
143
|
}
|
|
136
144
|
|
|
137
|
-
|
|
145
|
+
async setAirplaneMode(show: boolean): Promise<void> {
|
|
138
146
|
await this.broadcast("network", { airplane: show ? "show" : "hide" });
|
|
139
147
|
}
|
|
140
148
|
|
|
141
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
177
|
+
async setNoSimCardIcon(show: boolean): Promise<void> {
|
|
174
178
|
await this.broadcast("network", { nosim: show ? "show" : "hide" });
|
|
175
179
|
}
|
|
176
180
|
|
|
177
|
-
|
|
181
|
+
async setStatusBarMode(mode: DemoModeStatusBarMode): Promise<void> {
|
|
178
182
|
await this.broadcast("bars", { mode });
|
|
179
183
|
}
|
|
180
184
|
|
|
181
|
-
|
|
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
|
-
|
|
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
|
-
|
|
197
|
+
async setLocatingIcon(show: boolean): Promise<void> {
|
|
194
198
|
await this.broadcast("status", { location: show ? "show" : "hide" });
|
|
195
199
|
}
|
|
196
200
|
|
|
197
|
-
|
|
201
|
+
async setAlarmIcon(show: boolean): Promise<void> {
|
|
198
202
|
await this.broadcast("status", { alarm: show ? "show" : "hide" });
|
|
199
203
|
}
|
|
200
204
|
|
|
201
|
-
|
|
205
|
+
async setSyncingIcon(show: boolean): Promise<void> {
|
|
202
206
|
await this.broadcast("status", { sync: show ? "show" : "hide" });
|
|
203
207
|
}
|
|
204
208
|
|
|
205
|
-
|
|
209
|
+
async setMuteIcon(show: boolean): Promise<void> {
|
|
206
210
|
await this.broadcast("status", { mute: show ? "show" : "hide" });
|
|
207
211
|
}
|
|
208
212
|
|
|
209
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 {
|
|
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
|
|
126
|
+
return padZero(seconds, 6);
|
|
122
127
|
}
|
|
123
128
|
|
|
124
129
|
if (modifiers.epoch) {
|
|
125
|
-
return seconds
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
155
|
+
return padZero(nanoseconds, 9);
|
|
167
156
|
}
|
|
168
157
|
|
|
169
158
|
if (modifiers.microseconds) {
|
|
170
|
-
return (
|
|
159
|
+
return padZero(nanoseconds / 1000, 6);
|
|
171
160
|
}
|
|
172
161
|
|
|
173
|
-
return (
|
|
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:
|
|
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.
|
|
356
|
+
await stream.readExactly(entry.headerSize - LoggerEntry.size);
|
|
370
357
|
}
|
|
371
|
-
|
|
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
|
-
|
|
386
|
+
static logIdToName(id: LogId): string {
|
|
399
387
|
return LogId[id]!;
|
|
400
388
|
}
|
|
401
389
|
|
|
402
|
-
|
|
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
|
-
|
|
395
|
+
static joinLogId(ids: LogId[]): string {
|
|
408
396
|
return ids.map((id) => Logcat.logIdToName(id)).join(",");
|
|
409
397
|
}
|
|
410
398
|
|
|
411
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
500
|
-
|
|
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
|
}
|