@appium/coresim 1.13.0 → 1.13.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 +7 -0
- package/README.md +1 -0
- package/lib/src/commands/permissions.d.ts.map +1 -1
- package/lib/src/commands/permissions.js +12 -246
- package/lib/src/commands/permissions.js.map +1 -1
- package/lib/src/index.d.ts +1 -1
- package/lib/src/index.d.ts.map +1 -1
- package/lib/src/index.js.map +1 -1
- package/lib/src/native-simctl.d.ts +27 -9
- package/lib/src/native-simctl.d.ts.map +1 -1
- package/lib/src/native-simctl.js +9 -16
- package/lib/src/native-simctl.js.map +1 -1
- package/lib/src/utils/bulletin-board-model-v2.d.ts +10 -0
- package/lib/src/utils/bulletin-board-model-v2.d.ts.map +1 -0
- package/lib/src/utils/bulletin-board-model-v2.js +73 -0
- package/lib/src/utils/bulletin-board-model-v2.js.map +1 -0
- package/lib/src/utils/bulletin-board-model-v3.d.ts +4 -0
- package/lib/src/utils/bulletin-board-model-v3.d.ts.map +1 -0
- package/lib/src/utils/bulletin-board-model-v3.js +16 -0
- package/lib/src/utils/bulletin-board-model-v3.js.map +1 -0
- package/lib/src/utils/bulletin-board-model.d.ts +19 -0
- package/lib/src/utils/bulletin-board-model.d.ts.map +1 -0
- package/lib/src/utils/bulletin-board-model.js +2 -0
- package/lib/src/utils/bulletin-board-model.js.map +1 -0
- package/lib/src/utils/bulletin-board-store.d.ts +41 -0
- package/lib/src/utils/bulletin-board-store.d.ts.map +1 -0
- package/lib/src/utils/bulletin-board-store.js +114 -0
- package/lib/src/utils/bulletin-board-store.js.map +1 -0
- package/lib/src/utils/index.d.ts +3 -0
- package/lib/src/utils/index.d.ts.map +1 -1
- package/lib/src/utils/index.js +2 -0
- package/lib/src/utils/index.js.map +1 -1
- package/lib/src/utils/springboard.d.ts +26 -0
- package/lib/src/utils/springboard.d.ts.map +1 -0
- package/lib/src/utils/springboard.js +106 -0
- package/lib/src/utils/springboard.js.map +1 -0
- package/package.json +3 -2
- package/prebuilds/darwin-arm64/@appium+coresim.node +0 -0
- package/src/commands/permissions.ts +13 -263
- package/src/index.ts +1 -1
- package/src/native-simctl.ts +45 -19
- package/src/utils/bulletin-board-model-v2.ts +79 -0
- package/src/utils/bulletin-board-model-v3.ts +16 -0
- package/src/utils/bulletin-board-model.ts +20 -0
- package/src/utils/bulletin-board-store.ts +126 -0
- package/src/utils/index.ts +3 -0
- package/src/utils/springboard.ts +119 -0
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import {once} from 'node:events';
|
|
2
|
+
|
|
3
|
+
import {waitForCondition} from 'asyncbox';
|
|
4
|
+
|
|
5
|
+
import type {NativeSimctl} from '../native-simctl.js';
|
|
6
|
+
|
|
7
|
+
const SPRINGBOARD_SERVICE = 'com.apple.SpringBoard';
|
|
8
|
+
const SPRINGBOARD_RESTART_TIMEOUT_MS = 30000;
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* SpringBoard of a booted device: the process that owns the BulletinBoard store, see
|
|
12
|
+
* setNotificationsAccess. The simulator shares the host kernel, so it is signalled directly.
|
|
13
|
+
*/
|
|
14
|
+
export class SpringBoard {
|
|
15
|
+
private pausedPid: number | undefined;
|
|
16
|
+
|
|
17
|
+
constructor(
|
|
18
|
+
private readonly simctl: NativeSimctl,
|
|
19
|
+
private readonly udid: string,
|
|
20
|
+
) {}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Pauses the running SpringBoard so that it cannot rewrite the BulletinBoard store. It can be in
|
|
24
|
+
* the middle of a restart, hence the retries.
|
|
25
|
+
*/
|
|
26
|
+
async pause(): Promise<void> {
|
|
27
|
+
try {
|
|
28
|
+
await waitForCondition(
|
|
29
|
+
async () => {
|
|
30
|
+
const pid = await this.pid().catch(() => undefined);
|
|
31
|
+
if (pid && sendSignal(pid, 'SIGSTOP')) {
|
|
32
|
+
this.pausedPid = pid;
|
|
33
|
+
}
|
|
34
|
+
return Boolean(this.pausedPid);
|
|
35
|
+
},
|
|
36
|
+
{waitMs: SPRINGBOARD_RESTART_TIMEOUT_MS, intervalMs: 300},
|
|
37
|
+
);
|
|
38
|
+
} catch {}
|
|
39
|
+
if (!this.pausedPid) {
|
|
40
|
+
throw new Error(`${SPRINGBOARD_SERVICE} is not running`);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/** Lets the paused SpringBoard run again. */
|
|
45
|
+
resume(): void {
|
|
46
|
+
if (this.pausedPid) {
|
|
47
|
+
sendSignal(this.pausedPid, 'SIGCONT');
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Replaces the paused SpringBoard with a new one: asks launchd to stop it (launchd starts a new
|
|
53
|
+
* one right away), resumes it so that it can exit, then waits for the new process.
|
|
54
|
+
*/
|
|
55
|
+
async restart(): Promise<void> {
|
|
56
|
+
const previousPid = this.pausedPid;
|
|
57
|
+
try {
|
|
58
|
+
await this.stop();
|
|
59
|
+
} finally {
|
|
60
|
+
this.resume();
|
|
61
|
+
this.pausedPid = undefined;
|
|
62
|
+
}
|
|
63
|
+
try {
|
|
64
|
+
await waitForCondition(
|
|
65
|
+
async () => {
|
|
66
|
+
const pid = await this.pid().catch(() => undefined);
|
|
67
|
+
return Number.isInteger(pid) && pid !== previousPid;
|
|
68
|
+
},
|
|
69
|
+
{waitMs: SPRINGBOARD_RESTART_TIMEOUT_MS, intervalMs: 300},
|
|
70
|
+
);
|
|
71
|
+
} catch {
|
|
72
|
+
throw new Error(`${SPRINGBOARD_SERVICE} did not restart within ${SPRINGBOARD_RESTART_TIMEOUT_MS}ms`);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
private async pid(): Promise<number | undefined> {
|
|
77
|
+
return (await this.simctl.listProcesses(this.udid)).find(({name}) => name === SPRINGBOARD_SERVICE)?.pid;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
private async stop(): Promise<void> {
|
|
81
|
+
// Bare name: resolved against the guest runtime's own bin dirs, like in listProcesses.
|
|
82
|
+
const proc = await this.simctl.spawnProcess(this.udid, 'launchctl', {
|
|
83
|
+
arguments: ['launchctl', 'stop', SPRINGBOARD_SERVICE],
|
|
84
|
+
});
|
|
85
|
+
let stderr = '';
|
|
86
|
+
proc.stdout.resume();
|
|
87
|
+
proc.stderr.on('data', (chunk: Buffer) => {
|
|
88
|
+
stderr += chunk;
|
|
89
|
+
});
|
|
90
|
+
const streamError = Promise.race([once(proc.stdout, 'error'), once(proc.stderr, 'error')]).then(([err]) => {
|
|
91
|
+
throw err;
|
|
92
|
+
});
|
|
93
|
+
const [[code, signal]] = await Promise.race([
|
|
94
|
+
Promise.all([once(proc, 'exit'), once(proc.stderr, 'end')]),
|
|
95
|
+
streamError,
|
|
96
|
+
]);
|
|
97
|
+
if (code !== 0) {
|
|
98
|
+
const reason = signal ? `signal ${signal}` : `exit code ${code}`;
|
|
99
|
+
throw new Error(
|
|
100
|
+
`'launchctl stop ${SPRINGBOARD_SERVICE}' failed with ${reason}${stderr.trim() ? `: ${stderr.trim()}` : ''}`,
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* @returns `false` if the process no longer exists
|
|
108
|
+
*/
|
|
109
|
+
function sendSignal(pid: number, name: NodeJS.Signals): boolean {
|
|
110
|
+
try {
|
|
111
|
+
process.kill(pid, name);
|
|
112
|
+
return true;
|
|
113
|
+
} catch (err: any) {
|
|
114
|
+
if (err?.code === 'ESRCH') {
|
|
115
|
+
return false;
|
|
116
|
+
}
|
|
117
|
+
throw err;
|
|
118
|
+
}
|
|
119
|
+
}
|