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

Posted Mrsongs的心情杂货铺

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了深入了解PowerManagerService之Android 11.0 Power 键亮屏灭屏流程分析相关的知识,希望对你有一定的参考价值。

一、前言

环境:本文基于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;
            } Memcache技术之Memcached机制深入了解

iOS之深入了解控制器View的加载

深入了解jQuery之链式结构

2-2:套接字(Socket)编程之深入了解套接字

深入了解Promise

PowerManagerService流程分析