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相关的两个类:PowerManagerNotifier

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();}
}

现在到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_AWAKEsetWakefulnessLocked(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需要注意一下:

所以不管是哪种亮屏方式,最终都会在这里汇合的。之后通过setWakefulnessLocked()方法设置wakefulness,再通过Notifier进行处理和通知其他系统服务wakefulness的改变,最后更新用户活动的时间,重置下次超时灭屏时间。继续看看setWakefulnessLocked():

void setWakefulnessLocked(int wakefulness, int reason) {if (mWakefulness != wakefulness) {//改变WakefulnessmWakefulness = wakefulness;mWakefulnessChanging = true;//置位操作mDirty |= DIRTY_WAKEFULNESS;if (mNotifier != null) {//处理wakefulness改变前的操作mNotifier.onWakefulnessChangeStarted(wakefulness, reason);}}
}

首先,改变当前mWakefulness值,将mWakefulnessChanging标记为true,将mWakefulness值标志为DIRTY_WAKEFULNESS,然后通过Notifier进行改变wakefulness之前的一些处理,Notifier负责PMS和其他系统服务的交互。而Notifier中的onWakefulnessChangeStarted()方法,就是亮屏的主要方法之一,如发送亮屏或者灭屏的广播等。

为了不显得凌乱,将关于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();}}

由于是亮屏操作,此时部分变量值为:

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();}}

继续分析PMS中的剩余流程,setWakefulnessLocked()执行完毕后,接下来执行的是Notifier的onWakeUp()方法,这个方法负责和BatteryStatsService、AppService进行交互,将wakeup信息传递给它们,如下:

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) {}
}

接下来,执行userActivityNoUpdateLocked()方法,这个方法任务只有一个——负责更新系统和用户最后交互时间,计算的时间在updateUserActivitySummary()方法中会用于判断何时灭屏,该方法如下:

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;
}

在这个方法中来看下PowerManager.USER_ACTIVITY_FLAG_NO_CHANGE_LIGHT这个值,这个值和释放wakelock有关系,在分析WakeLock释放流程时分析到,如果带有PowerManager.ON_AFTER_RELEASE标记,则在释放该WakeLock时会先亮一小会之后才会灭屏,这里正是为何会亮一小会才会灭屏的关键。我们可以在释放WakeLock锁的流程方法中看到:

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标记,其他场景下不会带有该标识。

这些方法执行完后,执行updatePowerStateLocked()方法更新所有信息,这个方法作为PMS的核心方法,在PowerManagerService分析第二篇中分析过了,同时在这个方法中会进行亮屏的最关键的操作——updateDisplayPowerStateLocked(),这里对updateDisplayPowerStateLocked()方法进行分析:

  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;
}

这里对DisplayPowerRequest.policy进行下说明,在该方法中,由于是亮屏操作,所以此时mWakefulness=WAKEFULNESS_AWAKE(1),综合判断条件,所以policy的值为POLICY_BRIGHT。同样地,如果是灭屏操作的话,policy值就是POLICY_OFF,还有一种情况,如果系统配置了dozeComponent组件,那么在按Power键灭屏时,不会立即进入Sleep装填,而是会先进入Doze状态,所以这种情况下policy值为POLICY_DOZE。

现在回到updateDisplayPowerStateLocked()方法中,再来看看当“请求体”确定后,是如何进行请求的。PMS中向DisplayManagerService发起请求后,DisplayManagerService交给了DisplayController中进行处理,这个过程图示如下:

对应相关代码如下(有删减):
DisplayController.java:


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;}
}

在这个方法中,会判断请求时携带的DisplayPowerRequest对象是否和上一次发生请求的DisplayRequest对象相同,如果相同,则返回值mDisplayReadyLocked为true,如果不同,则表示发生了改变,此时会异步去请求新的Display状态,并向PMS返回false,表示Display状态正在更新,没有准备完成,直到更新完成后,会将mDisplayReadyLocked值置为true,表示更新完成。同时回调PMS中的onStateChanged()方法通知PMS更新完成。这个返回值会在PMS中作为下一步的执行条件。

处理完成后回调PMS中的onStateChanged()方法通知PMS,最终完成Display的更新。关于DisplayPowerControllerDisplayManagerService以及其他模块中如何处理的,这里暂不分析。只需要知道当DisplayPowerController处理完请求后,回调DisplayManagerInternal.DisplayPowerCallbacks的onStateChanged()方法,再来看看这个方法:

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();}}.........}

在这个方法中,对mDirty进行了置位操作,然后由调用了updatePowerState()方法,这次调用时状态已经没有发生过改变,因此会根据执行条件而在某一阶段跳出。
当请求完毕后,对于updatePowerStateLocked()方法中剩余的其他三个方法主要作用是和屏保、wakefulness改变的收尾工作和申请/释放SuspendBlocker锁,这里略去。
关于按power键亮屏PMS相关部分就分析完了,当然,亮屏完整流程涉及模块较多,绝非几句就可以说完,这里仅仅将PMS相关的进行分析,至于其他模块如DMS、LightsService中的,会在下篇文章中进行分析。整个Power键亮屏时序图如下:

PMS发起请求后其他模块的处理时序图:

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可以说是PMS向Application层提供信息的一个接口。PowerManager用来控制设备电源状态。在上面分析了PMS,是一个系统服务,由SystemServer启动并运行,并没有提供上层调用的接口,因此呢,PowerManager作为PMS的一个代理类,向上层应用层提供开放接口,供Application层调用,实现对电源的管理,其实现原理和上文谈到的Binider注册有关。
PowerManager作为系统级别服务,在获取其实例时,通过以下方式进行获取:

PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);

通过Context.POWER_SERVICE,获取了PowerManager实例,而这个字段在PMS进行Binder注册的时候使用了,因此,实际上PowerManager对象中包含了一个PMS.BindService对象,当应用层调用PowerManager开放接口后,PowerManager再通过了PMS.BindService向下调用到了PMS中。这点可以在PowerManager的构造方法中看出:

public PowerManager(Context context, IPowerManager service, Handler handler) {mContext = context;mService = service;mHandler = handler;
}

在PowerManager中,提供了许多public方法,当应用层调用这些方法时,PowerManager将向下调用PMS。

3.Notifier类

Notifier类好比PMS和其他系统服务交互的”中介“,Notifier和PMS在结构上可以说是组合关系,PMS中需要和其他组件交互的大部分都由Notifier处理,如亮灭屏通知其他服务等,亮灭屏广播也是在该类中发出。这里介绍其中的部分方法,有些可能已经在上面内容的分析中涉及到了。(注:如果是第一次看到这部分内容,那么应该先看看之前的内容。)

3.1.onWakefulnessChangeStarted()

该方法用于亮屏或者灭屏时逻辑的处理,和onWakefulnessChangeFinished()方法对应,分别负责操作开始和结束的逻辑处理,当wakefulness改变时进行回调,因此当亮屏、灭屏、进入Doze模式时都会调用这个方法,看看这个方法:

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();}
}

首先判断系统是否可以进行交互,如果处于Dream或者Awake状态,表示可以进行交互,interactive为true;在这个方法中有两个关键方法,handleLateInteractiveChange()handleEarlyInteractiveChange(),分别表示处理交互状态改变后的操作和改变前的操作,如果是亮屏场景,则在执行到该方法时,在setWakeFulnessLocked()方法中将wakefulness设置为了WAKEFULNESS_AWAKE,所以interactive为true,mInteractive是false,因此会先执行handleEarlyInteractiveChange(),继续看看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()

这个方法用于交互状态改变时发送广播,最常见的就是由亮屏-灭屏之间的改变了,都会发送这个广播。亮屏时,在handlerEarlyInteractiveChang()方法中调用该方法发送广播,灭屏时,在handlerLateInteractiveChang()中调用方法发送广播。接下来会分两种情况进行分析。
当系统由不可交互变成可交互时,如由灭屏-亮屏,首先做了如下处理:

// 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;

在这个方法中,首先申请了一个suspend锁,这个锁是通过在PMS中创建Notifier对象时创建传入的,name为PowerManagerService.Broadcast在广播发送完成后又进行了释放,这样作的目的是避免在发送广播过程中系统休眠而导致广播未发送完成;可以通过如下命令查看该锁:

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();}
}

在这里总结下该方法的判断条件:

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 亮屏流程分析相关推荐

  1. 安卓手机来电亮屏流程分析

    来电亮屏流程分析 本文档是针对手机来电时候自主点亮屏幕这一流程的分析,很自然的就将其分为2个阶段,第一个是来电,第二个是点亮屏幕. 来电的流程: 来电消息是从RIL层接收到的,然后才开始传递上来. A ...

  2. Android 8.1 PowerManagerService分析(四)——亮屏流程分析

    欢迎大家关注我的掘金帐号 我会在那里定期更新最新版本的Android Framework源码分析! 相关文章: [Android Framework] 8.1 PowerManagerService分 ...

  3. Android手机亮屏流程分析

    极力推荐Android 开发大总结文章:欢迎收藏程序员Android 力荐 ,Android 开发者需要的必备技能 注:文章转于网络,点击查看原文 PowerManagerService 之前系列文章 ...

  4. (原创)Android6.0亮屏流程分析

    1.概述 Android的亮屏流程从android系统结构层次来分可以分为三个流程,App应用唤醒源:Framework层Power结合Display,Light服务做亮屏绘制准备工作:底层驱动点亮背 ...

  5. android 7.0 解锁亮屏,Android7.0亮屏流程分析

    亮屏的本质是改变屏幕的电源状态,经过一系列的调用会来到PowerManagerService中的updatePowerStateLocked() 1.PowerManagerService到Displ ...

  6. Android 亮屏速度分析

    前面聊的 最近在调试项目的亮屏速度,我们希望在按下power键后到亮屏这个时间能达到500MS以内,在Rockchip 3399和3288上面的时间都不能达到要求,因此引发了一系列的调试之路. 计算按 ...

  7. 单击屏幕亮屏流程分析

    一. kernel部分 1.看TP驱动有没有事件上报  cat /dev/input/evnet1  或者看kernel log [ 4036.282237] bt541_ts_device 5-00 ...

  8. android 亮屏分析,Android亮屏速度分析总结

    前面聊的 最近在调试项目的亮屏速度,我们希望在按下power键后到亮屏这个时间能达到500MS以内,在Rockchip 3399和3288上面的时间都不能达到要求,因此引发了一系列的调试之路. 计算按 ...

  9. Android 亮屏速度分析总结

    前面聊的 最近在调试项目的亮屏速度,我们希望在按下power键后到亮屏这个时间能达到500MS以内,在Rockchip 3399和3288上面的时间都不能达到要求,因此引发了一系列的调试之路. 计算按 ...

最新文章

  1. 打开程序时固定位置_新手入门第五课:免费开源图像处理程序GIMP之矩形选择工具...
  2. Why is it recommended to create clusters with odd number of nodes? | 为什么集群节点建议奇数个?
  3. oracle脚本审核平台,Oracle 脚本(适应各种业务需要)
  4. 单处理器调度算法详解
  5. f5源站获取http/https访问的真实源IP解决方案
  6. The Robustness of Deep Networks A geometrical perspective论文解读
  7. python定义和调用函数
  8. Sqlmap脱库之“你的数据我所见”
  9. Android开发环境的搭建教程
  10. 剑指offer32-III.从上到下打印二叉树(蛇形打印)
  11. Unity Shader: Blend混合
  12. vue中使用 svg图片
  13. 怎么减少别人屏蔽你的朋友圈(一)
  14. 电路实验——实验二 基尔霍夫定律的验证
  15. 讲讲React中的State和Props
  16. RxJava2 Flowable filter (过滤操作符)
  17. 史上最全网络安全面试题总结
  18. 蓝桥杯 Sine之舞
  19. 教你统计日留存、周留存、月留存率更准确的方法。
  20. centOS7重启网卡失败

热门文章

  1. NFS服务器配置与管理笔记
  2. 虾米音乐代码注释惊现“穷逼vip”程序员又背锅了
  3. 刷子 撸一撸手头的几把刷
  4. Silverstack Lab for Mac(媒体资源数据管理工具)激活版
  5. 黑猴子的家:Scala 常用类型
  6. 各大招聘网站信息实时查询浏览
  7. php 2038年,PHP 处理大于2038年以后的日期
  8. 什么是web前端技术?要学什么?
  9. 机器学习技术:使用深度学习处理文本
  10. 延续精彩分享,感受技术力量 | 开发者说·DTalk 鉴赏