JobService源碼探究之 onStartJob()返回false立馬被destroy

上一章節講解了JobService的基本特性和使用方法,本章我們下面從源碼(Android OREO)層面探究以下幾個疑問。


疑問一

onStartJob()返回false之後,Job幾乎立馬就被destory?


疑問二

自行cancel了JobService後,onStopJob()即使返回true也不能被重新啓動?


首先我們先來認識一下JobScheduler機制的各種類和接口。


android.app.job.JobService
定義:JobService抽象類
作用:內部定義了JobServiceEngine的匿名內部類,通過該內部類回調JobService實現類的onStartJob()和onStopJob()
實現:需要APP端自行實現onStartJob()和onStopJob()等邏輯


android.app.job.IJobService.aidl
定義:描述JobScheduler向JobService發出命令的接口
實現:該接口實現位於JobServiceEngine中


android.app.job.JobServiceEngine
定義:用於輔助JobScheduler和JobService交互的抽象類
作用:
1.內部定義了IJobService實現類,JobScheduler通過IJobService跨進程通知JobService去開始或者停止任務
2.利用JobScheduler傳過來的IJobCallback對象,將開始或者停止任務的返回結果傳回給JobScheduler
實現:該抽象類的實現位於JobService中


android.app.job.JobScheduler
定義:定義了JobScheduler相關API的抽象類
實現:具體實現在android.app.JobSchedulerImpl中


android.app.JobSchedulerImpl
定義:JobScheduler相關API的具體實現類
作用:內部持有JobSchedulerService裏IJobScheduler的代理對象,可以向其發出schedule等API的命令


android.app.job.IJobScheduler.aidl
定義:描述APP端(context)向JobScheduler發送請求的接口
實現:該接口實現位於JobSchedulerService中


android.app.job.IJobCallback.aidl
定義:描述JobService向JobScheduler發出請求的接口
實現:該類的實現類在JobSchedulerContext中。


com.android.server.job.JobSchedulerService
定義:用於對JobService進行安排,執行,計劃等調度的核心服務


com.android.server.job.JobServiceContext
定義:接收JobSchedulerService的調度實際的用於和JobService交互輔助類
作用:直接參與管理APP的JobService生命週期


其他的類還有不少,但是核心的就是這幾個。光看上面這些描述很難有個系統的直觀的認識。

類圖

我以Android O的源碼做了個class圖,來整體的認識一下這個機制。





我們再從別的角度對這些核心類和接口梳理一下。


JobSchedulerService JobScheduler機制的核心服務
JobServiceContext   接收JobSchedulerService的調度對JobService進行生命週期管理


JobServiceEngine    和JobServiceContext端進行交互
JobService          接收JobServiceEngine的調度對JobService實現類進行處理


IJobScheduler.aidl  用於APP端(Context)和JobScheduler端(JobSchedulerService)進行IPC
IJobService.aidl    用於JobScheduler端(JobServiceContext)和JobService端進行IPC
IJobCallback.aidl   用於JobService端對JobScheduler端(JobServiceContext)進行IPC


是不是對JobScheduler機制的架構有點概念了呢?


我們按照實際的問題去看下代碼流程,可能對於這個架構的理解更有幫助。


第一個問題:onStartJob()返回false之後,Job立馬就被destory?



JobScheduler如何安排和綁定JobService的邏輯暫時先不談。
我們直接看onStartJob()回調開始的地方。


上面說過JobService的生命週期是由JobServiceContext執行的,而且是通過IJobService.aidl去IPC的。

我麼打開frameworks/base/core/java/android/app/job/IJobService.aidl


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


這裏有個startJob()的接口方法。應該就是執行onStartJob()的開始。



那麼打開我們frameworks/base/services/core/java/com/android/server/job/JobServiceContext.java文件。
檢索下IJobService對象調用startJob()的地方。

public final class JobServiceContext implements ServiceConnection {
    ...
    /** Start the job on the service. */
    private void handleServiceBoundLocked() {
        ...
        try {
            mVerb = VERB_STARTING; // 這裏將Job的狀態置爲VERB_STARTING
            scheduleOpTimeOutLocked();
            service.startJob(mParams); ★ 從這裏開始和JobService進行交互
        } catch (Exception e) {
            ...
        }
    }
    ...
}


我們檢索下IJobService實現的地方,就是frameworks/base/core/java/android/app/job/JobServiceEngine.java。


public abstract class JobServiceEngine {
    ...
    static final class JobInterface extends IJobService.Stub {
        final WeakReference<JobServiceEngine> mService;
        ...
        @Override
        public void startJob(JobParameters jobParams) throws RemoteException {
            JobServiceEngine service = mService.get();
            if (service != null) {
                Message m = Message.obtain(service.mHandler, MSG_EXECUTE_JOB, jobParams); ★
                m.sendToTarget();
            }
        }
        ...
    }
}

這裏給自己發JobServiceEngine內部Handler發送了MSG_EXECUTE_JOB的msg。


public abstract class JobServiceEngine {
    class JobHandler extends Handler {
        ...
        @Override
        public void handleMessage(Message msg) {
            final JobParameters params = (JobParameters) msg.obj;
            switch (msg.what) {
                case MSG_EXECUTE_JOB:
                    try {
                        boolean workOngoing = JobServiceEngine.this.onStartJob(params); ★1
                        ackStartMessage(params, workOngoing); ★2
                    } catch (Exception e) {
                        Log.e(TAG, "Error while executing job: " + params.getJobId());
                        throw new RuntimeException(e);
                    }
                    break;
                ...
            }
        }
    }
}

可以看到執行了兩個步驟:
1.調用JobServiceEngine去執行onStartJob;
2.將1的返回值作爲參數執行ackStartMessage方法;


JobServiceEngine是抽象類,檢索源碼發現實現的地方在frameworks/base/core/java/android/app/job/JobService.java中。


public abstract class JobService extends Service {
    ...
    /** @hide */
    public final IBinder onBind(Intent intent) {
        if (mEngine == null) {
            mEngine = new JobServiceEngine(this) {
                @Override
                public boolean onStartJob(JobParameters params) {
                    return JobService.this.onStartJob(params);★
                }
                ...
            };
        }
        return mEngine.getBinder();
    }
}

上面可以看到JobService裏定了JobServiceEngine的匿名內部類。
上面步驟1回掉到這,接着執行JobService自己的onStartJob邏輯。

我們假設APP端執行Job很快,然後onStartJob()返回了false。

那麼接下來步驟2將false值作爲ackStartMessage函數的參數準備告訴JobServiceContext。

public abstract class JobServiceEngine {
    class JobHandler extends Handler {
        ...
        private void ackStartMessage(JobParameters params, boolean workOngoing) {
            final IJobCallback callback = params.getCallback();
            final int jobId = params.getJobId();
            if (callback != null) {
                try {
                    callback.acknowledgeStartMessage(jobId, workOngoing);★
                }...
            }...
        }
    }
}

可以看到從JobParameters取出IJobCallback的代理,然後調用了acknowledgeStartMessage方法將返回值回傳。


搜索IJobCallback.Stub,可以看到IJobCallback的實現果然在JobServiceContext中。


public final class JobServiceContext implements ServiceConnection {
    ...
    final class JobCallback extends IJobCallback.Stub {
        @Override
        public void acknowledgeStartMessage(int jobId, boolean ongoing) {
            doAcknowledgeStartMessage(this, jobId, ongoing);★1
        }
        ...
    }
    ...
    void doAcknowledgeStartMessage(JobCallback cb, int jobId, boolean ongoing) {
        doCallback(cb, ongoing, "finished start");★2
    }
    ...
    void doCallback(JobCallback cb, boolean reschedule, String reason) {
        final long ident = Binder.clearCallingIdentity();
        try {
            synchronized (mLock) {
                if (!verifyCallerLocked(cb)) {
                    return;
                }
                doCallbackLocked(reschedule, reason);★3 此刻的reschedule爲false
            }
        }...
    }
    ...
    void doCallbackLocked(boolean reschedule, String reason) {
        ...
        removeOpTimeOutLocked();//在這裏移除回調onStartJob時發送的8s延時msg

        if (mVerb == VERB_STARTING) {
            handleStartedLocked(reschedule);★4 此刻的reschedule爲false
        } else if (mVerb == VERB_EXECUTING ||
                mVerb == VERB_STOPPING) {
            handleFinishedLocked(reschedule, reason);
        }...
    }
    ...
    private void handleStartedLocked(boolean workOngoing) {
        switch (mVerb) {
            case VERB_STARTING:
                mVerb = VERB_EXECUTING; // 此刻將Job狀態置爲VERB_EXECUTING
                if (!workOngoing) {/*這邊就是分水嶺,如果workOngoing爲false則結束job否則等待job的執行*/
                    // Job is finished already so fast-forward to handleFinished.
                    handleFinishedLocked(false, "onStartJob returned false"); ★5 準備結束該Job
                    return;
                }
             ...
        }
    }
    ...
    private void handleFinishedLocked(boolean reschedule, String reason) {
        switch (mVerb) {
            case VERB_EXECUTING:
            case VERB_STOPPING:
                closeAndCleanupJobLocked(reschedule, reason); ★6
                break;
            ...
        }
    }
    ...
    private void closeAndCleanupJobLocked(boolean reschedule, String reason) {
        ...
        applyStoppedReasonLocked(reason);
        completedJob = mRunningJob;
        mJobPackageTracker.noteInactive(completedJob);
        ...
        if (mWakeLock != null) {
            mWakeLock.release();//釋放WakeLock
        }
        mContext.unbindService(JobServiceContext.this); ★7 告訴AMS解綁該JobService,最終會調到它的onDestroy()
        mWakeLock = null;
        mRunningJob = null;
        mRunningCallback = null;
        mParams = null;
        mVerb = VERB_FINISHED;// 將Job狀態置爲VERB_FINISHED
        mCancelled = false;
        service = null;
        mAvailable = true;
        removeOpTimeOutLocked();
        mCompletedListener.onJobCompletedLocked(completedJob, reschedule);
    }
}

上面的流程很清晰易懂。
當onStartJob()返回了false,JobScheduler就認爲你的Job任務已經處理完了。
那麼就會直接去解綁JobService。
效果就如同自己調用了jobFinished()方法一樣。


到這裏我們已經成功回答了疑問一,從源碼處證明了onStartJob返回false後立馬就會被destroy。


到這裏我們不禁產生兩個思考。


思考一



如果我們在onStartJob()裏處理耗時邏輯,導致onStartJob()沒有及時返回給JobSchedulerContext。
最終結果是怎麼樣?


是ANR?
還是因爲超時,該Job可能被強制停止和銷燬?


思考二



如果onStartJob()裏起了新線程處理耗時邏輯,但是返回值返回了false,那麼系統還會銷燬Job嗎?
如果會的話,新線程是否會導致內存泄漏?


※當然,這種情況還是很少見,自己明明要處理任務呢,卻告訴系統處理完了。對於實際的編碼的意義不大,但是感興趣的話可以自行調查下。




我們還有個疑問二要繼續探究。留到下次再講。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章