Merge "Work on issue #62390590: SecurityException in JobIntentService$..." into oc-dev
am: 4eb76b2db8
Change-Id: I34f85b8e06b3eddfee1ea57e8dfcd3ef74e10ff3
This commit is contained in:
@@ -524,7 +524,7 @@ public final class JobSchedulerService extends com.android.server.SystemService
|
|||||||
Slog.d(TAG, "Removing jobs for package " + pkgName
|
Slog.d(TAG, "Removing jobs for package " + pkgName
|
||||||
+ " in user " + userId);
|
+ " in user " + userId);
|
||||||
}
|
}
|
||||||
cancelJobsForUid(pkgUid);
|
cancelJobsForUid(pkgUid, "app package state changed");
|
||||||
}
|
}
|
||||||
} catch (RemoteException|IllegalArgumentException e) {
|
} catch (RemoteException|IllegalArgumentException e) {
|
||||||
/*
|
/*
|
||||||
@@ -553,7 +553,7 @@ public final class JobSchedulerService extends com.android.server.SystemService
|
|||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
Slog.d(TAG, "Removing jobs for uid: " + uidRemoved);
|
Slog.d(TAG, "Removing jobs for uid: " + uidRemoved);
|
||||||
}
|
}
|
||||||
cancelJobsForUid(uidRemoved);
|
cancelJobsForUid(uidRemoved, "app uninstalled");
|
||||||
}
|
}
|
||||||
} else if (Intent.ACTION_USER_REMOVED.equals(action)) {
|
} else if (Intent.ACTION_USER_REMOVED.equals(action)) {
|
||||||
final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
|
final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
|
||||||
@@ -611,7 +611,7 @@ public final class JobSchedulerService extends com.android.server.SystemService
|
|||||||
@Override public void onUidGone(int uid, boolean disabled) throws RemoteException {
|
@Override public void onUidGone(int uid, boolean disabled) throws RemoteException {
|
||||||
updateUidState(uid, ActivityManager.PROCESS_STATE_CACHED_EMPTY);
|
updateUidState(uid, ActivityManager.PROCESS_STATE_CACHED_EMPTY);
|
||||||
if (disabled) {
|
if (disabled) {
|
||||||
cancelJobsForUid(uid);
|
cancelJobsForUid(uid, "uid gone");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -620,7 +620,7 @@ public final class JobSchedulerService extends com.android.server.SystemService
|
|||||||
|
|
||||||
@Override public void onUidIdle(int uid, boolean disabled) throws RemoteException {
|
@Override public void onUidIdle(int uid, boolean disabled) throws RemoteException {
|
||||||
if (disabled) {
|
if (disabled) {
|
||||||
cancelJobsForUid(uid);
|
cancelJobsForUid(uid, "app uid idle");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -689,7 +689,7 @@ public final class JobSchedulerService extends com.android.server.SystemService
|
|||||||
jobStatus.prepareLocked(ActivityManager.getService());
|
jobStatus.prepareLocked(ActivityManager.getService());
|
||||||
|
|
||||||
if (toCancel != null) {
|
if (toCancel != null) {
|
||||||
cancelJobImplLocked(toCancel, jobStatus);
|
cancelJobImplLocked(toCancel, jobStatus, "job rescheduled by app");
|
||||||
}
|
}
|
||||||
if (work != null) {
|
if (work != null) {
|
||||||
// If work has been supplied, enqueue it into the new job.
|
// If work has been supplied, enqueue it into the new job.
|
||||||
@@ -747,7 +747,7 @@ public final class JobSchedulerService extends com.android.server.SystemService
|
|||||||
final List<JobStatus> jobsForUser = mJobs.getJobsByUser(userHandle);
|
final List<JobStatus> jobsForUser = mJobs.getJobsByUser(userHandle);
|
||||||
for (int i=0; i<jobsForUser.size(); i++) {
|
for (int i=0; i<jobsForUser.size(); i++) {
|
||||||
JobStatus toRemove = jobsForUser.get(i);
|
JobStatus toRemove = jobsForUser.get(i);
|
||||||
cancelJobImplLocked(toRemove, null);
|
cancelJobImplLocked(toRemove, null, "user removed");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -765,7 +765,7 @@ public final class JobSchedulerService extends com.android.server.SystemService
|
|||||||
for (int i = jobsForUid.size() - 1; i >= 0; i--) {
|
for (int i = jobsForUid.size() - 1; i >= 0; i--) {
|
||||||
final JobStatus job = jobsForUid.get(i);
|
final JobStatus job = jobsForUid.get(i);
|
||||||
if (job.getSourcePackageName().equals(pkgName)) {
|
if (job.getSourcePackageName().equals(pkgName)) {
|
||||||
cancelJobImplLocked(job, null);
|
cancelJobImplLocked(job, null, "app force stopped");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -778,12 +778,12 @@ public final class JobSchedulerService extends com.android.server.SystemService
|
|||||||
* @param uid Uid to check against for removal of a job.
|
* @param uid Uid to check against for removal of a job.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public void cancelJobsForUid(int uid) {
|
public void cancelJobsForUid(int uid, String reason) {
|
||||||
synchronized (mLock) {
|
synchronized (mLock) {
|
||||||
final List<JobStatus> jobsForUid = mJobs.getJobsByUid(uid);
|
final List<JobStatus> jobsForUid = mJobs.getJobsByUid(uid);
|
||||||
for (int i=0; i<jobsForUid.size(); i++) {
|
for (int i=0; i<jobsForUid.size(); i++) {
|
||||||
JobStatus toRemove = jobsForUid.get(i);
|
JobStatus toRemove = jobsForUid.get(i);
|
||||||
cancelJobImplLocked(toRemove, null);
|
cancelJobImplLocked(toRemove, null, reason);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -800,12 +800,12 @@ public final class JobSchedulerService extends com.android.server.SystemService
|
|||||||
synchronized (mLock) {
|
synchronized (mLock) {
|
||||||
toCancel = mJobs.getJobByUidAndJobId(uid, jobId);
|
toCancel = mJobs.getJobByUidAndJobId(uid, jobId);
|
||||||
if (toCancel != null) {
|
if (toCancel != null) {
|
||||||
cancelJobImplLocked(toCancel, null);
|
cancelJobImplLocked(toCancel, null, "cancel() called by app");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void cancelJobImplLocked(JobStatus cancelled, JobStatus incomingJob) {
|
private void cancelJobImplLocked(JobStatus cancelled, JobStatus incomingJob, String reason) {
|
||||||
if (DEBUG) Slog.d(TAG, "CANCEL: " + cancelled.toShortString());
|
if (DEBUG) Slog.d(TAG, "CANCEL: " + cancelled.toShortString());
|
||||||
cancelled.unprepareLocked(ActivityManager.getService());
|
cancelled.unprepareLocked(ActivityManager.getService());
|
||||||
stopTrackingJobLocked(cancelled, incomingJob, true /* writeBack */);
|
stopTrackingJobLocked(cancelled, incomingJob, true /* writeBack */);
|
||||||
@@ -814,7 +814,7 @@ public final class JobSchedulerService extends com.android.server.SystemService
|
|||||||
mJobPackageTracker.noteNonpending(cancelled);
|
mJobPackageTracker.noteNonpending(cancelled);
|
||||||
}
|
}
|
||||||
// Cancel if running.
|
// Cancel if running.
|
||||||
stopJobOnServiceContextLocked(cancelled, JobParameters.REASON_CANCELED);
|
stopJobOnServiceContextLocked(cancelled, JobParameters.REASON_CANCELED, reason);
|
||||||
reportActiveLocked();
|
reportActiveLocked();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -844,7 +844,8 @@ public final class JobSchedulerService extends com.android.server.SystemService
|
|||||||
final JobStatus executing = jsc.getRunningJobLocked();
|
final JobStatus executing = jsc.getRunningJobLocked();
|
||||||
if (executing != null
|
if (executing != null
|
||||||
&& (executing.getFlags() & JobInfo.FLAG_WILL_BE_FOREGROUND) == 0) {
|
&& (executing.getFlags() & JobInfo.FLAG_WILL_BE_FOREGROUND) == 0) {
|
||||||
jsc.cancelExecutingJobLocked(JobParameters.REASON_DEVICE_IDLE);
|
jsc.cancelExecutingJobLocked(JobParameters.REASON_DEVICE_IDLE,
|
||||||
|
"cancelled due to doze");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -1023,12 +1024,12 @@ public final class JobSchedulerService extends com.android.server.SystemService
|
|||||||
return removed;
|
return removed;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean stopJobOnServiceContextLocked(JobStatus job, int reason) {
|
private boolean stopJobOnServiceContextLocked(JobStatus job, int reason, String debugReason) {
|
||||||
for (int i=0; i<mActiveServices.size(); i++) {
|
for (int i=0; i<mActiveServices.size(); i++) {
|
||||||
JobServiceContext jsc = mActiveServices.get(i);
|
JobServiceContext jsc = mActiveServices.get(i);
|
||||||
final JobStatus executing = jsc.getRunningJobLocked();
|
final JobStatus executing = jsc.getRunningJobLocked();
|
||||||
if (executing != null && executing.matches(job.getUid(), job.getJobId())) {
|
if (executing != null && executing.matches(job.getUid(), job.getJobId())) {
|
||||||
jsc.cancelExecutingJobLocked(reason);
|
jsc.cancelExecutingJobLocked(reason, debugReason);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1270,7 +1271,8 @@ public final class JobSchedulerService extends com.android.server.SystemService
|
|||||||
queueReadyJobsForExecutionLocked();
|
queueReadyJobsForExecutionLocked();
|
||||||
break;
|
break;
|
||||||
case MSG_STOP_JOB:
|
case MSG_STOP_JOB:
|
||||||
cancelJobImplLocked((JobStatus) message.obj, null);
|
cancelJobImplLocked((JobStatus) message.obj, null,
|
||||||
|
"app no longer allowed to run");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
maybeRunPendingJobsLocked();
|
maybeRunPendingJobsLocked();
|
||||||
@@ -1286,7 +1288,8 @@ public final class JobSchedulerService extends com.android.server.SystemService
|
|||||||
final JobStatus running = serviceContext.getRunningJobLocked();
|
final JobStatus running = serviceContext.getRunningJobLocked();
|
||||||
if (running != null && !running.isReady()) {
|
if (running != null && !running.isReady()) {
|
||||||
serviceContext.cancelExecutingJobLocked(
|
serviceContext.cancelExecutingJobLocked(
|
||||||
JobParameters.REASON_CONSTRAINTS_NOT_SATISFIED);
|
JobParameters.REASON_CONSTRAINTS_NOT_SATISFIED,
|
||||||
|
"cancelled due to unsatisfied constraints");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1960,7 +1963,7 @@ public final class JobSchedulerService extends com.android.server.SystemService
|
|||||||
|
|
||||||
long ident = Binder.clearCallingIdentity();
|
long ident = Binder.clearCallingIdentity();
|
||||||
try {
|
try {
|
||||||
JobSchedulerService.this.cancelJobsForUid(uid);
|
JobSchedulerService.this.cancelJobsForUid(uid, "cancelAll() called by app");
|
||||||
} finally {
|
} finally {
|
||||||
Binder.restoreCallingIdentity(ident);
|
Binder.restoreCallingIdentity(ident);
|
||||||
}
|
}
|
||||||
@@ -2357,7 +2360,14 @@ public final class JobSchedulerService extends com.android.server.SystemService
|
|||||||
pw.print(" Slot #"); pw.print(i); pw.print(": ");
|
pw.print(" Slot #"); pw.print(i); pw.print(": ");
|
||||||
final JobStatus job = jsc.getRunningJobLocked();
|
final JobStatus job = jsc.getRunningJobLocked();
|
||||||
if (job == null) {
|
if (job == null) {
|
||||||
|
if (jsc.mStoppedReason != null) {
|
||||||
|
pw.print("inactive since ");
|
||||||
|
TimeUtils.formatDuration(jsc.mStoppedTime, nowElapsed, pw);
|
||||||
|
pw.print(", stopped because: ");
|
||||||
|
pw.println(jsc.mStoppedReason);
|
||||||
|
} else {
|
||||||
pw.println("inactive");
|
pw.println("inactive");
|
||||||
|
}
|
||||||
continue;
|
continue;
|
||||||
} else {
|
} else {
|
||||||
pw.println(job.toShortString());
|
pw.println(job.toShortString());
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ import android.os.SystemClock;
|
|||||||
import android.os.UserHandle;
|
import android.os.UserHandle;
|
||||||
import android.os.WorkSource;
|
import android.os.WorkSource;
|
||||||
import android.util.Slog;
|
import android.util.Slog;
|
||||||
|
import android.util.TimeUtils;
|
||||||
|
|
||||||
import com.android.internal.annotations.GuardedBy;
|
import com.android.internal.annotations.GuardedBy;
|
||||||
import com.android.internal.annotations.VisibleForTesting;
|
import com.android.internal.annotations.VisibleForTesting;
|
||||||
@@ -126,6 +127,12 @@ public class JobServiceContext extends IJobCallback.Stub implements ServiceConne
|
|||||||
/** Track when job will timeout. */
|
/** Track when job will timeout. */
|
||||||
private long mTimeoutElapsed;
|
private long mTimeoutElapsed;
|
||||||
|
|
||||||
|
// Debugging: reason this job was last stopped.
|
||||||
|
public String mStoppedReason;
|
||||||
|
|
||||||
|
// Debugging: time this job was last stopped.
|
||||||
|
public long mStoppedTime;
|
||||||
|
|
||||||
JobServiceContext(JobSchedulerService service, IBatteryStats batteryStats,
|
JobServiceContext(JobSchedulerService service, IBatteryStats batteryStats,
|
||||||
JobPackageTracker tracker, Looper looper) {
|
JobPackageTracker tracker, Looper looper) {
|
||||||
this(service.getContext(), service.getLock(), batteryStats, tracker, service, looper);
|
this(service.getContext(), service.getLock(), batteryStats, tracker, service, looper);
|
||||||
@@ -204,6 +211,8 @@ public class JobServiceContext extends IJobCallback.Stub implements ServiceConne
|
|||||||
}
|
}
|
||||||
mJobPackageTracker.noteActive(job);
|
mJobPackageTracker.noteActive(job);
|
||||||
mAvailable = false;
|
mAvailable = false;
|
||||||
|
mStoppedReason = null;
|
||||||
|
mStoppedTime = 0;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -216,12 +225,12 @@ public class JobServiceContext extends IJobCallback.Stub implements ServiceConne
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Called externally when a job that was scheduled for execution should be cancelled. */
|
/** Called externally when a job that was scheduled for execution should be cancelled. */
|
||||||
void cancelExecutingJobLocked(int reason) {
|
void cancelExecutingJobLocked(int reason, String debugReason) {
|
||||||
doCancelLocked(reason);
|
doCancelLocked(reason, debugReason);
|
||||||
}
|
}
|
||||||
|
|
||||||
void preemptExecutingJobLocked() {
|
void preemptExecutingJobLocked() {
|
||||||
doCancelLocked(JobParameters.REASON_PREEMPT);
|
doCancelLocked(JobParameters.REASON_PREEMPT, "cancelled due to preemption");
|
||||||
}
|
}
|
||||||
|
|
||||||
int getPreferredUid() {
|
int getPreferredUid() {
|
||||||
@@ -247,7 +256,7 @@ public class JobServiceContext extends IJobCallback.Stub implements ServiceConne
|
|||||||
&& (!matchJobId || jobId == executing.getJobId())) {
|
&& (!matchJobId || jobId == executing.getJobId())) {
|
||||||
if (mVerb == VERB_EXECUTING) {
|
if (mVerb == VERB_EXECUTING) {
|
||||||
mParams.setStopReason(JobParameters.REASON_TIMEOUT);
|
mParams.setStopReason(JobParameters.REASON_TIMEOUT);
|
||||||
sendStopMessageLocked();
|
sendStopMessageLocked("force timeout from shell");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -256,17 +265,17 @@ public class JobServiceContext extends IJobCallback.Stub implements ServiceConne
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void jobFinished(int jobId, boolean reschedule) {
|
public void jobFinished(int jobId, boolean reschedule) {
|
||||||
doCallback(reschedule);
|
doCallback(reschedule, "app called jobFinished");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void acknowledgeStopMessage(int jobId, boolean reschedule) {
|
public void acknowledgeStopMessage(int jobId, boolean reschedule) {
|
||||||
doCallback(reschedule);
|
doCallback(reschedule, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void acknowledgeStartMessage(int jobId, boolean ongoing) {
|
public void acknowledgeStartMessage(int jobId, boolean ongoing) {
|
||||||
doCallback(ongoing);
|
doCallback(ongoing, "finished start");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -275,14 +284,11 @@ public class JobServiceContext extends IJobCallback.Stub implements ServiceConne
|
|||||||
final long ident = Binder.clearCallingIdentity();
|
final long ident = Binder.clearCallingIdentity();
|
||||||
try {
|
try {
|
||||||
synchronized (mLock) {
|
synchronized (mLock) {
|
||||||
if (!verifyCallingUidLocked(callingUid)) {
|
assertCallingUidLocked(callingUid);
|
||||||
throw new SecurityException("Bad calling uid: " + callingUid);
|
|
||||||
}
|
|
||||||
|
|
||||||
final JobWorkItem work = mRunningJob.dequeueWorkLocked();
|
final JobWorkItem work = mRunningJob.dequeueWorkLocked();
|
||||||
if (work == null && !mRunningJob.hasExecutingWorkLocked()) {
|
if (work == null && !mRunningJob.hasExecutingWorkLocked()) {
|
||||||
// This will finish the job.
|
// This will finish the job.
|
||||||
doCallbackLocked(false);
|
doCallbackLocked(false, "last work dequeued");
|
||||||
}
|
}
|
||||||
return work;
|
return work;
|
||||||
}
|
}
|
||||||
@@ -297,9 +303,7 @@ public class JobServiceContext extends IJobCallback.Stub implements ServiceConne
|
|||||||
final long ident = Binder.clearCallingIdentity();
|
final long ident = Binder.clearCallingIdentity();
|
||||||
try {
|
try {
|
||||||
synchronized (mLock) {
|
synchronized (mLock) {
|
||||||
if (!verifyCallingUidLocked(callingUid)) {
|
assertCallingUidLocked(callingUid);
|
||||||
throw new SecurityException("Bad calling uid: " + callingUid);
|
|
||||||
}
|
|
||||||
return mRunningJob.completeWorkLocked(ActivityManager.getService(), workId);
|
return mRunningJob.completeWorkLocked(ActivityManager.getService(), workId);
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
@@ -324,7 +328,8 @@ public class JobServiceContext extends IJobCallback.Stub implements ServiceConne
|
|||||||
runningJob = mRunningJob;
|
runningJob = mRunningJob;
|
||||||
|
|
||||||
if (runningJob == null || !name.equals(runningJob.getServiceComponent())) {
|
if (runningJob == null || !name.equals(runningJob.getServiceComponent())) {
|
||||||
closeAndCleanupJobLocked(true /* needsReschedule */);
|
closeAndCleanupJobLocked(true /* needsReschedule */,
|
||||||
|
"connected for different component");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.service = IJobService.Stub.asInterface(service);
|
this.service = IJobService.Stub.asInterface(service);
|
||||||
@@ -355,7 +360,7 @@ public class JobServiceContext extends IJobCallback.Stub implements ServiceConne
|
|||||||
@Override
|
@Override
|
||||||
public void onServiceDisconnected(ComponentName name) {
|
public void onServiceDisconnected(ComponentName name) {
|
||||||
synchronized (mLock) {
|
synchronized (mLock) {
|
||||||
closeAndCleanupJobLocked(true /* needsReschedule */);
|
closeAndCleanupJobLocked(true /* needsReschedule */, "unexpectedly disconnected");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -374,6 +379,21 @@ public class JobServiceContext extends IJobCallback.Stub implements ServiceConne
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void assertCallingUidLocked(final int callingUid) {
|
||||||
|
if (!verifyCallingUidLocked(callingUid)) {
|
||||||
|
StringBuilder sb = new StringBuilder(128);
|
||||||
|
sb.append("Bad calling uid ");
|
||||||
|
sb.append(callingUid);
|
||||||
|
if (mStoppedReason != null) {
|
||||||
|
sb.append(", last stopped ");
|
||||||
|
TimeUtils.formatDuration(SystemClock.elapsedRealtime() - mStoppedTime, sb);
|
||||||
|
sb.append(" because: ");
|
||||||
|
sb.append(mStoppedReason);
|
||||||
|
}
|
||||||
|
throw new SecurityException(sb.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Scheduling of async messages (basically timeouts at this point).
|
* Scheduling of async messages (basically timeouts at this point).
|
||||||
*/
|
*/
|
||||||
@@ -401,7 +421,7 @@ public class JobServiceContext extends IJobCallback.Stub implements ServiceConne
|
|||||||
handleServiceBoundLocked();
|
handleServiceBoundLocked();
|
||||||
}
|
}
|
||||||
|
|
||||||
void doCallback(boolean reschedule) {
|
void doCallback(boolean reschedule, String reason) {
|
||||||
final int callingUid = Binder.getCallingUid();
|
final int callingUid = Binder.getCallingUid();
|
||||||
final long ident = Binder.clearCallingIdentity();
|
final long ident = Binder.clearCallingIdentity();
|
||||||
try {
|
try {
|
||||||
@@ -409,14 +429,14 @@ public class JobServiceContext extends IJobCallback.Stub implements ServiceConne
|
|||||||
if (!verifyCallingUidLocked(callingUid)) {
|
if (!verifyCallingUidLocked(callingUid)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
doCallbackLocked(reschedule);
|
doCallbackLocked(reschedule, reason);
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
Binder.restoreCallingIdentity(ident);
|
Binder.restoreCallingIdentity(ident);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void doCallbackLocked(boolean reschedule) {
|
void doCallbackLocked(boolean reschedule, String reason) {
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
Slog.d(TAG, "doCallback of : " + mRunningJob
|
Slog.d(TAG, "doCallback of : " + mRunningJob
|
||||||
+ " v:" + VERB_STRINGS[mVerb]);
|
+ " v:" + VERB_STRINGS[mVerb]);
|
||||||
@@ -427,7 +447,7 @@ public class JobServiceContext extends IJobCallback.Stub implements ServiceConne
|
|||||||
handleStartedLocked(reschedule);
|
handleStartedLocked(reschedule);
|
||||||
} else if (mVerb == VERB_EXECUTING ||
|
} else if (mVerb == VERB_EXECUTING ||
|
||||||
mVerb == VERB_STOPPING) {
|
mVerb == VERB_STOPPING) {
|
||||||
handleFinishedLocked(reschedule);
|
handleFinishedLocked(reschedule, reason);
|
||||||
} else {
|
} else {
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
Slog.d(TAG, "Unrecognised callback: " + mRunningJob);
|
Slog.d(TAG, "Unrecognised callback: " + mRunningJob);
|
||||||
@@ -435,7 +455,7 @@ public class JobServiceContext extends IJobCallback.Stub implements ServiceConne
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void doCancelLocked(int arg1) {
|
void doCancelLocked(int arg1, String debugReason) {
|
||||||
if (mVerb == VERB_FINISHED) {
|
if (mVerb == VERB_FINISHED) {
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
Slog.d(TAG,
|
Slog.d(TAG,
|
||||||
@@ -448,7 +468,7 @@ public class JobServiceContext extends IJobCallback.Stub implements ServiceConne
|
|||||||
mPreferredUid = mRunningJob != null ? mRunningJob.getUid() :
|
mPreferredUid = mRunningJob != null ? mRunningJob.getUid() :
|
||||||
NO_PREFERRED_UID;
|
NO_PREFERRED_UID;
|
||||||
}
|
}
|
||||||
handleCancelLocked();
|
handleCancelLocked(debugReason);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Start the job on the service. */
|
/** Start the job on the service. */
|
||||||
@@ -459,7 +479,7 @@ public class JobServiceContext extends IJobCallback.Stub implements ServiceConne
|
|||||||
if (mVerb != VERB_BINDING) {
|
if (mVerb != VERB_BINDING) {
|
||||||
Slog.e(TAG, "Sending onStartJob for a job that isn't pending. "
|
Slog.e(TAG, "Sending onStartJob for a job that isn't pending. "
|
||||||
+ VERB_STRINGS[mVerb]);
|
+ VERB_STRINGS[mVerb]);
|
||||||
closeAndCleanupJobLocked(false /* reschedule */);
|
closeAndCleanupJobLocked(false /* reschedule */, "started job not pending");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (mCancelled) {
|
if (mCancelled) {
|
||||||
@@ -467,7 +487,7 @@ public class JobServiceContext extends IJobCallback.Stub implements ServiceConne
|
|||||||
Slog.d(TAG, "Job cancelled while waiting for bind to complete. "
|
Slog.d(TAG, "Job cancelled while waiting for bind to complete. "
|
||||||
+ mRunningJob);
|
+ mRunningJob);
|
||||||
}
|
}
|
||||||
closeAndCleanupJobLocked(true /* reschedule */);
|
closeAndCleanupJobLocked(true /* reschedule */, "cancelled while waiting for bind");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
@@ -496,7 +516,7 @@ public class JobServiceContext extends IJobCallback.Stub implements ServiceConne
|
|||||||
mVerb = VERB_EXECUTING;
|
mVerb = VERB_EXECUTING;
|
||||||
if (!workOngoing) {
|
if (!workOngoing) {
|
||||||
// Job is finished already so fast-forward to handleFinished.
|
// Job is finished already so fast-forward to handleFinished.
|
||||||
handleFinishedLocked(false);
|
handleFinishedLocked(false, "onStartJob returned false");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (mCancelled) {
|
if (mCancelled) {
|
||||||
@@ -504,7 +524,7 @@ public class JobServiceContext extends IJobCallback.Stub implements ServiceConne
|
|||||||
Slog.d(TAG, "Job cancelled while waiting for onStartJob to complete.");
|
Slog.d(TAG, "Job cancelled while waiting for onStartJob to complete.");
|
||||||
}
|
}
|
||||||
// Cancelled *while* waiting for acknowledgeStartMessage from client.
|
// Cancelled *while* waiting for acknowledgeStartMessage from client.
|
||||||
handleCancelLocked();
|
handleCancelLocked(null);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
scheduleOpTimeOutLocked();
|
scheduleOpTimeOutLocked();
|
||||||
@@ -522,11 +542,11 @@ public class JobServiceContext extends IJobCallback.Stub implements ServiceConne
|
|||||||
* _STARTING -> Error
|
* _STARTING -> Error
|
||||||
* _PENDING -> Error
|
* _PENDING -> Error
|
||||||
*/
|
*/
|
||||||
private void handleFinishedLocked(boolean reschedule) {
|
private void handleFinishedLocked(boolean reschedule, String reason) {
|
||||||
switch (mVerb) {
|
switch (mVerb) {
|
||||||
case VERB_EXECUTING:
|
case VERB_EXECUTING:
|
||||||
case VERB_STOPPING:
|
case VERB_STOPPING:
|
||||||
closeAndCleanupJobLocked(reschedule);
|
closeAndCleanupJobLocked(reschedule, reason);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
Slog.e(TAG, "Got an execution complete message for a job that wasn't being" +
|
Slog.e(TAG, "Got an execution complete message for a job that wasn't being" +
|
||||||
@@ -544,7 +564,7 @@ public class JobServiceContext extends IJobCallback.Stub implements ServiceConne
|
|||||||
* in the message queue.
|
* in the message queue.
|
||||||
* _ENDING -> No point in doing anything here, so we ignore.
|
* _ENDING -> No point in doing anything here, so we ignore.
|
||||||
*/
|
*/
|
||||||
private void handleCancelLocked() {
|
private void handleCancelLocked(String reason) {
|
||||||
if (JobSchedulerService.DEBUG) {
|
if (JobSchedulerService.DEBUG) {
|
||||||
Slog.d(TAG, "Handling cancel for: " + mRunningJob.getJobId() + " "
|
Slog.d(TAG, "Handling cancel for: " + mRunningJob.getJobId() + " "
|
||||||
+ VERB_STRINGS[mVerb]);
|
+ VERB_STRINGS[mVerb]);
|
||||||
@@ -553,9 +573,10 @@ public class JobServiceContext extends IJobCallback.Stub implements ServiceConne
|
|||||||
case VERB_BINDING:
|
case VERB_BINDING:
|
||||||
case VERB_STARTING:
|
case VERB_STARTING:
|
||||||
mCancelled = true;
|
mCancelled = true;
|
||||||
|
applyStoppedReasonLocked(reason);
|
||||||
break;
|
break;
|
||||||
case VERB_EXECUTING:
|
case VERB_EXECUTING:
|
||||||
sendStopMessageLocked();
|
sendStopMessageLocked(reason);
|
||||||
break;
|
break;
|
||||||
case VERB_STOPPING:
|
case VERB_STOPPING:
|
||||||
// Nada.
|
// Nada.
|
||||||
@@ -572,7 +593,7 @@ public class JobServiceContext extends IJobCallback.Stub implements ServiceConne
|
|||||||
case VERB_BINDING:
|
case VERB_BINDING:
|
||||||
Slog.e(TAG, "Time-out while trying to bind " + mRunningJob.toShortString() +
|
Slog.e(TAG, "Time-out while trying to bind " + mRunningJob.toShortString() +
|
||||||
", dropping.");
|
", dropping.");
|
||||||
closeAndCleanupJobLocked(false /* needsReschedule */);
|
closeAndCleanupJobLocked(false /* needsReschedule */, "timed out while binding");
|
||||||
break;
|
break;
|
||||||
case VERB_STARTING:
|
case VERB_STARTING:
|
||||||
// Client unresponsive - wedged or failed to respond in time. We don't really
|
// Client unresponsive - wedged or failed to respond in time. We don't really
|
||||||
@@ -580,25 +601,25 @@ public class JobServiceContext extends IJobCallback.Stub implements ServiceConne
|
|||||||
// FINISHED/NO-RETRY.
|
// FINISHED/NO-RETRY.
|
||||||
Slog.e(TAG, "No response from client for onStartJob '" +
|
Slog.e(TAG, "No response from client for onStartJob '" +
|
||||||
mRunningJob.toShortString());
|
mRunningJob.toShortString());
|
||||||
closeAndCleanupJobLocked(false /* needsReschedule */);
|
closeAndCleanupJobLocked(false /* needsReschedule */, "timed out while starting");
|
||||||
break;
|
break;
|
||||||
case VERB_STOPPING:
|
case VERB_STOPPING:
|
||||||
// At least we got somewhere, so fail but ask the JobScheduler to reschedule.
|
// At least we got somewhere, so fail but ask the JobScheduler to reschedule.
|
||||||
Slog.e(TAG, "No response from client for onStopJob, '" +
|
Slog.e(TAG, "No response from client for onStopJob, '" +
|
||||||
mRunningJob.toShortString());
|
mRunningJob.toShortString());
|
||||||
closeAndCleanupJobLocked(true /* needsReschedule */);
|
closeAndCleanupJobLocked(true /* needsReschedule */, "timed out while stopping");
|
||||||
break;
|
break;
|
||||||
case VERB_EXECUTING:
|
case VERB_EXECUTING:
|
||||||
// Not an error - client ran out of time.
|
// Not an error - client ran out of time.
|
||||||
Slog.i(TAG, "Client timed out while executing (no jobFinished received)." +
|
Slog.i(TAG, "Client timed out while executing (no jobFinished received)." +
|
||||||
" sending onStop. " + mRunningJob.toShortString());
|
" sending onStop. " + mRunningJob.toShortString());
|
||||||
mParams.setStopReason(JobParameters.REASON_TIMEOUT);
|
mParams.setStopReason(JobParameters.REASON_TIMEOUT);
|
||||||
sendStopMessageLocked();
|
sendStopMessageLocked("timeout while executing");
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
Slog.e(TAG, "Handling timeout for an invalid job state: " +
|
Slog.e(TAG, "Handling timeout for an invalid job state: " +
|
||||||
mRunningJob.toShortString() + ", dropping.");
|
mRunningJob.toShortString() + ", dropping.");
|
||||||
closeAndCleanupJobLocked(false /* needsReschedule */);
|
closeAndCleanupJobLocked(false /* needsReschedule */, "invalid timeout");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -606,11 +627,11 @@ public class JobServiceContext extends IJobCallback.Stub implements ServiceConne
|
|||||||
* Already running, need to stop. Will switch {@link #mVerb} from VERB_EXECUTING ->
|
* Already running, need to stop. Will switch {@link #mVerb} from VERB_EXECUTING ->
|
||||||
* VERB_STOPPING.
|
* VERB_STOPPING.
|
||||||
*/
|
*/
|
||||||
private void sendStopMessageLocked() {
|
private void sendStopMessageLocked(String reason) {
|
||||||
removeOpTimeOutLocked();
|
removeOpTimeOutLocked();
|
||||||
if (mVerb != VERB_EXECUTING) {
|
if (mVerb != VERB_EXECUTING) {
|
||||||
Slog.e(TAG, "Sending onStopJob for a job that isn't started. " + mRunningJob);
|
Slog.e(TAG, "Sending onStopJob for a job that isn't started. " + mRunningJob);
|
||||||
closeAndCleanupJobLocked(false /* reschedule */);
|
closeAndCleanupJobLocked(false /* reschedule */, reason);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
@@ -620,7 +641,7 @@ public class JobServiceContext extends IJobCallback.Stub implements ServiceConne
|
|||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
Slog.e(TAG, "Error sending onStopJob to client.", e);
|
Slog.e(TAG, "Error sending onStopJob to client.", e);
|
||||||
// The job's host app apparently crashed during the job, so we should reschedule.
|
// The job's host app apparently crashed during the job, so we should reschedule.
|
||||||
closeAndCleanupJobLocked(true /* reschedule */);
|
closeAndCleanupJobLocked(true /* reschedule */, "host crashed when trying to stop");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -630,11 +651,12 @@ public class JobServiceContext extends IJobCallback.Stub implements ServiceConne
|
|||||||
* or from acknowledging the stop message we sent. Either way, we're done tracking it and
|
* or from acknowledging the stop message we sent. Either way, we're done tracking it and
|
||||||
* we want to clean up internally.
|
* we want to clean up internally.
|
||||||
*/
|
*/
|
||||||
private void closeAndCleanupJobLocked(boolean reschedule) {
|
private void closeAndCleanupJobLocked(boolean reschedule, String reason) {
|
||||||
final JobStatus completedJob;
|
final JobStatus completedJob;
|
||||||
if (mVerb == VERB_FINISHED) {
|
if (mVerb == VERB_FINISHED) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
applyStoppedReasonLocked(reason);
|
||||||
completedJob = mRunningJob;
|
completedJob = mRunningJob;
|
||||||
mJobPackageTracker.noteInactive(completedJob);
|
mJobPackageTracker.noteInactive(completedJob);
|
||||||
try {
|
try {
|
||||||
@@ -658,6 +680,13 @@ public class JobServiceContext extends IJobCallback.Stub implements ServiceConne
|
|||||||
mCompletedListener.onJobCompletedLocked(completedJob, reschedule);
|
mCompletedListener.onJobCompletedLocked(completedJob, reschedule);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void applyStoppedReasonLocked(String reason) {
|
||||||
|
if (reason != null && mStoppedReason == null) {
|
||||||
|
mStoppedReason = reason;
|
||||||
|
mStoppedTime = SystemClock.elapsedRealtime();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when sending a message to the client, over whose execution we have no control. If
|
* Called when sending a message to the client, over whose execution we have no control. If
|
||||||
* we haven't received a response in a certain amount of time, we want to give up and carry
|
* we haven't received a response in a certain amount of time, we want to give up and carry
|
||||||
|
|||||||
Reference in New Issue
Block a user