欢迎大家关注我的掘金帐号
我会在那里定期更新最新版本的Android Framework源码分析!
相关文章:
[Android Framework] 8.1 PowerManagerService分析(一)——PMS的启动
[Android Framework] 8.1 PowerManagerService分析(二) ——updatePowerStateLocked()方法
[Android Framework] 8.1 PowerManagerService分析(三)——WakeLock机制
本篇分析PMS中涉及到亮屏的部分,以及PMS相关的两个类:PowerManager和Notifier。
1.亮屏流程
1.1.Power键亮屏
这里直接从PhoneWindowManager开始分析。按power键后,会触发PhoneWindowManager的interceptKeyBeforeQueueing()方法:
@Override
public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {
.......
case KeyEvent.KEYCODE_POWER: {
cancelPendingAccessibilityShortcutAction();
result &= ~ACTION_PASS_TO_USER;
isWakeKey = false; // wake-up will be handled separately
if (down) {
interceptPowerKeyDown(event, interactive);
} else {
interceptPowerKeyUp(event, interactive, canceled);
}
break;
}
.......
在这个方法中,对Power键的按下和抬起做了处理,按下时,调用interceptPowerKeyDown()
:
private void interceptPowerKeyDown(KeyEvent event, boolean interactive) {
// Hold a wake lock until the power key is released.
if (!mPowerKeyWakeLock.isHeld()) {
//1.申请一个唤醒锁,使CPU保持唤醒
mPowerKeyWakeLock.acquire();
}
......
if (!mPowerKeyHandled) {
if (interactive) {
......
} else {
//2.进行亮屏处理
wakeUpFromPowerKey(event.getDownTime());
........
}
}
}
在这个方法中,首先是申请了一个唤醒锁,然后会对一些特定功能进行处理,如截屏、结束通话,等等,然后如果此时处于非交互状态(interactive=false),进行亮屏操作。该锁实例化如下:
mPowerKeyWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
"PhoneWindowManager.mPowerKeyWakeLock");
申请锁流程在PowerManagerService分析第三篇中已经分析过了。继续看wakeUpFromPowerKey()方法:
private void wakeUpFromPowerKey(long eventTime) {
//第三个参数为亮屏原因,因此如果是power键亮屏,则log中会出现android.policy:POWER
wakeUp(eventTime, mAllowTheaterModeWakeFromPowerKey, "android.policy:POWER");
}
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);
return true;
}
在这个方法中,首先判断是否允许在剧院模式下点亮屏幕(这个模式不常用,未进行详细分析),之后通过PowerManager在PMS进行屏幕的唤醒,先来看看PowerManager的wakeup()
方法:
public void wakeUp(long time) {
try {
mService.wakeUp(time, "wakeUp", mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
现在到PMS中继续分析流程:
@Override // Binder call
public void wakeUp(long eventTime, String reason, String opPackageName) {
if (eventTime > SystemClock.uptimeMillis()) {
throw new IllegalArgumentException("event time must not be in the future");
}
//权限检查
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.DEVICE_POWER, null);
final int uid = Binder.getCallingUid();
//清除IPC标志
final long ident = Binder.clearCallingIdentity();
try {
//调用内部方法
wakeUpInternal(eventTime, reason, uid, opPackageName, uid);
} finally {
//重置IPC标志
Binder.restoreCallingIdentity(ident);
}
}
在PMS中暴露给Binder客户端的方法中,进行了权限的检查,然后调用wakeUpInternal()
方法,该方法如下:
private void wakeUpInternal(long eventTime, String reason, int uid, String opPackageName,
int opUid) {
synchronized (mLock) {
if (wakeUpNoUpdateLocked(eventTime, reason, uid, opPackageName, opUid)) {
updatePowerStateLocked();
}
}
}
这里又调用了wakeUpNoUpdateLocked()
方法,如果这个方法返回true,则会执行updatePowerStateLocked()
方法,如果返回false,则整个过程结束。这个方法在我们分析wakelock申请时提到过,如果申请的wakelock锁带有唤醒屏幕的标志,也只执行这个方法,因此,这个方法是唤醒屏幕的主要方法之一,来看看这个方法:
private boolean wakeUpNoUpdateLocked(long eventTime, String reason, int reasonUid,
String opPackageName, int opUid) {
if (eventTime < mLastSleepTime || mWakefulness == WAKEFULNESS_AWAKE
|| !mBootCompleted || !mSystemReady) {
return false;
}
try {
//根据当前wakefulness状态打印log,这些log很有用
switch (mWakefulness) {
case WAKEFULNESS_ASLEEP:
Slog.i(TAG, "Waking up from sleep (uid " + reasonUid +")...");
break;
case WAKEFULNESS_DREAMING:
Slog.i(TAG, "Waking up from dream (uid " + reasonUid +")...");
break;
case WAKEFULNESS_DOZING:
Slog.i(TAG, "Waking up from dozing (uid " + reasonUid +")...");
break;
}
//设置最后一次亮屏时间,即该次的时间
mLastWakeTime = eventTime;
//设置wakefulness为WAKEFULNESS_AWAKE
setWakefulnessLocked(WAKEFULNESS_AWAKE, 0);
//Notifier中通知BatteryStatsService统计亮屏
mNotifier.onWakeUp(reason, reasonUid, opPackageName, opUid);
//更新用户活动时间
userActivityNoUpdateLocked(
eventTime, PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, reasonUid);
} finally {
}
return true;
}
在这个方法中,Log中的reason需要注意一下:
- Power键亮屏,则reason是PWM中传入的
android.policy:POWER
; - 来电亮屏为
android.server.am:TURN_ON
; - USB插拔时为
android.server.power:POWER
所以不管是哪种亮屏方式,最终都会在这里汇合的。之后通过setWakefulnessLocked()
方法设置wakefulness,再通过Notifier进行处理和通知其他系统服务wakefulness的改变,最后更新用户活动的时间,重置下次超时灭屏时间。继续看看setWakefulnessLocked()
:
void setWakefulnessLocked(int wakefulness, int reason