第二個關鍵點是init函數,該函數將初始化PMS內部的一些重要成員變量,由于此函數代碼較長,此處將分段討論。
從流程角度看,init大體可分為三段。
1. init分析之一
**PowerManagerService.java::init函數**
~~~
void init(Context context, LightsService lights,IActivityManager activity,
BatteryService battery) {
//①保存幾個成員變量
mLightsService = lights;//保存LightService
mContext= context;
mActivityService = activity;//保存ActivityManagerService
//保存BatteryStatsService
mBatteryStats = BatteryStatsService.getService();//
mBatteryService = battery;//保存BatteryService
//從LightService中獲取代表不同硬件Light的Light對象
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);
//②調用nativeInit函數
nativeInit();
synchronized (mLocks) {
updateNativePowerStateLocked();//③更新Native層的電源狀態
}
~~~
第一階段工作可分為三步:
- 對一些成員變量進行賦值。
- 調用nativeInit函數初始化Native層相關資源。
- 調用updateNativePowerStateLocked更新Native層的電源狀態。這個函數的調用次數較為頻繁,以后續分析時討論。
先來看第一階段出現的各類成員變量,如表5-1所示。
:-: 表5-1 成員變量說明
| 成員變量名 | 數據類型 | 作用 |
| --- | --- | --- |
| mLightsService | LightsService| 和LightsService交互用 |
|mActivityService | IActivityManager | 和ActivityManagerService交互 |
| mBatteryStats | IBatteryStats | 和BatteryStatsService交互,用于系統耗電量統計方面的工作 |
| mBatteryService | BatteryService | 用于獲取電源狀態,例如是否為低電狀態、查詢電池電量等 |
| mLcdLight、mButtonLight、mKeyboardLight、mAttentionLight| LightsService.Light| 由PMS控制,在不同狀態下點亮或熄滅它們 |
下面來看nativeInit函數,其JNI層實現代碼如下:
**com_android_server_PowerManagerService.cpp**
~~~
static void android_server_PowerManagerService_nativeInit(JNIEnv*env,
jobject obj) {
//非常簡單,就是創建一個全局引用對象gPowerManagerServiceObj
gPowerManagerServiceObj = env->NewGlobalRef(obj);
}
~~~
init第一階段工作比較簡單,下面進入第二階段的分析。
2. init分析之二
init第二階段工作將創建兩個HandlerThread對象,即創建兩個帶消息循環的工作線程。PMS本身由ServerThread線程創建,并且將自己的工作委托給這兩個線程,它們分別是:
- mScreenOffThread:按Power鍵關閉屏幕時,屏幕不是突然變黑的,而是一個漸暗的過程。mScreenOffThread線程就用于控制關屏過程中的亮度調節。
- mHandlerThread:該線程是PMS的主要工作線程。
先來看這兩個線程的創建。
(1) mScreenOffThread和mHandlerThread分析
**PowerManagerService.java::init函數**
~~~
......
mScreenOffThread= new HandlerThread("PowerManagerService.mScreenOffThread") {
protected void onLooperPrepared() {
mScreenOffHandler = new Handler();//向這個handler發送的消息,將由此線程處理
synchronized (mScreenOffThread) {
mInitComplete = true;
mScreenOffThread.notifyAll();
}
}
};
mScreenOffThread.start();//創建對應的工作線程
synchronized (mScreenOffThread) {
while(!mInitComplete) {
try {//等待mScreenOffThread線程創建完成
mScreenOffThread.wait();
} ......
}
}
~~~
* * * * *
**注意**,在Android代碼中經常出現“線程A創建線程B,然后線程A等待線程B創建完成”的情況,讀者了解它們的作用即可。接著看以下代碼。
* * * * *
**PowerManagerService.java::init函數**
~~~
mInitComplete= false;
//創建 mHandlerThread
mHandlerThread = new HandlerThread("PowerManagerService") {
protectedvoid onLooperPrepared() {
super.onLooperPrepared();
initInThread();//①初始化另外一些成員變量
}
};
mHandlerThread.start();
......//等待mHandlerThread創建完成
~~~
由于mHandlerThread承擔了PMS的主要工作任務,因此需要先做一些初始化工作,相關的代碼在initInThread中,擬放在單獨一節中進行討論。
(2) initInThread分析
initInThread本身比較簡單,涉及三個方面的工作,總結如下:
- PMS需要了解外面的世界,所以它會注冊一些廣播接收對象,接收諸如啟動完畢、電池狀態變化等廣播。
- PMS所從事的電源管理工作需要遵守一定的規則,而這些規則在代碼中就是一些配置參數,這些配置參數的值可以是固定寫死的(編譯完后就無法改動),也可以是經由Settings數據庫動態設定的。
- PMS需要對外發出一些通知,例如屏幕關閉/屏幕開啟。
了解initInThread的概貌后,再來看如下代碼。
**PowerManagerService.java::initInThread**
~~~
void initInThread() {
mHandler= new Handler();
//PMS內部也需要使用WakeLock,此處定義了幾種不同的UnsynchronizedWakeLock。它們的
//作用見后文分析
mBroadcastWakeLock = newUnsynchronizedWakeLock(
PowerManager.PARTIAL_WAKE_LOCK, "sleep_broadcast", true);
//創建廣播通知的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);
//取配置參數,這些參數是編譯時確定的,運行過程中無法修改
Resourcesresources = mContext.getResources();
mAnimateScreenLights = resources.getBoolean(
com.android.internal.R.bool.config_animateScreenLights);
......//見下文的配置參數匯總
//通過數據庫設置的配置參數
ContentResolver resolver =mContext.getContentResolver();
Cursor settingsCursor =resolver.query(Settings.System.CONTENT_URI, null,
......//設置查詢條件和查詢項的名字,見后文的配置參數匯總
null);
//ContentQueryMap是一個常用類,簡化了數據庫查詢工作。讀者可參考SDK中該類的說明文檔
mSettings= new ContentQueryMap(settingsCursor, Settings.System.NAME,
true, mHandler);
//監視上邊創建的ContentQueryMap中內容的變化
SettingsObserver settingsObserver = new SettingsObserver();
mSettings.addObserver(settingsObserver);
settingsObserver.update(mSettings, null);
//注冊接收通知的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);
//監視Settings數據中secure表的變化
mContext.getContentResolver().registerContentObserver(
Settings.Secure.CONTENT_URI, true,
new ContentObserver(new Handler()) {
public void onChange(boolean selfChange) {
updateSettingsValues();
}
});
updateSettingsValues();
......//通知其他線程
}
~~~
在上述代碼中,很大一部分用于獲取配置參數。同時,對于數據庫中的配置值,還需要建立監測機制,細節部分請讀者自己閱讀相關代碼,這里總結一下常用的配置參數,如表5-2所示。
:-: 表5-2 PMS使用的配置參數
| 參數名:類型 | 來源 | 備注 |
| --- | --- | --- |
| mAnimateScreenLights:bool | config.xml[^write]| 關屏時屏幕光是否漸暗,默認為true |
| mUnplugTurnsOnScreen:bool | config.xml | 拔掉USB線,是否點亮屏幕 |
| mScreenBrightnessDim:int | config.xml | PMS可設置的屏幕亮度的最小值,默認20(單位lx) |
| mUseSoftwareAutoBrightness:bool | config.xml | 是否啟用Setting中的亮度自動調節,如果硬件不支持該功能,則可由軟件控制。默認為false |
|mAutoBrightnessLevels:int[]、mLcdBacklightValues:int[] 、…… | config.xml,具體值由硬件廠商定義 | 當使用軟件自動亮度調節時,需配置不同亮度時對應的參數 |
| STAY_ON_WHILE_PLUGGED_IN:int | Settings.db | 插入USB時是否保持喚醒狀態 |
| SCREEN_OFF_TIMEOUT:int | Settings.db | 屏幕超時時間 |
| DIM_SCREEN:int | Settings.db |是否變暗(dim)屏幕 |
| SCREEN_BRIGHTNESS_MODE:int | Settings.db |屏幕亮度模式(自動還是手動調節) |
除了獲取配置參數外,initInThread還創建了好幾個UnsynchronizedWakeLock對象,它的作用是:在Android系統中,為了搶占電力資源,客戶端要使用WakeLock對象。PMS自己也不例外,所以為了保證在工作中不至于突然掉電(當其他客戶端都不使用WakeLock的時候,這種情況理論上是有可能發生的),PMS需要定義供自己使用的WakeLock。由于線程同步方面的原因,PMS封裝了一個UnsynchronizedWakeLock結構,它的調用已經處于鎖保護下,所以在內部無需再做同步處理。UnsynchronizedWakeLock比較簡單,因此不再贅述。
下面來看init第三階段的工作。
3. init分析之三
**PowerManagerService.java::init函數**
~~~
nativeInit();//不知道此處為何還要調用一次nativeInit,筆者懷疑此處為bug
synchronized (mLocks) {
updateNativePowerStateLocked();//更新native層power狀態,以后分析
forceUserActivityLocked();//強制觸發一次用戶事件
mInitialized = true;
}//init函數完畢
~~~
forceUserActivityLocked表示強制觸發一次用戶事件。這個解釋是否會讓讀者丈二和尚摸不著頭?先來看它的代碼:
**PowerManagerService.java:: forceUserActivityLocked**
~~~
private void forceUserActivityLocked() {
if(isScreenTurningOffLocked()) {
mScreenBrightness.animating = false;
}
boolean savedActivityAllowed =mUserActivityAllowed;
mUserActivityAllowed = true;
//下面這個函數以后會分析, SDK中有對應的API
userActivity(SystemClock.uptimeMillis(), false);
mUserActivityAllowed= savedActivityAllowed;
}
~~~
forceUserActivityLocked內部就是為調用userActivity掃清一切障礙。對于SDK中PowerManager.userActivity的說明文檔“User activity happened.Turnsthe device from whatever state it's in to full on, and resets the auto-offtimer.”簡單翻譯過來是:調用此函數后,手機將被喚醒。屏幕超時時間將重新計算。
userActivity是PMS中很重要的一個函數,本章后面將對其進行詳細分析。
4. init函數總結
PMS的init函數比較簡單,但是其眾多的成員變量讓人感到有點頭暈。讀者自行閱讀代碼時,不妨參考表5-1和表5-2。
[^write]: config.xml文件的全路徑是4.0源碼/frameworks/base/core/res/res/values/config.xml。
- 前言
- 第1章 搭建Android源碼工作環境
- 1.1 Android系統架構
- 1.2 搭建開發環境
- 1.2.1 下載源碼
- 1.2.2 編譯源碼
- 1.2.3 利用Eclipse調試system_process
- 1.3 本章小結
- 第2章 深入理解Java Binder和MessageQueue
- 2.1 概述
- 2.2 Java層中的Binder架構分析
- 2.2.1 Binder架構總覽
- 2.2.2 初始化Java層Binder框架
- 2.2.3 addService實例分析
- 2.2.4 Java層Binder架構總結
- 2.3 心系兩界的MessageQueue
- 2.3.1 MessageQueue的創建
- 2.3.2 提取消息
- 2.3.3 nativePollOnce函數分析
- 2.3.4 MessageQueue總結
- 2.4 本章小結
- 第3章 深入理解SystemServer
- 3.1 概述
- 3.2 SystemServer分析
- 3.2.1 main函數分析
- 3.2.2 Service群英會
- 3.3 EntropyService分析
- 3.4 DropBoxManagerService分析
- 3.4.1 DBMS構造函數分析
- 3.4.2 dropbox日志文件的添加
- 3.4.3 DBMS和settings數據庫
- 3.5 DiskStatsService和DeviceStorageMonitorService分析
- 3.5.1 DiskStatsService分析
- 3.5.2 DeviceStorageManagerService分析
- 3.6 SamplingProfilerService分析
- 3.6.1 SamplingProfilerService構造函數分析
- 3.6.2 SamplingProfilerIntegration分析
- 3.7 ClipboardService分析
- 3.7.1 復制數據到剪貼板
- 3.7.2 從剪切板粘貼數據
- 3.7.3 CBS中的權限管理
- 3.8 本章小結
- 第4章 深入理解PackageManagerService
- 4.1 概述
- 4.2 初識PackageManagerService
- 4.3 PKMS的main函數分析
- 4.3.1 構造函數分析之前期準備工作
- 4.3.2 構造函數分析之掃描Package
- 4.3.3 構造函數分析之掃尾工作
- 4.3.4 PKMS構造函數總結
- 4.4 APK Installation分析
- 4.4.1 adb install分析
- 4.4.2 pm分析
- 4.4.3 installPackageWithVerification函數分析
- 4.4.4 APK 安裝流程總結
- 4.4.5 Verification介紹
- 4.5 queryIntentActivities分析
- 4.5.1 Intent及IntentFilter介紹
- 4.5.2 Activity信息的管理
- 4.5.3 Intent 匹配查詢分析
- 4.5.4 queryIntentActivities總結
- 4.6 installd及UserManager介紹
- 4.6.1 installd介紹
- 4.6.2 UserManager介紹
- 4.7 本章學習指導
- 4.8 本章小結
- 第5章 深入理解PowerManagerService
- 5.1 概述
- 5.2 初識PowerManagerService
- 5.2.1 PMS構造函數分析
- 5.2.2 init分析
- 5.2.3 systemReady分析
- 5.2.4 BootComplete處理
- 5.2.5 初識PowerManagerService總結
- 5.3 PMS WakeLock分析
- 5.3.1 WakeLock客戶端分析
- 5.3.2 PMS acquireWakeLock分析
- 5.3.3 Power類及LightService類介紹
- 5.3.4 WakeLock總結
- 5.4 userActivity及Power按鍵處理分析
- 5.4.1 userActivity分析
- 5.4.2 Power按鍵處理分析
- 5.5 BatteryService及BatteryStatsService分析
- 5.5.1 BatteryService分析
- 5.5.2 BatteryStatsService分析
- 5.5.3 BatteryService及BatteryStatsService總結
- 5.6 本章學習指導
- 5.7 本章小結
- 第6章 深入理解ActivityManagerService
- 6.1 概述
- 6.2 初識ActivityManagerService
- 6.2.1 ActivityManagerService的main函數分析
- 6.2.2 AMS的 setSystemProcess分析
- 6.2.3 AMS的 installSystemProviders函數分析
- 6.2.4 AMS的 systemReady分析
- 6.2.5 初識ActivityManagerService總結
- 6.3 startActivity分析
- 6.3.1 從am說起
- 6.3.2 AMS的startActivityAndWait函數分析
- 6.3.3 startActivityLocked分析
- 6.4 Broadcast和BroadcastReceiver分析
- 6.4.1 registerReceiver流程分析
- 6.4.2 sendBroadcast流程分析
- 6.4.3 BROADCAST_INTENT_MSG消息處理函數
- 6.4.4 應用進程處理廣播分析
- 6.4.5 廣播處理總結
- 6.5 startService之按圖索驥
- 6.5.1 Service知識介紹
- 6.5.2 startService流程圖
- 6.6 AMS中的進程管理
- 6.6.1 Linux進程管理介紹
- 6.6.2 關于Android中的進程管理的介紹
- 6.6.3 AMS進程管理函數分析
- 6.6.4 AMS進程管理總結
- 6.7 App的 Crash處理
- 6.7.1 應用進程的Crash處理
- 6.7.2 AMS的handleApplicationCrash分析
- 6.7.3 AppDeathRecipient binderDied分析
- 6.7.4 App的Crash處理總結
- 6.8 本章學習指導
- 6.9 本章小結
- 第7章 深入理解ContentProvider
- 7.1 概述
- 7.2 MediaProvider的啟動及創建
- 7.2.1 Context的getContentResolver函數分析
- 7.2.2 MediaStore.Image.Media的query函數分析
- 7.2.3 MediaProvider的啟動及創建總結
- 7.3 SQLite創建數據庫分析
- 7.3.1 SQLite及SQLiteDatabase家族
- 7.3.2 MediaProvider創建數據庫分析
- 7.3.3 SQLiteDatabase創建數據庫的分析總結
- 7.4 Cursor 的query函數的實現分析
- 7.4.1 提取query關鍵點
- 7.4.2 MediaProvider 的query分析
- 7.4.3 query關鍵點分析
- 7.4.4 Cursor query實現分析總結
- 7.5 Cursor close函數實現分析
- 7.5.1 客戶端close的分析
- 7.5.2 服務端close的分析
- 7.5.3 finalize函數分析
- 7.5.4 Cursor close函數總結
- 7.6 ContentResolver openAssetFileDescriptor函數分析
- 7.6.1 openAssetFileDescriptor之客戶端調用分析
- 7.6.2 ContentProvider的 openTypedAssetFile函數分析
- 7.6.3 跨進程傳遞文件描述符的探討
- 7.6.4 openAssetFileDescriptor函數分析總結
- 7.7 本章學習指導
- 7.8 本章小結
- 第8章 深入理解ContentService和AccountManagerService
- 8.1 概述
- 8.2 數據更新通知機制分析
- 8.2.1 初識ContentService
- 8.2.2 ContentResovler 的registerContentObserver分析
- 8.2.3 ContentResolver的 notifyChange分析
- 8.2.4 數據更新通知機制總結和深入探討
- 8.3 AccountManagerService分析
- 8.3.1 初識AccountManagerService
- 8.3.2 AccountManager addAccount分析
- 8.3.3 AccountManagerService的分析總結
- 8.4 數據同步管理SyncManager分析
- 8.4.1 初識SyncManager
- 8.4.2 ContentResolver 的requestSync分析
- 8.4.3 數據同步管理SyncManager分析總結
- 8.5 本章學習指導
- 8.6 本章小結