电源管理(PowerManager)在任何设备中都是最重要的组成部分之一,良好的电源管理方案可以达到节能、延长电池寿命、降低辐射、降温等目的。
移动设备的电量主要有两种元件消耗:CPU和显示屏。设法降低这两种元件的耗电量就是电源管理的关键。为移动设备设计的CPU大都有两种工作频率,为了省电,大部分时间CPU都工作在较低的频率下,只有进行密集计算时,如视频解码,才会切换到高频状态。而显示屏省电的方法是尽量减少亮屏的时间,但是显示屏的开关和应用有很大的关系,因此,系统需要有一套机制来控制显示屏的开关和亮度,这是电源管理模块的主要工作之一。
Android的电源管理主要是通过wacklock和定时器来切换系统的状态,使系统的功耗降至最低,整个系统的框架可以分为四个层次:
应用接口层(PowerManager.java),Framework层(PowerManagerService.java),HAL层(Power.c),和内核层(kernel/Power)。
应用层:PowerManager中开放给应用一系列接口,应用可以调用PM的接口申请wakelock,唤醒系统,使系统进入睡眠等操作
框架层:应用调用PowerManager开放的接口,来对系统进行一些列的操作是在PowerManagerService中完成的,PowerManagerService计算系统中和Power相关的计算,是整个电源管理的决策系统。同时协调Power如何与系统其它模块的交互,比如亮屏,暗屏,系统睡眠,唤醒等等。
HAL层:该层只有一个Power.c文件,该文件通过sysfs的方式与kernel进行通信。主要功能有申请wake_lock,释放wake_lock,设置屏幕状态等。用户空间的native库绝不能直接调用Android电源管理(见下图)。绕过Android运行时的电源管理政策,将破坏该系统。所有对电源管理的调用应通过Android的PowerManagerAPI来完成。
Kernel层:内核层的电源管理方案实现主要包含三部分:
1、Kernel/power/:实现了系统电源管理框架机制。
2、Arch/arm(ormips or powerpc)/mach-XXX/pm.c:实现对特定板的处理器电源管理。
3、drivers/power:是设备电源管理的基础框架,为驱动提供了电源管理接口。
系统正常开机后,Brightness的亮度会设置成用户设定的亮度,系统Screen off timer开始计时,在计时时间到之前,如果有任何的userActivity事件发生,比如Touch click等事件,则将重新设置screen off timer,系统保持在Awake状态。如果应用程序在这段时间申请了Full wakelock,系统也将保持在Awake状态。在没有交互的情况下,首先进入到Awake状态,之后进入Dozing状态,最后进入Asleep状态。
1. PowerManagerService
1.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()。
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。
Android设备的休眠和唤醒主要基于WakeLock机制。WakeLock是一种上锁机制,只要有进程获得了WakeLock锁系统就不会进入休眠。例如,在下载文件或播放音乐时,即使休眠时间到了,系统也不能进行休眠。WakeLock可以设置超时,超时后会自动解锁。
应用使用WakeLock功能前,需要先使用new WakeLock()接口创建一个WakeLock类对象,然后调用它的acquire()方法禁止系统休眠,应用完成工作后调用release()方法来恢复休眠机制,否则系统将无法休眠,直到耗光所有电量。
WakeLock类中实现acquire()和release()方法实际上是调用了PowerManagerService的acquireWakeLock()和releaseWakeLock()方法。
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更新为当前时间,这样当休眠时间到时,系统就会休眠。
我们先回到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了。
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()方法。来决定系统是休眠还是唤醒。
1.Wakelock 锁机制:
应用程序可以通过申请 wakelock 锁的机制来对系统是否待机作出投票,当有任何一个应用申请了 wakelock 锁,待机时没有释放掉,系统是不会进入待机的,直到所有应用的 wakelock 锁都释放掉了,才会进入待机。
/**
* 获取电源锁,保持该服务在屏幕熄灭时仍然获取CPU时,保持运行
*/
private void acquireWakeLock() {
if (null == wakeLock) {
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK | PowerManager.ON_AFTER_RELEASE,
getClass() .getCanonicalName());
if (null != wakeLock) {
Log.i(TAG, "call acquireWakeLock");
wakeLock.acquire();
}
}
}
private WakeLock wakeLock = null;
// 释放设备电源锁
private void releaseWakeLock() {
if (null != wakeLock && wakeLock.isHeld()) {
Log.i(TAG, "call releaseWakeLock");
wakeLock.release();
wakeLock = null;
}
}
WakeLock 类型以及说明:
PARTIAL_WAKE_LOCK:保持CPU 运转,屏幕和键盘灯有可能是关闭的。
SCREEN_DIM_WAKE_LOCK:保持CPU 运转,允许保持屏幕显示但有可能是灰的,允许关闭键盘灯
SCREEN_BRIGHT_WAKE_LOCK:保持CPU 运转,允许保持屏幕高亮显示,允许关闭键盘灯
FULL_WAKE_LOCK:保持CPU 运转,保持屏幕高亮显示,键盘灯也保持亮度
ACQUIRE_CAUSES_WAKEUP:强制使屏幕亮起,这种锁主要针对一些必须通知用户的操作.
ON_AFTER_RELEASE:当锁被释放时,保持屏幕亮起一段时间
最后 AndroidManifest.xml 声明权限:
在 onResume() 或者 onStart() 中申请 wakelock 锁,即调用acquireWakeLock()方法,来保证系统不会进入待机
在 onPause() 或者 onDistroy() 中处理应用待机后再释放掉 wakelock 锁,此时调用releaseWakeLock()方法
另外WakeLock的设置是 Activiy 级别的,不是针对整个Application应用的。如果有多个activity一定需要注意下!
adb shell cat /sys/kernel/debug/wakeup_sources
adb shell dumpsys power