PowerManagerService流程分析


一、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的流程並不復雜,不過需要靜下心來分析代碼仍然不是一件很容易的事情,本人水平有限,有不足之處請指出,后續我會持續更新修改。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM