android電源鎖
1. Android 電源管理相關邏輯之PMS
PowerManagerService是負責管理、協調設備電源管理的系統服務之一,設備常見功能如亮滅屏、亮度調節、低電量模式、保持CPU喚醒等,都會通過PMS的協調和處理。其繼承自SystemService,因此具有SystemService子類的共性:具有生命周期方法,由SystemServer啟動、注冊到系統服務中,通過Binder和其他組件進行交互等。
和SystemService的其他子類一樣,PMS由SystemServer通過反射的方式啟動,看一下PMS的構造方法:
通過上面可以看到,在構造方法中首先創建了一個HandlerThread;其次獲取了兩個Suspend鎖,SuspendBlocker是一種鎖機制,只用於系統內部,上層申請的Wakelock鎖在PMS中都會反映為SuspendBlocker鎖。這里獲取的兩個Suspend鎖在申請Wakelock時會用到;最後調用了native方法,這幾個方法會通過JNI層調用到HAL層。
在該方法中,首先對該服務進行Binder注冊和本地注冊,當進行Binder注冊後,在其他模塊中就可以通過Binder機制獲取其實例,同理,當進行本地注冊後,只有在System進程才能獲取到其實例;最後設置Watchdog的監聽。
在這個方法中,設置mBootCompleted為true,表示啟動完成,將mDirty置位,mDirty是一個二進制的標記位,用來表示電源狀態哪一部分發生了改變,通過對其進行置位(|操作)、清零(~操作),得到二進制數各個位的值(0或1),進行不同的處理 ,然後執行updatePowerStateLocked()方法,這是整個PMS中最重要的方法,這塊會在下文中具體功能中進行詳細分析。
該方法內主要有5個重要功能 :
a.獲取各類本地服務和遠程服務,如屏保(DreamMangerService)、窗口(PhoneWindowManager)、電池狀態監聽服務(BatteryService)等服務,用於進行交互;
b.注冊用於和其他Sytem交互的廣播;
c.調用updateSettingsLocked()方法更新Settings中值的變化;
d.調用readConfigurationLocked()方法讀取配置文件中的默認值;
e.注冊SettingsObserver監聽;
當通過系統設置等進行屏幕亮度調節時,會調用到PMS內部的updatePowerStateLocked(),通過該方法進行接下來的邏輯執行,最終通過HAL層來設置屏幕亮度,本文基於 Android 8.1 版本進行分析:
當亮度調節時,處理邏輯主要是在phase 2,即updateDisplayPowerStateLocked(dirtyPhase2),一起看一下該方法:
該方法內部主要做了兩件事:
a.封裝DisplayPowerRequest實例mDisplayPowerRequest,包括通過
getDesiredScreenPolicyLocked()獲取policy,此處為DisplayPowerRequest. POLICY_BRIGHT ;還有screenBrightness等;
b.調用DisplayManagerInternal的requestPowerState(),上步封裝的DisplayPowerRequest作為參數傳入,mDisplayManagerInternal是在systemReady()內部獲取的;
DisplayManagerInternal內部的requestPowerState為抽象方法,因此會調用到實現類中,具體是在DisplayManagerService內部的LocalService,看一下具體實現:
最終會調用到DisplayPowerController內部的requestPowerState()方法:
在該方法內部先將傳入的DisplayPowerRequest對象賦值給mPendingRequestLocked,後續會使用;接著執行sendUpdatePowerStateLocked(),在該方法內部會發送非同步消息 MSG_UPDATE_POWER_STATE ,對應處理方法為updatePowerState();
該方法內部主要幹了6件事:
a.將要更新的DisplayPowerRequest實例賦值給mPowerRequest;
b.如果為首次執行的話,需要執行initialize()來執行初始化操作,創建DisplayPowerState實例mPowerState、RampAnimator實例mScreenBrightnessRampAnimator等;
c.根據mPowerRequest.policy來更新state,此處為Display. STATE_ON ;
d.執行animateScreenStateChange(state, performScreenOffTransition)來更新DisplayPowerState;
e.根據策略進行選擇,最終確定要更新的brightness值;
f.執行animateScreenBrightness(brightness,slowChange ? mBrightnessRampRateSlow : mBrightnessRampRateFast)來進行更新;
可以看到,在animateTo()內部會執行mProperty.setValue(mObject, target),mProperty對應的是
DisplayPowerState. SCREEN_BRIGHTNESS, mObject對應的是mPowerState,都是在DisplayPowerController內部的initialize()內部傳入的,接下來就進入了DisplayPowerState內部了 ;
scheleScreenUpdate()會執行到postScreenUpdateThreadSafe(),然後會post mScreenUpdateRunnable;
可以看到,在執行setState()後,最終會執行mBlanker.requestDisplayState(state, backlight),mBlanker是DisplayBlanker實例,初始化是在DisplayPowerController構造方法內,在DisplayPowerController內部的initialize()內部傳入的,根據調用關系會追溯到DisplayMangerService的LocalService的initPowerManagerment()方法,該方法是在PowerManagerService的systemReady()方法內執行的;
由於傳入的state為Display. STATE_ON ,執行到(state, brightness),根據調用關系最終會執行到updateDisplayStateLocked()獲取Runnable實例;
根據調用關系看到,會通過DisplayDevice的requestDisplayStateLocked()來獲取到Runnable;
在DisplayManagerService的onStart()內發送消息來執行registerDisplayAdapterLocked(new LocalDisplayAdapter())載入 BUILT_IN_DISPLAY_IDS_TO_SCAN對應 的LocalDisplayDevice(繼承DisplayDevice),載入成功後存入mDisplayDevices列表內進行管理;
在創建LocalDisplayDeivce時會通過lights.getLight(LightsManager. LIGHT_ID_BACKLIGHT )獲取mBackLight,對應的是LightsService內部的LightImpl繼承light;
在通過LocalDisplayDevice獲取到Runnable後接著執行run(),會執行到setDisplayBrightness();
在setDisplayBrightness()內部會執行到mBacklight.setBrightness(brightness),具體實現邏輯是在LightsService內部;
最終通過native方法調用到HAL層對屏幕的背光進行設置。
不同的調節方式對應不同的入口及判斷邏輯,只分析調用入口及涉及的關鍵策略來選擇最終目標brightness值邏輯;
系統設置在調節屏幕亮度時,會實時更新Settings. SCREEN_BRIGHTNESS 值,DisplayPowerController在監聽到該值變化後會執行handleSettingsChanged()方法:
監聽到變化後,先通過getScreenBrightnessSetting()來獲取到當前值,然後賦值給,接下來執行sendUpdatePowerState(),最終執行updatePowerState()方法:
結論:系統設置會根據的值來設置對應的目標brightness值;
快速設置來滑動進度條來調節屏幕亮度時,會調用PowerManagerService的()方法:
跟隨調用關系,調用到DisplayPowerController的setTemporaryBrightness()方法,發送 MSG_SET_TEMPORARY_BRIGHTNESS 消息,設置mTemporaryScreenBrightness為傳入的值,然後執行updatePowerState():
結論:快速設置會根據mTemporaryScreenBrightness的值來設置對應的目標brightness值;
在視頻播放界面可以通過左側上下滑動來調節屏幕亮度,具體實現方式如下:
Window是activity對應的Window,通過getWindow()可以得到,設置WindowManager.LayoutParams內部的screenBrightness後執行window.setAttributes(lp)可以來調節屏幕亮度;
Window執行setAttributes()會執行到Activity的onWindowAttributesChanged()方法,調用到WindowManagerGlobal的updateViewLayout()最終調用到ViewRootImpl的setLayoutParams來執行重新繪制;
繪制流程就不陳述了,最終會執行到RootWindowContainer內部的performSurfacePlacement()方法,接下來通過handleNotObscuredLocked()獲取到對應WindowState的w.mAttrs.screenBrightness賦值給mScreenBrightness,然後在performSurfacePlacement()發送 SET_SCREEN_BRIGHTNESS_OVERRIDE消息, 最終通過WindowManagerService來調用到PowerManagerService內部的()方法:
可以看到,在Internal()內部會將brightness賦值給,然後執行updatePowerStateLocked(),先看
updateDisplayPowerStateLocked()方法:
可以看到,screenBrightness會設置為,該值默認為-1,經過設置後screenBrightness>0,接著執行到DisplayPowerController的updatePowerState()方法:
結論:Window屬性調節會根據的值來設置對應的目標brightness值;
設置屏幕亮度時,主要是在DisplayPowerController內部的 updatePowerState() 來對目標screenBrightness進行設置,screenBrightness默認值為PowerManager.BRIGHTNESS_DEFAULT = -1,會根據DisplayPowerRequest及其他策略進行選擇,順序依次為:
a.if (brightness < 0 && mPowerRequest.screenBrightness >= 0): 通過設置Window屬性來進行調節(視頻播放界面)
b.if (mTemporaryScreenBrightness > 0): 通過快速設置滑動來進行調節
c.if (brightness < 0) {brightness = clampScreenBrightness()}: 通過系統設置滑動調節
當系統設置內部設置了自動進入屏保時間後,如果在此段時間後滿足進入條件,會進入屏保,該邏輯入口是在PMS內部的updatePowerStateLocked(),一起看一下:
本流程只分析滿足條件後進入屏保的整個過程,關於條件判斷會在下一節中進行分析,先從updatePowerStateLocked()看起:
在該方法內部首先循環執行了三個方法:
a.updateWakeLockSummaryLocked():根據mWakeLocks來計算得到mWakeLockSummary的值;
b.():計算得到mUserActivitySummary以及何時進行下一次check;
c.updateWakefulnessLocked():判斷是否可以進入屏保及更新mWakefulness狀態;
d.updateDreamLocked():根據當前狀態選擇是否進入屏保;
當mWakefulness為 WAKEFULNESS_AWAKE 時,且isItBedTimeYetLocked(),即:副駕滿足進入屏保的條件,看一下該方法的邏輯:
當滿足以上條件後,執行napNoUpdateLocked():
設置mSandmanSummoned為true,更新當前mWakefulness狀態 WAKEFULNESS_DREAMING ,最後返回true;
前面的循環中當結果返回true時,會執行下一次循環,重新計算mWakeLockSummary和mUserActivitySummary,最終返回false,執行break退出循環,執行updateDreamLocked();
滿足條件後執行scheleSandmanLocked()來發送非同步消息,執行handleSandman(),mDisplayReady是在updateDisplayPowerStateLocked()內部最終通過DisplayPowerController內部返回的;
在handleSandman()先進行判斷,滿足條件後即startDreaming為true時,執行stopDream()、startDream(),接下來再執行wakeUpNoUpdateLocked(),一起看一下該方法的實現:
將mWakefulness更新為 WAKEFULNESS_AWAKE ;然後再執行 userActivityNoUpdateLocked()來更新user activity相關信息,接著上面進行分析,執行startDream()進入屏保;
在startDream()邏輯執行過程中首先獲取到本地屏保實現的ComponentName,通過在core/res/res/values/config.xml內進行配置:
接下來最終通過DreamController的startDream()來啟動;
可以看到在startDream()內部通過bindService()來啟動本地實現的屏保服務SevenDreamService;
2. 安卓系統被鎖定,如何才能開啟
方法如下:
1、將手機關機,長按【音量+】鍵、【home】鍵和【開關】鍵,等到屏幕亮之後,松開【開關鍵】,直到recovery界面出現。
(2)android電源鎖擴展閱讀:
Recovery是Android手機備份功能,指的是一種可以對安卓機內部的數據或系統進行修改的模式。在這個模式下我們可以,對已有的系統進行備份或升級,也可以在此恢復出廠設置。
刷入第三方的Recovery,將獲得更多的功能,並且可以刷入第三方rom,官方自帶則不行。