Android7.0 PowerManagerService亮灭屏分析(一)

本文主要分析Android 7.0中按电源键亮屏和来电亮屏的过程,涉及PowerManagerService、DisplayPowerController等关键类的功能。在亮屏流程中,Input事件传递到PhoneWindowManager,调用PowerManagerService的wakeup函数,接着更新电源状态并发送广播。PowerManagerService的updatePowerStateLocked函数根据设备状态、电池状态、wakeLock等因素决定屏幕状态,并通过DisplayPowerController处理屏幕亮度。

绪论

可以导致手机亮灭屏的因素有多种,而在本文中主要讲解按power键亮灭屏过程以及来电亮屏。在亮灭屏过程power中主要的实现类与功能如下所述:
PowerManagerService.java:以下简称PMS或者PowerMS,主要处理系统中与power相关的计算,然后决策系统该如何反应。同时协调power如何与系统其他模块的交互,比如没有用户活动时屏幕变暗等。
DisplayPowerController.java:以下简称DPC或者DisplayPC,管理display设备状态,在DisplayManagerService.java(简称DMS)中实例化一个对象,以DMS为桥梁与PMS进行交互。主要处理距离传感器,亮灭屏动画,以及计算屏幕目标亮度值。通过异步回调机制来通知PMS那些事情发生了改变。同时也与WMS进行交互。
DisplayPowerState.java:以下简称DPS,power通过其与系统进行交互,如调用其它模块设置屏幕状态与亮度。仅在DPC中实例化一个对象,它算是DPC的一部分只不过将其独立出来了。
Notifier.java:将power状态的重要变化,通过广播发送出去,并且参与了与AMS,WMS,IMP的交互。
ColorFade.java:负责屏幕由关到开,由开到关的一些GL动画,由DPC进行控制。
AutomaticBrightnessController.java:主要处理光传感器,将底层上传的参数进行处理计算,将计算的新的亮度值传给DPC。
RampAnimator.java:处理屏幕亮度渐变动画。

亮屏总览


    在点击power键亮屏过程中,主要流程就是input对按键事件的传输,传送到上层处理。之后就是在power中进行对亮屏状态的处理,计算一系列的数值,并且与AMS,WMS等模块进行交互,最后调用底层LCD进行最终的设备状态与亮度的设置。在下面将会对各流程详细讲解。

Input传输Power键



    当触发power键,kernel会将该事件中断,然后InputReader通过EventHub获取事件,并且对输入事件进行处理,之后交由InputDispatcher进行分发。如果该事件为key事件会先调用interceptKeyBeforeQueueing,提前对需要系统处理的事件进行处理。最终调到PhoneWindowManager类中的interceptKeyBeforeQueueing函数对该事件优先处理,对power键以及屏幕状态进行判断,来决定亮屏还是灭屏等操作。当需要亮屏时,会调用PowerMangerService中的wakeup函数进行处理。
从底层到上层的具体代码调用流程 InputReader.cpp->InputDispatcher.cpp->com_android_server_input_InputManagerService.cpp->InputManagerService.java->InputMonitor.java->WindowManagerPolicy.java->PhoneWindowManager.java最终来到java层处理按键事件.


    public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {
        if (!mSystemBooted) {      //系统还没有启动完成,不处理任何按键事件
            // If we have not yet booted, don't let key events do anything.
            return 0;
        }

        final boolean interactive = (policyFlags & FLAG_INTERACTIVE) != 0;   //是否能与用户交互, 如果亮屏为true
        final boolean down = event.getAction() == KeyEvent.ACTION_DOWN; //按键down事件
        final boolean canceled = event.isCanceled();     //事件被取消
        final int keyCode = event.getKeyCode();       //按键事件的code

        final boolean isInjected = (policyFlags & WindowManagerPolicy.FLAG_INJECTED) != 0;  
        // Basic policy based on interactive state.
        int result;    
        boolean isWakeKey = (policyFlags & WindowManagerPolicy.FLAG_WAKE) != 0
                || event.isWakeKey();   //flags有wake标记,或者按键为KEYCODE_BACK, KEYCODE_MENU, KEYCODE_WAKEUP, KEYCODE_PAIRING, KEYCODE_STEM_1, KEYCODE_STEM_2, KEYCODE_STEM_3设置isWakeKey为true.  power ,home键属于systemKey

        // If the key would be handled globally, just return the result, don't worry about special
        // key processing.
        if (isValidGlobalKey(keyCode)   
                && mGlobalKeyManager.shouldHandleGlobalKey(keyCode, event)) {
            if (isWakeKey) {  //如果按键时间有效, 并且在com.android.internal.R.xml.global_keys文件中配置了keycode. 如果是唤醒键就调用wakeUp唤醒屏幕
                wakeUp(event.getEventTime(), mAllowTheaterModeWakeFromKey, "android.policy:KEY");
            }
            return result;
        }

        // Handle special keys.   //处理特殊的按键事件 ,这里主要讲解power键事件
        switch (keyCode) {
            case KeyEvent.KEYCODE_BACK:    //back键
            case KeyEvent.KEYCODE_VOLUME_DOWN: //音量下键
            case KeyEvent.KEYCODE_VOLUME_UP:  //音量上键
            case KeyEvent.KEYCODE_VOLUME_MUTE:   //静音键
            case KeyEvent.KEYCODE_ENDCALL:     //挂断电话键
            case KeyEvent.KEYCODE_POWER: {      //电源键
                result &= ~ACTION_PASS_TO_USER;
                isWakeKey = false; // wake-up will be handled separately
                if (down) {     //power按下事件
                    interceptPowerKeyDown(event, interactive);   //处理power下键
                } else {      //power键松开
                    interceptPowerKeyUp(event, interactive, canceled); //处理power上键
                }
                break;
            }
            case KeyEvent.KEYCODE_SLEEP:  
            case KeyEvent.KEYCODE_SOFT_SLEEP:
            case KeyEvent.KEYCODE_WAKEUP:
            case KeyEvent.KEYCODE_MEDIA_PLAY:
            case KeyEvent.KEYCODE_MEDIA_PAUSE:
            case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
            case KeyEvent.KEYCODE_HEADSETHOOK:
            case KeyEvent.KEYCODE_MUTE:
            case KeyEvent.KEYCODE_MEDIA_STOP:
            case KeyEvent.KEYCODE_MEDIA_NEXT:
            case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
            case KeyEvent.KEYCODE_MEDIA_REWIND:
            case KeyEvent.KEYCODE_MEDIA_RECORD:
            case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD:
            case KeyEvent.KEYCODE_MEDIA_AUDIO_TRACK:
            case KeyEvent.KEYCODE_CALL:
            case KeyEvent.KEYCODE_VOICE_ASSIST:
            case KeyEvent.KEYCODE_WINDOW:
            }
        }
        if (isWakeKey) {   //如果除了power键, 别的按键也需要亮屏,就调用WakeUp亮屏
            wakeUp(event.getEventTime(), mAllowTheaterModeWakeFromKey, "android.policy:KEY");
        }

        return result;
    }
处理power键down事件

    private void interceptPowerKeyDown(KeyEvent event, boolean interactive) {
        // Hold a wake lock until the power key is released.
        if (!mPowerKeyWakeLock.isHeld()) {
            mPowerKeyWakeLock.acquire();   //获取wakeLock,保持cpu唤醒状态
        }

        // Latch power key state to detect screenshot chord.
        if (interactive && !mScreenshotChordPowerKeyTriggered
                && (event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) {
            mScreenshotChordPowerKeyTriggered = true;
            mScreenshotChordPowerKeyTime = event.getDownTime();
            interceptScreenshotChord();      //屏幕截屏
        }

        // Stop ringing or end call if configured to do so when power is pressed.
        TelecomManager telecomManager = getTelecommService();   //获取telecom
        boolean hungUp = false;
        if (telecomManager != null) {
            if (telecomManager.isRinging()) {   //如果来电过程中,按power键手机将静音,停止响铃
                // 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();  //如果在Setting数据库中配置了,按power键挂断电话, 就将电话挂断
            }
        }
        //................
        // If the power key has still not yet been handled, then detect short
        // press, long press, or multi press and decide what to do.     //如果power键还没有被处理,就判断是短按, 长按,还是多按来决定如何处理
        mPowerKeyHandled = hungUp || mScreenshotChordVolumeDownKeyTriggered
                || mScreenshotChordVolumeUpKeyTriggered || 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.
                if (hasLongPressOnPowerBehavior()) {    //如果屏幕是亮这的,长按power键 ,就处理长按事件
                    Message msg = mHandler.obtainMessage(MSG_POWER_LONG_PRESS);
                    msg.setAsynchronous(true);
                    mHandler.sendMessageDelayed(msg,
                            ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout());
                }
            } else {
                wakeUpFromPowerKey(event.getDownTime());   //如果屏幕是休眠状态,就唤醒屏幕

                if (mSupportLongPressPowerWhenNonInteractive && hasLongPressOnPowerBehavior()) {
                    Message msg = mHandler.obtainMessage(MSG_POWER_LONG_PRESS);
                    msg.setAsynchronous(true);
                    mHandler.sendMessageDelayed(msg,    //如果还是长按power键, 就再处理长按事件
                            ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout());
                    mBeganFromNonInteractive = true;
                } else {
                    final int maxCount = getMaxMultiPressPowerCount();

                    if (maxCount <= 1) {
                        mPowerKeyHandled = true;
                    } else {
                        mBeganFromNonInteractive = true;
                    }
                }
            }
        } 
    }
Power键up事件

    private void interceptPowerKeyUp(KeyEvent event, boolean interactive, boolean canceled) {
        final boolean handled = canceled || mPowerKeyHandled;
        mScreenshotChordPowerKeyTriggered = false;
        cancelPendingScreenshotChordAction();
        cancelPendingPowerKeyAction();

        if (!handled) {    //power键还没被处理
            // 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.    //等待一会调用powerPress处理
<think>我们正在分析Android系统中Power Manager服务(PMS)的屏幕流程。根据引用内容,我们可以构建个从按键事件到屏幕状态变化的完整流程。以下将结合引用信息逐步分析: ### 1. **按键事件触发** 当用户按下Power键时,Input子系统会捕获该事件并传递给上层。在`PhoneWindowManager`中,会调用`wakeUpFromWakeKey`方法处理请求(引用[5]): ```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")) { // ... 可能启动HOME界面 } } ``` 这里通过`wakeUp`方法向PowerManagerService发起请求。 ### 2. **PowerManagerService处理请求** 在PMS中,会计算屏幕状态、度等参数,并与ActivityManagerService(AMS)、WindowManagerService(WMS)等模块交互(引用[3])。核心流程包括: - 更新电源状态(如从休眠状态切换到状态) - 计算屏幕度曲线(考虑自动度、环境光等) - 通知AMS/WMS准备界面绘制 ### 3. **底层LCD控制** PMS最终会通过写入`/sys/power/state`节点控制屏幕状态(引用[4]): - :调用`autosuspend_disable()`,向节点写入`on` - :写入`mem`(或其他休眠状态字符串) 在写入节点后,会触发LCD的`late_resume`操作(如`sprdfb_dispc_resume`函数),硬件完成屏幕。 ### 4. **流程** 流程与类似,但方向相反(引用[1][2]): 1. Power键事件触发`goToSleep`方法 2. PMS计算休眠状态 3. 通知AMS/WMS进入休眠(暂停界面绘制) 4. 写入`/sys/power/state`节点(如`mem`)关闭屏幕 ### 5. **关键节点总结** | **阶段** | **关键操作** | |----------------|-----------------------------------------------------------------------------| | **按键捕获** | `PhoneWindowManager`处理Power键事件,调用`wakeUp`或`goToSleep` | | **PMS状态计算**| 更新全局电源状态,与AMS/WMS交互,计算度/超时等参数 | | **底层控制** | 通过`/sys/power/state`节点控制LCD电源,调用驱动层`resume/suspend`函数 | > **注意**:不同Android版本或厂商定制可能修改流程细节,但核心框架保持致。 §§相关问题§§ 1. Power键事件如何从内核传递到Android框架层? 2. PMS与WakeLock机制如何协同工作? 3. 自动度调节在流程中如何生效? 4. 时如何保证应用数据安全?</think>### Android Power Manager 屏幕流程分析 Android的电源管理核心是`PowerManagerService`(PMS),屏幕流程涉及**输入事件处理、状态计算、跨模块协作、硬件控制**四个关键阶段。以下是基于Android 7.0+的流程解析(兼容至Android 11): --- #### **1. 输入事件捕获** 当用户按下Power键: - **Input子系统**捕获按键事件,通过`InputReader`/`InputDispatcher`传递到上层。 - **`PhoneWindowManager`** 处理事件: ```java // PhoneWindowManager.java private void wakeUpFromWakeKey(KeyEvent event) { if (wakeUp(event.getEventTime(), mAllowTheaterModeWakeFromKey, PowerManager.WAKE_REASON_WAKE_KEY, "android.policy:KEY")) { // 若满足条件(如长按HOME键),启动HOME界面 } } ``` 调用`PowerManager.wakeUp()`触发流程[^5]。 --- #### **2. PMS状态计算与决策** **`PowerManagerService`** 执行核心逻辑: - **状态机切换**:从`OFF`状态切换到`ON`或`DREAM`状态。 - **参数计算**: - 屏幕度(结合自动度调节) - 超时时间(根据用户设置、传感器数据) - 电源策略(如是否允许剧院模式唤醒) - **跨模块协作**: - 通知`ActivityManagerService`(AMS)准备应用界面绘制。 - 同步`WindowManagerService`(WMS)更新窗口状态[^3]。 --- #### **3. 底层硬件控制** PMS通过**HAL层**操作显示设备: 1. **禁用自动挂起**: ```c autosuspend_disable(); // 向/sys/power/state写入"on" ``` 2. **唤醒显示控制器**: - 调用`late_resume()`恢复LCD(如`sprdfb_dispc_resume`函数)。 - 硬件初始化时间因设备而异[^4]。 3. **设置度**: - 通过`/sys/class/backlight`节点写入度值。 > 💡 **流程相反**: > 1. PMS计算休眠策略(如`USER_ACTIVITY`超时)。 > 2. 通知AMS/WMS暂停界面。 > 3. 向`/sys/power/state`写入`mem`触发LCD休眠[^1][^2]。 --- #### **4. 关键参与模块** | **模块** | **职责** | |------------------------|---------------------------------------| | `PhoneWindowManager` | 输入事件路由 | | `PowerManagerService` | 电源策略决策、状态管理 | | `DisplayManagerService`| 显示设备控制(度/状态) | | `ActivityManagerService` | 协调应用生命周期 | | 内核驱动 | 操作`/sys/power`节点控制硬件电源状态 | --- ### 流程总结 ```mermaid graph TD A[Power键按下] --> B{Input子系统捕获} B --> C[PhoneWindowManager处理] C --> D[PMS唤醒请求] D --> E[状态计算+跨模块协作] E --> F[写入/sys/power/state] F --> G[内核控制LCD起] ```
评论 3
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值