一.亮屏
在上面讲解PSensor灭屏的时候其实已经有涉及到关于亮屏的相关知识。当灭屏之后WakeLock就不会被进程所持有,因此如果需要点亮屏幕,就需要去申请WakeLock。我们以最简单的按Power键亮屏来讲述
1.Power键亮屏
按下Power键的时候,down值为true,就会执行到interceptPowerKeyDown方法:
private void interceptPowerKeyDown(KeyEvent event, boolean interactive) {
// Hold a wake lock until the power key is released.
// 申请唤醒锁
if (!mPowerKeyWakeLock.isHeld()) {
mPowerKeyWakeLock.acquire();
}
// Cancel multi-press detection timeout.
if (mPowerKeyPressCounter != 0) {
mHandler.removeMessages(MSG_POWER_DELAYED_PRESS);
}
mWindowManagerFuncs.onPowerKeyDown(interactive);
// Latch power key state to detect screenshot chord.
if (interactive && !mScreenshotChordPowerKeyTriggered
&& (event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) {
mScreenshotChordPowerKeyTriggered = true;
mScreenshotChordPowerKeyTime = event.getDownTime();
interceptScreenshotChord();
interceptRingerToggleChord();
}
// Stop ringing or end call if configured to do so when power is pressed.
TelecomManager telecomManager = getTelecommService();
boolean hungUp = false;
if (telecomManager != null) {
if (telecomManager.isRinging()) {
// 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();
}
}
GestureLauncherService gestureService = LocalServices.getService(
GestureLauncherService.class);
boolean gesturedServiceIntercepted = false;
if (gestureService != null) {
gesturedServiceIntercepted = gestureService.interceptPowerKeyDown(event, interactive,
mTmpBoolean);
if (mTmpBoolean.value && mRequestedOrGoingToSleep) {
mCameraGestureTriggeredDuringGoingToSleep = true;
}
}
// Inform the StatusBar; but do not allow it to consume the event.
sendSystemKeyToStatusBarAsync(event.getKeyCode());
schedulePossibleVeryLongPressReboot();
// If the power key has still not yet been handled, then detect short
// press, long press, or multi press and decide what to do.
mPowerKeyHandled = hungUp || mScreenshotChordVolumeDownKeyTriggered
|| mA11yShortcutChordVolumeUpKeyTriggered || 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.
// 长按power键
if (hasLongPressOnPowerBehavior()) {
if ((event.getFlags() & KeyEvent.FLAG_LONG_PRESS) != 0) {
powerLongPress();
} else {
Message msg = mHandler.obtainMessage(MSG_POWER_LONG_PRESS);
msg.setAsynchronous(true);
if (hasVeryLongPressOnPowerBehavior()) {
Message longMsg = mHandler.obtainMessage(MSG_POWER_VERY_LONG_PRESS);
longMsg.setAsynchronous(true);
mHandler.sendMessageDelayed(longMsg, mVeryLongPressTimeout);
}
}
}
} else {
// 亮屏处理
wakeUpFromPowerKey(event.getDownTime());
if (mSupportLongPressPowerWhenNonInteractive && hasLongPressOnPowerBehavior()) {
if ((event.getFlags() & KeyEvent.FLAG_LONG_PRESS) != 0) {
powerLongPress();
} else {
Message msg = mHandler.obtainMessage(MSG_POWER_LONG_PRESS);
msg.setAsynchronous(true);
if (hasVeryLongPressOnPowerBehavior()) {
Message longMsg = mHandler.obtainMessage(MSG_POWER_VERY_LONG_PRESS);
longMsg.setAsynchronous(true);
mHandler.sendMessageDelayed(longMsg, mVeryLongPressTimeout);
}
}
mBeganFromNonInteractive = true;
} else {
final int maxCount = getMaxMultiPressPowerCount();
if (maxCount <= 1) {
mPowerKeyHandled = true;
} else {
mBeganFromNonInteractive = true;
}
}
}
}
}来看wakeUpFromPowerKey方法:
可以看到会先去申请一个WakeLock锁,之后执行亮屏动作。调用wakeUpFromPowerKey方法:
private void wakeUpFromPowerKey(long eventTime) {
wakeUp(eventTime, mAllowTheaterModeWakeFromPowerKey,
PowerManager.WAKE_REASON_POWER_BUTTON, "android.policy:POWER");
}
接着看wakeUp的实现:
private boolean wakeUp(long wakeTime, boolean wakeInTheaterMode, @WakeReason int reason,
String details) {
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, details);
return true;
}
传入的第三个参数是亮屏的原因:WAKE_REASON_POWER_BUTTON(按Power键亮屏)。最终会走到PowerManager的wakeup方法(传三个参数的):
public void wakeUp(long time, @WakeReason int reason, String details) {
try {
mService.wakeUp(time, reason, details, mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
这时就会调用PowerManagerService的wakeUp方法:
@Override // Binder call
public void wakeUp(long eventTime, @WakeReason int reason, String details,
String opPackageName) {
if (eventTime > SystemClock.uptimeMillis()) {
throw new IllegalArgumentException("event time must not be in the future");
}
// 判断DEVICE_POWER权限
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.DEVICE_POWER, null);
final int uid = Binder.getCallingUid();
final long ident = Binder.clearCallingIdentity();
try {
wakeUpInternal(eventTime, reason, details, uid, opPackageName, uid);
} finally {
Binder.restoreCallingIdentity(ident);
}
}
执行到wakeUpInternal方法:
private void wakeUpInternal(long eventTime, @WakeReason int reason, String details, int uid,
String opPackageName, int opUid) {
synchronized (mLock) {
if (wakeUpNoUpdateLocked(eventTime, reason, details, uid, opPackageName, opUid)) {
updatePowerStateLocked();
}
}
}
加锁后,先调用wakeUpNoUpdateLocked判断是否需要update,一般都是返回true。最终还是执行到PowerManagerService的关键方法updatePowerStateLocked上。
private boolean wakeUpNoUpdateLocked(long eventTime, @WakeReason int reason, String details,
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 || mForceSuspendActive) {
return false;
}
Trace.asyncTraceBegin(Trace.TRACE_TAG_POWER, TRACE_SCREEN_ON, 0);
Trace.traceBegin(Trace.TRACE_TAG_POWER, "wakeUp");
try {
Slog.i(TAG, "Waking up from "
+ PowerManagerInternal.wakefulnessToString(mWakefulness)
+ " (uid=" + reasonUid
+ ", reason=" + PowerManager.wakeReasonToString(reason)
+ ", details=" + details
+ ")...");
// 设置最后一次亮屏时间,即该次的时间
mLastWakeTime = eventTime;
// 设置最后一次亮屏的原因,即该次的原因
mLastWakeReason = reason;
// 设置wakefulness为WAKEFULNESS_AWAKE
setWakefulnessLocked(WAKEFULNESS_AWAKE, reason, eventTime);
// 通知BatteryStatsService统计亮屏
mNotifier.onWakeUp(reason, details, reasonUid, opPackageName, opUid);
// 更新用户活动时间
userActivityNoUpdateLocked(
eventTime, PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, reasonUid);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_POWER);
}
return true;
}
接着看setWakefulnessLocked方法的实现:
void setWakefulnessLocked(int wakefulness, int reason, long eventTime) {
if (mWakefulness != wakefulness) {
mWakefulness = wakefulness;
mWakefulnessChanging = true;
mDirty |= DIRTY_WAKEFULNESS;
if (mNotifier != null) {
mNotifier.onWakefulnessChangeStarted(wakefulness, reason, eventTime);
}
mAttentionDetector.onWakefulnessChangeStarted(wakefulness);
}
}
这里会调用Notifier类的onWakefulnessChangeStarted方法,这个方法是用来通知设备正在更改唤醒状态:
public void onWakefulnessChangeStarted(final int wakefulness, int reason, long eventTime) {
final boolean interactive = PowerManagerInternal.isInteractive(wakefulness);
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.
// 唤醒ActivityManagerService
mHandler.post(new Runnable() {
@Override
public void run() {
mActivityManagerInternal.onWakefulnessChanged(wakefulness);
}
});
// 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.
// 启动Input
mInputManagerInternal.setInteractive(interactive);
mInputMethodManagerInternal.setInteractive(interactive);
// Notify battery stats.
// 通知电池状态
try {
mBatteryStats.noteInteractive(interactive);
} catch (RemoteException ex) { }
StatsLog.write(StatsLog.INTERACTIVE_STATE_CHANGED,
interactive ? StatsLog.INTERACTIVE_STATE_CHANGED__STATE__ON :
StatsLog.INTERACTIVE_STATE_CHANGED__STATE__OFF);
// Handle early behaviors.
// 处理前期行为
mInteractive = interactive;
mInteractiveChangeReason = reason;
mInteractiveChangeStartTime = eventTime;
mInteractiveChanging = true;
handleEarlyInteractiveChange();
}
}
处理前期交互的handleEarlyInteractiveChange方法:
private void handleEarlyInteractiveChange() {
synchronized (mLock) {
if (mInteractive) {
// Waking up...
mHandler.post(new Runnable() {
@Override
public void run() {
final int why = translateOnReason(mInteractiveChangeReason);
// 回调PhoneWindowManager
mPolicy.startedWakingUp(why);
}
});
// 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);
}
});
}
}
}
调用堆栈信息如下:
12-09 03:31:37.397 1086 1192 I xw : at android.os.PowerManager.wakeUp(PowerManager.java:1208)
12-09 03:31:37.397 1086 1192 I xw : at com.android.server.policy.PhoneWindowManager.wakeUp(PhoneWindowManager.java:4981)
12-09 03:31:37.397 1086 1192 I xw : at com.android.server.policy.PhoneWindowManager.wakeUpFromPowerKey(PhoneWindowManager.java:4965)
12-09 03:31:37.397 1086 1192 I xw : at com.android.server.policy.PhoneWindowManager.interceptPowerKeyDown(PhoneWindowManager.java:1124)
12-09 03:31:37.397 1086 1192 I xw : at com.android.server.policy.PhoneWindowManager.interceptKeyBeforeQueueing(PhoneWindowManager.java:4283)
12-09 03:31:37.397 1086 1192 I xw : at com.android.server.wm.InputManagerCallback.interceptKeyBeforeQueueing(InputManagerCallback.java:164)
12-09 03:31:37.397 1086 1192 I xw : at com.android.server.input.InputManagerService.interceptKeyBeforeQueueing(InputManagerService.java:1827)
##二.总结
这里涉及的PowerManagerServices的一部分亮屏流程。整个唤醒流程是底层把power key传到上层 --> PowerManagerService处理 -->初始化keyguard/唤醒底层 --> 将亮度写到设备节点中。
adroid_newbie 发布了18 篇原创文章 · 获赞 5 · 访问量 2万+ 私信 关注