@react-native-harness/platform-android 1.2.0 → 1.4.0-rc.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.
Files changed (41) hide show
  1. package/dist/__tests__/app-monitor.test.js +180 -102
  2. package/dist/__tests__/crash-diagnostics.test.d.ts +2 -0
  3. package/dist/__tests__/crash-diagnostics.test.d.ts.map +1 -0
  4. package/dist/__tests__/crash-diagnostics.test.js +119 -0
  5. package/dist/__tests__/crash-reporter.test.d.ts +2 -0
  6. package/dist/__tests__/crash-reporter.test.d.ts.map +1 -0
  7. package/dist/__tests__/crash-reporter.test.js +150 -0
  8. package/dist/__tests__/instance.test.js +133 -24
  9. package/dist/adb.d.ts +4 -0
  10. package/dist/adb.d.ts.map +1 -1
  11. package/dist/adb.js +42 -2
  12. package/dist/app-session.d.ts +17 -0
  13. package/dist/app-session.d.ts.map +1 -0
  14. package/dist/app-session.js +209 -0
  15. package/dist/crash-diagnostics.d.ts +40 -0
  16. package/dist/crash-diagnostics.d.ts.map +1 -0
  17. package/dist/crash-diagnostics.js +256 -0
  18. package/dist/crash-reporter.d.ts +12 -0
  19. package/dist/crash-reporter.d.ts.map +1 -0
  20. package/dist/crash-reporter.js +150 -0
  21. package/dist/device-state.d.ts +6 -0
  22. package/dist/device-state.d.ts.map +1 -0
  23. package/dist/device-state.js +142 -0
  24. package/dist/instance.d.ts +1 -1
  25. package/dist/instance.d.ts.map +1 -1
  26. package/dist/instance.js +32 -59
  27. package/dist/runner.d.ts.map +1 -1
  28. package/dist/runner.js +1 -1
  29. package/dist/tsconfig.lib.tsbuildinfo +1 -1
  30. package/package.json +4 -4
  31. package/src/__tests__/crash-diagnostics.test.ts +144 -0
  32. package/src/__tests__/crash-reporter.test.ts +167 -0
  33. package/src/__tests__/instance.test.ts +174 -31
  34. package/src/adb.ts +61 -2
  35. package/src/app-session.ts +300 -0
  36. package/src/crash-diagnostics.ts +471 -0
  37. package/src/crash-reporter.ts +263 -0
  38. package/src/instance.ts +56 -91
  39. package/src/runner.ts +7 -3
  40. package/test/setup.ts +1 -0
  41. package/src/app-monitor.ts +0 -577
@@ -5,6 +5,19 @@ import * as adb from '../adb.js';
5
5
  import * as avdConfig from '../avd-config.js';
6
6
  import * as sharedPrefs from '../shared-prefs.js';
7
7
  import { HarnessAppPathError, HarnessEmulatorConfigError } from '../errors.js';
8
+ const createLogcatProcess = (lines = []) => {
9
+ const process = {
10
+ nodeChildProcess: Promise.resolve({
11
+ kill: vi.fn(),
12
+ }),
13
+ [Symbol.asyncIterator]: async function* () {
14
+ for (const line of lines) {
15
+ yield line;
16
+ }
17
+ },
18
+ };
19
+ return process;
20
+ };
8
21
  const harnessConfig = {
9
22
  metroPort: DEFAULT_METRO_PORT,
10
23
  };
@@ -19,6 +32,7 @@ describe('Android platform instance', () => {
19
32
  beforeEach(async () => {
20
33
  vi.restoreAllMocks();
21
34
  vi.unstubAllEnvs();
35
+ vi.useRealTimers();
22
36
  vi.spyOn(await import('../environment.js'), 'ensureAndroidEmulatorAvailable').mockResolvedValue('/tmp/android-sdk');
23
37
  });
24
38
  it('reuses a running emulator and does not shut it down on dispose', async () => {
@@ -32,6 +46,7 @@ describe('Android platform instance', () => {
32
46
  vi.spyOn(adb, 'reversePort').mockResolvedValue(undefined);
33
47
  vi.spyOn(adb, 'setHideErrorDialogs').mockResolvedValue(undefined);
34
48
  vi.spyOn(adb, 'getAppUid').mockResolvedValue(10234);
49
+ vi.spyOn(adb, 'getLogcatTimestamp').mockResolvedValue('01-01 00:00:00.000');
35
50
  vi.spyOn(sharedPrefs, 'applyHarnessDebugHttpHost').mockResolvedValue(undefined);
36
51
  vi.spyOn(sharedPrefs, 'clearHarnessDebugHttpHost').mockResolvedValue(undefined);
37
52
  vi.spyOn(adb, 'stopApp').mockResolvedValue(undefined);
@@ -68,6 +83,7 @@ describe('Android platform instance', () => {
68
83
  vi.spyOn(adb, 'reversePort').mockResolvedValue(undefined);
69
84
  vi.spyOn(adb, 'setHideErrorDialogs').mockResolvedValue(undefined);
70
85
  vi.spyOn(adb, 'getAppUid').mockResolvedValue(10234);
86
+ vi.spyOn(adb, 'getLogcatTimestamp').mockResolvedValue('01-01 00:00:00.000');
71
87
  vi.spyOn(sharedPrefs, 'applyHarnessDebugHttpHost').mockResolvedValue(undefined);
72
88
  vi.spyOn(sharedPrefs, 'clearHarnessDebugHttpHost').mockResolvedValue(undefined);
73
89
  vi.spyOn(adb, 'stopApp').mockResolvedValue(undefined);
@@ -113,6 +129,7 @@ describe('Android platform instance', () => {
113
129
  vi.spyOn(adb, 'reversePort').mockResolvedValue(undefined);
114
130
  vi.spyOn(adb, 'setHideErrorDialogs').mockResolvedValue(undefined);
115
131
  vi.spyOn(adb, 'getAppUid').mockResolvedValue(10234);
132
+ vi.spyOn(adb, 'getLogcatTimestamp').mockResolvedValue('01-01 00:00:00.000');
116
133
  vi.spyOn(sharedPrefs, 'applyHarnessDebugHttpHost').mockResolvedValue(undefined);
117
134
  await expect(getAndroidEmulatorPlatformInstance({
118
135
  name: 'android',
@@ -152,6 +169,7 @@ describe('Android platform instance', () => {
152
169
  vi.spyOn(adb, 'reversePort').mockResolvedValue(undefined);
153
170
  vi.spyOn(adb, 'setHideErrorDialogs').mockResolvedValue(undefined);
154
171
  vi.spyOn(adb, 'getAppUid').mockResolvedValue(10234);
172
+ vi.spyOn(adb, 'getLogcatTimestamp').mockResolvedValue('01-01 00:00:00.000');
155
173
  vi.spyOn(sharedPrefs, 'applyHarnessDebugHttpHost').mockResolvedValue(undefined);
156
174
  await expect(getAndroidEmulatorPlatformInstance({
157
175
  name: 'android',
@@ -196,6 +214,7 @@ describe('Android platform instance', () => {
196
214
  vi.spyOn(adb, 'reversePort').mockResolvedValue(undefined);
197
215
  vi.spyOn(adb, 'setHideErrorDialogs').mockResolvedValue(undefined);
198
216
  vi.spyOn(adb, 'getAppUid').mockResolvedValue(10234);
217
+ vi.spyOn(adb, 'getLogcatTimestamp').mockResolvedValue('01-01 00:00:00.000');
199
218
  vi.spyOn(sharedPrefs, 'applyHarnessDebugHttpHost').mockResolvedValue(undefined);
200
219
  await expect(getAndroidEmulatorPlatformInstance({
201
220
  name: 'android',
@@ -238,6 +257,7 @@ describe('Android platform instance', () => {
238
257
  vi.spyOn(adb, 'reversePort').mockResolvedValue(undefined);
239
258
  vi.spyOn(adb, 'setHideErrorDialogs').mockResolvedValue(undefined);
240
259
  vi.spyOn(adb, 'getAppUid').mockResolvedValue(10234);
260
+ vi.spyOn(adb, 'getLogcatTimestamp').mockResolvedValue('01-01 00:00:00.000');
241
261
  vi.spyOn(sharedPrefs, 'applyHarnessDebugHttpHost').mockResolvedValue(undefined);
242
262
  await expect(getAndroidEmulatorPlatformInstance({
243
263
  name: 'android',
@@ -315,7 +335,8 @@ describe('Android platform instance', () => {
315
335
  activityName: '.MainActivity',
316
336
  }, harnessConfig, init)).rejects.toBeInstanceOf(HarnessEmulatorConfigError);
317
337
  });
318
- it('returns a noop emulator app monitor when native crash detection is disabled', async () => {
338
+ it('creates a real emulator app session when native crash detection is disabled', async () => {
339
+ vi.useFakeTimers();
319
340
  vi.spyOn(await import('../environment.js'), 'ensureAndroidEmulatorEnvironment').mockResolvedValue('/tmp/android-sdk');
320
341
  vi.spyOn(adb, 'getDeviceIds').mockResolvedValue(['emulator-5554']);
321
342
  vi.spyOn(adb, 'getEmulatorName').mockResolvedValue('Pixel_8_API_35');
@@ -324,7 +345,14 @@ describe('Android platform instance', () => {
324
345
  vi.spyOn(adb, 'reversePort').mockResolvedValue(undefined);
325
346
  vi.spyOn(adb, 'setHideErrorDialogs').mockResolvedValue(undefined);
326
347
  vi.spyOn(adb, 'getAppUid').mockResolvedValue(10234);
348
+ vi.spyOn(adb, 'getLogcatTimestamp').mockResolvedValue('01-01 00:00:00.000');
327
349
  vi.spyOn(sharedPrefs, 'applyHarnessDebugHttpHost').mockResolvedValue(undefined);
350
+ const stopApp = vi.spyOn(adb, 'stopApp').mockResolvedValue(undefined);
351
+ const startApp = vi.spyOn(adb, 'startApp').mockResolvedValue(undefined);
352
+ const getAppPid = vi.spyOn(adb, 'getAppPid').mockResolvedValue(4321);
353
+ const startLogcat = vi
354
+ .spyOn(adb, 'startLogcat')
355
+ .mockReturnValue(createLogcatProcess());
328
356
  const instance = await getAndroidEmulatorPlatformInstance({
329
357
  name: 'android',
330
358
  device: {
@@ -341,14 +369,84 @@ describe('Android platform instance', () => {
341
369
  activityName: '.MainActivity',
342
370
  }, harnessConfigWithoutNativeCrashDetection, init);
343
371
  const listener = vi.fn();
344
- const appMonitor = instance.createAppMonitor();
345
- await expect(appMonitor.start()).resolves.toBeUndefined();
346
- await expect(appMonitor.stop()).resolves.toBeUndefined();
347
- await expect(appMonitor.dispose()).resolves.toBeUndefined();
348
- expect(appMonitor.addListener(listener)).toBeUndefined();
349
- expect(appMonitor.removeListener(listener)).toBeUndefined();
372
+ const appSession = await instance.createAppSession();
373
+ appSession.addListener(listener);
374
+ await vi.advanceTimersByTimeAsync(0);
375
+ expect(startLogcat).toHaveBeenCalledWith('emulator-5554', [
376
+ 'logcat',
377
+ '-v',
378
+ 'threadtime',
379
+ '-b',
380
+ 'crash',
381
+ '--uid=10234',
382
+ '-T',
383
+ '01-01 00:00:00.000',
384
+ ]);
385
+ expect(startLogcat.mock.invocationCallOrder[0]).toBeLessThan(startApp.mock.invocationCallOrder[0]);
386
+ await expect(appSession.getState()).resolves.toEqual({
387
+ status: 'running',
388
+ pid: 4321,
389
+ });
390
+ expect(getAppPid).toHaveBeenCalled();
391
+ expect(listener).not.toHaveBeenCalled();
392
+ expect(appSession.removeListener(listener)).toBeUndefined();
393
+ await expect(appSession.dispose()).resolves.toBeUndefined();
394
+ expect(stopApp).toHaveBeenCalled();
395
+ });
396
+ it('reports an early Android crash from logcat before a PID poll succeeds', async () => {
397
+ vi.useFakeTimers();
398
+ vi.spyOn(await import('../environment.js'), 'ensureAndroidEmulatorEnvironment').mockResolvedValue('/tmp/android-sdk');
399
+ vi.spyOn(adb, 'getDeviceIds').mockResolvedValue(['emulator-5554']);
400
+ vi.spyOn(adb, 'getEmulatorName').mockResolvedValue('Pixel_8_API_35');
401
+ vi.spyOn(adb, 'waitForBoot').mockResolvedValue('emulator-5554');
402
+ vi.spyOn(adb, 'isAppInstalled').mockResolvedValue(true);
403
+ vi.spyOn(adb, 'reversePort').mockResolvedValue(undefined);
404
+ vi.spyOn(adb, 'setHideErrorDialogs').mockResolvedValue(undefined);
405
+ vi.spyOn(adb, 'getAppUid').mockResolvedValue(10234);
406
+ vi.spyOn(adb, 'getLogcatTimestamp').mockResolvedValue('01-01 00:00:00.000');
407
+ vi.spyOn(sharedPrefs, 'applyHarnessDebugHttpHost').mockResolvedValue(undefined);
408
+ vi.spyOn(adb, 'stopApp').mockResolvedValue(undefined);
409
+ vi.spyOn(adb, 'startApp').mockResolvedValue(undefined);
410
+ vi.spyOn(adb, 'getAppPid').mockResolvedValue(null);
411
+ vi.spyOn(adb, 'startLogcat').mockReturnValue(createLogcatProcess([
412
+ '--------- beginning of crash',
413
+ 'Process: com.harnessplayground, PID: 7777',
414
+ 'FATAL EXCEPTION: main',
415
+ ]));
416
+ const instance = await getAndroidEmulatorPlatformInstance({
417
+ name: 'android',
418
+ device: {
419
+ type: 'emulator',
420
+ name: 'Pixel_8_API_35',
421
+ avd: {
422
+ apiLevel: 35,
423
+ profile: 'pixel_8',
424
+ diskSize: '1G',
425
+ heapSize: '1G',
426
+ },
427
+ },
428
+ bundleId: 'com.harnessplayground',
429
+ activityName: '.MainActivity',
430
+ }, harnessConfig, init);
431
+ const listener = vi.fn();
432
+ const appSession = await instance.createAppSession();
433
+ appSession.addListener(listener);
434
+ await vi.advanceTimersByTimeAsync(0);
435
+ expect(appSession.getLogs().map((entry) => entry.line)).toEqual([
436
+ '--------- beginning of crash',
437
+ 'Process: com.harnessplayground, PID: 7777',
438
+ 'FATAL EXCEPTION: main',
439
+ ]);
440
+ await expect(appSession.getState()).resolves.toMatchObject({
441
+ status: 'exited',
442
+ pid: 7777,
443
+ reason: 'observed-exit',
444
+ });
445
+ expect(listener).toHaveBeenCalledWith({ type: 'app_exited' });
446
+ await appSession.dispose();
350
447
  });
351
- it('returns a noop physical device app monitor when native crash detection is disabled', async () => {
448
+ it('creates a real physical-device app session when native crash detection is disabled', async () => {
449
+ vi.useFakeTimers();
352
450
  vi.spyOn(adb, 'getDeviceIds').mockResolvedValue(['012345']);
353
451
  vi.spyOn(adb, 'getDeviceInfo').mockResolvedValue({
354
452
  manufacturer: 'motorola',
@@ -358,17 +456,14 @@ describe('Android platform instance', () => {
358
456
  vi.spyOn(adb, 'reversePort').mockResolvedValue(undefined);
359
457
  vi.spyOn(adb, 'setHideErrorDialogs').mockResolvedValue(undefined);
360
458
  vi.spyOn(adb, 'getAppUid').mockResolvedValue(10234);
459
+ vi.spyOn(adb, 'getLogcatTimestamp').mockResolvedValue('01-01 00:00:00.000');
361
460
  vi.spyOn(sharedPrefs, 'applyHarnessDebugHttpHost').mockResolvedValue(undefined);
362
- await expect(getAndroidPhysicalDevicePlatformInstance({
363
- name: 'android-device',
364
- device: {
365
- type: 'physical',
366
- manufacturer: 'motorola',
367
- model: 'moto g72',
368
- },
369
- bundleId: 'com.harnessplayground',
370
- activityName: '.MainActivity',
371
- }, harnessConfigWithoutNativeCrashDetection)).resolves.toBeDefined();
461
+ vi.spyOn(adb, 'stopApp').mockResolvedValue(undefined);
462
+ vi.spyOn(adb, 'startApp').mockResolvedValue(undefined);
463
+ vi.spyOn(adb, 'getAppPid').mockResolvedValue(8765);
464
+ const startLogcat = vi
465
+ .spyOn(adb, 'startLogcat')
466
+ .mockReturnValue(createLogcatProcess());
372
467
  const instance = await getAndroidPhysicalDevicePlatformInstance({
373
468
  name: 'android-device',
374
469
  device: {
@@ -380,12 +475,26 @@ describe('Android platform instance', () => {
380
475
  activityName: '.MainActivity',
381
476
  }, harnessConfigWithoutNativeCrashDetection);
382
477
  const listener = vi.fn();
383
- const appMonitor = instance.createAppMonitor();
384
- await expect(appMonitor.start()).resolves.toBeUndefined();
385
- await expect(appMonitor.stop()).resolves.toBeUndefined();
386
- await expect(appMonitor.dispose()).resolves.toBeUndefined();
387
- expect(appMonitor.addListener(listener)).toBeUndefined();
388
- expect(appMonitor.removeListener(listener)).toBeUndefined();
478
+ const appSession = await instance.createAppSession();
479
+ appSession.addListener(listener);
480
+ await vi.advanceTimersByTimeAsync(0);
481
+ expect(startLogcat).toHaveBeenCalledWith('012345', [
482
+ 'logcat',
483
+ '-v',
484
+ 'threadtime',
485
+ '-b',
486
+ 'crash',
487
+ '--uid=10234',
488
+ '-T',
489
+ '01-01 00:00:00.000',
490
+ ]);
491
+ await expect(appSession.getState()).resolves.toEqual({
492
+ status: 'running',
493
+ pid: 8765,
494
+ });
495
+ expect(listener).not.toHaveBeenCalled();
496
+ expect(appSession.removeListener(listener)).toBeUndefined();
497
+ await expect(appSession.dispose()).resolves.toBeUndefined();
389
498
  });
390
499
  it('grants permissions when permissions are enabled for emulator', async () => {
391
500
  vi.spyOn(await import('../environment.js'), 'ensureAndroidEmulatorEnvironment').mockResolvedValue('/tmp/android-sdk');
package/dist/adb.d.ts CHANGED
@@ -40,10 +40,14 @@ export declare const waitForEmulator: (name: string, signal: AbortSignal) => Pro
40
40
  export declare const waitForEmulatorDisconnect: (adbId: string, signal: AbortSignal) => Promise<void>;
41
41
  export declare const waitForBoot: (name: string, signal: AbortSignal) => Promise<string>;
42
42
  export declare const isAppRunning: (adbId: string, bundleId: string) => Promise<boolean>;
43
+ export declare const getAppPid: (adbId: string, bundleId: string) => Promise<number | null>;
43
44
  export declare const getAppUid: (adbId: string, bundleId: string) => Promise<number>;
44
45
  export declare const setHideErrorDialogs: (adbId: string, hide: boolean) => Promise<void>;
45
46
  export declare const getLogcatTimestamp: (adbId: string) => Promise<string>;
46
47
  export declare const startLogcat: (adbId: string, args: readonly string[]) => Subprocess;
48
+ export declare const DROPBOX_CRASH_TAGS: readonly ["data_app_crash", "data_app_native_crash"];
49
+ export declare const getDropboxPrint: (adbId: string, tags?: readonly string[]) => Promise<string>;
50
+ export declare const getActivityExitInfo: (adbId: string, bundleId: string) => Promise<string>;
47
51
  export declare const getAvds: () => Promise<string[]>;
48
52
  export type AdbDevice = {
49
53
  id: string;
package/dist/adb.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"adb.d.ts","sourceRoot":"","sources":["../src/adb.ts"],"names":[],"mappings":"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"}
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,EAIL,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,EAEL,KAAK,gBAAgB,EACtB,MAAM,uBAAuB,CAAC;AA2C/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,CAkBjC,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,CAgFd,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,KACtB,UAIC,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
@@ -432,6 +432,9 @@ export const waitForBoot = async (name, signal) => {
432
432
  throw signal.reason;
433
433
  };
434
434
  export const isAppRunning = async (adbId, bundleId) => {
435
+ return (await getAppPid(adbId, bundleId)) != null;
436
+ };
437
+ export const getAppPid = async (adbId, bundleId) => {
435
438
  try {
436
439
  const { stdout } = await spawn(getAdbBinaryPath(), [
437
440
  '-s',
@@ -440,11 +443,15 @@ export const isAppRunning = async (adbId, bundleId) => {
440
443
  'pidof',
441
444
  bundleId,
442
445
  ]);
443
- return stdout.trim() !== '';
446
+ const pid = stdout
447
+ .trim()
448
+ .split(/\s+/)
449
+ .find((value) => value !== '');
450
+ return pid ? Number(pid) : null;
444
451
  }
445
452
  catch (error) {
446
453
  if (error instanceof SubprocessError && error.exitCode === 1) {
447
- return false;
454
+ return null;
448
455
  }
449
456
  throw error;
450
457
  }
@@ -494,6 +501,39 @@ export const startLogcat = (adbId, args) => spawn(getAdbBinaryPath(), ['-s', adb
494
501
  stdout: 'pipe',
495
502
  stderr: 'pipe',
496
503
  });
504
+ export const DROPBOX_CRASH_TAGS = [
505
+ 'data_app_crash',
506
+ 'data_app_native_crash',
507
+ ];
508
+ export const getDropboxPrint = async (adbId, tags = DROPBOX_CRASH_TAGS) => {
509
+ // Android treats multiple args after --print as one search string, so each
510
+ // tag must be queried separately and merged on the host.
511
+ const outputs = await Promise.all(tags.map(async (tag) => {
512
+ const { stdout } = await spawn(getAdbBinaryPath(), [
513
+ '-s',
514
+ adbId,
515
+ 'shell',
516
+ 'dumpsys',
517
+ 'dropbox',
518
+ '--print',
519
+ tag,
520
+ ]);
521
+ return stdout;
522
+ }));
523
+ return outputs.join('\n');
524
+ };
525
+ export const getActivityExitInfo = async (adbId, bundleId) => {
526
+ const { stdout } = await spawn(getAdbBinaryPath(), [
527
+ '-s',
528
+ adbId,
529
+ 'shell',
530
+ 'dumpsys',
531
+ 'activity',
532
+ 'exit-info',
533
+ bundleId,
534
+ ]);
535
+ return stdout;
536
+ };
497
537
  export const getAvds = async () => {
498
538
  try {
499
539
  const emulatorBinaryPath = await ensureEmulatorInstalled();
@@ -0,0 +1,17 @@
1
+ import { type AppSession, type CrashArtifactWriter } from '@react-native-harness/platforms';
2
+ import { type Subprocess } from '@react-native-harness/tools';
3
+ type CreateAndroidAppSessionOptions = {
4
+ appUid: number;
5
+ bundleId: string;
6
+ startApp: () => Promise<void>;
7
+ stopApp: () => Promise<void>;
8
+ getAppPid: () => Promise<number | null>;
9
+ getLogcatTimestamp: () => Promise<string>;
10
+ startLogcat: (args: readonly string[]) => Subprocess;
11
+ getDropboxOutput?: () => Promise<string>;
12
+ getExitInfo?: () => Promise<string>;
13
+ crashArtifactWriter?: CrashArtifactWriter;
14
+ };
15
+ export declare const createAndroidAppSession: ({ appUid, bundleId, startApp, stopApp, getAppPid, getLogcatTimestamp, startLogcat, getDropboxOutput, getExitInfo, crashArtifactWriter, }: CreateAndroidAppSessionOptions) => Promise<AppSession>;
16
+ export {};
17
+ //# sourceMappingURL=app-session.d.ts.map
@@ -0,0 +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;AAkErC,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,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,KAAK,UAAU,CAAC;IACrD,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;CAC3C,CAAC;AAEF,eAAO,MAAM,uBAAuB,GAAU,0IAW3C,8BAA8B,KAAG,OAAO,CAAC,UAAU,CAsMrD,CAAC"}
@@ -0,0 +1,209 @@
1
+ import { createAppSessionEmitter, createBoundedLogBuffer, } from '@react-native-harness/platforms';
2
+ import { escapeRegExp, logger, } from '@react-native-harness/tools';
3
+ import { createAndroidCrashReporter } from './crash-reporter.js';
4
+ const androidAppSessionLogger = logger.child('android-app-session');
5
+ const APP_EXIT_POLL_INTERVAL_MS = 1000;
6
+ const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
7
+ const getLogcatArgs = (appUid, fromTime) => [
8
+ 'logcat',
9
+ '-v',
10
+ 'threadtime',
11
+ '-b',
12
+ 'crash',
13
+ `--uid=${appUid}`,
14
+ '-T',
15
+ fromTime,
16
+ ];
17
+ const getProcessPattern = (bundleId) => new RegExp(`Process:\\s*${escapeRegExp(bundleId)},\\s*PID:\\s*(\\d+)`);
18
+ const getStartProcPattern = (bundleId) => new RegExp(`Start proc (\\d+):${escapeRegExp(bundleId)}(?:/|\\s)`);
19
+ const getProcessDiedPattern = (bundleId) => new RegExp(`Process\\s+${escapeRegExp(bundleId)}\\s+\\(pid\\s+(\\d+)\\)\\s+has\\s+died`, 'i');
20
+ const getObservedPid = (line, bundleId) => {
21
+ const match = line.match(getProcessPattern(bundleId)) ??
22
+ line.match(getStartProcPattern(bundleId)) ??
23
+ line.match(getProcessDiedPattern(bundleId));
24
+ return match?.[1] ? Number(match[1]) : undefined;
25
+ };
26
+ const isCrashSignal = (line, bundleId) => {
27
+ return (getProcessPattern(bundleId).test(line) ||
28
+ new RegExp(`>>>\\s*${escapeRegExp(bundleId)}\\s*<<<`).test(line) ||
29
+ getProcessDiedPattern(bundleId).test(line) ||
30
+ (line.includes(bundleId) &&
31
+ /fatal|crash|signal 11|signal 6|backtrace/i.test(line)));
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
+ const isExitedState = (state) => state.status === 'exited';
42
+ export const createAndroidAppSession = async ({ appUid, bundleId, startApp, stopApp, getAppPid, getLogcatTimestamp, startLogcat, getDropboxOutput, getExitInfo, crashArtifactWriter, }) => {
43
+ const emitter = createAppSessionEmitter();
44
+ const logBuffer = createBoundedLogBuffer();
45
+ let state = { status: 'running' };
46
+ let disposed = false;
47
+ let stopPolling = false;
48
+ let hasObservedProcess = false;
49
+ let exitNotification = null;
50
+ let pollDelayTimeout = null;
51
+ let resolvePollDelay = null;
52
+ const getCurrentPid = () => ('pid' in state ? state.pid : undefined);
53
+ const setRunning = (pid) => {
54
+ if (disposed || state.status === 'disposed' || state.status === 'exited') {
55
+ return;
56
+ }
57
+ if (pid !== undefined) {
58
+ hasObservedProcess = true;
59
+ }
60
+ state =
61
+ pid === undefined ? { status: 'running' } : { status: 'running', pid };
62
+ };
63
+ const scheduleExitNotification = () => {
64
+ if (exitNotification) {
65
+ return;
66
+ }
67
+ exitNotification = setTimeout(() => {
68
+ exitNotification = null;
69
+ if (!disposed && state.status === 'exited') {
70
+ emitter.emit({ type: 'app_exited' });
71
+ }
72
+ }, 0);
73
+ };
74
+ const waitForNextPoll = () => new Promise((resolve) => {
75
+ resolvePollDelay = () => {
76
+ resolvePollDelay = null;
77
+ pollDelayTimeout = null;
78
+ resolve();
79
+ };
80
+ pollDelayTimeout = setTimeout(() => {
81
+ resolvePollDelay?.();
82
+ }, APP_EXIT_POLL_INTERVAL_MS);
83
+ });
84
+ const cancelPendingPollDelay = () => {
85
+ if (pollDelayTimeout) {
86
+ clearTimeout(pollDelayTimeout);
87
+ pollDelayTimeout = null;
88
+ }
89
+ resolvePollDelay?.();
90
+ };
91
+ const setExited = (reason, pid) => {
92
+ if (disposed || state.status === 'disposed' || state.status === 'exited') {
93
+ return;
94
+ }
95
+ state = {
96
+ status: 'exited',
97
+ occurredAt: Date.now(),
98
+ pid: pid ?? getCurrentPid(),
99
+ reason,
100
+ };
101
+ scheduleExitNotification();
102
+ };
103
+ const setExitedPid = (pid) => {
104
+ if (state.status !== 'exited' || state.pid !== undefined) {
105
+ return;
106
+ }
107
+ state = {
108
+ status: 'exited',
109
+ occurredAt: state.occurredAt,
110
+ reason: state.reason,
111
+ pid,
112
+ };
113
+ };
114
+ const logcatTimestamp = await getLogcatTimestamp();
115
+ const sessionStartedAt = Date.now();
116
+ const logcatProcess = startLogcat(getLogcatArgs(appUid, logcatTimestamp));
117
+ const crashReporter = createAndroidCrashReporter({
118
+ bundleId,
119
+ crashArtifactWriter,
120
+ getLogs: () => logBuffer.getLogs(),
121
+ getDropboxOutput,
122
+ getExitInfo,
123
+ minOccurredAt: sessionStartedAt,
124
+ });
125
+ const logTask = (async () => {
126
+ try {
127
+ for await (const rawLine of logcatProcess) {
128
+ const line = String(rawLine);
129
+ if (!disposed) {
130
+ logBuffer.push(line);
131
+ }
132
+ const observedPid = getObservedPid(line, bundleId);
133
+ if (observedPid !== undefined) {
134
+ if (state.status === 'running') {
135
+ setRunning(observedPid);
136
+ }
137
+ else {
138
+ setExitedPid(observedPid);
139
+ }
140
+ }
141
+ if (state.status === 'running' && isCrashSignal(line, bundleId)) {
142
+ setExited('observed-exit', observedPid);
143
+ }
144
+ }
145
+ }
146
+ catch (error) {
147
+ if (!disposed) {
148
+ androidAppSessionLogger.debug('Android logcat stream stopped', error);
149
+ }
150
+ }
151
+ })();
152
+ try {
153
+ await startApp();
154
+ }
155
+ catch (error) {
156
+ disposed = true;
157
+ stopPolling = true;
158
+ emitter.clear();
159
+ await stopSubprocess(logcatProcess);
160
+ await Promise.allSettled([logTask]);
161
+ throw error;
162
+ }
163
+ const pollTask = (async () => {
164
+ await sleep(0);
165
+ while (!stopPolling) {
166
+ if (isExitedState(state)) {
167
+ return;
168
+ }
169
+ try {
170
+ const pid = await getAppPid();
171
+ if (pid != null) {
172
+ setRunning(pid);
173
+ }
174
+ else if (hasObservedProcess) {
175
+ setExited('process-gone');
176
+ return;
177
+ }
178
+ }
179
+ catch (error) {
180
+ androidAppSessionLogger.debug('Android app session poll failed', error);
181
+ }
182
+ await waitForNextPoll();
183
+ }
184
+ })();
185
+ return {
186
+ dispose: async () => {
187
+ if (disposed) {
188
+ return;
189
+ }
190
+ disposed = true;
191
+ stopPolling = true;
192
+ state = { status: 'disposed', occurredAt: Date.now() };
193
+ if (exitNotification) {
194
+ clearTimeout(exitNotification);
195
+ exitNotification = null;
196
+ }
197
+ cancelPendingPollDelay();
198
+ emitter.clear();
199
+ await stopSubprocess(logcatProcess);
200
+ await stopApp();
201
+ await Promise.allSettled([logTask, pollTask]);
202
+ },
203
+ getState: async () => state,
204
+ getLogs: () => logBuffer.getLogs(),
205
+ getCrashDetails: crashReporter.getCrashDetails,
206
+ addListener: emitter.addListener,
207
+ removeListener: emitter.removeListener,
208
+ };
209
+ };
@@ -0,0 +1,40 @@
1
+ import type { AppCrashDetails, CrashArtifactWriter, CrashDetailsLookupOptions, CrashEnrichmentArtifact } from '@react-native-harness/platforms';
2
+ export declare const DROPBOX_CRASH_TAGS: readonly ["data_app_crash", "data_app_native_crash"];
3
+ export type DropboxEntry = {
4
+ tag: string;
5
+ timestamp: string;
6
+ content: string;
7
+ pid?: number;
8
+ processName?: string;
9
+ };
10
+ export type DropboxCrashArtifact = AppCrashDetails & {
11
+ artifactType: 'dropbox-crash' | 'dropbox-native-crash';
12
+ dropboxTag: string;
13
+ occurredAt: number;
14
+ score?: number;
15
+ };
16
+ type CollectDropboxArtifactsOptions = {
17
+ bundleId: string;
18
+ crashArtifactWriter?: CrashArtifactWriter;
19
+ getDropboxOutput: () => Promise<string>;
20
+ minOccurredAt?: number;
21
+ };
22
+ type WaitForDropboxArtifactsOptions = CollectDropboxArtifactsOptions & CrashDetailsLookupOptions;
23
+ export declare const parseDropboxOutput: (output: string) => DropboxEntry[];
24
+ export declare const collectDropboxArtifacts: ({ bundleId, crashArtifactWriter, getDropboxOutput, minOccurredAt, ...lookup }: WaitForDropboxArtifactsOptions) => Promise<DropboxCrashArtifact[]>;
25
+ export declare const waitForDropboxArtifacts: (options: WaitForDropboxArtifactsOptions) => Promise<DropboxCrashArtifact[]>;
26
+ export declare const filterExitInfo: ({ output, bundleId, pid, }: {
27
+ output: string;
28
+ bundleId: string;
29
+ pid?: number;
30
+ }) => string | null;
31
+ export declare const collectExitInfoArtifact: ({ bundleId, crashArtifactWriter, getExitInfo, pid, testFilePath, }: {
32
+ bundleId: string;
33
+ crashArtifactWriter?: CrashArtifactWriter;
34
+ getExitInfo: () => Promise<string>;
35
+ pid?: number;
36
+ testFilePath?: string;
37
+ }) => Promise<CrashEnrichmentArtifact | null>;
38
+ export declare const getBestDropboxArtifact: (artifacts: DropboxCrashArtifact[]) => DropboxCrashArtifact | null;
39
+ export {};
40
+ //# sourceMappingURL=crash-diagnostics.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"crash-diagnostics.d.ts","sourceRoot":"","sources":["../src/crash-diagnostics.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,eAAe,EACf,mBAAmB,EACnB,yBAAyB,EACzB,uBAAuB,EACxB,MAAM,iCAAiC,CAAC;AAWzC,eAAO,MAAM,kBAAkB,sDAGrB,CAAC;AAEX,MAAM,MAAM,YAAY,GAAG;IACzB,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG,eAAe,GAAG;IACnD,YAAY,EAAE,eAAe,GAAG,sBAAsB,CAAC;IACvD,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,KAAK,8BAA8B,GAAG;IACpC,QAAQ,EAAE,MAAM,CAAC;IACjB,mBAAmB,CAAC,EAAE,mBAAmB,CAAC;IAC1C,gBAAgB,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;IACxC,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB,CAAC;AAEF,KAAK,8BAA8B,GAAG,8BAA8B,GAClE,yBAAyB,CAAC;AA2D5B,eAAO,MAAM,kBAAkB,GAAI,QAAQ,MAAM,KAAG,YAAY,EAgD/D,CAAC;AAkKF,eAAO,MAAM,uBAAuB,GAAU,+EAM3C,8BAA8B,KAAG,OAAO,CAAC,oBAAoB,EAAE,CA6BjE,CAAC;AAEF,eAAO,MAAM,uBAAuB,GAClC,SAAS,8BAA8B,KACtC,OAAO,CAAC,oBAAoB,EAAE,CAqBhC,CAAC;AAEF,eAAO,MAAM,cAAc,GAAI,4BAI5B;IACD,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,CAAC,EAAE,MAAM,CAAC;CACd,KAAG,MAAM,GAAG,IAgCZ,CAAC;AAEF,eAAO,MAAM,uBAAuB,GAAU,oEAM3C;IACD,QAAQ,EAAE,MAAM,CAAC;IACjB,mBAAmB,CAAC,EAAE,mBAAmB,CAAC;IAC1C,WAAW,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;IACnC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,KAAG,OAAO,CAAC,uBAAuB,GAAG,IAAI,CAmCzC,CAAC;AAEF,eAAO,MAAM,sBAAsB,GACjC,WAAW,oBAAoB,EAAE,KAChC,oBAAoB,GAAG,IAEpB,CAAC"}