PowerManagerService流程分析(电源管理)
来源:互联网 发布:60魔兽世界数据库 编辑:程序博客网 时间:2024/05/29 17:58
原文地址:http://www.cnblogs.com/joker8/p/7087321.html
一、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 " + name16 + ": service could not be instantiated", ex);17 } catch (IllegalAccessException ex) {18 throw new RuntimeException("Failed to create service " + name19 + ": service must have a public constructor with a Context argument", ex);20 } catch (NoSuchMethodException ex) {21 throw new RuntimeException("Failed to create service " + name22 + ": service must have a public constructor with a Context argument", ex);23 } catch (InvocationTargetException ex) {24 throw new RuntimeException("Failed to create service " + name25 + ": 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 " + name36 + ": 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 influenced19 // 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 sure45 // 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=" + wasPowered14 + ", mIsPowered=" + mIsPowered15 + ", oldPlugType=" + oldPlugType16 + ", mPlugType=" + mPlugType17 + ", 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 device30 // and it shuts off right away.31 // Some devices also wake the device when plugged or unplugged because32 // 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 that46 // it can provide feedback to the user.47 //当无线充电器开始充电时给出提示音,在mNotifier中进行处理,播放一个ogg音频文件,我的三星设备是在/system/media/audio/ui/WirelessChargingStarted.ogg48 //该路径下有不少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_OFF47 这几种WakeLock的标志位都会被清空,标志位被清空作用就是类似系统释放了这些锁;仔细看唯独WAKE_LOCK_CPU标志位不变,说明PARTIAL_WAKE_LOCK在系统休眠的48 时候是不是会自动清空的,如果系统中存在PARTIAL_WAKE_LOCK,那么除非手动释放,不然系统将没办法进入休眠49 如果第三方的应用获取了PARTIAL_WAKE_LOCK,但是在系统休眠时又不是释放该怎么办呢?在后面调试经验中会给出答案。50 */51 if (mWakefulness == WAKEFULNESS_ASLEEP52 || (mWakeLockSummary & WAKE_LOCK_DOZE) != 0) {53 mWakeLockSummary &= ~(WAKE_LOCK_SCREEN_BRIGHT | WAKE_LOCK_SCREEN_DIM54 | 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的时候这里不会获取suspendblocker23 */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 wakefulness34 // as reported by isInteractive(), it is actually more desirable to track35 // the display policy state instead so that the interactive state observed36 // 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 signal40 // until the display is actually ready so that all transitions have41 // completed. This is probably a good sign that things have gotten42 // 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_ASLEEP2 || (mWakeLockSummary & WAKE_LOCK_DOZE) != 0) {3 mWakeLockSummary &= ~(WAKE_LOCK_SCREEN_BRIGHT | WAKE_LOCK_SCREEN_DIM4 | WAKE_LOCK_BUTTON_BRIGHT |WAKE_LOCK_CPU); //待机休眠时清楚 WAKE_LOCK_CPU5 if (mWakefulness == WAKEFULNESS_ASLEEP) {6 mWakeLockSummary &= ~WAKE_LOCK_PROXIMITY_SCREEN_OFF;7 }8 }
dumpsysy power可打印PMS中锁信息:
五、总结
总的来说PMS的流程并不复杂,不过需要静下心来分析代码仍然不是一件很容易的事情,本人水平有限,有不足之处请指出,后续我会持续更新修改。
- PowerManagerService流程分析(电源管理)
- Android系统--PowerManagerService电源管理分析
- Android5.1--PowerManagerService电源管理
- Android5.1--PowerManagerService电源管理
- android4.4 PowerManagerService流程分析
- android4.4 PowerManagerService流程分析
- PowerManagerService电源管理和Wacklock锁申请与释放机制
- PowerManagerService电源管理和Wacklock锁申请与释放机制
- Android 4.0按键事件以及电源管理流程分析
- Android 4.0按键事件以及电源管理流程分析
- Android usb子系统的 电源管理 流程分析
- powermanagerservice分析
- Android电源管理分析
- Android电源管理分析
- Android电源管理分析
- Android电源管理分析
- PowerManagerService的启动流程
- 电源管理芯片 mc13892 分析
- 长方形去重排序
- sql学习--truncate/delete/drop的区别
- UI
- Oracle GRANT 附权详解
- java string null + ""
- PowerManagerService流程分析(电源管理)
- 一张图搞定Android开发学习路线
- 线段树入门
- python-TypeError: write() argument must be str, not numpy.float64
- JPush极光推送Java服务器端实例
- Array与ArrayBuffer的区别
- 树莓派+hokuyo激光+gmapping+navigation
- connect by
- Single Number 系列