Android 9.0 JobScheduler(四) Job约束条件的控制

本文详细分析了Android 9.0中JobScheduler的约束条件控制,包括DeviceIdleJobsController、IdleController、TimeController、BatteryController、BackgroundJobsController、ConnectivityController、StorageController和ContentObserverController的工作原理,阐述了它们如何根据设备状态、时间、电池、网络和存储等条件来调度和限制Job的执行。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

上一篇文章:JobScheduler源码分析(三) Job从创建到执行

在前两篇文章中,对JobSchedulerService的启动和Job的调度过程大致做了个梳理,通过前几篇的分析我们知道,要使得客户端Job被JSS调度执行,必须满足该Job在创建时所设置的约束,而这些约束何时满足,这将由StateController进行控制,本篇中将对所有StateController类的控制流程进行分析。

通过前面文章的分析得,共有八个StateController的子类,各自单独地记录每个Job的状态,并在Job准备好运行时通知JSS进行调度执行,或者在约束条件不满足时通知JSS停止Job的执行。所有的StateController类有如下共性:

  • 1.在JobSchedulerService的构造方法中进行实例化;
  • 2.每向JSS中加入一个Job,都会调用StateController.maybeStartTrackingJobLocked()方法开始记录跟踪此Job;
  • 3.当Job调度执行完毕后、或当Job被取消时,都会调用StateController.maybeStopTrackingJobLocked()方法停止此Job的记录;

除了以上共同特性外,各个状态控制器中对约束的设置,大部分是通过广播实现的,状态控制器内部会注册一个广播,当广播接收器收到广播后,将根据得到的状态,通过setXXXConstraintSatisfied()方法,对satisfiedConstraints进行按位运算,比如在DeviceIdleJobsController中会调用setDeviceNotDozingConstraintSatisfied(true/false)来设置是否Doze的约束条件满足。第三篇文章分析时说过:JobStatus中有一个全局变量satisfiedConstraints,这个表示该Job当前满足的约束,如果当前状态控制器所检测到的系统状态满足某个约束,则按位或,否则清零即可。最终在判断Job约束条件是否满足时,将拿satisfiedConstraintsrequiredConstraints进行比较,requiredConstraints变量上记录的是创建Job时在JobInfo设置的所有约束条件,也是通过按位或运算进行标记的:

    public boolean isConstraintsSatisfied() {
   
        //该Job所有的约束条件
        final int req = requiredConstraints & CONSTRAINTS_OF_INTEREST;
        //该Job现在所满足的约束条件
        int sat = satisfiedConstraints & CONSTRAINTS_OF_INTEREST;
        //相等,说明当前所满足约束已是所需所有约束
        return (sat & req) == req;
    }

下面我们就具体来看看,各个状态控制器如何获取并将结果设置给satisfiedConstraints的,这部分逻辑比较清晰易懂,就不再啰哩啰嗦了,点到为止即可。

1. DeviceIdleJobsController

DeviceIdleJobsController用来控制Job对Doze的依赖条件,或者也可以说Doze对Job的限制,当设备进入Doze模式的IDLE状态时,将会限制除了Doze白名单外的所有应用的Job调度,当Doze退出IDLE状态进入维护状态后,将会对所有应用的Job解除限制。而DeviceIdleJobsController中则是通过广播的形式来感知Doze模式的状态变化,在其构造方法中可以看到广播的注册和监听:

    public DeviceIdleJobsController(JobSchedulerService service) {
   
        super(service);

        // ......
        final IntentFilter filter = new IntentFilter();
        // Deep Doze状态发生改变后发送
        filter.addAction(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED);
        // Light Doze状态发生改变后发送
        filter.addAction(PowerManager.ACTION_LIGHT_DEVICE_IDLE_MODE_CHANGED);
        // 白名单列表发生变化时发送
        filter.addAction(PowerManager.ACTION_POWER_SAVE_WHITELIST_CHANGED);
        // i临时白名单列表发生变化时发送
        filter.addAction(PowerManager.ACTION_POWER_SAVE_TEMP_WHITELIST_CHANGED);
        mContext.registerReceiverAsUser(
                mBroadcastReceiver, UserHandle.ALL, filter, null, null);
    }

来看看关于广播接收器中的逻辑,其中只看当Doze的状态发生变化的部分:


    private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
   
        @Override
        public void onReceive(Context context, Intent intent) {
   
            switch (intent.getAction()) {
   
                // Deep Doze和Light Doze进入/退出IDLE后发送
                case PowerManager.ACTION_LIGHT_DEVICE_IDLE_MODE_CHANGED:
                case PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED:
                    //根据Doze是否进入IDLE状态更新状态
                    updateIdleMode(mPowerManager != null && (mPowerManager.isDeviceIdleMode()
                            || mPowerManager.isLightDeviceIdleMode()));
                    break;
            }
        }
    };

以上逻辑中可以看到,不管是Deep Doze还是Light Doze,当进入或者退出IDLE后,执行的是同样的流程,这一方面也说明两种Doze对Job都是有延迟的。然后通过PowerManager获取到当前Doze的状态,并调用updateIdleMode()更新,updateIdleMode()方法中的处理主要如下:

  • 1.Doze退出/进入时,都会进行Job的遍历,并最终会调用updateTaskStateLocked()方法更新Job的Doze约束;
  • 2.如果退出Doze后,立即会处理处于前台的进程的Job,其余进程通过Handler延时3s处理;
  • 3.一旦Doze状态发生改变,将通过onDeviceIdleStateChanged()回调进入JSS中。

来看看updateTaskStateLocked():

    private boolean updateTaskStateLocked(JobStatus task) {
   
        //是否豁免Doze模式的限制:设置了标记且(对应app处于前台或app处于临时白名单列表中)
        final boolean allowInIdle = ((task.getFlags()&JobInfo.FLAG_IMPORTANT_WHILE_FOREGROUND) != 0)
                && (mForegroundUids.get(task.getSourceUid()) || isTempWhitelistedLocked(task));
        //Job所属应用是否处于Doze白名单中
        final boolean whitelisted = isWhitelistedLocked(task);
        //Job是否允许调度:Doze模式不处于IDLE状态或应用处于白名单中或应用处于前台且带有FLAG_IMPORTANT_WHILE_FOREGROUND
        final boolean enableTask = !mDeviceIdleMode || whitelisted || allowInIdle;
        //设置Doze模式约束条件
        return task.setDeviceNotDozingConstraintSatisfied(enableTask, whitelisted);
    }

在以上方法中,判断是否这个Job可以在Doze下调度呢?并将结果通过setDeviceNotDozingConstraintSatisfied()设置给JobStatus:

    boolean setDeviceNotDozingConstraintSatisfied(boolean state, 
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值