(原创)android PowerManager分析(非常详细)
Posted 风雨田
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了(原创)android PowerManager分析(非常详细)相关的知识,希望对你有一定的参考价值。
概述
一直以来,电源管理是电子产品设计中非常重要的环节,也是任何电子设备中最为重要的系统模块之一,优秀的电源管理方案,能够提供持久的续航能力,良好的用户体验,更能提升电子产品的竞争力。
移动设备的电量主要由两种元件消耗:CPU和显示屏,因此设法降低这两种元件的耗电量就是电源管理的关键,为移动设备设计的CPU大多有两种工作频率,为了省电,大部分时间内cpu都工作在降低频率下,只有进行密集计算时,如视频解码才会切换到高频状态,而显示屏省电的方法是尽量减少亮屏时间,但是显示屏的开关和应用有很大的关系,因此系统中需要有一套机制来控制显示屏的开关和亮度,这也是电源管理的主要工作。
电源管理架构
android的电源管理主要是通过wakelock机制来管理系统的状态,整个android电源管理,可以分为四个层次:应用接口层(PowerManager.java),Framework层(PowerManagerService.java),HAL层(Power.c),和内核层(kernel/Power)。
应用接口层:PowerManager中开放给应用一系列接口,应用可以调用PM的接口申请wakelock,唤醒系统,使系统进入睡眠等操作;
Framework层:应用调用PowerManager开放的接口,来对系统进行一些列的操作是在PowerManagerService中完成的,PowerManagerService计算系统中和Power相关的计算,是整个电源管理的决策系统。同时协调Power如何与系统其它模块的交互,比如亮屏,暗屏,系统睡眠,唤醒等等。
HAL层:该层只有一个power.c文件,该文件通过上层传下来的参数,向/sys/power/wake_lock或者/sys/power/wake_unlock文件节点写数据来与kernel进行通信,主要功能是申请/释放锁,维持屏幕亮灭
Kernel层:内核层实现电源管理的方案主要包含三个部分:
1、Kernel/power/:实现了系统电源管理框架机制。
2、Arch/arm(ormips or powerpc)/mach-XXX/pm.c:实现对特定板的处理器电源管理。
3、drivers/power:是设备电源管理的基础框架,为驱动提供了电源管理接口。
Android电源管理框架如下图:
电源管理服务——PowerManagerService
PowerManagerServcie是android系统电源管理的核心服务,它在Framework层建立起一个策略控制方案,向下决策HAL层以及kernel层来控制设备待机状态,控制显示屏,背光灯,距离传感器,光线传感器等硬件设备的状态。向上提供给应用程序相应的操作接口,比如听音乐时持续保持系统唤醒,应用通知来临唤醒手机屏幕等场景
启动过程
SystemServer在系统启动的时候会启动三类服务:引导关键服务,核心服务,其他服务;PowerManagerService是在SystemServer中创建的,并将其作为一个系统服务加入到ServiceManager中:
mPowerManagerService = mSystemServiceManager.startService(PowerManagerService.class);
在启动引导关键服务调用startBootstrapServices(),其中各种服务都是通过SystemServiceManager中的startService()函数来启动:
public <T extends SystemService> T startService(Class<T> serviceClass) {
final String name = serviceClass.getName();
final T service;
Constructor<T> constructor = serviceClass.getConstructor(Context.class);
service = constructor.newInstance(mContext);
mServices.add(service);//注册服务到服务列表中去
service.onStart();//启动服务
}
在启动PowerManagerService时,传入的参数类是PowerManagerService,在startService()中首先调用PowerManagerService的构造函数,然后调用其onStart()函数
PowerManagerServcie的构造函数:
mHandler = new PowerManagerHandler(mHandlerThread.getLooper());
synchronized (mLock) {
mWakeLockSuspendBlocker = createSuspendBlockerLocked("PowerManagerService.WakeLocks");
mDisplaySuspendBlocker = createSuspendBlockerLocked("PowerManagerService.Display");
mDisplaySuspendBlocker.acquire();
mWakefulness = WAKEFULNESS_AWAKE;
nativeInit();
创建一个处理消息和发送消息的线程mHandler,并且两种标志flag的wakelock锁:PowerManagerService.WakeLocks和PowerManagerService.Display,前者是传入到底层是控制cpu唤醒状态,后者则是控制屏幕亮灭。在构造函数最后调用nativeInit();在native层初始化相关资源。将mWakefulness 置成WAKEFULNESS_AWAKE状态,mWakefulness 标识系统当前状态共有四种定义:
WAKEFULNESS_ASLEEP:表示系统当前处于休眠状态,只能被wakeUp()调用唤醒。
WAKEFULNESS_AWAKE:表示系统目前处于正常运行状态。
WAKEFULNESS_DREAMING:表示系统当前正处于屏保的状态。
WAKEFULNESS_DOZING:表示系统正处于“doze”状态。这种状态下只有低耗电的“屏保”可以运行,其他应用进程都被挂起。
在SystemServer中startService中调用到PowerManagerService构造函数做完初始化操作之后便会调用PowerManagerService的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是否空闲;
系统准备工作
SystemServer在调用PowerManagerService之后还会调用其SystemReady,相当于在系统准备就绪后对PowerManagerService再进行一些初始化工作。SystemReady()方法代码如下:
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();
获取与PowerManager相关的本地服务,比如屏保(mDreamManager),屏幕显示(mDisplayManagerInternal),窗口策略(mPolicy),电池电量(mBatteryManagerInternal)等服务,然后初始化屏幕最大亮度,最小亮度,和默认亮度;
SensorManager sensorManager = new SystemSensorManager(mContext, mHandler.getLooper());
mBatteryStats = BatteryStatsService.getService();
mNotifier = new Notifier(Looper.getMainLooper(), mContext, mBatteryStats,
mAppOps, createSuspendBlockerLocked("PowerManagerService.Broadcasts"),
mPolicy);
mWirelessChargerDetector = new WirelessChargerDetector(sensorManager,
createSuspendBlockerLocked("PowerManagerService.WirelessChargerDetector"), mHandler);
mSettingsObserver = new SettingsObserver(mHandler);
mLightsManager = getLocalService(LightsManager.class);
mAttentionLight = mLightsManager.getLight(LightsManager.LIGHT_ID_ATTENTION);
创建sensorManager 对象,用于与sensor交互,比如距离传感器,光线传感器,加速度传感器(doze上使用)。获取电池状态服务,和背光服务;
创建mNotifier 对象,在通过mNotifier 发送通知时候,会传入底层申请PowerManagerService.Broadcasts的wakelock锁。
创建mSettingsObserver 监听系统设置变化,比如亮屏时间,自动背光,屏幕亮度,屏保,低电模式等等
总而言之在SystemReady方法中完成的主要工作如下:
获取与PowerManagerServcie相关的系统服务以及本地服务;
获取屏幕最大,最小以及默认亮度值;
创建SensorManager 对象,用于和SensorService交互;
创建Notifier对象,用于通知系统中电源状态的改变;
创建WirelessChargerDetector对象,用于检测无线充电的传感器(市面上支持的手机较少)
调用DisplayManagerService的initPowerManagement()方法来初始化Power显示模块。
注册SettingsObserver监听系统设置的变化
PowerManagerServcie的启动初始化过程如下:
相关接口
PowerManager向应用提供了相应的接口,以供应用程序调用,来改变系统待机状态,屏幕状态,屏幕亮度等,PowerManager是PowerManagerService的代理类,PowerManager向上层应用提供交互的接口,具体的处理工作在PowerManagerService中完成。下面介绍PowerManager中提供的相应接口作用:
Wakeup():强制系统从睡眠状态唤醒,此接口对应用是不开放的,应用想唤醒系统必须通过设置亮屏标志(后面即将讲到);
gotoSleep():强制系统进入到睡眠状态,此接口也是应用不开放。
userActivity():向PowerManagerService报告影响系统休眠的用户活动,重计算灭屏时间,背光亮度等,例如触屏,划屏,power键等用户活动;
Wakelock:wakelock是PowerManager的一个内部类,提供了相关的接口来操作wakelock锁,比如newWakeLock()方法来创建wakelock锁,acquire()和release()方法来申请和释放锁。
isDeviceIdleMode():返回设备当前的状态,如果处于Idle状态,则返回true,Idle状态是在手机长时间没有被使用以及没有运动的情况下,手机进入到一种Doze低功耗的模式下,这种状态下手机可能会关掉网络数据访问,可以通过监视DEVICE_IDLE_MODE_CHANGED这个广播信息,来监控手机状态的改变
唤醒——wakeup
PowerManager的wakeup接口属性是@hide的,所以对于上层应用是不可见的,上层应用要唤醒系统大都依靠两种方式:1.在应用启动Activity时候设置相应的window的flags,通过WMS来唤醒系统;2.在应用申请wakelock锁时附带ACQUIRE_CAUSES_WAKEUP标志;
Wakeup流程如下图所示
PowerManager的wakeup接口,可供应用程序调用,来强制唤醒系统,如果该设备处于睡眠状态,调用该接口会立即唤醒系统,比如按Power键,来电,闹钟等场景都会调用该接口。唤醒系统需要android.Manifest.permission#DEVICE_POWER的权限;
我们来看看PowerManagerServcie中wakeup接口的代码:
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER, null);
final int uid = Binder.getCallingUid();
final long ident = Binder.clearCallingIdentity();
wakeUpInternal(eventTime, reason, uid, opPackageName, uid);
Wakeup接口中仅仅是对调用者的权限进行检查;然后放到wakeUpInternal()中处理,wakeUpInternal()中没有做操作,只是调用wakeUpNoUpdateLocked()函数,然后更新调用updatePowerStateLocked()更新电源状态
wakeUpNoUpdateLocked()关键代码
mLastWakeTime = eventTime;
setWakefulnessLocked(WAKEFULNESS_AWAKE, 0);
以上是关于(原创)android PowerManager分析(非常详细)的主要内容,如果未能解决你的问题,请参考以下文章