深入了解PowerManagerService(一)之Android 11.0 Power 键亮屏灭屏流程分析

创作不易,请尊重原创,转载须注明出处:https://blog.csdn.net/An_Times/article/details/120027015

一、前言

环境:本文基于MTK 6765 Android 11


PowerManagerService(下文简称PMS)是Android系统的核心服务之一,控制着系统的亮灭屏,电源管理,等等重要的功能,本文将先从Power键亮灭屏流程分析入手去了解PMS。


二、PhoneWindowManager中Power键按键响应流程


  • 代码路径:
    frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java.`

  • Power键按键处理是在PhoneWindowManager中,分为按下事件和松开事件。interceptKeyBeforeDispatching方法中也是根据是按下事件还是松开事件分别对应处理。final boolean down = event.getAction() == KeyEvent.ACTION_DOWN;

  • 按下power键事件对应处理方法是interceptPowerKeyDown(event, interactive);

  • 松开power键事件对应处理方法是interceptPowerKeyUp(event, interactive, canceled);

 // TODO(b/117479243): handle it in InputPolicy
    /** {@inheritDoc} */
    @Override
    public long interceptKeyBeforeDispatching(IBinder focusedToken, KeyEvent event,
            int policyFlags) {
 
 ...省略部分代码
            case KeyEvent.KEYCODE_POWER: {
                EventLogTags.writeInterceptPower(
                        KeyEvent.actionToString(event.getAction()),
                        mPowerKeyHandled ? 1 : 0, mPowerKeyPressCounter);
                // Any activity on the power button stops the accessibility shortcut
                cancelPendingAccessibilityShortcutAction();
                result &= ~ACTION_PASS_TO_USER;
                isWakeKey = false; // wake-up will be handled separately
                if (down) {
                    interceptPowerKeyDown(event, interactive);
                } else {
                    interceptPowerKeyUp(event, interactive, canceled);
                }
                break;
            }
 ...省略部分代码

        // Let the application handle the key.
        return 0;
    }

Power键按下事件处理方法 interceptPowerKeyDown 主要做以下几件事:

  • 1、获得一个PARTIAL_WAKE_LOCK 保持CPU运行,WAKE_LOCK这里不介绍,后面文章在介绍。
  • 2、判断是否是组合键截图事件,并做对应的处理。
  • 3、判断是否开启了对应的功能,power键可以直接挂断电话或者关闭来电响铃。
  • 4、判断是否是手势事件对应处理。
  • 5、根据interactive 当前是否Awake判断,如果是唤醒状态,则处理Power键长按事件, 如果不是唤醒状态即灭屏状态,则调用 wakeUpFromPowerKey 方法唤醒。
  • 6、统计Power键按键次数
    private void interceptPowerKeyDown(KeyEvent event, boolean interactive) {
        // Hold a wake lock until the power key is released.
        //获得一个PARTIAL_WAKE_LOCK 保持CPU运行,WAKE_LOCK这里不介绍,后面文章在介绍。
        if (!mPowerKeyWakeLock.isHeld()) {
            mPowerKeyWakeLock.acquire();
        }

        // Cancel multi-press detection timeout.
        if (mPowerKeyPressCounter != 0) {
            mHandler.removeMessages(MSG_POWER_DELAYED_PRESS);
        }

        mWindowManagerFuncs.onPowerKeyDown(interactive);

        //2、判断是否是组合键截图事件,并做对应的处理。
        // Latch power key state to detect screenshot chord.
        if (interactive && !mScreenshotChordPowerKeyTriggered
                && (event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) {
            mScreenshotChordPowerKeyTriggered = true;
            mScreenshotChordPowerKeyTime = event.getDownTime();
            interceptScreenshotChord();
            interceptRingerToggleChord();
        }

        //3、判断是否开启了对应的功能,power键可以直接挂断电话或者关闭来电响铃。
        // Stop ringing or end call if configured to do so when power is pressed.
        TelecomManager telecomManager = getTelecommService();
        boolean hungUp = false;
        if (telecomManager != null) {
            if (telecomManager.isRinging()) {
                // Pressing Power while there's a ringing incoming
                // call should silence the ringer.
                telecomManager.silenceRinger();
            } else if ((mIncallPowerBehavior
                    & Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_HANGUP) != 0
                    && telecomManager.isInCall() && interactive) {
                // Otherwise, if "Power button ends call" is enabled,
                // the Power button will hang up any current active call.
                hungUp = telecomManager.endCall();
            }
        }

        //4、判断是否是手势事件对应处理。
        GestureLauncherService gestureService = LocalServices.getService(
                GestureLauncherService.class);
        boolean gesturedServiceIntercepted = false;
        if (gestureService != null) {
            gesturedServiceIntercepted = gestureService.interceptPowerKeyDown(event, interactive,
                    mTmpBoolean);
            if (mTmpBoolean.value && mRequestedOrGoingToSleep) {
                mCameraGestureTriggeredDuringGoingToSleep = true;
            }
        }

        // Inform the StatusBar; but do not allow it to consume the event.
        sendSystemKeyToStatusBarAsync(event.getKeyCode());

        schedulePossibleVeryLongPressReboot();

        // If the power key has still not yet been handled, then detect short
        // press, long press, or multi press and decide what to do.
        mPowerKeyHandled = hungUp || mScreenshotChordVolumeDownKeyTriggered
                || mA11yShortcutChordVolumeUpKeyTriggered || gesturedServiceIntercepted;
        if (!mPowerKeyHandled) {
            if (interactive) {
                // When interactive, we're already awake.
                // Wait for a long press or for the button to be released to decide what to do.
                //interactive为true,当前是Awake状态即亮屏状态,处理亮屏下的Power键长按事件
                if (hasLongPressOnPowerBehavior()) {
                    if ((event.getFlags() & KeyEvent.FLAG_LONG_PRESS) != 0) {
                        powerLongPress();
                    } else {
                        Message msg = mHandler.obtainMessage(MSG_POWER_LONG_PRESS);
                        msg.setAsynchronous(true);
                        mHandler.sendMessageDelayed(msg,
                                ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout());

                        if (hasVeryLongPressOnPowerBehavior()) {
                            Message longMsg = mHandler.obtainMessage(MSG_POWER_VERY_LONG_PRESS);
                            longMsg.setAsynchronous(true);
                            mHandler.sendMessageDelayed(longMsg, mVeryLongPressTimeout);
                        }
                    }
                }
            } else {
                //interactive为false说明不是唤醒状态即灭屏状态,则调用 wakeUpFromPowerKey 方法唤醒系统。
                wakeUpFromPowerKey(event.getDownTime());

                if (mSupportLongPressPowerWhenNonInteractive && hasLongPressOnPowerBehavior()) {
                    if ((event.getFlags() & KeyEvent.FLAG_LONG_PRESS) != 0) {
                        powerLongPress();
                    } else {
                        Message msg = mHandler.obtainMessage(MSG_POWER_LONG_PRESS);
                        msg.setAsynchronous(true);
                        mHandler.sendMessageDelayed(msg,
                                ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout());

                        if (hasVeryLongPressOnPowerBehavior()) {
                            Message longMsg = mHandler.obtainMessage(MSG_POWER_VERY_LONG_PRESS);
                            longMsg.setAsynchronous(true);
                            mHandler.sendMessageDelayed(longMsg, mVeryLongPressTimeout);
                        }
                    }

                    mBeganFromNonInteractive = true;
                } else {
                    final int maxCount = getMaxMultiPressPowerCount();

                    if (maxCount <= 1) {
                        mPowerKeyHandled = true;
                    } else {
                        mBeganFromNonInteractive = true;
                    }
                }
            }
        }
    }


三、PowerManagerService 继续处理wakeup事件


3.1、power键按下时PowerManagerService 的wakeup到updatePowerStateLocked 调用过程

  • 代码路径:
    frameworks\base\services\core\java\com\android\server\power\PowerManagerService.java.
    `

  • 1、上文中 PhoneWindowManager的 wakeUpFromPowerKey 方法调用的是PowerManagerService 的WakeUp方法,再通过Binder 跨进程调用服务端PowerManagerServicewakeUp ,最后除非是当前已经是唤醒等情况,否则都会调用到updatePowerStateLocked方法。

  • 2、wakeUpNoUpdateLocked 只有在如下几种情况下为false,正常情况都是true。

    a)、当前事件时间比上次asleep 时间还早(这不可能,除非穿越了);

    b)、当前已经是WAKEFULNESS_AWAKE 唤醒状态;

    c)、mForceSuspendActive 为true,即有强制挂起激活标志;

    d)、刚开机系统没有Ready 好;

  • 3、wakeUpNoUpdateLocked主要是设置当前Wakefulness 为WAKEFULNESS_AWAKE ,然后通知wakeup,和调用userActivityNoUpdateLocked 更新用户活动时间,这个和超时休眠有关。

    ...此处省略部分代码

        @Override // Binder call
        public void wakeUp(long eventTime, @WakeReason int reason, String details,
                String opPackageName) {
            if (eventTime > mClock.uptimeMillis()) {
                throw new IllegalArgumentException("event time must not be in the future");
            }

            mContext.enforceCallingOrSelfPermission(
                    android.Manifest.permission.DEVICE_POWER, null);

            final int uid = Binder.getCallingUid();
            final long ident = Binder.clearCallingIdentity();
            try {
                wakeUpInternal(eventTime, reason, details, uid, opPackageName, uid);
            } finally {
                Binder.restoreCallingIdentity(ident);
            }
        }

    ...此处省略部分代码

     private void wakeUpInternal(long eventTime, @WakeReason int reason, String details, int uid,
            String opPackageName, int opUid) {
        synchronized (mLock) {
            /**wakeUpNoUpdateLocked 只有在如下几种情况下为false,正常情况都是true
            *1、当前事件时间比上次asleep 时间还早(这不可能,除非穿越了);
            *2、当前已经是WAKEFULNESS_AWAKE 唤醒状态;
            *3、mForceSuspendActive 为true,即有强制挂起激活标志;
            *4、刚开机系统没有Ready 好;
            */
            if (wakeUpNoUpdateLocked(eventTime, reason, details, uid, opPackageName, opUid)) {
                updatePowerStateLocked();
            }
        }
    }

    ...此处省略部分代码    

四、PowerManagerService 的核心方法 updatePowerStateLocked


  • 代码路径:
    frameworks\base\services\core\java\com\android\server\power\PowerManagerService.java.
    `

  • PMS中updatePowerStateLocked 方法调用的非常频繁并且非常的重要,里面的case 情况非常多,如果能搞清楚这个方法,基本上对PMS的逻辑流程就很熟悉了。

    /**
     * Updates the global power state based on dirty bits recorded in mDirty.
     *
     * This is the main function that performs power state transitions.
     * We centralize them here so that we can recompute the power state completely
     * each time something important changes, and ensure that we do it the same
     * way each time.  The point is to gather all of the transition logic here.
     */
    private void updatePowerStateLocked() {
        if (!mSystemReady || mDirty == 0) {
            return;
        }
        if (!Thread.holdsLock(mLock)) {
            Slog.wtf(TAG, "Power manager lock was not held when calling updatePowerStateLocked");
        }

        Trace.traceBegin(Trace.TRACE_TAG_POWER, "updatePowerState");
        try {
            // Phase 0: Basic state updates.
            //充电相关,插入充电器充电相关处理
            updateIsPoweredLocked(mDirty);
            //更新屏幕保持唤醒标识值mStayOn
            updateStayOnLocked(mDirty);
            //亮度增强相关
            updateScreenBrightnessBoostLocked(mDirty);

            // Phase 1: Update wakefulness.
            // Loop because the wake lock and user activity computations are influenced
            // by changes in wakefulness.
            final long now = mClock.uptimeMillis();
            int dirtyPhase2 = 0;
            for (;;) {
                int dirtyPhase1 = mDirty;
                dirtyPhase2 |= dirtyPhase1;
                mDirty = 0;

                updateWakeLockSummaryLocked(dirtyPhase1);
                updateUserActivitySummaryLocked(now, dirtyPhase1);
                updateAttentiveStateLocked(now, dirtyPhase1);
                if (!updateWakefulnessLocked(dirtyPhase1)) {
                    break;
                }
            }

            // Phase 2: Lock profiles that became inactive/not kept awake.
            updateProfilesLocked(now);

            // Phase 3: Update display power state.
            final boolean displayBecameReady = updateDisplayPowerStateLocked(dirtyPhase2);

            // Phase 4: Update dream state (depends on display ready signal).
            //更新屏保
            updateDreamLocked(dirtyPhase2, displayBecameReady);

            // Phase 5: Send notifications, if needed.
            finishWakefulnessChangeIfNeededLocked();

            // Phase 6: Update suspend blocker.
            // Because we might release the last suspend blocker here, we need to make sure
            // we finished everything else first!
            updateSuspendBlockerLocked();
        } finally {
            Trace.traceEnd(Trace.TRACE_TAG_POWER);
        }
    }

4.1 APP等进程向PowerManager申请的WakeLock在PowerManagerService中的名称变化


  • 1、这里先简单提一下WakeLock,我们保持屏幕唤醒申请的是PowerManager.PARTIAL_WAKE_LOCK ,使用距离传感器控制屏幕亮灭申请的是PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK 等等,这些是应用向PowerManager 申请的WakeLock,而且不同的应用申请各种WakeLock,因此在PMS 里面呢它用的是mWakeLockSummary与之对应,可以理解是持有wakeLock 的汇总概要,他的对应关系如下。
    /** Get wake lock summary flags that correspond to the given wake lock. */
    private int getWakeLockSummaryFlags(WakeLock wakeLock) {
        switch (wakeLock.mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK) {
            case PowerManager.PARTIAL_WAKE_LOCK:
                if (!wakeLock.mDisabled) {
                    // We only respect this if the wake lock is not disabled.
                    return WAKE_LOCK_CPU;
                }
                break;
            case PowerManager.FULL_WAKE_LOCK:
                return WAKE_LOCK_SCREEN_BRIGHT | WAKE_LOCK_BUTTON_BRIGHT;
            case PowerManager.SCREEN_BRIGHT_WAKE_LOCK:
                return WAKE_LOCK_SCREEN_BRIGHT;
            case PowerManager.SCREEN_DIM_WAKE_LOCK:
                return WAKE_LOCK_SCREEN_DIM;
            case PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK:
                return WAKE_LOCK_PROXIMITY_SCREEN_OFF;
            case PowerManager.DOZE_WAKE_LOCK:
                return WAKE_LOCK_DOZE;
            case PowerManager.DRAW_WAKE_LOCK:
                return WAKE_LOCK_DRAW;
        }
        return 0;
    }

4.2、updatePowerStateLocked 之 updateWakeLockSummaryLocked 整合PMS持有的wakelock 的状态


  • 1、PMS整合所持有的Wakelock 过程都是一些按位运算,刚开始看的时候直接搞懵逼了。后来多看几遍发现清楚多了。

  • 2、首选PMS获取从PowerManager里面申请的所有Wakelock的集合,然后将所有的Wakelock转化整合成 mWakeLockSummary。

  • 3、通过getWakefulnessLocked()获取当前设置的Wakefulness,这里power键按下事件在前面设置过是WAKEFULNESS_AWAKE 状态。然后根据当前的Wakefulness 和整合后的mWakeLockSummary,去对mWakeLockSummary重新赋值。

  • 4、profile.mWakeLockSummary这个干嘛用的,我也不懂,有清除的记得Call 我。
    /**
     * Updates the value of mWakeLockSummary to summarize the state of all active wake locks.
     * Note that most wake-locks are ignored when the system is asleep.
     *
     * This function must have no other side-effects.
     */
    @SuppressWarnings("deprecation")
    private void updateWakeLockSummaryLocked(int dirty) {
        if ((dirty & (DIRTY_WAKE_LOCKS | DIRTY_WAKEFULNESS)) != 0) {
            mWakeLockSummary = 0;

            final int numProfiles = mProfilePowerState.size();
            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);
                final int wakeLockFlags = getWakeLockSummaryFlags(wakeLock);
                mWakeLockSummary |= wakeLockFlags;
                for (int j = 0; j < numProfiles; j++) {
                    final ProfilePowerState profile = mProfilePowerState.valueAt(j);
                    if (wakeLockAffectsUser(wakeLock, profile.mUserId)) {
                        profile.mWakeLockSummary |= wakeLockFlags;
                    }
                }
            }

            mWakeLockSummary = adjustWakeLockSummaryLocked(mWakeLockSummary);
            for (int i = 0; i < numProfiles; i++) {
                final ProfilePowerState profile = mProfilePowerState.valueAt(i);
                profile.mWakeLockSummary = adjustWakeLockSummaryLocked(profile.mWakeLockSummary);
            }

            if (DEBUG_SPEW) {
                Slog.d(TAG, "updateWakeLockSummaryLocked: mWakefulness="
                        + PowerManagerInternal.wakefulnessToString(getWakefulnessLocked())
                        + ", mWakeLockSummary=0x" + Integer.toHexString(mWakeLockSummary));
            }
        }
    }

    private int adjustWakeLockSummaryLocked(int wakeLockSummary) {
        // Cancel wake locks that make no sense based on the current state.
        //如果当前wakefulness 不是打盹儿Dozing 状态就忽略WAKE_LOCK_DOZE 和WAKE_LOCK_DRAW
        if (getWakefulnessLocked() != WAKEFULNESS_DOZING) {
            wakeLockSummary &= ~(WAKE_LOCK_DOZE | WAKE_LOCK_DRAW);
        }
        //如果整合之后wakefulness 是 WAKEFULNESS_ASLEEP或者包含了WAKE_LOCK_DOZE状态就忽略WAKE_LOCK_SCREEN_BRIGHT 和WAKE_LOCK_SCREEN_DIM、WAKE_LOCK_BUTTON_BRIGHT这里还亮屏的状态。
        if (getWakefulnessLocked() == WAKEFULNESS_ASLEEP
                || (wakeLockSummary & WAKE_LOCK_DOZE) != 0) {
            wakeLockSummary &= ~(WAKE_LOCK_SCREEN_BRIGHT | WAKE_LOCK_SCREEN_DIM
                    | WAKE_LOCK_BUTTON_BRIGHT);
            if (getWakefulnessLocked() == WAKEFULNESS_ASLEEP) {
                wakeLockSummary &= ~WAKE_LOCK_PROXIMITY_SCREEN_OFF;
            }
        }

        // Infer implied wake locks where necessary based on the current state.
        /*这里开始应用整合之后的wakeLockSummary状态:
        *1、如果整合之后wakefulness 包含亮屏的WAKE_LOCK_SCREEN_BRIGHT 或者 WAKE_LOCK_SCREEN_DIM,如果获取当前wakeLockSummary是WAKEFULNESS_AWAKE就把 wakeLockSummary 改为WAKE_LOCK_CPU | WAKE_LOCK_STAY_AWAKE.
        *2、如果获取当前wakeLockSummary是WAKEFULNESS_DREAMING就把 wakeLockSummary 改为WAKE_LOCK_CPU.
        */
        if ((wakeLockSummary & (WAKE_LOCK_SCREEN_BRIGHT | WAKE_LOCK_SCREEN_DIM)) != 0) {
            if (getWakefulnessLocked() == WAKEFULNESS_AWAKE) {
                wakeLockSummary |= WAKE_LOCK_CPU | WAKE_LOCK_STAY_AWAKE;
            } else if (getWakefulnessLocked() == WAKEFULNESS_DREAMING) {
                wakeLockSummary |= WAKE_LOCK_CPU;
            }
        }
        if ((wakeLockSummary & WAKE_LOCK_DRAW) != 0) {
            wakeLockSummary |= WAKE_LOCK_CPU;
        }

        return wakeLockSummary;
    }

4.3、updatePowerStateLocked 之updateUserActivitySummaryLocked更新用户活动状态


  • updateUserActivitySummaryLocked主要用于更新用户活动时间以及重新计算下次超时灭屏时间。
  • screenOffTimeout 一般情况下是设置里面设置的超时灭屏时间,它从数据库里读取。
  • screenDimDuration 是 Dim 屏幕变暗状态下的持续时间,这里他是设置的超时灭屏时间乘以mMaximumScreenDimRatioConfig 系数计算的。由dumpsys power可以打印出来,当前我设置超时灭屏时间是15s,灭屏前Dim状态的变暗的那段时长是 15*0.2 = 3s 。

    /**
     * Updates the value of mUserActivitySummary to summarize the user requested
     * state of the system such as whether the screen should be bright or dim.
     * Note that user activity is ignored when the system is asleep.
     *
     * This function must have no other side-effects.
     */
    private void updateUserActivitySummaryLocked(long now, int dirty) {
        // Update the status of the user activity timeout timer.
        if ((dirty & (DIRTY_WAKE_LOCKS | DIRTY_USER_ACTIVITY
                | DIRTY_WAKEFULNESS | DIRTY_SETTINGS)) != 0) {
            mHandler.removeMessages(MSG_USER_ACTIVITY_TIMEOUT);

            long nextTimeout = 0;
            if (getWakefulnessLocked() == WAKEFULNESS_AWAKE
                    || getWakefulnessLocked() == WAKEFULNESS_DREAMING
                    || getWakefulnessLocked() == WAKEFULNESS_DOZING) {
                //1、默认为-1 禁用,可以从dumpsys power中看到值        
                final long attentiveTimeout = getAttentiveTimeoutLocked();
                final long sleepTimeout = getSleepTimeoutLocked(attentiveTimeout);
                //2、设置中的超时灭屏时长
                final long screenOffTimeout = getScreenOffTimeoutLocked(sleepTimeout,
                        attentiveTimeout);
                //3、DIM 屏幕变暗持续的时间。
                final long screenDimDuration = getScreenDimDurationLocked(screenOffTimeout);
                final boolean userInactiveOverride = mUserInactiveOverrideFromWindowManager;
                final long nextProfileTimeout = getNextProfileTimeoutLocked(now);

                mUserActivitySummary = 0;
                //4、根据最后一次用户活动时间和设置的超时灭屏时间判断下一次超时灭屏的时间。
                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) {
                        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;
                        }
                    }
                }

                //5、屏保时间相关
                if (mUserActivitySummary == 0) {
                    if (sleepTimeout >= 0) {
                        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) {
                        // Device is being kept awake by recent user activity
                        if (nextTimeout >= now && mOverriddenTimeout == -1) {
                            // Save when the next timeout would have occurred
                            mOverriddenTimeout = nextTimeout;
                        }
                    }
                    mUserActivitySummary = USER_ACTIVITY_SCREEN_DREAM;
                    nextTimeout = -1;
                }

                if ((mUserActivitySummary & USER_ACTIVITY_SCREEN_BRIGHT) != 0
                        && (mWakeLockSummary & WAKE_LOCK_STAY_AWAKE) == 0) {
                    nextTimeout = mAttentionDetector.updateUserActivity(nextTimeout,
                            screenDimDuration);
                }

                if (nextProfileTimeout > 0) {
                    nextTimeout = Math.min(nextTimeout, nextProfileTimeout);
                }

                if (mUserActivitySummary != 0 && nextTimeout >= 0) {
                    scheduleUserInactivityTimeout(nextTimeout);
                }
            } else {
                mUserActivitySummary = 0;
            }

            if (DEBUG_SPEW) {
                Slog.d(TAG, "updateUserActivitySummaryLocked: mWakefulness="
                        + PowerManagerInternal.wakefulnessToString(getWakefulnessLocked())
                        + ", mUserActivitySummary=0x" + Integer.toHexString(mUserActivitySummary)
                        + ", nextTimeout=" + TimeUtils.formatUptime(nextTimeout));
            }
        }
    }

4.4、updatePowerStateLocked 之updateWakefulnessLocked更新Wakefulness状态


  • 在updateWakefulnessLocked 执行之前还有 updateAttentiveStateLocked方法,这个没啥好说的,就是更新系统即将进入休眠。

  • 我们可以看到 updatePowerStateLocked 方法中有一个for死循环,而updateWakefulnessLocked方法返回为false是退出死循环的唯一办法。

  • 系统的WAKEFULNESS 有如下四种状态, updateWakefulnessLocked 方法中如果当前设备处于唤醒状态(awake),并且将要退出唤醒状态,也就是进入睡眠状态(sleep)或者屏保状态(dreaming),如果设备开启了屏保,进入屏保状态,否则直接进入睡眠状态。这种情况下,wakefulness发生改变,因此返回值为true,需要通过下一次循环重新统计wakelockSummary和userActivitySummary。如果不是以上情况,则不会进入if语句,说明不需要改变wakefulness值,返回false,则循环体只执行一次便退出。因此,该循环只有在一段时间不活动到达用户超时时间后进入屏保或者进入睡眠时,会执行两次,其他情况下只执行一次便退出,比如按power键灭屏等只会执行一次,因为当power键灭屏时,wakefulness值已经由唤醒状态变为SLEEP状态,因此不满足执行条件。

  • 当刚开始灭屏,power键按下的时候系统状态是WAKEFULNESS_AWAKE,但是isItBedTimeYetLocked为false,因此不会进入这个判断直接返回false 跳出for循环。

    • WAKEFULNESS_ASLEEP;
    • WAKEFULNESS_AWAKE;
    • WAKEFULNESS_DOZING;
    • WAKEFULNESS_DREAMING;
    /**
     * Updates the wakefulness of the device.
     *
     * This is the function that decides whether the device should start dreaming
     * based on the current wake locks and user activity state.  It may modify mDirty
     * if the wakefulness changes.
     *
     * Returns true if the wakefulness changed and we need to restart power state calculation.
     */
    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 | DIRTY_ATTENTIVE | DIRTY_SETTINGS
                | DIRTY_SCREEN_BRIGHTNESS_BOOST)) != 0) {
            //当前屏幕保持唤醒&&设备将要退出唤醒状态(睡眠or屏保).
            if (getWakefulnessLocked() == WAKEFULNESS_AWAKE && isItBedTimeYetLocked()) {
                if (DEBUG_SPEW) {
                    Slog.d(TAG, "updateWakefulnessLocked: Bed time...");
                }
                final long time = mClock.uptimeMillis();
                //mAttentiveTimeoutSetting=-1,这里没有启用
                if (isAttentiveTimeoutExpired(time)) {
                    changed = goToSleepNoUpdateLocked(time, PowerManager.GO_TO_SLEEP_REASON_TIMEOUT,
                            PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE, Process.SYSTEM_UID);
                //是否在休眠时启用屏保
                } else 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.5、updatePowerStateLocked 之updateDisplayPowerStateLocked更新屏幕状态


  • updateDisplayPowerStateLocked 主要用于更新屏幕的状态亮度,它和DisplayPowerService 进行交互,最终还是在DispalyPowerControl中进行处理的。
  • PMS中将亮度、请求更新屏幕的状态、是否使用了距离传感器等参数封装到了mDisplayPowerRequest 请求中然后通过DisplayManagerInternal.requestPowerState发送给DispalyPowerController处理。
    /**
     * Updates the display power state asynchronously.
     * When the update is finished, mDisplayReady will be set to true.  The display
     * controller posts a message to tell us when the actual display power state
     * has been updated so we come back here to double-check and finish up.
     *
     * This function recalculates the display power state each time.
     *
     * @return True if the display became ready.
     */
    private boolean updateDisplayPowerStateLocked(int dirty) {
        final boolean oldDisplayReady = mDisplayReady;
        if ((dirty & (DIRTY_WAKE_LOCKS | DIRTY_USER_ACTIVITY | DIRTY_WAKEFULNESS
                | DIRTY_ACTUAL_DISPLAY_POWER_STATE_UPDATED | DIRTY_BOOT_COMPLETED
                | DIRTY_SETTINGS | DIRTY_SCREEN_BRIGHTNESS_BOOST | DIRTY_VR_MODE_CHANGED |
                DIRTY_QUIESCENT)) != 0) {
            if ((dirty & DIRTY_QUIESCENT) != 0) {
                sQuiescent = false;
            }

            //1、获取将要设置的屏幕状态告诉DisplayPowerController(DPC).
            mDisplayPowerRequest.policy = getDesiredScreenPolicyLocked();

            // Determine appropriate screen brightness and auto-brightness adjustments.
            final boolean autoBrightness;
            //2、设置亮度
            final float screenBrightnessOverride;
            if (!mBootCompleted) {
                // Keep the brightness steady during boot. This requires the
                // bootloader brightness and the default brightness to be identical.
                autoBrightness = false;
                screenBrightnessOverride = mScreenBrightnessSettingDefault;
            } else if (isValidBrightness(mScreenBrightnessOverrideFromWindowManager)) {
                autoBrightness = false;
                screenBrightnessOverride = mScreenBrightnessOverrideFromWindowManager;
            } else {
                autoBrightness = (mScreenBrightnessModeSetting ==
                        Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC);
                screenBrightnessOverride = PowerManager.BRIGHTNESS_INVALID_FLOAT;
            }

            // Update display power request.
            mDisplayPowerRequest.screenBrightnessOverride = screenBrightnessOverride;
            mDisplayPowerRequest.useAutoBrightness = autoBrightness;
            //3、设置是否使用了距离传感器,这跟PROXIMITY_SCREEN_OFF_WAKE_LOCK 有关
            mDisplayPowerRequest.useProximitySensor = shouldUseProximitySensorLocked();
            mDisplayPowerRequest.boostScreenBrightness = shouldBoostScreenBrightness();

            updatePowerRequestFromBatterySaverPolicy(mDisplayPowerRequest);

            if (mDisplayPowerRequest.policy == DisplayPowerRequest.POLICY_DOZE) {
                mDisplayPowerRequest.dozeScreenState = mDozeScreenStateOverrideFromDreamManager;
                if ((mWakeLockSummary & WAKE_LOCK_DRAW) != 0
                        && !mDrawWakeLockOverrideFromSidekick) {
                    if (mDisplayPowerRequest.dozeScreenState == Display.STATE_DOZE_SUSPEND) {
                        mDisplayPowerRequest.dozeScreenState = Display.STATE_DOZE;
                    }
                    if (mDisplayPowerRequest.dozeScreenState == Display.STATE_ON_SUSPEND) {
                        mDisplayPowerRequest.dozeScreenState = Display.STATE_ON;
                    }
                }
                mDisplayPowerRequest.dozeScreenBrightness =
                        mDozeScreenBrightnessOverrideFromDreamManagerFloat;
            } else {
                mDisplayPowerRequest.dozeScreenState = Display.STATE_UNKNOWN;
                mDisplayPowerRequest.dozeScreenBrightness =
                        PowerManager.BRIGHTNESS_INVALID_FLOAT;
            }

            //4、发送请求给DPC
            mDisplayReady = mDisplayManagerInternal.requestPowerState(mDisplayPowerRequest,
                    mRequestWaitForNegativeProximity);
            mRequestWaitForNegativeProximity = false;

            if (DEBUG_SPEW) {
                Slog.d(TAG, "updateDisplayPowerStateLocked: mDisplayReady=" + mDisplayReady
                        + ", policy=" + mDisplayPowerRequest.policy
                        + ", mWakefulness=" + getWakefulnessLocked()
                        + ", mWakeLockSummary=0x" + Integer.toHexString(mWakeLockSummary)
                        + ", mUserActivitySummary=0x" + Integer.toHexString(mUserActivitySummary)
                        + ", mBootCompleted=" + mBootCompleted
                        + ", screenBrightnessOverride=" + screenBrightnessOverride
                        + ", useAutoBrightness=" + autoBrightness
                        + ", mScreenBrightnessBoostInProgress=" + mScreenBrightnessBoostInProgress
                        + ", mIsVrModeEnabled= " + mIsVrModeEnabled
                        + ", sQuiescent=" + sQuiescent);
            }
        }
        return mDisplayReady && !oldDisplayReady;
    }

五、DisplayPowerController (下文简称DPC) 处理PMS的 改变屏幕状态request


5.1、PMS与DPC的关联过程


  • 上面4.5小结我们知道 发送请求是 mDisplayManagerInternal.requestPowerState,这个DisplayManagerInternal 是抽象类,DispalyManagerService的内部类 LocalService extends DisplayManagerInternal , DispalyManagerService 实际上就是调用mDisplayPowerController处理的。这个过程非常简单是同步的没有跨进程调用。

  • 代码路径:
    frameworks\base\services\core\java\com\android\server\display\DisplayManagerService.java.
    `

        @Override
        public boolean requestPowerState(DisplayPowerRequest request,
                boolean waitForNegativeProximity) {
            synchronized (mSyncRoot) {
                return mDisplayPowerController.requestPowerState(request,
                        waitForNegativeProximity);
            }
        }

5.2、DPC处理PMS发过来的改变屏幕状态request 请求


  • 代码路径:
    frameworks\base\services\core\java\com\android\server\display\DisplayPowerController.java.
    `

  • 如果看过log就知道PMS的 updatePowerStateLocked 被调用的非常频繁,其他进程每次申请、释放Wake Lock,AMS回调过来的进程状态发送了改变、用户活动改变更新timeout 计时等等都会调用到,而且每次调用最终都会走到updateDisplayPowerStateLocked像DPC发送屏幕请求的,如果DPC每个都响应,那不得忙的要死,所以这里肯定是有过滤的。

  • 如下注释中第三步说明的,后续只有判断PMS的 request 与之前的不一样才会继续处理,这样保证DPC处理的都是有效的请求。

  • mPendingRequestLocked 是上一次PMS发送过来的请求。

    public boolean requestPowerState(DisplayPowerRequest request,
            boolean waitForNegativeProximity) {

...此处省略部分代码

            if (mPendingRequestLocked == null) {
                //1、只有系统第一次起来会走这里
                mPendingRequestLocked = new DisplayPowerRequest(request);
                changed = true;
            } else if (!mPendingRequestLocked.equals(request)) {
                //2、后面PMS发送过来请求都会走这里,只有request发生了改变才会将changed置为true
                mPendingRequestLocked.copyFrom(request);
                changed = true;
            }

...
            if (changed && !mPendingRequestChangedLocked) {
                //3.changed为true,mPendingRequestChangedLocked通常处理过就立即为false,所以走的是这里继续处理请求
                mPendingRequestChangedLocked = true;
                sendUpdatePowerStateLocked();
            }

...此处省略部分代码

5.3、DPC根据PMSrequest 请求在updatePowerState 中设置屏幕状态和亮度


  • 代码路径:
    frameworks\base\services\core\java\com\android\server\display\DisplayPowerController.java.
    `

  • updatePowerState 方法很长,除了PMS发过来的request 不一样会执行该方法以外,P-Sensor事件也会执行该方法。同时P-Sensor事件只设置屏幕状态,并没有将系统从Asleep状态中唤醒。

  • updatePowerState 主要做的事情如下:

    • 1、提取PMS发过来的request中携带的参数设置屏幕的状态state,并根据state 设置背光亮度值和是否打开关闭P-Sensor监听等等。
    • 2、根据mScreenOffBecauseOfProximity 参数判断是否为P-Sensor事件引起的亮灭屏,对应设置屏幕状态。
    • 3、animateScreenStateChange 为设置屏幕亮灭的方法。后续就不继续跟下去了,有兴趣的同学可以自己继续看一下。

    private void updatePowerState() {

...此处省略部分代码
        //设置屏幕的亮灭
        animateScreenStateChange(state, performScreenOffTransition);
 ...此处省略部分代码

六、结语


本文作为PMS系列的第一篇博客,以Power键灭屏现象为切入点去了解代码流程,排版和编排顺序可能有点乱,其实PowerManagerService还有很多内容,比如WakeLock机制,P-Sensor亮灭屏原理,电池管理等等。等本博主写完之后会做一个整理,这样读起来可能会由浅入深了解的更加深刻。如果博客中有什么错误的地方欢迎评论指正!

你可能感兴趣的:(PMS)