Android 亮屏流程分析
https://blog.csdn.net/FightFightFight/article/details/79808100
相关文章:
[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()方法:
@Overridepublic int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {.......case KeyEvent.KEYCODE_POWER: {cancelPendingAccessibilityShortcutAction();result &= ~ACTION_PASS_TO_USER;isWakeKey = false; // wake-up will be handled separatelyif (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:POWERwakeUp(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();}
}
@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();}}
}
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_AWAKEsetWakefulnessLocked(WAKEFULNESS_AWAKE, 0);//Notifier中通知BatteryStatsService统计亮屏mNotifier.onWakeUp(reason, reasonUid, opPackageName, opUid);//更新用户活动时间userActivityNoUpdateLocked(eventTime, PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, reasonUid);} finally {}return true;
}
- Power键亮屏,则reason是PWM中传入的
android.policy:POWER
; - 来电亮屏为
android.server.am:TURN_ON
; - USB插拔时为
android.server.power:POWER
void setWakefulnessLocked(int wakefulness, int reason) {if (mWakefulness != wakefulness) {//改变WakefulnessmWakefulness = wakefulness;mWakefulnessChanging = true;//置位操作mDirty |= DIRTY_WAKEFULNESS;if (mNotifier != null) {//处理wakefulness改变前的操作mNotifier.onWakefulnessChangeStarted(wakefulness, reason);}}
}
为了不显得凌乱,将关于Notifier的具体细节的分析放在了3小节中。这里对其大概的进行下阐述。onWakefulnessChangeStarted()
方法部分如下:
public void onWakefulnessChangeStarted(final int wakefulness, int reason) {final boolean interactive = PowerManagerInternal.isInteractive(wakefulness);if (DEBUG) {Slog.d(TAG, "onWakefulnessChangeStarted: wakefulness=" + wakefulness+ ", reason=" + reason + ", interactive=" + interactive);}// 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();}// Handle early behaviors.mInteractive = interactive;mInteractiveChangeReason = reason;mInteractiveChanging = true;//做亮屏早期工作handleEarlyInteractiveChange();}}
- interactive为true;
- mInteractive为false;
- mInteractiveChanging = true;
因此会开始执行handleEarlyInteractiveChange()
方法,做一些亮屏前期的工作,该方法亮屏部分如下:
private void handleEarlyInteractiveChange() {synchronized (mLock) {if (mInteractive) {// Waking up...mHandler.post(new Runnable() {@Overridepublic void run() {//回调PhoneWindowManagermPolicy.startedWakingUp();}});// Send interactive broadcast.mPendingInteractiveState = INTERACTIVE_STATE_AWAKE;mPendingWakeUpBroadcast = true;//发送亮/灭屏广播updatePendingBroadcastLocked();} else {// Going to sleep...}}}
首先,会回调PhoneWindowManager中的startedWakingUp()
,然后发送亮屏广播。在startedWakingUp()
中的工作如下:
@Overridepublic void startedWakingUp() {if (DEBUG_WAKEUP) Slog.i(TAG, "Started waking up...");synchronized (mLock) {mAwake = true;updateWakeGestureListenerLp();updateOrientationListenerLp();updateLockScreenTimeout();}if (mKeyguardDelegate != null) {mKeyguardDelegate.onStartedWakingUp();}}
public void onWakeUp(String reason, int reasonUid, String opPackageName, int opUid) {try {//开始统计亮屏时间mBatteryStats.noteWakeUp(reason, reasonUid);if (opPackageName != null) {mAppOps.noteOperation(AppOpsManager.OP_TURN_SCREEN_ON, opUid, opPackageName);}} catch (RemoteException ex) {}
}
private boolean userActivityNoUpdateLocked(long eventTime, int event, int flags, int uid) {// ....../*** USER_ACTIVITY_FLAG_NO_CHANGE_LIGHTS标识* 只有带有PowerManager.ON_AFTER_RELEASE类型的锁在释放时才会有该flag,在亮屏流程中没有该标识,因此不满足该条* 件,如果满足条件,改变mLastUserActivityTimeNoChangeLights的值,否则进入else语句,改变* mLastUserActivityTime的值*/if ((flags & PowerManager.USER_ACTIVITY_FLAG_NO_CHANGE_LIGHTS) != 0) {if (eventTime > mLastUserActivityTimeNoChangeLights&& eventTime > mLastUserActivityTime) {mLastUserActivityTimeNoChangeLights = eventTime;mDirty |= DIRTY_USER_ACTIVITY;if (event == PowerManager.USER_ACTIVITY_EVENT_BUTTON) {mDirty |= DIRTY_QUIESCENT;}return true;}} else {if (eventTime > mLastUserActivityTime) {mLastUserActivityTime = eventTime;mDirty |= DIRTY_USER_ACTIVITY;if (event == PowerManager.USER_ACTIVITY_EVENT_BUTTON) {mDirty |= DIRTY_QUIESCENT;}return true;}}// ......return false;
}
private void applyWakeLockFlagsOnReleaseLocked(WakeLock wakeLock) {if ((wakeLock.mFlags & PowerManager.ON_AFTER_RELEASE) != 0&& isScreenLock(wakeLock)) {userActivityNoUpdateLocked(SystemClock.uptimeMillis(),PowerManager.USER_ACTIVITY_EVENT_OTHER,PowerManager.USER_ACTIVITY_FLAG_NO_CHANGE_LIGHTS,wakeLock.mOwnerUid);}
}
因此,如果是释放带有ON_AFTER_REALESE
标记的锁,则会给该方法传入USER_ACTIVITY_FLAG_NO_CHANGE_LIGHT
标记,其他场景下不会带有该标识。
private boolean updateDisplayPowerStateLocked(int dirty) {final boolean oldDisplayReady = mDisplayReady;//策略值,请求Display的重要属性mDisplayPowerRequest.policy = getDesiredScreenPolicyLocked();//确定亮度值部分省略......//亮度值mDisplayPowerRequest.screenBrightness = screenBrightness;//自动调节亮度比例值mDisplayPowerRequest.screenAutoBrightnessAdjustment =screenAutoBrightnessAdjustment;//是否是用户设置亮度mDisplayPowerRequest.brightnessSetByUser = brightnessSetByUser;//是否使用自动调节亮度mDisplayPowerRequest.useAutoBrightness = autoBrightness;//是否使用PSensormDisplayPowerRequest.useProximitySensor = shouldUseProximitySensorLocked();//是否进行亮度增强mDisplayPowerRequest.boostScreenBrightness = shouldBoostScreenBrightness();//低电量模式一些值的设置updatePowerRequestFromBatterySaverPolicy(mDisplayPowerRequest);//Doze状态下相关设置值if (mDisplayPowerRequest.policy == DisplayPowerRequest.POLICY_DOZE) {mDisplayPowerRequest.dozeScreenState = mDozeScreenStateOverrideFromDreamManager;if (mDisplayPowerRequest.dozeScreenState == Display.STATE_DOZE_SUSPEND&& (mWakeLockSummary & WAKE_LOCK_DRAW) != 0) {mDisplayPowerRequest.dozeScreenState = Display.STATE_DOZE;}mDisplayPowerRequest.dozeScreenBrightness =mDozeScreenBrightnessOverrideFromDreamManager;} else {mDisplayPowerRequest.dozeScreenState = Display.STATE_UNKNOWN;mDisplayPowerRequest.dozeScreenBrightness = PowerManager.BRIGHTNESS_DEFAULT;}//通过DMS本地服务DisplayManagerInternal请求DisplayManagerServicemDisplayReady = mDisplayManagerInternal.requestPowerState(mDisplayPowerRequest,mRequestWaitForNegativeProximity);mRequestWaitForNegativeProximity = false;if ((dirty & DIRTY_QUIESCENT) != 0) {sQuiescent = false;}}//mDisplayReady表示请求的新的显示是否完成return mDisplayReady && !oldDisplayReady;}
@VisibleForTesting
int getDesiredScreenPolicyLocked() {//asleep时,policy值为0if (mWakefulness == WAKEFULNESS_ASLEEP || sQuiescent) {return DisplayPowerRequest.POLICY_OFF;//0}if (mWakefulness == WAKEFULNESS_DOZING) {if ((mWakeLockSummary & WAKE_LOCK_DOZE) != 0) {return DisplayPowerRequest.POLICY_DOZE;//1}if (mDozeAfterScreenOffConfig) {return DisplayPowerRequest.POLICY_OFF;}} if ((mWakeLockSummary & WAKE_LOCK_SCREEN_BRIGHT) != 0|| (mUserActivitySummary & USER_ACTIVITY_SCREEN_BRIGHT) != 0|| !mBootCompleted|| mScreenBrightnessBoostInProgress) {return DisplayPowerRequest.POLICY_BRIGHT;//3}return DisplayPowerRequest.POLICY_DIM;
}
public boolean requestPowerState(DisplayPowerRequest request,boolean waitForNegativeProximity) {synchronized (mLock) {boolean changed = false;//开机后第一次进入if (mPendingRequestLocked == null) {mPendingRequestLocked = new DisplayPowerRequest(request);changed = true;//如果该次请求和上次请求不同,说明已经改变,需要更新Display} else if (!mPendingRequestLocked.equals(request)) {mPendingRequestLocked.copyFrom(request);changed = true;}/*** changed为true,说明有改变发生,这个改变交给Handler异步去处理,此时说* 明显示没有准备好,mDisplayReadyLocked=false* 直到改变处理成功,mDisplayReadyLocked又被置为true,*/if (changed) {mDisplayReadyLocked = false;}//mPendingRequestChangedLocked:用于标识电源请求状态或者PSensor标签是//否改变if (changed && !mPendingRequestChangedLocked) {mPendingRequestChangedLocked = true;sendUpdatePowerStateLocked();}return mDisplayReadyLocked;}
}
private final DisplayManagerInternal.DisplayPowerCallbacks mDisplayPowerCallbacks =new DisplayManagerInternal.DisplayPowerCallbacks() {private int mDisplayState = Display.STATE_UNKNOWN;@Overridepublic void onStateChanged() {synchronized (mLock) {mDirty |= DIRTY_ACTUAL_DISPLAY_POWER_STATE_UPDATED;updatePowerStateLocked();}}.........}
1.2.插拔USB亮屏
原理
当插拔USB时,会发送BATTERY_CHANGED广播,PMS中对该广播进行监听,如果收到广播后,配置了插播USB时亮屏,则会进行亮屏操作。
在BatteryService中,如果电池状态发生改变,则会发送一个ACTION_Battery_CAHNGED广播:
private void sendIntentLocked() {// Pack up the values and broadcast them to everyonefinal Intent intent = new Intent(Intent.ACTION_BATTERY_CHANGED);intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY| Intent.FLAG_RECEIVER_REPLACE_PENDING);....mHandler.post(new Runnable() {@Overridepublic void run() {ActivityManager.broadcastStickyIntent(intent, UserHandle.USER_ALL);}});
}
在PMS中,注册了广播接受者,会接收该广播:
public void systemReady(IAppOpsService appOps) {....
IntentFilter filter = new IntentFilter();filter.addAction(Intent.ACTION_BATTERY_CHANGED);filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);mContext.registerReceiver(new BatteryReceiver(), filter, null, mHandler);......
}
因此当BatteryService中检测到底层电池状态发生变化后,会发送该广播,PMS中的BatteryReceiver用于接受该广播并进行处理,如下:
private final class BatteryReceiver extends BroadcastReceiver {@Overridepublic void onReceive(Context context, Intent intent) {synchronized (mLock) {handleBatteryStateChangedLocked();}}
}
继续看看:
private void handleBatteryStateChangedLocked() {mDirty |= DIRTY_BATTERY_STATE;updatePowerStateLocked();
}
在这里对mDirty进行了置位,之后开始调用updatePowerStateLocked()方法。在之前已经分析过该方法了,其中调用的updateIsPowerLocked()方法之前分析过了,是插播USB亮屏的入口方法,所有和电池相关的都是在这里处理。这里看看具体是如何进行亮屏的:
private void updateIsPoweredLocked(int dirty) {if ((dirty & DIRTY_BATTERY_STATE) != 0) {........if (shouldWakeUpWhenPluggedOrUnpluggedLocked(wasPowered, oldPlugType, dockedOnWirelessCharger)) {wakeUpNoUpdateLocked(now, "android.server.power:POWER", Process.SYSTEM_UID,mContext.getOpPackageName(), Process.SYSTEM_UID);}}}
}
因此,如果shouldWakeUpWhenPluggedOrUnpluggedLocked()
方法返回true,则会开始亮屏,否则不会亮屏。该方法如下:
private boolean shouldWakeUpWhenPluggedOrUnpluggedLocked(boolean wasPowered, int oldPlugType, boolean dockedOnWirelessCharger) {// 如果配置config_unplugTurnsOnScreen为false,则不会亮屏if (!mWakeUpWhenPluggedOrUnpluggedConfig) {return false;}//断开无线充电不会亮屏if (wasPowered && !mIsPowered&& oldPlugType == BatteryManager.BATTERY_PLUGGED_WIRELESS) {return false;}//连接无线充电不会亮屏if (!wasPowered && mIsPowered&& mPlugType == BatteryManager.BATTERY_PLUGGED_WIRELESS&& !dockedOnWirelessCharger) {return false;}// 插入充电时屏保状态下不会亮屏if (mIsPowered && mWakefulness == WAKEFULNESS_DREAMING) {return false;}//剧院模式下,且配置了剧院模式下充电是否亮屏为false,则不会亮屏if (mTheaterModeEnabled && !mWakeUpWhenPluggedOrUnpluggedInTheaterModeConfig) {return false;}//如果屏幕保持常亮且当前wakefulness为Doze状态if (mAlwaysOnEnabled && mWakefulness == WAKEFULNESS_DOZING) {return false;}// 其他情况下则亮屏return true;
}
当该方法返回true后,开始调用wakeUpNoUpdateLocked()
方法开始唤醒屏幕,该方法是唤醒屏幕的入口方法,在前面有详细的分析。
2.PowerManager类
PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
public PowerManager(Context context, IPowerManager service, Handler handler) {mContext = context;mService = service;mHandler = handler;
}
在PowerManager中,提供了许多public方法,当应用层调用这些方法时,PowerManager将向下调用PMS。
3.Notifier类
3.1.onWakefulnessChangeStarted()
public void onWakefulnessChangeStarted(final int wakefulness, int reason) {//是否可以和用户进行交互
//既wakefulness == WAKEFULNESS_AWAKE || WAKEFULNESS_DREAMfinal boolean interactive = PowerManagerInternal.isInteractive(wakefulness);mHandler.post(new Runnable() {@Overridepublic void run() {//和AMS交互,通知AMS wakefulness发生改变mActivityManagerInternal.onWakefulnessChanged(wakefulness);}});//如果为false,表示交互状态发生改变,即从亮屏到灭屏或者从灭屏到亮屏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.//和IMS交互mInputManagerInternal.setInteractive(interactive);mInputMethodManagerInternal.setInteractive(interactive);//和BatteryStatsService交互try {mBatteryStats.noteInteractive(interactive);} catch (RemoteException ex) { }//处理交互完成前的操作mInteractive = interactive;mInteractiveChangeReason = reason;mInteractiveChanging = true;handleEarlyInteractiveChange();}
}
//mScreenOnIntent = new Intent(Intent.ACTION_SCREEN_ON);
private void sendWakeUpBroadcast() {if (DEBUG) {Slog.d(TAG, "Sending wake up broadcast.");}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();}
}
3.2.onWakefulnessChangeFinished()
该方法负责wakefulness状态改变完成后的工作,和3.1方法相对应。这个方法较简单,当PMS中调用它后,它会调用handleLaterInteractiveChanged()方法,如下:
/*** Notifies that the device has finished changing wakefulness.*/
public void onWakefulnessChangeFinished() {if (mInteractiveChanging) {mInteractiveChanging = false;handleLateInteractiveChange();}
}
private void handleLateInteractiveChange() {synchronized (mLock) {//mInteractive在onWakefulnessCHangeStated()中进行了改变,以用来确定是否//是亮屏或者灭屏if (mInteractive) {//亮屏...mHandler.post(new Runnable() {@Overridepublic void run() {mPolicy.finishedWakingUp();}});} else {//灭屏...if (mUserActivityPending) {mUserActivityPending = false;mHandler.removeMessages(MSG_USER_ACTIVITY);}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);MetricsLogger.action(log);EventLogTags.writePowerScreenState(0, why, 0, 0, 0);mPolicy.finishedGoingToSleep(why);}});// 发送完成后的广播mPendingInteractiveState = INTERACTIVE_STATE_ASLEEP;mPendingGoToSleepBroadcast = true;updatePendingBroadcastLocked();}}
}
在这个方法中,如果是亮屏,则调用PWM的finishedWakingUp()表示亮屏处理成功,如果是灭屏,则调用PWM的finishedGoingToSleep()
3.3.updatePendingBroadcaseLocked()
// Send interactive broadcast.
mPendingInteractiveState = INTERACTIVE_STATE_AWAKE;
mPendingWakeUpBroadcast = true;
updatePendingBroadcastLocked();
private void updatePendingBroadcastLocked() {/*** 广播没有进行中&&要发送的广播状态!= UNKNOW* && (发送亮屏广播||发送灭屏广播||发送广播状态!=当前广播交互状态)* mBroadcastedInteractiveState值实际上是上次发送广播交互状态的值*/if (!mBroadcastInProgress&& mPendingInteractiveState != INTERACTIVE_STATE_UNKNOWN&& (mPendingWakeUpBroadcast || mPendingGoToSleepBroadcast|| mPendingInteractiveState != mBroadcastedInteractiveState)) {mBroadcastInProgress = true;//申请一个Suspend锁,以防广播发送未完成系统休眠而失败mSuspendBlocker.acquire();Message msg = mHandler.obtainMessage(MSG_BROADCAST);msg.setAsynchronous(true);mHandler.sendMessage(msg);}
}
//要广播的交互状态
private int mPendingInteractiveState;
//是否广播亮屏
private boolean mPendingWakeUpBroadcast;
//是否广播灭屏
private boolean mPendingGoToSleepBroadcast;
//当前要广播的交互状态
private int mBroadcastedInteractiveState;
//是否广播正在进行中
private boolean mBroadcastInProgress;
adb root
adb remount
adb shell
cat /sys/power/wake_lock
之后通过Handler中调用sendNextBroadcaset()方法发送广播,看看这个方法:
private void sendNextBroadcast() {final int powerState;synchronized (mLock) {//当前广播的交互状态=0(成员变量默认0)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 {if (mPendingWakeUpBroadcast || mPendingGoToSleepBroadcast|| mPendingInteractiveState == INTERACTIVE_STATE_AWAKE) {mPendingWakeUpBroadcast = false;mBroadcastedInteractiveState = INTERACTIVE_STATE_AWAKE;} else {finishPendingBroadcastLocked();return;}}mBroadcastStartTime = SystemClock.uptimeMillis();powerState = mBroadcastedInteractiveState;}if (powerState == INTERACTIVE_STATE_AWAKE) {//发送亮屏广播sendWakeUpBroadcast();} else {//发送灭屏广播sendGoToSleepBroadcast();}
}
- 1.如果mBroadcastedInteractiveState为
INTERACTIVE_STATE_UNKNOWN
,即0,由于是成员变量,因此初始值就等于0.开机后灭屏满足这个情景,此时会将mBroadcastedInteractiveState置为INTERACTIVE_STATE_AWAKE
; - 2.如果mBroadcastedInteractiveState为INTERACTIVE_STATE_AWAKE,表示当前广播的交互状态为可交互状态,即此时处于亮屏状态;(下同)
- 3.如果mBroadcastedInteractiveState为INTERACTIVE_STATE_ASLEEP,表示此时处于灭屏状态。
到这里为止,我们理清了发送广播的大概流程,可以确定交互状态改变时对应的操作了,现在分别对亮屏和灭屏的流程进行分析。
3.3.1.由灭屏-亮屏:
onWakefulnessChangeStarted()方法中部分变量初始值和调用流程:
wakefulness=1, 即WAKEFULNESS_AWAKE;
reason=0, PMS中传入;
interactive=true,即处于AWAKE或者DREAM状态
mInteractive=false,即前一次不出于交互状态,
mInteractiveChanging=false,刚进入该函数该值初始值;
handleEarlyInteractiveChange()被调用; --->
handleEarlyInteractiveChange()方法中相关变量赋值:
mPendingInteractiveState = INTERACTIVE_STATE_AWAKE,即为1,最终 要广播的交互状态;
mPendingWakeUpBroadcast = true;表示是否最终发送的为wakeup广播;
updatePendingBroadcastLocked()被调用; --->
updatePendingBroadcastLocked()中的变量值:
mBroadcastInProgress=false, 表示当前没有正在进行的广播;
mPendingInteractiveState=1, handleEarlyInteractiveChange()中赋值;
mPendingWakeUpBroadcast=true,handleEarlyInteractiveChange()中赋值
mPendingGoToSleepBroadcast=false,是否最终发送的为asleep广播;
mBroadcastedInteractiveState=2,当前广播的状态(还未发送wakeup广播状态),为INTERACTIVE_STATE_ASLEEP,2;
sendNextBroadcast()中根据上述变量值,走else语句:
mPendingWakeUpBroadcast=false,
mBroadcastedInteractiveState=INTERACTIVE_STATE_AWAKE;
sendWakeUpBroadcast()被调用。 --->
sendWakeUpBroadcast()中发送Intent_SCREEN_ON广播:
private void sendWakeUpBroadcast() {if (mActivityManagerInternal.isSystemReady()) {//广播发送完成后最后被mWakeUpBroadcastDone接受mContext.sendOrderedBroadcastAsUser(mScreenOnIntent, UserHandle.ALL, null, mWakeUpBroadcastDone, mHandler,0, null, null);} else {sendNextBroadcast();}
}
mWakeUpBroadcastDone会在最后接受触发onReceive()方法,继续看看MWakeUpBroadcastDone这个广播接受器:
private final BroadcastReceiver mWakeUpBroadcastDone = new BroadcastReceiver() {@Overridepublic void onReceive(Context context, Intent intent) {EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_DONE, 1,SystemClock.uptimeMillis() - mBroadcastStartTime, 1);sendNextBroadcast();}
};
在这里,又调用了sendNextBroadcast()方法,并根据条件判断,走else if 语句,此时相关变量值如下:
mPendingWakeUpBroadcast = false;上次else if中设置;
mPendingGoToSleepBoradcast = false;发送灭屏广播时才会设置为true;
mPendingInteractiveState = 1;handleEarlyInteractiveChange()中设置;
结合以上变量值,在else if中走else语句,else中直接调用了finishPendingBroadcastLocked()
方法,该方法如下:
private void finishPendingBroadcastLocked() {//表示此时没有正在进行的广播mBroadcastInProgress = false;//释放suspend锁mSuspendBlocker.release();
}
在这个方法中,将mBroadcastInProgress值设置为false,表示当前没有正在进行中的广播,并释sendGoToSleepBroadcast放了避免系统CPU休眠的Suspend锁。亮屏广播就发送完毕了。
3.3.2.由亮屏-灭屏:
onWakefulnessChangeStarted()方法中部分变量初始值:
wakefulness=3, WAKE_LOCK_DOZE,即先进入doze模式;
reason=4, PM.GO_TO_SLEEP_POWER_BUTTTON,即由power键灭屏;
interactive=false,由于wakefulness已变为doze,因此不可交互状态;
mInteractive=true,上次状态为可交互状态;
mInteractiveChanging=false,刚进入该函数该值初始值;
handleEarlyInteractiveState()被调用;
handleEarlyInteractiveState()中:只做了通过WindowManagerPolicy开始睡眠的操作,之后返回。
在PMS的handleSandman()中,调用reallyGoToSleepNoUpdateLocke()方法进入睡眠,因此又会调用到onWakefulnessChangeStarted()方法中:
onWakefulnessChangeStarted()中部分变量初始值:
wakefulness=0,WAKEFULNESS_ASLEEP=0;表示进入睡眠状态reason=2,PM.GO_TO_SLEEP_REASON_TIMEOUT.
interactive=false,当前为asleep状态,表示不可交互
mInteractive=false,上次为doze状态,也是不可交互
mInteractiveChanging=true,是上次由awake->doze时设置;
handleEarlyInteractiveState()被调用;
handleEarlyInteractiveState()中:只做了通过WindowManagerPolicy开始睡眠的操作,之后返回。
最终,在onWakefulnessChangeFinished()
方法中,调用了handleLateInteractiveChanged()
,发送灭屏广播前设置值如下:
mPendingInteractiveState = INTERACTIVE_STATE_ASLEEP;
mPendingGoToSleepBroadcast = true;
updatePendingBroadcastLocked();
进入到sendNextBroadcast()中,此时部分变量值如下:
mBroadcastedInteractiveState=1,表示当前广播的交互状态为awake;
mPendingWakeUpBroadcast=false,是否最终发送的为wakeup广播;
mPendingGoToSleepBroadcast=true,表示最终发送的为sleep广播;
因此,走sendNextBroadcast()中的else if->if语句,sendGoToSleepBroadcast()
被调用;
sendGoToSleepBroadcast()中发送Intent.SCREEN_OFF广播:
private void sendGoToSleepBroadcast() {if (mActivityManagerInternal.isSystemReady()) {//广播发送后最后一个广播接受器mGoToSleepBroadcastDonemContext.sendOrderedBroadcastAsUser(mScreenOffIntent, UserHandle.ALL, null,mGoToSleepBroadcastDone, mHandler, 0, null, null);} else {sendNextBroadcast();}
}
灭屏广播发出后,mGoToSleepBroadcastDone会在最后接受到,这里进行收尾处理:
private final BroadcastReceiver mGoToSleepBroadcastDone = new BroadcastReceiver() {@Overridepublic void onReceive(Context context, Intent intent) {sendNextBroadcast();}
};
这里又调用了sendNextBroadcast()方法,此时相关变量值如下:
mPendingWakeUpBroadcast=false,
mPendingGoToSleepBroadcast=false,
mPendingInteractiveState=true,
mBroadcastInteractiveState=ASLEEP(2);
因此,走else->else语句,调用了finishPendingBroadcastLocked(),在这个方法中重置了mBroadcastInPorgress和释放了Suspend。
Notifier类比较简单,稍微复杂的就是发送广播这块。
Android 亮屏流程分析相关推荐
- 安卓手机来电亮屏流程分析
来电亮屏流程分析 本文档是针对手机来电时候自主点亮屏幕这一流程的分析,很自然的就将其分为2个阶段,第一个是来电,第二个是点亮屏幕. 来电的流程: 来电消息是从RIL层接收到的,然后才开始传递上来. A ...
- Android 8.1 PowerManagerService分析(四)——亮屏流程分析
欢迎大家关注我的掘金帐号 我会在那里定期更新最新版本的Android Framework源码分析! 相关文章: [Android Framework] 8.1 PowerManagerService分 ...
- Android手机亮屏流程分析
极力推荐Android 开发大总结文章:欢迎收藏程序员Android 力荐 ,Android 开发者需要的必备技能 注:文章转于网络,点击查看原文 PowerManagerService 之前系列文章 ...
- (原创)Android6.0亮屏流程分析
1.概述 Android的亮屏流程从android系统结构层次来分可以分为三个流程,App应用唤醒源:Framework层Power结合Display,Light服务做亮屏绘制准备工作:底层驱动点亮背 ...
- android 7.0 解锁亮屏,Android7.0亮屏流程分析
亮屏的本质是改变屏幕的电源状态,经过一系列的调用会来到PowerManagerService中的updatePowerStateLocked() 1.PowerManagerService到Displ ...
- Android 亮屏速度分析
前面聊的 最近在调试项目的亮屏速度,我们希望在按下power键后到亮屏这个时间能达到500MS以内,在Rockchip 3399和3288上面的时间都不能达到要求,因此引发了一系列的调试之路. 计算按 ...
- 单击屏幕亮屏流程分析
一. kernel部分 1.看TP驱动有没有事件上报 cat /dev/input/evnet1 或者看kernel log [ 4036.282237] bt541_ts_device 5-00 ...
- android 亮屏分析,Android亮屏速度分析总结
前面聊的 最近在调试项目的亮屏速度,我们希望在按下power键后到亮屏这个时间能达到500MS以内,在Rockchip 3399和3288上面的时间都不能达到要求,因此引发了一系列的调试之路. 计算按 ...
- Android 亮屏速度分析总结
前面聊的 最近在调试项目的亮屏速度,我们希望在按下power键后到亮屏这个时间能达到500MS以内,在Rockchip 3399和3288上面的时间都不能达到要求,因此引发了一系列的调试之路. 计算按 ...
最新文章
- 打开程序时固定位置_新手入门第五课:免费开源图像处理程序GIMP之矩形选择工具...
- Why is it recommended to create clusters with odd number of nodes? | 为什么集群节点建议奇数个?
- oracle脚本审核平台,Oracle 脚本(适应各种业务需要)
- 单处理器调度算法详解
- f5源站获取http/https访问的真实源IP解决方案
- The Robustness of Deep Networks A geometrical perspective论文解读
- python定义和调用函数
- Sqlmap脱库之“你的数据我所见”
- Android开发环境的搭建教程
- 剑指offer32-III.从上到下打印二叉树(蛇形打印)
- Unity Shader: Blend混合
- vue中使用 svg图片
- 怎么减少别人屏蔽你的朋友圈(一)
- 电路实验——实验二 基尔霍夫定律的验证
- 讲讲React中的State和Props
- RxJava2 Flowable filter (过滤操作符)
- 史上最全网络安全面试题总结
- 蓝桥杯 Sine之舞
- 教你统计日留存、周留存、月留存率更准确的方法。
- centOS7重启网卡失败