@yume-chan/adb 0.0.13 → 0.0.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (116) hide show
  1. package/CHANGELOG.json +57 -0
  2. package/CHANGELOG.md +29 -1
  3. package/LICENSE +21 -21
  4. package/README.md +247 -247
  5. package/esm/adb.d.ts +12 -4
  6. package/esm/adb.d.ts.map +1 -1
  7. package/esm/adb.js +29 -19
  8. package/esm/adb.js.map +1 -1
  9. package/esm/commands/reverse.d.ts +9 -12
  10. package/esm/commands/reverse.d.ts.map +1 -1
  11. package/esm/commands/reverse.js +44 -36
  12. package/esm/commands/reverse.js.map +1 -1
  13. package/esm/commands/subprocess/protocols/none.d.ts +2 -1
  14. package/esm/commands/subprocess/protocols/none.d.ts.map +1 -1
  15. package/esm/commands/subprocess/protocols/none.js +10 -9
  16. package/esm/commands/subprocess/protocols/none.js.map +1 -1
  17. package/esm/commands/sync/pull.d.ts.map +1 -1
  18. package/esm/commands/sync/pull.js +6 -3
  19. package/esm/commands/sync/pull.js.map +1 -1
  20. package/esm/commands/sync/stat.d.ts.map +1 -1
  21. package/esm/commands/sync/stat.js +2 -2
  22. package/esm/commands/sync/stat.js.map +1 -1
  23. package/esm/commands/sync/sync.js +1 -1
  24. package/esm/commands/sync/sync.js.map +1 -1
  25. package/esm/socket/dispatcher.d.ts +25 -14
  26. package/esm/socket/dispatcher.d.ts.map +1 -1
  27. package/esm/socket/dispatcher.js +94 -63
  28. package/esm/socket/dispatcher.js.map +1 -1
  29. package/esm/socket/socket.d.ts +18 -4
  30. package/esm/socket/socket.d.ts.map +1 -1
  31. package/esm/socket/socket.js +36 -21
  32. package/esm/socket/socket.js.map +1 -1
  33. package/esm/stream/buffered.d.ts +7 -3
  34. package/esm/stream/buffered.d.ts.map +1 -1
  35. package/esm/stream/buffered.js +69 -49
  36. package/esm/stream/buffered.js.map +1 -1
  37. package/esm/stream/detect.js +1 -0
  38. package/esm/stream/detect.js.map +1 -1
  39. package/esm/stream/detect.polyfill.d.ts +1 -1
  40. package/esm/stream/detect.polyfill.d.ts.map +1 -1
  41. package/esm/stream/detect.polyfill.js +0 -5
  42. package/esm/stream/detect.polyfill.js.map +1 -1
  43. package/esm/stream/transform.d.ts +39 -13
  44. package/esm/stream/transform.d.ts.map +1 -1
  45. package/esm/stream/transform.js +67 -90
  46. package/esm/stream/transform.js.map +1 -1
  47. package/esm/utils/base64.js +5 -5
  48. package/esm/utils/base64.js.map +1 -1
  49. package/package.json +10 -10
  50. package/src/adb.ts +280 -270
  51. package/src/auth.ts +173 -173
  52. package/src/backend.ts +11 -11
  53. package/src/commands/base.ts +11 -11
  54. package/src/commands/framebuffer.ts +73 -73
  55. package/src/commands/index.ts +8 -8
  56. package/src/commands/install.ts +30 -30
  57. package/src/commands/power.ts +54 -54
  58. package/src/commands/reverse.ts +140 -136
  59. package/src/commands/subprocess/index.ts +139 -139
  60. package/src/commands/subprocess/protocols/none.ts +70 -68
  61. package/src/commands/subprocess/protocols/shell.ts +190 -190
  62. package/src/commands/subprocess/protocols/types.ts +59 -59
  63. package/src/commands/subprocess/utils.ts +20 -20
  64. package/src/commands/sync/index.ts +7 -7
  65. package/src/commands/sync/list.ts +86 -86
  66. package/src/commands/sync/pull.ts +46 -43
  67. package/src/commands/sync/push.ts +41 -41
  68. package/src/commands/sync/request.ts +50 -50
  69. package/src/commands/sync/response.ts +64 -64
  70. package/src/commands/sync/stat.ts +151 -150
  71. package/src/commands/sync/sync.ts +181 -181
  72. package/src/commands/tcpip.ts +21 -21
  73. package/src/crypto.ts +296 -296
  74. package/src/features.ts +9 -9
  75. package/src/index.ts +11 -11
  76. package/src/packet.ts +80 -80
  77. package/src/socket/dispatcher.ts +305 -270
  78. package/src/socket/index.ts +2 -2
  79. package/src/socket/socket.ts +155 -136
  80. package/src/stream/buffered.ts +168 -147
  81. package/src/stream/detect.native.ts +362 -362
  82. package/src/stream/detect.polyfill.ts +22 -28
  83. package/src/stream/detect.ts +7 -5
  84. package/src/stream/index.ts +3 -3
  85. package/src/stream/transform.ts +474 -483
  86. package/src/utils/auto-reset-event.ts +41 -41
  87. package/src/utils/base64.ts +306 -306
  88. package/src/utils/index.ts +3 -3
  89. package/tsconfig.build.json +3 -3
  90. package/tsconfig.build.tsbuildinfo +1 -1
  91. package/tsconfig.test.json +9 -10
  92. package/web-streams-polyfill-4.0.0-beta.2.tgz +0 -0
  93. package/esm/commands/subprocess/legacy.d.ts +0 -35
  94. package/esm/commands/subprocess/legacy.d.ts.map +0 -1
  95. package/esm/commands/subprocess/legacy.js +0 -53
  96. package/esm/commands/subprocess/legacy.js.map +0 -1
  97. package/esm/commands/subprocess/protocol.d.ts +0 -39
  98. package/esm/commands/subprocess/protocol.d.ts.map +0 -1
  99. package/esm/commands/subprocess/protocol.js +0 -157
  100. package/esm/commands/subprocess/protocol.js.map +0 -1
  101. package/esm/commands/subprocess/types.d.ts +0 -50
  102. package/esm/commands/subprocess/types.d.ts.map +0 -1
  103. package/esm/commands/subprocess/types.js +0 -2
  104. package/esm/commands/subprocess/types.js.map +0 -1
  105. package/esm/socket/controller.d.ts +0 -37
  106. package/esm/socket/controller.d.ts.map +0 -1
  107. package/esm/socket/controller.js +0 -66
  108. package/esm/socket/controller.js.map +0 -1
  109. package/esm/stream/detect.bak.d.ts +0 -240
  110. package/esm/stream/detect.bak.d.ts.map +0 -1
  111. package/esm/stream/detect.bak.js +0 -60
  112. package/esm/stream/detect.bak.js.map +0 -1
  113. package/esm/utils/encoding.d.ts +0 -3
  114. package/esm/utils/encoding.d.ts.map +0 -1
  115. package/esm/utils/encoding.js +0 -11
  116. package/esm/utils/encoding.js.map +0 -1
package/src/adb.ts CHANGED
@@ -1,270 +1,280 @@
1
- // cspell: ignore libusb
2
-
3
- import { PromiseResolver } from '@yume-chan/async';
4
- import { AdbAuthenticationProcessor, ADB_DEFAULT_AUTHENTICATORS, type AdbCredentialStore } from './auth.js';
5
- import { AdbPower, AdbReverseCommand, AdbSubprocess, AdbSync, AdbTcpIpCommand, escapeArg, framebuffer, install, type AdbFrameBuffer } from './commands/index.js';
6
- import { AdbFeatures } from './features.js';
7
- import { AdbCommand, calculateChecksum, type AdbPacketData, type AdbPacketInit } from './packet.js';
8
- import { AdbPacketDispatcher, type AdbSocket } from './socket/index.js';
9
- import { AbortController, DecodeUtf8Stream, GatherStringStream, WritableStream, type ReadableWritablePair } from "./stream/index.js";
10
- import { decodeUtf8, encodeUtf8 } from "./utils/index.js";
11
-
12
- export enum AdbPropKey {
13
- Product = 'ro.product.name',
14
- Model = 'ro.product.model',
15
- Device = 'ro.product.device',
16
- Features = 'features',
17
- }
18
-
19
- export const VERSION_OMIT_CHECKSUM = 0x01000001;
20
-
21
- export class Adb {
22
- /**
23
- * It's possible to call `authenticate` multiple times on a single connection,
24
- * every time the device receives a `CNXN` packet, it resets its internal state,
25
- * and starts a new authentication process.
26
- */
27
- public static async authenticate(
28
- connection: ReadableWritablePair<AdbPacketData, AdbPacketInit>,
29
- credentialStore: AdbCredentialStore,
30
- authenticators = ADB_DEFAULT_AUTHENTICATORS,
31
- ): Promise<Adb> {
32
- // Initially, set to highest-supported version and payload size.
33
- let version = 0x01000001;
34
- let maxPayloadSize = 0x100000;
35
-
36
- const resolver = new PromiseResolver<string>();
37
- const authProcessor = new AdbAuthenticationProcessor(authenticators, credentialStore);
38
-
39
- // Here is similar to `AdbPacketDispatcher`,
40
- // But the received packet types and send packet processing are different.
41
- const abortController = new AbortController();
42
- const pipe = connection.readable
43
- .pipeTo(new WritableStream({
44
- async write(packet) {
45
- switch (packet.command) {
46
- case AdbCommand.Connect:
47
- version = Math.min(version, packet.arg0);
48
- maxPayloadSize = Math.min(maxPayloadSize, packet.arg1);
49
- resolver.resolve(decodeUtf8(packet.payload));
50
- break;
51
- case AdbCommand.Auth:
52
- const response = await authProcessor.process(packet);
53
- await sendPacket(response);
54
- break;
55
- default:
56
- // Maybe the previous ADB session exited without reading all packets,
57
- // so they are still waiting in OS internal buffer.
58
- // Just ignore them.
59
- // Because a `Connect` packet will reset the device,
60
- // Eventually there will be `Connect` and `Auth` response packets.
61
- break;
62
- }
63
- }
64
- }), {
65
- preventCancel: true,
66
- signal: abortController.signal,
67
- })
68
- .catch((e) => {
69
- resolver.reject(e);
70
- });
71
-
72
- const writer = connection.writable.getWriter();
73
- async function sendPacket(init: AdbPacketData) {
74
- // Always send checksum in auth steps
75
- // Because we don't know if the device needs it or not.
76
- await writer.write(calculateChecksum(init));
77
- }
78
-
79
- try {
80
- // https://android.googlesource.com/platform/packages/modules/adb/+/79010dc6d5ca7490c493df800d4421730f5466ca/transport.cpp#1252
81
- // There are some other feature constants, but some of them are only used by ADB server, not devices.
82
- const features = [
83
- AdbFeatures.ShellV2,
84
- AdbFeatures.Cmd,
85
- AdbFeatures.StatV2,
86
- AdbFeatures.ListV2,
87
- 'fixed_push_mkdir',
88
- 'apex',
89
- 'abb',
90
- 'fixed_push_symlink_timestamp',
91
- 'abb_exec',
92
- 'remount_shell',
93
- 'track_app',
94
- 'sendrecv_v2',
95
- 'sendrecv_v2_brotli',
96
- 'sendrecv_v2_lz4',
97
- 'sendrecv_v2_zstd',
98
- 'sendrecv_v2_dry_run_send',
99
- ].join(',');
100
-
101
- await sendPacket({
102
- command: AdbCommand.Connect,
103
- arg0: version,
104
- arg1: maxPayloadSize,
105
- // The terminating `;` is required in formal definition
106
- // But ADB daemon (all versions) can still work without it
107
- payload: encodeUtf8(`host::features=${features};`),
108
- });
109
-
110
- const banner = await resolver.promise;
111
-
112
- // Stop piping before creating `Adb` object
113
- // Because `AdbPacketDispatcher` will lock the streams when initializing
114
- abortController.abort();
115
- writer.releaseLock();
116
-
117
- // Wait until pipe stops (`ReadableStream` lock released)
118
- await pipe;
119
-
120
- return new Adb(
121
- connection,
122
- version,
123
- maxPayloadSize,
124
- banner,
125
- );
126
- } catch (e) {
127
- abortController.abort();
128
- writer.releaseLock();
129
- throw e;
130
- }
131
- }
132
-
133
- private readonly packetDispatcher: AdbPacketDispatcher;
134
-
135
- public get disconnected() { return this.packetDispatcher.disconnected; }
136
-
137
- private _protocolVersion: number | undefined;
138
- public get protocolVersion() { return this._protocolVersion; }
139
-
140
- private _product: string | undefined;
141
- public get product() { return this._product; }
142
-
143
- private _model: string | undefined;
144
- public get model() { return this._model; }
145
-
146
- private _device: string | undefined;
147
- public get device() { return this._device; }
148
-
149
- private _features: AdbFeatures[] | undefined;
150
- public get features() { return this._features; }
151
-
152
- public readonly subprocess: AdbSubprocess;
153
- public readonly power: AdbPower;
154
- public readonly reverse: AdbReverseCommand;
155
- public readonly tcpip: AdbTcpIpCommand;
156
-
157
- public constructor(
158
- connection: ReadableWritablePair<AdbPacketData, AdbPacketInit>,
159
- version: number,
160
- maxPayloadSize: number,
161
- banner: string,
162
- ) {
163
- this.parseBanner(banner);
164
-
165
- let calculateChecksum: boolean;
166
- let appendNullToServiceString: boolean;
167
- if (version >= VERSION_OMIT_CHECKSUM) {
168
- calculateChecksum = false;
169
- appendNullToServiceString = false;
170
- } else {
171
- calculateChecksum = true;
172
- appendNullToServiceString = true;
173
- }
174
-
175
- this.packetDispatcher = new AdbPacketDispatcher(
176
- connection,
177
- {
178
- calculateChecksum,
179
- appendNullToServiceString,
180
- maxPayloadSize,
181
- }
182
- );
183
-
184
- this._protocolVersion = version;
185
-
186
- this.subprocess = new AdbSubprocess(this);
187
- this.power = new AdbPower(this);
188
- this.reverse = new AdbReverseCommand(this.packetDispatcher);
189
- this.tcpip = new AdbTcpIpCommand(this);
190
- }
191
-
192
- private parseBanner(banner: string): void {
193
- this._features = [];
194
-
195
- const pieces = banner.split('::');
196
- if (pieces.length > 1) {
197
- const props = pieces[1]!;
198
- for (const prop of props.split(';')) {
199
- if (!prop) {
200
- continue;
201
- }
202
-
203
- const keyValue = prop.split('=');
204
- if (keyValue.length !== 2) {
205
- continue;
206
- }
207
-
208
- const [key, value] = keyValue;
209
- switch (key) {
210
- case AdbPropKey.Product:
211
- this._product = value;
212
- break;
213
- case AdbPropKey.Model:
214
- this._model = value;
215
- break;
216
- case AdbPropKey.Device:
217
- this._device = value;
218
- break;
219
- case AdbPropKey.Features:
220
- this._features = value!.split(',') as AdbFeatures[];
221
- break;
222
- }
223
- }
224
- }
225
- }
226
-
227
- public async createSocket(service: string): Promise<AdbSocket> {
228
- return this.packetDispatcher.createSocket(service);
229
- }
230
-
231
- public async createSocketAndWait(service: string): Promise<string> {
232
- const socket = await this.createSocket(service);
233
- const gatherStream = new GatherStringStream();
234
- await socket.readable
235
- .pipeThrough(new DecodeUtf8Stream())
236
- .pipeTo(gatherStream);
237
- return gatherStream.result;
238
- }
239
-
240
- public async getProp(key: string): Promise<string> {
241
- const stdout = await this.subprocess.spawnAndWaitLegacy(
242
- ['getprop', key]
243
- );
244
- return stdout.trim();
245
- }
246
-
247
- public async rm(...filenames: string[]): Promise<string> {
248
- const stdout = await this.subprocess.spawnAndWaitLegacy(
249
- ['rm', '-rf', ...filenames.map(arg => escapeArg(arg))],
250
- );
251
- return stdout;
252
- }
253
-
254
- public install() {
255
- return install(this);
256
- }
257
-
258
- public async sync(): Promise<AdbSync> {
259
- const socket = await this.createSocket('sync:');
260
- return new AdbSync(this, socket);
261
- }
262
-
263
- public async framebuffer(): Promise<AdbFrameBuffer> {
264
- return framebuffer(this);
265
- }
266
-
267
- public async dispose(): Promise<void> {
268
- this.packetDispatcher.dispose();
269
- }
270
- }
1
+ // cspell: ignore libusb
2
+
3
+ import { PromiseResolver } from '@yume-chan/async';
4
+ import { AdbAuthenticationProcessor, ADB_DEFAULT_AUTHENTICATORS, type AdbCredentialStore } from './auth.js';
5
+ import { AdbPower, AdbReverseCommand, AdbSubprocess, AdbSync, AdbTcpIpCommand, escapeArg, framebuffer, install, type AdbFrameBuffer } from './commands/index.js';
6
+ import { AdbFeatures } from './features.js';
7
+ import { AdbCommand, calculateChecksum, type AdbPacketData, type AdbPacketInit } from './packet.js';
8
+ import { AdbIncomingSocketHandler, AdbPacketDispatcher, type AdbSocket, type Closeable } from './socket/index.js';
9
+ import { AbortController, DecodeUtf8Stream, GatherStringStream, WritableStream, type ReadableWritablePair } from "./stream/index.js";
10
+ import { decodeUtf8, encodeUtf8 } from "./utils/index.js";
11
+
12
+ export enum AdbPropKey {
13
+ Product = 'ro.product.name',
14
+ Model = 'ro.product.model',
15
+ Device = 'ro.product.device',
16
+ Features = 'features',
17
+ }
18
+
19
+ export const VERSION_OMIT_CHECKSUM = 0x01000001;
20
+
21
+ export class Adb implements Closeable {
22
+ /**
23
+ * It's possible to call `authenticate` multiple times on a single connection,
24
+ * every time the device receives a `CNXN` packet, it resets its internal state,
25
+ * and starts a new authentication process.
26
+ */
27
+ public static async authenticate(
28
+ connection: ReadableWritablePair<AdbPacketData, AdbPacketInit>,
29
+ credentialStore: AdbCredentialStore,
30
+ authenticators = ADB_DEFAULT_AUTHENTICATORS,
31
+ ): Promise<Adb> {
32
+ // Initially, set to highest-supported version and payload size.
33
+ let version = 0x01000001;
34
+ let maxPayloadSize = 0x100000;
35
+
36
+ const resolver = new PromiseResolver<string>();
37
+ const authProcessor = new AdbAuthenticationProcessor(authenticators, credentialStore);
38
+
39
+ // Here is similar to `AdbPacketDispatcher`,
40
+ // But the received packet types and send packet processing are different.
41
+ const abortController = new AbortController();
42
+ const pipe = connection.readable
43
+ .pipeTo(new WritableStream({
44
+ async write(packet) {
45
+ switch (packet.command) {
46
+ case AdbCommand.Connect:
47
+ version = Math.min(version, packet.arg0);
48
+ maxPayloadSize = Math.min(maxPayloadSize, packet.arg1);
49
+ resolver.resolve(decodeUtf8(packet.payload));
50
+ break;
51
+ case AdbCommand.Auth:
52
+ const response = await authProcessor.process(packet);
53
+ await sendPacket(response);
54
+ break;
55
+ default:
56
+ // Maybe the previous ADB client exited without reading all packets,
57
+ // so they are still waiting in OS internal buffer.
58
+ // Just ignore them.
59
+ // Because a `Connect` packet will reset the device,
60
+ // Eventually there will be `Connect` and `Auth` response packets.
61
+ break;
62
+ }
63
+ }
64
+ }), {
65
+ preventCancel: true,
66
+ signal: abortController.signal,
67
+ })
68
+ .catch((e) => {
69
+ resolver.reject(e);
70
+ });
71
+
72
+ const writer = connection.writable.getWriter();
73
+ async function sendPacket(init: AdbPacketData) {
74
+ // Always send checksum in auth steps
75
+ // Because we don't know if the device needs it or not.
76
+ await writer.write(calculateChecksum(init));
77
+ }
78
+
79
+ let banner: string;
80
+ try {
81
+ // https://android.googlesource.com/platform/packages/modules/adb/+/79010dc6d5ca7490c493df800d4421730f5466ca/transport.cpp#1252
82
+ // There are some other feature constants, but some of them are only used by ADB server, not devices (daemons).
83
+ const features = [
84
+ AdbFeatures.ShellV2,
85
+ AdbFeatures.Cmd,
86
+ AdbFeatures.StatV2,
87
+ AdbFeatures.ListV2,
88
+ AdbFeatures.FixedPushMkdir,
89
+ 'apex',
90
+ 'abb',
91
+ // only tells the client the symlink timestamp issue in `adb push --sync` has been fixed.
92
+ // No special handling required.
93
+ 'fixed_push_symlink_timestamp',
94
+ 'abb_exec',
95
+ 'remount_shell',
96
+ 'track_app',
97
+ 'sendrecv_v2',
98
+ 'sendrecv_v2_brotli',
99
+ 'sendrecv_v2_lz4',
100
+ 'sendrecv_v2_zstd',
101
+ 'sendrecv_v2_dry_run_send',
102
+ ].join(',');
103
+
104
+ await sendPacket({
105
+ command: AdbCommand.Connect,
106
+ arg0: version,
107
+ arg1: maxPayloadSize,
108
+ // The terminating `;` is required in formal definition
109
+ // But ADB daemon (all versions) can still work without it
110
+ payload: encodeUtf8(`host::features=${features};`),
111
+ });
112
+
113
+ banner = await resolver.promise;
114
+ } finally {
115
+ // When failed, release locks on `connection` so the caller can try again.
116
+ // When success, also release locks so `AdbPacketDispatcher` can use them.
117
+ abortController.abort();
118
+ writer.releaseLock();
119
+
120
+ // Wait until pipe stops (`ReadableStream` lock released)
121
+ await pipe;
122
+ }
123
+
124
+ return new Adb(
125
+ connection,
126
+ version,
127
+ maxPayloadSize,
128
+ banner,
129
+ );
130
+ }
131
+
132
+ private readonly dispatcher: AdbPacketDispatcher;
133
+
134
+ public get disconnected() { return this.dispatcher.disconnected; }
135
+
136
+ private _protocolVersion: number | undefined;
137
+ public get protocolVersion() { return this._protocolVersion; }
138
+
139
+ private _product: string | undefined;
140
+ public get product() { return this._product; }
141
+
142
+ private _model: string | undefined;
143
+ public get model() { return this._model; }
144
+
145
+ private _device: string | undefined;
146
+ public get device() { return this._device; }
147
+
148
+ private _features: AdbFeatures[] | undefined;
149
+ public get features() { return this._features; }
150
+
151
+ public readonly subprocess: AdbSubprocess;
152
+ public readonly power: AdbPower;
153
+ public readonly reverse: AdbReverseCommand;
154
+ public readonly tcpip: AdbTcpIpCommand;
155
+
156
+ public constructor(
157
+ connection: ReadableWritablePair<AdbPacketData, AdbPacketInit>,
158
+ version: number,
159
+ maxPayloadSize: number,
160
+ banner: string,
161
+ ) {
162
+ this.parseBanner(banner);
163
+
164
+ let calculateChecksum: boolean;
165
+ let appendNullToServiceString: boolean;
166
+ if (version >= VERSION_OMIT_CHECKSUM) {
167
+ calculateChecksum = false;
168
+ appendNullToServiceString = false;
169
+ } else {
170
+ calculateChecksum = true;
171
+ appendNullToServiceString = true;
172
+ }
173
+
174
+ this.dispatcher = new AdbPacketDispatcher(
175
+ connection,
176
+ {
177
+ calculateChecksum,
178
+ appendNullToServiceString,
179
+ maxPayloadSize,
180
+ }
181
+ );
182
+
183
+ this._protocolVersion = version;
184
+
185
+ this.subprocess = new AdbSubprocess(this);
186
+ this.power = new AdbPower(this);
187
+ this.reverse = new AdbReverseCommand(this);
188
+ this.tcpip = new AdbTcpIpCommand(this);
189
+ }
190
+
191
+ private parseBanner(banner: string): void {
192
+ this._features = [];
193
+
194
+ const pieces = banner.split('::');
195
+ if (pieces.length > 1) {
196
+ const props = pieces[1]!;
197
+ for (const prop of props.split(';')) {
198
+ if (!prop) {
199
+ continue;
200
+ }
201
+
202
+ const keyValue = prop.split('=');
203
+ if (keyValue.length !== 2) {
204
+ continue;
205
+ }
206
+
207
+ const [key, value] = keyValue;
208
+ switch (key) {
209
+ case AdbPropKey.Product:
210
+ this._product = value;
211
+ break;
212
+ case AdbPropKey.Model:
213
+ this._model = value;
214
+ break;
215
+ case AdbPropKey.Device:
216
+ this._device = value;
217
+ break;
218
+ case AdbPropKey.Features:
219
+ this._features = value!.split(',') as AdbFeatures[];
220
+ break;
221
+ }
222
+ }
223
+ }
224
+ }
225
+
226
+ public addIncomingSocketHandler(handler: AdbIncomingSocketHandler) {
227
+ return this.dispatcher.addIncomingSocketHandler(handler);
228
+ }
229
+
230
+ public async createSocket(service: string): Promise<AdbSocket> {
231
+ return this.dispatcher.createSocket(service);
232
+ }
233
+
234
+ public async createSocketAndWait(service: string): Promise<string> {
235
+ const socket = await this.createSocket(service);
236
+ const gatherStream = new GatherStringStream();
237
+ await socket.readable
238
+ .pipeThrough(new DecodeUtf8Stream())
239
+ .pipeTo(gatherStream);
240
+ return gatherStream.result;
241
+ }
242
+
243
+ public async getProp(key: string): Promise<string> {
244
+ const stdout = await this.subprocess.spawnAndWaitLegacy(
245
+ ['getprop', key]
246
+ );
247
+ return stdout.trim();
248
+ }
249
+
250
+ public async rm(...filenames: string[]): Promise<string> {
251
+ const stdout = await this.subprocess.spawnAndWaitLegacy(
252
+ ['rm', '-rf', ...filenames.map(arg => escapeArg(arg))],
253
+ );
254
+ return stdout;
255
+ }
256
+
257
+ public install() {
258
+ return install(this);
259
+ }
260
+
261
+ public async sync(): Promise<AdbSync> {
262
+ const socket = await this.createSocket('sync:');
263
+ return new AdbSync(this, socket);
264
+ }
265
+
266
+ public async framebuffer(): Promise<AdbFrameBuffer> {
267
+ return framebuffer(this);
268
+ }
269
+
270
+ /**
271
+ * Close the ADB connection.
272
+ *
273
+ * Note that it won't close the streams from backends.
274
+ * The streams are both physically and logically intact,
275
+ * and can be reused.
276
+ */
277
+ public async close(): Promise<void> {
278
+ await this.dispatcher.close();
279
+ }
280
+ }