PowerManagerService原始碼分析

若曲一風發表於2019-04-25

1.定義

  PowerManagerService(以下簡稱PMS)是Android系統電源管理的核心服務,它在Framework層建立起一個策略控制方案,向下決策HAL以及kernel層來控制裝置待機狀態,控制螢幕,背光燈,距離感測器,光線感測器等硬體裝置的狀態。向上提供給應用程式相應的操作介面來保持系統處於喚醒狀態,比如音樂播放時持續保持系統喚醒,應用通知來臨喚醒手機螢幕等場景。它的啟動方式和AlarmManagerService大同小異,只不過PMS是在SystemServer中的引導服務中啟動,AMS是在SystemServer中的其他服務中啟動。啟動時序圖如下:

PowerManagerService原始碼分析

2.PowerManager

  PowerManager是PowerManagerService的代理類,它對外提供了操作PMS的介面函式,真正的處理工作則是在PMS中。獲取PowerManager的例項方式和AlarmManager一樣,時序圖也類似,這裡不做過多講解。在PowerManager中只有部分方法對上層應用開放,相關部分介面如下:

(1)isScreenOn():獲取螢幕是否亮起;

(2)reboot(xx):用於重啟裝置,但是需要REBOOT許可權;

(3)isPowerSaveMode():獲取系統是否處於省電模式;

(4)isDeviceIdleMode():系統是否處於idle狀態;

(5)newWakeLock(xx):生成新的wakelock例項;

(6)wakeUp(xx):用於強制喚醒系統;@hide

(7)shutdown(xx):關機;@hide

(8)userActivity(xx):用於通知PowerMangerService有使用者活動發生了,並重新計算自動滅屏時間同時如果系統沒有進入睡眠則點亮螢幕,比如使用者點選了螢幕等;@hide

(9)goToSleep(xx):強制使系統進入到睡眠狀態;當使用者按了power鍵則會呼叫該方法;@hide

(10)boostScreenBrightness(xx):將螢幕亮度調到最大值;@hide

(11) setPowerSaveMode;設定系統省電模式是否開啟;@hide;

(12)and so on;

  在PowerManager中所有的方法實現最後都是通過Binder的方式呼叫到PowerManagerService中的函式進行實現的。所以後面對PowerManagerService的實現進行講解,在講解PMS之前先來了解一下wakelock機制。

3.WakeLock機制

  Wakelock是一種鎖的機制,當使用者通過PowerManager獲取到該鎖之後那麼系統就不能進入到休眠狀態,直到該鎖被釋放為止。

3.1 生成wakeLock例項

  在Android中通過PowerManager對系統電源狀態進行管理。而在實際開發過程中,我們使用PowerManager主要是為了通過它獲取一個WakeLock鎖,用於控制當前裝置的一些耗電操作。WakeLock是PowerManager中的內部類,我們需要通過PowerManager中的newWakeLock(int levelAndFlags,String tag)方法生成例項,程式碼如下:

public WakeLock newWakeLock(int levelAndFlags, String tag) {
    //判斷使用者傳入的levelAndFlags以及tag是否合法
    validateWakeLockParameters(levelAndFlags, tag);
    return new WakeLock(levelAndFlags, tag, mContext.getOpPackageName());
}
複製程式碼

3.2 levelAndFlags值講解

(1)PARTIAL_WAKE_LOCK:使CPU高速執行,螢幕和鍵盤光關閉;

(2)SCREEN_DIM_WAKE_LOCK:確保螢幕亮起,但是允許它是最低亮度;已經被廢棄;

(3)SCREEN_BRIGHT_WAKE_LOCK:保證螢幕亮起,並且是最大亮度;已經被廢棄;

(4)FULL_WAKE_LOCK:保證螢幕和鍵盤背光是以最大亮度亮起;已經被廢棄;

(5)PROXIMITY_SCREEN_OFF_WAKE_LOCK:用於和接近感測器配合使用,來實現電話類應用中當手機貼近耳朵的時候將螢幕熄滅,而離開的時候又使螢幕亮起;

(6)DOZE_WAKE_LOCK:系統級別的flag,在DreamManager中被使用;

(7)DRAW_WAKE_LOCK:系統級別的flag,在WindowManager中被使用。

3.3 WakeLock的使用

(1)即使持有多次wakelock鎖也只需要一次釋放;

(2)持有多少次wakelock鎖就需要釋放多少次;

(3)設定wakelock超時時間,超時之後自動釋放,可以手動釋放;

持有wakelock鎖程式碼如下:

private void acquireLocked() {
        //用於統計呼叫當前wakelock多少次
        mInternalCount++;
        mExternalCount++;
        //mRefCounted表示是否通過計數的方式使用wakelock,預設為true:
        //true:那麼acquire了多少次就需要release多少次;實際情況就是在第一次呼叫的
        //時候才會真正去獲取wakelock鎖,最後一次釋放的時候才會真正釋放wakelock鎖
        //false:那麼即使呼叫了多次也只需要釋放一次
        if (!mRefCounted || mInternalCount == 1) {
            mHandler.removeCallbacks(mReleaser);
            Trace.asyncTraceBegin(Trace.TRACE_TAG_POWER, mTraceName, 0);
            try {
                //呼叫到PowerManagerService中
                mService.acquireWakeLock(mToken, mFlags, mTag, mPackageName, mWorkSource,
                        mHistoryTag);
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
            mHeld = true;
        }
    }
複製程式碼

釋放wakelock鎖程式碼如下:

 public void release(int flags) {
        synchronized (mToken) {
            //將呼叫次數減1
            if (mInternalCount > 0) {
                mInternalCount--;
            }
            //RELEASE_FLAG_TIMEOUT表示是通過設定超時時間的方式持有wakelock鎖的
            if ((flags & RELEASE_FLAG_TIMEOUT) == 0) {
                mExternalCount--;
            }
            if (!mRefCounted || mInternalCount == 0) {
                mHandler.removeCallbacks(mReleaser);
                if (mHeld) {
                    Trace.asyncTraceEnd(Trace.TRACE_TAG_POWER, mTraceName, 0);
                    try {
                        mService.releaseWakeLock(mToken, flags);
                    } catch (RemoteException e) {
                        throw e.rethrowFromSystemServer();
                    }
                    mHeld = false;
                }
            }
            //如果是持有多少次wakelock鎖就需要釋放多少次wakelock鎖
            //那麼釋放wakelock之前必須先持有wakelock鎖
            if (mRefCounted && mExternalCount < 0) {
                throw new RuntimeException("WakeLock under-locked " + mTag);
            }
        }
    }
複製程式碼

4.PMS中各個方法講解

4.1 wakeup

  該方法用於強制喚醒系統,通過PowerManager呼叫到PMS中的wakeUp(xx)方法中,首先檢查使用者是否新增了DEVICE_POWER許可權並獲取應用的uid,最後呼叫wakeUpNoUpdateLocked(xx)函式和updatePowerStateLocked()函式,部分程式碼如下所示:

mDirty:用於標識哪個狀態改變了或者需要被重新計算

 private boolean wakeUpNoUpdateLocked(long eventTime, String reason, int reasonUid,String opPackageName,
                                                    int opUid) {
    //判斷喚醒的時間是否小於上一次睡眠時間或者系統處於睡眠時間或者系統還沒有完全啟動或者系統還沒有ready
    //則不進行喚醒
    if (eventTime < mLastSleepTime || mWakefulness == WAKEFULNESS_AWAKE
            || !mBootCompleted || !mSystemReady) {
        return false;
    }
    Trace.traceBegin(Trace.TRACE_TAG_POWER, "wakeUp");
    try {
        .......
        //更新上一次喚醒時間
        mLastWakeTime = eventTime;
        //呼叫鏈:mNotifier.onWakeUp(xx)-->BatteryStatsService.noteWakeUp(xx)-->
        //BatteryStatsImpl.noteWakeUpLocke(xx)-->BatteryStatsImpl.addHistoryEventLocked(xx)
        mNotifier.onWakeUp(reason, reasonUid, opPackageName, opUid);
        userActivityNoUpdateLocked(eventTime, PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, reasonUid);
    } finally {
        Trace.traceEnd(Trace.TRACE_TAG_POWER);
    }
    return true;
}
複製程式碼

4.2 userActivity

  用於通知PowerManagerService有使用者活動發生,並重新計算自動滅屏時間以及在系統沒有進入睡眠的時候重新點亮螢幕;比如使用者點選螢幕或者按鍵等操作都會觸發到該函式中。當從PowerManager中通過Binder的方式呼叫到PowerManagerService中首先會進行許可權的檢測,然後呼叫到userActivityNoUpdateLocked和updatePowerStateLocked方法中,部分程式碼如下:

 //更新使用者活動上一次觸發時間以及mDirty標籤等
 private boolean userActivityNoUpdateLocked(long eventTime, int event, int flags, int uid) {
    //如果當前觸發時間小於上一次睡眠時間或者小於上一次喚醒時間(時間不合法)等則直接返回false
    if (eventTime < mLastSleepTime || eventTime < mLastWakeTime
            || !mBootCompleted || !mSystemReady) {
        return false;
    }
    Trace.traceBegin(Trace.TRACE_TAG_POWER, "userActivity");
    try {
        //如果觸發時間大於上一次喚醒螢幕時間,更新上一次喚醒螢幕時間
        if (eventTime > mLastInteractivePowerHintTime) {
            powerHintInternal(PowerHint.INTERACTION, 0);
            mLastInteractivePowerHintTime = eventTime;
        }
        mNotifier.onUserActivity(event, uid);
        if (mUserInactiveOverrideFromWindowManager) {
            mUserInactiveOverrideFromWindowManager = false;
            mOverriddenTimeout = -1;
        }
        //如果系統處於睡眠或者doze狀態那麼直接返回false
        if (mWakefulness == WAKEFULNESS_ASLEEP
                || mWakefulness == WAKEFULNESS_DOZING
                || (flags & PowerManager.USER_ACTIVITY_FLAG_INDIRECT) != 0) {
            return false;
        }
        //如果有應用Activity在前臺,則更新該應用前臺時間
        maybeUpdateForegroundProfileLastActivityLocked(eventTime);
        //如果設定了螢幕已經變暗但是延長螢幕當前亮度的時間flag值
        if ((flags & PowerManager.USER_ACTIVITY_FLAG_NO_CHANGE_LIGHTS) != 0) {
            //如果當前觸發時間大於上一次延長螢幕當前亮度觸發時間以及上一次讓螢幕更亮的觸發時間
            if (eventTime > mLastUserActivityTimeNoChangeLights
                    && eventTime > mLastUserActivityTime) {
                mLastUserActivityTimeNoChangeLights = eventTime;
                //給PMS中的標籤新增有使用者活動發生標籤
                mDirty |= DIRTY_USER_ACTIVITY;
                //如果是按鈕被點選或者被釋放的使用者活動
                if (event == PowerManager.USER_ACTIVITY_EVENT_BUTTON) {
                    mDirty |= DIRTY_QUIESCENT;
                }
                return true;
            }
        } else {
            //更新上一次使用者活動觸發時間
            if (eventTime > mLastUserActivityTime) {
                mLastUserActivityTime = eventTime;
                mDirty |= DIRTY_USER_ACTIVITY;
                if (event == PowerManager.USER_ACTIVITY_EVENT_BUTTON) {
                    mDirty |= DIRTY_QUIESCENT;
                }
                return true;
            }
        }
    } finally {
        Trace.traceEnd(Trace.TRACE_TAG_POWER);
    }
    return false;
}
複製程式碼

4.3 goToSleep

  強制系統進入到休眠狀態,並覆蓋掉所有正在執行的wakelock,在使用者按了power鍵之後會被觸發。在PowerManager中通過Bidner的方式呼叫到PMS中,首先進行許可權檢測,然後呼叫到goToSleepInternal(xx)方法中,最後呼叫到goToSleepNoUpdateLocked和updatePowerStateLocked方法,部分程式碼如下:

  private boolean goToSleepNoUpdateLocked(long eventTime, int reason, int flags, int uid) {
    //如果觸發時間小於上一次喚醒時間或者系統處於睡眠或者doze狀態,或者系統沒有完全啟動或者系統沒有準備完全
    //直接返回false
    if (eventTime < mLastWakeTime || mWakefulness == WAKEFULNESS_ASLEEP|| mWakefulness == WAKEFULNESS_DOZING
            || !mBootCompleted || !mSystemReady) {
        return false;
    }

    Trace.traceBegin(Trace.TRACE_TAG_POWER, "goToSleep");
    try {
        //更新上一次進入睡眠時間
        mLastSleepTime = eventTime;
        //可以開啟屏保
        mSandmanSummoned = true;
        //將當前設定為doze狀態
        setWakefulnessLocked(WAKEFULNESS_DOZING, reason);
        //用於記錄在系統進入到睡眠狀態的時候有多少wakelock會被清除掉
        int numWakeLocksCleared = 0;    
        final int numWakeLocks = mWakeLocks.size();
        for (int i = 0; i < numWakeLocks; i++) {
            final WakeLock wakeLock = mWakeLocks.get(i);
            switch (wakeLock.mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK) {
                case PowerManager.FULL_WAKE_LOCK:
                case PowerManager.SCREEN_BRIGHT_WAKE_LOCK:
                case PowerManager.SCREEN_DIM_WAKE_LOCK:
                    numWakeLocksCleared += 1;
                    break;
            }
        }
        EventLogTags.writePowerSleepRequested(numWakeLocksCleared);

        // 將系統設定為睡眠狀態
        if ((flags & PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE) != 0) {
            reallyGoToSleepNoUpdateLocked(eventTime, uid);
        }
    } finally {
        Trace.traceEnd(Trace.TRACE_TAG_POWER);
    }
    return true;
}
複製程式碼

4.4 acquireWakeLockInternal

  PowerManager通過Binder的方式呼叫到PMS的acquireWakeLock(xx)方法之後,首先進行許可權檢測,然後獲取到呼叫Binder的uid和Pid,並傳遞到acquireWakeLockInternal(xx)方法中;最後再呼叫到updatePowerStateLocked()方法,更新電源狀態。部分程式碼如下所示:

 private void acquireWakeLockInternal(IBinder lock, int flags, String tag, String packageName,
                                     WorkSource ws, String historyTag, int uid, int pid) {
    synchronized (mLock) {
        WakeLock wakeLock;
        //從儲存wakelock的列表中查詢是否存在當前設定的wakelock
        int index = findWakeLockIndexLocked(lock);
        boolean notifyAcquire;
        if (index >= 0) {
            wakeLock = mWakeLocks.get(index);
            //判斷設定的wakelock與列表中儲存的wakelock屬性是否發生了變化
            if (!wakeLock.hasSameProperties(flags, tag, ws, uid, pid)) {
                // Update existing wake lock.  This shouldn't happen but is harmless.
                notifyWakeLockChangingLocked(wakeLock, flags, tag, packageName,
                        uid, pid, ws, historyTag);
                wakeLock.updateProperties(flags, tag, packageName, ws, historyTag, uid, pid);
            }
            notifyAcquire = false;
        //建立一個新的wakelock並新增到wakelocks列表中去
        } else {
            ..................
            mWakeLocks.add(wakeLock);
            setWakeLockDisabledStateLocked(wakeLock);
            notifyAcquire = true;
        }
        
        applyWakeLockFlagsOnAcquireLocked(wakeLock, uid);
        mDirty |= DIRTY_WAKE_LOCKS;
        updatePowerStateLocked();
        if (notifyAcquire) {
            // This needs to be done last so we are sure we have acquired the
            // kernel wake lock.  Otherwise we have a race where the system may
            // go to sleep between the time we start the accounting in battery
            // stats and when we actually get around to telling the kernel to
            // stay awake.
            //傳送wakelock已經執行通知
            notifyWakeLockAcquiredLocked(wakeLock);
        }
    }
}

private void applyWakeLockFlagsOnAcquireLocked(WakeLock wakeLock, int uid) {
    //如果當前wakelock能夠喚醒螢幕,且當前wakelock鎖設定的flag也能夠喚醒螢幕
    if ((wakeLock.mFlags & PowerManager.ACQUIRE_CAUSES_WAKEUP) != 0
            && isScreenLock(wakeLock)) {
        String opPackageName;
        int opUid;
        //更新包名
        if (wakeLock.mWorkSource != null && wakeLock.mWorkSource.getName(0) != null) {
            opPackageName = wakeLock.mWorkSource.getName(0);
            opUid = wakeLock.mWorkSource.get(0);
        } else {
            opPackageName = wakeLock.mPackageName;
            opUid = wakeLock.mWorkSource != null ? wakeLock.mWorkSource.get(0)
                    : wakeLock.mOwnerUid;
        }
        //更新上一次發生時間
        wakeUpNoUpdateLocked(SystemClock.uptimeMillis(), wakeLock.mTag, opUid,
                opPackageName, opUid);
    }
    
private boolean wakeUpNoUpdateLocked(long eventTime, String reason, int reasonUid,
                                     String opPackageName, int opUid) {
    //如果系統開機時間小於上一次睡眠時間或者當前系統處於喚醒狀態或者系統沒有啟動完全則直接返回false
    if (eventTime < mLastSleepTime || mWakefulness == WAKEFULNESS_AWAKE
            || !mBootCompleted || !mSystemReady) {
        return false;
    }
    Trace.asyncTraceBegin(Trace.TRACE_TAG_POWER, TRACE_SCREEN_ON, 0);
    Trace.traceBegin(Trace.TRACE_TAG_POWER, "wakeUp");
    ..............
        //更新上一次喚醒時間
        mLastWakeTime = eventTime;
        mNotifier.onWakeUp(reason, reasonUid, opPackageName, opUid);
        //更新使用者活動時間
        userActivityNoUpdateLocked(
                eventTime, PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, reasonUid);
    } finally {
        Trace.traceEnd(Trace.TRACE_TAG_POWER);
    }
    return true;
}
複製程式碼

4.5 updatePowerStateLocked

  該方法根據各個方法所設定的mDirty值來重新計算系統電源狀態。部分程式碼如下所示:

private void updatePowerStateLocked() {
    //如果系統還沒有準備好或者沒有任何改變則直接返回;
    if (!mSystemReady || mDirty == 0) {
        return;
    }
    Trace.traceBegin(Trace.TRACE_TAG_POWER, "updatePowerState");
    try {
        //用於更新充電以及電池狀態,充電方式,剩餘電量,是否是低電量,並記錄充電狀態是否改變以及是否在
        //插拔電之後亮屏等
        updateIsPoweredLocked(mDirty);
        //用於更新mStayOn變數,如果為true則表示螢幕長亮
        //如果設定中設定了可保持長亮,如果手機正在充電則會將mStayOn設定為true
        updateStayOnLocked(mDirty);
        //更新螢幕亮度超時時間,如果當前時間小於離上一次將亮度調整到最大到下一次亮度調整到最大的時間延遲
        //則在最小時間延遲之後才將亮度調整到最大
        updateScreenBrightnessBoostLocked(mDirty);
        final long now = SystemClock.uptimeMillis();
        int dirtyPhase2 = 0;
        //迴圈是因為wakelock和user activity的計算會受到Wakefulness的影響
        for (;;) {
            int dirtyPhase1 = mDirty;
            dirtyPhase2 |= dirtyPhase1;
            mDirty = 0;
            //將對應uid的wakelock的flag值更新到mProfilePowerState列表中對應item的mWakeLockSummary上
            //並根據系統狀態去除不必要的wakelock的flag值
            updateWakeLockSummaryLocked(dirtyPhase1);
            //根據系統最後一次呼叫userActivity(xx)方法的時間計算現在是否可以將螢幕狀態
            //mUserActivitySummary設定成亮屏或者暗屏或者屏保,當系統處於深度睡眠的時候則會忽略掉使用者活動
            updateUserActivitySummaryLocked(now, dirtyPhase1);
            //用於更新系統狀態,並且用於決定系統是否進入到屏保狀態。
            //返回true表示系統狀態發生了變化(進入了屏保或者休眠狀態),
            //那麼需要重新計算user Activity以及wakelock的flag值
            if (!updateWakefulnessLocked(dirtyPhase1)) {
                break;
            }
        }
        
        updateProfilesLocked(now);
        //更新裝置螢幕顯示,在該方法中會最終計算出螢幕亮度、是否自動調節亮度等值
        final boolean displayBecameReady = updateDisplayPowerStateLocked(dirtyPhase2);
        //更新屏保
        updateDreamLocked(dirtyPhase2, displayBecameReady);
        //系統狀態更新完成
        finishWakefulnessChangeIfNeededLocked();
        //可能需要釋放最後一個維持cpu喚醒或者螢幕亮滅的suspend鎖,所以需要確保所有的任務都已經完成
        //更新suspend鎖使螢幕處於喚醒狀態
        updateSuspendBlockerLocked();
    } finally {
        Trace.traceEnd(Trace.TRACE_TAG_POWER);
    }
}
 private void updateScreenBrightnessBoostLocked(int dirty) {
    //如果可以將螢幕亮度調節到了最大
    if ((dirty & DIRTY_SCREEN_BRIGHTNESS_BOOST) != 0) {
        if (mScreenBrightnessBoostInProgress) {
            final long now = SystemClock.uptimeMillis();
            mHandler.removeMessages(MSG_SCREEN_BRIGHTNESS_BOOST_TIMEOUT);
            //如果上一次調節螢幕亮度到最大的時間晚於上一次系統睡眠時間
            if (mLastScreenBrightnessBoostTime > mLastSleepTime) {
                //調節亮度到最大的下一次時間延遲 = 上一次調節亮度到最大 + 5s
                final long boostTimeout = mLastScreenBrightnessBoostTime +
                        SCREEN_BRIGHTNESS_BOOST_TIMEOUT;
                //如果調節亮度到最大的最小時間延遲大於當前時間,則在boostTimeOut時間通過handler重新觸發
                //才允許將亮度調整到最大
                if (boostTimeout > now) {
                    Message msg = mHandler.obtainMessage(MSG_SCREEN_BRIGHTNESS_BOOST_TIMEOUT);
                    msg.setAsynchronous(true);
                    mHandler.sendMessageAtTime(msg, boostTimeout);
                    return;
                }
            }
            //將是否正在調節亮度到最大置為false
            mScreenBrightnessBoostInProgress = false;
            mNotifier.onScreenBrightnessBoostChanged();
            //觸發使用者活動
            userActivityNoUpdateLocked(now,
                    PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, Process.SYSTEM_UID);
        }
    }
}
 private void updateWakeLockSummaryLocked(int dirty) {
    //如果wakelock和WAKEFULNESS改變了則繼續執行
    if ((dirty & (DIRTY_WAKE_LOCKS | DIRTY_WAKEFULNESS)) != 0) {
        mWakeLockSummary = 0;

        final int numProfiles = mProfilePowerState.size();
        //mProfilePowerState:用於儲存使用者設定的螢幕滅屏時間
        for (int i = 0; i < numProfiles; i++) {
            mProfilePowerState.valueAt(i).mWakeLockSummary = 0;
        }
    
        final int numWakeLocks = mWakeLocks.size();
        for (int i = 0; i < numWakeLocks; i++) {
            final WakeLock wakeLock = mWakeLocks.get(i);
            //根據wakelock的flag值來確定系統的狀態(cpu執行、螢幕變數或者變暗等)
            final int wakeLockFlags = getWakeLockSummaryFlags(wakeLock);
            //將wakelock的flag值更新到mWakeLockSummary中
            mWakeLockSummary |= wakeLockFlags;
            for (int j = 0; j < numProfiles; j++) {
                final ProfilePowerState profile = mProfilePowerState.valueAt(j);
                //將對應uid的wakelock的flag值更新到mProfilePowerState中item對應uid的mWakeLockSummary中
                if (wakeLockAffectsUser(wakeLock, profile.mUserId)) {
                    profile.mWakeLockSummary |= wakeLockFlags;
                }
            }
        }
        //如果系統不處於doze狀態則從mWakeLockSummary中移除doze和dream標籤
        if (mWakefulness != WAKEFULNESS_DOZING) {
            mWakeLockSummary &= ~(WAKE_LOCK_DOZE | WAKE_LOCK_DRAW);
        }
        //如果系統處於睡眠狀態或者有wakelock有doze標籤則系統不允許亮屏
        if (mWakefulness == WAKEFULNESS_ASLEEP
                || (mWakeLockSummary & WAKE_LOCK_DOZE) != 0) {
            //從mWakeLockSummary中去掉
            mWakeLockSummary &= ~(WAKE_LOCK_SCREEN_BRIGHT | WAKE_LOCK_SCREEN_DIM
                    | WAKE_LOCK_BUTTON_BRIGHT);
        }
        //根據系統狀態重新調整mWakeLockSummary值(去除不必要的wakelockflag值)
        mWakeLockSummary = adjustWakeLockSummaryLocked(mWakeLockSummary);
        for (int i = 0; i < numProfiles; i++) {
            final ProfilePowerState profile = mProfilePowerState.valueAt(i);
            profile.mWakeLockSummary = adjustWakeLockSummaryLocked(profile.mWakeLockSummary);
        }
    }
 }

private void updateUserActivitySummaryLocked(long now, int dirty) {
    //如果有使用者活動發生
    if ((dirty & (DIRTY_WAKE_LOCKS | DIRTY_USER_ACTIVITY
            | DIRTY_WAKEFULNESS | DIRTY_SETTINGS)) != 0) {
        mHandler.removeMessages(MSG_USER_ACTIVITY_TIMEOUT);
    
        long nextTimeout = 0;
        //系統出喚醒或者dream或者doze狀態
        if (mWakefulness == WAKEFULNESS_AWAKE
                || mWakefulness == WAKEFULNESS_DREAMING
                || mWakefulness == WAKEFULNESS_DOZING) {
            //獲取系統進入休眠時間,該時間大於等於螢幕最小滅屏時間
            final long sleepTimeout = getSleepTimeoutLocked();
            //獲取螢幕滅屏時間
            final long screenOffTimeout = getScreenOffTimeoutLocked(sleepTimeout);
            //獲取螢幕處於亮度很暗持續時間
            final long screenDimDuration = getScreenDimDurationLocked(screenOffTimeout);
            //通過windowmanager的使用者互動
            final boolean userInactiveOverride = mUserInactiveOverrideFromWindowManager;
            //系統下次休眠時間
            final long nextProfileTimeout = getNextProfileTimeoutLocked(now);
            mUserActivitySummary = 0;
            if (mLastUserActivityTime >= mLastWakeTime) {
                //系統下次睡眠時間 = 上一次使用者活動時間 + 滅屏時間 - 螢幕處於暗屏持續時間
                nextTimeout = mLastUserActivityTime
                        + screenOffTimeout - screenDimDuration;
                //如果當前時間小於下一次系統睡眠時間,說明此時是亮屏狀態
                if (now < nextTimeout) {
                    mUserActivitySummary = USER_ACTIVITY_SCREEN_BRIGHT;
                } else {
                    //下一次滅屏時間 = 上一次使用者活動時間 + 滅屏時間
                    nextTimeout = mLastUserActivityTime + screenOffTimeout;
                    //如果當前時間小於下一次滅屏時間,那麼系統此時處於暗屏狀態
                    if (now < nextTimeout) {
                        mUserActivitySummary = USER_ACTIVITY_SCREEN_DIM;
                    }
                }
            }
            //如果上一次使用者活動時間 > 上一次喚醒時間
            if (mUserActivitySummary == 0&& mLastUserActivityTimeNoChangeLights >= mLastWakeTime) {
                //下一次滅屏時間 = 上一次使用者活動時間 + 滅屏時間
                nextTimeout = mLastUserActivityTimeNoChangeLights + screenOffTimeout;
                //如果當前時間 < 下一次滅屏時間
                if (now < nextTimeout) {
                    //根據mDisplayPowerRequest.policy設定螢幕狀態
                    if (mDisplayPowerRequest.policy == DisplayPowerRequest.POLICY_BRIGHT
                            || mDisplayPowerRequest.policy == DisplayPowerRequest.POLICY_VR) {
                        mUserActivitySummary = USER_ACTIVITY_SCREEN_BRIGHT;
                    } else if (mDisplayPowerRequest.policy == DisplayPowerRequest.POLICY_DIM) {
                        mUserActivitySummary = USER_ACTIVITY_SCREEN_DIM;
                    }
                }
            }
            if (mUserActivitySummary == 0) {
                //如果系統進入休眠時間 >= 0
                if (sleepTimeout >= 0) {
                    //獲取上一次使用者活動時間兩種flag的最大值
                    final long anyUserActivity = Math.max(mLastUserActivityTime,
                            mLastUserActivityTimeNoChangeLights);
                    //如果上一次使用者活動時間 >= 上一次喚醒時間
                    if (anyUserActivity >= mLastWakeTime) {
                        //下一次休眠時間 = 上一次使用者活動時間 + 系統進入休眠時間
                        nextTimeout = anyUserActivity + sleepTimeout;
                        //如果當前時間 < 下一次休眠時間則將螢幕狀態置為屏保狀態
                        if (now < nextTimeout) {
                            mUserActivitySummary = USER_ACTIVITY_SCREEN_DREAM;
                        }
                    }
                } else {
                    mUserActivitySummary = USER_ACTIVITY_SCREEN_DREAM;
                    nextTimeout = -1;
                }
            }
            if (mUserActivitySummary != USER_ACTIVITY_SCREEN_DREAM && userInactiveOverride) {
                if ((mUserActivitySummary &
                        (USER_ACTIVITY_SCREEN_BRIGHT | USER_ACTIVITY_SCREEN_DIM)) != 0) {
                    //系統因為最近的使用者活動保持為喚醒狀態
                    if (nextTimeout >= now && mOverriddenTimeout == -1) {
                        // Save when the next timeout would have occurred
                        mOverriddenTimeout = nextTimeout;
                    }
                }
                mUserActivitySummary = USER_ACTIVITY_SCREEN_DREAM;
                nextTimeout = -1;
            }
            //計算下一次滅屏時間
            if (nextProfileTimeout > 0) {
                nextTimeout = Math.min(nextTimeout, nextProfileTimeout);
            }
            //在nextTimeout時間之後傳送message給handler進行處理,再次觸發updatePowerStateLocked()進行重新整理
            if (mUserActivitySummary != 0 && nextTimeout >= 0) {
                scheduleUserInactivityTimeout(nextTimeout);
            }
        } else {
            mUserActivitySummary = 0;
        }
    }
}
 
//該方法會根據當前的wakelocks以及user Activity判斷裝置進入到屏保狀態
 private boolean updateWakefulnessLocked(int dirty) {
    boolean changed = false;
    //如果系統中有狀態變化
    if ((dirty & (DIRTY_WAKE_LOCKS | DIRTY_USER_ACTIVITY | DIRTY_BOOT_COMPLETED
            | DIRTY_WAKEFULNESS | DIRTY_STAY_ON | DIRTY_PROXIMITY_POSITIVE
            | DIRTY_DOCK_STATE)) != 0) {
        //如果系統是喚醒狀態且系統需要馬上進入到睡眠狀態
        if (mWakefulness == WAKEFULNESS_AWAKE && isItBedTimeYetLocked()) {
            final long time = SystemClock.uptimeMillis();
            //返回true表示手機會自動進入屏保
            if (shouldNapAtBedTimeLocked()) {
                changed = napNoUpdateLocked(time, Process.SYSTEM_UID);
            } else {
                //系統進入了深度睡眠
                changed = goToSleepNoUpdateLocked(time,
                        PowerManager.GO_TO_SLEEP_REASON_TIMEOUT, 0, Process.SYSTEM_UID);
            }
        }
    }
    return changed;
}
複製程式碼

4.6 PowerManagerInternal中定義了四種WakeFulness值用於標識系統當前的狀態:

(1)WAKEFULNESS_ASLEEP:表示系統當前處於休眠狀態,只能被wakeup()喚醒;

(2)WAKEFULNESS_AWAKE:表示系統目前處於正常執行狀態;

(3)WAKEFULNESS_DREAMING:表示系統當前處於屏保狀態;

(4)WAKEFULNESS_DOZING:表示系統處於doze狀態。

5 總結

  從上面的分析來看,對於PowerManagerService中的資料處理流程可以歸結為如下的步驟:

(1)使用者通過呼叫PowerManager進行資料處理;

(2)PowerManager通過Binder的方式呼叫到PMS中;

(3)PMS中的方法首先進行許可權檢測並獲取到呼叫Binder應用的uid以及pid;

(4)判斷時間是否合法;

(5)更新上一次相關時間;

(6)呼叫到updatePowerStateLocked()方法中,最後通過方法updateSuspendBlockerLocked()呼叫到底層更新suspen鎖以保持cpu喚醒。

至此,PMS中比較重要的程式碼算是記錄完了,當然裡面還有很多細節部分需要不斷的完善閱讀,這樣才能不斷的將PMS的核心理解的更加透徹。

參考連結:juejin.im/post/5921ca…

相關文章