引言
在上一篇中,我们理解了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的高级电源管理机制:
- Doze模式:设备级省电,通过状态机和维护窗口实现智能休眠
- App Standby:应用级省电,根据使用频率动态限制后台活动
- 后台限制:多重限制机制,包括服务、广播、网络、WakeLock
- BatteryStats:完善的统计系统,追踪所有电量消耗
- 充电优化:智能充电策略,延长电池寿命
关键设计思想:
- 用户无感:限制只在用户不使用时生效
- 分级限制:根据重要性施加不同程度的限制
- 白名单机制:保证关键功能不受影响
- 开发者友好:提供WorkManager等高层API简化适配
参考资料
系列导航:
本文基于Android 15 (API Level 35)源码分析,不同厂商的定制ROM可能存在差异。 欢迎来我中的个人主页找到更多有用的知识和有趣的产品