Summary
- ALEAPP now has 15 Bug Report artifacts in four groups: permissions and app ops (6), app usage (3), alarms and jobs (3) and notifications (3). The pull request was merged on 27 October 2026.
- Values stay as the report printed them. Modes, flags, states and reason codes are not decoded. A UTC column is added only where the report holds what the conversion needs.
- Row counts were compared with counts from the raw text and with a second parser written by a different method. Cases that no research report contained were built as synthetic fixtures.
- An empty table has three possible causes: nothing was there, the platform cut the dump, or that build does not print the section. The notes of each artifact say which one applies.
- 15artifacts added in four groups
- 135test baselines in 2 case folders
- 30 of 30table comparisons equal a second parser
- 15,810permission rows on the largest of two reports, equal to a raw-text count
Methodology note
Drafted with AI assistance and reviewed by the author before publication. Every figure uses synthetic example values or counts taken from the pull request.
The issue
Suppose an examiner has to say which apps could use the microphone on a phone, and when one last did. A bug report can answer both without a full file system extraction, but the answer is spread over several sections. The permissions an app holds are in the package dump. The operations it may perform, and a few lines about when it last performed them, are in the app ops dump. The holder of a role such as the default dialer is in the role dump, and on newer builds the permission manager dump lists grants by app id.
Each dump has its own layout, and the layout changes between versions. The standby bucket list is indented under each user on Android 10 and sits under a "User N App Standby States" heading on Android 15 and 16. Android 10 prints no attribution tag lines. The Samsung reports on Android 16 print no role section at all, so a role table for them is empty and says nothing about the phone. Finding the right heading in a file that can pass two million lines, and reading it by eye, is slow and cannot be repeated or checked by a second examiner.
A tool that reads these dumps must also avoid failing quietly. LAB-TR-0001 describes a single damaged line inside the package dump that made a parser end its package list early: 15 of 284 packages remained and no error was shown. Permissions are read from that same dump, so a short permission table is exactly what an examiner could mistake for a quiet device. This contribution is built around counting every table a second way before it is trusted. Figure 1 shows the reading of one line.
Show this figure as a table
| Field | Value (synthetic example) |
|---|---|
| Kind | Access |
| Uid (as printed) | u0a999 |
| Numeric Uid | 10999 |
| Package | org.example.recorder |
| Op | RECORD_AUDIO |
| Op Mode | allow |
| Uid State | top |
| Op Flags | s |
| Time As Printed | 2026-03-14 09:26:53.589 |
| Offset From Dump | -5s250ms |
| Time (UTC) | 2026-03-14 08:26:53.589 |
The essence
The pull request adds 15 artifacts that read eight sections of the report text in one pass. Each row is what the dump printed for one entry. Modes, flags, states and reason codes are kept as printed. The one name that is added is the standby bucket name, which comes from the platform's published constants and is marked as a mapping, not as something decoded from the dump. A UTC column is filled where the dump gives enough to compute it, and a note column says why it is empty when it is.
A row says that the service listed that entry when the dump ran. It does not say that an app used the access, that a job ran or that an alarm fired.
| Group | Artifacts | Report sections read |
|---|---|---|
| Permissions and App Ops (6) | Package Permissions, Permission Definitions, App Ops Modes, App Ops Accesses, Role Holders, Permission Manager Grants | package, appops, role, permissionmgr |
| App Usage (3) | Usage Intervals, Usage Interval Event Counts, Standby Buckets | usagestats and the CHECKIN USAGESTATS command section |
| Alarms and Jobs (3) | Scheduled Jobs, Pending Alarms, Alarm History | jobscheduler, alarm |
| Notifications (3) | Notification Records, Notification Listeners, Notification Channels | notification |
Our methodology
We start from the text, not from the platform source. For each service we list the heading shapes found in every report we hold, by Android version and vendor, and write the reader to those shapes. A reader is a small class registered for one section. The shared single-pass reader described in LAB-TR-0001 streams the report once and hands the lines of the open section only to the readers registered for it (Figure 2). A reader keeps bounded rows, cuts long text at a set length and decodes nothing.
Time needs the most care, because these dumps print it in three ways. App ops access lines print a device wall-clock time with milliseconds and no zone, and an offset from the dump in brackets. We keep both as printed and add a UTC value computed with the zone the report itself records. Time minus offset gave the same instant for every row of a report, within a second of the section footer, which is a check that the line was read correctly. Pending alarms print offsets from the dump; their UTC value is computed from the nowRTC value printed in the same dump, so it does not depend on a zone, and it is left empty with a note when nowRTC is not printed. The job scheduler prints offsets and no absolute anchor, so those columns stay as offsets and are not converted.
Show this figure as a table
| Step | What happens |
|---|---|
| 1. Find the file | Six path patterns match a plain text, a finished zip, a temporary file or a zip kept on the device. |
| 2. Index the sections | The shared reader enters every section with kind, name, first and last line and duration, and stores a DUMP TIMEOUT marker when the platform cut a service. |
| 3. Hand over the lines | Only the readers registered for the open section see its lines: package, appops, role, permissionmgr, usagestats, jobscheduler, alarm, notification. |
| 4. Keep bounded rows | Readers keep rows as printed, cut long text and decode nothing. |
| 5. Present | 15 artifacts show the tables; a UTC column is added only where the report holds what the conversion needs. |
Checking has four layers. First, synthetic fixtures: small invented bug reports, one case per situation. The case names include one per Android layout (a10, a15, a16), a dump cut by the time limit, an empty report, a report without a zone, a file that is not a report, odd bytes, two reports in one run and a zip kept on the device. Between them the two modules have 135 baselines in two case folders, and all pass under TZ=UTC.
Second, an independent recount on five older research reports. Each permission table was compared field by field, source line number included, with a second parser built differently (an indentation tree, and a regular expression for roles): 30 of 30 table-by-report comparisons were equal. The Op Count of App Ops Modes adds up to the raw line count on all five. For usage and jobs, all nine row counts equalled counts from the raw text, and a second regular expression parser agreed field by field.
Third, two newer Android 16 reports were run through the whole tool with no failed artifact, and counts made with our own line rules, not the readers, equalled the artifact rows for Package Permissions and Permission Manager Grants (Figure 3). Fourth, the 198 bug report unit tests of the stack so far pass, and the changed files score 10.00 of 10 on pylint.
Missing and cut data get explicit handling. The package dump of one report ends with a 10,000 ms time-limit marker after the block that holds the permission lines, so none were lost; the log says so whenever a cut dump is read, because a report cut earlier would lose the rest. No research report had a usage, job, alarm or notification dump cut, so that case exists only as a synthetic fixture.
Show every artifact of this pull request as a table
| Artifact | Report 1 rows | Report 2 rows |
|---|---|---|
| Package Permissions (Permissions and App Ops) | 12,598 | 15,810 |
| Permission Definitions (Permissions and App Ops) | 2,939 | 3,201 |
| App Ops Modes (Permissions and App Ops) | 2,171 | 3,199 |
| App Ops Accesses (Permissions and App Ops) | 1,632 | 2,667 |
| Role Holders (Permissions and App Ops) | 43 | 44 |
| Permission Manager Grants (Permissions and App Ops) | 12,115 | 15,278 |
| Usage Intervals (App Usage) | 1,056 | 872 |
| Usage Interval Event Counts (App Usage) | 32 | 16 |
| Standby Buckets (App Usage) | 806 | 512 |
| Scheduled Jobs (Alarms and Jobs) | 480 | 558 |
| Pending Alarms (Alarms and Jobs) | 109 | 204 |
| Alarm History (Alarms and Jobs) | 999 | 1,544 |
| Notification Records (Notifications) | 18 | 18 |
| Notification Listeners (Notifications) | 18 | 23 |
| Notification Channels (Notifications) | 609 | 900 |
The value
The gain is a set of questions that can be asked of a bug report and answered from a table: which packages hold a runtime permission and with which flags; which ops are allowed, ignored or foreground-only for a package; which app holds a role; which apps sit in the rare or restricted standby buckets; what is scheduled to run later; which apps may listen to notifications and which channels an app defined. A bug report can be obtained without a full file system extraction (LAB-TR-0003), so these tables reach questions that would otherwise wait for one.
The limits matter as much as the tables. The app ops dump keeps a few lines per op and package, not a log: on the five older reports the printed access times reached back between 283 and 2,277 days from the dump, so an access that is not listed says nothing about whether it happened. Op Mode is the mode at dump time. In LAB-TR-0003, 99.1 to 99.8 percent of the uid-level mode lines on the Android 15 and 16 reports were "ignore", so the modes table is long but narrow. A pending alarm or a scheduled job shows that the service held it when the dump ran. The notification archive printed 5 of 100 entries on the two newest reports, and the tool logs how many it lists. Permission Manager Grants are per app id, so every package sharing an app id repeats the same rows.
Large tables need care in reading. Together the five older reports gave 59,380 Package Permissions rows, above the 50,000-row limit the report builder sets for an HTML page, so the page left that table out; the TSV and LAVA outputs hold every row. As in earlier ALEAPP bug report work, identifiers such as account names are shown as printed, because the tool runs on the examiner's own evidence. This page shows none.
Show this figure as a table
| Column | Items |
|---|---|
| Checked on research reports | 30 of 30 table-by-report comparisons equal a second parser (permissions); 9 of 9 usage, job and alarm row counts equal raw-text counts; App Ops Modes: Op Count adds up to the raw line count on five reports; Package Permissions and Grants counts equal raw-text counts on two more |
| Synthetic fixtures only | Time zones other than UTC+0, and daylight saving; A second Android user in usage statistics; A usage, job, alarm or notification dump cut by the time limit; A report without nowRTC; More than one holder in one role |
| Not examined | Android 11 to 14; Vendors other than the four seen; Field values of the app ops, permission and job tables against a second parser on the two newest reports (counts only) |
Where this sits in the Lab's research
Two Lab reports cover this work. LAB-TR-0003, Where Android Records Who Used What: App Ops History in Databases, XML Files and Bug Reports (Zenodo, version 1.2, 10.5281/zenodo.23720064), uses the two App Ops artifacts of this pull request for its bug report measurements. It reports 30 table-by-report comparisons for the six permission artifacts, that every access line resolves to one dump instant, and that the dump form is narrow beside the Android 16 history databases. Those databases are read by a separate pull request, ALEAPP #1786, which is in review and is not part of this one.
LAB-TR-0001, Making Silent Failures Visible: A Single-Pass Section Reader for Android Bug Reports (Zenodo, version 1.1, 10.5281/zenodo.23719508), describes the reader these artifacts plug into, the section index and the record of cut dumps. The grouping follows the 22 categories of Android bug reports, category by category.
Sources
Every number and claim on this page, with where it came from. Figure values are either synthetic examples (marked) or counts from the pull request.
| Number or claim | Where it came from |
|---|---|
| 15 artifacts in 4 groups (6, 3, 3, 3); eight sections read | Pull request description, section 'What this changes'; artifact list in scripts/artifacts/bugreportPermissions.py and bugreportUsageJobs.py |
| Merged on 27 October 2026 | Pull request state and merge time (mergedAt); the review and comment lists are empty |
| 135 baselines in 2 case folders, all pass; 198 cumulative unit tests; pylint 10.00/10 | Pull request description, 'Test record' table |
| Fixture case names (a10, a15, a16, cut, empty, no_zone, not_a_report, odd_bytes, two_reports, zip_on_device) | File names under admin/test/cases/data/ in the pull request file list |
| 30 of 30 table-by-report comparisons equal; Op Count equals raw lines; 9 of 9 usage and job counts equal | Pull request description, 'Proven on real reports'; LAB-TR-0003 section 4.5 |
| Package Permissions 12,598 and 15,810; Permission Manager Grants 12,115 and 15,278; all other row counts in Figure 3 | Pull request description, table of rows per artifact (two newest Samsung reports) |
| Seven reports: four Samsung (Android 16), Huawei and Transsion-brand (Android 10), Motorola (Android 15); all UTC+0 | Pull request description; device classes only |
| Constructed only and not examined lists (Figure 4) | Pull request description, 'Constructed only' and 'Not examined' |
| Access times reach back 283 to 2,277 days from the dump; Op Mode is the mode at dump time; time minus offset gives one dump instant | Notes of App Ops Accesses in bugreportPermissions.py |
| 99.1 to 99.8 percent of uid-level mode lines are 'ignore' on the Android 15 and 16 reports; dump instant spread 0.0 s | LAB-TR-0003, Table 3 and section 5.5 |
| Pending alarm UTC = nowRTC + printed offset; job times are offsets and are not converted | Notes of Pending Alarms and Scheduled Jobs in bugreportUsageJobs.py |
| Package dump of one report ends with a 10,000 ms DUMP TIMEOUT marker after the shared users block | Notes of Package Permissions in bugreportPermissions.py |
| Role section absent on the Samsung Android 16 reports; standby list layout differs between Android 10 and 15/16 | Notes of Role Holders and Standby Buckets |
| 59,380 Package Permissions rows on five reports exceed the 50,000-row HTML limit; TSV and LAVA hold the rows | Notes of Package Permissions in bugreportPermissions.py |
| Notification archive prints 5 of 100 entries on the two newest reports | Pull request description, 'Anything reviewers should know' |
| 284 packages reduced to 15 by one damaged line; 2 million lines; HTML, TSV and LAVA output | LAB-TR-0001, section 1 and Listing 1 |