绪论
可以导致手机亮灭屏的因素有多种,而在本文中主要讲解按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处理
Message msg = mHandler.obtai