Open Source / iLEAPP #2573

Reading the Screen Time store databases

Common advice treats the Screen Time database as a record of app usage. On current iPhones the usage tables are mostly empty, and what the stores do hold is configuration, an app list and a history of deleted rows. This contribution reads all of it and says what each row is.

  • Daniel Addai, SectraTEK Lab
  • Merged
  • CC BY 4.0

View iLEAPP pull request #2573 on GitHub

Summary

  • Screen Time keeps its state in two remote-management databases. Common advice treats them as a usage source; on current iPhones the usage tables are usually empty.
  • This pull request adds eight iLEAPP artifacts that report what the stores do hold: settings, organization settings, users and devices, blueprints, installed apps, usage, change history and deleted-row entries.
  • Counts on three further extractions equal an independent count(*). It was merged on 25 October 2026.
  • A row says what the store held. It does not show that a person used the feature, or that a deleted app left the phone.
  • 8artifacts added
  • +2,577lines added
  • 12unit tests
  • 26 of 26CI jobs passed

The issue

Advice on the Screen Time database is short: it holds app usage by app and by hour, so take a full file system extraction and parse the usage tables. That advice dates from iOS 12. An examiner who follows it on a current phone opens the store and finds the usage tables empty, and may conclude that the device was not used or that Screen Time was off. Before this contribution iLEAPP had no Screen Time artifact at all, so the store was opened by hand or not at all.

On 17 iPhone stores in the Lab's research corpus, usage rows were present on only 4. Six of the seven iOS 26 stores whose Screen Time flag was on held none. What the stores do hold is configuration (a settings row on every store), an installed-app list on 11, and Core Data persistent history on 12, which keeps delete entries for rows that are no longer in the live tables. Four stores held nothing beyond the single configuration row.

So the question is not only "how much was the phone used". It is also "what was configured, which apps did the store list, and what was deleted", and an empty usage table answers none of those. Figure 1 shows how little of the store the usage chain covers.

What 17 Screen Time stores heldBar chart: of 17 iPhone Screen Time stores, 17 held a settings row, 16 a blueprint, 12 history transactions, 11 an installed-app list, 8 installed-app delete entries and 4 usage rows.Stores (of 17) that hold rows in each groupSettings row17Blueprint row16History transactions12Installed-app list11Installed-app delete entries8Usage rows4051015Usage, the content the common advice points to, is the least common content.
Show this figure as a table
Stores that hold each kind of content
ContentStores of 17
Settings row17
Blueprint row16
History transactions12
Installed-app list11
Installed-app delete entries8
Usage rows4
Figure 1What 17 iPhone stores held. Usage rows, the content the common advice points to, are the least common. Source: LAB-TR-0009 section 4.1 and Table 4 (aggregate counts, no synthetic values).

The essence

The contribution adds eight artifacts that read the two remote-management stores, RMAdminStore-Local.sqlite and RMAdminStore-Cloud.sqlite, from a full file system extraction. They report the store settings, the organization settings, users and devices, blueprints with their declaration payloads decoded, the installed-app list, usage tallies, the Core Data change history, and the deleted-row entries that keep an identifier after the row is gone. The passcode is reported as present or absent and its value is never read.

The work is separate from the sysdiagnose ManagedSettings artifacts. It reads the database on the file system, not a sysdiagnose.

The eight artifacts, the tables they read and what each reports
ArtifactTables readReports
SettingsZSCREENTIMESETTINGSStore-level flags, shown as Yes and No
Organization SettingsZCOREORGANIZATIONSETTINGSCommunication and safety policies; passcode present or absent
Users and DevicesZUSERDEVICESTATE, ZCOREUSER, ZCOREDEVICEUsers, devices and per-device state
Blueprints and ConfigurationsZBLUEPRINT, ZBLUEPRINTCONFIGURATIONBlueprints with the declaration payload decoded
Installed AppsZINSTALLEDAPPThe app list the store keeps
UsageZUSAGEBLOCK and the category, timed and counted item tablesUsage blocks and tallies; unverified on real data
Change HistoryATRANSACTION, ACHANGEPersistent-history transactions with author, bundle and change counts
Deleted RowsACHANGE where ZCHANGETYPE = 2Delete entries with the tombstone values as stored

Our methodology

Core Data names its tables after the model entities, with a Z prefix, and keeps an entity table that maps numbers to names. We read the schema from the stores and wrote each query against it, with the results of three habits visible in the code. A table or column that is absent gives no rows for that artifact and not an error, so older stores still run. Flags are shown as Yes and No, with a blank for NULL and any other number kept as stored. Core Data dates are converted to UTC, and each report puts its time columns first. Binary tombstone values are shown as hexadecimal, and the passcode columns are reduced to 0 or 1 inside the SQL query so that no passcode text leaves it.

The search pattern ends in RMAdminStore-*.sqlite*, so the log and shared-memory files are matched beside the database, and the code opens only the main files. The Lab report behind this work measured why that matters: reading the database without its write-ahead log changed at least one count on 14 of 17 stores.

Validation compared the artifacts with plain SQL. For the review of this pull request, three more iPhone extractions (iOS 26.5.2, 26.6 and 26.6.2) were run through the real tool, and independent count(*) on the store tables, with no iLEAPP code, gave the same numbers as the reports (Figure 3). Earlier runs covered five other extractions. On the 26.6.2 store the four deletes are four ZCHANGETYPE = 2 rows in one transaction. The Lab report records 136 of 136 counts equal to independent SQL (eight artifacts on 17 stores), and that the first run on real stores exposed a schema error: timed usage items reach their block through the category row, not through a block column of their own. The query now follows that path.

The output check flagged a few columns as empty or constant: a communication-safety flag that is NULL in the store on two stores, and, on the 26.6.2 store, a timestamp and transaction row shared by the four deletes. Each is now named in the artifact notes. The fixtures are synthetic: a generator builds stores with invented values in two shapes, a managed child profile with usage rows and the plain unmanaged shape seen on real iOS 26 stores. The pull request adds twelve unit tests and two registered cases per artifact, which pass 16 of 16 once the harness uses an absolute temporary folder, and 26 of 26 CI jobs passed.

From the two store files to eight artifactsStorage layout: two Core Data store files with their sidecars, the tables read from them, and the eight artifacts that report them.FileTables readArtifactRMAdminStore-Local.sqliteRMAdminStore-Cloud.sqlitewith -wal and -shm besidethem (the search patternends in .sqlite*)com.apple.remotemanagementd,Application SupportStore column says Local orCloud on every rowMissing table: no rows forthat artifact, no errorZSCREENTIMESETTINGSSettingsZCOREORGANIZATIONSETTINGSpasscode as present or absentOrganization SettingsZUSERDEVICESTATEjoined to ZCOREUSER, ZCOREDEVICEUsers and DevicesZBLUEPRINTwith ZBLUEPRINTCONFIGURATIONBlueprints and ConfigurationsZINSTALLEDAPPInstalled AppsZUSAGEBLOCK, ZUSAGECATEGORYZUSAGETIMEDITEM, ZUSAGECOUNTEDITEMUsageATRANSACTION, ACHANGEATRANSACTIONSTRINGChange HistoryACHANGEwhere ZCHANGETYPE = 2Deleted Rows
Show this figure as a table
Files, tables and artifacts
Table readArtifact
ZSCREENTIMESETTINGSSettings
ZCOREORGANIZATIONSETTINGSOrganization Settings
ZUSERDEVICESTATE, ZCOREUSER, ZCOREDEVICEUsers and Devices
ZBLUEPRINT, ZBLUEPRINTCONFIGURATIONBlueprints and Configurations
ZINSTALLEDAPPInstalled Apps
ZUSAGEBLOCK and the category, timed and counted item tablesUsage
ATRANSACTION, ACHANGEChange History
ACHANGE where ZCHANGETYPE = 2Deleted Rows
Figure 2Storage layout: the store files, the tables read from them, and the artifact each feeds (schematic). Source: diff file scripts/artifacts/screenTimeStore.py (diagram, synthetic example of the layout).
Rows per artifact on three extractions, equal to an independent countCoverage matrix: eight artifacts by three extractions. Settings, organization settings, users and blueprints have one row each; installed apps 336, 0, 0; change history 1, 0, 4; deleted rows 0, 0, 4; usage 0 on all.Rows reported (iOS release across the top)26.5.226.626.6.2Settings111Organization Settings111Users and Devices111Blueprints and Configurations111Installed Apps33600Usage000Change History104Deleted Rows004Each count equals count(*) on the store tables taken without any iLEAPP code.
Show this figure as a table
Rows per artifact per extraction
Artifact26.5.226.626.6.2
Settings111
Organization Settings111
Users and Devices111
Blueprints and Configurations111
Installed Apps33600
Usage000
Change History104
Deleted Rows004
Figure 3Rows per artifact on three extractions. A dashed cell is a count of zero, which is a result. Source: PR #2573 body, checklist item 1 (aggregate counts, no synthetic values).

The value

With these artifacts an examiner can say what the store held when the extraction was taken: whether Screen Time and cloud sync were flagged on, which organization settings and blueprints were present, which apps the store listed, and which identifiers the history shows as deleted. The deleted-row entries are the most useful for a case. On eight stores in the Lab's report, 218 installed-app delete entries cover 207 identifiers, and 173 of them are absent from the live list of the same store (Figure 4).

The limits are firm. A tombstone records a deletion, not that an app left the phone: 34 of the 207 identifiers are in the live list again. An empty usage table supports no statement about use, and the usage artifact is exercised only by a synthetic store because usage tables were empty on all eight real devices checked during this review. The installed-app display name was empty on every row examined in the Lab's parser-development set, so the bundle identifier is the only name. Older iOS releases and iPad were not available for this review and are not verified, and the notes say how each artifact reads when a row is absent. Every reading should state whether the log was applied.

A delete entry outlives the row it describesLeft: one transaction of four delete entries in an iOS 26.6.2 store. Right: the live tables no longer hold those rows. Below: of 207 installed-app identifiers with delete entries across eight stores, 173 are absent from the live list and 34 are present.One transaction in one storeTransaction4 delete entriesZCHANGETYPE = 2kept in the historyDelete: BlueprintDelete: BlueprintConfigurationDelete: LocalOrganizationDelete: LocalOrganizationSettingsLive tablesthe four rows are gone;the history still liststhat they were deletedInstalled-app delete entries: 207 identifiers across eight stores173 absent from the live list34 presentAn absent identifier is one the live list no longer holds. A present one was deleted at some pointand is listed again, so a delete entry does not show that an app left the phone.The four-entry transaction is from the pull request; the 207 split is from the Lab report.
Show this figure as a table
Delete entries and the live list
GroupIdentifiers
Installed-app identifiers with delete entries207
Absent from the live list173
Present in the live list34
Figure 4A transaction of four delete entries (iOS 26.6.2), and how many installed-app identifiers with delete entries are still in the live list. Source: PR #2573 body (transaction); LAB-TR-0009 section 4.4 (207 split; aggregate counts, no synthetic values).

Where this sits in the Lab's research

This contribution is the tooling side of Lab Technical Report LAB-TR-0009, Screen Time on iOS 15 to 27: Mostly Empty Usage Tables and Counts That Change Without the Write-Ahead Log, published on Zenodo (doi:10.5281/zenodo.23720067, version 1.2; the concept DOI 10.5281/zenodo.23717932 always points to the newest version). The report reads 17 stores from iOS 15.6 to 26.6.2, finds usage rows on 4, measures the log effect and analyzes the delete entries. Its eight file system artifacts are the ones described here.

No other Lab report covers this pull request yet; the method above is from the pull request and the report.

Sources

Every figure in the text and in the diagrams is listed here with where it comes from. Nothing else was used: no device, image or report was opened for this post.

Every number and claim in this post, with where it comes from
Number or claimSource
8 artifacts, +2,577 lines, 0 deleted, one new modulePR #2573 body and file list
Merged 25 October 2026PR #2573 state and mergedAt
Rows on three extractions: 1/1/1 for four artifacts; 336/0/0; 1/0/4; 0/0/4; usage 0PR #2573 body, checklist item 1
Independent count(*) gives the same numbers; four deletes are four ZCHANGETYPE = 2 rows in one transactionPR #2573 body, checklist item 1
Earlier run on five extractionsPR #2573 body, checklist item 1
Usage tables empty on all eight real devices; usage artifact unverified on real dataPR #2573 body, reviewer notes
Older iOS versions and iPad not verifiedPR #2573 body, checklist item 1
12 unit tests; 16 of 16 test cases on a Windows host with an absolute temp folder; 26 of 26 CI jobsPR #2573 body, test record
Two synthetic shapes: managed child with usage rows; plain unmanagedPR #2573 body, reviewer notes
Passcode reported as present or absent; reduced to 0 or 1 in SQLPR #2573 body; diff file screenTimeStore.py
Search pattern ends in RMAdminStore-*.sqlite*; only main files openedDiff file screenTimeStore.py (paths and _stores)
17 stores: settings 17, blueprint 16, history 12, installed apps 11, tombstones 8, usage 4LAB-TR-0009 section 4.1 and Table 4
Reading without the log changed a count on 14 of 17 storesLAB-TR-0009 abstract and section 4.3
218 delete entries, 207 identifiers, 173 absent from the live list, 34 presentLAB-TR-0009 section 4.4
136 of 136 counts equal independent SQL; schema error found on first runLAB-TR-0009 section 4.7
Display name empty on every row examined in set PLAB-TR-0009 section 4.4
Zenodo DOI 10.5281/zenodo.23720067 (version 1.2), concept 10.5281/zenodo.23717932papers/zenodo/DOIS.md