设置了 Idle 约束条件的 Job 执行一次后不会被移除
/**
* Policy: we decide that we're "idle" if the device has been unused
* screen off or dreaming for at least this long
* 息屏或进入 dreaming 状态 71min 后被认为是 idle 状态
*/
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
一、调用流程
public JobSchedulerService(Context context) {
super(context);
// Create the controllers.
mControllers = new ArrayList<StateController>();
mControllers.add(ConnectivityController.get(this));
mControllers.add(TimeController.get(this));
mControllers.add(IdleController.get(this));
mControllers.add(BatteryController.get(this));
mHandler = new JobSchedulerService.JobHandler(context.getMainLooper());
mJobSchedulerStub = new JobSchedulerService.JobSchedulerStub();
mJobs = JobStore.initAndGet(this);
}
|
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();
}
二、初始化 IdlenessTracker
/**
* Idle state tracking, and messaging with the task manager when
* significant state changes occur
*/
private void initIdleStateTracking() {
mIdleTracker = new IdleController.IdlenessTracker();
// 注册一些需要监听的广播
mIdleTracker.startTracking();
}
public IdlenessTracker() {
mAlarm = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(ACTION_TRIGGER_IDLE)
.setPackage("android")
.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
mIdleTriggerIntent = PendingIntent.getBroadcast(mContext, 0, intent, 0);
// At boot we presume that the user has just "interacted" with the
// device in some meaningful way.
mIdle = false;
}
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);
}
三、添加需要追踪的 Job
public void maybeStartTrackingJob(JobStatus taskStatus) {
if (taskStatus.hasIdleConstraint()) {
synchronized (mTrackedTasks) {
// 把 Job 添加入追踪列表,为 Job 设置当前的设备 idle 状态
mTrackedTasks.add(taskStatus);
taskStatus.idleConstraintSatisfied.set(mIdleTracker.isIdle());
}
}
}
四、移除不再需要追踪的 Job
public void maybeStopTrackingJob(JobStatus taskStatus) {
synchronized (mTrackedTasks) {
mTrackedTasks.remove(taskStatus);
}
}
五、通过 Receiver 驱动 Job 执行的流程
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)) {
// possible transition to not-idle
if (mIdle) {
// 进入 idle 状态后被唤醒
// 设备已被唤醒,取消 71min 后要发送的广播
mAlarm.cancel(mIdleTriggerIntent);
mIdle = false;
// 设置追踪列表中 Job 的 idle 约束条件设置为 false
// 触发 JobSchedulerService 检查所有满足执行条件的 Job,根据策略决定是否放入 mPendingJobs,随后执行 mPendingJobs 中的 Job
reportNewIdleState(mIdle);
}
} else if (action.equals(Intent.ACTION_SCREEN_OFF) || action.equals(Intent.ACTION_DREAMING_STARTED)) {
// when the screen goes off or dreaming starts, we schedule the
// alarm that will tell us when we have decided the device is truly idle.
final long nowElapsed = SystemClock.elapsedRealtime();
final long when = nowElapsed + INACTIVITY_IDLE_THRESHOLD;
// 71min 后,AlarmManager 要在 5min 内发出广播,通知进入 idle 状态
mAlarm.setWindow(AlarmManager.ELAPSED_REALTIME_WAKEUP, when, IDLE_WINDOW_SLOP, mIdleTriggerIntent);
} else if (action.equals(ACTION_TRIGGER_IDLE)) {
// idle time starts now
if (!mIdle) {
// 由非 idle 状态进入 idle 状态
mIdle = true;
// 设置追踪列表中 Job 的 idle 约束条件设置为 true,
// 触发 JobSchedulerService 检查所有满足执行条件的 Job,根据策略决定是否放入 mPendingJobs,随后执行 mPendingJobs 中的 Job
reportNewIdleState(mIdle);
}
}
}
void reportNewIdleState(boolean isIdle) {
synchronized (mTrackedTasks) {
for (JobStatus task : mTrackedTasks) {
task.idleConstraintSatisfied.set(isIdle);
}
}
// 触发 JobSchedulerService 检查所有满足执行条件的 Job,根据策略决定是否放入 mPendingJobs,随后执行 mPendingJobs 中的 Job
mStateChangedListener.onControllerStateChanged();
}
六、驱动 JobShedulerService 执行 Job
public void onControllerStateChanged() {
mHandler.obtainMessage(MSG_CHECK_JOB).sendToTarget();
}