日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > Android >内容正文

Android

Android7.0 PowerManagerService(3) 核心函数updatePowerStateLocked的主要流程

發布時間:2025/3/15 Android 49 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Android7.0 PowerManagerService(3) 核心函数updatePowerStateLocked的主要流程 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

前面的博客中,我們已經分析過,當Android中的進程要使用電量時,需要向PMS申請WakeLock;當進程完成工作后,需要釋放對應的WakeLock。?
PMS收到申請和釋放WakeLock的請求后,均需要調用updatePowerStateLocked來更新電源的狀態,該函數是PMS的核心方法。?
接下來,我們就結合代碼,看一下updatePowerStateLocked的工作流程。

/** * Updates the global power state based on dirty bits recorded in mDirty. * * This is the main function that performs power state transitions. * We centralize them here so that we can recompute the power state completely * each time something important changes, and ensure that we do it the same * way each time. The point is to gather all of the transition logic here. */ private void updatePowerStateLocked() {//未啟動完畢或mDirty沒有記錄變化if (!mSystemReady || mDirty == 0) {return;}..........try {// Basic state updates.// 1、更新基本狀態updateIsPoweredLocked(mDirty);updateStayOnLocked(mDirty);updateScreenBrightnessBoostLocked(mDirty);// Update wakefulness.// Loop because the wake lock and user activity computations are influenced// by changes in wakefulness.// 2、更新wakelock和用戶活動 final long now = SystemClock.uptimeMillis();int dirtyPhase2 = 0;for (;;) {int dirtyPhase1 = mDirty;dirtyPhase2 |= dirtyPhase1;mDirty = 0;updateWakeLockSummaryLocked(dirtyPhase1);updateUserActivitySummaryLocked(now, dirtyPhase1);if (!updateWakefulnessLocked(dirtyPhase1)) {break;}}// Update display power state.// 3、更新display power stateboolean displayBecameReady = updateDisplayPowerStateLocked(dirtyPhase2);// Update dream state (depends on display ready signal).// 4、更新dream stateupdateDreamLocked(dirtyPhase2, displayBecameReady);// Send notifications, if needed.finishWakefulnessChangeIfNeededLocked();// Update suspend blocker.// Because we might release the last suspend blocker here, we need to make sure// we finished everything else first!// 5、更新suspend blockerupdateSuspendBlockerLocked();} finally {..........} }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59

在PMS中有個很重要的變量mDirty,該變量按位存儲PMS中的各種變化狀態。?
例如,之前介紹PMS的acquire WakeLock流程時,就進行了以下操作:

......... mDirty |= DIRTY_WAKE_LOCKS; ........
  • 1
  • 2
  • 3

每當PMS檢測到一些重要事件發生時,就會更新mDirty的相應的位。?
從updatePowerStateLocked的代碼可以看出,它將根據mDirty中的信息,來更新手機中的電源狀態。

根據Android源碼中的注釋,可以看出updatePowerStateLocked的工作主要分為幾個步驟,接下來我們一個一個步驟的來進行分析。

一、更新基本狀態信息?
1、updateIsPoweredLocked?
我們先來看看updateIsPoweredLocked函數:

private void updateIsPoweredLocked(int dirty) {//DIRTY_BATTERY_STATE位置1時,表示終端的電源狀態發生了改變if ((dirty & DIRTY_BATTERY_STATE) != 0) {//記錄過去的狀態final boolean wasPowered = mIsPowered;final int oldPlugType = mPlugType;final boolean oldLevelLow = mBatteryLevelLow;//得到終端現在是否在充電mIsPowered = mBatteryManagerInternal.isPowered(BatteryManager.BATTERY_PLUGGED_ANY);//得到充電的類型mPlugType = mBatteryManagerInternal.getPlugType();//得到當前的電量mBatteryLevel = mBatteryManagerInternal.getBatteryLevel();//判斷是否為低電量mBatteryLevelLow = mBatteryManagerInternal.getBatteryLevelLow();//是否充電的狀態發生改變,或者充電類型發生改變if (wasPowered != mIsPowered || oldPlugType != mPlugType) {mDirty |= DIRTY_IS_POWERED;// Update wireless dock detection state.//無線充電相關,暫時不用管final boolean dockedOnWirelessCharger = mWirelessChargerDetector.update(mIsPowered, mPlugType, mBatteryLevel);final long now = SystemClock.uptimeMillis();//判斷插拔充電器或者USB是否需要喚醒屏幕 if (shouldWakeUpWhenPluggedOrUnpluggedLocked(wasPowered, oldPlugType,dockedOnWirelessCharger)) {//之前的博客中已經分析過這個函數,主要是做好喚醒終端屏幕前的準備工作wakeUpNoUpdateLocked(now, "android.server.power:POWER", Process.SYSTEM_UID,mContext.getOpPackageName(), Process.SYSTEM_UID);}//觸發一次用戶活動,修改PMS中記錄用戶活動事件的時間,同時通知BatteryStatsService等userActivityNoUpdateLocked(now, PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, Process.SYSTEM_UID);// Tell the notifier whether wireless charging has started so that// it can provide feedback to the user.//無線充電相關的通知,暫時可以不管if (dockedOnWirelessCharger) {mNotifier.onWirelessChargingStarted();}}if (wasPowered != mIsPowered || oldLevelLow != mBatteryLevelLow) {//結束低電的狀態if (oldLevelLow != mBatteryLevelLow && !mBatteryLevelLow) {........//從命名來看,該標志用于決定終端在低電模式下是否“打盹”(接近休眠)mAutoLowPowerModeSnoozing = false;}//更新低電模式相關的操作updateLowPowerModeLocked();}} }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61

從以上代碼可以看出updateIsPoweredLocked主要用于:?
更新PMS中的一些變量,包括記錄終端是否在充電、充電的類型、電池的電量及電池電量是否處于低電狀態;?
當電源的充電狀態,或者充電類型發生變化,判斷出現插拔充電器等操作時,是否需要點亮或熄滅屏幕;?
當電源充電狀態發生變化,或者終端是否處于低電量的標志發生變化的時候,終端調用updateLowPowerModeLocked()更新低電模式相關的操作。

我們跟進一下updateLowPowerModeLocked函數:

private void updateLowPowerModeLocked() {//處于充電狀態,并且設置過低電模式的標志位if (mIsPowered && mLowPowerModeSetting) {........ // Turn setting off if powered//更新數據庫,關閉低電模式Settings.Global.putInt(mContext.getContentResolver(),Settings.Global.LOW_POWER_MODE, 0);mLowPowerModeSetting = false;}//判斷是否可以進入自動省電模式//要求是:未充電 && 進行了自動省電的配置 && 沒有設置低電“打盹” && 電池電量低final boolean autoLowPowerModeEnabled = !mIsPowered && mAutoLowPowerModeConfigured&& !mAutoLowPowerModeSnoozing && mBatteryLevelLow;//當前是否為低電模式final boolean lowPowerModeEnabled = mLowPowerModeSetting || autoLowPowerModeEnabled;if (mLowPowerModeEnabled != lowPowerModeEnabled) {mLowPowerModeEnabled = lowPowerModeEnabled;//調用底層動態庫的powerHint函數powerHintInternal(POWER_HINT_LOW_POWER, lowPowerModeEnabled ? 1 : 0);//開機完成后才能執行的Runnable對象postAfterBootCompleted(new Runnable() {//發送低電模式CHANGING的廣播Intent intent = new Intent(PowerManager.ACTION_POWER_SAVE_MODE_CHANGING).putExtra(PowerManager.EXTRA_POWER_SAVE_MODE, mLowPowerModeEnabled).addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);mContext.sendBroadcast(intent);//PMS提供了registerLowPowerModeObserver的接口//其它進程可以調用該接口,注冊觀察者synchronized (mLock) {listeners = new ArrayList<PowerManagerInternal.LowPowerModeListener>(mLowPowerModeListeners);}for (int i=0; i<listeners.size(); i++) {//調用回調接口的onLowPowerModeChanged函數,通知其它進程低電模式發生改變listeners.get(i).onLowPowerModeChanged(lowPowerModeEnabled);}//再次發送CHANGED廣播intent = new Intent(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED);intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);mContext.sendBroadcast(intent);// Send internal version that requires signature permission.mContext.sendBroadcastAsUser(new Intent(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED_INTERNAL), UserHandle.ALL,Manifest.permission.DEVICE_POWER);});} }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55

從上面的代碼可以看出updateLowPowerModeLocked函數,?
首先判斷手機是否在充電,如果手機在充電,退出LowPowerMode模式,同時更新數據庫;?
當手機的低電量模式發生了變化,就發送廣播進行通知,并回調關于監聽該模式變化的觀察者的接口。?
例如:UI對應的APK收到低電量省電模式的廣播,就會彈出低電量省電模式的提醒界面。

可以看出這一部分除了更新PMS中的一些變量外,關注的重點還是集中在:?
充電狀態是否改變;?
充電狀態的改變,將引出對充電器插拔是否需要亮屏的考慮;?
同樣,充電狀態的改變,將引出對終端的低電模式是否發生改變的考慮。?
從這個角度來看,updateIsPoweredLocked函數的命名是實至名歸的。

2、updateStayOnLocked?
現在我們看看基本狀態更新第二部分的updateStayOnLocked函數:

/** * Updates the value of mStayOn. * Sets DIRTY_STAY_ON if a change occurred. */ private void updateStayOnLocked(int dirty) {//電源狀態或電源設置發生了改變if ((dirty & (DIRTY_BATTERY_STATE | DIRTY_SETTINGS)) != 0) {final boolean wasStayOn = mStayOn;//設置了充電器插入時亮屏(分為AC充電亮屏、USB充電亮屏或無線充電亮屏)if (mStayOnWhilePluggedInSetting != 0//判斷mMaximumScreenOffTimeoutFromDeviceAdmin的是否處于0與Integer.MAX_VALUE之間//Android給出的注釋是://The maximum allowable screen off timeout according to the device// administration policy//初始為Integer.MAX_VALUE,因此這里是要求其它進程沒有設置這個值//應該對應于強制息屏時間&& !isMaximumScreenOffTimeoutFromDeviceAdminEnforcedLocked()) {//判斷是否充電亮屏,定義于BatteryService.java中//從代碼來看,只要mStayOnWhilePluggedInSetting設置了,就會亮屏mStayOn = mBatteryManagerInternal.isPowered(mStayOnWhilePluggedInSetting);} else {mStayOn = false;}if (mStayOn != wasStayOn) {mDirty |= DIRTY_STAY_ON;}} }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

這一部分的代碼功能比較單一,主要用于更新變量mStayOn的值。?
如果mStayOn如果為true,則屏幕保持長亮的狀態。

3、updateScreenBrightnessBoostLocked?
Android手機定義了一個最大屏幕亮度,用戶可以手動或者讓終端自動確定最大的屏幕亮度。?
updateScreenBrightnessBoostLocked函數主要用于:更新終端可處于最大屏幕亮度的時間。

為了比較好的理解updateScreenBrightnessBoostLocked函數,?
我們可以先分析一下與之相關的,PMS提供的對外的接口boostScreenBrightness。?
該方法的作用是讓屏幕在一段時間內保持最大的亮度,使屏幕在強光下有更好的可讀性。

public void boostScreenBrightness(long eventTime) {..........mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER, null);final int uid = Binder.getCallingUid();final long ident = Binder.clearCallingIdentity();try {boostScreenBrightnessInternal(eventTime, uid);} finally {Binder.restoreCallingIdentity(ident);} }private void boostScreenBrightnessInternal(long eventTime, int uid) {synchronized (mLock) {//系統沒有準備好或者當前為Asleep狀態, 不處理新到的事件if (!mSystemReady || mWakefulness == WAKEFULNESS_ASLEEP//過時的事件不處理|| eventTime < mLastScreenBrightnessBoostTime) {return;}..............//記錄事件到來的事件,也可以認為是終端處于最亮屏幕狀態的起始時間mLastScreenBrightnessBoostTime = eventTime;//設置最亮屏幕的標志位true if (!mScreenBrightnessBoostInProgress) {mScreenBrightnessBoostInProgress = true;//發送廣播mNotifier.onScreenBrightnessBoostChanged();}//修改mDirty的值,表示最大屏幕亮度的狀態發生了變化 mDirty |= DIRTY_SCREEN_BRIGHTNESS_BOOST;//記錄userActivityNoUpdateLocked(eventTime,PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, uid);//更新電源的狀態信息updatePowerStateLocked();} }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44

從上面的代碼可以看出,該函數:?
首先,使用mLastScreenBrightnessBoostTime變量記錄了終端處于最大屏幕亮度的起始時間;?
然后,將最大屏幕亮度的標志位置為true,并修改mDirty標志位,以表示最大屏幕亮度的狀態發生了變化;?
最后,調用updatePowerStateLocked方法更新電源狀態信息。?
我們已經知道,updatePowerStateLocked將會調用到updateScreenBrightnessBoostLocked。

接下來,我們看看updateScreenBrightnessBoostLocked對應的代碼:

private void updateScreenBrightnessBoostLocked(int dirty) {//根據mDirty的標志位來判斷終端屏幕最大可用亮度的狀態是否發生了變化if ((dirty & DIRTY_SCREEN_BRIGHTNESS_BOOST) != 0) {//上面的代碼已經提到過,當boostScreenBrightness接口被調用時,mScreenBrightnessBoostInProgress置為trueif (mScreenBrightnessBoostInProgress) {//移除舊的超時事件final long now = SystemClock.uptimeMillis();mHandler.removeMessages(MSG_SCREEN_BRIGHTNESS_BOOST_TIMEOUT);//終端處于最大屏幕亮度的時間,在sleep的時間之后,說明終端還未息屏之類的if (mLastScreenBrightnessBoostTime > mLastSleepTime) {//此時,重新計算終端可處于最大屏幕亮度的時間final long boostTimeout = mLastScreenBrightnessBoostTime +SCREEN_BRIGHTNESS_BOOST_TIMEOUT;if (boostTimeout > now) {Message msg = mHandler.obtainMessage(MSG_SCREEN_BRIGHTNESS_BOOST_TIMEOUT);msg.setAsynchronous(true);//發送延遲的超時事件//當屏幕離開最大亮度狀態時,該事件將被發送//當該事件被處理時,會再次進入到updateScreenBrightnessBoostLocked函數mHandler.sendMessageAtTime(msg, boostTimeout);return;}}//進入到這個分支時,說明屏幕處于最大亮度狀態的時間已經超時了//將該標志置為falsemScreenBrightnessBoostInProgress = false;//發送廣播mNotifier.onScreenBrightnessBoostChanged();//觸發一次用戶活動,寫入mDirty標志位,同時做一些其它記錄userActivityNoUpdateLocked(now,PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, Process.SYSTEM_UID);}} }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42

至此,PMS第一階段更新基本狀態信息的流程結束。

二、更新wakelock和用戶活動

for (;;) {int dirtyPhase1 = mDirty;dirtyPhase2 |= dirtyPhase1;mDirty = 0;updateWakeLockSummaryLocked(dirtyPhase1);updateUserActivitySummaryLocked(now, dirtyPhase1);//updateWakefulnessLocked將決定系統是否進入休眠或dreaming狀態//主要是更新DIRTY_WAKEFULNESS位,如果不需要更新,則返回falseif (!updateWakefulnessLocked(dirtyPhase1)) {break;} }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

1、updateWakeLockSummaryLocked?
updateWakeLockSummaryLocked函數根據PMS當前持有的所有WakeLock,得到當前終端整體的信息,保存到mWakeLockSummary變量中。

/** * Updates the value of mWakeLockSummary to summarize the state of all active wake locks. * Note that most wake-locks are ignored when the system is asleep. */ private void updateWakeLockSummaryLocked(int dirty) {//PMS持有的WakeLock發生變化,或者喚醒狀態發生變化時,才重新進行更新mWakeLockSummary//例如:調用PMS的acquireWakeLock時,就會將dirty的DIRTY_WAKE_LOCKS位置1if ((dirty & (DIRTY_WAKE_LOCKS | DIRTY_WAKEFULNESS)) != 0) {mWakeLockSummary = 0;final int numWakeLocks = mWakeLocks.size();for (int i = 0; i < numWakeLocks; i++) {final WakeLock wakeLock = mWakeLocks.get(i);//這里只關注WakeLock的level//下面的代碼其實就是實現每個level WakeLock對應的注釋信息switch (wakeLock.mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK) {case PowerManager.PARTIAL_WAKE_LOCK://在分析PMS acquireWakeLock的流程時,已經提到過//在doze模式下,不在白名單內的非系統應用申請PARTIAL_WAKE_LOCK時,將被disabledif (!wakeLock.mDisabled) {// We only respect this if the wake lock is not disabled.mWakeLockSummary |= WAKE_LOCK_CPU;}break;case PowerManager.FULL_WAKE_LOCK:mWakeLockSummary |= WAKE_LOCK_SCREEN_BRIGHT | WAKE_LOCK_BUTTON_BRIGHT;break;case PowerManager.SCREEN_BRIGHT_WAKE_LOCK:mWakeLockSummary |= WAKE_LOCK_SCREEN_BRIGHT;break;case PowerManager.SCREEN_DIM_WAKE_LOCK:mWakeLockSummary |= WAKE_LOCK_SCREEN_DIM;break;case PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK:mWakeLockSummary |= WAKE_LOCK_PROXIMITY_SCREEN_OFF;break;case PowerManager.DOZE_WAKE_LOCK:mWakeLockSummary |= WAKE_LOCK_DOZE;break;case PowerManager.DRAW_WAKE_LOCK:mWakeLockSummary |= WAKE_LOCK_DRAW;break;}}// Cancel wake locks that make no sense based on the current state.//從下面的代碼可以看出,PMS中的mWakefulness變量記錄了終端當前的狀態//下面就是移除在特定狀態下,沒有意義的WakeLockif (mWakefulness != WAKEFULNESS_DOZING) {//如果不是Dozing狀態,移除相應的wakeLock標志位mWakeLockSummary &= ~(WAKE_LOCK_DOZE | WAKE_LOCK_DRAW);}if (mWakefulness == WAKEFULNESS_ASLEEP|| (mWakeLockSummary & WAKE_LOCK_DOZE) != 0) {//如果當前為Asleep或者有Doze的wakeLock鎖的時候,應該移除掉屏幕亮度相關的wakeLock鎖mWakeLockSummary &= ~(WAKE_LOCK_SCREEN_BRIGHT | WAKE_LOCK_SCREEN_DIM| WAKE_LOCK_BUTTON_BRIGHT);if (mWakefulness == WAKEFULNESS_ASLEEP) {//休眠時,sensor不再需要監聽終端是否靠近物體,以觸發亮滅屏mWakeLockSummary &= ~WAKE_LOCK_PROXIMITY_SCREEN_OFF;}}// Infer implied wake locks where necessary based on the current state.//根據當前的狀態,及PMS持有的WakeLock,推斷出隱含的持鎖需求//例如:當PMS持有亮屏鎖WAKE_LOCK_SCREEN_BRIGHT時,若當前終端為喚醒態//那么CPU顯然也需要處于喚醒態if ((mWakeLockSummary & (WAKE_LOCK_SCREEN_BRIGHT | WAKE_LOCK_SCREEN_DIM)) != 0) {if (mWakefulness == WAKEFULNESS_AWAKE) {mWakeLockSummary |= WAKE_LOCK_CPU | WAKE_LOCK_STAY_AWAKE;} else if (mWakefulness == WAKEFULNESS_DREAMING) {mWakeLockSummary |= WAKE_LOCK_CPU;}}if ((mWakeLockSummary & WAKE_LOCK_DRAW) != 0) {mWakeLockSummary |= WAKE_LOCK_CPU;}...................} }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81

結合每個WakeLock level的注釋信息,以上代碼還是比較好理解的。

這里唯一需要說明的是,Android定義一個mWakeLockSummary變量的原因是:?
PMS將WakeLock定義為不同進程的請求信息,這些請求信息對CPU、屏幕和鍵盤有不同的需求。?
對于每一種資源而言,只要有一個申請滿足獲取條件,PMS就需要為終端分配該申請對應的資源。?
例如:假設PMS有20個WakeLock,只有1個申請亮屏,另外19個只申請CPU喚醒,PMS仍然需要保持終端亮屏。?
因此,mWakeLockSummary就提供了一種整合多個WakeLock請求的功能,方便PMS進行集中的控制。

2、updateUserActivitySummaryLocked?
updateUserActivitySummaryLocked主要根據用戶最后的活動來決定當前屏幕的狀態。

/** * Updates the value of mUserActivitySummary to summarize the user requested * state of the system such as whether the screen should be bright or dim. * Note that user activity is ignored when the system is asleep. */ private void updateUserActivitySummaryLocked(long now, int dirty) {if ((dirty & (DIRTY_WAKE_LOCKS | DIRTY_USER_ACTIVITY| DIRTY_WAKEFULNESS | DIRTY_SETTINGS)) != 0) {mHandler.removeMessages(MSG_USER_ACTIVITY_TIMEOUT);long nextTimeout = 0;if (mWakefulness == WAKEFULNESS_AWAKE|| mWakefulness == WAKEFULNESS_DREAMING|| mWakefulness == WAKEFULNESS_DOZING) {//獲取進入休眠狀態的時間sleepTimeout//getSleepTimeoutLocked中會判斷休眠時間和屏幕熄滅時間的關系//如果休眠時間sleepTimeout小于屏幕熄滅時間screenOfftime, //則休眠時間被調整為屏幕熄滅時間,因為屏幕亮屏狀態下,終端不能進入休眠final int sleepTimeout = getSleepTimeoutLocked();//獲取屏幕熄滅的時間final int screenOffTimeout = getScreenOffTimeoutLocked(sleepTimeout);//獲取屏幕變暗的時間final int screenDimDuration = getScreenDimDurationLocked(screenOffTimeout);//當Window Manager判定用戶inactive時,將此標志置為truefinal boolean userInactiveOverride = mUserInactiveOverrideFromWindowManager;//類似于之前的mWakeLockSummary,將當前的用戶事件,轉化為PMS可以處理的屏幕狀態mUserActivitySummary = 0;//在喚醒的狀態下,發生過用戶事件if (mLastUserActivityTime >= mLastWakeTime) {//重新計算出屏幕需要變暗的時間nextTimeout = mLastUserActivityTime+ screenOffTimeout - screenDimDuration;if (now < nextTimeout) {//如果沒有到達需要變暗的時間,那么當前屏幕的狀態為USER_ACTIVITY_SCREEN_BRIGHT(亮屏)mUserActivitySummary = USER_ACTIVITY_SCREEN_BRIGHT;} else {//到達變暗的時間,則計算出屏幕熄滅的時間nextTimeout = mLastUserActivityTime + screenOffTimeout;if (now < nextTimeout) {//還沒到熄滅的時間,則當前屏幕的狀態為USER_ACTIVITY_SCREEN_DIM(暗屏)mUserActivitySummary = USER_ACTIVITY_SCREEN_DIM;}}}//注意mUserActivitySummary為0才會進入下面的分支//即上面改變mUserActivitySummary的條件不滿足時,才會進入這個分支(例如:喚醒狀態下,沒發生過改變屏幕狀態的UserActivity)if (mUserActivitySummary == 0//mLastUserActivityTimeNoChangeLights表示用戶最后的活動不會改變屏幕當前的狀態&& mLastUserActivityTimeNoChangeLights >= mLastWakeTime) {//計算下次屏幕熄滅的時間nextTimeout = mLastUserActivityTimeNoChangeLights + screenOffTimeout;//還未到達熄屏時間if (now < nextTimeout) {if (mDisplayPowerRequest.policy == DisplayPowerRequest.POLICY_BRIGHT) {//當前屏幕是亮屏,仍然設置為亮屏mUserActivitySummary = USER_ACTIVITY_SCREEN_BRIGHT;} else if (mDisplayPowerRequest.policy == DisplayPowerRequest.POLICY_DIM) {//當前屏幕是變暗,仍然設置為變暗mUserActivitySummary = USER_ACTIVITY_SCREEN_DIM;}}}if (mUserActivitySummary == 0) {//若定義了有效的休眠時間if (sleepTimeout >= 0) {//計算用戶最后的活動時間final long anyUserActivity = Math.max(mLastUserActivityTime,mLastUserActivityTimeNoChangeLights);//只有在喚醒狀態下,進行了用戶活動,才會重新更新休眠時間 (此時,應該是有過用戶活動,但過了息屏時間了)if (anyUserActivity >= mLastWakeTime) {nextTimeout = anyUserActivity + sleepTimeout;if (now < nextTimeout) {//走到這個分支,應該是屏幕已經熄滅,但還未到達休眠狀態,先進入dream態mUserActivitySummary = USER_ACTIVITY_SCREEN_DREAM;}}} else {//直接進入dream態,后文的updateWakefulnessLocked將判斷是否休眠mUserActivitySummary = USER_ACTIVITY_SCREEN_DREAM;nextTimeout = -1;}}//如果屏幕未進入dream態,但Window Manager判定用戶inactive,則進入下面分支if (mUserActivitySummary != USER_ACTIVITY_SCREEN_DREAM && userInactiveOverride) {//如果屏幕未熄滅if ((mUserActivitySummary &(USER_ACTIVITY_SCREEN_BRIGHT | USER_ACTIVITY_SCREEN_DIM)) != 0) {// Device is being kept awake by recent user activityif (nextTimeout >= now && mOverriddenTimeout == -1) {// Save when the next timeout would have occurredmOverriddenTimeout = nextTimeout;}}//Window Manager的權限很大,如果它判斷用戶inactive,直接進入dream態mUserActivitySummary = USER_ACTIVITY_SCREEN_DREAM;nextTimeout = -1;}//根據nextTimeOut延遲發送信息,信息被處理后,將重新調用updatePowerStateLocked,于是再次進入到該方法//通過不斷進入該方法,不斷評估是否根據用戶動作亮、熄屏等if (mUserActivitySummary != 0 && nextTimeout >= 0) {Message msg = mHandler.obtainMessage(MSG_USER_ACTIVITY_TIMEOUT);msg.setAsynchronous(true);mHandler.sendMessageAtTime(msg, nextTimeout);}} else {mUserActivitySummary = 0;}..........} }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125

從上面的代碼可以看出,在該函數中用mUserActivitySummary變量存儲當前屏幕的狀態。?
一共有3中基本狀態:?
* USER_ACTIVITY_SCREEN_BRIGHT 點亮屏幕?
* USER_ACTIVITY_SCREEN_DIM 屏幕變暗?
* USER_ACTIVITY_SCREEN_DREAM 屏保狀態?
從代碼可以看出,屏幕變化和userActivity活動有關,它根據最后的userActivity活動的時間決定點亮屏幕、調暗屏幕或熄滅屏幕。

之前的很多方法中都會調用userActivityNoUpdateLocked方法。該方法將觸發一次用戶活動,以更新用戶活動的時間,這樣屏幕變暗和熄滅時間就會重新進行計算。?
這也就是為什么用戶一直操作手機,屏幕不會熄滅或者變暗的原因。?

大圖地址?
整體來講,個人感覺這個函數的代碼寫的還是挺繞的,因此還是作一個圖記錄一下。?
大家有興趣可以看一下。

3、updateWakefulnessLocked?
從之前的代碼可以看出,updateWakefulnessLocked將決定第二階段的電源狀態更新是否結束。?
我們看一下updateWakefulnessLocked函數:

/** * Updates the wakefulness of the device. * * This is the function that decides whether the device should start dreaming * based on the current wake locks and user activity state. It may modify mDirty * if the wakefulness changes. * * Returns true if the wakefulness changed and we need to restart power state calculation. */ private boolean updateWakefulnessLocked(int dirty) {boolean changed = false;//下面的條件還是比較容易滿足的,基本上只要之前的流程更改過mDirty就會進入分支if ((dirty & (DIRTY_WAKE_LOCKS | DIRTY_USER_ACTIVITY | DIRTY_BOOT_COMPLETED| DIRTY_WAKEFULNESS | DIRTY_STAY_ON | DIRTY_PROXIMITY_POSITIVE| DIRTY_DOCK_STATE)) != 0) {//如果當前的狀態是喚醒的,isItBedTimeYetLocked判定不能再保持喚醒態if (mWakefulness == WAKEFULNESS_AWAKE && isItBedTimeYetLocked()) {................final long time = SystemClock.uptimeMillis();//主要根據設置信息,判斷是否滿足進入Dream狀態的條件if (shouldNapAtBedTimeLocked()) {//將mWakefullness的值置為WAKEFULNESS_DREAMING,修改mDirty變量,并進行通知等changed = napNoUpdateLocked(time, Process.SYSTEM_UID);} else {//將mWakefullness的值置為WAKEFULNESS_DOZING//如果系統設置了跳過Dozing態,則將mWakefullness置為WAKEFULNESS_ASLEEP//同時修改mDirty變量,并進行通知等changed = goToSleepNoUpdateLocked(time,PowerManager.GO_TO_SLEEP_REASON_TIMEOUT, 0, Process.SYSTEM_UID);}//注意:napNoUpdateLocked和goToSleepNoUpdateLocked函數正常執行后,//都會將mSandmanSummoned(被"睡魔"眷顧了)置為true}}return changed; }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36

從上面的代碼可以看出,如果終端可以一直保持喚醒狀態,或一開始就是非喚醒態,?
那么mWakefulness不會發生改變,第二階段的for循環將會break;

如果終端要從喚醒態變為非喚醒態,那么for循環將再運行一次,即重新計算一次mWakeLockSummary和mUserActivitySummary。?
這么做的原因是:updateWakeLockSummaryLocked和updateUserActivitySummaryLocked函數的一些計算,與終端是否處于喚醒狀態,即mWakefulness的值有關。?
由于這兩個函數并不會修改mWakefulness,因此在這一次運行時,updateWakefulnessLocked將返回false,即第二階段結束。

因此,我們可以得出結論:更新電源狀態的第二階段,正常情況下最多運行兩次。?
在第二階段的最后,我們看一下isItBedTimeYetLocked函數:

/** * Returns true if the device should go to sleep now. * Also used when exiting a dream to determine whether we should go back * to being fully awake or else go to sleep for good. */ private boolean isItBedTimeYetLocked() {//主要由isBeingKeptAwakeLocked決定return mBootCompleted && !isBeingKeptAwakeLocked(); }/** * Returns true if the device is being kept awake by a wake lock, user activity * or the stay on while powered setting. We also keep the phone awake when * the proximity sensor returns a positive result so that the device does not * lock while in a phone call. This function only controls whether the device * will go to sleep or dream which is independent of whether it will be allowed * to suspend. */ //根據狀態,判斷終端是否應該處于喚醒狀態 private boolean isBeingKeptAwakeLocked() {return mStayOn|| mProximityPositive|| (mWakeLockSummary & WAKE_LOCK_STAY_AWAKE) != 0|| (mUserActivitySummary & (USER_ACTIVITY_SCREEN_BRIGHT| USER_ACTIVITY_SCREEN_DIM)) != 0|| mScreenBrightnessBoostInProgress; }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

參考原生代碼的注釋,這一部分代碼還是比較好理解的。

三、更新display power state?
第三階段將負責更新屏幕的顯示狀態。

/** * Updates the display power state asynchronously. * When the update is finished, mDisplayReady will be set to true. The display * controller posts a message to tell us when the actual display power state * has been updated so we come back here to double-check and finish up. * * This function recalculates the display power state each time. */ private boolean updateDisplayPowerStateLocked(int dirty) {final boolean oldDisplayReady = mDisplayReady;//mDirty滿足條件時,進入以下分支if ((dirty & (DIRTY_WAKE_LOCKS | DIRTY_USER_ACTIVITY | DIRTY_WAKEFULNESS| DIRTY_ACTUAL_DISPLAY_POWER_STATE_UPDATED | DIRTY_BOOT_COMPLETED| DIRTY_SETTINGS | DIRTY_SCREEN_BRIGHTNESS_BOOST)) != 0) {//根據mWakefullness、mWakeLockSummary、mUserActivitySummary等,決定屏幕的policy//policy定義為DisplayPowerRequest.(POLICY_OFF、POLICY_DOZE、POLICY_BRIGHT和POLICY_DIM)mDisplayPowerRequest.policy = getDesiredScreenPolicyLocked();// Determine appropriate screen brightness and auto-brightness adjustments.//決定屏幕的亮度.................// Update display power request.// 更新mDisplayPowerRequest的參數...................//實際上調用DisplayPowerController的requestPowerState函數//在初始時,PMS注冊了mDisplayPowerCallbacks到DisplayPowerController中,//當更新完成后,會回調定義的接口,重新updatePowerStateLockedmDisplayReady = mDisplayManagerInternal.requestPowerState(mDisplayPowerRequest,mRequestWaitForNegativeProximity);...................}return mDisplayReady && !oldDisplayReady; }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34

我們跟進一下DisplayPowerController的requestPowerState函數:

/** * Requests a new power state. * The controller makes a copy of the provided object and then * begins adjusting the power state to match what was requested. */ public boolean requestPowerState(DisplayPowerRequest request,boolean waitForNegativeProximity) {.........synchronized (mLock) {boolean changed = false;//新需求增加:proximity sensor需要檢測距離if (waitForNegativeProximity//原來沒有這個需求&& !mPendingWaitForNegativeProximityLocked) {mPendingWaitForNegativeProximityLocked = true;changed = true;}//以下表示,參數中的Request對于DisplayPowerController而言,是一個新的需求if (mPendingRequestLocked == null) {mPendingRequestLocked = new DisplayPowerRequest(request);changed = true;} else if (!mPendingRequestLocked.equals(request)) {mPendingRequestLocked.copyFrom(request);changed = true;}if (changed) {//一但有新的需求,mDisplayReadyLocked就是false,表示屏幕有待調整mDisplayReadyLocked = false;}//有新需求,同時有對應的requestif (changed && !mPendingRequestChangedLocked) {mPendingRequestChangedLocked = true;//發送消息,更新屏幕狀態//最終通過DisplayPowerController的updatePowerState函數,進行屏幕狀態更新//這部分代碼也極其復雜,暫時不在這里展開分析//更新屏幕狀態后,將回調PMS的接口sendUpdatePowerStateLocked();}return mDisplayReadyLocked;} }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45

根據requestPowerState的代碼,我們知道:?
當PMS傳入一個新的mDisplayPowerRequest時,requestPowerState應該返回為false;當DisplayPowerController按照mDisplayPowerRequest修改完屏幕狀態,再次進入回到updateDisplayPowerStateLocked函數,調用requestPowerState時才會返回true。

整體的代碼流程大概可以抽象成下圖:?

這一階段的代碼,我們只是分析了整個過程的冰山一角,并沒有分析更新屏幕狀態的實際操作。?
但從現有的代碼可以看出,PMS的作用僅僅是維護終端電源相關狀態,實際的工作還是通過類似發送Request的方式,讓其它的服務協助完成。?
例如:在整個階段,PMS根據之前得到信息,構造出DisplayPowerRequest,然后發送給DisplayPowerController進行實際的處理。?
當DisplayPowerController完成實際的工作(部分工作還依賴于PhoneWindowManager)后,再通知PMS進行復查。

因此PMS的定位,確實可以用一個”Manager”來形容;?
負責整個終端信息的搜集和維護,然后將相應的工作指派給具體的“員工”執行;?
“員工”執行完畢后,向”Manager”匯報;?
“Manager”檢查工作的完成情況后,然后做出下一步的指示。

四、更新dream state?
updateDreamLocked函數主要用于更新屏保狀態,當設備進入或者退出屏保的時候都會觸發這個方法:

private void updateDreamLocked(int dirty, boolean displayBecameReady) {if ((dirty & (DIRTY_WAKEFULNESS| DIRTY_USER_ACTIVITY| DIRTY_WAKE_LOCKS| DIRTY_BOOT_COMPLETED| DIRTY_SETTINGS| DIRTY_IS_POWERED| DIRTY_STAY_ON| DIRTY_PROXIMITY_POSITIVE| DIRTY_BATTERY_STATE)) != 0 || displayBecameReady) {if (mDisplayReady) {//mDirty滿足條件,同時屏幕狀態調整完畢,才進入下一步scheduleSandmanLocked();} }private void scheduleSandmanLocked() {if (!mSandmanScheduled) {//mSandmanScheduled的作用就是讓MessageQueue中僅保留一個MSG_SANDMANmSandmanScheduled = true;//由handleSandman處理Message msg = mHandler.obtainMessage(MSG_SANDMAN);msg.setAsynchronous(true);mHandler.sendMessage(msg);} }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

handleSandman函數比較復雜,主要用于決定設備是否應該停留在dreaming或dozing狀態。?
我們分段介紹該函數的功能。

1、決定是否可以進入屏保狀態

/** * Called when the device enters or exits a dreaming or dozing state. */ private void handleSandman() {final boolean startDreaming;final int wakefulness;synchronized (mLock) {mSandmanScheduled = false;wakefulness = mWakefulness;//前面提到過,當updateWakefulnessLocked判斷進入dozing或sleep狀態時,//會將mSandmanSummoned置為true//mDisplayReady主要確保前面屏幕狀態更新完畢if (mSandmanSummoned && mDisplayReady) {//判斷device是否可以dream或dozingstartDreaming = canDreamLocked() || canDozeLocked();mSandmanSummoned = false;} else {startDreaming = false;}} ..........
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

這段代碼主要用于確定,設備是否可以看是dreaming。?
除去前置條件的限制外,此處的結果主要由canDreamLocked和canDozeLocked決定。

我們分別看看這兩個函數:

/** * Returns true if the device is allowed to dream in its current state. */ private boolean canDreamLocked() {//mWakefulness等于WAKEFULNESS_DREAMINGif (mWakefulness != WAKEFULNESS_DREAMING//設備支持dreaming|| !mDreamsSupportedConfig//設置開關開啟|| !mDreamsEnabledSetting//屏幕熄滅|| !mDisplayPowerRequest.isBrightOrDim()|| (mUserActivitySummary & (USER_ACTIVITY_SCREEN_BRIGHT| USER_ACTIVITY_SCREEN_DIM | USER_ACTIVITY_SCREEN_DREAM)) == 0//初始化完成|| !mBootCompleted) {return false;}//以上條件均滿足,才能進入后面的判斷//不處于喚醒態if (!isBeingKeptAwakeLocked()) {//沒充電,電源選項也未配置,不可dreamingif (!mIsPowered && !mDreamsEnabledOnBatteryConfig) {return false;}//沒充電,且電池電量過低,不可dreamingif (!mIsPowered&& mDreamsBatteryLevelMinimumWhenNotPoweredConfig >= 0&& mBatteryLevel < mDreamsBatteryLevelMinimumWhenNotPoweredConfig) {return false;}//充電,但電池電量過低,不可dreamingif (mIsPowered&& mDreamsBatteryLevelMinimumWhenPoweredConfig >= 0&& mBatteryLevel < mDreamsBatteryLevelMinimumWhenPoweredConfig) {return false;}//充電和未充電分別有一個最低的dreaming電量門限}return true; }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45

從上面的代碼可以看出,dreaming除了對終端當前的狀態、配置項有關外,在非喚醒狀態下還與當前的電池電量有關系。

canDozeLocked函數相對簡單:

private boolean canDozeLocked() {return mWakefulness == WAKEFULNESS_DOZING; }
  • 1
  • 2
  • 3

2、在必要時,進入屏保狀態

// Start dreaming if needed. final boolean isDreaming; if (mDreamManager != null) {if (startDreaming) {//結束舊夢mDreamManager.stopDream(false /*immediate*/);//開啟新夢mDreamManager.startDream(wakefulness == WAKEFULNESS_DOZING);}//startDream成功后,一般isDreaming就會返回trueisDreaming = mDreamManager.isDreaming(); } else {isDreaming = false; }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

決定了是否可以進入屏保狀態后,這一部分就開始進行實際的工作。

mDreamManager為DreamManagerService的Binder代理。?
我們重點看看DreamManagerService的startDream函數,stopDream的工作內容與startDream相反,不做細致分析:

//定義于DreamManagerService的內部類中 public void startDream(boolean doze) {startDreamInternal(doze); }//定義于DreamManagerService private void startDreamInternal(boolean doze) {final int userId = ActivityManager.getCurrentUser();//個人覺得這里應該是獲取屏保對象final ComponentName dream = chooseDreamForUser(doze, userId);if (dream != null) {synchronized (mLock) {startDreamLocked(dream, false /*isTest*/, doze, userId);}} }private void startDreamLocked(final ComponentName name,final boolean isTest, final boolean canDoze, final int userId) {//申請的屏保與當前的一致,不用進行修改if (Objects.equal(mCurrentDreamName, name)&& mCurrentDreamIsTest == isTest&& mCurrentDreamCanDoze == canDoze&& mCurrentDreamUserId == userId) {return;}//立即停止當前的屏保stopDreamLocked(true /*immediate*/);final Binder newToken = new Binder();mCurrentDreamToken = newToken;mCurrentDreamName = name;mCurrentDreamIsTest = isTest;mCurrentDreamCanDoze = canDoze;mCurrentDreamUserId = userId;mHandler.post(new Runnable() {@Overridepublic void run() {//調用DreamController的startDream函數mController.startDream(newToken, name, isTest, canDoze, userId);}}); }//定義于DreamController中 public void startDream(Binder token, ComponentName name,boolean isTest, boolean canDoze, int userId) {//移除當前屏保并回調通知stopDream(true /*immediate*/);.........try {..............//記錄dreammCurrentDream = new DreamRecord(token, name, isTest, canDoze, userId);mDreamStartTime = SystemClock.elapsedRealtime();..............//做好屏幕相關的準備工作try {mIWindowManager.addWindowToken(token, WindowManager.LayoutParams.TYPE_DREAM);} catch (RemoteException ex) {Slog.e(TAG, "Unable to add window token for dream.", ex);stopDream(true /*immediate*/);return;}Intent intent = new Intent(DreamService.SERVICE_INTERFACE);intent.setComponent(name);intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);try {//拉起屏保服務if (!mContext.bindServiceAsUser(intent, mCurrentDream,Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE,new UserHandle(userId))) {Slog.e(TAG, "Unable to bind dream service: " + intent);stopDream(true /*immediate*/);return;} catch (SecurityException ex) {............stopDream(true /*immediate*/);return;}mCurrentDream.mBound = true;//在DREAM_CONNECTION_TIMEOUT到期時,bind服務還未成功,runnable就負責結束dreammHandler.postDelayed(mStopUnconnectedDreamRunnable, DREAM_CONNECTION_TIMEOUT);} finally {........} }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91

從這部分代碼我們知道了,所謂的屏保其實就是拉起一個特殊的服務。

3、更新屏保狀態

// Update dream state. synchronized (mLock) {// Remember the initial battery level when the dream started.if (startDreaming && isDreaming) {mBatteryLevelWhenDreamStarted = mBatteryLevel;................}// If preconditions changed, wait for the next iteration to determine// whether the dream should continue (or be restarted).//例如:mDisplayReady為false時, mSandmanSummoned保持為falseif (mSandmanSummoned || mWakefulness != wakefulness) {return; // wait for next cycle}.............// Determine whether the dream should continue.if (wakefulness == WAKEFULNESS_DREAMING) {if (isDreaming && canDreamLocked()) {if (mDreamsBatteryLevelDrainCutoffConfig >= 0//下面這句我是懵逼的,這不是必然成立的么?//也就是只要配置了mDreamsBatteryLevelDrainCutoffConfig就會成立//按注釋來講,這里好歹重新取一次mBatteryLevel啊!!!懷疑是bug點&& mBatteryLevel < mBatteryLevelWhenDreamStarted- mDreamsBatteryLevelDrainCutoffConfig&& !isBeingKeptAwakeLocked()) {// If the user activity timeout expired and the battery appears// to be draining faster than it is charging then stop dreaming// and go to sleep.} else {return; // continue dreaming}}// Dream has ended or will be stopped. Update the power state.if (isItBedTimeYetLocked()) {//休眠goToSleepNoUpdateLocked(SystemClock.uptimeMillis(),PowerManager.GO_TO_SLEEP_REASON_TIMEOUT, 0, Process.SYSTEM_UID);updatePowerStateLocked();} else {//喚醒wakeUpNoUpdateLocked(SystemClock.uptimeMillis(), "android.server.power:DREAM",Process.SYSTEM_UID, mContext.getOpPackageName(), Process.SYSTEM_UID);updatePowerStateLocked();}} else if (wakefulness == WAKEFULNESS_DOZING) {if (isDreaming) {return; // continue dozing}// Doze has ended or will be stopped. Update the power state.reallyGoToSleepNoUpdateLocked(SystemClock.uptimeMillis(), Process.SYSTEM_UID);updatePowerStateLocked();} }// Stop dream. //執行到這里說明退出了dreaming狀態,如果之前拉起過屏保服務,此時應該停止它 if (isDreaming) {mDreamManager.stopDream(false /*immediate*/); } ...........
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63

以上是PMS更新屏保狀態的基本流程,整體來看相當的繁瑣。?
我們還是用一個圖來整體整理一下:?

大圖鏈接?
這部分代碼最后太亂,每次更新狀態后都會重新調用updatePowerStateLocked,然后再次進入到handleSandman函數中。?
這種反復地遞歸調用,比較難以把控。

五、更新suspend blocker?
updateSuspendBlockerLocked函數主要根據之前流程的執行結果,持有或者釋放CPU和屏幕的鎖。?
我們一起來看看對應的函數:

private void updateSuspendBlockerLocked() {//根據是否有CPU的wakelock,來決定cpu是保持否喚醒 final boolean needWakeLockSuspendBlocker = ((mWakeLockSummary & WAKE_LOCK_CPU) != 0);//根據前面屏幕相關的狀態,來決定是否需要持有屏幕的鎖final boolean needDisplaySuspendBlocker = needDisplaySuspendBlockerLocked();//屏幕如果不需要保持開啟狀態,那么可自動熄滅final boolean autoSuspend = !needDisplaySuspendBlocker;//應該是表示屏幕是否是可交互的final boolean interactive = mDisplayPowerRequest.isBrightOrDim();// Disable auto-suspend if needed.//autoSuspend為false,說明屏幕還需要點亮if (!autoSuspend && mDecoupleHalAutoSuspendModeFromDisplayConfig) {//通過native函數,調用底層的autosuspend_disablesetHalAutoSuspendModeLocked(false);}// First acquire suspend blockers if needed.//在需要的情況下,獲取CPU和屏幕的鎖if (needWakeLockSuspendBlocker && !mHoldingWakeLockSuspendBlocker) {mWakeLockSuspendBlocker.acquire();mHoldingWakeLockSuspendBlocker = true;}if (needDisplaySuspendBlocker && !mHoldingDisplaySuspendBlocker) {mDisplaySuspendBlocker.acquire();mHoldingDisplaySuspendBlocker = true;}// Inform the power HAL about interactive mode.if (mDecoupleHalInteractiveModeFromDisplayConfig) {if (interactive || mDisplayReady) {//調用底層動態庫的setInteractive函數,決定終端是否可以進行交互setHalInteractiveModeLocked(interactive);}}// Then release suspend blockers if needed.//如果不需要,則釋放CPU和屏幕的鎖 if (!needWakeLockSuspendBlocker && mHoldingWakeLockSuspendBlocker) {mWakeLockSuspendBlocker.release();mHoldingWakeLockSuspendBlocker = false;}if (!needDisplaySuspendBlocker && mHoldingDisplaySuspendBlocker) {mDisplaySuspendBlocker.release();mHoldingDisplaySuspendBlocker = false;}// Enable auto-suspend if needed.//如果需要設置自動休眠模式if (autoSuspend && mDecoupleHalAutoSuspendModeFromDisplayConfig) {setHalAutoSuspendModeLocked(true);} }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56

從上面的代碼可以看出PMS是非常依賴于native層的,真實的持鎖、釋放鎖、設置交互狀態等工作,均是移交到native層進行操作。?
我們以mWakeLockSuspendBlocker的處理流程為例,看看native的調用過程:

.......... mWakeLockSuspendBlocker = createSuspendBlockerLocked("PowerManagerService.WakeLocks"); .........
  • 1
  • 2
  • 3

之前的博客也提到過,PMS在其構造函數中調用createSuspendBlockerLocked函數,創建出了mWakeLockSuspendBlocker:

private SuspendBlocker createSuspendBlockerLocked(String name) {//實際對象為PMS內部類SuspendBlockerImplSuspendBlocker suspendBlocker = new SuspendBlockerImpl(name);mSuspendBlockers.add(suspendBlocker);return suspendBlocker; }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

從上面的代碼,我們知道當PMS需要獲取底層鎖時,調用的是SuspendBlockerImpl的acquire函數:

public void acquire() {synchronized (this) {mReferenceCount += 1;if (mReferenceCount == 1) {.......//調用到了native層nativeAcquireSuspendBlocker(mName);}} }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

在native層的com_android_server_power_PowerManagerService.cpp中,對應的native函數為:

static void nativeAcquireSuspendBlocker(JNIEnv *env, jclass /* clazz */, jstring nameStr) {ScopedUtfChars name(env, nameStr);//獲取的是PARTIAL_WAKE_LOCK的類型,即保持CPU喚醒的acquire_wake_lock(PARTIAL_WAKE_LOCK, name.c_str()); }
  • 1
  • 2
  • 3
  • 4
  • 5

從這里的代碼我們不難發現,盡管PMS定義了不同的WakeLock等級,但當通過PMS的native函數調用HAL層函數acquire_wake_lock時,使用的都是PARTIAL_WAKE_LOCK。?
個人覺得這是可以理解的,當其它進程向PMS申請保持屏幕喚醒的Framework層WakeLock后,PMS在Framework層就進行了對應的處理,例如將請求信息等地交給DisplayPowerController等處理。因此,對于底層的HAL層而言,只需要關注CPU是否需要保持喚醒即可。?
HAL層函數acquire_wake_lock,最后會向/sys/power/wake_lock節點進行write操作。

總結?
至此,updatePowerStateLocked的基本流程介紹完畢,大體上如下圖所示:

通過其中的源碼,我們也能看出僅管理當前的狀態,涉及的細節就非常的瑣碎。?
而屏幕和CPU的實際控制,還牽扯到大量其它對象和HAL層代碼。?
Android電源的管理實際上是基于Linux電源管理策略的,因此若要真正掌握,還需要對Linux的電源管理策略作進一步的了解。?
由于個人水平有限,目前還無法高屋建瓴地整體分析宏觀的電源管理架構,細節也有一些遺漏。?
后續爭取以此博客為基礎,不斷迭代,以求更進一步地了解PMS的知識。

原文地址: http://blog.csdn.net/gaugamela/article/details/52838654

與50位技術專家面對面20年技術見證,附贈技術全景圖

總結

以上是生活随笔為你收集整理的Android7.0 PowerManagerService(3) 核心函数updatePowerStateLocked的主要流程的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

4438全国亚洲精品观看视频 | 国产a国产a国产a | 又爽又黄在线观看 | 欧美日产一区 | 最近最新最好看中文视频 | 99精品视频免费观看视频 | 中文国产在线观看 | 一区二区三区国产精品 | 成人91在线| 免费福利视频导航 | 婷婷成人在线 | 看黄色91 | 亚洲黄色免费在线看 | 午夜在线观看一区 | 日韩av午夜| 亚洲九九影院 | 国产精品黄色 | 欧美a视频在线观看 | 精品在线观 | 国产亚洲婷婷 | 国产成人精品综合 | 亚洲精品乱码久久久久久久久久 | 人人爽久久久噜噜噜电影 | 国产99久| 日韩两性视频 | 在线国产激情视频 | 毛片精品免费在线观看 | 日韩在线观看a | 国产在线观看你懂的 | 最近高清中文字幕 | 高清在线一区 | 久久av在线播放 | 日本女人b | 亚洲国产中文字幕在线观看 | www.99av| 最近中文字幕免费av | 中文字幕日本特黄aa毛片 | 狠狠干2018 | 精品国产一区二区三区四区在线观看 | 亚洲精品人人 | 日韩av成人 | 永久免费看av | 色狠狠久久av五月综合 | 成人在线观看你懂的 | 特级西西444www大胆高清无视频 | 二区三区在线 | 欧美日韩免费看 | 久久99在线视频 | 色综合www | 9999国产精品 | 国产裸体永久免费视频网站 | 天天干天天操人体 | 欧美日韩中| 成人在线观看av | 久久综合免费视频 | 国产二级视频 | 久久综合成人 | 亚洲性少妇性猛交wwww乱大交 | 四虎影视成人永久免费观看亚洲欧美 | 日韩精品欧美精品 | 欧美一级片免费观看 | 国产在线看一区 | 日日夜夜综合网 | 97成人在线免费视频 | 精品亚洲免费视频 | 久久精品国产免费看久久精品 | 欧美日韩一区二区三区在线观看视频 | 国内精品久久久久影院日本资源 | 亚洲婷婷免费 | 国产高清在线a视频大全 | 久久国产精品视频免费看 | 国产午夜精品一区二区三区 | 国产经典av | a天堂中文在线 | 狠狠干天天操 | 免费人成在线观看 | 国产成人综合在线观看 | 久久日本视频 | 中文字幕视频三区 | 国产一级黄色片免费看 | av高清在线观看 | 国产黄色片免费 | 中文字幕日韩精品有码视频 | 国内精品久久久 | 亚洲天堂精品 | 国产精品乱码高清在线看 | 四虎永久免费网站 | 亚洲欧美观看 | 欧女人精69xxxxxx | 国产69熟 | 欧美日韩久久 | 中文在线最新版天堂 | 久久精品在线免费观看 | 国产无遮挡又黄又爽在线观看 | 亚洲国产精品久久久久久 | 久久久久久网址 | 久久国产精品一二三区 | 国产中文字幕视频 | 久久精品99北条麻妃 | 亚洲涩涩涩涩涩涩 | 亚洲美女在线国产 | 少妇bbw搡bbbb搡bbbb | 激情视频区 | 精品福利在线 | 亚洲欧洲一区二区在线观看 | 成人丁香花| 久久资源总站 | 91九色在线视频观看 | 一级片免费在线 | 一级黄色片在线 | 国内精品久久久久久久影视简单 | 91丨porny丨九色| 99精品国产高清在线观看 | 日韩有色 | 午夜久久成人 | 欧美久久影院 | 久久久精品国产免费观看一区二区 | 成人毛片a| 嫩模bbw搡bbbb搡bbbb | 欧美aⅴ在线观看 | 超碰在线1 | 中国一级片在线 | 免费精品人在线二线三线 | 在线视频黄 | 午夜精品久久久久久久99婷婷 | 岛国av在线 | 色网免费观看 | 日韩精品视频免费看 | 九草在线视频 | 日韩电影一区二区在线 | 国产精品一区久久久久 | 中文字幕综合在线 | 五月天国产 | 色网站免费在线看 | 精品久久久精品 | 91超级碰碰 | 日韩精品一区二区三区丰满 | av电影亚洲 | 麻豆一二| 久久精品视频国产 | 玖玖爱在线观看 | 午夜视频在线观看一区二区三区 | www.com黄色 | 成人禁用看黄a在线 | 狠狠色丁香久久综合网 | 天天操天天怕 | 激情黄色一级片 | 日本精品视频在线观看 | 51精品国自产在线 | 香蕉视频久久久 | www.国产高清 | 成人网在线免费视频 | 精品在线视频一区 | 在线观看日韩免费视频 | 久久公开免费视频 | 成人免费视频播放 | 日本少妇久久久 | 欧美 激情 国产 91 在线 | 久久久精品欧美 | 丁香六月婷 | 色噜噜在线观看 | 97国产在线| 蜜臀久久99精品久久久久久网站 | 在线国产福利 | 草莓视频在线观看免费观看 | 依人成人综合网 | 2023国产精品自产拍在线观看 | 一区二区三区日韩在线 | 国产色a在线观看 | 国产精品综合在线观看 | 97国产在线视频 | 亚洲国产精品影院 | 色婷婷综合久久久久中文字幕1 | 九九热久久免费视频 | 午夜色婷婷 | 精品影院一区二区久久久 | 粉嫩av一区二区三区免费 | 国产区精品视频 | 欧美精品久久久久性色 | 色偷偷人人澡久久超碰69 | 日韩视频在线播放 | .精品久久久麻豆国产精品 亚洲va欧美 | 91女人18片女毛片60分钟 | 黄色成人免费电影 | 国产男女爽爽爽免费视频 | 中文字幕第一页av | 天天草夜夜| 久久av免费 | 久久久久久久久久福利 | 国产精品自产拍在线观看中文 | 日本99久久 | 91麻豆免费看 | av免费看在线 | 青青久草在线视频 | 91爱爱网址| 国产精品久久婷婷六月丁香 | 99在线观看| 黄色在线观看免费 | 中文字幕a∨在线乱码免费看 | 久久精品香蕉 | av网站在线观看播放 | 中文字幕在线视频一区二区三区 | 国产午夜av | 999一区二区三区 | 日韩综合一区二区三区 | 精品久久久久久久久久岛国gif | 美女视频永久黄网站免费观看国产 | 国产精品热视频 | 免费看精品久久片 | 天天操夜夜摸 | 成人在线观看日韩 | 成人一区影院 | 手机在线黄色网址 | 亚洲美女视频在线观看 | 精品一区二区在线看 | 五月婷婷久久丁香 | 婷婷网址| 日本韩国精品在线 | 久久精品亚洲 | 久久伦理 | 中国一级片免费看 | 久久久久久网址 | 亚洲开心激情 | 日本黄色免费大片 | 欧美精彩视频在线观看 | 国产精品久久久久久久婷婷 | 黄色成人av网址 | 青青草国产成人99久久 | 国产精品视频99 | 成年人免费观看在线视频 | 射射色| 久久久鲁| 黄色亚洲在线 | 欧美日韩性生活 | 久久久男人的天堂 | 91福利视频免费观看 | 日韩色区| 亚洲日本精品视频 | 亚洲精品国精品久久99热 | 久久91久久久久麻豆精品 | av色图天堂网| 国产精品理论片在线播放 | 国产精久久 | 最新黄色av网址 | 国产视频精选在线 | 亚洲首页 | 亚洲精品xxxx | 久久久久久国产精品久久 | 国产原创在线 | 91传媒免费在线观看 | 波多野结衣一区 | 最新成人av | 亚洲一区二区高潮无套美女 | 午夜免费视频网站 | 久久免费视频网 | 永久免费毛片在线观看 | 欧美日韩免费观看一区二区三区 | 人人射网站| 91亚洲精品在线观看 | 丁香免费视频 | 1000部国产精品成人观看 | 91视频在线网址 | 欧美激情va永久在线播放 | 午夜国产一区二区 | 伊人狠狠色丁香婷婷综合 | 在线观看中文字幕亚洲 | 久久综合九色综合欧美狠狠 | 成人av影视观看 | 成人欧美日韩国产 | 国产字幕在线看 | 日韩av区| 97视频免费 | 日韩影片在线观看 | www.天天成人国产电影 | 日韩一区二区免费在线观看 | 欧美一二三区在线观看 | 免费看黄电影 | 懂色av一区二区在线播放 | 98精品国产自产在线观看 | 激情综合色综合久久 | 国产不卡高清 | 韩国av免费在线观看 | 日本高清dvd | 中文字幕有码在线播放 | 亚洲毛片久久 | 天天操月月操 | 婷婷在线免费 | www好男人 | 久久99免费观看 | 日韩av免费大片 | 成人av久久 | 免费情缘 | 99久久精品一区二区成人 | 最近中文国产在线视频 | 狠狠干网 | 最新av免费在线观看 | 日韩欧美视频一区二区 | 久久久综合九色合综国产精品 | 黄色在线观看免费 | 99久久久久久国产精品 | 午夜视频一区二区三区 | 91亚洲网 | 天天摸天天操天天爽 | www色com | 欧洲亚洲女同hd | 一二区电影 | 国产精品久久久久久久久免费 | 狠狠狠综合 | 国产福利小视频在线 | 在线视频18在线视频4k | 国产精品久久久久久久久久久不卡 | 久久久久日本精品一区二区三区 | 亚洲欧洲精品一区二区精品久久久 | 欧美日韩在线播放 | 日韩在线视频不卡 | 欧美国产精品一区二区 | 亚洲精品在线视频观看 | 国产视频九色蝌蚪 | 色多多污污在线观看 | 五月天六月色 | 久久色网站 | 色综合色综合色综合 | 欧美一区中文字幕 | 成人黄大片 | 国产精品久久久久永久免费观看 | 99精品国产一区二区三区不卡 | 天天干天天草天天爽 | 91丨九色丨91啦蝌蚪老版 | 日日爽天天操 | 久久国产精品免费一区二区三区 | 韩国一区二区三区在线观看 | 午夜国产福利在线观看 | 久久精品香蕉视频 | 国产在线高清精品 | 丁香六月网 | 亚洲免费av在线 | 久久国产视屏 | 91免费的视频在线播放 | 免费午夜网站 | 精品黄色在线观看 | 亚洲免费观看在线视频 | 日韩欧美在线观看一区 | 成年人视频在线免费 | 国产操在线 | 精品免费久久久久久 | 91精品国产高清自在线观看 | 国产综合视频在线观看 | 久久精品一区二区三区国产主播 | 久久综合狠狠综合久久狠狠色综合 | 精品国产乱码久久久久久浪潮 | 免费看污黄网站 | 国产精品久久久久久久毛片 | 国产破处在线视频 | 中文资源在线播放 | 欧美一级大片在线观看 | 国产精品igao视频网入口 | 亚洲最大av | 91在线视频在线 | 久一久久 | 精品亚洲视频在线 | 亚洲精品美女久久17c | 瑞典xxxx性hd极品 | 九九久久婷婷 | 国产精品美女在线观看 | 天天干一干| 欧美亚洲成人xxx | 婷婷色综合色 | 亚洲jizzjizz日本少妇 | 国产伦理久久精品久久久久_ | 久草久热| 91精品人成在线观看 | 亚洲黄色免费在线 | 黄网站色视频 | 久久成人精品电影 | 国产在线观看国语版免费 | 91在线小视频| 免费视频一级片 | 日本成人黄色片 | 午夜精品999 | 啪一啪在线| 91超国产| 久久成人麻豆午夜电影 | 免费色视频| 免费中文字幕 | 在线播放日韩av | 欧美日韩在线视频观看 | 日批视频在线 | 免费激情网 | 国产又黄又猛又粗 | 亚洲精品在线一区二区 | 亚洲尺码电影av久久 | 成人cosplay福利网站 | 狠狠狠色丁香婷婷综合久久五月 | 欧美日韩国产网站 | 天天插日日射 | 狠狠gao | 久草在线一免费新视频 | 欧美在线日韩在线 | 碰超在线观看 | 五月婷久| 久久国产福利 | 久久99精品久久久久婷婷 | 久久久久久毛片精品免费不卡 | 色综合久久久久网 | 久久一视频 | 日韩乱码在线 | 亚洲综合激情小说 | 在线视频日韩 | 久久精品免费观看 | 91精品国产九九九久久久亚洲 | 91秒拍国产福利一区 | 亚洲毛片一区二区三区 | 波多野结衣在线观看视频 | 久久久久久久久久免费视频 | 亚在线播放中文视频 | 天天玩天天干天天操 | 日韩高清在线不卡 | 精品国产欧美一区二区 | 亚洲女欲精品久久久久久久18 | 国产精品1000 | 亚洲人成影院在线 | 亚洲精品中文在线资源 | 免费看的视频 | 久久官网| 亚洲一区日韩 | 五月婷婷六月综合 | 国产精品理论片在线播放 | 在线黄av| 久久久久久99精品 | 国内一区二区视频 | 国产69精品久久久久99 | 日韩视频一区二区在线观看 | 天天操天天玩 | 四虎最新域名 | 2019天天干夜夜操 | 成人av资源站 | 一区三区在线欧 | 久久精品2| 国产不卡在线观看 | 一级特黄aaa大片在线观看 | 国产精品久久久久婷婷二区次 | 久久久免费| 国产成人福利 | 日韩精品欧美专区 | 四虎影视成人永久免费观看亚洲欧美 | 在线观av | 亚洲精品乱码久久久久久蜜桃91 | 成人9ⅰ免费影视网站 | 日韩系列 | 91久久奴性调教 | 日韩精品视频一二三 | 亚洲一区二区三区毛片 | 国内成人精品2018免费看 | 精品国产1区二区 | 欧美激情综合五月色丁香小说 | 国产成人在线免费观看 | 99久久精品一区二区成人 | 日韩国产精品毛片 | 国产理论一区二区三区 | 久久夜夜夜| 天天操天 | 久久国产精品免费看 | 亚洲欧美日韩国产精品一区午夜 | 日韩一区二区三 | 亚州av免费 | 91最新在线视频 | 欧美激情另类 | 美女久久久久 | 伊人成人久久 | 午夜久久久精品 | 91麻豆传媒 | 美女精品网站 | 麻豆传媒一区二区 | 黄色大片日本 | 少妇性xxx| 亚洲欧美成aⅴ人在线观看 四虎在线观看 | 天天操综 | 日韩综合一区二区三区 | 狠狠操电影网 | 日韩免费中文字幕 | 区一区二区三在线观看 | 91桃色视频| 99视频久久 | 黄色片视频在线观看 | 91在线区| 在线 国产 日韩 | 四虎影视欧美 | 亚洲国产片色 | 色在线亚洲 | 久久久久久久久久久网 | 亚洲日韩中文字幕在线播放 | av免费看在线 | 亚洲综合激情小说 | 国产精品久久久一区二区三区网站 | 国产成人久久av免费高清密臂 | 欧美日韩色婷婷 | 在线视频观看亚洲 | 欧美日韩视频在线 | 岛国片在线 | 激情视频免费在线 | 日韩成人高清在线 | 国产一级电影在线 | 福利电影一区二区 | a黄色片 | 成人毛片a | 一区二区中文字幕在线播放 | 6699私人影院| 91欧美视频网站 | 黄色亚洲精品 | 久久久高清免费视频 | 精品一区二区久久久久久久网站 | 亚洲精品国精品久久99热一 | 天天玩天天干天天操 | 亚洲日本韩国一区二区 | av在线影片 | 欧美成人h版 | 最近免费中文字幕mv在线视频3 | 中文字幕国产一区 | 精品国产乱码久久久久久天美 | 久久在线电影 | 91av在线播放| 国产另类xxxxhd高清 | 97精品国产97久久久久久粉红 | 中文字幕在线字幕中文 | 美女视频久久黄 | 午夜色站| 在线视频日韩精品 | 日本成人免费在线观看 | 国产成人av网站 | 激情婷婷av | 亚洲成人精品 | 一级精品视频在线观看宜春院 | av免费成人 | 国产视频一区二区在线播放 | 午夜免费在线观看 | 久久新| 免费男女羞羞的视频网站中文字幕 | 综合色站 | 国产在线视频导航 | 国产美女在线精品免费观看 | 国产精品永久在线 | 97成人免费视频 | 麻豆国产精品永久免费视频 | 成人影片在线播放 | 日韩极品在线 | 激情五月播播久久久精品 | 久草免费在线观看视频 | 九九国产精品视频 | 免费成人av电影 | 久久免费视频2 | 亚洲午夜精品久久久 | 在线 日韩 av| 天天激情综合网 | 五月的婷婷 | 国产乱码精品一区二区三区介绍 | 精品国产乱码久久久久久1区2匹 | 国产在线观看a | 最近中文字幕免费av | 国产精品成人一区二区三区 | 99精品福利 | 在线看欧美 | 日韩久久一区 | 97超碰人人澡人人 | 国产视频在线观看一区二区 | 国产精品高清av | 日韩成人精品一区二区三区 | 国产美女精品人人做人人爽 | 国产精品99久久99久久久二8 | 五月婷婷丁香色 | 日韩视频免费 | 中文字幕在线观看2018 | 天天摸天天操天天爽 | 91在线日韩| 精品国产三级a∨在线欧美 免费一级片在线观看 | 久久精品毛片 | 91视频传媒 | 天天拍天天爽 | 在线观看黄色免费视频 | 久草精品视频在线看网站免费 | 三级av免费看 | 欧美日韩裸体免费视频 | 嫩小bbbb摸bbb摸bbb | 五月综合色婷婷 | 综合国产在线 | 91av九色 | 日韩有码专区 | 日韩| 在线观看免费视频 | 国产小视频免费在线网址 | 免费人成网 | 亚洲在线激情 | 久久国产精品一区二区三区四区 | 亚洲爽爽网 | 成人国产精品一区二区 | 色中文字幕在线观看 | 在线一二三四区 | 国产97在线播放 | 手机在线永久免费观看av片 | 午夜在线观看影院 | 在线观看视频你懂得 | 五月开心婷婷 | 激情婷婷在线观看 | 日韩影视大全 | 久久成人一区二区 | 日韩中文幕 | 午夜精品久久久久久久久久久久久久 | 黄色av电影免费观看 | 99r在线精品| 午夜男人影院 | 久艹视频免费观看 | 国产精品永久在线观看 | 国产精品麻豆欧美日韩ww | 色欧美综合 | 激情九九| 亚洲一区二区视频在线播放 | 国产99久久久国产精品 | 日韩三级视频在线看 | 国产视频亚洲 | 五月婷久久 | 欧美a级一区二区 | 天天操比 | 日韩精品一区二区三区在线播放 | 丁香婷婷激情 | 亚洲欧美激情精品一区二区 | 久久99久久99精品免费看小说 | 99在线播放 | 久久久精品国产一区二区电影四季 | 免费看一级特黄a大片 | 国产福利一区二区三区在线观看 | 在线看毛片网站 | 久久天堂网站 | 久久综合导航 | 91热在线 | 成人资源在线播放 | 中文字幕国产精品一区二区 | 99综合影院在线 | 99精品欧美一区二区 | 久久99精品国产99久久 | 成人h视频在线播放 | 91影视成人 | 久久久国产高清 | 91香蕉视频 | 日本精品在线看 | 久久免视频 | 中文字幕在线中文 | 毛片888| 99热最新地址 | 蜜臀av一区二区 | 中文字幕日韩在线播放 | 麻豆一区在线观看 | 6080yy精品一区二区三区 | 日韩中文字幕视频在线观看 | www日韩精品 | 91色吧 | 欧美一级艳片视频免费观看 | 久操视频在线播放 | 字幕网在线观看 | 日韩久久久久久久久久 | 精品一区二区在线免费观看 | 免费在线观看av网站 | 欧美日韩国产一二 | 在线观看一区 | 乱子伦av | 狠狠色丁香婷婷综合最新地址 | 国产精品一区二区三区99 | 欧美色婷| 国产精品黑丝在线观看 | av永久网址 | 国产69熟 | 亚洲网站在线看 | 中文区中文字幕免费看 | 日韩激情精品 | 日韩综合一区二区 | 欧美日韩裸体免费视频 | 欧美日韩亚洲国产一区 | 久久99欧美 | 天堂av免费 | 亚洲天天综合 | 亚洲aⅴ免费在线观看 | 久久福利精品 | 天天曰天天射 | 国产最新视频在线观看 | 婷婷在线视频观看 | 在线看的av网站 | 久久公开免费视频 | 精品日韩中文字幕 | 视频二区在线 | 在线观看一级 | 久久视频在线观看免费 | 欧美一级视频免费看 | 蜜臀久久99精品久久久无需会员 | 国产黄色理论片 | 麻豆精品在线视频 | 天天看天天干 | 久久久蜜桃 | 五月天久久狠狠 | 成人免费看电影 | 在线观看色网 | 成人av电影免费观看 | 亚洲码国产日韩欧美高潮在线播放 | 一区二区三区三区在线 | 日韩网站在线观看 | 久久久久久免费视频 | 黄色免费大全 | 国产精品短视频 | 日韩网站免费观看 | 欧美日本三级 | 亚洲精品五月 | av在线电影网站 | 在线之家免费在线观看电影 | 久草在线国产 | 国产成人一区二区三区免费看 | 国产精品久久久久亚洲影视 | 欧美a级在线免费观看 | 丁香视频免费观看 | 探花视频网站 | 欧美日韩国产精品久久 | 99热在 | 91亚洲精品久久久久图片蜜桃 | 国产精品 日韩 欧美 | 99久久99热这里只有精品 | 黄色小说网站在线 | 激情五月在线观看 | 日本中文字幕网址 | 天天干天天做天天操 | 欧美精品久久久久久久久免 | 在线观看视频免费大全 | 日韩午夜三级 | 五月天中文字幕 | 黄色一级在线观看 | 综合激情久久 | 99精品欧美一区二区蜜桃免费 | 蜜臀久久99精品久久久酒店新书 | 国产高清视频免费观看 | 天天射综合网站 | 亚洲视频在线免费观看 | 成人免费观看网站 | av成人在线观看 | 丁香影院在线 | 免费av片在线 | 午夜av免费观看 | 日韩精品一区二区在线观看 | 成人毛片一区二区三区 | 亚洲国产欧美在线人成大黄瓜 | 五月天丁香亚洲 | 偷拍精偷拍精品欧洲亚洲网站 | 久草视频在线新免费 | 国产精品久久久久免费 | 精品国产一区二区三区噜噜噜 | 91桃花视频 | 久久er99热精品一区二区 | 中文字幕之中文字幕 | 91久久黄色 | 日韩中文字幕视频在线 | 日韩激情影院 | 97夜夜澡人人爽人人免费 | 夜夜操狠狠操 | 亚洲色图美腿丝袜 | 成人免费视频a | 亚洲精品大片www | 在线免费视频a | 日韩av资源站 | 国产一级片不卡 | 成x99人av在线www | 97超碰总站| 91视频88av| 国产欧美综合在线观看 | 黄色在线网站噜噜噜 | 色香天天 | 日韩欧美国产激情在线播放 | 2021久久| 精品一区二区久久久久久久网站 | 在线观看中文av | 九九热在线播放 | 午夜影院一级片 | 日韩精品视频免费专区在线播放 | 成人av午夜 | 最近免费观看的电影完整版 | 丝袜护士aⅴ在线白丝护士 天天综合精品 | 91香蕉视频好色先生 | 99精品国产一区二区三区不卡 | 97国产| 色视频网址 | 狠狠色丁香婷婷综合欧美 | 极品久久久久久久 | 91成人亚洲 | 免费观看91视频大全 | www激情com| 欧美精品在线观看免费 | 亚洲春色奇米影视 | 好看av在线 | av成人在线播放 | 久久久精华网 | 国产精品中文字幕在线播放 | 玖玖在线观看视频 | 免费视频一二三区 | 中文字幕一区二区三区在线观看 | 色欧美成人精品a∨在线观看 | 高清不卡免费视频 | 中文理论片 | 一区久久久 | 亚洲va欧美 | 日韩电影久久久 | 国产高清网站 | 日本最新高清不卡中文字幕 | 91夫妻自拍 | 黄色国产在线观看 | av三级av | 99视频这里只有 | av大全在线免费观看 | www.69xx | 久操中文字幕在线观看 | 五月婷婷天堂 | 在线视频 日韩 | 成人黄色片在线播放 | 国产一区91| 婷婷色亚洲 | 91在线影院 | 黄色大全视频 | 91精品专区 | 激情婷婷综合 | 日韩视频中文字幕在线观看 | 国产黄网站在线观看 | 久久免费99精品久久久久久 | 国产一区二区不卡视频 | 视频一区二区在线 | 亚洲欧洲精品视频 | 一区二区三区视频网站 | 在线一区二区三区 | 日本aa在线 | 在线三级av | 欧美精品午夜 | 午夜精品福利一区二区三区蜜桃 | 免费高清国产 | 精品一区久久 | 日本99干网 | 又黄又爽又色无遮挡免费 | av中文字幕网址 | 亚洲在线日韩 | av成人亚洲 | 国产一级不卡视频 | 日本精品视频一区二区 | 狠狠色伊人亚洲综合网站色 | 97av在线视频 | 国产婷婷久久 | www.com.黄| 国产原厂视频在线观看 | 97精品国产97久久久久久久久久久久 | 伊人婷婷综合 | 麻豆一区二区三区视频 | 日韩av黄| 高清av中文在线字幕观看1 | 日韩免费av在线 | 国语麻豆 | 中文字幕在线影院 | 国产在线色站 | 精品在线视频观看 | 国产96在线| 久草在线官网 | 午夜少妇一区二区三区 | 天天草天天干天天 | 成人免费在线播放视频 | 免费av在线 | 香蕉蜜桃视频 | 国语精品免费视频 | 97视频免费在线观看 | 99视频在线免费 | 中文字幕av网站 | 天天操天天干天天摸 | 热久久免费视频精品 | 色婷婷综合久久久 | 男女视频国产 | 日韩二区精品 | 久久久受www免费人成 | 九九99 | 亚洲综合干 | 国产色婷婷精品综合在线手机播放 | 日黄网站 | 久久久久久久国产精品视频 | 黄色福利网 | 在线观看一区二区视频 | 免费十分钟 | 久久久人人爽 | 久久五月天色综合 | 黄色特级一级片 | 久久综合色播五月 | 久久不射网站 | 欧美日韩一区二区三区在线观看视频 | 亚洲综合激情小说 | 国产精品美女久久久久久久 | 国产三级香港三韩国三级 | 国产精品福利视频 | 国产精品久久久久久久7电影 | 亚洲欧洲精品在线 | 欧美在线你懂的 | 六月丁香社区 | 日本丰满少妇免费一区 | 制服丝袜成人在线 | 久久电影国产免费久久电影 | 欧美 日韩 视频 | 日韩在线电影一区二区 | 久久久免费观看完整版 | 国产码电影 | 成年人在线免费视频观看 | 成人av电影免费观看 | 午夜影院一级片 | 国产一区二区三区在线免费观看 | 亚洲网久久| 久操视频在线免费看 | 在线亚洲欧美视频 | 国产精品永久在线 | 看v片 | .国产精品成人自产拍在线观看6 | 国产成人一二片 | 国产手机视频在线播放 | 精品欧美日韩 | 六月天色婷婷 | 精品国产一区二区三区蜜臀 | 色激情在线 | www操操 | a精品视频 | 九九视频在线观看视频6 | 新版资源中文在线观看 | 国产破处精品 | 综合网天天射 | 中文字幕乱在线伦视频中文字幕乱码在线 | 欧美久久综合 | 国产专区欧美专区 | 天天操天天操天天操天天 | 欧美激情亚洲综合 | 欧美另类人妖 | 国产精品成人免费一区久久羞羞 | 人人干,人人爽 | 精品国产伦一区二区三区观看说明 | 国产午夜精品av一区二区 | 国产午夜在线观看 | 国产精品久久久久av福利动漫 | 日本久久不卡视频 | 四虎在线免费观看视频 | 综合色天天| 97香蕉久久超级碰碰高清版 | 97色在线观看免费视频 | 97人人精品| 午夜在线看 | 国产在线国偷精品产拍免费yy | 中文字幕免费一区 | 亚洲视频1 | 久久亚洲影视 | 99精品久久只有精品 | 日日夜夜人人天天 | 欧美视频国产视频 | 免费观看国产视频 | 波多野结衣久久资源 | www.av免费观看 | 国产精品成人国产乱 | 久久五月婷婷综合 | 天堂av中文字幕 | 国产成人免费高清 | 国产一区在线不卡 | 在线小视频你懂的 | 国产精品福利午夜在线观看 | 97在线看 | 日韩精品一区二区三区丰满 | 狠狠色噜噜狠狠狠狠2021天天 | 九九九热精品免费视频观看网站 | www黄在线 | 黄色一级在线观看 | 久精品视频| 免费下载高清毛片 | 日韩理论在线视频 | 中文字幕中文字幕在线中文字幕三区 | 日韩黄色网络 | 亚洲免费在线 | 国产短视频在线播放 | 久久精品欧美日韩精品 | 三级在线视频观看 | 午夜精品视频福利 | 精品久久久免费视频 | 免费观看国产视频 | 国产在线视频一区二区 | 国产视频精品视频 | 探花系列在线 | 国产精品扒开做爽爽的视频 | 九九电影在线 | 精品久久久久久国产 | 超碰在线94 | 人人躁| 国产视频二| 激情在线网 | 国产精品一区二区三区免费视频 | 天天插天天 | 国产一区二区成人 | 97人人澡人人爽人人模亚洲 | 日韩高清国产精品 | 精品国产一区二区三区四 | 激情影院在线观看 | 国产日韩欧美在线免费观看 | 日韩免费电影一区二区三区 |