|
之前有篇文章專門介紹了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);
. . .
}
}
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;
}
// 任務(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);
}
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);
}
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);
}
下面按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());
}
}
}
由于該控制器跟任務(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")
+ ")");
}
}
}
該控制器的大致實現(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("..");
}
}
}
}
該控制器的大致實現(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();
}
}
}
該控制器的大致實現(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);
}
}
}
/**
* 當(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();
}
那么接下來就看下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)用者必須先檢查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;
}
}
/**
* 在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);
}
}
}
/**
* 從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();
}
}
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);
}
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);
}
}
};
接著看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);
}
@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ù)列表中并開始追蹤的。 應(yīng)用通過getSystemService方法獲取系統(tǒng)服務(wù)時,會調(diào)用到ContextImpl類的getSystemService方法中: @Override
public Object getSystemService(String name) {
return SystemServiceRegistry.getSystemService(this, name);
}
/**
* 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;
}
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();
}
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)用調(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);
}
}
}
代碼量較大,理解錯誤或有偏差之處請指正,謝謝! |
|
|