JobScheduler实现机制分析
系统服务是怎么初始化的?
系统的Service,如VibratorService、JobSchedulerService,这些后端的服务是怎么完成初始的。
我们一般在使用时,是通过context里的方法:
context.getSystemService("serviceName");
来获取可以与后端服务交互的对象。
系统服务的初始化时在SystemServer
里的操作的,在android启动时,执行main函数:
public static void main(String[] args) {
new SystemServer().run();
}
在run()方法里,有启动服务的功能:
private void run() {
...
// Start services.
try {
traceBeginAndSlog("StartServices");
startBootstrapServices();
startCoreServices();
startOtherServices();
SystemServerInitThreadPool.shutdown();
} catch (Throwable ex) {
Slog.e("System", "******************************************");
Slog.e("System", "************ Failure starting system services", ex);
throw ex;
} finally {
traceEnd();
}
...
}
在这里会启动3种service,这里主要关注的是coreService和otherService。而我们的JobSchedulerService就是在otherService。
private void startOtherServices() {
...
mSystemServiceManager.startService(JobSchedulerService.class);
...
}
系统服务的架构
- SystemService:抽象类,所有的服务都需要继承于此,定义了服务的生命周期
- XXXXService:具体的服务类
- SystemServiceManager:服务的管理类,负责服务的创建、启动等生命周期。
SystemService的生命周期
- 带有Context参数的构造函数实现服务的初始化
- 触发
onStart()
,使得Service进入运行状态。- 【必须】子类需要将它的实现Ibinder接口发布出去,通过调用
publishBinderService()
方法 - 【可选】如果需要在SystemServer进程中的其他服务可以访问到,则可以发布local接口
- 【必须】子类需要将它的实现Ibinder接口发布出去,通过调用
onBootPhase()
会被触发多次,直到PHASE_BOOT_COMPLETED
被触发,这是最后的boot阶段。在每个阶段,子类都是可以做不同的事情的。
ServiceManager & LocalServices
- ServiceManager: 跟上面的
publishBinderService
对应,将服务发布出去 - LocalServices: 跟上面的
publishLocalService
对应
ServiceManager发布出去的服务是可以被其他services和apps访问的;而LocalServices的只能在当前system进程可以被访问。
JobScheduler
构造函数
public JobSchedulerService(Context context) {
super(context);
mHandler = new JobHandler(context.getMainLooper());
mConstants = new Constants(mHandler);
mJobSchedulerStub = new JobSchedulerStub();
mJobs = JobStore.initAndGet(this);
// Create the controllers.
mControllers = new ArrayList<StateController>();
mControllers.add(ConnectivityController.get(this));
mControllers.add(TimeController.get(this));
mControllers.add(IdleController.get(this));
mBatteryController = BatteryController.get(this);
mControllers.add(mBatteryController);
mStorageController = StorageController.get(this);
mControllers.add(mStorageController);
mControllers.add(AppIdleController.get(this));
mControllers.add(ContentObserverController.get(this));
mControllers.add(DeviceIdleJobsController.get(this));
}
StateController相关
JobScheduler创建了7个不同的StateController:
- ConnectivityController:注册监听网络连接状态的广播
- TimeController:注册监听job时间到期的广播
- IdleController:注册监听屏幕亮/灭,dream进入/退出,状态改变的广播
- BatteryController:注册监听电池是否充电,电量状态的广播
- AppIdleController:监听app是否空闲
- ContentObserverController: 监控content uirs的变化状态
- DeviceIdleJobsController:设备是否dozing的状态
整个的框架结构:
JobStore
创建job目录以及jobs.xml文件, 以及从文件中读取所有的JobStatus。
这个是job持久化的关键!!!
/data/system/job/jobs.xml
:
<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
<job-info version="0">
<job jobid="101" package="com.sankuai.meituan" class="com.dianping.base.push.pushservice.PushWakeUpJob" uid="10200">
<constraints connectivity="true" />
<periodic period="120000" deadline="1519043029250" delay="1519042909250" />
<extras />
</job>
<job jobid="800" package="android" class="com.android.server.pm.BackgroundDexOptService" uid="1000">
<constraints idle="true" charging="true" />
<one-off />
<extras />
</job>
<job jobid="0" package="com.example.android.jobscheduler" class="com.example.android.jobscheduler.service.MyJobService" uid="10215">
<constraints connectivity="true" />
<one-off deadline="1519221169404" delay="1519221154404" />
<extras>
<long name="com.example.android.jobscheduler.WORK_DURATION_KEY" value="2000" />
</extras>
</job>
</job-info>
onStart()
@Override
public void onStart() {
publishLocalService(JobSchedulerInternal.class, new LocalService());
publishBinderService(Context.JOB_SCHEDULER_SERVICE, mJobSchedulerStub);
}
同时发布了Binder服务和Local服务。
schedule
SystemServiceRegistry.java
这个的主要作用就是管理所有的system services,从而在通过Context#getSystemService()
调用时可以获取对应的服务。
ContextImpl.java:
@Override
public Object getSystemService(String name) {
return SystemServiceRegistry.getSystemService(this, name);
}
@Override
public String getSystemServiceName(Class<?> serviceClass) {
return SystemServiceRegistry.getSystemServiceName(serviceClass);
}
SystemServiceRegistry注册服务:
registerService(Context.JOB_SCHEDULER_SERVICE, JobScheduler.class,
new StaticServiceFetcher<JobScheduler>() {
@Override
public JobScheduler createService() throws ServiceNotFoundException {
IBinder b = ServiceManager.getServiceOrThrow(Context.JOB_SCHEDULER_SERVICE);
return new JobSchedulerImpl(IJobScheduler.Stub.asInterface(b));
}});
所以返回的job服务是JobSchedulerImpl对象。JobSchedulerImpl对象继承于JobScheduler对象。
@Override
public int schedule(JobInfo job) {
try {
return mBinder.schedule(job);
} catch (RemoteException e) {
return JobScheduler.RESULT_FAILURE;
}
}
可见,当app端调用JobSchedulerImpl的schedule()过程,通过binder call进入了system_server的binder线程。
这样其实调用到了JSS里的JobSchedulerStub对象。
final class JobSchedulerStub extends IJobScheduler.Stub {
@Override
public int schedule(JobInfo job) throws RemoteException {
long ident = Binder.clearCallingIdentity();
try {
return JobSchedulerService.this.scheduleAsPackage(job, null, uid, null, -1, null);
} finally {
Binder.restoreCallingIdentity(ident);
}
}
}
然后最主要的就是JSS里的startTrackingJobLocked()方法:
private void startTrackingJobLocked(JobStatus jobStatus, JobStatus lastJob) {
if (!jobStatus.isPreparedLocked()) {
Slog.wtf(TAG, "Not yet prepared when started tracking: " + jobStatus);
}
jobStatus.enqueueTime = SystemClock.elapsedRealtime();
final boolean update = mJobs.add(jobStatus);
if (mReadyToRock) {
for (int i = 0; i < mControllers.size(); i++) {
StateController controller = mControllers.get(i);
if (update) {
controller.maybeStopTrackingJobLocked(jobStatus, null, true);
}
controller.maybeStartTrackingJobLocked(jobStatus, lastJob);
}
}
}
先将该JobStatus添加到JobStore,再遍历已添加的各个状态控制器, 依次检查是否需要将该任务添加到相应的追踪控制器。
。。。。
Cancel
流程跟上面的schedule差不多。