深入理解 Android:PowerManagerService、BatteryService/BatteryStatsService

PowerManagerService 简介:

  • PowerManagerServiceIPowerManager.Stub 类派生,并实现了 Watchdog.MonitorLocalPowerManager 接口;

  • 客户端使用 PowerManager 类,其内部通过代表 BinderProxy 端的 mService 成员变量与 PowerManagerService 进行 Binder 通信;

  • PowerManagerServiceBatteryServiceBatteryStatsServiceLightServiceSensorManagerActivityManagerServiceWindowManagerService 等许多系统服务均有交互;

PowerManagerService 的创建:

  • PowerManagerServiceSystemServerServerThread 线程中创建;

  • 调用构造方法:

    1. 获取当前进程的 uid 和 pid;

    2. 调用 Power.setLastUserActivityTimeout() 设置超时为一周,Power 类封装了同 Linux 内核交互的接口;

    3. 初始化 mUserStatemPowerState 变量为 0

    4. 调用 Watchdog.getInstance().addMonitor() 将自己添加到 Watchdog 监控队列;

  • 调用 PowerManagerService.init():

    1. 获取 LightsServiceActivityManagerServiceBatteryService(查询电池状态及电量)、BatteryStatsService(统计耗电量)四个对象;

    2. 调用 nativeInit() 函数,创建全局引用对象 gPowerManagerServiceObj

    3. 创建两个 HandlerThread 类型的工作线程 mScreenOffThread(控制屏幕关闭时的亮度来调节)和 mHandlerThread(主要工作线程):

      1. 创建 UnsynchronizedWakeLock 对象,保证工作中不至于突然掉电;

      2. 创建广播通知的 Intent,用于通知 SCREEN_ONSCREEN_OFF 消息;

      3. 获取配置参数,有的是编译时确定的,有的是 Settings 数据库维护的;

      4. 创建 ContentQueryMap 对象,用于查询 Settings 数据库,并创建 SettingsObserver 监视其变化;

      5. 注册接收通知的 BoroadcastReceiver

      6. 添加 ContentObserver 监视 Settings 数据库中 secure 表的变化;

    4.调用 updateNativePowerStateLocked() 更新 Native 层的电源状态;

    5.调用 forceUserActivityLocked() 强制触发 UserActivity,它意味着手机将被唤醒,且屏幕超时时间也将重新计算;

  • 调用 PowerManagerService.systemReady():

    1. 创建 SensorManager 对象,用于和传感器交互;

    2. 调用 setPowerState() 设置电源状态;判断是否启用 LightSensor

    3. 调用 BatteryStatsServicenoteScreenBrightness()noteScreenOn() 方法;

  • 处理 ACTION_BOOT_COMPLETED 广播:

    1. 再次调用 userActivity() 触发 UserActivity 事件;

    2. 如果处于 USB 充电状态,调用 WakeLockacquire() 方法保持唤醒,否则调用 release() 进入休眠;

WakeLock:

  • newWakeLock()

    1. 创建 PowerManager.WakeLock 对象.通过传入的 flags 参数控制 CPU 、屏幕、键盘的休眠状态;

    2. 创建 Binder 对象,除了作为 Token,也用于 PowerManagerService 监听客户端的生死;

  • acquire(),实际调用 PowerManagerService.acquireWakeLock() 方法:

    1. 读取 Binder 调用方 uid 和 pid;

    2. 检查 Manifest 中的 WAKE_LOCK 权限;如果传入的 WorkSource 参数不为空,检查是否有 UPDATE_DEVICE_STATS 权限;

    3. 创建 PowerManagerService.WakeLock 对象,它实现了 IBinder.DeathRecipient 接口,用于接收 Binder 死亡通知;

    4. 将客户端传入的 flags 转换为 minState 成员变量,将当前 WakeLock 加入到 mLocks

    5. 判断 flags 是否和屏幕有关,更新引用计数,调用 gatherSate() 统计当前活跃的 WakeLockminState(进行或运算);

    6. 调用 setPowerState(mWakeLockState|mUserState)

      1. 内部通过 Power 类(android_os_Power.cpp)、LightService(com_android_server_LightService.cpp)与内核和底层硬件交互;

      2. mWakeLockState 参数来源于当前活跃的 WakeLockminState,而 mUserState 表示用户触发事件导致的电源状态;

      3. 检查是否否打开 Proximity 传感器(不需要点亮屏幕),是否电量低,是否未启动完成(需要全亮);

      4. 根据 mStillNeedSleepNotification 判断是否调用 sendNotificationLocked(),该方法用于触发 SCREEN_ON/SCREEN_OFF 广播;

      5. PowerManagerService 还提供了一个 preventScreenOn() 方法用于切换页面时阻止屏幕点亮(比如启动 Activity 时突然来电);

      6. 根据 reallyTurnScreenOn 判断是否需要点亮屏幕,并通知 BatteryStatsService 做电量统计;

      7. 更新键盘灯和按键灯状态;

      8. 当 WakeLock 标志和 PARTIAL_WAKE_LOCK (只有 CPU 唤醒) 有关时,仅简单调用 Power.acquireWakeLock()

BatteryService初始化:

  1. 创建 Led 对象,用于控制提示灯;获取 BatteryStatsService 对象;

  2. 读取三个阈值:mCriticalBatteryLevel(电量低于该值会关机)、mLowBatteryWarningLevel(电量低于该值会警告)、mLowBatteryCloseWarningLevel(电量高于该值停止提示);

  3. 启动 mPowerSupplyOberver,监听 power_supply 信息;

  4. 如果 /sys/devices/virtual/switch/invalid_charger/state 文件存在,启动 mInvalidChargerObserver

  5. 调用 update() 查询 HAL 层电池信息:

    1. 通过 JNI 设置 Java 层的 temp 文件路径等变量;

    2. 通过文件读取电池温度、电压、电量等信息,并通过 JNI 写入 Java 层;

    3. 调用 BatteryStatsService.setBatteryState() 设置电池状态;

    4. 如果电量不够或电池过热,弹窗提示;

    5.记录信息到日志文件;发送低电广播(如果需要);更新 LED 灯状态;

BatteryStatsService:

  • 与其他系统服务不同,BatteryStatsService 是在 ActivityManagerService 中创建和注册的:

    1. 创建 BatteryStatsService 对象;

    2. 调用 BatteryStatsService.getActiveStatistics().readLocked()BatteryStatsService.getActiveStatistics().writeAsyncLocked() 操作日志文件;

    3. 调用 BatteryStatsService.getActiveStatistics().setCallback() 设置回调,该回调也用于信息统计;

    4. 调用 BatteryStatsService.publish() 注册到 ServiceManager,并从 /frameworks/base/core/res/res/xml/power_profile.xml 文件读取相关参数,该文件定义了和硬件相关的各种操作的耗电情况(以 mA.h 为单位);

  • BatteryStatsService 内部通过成员变量 mStats 指向其子类 BatteryStatsImpl 对象,它实现了 Parcelable 接口;

  • getStatistics() 方法:

    1. 检查调用进程是否有 BATTERY_STATS 权限;

    2. BatteryStatsImpl 信息写入 Parcel 包,序列化为一个 buffer,通过 Binder 传递;

  • BatteryStatus.Uid 家族:

    1. 在 Android 4.0 中,和进程相关的用电统计并非以 pid 划分,而是 uid;

    2. Wakelock 用于统计该 Uid 对应进程使用 WakeLock 的用电情况;

    3. Proc 用于统计 Uid 中某个进程的用电情况;

    4. Pkg 用于统计某个特定 Package 用电情况,其内部类 Serv 用于统计该 Package 下 Service 用电情况;

    5. Sensor 用于统计传感器用电情况;

BatteryStatsImpl:

  • BatteryStatsImpl 实现了 StopwatchTimerSamplingTimerCounterSamplingCounter 等用于电量统计的测量工具类;

  • BatteryStatsImpl 还定义了一个 Unpluggable 接口用于统计电量,比如 USB 连接时调用 plug(),断开时调用 unplug()

  • 构造方法:

    1. 创建 JournaledFile 日志文件对象,内部包含原始文件和临时文件,双备份防止读写过程中信息丢失或出错;

    2. 创建 Handler 对象和 StopwatchTimerCounter 等对象;

    3. 调用 initTimes() 初始化统计时间,注意系统时间分为 uptime 和 realtime,二者都从系统启动开始算,但 uptime 不包括休眠时间;

    4. 调用 initDischarge() 初始化和电池 level 相关的变量;

    5. 调用 clearHistoryLocked() 删除用电统计历史记录;

  • setBatteryState():

    1. 判断是否为电池供电状态是否变化,如果变化(USB 插拔),调用 setOnBatteryLocked()

    2. 如果供电状态未变化,判断电池信息是否变化(电量电压等),如果变化则调用 addHistoryRecordLocked() 添加一次历史记录;

  • setOnBatteryLocked():

    1. 发送消息给 Handler,将在内部调用 ActivityManagerService 设置的回调函数;

    2. 如果是电池供电,在满足条件的情况下会清空电量统计数据;

    3. 读取 /proc/wakelock 文件;

    4. 调用 addHistoryRecordLocked() 添加一次历史记录;

    5. 记录时间和电量;

  • noteScrrenOnLocked():

    1. 调用 addHistoryRecordLocked() 添加一次历史记录;

    2. 启动 StopwatchTimer

    3. 调用 noteStartWakeLocked() 更新 WakeLock 用电统计;

    4. 调用 updateDischargeScreenLevelLocked() 更新电池 Level;

  • noteUserActivity():

    1. 调用 getUidStatsLocked() 获得 Uid 对象,并调用其 noteUserActivityLocked();

    2. 内部定义了一个七元 Counter 数组 mUserActivityCounters,对应其中不同的事件类型;

    3. 调用对应 type 的 Counter.stepAtomic() 使计数器加一;

StopwatchTimer:

  • 构造方法会传入一个 ArrayList<Unpluggable> 类型的 mUnpluggables 参数;

  • 调用 startRunningLocked() 开始统计,主要是读取电池总的使用时间、计数控制;

  • 调用 stopRunningLocked() 结束统计,主要是统计此次启动/停止周期的时间、计数控制;


参考:

《深入理解 Android: 卷 II》