【Android 电量优化】JobScheduler 相关源码分析 ( JobSchedulerService 源码分析 | 任务检查 | 任务执行 )
文章目錄
- 一、回調 StateChangedListener 接口
- 二、JobHandler 處理 ( 任務檢查 )
- 三、maybeRunPendingJobsH 方法
- 四、assignJobsToContextsLocked 方法 ( 任務執行 )
- 五、JobSchedulerService 部分源碼注釋
推薦代碼查看網站 :
-
https://www.androidos.net.cn/sourcecode ( 推薦 )
-
http://androidxref.com/
一、回調 StateChangedListener 接口
上一篇博客 【Android 電量優化】JobScheduler 相關源碼分析 ( ConnectivityController 底層源碼分析 | 構造函數 | 追蹤任務更新 | 注冊接收者監聽連接變化 ) 中 ConnectivityController 最后調用了 mStateChangedListener 任務狀態改變監聽器接口的 onControllerStateChanged 方法 , 該接口實際上是 JobSchedulerService 類型的對象 ;
StateController 狀態控制器創建時 , 會傳入 mStateChangedListener , 該狀態改變監聽器就是 JobSchedulerService , 其實現了 StateChangedListener 接口 ; 如下代碼中 , ConnectivityController 創建時 , 通過 get 方法設置了 JobSchedulerService 為狀態監聽器 ;
public final class JobSchedulerService extends com.android.server.SystemServiceimplements StateChangedListener, JobCompletedListener {// ... public JobSchedulerService(Context context) {// ...// 創建控制器集合mControllers = new ArrayList<StateController>();// 網絡連接控制器mControllers.add(ConnectivityController.get(this));// ... }// ... }在實現接口的 onControllerStateChanged 方法中 , 傳遞消息給 com.android.server.job.JobSchedulerService.JobHandler , 通知如下內容 : 一些控制器的狀態發生了改變 , 以便去遍歷集合并開啟或停止相應的任務 ;
// public final class JobSchedulerService extends com.android.server.SystemServiceimplements StateChangedListener, JobCompletedListener {// .../*** 實現的 StateChangedListener 接口方法* 傳遞消息給 com.android.server.job.JobSchedulerService.JobHandler , * 通知如下內容 : 一些控制器的狀態發生了改變 , 以便去遍歷集合并開啟或停止相應的任務*/@Overridepublic void onControllerStateChanged() {// 發送了 Handler 信息mHandler.obtainMessage(MSG_CHECK_JOB).sendToTarget();}// ... }二、JobHandler 處理 ( 任務檢查 )
JobHandler 是定義在 JobSchedulerService 中的內部類 , 在該類中通過接收不同的 Message 信息 , 進行任務超時處理 , 任務檢查 , 任務貪婪檢查 , 任務停止 444 個操作 ;
構造函數 : 使用主線程的 context.getMainLooper() 作為參數 ;
處理消息 : 根據不同的消息的 what 標識 , 進行不同的任務處理 ;
-
MSG_JOB_EXPIRED : 處理超時任務 , 首先 獲取任務狀態 , 任務狀態可能是空的 , 這是控制器表示其狀態的一種方式 , 所有已準備的任務應該馬上被執行 ;
-
MSG_CHECK_JOB : 檢查任務 , 查看任務執行是否滿足條件 , 如果滿足就啟動任務 ; 如果當前正在執行任務 , 將本次準備好了的任務放入待執行隊列中準備執行 ; 反之如果當前沒有執行任務 , 檢查任務集合 , 如果合適運行其中的一些工任務 ;
-
MSG_CHECK_JOB_GREEDY : 貪婪檢查任務 , 不管當前有沒有正在執行任務 , 都將本次準備好了的任務放入待執行隊列中準備執行 ;
-
MSG_STOP_JOB : 停止正在執行的任務 ;
上述操作都是針對任務隊列的 ;
maybeRunPendingJobsH 方法是真正執行任務的核心邏輯 ;
public final class JobSchedulerService extends com.android.server.SystemServiceimplements StateChangedListener, JobCompletedListener {// ...final JobHandler mHandler;// ... // JobHandler 內部類private class JobHandler extends Handler {// 構造函數 , 使用主線程的 context.getMainLooper() 作為參數public JobHandler(Looper looper) {super(looper);}@Overridepublic void handleMessage(Message message) {synchronized (mLock) {if (!mReadyToRock) {return;}}// 根據 message.what 處理消息switch (message.what) {case MSG_JOB_EXPIRED:// 處理超時任務synchronized (mLock) {// 獲取任務狀態 JobStatus runNow = (JobStatus) message.obj;// runNow 任務狀態可能是空的 , // 這是控制器表示其狀態的一種方式 , // 所有已準備的任務應該馬上被執行 ; if (runNow != null && !mPendingJobs.contains(runNow)&& mJobs.containsJob(runNow)) {mJobPackageTracker.notePending(runNow);mPendingJobs.add(runNow);}// 如果當前正在執行任務 , 將本次準備好了的任務放入待執行隊列中準備執行queueReadyJobsForExecutionLockedH();}break;case MSG_CHECK_JOB:// 檢查任務 synchronized (mLock) {// 查看任務執行是否滿足條件 , 如果滿足就啟動任務 if (mReportedActive) {// 如果當前正在執行任務 , 將本次準備好了的任務放入待執行隊列中準備執行queueReadyJobsForExecutionLockedH();} else {// 檢查任務集合 , 如果合適運行其中的一些工任務maybeQueueReadyJobsForExecutionLockedH();}}break;case MSG_CHECK_JOB_GREEDY:// 貪婪的檢查任務 , 直接將當前準備好的任務放入待執行隊列中synchronized (mLock) {queueReadyJobsForExecutionLockedH();}break;case MSG_STOP_JOB:// 停止任務 cancelJobImpl((JobStatus)message.obj, null);break;}// 這里是真正執行任務的核心邏輯maybeRunPendingJobsH();// 移除 MSG_CHECK_JOB 任務 // JOB_EXPIRED 異步任務不能移除 , 防止處理隊列時 JOB_EXPIRED 類型消息到達removeMessages(MSG_CHECK_JOB);}}
三、maybeRunPendingJobsH 方法
maybeRunPendingJobsH 方法中 , 根據可用的執行上下文 , 協調等待隊列中的任務 ; 控制器可以強制將任務放入等待隊列中 , 即使該任務已經在運行中 ; 在這里我們可以決定是否真正地執行該操作 ;
在 assignJobsToContextsLocked 方法中 , 啟動任務 ;
public final class JobSchedulerService extends com.android.server.SystemServiceimplements StateChangedListener, JobCompletedListener {// ... /*** 根據可用的執行上下文 , 協調等待隊列中的任務 ; * 控制器可以強制將任務放入等待隊列中 , 即使該任務已經在運行中 ; * 在這里我們可以決定是否真正地執行該操作 ; */private void maybeRunPendingJobsH() {synchronized (mLock) {if (DEBUG) {Slog.d(TAG, "pending queue: " + mPendingJobs.size() + " jobs.");}// 在該函數中啟動任務 assignJobsToContextsLocked();reportActive();}}// ... }
四、assignJobsToContextsLocked 方法 ( 任務執行 )
assignJobsToContextsLocked 方法作用 : 從等待隊列中獲取任務 , 并在可用的上下文中執行它們 , 如果當前沒有可用的上下文 , 執行高優先級任務 , 取代執行低優先級任務 ;
assignJobsToContextsLocked 方法代碼邏輯 :
-
獲取可執行任務數 : 獲取內存等級 , 根據內存等級確定最大的激活任務數 , 不同的可用內存等級 , 有不同的任務數 , 內存容量高 , 可同時執行的任務多 ;
-
記錄任務 : 使用 JobStatus[] contextIdToJobMap 記錄可執行任務 ;
-
獲取任務 : 開始遍歷 mPendingJobs 待執行任務集合 , 如果獲取到可執行任務 , 放入 contextIdToJobMap 集合中 ;
-
執行任務 : 遍歷 contextIdToJobMap 集合 , 從該集合中取出可執行任務并執行 ;
執行任務方法 : 使用 mActiveServices.get(i).executeRunnableJob(pendingJob) 方法執行任務 , mActiveServices 集合元素類型是 JobServiceContext , 調用該 JobServiceContext 類對象的 executeRunnableJob 方法 , 傳入 pendingJob 待執行任務 , 即可執行該任務 ;
五、JobSchedulerService 部分源碼注釋
public final class JobSchedulerService extends com.android.server.SystemServiceimplements StateChangedListener, JobCompletedListener {/** 任務的主要集合. */final JobStore mJobs;final JobHandler mHandler;/*** 該數組實際存儲了 mActiveServices 數組狀態 .* 該數組第 i 個索引存儲了第 i 個 JobServiceContext 的任務 . * 我們會操作該數組 , 直到我們已經知道了哪些任務應該在哪些 JobServiceContext 上執行 .*/JobStatus[] mTmpAssignContextIdToJobMap = new JobStatus[MAX_JOB_CONTEXTS_COUNT];/*** 追蹤那些已經激活或者等待執行額任務對應的服務 . * 對應的索引由 JobStatus.getServiceToken() 方法提供 .*/final List<JobServiceContext> mActiveServices = new ArrayList<>();public JobSchedulerService(Context context) {super(context);// 創建 Handler mHandler = new JobHandler(context.getMainLooper());// 創建控制器集合mControllers = new ArrayList<StateController>();// 網絡連接控制器mControllers.add(ConnectivityController.get(this));// ... }/*** 實現的 StateChangedListener 接口方法* 傳遞消息給 com.android.server.job.JobSchedulerService.JobHandler , * 通知如下內容 : 一些控制器的狀態發生了改變 , 以便去遍歷集合并開啟或停止相應的任務*/@Overridepublic void onControllerStateChanged() {// 發送了 Handler 信息mHandler.obtainMessage(MSG_CHECK_JOB).sendToTarget();}// JobHandler 內部類private class JobHandler extends Handler {// 構造函數 , 使用主線程的 context.getMainLooper() 作為參數public JobHandler(Looper looper) {super(looper);}@Overridepublic void handleMessage(Message message) {synchronized (mLock) {if (!mReadyToRock) {return;}}// 根據 message.what 處理消息switch (message.what) {case MSG_JOB_EXPIRED:// 處理超時任務synchronized (mLock) {// 獲取任務狀態 JobStatus runNow = (JobStatus) message.obj;// runNow 任務狀態可能是空的 , // 這是控制器表示其狀態的一種方式 , // 所有已準備的任務應該馬上被執行 ; if (runNow != null && !mPendingJobs.contains(runNow)&& mJobs.containsJob(runNow)) {mJobPackageTracker.notePending(runNow);mPendingJobs.add(runNow);}// 如果當前正在執行任務 , 將本次準備好了的任務放入待執行隊列中準備執行queueReadyJobsForExecutionLockedH();}break;case MSG_CHECK_JOB:// 檢查任務 synchronized (mLock) {// 查看任務執行是否滿足條件 , 如果滿足就啟動任務 if (mReportedActive) {// 如果當前正在執行任務 , 將本次準備好了的任務放入待執行隊列中準備執行queueReadyJobsForExecutionLockedH();} else {// 檢查任務集合 , 如果合適運行其中的一些工任務maybeQueueReadyJobsForExecutionLockedH();}}break;case MSG_CHECK_JOB_GREEDY:// 貪婪的檢查任務 , 直接將當前準備好的任務放入待執行隊列中synchronized (mLock) {queueReadyJobsForExecutionLockedH();}break;case MSG_STOP_JOB:// 停止任務 cancelJobImpl((JobStatus)message.obj, null);break;}// 這里是真正執行任務的核心邏輯maybeRunPendingJobsH();// 移除 MSG_CHECK_JOB 任務 // JOB_EXPIRED 異步任務不能移除 , 防止處理隊列時 JOB_EXPIRED 類型消息到達removeMessages(MSG_CHECK_JOB);}// 設置狀態變化 , 將滿足條件的任務放入 mPendingJobs 集合中 private void maybeQueueReadyJobsForExecutionLockedH() {if (DEBUG) Slog.d(TAG, "Maybe queuing ready jobs...");noteJobsNonpending(mPendingJobs);mPendingJobs.clear();mJobs.forEachJob(mMaybeQueueFunctor);mMaybeQueueFunctor.postProcess();}/*** 根據可用的執行上下文 , 協調等待隊列中的任務 ; * 控制器可以強制將任務放入等待隊列中 , 即使該任務已經在運行中 ; * 在這里我們可以決定是否真正地執行該操作 ; */private void maybeRunPendingJobsH() {synchronized (mLock) {if (DEBUG) {Slog.d(TAG, "pending queue: " + mPendingJobs.size() + " jobs.");}// 在該函數中啟動任務 assignJobsToContextsLocked();reportActive();}}/*** 從等待隊列中獲取任務 , 并在可用的上下文中執行它們 ; * 如果當前沒有可用的上下文 ; * 這里的上下文指的是四大組件或者 Application ; * 執行高優先級任務 , 取代執行低優先級任務 ; */private void assignJobsToContextsLocked() {if (DEBUG) {Slog.d(TAG, printPendingQueue());}// 獲取內存等級int memLevel;try {memLevel = ActivityManagerNative.getDefault().getMemoryTrimLevel();} catch (RemoteException e) {memLevel = ProcessStats.ADJ_MEM_FACTOR_NORMAL;}// 根據內存等級確定最大的激活任務數 // 不同的可用內存等級 , 有不同的任務數 , 內存容量高 , 可同時執行的任務多 switch (memLevel) {case ProcessStats.ADJ_MEM_FACTOR_MODERATE:mMaxActiveJobs = mConstants.BG_MODERATE_JOB_COUNT;break;case ProcessStats.ADJ_MEM_FACTOR_LOW:mMaxActiveJobs = mConstants.BG_LOW_JOB_COUNT;break;case ProcessStats.ADJ_MEM_FACTOR_CRITICAL:mMaxActiveJobs = mConstants.BG_CRITICAL_JOB_COUNT;break;default:mMaxActiveJobs = mConstants.BG_NORMAL_JOB_COUNT;break;}// 用于記錄可執行任務 , JobStatus[] contextIdToJobMap = mTmpAssignContextIdToJobMap;// ... // 開始遍歷 mPendingJobs 待執行任務集合 // 啟動任務 for (int i=0; i<mPendingJobs.size(); i++) {// 獲取一個待執行任務 JobStatus nextPending = mPendingJobs.get(i);// 如果當前任務正在執行 , 處理下一個任務int jobRunningContext = findJobContextIdFromMap(nextPending, contextIdToJobMap);if (jobRunningContext != -1) {continue;}// 進行一系列判斷 ... if (minPriorityContextId != -1) {// 獲取到可執行任務 , 放入 contextIdToJobMap 集合中contextIdToJobMap[minPriorityContextId] = nextPending;act[minPriorityContextId] = true;numActive++;if (priority >= JobInfo.PRIORITY_TOP_APP) {numForeground++;}}}mJobPackageTracker.noteConcurrency(numActive, numForeground);// 遍歷 contextIdToJobMap 集合 , 從該集合中取出可執行任務并執行for (int i=0; i<MAX_JOB_CONTEXTS_COUNT; i++) {boolean preservePreferredUid = false;if (act[i]) {JobStatus js = mActiveServices.get(i).getRunningJob();if (js != null) {// ... } else {// 取出要執行的任務final JobStatus pendingJob = contextIdToJobMap[i];// ...// executeRunnableJob 方法用于正式執行任務 // mActiveServices 集合元素類型是 JobServiceContext // 調用的 executeRunnableJob 方法定義在 JobServiceContext 中 if (!mActiveServices.get(i).executeRunnableJob(pendingJob)) {Slog.d(TAG, "Error executing " + pendingJob);}if (mPendingJobs.remove(pendingJob)) {mJobPackageTracker.noteNonpending(pendingJob);}}}if (!preservePreferredUid) {mActiveServices.get(i).clearPreferredUid();}}}}
該代碼路徑為 /frameworks/base/services/core/java/com/android/server/job/JobSchedulerService.java , 點擊鏈接可跳轉查看完整源碼 ;
本篇博客涉及到的源碼 :
- /frameworks/base/services/core/java/com/android/server/job/JobSchedulerService.java
總結
以上是生活随笔為你收集整理的【Android 电量优化】JobScheduler 相关源码分析 ( JobSchedulerService 源码分析 | 任务检查 | 任务执行 )的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【Android 电量优化】JobSch
- 下一篇: 【Android 电量优化】JobSch