Revised edition, 2 August 2026. The original version of this post was published on 27 March 2026 and described the CarPlay handshake on iOS 18. Since then the iLEAPP CarPlay module reported that the vehicle-UUID entries described here did not appear in any of their images, and that per-vehicle attribution was therefore waiting for validation data. That is a fair challenge, so I generated the data: three controlled runs on iOS 26.6. Four of the five anchors reproduce. One does not, and the conclusion I drew from it was too strong. Everything below reflects the re-validated version.
Key finding
Anchor a wired CarPlay session on the kernel VBUS entry, which marks the cable connection in every run. accessoryd CoreAnalytics events name the vehicle (manufacturer, model, firmware) in a single record. The vehicle UUID now sits under CarPlayApp:Widgets instead of Stark, and it is a locally assigned ID, not a hardware identifier. Revised in August 2026 after three controlled runs.
In the realm of iOS forensics, certain codenames carry more weight than others. “Stark” is one of them. While the user interface proudly displays “CarPlay,” the artifacts underneath stayed loyal to their internal heritage for years. On iOS 26 that heritage is finally fading, and the way it fades is instructive: the artifact did not disappear, it was renamed. Below is the full sequence, from physical voltage detection to per-vehicle attribution, with the anchors that survived and the ones that need a warning label.
What changed in this revision
- The
Starksubsystem tag no longer exists on iOS 26.6. The vehicle UUID now appears under[com.apple.CarPlayApp:Widgets]. - The UUID is not a vehicle hardware identifier. I called it one in March. It is a locally assigned, per-vehicle identifier, and no log entry binds it to the vehicle’s make, model or serial.
- Attribution to a specific vehicle is better served by a family of
accessorydCoreAnalytics events that I missed entirely the first time. - The CarKit authentication entry lives under
[com.apple.carkit:General], is emitted by dozens of processes, and has a0, 0variant that fires during the same handshake. - The FrontBoard bootstrap entry only appears on a cold start. Its absence proves nothing.
- The interface name
en3is not fixed and must not be hardcoded.
Reference set
| Handset | iPhone 14 |
| iOS | 26.6, build 23G71 |
| Head unit | Volvo EC40 (2026), Android Automotive |
| Connection | Wired, vehicle USB data port |
| Pairing state | Previously paired with this handset |
| Bluetooth | Off for the duration of the series |
| Runs | Three, 2 August 2026, 09:22–09:30 CEST |
| Capture | Full log export per run: 434,660 / 295,693 / 269,704 entries |
| Method | Anchored Log Reconstruction. Cable connect, app open, dial, answer, hang up and cable disconnect were written down by hand during each run, before the logs were pulled. Every entry below is matched against those recorded times, not the other way round. |
Only one vehicle was present in each archive. That matters for the attribution argument further down.
The physical layer
Before anything else happens, the kernel acknowledges the physical connection:
2026-08-02 09:28:21.470680+0200 localhost kernel[0]: (IOAccessoryManager) IOAccessoryUSBConnectShim: USB Power (VBUS) Present: 1, Physical Connection (CON_DET): 1
This remains the primary anchor, and it is the strongest one in the set. Across three runs it lands on the recorded cable-connect second every time: 09:22:38, 09:26:01 and 09:28:21, against protocol entries of 09:22:38, 09:26:01 and 09:28:21. It is a kernel event, so unlike the analytics entries further down it is not subject to sampling. If you only get to keep one artifact, keep this one.
The disconnect deserves a warning the original post did not give. It is not a clean mirror image:
2026-08-02 09:29:32.817155+0200 localhost kernel[0]: (IOAccessoryManager) IOAccessoryUSBConnectShim: USB Power (VBUS) Present: 0, Physical Connection (CON_DET): 0
Two of the three runs ended with both flags at zero. The third ended with VBUS: 0 while CON_DET stayed at 1. One anchor, three runs, two different exit states. Treat VBUS as the deterministic field and CON_DET as descriptive.
The accessory identifies itself
Roughly a second and a half after the voltage swing, accessoryd starts emitting CoreAnalytics events. This is the part I missed in March, and it is the single most useful thing in the dataset:
2026-08-02 09:26:05.451429+0200 localhost accessoryd[210]: [com.apple.accessories:Platform] [#EventLogger] CoreAnalytics event: com.apple.accessories.endpoint.iap2.featuresSupported
eventDict: {
AdapterPID = 0;
AdapterVID = 0;
ConnectedThroughAdapter = 0;
accessoryFirmwareVersionActive = "TAG2.241130.001.26.04.5.15.0014-********";
accessoryHardwareVersion = "qcom 5.0";
accessoryManufacturer = VolvoCars;
accessoryModel = EC40;
accessoryName = Volvo;
accessoryPID = 2654;
accessoryVID = 32903;
carPlayCapable = 1;
connectionType = Lightning;
connectionUUID = "3D013CE7-6158-4F56-BDAF-5D43B4A65F8E";
endpointUUID = "D6F74781-422F-4BFC-A0F4-E9915F620349";
featuresBitmask = 20480;
protocol = iAP2;
screenIsLocked = 0;
transportType = "USB Host Mode";
unlockedSinceBoot = 1;
Manufacturer, model, name, vendor ID, product ID, firmware, transport, protocol and the device lock state at the moment of connection, in one record. No correlation required.
Note connectionType = Lightning and transportType = "USB Host Mode" with ConnectedThroughAdapter = 0. That is a direct statement of a wired session. It also settles a heuristic I have seen used elsewhere, including in my own earlier notes: the absence of iaptransportd does not imply a wireless session. Here protocol = iAP2 is stated explicitly while that process appears zero times in the entire capture.
accessoryVID = 32903 and accessoryPID = 2654 are identical across all three runs. They identify the head unit type rather than the individual unit, which makes them the right values to cite in a report or a parser test.
This entry is not alone. It is one of nineteen CoreAnalytics events that fire in the same order in every run:
cable.typeChanged → connection.statistics → charging.configurationChanged → authCPEvent
→ cable.typeChanged → connection.statistics
→ connection.added → endpoint.added → endpoint.accessoryInfoChanged → endpoint.protocolChanged
→ endpoint.accessoryInfoChanged → connection.passedAuth → endpoint.iap2.featuresSupported
→ endpoint.setAvailableCurrent (×2) → endpoint.removed → connection.removed
From endpoint.accessoryInfoChanged onward, the accessory identity block rides along with every subsequent event, and a single connectionUUID ties the whole sequence together. connection.added and connection.removed give you a named beginning and end of the session instead of a flag whose edges you have to infer.
Two caveats. The connectionUUID and endpointUUID are session-scoped, not vehicle-scoped: they differ in every run. And these are CoreAnalytics events, which are opportunistic and subject to sampling, so their absence in another image is not evidence that no connection occurred. That is exactly why VBUS stays the primary anchor.
The network tunnel
CarPlay is an IP service. The kernel brings up a virtual Ethernet interface over the USB link, configd configures it like any other network, and only then does the CarPlay-specific traffic start:
2026-08-02 09:28:25.054391+0200 localhost kernel[0]: en3: attached (recycled)
2026-08-02 09:28:25.106022+0200 localhost configd[47]: (IPConfiguration) [com.apple.IPConfiguration:Server] DHCP en3: start
2026-08-02 09:28:30.734153+0200 localhost airplayd[43898]: (CoreUtils) [com.apple.airplay:APSSystemUtils] Found USB DirectLink on the network interface en3
The airplayd line is the discriminator for a wired session, and it reproduces in all three runs.
The interface name is not. attached (recycled) means the kernel reused a freed interface index. It happened to be en3 in all three of my runs and in the original February capture, but en1 and en2 also appear elsewhere in the same logs, and on a device with different network history the same connection can come up as en2 or en4. Read the name out of the airplayd entry as a variable and use it to find the matching attach and detach events. Do not hardcode it.
A negative control is worth having, because the interface exists outside the session as well:
2026-08-02 09:28:25.138648+0200 localhost symptomsd[37487]: (SymptomEvaluator) [com.apple.symptomsd:other] Interface en3 is not a DirectLink interface
One further note for anyone building on this. The head unit’s IPv6 link-local address on that interface is derived from its MAC through modified EUI-64, so the hardware address can be recovered from the log. In this series it was stable across all three sessions. I am not publishing the values, and I would treat persistence across reboots or a head-unit reset as untested.
Application bootstrapping via FrontBoard
The original post presented this as a reliable stage marker. It is not, and this is the anchor most likely to mislead an examiner.
2026-08-02 09:23:05.823267+0200 SpringBoard [com.apple.FrontBoard:Process] Asked to bootstrap a new process for handle: [osservice<com.apple.CarPlayApp>:46591]
The wording has changed from what I published in March, and more importantly it appeared exactly once across all three runs. Runs two and three have no equivalent entry, because CarPlayApp was still resident under the same PID 46591. Absence of a bootstrap event is not absence of a CarPlay session. It tells you the app did not need launching, and nothing more.
Session authentication and activation
The CarKit framework still logs the handshake result, with two corrections.
2026-08-02 09:28:31.274399+0200 localhost SpringBoard[37]: (CarKit) [com.apple.carkit:General] session isAuthenticated:1, isActivated:1
First, the subsystem tag is [com.apple.carkit:General], not [com.apple.CarKit:CARSession] as originally published. Second, look at the emitting process. It is SpringBoard here, and across the three runs the same message comes from homed, callservicesd, mediaremoted, photoanalysisd, wifid and a dozen others, over a thousand instances per run. Filtering on carkitd returns an arbitrary slice of the evidence rather than the evidence.
And the string alone proves nothing, because the negative variant fires in the same window:
2026-08-02 09:26:10.355434+0200 localhost photoanalysisd[1745]: (CarKit) [com.apple.carkit:General] session isAuthenticated:0, isActivated:0
Roughly seventy of those per run, seconds before the session authenticates. Read the booleans, not the message name.
Stark is gone. The UUID is not.
In March I wrote that CarPlayApp persists vehicle state under the Stark subsystem tag, and quoted this:
2026-02-04 14:29:41.042312+0100 [com.apple.CarPlayApp:Stark] Saving state for vehicle id: 0485754C-07EE-4E60-978C-703FF0B453F1
On iOS 26.6 there are zero hits for [com.apple.CarPlayApp:Stark] and zero for Saving state for vehicle id across roughly a million log lines. The codename now survives only in media routing, in strings like FigStarkModeCopyController and doNotMakeStarkAudioPortRoutable.
The artifact itself moved to the Widgets subsystem:
2026-08-02 09:28:31.357474+0200 localhost CarPlay[46591]: (DashBoard) [com.apple.CarPlayApp:Widgets] Initialized provider view areas for vehicle ID 996B4167-F3FA-4D99-A429-19BCC2A9B066: [NSRect: {{0, 0}, {384, 316}}]
2026-08-02 09:28:31.547778+0200 localhost CarPlay[46591]: (DashBoard) [com.apple.CarPlayApp:Widgets] Persisting widget state for vehicle ID: 996B4167-F3FA-4D99-A429-19BCC2A9B066
Persisting does what Saving state used to do. Same UUID in run one, run two and run three, and the same UUID again after each disconnect. So the entry is alive and well; the search term I published simply no longer finds it. Grep for Stark and you conclude the artifact is gone, which is how a documented pattern quietly turns into a dead parser rule.
The correction: this is not a hardware ID
The original conclusion called this entry an anchor to “a specific, unique vehicle hardware ID.” Three runs say that is wrong, and the way it is wrong matters more than the fact that it is.
Of the eighteen lines carrying the UUID in run three, exactly zero contain Volvo, EC40, VolvoCars or the head-unit serial. And no line carrying the make, model or serial contains the UUID. Nothing in this dataset binds the two directly. The UUID is a locally assigned identifier that CarPlayApp keeps for a paired vehicle. It is stable and it is per-vehicle, but on its own it says nothing about hardware.
The link has to be built, and it can be. In the same process, 33 milliseconds before the UUID appears:
2026-08-02 09:28:31.347438+0200 localhost CarPlay[46591]: (DashBoard) [com.apple.CarPlayApp:Session] -[DBDisplayManager _isPassengerDisplay:]: session = <CARSession: 0xaf59d0380>, night mode: NO, limit UI: NO, ETC available: unset, configuration: [<CARSessionConfiguration: 0xaf74341c0> session: (null), name: Volvo, modelName: EC40, manufacturer: VolvoCars, serialNumber: 88ec****, transport: USB, ETC supported: NO, right hand drive: NO, ...]
Same PID, same namespace, same session object. And carkitd uses the UUID under a field name that says what it is:
2026-08-02 09:29:33.214907+0200 localhost carkitd[44536]: [com.apple.carkit:ThemeAssets] removing asset progress for vehicleID: 996B4167-F3FA-4D99-A429-19BCC2A9B066 assetID: (null)
Two processes, both holding both identifiers, never printing them together. What makes the attribution sound is the session window, not any single line. Between VBUS Present: 1 at 09:28:21.470 and VBUS Present: 0 at 09:29:32.817 there is one session and one head unit, so within that window the UUID and the vehicle description refer to the same thing. With two vehicles in one archive you have to redo that reasoning per window. Quoting the UUID on its own as “the Volvo” is a step the data does not take.
Which makes this a worked example of the argument in #21. The entry did not become more informative between March and August. The chain around it did.
A readable second layer
Two further entries carry the same attribution from places you would not think to look:
2026-08-02 09:28:25.631897+0200 localhost carkitd[44536]: [com.apple.carkit:DNDWD] Generated vehicle state Vehicle State 1, device ID CarKit Volvo EC40, Vehicular Hints: None: 0 Motion: 0 GPS: 0 Baseband: 0 WiFi: 0 Bluetooth: 16
2026-08-02 09:28:31.284896+0200 localhost wifid[55]: (WiFiPolicy) [com.apple.WiFiPolicy:] WiFiDeviceManagerSetCarPlaySessionState: CarPlay session vehicle inform: model EC40, manufacturer VolvoCars, hardware version qcom 5.0, isSessionActive Y
Model, manufacturer and head-unit software version in wifid, of all processes. The isSessionActive Y/N pair also gives session boundaries independent of CarKit, matching the carPlaySession state flag in powerexperienced to within fifteen milliseconds in two of the three runs. Three independent timelines for the same session is what turns a claim into a finding.
Conclusion
Reconstructing a CarPlay connection is a tiered exercise, and the tiers have different reliability. VBUS tells you when the cable went in, always, from the kernel. The accessoryd CoreAnalytics family tells you which vehicle, in one record, when analytics happened to fire. The virtual network interface and the airplayd DirectLink entry tell you the session was carried over USB rather than Wi-Fi. CarKit tells you the handshake completed, provided you read the booleans and do not filter by process name. And the CarPlayApp UUID tells you this is the same vehicle as last time, across sessions and reboots.
That last one is the part I originally published, and on its own it is the weakest of the five. It carries no attribution without the session window around it. The March version of this post overstated it, and the iLEAPP maintainers were right to flag that the pattern did not hold on their images. It did not hold because the tag had moved, and the conclusion drawn from it was broader than the evidence.
If you have a test device and twenty minutes, generate one of these connections on a build I have not covered and check whether the Widgets tag is still there. That is how this post got corrected, and it is the only way the next correction will happen.
Disclaimer: this revision rests on three runs with one handset, one iOS build and one head unit, already paired, with only one vehicle present per archive. The UUID-to-vehicle mapping is established here by session-window correlation, not by any single entry. A first-time pairing, a second vehicle in the same archive, and a wireless session are all untested. The Widgets tag is version-bound and may drift again.
Happy hunting
© 2026 Tim Korver — Thesis Friday. Licensed under CC BY-NC-ND 4.0. Method: Anchored Log Reconstruction (ALR). Commercial or training use requires written permission. See Copyright and Use.

