上一章节讲解了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吗?
如果会的话,新线程是否会导致内存泄漏?
※当然,这种情况还是很少见,自己明明要处理任务呢,却告诉系统处理完了。对于实际的编码的意义不大,但是感兴趣的话可以自行调查下。