Android系统--PowerManagerService电源管理分析

2019-04-14 19:09发布

PowerManagerService

代码参考:http://blog.csdn.net/iefswang/article/details/38701709 并加上自己的理解和补充

简介

PowerManagerService服务是Android系统的上层的电源管理服务,主要负责系统待机、屏幕背光、按键背光、键盘背光以及用户事件的处理。通过锁的申请与释放以及默认的待机时间来控制系统的待机状态;通过系统默认灭屏时间以及用户操作的事件状态控制背光亮、暗。该服务还包括了光线、距离传感器上层查询与控制,LCD亮度的调节最终也是由该服务完成。

PowerManagerService如何来进行电源管理,那就要有外部事件的时候去通知它,WindowManagerService会把用户的点击屏幕,按键等作为user activity事件来调用userActivity函数,PowerManagerService就会在userActivity里面判断事件类型作出反映,是点亮屏幕提供操作,还是完全不理会,或者只亮一下就关掉。 电源管理架构图如下:  

开机启动及处理

当系统开启时,在SystemServer.java的run接口通过将power服务加入到系统服务中: power = new PowerManagerService(); ServiceManager.addService(Context.POWER_SERVICE, power); 当光感服务与电池管理服务都开始后进行power服务的初始化: // only initialize the power service after we have started the // lights service, content providers and the battery service. power.init(context, lights, ActivityManagerService.self(), battery,           BatteryStatsService.getService(),           ActivityManagerService.self().getAppOpsService(), display);
Init()接口实现一些基本的初始化工作,包括将lights和battery两个服务实例传入到power服务中,这两个服务将与power进行交互。另外,开启了两线程,其中有一个比较重要的线程后期用于处理亮度动画的:  mScreenBrightnessAnimator.start( ); mScreenBrightnessAnimator为PowerManagerService子类ScreenBrightnessAnimator的实例。 mHandlerThread = new HandlerThread("PowerManagerService") mHandlerThread.start( ); 另外一个PowerManagerService线程完成接下来的部分初始化工作。start后,会调用到run接口,并在其中回调到子类中的protected void onLooperPrepared()中,该接口又调用到initInThread( ),主要实现一些值的初始化,并标识mInitComplete = true;这时,mHandlerThread.notifyAll();通知mHandlerThread的Looper实例创建,该实例在systemReady( )接口中被SystemSensorManager(mHandlerThread.getLooper());使用。还有一个地方需要注意一个,在initThread中还实现了一个设置的监听:mSettings.addObserver(mSettingsObserver);如果用户在系统中变更了关于背光时间或是否启用光感等,PowerManagerService能获取到最新的状态值,通过update()进行更新。   此外,在系统准备就绪后,systemservice.java中会调用power.systemReady( );该接口主要进行一些配置值的读取,如Lcd背光、键盘背光等数组配值。 当系统完全启动,即ActivityManagerService中的finishBooting()发出bootCompleted广播后: broadcastIntentLocked(null, null, new Intent(Intent.ACTION_BOOT_COMPLETED, null),null, null, 0, null, null, android.Manifest.permission.RECEIVE_BOOT_COMPLETED, false, false, MY_PID, Process.SYSTEM_UID, Binder.getOrigCallingUser()); 此时,PMS中会收到该广播BootCompletedReceiver,接收广播后进行处理 private void handleBootCompletedLocked() {         final long now = SystemClock.uptimeMillis();         mBootCompleted = true;         mDirty |= DIRTY_BOOT_COMPLETED;         userActivityNoUpdateLocked(                 now, PowerManager.USER_ACTIVITY_EVENT_OTHER, 0,              Process.SYSTEM_UID);  //好像是模拟触发一次按键事件件          updatePowerStateLocked(); //更新电源状态 }  

和应用层交互:

在Android中应用程序并不是直接同PowerManagerService交互的,而是通过PowerManager间接地与PowerManagerService打交道。不过在使用PowerManager和PowerManager,WakeLock之前,我们要首先在APP中申请使用如下权限: 而APP能够与PowerManager做哪些交互,我们可以看到PowerManage提供了如下公共的接口: PowerManager PowerManagerService goToSleep(long time) goToSleep(long eventTime, int reason) isScreenOn() isScreenOn() reboot(String reason) reboot(boolean confirm, String reason, boolean wait) userActivity(long when, boolean noChangeLights) userActivity(long eventTime, int event, int flags) wakeUp(long time) wakeUp(long eventTime) //User activity事件发生,设备会被切换到Full on的状态,同时Reset Screen off timer. 还有一个很重要的方法newWakeLock(int flags, String tag);//取得相应层次的锁。 flags参数说明: PARTIAL_WAKE_LOCK: Screen off, keyboard light off SCREEN_DIM_WAKE_LOCK: screen dim, keyboard light off SCREEN_BRIGHT_WAKE_LOCK: screen bright, keyboard light off FULL_WAKE_LOCK: screen bright, keyboard bright ACQUIRE_CAUSES_WAKEUP: 一旦有请求锁时强制打开Screen和keyboard light ON_AFTER_RELEASE: 在释放锁时reset activity timer
注:所有的锁必须成对的使用,如果申请了而没有及时释放会造成系统故障.如申请了partial wakelock,而没有及时释放,那系统就永远进不了Sleep模式.       其实PowerManager的方法在实现的过程中,都是通过调用PowerManagerService相应的函数来实现的。PowerManager就像是PowerManagerService的"代理类"。这里略过PowerManager是如何通过binder与PowerManagerService进行通信的。 主要方法分析: 1,goToSleep     @Override // Binder call     public void goToSleep(long eventTime, int reason) {         if (eventTime > SystemClock.uptimeMillis()) {             throw new IllegalArgumentException("event time must not be in the future");         }  //权限检查          mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVIC E_POWER, null);         final long ident = Binder.clearCallingIdentity();         try {             goToSleepInternal(eventTime, reason);         } finally {             Binder.restoreCallingIdentity(ident);         } } private void goToSleepInternal(long eventTime, int reason) {         synchronized (mLock) {             if (goToSleepNoUpdateLocked(eventTime, reason)) {                 updatePowerStateLocked();             }         } } 在这段代码中,涉及到另个重要的函数goToSleepNoUpdateLocked()和updatePowerStateLocked(),而goToSleepNoUpdateLocked是goToSleep功能的计算者,来决定是否要休眠,而updatePowerStateLocked函数算是功能的执行者,而且这个执行者同时负责执行了很多其他的功能,在总结的时候会着重分析这个函数。其实goToSleepNoUpdateLocked并没有真正地让device进行sleep,仅仅只是把PowerManagerService中一些必要的属性进行了赋值。在PowerManagerService的代码中,有很多的方法的名字中都含有xxxNoUpdateLocked这样的后缀,我觉得这样做大概是因为,都类似于goToSleepNoUpdateLocked方法,并没有真正地执行方法名字所描述的功能,仅仅是更新了一些必要的属性。 所以在Android系统中可以把多个power state属性的多个变化放在一起共同执行的,而真正的功能执行者就是updatePowerStateLocked。   2,userActivity 很多地方都有调用到这个方法。直接的看,如要桌面你桌面点击或者滑动一次就会调用一次该接口。该接口会更新一些状态,其中有一个比较重要的,mUserState,该值决定了系统对lcd、按键以及键盘等亮和灭。 @Override // Binder call     public void userActivity(long eventTime, int event, int flags) { ... //判断权限等操作         final int uid = Binder.getCallingUid();         final long ident = Binder.clearCallingIdentity();         try {             userActivityInternal(eventTime, event, flags, uid);         } finally {             Binder.restoreCallingIdentity(ident);         } } private void userActivityInternal(long eventTime, int event, int flags, int uid) {         synchronized (mLock) {             if (userActivityNoUpdateLocked(eventTime, event, flags, uid)) {                 updatePowerStateLocked();             }         }  } 这里也是一样,userActivityNoUpdateLocked方法进行一些初始化操作,根据用户事件进行相应的处理,然后再调用updatePowerStateLocked执行。    

与系统其它模块之间的交互

        PowerManagerService作为Android系统Framework中重要的电源管理模块,除了与应用程序交互之外,还要与系统中其它模块配合,在提供良好的能源管理同时提供友好的用户体验。          Android系统除了提供公共接口与其它模块交互外,还提供BroadCast机制,用来对系统中发生的重要变化做出反应。下表列出了,在PowerManagerService中注册的Receiver,以及这些Receiver监听的事件,和处理方法: BatteryReceiver ACTION_BATTERY_CHANGED handleBatterStateChangeLocked() BootCompleteReceiver ACTION_BOOT_COMPLETED startWatchingForBootAnimationFinished() userSwitchReceiver ACTION_USER_SWITCHED handleSettingsChangedLocked DockReceiver ACTION_DOCK_EVENT updatePowerStateLocked DreamReceiver ACTION_DREAMING_STARTED 
ACTION_DREAMING_STOPPED scheduleSandmanLocked  PowerManagerService中除了注册了这五个Receiver之外,还定义了一个SettingsObserver,用于监视系统中以下属性的变化: SCREENSAVER_ENABLE,屏保的功能开启 SCREENSAVER_ACTIVE_ON_SLEEP,在睡眠时屏保启动 SCREENSAVER_ACTIVE_ON_DOCK,连接底座并且屏保启动 SCREEN_OFF_TIMEOUT,休眠时间 STAY_ON_PLUGGED_IN,有插入并且屏幕开启 SCREEN_BRIGHTNESS,屏幕的亮度 SCREEN_BRIGHTNESS_MODE,屏幕亮度的模式 当以上这些属性发生变化时,SettingsObserver都会监视到,并且调用SettingsObserver的onChange方法, private final class SettingsObserver extends ContentObserver {         public SettingsObserver(Handler handler) {             super(handler);         }         @Override         public void onChange(boolean selfChange, Uri uri) {             synchronized (mLock) {                 handleSettingsChangedLocked();             }         } }  以上内容,说明PowerManagerService 不仅能够接收用户的请求,被动地去做一些操作,还要主动监视系统中一些重要的属性的变化,和重要的事件的发生。无论是处理主动还是被动的操作,在上面都一一列出了对应的处理函数。 虽然对这些方法没有逐一说明,但是通过上面的goToSleepNoUpdateLocke的例子,自己阅读下应该没有问题的。如果看过这些方法之后,你会发现一个很重要的共同点,就是PowerManagerService在处理各种各样的事件的时候,最终都会经过这么一个方法updatePowerStateLocked。 在上面这些内容中,我们说各种变化的时候,常用的一个词就是power state,而在updatePowerStateLocked方法的名字中,我们很容易推测出这个方法要做的事情,就是把PowerManagerService中发生的变化,能够影响到Power Management的都要放在一起进行更新,让其真正地起作用。     下面重点研究一下updatePowerStateLocked这个方法 /**      * Updates the global power state based on dirty bits recorded in mDirty.      *      * This is the main function that performs power state transitions.      * We centralize them here so that we can recompute the power state completely      * each time something important changes, and ensure that we do it the same      * way each time.  The point is to gather all of the transition logic here.      */ private void updatePowerStateLocked() { //如果系统没有准备好,或者power state没有发生任何变化,这个方法可以不用执行的         if (!mSystemReady || mDirty == 0) {             return;         }         if (!Thread.holdsLock(mLock)) {             Slog.wtf(TAG, "Power manager lock was not held when calling updatePowerStateLocked");         }         // Phase 0: Basic state updates.         updateIsPoweredLocked(mDirty);         updateStayOnLocked(mDirty);           // Phase 1: Update wakefulness.         // Loop because the wake lock and user 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);             updateUserActivitySummaryLocked(now, dirtyPhase1);             if (!updateWakefulnessLocked(dirtyPhase1)) {                 break;             }         }           // Phase 2: Update dreams and display power state.         updateDreamLocked(dirtyPhase2);         updateDisplayPowerStateLocked(dirtyPhase2);           // Phase 3: Send notifications, if needed.         if (mDisplayReady) {             sendPendingNotificationsLocked();         }           // Phase 4: Update suspend blocker.         // Because we might release the last suspend blocker here, we need to make sure         // we finished everything else first!         updateSuspendBlockerLocked(); } 从这段代码中,很容易就看出,这个方法对于power state的更新时分成四个阶段进行的。从注释中看到, 第一阶段: 基本状态的更新; 第二阶段:显示内容的更新;  第三阶段:dream和display状态的更新; 第四阶段:suspend blocker的更新。之所以放在最后一步才进行suspend blocker的更新,是因为在这里可能会释放suspend blocker。 对这个方法有了大概的了解之后,我们开始这个PowerManagerService中重要的函数进行分析: 第一阶段: 1,updateIsPoweredLocked 这个方法的功能是判断设备是否处于充电状态中,如果DIRTY_BATTERY_STATE发生了变化,说明设备的电池的状态有过改变,然后通过对比和判断(通过电池的状态前后的变化和充电状态的变化来判断),确定是否处于在充电,充电方式的改变也会在mDirty中标记出来。同时根据充电状态的变化进行一些相应的处理,同时是否在充电或者充电方式的改变都会认为是一次用户事件或者叫用户活动的发生。   2,updateStayOnLocked 用来更新device是否开启状态。也是通过mStayOn的前后变化作为判断依据,如果device的属性Settings.Global.STAY_ON_WHILE_PLUGGED_IN为置位,并且没有达到电池充电时持续开屏时间的最大值(也就是说,在插入电源后的一段时间内保持开屏状态),那么mStayOn为真。 上面这两个方法完成了第一阶段的更新,通过代码我们可以看到,主要是进行了充电状态的判断,然后根据充电的状态更新了一些必要的属性的变化,同时也在更新mDirty。   第二阶段: 在前面说到过mWakefuless是表示device处于的醒着或睡眠或两者之间的一种状态,这种状态会影响到wake lock和user activity的计算,所以要进行更新。第二阶段是通过一个死循环进行了,只有当updateWakefulnessLocked返回为false的时候,才能跳出这个循环。刚刚进入这个循环的时候,把mDirty进行了重置,这点从侧面说明了这次updatePowerState之后,会把前面所有发生的power state执行,不会让其影响到下一次的变化。同时也在为下一次的power state从头开始更新做好准备。updateWakeLockSummaryLocked和updateUserActivitySummaryLocked代码很容易明白,要注意的是在updateUserActivitySummaryLocked在中锁屏时间和变暗时间的的比较。假如说在系统中设置的睡眠时间是30s,而在PowerManagerService中默认的SCREEN_DIM_DURATION是7s,这就意味着:如果没有用户活动的话,在第23s,设备的屏幕开始变换,持续7s时间,然后屏幕开始关闭。 下面就是开始看看,在何时才能跳出这个循环,主要就是看updateWakefulnessLocked的返回值,先看看其代码: updateWakefulnessLocked /**      * Updates the wakefulness of the device.      *      * This is the function that decides whether the device should start napping//这个方法的功能是:根据当前的wakeLocks和用户的活动情况,来决定设备是否需要小憩      * based on the current wake locks and user activity state.  It may modify mDirty      * if the wakefulness changes.      *      * Returns true if the wakefulness changed and we need to restart power state calculation.//当wakefulness发生变化的时,返回true,同时也需要重新计算power state      */     private boolean updateWakefulnessLocked(int dirty) {         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: Bed time...");                 }                 final long time = SystemClock.uptimeMillis();                 if (shouldNapAtBedTimeLocked()) {                     changed = napNoUpdateLocked(time);                 } else {                     changed = goToSleepNoUpdateLocked(time,                             PowerManager.GO_TO_SLEEP_REASON_TIMEOUT);                 }             }         }         return changed; } 先看函数isItBedTimeYetLocked,通过名字看,是在询问是否到了应该上床睡觉的的时间了。然后结合line 15整个判断来看,如果现在设备处于醒着的状态,但是到了该睡眠的时间了, 就要进行如下操作。那么我们就来看看设备是判断是否该睡眠的: /**      * Returns true if the device should go to sleep now.      * Also used when exiting a dream to determine whether we should go back      * to being fully awake or else go to sleep for good.      */     private boolean isItBedTimeYetLocked() {         return mBootCompleted && !isBeingKeptAwakeLocked();     }       /**      * Returns true if the device is being kept awake by a wake lock, user activity      * or the stay on while powered setting.  We also keep the phone awake when      * the proximity sensor returns a positive result so that the device does not      * lock while in a phone call.  This function only controls whether the device      * will go to sleep or dream which is independent of whether it will be allowed      * to suspend.      */     private boolean isBeingKeptAwakeLocked() {         return mStayOn                 || mProximityPositive                 || (mWakeLockSummary & WAKE_LOCK_STAY_AWAKE) != 0                 || (mUserActivitySummary & (USER_ACTIVITY_SCREEN_BRIGHT                         | USER_ACTIVITY_SCREEN_DIM)) != 0;     }   如果有应用程序持有wakelock,或者有用户活动的产生,或者处于充电状态,那么isBeingKeptAwakeLocked的返回值就是true,相应地isItBedTimeYetLocked 返回值就是false,说明还没有到睡眠的时间,因为还有wakelock没释放,或者有用户活动,或者是在充电等。但是,如果wakelock都释放了,并且也没有了用户活动了 也没有其他的顾虑了,那么就可以进入睡眠状态了。这时候我们就要考虑设备由醒着到睡眠的处理过程了。 接下来执行的函数就是goToSleepNoUpdateLocked。这个方法在前面已经看到过了,当时是说这个方法只是更新了下power state中一些必要的属性,并没有进行真正的执行能够让device进入sleep的代码,真正的执行代码在updatePowerStateLocked方法中,可是现在到这里,又调用了goToSleepNoUpdateLocked方法,这不还是没能让设备进入sleep嘛,这到底是怎么回事?这个问题我们先放一放,接着往下看。   第三阶段: updateDreamLocked(dirtyPhase2); 根据mDirty的变化结合其他的属性一起判断是否要开始dreaming,其实就是开始屏保。如果需要开始屏保的话,通过DreamManagerService开始dreaming。 updateDisplayPowerStateLocked 主要功能是每次都要重新计算一下display power state的值,即SCREEN_STATE_OFF,SCREEN_STATE_DIM,SCREEN_STATE_BRIGHT之一。此外,如果在DisplayController中更新了display power state的话,DisplayController会发送消息通知我们,因此我们还要回来重新检查一次。   第四阶段 这里对于SuspendBlocker的更新很简单,仅仅是判断现在device是否需要持有CPU或者是否需要CPU继续运行,如果有WakeLock没有释放,或者还有用户活动的话,或者屏幕没有关闭的话等等,这是肯定是需要持有CPU的。所以这里就是更具需求去申请或者释放SuspendBlocker。   其他底层相关代码: frameworksasecorejavaandroidosPower.java frameworksasecorejniandroid_os_power.cpp hardwarelibhardwarepowerpower.c     参考:http://blog.csdn.net/iefswang/article/details/38701709