·??深入分析PowerManagerService
·??深入分析BatteryService和BatteryStatsService
·??PowerManagerService.java
frameworks/base/services/java/com/android/server/PowerManagerService.java
·??com_android_server_PowerManagerService.cpp
frameworks/base/services/jni/com_android_server_PowerManagerService.cpp
·??PowerManager.java
frameworks/base/core/java/android/os/PowerManager.java
·??WorkSoure.java
frameworks/base/core/java/android/os/WorkSoure.java
·??Power.java
frameworks/base/core/java/android/os/Power.java
·??android_os_Power.cpp
frameworks/base/core/jni/android_os_Power.cpp
·??com_android_server_InputManager.cpp
frameworks/base/services/jni/com_android_server_InputManager.cpp
·??LightService.java
frameworks/base/services/java/com/android/server/LightService.java
·??com_android_server_LightService.cpp
frameworks/base/services/jni/com_android_server_LightService.cpp
·??BatteryService.java
frameworks/base/services/java/com/android/server/BatteryService.java
·??com_android_server_BatteryService.cpp
frameworks/base/services/jni/com_android_server_BatteryService.cpp
·??ActivityManagerService.java
frameworks/base/services/java/com/android/server/am/ActivityManagerService.java
·??BatteryStatsService.java
frameworks/base/services/java/com/android/server/am/BatteryStatsService.java
·??BatteryStatsImpl.java
frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
·??LocalPowerManager.java
frameworks/base/core/java/android/os/LocalPowerManager.java
PowerManagerService負(fù)責(zé)Andorid系統(tǒng)中電源管理方面的工作。作為系統(tǒng)核心服務(wù)之一,PowerManagerService與其他服務(wù)及HAL層等都有交互關(guān)系,所以PowerManagerService相對(duì)PackageManager來(lái)說(shuō),其社會(huì)關(guān)系更復(fù)雜,分析難度也會(huì)更大一些。
先來(lái)看直接與PowerManagerService有關(guān)的類家族成員,如圖5-1所示
http://wiki.jikexueyuan.com/project/deep-android-v2/images/chapter5/image001.png" alt="image" />
圖5-1? PowerManagerService及相關(guān)類家族
由圖5-1可知:
·??PowerManagerService從IPowerManager.Stub類派生,并實(shí)現(xiàn)了Watchdog.Monitor及LocalPowerManager接口。PowerManagerService內(nèi)部定義了較多的成員變量,在后續(xù)分析中,我們會(huì)對(duì)其中比較重要的成員逐一進(jìn)行介紹。
·??根據(jù)第4章介紹的知識(shí),IPowerManager.Stub及內(nèi)部類Proxy均由aidl工具處理PowerManager.aidl后得到。
·??客戶端使用PowerManager類,其內(nèi)部通過(guò)代表BinderProxy端的mService成員變量與PowerManagerService進(jìn)行跨Binder通信。
現(xiàn)在開(kāi)始PowerManagerService(以后簡(jiǎn)寫為PMS)的分析之旅,先從它的調(diào)用流程入手。
提示PMS和BatteryService、BatteryStatsService均有交互關(guān)系,這些內(nèi)容放在后面分析。
PMS由SystemServer在ServerThread線程中創(chuàng)建。這里從中提取了4個(gè)關(guān)鍵調(diào)用點(diǎn),如下所示:
[-->SystemServer.java]
??? ......//ServerThread的run函數(shù)
??? power =new PowerManagerService();//①創(chuàng)建PMS對(duì)象
???ServiceManager.addService(Context.POWER_SERVICE, power);//注冊(cè)到SM中
?? ......
?? //②調(diào)用PMS的init函數(shù)
?? power.init(context,lights, ActivityManagerService.self(), battery);
?? ......//其他服務(wù)
?? power.systemReady();//③調(diào)用PMS的systemReady
?? ......//系統(tǒng)啟動(dòng)完畢,會(huì)收到ACTION_BOOT_COMPLETED廣播
?? //④PMS處理ACTION_BOOT_COMPLETED廣播
先從第一個(gè)關(guān)鍵點(diǎn)即PMS的構(gòu)造函數(shù)開(kāi)始分析。
PMS構(gòu)造函數(shù)的代碼如下:
[-->PowerManagerService.java::構(gòu)造函數(shù)]
PowerManagerService() {
??? longtoken = Binder.clearCallingIdentity();
??? MY_UID =Process.myUid();//取本進(jìn)程(即SystemServer)的uid及pid
??? MY_PID =Process.myPid();
???Binder.restoreCallingIdentity(token);
??? //設(shè)置超時(shí)時(shí)間為1周。Power類封裝了同Linux內(nèi)核交互的接口。本章最后再來(lái)分析它
???Power.setLastUserActivityTimeout(7*24*3600*1000);
??? //初始化兩個(gè)狀態(tài)變量,它們非常有意義。其具體作用后續(xù)再分析
??? mUserState= mPowerState = 0;
??? //將自己添加到看門狗的監(jiān)控管理隊(duì)列中
?? Watchdog.getInstance().addMonitor(this);
?}
PMS的構(gòu)造函數(shù)比較簡(jiǎn)單。值得注意的是mUserState和mPowerState兩個(gè)成員,至于它們的具體作用,后續(xù)分析時(shí)自會(huì)知曉。
下面分析第二個(gè)關(guān)鍵點(diǎn)。
第二個(gè)關(guān)鍵點(diǎn)是init函數(shù),該函數(shù)將初始化PMS內(nèi)部的一些重要成員變量,由于此函數(shù)代碼較長(zhǎng),此處將分段討論。
從流程角度看,init大體可分為三段。
[-->PowerManagerService.java::init函數(shù)]
void init(Context context, LightsService lights,IActivityManager activity,
????????? ??????????????????BatteryService battery) {
?? //①保存幾個(gè)成員變量
??mLightsService = lights;//保存LightService
?? mContext= context;
??mActivityService = activity;//保存ActivityManagerService
?? //保存BatteryStatsService
??mBatteryStats = BatteryStatsService.getService();//
??mBatteryService = battery;//保存BatteryService
?? //從LightService中獲取代表不同硬件Light的Light對(duì)象
?? mLcdLight= lights.getLight(LightsService.LIGHT_ID_BACKLIGHT);
??mButtonLight = lights.getLight(LightsService.LIGHT_ID_BUTTONS);
??mKeyboardLight = lights.getLight(LightsService.LIGHT_ID_KEYBOARD);
??mAttentionLight = lights.getLight(LightsService.LIGHT_ID_ATTENTION);
?? //②調(diào)用nativeInit函數(shù)
??nativeInit();
??synchronized (mLocks) {
?????updateNativePowerStateLocked();//③更新Native層的電源狀態(tài)
? }
第一階段工作可分為三步:
·??對(duì)一些成員變量進(jìn)行賦值。
·??調(diào)用nativeInit函數(shù)初始化Native層相關(guān)資源。
·??調(diào)用updateNativePowerStateLocked更新Native層的電源狀態(tài)。這個(gè)函數(shù)的調(diào)用次數(shù)較為頻繁,以后續(xù)分析時(shí)討論。
先來(lái)看第一階段出現(xiàn)的各類成員變量,如表5-1所示。
表5-1? 成員變量說(shuō)明
成員變量名 |
數(shù)據(jù)類型 |
作用 |
mLightsService |
LightsService |
和LightsService交互用 |
mActivityService |
IActivityManager |
和ActivityManagerService交互 |
mBatteryStats |
IBatteryStats |
和BatteryStatsService交互,用于系統(tǒng)耗電量統(tǒng)計(jì)方面的工作 |
mBatteryService |
BatteryService |
用于獲取電源狀態(tài),例如是否為低電狀態(tài)、查詢電池電量等 |
mLcdLight、mButtonLight、 mKeyboardLight、mAttentionLight |
LightsService.Light |
由PMS控制,在不同狀態(tài)下點(diǎn)亮或熄滅它們 |
下面來(lái)看nativeInit函數(shù),其JNI層實(shí)現(xiàn)代碼如下:
[-->com_android_server_PowerManagerService.cpp]
static void android_server_PowerManagerService_nativeInit(JNIEnv*env,
???????????????????????????? jobject obj) {
??? //非常簡(jiǎn)單,就是創(chuàng)建一個(gè)全局引用對(duì)象gPowerManagerServiceObj
???gPowerManagerServiceObj = env->NewGlobalRef(obj);
}
init第一階段工作比較簡(jiǎn)單,下面進(jìn)入第二階段的分析。
init第二階段工作將創(chuàng)建兩個(gè)HandlerThread對(duì)象,即創(chuàng)建兩個(gè)帶消息循環(huán)的工作線程。PMS本身由ServerThread線程創(chuàng)建,并且將自己的工作委托給這兩個(gè)線程,它們分別是:
·??mScreenOffThread:按Power鍵關(guān)閉屏幕時(shí),屏幕不是突然變黑的,而是一個(gè)漸暗的過(guò)程。mScreenOffThread線程就用于控制關(guān)屏過(guò)程中的亮度調(diào)節(jié)。
·??mHandlerThread:該線程是PMS的主要工作線程。
先來(lái)看這兩個(gè)線程的創(chuàng)建。
[-->PowerManagerService.java::init函數(shù)]
......
?mScreenOffThread= new HandlerThread("PowerManagerService.mScreenOffThread") {
?? protected void onLooperPrepared() {
??mScreenOffHandler = new Handler();//向這個(gè)handler發(fā)送的消息,將由此線程處理
?? synchronized (mScreenOffThread) {
?? ???mInitComplete = true;
?? ???mScreenOffThread.notifyAll();
??? ??}
?? ?}
?? };
?mScreenOffThread.start();//創(chuàng)建對(duì)應(yīng)的工作線程
?synchronized (mScreenOffThread) {
??? while(!mInitComplete) {
?????? try {//等待mScreenOffThread線程創(chuàng)建完成
?????????????mScreenOffThread.wait();
??????? } ......
?????? }
??? }
注意,在Android代碼中經(jīng)常出現(xiàn)“線程A創(chuàng)建線程B,然后線程A等待線程B創(chuàng)建完成”的情況,讀者了解它們的作用即可。接著看以下代碼。
[-->PowerManagerService.java::init函數(shù)]
?? mInitComplete= false;
?? //創(chuàng)建 mHandlerThread
??mHandlerThread = new HandlerThread("PowerManagerService") {
?? protectedvoid onLooperPrepared() {
??????super.onLooperPrepared();
??????initInThread();//①初始化另外一些成員變量
???? }
?? };
?mHandlerThread.start();
??????? ......//等待mHandlerThread創(chuàng)建完成
由于mHandlerThread承擔(dān)了PMS的主要工作任務(wù),因此需要先做一些初始化工作,相關(guān)的代碼在initInThread中,擬放在單獨(dú)一節(jié)中進(jìn)行討論。
initInThread本身比較簡(jiǎn)單,涉及三個(gè)方面的工作,總結(jié)如下:
·??PMS需要了解外面的世界,所以它會(huì)注冊(cè)一些廣播接收對(duì)象,接收諸如啟動(dòng)完畢、電池狀態(tài)變化等廣播。
·??PMS所從事的電源管理工作需要遵守一定的規(guī)則,而這些規(guī)則在代碼中就是一些配置參數(shù),這些配置參數(shù)的值可以是固定寫死的(編譯完后就無(wú)法改動(dòng)),也可以是經(jīng)由Settings數(shù)據(jù)庫(kù)動(dòng)態(tài)設(shè)定的。
·??PMS需要對(duì)外發(fā)出一些通知,例如屏幕關(guān)閉/屏幕開(kāi)啟。
了解initInThread的概貌后,再來(lái)看如下代碼。
[-->PowerManagerService.java::initInThread]
void initInThread() {
?? mHandler= new Handler();
? ?//PMS內(nèi)部也需要使用WakeLock,此處定義了幾種不同的UnsynchronizedWakeLock。它們的
? ?//作用見(jiàn)后文分析
? ?mBroadcastWakeLock = newUnsynchronizedWakeLock(
??????????????PowerManager.PARTIAL_WAKE_LOCK, "sleep_broadcast", true);
? ?//創(chuàng)建廣播通知的Intent,用于通知SCREEN_ON和SCREEN_OFF消息
??mScreenOnIntent = new Intent(Intent.ACTION_SCREEN_ON);
??mScreenOnIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
??mScreenOffIntent = new Intent(Intent.ACTION_SCREEN_OFF);
??mScreenOffIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
?
?? //取配置參數(shù),這些參數(shù)是編譯時(shí)確定的,運(yùn)行過(guò)程中無(wú)法修改
?? Resourcesresources = mContext.getResources();
??mAnimateScreenLights = resources.getBoolean(
???????????????com.android.internal.R.bool.config_animateScreenLights);
??????? ......//見(jiàn)下文的配置參數(shù)匯總
??????? //通過(guò)數(shù)據(jù)庫(kù)設(shè)置的配置參數(shù)
? ?ContentResolver resolver =mContext.getContentResolver();
? ?Cursor settingsCursor =resolver.query(Settings.System.CONTENT_URI, null,
???????????????......//設(shè)置查詢條件和查詢項(xiàng)的名字,見(jiàn)后文的配置參數(shù)匯總
???????????????null);
? ?//ContentQueryMap是一個(gè)常用類,簡(jiǎn)化了數(shù)據(jù)庫(kù)查詢工作。讀者可參考SDK中該類的說(shuō)明文檔
?? mSettings= new ContentQueryMap(settingsCursor, Settings.System.NAME,
???????????????????????????? ??????true, mHandler);
?? //監(jiān)視上邊創(chuàng)建的ContentQueryMap中內(nèi)容的變化
??SettingsObserver settingsObserver = new SettingsObserver();
? ?mSettings.addObserver(settingsObserver);
? ?settingsObserver.update(mSettings, null);
?? //注冊(cè)接收通知的BroadcastReceiver
??IntentFilter filter = new IntentFilter();
??filter.addAction(Intent.ACTION_BATTERY_CHANGED);
??mContext.registerReceiver(new BatteryReceiver(), filter);
?? filter =new IntentFilter();
??filter.addAction(Intent.ACTION_BOOT_COMPLETED);
??mContext.registerReceiver(new BootCompletedReceiver(), filter);
?? filter =new IntentFilter();
??filter.addAction(Intent.ACTION_DOCK_EVENT);
??mContext.registerReceiver(new DockReceiver(), filter);
??? //監(jiān)視Settings數(shù)據(jù)中secure表的變化
??mContext.getContentResolver().registerContentObserver(
??? ????????Settings.Secure.CONTENT_URI, true,
???????????new ContentObserver(new Handler()) {
???????????????public void onChange(boolean selfChange) {
???????????????????updateSettingsValues();
???????????????}
???????????});
? ?updateSettingsValues();
??? ......//通知其他線程
?}
在上述代碼中,很大一部分用于獲取配置參數(shù)。同時(shí),對(duì)于數(shù)據(jù)庫(kù)中的配置值,還需要建立監(jiān)測(cè)機(jī)制,細(xì)節(jié)部分請(qǐng)讀者自己閱讀相關(guān)代碼,這里總結(jié)一下常用的配置參數(shù),如表5-2所示。
表5-2? PMS使用的配置參數(shù)
參數(shù)名:類型 |
來(lái)源 |
備注 |
mAnimateScreenLights:bool |
config.xml[①] |
關(guān)屏?xí)r屏幕光是否漸暗,默認(rèn)為true |
mUnplugTurnsOnScreen:bool |
config.xml |
拔掉USB線,是否點(diǎn)亮屏幕 |
mScreenBrightnessDim:int |
config.xml |
PMS可設(shè)置的屏幕亮度的最小值,默認(rèn)20(單位lx) |
mUseSoftwareAutoBrightness:bool |
config.xml |
是否啟用Setting中的亮度自動(dòng)調(diào)節(jié),如果硬件不支持該功能,則可由軟件控制。默認(rèn)為false |
mAutoBrightnessLevels:int[] mLcdBacklightValues:int[] ...... |
config.xml,具體值由硬件廠商定義 |
當(dāng)使用軟件自動(dòng)亮度調(diào)節(jié)時(shí),需配置不同亮度時(shí)對(duì)應(yīng)的參數(shù) |
STAY_ON_WHILE_PLUGGED_IN:int |
Settings.db |
插入U(xiǎn)SB時(shí)是否保持喚醒狀態(tài) |
SCREEN_OFF_TIMEOUT:int |
Settings.db |
屏幕超時(shí)時(shí)間 |
DIM_SCREEN:int |
Settings.db |
是否變暗(dim)屏幕 |
SCREEN_BRIGHTNESS_MODE:int |
Settings.db |
屏幕亮度模式(自動(dòng)還是手動(dòng)調(diào)節(jié)) |
除了獲取配置參數(shù)外,initInThread還創(chuàng)建了好幾個(gè)UnsynchronizedWakeLock對(duì)象,它的作用是:在Android系統(tǒng)中,為了搶占電力資源,客戶端要使用WakeLock對(duì)象。PMS自己也不例外,所以為了保證在工作中不至于突然掉電(當(dāng)其他客戶端都不使用WakeLock的時(shí)候,這種情況理論上是有可能發(fā)生的),PMS需要定義供自己使用的WakeLock。由于線程同步方面的原因,PMS封裝了一個(gè)UnsynchronizedWakeLock結(jié)構(gòu),它的調(diào)用已經(jīng)處于鎖保護(hù)下,所以在內(nèi)部無(wú)需再做同步處理。UnsynchronizedWakeLock比較簡(jiǎn)單,因此不再贅述。
下面來(lái)看init第三階段的工作。
[-->PowerManagerService.java::init函數(shù)]
??nativeInit();//不知道此處為何還要調(diào)用一次nativeInit,筆者懷疑此處為bug
??synchronized (mLocks) {
?? ??updateNativePowerStateLocked();//更新native層power狀態(tài),以后分析
??? ?forceUserActivityLocked();//強(qiáng)制觸發(fā)一次用戶事件
????mInitialized = true;
?}//init函數(shù)完畢
forceUserActivityLocked表示強(qiáng)制觸發(fā)一次用戶事件。這個(gè)解釋是否會(huì)讓讀者丈二和尚摸不著頭?先來(lái)看它的代碼:
[-->PowerManagerService.java:: forceUserActivityLocked]
private void forceUserActivityLocked() {
?? if(isScreenTurningOffLocked()) {
????mScreenBrightness.animating = false;
? }
? ?boolean savedActivityAllowed =mUserActivityAllowed;
??mUserActivityAllowed = true;
? //下面這個(gè)函數(shù)以后會(huì)分析, SDK中有對(duì)應(yīng)的API
??userActivity(SystemClock.uptimeMillis(), false);
?? mUserActivityAllowed= savedActivityAllowed;
?}
forceUserActivityLocked內(nèi)部就是為調(diào)用userActivity掃清一切障礙。對(duì)于SDK中PowerManager.userActivity的說(shuō)明文檔“User activity happened.Turnsthe device from whatever state it's in to full on, and resets the auto-offtimer.”簡(jiǎn)單翻譯過(guò)來(lái)是:調(diào)用此函數(shù)后,手機(jī)將被喚醒。屏幕超時(shí)時(shí)間將重新計(jì)算。
userActivity是PMS中很重要的一個(gè)函數(shù),本章后面將對(duì)其進(jìn)行詳細(xì)分析。
PMS的init函數(shù)比較簡(jiǎn)單,但是其眾多的成員變量讓人感到有點(diǎn)頭暈。讀者自行閱讀代碼時(shí),不妨參考表5-1和表5-2。
下面來(lái)分析PMS第三階段的工作。此時(shí)系統(tǒng)中大部分服務(wù)都已創(chuàng)建好,即將進(jìn)入就緒階段。就緒階段的工作在systemReady中完成,代碼如下:
[-->PowerManagerService.java::systemReady]
void systemReady() {
? /*
? 創(chuàng)建一個(gè)SensorManager,用于和系統(tǒng)中的傳感器系統(tǒng)交互,由于該部分涉及較多的native層
? 代碼,因此將相關(guān)內(nèi)容放到本書后續(xù)章節(jié)進(jìn)行討論
? */
?mSensorManager = new SensorManager(mHandlerThread.getLooper());
?mProximitySensor = mSensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY);
? if(mUseSoftwareAutoBrightness) {
???? ?mLightSensor =mSensorManager.getDefaultSensor(Sensor.TYPE_LIGHT);
? }
? if(mUseSoftwareAutoBrightness) {
?????setPowerState(SCREEN_BRIGHT);
??? } else {//不考慮軟件自動(dòng)亮度調(diào)節(jié),所以執(zhí)行下面這個(gè)分支
???setPowerState(ALL_BRIGHT);//設(shè)置手機(jī)電源狀態(tài)為ALL_BRIGHT,即屏幕、按鍵燈都打開(kāi)
?}
?synchronized (mLocks) {
?mDoneBooting = true;
? //根據(jù)情況啟用LightSensor
?enableLightSensorLocked(mUseSoftwareAutoBrightness&&mAutoBrightessEnabled);
? longidentity = Binder.clearCallingIdentity();
? try {//通知BatteryStatsService,它將統(tǒng)計(jì)相關(guān)的電量使用情況,后續(xù)再分析它
? ??mBatteryStats.noteScreenBrightness(getPreferredBrightness());
?? ?mBatteryStats.noteScreenOn();
? }......
}
systemReady主要工作為:
·??PMS創(chuàng)建SensorManager,通過(guò)它可與對(duì)應(yīng)的傳感器交互。關(guān)于Android傳感器系統(tǒng),將放到本書后續(xù)章節(jié)討論。PMS僅僅啟用或禁止特定的傳感器,而來(lái)自傳感器的數(shù)據(jù)將通過(guò)回調(diào)的方式通知PMS,PMS根據(jù)接收到的傳感器事件做相應(yīng)處理。
·??通過(guò)setPowerState函數(shù)設(shè)置電源狀態(tài)為ALL_BRIGHT(不考慮UseSoftwareAutoBrightness的情況)。此時(shí)屏幕及鍵盤燈都會(huì)點(diǎn)亮。關(guān)于setPowrState函數(shù),后文再做詳細(xì)分析。
·??調(diào)用BatteryStatsService提供的函數(shù),以通知屏幕打開(kāi)事件,在BatteryStatsService內(nèi)部將處理該事件。稍后,本章將詳細(xì)討論BatteryStatsService的功能。
當(dāng)系統(tǒng)中的服務(wù)都在systemReady中進(jìn)行處理后,系統(tǒng)會(huì)廣播一次ACTION_BOOT_COMPLETED消息,而PMS也將處理該廣播,下面來(lái)分析。
[-->PowerManagerService.java::BootCompletedReceiver]
private final class BootCompletedReceiver extendsBroadcastReceiver {
? publicvoid onReceive(Context context, Intent intent) {
??bootCompleted();//調(diào)用PMS的bootCompleted函數(shù)
? }
}
[-->PowerManagerService.java::bootCompleted函數(shù)]
void bootCompleted() {
?
?synchronized (mLocks) {
??mBootCompleted = true;
?? //再次碰見(jiàn)userActivity,根據(jù)前面的描述,此時(shí)將重新計(jì)算屏幕超時(shí)時(shí)間
??userActivity(SystemClock.uptimeMillis(), false, BUTTON_EVENT, true);
??updateWakeLockLocked();//此處先分析這個(gè)函數(shù)
??mLocks.notifyAll();
?? }
?}
在以上代碼中,再一次遇見(jiàn)了userActivity,暫且對(duì)其置之不理。先分析updateWakeLockLocked函數(shù),其代碼如下:
private void updateWakeLockLocked() {
? /*
? ??mStayOnConditions用于控制當(dāng)插上USB時(shí),手機(jī)是否保持喚醒狀態(tài)。
? ??mBatteryService的isPowered用于判斷當(dāng)前是否處于USB充電狀態(tài)。
? ??如果滿足下面的if條件滿,則PMS需要使用wakeLock來(lái)確保系統(tǒng)不會(huì)掉電
? */
? if(mStayOnConditions != 0 &&mBatteryService.isPowered(mStayOnConditions)) {
?????mStayOnWhilePluggedInScreenDimLock.acquire();
?????mStayOnWhilePluggedInPartialLock.acquire();
? } else {
????? //如果不滿足if條件,則釋放對(duì)應(yīng)的wakeLock,這樣系統(tǒng)就可以進(jìn)入休眠狀態(tài)
?????mStayOnWhilePluggedInScreenDimLock.release();
?????mStayOnWhilePluggedInPartialLock.release();
? }
}
mStayOnWhilePluggedInScreenDimLock和mStayOnWhilePluggedInPartialLock都為UnsynchronizedWakeLock類型,它們封裝了WakeLock,可幫助PMS在使用它們時(shí)免遭線程同步之苦。
這一節(jié)向讀者展示了PMS的大體面貌,包括:
·??主要的成員變量及它們的作用和來(lái)歷。如有需要,可查閱表5-1和5-2。
·??見(jiàn)識(shí)了PMS中幾個(gè)主要的函數(shù),其中有一些將留到后文進(jìn)行深入分析,現(xiàn)在只需要了解其大概作用即可。
WakeLock是Android提供給應(yīng)用程序獲取電力資源的唯一方法。只要還有地方在使用WakeLock,系統(tǒng)就不會(huì)進(jìn)入休眠狀態(tài)。
WakeLock的一般使用方法如下:
PowerManager pm = (PowerManager)getSystemService(Context.POWER_SERVICE);
?//①創(chuàng)建一個(gè)WakeLock,注意它的參數(shù)
?PowerManager.WakeLock wl =pm.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK,
????????????????????????????????????????????? "MyTag");
?wl.acquire();//②獲取該鎖
?? ......//工作
?wl.release();//③釋放該鎖
以上代碼中共列出三個(gè)關(guān)鍵點(diǎn),本章將分析前兩個(gè)(在此基礎(chǔ)上,讀者可自行分析release函數(shù))。
這3個(gè)函數(shù)都由PMS的Binder客戶端的PowerManager使用,所以將本次分析劃分為客戶端和服務(wù)端兩大部分。
?
通過(guò)PowerManager(以后簡(jiǎn)稱PM)的newWakeLock將創(chuàng)建一個(gè)WakeLock,代碼如下:
public WakeLock newWakeLock(int flags, String tag)
{
??//tag不能為null,否則拋異常
??return new WakeLock(flags, tag);//WakeLock為PM的內(nèi)部類,第一個(gè)參數(shù)flags很關(guān)鍵
?}
WakeLock的第一個(gè)參數(shù)flags很關(guān)鍵,它用于控制CPU/Screen/Keyboard的休眠狀態(tài)。flags的可選值如表5-3所示。
表5-3? WakeLock 的flags參數(shù)說(shuō)明
flags值 |
CPU |
Screen |
Keyboard |
備注 |
PARTIAL_WAKE_LOCK |
On |
Off |
Off |
不受電源鍵影響 |
SCREEN_DIM_WAKE_LOCK |
On |
Dim |
Off |
按下電源鍵后,系統(tǒng)還是會(huì)進(jìn)入休眠狀態(tài) |
SCREEN_BRIGHT_WAKE_LOCK |
On |
Bright |
Off |
|
FULL_WAKE_LOCK |
On |
Bright |
On |
|
ACQUIRE_CAUSES_WAKEUP |
說(shuō)明:在正常情況下,獲取WakeLock并不會(huì)喚醒機(jī)器(例如acquire之前機(jī)器處于關(guān)屏狀態(tài),則無(wú)法喚醒)。加上該標(biāo)志后,acquire WakeLock同時(shí)也能喚醒機(jī)器(即點(diǎn)亮屏幕等)。該標(biāo)志常用于提示框、來(lái)電提醒等應(yīng)用場(chǎng)景 |
|||
ON_AFTER_RELEASE |
說(shuō)明:和用戶體驗(yàn)有關(guān),當(dāng)WakeLock釋放后,如沒(méi)有該標(biāo)志,系統(tǒng)會(huì)立即黑屏。有了該標(biāo)志,系統(tǒng)會(huì)延時(shí)一段時(shí)間再黑屏 |
由表5-3可知:
·??WakeLock只控制CPU、屏幕和鍵盤三大部分。
·??表中最后兩項(xiàng)是附加標(biāo)志,和前面的其他WAKE_LOCK標(biāo)志組合使用。注意, PARTIAL_WAKE_LOCK比較特殊,附加標(biāo)志不能影響它。
·??PARTIAL_WAKE_LOCK不受電源鍵控制,即按電源鍵不能使PARTIAL_WAKE_LOCK系統(tǒng)進(jìn)入休眠狀態(tài)(屏幕可以關(guān)閉,但CPU不會(huì)休眠)。
了解了上述知識(shí)后,再來(lái)看如下代碼:
[-->PowerManager.java::WakeLock]
WakeLock(int flags, String tag)
{
???? //檢查flags參數(shù)是否非法
??? mFlags =flags;
? ??mTag =tag;
?? ?//創(chuàng)建一個(gè)Binder對(duì)象,除了做Token外,PMS需要監(jiān)視客戶端的生死狀況,否則有可能導(dǎo)致
?? ?//WakeLock不能被釋放
?? ??mToken= new Binder();
}
客戶端創(chuàng)建WakeLock后,需要調(diào)用acquire以確保電力資源供應(yīng)正常。下面對(duì)acquire代碼進(jìn)行分析。
[-->PowerManager.java::WakeLock.acquire函數(shù)]
public void acquire()
?{
?synchronized (mToken) {
??acquireLocked();//調(diào)用acquireLocked函數(shù)
? }
?}
//acquireLoced函數(shù)
private void acquireLocked() {
? if(!mRefCounted || mCount++ == 0) {
?????mHandler.removeCallbacks(mReleaser);//引用計(jì)數(shù)控制
? try {
????? //調(diào)用PMS的acquirewakeLock,注意這里傳遞的參數(shù),其中mWorkSource為空
?????mService.acquireWakeLock(mFlags, mToken, mTag, mWorkSource);
? }......
??? mHeld =true;
?? }
}
上邊代碼中調(diào)用PMS的acquireWakeLock函數(shù)與PMS交互,該函數(shù)最后一個(gè)參數(shù)為WorkSource類。這個(gè)類從Android 2.2開(kāi)始就存在,但一直沒(méi)有明確的作用,下面是關(guān)于它的一段說(shuō)明。
/**??? 見(jiàn)WorkSoure.java
?* Describesthe source of some work that may be done by someone else.
?* Currentlythe public representation of what a work source is is not
?* defined;this is an opaque container.
?*/
由以上注釋可知,WorkSource本意用來(lái)描述某些任務(wù)的Source。傳遞此Source給其他人,這些人就可以執(zhí)行該Source對(duì)應(yīng)的工作。目前使用WorkSource的地方僅是ContentService中的SynManager。讀者暫時(shí)可不理會(huì)WorkSource。
客戶端的功能比較簡(jiǎn)單,和PMS僅通過(guò)acquireWakeLock函數(shù)交互。下面來(lái)分析服務(wù)端的工作。
[-->PowerManagerService.java::acquireWakeLock]
public void acquireWakeLock(int flags, IBinderlock, String tag, WorkSource ws) {
??????? intuid = Binder.getCallingUid();
??????? intpid = Binder.getCallingPid();
??????? if(uid != Process.myUid()) {
???????????mContext.enforceCallingOrSelfPermission(//檢查WAKE_LOCK權(quán)限
??????? ??????????????????android.Manifest.permission.WAKE_LOCK,null);
??????? }
??????? if(ws != null) {
??????????? //如果ws不為空,需要檢查調(diào)用進(jìn)程是否有UPDATE_DEVICE_STATS的權(quán)限
???????????enforceWakeSourcePermission(uid, pid);
??????? }
??????? longident = Binder.clearCallingIdentity();
??????? try{
???????????synchronized (mLocks) {調(diào)用acquireWakeLockLocked函數(shù)
???????????????acquireWakeLockLocked(flags, lock, uid, pid, tag, ws);
???????????}
??????? } ......
??? }
接下來(lái)分析acquireWakeLockLocked函數(shù)。由于此段代碼較長(zhǎng),宜分段來(lái)看。
開(kāi)始分析之前,有必要先介紹另外一個(gè)數(shù)據(jù)結(jié)構(gòu),它為PowerManagerService的內(nèi)部類,名字也為WakeLock。其定義如下:
[-->PowerManagerService.java]
class WakeLock implements IBinder.DeathRecipient
PMS的WakeLock實(shí)現(xiàn)了DeathRecipient接口。根據(jù)前面Binder系統(tǒng)的知識(shí)可知,當(dāng)Binder服務(wù)端死亡后,Binder系統(tǒng)會(huì)向注冊(cè)了訃告接收的Binder客戶端發(fā)送訃告通知,因此客戶端可以做一些資源清理工作。在本例中,PM.WakeLock是Binder服務(wù)端,而PMS.WakeLock是Binder客戶端。假如PM.WakeLock所在進(jìn)程在release喚醒鎖(即WakeLock)之前死亡,PMS.WakeLock的binderDied函數(shù)則會(huì)被調(diào)用,這樣,PMS也能及時(shí)進(jìn)行釋放(release)工作。對(duì)于系統(tǒng)的重要資源來(lái)說(shuō),采用這種安全保護(hù)措施尤其必要。
回到acquireWakeLockLocked函數(shù),先看第一段代碼:
[-->PowerManagerService.java::acquireWakeLockLocked]
public void acquireWakeLockLocked(int flags,IBinder lock, int uid,
??????????????????????? int pid, Stringtag,WorkSource ws) {
? ......
? //mLocks是一個(gè)ArrayList,保存PMS.WakeLock對(duì)象
? int index= mLocks.getIndex(lock);
? WakeLockwl;
? booleannewlock;
? booleandiffsource;
? WorkSourceoldsource;
? if (index< 0) {
???? //創(chuàng)建一個(gè)PMS.WakeLock對(duì)象,保存客戶端acquire傳來(lái)的參數(shù)
?? ?wl = new WakeLock(flags, lock, tag, uid, pid);
??? switch(wl.flags & LOCK_MASK)
??? {??? //將flags轉(zhuǎn)換成對(duì)應(yīng)的minState
????? casePowerManager.FULL_WAKE_LOCK:
?????? if(mUseSoftwareAutoBrightness) {
????????wl.minState = SCREEN_BRIGHT;
?????? }else {
??? ?????wl.minState = (mKeyboardVisible ? ALL_BRIGHT: SCREEN_BUTTON_BRIGHT);
??????? }
???????break;
????? casePowerManager.SCREEN_BRIGHT_WAKE_LOCK:
????????wl.minState = SCREEN_BRIGHT;
???????? break;
?????? casePowerManager.SCREEN_DIM_WAKE_LOCK:
????????wl.minState = SCREEN_DIM;
????????break;
????? ?case PowerManager.PARTIAL_WAKE_LOCK:
?????? //PROXIMITY_SCREEN_OFF_WAKE_LOCK在SDK中并未輸出,原因是有部分手機(jī)并沒(méi)有接近
?????? //傳感器
?????? casePowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK:
????????break;
??????default:
?????? ??return;
???? ?}
???mLocks.addLock(wl);//將PMS.WakeLock對(duì)象保存到mLocks中
??? if (ws!= null) {
???????wl.ws = new WorkSource(ws);
???? }
???? newlock= true;? //設(shè)置幾個(gè)參數(shù)信息,newlock表示新創(chuàng)建了一個(gè)PMS.WakeLock對(duì)象
????diffsource = false;
????oldsource = null;
?}else{
?? //如果之前保存有PMS.WakeLock,則要判斷新傳入的WorkSource和之前保存的WorkSource
?? //是否一樣。此處不討論這種情況
?? ......
}
在上面代碼中,很重要一部分是將前面flags信息轉(zhuǎn)成PMS.WakeLock的成員變量minState,下面是對(duì)轉(zhuǎn)換關(guān)系的總結(jié)。
·??FULL_WAKE_LOCK:當(dāng)啟用mUseSoftwareAutoBrightness時(shí),minState為SCREEN_BRIGHT(表示屏幕全亮),否則為ALL_BRIGHT(屏幕、鍵盤、按鍵全亮。注意,只有在打開(kāi)鍵盤時(shí)才能選擇此項(xiàng))或SCREEN_BUTTON_BRIGHT(屏幕、按鍵全亮)。
·??SCREEN_BRIGHT_WAKE_LOCK:minState為SCREEN_BRIGHT,表示屏幕全亮。
·??SCREEN_DIM_WAKE_LOCK:minState為SCREEN_DIM,表示屏幕Dim。
·??對(duì)PARTIAL_WAKE_LOCK和PROXIMITY_SCREEN_OFF_WAKE_LOCK情況不做處理。
該做的準(zhǔn)備工作都做了,下面來(lái)看第二階段的工作是什么。
代碼如下:
? //isScreenLock用于判斷flags是否和屏幕有關(guān),除PARTIAL_WAKE_LOCK外,其他WAKE_LOCK
? //都和屏幕有關(guān)
if (isScreenLock(flags)) {
? if ((flags& LOCK_MASK) == PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK) {
??????mProximityWakeLockCount++;//引用計(jì)數(shù)控制
?????? if(mProximityWakeLockCount == 1) {
????????enableProximityLockLocked();//使能Proximity傳感器
??????? }
?? } else {
?? if((wl.flags & PowerManager.ACQUIRE_CAUSES_WAKEUP) != 0) {
??? ?......//ACQUIRE_CAUSES_WAKEUP標(biāo)志處理
? } else {
? ?//①gatherState返回一個(gè)狀態(tài),稍后分析該函數(shù)
??mWakeLockState = (mUserState | mWakeLockState) &mLocks.gatherState();
? }
? ?//②設(shè)置電源狀態(tài),
? ?setPowerState(mWakeLockState | mUserState);
?? }
?}
以上代碼列出了兩個(gè)關(guān)鍵函數(shù),一個(gè)是gatherState,另外一個(gè)是setPowerState,下面來(lái)分析它們。
gatherState函數(shù)的代碼如下:
[-->PowerManagerService.java::gatherState]
int gatherState()
{
??? intresult = 0;
??? int N =this.size();
??? for (inti=0; i<N; i++) {
???? WakeLock wl = this.get(i);
???? if(wl.activated)
??????? if(isScreenLock(wl.flags))
??????????result |= wl.minState;//對(duì)系統(tǒng)中所有活躍PMS.WakeLock的狀態(tài)進(jìn)行或操作
? }
?? returnresult;
?}
由以上代碼可知,gatherState將統(tǒng)計(jì)當(dāng)前系統(tǒng)內(nèi)部活躍WakeLock的minState。這里為什么要“使用”或“操作”呢?舉個(gè)例子,假如WakeLock A的minState為SCREEN_DIM,而WakeLock B的minState為SCREEN_BRIGHT,二者共同作用,最終的屏幕狀態(tài)顯然應(yīng)該是SCREEN_BRIGHT。
提示讀者也可參考PowerManagerService中SCREEN_DIM等變量的定義。
下面來(lái)看setPowerState,本章前面曾兩次對(duì)該函數(shù)避而不談,現(xiàn)在該見(jiàn)識(shí)見(jiàn)識(shí)它了。
setPowerState用于設(shè)置電源狀態(tài),先來(lái)看其在代碼中的調(diào)用:
setPowerState(mWakeLockState | mUserState);
在以上代碼中除了mWakeLockState外,還有一個(gè)mUserState。根據(jù)前面對(duì)gatherState函數(shù)的介紹可知,mWakeLockState的值來(lái)源于系統(tǒng)當(dāng)前活躍WakeLock的minState。那么mUserState代表什么呢?
mUserState代表用戶觸發(fā)事件導(dǎo)致的電源狀態(tài)。例如,按Home鍵后,將該值設(shè)置為SCREEN_BUTTON_BRIGHT(假設(shè)手機(jī)沒(méi)有鍵盤)。很顯然,此時(shí)系統(tǒng)的電源狀態(tài)應(yīng)該是mUserState和mWakeLockState的組合。
提示 “一個(gè)小小的變量背后代表了一個(gè)很重要的case”,讀者能體會(huì)到嗎?
下面來(lái)看setPowerState的代碼,這段代碼較長(zhǎng),也適合分段來(lái)看。第一段代碼如下:
[-->PowerManagerService.java::setPowerState]
private void setPowerState(int state)
{//調(diào)用另外一個(gè)同名函數(shù)
?setPowerState(state, false,WindowManagerPolicy.OFF_BECAUSE_OF_TIMEOUT);
}
//setPowerState
private void setPowerState(int newState, booleannoChangeLights, int reason)
{
?synchronized (mLocks) {
? int err;
??if (noChangeLights)//在這種情況中,noChangeLights為false
????newState = (newState & ~LIGHTS_MASK) | (mPowerState &LIGHTS_MASK);
??
? if(mProximitySensorActive)//如果打開(kāi)了接近感應(yīng)器,就不需要在這里點(diǎn)亮屏幕了
????newState = (newState & ~SCREEN_BRIGHT);
?
? if(batteryIsLow())//判斷是否處于低電狀態(tài)
?????newState |= BATTERY_LOW_BIT;
?? else
?????newState &= ~BATTERY_LOW_BIT;
?......
? //如果還沒(méi)啟動(dòng)完成,則需要將newState置為ALL_