JobScheduler机制简析
1.概述
JobScheduler主要用于在未来某个时间下满足一定条件时触发执行某项任务的情况,那么可以创建一个JobService的子类,重写其onStartJob()方法来实现这个功能。
JobScheduler提供了接口来调度各种类型的工作,在应用进程中执行。
JobInfo里面包含了很多关于工作的信息,可以将JobInfo传递给JobScheduler的schedule()方法。当声明的条件满足时,系统将会在应用进程中执行该工作。
当在创建JobInfo时,可以指定使用哪个JobService来执行工作。
Framework会知道你什么时候接收回调,并且尽可能尝试批量和延迟执行这些工作。典型的,如果你没有特别声明一个工作截止期限,那么工作将可能在任何时候被执行,这个依赖于JobScheduler内部队列的当前状态。然而,工作也可能被延迟到下一次设备连接到电源时执行。
JobScheduler不能直接初始化,而应该通过Context.getSystemService(Context.JOB_SCHEDULER_SERVICE)方法获取。
JobScheduler的定义如下:
public abstract class JobScheduler {
/*
* schedule(JobInfo)的返回值;
* 当输入参数无效时,则返回RESULT_FAILURE。这种情况会出现在工作执行时间太短了,或者系统不能解析JobService服务。
*/
public static final int RESULT_FAILURE = 0;
/*
* schedule(JobInfo)的返回值;
* 如果该工作被成功执行后,返回RESULT_SUCCESS。
*/
public static final int RESULT_SUCCESS = 1;
public abstract int schedule(JobInfo job);
public abstract int scheduleAsPackage(JobInfo job, String packageName, int userId, String tag);
public abstract void cancel(int jobId);
public abstract void cancelAll();
public abstract @NonNull List<JobInfo> getAllPendingJobs();
public abstract @Nullable JobInfo getPendingJob(int jobId);
}
JobScheduler是一个抽象类,具体的实现类是JobSchedulerImpl类。
2.JobScheduler服务的初始化
JobScheduler服务的启动是从SystemServer的startOtherServices()方法开始的。
private void startOtherServices() {
......
mSystemServiceManager.startService(JobSchedulerService.class);
......
}
JobSchedulerService服务继承自SystemService服务,在被启动的时候,会执行onStart()方法。
2.1 SystemServiceManager.startService()
public <T extends SystemService> T startService(Class<T> serviceClass) {
try {
final String name = serviceClass.getName();
// Create the service.
......
final T service;
try {
Constructor<T> constructor = serviceClass.getConstructor(Context.class);
service = constructor.newInstance(mContext);//获取构造器
} catch (InstantiationException ex) {
......
}
// Register it.
mServices.add(service);
// Start it.
try {
service.onStart();//调用服务的onStart()方法
} catch (RuntimeException ex) {
throw new RuntimeException("Failed to start service " + name
+ ": onStart threw an exception", ex);
}
return service;
} finally {
Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
}
}
可以看到,SystemServiceManager的startService()方法的主要作用是创建一个服务对象实例,并调用服务对象实例的onStart()方法。
2.2 JobSchedulerService.onStart()
public void onStart() {
publishLocalService(JobSchedulerInternal.class, new LocalService());//将JobSchedulerService里的LocalService发布到本地服务中,只能被system进程访问该服务
publishBinderService(Context.JOB_SCHEDULER_SERVICE, mJobSchedulerStub);//发布jobscheduler服务,这样其他服务和应用可以访问该服务
}
在onStart()方法中,主要是完成以下两件事情:
- 将JobSchedulerService里的LocalService发布到本地服务中,该服务只能被system进程访问;
- 将jobscheduler服务发布到SystemManager中,这样其他服务和应用可以访问该服务。
LocalService对应的实现如下:
final class LocalService implements JobSchedulerInternal {
/**
* Returns a list of all pending jobs. A running job is not considered pending. Periodic
* jobs are always considered pending.
*/
@Override
public List<JobInfo> getSystemScheduledPendingJobs() {
synchronized (mLock) {
final List<JobInfo> pendingJobs = new ArrayList<JobInfo>();
mJobs.forEachJob(Process.SYSTEM_UID, new JobStatusFunctor() {
@Override
public void process(JobStatus job) {
if (job.getJob().isPeriodic() || !isCurrentlyActiveLocked(job)) {
pendingJobs.add(job.getJob());
}
}
});
return pendingJobs;
}
}
}
LocalService实现了JobSchedulerInternal接口,主要是返回所有待处理的工作。该服务是添加到本地服务列表中的,只能被system进程访问。
jobscheduler服务对应的实现是mJobSchedulerStub,它是在构建JobSchedulerService服务时被初始化的。
2.3 JobSchedulerService()
public JobSchedulerService(Context context) {
super(context);
mHandler = new JobHandler(context.getMainLooper());//构建一个主线程的Handler
mConstants = new Constants(mHandler);
mJobSchedulerStub = new JobSchedulerStub();//初始化JobSchedulerStub
mJobs = JobStore.initAndGet(this);//初始化JobStore,见2.4
// Create the controllers.
mControllers = new ArrayList<StateController>();
mControllers.add(ConnectivityController.get(this));//创建连接状态Controller
mControllers.add(TimeController.get(this));//创建时间Controller
mControllers.add(IdleController.get(this));//创建空闲Controller
mControllers.add(BatteryController.get(this));//创建电池状态Controller
mControllers.add(AppIdleController.get(this));//创建应用空闲Controller
mControllers.add(ContentObserverController.get(this));
mControllers.add(DeviceIdleJobsController.get(this));//创建设备空闲Controller
}
JobSchedulerStub继承了IJobScheduler.Stub类,作为实现接口IJobScheduler的binder服务端。
2.4 JobStore.initAndGet()
static JobStore initAndGet(JobSchedulerService jobManagerService) {
//单例模式
synchronized (sSingletonLock) {
if (sSingleton == null) {
sSingleton = new JobStore(jobManagerService.getContext(),
jobManagerService.getLock(), Environment.getDataDirectory());//见2.5
}
return sSingleton;
}
}
JobStore的构造采取的是单例模式,全局只会创建一个对象实例。
2.5 JobStore()
private JobStore(Context context, Object lock, File dataDir) {
mLock = lock;
mContext = context;
mDirtyOperations = 0;
File systemDir = new File(dataDir, "system");//system目录
File jobDir = new File(systemDir, "job");//job目录
jobDir.mkdirs();
mJobsFile = new AtomicFile(new File(jobDir, "jobs.xml"));// 创建一个jobs.xml文件
mJobSet = new JobSet();//创建一个JobSet对象
readJobMapFromDisk(mJobSet);//见2.6
}
在构造JobStore的时候,会创建一个jobs.xml文件,并创建一个JobSet对象,里面保存的是一个JobStatus的集合,最后将磁盘中的数据读取到JobSet对象中。这里的mJobsFile就是/data/system/job/jobs.xml。
2.6 JobStore.readJobMapFromDisk()
public void readJobMapFromDisk(JobSet jobSet) {
new ReadJobMapFromDiskRunnable(jobSet).run();
}
@Override
public void run() {
try {
List<JobStatus> jobs;
FileInputStream fis = mJobsFile.openRead();//打开JobsFile
synchronized (mLock) {
jobs = readJobMapImpl(fis);//借助XmlPullParser,从输入文件流中读取Job状态信息
if (jobs != null) {
for (int i=0; i<jobs.size(); i++) {
this.jobSet.add(jobs.get(i));//将JobStatus添加到JobSet中
}
}
}
fis.close();
} catch (FileNotFoundException e) {
......
}
}
readJobMapFromDisk方法主要是将磁盘文件中的Job状态信息读取到内存中,并通过XmlPullParser解析xml文件信息,将Job相关信息逐步封装成JobInfo——>JobStatus——>JobStore,最后保存在JobSchedulerService服务中。
在JobSchedulerService中保存了与工作相关的JobStore,然后JobStore又保存了JobSet,在JobSet中保存了一个JobStatus的集合,在每个JobStatus中都有一个JobInfo,在JobInfo里面保存了与工作相关的信息,例如jobId,service。他们之间的类图关系如下:
在创建JobSchedulerService的时候,初始化了7个StateController,这些Controller分别控制不同触发条件。
public abstract class StateController {
protected final Context mContext;
protected final Object mLock;
protected final StateChangedListener mStateChangedListener;
public StateController(StateChangedListener stateChangedListener, Context context,
Object lock) {
mStateChangedListener = stateChangedListener;
mContext = context;
mLock = lock;
}
......
}
以ConnectivityController为例,来描述Controller的初始化过程。
2.7 ConnectivityController.get()
public static ConnectivityController get(JobSchedulerService jms) {
synchronized (sC