JobSchedulerService启动过程,最主要工作是从jobs.xml文件收集所有的jobs,放入到JobStore的成员变量mJobSet,转成jobinfo。

JobScheduler服务启动

2.1 startOtherServices

[-> SystemServer.java]

private void startOtherServices() {
...
mSystemServiceManager.startService(JobSchedulerService.class);
...
}

该方法先初始化JSS,然后再调用其onStart()方法。

2.2 JobSchedulerService

[-> JobSchedulerService.java]

JobSchedulerService {
List<StateController> mControllers;
final JobHandler mHandler;
final JobSchedulerStub mJobSchedulerStub;
final JobStore mJobs;
... public JobSchedulerService(Context context) {
super(context);
mControllers = new ArrayList<StateController>();
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)); //创建主线程的looper[见小节2.3]
mHandler = new JobHandler(context.getMainLooper());
//创建binder服务端[见小节2.4]
mJobSchedulerStub = new JobSchedulerStub();
//[见小节2.5]
mJobs = JobStore.initAndGet(this);
} public void onStart() {
publishBinderService(Context.JOB_SCHEDULER_SERVICE, mJobSchedulerStub);
}
}

创建了5个不同的StateController,分别添加到mControllers。

类型 说明
ConnectivityController 注册监听网络连接状态的广播
TimeController 注册监听job时间到期的广播
IdleController 注册监听屏幕亮/灭,dream进入/退出,状态改变的广播
BatteryController 注册监听电池是否充电,电量状态的广播
AppIdleController 监听app是否空闲

接下来,以ConnectivityController为例,说一说相应Controller的创建过程, 其他Controller也基本类似.

2.2.1 ConnectivityController

[-> ConnectivityController.java]

public class ConnectivityController extends StateController implements ConnectivityManager.OnNetworkActiveListener {

    public static ConnectivityController get(JobSchedulerService jms) {
synchronized (sCreationLock) {
if (mSingleton == null) {
//单例模式
mSingleton = new ConnectivityController(jms, jms.getContext());
}
return mSingleton;
}
} private ConnectivityController(StateChangedListener stateChangedListener, Context context) {
super(stateChangedListener, context);
//注册监听网络连接状态的广播,且采用BackgroundThread线程
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
mContext.registerReceiverAsUser(
mConnectivityChangedReceiver, UserHandle.ALL, intentFilter, null,
BackgroundThread.getHandler());
ConnectivityService cs =
(ConnectivityService)ServiceManager.getService(Context.CONNECTIVITY_SERVICE);
if (cs != null) {
if (cs.getActiveNetworkInfo() != null) {
mNetworkConnected = cs.getActiveNetworkInfo().isConnected();
}
mNetworkUnmetered = mNetworkConnected && !cs.isActiveNetworkMetered();
}
}
}

当监听到CONNECTIVITY_ACTION广播,onReceive方法的执行位于“android.bg”线程。

2.3 JSS.JobHandler

[-> JobSchedulerService.java ::JobHandler]

public class JobSchedulerService extends com.android.server.SystemService implements StateChangedListener, JobCompletedListener {
private class JobHandler extends Handler { public JobHandler(Looper looper) {
super(looper);
} public void handleMessage(Message message) {
synchronized (mJobs) {
//当系统启动到phase 600,则mReadyToRock=true.
if (!mReadyToRock) {
return;
}
}
switch (message.what) {
case MSG_JOB_EXPIRED: ...
case MSG_CHECK_JOB: ...
}
maybeRunPendingJobsH();
removeMessages(MSG_CHECK_JOB);
}

JobHandler采用的是system_server进程的主线程Looper,也就是该过程运行在主线程。

2.4 JobSchedulerStub

[-> JobSchedulerService.java ::JobSchedulerStub]

final class JobSchedulerStub extends IJobScheduler.Stub {
...
}

JobSchedulerStub作为实现接口IJobScheduler的binder服务端。

2.5 JS.initAndGet

[-> JobStore.java]

static JobStore initAndGet(JobSchedulerService jobManagerService) {
synchronized (sSingletonLock) {
if (sSingleton == null) {
//[见小节2.6]
sSingleton = new JobStore(jobManagerService.getContext(),
Environment.getDataDirectory());
}
return sSingleton;
}
}

2.6 创建JobStore

[-> JobStore.java]

public class JobStore {
final ArraySet<JobStatus> mJobSet;
private final Handler mIoHandler = IoThread.getHandler();
... private JobStore(Context context, File dataDir) {
mContext = context;
mDirtyOperations = 0; File systemDir = new File(dataDir, "system");
File jobDir = new File(systemDir, "job");
jobDir.mkdirs();
// 创建/data/system/job/jobs.xml
mJobsFile = new AtomicFile(new File(jobDir, "jobs.xml"));
mJobSet = new ArraySet<JobStatus>();
//[见小节2.7.1]
readJobMapFromDisk(mJobSet);
}
}

该方法会创建job目录以及jobs.xml文件, 以及从文件中读取所有的JobStatus。

2.7 xml解析

2.7.1 ReadJobMapFromDiskRunnable

[-> JobStore.java]

private class ReadJobMapFromDiskRunnable implements Runnable {
private final ArraySet<JobStatus> jobSet; ReadJobMapFromDiskRunnable(ArraySet<JobStatus> jobSet) {
this.jobSet = jobSet;
} public void run() {
List<JobStatus> jobs;
FileInputStream fis = mJobsFile.openRead();
synchronized (JobStore.this) {
jobs = readJobMapImpl(fis); //[见小节2.7.2]
if (jobs != null) {
for (int i=0; i<jobs.size(); i++) {
this.jobSet.add(jobs.get(i));
}
}
}
fis.close();
}
}

此处mJobsFile便是/data/system/job/jobs.xml。

2.7.2 readJobMapImpl

[-> JobStore.java]

private List<JobStatus> readJobMapImpl(FileInputStream fis)
throws XmlPullParserException, IOException {
XmlPullParser parser = Xml.newPullParser();
parser.setInput(fis, StandardCharsets.UTF_8.name());
... String tagName = parser.getName();
if ("job-info".equals(tagName)) {
final List<JobStatus> jobs = new ArrayList<JobStatus>();
...
eventType = parser.next();
do {
//读取每一个 <job/>
if (eventType == XmlPullParser.START_TAG) {
tagName = parser.getName();
if ("job".equals(tagName)) {
//[见小节2.7.3]
JobStatus persistedJob = restoreJobFromXml(parser);
if (persistedJob != null) {
jobs.add(persistedJob);
}
}
}
eventType = parser.next();
} while (eventType != XmlPullParser.END_DOCUMENT);
return jobs;
}
return null;
}

从文件jobs.xml中读取并创建JobStatus,然后添加到mJobSet.

2.7.3 restoreJobFromXml

[-> JobStore.java]

private JobStatus restoreJobFromXml(XmlPullParser parser) throws XmlPullParserException, IOException {
JobInfo.Builder jobBuilder;
int uid;
//创建用于获取jobInfo的Builder[见小节2.7.4]
jobBuilder = buildBuilderFromXml(parser);
jobBuilder.setPersisted(true);
uid = Integer.valueOf(parser.getAttributeValue(null, "uid"));
... buildConstraintsFromXml(jobBuilder, parser); //读取常量
//读取job执行的两个时间点:delay和deadline
Pair<Long, Long> elapsedRuntimes = buildExecutionTimesFromXml(parser);
...
//[见小节2.8]
return new JobStatus(jobBuilder.build(), uid,
elapsedRuntimes.first, elapsedRuntimes.second);
}

2.7.4 buildBuilderFromXml

[-> JobStore.java]

private JobInfo.Builder buildBuilderFromXml(XmlPullParser parser) throws NumberFormatException {
int jobId = Integer.valueOf(parser.getAttributeValue(null, "jobid"));
String packageName = parser.getAttributeValue(null, "package");
String className = parser.getAttributeValue(null, "class");
ComponentName cname = new ComponentName(packageName, className);
//[见小节2.7.5]
return new JobInfo.Builder(jobId, cname);
}

创建的JobInfo对象,记录着任务的jobid, package, class。

2.7.5 创建JobInfo

[-> JobInfo.java]

public class JobInfo implements Parcelable {
public static final class Builder {
public Builder(int jobId, ComponentName jobService) {
mJobService = jobService;
mJobId = jobId;
}
public JobInfo build() {
mExtras = new PersistableBundle(mExtras);
return new JobInfo(this); //创建JobInfo
}
}
}

2.8 创建JobStatus

[-> JobStatus.java]

public JobStatus(JobInfo job, int uId, long earliestRunTimeElapsedMillis, long latestRunTimeElapsedMillis) {
this(job, uId, 0); this.earliestRunTimeElapsedMillis = earliestRunTimeElapsedMillis;
this.latestRunTimeElapsedMillis = latestRunTimeElapsedMillis;
} private JobStatus(JobInfo job, int uId, int numFailures) {
this.job = job;
this.uId = uId;
this.name = job.getService().flattenToShortString();
this.tag = "*job*/" + this.name;
this.numFailures = numFailures;
}

JobStatus对象记录着任务的jobId, ComponentName, uid以及标签和失败次数信息。

2.9 JSS.onBootPhase

public void onBootPhase(int phase) {
if (PHASE_SYSTEM_SERVICES_READY == phase) {
//阶段500,则开始注册package和use移除的广播监听
final IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_REMOVED);
filter.addDataScheme("package");
getContext().registerReceiverAsUser(
mBroadcastReceiver, UserHandle.ALL, filter, null, null);
final IntentFilter userFilter = new IntentFilter(Intent.ACTION_USER_REMOVED);
userFilter.addAction(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED);
getContext().registerReceiverAsUser(
mBroadcastReceiver, UserHandle.ALL, userFilter, null, null);
mPowerManager = (PowerManager)getContext().getSystemService(Context.POWER_SERVICE);
} else if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) {
synchronized (mJobs) {
mReadyToRock = true;
mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService(
BatteryStats.SERVICE_NAME));
for (int i = 0; i < MAX_JOB_CONTEXTS_COUNT; i++) {
//创建JobServiceContext对象
mActiveServices.add(
new JobServiceContext(this, mBatteryStats,
getContext().getMainLooper()));
}
ArraySet<JobStatus> jobs = mJobs.getJobs();
for (int i=0; i<jobs.size(); i++) {
JobStatus job = jobs.valueAt(i);
for (int controller=0; controller<mControllers.size(); controller++) {
mControllers.get(controller).deviceIdleModeChanged(mDeviceIdleMode);
mControllers.get(controller).maybeStartTrackingJob(job);
}
}
//[见小节3.8]
mHandler.obtainMessage(MSG_CHECK_JOB).sendToTarget();
}
}
}

对于低内存的设备,则只创建一个创建JobServiceContext对象;否则创建3个该对象。

2.9.1 创建JobServiceContext

[-> JobServiceContext.java]

JobServiceContext(JobSchedulerService service, IBatteryStats batteryStats, Looper looper) {
this(service.getContext(), batteryStats, service, looper);
} JobServiceContext(Context context, IBatteryStats batteryStats,
JobCompletedListener completedListener, Looper looper) {
mContext = context;
mBatteryStats = batteryStats;
mCallbackHandler = new JobServiceHandler(looper);
mCompletedListener = completedListener;
mAvailable = true;
}

此处的JobServiceHandler采用的是system_server进程的主线程。

2.10 小结

  1. JSS.JobHandler运行在system_server进程的主线程;
  2. JobServiceContext.JobServiceHandler运行在system_server进程的主线程;
  3. JobSchedulerStub作为实现接口IJobScheduler的binder服务端;
  4. JobStore:其成员变量mIoHandler运行在”android.io”线程;
  5. JobStatus:从/data/system/job/jobs.xml文件中读取每个JobInfo,再解析成JobStatus对象,添加到mJobSet。

JobScheduler调度器过程(JobSchedulerService的启动过程)的更多相关文章

  1. 从Linux启动过程到android启动过程

    Linux启动过程: 1.首先开机给系统供电,此时硬件电路会产生一个确定的复位时序,保证cpu是最后一个被复位的器件.为什么cpu要最后被复位呢?因为 如果cpu第一个被复位,则当cpu复位后开始运行 ...

  2. Linux 启动过程详解

    目录 1. Linux启动过程 2. 启动过程概述 3. 引导加载阶段 4. 内核阶段 4.1 内核加载阶段 4.2 内核启动阶段 5. 早期的用户空间 6. 初始化过程 6.1 SysV init ...

  3. 作业三:LINUX内核的启动过程

    作业三:LINUX内核的启动过程 一.使用GDB跟踪内核从start_kernel到init进程启动(附实验截图) (一)使用自己的Linux系统环境搭建MenuOS的过程 下载内核源代码编译内核 c ...

  4. 分布式事务_02_2PC框架raincat源码解析-启动过程

    一.前言 上一节已经将raincat demo工程运行起来了,这一节来分析下raincat启动过程的源码 主要包括: 事务协调者启动过程 事务参与者启动过程 二.协调者启动过程 主要就是在启动类中通过 ...

  5. Linux 开机引导和启动过程详解

    你是否曾经对操作系统为何能够执行应用程序而感到疑惑?那么本文将为你揭开操作系统引导与启动的面纱. 理解操作系统开机引导和启动过程对于配置操作系统和解决相关启动问题是至关重要的.该文章陈述了 GRUB2 ...

  6. uboot启动过程理解

    对于2440而言,启动的方式不多.一般就是外界一个NAND FLASH ,2440内部有个NAND FLASH Controller,会自动把NAND FLASH的前4K拷贝到2440的片内SRAM. ...

  7. Oracle的启动过程

    在Windows操作系统平台下,可以使用SQL*Plus.OEM和系统服务管理等方式进行数据库的启动与关闭操作.数据库启动分为3个步骤:创建并启动数据库实例.装载数据库和打开数据库.数据库的关闭过程与 ...

  8. PMP--3. 项目启动过程组

    ####################################################### 从第三章开始,我正式进入项目过程,启动.规划.执行.监控.收尾五大过程组的具体在之后依次 ...

  9. Django 源码小剖: URL 调度器(URL dispatcher)

    在刚开始接触 django 的时候, 我们尝试着从各种入门文档中创建一个自己的 django 项目, 需要在 mysite.urls.py 中配置 URL. 这是 django url 匹配处理机制的 ...

随机推荐

  1. linux 安装 ORACLE JDK 8

    1.卸载默认的OPENJDK 查看 open jdk 的安装 rpm -qa | grep java 卸载 openjdk rpm -e --nodeps java-1.7.0-openjdk-1.7 ...

  2. latex字体颜色

    具体的如下:\usepackage{color} 1. {\color{red} 文本} 2. \textcolor[rgb]{1,0,0}{文本}  颜色参数范围为[0,1]

  3. PHP-CGI、FASTCGI和php-fpm的关系

    首先,CGI是干嘛的?CGI是为了保证web server传递过来的数据是标准格式的,方便CGI程序的编写者. web server(比如说nginx)只是内容的分发者.比如,如果请求/index.h ...

  4. Java潜在的坑持续总结

    1.Java里如果有if (foo == 0),如果foo是null这里居然是会抛NPE异常而不是返回false: 2.Java里整形数值不能用==来比较,因为只有区间是[-128,127]的才能这么 ...

  5. 微信小程序踩坑集合

    1:官方工具:https://mp.weixin.qq.com/debug/w ... tml?t=1476434678461 2:简易教程:https://mp.weixin.qq.com/debu ...

  6. MySQL 安装与使用(三)

    操作系统:CentOS release 5.10 (Final) MySQL版本:5.1.72-community 占位学习与编辑中……

  7. crontab和crond分析

    目录 目录 1 1. 研究目的 1 2. 基本概念 1 3. crontab 1 3.1. 编辑 2 3.1.1. "crontab -e"工作流 2 3.2. 问题 3 4. c ...

  8. 如果我写一个开源的HIS软件

    HIS也称为医院信息管理系统,如果我要写一个 开源的,会成吗?为什么要这么做?出于对这个行业的担忧及其当前该行业的一些问题的思考.我曾跟两个HIS供应商讨论过这个话题,但可以感受到他们在利益面前,最终 ...

  9. Android学习指南之三十八:Android手势操作编程[转]

    手势操作在我们使用智能设备的过程中奉献了不一样的体验.Android开发中必然会进行手势操作方面的编程.那么它的原理是怎样的呢?我们如何进行手势操作编程呢? 手势操作原理 首先,在Android系统中 ...

  10. 2017-11-29 由runnable说起Android中的子线程和主线程

    1.首先纠正一个观点,就是runnable运行在子线程中是错误的观念.runnable只是创建了一个执行任务的对象,但是它本身并不会创建一个新的子线程,Runable只是给你接口让你实现工作线程的工作 ...