上一篇介绍了Android 电源键事件流程分析,其中分析了,在按电源键,长按的时候,弹出系统菜单,以及点击其中的关机按键,都执行了哪些操作。这一篇,作为上一篇的补充,主要分析一下,Android按键亮屏、息屏流程。

唤醒

case KeyEvent.KEYCODE_POWER: {EventLogTags.writeInterceptPower(KeyEvent.actionToString(event.getAction()),mPowerKeyHandled ? 1 : 0, mPowerKeyPressCounter);// Any activity on the power button stops the accessibility shortcutcancelPendingAccessibilityShortcutAction();result &= ~ACTION_PASS_TO_USER;isWakeKey = false; // wake-up will be handled separatelyif (down) {//interactive 表示当前是否是息屏interceptPowerKeyDown(event, interactive);} else {interceptPowerKeyUp(event, interactive, canceled);}break;}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.//......................} else {wakeUpFromPowerKey(event.getDownTime());//......................}}}

可以看到,在按下电源键的时候,如果判断,当前是息屏状态,则执行wakeUpFromPowerKey()方法,

  private void wakeUpFromPowerKey(long eventTime) {wakeUp(eventTime, mAllowTheaterModeWakeFromPowerKey,PowerManager.WAKE_REASON_POWER_BUTTON, "android.policy:POWER");}
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);// Turn on the connected TV and switch HDMI input if we're a HDMI playback device.final HdmiControl hdmiControl = getHdmiControl();if (hdmiControl != null) {hdmiControl.turnOnTv();}return true;}

往下继续追

  //android.os.PowerManagerpublic 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 callpublic void wakeUp(long eventTime, @WakeReason int reason, String details,String opPackageName) {if (eventTime > mClock.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();final long ident = Binder.clearCallingIdentity();try {wakeUpInternal(eventTime, reason, details, uid, opPackageName, uid);} finally {Binder.restoreCallingIdentity(ident);}}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()方法,如果它返回true,则执行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 || getWakefulnessLocked() == WAKEFULNESS_AWAKE|| mForceSuspendActive || !mSystemReady) {return false;}Trace.asyncTraceBegin(Trace.TRACE_TAG_POWER, TRACE_SCREEN_ON, 0);Trace.traceBegin(Trace.TRACE_TAG_POWER, "wakeUp");try {//更新屏幕亮屏超时时间mLastWakeTime = eventTime;mLastWakeReason = reason;setWakefulnessLocked(WAKEFULNESS_AWAKE, reason, eventTime);//通知BatteryStatsService、AppService系统服务状态改变mNotifier.onWakeUp(reason, details, reasonUid, opPackageName, opUid);//更新用户活动时间userActivityNoUpdateLocked(eventTime, PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, reasonUid);if (sQuiescent) {mDirty |= DIRTY_QUIESCENT;}} finally {Trace.traceEnd(Trace.TRACE_TAG_POWER);}return true;}

先来看看setWakefulnessLocked方法

    void setWakefulnessLocked(int wakefulness, int reason, long eventTime) {if (getWakefulnessLocked() != wakefulness) {// Under lock, invalidate before set ensures caches won't return stale values.mInjector.invalidateIsInteractiveCaches();mWakefulnessRaw = wakefulness;mWakefulnessChanging = true;mDirty |= DIRTY_WAKEFULNESS;// This is only valid while we are in wakefulness dozing. Set to false otherwise.mDozeStartInProgress &= (getWakefulnessLocked() == WAKEFULNESS_DOZING);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.mHandler.post(new Runnable() {@Overridepublic 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.mInputManagerInternal.setInteractive(interactive);mInputMethodManagerInternal.setInteractive(interactive);// Notify battery stats.try {mBatteryStats.noteInteractive(interactive);} catch (RemoteException ex) { }FrameworkStatsLog.write(FrameworkStatsLog.INTERACTIVE_STATE_CHANGED,interactive ? FrameworkStatsLog.INTERACTIVE_STATE_CHANGED__STATE__ON :FrameworkStatsLog.INTERACTIVE_STATE_CHANGED__STATE__OFF);// Handle early behaviors.mInteractive = interactive;mInteractiveChangeReason = reason;mInteractiveChangeStartTime = eventTime;mInteractiveChanging = true;handleEarlyInteractiveChange();}}
  private void handleEarlyInteractiveChange() {synchronized (mLock) {if (mInteractive) {// Waking up...mHandler.post(new Runnable() {@Overridepublic void run() {final int why = translateOnReason(mInteractiveChangeReason);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() {@Overridepublic void run() {mPolicy.startedGoingToSleep(why);}});}}}
    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);}}@Overridepublic void handleMessage(Message msg) {switch (msg.what) {case MSG_BROADCAST:sendNextBroadcast();break;//.......................}}
private void sendWakeUpBroadcast() {if (DEBUG) {Slog.d(TAG, "Sending wake up broadcast.");}/**
* mScreenOnIntent = new Intent(Intent.ACTION_SCREEN_ON);
*  mScreenOnIntent.addFlags(
*   Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FOREGROUND
*   | Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS);
*/if (mActivityManagerInternal.isSystemReady()) {mContext.sendOrderedBroadcastAsUser(mScreenOnIntent, UserHandle.ALL, null,mWakeUpBroadcastDone, mHandler, 0, null, null);} else {EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_STOP, 2, 1);sendNextBroadcast();}}

再来分析updatePowerStateLocked方法,此方法目的是更新PackageManagerService全局状态

   private void updatePowerStateLocked() {if (!mSystemReady || mDirty == 0) {return;}if (!Thread.holdsLock(mLock)) {Slog.wtf(TAG, "Power manager lock was not held when calling updatePowerStateLocked");}Trace.traceBegin(Trace.TRACE_TAG_POWER, "updatePowerState");try {// Phase 0: Basic state updates.updateIsPoweredLocked(mDirty);updateStayOnLocked(mDirty);updateScreenBrightnessBoostLocked(mDirty);// Phase 1: Update wakefulness.// Loop because the wake lock and user activity computations are influenced// by changes in wakefulness.final long now = mClock.uptimeMillis();int dirtyPhase2 = 0;for (;;) {int dirtyPhase1 = mDirty;dirtyPhase2 |= dirtyPhase1;mDirty = 0;updateWakeLockSummaryLocked(dirtyPhase1);updateUserActivitySummaryLocked(now, dirtyPhase1);updateAttentiveStateLocked(now, dirtyPhase1);if (!updateWakefulnessLocked(dirtyPhase1)) {break;}}// Phase 2: Lock profiles that became inactive/not kept awake.updateProfilesLocked(now);// Phase 3: Update display power state./***异步更新显示器电源状态。更新完成后,mDisplayReady 将设置为 true。显示控制器会发布一条消息,告诉我们实际显示电源状态何时更                                                  *  新,因此我们回到这里仔细检查并完成。此功能每次重新计算显示器电源状态。返回:如果显示已准备好,则为true。*经过这一步后,会将系统的亮度、显示状态等全部设置完毕,此时屏幕已经亮了*/final boolean displayBecameReady = updateDisplayPowerStateLocked(dirtyPhase2);// Phase 4: Update dream state (depends on display ready signal).updateDreamLocked(dirtyPhase2, displayBecameReady);// Phase 5: Send notifications, if needed.finishWakefulnessChangeIfNeededLocked();// Phase 6: Update suspend blocker.// Because we might release the last suspend blocker here, we need to make sure// we finished everything else first!updateSuspendBlockerLocked();} finally {Trace.traceEnd(Trace.TRACE_TAG_POWER);}}

再来分析 finishWakefulnessChangeIfNeededLocked() 方法,看看亮屏收尾工作都做了那些

   private void finishWakefulnessChangeIfNeededLocked() {if (mWakefulnessChanging && mDisplayReady) {if (getWakefulnessLocked() == WAKEFULNESS_DOZING&& (mWakeLockSummary & WAKE_LOCK_DOZE) == 0) {return; // wait until dream has enabled dozing} else {// Doze wakelock acquired (doze started) or device is no longer dozing.mDozeStartInProgress = false;}if (getWakefulnessLocked() == WAKEFULNESS_DOZING|| getWakefulnessLocked() == WAKEFULNESS_ASLEEP) {logSleepTimeoutRecapturedLocked();}if (getWakefulnessLocked() == WAKEFULNESS_AWAKE) {Trace.asyncTraceEnd(Trace.TRACE_TAG_POWER, TRACE_SCREEN_ON, 0);final int latencyMs = (int) (mClock.uptimeMillis() - mLastWakeTime);if (latencyMs >= SCREEN_ON_LATENCY_WARNING_MS) {Slog.w(TAG, "Screen on took " + latencyMs + " ms");}}mWakefulnessChanging = false;mNotifier.onWakefulnessChangeFinished();}}

Notifier类里的onWakefulnessChangeFinished

   public void onWakefulnessChangeFinished() {if (DEBUG) {Slog.d(TAG, "onWakefulnessChangeFinished");}if (mInteractiveChanging) {mInteractiveChanging = false;handleLateInteractiveChange();}}private void handleLateInteractiveChange() {synchronized (mLock) {final int interactiveChangeLatency =(int) (SystemClock.uptimeMillis() - mInteractiveChangeStartTime);if (mInteractive) {// Finished waking up...final int why = translateOnReason(mInteractiveChangeReason);mHandler.post(new Runnable() {@Overridepublic void run() {LogMaker log = new LogMaker(MetricsEvent.SCREEN);log.setType(MetricsEvent.TYPE_OPEN);log.setSubtype(why);log.setLatency(interactiveChangeLatency);log.addTaggedData(MetricsEvent.FIELD_SCREEN_WAKE_REASON, mInteractiveChangeReason);MetricsLogger.action(log);EventLogTags.writePowerScreenState(1, 0, 0, 0, interactiveChangeLatency);//通知PhoneWindowManager唤醒操作结束mPolicy.finishedWakingUp(why);}});} else {}}}

息屏

同唤醒操作类似,按键首先会走执行

 case KeyEvent.KEYCODE_POWER: {EventLogTags.writeInterceptPower(KeyEvent.actionToString(event.getAction()),mPowerKeyHandled ? 1 : 0, mPowerKeyPressCounter);// Any activity on the power button stops the accessibility shortcutcancelPendingAccessibilityShortcutAction();result &= ~ACTION_PASS_TO_USER;isWakeKey = false; // wake-up will be handled separatelyif (down) {interceptPowerKeyDown(event, interactive);} else {//手指抬起interceptPowerKeyUp(event, interactive, canceled);}break;}private void interceptPowerKeyUp(KeyEvent event, boolean interactive, boolean canceled) {final boolean handled = canceled || mPowerKeyHandled;mScreenshotChordPowerKeyTriggered = false;cancelPendingScreenshotChordAction();cancelPendingPowerKeyAction();if (!handled) {if ((event.getFlags() & KeyEvent.FLAG_LONG_PRESS) == 0) {// Abort possibly stuck animations only when power key up without long press case.mHandler.post(mWindowManagerFuncs::triggerAnimationFailsafe);}// 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.Message msg = mHandler.obtainMessage(MSG_POWER_DELAYED_PRESS,interactive ? 1 : 0, mPowerKeyPressCounter, eventTime);msg.setAsynchronous(true);mHandler.sendMessageDelayed(msg, ViewConfiguration.getMultiPressTimeout());return;}//核心代码// No other actions.  Handle it immediately.powerPress(eventTime, interactive, mPowerKeyPressCounter);}// Done.  Reset our state.finishPowerKeyPress();}

继续往下追

   private void powerPress(long eventTime, boolean interactive, int count) {if (mDefaultDisplayPolicy.isScreenOnEarly() && !mDefaultDisplayPolicy.isScreenOnFully()) {Slog.i(TAG, "Suppressed redundant power key press while "+ "already in the process of turning the screen on.");return;}Slog.d(TAG, "powerPress: eventTime=" + eventTime + " interactive=" + interactive+ " count=" + count + " beganFromNonInteractive=" + mBeganFromNonInteractive +" mShortPressOnPowerBehavior=" + mShortPressOnPowerBehavior);if (count == 2) {powerMultiPressAction(eventTime, interactive, mDoublePressOnPowerBehavior);} else if (count == 3) {powerMultiPressAction(eventTime, interactive, mTriplePressOnPowerBehavior);} else if (interactive && !mBeganFromNonInteractive) {switch (mShortPressOnPowerBehavior) {case SHORT_PRESS_POWER_NOTHING:break;case SHORT_PRESS_POWER_GO_TO_SLEEP:goToSleepFromPowerButton(eventTime, 0);break;case SHORT_PRESS_POWER_REALLY_GO_TO_SLEEP:goToSleepFromPowerButton(eventTime, PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE);break;//....................}}}}

查看mShortPressOnPowerBehavior赋值

       mShortPressOnPowerBehavior = mContext.getResources().getInteger(com.android.internal.R.integer.config_shortPressOnPowerBehavior);
//通过查看配置文件<!-- Control the behavior when the user short presses the power button.0 - Nothing1 - Go to sleep (doze)2 - Really go to sleep (don't doze)3 - Really go to sleep and go home (don't doze)4 - Go to home5 - Dismiss IME if shown. Otherwise go to home--><integer name="config_shortPressOnPowerBehavior">1</integer>

执行case SHORT_PRESS_POWER_GO_TO_SLEEP,即goToSleepFromPowerButton()方法

//由于按下电源按钮,设备进入睡眠状态。返回:如果设备被发送到睡眠状态,则返回 true,如果睡眠被抑制,则返回 falseprivate boolean goToSleepFromPowerButton(long eventTime, int flags) {// Before we actually go to sleep, we check the last wakeup reason.// If the device very recently woke up from a gesture (like user lifting their device)// then ignore the sleep instruction. This is because users have developed// a tendency to hit the power button immediately when they pick up their device, and we// don't want to put the device back to sleep in those cases.final PowerManager.WakeData lastWakeUp = mPowerManagerInternal.getLastWakeup();if (lastWakeUp != null && lastWakeUp.wakeReason == PowerManager.WAKE_REASON_GESTURE) {final int gestureDelayMillis = Settings.Global.getInt(mContext.getContentResolver(),Settings.Global.POWER_BUTTON_SUPPRESSION_DELAY_AFTER_GESTURE_WAKE,POWER_BUTTON_SUPPRESSION_DELAY_DEFAULT_MILLIS);final long now = SystemClock.uptimeMillis();if (mPowerButtonSuppressionDelayMillis > 0&& (now < lastWakeUp.wakeTime + mPowerButtonSuppressionDelayMillis)) {Slog.i(TAG, "Sleep from power button suppressed. Time since gesture: "+ (now - lastWakeUp.wakeTime) + "ms");return false;}}goToSleep(eventTime, PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON, flags);return true;}
 private void goToSleep(long eventTime, int reason, int flags) {mRequestedOrGoingToSleep = true;mPowerManager.goToSleep(eventTime, reason, flags);}

继续往下追PowerManagerService 的goToSleep()

  @Override // Binder callpublic void goToSleep(long eventTime, int reason, int flags) {if (eventTime > mClock.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();final long ident = Binder.clearCallingIdentity();try {goToSleepInternal(eventTime, reason, flags, uid);} finally {Binder.restoreCallingIdentity(ident);}}private void goToSleepInternal(long eventTime, int reason, int flags, int uid) {synchronized (mLock) {if (goToSleepNoUpdateLocked(eventTime, reason, flags, uid)) {updatePowerStateLocked();//稍后分析}}}
    @SuppressWarnings("deprecation")private boolean goToSleepNoUpdateLocked(long eventTime, int reason, int flags, int uid) {//........................Trace.traceBegin(Trace.TRACE_TAG_POWER, "goToSleep");try {reason = Math.min(PowerManager.GO_TO_SLEEP_REASON_MAX,Math.max(reason, PowerManager.GO_TO_SLEEP_REASON_MIN));Slog.i(TAG, "Going to sleep due to " + PowerManager.sleepReasonToString(reason)+ " (uid " + uid + ")...");//同wakeup一样,更新最后一次息屏时间mLastSleepTime = eventTime;mLastSleepReason = reason;mSandmanSummoned = true;mDozeStartInProgress = true;//核心代码setWakefulnessLocked(WAKEFULNESS_DOZING, reason, eventTime);// Report the number of wake locks that will be cleared by going to sleep.int numWakeLocksCleared = 0;final int numWakeLocks = mWakeLocks.size();for (int i = 0; i < numWakeLocks; i++) {final WakeLock wakeLock = mWakeLocks.get(i);switch (wakeLock.mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK) {case PowerManager.FULL_WAKE_LOCK:case PowerManager.SCREEN_BRIGHT_WAKE_LOCK:case PowerManager.SCREEN_DIM_WAKE_LOCK:numWakeLocksCleared += 1;break;}}EventLogTags.writePowerSleepRequested(numWakeLocksCleared);// Skip dozing if requested.if ((flags & PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE) != 0) {reallyGoToSleepNoUpdateLocked(eventTime, uid);}} finally {Trace.traceEnd(Trace.TRACE_TAG_POWER);}return true;}

同wakeup一样,会走到Notifer类的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.mHandler.post(new Runnable() {@Overridepublic 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.mInputManagerInternal.setInteractive(interactive);mInputMethodManagerInternal.setInteractive(interactive);// Notify battery stats.try {mBatteryStats.noteInteractive(interactive);} catch (RemoteException ex) { }FrameworkStatsLog.write(FrameworkStatsLog.INTERACTIVE_STATE_CHANGED,interactive ? FrameworkStatsLog.INTERACTIVE_STATE_CHANGED__STATE__ON :FrameworkStatsLog.INTERACTIVE_STATE_CHANGED__STATE__OFF);// Handle early behaviors.mInteractive = interactive;mInteractiveChangeReason = reason;mInteractiveChangeStartTime = eventTime;mInteractiveChanging = true;handleEarlyInteractiveChange();}}

继续看handleErarlyInteractiveChange()方法

 private void handleEarlyInteractiveChange() {synchronized (mLock) {if (mInteractive) {// Waking up...mHandler.post(new Runnable() {@Overridepublic void run() {final int why = translateOnReason(mInteractiveChangeReason);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() {@Overridepublic void run() {///通知PhoneWindowManager执行sleep操作mPolicy.startedGoingToSleep(why);}});}}}

我们现在在返回去看updatePowerStateLocked方法,对,没错,唤醒的时候,也会走到这里

   private void updatePowerStateLocked() {if (!mSystemReady || mDirty == 0) {return;}if (!Thread.holdsLock(mLock)) {Slog.wtf(TAG, "Power manager lock was not held when calling updatePowerStateLocked");}Trace.traceBegin(Trace.TRACE_TAG_POWER, "updatePowerState");try {// Phase 0: Basic state updates.updateIsPoweredLocked(mDirty);updateStayOnLocked(mDirty);updateScreenBrightnessBoostLocked(mDirty);// Phase 1: Update wakefulness.// Loop because the wake lock and user activity computations are influenced// by changes in wakefulness.final long now = mClock.uptimeMillis();int dirtyPhase2 = 0;for (;;) {int dirtyPhase1 = mDirty;dirtyPhase2 |= dirtyPhase1;mDirty = 0;updateWakeLockSummaryLocked(dirtyPhase1);updateUserActivitySummaryLocked(now, dirtyPhase1);updateAttentiveStateLocked(now, dirtyPhase1);if (!updateWakefulnessLocked(dirtyPhase1)) {break;}}// Phase 2: Lock profiles that became inactive/not kept awake.updateProfilesLocked(now);// Phase 3: Update display power state.final boolean displayBecameReady = updateDisplayPowerStateLocked(dirtyPhase2);// Phase 4: Update dream state (depends on display ready signal).updateDreamLocked(dirtyPhase2, displayBecameReady);// Phase 5: Send notifications, if needed.finishWakefulnessChangeIfNeededLocked();// Phase 6: Update suspend blocker.// Because we might release the last suspend blocker here, we need to make sure// we finished everything else first!updateSuspendBlockerLocked();} finally {Trace.traceEnd(Trace.TRACE_TAG_POWER);}}

当息屏执行结束,我们分析finishWakefulnessChangeIfNeededLocked方法

    private void finishWakefulnessChangeIfNeededLocked() {if (mWakefulnessChanging && mDisplayReady) {if (getWakefulnessLocked() == WAKEFULNESS_DOZING&& (mWakeLockSummary & WAKE_LOCK_DOZE) == 0) {return; // wait until dream has enabled dozing} else {// Doze wakelock acquired (doze started) or device is no longer dozing.mDozeStartInProgress = false;}if (getWakefulnessLocked() == WAKEFULNESS_DOZING|| getWakefulnessLocked() == WAKEFULNESS_ASLEEP) {logSleepTimeoutRecapturedLocked();}if (getWakefulnessLocked() == WAKEFULNESS_AWAKE) {Trace.asyncTraceEnd(Trace.TRACE_TAG_POWER, TRACE_SCREEN_ON, 0);final int latencyMs = (int) (mClock.uptimeMillis() - mLastWakeTime);if (latencyMs >= SCREEN_ON_LATENCY_WARNING_MS) {Slog.w(TAG, "Screen on took " + latencyMs + " ms");}}mWakefulnessChanging = false;mNotifier.onWakefulnessChangeFinished();}}

我们继续来分析Notifier类的onWakefulnessChangeFinished方法

    public void onWakefulnessChangeFinished() {if (DEBUG) {Slog.d(TAG, "onWakefulnessChangeFinished");}if (mInteractiveChanging) {mInteractiveChanging = false;handleLateInteractiveChange();}}
  private void handleLateInteractiveChange() {synchronized (mLock) {final int interactiveChangeLatency =(int) (SystemClock.uptimeMillis() - mInteractiveChangeStartTime);if (mInteractive) {// Finished waking up...final int why = translateOnReason(mInteractiveChangeReason);mHandler.post(new Runnable() {@Overridepublic void run() {LogMaker log = new LogMaker(MetricsEvent.SCREEN);log.setType(MetricsEvent.TYPE_OPEN);log.setSubtype(why);log.setLatency(interactiveChangeLatency);log.addTaggedData(MetricsEvent.FIELD_SCREEN_WAKE_REASON, mInteractiveChangeReason);MetricsLogger.action(log);EventLogTags.writePowerScreenState(1, 0, 0, 0, interactiveChangeLatency);mPolicy.finishedWakingUp(why);}});} else {// Finished going to sleep...// This is a good time to make transitions that we don't want the user to see,// such as bringing the key guard to focus.  There's no guarantee for this// however because the user could turn the device on again at any time.// Some things may need to be protected by other mechanisms that defer screen on.// Cancel pending user activity.if (mUserActivityPending) {mUserActivityPending = false;mHandler.removeMessages(MSG_USER_ACTIVITY);}// Tell the policy we finished going to sleep.final int why = translateOffReason(mInteractiveChangeReason);mHandler.post(new Runnable() {@Overridepublic void run() {LogMaker log = new LogMaker(MetricsEvent.SCREEN);log.setType(MetricsEvent.TYPE_CLOSE);log.setSubtype(why);log.setLatency(interactiveChangeLatency);log.addTaggedData(MetricsEvent.FIELD_SCREEN_SLEEP_REASON, mInteractiveChangeReason);MetricsLogger.action(log);EventLogTags.writePowerScreenState(0, why, 0, 0, interactiveChangeLatency);//通知PhoneWindowManager 息屏完成mPolicy.finishedGoingToSleep(why);}});// Send non-interactive broadcast.mPendingInteractiveState = INTERACTIVE_STATE_ASLEEP;mPendingGoToSleepBroadcast = true;//发送息屏广播,和唤醒类似,就不再赘述了。updatePendingBroadcastLocked();}}}

好了,从我们分析源码得知
唤醒的时候,唤醒广播是在handleEarlyInteractiveChange方法,就是在通知PhoneWindowManager 去执行startedWakingUp方法,紧跟着就执行updatePendingBroadcastLocked方法,去发送唤醒广播
而在息屏的时候,在handleEarlyInteractiveChange里,我们只是通知PhoneWindowManager去执行startedGoingToSleep方法,最后在updatePowerStateLocked==>finishWakefulnessChangeIfNeededLocked==>Notifier==>onWakefulnessChangeFinished==》handleLateInteractiveChange方法里,在通知PhoneWindowManager执行finishedGoingToSleep()之后,才执行updatePendingBroadcastLocked()方法去发送息屏广播(Intent.ACTION_SCREEN_OFF),这个时机需要特别注意一下。

Android 按电源键亮屏/息屏流程分析相关推荐

  1. Android屏幕常亮防息屏

    Android屏幕常亮防息屏 PowerManager 主要是用来控制电源状态的. 通过使用该类提供的api可以控制电池的待机时间 尽可能的使用最低级别的WakeLocks锁,并且确保使用完后释放它 ...

  2. 联想笔记本键盘亮屏幕不亮_联想笔记本电脑开机键亮但是黑屏 联想笔记本电脑键盘失灵怎么办...

    联想笔记本电脑一直是笔记本电脑行业里的大品牌,非常的受人们欢迎.但是它在使用时也会遇到很多问题,例如联想笔记本电脑开机键亮但是黑屏怎么办?联想笔记本电脑键盘失灵怎么办?所以在联想笔记本选购之前需要了解 ...

  3. 联想笔记本键盘亮屏幕不亮_联想笔记本电脑开机键亮但是黑屏,联想笔记本电脑键盘失灵怎么办...

    联想笔记本电脑一直是笔记本电脑行业的大品牌,深受人们的喜爱.然而,它在使用时也会遇到很多问题,比如如何处理联想笔记本电脑开机键亮但是黑屏?联想笔记本电脑键盘失灵怎么办?因此,在购买联想笔记本之前,我们 ...

  4. 【板栗糖GIS】联想拯救者的电源键亮红色是什么意思?

    联想拯救者的电源键亮红色是什么意思? 联想拯救者电源键红点是进入了野兽模式. 联想拯救者有三种模式. 电源红色是野兽模式,在大型游戏时开. 白色是均衡模式平常用的. 蓝色是静音模式,办公时候使用. 按 ...

  5. 针对xps13无法开机,按下电源键亮几秒无反应的问题

    背景:2018.3.24晚我初学git后,关机睡觉.第二天,起来第一件事就是打开电脑继续我的学习.这个时候,TM的电脑出问题了,怎么都无法开机.我慌了,长按1分钟,30秒......都快要把电源键按烂 ...

  6. android app启动流程分析,Android应用开发之Android 7.0 Launcher3的启动和加载流程分析...

    本文将带你了解Android应用开发Android 7.0 Launcher3的启动和加载流程分析,希望本文对大家学Android有所帮助. Android 7.0 Launcher3的启动和加载流程 ...

  7. Android 7.0 Launcher3的启动和加载流程分析----转载

     Android 7.0 Launcher3的启动和加载流程分析,Launcher的本质就是一个普通应用,它比普通应用多配置了Category的Android:name="android ...

  8. 【Android 逆向】整体加固脱壳 ( DEX 优化流程分析 | dvmDexFileOpenPartial | dexFileParse | 脱壳点 | 获取 dex 文件在内存中的首地址 )

    文章目录 前言 一.DexPrepare.cpp 中 rewriteDex() 方法分析 二.DvmDex.cpp 中 dvmDexFileOpenPartial() 方法分析 ( 脱壳点 ) 三.D ...

  9. 【Android 逆向】整体加固脱壳 ( DEX 优化流程分析 | DexPrepare.cpp 中 dvmContinueOptimizati() 函数分析 )

    文章目录 前言 一.DexPrepare.cpp 中 dvmContinueOptimizati() 方法分析 前言 上一篇博客 [Android 逆向]整体加固脱壳 ( DEX 优化流程分析 | D ...

最新文章

  1. 中国人口将迎来负增长,这是旷视们的机会
  2. Cent OS – Tomcat 7 - 集群
  3. 安卓连接mysql客户端_安卓客户端与mysql服务器端数据交互
  4. leetcode算法题--最长湍流子数组
  5. OnScrollListener回调分析
  6. RocketMQ集群之集群模式讲解
  7. 随机加解密java_JAVA随机数生成 Math.random和java.util.Random使用简介
  8. 盲僧一键r闪用什么设置_美加狮R.A.T. PRO X3至尊版带你畅玩模拟飞行
  9. Linux 实操 —— Linux 系统性能分析
  10. mysql show
  11. ASP.NET 页面验证cookie
  12. Android 内存映射mmap浅谈
  13. tc的linux命令详解,linux tc命令详解
  14. 中国大学MOOC体育保健学考试试题及答案
  15. 我的2013——学习、工作与生活
  16. linux绝育玩客云_玩客云实用指南(真·无痛绝育),附玩物下载对比
  17. 应用系统安全规范-自己想到和网络搜索到的点子记录整合一下
  18. Autoware介绍
  19. Excel 2019:二级级联下拉框设置
  20. python文件有几种类型、分别是什么_4. 内置类型

热门文章

  1. 凝胶负载染料行业调研报告 - 市场现状分析与发展前景预测(2021-2027年)
  2. linux车机系统怎么进工厂模式,工厂方法模式 - 跟JBPM学习设计模式_Linux编程_Linux公社-Linux系统门户网站...
  3. AD19-DRC检查
  4. 拼多多店铺怎么布置装修,订单才能暴涨?
  5. 【SAP】ABAP开发——ALV展示后字段的下划线连接
  6. 刚体“下落速度“与“质量“无关
  7. 人脑与计算机之间有什么联系,电脑和人脑有什么不同
  8. 云时代编程语言Ballerina发布,TIOBE9月排行榜PHP排名在边缘飘摇(2019/09/16)
  9. ballerina 学习 三十一 扩展开发(二)
  10. 新版华为P30,这5个新功能C位出道,3988值得拥有