appium-adb 16.0.0 → 16.0.1
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.md +6 -0
- package/build/lib/adb.d.ts +11 -11
- package/build/lib/adb.d.ts.map +1 -1
- package/build/lib/adb.js +9 -9
- package/build/lib/adb.js.map +1 -1
- package/build/lib/logcat.d.ts +1 -1
- package/build/lib/logcat.d.ts.map +1 -1
- package/build/lib/logcat.js +4 -14
- package/build/lib/logcat.js.map +1 -1
- package/build/lib/tools/aab-utils.d.ts.map +1 -1
- package/build/lib/tools/aab-utils.js +4 -4
- package/build/lib/tools/aab-utils.js.map +1 -1
- package/build/lib/tools/android-manifest.d.ts.map +1 -1
- package/build/lib/tools/android-manifest.js +4 -7
- package/build/lib/tools/android-manifest.js.map +1 -1
- package/build/lib/tools/apk-signing.d.ts.map +1 -1
- package/build/lib/tools/apk-signing.js +9 -11
- package/build/lib/tools/apk-signing.js.map +1 -1
- package/build/lib/tools/apk-utils.d.ts.map +1 -1
- package/build/lib/tools/apk-utils.js +19 -38
- package/build/lib/tools/apk-utils.js.map +1 -1
- package/build/lib/tools/apks-utils.d.ts.map +1 -1
- package/build/lib/tools/apks-utils.js +3 -3
- package/build/lib/tools/apks-utils.js.map +1 -1
- package/build/lib/tools/app-commands.d.ts.map +1 -1
- package/build/lib/tools/app-commands.js +11 -15
- package/build/lib/tools/app-commands.js.map +1 -1
- package/build/lib/tools/device-settings.d.ts.map +1 -1
- package/build/lib/tools/device-settings.js +6 -17
- package/build/lib/tools/device-settings.js.map +1 -1
- package/build/lib/tools/emulator-commands.d.ts.map +1 -1
- package/build/lib/tools/emulator-commands.js +6 -8
- package/build/lib/tools/emulator-commands.js.map +1 -1
- package/build/lib/tools/fs-commands.d.ts +1 -1
- package/build/lib/tools/fs-commands.d.ts.map +1 -1
- package/build/lib/tools/fs-commands.js.map +1 -1
- package/build/lib/tools/general-commands.d.ts.map +1 -1
- package/build/lib/tools/general-commands.js +3 -5
- package/build/lib/tools/general-commands.js.map +1 -1
- package/build/lib/tools/keyboard-commands.d.ts.map +1 -1
- package/build/lib/tools/keyboard-commands.js +1 -1
- package/build/lib/tools/keyboard-commands.js.map +1 -1
- package/build/lib/tools/lockmgmt.d.ts.map +1 -1
- package/build/lib/tools/lockmgmt.js +4 -10
- package/build/lib/tools/lockmgmt.js.map +1 -1
- package/build/lib/tools/logcat-commands.d.ts.map +1 -1
- package/build/lib/tools/logcat-commands.js.map +1 -1
- package/build/lib/tools/network-commands.d.ts.map +1 -1
- package/build/lib/tools/network-commands.js.map +1 -1
- package/build/lib/tools/process-commands.d.ts.map +1 -1
- package/build/lib/tools/process-commands.js +1 -1
- package/build/lib/tools/process-commands.js.map +1 -1
- package/build/lib/tools/system-calls.d.ts.map +1 -1
- package/build/lib/tools/system-calls.js +15 -11
- package/build/lib/tools/system-calls.js.map +1 -1
- package/build/lib/tools/types.d.ts.map +1 -1
- package/build/lib/utils/helpers/index.d.ts +1 -1
- package/build/lib/utils/helpers/index.d.ts.map +1 -1
- package/build/lib/utils/helpers/index.js +1 -1
- package/build/lib/utils/helpers/index.js.map +1 -1
- package/build/lib/utils/helpers/install.d.ts.map +1 -1
- package/build/lib/utils/helpers/install.js.map +1 -1
- package/build/lib/utils/helpers/manifest.d.ts.map +1 -1
- package/build/lib/utils/helpers/manifest.js.map +1 -1
- package/build/lib/utils/helpers/resource.d.ts.map +1 -1
- package/build/lib/utils/helpers/resource.js +1 -2
- package/build/lib/utils/helpers/resource.js.map +1 -1
- package/build/lib/utils/helpers/sdk.d.ts.map +1 -1
- package/build/lib/utils/helpers/sdk.js +1 -1
- package/build/lib/utils/helpers/sdk.js.map +1 -1
- package/build/lib/utils/index.d.ts +1 -1
- package/build/lib/utils/index.d.ts.map +1 -1
- package/build/lib/utils/index.js +1 -1
- package/build/lib/utils/index.js.map +1 -1
- package/build/lib/utils/lodash/core.d.ts.map +1 -1
- package/build/lib/utils/lodash/core.js.map +1 -1
- package/lib/adb.ts +14 -13
- package/lib/logcat.ts +9 -23
- package/lib/tools/aab-utils.ts +9 -15
- package/lib/tools/android-manifest.ts +12 -28
- package/lib/tools/apk-signing.ts +16 -41
- package/lib/tools/apk-utils.ts +27 -82
- package/lib/tools/apks-utils.ts +10 -21
- package/lib/tools/app-commands.ts +31 -95
- package/lib/tools/device-settings.ts +15 -48
- package/lib/tools/emulator-commands.ts +13 -38
- package/lib/tools/fs-commands.ts +3 -1
- package/lib/tools/general-commands.ts +6 -13
- package/lib/tools/keyboard-commands.ts +2 -1
- package/lib/tools/lockmgmt.ts +12 -42
- package/lib/tools/logcat-commands.ts +1 -1
- package/lib/tools/network-commands.ts +4 -11
- package/lib/tools/process-commands.ts +4 -11
- package/lib/tools/system-calls.ts +59 -137
- package/lib/tools/types.ts +4 -8
- package/lib/utils/helpers/index.ts +1 -6
- package/lib/utils/helpers/install.ts +2 -4
- package/lib/utils/helpers/manifest.ts +4 -11
- package/lib/utils/helpers/resource.ts +5 -9
- package/lib/utils/helpers/sdk.ts +5 -9
- package/lib/utils/index.ts +2 -1
- package/lib/utils/lodash/core.ts +3 -9
- package/package.json +36 -46
package/lib/tools/lockmgmt.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {util} from '@appium/support';
|
|
2
2
|
import {sleep, waitForCondition} from 'asyncbox';
|
|
3
|
+
|
|
3
4
|
import type {ADB} from '../adb.js';
|
|
4
|
-
import {
|
|
5
|
+
import {log} from '../logger.js';
|
|
5
6
|
|
|
6
7
|
const CREDENTIAL_CANNOT_BE_NULL_OR_EMPTY_ERROR = `Credential can't be null or empty`;
|
|
7
8
|
const CREDENTIAL_DID_NOT_MATCH_ERROR = `didn't match`;
|
|
@@ -24,10 +25,7 @@ export async function isLockManagementSupported(this: ADB): Promise<boolean> {
|
|
|
24
25
|
output = await this.shell([`locksettings help && echo ${passFlag}`]);
|
|
25
26
|
} catch {}
|
|
26
27
|
this._isLockManagementSupported = output.includes(passFlag);
|
|
27
|
-
log.debug(
|
|
28
|
-
`Extended lock settings management is ` +
|
|
29
|
-
`${this._isLockManagementSupported ? '' : 'not '}supported`,
|
|
30
|
-
);
|
|
28
|
+
log.debug(`Extended lock settings management is ${this._isLockManagementSupported ? '' : 'not '}supported`);
|
|
31
29
|
}
|
|
32
30
|
return this._isLockManagementSupported as boolean;
|
|
33
31
|
}
|
|
@@ -44,10 +42,7 @@ export async function isLockManagementSupported(this: ADB): Promise<boolean> {
|
|
|
44
42
|
* @return True if the given credential matches to the device's one
|
|
45
43
|
* @throws {Error} If the verification faces an unexpected error
|
|
46
44
|
*/
|
|
47
|
-
export async function verifyLockCredential(
|
|
48
|
-
this: ADB,
|
|
49
|
-
credential: string | null = null,
|
|
50
|
-
): Promise<boolean> {
|
|
45
|
+
export async function verifyLockCredential(this: ADB, credential: string | null = null): Promise<boolean> {
|
|
51
46
|
try {
|
|
52
47
|
const {stdout, stderr} = await this.shell(buildCommand('verify', credential), {
|
|
53
48
|
outputFormat: this.EXEC_OUTPUT_FORMAT.FULL,
|
|
@@ -55,11 +50,7 @@ export async function verifyLockCredential(
|
|
|
55
50
|
if (stdout?.includes('verified successfully')) {
|
|
56
51
|
return true;
|
|
57
52
|
}
|
|
58
|
-
if (
|
|
59
|
-
[`didn't match`, CREDENTIAL_CANNOT_BE_NULL_OR_EMPTY_ERROR].some((x) =>
|
|
60
|
-
(stderr || stdout)?.includes(x),
|
|
61
|
-
)
|
|
62
|
-
) {
|
|
53
|
+
if ([`didn't match`, CREDENTIAL_CANNOT_BE_NULL_OR_EMPTY_ERROR].some((x) => (stderr || stdout)?.includes(x))) {
|
|
63
54
|
return false;
|
|
64
55
|
}
|
|
65
56
|
throw new Error(stderr || stdout);
|
|
@@ -88,19 +79,12 @@ export async function verifyLockCredential(
|
|
|
88
79
|
* null/empty value assumes the device has no lock currently set.
|
|
89
80
|
* @throws {Error} If operation faces an unexpected error
|
|
90
81
|
*/
|
|
91
|
-
export async function clearLockCredential(
|
|
92
|
-
this: ADB,
|
|
93
|
-
credential: string | null = null,
|
|
94
|
-
): Promise<void> {
|
|
82
|
+
export async function clearLockCredential(this: ADB, credential: string | null = null): Promise<void> {
|
|
95
83
|
try {
|
|
96
84
|
const {stdout, stderr} = await this.shell(buildCommand('clear', credential), {
|
|
97
85
|
outputFormat: this.EXEC_OUTPUT_FORMAT.FULL,
|
|
98
86
|
});
|
|
99
|
-
if (
|
|
100
|
-
!['user has no password', 'Lock credential cleared'].some((x) =>
|
|
101
|
-
(stderr || stdout)?.includes(x),
|
|
102
|
-
)
|
|
103
|
-
) {
|
|
87
|
+
if (!['user has no password', 'Lock credential cleared'].some((x) => (stderr || stdout)?.includes(x))) {
|
|
104
88
|
throw new Error(stderr || stdout);
|
|
105
89
|
}
|
|
106
90
|
} catch (e) {
|
|
@@ -141,10 +125,7 @@ export async function isLockEnabled(this: ADB): Promise<boolean> {
|
|
|
141
125
|
}
|
|
142
126
|
throw new Error(stderr || stdout);
|
|
143
127
|
} catch (e) {
|
|
144
|
-
throw new Error(
|
|
145
|
-
`Cannot check if device lock is enabled. Original error: ${(e as Error).message}`,
|
|
146
|
-
{cause: e},
|
|
147
|
-
);
|
|
128
|
+
throw new Error(`Cannot check if device lock is enabled. Original error: ${(e as Error).message}`, {cause: e});
|
|
148
129
|
}
|
|
149
130
|
}
|
|
150
131
|
|
|
@@ -301,9 +282,7 @@ export function isShowingLockscreen(dumpsys: string): boolean {
|
|
|
301
282
|
return (
|
|
302
283
|
['mShowingLockscreen=true', 'mDreamingLockscreen=true'].some((x) => dumpsys.includes(x)) ||
|
|
303
284
|
// `mIsShowing` and `mInputRestricted` are `true` in lock condition. `false` is unlock condition.
|
|
304
|
-
[/KeyguardStateMonitor[\n\s]+mIsShowing=true/, /\s+mInputRestricted=true/].every((x) =>
|
|
305
|
-
x.test(dumpsys),
|
|
306
|
-
)
|
|
285
|
+
[/KeyguardStateMonitor[\n\s]+mIsShowing=true/, /\s+mInputRestricted=true/].every((x) => x.test(dumpsys))
|
|
307
286
|
);
|
|
308
287
|
}
|
|
309
288
|
|
|
@@ -325,11 +304,7 @@ export function isScreenStateOff(dumpsys: string): boolean {
|
|
|
325
304
|
* @param oldCredential
|
|
326
305
|
* @param args
|
|
327
306
|
*/
|
|
328
|
-
function buildCommand(
|
|
329
|
-
verb: string,
|
|
330
|
-
oldCredential: string | null = null,
|
|
331
|
-
...args: string[]
|
|
332
|
-
): string[] {
|
|
307
|
+
function buildCommand(verb: string, oldCredential: string | null = null, ...args: string[]): string[] {
|
|
333
308
|
const cmd = ['locksettings', verb];
|
|
334
309
|
if (oldCredential && !util.isEmpty(oldCredential)) {
|
|
335
310
|
cmd.push('--old', oldCredential);
|
|
@@ -357,12 +332,7 @@ async function swipeUp(this: ADB, windowDumpsys: string): Promise<void> {
|
|
|
357
332
|
const y0 = (displayHeight / 5) * 4;
|
|
358
333
|
const x1 = x0;
|
|
359
334
|
const y1 = displayHeight / 5;
|
|
360
|
-
await this.shell([
|
|
361
|
-
'input',
|
|
362
|
-
'touchscreen',
|
|
363
|
-
'swipe',
|
|
364
|
-
...[x0, y0, x1, y1].map((c) => `${Math.trunc(c)}`),
|
|
365
|
-
]);
|
|
335
|
+
await this.shell(['input', 'touchscreen', 'swipe', ...[x0, y0, x1, y1].map((c) => `${Math.trunc(c)}`)]);
|
|
366
336
|
}
|
|
367
337
|
|
|
368
338
|
/**
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import {EOL} from 'node:os';
|
|
2
|
-
|
|
2
|
+
|
|
3
3
|
import type {ADB} from '../adb.js';
|
|
4
|
+
import {log} from '../logger.js';
|
|
4
5
|
import type {PortFamily, PortInfo} from './types.js';
|
|
5
6
|
|
|
6
7
|
/**
|
|
@@ -21,11 +22,7 @@ export async function getForwardList(this: ADB): Promise<string[]> {
|
|
|
21
22
|
* @param systemPort - The number of the local system port.
|
|
22
23
|
* @param devicePort - The number of the remote device port.
|
|
23
24
|
*/
|
|
24
|
-
export async function forwardPort(
|
|
25
|
-
this: ADB,
|
|
26
|
-
systemPort: string | number,
|
|
27
|
-
devicePort: string | number,
|
|
28
|
-
): Promise<void> {
|
|
25
|
+
export async function forwardPort(this: ADB, systemPort: string | number, devicePort: string | number): Promise<void> {
|
|
29
26
|
log.debug(`Forwarding system: ${systemPort} to device: ${devicePort}`);
|
|
30
27
|
await this.adbExec(['forward', `tcp:${systemPort}`, `tcp:${devicePort}`]);
|
|
31
28
|
}
|
|
@@ -61,11 +58,7 @@ export async function getReverseList(this: ADB): Promise<string[]> {
|
|
|
61
58
|
* @param devicePort - The number of the remote device port.
|
|
62
59
|
* @param systemPort - The number of the local system port.
|
|
63
60
|
*/
|
|
64
|
-
export async function reversePort(
|
|
65
|
-
this: ADB,
|
|
66
|
-
devicePort: string | number,
|
|
67
|
-
systemPort: string | number,
|
|
68
|
-
): Promise<void> {
|
|
61
|
+
export async function reversePort(this: ADB, devicePort: string | number, systemPort: string | number): Promise<void> {
|
|
69
62
|
log.debug(`Forwarding device: ${devicePort} to system: ${systemPort}`);
|
|
70
63
|
await this.adbExec(['reverse', `tcp:${devicePort}`, `tcp:${systemPort}`]);
|
|
71
64
|
}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import {log} from '../logger.js';
|
|
2
1
|
import {util} from '@appium/support';
|
|
3
2
|
import type {ExecError} from 'teen_process';
|
|
3
|
+
|
|
4
4
|
import type {ADB} from '../adb.js';
|
|
5
|
+
import {log} from '../logger.js';
|
|
5
6
|
|
|
6
7
|
const PID_COLUMN_TITLE: string = 'PID';
|
|
7
8
|
const PROCESS_NAME_COLUMN_TITLE: string = 'NAME';
|
|
@@ -118,11 +119,7 @@ export async function getProcessIdsByName(this: ADB, name: string): Promise<numb
|
|
|
118
119
|
* @param signal - The signal to send to the process. Default is 'SIGTERM' ('15').
|
|
119
120
|
* @throws {Error} If the processes cannot be killed.
|
|
120
121
|
*/
|
|
121
|
-
export async function killProcessesByName(
|
|
122
|
-
this: ADB,
|
|
123
|
-
name: string,
|
|
124
|
-
signal: string = 'SIGTERM',
|
|
125
|
-
): Promise<void> {
|
|
122
|
+
export async function killProcessesByName(this: ADB, name: string, signal: string = 'SIGTERM'): Promise<void> {
|
|
126
123
|
try {
|
|
127
124
|
log.debug(`Attempting to kill all ${name} processes`);
|
|
128
125
|
const pids: number[] = await this.getProcessIdsByName(name);
|
|
@@ -148,11 +145,7 @@ export async function killProcessesByName(
|
|
|
148
145
|
* @param signal - The signal to send to the process. Default is 'SIGTERM' ('15').
|
|
149
146
|
* @throws {Error} If the process cannot be killed.
|
|
150
147
|
*/
|
|
151
|
-
export async function killProcessByPID(
|
|
152
|
-
this: ADB,
|
|
153
|
-
pid: string | number,
|
|
154
|
-
signal: string = 'SIGTERM',
|
|
155
|
-
): Promise<void> {
|
|
148
|
+
export async function killProcessByPID(this: ADB, pid: string | number, signal: string = 'SIGTERM'): Promise<void> {
|
|
156
149
|
log.debug(`Attempting to kill process ${pid}`);
|
|
157
150
|
const noProcessFlag: string = 'No such process';
|
|
158
151
|
try {
|
|
@@ -1,18 +1,14 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
|
-
|
|
2
|
+
|
|
3
3
|
import {system, fs, util, tempDir, timing} from '@appium/support';
|
|
4
|
-
import {exec, SubProcess} from 'teen_process';
|
|
5
|
-
import type {ExecError, TeenProcessExecResult} from 'teen_process';
|
|
6
4
|
import {asyncmap, retry, retryInterval, sleep, waitForCondition} from 'asyncbox';
|
|
7
5
|
import * as semver from 'semver';
|
|
6
|
+
import {exec, SubProcess} from 'teen_process';
|
|
7
|
+
import type {ExecError, TeenProcessExecResult} from 'teen_process';
|
|
8
|
+
|
|
8
9
|
import type {ADB} from '../adb.js';
|
|
9
|
-
import {
|
|
10
|
-
|
|
11
|
-
cloneDeep,
|
|
12
|
-
getSdkRootFromEnv,
|
|
13
|
-
memoize,
|
|
14
|
-
zip,
|
|
15
|
-
} from '../utils/index.js';
|
|
10
|
+
import {log} from '../logger.js';
|
|
11
|
+
import {DEFAULT_ADB_EXEC_TIMEOUT, cloneDeep, getSdkRootFromEnv, memoize, zip} from '../utils/index.js';
|
|
16
12
|
import type {
|
|
17
13
|
ConnectedDevicesOptions,
|
|
18
14
|
Device,
|
|
@@ -87,9 +83,7 @@ function _getBinaryNameForOS(binaryName: string): string {
|
|
|
87
83
|
* @returns Array of possible binary location paths
|
|
88
84
|
*/
|
|
89
85
|
function getSdkBinaryLocationCandidates(sdkRoot: string, fullBinaryName: string): string[] {
|
|
90
|
-
return SDK_BINARY_ROOTS.map((x) =>
|
|
91
|
-
path.resolve(sdkRoot, ...(Array.isArray(x) ? x : [x]), fullBinaryName),
|
|
92
|
-
);
|
|
86
|
+
return SDK_BINARY_ROOTS.map((x) => path.resolve(sdkRoot, ...(Array.isArray(x) ? x : [x]), fullBinaryName));
|
|
93
87
|
}
|
|
94
88
|
|
|
95
89
|
/**
|
|
@@ -235,10 +229,7 @@ export async function getConnectedDevices(
|
|
|
235
229
|
* @returns Array of connected devices
|
|
236
230
|
* @throws {Error} If adb devices command fails or returns unexpected output
|
|
237
231
|
*/
|
|
238
|
-
export async function getConnectedDevices(
|
|
239
|
-
this: ADB,
|
|
240
|
-
opts?: ConnectedDevicesOptions,
|
|
241
|
-
): Promise<Device[]>;
|
|
232
|
+
export async function getConnectedDevices(this: ADB, opts?: ConnectedDevicesOptions): Promise<Device[]>;
|
|
242
233
|
export async function getConnectedDevices(
|
|
243
234
|
this: ADB,
|
|
244
235
|
opts: ConnectedDevicesOptions = {},
|
|
@@ -339,9 +330,7 @@ export async function getDevicesWithRetry(this: ADB, timeoutMs: number = 20000):
|
|
|
339
330
|
} catch (err: unknown) {
|
|
340
331
|
const error = err as Error;
|
|
341
332
|
log.debug(error.stack);
|
|
342
|
-
log.warn(
|
|
343
|
-
`Got an unexpected error while fetching connected devices list: ${error.message}`,
|
|
344
|
-
);
|
|
333
|
+
log.warn(`Got an unexpected error while fetching connected devices list: ${error.message}`);
|
|
345
334
|
}
|
|
346
335
|
|
|
347
336
|
try {
|
|
@@ -426,33 +415,27 @@ export async function killServer(this: ADB): Promise<void> {
|
|
|
426
415
|
*
|
|
427
416
|
* @returns True if token was reset successfully, false otherwise
|
|
428
417
|
*/
|
|
429
|
-
export const resetTelnetAuthToken = memoize(
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
418
|
+
export const resetTelnetAuthToken = memoize(async function resetTelnetAuthToken(): Promise<boolean> {
|
|
419
|
+
// The methods is used to remove telnet auth token
|
|
420
|
+
//
|
|
421
|
+
const homeFolderPath = process.env[process.platform === 'win32' ? 'USERPROFILE' : 'HOME'];
|
|
422
|
+
if (!homeFolderPath) {
|
|
423
|
+
log.warn(`Cannot find the path to user home folder. Ignoring resetting of emulator's telnet authentication token`);
|
|
424
|
+
return false;
|
|
425
|
+
}
|
|
426
|
+
const dstPath = path.resolve(homeFolderPath, '.emulator_console_auth_token');
|
|
427
|
+
log.debug(`Overriding ${dstPath} with an empty string to avoid telnet authentication for emulator commands`);
|
|
428
|
+
try {
|
|
429
|
+
await fs.writeFile(dstPath, '');
|
|
430
|
+
} catch (e: unknown) {
|
|
431
|
+
const error = e as Error;
|
|
432
|
+
log.warn(
|
|
433
|
+
`Error ${error.message} while resetting the content of ${dstPath}. Ignoring resetting of emulator's telnet authentication token`,
|
|
443
434
|
);
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
log.warn(
|
|
449
|
-
`Error ${error.message} while resetting the content of ${dstPath}. Ignoring resetting of emulator's telnet authentication token`,
|
|
450
|
-
);
|
|
451
|
-
return false;
|
|
452
|
-
}
|
|
453
|
-
return true;
|
|
454
|
-
},
|
|
455
|
-
);
|
|
435
|
+
return false;
|
|
436
|
+
}
|
|
437
|
+
return true;
|
|
438
|
+
});
|
|
456
439
|
|
|
457
440
|
/**
|
|
458
441
|
* Execute the given emulator command using _adb emu_ tool.
|
|
@@ -494,16 +477,8 @@ export async function adbExec(
|
|
|
494
477
|
* @returns Command stdout
|
|
495
478
|
* @throws {Error} If command execution fails or timeout is exceeded
|
|
496
479
|
*/
|
|
497
|
-
export async function adbExec(
|
|
498
|
-
|
|
499
|
-
cmd: string | string[],
|
|
500
|
-
opts?: AdbExecOptions,
|
|
501
|
-
): Promise<string>;
|
|
502
|
-
export async function adbExec(
|
|
503
|
-
this: ADB,
|
|
504
|
-
cmd: string | string[],
|
|
505
|
-
opts?: AdbExecOptions,
|
|
506
|
-
): Promise<string | ExecResult> {
|
|
480
|
+
export async function adbExec(this: ADB, cmd: string | string[], opts?: AdbExecOptions): Promise<string>;
|
|
481
|
+
export async function adbExec(this: ADB, cmd: string | string[], opts?: AdbExecOptions): Promise<string | ExecResult> {
|
|
507
482
|
if (!cmd) {
|
|
508
483
|
throw new Error('You need to pass in a command to adbExec()');
|
|
509
484
|
}
|
|
@@ -607,16 +582,8 @@ export async function shell(
|
|
|
607
582
|
* @returns Command stdout
|
|
608
583
|
* @throws {Error} If command execution fails
|
|
609
584
|
*/
|
|
610
|
-
export async function shell(
|
|
611
|
-
|
|
612
|
-
cmd: string | string[],
|
|
613
|
-
opts?: ShellExecOptions,
|
|
614
|
-
): Promise<string>;
|
|
615
|
-
export async function shell(
|
|
616
|
-
this: ADB,
|
|
617
|
-
cmd: string | string[],
|
|
618
|
-
opts?: ShellExecOptions,
|
|
619
|
-
): Promise<string | ExecResult> {
|
|
585
|
+
export async function shell(this: ADB, cmd: string | string[], opts?: ShellExecOptions): Promise<string>;
|
|
586
|
+
export async function shell(this: ADB, cmd: string | string[], opts?: ShellExecOptions): Promise<string | ExecResult> {
|
|
620
587
|
const {privileged} = opts ?? {};
|
|
621
588
|
|
|
622
589
|
const cmdArr = Array.isArray(cmd) ? cmd : [cmd];
|
|
@@ -703,10 +670,7 @@ export async function getConnectedEmulators(
|
|
|
703
670
|
* @returns Array of connected emulator devices
|
|
704
671
|
* @throws {Error} If error occurs while getting emulators
|
|
705
672
|
*/
|
|
706
|
-
export async function getConnectedEmulators(
|
|
707
|
-
this: ADB,
|
|
708
|
-
opts?: ConnectedDevicesOptions,
|
|
709
|
-
): Promise<Device[]>;
|
|
673
|
+
export async function getConnectedEmulators(this: ADB, opts?: ConnectedDevicesOptions): Promise<Device[]>;
|
|
710
674
|
export async function getConnectedEmulators(
|
|
711
675
|
this: ADB,
|
|
712
676
|
opts: ConnectedDevicesOptions = {},
|
|
@@ -898,9 +862,7 @@ export async function killEmulator(
|
|
|
898
862
|
}
|
|
899
863
|
}
|
|
900
864
|
await this.adbExec(['emu', 'kill']);
|
|
901
|
-
log.debug(
|
|
902
|
-
`Waiting up to ${timeout}ms until the emulator '${avdName ? avdName : this.curDeviceId}' is killed`,
|
|
903
|
-
);
|
|
865
|
+
log.debug(`Waiting up to ${timeout}ms until the emulator '${avdName ? avdName : this.curDeviceId}' is killed`);
|
|
904
866
|
try {
|
|
905
867
|
await waitForCondition(
|
|
906
868
|
async () => {
|
|
@@ -934,23 +896,10 @@ export async function killEmulator(
|
|
|
934
896
|
* @returns The SubProcess instance for the launched emulator
|
|
935
897
|
* @throws {Error} If emulator fails to launch or boot
|
|
936
898
|
*/
|
|
937
|
-
export async function launchAVD(
|
|
938
|
-
|
|
939
|
-
avdName: string,
|
|
940
|
-
opts: AvdLaunchOptions = {},
|
|
941
|
-
): Promise<SubProcess> {
|
|
942
|
-
const {
|
|
943
|
-
args = [],
|
|
944
|
-
env = {},
|
|
945
|
-
language,
|
|
946
|
-
country,
|
|
947
|
-
launchTimeout = 60000,
|
|
948
|
-
readyTimeout = 60000,
|
|
949
|
-
retryTimes = 1,
|
|
950
|
-
} = opts;
|
|
899
|
+
export async function launchAVD(this: ADB, avdName: string, opts: AvdLaunchOptions = {}): Promise<SubProcess> {
|
|
900
|
+
const {args = [], env = {}, language, country, launchTimeout = 60000, readyTimeout = 60000, retryTimes = 1} = opts;
|
|
951
901
|
log.debug(
|
|
952
|
-
`Launching Emulator with AVD ${avdName}, launchTimeout
|
|
953
|
-
`${launchTimeout}ms and readyTimeout ${readyTimeout}ms`,
|
|
902
|
+
`Launching Emulator with AVD ${avdName}, launchTimeout ${launchTimeout}ms and readyTimeout ${readyTimeout}ms`,
|
|
954
903
|
);
|
|
955
904
|
const emulatorBinaryPath = await this.getSdkBinaryPath('emulator');
|
|
956
905
|
let processedAvdName = avdName;
|
|
@@ -990,7 +939,11 @@ export async function launchAVD(
|
|
|
990
939
|
}
|
|
991
940
|
|
|
992
941
|
if (!util.isEmpty(args)) {
|
|
993
|
-
launchArgs.push(
|
|
942
|
+
launchArgs.push(
|
|
943
|
+
...(Array.isArray(args)
|
|
944
|
+
? args
|
|
945
|
+
: util.shellParse(`${args}`).filter((token): token is string => typeof token === 'string')),
|
|
946
|
+
);
|
|
994
947
|
}
|
|
995
948
|
|
|
996
949
|
log.debug(`Running '${emulatorBinaryPath}' with args: ${util.quote(launchArgs)}`);
|
|
@@ -1005,14 +958,9 @@ export async function launchAVD(
|
|
|
1005
958
|
proc.on(`line-${streamName}`, (line: string) => log.debug(`[AVD OUTPUT] ${line}`));
|
|
1006
959
|
}
|
|
1007
960
|
proc.on('die', (code: number | null, signal: string | null) => {
|
|
1008
|
-
log.warn(
|
|
1009
|
-
`Emulator avd ${processedAvdName} exited with code ${code}${signal ? `, signal ${signal}` : ''}`,
|
|
1010
|
-
);
|
|
961
|
+
log.warn(`Emulator avd ${processedAvdName} exited with code ${code}${signal ? `, signal ${signal}` : ''}`);
|
|
1011
962
|
});
|
|
1012
|
-
await retry(
|
|
1013
|
-
retryTimes,
|
|
1014
|
-
async () => await this.getRunningAVDWithRetry(processedAvdName, launchTimeout),
|
|
1015
|
-
);
|
|
963
|
+
await retry(retryTimes, async () => await this.getRunningAVDWithRetry(processedAvdName, launchTimeout));
|
|
1016
964
|
// At this point we have deviceId already assigned
|
|
1017
965
|
const timer = new timing.Timer().start();
|
|
1018
966
|
if (isDelayAdbFeatureEnabled) {
|
|
@@ -1020,10 +968,9 @@ export async function launchAVD(
|
|
|
1020
968
|
await this.adbExec(['wait-for-device'], {timeout: readyTimeout});
|
|
1021
969
|
} catch (e: unknown) {
|
|
1022
970
|
const error = e as ExecError;
|
|
1023
|
-
throw new Error(
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
);
|
|
971
|
+
throw new Error(`'${processedAvdName}' Emulator has failed to boot: ${error.stderr || error.message}`, {
|
|
972
|
+
cause: e,
|
|
973
|
+
});
|
|
1027
974
|
}
|
|
1028
975
|
}
|
|
1029
976
|
await this.waitForEmulatorReady(Math.trunc(readyTimeout - timer.getDuration().asMilliSeconds));
|
|
@@ -1104,10 +1051,7 @@ export async function waitForEmulatorReady(this: ADB, timeoutMs: number = 20000)
|
|
|
1104
1051
|
|
|
1105
1052
|
const servicesOutput = await this.shell(['service', 'list']);
|
|
1106
1053
|
services = servicesOutput;
|
|
1107
|
-
if (
|
|
1108
|
-
!servicesOutput ||
|
|
1109
|
-
!requiredServicesRe.every((pattern) => pattern.test(servicesOutput))
|
|
1110
|
-
) {
|
|
1054
|
+
if (!servicesOutput || !requiredServicesRe.every((pattern) => pattern.test(servicesOutput))) {
|
|
1111
1055
|
log.debug(`Running services: ${servicesOutput}`);
|
|
1112
1056
|
return false;
|
|
1113
1057
|
}
|
|
@@ -1194,10 +1138,7 @@ export async function waitForDevice(this: ADB, appDeviceReadyTimeout: number = 3
|
|
|
1194
1138
|
* @param retries - Number of retry attempts (default: 90)
|
|
1195
1139
|
* @throws {Error} If reboot fails or device is not ready after reboot
|
|
1196
1140
|
*/
|
|
1197
|
-
export async function reboot(
|
|
1198
|
-
this: ADB,
|
|
1199
|
-
retries: number = DEFAULT_ADB_REBOOT_RETRIES,
|
|
1200
|
-
): Promise<void> {
|
|
1141
|
+
export async function reboot(this: ADB, retries: number = DEFAULT_ADB_REBOOT_RETRIES): Promise<void> {
|
|
1201
1142
|
// Get root access so we can run the next shell commands which require root access
|
|
1202
1143
|
const {wasAlreadyRooted} = await this.root();
|
|
1203
1144
|
try {
|
|
@@ -1255,11 +1196,7 @@ export async function changeUserPrivileges(this: ADB, isElevated: boolean): Prom
|
|
|
1255
1196
|
const error = err as ExecError;
|
|
1256
1197
|
// Check the output of the stdErr to see if there's any clues that show that the device went offline
|
|
1257
1198
|
// and if it did go offline, restart ADB
|
|
1258
|
-
if (
|
|
1259
|
-
['closed', 'device offline', 'timeout expired'].some((x) =>
|
|
1260
|
-
(error.stderr || '').toLowerCase().includes(x),
|
|
1261
|
-
)
|
|
1262
|
-
) {
|
|
1199
|
+
if (['closed', 'device offline', 'timeout expired'].some((x) => (error.stderr || '').toLowerCase().includes(x))) {
|
|
1263
1200
|
log.warn(`Attempt to ${cmd} caused ADB to think the device went offline`);
|
|
1264
1201
|
try {
|
|
1265
1202
|
await this.reconnect();
|
|
@@ -1298,9 +1235,7 @@ export async function changeUserPrivileges(this: ADB, isElevated: boolean): Prom
|
|
|
1298
1235
|
} catch (err: unknown) {
|
|
1299
1236
|
const error = err as ExecError;
|
|
1300
1237
|
const {stderr = '', message} = error;
|
|
1301
|
-
log.warn(
|
|
1302
|
-
`Unable to ${cmd} adb daemon. Original error: '${message}'. Stderr: '${stderr}'. Continuing.`,
|
|
1303
|
-
);
|
|
1238
|
+
log.warn(`Unable to ${cmd} adb daemon. Original error: '${message}'. Stderr: '${stderr}'. Continuing.`);
|
|
1304
1239
|
return {isSuccessful: false, wasAlreadyRooted};
|
|
1305
1240
|
}
|
|
1306
1241
|
}
|
|
@@ -1356,11 +1291,9 @@ export async function installMitmCertificate(this: ADB, cert: Buffer | string):
|
|
|
1356
1291
|
log.debug(`Got certificate hash: ${certHash}`);
|
|
1357
1292
|
log.debug('Preparing certificate content');
|
|
1358
1293
|
const {stdout: stdoutBuff1} = await exec(openSsl, ['x509', '-in', srcCert], {isBuffer: true});
|
|
1359
|
-
const {stdout: stdoutBuff2} = await exec(
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
{isBuffer: true},
|
|
1363
|
-
);
|
|
1294
|
+
const {stdout: stdoutBuff2} = await exec(openSsl, ['x509', '-in', srcCert, '-text', '-fingerprint', '-noout'], {
|
|
1295
|
+
isBuffer: true,
|
|
1296
|
+
});
|
|
1364
1297
|
const dstCertContent = Buffer.concat([stdoutBuff1, stdoutBuff2]);
|
|
1365
1298
|
const dstCert = path.resolve(tmpRoot, `${certHash}.0`);
|
|
1366
1299
|
await fs.writeFile(dstCert, dstCertContent);
|
|
@@ -1392,10 +1325,7 @@ export async function installMitmCertificate(this: ADB, cert: Buffer | string):
|
|
|
1392
1325
|
* @returns True if certificate is installed, false otherwise
|
|
1393
1326
|
* @throws {Error} If certificate hash cannot be retrieved
|
|
1394
1327
|
*/
|
|
1395
|
-
export async function isMitmCertificateInstalled(
|
|
1396
|
-
this: ADB,
|
|
1397
|
-
cert: Buffer | string,
|
|
1398
|
-
): Promise<boolean> {
|
|
1328
|
+
export async function isMitmCertificateInstalled(this: ADB, cert: Buffer | string): Promise<boolean> {
|
|
1399
1329
|
const openSsl = await getOpenSslForOs();
|
|
1400
1330
|
|
|
1401
1331
|
const tmpRoot = await tempDir.openDir();
|
|
@@ -1431,11 +1361,7 @@ export async function isMitmCertificateInstalled(
|
|
|
1431
1361
|
* @param args - Array of arguments to process
|
|
1432
1362
|
* @throws {Error} If argument transformer returns invalid result or command execution fails
|
|
1433
1363
|
*/
|
|
1434
|
-
export async function shellChunks(
|
|
1435
|
-
this: ADB,
|
|
1436
|
-
argTransformer: (x: string) => string[],
|
|
1437
|
-
args: string[],
|
|
1438
|
-
): Promise<void> {
|
|
1364
|
+
export async function shellChunks(this: ADB, argTransformer: (x: string) => string[], args: string[]): Promise<void> {
|
|
1439
1365
|
const commands: string[][] = [];
|
|
1440
1366
|
let cmdChunk: string[] = [];
|
|
1441
1367
|
for (const arg of args) {
|
|
@@ -1506,9 +1432,7 @@ export function toAvdLocaleArgs(language: string | null, country: string | null)
|
|
|
1506
1432
|
* @param sdkRoot - The Android SDK root directory path
|
|
1507
1433
|
* @returns Array of build-tools directory paths (newest first)
|
|
1508
1434
|
*/
|
|
1509
|
-
export const getBuildToolsDirs = memoize(async function getBuildToolsDirs(
|
|
1510
|
-
sdkRoot: string,
|
|
1511
|
-
): Promise<string[]> {
|
|
1435
|
+
export const getBuildToolsDirs = memoize(async function getBuildToolsDirs(sdkRoot: string): Promise<string[]> {
|
|
1512
1436
|
let buildToolsDirs = await fs.glob('*/', {
|
|
1513
1437
|
cwd: path.resolve(sdkRoot, 'build-tools'),
|
|
1514
1438
|
absolute: true,
|
|
@@ -1531,9 +1455,7 @@ export const getBuildToolsDirs = memoize(async function getBuildToolsDirs(
|
|
|
1531
1455
|
);
|
|
1532
1456
|
buildToolsDirs = pairs.sort((a, b) => (a[0] < b[0] ? 1 : -1)).map((pair) => pair[1]);
|
|
1533
1457
|
}
|
|
1534
|
-
log.info(
|
|
1535
|
-
`Found ${buildToolsDirs.length} 'build-tools' folders under '${sdkRoot}' (newest first):`,
|
|
1536
|
-
);
|
|
1458
|
+
log.info(`Found ${buildToolsDirs.length} 'build-tools' folders under '${sdkRoot}' (newest first):`);
|
|
1537
1459
|
for (const dir of buildToolsDirs) {
|
|
1538
1460
|
log.info(` ${dir}`);
|
|
1539
1461
|
}
|
package/lib/tools/types.ts
CHANGED
|
@@ -732,14 +732,10 @@ export interface RootResult {
|
|
|
732
732
|
}
|
|
733
733
|
|
|
734
734
|
export type Sensors = (typeof emuConstants.SENSORS)[keyof typeof emuConstants.SENSORS];
|
|
735
|
-
export type NetworkSpeed =
|
|
736
|
-
|
|
737
|
-
export type
|
|
738
|
-
|
|
739
|
-
export type GsmCallActions =
|
|
740
|
-
(typeof emuConstants.GSM_CALL_ACTIONS)[keyof typeof emuConstants.GSM_CALL_ACTIONS];
|
|
741
|
-
export type PowerAcStates =
|
|
742
|
-
(typeof emuConstants.POWER_AC_STATES)[keyof typeof emuConstants.POWER_AC_STATES];
|
|
735
|
+
export type NetworkSpeed = (typeof emuConstants.NETWORK_SPEED)[keyof typeof emuConstants.NETWORK_SPEED];
|
|
736
|
+
export type GsmVoiceStates = (typeof emuConstants.GSM_VOICE_STATES)[keyof typeof emuConstants.GSM_VOICE_STATES];
|
|
737
|
+
export type GsmCallActions = (typeof emuConstants.GSM_CALL_ACTIONS)[keyof typeof emuConstants.GSM_CALL_ACTIONS];
|
|
738
|
+
export type PowerAcStates = (typeof emuConstants.POWER_AC_STATES)[keyof typeof emuConstants.POWER_AC_STATES];
|
|
743
739
|
|
|
744
740
|
export interface PlatformInfo {
|
|
745
741
|
/**
|
|
@@ -1,9 +1,4 @@
|
|
|
1
|
-
export {
|
|
2
|
-
APKS_EXTENSION,
|
|
3
|
-
APK_EXTENSION,
|
|
4
|
-
APK_INSTALL_TIMEOUT,
|
|
5
|
-
DEFAULT_ADB_EXEC_TIMEOUT,
|
|
6
|
-
} from './constants.js';
|
|
1
|
+
export {APKS_EXTENSION, APK_EXTENSION, APK_INSTALL_TIMEOUT, DEFAULT_ADB_EXEC_TIMEOUT} from './constants.js';
|
|
7
2
|
export {buildInstallArgs, type BuildInstallArgsOptions} from './install.js';
|
|
8
3
|
export {readPackageManifest} from './manifest.js';
|
|
9
4
|
export {getResourcePath, unzipFile} from './resource.js';
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import {util} from '@appium/support';
|
|
2
|
+
|
|
2
3
|
import {log} from '../../logger.js';
|
|
3
4
|
|
|
4
5
|
export interface BuildInstallArgsOptions {
|
|
@@ -16,10 +17,7 @@ export interface BuildInstallArgsOptions {
|
|
|
16
17
|
* @param options - Install options mapped to adb flags
|
|
17
18
|
* @returns A list of install flags
|
|
18
19
|
*/
|
|
19
|
-
export function buildInstallArgs(
|
|
20
|
-
apiLevel: number,
|
|
21
|
-
options: BuildInstallArgsOptions = {},
|
|
22
|
-
): string[] {
|
|
20
|
+
export function buildInstallArgs(apiLevel: number, options: BuildInstallArgsOptions = {}): string[] {
|
|
23
21
|
const result: string[] = [];
|
|
24
22
|
|
|
25
23
|
if (!util.hasValue(options.replace) || options.replace) {
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import {util} from '@appium/support';
|
|
2
2
|
import {exec, type ExecError} from 'teen_process';
|
|
3
|
-
|
|
3
|
+
|
|
4
4
|
import type {ADB} from '../../adb.js';
|
|
5
|
+
import {log} from '../../logger.js';
|
|
5
6
|
import type {ApkManifest} from '../../tools/types.js';
|
|
6
7
|
|
|
7
8
|
/**
|
|
@@ -34,22 +35,14 @@ export async function readPackageManifest(this: ADB, apkPath: string): Promise<A
|
|
|
34
35
|
throw new Error(`${prefix}. ${suffix}`, {cause: e});
|
|
35
36
|
}
|
|
36
37
|
|
|
37
|
-
const extractValue = (
|
|
38
|
-
line: string,
|
|
39
|
-
propPattern: RegExp,
|
|
40
|
-
valueTransformer: ((x: string) => any) | null,
|
|
41
|
-
): any => {
|
|
38
|
+
const extractValue = (line: string, propPattern: RegExp, valueTransformer: ((x: string) => any) | null): any => {
|
|
42
39
|
const match = propPattern.exec(line);
|
|
43
40
|
if (match) {
|
|
44
41
|
return valueTransformer ? valueTransformer(match[1]) : match[1];
|
|
45
42
|
}
|
|
46
43
|
return undefined;
|
|
47
44
|
};
|
|
48
|
-
const extractArray = (
|
|
49
|
-
line: string,
|
|
50
|
-
propPattern: RegExp,
|
|
51
|
-
valueTransformer: ((x: string) => any) | null,
|
|
52
|
-
): any[] => {
|
|
45
|
+
const extractArray = (line: string, propPattern: RegExp, valueTransformer: ((x: string) => any) | null): any[] => {
|
|
53
46
|
let match: RegExpExecArray | null;
|
|
54
47
|
const resultArray: any[] = [];
|
|
55
48
|
while ((match = propPattern.exec(line))) {
|
|
@@ -1,18 +1,17 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
2
|
import {fileURLToPath} from 'node:url';
|
|
3
|
+
|
|
3
4
|
import {fs, zip, util} from '@appium/support';
|
|
5
|
+
|
|
4
6
|
import {log} from '../../logger.js';
|
|
5
7
|
import {MODULE_NAME} from './constants.js';
|
|
6
8
|
|
|
7
|
-
export const getResourcePath = util.memoize(async function getResourcePath(
|
|
8
|
-
relPath: string,
|
|
9
|
-
): Promise<string> {
|
|
9
|
+
export const getResourcePath = util.memoize(async function getResourcePath(relPath: string): Promise<string> {
|
|
10
10
|
const moduleRoot = await getModuleRoot();
|
|
11
11
|
const resultPath = path.resolve(moduleRoot, relPath);
|
|
12
12
|
if (!(await fs.exists(resultPath))) {
|
|
13
13
|
throw new Error(
|
|
14
|
-
`Cannot find the resource '${relPath}' under the '${moduleRoot}'
|
|
15
|
-
`folder of ${MODULE_NAME} Node.js module`,
|
|
14
|
+
`Cannot find the resource '${relPath}' under the '${moduleRoot}' folder of ${MODULE_NAME} Node.js module`,
|
|
16
15
|
);
|
|
17
16
|
}
|
|
18
17
|
return resultPath;
|
|
@@ -24,10 +23,7 @@ export const getResourcePath = util.memoize(async function getResourcePath(
|
|
|
24
23
|
* @param zipPath - Source zip file path
|
|
25
24
|
* @param dstRoot - Destination directory. Defaults to zip parent directory
|
|
26
25
|
*/
|
|
27
|
-
export async function unzipFile(
|
|
28
|
-
zipPath: string,
|
|
29
|
-
dstRoot: string = path.dirname(zipPath),
|
|
30
|
-
): Promise<void> {
|
|
26
|
+
export async function unzipFile(zipPath: string, dstRoot: string = path.dirname(zipPath)): Promise<void> {
|
|
31
27
|
log.debug(`Unzipping '${zipPath}' to '${dstRoot}'`);
|
|
32
28
|
await zip.assertValidZip(zipPath);
|
|
33
29
|
await zip.extractAllTo(zipPath, dstRoot);
|