Loading core/java/android/app/job/JobScheduler.java +11 −2 Original line number Diff line number Diff line Loading @@ -21,14 +21,23 @@ import java.util.List; import android.content.Context; /** * Class for scheduling various types of jobs with the scheduling framework on the device. * This is an API for scheduling various types of jobs against the framework that will be executed * in your application's own process. * <p> * See {@link android.app.job.JobInfo} for more description of the types of jobs that can be run * and how to construct them. * and how to construct them. You will construct these JobInfo objects and pass them to the * JobScheduler with {@link #schedule(JobInfo)}. When the criteria declared are met, the * system will execute this job on your application's {@link android.app.job.JobService}. * You identify which JobService is meant to execute the logic for your job when you create the * JobInfo with {@link android.app.job.JobInfo.Builder#Builder(int, android.content.ComponentName)}. * </p> * <p> * The framework will be intelligent about when you receive your callbacks, and attempt to batch * and defer them as much as possible. Typically if you don't specify a deadline on your job, it * can be run at any moment depending on the current state of the JobScheduler's internal queue, * however it might be deferred as long as until the next time the device is connected to a power * source. * </p> * <p>You do not * instantiate this class directly; instead, retrieve it through * {@link android.content.Context#getSystemService Loading services/core/java/com/android/server/job/JobSchedulerService.java +17 −6 Original line number Diff line number Diff line Loading @@ -199,9 +199,6 @@ public class JobSchedulerService extends com.android.server.SystemService List<JobStatus> jobsForUser = mJobs.getJobsByUser(userHandle); for (int i=0; i<jobsForUser.size(); i++) { JobStatus toRemove = jobsForUser.get(i); if (DEBUG) { Slog.d(TAG, "Cancelling: " + toRemove); } cancelJobLocked(toRemove); } } Loading @@ -219,9 +216,6 @@ public class JobSchedulerService extends com.android.server.SystemService List<JobStatus> jobsForUid = mJobs.getJobsByUid(uid); for (int i=0; i<jobsForUid.size(); i++) { JobStatus toRemove = jobsForUid.get(i); if (DEBUG) { Slog.d(TAG, "Cancelling: " + toRemove); } cancelJobLocked(toRemove); } } Loading Loading @@ -547,14 +541,28 @@ public class JobSchedulerService extends com.android.server.SystemService private void queueReadyJobsForExecutionH() { synchronized (mJobs) { ArraySet<JobStatus> jobs = mJobs.getJobs(); if (DEBUG) { Slog.d(TAG, "queuing all ready jobs for execution:"); } for (int i=0; i<jobs.size(); i++) { JobStatus job = jobs.valueAt(i); if (isReadyToBeExecutedLocked(job)) { if (DEBUG) { Slog.d(TAG, " queued " + job.toShortString()); } mPendingJobs.add(job); } else if (isReadyToBeCancelledLocked(job)) { stopJobOnServiceContextLocked(job); } } if (DEBUG) { final int queuedJobs = mPendingJobs.size(); if (queuedJobs == 0) { Slog.d(TAG, "No jobs pending."); } else { Slog.d(TAG, queuedJobs + " jobs queued."); } } } } Loading Loading @@ -657,6 +665,9 @@ public class JobSchedulerService extends com.android.server.SystemService private void maybeRunPendingJobsH() { synchronized (mJobs) { Iterator<JobStatus> it = mPendingJobs.iterator(); if (DEBUG) { Slog.d(TAG, "pending queue: " + mPendingJobs.size() + " jobs."); } while (it.hasNext()) { JobStatus nextPending = it.next(); JobServiceContext availableContext = null; Loading services/core/java/com/android/server/job/JobServiceContext.java +36 −37 Original line number Diff line number Diff line Loading @@ -157,6 +157,7 @@ public class JobServiceContext extends IJobCallback.Stub implements ServiceConne mExecutionStartTimeElapsed = SystemClock.elapsedRealtime(); mVerb = VERB_BINDING; scheduleOpTimeOut(); final Intent intent = new Intent().setComponent(job.getServiceComponent()); boolean binding = mContext.bindServiceAsUser(intent, this, Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND, Loading Loading @@ -253,8 +254,6 @@ public class JobServiceContext extends IJobCallback.Stub implements ServiceConne return; } this.service = IJobService.Stub.asInterface(service); // Remove all timeouts. mCallbackHandler.removeMessages(MSG_TIMEOUT); final PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, mRunningJob.getTag()); Loading Loading @@ -299,6 +298,7 @@ public class JobServiceContext extends IJobCallback.Stub implements ServiceConne public void handleMessage(Message message) { switch (message.what) { case MSG_SERVICE_BOUND: removeMessages(MSG_TIMEOUT); handleServiceBoundH(); break; case MSG_CALLBACK: Loading Loading @@ -337,6 +337,9 @@ public class JobServiceContext extends IJobCallback.Stub implements ServiceConne /** Start the job on the service. */ private void handleServiceBoundH() { if (DEBUG) { Slog.d(TAG, "MSG_SERVICE_BOUND for " + mRunningJob.toShortString()); } if (mVerb != VERB_BINDING) { Slog.e(TAG, "Sending onStartJob for a job that isn't pending. " + VERB_STRINGS[mVerb]); Loading Loading @@ -456,42 +459,36 @@ public class JobServiceContext extends IJobCallback.Stub implements ServiceConne /** Process MSG_TIMEOUT here. */ private void handleOpTimeoutH() { if (JobSchedulerService.DEBUG) { Slog.d(TAG, "MSG_TIMEOUT of " + mRunningJob.getServiceComponent().getShortClassName() + " : " + mParams.getJobId()); } final int jobId = mParams.getJobId(); switch (mVerb) { case VERB_BINDING: Slog.e(TAG, "Time-out while trying to bind " + mRunningJob.toShortString() + ", dropping."); closeAndCleanupJobH(false /* needsReschedule */); break; case VERB_STARTING: // Client unresponsive - wedged or failed to respond in time. We don't really // know what happened so let's log it and notify the JobScheduler // FINISHED/NO-RETRY. Slog.e(TAG, "No response from client for onStartJob '" + mRunningJob.getServiceComponent().getShortClassName() + "' jId: " + jobId); mRunningJob.toShortString()); closeAndCleanupJobH(false /* needsReschedule */); 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.getServiceComponent().getShortClassName() + "' jId: " + jobId); mRunningJob.toShortString()); closeAndCleanupJobH(true /* needsReschedule */); 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.getServiceComponent().getShortClassName() + "' jId: " + jobId); " sending onStop. " + mRunningJob.toShortString()); sendStopMessageH(); break; default: Slog.e(TAG, "Handling timeout for an unknown active job state: " + mRunningJob); return; Slog.e(TAG, "Handling timeout for an invalid job state: " + mRunningJob.toShortString() + ", dropping."); closeAndCleanupJobH(false /* needsReschedule */); } } Loading Loading @@ -530,7 +527,9 @@ public class JobServiceContext extends IJobCallback.Stub implements ServiceConne } catch (RemoteException e) { // Whatever. } if (mWakeLock != null) { mWakeLock.release(); } mContext.unbindService(JobServiceContext.this); mWakeLock = null; mRunningJob = null; Loading @@ -547,6 +546,7 @@ public class JobServiceContext extends IJobCallback.Stub implements ServiceConne removeMessages(MSG_SHUTDOWN_EXECUTION); mCompletedListener.onJobCompleted(completedJob, reschedule); } } /** * Called when sending a message to the client, over whose execution we have no control. If Loading @@ -568,4 +568,3 @@ public class JobServiceContext extends IJobCallback.Stub implements ServiceConne mTimeoutElapsed = SystemClock.elapsedRealtime() + timeoutMillis; } } } Loading
core/java/android/app/job/JobScheduler.java +11 −2 Original line number Diff line number Diff line Loading @@ -21,14 +21,23 @@ import java.util.List; import android.content.Context; /** * Class for scheduling various types of jobs with the scheduling framework on the device. * This is an API for scheduling various types of jobs against the framework that will be executed * in your application's own process. * <p> * See {@link android.app.job.JobInfo} for more description of the types of jobs that can be run * and how to construct them. * and how to construct them. You will construct these JobInfo objects and pass them to the * JobScheduler with {@link #schedule(JobInfo)}. When the criteria declared are met, the * system will execute this job on your application's {@link android.app.job.JobService}. * You identify which JobService is meant to execute the logic for your job when you create the * JobInfo with {@link android.app.job.JobInfo.Builder#Builder(int, android.content.ComponentName)}. * </p> * <p> * The framework will be intelligent about when you receive your callbacks, and attempt to batch * and defer them as much as possible. Typically if you don't specify a deadline on your job, it * can be run at any moment depending on the current state of the JobScheduler's internal queue, * however it might be deferred as long as until the next time the device is connected to a power * source. * </p> * <p>You do not * instantiate this class directly; instead, retrieve it through * {@link android.content.Context#getSystemService Loading
services/core/java/com/android/server/job/JobSchedulerService.java +17 −6 Original line number Diff line number Diff line Loading @@ -199,9 +199,6 @@ public class JobSchedulerService extends com.android.server.SystemService List<JobStatus> jobsForUser = mJobs.getJobsByUser(userHandle); for (int i=0; i<jobsForUser.size(); i++) { JobStatus toRemove = jobsForUser.get(i); if (DEBUG) { Slog.d(TAG, "Cancelling: " + toRemove); } cancelJobLocked(toRemove); } } Loading @@ -219,9 +216,6 @@ public class JobSchedulerService extends com.android.server.SystemService List<JobStatus> jobsForUid = mJobs.getJobsByUid(uid); for (int i=0; i<jobsForUid.size(); i++) { JobStatus toRemove = jobsForUid.get(i); if (DEBUG) { Slog.d(TAG, "Cancelling: " + toRemove); } cancelJobLocked(toRemove); } } Loading Loading @@ -547,14 +541,28 @@ public class JobSchedulerService extends com.android.server.SystemService private void queueReadyJobsForExecutionH() { synchronized (mJobs) { ArraySet<JobStatus> jobs = mJobs.getJobs(); if (DEBUG) { Slog.d(TAG, "queuing all ready jobs for execution:"); } for (int i=0; i<jobs.size(); i++) { JobStatus job = jobs.valueAt(i); if (isReadyToBeExecutedLocked(job)) { if (DEBUG) { Slog.d(TAG, " queued " + job.toShortString()); } mPendingJobs.add(job); } else if (isReadyToBeCancelledLocked(job)) { stopJobOnServiceContextLocked(job); } } if (DEBUG) { final int queuedJobs = mPendingJobs.size(); if (queuedJobs == 0) { Slog.d(TAG, "No jobs pending."); } else { Slog.d(TAG, queuedJobs + " jobs queued."); } } } } Loading Loading @@ -657,6 +665,9 @@ public class JobSchedulerService extends com.android.server.SystemService private void maybeRunPendingJobsH() { synchronized (mJobs) { Iterator<JobStatus> it = mPendingJobs.iterator(); if (DEBUG) { Slog.d(TAG, "pending queue: " + mPendingJobs.size() + " jobs."); } while (it.hasNext()) { JobStatus nextPending = it.next(); JobServiceContext availableContext = null; Loading
services/core/java/com/android/server/job/JobServiceContext.java +36 −37 Original line number Diff line number Diff line Loading @@ -157,6 +157,7 @@ public class JobServiceContext extends IJobCallback.Stub implements ServiceConne mExecutionStartTimeElapsed = SystemClock.elapsedRealtime(); mVerb = VERB_BINDING; scheduleOpTimeOut(); final Intent intent = new Intent().setComponent(job.getServiceComponent()); boolean binding = mContext.bindServiceAsUser(intent, this, Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND, Loading Loading @@ -253,8 +254,6 @@ public class JobServiceContext extends IJobCallback.Stub implements ServiceConne return; } this.service = IJobService.Stub.asInterface(service); // Remove all timeouts. mCallbackHandler.removeMessages(MSG_TIMEOUT); final PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, mRunningJob.getTag()); Loading Loading @@ -299,6 +298,7 @@ public class JobServiceContext extends IJobCallback.Stub implements ServiceConne public void handleMessage(Message message) { switch (message.what) { case MSG_SERVICE_BOUND: removeMessages(MSG_TIMEOUT); handleServiceBoundH(); break; case MSG_CALLBACK: Loading Loading @@ -337,6 +337,9 @@ public class JobServiceContext extends IJobCallback.Stub implements ServiceConne /** Start the job on the service. */ private void handleServiceBoundH() { if (DEBUG) { Slog.d(TAG, "MSG_SERVICE_BOUND for " + mRunningJob.toShortString()); } if (mVerb != VERB_BINDING) { Slog.e(TAG, "Sending onStartJob for a job that isn't pending. " + VERB_STRINGS[mVerb]); Loading Loading @@ -456,42 +459,36 @@ public class JobServiceContext extends IJobCallback.Stub implements ServiceConne /** Process MSG_TIMEOUT here. */ private void handleOpTimeoutH() { if (JobSchedulerService.DEBUG) { Slog.d(TAG, "MSG_TIMEOUT of " + mRunningJob.getServiceComponent().getShortClassName() + " : " + mParams.getJobId()); } final int jobId = mParams.getJobId(); switch (mVerb) { case VERB_BINDING: Slog.e(TAG, "Time-out while trying to bind " + mRunningJob.toShortString() + ", dropping."); closeAndCleanupJobH(false /* needsReschedule */); break; case VERB_STARTING: // Client unresponsive - wedged or failed to respond in time. We don't really // know what happened so let's log it and notify the JobScheduler // FINISHED/NO-RETRY. Slog.e(TAG, "No response from client for onStartJob '" + mRunningJob.getServiceComponent().getShortClassName() + "' jId: " + jobId); mRunningJob.toShortString()); closeAndCleanupJobH(false /* needsReschedule */); 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.getServiceComponent().getShortClassName() + "' jId: " + jobId); mRunningJob.toShortString()); closeAndCleanupJobH(true /* needsReschedule */); 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.getServiceComponent().getShortClassName() + "' jId: " + jobId); " sending onStop. " + mRunningJob.toShortString()); sendStopMessageH(); break; default: Slog.e(TAG, "Handling timeout for an unknown active job state: " + mRunningJob); return; Slog.e(TAG, "Handling timeout for an invalid job state: " + mRunningJob.toShortString() + ", dropping."); closeAndCleanupJobH(false /* needsReschedule */); } } Loading Loading @@ -530,7 +527,9 @@ public class JobServiceContext extends IJobCallback.Stub implements ServiceConne } catch (RemoteException e) { // Whatever. } if (mWakeLock != null) { mWakeLock.release(); } mContext.unbindService(JobServiceContext.this); mWakeLock = null; mRunningJob = null; Loading @@ -547,6 +546,7 @@ public class JobServiceContext extends IJobCallback.Stub implements ServiceConne removeMessages(MSG_SHUTDOWN_EXECUTION); mCompletedListener.onJobCompleted(completedJob, reschedule); } } /** * Called when sending a message to the client, over whose execution we have no control. If Loading @@ -568,4 +568,3 @@ public class JobServiceContext extends IJobCallback.Stub implements ServiceConne mTimeoutElapsed = SystemClock.elapsedRealtime() + timeoutMillis; } } }