第二个关键点是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 本章小结