原文地址: https://www.cnblogs.com/dyufei/p/8017604.html

写的太好了,粘过来!

本篇从按下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: 按键处理判断是否要量灭屏

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 applicationif (keyCode == mPendingWakeKey && !down) {result = 0;}// Reset the pending keymPendingWakeKey = 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 keymPendingWakeKey = 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 appif (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;}

B:wakeUp处理量灭屏

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

Android 知识点 109 —— Android7.0 PowerManagerService 之亮灭屏相关推荐

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

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

  2. Android 系统(42)---Android7.0 PowerManagerService亮灭屏分析(三)

    Android7.0 PowerManagerService亮灭屏分析(三) 在前面两部分已经对绘制windows与设置设备状态进行了详细讲解. 之后接着就该对亮度值进行设置, 实现亮屏动作了. 在D ...

  3. Android 系统(40)--Android7.0 PowerManagerService亮灭屏分析(一)

    Android7.0 PowerManagerService亮灭屏分析(一) 可以导致手机亮灭屏的因素有多种,而在本文中主要讲解按power键亮灭屏过程以及来电亮屏.在亮灭屏过程power中主要的实现 ...

  4. Android 系统(41)---Android7.0 PowerManagerService亮灭屏分析(二)

    Android7.0 PowerManagerService亮灭屏分析(二) 3029 在PowerManagerService中对各种状态进行判断后,将其数值封装进DisplayPowerReque ...

  5. Android7.0 PowerManagerService亮灭屏分析(三)

    在前面两部分已经对绘制windows与设置设备状态进行了详细讲解. 之后接着就该对亮度值进行设置, 实现亮屏动作了. 在DisplayPowerController中的animateScreenBri ...

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

    绪论 可以导致手机亮灭屏的因素有多种,而在本文中主要讲解按power键亮灭屏过程以及来电亮屏.在亮灭屏过程power中主要的实现类与功能如下所述: PowerManagerService.java:以 ...

  7. Android7.0 PowerManagerService亮灭屏分析(二)

    在PowerManagerService中对各种状态进行判断后,将其数值封装进DisplayPowerRequest中传入DisplayPowerController中进一步处理.在亮屏过程中Disp ...

  8. Android7.0 PowerManagerService(3) 核心函数updatePowerStateLocked的主要流程

    前面的博客中,我们已经分析过,当Android中的进程要使用电量时,需要向PMS申请WakeLock:当进程完成工作后,需要释放对应的WakeLock.  PMS收到申请和释放WakeLock的请求后 ...

  9. Android 8.0 手机亮灭屏

    本文主要跟踪分析通过按松power键来唤醒,熄灭屏幕的逻辑.下面是一些相关类的介绍 PowerManagerService.java:简称PMS,负责Andorid系统中电源管理方面的工作.作为系统核 ...

最新文章

  1. 《github一天一道算法题》:并归排序
  2. 我们注意到您的计算机目前处于离线状态_如何将您的计算机添加到Pekka网络
  3. Github|类别不平衡学习资源(上)
  4. 绕过基于签名的XSS筛选器:修改HTML
  5. ubuntu环境搭建四:安装和使用git
  6. 西瓜书《机器学习》决策树IDW3, C4.5公式推导
  7. SystemCenter2012SP1实践(12)服务器、网络和存储配置
  8. R 中同步进行的多组比较的包:npmc
  9. SparkSQL Catalog的作用和访问Hive元数据信息
  10. redis通用key操作
  11. erps 单环基本原理
  12. win10子系统ubuntu WSL下无法用git下载代码
  13. open3d 0.13的c++版本使用demo
  14. 解决Oracle安装过程中出现的缺少KEY_XE.reg文件的问题
  15. web3对象提供了所有方法。
  16. vnc使用教程,超实用的vnc使用教程
  17. IdentityHashMap 源代码
  18. 什么是power bi
  19. C++程序设计课程主页-2015级
  20. 人工智能对人类有哪些影响 选择Python入门怎样

热门文章

  1. Actor模型和CSP模型的区别
  2. 转载:80端口、443端口、8080端口、8000端口的区别
  3. access是干什么的软件
  4. 【CSDN软件工程师能力认证学习精选】吐血整理!140 种 Python 标准库、第三方库和外部工具都有了
  5. excel删除重复的行
  6. 从事java的年龄_请教前辈们:JAVA的职业有年龄限制吗
  7. Echarts 柱状图横向展示和竖向展示
  8. 如何给MySQL 数据瘦身
  9. 利用WiFi控制手机进行刷宝APP看视频
  10. 如何突出照片中的人物