@react-native-harness/platform-android 1.4.0-rc.1 → 1.4.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/dist/adb.d.ts +3 -1
- package/dist/adb.d.ts.map +1 -1
- package/dist/adb.js +30 -21
- package/dist/app-session.d.ts +11 -2
- package/dist/app-session.d.ts.map +1 -1
- package/dist/app-session.js +17 -12
- package/dist/avd-config.d.ts +1 -0
- package/dist/avd-config.d.ts.map +1 -1
- package/dist/avd-config.js +11 -0
- package/dist/emulator-startup.d.ts +23 -0
- package/dist/emulator-startup.d.ts.map +1 -1
- package/dist/emulator-startup.js +58 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/instance.d.ts.map +1 -1
- package/dist/instance.js +21 -15
- package/dist/runner.d.ts +2 -2
- package/dist/runner.d.ts.map +1 -1
- package/package.json +4 -4
- package/src/adb.ts +72 -65
- package/src/app-session.ts +28 -12
- package/src/avd-config.ts +17 -0
- package/src/emulator-startup.ts +74 -0
- package/src/index.ts +1 -0
- package/src/instance.ts +30 -16
- package/src/runner.ts +5 -9
- package/dist/__tests__/adb-id.test.d.ts +0 -2
- package/dist/__tests__/adb-id.test.d.ts.map +0 -1
- package/dist/__tests__/adb-id.test.js +0 -41
- package/dist/__tests__/adb.test.d.ts +0 -2
- package/dist/__tests__/adb.test.d.ts.map +0 -1
- package/dist/__tests__/adb.test.js +0 -552
- package/dist/__tests__/app-monitor.test.d.ts +0 -2
- package/dist/__tests__/app-monitor.test.d.ts.map +0 -1
- package/dist/__tests__/app-monitor.test.js +0 -257
- package/dist/__tests__/avd-config.test.d.ts +0 -2
- package/dist/__tests__/avd-config.test.d.ts.map +0 -1
- package/dist/__tests__/avd-config.test.js +0 -174
- package/dist/__tests__/ci-action.test.d.ts +0 -2
- package/dist/__tests__/ci-action.test.d.ts.map +0 -1
- package/dist/__tests__/ci-action.test.js +0 -46
- package/dist/__tests__/crash-diagnostics.test.d.ts +0 -2
- package/dist/__tests__/crash-diagnostics.test.d.ts.map +0 -1
- package/dist/__tests__/crash-diagnostics.test.js +0 -119
- package/dist/__tests__/crash-parser.test.d.ts +0 -2
- package/dist/__tests__/crash-parser.test.d.ts.map +0 -1
- package/dist/__tests__/crash-parser.test.js +0 -45
- package/dist/__tests__/crash-reporter.test.d.ts +0 -2
- package/dist/__tests__/crash-reporter.test.d.ts.map +0 -1
- package/dist/__tests__/crash-reporter.test.js +0 -150
- package/dist/__tests__/emulator-startup.test.d.ts +0 -2
- package/dist/__tests__/emulator-startup.test.d.ts.map +0 -1
- package/dist/__tests__/emulator-startup.test.js +0 -20
- package/dist/__tests__/environment.test.d.ts +0 -2
- package/dist/__tests__/environment.test.d.ts.map +0 -1
- package/dist/__tests__/environment.test.js +0 -117
- package/dist/__tests__/instance.test.d.ts +0 -2
- package/dist/__tests__/instance.test.d.ts.map +0 -1
- package/dist/__tests__/instance.test.js +0 -593
- package/dist/__tests__/shared-prefs.test.d.ts +0 -2
- package/dist/__tests__/shared-prefs.test.d.ts.map +0 -1
- package/dist/__tests__/shared-prefs.test.js +0 -87
- package/dist/__tests__/targets.test.d.ts +0 -2
- package/dist/__tests__/targets.test.d.ts.map +0 -1
- package/dist/__tests__/targets.test.js +0 -49
- package/dist/tsconfig.lib.tsbuildinfo +0 -1
- package/src/__tests__/adb-id.test.ts +0 -51
- package/src/__tests__/avd-config.test.ts +0 -206
- package/src/__tests__/ci-action.test.ts +0 -81
- package/src/__tests__/crash-diagnostics.test.ts +0 -144
- package/src/__tests__/crash-parser.test.ts +0 -52
- package/src/__tests__/crash-reporter.test.ts +0 -167
- package/src/__tests__/emulator-startup.test.ts +0 -35
- package/src/__tests__/instance.test.ts +0 -845
- package/src/__tests__/shared-prefs.test.ts +0 -144
- package/src/__tests__/targets.test.ts +0 -53
- package/tsconfig.tsbuildinfo +0 -1
package/dist/adb.d.ts
CHANGED
|
@@ -44,7 +44,9 @@ export declare const getAppPid: (adbId: string, bundleId: string) => Promise<num
|
|
|
44
44
|
export declare const getAppUid: (adbId: string, bundleId: string) => Promise<number>;
|
|
45
45
|
export declare const setHideErrorDialogs: (adbId: string, hide: boolean) => Promise<void>;
|
|
46
46
|
export declare const getLogcatTimestamp: (adbId: string) => Promise<string>;
|
|
47
|
-
export declare const startLogcat: (adbId: string, args: readonly string[]
|
|
47
|
+
export declare const startLogcat: (adbId: string, args: readonly string[], options?: {
|
|
48
|
+
signal?: AbortSignal;
|
|
49
|
+
}) => Subprocess;
|
|
48
50
|
export declare const DROPBOX_CRASH_TAGS: readonly ["data_app_crash", "data_app_native_crash"];
|
|
49
51
|
export declare const getDropboxPrint: (adbId: string, tags?: readonly string[]) => Promise<string>;
|
|
50
52
|
export declare const getActivityExitInfo: (adbId: string, bundleId: string) => Promise<string>;
|
package/dist/adb.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"adb.d.ts","sourceRoot":"","sources":["../src/adb.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,uBAAuB,EAAE,MAAM,iCAAiC,CAAC;AAC/E,OAAO,
|
|
1
|
+
{"version":3,"file":"adb.d.ts","sourceRoot":"","sources":["../src/adb.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,uBAAuB,EAAE,MAAM,iCAAiC,CAAC;AAC/E,OAAO,EAML,KAAK,UAAU,EAChB,MAAM,6BAA6B,CAAC;AAErC,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAE9D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAgB5C,OAAO,EAGL,KAAK,gBAAgB,EACtB,MAAM,uBAAuB,CAAC;AAgC/B,eAAO,MAAM,eAAe;iCAElB,MAAM,QACN,SAAS,MAAM,EAAE,KACtB,mBAAmB,CAAC,IAAI,EAAE,QAAQ,EAAE,QAAQ,CAAC;CAKjD,CAAC;AAqEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,eAAO,MAAM,2BAA2B,GAAI,UAAU,MAAM,KAAG,MAAM,EAMpE,CAAC;AAEF,eAAO,MAAM,wBAAwB,GACnC,UAAU,MAAM,KACf,OAAO,CAAC,IAAI,CAEd,CAAC;AAgEF,eAAO,MAAM,eAAe,GAC1B,UAAU,MAAM,EAChB,cAAc,MAAM,EACpB,UAAU,uBAAuB,KAChC,MAAM,EAoCR,CAAC;AAEF,eAAO,MAAM,cAAc,GACzB,OAAO,MAAM,EACb,UAAU,MAAM,KACf,OAAO,CAAC,OAAO,CAWjB,CAAC;AAEF,eAAO,MAAM,WAAW,GACtB,OAAO,MAAM,EACb,MAAM,MAAM,EACZ,WAAU,MAAa,KACtB,OAAO,CAAC,IAAI,CAQd,CAAC;AAEF,eAAO,MAAM,OAAO,GAClB,OAAO,MAAM,EACb,UAAU,MAAM,KACf,OAAO,CAAC,IAAI,CASd,CAAC;AAEF,eAAO,MAAM,QAAQ,GACnB,OAAO,MAAM,EACb,UAAU,MAAM,EAChB,cAAc,MAAM,EACpB,UAAU,uBAAuB,KAChC,OAAO,CAAC,IAAI,CAMd,CAAC;AAEF,eAAO,MAAM,YAAY,QAAa,OAAO,CAAC,MAAM,EAAE,CAOrD,CAAC;AAEF,eAAO,MAAM,eAAe,GAC1B,OAAO,MAAM,KACZ,OAAO,CAAC,MAAM,GAAG,IAAI,CASvB,CAAC;AAEF,eAAO,MAAM,gBAAgB,GAC3B,OAAO,MAAM,EACb,UAAU,MAAM,KACf,OAAO,CAAC,MAAM,GAAG,IAAI,CASvB,CAAC;AAMF,MAAM,MAAM,UAAU,GAAG;IACvB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB,CAAC;AAEF,eAAO,MAAM,aAAa,GACxB,OAAO,MAAM,KACZ,OAAO,CAAC,UAAU,GAAG,IAAI,CAI3B,CAAC;AA2EF,eAAO,MAAM,eAAe,GAAU,OAAO,MAAM,KAAG,OAAO,CAAC,OAAO,CAWpE,CAAC;AAEF,eAAO,MAAM,YAAY,GAAU,OAAO,MAAM,KAAG,OAAO,CAAC,IAAI,CAE9D,CAAC;AAEF,eAAO,MAAM,UAAU,GACrB,OAAO,MAAM,EACb,SAAS,MAAM,KACd,OAAO,CAAC,IAAI,CAEd,CAAC;AAEF,eAAO,MAAM,YAAY,GACvB,OAAO,MAAM,EACb,UAAU,MAAM,KACf,OAAO,CAAC,IAAI,CAEd,CAAC;AAEF,eAAO,MAAM,MAAM,GAAU,MAAM,MAAM,KAAG,OAAO,CAAC,OAAO,CAG1D,CAAC;AAEF,eAAO,MAAM,SAAS,GAAU,kDAM7B,gBAAgB,KAAG,OAAO,CAAC,IAAI,CAyBjC,CAAC;AAEF,eAAO,MAAM,SAAS,GAAU,MAAM,MAAM,KAAG,OAAO,CAAC,IAAI,CAkB1D,CAAC;AAEF,eAAO,MAAM,aAAa,GACxB,MAAM,MAAM,EACZ,OAAM,gBAAiC,KACtC,OAAO,CAAC,IAAI,CAsFd,CAAC;AAEF,eAAO,MAAM,eAAe,GAC1B,MAAM,MAAM,EACZ,QAAQ,WAAW,KAClB,OAAO,CAAC,MAAM,CAoBhB,CAAC;AAEF,eAAO,MAAM,yBAAyB,GACpC,OAAO,MAAM,EACb,QAAQ,WAAW,KAClB,OAAO,CAAC,IAAI,CAYd,CAAC;AAEF,eAAO,MAAM,WAAW,GACtB,MAAM,MAAM,EACZ,QAAQ,WAAW,KAClB,OAAO,CAAC,MAAM,CAwBhB,CAAC;AAEF,eAAO,MAAM,YAAY,GACvB,OAAO,MAAM,EACb,UAAU,MAAM,KACf,OAAO,CAAC,OAAO,CAEjB,CAAC;AAEF,eAAO,MAAM,SAAS,GACpB,OAAO,MAAM,EACb,UAAU,MAAM,KACf,OAAO,CAAC,MAAM,GAAG,IAAI,CAsBvB,CAAC;AAEF,eAAO,MAAM,SAAS,GACpB,OAAO,MAAM,EACb,UAAU,MAAM,KACf,OAAO,CAAC,MAAM,CAoBhB,CAAC;AAEF,eAAO,MAAM,mBAAmB,GAC9B,OAAO,MAAM,EACb,MAAM,OAAO,KACZ,OAAO,CAAC,IAAI,CAWd,CAAC;AAEF,eAAO,MAAM,kBAAkB,GAAU,OAAO,MAAM,KAAG,OAAO,CAAC,MAAM,CAUtE,CAAC;AAEF,eAAO,MAAM,WAAW,GACtB,OAAO,MAAM,EACb,MAAM,SAAS,MAAM,EAAE,EACvB,UAAU;IAAE,MAAM,CAAC,EAAE,WAAW,CAAA;CAAE,KACjC,UAKC,CAAC;AAEL,eAAO,MAAM,kBAAkB,sDAGrB,CAAC;AAEX,eAAO,MAAM,eAAe,GAC1B,OAAO,MAAM,EACb,OAAM,SAAS,MAAM,EAAuB,KAC3C,OAAO,CAAC,MAAM,CAoBhB,CAAC;AAEF,eAAO,MAAM,mBAAmB,GAC9B,OAAO,MAAM,EACb,UAAU,MAAM,KACf,OAAO,CAAC,MAAM,CAYhB,CAAC;AAEF,eAAO,MAAM,OAAO,QAAa,OAAO,CAAC,MAAM,EAAE,CAWhD,CAAC;AAEF,MAAM,MAAM,SAAS,GAAG;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF,eAAO,MAAM,mBAAmB,QAAa,OAAO,CAAC,SAAS,EAAE,CA8B/D,CAAC;AAEF,eAAO,MAAM,gBAAgB,GAC3B,OAAO,MAAM,EACb,UAAU,MAAM,KACf,OAAO,CAAC,IAAI,CAqEd,CAAC"}
|
package/dist/adb.js
CHANGED
|
@@ -1,30 +1,27 @@
|
|
|
1
|
-
import { logger, spawn, SubprocessError, } from '@react-native-harness/tools';
|
|
1
|
+
import { delay, logger, spawn, SubprocessError, waitForAbort, } from '@react-native-harness/tools';
|
|
2
2
|
import { spawn as nodeSpawn } from 'node:child_process';
|
|
3
3
|
import { access, rm } from 'node:fs/promises';
|
|
4
4
|
import { getAvdConfigPath, getAvdDirectory, readAvdConfig, } from './avd-config.js';
|
|
5
5
|
import { ensureAndroidEmulatorAvailable, ensureAndroidSdkPackages, getAdbBinaryPath, getAndroidSystemImagePackage, getAvdManagerBinaryPath, getEmulatorBinaryPath, getHostAndroidSystemImageArch, getRequiredAndroidSdkPackages, } from './environment.js';
|
|
6
|
-
import { getEmulatorStartupArgs, } from './emulator-startup.js';
|
|
6
|
+
import { getEmulatorCpuCores, getEmulatorStartupArgs, } from './emulator-startup.js';
|
|
7
7
|
import { AdbAppNotInstalledError, AdbPermissionGrantError, } from './adb-errors.js';
|
|
8
|
-
const wait = async (ms) => {
|
|
9
|
-
await new Promise((resolve) => {
|
|
10
|
-
setTimeout(resolve, ms);
|
|
11
|
-
});
|
|
12
|
-
};
|
|
13
|
-
const waitForAbort = (signal) => {
|
|
14
|
-
if (signal.aborted) {
|
|
15
|
-
return Promise.reject(signal.reason);
|
|
16
|
-
}
|
|
17
|
-
return new Promise((_, reject) => {
|
|
18
|
-
signal.addEventListener('abort', () => {
|
|
19
|
-
reject(signal.reason);
|
|
20
|
-
}, { once: true });
|
|
21
|
-
});
|
|
22
|
-
};
|
|
23
8
|
const waitWithSignal = async (ms, signal) => {
|
|
24
9
|
if (signal.aborted) {
|
|
25
10
|
throw signal.reason;
|
|
26
11
|
}
|
|
27
|
-
|
|
12
|
+
// Both sides of this race must be torn down explicitly when they lose:
|
|
13
|
+
// an uncancelled timer keeps a ref'd Timeout alive, and an uncancelled
|
|
14
|
+
// abort wait leaks a listener on `signal`, which is a session-lifetime
|
|
15
|
+
// signal here and gets polled against once per second.
|
|
16
|
+
const timer = delay(ms);
|
|
17
|
+
const abort = waitForAbort(signal);
|
|
18
|
+
try {
|
|
19
|
+
await Promise.race([timer.promise, abort.promise]);
|
|
20
|
+
}
|
|
21
|
+
finally {
|
|
22
|
+
timer.cancel();
|
|
23
|
+
abort.cancel();
|
|
24
|
+
}
|
|
28
25
|
};
|
|
29
26
|
const EMULATOR_STARTUP_OBSERVATION_TIMEOUT_MS = 5000;
|
|
30
27
|
const EMULATOR_OUTPUT_BUFFER_LIMIT = 16 * 1024;
|
|
@@ -311,9 +308,14 @@ export const createAvd = async ({ name, apiLevel, profile, diskSize, heapSize, }
|
|
|
311
308
|
]);
|
|
312
309
|
await ensureAvdIniExists({ name, apiLevel });
|
|
313
310
|
const configPath = await ensureAvdConfigExists(name);
|
|
311
|
+
// hw.cpu.ncore is baked into config.ini (rather than passed as a `-cores`
|
|
312
|
+
// boot flag) so it's part of the AVD's persisted hardware profile: boot
|
|
313
|
+
// snapshots require an identical hardware config to load, so the vCPU
|
|
314
|
+
// count must be fixed at AVD-creation time and stay consistent across
|
|
315
|
+
// boots.
|
|
314
316
|
await spawn('bash', [
|
|
315
317
|
'-lc',
|
|
316
|
-
`printf '%s\n%s\n' 'disk.dataPartition.size=${diskSize}' 'vm.heapSize=${heapSize}' >> "${configPath}"`,
|
|
318
|
+
`printf '%s\n%s\n%s\n' 'disk.dataPartition.size=${diskSize}' 'vm.heapSize=${heapSize}' 'hw.cpu.ncore=${getEmulatorCpuCores()}' >> "${configPath}"`,
|
|
317
319
|
]);
|
|
318
320
|
};
|
|
319
321
|
export const deleteAvd = async (name) => {
|
|
@@ -375,11 +377,17 @@ export const startEmulator = async (name, mode = 'default-boot') => {
|
|
|
375
377
|
}
|
|
376
378
|
throw error;
|
|
377
379
|
});
|
|
378
|
-
const
|
|
380
|
+
const observationTimer = delay(EMULATOR_STARTUP_OBSERVATION_TIMEOUT_MS);
|
|
381
|
+
const observationTimeout = observationTimer.promise.then(() => 'timeout');
|
|
379
382
|
try {
|
|
380
383
|
await Promise.race([earlyExit, observedBoot, observationTimeout]);
|
|
381
384
|
}
|
|
382
385
|
finally {
|
|
386
|
+
// If `earlyExit` or `observedBoot` won the race, this timer would
|
|
387
|
+
// otherwise sit ref'd in the event loop for the rest of its 5s;
|
|
388
|
+
// cancelling here is a no-op on the happy "proceed detached" path
|
|
389
|
+
// where the timer itself won.
|
|
390
|
+
observationTimer.cancel();
|
|
383
391
|
cleanup();
|
|
384
392
|
}
|
|
385
393
|
childProcess.stdout?.destroy();
|
|
@@ -497,9 +505,10 @@ export const getLogcatTimestamp = async (adbId) => {
|
|
|
497
505
|
]);
|
|
498
506
|
return stdout.trim().replace(/^'+|'+$/g, '');
|
|
499
507
|
};
|
|
500
|
-
export const startLogcat = (adbId, args) => spawn(getAdbBinaryPath(), ['-s', adbId, ...args], {
|
|
508
|
+
export const startLogcat = (adbId, args, options) => spawn(getAdbBinaryPath(), ['-s', adbId, ...args], {
|
|
501
509
|
stdout: 'pipe',
|
|
502
510
|
stderr: 'pipe',
|
|
511
|
+
signal: options?.signal,
|
|
503
512
|
});
|
|
504
513
|
export const DROPBOX_CRASH_TAGS = [
|
|
505
514
|
'data_app_crash',
|
package/dist/app-session.d.ts
CHANGED
|
@@ -7,11 +7,20 @@ type CreateAndroidAppSessionOptions = {
|
|
|
7
7
|
stopApp: () => Promise<void>;
|
|
8
8
|
getAppPid: () => Promise<number | null>;
|
|
9
9
|
getLogcatTimestamp: () => Promise<string>;
|
|
10
|
-
startLogcat: (args: readonly string[]
|
|
10
|
+
startLogcat: (args: readonly string[], options: {
|
|
11
|
+
signal: AbortSignal;
|
|
12
|
+
}) => Subprocess;
|
|
11
13
|
getDropboxOutput?: () => Promise<string>;
|
|
12
14
|
getExitInfo?: () => Promise<string>;
|
|
13
15
|
crashArtifactWriter?: CrashArtifactWriter;
|
|
16
|
+
/**
|
|
17
|
+
* Session-lifetime abort signal (see HarnessPlatformInitOptions.signal).
|
|
18
|
+
* Combined with the app session's own logcatAbortController so that
|
|
19
|
+
* aborting the session stops the logcat stream even if dispose() hasn't
|
|
20
|
+
* been called yet (e.g. SIGTERM during teardown of other resources).
|
|
21
|
+
*/
|
|
22
|
+
signal?: AbortSignal;
|
|
14
23
|
};
|
|
15
|
-
export declare const createAndroidAppSession: ({ appUid, bundleId, startApp, stopApp, getAppPid, getLogcatTimestamp, startLogcat, getDropboxOutput, getExitInfo, crashArtifactWriter, }: CreateAndroidAppSessionOptions) => Promise<AppSession>;
|
|
24
|
+
export declare const createAndroidAppSession: ({ appUid, bundleId, startApp, stopApp, getAppPid, getLogcatTimestamp, startLogcat, getDropboxOutput, getExitInfo, crashArtifactWriter, signal, }: CreateAndroidAppSessionOptions) => Promise<AppSession>;
|
|
16
25
|
export {};
|
|
17
26
|
//# sourceMappingURL=app-session.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app-session.d.ts","sourceRoot":"","sources":["../src/app-session.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,UAAU,EAEf,KAAK,mBAAmB,EACzB,MAAM,iCAAiC,CAAC;AACzC,OAAO,EAGL,KAAK,UAAU,EAChB,MAAM,6BAA6B,CAAC;
|
|
1
|
+
{"version":3,"file":"app-session.d.ts","sourceRoot":"","sources":["../src/app-session.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,UAAU,EAEf,KAAK,mBAAmB,EACzB,MAAM,iCAAiC,CAAC;AACzC,OAAO,EAGL,KAAK,UAAU,EAChB,MAAM,6BAA6B,CAAC;AA0DrC,KAAK,8BAA8B,GAAG;IACpC,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9B,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7B,SAAS,EAAE,MAAM,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IACxC,kBAAkB,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;IAC1C,WAAW,EAAE,CACX,IAAI,EAAE,SAAS,MAAM,EAAE,EACvB,OAAO,EAAE;QAAE,MAAM,EAAE,WAAW,CAAA;KAAE,KAC7B,UAAU,CAAC;IAChB,gBAAgB,CAAC,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;IACzC,WAAW,CAAC,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;IACpC,mBAAmB,CAAC,EAAE,mBAAmB,CAAC;IAC1C;;;;;OAKG;IACH,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB,CAAC;AAEF,eAAO,MAAM,uBAAuB,GAAU,kJAY3C,8BAA8B,KAAG,OAAO,CAAC,UAAU,CAmNrD,CAAC"}
|
package/dist/app-session.js
CHANGED
|
@@ -30,16 +30,8 @@ const isCrashSignal = (line, bundleId) => {
|
|
|
30
30
|
(line.includes(bundleId) &&
|
|
31
31
|
/fatal|crash|signal 11|signal 6|backtrace/i.test(line)));
|
|
32
32
|
};
|
|
33
|
-
const stopSubprocess = async (child) => {
|
|
34
|
-
try {
|
|
35
|
-
(await child.nodeChildProcess).kill();
|
|
36
|
-
}
|
|
37
|
-
catch {
|
|
38
|
-
// Ignore termination failures for already-ended background processes.
|
|
39
|
-
}
|
|
40
|
-
};
|
|
41
33
|
const isExitedState = (state) => state.status === 'exited';
|
|
42
|
-
export const createAndroidAppSession = async ({ appUid, bundleId, startApp, stopApp, getAppPid, getLogcatTimestamp, startLogcat, getDropboxOutput, getExitInfo, crashArtifactWriter, }) => {
|
|
34
|
+
export const createAndroidAppSession = async ({ appUid, bundleId, startApp, stopApp, getAppPid, getLogcatTimestamp, startLogcat, getDropboxOutput, getExitInfo, crashArtifactWriter, signal, }) => {
|
|
43
35
|
const emitter = createAppSessionEmitter();
|
|
44
36
|
const logBuffer = createBoundedLogBuffer();
|
|
45
37
|
let state = { status: 'running' };
|
|
@@ -113,7 +105,20 @@ export const createAndroidAppSession = async ({ appUid, bundleId, startApp, stop
|
|
|
113
105
|
};
|
|
114
106
|
const logcatTimestamp = await getLogcatTimestamp();
|
|
115
107
|
const sessionStartedAt = Date.now();
|
|
116
|
-
const
|
|
108
|
+
const logcatAbortController = new AbortController();
|
|
109
|
+
const logcatSignal = signal
|
|
110
|
+
? AbortSignal.any([signal, logcatAbortController.signal])
|
|
111
|
+
: logcatAbortController.signal;
|
|
112
|
+
const logcatProcess = startLogcat(getLogcatArgs(appUid, logcatTimestamp), {
|
|
113
|
+
signal: logcatSignal,
|
|
114
|
+
});
|
|
115
|
+
// Aborting is nano-spawn's own cancellation path, so the resulting
|
|
116
|
+
// SubprocessError is settled the same way regardless of which of the
|
|
117
|
+
// merged stdout/stderr iterators observes it first. Without this, killing
|
|
118
|
+
// the underlying process directly can make both iterators reject at once,
|
|
119
|
+
// and nano-spawn's internal `Promise.race` only reports one of them,
|
|
120
|
+
// leaving the other an unhandled rejection.
|
|
121
|
+
logcatProcess.catch(() => undefined);
|
|
117
122
|
const crashReporter = createAndroidCrashReporter({
|
|
118
123
|
bundleId,
|
|
119
124
|
crashArtifactWriter,
|
|
@@ -156,7 +161,7 @@ export const createAndroidAppSession = async ({ appUid, bundleId, startApp, stop
|
|
|
156
161
|
disposed = true;
|
|
157
162
|
stopPolling = true;
|
|
158
163
|
emitter.clear();
|
|
159
|
-
|
|
164
|
+
logcatAbortController.abort();
|
|
160
165
|
await Promise.allSettled([logTask]);
|
|
161
166
|
throw error;
|
|
162
167
|
}
|
|
@@ -196,7 +201,7 @@ export const createAndroidAppSession = async ({ appUid, bundleId, startApp, stop
|
|
|
196
201
|
}
|
|
197
202
|
cancelPendingPollDelay();
|
|
198
203
|
emitter.clear();
|
|
199
|
-
|
|
204
|
+
logcatAbortController.abort();
|
|
200
205
|
await stopApp();
|
|
201
206
|
await Promise.allSettled([logTask, pollTask]);
|
|
202
207
|
},
|
package/dist/avd-config.d.ts
CHANGED
package/dist/avd-config.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"avd-config.d.ts","sourceRoot":"","sources":["../src/avd-config.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,kBAAkB,CAAC;AAC/D,OAAO,KAAK,EAAE,eAAe,EAAE,wBAAwB,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"avd-config.d.ts","sourceRoot":"","sources":["../src/avd-config.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,kBAAkB,CAAC;AAC/D,OAAO,KAAK,EAAE,eAAe,EAAE,wBAAwB,EAAE,MAAM,aAAa,CAAC;AAG7E,MAAM,MAAM,SAAS,GAAG;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,sBAAsB,GAC9B;IAAE,UAAU,EAAE,IAAI,CAAA;CAAE,GACpB;IAAE,UAAU,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAE1C,eAAO,MAAM,eAAe,GAAI,MAAM,MAAM,KAAG,MAI9C,CAAC;AAEF,eAAO,MAAM,gBAAgB,GAAI,MAAM,MAAM,KAAG,MAE/C,CAAC;AAkEF,eAAO,MAAM,cAAc,GAAI,UAAU,MAAM,KAAG,SA4CjD,CAAC;AAEF,eAAO,MAAM,aAAa,GACxB,MAAM,MAAM,KACX,OAAO,CAAC,SAAS,GAAG,IAAI,CAU1B,CAAC;AAEF,eAAO,MAAM,eAAe,GAAI,oCAI7B;IACD,QAAQ,EAAE,eAAe,CAAC;IAC1B,SAAS,EAAE,SAAS,CAAC;IACrB,QAAQ,EAAE,sBAAsB,CAAC;CAClC,KAAG,sBA+FH,CAAC;AAEF,eAAO,MAAM,2BAA2B,GAAI,yBAGzC;IACD,QAAQ,EAAE,eAAe,CAAC;IAC1B,QAAQ,EAAE,sBAAsB,CAAC;CAClC,KAAG;IACF,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,sBAAsB,CAAC;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CAClB,GAAG,IAeH,CAAC;AAEF,eAAO,MAAM,wBAAwB,GAAI,8BAItC;IACD,GAAG,CAAC,EAAE,wBAAwB,CAAC;IAC/B,aAAa,EAAE,OAAO,CAAC;IACvB,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;CACzB,KAAG,OAWH,CAAC"}
|
package/dist/avd-config.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { access, readFile } from 'node:fs/promises';
|
|
2
|
+
import { getEmulatorCpuCores } from './emulator-startup.js';
|
|
2
3
|
export const getAvdDirectory = (name) => {
|
|
3
4
|
return `${process.env.ANDROID_AVD_HOME ?? `${process.env.HOME}/.android/avd`}/${name}.avd`;
|
|
4
5
|
};
|
|
@@ -81,6 +82,9 @@ export const parseAvdConfig = (contents) => {
|
|
|
81
82
|
case 'vm.heapSize':
|
|
82
83
|
config.vmHeapSize = value;
|
|
83
84
|
break;
|
|
85
|
+
case 'hw.cpu.ncore':
|
|
86
|
+
config.hwCpuNcore = value;
|
|
87
|
+
break;
|
|
84
88
|
default:
|
|
85
89
|
break;
|
|
86
90
|
}
|
|
@@ -146,6 +150,13 @@ export const isAvdCompatible = ({ emulator, avdConfig, hostArch, }) => {
|
|
|
146
150
|
reason: `Heap size mismatch: expected ${requestedAvdConfig.heapSize}, got ${avdConfig.vmHeapSize ?? 'missing'}.`,
|
|
147
151
|
};
|
|
148
152
|
}
|
|
153
|
+
if (normalizeConfigValue(avdConfig.hwCpuNcore ?? '') !==
|
|
154
|
+
normalizeConfigValue(String(getEmulatorCpuCores()))) {
|
|
155
|
+
return {
|
|
156
|
+
compatible: false,
|
|
157
|
+
reason: `CPU core count mismatch: expected ${getEmulatorCpuCores()}, got ${avdConfig.hwCpuNcore ?? 'missing'}.`,
|
|
158
|
+
};
|
|
159
|
+
}
|
|
149
160
|
return { compatible: true };
|
|
150
161
|
};
|
|
151
162
|
export const getNormalizedAvdCacheConfig = ({ emulator, hostArch, }) => {
|
|
@@ -1,3 +1,26 @@
|
|
|
1
1
|
export type EmulatorBootMode = 'default-boot' | 'clean-snapshot-generation' | 'snapshot-reuse';
|
|
2
|
+
/**
|
|
3
|
+
* Returns the vCPU count baked into an AVD for this runner.
|
|
4
|
+
*
|
|
5
|
+
* AVD snapshots require an identical hardware configuration to load, so all
|
|
6
|
+
* AVD creation, compatibility, and cache-key callers must use this value on
|
|
7
|
+
* the same host.
|
|
8
|
+
*/
|
|
9
|
+
export declare const getEmulatorCpuCores: () => number;
|
|
2
10
|
export declare const getEmulatorStartupArgs: (name: string, mode: EmulatorBootMode) => string[];
|
|
11
|
+
/**
|
|
12
|
+
* Parses the output of `emulator -accel-check` to determine whether
|
|
13
|
+
* hardware acceleration (KVM on Linux, HVF on macOS) is usable. The
|
|
14
|
+
* emulator prints a message containing "is installed and usable" when
|
|
15
|
+
* acceleration is available.
|
|
16
|
+
*/
|
|
17
|
+
export declare const isAccelerationUsable: (accelCheckOutput: string) => boolean;
|
|
18
|
+
/**
|
|
19
|
+
* Runs `emulator -accel-check` and logs a non-fatal warning when hardware
|
|
20
|
+
* acceleration (KVM/HVF) appears unavailable, in which case the emulator
|
|
21
|
+
* falls back to very slow software emulation. This check must never fail or
|
|
22
|
+
* block emulator startup - any error running it is swallowed and only
|
|
23
|
+
* debug-logged.
|
|
24
|
+
*/
|
|
25
|
+
export declare const warnIfEmulatorAccelerationUnavailable: () => Promise<void>;
|
|
3
26
|
//# sourceMappingURL=emulator-startup.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"emulator-startup.d.ts","sourceRoot":"","sources":["../src/emulator-startup.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"emulator-startup.d.ts","sourceRoot":"","sources":["../src/emulator-startup.ts"],"names":[],"mappings":"AAWA,MAAM,MAAM,gBAAgB,GACxB,cAAc,GACd,2BAA2B,GAC3B,gBAAgB,CAAC;AAErB;;;;;;GAMG;AACH,eAAO,MAAM,mBAAmB,QAAO,MAEtC,CAAC;AAWF,eAAO,MAAM,sBAAsB,GACjC,MAAM,MAAM,EACZ,MAAM,gBAAgB,KACrB,MAAM,EASR,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,oBAAoB,GAAI,kBAAkB,MAAM,KAAG,OAE/D,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,qCAAqC,QACtC,OAAO,CAAC,IAAI,CA+BrB,CAAC"}
|
package/dist/emulator-startup.js
CHANGED
|
@@ -1,9 +1,24 @@
|
|
|
1
|
+
import { getDeviceCoreBudget, logger, spawn, SubprocessError, } from '@react-native-harness/tools';
|
|
2
|
+
import os from 'node:os';
|
|
3
|
+
import { getEmulatorBinaryPath } from './environment.js';
|
|
4
|
+
const emulatorStartupLogger = logger.child('android-emulator-startup');
|
|
5
|
+
/**
|
|
6
|
+
* Returns the vCPU count baked into an AVD for this runner.
|
|
7
|
+
*
|
|
8
|
+
* AVD snapshots require an identical hardware configuration to load, so all
|
|
9
|
+
* AVD creation, compatibility, and cache-key callers must use this value on
|
|
10
|
+
* the same host.
|
|
11
|
+
*/
|
|
12
|
+
export const getEmulatorCpuCores = () => {
|
|
13
|
+
return getDeviceCoreBudget(os.availableParallelism());
|
|
14
|
+
};
|
|
1
15
|
const COMMON_EMULATOR_ARGS = [
|
|
2
16
|
'-no-window',
|
|
3
17
|
'-gpu',
|
|
4
18
|
'swiftshader_indirect',
|
|
5
19
|
'-noaudio',
|
|
6
20
|
'-no-boot-anim',
|
|
21
|
+
'-no-metrics',
|
|
7
22
|
];
|
|
8
23
|
export const getEmulatorStartupArgs = (name, mode) => {
|
|
9
24
|
const modeArgs = mode === 'clean-snapshot-generation'
|
|
@@ -13,3 +28,46 @@ export const getEmulatorStartupArgs = (name, mode) => {
|
|
|
13
28
|
: ['-no-snapshot-load', '-no-snapshot-save'];
|
|
14
29
|
return [`@${name}`, ...modeArgs, ...COMMON_EMULATOR_ARGS];
|
|
15
30
|
};
|
|
31
|
+
/**
|
|
32
|
+
* Parses the output of `emulator -accel-check` to determine whether
|
|
33
|
+
* hardware acceleration (KVM on Linux, HVF on macOS) is usable. The
|
|
34
|
+
* emulator prints a message containing "is installed and usable" when
|
|
35
|
+
* acceleration is available.
|
|
36
|
+
*/
|
|
37
|
+
export const isAccelerationUsable = (accelCheckOutput) => {
|
|
38
|
+
return accelCheckOutput.includes('is installed and usable');
|
|
39
|
+
};
|
|
40
|
+
/**
|
|
41
|
+
* Runs `emulator -accel-check` and logs a non-fatal warning when hardware
|
|
42
|
+
* acceleration (KVM/HVF) appears unavailable, in which case the emulator
|
|
43
|
+
* falls back to very slow software emulation. This check must never fail or
|
|
44
|
+
* block emulator startup - any error running it is swallowed and only
|
|
45
|
+
* debug-logged.
|
|
46
|
+
*/
|
|
47
|
+
export const warnIfEmulatorAccelerationUnavailable = async () => {
|
|
48
|
+
let combinedOutput;
|
|
49
|
+
try {
|
|
50
|
+
const emulatorBinaryPath = getEmulatorBinaryPath();
|
|
51
|
+
const { stdout, stderr } = await spawn(emulatorBinaryPath, [
|
|
52
|
+
'-accel-check',
|
|
53
|
+
]);
|
|
54
|
+
combinedOutput = `${stdout}\n${stderr}`;
|
|
55
|
+
}
|
|
56
|
+
catch (error) {
|
|
57
|
+
if (error instanceof SubprocessError) {
|
|
58
|
+
// The check itself ran but exited non-zero - this is how
|
|
59
|
+
// `-accel-check` reports that acceleration is unavailable, so treat
|
|
60
|
+
// its output as a normal (non-fatal) result rather than swallowing it.
|
|
61
|
+
combinedOutput = `${error.stdout}\n${error.stderr}`;
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
// Failed to even run the check (e.g. binary missing). This must never
|
|
65
|
+
// fail or block emulator startup.
|
|
66
|
+
emulatorStartupLogger.debug('Failed to run "emulator -accel-check": %o', error);
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
if (!isAccelerationUsable(combinedOutput)) {
|
|
71
|
+
logger.warn('Hardware acceleration (KVM/HVF) appears unavailable for the Android emulator. It will fall back to very slow software emulation.');
|
|
72
|
+
}
|
|
73
|
+
};
|
package/dist/index.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ export { androidEmulator, physicalAndroidDevice, androidPlatform, } from './fact
|
|
|
2
2
|
export type { AndroidPlatformConfig } from './config.js';
|
|
3
3
|
export { getNormalizedAvdCacheConfig, resolveAvdCachingEnabled, } from './avd-config.js';
|
|
4
4
|
export { getHostAndroidSystemImageArch } from './environment.js';
|
|
5
|
+
export { getEmulatorCpuCores } from './emulator-startup.js';
|
|
5
6
|
export { HarnessAppPathError, HarnessEmulatorConfigError } from './errors.js';
|
|
6
7
|
export { getRunTargets } from './targets.js';
|
|
7
8
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,eAAe,EACf,qBAAqB,EACrB,eAAe,GAChB,MAAM,cAAc,CAAC;AACtB,YAAY,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AACzD,OAAO,EACL,2BAA2B,EAC3B,wBAAwB,GACzB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,6BAA6B,EAAE,MAAM,kBAAkB,CAAC;AACjE,OAAO,EAAE,mBAAmB,EAAE,0BAA0B,EAAE,MAAM,aAAa,CAAC;AAC9E,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,eAAe,EACf,qBAAqB,EACrB,eAAe,GAChB,MAAM,cAAc,CAAC;AACtB,YAAY,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AACzD,OAAO,EACL,2BAA2B,EAC3B,wBAAwB,GACzB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,6BAA6B,EAAE,MAAM,kBAAkB,CAAC;AACjE,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,EAAE,mBAAmB,EAAE,0BAA0B,EAAE,MAAM,aAAa,CAAC;AAC9E,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export { androidEmulator, physicalAndroidDevice, androidPlatform, } from './factory.js';
|
|
2
2
|
export { getNormalizedAvdCacheConfig, resolveAvdCachingEnabled, } from './avd-config.js';
|
|
3
3
|
export { getHostAndroidSystemImageArch } from './environment.js';
|
|
4
|
+
export { getEmulatorCpuCores } from './emulator-startup.js';
|
|
4
5
|
export { HarnessAppPathError, HarnessEmulatorConfigError } from './errors.js';
|
|
5
6
|
export { getRunTargets } from './targets.js';
|
package/dist/instance.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"instance.d.ts","sourceRoot":"","sources":["../src/instance.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,0BAA0B,EAC/B,qBAAqB,EACtB,MAAM,iCAAiC,CAAC;AACzC,OAAO,KAAK,EAAE,MAAM,IAAI,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAE5E,OAAO,EACL,qBAAqB,EAGtB,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"instance.d.ts","sourceRoot":"","sources":["../src/instance.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,0BAA0B,EAC/B,qBAAqB,EACtB,MAAM,iCAAiC,CAAC;AACzC,OAAO,KAAK,EAAE,MAAM,IAAI,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAE5E,OAAO,EACL,qBAAqB,EAGtB,MAAM,aAAa,CAAC;AAyKrB,eAAO,MAAM,kCAAkC,GAC7C,QAAQ,qBAAqB,EAC7B,eAAe,aAAa,EAC5B,MAAM,0BAA0B,KAC/B,OAAO,CAAC,qBAAqB,CAoI/B,CAAC;AAEF,eAAO,MAAM,wCAAwC,GACnD,QAAQ,qBAAqB,EAC7B,eAAe,aAAa,EAC5B,OAAO,0BAA0B,KAChC,OAAO,CAAC,qBAAqB,CA+D/B,CAAC"}
|
package/dist/instance.js
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import { AppNotInstalledError, DeviceNotFoundError, } from '@react-native-harness/platforms';
|
|
2
|
-
import { logger } from '@react-native-harness/tools';
|
|
2
|
+
import { instrumented, logger, noopDiagnostics } from '@react-native-harness/tools';
|
|
3
3
|
import { assertAndroidDeviceEmulator, assertAndroidDevicePhysical, } from './config.js';
|
|
4
4
|
import { isAvdCompatible, readAvdConfig, resolveAvdCachingEnabled, } from './avd-config.js';
|
|
5
5
|
import { getAdbId } from './adb-id.js';
|
|
6
|
-
import * as
|
|
6
|
+
import * as adbModule from './adb.js';
|
|
7
7
|
import { applyHarnessDebugHttpHost, clearHarnessDebugHttpHost, } from './shared-prefs.js';
|
|
8
8
|
import { getDeviceName } from './utils.js';
|
|
9
9
|
import { HarnessAppPathError, HarnessEmulatorConfigError } from './errors.js';
|
|
10
10
|
import { ensureAndroidEmulatorAvailable, ensureAndroidEmulatorEnvironment, getHostAndroidSystemImageArch, } from './environment.js';
|
|
11
|
+
import { warnIfEmulatorAccelerationUnavailable } from './emulator-startup.js';
|
|
11
12
|
import { isInteractive } from '@react-native-harness/tools';
|
|
12
13
|
import fs from 'node:fs';
|
|
13
14
|
import { createAndroidAppSession } from './app-session.js';
|
|
@@ -35,23 +36,24 @@ const getOptionalHarnessAppPath = () => {
|
|
|
35
36
|
const configureAndroidRuntime = async (adbId, config, harnessConfig) => {
|
|
36
37
|
const metroPort = harnessConfig.metroPort;
|
|
37
38
|
await Promise.all([
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
39
|
+
adbModule.reversePort(adbId, metroPort),
|
|
40
|
+
adbModule.reversePort(adbId, 8080),
|
|
41
|
+
adbModule.setHideErrorDialogs(adbId, true),
|
|
41
42
|
applyHarnessDebugHttpHost(adbId, config.bundleId, `localhost:${metroPort}`),
|
|
42
43
|
]);
|
|
43
|
-
return
|
|
44
|
+
return adbModule.getAppUid(adbId, config.bundleId);
|
|
44
45
|
};
|
|
45
46
|
const startAndWaitForBoot = async ({ emulatorName, signal, mode, }) => {
|
|
46
47
|
await ensureAndroidEmulatorAvailable();
|
|
47
|
-
await
|
|
48
|
-
|
|
48
|
+
await warnIfEmulatorAccelerationUnavailable();
|
|
49
|
+
await adbModule.startEmulator(emulatorName, mode);
|
|
50
|
+
return adbModule.waitForBoot(emulatorName, signal);
|
|
49
51
|
};
|
|
50
52
|
const recreateAvd = async ({ emulatorConfig, }) => {
|
|
51
53
|
if (!emulatorConfig.avd) {
|
|
52
54
|
throw new HarnessEmulatorConfigError(emulatorConfig.name);
|
|
53
55
|
}
|
|
54
|
-
await
|
|
56
|
+
await adbModule.createAvd({
|
|
55
57
|
name: emulatorConfig.name,
|
|
56
58
|
apiLevel: emulatorConfig.avd.apiLevel,
|
|
57
59
|
profile: emulatorConfig.avd.profile,
|
|
@@ -62,7 +64,7 @@ const recreateAvd = async ({ emulatorConfig, }) => {
|
|
|
62
64
|
const prepareCachedAvd = async ({ emulatorConfig, signal, }) => {
|
|
63
65
|
const emulatorName = emulatorConfig.name;
|
|
64
66
|
const hostArch = getHostAndroidSystemImageArch();
|
|
65
|
-
const hasExistingAvd = await
|
|
67
|
+
const hasExistingAvd = await adbModule.hasAvd(emulatorName);
|
|
66
68
|
const avdConfig = hasExistingAvd ? await readAvdConfig(emulatorName) : null;
|
|
67
69
|
const compatibility = avdConfig == null
|
|
68
70
|
? { compatible: false, reason: 'Missing AVD config.ini.' }
|
|
@@ -77,7 +79,7 @@ const prepareCachedAvd = async ({ emulatorConfig, signal, }) => {
|
|
|
77
79
|
: 'Creating Android emulator %s...', emulatorName);
|
|
78
80
|
if (hasExistingAvd && !compatibility.compatible) {
|
|
79
81
|
androidInstanceLogger.debug('Android AVD %s is not reusable: %s', emulatorName, compatibility.reason);
|
|
80
|
-
await
|
|
82
|
+
await adbModule.deleteAvd(emulatorName);
|
|
81
83
|
}
|
|
82
84
|
await recreateAvd({ emulatorConfig });
|
|
83
85
|
const generationAdbId = await startAndWaitForBoot({
|
|
@@ -86,8 +88,8 @@ const prepareCachedAvd = async ({ emulatorConfig, signal, }) => {
|
|
|
86
88
|
mode: 'clean-snapshot-generation',
|
|
87
89
|
});
|
|
88
90
|
logger.info('Saving Android emulator snapshot for %s...', emulatorName);
|
|
89
|
-
await
|
|
90
|
-
await
|
|
91
|
+
await adbModule.stopEmulator(generationAdbId);
|
|
92
|
+
await adbModule.waitForEmulatorDisconnect(generationAdbId, signal);
|
|
91
93
|
}
|
|
92
94
|
else {
|
|
93
95
|
logger.info('Using cached Android emulator %s...', emulatorName);
|
|
@@ -100,6 +102,7 @@ const prepareCachedAvd = async ({ emulatorConfig, signal, }) => {
|
|
|
100
102
|
};
|
|
101
103
|
export const getAndroidEmulatorPlatformInstance = async (config, harnessConfig, init) => {
|
|
102
104
|
assertAndroidDeviceEmulator(config.device);
|
|
105
|
+
const adb = instrumented(adbModule, 'platform.android.adb', init.diagnostics ?? noopDiagnostics);
|
|
103
106
|
const permissionsEnabled = harnessConfig.permissions ?? false;
|
|
104
107
|
const emulatorConfig = config.device;
|
|
105
108
|
const emulatorName = emulatorConfig.name;
|
|
@@ -169,10 +172,11 @@ export const getAndroidEmulatorPlatformInstance = async (config, harnessConfig,
|
|
|
169
172
|
stopApp: () => adb.stopApp(adbId, config.bundleId),
|
|
170
173
|
getAppPid: () => adb.getAppPid(adbId, config.bundleId),
|
|
171
174
|
getLogcatTimestamp: () => adb.getLogcatTimestamp(adbId),
|
|
172
|
-
startLogcat: (args) => adb.startLogcat(adbId, args),
|
|
175
|
+
startLogcat: (args, options) => adb.startLogcat(adbId, args, options),
|
|
173
176
|
getDropboxOutput: () => adb.getDropboxPrint(adbId),
|
|
174
177
|
getExitInfo: () => adb.getActivityExitInfo(adbId, config.bundleId),
|
|
175
178
|
crashArtifactWriter: init.crashArtifactWriter,
|
|
179
|
+
signal: init.signal,
|
|
176
180
|
});
|
|
177
181
|
},
|
|
178
182
|
dispose: async () => {
|
|
@@ -188,6 +192,7 @@ export const getAndroidEmulatorPlatformInstance = async (config, harnessConfig,
|
|
|
188
192
|
};
|
|
189
193
|
export const getAndroidPhysicalDevicePlatformInstance = async (config, harnessConfig, init) => {
|
|
190
194
|
assertAndroidDevicePhysical(config.device);
|
|
195
|
+
const adb = instrumented(adbModule, 'platform.android.adb', init?.diagnostics ?? noopDiagnostics);
|
|
191
196
|
const permissionsEnabled = harnessConfig.permissions ?? false;
|
|
192
197
|
const adbId = await getAdbId(config.device);
|
|
193
198
|
if (!adbId) {
|
|
@@ -213,10 +218,11 @@ export const getAndroidPhysicalDevicePlatformInstance = async (config, harnessCo
|
|
|
213
218
|
stopApp: () => adb.stopApp(adbId, config.bundleId),
|
|
214
219
|
getAppPid: () => adb.getAppPid(adbId, config.bundleId),
|
|
215
220
|
getLogcatTimestamp: () => adb.getLogcatTimestamp(adbId),
|
|
216
|
-
startLogcat: (args) => adb.startLogcat(adbId, args),
|
|
221
|
+
startLogcat: (args, options) => adb.startLogcat(adbId, args, options),
|
|
217
222
|
getDropboxOutput: () => adb.getDropboxPrint(adbId),
|
|
218
223
|
getExitInfo: () => adb.getActivityExitInfo(adbId, config.bundleId),
|
|
219
224
|
crashArtifactWriter: init?.crashArtifactWriter,
|
|
225
|
+
signal: init?.signal,
|
|
220
226
|
});
|
|
221
227
|
},
|
|
222
228
|
dispose: async () => {
|
package/dist/runner.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { type HarnessPlatformRunnerFactory } from '@react-native-harness/platforms';
|
|
2
2
|
import type { Config as HarnessConfig } from '@react-native-harness/config';
|
|
3
3
|
import { type AndroidPlatformConfig } from './config.js';
|
|
4
|
-
declare const getAndroidRunner:
|
|
4
|
+
declare const getAndroidRunner: HarnessPlatformRunnerFactory<AndroidPlatformConfig, HarnessConfig>;
|
|
5
5
|
export default getAndroidRunner;
|
|
6
6
|
//# sourceMappingURL=runner.d.ts.map
|
package/dist/runner.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../src/runner.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../src/runner.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,4BAA4B,EAAE,MAAM,iCAAiC,CAAC;AACpF,OAAO,KAAK,EAAE,MAAM,IAAI,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAC5E,OAAO,EAEL,KAAK,qBAAqB,EAE3B,MAAM,aAAa,CAAC;AAUrB,QAAA,MAAM,gBAAgB,EAAE,4BAA4B,CAClD,qBAAqB,EACrB,aAAa,CAqBd,CAAC;AAEF,eAAe,gBAAgB,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@react-native-harness/platform-android",
|
|
3
3
|
"description": "Android platform for React Native Harness",
|
|
4
|
-
"version": "1.4.
|
|
4
|
+
"version": "1.4.1",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
7
7
|
"module": "./dist/index.js",
|
|
@@ -19,9 +19,9 @@
|
|
|
19
19
|
"vite": "^7.2.2",
|
|
20
20
|
"zod": "^3.25.67",
|
|
21
21
|
"tslib": "^2.3.0",
|
|
22
|
-
"@react-native-harness/
|
|
23
|
-
"@react-native-harness/
|
|
24
|
-
"@react-native-harness/tools": "1.4.
|
|
22
|
+
"@react-native-harness/config": "1.4.1",
|
|
23
|
+
"@react-native-harness/platforms": "1.4.1",
|
|
24
|
+
"@react-native-harness/tools": "1.4.1"
|
|
25
25
|
},
|
|
26
26
|
"license": "MIT"
|
|
27
27
|
}
|