@yume-chan/adb 0.0.16 → 0.0.18
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 +18 -0
- package/CHANGELOG.md +13 -1
- package/LICENSE +1 -1
- package/esm/adb.d.ts +13 -8
- package/esm/adb.d.ts.map +1 -1
- package/esm/adb.js +63 -38
- package/esm/adb.js.map +1 -1
- package/esm/auth.d.ts +4 -4
- package/esm/auth.d.ts.map +1 -1
- package/esm/auth.js +6 -6
- package/esm/auth.js.map +1 -1
- package/esm/backend.d.ts +3 -3
- package/esm/backend.d.ts.map +1 -1
- package/esm/commands/base.d.ts +2 -2
- package/esm/commands/base.d.ts.map +1 -1
- package/esm/commands/base.js +1 -1
- package/esm/commands/base.js.map +1 -1
- package/esm/commands/framebuffer.d.ts +22 -6
- package/esm/commands/framebuffer.d.ts.map +1 -1
- package/esm/commands/framebuffer.js +33 -45
- package/esm/commands/framebuffer.js.map +1 -1
- package/esm/commands/install.d.ts +2 -2
- package/esm/commands/install.d.ts.map +1 -1
- package/esm/commands/install.js +12 -5
- package/esm/commands/install.js.map +1 -1
- package/esm/commands/power.d.ts.map +1 -1
- package/esm/commands/power.js +13 -9
- package/esm/commands/power.js.map +1 -1
- package/esm/commands/reverse.d.ts +5 -5
- package/esm/commands/reverse.d.ts.map +1 -1
- package/esm/commands/reverse.js +20 -18
- package/esm/commands/reverse.js.map +1 -1
- package/esm/commands/subprocess/command.d.ts +52 -0
- package/esm/commands/subprocess/command.d.ts.map +1 -0
- package/esm/commands/subprocess/command.js +81 -0
- package/esm/commands/subprocess/command.js.map +1 -0
- package/esm/commands/subprocess/index.d.ts +1 -53
- package/esm/commands/subprocess/index.d.ts.map +1 -1
- package/esm/commands/subprocess/index.js +1 -85
- package/esm/commands/subprocess/index.js.map +1 -1
- package/esm/commands/subprocess/protocols/none.d.ts +5 -5
- package/esm/commands/subprocess/protocols/none.d.ts.map +1 -1
- package/esm/commands/subprocess/protocols/none.js +5 -3
- package/esm/commands/subprocess/protocols/none.js.map +1 -1
- package/esm/commands/subprocess/protocols/shell.d.ts +4 -4
- package/esm/commands/subprocess/protocols/shell.d.ts.map +1 -1
- package/esm/commands/subprocess/protocols/shell.js +28 -20
- package/esm/commands/subprocess/protocols/shell.js.map +1 -1
- package/esm/commands/subprocess/protocols/types.d.ts +7 -7
- package/esm/commands/subprocess/protocols/types.d.ts.map +1 -1
- package/esm/commands/sync/index.d.ts +1 -1
- package/esm/commands/sync/index.d.ts.map +1 -1
- package/esm/commands/sync/index.js +1 -1
- package/esm/commands/sync/index.js.map +1 -1
- package/esm/commands/sync/list.d.ts +7 -7
- package/esm/commands/sync/list.d.ts.map +1 -1
- package/esm/commands/sync/list.js +34 -50
- package/esm/commands/sync/list.js.map +1 -1
- package/esm/commands/sync/pull.d.ts +5 -4
- package/esm/commands/sync/pull.d.ts.map +1 -1
- package/esm/commands/sync/pull.js +21 -22
- package/esm/commands/sync/pull.js.map +1 -1
- package/esm/commands/sync/push.d.ts +4 -4
- package/esm/commands/sync/push.d.ts.map +1 -1
- package/esm/commands/sync/push.js +7 -11
- package/esm/commands/sync/push.js.map +1 -1
- package/esm/commands/sync/request.d.ts +4 -4
- package/esm/commands/sync/request.d.ts.map +1 -1
- package/esm/commands/sync/request.js +6 -6
- package/esm/commands/sync/request.js.map +1 -1
- package/esm/commands/sync/response.d.ts +5 -10
- package/esm/commands/sync/response.d.ts.map +1 -1
- package/esm/commands/sync/response.js +35 -26
- package/esm/commands/sync/response.js.map +1 -1
- package/esm/commands/sync/stat.d.ts +7 -7
- package/esm/commands/sync/stat.d.ts.map +1 -1
- package/esm/commands/sync/stat.js +48 -55
- package/esm/commands/sync/stat.js.map +1 -1
- package/esm/commands/sync/sync.d.ts +7 -7
- package/esm/commands/sync/sync.d.ts.map +1 -1
- package/esm/commands/sync/sync.js +25 -22
- package/esm/commands/sync/sync.js.map +1 -1
- package/esm/crypto.d.ts.map +1 -1
- package/esm/crypto.js +26 -16
- package/esm/crypto.js.map +1 -1
- package/esm/index.d.ts +9 -10
- package/esm/index.d.ts.map +1 -1
- package/esm/index.js +9 -10
- package/esm/index.js.map +1 -1
- package/esm/packet.d.ts +8 -8
- package/esm/packet.d.ts.map +1 -1
- package/esm/packet.js +14 -12
- package/esm/packet.js.map +1 -1
- package/esm/socket/dispatcher.d.ts +11 -6
- package/esm/socket/dispatcher.d.ts.map +1 -1
- package/esm/socket/dispatcher.js +28 -20
- package/esm/socket/dispatcher.js.map +1 -1
- package/esm/socket/index.d.ts +1 -1
- package/esm/socket/index.d.ts.map +1 -1
- package/esm/socket/index.js +1 -1
- package/esm/socket/index.js.map +1 -1
- package/esm/socket/socket.d.ts +5 -5
- package/esm/socket/socket.d.ts.map +1 -1
- package/esm/socket/socket.js +37 -17
- package/esm/socket/socket.js.map +1 -1
- package/esm/utils/auto-reset-event.d.ts +1 -1
- package/esm/utils/auto-reset-event.d.ts.map +1 -1
- package/esm/utils/auto-reset-event.js +2 -2
- package/esm/utils/base64.d.ts +23 -0
- package/esm/utils/base64.d.ts.map +1 -1
- package/esm/utils/base64.js +36 -29
- package/esm/utils/base64.js.map +1 -1
- package/package.json +19 -17
- package/src/adb.ts +140 -86
- package/src/auth.ts +27 -18
- package/src/backend.ts +7 -4
- package/src/commands/base.ts +3 -2
- package/src/commands/framebuffer.ts +48 -47
- package/src/commands/install.ts +20 -10
- package/src/commands/power.ts +14 -10
- package/src/commands/reverse.ts +53 -33
- package/src/commands/subprocess/command.ts +134 -0
- package/src/commands/subprocess/index.ts +1 -137
- package/src/commands/subprocess/protocols/none.ts +10 -6
- package/src/commands/subprocess/protocols/shell.ts +72 -39
- package/src/commands/subprocess/protocols/types.ts +12 -8
- package/src/commands/sync/index.ts +1 -1
- package/src/commands/sync/list.ts +63 -68
- package/src/commands/sync/pull.ts +53 -37
- package/src/commands/sync/push.ts +26 -15
- package/src/commands/sync/request.ts +20 -21
- package/src/commands/sync/response.ts +63 -53
- package/src/commands/sync/stat.ts +91 -90
- package/src/commands/sync/sync.ts +56 -34
- package/src/crypto.ts +61 -33
- package/src/features.ts +1 -1
- package/src/index.ts +9 -11
- package/src/packet.ts +40 -30
- package/src/socket/dispatcher.ts +119 -77
- package/src/socket/index.ts +1 -1
- package/src/socket/socket.ts +68 -26
- package/src/utils/auto-reset-event.ts +3 -3
- package/src/utils/base64.ts +75 -42
- package/tsconfig.build.json +1 -1
- package/tsconfig.build.tsbuildinfo +1 -1
- package/esm/stream/buffered.d.ts +0 -39
- package/esm/stream/buffered.d.ts.map +0 -1
- package/esm/stream/buffered.js +0 -143
- package/esm/stream/buffered.js.map +0 -1
- package/esm/stream/detect.d.ts +0 -2
- package/esm/stream/detect.d.ts.map +0 -1
- package/esm/stream/detect.js +0 -6
- package/esm/stream/detect.js.map +0 -1
- package/esm/stream/detect.native.d.ts +0 -240
- package/esm/stream/detect.native.d.ts.map +0 -1
- package/esm/stream/detect.native.js +0 -60
- package/esm/stream/detect.native.js.map +0 -1
- package/esm/stream/detect.polyfill.d.ts +0 -18
- package/esm/stream/detect.polyfill.d.ts.map +0 -1
- package/esm/stream/detect.polyfill.js +0 -4
- package/esm/stream/detect.polyfill.js.map +0 -1
- package/esm/stream/index.d.ts +0 -4
- package/esm/stream/index.d.ts.map +0 -1
- package/esm/stream/index.js +0 -4
- package/esm/stream/index.js.map +0 -1
- package/esm/stream/transform.d.ts +0 -124
- package/esm/stream/transform.d.ts.map +0 -1
- package/esm/stream/transform.js +0 -379
- package/esm/stream/transform.js.map +0 -1
- package/src/stream/buffered.ts +0 -168
- package/src/stream/detect.native.ts +0 -362
- package/src/stream/detect.polyfill.ts +0 -22
- package/src/stream/detect.ts +0 -7
- package/src/stream/index.ts +0 -3
- package/src/stream/transform.ts +0 -474
- package/tsconfig.test.json +0 -9
- package/web-streams-polyfill-4.0.0-beta.2.tgz +0 -0
package/src/adb.ts
CHANGED
|
@@ -1,19 +1,50 @@
|
|
|
1
1
|
// cspell: ignore libusb
|
|
2
2
|
|
|
3
|
-
import { PromiseResolver } from
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
3
|
+
import { PromiseResolver } from "@yume-chan/async";
|
|
4
|
+
import {
|
|
5
|
+
AbortController,
|
|
6
|
+
DecodeUtf8Stream,
|
|
7
|
+
GatherStringStream,
|
|
8
|
+
WritableStream,
|
|
9
|
+
type ReadableWritablePair,
|
|
10
|
+
} from "@yume-chan/stream-extra";
|
|
11
|
+
|
|
12
|
+
import {
|
|
13
|
+
ADB_DEFAULT_AUTHENTICATORS,
|
|
14
|
+
AdbAuthenticationProcessor,
|
|
15
|
+
type AdbCredentialStore,
|
|
16
|
+
} from "./auth.js";
|
|
17
|
+
import {
|
|
18
|
+
AdbPower,
|
|
19
|
+
AdbReverseCommand,
|
|
20
|
+
AdbSubprocess,
|
|
21
|
+
AdbSync,
|
|
22
|
+
AdbTcpIpCommand,
|
|
23
|
+
escapeArg,
|
|
24
|
+
framebuffer,
|
|
25
|
+
install,
|
|
26
|
+
type AdbFrameBuffer,
|
|
27
|
+
} from "./commands/index.js";
|
|
28
|
+
import { AdbFeatures } from "./features.js";
|
|
29
|
+
import {
|
|
30
|
+
AdbCommand,
|
|
31
|
+
calculateChecksum,
|
|
32
|
+
type AdbPacketData,
|
|
33
|
+
type AdbPacketInit,
|
|
34
|
+
} from "./packet.js";
|
|
35
|
+
import {
|
|
36
|
+
AdbPacketDispatcher,
|
|
37
|
+
type AdbIncomingSocketHandler,
|
|
38
|
+
type AdbSocket,
|
|
39
|
+
type Closeable,
|
|
40
|
+
} from "./socket/index.js";
|
|
10
41
|
import { decodeUtf8, encodeUtf8 } from "./utils/index.js";
|
|
11
42
|
|
|
12
43
|
export enum AdbPropKey {
|
|
13
|
-
Product =
|
|
14
|
-
Model =
|
|
15
|
-
Device =
|
|
16
|
-
Features =
|
|
44
|
+
Product = "ro.product.name",
|
|
45
|
+
Model = "ro.product.model",
|
|
46
|
+
Device = "ro.product.device",
|
|
47
|
+
Features = "features",
|
|
17
48
|
}
|
|
18
49
|
|
|
19
50
|
export const VERSION_OMIT_CHECKSUM = 0x01000001;
|
|
@@ -27,44 +58,57 @@ export class Adb implements Closeable {
|
|
|
27
58
|
public static async authenticate(
|
|
28
59
|
connection: ReadableWritablePair<AdbPacketData, AdbPacketInit>,
|
|
29
60
|
credentialStore: AdbCredentialStore,
|
|
30
|
-
authenticators = ADB_DEFAULT_AUTHENTICATORS
|
|
61
|
+
authenticators = ADB_DEFAULT_AUTHENTICATORS
|
|
31
62
|
): Promise<Adb> {
|
|
32
63
|
// Initially, set to highest-supported version and payload size.
|
|
33
64
|
let version = 0x01000001;
|
|
34
65
|
let maxPayloadSize = 0x100000;
|
|
35
66
|
|
|
36
67
|
const resolver = new PromiseResolver<string>();
|
|
37
|
-
const authProcessor = new AdbAuthenticationProcessor(
|
|
68
|
+
const authProcessor = new AdbAuthenticationProcessor(
|
|
69
|
+
authenticators,
|
|
70
|
+
credentialStore
|
|
71
|
+
);
|
|
38
72
|
|
|
39
73
|
// Here is similar to `AdbPacketDispatcher`,
|
|
40
74
|
// But the received packet types and send packet processing are different.
|
|
41
75
|
const abortController = new AbortController();
|
|
42
76
|
const pipe = connection.readable
|
|
43
|
-
.pipeTo(
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
77
|
+
.pipeTo(
|
|
78
|
+
new WritableStream({
|
|
79
|
+
async write(packet) {
|
|
80
|
+
switch (packet.command) {
|
|
81
|
+
case AdbCommand.Connect:
|
|
82
|
+
version = Math.min(version, packet.arg0);
|
|
83
|
+
maxPayloadSize = Math.min(
|
|
84
|
+
maxPayloadSize,
|
|
85
|
+
packet.arg1
|
|
86
|
+
);
|
|
87
|
+
resolver.resolve(decodeUtf8(packet.payload));
|
|
88
|
+
break;
|
|
89
|
+
case AdbCommand.Auth: {
|
|
90
|
+
const response = await authProcessor.process(
|
|
91
|
+
packet
|
|
92
|
+
);
|
|
93
|
+
await sendPacket(response);
|
|
94
|
+
break;
|
|
95
|
+
}
|
|
96
|
+
default:
|
|
97
|
+
// Maybe the previous ADB client exited without reading all packets,
|
|
98
|
+
// so they are still waiting in OS internal buffer.
|
|
99
|
+
// Just ignore them.
|
|
100
|
+
// Because a `Connect` packet will reset the device,
|
|
101
|
+
// Eventually there will be `Connect` and `Auth` response packets.
|
|
102
|
+
break;
|
|
103
|
+
}
|
|
104
|
+
},
|
|
105
|
+
}),
|
|
106
|
+
{
|
|
107
|
+
// Don't cancel the source ReadableStream on AbortSignal abort.
|
|
108
|
+
preventCancel: true,
|
|
109
|
+
signal: abortController.signal,
|
|
63
110
|
}
|
|
64
|
-
|
|
65
|
-
preventCancel: true,
|
|
66
|
-
signal: abortController.signal,
|
|
67
|
-
})
|
|
111
|
+
)
|
|
68
112
|
.catch((e) => {
|
|
69
113
|
resolver.reject(e);
|
|
70
114
|
});
|
|
@@ -86,20 +130,20 @@ export class Adb implements Closeable {
|
|
|
86
130
|
AdbFeatures.StatV2,
|
|
87
131
|
AdbFeatures.ListV2,
|
|
88
132
|
AdbFeatures.FixedPushMkdir,
|
|
89
|
-
|
|
90
|
-
|
|
133
|
+
"apex",
|
|
134
|
+
"abb",
|
|
91
135
|
// only tells the client the symlink timestamp issue in `adb push --sync` has been fixed.
|
|
92
136
|
// No special handling required.
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
].join(
|
|
137
|
+
"fixed_push_symlink_timestamp",
|
|
138
|
+
"abb_exec",
|
|
139
|
+
"remount_shell",
|
|
140
|
+
"track_app",
|
|
141
|
+
"sendrecv_v2",
|
|
142
|
+
"sendrecv_v2_brotli",
|
|
143
|
+
"sendrecv_v2_lz4",
|
|
144
|
+
"sendrecv_v2_zstd",
|
|
145
|
+
"sendrecv_v2_dry_run_send",
|
|
146
|
+
].join(",");
|
|
103
147
|
|
|
104
148
|
await sendPacket({
|
|
105
149
|
command: AdbCommand.Connect,
|
|
@@ -121,32 +165,39 @@ export class Adb implements Closeable {
|
|
|
121
165
|
await pipe;
|
|
122
166
|
}
|
|
123
167
|
|
|
124
|
-
return new Adb(
|
|
125
|
-
connection,
|
|
126
|
-
version,
|
|
127
|
-
maxPayloadSize,
|
|
128
|
-
banner,
|
|
129
|
-
);
|
|
168
|
+
return new Adb(connection, version, maxPayloadSize, banner);
|
|
130
169
|
}
|
|
131
170
|
|
|
132
171
|
private readonly dispatcher: AdbPacketDispatcher;
|
|
133
172
|
|
|
134
|
-
public get disconnected() {
|
|
173
|
+
public get disconnected() {
|
|
174
|
+
return this.dispatcher.disconnected;
|
|
175
|
+
}
|
|
135
176
|
|
|
136
177
|
private _protocolVersion: number | undefined;
|
|
137
|
-
public get protocolVersion() {
|
|
178
|
+
public get protocolVersion() {
|
|
179
|
+
return this._protocolVersion;
|
|
180
|
+
}
|
|
138
181
|
|
|
139
182
|
private _product: string | undefined;
|
|
140
|
-
public get product() {
|
|
183
|
+
public get product() {
|
|
184
|
+
return this._product;
|
|
185
|
+
}
|
|
141
186
|
|
|
142
187
|
private _model: string | undefined;
|
|
143
|
-
public get model() {
|
|
188
|
+
public get model() {
|
|
189
|
+
return this._model;
|
|
190
|
+
}
|
|
144
191
|
|
|
145
192
|
private _device: string | undefined;
|
|
146
|
-
public get device() {
|
|
193
|
+
public get device() {
|
|
194
|
+
return this._device;
|
|
195
|
+
}
|
|
147
196
|
|
|
148
|
-
private _features: AdbFeatures[]
|
|
149
|
-
public get features() {
|
|
197
|
+
private _features: AdbFeatures[] = [];
|
|
198
|
+
public get features() {
|
|
199
|
+
return this._features;
|
|
200
|
+
}
|
|
150
201
|
|
|
151
202
|
public readonly subprocess: AdbSubprocess;
|
|
152
203
|
public readonly power: AdbPower;
|
|
@@ -157,7 +208,7 @@ export class Adb implements Closeable {
|
|
|
157
208
|
connection: ReadableWritablePair<AdbPacketData, AdbPacketInit>,
|
|
158
209
|
version: number,
|
|
159
210
|
maxPayloadSize: number,
|
|
160
|
-
banner: string
|
|
211
|
+
banner: string
|
|
161
212
|
) {
|
|
162
213
|
this.parseBanner(banner);
|
|
163
214
|
|
|
@@ -171,14 +222,11 @@ export class Adb implements Closeable {
|
|
|
171
222
|
appendNullToServiceString = true;
|
|
172
223
|
}
|
|
173
224
|
|
|
174
|
-
this.dispatcher = new AdbPacketDispatcher(
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
maxPayloadSize,
|
|
180
|
-
}
|
|
181
|
-
);
|
|
225
|
+
this.dispatcher = new AdbPacketDispatcher(connection, {
|
|
226
|
+
calculateChecksum,
|
|
227
|
+
appendNullToServiceString,
|
|
228
|
+
maxPayloadSize,
|
|
229
|
+
});
|
|
182
230
|
|
|
183
231
|
this._protocolVersion = version;
|
|
184
232
|
|
|
@@ -189,17 +237,15 @@ export class Adb implements Closeable {
|
|
|
189
237
|
}
|
|
190
238
|
|
|
191
239
|
private parseBanner(banner: string): void {
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
const pieces = banner.split('::');
|
|
240
|
+
const pieces = banner.split("::");
|
|
195
241
|
if (pieces.length > 1) {
|
|
196
242
|
const props = pieces[1]!;
|
|
197
|
-
for (const prop of props.split(
|
|
243
|
+
for (const prop of props.split(";")) {
|
|
198
244
|
if (!prop) {
|
|
199
245
|
continue;
|
|
200
246
|
}
|
|
201
247
|
|
|
202
|
-
const keyValue = prop.split(
|
|
248
|
+
const keyValue = prop.split("=");
|
|
203
249
|
if (keyValue.length !== 2) {
|
|
204
250
|
continue;
|
|
205
251
|
}
|
|
@@ -216,15 +262,20 @@ export class Adb implements Closeable {
|
|
|
216
262
|
this._device = value;
|
|
217
263
|
break;
|
|
218
264
|
case AdbPropKey.Features:
|
|
219
|
-
this._features = value!.split(
|
|
265
|
+
this._features = value!.split(",") as AdbFeatures[];
|
|
220
266
|
break;
|
|
221
267
|
}
|
|
222
268
|
}
|
|
223
269
|
}
|
|
224
270
|
}
|
|
225
271
|
|
|
226
|
-
|
|
227
|
-
|
|
272
|
+
/**
|
|
273
|
+
* Add a handler for incoming socket.
|
|
274
|
+
* @param handler A function to call with new incoming sockets. It must return `true` if it accepts the socket.
|
|
275
|
+
* @returns A function to remove the handler.
|
|
276
|
+
*/
|
|
277
|
+
public onIncomingSocket(handler: AdbIncomingSocketHandler) {
|
|
278
|
+
return this.dispatcher.onIncomingSocket(handler);
|
|
228
279
|
}
|
|
229
280
|
|
|
230
281
|
public async createSocket(service: string): Promise<AdbSocket> {
|
|
@@ -241,16 +292,19 @@ export class Adb implements Closeable {
|
|
|
241
292
|
}
|
|
242
293
|
|
|
243
294
|
public async getProp(key: string): Promise<string> {
|
|
244
|
-
const stdout = await this.subprocess.spawnAndWaitLegacy(
|
|
245
|
-
|
|
246
|
-
|
|
295
|
+
const stdout = await this.subprocess.spawnAndWaitLegacy([
|
|
296
|
+
"getprop",
|
|
297
|
+
key,
|
|
298
|
+
]);
|
|
247
299
|
return stdout.trim();
|
|
248
300
|
}
|
|
249
301
|
|
|
250
302
|
public async rm(...filenames: string[]): Promise<string> {
|
|
251
|
-
const stdout = await this.subprocess.spawnAndWaitLegacy(
|
|
252
|
-
|
|
253
|
-
|
|
303
|
+
const stdout = await this.subprocess.spawnAndWaitLegacy([
|
|
304
|
+
"rm",
|
|
305
|
+
"-rf",
|
|
306
|
+
...filenames.map((arg) => escapeArg(arg)),
|
|
307
|
+
]);
|
|
254
308
|
return stdout;
|
|
255
309
|
}
|
|
256
310
|
|
|
@@ -259,7 +313,7 @@ export class Adb implements Closeable {
|
|
|
259
313
|
}
|
|
260
314
|
|
|
261
315
|
public async sync(): Promise<AdbSync> {
|
|
262
|
-
const socket = await this.createSocket(
|
|
316
|
+
const socket = await this.createSocket("sync:");
|
|
263
317
|
return new AdbSync(this, socket);
|
|
264
318
|
}
|
|
265
319
|
|
package/src/auth.ts
CHANGED
|
@@ -1,9 +1,14 @@
|
|
|
1
|
-
import { PromiseResolver } from
|
|
2
|
-
import type
|
|
3
|
-
import type
|
|
4
|
-
|
|
5
|
-
import {
|
|
6
|
-
|
|
1
|
+
import { PromiseResolver } from "@yume-chan/async";
|
|
2
|
+
import { type Disposable } from "@yume-chan/event";
|
|
3
|
+
import { type ValueOrPromise } from "@yume-chan/struct";
|
|
4
|
+
|
|
5
|
+
import {
|
|
6
|
+
calculatePublicKey,
|
|
7
|
+
calculatePublicKeyLength,
|
|
8
|
+
sign,
|
|
9
|
+
} from "./crypto.js";
|
|
10
|
+
import { AdbCommand, type AdbPacketData } from "./packet.js";
|
|
11
|
+
import { calculateBase64EncodedLength, encodeBase64 } from "./utils/index.js";
|
|
7
12
|
|
|
8
13
|
export type AdbKeyIterable = Iterable<Uint8Array> | AsyncIterable<Uint8Array>;
|
|
9
14
|
|
|
@@ -49,7 +54,7 @@ export interface AdbAuthenticator {
|
|
|
49
54
|
|
|
50
55
|
export const AdbSignatureAuthenticator: AdbAuthenticator = async function* (
|
|
51
56
|
credentialStore: AdbCredentialStore,
|
|
52
|
-
getNextRequest: () => Promise<AdbPacketData
|
|
57
|
+
getNextRequest: () => Promise<AdbPacketData>
|
|
53
58
|
): AsyncIterable<AdbPacketData> {
|
|
54
59
|
for await (const key of credentialStore.iterateKeys()) {
|
|
55
60
|
const packet = await getNextRequest();
|
|
@@ -70,7 +75,7 @@ export const AdbSignatureAuthenticator: AdbAuthenticator = async function* (
|
|
|
70
75
|
|
|
71
76
|
export const AdbPublicKeyAuthenticator: AdbAuthenticator = async function* (
|
|
72
77
|
credentialStore: AdbCredentialStore,
|
|
73
|
-
getNextRequest: () => Promise<AdbPacketData
|
|
78
|
+
getNextRequest: () => Promise<AdbPacketData>
|
|
74
79
|
): AsyncIterable<AdbPacketData> {
|
|
75
80
|
const packet = await getNextRequest();
|
|
76
81
|
|
|
@@ -84,23 +89,20 @@ export const AdbPublicKeyAuthenticator: AdbAuthenticator = async function* (
|
|
|
84
89
|
break;
|
|
85
90
|
}
|
|
86
91
|
|
|
87
|
-
|
|
88
92
|
if (!privateKey) {
|
|
89
93
|
privateKey = await credentialStore.generateKey();
|
|
90
94
|
}
|
|
91
95
|
|
|
92
96
|
const publicKeyLength = calculatePublicKeyLength();
|
|
93
|
-
const [publicKeyBase64Length] =
|
|
97
|
+
const [publicKeyBase64Length] =
|
|
98
|
+
calculateBase64EncodedLength(publicKeyLength);
|
|
94
99
|
|
|
95
100
|
// The public key is null terminated,
|
|
96
101
|
// So we allocate the buffer with one extra byte.
|
|
97
102
|
const publicKeyBuffer = new Uint8Array(publicKeyBase64Length + 1);
|
|
98
103
|
|
|
99
104
|
calculatePublicKey(privateKey, publicKeyBuffer);
|
|
100
|
-
encodeBase64(
|
|
101
|
-
publicKeyBuffer.subarray(0, publicKeyLength),
|
|
102
|
-
publicKeyBuffer
|
|
103
|
-
);
|
|
105
|
+
encodeBase64(publicKeyBuffer.subarray(0, publicKeyLength), publicKeyBuffer);
|
|
104
106
|
|
|
105
107
|
yield {
|
|
106
108
|
command: AdbCommand.Auth,
|
|
@@ -136,9 +138,16 @@ export class AdbAuthenticationProcessor implements Disposable {
|
|
|
136
138
|
return this.pendingRequest.promise;
|
|
137
139
|
};
|
|
138
140
|
|
|
139
|
-
private async*
|
|
141
|
+
private async *invokeAuthenticator(): AsyncGenerator<
|
|
142
|
+
AdbPacketData,
|
|
143
|
+
void,
|
|
144
|
+
void
|
|
145
|
+
> {
|
|
140
146
|
for (const authenticator of this.authenticators) {
|
|
141
|
-
for await (const packet of authenticator(
|
|
147
|
+
for await (const packet of authenticator(
|
|
148
|
+
this.credentialStore,
|
|
149
|
+
this.getNextRequest
|
|
150
|
+
)) {
|
|
142
151
|
// If the authenticator yielded a response
|
|
143
152
|
// Prepare `nextRequest` for next authentication request
|
|
144
153
|
this.pendingRequest = new PromiseResolver();
|
|
@@ -161,13 +170,13 @@ export class AdbAuthenticationProcessor implements Disposable {
|
|
|
161
170
|
|
|
162
171
|
const result = await this.iterator.next();
|
|
163
172
|
if (result.done) {
|
|
164
|
-
throw new Error(
|
|
173
|
+
throw new Error("No authenticator can handle the request");
|
|
165
174
|
}
|
|
166
175
|
|
|
167
176
|
return result.value;
|
|
168
177
|
}
|
|
169
178
|
|
|
170
179
|
public dispose() {
|
|
171
|
-
this.iterator?.return?.();
|
|
180
|
+
void this.iterator?.return?.();
|
|
172
181
|
}
|
|
173
182
|
}
|
package/src/backend.ts
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
|
-
import type
|
|
2
|
-
import
|
|
3
|
-
|
|
1
|
+
import { type ReadableWritablePair } from "@yume-chan/stream-extra";
|
|
2
|
+
import { type ValueOrPromise } from "@yume-chan/struct";
|
|
3
|
+
|
|
4
|
+
import { type AdbPacketData, type AdbPacketInit } from "./packet.js";
|
|
4
5
|
|
|
5
6
|
export interface AdbBackend {
|
|
6
7
|
readonly serial: string;
|
|
7
8
|
|
|
8
9
|
readonly name: string | undefined;
|
|
9
10
|
|
|
10
|
-
connect(): ValueOrPromise<
|
|
11
|
+
connect(): ValueOrPromise<
|
|
12
|
+
ReadableWritablePair<AdbPacketData, AdbPacketInit>
|
|
13
|
+
>;
|
|
11
14
|
}
|
package/src/commands/base.ts
CHANGED
|
@@ -1,14 +1,50 @@
|
|
|
1
|
+
import { BufferedReadableStream } from "@yume-chan/stream-extra";
|
|
1
2
|
import Struct from "@yume-chan/struct";
|
|
2
|
-
import type { Adb } from '../adb.js';
|
|
3
|
-
import { AdbBufferedStream } from '../stream/index.js';
|
|
4
3
|
|
|
5
|
-
|
|
6
|
-
new Struct({ littleEndian: true })
|
|
7
|
-
.uint32('version');
|
|
4
|
+
import { type Adb } from "../adb.js";
|
|
8
5
|
|
|
9
|
-
|
|
6
|
+
const Version = new Struct({ littleEndian: true }).uint32("version");
|
|
7
|
+
|
|
8
|
+
export const AdbFrameBufferV1 = new Struct({ littleEndian: true })
|
|
9
|
+
.uint32("bpp")
|
|
10
|
+
.uint32("size")
|
|
11
|
+
.uint32("width")
|
|
12
|
+
.uint32("height")
|
|
13
|
+
.uint32("red_offset")
|
|
14
|
+
.uint32("red_length")
|
|
15
|
+
.uint32("blue_offset")
|
|
16
|
+
.uint32("blue_length")
|
|
17
|
+
.uint32("green_offset")
|
|
18
|
+
.uint32("green_length")
|
|
19
|
+
.uint32("alpha_offset")
|
|
20
|
+
.uint32("alpha_length")
|
|
21
|
+
.uint8Array("data", { lengthField: "size" });
|
|
22
|
+
|
|
23
|
+
export type AdbFrameBufferV1 = typeof AdbFrameBufferV1["TDeserializeResult"];
|
|
24
|
+
|
|
25
|
+
export const AdbFrameBufferV2 = new Struct({ littleEndian: true })
|
|
26
|
+
.uint32("bpp")
|
|
27
|
+
.uint32("colorSpace")
|
|
28
|
+
.uint32("size")
|
|
29
|
+
.uint32("width")
|
|
30
|
+
.uint32("height")
|
|
31
|
+
.uint32("red_offset")
|
|
32
|
+
.uint32("red_length")
|
|
33
|
+
.uint32("blue_offset")
|
|
34
|
+
.uint32("blue_length")
|
|
35
|
+
.uint32("green_offset")
|
|
36
|
+
.uint32("green_length")
|
|
37
|
+
.uint32("alpha_offset")
|
|
38
|
+
.uint32("alpha_length")
|
|
39
|
+
.uint8Array("data", { lengthField: "size" });
|
|
40
|
+
|
|
41
|
+
export type AdbFrameBufferV2 = typeof AdbFrameBufferV2["TDeserializeResult"];
|
|
42
|
+
|
|
43
|
+
/**
|
|
10
44
|
* ADB uses 8 int32 fields to describe bit depths
|
|
45
|
+
*
|
|
11
46
|
* The only combination I have seen is RGBA8888, which is
|
|
47
|
+
*
|
|
12
48
|
* red_offset: 0
|
|
13
49
|
* red_length: 8
|
|
14
50
|
* blue_offset: 16
|
|
@@ -17,57 +53,22 @@ const Version =
|
|
|
17
53
|
* green_length: 8
|
|
18
54
|
* alpha_offset: 24
|
|
19
55
|
* alpha_length: 8
|
|
56
|
+
*
|
|
57
|
+
* But it doesn't mean that other combinations are not possible.
|
|
20
58
|
*/
|
|
21
|
-
|
|
22
|
-
export const AdbFrameBufferV1 =
|
|
23
|
-
new Struct({ littleEndian: true })
|
|
24
|
-
.uint32('bpp')
|
|
25
|
-
.uint32('size')
|
|
26
|
-
.uint32('width')
|
|
27
|
-
.uint32('height')
|
|
28
|
-
.uint32('red_offset')
|
|
29
|
-
.uint32('red_length')
|
|
30
|
-
.uint32('blue_offset')
|
|
31
|
-
.uint32('blue_length')
|
|
32
|
-
.uint32('green_offset')
|
|
33
|
-
.uint32('green_length')
|
|
34
|
-
.uint32('alpha_offset')
|
|
35
|
-
.uint32('alpha_length')
|
|
36
|
-
.uint8Array('data', { lengthField: 'size' });
|
|
37
|
-
|
|
38
|
-
export type AdbFrameBufferV1 = typeof AdbFrameBufferV1['TDeserializeResult'];
|
|
39
|
-
|
|
40
|
-
export const AdbFrameBufferV2 =
|
|
41
|
-
new Struct({ littleEndian: true })
|
|
42
|
-
.uint32('bpp')
|
|
43
|
-
.uint32('colorSpace')
|
|
44
|
-
.uint32('size')
|
|
45
|
-
.uint32('width')
|
|
46
|
-
.uint32('height')
|
|
47
|
-
.uint32('red_offset')
|
|
48
|
-
.uint32('red_length')
|
|
49
|
-
.uint32('blue_offset')
|
|
50
|
-
.uint32('blue_length')
|
|
51
|
-
.uint32('green_offset')
|
|
52
|
-
.uint32('green_length')
|
|
53
|
-
.uint32('alpha_offset')
|
|
54
|
-
.uint32('alpha_length')
|
|
55
|
-
.uint8Array('data', { lengthField: 'size' });
|
|
56
|
-
|
|
57
|
-
export type AdbFrameBufferV2 = typeof AdbFrameBufferV2['TDeserializeResult'];
|
|
58
|
-
|
|
59
59
|
export type AdbFrameBuffer = AdbFrameBufferV1 | AdbFrameBufferV2;
|
|
60
60
|
|
|
61
61
|
export async function framebuffer(adb: Adb): Promise<AdbFrameBuffer> {
|
|
62
|
-
const socket = await adb.createSocket(
|
|
63
|
-
const stream = new
|
|
62
|
+
const socket = await adb.createSocket("framebuffer:");
|
|
63
|
+
const stream = new BufferedReadableStream(socket.readable);
|
|
64
64
|
const { version } = await Version.deserialize(stream);
|
|
65
65
|
switch (version) {
|
|
66
66
|
case 1:
|
|
67
|
+
// TODO: AdbFrameBuffer: does all v1 responses uses the same color space? Add it so the command returns same format for all versions.
|
|
67
68
|
return AdbFrameBufferV1.deserialize(stream);
|
|
68
69
|
case 2:
|
|
69
70
|
return AdbFrameBufferV2.deserialize(stream);
|
|
70
71
|
default:
|
|
71
|
-
throw new Error(
|
|
72
|
+
throw new Error("Unknown FrameBuffer version");
|
|
72
73
|
}
|
|
73
74
|
}
|
package/src/commands/install.ts
CHANGED
|
@@ -1,30 +1,40 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
1
|
+
import {
|
|
2
|
+
WrapWritableStream,
|
|
3
|
+
type WritableStream,
|
|
4
|
+
} from "@yume-chan/stream-extra";
|
|
5
|
+
|
|
6
|
+
import { type Adb } from "../adb.js";
|
|
7
|
+
|
|
3
8
|
import { escapeArg } from "./subprocess/index.js";
|
|
4
|
-
import type
|
|
9
|
+
import { type AdbSync } from "./sync/index.js";
|
|
5
10
|
|
|
6
|
-
export function install(
|
|
7
|
-
|
|
8
|
-
)
|
|
9
|
-
|
|
11
|
+
export function install(adb: Adb): WritableStream<Uint8Array> {
|
|
12
|
+
const filename = `/data/local/tmp/${Math.random()
|
|
13
|
+
.toString()
|
|
14
|
+
.substring(2)}.apk`;
|
|
10
15
|
|
|
11
16
|
let sync!: AdbSync;
|
|
12
17
|
return new WrapWritableStream<Uint8Array>({
|
|
13
18
|
async start() {
|
|
14
19
|
// TODO: install: support other install apk methods (streaming, etc.)
|
|
20
|
+
// TODO: install: support split apk formats (`adb install-multiple`)
|
|
15
21
|
|
|
16
22
|
// Upload apk file to tmp folder
|
|
17
23
|
sync = await adb.sync();
|
|
18
24
|
return sync.write(filename, undefined, undefined);
|
|
19
25
|
},
|
|
20
26
|
async close() {
|
|
21
|
-
sync.dispose();
|
|
27
|
+
await sync.dispose();
|
|
22
28
|
|
|
23
29
|
// Invoke `pm install` to install it
|
|
24
|
-
await adb.subprocess.spawnAndWaitLegacy([
|
|
30
|
+
await adb.subprocess.spawnAndWaitLegacy([
|
|
31
|
+
"pm",
|
|
32
|
+
"install",
|
|
33
|
+
escapeArg(filename),
|
|
34
|
+
]);
|
|
25
35
|
|
|
26
36
|
// Remove the temp file
|
|
27
37
|
await adb.rm(filename);
|
|
28
|
-
}
|
|
38
|
+
},
|
|
29
39
|
});
|
|
30
40
|
}
|