第 30 章:后台任务调度

后台工作是移动操作系统中永恒的矛盾点。用户希望邮件同步、照片备份、信息流刷新、通知能够及时送达。但每一项后台操作都会消耗电池、占用网络带宽,还会与前台应用争抢 CPU 与内存资源。一台普通设备上安装有成百上千款应用,这就造成了公地悲剧:单个应用的后台工作看似合理,但叠加在一起会严重损耗电池续航。

十余年以来,Android 针对后台行为出台了越来越严格的限制机制。本章完整梳理后台执行整套基础设施:Android 8.0 引入的执行限制、JobScheduler(使用约束感知调度器替代零散后台任务)、负责定时唤醒的 AlarmManager、WorkManager 抽象层、前台服务及其迭代变更的要求,以及用于限制隐式唤醒的广播限制。

30.1 后台执行限制

Android 8.0(Oreo,API 26)引入了平台历史上力度最大的后台执行限制。在 Oreo 之前,任意应用都可以启动服务、注册广播接收器,几乎不受约束地执行后台任务。最终造成电池续航差、系统性能下降。

30.1.1 Oreo 之前存在的问题

Android 8.0 之前,后台滥用现象十分普遍:

  • 应用启动长期运行的服务,无期限驻留后台
  • 数十个应用注册同一类隐式广播(例如CONNECTIVITY_CHANGED),引发广播风暴,唤醒每一个注册应用
  • 后台服务无协调地消耗 CPU、内存、网络资源
  • 用户无法直观看到哪些应用在后台消耗资源

30.1.2 后台服务限制

从 Android 8.0 开始,target API26 及以上的应用受如下约束:

后台服务限制:处于后台的应用不能随意调用startService()。如果应用不在前台(无可见 Activity、无正在运行的前台服务),调用startService()会抛出IllegalStateException

允许的替代方案:

  • startForegroundService() — 启动服务,必须在 5 秒内发布一条通知
  • JobScheduler.schedule() — 调度带约束的任务
  • WorkManager.enqueue() — 调度可延迟任务(AndroidX)

30.1.3 前台状态定义

满足下面任意条件,系统判定应用处于前台

条件 示例
拥有可见 Activity 应用打开,显示在屏幕上
拥有前台服务 音乐播放器、导航、文件上传
被前台应用通过 ContentProvider 调用 前台应用正在使用该应用的 ContentProvider
处于临时白名单 刚刚收到高优先级 FCM 消息

前台 / 后台的精确状态由ActivityManagerService中每个应用 UID 对应的UidRecord跟踪维护。

30.1.4 应用待机分组(App Standby Buckets)

Android 9.0(Pie,API28)引入应用待机分组,根据用户最近使用频率,对后台限制做进一步分级。

分组 判定条件 Job 延迟时长 Alarm 延迟时长
Active 正在使用或刚刚使用过 无限制 无限制
Working Set 经常使用,当前不在活跃状态 最多延迟 2 小时 最多延迟 6 分钟
Frequent 经常使用,但非每日使用 最多延迟 8 小时 最多延迟 30 分钟
Rare 很少使用 最多延迟 24 小时 最多延迟 2 小时
Restricted 极少交互,耗电高 最多 24 小时,每日最多 1 个 Job 最多延迟 24 小时

分组由UsageStatsManagerInternalAppStandbyInternal管理。

// JobSchedulerService中定义的分组索引
// frameworks/base/apex/jobscheduler/service/java/com/android/server/job/
//     JobSchedulerService.java
public static final int ACTIVE_INDEX = 0;
public static final int WORKING_INDEX = 1;
public static final int FREQUENT_INDEX = 2;
public static final int RARE_INDEX = 3;
public static final int NEVER_INDEX = 4;
public static final int RESTRICTED_INDEX = 5;
public static final int EXEMPTED_INDEX = 6;

30.1.5 Doze 模式与应用待机

Android 6.0 引入 Doze 模式:当设备静置、未充电、屏幕长时间熄灭时,限制后台活动。Android7.0 新增轻量 “移动 Doze”,屏幕熄灭即可触发,即便设备在移动状态。

Doze 模式下行为:

  • 禁止网络访问
  • JobScheduler 任务不执行
  • 不同步数据
  • 闹钟全部延迟
  • 唤醒锁失效

Doze 期间系统行为:

  1. 延迟全部闹钟(setAlarmClock()以及白名单精确闹钟除外)
  2. 阻断网络访问
  3. 暂停 Job 与同步任务
  4. 忽略唤醒锁
  5. 周期性打开维护窗口,执行被延迟的任务

30.1.6 省电模式

省电模式(用户手动开启或者低电量自动触发)会叠加更多限制:

  • 降低后台网络访问
  • 延迟 Job 与闹钟
  • 降低定位精度
  • 限制后台 CPU 占用
  • 限制视觉效果(动画、动态壁纸)

30.1.7 后台限制演进历史

Android 版本 API 核心限制
6.0 (Marshmallow) 23 Doze 模式、应用待机
7.0 (Nougat) 24 移动 Doze、隐式广播受限
8.0 (Oreo) 26 后台服务限制、广播限制
9.0 (Pie) 28 应用待机分组
10 (Q) 29 后台启动 Activity 限制
11 (R) 30 强制前台服务类型
12 (S) 31 精确闹钟限制、后台启动前台服务限制
12L 32 进一步收紧前台服务限制
13 (T) 33 按应用语言、细化运行时权限
14 (U) 34 强制前台服务类型、SCHEDULE_EXACT_ALARM权限受限
15 (V) 35 dataSync 前台服务 6 小时超时
16 36 用户发起任务 (UIJ) 通知集中管控,UIJ 通知禁止随意关闭
17 37 新增getPendingJobReasons*()诊断接口、废弃 Job 检测、按网络连接批量调度、Perfetto Job 追踪、start‑user‑before‑alarm

30.2 JobScheduler

JobScheduler 是 Android 调度可延迟后台任务的核心机制,Android5.0(API21)引入。应用声明需要执行的工作与执行条件,由系统决定实际运行时机。系统可以批量合并任务、推迟到合适时机(充电、Wi‑Fi 环境)执行,同时强制执行待机分组配额。

30.2.1 架构总览

全部核心组件位于 JobScheduler APEX 模块。

源码路径:frameworks/base/apex/jobscheduler/service/java/com/android/server/job/

30.2.2 JobSchedulerService

JobSchedulerService是总调度协调器,继承SystemService,实现两个监听接口。

// frameworks/base/apex/jobscheduler/service/java/com/android/server/job/
//     JobSchedulerService.java
public class JobSchedulerService extends com.android.server.SystemService
        implements StateChangedListener, JobCompletedListener {

    public static final String TAG = "JobScheduler";

    /** 单个应用允许调度的默认最大任务数量 */
    private static final int DEFAULT_MAX_JOBS_PER_APP = 150;

    /** 任务主存储列表 */
    final JobStore mJobs;

    /** 控制器列表,通知服务任务状态变更 */
    final List<StateController> mControllers;

    /** 就绪待执行任务队列 */
    private final PendingJobQueue mPendingJobQueue = new PendingJobQueue();

    /** 管理任务并发执行槽位 */
    final JobConcurrencyManager mConcurrencyManager;

    // ...
}

关键常量与限制:

  • DEFAULT_MAX_JOBS_PER_APP = 150:单应用默认最多 150 个调度任务;该数值通过构造函数传入,可配置,不是硬编码常量。
  • NUM_COMPLETED_JOB_HISTORY = 20:系统保存最近 20 个已完成任务用于调试。

构造函数会初始化JobPerfettoTracer(参见 §30.7),任务完整生命周期输出到 Perfetto 跟踪。

this(context, DEFAULT_MAX_JOBS_PER_APP, null, JobPerfettoTracer.create());

30.2.3 JobInfo:定义任务与约束

应用使用JobInfo.Builder描述任务。

JobInfo jobInfo = new JobInfo.Builder(JOB_ID,
        new ComponentName(context, MyJobService.class))
    // 约束条件
    .setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED)
    .setRequiresCharging(true)
    .setRequiresDeviceIdle(true)
    .setRequiresBatteryNotLow(true)
    .setRequiresStorageNotLow(true)

    // 时间配置
    .setMinimumLatency(15 * 60 * 1000)     // 至少延迟15分钟后执行
    .setOverrideDeadline(60 * 60 * 1000)    // 1小时内必须执行
    .setPeriodic(24 * 60 * 60 * 1000)       // 每24小时重复执行

    // 持久化,重启后保留
    .setPersisted(true)

    // Content URI内容触发器
    .addTriggerContentUri(
        new JobInfo.TriggerContentUri(
            MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
            JobInfo.TriggerContentUri.FLAG_NOTIFY_FOR_DESCENDANTS))

    // 重试退避策略
    .setBackoffCriteria(30_000, JobInfo.BACKOFF_POLICY_EXPONENTIAL)

    // 加急任务(API31+)
    .setExpedited(true)

    // 预估网络流量
    .setEstimatedNetworkBytes(
        5 * 1024 * 1024,   // 下载5MB
        1024 * 1024)        // 上传1MB

    .build();

// 提交调度
JobScheduler scheduler = context.getSystemService(JobScheduler.class);
int result = scheduler.schedule(jobInfo);
// result == JobScheduler.RESULT_SUCCESS 或 RESULT_FAILURE

30.2.4 约束类型

约束系统是 JobScheduler 的核心,每种约束由独立StateController管理。

约束 控制器 源码文件
网络类型 / 网络连通性 ConnectivityController controllers/ConnectivityController.java
时间(延迟、截止时间、周期) TimeController controllers/TimeController.java
设备空闲 IdleController controllers/IdleController.java
充电 / 电量充足 BatteryController controllers/BatteryController.java
存储空间充足 StorageController controllers/StorageController.java
Content URI 变更 ContentObserverController controllers/ContentObserverController.java
配额管控 QuotaController controllers/QuotaController.java
弹性约束降级 FlexibilityController controllers/FlexibilityController.java
后台限制 BackgroundJobsController controllers/BackgroundJobsController.java
Doze 模式 DeviceIdleJobsController controllers/DeviceIdleJobsController.java
应用组件启用状态 ComponentController controllers/ComponentController.java
预取时机控制 PrefetchController controllers/PrefetchController.java

全部控制器源码路径: frameworks/base/apex/jobscheduler/service/java/com/android/server/job/controllers/

部分控制器(BatteryController、ConnectivityController、IdleController)继承RestrictingController而非直接继承StateController。该类增加两个钩子:startTrackingRestrictedJobLocked()stopTrackingRestrictedJobLocked(),专门跟踪处于RESTRICTED待机分组的应用任务,该分组约束执行条件更加严格。

IdleController 的空闲检测逻辑在controllers/idle/子包下:包含DeviceIdlenessTrackerCarIdlenessTracker,以及IdlenessTracker/IdlenessListener接口,手机与车载设备可以使用不同的 “空闲” 判定逻辑。

30.2.5 StateController 架构

所有控制器继承抽象基类StateController

// frameworks/base/apex/jobscheduler/service/java/com/android/server/job/
//     controllers/StateController.java
public abstract class StateController {
    protected final JobSchedulerService mService;
    protected final StateChangedListener mStateChangedListener;
    protected final Context mContext;
    protected final Object mLock;

    /**
     * 实现该逻辑,判断控制器是否需要跟踪该任务
     */
    public abstract void maybeStartTrackingJobLocked(
            JobStatus jobStatus, JobStatus lastJob);

    /**
     * 将任务从控制器跟踪列表移除
     */
    public abstract void maybeStopTrackingJobLocked(
            JobStatus jobStatus, JobStatus lastJob);

    /**
     * 控制器状态变更时调用,重新评估就绪任务
     */
    public void evaluateStateLocked(JobStatus jobStatus) {}
}

每个控制器维护一组被跟踪任务,在JobStatus对象上维护约束满足标记位。当控制器状态发生变化(例如设备连上 Wi‑Fi),通过StateChangedListener通知JobSchedulerService,重新评估待执行任务。

30.2.6 JobStatus:任务内部表示

JobStatus是调度器内部对任务的表示,融合原始JobInfo与控制器维护的运行时状态。

// frameworks/base/apex/jobscheduler/service/java/com/android/server/job/
//     controllers/JobStatus.java

/**
 * 任务内部唯一标识
 * 任务被调度时,由公开API JobInfo生成
 * 保存任务各项约束的当前状态,提供判断是否可运行的函数
 */
public final class JobStatus {
    // 显式约束低位,与JobInfo.CONSTRAINT_FLAG_*共用
    public static final int CONSTRAINT_CHARGING = JobInfo.CONSTRAINT_FLAG_CHARGING;      // 1 << 0
    public static final int CONSTRAINT_BATTERY_NOT_LOW =
            JobInfo.CONSTRAINT_FLAG_BATTERY_NOT_LOW;                                     // 1 << 1
    public static final int CONSTRAINT_IDLE = JobInfo.CONSTRAINT_FLAG_DEVICE_IDLE;       // 1 << 2
    public static final int CONSTRAINT_STORAGE_NOT_LOW =
            JobInfo.CONSTRAINT_FLAG_STORAGE_NOT_LOW;                                     // 1 << 3

    // 其余显式约束占用高位比特
    public static final int CONSTRAINT_TIMING_DELAY = 1 << 31;
    public static final int CONSTRAINT_DEADLINE = 1 << 30;
    public static final int CONSTRAINT_CONNECTIVITY = 1 << 28;
    public static final int CONSTRAINT_CONTENT_TRIGGER = 1 << 26;

    // 系统额外叠加的隐式约束(应用未声明)
    public static final int CONSTRAINT_DEVICE_NOT_DOZING = 1 << 25;        // 隐式约束
    public static final int CONSTRAINT_WITHIN_QUOTA = 1 << 24;             // 隐式约束
    public static final int CONSTRAINT_PREFETCH = 1 << 23;
    public static final int CONSTRAINT_BACKGROUND_NOT_RESTRICTED = 1 << 22; // 隐式约束
    public static final int CONSTRAINT_FLEXIBLE = 1 << 21;                  // 隐式约束

    // 全部约束满足时任务才可执行
    public boolean isReady() {
        return isReady(mSatisfiedConstraintsOfInterest);
    }
}

低 4 位(充电、电量充足、设备空闲、存储充足)与应用设置的JobInfo.CONSTRAINT_FLAG_*共用;高位保存时间、网络、内容触发器,同时叠加系统隐式约束(非 Doze 状态、配额可用、后台未被限制、弹性降级标记)。

这就是为什么仅仅设置网络约束的任务依然可能处于等待状态:Doze、配额、后台限制同样是约束条件,由对应控制器评估。

30.2.7 任务调度流程

30.2.8 JobStore:持久化存储

JobStore 将调度任务持久化为 XML 文件,设备重启后任务不丢失。

源码路径:frameworks/base/apex/jobscheduler/service/java/com/android/server/job/JobStore.java

// frameworks/base/apex/jobscheduler/service/java/com/android/server/job/
//     JobStore.java
package com.android.server.job;

// 任务存储路径 /data/system/job/jobs.xml
// XML格式,保存每个任务约束、时间、元数据

文件使用AtomicFile原子写入,防止异常关机文件损坏。开机时 JobStore 读取该文件,恢复所有通过setPersisted(true)设置持久化的任务。

30.2.9 ConnectivityController:网络约束

ConnectivityController跟踪网络状态,判断任务网络约束是否满足。

源码路径:frameworks/base/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java

// frameworks/base/apex/jobscheduler/service/java/com/android/server/job/
//     controllers/ConnectivityController.java
package com.android.server.job.controllers;

//
内容概要:本文研究了在通信资源受限与恶意攻击干扰下的孤岛微电网分布式二次控制策略,提出了一种兼具通信效率与攻击弹性的动态事件触发控制方案,旨在实现电压频率的精确恢复与有功无功功率的均衡共享。通过Simulink仿真与Matlab代码实现,系统验证了该策略在显著降低通信频次的同时,能够有效抵御拒绝服务(DoS)等网络攻击,保障微电网在复杂环境下的稳定运行。研究深入探讨了动态事件触发机制的设计、分布式控制算法的弹性优化,并确保系统具备排除芝诺行为的能力,从而全面提升微电网在极端条件下的鲁棒性、可靠性与运行效率。; 适合人群:具备电力系统、自动化或相关领域基础知识,从事微电网、分布式控制、能源系统安全方向研究的研究生、科研人员及工程技术人员。; 使用场景及目标:①应用于孤岛微电网在遭受通信限制和网络攻击时的二次电压与频率调节;②为高比例新能源接入场景下的微电网提供具备攻击容忍能力的弹性控制解决方案;③支持科研仿真验证与教学演示,推动分布式能源系统安全控制技术的发展。; 阅读建议:建议结合提供的Simulink模型与Matlab代码进行仿真实践,深入理解控制策略的实现细节,并可通过修改攻击模型、通信参数或网络拓扑进行拓展性研究,以全面掌握其弹性机制与优化潜力。
上市公司绿色全要素生产率(Green Total Factor Productivity,简称GTFP)是衡量企业绿色发展和资源配置效率的重要指标,其不仅关注经济效益,还强调环境效益,体现了绿色发展理念。 一、上市公司绿色全要素生产率的介绍 上市公司绿色全要素生产率是衡量企业在实现绿色发展的过程中,如何有效地利用劳动、资本、能源等资源进行生产的综合效率。本分享数据涵盖2500+家上市公司,数据年份为2007-2022年,共46424条样本,含证券代码、年份、绿色全要素生产率、绿色技术效率变化指数、绿色技术进步变化指数。 二、数据指标 绿色全要素生产率 绿色技术效率变化指数 绿色技术进步变化指数 用于衡量企业绿色发展效率的综合指标 反映绿色技术使用效率的变化 衡量绿色技术进步的效果 三、测算方式 企业绿色全要素生产率的测算采用了非径向SBM-ML指数(简称“ML指数”)模型。该模型通过将企业的环境污染、绿色技术进步等因素纳入生产效率评价体系,全面反映了企业在绿色发展方面的整体表现。 具体的测算方式如下: (1)要素投入:以企业员工数作为劳动投入的代理变量,企业固定资产净额作为资本投入的代理变量,企业所在城市的工业用电量根据企业从业人员占城市城镇人员就业比重进行换算作为能源投入的代理变量。 (2)期望产出:以企业的营业收入作为期望产出的代理变量。 (3)非期望产出:将企业从业人员占所在城市城镇人员就业比重与“工业三废”(即工业二氧化硫、工业废水、工业烟粉尘排放量)结合,进行换算,作为非期望产出的代理变量。 四、参考文献 崔立志,孙旺,黄敏敏.新能源示范城市建设对企业绿色全要素生产率的影响研究——基于A股上市公司的实证分析[J].广西财经学院学报,2023,36(01):92-104. 五、数据来源 数据来源于《中国城市统计年鉴》、《中国环境统计年鉴》、
内容概要:本文针对电动汽车充电站接入对配电网承载能力的影响,提出了一套完整的评估与优化方法体系。基于Matlab代码实现,构建了计及多渗透率电动汽车接入的配电网承载能力评估模型,综合考虑一次设备安全、负荷平稳性、电能质量和系统效率等多维度指标,建立了基于熵权法与模糊综合评价相结合的双层评分模型,实现了对不同场景下配电网承载能力的科学量化评估。通过典型算例仿真,分析了电动汽车不同接入规模对配电网各项性能指标的影响规律与敏感性,验证了所提方法的有效性与实用性,为高比例电动汽车接入背景下的电网规划、扩容改造及运行管理提供了有力的技术支撑与决策依据。; 适合人群:具备电力系统分析基础和Matlab编程能力,从事智能电网、电动汽车并网、配电系统规划等相关领域的研究生、科研人员及工程技术人员。; 使用场景及目标:①评估大规模电动汽车充电负荷对配电网安全性、稳定性和电能质量的综合影响;②为充电基础设施规划布局、配电网升级改造及需求侧管理策略制定提供量化分析工具;③开展相关课题研究或撰写学术论文时提供可复现的模型框架与代码实现参考; 阅读建议:建议结合文中提供的Matlab代码与仿真算例进行实践操作,重点掌握多维评价指标体系的构建逻辑、熵权法赋权与模糊综合评价的集成方法,并可通过调整参数设置进一步探究不同因素对评估结果的影响,深化对配电网承载能力演化规律的理解。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值