Use the android.app.job.JobInfo.Builder to configure how the scheduled task should run. You can schedule the task to run under specific conditions, such as:
@Override public Object getSystemService(String name) { return SystemServiceRegistry.getSystemService(this, name); }[SystemServiceRegistry.java]---getSystemService()
/** * Manages all of the system services that can be returned by {@link Context#getSystemService}. * Used by {@link ContextImpl}. */
final class SystemServiceRegistry {
static{ .................. registerService(Context.JOB_SCHEDULER_SERVICE, JobScheduler.class, new StaticServiceFetcher() { @Override public JobScheduler createService() { IBinder b = ServiceManager.getService(Context.JOB_SCHEDULER_SERVICE); return new JobSchedulerImpl(IJobScheduler.Stub.asInterface(b)); }});
..................
}
/** * Gets a system service from a given context. */ public static Object getSystemService(ContextImpl ctx, String name) { ServiceFetcher> fetcher = SYSTEM_SERVICE_FETCHERS.get(name); return fetcher != null ? fetcher.getService(ctx) : null; }
// IJobScheduler implementation @Override public int schedule(JobInfo job) throws RemoteException { if (DEBUG) { Slog.d(TAG, "Scheduling job: " + job.toString()); } final int pid = Binder.getCallingPid(); final int uid = Binder.getCallingUid(); enforceValidJobRequest(uid, job);//一些合法性的检查 if (job.isPersisted()) { if (!canPersistJobs(pid, uid)) { throw new IllegalArgumentException("Error: requested job be persisted without" + " holding RECEIVE_BOOT_COMPLETED permission.");//手机重启job是否有效权限检验 } } long ident = Binder.clearCallingIdentity(); try { return JobSchedulerService.this.schedule(job, uid); } finally { Binder.restoreCallingIdentity(ident); } }schedule方法具体实现,应用程序将自己的job在这里交给系统调度执行
/**
* Entry point from client to schedule the provided job.
* This cancels the job if it's already been scheduled, and replaces it with the one provided.
* @param job JobInfo object containing execution parameters//应用程序JobService中定义的job
* @param uId The package identifier of the application this job is for.//该Job来自那个应用程序
* @return Result of this operation. See
JobScheduler#RESULT_* return codes.
*/
public int schedule(JobInfo job, int uId) {
JobStatus jobStatus = new JobStatus(job, uId);
cancelJob(uId, job.getId());
try {
if (ActivityManagerNative.getDefault().getAppStartMode(uId,
job.getService().getPackageName()) == ActivityManager.APP_START_MODE_DISABLED) {
Slog.w(TAG, "Not scheduling job " + uId + ":" + job.toString()//该Job所在的package是否被disable掉
+ " -- package not allowed to start");
return JobScheduler.RESULT_FAILURE;
}
} catch (RemoteException e) {
}
startTrackingJob(jobStatus);
mHandler.obtainMessage(MSG_CHECK_JOB).sendToTarget();
return JobScheduler.RESULT_SUCCESS;
}
/** * Called when we have a job status object that we need to insert in our * {@link com.android.server.job.JobStore}, and make sure all the relevant controllers know * about. */ private void startTrackingJob(JobStatus jobStatus) { boolean update; boolean rocking; synchronized (mJobs) { update = mJobs.add(jobStatus); rocking = mReadyToRock; } if (rocking) { for (int i=0; i<mControllers.size(); i++) { StateController controller = mControllers.get(i); if (update) { controller.maybeStopTrackingJob(jobStatus);//如果当前job更换了以前的一个job,则停止追踪以前的job } controller.maybeStartTrackingJob(jobStatus);//继续追踪新的job } } }开始追踪该job,从源码中可以看到追踪job的实质是 循环获取所有控制器,并回调控制器的开始追踪方法。关于控制器在JobSchedulerService的构造中我们可以看到,在构造方法中初始化了所有的控制器,每个控制器对应创建job时的每个条件
public JobSchedulerService(Context context) { super(context); // Create the controllers. mControllers = new ArrayList(); mControllers.add(ConnectivityController.get(this)); mControllers.add(TimeController.get(this)); mControllers.add(IdleController.get(this)); mControllers.add(BatteryController.get(this)); mControllers.add(AppIdleController.get(this)); mHandler = new JobHandler(context.getMainLooper()); mJobSchedulerStub = new JobSchedulerStub(); mJobs = JobStore.initAndGet(this); }
private class JobHandler extends Handler { public JobHandler(Looper looper) { super(looper); } @Override public void handleMessage(Message message) { synchronized (mJobs) { if (!mReadyToRock) { return; } } switch (message.what) { case MSG_JOB_EXPIRED: synchronized (mJobs) { JobStatus runNow = (JobStatus) message.obj; // runNow can be null, which is a controller's way of indicating that its // state is such that all ready jobs should be run immediately. if (runNow != null && !mPendingJobs.contains(runNow) && mJobs.containsJob(runNow)) { mPendingJobs.add(runNow); } queueReadyJobsForExecutionLockedH(); } break; case MSG_CHECK_JOB: synchronized (mJobs) { // Check the list of jobs and run some of them if we feel inclined. maybeQueueReadyJobsForExecutionLockedH();//检查是否有可执行的job } break; case MSG_STOP_JOB: cancelJobImpl((JobStatus)message.obj); break; } maybeRunPendingJobsH(); // Don't remove JOB_EXPIRED in case one came along while processing the queue. removeMessages(MSG_CHECK_JOB); }maybeRunPendingJobsH();该方法中才真正决定是否要执行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 * here is where we decide whether to actually execute it. */ private void maybeRunPendingJobsH() { if (availableContext != null) { if (!availableContext.executeRunnableJob(nextPending)) { if (DEBUG) { Slog.d(TAG, "Error executing " + nextPending); } mJobs.remove(nextPending); } it.remove(); } }executeRunnableJob(nextPending)具体执行
boolean executeRunnableJob(JobStatus job) { .................... final Intent intent = new Intent().setComponent(job.getServiceComponent()); boolean binding = mContext.bindServiceAsUser(intent, this, Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND, new UserHandle(job.getUserId())); ........................ } }到这里最终通过mContext.bindServiceAsUser绑定了到了我们自定义的JobService,然后回调OnStartJob最终调度我们的方法执行
oneway interface IJobService { /** Begin execution of application's job. */ void startJob(in JobParameters jobParams); /** Stop execution of application's job. */ void stopJob(in JobParameters jobParams); }