一、电源管理框架
PowerManagerServcie是android系统电源管理的核心服务,它在Framework层建立起一个策略控制方案,向下决策HAL层以及kernel层来控制设备待机状态,控制显示屏,背光灯,距离传感器,光线传感器等硬件设备的状态。向上提供给应用程序相应的操作接口,比如听音乐时持续保持系统唤醒,应用通知来临唤醒手机屏幕等场景等,PMS也是系统的核心服务,Android的电源管理主要是通过wakelock机制来管理系统的状态,整个android电源管理,可以分为如下四个层次:
1. 应用接口层(PowerManager.java)
PowerManager中开放给应用一系列接口,应用可以调用PM的接口申请wakelock,唤醒系统,或使系统进入睡眠等操作;
2. Framework层(PowerManagerService.java)
应用调用PowerManager开放的接口,来对系统进行一些列的操作是在PowerManagerService中完成的,PowerManagerService计算系统中和Power 相关的计算,是整个电源管理的决策系统。同时协调Power如何与系统其 它模块的交互,比如亮屏,暗屏,系统睡眠,唤醒等等;
3. HAL层(Power.c)
该层只有一个power.c文件,该文件通过上层传下来的参数,向/sys/power/wake_lock 或者/sys/power/wake_unlock文件节点写数据来与kernel进行通信,主要功能是申请/释放锁,维持屏幕亮灭;
4. 内核层(kernel/Power)
内核层实现电源管理的方案主要包含三个部分:
(1)Kernel/power/:实现了系统电源管理框架机制;
(2)Arch/arm(ormips or powerpc)/mach-XXX/pm.c:实现对特定板的处理器电源管理;
(3)drivers/power:是设备电源管理的基础框架,为驱动提供了电源管理接口。
整体框架图如下(借鉴):
二、电源管理服务PowerManagerService
1. PowerServiceManager启动流程
PowerManagerService是在SystemServer中创建的,其中在SystemServer在系统启动的时候会启动三类服务:引导关键服务、核心服务和其他服务,PowerManagerService是作为一个核心服务加入到ServiceManager中,启动服务的方式如下:
startBootstrapServices(); //启动引导服务
startCoreServices();//启动核心服务
startOtherServices();//其他服务
(1)核心服务创建以后,PowerServiceManager的服务随之创建(SystemServer.java):
mPowerManagerService =
mSystemServiceManager.startService(PowerManagerService.class);
(2)startService方法(SystemServiceManager.java ):
public T startService(Class serviceClass) {
mServices.add(service); //注册服务到服务列表中去
ervice.onStart();//启动服务
return service;//返回启动的服务
}
在startService方法中,利用反射方法构造PowerManagerService的对象,将它添加到本地service变量中,然后调用了PowerManagerService的onStart方法。
(3)PowerManagerService构造方法(PowerManagerService.java)
public PowerManagerService(Context context) {
//创建一个HandlerThread,并启动
mHandlerThread = new ServiceThread(TAG,
Process.THREAD_PRIORITY_DISPLAY, false /*allowIo*/);
mHandlerThread.start();
//基于这个HandlerThread创建相关的Handler对象,用于向handlerThread中发送消息
mHandler = new PowerManagerHandler(mHandlerThread.getLooper());
synchronized (mLock) {
mWakeLockSuspendBlocker =
createSuspendBlockerLocked("PowerManagerService.WakeLocks");
mDisplaySuspendBlocker =
createSuspendBlockerLocked("PowerManagerService.Display");
mDisplaySuspendBlocker.acquire();
//调用native层初始化
nativeInit();
nativeSetAutoSuspend(false);
nativeSetInteractive(true);
nativeSetFeature(POWER_FEATURE_DOUBLE_TAP_TO_WAKE, 0);
}
}
在PowerManagerService的构造函数创建了一个消息发送和处理的Handler和两种WakeLock锁:
a、PowerManagerService.WakeLocks,主要用于控制CPU的唤醒;
b、PowerManagerService.Display 主要用于控制屏幕的点亮和熄灭;
(4)PowerManagerService的Onstart方法:
在PowerManagerService的Onstart方法中:
public void onStart() {
publishBinderService(Context.POWER_SERVICE, new BinderService());
publishLocalService(PowerManagerInternal.class, new LocalService());
Watchdog.getInstance().addMonitor(this);
Watchdog.getInstance().addThread(mHandler);
}
Onstart完成的工作就是将POWER_SERVICE作为Binder的服务端,注册到SystemService中去;将PowerManagerInternal注册到本地服务中,将自己加到watchdog的监控队列中去;将之前在构造函数中创建的mHandler对象加入到watchdog的中,用于监视mHandler的looper是否空闲。
(4)系统准备工作:
在PowerManagerService创建之后会调用systemReady做一些初始化相关的操作,获取与PowerManager相关的本地服务:
public void systemReady(IAppOpsService appOps) {
synchronized (mLock) {
//第一步:初始化相关的变量
mSystemReady = true;
mAppOps = appOps;
mDreamManager = getLocalService(DreamManagerInternal.class);
//初始化互动屏保管理
mDisplayManagerInternal = getLocalService(DisplayManagerInternal.class);
//初始化屏幕显示管理服务
mPolicy = getLocalService(WindowManagerPolicy.class);
mBatteryManagerInternal = getLocalService(BatteryManagerInternal.class);
//初始化电池管理服务
PowerManager pm = (PowerManager)
mContext.getSystemService(Context.POWER_SERVICE);
mScreenBrightnessSettingMinimum = pm.getMinimumScreenBrightnessSetting();
mScreenBrightnessSettingMaximum = pm.getMaximumScreenBrightnessSetting();
mScreenBrightnessSettingDefault = pm.getDefaultScreenBrightnessSetting();
//获取屏幕的亮度值,最大亮度,最小亮度,默认亮度
SensorManager sensorManager = new SystemSensorManager
(mContext, mHandler.getLooper());
//获取传感器管理服务
mBatteryStats = BatteryStatsService.getService();
//初始化电量统计服务
mNotifier = new Notifier(
Looper.getMainLooper(),
mBatteryStats,mAppOps,
createSuspendBlockerLocked("PowerManagerService.Broadcasts"),
mPolicy);
mWirelessChargerDetector = new WirelessChargerDetector(sensorManager,
createSuspendBlockerLocked
("PowerManagerService.WirelessChargerDetector"),mHandler);
mSettingsObserver = new SettingsObserver(mHandler);
//settings的监听器
mLightsManager = getLocalService(LightsManager.class);
//LED指示灯管理服务
mAttentionLight =
mLightsManager.getLight(LightsManager.LIGHT_ID_ATTENTION);
// 初始化屏幕显示服务
mDisplayManagerInternal.initPowerManagement(
mDisplayPowerCallbacks, mHandler, sensorManager);
//第二步:注册相关的BroadCastReceiver
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_BATTERY_CHANGED);
filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
mContext.registerReceiver(new BatteryReceiver(), filter, null, mHandler);
//注册电池变化的接收器
filter = new IntentFilter();
filter.addAction(Intent.ACTION_DREAMING_STARTED);
filter.addAction(Intent.ACTION_DREAMING_STOPPED);
mContext.registerReceiver(new DreamReceiver(), filter, null, mHandler);
//注册屏保开始和结束的接收器
filter = new IntentFilter();
filter.addAction(Intent.ACTION_USER_SWITCHED);
mContext.registerReceiver
(new UserSwitchedReceiver(), filter, null, mHandler);
//注册切换用户的接收器
filter = new IntentFilter();
filter.addAction(Intent.ACTION_DOCK_EVENT);
mContext.registerReceiver(new DockReceiver(), filter, null, mHandler);
//第三步.注册设置变化的监听器
final ContentResolver resolver = mContext.getContentResolver();
resolver.registerContentObserver(Settings.Secure.getUriFor(
Settings.Secure.SCREENSAVER_ENABLED),
false, mSettingsObserver, UserHandle.USER_ALL);
……
resolver.registerContentObserver(Settings.Secure.getUriFor(
Settings.Secure.DOUBLE_TAP_TO_WAKE),
false, mSettingsObserver, UserHandle.USER_ALL);
//双击唤醒屏幕
// 第四步: 从文件读取默认的配置信息
readConfigurationLocked();
//读取设置信息,并更新相关的变量
updateSettingsLocked();
// 第五步
mDirty |= DIRTY_BATTERY_STATE;
//更新电源的相关信息
updatePowerStateLocked();
}
}
SystemReady所完成的工作如下:
-获取与PowerManagerServcie相关的系统服务以及本地服务;
-获取屏幕最大,最小以及默认亮度值;
-创建SensorManager 对象,用于和SensorService交互;
-创建Notifier对象,用于通知系统中电源状态的改变;
-调用DisplayManagerService的initPowerManagement()方法来初始化Power显示模块。
-注册SettingsObserver监听系统设置的变化。
整体框架如下图(借鉴):
(5)PowerManager相关接口:
PowerManager向应用提供了相应的接口,以供应用程序调用,来改变系统待机状态,屏幕状态,屏幕亮度等,PowerManager是PowerManagerService的代理类,PowerManager向上层应用提供交互的接口,具体的处理工作在PowerManagerService中完成。下面介绍PowerManager中提供的相应接口作用:
a、Wakeup():
强制系统从睡眠状态唤醒,此接口对应用是不开放的,应用想唤醒系统必须通过设置亮屏标志;
b、gotoSleep():
强制系统进入到睡眠状态,此接口也是应用不开放;
c、userActivity():
向PowerManagerService报告影响系统休眠的用户活动,重计算灭屏时间,背光亮度等,例如触屏,划屏,power键等用户活动;
d、Wakelock:
wakelock是PowerManager的一个内部类,提供了相关的接口来操作wakelock锁,比如newWakeLock()方法来创建wakelock锁,acquire()和release()方法来申请和释放锁;
e、isDeviceIdleMode():
返回设备当前的状态,如果处于Idle状态,则返回true,Idle状态是在手机长时间没有被使用以及没有运动的情况下,手机进入到一种Doze低功耗的模式下,这种状态下手机可能会关掉网络数据访问,可以通过监视DEVICE_IDLE_MODE_CHANGED这个广播信息,来监控手机状态的改变。
三、系统唤醒wakeup/睡眠goToSleep
1、PowerManager的wakeup接口,可供应用程序调用,来强制唤醒系统,如果该设备处于睡眠状态,调用该接口会立即唤醒系统,比如按Power键,来电,闹钟等场景都会调用该接口。PowerManager的wakeup接口属性是@hide的,所以对于上层应用是不可见的,上层应用要唤醒系统大都依靠两种方式:
(1)在应用启动Activity时候设置相应的window的flags,通过WMS来唤醒系统;
(2)在应用申请wakelock锁时附带ACQUIRE_CAUSES_WAKEUP标志。
/**
* @hide
*/
public void wakeUp(long time, String reason) {
try {
mService.wakeUp(time, reason, mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
在wakeUp中调用PowerManagerService的wakeUp方法如下:
public void wakeUp(long eventTime, String reason, String opPackageName) {
if (eventTime > SystemClock.uptimeMillis()) {
throw new IllegalArgumentException
("event time must not be in the future");
}
//检查android.Manifest.permission.DEVICE_POWER的权限
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.DEVICE_POWER, null);
final int uid = Binder.getCallingUid();
final long ident = Binder.clearCallingIdentity();
try {
//调用自身的wakeUpInternal接口
wakeUpInternal(eventTime, reason, uid, opPackageName, uid);
} finally {
Binder.restoreCallingIdentity(ident);
}
}
在wakeUpInternal中,通过wakeUpNoUpdateLocked来做唤醒系统的相关通知工作,最后调用PowerManagerService的核心接口updatePowerStateLocked来更新电源状态,从而完成亮屏前的图形绘制工作及亮屏动作。
private void wakeUpInternal(long eventTime, String reason, int uid, String opPackageName,
int opUid) {
synchronized (mLock) {
if (mIPOShutdown && reason != PowerManager.WAKE_UP_REASON_SHUTDOWN)
return;
if (wakeUpNoUpdateLocked(eventTime, reason, uid, opPackageName, opUid)) {
updatePowerStateLocked();
}
}
}
2、系统睡眠goToSleep
PowerManager的gotoSleep()接口是@hide属性,因此对于上层应用是不开放的,设备强制进入睡眠状态,在处理一些灭屏按键事件时,会通过WMS来调用PowerManager的gotoSleep接口,一般在系统一段时间没有被操作时,系统将会自动调用gotoSleep函数,让其进入到睡眠模式;与wakeup唤醒一样,PowerManager的gotoSleep()在PowerManagerService中处理,PMS中的gotoSleep()首先检查调用者是否拥有android.Manifest.permission.DEVICE_POWER权限。然后调用到goToSleepInternal()中处理:
/**
* @hide Requires signature permission.
*/
public void goToSleep(long time, int reason, int flags) {
try {
//调用PMS的goToSleep方法
mService.goToSleep(time, reason, flags);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
public void goToSleep(long eventTime, int reason, int flags) {
//检测权限android.Manifest.permission.DEVICE_POWER的权限
...
goToSleepInternal(eventTime, reason, flags, uid);
}
下面继续看goToSleepInternal,在goToSleepNoUpdateLocked()中完成发送了将要休眠的通知,然后修改了Wakefulness,将其置成WAKEFULNESS_DOZING,将mDirty |= DIRTY_WAKEFULNESS置位,更多的实际工作在updatePowerStateLocked()中完成。在updateDreamLocked中完成真正进入睡眠的过程:
private void goToSleepInternal(long eventTime, int reason, int flags, int uid) {
synchronized (mLock) {
if (mProximityPositive && reason ==
PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON) {
mDirty |= DIRTY_WAKEFULNESS;
mWakefulness = WAKEFULNESS_ASLEEP;
updatePowerStateLocked();
return;
}
if (goToSleepNoUpdateLocked(eventTime, reason, flags, uid)) {
updatePowerStateLocked();//PMS核心
}
}
}
三、系统睡眠唤醒策略wakelock
Android设备的休眠和唤醒主要基于WakeLock机制。WakeLock是一种上锁机制,只要有进程获得了WakeLock锁系统就不会进 入休眠。例如,在下载文件或播放音乐时,即使休眠时间到了,系统也不能进行休眠。WakeLock可以设置超时,超时后会自动解锁。
应用使用WakeLock功能前,需要先使用new WakeLock()接口创建一个WakeLock类对象,然后调用它的acquire()方法禁止系统休眠,应用完成工作后调用release()方法来恢复休眠机制,否则系统将无法休眠,直到耗光所有电量。WakeLock类中实现acquire()和release()方法实际上是调用了PowerManagerService的acquireWakeLock()和releaseWakeLock()方法。updatePowerStateLocked为PowerManagerService的核心函数;在执行完申请锁,释放锁,用户事件,强制唤醒/睡眠等操作都需要调用updatePowerStateLocked()来更新电源状态。
未完待续…
作者:frank_zyp
您的支持是对博主最大的鼓励,感谢您的认真阅读。
本文无所谓版权,欢迎转载。