在上篇
《JobService源码探究之 onStartJob()里如何优雅地处理耗时逻辑?》里我们留下了如下两个疑问。
在本篇里一一解答。
这两个疑问的有如下区别:
疑问二 后台线程
疑问二 被自动停止和销毁
疑问二 onStartJob()并没有耗时,但是Job的后台任务执行时间过长,属于Job执行超时。
我们看看这两种情况下系统输出的Log。
按照上述log,我们检索源码得知,这两句话出自如下函数。
★1可以看到当Job处在STARTING状态的时候发生超时的话,系统将直接去执行JobService的结束处理,这里面会去解绑JobService并销毁。
★2可以看到当Job处在EXECUTING状态的时候发生超时的话,系统将直接去执行JobService的停止处理,之后再去执行JobService的结束处理。
检索handleOpTimeoutLocked()的调用,发现是内部类JobServiceHandler调用的。
检索MSG_TIMEOUT msg发出的地方,如下:
●executeRunnableJob() JobService刚开始绑定的时候,发送18s的延时MSG
●handleServiceBoundLocked() 回调JobService的onStartJob()的时候,发送8s的延时MSG
●handleStartedLocked() JobService的onStartJob()回调成功后,发送10mins的延时MSG
●sendStopMessageLocked() 回调JobService的onStopJob()的时候,发送8s的延时MSG
以上可以看出。
在本篇里一一解答。
疑问一
为什么onStartJob()直接执行耗时逻辑后,即便自己没有finish该Job,但是Job还是会被自动销毁?疑问二
为什么onStartJob()里开启新线程执行的耗时逻辑超过10min,但是Job被自动停止和销毁?这两个疑问的有如下区别:
耗时逻辑所属的线程
疑问一 UI线程疑问二 后台线程
Job最后的结果
疑问一 被自动销毁疑问二 被自动停止和销毁
但他们之间也存在共同点,就是都是某种程度上的超时。
疑问一 onStartJob()耗时,导致本函数没有及时执行结束,属于onStartJob()回调超时。疑问二 onStartJob()并没有耗时,但是Job的后台任务执行时间过长,属于Job执行超时。
我们看看这两种情况下系统输出的Log。
疑问一
JobServiceContext: No response from client for onStartJob ef7724f #u0a174/0 com.example.timeapidemo/.EllisonsJobService
疑问二
JobServiceContext( 1433): Client timed out while executing (no jobFinished received), sending onStop: 5673577 #u0a174/0 com.example.timeapidemo/.EllisonsJobService
按照上述log,我们检索源码得知,这两句话出自如下函数。
frameworks/base/services/core/java/com/android/server/job/JobServiceContext.java
private void handleOpTimeoutLocked() {
switch (mVerb) {
...
case VERB_STARTING:
// Client unresponsive - wedged or failed to respond in time. We don't really
// know what happened so let's log it and notify the JobScheduler
// FINISHED/NO-RETRY.
Slog.w(TAG, "No response from client for onStartJob " +
mRunningJob != null ? mRunningJob.toShortString() : "<null>");
closeAndCleanupJobLocked(false /* needsReschedule */, "timed out while starting");★1
break;
...
case VERB_EXECUTING:
// Not an error - client ran out of time.
Slog.i(TAG, "Client timed out while executing (no jobFinished received), " +
"sending onStop: " +
mRunningJob != null ? mRunningJob.toShortString() : "<null>");
mParams.setStopReason(JobParameters.REASON_TIMEOUT);
sendStopMessageLocked("timeout while executing");★2
break;
...
}
}
★1可以看到当Job处在STARTING状态的时候发生超时的话,系统将直接去执行JobService的结束处理,这里面会去解绑JobService并销毁。
★2可以看到当Job处在EXECUTING状态的时候发生超时的话,系统将直接去执行JobService的停止处理,之后再去执行JobService的结束处理。
检索handleOpTimeoutLocked()的调用,发现是内部类JobServiceHandler调用的。
private class JobServiceHandler extends Handler {
...
@Override
public void handleMessage(Message message) {
switch (message.what) {
case MSG_TIMEOUT:
synchronized (mLock) {
if (message.obj == mRunningCallback) {
handleOpTimeoutLocked();
}...
}
...
}
}
}
检索MSG_TIMEOUT msg发出的地方,如下:
private void scheduleOpTimeOutLocked() {
...
final long timeoutMillis;
switch (mVerb) {
case VERB_EXECUTING:
timeoutMillis = EXECUTING_TIMESLICE_MILLIS; // 10mins
break;
case VERB_BINDING:
timeoutMillis = OP_BIND_TIMEOUT_MILLIS; // 18s
break;
default:
timeoutMillis = OP_TIMEOUT_MILLIS; // 8s
break;
}
Message m = mCallbackHandler.obtainMessage(MSG_TIMEOUT, mRunningCallback);
mCallbackHandler.sendMessageDelayed(m, timeoutMillis);
mTimeoutElapsed = SystemClock.elapsedRealtime() + timeoutMillis;
}
●executeRunnableJob() JobService刚开始绑定的时候,发送18s的延时MSG
●handleServiceBoundLocked() 回调JobService的onStartJob()的时候,发送8s的延时MSG
●handleStartedLocked() JobService的onStartJob()回调成功后,发送10mins的延时MSG
●sendStopMessageLocked() 回调JobService的onStopJob()的时候,发送8s的延时MSG
以上可以看出。
疑问一的原因是
onStartJob()没有及时在8s内完成回调,导致JobScheduler自行销毁了该JobService。
而且这时候JobScheduler在结束该Job的时候设置needsReschedule为false,所以这种情况下被销毁了的Job无法自启动。
疑问二的原因是
onStartJob()回调后没有在10mins内调用JobFinished方法通知JobScheduler,导致JobScheduler强制停止了该JobService。
到这里,上面两个疑问都解答了。
我们不禁得到如下启发: