之前有篇文章专门介绍了JobScheduler的使用,这里再大致说下:
如果想在将来达到一定条件下执行某项任务时,可以在一个实现了JobService的子类的onStartJob方法中执行这项任务,使用JobInfo的Builder方法来设定条件并和实现了JobService的子类的组件名绑定,然后调用系统服务JobScheduler的schedule方法。这样,即便在执行任务之前应用程序进程被杀,也不会导致任务不会执行,因为系统服务JobScheduler会使用bindServiceAsUser的方法把实现了JobService的子类服务启动起来,并执行它的onStartJob方法。
由于JobSchedulerService是系统服务,故这里按照启动流程和使用流程分开分析源码,下面先看下启动流程的时序图:
由于JobSchedulerService的构造方法中执行的操作比较多,时序图中没有详细画出。
Zygote进程启动后会启动System进程,在System进程启动过程中会启动系统中的关键服务,如AMS、PMS以及这里要用到的JobSchedulerService等。
SystemServer启动JobSchedulerService服务调用的是SystemServiceManager类的startService方法:
private void startOtherServices() {
. . .
if (mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL) {
// 开启JobSchedulerService服务
mSystemServiceManager.startService(JobSchedulerService.class);
. . .
}
}
看下SystemServiceManager类的startService方法的具体操作:
private final ArrayList mServices = new ArrayList();
/**
* 创建并启动一个继承自SystemService类的系统服务。
*
* @param 一个继承自SystemService类的服务类
* @return 服务类的实例
* @throws 如果服务启动失败则抛RuntimeException异常
*/
@SuppressWarnings("unchecked")
public T startService(Class serviceClass) {
// 获取服务类的类名
final String name = serviceClass.getName();
Slog.i(TAG, "Starting " + name);
// 判断服务类是否是SystemService的子类
if (!SystemService.class.isAssignableFrom(serviceClass)) {
throw new RuntimeException("Failed to create " + name
+ ": service must extend " + SystemService.class.getName());
}
final T service;
try {
// 获取服务类包含一个Context参数的构造方法
Constructor constructor = serviceClass.getConstructor(Context.class);
// 创建这个服务类的实例
service = constructor.newInstance(mContext);
} catch (InstantiationException ex) {
throw new RuntimeException("Failed to create service " + name
+ ": service could not be instantiated", ex);
} catch (IllegalAccessException ex) {
throw new RuntimeException("Failed to create service " + name
+ ": service must have a public constructor with a Context argument", ex);
} catch (NoSuchMethodException ex) {
throw new RuntimeException("Failed to create service " + name
+ ": service must have a public constructor with a Context argument", ex);
} catch (InvocationTargetException ex) {
throw new RuntimeException("Failed to create service " + name
+ ": service constructor threw an exception", ex);
}
// 把服务添加到mServices列表中,方便后续使用时取出
mServices.add(service);
try {
// 回调服务的onStart方法
service.onStart();
} catch (RuntimeException ex) {
throw new RuntimeException("Failed to start service " + name
+ ": onStart threw an exception", ex);
}
return service;
}
在开启JobSchedulerService服务时,会创建该服务的实例,来看下该服务的创建过程:
// 任务状态控制器列表
List mControllers;
final JobHandler mHandler;
final JobSchedulerStub mJobSchedulerStub;
// 任务主列表
final JobStore mJobs;
public JobSchedulerService(Context context) {
super(context);
// 创建控制器
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));
// 初始化JobHandler,主要处理任务到期和检查任务的消息
mHandler = new JobHandler(context.getMainLooper());
// 初始化mJobSchedulerStub
mJobSchedulerStub = new JobSchedulerStub();
// 初始化JobStore并返回从data/system/job/jobs.xml文件中读取的永久性任务
mJobs = JobStore.initAndGet(this);
}
由上面代码可以看出,创建服务有下面几个步骤:
1.初始化各种控制器并添加到列表中
2.初始化JobHandler
3.初始化JobSchedulerStub代理对象
4.初始化任务主列表
下面按顺序分析上面几个步骤:
1.初始化各种控制器并添加到列表中:
抽象类StateController:
public abstract class StateController {
protected static final boolean DEBUG = JobSchedulerService.DEBUG;
protected Context mContext;
protected StateChangedListener mStateChangedListener;
protected boolean mDeviceIdleMode;
public StateController(StateChangedListener stateChangedListener, Context context) {
mStateChangedListener = stateChangedListener;
mContext = context;
}
public void deviceIdleModeChanged(boolean enabled) {
mDeviceIdleMode = enabled;
}
/**
* 该方法中实现控制器添加追踪任务的逻辑
*/
public abstract void maybeStartTrackingJob(JobStatus jobStatus);
/**
* 如果任务被取消、执行完成等则remove掉该任务
*/
public abstract void maybeStopTrackingJob(JobStatus jobStatus);
public abstract void dumpControllerState(PrintWriter pw);
}
接口StateChangedListener:
public interface StateChangedListener {
/**
* 控制器调用该方法通知JobManager该检查某项任务的状态
*/
public void onControllerStateChanged();
/**
* 控制器调用该方法通知JobManager执行该项任务
* @param jobStatus 直接执行任务,null表示刷新所有准备好的任务
*/
public void onRunJobNow(JobStatus jobStatus);
}
说明:第三方应用使用JobInfo设置任务信息时会调用maybeStartTrackingJob方法,如果设置了该控制器相关的控制项时,就会把该任务添加到追踪列表中。后面会分析任务的添加过程。
下面按JobSchedulerService的构造方法中添加控制器的顺序分析各个控制器的实现原理:
1.ConnectivityController:
该控制器的大致实现流程:
初始化该控制器时,动态注册接收网络变化的广播,并给mNetworkConnected变量和mNetworkUnmetered变量赋初值,收到广播后会修改这两个参数的值并调用updateTrackedJobs方法,该方法主要是遍历保存在追踪列表中的任务,查看是否有任务的两个参数值相对于之前保存的值有变化,如果有则调用mStateChangedListener监听器的onControllerStateChanged()方法通知JobSchedulerService约束任务的条件状态发生改变,这里的mStateChangedListener就是构造方法传递来的JobSchedulerService的实例。由于控制器实现了ConnectivityManage.OnNetworkActiveListener接口,故当网络可用时会调用该接口中的onNetworkActive方法,在该方法中会调用监听器的onRunJobNow方法通知JobSchedulerService执行任务。
下面看下代码实现部分:
public class ConnectivityController extends StateController implements
ConnectivityManager.OnNetworkActiveListener {
private static final String TAG = "JobScheduler.Conn";
// 追踪任务状态列表
private final List mTrackedJobs = new LinkedList();
// 网络变化的广播
private final BroadcastReceiver mConnectivityChangedReceiver =
new ConnectivityChangedReceiver();
/** Singleton. */
private static ConnectivityController mSingleton;
private static Object sCreationLock = new Object();
/** 追踪最新活动网络是否可计量(网络连接是否收费) */
private boolean mNetworkUnmetered;
/** 追踪最新活动网络是否已经连接 */
private boolean mNetworkConnected;
// 单例模式获取实例
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);
// 注册接收网络变化的广播
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
mContext.registerReceiverAsUser(
mConnectivityChangedReceiver, UserHandle.ALL, intentFilter, null, null);
ConnectivityService cs =
(ConnectivityService)ServiceManager.getService(Context.CONNECTIVITY_SERVICE);
if (cs != null) {
if (cs.getActiveNetworkInfo() != null) {
// 给网络连接变量赋值
mNetworkConnected = cs.getActiveNetworkInfo().isConnected();
}
// 给不可计量变量赋值
mNetworkUnmetered = mNetworkConnected && !cs.isActiveNetworkMetered();
}
}
@Override
public void maybeStartTrackingJob(JobStatus jobStatus) {
// 任务是否有连接约束或不可计量约束。说明:任务的约束是通过JobInfo的builder方法设置的
if (jobStatus.hasConnectivityConstraint() || jobStatus.hasUnmeteredConstraint()) {
synchronized (mTrackedJobs) {
jobStatus.connectivityConstraintSatisfied.set(mNetworkConnected);
jobStatus.unmeteredConstraintSatisfied.set(mNetworkUnmetered);
// 把任务添加到追踪列表中
mTrackedJobs.add(jobStatus);
}
}
}
@Override
public void maybeStopTrackingJob(JobStatus jobStatus) {
if (jobStatus.hasConnectivityConstraint() || jobStatus.hasUnmeteredConstraint()) {
synchronized (mTrackedJobs) {
// 把任务从列表中移除
mTrackedJobs.remove(jobStatus);
}
}
}
/**
* @param userId Id of the user for whom we are updating the connectivity state.
*/
private void updateTrackedJobs(int userId) {
synchronized (mTrackedJobs) {
boolean changed = false;
// 遍历保存在mTrackedJobs列表中的任务
for (JobStatus js : mTrackedJobs) {
if (js.getUserId() != userId) {
continue;
}
// getAndSet方法返回上次保存的值,并把新值替换旧值保存
boolean prevIsConnected =
js.connectivityConstraintSatisfied.getAndSet(mNetworkConnected);
boolean prevIsMetered = js.unmeteredConstraintSatisfied.getAndSet(mNetworkUnmetered);
// 如果本次的mNetworkConnected或mNetworkUnmetered与上一次保存的值不一样,则设置changed为true
if (prevIsConnected != mNetworkConnected || prevIsMetered != mNetworkUnmetered) {
changed = true;
}
}
// 如果changed为true,则调用监听器(即JobSchedulerService)的onControllerStateChanged方法
if (changed) {
mStateChangedListener.onControllerStateChanged();
}
}
}
// 该方法是OnNetworkActiveListener接口中的方法,网络可用时调用该方法
public synchronized void onNetworkActive() {
synchronized (mTrackedJobs) {
for (JobStatus js : mTrackedJobs) {
// 判断该任务的所有约束条件是否都已得到满足
if (js.isReady()) {
if (DEBUG) {
Slog.d(TAG, "Running " + js + " due to network activity.");
}
// 调用监听器的onRunJobNow方法执行任务
mStateChangedListener.onRunJobNow(js);
}
}
}
}
class ConnectivityChangedReceiver extends BroadcastReceiver {
// TODO: Test whether this will be called twice for each user.
@Override
public void onReceive(Context context, Intent intent) {
if (DEBUG) {
Slog.d(TAG, "Received connectivity event: " + intent.getAction() + " u"
+ context.getUserId());
}
final String action = intent.getAction();
if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
// 取出广播传递来的网络连接类型
final int networkType =
intent.getIntExtra(ConnectivityManager.EXTRA_NETWORK_TYPE,
ConnectivityManager.TYPE_NONE);
// Connectivity manager for THIS context - important!
final ConnectivityManager connManager = (ConnectivityManager)
context.getSystemService(Context.CONNECTIVITY_SERVICE);
final NetworkInfo activeNetwork = connManager.getActiveNetworkInfo();
final int userid = context.getUserId();
// This broadcast gets sent a lot, only update if the active network has changed.
// 网络不可用
if (activeNetwork == null) {
mNetworkUnmetered = false;
mNetworkConnected = false;
// 更新追踪任务
updateTrackedJobs(userid);
// 判断当前激活的网络连接类型是否和广播传递来的网络连接类型相同
} else if (activeNetwork.getType() == networkType) {
mNetworkUnmetered = false;
mNetworkConnected = !intent.getBooleanExtra(
ConnectivityManager.EXTRA_NO_CONNECTIVITY, false);
if (mNetworkConnected) { // No point making the call if we know there's no conn.
mNetworkUnmetered = !connManager.isActiveNetworkMetered();
}
// 更新追踪任务
updateTrackedJobs(userid);
}
} else {
if (DEBUG) {
Slog.d(TAG, "Unrecognised action in intent: " + action);
}
}
}
};
@Override
public void dumpControllerState(PrintWriter pw) {
pw.println("Conn.");
pw.println("connected: " + mNetworkConnected + " unmetered: " + mNetworkUnmetered);
for (JobStatus js: mTrackedJobs) {
pw.println(String.valueOf(js.hashCode()).substring(0, 3) + ".."
+ ": C=" + js.hasConnectivityConstraint()
+ ", UM=" + js.hasUnmeteredConstraint());
}
}
}
2.TimeController
由于该控制器跟任务执行时间相关,故调用maybeStartTrackingJob方法添加任务时会根据任务执行时间点插入到追踪列表中,并更新下一个要执行任务的执行时间点。
该控制器的大致实现流程:
初始化控制器时,初始化任务的deadline到期和延迟到期时发送广播的操作,动态注册这两个广播,根据接收到不同的广播执行不同的检查机制:
遍历检查任务的延迟时间是否已经到期,如果有任务的延迟时间到期并且所有的约束都得到满足时,调用mStateChangedListener监听器的onControllerStateChanged方法;
或者检查任务追踪列表中是否有deadline过期导致该任务需要执行,如果有则调用mStateChangedListener监听器的onRunJobNow方法。
下面看下代码实现部分:
/**
* 该类为下一个到期任务设置一个alarm,并确定任务的最小延迟是否已经满足
*/
public class TimeController extends StateController {
private static final String TAG = "JobScheduler.Time";
private static final String ACTION_JOB_EXPIRED =
"android.content.jobscheduler.JOB_DEADLINE_EXPIRED";
private static final String ACTION_JOB_DELAY_EXPIRED =
"android.content.jobscheduler.JOB_DELAY_EXPIRED";
/** 任务的deadline到期时执行的操作. */
private final PendingIntent mDeadlineExpiredAlarmIntent;
/** 任务的延迟时间到期时执行的操作. */
private final PendingIntent mNextDelayExpiredAlarmIntent;
private long mNextJobExpiredElapsedMillis;
private long mNextDelayExpiredElapsedMillis;
private AlarmManager mAlarmService = null;
/** 按任务执行时间点从小到大的顺序排列的任务列表 */
private final List mTrackedJobs = new LinkedList();
/** Singleton. */
private static TimeController mSingleton;
public static synchronized TimeController get(JobSchedulerService jms) {
if (mSingleton == null) {
mSingleton = new TimeController(jms, jms.getContext());
}
return mSingleton;
}
private TimeController(StateChangedListener stateChangedListener, Context context) {
super(stateChangedListener, context);
// 任务的deadline到期时会发送一个ACTION_JOB_EXPIRED广播
mDeadlineExpiredAlarmIntent =
PendingIntent.getBroadcast(mContext, 0 /* ignored */,
new Intent(ACTION_JOB_EXPIRED), 0);
// 任务的延迟时间到期时会发送一个ACTION_JOB_DELAY_EXPIRED广播
mNextDelayExpiredAlarmIntent =
PendingIntent.getBroadcast(mContext, 0 /* ignored */,
new Intent(ACTION_JOB_DELAY_EXPIRED), 0);
// 初始化下一个将要执行的任务的到期时间和延迟时间都为最大长整形
mNextJobExpiredElapsedMillis = Long.MAX_VALUE;
mNextDelayExpiredElapsedMillis = Long.MAX_VALUE;
// 注册广播
IntentFilter intentFilter = new IntentFilter(ACTION_JOB_EXPIRED);
intentFilter.addAction(ACTION_JOB_DELAY_EXPIRED);
mContext.registerReceiver(mAlarmExpiredReceiver, intentFilter);
}
/**
* 把设置了时间约束的任务,根据任务执行时间点插入到列表中正确的位置
*/
@Override
public synchronized void maybeStartTrackingJob(JobStatus job) {
// 判断任务是否有延迟约束或deadline约束
if (job.hasTimingDelayConstraint() || job.hasDeadlineConstraint()) {
maybeStopTrackingJob(job);
// 插入操作
boolean isInsert = false;
ListIterator it = mTrackedJobs.listIterator(mTrackedJobs.size());
// 从列表后面往前遍历,如果前一个任务的执行时间点小于该任务的执行时间点则插入该任务
while (it.hasPrevious()) {
JobStatus ts = it.previous();
if (ts.getLatestRunTimeElapsed() < job.getLatestRunTimeElapsed()) {
// Insert
isInsert = true;
break;
}
}
if(isInsert)
{
// 获取要插入该任务的位置
it.next();
}
// 插入该任务
it.add(job);
// 更新下一个将要执行任务的alarm时间
maybeUpdateAlarms(
job.hasTimingDelayConstraint() ? job.getEarliestRunTime() : Long.MAX_VALUE,
job.hasDeadlineConstraint() ? job.getLatestRunTimeElapsed() : Long.MAX_VALUE);
}
}
/**
* 停止追踪任务时,只需要更新alarm
*/
@Override
public synchronized void maybeStopTrackingJob(JobStatus job) {
if (mTrackedJobs.remove(job)) {
// 检查延迟alarm
checkExpiredDelaysAndResetAlarm();
// 检查deadline的alarm
checkExpiredDeadlinesAndResetAlarm();
}
}
/**
* 任务的约束得到满足后,控制器不再追踪该任务
*/
private boolean canStopTrackingJob(JobStatus job) {
return (!job.hasTimingDelayConstraint() ||
job.timeDelayConstraintSatisfied.get()) &&
(!job.hasDeadlineConstraint() ||
job.deadlineConstraintSatisfied.get());
}
private void ensureAlarmService() {
if (mAlarmService == null) {
mAlarmService = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
}
}
/**
* 检查任务追踪列表是否有该执行的任务
*/
private synchronized void checkExpiredDeadlinesAndResetAlarm() {
long nextExpiryTime = Long.MAX_VALUE;
// 获取手机开机时间
final long nowElapsedMillis = SystemClock.elapsedRealtime();
Iterator it = mTrackedJobs.iterator();
while (it.hasNext()) {
JobStatus job = it.next();
// 如果任务没有设置deadline约束,则跳过本次循环
if (!job.hasDeadlineConstraint()) {
continue;
}
// 获取任务下一次执行的时间
final long jobDeadline = job.getLatestRunTimeElapsed();
// 如果任务的下一次执行时间小于手机运行时间,则设置任务的deadline已经得到满足,并运行该任务
if (jobDeadline <= nowElapsedMillis) {
job.deadlineConstraintSatisfied.set(true);
mStateChangedListener.onRunJobNow(job);
it.remove();
} else { // Sorted by expiry time, so take the next one and stop.
nextExpiryTime = jobDeadline;
break;
}
}
// 更新下一个将要执行任务的deadline时间
setDeadlineExpiredAlarm(nextExpiryTime);
}
/**
* 遍历检查任务的延迟时间是否已经到期
*/
private synchronized void checkExpiredDelaysAndResetAlarm() {
// 获取手机当前运行时间
final long nowElapsedMillis = SystemClock.elapsedRealtime();
long nextDelayTime = Long.MAX_VALUE;
boolean ready = false;
Iterator it = mTrackedJobs.iterator();
while (it.hasNext()) {
final JobStatus job = it.next();
// 如果任务没有设置延迟约束则跳过本次循环
if (!job.hasTimingDelayConstraint()) {
continue;
}
// 获取任务的最早执行时间
final long jobDelayTime = job.getEarliestRunTime();
// 判断任务的最早执行时间是否小于等于开机时间
if (jobDelayTime <= nowElapsedMillis) {
// 设置任务的延迟已经得到满足
job.timeDelayConstraintSatisfied.set(true);
// 判断任务是否可以停止追踪
if (canStopTrackingJob(job)) {
it.remove();
}
if (job.isReady()) {
ready = true;
}
} else { // Keep going through list to get next delay time.
// 如果任务的最早执行时间小于最大长整形,则更新nextDelayTime变量为最早执行任务的时间
if (nextDelayTime > jobDelayTime) {
nextDelayTime = jobDelayTime;
}
}
}
// 如果任务的约束条件都得到满足,则调用监听器(即JobSchedulerService)的onControllerStateChanged方法
if (ready) {
mStateChangedListener.onControllerStateChanged();
}
// 更新下一个将要执行任务的延迟过期时间
setDelayExpiredAlarm(nextDelayTime);
}
private void maybeUpdateAlarms(long delayExpiredElapsed, long deadlineExpiredElapsed) {
// 如果该任务的延迟过期时间小于下一个将要执行的任务的延迟过期时间,则更新下一个将要执行任务的延迟过期时间
if (delayExpiredElapsed < mNextDelayExpiredElapsedMillis) {
setDelayExpiredAlarm(delayExpiredElapsed);
}
// 如果该任务的deadline时间小于下一个将要执行的任务的deadline时间,则更新下一个将要执行任务的deadline时间
if (deadlineExpiredElapsed < mNextJobExpiredElapsedMillis) {
setDeadlineExpiredAlarm(deadlineExpiredElapsed);
}
}
/**
* 用AlarmManager为下一个将要执行的任务设置一个alarm,该alarm不会唤醒手机
*/
private void setDelayExpiredAlarm(long alarmTimeElapsedMillis) {
// 调整alarm时间,如果alarm时间设置不对则调整
alarmTimeElapsedMillis = maybeAdjustAlarmTime(alarmTimeElapsedMillis);
// 更新下一个将要执行任务的延迟过期时间
mNextDelayExpiredElapsedMillis = alarmTimeElapsedMillis;
// 更新执行任务延迟时间到期操作的时间
updateAlarmWithPendingIntent(mNextDelayExpiredAlarmIntent, mNextDelayExpiredElapsedMillis);
}
/**
* 用AlarmManager为deadline将要到期的任务设置一个alarm,该alarm将会唤醒手机
*/
private void setDeadlineExpiredAlarm(long alarmTimeElapsedMillis) {
// 调整alarm时间,如果alarm时间设置不对则调整
alarmTimeElapsedMillis = maybeAdjustAlarmTime(alarmTimeElapsedMillis);
// 更新下一个将要执行任务的deadline到期时间
mNextJobExpiredElapsedMillis = alarmTimeElapsedMillis;
// 更新执行任务deadline到期操作的时间
updateAlarmWithPendingIntent(mDeadlineExpiredAlarmIntent, mNextJobExpiredElapsedMillis);
}
// 调整alarm时间,如果alarm时间设置不对则调整
private long maybeAdjustAlarmTime(long proposedAlarmTimeElapsedMillis) {
final long earliestWakeupTimeElapsed = SystemClock.elapsedRealtime();
// 如果设置值小于开机时间则返回开机时间,因为AlarmManager的set方法只能设置比开机时间晚的时间点
if (proposedAlarmTimeElapsedMillis < earliestWakeupTimeElapsed) {
return earliestWakeupTimeElapsed;
}
return proposedAlarmTimeElapsedMillis;
}
// 更新执行pi的alarm时间
private void updateAlarmWithPendingIntent(PendingIntent pi, long alarmTimeElapsed) {
ensureAlarmService();
// 如果传递过来的时间是最大长整形,则取消该PendingIntent
if (alarmTimeElapsed == Long.MAX_VALUE) {
mAlarmService.cancel(pi);
} else {
if (DEBUG) {
Slog.d(TAG, "Setting " + pi.getIntent().getAction() + " for: " + alarmTimeElapsed);
}
// 否则更新pi的执行时间,AlarmManager的set方法是设置在alarmTimeElapsed时间启动pi指定的组件
mAlarmService.set(AlarmManager.ELAPSED_REALTIME, alarmTimeElapsed, pi);
}
}
private final BroadcastReceiver mAlarmExpiredReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (DEBUG) {
Slog.d(TAG, "Just received alarm: " + intent.getAction());
}
// 根据接收到广播的Action检查不同的alarm
if (ACTION_JOB_EXPIRED.equals(intent.getAction())) {
checkExpiredDeadlinesAndResetAlarm();
} else if (ACTION_JOB_DELAY_EXPIRED.equals(intent.getAction())) {
checkExpiredDelaysAndResetAlarm();
}
}
};
@Override
public void dumpControllerState(PrintWriter pw) {
final long nowElapsed = SystemClock.elapsedRealtime();
pw.println("Alarms (" + SystemClock.elapsedRealtime() + ")");
pw.println(
"Next delay alarm in " + (mNextDelayExpiredElapsedMillis - nowElapsed)/1000 + "s");
pw.println("Next deadline alarm in " + (mNextJobExpiredElapsedMillis - nowElapsed)/1000
+ "s");
pw.println("Tracking:");
for (JobStatus ts : mTrackedJobs) {
pw.println(String.valueOf(ts.hashCode()).substring(0, 3) + ".."
+ ": (" + (ts.hasTimingDelayConstraint() ? ts.getEarliestRunTime() : "N/A")
+ ", " + (ts.hasDeadlineConstraint() ?ts.getLatestRunTimeElapsed() : "N/A")
+ ")");
}
}
}
3.IdleController:
该控制器的大致实现流程:
初始化该控制器时,动态注册监听息屏/亮屏,进入休眠/退出休眠以及进入空闲状态的广播。
收到亮屏/退出休眠广播时,设置mScreenOn为true,并取消空闲时发送空闲广播的PendingIntent,如果mIdle为true,则修改为false,并上报空闲状态改变,遍历追踪任务,设置任务的空闲满足状态为isIdle,并调用mStateChangedListener监听器的onControllerStateChanged方法;
收到息屏/进入休眠广播时设置mScreenOn为false,并设置一个在开机时间+息屏/进入休眠阈值的时间点、IDLE_WINDOW_SLOP时间窗内触发的发送进入空闲状态的广播;
收到进入空闲状态广播时,符合(!mIdle && !mScreenOn)判断时,设置mIdle为true,并上报新的空闲状态,遍历追踪任务,设置任务的空闲满足状态为isIdle,并调用mStateChangedListener监听器的onControllerStateChanged方法。
下面看下代码实现部分:
public class IdleController extends StateController {
private static final String TAG = "IdleController";
// 息屏或休眠阈值
private static final long INACTIVITY_IDLE_THRESHOLD = 71 * 60 * 1000; // millis; 71 min
// 触发发送广播的时间窗
private static final long IDLE_WINDOW_SLOP = 5 * 60 * 1000; // 5 minute window, to be nice
private static final String ACTION_TRIGGER_IDLE =
"com.android.server.task.controllers.IdleController.ACTION_TRIGGER_IDLE";
final ArrayList mTrackedTasks = new ArrayList();
IdlenessTracker mIdleTracker;
// Singleton factory
private static Object sCreationLock = new Object();
private static volatile IdleController sController;
public static IdleController get(JobSchedulerService service) {
synchronized (sCreationLock) {
if (sController == null) {
sController = new IdleController(service, service.getContext());
}
return sController;
}
}
private IdleController(StateChangedListener stateChangedListener, Context context) {
super(stateChangedListener, context);
// 初始化空闲状态追踪
initIdleStateTracking();
}
/**
* StateController interface
*/
@Override
public void maybeStartTrackingJob(JobStatus taskStatus) {
// 判断任务是否设置了空闲约束
if (taskStatus.hasIdleConstraint()) {
synchronized (mTrackedTasks) {
// 把任务添加到追踪任务列表
mTrackedTasks.add(taskStatus);
// 获取当前手机状态并设置任务的空闲约束满足状态
taskStatus.idleConstraintSatisfied.set(mIdleTracker.isIdle());
}
}
}
@Override
public void maybeStopTrackingJob(JobStatus taskStatus) {
synchronized (mTrackedTasks) {
mTrackedTasks.remove(taskStatus);
}
}
/**
* 上报新的空闲状态
*/
void reportNewIdleState(boolean isIdle) {
synchronized (mTrackedTasks) {
// 遍历追踪任务,设置任务的空闲满足状态为isIdle
for (JobStatus task : mTrackedTasks) {
task.idleConstraintSatisfied.set(isIdle);
}
}
// 调用监听器的onControllerStateChanged方法
mStateChangedListener.onControllerStateChanged();
}
/**
* 空闲状态追踪,当状态发生改变时通知任务管理器
*/
private void initIdleStateTracking() {
// 初始化空闲状态追踪器广播
mIdleTracker = new IdlenessTracker();
// 注册广播开始追踪
mIdleTracker.startTracking();
}
class IdlenessTracker extends BroadcastReceiver {
private AlarmManager mAlarm;
private PendingIntent mIdleTriggerIntent;
boolean mIdle;
boolean mScreenOn;
public IdlenessTracker() {
mAlarm = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(ACTION_TRIGGER_IDLE)
.setPackage("android")
.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
// 初始化发送ACTION_TRIGGER_IDLE广播的延迟Intent
mIdleTriggerIntent = PendingIntent.getBroadcast(mContext, 0, intent, 0);
// 开机时假设用户刚使用过手机
mIdle = false;
mScreenOn = true;
}
public boolean isIdle() {
return mIdle;
}
public void startTracking() {
IntentFilter filter = new IntentFilter();
// Screen state
filter.addAction(Intent.ACTION_SCREEN_ON);
filter.addAction(Intent.ACTION_SCREEN_OFF);
// Dreaming state
filter.addAction(Intent.ACTION_DREAMING_STARTED);
filter.addAction(Intent.ACTION_DREAMING_STOPPED);
// Debugging/instrumentation
filter.addAction(ACTION_TRIGGER_IDLE);
// 注册广播
mContext.registerReceiver(this, filter);
}
@Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
if (action.equals(Intent.ACTION_SCREEN_ON)
|| action.equals(Intent.ACTION_DREAMING_STOPPED)) {
if (DEBUG) {
Slog.v(TAG,"exiting idle : " + action);
}
mScreenOn = true;
//cancel the alarm
mAlarm.cancel(mIdleTriggerIntent);
if (mIdle) {
// possible transition to not-idle
mIdle = false;
// 上报新的空闲状态
reportNewIdleState(mIdle);
}
} else if (action.equals(Intent.ACTION_SCREEN_OFF)
|| action.equals(Intent.ACTION_DREAMING_STARTED)) {
final long nowElapsed = SystemClock.elapsedRealtime();
// 开机时间+息屏/进入休眠阈值
final long when = nowElapsed + INACTIVITY_IDLE_THRESHOLD;
if (DEBUG) {
Slog.v(TAG, "Scheduling idle : " + action + " now:" + nowElapsed + " when="
+ when);
}
mScreenOn = false;
// 设置一个在时间窗内触发的mIdleTriggerIntent。类似于set方法,只不过setWindow允许系统调整触发任务的时间。
mAlarm.setWindow(AlarmManager.ELAPSED_REALTIME_WAKEUP,
when, IDLE_WINDOW_SLOP, mIdleTriggerIntent);
} else if (action.equals(ACTION_TRIGGER_IDLE)) {
// idle time starts now. Do not set mIdle if screen is on.
if (!mIdle && !mScreenOn) {
if (DEBUG) {
Slog.v(TAG, "Idle trigger fired @ " + SystemClock.elapsedRealtime());
}
mIdle = true;
reportNewIdleState(mIdle);
}
}
}
}
@Override
public void dumpControllerState(PrintWriter pw) {
synchronized (mTrackedTasks) {
pw.print("Idle: ");
pw.println(mIdleTracker.isIdle() ? "true" : "false");
pw.println(mTrackedTasks.size());
for (int i = 0; i < mTrackedTasks.size(); i++) {
final JobStatus js = mTrackedTasks.get(i);
pw.print(" ");
pw.print(String.valueOf(js.hashCode()).substring(0, 3));
pw.println("..");
}
}
}
}
4.BatteryController:
该控制器的大致实现流程:
初始化该控制器时,动态注册监听电量低/电量OK,充电/非充电的广播。
收到电量低的广播时,设置mBatteryHealthy为false;
收到电量OK的广播时,设置mBatteryHealthy为true,并上报新的充电状态:如果是否可以开始执行任务的状态发生变化,则调用监听器的onControllerStateChanged方法,如果可以开始执行任务,则刷新所有准备好的任务;
收到充电/非充电广播时,分别设置mCharging为true/false,并上报新的充电状态。
下面看下代码实现部分:
/**
* 追踪手机是否在充电的简单控制器,如果手机充电超过两分钟,则系统会发送ACTION_BATTERY_OK广播
*/
public class BatteryController extends StateController {
private static final String TAG = "JobScheduler.Batt";
private static final Object sCreationLock = new Object();
private static volatile BatteryController sController;
private List mTrackedTasks = new ArrayList();
private ChargingTracker mChargeTracker;
public static BatteryController get(JobSchedulerService taskManagerService) {
synchronized (sCreationLock) {
if (sController == null) {
sController = new BatteryController(taskManagerService,
taskManagerService.getContext());
}
}
return sController;
}
@VisibleForTesting
public ChargingTracker getTracker() {
return mChargeTracker;
}
@VisibleForTesting
public static BatteryController getForTesting(StateChangedListener stateChangedListener,
Context context) {
return new BatteryController(stateChangedListener, context);
}
private BatteryController(StateChangedListener stateChangedListener, Context context) {
super(stateChangedListener, context);
// 初始化充电追踪器广播
mChargeTracker = new ChargingTracker();
// 注册广播开始追踪
mChargeTracker.startTracking();
}
@Override
public void maybeStartTrackingJob(JobStatus taskStatus) {
// 获取当前手机是否在充电并且可以开始执行任务
final boolean isOnStablePower = mChargeTracker.isOnStablePower();
// 判断任务是否设置了充电约束
if (taskStatus.hasChargingConstraint()) {
synchronized (mTrackedTasks) {
// 添加任务到追踪列表
mTrackedTasks.add(taskStatus);
// 设置任务的充电满足状态为isOnStablePower
taskStatus.chargingConstraintSatisfied.set(isOnStablePower);
}
}
}
@Override
public void maybeStopTrackingJob(JobStatus taskStatus) {
if (taskStatus.hasChargingConstraint()) {
synchronized (mTrackedTasks) {
mTrackedTasks.remove(taskStatus);
}
}
}
// 上报新的充电状态
private void maybeReportNewChargingState() {
final boolean stablePower = mChargeTracker.isOnStablePower();
if (DEBUG) {
Slog.d(TAG, "maybeReportNewChargingState: " + stablePower);
}
boolean reportChange = false;
synchronized (mTrackedTasks) {
for (JobStatus ts : mTrackedTasks) {
// 获取任务上一次的是否可以开始执行任务的判断
boolean previous = ts.chargingConstraintSatisfied.getAndSet(stablePower);
// 如果是否可以开始执行任务的状态发生变化
if (previous != stablePower) {
reportChange = true;
}
}
}
// 如果是否可以开始执行任务的状态发生变化,则调用监听器的onControllerStateChanged方法
if (reportChange) {
mStateChangedListener.onControllerStateChanged();
}
// 如果可以开始执行任务,则刷新所有准备好的任务
if (stablePower) {
mStateChangedListener.onRunJobNow(null);
}
}
public class ChargingTracker extends BroadcastReceiver {
private boolean mCharging;
private boolean mBatteryHealthy;
public ChargingTracker() {
}
public void startTracking() {
IntentFilter filter = new IntentFilter();
// Battery health.
filter.addAction(Intent.ACTION_BATTERY_LOW);
filter.addAction(Intent.ACTION_BATTERY_OKAY);
// Charging/not charging.
filter.addAction(BatteryManager.ACTION_CHARGING);
filter.addAction(BatteryManager.ACTION_DISCHARGING);
// 注册广播
mContext.registerReceiver(this, filter);
// 初始化追踪器状态
BatteryManagerInternal batteryManagerInternal =
LocalServices.getService(BatteryManagerInternal.class);
mBatteryHealthy = !batteryManagerInternal.getBatteryLevelLow();
mCharging = batteryManagerInternal.isPowered(BatteryManager.BATTERY_PLUGGED_ANY);
}
// 判断是否可以开始执行任务
boolean isOnStablePower() {
return mCharging && mBatteryHealthy;
}
@Override
public void onReceive(Context context, Intent intent) {
onReceiveInternal(intent);
}
@VisibleForTesting
public void onReceiveInternal(Intent intent) {
final String action = intent.getAction();
if (Intent.ACTION_BATTERY_LOW.equals(action)) {
if (DEBUG) {
Slog.d(TAG, "Battery life too low to do work. @ "
+ SystemClock.elapsedRealtime());
}
// If we get this action, the battery is discharging => it isn't plugged in so
// there's no work to cancel. We track this variable for the case where it is
// charging, but hasn't been for long enough to be healthy.
mBatteryHealthy = false;
} else if (Intent.ACTION_BATTERY_OKAY.equals(action)) {
if (DEBUG) {
Slog.d(TAG, "Battery life healthy enough to do work. @ "
+ SystemClock.elapsedRealtime());
}
mBatteryHealthy = true;
// 上报新的充电状态
maybeReportNewChargingState();
} else if (BatteryManager.ACTION_CHARGING.equals(action)) {
if (DEBUG) {
Slog.d(TAG, "Received charging intent, fired @ "
+ SystemClock.elapsedRealtime());
}
mCharging = true;
// 上报新的充电状态
maybeReportNewChargingState();
} else if (BatteryManager.ACTION_DISCHARGING.equals(action)) {
if (DEBUG) {
Slog.d(TAG, "Disconnected from power.");
}
mCharging = false;
// 上报新的充电状态
maybeReportNewChargingState();
}
}
}
@Override
public void dumpControllerState(PrintWriter pw) {
pw.println("Batt.");
pw.println("Stable power: " + mChargeTracker.isOnStablePower());
synchronized (mTrackedTasks) {
Iterator it = mTrackedTasks.iterator();
if (it.hasNext()) {
pw.print(String.valueOf(it.next().hashCode()));
}
while (it.hasNext()) {
pw.print("," + String.valueOf(it.next().hashCode()));
}
pw.println();
}
}
}
5.AppIdleController:
该控制器的大致实现流程:
初始化该控制器时,添加一个继承了UsageStatsManagerInternal.AppIdleStateChangeListener的APP空闲状态监听器来监听APP的空闲状态。
如果应用的空闲状态发生改变,会调用onAppIdleStateChanged方法,在该方法中循环判断空闲状态发生变化的应用是否在追踪列表中,在则调用监听器的onControllerStateChanged方法;
如果假释状态变化时,会调用onParoleStateChanged方法,该方法中的处理逻辑和onAppIdleStateChanged方法中一致。
下面看下代码实现部分:
public class AppIdleController extends StateController {
private static final String LOG_TAG = "AppIdleController";
private static final boolean DEBUG = false;
// Singleton factory
private static Object sCreationLock = new Object();
private static volatile AppIdleController sController;
final ArrayList mTrackedTasks = new ArrayList();
private final UsageStatsManagerInternal mUsageStatsInternal;
boolean mAppIdleParoleOn;
public static AppIdleController get(JobSchedulerService service) {
synchronized (sCreationLock) {
if (sController == null) {
sController = new AppIdleController(service, service.getContext());
}
return sController;
}
}
private AppIdleController(StateChangedListener stateChangedListener, Context context) {
super(stateChangedListener, context);
mUsageStatsInternal = LocalServices.getService(UsageStatsManagerInternal.class);
mAppIdleParoleOn = mUsageStatsInternal.isAppIdleParoleOn();
mUsageStatsInternal.addAppIdleStateChangeListener(new AppIdleStateChangeListener());
}
@Override
public void maybeStartTrackingJob(JobStatus jobStatus) {
synchronized (mTrackedTasks) {
// 把任务添加到追踪列表
mTrackedTasks.add(jobStatus);
// 获取任务所在应用的包名
String packageName = jobStatus.job.getService().getPackageName();
// 判断该应用是否空处于闲状态
final boolean appIdle = !mAppIdleParoleOn && mUsageStatsInternal.isAppIdle(packageName,
jobStatus.uId, jobStatus.getUserId());
if (DEBUG) {
Slog.d(LOG_TAG, "Start tracking, setting idle state of "
+ packageName + " to " + appIdle);
}
// 设置任务的空闲约束不满足状态
jobStatus.appNotIdleConstraintSatisfied.set(!appIdle);
}
}
@Override
public void maybeStopTrackingJob(JobStatus jobStatus) {
synchronized (mTrackedTasks) {
mTrackedTasks.remove(jobStatus);
}
}
@Override
public void dumpControllerState(PrintWriter pw) {
pw.println("AppIdle");
pw.println("Parole On: " + mAppIdleParoleOn);
synchronized (mTrackedTasks) {
for (JobStatus task : mTrackedTasks) {
pw.print(task.job.getService().getPackageName());
pw.print(":idle=" + !task.appNotIdleConstraintSatisfied.get());
pw.print(", ");
}
pw.println();
}
}
void setAppIdleParoleOn(boolean isAppIdleParoleOn) {
// Flag if any app's idle state has changed
boolean changed = false;
synchronized (mTrackedTasks) {
if (mAppIdleParoleOn == isAppIdleParoleOn) {
return;
}
mAppIdleParoleOn = isAppIdleParoleOn;
// 循环判断是否有应用的空闲状态发生变化
for (JobStatus task : mTrackedTasks) {
String packageName = task.job.getService().getPackageName();
final boolean appIdle = !mAppIdleParoleOn && mUsageStatsInternal.isAppIdle(packageName,
task.uId, task.getUserId());
if (DEBUG) {
Slog.d(LOG_TAG, "Setting idle state of " + packageName + " to " + appIdle);
}
if (task.appNotIdleConstraintSatisfied.get() == appIdle) {
task.appNotIdleConstraintSatisfied.set(!appIdle);
changed = true;
}
}
}
// 如果应用的空闲状态发生变化,则调用监听器的onControllerStateChanged方法
if (changed) {
mStateChangedListener.onControllerStateChanged();
}
}
private class AppIdleStateChangeListener
extends UsageStatsManagerInternal.AppIdleStateChangeListener {
@Override
public void onAppIdleStateChanged(String packageName, int userId, boolean idle) {
boolean changed = false;
synchronized (mTrackedTasks) {
// 如果已经是空闲状态,则直接返回
if (mAppIdleParoleOn) {
return;
}
// 循环判断空闲状态发生变化的应用是否在追踪列表中
for (JobStatus task : mTrackedTasks) {
if (task.job.getService().getPackageName().equals(packageName)
&& task.getUserId() == userId) {
// 判断任务的空闲状态是否发生改变
if (task.appNotIdleConstraintSatisfied.get() != !idle) {
if (DEBUG) {
Slog.d(LOG_TAG, "App Idle state changed, setting idle state of "
+ packageName + " to " + idle);
}
task.appNotIdleConstraintSatisfied.set(!idle);
changed = true;
}
}
}
}
if (changed) {
// 调用监听器的onControllerStateChanged方法
mStateChangedListener.onControllerStateChanged();
}
}
@Override
public void onParoleStateChanged(boolean isParoleOn) {
if (DEBUG) {
Slog.d(LOG_TAG, "Parole on: " + isParoleOn);
}
// 假释应用空闲
setAppIdleParoleOn(isParoleOn);
}
}
}
上面5种约束条件的实现都差不多,在maybeStartTrackingJob方法中添加设置有各自约束的任务,在maybeStopTrackingJob方法中移除任务。然后监听各自关心的状态是否发生改变或得到满足,发生变化则调用JobSchedulerService类的onControllerStateChanged方法,得到满足则调用onRunJobNow方法:
/**
* 当某个控制器状态发生变化时,向JobSchedulerService.JobHandler发送一条消息,以便将列表中某个任务开启或停止执行
*/
@Override
public void onControllerStateChanged() {
mHandler.obtainMessage(MSG_CHECK_JOB).sendToTarget();
}
@Override
public void onRunJobNow(JobStatus jobStatus) {
// 向Handler发送消息,开始执行任务jobStatus
mHandler.obtainMessage(MSG_JOB_EXPIRED, jobStatus).sendToTarget();
}
2.初始化JobHandler
那么接下来就看下JobSchedulerService的内部类JobHandler的初始化以及handleMessage方法:
/**
* 等待执行任务列表。JobServiceContext类将会接收到该列表中可以开始执行的任务
*/
final ArrayList mPendingJobs = new ArrayList<>();
/**
* Track Services that have currently active or pending jobs. The index is provided by
* {@link JobStatus#getServiceToken()}
*/
final List mActiveServices = new ArrayList<>();
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为null时所有准备好的任务都要开始执行
if (runNow != null && !mPendingJobs.contains(runNow)
&& mJobs.containsJob(runNow)) {
// 把要执行的任务添加到等待执行任务列表
mPendingJobs.add(runNow);
}
// 遍历任务列表,把准备好执行的任务添加到等待执行任务列表,把准备好取消的正在运行的任务取消
queueReadyJobsForExecutionLockedH();
}
break;
case MSG_CHECK_JOB:
synchronized (mJobs) {
// 检查任务列表,把符合执行要求的添加到等待执行任务列表中
maybeQueueReadyJobsForExecutionLockedH();
}
break;
}
// 开始执行等待执行任务列表中的任务
maybeRunPendingJobsH();
// Don't remove JOB_EXPIRED in case one came along while processing the queue.
removeMessages(MSG_CHECK_JOB);
}
/**
* 遍历任务列表,把准备好执行的任务添加到等待执行任务列表,把准备好取消的正在运行的任务取消
*/
private void queueReadyJobsForExecutionLockedH() {
// 取出任务
ArraySet jobs = mJobs.getJobs();
if (DEBUG) {
Slog.d(TAG, "queuing all ready jobs for execution:");
}
for (int i=0; i runnableJobs = new ArrayList();
ArraySet jobs = mJobs.getJobs();
for (int i=0; i 0) {
backoffCount++;
}
// 判断是否满足任务的空闲状态要求
if (job.hasIdleConstraint()) {
idleCount++;
}
// 判断是否满足任务的连接要求
if (job.hasConnectivityConstraint() || job.hasUnmeteredConstraint()) {
connectivityCount++;
}
// 判断是否满足任务的充电要求
if (job.hasChargingConstraint()) {
chargingCount++;
}
// 把准备好执行的任务添加到runnableJobs列表中
runnableJobs.add(job);
// 判断任务是否准备好取消执行
} else if (isReadyToBeCancelledLocked(job)) {
// 取消正在执行的任务
stopJobOnServiceContextLocked(job);
}
}
if (backoffCount > 0 ||
idleCount >= MIN_IDLE_COUNT ||
connectivityCount >= MIN_CONNECTIVITY_COUNT ||
chargingCount >= MIN_CHARGING_COUNT ||
runnableJobs.size() >= MIN_READY_JOBS_COUNT) {
if (DEBUG) {
Slog.d(TAG, "maybeQueueReadyJobsForExecutionLockedH: Running jobs.");
}
for (int i=0; i
执行任务时调用的是JobServiceContext类中的executeRunnableJob方法:
/**
* 执行传递过来的任务,调用者必须先检查context可用以确保能正常执行任务。
* @param job The status of the job that we are going to run.
* @return True if the job is valid and is running. False if the job cannot be executed.
*/
boolean executeRunnableJob(JobStatus job) {
synchronized (mLock) {
// 如果context无效则直接返回false
if (!mAvailable) {
Slog.e(TAG, "Starting new runnable but context is unavailable > Error.");
return false;
}
mRunningJob = job;
// deadline约束得到满足并且上次运行时间小于开机时间
final boolean isDeadlineExpired =
job.hasDeadlineConstraint() &&
(job.getLatestRunTimeElapsed() < SystemClock.elapsedRealtime());
mParams = new JobParameters(this, job.getJobId(), job.getExtras(), isDeadlineExpired);
mExecutionStartTimeElapsed = SystemClock.elapsedRealtime();
mVerb = VERB_BINDING;
scheduleOpTimeOut();
// 以任务所在服务的组件名创建Intent
final Intent intent = new Intent().setComponent(job.getServiceComponent());
/*这里可以为intent put一个参数,在ActiveServices类的bindServiceLocked方法
* 中取出该参数以判断服务是从JobSchedulerService开启的,以便禁止服务启动来达到禁止
* 应用通过JobSchedulerService的方式来自启的目的*/
// 通过bindServiceAsUser的方式开启任务所在的服务
boolean binding = mContext.bindServiceAsUser(intent, this,
Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND,
new UserHandle(job.getUserId()));
if (!binding) {
if (DEBUG) {
Slog.d(TAG, job.getServiceComponent().getShortClassName() + " unavailable.");
}
mRunningJob = null;
mParams = null;
mExecutionStartTimeElapsed = 0L;
removeOpTimeOut();
return false;
}
try {
mBatteryStats.noteJobStart(job.getName(), job.getUid());
} catch (RemoteException e) {
// Whatever.
}
mAvailable = false;
return true;
}
}
上面bindServiceAsUser方法中传递的服务是this,故绑定成功后调用的是JobServiceContext类中的onServiceConnected方法:
/**
* 在onServiceConnected或unbindService中获取或释放wakelock。当服务unbound时停止向客户端发送任务,直到持有wakelock。
* @param name The concrete component name of the service that has been connected.
* @param service The IBinder of the Service's communication channel,
*/
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
JobStatus runningJob;
synchronized (mLock) {
// This isn't strictly necessary b/c the JobServiceHandler is running on the main
// looper and at this point we can't get any binder callbacks from the client. Better
// safe than sorry.
runningJob = mRunningJob;
}
// 如果正在执行的任务为null或者正在执行的任务所在的组件名不等于绑定服务的组件名则停止执行任务
if (runningJob == null || !name.equals(runningJob.getServiceComponent())) {
mCallbackHandler.obtainMessage(MSG_SHUTDOWN_EXECUTION).sendToTarget();
return;
}
this.service = IJobService.Stub.asInterface(service);
final PowerManager pm =
(PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, runningJob.getTag());
mWakeLock.setWorkSource(new WorkSource(runningJob.getUid()));
mWakeLock.setReferenceCounted(false);
mWakeLock.acquire();
// 向mCallbackHandler发送绑定服务成功的消息
mCallbackHandler.obtainMessage(MSG_SERVICE_BOUND).sendToTarget();
}
private class JobServiceHandler extends Handler {
JobServiceHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message message) {
switch (message.what) {
case MSG_SERVICE_BOUND:
// 移除掉操作超时的任务
removeOpTimeOut();
// 处理绑定成功的操作
handleServiceBoundH();
break;
. . .
default:
Slog.e(TAG, "Unrecognised message: " + message);
}
}
/** 处理绑定服务成功的操作. */
private void handleServiceBoundH() {
if (DEBUG) {
Slog.d(TAG, "MSG_SERVICE_BOUND for " + mRunningJob.toShortString());
}
if (mVerb != VERB_BINDING) {
Slog.e(TAG, "Sending onStartJob for a job that isn't pending. "
+ VERB_STRINGS[mVerb]);
closeAndCleanupJobH(false /* reschedule */);
return;
}
if (mCancelled.get()) {
if (DEBUG) {
Slog.d(TAG, "Job cancelled while waiting for bind to complete. "
+ mRunningJob);
}
closeAndCleanupJobH(true /* reschedule */);
return;
}
try {
mVerb = VERB_STARTING;
scheduleOpTimeOut();
// 调用JobService的startJob方法
service.startJob(mParams);
} catch (RemoteException e) {
Slog.e(TAG, "Error sending onStart message to '" +
mRunningJob.getServiceComponent().getShortClassName() + "' ", e);
}
}
}
到这里调用到了JobService的startJob方法。下面看下JobService的实现原理:
/**
* 从JobScheduler回调方法的入口。这是处理之前安排的异步请求的基类。
* 使用时需要重写onStartJob方法来写任务的执行逻辑。
* 该服务执行运行在应用程序主线程的Handler传递过来的每个任务。这意味着你必须在thread/handler/AsyncTask
* 中实现执行的逻辑。不这样做将导致来自JobManager的任务阻塞,无法继续执行。
*/
// JobService是实现了Service的抽象类
public abstract class JobService extends Service {
private static final String TAG = "JobService";
/**
* JobService的子类必须在Manifest中声明该权限,如:
*
* ...
*
*/
public static final String PERMISSION_BIND =
"android.permission.BIND_JOB_SERVICE";
// 调用onStartJob方法的标识符
private final int MSG_EXECUTE_JOB = 0;
// 调用onStopJob方法的标识符
private final int MSG_STOP_JOB = 1;
// 任务完成的标识符
private final int MSG_JOB_FINISHED = 2;
// mHandler的锁对象
private final Object mHandlerLock = new Object();
// 处理post传来的任务:负责调用到客户端的逻辑和处理系统回调
@GuardedBy("mHandlerLock")
JobHandler mHandler;
// 服务的Binder,后面重写的onBind方法中会返回该Binder的实例,
// mBinder是IJobService.aidl的接口的一个对象
IJobService mBinder = new IJobService.Stub() {
@Override
public void startJob(JobParameters jobParams) {
ensureHandler();
// 把jobParams封装成一个消息
Message m = Message.obtain(mHandler, MSG_EXECUTE_JOB, jobParams);
// 把消息发送给mHandler
m.sendToTarget();
}
@Override
public void stopJob(JobParameters jobParams) {
ensureHandler();
Message m = Message.obtain(mHandler, MSG_STOP_JOB, jobParams);
m.sendToTarget();
}
};
/** @hide */
void ensureHandler() {
synchronized (mHandlerLock) {
if (mHandler == null) {
// 创建Handler对象时传递的是主线程的looper,即消息会在主线程中处理
mHandler = new JobHandler(getMainLooper());
}
}
}
/**
* 运行在应用程序的主线程 - callbacks are meant to offboard work to some other
* (app-specified) mechanism.
* @hide
*/
class JobHandler extends Handler {
JobHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
// 从msg消息中取出JobParameters对象
final JobParameters params = (JobParameters) msg.obj;
switch (msg.what) {
case MSG_EXECUTE_JOB:
try {
// 执行JobService中的onStartJob方法,该方法是一个抽象方法,需要子类重写
boolean workOngoing = JobService.this.onStartJob(params);
ackStartMessage(params, workOngoing);
} catch (Exception e) {
Log.e(TAG, "Error while executing job: " + params.getJobId());
throw new RuntimeException(e);
}
break;
case MSG_STOP_JOB:
try {
// 执行JobService中的onStopJob方法,该方法是一个抽象方法,需要子类重写
boolean ret = JobService.this.onStopJob(params);
ackStopMessage(params, ret);
} catch (Exception e) {
Log.e(TAG, "Application unable to handle onStopJob.", e);
throw new RuntimeException(e);
}
break;
case MSG_JOB_FINISHED:
// 从消息中获取任务是否需要重试
final boolean needsReschedule = (msg.arg2 == 1);
// 从参数中获取回调接口
IJobCallback callback = params.getCallback();
if (callback != null) {
try {
// 调用回调接口中的jobFinished方法
callback.jobFinished(params.getJobId(), needsReschedule);
} catch (RemoteException e) {
Log.e(TAG, "Error reporting job finish to system: binder has gone" +
"away.");
}
} else {
Log.e(TAG, "finishJob() called for a nonexistent job id.");
}
break;
default:
Log.e(TAG, "Unrecognised message received.");
break;
}
}
private void ackStartMessage(JobParameters params,
boolean workOngoing) {
// 获取params的回调接口
final IJobCallback callback = params.getCallback();
final int jobId = params.getJobId();
if (callback != null) {
try {
//调用回调接口中的acknowledgeStartMessage方法
callback.acknowledgeStartMessage(jobId, workOngoing);
} catch (RemoteException e) {
Log.e(TAG, "System unreachable for starting job.");
}
} else {
// 任务已经处理完了
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG,
"Attempting to ack a job that has already been processed.");
}
}
}
private void ackStopMessage(JobParameters params, boolean reschedule) {
final IJobCallback callback = params.getCallback();
final int jobId = params.getJobId();
if (callback != null) {
try {
callback.acknowledgeStopMessage(jobId, reschedule);
} catch(RemoteException e) {
Log.e(TAG, "System unreachable for stopping job.");
}
} else {
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "Attempting to ack a job that has already been processed.");
}
}
}
}
// JobService重写了onBind方法,返回mBinder的一个对象
/** @hide */
public final IBinder onBind(Intent intent) {
return mBinder.asBinder();
}
/**
* 抽象方法,需要子类重写该方法,在该方法中写执行任务的逻辑,该方法运行在主线程
*
* @param params 任务相关的参数,包括在创建任务时自己设定的所有参数
* @return true:如果要执行的任务比较耗时,并且当任务完成时需要调用jobFinished()方法来通知系统
* false:如果要执行的任务不耗时
*
*/
public abstract boolean onStartJob(JobParameters params);
/**
* 抽象方法,需要子类重写该方法,在该方法中写任务停止时的逻辑,该方法运行在主线程
* 该方法被调用场景:在执行任务时,规定的要求已不再满足。
* 如果不重写这个方法,系统可能不再为你的应用程序持有wakelock
*
* @param params 任务相关的参数.
* @return true:基于在创建任务时设定的重试机制指示JobManager是否要重新安排任务。
* false:丢弃本次任务。
* 无论返回什么值,任务必须停止执行。
*/
public abstract boolean onStopJob(JobParameters params);
/**
* 通知JobManager任务已经执行完成的回调方法。该方法可以从任何线程中调用,因为该方法最终会在应用程序的主线程中执行。
* 当系统收到这个消息时,它会释放持有的wakelock锁。
* 可以根据needsReschedule参数写执行后的操作,基于默认值或使用setBackoffCriteria方法设置的值回退任务的定时器。
* 运行在空闲模式的任务是不能回退的。这可能会导致任务重复添加到任务队列中,并且在未来的某个空闲时间内重复执行该任务。
*
* @param params 通过onStartJob方法传递的JobParameters参数
* @param needsReschedule true:如果该任务需要重写安排
* false:其他情况
*/
public final void jobFinished(JobParameters params, boolean needsReschedule) {
ensureHandler();
// 把参数封装成消息
Message m = Message.obtain(mHandler, MSG_JOB_FINISHED, params);
m.arg2 = needsReschedule ? 1 : 0;
// 把消息发送给mHandler
m.sendToTarget();
}
}
看下IJobService.aidl的定义:
package android.app.job;
import android.app.job.JobParameters;
/**
* 这是一个framework用来与继承自JobService的应用程序代码进行通信的接口。
* 应用程序代码不直接实现该接口,而是继承自JobService。
* {@hide}
*/
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);
}
上面接口定义中用到了oneway,意思是如果调用者和被调用者在同一个进程则同步执行,如果不在同一个进程则异步执行,即:调用该接口中的方法后不需要等待方法执行完成。
3.初始化JobSchedulerStub代理对象
下面就看下JobSchedulerService的内部类JobSchedulerStub,它是一个Binder接口的代理类:
/**
* Binder stub trampoline implementation
*/
final class JobSchedulerStub extends IJobScheduler.Stub {
/** Cache determination of whether a given app can persist jobs
* key is uid of the calling app; value is undetermined/true/false
*/
private final SparseArray mPersistCache = new SparseArray();
// 执行只有应用程序自己可以调度运行在自己服务中的任务,以及验证服务是否有BIND_JOB_SERVICE权限。
private void enforceValidJobRequest(int uid, JobInfo job) {
final IPackageManager pm = AppGlobals.getPackageManager();
// 获取任务所在服务组件名
final ComponentName service = job.getService();
try {
// 获取服务相关信息
ServiceInfo si = pm.getServiceInfo(service, 0, UserHandle.getUserId(uid));
// 如果服务相关信息为null则抛异常
if (si == null) {
throw new IllegalArgumentException("No such service " + service);
}
// 如果调用者的uid和服务所在应用程序的uid不同则抛异常
if (si.applicationInfo.uid != uid) {
throw new IllegalArgumentException("uid " + uid +
" cannot schedule job in " + service.getPackageName());
}
// 如果服务没有设置BIND_JOB_SERVICE权限,则抛异常
if (!JobService.PERMISSION_BIND.equals(si.permission)) {
throw new IllegalArgumentException("Scheduled service " + service
+ " does not require android.permission.BIND_JOB_SERVICE permission");
}
} catch (RemoteException e) {
// Can't happen; the Package Manager is in this same process
}
}
private boolean canPersistJobs(int pid, int uid) {
// 检查服务是否可以是永久性的执行任务
final boolean canPersist;
synchronized (mPersistCache) {
Boolean cached = mPersistCache.get(uid);
// 如果cached不为null,则直接取值返回
if (cached != null) {
canPersist = cached.booleanValue();
} else {
// 永久性任务相当于在手机启动时运行,所以它所在的app需要声明RECEIVE_BOOT_COMPLETED权限
int result = getContext().checkPermission(
android.Manifest.permission.RECEIVE_BOOT_COMPLETED, pid, uid);
canPersist = (result == PackageManager.PERMISSION_GRANTED);
mPersistCache.put(uid, canPersist);
}
}
return canPersist;
}
// IJobScheduler implementation
@Override
public int schedule(JobInfo job) throws RemoteException {
if (DEBUG) {
Slog.d(TAG, "Scheduling job: " + job.toString());
}
// 获取调用者pid
final int pid = Binder.getCallingPid();.
// 获取调用者uid
final int uid = Binder.getCallingUid();
// 判断服务的有效性
enforceValidJobRequest(uid, job);
// 服务是否是永久性的判断
if (job.isPersisted()) {
// 根据pid、uid判断服务是否可以是永久性的,如果不是则抛异常
if (!canPersistJobs(pid, uid)) {
throw new IllegalArgumentException("Error: requested job be persisted without"
+ " holding RECEIVE_BOOT_COMPLETED permission.");
}
}
long ident = Binder.clearCallingIdentity();
try {
// 调用JobSchedulerService类的schedule方法
return JobSchedulerService.this.schedule(job, uid);
} finally {
Binder.restoreCallingIdentity(ident);
}
}
@Override
public List getAllPendingJobs() throws RemoteException {
final int uid = Binder.getCallingUid();
long ident = Binder.clearCallingIdentity();
try {
// 调用JobSchedulerService类的getPendingJobs方法
return JobSchedulerService.this.getPendingJobs(uid);
} finally {
Binder.restoreCallingIdentity(ident);
}
}
@Override
public void cancelAll() throws RemoteException {
final int uid = Binder.getCallingUid();
long ident = Binder.clearCallingIdentity();
try {
// 调用JobSchedulerService类的cancelJobsForUid方法
JobSchedulerService.this.cancelJobsForUid(uid);
} finally {
Binder.restoreCallingIdentity(ident);
}
}
@Override
public void cancel(int jobId) throws RemoteException {
final int uid = Binder.getCallingUid();
long ident = Binder.clearCallingIdentity();
try {
// 调用JobSchedulerService类的cancelJob方法
JobSchedulerService.this.cancelJob(uid, jobId);
} finally {
Binder.restoreCallingIdentity(ident);
}
}
/**
* "dumpsys" infrastructure
*/
@Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
getContext().enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
long identityToken = Binder.clearCallingIdentity();
try {
JobSchedulerService.this.dumpInternal(pw);
} finally {
Binder.restoreCallingIdentity(identityToken);
}
}
};
4.初始化任务主列表
接着看JobStore类的initAndGet方法:
/** 使用JobSchedulerService初始化JobStore. */
static JobStore initAndGet(JobSchedulerService jobManagerService) {
synchronized (sSingletonLock) {
if (sSingleton == null) {
sSingleton = new JobStore(jobManagerService.getContext(),
Environment.getDataDirectory());
}
return sSingleton;
}
}
/**
* 构造任务存储的实例。结果是一个会从磁盘中读出的块
* Construct the instance of the job store. This results in a blocking read from disk.
*/
private JobStore(Context context, File dataDir) {
mContext = context;
mDirtyOperations = 0;
File systemDir = new File(dataDir, "system");
File jobDir = new File(systemDir, "job");
// 创建data/system/job目录
jobDir.mkdirs();
// 在data/system/job目录下创建jobs.xml文件
mJobsFile = new AtomicFile(new File(jobDir, "jobs.xml"));
mJobSet = new ArraySet();
// 从磁盘中读取任务map存放在mJobSet中,xml文件的解析,不再粘贴源码
readJobMapFromDisk(mJobSet);
}
下面看下JobSchedulerService类的onStart方法:
@Override
public void onStart() {
// 调用父类SystemService的publishBinderService方法将mJobSchedulerStub发布出去
publishBinderService(Context.JOB_SCHEDULER_SERVICE, mJobSchedulerStub);
}
SystemService类中的publishBinderService方法:
/**
* 发布服务,以便其他服务或应用程序能调用该服务。
*/
protected final void publishBinderService(String name, IBinder service) {
publishBinderService(name, service, false);
}
/**
* 发布服务,以便其他服务或应用程序能调用该服务。
*/
protected final void publishBinderService(String name, IBinder service,
boolean allowIsolated) {
// 把服务添加到ServiceManager中,以便其他服务或应用程序能够调用该服务
// getSystemService时就是根据name获取到该服务的
ServiceManager.addService(name, service, allowIsolated);
}
到这里JobSchedulerService的启动流程就分析完了。在分析启动流程的时候,任务各种约束的添加任务、移除任务、监听任务的状态变化以及任务的执行等操作也都跟着分析了。
下面分析下使用JobSchedulerService的流程,主要是看怎么把任务添加到主任务列表中并开始追踪的。
应用通过getSystemService方法获取系统服务时,会调用到ContextImpl类的getSystemService方法中:
@Override
public Object getSystemService(String name) {
return SystemServiceRegistry.getSystemService(this, name);
}
SystemServiceRegistry类中的getSystemService方法:
/**
* Gets a system service from a given context.
*/
public static Object getSystemService(ContextImpl ctx, String name) {
// 根据服务名从map中取出ServiceFetcher
ServiceFetcher> fetcher = SYSTEM_SERVICE_FETCHERS.get(name);
// 如果fetcher不为null,则从fetcher中根据ctx取出对应的服务并返回
return fetcher != null ? fetcher.getService(ctx) : null;
}
但是在SystemServiceRegistry类的静态代码块中注册服务时,就是把上面发布到ServiceManager中的Binder代理对象mJobSchedulerStub返回给createService方法:
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));
}});
}
private static void registerService(String serviceName, Class serviceClass,
ServiceFetcher serviceFetcher) {
SYSTEM_SERVICE_NAMES.put(serviceClass, serviceName);
SYSTEM_SERVICE_FETCHERS.put(serviceName, serviceFetcher);
}
static abstract interface ServiceFetcher {
T getService(ContextImpl ctx);
}
static abstract class StaticServiceFetcher implements ServiceFetcher {
private T mCachedInstance;
@Override
public final T getService(ContextImpl unused) {
// 单例懒加载模式,具体的创建由子类实现
synchronized (StaticServiceFetcher.this) {
if (mCachedInstance == null) {
mCachedInstance = createService();
}
return mCachedInstance;
}
}
public abstract T createService();
}
看下JobSchedulerImpl类:
public class JobSchedulerImpl extends JobScheduler {
IJobScheduler mBinder;
/* package */ JobSchedulerImpl(IJobScheduler binder) {
mBinder = binder;
}
@Override
public int schedule(JobInfo job) {
try {
return mBinder.schedule(job);
} catch (RemoteException e) {
return JobScheduler.RESULT_FAILURE;
}
}
. . .
}
也就是说,其他应用通过getSystemService(Context.JOB_SCHEDULER_SERVICE)方法获取到的JobScheduler对象中的Binder对象其实就是JobSchedulerService类中的JobSchedulerStub代理对象。
下面看下其他应用调用JobScheduler的schedule方法的流程,由上面分析知,其他应用通过JobScheduler对象调用schedule方法其实是调用的JobSchedulerService类中的JobSchedulerStub代理对象的schedule方法。由上面代理对象的schedule方法知,它调用了JobSchedulerService类的schedule方法:
public int schedule(JobInfo job, int uId) {
JobStatus jobStatus = new JobStatus(job, uId);
// 如果任务已经在等待队列或已经在执行则从等待队列中移除或取消任务的执行
cancelJob(uId, job.getId());
// 开始追踪任务
startTrackingJob(jobStatus);
// 向Handler发送检查任务的消息
mHandler.obtainMessage(MSG_CHECK_JOB).sendToTarget();
return JobScheduler.RESULT_SUCCESS;
}
private void startTrackingJob(JobStatus jobStatus) {
boolean update;
boolean rocking;
synchronized (mJobs) {
// 把新任务添加到主列表中
update = mJobs.add(jobStatus);
rocking = mReadyToRock;
}
if (rocking) {
// 循环获取所有控制器,并回调控制器的开始追踪方法
for (int i=0; i
到这里,任务的添加、追踪逻辑就分析完了。
代码量较大,理解错误或有偏差之处请指正,谢谢!