本篇从按下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 按键处理流程】此处仅略微的复习一下,方便了后面的理解。

1)Power按键的上报

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

2)power 按键关于量灭屏处理

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

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

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

  1. public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {
  2.  
  3. boolean isWakeKey = (policyFlags & WindowManagerPolicy.FLAG_WAKE) != 0
  4. || event.isWakeKey();
  5. if (interactive || (isInjected && !isWakeKey)) {
  6. // When the device is interactive or the key is injected pass the
  7. // key to the application.
  8. result = ACTION_PASS_TO_USER;
  9. isWakeKey = false;
  10.  
  11. if (interactive) {
  12. // If the screen is awake, but the button pressed was the one that woke the device
  13. // then don't pass it to the application
  14. if (keyCode == mPendingWakeKey && !down) {
  15. result = 0;
  16. }
  17. // Reset the pending key
  18. mPendingWakeKey = PENDING_KEY_NULL;
  19. }
  20. } else if (!interactive && shouldDispatchInputWhenNonInteractive(event)) {
  21. // If we're currently dozing with the screen on and the keyguard showing, pass the key
  22. // to the application but preserve its wake key status to make sure we still move
  23. // from dozing to fully interactive if we would normally go from off to fully
  24. // interactive.
  25. result = ACTION_PASS_TO_USER;
  26. // Since we're dispatching the input, reset the pending key
  27. mPendingWakeKey = PENDING_KEY_NULL;
  28. } else {
  29. // When the screen is off and the key is not injected, determine whether
  30. // to wake the device but don't pass the key to the application.
  31. result = 0;
  32. if (isWakeKey && (!down || !isWakeKeyWhenScreenOff(keyCode))) {
  33. isWakeKey = false;
  34. }
  35. // Cache the wake key on down event so we can also avoid sending the up event to the app
  36. if (isWakeKey && down) {
  37. mPendingWakeKey = keyCode;
  38. }
  39. }
  40.  
  41. // If the key would be handled globally, just return the result, don't worry about special
  42. // key processing.
  43. if (isValidGlobalKey(keyCode)
  44. && mGlobalKeyManager.shouldHandleGlobalKey(keyCode, event)) {
  45. if (isWakeKey) {
  46. wakeUp(event.getEventTime(), mAllowTheaterModeWakeFromKey, "android.policy:KEY");
  47. }
  48. return result;
  49. }
  50.  
  51. ....................
  52.  
  53. case KeyEvent.KEYCODE_ENDCALL: {
  54. result &= ~ACTION_PASS_TO_USER;
  55. if (down) {
  56. TelecomManager telecomManager = getTelecommService();
  57. boolean hungUp = false;
  58. if (telecomManager != null) {
  59. hungUp = telecomManager.endCall();
  60. }
  61. if (interactive && !hungUp) {
  62. mEndCallKeyHandled = false;
  63. mHandler.postDelayed(mEndCallLongPress,
  64. ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout());
  65. } else {
  66. mEndCallKeyHandled = true;
  67. }
  68. } else {
  69. if (!mEndCallKeyHandled) {
  70. mHandler.removeCallbacks(mEndCallLongPress);
  71. if (!canceled) {
  72. if ((mEndcallBehavior
  73. & Settings.System.END_BUTTON_BEHAVIOR_HOME) != 0) {
  74. if (goHome()) {
  75. break;
  76. }
  77. }
  78. if ((mEndcallBehavior
  79. & Settings.System.END_BUTTON_BEHAVIOR_SLEEP) != 0) {
  80. mPowerManager.goToSleep(event.getEventTime(),
  81. PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON, 0);
  82. isWakeKey = false;
  83. }
  84. }
  85. }
  86. }
  87. break;
  88. }
  89.  
  90. ....................
  91.  
  92. if (useHapticFeedback) {
  93. performHapticFeedbackLw(null, HapticFeedbackConstants.VIRTUAL_KEY, false);
  94. }
  95.  
  96. if (isWakeKey) {
  97. wakeUp(event.getEventTime(), mAllowTheaterModeWakeFromKey, "android.policy:KEY");
  98. }
  99.  
  100. return result;
  101. }

B:wakeUp处理量灭屏

  1. private boolean wakeUp(long wakeTime, boolean wakeInTheaterMode, String reason) {
  2. final boolean theaterModeEnabled = isTheaterModeEnabled();
  3. if (!wakeInTheaterMode && theaterModeEnabled) {
  4. return false;
  5. }
  6.  
  7. if (theaterModeEnabled) {
  8. Settings.Global.putInt(mContext.getContentResolver(),
  9. Settings.Global.THEATER_MODE_ON, 0);
  10. }
  11.  
  12. mPowerManager.wakeUp(wakeTime, reason); //调用PowerManagerService亮屏操作
  13. return true;
  14. }
  15. }

二、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状态. 之后发送亮灭屏广播通知其他应用手机处于亮屏还是灭屏状态。

  1. private boolean wakeUpNoUpdateLocked(long eventTime, String reason, int reasonUid,  
  2.         String opPackageName, int opUid) {  
  3.     if (DEBUG_SPEW) {  
  4.         Slog.d(TAG, "wakeUpNoUpdateLocked: eventTime=" + eventTime + ", uid=" + reasonUid);  
  5.     }  
  6.   
  7.     if (eventTime < mLastSleepTime || mWakefulness == WAKEFULNESS_AWAKE  
  8.             || !mBootCompleted || !mSystemReady) {  
  9.         return false;        //判断是否要去亮屏  
  10.     }  
  11.   
  12.     Trace.traceBegin(Trace.TRACE_TAG_POWER, "wakeUp");  
  13.     try {  
  14.         switch (mWakefulness) {  
  15.             case WAKEFULNESS_ASLEEP:  
  16.                 Slog.i(TAG, "Waking up from sleep due to"+opPackageName+" "+reason+" (uid " + reasonUid +")...");  
  17.                 break;  
  18.             case WAKEFULNESS_DREAMING:  
  19.                 Slog.i(TAG, "Waking up from dream due to"+opPackageName+" "+reason+" (uid " + reasonUid +")...");  
  20.                 break;  
  21.             case WAKEFULNESS_DOZING:  
  22.                 Slog.i(TAG, "Waking up from dozing due to"+opPackageName+" "+reason+" (uid " + reasonUid +")...");  
  23.                 break;  
  24.         }  
  25.   
  26.         mLastWakeTime = eventTime;   //设置最后一次唤醒的时间  
  27.         setWakefulnessLocked(WAKEFULNESS_AWAKE, 0);   //Notifier调用onWakefulnessChangeStarted发送亮屏广播  
  28.   
  29.         mNotifier.onWakeUp(reason, reasonUid, opPackageName, opUid);  //调用Notifier通知battery处理  
  30.         userActivityNoUpdateLocked(     //更新最后一次用户事件时间  
  31.                 eventTime, PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, reasonUid);  
  32.     } finally {  
  33.         Trace.traceEnd(Trace.TRACE_TAG_POWER);  
  34.     }  
  35.     return true;  
  36. }  

1)Notifier 发送量灭屏广播

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

A:onWakefulnessChangeStarted()

  1. public void onWakefulnessChangeStarted(final int wakefulness, int reason) {  
  2.    final boolean interactive = PowerManagerInternal.isInteractive(wakefulness); //亮屏true, 灭屏false  
  3.    if (DEBUG) {  
  4.        Slog.d(TAG, "onWakefulnessChangeStarted: wakefulness=" + wakefulness  
  5.                + ", reason=" + reason + ", interactive=" + interactive);  
  6.    }  
  7.  
  8.    // Tell the activity manager about changes in wakefulness, not just interactivity.  
  9.    // It needs more granularity than other components.  
  10.     mHandler.post(new Runnable() {  
  11.         @Override  
  12.         public void run() {  
  13.             mActivityManagerInternal.onWakefulnessChanged(wakefulness);   //与AMS交互处理  
  14.         }  
  15.     });  
  16.   
  17.     // Handle any early interactive state changes.  
  18.     // Finish pending incomplete ones from a previous cycle.  
  19.     if (mInteractive != interactive) {  
  20.         // Finish up late behaviors if needed.  
  21.         if (mInteractiveChanging) {  
  22.             handleLateInteractiveChange();  
  23.         }  
  24.   
  25.         // Start input as soon as we start waking up or going to sleep.  
  26.         mInputManagerInternal.setInteractive(interactive);    //在IMS中记录现在的屏幕状态  
  27.         mInputMethodManagerInternal.setInteractive(interactive);  
  28.   
  29.         // Notify battery stats.  
  30.         try {  
  31.             mBatteryStats.noteInteractive(interactive);   //唤醒battery状态  
  32.         } catch (RemoteException ex) { }  
  33.   
  34.         // Handle early behaviors.  
  35.         mInteractive = interactive;  
  36.         mInteractiveChangeReason = reason;  
  37.         mInteractiveChanging = true;  
  38.         handleEarlyInteractiveChange();   //初期处理交互模式改变  
  39.     }  
  40. }  

B: handleEarlyInteractiveChange()

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

  1. private void handleEarlyInteractiveChange() {
  2. synchronized (mLock) {
  3. if (mInteractive) {
  4. // Waking up... //亮屏
  5. mHandler.post(new Runnable() {
  6. @Override
  7. public void run() {
  8. EventLog.writeEvent(EventLogTags.POWER_SCREEN_STATE, 1, 0, 0, 0);
  9. mPolicy.startedWakingUp();
  10. }
  11. });
  12.  
  13. // Send interactive broadcast.
  14. mPendingInteractiveState = INTERACTIVE_STATE_AWAKE;
  15. mPendingWakeUpBroadcast = true;
  16. updatePendingBroadcastLocked(); //更新亮屏广播
  17. } else {
  18. // Going to sleep... //灭屏
  19. // Tell the policy that we started going to sleep.
  20. final int why = translateOffReason(mInteractiveChangeReason);
  21. mHandler.post(new Runnable() {
  22. @Override
  23. public void run() {
  24. mPolicy.startedGoingToSleep(why);
  25. }
  26. });
  27. }
  28. }

(1):updatePendingBroadcastLocked()

  1. private void updatePendingBroadcastLocked() {
  2. if (!mBroadcastInProgress
  3. && mPendingInteractiveState != INTERACTIVE_STATE_UNKNOWN
  4. && (mPendingWakeUpBroadcast || mPendingGoToSleepBroadcast
  5. || mPendingInteractiveState != mBroadcastedInteractiveState)) {
  6. mBroadcastInProgress = true;
  7. mSuspendBlocker.acquire();
  8. Message msg = mHandler.obtainMessage(MSG_BROADCAST);
  9. msg.setAsynchronous(true);
  10. mHandler.sendMessage(msg);
  11. }
  12. }

(2)sendNextBroadcast()

  1. private void sendNextBroadcast() {
  2. final int powerState;
  3. synchronized (mLock) {
  4. if (mBroadcastedInteractiveState == INTERACTIVE_STATE_UNKNOWN) {
  5. // Broadcasted power state is unknown. Send wake up.
  6. mPendingWakeUpBroadcast = false;
  7. mBroadcastedInteractiveState = INTERACTIVE_STATE_AWAKE;
  8. } else if (mBroadcastedInteractiveState == INTERACTIVE_STATE_AWAKE) {
  9. // Broadcasted power state is awake. Send asleep if needed.
  10. if (mPendingWakeUpBroadcast || mPendingGoToSleepBroadcast
  11. || mPendingInteractiveState == INTERACTIVE_STATE_ASLEEP) {
  12. mPendingGoToSleepBroadcast = false;
  13. mBroadcastedInteractiveState = INTERACTIVE_STATE_ASLEEP;
  14. } else {
  15. finishPendingBroadcastLocked();
  16. return;
  17. }
  18. } else {
  19. // Broadcasted power state is asleep. Send awake if needed.
  20. if (mPendingWakeUpBroadcast || mPendingGoToSleepBroadcast
  21. || mPendingInteractiveState == INTERACTIVE_STATE_AWAKE) {
  22. mPendingWakeUpBroadcast = false;
  23. mBroadcastedInteractiveState = INTERACTIVE_STATE_AWAKE;
  24. } else {
  25. finishPendingBroadcastLocked();
  26. return;
  27. }
  28. }
  29.  
  30. mBroadcastStartTime = SystemClock.uptimeMillis();
  31. powerState = mBroadcastedInteractiveState;
  32. }
  33.  
  34. EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_SEND, 1);
  35.  
  36. if (powerState == INTERACTIVE_STATE_AWAKE) {
  37. sendWakeUpBroadcast();//这里发送亮屏广播
  38. } else {
  39. sendGoToSleepBroadcast();
  40. }
  41. }

 (3)sendWakeUpBroadcast()

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

  1. private void sendWakeUpBroadcast() {
  2. if (DEBUG) {
  3. Slog.d(TAG, "Sending wake up broadcast.");
  4. }
  5.  
  6. if (ActivityManagerNative.isSystemReady()) {
  7. mContext.sendOrderedBroadcastAsUser(mScreenOnIntent, UserHandle.ALL, null,
  8. mWakeUpBroadcastDone, mHandler, 0, null, null);
  9. } else {
  10. EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_STOP, 2, 1);
  11. sendNextBroadcast();
  12. }
  13. }

Android7.0 PowerManagerService 之亮灭屏(一)的更多相关文章

  1. Android7.0 PowerManagerService 之亮灭屏(二) PMS 电源状态管理updatePowerStateLocked()

    本篇注意接着上篇[Android7.0 PowerManagerService 之亮灭屏(一)]继续分析量灭屏的流程,这篇主要分析PMS的状态计算和更新流程,也是PMS中最为重要和复杂的一部分电源状态 ...

  2. qcom 8953平台 LCD亮灭屏流程及LCD知识点总结【转】

    一.LK中亮屏流程 gcdb_display_init(),进行display初始化的起始地方: oem_panel_select(),在这里去选择哪一款屏,也可以在这里添加新一款屏: dsi_pan ...

  3. Android横竖屏切换和灭屏亮屏时Activity的生命周期探究(1)

    研究这个问题的初衷在于项目中碰到了一个问题:横屏的时候灭屏再亮屏,亮屏的时候用户能够清晰的看到先启动竖屏(过程1)再切换到横屏的过程,因为灭屏的时候onSaveInstanceState()保存的时横 ...

  4. Android7.0 Doze模式分析(一)Doze介绍 &amp; DeviceIdleController

     參考:http://blog.csdn.net/gaugamela/article/details/52981984 在Android M中.Google就引入了Doze模式.它定义了一种全新的 ...

  5. 关机充电如何实现短按pwrkey灭屏

    目前关机充电PWRKEY实现长按开机和短按亮屏功能,灭屏是根据BL_SWITCH_TIMEOUTS时间,自动灭屏的:如果需要实现PWRKEY主动灭屏,请按照如下方法修改:     alps/media ...

  6. PIC12F629帮我用C语言写个程序,控制三个LED亮灭

    http://power.baidu.com/question/240873584599025684.html?entry=browse_difficult PIC12F629帮我用C语言写个程序,控 ...

  7. (三)开关检测来控制LED灯的亮灭

    开关检测案例一: 具体电路图如下: K1--K4闭合,控制 D1—D4 亮灭 产生的问题: 1.关于 R8 R9 R7 R10 的阻值选择问题,倘若太大的话,  比如10K 不管开关断开还是闭合,好像 ...

  8. Android -- 距离感应器控制屏幕灭屏白屏

    权限                                                                                             <u ...

  9. n盏灯亮灭问题

    前几天看了华为的一个上机操作题,讲得是n盏灯亮灭问题,本质上还是数学问题,感觉很有趣,和大家分享一下,问题描述如下: 有n盏灯排成一排,依次标号1,2,…,n,每盏灯都有一根拉线开关,最初电灯都是关着 ...

随机推荐

  1. C#连接oracle数据库提示ORA-12154: TNS: 无法解析指定的连接标识符

    C#连接oracle数据库提示ORA-12154: TNS: 无法解析指定的连接标识符如果PLSQL Develope能连接上而用代码无法连接上则可以考虑sqlnet.ora文件中是否有NAMES.D ...

  2. LeetCode 548. Split Array with Equal Sum (分割数组使得子数组的和都相同)$

    Given an array with n integers, you need to find if there are triplets (i, j, k) which satisfies fol ...

  3. App 组件化/模块化之路——使用SDK的思路进行模块化设计接口

    在不久之前分享一篇<App 组件化/模块化之路——如何封装网络请求框架>文章介绍了我在项目中封装网络请求框架的思路.开发一个 App 会涉及到很多网络请求 API ,例如登录注册接口.用户 ...

  4. 一个有意思的Python小程序(全国省会名称随机出题)

    本文为作者原创,转载请注明出处(http://www.cnblogs.com/mar-q/)by 负赑屃 最近比较迷Python,仿照<Python编程快速上手>8.5写了一个随机出卷的小 ...

  5. 将一个实体转换成 Url 参数的形式 ?a=a&b=b

    function toQueryString(obj) { var ret = []; for (var key in obj) { key = encodeURIComponent(key); va ...

  6. hbase-1.2.5完全分布式部署

    详细配置参考http://abloz.com/hbase/book.html#distributed ,2.2.2.2小节 1.修改hbase-site.xml文件.添加如下配置 cluster为ha ...

  7. 基于winsocket的框体Server和Client

    前面学了一点Winsock的知识,会编写简单的Server和Client,现在就想通过VS2008编写框体的Server和Client,而不是在控制台上的操作了,毕竟学编程就是要多加练习,在实践中发现 ...

  8. code forces 436 C. Bus

    C. Bus time limit per test 2 seconds memory limit per test 256 megabytes input standard input output ...

  9. 【Win 10 应用开发】UI Composition 札记(三):与 XAML 集成

    除了 DirectX 游戏开发,我们一般很少单独使用 UI Composition ,因此,与 XAML 互动并集成是必然结果.这样能够把两者的优势混合使用,让UI布局能够更灵活. 说到与 XAML ...

  10. Tomcat初应用

    Tomcat初应用 这里我们自己建立一个html的web资源,然后在tomcat里进行配置,使我们可以通过服务器在浏览器里打开. 第一步:新建html文件,在里面随便输入几个字符串如:新建txt文件- ...