一、PowerManagerService简介
PowerManagerService主要服务Android系统电源管理工作,这样讲比较笼统,就具体细节上大致可以认为PowerManagerService集中处理用户活动(如点击屏幕,按电源键等)、电量变化、用户设置(如在Setting中设置省电模式,飞行模式)、插拔充电器(无线冲,有线冲)等。当发生以上事件时,PowerManagerService都要进行各种状态的更新,以下把PMS作为PowerManagerService的简称
二、PowerManagerService启动流程
2.1、PMS启动
// Power manager needs to be started early because other services need it. // Native daemons may be watching for it to be registered so it must be ready // to handle incoming binder calls immediately (including being able to verify // the permissions for those calls). mPowerManagerService = mSystemServiceManager.startService(PowerManagerService.class); . . . try { // TODO: use boot phase mPowerManagerService.systemReady(mActivityManagerService.getAppOpsService()); } catch (Throwable e) { reportWtf("making Power Manager Service ready", e); }
2.2、SystemServiceManager.startService()
1 public <T extends SystemService> T startService(Class<T> serviceClass) { 2 final String name = serviceClass.getName(); 3 Slog.i(TAG, "Starting " + name); 4 5 // Create the service. 6 if (!SystemService.class.isAssignableFrom(serviceClass)) { 7 throw new RuntimeException("Failed to create " + name 8 + ": service must extend " + SystemService.class.getName()); 9 } 10 final T service; 11 try { 12 Constructor<T> constructor = serviceClass.getConstructor(Context.class); 13 service = constructor.newInstance(mContext); 14 } catch (InstantiationException ex) { 15 throw new RuntimeException("Failed to create service " + name 16 + ": service could not be instantiated", ex); 17 } catch (IllegalAccessException ex) { 18 throw new RuntimeException("Failed to create service " + name 19 + ": service must have a public constructor with a Context argument", ex); 20 } catch (NoSuchMethodException ex) { 21 throw new RuntimeException("Failed to create service " + name 22 + ": service must have a public constructor with a Context argument", ex); 23 } catch (InvocationTargetException ex) { 24 throw new RuntimeException("Failed to create service " + name 25 + ": service constructor threw an exception", ex); 26 } 27 28 // Register it. 29 mServices.add(service); 30 31 // Start it. 32 try { 33 service.onStart(); 34 } catch (RuntimeException ex) { 35 throw new RuntimeException("Failed to start service " + name 36 + ": onStart threw an exception", ex); 37 } 38 return service; 39 }
在Android5.0以后SystemServer启动服务的方式发生了改变,在Android4.4以前SystemServer通过new方法创建服务的对象,并把服务注册到SystemManager中;Android5.0以后SystemServer通过SystemServiceManager.startService来启动服务,主要通过反射的方式获取服务的构造方法,并创建服务对象;最后调用服务重写的onStart()方法。
说明:Android5.0以后所有服务都实现SystemService接口,这样方法服务的统一管理。
2.3 、PMS构造方法
public PowerManagerService(Context context) { super(context); mContext = context; //启动一个线程,创建一个handler,handler发送的消息由该线程来处理 mHandlerThread = new ServiceThread(TAG, Process.THREAD_PRIORITY_DISPLAY, false /*allowIo*/); mHandlerThread.start(); mHandler = new PowerManagerHandler(mHandlerThread.getLooper()); synchronized (mLock) { //创建两个suspendBlocker对象,获取suspendblocker防止cpu进去休眠 mWakeLockSuspendBlocker = createSuspendBlockerLocked("PowerManagerService.WakeLocks"); mDisplaySuspendBlocker = createSuspendBlockerLocked("PowerManagerService.Display"); mDisplaySuspendBlocker.acquire(); mHoldingDisplaySuspendBlocker = true; mHalAutoSuspendModeEnabled = false; mHalInteractiveModeEnabled = true; mWakefulness = WAKEFULNESS_AWAKE; //初始化电源相关设置,这些方法通过jni调动native方法 nativeInit(); nativeSetAutoSuspend(false); nativeSetInteractive(true); nativeSetFeature(POWER_FEATURE_DOUBLE_TAP_TO_WAKE, 0); } }
2.4、OnStart()方法
1 @Override 2 public void onStart() { 3 //BinderService继承IPowerManager.Stub,其实就是PowerManager的服务端 4 //这里其实就是把BinderService对象注册到ServiceManager中 5 publishBinderService(Context.POWER_SERVICE, new BinderService()); 6 publishLocalService(PowerManagerInternal.class, new LocalService()); 7 8 //加入Watchdog监听 9 Watchdog.getInstance().addMonitor(this); 10 Watchdog.getInstance().addThread(mHandler); 11 }
2.5、systemReady()方法
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); PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); //最大、最小、默认的屏幕亮超时时间 mScreenBrightnessSettingMinimum = pm.getMinimumScreenBrightnessSetting(); mScreenBrightnessSettingMaximum = pm.getMaximumScreenBrightnessSetting(); mScreenBrightnessSettingDefault = pm.getDefaultScreenBrightnessSetting(); //传感器相关,传感器检查到外部事件可以通过发送消息到mHandler的消息队列中处理 SensorManager sensorManager = new SystemSensorManager(mContext, mHandler.getLooper()); // The notifier runs on the system server's main looper so as not to interfere // with the animations and other critical functions of the power manager. mBatteryStats = BatteryStatsService.getService(); //注意上面的注释,notifier运行在system server的主线程中,并且参数中传入了一个SuspendBlocker对象,应该发送通知的时候需要点亮屏幕 mNotifier = new Notifier(Looper.getMainLooper(), mContext, mBatteryStats, mAppOps, createSuspendBlockerLocked("PowerManagerService.Broadcasts"), mPolicy); //无线充电器相关,参数中传入了sensorManager,并且参数中传入了一个SuspendBlocker对象,也是为了有外部事件发生时点亮屏幕 mWirelessChargerDetector = new WirelessChargerDetector(sensorManager, createSuspendBlockerLocked("PowerManagerService.WirelessChargerDetector"), mHandler); //ContentObserver对象,用来监听电源相关设置的改变 mSettingsObserver = new SettingsObserver(mHandler); mLightsManager = getLocalService(LightsManager.class); mAttentionLight = mLightsManager.getLight(LightsManager.LIGHT_ID_ATTENTION); // Initialize display power management. mDisplayManagerInternal.initPowerManagement( mDisplayPowerCallbacks, mHandler, sensorManager); // Register for broadcasts from other components of the system. //注册一些广播监听器,如电量变化、用户切换(多用户模式,一般手机就是单用户) IntentFilter filter = new IntentFilter(); filter.addAction(Intent.ACTION_BATTERY_CHANGED); filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY); mContext.registerReceiver(new BatteryReceiver(), filter, null, mHandler); filter = new IntentFilter(); filter.addAction(Intent.ACTION_DREAMING_STARTED); filter.addAction(Intent.ACTION_DREAMING_STOPPED); mContext.registerReceiver(new DreamReceiver(), filter, null, mHandler); filter = new IntentFilter(); filter.addAction(Intent.ACTION_USER_SWITCHED); mContext.registerReceiver(new UserSwitchedReceiver(), filter, null, mHandler); filter = new IntentFilter(); filter.addAction(Intent.ACTION_DOCK_EVENT); mContext.registerReceiver(new DockReceiver(), filter, null, mHandler); // Register for settings changes. //监听系统中对电源的设置,如开启省电模式、默认休眠超时时间、屏幕亮度、充电是否亮屏等等 final ContentResolver resolver = mContext.getContentResolver(); resolver.registerContentObserver(Settings.Secure.getUriFor( Settings.Secure.SCREENSAVER_ENABLED), false, mSettingsObserver, UserHandle.USER_ALL); ....... ....... ....... // Go. //读取资源文件中电源相关设置 readConfigurationLocked(); //更新设置中对电源的相关设置 updateSettingsLocked(); mDirty |= DIRTY_BATTERY_STATE; //更新电源状态,这里统一处理了所有的状态更新,该方法会被频繁调用 updatePowerStateLocked(); } }
2.6、updatePowerStateLocked()方法
1 private void updatePowerStateLocked() { 2 if (!mSystemReady || mDirty == 0) { 3 return; 4 } 5 if (!Thread.holdsLock(mLock)) { 6 Slog.wtf(TAG, "Power manager lock was not held when calling updatePowerStateLocked"); 7 } 8 9 Trace.traceBegin(Trace.TRACE_TAG_POWER, "updatePowerState"); 10 try { 11 // Phase 0: Basic state updates. 12 updateIsPoweredLocked(mDirty); 13 //设置DIRTY_STAY_ON标志位 14 updateStayOnLocked(mDirty); 15 updateScreenBrightnessBoostLocked(mDirty); 16 17 // Phase 1: Update wakefulness. 18 // Loop because the wake lock and user activity computations are influenced 19 // by changes in wakefulness. 20 final long now = SystemClock.uptimeMillis(); 21 int dirtyPhase2 = 0; 22 for (;;) { 23 int dirtyPhase1 = mDirty; 24 dirtyPhase2 |= dirtyPhase1; 25 mDirty = 0; 26 27 updateWakeLockSummaryLocked(dirtyPhase1); 28 updateUserActivitySummaryLocked(now, dirtyPhase1); 29 if (!updateWakefulnessLocked(dirtyPhase1)) { 30 break; 31 } 32 } 33 34 // Phase 2: Update display power state. 35 boolean displayBecameReady = updateDisplayPowerStateLocked(dirtyPhase2); 36 37 // Phase 3: Update dream state (depends on display ready signal). 38 updateDreamLocked(dirtyPhase2, displayBecameReady); 39 40 // Phase 4: Send notifications, if needed. 41 finishWakefulnessChangeIfNeededLocked(); 42 43 // Phase 5: Update suspend blocker. 44 // Because we might release the last suspend blocker here, we need to make sure 45 // we finished everything else first! 46 updateSuspendBlockerLocked(); 47 } finally { 48 Trace.traceEnd(Trace.TRACE_TAG_POWER); 49 } 50 }
这里还是需要把代码贴出来比较好,可以直观看到updatePowerStateLocked()有6个阶段
第0阶段:基本状态更新:
2.6.1、updateIsPoweredLocked()
1 private void updateIsPoweredLocked(int dirty) { 2 if ((dirty & DIRTY_BATTERY_STATE) != 0) { 3 final boolean wasPowered = mIsPowered; 4 final int oldPlugType = mPlugType; 5 final boolean oldLevelLow = mBatteryLevelLow; 6 //获取充电标志位、充电器类型、电量百分比、低电量标志位 7 mIsPowered = mBatteryManagerInternal.isPowered(BatteryManager.BATTERY_PLUGGED_ANY); 8 mPlugType = mBatteryManagerInternal.getPlugType(); 9 mBatteryLevel = mBatteryManagerInternal.getBatteryLevel(); 10 mBatteryLevelLow = mBatteryManagerInternal.getBatteryLevelLow(); 11 12 if (DEBUG_SPEW) { 13 Slog.d(TAG, "updateIsPoweredLocked: wasPowered=" + wasPowered 14 + ", mIsPowered=" + mIsPowered 15 + ", oldPlugType=" + oldPlugType 16 + ", mPlugType=" + mPlugType 17 + ", mBatteryLevel=" + mBatteryLevel); 18 } 19 //充电器插拔时间发生、或者充电器类型更变则设置DIRTY_IS_POWERED标志位 20 if (wasPowered != mIsPowered || oldPlugType != mPlugType) { 21 mDirty |= DIRTY_IS_POWERED; 22 23 // Update wireless dock detection state. 24 //判断是否进行无线充电 25 final boolean dockedOnWirelessCharger = mWirelessChargerDetector.update( 26 mIsPowered, mPlugType, mBatteryLevel); 27 28 // Treat plugging and unplugging the devices as a user activity. 29 // Users find it disconcerting when they plug or unplug the device 30 // and it shuts off right away. 31 // Some devices also wake the device when plugged or unplugged because 32 // they don't have a charging LED. 33 //上面的注释意思是说插拔充电器可以看做是用户行为,当插拔充电器时如果设备没有给出提示则用户会比较疑惑 34 //特别是在设备没有充电指示灯的时,所以一般插拔充电器时会唤醒设备 35 final long now = SystemClock.uptimeMillis(); 36 if (shouldWakeUpWhenPluggedOrUnpluggedLocked(wasPowered, oldPlugType, 37 dockedOnWirelessCharger)) { 38 //如果设置了插拔充电器时候需要唤醒设备,则在这里唤醒设备 39 wakeUpNoUpdateLocked(now, "android.server.power:POWER", Process.SYSTEM_UID, 40 mContext.getOpPackageName(), Process.SYSTEM_UID); 41 } 42 userActivityNoUpdateLocked( 43 now, PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, Process.SYSTEM_UID); 44 45 // Tell the notifier whether wireless charging has started so that 46 // it can provide feedback to the user. 47 //当无线充电器开始充电时给出提示音,在mNotifier中进行处理,播放一个ogg音频文件,我的三星设备是在/system/media/audio/ui/WirelessChargingStarted.ogg 48 //该路径下有不少ogg文件,有兴趣的可以看看都是在什么情况下播的 49 if (dockedOnWirelessCharger) { 50 mNotifier.onWirelessChargingStarted(); 51 } 52 } 53 //如果电源插拔时间发生、或者是低电量标志位发生变化 54 if (wasPowered != mIsPowered || oldLevelLow != mBatteryLevelLow) { 55 if (oldLevelLow != mBatteryLevelLow && !mBatteryLevelLow) { 56 //当设备从低电量切换为非低电量,则设置自动打盹标志为false(因为已经不是低电量了) 57 if (DEBUG_SPEW) { 58 Slog.d(TAG, "updateIsPoweredLocked: resetting low power snooze"); 59 } 60 mAutoLowPowerModeSnoozing = false; 61 } 62 //发送广播ACTION_POWER_SAVE_MODE_CHANGED,该广播在系统多处进行处理,在SystemUI中进行处理,如果低电量则给出提示 63 updateLowPowerModeLocked(); 64 } 65 } 66 }
2.6.2、updateScreenBrightnessBoostLocked()
1 private void updateScreenBrightnessBoostLocked(int dirty) { 2 if ((dirty & DIRTY_SCREEN_BRIGHTNESS_BOOST) != 0) { 3 if (mScreenBrightnessBoostInProgress) { 4 final long now = SystemClock.uptimeMillis(); 5 //删除屏幕亮度提升超时广播 6 mHandler.removeMessages(MSG_SCREEN_BRIGHTNESS_BOOST_TIMEOUT); 7 if (mLastScreenBrightnessBoostTime > mLastSleepTime) { 8 final long boostTimeout = mLastScreenBrightnessBoostTime + 9 SCREEN_BRIGHTNESS_BOOST_TIMEOUT; 10 //如果超时还没有发生,则重新发送广播(定时广播) 11 if (boostTimeout > now) { 12 Message msg = mHandler.obtainMessage(MSG_SCREEN_BRIGHTNESS_BOOST_TIMEOUT); 13 msg.setAsynchronous(true); 14 mHandler.sendMessageAtTime(msg, boostTimeout); 15 return; 16 } 17 } 18 //运行到这里有2个条件 19 //mLastScreenBrightnessBoostTime <= mLastSleepTime 说明还在睡眠中 20 //boostTimeout <= now 说明屏幕提升超时发生 21 mScreenBrightnessBoostInProgress = false; 22 mNotifier.onScreenBrightnessBoostChanged(); 23 userActivityNoUpdateLocked(now, 24 PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, Process.SYSTEM_UID); 25 } 26 } 27 }
第1阶段:基本状态更新:
2.6.3、updateWakeLockSummaryLocked()
1 @SuppressWarnings("deprecation") 2 private void updateWakeLockSummaryLocked(int dirty) { 3 if ((dirty & (DIRTY_WAKE_LOCKS | DIRTY_WAKEFULNESS)) != 0) { 4 mWakeLockSummary = 0; 5 //mWakeLocks保存了用户创建的所有wakelock 6 final int numWakeLocks = mWakeLocks.size(); 7 for (int i = 0; i < numWakeLocks; i++) { 8 final WakeLock wakeLock = mWakeLocks.get(i); 9 switch (wakeLock.mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK) { 10 case PowerManager.PARTIAL_WAKE_LOCK: 11 if (!wakeLock.mDisabled) { 12 // We only respect this if the wake lock is not disabled. 13 if(!wakeLock.mPackageName.equals("com.google.android.gms")){ 14 mWakeLockSummary |= WAKE_LOCK_CPU; 15 } 16 } 17 break; 18 case PowerManager.FULL_WAKE_LOCK: 19 mWakeLockSummary |= WAKE_LOCK_SCREEN_BRIGHT | WAKE_LOCK_BUTTON_BRIGHT; 20 break; 21 case PowerManager.SCREEN_BRIGHT_WAKE_LOCK: 22 mWakeLockSummary |= WAKE_LOCK_SCREEN_BRIGHT; 23 break; 24 case PowerManager.SCREEN_DIM_WAKE_LOCK: 25 mWakeLockSummary |= WAKE_LOCK_SCREEN_DIM; 26 break; 27 case PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK: 28 mWakeLockSummary |= WAKE_LOCK_PROXIMITY_SCREEN_OFF; 29 break; 30 case PowerManager.DOZE_WAKE_LOCK: 31 mWakeLockSummary |= WAKE_LOCK_DOZE; 32 break; 33 case PowerManager.DRAW_WAKE_LOCK: 34 mWakeLockSummary |= WAKE_LOCK_DRAW; 35 break; 36 } 37 } 38 /** 39 根据mWakefullness的状态取消某些锁的作用,意思就是说在系统处于特定状态时,有些锁是没有意义的,需要取消mWakeLockSummary中相应的标志位 40 */ 41 // Cancel wake locks that make no sense based on the current state. 42 if (mWakefulness != WAKEFULNESS_DOZING) { 43 mWakeLockSummary &= ~(WAKE_LOCK_DOZE | WAKE_LOCK_DRAW); 44 } 45 /** 46 注意这里,当mWakefulless状态为asleep时,WAKE_LOCK_SCREEN_BRIGHT、WAKE_LOCK_SCREEN_DIM、WAKE_LOCK_BUTTON_BRIGHT、WAKE_LOCK_PROXIMITY_SCREEN_OFF 47 这几种WakeLock的标志位都会被清空,标志位被清空作用就是类似系统释放了这些锁;仔细看唯独WAKE_LOCK_CPU标志位不变,说明PARTIAL_WAKE_LOCK在系统休眠的 48 时候是不是会自动清空的,如果系统中存在PARTIAL_WAKE_LOCK,那么除非手动释放,不然系统将没办法进入休眠 49 如果第三方的应用获取了PARTIAL_WAKE_LOCK,但是在系统休眠时又不是释放该怎么办呢?在后面调试经验中会给出答案。 50 */ 51 if (mWakefulness == WAKEFULNESS_ASLEEP 52 || (mWakeLockSummary & WAKE_LOCK_DOZE) != 0) { 53 mWakeLockSummary &= ~(WAKE_LOCK_SCREEN_BRIGHT | WAKE_LOCK_SCREEN_DIM 54 | WAKE_LOCK_BUTTON_BRIGHT); 55 if (mWakefulness == WAKEFULNESS_ASLEEP) { 56 mWakeLockSummary &= ~WAKE_LOCK_PROXIMITY_SCREEN_OFF; 57 } 58 } 59 /** 60 根据mWakefullness的状态增加某些锁的作用,就是说当系统处于特定状态时,需要某些锁来保持系统的状态,比如WAKEFULNESS_AWAKE状态肯定是要保持CPU运行的,所以 61 需要添加WAKE_LOCK_CPU标志位以确保cpu处于运行状态 62 */ 63 // Infer implied wake locks where necessary based on the current state. 64 if ((mWakeLockSummary & (WAKE_LOCK_SCREEN_BRIGHT | WAKE_LOCK_SCREEN_DIM)) != 0) { 65 if (mWakefulness == WAKEFULNESS_AWAKE) { 66 mWakeLockSummary |= WAKE_LOCK_CPU | WAKE_LOCK_STAY_AWAKE; 67 } else if (mWakefulness == WAKEFULNESS_DREAMING) { 68 mWakeLockSummary |= WAKE_LOCK_CPU; 69 } 70 } 71 if ((mWakeLockSummary & WAKE_LOCK_DRAW) != 0) { 72 mWakeLockSummary |= WAKE_LOCK_CPU; 73 } 74 75 if (DEBUG_SPEW) { 76 Slog.d(TAG, "updateWakeLockSummaryLocked: mWakefulness=" 77 + PowerManagerInternal.wakefulnessToString(mWakefulness) 78 + ", mWakeLockSummary=0x" + Integer.toHexString(mWakeLockSummary)); 79 } 80 } 81 }
2.6.4、updateUserActivitySummaryLocked()
这个方法只是更新mUserActivitySummary的值,内容比较简单,这里不再贴代码分析了,读者自行分析吧
2.6.5、updateWakefulnessLocked()
1 private boolean updateWakefulnessLocked(int dirty) { 2 boolean changed = false; 3 if ((dirty & (DIRTY_WAKE_LOCKS | DIRTY_USER_ACTIVITY | DIRTY_BOOT_COMPLETED 4 | DIRTY_WAKEFULNESS | DIRTY_STAY_ON | DIRTY_PROXIMITY_POSITIVE 5 | DIRTY_DOCK_STATE)) != 0) { 6 //注意这里会改变mWakefullness的值,但是mWakefullness的值会影响锁的有效性,因此阶段2的处理在一个for循环中 7 if (mWakefulness == WAKEFULNESS_AWAKE && isItBedTimeYetLocked()) { 8 if (DEBUG_SPEW) { 9 Slog.d(TAG, "updateWakefulnessLocked: Bed time..."); 10 } 11 final long time = SystemClock.uptimeMillis(); 12 if (shouldNapAtBedTimeLocked()) { 13 changed = napNoUpdateLocked(time, Process.SYSTEM_UID); 14 } else { 15 changed = goToSleepNoUpdateLocked(time, 16 PowerManager.GO_TO_SLEEP_REASON_TIMEOUT, 0, Process.SYSTEM_UID); 17 } 18 } 19 } 20 return changed; 21 }
第2、3、4、5代码比较简单,这里就不分析了,读者自行分析,下面我们来关注第6阶段
阶段6:
2.6.6、updateSuspendBlockerLocked()
1 private void updateSuspendBlockerLocked() { 2 final boolean needWakeLockSuspendBlocker = ((mWakeLockSummary & WAKE_LOCK_CPU) != 0); 3 final boolean needDisplaySuspendBlocker = needDisplaySuspendBlockerLocked(); 4 final boolean autoSuspend = !needDisplaySuspendBlocker; 5 final boolean interactive = mDisplayPowerRequest.isBrightOrDim(); 6 7 // Disable auto-suspend if needed. 8 // FIXME We should consider just leaving auto-suspend enabled forever since 9 // we already hold the necessary wakelocks. 10 if (!autoSuspend && mDecoupleHalAutoSuspendModeFromDisplayConfig) { 11 setHalAutoSuspendModeLocked(false); 12 } 13 /** 14 从上面我们知道有WAKE_LOCK_CPU标志的话就获取一个suspendblocker,这才是正真会阻止cpu待机的东西 15 */ 16 // First acquire suspend blockers if needed. 17 if (needWakeLockSuspendBlocker && !mHoldingWakeLockSuspendBlocker) { 18 mWakeLockSuspendBlocker.acquire(); 19 mHoldingWakeLockSuspendBlocker = true; 20 } 21 /* 22 只有屏幕亮的时候才需要display suspendblocker,当屏幕灭或者doz的时候这里不会获取suspendblocker 23 */ 24 if (needDisplaySuspendBlocker && !mHoldingDisplaySuspendBlocker) { 25 mDisplaySuspendBlocker.acquire(); 26 mHoldingDisplaySuspendBlocker = true; 27 } 28 29 /* 30 设置设备为可交互模式 31 */ 32 // Inform the power HAL about interactive mode. 33 // Although we could set interactive strictly based on the wakefulness 34 // as reported by isInteractive(), it is actually more desirable to track 35 // the display policy state instead so that the interactive state observed 36 // by the HAL more accurately tracks transitions between AWAKE and DOZING. 37 // Refer to getDesiredScreenPolicyLocked() for details. 38 if (mDecoupleHalInteractiveModeFromDisplayConfig) { 39 // When becoming non-interactive, we want to defer sending this signal 40 // until the display is actually ready so that all transitions have 41 // completed. This is probably a good sign that things have gotten 42 // too tangled over here... 43 if (interactive || mDisplayReady) { 44 setHalInteractiveModeLocked(interactive); 45 } 46 } 47 /* 48 注意这里needWakeLockSuspendBlocker为ture的话是不会释放mWakeLockSuspendBlocker的,所以系统会无法待机 49 这样就能解释的通为什么PARTIAL_WAKE_LOCK级别的锁会导致不能待机了: 50 app-->newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,flag) --->PMS设置mWakeLockSummary的WAKE_LOCK_CPU标志位 51 --->PMS 因为WAKE_LOCK_CPU标志位存在mWakeLockSuspendBlocker.acquire()-->待机失败 52 */ 53 // Then release suspend blockers if needed. 54 if (!needWakeLockSuspendBlocker && mHoldingWakeLockSuspendBlocker) { 55 mWakeLockSuspendBlocker.release(); 56 mHoldingWakeLockSuspendBlocker = false; 57 } 58 if (!needDisplaySuspendBlocker && mHoldingDisplaySuspendBlocker) { 59 mDisplaySuspendBlocker.release(); 60 mHoldingDisplaySuspendBlocker = false; 61 } 62 63 //如果条件成立的话设置自动待机模式 64 // Enable auto-suspend if needed. 65 if (autoSuspend && mDecoupleHalAutoSuspendModeFromDisplayConfig) { 66 setHalAutoSuspendModeLocked(true); 67 } 68 }
三、PowerManager用法
PowerManager的用法很简单,我们主要看下PowerManager创建锁这部分:
newWakeLock(int levelAndFlags, String tag)
levelAndFlags: 就是上边表格中的几个flag,可以看到不同的flag对系统的影响并不一样
PARTIAL_WAKE_LOCK: 保持cpu运转状态,屏幕键盘灭,按power键该锁不会被系统自动释放,所以系统无法进去待机休眠
SCREEN_DIM_WAKE_LOCK: 保持cpu处于运行状态,屏幕微亮、键盘灭,但是按power键进入待机休眠时会自动释放
SCREEN_BRIGHT_WAKE_LOCK: 保持cpu处于运行状态,屏幕亮、键盘灭,但是按power键进入待机休眠时会自动释放
FULL_WAKE_LOCK: 保持cpu处于运行状态,屏幕、键盘亮,但是按power键进入待机休眠时会自动释放
注意:官方的文档介绍尽量不要使用WAKE_LOCK,用FLAG_KEEP_SCREEN_ON标志位代替WAKE_LOCK,用如下方式:
1 getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
当然该方法只是针对当前Activity,如果要整个应用都保持屏幕亮,则可以写了BaseActivity并设置该标志位,其他Activity继承BaseActivity即可。
四、PowerManagerService调试
PMS中最容易出现的问题就是待机待不下去,原因就是上面说的PARTIAL_WAKE_LOCK级别的锁没有释放,按道理说这种锁的释放应该由应用自身来作的,但是一些第三方的应用(Google的一些应用就很多这种锁)没有释放的话该怎么办呢?
下面介绍两种办法:
1、强制不给设置WAKE_LOCK_CPU标志位
1 private void updateWakeLockSummaryLocked(int dirty) { 2 if ((dirty & (DIRTY_WAKE_LOCKS | DIRTY_WAKEFULNESS)) != 0) { 3 mWakeLockSummary = 0; 4 //mWakeLocks保存了用户创建的所有wakelock 5 final int numWakeLocks = mWakeLocks.size(); 6 for (int i = 0; i < numWakeLocks; i++) { 7 final WakeLock wakeLock = mWakeLocks.get(i); 8 switch (wakeLock.mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK) { 9 case PowerManager.PARTIAL_WAKE_LOCK: 10 if (!wakeLock.mDisabled) { 11 // We only respect this if the wake lock is not disabled. 12 //com.google.android.gms获取了PARTIAL_WAKE_LOCK,但是不给设置WAKE_LOCK_CPU标志位 13 if(!wakeLock.mPackageName.equals("com.google.android.gms")){ 14 mWakeLockSummary |= WAKE_LOCK_CPU; 15 }else{ 16 mWakeLockSummary |= WAKE_LOCK_SCREEN_BRIGHT; 17 } 18 }
2、让系统自动清楚WAKE_LOCK_CPU标志
1 if (mWakefulness == WAKEFULNESS_ASLEEP 2 || (mWakeLockSummary & WAKE_LOCK_DOZE) != 0) { 3 mWakeLockSummary &= ~(WAKE_LOCK_SCREEN_BRIGHT | WAKE_LOCK_SCREEN_DIM 4 | WAKE_LOCK_BUTTON_BRIGHT |WAKE_LOCK_CPU); //待机休眠时清楚 WAKE_LOCK_CPU 5 if (mWakefulness == WAKEFULNESS_ASLEEP) { 6 mWakeLockSummary &= ~WAKE_LOCK_PROXIMITY_SCREEN_OFF; 7 } 8 }
dumpsysy power可打印PMS中锁信息:
五、总结
总的来说PMS的流程并不复杂,不过需要静下心来分析代码仍然不是一件很容易的事情,本人水平有限,有不足之处请指出,后续我会持续更新修改。