@yume-chan/adb 0.0.19 → 0.0.20
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 +33 -0
- package/CHANGELOG.md +15 -1
- package/README.md +220 -103
- package/esm/adb.d.ts +24 -44
- package/esm/adb.d.ts.map +1 -1
- package/esm/adb.js +14 -203
- package/esm/adb.js.map +1 -1
- package/esm/banner.d.ts +17 -0
- package/esm/banner.d.ts.map +1 -0
- package/esm/banner.js +67 -0
- package/esm/banner.js.map +1 -0
- package/esm/commands/power.d.ts +1 -1
- package/esm/commands/power.js +2 -2
- package/esm/commands/reverse.d.ts +17 -18
- package/esm/commands/reverse.d.ts.map +1 -1
- package/esm/commands/reverse.js +53 -48
- package/esm/commands/reverse.js.map +1 -1
- package/esm/commands/subprocess/protocols/none.d.ts +3 -8
- package/esm/commands/subprocess/protocols/none.d.ts.map +1 -1
- package/esm/commands/subprocess/protocols/none.js +16 -16
- package/esm/commands/subprocess/protocols/none.js.map +1 -1
- package/esm/commands/subprocess/protocols/shell.d.ts +3 -9
- package/esm/commands/subprocess/protocols/shell.d.ts.map +1 -1
- package/esm/commands/subprocess/protocols/shell.js +48 -42
- package/esm/commands/subprocess/protocols/shell.js.map +1 -1
- package/esm/commands/subprocess/protocols/types.d.ts +1 -2
- package/esm/commands/subprocess/protocols/types.d.ts.map +1 -1
- package/esm/commands/sync/list.js +2 -2
- package/esm/commands/sync/push.d.ts +14 -3
- package/esm/commands/sync/push.d.ts.map +1 -1
- package/esm/commands/sync/push.js +8 -8
- package/esm/commands/sync/push.js.map +1 -1
- package/esm/commands/sync/request.js +1 -1
- package/esm/commands/sync/response.d.ts +3 -3
- package/esm/commands/sync/response.d.ts.map +1 -1
- package/esm/commands/sync/response.js +3 -3
- package/esm/commands/sync/response.js.map +1 -1
- package/esm/commands/sync/socket.d.ts +8 -13
- package/esm/commands/sync/socket.d.ts.map +1 -1
- package/esm/commands/sync/socket.js +32 -29
- package/esm/commands/sync/socket.js.map +1 -1
- package/esm/commands/sync/stat.js +2 -2
- package/esm/commands/sync/stat.js.map +1 -1
- package/esm/commands/sync/sync.d.ts +11 -18
- package/esm/commands/sync/sync.d.ts.map +1 -1
- package/esm/commands/sync/sync.js +19 -23
- package/esm/commands/sync/sync.js.map +1 -1
- package/esm/commands/tcpip.d.ts +2 -2
- package/esm/commands/tcpip.d.ts.map +1 -1
- package/esm/commands/tcpip.js +4 -2
- package/esm/commands/tcpip.js.map +1 -1
- package/esm/{auth.d.ts → daemon/auth.d.ts} +1 -2
- package/esm/daemon/auth.d.ts.map +1 -0
- package/esm/{auth.js → daemon/auth.js} +14 -14
- package/esm/daemon/auth.js.map +1 -0
- package/esm/daemon/connection.d.ts +11 -0
- package/esm/daemon/connection.d.ts.map +1 -0
- package/esm/daemon/connection.js +2 -0
- package/esm/daemon/connection.js.map +1 -0
- package/esm/{crypto.d.ts → daemon/crypto.d.ts} +5 -5
- package/esm/daemon/crypto.d.ts.map +1 -0
- package/esm/{crypto.js → daemon/crypto.js} +23 -27
- package/esm/daemon/crypto.js.map +1 -0
- package/esm/{backend.d.ts → daemon/device.d.ts} +2 -2
- package/esm/daemon/device.d.ts.map +1 -0
- package/esm/daemon/device.js +2 -0
- package/esm/daemon/device.js.map +1 -0
- package/esm/{socket → daemon}/dispatcher.d.ts +8 -26
- package/esm/daemon/dispatcher.d.ts.map +1 -0
- package/esm/{socket → daemon}/dispatcher.js +65 -63
- package/esm/daemon/dispatcher.js.map +1 -0
- package/esm/daemon/index.d.ts +8 -0
- package/esm/daemon/index.d.ts.map +1 -0
- package/esm/daemon/index.js +8 -0
- package/esm/daemon/index.js.map +1 -0
- package/esm/{packet.d.ts → daemon/packet.d.ts} +4 -4
- package/esm/daemon/packet.d.ts.map +1 -0
- package/esm/{packet.js → daemon/packet.js} +1 -1
- package/esm/daemon/packet.js.map +1 -0
- package/esm/{socket → daemon}/socket.d.ts +15 -17
- package/esm/daemon/socket.d.ts.map +1 -0
- package/esm/{socket → daemon}/socket.js +38 -35
- package/esm/daemon/socket.js.map +1 -0
- package/esm/daemon/transport.d.ts +45 -0
- package/esm/daemon/transport.d.ts.map +1 -0
- package/esm/daemon/transport.js +184 -0
- package/esm/daemon/transport.js.map +1 -0
- package/esm/index.d.ts +3 -5
- package/esm/index.d.ts.map +1 -1
- package/esm/index.js +3 -5
- package/esm/index.js.map +1 -1
- package/esm/server/client.d.ts +78 -0
- package/esm/server/client.d.ts.map +1 -0
- package/esm/server/client.js +329 -0
- package/esm/server/client.js.map +1 -0
- package/esm/server/index.d.ts +3 -0
- package/esm/server/index.d.ts.map +1 -0
- package/esm/server/index.js +3 -0
- package/esm/server/index.js.map +1 -0
- package/esm/server/transport.d.ts +19 -0
- package/esm/server/transport.d.ts.map +1 -0
- package/esm/server/transport.js +44 -0
- package/esm/server/transport.js.map +1 -0
- package/esm/utils/auto-reset-event.d.ts +1 -2
- package/esm/utils/auto-reset-event.d.ts.map +1 -1
- package/esm/utils/auto-reset-event.js +12 -12
- package/esm/utils/auto-reset-event.js.map +1 -1
- package/esm/utils/base64.js +5 -5
- package/esm/utils/base64.js.map +1 -1
- package/esm/utils/conditional-variable.d.ts +1 -2
- package/esm/utils/conditional-variable.d.ts.map +1 -1
- package/esm/utils/conditional-variable.js +10 -10
- package/esm/utils/conditional-variable.js.map +1 -1
- package/esm/utils/hex.d.ts +3 -0
- package/esm/utils/hex.d.ts.map +1 -0
- package/esm/utils/hex.js +55 -0
- package/esm/utils/hex.js.map +1 -0
- package/esm/utils/index.d.ts +2 -0
- package/esm/utils/index.d.ts.map +1 -1
- package/esm/utils/index.js +2 -0
- package/esm/utils/index.js.map +1 -1
- package/esm/utils/no-op.d.ts +7 -0
- package/esm/utils/no-op.d.ts.map +1 -0
- package/esm/utils/no-op.js +12 -0
- package/esm/utils/no-op.js.map +1 -0
- package/package.json +11 -10
- package/src/adb.ts +41 -252
- package/src/banner.ts +82 -0
- package/src/commands/power.ts +2 -2
- package/src/commands/reverse.ts +68 -73
- package/src/commands/subprocess/protocols/none.ts +17 -18
- package/src/commands/subprocess/protocols/shell.ts +54 -56
- package/src/commands/subprocess/protocols/types.ts +1 -2
- package/src/commands/sync/list.ts +2 -2
- package/src/commands/sync/push.ts +22 -10
- package/src/commands/sync/request.ts +1 -1
- package/src/commands/sync/response.ts +6 -6
- package/src/commands/sync/socket.ts +37 -35
- package/src/commands/sync/sync.ts +25 -28
- package/src/commands/tcpip.ts +6 -4
- package/src/{auth.ts → daemon/auth.ts} +17 -17
- package/src/{crypto.ts → daemon/crypto.ts} +25 -33
- package/src/{backend.ts → daemon/device.ts} +1 -1
- package/src/{socket → daemon}/dispatcher.ts +71 -78
- package/src/daemon/index.ts +7 -0
- package/src/{packet.ts → daemon/packet.ts} +5 -5
- package/src/{socket → daemon}/socket.ts +50 -44
- package/src/daemon/transport.ts +269 -0
- package/src/index.ts +3 -5
- package/src/server/client.ts +476 -0
- package/src/server/index.ts +2 -0
- package/src/server/transport.ts +77 -0
- package/src/utils/auto-reset-event.ts +12 -12
- package/src/utils/conditional-variable.ts +10 -10
- package/src/utils/hex.ts +58 -0
- package/src/utils/index.ts +2 -0
- package/src/utils/no-op.ts +12 -0
- package/tsconfig.build.json +12 -1
- package/tsconfig.build.tsbuildinfo +1 -1
- package/esm/auth.d.ts.map +0 -1
- package/esm/auth.js.map +0 -1
- package/esm/backend.d.ts.map +0 -1
- package/esm/backend.js +0 -2
- package/esm/backend.js.map +0 -1
- package/esm/commands/install.d.ts +0 -10
- package/esm/commands/install.d.ts.map +0 -1
- package/esm/commands/install.js +0 -29
- package/esm/commands/install.js.map +0 -1
- package/esm/crypto.d.ts.map +0 -1
- package/esm/crypto.js.map +0 -1
- package/esm/packet.d.ts.map +0 -1
- package/esm/packet.js.map +0 -1
- package/esm/socket/dispatcher.d.ts.map +0 -1
- package/esm/socket/dispatcher.js.map +0 -1
- package/esm/socket/index.d.ts +0 -3
- package/esm/socket/index.d.ts.map +0 -1
- package/esm/socket/index.js +0 -3
- package/esm/socket/index.js.map +0 -1
- package/esm/socket/socket.d.ts.map +0 -1
- package/esm/socket/socket.js.map +0 -1
- package/src/socket/index.ts +0 -2
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
import { PromiseResolver } from "@yume-chan/async";
|
|
2
|
+
import type { Consumable, ReadableWritablePair } from "@yume-chan/stream-extra";
|
|
3
|
+
import {
|
|
4
|
+
AbortController,
|
|
5
|
+
ConsumableWritableStream,
|
|
6
|
+
WritableStream,
|
|
7
|
+
} from "@yume-chan/stream-extra";
|
|
8
|
+
import type { ValueOrPromise } from "@yume-chan/struct";
|
|
9
|
+
import { decodeUtf8, encodeUtf8 } from "@yume-chan/struct";
|
|
10
|
+
|
|
11
|
+
import type {
|
|
12
|
+
AdbIncomingSocketHandler,
|
|
13
|
+
AdbSocket,
|
|
14
|
+
AdbTransport,
|
|
15
|
+
} from "../adb.js";
|
|
16
|
+
import { AdbBanner } from "../banner.js";
|
|
17
|
+
import { AdbFeature } from "../features.js";
|
|
18
|
+
|
|
19
|
+
import type { AdbAuthenticator, AdbCredentialStore } from "./auth.js";
|
|
20
|
+
import {
|
|
21
|
+
ADB_DEFAULT_AUTHENTICATORS,
|
|
22
|
+
AdbAuthenticationProcessor,
|
|
23
|
+
} from "./auth.js";
|
|
24
|
+
import { AdbPacketDispatcher } from "./dispatcher.js";
|
|
25
|
+
import type { AdbPacketData, AdbPacketInit } from "./packet.js";
|
|
26
|
+
import { AdbCommand, calculateChecksum } from "./packet.js";
|
|
27
|
+
|
|
28
|
+
export const ADB_DAEMON_VERSION_OMIT_CHECKSUM = 0x01000001;
|
|
29
|
+
|
|
30
|
+
interface AdbDaemonAuthenticationOptions {
|
|
31
|
+
serial: string;
|
|
32
|
+
connection: ReadableWritablePair<AdbPacketData, Consumable<AdbPacketInit>>;
|
|
33
|
+
credentialStore: AdbCredentialStore;
|
|
34
|
+
authenticators?: AdbAuthenticator[];
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
interface AdbDaemonSocketConnectorConstructionOptions {
|
|
38
|
+
serial: string;
|
|
39
|
+
connection: ReadableWritablePair<AdbPacketData, Consumable<AdbPacketInit>>;
|
|
40
|
+
version: number;
|
|
41
|
+
maxPayloadSize: number;
|
|
42
|
+
banner: string;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export class AdbDaemonTransport implements AdbTransport {
|
|
46
|
+
/**
|
|
47
|
+
* Authenticates the connection and creates an `AdbDaemonTransport` instance
|
|
48
|
+
* that can be used by `Adb` class.
|
|
49
|
+
*
|
|
50
|
+
* If an authentication process failed, it's possible to call `authenticate` again
|
|
51
|
+
* on the same connection. Because every time the device receives a `CNXN` packet,
|
|
52
|
+
* it resets all internal state, and starts a new authentication process.
|
|
53
|
+
*/
|
|
54
|
+
public static async authenticate({
|
|
55
|
+
serial,
|
|
56
|
+
connection,
|
|
57
|
+
credentialStore,
|
|
58
|
+
authenticators = ADB_DEFAULT_AUTHENTICATORS,
|
|
59
|
+
}: AdbDaemonAuthenticationOptions): Promise<AdbDaemonTransport> {
|
|
60
|
+
// Initially, set to highest-supported version and payload size.
|
|
61
|
+
let version = 0x01000001;
|
|
62
|
+
// Android 4: 4K, Android 7: 256K, Android 9: 1M
|
|
63
|
+
let maxPayloadSize = 1024 * 1024;
|
|
64
|
+
|
|
65
|
+
const resolver = new PromiseResolver<string>();
|
|
66
|
+
const authProcessor = new AdbAuthenticationProcessor(
|
|
67
|
+
authenticators,
|
|
68
|
+
credentialStore
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
// Here is similar to `AdbPacketDispatcher`,
|
|
72
|
+
// But the received packet types and send packet processing are different.
|
|
73
|
+
const abortController = new AbortController();
|
|
74
|
+
const pipe = connection.readable
|
|
75
|
+
.pipeTo(
|
|
76
|
+
new WritableStream({
|
|
77
|
+
async write(packet) {
|
|
78
|
+
switch (packet.command) {
|
|
79
|
+
case AdbCommand.Connect:
|
|
80
|
+
version = Math.min(version, packet.arg0);
|
|
81
|
+
maxPayloadSize = Math.min(
|
|
82
|
+
maxPayloadSize,
|
|
83
|
+
packet.arg1
|
|
84
|
+
);
|
|
85
|
+
resolver.resolve(decodeUtf8(packet.payload));
|
|
86
|
+
break;
|
|
87
|
+
case AdbCommand.Auth: {
|
|
88
|
+
const response = await authProcessor.process(
|
|
89
|
+
packet
|
|
90
|
+
);
|
|
91
|
+
await sendPacket(response);
|
|
92
|
+
break;
|
|
93
|
+
}
|
|
94
|
+
default:
|
|
95
|
+
// Maybe the previous ADB client exited without reading all packets,
|
|
96
|
+
// so they are still waiting in OS internal buffer.
|
|
97
|
+
// Just ignore them.
|
|
98
|
+
// Because a `Connect` packet will reset the device,
|
|
99
|
+
// Eventually there will be `Connect` and `Auth` response packets.
|
|
100
|
+
break;
|
|
101
|
+
}
|
|
102
|
+
},
|
|
103
|
+
}),
|
|
104
|
+
{
|
|
105
|
+
// Don't cancel the source ReadableStream on AbortSignal abort.
|
|
106
|
+
preventCancel: true,
|
|
107
|
+
signal: abortController.signal,
|
|
108
|
+
}
|
|
109
|
+
)
|
|
110
|
+
.then(
|
|
111
|
+
() => {
|
|
112
|
+
if (resolver.state === "running") {
|
|
113
|
+
resolver.reject(
|
|
114
|
+
new Error("Connection closed unexpectedly")
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
},
|
|
118
|
+
(e) => {
|
|
119
|
+
resolver.reject(e);
|
|
120
|
+
}
|
|
121
|
+
);
|
|
122
|
+
|
|
123
|
+
const writer = connection.writable.getWriter();
|
|
124
|
+
async function sendPacket(init: AdbPacketData) {
|
|
125
|
+
// Always send checksum in auth steps
|
|
126
|
+
// Because we don't know if the device needs it or not.
|
|
127
|
+
(init as AdbPacketInit).checksum = calculateChecksum(init.payload);
|
|
128
|
+
(init as AdbPacketInit).magic = init.command ^ 0xffffffff;
|
|
129
|
+
await ConsumableWritableStream.write(writer, init as AdbPacketInit);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
let banner: string;
|
|
133
|
+
try {
|
|
134
|
+
// https://android.googlesource.com/platform/packages/modules/adb/+/79010dc6d5ca7490c493df800d4421730f5466ca/transport.cpp#1252
|
|
135
|
+
// There are some other feature constants, but some of them are only used by ADB server, not devices (daemons).
|
|
136
|
+
const features = [
|
|
137
|
+
AdbFeature.ShellV2,
|
|
138
|
+
AdbFeature.Cmd,
|
|
139
|
+
AdbFeature.StatV2,
|
|
140
|
+
AdbFeature.ListV2,
|
|
141
|
+
AdbFeature.FixedPushMkdir,
|
|
142
|
+
"apex",
|
|
143
|
+
AdbFeature.Abb,
|
|
144
|
+
// only tells the client the symlink timestamp issue in `adb push --sync` has been fixed.
|
|
145
|
+
// No special handling required.
|
|
146
|
+
"fixed_push_symlink_timestamp",
|
|
147
|
+
AdbFeature.AbbExec,
|
|
148
|
+
"remount_shell",
|
|
149
|
+
"track_app",
|
|
150
|
+
"sendrecv_v2",
|
|
151
|
+
"sendrecv_v2_brotli",
|
|
152
|
+
"sendrecv_v2_lz4",
|
|
153
|
+
"sendrecv_v2_zstd",
|
|
154
|
+
"sendrecv_v2_dry_run_send",
|
|
155
|
+
].join(",");
|
|
156
|
+
|
|
157
|
+
await sendPacket({
|
|
158
|
+
command: AdbCommand.Connect,
|
|
159
|
+
arg0: version,
|
|
160
|
+
arg1: maxPayloadSize,
|
|
161
|
+
// The terminating `;` is required in formal definition
|
|
162
|
+
// But ADB daemon (all versions) can still work without it
|
|
163
|
+
payload: encodeUtf8(`host::features=${features}`),
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
banner = await resolver.promise;
|
|
167
|
+
} finally {
|
|
168
|
+
// When failed, release locks on `connection` so the caller can try again.
|
|
169
|
+
// When success, also release locks so `AdbPacketDispatcher` can use them.
|
|
170
|
+
abortController.abort();
|
|
171
|
+
writer.releaseLock();
|
|
172
|
+
|
|
173
|
+
// Wait until pipe stops (`ReadableStream` lock released)
|
|
174
|
+
await pipe;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
return new AdbDaemonTransport({
|
|
178
|
+
serial,
|
|
179
|
+
connection,
|
|
180
|
+
version,
|
|
181
|
+
maxPayloadSize,
|
|
182
|
+
banner,
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
readonly #dispatcher: AdbPacketDispatcher;
|
|
187
|
+
|
|
188
|
+
#serial: string;
|
|
189
|
+
public get serial() {
|
|
190
|
+
return this.#serial;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
#protocolVersion: number;
|
|
194
|
+
public get protocolVersion() {
|
|
195
|
+
return this.#protocolVersion;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
#maxPayloadSize: number;
|
|
199
|
+
public get maxPayloadSize() {
|
|
200
|
+
return this.#maxPayloadSize;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
#banner: AdbBanner;
|
|
204
|
+
public get banner() {
|
|
205
|
+
return this.#banner;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
public get disconnected() {
|
|
209
|
+
return this.#dispatcher.disconnected;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
public constructor({
|
|
213
|
+
serial,
|
|
214
|
+
connection,
|
|
215
|
+
version,
|
|
216
|
+
maxPayloadSize,
|
|
217
|
+
banner,
|
|
218
|
+
}: AdbDaemonSocketConnectorConstructionOptions) {
|
|
219
|
+
this.#serial = serial;
|
|
220
|
+
this.#banner = AdbBanner.parse(banner);
|
|
221
|
+
|
|
222
|
+
let calculateChecksum: boolean;
|
|
223
|
+
let appendNullToServiceString: boolean;
|
|
224
|
+
if (version >= ADB_DAEMON_VERSION_OMIT_CHECKSUM) {
|
|
225
|
+
calculateChecksum = false;
|
|
226
|
+
appendNullToServiceString = false;
|
|
227
|
+
} else {
|
|
228
|
+
calculateChecksum = true;
|
|
229
|
+
appendNullToServiceString = true;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
this.#dispatcher = new AdbPacketDispatcher(connection, {
|
|
233
|
+
calculateChecksum,
|
|
234
|
+
appendNullToServiceString,
|
|
235
|
+
maxPayloadSize,
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
this.#protocolVersion = version;
|
|
239
|
+
this.#maxPayloadSize = maxPayloadSize;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
public connect(service: string): ValueOrPromise<AdbSocket> {
|
|
243
|
+
return this.#dispatcher.createSocket(service);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
public addReverseTunnel(
|
|
247
|
+
handler: AdbIncomingSocketHandler,
|
|
248
|
+
address?: string
|
|
249
|
+
): string {
|
|
250
|
+
if (!address) {
|
|
251
|
+
const id = Math.random().toString().substring(2);
|
|
252
|
+
address = `localabstract:reverse_${id}`;
|
|
253
|
+
}
|
|
254
|
+
this.#dispatcher.addReverseTunnel(address, handler);
|
|
255
|
+
return address;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
public removeReverseTunnel(address: string): void {
|
|
259
|
+
this.#dispatcher.removeReverseTunnel(address);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
public clearReverseTunnels(): void {
|
|
263
|
+
this.#dispatcher.clearReverseTunnels();
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
public close(): ValueOrPromise<void> {
|
|
267
|
+
return this.#dispatcher.close();
|
|
268
|
+
}
|
|
269
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
export * from "./adb.js";
|
|
2
|
-
export * from "./
|
|
3
|
-
export * from "./backend.js";
|
|
2
|
+
export * from "./banner.js";
|
|
4
3
|
export * from "./commands/index.js";
|
|
5
|
-
export * from "./
|
|
4
|
+
export * from "./daemon/index.js";
|
|
6
5
|
export * from "./features.js";
|
|
7
|
-
export * from "./
|
|
8
|
-
export * from "./socket/index.js";
|
|
6
|
+
export * from "./server/index.js";
|
|
9
7
|
export * from "./utils/index.js";
|