You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Add opt-in local diagnostics that tee AppLog - #187
Beta testers stop receiving update notifications until they open the app, and existing logs (Crashlytics breadcrumbs, refresh history) cannot show what happened in between. This adds opt-in, on-device diagnostics for selected accounts so a tester can share a log covering the silent period.
Split out of #186, which keeps only the sync hardening. Independent of #186; based on master.
What
Settings toggle shown only for accounts in a private build-time allowlist (APPWATCHER_DIAGNOSTIC_ACCOUNTS in the Gradle user home, stored in BuildConfig as SHA-256 hashes; a rollout gate, not a security boundary). Off by default; consent is stored per device and bound to the selected account, so switching accounts disables it.
While enabled, an AppLog tee also writes log lines to noBackupFilesDir/diagnostics (30-day / 10 MiB rotation). Logs may contain package names and error messages. Enabling records a startup snapshot: power/background restrictions, standby bucket, recent process exit reasons, and sync WorkManager state.
Manual Share (FileProvider snapshot under a narrow cache path) and Delete. Nothing uploads automatically.
Performance
Disabled or not allowed: no tee installed; AppLog cost unchanged.
Enabled: callers only enqueue into a bounded non-blocking channel (lines dropped and counted under load); a single IO writer appends and flushes.
Wiring
DiagnosticAllowlist and WorkInfoSource are explicit Koin dependencies, so Preferences and DiagnosticRecorder use singleOf without hidden defaults.
Allowlisted accounts can record app log lines to bounded on-device files and share a snapshot manually. No logging tee is installed unless diagnostics are enabled and allowed.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
The reason will be displayed to describe this comment to others. Learn more.
🟡 Changes recommended
Unresolved issues preserve diagnostic consent across account changes, leave displayed log state stale, prevent recovery after file-open failures, and can leave callers suspended indefinitely during shutdown.
Adds opt-in, on-device diagnostics to help investigate gaps in background update notifications. This complements the sync hardening in #186 by capturing logs for manual sharing, without automatic uploads.
Changes:
Adds a hashed account allowlist and device-local, account-bound recording consent.
Introduces bounded AppLog recording, startup snapshots, retention, sharing, and deletion.
Wires diagnostics into Settings and dependency injection, with focused tests.
File
Description
README.md
Documents configuration, consent, retention, and sharing.
- Show the Settings Local diagnostics section only when the selected
account is on the diagnostic allowlist; drop the long description.
- Read WorkManager state via suspend Flow instead of a blocking get.
- Pass DiagnosticStorageState to preferenceItems instead of the recorder.
- Make DiagnosticFileStore limits explicit constructor arguments.
- Remove unused TestDiagnostics and the README digest claim.
- Add PreferenceItemsDiagnosticsTest and a Pixel device recorder test.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
The reason will be displayed to describe this comment to others. Learn more.
🔵 Needs a closer look
Unresolved defects can re-enable recording without renewed consent after account switches, leave saved logs unshareable, and cause persistent write failures or indefinitely suspended operations.
A log call paused in DiagnosticLogger's delegate can resume after disable/re-enable or an account switch and enqueue its old message with the new account/generation. process() then accepts that message, restoring discarded content into the new recording. Bind each tee to an immutable recording identity, reject calls from retired tees, and cover this interleaving with a blocking-delegate test.
Prevent isolated test cleanup from deleting real diagnostic exports
IsolatedContext inherits the target app's cacheDir, so this test's startup cleanup and disable operations delete real diagnostic exports. Running it on an installation with tester diagnostics can delete snapshots or interrupt a share. Override the test cache directory to use a unique subtree within the FileProvider's allowed root, and remove that subtree during teardown.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
Beta testers stop receiving update notifications until they open the app, and existing logs (Crashlytics breadcrumbs, refresh history) cannot show what happened in between. This adds opt-in, on-device diagnostics for selected accounts so a tester can share a log covering the silent period.
Split out of #186, which keeps only the sync hardening. Independent of #186; based on
master.What
APPWATCHER_DIAGNOSTIC_ACCOUNTSin the Gradle user home, stored in BuildConfig as SHA-256 hashes; a rollout gate, not a security boundary). Off by default; consent is stored per device and bound to the selected account, so switching accounts disables it.AppLogtee also writes log lines tonoBackupFilesDir/diagnostics(30-day / 10 MiB rotation). Logs may contain package names and error messages. Enabling records a startup snapshot: power/background restrictions, standby bucket, recent process exit reasons, and sync WorkManager state.Performance
AppLogcost unchanged.Wiring
DiagnosticAllowlistandWorkInfoSourceare explicit Koin dependencies, soPreferencesandDiagnosticRecorderusesingleOfwithout hidden defaults.Tests
:app:testDebugUnitTest251/251;:app:assembleDebugand main ktlint clean (pre-existingAppItemStateTestunused import untouched).