CVE-2024-0019 AI-generated analysis
platform/frameworks/base, SystemUI (appops privacy indicators / status bar event scheduler)
System UI's AppOpsControllerImpl now queries AppOpsManager.getPackagesForOps for already-running ops when it starts listening, and both SystemStatusAnimationScheduler implementations no longer drop force-visible (privacy) status events during the early-uptime window, so privacy indicators reappear after a System UI restart.
Root cause
AppOpsControllerImpl.setListening(true) only registered mAppOps.startWatchingActive/startWatchingNoted and audio-recording callbacks. It never fetched the ops that were already active at that moment, so if System UI was (re)started while an app was using camera, microphone or location, the controller's active-op list stayed empty and the privacy chip/dot was not shown until the op state changed again. Independently, SystemStatusAnimationSchedulerImpl.onStatusEvent and SystemStatusAnimationSchedulerLegacyImpl.onStatusEvent returned early whenever isTooEarly() was true, including for privacy events (event.forceVisible), so a privacy event delivered shortly after process start was silently dropped.
How the fix works
- packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java:setListening: when listening becomes true, calls new fetchCurrentActiveOps() before registering startWatchingActive/startWatchingNoted.
- AppOpsControllerImpl.java:fetchCurrentActiveOps (new): calls mAppOps.getPackagesForOps(OPS); for every PackageOps -> OpEntry -> AttributedOpEntry whose isRunning() is true, invokes onOpActiveChanged(entry.getOpStr(), op.getUid(), op.getPackageName(), attributionTag, active=true, AppOpsManager.ATTRIBUTION_FLAGS_NONE, AppOpsManager.ATTRIBUTION_CHAIN_ID_NONE), reusing the existing live-callback path to populate the active list and notify callbacks.
- packages/SystemUI/src/com/android/systemui/statusbar/events/SystemStatusAnimationSchedulerImpl.kt:onStatusEvent: early-return condition changed from `isTooEarly() || !isImmersiveIndicatorEnabled()` to `(isTooEarly() && !event.forceVisible) || !isImmersiveIndicatorEnabled()`, so force-visible events are processed even before MIN_UPTIME.
- packages/SystemUI/src/com/android/systemui/statusbar/events/SystemStatusAnimationSchedulerLegacyImpl.kt:onStatusEvent: identical condition change for the legacy scheduler.
- Tests: AppOpsControllerTest adds startListening_fetchesCurrentActive_* and addCallback_existingCallbacksNotifiedOfCurrentActive (regression tests for b/294104969); SystemStatusAnimationSchedulerImplTest adds testPrivacyStatusEvent_beforeSystemUptime_stillDisplayed and an advancePastMinUptime parameter.
Completeness
- Covers active ops in AppOpsControllerImpl.OPS only (whatever that list contains); ops not in OPS are not fetched, matching the existing watch scope.
- Only active (isRunning) ops are reconstructed; previously noted ops (startWatchingNoted path) are not back-filled on startup.
- Attribution flags and chain ID are defaulted to ATTRIBUTION_FLAGS_NONE / ATTRIBUTION_CHAIN_ID_NONE for fetched ops (the diff comment notes AppOpsManager offers no way to retrieve them from an OpEntry); whether onOpActiveChanged handles fetched ops differently as a result is not shown.
- Both scheduler implementations present in Android 14 (SystemStatusAnimationSchedulerImpl and SystemStatusAnimationSchedulerLegacyImpl) are patched; the isImmersiveIndicatorEnabled() gate is unchanged and still suppresses events, including privacy ones, when the device config disables the indicator.
- The fetch runs synchronously inside setListening(true); the material does not show which thread calls setListening.
Behavior changes
- setListening(true) now calls getPackagesForOps and may synchronously fire onOpActiveChanged for each running attributed op, so callbacks see pre-existing active ops.
- Privacy (forceVisible) status events are no longer discarded during the first MIN_UPTIME after System UI process start; non-forceVisible events are still dropped in that window.
- Privacy chip/dot now reappears after a System UI restart while recording or the camera is in use (per commit test steps).
Per major
- Android 14: same fix: commit f747b1e48830 in android-security-14.0.0_r4 (cherry-pick of 084a7afb4bb4); all 8/8 patched lines present at android-security-14.0.0_r29.
- Android 15: not affected per bulletin; patched code (8/8 lines) present at android-security-15.0.0_r17.
- Android 16: not affected per bulletin; patched code (8/8 lines) present at android-security-16.0.0_r8.
- Android 17: not affected per bulletin; patched code (8/8 lines) present at android-security-17.0.0_r1.
Unknowns
- Fix commits for Android 12, 12L and 13 are not included in the material.
- Whether the onOpActiveChanged signature and OpEntry.getAttributedOpEntries()/AttributedOpEntry.isRunning() are available on 12/12L/13.
- Which component calls AppOpsControllerImpl.setListening and on which thread; the index results shown are unrelated setListening methods.
- Contents of AppOpsControllerImpl.OPS and whether onOpActiveChanged treats ATTRIBUTION_FLAGS_NONE/CHAIN_ID_NONE differently from real flags (not shown).