@yume-chan/adb 0.0.17 → 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 +6 -0
- package/CHANGELOG.md +6 -1
- package/LICENSE +1 -1
- package/esm/adb.d.ts +6 -6
- package/esm/adb.d.ts.map +1 -1
- package/esm/adb.js +55 -35
- 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/framebuffer.d.ts +7 -7
- package/esm/commands/framebuffer.d.ts.map +1 -1
- package/esm/commands/framebuffer.js +32 -33
- 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 -6
- package/esm/commands/install.js.map +1 -1
- package/esm/commands/power.d.ts +1 -1
- package/esm/commands/power.d.ts.map +1 -1
- package/esm/commands/power.js +14 -10
- package/esm/commands/power.js.map +1 -1
- package/esm/commands/reverse.d.ts +3 -3
- package/esm/commands/reverse.d.ts.map +1 -1
- package/esm/commands/reverse.js +14 -12
- package/esm/commands/reverse.js.map +1 -1
- package/esm/commands/subprocess/command.d.ts +2 -2
- package/esm/commands/subprocess/command.d.ts.map +1 -1
- package/esm/commands/subprocess/command.js +14 -16
- package/esm/commands/subprocess/command.js.map +1 -1
- package/esm/commands/subprocess/protocols/none.d.ts +4 -4
- package/esm/commands/subprocess/protocols/none.d.ts.map +1 -1
- 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 +23 -15
- package/esm/commands/subprocess/protocols/shell.js.map +1 -1
- package/esm/commands/subprocess/protocols/types.d.ts +4 -4
- package/esm/commands/subprocess/protocols/types.d.ts.map +1 -1
- package/esm/commands/sync/list.d.ts +6 -6
- package/esm/commands/sync/list.d.ts.map +1 -1
- package/esm/commands/sync/list.js +23 -11
- package/esm/commands/sync/list.js.map +1 -1
- package/esm/commands/sync/pull.d.ts +4 -4
- package/esm/commands/sync/pull.d.ts.map +1 -1
- package/esm/commands/sync/pull.js +12 -11
- package/esm/commands/sync/pull.js.map +1 -1
- package/esm/commands/sync/push.d.ts +3 -3
- package/esm/commands/sync/push.d.ts.map +1 -1
- package/esm/commands/sync/push.js +6 -7
- 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 +7 -7
- package/esm/commands/sync/request.js.map +1 -1
- package/esm/commands/sync/response.d.ts +4 -4
- package/esm/commands/sync/response.d.ts.map +1 -1
- package/esm/commands/sync/response.js +7 -7
- package/esm/commands/sync/response.js.map +1 -1
- package/esm/commands/sync/stat.d.ts +5 -5
- package/esm/commands/sync/stat.d.ts.map +1 -1
- package/esm/commands/sync/stat.js +37 -27
- package/esm/commands/sync/stat.js.map +1 -1
- package/esm/commands/sync/sync.d.ts +6 -6
- package/esm/commands/sync/sync.d.ts.map +1 -1
- package/esm/commands/sync/sync.js +20 -19
- package/esm/commands/sync/sync.js.map +1 -1
- package/esm/crypto.d.ts.map +1 -1
- package/esm/crypto.js +25 -15
- package/esm/crypto.js.map +1 -1
- package/esm/index.d.ts +9 -9
- package/esm/index.d.ts.map +1 -1
- package/esm/index.js +9 -9
- 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 +6 -6
- package/esm/socket/dispatcher.d.ts.map +1 -1
- package/esm/socket/dispatcher.js +22 -19
- package/esm/socket/dispatcher.js.map +1 -1
- package/esm/socket/socket.d.ts +4 -4
- 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.map +1 -1
- package/esm/utils/base64.js +30 -29
- package/esm/utils/base64.js.map +1 -1
- package/package.json +16 -13
- package/src/adb.ts +133 -84
- package/src/auth.ts +27 -19
- package/src/backend.ts +6 -4
- package/src/commands/base.ts +2 -2
- package/src/commands/framebuffer.ts +37 -41
- package/src/commands/install.ts +19 -11
- package/src/commands/power.ts +15 -11
- package/src/commands/reverse.ts +48 -29
- package/src/commands/subprocess/command.ts +24 -21
- package/src/commands/subprocess/protocols/none.ts +4 -3
- package/src/commands/subprocess/protocols/shell.ts +65 -33
- package/src/commands/subprocess/protocols/types.ts +8 -5
- package/src/commands/sync/list.ts +51 -24
- package/src/commands/sync/pull.ts +51 -34
- package/src/commands/sync/push.ts +25 -11
- package/src/commands/sync/request.ts +20 -22
- package/src/commands/sync/response.ts +31 -25
- package/src/commands/sync/stat.ts +78 -55
- package/src/commands/sync/sync.ts +47 -26
- package/src/crypto.ts +60 -32
- package/src/index.ts +9 -10
- package/src/packet.ts +40 -30
- package/src/socket/dispatcher.ts +115 -78
- package/src/socket/socket.ts +68 -27
- package/src/utils/auto-reset-event.ts +3 -3
- package/src/utils/base64.ts +51 -41
- package/tsconfig.build.json +1 -1
- package/tsconfig.build.tsbuildinfo +1 -1
package/src/auth.ts
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
|
-
import { PromiseResolver } from
|
|
2
|
-
import type
|
|
3
|
-
import type
|
|
4
|
-
|
|
5
|
-
import {
|
|
6
|
-
|
|
7
|
-
|
|
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";
|
|
8
12
|
|
|
9
13
|
export type AdbKeyIterable = Iterable<Uint8Array> | AsyncIterable<Uint8Array>;
|
|
10
14
|
|
|
@@ -50,7 +54,7 @@ export interface AdbAuthenticator {
|
|
|
50
54
|
|
|
51
55
|
export const AdbSignatureAuthenticator: AdbAuthenticator = async function* (
|
|
52
56
|
credentialStore: AdbCredentialStore,
|
|
53
|
-
getNextRequest: () => Promise<AdbPacketData
|
|
57
|
+
getNextRequest: () => Promise<AdbPacketData>
|
|
54
58
|
): AsyncIterable<AdbPacketData> {
|
|
55
59
|
for await (const key of credentialStore.iterateKeys()) {
|
|
56
60
|
const packet = await getNextRequest();
|
|
@@ -71,7 +75,7 @@ export const AdbSignatureAuthenticator: AdbAuthenticator = async function* (
|
|
|
71
75
|
|
|
72
76
|
export const AdbPublicKeyAuthenticator: AdbAuthenticator = async function* (
|
|
73
77
|
credentialStore: AdbCredentialStore,
|
|
74
|
-
getNextRequest: () => Promise<AdbPacketData
|
|
78
|
+
getNextRequest: () => Promise<AdbPacketData>
|
|
75
79
|
): AsyncIterable<AdbPacketData> {
|
|
76
80
|
const packet = await getNextRequest();
|
|
77
81
|
|
|
@@ -85,23 +89,20 @@ export const AdbPublicKeyAuthenticator: AdbAuthenticator = async function* (
|
|
|
85
89
|
break;
|
|
86
90
|
}
|
|
87
91
|
|
|
88
|
-
|
|
89
92
|
if (!privateKey) {
|
|
90
93
|
privateKey = await credentialStore.generateKey();
|
|
91
94
|
}
|
|
92
95
|
|
|
93
96
|
const publicKeyLength = calculatePublicKeyLength();
|
|
94
|
-
const [publicKeyBase64Length] =
|
|
97
|
+
const [publicKeyBase64Length] =
|
|
98
|
+
calculateBase64EncodedLength(publicKeyLength);
|
|
95
99
|
|
|
96
100
|
// The public key is null terminated,
|
|
97
101
|
// So we allocate the buffer with one extra byte.
|
|
98
102
|
const publicKeyBuffer = new Uint8Array(publicKeyBase64Length + 1);
|
|
99
103
|
|
|
100
104
|
calculatePublicKey(privateKey, publicKeyBuffer);
|
|
101
|
-
encodeBase64(
|
|
102
|
-
publicKeyBuffer.subarray(0, publicKeyLength),
|
|
103
|
-
publicKeyBuffer
|
|
104
|
-
);
|
|
105
|
+
encodeBase64(publicKeyBuffer.subarray(0, publicKeyLength), publicKeyBuffer);
|
|
105
106
|
|
|
106
107
|
yield {
|
|
107
108
|
command: AdbCommand.Auth,
|
|
@@ -137,9 +138,16 @@ export class AdbAuthenticationProcessor implements Disposable {
|
|
|
137
138
|
return this.pendingRequest.promise;
|
|
138
139
|
};
|
|
139
140
|
|
|
140
|
-
private async*
|
|
141
|
+
private async *invokeAuthenticator(): AsyncGenerator<
|
|
142
|
+
AdbPacketData,
|
|
143
|
+
void,
|
|
144
|
+
void
|
|
145
|
+
> {
|
|
141
146
|
for (const authenticator of this.authenticators) {
|
|
142
|
-
for await (const packet of authenticator(
|
|
147
|
+
for await (const packet of authenticator(
|
|
148
|
+
this.credentialStore,
|
|
149
|
+
this.getNextRequest
|
|
150
|
+
)) {
|
|
143
151
|
// If the authenticator yielded a response
|
|
144
152
|
// Prepare `nextRequest` for next authentication request
|
|
145
153
|
this.pendingRequest = new PromiseResolver();
|
|
@@ -162,13 +170,13 @@ export class AdbAuthenticationProcessor implements Disposable {
|
|
|
162
170
|
|
|
163
171
|
const result = await this.iterator.next();
|
|
164
172
|
if (result.done) {
|
|
165
|
-
throw new Error(
|
|
173
|
+
throw new Error("No authenticator can handle the request");
|
|
166
174
|
}
|
|
167
175
|
|
|
168
176
|
return result.value;
|
|
169
177
|
}
|
|
170
178
|
|
|
171
179
|
public dispose() {
|
|
172
|
-
this.iterator?.return?.();
|
|
180
|
+
void this.iterator?.return?.();
|
|
173
181
|
}
|
|
174
182
|
}
|
package/src/backend.ts
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
|
-
import type
|
|
2
|
-
import type
|
|
1
|
+
import { type ReadableWritablePair } from "@yume-chan/stream-extra";
|
|
2
|
+
import { type ValueOrPromise } from "@yume-chan/struct";
|
|
3
3
|
|
|
4
|
-
import type
|
|
4
|
+
import { type AdbPacketData, type AdbPacketInit } from "./packet.js";
|
|
5
5
|
|
|
6
6
|
export interface AdbBackend {
|
|
7
7
|
readonly serial: string;
|
|
8
8
|
|
|
9
9
|
readonly name: string | undefined;
|
|
10
10
|
|
|
11
|
-
connect(): ValueOrPromise<
|
|
11
|
+
connect(): ValueOrPromise<
|
|
12
|
+
ReadableWritablePair<AdbPacketData, AdbPacketInit>
|
|
13
|
+
>;
|
|
12
14
|
}
|
package/src/commands/base.ts
CHANGED
|
@@ -1,48 +1,44 @@
|
|
|
1
|
-
import { BufferedReadableStream } from
|
|
2
|
-
import Struct from
|
|
1
|
+
import { BufferedReadableStream } from "@yume-chan/stream-extra";
|
|
2
|
+
import Struct from "@yume-chan/struct";
|
|
3
3
|
|
|
4
|
-
import type
|
|
4
|
+
import { type Adb } from "../adb.js";
|
|
5
5
|
|
|
6
|
-
const Version =
|
|
7
|
-
new Struct({ littleEndian: true })
|
|
8
|
-
.uint32('version');
|
|
6
|
+
const Version = new Struct({ littleEndian: true }).uint32("version");
|
|
9
7
|
|
|
10
|
-
export const AdbFrameBufferV1 =
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
.uint8Array('data', { lengthField: 'size' });
|
|
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" });
|
|
25
22
|
|
|
26
|
-
export type AdbFrameBufferV1 = typeof AdbFrameBufferV1[
|
|
23
|
+
export type AdbFrameBufferV1 = typeof AdbFrameBufferV1["TDeserializeResult"];
|
|
27
24
|
|
|
28
|
-
export const AdbFrameBufferV2 =
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
.uint8Array('data', { lengthField: 'size' });
|
|
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" });
|
|
44
40
|
|
|
45
|
-
export type AdbFrameBufferV2 = typeof AdbFrameBufferV2[
|
|
41
|
+
export type AdbFrameBufferV2 = typeof AdbFrameBufferV2["TDeserializeResult"];
|
|
46
42
|
|
|
47
43
|
/**
|
|
48
44
|
* ADB uses 8 int32 fields to describe bit depths
|
|
@@ -63,7 +59,7 @@ export type AdbFrameBufferV2 = typeof AdbFrameBufferV2['TDeserializeResult'];
|
|
|
63
59
|
export type AdbFrameBuffer = AdbFrameBufferV1 | AdbFrameBufferV2;
|
|
64
60
|
|
|
65
61
|
export async function framebuffer(adb: Adb): Promise<AdbFrameBuffer> {
|
|
66
|
-
const socket = await adb.createSocket(
|
|
62
|
+
const socket = await adb.createSocket("framebuffer:");
|
|
67
63
|
const stream = new BufferedReadableStream(socket.readable);
|
|
68
64
|
const { version } = await Version.deserialize(stream);
|
|
69
65
|
switch (version) {
|
|
@@ -73,6 +69,6 @@ export async function framebuffer(adb: Adb): Promise<AdbFrameBuffer> {
|
|
|
73
69
|
case 2:
|
|
74
70
|
return AdbFrameBufferV2.deserialize(stream);
|
|
75
71
|
default:
|
|
76
|
-
throw new Error(
|
|
72
|
+
throw new Error("Unknown FrameBuffer version");
|
|
77
73
|
}
|
|
78
74
|
}
|
package/src/commands/install.ts
CHANGED
|
@@ -1,13 +1,17 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
WrapWritableStream,
|
|
3
|
+
type WritableStream,
|
|
4
|
+
} from "@yume-chan/stream-extra";
|
|
2
5
|
|
|
3
|
-
import type
|
|
4
|
-
import { escapeArg } from './subprocess/index.js';
|
|
5
|
-
import type { AdbSync } from './sync/index.js';
|
|
6
|
+
import { type Adb } from "../adb.js";
|
|
6
7
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
import { escapeArg } from "./subprocess/index.js";
|
|
9
|
+
import { type AdbSync } from "./sync/index.js";
|
|
10
|
+
|
|
11
|
+
export function install(adb: Adb): WritableStream<Uint8Array> {
|
|
12
|
+
const filename = `/data/local/tmp/${Math.random()
|
|
13
|
+
.toString()
|
|
14
|
+
.substring(2)}.apk`;
|
|
11
15
|
|
|
12
16
|
let sync!: AdbSync;
|
|
13
17
|
return new WrapWritableStream<Uint8Array>({
|
|
@@ -20,13 +24,17 @@ export function install(
|
|
|
20
24
|
return sync.write(filename, undefined, undefined);
|
|
21
25
|
},
|
|
22
26
|
async close() {
|
|
23
|
-
sync.dispose();
|
|
27
|
+
await sync.dispose();
|
|
24
28
|
|
|
25
29
|
// Invoke `pm install` to install it
|
|
26
|
-
await adb.subprocess.spawnAndWaitLegacy([
|
|
30
|
+
await adb.subprocess.spawnAndWaitLegacy([
|
|
31
|
+
"pm",
|
|
32
|
+
"install",
|
|
33
|
+
escapeArg(filename),
|
|
34
|
+
]);
|
|
27
35
|
|
|
28
36
|
// Remove the temp file
|
|
29
37
|
await adb.rm(filename);
|
|
30
|
-
}
|
|
38
|
+
},
|
|
31
39
|
});
|
|
32
40
|
}
|
package/src/commands/power.ts
CHANGED
|
@@ -3,27 +3,27 @@
|
|
|
3
3
|
// cspell: ignore keyevent
|
|
4
4
|
// cspell: ignore longpress
|
|
5
5
|
|
|
6
|
-
import { AdbCommandBase } from
|
|
6
|
+
import { AdbCommandBase } from "./base.js";
|
|
7
7
|
|
|
8
8
|
export class AdbPower extends AdbCommandBase {
|
|
9
|
-
public reboot(name
|
|
9
|
+
public reboot(name = "") {
|
|
10
10
|
return this.adb.createSocketAndWait(`reboot:${name}`);
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
public bootloader() {
|
|
14
|
-
return this.reboot(
|
|
14
|
+
return this.reboot("bootloader");
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
public fastboot() {
|
|
18
|
-
return this.reboot(
|
|
18
|
+
return this.reboot("fastboot");
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
public recovery() {
|
|
22
|
-
return this.reboot(
|
|
22
|
+
return this.reboot("recovery");
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
public sideload() {
|
|
26
|
-
return this.reboot(
|
|
26
|
+
return this.reboot("sideload");
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
/**
|
|
@@ -32,15 +32,19 @@ export class AdbPower extends AdbCommandBase {
|
|
|
32
32
|
* Only works on some Qualcomm devices.
|
|
33
33
|
*/
|
|
34
34
|
public qualcommEdlMode() {
|
|
35
|
-
return this.reboot(
|
|
35
|
+
return this.reboot("edl");
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
public powerOff() {
|
|
39
|
-
return this.adb.subprocess.spawnAndWaitLegacy([
|
|
39
|
+
return this.adb.subprocess.spawnAndWaitLegacy(["reboot", "-p"]);
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
-
public powerButton(longPress
|
|
43
|
-
return this.adb.subprocess.spawnAndWaitLegacy([
|
|
42
|
+
public powerButton(longPress = false) {
|
|
43
|
+
return this.adb.subprocess.spawnAndWaitLegacy([
|
|
44
|
+
"input",
|
|
45
|
+
"keyevent",
|
|
46
|
+
longPress ? "--longpress POWER" : "POWER",
|
|
47
|
+
]);
|
|
44
48
|
}
|
|
45
49
|
|
|
46
50
|
/**
|
|
@@ -49,6 +53,6 @@ export class AdbPower extends AdbCommandBase {
|
|
|
49
53
|
* Only works on Samsung devices.
|
|
50
54
|
*/
|
|
51
55
|
public samsungOdin() {
|
|
52
|
-
return this.reboot(
|
|
56
|
+
return this.reboot("download");
|
|
53
57
|
}
|
|
54
58
|
}
|
package/src/commands/reverse.ts
CHANGED
|
@@ -1,12 +1,18 @@
|
|
|
1
1
|
// cspell: ignore killforward
|
|
2
2
|
|
|
3
|
-
import { AutoDisposable } from
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
import
|
|
9
|
-
|
|
3
|
+
import { AutoDisposable } from "@yume-chan/event";
|
|
4
|
+
import {
|
|
5
|
+
BufferedReadableStream,
|
|
6
|
+
BufferedReadableStreamEndedError,
|
|
7
|
+
} from "@yume-chan/stream-extra";
|
|
8
|
+
import Struct from "@yume-chan/struct";
|
|
9
|
+
|
|
10
|
+
import { type Adb } from "../adb.js";
|
|
11
|
+
import {
|
|
12
|
+
type AdbIncomingSocketHandler,
|
|
13
|
+
type AdbSocket,
|
|
14
|
+
} from "../socket/index.js";
|
|
15
|
+
import { decodeUtf8 } from "../utils/index.js";
|
|
10
16
|
|
|
11
17
|
export interface AdbForwardListener {
|
|
12
18
|
deviceSerial: string;
|
|
@@ -16,20 +22,21 @@ export interface AdbForwardListener {
|
|
|
16
22
|
remoteName: string;
|
|
17
23
|
}
|
|
18
24
|
|
|
19
|
-
const AdbReverseStringResponse =
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
.string('content', { lengthField: 'length', lengthFieldRadix: 16 });
|
|
25
|
+
const AdbReverseStringResponse = new Struct()
|
|
26
|
+
.string("length", { length: 4 })
|
|
27
|
+
.string("content", { lengthField: "length", lengthFieldRadix: 16 });
|
|
23
28
|
|
|
24
|
-
const AdbReverseErrorResponse =
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
});
|
|
29
|
+
const AdbReverseErrorResponse = new Struct()
|
|
30
|
+
.fields(AdbReverseStringResponse)
|
|
31
|
+
.postDeserialize((value) => {
|
|
32
|
+
throw new Error(value.content);
|
|
33
|
+
});
|
|
30
34
|
|
|
31
35
|
export class AdbReverseCommand extends AutoDisposable {
|
|
32
|
-
protected localAddressToHandler = new Map<
|
|
36
|
+
protected localAddressToHandler = new Map<
|
|
37
|
+
string,
|
|
38
|
+
AdbIncomingSocketHandler
|
|
39
|
+
>();
|
|
33
40
|
|
|
34
41
|
protected deviceAddressToLocalAddress = new Map<string, string>();
|
|
35
42
|
|
|
@@ -41,13 +48,15 @@ export class AdbReverseCommand extends AutoDisposable {
|
|
|
41
48
|
super();
|
|
42
49
|
|
|
43
50
|
this.adb = adb;
|
|
44
|
-
this.addDisposable(
|
|
51
|
+
this.addDisposable(
|
|
52
|
+
this.adb.onIncomingSocket(this.handleIncomingSocket)
|
|
53
|
+
);
|
|
45
54
|
}
|
|
46
55
|
|
|
47
56
|
protected handleIncomingSocket = async (socket: AdbSocket) => {
|
|
48
57
|
let address = socket.serviceString;
|
|
49
58
|
// ADB daemon appends `\0` to the service string
|
|
50
|
-
address = address.replace(/\0/g,
|
|
59
|
+
address = address.replace(/\0/g, "");
|
|
51
60
|
return !!(await this.localAddressToHandler.get(address)?.(socket));
|
|
52
61
|
};
|
|
53
62
|
|
|
@@ -58,7 +67,7 @@ export class AdbReverseCommand extends AutoDisposable {
|
|
|
58
67
|
|
|
59
68
|
private async sendRequest(service: string) {
|
|
60
69
|
const stream = await this.createBufferedStream(service);
|
|
61
|
-
const success = decodeUtf8(await stream.read(4)) ===
|
|
70
|
+
const success = decodeUtf8(await stream.read(4)) === "OKAY";
|
|
62
71
|
if (!success) {
|
|
63
72
|
await AdbReverseErrorResponse.deserialize(stream);
|
|
64
73
|
}
|
|
@@ -66,11 +75,15 @@ export class AdbReverseCommand extends AutoDisposable {
|
|
|
66
75
|
}
|
|
67
76
|
|
|
68
77
|
public async list(): Promise<AdbForwardListener[]> {
|
|
69
|
-
const stream = await this.createBufferedStream(
|
|
78
|
+
const stream = await this.createBufferedStream("reverse:list-forward");
|
|
70
79
|
|
|
71
80
|
const response = await AdbReverseStringResponse.deserialize(stream);
|
|
72
|
-
return response.content!.split(
|
|
73
|
-
const [deviceSerial, localName, remoteName] = line.split(
|
|
81
|
+
return response.content!.split("\n").map((line) => {
|
|
82
|
+
const [deviceSerial, localName, remoteName] = line.split(" ") as [
|
|
83
|
+
string,
|
|
84
|
+
string,
|
|
85
|
+
string
|
|
86
|
+
];
|
|
74
87
|
return { deviceSerial, localName, remoteName };
|
|
75
88
|
});
|
|
76
89
|
|
|
@@ -86,13 +99,17 @@ export class AdbReverseCommand extends AutoDisposable {
|
|
|
86
99
|
public async add(
|
|
87
100
|
deviceAddress: string,
|
|
88
101
|
localAddress: string,
|
|
89
|
-
handler: AdbIncomingSocketHandler
|
|
102
|
+
handler: AdbIncomingSocketHandler
|
|
90
103
|
): Promise<string> {
|
|
91
|
-
|
|
104
|
+
// TODO(reverse): handle ADB bug
|
|
105
|
+
// https://issuetracker.google.com/issues/37066218
|
|
106
|
+
const stream = await this.sendRequest(
|
|
107
|
+
`reverse:forward:${deviceAddress};${localAddress}`
|
|
108
|
+
);
|
|
92
109
|
|
|
93
110
|
// `tcp:0` tells the device to pick an available port.
|
|
94
111
|
// On Android >=8, device will respond with the selected port for all `tcp:` requests.
|
|
95
|
-
if (deviceAddress.startsWith(
|
|
112
|
+
if (deviceAddress.startsWith("tcp:")) {
|
|
96
113
|
let length: number | undefined;
|
|
97
114
|
try {
|
|
98
115
|
length = Number.parseInt(decodeUtf8(await stream.read(4)), 16);
|
|
@@ -107,7 +124,7 @@ export class AdbReverseCommand extends AutoDisposable {
|
|
|
107
124
|
}
|
|
108
125
|
|
|
109
126
|
if (length !== undefined) {
|
|
110
|
-
const port = decodeUtf8(await stream.read(length
|
|
127
|
+
const port = decodeUtf8(await stream.read(length));
|
|
111
128
|
deviceAddress = `tcp:${Number.parseInt(port, 10)}`;
|
|
112
129
|
}
|
|
113
130
|
}
|
|
@@ -123,7 +140,9 @@ export class AdbReverseCommand extends AutoDisposable {
|
|
|
123
140
|
await this.sendRequest(`reverse:killforward:${deviceAddress}`);
|
|
124
141
|
|
|
125
142
|
if (this.deviceAddressToLocalAddress.has(deviceAddress)) {
|
|
126
|
-
this.localAddressToHandler.delete(
|
|
143
|
+
this.localAddressToHandler.delete(
|
|
144
|
+
this.deviceAddressToLocalAddress.get(deviceAddress)!
|
|
145
|
+
);
|
|
127
146
|
this.deviceAddressToLocalAddress.delete(deviceAddress);
|
|
128
147
|
}
|
|
129
148
|
|
|
@@ -1,7 +1,13 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { DecodeUtf8Stream, GatherStringStream } from "@yume-chan/stream-extra";
|
|
2
2
|
|
|
3
|
-
import { AdbCommandBase } from
|
|
4
|
-
|
|
3
|
+
import { AdbCommandBase } from "../base.js";
|
|
4
|
+
|
|
5
|
+
import {
|
|
6
|
+
AdbSubprocessNoneProtocol,
|
|
7
|
+
AdbSubprocessShellProtocol,
|
|
8
|
+
type AdbSubprocessProtocol,
|
|
9
|
+
type AdbSubprocessProtocolConstructor,
|
|
10
|
+
} from "./protocols/index.js";
|
|
5
11
|
|
|
6
12
|
export interface AdbSubprocessOptions {
|
|
7
13
|
/**
|
|
@@ -30,7 +36,7 @@ export interface AdbSubprocessWaitResult {
|
|
|
30
36
|
|
|
31
37
|
export class AdbSubprocess extends AdbCommandBase {
|
|
32
38
|
private async createProtocol(
|
|
33
|
-
mode:
|
|
39
|
+
mode: "pty" | "raw",
|
|
34
40
|
command?: string | string[],
|
|
35
41
|
options?: Partial<AdbSubprocessOptions>
|
|
36
42
|
): Promise<AdbSubprocessProtocol> {
|
|
@@ -46,14 +52,14 @@ export class AdbSubprocess extends AdbCommandBase {
|
|
|
46
52
|
}
|
|
47
53
|
|
|
48
54
|
if (!Constructor) {
|
|
49
|
-
throw new Error(
|
|
55
|
+
throw new Error("No specified protocol is supported by the device");
|
|
50
56
|
}
|
|
51
57
|
|
|
52
58
|
if (Array.isArray(command)) {
|
|
53
|
-
command = command.join(
|
|
59
|
+
command = command.join(" ");
|
|
54
60
|
} else if (command === undefined) {
|
|
55
61
|
// spawn the default shell
|
|
56
|
-
command =
|
|
62
|
+
command = "";
|
|
57
63
|
}
|
|
58
64
|
return await Constructor[mode](this.adb, command);
|
|
59
65
|
}
|
|
@@ -68,7 +74,7 @@ export class AdbSubprocess extends AdbCommandBase {
|
|
|
68
74
|
command?: string | string[],
|
|
69
75
|
options?: Partial<AdbSubprocessOptions>
|
|
70
76
|
): Promise<AdbSubprocessProtocol> {
|
|
71
|
-
return this.createProtocol(
|
|
77
|
+
return this.createProtocol("pty", command, options);
|
|
72
78
|
}
|
|
73
79
|
|
|
74
80
|
/**
|
|
@@ -81,7 +87,7 @@ export class AdbSubprocess extends AdbCommandBase {
|
|
|
81
87
|
command: string | string[],
|
|
82
88
|
options?: Partial<AdbSubprocessOptions>
|
|
83
89
|
): Promise<AdbSubprocessProtocol> {
|
|
84
|
-
return this.createProtocol(
|
|
90
|
+
return this.createProtocol("raw", command, options);
|
|
85
91
|
}
|
|
86
92
|
|
|
87
93
|
/**
|
|
@@ -100,13 +106,9 @@ export class AdbSubprocess extends AdbCommandBase {
|
|
|
100
106
|
const stderr = new GatherStringStream();
|
|
101
107
|
|
|
102
108
|
const [, , exitCode] = await Promise.all([
|
|
103
|
-
shell.stdout
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
shell.stderr
|
|
107
|
-
.pipeThrough(new DecodeUtf8Stream())
|
|
108
|
-
.pipeTo(stderr),
|
|
109
|
-
shell.exit
|
|
109
|
+
shell.stdout.pipeThrough(new DecodeUtf8Stream()).pipeTo(stdout),
|
|
110
|
+
shell.stderr.pipeThrough(new DecodeUtf8Stream()).pipeTo(stderr),
|
|
111
|
+
shell.exit,
|
|
110
112
|
]);
|
|
111
113
|
|
|
112
114
|
return {
|
|
@@ -121,11 +123,12 @@ export class AdbSubprocess extends AdbCommandBase {
|
|
|
121
123
|
* @param command The command to run
|
|
122
124
|
* @returns The entire output of the command
|
|
123
125
|
*/
|
|
124
|
-
public async spawnAndWaitLegacy(
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
126
|
+
public async spawnAndWaitLegacy(
|
|
127
|
+
command: string | string[]
|
|
128
|
+
): Promise<string> {
|
|
129
|
+
const { stdout } = await this.spawnAndWait(command, {
|
|
130
|
+
protocols: [AdbSubprocessNoneProtocol],
|
|
131
|
+
});
|
|
129
132
|
return stdout;
|
|
130
133
|
}
|
|
131
134
|
}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { DuplexStreamFactory, ReadableStream } from '@yume-chan/stream-extra';
|
|
2
2
|
|
|
3
|
-
import type
|
|
4
|
-
import type
|
|
5
|
-
|
|
3
|
+
import { type Adb } from "../../../adb.js";
|
|
4
|
+
import { type AdbSocket } from "../../../socket/index.js";
|
|
5
|
+
|
|
6
|
+
import { type AdbSubprocessProtocol } from "./types.js";
|
|
6
7
|
|
|
7
8
|
/**
|
|
8
9
|
* The legacy shell
|