系统电源管理简介
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中的,代码如下:
mPowerManagerService = mSystemServiceManager.startService(
PowerManagerService.class);
调用SystemServiceManager的startService方法创建PowerManagerService对象并注册到ServiceManager中。PowerManagerService的构造方法代码如下:
public PowerManagerService(Context context) {
super(context);
mContext = context;
//创建处理消息的线程和Handler对象
mHandlerThread = new ServiceThread(TAG,
Process.THREAD_PRIORITY_DISPLAY, false/*allowIo*/);
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;//设置PowerManagerService的状态
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()方法代码如下:
public void systemReady(IAppOpsService appOps) {
synchronized (mLock) {
mSystemReady = true;
mAppOps = appOps;
mDreamManager =getLocalService(DreamManagerInternal.class);//获取DreamManagerService对象
mDisplayManagerInternal =getLocalService(DisplayManagerInternal.class);//DisplayManagerService
mPolicy = getLocalService(WindowManagerPolicy.class);//WindowManagerPolicy
mBatteryManagerInternal =getLocalService(BatteryManagerInternal.class);//BatteryService
//获取最小、最大、默认屏幕亮度
。。。。。。
//创建SensorManager对象,用于和SensorService交互
SensorManager sensorManager = new SystemSensorManager(mContext, mHandler.getLooper());
mBatteryStats = BatteryStatsService.getService();//获得BatteryStatsService的引用对象
mNotifier = new Notifier(Looper.getMainLooper(), mContext, mBatteryStats,
mAppOps,createSuspendBlockerLocked("PowerManagerService.Broadcasts"),
mPolicy);//创建Notifier对象
mWirelessChargerDetector = new WirelessChargerDetector(sensorManager,
createSuspendBlockerLocked("PowerManagerService.WirelessChargerDetector"),
mHandler);//创建检测无线充电的对象WirelessChargerDetector
mSettingsObserver = new SettingsObserver(mHandler);//创建监听系统设置项变化的对象
mLightsManager = getLocalService(LightsManager.class);//LightsManager对象
mAttentionLight =mLightsManager.getLight(LightsManager.LIGHT_ID_ATTENTION);
//初始化Power的管理模块
mDisplayManagerInternal.initPowerManagement(
mDisplayPowerCallbacks,mHandler, sensorManager);
。。。。。。 //注册广播接收器
。。。。。。//注册监听更多的settngs项的变化
// Go.
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流程图
具体代码如下:
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()方法:
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);//powerHintInternal是通过JNI调用底层函数,将cpu频率提高等等
mLastInteractivePowerHintTime= eventTime;//记录时间
}
mNotifier.onUserActivity(event,uid);//发出通知
if (mWakefulness== WAKEFULNESS_ASLEEP
|| mWakefulness ==WAKEFULNESS_DOZING
|| (flags &PowerManager.USER_ACTIVITY_FLAG_INDIRECT) != 0) {
return false;
}//如果系统处于休眠或doze模式,返回
if ((flags& PowerManager.USER_ACTIVITY_FLAG_NO_CHANGE_LIGHTS) !=0){
if (eventTime> mLastUserActivityTimeNoChangeLights
&& eventTime> mLastUserActivityTime) {
mLastUserActivityTimeNoChangeLights = eventTime;//记录时间
mDirty |=DIRTY_USER_ACTIVITY;
return true;
}
} else {
if (eventTime> mLastUserActivityTime) {
mLastUserActivityTime =eventTime;//记录时间
mDirty |=DIRTY_USER_ACTIVITY;
return true;
}
}
} finally {
Trace.traceEnd(Trace.TRACE_TAG_POWER);
}
return false;
}
userActivityNoUpdateLocked()方法主要的工作是更新几个内部变量。其中mLastUserActivityTime变量和mLastUserActivityTimeNoChangeLights变量用来记录调用userActivity()方法的时间,mDirty用来记录用户的操作类型,这些变量的值在updatePowerStateLocked()方法中将会作为是否要执行
睡眠或唤醒操作的依据。
强制系统进入休眠模式—gotoSleep接口
gotoSleep()接口用来强制系统进入休眠模式。通常当系统一段时间无人操作后,系统将调用gotoSleep()接口来进入休眠模式。大体流程如下:
图2-3 gotoSleep流程
PowerManagerService的gotoSleep()接口主要是调用内部方法goToSleepInternal()来完成其功能。如下:
private void goToSleepInternal(
longeventTime,
intreason,
int
flags,
intuid) {
synchronized (mLock) {
if (goToSleepNoUpdateLocked(eventTime,reason, flags, uid)) {
updatePowerStateLocked();
}
}
}
goToSleepInternal()代码的结构和前面的userActivity类似,都是先调用一个内部方法,然后再调用updatePowerStateLocked()方法,我们先看下goToSleepNoUpdateLocked()方法,如下:
private boolean goToSleepNoUpdateLocked(
longeventTime,
intreason,
intflags,
intuid)
{
try {
switch (reason){
case PowerManager.GO_TO_SLEEP_REASON_DEVICE_ADMIN:
Slog.i(TAG,
"Going to sleep due to deviceadministration policy "
+
"(uid "+ uid +
")...");
break;
case PowerManager.GO_TO_SLEEP_REASON_TIMEOUT:
Slog.i(TAG,
"Going to sleep due to screen timeout(uid "+ uid +
")...");
break;
case PowerManager.GO_TO_SLEEP_REASON_LID_SWITCH:
Slog.i(TAG,
"Going to sleep due to lid switch (uid"+ uid +
")...");
break;
case PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON:
Slog.i(TAG,
"Going to sleep due to power button (uid"+ uid +
")...");
break;
case PowerManager.GO_TO_SLEEP_REASON_HDMI:
Slog.i(TAG,
"Going to sleep due to HDMI standby (uid"+ uid +
")...");
break;
default:
Slog.i(TAG,
"Going to sleep by application request(uid "+ uid +
")...");
reason =PowerManager.GO_TO_SLEEP_REASON_APPLICATION;
break;
}
//修改成员变量的值
mLastSleepTime = eventTime;
mSandmanSummoned =
true;
setWakefulnessLocked(WAKEFULNESS_DOZING, reason);
//设置mWakefulness的值
// Report the number of wake locks that will be clearedby going to sleep.
int numWakeLocksCleared=
0;
final int numWakeLocks= mWakeLocks.size();
for (
inti =
0; i < numWakeLocks; i++) {
final WakeLockwakeLock = mWakeLocks.get(i);
switch (wakeLock.mFlags& PowerManager.WAKE_LOCK_LEVEL_MASK) {
case PowerManager.FULL_WAKE_LOCK:
case PowerManager.SCREEN_BRIGHT_WAKE_LOCK:
case PowerManager.SCREEN_DIM_WAKE_LOCK:
numWakeLocksCleared+=
1;
break;
}
}
EventLog.writeEvent(EventLogTags.POWER_SLEEP_REQUESTED,numWakeLocksCleared);//打印Eventlog
// Skip dozing if requested.
if ((flags& PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE) !=
0) {
reallyGoToSleepNoUpdateLocked(eventTime, uid);
}
}
finally {
Trace.traceEnd(Trace.TRACE_TAG_POWER);
}
return true;
}
goToSleepNoUpdateLocked()只是发送了将要休眠的通知,然后修改了成员变量mDirty、mLastSleepTime、mWakefulness的值。更多的实际工作还是在updatePowerStateLocked()方法中完成。
三、控制系统的休眠机制
Android设备的休眠和唤醒主要基于WakeLock机制。WakeLock是一种上锁机制,只要有进程获得了WakeLock锁系统就不会进入休眠。例如,在下载文件或播放音乐时,即使休眠时间到了,系统也不能进行休眠。WakeLock可以设置超时,超时后会自动解锁。
应用使用WakeLock功能前,需要先使用new WakeLock()接口创建一个WakeLock类对象,然后调用它的acquire()方法禁止系统休眠,应用完成工作后调用release()方法来恢复休眠机制,否则系统将无法休眠,直到耗光所有电量。
WakeLock类中实现acquire()和release()方法实际上是调用了PowerManagerService的acquireWakeLock()和releaseWakeLock()方法。
1、PMS中WakeLock相关接口
acquireWakeLock()方法检查完权限后,调用了内部方法acquireWakeLockInternal()方法,如下:
private void acquireWakeLockInternal(IBinder lock,
intflags, String tag, String packageName,
WorkSource ws, String historyTag,
int
uid,
int pid) {
synchronized (mLock) {
if(mBlockedUids.contains(
newInteger(uid)) && uid != Process.myUid()) {
WakeLock wakeLock;
int index= findWakeLockIndexLocked(lock);
//检查这个lock是否已经存在
boolean notifyAcquire;
if (index>=
0){
//lock已经存在
wakeLock = mWakeLocks.get(index);
if (!wakeLock.hasSameProperties(flags,tag, ws, uid, pid)) {
notifyWakeLockChangingLocked(wakeLock, flags, tag,packageName,
uid, pid, ws,historyTag);
wakeLock.updateProperties(flags, tag, packageName, ws, historyTag, uid,pid);
}
notifyAcquire =
false;
}
else {
wakeLock =
new WakeLock(lock, flags, tag, packageName, ws, historyTag,uid, pid);
try {
lock.linkToDeath(wakeLock,
0);
}
catch (RemoteExceptionex) {
throw new IllegalArgumentException(
"Wake lock is already dead.");
}
mWakeLocks.add(wakeLock);
//将新建的WakeLock对象加入到mWakeLocks中
notifyAcquire =
true;
}
applyWakeLockFlagsOnAcquireLocked(wakeLock, uid);
mDirty |= DIRTY_WAKE_LOCKS;
updatePowerStateLocked();
if (notifyAcquire){
notifyWakeLockAcquiredLocked(wakeLock);
}
}
}
acquireWakeLockInternal()方法的主要工作是创建WakeLock对象并加入到mWakeLocks列表中,这个列表中包含了所有WakeLock对象。但是如果mWakeLocks列表中已经存在具有相同token的WakeLock对象,则只更新其属性值,不会再创建对象,这个token是用户进程调用gotoSleep时传递的参数:用户进程中WakeLock对象。创建或更新WakeLock对象后,接下来调用applyWakeLockFlagsOnAcquireLocked()方法,这个方法只是调用了wakeUpNoUpdateLocked方法,如下:
private boolean wakeUpNoUpdateLocked(
longeventTime,
intuid) {
if
(YulongFeature.FEATURE_POWERKEY_FORCE_SCREENON) {
if (eventTime< mLastSleepTime
|| (mWakefulness ==WAKEFULNESS_AWAKE && mProximityPositive !=
true)
|| !mBootCompleted ||!mSystemReady) {
return false;
}
}
else {
if (eventTime < mLastSleepTime || mWakefulness ==WAKEFULNESS_AWAKE
|| !mBootCompleted ||!mSystemReady) {
return false;
}
}
if
(YulongFeature.FEATURE_POWERKEY_FORCE_SCREENON) {
if (mProximityPositive==
true) {
mDisplayManagerInternal.setPowerKeyState(
1);
}
}
Trace.traceBegin(Trace.TRACE_TAG_POWER,
"wakeUp");
try {
switch (mWakefulness){
case WAKEFULNESS_ASLEEP:
Slog.i(TAG,
"Waking up from sleep (uid "+ uid +
")...");
break;
case WAKEFULNESS_DREAMING:
Slog.i(TAG,
"Waking up from dream (uid "+ uid +
")...");
break;
case WAKEFULNESS_DOZING:
Slog.i(TAG,
"Waking up from dozing (uid "+ uid +
")...");
break;
}
mLastWakeTime = eventTime;
setWakefulnessLocked(WAKEFULNESS_AWAKE,
0);
userActivityNoUpdateLocked(
eventTime,PowerManager.USER_ACTIVITY_EVENT_OTHER,
0,uid);
}
finally {
Trace.traceEnd(Trace.TRACE_TAG_POWER);
}
return true;
}
在这个方法中主要是设置mLastWakeTime、mWakefulness,最后调用userActivityNoUpdateLocked方法设置mLastUserActivityTime的值。我们将acquireWakeLock()方法的流程图简单概括如下:
图3-1 acquireWakeLock流程图
我们再看下PMS的releaseWakeLock()接口,这个接口也是调用PMS的releaseWakeLockInternal()方法,如下:
private void releaseWakeLockInternal(IBinder lock,
intflags) {
synchronized (mLock) {
int index= findWakeLockIndexLocked(lock);
if (index<
0){
return;
}
if ((flags& PowerManager.RELEASE_FLAG_WAIT_FOR_NO_PROXIMITY) !=
0){
mRequestWaitForNegativeProximity =
true;
}
wakeLock.mLock.unlinkToDeath(wakeLock,
0);
removeWakeLockLocked(wakeLock,index);
}
}
releaseWakeLockInternal()方法首先查找lock在mWakeLocks中的index,然后从mWakeLocks中得到WakeLock对象,最后调用removeWakeLockLocked方法,如下:
private void removeWakeLockLocked(WakeLock wakeLock,
intindex) {
mWakeLocks.remove(index);
notifyWakeLockReleasedLocked(wakeLock);
applyWakeLockFlagsOnReleaseLocked(wakeLock);
mDirty |= DIRTY_WAKE_LOCKS;
updatePowerStateLocked();
}
removeWakeLockLocked方法首先从mWakeLocks中移除WakeLock对象并发出通知,接着调用applyWakeLockFlagsOnReleaseLocked(),这个方法中只是调用userActivityNoUpdateLocked()方法来把mLastUserActivityTime更新为当前时间,这样当休眠时间到时,系统就会休眠。
2、WakeLock的native层实现
我们先回到PowerManagerService的构造方法中,看看是如何创建两个变量mWakeLockSuspendBlocker和mDisplaySuspendBlocker的。
mWakeLockSuspendBlocker= createSuspendBlockerLocked(
"PowerManagerService.WakeLocks");
mDisplaySuspendBlocker = createSuspendBlockerLocked(
"PowerManagerService.Display");
从代码中可以看出这两个变量都是调用createSuspendBlocker()方法创建的,只是参数不同,一个是PowerManagerService.WakeLocks,一个是PowerManagerService.Display;方法代码如下:
private SuspendBlocker createSuspendBlockerLocked(String name) {
SuspendBlocker suspendBlocker =
new SuspendBlockerImpl(name);
mSuspendBlockers.add(suspendBlocker);
return suspendBlocker;
}
createSuspendBlockerLocked()方法创建了一个SuspendBlockerImpl对象并返回,因此mWakeLockSuspendBlocker和mDisplaySuspendBlocker变量的类型应该是SuspendBlockerImpl。我们看下它的acquire()和release()方法,流程图如下所示。
图3-2 acruire()方法流程图
详细代码如下:
public void acquire() {
synchronized (
this) {
mReferenceCount+= 1;
if (mReferenceCount ==
1) {
Trace.asyncTraceBegin(Trace.TRACE_TAG_POWER, mTraceName,
0);
nativeAcquireSuspendBlocker(mName);
}
}
}
@Override
public void release() {
synchronized (
this) {
mReferenceCount-= 1;
if (mReferenceCount ==
0) {
nativeReleaseSuspendBlocker(mName);
Trace.asyncTraceEnd(Trace.TRACE_TAG_POWER, mTraceName,
0);
}
else if (mReferenceCount <
0) {
mReferenceCount =
0;
}
}
}
SuspendBlockerImpl类中维护了一个计数器,调用acquire()方法时计数器加1,当计数器的值为1时,调用nativeAcquireSuspendBlocker()方法。调用release()方法时计数器减1,当计数器的值为0时,调用nativeReleaseSuspendBlocked()方法。
调用的native层的函数中又分别调用了acquire_wake_lock()函数和release_wake_lock()函数,其实现如下:
从上面两个函数的实现可以看到,都是通过向不同的驱动文件中写数据来实现其功能。这里写的数据就是前面构造方法中创建变量时传递的参数“PowerManagerService.WakeLocks”和“PowerManagerService.Display”。那么acquire()和release()中使用的文件设备句柄是如何创建的呢?看下initialize_fds()函数,如下:
Initialize_fds()函数先打开NEW_PATHS数组中的文件,不成功再打开OLD_PATHS数组中的设备文件。
因此,Android实现防止系统休眠的功能是通过向设备文件“sys/power/wake_lock”中写数据来完成的,如果写的是“PowerManagerService.WakeLocks”,系统将不能进入休眠状态,但是屏幕会关闭;如果写的是“PowerManagerService.Display”,则屏幕不会关闭。如果系统要恢复休眠,再向设备文件“sys/power/wake_unlock”中写入同样的字符串就OK了。
3、理解updatePowerStateLocked方法
private void updatePowerStateLocked() {
if (!mSystemReady|| mDirty ==
0) {
return;
}
Trace.traceBegin(Trace.TRACE_TAG_POWER,
"updatePowerState");
try {
// Phase 0:更新基本状态
updateIsPoweredLocked(mDirty);
//更新mIsPowered、mPlugType、mBatteryLevel
updateStayOnLocked(mDirty);
//更新mStayOn
updateScreenBrightnessBoostLocked(mDirty);
// Phase 1: 更新wakefulness
// Loop because the wake lock anduser activity computations are influenced
// by changes in wakefulness.
final long now= SystemClock.uptimeMillis();
int dirtyPhase2=
0;
for (;;) {
int dirtyPhase1= mDirty;
dirtyPhase2 |= dirtyPhase1;
mDirty =
0;
updateWakeLockSummaryLocked(dirtyPhase1);
//更新mWakeLockSummary
updateUserActivitySummaryLocked(now, dirtyPhase1);
//更新mUserActivitySummary的值
if (!updateWakefulnessLocked(dirtyPhase1)){
//更新mWakefulness的值
break;
}
}
// Phase 2: Update display power state.更新显示设备状态;确定屏幕状态和亮度,并设置到DisplayPowerController对象中。
booleandisplayBecameReady= updateDisplayPowerStateLocked(dirtyPhase2);
// Phase 3: Update dream state (depends on display readysignal).
updateDreamLocked(dirtyPhase2, displayBecameReady);
//更新屏保状态,是否启动屏保
// Phase 4: Send notifications, if needed.发送通知
if(mDisplayReady){
finishWakefulnessChangeLocked();
}
// Phase 5:Update suspend blocker.
updateSuspendBlockerLocked();
}
finally {
Trace.traceEnd(Trace.TRACE_TAG_POWER);
}
}
(1)首先调用updateIsPoweredLocked()方法,这个方法主要是通过调用BatteryService的接口来更新几个成员变量的值,如下:
mIsPowered =mBatteryManagerInternal.isPowered(BatteryManager.BATTERY_PLUGGED_ANY);
mPlugType = mBatteryManagerInternal.getPlugType();
mBatteryLevel = mBatteryManagerInternal.getBatteryLevel();
mBatteryLevelLow = mBatteryManagerInternal.getBatteryLevelLow();
mIsPowered表示是否在充电,mPlugType表示充电的类型,mBatteryLevel表示当前电池电量的等级。
(2)调用updateStayOnLocked()方法来更新变量mStayOn的值,mStayOn如果为true,屏幕将保持长亮状态。在Setting中可以设置充电时屏幕长亮,如果Setting中设置了该选项,updateStayOnLocked()函数中如果检测到正在充电,会将mStayOn的值设为true。
(3)接着调用updateScreenBrightnessBoostLocked()方法,这是Android5.1新增加的方法。
DIRTY_SCREEN_BRIGHTNESS_BOOST是5.1新增加的,表示屏幕亮度提高的状态;
(4)接下来是一个无限for循环,其实这个for循环,最多两次就结束了,后面分析。我们先来看看在循环中调用的updateWakeLockSummaryLocked()方法,这个方法的主要作用是根据PowerManagerService中所有的WakeLock对象的类型,计算一个最终的类型集合,并保存在变量mWakeLockSummary中。不管系统中一共创建了多少个WakeLock对象,一个就足以阻止系统休眠,因此,这里把所有WakeLock对象的状态总结后放到一个变量中。
应用在创建WakeLock对象时,会指定对象的类型,这个类型将作为参数传递到PowerManagerService中。WakeLock类型有:
PARTIAL_WAKE_LOCK
FULL_WAKE_LOCK
SCREEN_BRIGHT_WAKE_LOCK
SCREEN_DIM_WAKE_LOCK
PROXIMITY_SCREEN_OFF_WAKE_LOCK:Android5.0新增锁,这个类型并不是用来阻止系统进入休眠,而是用来打开距离传感器控制屏幕开关的功能。如果应用持有这种类型的WakeLock,当距离传感器被遮挡时,屏幕将会关闭。
DOZE_WAKE_LOCK:Android5.0新增锁,这个类型用来让屏保管理器实现doze模式。
(5)
updateUserActivitySummaryLocked()方法,这个方法根据最后一次调用userActivity()方法的时间,计算现在是否可以将表示屏幕状态的变量mUserActivitySummary的值设为SCREEN_STATE_DIM或SCREEN_STATE_OFF。如果时间还没到,则发送一个定时消息MSG_USER_ACTIVITY_TIMEOUT。当处理消息的时间到了以后,会在消息的处理方法handleUserActivityTimeout()中重新调用updatePowerStateLocked()方法,再次调用updatePowerStateLocked方法时,会根据当前状态重新计算mUserActivitySummary的值。
(6)updateWakefulnessLocked()方法,这个方法是结束循环的关键。
如果它的返回值是true,表示PowerManagerService的状态发生了变化,将继续循环,然后重新调用前面的两个方法updateWakelockSummaryLocked()和updateUserActivitySummaryLocked()方法来更新状态。而第二次调用updateWakefulnessLocked方法时通常会返回false,跳出循环。
private boolean updateWakefulnessLocked(
intdirty) {
boolean changed =
false;
if ((dirty & (DIRTY_WAKE_LOCKS |DIRTY_USER_ACTIVITY | DIRTY_BOOT_COMPLETED
| DIRTY_WAKEFULNESS |DIRTY_STAY_ON | DIRTY_PROXIMITY_POSITIVE
| DIRTY_DOCK_STATE)) !=
0) {
if (
mWakefulness == WAKEFULNESS_AWAKE &&isItBedTimeYetLocked()) {
if (DEBUG_SPEW) {
Slog.d(TAG,
"updateWakefulnessLocked: Bedtime...");
}
final long time = SystemClock.uptimeMillis();
if (shouldNapAtBedTimeLocked()) {
changed =napNoUpdateLocked(time, Process.SYSTEM_UID);
}
else {
changed =goToSleepNoUpdateLocked(time,
PowerManager.GO_TO_SLEEP_REASON_TIMEOUT,
0, Process.SYSTEM_UID);
}
}
}
return changed;
}
updateWakefulnessLocked方法中首先判断dirty的值,如果是第一次调用,这个条件很容易满足。注意第二个if语句的判断条件,mWakefulness为WAKEFULNESS_AWAKE并且isItBedTimeYetLocked()方法返回true时才会执行,否则方法结束并返回false,返回false时就会跳出循环。
我们先假定调用的时候mWakefulness为WAKEFULNESS_AEAKE,下面看看isItBedTimeYetLocked方法什么情况下返回true。
private boolean isItBedTimeYetLocked() {
return mBootCompleted &&!isBeingKeptAwakeLocked();
}
private boolean isBeingKeptAwakeLocked() {
return mStayOn
|| mProximityPositive
|| (mWakeLockSummary &WAKE_LOCK_STAY_AWAKE) !=
0
|| (mUserActivitySummary &(USER_ACTIVITY_SCREEN_BRIGHT
|USER_ACTIVITY_SCREEN_DIM)) !=
0
|| mScreenBrightnessBoostInProgress;
}
我们看下isBeingKeptAwakeLocked()方法,如果系统目前不能睡眠,这个方法返回true,这几个变量正是前面方法中设置的判断系统是否能够睡眠的变量。
因此,isItBedTimeYetLocked方法只有在系统能够进入睡眠的情况下才会返回true。
我们回到updateWakefulnessLocked方法中,假如系统能够睡眠,接下来将调用方法shouldNapAtBedTimeLocked(),这个方法将检查系统有没有设置睡眠时间到启动屏保或者插在Dock上启动屏保。如果设置了将调用napNoUpdateLocked方法,如果没有设置则调用goToSleepnoUpdateLocked方法。我们看下napNoUpdateLocked方法:
private boolean napNoUpdateLocked(
longeventTime,
int
uid) {
if (eventTime < mLastWakeTime ||mWakefulness != WAKEFULNESS_AWAKE
|| !mBootCompleted ||!mSystemReady) {
return false;
}
Trace.traceBegin(Trace.TRACE_TAG_POWER,
"nap");
try {
mSandmanSummoned =
true;
setWakefulnessLocked(
WAKEFULNESS_DREAMING,
0);
}
finally {
Trace.traceEnd(Trace.TRACE_TAG_POWER);
}
return true;
}
private void setWakefulnessLocked(
intwakefulness,
int
reason) {
if (mWakefulness != wakefulness) {
finishWakefulnessChangeLocked();
mWakefulness = wakefulness;
mWakefulnessChanging =
true;
mDirty |= DIRTY_WAKEFULNESS;
mNotifier.onWakefulnessChangeStarted(wakefulness, reason);
}
}
从上面代码中可以看到,如果if语句中4项表达式有一项为true,则返回false。但是如果是循环中第一次调用该方法,则4项正常情况下都为false,不会执行到这里。这样就会继续向下执行,就会改变mDirty和mWakefulness的值。mWakefulness的值既然改变了,当循环中第二次调用到该方法时,就会返回false,这样就结束了updatePowerStateLocked方法中的循环。
(7)结束循环后,接着调用updateDisplayPowerStateLocked()方法。这个方法的主要作用就是根据更新后的mUserActivitySummary的值来确定屏幕的状态和亮度,并设置到DisplayPowerController对象中。
(8)updateDreamLocked()方法,用来启动屏保。
(9)updateSuspendBlockerLocked()方法。来决定系统是休眠还是唤醒。
4、管理显示设备
在更新电源状态的updatePowerStateLocked()方法中,我们看到调用了updateDisplayPowerStateLocked()方法,该方法的主要作用就是更新PowerManagerService中表示显示屏状态的变量mDisplayPowerRequest,以及重新确定屏幕的亮度。注意在这个方法的结尾处调用了mDisplayPowerController的requestPowerState()方法,这个方法的返回值会赋值给mDisplayReady,如果
mDisplayReady为false,屏幕是不会关闭的。
这里我们先看下requestPowerState()方法是怎样被调用的,流程图如下:
图3-4 显示控制流程
具体代码如下:
public boolean requestPowerState(DisplayPowerRequest request,
boolean waitForNegativeProximity) {
synchronized (mLock) {
boolean changed =
false;
//如果和近距离传感器相关的变量发生变化,则将change设为true
if (waitForNegativeProximity
&&!mPendingWaitForNegativeProximityLocked) {
mPendingWaitForNegativeProximityLocked =
true;
changed =
true;
}
//使用参数更新mPendingRequestLocked对象,如果两者不相同,则将change设为true if(mPendingRequestLocked ==
null) {
mPendingRequestLocked =
new DisplayPowerRequest(request);
changed =
true;
}
else {
if (!mPendingRequestLocked.equals(request)) {
mPendingRequestLocked.copyFrom(request);
changed =
true;
}
}
if(changed) {
//如果chenge为true,将mDisplayReadyLocked设为false
mDisplayReadyLocked =
false;
}
if (changed &&!mPendingRequestChangedLocked) {
mPendingRequestChangedLocked=
true;
sendUpdatePowerStateLocked();
//发送消息
}
return mDisplayReadyLocked;
//返回mDisplayReadyLocked
}
}
从上面代码中可以看到,requestPowerState()方法会将参数request和waitForNegativeProximity与DisplayPowerController对象中已有的值比较,如果不同,则更新DisplayPowerController对象中的值,然后返回mDisplayReadyLocked的值,此时为false。这就意味着,如果屏幕状态发生了变化,即使这种变化是要求关闭屏幕,也不会在updateSyspendBlockerLocked()方法中立即关闭屏幕,那么这个关闭屏幕的操作在什么地方呢?
在requestPowerState()方法中最后会调用sendUpdatePowerStateLocked()方法,发送MSG_UPDATE_POWER_STATE消息,消息的处理方法是updatePowerStateLocked(),这个方法的主要作用是开始播放各种打开或关闭屏幕的动画,或者屏幕变亮或变暗的动画,之后才会将mDisplayReadyLocked设为true,这样屏幕就能关闭了。
private void updatePowerState() {
// 。。。。。。播放动画
// Notify the power manager when ready.
if (ready && mustNotify) {
// Send state change.
synchronized (mLock) {
if (!mPendingRequestChangedLocked) {
mDisplayReadyLocked = true;//将mDisplayReadyLocked设为true
}
}
sendOnStateChangedWithWakelock();
//发送通知
}
}
updatePowerState()方法最后会调用sendOnStateChangedWithWakelock()方法来发送消息,如下:
private void sendOnStateChangedWithWakelock() {
mCallbacks.acquireSuspendBlocker();
mHandler.post(
mOnStateChangedRunnable);
}
private final Runnable
mOnStateChangedRunnable =
new Runnable() {
@Override
public void run() {
mCallbacks.
onStateChanged();
mCallbacks.releaseSuspendBlocker();
}
};
mCallbacks在PowerManagerService中定义了Callback方法,如下:
private final DisplayManagerInternal.DisplayPowerCallbacks mDisplayPowerCallbacks =
new DisplayManagerInternal.DisplayPowerCallbacks(){
@Override
public void onStateChanged() {
synchronized (mLock) {
mDirty |=DIRTY_ACTUAL_DISPLAY_POWER_STATE_UPDATED;
updatePowerStateLocked();
}
}
在onStateChanged()方法中又调用了updatePowerStateLocked()方法,重新开始处理Power系统的状态更新。
四、电池管理服务
1、概述
Android的电池管理功能用于管理电池的充、放电功能。整个电池管理的部分包括Linux电池驱动、Android电池服务、电池属性和参数、电池曲线优化四个部分。
Linux电池驱动用户和PMIC交互、负责监听电池产生的相关事件,例如低电报警、电量发生变化、高温报警、USB插拔等。
Android电池服务,用来监听内核上报的电池事件,并将最新的电池数据上报给系统,系统收到新数据后会去更新电池显示状态、剩余电量等信息。如果收到过温报警和低电报警,系统会自动触发关机流程,保护电池和机器不受到危害。
整个电池系统的工作流程,即从底层向Framework层上报数据的流程如下:
2、电池服务
1)、电池服务的启动和运行流程:
2)、Android电池服务的源码结构
Frameworkaseservicesjavacomandroidserver
├── SystemServer.java
创建BatteryServices、PowerManagerService、ActivityManagerService
├── BatterySevices.java
监听底层上报的battery事件,广播电池发生改变的消息
Frameworkaseservicesjavacomandroidserveram
├── ActivityManagerService.java
创建BatteryStatsService
├── BatteryStatsService.java
统计和记录电池参数的信息
Frameworkaseservicesjavacomandroidserverpower
├── PowerManagerService.java
监听电池发生变化的广播消息,并调节系统的电源状态,例如亮屏
Frameworkasecorejavacominternalos
├── BatteryStatsImpl.java
统计和记录电池参数的信息,并通知其他模块
Systemcorehealthd
├── healthd.cpp
创建uevent socket,监听内核上报的内核事件
├── BatteryMonitor.cpp
初始化本地电池数据结构,将power_supply路径下属性节点路径填充进去,
├── BatteryMonitor.h
├── BatteryPropertiesRegistrar.cpp
创建电池属性监听器,并将其注册到Android的系统服务中
├── BatteryPropertiesRegistrar.h
3、BatteryService类的作用
在PowerManagerService中调用了BatteryService类的一些接口来获得电池的状态,下面来看看BatteryService是如何获得电池状态数据的。
public BatteryService(Context context) {
super(context);
mBatteryStats =BatteryStatsService.getService();
//获得BatteryStatsService对象
//读取系统设定的各种低电量报警值
// 监听设备文件:无效的充电设备
if(
newFile(
"/sys/devices/virtual/switch/invalid_charger/state").exists())
{
mInvalidChargerObserver.startObserving(
"DEVPATH=/devices/virtual/switch/invalid_charger");
}
}
publicvoid onStart() {
IBinder b =ServiceManager.getService(
"batteryproperties");
final IBatteryPropertiesRegistrarbatteryPropertiesRegistrar =
IBatteryPropertiesRegistrar.Stub.asInterface(b);
try {
batteryPropertiesRegistrar.registerListener(
newBatteryListener());
}
catch (RemoteException e) {
// Should never happen.
}
1、BatteryService的构造方法首先获得BatteryStatsService的对象,BatteryStatsService主要的功能是收集系统中各个模块和进程的耗电情况。通过BatteryStatsService记录的数据,可以找到耗电量大的模块然后进行分析加以改进。
2、接下来读取了系统设定的各种低电量报警值,如下:
l mCriticalBatteryLevel:表示电量严重不足时的值,低于这个值系统将关闭;
l mLowBatteryWarningLevel:表示电量不足时的值,低于这个值系统将发出警告;
l mLowBatteryCloseWarningLevel:表示停止电量不足警告