zoukankan      html  css  js  c++  java
  • Android7.0 PowerManagerService 之亮灭屏(一)

    本篇从按下power按键后,按键事件从InputManagerService 传到PhoneWindowManager.java开始分析power 按键做屏幕亮灭过程的分析,关于power 按键的其他行为参考另一篇博文(Android 7.0 Power 按键处理流程

        (注:博客园显示的图片很模糊,上传的为大图,可以图片另存为查看)

        言归正传,本篇涉及的几个模块(文件)如下,先做个简单的介绍有个直观大概的了解,方便后面流程细节的理解。

    Ø  PowerManagerService.Java(/frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java)

       PMS,是Android系统中的电源处理服务,主要负责电源相关的计算和决策,如是否应该灭屏 或者让屏幕变暗,是否应该让系统休眠等等。

    Ø  DisplayPowerController.java(/frameworks/base/services/core/java/com/android/server/display/DisplayPowerController.java

      DPC,管理显示设备(这里指的显示设备是屏幕)状态,主要处理距离传感器(如打电话时候靠近则灭屏,离开时候屏幕亮起)以及亮灭屏动画(包括根据光感传感器计算屏幕目标亮度值)。在DisplayManagerService.java(DMS)中实例化一个对象,以DMS为桥梁与PMS进行交互通过异步回调机制来通知PMS那些发生了改变。同时也与WMS进行交互。

    Ø  DisplayPowerState.java/frameworks/base/services/core/java/com/android/server/display/DisplayPowerState.java)

      DPS,管理显示设备的状态仅在DPC中实例化一个对象,是DPC的一部分。

    Ø  Notifier.java:( /frameworks/base/services/core/java/com/android/server/power/Notifier.java

      将电源状态的重要变化,通过广播通知出去。

    Ø  ColorFade.java:(/frameworks/base/services/core/java/com/android/server/display/ColorFade.java

      是负责屏幕由关到开,由开到关的一些GL动画,由DPC进行控制。

    Ø  AutomaticBrightnessController.java:(/frameworks/base/services/core/java/com/android/server/display/AutomaticBrightnessController.java)

      主要处理光传感器,将底层上传的参数进行处理计算,将计算的新的亮度值传给DPC来设定屏幕的亮度值(即根据环境的光线强度来计算屏幕的亮暗程度)。

    Ø  RampAnimator.java:(/frameworks/base/services/core/java/com/android/server/display/RampAnimator.java)

      仅仅是屏幕亮度渐变动画。

    一、Power按键的上报与处理

    详细见【Android 7.0 Power 按键处理流程】此处仅略微的复习一下,方便了后面的理解。

    1Power按键的上报

    InputManagerService收到power按键事件经过一系列的处理和转换最终将会传递到PhoneWindowManager(PWM)的interceptKeyBeforeQueueing()函数来做具体的业务逻辑.下图为上报的流程图。

    2power 按键关于量灭屏处理

    关于量灭屏的处理主要在interceptKeyBeforeQueueing()函数中。判断是否是isWakeKey,如果是则在此函数的最后通过调用wakeUp()函数来具体处理,这就拉开了本文的序幕。

    注:此函数很长本文删除无关的部分,仅仅保留部分和量灭屏相关的说明具体处理流程即可。详细参考【Android 7.0 Power 按键处理流程

    A: 按键处理判断是否要量灭屏

    public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {
    
            boolean isWakeKey = (policyFlags & WindowManagerPolicy.FLAG_WAKE) != 0
                    || event.isWakeKey();
            if (interactive || (isInjected && !isWakeKey)) {
                // When the device is interactive or the key is injected pass the
                // key to the application.
                result = ACTION_PASS_TO_USER;
                isWakeKey = false;
    
                if (interactive) {
                    // If the screen is awake, but the button pressed was the one that woke the device
                    // then don't pass it to the application
                    if (keyCode == mPendingWakeKey && !down) {
                        result = 0;
                    }
                    // Reset the pending key
                    mPendingWakeKey = PENDING_KEY_NULL;
                }
            } else if (!interactive && shouldDispatchInputWhenNonInteractive(event)) {
                // If we're currently dozing with the screen on and the keyguard showing, pass the key
                // to the application but preserve its wake key status to make sure we still move
                // from dozing to fully interactive if we would normally go from off to fully
                // interactive.
                result = ACTION_PASS_TO_USER;
                // Since we're dispatching the input, reset the pending key
                mPendingWakeKey = PENDING_KEY_NULL;
            } else {
                // When the screen is off and the key is not injected, determine whether
                // to wake the device but don't pass the key to the application.
                result = 0;
                if (isWakeKey && (!down || !isWakeKeyWhenScreenOff(keyCode))) {
                    isWakeKey = false;
                }
                // Cache the wake key on down event so we can also avoid sending the up event to the app
                if (isWakeKey && down) {
                    mPendingWakeKey = keyCode;
                }
            }
    
            // 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) {
                    wakeUp(event.getEventTime(), mAllowTheaterModeWakeFromKey, "android.policy:KEY");
                }
                return result;
            }
    
         ....................
    
                case KeyEvent.KEYCODE_ENDCALL: {
                    result &= ~ACTION_PASS_TO_USER;
                    if (down) {
                        TelecomManager telecomManager = getTelecommService();
                        boolean hungUp = false;
                        if (telecomManager != null) {
                            hungUp = telecomManager.endCall();
                        }
                        if (interactive && !hungUp) {
                            mEndCallKeyHandled = false;
                            mHandler.postDelayed(mEndCallLongPress,
                                    ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout());
                        } else {
                            mEndCallKeyHandled = true;
                        }
                    } else {
                        if (!mEndCallKeyHandled) {
                            mHandler.removeCallbacks(mEndCallLongPress);
                            if (!canceled) {
                                if ((mEndcallBehavior
                                        & Settings.System.END_BUTTON_BEHAVIOR_HOME) != 0) {
                                    if (goHome()) {
                                        break;
                                    }
                                }
                                if ((mEndcallBehavior
                                        & Settings.System.END_BUTTON_BEHAVIOR_SLEEP) != 0) {
                                    mPowerManager.goToSleep(event.getEventTime(),
                                            PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON, 0);
                                    isWakeKey = false;
                                }
                            }
                        }
                    }
                    break;
                }
    
      
    
    ....................
    
            if (useHapticFeedback) {
                performHapticFeedbackLw(null, HapticFeedbackConstants.VIRTUAL_KEY, false);
            }
    
            if (isWakeKey) {
                wakeUp(event.getEventTime(), mAllowTheaterModeWakeFromKey, "android.policy:KEY");
            }
    
            return result;
        }

    BwakeUp处理量灭屏

    private boolean wakeUp(long wakeTime, boolean wakeInTheaterMode, String reason) {  
        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);      //调用PowerManagerService亮屏操作
            return true;  
        } 
    }

    二、PowerManagerService处理量灭屏过程

    从上面的分析可知,在PWM中处理按键事件如果需要唤醒屏幕则会调用PWM的wakeUp()函数,此函数会调用PMS 的wakeUp()函数来具体处理。

    从上面的分析可知,在PWM中处理按键事件如果需要唤醒屏幕则会调用PWM的wakeUp()函数,此函数会调用PMS 的wakeUp()函数来具体处理。

      注:限于篇幅本文仅列出重要的函数和调用过程

    首先来个概览,了解一下主要完成了如下三件事

    1)  由Notifier根据系统的具体状态来发出广播

    2)  PMS 通过updatePowerStateLocked()计算和更新电源的全局状态

    3)  PMS将最新的电源状态等传入DPC中,根据距离传感器和光感传感器,计算具体的屏幕亮度和量灭屏动画等

    4)  DPC通知PWM绘制keyguard与windows(此时会block等待绘制完成,灭屏时候无需绘制),绘制完成后通知DPC继续

    5)  DPC具体调用显示设备开启或关闭屏幕(执行量灭屏的动画效果)

    1)PowerManagerService--wakeUpNoUpdateLocked()

    PMS首先讲wakefullness状态. 之后发送亮灭屏广播通知其他应用手机处于亮屏还是灭屏状态。

    private boolean wakeUpNoUpdateLocked(long eventTime, String reason, int reasonUid,  
            String opPackageName, int opUid) {  
        if (DEBUG_SPEW) {  
            Slog.d(TAG, "wakeUpNoUpdateLocked: eventTime=" + eventTime + ", uid=" + reasonUid);  
        }  
      
        if (eventTime < mLastSleepTime || mWakefulness == WAKEFULNESS_AWAKE  
                || !mBootCompleted || !mSystemReady) {  
            return false;        //判断是否要去亮屏  
         }  
       
         Trace.traceBegin(Trace.TRACE_TAG_POWER, "wakeUp");  
         try {  
             switch (mWakefulness) {  
                 case WAKEFULNESS_ASLEEP:  
                     Slog.i(TAG, "Waking up from sleep due to"+opPackageName+" "+reason+" (uid " + reasonUid +")...");  
                     break;  
                 case WAKEFULNESS_DREAMING:  
                     Slog.i(TAG, "Waking up from dream due to"+opPackageName+" "+reason+" (uid " + reasonUid +")...");  
                     break;  
                 case WAKEFULNESS_DOZING:  
                     Slog.i(TAG, "Waking up from dozing due to"+opPackageName+" "+reason+" (uid " + reasonUid +")...");  
                     break;  
             }  
       
             mLastWakeTime = eventTime;   //设置最后一次唤醒的时间  
             setWakefulnessLocked(WAKEFULNESS_AWAKE, 0);   //Notifier调用onWakefulnessChangeStarted发送亮屏广播  
       
             mNotifier.onWakeUp(reason, reasonUid, opPackageName, opUid);  //调用Notifier通知battery处理  
             userActivityNoUpdateLocked(     //更新最后一次用户事件时间  
                     eventTime, PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, reasonUid);  
         } finally {  
             Trace.traceEnd(Trace.TRACE_TAG_POWER);  
         }  
         return true;  
     }  

    1)Notifier 发送量灭屏广播

    Notifier发送广播前会与与AMS,WMS,IMS进行交互,通知各模块电源状态的改变,各模块会自行处理电源状态改变通知。

    A:onWakefulnessChangeStarted()

    public void onWakefulnessChangeStarted(final int wakefulness, int reason) {  
       final boolean interactive = PowerManagerInternal.isInteractive(wakefulness); //亮屏true, 灭屏false  
       if (DEBUG) {  
           Slog.d(TAG, "onWakefulnessChangeStarted: wakefulness=" + wakefulness  
                   + ", reason=" + reason + ", interactive=" + interactive);  
       }  
     
       // Tell the activity manager about changes in wakefulness, not just interactivity.  
       // It needs more granularity than other components.  
        mHandler.post(new Runnable() {  
            @Override  
            public void run() {  
                mActivityManagerInternal.onWakefulnessChanged(wakefulness);   //与AMS交互处理  
            }  
        });  
      
        // Handle any early interactive state changes.  
        // Finish pending incomplete ones from a previous cycle.  
        if (mInteractive != interactive) {  
            // Finish up late behaviors if needed.  
            if (mInteractiveChanging) {  
                handleLateInteractiveChange();  
            }  
      
            // Start input as soon as we start waking up or going to sleep.  
            mInputManagerInternal.setInteractive(interactive);    //在IMS中记录现在的屏幕状态  
            mInputMethodManagerInternal.setInteractive(interactive);  
      
            // Notify battery stats.  
            try {  
                mBatteryStats.noteInteractive(interactive);   //唤醒battery状态  
            } catch (RemoteException ex) { }  
      
            // Handle early behaviors.  
            mInteractive = interactive;  
            mInteractiveChangeReason = reason;  
            mInteractiveChanging true;  
            handleEarlyInteractiveChange();   //初期处理交互模式改变  
        }  
    }  

    B: handleEarlyInteractiveChange()

    当屏幕在wakingup时需要通知window进行更新手势监听,更新方向监听,更新锁屏超时时间 

    private void handleEarlyInteractiveChange() {  
        synchronized (mLock) {  
            if (mInteractive) {  
                // Waking up...    //亮屏  
                mHandler.post(new Runnable() {  
                    @Override  
                    public void run() {  
                        EventLog.writeEvent(EventLogTags.POWER_SCREEN_STATE, 1, 0, 0, 0);  
                        mPolicy.startedWakingUp();   
                     }  
                 });  
       
                 // Send interactive broadcast.  
                 mPendingInteractiveState = INTERACTIVE_STATE_AWAKE;  
                 mPendingWakeUpBroadcast = true;  
                 updatePendingBroadcastLocked();   //更新亮屏广播  
             } else {  
                 // Going to sleep...   //灭屏  
                 // Tell the policy that we started going to sleep.  
                 final int why = translateOffReason(mInteractiveChangeReason);  
                 mHandler.post(new Runnable() {  
                     @Override  
                     public void run() {  
                         mPolicy.startedGoingToSleep(why);  
                     }  
                 });  
             }  
         } 

    (1):updatePendingBroadcastLocked()

        private void updatePendingBroadcastLocked() {
            if (!mBroadcastInProgress
                    && mPendingInteractiveState != INTERACTIVE_STATE_UNKNOWN
                    && (mPendingWakeUpBroadcast || mPendingGoToSleepBroadcast
                            || mPendingInteractiveState != mBroadcastedInteractiveState)) {
                mBroadcastInProgress = true;
                mSuspendBlocker.acquire();
                Message msg = mHandler.obtainMessage(MSG_BROADCAST);
                msg.setAsynchronous(true);
                mHandler.sendMessage(msg);
            }
        }

    (2)sendNextBroadcast()

     private void sendNextBroadcast() {
            final int powerState;
            synchronized (mLock) {
                if (mBroadcastedInteractiveState == INTERACTIVE_STATE_UNKNOWN) {
                    // Broadcasted power state is unknown.  Send wake up.
                    mPendingWakeUpBroadcast = false;
                    mBroadcastedInteractiveState = INTERACTIVE_STATE_AWAKE;
                } else if (mBroadcastedInteractiveState == INTERACTIVE_STATE_AWAKE) {
                    // Broadcasted power state is awake.  Send asleep if needed.
                    if (mPendingWakeUpBroadcast || mPendingGoToSleepBroadcast
                            || mPendingInteractiveState == INTERACTIVE_STATE_ASLEEP) {
                        mPendingGoToSleepBroadcast = false;
                        mBroadcastedInteractiveState = INTERACTIVE_STATE_ASLEEP;
                    } else {
                        finishPendingBroadcastLocked();
                        return;
                    }
                } else {
                    // Broadcasted power state is asleep.  Send awake if needed.
                    if (mPendingWakeUpBroadcast || mPendingGoToSleepBroadcast
                            || mPendingInteractiveState == INTERACTIVE_STATE_AWAKE) {
                        mPendingWakeUpBroadcast = false;
                        mBroadcastedInteractiveState = INTERACTIVE_STATE_AWAKE;
                    } else {
                        finishPendingBroadcastLocked();
                        return;
                    }
                }
    
                mBroadcastStartTime = SystemClock.uptimeMillis();
                powerState = mBroadcastedInteractiveState;
            }
    
            EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_SEND, 1);
    
            if (powerState == INTERACTIVE_STATE_AWAKE) {
                sendWakeUpBroadcast();//这里发送亮屏广播
            } else {
                sendGoToSleepBroadcast();
            }
        }

     (3)sendWakeUpBroadcast()

     注意:Notifier 自身也会接收亮屏广播,其受到后会调用finishPendingBroadcastLocked()函数来释放wakeLock

        private void sendWakeUpBroadcast() {
            if (DEBUG) {
                Slog.d(TAG, "Sending wake up broadcast.");
            }
    
            if (ActivityManagerNative.isSystemReady()) {
                mContext.sendOrderedBroadcastAsUser(mScreenOnIntent, UserHandle.ALL, null,
                        mWakeUpBroadcastDone, mHandler, 0, null, null);
            } else {
                EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_STOP, 2, 1);
                sendNextBroadcast();
            }
        }

  • 相关阅读:
    Encrypted Handshake Message
    RSAParameters Struct
    What if JWT is stolen?
    What's the difference between JWTs and Bearer Token?
    RSA Algorithm Example
    第18届Jolt大奖结果公布
    Ruby on rails开发从头来(windows)(三十六) 调试技巧
    Ruby on rails开发从头来(四十二) ActiveRecord基础(主键和ID)
    YouTube开放基础技术架构 让用户建自家YouTube
    Ruby on rails开发从头来(四十) ActiveRecord基础(Boolean属性)
  • 原文地址:https://www.cnblogs.com/dyufei/p/8017604.html
Copyright © 2011-2022 走看看