How macOS 26 Tahoe updates: 2 Finite state machines

Script-based updaters were underpowered and too unreliable to build the Signed System Volume and other components of macOS in Big Sur and beyond. When Apple was designing the software update subsystem to be used for its new Macs, it chose to develop a modern design from scratch, built around finite state machines. The end result is seen today in the log entries made when updating macOS.

At first sight those appear to be examples of everything the Unified log shouldn’t be. From the initial entries reporting the softwareupdated service is checking for updates, there’s a succession of huge and apparently incomprehensible entries in the log that surely belong somewhere else. In fact we’re given a remarkable step-by-step account of some of the most elegant and successful engineering design in macOS that reveals its inner workings. It also shows how Apple is now able to detect and fix update problems in real-time.

Finite state machine

This is a formal model used widely in computing to design, describe and implement a machine or automaton that can only exist in one of a finite number of states. Its state changes in response to defined events, which result in actions that in turn determine its transition to its next state. Although some FSMs are non-deterministic and subject to chance, those in softwareupdated are governed by deterministic rules. This is illustrated in the excerpt below, extracted from a sequence of log entries for one of the FSMs run by softwareupdated when it’s working out what updates are required, early during macOS updating.

This FSM starts here in the top state shown in blue, where it’s scanning for an SFR update. If that’s successful (the event), its next action is to decide whether the update requires an update to Rosetta 2. If it does (the next event), then its action is to scan for Rosetta updates, and it then transitions to its next state of scanning for Rosetta. If that’s followed by the event that the scan succeeds, the next action is to decide whether an update to RecoveryOS is required, and so the FSM proceeds to work out what updates are required before starting to download and prepare them for installation.

This may appear long-winded, but FSMs can be described formally and from there implemented in code that is robust and correct, fundamental requirements for macOS updates. It also builds in flexibility to tailor each update to what that Mac requires.

Log documentation

The unified log is used by softwareupdated to document the operation of the several FSMs it runs. If an error occurs during software update, this enables its origin and causation to be established, one of the primary purposes of the log. Full detail has to be captured in entries at the time the FSM is running, as they can’t be recreated in retrospect.

As a result, every state transition, each event, and all actions are entered in full detail. The message field in those log entries identifies the FSM involved, reports its current state (S), the event (E), its action (A), and then provides full information about its current data. Those must enable the FSM to be recreated and run in the event that something goes wrong, to investigate and fix malfunction or failure.

Although those large and copious log entries are a challenge to browse, the architecture of the Unified log is designed to cope with them. Such long messages are stored separately in the warren of directories inside /var/db/uuidtext, and don’t burden the main log’s tracev3 log files.

FSMs

When softwareupdated checks for, discovers, downloads and prepares the macOS update from 26.2 to 26.3, the following named FSMs are identifiable in log entries:

  • SUMacControllerScanManager
  • scan[UUID]
  • SUMacControllerRecoveryOSManagerScan
  • update_downloader
  • SUMacControllerStateMachine
  • update[UUID]
  • SUMacControllerScanManager (again)
  • scan[UUID] (again)
  • SUMacControllerRecoveryOSManagerScan (again)

in the order in which they appear. In some cases, before the FSM is run, it’s loaded with Events that are detailed in the log, and provide further insight into what that FSM does.

The UUID used for FSMs and throughout softwareupdated is allocated at the start of these processes, before scanning for software updates. It’s referred to as “the SUCore SoftwareUpdate UUID”, and doesn’t appear to be the same as well-known UUIDs used elsewhere. However, as it’s a version 5 UUID it probably doesn’t contain any randomly generated content. This is worth bearing in mind, as it’s this UUID that is attached to Event Reports.

Real-time reporting

Many of us can recall macOS updates that have gone badly wrong, and some that had to be withdrawn or replaced because of their problems. Apple tackles that now using an event reporting system that provides real-time information about how every Mac being updated is progressing. This is anonymised, the only identifier being the UUID allocated to that software update by softwareupdated before starting to scan for updates.

At frequent stages during software update, softwareupdated updates its Event Report to reflect progress, and that’s automatically uploaded to Apple’s servers at an HTTPS address starting with xp.apple.com/report/ Although typically only just over 500 bytes in length, a typical Event Report contains the following named fields:
UUID, audienceType, batteryIsCharging, batteryLevel, currentBaseOSVersion, currentOSType, currentOSVersion, currentProductVersionExtra, dataFsCapacity, dataFsFree, deviceClass, deviceModel, event, eventTime, lowPowerMode, macPlatform, mandatoryUpdateEligible, mandatoryUpdateOptional, preSUStagingEnabled, preSUStagingMaxSize, preSUStagingOptionalSize, preSUStagingRequiredSize, preferredType, rampEnabled, rapidSecurityResponseCombo, rapidSecurityResponseInstalled, rapidSecurityResponseSemiSplat, reportVersion, result, storageCapacity, ucoreVersion, systemFsCapacity, systemFsFree, targetOSVersion, totalRequiredFreeSpace, updateType.

Most should be fairly self-explanatory, and in this case the event field was set to SUCoreOTAPreSUStagingDetermineStarted.

The first of these is sent less than one second after starting to scan for updates, when policy and sizing for the updates to be downloaded have just been determined, and that’s repeated after each significant stage until the Mac is rebooted to apply the update. I suspect there’s also a final Event Report sent once the Mac has booted into the updated macOS.

Apple is thus able to track progress for each UUID during the software update process. Should it detect a problem, for example a required component being unavailable, it should be able to take immediate action to address that, rather than having to wait for individual users to report errors or failures long after they occurred.

Summary

  • From Big Sur, software update uses a modern design based on finite state machines, completely replacing its old script-based system.
  • FSMs bring the greatly improved reliability necessary to install and build the Signed System Volume and other components of macOS.
  • The log contains detailed accounts of FSMs as they are run to accomplish the many phases of these complex software updates.
  • Those log entries could be used to recreate the FSM in the event of failure or error, e.g. as provided in a sysdiagnose.
  • Bulky message content in log entries is stored outside log files, in the /var/db/uuidtext directory.
  • Each software update is given its own UUID.
  • Update progress is reported to Apple frequently in Event Reports.
  • Event Reports can enable real-time detection and correction of problems in software updates.