疑問一
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嗎?
如果會的話,新線程是否會導致內存泄漏?
※當然,這種情況還是很少見,自己明明要處理任務呢,卻告訴系統處理完了。對於實際的編碼的意義不大,但是感興趣的話可以自行調查下。
我們還有個疑問二要繼續探究。留到下次再講。