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