日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

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

Android

Android 8.0 手机亮灭屏

發布時間:2024/1/8 Android 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Android 8.0 手机亮灭屏 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

本文主要跟蹤分析通過按松power鍵來喚醒,熄滅屏幕的邏輯。下面是一些相關類的介紹

PowerManagerService.java:簡稱PMS,負責Andorid系統中電源管理方面的工作。作為系統核心服務之一,主要處理系統中與power相關的計算,然后決策系統該如何反應。同時PowerManagerService與其他服務及HAL層等都有交互關系,協調power如何與系統其他模塊的交互,比如沒有用戶活動時屏幕變暗等。

DisplayPowerController.java:簡稱DPC管理Display設備的電源狀態。僅在PowerManagerService中實例化了一個對象,它算是PowerManagerService的一部分,只不過是獨立出來了而已。主要處理和距離傳感器,

燈光傳感器,以及包括關屏在內的一些動畫,通過異步回調的方式來通知PowerManagerService某些事情發生了變化。

DisplayPowerState.java:簡稱DPS,在本質上類似于View,只不過用來描述一個display的屬性,當這些屬性發生變化時,可以通過一個序列化的命令,讓這些和display電源狀態的屬性一起產生變化。

這個類的對象只能被DispalyPowerController的Looper持有。而這個Looper應該就是PowerManagerService中新建的一個HandlerThread中的Looper。和PowerManager相關的,

包括DisplayPowerState和DisplayPowerController相關的消息處理應該都可以通過這個HandlerThread進行運轉的

Notifier.java:將power狀態的重要變化,通過廣播發送出去,并且參與了與AMS,WMS,IMP的交互。

ColorFade.java:負責屏幕由關到開,由開到關的一些GL動畫,由DPC進行控制。

AutomaticBrightnessController.java:主要處理光傳感器,將底層上傳的參數進行處理計算,將計算的新的亮度值傳給DPC。

RampAnimator.java:處理屏幕亮度漸變動畫。

  • 代碼流程分析
  • Power事件上報跟蹤
  • 正常我們按下power鍵后,出觸發Kernel關于該事件的中斷。然后inputReader通過EventHub獲取該事件,并做出事件處理,之后由inputdispatch進行事件分發。

    因為power事件是key事件,會調用interceptKeyBeforeQueueing進行處理,通過如果流程

    InputDispatcher.cpp

    ? ->com_android_server_input_InputManagerService.cpp

    ????????? ->InputManagerService.java

    ?????????????????? ->InputMonitor.java

    ?????????????????????????? ->WindowManagerPolicy.java

    ??????????????????????????????????? ->PhoneWindowManager.java

  • PhoneWindowManager.java
  • 最終由PhoneWindowManager.java的interceptKeyBeforeQueueing方法對該次事件進行處理,對power鍵以及屏幕狀態進行判斷,來決定亮屏還是滅屏等操作。當需要亮屏時,會調用PowerMangerService中的wakeup函數進行處理。

    主要代碼如下:

    首先定義以下幾個布爾值,主要是按鍵屬性和屏幕狀態

    //是否亮屏狀態,代碼是否可以與用戶交互

    final boolean interactive = (policyFlags & FLAG_INTERACTIVE) != 0;

    //按鍵事件是否為down事件

    final boolean down = event.getAction() == KeyEvent.ACTION_DOWN;

    //事件是否被取消

    final boolean canceled = event.isCanceled();

    //按鍵的keycode,不同按鍵 keycode不同,一般power 116

    final int keyCode = event.getKeyCode();

    //是否是輸入事件

    final boolean isInjected = (policyFlags & WindowManagerPolicy.FLAG_INJECTED) != 0;

    //鎖屏界面狀態

    final boolean keyguardActive = (mKeyguardDelegate == null ? false :(interactive ?isKeyguardShowingAndNotOccluded() :mKeyguardDelegate.isShowing()));

    //flags有wake標記,或者按鍵(isWakeKey函數)為KEYCODE_BACK, KEYCODE_MENU, KEYCODE_WAKEUP, KEYCODE_PAIRING, KEYCODE_STEM_1, KEYCODE_STEM_2, KEYCODE_STEM_3設置isWakeKey為true

    boolean isWakeKey = (policyFlags & WindowManagerPolicy.FLAG_WAKE) != 0 || event.isWakeKey();

    ?

    ?

    if (isValidGlobalKey(keyCode)//有效的全局按鍵 (KEYCODE_POWER:KEYCODE_WAKEUP:KeyEvent.KEYCODE_SLEEP:),

    ????????? && mGlobalKeyManager.shouldHandleGlobalKey(keyCode, event)) {//在com.android.internal.R.xml.global_keys 有定義

    ? if (isWakeKey) {

    ????????? wakeUp(event.getEventTime(), mAllowTheaterModeWakeFromKey, "android.policy:KEY");喚醒屏幕

    ? }

    ? return result;

    }

    ?

    接下來是對特殊按鍵的處理,這里只關注power鍵

    ?switch (keyCode) {

    ? ?case KeyEvent.KEYCODE_POWER: {

    ????????? result &= ~ACTION_PASS_TO_USER;

    ????????? isWakeKey = false; // wake-up will be handled separately

    ????????? if (down) {

    ?????????????????? interceptPowerKeyDown(event, interactive);//處理power按下

    ????????? } else {

    ?????????????????? interceptPowerKeyUp(event, interactive, canceled);//處理power松開

    ????????? }

    ????????? break;

    ? }

    ?

    power down 鍵的處理

    private void interceptPowerKeyDown(KeyEvent event, boolean interactive) {

    ? // 獲取wakelock,報錯CPU喚醒狀態

    ? if (!mPowerKeyWakeLock.isHeld()) {

    ????????? mPowerKeyWakeLock.acquire();

    ? }

    ?

    ? // 取消多次按下超時監測

    ? if (mPowerKeyPressCounter != 0) {

    ????????? mHandler.removeMessages(MSG_POWER_DELAYED_PRESS);

    ? }

    ?

    ? // Detect user pressing the power button in panic when an application has

    ? // taken over the whole screen.

    boolean panic = mImmersiveModeConfirmation.onPowerKeyDown(interactive,

    ?????????????????? SystemClock.elapsedRealtime(), isImmersiveMode(mLastSystemUiFlags),

    ?????????????????? isNavBarEmpty(mLastSystemUiFlags));

    ? if (panic) {

    ????????? mHandler.post(mHiddenNavPanic);

    ? }

    ?

    ? // Latch power key state to detect screenshot chord.

    ? if (interactive && !mScreenshotChordPowerKeyTriggered

    ?????????????????? && (event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) {

    ????????? mScreenshotChordPowerKeyTriggered = true;

    ????????? mScreenshotChordPowerKeyTime = event.getDownTime();

    ????????? interceptScreenshotChord();//屏幕截屏

    ????????? interceptDisableTouchModeChord();? //添加口袋模式

    ? }

    ?

    ? // 當power鍵按下,停止電話響鈴或者結束通話

    ? TelecomManager telecomManager = getTelecommService();

    ? boolean hungUp = false;

    ? if (telecomManager != null) {

    ????????? if (telecomManager.isRinging()) {

    ?????????????????? 停止響鈴

    ?????????????????? telecomManager.silenceRinger();

    ????????? } else if ((mIncallPowerBehavior

    ?????????????????????????? & Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_HANGUP) != 0

    ?????????????????????????? && telecomManager.isInCall() && interactive) {

    ?????????????????? Setting數據庫讀取設置,如果開了掛斷電話

    ?????????????????? hungUp = telecomManager.endCall();

    ????????? }

    ? }

    ?

    ? SprdGestureLauncherService gestureService = LocalServices.getService(

    ?????????????????? SprdGestureLauncherService.class);

    ? boolean gesturedServiceIntercepted = false;

    ? if (gestureService != null) {

    ????????? gesturedServiceIntercepted = gestureService.interceptPowerKeyDown(event, interactive,

    ?????????????????????????? mTmpBoolean);

    ????????? if (mTmpBoolean.value && mGoingToSleep) {

    ?????????????????? mCameraGestureTriggeredDuringGoingToSleep = true;

    ????????? }

    ? }

    ?

    ? // If the power key has still not yet been handled, then detect short

    ? // 如果power鍵還沒有被處理,判斷是短按,多按,長按等場景并做出對應處理

    ? mPowerKeyHandled = hungUp || mScreenshotChordVolumeDownKeyTriggered

    ?????????????????? || mA11yShortcutChordVolumeUpKeyTriggered || gesturedServiceIntercepted;

    ? if (!mPowerKeyHandled) {

    ????????? if (interactive) {

    ?????????????????? //如果屏幕是亮的,長按動作處理對應的長按動作

    ?????????????????? if (hasLongPressOnPowerBehavior()) {

    ?????????????????????????? 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,//如果長按動作繼續執行長按操作

    ??????????????????????????????????? ??????? 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; //power鍵是否被處理了

    ? mScreenshotChordPowerKeyTriggered = false;

    ? cancelPendingScreenshotChordAction();

    ? cancelPendingPowerKeyAction();

    ?

    ? if (!handled) {

    ????????? // power press 加1

    ????????? mPowerKeyPressCounter += 1;

    ????????

    ????????? final int maxCount = getMaxMultiPressPowerCount();//多按的次數

    ????????? final long eventTime = event.getDownTime();//press power 時間

    ????????? if (mPowerKeyPressCounter < maxCount) {

    ?????????????????? // 這種情況可能是一個多次按鍵事件,等待一會做確認處理

    ?????????????????? Message msg = mHandler.obtainMessage(MSG_POWER_DELAYED_PRESS,

    ??????????????????????????????????? interactive ? 1 : 0, mPowerKeyPressCounter, eventTime);

    ?????????????????? msg.setAsynchronous(true);

    ?????????????????? mHandler.sendMessageDelayed(msg, ViewConfiguration.getDoubleTapTimeout());

    ?????????????????? return;

    ????????? }

    ?

    ????????? // 沒有其他action,繼續處理power按下事件

    ????????? powerPress(eventTime, interactive, mPowerKeyPressCounter);

    ? }

    ?

    ? // Done.? Reset our state.

    ? finishPowerKeyPress();//power按鍵處理結束

    }

    private void finishPowerKeyPress() {

    ? mBeganFromNonInteractive = false;

    ? mPowerKeyPressCounter = 0;

    ? if (mPowerKeyWakeLock.isHeld()) {

    ????????? mPowerKeyWakeLock.release();//釋放wakelock

    ? }

    }

    下面繼續跟蹤powerPress函數

    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) {//按兩次power事件

    ????????? powerMultiPressAction(eventTime, interactive, mDoublePressOnPowerBehavior);

    ? } else if (count == 3) {//按三次power事件

    ????????? powerMultiPressAction(eventTime, interactive, mTriplePressOnPowerBehavior);

    ? } else if (interactive && !mBeganFromNonInteractive) {//屏幕如果亮著而且mBeganFromNonInteractive為false會執行下面操作

    ????????? switch (mShortPressOnPowerBehavior) {//根據配置om.android.internal.R.integer.config_shortPressOnPowerBehavior 決定對應值 此處為1

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

    ?????????????????? ......

    }

    ?

    我們繼續跟蹤亮屏操作,從power down事件處理可知,調用wakeUpFromPowerKey點亮屏幕

    private void wakeUpFromPowerKey(long eventTime) {

    ? Slog.d(TAG, "wake Up From Power Key"); // 此處會打印這句log,可作為分析問題是注意點

    ? wakeUp(eventTime, mAllowTheaterModeWakeFromPowerKey, "android.policy:POWER");//調用wakeup繼續執行亮屏操作,注意調用mPowerManager.wakeUp操作

    }

  • PowerManager.wakeUp
  • 下面我們看下PowerManager.wakeUp的相關處理

    public void wakeUp(long time) {

    ? try {

    ????????? mService.wakeUp(time, "wakeUp", mContext.getOpPackageName());//調用到PWM.wakeUpInternal->PWM.wakeUpNoUpdateLocked

    ? } catch (RemoteException e) {

    ????????? throw e.rethrowFromSystemServer();

    ? }

    }

    ?

    當power接收到亮滅屏調用后,會先進行設置手機wakefullness狀態. 之后發送亮滅屏廣播通知其他應用手機處于亮屏還是滅屏狀態。

    private boolean wakeUpNoUpdateLocked(long eventTime, String reason, int reasonUid,

    ????????? String opPackageName, int opUid) {

    ? //mWakefulness標識系統當前狀態共有四種定義:

    ? WAKEFULNESS_ASLEEP:表示系統當前處于休眠狀態,只能被wakeUp()調用喚醒。

    ? WAKEFULNESS_AWAKE:表示系統目前處于正常運行狀態。

    ? WAKEFULNESS_DREAMING:表示系統當前正處于互動屏保的狀態。

    ? WAKEFULNESS_DOZING:表示系統正處于“doze”狀態

    ? if (eventTime < mLastSleepTime || mWakefulness == WAKEFULNESS_AWAKE

    ?????????????????? || !mBootCompleted || !mSystemReady) {//按鍵時間在睡下去之前,屏幕是正常狀態,沒有完成開機流程,系統沒有準備完成,這四種情況不繼續執行喚醒流程

    ????????? return false;

    ? }

    ?

    ? try {//系統不是點亮狀態,打出相關log

    ????????? switch (mWakefulness) {

    ?????????????????? case WAKEFULNESS_ASLEEP:

    ?????????????????? case WAKEFULNESS_DREAMING:

    ?????????????????? case WAKEFULNESS_DOZING:

    ?????????????????????????? Slog.i(TAG, "Waking up from dozing due to"+opPackageName+" "+reason+" (uid " + reasonUid +")...");

    ?????????????????????????? break;

    ????????? }

    ?

    ????????? mLastWakeTime = eventTime;//更新wake時間

    ????????? setWakefulnessLocked(WAKEFULNESS_AWAKE, 0);//更新mWakefulness,并調用Notifier.onWakefulnessChangeStarted發送亮屏廣播?

    ????????? mNotifier.onWakeUp(reason, reasonUid, opPackageName, opUid);//調用Notifier通知battery處理?

    ????????? userActivityNoUpdateLocked(eventTime, PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, reasonUid);//更新最后一次用戶事件的時間

    ? } finally {

    ? }

    ? return true;

    }

    ?

  • Notifier.java
  • 然后主要就是在Notifier.java中與AMS,window,input進行交互,通知各模塊手機狀態發生了改變,根據屏幕狀態各自進行處理, 最后發送亮滅屏廣播, 通知相關的模塊.

    private void setWakefulnessLocked(int wakefulness, int reason) {

    ? if (mWakefulness != wakefulness) {

    ????????? mWakefulness = wakefulness;//更新mWakefulness變量

    ????????? mWakefulnessChanging = true;

    ????????? mDirty |= DIRTY_WAKEFULNESS;

    ????????? mNotifier.onWakefulnessChangeStarted(wakefulness, reason);//調用Notify的函數onWakefulnessChangeStarted 發廣播通知

    ? }

    }

    public void onWakefulnessChangeStarted(final int wakefulness, int reason) {

    ??? //獲取交互模式變量,亮屏為true, 滅屏為false

    ? final boolean interactive = PowerManagerInternal.isInteractive(wakefulness);

    ?

    ? 通知AMS wakefulness狀態的變化

    ? mHandler.post(new Runnable() {

    ????????? @Override

    ????????? public void run() {

    ?????????????????? mActivityManagerInternal.onWakefulnessChanged(wakefulness);

    ????????? }

    ? });

    ?

    ? //interactive 變化時才會執行里面的邏輯

    ? if (mInteractive != interactive) {

    ????????? // Finish up late behaviors if needed.

    ????????? if (mInteractiveChanging) {

    ?????????????????? handleLateInteractiveChange();

    ????????? }

    ?

    ????????? //在input中記錄現在的屏幕狀態

    ????????? mInputManagerInternal.setInteractive(interactive);

    ????????? mInputMethodManagerInternal.setInteractive(interactive);

    ?

    ????????? //喚醒battery狀態

    ????????? try {

    ?????????????????? mBatteryStats.noteInteractive(interactive);

    ????????? } catch (RemoteException ex) { }

    ?

    ????????? // Handle early behaviors.

    ????????? mInteractive = interactive;

    ????????? mInteractiveChangeReason = reason;

    ????????? mInteractiveChanging = true;

    ????????? handleEarlyInteractiveChange();//處理交互模式改變

    ? }

    }

    ?

    private void handleEarlyInteractiveChange() {

    ? synchronized (mLock) {

    ????????? if (mInteractive) {//mInteractive 為true代表要執行亮屏邏輯

    ?????????????????? // Waking up...

    ?????????????????? mHandler.post(new Runnable() {

    ?????????????????????????? @Override

    ?????????????????????????? public void run() {

    ??????????????????????????????????? // Note a SCREEN tron event is logged in PowerManagerService.

    ??????????????????????????????????? mPolicy.startedWakingUp();//調用PhoneWindowManager 方法開始亮屏流程

    ?????????????????????????? }

    ?????????????????? });

    ?

    ?????????????????? // 更新亮屏廣播

    ?????????????????? mPendingInteractiveState = INTERACTIVE_STATE_AWAKE;

    ?????????????????? mPendingWakeUpBroadcast = true;

    ?????????????????? updatePendingBroadcastLocked();//mSuspendBlocker.acquire();持有partial 鎖

    ????????? } else {//mInteractive 為false代表要執行滅屏邏輯

    ?????????????????? final int why = translateOffReason(mInteractiveChangeReason);

    ?????????????????? mHandler.post(new Runnable() {

    ?????????????????????????? @Override

    ?????????????????????????? public void run() {

    ??????????????????????????????????? mPolicy.startedGoingToSleep(why);//調用PhoneWindowManager 方法開始滅屏流程

    ?????????????????????????? }

    ?????????????????? });

    ????????? }

    ? }

    }

    ?

  • 廣播更新的流程
  • 調用updatePendingBroadcastLocked函數發出handle msg 消息

    Message msg = mHandler.obtainMessage(MSG_BROADCAST);

    msg.setAsynchronous(true);

    mHandler.sendMessage(msg);

    然后handle收到后執行sendNextBroadcast函數

    case MSG_BROADCAST:

    ? sendNextBroadcast();

    ? break;

    private void sendNextBroadcast() {

    ? final int powerState;

    ? //mBroadcastedInteractiveState 這個變量記錄當前的系統亮滅屏情況

    ? synchronized (mLock) {

    ????????? if (mBroadcastedInteractiveState == INTERACTIVE_STATE_UNKNOWN) {

    ?????????????????? // 當前狀態位置更新為喚醒狀態

    ?????????????????? mPendingWakeUpBroadcast = false;

    ?????????????????? mBroadcastedInteractiveState = INTERACTIVE_STATE_AWAKE;

    ????????? } else if (mBroadcastedInteractiveState == INTERACTIVE_STATE_AWAKE) {

    ?????????????????? // 當前是喚醒狀態,更新為滅屏狀態

    ?????????????????? if (mPendingWakeUpBroadcast || mPendingGoToSleepBroadcast

    ??????????????????????????????????? || mPendingInteractiveState == INTERACTIVE_STATE_ASLEEP) {

    ?????????????????????????? mPendingGoToSleepBroadcast = false;

    ?????????????????????????? mBroadcastedInteractiveState = INTERACTIVE_STATE_ASLEEP;

    ?????????????????? } else {

    ?????????????????????????? finishPendingBroadcastLocked();//釋放partial 鎖

    ?????????????????????????? return;

    ?????????????????? }

    ????????? } else {

    ?????????????????? // 當前是滅屏狀態,更新為喚醒狀態

    ?????????????????? 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);//打出event log

    ?

    ? if (powerState == INTERACTIVE_STATE_AWAKE) {//根據powerState的值決定發亮屏還是滅屏廣播

    ????????? sendWakeUpBroadcast();

    ? } else {

    ????????? sendGoToSleepBroadcast();

    ? }

    }

    廣播都是前臺廣播,然后其他模塊收到廣播后作出對應處理

    mScreenOnIntent.addFlags(

    ? Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FOREGROUND

    ? | Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS);

    mScreenOffIntent.addFlags(

    ? Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FOREGROUND

    ? | Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS);

    Notify 收到這個廣播后會,繼續調用sendNextBroadcast,因為mPendingWakeUpBroadcast值變化,會調用finishPendingBroadcastLocked();釋放partial 鎖

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

    ? }

    };

    總結:當power接收到亮滅屏調用后,會先進行設置手機wakefullness狀態,之后發送亮滅屏廣播通知其他模塊手機處于亮屏還是滅屏狀態。并且在發送廣播過程中power也與AMS,window,input進行交互,通知各模塊手機狀態發生了改變,根據屏幕狀態各自進行處理。其中發送亮滅屏廣播的主要實現在Notifier.java中。

    當wakefulness狀態發生改變,AMS收到通知。如果亮屏操作,AMS就會通過函數comeOutOfSleepIfNeedLocked調用到ActivityStackSupervisor中,將sleep超時消息移除,最后將在棧頂的activity顯示出來。

    power是通過WindowManagerPolicy與PhoneWindowManager進行交互,當屏幕在喚醒時需要通知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

    ?????????????????? /* < Bug#696466 optimization for sceenoff */

    ?????????????????? if (wasPowered != mIsPowered)

    ?????????????????????????? SystemProperties.set("sys.sprd.power.ispowered", (mIsPowered? "1": "0"));//設置屬性sys.sprd.power.ispowered

    ?????????????????? /* Bug#696466 optimization for sceenoff > */

    ?????????????????? //無線充電

    ?????????????????? final boolean dockedOnWirelessCharger = mWirelessChargerDetector.update(

    ??????????????????????????????????? mIsPowered, mPlugType, mBatteryLevel);

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

    ?????????????????????????? mAutoLowPowerModeSnoozing = false;

    ?????????????????? }

    ?????????????????? updateLowPowerModeLocked();//更新低電模式

    ????????? }

    ? }

    }

    • 更新wakefulness

    for (;;) {

    ? int dirtyPhase1 = mDirty;

    ? dirtyPhase2 |= dirtyPhase1;

    ? mDirty = 0;

    ? updateWakeLockSummaryLocked(dirtyPhase1);

    ? updateUserActivitySummaryLocked(now, dirtyPhase1);

    ? if (!updateWakefulnessLocked(dirtyPhase1)) {

    ????????? break;

    ? }

    }

    updateWakeLockSummaryLocked函數將wakeLock的類型用mWakeLockSummary進行記錄,最后與Wakefulness狀態結合重新算出新的mWakeLockSummary值,再判斷是否需要睡眠時會使用。

    之后updateUserActivitySummaryLocked就會更新屏幕超時時間,根據最后一次的用戶事件與屏幕超時時間與dim持續時間來計算屏幕超時的時間,然后與現在的時間進行對比,來決定屏幕要繼續高亮,還是要變為dim狀態。

    PowerManagerHandler接收屏幕超時的消息, 并且調用handleUserActivityTimeout進行處理, 該函數之后就在Handler線程中運行

    ?

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

    }?

    [java] view plain copy

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

    }?

    [java] view plain copy

    ???? 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);?

    }?

    [java] view plain copy

    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鍵滅屏是也會調用該函數.

    ?

    [java] view plain copy

    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中,進行處理。

    在PowerManagerService中對各種狀態進行判斷后,將其數值封裝進DisplayPowerRequest中傳入DisplayPowerController中進一步處理。在亮屏過程中DisplayPowerController會根據傳過來的數值來設置新的電源狀態為亮屏,然后調用DisplayPowerState來對狀態進行設置。由于此時ColorFade level(就是在手機屏幕的一層surface,當level為0是為一層黑幀,level為1.0時為透明)的值為0,表示屏幕還沒有繪制好,所以此時需要block screen直到window界面繪制完成。當需要亮屏時調用PhoneWindowManager的screenTurningOn函數,通知window屏幕就要點亮了。然后調用WMS中函數waitForAllWindowsDrawn函數等待將所有需要繪制的window繪制完成后回調回來,超時時間為1000ms。在WMS中獲取需要繪制的window將其加入mWaitingForDrawn中等待繪制,通過檢查mWaitingForDrawn是否為空來判斷,window是否繪制完成。此時screenTurningOn函數就執行完了,剩下的就是等待windows繪制完成。

    總結

    以上是生活随笔為你收集整理的Android 8.0 手机亮灭屏的全部內容,希望文章能夠幫你解決所遇到的問題。

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