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 按键处理流程】此处仅略微的复习一下,方便了后面的理解。
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 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;
- }
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();
- }
- }
Android7.0 PowerManagerService 之亮灭屏(一)的更多相关文章
- Android7.0 PowerManagerService 之亮灭屏(二) PMS 电源状态管理updatePowerStateLocked()
本篇注意接着上篇[Android7.0 PowerManagerService 之亮灭屏(一)]继续分析量灭屏的流程,这篇主要分析PMS的状态计算和更新流程,也是PMS中最为重要和复杂的一部分电源状态 ...
- qcom 8953平台 LCD亮灭屏流程及LCD知识点总结【转】
一.LK中亮屏流程 gcdb_display_init(),进行display初始化的起始地方: oem_panel_select(),在这里去选择哪一款屏,也可以在这里添加新一款屏: dsi_pan ...
- Android横竖屏切换和灭屏亮屏时Activity的生命周期探究(1)
研究这个问题的初衷在于项目中碰到了一个问题:横屏的时候灭屏再亮屏,亮屏的时候用户能够清晰的看到先启动竖屏(过程1)再切换到横屏的过程,因为灭屏的时候onSaveInstanceState()保存的时横 ...
- Android7.0 Doze模式分析(一)Doze介绍 & DeviceIdleController
參考:http://blog.csdn.net/gaugamela/article/details/52981984 在Android M中.Google就引入了Doze模式.它定义了一种全新的 ...
- 关机充电如何实现短按pwrkey灭屏
目前关机充电PWRKEY实现长按开机和短按亮屏功能,灭屏是根据BL_SWITCH_TIMEOUTS时间,自动灭屏的:如果需要实现PWRKEY主动灭屏,请按照如下方法修改: alps/media ...
- PIC12F629帮我用C语言写个程序,控制三个LED亮灭
http://power.baidu.com/question/240873584599025684.html?entry=browse_difficult PIC12F629帮我用C语言写个程序,控 ...
- (三)开关检测来控制LED灯的亮灭
开关检测案例一: 具体电路图如下: K1--K4闭合,控制 D1—D4 亮灭 产生的问题: 1.关于 R8 R9 R7 R10 的阻值选择问题,倘若太大的话, 比如10K 不管开关断开还是闭合,好像 ...
- Android -- 距离感应器控制屏幕灭屏白屏
权限 <u ...
- n盏灯亮灭问题
前几天看了华为的一个上机操作题,讲得是n盏灯亮灭问题,本质上还是数学问题,感觉很有趣,和大家分享一下,问题描述如下: 有n盏灯排成一排,依次标号1,2,…,n,每盏灯都有一根拉线开关,最初电灯都是关着 ...
随机推荐
- C#连接oracle数据库提示ORA-12154: TNS: 无法解析指定的连接标识符
C#连接oracle数据库提示ORA-12154: TNS: 无法解析指定的连接标识符如果PLSQL Develope能连接上而用代码无法连接上则可以考虑sqlnet.ora文件中是否有NAMES.D ...
- 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 ...
- App 组件化/模块化之路——使用SDK的思路进行模块化设计接口
在不久之前分享一篇<App 组件化/模块化之路——如何封装网络请求框架>文章介绍了我在项目中封装网络请求框架的思路.开发一个 App 会涉及到很多网络请求 API ,例如登录注册接口.用户 ...
- 一个有意思的Python小程序(全国省会名称随机出题)
本文为作者原创,转载请注明出处(http://www.cnblogs.com/mar-q/)by 负赑屃 最近比较迷Python,仿照<Python编程快速上手>8.5写了一个随机出卷的小 ...
- 将一个实体转换成 Url 参数的形式 ?a=a&b=b
function toQueryString(obj) { var ret = []; for (var key in obj) { key = encodeURIComponent(key); va ...
- hbase-1.2.5完全分布式部署
详细配置参考http://abloz.com/hbase/book.html#distributed ,2.2.2.2小节 1.修改hbase-site.xml文件.添加如下配置 cluster为ha ...
- 基于winsocket的框体Server和Client
前面学了一点Winsock的知识,会编写简单的Server和Client,现在就想通过VS2008编写框体的Server和Client,而不是在控制台上的操作了,毕竟学编程就是要多加练习,在实践中发现 ...
- code forces 436 C. Bus
C. Bus time limit per test 2 seconds memory limit per test 256 megabytes input standard input output ...
- 【Win 10 应用开发】UI Composition 札记(三):与 XAML 集成
除了 DirectX 游戏开发,我们一般很少单独使用 UI Composition ,因此,与 XAML 互动并集成是必然结果.这样能够把两者的优势混合使用,让UI布局能够更灵活. 说到与 XAML ...
- Tomcat初应用
Tomcat初应用 这里我们自己建立一个html的web资源,然后在tomcat里进行配置,使我们可以通过服务器在浏览器里打开. 第一步:新建html文件,在里面随便输入几个字符串如:新建txt文件- ...