欢迎来真孝善网,为您提供真孝善正能量书籍故事!

Android R版PowerManagerService模块启动流程与关键方法解析

时间:11-03 民间故事 提交错误

各位老铁们,大家好,今天由我来为大家分享Android R版PowerManagerService模块启动流程与关键方法解析,以及的相关问题知识,希望对大家有所帮助。如果可以帮助到大家,还望关注收藏下本站,您的支持是我们最大的动力,谢谢大家了哈,下面我们开始吧!

所有SystemService类在启动过程中都会依次执行以下生命周期方法:

构造方法:通过反射调用获取实例; onstart()方法:启动对应的SystemService; onBootPhase()方法:指定SystemService服务启动过程中服务的启动阶段,并指定每个阶段的具体工作;

1.PMS的启动流程

当system_server启动后,PMS将由SystemServer通过反射启动。

首先在SystemServer的main()方法中,调用了自己的run()方法,在run()方法中启动了三类服务:

引导服务:对其他系统服务依赖度较高的服务;核心服务:一些依赖度较低的基本必需服务;其他服务:一些杂乱的系统服务; //框架/base/services/java/com/android/server/SystemServer.java

私有无效运行(){

//.

尝试{

startBootstrapServices();//启动开机服务

startCoreServices();//启动核心服务

startOtherServices();//启动其他服务

} catch(可抛出的前){

}

.

其中,PMS:包含在开机服务的启动中。

//框架/base/services/java/com/android/server/SystemServer.java

私有无效startBootstrapServices(){

//通过SystemManagerService启动PMS服务

mPowerManagerService=mSystemServiceManager.startService(PowerManagerService.class);

}可见其他服务对PMS的依赖度还是很高的。

在SystemServiceManager的startService()方法中,会通过反射获取PMS对象:

公共SystemService startService(字符串类名){

最终类服务类;

serviceClass=(Class)Class.forName(className);

返回startService(serviceClass);

}

publicT startService(ClassserviceClass) {

尝试{

最终字符串名称=serviceClass.getName();

//创建服务。

最后的T服务;

尝试{

//创建PMS对象

构造函数constructor=serviceClass.getConstructor(Context.class);

服务=构造函数.newInstance(mContext);

} catch (InstantiationException ex) {

}

启动服务(服务);

退货服务;

}

}

公共无效startService(@NonNull最终SystemService服务){

//注册它。

mServices.add(服务);

//启动它。

长时间=SystemClock.elapsedRealtime();

尝试{

//执行onStart()

service.onStart();

} catch (RuntimeException ex) {

}

}获取PMS实例后,首先将该实例添加到一个ArrayList中,ArrayList中存储了所有的SystemServices。在后续的启动过程中,会对整个List中的元素进行方法回调。

然后,调用PMS的onStart()方法。我们分别看一下这两个方法的内容。

1.1. 构造方法进行初始化

PMS施工方法如下:

//框架/base/services/core/java/com/android/server/power/PowerManagerService.java

PowerManagerService(上下文上下文,注入器注入器){

超级(上下文);

mContext=上下文;

mBinderService=new BinderService(); //用于IPC交互

mLocalService=new LocalService(); //用户跨线程交互

//创建NativeWrapper对象来管理所有原生交互

mNativeWrapper=注入器.createNativeWrapper();

//内部类Injector对象,管理其他对象的创建

mInjector=注射器;

//创建PMS主线程

mHandlerThread=新ServiceThread(TAG,

Process.THREAD_PRIORITY_DISPLAY, false /*allowIo*/);

mHandlerThread.start();

//创建PMS主线程Handler

mHandler=new PowerManagerHandler(mHandlerThread.getLooper());

//管理Settings.Global下的常量

mConstants=new Constants(mHandler);

//创建AmbientDisplayConfiguration对象来管理一些显示配置,例如AOD

mAmbientDisplayConfiguration=mInjector.createAmbientDisplayConfiguration(context);

//创建一个AttentionDetector对象来检查用户活动是否需要更新。

mAttentionDetector=new AttentionDetector(this:onUserAttention, mLock);

//创建BatterySavingStats对象来记录电池消耗率

mBatterySavingStats=new BatterySavingStats(mLock);

//创建BatterySaverPolicy对象来管理一些省电策略

mBatterySaverPolicy=

mInjector.createBatterySaverPolicy(mLock, mContext, mBatterySavingStats);

//创建BatterySaverController对象来管理省电策略的切换

mBatterySaverController=新的BatterySaverController(mLock, mContext,

BackgroundThread.get().getLooper(), mBatterySaverPolicy,

mBatterySavingStats);

//创建BatterySaverStateMachine对象,负责开启/关闭省电策略

mBatterySaverStateMachine=新的BatterySaverStateMachine(

mLock、mContext、mBatterySaverController);

同步(mLock){

//创建SuspendBlockerImpl对象,WakeLock的最终反射,"PowerManagerService.WakeLocks"类型对象负责保持CPU存活

mWakeLockSuspendBlocker=

mInjector.createSuspendBlocker(this, "PowerManagerService.WakeLocks");

//创建一个SuspendBlockerImpl对象。 “PowerManagerService.Display”类型对象负责保持屏幕打开。

mDisplaySuspendBlocker=

mInjector.createSuspendBlocker(this, "PowerManagerService.Display");

if (mDisplaySuspendBlocker !=null) {

//应用mDisplaySuspendBlocker保持屏幕常亮

mDisplaySuspendBlocker.acquire();

mHoldingDisplaySuspendBlocker=true;

}

//自动挂起模式是否可用?

mHalAutoSuspendModeEnabled=false;

//是否为交互状态

mHalInteractiveModeEnabled=true;

//设置设备状态为唤醒状态

mWakeiness=WAKEFULNESS_AWAKE;

//静音模式会控制背光的点亮,使用场景不多。

sQuiescent=SystemProperties.get(SYSTEM_PROPERTY_QUIESCENT, "0").equals("1");

//mNativeWrapper对象执行native层初始化工作

mNativeWrapper.nativeInit(this);

mNativeWrapper.nativeSetAutoSuspend(false); //设置自动挂起状态

mNativeWrapper.nativeSetInteractive(true); //设置交互状态

mNativeWrapper.nativeSetFeature(POWER_FEATURE_DOUBLE_TAP_TO_WAKE, 0);//设置双击唤醒Feature状态

}

}上述方法中,做了很多初始化工作,主要如下:

在system_server进程中创建用于IPC的BinderService对象和用于跨线程交互的LocalService对象;创建PMS主线程,并使用HandlerThread的Looper实例化PowerManagerHandler,将其作为PMS主线程Handler处理Message;读取相关配置参数,例如系统配置各种亮度参数;获得两个Suspend锁对象。 SuspendBlocker 是一种锁定机制。上层申请的wakelock会在PMS中体现为SuspendBlocker锁;与底层的状态交互是通过mNativeWrapper对象进行的。

1.2.onStart()方法注册服务

构造方法执行完毕后,执行onStart()方法:

//框架/base/services/core/java/com/android/server/power/PowerManagerService.java

@覆盖

公共无效onStart() {

//发布到系统服务

publishBinderService(Context.POWER_SERVICE, mBinderService);

//发布到本地服务

publishLocalService(PowerManagerInternal.class, mLocalService);

//设置Watchdog监控

Watchdog.getInstance().addMonitor(this);

Watchdog.getInstance().addThread(mHandler);

}该方法中会注册PMS的Binder服务和Local服务。 BinderService注册后,可以通过其他模块中的ServiceManager获取对应的Binder对象,进行IPC通信; LocalService注册后,system_server进程就可以通过获取LocalService对象进行跨线程交互。

PMS中的BinderService是一个继承自IPowerManager.Stub的内部类BinderService。 IPowerManager.Stub继承自Binder并实现了IPowerManager。因此,PMS与其他模块的跨进程交互实际上是通过PMS.BinderService来实现的。

Binder的注册过程是在ServiceManager中进行的:

//框架/base/core/java/android/os/ServiceManager.java

@UnsupportedAppUsage

公共静态无效addService(字符串名称,IBinder服务,布尔allowIsolated,

int 转储优先级) {

尝试{

getIServiceManager().addService(名称、服务、allowIsolated、dumpPriority);

} catch (RemoteException e) {

Log.e(TAG, "addService 错误", e);

}

}通过ServiceManager注册后,可以基于Context.POWER_SERVICE获取其他服务中的IPowerManager.Stub对象,进行跨进程交互。

LocalService用于system_server进程的内部交互。注册的对象是LocalService,另一个继承自PowerManagerInternal的内部类——(带有Internal的类一般在System进程内使用)。 LocalService的注册是在LocalServices中进行的。注册方法如下:

//框架/base/core/java/com/android/server/LocalServices.java

公共staticvoid addService(Classtype, T 服务) {

同步(sLocalServiceObjects){

if (sLocalServiceObjects.containsKey(type)) {

throw new IllegalStateException("覆盖服务注册");

}

//添加到地图

sLocalServiceObjects.put(类型,服务);

}

}可以看到,Local Service的注册是直接添加到一个Map中的。

1.3.onBootPhase()进行各个启动阶段的处理

返回SytemServer,startBootstrapServices()方法中PMS的实例化和注册过程完成。接下来SystemService的生命周期就会开始执行onBootPhase()。该方法实例化并注册为所有服务设置启动阶段,以在不同的启动阶段执行不同的任务。方法如下:

//框架/base/services/core/java/com/android/server/SystemServiceManager.java

公共无效startBootPhase(最终int阶段){

mCurrentPhase=相位;

尝试{

最终int serviceLen=mServices.size();

for (int i=0; i serviceLen; i++) {

//遍历并调用SystemService的onBootPhase()

最终SystemService 服务=mServices.get(i);

尝试{

service.onBootPhase(mCurrentPhase);

} catch (异常前) {

}

}

} 最后{

}

}在SystemServiceManager#startBootPhase()中,通过传入SystemServiceManager中不同的形参,遍历SystemServiceManager#mServices列表,调用各个SystemService#onBootPhase(int)方法,根据参数完成方法实现中的不同任务。 SystemService中定义了代表启动阶段的七个参数:

PHASE_WAIT_FOR_DEFAULT_DISPLAY:第一个启动阶段用于确保在启动PKMS 之前已经存在默认逻辑屏幕。只有DisplayManagerService 使用此阶段; PHASE_LOCK_SETTINGS_READY:第二启动阶段。该阶段的执行意味着Lock Pattern/Password相关服务已经准备好,只有DisplayManagerService使用该阶段; PHASE_SYSTEM_SERVICES_READY:第三个启动阶段,该阶段的执行,意味着其他服务可以安全地使用核心系统服务; PHASE_DEVICE_SPECIFIC_SERVICES_READY:第四个启动阶段,该阶段的执行,意味着这个其他服务可以安全地使用设备指定的一些系统服务,这些服务是在config_deviceSpecificSystemServices中配置的; PHASE_ACTIVITY_MANAGER_READY:第五启动阶段。该阶段的执行意味着其他AMS组件已经启动,可以进行广播操作; PHASE_THIRD_PARTY_APPS_CAN_START:第六个启动阶段,该阶段的执行,意味着系统可以启动APP,并且可以进行服务的bind/start操作; PHASE_BOOT_COMPLETED:第六个启动阶段,该阶段的执行,意味着启动完成,Home应用也已经启动,可以与设备进行交互了。 PMS#onBootPhase() 方法仅处理上述两个阶段:

//框架/base/services/core/java/com/android/server/power/PowerManagerService.java

@覆盖

公共无效onBootPhase(int阶段){

同步(mLock){

如果(阶段==PHASE_THIRD_PARTY_APPS_CAN_START){

//统计系统启动次数,可以通过adb shell settings get global boot_count查看

增量BootCount();

} else if (phase==PHASE_BOOT_COMPLETED) {

现在最终长=SystemClock.uptimeMillis();

mBootCompleted=true; //表示启动完成

//mDirty 是一个位标记

mDirty |=DIRTY_BOOT_COMPLETED;

mBatterySaverStateMachine.onBootCompleted();

//更新用户活动时间

用户活动NoUpdateLocked(

现在,PowerManager.USER_ACTIVITY_EVENT_OTHER,0,Process.SYSTEM_UID);

//更新全局状态信息

更新PowerStateLocked();

}

}

}mDirty 是一个二进制标志位,用于指示哪部分电源状态发生了变化。通过设置(|操作)和清除(操作),获得二进制数(0或1)的各个位的值。执行不同的处理,这个变量非常重要。

最后调用的是updatePowerStateLocked()方法,该方法是整个PMS中最重要的方法,下面会详细分析。

此时,在系统启动过程中

Service的生命周期方法全部执行完毕。

1.4. sytemReady()方法

对于PMS的启动,当执行完生命周期方法后,在SystemServer.startOtherServices()中还进行了一步操作: private void startOtherServices() { // ...... mPowerManagerService.systemReady(mActivityManagerService.getAppOpsService()); // ...... }这个方法中主要做了以下几个操作,相关方法代码就不再粘贴: 获取各类本地服务和远程服务,如Dreamland服务(DreamMangerService)、窗口服务(PhoneWindowManager)、电池状态监听(BatteryService)等服务;注册用于和其他SytemService交互的广播;调用updateSettingsLocked()方法更新Settings中值的变化;调用readConfigurationLocked()方法读取配置文件中的默认值;注册SettingsObserver监听;到此为止,PMS的启动过程完成。 以上过程时序图如下: start-pms.jpg

2.核心方法updatePowerStateLocked()

updatePowerStateLocked()方法是整个PMS模块的核心方法,也是整个PSM中最重要的一个方法,它用来更新整个Power状态。当Power状态发生改变时,如亮灭屏、电池状态改变、暗屏、WakeLock锁申请/释放......都会调用该方法,并调用其他同级方法进行各个状态的更新: // frameworks/base/services/core/java/com/android/server/SystemService.java private void updatePowerStateLocked() { if (!mSystemReady || mDirty == 0) { // 当mDirty变量值为0时,不进行任何更新 return; } try { // Phase 0: 基本状态的更新 updateIsPoweredLocked(mDirty); // 更新充电状态 updateStayOnLocked(mDirty); // 更新当前是否为屏幕常亮状态,由mStayOn控制 updateScreenBrightnessBoostLocked(mDirty); // 更新是否需要增强亮度变量 // Phase 1: 更新唤醒状态 // by changes in wakefulness. final long now = mClock.uptimeMillis(); int dirtyPhase2 = 0; // 循环进行更新流程,直到updateWakefulnessLocked()返回false for (;;) { int dirtyPhase1 = mDirty; dirtyPhase2 |= dirtyPhase1; mDirty = 0; //清空标记 // 更新用于统计wakelock的标记值mWakeLockSummary属性 updateWakeLockSummaryLocked(dirtyPhase1); // 更新用于统计用户活动状态的标记值mUserActivitySummary属性 updateUserActivitySummaryLocked(now, dirtyPhase1); // 更新细微模式状态

updateAttentiveStateLocked(now, dirtyPhase1); // 更新唤醒状态,如果状态改变返回true if (!updateWakefulnessLocked(dirtyPhase1)) { break; } } // Phase 2: updateProfilesLocked(now); // Phase 3: 更新display状态 final boolean displayBecameReady = updateDisplayPowerStateLocked(dirtyPhase2); // Phase 4: 更新Dreamland状态 updateDreamLocked(dirtyPhase2, displayBecameReady); // Phase 5: 如果wakefulness改变,做最后的收尾工作 finishWakefulnessChangeIfNeededLocked(); // Phase 6: 更新SuspendBlocker锁状态 updateSuspendBlockerLocked(); } }下面对以上所有方法逐个进行分析。

2.1. updateIsPoweredLocked()更新充电状态

这个方法用于更新mIsPowered属性,它代表当前的充电状态。插拔USB点亮屏幕功能的逻辑,就是在这个方法中。该方法如下: // frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java private void updateIsPoweredLocked(int dirty) { if ((dirty & DIRTY_BATTERY_STATE) != 0) { // 只有有标记位DIRTY_BATTERY_STATE时,才会执行这个方法 // 记录旧值 final boolean wasPowered = mIsPowered; // 是否充电 final int oldPlugType = mPlugType; // 充电类型 final boolean oldLevelLow = mBatteryLevelLow; // 是否小于低电量阈值 // 获取新值 mIsPowered = mBatteryManagerInternal.isPowered(BatteryManager.BATTERY_PLUGGED_ANY); mPlugType = mBatteryManagerInternal.getPlugType(); mBatteryLevel = mBatteryManagerInternal.getBatteryLevel(); // 当前电量 mBatteryLevelLow = mBatteryManagerInternal.getBatteryLevelLow(); if (wasPowered != mIsPowered || oldPlugType != mPlugType) { // 说明充电状态发生变化 mDirty |= DIRTY_IS_POWERED; // 设置标记位DIRTY_IS_POWERED // 更新无线充电状态 final boolean dockedOnWirelessCharger = mWirelessChargerDetector.update( mIsPowered, mPlugType); final long now = SystemClock.uptimeMillis(); // 插拔USB是否需要亮屏 if (shouldWakeUpWhenPluggedOrUnpluggedLocked(wasPowered, oldPlugType, dockedOnWirelessCharger)) { // 亮屏流程 wakeUpNoUpdateLocked(now, PowerManager.WAKE_REASON_PLUGGED_IN, "android.server.power:PLUGGED:" + mIsPowered, Process.SYSTEM_UID, mContext.getOpPackageName(), Process.SYSTEM_UID); } // 更新用户活动时间 userActivityNoUpdateLocked( now, PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, Process.SYSTEM_UID); // 播放充电提示音和动画 if (mBootCompleted) { //只有在启动完成后,才会播放 if (mIsPowered && !BatteryManager.isPlugWired(oldPlugType) && BatteryManager.isPlugWired(mPlugType)) { mNotifier.onWiredChargingStarted(mForegroundProfile); } else if (dockedOnWirelessCharger) { mNotifier.onWirelessChargingStarted(mBatteryLevel, mForegroundProfile); } } } // 将充电状态更新给BatterySaverStateMachine mBatterySaverStateMachine.setBatteryStatus(mIsPowered, mBatteryLevel, mBatteryLevelLow); } }只有对mDirty设置了DIRTY_BATTERY_STATE标记时,那么DIRTY_BATTERY_STATE在什么时候会设置呢?当电池信息变化后,由healthd模块上报给BatteryService,BatteryService中则会发出广播Intent.ACTION_BATTERY_CHANGED来通知其他组件,PMS中会接收这个广播并作出处理: // frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java private void handleBatteryStateChangedLocked() { mDirty |= DIRTY_BATTERY_STATE; updatePowerStateLocked(); }因此,只要电池状态发生变化,就会执行这个方法。在这个方法中: 首先,更新一些如mIsPowered等全局变量。然后,通过shouldWakeUpWhenPluggedOrUnpluggedLocked()方法判断是否需要亮屏,这就是插拔USB点亮屏幕功能的逻辑。接下来,执行userActivityNoUpdateLocked()方法更新用户活动时间,这个时间决定了何时会自动灭屏,用户每次操作手机(触摸、按键、Other)都会更新到当前时间,用户最后活动时间 + 设置自动休眠时间 = 最终自动灭屏的时间点,这个方法会在后面部分分析。再接下来,则调用Notifier对象播放插拔USB音效或动画,Notifier类是PMS模块中用于发送广播、异步通知其他组件的一个类。最后,将充电状态传递给mBatterySaverStateMachine中,进行省电策略的调整。

2.2.updateStayOnLocked()更新屏幕常亮状态

这个方法用来更新全局变量mStayOn的值,"开发者选项—不锁定屏幕"这个选项开启后,则在充电时将保持常亮不会自动休眠: // frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java private void updateStayOnLocked(int dirty) { if ((dirty & (DIRTY_BATTERY_STATE | DIRTY_SETTINGS)) != 0) { final boolean wasStayOn = mStayOn; if (mStayOnWhilePluggedInSetting != 0 && !isMaximumScreenOffTimeoutFromDeviceAdminEnforcedLocked()) { // 如果任意方式充电(AC/USB/wireless),返回true mStayOn = mBatteryManagerInternal.isPowered(mStayOnWhilePluggedInSetting); } else { mStayOn = false; } // 状态发生变化时,向mDirty设置DIRTY_STAY_ON标记 if (mStayOn != wasStayOn) { mDirty |= DIRTY_STAY_ON; } } }只有mDirty设置了DIRTY_BATTERY_STATE或DIRTY_SETTINGS标记位后,才会执行该方法。DIRTY_BATTERY_STATE在电池状态发生变化后设置,DIRTY_SETTINGS是在Settings中的值发生变化后设置,mStayOnWhilePluggedInSetting就是从来自于Settings中"不锁定屏幕"的值,如果发生变化,且处于充电状态,则会更新mStayOn变量的值。在自动灭屏流程中,一旦mStayOn值为true,则永远不会灭屏,从而实现了“不锁定屏幕”这个功能。

2.3.updateScreenBrightnessBoostLocked()更新是否增强亮度

这个方法会更新表示增强亮度的全局变量mScreenBrightnessBoostInProgress,PMS.BinderService提供了boostScreenBrightness()方法,允许其他组件通过该接口将亮度调节到最大,并保持5s后恢复: // frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java private void updateScreenBrightnessBoostLocked(int dirty) { if ((dirty & DIRTY_SCREEN_BRIGHTNESS_BOOST) != 0) { if (mScreenBrightnessBoostInProgress) { final long now = SystemClock.uptimeMillis(); mHandler.removeMessages(MSG_SCREEN_BRIGHTNESS_BOOST_TIMEOUT); if (mLastScreenBrightnessBoostTime >mLastSleepTime) { final long boostTimeout = mLastScreenBrightnessBoostTime + SCREEN_BRIGHTNESS_BOOST_TIMEOUT; // 5s后会再次更新 if (boostTimeout >now) { Message msg = mHandler.obtainMessage(MSG_SCREEN_BRIGHTNESS_BOOST_TIMEOUT); msg.setAsynchronous(true); mHandler.sendMessageAtTime(msg, boostTimeout); return; } } // 表示增强亮度结束 mScreenBrightnessBoostInProgress = false; mNotifier.onScreenBrightnessBoostChanged(); // 更新用户活动时间 userActivityNoUpdateLocked(now, PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, Process.SYSTEM_UID); } } }只有当mDirty设置了DIRTY_SCREEN_BRIGHTNESS_BOOST标记时,才会执行这个方法。这个标记位就是通过boostScreenBrightness()设置,这个功能在Google原生逻辑中有一个使用场景: // frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java mDoublePressOnPowerBehavior = mContext.getResources().getInteger( com.android.internal.R.integer.config_doublePressOnPowerBehavior);将config_doublePressOnPowerBehavior配置为2后,双击power键会通过上述方法将增强亮度到最大。

2.4.updateWakeLockSummaryLocked()更新WakeLock统计值

从这个方法开始到,直到updateWakefulnessLocked()结束,将会在一个for循环中执行。 该方法用来更新mWakeLockSummary属性,它是用来记录所有WakeLock锁状态的状态值,代表了所有的WakeLock,在请求Display状时作为判断条件确定具体的请求状态。系统规定了系统休眠状态对WakeLock锁的使用影响,如当系统休眠后,常亮锁(PowerManager.SCREEN_BRIGHT等)将会被忽略;系统唤醒后,Doze锁(PowerManager.DOZE_WAKE_LOCK等)将会被忽略: // frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java private void updateWakeLockSummaryLocked(int dirty) { if ((dirty & (DIRTY_WAKE_LOCKS | DIRTY_WAKEFULNESS)) != 0) { mWakeLockSummary = 0; // 置为0 // 将每个ProfilePowerState的mWakeLockSummary也进行重置 final int numProfiles = mProfilePowerState.size(); for (int i = 0; i< numProfiles; i++) { mProfilePowerState.valueAt(i).mWakeLockSummary = 0; } // 遍历mWakeLocks列表 final int numWakeLocks = mWakeLocks.size(); for (int i = 0; i< numWakeLocks; i++) { final WakeLock wakeLock = mWakeLocks.get(i); // 获取每个WakeLock对应的Flag标记 final int wakeLockFlags = getWakeLockSummaryFlags(wakeLock); // 标记在mWakeLockSummary上 mWakeLockSummary |= wakeLockFlags; // 对每个ProfilePowerState#mWakeLockSummary也进行标记 for (int j = 0; j< numProfiles; j++) { final ProfilePowerState profile = mProfilePowerState.valueAt(j); if (wakeLockAffectsUser(wakeLock, profile.mUserId)) { profile.mWakeLockSummary |= wakeLockFlags; } } } // 根据系统状态对mWakeLockSummary进行调整 mWakeLockSummary = adjustWakeLockSummaryLocked(mWakeLockSummary); // 对每个ProfilePowerState#mWakeLockSummary也进行调整 for (int i = 0; i< numProfiles; i++) { final ProfilePowerState profile = mProfilePowerState.valueAt(i); profile.mWakeLockSummary = adjustWakeLockSummaryLocked(profile.mWakeLockSummary); } } }只有当mDirty设置了DIRTY_WAKE_LOCKS和DIRTY_WAKEFULNESS标记位时,才会执行该方法。DIRTY_WAKE_LOCKS在申请WakeLock锁时设置,DIRTY_WAKEFULNESS在系统唤醒状态发生变化时设置。 进入该方法后,首先从保存了WakeLock的List中进行遍历,并根据WakeLock类型给mWakeLockSummary设置标记,这些标记位如下: // frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java private static final int WAKE_LOCK_CPU = 1<< 0; // 表示需要CPU保持唤醒状态 private static final int WAKE_LOCK_SCREEN_BRIGHT = 1<< 1; // 表示持有FULL_WAKE_LOCK锁,需要屏幕常亮 private static final int WAKE_LOCK_SCREEN_DIM = 1<< 2; // 表示持有SCREEN_DIM_WAKE_LOCK锁,需要保持dim不灭屏 private static final int WAKE_LOCK_BUTTON_BRIGHT = 1<< 3; //表示持有FULL_WAKE_LOCK锁,需要按键灯常亮 private static final int WAKE_LOCK_PROXIMITY_SCREEN_OFF = 1<< 4; // 表示持有Psensor WakeLock锁 private static final int WAKE_LOCK_STAY_AWAKE = 1<< 5; // 表示保持屏幕常亮 private static final int WAKE_LOCK_DOZE = 1<< 6; // 表示持有DOZE_WAKE_LOCK锁 private static final int WAKE_LOCK_DRAW = 1<< 7; //表示持有DRAW_WAKE_LOCK锁然后将根据系统状态进行调整: // frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java private int adjustWakeLockSummaryLocked(int wakeLockSummary) { // 唤醒状态不处于Doze状态时,忽略掉PowerManager.DOZE_WAKE_LOCK和PowerManager.DRAW_WAKE_LOCK两类型锁 if (mWakefulness != WAKEFULNESS_DOZING) { wakeLockSummary &= ~(WAKE_LOCK_DOZE | WAKE_LOCK_DRAW); } // 唤醒状态处于Asleep状态或者Doze状态时,忽略掉屏幕常亮锁、PSensor锁 if (mWakefulness == WAKEFULNESS_ASLEEP || (wakeLockSummary & WAKE_LOCK_DOZE) != 0) { wakeLockSummary &= ~(WAKE_LOCK_SCREEN_BRIGHT | WAKE_LOCK_SCREEN_DIM | WAKE_LOCK_BUTTON_BRIGHT); if (mWakefulness == WAKEFULNESS_ASLEEP) { wakeLockSummary &= ~WAKE_LOCK_PROXIMITY_SCREEN_OFF; } } if ((wakeLockSummary & (WAKE_LOCK_SCREEN_BRIGHT | WAKE_LOCK_SCREEN_DIM)) != 0) { // 唤醒状态处于Awake状态,WAKE_LOCK_STAY_AWAKE只用于awake状态时 if (mWakefulness == WAKEFULNESS_AWAKE) { wakeLockSummary |= WAKE_LOCK_CPU | WAKE_LOCK_STAY_AWAKE; } else if (mWakefulness == WAKEFULNESS_DREAMING) { // 唤醒状态处于Dreamland,需要CPU保持激活 wakeLockSummary |= WAKE_LOCK_CPU; } } // 有DRAW_WAKE_LOCK锁时,需要CPU保持唤醒 if ((wakeLockSummary & WAKE_LOCK_DRAW) != 0) { wakeLockSummary |= WAKE_LOCK_CPU; } return wakeLockSummary; }在平时分析处理不灭屏相关Bug时,通过该值可确定当前系统持有哪些类型的锁。 最终得到mWakeLockSummary,在自动灭屏流程中将使用起到重要作用,当自动灭屏时,如果mWakeLockSummary设置有WAKE_LOCK_STAY_AWAKE标记位,那么将不会灭屏。 此外,上面方法中出现了对ProfilePowerState对象的处理,它用来对不同user进行不同参数的设置,在多用户模式下,可以支持不同的状态,这部分略去。

2.5.updateUserActivitySummaryLocked()更新用户活动状态

这个方法用来更新全局变量mUserActivitySummary,它表示用户活动状态,有三个值: private static final int USER_ACTIVITY_SCREEN_BRIGHT = 1<< 0; // 表示亮屏状态下的交互 private static final int USER_ACTIVITY_SCREEN_DIM = 1<< 1; // 表示Dim状态下的交互 private static final int USER_ACTIVITY_SCREEN_DREAM = 1<< 2; // 表示Dreamland状态下的交互何时开始自动灭屏,就是这个方法中实现的。当设备和用户有交互时,都会根据当前时间和自动灭屏时间、Dim时长、当前唤醒状态计算下次休眠的时间,完成自动灭屏的操作。由亮屏进入Dim的时长、Dim到灭屏的时长、亮屏到屏保的时长,都是在这里计算的,这个方法的详细分析见Android R PowerManagerService模块(4) 灭屏流程。

2.6.updateAttentiveStateLocked()更新细微模式状态

这个方法用来更新细微模式状态,这是Android R上新添加的一个功能,其目的就是解决用户长时间没有操作但一直持有亮屏锁导致系统不灭屏这个场景的,算是一个省电优化项,看下是如何实现的: // frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java private void updateAttentiveStateLocked(long now, int dirty) { // 触发细微模式的时间阈值 long attentiveTimeout = getAttentiveTimeoutLocked(); // 自动休眠时间 long goToSleepTime = mLastUserActivityTime + attentiveTimeout; // 细微模式提示Dialog弹出时间 long showWarningTime = goToSleepTime - mAttentiveWarningDurationConfig; // 是否已经弹出提升对话框

boolean warningDismissed = maybeHideInattentiveSleepWarningLocked(now, showWarningTime); if (attentiveTimeout >= 0 && (warningDismissed || (dirty & (DIRTY_ATTENTIVE | DIRTY_STAY_ON | DIRTY_SCREEN_BRIGHTNESS_BOOST | DIRTY_PROXIMITY_POSITIVE | DIRTY_WAKEFULNESS | DIRTY_BOOT_COMPLETED | DIRTY_SETTINGS)) != 0)) { ...... // 是否需要弹出警告 if (isBeingKeptFromShowingInattentiveSleepWarningLocked()) { return; } long nextTimeout = -1; if (now< showWarningTime) { nextTimeout = showWarningTime; } else if (now< goToSleepTime) { // 弹出警告给用户 mInattentiveSleepWarningOverlayController.show(); nextTimeout = goToSleepTime; } else { } // 下一次进入时将会灭屏 if (nextTimeout >= 0) { scheduleAttentiveTimeout(nextTimeout); } } }这里提供了两个配置值: mAttentiveWarningDurationConfig表示触发细微模式前,弹出警告的时长,到达该时间时,会弹出对话框提示用户是否还要亮屏;mAttentiveTimeoutConfig表示触发细微模式的时间阈值,到达该时长后,会进行自动灭屏; 这种情况下,即使没有达到用户设置的自动休眠时间,也会进行自动灭屏。

2.7.updateWakefulnessLocked()是否需要更新唤醒状态

这个方法也和自动灭屏流程有关。如果满足自动灭屏条件,会更新系统唤醒状态。 这三个方法放在for(;;)循环中执行,是因为它们共同决定了设备的唤醒状态,前两个方法是汇总状态,后一个方法是根据前两个方法汇总的值而进行判断是否要改变当前的设备唤醒状态,汇总状态会受mWakefulness的影响,因此会进行循环处理。 同时,也仅仅会在超时灭屏进入睡眠或屏保时,for循环会执行两次,其他情况下,只会执行一次。这个方法的详细分析见Android R PowerManagerService模块(4) 灭屏流程。

2.8.updateProfilesLocked()

以上几个方法针对全局状态进行更新,这个方法则根据ProfilePowerState中保存的状态,更新不同用户是否进入锁定状态,由于使用场景不是很高,这里暂且略过。

2.9.updateDisplayPowerStateLocked()

该方法用于请求并更新Display状态,在这个方法中,会确定多个影响Display状态的属性,并将这些值封装到DisplayPowerRequest对象中,向DisplayMangerService发起请求,最终由DMS完成Display亮度、状态的更新: // frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java private boolean updateDisplayPowerStateLocked(int dirty) { final boolean oldDisplayReady = mDisplayReady; if ((dirty & (DIRTY_WAKE_LOCKS | DIRTY_USER_ACTIVITY | DIRTY_WAKEFULNESS | DIRTY_ACTUAL_DISPLAY_POWER_STATE_UPDATED | DIRTY_BOOT_COMPLETED | DIRTY_SETTINGS | DIRTY_SCREEN_BRIGHTNESS_BOOST | DIRTY_VR_MODE_CHANGED | DIRTY_QUIESCENT)) != 0) { // 根据系统唤醒状态获取请求的"策略": off, doze, dim or bright. mDisplayPowerRequest.policy = getDesiredScreenPolicyLocked(); final boolean autoBrightness; // 自动亮度是否开启 final int screenBrightnessOverride; // 是否有覆盖亮度 ...... // WindowManager覆盖的亮度值,如播放视频时调节亮度 mDisplayPowerRequest.screenBrightnessOverride = screenBrightnessOverride; // 是否使用自动亮度 mDisplayPowerRequest.useAutoBrightness = autoBrightness; // 是否存在PSensor Wakelock锁 mDisplayPowerRequest.useProximitySensor = shouldUseProximitySensorLocked(); // 是否有增强亮度 mDisplayPowerRequest.boostScreenBrightness = shouldBoostScreenBrightness(); // 设置某些设置亮度时用到的battery信息 updatePowerRequestFromBatterySaverPolicy(mDisplayPowerRequest); // 唤醒状态为Doze时,确定display的状态 if (mDisplayPowerRequest.policy == DisplayPowerRequest.POLICY_DOZE) { mDisplayPowerRequest.dozeScreenState = mDozeScreenStateOverrideFromDreamManager; if ((mWakeLockSummary & WAKE_LOCK_DRAW) != 0 && !mDrawWakeLockOverrideFromSidekick) { if (mDisplayPowerRequest.dozeScreenState == Display.STATE_DOZE_SUSPEND) { mDisplayPowerRequest.dozeScreenState = Display.STATE_DOZE; } if (mDisplayPowerRequest.dozeScreenState == Display.STATE_ON_SUSPEND) { mDisplayPowerRequest.dozeScreenState = Display.STATE_ON; } } // Doze时的屏幕亮度 mDisplayPowerRequest.dozeScreenBrightness = mDozeScreenBrightnessOverrideFromDreamManager; } else { mDisplayPowerRequest.dozeScreenState = Display.STATE_UNKNOWN; mDisplayPowerRequest.dozeScreenBrightness = PowerManager.BRIGHTNESS_DEFAULT; } // 发起请求,返回值表示DisplayPowerController中是否完成这次请求 mDisplayReady = mDisplayManagerInternal.requestPowerState(mDisplayPowerRequest, mRequestWaitForNegativeProximity); // 释放PSensor WakeLock锁时的一个标记 mRequestWaitForNegativeProximity = false; if ((dirty & DIRTY_QUIESCENT) != 0) { sQuiescent = false; // 这个值主要是单独控制背光,默认为false } } return mDisplayReady && !oldDisplayReady; }在向DisplayManagerService发起请求时,会将所有的信息封装到DisplayPowerRequest对象中,其中,policy属性值有五类: POLICY_OFF:请求屏幕进入灭屏状态;POLICY_DOZE:请求屏幕进入Doze状态;POLICY_DIM:请求屏幕进入Dim状态,POLICY_BRIGHT:请求屏幕处于正常亮屏状态;POLICY_VR:VR模式相关;在请求过程中,通过getDesiredScreenPolicyLocked()方法,根据当前唤醒状态和WakeLock统计状态来决定要请求的Display状态: // frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java int getDesiredScreenPolicyLocked() { // 当前唤醒状态为Asleep,则Display状态会设置为OFF if (mWakefulness == WAKEFULNESS_ASLEEP || sQuiescent) { return DisplayPowerRequest.POLICY_OFF; } // 当前唤醒状态为Doze,则Display状态会设置为Doze指定的状态 if (mWakefulness == WAKEFULNESS_DOZING) { if ((mWakeLockSummary & WAKE_LOCK_DOZE) != 0) { return DisplayPowerRequest.POLICY_DOZE; } if (mDozeAfterScreenOff) { // 表示跳过Doze的状态,直接设置成OFF return DisplayPowerRequest.POLICY_OFF; } } ...... // 如果存在亮屏锁、用户活动状态为亮屏、进行增强亮度,则Display状态将设置为ON if ((mWakeLockSummary & WAKE_LOCK_SCREEN_BRIGHT) != 0 || (mUserActivitySummary & USER_ACTIVITY_SCREEN_BRIGHT) != 0 || !mBootCompleted || mScreenBrightnessBoostInProgress) { return DisplayPowerRequest.POLICY_BRIGHT; } // 不满足以上条件,默认设置DIM return DisplayPowerRequest.POLICY_DIM; }当DisplayPowerController中完成请求后,将返回true给mDisplayReady,表示这次请求完成了。后面的流程在亮屏流程中总结。

2.10.updateDreamLocked()

该方法用来更新设备Dreamland状态,比如是否进入Dream、Doze或者开始休眠: // frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java private void updateDreamLocked(int dirty, boolean displayBecameReady) { if ((dirty & (DIRTY_WAKEFULNESS | DIRTY_USER_ACTIVITY | DIRTY_WAKE_LOCKS | DIRTY_BOOT_COMPLETED | DIRTY_SETTINGS | DIRTY_IS_POWERED | DIRTY_STAY_ON | DIRTY_PROXIMITY_POSITIVE | DIRTY_BATTERY_STATE)) != 0 || displayBecameReady) { if (mDisplayReady) { //mDisplayReady为ture后,才会进一步执行 //通过Handler异步发送一个消息 scheduleSandmanLocked(); } } }可以看到,对于Dreamland相关状态的更新,依赖于mDisplayReady变量,它表示Display是否准备就绪,因此只有在准备就绪的情况下才会进一步调用该方法的方法体。最后会PMS主线程中,调用handleSandman()方法执行Dreamland的操作: // frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java private void handleSandman() { ...... synchronized (mLock) { // 如果召唤了"睡眠精灵",且Display状态已经准备完毕 if (mSandmanSummoned && mDisplayReady) { // 判断是否可以进入Dreamland startDreaming = canDreamLocked() || canDozeLocked(); mSandmanSummoned = false; } else { startDreaming = false; } } final boolean isDreaming; if (mDreamManager != null) { if (startDreaming) { mDreamManager.stopDream(false /*immediate*/); // 开始进入Dreamland mDreamManager.startDream(wakefulness == WAKEFULNESS_DOZING); } isDreaming = mDreamManager.isDreaming(); } else { isDreaming = false; } synchronized (mLock) { ...... // Determine whether the dream should continue. if (wakefulness == WAKEFULNESS_DREAMING) { if (isDreaming && canDreamLocked()) { if (mDreamsBatteryLevelDrainCutoffConfig >= 0 && mBatteryLevel< mBatteryLevelWhenDreamStarted - mDreamsBatteryLevelDrainCutoffConfig && !isBeingKeptAwakeLocked()) { // 退出Dreamland } else { return; // continue dreaming } } // 退出Dreamland,进入休眠状态 if (isItBedTimeYetLocked()) { goToSleepNoUpdateLocked(SystemClock.uptimeMillis(), PowerManager.GO_TO_SLEEP_REASON_TIMEOUT, 0, Process.SYSTEM_UID); updatePowerStateLocked(); } else { // 唤醒设备 wakeUpNoUpdateLocked(SystemClock.uptimeMillis(), PowerManager.WAKE_REASON_UNKNOWN, "android.server.power:DREAM_FINISHED", Process.SYSTEM_UID, mContext.getOpPackageName(), Process.SYSTEM_UID); updatePowerStateLocked(); } } else if (wakefulness == WAKEFULNESS_DOZING) { if (isDreaming) { return; // continue dozing } // 进行灭屏流程 reallyGoToSleepNoUpdateLocked(SystemClock.uptimeMillis(), Process.SYSTEM_UID); // 更新PMS状态 updatePowerStateLocked(); } } // Stop dream. if (isDreaming) { mDreamManager.stopDream(false /*immediate*/); } }在以上方法中,将会调用DreamManager处理具体的Dreamland逻辑,这部分流程的分析,在DreamManagerService模块分析时会进行详细分析。

2.11.finishWakefulnessChangeIfNeededLocked()

该方法主要做唤醒状态发生变化后,后半部分更新工作: private void finishWakefulnessChangeIfNeededLocked() { if (mWakefulnessChanging && mDisplayReady) { // 如果唤醒状态处于Doze状态,不进行任何处理 if (mWakefulness == WAKEFULNESS_DOZING && (mWakeLockSummary & WAKE_LOCK_DOZE) == 0) { return; // wait until dream has enabled dozing } if (mWakefulness == WAKEFULNESS_AWAKE) { // 如果亮屏流程超过200ms,输出亮屏所用时间 if (latencyMs >= SCREEN_ON_LATENCY_WARNING_MS) { Slog.w(TAG, "Screen on took " + latencyMs + " ms"); } } // 表示唤醒状态更新完成 mWakefulnessChanging = false; //通过Notifier进行唤醒状态改变后的处理 mNotifier.onWakefulnessChangeFinished(); } }只有当屏幕状态改变后,才会执行该方法。进入该方法后,将通过Notifier#onWakefulnessChangeFinished()方法发送亮屏、灭屏广播等。 该方法中的logScreenOn()方法将打印出整个亮屏流程的耗时,在平时处理问题时很有帮助。

2.12.updateSuspendBlockerLocked()

这个方法用来更新SuspendBlocker锁状态。Suspend锁机制是Android框架中锁机的一种锁,它代表了框架层以上所有的WakeLock。Wakelock锁是APP或其他组建向PMS模块申请,而Suspend锁是PMS模块中对WakeLock锁的最终表现,或者说上层应用或system_server其他组件申请了wakelock锁后,在PMS中最终都会表现为Suspend锁,通过Suspend锁向Hal层写入节点,Kernal层会读取节点,从而唤醒或者休眠CPU。 该方法的详细分析在Android R PowerManagerService模块(2) WakeLock机制中进行汇总。

用户评论

珠穆郎马疯@

终于找到介绍PowerManagerService的资料了!一直想知道 Android 系统是如何管理设备电源的。

    有10位网友表示赞同!

身影

我正学习 Android 内核,这篇关于 PowerManagerService 的文章正好可以补我的知识空缺,谢谢分享!

    有12位网友表示赞同!

我的黑色迷你裙

想了解一下在特殊情况下如何自定义 Power Manager 的策略?这篇文章能解答吗?

    有18位网友表示赞同!

伱德柔情是我的痛。

Android R 版本有什么新特性在电源管理方面呢?希望文章能详细介绍。

    有10位网友表示赞同!

减肥伤身#

我正在写一篇关于 Android 电池续航的文章,这篇文章对我很有帮助!

    有15位网友表示赞同!

生命一旅程

PowerManagerService 是一个非常重要的系统服务,它保证了设备的正常运行和电池寿命。

    有20位网友表示赞同!

无关风月

想了解一下不同电源状态下 PowerManagerService 的行为机制。

    有6位网友表示赞同!

开心的笨小孩

如果我能修改 PowerManager Service 的内部实现,我就可以定制很多独特的应用功能吧?

    有15位网友表示赞同!

短发

学习 Android 系统架构总是会让我感觉很震撼,PowerManagerService 作为一个核心组件的确让人叹为观止!

    有18位网友表示赞同!

来自火星的我

文章中提到的核心方法有哪些呢?能否罗列一下?

    有12位网友表示赞同!

*巴黎铁塔

我记得有个 PowerSave 模式,它是由 PowerManagerService 控制的吗?

    有8位网友表示赞同!

轨迹!

学习 Android 电源管理的知识非常有用,可以帮助我开发更省电的 App。

    有11位网友表示赞同!

蝶恋花╮

Android 系统中的电源策略是如何根据手机的使用场景来调节的呢?这个机制很复杂吧?

    有11位网友表示赞同!

摩天轮的依恋

我想了解一下 PowerManagerService 和其他系统服务的交互方式。

    有15位网友表示赞同!

不浪漫罪名

如果想深入学习这个模块,需要参考哪些资料呢?

    有7位网友表示赞同!

陌上花

Android R 版本的电源管理有什么新的改进和优化吗?期待了解更多细节。

    有7位网友表示赞同!

【Android R版PowerManagerService模块启动流程与关键方法解析】相关文章:

1.蛤蟆讨媳妇【哈尼族民间故事】

2.米颠拜石

3.王羲之临池学书

4.清代敢于创新的“浓墨宰相”——刘墉

5.“巧取豪夺”的由来--米芾逸事

6.荒唐洁癖 惜砚如身(米芾逸事)

7.拜石为兄--米芾逸事

8.郑板桥轶事十则

9.王献之被公主抢亲后的悲惨人生

10.史上真实张三丰:在棺材中竟神奇复活