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;
    }

后续流程图如下:

相关推荐
数据猎手小k1 小时前
AndroidLab:一个系统化的Android代理框架,包含操作环境和可复现的基准测试,支持大型语言模型和多模态模型。
android·人工智能·机器学习·语言模型
你的小102 小时前
JavaWeb项目-----博客系统
android
风和先行2 小时前
adb 命令查看设备存储占用情况
android·adb
AaVictory.3 小时前
Android 开发 Java中 list实现 按照时间格式 yyyy-MM-dd HH:mm 顺序
android·java·list
似霰4 小时前
安卓智能指针sp、wp、RefBase浅析
android·c++·binder
大风起兮云飞扬丶4 小时前
Android——网络请求
android
干一行,爱一行4 小时前
android camera data -> surface 显示
android
断墨先生4 小时前
uniapp—android原生插件开发(3Android真机调试)
android·uni-app
无极程序员6 小时前
PHP常量
android·ide·android studio
萌面小侠Plus7 小时前
Android笔记(三十三):封装设备性能级别判断工具——低端机还是高端机
android·性能优化·kotlin·工具类·低端机