JobService源码探究之 onStartJob()里执行耗时逻辑导致Job可能被强制销毁

本文解答了关于JobService中onStartJob()方法处理耗时逻辑的两个疑问:为何直接执行耗时操作会导致Job自动销毁;为何后台线程执行超过10分钟也会使Job被停止销毁。通过分析源码揭示了不同场景下的超时处理机制。
摘要由CSDN通过智能技术生成
在上篇 《JobService源码探究之 onStartJob()里如何优雅地处理耗时逻辑?》里我们留下了如下两个疑问。
在本篇里一一解答。


疑问一

为什么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;
    }


检索scheduleOpTimeOutLocked()调用的地方,我们发现如下场合的时候都会调用该方法发送一定时间的延时MSG。


●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。


到这里,上面两个疑问都解答了。


我们不禁得到如下启发:


启发一

如果非得在onStartJob()里执行任务逻辑的话,请不要超过8s。


启发二

如果在onStartJob()里已经开启了线程执行任务逻辑,但是处理时间尽量控制在10mins内。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

TechMerger

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值