上一章节讲解了JobService的基本特性和使用方法,本章我们下面从源码(Android OREO)层面探究以下几个疑问。
首先我们先来认识一下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生命周期
其他的类还有不少,但是核心的就是这几个。光看上面这些描述很难有个系统的直观的认识。

我们再从别的角度对这些核心类和接口梳理一下。
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机制的架构有点概念了呢?
我们按照实际的问题去看下代码流程,可能对于这个架构的理解更有帮助。
JobScheduler如何安排和绑定JobService的逻辑暂时先不谈。
我们直接看onStartJob()回调开始的地方。
上面说过JobService的生命周期是由JobServiceContext执行的,而且是通过IJobService.aidl去IPC的。
那么打开我们frameworks/base/services/core/java/com/android/server/job/JobServiceContext.java文件。
检索下IJobService对象调用startJob()的地方。
我们检索下IJobService实现的地方,就是frameworks/base/core/java/android/app/job/JobServiceEngine.java。
这里给自己发JobServiceEngine内部Handler发送了MSG_EXECUTE_JOB的msg。
可以看到执行了两个步骤:
1.调用JobServiceEngine去执行onStartJob;
2.将1的返回值作为参数执行ackStartMessage方法;
JobServiceEngine是抽象类,检索源码发现实现的地方在frameworks/base/core/java/android/app/job/JobService.java中。
上面可以看到JobService里定了JobServiceEngine的匿名内部类。
上面步骤1回掉到这,接着执行JobService自己的onStartJob逻辑。
我们假设APP端执行Job很快,然后onStartJob()返回了false。
那么接下来步骤2将false值作为ackStartMessage函数的参数准备告诉JobServiceContext。
可以看到从JobParameters取出IJobCallback的代理,然后调用了acknowledgeStartMessage方法将返回值回传。
搜索IJobCallback.Stub,可以看到IJobCallback的实现果然在JobServiceContext中。
上面的流程很清晰易懂。
当onStartJob()返回了false,JobScheduler就认为你的Job任务已经处理完了。
那么就会直接去解绑JobService。
效果就如同自己调用了jobFinished()方法一样。
到这里我们已经成功回答了疑问一,从源码处证明了onStartJob返回false后立马就会被destroy。
到这里我们不禁产生两个思考。
如果我们在onStartJob()里处理耗时逻辑,导致onStartJob()没有及时返回给JobSchedulerContext。
最终结果是怎么样?
是ANR?
还是因为超时,该Job可能被强制停止和销毁?
如果onStartJob()里起了新线程处理耗时逻辑,但是返回值返回了false,那么系统还会销毁Job吗?
如果会的话,新线程是否会导致内存泄漏?
※当然,这种情况还是很少见,自己明明要处理任务呢,却告诉系统处理完了。对于实际的编码的意义不大,但是感兴趣的话可以自行调查下。
我们还有个疑问二要继续探究。留到下次再讲。
疑问一
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吗?
如果会的话,新线程是否会导致内存泄漏?
※当然,这种情况还是很少见,自己明明要处理任务呢,却告诉系统处理完了。对于实际的编码的意义不大,但是感兴趣的话可以自行调查下。
我们还有个疑问二要继续探究。留到下次再讲。