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

后续流程图如下:

相关推荐
Devil枫30 分钟前
Kotlin高级特性深度解析
android·开发语言·kotlin
ChinaDragonDreamer32 分钟前
Kotlin:2.1.20 的新特性
android·开发语言·kotlin
雨白11 小时前
Jetpack系列(二):Lifecycle与LiveData结合,打造响应式UI
android·android jetpack
kk爱闹13 小时前
【挑战14天学完python和pytorch】- day01
android·pytorch·python
每次的天空14 小时前
Android-自定义View的实战学习总结
android·学习·kotlin·音视频
恋猫de小郭15 小时前
Flutter Widget Preview 功能已合并到 master,提前在体验毛坯的预览支持
android·flutter·ios
断剑重铸之日16 小时前
Android自定义相机开发(类似OCR扫描相机)
android
随心最为安16 小时前
Android Library Maven 发布完整流程指南
android
岁月玲珑16 小时前
【使用Android Studio调试手机app时候手机老掉线问题】
android·ide·android studio
还鮟20 小时前
CTF Web的数组巧用
android