From 6d06826b2424f5d937bf97576d3b51169c576fc5 Mon Sep 17 00:00:00 2001 From: Dianne Hackborn Date: Tue, 16 May 2017 13:14:37 -0700 Subject: [PATCH] Fix issue #38244875: Bring back testChargingConstraintFails - Add new "get-job-state" shell command that the tests can use to find out what is going on with a job. - Fix an issue in the battery controller where it would not immediately stop with a "battery not low" constraint when the battery becomes low. - Also an optimization to rescheduling jobs, for every scheduled job that is not ready don't look to see if it is active. Instead, go through the active jobs and see if any are no longer ready. Test: bit -t CtsJobSchedulerTestCases:* Change-Id: I5611886653258ca337eee97c5ee1b9b3dfdb6d85 --- .../server/job/JobSchedulerService.java | 122 +++++++++++++--- .../server/job/JobSchedulerShellCommand.java | 133 +++++++++++++----- .../job/controllers/BatteryController.java | 99 ++++++------- 3 files changed, 247 insertions(+), 107 deletions(-) diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java index c08f866086568..0e55c3f19c3d5 100644 --- a/services/core/java/com/android/server/job/JobSchedulerService.java +++ b/services/core/java/com/android/server/job/JobSchedulerService.java @@ -1270,6 +1270,17 @@ public final class JobSchedulerService extends com.android.server.SystemService } } + private void stopNonReadyActiveJobsLocked() { + for (int i=0; i(); } newReadyJobs.add(job); - } else if (areJobConstraintsNotSatisfiedLocked(job)) { - stopJobOnServiceContextLocked(job, - JobParameters.REASON_CONSTRAINTS_NOT_SATISFIED); } } @@ -1387,9 +1396,6 @@ public final class JobSchedulerService extends com.android.server.SystemService runnableJobs = new ArrayList<>(); } runnableJobs.add(job); - } else if (areJobConstraintsNotSatisfiedLocked(job)) { - stopJobOnServiceContextLocked(job, - JobParameters.REASON_CONSTRAINTS_NOT_SATISFIED); } } @@ -1439,6 +1445,7 @@ public final class JobSchedulerService extends com.android.server.SystemService noteJobsNonpending(mPendingJobs); mPendingJobs.clear(); + stopNonReadyActiveJobsLocked(); mJobs.forEachJob(mMaybeQueueFunctor); mMaybeQueueFunctor.postProcess(); } @@ -1515,15 +1522,6 @@ public final class JobSchedulerService extends com.android.server.SystemService return componentPresent; } - /** - * Criteria for cancelling an active job: - * - It's not ready - * - It's running on a JSC. - */ - private boolean areJobConstraintsNotSatisfiedLocked(JobStatus job) { - return !job.isReady() && isCurrentlyActiveLocked(job); - } - /** * Reconcile jobs in the pending queue against available execution contexts. * A controller can force a job into the pending queue even if it's already running, but @@ -2088,6 +2086,83 @@ public final class JobSchedulerService extends com.android.server.SystemService } } + int getJobState(PrintWriter pw, String pkgName, int userId, int jobId) { + try { + final int uid = AppGlobals.getPackageManager().getPackageUid(pkgName, 0, + userId != UserHandle.USER_ALL ? userId : UserHandle.USER_SYSTEM); + if (uid < 0) { + pw.print("unknown("); pw.print(pkgName); pw.println(")"); + return JobSchedulerShellCommand.CMD_ERR_NO_PACKAGE; + } + + synchronized (mLock) { + final JobStatus js = mJobs.getJobByUidAndJobId(uid, jobId); + if (DEBUG) Slog.d(TAG, "get-job-state " + uid + "/" + jobId + ": " + js); + if (js == null) { + pw.print("unknown("); UserHandle.formatUid(pw, uid); + pw.print("/jid"); pw.print(jobId); pw.println(")"); + return JobSchedulerShellCommand.CMD_ERR_NO_JOB; + } + + boolean printed = false; + if (mPendingJobs.contains(js)) { + pw.print("pending"); + printed = true; + } + if (isCurrentlyActiveLocked(js)) { + if (printed) { + pw.print(" "); + } + printed = true; + pw.println("active"); + } + if (!ArrayUtils.contains(mStartedUsers, js.getUserId())) { + if (printed) { + pw.print(" "); + } + printed = true; + pw.println("user-stopped"); + } + if (mBackingUpUids.indexOfKey(js.getSourceUid()) >= 0) { + if (printed) { + pw.print(" "); + } + printed = true; + pw.println("backing-up"); + } + boolean componentPresent = false; + try { + componentPresent = (AppGlobals.getPackageManager().getServiceInfo( + js.getServiceComponent(), + PackageManager.MATCH_DEBUG_TRIAGED_MISSING, + js.getUserId()) != null); + } catch (RemoteException e) { + } + if (!componentPresent) { + if (printed) { + pw.print(" "); + } + printed = true; + pw.println("no-component"); + } + if (js.isReady()) { + if (printed) { + pw.print(" "); + } + printed = true; + pw.println("ready"); + } + if (!printed) { + pw.print("waiting"); + } + pw.println(); + } + } catch (RemoteException e) { + // can't happen + } + return 0; + } + private String printContextIdToJobMap(JobStatus[] map, String initial) { StringBuilder s = new StringBuilder(initial + ": "); for (int i=0; i= 0; i--) { - final JobStatus ts = mTrackedTasks.valueAt(i); - boolean previous = ts.setChargingConstraintSatisfied(stablePower); - if (previous != stablePower) { - reportChange = true; - } - previous = ts.setBatteryNotLowConstraintSatisfied(batteryNotLow); - if (previous != batteryNotLow) { - reportChange = true; - } + for (int i = mTrackedTasks.size() - 1; i >= 0; i--) { + final JobStatus ts = mTrackedTasks.valueAt(i); + boolean previous = ts.setChargingConstraintSatisfied(stablePower); + if (previous != stablePower) { + reportChange = true; + } + previous = ts.setBatteryNotLowConstraintSatisfied(batteryNotLow); + if (previous != batteryNotLow) { + reportChange = true; } } - // Let the scheduler know that state has changed. This may or may not result in an - // execution. - if (reportChange) { - mStateChangedListener.onControllerStateChanged(); - } - // Also tell the scheduler that any ready jobs should be flushed. if (stablePower || batteryNotLow) { + // If one of our conditions has been satisfied, always schedule any newly ready jobs. mStateChangedListener.onRunJobNow(null); + } else if (reportChange) { + // Otherwise, just let the job scheduler know the state has changed and take care of it + // as it thinks is best. + mStateChangedListener.onControllerStateChanged(); } } @@ -201,38 +198,42 @@ public class BatteryController extends StateController { @VisibleForTesting public void onReceiveInternal(Intent intent) { - final String action = intent.getAction(); - if (Intent.ACTION_BATTERY_LOW.equals(action)) { - if (DEBUG) { - Slog.d(TAG, "Battery life too low to do work. @ " - + SystemClock.elapsedRealtime()); + synchronized (mLock) { + final String action = intent.getAction(); + if (Intent.ACTION_BATTERY_LOW.equals(action)) { + if (DEBUG) { + Slog.d(TAG, "Battery life too low to do work. @ " + + SystemClock.elapsedRealtime()); + } + // If we get this action, the battery is discharging => it isn't plugged in so + // there's no work to cancel. We track this variable for the case where it is + // charging, but hasn't been for long enough to be healthy. + mBatteryHealthy = false; + maybeReportNewChargingStateLocked(); + } else if (Intent.ACTION_BATTERY_OKAY.equals(action)) { + if (DEBUG) { + Slog.d(TAG, "Battery life healthy enough to do work. @ " + + SystemClock.elapsedRealtime()); + } + mBatteryHealthy = true; + maybeReportNewChargingStateLocked(); + } else if (BatteryManager.ACTION_CHARGING.equals(action)) { + if (DEBUG) { + Slog.d(TAG, "Received charging intent, fired @ " + + SystemClock.elapsedRealtime()); + } + mCharging = true; + maybeReportNewChargingStateLocked(); + } else if (BatteryManager.ACTION_DISCHARGING.equals(action)) { + if (DEBUG) { + Slog.d(TAG, "Disconnected from power."); + } + mCharging = false; + maybeReportNewChargingStateLocked(); } - // If we get this action, the battery is discharging => it isn't plugged in so - // there's no work to cancel. We track this variable for the case where it is - // charging, but hasn't been for long enough to be healthy. - mBatteryHealthy = false; - } else if (Intent.ACTION_BATTERY_OKAY.equals(action)) { - if (DEBUG) { - Slog.d(TAG, "Battery life healthy enough to do work. @ " - + SystemClock.elapsedRealtime()); - } - mBatteryHealthy = true; - maybeReportNewChargingState(); - } else if (BatteryManager.ACTION_CHARGING.equals(action)) { - if (DEBUG) { - Slog.d(TAG, "Received charging intent, fired @ " - + SystemClock.elapsedRealtime()); - } - mCharging = true; - maybeReportNewChargingState(); - } else if (BatteryManager.ACTION_DISCHARGING.equals(action)) { - if (DEBUG) { - Slog.d(TAG, "Disconnected from power."); - } - mCharging = false; - maybeReportNewChargingState(); + mLastBatterySeq = intent.getIntExtra(BatteryManager.EXTRA_SEQUENCE, + mLastBatterySeq); } - mLastBatterySeq = intent.getIntExtra(BatteryManager.EXTRA_SEQUENCE, mLastBatterySeq); } }