Skip to content

Commit 48e091e

Browse files
Merge pull request #217 from compiled-run/ios-sim-fullscreen
iOS simulators boot pinned to Full Screen Apps (iPad capture-trust failures in queues 59 and 60)
2 parents c49d4db + 70307c2 commit 48e091e

3 files changed

Lines changed: 69 additions & 15 deletions

File tree

‎packages/parity/out/lanes.json‎

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -521,7 +521,7 @@
521521
},
522522
"device": null,
523523
"evidence": {
524-
"laneCode": "74eab0d492591082f5e40867ad0d7e659cf197cc24e65c689a30cd6c0b09761f",
524+
"laneCode": "2bc4c5e7a9b98a186f9b690efd35fc9cff64e13e60d385c7e1ff703f4b7d54af",
525525
"referenceData": "d12c446d3fb8fb3af56934e969a4564a089527a7fe0170339a327e56cca33717",
526526
"app": "f38bcea7fbe957087cea5e24e45b211d38655519d1988ba00a7033de95126807"
527527
}
@@ -631,7 +631,7 @@
631631
"trust": null
632632
},
633633
"evidence": {
634-
"laneCode": "74eab0d492591082f5e40867ad0d7e659cf197cc24e65c689a30cd6c0b09761f",
634+
"laneCode": "2bc4c5e7a9b98a186f9b690efd35fc9cff64e13e60d385c7e1ff703f4b7d54af",
635635
"referenceData": "d12c446d3fb8fb3af56934e969a4564a089527a7fe0170339a327e56cca33717",
636636
"app": "f38bcea7fbe957087cea5e24e45b211d38655519d1988ba00a7033de95126807"
637637
}
@@ -741,7 +741,7 @@
741741
"trust": null
742742
},
743743
"evidence": {
744-
"laneCode": "74eab0d492591082f5e40867ad0d7e659cf197cc24e65c689a30cd6c0b09761f",
744+
"laneCode": "2bc4c5e7a9b98a186f9b690efd35fc9cff64e13e60d385c7e1ff703f4b7d54af",
745745
"referenceData": "d12c446d3fb8fb3af56934e969a4564a089527a7fe0170339a327e56cca33717",
746746
"app": "f38bcea7fbe957087cea5e24e45b211d38655519d1988ba00a7033de95126807"
747747
}
@@ -851,7 +851,7 @@
851851
"trust": null
852852
},
853853
"evidence": {
854-
"laneCode": "74eab0d492591082f5e40867ad0d7e659cf197cc24e65c689a30cd6c0b09761f",
854+
"laneCode": "2bc4c5e7a9b98a186f9b690efd35fc9cff64e13e60d385c7e1ff703f4b7d54af",
855855
"referenceData": "d12c446d3fb8fb3af56934e969a4564a089527a7fe0170339a327e56cca33717",
856856
"app": "f38bcea7fbe957087cea5e24e45b211d38655519d1988ba00a7033de95126807"
857857
}
@@ -1143,7 +1143,7 @@
11431143
]
11441144
},
11451145
"evidence": {
1146-
"laneCode": "74eab0d492591082f5e40867ad0d7e659cf197cc24e65c689a30cd6c0b09761f",
1146+
"laneCode": "2bc4c5e7a9b98a186f9b690efd35fc9cff64e13e60d385c7e1ff703f4b7d54af",
11471147
"referenceData": "d12c446d3fb8fb3af56934e969a4564a089527a7fe0170339a327e56cca33717",
11481148
"app": "f38bcea7fbe957087cea5e24e45b211d38655519d1988ba00a7033de95126807"
11491149
}
@@ -1253,7 +1253,7 @@
12531253
"trust": null
12541254
},
12551255
"evidence": {
1256-
"laneCode": "74eab0d492591082f5e40867ad0d7e659cf197cc24e65c689a30cd6c0b09761f",
1256+
"laneCode": "2bc4c5e7a9b98a186f9b690efd35fc9cff64e13e60d385c7e1ff703f4b7d54af",
12571257
"referenceData": "d12c446d3fb8fb3af56934e969a4564a089527a7fe0170339a327e56cca33717",
12581258
"app": "f38bcea7fbe957087cea5e24e45b211d38655519d1988ba00a7033de95126807"
12591259
}
@@ -1363,7 +1363,7 @@
13631363
"trust": null
13641364
},
13651365
"evidence": {
1366-
"laneCode": "74eab0d492591082f5e40867ad0d7e659cf197cc24e65c689a30cd6c0b09761f",
1366+
"laneCode": "2bc4c5e7a9b98a186f9b690efd35fc9cff64e13e60d385c7e1ff703f4b7d54af",
13671367
"referenceData": "d12c446d3fb8fb3af56934e969a4564a089527a7fe0170339a327e56cca33717",
13681368
"app": "f38bcea7fbe957087cea5e24e45b211d38655519d1988ba00a7033de95126807"
13691369
}
@@ -1996,7 +1996,7 @@
19961996
},
19971997
"device": null,
19981998
"evidence": {
1999-
"laneCode": "74eab0d492591082f5e40867ad0d7e659cf197cc24e65c689a30cd6c0b09761f",
1999+
"laneCode": "2bc4c5e7a9b98a186f9b690efd35fc9cff64e13e60d385c7e1ff703f4b7d54af",
20002000
"referenceData": "d12c446d3fb8fb3af56934e969a4564a089527a7fe0170339a327e56cca33717",
20012001
"app": "e92d1144d1ffd2d5cd391c31acb620581a18ebb486a3afcaad0709a666ad3fef"
20022002
}
@@ -2152,7 +2152,7 @@
21522152
"trust": null
21532153
},
21542154
"evidence": {
2155-
"laneCode": "74eab0d492591082f5e40867ad0d7e659cf197cc24e65c689a30cd6c0b09761f",
2155+
"laneCode": "2bc4c5e7a9b98a186f9b690efd35fc9cff64e13e60d385c7e1ff703f4b7d54af",
21562156
"referenceData": "d12c446d3fb8fb3af56934e969a4564a089527a7fe0170339a327e56cca33717",
21572157
"app": "e92d1144d1ffd2d5cd391c31acb620581a18ebb486a3afcaad0709a666ad3fef"
21582158
}
@@ -2308,7 +2308,7 @@
23082308
"trust": null
23092309
},
23102310
"evidence": {
2311-
"laneCode": "74eab0d492591082f5e40867ad0d7e659cf197cc24e65c689a30cd6c0b09761f",
2311+
"laneCode": "2bc4c5e7a9b98a186f9b690efd35fc9cff64e13e60d385c7e1ff703f4b7d54af",
23122312
"referenceData": "d12c446d3fb8fb3af56934e969a4564a089527a7fe0170339a327e56cca33717",
23132313
"app": "e92d1144d1ffd2d5cd391c31acb620581a18ebb486a3afcaad0709a666ad3fef"
23142314
}
@@ -2464,7 +2464,7 @@
24642464
"trust": null
24652465
},
24662466
"evidence": {
2467-
"laneCode": "74eab0d492591082f5e40867ad0d7e659cf197cc24e65c689a30cd6c0b09761f",
2467+
"laneCode": "2bc4c5e7a9b98a186f9b690efd35fc9cff64e13e60d385c7e1ff703f4b7d54af",
24682468
"referenceData": "d12c446d3fb8fb3af56934e969a4564a089527a7fe0170339a327e56cca33717",
24692469
"app": "e92d1144d1ffd2d5cd391c31acb620581a18ebb486a3afcaad0709a666ad3fef"
24702470
}
@@ -2811,7 +2811,7 @@
28112811
]
28122812
},
28132813
"evidence": {
2814-
"laneCode": "74eab0d492591082f5e40867ad0d7e659cf197cc24e65c689a30cd6c0b09761f",
2814+
"laneCode": "2bc4c5e7a9b98a186f9b690efd35fc9cff64e13e60d385c7e1ff703f4b7d54af",
28152815
"referenceData": "d12c446d3fb8fb3af56934e969a4564a089527a7fe0170339a327e56cca33717",
28162816
"app": "e92d1144d1ffd2d5cd391c31acb620581a18ebb486a3afcaad0709a666ad3fef"
28172817
}
@@ -2967,7 +2967,7 @@
29672967
"trust": null
29682968
},
29692969
"evidence": {
2970-
"laneCode": "74eab0d492591082f5e40867ad0d7e659cf197cc24e65c689a30cd6c0b09761f",
2970+
"laneCode": "2bc4c5e7a9b98a186f9b690efd35fc9cff64e13e60d385c7e1ff703f4b7d54af",
29712971
"referenceData": "d12c446d3fb8fb3af56934e969a4564a089527a7fe0170339a327e56cca33717",
29722972
"app": "e92d1144d1ffd2d5cd391c31acb620581a18ebb486a3afcaad0709a666ad3fef"
29732973
}
@@ -3123,7 +3123,7 @@
31233123
"trust": null
31243124
},
31253125
"evidence": {
3126-
"laneCode": "74eab0d492591082f5e40867ad0d7e659cf197cc24e65c689a30cd6c0b09761f",
3126+
"laneCode": "2bc4c5e7a9b98a186f9b690efd35fc9cff64e13e60d385c7e1ff703f4b7d54af",
31273127
"referenceData": "d12c446d3fb8fb3af56934e969a4564a089527a7fe0170339a327e56cca33717",
31283128
"app": "e92d1144d1ffd2d5cd391c31acb620581a18ebb486a3afcaad0709a666ad3fef"
31293129
}

‎packages/parity/src/device-run.ts‎

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -514,6 +514,40 @@ async function bootIosHeld(spec: IosDeviceSpec): Promise<DeviceHandle> {
514514
}
515515
}
516516

517+
/**
518+
* The SpringBoard preferences every simulator is pinned to: Full Screen Apps (no Windowed Apps, no Stage Manager). iPadOS 26 defaults
519+
* to Windowed Apps, where SpringBoard reopens an app at the window size it last kept for the bundle, across reinstalls and reboots:
520+
* one scene rotation on a portrait iPad (requestGeometryUpdate) left every later launch of the host in a scaled window, so the OS
521+
* screenshot of capture trust showed the wallpaper around it. Each key reads 0 once pinned.
522+
*/
523+
export const IOS_SPRINGBOARD_PINS: readonly string[] = ['SBMedusaMultitaskingEnabled', 'SBChamoisWindowingEnabled'];
524+
525+
/** The pinned keys a simulator does not hold yet; read gives a key's `defaults read` output, or null when the key is absent. */
526+
export function springboardPinsToWrite(read: (key: string) => string | null): string[] {
527+
return IOS_SPRINGBOARD_PINS.filter((k) => read(k)?.trim() !== '0');
528+
}
529+
530+
function readSpringboard(udid: string, key: string): string | null {
531+
const r = exec('xcrun', ['simctl', 'spawn', udid, 'defaults', 'read', 'com.apple.springboard', key], { allowFailure: 'an absent key fails the read; it is written below' });
532+
return r.ok ? r.stdout : null;
533+
}
534+
535+
/**
536+
* Pins the multitasking mode (IOS_SPRINGBOARD_PINS). SpringBoard reads it when it starts, so a simulator that did not hold it
537+
* boots once more; the pins persist, so that happens once per simulator. A pin that does not read back fails the boot.
538+
*/
539+
async function pinFullScreenApps(spec: IosDeviceSpec, udid: string): Promise<void> {
540+
const missing = springboardPinsToWrite((k) => readSpringboard(udid, k));
541+
if (missing.length === 0) return;
542+
for (const k of missing) exec('xcrun', ['simctl', 'spawn', udid, 'defaults', 'write', 'com.apple.springboard', k, '-bool', 'NO']);
543+
exec('xcrun', ['simctl', 'shutdown', udid]);
544+
exec('xcrun', ['simctl', 'boot', udid]);
545+
const b = await execAsync('xcrun', ['simctl', 'bootstatus', udid, '-b'], { timeoutMs: 300_000, allowFailure: 'a failed reboot fails naming this output' });
546+
if (!b.ok) throw new Error(`the ${spec.name} simulator did not boot again after its multitasking mode was pinned (tooling fault): ${b.out.slice(-500)}`);
547+
const still = springboardPinsToWrite((k) => readSpringboard(udid, k));
548+
if (still.length > 0) throw new Error(`the ${spec.name} simulator does not hold the SpringBoard pins ${still.join(', ')} after writing them (tooling fault)`);
549+
}
550+
517551
async function bootIosFrom(spec: IosDeviceSpec, udid: string, was: string): Promise<DeviceHandle> {
518552
for (let attempt = 1; ; attempt++) {
519553
if (was === 'Shutdown') noteStartedSim(udid, spec.name);
@@ -526,6 +560,7 @@ async function bootIosFrom(spec: IosDeviceSpec, udid: string, was: string): Prom
526560
const stopped = await stopDevice({ spec, udid, startedHere: true });
527561
if (stopped !== null) throw new Error(`the ${spec.name} simulator failed to boot, and before the retry ${stopped} (tooling fault): ${b.out.slice(-500)}`);
528562
}
563+
await pinFullScreenApps(spec, udid);
529564
exec('xcrun', ['simctl', 'ui', udid, 'content_size', 'large']);
530565
return { spec, udid, startedHere: was === 'Shutdown' };
531566
}

‎packages/parity/test/device-run.test.ts‎

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import { repoPath } from '../src/paths.ts';
1010
import { trustCoverageProblems } from '../src/lanes.ts';
1111
import type { AvdDeviceSpec, DeviceRecord, DeviceSpec, GoldenParts } from '../src/device-run.ts';
1212
import type { SettleState } from '../src/device-run.ts';
13-
import { ANDROID_RENDERER, avdDir, dropGolden, deviceRecord, dropSuspect, emulatorArgs, failedAttemptStep, GOLDEN_SNAPSHOT, goldenEnabled, GUEST_TIMEZONE, snapshotLoadFailed, goldenCurrent, goldenKey, goldenKeyFile } from '../src/device-run.ts';
13+
import { ANDROID_RENDERER, avdDir, dropGolden, deviceRecord, dropSuspect, emulatorArgs, failedAttemptStep, GOLDEN_SNAPSHOT, goldenEnabled, GUEST_TIMEZONE, IOS_SPRINGBOARD_PINS, snapshotLoadFailed, goldenCurrent, goldenKey, goldenKeyFile, springboardPinsToWrite } from '../src/device-run.ts';
1414
import { ANDROID_IMAGE_API, avdKeys, parseWindowFocus, SETTLE_SAMPLES, SETTLE_START, settleStep, settleTimeoutMessage, avdScale, DEVICE_MATRIX, isGlyphPlant, isLinePlant, isPaintPlant, judgeGlyphPlant, judgeLinePlant, LINE_PLANT_CASE, liveProblems, matrixProblems, parseAppRecord, spawnDetached, PLANT_AXIS, PLANT_CASES, PLANT_DEVICES, PLANT_RULES, PLANT_MARGIN_DEVICE_PX, PLANT_SHIFT_DEVICE_PX, PLANT_SHIFT_SPREAD_DEVICE_PX, recordProblems, TEXT_SCALE, TRUST_CASES, VECTOR_DEVICES } from '../src/device-run.ts';
1515
import { emitNativeSupport, SUPPORT_PLANTS } from 'dragon';
1616
import { paintPlants } from '../../dragon/src/emit/paint/registry.ts';
@@ -386,3 +386,22 @@ describe('the golden snapshot (Android quickboot)', () => {
386386
expect(src).toMatch(/provision: \[prepareAvd, waitForSettledFocus, saveGolden, saveGoldenAndSettle,/);
387387
});
388388
});
389+
390+
describe('the simulators run in Full Screen Apps (iPadOS 26 Windowed Apps kept the host in a scaled window)', () => {
391+
it('writes every pin a simulator does not hold as 0', () => {
392+
expect(IOS_SPRINGBOARD_PINS).toEqual(['SBMedusaMultitaskingEnabled', 'SBChamoisWindowingEnabled']);
393+
expect(springboardPinsToWrite(() => null)).toEqual([...IOS_SPRINGBOARD_PINS]);
394+
expect(springboardPinsToWrite(() => '0\n')).toEqual([]);
395+
expect(springboardPinsToWrite((k) => (k === 'SBChamoisWindowingEnabled' ? '1\n' : '0\n'))).toEqual(['SBChamoisWindowingEnabled']);
396+
expect(springboardPinsToWrite(() => '')).toEqual([...IOS_SPRINGBOARD_PINS]);
397+
});
398+
399+
it('pins the mode on every iOS boot, rebooting once and reading the pins back, before the app is installed', () => {
400+
const src = readFileSync(repoPath('packages/parity/src/device-run.ts'), 'utf8');
401+
expect(src).toMatch(/ {2}await pinFullScreenApps\(spec, udid\);\n {2}exec\('xcrun', \['simctl', 'ui', udid, 'content_size', 'large'\]\);/);
402+
const pin = src.slice(src.indexOf('async function pinFullScreenApps'), src.indexOf('async function bootIosFrom'));
403+
expect(pin).toMatch(/'defaults', 'write', 'com\.apple\.springboard', k, '-bool', 'NO'/);
404+
expect(pin.indexOf("'shutdown'")).toBeLessThan(pin.indexOf("'boot', udid"));
405+
expect(pin).toContain('const still = springboardPinsToWrite(');
406+
});
407+
});

0 commit comments

Comments
 (0)