Merge "Fix issue #38244875: Bring back testChargingConstraintFails" into oc-dev
am: 0cd3e8f694
Change-Id: I5280a18f0f93396e02df236fb3f78fa952cbc460
This commit is contained in:
@@ -1270,6 +1270,17 @@ public final class JobSchedulerService extends com.android.server.SystemService
|
||||
}
|
||||
}
|
||||
|
||||
private void stopNonReadyActiveJobsLocked() {
|
||||
for (int i=0; i<mActiveServices.size(); i++) {
|
||||
JobServiceContext serviceContext = mActiveServices.get(i);
|
||||
final JobStatus running = serviceContext.getRunningJobLocked();
|
||||
if (running != null && !running.isReady()) {
|
||||
serviceContext.cancelExecutingJobLocked(
|
||||
JobParameters.REASON_CONSTRAINTS_NOT_SATISFIED);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Run through list of jobs and execute all possible - at least one is expired so we do
|
||||
* as many as we can.
|
||||
@@ -1280,6 +1291,7 @@ public final class JobSchedulerService extends com.android.server.SystemService
|
||||
}
|
||||
noteJobsNonpending(mPendingJobs);
|
||||
mPendingJobs.clear();
|
||||
stopNonReadyActiveJobsLocked();
|
||||
mJobs.forEachJob(mReadyQueueFunctor);
|
||||
mReadyQueueFunctor.postProcess();
|
||||
|
||||
@@ -1306,9 +1318,6 @@ public final class JobSchedulerService extends com.android.server.SystemService
|
||||
newReadyJobs = new ArrayList<JobStatus>();
|
||||
}
|
||||
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<map.length; i++) {
|
||||
@@ -2152,7 +2227,8 @@ public final class JobSchedulerService extends com.android.server.SystemService
|
||||
}
|
||||
|
||||
final int filterUidFinal = UserHandle.getAppId(filterUid);
|
||||
final long now = SystemClock.elapsedRealtime();
|
||||
final long nowElapsed = SystemClock.elapsedRealtime();
|
||||
final long nowUptime = SystemClock.uptimeMillis();
|
||||
synchronized (mLock) {
|
||||
mConstants.dump(pw);
|
||||
pw.println();
|
||||
@@ -2184,7 +2260,7 @@ public final class JobSchedulerService extends com.android.server.SystemService
|
||||
continue;
|
||||
}
|
||||
|
||||
job.dump(pw, " ", true, now);
|
||||
job.dump(pw, " ", true, nowElapsed);
|
||||
pw.print(" Ready: ");
|
||||
pw.print(isReadyToBeExecutedLocked(job));
|
||||
pw.print(" (job=");
|
||||
@@ -2254,14 +2330,14 @@ public final class JobSchedulerService extends com.android.server.SystemService
|
||||
JobStatus job = mPendingJobs.get(i);
|
||||
pw.print(" Pending #"); pw.print(i); pw.print(": ");
|
||||
pw.println(job.toShortString());
|
||||
job.dump(pw, " ", false, now);
|
||||
job.dump(pw, " ", false, nowElapsed);
|
||||
int priority = evaluateJobPriorityLocked(job);
|
||||
if (priority != JobInfo.PRIORITY_DEFAULT) {
|
||||
pw.print(" Evaluated priority: "); pw.println(priority);
|
||||
}
|
||||
pw.print(" Tag: "); pw.println(job.getTag());
|
||||
pw.print(" Enq: ");
|
||||
TimeUtils.formatDuration(job.madePending - now, pw);
|
||||
TimeUtils.formatDuration(job.madePending - nowUptime, pw);
|
||||
pw.println();
|
||||
}
|
||||
pw.println();
|
||||
@@ -2276,17 +2352,17 @@ public final class JobSchedulerService extends com.android.server.SystemService
|
||||
} else {
|
||||
pw.println(job.toShortString());
|
||||
pw.print(" Running for: ");
|
||||
TimeUtils.formatDuration(now - jsc.getExecutionStartTimeElapsed(), pw);
|
||||
TimeUtils.formatDuration(nowElapsed - jsc.getExecutionStartTimeElapsed(), pw);
|
||||
pw.print(", timeout at: ");
|
||||
TimeUtils.formatDuration(jsc.getTimeoutElapsed() - now, pw);
|
||||
TimeUtils.formatDuration(jsc.getTimeoutElapsed() - nowElapsed, pw);
|
||||
pw.println();
|
||||
job.dump(pw, " ", false, now);
|
||||
job.dump(pw, " ", false, nowElapsed);
|
||||
int priority = evaluateJobPriorityLocked(jsc.getRunningJobLocked());
|
||||
if (priority != JobInfo.PRIORITY_DEFAULT) {
|
||||
pw.print(" Evaluated priority: "); pw.println(priority);
|
||||
}
|
||||
pw.print(" Active at ");
|
||||
TimeUtils.formatDuration(job.madeActive - now, pw);
|
||||
TimeUtils.formatDuration(job.madeActive - nowUptime, pw);
|
||||
pw.print(", pending for ");
|
||||
TimeUtils.formatDuration(job.madeActive - job.madePending, pw);
|
||||
pw.println();
|
||||
|
||||
@@ -60,6 +60,8 @@ public class JobSchedulerShellCommand extends ShellCommand {
|
||||
return getStorageSeq(pw);
|
||||
case "get-storage-not-low":
|
||||
return getStorageNotLow(pw);
|
||||
case "get-job-state":
|
||||
return getJobState(pw);
|
||||
default:
|
||||
return handleDefaultCommands(cmd);
|
||||
}
|
||||
@@ -83,6 +85,43 @@ public class JobSchedulerShellCommand extends ShellCommand {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean printError(int errCode, String pkgName, int userId, int jobId) {
|
||||
PrintWriter pw;
|
||||
switch (errCode) {
|
||||
case CMD_ERR_NO_PACKAGE:
|
||||
pw = getErrPrintWriter();
|
||||
pw.print("Package not found: ");
|
||||
pw.print(pkgName);
|
||||
pw.print(" / user ");
|
||||
pw.println(userId);
|
||||
return true;
|
||||
|
||||
case CMD_ERR_NO_JOB:
|
||||
pw = getErrPrintWriter();
|
||||
pw.print("Could not find job ");
|
||||
pw.print(jobId);
|
||||
pw.print(" in package ");
|
||||
pw.print(pkgName);
|
||||
pw.print(" / user ");
|
||||
pw.println(userId);
|
||||
return true;
|
||||
|
||||
case CMD_ERR_CONSTRAINTS:
|
||||
pw = getErrPrintWriter();
|
||||
pw.print("Job ");
|
||||
pw.print(jobId);
|
||||
pw.print(" in package ");
|
||||
pw.print(pkgName);
|
||||
pw.print(" / user ");
|
||||
pw.print(userId);
|
||||
pw.println(" has functional constraints but --force not specified");
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private int runJob(PrintWriter pw) throws Exception {
|
||||
checkPermission("force scheduled jobs");
|
||||
|
||||
@@ -114,42 +153,17 @@ public class JobSchedulerShellCommand extends ShellCommand {
|
||||
final long ident = Binder.clearCallingIdentity();
|
||||
try {
|
||||
int ret = mInternal.executeRunCommand(pkgName, userId, jobId, force);
|
||||
switch (ret) {
|
||||
case CMD_ERR_NO_PACKAGE:
|
||||
pw.print("Package not found: ");
|
||||
pw.print(pkgName);
|
||||
pw.print(" / user ");
|
||||
pw.println(userId);
|
||||
break;
|
||||
|
||||
case CMD_ERR_NO_JOB:
|
||||
pw.print("Could not find job ");
|
||||
pw.print(jobId);
|
||||
pw.print(" in package ");
|
||||
pw.print(pkgName);
|
||||
pw.print(" / user ");
|
||||
pw.println(userId);
|
||||
break;
|
||||
|
||||
case CMD_ERR_CONSTRAINTS:
|
||||
pw.print("Job ");
|
||||
pw.print(jobId);
|
||||
pw.print(" in package ");
|
||||
pw.print(pkgName);
|
||||
pw.print(" / user ");
|
||||
pw.print(userId);
|
||||
pw.println(" has functional constraints but --force not specified");
|
||||
break;
|
||||
|
||||
default:
|
||||
// success!
|
||||
pw.print("Running job");
|
||||
if (force) {
|
||||
pw.print(" [FORCED]");
|
||||
}
|
||||
pw.println();
|
||||
break;
|
||||
if (printError(ret, pkgName, userId, jobId)) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
// success!
|
||||
pw.print("Running job");
|
||||
if (force) {
|
||||
pw.print(" [FORCED]");
|
||||
}
|
||||
pw.println();
|
||||
|
||||
return ret;
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(ident);
|
||||
@@ -244,6 +258,43 @@ public class JobSchedulerShellCommand extends ShellCommand {
|
||||
return 0;
|
||||
}
|
||||
|
||||
private int getJobState(PrintWriter pw) throws Exception {
|
||||
checkPermission("force timeout jobs");
|
||||
|
||||
int userId = UserHandle.USER_SYSTEM;
|
||||
|
||||
String opt;
|
||||
while ((opt = getNextOption()) != null) {
|
||||
switch (opt) {
|
||||
case "-u":
|
||||
case "--user":
|
||||
userId = UserHandle.parseUserArg(getNextArgRequired());
|
||||
break;
|
||||
|
||||
default:
|
||||
pw.println("Error: unknown option '" + opt + "'");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (userId == UserHandle.USER_CURRENT) {
|
||||
userId = ActivityManager.getCurrentUser();
|
||||
}
|
||||
|
||||
final String pkgName = getNextArgRequired();
|
||||
final String jobIdStr = getNextArgRequired();
|
||||
final int jobId = Integer.parseInt(jobIdStr);
|
||||
|
||||
final long ident = Binder.clearCallingIdentity();
|
||||
try {
|
||||
int ret = mInternal.getJobState(pw, pkgName, userId, jobId);
|
||||
printError(ret, pkgName, userId, jobId);
|
||||
return ret;
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(ident);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onHelp() {
|
||||
final PrintWriter pw = getOutPrintWriter();
|
||||
@@ -277,6 +328,18 @@ public class JobSchedulerShellCommand extends ShellCommand {
|
||||
pw.println(" Return the last storage update sequence number that was received.");
|
||||
pw.println(" get-storage-not-low");
|
||||
pw.println(" Return whether storage is currently considered to not be low.");
|
||||
pw.println(" get-job-state [-u | --user USER_ID] PACKAGE JOB_ID");
|
||||
pw.println(" Return the current state of a job, may be any combination of:");
|
||||
pw.println(" pending: currently on the pending list, waiting to be active");
|
||||
pw.println(" active: job is actively running");
|
||||
pw.println(" user-stopped: job can't run because its user is stopped");
|
||||
pw.println(" backing-up: job can't run because app is currently backing up its data");
|
||||
pw.println(" no-component: job can't run because its component is not available");
|
||||
pw.println(" ready: job is ready to run (all constraints satisfied or bypassed)");
|
||||
pw.println(" waiting: if nothing else above is printed, job not ready to run");
|
||||
pw.println(" Options:");
|
||||
pw.println(" -u or --user: specify which user's job is to be run; the default is");
|
||||
pw.println(" the primary or system user");
|
||||
pw.println();
|
||||
}
|
||||
|
||||
|
||||
@@ -93,34 +93,31 @@ public class BatteryController extends StateController {
|
||||
}
|
||||
}
|
||||
|
||||
private void maybeReportNewChargingState() {
|
||||
private void maybeReportNewChargingStateLocked() {
|
||||
final boolean stablePower = mChargeTracker.isOnStablePower();
|
||||
final boolean batteryNotLow = mChargeTracker.isBatteryNotLow();
|
||||
if (DEBUG) {
|
||||
Slog.d(TAG, "maybeReportNewChargingState: " + stablePower);
|
||||
Slog.d(TAG, "maybeReportNewChargingStateLocked: " + stablePower);
|
||||
}
|
||||
boolean reportChange = false;
|
||||
synchronized (mLock) {
|
||||
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;
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user