PowerManagerService(下):Doze模式与电池优化

引言

在上一篇中,我们理解了PowerManagerService的基础架构和WakeLock机制------这是主动电源管理:应用告诉系统"我需要保持唤醒"。

但Android还有一套被动电源管理 机制:当应用不活跃时,系统主动限制它的资源使用。这就是Doze模式和App Standby的职责。

想象一下:你的手机在口袋里静置了一整天,但打开后发现电量还剩很多。这背后的功臣,就是今天要讲的这些省电黑科技。

一、Doze模式深度解析

1.1 Doze模式的设计哲学

Doze模式的核心思想很简单:当用户不使用设备时,大部分应用根本不需要后台活动

生活类比:想象你的公司在深夜时分------大楼关灯、空调调低、安保巡逻间隔拉长。但紧急电话还是会接通、消防系统仍在运行。这就是Doze模式:降低非紧急活动,保留关键功能。

1.2 Doze模式的五种状态

Doze模式不是简单的开关,而是一个复杂的状态机:

📌 状态机图 : 见 images/doze-state-machine.excalidraw

scss 复制代码
屏幕开启/充电
      ↓
┌──────────┐  屏幕关闭+拔掉充电器
│  ACTIVE  │ ──────────────────────→ ┌────────────┐
│(完全活跃)│                          │  INACTIVE  │
└──────────┘                          │ (开始监控) │
                                      └──────┬─────┘
                                             │ 无运动+30分钟
                                             ↓
                                      ┌──────────────┐
                                      │IDLE_PENDING  │
                                      │(准备进入Idle)│
                                      └──────┬───────┘
                                             │ 再等待+无网络活动
                                             ↓
                                      ┌─────────────┐
                                      │    IDLE     │ ←┐
                                      │(网络/任务限制)│  │ 循环
                                      └──────┬──────┘  │
                                             │ 维护窗口 │
                                             ↓         │
                                      ┌──────────────┐│
                                      │IDLE_MAINTENANCE││
                                      │(短暂允许活动) │─┘
                                      └──────────────┘

1.3 进入Doze的触发条件

java 复制代码
// frameworks/base/services/core/java/com/android/server/deviceidle/DeviceIdleController.java

// 检查是否可以进入Doze
boolean shouldEnterDeepDoze() {
    // 1. 屏幕必须关闭
    if (mScreenOn) return false;

    // 2. 不能在充电
    if (mCharging) return false;

    // 3. 设备必须静止(无运动)
    if (mMotionActive) return false;

    // 4. 已经过了初始等待时间
    long now = SystemClock.elapsedRealtime();
    if (now - mInactiveTime < mConstants.INACTIVE_TIMEOUT) {
        return false;
    }

    // 5. 没有紧急通知
    if (hasEmergencyAlert()) return false;

    return true;
}

关键理解:进入Doze需要多个条件同时满足,这确保了用户体验不受影响------只在设备确实长时间闲置时才生效。

1.4 Doze模式的核心限制

一旦进入IDLE状态,系统会施加严格限制:

限制项 Doze模式下的行为 正常状态
网络访问 ❌ 禁用,仅维护窗口可用 ✅ 随时可用
WakeLock ❌ 被忽略(PARTIAL除外前台服务) ✅ 正常工作
Alarm ⏰ 延迟到维护窗口 ✅ 准时触发
JobScheduler ⏰ 延迟到维护窗口 ✅ 正常调度
GPS ❌ 禁用 ✅ 可用
WiFi扫描 ❌ 禁用 ✅ 可用
SyncAdapter ⏰ 延迟 ✅ 正常同步

例外情况

  • 高优先级FCM消息(通过特殊通道)
  • 前台服务的WakeLock
  • setAlarmClock()设置的闹钟
  • setExactAndAllowWhileIdle()的Alarm

1.5 维护窗口机制

Doze不是"一直睡",而是"周期性醒来"

makefile 复制代码
Idle周期规律 (指数退避):
第1次: Idle 30分钟 → 维护5分钟
第2次: Idle 60分钟 → 维护5分钟
第3次: Idle 120分钟 → 维护5分钟
第4次: Idle 240分钟 → 维护5分钟
...
最长: Idle 360分钟(6小时) → 维护5分钟

源码实现

java 复制代码
// DeviceIdleController.java

void scheduleAlarmLocked(long delay, boolean idleUntil) {
    if (mMotionSensor == null) {
        // 无运动传感器设备,使用更短的周期
        delay = Math.min(delay, mConstants.MAX_IDLE_TIMEOUT);
    }

    // 计算下一次维护窗口时间
    long nextAlarmTime = SystemClock.elapsedRealtime() + delay;

    // 设置Alarm触发维护窗口
    mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP,
            nextAlarmTime, "DeviceIdleController.deep",
            mDeepAlarmListener, mHandler);
}

// 进入维护窗口
void stepIdleStateLocked(String reason) {
    if (mState == STATE_IDLE) {
        // 从IDLE切换到IDLE_MAINTENANCE
        mState = STATE_IDLE_MAINTENANCE;

        // 解除限制,允许网络活动
        mNetworkPolicyManager.setDeviceIdleMode(false);

        // 唤醒待执行的任务
        mJobSchedulerInternal.unblockAllUnexemptedJobs();

        // 设置维护窗口超时(通常5分钟)
        scheduleAlarmLocked(mConstants.IDLE_MAINTENANCE_TIMEOUT, false);
    }
}

设计智慧

  • 指数退避:越久不用,醒来间隔越长,省电越明显
  • 固定维护时长:保证应用有稳定的同步机会
  • 可配置参数:厂商可根据设备特性调整

1.6 Light Doze vs Deep Doze

Android N引入了两级Doze:

scss 复制代码
┌─────────────┬────────────────┬─────────────────┐
│             │   Light Doze   │   Deep Doze     │
├─────────────┼────────────────┼─────────────────┤
│ 触发条件    │ 屏幕关闭       │ 屏幕关+静止+时间│
│ 首次触发    │ 立即           │ 30-60分钟       │
│ 网络限制    │ 间歇禁用       │ 完全禁用(维护窗口除外) │
│ 维护窗口    │ 每分钟         │ 指数退避(最长6小时) │
│ 使用场景    │ 口袋/包里      │ 桌上/夜间       │
└─────────────┴────────────────┴─────────────────┘

源码区分

java 复制代码
// Light Doze
boolean isLightDoze() {
    return mState >= STATE_LIGHT_IDLE_PENDING
        && mState <= STATE_LIGHT_IDLE_MAINTENANCE;
}

// Deep Doze
boolean isDeepDoze() {
    return mState >= STATE_IDLE_PENDING
        && mState <= STATE_IDLE_MAINTENANCE;
}

二、App Standby机制

2.1 什么是App Standby?

如果说Doze是"设备级省电",App Standby就是"应用级省电"------即使设备在使用,长期不用的应用也会被限制

2.2 五种Standby Bucket

Android将所有应用分为5个"桶"(Bucket),根据使用频率动态调整:

2.3 Bucket的判定逻辑

java 复制代码
// frameworks/base/services/core/java/com/android/server/usage/AppStandbyController.java

int getBucketForPackage(String packageName, int userId, long elapsedRealtime) {
    // 1. 正在前台运行 → ACTIVE
    if (isAppInForeground(packageName, userId)) {
        return STANDBY_BUCKET_ACTIVE;
    }

    // 2. 有前台服务或通知 → ACTIVE
    if (hasNotifications(packageName, userId)) {
        return STANDBY_BUCKET_ACTIVE;
    }

    // 3. 获取上次使用时间
    long lastUsedTime = getLastUsedTime(packageName, userId);
    long timeSinceLastUse = elapsedRealtime - lastUsedTime;

    // 4. 根据时间判定Bucket
    if (timeSinceLastUse < WORKING_SET_THRESHOLD) {
        return STANDBY_BUCKET_WORKING_SET;  // 1天内
    } else if (timeSinceLastUse < FREQUENT_THRESHOLD) {
        return STANDBY_BUCKET_FREQUENT;     // 7天内
    } else if (timeSinceLastUse < RARE_THRESHOLD) {
        return STANDBY_BUCKET_RARE;         // 30天内
    } else {
        return STANDBY_BUCKET_RESTRICTED;   // 超过30天
    }
}

动态调整

  • 使用应用 → 立即升级到ACTIVE
  • 停止使用 → 逐步降级到RARE/RESTRICTED
  • 系统通过UsageStatsService跟踪使用情况

2.4 不同Bucket的具体限制

java 复制代码
// frameworks/base/services/core/java/com/android/server/usage/AppStandbyController.java

// JobScheduler的延迟时间
long getMinJobExecutionGuaranteeMs(int bucket) {
    switch (bucket) {
        case STANDBY_BUCKET_ACTIVE:
            return 0;  // 无延迟
        case STANDBY_BUCKET_WORKING_SET:
            return 2 * 60 * 1000;  // 2分钟
        case STANDBY_BUCKET_FREQUENT:
            return 2 * 60 * 60 * 1000;  // 2小时
        case STANDBY_BUCKET_RARE:
            return 24 * 60 * 60 * 1000;  // 24小时
        case STANDBY_BUCKET_RESTRICTED:
            return 7 * 24 * 60 * 60 * 1000;  // 7天
    }
}

// Alarm的最小间隔
long getMinAlarmIntervalMs(int bucket) {
    switch (bucket) {
        case STANDBY_BUCKET_ACTIVE:
        case STANDBY_BUCKET_WORKING_SET:
            return 0;  // 无限制
        case STANDBY_BUCKET_FREQUENT:
            return 9 * 60 * 1000;  // 9分钟
        case STANDBY_BUCKET_RARE:
            return 15 * 60 * 1000;  // 15分钟
        case STANDBY_BUCKET_RESTRICTED:
            return 60 * 60 * 1000;  // 60分钟
    }
}

关键洞察:RARE和RESTRICTED的延迟非常大,这迫使开发者优化应用,不要依赖频繁的后台任务。

三、后台限制策略

3.1 后台执行限制

Android 15对后台应用有多重限制:

3.1.1 Background Service限制

java 复制代码
// frameworks/base/services/core/java/com/android/server/am/ActiveServices.java

ComponentName startServiceLocked(IApplicationThread caller,
        Intent service, String resolvedType, int callingPid,
        int callingUid, String callingPackage, int userId) {

    // 检查是否允许后台启动服务
    if (!appInForeground && !canStartBackgroundService(callingUid)) {
        throw new IllegalStateException(
            "Not allowed to start service Intent: " + service
            + " app is in background uid " + callingUid);
    }

    // ...启动服务
}

boolean canStartBackgroundService(int uid) {
    // 1. 应用在前台 → 允许
    if (isAppForeground(uid)) return true;

    // 2. 有前台服务 → 允许
    if (hasForegroundService(uid)) return true;

    // 3. 白名单应用 → 允许
    if (isWhitelisted(uid)) return true;

    // 4. 最近用户交互 → 允许(短暂窗口)
    if (recentlyInteracted(uid)) return true;

    return false;
}

例外情况

  • 前台服务(需通知)
  • 接收高优先级消息(FCM)
  • 执行精确的Alarm回调
  • 系统服务或系统签名应用

3.1.2 Broadcast限制

java 复制代码
// 隐式广播(大部分)在后台无法接收
// 例如:CONNECTIVITY_ACTION, BATTERY_CHANGED等
// 解决方案:使用JobScheduler或WorkManager

3.2 网络访问限制

java 复制代码
// frameworks/base/services/core/java/com/android/server/net/NetworkPolicyManagerService.java

void updateRulesForPowerRestrictionsLocked(int uid) {
    boolean backgroundRestricted = isBackgroundRestricted(uid);

    if (backgroundRestricted) {
        // 后台时禁止网络访问
        setUidFirewallRule(FIREWALL_CHAIN_DOZABLE, uid, FIREWALL_RULE_DENY);
    } else {
        setUidFirewallRule(FIREWALL_CHAIN_DOZABLE, uid, FIREWALL_RULE_ALLOW);
    }
}

Data Saver模式

  • 用户可主动开启"省流量模式"
  • 后台应用网络被完全禁用
  • 前台应用不受影响

3.3 唤醒锁(WakeLock)限制

java 复制代码
// PowerManagerService.java

void acquireWakeLockInternal(IBinder lock, int flags, String tag,
        String packageName, WorkSource ws, String historyTag,
        int uid, int pid) {

    // 检查应用的Standby Bucket
    int bucket = mAppStandbyInternal.getAppStandbyBucket(
        packageName, UserHandle.getUserId(uid),
        SystemClock.elapsedRealtime(), false);

    // RESTRICTED bucket的应用WakeLock被严格限制
    if (bucket == STANDBY_BUCKET_RESTRICTED) {
        if (!isExempted(packageName)) {
            // 拒绝或设置超时强制释放
            enforceWakeLockTimeout(lock, RESTRICTED_WAKELOCK_MAX_TIMEOUT);
        }
    }

    // ...继续正常流程
}

四、BatteryStats统计系统

4.1 BatteryStats架构

BatteryStats是Android的"黑匣子",记录所有电量相关的操作:

scss 复制代码
BatteryStatsService (Framework)
           ↓
    BatteryStats (核心统计)
           ↓
    ┌──────┴──────┐
    │             │
UID Statistics   System Statistics
(每个应用)        (系统级)
    │             │
    ├─ WakeLock   ├─ Screen On/Off
    ├─ CPU Time   ├─ WiFi On/Off
    ├─ Network    ├─ Bluetooth
    ├─ Sensor     ├─ GPS
    └─ Alarm      └─ Charging

4.2 关键统计项

java 复制代码
// frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java

// 每个UID的统计
public static class Uid extends BatteryStats.Uid {
    // WakeLock持有时长
    StopwatchTimer mWakeLockStats;

    // CPU使用时间
    LongSamplingCounter mUserCpuTime;
    LongSamplingCounter mSystemCpuTime;

    // 网络流量
    LongSamplingCounter mNetworkBytesSent;
    LongSamplingCounter mNetworkBytesReceived;

    // 传感器使用时长
    HashMap<Integer, Sensor> mSensorStats;

    // Alarm触发次数
    Counter mAlarmCount;
}

4.3 电量消耗计算

BatteryStats不直接测量电量,而是通过模型估算

java 复制代码
// Power profile定义硬件功耗参数
// frameworks/base/core/res/res/xml/power_profile.xml

<device name="Android">
    <item name="screen.on">100</item>      <!-- 屏幕开启功耗(mA) -->
    <item name="cpu.active">120</item>     <!-- CPU活跃功耗 -->
    <item name="wifi.on">30</item>         <!-- WiFi开启功耗 -->
    <item name="bluetooth.on">10</item>    <!-- 蓝牙开启功耗 -->
</device>

计算公式

arduino 复制代码
应用耗电量 = Σ (使用时长 × 对应功耗)

例如:
  WakeLock功耗 = WakeLock持有时长 × CPU功耗
  网络功耗 = 网络活跃时长 × WiFi/数据网络功耗
  传感器功耗 = 传感器使用时长 × 传感器功耗

4.4 查看BatteryStats

bash 复制代码
# 导出完整统计
adb shell dumpsys batterystats > batterystats.txt

# 重置统计(调试用)
adb shell dumpsys batterystats --reset

# 查看特定应用
adb shell dumpsys batterystats <package-name>

# 生成HTML报告(需SDK工具)
python battery-historian/scripts/historian.py batterystats.txt > report.html

关键指标

  • Screen on time - 屏幕亮起总时长
  • Wake Lock time - WakeLock持有总时长
  • Mobile active time - 数据网络活跃时长
  • WiFi running time - WiFi开启时长
  • GPS on time - GPS使用时长

五、充电管理与电池健康

5.1 电池状态监控

java 复制代码
// frameworks/base/services/core/java/com/android/server/BatteryService.java

private void processValuesLocked(boolean force) {
    // 从底层HAL读取电池信息
    mHealthInfo = mHealthServiceWrapper.getHealthInfo();

    int level = mHealthInfo.batteryLevel;        // 电量百分比
    int status = mHealthInfo.batteryStatus;      // 充电状态
    int health = mHealthInfo.batteryHealth;      // 电池健康度
    int temperature = mHealthInfo.batteryTemperature;  // 温度(0.1°C)

    // 发送电池变化广播
    if (force || level != mLastBatteryLevel || status != mLastBatteryStatus) {
        Intent intent = new Intent(Intent.ACTION_BATTERY_CHANGED);
        intent.putExtra(BatteryManager.EXTRA_LEVEL, level);
        intent.putExtra(BatteryManager.EXTRA_STATUS, status);
        // ... 其他参数
        mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
    }
}

5.2 充电优化策略

Android 15引入了智能充电优化:

java 复制代码
// Adaptive Charging - 自适应充电
// 根据用户习惯,在晚上慢速充电到80%,早上前充满

boolean shouldEnableAdaptiveCharging() {
    // 1. 检查是否在夜间充电
    boolean isNightTime = isCurrentlyNightTime();
    if (!isNightTime) return false;

    // 2. 预测用户起床时间
    long predictedWakeTime = predictUserWakeTime();

    // 3. 计算充电策略
    if (predictedWakeTime - SystemClock.elapsedRealtime() > 4 * 60 * 60 * 1000) {
        // 超过4小时,启用慢充
        return true;
    }

    return false;
}

慢充好处

  • 降低电池温度,延长寿命
  • 减少充满后"浮充"时间
  • 根据用户习惯,恰好在需要时充满

5.3 电池健康监控

java 复制代码
// 电池健康状态
public static final int BATTERY_HEALTH_UNKNOWN = 1;
public static final int BATTERY_HEALTH_GOOD = 2;
public static final int BATTERY_HEALTH_OVERHEAT = 3;      // 过热
public static final int BATTERY_HEALTH_DEAD = 4;          // 损坏
public static final int BATTERY_HEALTH_OVER_VOLTAGE = 5;  // 过压
public static final int BATTERY_HEALTH_COLD = 7;          // 过冷

// 温度保护机制
void checkBatteryTemperature() {
    if (mHealthInfo.batteryTemperature > TEMP_OVERHEAT_THRESHOLD) {
        // 过热时停止充电
        setChargingEnabled(false);
        showOverheatNotification();
    }
}

六、调试与问题诊断

6.1 Doze模式调试

bash 复制代码
# 强制进入Doze模式
adb shell dumpsys deviceidle force-idle

# 退出Doze
adb shell dumpsys deviceidle unforce

# 查看当前Doze状态
adb shell dumpsys deviceidle

# 输出示例:
#   Idle mode: STATE_IDLE
#   Light idle: STATE_LIGHT_IDLE
#   Next maintenance window: 2024-01-01 10:30:00

模拟完整Doze流程

bash 复制代码
# 1. 拔掉充电器
# 2. 关闭屏幕
adb shell input keyevent KEYCODE_SLEEP

# 3. 禁用运动传感器(模拟静止)
adb shell dumpsys deviceidle disable

# 4. 强制进入IDLE_PENDING
adb shell dumpsys deviceidle step

# 5. 强制进入IDLE
adb shell dumpsys deviceidle step

# 6. 测试维护窗口
adb shell dumpsys deviceidle step  # 进入IDLE_MAINTENANCE

# 7. 恢复
adb shell dumpsys deviceidle enable

6.2 App Standby调试

bash 复制代码
# 查看应用的Standby Bucket
adb shell am get-standby-bucket <package-name>

# 手动设置Bucket(测试用)
adb shell am set-standby-bucket <package-name> rare

# Bucket选项:
# - active (10)
# - working_set (20)
# - frequent (30)
# - rare (40)
# - restricted (50)

# 查看所有应用Bucket
adb shell dumpsys usagestats | grep -A 10 "Standby Buckets"

6.3 电量问题诊断

常见问题1:应用耗电异常

bash 复制代码
# 查看耗电排行
adb shell dumpsys batterystats | grep "Estimated power"

# 分析特定应用
adb shell dumpsys batterystats <package-name> | grep -E "Wake lock|Sensor|Network"

# 检查WakeLock泄漏
adb shell dumpsys batterystats | grep "PARTIAL_WAKE_LOCK"

常见问题2:Doze模式不生效

bash 复制代码
# 检查是否有阻止Doze的条件
adb shell dumpsys deviceidle

# 查看输出:
# - mCharging: 是否在充电
# - mScreenOn: 屏幕是否开启
# - mMotionActive: 是否检测到运动
# - mState: 当前状态

常见问题3:后台任务不执行

bash 复制代码
# 检查应用Bucket
adb shell am get-standby-bucket <package-name>

# 检查电池优化设置
adb shell dumpsys deviceidle whitelist | grep <package-name>

# 检查是否有JobScheduler任务被延迟
adb shell dumpsys jobscheduler | grep <package-name>

七、最佳实践

7.1 Doze适配建议

kotlin 复制代码
// ✅ 正确:使用FCM高优先级消息
val message = RemoteMessage.Builder("to")
    .setPriority(RemoteMessage.PRIORITY_HIGH)  // 高优先级,Doze时也能收到
    .setData(mapOf("key" to "value"))
    .build()

// ✅ 正确:重要闹钟使用setAlarmClock
alarmManager.setAlarmClock(
    AlarmManager.AlarmClockInfo(triggerTime, pendingIntent),
    pendingIntent
)

// ✅ 正确:允许Doze时触发的Alarm
alarmManager.setExactAndAllowWhileIdle(
    AlarmManager.RTC_WAKEUP,
    triggerTime,
    pendingIntent
)

// ❌ 错误:普通Alarm在Doze时会被延迟
alarmManager.setExact(
    AlarmManager.RTC_WAKEUP,
    triggerTime,
    pendingIntent  // Doze时会延迟到维护窗口
)

7.2 App Standby适配

kotlin 复制代码
// 监听Bucket变化
class MyUsageStatsObserver : UsageStatsManager.OnUsageStatsChangeListener {
    override fun onUsageStatsChanged(event: Event) {
        val bucket = usageStatsManager.getAppStandbyBucket()
        when (bucket) {
            STANDBY_BUCKET_ACTIVE -> {
                // 无限制,可以正常后台任务
            }
            STANDBY_BUCKET_WORKING_SET -> {
                // 轻微限制,减少后台频率
            }
            STANDBY_BUCKET_FREQUENT -> {
                // 中等限制,只保留重要同步
            }
            STANDBY_BUCKET_RARE, STANDBY_BUCKET_RESTRICTED -> {
                // 严格限制,几乎停止后台活动
                cancelNonEssentialWork()
            }
        }
    }
}

// 使用WorkManager自动适配Bucket
val work = PeriodicWorkRequestBuilder<SyncWorker>(
    repeatInterval = 1, TimeUnit.HOURS  // WorkManager会自动根据Bucket调整
).build()
workManager.enqueue(work)

7.3 后台限制适配

kotlin 复制代码
// ✅ 正确:使用前台服务(有通知)
class DownloadService : Service() {
    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        // 显示前台通知
        val notification = createNotification()
        startForeground(NOTIFICATION_ID, notification)

        // 执行下载任务
        doDownload()
        return START_NOT_STICKY
    }
}

// ✅ 正确:使用WorkManager替代后台服务
val downloadWork = OneTimeWorkRequestBuilder<DownloadWorker>()
    .setConstraints(
        Constraints.Builder()
            .setRequiredNetworkType(NetworkType.CONNECTED)
            .setRequiresCharging(false)
            .build()
    )
    .build()
workManager.enqueue(downloadWork)

// ❌ 错误:后台启动Service(Android 8+会崩溃)
if (appInBackground) {
    context.startService(Intent(context, MyService::class.java))
    // 抛出 IllegalStateException
}

7.4 电量优化建议

场景 传统方案 优化方案
定时同步 AlarmManager + Service WorkManager定期任务
推送消息 轮询 FCM推送
位置更新 GPS持续运行 Fused Location + 被动位置
传感器 持续监听 降低采样率 + 批处理
网络请求 随时发起 批量合并 + 延迟执行

八、Android 15新特性

8.1 增强的Doze模式

java 复制代码
// 更短的进入时间
// Android 15降低了进入Doze的时间门槛
private static final long INACTIVE_TIMEOUT = 15 * 60 * 1000;  // 15分钟(原30分钟)

// 更智能的维护窗口
// 根据应用优先级分配维护窗口时长
long getMaintenanceWindowDuration(String packageName) {
    int importance = mImportanceProvider.getImportance(packageName);
    if (importance == IMPORTANCE_HIGH) {
        return 10 * 60 * 1000;  // 高优先级10分钟
    }
    return 5 * 60 * 1000;  // 普通5分钟
}

8.2 预测性电池管理

java 复制代码
// 机器学习预测用户行为
class AdaptiveBatteryManager {
    // 预测应用未来使用概率
    float predictAppUsageProbability(String packageName, long timeWindow) {
        // 基于历史使用模式的ML模型
        return mMLModel.predict(packageName, timeWindow);
    }

    // 根据预测调整Bucket
    void adjustBucketByPrediction(String packageName) {
        float probability = predictAppUsageProbability(packageName,
            60 * 60 * 1000);  // 未来1小时

        if (probability > 0.8) {
            // 高概率使用,提前升级到ACTIVE
            setStandbyBucket(packageName, STANDBY_BUCKET_ACTIVE);
        }
    }
}

8.3 更细粒度的网络控制

java 复制代码
// 应用可以声明网络使用优先级
<application>
    <meta-data
        android:name="android.net.network_priority"
        android:value="high" />  <!-- high/medium/low -->
</application>

// Doze时,high优先级的网络请求可以更早执行

总结

本篇我们深入分析了Android的高级电源管理机制:

  1. Doze模式:设备级省电,通过状态机和维护窗口实现智能休眠
  2. App Standby:应用级省电,根据使用频率动态限制后台活动
  3. 后台限制:多重限制机制,包括服务、广播、网络、WakeLock
  4. BatteryStats:完善的统计系统,追踪所有电量消耗
  5. 充电优化:智能充电策略,延长电池寿命

关键设计思想

  • 用户无感:限制只在用户不使用时生效
  • 分级限制:根据重要性施加不同程度的限制
  • 白名单机制:保证关键功能不受影响
  • 开发者友好:提供WorkManager等高层API简化适配

参考资料


系列导航


本文基于Android 15 (API Level 35)源码分析,不同厂商的定制ROM可能存在差异。 欢迎来我中的个人主页找到更多有用的知识和有趣的产品

相关推荐
砖厂小工3 小时前
Compose 中函数引用 vs Lambda:到底该用哪个?
android
Kapaseker13 小时前
详解 Compose background 的重组陷阱
android·kotlin
黄林晴14 小时前
Kotlin 2.3.20-RC2 来了!JPA 开发者狂喜,6 大更新一文速览
android·kotlin
冬奇Lab1 天前
OpenClaw 深度解析(八):Skill 系统——让 LLM 按需学习工作流
人工智能·开源·源码阅读
kymjs张涛1 天前
OpenClaw 学习小组:初识
android·linux·人工智能
范特西林1 天前
实战演练——从零实现一个高性能 Binder 服务
android
范特西林1 天前
代码的生成:AIDL 编译器与 Parcel 的序列化艺术
android
范特西林1 天前
深入内核:Binder 驱动的内存管理与事务调度
android
范特西林1 天前
解剖麻雀:Binder 通信的整体架构全景图
android