Android 电源管理相关逻辑之PMS
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android 电源管理相关逻辑之PMS相关的知识,希望对你有一定的参考价值。
参考技术APowerManagerService是负责管理、协调设备电源管理的系统服务之一,设备常见功能如亮灭屏、亮度调节、低电量模式、保持CPU唤醒等,都会通过PMS的协调和处理。其继承自SystemService,因此具有SystemService子类的共性:具有生命周期方法,由SystemServer启动、注册到系统服务中,通过Binder和其他组件进行交互等。
和SystemService的其他子类一样,PMS由SystemServer通过反射的方式启动,看一下PMS的构造方法:
通过上面可以看到,在构造方法中首先创建了一个HandlerThread;其次获取了两个Suspend锁,SuspendBlocker是一种锁机制,只用于系统内部,上层申请的Wakelock锁在PMS中都会反映为SuspendBlocker锁。这里获取的两个Suspend锁在申请Wakelock时会用到;最后调用了native方法,这几个方法会通过JNI层调用到HAL层。
在该方法中,首先对该服务进行Binder注册和本地注册,当进行Binder注册后,在其他模块中就可以通过Binder机制获取其实例,同理,当进行本地注册后,只有在System进程才能获取到其实例;最后设置Watchdog的监听。
在这个方法中,设置mBootCompleted为true,表示启动完成,将mDirty置位,mDirty是一个二进制的标记位,用来表示电源状态哪一部分发生了改变,通过对其进行置位(|操作)、清零(~操作),得到二进制数各个位的值(0或1),进行不同的处理 ,然后执行updatePowerStateLocked()方法,这是整个PMS中最重要的方法,这块会在下文中具体功能中进行详细分析。
该方法内主要有5个重要功能 :
a.获取各类本地服务和远程服务,如屏保(DreamMangerService)、窗口(PhoneWindowManager)、电池状态监听服务(BatteryService)等服务,用于进行交互;
b.注册用于和其他Sytem交互的广播;
c.调用updateSettingsLocked()方法更新Settings中值的变化;
d.调用readConfigurationLocked()方法读取配置文件中的默认值;
e.注册SettingsObserver监听;
当通过系统设置等进行屏幕亮度调节时,会调用到PMS内部的updatePowerStateLocked(),通过该方法进行接下来的逻辑执行,最终通过HAL层来设置屏幕亮度,本文基于 android 8.1 版本进行分析:
当亮度调节时,处理逻辑主要是在phase 2,即updateDisplayPowerStateLocked(dirtyPhase2),一起看一下该方法:
该方法内部主要做了两件事:
a.封装DisplayPowerRequest实例mDisplayPowerRequest,包括通过
getDesiredScreenPolicyLocked()获取policy,此处为DisplayPowerRequest. POLICY_BRIGHT ;还有screenBrightness等;
b.调用DisplayManagerInternal的requestPowerState(),上步封装的DisplayPowerRequest作为参数传入,mDisplayManagerInternal是在systemReady()内部获取的;
DisplayManagerInternal内部的requestPowerState为抽象方法,因此会调用到实现类中,具体是在DisplayManagerService内部的LocalService,看一下具体实现:
最终会调用到DisplayPowerController内部的requestPowerState()方法:
在该方法内部先将传入的DisplayPowerRequest对象赋值给mPendingRequestLocked,后续会使用;接着执行sendUpdatePowerStateLocked(),在该方法内部会发送异步消息 MSG_UPDATE_POWER_STATE ,对应处理方法为updatePowerState();
该方法内部主要干了6件事:
a.将要更新的DisplayPowerRequest实例赋值给mPowerRequest;
b.如果为首次执行的话,需要执行initialize()来执行初始化操作,创建DisplayPowerState实例mPowerState、RampAnimator实例mScreenBrightnessRampAnimator等;
c.根据mPowerRequest.policy来更新state,此处为Display. STATE_ON ;
d.执行animateScreenStateChange(state, performScreenOffTransition)来更新DisplayPowerState;
e.根据策略进行选择,最终确定要更新的brightness值;
f.执行animateScreenBrightness(brightness,slowChange ? mBrightnessRampRateSlow : mBrightnessRampRateFast)来进行更新;
可以看到,在animateTo()内部会执行mProperty.setValue(mObject, target),mProperty对应的是
DisplayPowerState. SCREEN_BRIGHTNESS, mObject对应的是mPowerState,都是在DisplayPowerController内部的initialize()内部传入的,接下来就进入了DisplayPowerState内部了 ;
scheduleScreenUpdate()会执行到postScreenUpdateThreadSafe(),然后会post mScreenUpdateRunnable;
可以看到,在执行setState()后,最终会执行mBlanker.requestDisplayState(state, backlight),mBlanker是DisplayBlanker实例,初始化是在DisplayPowerController构造方法内,在DisplayPowerController内部的initialize()内部传入的,根据调用关系会追溯到DisplayMangerService的LocalService的initPowerManagerment()方法,该方法是在PowerManagerService的systemReady()方法内执行的;
由于传入的state为Display. STATE_ON ,执行到requestGlobalDisplayStateInternal(state, brightness),根据调用关系最终会执行到updateDisplayStateLocked()获取Runnable实例;
根据调用关系看到,会通过DisplayDevice的requestDisplayStateLocked()来获取到Runnable;
在DisplayManagerService的onStart()内发送消息来执行registerDisplayAdapterLocked(new LocalDisplayAdapter())加载 BUILT_IN_DISPLAY_IDS_TO_SCAN对应 的LocalDisplayDevice(继承DisplayDevice),加载成功后存入mDisplayDevices列表内进行管理;
在创建LocalDisplayDeivce时会通过lights.getLight(LightsManager. LIGHT_ID_BACKLIGHT )获取mBackLight,对应的是LightsService内部的LightImpl继承light;
在通过LocalDisplayDevice获取到Runnable后接着执行run(),会执行到setDisplayBrightness();
在setDisplayBrightness()内部会执行到mBacklight.setBrightness(brightness),具体实现逻辑是在LightsService内部;
最终通过native方法调用到HAL层对屏幕的背光进行设置。
不同的调节方式对应不同的入口及判断逻辑,只分析调用入口及涉及的关键策略来选择最终目标brightness值逻辑;
系统设置在调节屏幕亮度时,会实时更新Settings. SCREEN_BRIGHTNESS 值,DisplayPowerController在监听到该值变化后会执行handleSettingsChanged()方法:
监听到变化后,先通过getScreenBrightnessSetting()来获取到当前值,然后赋值给mPendingScreenBrightnessSetting,接下来执行sendUpdatePowerState(),最终执行updatePowerState()方法:
结论:系统设置会根据mCurrentScreenBrightnessSetting的值来设置对应的目标brightness值;
快速设置来滑动进度条来调节屏幕亮度时,会调用PowerManagerService的setTemporaryScreenBrightnessSettingOverride()方法:
跟随调用关系,调用到DisplayPowerController的setTemporaryBrightness()方法,发送 MSG_SET_TEMPORARY_BRIGHTNESS 消息,设置mTemporaryScreenBrightness为传入的值,然后执行updatePowerState():
结论:快速设置会根据mTemporaryScreenBrightness的值来设置对应的目标brightness值;
在视频播放界面可以通过左侧上下滑动来调节屏幕亮度,具体实现方式如下:
Window是activity对应的Window,通过getWindow()可以得到,设置WindowManager.LayoutParams内部的screenBrightness后执行window.setAttributes(lp)可以来调节屏幕亮度;
Window执行setAttributes()会执行到Activity的onWindowAttributesChanged()方法,调用到WindowManagerGlobal的updateViewLayout()最终调用到ViewRootImpl的setLayoutParams来执行重新绘制;
绘制流程就不陈述了,最终会执行到RootWindowContainer内部的performSurfacePlacement()方法,接下来通过handleNotObscuredLocked()获取到对应WindowState的w.mAttrs.screenBrightness赋值给mScreenBrightness,然后在performSurfacePlacement()发送 SET_SCREEN_BRIGHTNESS_OVERRIDE消息, 最终通过WindowManagerService来调用到PowerManagerService内部的setScreenBrightnessOverrideFromWindowManager()方法:
可以看到,在setScreenBrightnessOverrideFromWindowManagerInternal()内部会将brightness赋值给mScreenBrightnessOverrideFromWindowManager,然后执行updatePowerStateLocked(),先看
updateDisplayPowerStateLocked()方法:
可以看到,screenBrightness会设置为mScreenBrightnessOverrideFromWindowManager,该值默认为-1,经过设置后screenBrightness>0,接着执行到DisplayPowerController的updatePowerState()方法:
结论:Window属性调节会根据mScreenBrightnessOverrideFromWindowManager的值来设置对应的目标brightness值;
设置屏幕亮度时,主要是在DisplayPowerController内部的 updatePowerState() 来对目标screenBrightness进行设置,screenBrightness默认值为PowerManager.BRIGHTNESS_DEFAULT = -1,会根据DisplayPowerRequest及其他策略进行选择,顺序依次为:
a.if (brightness < 0 && mPowerRequest.screenBrightness >= 0): 通过设置Window属性来进行调节(视频播放界面)
b.if (mTemporaryScreenBrightness > 0): 通过快速设置滑动来进行调节
c.if (brightness < 0) brightness = clampScreenBrightness(mCurrentScreenBrightnessSetting): 通过系统设置滑动调节
当系统设置内部设置了自动进入屏保时间后,如果在此段时间后满足进入条件,会进入屏保,该逻辑入口是在PMS内部的updatePowerStateLocked(),一起看一下:
本流程只分析满足条件后进入屏保的整个过程,关于条件判断会在下一节中进行分析,先从updatePowerStateLocked()看起:
在该方法内部首先循环执行了三个方法:
a.updateWakeLockSummaryLocked():根据mWakeLocks来计算得到mWakeLockSummary的值;
b.updateUserActivitySummaryLocked():计算得到mUserActivitySummary以及何时进行下一次check;
c.updateWakefulnessLocked():判断是否可以进入屏保及更新mWakefulness状态;
d.updateDreamLocked():根据当前状态选择是否进入屏保;
当mWakefulness为 WAKEFULNESS_AWAKE 时,且isItBedTimeYetLocked(),即:副驾满足进入屏保的条件,看一下该方法的逻辑:
当满足以上条件后,执行napNoUpdateLocked():
设置mSandmanSummoned为true,更新当前mWakefulness状态 WAKEFULNESS_DREAMING ,最后返回true;
前面的循环中当结果返回true时,会执行下一次循环,重新计算mWakeLockSummary和mUserActivitySummary,最终返回false,执行break退出循环,执行updateDreamLocked();
满足条件后执行scheduleSandmanLocked()来发送异步消息,执行handleSandman(),mDisplayReady是在updateDisplayPowerStateLocked()内部最终通过DisplayPowerController内部返回的;
在handleSandman()先进行判断,满足条件后即startDreaming为true时,执行stopDream()、startDream(),接下来再执行wakeUpNoUpdateLocked(),一起看一下该方法的实现:
将mWakefulness更新为 WAKEFULNESS_AWAKE ;然后再执行 userActivityNoUpdateLocked()来更新user activity相关信息,接着上面进行分析,执行startDream()进入屏保;
在startDream()逻辑执行过程中首先获取到本地屏保实现的ComponentName,通过在core/res/res/values/config.xml内进行配置:
接下来最终通过DreamController的startDream()来启动;
可以看到在startDream()内部通过bindService()来启动本地实现的屏保服务SevenDreamService;
PMS AMS相关
以上是关于Android 电源管理相关逻辑之PMS的主要内容,如果未能解决你的问题,请参考以下文章
PMS服务之updatePowerStateLocked方法分析