Android 14 Power键亮灭屏流程

Android14中Power键的事件分发和Android10的是不一样的,这里并没有经过interceptKeyBeforeDispatching方法,而是直接走到了interceptKeyBeforeQueueing方法

PhoneWindowManager中的堆栈如下

java 复制代码
07-06 08:59:04.481  1844  1984 D WindowManager: interceptKeyTq keycode=26 down=true
07-06 08:59:04.481  1844  1984 W System.err: java.lang.Exception
07-06 08:59:04.481  1844  1984 W System.err: 	at com.android.server.policy.PhoneWindowManager.interceptKeyBeforeQueueing(PhoneWindowManager.java:4127)
07-06 08:59:04.481  1844  1984 W System.err: 	at com.android.server.wm.InputManagerCallback.interceptKeyBeforeQueueing(InputManagerCallback.java:149)
07-06 08:59:04.481  1844  1984 W System.err: 	at com.android.server.input.InputManagerService.interceptKeyBeforeQueueing(InputManagerService.java:2476)

当用户点击物理按键Power键时,input模块会分发此事件,jni层的input相关的堆栈如下

java 复制代码
07-06 08:59:04.481  1844  1984 D NativeInputManager:   #00 pc 000000000007e62c  /system/lib64/libandroid_servers.so (android::NativeInputManager::interceptKeyBeforeQueueing(android::KeyEvent const&, unsigned int&)+108) (BuildId: a244f886fcc4e4d7951cb0b0dd8e0a93)
07-06 08:59:04.481  1844  1984 D NativeInputManager:   #01 pc 00000000000ac5d0  /system/lib64/libinputflinger.so (android::inputdispatcher::InputDispatcher::notifyKey(android::NotifyKeyArgs const&)+372) (BuildId: a55568bcb9c61a30bcd4f9eba5623696)
07-06 08:59:04.481  1844  1984 D NativeInputManager:   #02 pc 0000000000007cd4  /system/lib64/libinputflinger_base.so (android::QueuedInputListener::flush()+132) (BuildId: a9c65a12bbe41d35ccac4bea02eabbf0)
07-06 08:59:04.481  1844  1984 D NativeInputManager:   #03 pc 0000000000007cd4  /system/lib64/libinputflinger_base.so (android::QueuedInputListener::flush()+132) (BuildId: a9c65a12bbe41d35ccac4bea02eabbf0)
07-06 08:59:04.481  1844  1984 D NativeInputManager:   #04 pc 0000000000007cd4  /system/lib64/libinputflinger_base.so (android::QueuedInputListener::flush()+132) (BuildId: a9c65a12bbe41d35ccac4bea02eabbf0)
07-06 08:59:04.481  1844  1984 D NativeInputManager:   #05 pc 00000000000a0d54  /system/lib64/libinputreader.so (android::InputReader::loopOnce()+1424) (BuildId: 7171b6e142e1b4551a0406d673f063e5)
07-06 08:59:04.481  1844  1984 D NativeInputManager:   #06 pc 000000000000ad14  /system/lib64/libinputflinger_base.so (android::(anonymous namespace)::InputThreadImpl::threadLoop()+28) (BuildId: a9c65a12bbe41d35ccac4bea02eabbf0)
07-06 08:59:04.481  1844  1984 D NativeInputManager:   #07 pc 00000000000142d0  /system/lib64/libutils.so (android::Thread::_threadLoop(void*)+288) (BuildId: 6df8048e2f2c69be0a5d8ee3149d683d)
07-06 08:59:04.481  1844  1984 D NativeInputManager:   #08 pc 00000000000ebc40  /system/lib64/libandroid_runtime.so (android::AndroidRuntime::javaThreadShell(void*)+144) (BuildId: af0fa43783211a0f2494f720559e5d5c)
07-06 08:59:04.481  1844  1984 D NativeInputManager:   #09 pc 00000000000c3644  /apex/com.android.runtime/lib64/bionic/libc.so (__pthread_start(void*)+208) (BuildId: 50118287324a156bc7be11d3d940c7be)
07-06 08:59:04.481  1844  1984 D NativeInputManager:   #10 pc 000000000005cfa4  /apex/com.android.runtime/lib64/bionic/libc.so (__start_thread+68) (BuildId: 50118287324a156bc7be11d3d940c7be)

整个流程图如下:


InputManagerService.java - OpenGrok cross reference for /frameworks/base/services/core/java/com/android/server/input/InputManagerService.java

java 复制代码
    // Native callback.
    @SuppressWarnings("unused")
    private int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {
        synchronized (mFocusEventDebugViewLock) {
            if (mFocusEventDebugView != null) {
                mFocusEventDebugView.reportEvent(event);
            }
        }
        return mWindowManagerCallbacks.interceptKeyBeforeQueueing(event, policyFlags);
    }
复制代码
private WindowManagerCallbacks mWindowManagerCallbacks;

mWindowManagerCallbacks定义如上,我们可以看到WindowManagerCallbacks只是一个接口,没有具体的实现

java 复制代码
​
public interface WindowManagerCallbacks extends LidSwitchCallback {
        /**
         * This callback is invoked when an event first arrives to InputDispatcher and before it is
         * placed onto InputDispatcher's queue. If this event is intercepted, it will never be
         * processed by InputDispacher.
         * @param event The key event that's arriving to InputDispatcher
         * @param policyFlags The policy flags
         * @return the flags that tell InputDispatcher how to handle the event (for example, whether
         * to pass it to the user)
         */
        int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags);
}

​

查找代码会发现InputManagerCallback实现了WindowManagerCallbacks,然后就到了InputManagerCallback这里

InputManagerCallback.java - OpenGrok cross reference for /frameworks/base/services/core/java/com/android/server/wm/InputManagerCallback.java

java 复制代码
 final class InputManagerCallback implements InputManagerService.WindowManagerCallbacks {
...
    /**
     * Provides an opportunity for the window manager policy to intercept early key
     * processing as soon as the key has been read from the device.
     */
    @Override
    public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {
        return mService.mPolicy.interceptKeyBeforeQueueing(event, policyFlags);
    }

然后就走到了PhoneWindowManager中

PhoneWindowManager.java - OpenGrok cross reference for /frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java

java 复制代码
    @Override
    public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {
//获取键值
        final int keyCode = event.getKeyCode();
//获取当前是否是按键down
        final boolean down = event.getAction() == KeyEvent.ACTION_DOWN;
//是否是wake key
        boolean isWakeKey = (policyFlags & WindowManagerPolicy.FLAG_WAKE) != 0
                || event.isWakeKey();
...
        final boolean interactive = (policyFlags & FLAG_INTERACTIVE) != 0;
//此按键是否取消
        final boolean canceled = event.isCanceled();
//获取屏幕的ID
        final int displayId = event.getDisplayId();
        final boolean isInjected = (policyFlags & WindowManagerPolicy.FLAG_INJECTED) != 0;
...
        // Handle special keys.
        switch (keyCode) {
...
//走进Power按键的处理逻辑
            case KeyEvent.KEYCODE_POWER: {
                EventLogTags.writeInterceptPower(
                        KeyEvent.actionToString(event.getAction()),
                        mPowerKeyHandled ? 1 : 0,
                        mSingleKeyGestureDetector.getKeyPressCounter(KeyEvent.KEYCODE_POWER));
                // Any activity on the power button stops the accessibility shortcut
//这个意思是此事件只有系统层可以接收,不下发给app
                result &= ~ACTION_PASS_TO_USER;
                isWakeKey = false; // wake-up will be handled separately
                if (down) {
                    interceptPowerKeyDown(event, interactiveAndOn);
                } else {
                    interceptPowerKeyUp(event, canceled);
                }
                break;
            }
...
//使用震动反馈
        if (useHapticFeedback) {
            performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY, false,
                    "Virtual Key - Press");
        }

        if (isWakeKey) {
            wakeUpFromWakeKey(event);
        }
...
}

然后就走到了power down这里的逻辑

PhoneWindowManager.java - OpenGrok cross reference for /frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java

java 复制代码
    private void interceptPowerKeyDown(KeyEvent event, boolean interactive) {
        // Hold a wake lock until the power key is released.
//申请wake lock锁,申请这个锁才能亮屏哦!!!
        if (!mPowerKeyWakeLock.isHeld()) {
            mPowerKeyWakeLock.acquire();
        }
//会走到WMS的onPowerKeyDown方法
//mRoot.forAllDisplayPolicies(p -> p.onPowerKeyDown(isScreenOn));
        mWindowManagerFuncs.onPowerKeyDown(interactive);

        // 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.
//如果当前电话正在响铃, 按下power键就会静音
                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();
            }
        }
//return true if the proximity sensor was successfully ignored and we should consume the key event.---Power
        final boolean handledByPowerManager = mPowerManagerInternal.interceptPowerKeyDown(event);

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

        // 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 = mPowerKeyHandled || hungUp
                || handledByPowerManager || mKeyCombinationManager.isPowerKeyIntercepted();
        if (!mPowerKeyHandled) {
            if (!interactive) {
                wakeUpFromPowerKey(event.getDownTime());
            }
        } else {
            // handled by another power key policy.
            if (mSingleKeyGestureDetector.isKeyIntercepted(KEYCODE_POWER)) {
                Slog.d(TAG, "Skip power key gesture for other policy has handled it.");
                mSingleKeyGestureDetector.reset();
            }
        }
    }

如果mPowerKeyHandled为false,也就是没有消费掉这个power事件,则,走进wakeUpFromWakeKey逻辑。

PhoneWindowManager.java - OpenGrok cross reference for /frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java

java 复制代码
    private void wakeUpFromWakeKey(KeyEvent event) {
//亮屏, 原因是WAKE_REASON_WAKE_KEY, details是"android.policy:KEY"
        if (wakeUp(event.getEventTime(), mAllowTheaterModeWakeFromKey,
                PowerManager.WAKE_REASON_WAKE_KEY, "android.policy:KEY")) {
            // Start HOME with "reason" extra if sleeping for more than mWakeUpToLastStateTimeout
            if (shouldWakeUpWithHomeIntent() && event.getKeyCode() == KEYCODE_HOME) {
                startDockOrHome(DEFAULT_DISPLAY, /*fromHomeKey*/ true, /*wakenFromDreams*/ true,
                        PowerManager.wakeReasonToString(PowerManager.WAKE_REASON_WAKE_KEY));
            }
        }
    }

PhoneWindowManager.java - OpenGrok cross reference for /frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java

java 复制代码
    private boolean wakeUp(long wakeTime, boolean wakeInTheaterMode, @WakeReason int reason,
            String details) {
        final boolean theaterModeEnabled = isTheaterModeEnabled();
        if (!wakeInTheaterMode && theaterModeEnabled) {
            return false;
        }

        if (theaterModeEnabled) {
            Settings.Global.putInt(mContext.getContentResolver(),
                    Settings.Global.THEATER_MODE_ON, 0);
        }

        mPowerManager.wakeUp(wakeTime, reason, details);
        return true;
    }

后续流程图如下:

相关推荐
sweetying1 小时前
30了,人生按部就班
android·程序员
用户2018792831672 小时前
Binder驱动缓冲区的工作机制答疑
android
真夜2 小时前
关于rngh手势与Slider组件手势与事件冲突解决问题记录
android·javascript·app
用户2018792831672 小时前
浅析Binder通信的三种调用方式
android
用户092 小时前
深入了解 Android 16KB内存页面
android·kotlin
火车叼位3 小时前
Android Studio与命令行Gradle表现不一致问题分析
android
前行的小黑炭5 小时前
【Android】 Context使用不当,存在内存泄漏,语言不生效等等
android·kotlin·app
前行的小黑炭6 小时前
【Android】CoordinatorLayout详解;实现一个交互动画的效果(上滑隐藏,下滑出现);附例子
android·kotlin·app
用户20187928316718 小时前
Android黑夜白天模式切换原理分析
android
芦半山18 小时前
「幽灵调用」背后的真相:一个隐藏多年的Android原生Bug
android