该系列文章总纲链接:专题分纲目录 Android Framework 电源子系统


本章关键点总结 & 说明:

本章节主要关注➕ updatePowerStateLocked 方法中 更新屏保 和 发送通知 并 更新wakelock锁 部分 即可。该章节 主要是 对更新屏保 和 发送通知 并 更新wakelock锁 部分 进行 详细解读。

PMS核心方法updatePowerStateLocked

updatePowerStateLocked 方法是整个PMS中的核心方法,它用来更新整个电源状态的改变,并进行重新计算。PMS中使用一个int值mDirty作为标志位判断电源状态是否发生变化,当电源状态发生改变时,如亮灭屏、电池状态改变、暗屏…都会调用该方法,它的代码实现如下:

private void updatePowerStateLocked() {//...Trace.traceBegin(Trace.TRACE_TAG_POWER, "updatePowerState");try {// 1 更新基本状态// 1.1 更新mIsPowered,mPlugType,mBatteryLevelupdateIsPoweredLocked(mDirty);// 1.2 更新mStayonupdateStayOnLocked(mDirty);updateScreenBrightnessBoostLocked(mDirty);// 2 更新wakefulness和用户活动final long now = SystemClock.uptimeMillis();int dirtyPhase2 = 0;for (;;) {int dirtyPhase1 = mDirty;dirtyPhase2 |= dirtyPhase1;mDirty = 0;// 2.1 得到当前终端整体的信息,保存到mWakeLockSummary变量中updateWakeLockSummaryLocked(dirtyPhase1);// 2.2 根据用户最后的活动来决定当前屏幕的状态updateUserActivitySummaryLocked(now, dirtyPhase1);// 2.3 判定 第二阶段的电源状态更新是否结束if (!updateWakefulnessLocked(dirtyPhase1)) {break;}}// 3 更新显示设备状态boolean displayBecameReady = updateDisplayPowerStateLocked(dirtyPhase2);// 4 更新屏保状态updateDreamLocked(dirtyPhase2, displayBecameReady);// 5 发送通知 并 更新底层wakelock// 5.1 发送通知if (mDisplayReady) {finishWakefulnessChangeLocked();}// 5.2 更新底层wakelockupdateSuspendBlockerLocked();} finally {Trace.traceEnd(Trace.TRACE_TAG_POWER);}
}

该部分代码共分为5部分,因为篇幅较长,所以拆分成3个章节进行分析。本章节是 4 5部分。


4 更新屏保 updateDreamLocked分析

updateDreamLocked函数主要用于更新屏保状态,当设备进入或者退出屏保的时候都会触发这个方法:

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) {//mDirty满足条件,同时屏幕状态调整完毕,才进入下一步scheduleSandmanLocked();}}
}

这里 关键分析 scheduleSandmanLocked,代码实现如下:

private void scheduleSandmanLocked() {if (!mSandmanScheduled) {//让MessageQueue中仅保留一个MSG_SANDMANmSandmanScheduled = true;//由handleSandman处理Message msg = mHandler.obtainMessage(MSG_SANDMAN);msg.setAsynchronous(true);mHandler.sendMessage(msg);}
}

处理该消息 使用handleSandman函数,它比较复杂,主要用于决定设备是否应该停留在dreaming或dozing状态。 代码如下:

private void handleSandman() { // runs on handler thread//1 是否开始进入屏保final boolean startDreaming;final int wakefulness;synchronized (mLock) {mSandmanScheduled = false;wakefulness = mWakefulness;//当updateWakefulnessLocked判断进入dozing或sleep状态时,//会将mSandmanSummoned置为true//mDisplayReady主要确保前面屏幕状态更新完毕if (mSandmanSummoned && mDisplayReady) {//判断device是否可以dream或dozingstartDreaming = canDreamLocked() || canDozeLocked();mSandmanSummoned = false;} else {startDreaming = false;}}//2 表示是否正在屏保final boolean isDreaming;if (mDreamManager != null) {// Restart the dream whenever the sandman is summoned.//重启屏保if (startDreaming) {//结束旧屏保mDreamManager.stopDream(false /*immediate*/);//开启新屏保mDreamManager.startDream(wakefulness == WAKEFULNESS_DOZING);}//startDream成功后,一般isDreaming就会返回trueisDreaming = mDreamManager.isDreaming();} else {isDreaming = false;}//3 更新屏保状态.synchronized (mLock) {//记录进入屏保时的电池电量if (startDreaming && isDreaming) {mBatteryLevelWhenDreamStarted = mBatteryLevel;}if (mSandmanSummoned || mWakefulness != wakefulness) {return; // wait for next cycle}// Determine whether the dream should continue.if (wakefulness == WAKEFULNESS_DREAMING) {if (isDreaming && canDreamLocked()) {if (mDreamsBatteryLevelDrainCutoffConfig >= 0&& mBatteryLevel < mBatteryLevelWhenDreamStarted- mDreamsBatteryLevelDrainCutoffConfig&& !isBeingKeptAwakeLocked()) {} else {return; // continue dreaming}}// Dream has ended or will be stopped.  Update the power state.if (isItBedTimeYetLocked()) {//休眠goToSleepNoUpdateLocked(SystemClock.uptimeMillis(),PowerManager.GO_TO_SLEEP_REASON_TIMEOUT, 0, Process.SYSTEM_UID);updatePowerStateLocked();} else {//唤醒wakeUpNoUpdateLocked(SystemClock.uptimeMillis(), Process.SYSTEM_UID);updatePowerStateLocked();}//如果处于Doze状态,在power键灭屏时,首次会将wakefulness设置为该值} else if (wakefulness == WAKEFULNESS_DOZING) {if (isDreaming) {return; // continue dozing}//进入asleep状态reallyGoToSleepNoUpdateLocked(SystemClock.uptimeMillis(), Process.SYSTEM_UID);updatePowerStateLocked();}}//如果正处在Dream,则只要触发updatePowerStateLocked(),立即退出Dreamif (isDreaming) {mDreamManager.stopDream(false /*immediate*/);}
}

这里主要分3部分 对这段代码进行分析

4.1 决定是否可以进入屏保状态

    ...//1 是否开始进入屏保final boolean startDreaming;final int wakefulness;synchronized (mLock) {mSandmanScheduled = false;wakefulness = mWakefulness;//当updateWakefulnessLocked判断进入dozing或sleep状态时,//会将mSandmanSummoned置为true//mDisplayReady主要确保前面屏幕状态更新完毕if (mSandmanSummoned && mDisplayReady) {//判断device是否可以dream或dozingstartDreaming = canDreamLocked() || canDozeLocked();mSandmanSummoned = false;} else {startDreaming = false;}}...

这段代码主要用于确定 设备是否可以看是dreaming。 除去前置条件的限制外,此处结果主要由canDreamLocked和canDozeLocked决定。canDreamLocked的实现如下:

private boolean canDreamLocked() {//mWakefulness等于WAKEFULNESS_DREAMINGif (mWakefulness != WAKEFULNESS_DREAMING || !mDreamsSupportedConfig //设备支持dreaming|| !mDreamsEnabledSetting  //设置开关开启|| !mDisplayPowerRequest.isBrightOrDim() //屏幕熄灭|| (mUserActivitySummary & (USER_ACTIVITY_SCREEN_BRIGHT| USER_ACTIVITY_SCREEN_DIM | USER_ACTIVITY_SCREEN_DREAM)) == 0|| !mBootCompleted) {return false;}//不处于唤醒态if (!isBeingKeptAwakeLocked()) {//没充电,电源选项也未配置,不可dreamingif (!mIsPowered && !mDreamsEnabledOnBatteryConfig) {return false;}//没充电,且电池电量过低,不可dreamingif (!mIsPowered&& mDreamsBatteryLevelMinimumWhenNotPoweredConfig >= 0&& mBatteryLevel < mDreamsBatteryLevelMinimumWhenNotPoweredConfig) {return false;}//充电,但电池电量过低,不可dreamingif (mIsPowered&& mDreamsBatteryLevelMinimumWhenPoweredConfig >= 0&& mBatteryLevel < mDreamsBatteryLevelMinimumWhenPoweredConfig) {return false;}}return true;
}

从上面的代码可以看出,充电和未充电分别有一个最低的dreaming电量门限,同时 dreaming除了对终端当前的状态、配置项有关外,在非唤醒状态下还与当前的电池电量有关系。

canDozeLocked的实现简单很多,仅仅是 mWakefulness的一个判断,代码如下:

private boolean canDozeLocked() {return mWakefulness == WAKEFULNESS_DOZING;
}

这个过程就是 判定 是否可以进入屏保状态。接下来 满足条件 则进入到屏保状态

4.2 在必要时,进入屏保状态

进入屏保状态后,这一部分就开始进行实际的工作。该部分代码如下:

    ...//2 表示是否正在屏保final boolean isDreaming;if (mDreamManager != null) {// Restart the dream whenever the sandman is summoned.//重启屏保if (startDreaming) {//结束旧屏保mDreamManager.stopDream(false /*immediate*/);//开启新屏保mDreamManager.startDream(wakefulness == WAKEFULNESS_DOZING);}//startDream成功后,一般isDreaming就会返回trueisDreaming = mDreamManager.isDreaming();} else {isDreaming = false;}...

mDreamManager为DreamManagerService的Binder代理。 我们重点看看DreamManagerService的startDream函数,stopDream的工作内容与startDream相反。

public void startDream(boolean doze) {startDreamInternal(doze);
}

继续分析startDreamInternal,代码如下:

private void startDreamInternal(boolean doze) {final int userId = ActivityManager.getCurrentUser();//获取屏保对象final ComponentName dream = chooseDreamForUser(doze, userId);if (dream != null) {synchronized (mLock) {startDreamLocked(dream, false /*isTest*/, doze, userId);}}
}

继续分析startDreamLocked,代码如下:

private void startDreamLocked(final ComponentName name,final boolean isTest, final boolean canDoze, final int userId) {//申请的屏保与当前的一致,不用进行修改if (Objects.equal(mCurrentDreamName, name)&& mCurrentDreamIsTest == isTest&& mCurrentDreamCanDoze == canDoze&& mCurrentDreamUserId == userId) {return;}//停止当前屏保stopDreamLocked(true /*immediate*/);final Binder newToken = new Binder();mCurrentDreamToken = newToken;mCurrentDreamName = name;mCurrentDreamIsTest = isTest;mCurrentDreamCanDoze = canDoze;mCurrentDreamUserId = userId;mHandler.post(new Runnable() {@Overridepublic void run() {//调用DreamController的startDream函数mController.startDream(newToken, name, isTest, canDoze, userId);}});
}

继续分析 DreamController 的 startDream 函数,代码实现如下:

public void startDream(Binder token, ComponentName name,boolean isTest, boolean canDoze, int userId) {//移除当前屏保并回调通知stopDream(true /*immediate*/);//...// Close the notification shade. Don't need to send to all, but better to be explicit.mContext.sendBroadcastAsUser(mCloseNotificationShadeIntent, UserHandle.ALL);mCurrentDream = new DreamRecord(token, name, isTest, canDoze, userId);try {//屏幕相关的准备工作mIWindowManager.addWindowToken(token, WindowManager.LayoutParams.TYPE_DREAM);} catch (RemoteException ex) {stopDream(true /*immediate*/);return;}Intent intent = new Intent(DreamService.SERVICE_INTERFACE);intent.setComponent(name);intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);try { //拉起屏保服务if (!mContext.bindServiceAsUser(intent, mCurrentDream,Context.BIND_AUTO_CREATE, new UserHandle(userId))) {stopDream(true /*immediate*/);return;}} catch (SecurityException ex) {stopDream(true /*immediate*/);return;}mCurrentDream.mBound = true;//在DREAM_CONNECTION_TIMEOUT到期时,bind服务还未成功,runnable就负责结束dreammHandler.postDelayed(mStopUnconnectedDreamRunnable, DREAM_CONNECTION_TIMEOUT);//...
}

这里 所谓的屏保其实就是拉起一个特殊的服务。

4.3 更新屏保状态

    ...//3 更新屏保状态.synchronized (mLock) {//记录进入屏保时的电池电量if (startDreaming && isDreaming) {mBatteryLevelWhenDreamStarted = mBatteryLevel;}if (mSandmanSummoned || mWakefulness != wakefulness) {return; // wait for next cycle}// Determine whether the dream should continue.if (wakefulness == WAKEFULNESS_DREAMING) {if (isDreaming && canDreamLocked()) {if (mDreamsBatteryLevelDrainCutoffConfig >= 0&& mBatteryLevel < mBatteryLevelWhenDreamStarted- mDreamsBatteryLevelDrainCutoffConfig&& !isBeingKeptAwakeLocked()) {} else {return; // continue dreaming}}// Dream has ended or will be stopped.  Update the power state.if (isItBedTimeYetLocked()) {//休眠goToSleepNoUpdateLocked(SystemClock.uptimeMillis(),PowerManager.GO_TO_SLEEP_REASON_TIMEOUT, 0, Process.SYSTEM_UID);updatePowerStateLocked();} else {//唤醒wakeUpNoUpdateLocked(SystemClock.uptimeMillis(), Process.SYSTEM_UID);updatePowerStateLocked();}//如果处于Doze状态,在power键灭屏时,首次会将wakefulness设置为该值} else if (wakefulness == WAKEFULNESS_DOZING) {if (isDreaming) {return; // continue dozing}//进入asleep状态reallyGoToSleepNoUpdateLocked(SystemClock.uptimeMillis(), Process.SYSTEM_UID);updatePowerStateLocked();}}//如果正处在Dream,则只要触发updatePowerStateLocked(),立即退出Dreamif (isDreaming) {mDreamManager.stopDream(false /*immediate*/);}...

说明:每次更新状态后都会重新调用updatePowerStateLocked,然后再次进入到handleSandman函数中。整个过程就是就是 在条件合适后,这个方法中将启动屏保。

5 发送通知 并 更新 wakelock锁

5.1 发送通知 finishWakefulnessChangeLocked 分析

private void finishWakefulnessChangeLocked() {if (mWakefulnessChanging) {//通过Notifier进行wakefulness改变后的处理mNotifier.onWakefulnessChangeFinished(mWakefulness);mWakefulnessChanging = false;}
}

这里 Notifier好比PMS的一个喇叭,用来发送广播,和其他组件交互等。

5.2 更新wakelock锁 updateSuspendBlockerLocked 分析

private void updateSuspendBlockerLocked() {//根据是否有CPU的wakelock,来决定cpu是保持否唤醒final boolean needWakeLockSuspendBlocker = ((mWakeLockSummary & WAKE_LOCK_CPU) != 0);//根据前面屏幕相关的状态,来决定是否需要持有屏幕的锁final boolean needDisplaySuspendBlocker = needDisplaySuspendBlockerLocked();//屏幕如果不需要保持开启状态,那么可自动熄灭final boolean autoSuspend = !needDisplaySuspendBlocker;//应该是表示屏幕是否是可交互的final boolean interactive = mDisplayPowerRequest.isBrightOrDim();if (!autoSuspend && mDecoupleHalAutoSuspendModeFromDisplayConfig) {//通过native函数,调用底层的autosuspend_disablesetHalAutoSuspendModeLocked(false);}//在需要的情况下,获取CPU和屏幕的锁if (needWakeLockSuspendBlocker && !mHoldingWakeLockSuspendBlocker) {mWakeLockSuspendBlocker.acquire();mHoldingWakeLockSuspendBlocker = true;}if (needDisplaySuspendBlocker && !mHoldingDisplaySuspendBlocker) {mDisplaySuspendBlocker.acquire();mHoldingDisplaySuspendBlocker = true;}if (mDecoupleHalInteractiveModeFromDisplayConfig) {if (interactive || mDisplayReady) {//调用底层动态库的setInteractive函数,决定终端是否可以进行交互setHalInteractiveModeLocked(interactive);}}//如果不需要,则释放CPU和屏幕的锁 if (!needWakeLockSuspendBlocker && mHoldingWakeLockSuspendBlocker) {mWakeLockSuspendBlocker.release();mHoldingWakeLockSuspendBlocker = false;}if (!needDisplaySuspendBlocker && mHoldingDisplaySuspendBlocker) {mDisplaySuspendBlocker.release();mHoldingDisplaySuspendBlocker = false;}//如果需要设置自动休眠模式if (autoSuspend && mDecoupleHalAutoSuspendModeFromDisplayConfig) {setHalAutoSuspendModeLocked(true);}
}

这里 needDisplaySuspendBlockerLocked 方法决定 屏幕是否关闭,代码实现如下:

private boolean needDisplaySuspendBlockerLocked() {if (!mDisplayReady) {//显示设备没准备好,不能关闭屏幕return true;}//如果屏幕开着/变暗if (mDisplayPowerRequest.isBrightOrDim()) {//距离传感器 没有工作,不能关闭屏幕if (!mDisplayPowerRequest.useProximitySensor || !mProximityPositive|| !mSuspendWhenScreenOffDueToProximityConfig) {return true;}}if (mScreenBrightnessBoostInProgress) {return true;}// Let the system suspend if the screen is off or dozing.return false; //可以关闭屏幕
}

needDisplaySuspendBlockerLocked主要根据屏幕的状态来决定,如果屏幕开着 或 处于 变暗状态时,近距离传感器 也没有工作,不能关闭屏幕。

通过本次源码分析,我们能看出仅管理当前的状态,涉及的细节就非常的琐碎。 而屏幕和CPU的实际控制,还牵扯到大量其它对象和HAL层代码。 Android电源的管理实际上是基于Linux 电源管理策略的,因此若要真正掌握,还需要对Linux的电源管理策略作进一步的了解。

Android Framework 电源子系统(05)核心方法updatePowerStateLocked分析-3 更新屏保  发送通知  更新wakelock相关推荐

  1. Android Framework 电源子系统(04)核心方法updatePowerStateLocked分析-2 循环处理  更新显示设备状态

    该系列文章总纲链接:专题分纲目录 Android Framework 电源子系统 本章关键点总结 & 说明: 本章节主要关注➕ updatePowerStateLocked 方法中 循环处理 ...

  2. Android Framework 电源子系统(01)PowerManagerService启动分析

    该系列文章总纲链接:专题分纲目录 Android Framework 电源子系统 本章关键点总结 & 说明: 本章节主要关注➕ 以上思维导图即可.该章节 主要是 对 PMS 启动的分析,从sy ...

  3. Android Framework 窗口子系统 (08)窗口动画之动画系统框架

    该系列文章总纲链接:专题分纲目录 Android Framework 窗口子系统 本章关键点总结 & 说明: 导图是不断迭代的,这里主要关注➕ 左上角 Android 窗口动画系统部分(因为导 ...

  4. 专题总纲目录 Android Framework 总纲

    专题总纲说明: 本系列文章虽说是 Android 的知识体系专题,同时也是学习Android Framework 系统的一个思路,尤其是当我们对Android 框架层 一点都不了解的时候,但前提是要有 ...

  5. Android Framework中的线程Thread及它的threadLoop方法

    当初跟踪Camera的代码中的时候一直追到了HAL层,而在Framework中的代码看见了许许多多的Thread.它们普遍的特点就是有一个threadLoop方法.按照字面的意思应该是这个线程能够循环 ...

  6. Android7.0 PowerManagerService(3) 核心函数updatePowerStateLocked的主要流程

    前面的博客中,我们已经分析过,当Android中的进程要使用电量时,需要向PMS申请WakeLock:当进程完成工作后,需要释放对应的WakeLock.  PMS收到申请和释放WakeLock的请求后 ...

  7. Android Framework 框架系列之PowerManager

    极力推荐Android 开发大总结文章:欢迎收藏程序员Android 力荐 ,Android 开发者需要的必备技能 本篇文章主要介绍 Android 开发中的部分知识点,通过阅读本篇文章,您将收获以下 ...

  8. android系统自动休眠代码流程,Android P 电源管理(4)待机流程

    电视遥控器,短端走待机(str待机)流程, 长按是关机,走关机流程,记录下待机流程. 参考博客 待机流程 Android P引入自动待机功能,只有存在WakeLock,wakeup_count就不会为 ...

  9. Android平台Camera实时滤镜实现方法

    Android+JNI+OpenGL开发自己的美图秀秀 Android平台Camera实时滤镜实现方法探讨(十一)--实时美颜滤镜 Android平台Camera实时滤镜实现方法探讨(十)--代码地址 ...

最新文章

  1. SSM+BJUI实现以Base64方式上传照片
  2. 线程同步-AutoResetEvent
  3. 关于dismissViewControllerAnimated值得注意的一点(deinit)
  4. BotSharp v0.2 发布, 支持微信智能回复
  5. 关闭windows垃圾服务
  6. python字符串百分号_Python字符串格式化的2种方法
  7. IDEA导入项目笔记二
  8. csv java 科学计数法_Java入门笔记1/0(输入与输出)
  9. 汇编语言上机考试三星题——加密的key和明文字符串
  10. [运维笔记] PowerShell (模块).模块清单
  11. 极简主义︱利用apple机器学习平台Turicreate实现图像相似性检索(二)
  12. 区块链的供应链金融系统
  13. Fpdi实现pdf页面合并(php)
  14. 全球与中国无线门铃对讲设备市场深度研究分析报告
  15. 【爱吃肉的阿C】使用URL类将文件下载到本地
  16. 易语言多线程崩溃解决的原因
  17. 安卓美化——添加下拉菜单图片或下拉菜单透明
  18. 一个大数据架构师应该掌握的技能
  19. 柳岩直播卖货,三小时豪赚1500万?快手为什么那么带货?
  20. vue中Echarts实现伪3D地图

热门文章

  1. 云服务厂商人才空心化隐忧
  2. 面试了几十家软件测试公司全是这个“套路”
  3. 中国AI觉醒 阿里王坚:云智能将成为大趋势
  4. android emoji 服务器,Emoji 实战问题:iOS,Android,Server
  5. 主流射频半导体材料及特性介绍
  6. Thinkphp6调用企业微信官方php版本接口方法
  7. WordPress开源免费主题推荐
  8. 水纹效果(Water)源程序.
  9. 移动端身份证识别,APP证件信息采集
  10. iOS和Android的app界面设计规范