Display stack baseline (iPhone Duo simulator)

Simulator duo-baseline-display (28D2B766-…), iPhone19,4, iOS 27.1 24A94425, Xcode 27.1. Data: display.json (46085 records, 21 captures), transcripts in raw/display/states/<capture>-{backboardd,springboard,safari}.txt, posture-driver output in raw/display/posture/ (screenshots downscaled to 480 px).

How it was collected

  • probes/display-backboardd.lldb, probes/display-springboard.lldb, probes/display-safari.lldb are generated by src/display/gen-probe.zsh from src/display/src/{helpers.lldbfrag,*.body,footer.lldbfrag}.
  • Getters are enumerated, not listed by hand. For each object, the probe takes every declared property getter plus every zero-argument, non-void method of the class and its superclasses below NSObject (class_copyPropertyList, class_copyMethodList). It then drops names with side effects: set*, add*, remove*, invalidate*, _lock_*, _queue_*, _workQueue_*, copy*, create*, start*/stop*, focus and drag lazy getters, and others. The full lists are in helpers.lldbfrag. The probe calls each getter through a typed objc_msgSend cast chosen from the method's return type encoding. A getter that returns a block, a pointer, a union or an unknown struct gets a record with an error and is never called. UITraitCollection is the exception: 32 display-relevant getters are named in the probe, because third-party categories add hundreds more.
  • lldb expressions here cannot use @try. A getter that raises an exception aborts the whole expression, so src/display/iterate.zsh traced the last getter called to a file and added it to a skip list. Only one getter raised: -[CAWindowServerDisplay secureIndicatorsEnabled]. It is recorded with the error "raises an Objective-C exception in this process (not called)".
  • Each capture: posture.zsh (swap or status), then the backboardd probe, then the SpringBoard probe (plus MobileSafari for 08-13). src/display/capture.zsh, orient-cycle.zsh, merge.zsh.

Captures

capturepostureorientationforeground
01-bootclosed(boot)portraithome
02-open-after-closedopen(after-closed), the first unfoldportraithome
03-closed-after-openclosed(after-open)portraithome
04-book-after-closedbook(after-closed)portraithome
05-open-after-bookopen(after-book)portraithome
06-book-after-openbook(after-open), POSTURE_ANCHOR=noneportraithome
07-closed-after-bookclosed(after-book)portraithome
08-closed-{P,LL,LR}closed(after-closed)portrait / landscapeLeft / landscapeRightSafari
09-book-{P,LL,LR}book(after-closed)〃Safari
10-open-Popen(after-book)portraitSafari
11-rebootclosed(boot2): shutdown and boot againportraithome
12-open-{P,LL,LR}P: open(after-closed); LL, LR: open(after-open)〃Safari
13-book-{P,LL,LR}book(after-closed)〃Safari

Every posture verified (posture.zsh exit 0: closed → cover lit, book/open → inner lit).

Orientation: what took, and how

  • iPhone SpringBoard on the cover is portrait-only, so the home screen gives no orientation data. Captures 08-13 put MobileSafari in front.
  • The swap tool's -deviceOrientation=<o> option is what rotates apps. It drives SpringBoard's pose. It does not change backboardd's BKOrientationManager.currentRawDeviceOrientation, which stays 0 after boot.
  • BKSHIDServicesSetDeviceOrientationForAutomation (BackBoardServices, called in SpringBoard) changes BK's raw orientation and SpringBoard's UIDevice orientation. While the swap tool's pose orientation was landscape, it did not rotate the app back. Captures made that way were discarded (raw/display/states/discarded/). It was last called with 1, so captures 08-10 show raw orientation 1; after the reboot it is 0 again.
  • Mapping that was observed (Safari = the app's own UIDevice and scene orientation):
swap optioncover: Safari dev/io, scene boundsinner: Safari dev/io, scene bounds
portrait1/1, 466×6781/4, 951×669
landscapeLeft4/4, 678×4663/1, 669×951
landscapeRight3/3, 678×4664/2, 669×951

On the inner display the interface orientation is a quarter turn from the device orientation: holding the device in portrait gives landscape UI on the inner panel. The orientation field in the records is the swap option name.

Cover vs inner: where they differ in kind

All values are from 02-open-after-closed unless a capture is named. Both displays are always present and always connected. Only the power state and the lit panel follow the posture.

coverinner
CADisplay name / deviceNameLCD / primaryLCD-1 / primary-1
CADisplay displayId13 (2 is TVOut/external-0, 4 Wireless, 5 Resizable)
[CADisplay mainDisplay]this one (index 0)—
CADisplay tag (also CAWindowServerDisplay tag, FBS tags)065536
CADisplay bounds / nativeSize / mode1398×2034, internal_panel (fixed), single mode2007×2853, internal_panel (fixed), single mode
CADisplay nativeOrientationrot0rot0
CADisplay currentOrientationrot0 (rot90 / rot270 with the app in LL / LR)rot90 at io 4; rot0 at io 1; rot180 at io 2
CADisplay pointScale, refreshRate3, 1/603, 1/60
CADisplay physicalSize (in)3.0391×4.42174.3630×6.2022
CADisplay pixelsPerInch316.165 × 669.270323.596 × 653.901
CADisplay displayType / isExternal / transportType0 / NO / othersame
CADisplay seed (02)35 (rises with every rotation)
mode colorGamut / bitDepthgamut_P3 / 8same
CAWindowServerDisplay orientationportrait (landscapeLeft / landscapeRight when the cover app rotates)landscapeLeft (portrait at io 1, portraitUpsideDown at io 2)
CAWindowServerDisplay extendedPropertiesDisplayRotation 0, DeviceSurfaceType 1, kMGQDeviceSurfaceType 1, ChromeIdentifier com.apple.dt.devicekit.chrome.phone15, DeviceCornerRadius [8,8,59,59], DisplayScale 3DisplayRotation 270, DeviceSurfaceType 2, kMGQDeviceSurfaceType 2, ChromeIdentifier …chrome.phone14, DeviceCornerRadius [55,55,55,55], DisplayScale 3
CAWindowServerDisplay panelPhysicalSize3.0391×4.42174.3630×6.2022
CAWindowServerDisplay scale / scales / touchScales1 / 1×1 / 1×1same
CAWindowServerDisplay flipBook enabled/active/suppressedNO/NO/NONO/NO/NO
BKSDisplayService traitsForDisplayUUID:surfaceType: 1surfaceType: 2
BKDisplayController geometryForDisplayUUID:{1398×2034, 3, 0, {0,0,1,1}}{2007×2853, 3, 0, {0,0,1,1}}
BK digitizer (BKHIDDirectTouchEventProcessor)CoreDevice touchscreen(<cover UUID>), builtIn, authenticated; this is mainDisplayDigitizerServiceCoreDevice touchscreen(<inner UUID>), builtIn, authenticated
UIScreen index in [UIScreen screens]0, == mainScreen in every capture1
UIScreen _name / displayIdentityLCD / MainLCD-1 / Unknown.main[3]
UIScreen bounds466×678 (678×466 after the cover app was landscape; see History)669×951 at boot, then 951×669 (io 4) or 669×951 (io 1/2)
UIScreen nativeBounds / _nativeDisplayBounds / _unjailedReferenceBoundsInPixels1398×20342007×2853
UIScreen scale / nativeScale / maximumFramesPerSecond3 / 3 / 603 / 3 / 60
UIScreen _isMainScreen / _isEmbeddedScreen / _isMainLikeScreenYES / YES / YESNO / YES / YES
UIScreen _integerDisplayID / _displayID1 / cover UUID3 / inner UUID
UIScreen sbh_screenType / _screenType31 / -132 / -1
UIScreen _displayCornerRadius5959
UIScreen _peripheryInsetst/b 50.667 (l/r when io 3/4)l/r 50.667 at io 4; t/b at io 1/2 and at boot
UIScreen _displayPeripheryInsets / _bn_portraitPeripheryInsetstop 50.667 / t/b 50.667same as the cover
UIScreen _exclusionAreasingle rect {399, 30, 37, 37}the same rect
UIScreen _displayInfoProvider (UISDisplayContext)safeAreaInsets bottom 34 in all four orientations, peripheryInsets top 50.667identical to the cover's
UIScreen _pointsPerInch / _nativePointsPerMillimeter153.333 / 6.0367same
UIScreen traitCollection horizontal/vertical size classcompact/regular (1/2)0/0 at boot, regular/regular (2/2) after the first unfold
FBSDisplayConfiguration _nameForDisplayType / typeMain / 0Unknown / 7
FBSDisplayIdentity displayID / type / isMainDisplay / isMainRootDisplay / isRootIdentity / isUIKitMainLike / isAlwaysConnected1 / 0 / YES / YES / YES / YES / YES3 / 7 / NO / NO / YES / YES / YES
FBSDisplayIdentity connectionType / connectionSeed / pid / uniqueIdentifier0 / 0 / 0 / nilsame
FBSDisplayConfiguration hardwareIdentifiercover CADisplay uniqueIdinner CADisplay uniqueId
FBSDisplayConfiguration bounds / pixelSize / pointScale466×678 / 1398×2034 / 3669×951 / 2007×2853 / 3 (never rotates)
FBSDisplayMode466x678@3x (1398x2034/3) 60Hz p3 SDR, _rotation 0669x951@3x (2007x2853/3) 60Hz p3 SDR, _rotation 0
FBSDisplayConfiguration nativeOrientation / _nativeRotation0 / 00 / 0
FBSDisplayConfiguration renderingCenter / nativeCenter{699, 1017}{1003.5, 1426.5}
FBS/UIScreen sbui_systemArbitratedInterfaceOrientation14
FBSDisplayIdentity sb_displayWindowingMode11
FBS colorGamut / refreshRate / overscanCompensation / safeOverscanRatio1 / 60 / 0 / 0.9same
[FBDisplayManager mainIdentity]Main—
SpringBoard sceneSB-maincom.apple.springboard.bringup

For the VM's two-display path, these are the identities the inner display must reproduce:

  • FBS identity Unknown.main[3]: type 7, displayID 3, not main, its own root identity, UIKit-main-like, always connected.
  • CA LCD-1 / primary-1 with tag 65536 (0x10000).
  • extendedProperties with DisplayRotation 270 and DeviceSurfaceType 2.
  • BKS surfaceType 2.

The cover is Main, displayId 1, tag 0, surface type 1, and it is always mainScreen and mainDisplay.

Posture-dependent values (home screen, portrait)

closedbook / open
cover CADisplayStateControl displayState / targetDisplayState / powerState1 / 1 / 1 (displayState: on)0 / 0 / 1 (off, power stays on)
inner CADisplayStateControl displayState01
CAWindowServerDisplay enabled / isBlankedcover YES/NO, inner NO/YEScover NO/YES, inner YES/NO
BKDisplayController displayIsBlanked:cover NO, inner YEScover YES, inner NO
SB-main / bringup displayContentMode2 primary / 1 disabled3 auxiliary / 2 primary
BK touch-stream clientsSpringBoard system-gestures on the cover onlySpringBoard system-gestures client on the inner (the inner aggregate is empty again when closed)

Book and open are identical in every display-stack value (02 vs 04, 05 vs 06). CADisplay seed, bounds, modes and identities do not change with the posture.

History-dependent values

  1. The inner UIScreen before and after the first unfold. At boot (01, and again 11 after a reboot):

    • bounds 669×951 and _interfaceOrientation 0 (orientation: unknown (0))
    • _peripheryInsets t/b
    • traitCollection without size classes (0/0)

    From the first unfold on, in every posture including closed (02-07):

    • bounds 951×669 and _interfaceOrientation 4
    • _peripheryInsets l/r
    • horizontal/vertical size class Regular (2/2)

    Closed after open (03, 07) keeps the post-unfold values. The FBS current configuration seed goes 3 → 5 at the first unfold. The inner CAWindowServerDisplay is landscapeLeft, the CADisplay rot90, and BK holds orientation 4 for the inner UUID, already at boot.

  2. The cover UIScreen keeps the last orientation the cover had.

    • After 08-closed-LL/LR it stays 678×466 with _interfaceOrientation 4/3 while the inner is in use (09-book-LL/LR, 13-book-LL/LR). The book anchor swap to closed inherits the current device orientation, so the cover rotates first.
    • 12-open-LL/LR (no anchor) keeps the cover at 466×678.
  3. The SpringBoard inner primary scene orientation with device portrait.

    • It is 1 when the swap unfolded from closed: 09-book-P, 12-open-P, and 02/04 on the home screen.
    • It is 4 when the swap started on the inner: 10-open-P, 13-book-P.
    • Safari is at io 4 in both cases, and UIApplication.activeInterfaceOrientation is 4.
  4. Display UUIDs change on every boot. CADisplay uniqueId/UUID, FBS hardwareIdentifier, CAWindowServerDisplay systemIdentifiers and FramebufferIdentifier all change. Compare by name, displayId and identity, never by UUID.

Repeatability: closed 03 vs 07, open 02 vs 05 and book 04 vs 06 match except for the volatile fields (touch-stream creation times).

Digitizer → display mapping (backboardd)

From _queue_perDisplayInfo and _queue_displayUUIDForDigitizerService::

displayserviceflags
cover (LCD)CoreDevice touchscreen(<cover UUID>), senderID …03builtIn, authenticated, transport CoreDevice, mainDisplayDigitizerService
inner (LCD-1)CoreDevice touchscreen(<inner UUID>), senderID …04builtIn, authenticated
ResizableCoreDevice touchscreen(<Resizable UUID>) …05 and an accessory 0xACEFADE… (eventSource 2, displayIntegrated, not authenticated)

Each BKDirectTouchState._interfaceOrientation follows its display's BK orientation: the cover 1, the inner 4 (1 or 2 when the inner app is rotated). There is no AOP or pencil digitizer, and no chamois display.

Incident: at 14:45:36 every CoreDevice HID service disappeared from backboardd ("*** lost main display digitizer **", IOHIDEventSystem connections removed). The host side caused it; this sim did nothing at that moment. It left 10-open-LL/LR without digitizers. Those two captures were discarded, the sim was rebooted, and the open orientations were redone as 12-open-.

Other values (both displays unless stated)

  • [CAWindowServer serverIfRunning]: 5 displays (LCD 1398×2034, TVOut 0×0, LCD-1 2007×2853, Wireless 0×0, Resizable 0×0), rendererFlags 3, not secure, mirroring off, lss_extendedDisplays empty, _lss_primaryDisplay LCD.
  • BKDisplayRenderOverlayManager: one active overlay, BKDisplayRenderOverlaySpinny (gear, level -1, background) on the cover, in every capture. lockedOrientation 0, backlightLocked NO.
  • BKDisplayBrightnessController: brightnessLevel 0.5, curve 1, ALS / auto brightness / level control unavailable. UIScreen.brightness 0.5. No per-display brightness getter exists.
  • UISDisplayContext defaultContext: the cover (Main) configuration; displayEdgeInfo and exclusionArea are nil.

Missing, nil and errored

  • nil on both panels:
    • CADisplay: productName, containerId, externalDisplayAttributes, allowed/preferred/supportedHDRModes, availablePresets, currentPreset, _copyDebugProperties (NULL)
    • CADisplayStateControl: _copyAll{Power,FrameRate}AssertionInfo
    • CAWindowServerDisplay: brightnessCapabilities, virtualDisplayMode, averagePixelConstraints, TVMode, cloneMaster, cursorDictionary
    • CAWindowServer: displayExternalSyncManager
    • FBS: FBSDisplayIdentity.uniqueIdentifier, FBSDisplayConfiguration.uniqueIdentifier, originatingConfiguration
    • UIScreen: mirroredScreen, _overrideTraitCollection, __eventDisplay, _initialDisplayContext, _previousHardwareIdentifier, focusGroupIdentifier
    • +[UIScreen _carScreen], UITraitCollection._systemDisplayIdentifier, UISDisplayContext.displayEdgeInfo / exclusionArea
    • BK: mainDisplayAOP/PencilDigitizerService, chamoisDisplayUUID, _frozenDisplayIDs
  • Not called (type):
    • CADisplay.timingsControl (^v)
    • CAWindowServerDisplay blend/displayColorSpace (^{CGColorSpace}), detachingDisplay, systemGamma and blackpointAdaptation (CGColorTRC union), the six callback blocks
    • UIScreen _fallbackTraitCollection (^v)
  • Raises: CAWindowServerDisplay.secureIndicatorsEnabled.
  • Declared but not implemented: UIScreen _isEligibleForFocusInteraction, _isEligibleForFocusOcclusion, _linearFocusMovementSequences, _preferredFocusMovementStyle, traitOverrides (protocol properties).
  • Absent APIs:
    • CAWindowServerDisplay has no contextIds getter. The probe records contextIdAtPosition: at the panel centre instead; it is volatile.
    • There is no CADisplay.maximumFramesPerSecond, colorGamut or overscan getter. The equivalents are refreshRate, currentMode.colorGamut and overscanAmount / overscanAdjustment.
    • extendedProperties exists only on CAWindowServerDisplay, not on FBS.
    • _UIScreenDisplayConfiguration does not exist; it is UIScreen.displayConfiguration / fbsDisplay.
    • SpringBoard._accessibilityFrontMostApplication (a probe convenience) is not available.

Volatile fields (ignore when comparing)

  • CAWindowServerDisplay nextWakeupTime, previousVBL, vblDelta and contextIdAtPosition
  • pointer addresses inside descriptions
  • touch-stream client creationTime
  • brightness freeze times
  • seeds: CADisplay seed and FBS config seed rise with rotations and swaps