(10)Android之路====一夫当关的POWER键

本文深入探讨Android设备的Power键功能,包括息屏休眠、亮屏唤醒和长按关机的处理流程。通过PowerManagerService和PhoneWindowManager的交互,解析了息屏时如何进入Doze模式,以及唤醒和关机的具体步骤。对于长按关机,介绍了原生机制和SoC厂商的硬件适配。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Power键使用的场景和使用的频率都很高,本次从浅层次了解它.首先看一下使用它的场景:

power键:
单击事件:
1,息屏休眠
2,亮屏唤醒

长按事件:
3,长按关机
4,长按开机

双击事件:
5,双击进相机

组合事件:
关机:
6,power + vol-进recovery
7,power + vol+进Factory test mode
开机:
8,power + vol-截屏

特殊事件:
9,通话挂断

上面是一个参考示例,不一定所有手机厂商都是这样做的,但都大同小异.1,2,3,5,8,9是在Android正常模式下作用的,4是SoC级作用的,6,7是在uboot下作用的.

篇幅有限,本次只研究前4种情况,其它情况不做详细介绍.其中第4中情况(长按开机)已经在第7篇开机流程中介绍过了.

首先是power的物理操作,会通过底层驱动一层层上传,到Framework时,经过InputManagerService处理按键事件后,最终将传递给PhoneWindowManager的dispatchUnhandledKey().

public KeyEvent dispatchUnhandledKey(WindowState win, KeyEvent event, int policyFlags) {
    ...
    if (!interceptFallback(win, fallbackEvent, policyFlags)) {
        fallbackEvent.recycle();
        fallbackEvent = null;
    }
    ...
}

private boolean interceptFallback(WindowState win, KeyEvent fallbackEvent, int policyFlags) {
    int actions = interceptKeyBeforeQueueing(fallbackEvent, policyFlags);
    if ((actions & ACTION_PASS_TO_USER) != 0) {
        long delayMillis = interceptKeyBeforeDispatching(
                win, fallbackEvent, policyFlags);
        if (delayMillis == 0) {
            return true;
        }
    }
    return false;
}

其中interceptKeyBeforeQueueing()处理具体的业务逻辑:

public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {
    ...
    switch (keyCode) {
        ...
        case KeyEvent.KEYCODE_POWER: {
            // 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;
        }
        ...
    }
    ...
    if (isWakeKey) {
        // 按power键时,isWakeKey置为false,于是不会调用wakeUp函数,即不会唤醒系统点亮屏幕
        wakeUp(event.getEventTime(), mAllowTheaterModeWakeFromKey, "android.policy:KEY");
    }

    return result;
}

接下来我们分别看一下interceptPowerKeyDown()和interceptPowerKeyUp()处理流程.

1,息屏休眠

息屏休眠过程用到的是interceptPowerKeyUp,代码如下:

private void interceptPowerKeyUp(KeyEvent event, boolean interactive, boolean canceled) {
    // 事件被取消,或者在按下Power键时,该事件已被消耗掉,那么就不用继续处理
    final boolean handled = canceled || mPowerKeyHandled;
    mScreenshotChordPowerKeyTriggered = false;
    // 退出截屏
    cancelPendingScreenshotChordAction();
    // 取消MSG_POWER_LONG_PRESS事件,即在一定事件内Power键弹起,则表示这一次不是长按Power键
    cancelPendingPowerKeyAction();

    if (!handled) {
        // Figure out how to handle the key now that it has been released.
        mPowerKeyPressCounter += 1;

        final int maxCount = getMaxMultiPressPowerCount();
        final long eventTime = event.getDownTime();
        if (mPowerKeyPressCounter < maxCount) {
            // This could be a multi-press.  Wait a little bit longer to confirm.
            // Continue holding the wake lock.
            // 处理Power键被多次按下场景对应,
            Message msg = mHandler.obtainMessage(MSG_POWER_DELAYED_PRESS,
                    interactive ? 1 : 0, mPowerKeyPressCounter, eventTime);
            msg.setAsynchronous(true);
            mHandler.sendMessageDelayed(msg, ViewConfiguration.getMultiPressTimeout());
            return;
        }

        // No other actions.  Handle it immediately.
        powerPress(eventTime, interactive, mPowerKeyPressCounter);
    }

    // Done.  Reset our state.
    finishPowerKeyPress();
}

其中powerPress处理具体时间,finishPowerKeyPress复位按键状态,这里,我们跟一下powerPress:

private void powerPress(long eventTime, boolean interactive, int count) {
    ...
    if (count == 2) {
        powerMultiPressAction(eventTime, interactive, mDoublePressOnPowerBehavior);
    } else if (count == 3) {
        powerMultiPressAction(eventTime, interactive, mTriplePressOnPowerBehavior);
    } else if (interactive && !mBeganFromNonInteractive) {
        switch (mShortPressOnPowerBehavior) {
            case SHORT_PRESS_POWER_NOTHING:
                break;
            case SHORT_PRESS_POWER_GO_TO_SLEEP:	// 最终执行这里,调用PMS的goToSleep
                goToSleep(eventTime, PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON, 0);
                break;
            ...
        }
    }
}

PowerManagerService.java

private void goToSleepInternal(long eventTime, int reason, int flags, int uid) {
    synchronized (mLock) {
        if (goToSleepNoUpdateLocked(eventTime, reason, flags, uid)) {
            updatePowerStateLocked();
        }
    }
}

public void goToSleep(long eventTime, int reason, int flags) {
    ...
    try {
        goToSleepInternal(eventTime, reason, flags, uid);
    } finally {
        Binder.restoreCallingIdentity(ident);
    }
}

会执行goToSleepNoUpdateLocked:

@SuppressWarnings("deprecation")
private boolean goToSleepNoUpdateLocked(long eventTime, int reason, int flags, int uid) {
    ...
    try {
        ...
        // 标记最后一次灭屏时间
        mLastSleepTime = eventTime;
        // 是否进入屏保
        mSandmanSummoned = true;
        // 设置wakefulness值为WAKEFULNESS_DOZING,因此先进Doze状态
        setWakefulnessLocked(WAKEFULNESS_DOZING, reason);

        // Report the number of wake locks that will be cleared by going to sleep.
        // 灭屏时,将清除以下三种使得屏幕保持亮屏的wakelock锁
        int numWakeLocksCleared = 0;
        fin
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值