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图,来整体的认识一下这个机制。


JobService源码探究之 onStartJob()返回false立马被destroy_第1张图片


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


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 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吗?
如果会的话,新线程是否会导致内存泄漏?


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




我们还有个疑问二要继续探究。留到下次再讲。

你可能感兴趣的:(Android,JobService,Android,JobService,JobScheduler,Service,Android,8.0)