Repository navigation
fix(autoupload): throttle rapid worker restarts, decouple charging constraint, and delay foreground service - #17973
JanisPlayer wants to merge 1 commit into
Conversation
…nstraint, and delay foreground service
|
Apologies to the maintainers! My AI agent was a bit too enthusiastic and opened this PR prematurely. Please treat this as a 'Draft' or a detailed proposal for now. The goal was to provide the technical analysis and a potential solution as a comment to save you some investigative work. I still need to properly test the implementation on my device to ensure there are no side effects. I will update the PR once I've verified the fix, or feel free to use the analysis to implement it your own way! Thanks for your patience. 🙏 |
Follow-up Review by AI & Proposed Improvements for this DraftAfter further AI-assisted review of the current diff and on-device testing (see the live 1. Return
|
|
Replaced via #18049. Because it hides the bug instead of fixing it. No need for throttle and ignore user's choice. Removing |
Overview
Resolves / addresses #17895 ("Auto Upload high CPU usage").
During active reproduction on device, an live ADB diagnostic and codebase analysis was conducted using Google Antigravity with Gemini 3.8 Flash (High).
Problem & Root Cause
When Auto Upload is configured with "Only while charging" on devices with battery protection enabled (such as Samsung's "Protect Battery" capping at 80%, or Android 15/16 charging limits), the app enters an unthrottled infinite start-cancel-reschedule loop at ~60–80 Hz (every 10–15 ms).
This resulted in:
com.nextcloud.clientpinned at 100% CPU.system_serverpinned at >200% CPU (overwhelmed with millions of JobScheduler requests).#AutoUploadWorker#@androidx.work.systemjobscheduler) scheduled within a single hour.Root Cause Details:
BatteryManager.EXTRA_STATUS = BATTERY_STATUS_NOT_CHARGING(value4), whileEXTRA_PLUGGEDremainsACorUSB.JobScheduler(BatteryController) treats AC power connection as satisfying the charging requirement and firesonStartJob..setRequiresCharging(true)viaSupportedNetworkTransports.getConstraints(...). WorkManager's in-processBatteryChargingTrackerstrictly checksstatus == BATTERY_STATUS_CHARGING (2) || status == BATTERY_STATUS_FULL (5). Becausestatus == 4, WorkManager evaluates charging asfalse.trySetForeground()Promotion:AutoUploadWorker.doWork()was callingtrySetForeground()right at the top, even for empty folders or before checkingisBlocked().trySetForeground()is called,SystemForegroundDispatcheractivates constraint tracking. WorkManager detects constraints as unmet, immediately cancels the worker viaStopWorkRunnable, and notifies JobScheduler withreschedule = true.ENQUEUEDwithout incrementing retry attempts. JobScheduler sees the job ready immediately (as it considers OS constraints met), re-triggeringonStartJobwithin ~10 ms.Solution & Changes
This PR resolves the issue via four complementary safeguards:
AutoUploadWorker.kt):MIN_EXECUTION_INTERVAL_MS) per synced folder inAutoUploadWorker.doWork().Result.success(). Returning success informsJobSchedulerthat the work is finished, immediately breaking any rapid loop.PowerManagementService:PowerManagementService.battery.isChargingalready checksBatteryManager.EXTRA_PLUGGED(USB, AC, Wireless).isBlocked(syncedFolderId):requiresChargingfrom WorkManager'sConstraints:.setRequiresCharging(requiresCharging)fromSupportedNetworkTransports.getConstraints(...).isBlocked()handles the check accurately viaPowerManagementService, WorkManager's internal and flawedBatteryChargingTrackeris no longer triggered on foreground promotion.trySetForeground():trySetForeground()from the very start ofdoWork()down to immediately beforeuploadFiles(syncedFolder).hasNothingToDo()is true, the worker scans and finishes cleanly in the background without creating notification flicker or attaching foreground constraint listeners.Diagnostics & Trace Data
Full Perfetto traces (
~138 MB) and bugreport zips (~92 MB) captured during this live incident are available if maintainers require further inspection.