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接口
  • 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差不多。

results matching ""

    No results matching ""