Android 电源管理相关逻辑之PMS

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android 电源管理相关逻辑之PMS相关的知识,希望对你有一定的参考价值。

参考技术A

       PowerManagerService是负责管理、协调设备电源管理的系统服务之一,设备常见功能如亮灭屏、亮度调节、低电量模式、保持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相关

PackageManagerService

ContextWrapper和ContextImpl是怎么关联起来的

ContextWrapper中有一个变量mBase,实际就是ContextImpl对象,是何时赋值的?

startService简单流程

以上是关于Android 电源管理相关逻辑之PMS的主要内容,如果未能解决你的问题,请参考以下文章

PMS服务之updatePowerStateLocked方法分析

Android系统服务(SystemService)简介

Android:PowerManager类 电源管理

RK3399平台开发系列讲解(电源管理篇)11.6wakelock详解

Android N DisplayManager服务解析

Android N DisplayManager服务解析