JobSchedulerService 源碼分析—— IdleController (API 21)

設(shè)置了 Idle 約束條件的 Job 執(zhí)行一次后不會被移除

/**
 * Policy: we decide that we're "idle" if the device has been unused
 * screen off or dreaming for at least this long
 * 息屏或進入 dreaming 狀態(tài) 71min 后被認(rèn)為是 idle 狀態(tài)
 */
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

一、調(diào)用流程

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();
    // 注冊一些需要監(jiān)聽的廣播
    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 設(shè)置當(dāng)前的設(shè)備 idle 狀態(tài)
            mTrackedTasks.add(taskStatus);
            taskStatus.idleConstraintSatisfied.set(mIdleTracker.isIdle());
        }
    }
}

四、移除不再需要追蹤的 Job

public void maybeStopTrackingJob(JobStatus taskStatus) {
    synchronized (mTrackedTasks) {
        mTrackedTasks.remove(taskStatus);
    }
}


五、通過 Receiver 驅(qū)動 Job 執(zhí)行的流程

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 狀態(tài)后被喚醒
            // 設(shè)備已被喚醒,取消 71min 后要發(fā)送的廣播
            mAlarm.cancel(mIdleTriggerIntent);
            mIdle = false;
            // 設(shè)置追蹤列表中 Job 的 idle 約束條件設(shè)置為 false
            // 觸發(fā) JobSchedulerService 檢查所有滿足執(zhí)行條件的 Job,根據(jù)策略決定是否放入 mPendingJobs,隨后執(zhí)行 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 內(nèi)發(fā)出廣播,通知進入 idle 狀態(tài)
        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 狀態(tài)進入 idle 狀態(tài)
            mIdle = true;
            // 設(shè)置追蹤列表中 Job 的 idle 約束條件設(shè)置為 true, 
            // 觸發(fā) JobSchedulerService 檢查所有滿足執(zhí)行條件的 Job,根據(jù)策略決定是否放入 mPendingJobs,隨后執(zhí)行 mPendingJobs 中的 Job
            reportNewIdleState(mIdle);
        }
    }
}

void reportNewIdleState(boolean isIdle) {
    synchronized (mTrackedTasks) {
        for (JobStatus task : mTrackedTasks) {
            task.idleConstraintSatisfied.set(isIdle);
        }
    }
    // 觸發(fā) JobSchedulerService 檢查所有滿足執(zhí)行條件的 Job,根據(jù)策略決定是否放入 mPendingJobs,隨后執(zhí)行 mPendingJobs 中的 Job
    mStateChangedListener.onControllerStateChanged();
}

六、驅(qū)動 JobShedulerService 執(zhí)行 Job

public void onControllerStateChanged() {
    mHandler.obtainMessage(MSG_CHECK_JOB).sendToTarget();
}

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容