Android 9.0 JobScheduler(二) JobScheduler框架结构简述及JobSchedulerService的启动

上一篇文章:JobScheduler(一)——JobScheduler的使用

1.JobScheduler框架简述

在上一篇文章中,对怎样使用JobScheduler做了一个简单的总结,当客户端应用通过JobScheduler.schedule(JobInfo)方法将创建的Job发送给JobScheduler后,Framework层将完全负责它的启动、执行、完成等生命周期调度。从这篇文章开始,将对JobScheduler框架层的源码及其实现原理进行分析。

整个JobScheduler框架类结构如下图所示:
JSS类图

橙色代表暴露给应用层的API

从图中来看,整个JobScheduler框架还是挺复杂的,图中各类说明如下:

  • JobScheduler:暴露给客户端的接口类,它是一个抽象类,通过getSystemService()获取实例;
  • JobSchedulerImpl:JobScheduler的具体实现类,客户端实际拿到的是该类实例,其中携带一个Binder实例,将调用进入JobSchedulerService;
  • JobInfo:暴露给客户端的用于创建Job的类,封装了创建Job时所设置的所有信息;
  • JobService:继承于Service,客户端需要JobService的子类来执行任务;
  • JobSchedulerService:继承于SystemService的系统服务,负责调度所有的Job;
  • JobStatus:Framework层内部表示Job的唯一标识,通过JobInfo创建,其中存储了所有的Job信息;
  • JobStore:负责维护JobSchedulerService正在跟踪的Job的列表,还支持一些遍历Job、读写文件等操作(将job信息写入/data/system/job/jobs.xml中)。在获取JobStore实例时,通过单例模式保证JSS只持有一个该类对象;
  • StateController:状态控制器的基类,每个子类控制器单独负责控制一个系统状态,当状态发生变化后,将通知JobSchedulerService进行处理;
  • StateChangedListener:状态控制器的回调接口,所有控制器通过该接口来通知JobSchedulerService;
  • JobServiceContext:继承于ServiceConnection,负责和应用的JobService绑定和作业生命周期管理。此类的一个实例上只能执行一个作业。
  • JobServiceEngine:应用端的JobService和JobSchedulerService进行交互的"引擎",帮读一个客户端Service后,将由该类去调用客户端的onStartJob()方法开始执行任务;
  • JobCompletedListener:作业执行完毕后的回调接口。

针对整个框架的实现原理,可以简单地这样描述: 首先通过JobScheduler创建一个Job,接着JobSchedulerService将负责调度job,经过各种StateController对其进行跟踪,当满足条件后,将通过JobServiceContext和客户端JobService进行绑定并对Job进行生命周期管理,然后在生命周期的某个阶段中通过JobServiceEngine调用客户端方法来执行Job任务,执行完成后,又在生命周期的某个阶段回调JobCompletedListener接口通知JobSchedulerService

2.JobSchedulerService的启动

JobSchedulerService(以下简称JSS)是一个系统服务,它是SystemService的子类,因此,当系统开机后,SystemServer中将会启动它,并依次执行它的生命周期方法。

2.1.SystemServer中启动JSS

当SystemServer进程启动以后,将在startOtherService()中开始启动JobSchedulerService:

    /**
     * Starts a miscellaneous grab bag of stuff that has yet to be refactored
     * and organized.
     */
    private void startOtherServices() {
            //...
            mSystemServiceManager.startService(JobSchedulerService.class);
            //...
    }

进入到mSystemServiceManager中,将通过反射方式获得一个JobSchedulerService实例,并调用SystemService生命周期方法中的onStart():

    /**
     * Creates and starts a system service. The class must be a subclass of
     * {@link com.android.server.SystemService}.
     *
     * @param serviceClass A Java class that implements the SystemService interface.
     * @return The service instance, never null.
     * @throws RuntimeException if the service fails to start.
     */
    @SuppressWarnings("unchecked")
    public <T extends SystemService> T startService(Class<T> serviceClass) {
        try {
            final String name = serviceClass.getName();
            Slog.i(TAG, "Starting " + name);
            // Create the service.
            final T service;
            try {
                Constructor<T> constructor = serviceClass.getConstructor(Context.class);
                //获得JobSchedulerService实例
                service = constructor.newInstance(mContext);
            } catch (InstantiationException ex) {
               //......
            } catch (InvocationTargetException ex) {
                throw new RuntimeException("Failed to create service " + name
                        + ": service constructor threw an exception", ex);
            }
            startService(service);
            return service;
        } finally {
            Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
        }
    }

    public void startService(@NonNull final SystemService service) {
        // 加入到List<SystemService>集合中
        mServices.add(service);
        // Start it.
        long time = SystemClock.elapsedRealtime();
        try {
            //调用onStart()方法
            service.onStart();
        } catch (RuntimeException ex) {
            throw new RuntimeException("Failed to start service " + service.getClass().getName()
                    + ": onStart threw an exception", ex);
        }
    }

从以上代码中可以得知,首先会执行JobSchedulerService的构造方法,之后将执行其onStart()方法,除此之外,随着SystemServer的启动,最终还会执行其onBootPhase(int),这个方法表示启动阶段,根据参数每调用一次该方法,表示启动到了一个阶段。比如:

    private void startOtherServices() {
        //......
        //表示核心系统服务已经启动完毕,可以放心使用了
        mSystemServiceManager.startBootPhase(SystemService.PHASE_SYSTEM_SERVICES_READY);
        //到这个阶段时,表示服务可以启动或绑定到应用程序了,应用程序也将可以通过Binder调用SystemService进程了
        mSystemServiceManager.startBootPhase(
                    SystemService.PHASE_THIRD_PARTY_APPS_CAN_START);
        //......
    }

接下来,我们就进入JobSchedulerService中,根据它的启动流程,依次分析其构造方法、onStart()onBootPhase()方法。

2.2.Constructor()方法

首先来看其构造方法:

    public JobSchedulerService(Context context) {
        super(context);

        //获取本地PackManagerService内部类对象(只能在system_server进程使用)
        mLocalPM = LocalServices.getService(PackageManagerInternal.class);
        //获取本地ActivityManagerService内部类对象
        mActivityManagerInternal = Preconditions.checkNotNull(
                LocalServices.getService(ActivityManagerInternal.class));

        //实例化Handler,并使用当前进程主线程Looper
        mHandler = new JobHandler(context.getMainLooper());
        //实例化Constants,其中定义了许多常量
        mConstants = new Constants();
        //实例化内容观察者对象
        mConstantsObserver = new ConstantsObserver(mHandler);
        //实例化JobSchedulerStub对象,将发布到系统服务中,作为Binder的服务端
        mJobSchedulerStub = new JobSchedulerStub();

        //实例化StandbyTracker,用于记录appStandby信息
        mStandbyTracker = new StandbyTracker();
        //获取本地USageStatsService内部类对象
        mUsageStats = LocalServices.getService(UsageStatsManagerInternal.class);
        //设置一个AppIdleState监听
        mUsageStats.addAppIdleStateChangeListener(mStandbyTracker);

        // The job store needs to call back
        //发布本地服务,在system_server进程中就可以通过LocalServices.getService()得到JSS.LocalService
        publishLocalService(JobSchedulerInternal.class, new LocalService());

        //获取JobStore对象,使用了单例模式,保证只有一个JobStore对象
        mJobs = JobStore.initAndGet(this);

        // Create the controllers.
        //创建一系列控制器,并添加到集合mControllers中,每个控制器分别负责监听一项系统行为,如网络检测、Doze状态检测、截至时间控制...
        mControllers = new ArrayList<StateController>();
        mControllers.add(new ConnectivityController(this));
        mControllers.add(new TimeController(this));
        mControllers.add(new IdleController(this));
        mBatteryController = new BatteryController(this);
        mControllers.add(mBatteryController);
        mStorageController = new StorageController(this);
        mControllers.add(mStorageController);
        mControllers.add(new BackgroundJobsController(this));
        mControllers.add(new ContentObserverController(this));
        mDeviceIdleJobsController = new DeviceIdleJobsController(this);
        mControllers.add(mDeviceIdleJobsController);

        // If the job store determined that it can't yet reschedule persisted jobs,
        // we need to start watching the clock.
        //如果RTC未准备就绪,则注册一个广播
        if (!mJobs.jobTimesInflatedValid()) {
            Slog.w(TAG, "!!! RTC not yet good; tracking time updates for job scheduling");
            context.registerReceiver(mTimeSetReceiver, new IntentFilter(Intent.ACTION_TIME_CHANGED));
        }
    }

构造方法中初始化了许多系统服务实例,其中还以单例模式的形式得到一个JobStore对象,该对象作用是维护系统中的Job列表,客户端每向JSS中添加一个Job,JobStore都会对其进行记录,并写入/data/system/job/jobs.xml中。

2.3.onStart()

接下来再看看其onStart()方法:

    @Override
    public void onStart() {
        publishBinderService(Context.JOB_SCHEDULER_SERVICE, mJobSchedulerStub);
    }

这个方法非常简单,只是将JobSchedulerStub对象作为JobSchedulerService的Binder服务进行发布,这样做的目的主要是用来注册JobSchedulerService。之后在其他系统服务中,就可以通过ServiceManager.getService()获取得到这个Binder对象,在注册JobSchedulerService时,正是这样做的:

final class SystemServiceRegistry {
    static {
        // ......
        registerService(Context.JOB_SCHEDULER_SERVICE, JobScheduler.class,
                new StaticServiceFetcher<JobScheduler>() {
            @Override
            public JobScheduler createService() throws ServiceNotFoundException {
                //首先得到由publishBinderService()发布的mJobSchedulerStub对象
                IBinder b = ServiceManager.getServiceOrThrow(Context.JOB_SCHEDULER_SERVICE);
                return new JobSchedulerImpl(IJobScheduler.Stub.asInterface(b));
            }});
    }
    //......
}

在注册JobSchedulerService时,首先通过ServiceManager.getServiceOrThrow()得到JobScheduler.Stub对象,再将它作为参数实例化了JobSchedulerImpl。因此我们可以看到,在使用JobScheduler框架时,获取的JobScheduler对象,实际上是JobSchedulerImpl对象:

JobScheduler mJobScheduler = (JobScheduler) Context.getSystemService(Context.JOB_SCHEDULER_SERVICE).

而JobSchedulerImpl类则是抽象类JobScheduler的子类,并且在JobSchedulerImpl中携带一个IJobScheduler的Binder对象,当应用层调用JobScheduler的方法时,在方法内部会调用这个Binder的同名方法,从而进入JobSchedulerService中,完成调度。这一块会在下文中详细分析。

2.4.onBootPhase()

再回到JobSchedulerService的启动流程中,当调用完毕onStart()方法后,下一个调用的将是onBootPhase()方法,该方法如下:

    @Override
    public void onBootPhase(int phase) {
        //该启动阶段表示系统服务已准备完毕,可以被核心系统服务调用了
        if (PHASE_SYSTEM_SERVICES_READY == phase) {
            //注册内容观察者,用于监听指定Uri的改变
            mConstantsObserver.start(getContext().getContentResolver());

            //用于记录与Force App Standby相关的信息
            mAppStateTracker = Preconditions.checkNotNull(
                    LocalServices.getService(AppStateTracker.class));
            //设置一个心跳Alarm,用来进行待机桶心跳,心跳数超过某一待机桶后,将执行由于待机桶推迟的Job
            setNextHeartbeatAlarm();

            // Register br for package removals and user removals.
            final IntentFilter filter = new IntentFilter();
            //卸载应用广播
            filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
            //应用状态发生改变广播,如禁用/启用
            filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
            //应用发生重启广播
            filter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
            /* lock screen and clean apps for powercontroller */
            filter.addAction(PowerManager.ACTION_POWER_CONTROLLER_KILL_APP);
            //询问对应应用是否需要重启的广播
            filter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);
            //设置该filter处理的Data类型为package:,因为以上广播发送时通过Intent.setData()或Intent(action,uri)设置了data类型为package
            filter.addDataScheme("package");
            //注册以上广播
            getContext().registerReceiverAsUser(
                    mBroadcastReceiver, UserHandle.ALL, filter, null, null);
            //当用户移除时发送的广播
            final IntentFilter userFilter = new IntentFilter(Intent.ACTION_USER_REMOVED);
            getContext().registerReceiverAsUser(
                    mBroadcastReceiver, UserHandle.ALL, userFilter, null, null);
            try {
                //注册一个UidObserver,用来在Uid状态发生改变时做出相关反应
                ActivityManager.getService().registerUidObserver(mUidObserver,
                        ActivityManager.UID_OBSERVER_PROCSTATE | ActivityManager.UID_OBSERVER_GONE
                        | ActivityManager.UID_OBSERVER_IDLE | ActivityManager.UID_OBSERVER_ACTIVE,
                        ActivityManager.PROCESS_STATE_UNKNOWN, null);
            } catch (RemoteException e) {
                // ignored; both services live in system_server
            }
            // Remove any jobs that are not associated with any of the current users.
            //移除没有和当前用户关联的Job
            cancelJobsForNonExistentUsers();
        //该启动阶段表示三方应用的服务可以启动或绑定、三方应用可以通过Binder访问系统服务了
        } else if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) {
            synchronized (mLock) {
                // Let's go!
                //当系统可以运行三方应用时,将其置为true
                mReadyToRock = true;
                //获取BatteryStats对象,该服务负责统计电池信息
                mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService(
                        BatteryStats.SERVICE_NAME));
                //获取本地DeviceIdlerController对象,该服务负责Doze模式
                mLocalDeviceIdleController
                        = LocalServices.getService(DeviceIdleController.LocalService.class);
                // Create the "runners".
                //创建MAX_JOB_CONTEXTS_COUNT个JobServiceContext
                //一个Job只能在一个JobServiceContext实例上运行
                for (int i = 0; i < MAX_JOB_CONTEXTS_COUNT; i++) {
                    mActiveServices.add(
                            new JobServiceContext(this, mBatteryStats, mJobPackageTracker,
                                    getContext().getMainLooper()));
                }
                // Attach jobs to their controllers.
                //遍历每个userid对应的每个job,然后通过maybeStartTrackingJobLocked让每个控制器开始跟踪每个job
                mJobs.forEachJob((job) -> {
                    for (int controller = 0; controller < mControllers.size(); controller++) {
                        final StateController sc = mControllers.get(controller);
                        sc.maybeStartTrackingJobLocked(job, null);
                    }
                });
                // GO GO GO!
                //发送一个Handler
                mHandler.obtainMessage(MSG_CHECK_JOB).sendToTarget();
            }
        }
    }

在以上方法中,当系统分别启动到PHASE_SYSTEM_SERVICES_READY阶段和PHASE_THIRD_PARTY_APPS_CAN_START阶段时,将会调用该方法并执行各自的逻辑。

当这个方法执行完毕后,整个JobSchedulerService的启动就完成了。接下来我们对onBootPhase()中调用到的一些方法进行分析。

2.5.setNextHeartbeatAlarm()设置待机桶心跳

该方法用来进行AppStandbyBucket心跳,这是Android P新增的省电机制,在AppStandbyBucket机制中,系统将所有应用划分在了5个待机桶中:

  • ACTIVE: 当前正在运行的应用和经常运行的应用,处于该桶中的应用,不会对其进行Job、Alarm、网络等限制;
  • WORKING SET: 最近使用过,可能会在几小时内使用的应用,处于该桶中的应用,会推迟其Job、Alarm的执行;
  • FREQUENT: 通常会使用,但不会每天都使用的应用,处于该桶中的应用,会推迟其Job、Alarm的执行;;
  • RARE: 不频繁使用的应用,处于该桶中的应用,将会进行最严格的限制,比如推迟其Job、Alarm及后台网络等;
  • NEVER:从未使用的应用。

而待机桶中对Job的限制,正是和setNextHeartbeatAlarm()相关,下面逐步分析下到底怎样实现的限制。

    void setNextHeartbeatAlarm() {
        final long heartbeatLength;
        synchronized (mLock) {
            //心跳周期,660s
            heartbeatLength = mConstants.STANDBY_HEARTBEAT_TIME;
        }
        //当前时间
        final long now = sElapsedRealtimeClock.millis();
        //得到一个心跳序号:1,2,3....
        final long nextBeatOrdinal = (now + heartbeatLength) / heartbeatLength;
        //得到下次设置心跳Alarm时长 = 序号*心跳标准周期
        final long nextHeartbeat = nextBeatOrdinal * heartbeatLength;
        AlarmManager am = (AlarmManager) getContext().getSystemService(Context.ALARM_SERVICE);
        //设置心跳Alarm
        am.setExact(AlarmManager.ELAPSED_REALTIME, nextHeartbeat,
                HEARTBEAT_TAG, mHeartbeatAlarm, mHandler);
    }

在以上方法中,首先是得到一个心跳顺序值,并根据这个值得到Alarm的触发时间,到到达触发时间后,将回调mHeartbeatAlarm.onAlarm()方法,接着看这个方法:

class HeartbeatAlarmListener implements AlarmManager.OnAlarmListener {

@Override
public void onAlarm() {
    synchronized (mLock) {
        //上次心跳过了多久?因为心跳并非定期的,而是不规律的,而且可能有推迟
        final long sinceLast = sElapsedRealtimeClock.millis() - mLastHeartbeatTime;
        //时间间隔除以心跳标准周期,得到理论的心跳次数,为何不直接每次累加1得到心跳次数呢?因为Alarm毕竟不准确,而且进入Doze后对Alarm有调整
        final long beatsElapsed = sinceLast / mConstants.STANDBY_HEARTBEAT_TIME;
        // 当sinceLast >= mConstants.STANDBY_HEARTBEAT_TIME时,两者之商大于0
        // beatsElapsed > 0,说明至少这次和上次心跳间隔了1个心跳周期
        if (beatsElapsed > 0) {
            //累加最后一次心跳时间
            mLastHeartbeatTime += beatsElapsed * mConstants.STANDBY_HEARTBEAT_TIME;
            //处理心跳数是否满足某个桶的规定
            advanceHeartbeatLocked(beatsElapsed);
        }

     }
    //重新设置一个心跳Alarm
    setNextHeartbeatAlarm();
   }
}

onAlarm()中,如果满足两次Alarm间隔大于一个心跳周期,则会调用advanceHeartbeatLocked()方法:

    void advanceHeartbeatLocked(long beatsElapsed) {
        mHeartbeat += beatsElapsed;//累加心跳数
        // 不更新ACTIVE和NEVER桶,因为前者中的应用不进行限制,而后者中的应用永不运行
        // 当mHeartbeat >= mNextBucketHeartbeat[bucket],处于该桶中的应用的job将被允许立即执行
        boolean didAdvanceBucket = false;
        //遍历待机桶心跳时间,不包括ACTIVE和NEVER待机桶
        for (int i = 1; i < mNextBucketHeartbeat.length - 1; i++) {
            //如果心跳数到达或超过待机桶中的时间,将didAdvanceBucket置为true
            //当前心跳数等于或超过各个待机桶的心跳阀值时,将允许其中的应用的Job执行
            if (mHeartbeat >= mNextBucketHeartbeat[i]) {
                didAdvanceBucket = true;
            }
            //当前心跳数大于各个待机桶的心跳阀值时,则重置(增加)对应待机桶中应用的心跳时间
            while (mHeartbeat > mNextBucketHeartbeat[i]) {
                mNextBucketHeartbeat[i] += mConstants.STANDBY_BEATS[i];
            }
        }

        //检查Job队列,将运行符合条件的Job
        if (didAdvanceBucket) {
            mHandler.obtainMessage(MSG_CHECK_JOB).sendToTarget();
        }
    }

以上方法用来判断是否心跳数等于或者超过各个待机桶的心跳数阀值,如果满足,则将开始检查Job队列,并执行因待机桶而延迟的Job,否则将继续延迟,其中使用到的一些全局变量如下:

//各个待机桶中应用解除推迟Job的触发心跳数
final long[] mNextBucketHeartbeat = {0, 0, 0, 0, Long.MAX_VALUE};
//总的心跳次数,但并非Alarm触发一次就加1,而是根据心跳周期进行计算
long mHeartbeat = 0;
//最后一次心跳时间,默认值当前时间,累加心跳周期*心跳次数得到
long mLastHeartbeatTime = sElapsedRealtimeClock.millis();
//计算各个桶心跳阀值的数组源
final int[] STANDBY_BEATS = {
	0,//AVCTIVE桶,不限制
	DEFAULT_STANDBY_WORKING_BEATS,//WORKING SET桶心跳数阀值,11
	DEFAULT_STANDBY_FREQUENT_BEATS,//FREQUENT桶,43
	DEFAULT_STANDBY_RARE_BEATS//RARE桶,130
};

回到方法中,当当前心跳数等于或者大于各个待机桶的心跳阀值时,首先再次调整阀值,然后通过Handler开始检查Job状态并执行满足条件的Job。在调整各个待机桶阀值时,通过STANDBY_BEATS数组进行,比如当系统启动后,各个待机桶阀值为0,于是开始调整阀值分别为11,43,130…当心跳14次后,此时超过了WORKING_BEATS待机桶阀值,于是会对处于WORKING_BEATS桶中的应用的Job解除限制,然后将WORKING_BEATS桶阀值调整到11+11=22…

关于Job解除后的执行,会在下一篇文章中进行。而onBootPhase()方法中调用的sc.maybeStartTrackingJobLocked()用来通知各个控制器开始记录、跟踪每个应用的每个Job,这里也暂不分析。接下来我们看看mHandler.obtainMessage(MSG_CHECK_JOB)后的流程。

2.6.Handler.obtainMessage(MSG_CHECK_JOB)检查待执行Job队列

在JobHandler的handleMessage()中:


        @Override
        public void handleMessage(Message message) {
            synchronized (mLock) {
                    //......
                    case MSG_CHECK_JOB:
                        //如果系统Doze模式不处于IDLE状态(包括有Job正在运行或不处于Doze的IDLE状态),说明此时Job可以活动
                        if (mReportedActive) {
                            //对Job进行入队操作以准备执行
                            queueReadyJobsForExecutionLocked();
                        } else {
                            // 否则说明此时处于Doze的IDLE状态,但可以强制运行一些符合条件的job,这里对满足条件的Job也进行入队操作
                            maybeQueueReadyJobsForExecutionLocked();
                        }
                        break;
                     //......
                maybeRunPendingJobsLocked();
                // Don't remove JOB_EXPIRED in case one came along while processing the queue.
                removeMessages(MSG_CHECK_JOB);
            }
        }

在以上方法中,如果此时系统不处于处于Doze模式的IDLE状态时,说明Doze对Job无限制,此时就可以进Job进行入队操作了,如果处于Doze模式中的IDLE状态,此时可以对满足执行条件的job进行强制执行(即使处于IDLE状态),下面我们分别看下这两种Job入队的情况。

2.7.更新待执行Job队列

2.7.1.queueReadyJobsForExecutionLocked()

该方法如下:

    private void queueReadyJobsForExecutionLocked() {

        noteJobsNonpending(mPendingJobs);//记录待执行队列中但未执行Job
        mPendingJobs.clear();//清除待执行Job队列
        //取消未准备但已激活的Job
        stopNonReadyActiveJobsLocked();
        mJobs.forEachJob(mReadyQueueFunctor);//遍历各个Uid的所有Job
        //添加到待执行Job队列中,并按照时间排序,得到新的待执行队列mPendingJobs
        mReadyQueueFunctor.postProcess();
    }

在这个方法中,首先清空了原来的待执行Job队列mPendingJobs,然后通过mJob.forEachJob()进行遍历,遍历期间将触发mReadyQueueFunctor.accept(),在accept()中会创建一个新数组,并将满足约束的Job添加到数组中,最终将整个数组添加到mPendingJobs,以完成待执行队列的更新,一起看下这部分逻辑:

    final class ReadyJobQueueFunctor implements Consumer<JobStatus> {
        ArrayList<JobStatus> newReadyJobs;

        @Override
        public void accept(JobStatus job) {
            //是否满足执行条件
            if (isReadyToBeExecutedLocked(job)) {
                //创建一个新列表,作为保存待执行Job的临时列表
                if (newReadyJobs == null) {
                    newReadyJobs = new ArrayList<JobStatus>();
                }
                //在所有的Job中,将满足条件的Job添加
                newReadyJobs.add(job);
            }
        }

        public void postProcess() {
            if (newReadyJobs != null) {
                noteJobsPending(newReadyJobs);//记录待执行Job
                //将newReadyJobs所有元素添加到mPendingJobs中
                mPendingJobs.addAll(newReadyJobs);
                if (mPendingJobs.size() > 1) {
                    //按照Job创建时间排序
                    mPendingJobs.sort(mEnqueueTimeComparator);
                }
            }
            //置空临时列表newReadyJobs
            newReadyJobs = null;
        }
    }

在以上方法中,isReadyToBeExecutedLocked()用来判断该Job是否已满足所有的约束条件,这个方法将会在下一篇文章中分析到。再来看看另一个Job入队的方法。

2.7.2.maybeQueueReadyJobsForExecutionLocked()

该方法如下:

    private void maybeQueueReadyJobsForExecutionLocked() {

        //......
        mPendingJobs.clear();//清除要执行的Job
        stopNonReadyActiveJobsLocked();//取消未准备但运行的Job
        mJobs.forEachJob(mMaybeQueueFunctor);
        mMaybeQueueFunctor.postProcess();
    }

从以上内容中看,除了mJobs.forEachJob()参数不同外,方法中内容和queueReadyJobsForExecutionLocked()中的一模一样,继续来看其mMaybeQueueFunctor:

    final class MaybeReadyJobQueueFunctor implements Consumer<JobStatus> {

        // Functor method invoked for each job via JobStore.forEachJob()
        @Override
        public void accept(JobStatus job) {
            //是否满足执行条件
            if (isReadyToBeExecutedLocked(job)) {
                try {
                    //如果job对应app禁止运行,则返回
                    if (ActivityManager.getService().isAppStartModeDisabled(job.getUid(),
                            job.getJob().getService().getPackageName())) {
                        mHandler.obtainMessage(MSG_STOP_JOB, job).sendToTarget();
                        return;
                    }
                } catch (RemoteException e) {
                }
                //此Job执行失败次数
                if (job.getNumFailures() > 0) {
                    backoffCount++;
                }
                //此Job是否有Doze条件约束
                if (job.hasIdleConstraint()) {
                    idleCount++;
                }
                //此Job是否有Doze条件约束
                if (job.hasConnectivityConstraint()) {
                    connectivityCount++;
                }
                //此Job是否有充电约束
                if (job.hasChargingConstraint()) {
                    chargingCount++;
                }
                //是否有低电量约束
                if (job.hasBatteryNotLowConstraint()) {
                    batteryNotLowCount++;
                }
                if (job.hasStorageNotLowConstraint()) {
                    storageNotLowCount++;
                }
                //是否有内容观察者触发器约束
                if (job.hasContentTriggerConstraint()) {
                    contentCount++;
                }
                if (runnableJobs == null) {
                    runnableJobs = new ArrayList<>();
                }
                runnableJobs.add(job);
            }
        }

        public void postProcess() {
            //满足任意一个条件,就将runnableJobs中的Job添加到待执行队列中
            if (backoffCount > 0 ||
                    idleCount >= mConstants.MIN_IDLE_COUNT ||
                    connectivityCount >= mConstants.MIN_CONNECTIVITY_COUNT ||
                    chargingCount >= mConstants.MIN_CHARGING_COUNT ||
                    batteryNotLowCount >= mConstants.MIN_BATTERY_NOT_LOW_COUNT ||
                    storageNotLowCount >= mConstants.MIN_STORAGE_NOT_LOW_COUNT ||
                    contentCount >= mConstants.MIN_CONTENT_COUNT ||
                    (runnableJobs != null
                            && runnableJobs.size() >= mConstants.MIN_READY_JOBS_COUNT)) {
                noteJobsPending(runnableJobs);
                mPendingJobs.addAll(runnableJobs);
                if (mPendingJobs.size() > 1) {
                    mPendingJobs.sort(mEnqueueTimeComparator);
                }
            } else {
            }

            //重置数据为0或null
            reset();
        }

        private void reset() {
            chargingCount = 0;
            //......
        }
    }

从以上逻辑中可以看出,即使当前系统处于IDLE状态,但如果满足Job执行的约束条件,且满足规定的一些最小Job数,那么也会加入待执行队列的,而加入待执行Job队列后,接下来就要执行队列中的Job了。

2.8.maybeRunPendingJobsLocked()开始执行Job

回到handleMessage()中,当更新完mPendingJobs,将调用maybeRunPendingJobsLocked()开始执行Job:

    private void maybeRunPendingJobsLocked() {

        //为待执行队列中的Job分配JobServiceContext并执行
        assignJobsToContextsLocked();
        //向Doze状态(DeviceIdleController)报告状态
        reportActiveLocked();
    }

从此处开始,接下来的流程将在下一篇文章中分析,从此处分析来看,开始执行Job的起始方法就是maybeRunPendingJobsLocked()。以上流程时序图如下:
JSS启动流程

下一篇文章:JobScheduler(三)——Job从创建到执行

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值