JobService源码探究之 onStartJob()返回false立马被destroy

简介: JobService源码探究之 onStartJob()返回false立马被destroy

上一章节讲解了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图,来整体的认识一下这个机制。

20200308234636925.jpg

我们再从别的角度对这些核心类和接口梳理一下。

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吗?

如果会的话,新线程是否会导致内存泄漏?

※当然,这种情况还是很少见,自己明明要处理任务呢,却告诉系统处理完了。对于实际的编码的意义不大,但是感兴趣的话可以自行调查下。


相关文章
|
11月前
|
JavaScript
判断函数是否标记为async
判断函数是否标记为async
判断函数是否标记为async
|
4月前
|
测试技术
详解单元测试问题之MockHandlerImpl类的handle方法中VerificationMode不为空如何解决
详解单元测试问题之MockHandlerImpl类的handle方法中VerificationMode不为空如何解决
56 3
|
6月前
|
XML Java 数据格式
面试题:怎样把所有的组件的lazy-init值都设置为默认true?
面试题:怎样把所有的组件的lazy-init值都设置为默认true?
48 0
(附运行结果和截图)关于try{return}finally中都有return 运行结果测试之旅
(附运行结果和截图)关于try{return}finally中都有return 运行结果测试之旅
return的作用
js中的函数只是实现某种功能,最终的结果需要返回给函数的调用者 函数名( ) 通过return实现的。 只要函数遇到return 就把后面的结果,返回给函数的调用者。 函数名 ( ) = return 后面的结果。
|
前端开发
前端学习案例1-empty和undefined区别
前端学习案例1-empty和undefined区别
85 0
前端学习案例1-empty和undefined区别
|
应用服务中间件
reloadable=“false“ 的作用
reloadable=“false“ 的作用
136 0
|
存储 Java API
JobService源码探究之 Job自行Cancel后即使onStopJob返回true也不会被再启动
JobService源码探究之 Job自行Cancel后即使onStopJob返回true也不会被再启动
|
编译器 Linux C语言
C++__return 0是什么意思?
C++__return 0是什么意思?
343 0
|
JavaScript 数据安全/隐私保护 前端开发
js中return,return true,return false三者的用法及区别
return其实就是return undefined; 1.语法及返回方式 ①返回控制与函数结果         语法为:return 表达式;         语句结果函数的执行,返回调用函数,而且把表达式的值作为函数结果返回出去 ②返回控制无函数结果         语法为:return;         在大多数情况下,为事件处理函数如果让其返回false,可以防止默认的事件行为.
1637 0