小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

Android之JobScheduler運行機制源碼分析

 jiffes 2019-01-29

之前有篇文章專門介紹了JobScheduler的使用,這里再大致說下:

如果想在將來達到一定條件下執(zhí)行某項任務(wù)時,可以在一個實現(xiàn)了JobService的子類的onStartJob方法中執(zhí)行這項任務(wù),使用JobInfo的Builder方法來設(shè)定條件并和實現(xiàn)了JobService的子類的組件名綁定,然后調(diào)用系統(tǒng)服務(wù)JobScheduler的schedule方法。這樣,即便在執(zhí)行任務(wù)之前應(yīng)用程序進程被殺,也不會導(dǎo)致任務(wù)不會執(zhí)行,因為系統(tǒng)服務(wù)JobScheduler會使用bindServiceAsUser的方法把實現(xiàn)了JobService的子類服務(wù)啟動起來,并執(zhí)行它的onStartJob方法。

由于JobSchedulerService是系統(tǒng)服務(wù),故這里按照啟動流程和使用流程分開分析源碼,下面先看下啟動流程的時序圖:

由于JobSchedulerService的構(gòu)造方法中執(zhí)行的操作比較多,時序圖中沒有詳細畫出。

Zygote進程啟動后會啟動System進程,在System進程啟動過程中會啟動系統(tǒng)中的關(guān)鍵服務(wù),如AMS、PMS以及這里要用到的JobSchedulerService等。

SystemServer啟動JobSchedulerService服務(wù)調(diào)用的是SystemServiceManager類的startService方法:

private void startOtherServices() {
    . . .
    if (mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL) {
        // 開啟JobSchedulerService服務(wù)
        mSystemServiceManager.startService(JobSchedulerService.class);
        . . .
    }
}


看下SystemServiceManager類的startService方法的具體操作:

private final ArrayList<SystemService> mServices = new ArrayList<SystemService>();

/**
 * 創(chuàng)建并啟動一個繼承自SystemService類的系統(tǒng)服務(wù)。
 *
 * @param 一個繼承自SystemService類的服務(wù)類 
 * @return 服務(wù)類的實例
 * @throws 如果服務(wù)啟動失敗則拋RuntimeException異常
 */
@SuppressWarnings("unchecked")
public <T extends SystemService> T startService(Class<T> serviceClass) {
    // 獲取服務(wù)類的類名
    final String name = serviceClass.getName();
    Slog.i(TAG, "Starting " + name);

    // 判斷服務(wù)類是否是SystemService的子類
    if (!SystemService.class.isAssignableFrom(serviceClass)) {
        throw new RuntimeException("Failed to create " + name
                + ": service must extend " + SystemService.class.getName());
    }
    final T service;
    try {
        // 獲取服務(wù)類包含一個Context參數(shù)的構(gòu)造方法
        Constructor<T> constructor = serviceClass.getConstructor(Context.class);
        // 創(chuàng)建這個服務(wù)類的實例
        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);
    }

    // 把服務(wù)添加到mServices列表中,方便后續(xù)使用時取出
    mServices.add(service);

    try {
        // 回調(diào)服務(wù)的onStart方法
        service.onStart();
    } catch (RuntimeException ex) {
        throw new RuntimeException("Failed to start service " + name
                + ": onStart threw an exception", ex);
    }
    return service;
}


在開啟JobSchedulerService服務(wù)時,會創(chuàng)建該服務(wù)的實例,來看下該服務(wù)的創(chuàng)建過程:

// 任務(wù)狀態(tài)控制器列表
List<StateController> mControllers;
final JobHandler mHandler;
final JobSchedulerStub mJobSchedulerStub;
// 任務(wù)主列表
final JobStore mJobs;

public JobSchedulerService(Context context) {
    super(context);
    // 創(chuàng)建控制器
    mControllers = new ArrayList<StateController>();
    // 添加網(wǎng)絡(luò)控制器
    mControllers.add(ConnectivityController.get(this));
    // 添加時間控制器
    mControllers.add(TimeController.get(this));
    // 添加空閑控制器
    mControllers.add(IdleController.get(this));
    // 添加電池控制器
    mControllers.add(BatteryController.get(this));
    // 添加應(yīng)用空閑控制器
    mControllers.add(AppIdleController.get(this));

	// 初始化JobHandler,主要處理任務(wù)到期和檢查任務(wù)的消息
    mHandler = new JobHandler(context.getMainLooper());
    // 初始化mJobSchedulerStub
    mJobSchedulerStub = new JobSchedulerStub();
	// 初始化JobStore并返回從data/system/job/jobs.xml文件中讀取的永久性任務(wù)
    mJobs = JobStore.initAndGet(this);
}


由上面代碼可以看出,創(chuàng)建服務(wù)有下面幾個步驟:

1.初始化各種控制器并添加到列表中

2.初始化JobHandler

3.初始化JobSchedulerStub代理對象

4.初始化任務(wù)主列表

下面按順序分析上面幾個步驟:

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;
    }

    /**
     * 該方法中實現(xiàn)控制器添加追蹤任務(wù)的邏輯
     */
    public abstract void maybeStartTrackingJob(JobStatus jobStatus);
    /**
     * 如果任務(wù)被取消、執(zhí)行完成等則remove掉該任務(wù)
     */
    public abstract void maybeStopTrackingJob(JobStatus jobStatus);

    public abstract void dumpControllerState(PrintWriter pw);
}


接口StateChangedListener:

public interface StateChangedListener {
    /**
     * 控制器調(diào)用該方法通知JobManager該檢查某項任務(wù)的狀態(tài)
     */
    public void onControllerStateChanged();

    /**
     * 控制器調(diào)用該方法通知JobManager執(zhí)行該項任務(wù)
     * @param jobStatus 直接執(zhí)行任務(wù),null表示刷新所有準(zhǔn)備好的任務(wù)
     */
    public void onRunJobNow(JobStatus jobStatus);
}


說明:第三方應(yīng)用使用JobInfo設(shè)置任務(wù)信息時會調(diào)用maybeStartTrackingJob方法,如果設(shè)置了該控制器相關(guān)的控制項時,就會把該任務(wù)添加到追蹤列表中。后面會分析任務(wù)的添加過程。

下面按JobSchedulerService的構(gòu)造方法中添加控制器的順序分析各個控制器的實現(xiàn)原理:

1.ConnectivityController:

該控制器的大致實現(xiàn)流程:

初始化該控制器時,動態(tài)注冊接收網(wǎng)絡(luò)變化的廣播,并給mNetworkConnected變量和mNetworkUnmetered變量賦初值,收到廣播后會修改這兩個參數(shù)的值并調(diào)用updateTrackedJobs方法,該方法主要是遍歷保存在追蹤列表中的任務(wù),查看是否有任務(wù)的兩個參數(shù)值相對于之前保存的值有變化,如果有則調(diào)用mStateChangedListener監(jiān)聽器的onControllerStateChanged()方法通知JobSchedulerService約束任務(wù)的條件狀態(tài)發(fā)生改變,這里的mStateChangedListener就是構(gòu)造方法傳遞來的JobSchedulerService的實例。由于控制器實現(xiàn)了ConnectivityManage.OnNetworkActiveListener接口,故當(dāng)網(wǎng)絡(luò)可用時會調(diào)用該接口中的onNetworkActive方法,在該方法中會調(diào)用監(jiān)聽器的onRunJobNow方法通知JobSchedulerService執(zhí)行任務(wù)。

下面看下代碼實現(xiàn)部分:

public class ConnectivityController extends StateController implements
        ConnectivityManager.OnNetworkActiveListener {
    private static final String TAG = "JobScheduler.Conn";

    // 追蹤任務(wù)狀態(tài)列表
    private final List<JobStatus> mTrackedJobs = new LinkedList<JobStatus>();
    // 網(wǎng)絡(luò)變化的廣播
    private final BroadcastReceiver mConnectivityChangedReceiver =
            new ConnectivityChangedReceiver();
    /** Singleton. */
    private static ConnectivityController mSingleton;
    private static Object sCreationLock = new Object();
    /** 追蹤最新活動網(wǎng)絡(luò)是否可計量(網(wǎng)絡(luò)連接是否收費) */
    private boolean mNetworkUnmetered;
    /** 追蹤最新活動網(wǎng)絡(luò)是否已經(jīng)連接 */
    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);
        // 注冊接收網(wǎng)絡(luò)變化的廣播
        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) {
                // 給網(wǎng)絡(luò)連接變量賦值
                mNetworkConnected = cs.getActiveNetworkInfo().isConnected();
            }
            // 給不可計量變量賦值
            mNetworkUnmetered = mNetworkConnected && !cs.isActiveNetworkMetered();
        }
    }

    @Override
    public void maybeStartTrackingJob(JobStatus jobStatus) {
        // 任務(wù)是否有連接約束或不可計量約束。說明:任務(wù)的約束是通過JobInfo的builder方法設(shè)置的
        if (jobStatus.hasConnectivityConstraint() || jobStatus.hasUnmeteredConstraint()) {
            synchronized (mTrackedJobs) {
                jobStatus.connectivityConstraintSatisfied.set(mNetworkConnected);
                jobStatus.unmeteredConstraintSatisfied.set(mNetworkUnmetered);
                // 把任務(wù)添加到追蹤列表中
                mTrackedJobs.add(jobStatus);
            }
        }
    }

    @Override
    public void maybeStopTrackingJob(JobStatus jobStatus) {
        if (jobStatus.hasConnectivityConstraint() || jobStatus.hasUnmeteredConstraint()) {
            synchronized (mTrackedJobs) {
                // 把任務(wù)從列表中移除
                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列表中的任務(wù)
            for (JobStatus js : mTrackedJobs) {
                if (js.getUserId() != userId) {
                    continue;
                }
                // getAndSet方法返回上次保存的值,并把新值替換舊值保存
                boolean prevIsConnected =
                        js.connectivityConstraintSatisfied.getAndSet(mNetworkConnected);
                boolean prevIsMetered = js.unmeteredConstraintSatisfied.getAndSet(mNetworkUnmetered);
                // 如果本次的mNetworkConnected或mNetworkUnmetered與上一次保存的值不一樣,則設(shè)置changed為true
                if (prevIsConnected != mNetworkConnected || prevIsMetered != mNetworkUnmetered) {
                    changed = true;
                }
            }
            // 如果changed為true,則調(diào)用監(jiān)聽器(即JobSchedulerService)的onControllerStateChanged方法
            if (changed) {
                mStateChangedListener.onControllerStateChanged();
            }
        }
    }

    // 該方法是OnNetworkActiveListener接口中的方法,網(wǎng)絡(luò)可用時調(diào)用該方法
    public synchronized void onNetworkActive() {
        synchronized (mTrackedJobs) {
            for (JobStatus js : mTrackedJobs) {
			    // 判斷該任務(wù)的所有約束條件是否都已得到滿足
                if (js.isReady()) {
                    if (DEBUG) {
                        Slog.d(TAG, "Running " + js + " due to network activity.");
                    }
                    // 調(diào)用監(jiān)聽器的onRunJobNow方法執(zhí)行任務(wù)
                    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)) {
                // 取出廣播傳遞來的網(wǎng)絡(luò)連接類型
                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.
                // 網(wǎng)絡(luò)不可用
                if (activeNetwork == null) {
                    mNetworkUnmetered = false;
                    mNetworkConnected = false;
                    // 更新追蹤任務(wù)
                    updateTrackedJobs(userid);
                // 判斷當(dāng)前激活的網(wǎng)絡(luò)連接類型是否和廣播傳遞來的網(wǎng)絡(luò)連接類型相同
                } 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();
                    }
                    // 更新追蹤任務(wù)
                    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

由于該控制器跟任務(wù)執(zhí)行時間相關(guān),故調(diào)用maybeStartTrackingJob方法添加任務(wù)時會根據(jù)任務(wù)執(zhí)行時間點插入到追蹤列表中,并更新下一個要執(zhí)行任務(wù)的執(zhí)行時間點。

該控制器的大致實現(xiàn)流程:

初始化控制器時,初始化任務(wù)的deadline到期和延遲到期時發(fā)送廣播的操作,動態(tài)注冊這兩個廣播,根據(jù)接收到不同的廣播執(zhí)行不同的檢查機制:

遍歷檢查任務(wù)的延遲時間是否已經(jīng)到期,如果有任務(wù)的延遲時間到期并且所有的約束都得到滿足時,調(diào)用mStateChangedListener監(jiān)聽器的onControllerStateChanged方法;

或者檢查任務(wù)追蹤列表中是否有deadline過期導(dǎo)致該任務(wù)需要執(zhí)行,如果有則調(diào)用mStateChangedListener監(jiān)聽器的onRunJobNow方法。

下面看下代碼實現(xiàn)部分:

/**
 * 該類為下一個到期任務(wù)設(shè)置一個alarm,并確定任務(wù)的最小延遲是否已經(jīng)滿足
 */
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";

    /** 任務(wù)的deadline到期時執(zhí)行的操作. */
    private final PendingIntent mDeadlineExpiredAlarmIntent;
    /** 任務(wù)的延遲時間到期時執(zhí)行的操作. */
    private final PendingIntent mNextDelayExpiredAlarmIntent;

    private long mNextJobExpiredElapsedMillis;
    private long mNextDelayExpiredElapsedMillis;

    private AlarmManager mAlarmService = null;
    /** 按任務(wù)執(zhí)行時間點從小到大的順序排列的任務(wù)列表 */
    private final List<JobStatus> mTrackedJobs = new LinkedList<JobStatus>();
    /** 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);
		// 任務(wù)的deadline到期時會發(fā)送一個ACTION_JOB_EXPIRED廣播
        mDeadlineExpiredAlarmIntent =
                PendingIntent.getBroadcast(mContext, 0 /* ignored */,
                        new Intent(ACTION_JOB_EXPIRED), 0);
		// 任務(wù)的延遲時間到期時會發(fā)送一個ACTION_JOB_DELAY_EXPIRED廣播
        mNextDelayExpiredAlarmIntent =
                PendingIntent.getBroadcast(mContext, 0 /* ignored */,
                        new Intent(ACTION_JOB_DELAY_EXPIRED), 0);
		// 初始化下一個將要執(zhí)行的任務(wù)的到期時間和延遲時間都為最大長整形
        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);
    }

    /**
     * 把設(shè)置了時間約束的任務(wù),根據(jù)任務(wù)執(zhí)行時間點插入到列表中正確的位置
     */
    @Override
    public synchronized void maybeStartTrackingJob(JobStatus job) {
        // 判斷任務(wù)是否有延遲約束或deadline約束
        if (job.hasTimingDelayConstraint() || job.hasDeadlineConstraint()) {
            maybeStopTrackingJob(job);
            // 插入操作
            boolean isInsert = false;
            ListIterator<JobStatus> it = mTrackedJobs.listIterator(mTrackedJobs.size());
			// 從列表后面往前遍歷,如果前一個任務(wù)的執(zhí)行時間點小于該任務(wù)的執(zhí)行時間點則插入該任務(wù)
            while (it.hasPrevious()) {
                JobStatus ts = it.previous();
                if (ts.getLatestRunTimeElapsed() < job.getLatestRunTimeElapsed()) {
                    // Insert
                    isInsert = true;
                    break;
                }
            }
            if(isInsert)
            {
			    // 獲取要插入該任務(wù)的位置
                it.next();
            }
			// 插入該任務(wù)
            it.add(job);
            // 更新下一個將要執(zhí)行任務(wù)的alarm時間
            maybeUpdateAlarms(
                    job.hasTimingDelayConstraint() ? job.getEarliestRunTime() : Long.MAX_VALUE,
                    job.hasDeadlineConstraint() ? job.getLatestRunTimeElapsed() : Long.MAX_VALUE);
        }
    }

    /**
     * 停止追蹤任務(wù)時,只需要更新alarm
     */
    @Override
    public synchronized void maybeStopTrackingJob(JobStatus job) {
        if (mTrackedJobs.remove(job)) {
            // 檢查延遲alarm
            checkExpiredDelaysAndResetAlarm();
            // 檢查deadline的alarm
            checkExpiredDeadlinesAndResetAlarm();
        }
    }

    /**
     * 任務(wù)的約束得到滿足后,控制器不再追蹤該任務(wù)
     */
    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);
        }
    }

    /**
     * 檢查任務(wù)追蹤列表是否有該執(zhí)行的任務(wù)
     */
    private synchronized void checkExpiredDeadlinesAndResetAlarm() {
        long nextExpiryTime = Long.MAX_VALUE;
		// 獲取手機開機時間
        final long nowElapsedMillis = SystemClock.elapsedRealtime();

        Iterator<JobStatus> it = mTrackedJobs.iterator();
        while (it.hasNext()) {
            JobStatus job = it.next();
            // 如果任務(wù)沒有設(shè)置deadline約束,則跳過本次循環(huán)
            if (!job.hasDeadlineConstraint()) {
                continue;
            }
            // 獲取任務(wù)下一次執(zhí)行的時間
            final long jobDeadline = job.getLatestRunTimeElapsed();

            // 如果任務(wù)的下一次執(zhí)行時間小于手機運行時間,則設(shè)置任務(wù)的deadline已經(jīng)得到滿足,并運行該任務(wù)
            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;
            }
        }
		// 更新下一個將要執(zhí)行任務(wù)的deadline時間
        setDeadlineExpiredAlarm(nextExpiryTime);
    }

    /**
     * 遍歷檢查任務(wù)的延遲時間是否已經(jīng)到期
     */
    private synchronized void checkExpiredDelaysAndResetAlarm() {
        // 獲取手機當(dāng)前運行時間
        final long nowElapsedMillis = SystemClock.elapsedRealtime();
        long nextDelayTime = Long.MAX_VALUE;
        boolean ready = false;
        Iterator<JobStatus> it = mTrackedJobs.iterator();
        while (it.hasNext()) {
            final JobStatus job = it.next();
            // 如果任務(wù)沒有設(shè)置延遲約束則跳過本次循環(huán)
            if (!job.hasTimingDelayConstraint()) {
                continue;
            }
            // 獲取任務(wù)的最早執(zhí)行時間
            final long jobDelayTime = job.getEarliestRunTime();
			// 判斷任務(wù)的最早執(zhí)行時間是否小于等于開機時間
            if (jobDelayTime <= nowElapsedMillis) {
                // 設(shè)置任務(wù)的延遲已經(jīng)得到滿足
                job.timeDelayConstraintSatisfied.set(true);
                // 判斷任務(wù)是否可以停止追蹤
                if (canStopTrackingJob(job)) {
                    it.remove();
                }
                if (job.isReady()) {
                    ready = true;
                }
            } else {  // Keep going through list to get next delay time.
                // 如果任務(wù)的最早執(zhí)行時間小于最大長整形,則更新nextDelayTime變量為最早執(zhí)行任務(wù)的時間
                if (nextDelayTime > jobDelayTime) {
                    nextDelayTime = jobDelayTime;
                }
            }
        }
        // 如果任務(wù)的約束條件都得到滿足,則調(diào)用監(jiān)聽器(即JobSchedulerService)的onControllerStateChanged方法
        if (ready) {
            mStateChangedListener.onControllerStateChanged();
        }
        // 更新下一個將要執(zhí)行任務(wù)的延遲過期時間
        setDelayExpiredAlarm(nextDelayTime);
    }

    private void maybeUpdateAlarms(long delayExpiredElapsed, long deadlineExpiredElapsed) {
        // 如果該任務(wù)的延遲過期時間小于下一個將要執(zhí)行的任務(wù)的延遲過期時間,則更新下一個將要執(zhí)行任務(wù)的延遲過期時間
        if (delayExpiredElapsed < mNextDelayExpiredElapsedMillis) {
            setDelayExpiredAlarm(delayExpiredElapsed);
        }
        // 如果該任務(wù)的deadline時間小于下一個將要執(zhí)行的任務(wù)的deadline時間,則更新下一個將要執(zhí)行任務(wù)的deadline時間
        if (deadlineExpiredElapsed < mNextJobExpiredElapsedMillis) {
            setDeadlineExpiredAlarm(deadlineExpiredElapsed);
        }
    }

    /**
     * 用AlarmManager為下一個將要執(zhí)行的任務(wù)設(shè)置一個alarm,該alarm不會喚醒手機
     */
    private void setDelayExpiredAlarm(long alarmTimeElapsedMillis) {
        // 調(diào)整alarm時間,如果alarm時間設(shè)置不對則調(diào)整
        alarmTimeElapsedMillis = maybeAdjustAlarmTime(alarmTimeElapsedMillis);
        // 更新下一個將要執(zhí)行任務(wù)的延遲過期時間
        mNextDelayExpiredElapsedMillis = alarmTimeElapsedMillis;
        // 更新執(zhí)行任務(wù)延遲時間到期操作的時間
        updateAlarmWithPendingIntent(mNextDelayExpiredAlarmIntent, mNextDelayExpiredElapsedMillis);
    }

    /**
     * 用AlarmManager為deadline將要到期的任務(wù)設(shè)置一個alarm,該alarm將會喚醒手機
     */
    private void setDeadlineExpiredAlarm(long alarmTimeElapsedMillis) {
	    // 調(diào)整alarm時間,如果alarm時間設(shè)置不對則調(diào)整
        alarmTimeElapsedMillis = maybeAdjustAlarmTime(alarmTimeElapsedMillis);
		// 更新下一個將要執(zhí)行任務(wù)的deadline到期時間
        mNextJobExpiredElapsedMillis = alarmTimeElapsedMillis;
        // 更新執(zhí)行任務(wù)deadline到期操作的時間
        updateAlarmWithPendingIntent(mDeadlineExpiredAlarmIntent, mNextJobExpiredElapsedMillis);
    }

    // 調(diào)整alarm時間,如果alarm時間設(shè)置不對則調(diào)整
    private long maybeAdjustAlarmTime(long proposedAlarmTimeElapsedMillis) {
        final long earliestWakeupTimeElapsed = SystemClock.elapsedRealtime();
		// 如果設(shè)置值小于開機時間則返回開機時間,因為AlarmManager的set方法只能設(shè)置比開機時間晚的時間點
        if (proposedAlarmTimeElapsedMillis < earliestWakeupTimeElapsed) {
            return earliestWakeupTimeElapsed;
        }
        return proposedAlarmTimeElapsedMillis;
    }

    // 更新執(zhí)行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的執(zhí)行時間,AlarmManager的set方法是設(shè)置在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());
            }
            // 根據(jù)接收到廣播的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:

該控制器的大致實現(xiàn)流程:

初始化該控制器時,動態(tài)注冊監(jiān)聽息屏/亮屏,進入休眠/退出休眠以及進入空閑狀態(tài)的廣播。

收到亮屏/退出休眠廣播時,設(shè)置mScreenOn為true,并取消空閑時發(fā)送空閑廣播的PendingIntent,如果mIdle為true,則修改為false,并上報空閑狀態(tài)改變,遍歷追蹤任務(wù),設(shè)置任務(wù)的空閑滿足狀態(tài)為isIdle,并調(diào)用mStateChangedListener監(jiān)聽器的onControllerStateChanged方法;

收到息屏/進入休眠廣播時設(shè)置mScreenOn為false,并設(shè)置一個在開機時間+息屏/進入休眠閾值的時間點、IDLE_WINDOW_SLOP時間窗內(nèi)觸發(fā)的發(fā)送進入空閑狀態(tài)的廣播;

收到進入空閑狀態(tài)廣播時,符合(!mIdle && !mScreenOn)判斷時,設(shè)置mIdle為true,并上報新的空閑狀態(tài),遍歷追蹤任務(wù),設(shè)置任務(wù)的空閑滿足狀態(tài)為isIdle,并調(diào)用mStateChangedListener監(jiān)聽器的onControllerStateChanged方法。

下面看下代碼實現(xiàn)部分:

public class IdleController extends StateController {
    private static final String TAG = "IdleController";

    // 息屏或休眠閾值
    private static final long INACTIVITY_IDLE_THRESHOLD = 71 * 60 * 1000; // millis; 71 min
	// 觸發(fā)發(fā)送廣播的時間窗
    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<JobStatus> mTrackedTasks = new ArrayList<JobStatus>();
    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);
        // 初始化空閑狀態(tài)追蹤
        initIdleStateTracking();
    }

    /**
     * StateController interface
     */
    @Override
    public void maybeStartTrackingJob(JobStatus taskStatus) {
        // 判斷任務(wù)是否設(shè)置了空閑約束
        if (taskStatus.hasIdleConstraint()) {
            synchronized (mTrackedTasks) {
                // 把任務(wù)添加到追蹤任務(wù)列表
                mTrackedTasks.add(taskStatus);
                // 獲取當(dāng)前手機狀態(tài)并設(shè)置任務(wù)的空閑約束滿足狀態(tài)
                taskStatus.idleConstraintSatisfied.set(mIdleTracker.isIdle());
            }
        }
    }

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

    /**
     * 上報新的空閑狀態(tài)
     */
    void reportNewIdleState(boolean isIdle) {
        synchronized (mTrackedTasks) {
            // 遍歷追蹤任務(wù),設(shè)置任務(wù)的空閑滿足狀態(tài)為isIdle
            for (JobStatus task : mTrackedTasks) {
                task.idleConstraintSatisfied.set(isIdle);
            }
        }
        // 調(diào)用監(jiān)聽器的onControllerStateChanged方法
        mStateChangedListener.onControllerStateChanged();
    }

    /**
     * 空閑狀態(tài)追蹤,當(dāng)狀態(tài)發(fā)生改變時通知任務(wù)管理器
     */
    private void initIdleStateTracking() {
        // 初始化空閑狀態(tài)追蹤器廣播
        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);
			// 初始化發(fā)送ACTION_TRIGGER_IDLE廣播的延遲Intent
            mIdleTriggerIntent = PendingIntent.getBroadcast(mContext, 0, intent, 0);

            // 開機時假設(shè)用戶剛使用過手機
            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;
                    // 上報新的空閑狀態(tài)
                    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;
				// 設(shè)置一個在時間窗內(nèi)觸發(fā)的mIdleTriggerIntent。類似于set方法,只不過setWindow允許系統(tǒng)調(diào)整觸發(fā)任務(wù)的時間。
                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:

該控制器的大致實現(xiàn)流程:

初始化該控制器時,動態(tài)注冊監(jiān)聽電量低/電量OK,充電/非充電的廣播。

收到電量低的廣播時,設(shè)置mBatteryHealthy為false;

收到電量OK的廣播時,設(shè)置mBatteryHealthy為true,并上報新的充電狀態(tài):如果是否可以開始執(zhí)行任務(wù)的狀態(tài)發(fā)生變化,則調(diào)用監(jiān)聽器的onControllerStateChanged方法,如果可以開始執(zhí)行任務(wù),則刷新所有準(zhǔn)備好的任務(wù);

收到充電/非充電廣播時,分別設(shè)置mCharging為true/false,并上報新的充電狀態(tài)。

下面看下代碼實現(xiàn)部分:

/**
 * 追蹤手機是否在充電的簡單控制器,如果手機充電超過兩分鐘,則系統(tǒng)會發(fā)送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<JobStatus> mTrackedTasks = new ArrayList<JobStatus>();
    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) {
        // 獲取當(dāng)前手機是否在充電并且可以開始執(zhí)行任務(wù)
        final boolean isOnStablePower = mChargeTracker.isOnStablePower();
        // 判斷任務(wù)是否設(shè)置了充電約束
        if (taskStatus.hasChargingConstraint()) {
            synchronized (mTrackedTasks) {
                // 添加任務(wù)到追蹤列表
                mTrackedTasks.add(taskStatus);
                // 設(shè)置任務(wù)的充電滿足狀態(tài)為isOnStablePower
                taskStatus.chargingConstraintSatisfied.set(isOnStablePower);
            }
        }
    }

    @Override
    public void maybeStopTrackingJob(JobStatus taskStatus) {
        if (taskStatus.hasChargingConstraint()) {
            synchronized (mTrackedTasks) {
                mTrackedTasks.remove(taskStatus);
            }
        }
    }

	// 上報新的充電狀態(tài)
    private void maybeReportNewChargingState() {
        final boolean stablePower = mChargeTracker.isOnStablePower();
        if (DEBUG) {
            Slog.d(TAG, "maybeReportNewChargingState: " + stablePower);
        }
        boolean reportChange = false;
        synchronized (mTrackedTasks) {
            for (JobStatus ts : mTrackedTasks) {
                // 獲取任務(wù)上一次的是否可以開始執(zhí)行任務(wù)的判斷
                boolean previous = ts.chargingConstraintSatisfied.getAndSet(stablePower);
				// 如果是否可以開始執(zhí)行任務(wù)的狀態(tài)發(fā)生變化
                if (previous != stablePower) {
                    reportChange = true;
                }
            }
        }
        // 如果是否可以開始執(zhí)行任務(wù)的狀態(tài)發(fā)生變化,則調(diào)用監(jiān)聽器的onControllerStateChanged方法
        if (reportChange) {
            mStateChangedListener.onControllerStateChanged();
        }
        // 如果可以開始執(zhí)行任務(wù),則刷新所有準(zhǔn)備好的任務(wù)
        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);

            // 初始化追蹤器狀態(tài)
            BatteryManagerInternal batteryManagerInternal =
                    LocalServices.getService(BatteryManagerInternal.class);
            mBatteryHealthy = !batteryManagerInternal.getBatteryLevelLow();
            mCharging = batteryManagerInternal.isPowered(BatteryManager.BATTERY_PLUGGED_ANY);
        }

        // 判斷是否可以開始執(zhí)行任務(wù)
        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;
                // 上報新的充電狀態(tài)
                maybeReportNewChargingState();
            } else if (BatteryManager.ACTION_CHARGING.equals(action)) {
                if (DEBUG) {
                    Slog.d(TAG, "Received charging intent, fired @ "
                            + SystemClock.elapsedRealtime());
                }
                mCharging = true;
				// 上報新的充電狀態(tài)
                maybeReportNewChargingState();
            } else if (BatteryManager.ACTION_DISCHARGING.equals(action)) {
                if (DEBUG) {
                    Slog.d(TAG, "Disconnected from power.");
                }
                mCharging = false;
				// 上報新的充電狀態(tài)
                maybeReportNewChargingState();
            }
        }
    }

    @Override
    public void dumpControllerState(PrintWriter pw) {
        pw.println("Batt.");
        pw.println("Stable power: " + mChargeTracker.isOnStablePower());
        synchronized (mTrackedTasks) {
            Iterator<JobStatus> 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:

該控制器的大致實現(xiàn)流程:

初始化該控制器時,添加一個繼承了UsageStatsManagerInternal.AppIdleStateChangeListener的APP空閑狀態(tài)監(jiān)聽器來監(jiān)聽APP的空閑狀態(tài)。

如果應(yīng)用的空閑狀態(tài)發(fā)生改變,會調(diào)用onAppIdleStateChanged方法,在該方法中循環(huán)判斷空閑狀態(tài)發(fā)生變化的應(yīng)用是否在追蹤列表中,在則調(diào)用監(jiān)聽器的onControllerStateChanged方法;

如果假釋狀態(tài)變化時,會調(diào)用onParoleStateChanged方法,該方法中的處理邏輯和onAppIdleStateChanged方法中一致。

下面看下代碼實現(xiàn)部分:

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<JobStatus> mTrackedTasks = new ArrayList<JobStatus>();
    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) {
            // 把任務(wù)添加到追蹤列表
            mTrackedTasks.add(jobStatus);
            // 獲取任務(wù)所在應(yīng)用的包名
            String packageName = jobStatus.job.getService().getPackageName();
            // 判斷該應(yīng)用是否空處于閑狀態(tài)
            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);
            }
            // 設(shè)置任務(wù)的空閑約束不滿足狀態(tài)
            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;
            // 循環(huán)判斷是否有應(yīng)用的空閑狀態(tài)發(fā)生變化
            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;
                }
            }
        }
        // 如果應(yīng)用的空閑狀態(tài)發(fā)生變化,則調(diào)用監(jiān)聽器的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) {
			    // 如果已經(jīng)是空閑狀態(tài),則直接返回
                if (mAppIdleParoleOn) {
                    return;
                }
                // 循環(huán)判斷空閑狀態(tài)發(fā)生變化的應(yīng)用是否在追蹤列表中
                for (JobStatus task : mTrackedTasks) {
                    if (task.job.getService().getPackageName().equals(packageName)
                            && task.getUserId() == userId) {
						// 判斷任務(wù)的空閑狀態(tài)是否發(fā)生改變
                        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) {
                // 調(diào)用監(jiān)聽器的onControllerStateChanged方法
                mStateChangedListener.onControllerStateChanged();
            }
        }

        @Override
        public void onParoleStateChanged(boolean isParoleOn) {
            if (DEBUG) {
                Slog.d(LOG_TAG, "Parole on: " + isParoleOn);
            }
			// 假釋應(yīng)用空閑
            setAppIdleParoleOn(isParoleOn);
        }
    }
}


上面5種約束條件的實現(xiàn)都差不多,在maybeStartTrackingJob方法中添加設(shè)置有各自約束的任務(wù),在maybeStopTrackingJob方法中移除任務(wù)。然后監(jiān)聽各自關(guān)心的狀態(tài)是否發(fā)生改變或得到滿足,發(fā)生變化則調(diào)用JobSchedulerService類的onControllerStateChanged方法,得到滿足則調(diào)用onRunJobNow方法:

/**
 * 當(dāng)某個控制器狀態(tài)發(fā)生變化時,向JobSchedulerService.JobHandler發(fā)送一條消息,以便將列表中某個任務(wù)開啟或停止執(zhí)行
 */
@Override
public void onControllerStateChanged() {
    mHandler.obtainMessage(MSG_CHECK_JOB).sendToTarget();
}

@Override
public void onRunJobNow(JobStatus jobStatus) {
    // 向Handler發(fā)送消息,開始執(zhí)行任務(wù)jobStatus
    mHandler.obtainMessage(MSG_JOB_EXPIRED, jobStatus).sendToTarget();
}


2.初始化JobHandler

那么接下來就看下JobSchedulerService的內(nèi)部類JobHandler的初始化以及handleMessage方法:

/**
 * 等待執(zhí)行任務(wù)列表。JobServiceContext類將會接收到該列表中可以開始執(zhí)行的任務(wù)
 */
final ArrayList<JobStatus> mPendingJobs = new ArrayList<>();
/**
 * Track Services that have currently active or pending jobs. The index is provided by
 * {@link JobStatus#getServiceToken()}
 */
final List<JobServiceContext> mActiveServices = new ArrayList<>();


private class JobHandler extends Handler {

    public JobHandler(Looper looper) {
        super(looper);
    }

    @Override
    public void handleMessage(Message message) {
        synchronized (mJobs) {
            // 如果沒有準(zhǔn)備好執(zhí)行任務(wù)則直接返回
            if (!mReadyToRock) {
                return;
            }
        }
        switch (message.what) {
            case MSG_JOB_EXPIRED:
                synchronized (mJobs) {
                    // 從消息中獲取到要執(zhí)行的任務(wù)
                    JobStatus runNow = (JobStatus) message.obj;
                    // runNow為null時所有準(zhǔn)備好的任務(wù)都要開始執(zhí)行
                    if (runNow != null && !mPendingJobs.contains(runNow)
                            && mJobs.containsJob(runNow)) {
                        // 把要執(zhí)行的任務(wù)添加到等待執(zhí)行任務(wù)列表
                        mPendingJobs.add(runNow);
                    }
                    // 遍歷任務(wù)列表,把準(zhǔn)備好執(zhí)行的任務(wù)添加到等待執(zhí)行任務(wù)列表,把準(zhǔn)備好取消的正在運行的任務(wù)取消
                    queueReadyJobsForExecutionLockedH();
                }
                break;
            case MSG_CHECK_JOB:
                synchronized (mJobs) {
                    // 檢查任務(wù)列表,把符合執(zhí)行要求的添加到等待執(zhí)行任務(wù)列表中
                    maybeQueueReadyJobsForExecutionLockedH();
                }
                break;
        }
        // 開始執(zhí)行等待執(zhí)行任務(wù)列表中的任務(wù)
        maybeRunPendingJobsH();
        // Don't remove JOB_EXPIRED in case one came along while processing the queue.
        removeMessages(MSG_CHECK_JOB);
    }

    /**
     * 遍歷任務(wù)列表,把準(zhǔn)備好執(zhí)行的任務(wù)添加到等待執(zhí)行任務(wù)列表,把準(zhǔn)備好取消的正在運行的任務(wù)取消
     */
    private void queueReadyJobsForExecutionLockedH() {
        // 取出任務(wù)
        ArraySet<JobStatus> jobs = mJobs.getJobs();
        if (DEBUG) {
            Slog.d(TAG, "queuing all ready jobs for execution:");
        }
        for (int i=0; i<jobs.size(); i++) {
            JobStatus job = jobs.valueAt(i);
            // 判斷任務(wù)是否準(zhǔn)備好執(zhí)行
            if (isReadyToBeExecutedLocked(job)) {
                if (DEBUG) {
                    Slog.d(TAG, "    queued " + job.toShortString());
                }
                // 把任務(wù)添加到等待執(zhí)行任務(wù)列表中
                mPendingJobs.add(job);
            // 判斷任務(wù)是否準(zhǔn)備好取消
            } else if (isReadyToBeCancelledLocked(job)) {
                // 取消正在運行的任務(wù)
                stopJobOnServiceContextLocked(job);
            }
        }
        if (DEBUG) {
            final int queuedJobs = mPendingJobs.size();
            if (queuedJobs == 0) {
                Slog.d(TAG, "No jobs pending.");
            } else {
                Slog.d(TAG, queuedJobs + " jobs queued.");
            }
        }
    }

    /**
     * 任務(wù)的狀態(tài)發(fā)生改變時,檢查所有任務(wù),并把符合開始執(zhí)行要求的任務(wù)添加到等待執(zhí)行任務(wù)列表中。
     */
    private void maybeQueueReadyJobsForExecutionLockedH() {
        // 記錄滿足充電條件的任務(wù)數(shù)量
        int chargingCount = 0;
        // 記錄滿足空閑狀態(tài)的任務(wù)數(shù)量
        int idleCount =  0;
        // 記錄后退任務(wù)的數(shù)量
        int backoffCount = 0;
        // 記錄滿足連接任務(wù)的數(shù)量
        int connectivityCount = 0;
        // 準(zhǔn)備好執(zhí)行任務(wù)的列表
        List<JobStatus> runnableJobs = new ArrayList<JobStatus>();
        ArraySet<JobStatus> jobs = mJobs.getJobs();
        for (int i=0; i<jobs.size(); i++) {
            JobStatus job = jobs.valueAt(i);
            // 判斷任務(wù)是否準(zhǔn)備好執(zhí)行
            if (isReadyToBeExecutedLocked(job)) {
                // 判斷任務(wù)執(zhí)行失敗的次數(shù)是否大于0
                if (job.getNumFailures() > 0) {
                    backoffCount++;
                }
                // 判斷是否滿足任務(wù)的空閑狀態(tài)要求
                if (job.hasIdleConstraint()) {
                    idleCount++;
                }
                // 判斷是否滿足任務(wù)的連接要求
                if (job.hasConnectivityConstraint() || job.hasUnmeteredConstraint()) {
                    connectivityCount++;
                }
                // 判斷是否滿足任務(wù)的充電要求
                if (job.hasChargingConstraint()) {
                    chargingCount++;
                }
                // 把準(zhǔn)備好執(zhí)行的任務(wù)添加到runnableJobs列表中
                runnableJobs.add(job);
            // 判斷任務(wù)是否準(zhǔn)備好取消執(zhí)行
            } else if (isReadyToBeCancelledLocked(job)) {
                // 取消正在執(zhí)行的任務(wù)
                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<runnableJobs.size(); i++) {
                // 把準(zhǔn)備好執(zhí)行的任務(wù)添加到等待執(zhí)行任務(wù)列表中
                mPendingJobs.add(runnableJobs.get(i));
            }
        } else {
            if (DEBUG) {
                Slog.d(TAG, "maybeQueueReadyJobsForExecutionLockedH: Not running anything.");
            }
        }
        if (DEBUG) {
            Slog.d(TAG, "idle=" + idleCount + " connectivity=" +
            connectivityCount + " charging=" + chargingCount + " tot=" +
                    runnableJobs.size());
        }
    }

    /**
     * 把任務(wù)添加到等待執(zhí)行列表中的條件:
     *      - It's ready.
     *      - It's not pending.
     *      - It's not already running on a JSC.
     *      - The user that requested the job is running.
     */
    private boolean isReadyToBeExecutedLocked(JobStatus job) {
        final boolean jobReady = job.isReady();
        final boolean jobPending = mPendingJobs.contains(job);
        final boolean jobActive = isCurrentlyActiveLocked(job);
        final boolean userRunning = mStartedUsers.contains(job.getUserId());
        if (DEBUG) {
            Slog.v(TAG, "isReadyToBeExecutedLocked: " + job.toShortString()
                    + " ready=" + jobReady + " pending=" + jobPending
                    + " active=" + jobActive + " userRunning=" + userRunning);
        }
        return userRunning && jobReady && !jobPending && !jobActive;
    }

    /**
     * 取消一個激活任務(wù)的條件:
     *      - It's not ready
     *      - It's running on a JSC.
     */
    private boolean isReadyToBeCancelledLocked(JobStatus job) {
        return !job.isReady() && isCurrentlyActiveLocked(job);
    }

    /**
     * 運行等待執(zhí)行任務(wù)列表中的任務(wù)
     */
    private void maybeRunPendingJobsH() {
	
	    /*要開始執(zhí)行任務(wù)了,故這里可以增加判斷,如果是息屏狀態(tài)或非充電狀態(tài)則直接return*/
        
        synchronized (mJobs) {
            // 如果設(shè)備處于空閑狀態(tài),則直接返回
            if (mDeviceIdleMode) {
                return;
            }
            Iterator<JobStatus> it = mPendingJobs.iterator();
            if (DEBUG) {
                Slog.d(TAG, "pending queue: " + mPendingJobs.size() + " jobs.");
            }
            while (it.hasNext()) {
                JobStatus nextPending = it.next();
                JobServiceContext availableContext = null;
				// 系統(tǒng)初始化時會循環(huán)給mActiveServices添加jsc,而循環(huán)的次數(shù)是:ActivityManager.isLowRamDeviceStatic() ? 1 : 3
                for (int i=0; i<mActiveServices.size(); i++) {
                    JobServiceContext jsc = mActiveServices.get(i);
                    final JobStatus running = jsc.getRunningJob();
                    // 如果任務(wù)正在運行則跳出循環(huán)
                    if (running != null && running.matches(nextPending.getUid(),
                            nextPending.getJobId())) {
                        availableContext = null;
                        break;
                    }
                    if (jsc.isAvailable()) {
                        availableContext = jsc;
                    }
                }
                if (availableContext != null) {
                    if (DEBUG) {
                        Slog.d(TAG, "About to run job "
                                + nextPending.getJob().getService().toString());
                    }
                    // 調(diào)用JobServiceContext的executeRunnableJob方法執(zhí)行任務(wù)
                    if (!availableContext.executeRunnableJob(nextPending)) {
                        if (DEBUG) {
                            Slog.d(TAG, "Error executing " + nextPending);
                        }
                        // 如果任務(wù)不能正常執(zhí)行,則從mJobs列表中移除該任務(wù)
                        mJobs.remove(nextPending);
                    }
                    it.remove();
                }
            }
        }
    }
}

// 判斷任務(wù)是否在激活狀態(tài)
private boolean isCurrentlyActiveLocked(JobStatus job) {
    for (int i=0; i<mActiveServices.size(); i++) {
        JobServiceContext serviceContext = mActiveServices.get(i);
        final JobStatus running = serviceContext.getRunningJob();
        if (running != null && running.matches(job.getUid(), job.getJobId())) {
            return true;
        }
    }
    return false;
}

// 取消正在運行的任務(wù)
private boolean stopJobOnServiceContextLocked(JobStatus job) {
    for (int i=0; i<mActiveServices.size(); i++) {
        JobServiceContext jsc = mActiveServices.get(i);
        final JobStatus executing = jsc.getRunningJob();
        if (executing != null && executing.matches(job.getUid(), job.getJobId())) {
            jsc.cancelExecutingJob();
            return true;
        }
    }
    return false;
}


執(zhí)行任務(wù)時調(diào)用的是JobServiceContext類中的executeRunnableJob方法:

/**
 * 執(zhí)行傳遞過來的任務(wù),調(diào)用者必須先檢查context可用以確保能正常執(zhí)行任務(wù)。
 * @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();
        // 以任務(wù)所在服務(wù)的組件名創(chuàng)建Intent
        final Intent intent = new Intent().setComponent(job.getServiceComponent());
        
        /*這里可以為intent put一個參數(shù),在ActiveServices類的bindServiceLocked方法
         * 中取出該參數(shù)以判斷服務(wù)是從JobSchedulerService開啟的,以便禁止服務(wù)啟動來達到禁止
         * 應(yīng)用通過JobSchedulerService的方式來自啟的目的*/
        
        // 通過bindServiceAsUser的方式開啟任務(wù)所在的服務(wù)
        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方法中傳遞的服務(wù)是this,故綁定成功后調(diào)用的是JobServiceContext類中的onServiceConnected方法:

/**
 * 在onServiceConnected或unbindService中獲取或釋放wakelock。當(dāng)服務(wù)unbound時停止向客戶端發(fā)送任務(wù),直到持有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;
    }
    // 如果正在執(zhí)行的任務(wù)為null或者正在執(zhí)行的任務(wù)所在的組件名不等于綁定服務(wù)的組件名則停止執(zhí)行任務(wù)
    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發(fā)送綁定服務(wù)成功的消息
    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:
                // 移除掉操作超時的任務(wù)
                removeOpTimeOut();
                // 處理綁定成功的操作
                handleServiceBoundH();
                break;
            . . .
            default:
                Slog.e(TAG, "Unrecognised message: " + message);
        }
    }

    /** 處理綁定服務(wù)成功的操作. */
    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();
            // 調(diào)用JobService的startJob方法
            service.startJob(mParams);
        } catch (RemoteException e) {
            Slog.e(TAG, "Error sending onStart message to '" +
                    mRunningJob.getServiceComponent().getShortClassName() + "' ", e);
        }
    }

}


到這里調(diào)用到了JobService的startJob方法。下面看下JobService的實現(xiàn)原理:

/**
 * 從JobScheduler回調(diào)方法的入口。這是處理之前安排的異步請求的基類。
 * 使用時需要重寫onStartJob方法來寫任務(wù)的執(zhí)行邏輯。
 * 該服務(wù)執(zhí)行運行在應(yīng)用程序主線程的Handler傳遞過來的每個任務(wù)。這意味著你必須在thread/handler/AsyncTask
 * 中實現(xiàn)執(zhí)行的邏輯。不這樣做將導(dǎo)致來自JobManager的任務(wù)阻塞,無法繼續(xù)執(zhí)行。
 */
// JobService是實現(xiàn)了Service的抽象類
public abstract class JobService extends Service {
    private static final String TAG = "JobService";

    /**
     * JobService的子類必須在Manifest中聲明該權(quán)限,如:
     * <service android:name="MyJobService"
     *          android:permission="android.permission.BIND_JOB_SERVICE" >
     *     ...
     * </service>
     */
    public static final String PERMISSION_BIND =
            "android.permission.BIND_JOB_SERVICE";

    // 調(diào)用onStartJob方法的標(biāo)識符
    private final int MSG_EXECUTE_JOB = 0;
    
    // 調(diào)用onStopJob方法的標(biāo)識符
    private final int MSG_STOP_JOB = 1;
    
    // 任務(wù)完成的標(biāo)識符
    private final int MSG_JOB_FINISHED = 2;

    // mHandler的鎖對象
    private final Object mHandlerLock = new Object();

    // 處理post傳來的任務(wù):負(fù)責(zé)調(diào)用到客戶端的邏輯和處理系統(tǒng)回調(diào)
    @GuardedBy("mHandlerLock")
    JobHandler mHandler;

    // 服務(wù)的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);
            // 把消息發(fā)送給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) {
                // 創(chuàng)建Handler對象時傳遞的是主線程的looper,即消息會在主線程中處理
                mHandler = new JobHandler(getMainLooper());
            }
        }
    }

    /**
     * 運行在應(yīng)用程序的主線程 - 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 {
                        // 執(zhí)行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 {
                     // 執(zhí)行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:
                    // 從消息中獲取任務(wù)是否需要重試
                    final boolean needsReschedule = (msg.arg2 == 1);
                    // 從參數(shù)中獲取回調(diào)接口
                    IJobCallback callback = params.getCallback();
                    if (callback != null) {
                        try {
                            // 調(diào)用回調(diào)接口中的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的回調(diào)接口
            final IJobCallback callback = params.getCallback();
            final int jobId = params.getJobId();
            if (callback != null) {
                try {
                    //調(diào)用回調(diào)接口中的acknowledgeStartMessage方法
                    callback.acknowledgeStartMessage(jobId, workOngoing);
                } catch (RemoteException e) {
                    Log.e(TAG, "System unreachable for starting job.");
                }
            } else {
                // 任務(wù)已經(jīng)處理完了
                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();
    }

    /**
     * 抽象方法,需要子類重寫該方法,在該方法中寫執(zhí)行任務(wù)的邏輯,該方法運行在主線程
     *
     * @param params 任務(wù)相關(guān)的參數(shù),包括在創(chuàng)建任務(wù)時自己設(shè)定的所有參數(shù)
     * @return true:如果要執(zhí)行的任務(wù)比較耗時,并且當(dāng)任務(wù)完成時需要調(diào)用jobFinished()方法來通知系統(tǒng)
     *         false:如果要執(zhí)行的任務(wù)不耗時 
     *         
     */
    public abstract boolean onStartJob(JobParameters params);

    /**
     * 抽象方法,需要子類重寫該方法,在該方法中寫任務(wù)停止時的邏輯,該方法運行在主線程
     * 該方法被調(diào)用場景:在執(zhí)行任務(wù)時,規(guī)定的要求已不再滿足。
     * 如果不重寫這個方法,系統(tǒng)可能不再為你的應(yīng)用程序持有wakelock
     *
     * @param params 任務(wù)相關(guān)的參數(shù).
     * @return true:基于在創(chuàng)建任務(wù)時設(shè)定的重試機制指示JobManager是否要重新安排任務(wù)。
     *         false:丟棄本次任務(wù)。
     * 無論返回什么值,任務(wù)必須停止執(zhí)行。
     */
    public abstract boolean onStopJob(JobParameters params);

    /**
     * 通知JobManager任務(wù)已經(jīng)執(zhí)行完成的回調(diào)方法。該方法可以從任何線程中調(diào)用,因為該方法最終會在應(yīng)用程序的主線程中執(zhí)行。
     * 當(dāng)系統(tǒng)收到這個消息時,它會釋放持有的wakelock鎖。
     * 可以根據(jù)needsReschedule參數(shù)寫執(zhí)行后的操作,基于默認(rèn)值或使用setBackoffCriteria方法設(shè)置的值回退任務(wù)的定時器。
     * 運行在空閑模式的任務(wù)是不能回退的。這可能會導(dǎo)致任務(wù)重復(fù)添加到任務(wù)隊列中,并且在未來的某個空閑時間內(nèi)重復(fù)執(zhí)行該任務(wù)。
     *
     * @param params 通過onStartJob方法傳遞的JobParameters參數(shù)
     * @param needsReschedule true:如果該任務(wù)需要重寫安排
     *                        false:其他情況
     */
    public final void jobFinished(JobParameters params, boolean needsReschedule) {
        ensureHandler();
        // 把參數(shù)封裝成消息
        Message m = Message.obtain(mHandler, MSG_JOB_FINISHED, params);
        m.arg2 = needsReschedule ? 1 : 0;
        // 把消息發(fā)送給mHandler
        m.sendToTarget();
    }
}


看下IJobService.aidl的定義:

package android.app.job;

import android.app.job.JobParameters;

/**
 * 這是一個framework用來與繼承自JobService的應(yīng)用程序代碼進行通信的接口。
 * 應(yīng)用程序代碼不直接實現(xiàn)該接口,而是繼承自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,意思是如果調(diào)用者和被調(diào)用者在同一個進程則同步執(zhí)行,如果不在同一個進程則異步執(zhí)行,即:調(diào)用該接口中的方法后不需要等待方法執(zhí)行完成。

3.初始化JobSchedulerStub代理對象

下面就看下JobSchedulerService的內(nèi)部類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<Boolean> mPersistCache = new SparseArray<Boolean>();

    // 執(zhí)行只有應(yīng)用程序自己可以調(diào)度運行在自己服務(wù)中的任務(wù),以及驗證服務(wù)是否有BIND_JOB_SERVICE權(quán)限。
    private void enforceValidJobRequest(int uid, JobInfo job) {
        final IPackageManager pm = AppGlobals.getPackageManager();
        // 獲取任務(wù)所在服務(wù)組件名
        final ComponentName service = job.getService();
        try {
            // 獲取服務(wù)相關(guān)信息
            ServiceInfo si = pm.getServiceInfo(service, 0, UserHandle.getUserId(uid));
            // 如果服務(wù)相關(guān)信息為null則拋異常
            if (si == null) {
                throw new IllegalArgumentException("No such service " + service);
            }
            // 如果調(diào)用者的uid和服務(wù)所在應(yīng)用程序的uid不同則拋異常
            if (si.applicationInfo.uid != uid) {
                throw new IllegalArgumentException("uid " + uid +
                        " cannot schedule job in " + service.getPackageName());
            }
            // 如果服務(wù)沒有設(shè)置BIND_JOB_SERVICE權(quán)限,則拋異常
            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) {
        // 檢查服務(wù)是否可以是永久性的執(zhí)行任務(wù)
        final boolean canPersist;
        synchronized (mPersistCache) {
            Boolean cached = mPersistCache.get(uid);
            // 如果cached不為null,則直接取值返回
            if (cached != null) {
                canPersist = cached.booleanValue();
            } else {
                // 永久性任務(wù)相當(dāng)于在手機啟動時運行,所以它所在的app需要聲明RECEIVE_BOOT_COMPLETED權(quán)限
                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());
        }
        // 獲取調(diào)用者pid
        final int pid = Binder.getCallingPid();.
        // 獲取調(diào)用者uid
        final int uid = Binder.getCallingUid();

        // 判斷服務(wù)的有效性
        enforceValidJobRequest(uid, job);
        // 服務(wù)是否是永久性的判斷
        if (job.isPersisted()) {
            // 根據(jù)pid、uid判斷服務(wù)是否可以是永久性的,如果不是則拋異常
            if (!canPersistJobs(pid, uid)) {
                throw new IllegalArgumentException("Error: requested job be persisted without"
                        + " holding RECEIVE_BOOT_COMPLETED permission.");
            }
        }

        long ident = Binder.clearCallingIdentity();
        try {
            // 調(diào)用JobSchedulerService類的schedule方法
            return JobSchedulerService.this.schedule(job, uid);
        } finally {
            Binder.restoreCallingIdentity(ident);
        }
    }

    @Override
    public List<JobInfo> getAllPendingJobs() throws RemoteException {
        final int uid = Binder.getCallingUid();

        long ident = Binder.clearCallingIdentity();
        try {
            // 調(diào)用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 {
            // 調(diào)用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 {
            // 調(diào)用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.初始化任務(wù)主列表

接著看JobStore類的initAndGet方法:

/** 使用JobSchedulerService初始化JobStore. */
static JobStore initAndGet(JobSchedulerService jobManagerService) {
    synchronized (sSingletonLock) {
        if (sSingleton == null) {
            sSingleton = new JobStore(jobManagerService.getContext(),
                    Environment.getDataDirectory());
        }
        return sSingleton;
    }
}

/**
 * 構(gòu)造任務(wù)存儲的實例。結(jié)果是一個會從磁盤中讀出的塊
 * 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");
    // 創(chuàng)建data/system/job目錄
    jobDir.mkdirs();
    // 在data/system/job目錄下創(chuàng)建jobs.xml文件
    mJobsFile = new AtomicFile(new File(jobDir, "jobs.xml"));

    mJobSet = new ArraySet<JobStatus>();

    // 從磁盤中讀取任務(wù)map存放在mJobSet中,xml文件的解析,不再粘貼源碼
    readJobMapFromDisk(mJobSet);
}


下面看下JobSchedulerService類的onStart方法:

@Override
public void onStart() {
    // 調(diào)用父類SystemService的publishBinderService方法將mJobSchedulerStub發(fā)布出去
    publishBinderService(Context.JOB_SCHEDULER_SERVICE, mJobSchedulerStub);
}

SystemService類中的publishBinderService方法:
/**
* 發(fā)布服務(wù),以便其他服務(wù)或應(yīng)用程序能調(diào)用該服務(wù)。
*/
protected final void publishBinderService(String name, IBinder service) {
    publishBinderService(name, service, false);
}
   
/**
* 發(fā)布服務(wù),以便其他服務(wù)或應(yīng)用程序能調(diào)用該服務(wù)。
*/
protected final void publishBinderService(String name, IBinder service,
        boolean allowIsolated) {
    // 把服務(wù)添加到ServiceManager中,以便其他服務(wù)或應(yīng)用程序能夠調(diào)用該服務(wù)
    // getSystemService時就是根據(jù)name獲取到該服務(wù)的
    ServiceManager.addService(name, service, allowIsolated);
}


到這里JobSchedulerService的啟動流程就分析完了。在分析啟動流程的時候,任務(wù)各種約束的添加任務(wù)、移除任務(wù)、監(jiān)聽任務(wù)的狀態(tài)變化以及任務(wù)的執(zhí)行等操作也都跟著分析了。

下面分析下使用JobSchedulerService的流程,主要是看怎么把任務(wù)添加到主任務(wù)列表中并開始追蹤的。

應(yīng)用通過getSystemService方法獲取系統(tǒng)服務(wù)時,會調(diào)用到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) {
    // 根據(jù)服務(wù)名從map中取出ServiceFetcher
    ServiceFetcher<?> fetcher = SYSTEM_SERVICE_FETCHERS.get(name);
    // 如果fetcher不為null,則從fetcher中根據(jù)ctx取出對應(yīng)的服務(wù)并返回
    return fetcher != null ? fetcher.getService(ctx) : null;
}


但是在SystemServiceRegistry類的靜態(tài)代碼塊中注冊服務(wù)時,就是把上面發(fā)布到ServiceManager中的Binder代理對象mJobSchedulerStub返回給createService方法:

static {
    . . .
    registerService(Context.JOB_SCHEDULER_SERVICE, JobScheduler.class,
            new StaticServiceFetcher<JobScheduler>() {
        @Override
        public JobScheduler createService() {
            IBinder b = ServiceManager.getService(Context.JOB_SCHEDULER_SERVICE);
            return new JobSchedulerImpl(IJobScheduler.Stub.asInterface(b));
        }});

}

private static <T> void registerService(String serviceName, Class<T> serviceClass,
        ServiceFetcher<T> serviceFetcher) {
    SYSTEM_SERVICE_NAMES.put(serviceClass, serviceName);
    SYSTEM_SERVICE_FETCHERS.put(serviceName, serviceFetcher);
}

static abstract interface ServiceFetcher<T> {
    T getService(ContextImpl ctx);
}

static abstract class StaticServiceFetcher<T> implements ServiceFetcher<T> {
    private T mCachedInstance;

    @Override
    public final T getService(ContextImpl unused) {
        // 單例懶加載模式,具體的創(chuàng)建由子類實現(xiàn)
        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;
        }
    }
    . . .

}


也就是說,其他應(yīng)用通過getSystemService(Context.JOB_SCHEDULER_SERVICE)方法獲取到的JobScheduler對象中的Binder對象其實就是JobSchedulerService類中的JobSchedulerStub代理對象。

下面看下其他應(yīng)用調(diào)用JobScheduler的schedule方法的流程,由上面分析知,其他應(yīng)用通過JobScheduler對象調(diào)用schedule方法其實是調(diào)用的JobSchedulerService類中的JobSchedulerStub代理對象的schedule方法。由上面代理對象的schedule方法知,它調(diào)用了JobSchedulerService類的schedule方法:

public int schedule(JobInfo job, int uId) {
    JobStatus jobStatus = new JobStatus(job, uId);
    // 如果任務(wù)已經(jīng)在等待隊列或已經(jīng)在執(zhí)行則從等待隊列中移除或取消任務(wù)的執(zhí)行
    cancelJob(uId, job.getId());
    // 開始追蹤任務(wù)
    startTrackingJob(jobStatus);
    // 向Handler發(fā)送檢查任務(wù)的消息
    mHandler.obtainMessage(MSG_CHECK_JOB).sendToTarget();
    return JobScheduler.RESULT_SUCCESS;
}

private void startTrackingJob(JobStatus jobStatus) {
    boolean update;
    boolean rocking;
    synchronized (mJobs) {
        // 把新任務(wù)添加到主列表中
        update = mJobs.add(jobStatus);
        rocking = mReadyToRock;
    }
    if (rocking) {
        // 循環(huán)獲取所有控制器,并回調(diào)控制器的開始追蹤方法
        for (int i=0; i<mControllers.size(); i++) {
            StateController controller = mControllers.get(i);
            if (update) {
                controller.maybeStopTrackingJob(jobStatus);
            }
            controller.maybeStartTrackingJob(jobStatus);
        }
    }
}


到這里,任務(wù)的添加、追蹤邏輯就分析完了。

代碼量較大,理解錯誤或有偏差之處請指正,謝謝!

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多