androidPowerManager分析(十分详细)

androidPowerManager分析(⼗分详细)
(原创)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 = Name();
final T service;
Constructor<T> constructor = Constructor(Context.class);
service = wInstance(mContext);
mServices.add(service);//注册服务到服务列表中去
}
在启动PowerManagerService时,传⼊的参数类是PowerManagerService,在startService()中⾸先调⽤PowerManagerService的构造函数,然后调⽤其onStart()函数
PowerManagerServcie的构造函数:
mHandler = new Looper());
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());
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) SystemService(Context.POWER_SERVICE);
mScreenBrightnessSettingMinimum = pm.getMinimumScreenBrightnessSetting();
mScreenBrightnessSettingMaximum = pm.getMaximumScreenBrightnessSetting();
mScreenBrightnessSettingDefault = pm.getDefaultScreenBrightnessSetting();
获取与PowerManager相关的本地服务,⽐如屏保(mDreamManager),屏幕显⽰(mDisplayManagerInternal),窗⼝策略(mPolicy),电池电量(mBatteryManagerInternal)等服务,然后初始化屏幕最⼤亮度,最⼩亮度,和默认亮度;
SensorManager sensorManager = new SystemSensorManager(mContext, Looper());
mBatteryStats = Service();
mNotifier = new MainLooper(), mContext, mBatteryStats,
mAppOps, createSuspendBlockerLocked("PowerManagerService.Broadcasts"),
mPolicy);
mWirelessChargerDetector = new WirelessChargerDetector(sensorManager,
createSuspendBlockerLocked("PowerManagerService.WirelessChargerDetector"), mHandler);
mSettingsObserver = new SettingsObserver(mHandler);
mLightsManager = getLocalService(LightsManager.class);
mAttentionLight = Light(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接⼝的代码:
final int uid = CallingUid();
final long ident = Binder.clearCallingIdentity();
wakeUpInternal(eventTime, reason, uid, opPackageName, uid);
Wakeup接⼝中仅仅是对调⽤者的权限进⾏检查;然后放到wakeUpInternal()中处理,wakeUpInternal()中没有做操作,只是调⽤wakeUpNoUpdateLocked()函数,然后更新调⽤updatePowerStateLocked()更新电源状态
wakeUpNoUpdateLocked()关键代码
mLastWakeTime = eventTime;
setWakefulnessLocked(WAKEFULNESS_AWAKE, 0);
userActivityNoUpdateLocked(
eventTime, PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, reasonUid);
return true;
setWakefulnessLocked()函数将mWakefulness赋值为wakefulness和mD irty |= DIRTY_WAKEFULNESS;这两个标志在后⾯更新电源状态时有重要作⽤,同时调⽤到mNotifier中的onWakefulnessChangeStarted调⽤到handleEarlyInteractiveChange调⽤
到PhoneWindowManager的startedWakingUp函数,来通知到PhoneWindowManager屏幕开始启动;
调⽤mNotifier向系统中通知系统被唤醒;
更新⽤户活动,将mDirty |= DIRTY_USER_ACTIVITY置位;来重新计算亮屏时间。
在updatePowerStateLocked()中更新电源状态,updatePowerStateLocked为PowerManagerService
的核⼼函数,后⾯会详细介绍,这⾥简单介绍在wakeup中的流程。在updatePowerStateLocked()中的updateDisplayPowerStateLocked()函数中将mDisplayPowerRequest.policy设置成POLICY_BRIGHT;然后调⽤:
mDisplayReady = questPowerState(mDisplayPowerRequest,mRequestWaitForNegativeProximity);
通过调⽤到DisplayManagerService中对屏幕状态作出相应的改变,通过去与WindowManagerService执⾏亮屏之前的屏幕绘制过程,与LightServcie交互来点亮屏幕背光灯。其调⽤过程和具体逻辑在亮屏流程⽂档中有详细分析。
睡眠——goToSleep
PowerManager的gotoSleep()接⼝是@hide属性,因此对于上层应⽤是不开放的,设备强制进⼊睡眠状态,在处理⼀些灭屏按键事件时,会通过WMS来调⽤PowerManager的gotoSleep接⼝,⼀般在系统⼀段时间没有被操作时,系统将会⾃动调⽤gotoSleep函数,让其进⼊到睡眠模式;
与wakeup唤醒⼀样,PowerManager的gotoSleep()在PowerManagerService中处理,PMS中的gotoSleep()⾸先检查调⽤者是否拥有android.Manifest.permission.DEVICE_POWER 权限。然后调⽤到goToSleepInternal()中处理:
if (goToSleepNoUpdateLocked(eventTime, reason, flags, uid)) {空调衣
updatePowerStateLocked();
在goToSleepNoUpdateLocked()中完成发送了将要休眠的通知,然后修改了Wakefulness,将其置成WAKEFULNESS_DOZING,将mDirty |= DIRTY_WAKEFULNESS置位,更多的实际⼯作在updatePowerStateLocked()中完成。在updateDreamLocked中完成真正进⼊睡眠的过程;
其调⽤过程⼤致如下:
在reallyGoToSleepNoUpdateLocked中将mWakefulness置成WAKEFULNESS_ASLEEP,在updateWakeLockSummaryLocked中有如下:
if (mWakefulness == WAKEFULNESS_ASLEEP
|| (mWakeLockSummary & WAKE_LOCK_DOZE) != 0) {
mWakeLockSummary &= ~(WAKE_LOCK_SCREEN_BRIGHT | WAKE_LOCK_SCREEN_DIM
| WAKE_LOCK_BUTTON_BRIGHT);
闯红灯抓拍系统
将mWakeLockSummary列表中的wakelock锁所形成的集合变量mWakeLockSummary 中将WAKE_LOCK_SCREEN_BRIGHT,WAKE_LOCK_SCREEN_DIM,WAKE_LOCK_BUTTON_BRIGHT三种wakelock锁置为⽆效,再次调⽤updatePowerStateLocked更新电源状态时候,会在updateDisplayPowerStateLocked中做灭屏操作,其流程与wakeup唤醒系统亮屏操作流程⼤致⼀样。
⽤户活动——userActivity
userActivity()接⼝⽤于⽤户进程向PowerManagerService报告⽤户影响系统休眠的活动。例如,⽤户点击屏幕时,系统会调⽤该⽅法来告诉PowerManagerService⽤户点击的时间,这样PowerManagerService将更新内部保存的时间值,从⽽推迟系统休眠的时间。userActivity()⽅法主要通过调⽤内部的userActivityInternal()⽅法来完成⼯作。
在userActivityInternal()中并没有做任何操作,仅仅是将mLastUserActivityTime 更新为当前event的时间eventTime,mDirty |= DIRTY_USER_ACTIVITY;置位操作。具体操作仍然是在PowerManagerService中的核⼼函数updatePowerStateLocked()中完成;
在updateUserActivitySummaryLocked()中
final int sleepTimeout = getSleepTimeoutLocked();
final int screenOffTimeout = getScreenOffTimeoutLocked(sleepTimeout);
final int screenDimDuration = getScreenDimDurationLocked(screenOffTimeout);
mUserActivitySummary = 0;
if (mLastUserActivityTime >= mLastWakeTime) {
nextTimeout = mLastUserActivityTime
+ screenOffTimeout - screenDimDuration;
if (now < nextTimeout) {
mUserActivitySummary = USER_ACTIVITY_SCREEN_BRIGHT;
} else {
nextTimeout = mLastUserActivityTime + screenOffTimeout;
if (now < nextTimeout) {
mUserActivitySummary = USER_ACTIVITY_SCREEN_DIM;
}
}
重新计算睡眠超时时间,灭屏超时时间,暗屏超时时间,将m U s e r A c t i v i t y S u m m a r y 置为0,通过计算上⼀次的⽤户事件时间与超时时间作对⽐,来判断将屏幕置为亮屏 (USER_ACTIVITY_SCREEN_BRIGHT)还是暗屏(USER_ACTIVITY_SCREEN_DIM),前提是⼿机处于⾮睡眠状态。
if (mUserActivitySummary != 0 && nextTimeout >= 0) {
Message msg = mHandler.obtainMessage(MSG_USER_ACTIVITY_TIMEOUT);
msg.setAsynchronous(true);
mHandler.sendMessageAtTime(msg, nextTimeout);
}
如果时间还没到,则返回发送⼀个MSG_USER_ACTIVITY_TIMEOUT的定时消息,当处理时间到了,会在消息的处理⽅法handleUserActivityTimeout中重新调
⽤updatePowerStateLocked()电源状态。再次调⽤时会根据当前的状态重新计算mUserActivitySummary 的值。
控制系统休眠
Android设备的休眠和唤醒主要基于WakeLock机制。WakeLock是⼀种上锁机制,只要有进程获得了WakeLock锁系统就不会进⼊休眠。例如,在下载⽂件或播放⾳乐时,即使休眠时间到了,系统也不能进⾏休眠。WakeLock可以设置超时,超时后会⾃动解锁。
应⽤使⽤WakeLock功能前,需要先使⽤new WakeLock()接⼝创建⼀个WakeLock类对象,然后调⽤它的acquire()⽅法禁⽌系统休眠,应⽤完成⼯作后调⽤release()⽅法来恢复休眠机制,否则系统将⽆法休眠,直到耗光所有电量。
WakeLock类中实现acquire()和release()⽅法实际上是调⽤了PowerManagerService的acquireWakeLock()和releaseWakeLock()⽅法。updatePowerStateLocked为PowerManagerService的核⼼函数;在执⾏完申请锁,释放锁,⽤户事件,强制唤醒/睡眠等操作都需要调
⽤updatePowerStateLocked()来更新电源状态,
wakelock
Wakelock是android系统上特有的电源管理机制,只要有应⽤拿着这个锁,系统就不能进⼊睡眠状态,在上层不同的应⽤程序可以持有多个不同的wakelock锁,但是反映到底层就只有三种:控制系统休眠PowerManagerService.WakeLock,控制屏幕显⽰的PowerManagerService.Display和控制电源状态改变通知的PowerManagerService.Broadcasts。
PowerManagerService有加锁和解锁两种状态,加锁有两种⽅式:
第⼀种是永久的锁住,这样的锁除⾮显式的放开,否则是不会解锁的,所以这种锁⽤起来要⾮常的⼩⼼(默认)。
第⼆种锁是超时锁,这种锁会在锁住后⼀段时间解锁。
相关接⼝
newWakeLock():创建wakelock锁,当外界创建wakelock之前需要创建PowerManager的服务对象,然后其创建wakelock锁:
setReferenceCounted()设置计数锁和⾮计数锁;wakelock分为计数锁和⾮计数锁两种:计数锁是应⽤调⽤⼀次acquire申请必定会对应⼀个release来释放;⾮计数锁应⽤调⽤多
次acquire,调⽤⼀次release就可释放前⾯acquire的锁。在申请wakelock时默认申请的是计数锁。
飞羽辅助isHeld()判断⼀个wakelock锁是否acquire申请了,但是没有release释放;
acquire()和release()⽅法来申请和获取锁,acquire申请锁有两种:
acquire():申请wakelock永久锁(默认),需要⼿动release
acquire(long timeout) :申请wakelock超时锁,timeout为设置的超时时间,超时⾃动release掉该wakelock。

本文发布于:2024-09-25 13:19:42,感谢您对本站的认可!

本文链接:https://www.17tex.com/tex/4/253175.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:系统   状态   电源   屏幕   服务
留言与评论(共有 0 条评论)
   
验证码:
Copyright ©2019-2024 Comsenz Inc.Powered by © 易纺专利技术学习网 豫ICP备2022007602号 豫公网安备41160202000603 站长QQ:729038198 关于我们 投诉建议