Android7.0 PowerManagerService亮滅屏分析(一)
緒論
可以導致手機亮滅屏的因素有多種,而在本文中主要講解按power鍵亮滅屏過程以及來電亮屏。在亮滅屏過程power中主要的實現類與功能如下所述:
PowerManagerService.java:以下簡稱PMS或者PowerMS,主要處理系統中與power相關的計算,然後決策系統該如何反應。同時協調power如何與系統其他模組的互動,比如沒有使用者活動時螢幕變暗等。
DisplayPowerController.java:以下簡稱DPC或者DisplayPC,管理display裝置狀態,在DisplayManagerService.java(簡稱DMS)中例項化一個物件,以DMS為橋樑與PMS進行互動。主要處理距離感測器,亮滅屏動畫,以及計算螢幕目標亮度值。通過非同步回撥機制來通知PMS那些事情發生了改變。同時也與WMS進行互動。
DisplayPowerState.java:
Notifier.java:將power狀態的重要變化,通過廣播發送出去,並且參與了與AMS,WMS,IMP的互動。
ColorFade.java:負責螢幕由關到開,由開到關的一些GL動畫,由DPC進行控制。
AutomaticBrightnessController.java:主要處理光感測器,將底層上傳的引數進行處理計算,將計算的新的亮度值傳給DPC。
RampAnimator.java:處理螢幕亮度漸變動畫。
亮屏總覽
在點選power鍵亮屏過程中,主要流程就是input對按鍵事件的傳輸,傳送到上層處理。之後就是在power中進行對亮屏狀態的處理,計算一系列的數值,並且與AMS,WMS等模組進行互動,最後呼叫底層LCD進行最終的裝置狀態與亮度的設定。在下面將會對各流程詳細講解。
Input傳輸Power鍵
當觸發power鍵,kernel會將該事件中斷,然後InputReader通過EventHub獲取事件,並且對輸入事件進行處理,之後交由InputDispatcher進行分發。如果該事件為key事件會先呼叫interceptKeyBeforeQueueing,提前對需要系統處理的事件進行處理。最終調到PhoneWindowManager類中的interceptKeyBeforeQueueing函式對該事件優先處理,對power鍵以及螢幕狀態進行判斷,來決定亮屏還是滅屏等操作。當需要亮屏時,會呼叫PowerMangerService中的wakeup函式進行處理。
從底層到上層的具體程式碼呼叫流程 InputReader.cpp->InputDispatcher.cpp->com_android_server_input_InputManagerService.cpp->InputManagerService.java->InputMonitor.java->WindowManagerPolicy.java->PhoneWindowManager.java最終來到java層處理按鍵事件.
public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {
if (!mSystemBooted) { //系統還沒有啟動完成,不處理任何按鍵事件
// If we have not yet booted, don't let key events do anything.
return 0;
}
final boolean interactive = (policyFlags & FLAG_INTERACTIVE) != 0; //是否能與使用者互動, 如果亮屏為true
final boolean down = event.getAction() == KeyEvent.ACTION_DOWN; //按鍵down事件
final boolean canceled = event.isCanceled(); //事件被取消
final int keyCode = event.getKeyCode(); //按鍵事件的code
final boolean isInjected = (policyFlags & WindowManagerPolicy.FLAG_INJECTED) != 0;
// Basic policy based on interactive state.
int result;
boolean isWakeKey = (policyFlags & WindowManagerPolicy.FLAG_WAKE) != 0
|| event.isWakeKey(); //flags有wake標記,或者按鍵為KEYCODE_BACK, KEYCODE_MENU, KEYCODE_WAKEUP, KEYCODE_PAIRING, KEYCODE_STEM_1, KEYCODE_STEM_2, KEYCODE_STEM_3設定isWakeKey為true. power ,home鍵屬於systemKey
// If the key would be handled globally, just return the result, don't worry about special
// key processing.
if (isValidGlobalKey(keyCode)
&& mGlobalKeyManager.shouldHandleGlobalKey(keyCode, event)) {
if (isWakeKey) { //如果按鍵時間有效, 並且在com.android.internal.R.xml.global_keys檔案中配置了keycode. 如果是喚醒鍵就呼叫wakeUp喚醒螢幕
wakeUp(event.getEventTime(), mAllowTheaterModeWakeFromKey, "android.policy:KEY");
}
return result;
}
// Handle special keys. //處理特殊的按鍵事件 ,這裡主要講解power鍵事件
switch (keyCode) {
case KeyEvent.KEYCODE_BACK: //back鍵
case KeyEvent.KEYCODE_VOLUME_DOWN: //音量下鍵
case KeyEvent.KEYCODE_VOLUME_UP: //音量上鍵
case KeyEvent.KEYCODE_VOLUME_MUTE: //靜音鍵
case KeyEvent.KEYCODE_ENDCALL: //結束通話電話鍵
case KeyEvent.KEYCODE_POWER: { //電源鍵
result &= ~ACTION_PASS_TO_USER;
isWakeKey = false; // wake-up will be handled separately
if (down) { //power按下事件
interceptPowerKeyDown(event, interactive); //處理power下鍵
} else { //power鍵鬆開
interceptPowerKeyUp(event, interactive, canceled); //處理power上鍵
}
break;
}
case KeyEvent.KEYCODE_SLEEP:
case KeyEvent.KEYCODE_SOFT_SLEEP:
case KeyEvent.KEYCODE_WAKEUP:
case KeyEvent.KEYCODE_MEDIA_PLAY:
case KeyEvent.KEYCODE_MEDIA_PAUSE:
case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
case KeyEvent.KEYCODE_HEADSETHOOK:
case KeyEvent.KEYCODE_MUTE:
case KeyEvent.KEYCODE_MEDIA_STOP:
case KeyEvent.KEYCODE_MEDIA_NEXT:
case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
case KeyEvent.KEYCODE_MEDIA_REWIND:
case KeyEvent.KEYCODE_MEDIA_RECORD:
case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD:
case KeyEvent.KEYCODE_MEDIA_AUDIO_TRACK:
case KeyEvent.KEYCODE_CALL:
case KeyEvent.KEYCODE_VOICE_ASSIST:
case KeyEvent.KEYCODE_WINDOW:
}
}
if (isWakeKey) { //如果除了power鍵, 別的按鍵也需要亮屏,就呼叫WakeUp亮屏
wakeUp(event.getEventTime(), mAllowTheaterModeWakeFromKey, "android.policy:KEY");
}
return result;
}
處理power鍵down事件 private void interceptPowerKeyDown(KeyEvent event, boolean interactive) {
// Hold a wake lock until the power key is released.
if (!mPowerKeyWakeLock.isHeld()) {
mPowerKeyWakeLock.acquire(); //獲取wakeLock,保持cpu喚醒狀態
}
// Latch power key state to detect screenshot chord.
if (interactive && !mScreenshotChordPowerKeyTriggered
&& (event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) {
mScreenshotChordPowerKeyTriggered = true;
mScreenshotChordPowerKeyTime = event.getDownTime();
interceptScreenshotChord(); //螢幕截圖
}
// Stop ringing or end call if configured to do so when power is pressed.
TelecomManager telecomManager = getTelecommService(); //獲取telecom
boolean hungUp = false;
if (telecomManager != null) {
if (telecomManager.isRinging()) { //如果來電過程中,按power鍵手機將靜音,停止響鈴
// Pressing Power while there's a ringing incoming
// call should silence the ringer.
telecomManager.silenceRinger();
} else if ((mIncallPowerBehavior
& Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_HANGUP) != 0
&& telecomManager.isInCall() && interactive) {
// Otherwise, if "Power button ends call" is enabled,
// the Power button will hang up any current active call.
hungUp = telecomManager.endCall(); //如果在Setting資料庫中配置了,按power鍵結束通話電話, 就將電話結束通話
}
}
//................
// If the power key has still not yet been handled, then detect short
// press, long press, or multi press and decide what to do. //如果power鍵還沒有被處理,就判斷是短按, 長按,還是多按來決定如何處理
mPowerKeyHandled = hungUp || mScreenshotChordVolumeDownKeyTriggered
|| mScreenshotChordVolumeUpKeyTriggered || gesturedServiceIntercepted;
if (!mPowerKeyHandled) {
if (interactive) {
// When interactive, we're already awake.
// Wait for a long press or for the button to be released to decide what to do.
if (hasLongPressOnPowerBehavior()) { //如果螢幕是亮這的,長按power鍵 ,就處理長按事件
Message msg = mHandler.obtainMessage(MSG_POWER_LONG_PRESS);
msg.setAsynchronous(true);
mHandler.sendMessageDelayed(msg,
ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout());
}
} else {
wakeUpFromPowerKey(event.getDownTime()); //如果螢幕是休眠狀態,就喚醒螢幕
if (mSupportLongPressPowerWhenNonInteractive && hasLongPressOnPowerBehavior()) {
Message msg = mHandler.obtainMessage(MSG_POWER_LONG_PRESS);
msg.setAsynchronous(true);
mHandler.sendMessageDelayed(msg, //如果還是長按power鍵, 就再處理長按事件
ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout());
mBeganFromNonInteractive = true;
} else {
final int maxCount = getMaxMultiPressPowerCount();
if (maxCount <= 1) {
mPowerKeyHandled = true;
} else {
mBeganFromNonInteractive = true;
}
}
}
}
}
Power鍵up事件 private void interceptPowerKeyUp(KeyEvent event, boolean interactive, boolean canceled) {
final boolean handled = canceled || mPowerKeyHandled;
mScreenshotChordPowerKeyTriggered = false;
cancelPendingScreenshotChordAction();
cancelPendingPowerKeyAction();
if (!handled) { //power鍵還沒被處理
// Figure out how to handle the key now that it has been released.
mPowerKeyPressCounter += 1;
final int maxCount = getMaxMultiPressPowerCount(); //多按的次數
final long eventTime = event.getDownTime(); //按鍵發生的時間點
if (mPowerKeyPressCounter < maxCount) {
// This could be a multi-press. Wait a little bit longer to confirm.
// Continue holding the wake lock. //等待一會呼叫powerPress處理
Message msg = mHandler.obtainMessage(MSG_POWER_DELAYED_PRESS,
interactive ? 1 : 0, mPowerKeyPressCounter, eventTime);
msg.setAsynchronous(true);
mHandler.sendMessageDelayed(msg, ViewConfiguration.getDoubleTapTimeout());
return;
}
// No other actions. Handle it immediately.
powerPress(eventTime, interactive, mPowerKeyPressCounter); //沒有的的處理, 立即處理power down事件
}
// Done. Reset our state.
finishPowerKeyPress(); //power鍵處理結束
}
private void finishPowerKeyPress() {
mBeganFromNonInteractive = false;
mPowerKeyPressCounter = 0;
if (mPowerKeyWakeLock.isHeld()) {
mPowerKeyWakeLock.release(); //釋放wakLock
}
}
powerPress函式主要通過按power鍵的次數以及不同的behavior對power鍵做不同的處理. private void powerPress(long eventTime, boolean interactive, int count) {
if (mScreenOnEarly && !mScreenOnFully) {
Slog.i(TAG, "Suppressed redundant power key press while "
+ "already in the process of turning the screen on.");
return;
}
if (count == 2) {
powerMultiPressAction(eventTime, interactive, mDoublePressOnPowerBehavior); //處理按兩次power鍵事件
} else if (count == 3) {
powerMultiPressAction(eventTime, interactive, mTriplePressOnPowerBehavior); //處理按三次power鍵事件
} else if (interactive && !mBeganFromNonInteractive) {
switch (mShortPressOnPowerBehavior) {
case SHORT_PRESS_POWER_NOTHING:
break;
case SHORT_PRESS_POWER_GO_TO_SLEEP: //滅屏
mPowerManager.goToSleep(eventTime,
PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON, 0);
break;
case SHORT_PRESS_POWER_REALLY_GO_TO_SLEEP: //滅屏,不經歷doze流程
mPowerManager.goToSleep(eventTime,
PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON,
PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE);
break;
case SHORT_PRESS_POWER_REALLY_GO_TO_SLEEP_AND_GO_HOME:
mPowerManager.goToSleep(eventTime, //滅屏,不經歷doze流程, 並返回home介面
PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON,
PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE);
launchHomeFromHotKey();
break;
case SHORT_PRESS_POWER_GO_HOME: //返回home介面
launchHomeFromHotKey(true /* awakenFromDreams */, false /*respectKeyguard*/);
break;
}
}
}
根據前面分析可以知道在power鍵down事件時就會呼叫wakeUpFromPowerKey函式來喚醒螢幕. private void wakeUpFromPowerKey(long eventTime) {
wakeUp(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); //呼叫PowerManagerService喚醒螢幕
return true;
}
傳送亮屏廣播當power接收到亮滅屏呼叫後,會先進行設定手機wakefullness狀態. 之後傳送亮滅屏廣播通知其他應用手機處於亮屏還是滅屏狀態。
private boolean wakeUpNoUpdateLocked(long eventTime, String reason, int reasonUid,
String opPackageName, int opUid) {
if (DEBUG_SPEW) {
Slog.d(TAG, "wakeUpNoUpdateLocked: eventTime=" + eventTime + ", uid=" + reasonUid);
}
if (eventTime < mLastSleepTime || mWakefulness == WAKEFULNESS_AWAKE
|| !mBootCompleted || !mSystemReady) {
return false; //判斷是否要去亮屏
}
Trace.traceBegin(Trace.TRACE_TAG_POWER, "wakeUp");
try {
switch (mWakefulness) {
case WAKEFULNESS_ASLEEP:
Slog.i(TAG, "Waking up from sleep due to"+opPackageName+" "+reason+" (uid " + reasonUid +")...");
break;
case WAKEFULNESS_DREAMING:
Slog.i(TAG, "Waking up from dream due to"+opPackageName+" "+reason+" (uid " + reasonUid +")...");
break;
case WAKEFULNESS_DOZING:
Slog.i(TAG, "Waking up from dozing due to"+opPackageName+" "+reason+" (uid " + reasonUid +")...");
break;
}
mLastWakeTime = eventTime; //設定最後一次喚醒的時間
setWakefulnessLocked(WAKEFULNESS_AWAKE, 0); //Notifier呼叫onWakefulnessChangeStarted傳送亮屏廣播
mNotifier.onWakeUp(reason, reasonUid, opPackageName, opUid); //呼叫Notifier通知battery處理
userActivityNoUpdateLocked( //更新最後一次使用者事件的時間
eventTime, PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, reasonUid);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_POWER);
}
return true;
}
在Notifier.java中與AMS,window,input進行互動,通知各模組手機狀態發生了改變,根據螢幕狀態各自進行處理, 最後傳送亮滅屏廣播, 通知關心的模組. public void onWakefulnessChangeStarted(final int wakefulness, int reason) {
final boolean interactive = PowerManagerInternal.isInteractive(wakefulness); //獲取互動模式,亮屏為true, 滅屏為false
if (DEBUG) {
Slog.d(TAG, "onWakefulnessChangeStarted: wakefulness=" + wakefulness
+ ", reason=" + reason + ", interactive=" + interactive);
}
// Tell the activity manager about changes in wakefulness, not just interactivity.
// It needs more granularity than other components.
mHandler.post(new Runnable() {
@Override
public void run() {
mActivityManagerInternal.onWakefulnessChanged(wakefulness); //與AMS互動處理
}
});
// Handle any early interactive state changes.
// Finish pending incomplete ones from a previous cycle.
if (mInteractive != interactive) {
// Finish up late behaviors if needed.
if (mInteractiveChanging) {
handleLateInteractiveChange();
}
// Start input as soon as we start waking up or going to sleep.
mInputManagerInternal.setInteractive(interactive); //在input中記錄現在的螢幕狀態
mInputMethodManagerInternal.setInteractive(interactive);
// Notify battery stats.
try {
mBatteryStats.noteInteractive(interactive); //喚醒battery狀態
} catch (RemoteException ex) { }
// Handle early behaviors.
mInteractive = interactive;
mInteractiveChangeReason = reason;
mInteractiveChanging = true;
handleEarlyInteractiveChange(); //初期處理互動模式改變
}
}
private void handleEarlyInteractiveChange() {
synchronized (mLock) {
if (mInteractive) {
// Waking up... //亮屏
mHandler.post(new Runnable() {
@Override
public void run() {
EventLog.writeEvent(EventLogTags.POWER_SCREEN_STATE, 1, 0, 0, 0);
mPolicy.startedWakingUp(); //通過PhoneWindowManager系統開始亮屏, 更新轉向監聽器,手勢監聽器等
}
});
// Send interactive broadcast.
mPendingInteractiveState = INTERACTIVE_STATE_AWAKE;
mPendingWakeUpBroadcast = true;
updatePendingBroadcastLocked(); //更新亮屏廣播
} else {
// Going to sleep... //滅屏
// Tell the policy that we started going to sleep.
final int why = translateOffReason(mInteractiveChangeReason);
mHandler.post(new Runnable() {
@Override
public void run() {
mPolicy.startedGoingToSleep(why);
}
});
}
}
}
通過Handler傳送MSG_BROADCAST訊息來發送下一個廣播sendNextBroadcast() private void sendNextBroadcast() {
final int powerState;
synchronized (mLock) {
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 {
// Broadcasted power state is asleep. Send awake if needed.
if (mPendingWakeUpBroadcast || mPendingGoToSleepBroadcast
|| mPendingInteractiveState == INTERACTIVE_STATE_AWAKE) {
mPendingWakeUpBroadcast = false;
mBroadcastedInteractiveState = INTERACTIVE_STATE_AWAKE;
} else {
finishPendingBroadcastLocked();
return;
}
}
mBroadcastStartTime = SystemClock.uptimeMillis();
powerState = mBroadcastedInteractiveState;
}
EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_SEND, 1);
if (powerState == INTERACTIVE_STATE_AWAKE) {
sendWakeUpBroadcast(); //傳送亮屏廣播
} else {
sendGoToSleepBroadcast();
}
}
mScreenOnIntent = new Intent(Intent.ACTION_SCREEN_ON); //亮屏廣播intent
mScreenOnIntent.addFlags( //前臺廣播
Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FOREGROUND);
private void sendWakeUpBroadcast() {
if (DEBUG) {
Slog.d(TAG, "Sending wake up broadcast.");
}
if (ActivityManagerNative.isSystemReady()) {
mContext.sendOrderedBroadcastAsUser(mScreenOnIntent, UserHandle.ALL, null,
mWakeUpBroadcastDone, mHandler, 0, null, null); //傳送亮屏廣播,並且其它模組全部處理完後, 自身接收亮屏廣播
} else {
EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_STOP, 2, 1);
sendNextBroadcast();
}
}
private final BroadcastReceiver mWakeUpBroadcastDone = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_DONE, 1,
SystemClock.uptimeMillis() - mBroadcastStartTime, 1);
sendNextBroadcast(); //自身接收到亮屏廣播後, 之後會呼叫finishPendingBroadcastLocked,釋放wakeLock
}
};
當power接收到亮滅屏呼叫後,會先進行設定手機wakefullness狀態,之後傳送亮滅屏廣播通知其他應用手機處於亮屏還是滅屏狀態。並且在傳送廣播過程中power也與AMS,window,input進行互動,通知各模組手機狀態發生了改變,根據螢幕狀態各自進行處理。其中傳送亮滅屏廣播的主要實現在Notifier.java中。當wakefulness狀態發生改變,AMS收到通知。如果亮屏操作,AMS就會通過函式comeOutOfSleepIfNeedLocked呼叫到ActivityStackSupervisor中,將sleep超時訊息移除,如果抓的有partial鎖,就將其釋放,最後將在棧頂的activity顯示出來。
power是通過WindowManagerPolicy與PhoneWindowManager進行互動,當螢幕在wakingup時需要通知window進行更新手勢監聽,更新方向監聽,更新鎖屏超時時間。最後通知keyguard螢幕點亮了,進行重新整理鎖屏介面時間,之後通過回撥介面,回調回PhoneWindowManager的onShown函式,通知window keyguard準備完成。
當亮屏時通過InputManagerService將當前螢幕狀態傳入JNI中進行記錄,當再次發生power鍵事件可以方便確認該事件是需要亮屏還是滅屏。
更新Power全域性狀態
當廣播處理完畢後就會呼叫PMS的內部函式updatePowerStateLocked來更新全域性電源狀態。其實在PMS中很多函式都只是對一些必須的屬性進行賦值,大部分最終都會呼叫到updatePowerStateLocked函式中進行功能執行,其中更新電源狀態主要依據就是變數mDirty。mDirty就是用來記錄power state的變化的標記位,這樣的狀態變化在系統中一共定義了12個,每一個狀態對應一個固定的數字,都是2的倍數。這樣,若有多個狀態一塊變化,進行按位取或這樣結果既是唯一的,又能準確標記出各個狀態的變化。在updatePowerStateLocked中主要做了如下事情:
一.首先判斷手機是否處於充電狀態,如果標記位DIRTY_BATTERY_STATE發生改變時就證明電池狀態發生了改變,然後通過對比判斷(通過電池前後變化與充電狀態的變化),確認手機是否處於充電狀態。如果手機處於充電狀態會將表示充電的標記位記入mDirty中。當有USB插拔時我們也可以通過配置資訊來決定是否需要點亮螢幕。並且是否在充電或者充電方式發生改變,系統都會認為發生了一次使用者事件進行更新最後使用者操作時間,以此來重新計算螢幕超時時間。
private void updateIsPoweredLocked(int dirty) {
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; //如果充電中設定mDirty
// Update wireless dock detection state.
final boolean dockedOnWirelessCharger = mWirelessChargerDetector.update(
mIsPowered, mPlugType, mBatteryLevel); //無線充電
// Treat plugging and unplugging the devices as a user activity.
// Users find it disconcerting when they plug or unplug the device
// and it shuts off right away.
// Some devices also wake the device when plugged or unplugged because
// they don't have a charging LED.
final long now = SystemClock.uptimeMillis();
if (shouldWakeUpWhenPluggedOrUnpluggedLocked(wasPowered, oldPlugType,
dockedOnWirelessCharger)) { //插拔USB是否要點亮螢幕
wakeUpNoUpdateLocked(now, "android.server.power:POWER", Process.SYSTEM_UID,
mContext.getOpPackageName(), Process.SYSTEM_UID);
}
userActivityNoUpdateLocked( //插拔USB算一次使用者事件,重新設定最後一次使用者事件的時間點
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) {
if (DEBUG_SPEW) {
Slog.d(TAG, "updateIsPoweredLocked: resetting low power snooze");
}
mAutoLowPowerModeSnoozing = false;
}
updateLowPowerModeLocked(); //更新低電模式
}
}
}
mWakeUpWhenPluggedOrUnpluggedConfig = resources.getBoolean(
com.android.internal.R.bool.config_unplugTurnsOnScreen); //從xml檔案中讀取配置資訊
private boolean shouldWakeUpWhenPluggedOrUnpluggedLocked(
boolean wasPowered, int oldPlugType, boolean dockedOnWirelessCharger) {
// Don't wake when powered unless configured to do so.
if (!mWakeUpWhenPluggedOrUnpluggedConfig) { //如果配置為true, 可能會亮屏
return false;
}
// Don't wake when undocked from wireless charger.
// See WirelessChargerDetector for justification.
if (wasPowered && !mIsPowered
&& oldPlugType == BatteryManager.BATTERY_PLUGGED_WIRELESS) {
return false;
}
// Don't wake when docked on wireless charger unless we are certain of it.
// See WirelessChargerDetector for justification.
if (!wasPowered && mIsPowered
&& mPlugType == BatteryManager.BATTERY_PLUGGED_WIRELESS
&& !dockedOnWirelessCharger) {
return false;
}
// If already dreaming and becoming powered, then don't wake.
if (mIsPowered && mWakefulness == WAKEFULNESS_DREAMING) {
return false;
}
// Don't wake while theater mode is enabled.
if (mTheaterModeEnabled && !mWakeUpWhenPluggedOrUnpluggedInTheaterModeConfig) {
return false;
}
// Otherwise wake up!
return true;
}
二:更新wakefulness
for (;;) {
int dirtyPhase1 = mDirty;
dirtyPhase2 |= dirtyPhase1;
mDirty = 0; //將mDirty清零,不影響下個迴圈
updateWakeLockSummaryLocked(dirtyPhase1);
updateUserActivitySummaryLocked(now, dirtyPhase1);
if (!updateWakefulnessLocked(dirtyPhase1)) { //當updateWakefulnessLocked返回false跳出迴圈
break;
}
}
updateWakeLockSummaryLocked函式將wakeLock的型別用mWakeLockSummary進行記錄,最後與Wakefulness狀態結合重新算出新的mWakeLockSummary值,在下面判斷是否需要睡眠時會使用。
private void updateWakeLockSummaryLocked(int dirty) {
if ((dirty & (DIRTY_WAKE_LOCKS | DIRTY_WAKEFULNESS)) != 0) {
mWakeLockSummary = 0;
final int numWakeLocks = mWakeLocks.size(); //獲取所有的wakeLocks
for (int i = 0; i < numWakeLocks; i++) { //遍歷所有的wakeLocks, 將wakeLocks記錄在mWakeLockSummary中
final WakeLock wakeLock = mWakeLocks.get(i);
switch (wakeLock.mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK) {
case PowerManager.PARTIAL_WAKE_LOCK:
if (!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: //dim鎖
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.
if (mWakefulness != WAKEFULNESS_DOZING) { //根據當前的螢幕狀態, 取消不必要的wakeLocks
mWakeLockSummary &= ~(WAKE_LOCK_DOZE | WAKE_LOCK_DRAW);
}
if (mWakefulness == WAKEFULNESS_ASLEEP //如果螢幕為休眠,就將螢幕高亮,dim鎖取消
|| (mWakeLockSummary & WAKE_LOCK_DOZE) != 0) {
mWakeLockSummary &= ~(WAKE_LOCK_SCREEN_BRIGHT | WAKE_LOCK_SCREEN_DIM
| WAKE_LOCK_BUTTON_BRIGHT);
if (mWakefulness == WAKEFULNESS_ASLEEP) {
mWakeLockSummary &= ~WAKE_LOCK_PROXIMITY_SCREEN_OFF;
}
}
// Infer implied wake locks where necessary based on the current state.
if ((mWakeLockSummary & (WAKE_LOCK_SCREEN_BRIGHT | WAKE_LOCK_SCREEN_DIM)) != 0) {
if (mWakefulness == WAKEFULNESS_AWAKE) {
mWakeLockSummary |= WAKE_LOCK_CPU | WAKE_LOCK_STAY_AWAKE; //當WakeLock為亮屏鎖或dim鎖時,需要保持AWAKE狀態。
} else if (mWakefulness == WAKEFULNESS_DREAMING) {
mWakeLockSummary |= WAKE_LOCK_CPU;
}
}
if ((mWakeLockSummary & WAKE_LOCK_DRAW) != 0) {
mWakeLockSummary |= WAKE_LOCK_CPU;
}
if (DEBUG_SPEW) {
Slog.d(TAG, "updateWakeLockSummaryLocked: mWakefulness="
+ PowerManagerInternal.wakefulnessToString(mWakefulness)
+ ", mWakeLockSummary=0x" + Integer.toHexString(mWakeLockSummary));
}
}
}
之後updateUserActivitySummaryLocked就會更新螢幕超時時間,根據最後一次的使用者事件與螢幕超時時間與dim持續時間來計算螢幕超時的時間,然後與現在的時間進行對比,來決定螢幕要繼續高亮,還是要變為dim狀態。 private void updateUserActivitySummaryLocked(long now, int dirty) {
// Update the status of the user activity timeout timer.
if ((dirty & (DIRTY_WAKE_LOCKS | DIRTY_USER_ACTIVITY
| DIRTY_WAKEFULNESS | DIRTY_SETTINGS)) != 0) {
mHandler.removeMessages(MSG_USER_ACTIVITY_TIMEOUT); //移除螢幕超時的Message
long nextTimeout = 0;
if (mWakefulness == WAKEFULNESS_AWAKE
|| mWakefulness == WAKEFULNESS_DREAMING
|| mWakefulness == WAKEFULNESS_DOZING) {
final int sleepTimeout = getSleepTimeoutLocked(); //獲取睡眠超時時間
final int screenOffTimeout = getScreenOffTimeoutLocked(sleepTimeout); //獲取螢幕超時時間
final int screenDimDuration = getScreenDimDurationLocked(screenOffTimeout); //獲取dim持續時長
final boolean userInactiveOverride = mUserInactiveOverrideFromWindowManager;
mUserActivitySummary = 0;
if (mLastUserActivityTime >= mLastWakeTime) { //最後一次的使用者時間大於最後一次螢幕醒來的時間
nextTimeout = mLastUserActivityTime //計算下一次螢幕要變為dim的時間
+ screenOffTimeout - screenDimDuration;
if (now < nextTimeout) {
mUserActivitySummary = USER_ACTIVITY_SCREEN_BRIGHT; //現在還早於螢幕超時, 設定現在使用者活動為螢幕高亮
} else {
nextTimeout = mLastUserActivityTime + screenOffTimeout; //重新設定螢幕超時時間,進入dim階段
if (now < nextTimeout) { //進入dim階段了
mUserActivitySummary = USER_ACTIVITY_SCREEN_DIM;
}
}
}
if (mUserActivitySummary == 0
&& mLastUserActivityTimeNoChangeLights >= mLastWakeTime) {
nextTimeout = mLastUserActivityTimeNoChangeLights + screenOffTimeout;
if (now < nextTimeout) { //根據請求的policy來判斷螢幕是高亮,還是dim狀態
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) { //如果mUserActivitySummary還沒賦值
if (sleepTimeout >= 0) {
final long anyUserActivity = Math.max(mLastUserActivityTime,
mLastUserActivityTimeNoChangeLights);
if (anyUserActivity >= mLastWakeTime) {
nextTimeout = anyUserActivity + sleepTimeout;
if (now < nextTimeout) {
mUserActivitySummary = USER_ACTIVITY_SCREEN_DREAM; //設定dream狀態
}
}
} else {
mUserActivitySummary = USER_ACTIVITY_SCREEN_DREAM;
nextTimeout = -1;
}
}
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 activity
if (nextTimeout >= now && mOverriddenTimeout == -1) {
// Save when the next timeout would have occurred
mOverriddenTimeout = nextTimeout;
}
}
mUserActivitySummary = USER_ACTIVITY_SCREEN_DREAM;
nextTimeout = -1;
}
if (mUserActivitySummary != 0 && nextTimeout >= 0) { //mUserActivitySummary有值, 並且nextTimeout大於等於0, 發超時訊息
Message msg = mHandler.obtainMessage(MSG_USER_ACTIVITY_TIMEOUT);
msg.setAsynchronous(true);
mHandler.sendMessageAtTime(msg, nextTimeout); //傳送螢幕超時的Message
}
} else {
mUserActivitySummary = 0;
}
if (DEBUG_SPEW) {
Slog.d(TAG, "updateUserActivitySummaryLocked: mWakefulness="
+ PowerManagerInternal.wakefulnessToString(mWakefulness)
+ ", mUserActivitySummary=0x" + Integer.toHexString(mUserActivitySummary)
+ ", nextTimeout=" + TimeUtils.formatUptime(nextTimeout));
}
}
}
PowerManagerHandler接收螢幕超時的訊息, 並且呼叫handleUserActivityTimeout進行處理, 該函式之後就在Handler執行緒中執行.
/**
* Handler for asynchronous operations performed by the power manager.
*/
private final class PowerManagerHandler extends Handler {
public PowerManagerHandler(Looper looper) {
super(looper, null, true /*async*/);
}
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_USER_ACTIVITY_TIMEOUT:
handleUserActivityTimeout(); //處理使用者超時事件
break;
case MSG_SANDMAN:
handleSandman();
break;
case MSG_SCREEN_BRIGHTNESS_BOOST_TIMEOUT:
handleScreenBrightnessBoostTimeout();
break;
}
}
}
private void handleUserActivityTimeout() { // runs on handler thread
synchronized (mLock) {
if (DEBUG_SPEW) {
Slog.d(TAG, "handleUserActivityTimeout");
}
mDirty |= DIRTY_USER_ACTIVITY; //設定有使用者活動的mDirty值
updatePowerStateLocked(); //更新電源狀態, 最後去判斷是否要睡眠
}
}
根據前面流程圖可以看出更新wakefulness過程是通過一個死迴圈來執行的,只有呼叫函式updateWakefulnessLocked返回false時才會跳出迴圈。在迴圈中對wakeLockSummary進行更新,並且更新自動滅屏時間後,進行判斷系統是否該睡眠了,是否可以跳出迴圈,具體流程圖如下: 在updateWakefulnessLocked中主要根據是否存在wakeLock,使用者活動進行判斷裝置是否需要進入睡眠狀態。從函式isBeingKeptAwakeLocked可以看出當device拿著一個wake lock,有使用者事件,有距離感測器等都不會滅屏進行睡眠狀態。如果需要睡眠就會往下面呼叫,最後跳出迴圈。
private boolean updateWakefulnessLocked(int dirty) {
boolean changed = false;
if ((dirty & (DIRTY_WAKE_LOCKS | DIRTY_USER_ACTIVITY | DIRTY_BOOT_COMPLETED
| DIRTY_WAKEFULNESS | DIRTY_STAY_ON | DIRTY_PROXIMITY_POSITIVE
| DIRTY_DOCK_STATE)) != 0) {
if (mWakefulness == WAKEFULNESS_AWAKE && isItBedTimeYetLocked()) { //mWakefulness為AWAKE, 並且到了睡覺時間, 就去睡覺
if (DEBUG_SPEW) {
Slog.d(TAG, "updateWakefulnessLocked: Bed time...");
}
final long time = SystemClock.uptimeMillis();
if (shouldNapAtBedTimeLocked()) {
changed = napNoUpdateLocked(time, Process.SYSTEM_UID); //睡覺前先小憩一會
} else {
changed = goToSleepNoUpdateLocked(time,
PowerManager.GO_TO_SLEEP_REASON_TIMEOUT, 0, Process.SYSTEM_UID); //直接睡覺
}
}
}
return changed;
}
private boolean isItBedTimeYetLocked() {// 對所有該喚醒的情況取反, 就是該休眠了
return mBootCompleted && !isBeingKeptAwakeLocked();
}
private boolean isBeingKeptAwakeLocked() {
return mStayOn //設定了stay on
|| mProximityPositive //距離感測器返回一個positive結果,保持喚醒
|| (mWakeLockSummary & WAKE_LOCK_STAY_AWAKE) != 0 //當有wake lock時保持喚醒
|| (mUserActivitySummary & (USER_ACTIVITY_SCREEN_BRIGHT
| USER_ACTIVITY_SCREEN_DIM)) != 0 //有user activity時保持喚醒
|| mScreenBrightnessBoostInProgress;
}
mDreamsActivateOnSleepSetting = (Settings.Secure.getIntForUser(resolver,
Settings.Secure.SCREENSAVER_ACTIVATE_ON_SLEEP,
mDreamsActivatedOnSleepByDefaultConfig ? 1 : 0,
UserHandle.USER_CURRENT) != 0); //從settings資料庫獲取對應值
mDreamsActivateOnDockSetting = (Settings.Secure.getIntForUser(resolver,
Settings.Secure.SCREENSAVER_ACTIVATE_ON_DOCK,
mDreamsActivatedOnDockByDefaultConfig ? 1 : 0,
UserHandle.USER_CURRENT) != 0);
private boolean shouldNapAtBedTimeLocked() { //當返回true, 裝置自動nap
return mDreamsActivateOnSleepSetting
|| (mDreamsActivateOnDockSetting
&& mDockState != Intent.EXTRA_DOCK_STATE_UNDOCKED);
}
private boolean napNoUpdateLocked(long eventTime, int uid) {
if (DEBUG_SPEW) {
Slog.d(TAG, "napNoUpdateLocked: eventTime=" + eventTime + ", uid=" + uid);
}
if (eventTime < mLastWakeTime || mWakefulness != WAKEFULNESS_AWAKE
|| !mBootCompleted || !mSystemReady) {
return false;
}
Trace.traceBegin(Trace.TRACE_TAG_POWER, "nap");
try {
Slog.i(TAG, "Nap time (uid " + uid +")...");
mSandmanSummoned = true;
setWakefulnessLocked(WAKEFULNESS_DREAMING, 0); //設定WAKEFULNESS_DREAMING
} finally {
Trace.traceEnd(Trace.TRACE_TAG_POWER);
}
return true;
}
呼叫goToSleepNoUpdateLocked進行睡眠, 當按power鍵滅屏是也會呼叫該函式.
private boolean goToSleepNoUpdateLocked(long eventTime, int reason, int flags, int uid) {
if (DEBUG_SPEW) {
Slog.d(TAG, "goToSleepNoUpdateLocked: eventTime=" + eventTime
+ ", reason=" + reason + ", flags=" + flags + ", uid=" + uid);
}
if (eventTime < mLastWakeTime
|| mWakefulness == WAKEFULNESS_ASLEEP
|| mWakefulness == WAKEFULNESS_DOZING
|| !mBootCompleted || !mSystemReady) {
return false; //判斷裝置是否應該睡眠
}
Trace.traceBegin(Trace.TRACE_TAG_POWER, "goToSleep");
try {
switch (reason) { //輸出滅屏的原因
case PowerManager.GO_TO_SLEEP_REASON_DEVICE_ADMIN:
Slog.i(TAG, "Going to sleep due to device administration policy "
+ "(uid " + uid +")...");
break;
case PowerManager.GO_TO_SLEEP_REASON_TIMEOUT:
Slog.i(TAG, "Going to sleep due to screen timeout (uid " + uid +")...");
break;
case PowerManager.GO_TO_SLEEP_REASON_LID_SWITCH:
Slog.i(TAG, "Going to sleep due to lid switch (uid " + uid +")...");
break;
case PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON:
Slog.i(TAG, "Going to sleep due to power button (uid " + uid +")...");
break;
case PowerManager.GO_TO_SLEEP_REASON_SLEEP_BUTTON:
Slog.i(TAG, "Going to sleep due to sleep button (uid " + uid +")...");
break;
case PowerManager.GO_TO_SLEEP_REASON_HDMI:
Slog.i(TAG, "Going to sleep due to HDMI standby (uid " + uid +")...");
break;
default:
Slog.i(TAG, "Going to sleep by application request (uid " + uid +")...");
reason = PowerManager.GO_TO_SLEEP_REASON_APPLICATION;
break;
}
mLastSleepTime = eventTime;
mSandmanSummoned = true;
setWakefulnessLocked(WAKEFULNESS_DOZING, reason);
// Report the number of wake locks that will be cleared by going to sleep.
int numWakeLocksCleared = 0;
final int numWakeLocks = mWakeLocks.size();
for (int i = 0; i < numWakeLocks; i++) { //遍歷所有的wakeLocks, 將FULL, BRIGHT, DIM Locks,計入numWakeLocksCleared中
final WakeLock wakeLock = mWakeLocks.get(i);
switch (wakeLock.mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK) {
case PowerManager.FULL_WAKE_LOCK:
case PowerManager.SCREEN_BRIGHT_WAKE_LOCK:
case PowerManager.SCREEN_DIM_WAKE_LOCK:
numWakeLocksCleared += 1;
break;
}
}
EventLog.writeEvent(EventLogTags.POWER_SLEEP_REQUESTED, numWakeLocksCleared);
// Skip dozing if requested.
if ((flags & PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE) != 0) {
reallyGoToSleepNoUpdateLocked(eventTime, uid); //如果沒有doze流程,直接設定WAKEFULNESS_ASLEEP
}
} finally {
Trace.traceEnd(Trace.TRACE_TAG_POWER);
}
return true; //返回true
}
當第一個for迴圈中將所有的狀態都設定好了, 並且此時也沒有重要的mDirty發生變化, 在下一次迴圈中mDirty的值為0, updateWakefulnessLocked返回false,就會跳出迴圈. 當跳出迴圈之後在函式updateDisplayPowerStateLocked中進行獲取需要請求的裝置電源狀態是亮還是滅或者dim,判斷是否開啟了自動調節亮度開關,是否使用了距離感測器,並經過一系列的計算獲取亮度值等,最終都記錄到DisplayPowerRequest中,經過DMS傳入DPC中,進行處理。
private boolean updateDisplayPowerStateLocked(int dirty) {
final boolean oldDisplayReady = mDisplayReady;
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) {
mDisplayPowerRequest.policy = getDesiredScreenPolicyLocked(); //根據mWakefulness與mWakeLockSummary獲得,裝置新狀態是DIM, BRIGHT, OFF還是DOZE
// Determine appropriate screen brightness and auto-brightness adjustments.
boolean brightnessSetByUser = true;
int screenBrightness = mScreenBrightnessSettingDefault;
float screenAutoBrightnessAdjustment = 0.0f; //自動亮度調節
boolean autoBrightness = (mScreenBrightnessModeSetting ==
Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC); //是否開啟自動亮度
if (isValidBrightness(mScreenBrightnessOverrideFromWindowManager)) {
screenBrightness = mScreenBrightnessOverrideFromWindowManager;
autoBrightness = false;
brightnessSetByUser = false;
} else if (isValidBrightness(mTemporaryScreenBrightnessSettingOverride)) {
screenBrightness = mTemporaryScreenBrightnessSettingOverride;
} else if (isValidBrightness(mScreenBrightnessSetting)) {
screenBrightness = mScreenBrightnessSetting;
}
if (autoBrightness) {
screenBrightness = mScreenBrightnessSettingDefault; //自動亮度調節
if (isValidAutoBrightnessAdjustment(
mTemporaryScreenAutoBrightnessAdjustmentSettingOverride)) {
screenAutoBrightnessAdjustment =
mTemporaryScreenAutoBrightnessAdjustmentSettingOverride;
} else if (isValidAutoBrightnessAdjustment(
mScreenAutoBrightnessAdjustmentSetting)) {
screenAutoBrightnessAdjustment = mScreenAutoBrightnessAdjustmentSetting;
}
}
screenBrightness = Math.max(Math.min(screenBrightness, //獲得請求亮度
mScreenBrightnessSettingMaximum), mScreenBrightnessSettingMinimum);
screenAutoBrightnessAdjustment = Math.max(Math.min(
screenAutoBrightnessAdjustment, 1.0f), -1.0f);
// Update display power request. //將資料記錄在mDisplayPowerRequest中
mDisplayPowerRequest.screenBrightness = screenBrightness;
mDisplayPowerRequest.screenAutoBrightnessAdjustment =
screenAutoBrightnessAdjustment;
mDisplayPowerRequest.brightnessSetByUser = brightnessSetByUser;
mDisplayPowerRequest.useAutoBrightness = autoBrightness;
mDisplayPowerRequest.useProximitySensor = shouldUseProximitySensorLocked();
mDisplayPowerRequest.lowPowerMode = mLowPowerModeEnabled;
mDisplayPowerRequest.boostScreenBrightness = mScreenBrightnessBoostInProgress;
mDisplayPowerRequest.useTwilight = mBrightnessUseTwilight;
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;
}
mDisplayReady = mDisplayManagerInternal.requestPowerState(mDisplayPowerRequest,
mRequestWaitForNegativeProximity); //呼叫requestPowerState請求電源狀態
mRequestWaitForNegativeProximity = false;
if (DEBUG_SPEW) {
Slog.d(TAG, "updateDisplayPowerStateLocked: mDisplayReady=" + mDisplayReady
+ ", policy=" + mDisplayPowerRequest.policy
+ ", mWakefulness=" + mWakefulness
+ ", mWakeLockSummary=0x" + Integer.toHexString(mWakeLockSummary)
+ ", mUserActivitySummary=0x" + Integer.toHexString(mUserActivitySummary)
+ ", mBootCompleted=" + mBootCompleted
+ ", mScreenBrightnessBoostInProgress="
+ mScreenBrightnessBoostInProgress);
}
}
return mDisplayReady && !oldDisplayReady;
}
相關推薦
Android7.0 PowerManagerService亮滅屏分析(一)
緒論可以導致手機亮滅屏的因素有多種,而在本文中主要講解按power鍵亮滅屏過程以及來電亮屏。在亮滅屏過程power中主要的實現類與功能如下所述:PowerManagerService.java:以下簡稱PMS或者PowerMS,主要處理系統中與power相關的計算,然後決策系
Android7.0 PowerManagerService亮滅屏分析(三)
在前面兩部分已經對繪製windows與設定裝置狀態進行了詳細講解. 之後接著就該對亮度值進行設定, 實現亮屏動作了.在DisplayPowerController中的animateScreenBrightness函式通過亮度漸變動畫來將亮度設定到目標亮度. // Bri
Android7.0 PowerManagerService亮滅屏分析(二)
在PowerManagerService中對各種狀態進行判斷後,將其數值封裝進DisplayPowerRequest中傳入DisplayPowerController中進一步處理。在亮屏過程中DisplayPowerController會根據傳過來的數值來設定新的電源
Android7.1 Kyguard介面滅屏時間分析
概述 在Android系統中,當用戶沒有操作手機一段時間後,系統會自動滅屏進入休眠狀態,從而降低手機功耗。一般情況下系統滅屏的時間由使用者在手機設定中自己進行定義是10s,30s還是1min等等。但是如果現在系統當前顯示的是鎖屏介面,不論使用者在設定中定義的螢幕超時
Android7.0去電流程原始碼分析(一)
2.去電從撥號盤介面有關撥號的部分由DialpadFragment.java實現,無論是單卡還是雙卡,當點選撥號按鍵時,最後都會呼叫handleDialButtonPressed方法進行處理,DialogFragmentCall_Action的活動Call_Ac
popupWindow在android7.0以上顯示全屏的問題
在Android7.0以上版本呼叫popupWindow的showAsDropDown()方法,始終顯示全屏,今天記錄下解決這個問題的方法 自定義popupwindow複寫showAsDropDown
Android7.0 PowerManagerService(4) Power按鍵流程
按鍵的處理主要由InputManagerService負責,屬於Android輸入系統的流程。在這篇部落格裡,我們只關注與Power鍵相關的內容。InputManagerService處理的按鍵事件,最終將會傳遞到PhoneWindowManager的inter
android PowerManager亮滅屏(實現篇)
網上查了好多資料 不是講原理就是講原理呀! 你Tm到是實現呀!!!墨跡一大篇文章,都是看的官文件然後加上自己的理解一頓墨跡。 具體講下我要實現的功能: Android 6.0實現自動亮滅螢幕,按下電源鍵螢幕滅屏5s後自動亮屏,時間可以自己設定 用到的知識有 1:powe
android 監聽Home鍵和亮滅屏
1.註冊廣播 IntentFilter filter = new IntentFilter(); filter.addAction(Intent.ACTION_CLOS
Android6.0 亮屏滅屏流程(DisplayPowerControler、WMS)(二)亮度設定
上一篇部落格我們主要分析了在setScreenState中呼叫PhoneWindowManager的一些流程,在setScreenState中先是呼叫了DisplayPowerState的setScreenState函式。上篇部落格我們沒有分析,這篇部落格我們先從這個函式開
Android7.0 MediaRecorder源碼分析
錄像 stage sdn ice ren oop 新建 n) edi 最近在做Camera的方案(雙進程打開一個Camera),涉及到使用MediaRecorder 進行錄像,還是自己新建一套錄像系統。接下來我將記錄下本次源碼分析的流程。 有關於Client和Server
popupwindow在android7.0出現全屏解決方案
在android7.0的版本測出popupwindow使用showAsDropDown方法之後,並不能顯示在指定view的下方,而是全屏顯示,只要重寫showAsDropDown判斷一下版本就好了.建議不要使用popupwindow了,使用DialogFragment代替 publi
Android 螢幕滅屏亮屏廣播,螢幕滅屏亮屏監聽
service 類註冊廣播進行監聽 /** * 作者:created by meixi * 郵箱:[email protected] * 日期:2018/9/27 09 */ public class Serview extends Service { /**
Android7.1 [Camera] cam_board.xml 檔案解析原始碼分析(一)
原始碼平臺:rk3399 RK支援了很多個攝像頭,在驅動目錄hardware/rockchip/camer
Android7.1 [Camera] Camera Hal 原始碼分析(一)
原始碼平臺:rk3399 命令列ls看下原始碼的結構 hardware/rockchip/camera/CameraHal: lib目錄 原始碼的檔案看起來有點多,我們看看Android.mk檔案, 這些檔案最終編譯成camera.rk30bo
Android7.0原始碼分析之Binder——Client分析
Binder Client分析,咋一看,就那麼四個關鍵方法:getService()、addService()、checkService()、listServices()。四個方法原理都差不多,以下僅
android4.4 車載滅屏 按任意鍵及觸控式螢幕幕恢復亮屏
車載上的android4.4系統,基本上常亮。但最近需要一個新功能可以在launcher新增一個按鈕,點選的時候。螢幕亮度為0,但實際上不等於按power鍵,不會睡眠。 然後可以按任意鍵恢復亮度,包括觸屏事件。 一、PowerManagerService原先螢幕亮度流程
[Android7.0]NFC初始化的流程分析
1、NFC初始化的時序圖: 2、程式碼分析: 初始化分兩部分,第一供應framework使用的服務端初始化,並將服務新增到ServiceManager中,第二是初始化NFC介面卡NfcAdapter,其中就包含何種對應NFC協議的服務。 * 服務端的初
Android7.0 Settings主選單新增一條item
往Android7.0的settings的主選單裡新增一條item. N與M的Settings不同,在M上只要找到Settings裡面的相應的佈局新增就好,但在N上由於Setting裡面的item不再受佈局控制,所以得在程式碼中新增. 找到/packages
Android7.0 分屏多視窗
如果您使用 N Preview SDK 構建應用,則可以配置應用處理多視窗顯示的方法。 例如,您可以指定 Activity 的最小允許尺寸。 您還可以禁用應用的多視窗顯示,確保系統僅以全屏模式顯示應用。 概覽 Android N 允許多個應用同時共享螢幕。例如,使用者可以分屏顯示應用,在左邊檢視網頁,