系统电源管理简介
Android电源管理概述
电源管理(PowerManager)在任何设备中都是最重要的组成部分之一,良好的电源管理方案可以达到节能、延长电池寿命、降低辐射、降温等目的。
移动设备的电量主要有两种元件消耗:CPU和显示屏。设法降低这两种元件的耗电量就是电源管理的关键。为移动设备设计的CPU大都有两种工作频率,为了省电,大部分时间CPU都工作在较低的频率下,只有进行密集计算时,如视频解码,才会切换到高频状态。而显示屏省电的方法是尽量减少亮屏的时间,但是显示屏的开关和应用有很大的关系,因此,系统需要有一套机制来控制显示屏的开关和亮度,这是电源管理模块的主要工作之一。
Android电源管理组织架构
Android的电源管理主要是通过锁和定时器来切换系统的状态,使系统的功耗降至最低,整个系统的框架可以分为四个层次,分别是应用程序层、Framework层、硬件抽象层(HAL)和内核层。Android电源管理框架如图1-1所示。
l 应用层:这里所谓的应用层主要是指应用程序和其他使用电源管理的Service,包括但不限于以下Services: PowerManagerService、BatteryService、LightService等。
l 框架层:在Android框架层包含了对应用层接口的API调用以及电源的协调工作,主要包含PowerManager.
Java、PowerManagerService.java、com_android_server_PowerManagerService.cpp、Power.java、android_os_Power.cpp。其中PowerManagerService.java是核心,Power.java提供底层的函数接口,与JNI层进行交互。PowerManager.java是提供给应用层调用的。android_os_power.cpp是jni交互文件。这一层的功能相对比较复杂,比如系统状态的切换,背光的调节及开关,Wake
Lock的申请和释放等等,但这一层跟硬件平台无关。
l HAL层:该层只有一个Power.c文件,该文件通过sysfs的方式与kernel进行通信。主要功能有申请wake_lock,释放wake_lock,设置屏幕状态等。用户空间的
native库绝不能直接调用Android电源管理(见下图)。绕过Android运行时的电源管理政策,将破坏该系统。所有对电源管理的调用应通过Android的PowerManagerAPI来完成。
l Kernel层:内核层的电源管理方案实现主要包含三部分:
1、Kernelpower:实现了系统电源管理框架机制。
2、Archarm(ormips or powerpc)mach-XXXpm.c:实现对特定板的处理器电源管理。
3、driverspower:是设备电源管理的基础框架,为驱动提供了电源管理接口。
图1-1 Android电源管理框架图
系统正常开机后,Brightness的亮度会设置成用户设定的亮度,系统Screen off timer开始计时,在计时时间到之前,如果有任何的userActivity事件发生,比如Touch click等事件,则将重新设置screen off timer,系统保持在Awake状态。如果应用程序在这段时间申请了Full wakelock,系统也将保持在Awake状态。在没有交互的情况下,首先进入到Awake状态,之后进入Dozing状态,最后进入Asleep状态。
电源管理服务--PowerManagerService
PowerManagerService是Android电源管理的核心服务,主要功能是控制系统的待机状态,控制显示屏的开关和亮度调节,以及查询和控制光线传感器和距离传感器等。PowerManagerService的启动流程如下图2-1所示。
图2-1PowerManagerService启动流程
初始化过程
PowerManagerService也是在SystemServer中创建并加入到ServiceManager中的,代码如下:
[java] view
plain copy
-
mPowerManagerService = mSystemServiceManager.startService(
-
PowerManagerService.class);
调用SystemServiceManager的startService方法创建PowerManagerService对象并注册到ServiceManager中。PowerManagerService的构造方法代码如下:
[java] view
plain copy
-
public PowerManagerService(Context context) {
-
super(context);
-
mContext = context;
-
-
mHandlerThread = new ServiceThread(TAG,
-
Process.THREAD_PRIORITY_DISPLAY, false);
-
mHandlerThread.start();
-
mHandler = new PowerManagerHandler(mHandlerThread.getLooper());
-
-
synchronized (mLock) {
-
mWakeLockSuspendBlocker =createSuspendBlockerLocked("PowerManagerService.WakeLocks");
-
mDisplaySuspendBlocker =createSuspendBlockerLocked("PowerManagerService.Display");
-
mDisplaySuspendBlocker.acquire();
-
mHoldingDisplaySuspendBlocker = true;
-
mHalAutoSuspendModeEnabled = false;
-
mHalInteractiveModeEnabled = true;
-
-
mWakefulness = WAKEFULNESS_AWAKE;
-
-
nativeInit();
-
nativeSetAutoSuspend(false);
-
nativeSetInteractive(true);
-
}
-
}
PowerManagerService的构造方法中首先创建了处理消息的线程和发送消息的PowerManagerHandler对象,接着创建了mWakeLockSuspendBlocker对象、mDisplaySuspendBlocker对象。
变量mWakefulness的值被设置成WAKEFULNESS_AWAKE,它用来标示PowerManagerService的状态,一共有四种定义:
l WAKEFULNESS_ASLEEP:表示系统当前处于休眠状态,只能被wakeUp()调用唤醒。
l WAKEFULNESS_AWAKE:表示系统目前处于正常运行状态。
l WAKEFULNESS_DREAMING:表示系统当前正处于播放屏保的状态。
l WAKEFULNESS_DOZING:表示系统正处于“doze”状态。这种状态下只有低耗电的“屏保”可以运行,其他应用进程都被挂起。
最后,构造方法调用了nativeInit()方法,主要工作就是装载”Power”模块,之后调用模块的初始化函数init()。
系统准备工作—SystemReady方法
SystemServer创建PowerManagerService后,还会调用它的SystemReady()方法,相当于在系统准备就绪后对PowerManagerService再进行一些初始化工作。SystemReady()方法代码如下:
[java] view
plain copy
-
public void systemReady(IAppOpsService appOps) {
-
synchronized (mLock) {
-
mSystemReady = true;
-
mAppOps = appOps;
-
mDreamManager =getLocalService(DreamManagerInternal.class);
-
mDisplayManagerInternal =getLocalService(DisplayManagerInternal.class);
-
mPolicy = getLocalService(WindowManagerPolicy.class);
-
mBatteryManagerInternal =getLocalService(BatteryManagerInternal.class);
-
-
-
。。。。。。
-
-
SensorManager sensorManager = new SystemSensorManager(mContext, mHandler.getLooper());
-
-
mBatteryStats = BatteryStatsService.getService();
-
mNotifier = new Notifier(Looper.getMainLooper(), mContext, mBatteryStats,
-
mAppOps,createSuspendBlockerLocked("PowerManagerService.Broadcasts"),
-
mPolicy);
-
-
mWirelessChargerDetector = new WirelessChargerDetector(sensorManager,
-
createSuspendBlockerLocked("PowerManagerService.WirelessChargerDetector"),
-
mHandler);
-
mSettingsObserver = new SettingsObserver(mHandler);
-
-
mLightsManager = getLocalService(LightsManager.class);
-
mAttentionLight =mLightsManager.getLight(LightsManager.LIGHT_ID_ATTENTION);
-
-
-
mDisplayManagerInternal.initPowerManagement(
-
mDisplayPowerCallbacks,mHandler, sensorManager);
-
-
。。。。。。
-
。。。。。。
-
-
readConfigurationLocked();
-
updateSettingsLocked();
-
mDirty |= DIRTY_BATTERY_STATE;
-
updatePowerStateLocked();
-
}
-
}
systemReady()方法中通过调用getLocalService()方法得到一些在SystemServer中运行的内部服务的对象。在systemservice中也创建了一些内部使用的服务,这些服务没有通过ServiceManager发布,而是通过内部的LocalService类来管理。这些内部服务的共同特征是从SystemService类派生,通过getLocalService()方法可以获得参数关联的内部服务对象。
systemReady()方法完成的主要工作如下:
l 获取最小、最大、默认3种屏幕亮度。
l 创建SystemSensorManager对象,用于和SensorService交互。
l 创建Notifer对象。用于广播系统中和Power相关的变化。
l 创建WirelessChargerDetector对象,用于无线充电检测的传感器。
l 调用DisplayManagerService的initPowerManagement()方法来初始化Power管理模块。
l 注册Observer监听系统设置的变化。
l 监听其他模块广播的Intent。PowerManagerService需要关注系统的变化,这里注册了很多系统广播的接收器。包括系统启动完成、“屏保”启动和关闭、用户切换、Dock插拔等。
报告用户活动—userActivity接口
PowerManager是PowerManagerService的代理类,它提供了一些接口让用户进程可以和PowerManagerService交互,下面分析一些接口来进一步了解PowerManagerService的工作。
userActivity()接口用于用户进程向PowerManagerService报告
用户影响系统休眠的活动。例如,用户点击屏幕时,系统会调用该方法来告诉PowerManagerService用户点击的时间,这样PowerManagerService将更新内部保存的时间值,从而推迟系统休眠的时间。userActivity()方法主要通过调用内部的userActivityInternal()方法来完成工作,userActivity流程图如图2-2所示:
图2-2 userActivity流程图
具体代码如下:
[java] view plain copy - private void userActivityInternal(long eventTime, int event, int flags, int uid) {
- synchronized (mLock) {
- if (userActivityNoUpdateLocked(eventTime, event, flags, uid)) {
- updatePowerStateLocked();
- }
- }
- }
userActivityInternal()先调用了userActivityNoUpdateLocked()方法,然后再调用updatePowerStateLocked()方法。userActivityNoUpdateLocked()方法只是把参数保存到内部变量中,并不会采取任何动作,而PowerManagerService中核心的方法是updatePowerStateLocked()。我们先看下userActivityNoUpdateLocked()方法:
[java] view
plain copy
-
private boolean userActivityNoUpdateLocked(longeventTime,intevent,intflags,intuid) {
-
if (eventTime< mLastSleepTime || eventTime < mLastWakeTime
-
|| !mBootCompleted ||!mSystemReady) {
-
return false;
-
}
-
-
Trace.traceBegin(Trace.TRACE_TAG_POWER, "userActivity");
-
try {
-
if (eventTime> mLastInteractivePowerHintTime) {
-
powerHintInternal(POWER_HINT_INTERACTION, 0);