一、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的流程并不复杂,不过需要静下心来分析代码仍然不是一件很容易的事情,本人水平有限,有不足之处请指出,后续我会持续更新修改。

PowerManagerService流程分析的更多相关文章

  1. Android系统开发--灯光系统之电池灯的流程分析

    Android系统开发--Android灯光系统之电池灯的流程分析 前期系统准备 运行初始化,创建系统服务 创建电池服务,获得电池灯;创建监听者监听上报电池事件: mSystemServiceMana ...

  2. 8、Struts2 运行流程分析

    1.流程分析: 请求发送给 StrutsPrepareAndExecuteFilter StrutsPrepareAndExecuteFilter 询问 ActionMapper: 该请求是否是一个 ...

  3. freeswitch呼叫流程分析

    今天翻文档时发现之前整理的关于freeswitch呼叫相关的内容,写成博文分享出来也方便我以后查阅. 整体结构图 FreeswitchCore 模块加载过程 freeswitch主程序初始化时会从mo ...

  4. u-boot 流程分析

    u-boot 介绍: 对于计算机来说 , 从一开始上机通电是无法直接启动操作系统的 , 这中间需要一个引导过程 , 嵌入式Linux系统同样离不开引导程序 ,  这个启动程序就叫启动加载程序(Boot ...

  5. thttpd和cgilua安装与运行流程分析

    安装 参考如下博文安装thttpd软件 http://blog.csdn.net/21aspnet/article/details/7045845 http://blog.csdn.net/drago ...

  6. 【转】Hostapd工作流程分析

    [转]Hostapd工作流程分析 转自:http://blog.chinaunix.net/uid-30081165-id-5290531.html Hostapd是一个运行在用户态的守护进程,可以通 ...

  7. u-boot中nandflash初始化流程分析(转)

    u-boot中nandflash初始化流程分析(转) 原文地址http://zhuairlunjj.blog.163.com/blog/static/80050945201092011249136/ ...

  8. Android7.0 Phone应用源码分析(二) phone来电流程分析

    接上篇博文:Android7.0 Phone应用源码分析(一) phone拨号流程分析 今天我们再来分析下Android7.0 的phone的来电流程 1.1TelephonyFramework 当有 ...

  9. runc start container流程分析

    1.runc/start.go Action: func(context *cli.Context) error 该函数首先调用container, err := getContainer(conte ...

随机推荐

  1. 小白:String函数总结

    string.h函数: 1.strlen 数出字符串存在多少字符: 2.strcmp 比较两个字符串,若相等返回0不相等返回1 3.strcpy(char *restrict dst,const ch ...

  2. Linux 系统编程 学习:09-线程:线程的创建、回收与取消

    Linux 系统编程 学习:09-线程:线程的创建.回收与取消 背景 我们在此之前完成了 有关进程的学习.从这一讲开始我们学习线程. 完全的开发可以参考:<多线程编程指南> 在Linux ...

  3. 深入理解golang:内存分配原理

    一.Linux系统内存 在说明golang内存分配之前,先了解下Linux系统内存相关的基础知识,有助于理解golang内存分配原理. 1.1 虚拟内存技术 在早期内存管理中,如果程序太大,超过了空闲 ...

  4. Miller-Rabin 素数检验算法

    算法简介 Miller-Rabin算法,这是一个很高效的判断质数的方法,可以在用\(O(logn)\) 的复杂度快速判断一个数是否是质数.它运用了费马小定理和二次探测定理这两个筛质数效率极高的方法. ...

  5. Ubuntu 18.04 Tomcat 端口号查询

    参考http://blog.csdn.net/liufuwu1/article/details/71123597 最近几天发现许多这篇笔记被许多朋友访问,推测有很多朋友也与我有相同的疑惑,而原始版本过 ...

  6. leetcode26:valid-palindrome

    题目描述 判断题目给出的字符串是不是回文,仅考虑字符串中的字母字符和数字字符,并且忽略大小写 例如:"A man, a plan, a canal: Panama"是回文 &quo ...

  7. Spring中基于XML的声明式事务控制配置步骤

    1.配置事务管理器 2.配置事务的通知 此时,我们就需要导入事务的约束 tx名称空间和约束,同时也需要aop的 使用tx:advice标签配置事务通知 属性: id:给事务通知起一个唯一标识 tran ...

  8. 你还再为下载jar包慢而烦恼吗?Maven配置阿里云镜像

    Maven配置阿里云镜像 为什么我们下载jar这么慢 maven默认会从中央仓库下载jar包,这个仓库在国外,而且全世界的人都会从这里下载,所以下载速度肯定是非常慢的. 解决方案使用镜像 什么是镜像? ...

  9. 完全卸载node.js

    1.通过控制面板卸载node.js 2.删除安装所在文件夹下的nodejs文件夹[我的是 C:\Program Files\nodejs] 3.删除C:\Users\xxx(自己电脑的名字)下的.np ...

  10. centos常用指令之-卸载

    卸载centos自带java: rpm -qa|grep java // 查询javax相关 xxxxxxxxxxxxxx # 卸载1.2方式 # 1 yum -y remove java xxxxx ...