Android Q系統(tǒng)JobScheduler原理介紹

Job任務(wù)是Android系統(tǒng)上非及時(shí)性任務(wù)的一種運(yùn)行機(jī)制院促,由系統(tǒng)根據(jù)使用者的條件設(shè)置統(tǒng)一管理運(yùn)行醋虏,有條件性,周期性谭胚,統(tǒng)一執(zhí)行徐块,延遲執(zhí)行等特性未玻;為移動(dòng)設(shè)備性能和功耗帶來良好收益。Google自Android M起引入JobScheduler概念胡控,建議非必要alarm操作用該模式替換扳剿,讓其JobService運(yùn)行的Job任務(wù)滿足條件后開始執(zhí)行,之后Andoroid的每一個(gè)版本都有該功能的增添昼激。主要設(shè)計(jì)思想是懶執(zhí)行概念庇绽,滿足必要條件才觸發(fā)執(zhí)行。

本文基于Android Q代碼介紹橙困。

本文檔閱讀時(shí)間50分鐘瞧掺,黑色字體可作為本文檔的簡讀版本。

1. Job任務(wù)執(zhí)行原理概覽

使用者構(gòu)建Job任務(wù)纷宇,把其構(gòu)建信息傳遞給Job任務(wù)管理系統(tǒng)夸盟;任務(wù)管理系統(tǒng)負(fù)責(zé)Job任務(wù)滿足條件的觸發(fā),Job任務(wù)相應(yīng)的執(zhí)行和生命周期管理像捶。

執(zhí)行模塊如下圖所示上陕,紫色區(qū)域代表Job任務(wù)使用者創(chuàng)建模塊,紅色區(qū)域代表Job任務(wù)系統(tǒng)管理模塊拓春,藍(lán)色區(qū)域代表Job任務(wù)狀態(tài)控制模塊释簿,綠色區(qū)域代表Job任務(wù)生命周期管理模塊的實(shí)現(xiàn)。

執(zhí)行功能主要由以下四個(gè)模塊組成硼莽,

  • 調(diào)用者創(chuàng)建其相關(guān)的Job并傳遞給JobSchedulerService服務(wù)庶溶,一個(gè)Job任務(wù)由JobInfo的實(shí)例來描述,由唯一ID與JobService的實(shí)例一一綁定懂鸵,通過JobSchedulerService的對(duì)外暴露的接口函數(shù)schedule來把該Job任務(wù)傳遞到平臺(tái)層Framework的JobSchedulerService的服務(wù)中偏螺。
  • Job任務(wù)的系統(tǒng)管理模塊,JobScheduleService服務(wù)是整個(gè)Job任務(wù)的中樞管理系統(tǒng)匆光,負(fù)責(zé)管理Job任務(wù)的執(zhí)行和重試套像,以及管理Job控制模塊和Job生命周期控制模塊
  • Job任務(wù)狀態(tài)控制模塊终息,當(dāng)條件狀態(tài)滿足后觸發(fā)Job的執(zhí)行夺巩。根據(jù)系統(tǒng)特性定義了一些Job的系統(tǒng)控制條件,當(dāng)狀態(tài)滿足控制條件時(shí)會(huì)更新JobStatus的狀態(tài)周崭,而后JobSchedulerService服務(wù)接到通知去執(zhí)行Job任務(wù)柳譬。
  • Job任務(wù)生命周期控制模塊,該模塊是Job調(diào)用者需要運(yùn)行時(shí)對(duì)其運(yùn)行狀態(tài)的控制续镇。該模塊通過JobServiceContext類來實(shí)現(xiàn)美澳,該類是Job任務(wù)與調(diào)用者通信的橋梁(可跨進(jìn)程間調(diào)用),處理調(diào)用者JobService實(shí)例的綁定,啟動(dòng)人柿,執(zhí)行柴墩,停止忙厌,完成操作凫岖。

2. JobScheduler使用者

調(diào)用者使用JobScheduler時(shí),需構(gòu)建Job任務(wù)的相關(guān)構(gòu)造類為JobInfo逢净,其Buider類的參數(shù)為JobService的唯一ID和JobService的實(shí)現(xiàn)類的ComponentName哥放,調(diào)用者在Builder類里設(shè)置Job任務(wù)的相應(yīng)滿足條件,JobService的實(shí)現(xiàn)類包含了Job任務(wù)相應(yīng)的執(zhí)行或停止函數(shù)等實(shí)現(xiàn)爹土。
具體實(shí)現(xiàn)代碼如下例所示甥雕,

/** A JobService to clean up obsolete data in anomaly database */

//  定義一個(gè)繼承JobService的實(shí)現(xiàn)類,實(shí)現(xiàn)主要功能onStartJob和onStopJob函數(shù)
public class AnomalyCleanupJobService extends JobService{
    private static final String TAG = "AnomalyCleanUpJobService";
    @VisibleForTesting
    static final long CLEAN_UP_FREQUENCY_MS = TimeUnit.DAYS.toMillis(1);

    public static void scheduleCleanUp(Context context) {
        //獲取JobScheduler服務(wù)胀茵。 
        final JobScheduler jobScheduler = context.getSystemService(JobScheduler.class);
        final ComponentName component = new ComponentName(context, AnomalyCleanupJobService.class);
        // 構(gòu)建JobInfo.Builder, 為該JobInfo設(shè)置滿足的執(zhí)行條件
        final JobInfo.Builder jobBuilder =
                new JobInfo.Builder(R.integer.job_anomaly_clean_up, component)
                        .setPeriodic(CLEAN_UP_FREQUENCY_MS)
                        .setRequiresDeviceIdle(true)
                        .setRequiresCharging(true)
                        .setPersisted(true);

        final JobInfo pending = jobScheduler.getPendingJob(R.integer.job_anomaly_clean_up);
        // Don't schedule it if it already exists, to make sure it runs periodically even after
        // reboot
        // 開啟Job任務(wù)的執(zhí)行
        if (pending == null &&jobScheduler.schedule(jobBuilder.build())
                    != JobScheduler.RESULT_SUCCESS) {
                Log.i(TAG, "Anomaly clean up job service schedule failed.");
         }
    }

    @Override
    public boolean onStartJob(JobParameters params){
        final BatteryDatabaseManager batteryDatabaseManager = BatteryDatabaseManager
                .getInstance(this);
        final BatteryTipPolicy policy = new BatteryTipPolicy(this);
        ThreadUtils.postOnBackgroundThread(()  -> {
            batteryDatabaseManager.deleteAllAnomaliesBeforeTimeStamp(
                    System.currentTimeMillis() - TimeUnit.DAYS.toMillis(
                            policy.dataHistoryRetainDay));
              // Job任務(wù)執(zhí)行完成后回調(diào)完成通知社露,設(shè)置是否重試
              jobFinished(params, false /* wantsReschedule */);
        })
        return true;
    }

    @Override
    public boolean onStopJob(JobParameters jobParameters){
        return false;
    }
}

JobInfo.Builder對(duì)其Job任務(wù)的條件限制大致類別如下:
周期時(shí)長,網(wǎng)絡(luò)狀態(tài)琼娘,時(shí)間(延遲時(shí)長峭弟,最遲運(yùn)行時(shí)長),重試方式脱拼,電池信息瞒瘸,contend URI更新等。
具體定義及使用可參考如下文檔熄浓,文檔已清晰介紹情臭,不再過多闡述,
https://developer.android.com/reference/android/app/job/JobInfo.Builder

3. Job任務(wù)系統(tǒng)服務(wù)管理模塊

3.1 Job任務(wù)系統(tǒng)管理服務(wù)模塊簡介

Job任務(wù)系統(tǒng)管理模塊是Job任務(wù)的核心模塊赌蔑,系統(tǒng)管理服務(wù)是Job任務(wù)功能的核心俯在;對(duì)使用者起著通訊及同步的作用,擔(dān)負(fù)著任務(wù)調(diào)用娃惯,任務(wù)執(zhí)行狀態(tài)開啟停止及完成跷乐;主要管理功能有如下:

  • 控制Job的運(yùn)行數(shù)量JobConcurrencyManager(總體,后臺(tái)最小石景,后臺(tái)最大劈猿,根據(jù)內(nèi)存壓力配置數(shù)量組(ProcessStats.ADJ_MEM_FACTOR_*))。
  • 接收調(diào)用者創(chuàng)建的Job潮孽,將數(shù)據(jù)存入到JobStore揪荣。
  • 初始化Job的狀態(tài)控制模塊,將各個(gè)Job相應(yīng)的觸發(fā)條件分別更新到各個(gè)狀態(tài)控制模塊往史。
  • 常量配置仗颈,可執(zhí)行Job數(shù)量,權(quán)重因子等。
  • 創(chuàng)建平臺(tái)層Job任務(wù)為JobStatus(JobInfo為其構(gòu)造函數(shù)的首參數(shù))挨决,平臺(tái)層以此為來處理和維護(hù)Job请祖。
  • Job任務(wù)的消息處理,執(zhí)行脖祈,過期肆捕,停止;UID狀態(tài)更新(包含change, gone, active, idle)盖高。

3.2 Job任務(wù)系統(tǒng)管理服務(wù)初始化流程

主要介紹JobSchedulerService服務(wù)的構(gòu)造函數(shù)的實(shí)現(xiàn)慎陵,

  • 獲取系統(tǒng)服務(wù)(PackgeManager和ActivityManager);通過PM獲取uid喻奥,AM獲取是否異常應(yīng)用
  • Jobhandler處理席纽;負(fù)責(zé)管理服務(wù)內(nèi)部的消息處理;主要分兩類撞蚕,Job任務(wù)狀態(tài)的消息處理(MSG_JOB_EXPIRED润梯, MSG_CHECK_JOB,MSG_STOP_JOB)甥厦,Job任務(wù)Active根據(jù)UID狀態(tài)更新(MSG_UID_ACTIVE更新Job任務(wù)Active為ture 纺铭,MSG_UID_IDLE和MSG_UID_GONE更新Job任務(wù)Active為false)
  • Job常量數(shù)量和時(shí)間的初始化(前后臺(tái),idle矫渔,充電彤蔽,網(wǎng)絡(luò)連接, 電量,存儲(chǔ)庙洼,Standby, 失效時(shí)間) 以及settings數(shù)據(jù)庫與jobscheduler相關(guān)的數(shù)據(jù)變化的監(jiān)聽
  • JobSchedulerStub的實(shí)現(xiàn)顿痪,繼承IJobScheduler.Stub的接口,用于與app進(jìn)行通訊(schedule函數(shù))
  • JobConcurrencyManager的初始化油够, 該類是根據(jù)配置和系統(tǒng)狀態(tài)允許多少個(gè)Job任務(wù)共同運(yùn)行

dump里的配置信息如下:

Config={tot=10 bg min/max=2/6} Running[FG/BG (total)]: 0 / 0 (0) Pending: 0 / 0 (0) Actual max: 0 / 0 (0) Res BG: 0 Starting: 0 / 0 (0) Total: 0 / 0 (0)
  • 創(chuàng)建應(yīng)用待機(jī)組的跟蹤 (app standby bucket tracker)
  • 初始化各個(gè)子狀態(tài)控制模塊
  • 注冊(cè)time change的receiver蚁袭,當(dāng)時(shí)間更新后重新計(jì)算Job任務(wù)的執(zhí)行時(shí)間

3.3 Job任務(wù)系統(tǒng)管理服務(wù)啟動(dòng)階段

Job任務(wù)系統(tǒng)管理服務(wù)的啟動(dòng)主要包含系統(tǒng)服務(wù)自身初始化和系統(tǒng)服務(wù)開始綁定到三方應(yīng)用兩個(gè)流程,

3.3.1 系統(tǒng)服務(wù)自身初始化完成 (PHASE_SYSTEM_SERVICES_READY)

  • 初始化子條件狀態(tài)控制
for (StateController controller : mControllers) {
    controller.onSystemServicesReady();
}
  • 開始注冊(cè)broadcast receiver來監(jiān)聽package的相關(guān)變化(remove, change, restart, query package restart)
// Register br for package removals and user removals.
final IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
filter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
filter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);
filter.addDataScheme("package");
getContext().registerReceiverAsUser(
mBroadcastReceiver, UserHandle.ALL, filter, null, null);
final IntentFilter userFilter = new IntentFilter(Intent.ACTION_USER_REMOVED);
getContext().registerReceiverAsUser(
    mBroadcastReceiver, UserHandle.ALL, userFilter, null, null);
  • 開始注冊(cè)broadcast receiver來監(jiān)聽uid的相關(guān)變化(gone, idle, active, procstate)
ActivityManager.getService().registerUidObserver(mUidObserver,
ActivityManager.UID_OBSERVER_PROCSTATE | ActivityManager.UID_OBSERVER_GONE
| ActivityManager.UID_OBSERVER_IDLE | ActivityManager.UID_OBSERVER_ACTIVE,
ActivityManager.PROCESS_STATE_UNKNOWN, null);
//JobConcurrencyManager的初始化
mConcurrencyManager.onSystemReady();

public void onSystemReady() {
    mPowerManager = mContext.getSystemService(PowerManager.class);
    final IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_ON);
    filter.addAction(Intent.ACTION_SCREEN_OFF);
    mContext.registerReceiver(mReceiver, filter);
    onInteractiveStateChanged(mPowerManager.isInteractive());
}
  • 取消當(dāng)前無效的Job任務(wù)
// Remove any jobs that are not associated with any of the current users.
cancelJobsForNonExistentUsers();

3.3.2 系統(tǒng)服務(wù)開始綁定到三方應(yīng)用 (PHASE_THIRD_PARTY_APPS_CAN_START)

  • 獲取batterystats服務(wù)和DeviceIdleController
  mReadyToRock = true;
  mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService(
  BatteryStats.SERVICE_NAME));
  mLocalDeviceIdleController
     = LocalServices.getService(DeviceIdleController.LocalService.class);
  • 創(chuàng)建MAX_JOB_CONTEXTS_COUNT個(gè)JobServiceContext石咬,添加到mActiveServices JobServiceContext表達(dá)一個(gè)job的生命周期揩悄,每個(gè)job對(duì)應(yīng)該類的一個(gè)實(shí)例,該構(gòu)造中與JobPackageTracker和BatteryStats相關(guān)
// Create the "runners".
for (int i = 0; i < MAX_JOB_CONTEXTS_COUNT; i++) {
    mActiveServices.add(
        new JobServiceContext(this, mBatteryStats, mJobPackageTracker,
    getContext().getMainLooper()));
}
  • 把每個(gè)job任務(wù)在子條件狀態(tài)控制里做跟蹤
mJobs.forEachJob((job) -> {
    for (int controller = 0; controller < mControllers.size(); controller++) {
        final StateController sc = mControllers.get(controller);
    sc.maybeStartTrackingJobLocked(job, null);
   }
});

  • 檢查job, 開啟job工作模式
mHandler.obtainMessage(MSG_CHECK_JOB).sendToTarget();

3.4 系統(tǒng)管理服務(wù)對(duì)Job任務(wù)的處理流程

JobSchedulerService是該模塊的主要實(shí)現(xiàn)類鬼悠,其工作流程為删性,

  • JobScheduler將JobInfo實(shí)例(參數(shù)為Job ID和JobService的實(shí)例)注冊(cè)到JobSchedulerService服務(wù)中
  • 由JobSchedulerService服務(wù)維護(hù)Job列表JobStore,JobStore中所存儲(chǔ)的Job會(huì)存入PendingJobs的列表里
  • Job設(shè)置的條件被相應(yīng)的子StateController解讀并注冊(cè)
  • 子StateController中的狀態(tài)被滿足時(shí)會(huì)把相應(yīng)的jobstatus中的滿足的限制條件設(shè)置為true焕窝, 并發(fā)送檢查job的消息給JobSchedulerService的
  • 當(dāng)Job任務(wù)的條件全部滿足時(shí)把Job存入PendingJobs的以時(shí)間為序的隊(duì)列里JobConcurrencyManager觸發(fā)JobServiceContext去執(zhí)行相關(guān)的Job, 開啟Job生命周期的管理模塊

JobSchedulerService的Job任務(wù)執(zhí)行流程如下圖所示蹬挺,想要詳細(xì)了解的同學(xué)可根據(jù)代碼和如下流程自行查看。

4. Job任務(wù)條件狀態(tài)控制模塊

條件控制模塊是Job任務(wù)條件滿足的涌動(dòng)機(jī)它掂,主要作用是Job任務(wù)狀態(tài)的管理控制功能 巴帮,把調(diào)用者Job任務(wù)構(gòu)建滿足條件設(shè)置到相應(yīng)子狀態(tài)控制模塊(StateController的子類)中去,隨著Android版本的不斷升級(jí),該子模塊的功能不斷被擴(kuò)展添加榕茧。每個(gè)條件狀態(tài)控制會(huì)去接受系統(tǒng)的廣播信息垃沦,由此根據(jù)系統(tǒng)廣播狀態(tài)的變化信息來更新各個(gè)Job任務(wù)的滿足條件。

隨著系統(tǒng)版本的升級(jí)Job任務(wù)的狀態(tài)控制模塊在各個(gè)Android版本上演進(jìn)如下圖所示用押。

4.1 子條件狀態(tài)控制模塊(StateController的子類)

Job任務(wù)在初始化時(shí)肢簿,使用者對(duì)Job任務(wù)的條件設(shè)置通過條件位標(biāo)記的方法賦值給Job任務(wù)的請(qǐng)求條件變量(JobStatus的mRequiredConstraints),其設(shè)置條件會(huì)對(duì)應(yīng)設(shè)置到StateController的子類的條件狀態(tài)中只恨,Job任務(wù)主動(dòng)設(shè)置到狀態(tài)控制模塊里的條件稱為顯式滿足條件译仗,狀態(tài)控制模塊為Job任務(wù)添加的條件稱為隱式滿足條件。

該模塊的處理流程為官觅,子條件狀態(tài)控制模塊來監(jiān)控相關(guān)狀態(tài)(注冊(cè)BroadcastReceiver),狀態(tài)發(fā)生變更后會(huì)更新Job任務(wù)的滿足條件阐污;某個(gè)條件滿足會(huì)設(shè)置相應(yīng)的Job任務(wù)的滿足條件變量的某個(gè)條件標(biāo)記位為1(JobStatus的satisfiedConstraints變量的某指定條件位設(shè)置為1)休涤,當(dāng)一個(gè)Job任務(wù)所有的條件都滿足后(滿足條件為mReadyNotDozing && mReadyNotRestrictedInBg && (mReadyDeadlineSatisfied || mRequiredConstraintsOfInterest == satisfiedConstraints));最后由JobSchedulerService去觸發(fā)執(zhí)行Job任務(wù)笛辟。

4.1.1 顯式滿足條件的子狀態(tài)控制模塊

使用者主動(dòng)設(shè)置的條件稱為顯示滿足條件功氨,顯示滿足條件會(huì)主動(dòng)一一映射到各子條件狀態(tài)控制模塊,主要的顯示滿足相應(yīng)子條件控制模塊有手幢,

  • 網(wǎng)絡(luò)連接狀態(tài)控制模塊捷凄,Job任務(wù)的網(wǎng)絡(luò)類型及連接條件由ConnectivityController來實(shí)現(xiàn),ConnectivityController來監(jiān)控網(wǎng)絡(luò)的連接情況围来。
  • 執(zhí)行時(shí)間狀態(tài)控制模塊跺涤,針對(duì)Job任務(wù)的下次到期的時(shí)間設(shè)置alam提醒,該條件由TimeController實(shí)現(xiàn)监透。
  • 系統(tǒng)閑時(shí)狀態(tài)控制模塊桶错,條件由IdleController來監(jiān)控系統(tǒng)閑時(shí)的進(jìn)入和退出,閑時(shí)定義為充電狀態(tài)下滅屏后71min胀蛮。
  • 電池狀態(tài)控制模塊院刁,條件由BatteryController來實(shí)現(xiàn),其Job任務(wù)設(shè)置條件有正在充電和電池非低電情況粪狼。
  • 存儲(chǔ)空間狀態(tài)控制模塊退腥,條件由StorageController來監(jiān)控存儲(chǔ)空間是否處于低位。
  • 數(shù)據(jù)庫更新狀態(tài)控制模塊再榄,Contenet URI更新條件由ContentObserverController來實(shí)現(xiàn)狡刘,監(jiān)控Job任務(wù)設(shè)置的數(shù)據(jù)庫是否更新。

4.1.2 三個(gè)隱式滿足條件的子狀態(tài)控制模塊

有三個(gè)條件為系統(tǒng)自動(dòng)為Job任務(wù)強(qiáng)制添加不跟,使用者無法設(shè)置該類條件颓帝,其他條件均可被使用者設(shè)置,
該三個(gè)條件是:

  • Doze限制執(zhí)行(DEVICE_NOT_DOZING),設(shè)備Doze狀態(tài)下不允許執(zhí)行Job任務(wù)购城,前臺(tái)和白名單應(yīng)用除外吕座,該條件被DeviceIdleJobsController子條件狀態(tài)控制。
  • 后臺(tái)限制執(zhí)行(BACKGROUND_NOT_RESTRICTED)瘪板,根據(jù)AppStandby機(jī)制對(duì)后臺(tái)應(yīng)用的Job任務(wù)進(jìn)行限制吴趴,該條件被BackgroundJobsController子條件狀態(tài)控制。
  • 應(yīng)用待機(jī)組(WITHIN_QUOTA)侮攀,應(yīng)用待機(jī)組條件控制锣枝,依照各待機(jī)組類別做相應(yīng)的限制,該條件被QuotaController子條件狀態(tài)控制兰英。四類應(yīng)用待機(jī)組對(duì)Job的有相關(guān)限制撇叁,活躍組無限制,工作級(jí)組在兩個(gè)小時(shí)允許執(zhí)行10分鐘畦贸,頻繁使用組八個(gè)小時(shí)允許執(zhí)行10分鐘陨闹,非常用組二十四小時(shí)允許執(zhí)行10分鐘。

4.2 條件狀態(tài)控制模塊屬性

條件狀態(tài)控制模塊屬性分為常駐屬性和可選屬性兩類薄坏,常駐屬性表明在該子條件狀態(tài)控制模塊必須實(shí)現(xiàn)這些屬性趋厉,該屬性是所有子條件狀態(tài)控制模塊共有的特性;可選屬性意思則為按需加載實(shí)現(xiàn)胶坠。

4.2.1. 常駐屬性

所有子狀態(tài)控制模塊都需要實(shí)現(xiàn)該屬性:

  • 開啟任務(wù)狀態(tài)控制君账,每向JSS中加入一個(gè)Job,都會(huì)調(diào)用maybeStartTrackingJobLocked()方法開始記錄跟蹤此Job;
  • 停止任務(wù)狀態(tài)控制沈善,當(dāng)Job任務(wù)執(zhí)行完成或被取消時(shí)乡数,都會(huì)調(diào)用maybeStopTrackingJobLocked()方法停止此Job的記錄。

4.2.2 可選屬性

子狀態(tài)控制模塊有選擇的實(shí)現(xiàn)該屬性:

  • 重新調(diào)度失敗的任務(wù) rescheduleForFailureLocked (ContentObserverController)
  • 常量或白名單的更新 onConstantsUpdatedLocked (ConnectivityController, QuotaController)
    ConnectivityController: 在app idle里設(shè)置白名單為不允許
    QuotaController:根據(jù)App的Bucket來更新任務(wù)的Quota狀態(tài)
  • 準(zhǔn)備可運(yùn)行的任務(wù) prepareForExecutionLocked (ContentObserverController, QuotaController)
    ContentObserverController:為即將運(yùn)行的Job任務(wù)準(zhǔn)備好URI矮瘟。
    QuotaController:將非TOP應(yīng)用添加到追蹤列表中瞳脓。
  • 應(yīng)用刪除后的清理 onUserRemovedLocked (ConnectivityController, QuotaController)
  • 用戶刪除后的清理 onAppRemovedLocked (QuotaController)
  • 評(píng)估任務(wù)狀態(tài) (ConnectivityController, TimerController)
    ConnectivityController: 評(píng)估是否網(wǎng)絡(luò)連接的任務(wù)
    TimerController: 評(píng)估最遲運(yùn)行(deadine)時(shí)間(latestRunTimeElapsedMillis)是否到期

5. Job任務(wù)生命周期控制模塊

5.1 Job任務(wù)生命周期介紹

Job任務(wù)的運(yùn)行流程Job任務(wù)的執(zhí)行狀態(tài)來表示的,可稱之為Job任務(wù)的生命周期處理澈侠,由狀態(tài)機(jī)來表現(xiàn)劫侧,JobServiceContext是該模塊的一個(gè)主要邏輯類,承擔(dān)Job任務(wù)的生命周期的處理和與使用者的Job任務(wù)執(zhí)行狀態(tài)同步的作用哨啃。
JobServiceContext實(shí)例與Job任務(wù)的生命周期為一一對(duì)應(yīng)烧栋,將JobServiceContext綁定到使用者的JobService上,綁定過程中開啟PowerManager.PARTIAL_WAKE_LOCK操作, Job任務(wù)完成后釋放該WAKE_LOCK拳球,其主要目的是通知使用者執(zhí)行Job任務(wù)的開啟執(zhí)行或停止等操作审姓,當(dāng)使用者被開啟任務(wù)的執(zhí)行時(shí),完成Job任務(wù)后會(huì)發(fā)起主動(dòng)通知到JobServiceContext祝峻。

每一個(gè)Job任務(wù)的初始狀態(tài)由完成(Finishing)狀態(tài)開始魔吐,一個(gè)成功運(yùn)行的Job任務(wù)執(zhí)行狀態(tài)轉(zhuǎn)換按綁定狀態(tài)(binding)->開啟狀態(tài)(starting)->執(zhí)行狀態(tài)(executing)->完成狀態(tài)(finishing)的流程來完成狀態(tài)的切換扎筒。

Job任務(wù)執(zhí)行狀態(tài)流程如下圖所示,綠色代表Job任務(wù)生命周期狀態(tài)處理流程酬姆,紫色代表與使用者Job任務(wù)執(zhí)行狀態(tài)傳遞及返回嗜桌,紅色代表Job任務(wù)停止?fàn)顟B(tài)處理流程。

5.2 超時(shí)機(jī)制處理機(jī)制

JobServiceContext擁有一個(gè)執(zhí)行狀態(tài)超時(shí)處理機(jī)制辞色,由于JobServiceContext與其目的是為了與使用者的調(diào)用建立一個(gè)容錯(cuò)能力骨宠,如果在約定時(shí)間內(nèi)未完成操作就會(huì)觸發(fā)超時(shí)狀態(tài)的切換及清理工作,各個(gè)執(zhí)行狀態(tài)的超時(shí)時(shí)間設(shè)置為綁定狀態(tài)超時(shí)18s相满,開啟狀態(tài)超時(shí)8s层亿,執(zhí)行狀態(tài)超時(shí)600s;當(dāng)綁定和開啟狀態(tài)超時(shí)被觸發(fā)后執(zhí)行狀態(tài)切換到完成狀態(tài)立美,去運(yùn)行Job任務(wù)的清除動(dòng)作匿又。

5.3 停止?fàn)顟B(tài)的處理機(jī)制

當(dāng)在執(zhí)行狀態(tài)下觸發(fā)超時(shí),切換到停止?fàn)顟B(tài)悯辙,調(diào)用使用者的停止函數(shù)琳省,執(zhí)行停止成功后再把狀態(tài)切換到完成狀態(tài)。使用者中的JobServiceEngine由三個(gè)消息(MSG_EXECUTE_JOB, MSG_STOP_JOB, MSG_JOB_FINISHED)來構(gòu)建執(zhí)行流程躲撰, 其中執(zhí)行和停止操作由JobServiceContext主動(dòng)觸發(fā),而完成操作是被動(dòng)觸發(fā)JobServiceContext击费。

5.4 狀態(tài)取消處理機(jī)制

執(zhí)行狀態(tài)失敗處理與超時(shí)機(jī)制的處理邏輯是一致的拢蛋,一旦觸發(fā)取消操作,綁定和開啟狀態(tài)切換到完成狀態(tài)做后續(xù)的清理工作蔫巩;而執(zhí)行狀態(tài)下的取消操作谆棱,會(huì)切換到停止?fàn)顟B(tài),調(diào)用使用者的停止函數(shù)圆仔,執(zhí)行停止成功后再把狀態(tài)切換到完成狀態(tài)垃瞧。

5.5 Job任務(wù)的清除

完成狀態(tài)(Finishing)后的統(tǒng)一清除。設(shè)置狀態(tài)為完成狀態(tài)坪郭,解除使用者的JobService綁定个从,由系統(tǒng)統(tǒng)一清理未綁定的服務(wù);并通知JobSchedulerService該Job已完成歪沃,停止繼續(xù)檢測該Job管理狀態(tài)嗦锐。

5.6 設(shè)計(jì)要點(diǎn)

  • JobServiceContext實(shí)現(xiàn)與使用者通訊不返回的timeout容錯(cuò)機(jī)制**
  • 執(zhí)行狀態(tài)同步到使用者分為主動(dòng)狀態(tài)更新和被動(dòng)狀態(tài)更新兩類,除完成狀態(tài)更新為被動(dòng)狀態(tài)以外其他狀態(tài)皆為JobServiceContext主動(dòng)設(shè)置**
  • 執(zhí)行狀態(tài)的最后結(jié)束狀態(tài)皆為完成狀態(tài)沪曙,統(tǒng)一完成任務(wù)的清除操作**

作者:林芊_lqsohu
鏈接:http://www.reibang.com/p/e1b4d952c79f
來源:簡書
著作權(quán)歸作者所有奕污。商業(yè)轉(zhuǎn)載請(qǐng)聯(lián)系作者獲得授權(quán),非商業(yè)轉(zhuǎn)載請(qǐng)注明出處液走。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末碳默,一起剝皮案震驚了整個(gè)濱河市贾陷,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌嘱根,老刑警劉巖髓废,帶你破解...
    沈念sama閱讀 219,270評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異儿子,居然都是意外死亡瓦哎,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,489評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門柔逼,熙熙樓的掌柜王于貴愁眉苦臉地迎上來蒋譬,“玉大人,你說我怎么就攤上這事愉适》钢” “怎么了?”我有些...
    開封第一講書人閱讀 165,630評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵维咸,是天一觀的道長剂买。 經(jīng)常有香客問我,道長癌蓖,這世上最難降的妖魔是什么瞬哼? 我笑而不...
    開封第一講書人閱讀 58,906評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮租副,結(jié)果婚禮上坐慰,老公的妹妹穿的比我還像新娘。我一直安慰自己用僧,他們只是感情好结胀,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,928評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著责循,像睡著了一般糟港。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上院仿,一...
    開封第一講書人閱讀 51,718評(píng)論 1 305
  • 那天秸抚,我揣著相機(jī)與錄音,去河邊找鬼意蛀。 笑死耸别,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的县钥。 我是一名探鬼主播秀姐,決...
    沈念sama閱讀 40,442評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼若贮!你這毒婦竟也來了省有?” 一聲冷哼從身側(cè)響起痒留,我...
    開封第一講書人閱讀 39,345評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎蠢沿,沒想到半個(gè)月后伸头,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,802評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡舷蟀,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,984評(píng)論 3 337
  • 正文 我和宋清朗相戀三年恤磷,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片野宜。...
    茶點(diǎn)故事閱讀 40,117評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡扫步,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出匈子,到底是詐尸還是另有隱情河胎,我是刑警寧澤,帶...
    沈念sama閱讀 35,810評(píng)論 5 346
  • 正文 年R本政府宣布虎敦,位于F島的核電站游岳,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏其徙。R本人自食惡果不足惜胚迫,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,462評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望唾那。 院中可真熱鬧晌区,春花似錦、人聲如沸通贞。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,011評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽昌罩。三九已至,卻和暖如春灾馒,著一層夾襖步出監(jiān)牢的瞬間茎用,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,139評(píng)論 1 272
  • 我被黑心中介騙來泰國打工睬罗, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留轨功,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,377評(píng)論 3 373
  • 正文 我出身青樓容达,卻偏偏與公主長得像古涧,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子花盐,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,060評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容