Normal view

There are new articles available, click to refresh the page.
Before yesterdayMain stream

What does RunningBoard do? 5 Log insights

By: hoakley
7 August 2025 at 14:30

If RunningBoard’s copious log entries record the life cycle of apps, can we use them to our advantage? To test this out, I’ve analysed a section of log using waypoints and information provided in RunningBoard’s entries.

Waypoints, or landmarks if you prefer, are essential for navigating the log. In an ideal world we would always know when any significant event occurred, timed to the millisecond. In practice we may only be able to estimate to the nearest few seconds or minutes. Without some means of discovering exactly when to obtain log extracts, you can waste many hours trying to pin down when something happened, and in many cases will be forced to abandon the hunt.

Methods

My aim was to separate RunningBoard log entries into those handling its assertions, which should represent life-cycle events, and job descriptions giving details of apps launched. To try this yourself, open LogUI and set the Start date and time to the start of the period of interest. Set the Period to at least 100 seconds, and Max entries to 2,000 or more. Then set the Predicate popup menu to read subsystem, and type in com.apple.runningboard so that LogUI only gets entries from that subsystem. Click on the Get Log tool in the toolbar, and check you get at least 1,000 entries.

Click on the Save JSON tool to save the whole of this excerpt. To view all the RunningBoard assertions acquired over that excerpt, type acquiring assertion in the search box at the top right, and press Enter.

The window name then changes to append the text from the search box.

To save this limited selection of entries, first click on the Reduce tool to discard all the others, then click on the Save JSON tool again and save the entries using a different filename. Repeat that using each of three search terms:

  • acquiring assertion to see RunningBoard’s outline of life cycle events,
  • constructed job to see job descriptions for newly launched apps,
  • extension overlay to see similar information for appexes and similar extensions.

In my case, I analysed a period of 4 minutes of user activity on a Mac mini M4 Pro running macOS 15.6, during which there were 6,580 RunningBoard entries, suggesting that the whole log would have had well over 50,000 entries in that time, far too many to attempt any more detailed analysis. My search terms found 305 assertions acquired, 3 job descriptions constructed, and 20 extension overlays submitted.

Job descriptions

The three captured represented the three apps I had launched over those four minutes, Cormorant, DelightEd and Consolation 3. Each of them has a platform ID of 1, as notarized macOS apps. I also noticed that one was run in app translocation, although this was long after its first run. Recent versions of macOS, Sequoia in particular, appear prone to this, when an app that should have cleared quarantine gets stuck in perpetual app translocation.

Extension overlays

While I had expected to find those three app launches, I didn’t expect to see any appexes being run over this period. Those encountered consisted of three widgets, none of which had ever been opened, and five QuickLook thumbnail extensions. Most of these were run multiple times, with ScappleThumbnail appearing on six occasions. All were platform 1, except for the widgets, all three of which are bundled in macOS, for the FindMy widget and NewsToday2. They were platform 6, and subject to RunningBoard’s resource controls.

RunningBoard’s log entries here give potentially valuable insights that might otherwise be missed.

Assertions

It’s straightforward to construct a narrative of the key events that took place over that period of 4 minutes using a selection of assertions acquired. Rather than reproduce the whole of each of those waypoints, here they are laid out in more readable form.

11:40:50.424950 Acquiring assertion targeting app application.co.eclecticlight.Cormorant.10809046.10809052(501)
description "LS launch co.eclecticlight.Cormorant" ID:424-620-716
target: application.co.eclecticlight.Cormorant.10809046.10809052(501)
attributes: domain:"com.apple.launchservicesd" name:"LaunchRoleUserInteractive" sourceEnvironment:"(null)"

This marks the start of the launch process for Cormorant, handled in the normal way through LaunchServices and RunningBoard.

11:41:18.304367 Acquiring assertion targeting app application.co.eclecticlight.DelightEd.10206240.10206246(501)
description "LS launch co.eclecticlight.DelightEd" ID:424-620-756
target: application.co.eclecticlight.DelightEd.10206240.10206246(501)
attributes: domain:"com.apple.launchservicesd" name:"LaunchRoleUserInteractive" sourceEnvironment:"(null)"

This is the same for DelightEd.

11:41:20.050166 Acquiring assertion targeting [xpcservice com.apple.appkit.xpc.openAndSavePanelService([app application.co.eclecticlight.DelightEd.10206240.10206246(501) :1553])(501) 1576:1576]
description "viewBridge:1576" ID:424-391-769
target: 1576
attributes: domain:"com.apple.launchservicesd" name:"RoleViewBridge" sourceEnvironment:"(null)"

DelightEd is here being used to open a document using the openAndSavePanelService, a separate process.

11:41:44.171636 Acquiring assertion targeting app application.co.eclecticlight.Consolation3.430650.430692(501)
description "LS launch co.eclecticlight.Consolation3" ID:424-620-788
target: application.co.eclecticlight.Consolation3.430650.430692(501)
attributes: domain:"com.apple.launchservicesd" name:"LaunchRoleUserInteractive" sourceEnvironment:"(null)"

This is the launch of Consolation 3, a user error on this occasion!

Two long runs of assertions were discovered, both involving syncing the address book for Contacts.

11:41:57.462118 Acquiring assertion targeting [osservice com.apple.AddressBook.SourceSync(501):1610]
description "App is holding power assertion" ID:424-362-811
target: 1610
attributes: domain:"com.apple.appnap" name:"PowerAssertion" sourceEnvironment:"(null)", RBSAcquisitionCompletionAttribute policy:AfterApplication

The first of these was to sync the Address Book with its source in iCloud, and lasted 12.181 seconds.

11:42:11.840349 Acquiring assertion targeting [osservice com.apple.AddressBook.abd(501):1625]
description "Contacts shared filesystem lock" ID:424-1625-857
target: 1625
attributes: domain:"com.apple.common" name:"FinishTaskUninterruptable" sourceEnvironment:"(null)", RBSAcquisitionCompletionAttribute policy:AfterApplication

Shortly after that completed, synced data was updated by a service abd (Address Book Daemon?) that I had been unaware of. This only lasted 2.238 seconds.

RunningBoard’s assertions seldom appear for single-shot shell commands, and most commonly handle executable bundles rather than bare Mach-O binaries. They also don’t appear to provide clear information recording when apps are quit normally.

Conclusions

  • RunningBoard entries can readily provide accurate waypoints for many events in the log.
  • Establishing waypoints on the strength of RunningBoard log entries is straightforward in LogUI.
  • Job descriptions are readily found, and provide useful information on apps launched.
  • Extension overlays provide details of appexes that might otherwise be overlooked.
  • Acquisition of assertions identify various events in the app life cycle.
  • Once RunningBoard entries have provided precise times of events, attention can be focussed on obtaining more detail using short log extracts.

Last Week on My Mac: Search and you’ll find

By: hoakley
3 August 2025 at 15:00

One thing we humans are good at is searching. It’s a task we engage in from a few moments after birth until the time we slip away in death, we search everything around us. Locating and identifying that bird of prey wheeling high, finding the house keys, and that book we mislaid some time last week, meeting the perfect partner, discovering the right job, choosing the best education, looking through a Where’s Wally? or Where’s Waldo? book, and so on. Searching has transformed some into explorers like Christopher Columbus, and was the purpose of the chivalric quest. It’s what researchers in every field do, and thanks to Douglas Adams can be answered by the number 42.

Last week my searching took two new turns.

Spotlight

The first was more of a meta-search, in trying to discover more about the internals of Spotlight. Following the example of Maynard Handley, who has used them so successfully in understanding how M-series CPUs work, I looked through patents that have been awarded to Apple for the work of its search engineers. Yesterday’s slightly fuller history of Spotlight search is one result, and there are more to come in the future as I digest those patents concerned with performing search.

There’s a tinge of irony here, as many of my searches have been conducted using Google Patents, alongside Google Scholar one of the remaining search engines that doesn’t yet use AI and attempt to provide its own answers.

Logs

The other marks a new phase in my quest to get more information from the Unified log. Looking back to my first comment here, I realise how wildly over-optimistic I was when I wrote that it “should make my life a lot easier”, and that “a new version of Console will provide improved features to help us wade through logs.” Nine years later, I look wistfully at what remains of Console and realise how wrong I was on both counts.

When RunningBoard arrived in macOS Catalina, I soon noticed how “its log entries are profuse, detailed, and largely uncensored for privacy.” Since then it has proved garrulous to the point where its apparently ceaseless log chatter is a distraction, and can overwhelm attempts to read other log entries. I suspect it has contributed significantly to those advanced Mac users who now refuse to even try to make sense of the log.

One answer might be to tweak log preferences to shut out this noise, but given the purpose of RunningBoard in monitoring the life cycle of apps, why not try to use the information it provides? To do that, it’s first necessary to understand RunningBoard’s idiosyncratic language of assertions, and its protocols under which they’re acquired. The only way to do that without documentation is by observation: catalogue over 30 of those assertions for an interesting example like Apple’s Developer app, and see what they reveal.

By far the most informative entries from RunningBoard are those announcing that it’s acquiring an assertion, such as
Acquiring assertion targeting [app<application.developer.apple.wwdc-Release.9312198.9312203(501)>:2946] from originator [osservice<com.apple.uikitsystemapp(501)>:748] with description <RBSAssertionDescriptor| "com.apple.frontboard.after-life.subordinate" ID:424-748-2228 target:2946 attributes:[
<RBSDomainAttribute| domain:"com.apple.frontboard" name:"AfterLife-Subordinate" sourceEnvironment:"(null)">
]>

In a log often censored to the point of being unintelligible, this contains frank and explicit detail. The app is identified clearly, with the user ID of 501 and process ID of 2946. The originator is similarly identified as com.apple.uikitsystemapp with its PID of 748, which is confirmed in the middle digits in the Assertion ID. This is explicitly related to FrontBoard and an attribute named AfterLife-Subordinate. There’s not a single <private> to blight this entry, although further knowledge is needed to decode it fully.

Normally to get such information from a running process would require its source code to be instrumented with calls to write log entries, many of which would be lost to <private>, yet RunningBoard seems happy, for the moment, to provide that information freely. You can see what I mean by applying the predicate
subsystem == "com.apple.runningboard" AND message CONTAINS "Acquiring assertion t"
in LogUI, to obtain a running commentary on active apps and processes. Once you’ve identified a relevant assertion, you can focus attention on other log entries immediately prior to that. I will be following this up in the coming week, with fuller instructions and some demonstrations.

Although neither patents nor assertions have the significance of the number 42, in their own ways they show how the art and science of search aren’t dead yet, nor have they succumbed to AI.

What does RunningBoard do? 4 Assertions

By: hoakley
31 July 2025 at 14:30

This week’s dive into RunningBoard tackles one of the central questions: this subsystem repeatedly uses the term assertion, but what are these assertions, and how does RunningBoard handle them?

In computing, assertions may have their origin in hardware verification languages like Verilog, where they’re used to state required conditions in declarative form. They appear to have entered macOS through the background service assertiond, which made a name for itself as a killer of processes and apps. Power assertions have been noted in the log and elsewhere for at least the last decade, and are mentioned in IOPMLib, part of IOKit. Since macOS Catalina, assertions have been at the centre of RunningBoard, which remains essentially undocumented.

Developer app

To get a better idea of how assertions are used, I launched Apple’s Developer app on a Mac mini M4 Pro running macOS 15.5, and followed log entries for a period of over 14 seconds from the start of the launch process. Although RunningBoard’s job description records this app’s platform as 6, typical of a Catalyst app, in other log entries it’s claimed not to be a Catalyst app.

At an arbitrary start time of 01.126 seconds, LaunchServices decided to launch this app initially through CoreServicesUIAgent, which 0.04 seconds later requested RunningBoard to execute the launch request. This eventually led to a connection being initialised to FrontBoard Scene Manager, where the app was registered as a new scene, and activated.

Example assertion

FrontBoard set the process visibility to Foreground:
01.593239 com.apple.FrontBoard [app<application.developer.apple.wwdc-Release.9312198.9312203~>:2946] Setting process visibility to: Foreground

RunningBoard then announced it was acquiring a new assertion, giving its descriptor and the PID of the target process
01.593248 com.apple.runningboard Acquiring assertion: <RBSAssertionDescriptor| "com.apple.frontboard.after-life.subordinate" ID:(null) target:2946>
01.593288 com.apple.runningboard PERF: Received request from [osservice<com.apple.uikitsystemapp(501)>:748] (euid 501, auid 501) (persona (null)): acquireAssertionWithDescriptor:error:
01.593289 runningboardd acquireAssertionWithDescriptor

A fuller description followed, including the RunningBoard ID, and the attributes of the assertion
01.593324 com.apple.runningboard Acquiring assertion targeting [app<application.developer.apple.wwdc-Release.9312198.9312203(501)>:2946] from originator [osservice<com.apple.uikitsystemapp(501)>:748] with description <RBSAssertionDescriptor| "com.apple.frontboard.after-life.subordinate" ID:424-748-2228 target:2946 attributes:[
<RBSDomainAttribute| domain:"com.apple.frontboard" name:"AfterLife-Subordinate" sourceEnvironment:"(null)">
]>

This assertion was made active, and RunningBoard stated how many assertions were currently targeting that process
01.593343 com.apple.runningboard Assertion 424-748-2228 (target:[app<application.developer.apple.wwdc-Release.9312198.9312203(501)>:2946]) will be created as active
01.593389 com.apple.runningboard app<application.developer.apple.wwdc-Release.9312198.9312203(501)> is now targeted by 11 assertions

That triggered a state update for the process
01.593400 runningboardd state update

In this case, RunningBoard couldn’t do anything, so left the process’s assertions as they were
01.593461 com.apple.runningboard _checkForSuspendableAssertionCycle for app<application.developer.apple.wwdc-Release.9312198.9312203(501)> bailing out since it's not holding a suspendable assertion
01.593466 com.apple.runningboard Removing 0 assertions

This did, though, alter the inheritance of existing assertions
01.593556 com.apple.runningboard Process: [app<application.developer.apple.wwdc-Release.9312198.9312203(501)>:2946] has changes in inheritances: {(
<RBSInheritance| environment:(none) name:com.apple.launchservices.userfacing origID:424-391-2215 0>,
<RBSInheritance| environment:(none) name:com.apple.launchservices.userfacing origID:424-391-2215 0>,
<RBSInheritance| environment:(none) name:com.apple.launchservices.userfacing origID:424-391-2214 0>,
<RBSInheritance| environment:(none) name:com.apple.frontboard.visibility origID:424-420-2216 0>
)}

This completed the acquisition of this assertion, and the process’s new state was calculated
01.593564 com.apple.runningboard Finished acquiring assertion 424-748-2228 (target:[app<application.developer.apple.wwdc-Release.9312198.9312203(501)>:2946])
01.593741 com.apple.runningboard Calculated state for app<application.developer.apple.wwdc-Release.9312198.9312203(501)>: running-active (role: UserInteractiveFocal) (endowments: <private>)

This was all accomplished in around 0.0005 seconds. FrontBoard then continued processing the app’s scene
01.593743 com.apple.FrontBoard Ingesting properties from UIApplicationSceneSettings...

RunningBoard assertion numbers are of the form 424-748-2228, where the second group 748 is the PID of the source of the assertion, and the third group 2228 is a sequential number.

Assertions recorded

  • Assertion 424-620-2211 for LaunchServices to launch the app. For this, RunningBoard created its job description with its process ID of 2946, assigned it memory limits, stated the process will be managed, and stated it was running-active with a role of UserInteractive.
  • Assertion 424-424-2212 RunningBoard Underlying Assertion. RunningBoard stated the process will be created as active, calculated its processStartTime, created a new RunningBoard Coalition with an ID of 4460, set its Jetsam priority to 0 (the lowest priority over memory use), and set its Darwin GPU to “deny”. Its state was given as running-interactive-NotVisible with a taskState of 4.
  • Assertion 424-391-2213 foregroundApp 2946. This changed its role to UserInteractiveNonFocal, and was repeated in assertion 424-391-2214.
  • Assertion 424-391-2215 frontmost 2946. RunningBoard changed it to running-active-NotVisible, with a Jetsam priority of 100 (extremely unlikely to be killed to free memory), and Darwin GPU to “allow”.
  • Assertion 424-391-2217 LaunchServices notification. It was changed to running-active with a role of UserInteractiveFocal, handshaking took place with the process, and the launch request was recorded. Slightly later, RunningBoard announced it had started “death monitoring” of the process, in case its launch request was denied and the process was killed.
  • Assertion 424-748-2218 FrontBoard Bootstrap Background. Following this, the process acquired its first power assertion ID 34241, outside of RunningBoard.
  • Assertion 424-2946-2219 Shared Background Assertion
  • Assertion 424-655-2220 File Coordination Claim, the first of a series of five similar assertions. For each, RunningBoard recorded Prevent Task Suspend, Prevent Task Throttle Down. After the last it checked for a Suspendable Assertion Cycle, then removed several assertions held for the process.
  • Assertion 424-2946-2227 App Nap adapter assertion. RunningBoard then enabled and configured AppNap for the process, and set the AppNap state.
  • Assertion 424-748-2228 FrontBoard AfterLife-Subordinate. This is the assertion detailed above.
  • Assertion 424-748-2229 FrontBoard Visibility Workspace Foreground Focal. With this, RunningBoard set the process to running-active-Visible with taskState 4.
  • Assertion 424-420-2230 App Drawing. Following that, storekitagent was running as PID 2947, accompanying the Developer app.
  • Assertion 424-2946-2232 CFNetwork StorageDB.
  • Assertion 424-2946-2233 System Animation Fence.
  • Assertion 424-420-2234 App Visible. Following that, uikitsystemapp was drawing, presumably for the Developer app.
  • Assertion 424-420-2236 FuseBoard Process Window State Visible.
  • Assertion 424-2946-2238 system animation fence, which was repeated a total of five times.
  • Assertion 424-2946-2244 Shared Background Assertion 1, following which were two more assertions for system animation fence.
  • Assertion 424-2946-2247 com.apple.CFNetwork.StorageDB again.
  • Assertion 424-655-2248 File coordination claim, repeated in Assertion 424-655-2250.

All these assertions were completed in 14 seconds.

Reading RunningBoard

As shown in the series of assertions recorded in the log for the Developer app, RunningBoard provides a detailed account of milestones through the launch and early running of this app, covering much other than its security and TCC activity.

This starts with a job description containing a great deal of useful information about the app, when it’s neither visible nor focal. At that stage it’s given a minimal Jetsam priority, putting it in the front line to be forcibly quit if memory was short, and it’s denied access to the GPU. As launch proceeds, its Jetsam priority is raised to 100 and it’s allowed GPU access. Its role is then changed to UserInteractiveFocal, its window management is handled by FrontBoard and it becomes visible, and able to undergo AppNap. Two supporting services are engaged, storekitagent to handle its data, and uikitsystemapp to draw its interface.

Once the novelty of RunningBoard had worn off, I had come to consider its incessant chatter in the log as a distraction. However, a log extract obtained with the subsystem set to com.apple.runningboard provides a detailed account of events during an app’s life cycle, without the nuisance of privacy censorship, or the app having to make its own log entries.

Key points for close reading of the log

  • Set a predicate for obtaining log entries for the com.apple.runningboard subsystem, and initially filter entries on Acquiring assertion in the Messages field.
  • Identify the Process ID of interest.
  • Track assertion descriptions, giving the reason for each assertion.
  • Note assertion IDs, and interpret them with the aid of the PID given in their second number field.
  • Follow assertions for linked processes through their PIDs.

What does RunningBoard do? 2 Managed apps

By: hoakley
15 July 2025 at 14:30

In the previous article I looked at how RunningBoard monitored an ordinary notarized macOS app, but didn’t manage its life cycle by limiting its access to resources such as memory, CPU or GPU. Here I extend that to the two types of app that are most likely to be managed by RunningBoard, Catalyst and iPadOS apps.

Catalyst

Apple introduced this as a streamlined way for developers of iPadOS apps to be able to create a version that runs in macOS from Catalina onwards. When running on macOS, Catalyst apps are dependent on RunningBoard’s life cycle management, UIKitSystem (which first appeared in macOS Mojave) to bridge between UIKit’s class framework in iPadOS and those in macOS, and additional -board services including FrontBoard, FuseBoard and BaseBoard. Catalyst apps also have access to some features in AppKit, the central class framework for apps developed for macOS, at least until SwiftUI has started to replace it.

Although Apple might have had high hopes of Catalyst bringing many new apps from iPadOS, it hasn’t proved popular with third-party developers, and the ability of Apple silicon Macs to run iPadOS and iOS apps has reduced its relevance to users.

Job descriptions

RunningBoard’s lengthy job descriptions recorded in the log early during the app launch process allow regular macOS, Catalyst and iPadOS apps to be distinguished easily. At the start of each job description, the Platform is recorded, 1 for macOS, 2 for iPadOS, and 6 for Catalyst.

Other differences in job descriptions include:

  • In EnvironmentVariables, iPadOS adds Container values for CFFIXED_USER_HOME and _DYLD_CLOSURE_HOME.
  • In AdditionalProperties, both Catalyst and iPadOS apps have “Managed” set to true, and SpawnConstraints containing their CDHashes.
  • In AdditionalProperties, iPadOS apps have a BeforeTranslocationBundlePath specified.

Catalyst launch

Catalyst apps are launched using the same basic sequence of events as regular macOS apps, with some additional overhead resulting from their UIKitSystem and -board service support. However, when they reach RunningBoard they become managed, in the test case denying it access to the GPU:
00.984295 com.apple.runningboard [app…] Memory Limits: active 0 inactive 0
00.984303 com.apple.runningboard [app…] This process will be managed.
00.984307 com.apple.runningboard <private> is not freezer eligible, disabling freezing.
00.985634 com.apple.runningboard [app…] Set jetsam priority to 0 [0] flag[1]
00.985649 com.apple.runningboard 3638 Set Darwin GPU to "deny"
00.985708 com.apple.runningboard 3638 setGPURole role to 2 (no effect for this process)
00.985715 com.apple.runningboard [app…] Disabled CPU monitoring
00.985716 com.apple.runningboard [app…] Reset CPU monitoring limits to defaults
00.985717 com.apple.runningboard [app…] Resumed CPU monitoring

where [app…] is the app identifier.

Later management includes regular state updates, such as
01.209325 com.apple.runningboard Update delivered for [app…] with taskState 4
01.209327 com.apple.runningboard Received state update for 3638 (app…, running-active-Visible

iPadOS launch

iPadOS and iOS apps are launched completely differently on macOS. Initially MIS, presumably MobileInstallationService, validates the app and its Wrapper, which are translocated to a hidden location in /private/var/folders, from where the wrapped app will be launched. Translocation isn’t intended as a security measure, as it is with macOS apps run there when in quarantine, but is required to work around two limitations:

  • iOS/iPadOS apps may expect to be run from a path that doesn’t contain whitespaces. The path to the translocation folder guarantees that.
  • In macOS, the user can run apps from (almost) any path, such as the Desktop, and can rename apps. The translocation path ensures the app’s name and path remain fixed.

Those are reflected in the following log entries, which have changed little since Big Sur:
00.946662 com.apple.mis Bundle: <private>
00.946662 com.apple.mis Is main executable: 0
00.953668 com.apple.syspolicy MIS validation result: 0
00.953673 com.apple.syspolicy Valid app wrapper: <private>
00.953719 com.apple.syspolicy appWrapperPolicyResult: <private>, AWPolicyResult: 1,1,0
00.956399 com.apple.securityd SecTranslocateCreateGeneric: created /private/var/folders/x4/[…]/d/Wrapper
00.965043 com.apple.launchservices LAUNCH: translocate to <private> from <private>
01.047816 com.apple.launchservices Marking <private> as .requiresSecureLaunch because it is PLATFORM_IOS or PLATFORM_MACCATALYST.
01.049878 com.apple.launchservices LAUNCH: _LSLaunchThruRunningboard: com.parrot.freeflight6 / <private>

FairPlay DRM is then accessed through the Secure Enclave Processor.

When it reaches the attention of RunningBoard, the app’s memory limits are set, it’s denied the GPU, and it’s then managed through its life cycle.
02.365127 com.apple.runningboard [app…:3466] Memory Limits: active 16384 inactive 16384
02.365137 com.apple.runningboard [app…:3466] This process will be managed.
02.365142 com.apple.runningboard <private> is not freezer eligible, disabling freezing.
02.365150 com.apple.runningboard Now tracking process: [app…:3466]
02.367347 com.apple.runningboard 3466 Set Darwin GPU to "deny"
02.367450 com.apple.runningboard 3466 setGPURole role to 2 (no effect for this process)
02.367460 com.apple.runningboard [app…:3466] Disabled CPU monitoring
02.367462 com.apple.runningboard [app…:3466] Reset CPU monitoring limits to defaults
02.367464 com.apple.runningboard [app…:3466] Resumed CPU monitoring
02.367496 com.apple.runningboard [app…:3466] set Memory Limits to Hard Inactive (16384)

where [app…:3466] is the app identifier.

That’s followed by frequent assertions and state updates.

PerfPowerServices

Some users have reported RunningBoard using high CPU %, sometimes associated with high levels from PerfPowerServices. By chance, during these tests I encountered a similar situation. For several seconds, the log was filled with entries recording com.apple.PerfPowerServices requesting management information from RunningBoard about most if not all services running at that time.

Many entry sequences followed the pattern:
00.004740 com.apple.runningboard PERF: Received request from [osservice<com.apple.PerfPowerServices>:976] (euid 0, auid 0) (persona (null)): lookupHandleForPredicate:error:
00.004743 com.apple.runningboard PERF: Received lookupHandleForPredicate request from [osservice<com.apple.PerfPowerServices>:976] (euid 0, auid 0) (persona (null))
00.004971 com.apple.runningboard _multiInstance = 0
00.004973 com.apple.runningboard _executablePath = /usr/sbin/cfprefsd
00.004974 com.apple.runningboard no additional launch properties found for <private>
00.005020 com.apple.runningboard _resolveProcessWithIdentifier pid 2712 euid 277 auid 277
00.005040 com.apple.runningboard Resolved pid 2712 to [osservice<com.apple.cfprefsd.xpc.agent(277)>:2712]
00.005089 com.apple.runningboard memorystatus_control error: MEMORYSTATUS_CMD_CONVERT_MEMLIMIT_MB(-1) returned -1 22 (Invalid argument)
00.005091 com.apple.runningboard memorystatus_control error: MEMORYSTATUS_CMD_CONVERT_MEMLIMIT_MB(0) returned -1 22 (Invalid argument)
00.007828 com.apple.runningboard Full encoding handle <private>, with data 44b0344500000a98, and pid 2712
00.008019 com.apple.runningboard [osservice<com.apple.cfprefsd.xpc.agent(277)>:2712] is not RunningBoard jetsam managed.
00.008040 com.apple.runningboard [osservice<com.apple.cfprefsd.xpc.agent(277)>:2712] This process will not be managed.

for multiple copies of cfprefsd, and many other processes.

Presumably PerfPowerServices is concerned with performance power services, but the purpose of these many requests is unknown. After a few seconds of frenetic activity, and more than 10,000 log entries, this subsided and normal running was resumed. If anyone can provide an explanation, I’d be most grateful.

Key points

  • RunningBoard job descriptions record the app Platform: 1 for macOS, 2 for iPadOS, and 6 for Catalyst.
  • Catalyst apps are managed by RunningBoard through a relatively normal launch sequence.
  • iPadOS/iOS apps are launched differently, in a Wrapper and translocated to avoid problems with their name and path in macOS.
  • iPadOS/iOS apps rely on FairPlay DRM accessed through the Secure Enclave.
  • iPadOS/iOS apps have memory limits imposed by RunningBoard.
  • PerfPowerServices can busy RunningBoard with many requests and high CPU %. The cause is unknown, but that high activity should settle of its own accord.

What does RunningBoard do? 1 App launching

By: hoakley
10 July 2025 at 14:30

As Macs are computers, when they become overloaded with demands on their resources, they can slow down to a crawl. When Apple was developing its first iPhone it realised that wouldn’t work with a phone, so built safeguarding systems into iOS to ensure their continuing smooth function. When Apple was preparing for the transition from Intel Macs to using its own chips, it decided to bring similar safeguards to the management of their resources. These arrived in macOS 10.15 Catalina with the introduction of RunningBoard.

Launching apps in macOS had become increasingly complex, and required more than just running the executable using launchd. For an app to have its GUI, the code it uses has to be wired up with parts of macOS that run the GUI such as WindowServer. When it’s launched, its window(s) have to be created and brought into focus, in front of other windows. It needs its preference file opened, to be added to the Recent Items list, and for a list of its recently opened documents to be made available to its Open Recent menu command. Those latter services have been provided by LaunchServices, and to enable them it maintains a database of exhaustive details about every app it knows.

Prior to Catalina, it was LaunchServices that coordinated many of these aspects of launching an app from the Finder. Since then it has been handing more over to RunningBoard, while retaining many of its functions. RunningBoard has come to monitor and manage the entire life cycle of apps, from launch to exit. For regular macOS apps, its life cycle management remains supervisory, but for some, including Catalyst apps and those built for iPadOS, RunningBoard can manage and control their allocation of resources such as memory and access to the GPU.

As one of the newer and more pervasive services in macOS, RunningBoard writes a lot of detail in the log, indeed it’s garrulous almost to the point of excess. Although Apple documents almost nothing about its background service runningboardd except stating that it’s “a daemon that manages process assertions to ensure those processes are kept in the appropriate state while assertions are in effect”, and its information about LaunchServices is terse and largely deprecated, we can learn a great deal from the log.

I’ll start this series of articles by explaining how RunningBoard first gets involved in launching an application. I have recently summarised its key stages in the following diagram.

Here, for the sake of simplicity, I’m going to ignore the security side completely, so we’ll assume this app isn’t quarantined, has been run recently in this session, is notarised, and hasn’t changed its CDHashes since it was last run.

As soon as LaunchServices is informed of the action to open the app, it announces it will be launched through RunningBoard, a change from its previous behaviour in Catalina, where LaunchServices did more of the work at the start of the launch process. RunningBoard receives the launch request from CoreServices, and ‘acquires’ an ‘assertion’ targeting the app, with a description to launch the app in a User Interactive role.

RunningBoard works using these assertions, a type of declaration of an intention or intended event. Its next major task is to create a job description, which it helpfully writes to the log as a dictionary. This is a mine of useful information, and has replaced the copious data compiled by LaunchServices in the past. This includes:

  • a dictionary of Mach services
  • whether Pressured Exit is enabled
  • a full listing of environment variables, such as TMPDIR, SHELL, PATH
  • RunningBoard properties including another TMPDIR
  • whether to materialise dataless files.

A full example is given in the Appendix at the end. If you ever want to obtain a similar summary for an app, just launch it and inspect log entries from the com.apple.runningboard subsystem for the first second or two after launch.

Shortly after that launchd announces that it will start (spawn) the app, and the user ID (UID) is obtained by OpenDirectory, confirming that ‘divined’ earlier by RunningBoard. This allows launchd to complete spawning the app, and RunningBoard to decide whether it will be managed, in terms of memory and other resources. RunningBoard goes through further preparations before declaring whether the process is subject to GPU, CPU or memory limits.

LaunchServices creates the ‘pending’ application, and a new LSApplication object for it. But it also expects the imminent death of the app, in two entries that might appear surprising:
com.apple.launchservices DEATH: Expecting to hear about the death of app App:"AsmAttic" asn:0x0-5b05b pid:3083 refs=4 @ 0x55402ae00, adding to sRunningBoardDeathNotificationsSetRef (pid=3083}.
com.apple.launchservices DEATH: Listening for death via runningboard notification for pending application, pid=3083.

Its fears are unfounded, though, and RunningBoard continues to receive assertions as the launch proceeds. Eventually you should see log entries confirming success:
com.apple.launchservices LAUNCH: Starting application with ASN 0x0-0x5b05b co.eclecticlight.AsmAttic because it was launched and still stopped.
com.apple.processmanager LAUNCH: 0x0-0x5b05b co.eclecticlight.AsmAttic starting stopped process.
com.apple.launchservices LAUNCH: Sending 0x0-0x5b05b 3083 co.eclecticlight.AsmAttic a SIGCONT to get process started ( it was launched in the stopped state )

This is the cue for launchd to ‘uncork’ the executable and create the process
launchd pid/3083 [AsmAttic] uncorking exec source upfront
launchd pid/3083 [AsmAttic] created

After that, you should see log entries from the app at last, retrieving the UID and loading its preferences
AsmAttic Retrieve User by ID
AsmAttic Loading Preferences From User CFPrefsD

Key points

  • RunningBoard monitors and may manage the life cycle of apps, from launch to exit, and does so by acquiring assertions about the app’s status.
  • RunningBoard now plays an active part in app launch, and fills the log with its entries.
  • Soon after the start of the launch process, its job description is a mine of useful information about the app being launched.
  • It’s normal for app launch entries to expect the app’s imminent death before it’s launched successfully.
  • Don’t be surprised or concerned to see RunningBoard mentioned in early crash reports.

Appendix: Example RunningBoard job description

<dictionary: 0x896c7dda0> { count = 23, transaction: 0, voucher = 0x0, contents =
“Platform” => <int64: 0x9f2093afcb6817e7>: 1
“ProcessType” => <string: 0x896c70de0> { length = 3, contents = “App” }
“EnableTransactions” => <bool: 0x1fd757390>: false
“_ManagedBy” => <string: 0x896c72490> { length = 22, contents = “com.apple.runningboard” }
“CFBundleIdentifier” => <string: 0x896c729a0> { length = 25, contents = “co.eclecticlight.AsmAttic” }
“_ResourceCoalition” => <string: 0x896c71740> { length = 61, contents = “app<application.co.eclecticlight.AsmAttic.753771.753789(501)>” }
“_DisablePointerAuth” => <bool: 0x1fd757370>: true
“ThrottleInterval” => <int64: 0x9f2093ac3497e817>: 2147483647
“MachServices” => <dictionary: 0x89696b120> { count = 0, transaction: 0, voucher = 0x0, contents =
}
“EnablePressuredExit” => <bool: 0x1fd757390>: false
“LimitLoadToSessionType” => <array: 0x896c70c90> { count = 2, capacity = 8, contents =
0: <string: 0x896c71680> { length = 4, contents = “Aqua” }
1: <<string: 0x896c71920> { length = 11, contents = “LoginWindow” }
}
“InitialTaskRole” => <int64: 0x9f2093afcb6817ff>: 2
“EnvironmentVariables” => <dictionary: 0x896c7e220> { count = 12, transaction: 0, voucher = 0x0, contents =
“__CF_USER_TEXT_ENCODING” => <string: 0x896c72df0> { length = 13, contents = “0x1F5:0x0:0x2” }
“TMPDIR” => <string: 0x896c722e0> { length = 49, contents = “/var/folders/x4/x00kny5x0_5dsnmmxhtw6hc80000gn/T/” }
“SHELL” => <string: 0x896c715f0> { length = 8, contents = “/bin/zsh” }
“HOME” => <string: 0x896c72370> { length = 14, contents = “/Users/hoakley” }
“SSH_AUTH_SOCK” => <string: 0x896c71b60> { length = 51, contents = “/private/tmp/com.apple.launchd.kofHVtGWoW/Listeners” }
“LOGNAME” => <string: 0x896c723d0> { length = 7, contents = “hoakley” }
“PATH” => <string: 0x896c70ae0> { length = 29, contents = “/usr/bin:/bin:/usr/sbin:/sbin” }
“XPC_SERVICE_NAME” => <string: 0x896c71560> { length = 16, contents = “com.apple.Finder” }
“__CFBundleIdentifier” => <string: 0x896c72c10> { length = 25, contents = “co.eclecticlight.AsmAttic” }
“COMMAND_MODE” => <string: 0x896c72070> { length = 8, contents = “unix2003” }
“USER” => <string: 0x896c726a0> { length = 7, contents = “hoakley” }
“XPC_FLAGS” => <string: 0x896c725e0> { length = 3, contents = “0x0” }
}
“_AdditionalProperties” => <dictionary: 0x896c7e100> { count = 1, transaction: 0, voucher = 0x0, contents =
“RunningBoard” => <dictionary: 0x896c7eb20> { count = 4, transaction: 0, voucher = 0x0, contents =
“TMPDIR” => <string: 0x896c72820> { length = 49, contents = “/var/folders/x4/x00kny5x0_5dsnmmxhtw6hc80000gn/T/” }
“HOME” => <string: 0x896c72430> { length = 14, contents = “/Users/hoakley” }
“RunningBoardLaunchedIdentity” => <dictionary: 0x896c7f1e0> { count = 5, transaction: 0, voucher = 0x0, contents =
“AJL” => <string: 0x896c727c0> { length = 51, contents = “application.co.eclecticlight.AsmAttic.753771.753789” }
“TYPE” => <int64: 0x9f2093afcb6817e7>: 1
“AUID” => <uint64: 0x9fa093afcb681847>: 501
“EAI” => <string: 0x896c717d0> { length = 25, contents = “co.eclecticlight.AsmAttic” }
“PLAT” => <uint64: 0x9fa093afcb6817e7>: 1
}
“RunningBoardLaunched” => <bool: 0x1fd757370>: true
}
}
“ExitTimeOut” => <int64: 0x9f2093afcb6817e7>: 1
“Label” => <string: 0x896c70ea0> { length = 51, contents = “application.co.eclecticlight.AsmAttic.753771.753789” }
“WaitForDebugger” => <bool: 0x1fd757370>: true
“MaterializeDatalessFiles” => <bool: 0x1fd757370>: true
“WorkingDirectory” => <string: 0x896c72760> { length = 1, contents = “/” }
“_LaunchType” => <int64: 0x9f2093afcb6817f7>: 3
“AbandonProcessGroup” => <bool: 0x1fd757370>: true
“ProgramArguments” => <array: 0x896c71080> { count = 1, capacity = 8, contents =
0: <string: 0x896c716b0> { length = 50, contents = “/Applications/AsmAttic.app/Contents/MacOS/AsmAttic” }
}
“Program” => <string: 0x896c71c20> { length = 50, contents = “/Applications/AsmAttic.app/Contents/MacOS/AsmAttic” }
}

❌
❌