From 48a30db75dd0eedf8e065c89825b2af86a381b62 Mon Sep 17 00:00:00 2001 From: Matthew Williams Date: Tue, 23 Sep 2014 13:39:36 -0700 Subject: [PATCH] Fix lock ordering in JobScheduler BUG: 17625667 Two part clean-up. 1) Don't try to lock in onControllerStateChanged. Do it in the handleMessage instead where the rest of the locking is. This is sufficient to fix this bug. 2) The other side of the deadlock came b/c we lock when cancelling and calling stopTrackingJob. Controllers handle their own locking so this isn't necessary. B/c of a potential race from the controller side, added an explicit check for the JSS to only run an expired job if it still exists. Change-Id: Iaeebbc19437eb5b73e3ced3168f1fc13e564a4be --- .../server/job/JobSchedulerService.java | 206 +++++++++--------- .../java/com/android/server/job/JobStore.java | 22 +- .../com/android/server/job/JobStoreTest.java | 4 +- 3 files changed, 117 insertions(+), 115 deletions(-) diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java index 30154d716f7fc..f456bcd4af7f0 100644 --- a/services/core/java/com/android/server/job/JobSchedulerService.java +++ b/services/core/java/com/android/server/job/JobSchedulerService.java @@ -195,12 +195,13 @@ public class JobSchedulerService extends com.android.server.SystemService } private void cancelJobsForUser(int userHandle) { + List jobsForUser; synchronized (mJobs) { - List jobsForUser = mJobs.getJobsByUser(userHandle); - for (int i=0; i jobsForUid; synchronized (mJobs) { - List jobsForUid = mJobs.getJobsByUid(uid); - for (int i=0; i jobs = mJobs.getJobs(); - if (DEBUG) { - Slog.d(TAG, "queuing all ready jobs for execution:"); - } - for (int i=0; i jobs = mJobs.getJobs(); + if (DEBUG) { + Slog.d(TAG, "queuing all ready jobs for execution:"); + } + for (int i=0; i runnableJobs = new ArrayList(); - ArraySet jobs = mJobs.getJobs(); - for (int i=0; i 0) { - backoffCount++; - } - if (job.hasIdleConstraint()) { - idleCount++; - } - if (job.hasConnectivityConstraint() || job.hasUnmeteredConstraint()) { - connectivityCount++; - } - if (job.hasChargingConstraint()) { - chargingCount++; - } - runnableJobs.add(job); - } else if (isReadyToBeCancelledLocked(job)) { - stopJobOnServiceContextLocked(job); - } - } - if (backoffCount > 0 || - idleCount >= MIN_IDLE_COUNT || - connectivityCount >= MIN_CONNECTIVITY_COUNT || - chargingCount >= MIN_CHARGING_COUNT || - runnableJobs.size() >= MIN_READY_JOBS_COUNT) { - if (DEBUG) { - Slog.d(TAG, "maybeQueueReadyJobsForExecutionH: Running jobs."); - } - for (int i=0; i runnableJobs = new ArrayList(); + ArraySet jobs = mJobs.getJobs(); + for (int i=0; i 0) { + backoffCount++; } + if (job.hasIdleConstraint()) { + idleCount++; + } + if (job.hasConnectivityConstraint() || job.hasUnmeteredConstraint()) { + connectivityCount++; + } + if (job.hasChargingConstraint()) { + chargingCount++; + } + runnableJobs.add(job); + } else if (isReadyToBeCancelledLocked(job)) { + stopJobOnServiceContextLocked(job); } + } + if (backoffCount > 0 || + idleCount >= MIN_IDLE_COUNT || + connectivityCount >= MIN_CONNECTIVITY_COUNT || + chargingCount >= MIN_CHARGING_COUNT || + runnableJobs.size() >= MIN_READY_JOBS_COUNT) { if (DEBUG) { - Slog.d(TAG, "idle=" + idleCount + " connectivity=" + - connectivityCount + " charging=" + chargingCount + " tot=" + - runnableJobs.size()); + Slog.d(TAG, "maybeQueueReadyJobsForExecutionLockedH: Running jobs."); } + for (int i=0; i