Android 知识点 110 —— PowerManagerService 进入屏保 updateUserActivitySummaryLocked

屏screen_off和睡眠sleep都有对应的配置时间,如果Settings开了接口也都是可以配置的。默认情况下要看SettingsProvider里面对应的default的值,当然特定的产品要考虑到overlay的情况。

比如在这里def_screen_off_timeout则是60s,而def_sleep_timeout是-1则表示关闭了睡眠功能。换句话说,机器不用过1分钟系统会进入屏保,不会睡眠,屏幕或者hdmi是一直都有信号输出的。

/p-base/frameworks/base/packages/SettingsProvider/res/values/defaults.xml

    <integer name="def_screen_off_timeout">60000</integer>
    <integer name="def_sleep_timeout">-1</integer>

60000 ms , 看code里面的时间都是毫秒。

overlay的情况

这里面默认的睡眠时间是20s,屏保时间是10s,也就是说没事做10s进屏保,再过10s进睡眠。

    <integer name="def_sleep_timeout">20000</integer>
    <integer name="def_screen_off_timeout">10000</integer>

 参考日志如下,uid 1000 指的是Process.SYSTEM_UID, 说明是系统发起的。

08-22 05:09:51.244  3067  3092 I PowerManagerService: Nap time (uid 1000)...
08-22 05:09:51.245  3067  3092 I DreamManagerService: Entering dreamland.
08-22 05:09:51.245  3067  3092 I PowerManagerService: Dreaming...
 
08-22 05:10:01.243  3067  3092 I PowerManagerService: Going to sleep due to screen timeout (uid 1000)...
08-22 05:10:01.244  3067  3092 I DreamManagerService: Gently waking up from dream.
08-22 05:10:01.245  3067  3092 I PowerManagerService: Sleeping (uid 1000)...
08-22 05:10:01.247  2892  2954 E         : getRealActiveConfig to config(0).
08-22 05:10:01.248  3067  3088 I DreamManagerService: Performing gentle wake from dream.

在每次更新系统power状态的时候,都要基于当前的user activity计算再次唤醒或者睡眠的时间。关键函数updateUserActivitySummaryLocked,主要是计算出下次超时时间nextTimeout和用户状态mUserActivitySummary,当满足nextTimeout到下次更新状态的时候会基于这个用户状态来进行相应的动作,是dim、dream、还是sleep。注意,这个状态的计算是逐层变深的,后面的计算如果满足条件会覆盖掉前面的计算。另一方面,整个系统进入休眠的顺序也一定是dim、dream、doze、sleep。

    private void updateUserActivitySummaryLocked(long now, int dirty) {
        // Update the status of the user activity timeout timer.
        if ((dirty & (DIRTY_WAKE_LOCKS | DIRTY_USER_ACTIVITY
                | DIRTY_WAKEFULNESS | DIRTY_SETTINGS)) != 0) {
            mHandler.removeMessages(MSG_USER_ACTIVITY_TIMEOUT);

            long nextTimeout = 0;
            if (mWakefulness == WAKEFULNESS_AWAKE
                    || mWakefulness == WAKEFULNESS_DREAMING
                    || mWakefulness == WAKEFULNESS_DOZING) {
                //获取睡眠时长,为Settings.Secure.SLEEP_TIMEOUT的值和最小休眠时间的最大值,Settings.Secure.SLEEP_TIMEOUT一般为-1,
                //表示禁用,因此该值默认为-1
                final int sleepTimeout = getSleepTimeoutLocked();
                //获取休眠时长,在Settings中设置的值
                final int screenOffTimeout = getScreenOffTimeoutLocked(sleepTimeout);
                //获取Dim时长,由休眠时长剩Dim百分比得到
                final int screenDimDuration = getScreenDimDurationLocked(screenOffTimeout);
                //用户活动是否由Window覆盖
                final boolean userInactiveOverride = mUserInactiveOverrideFromWindowManager;
                //该值用来统计用户活动状态,每次进入该方法,置为0
                mUserActivitySummary = 0;
                //上次用户活动时间>=上次唤醒时间
                if (mLastUserActivityTime >= mLastWakeTime) {
                    //下次超时时间为上次用户活动时间+休眠时间-Dim时间,到达这个时间后,将进入Dim状态
                    nextTimeout = mLastUserActivityTime
                            + screenOffTimeout - screenDimDuration;
                    //如果当前时间<nextTimeout,则此时处于亮屏状态,标记mUserActivitySummary为USER_ACTIVITY_SCREEN_BRIGHT
                    if (now < nextTimeout) {
                        mUserActivitySummary = USER_ACTIVITY_SCREEN_BRIGHT;
                    } else {
                        //如果当前时间>nextTimeout,此时有两种情况,要么进入Dim要么进入Sleep
                        //将上次用户活动时间+灭屏时间赋值给nextTimeout,如果该值大于当前时间,则说明此时应该处于Dim状态
                        //因此将标记mUserActivitySummary为USER_ACTIVITY_SCREEN_DIM
                        nextTimeout = mLastUserActivityTime + screenOffTimeout;
                        if (now < nextTimeout) {
                            mUserActivitySummary = USER_ACTIVITY_SCREEN_DIM;
                        }
                    }
                }
                //判断和USER_ACTIVITY_FLAG_NO_CHANGE_LIGHTS标记相关,如果带有此标记,才会进入该if
                if (mUserActivitySummary == 0
                        && mLastUserActivityTimeNoChangeLights >= mLastWakeTime) {
                    //下次超时时间=上次用户活动时间+灭屏时间
                    nextTimeout = mLastUserActivityTimeNoChangeLights + screenOffTimeout;
                    //根据当前时间和nextTimeout设置mUserActivitySummary
                    if (now < nextTimeout) {
                        if (mDisplayPowerRequest.policy == DisplayPowerRequest.POLICY_BRIGHT
                                || mDisplayPowerRequest.policy == DisplayPowerRequest.POLICY_VR) {
                            mUserActivitySummary = USER_ACTIVITY_SCREEN_BRIGHT;
                        } else if (mDisplayPowerRequest.policy == DisplayPowerRequest.POLICY_DIM) {
                            mUserActivitySummary = USER_ACTIVITY_SCREEN_DIM;
                        }
                    }
                }
                //不满足以上条件时,此时mUserActivitySummary为0,这种情况应该为当mUserActivitySummary经历了USER_ACTIVITY_SCREEN_BRIGHT
                //和USER_ACTIVITY_SCREEN_DIM之后才会执行到这里
                if (mUserActivitySummary == 0) {
                    if (sleepTimeout >= 0) {
                        //获取上次用户活动时间的最后一次时间
                        final long anyUserActivity = Math.max(mLastUserActivityTime,
                                mLastUserActivityTimeNoChangeLights);
                        if (anyUserActivity >= mLastWakeTime) {
                            nextTimeout = anyUserActivity + sleepTimeout;
                            //将mUserActivitySummary值置为USER_ACTIVITY_SCREEN_DREAM,表示屏保
                            if (now < nextTimeout) {
                                mUserActivitySummary = USER_ACTIVITY_SCREEN_DREAM;
                            }
                        }
                    } else {
                        //将mUserActivitySummary值置为USER_ACTIVITY_SCREEN_DREAM,表示屏保
                        mUserActivitySummary = USER_ACTIVITY_SCREEN_DREAM;
                        nextTimeout = -1;
                    }
                }

                if (mUserActivitySummary != USER_ACTIVITY_SCREEN_DREAM && userInactiveOverride) {
                    if ((mUserActivitySummary &
                            (USER_ACTIVITY_SCREEN_BRIGHT | USER_ACTIVITY_SCREEN_DIM)) != 0) {
                        // Device is being kept awake by recent user activity
                        if (nextTimeout >= now && mOverriddenTimeout == -1) {
                            // Save when the next timeout would have occurred
                            mOverriddenTimeout = nextTimeout;
                        }
                    }
                    mUserActivitySummary = USER_ACTIVITY_SCREEN_DREAM;
                    nextTimeout = -1;
                }
                if (mUserActivitySummary != 0 && nextTimeout >= 0) {
                    //发送一个异步Handler定时消息
                    Message msg = mHandler.obtainMessage(MSG_USER_ACTIVITY_TIMEOUT);
                    msg.setAsynchronous(true);
                    mHandler.sendMessageAtTime(msg, nextTimeout);
                }
            } else {//当wakefulness=Sleep的时候,直接将mUserActivitySummary置为0
                mUserActivitySummary = 0;
            }
        }
    }

mUserActivitySummary 的取值如下,这个状态的改变需要打开PowerManagerService的debug 才好看。能看到从 0x1 -> 0x2 - >0x4 这个状态切换。

    // Summarizes the user activity state.
    private static final int USER_ACTIVITY_SCREEN_BRIGHT = 1 << 0;
    private static final int USER_ACTIVITY_SCREEN_DIM = 1 << 1;
    private static final int USER_ACTIVITY_SCREEN_DREAM = 1 << 2;

updateUserActivitySummaryLocked 入口参数 now ,我们可以看到时间是系统的SYSTEM_TIME_MONOTONIC 时间,是系统启动以后流逝的时间。所有的时间操作都是相对于这个时间进行的。

 

获得系统睡眠超时时间,要从设定值和最小灭屏值选一个大的出来,最小灭屏值一般是10s,也就是说睡眠时间不能比最小的灭屏值还小。mSleepTimeoutSetting 是可以从设置菜单设置的,菜单 "Put device to sleep" 指定多长时间进入睡眠。

    private long getSleepTimeoutLocked() {
        final long timeout = mSleepTimeoutSetting;
        if (timeout <= 0) {
            return -1;
        }
        return Math.max(timeout, mMinimumScreenOffTimeoutConfig);
    }

在初始化updateSettingsLocked里面,从SettingsProvider读数据,如果没有设定过就是默认值。

        mScreenOffTimeoutSetting = Settings.System.getIntForUser(resolver,
                Settings.System.SCREEN_OFF_TIMEOUT, DEFAULT_SCREEN_OFF_TIMEOUT,
                UserHandle.USER_CURRENT);
        mSleepTimeoutSetting = Settings.Secure.getIntForUser(resolver,
                Settings.Secure.SLEEP_TIMEOUT, DEFAULT_SLEEP_TIMEOUT,
                UserHandle.USER_CURRENT);

后取 系统灭屏超时时间,这个主要是选一个睡眠超时和系统灭屏时间的较小值。比如前面的是灭屏是10s,睡眠是20s,那就是10s,反之还是10s。前面的两个if里面的条件一般不满足。mScreenOffTimeoutSetting 同样也是在设置菜单里可以设置的,Screen saver菜单 -》 When to start 菜单。这里可能不同型号的机器,菜单放置的位置不一样。

    private long getScreenOffTimeoutLocked(long sleepTimeout) {
        long timeout = mScreenOffTimeoutSetting;
        if (isMaximumScreenOffTimeoutFromDeviceAdminEnforcedLocked()) {
            timeout = Math.min(timeout, mMaximumScreenOffTimeoutFromDeviceAdmin);
        }
        if (mUserActivityTimeoutOverrideFromWindowManager >= 0) {
            timeout = Math.min(timeout, mUserActivityTimeoutOverrideFromWindowManager);
        }
        if (sleepTimeout >= 0) {
            timeout = Math.min(timeout, sleepTimeout);
        }
        return Math.max(timeout, mMinimumScreenOffTimeoutConfig);
    }

最小灭屏值是在framework/base里面config.xml里面设定的

<integer name="config_minimumScreenOffTimeout">10000</integer>

参考日志

mWakefulness从Dreaming到Dozing到Asleep,mUserActivitySummary从USER_ACTIVITY_SCREEN_DREAM到啥都没。

08-22 06:22:02.828  3064  5660 D PowerManagerService: updateUserActivitySummaryLocked: mWakefulness=Dreaming, mUserActivitySummary=0x4, nextTimeout=146181 (in 264 ms)
08-22 06:22:02.828  3064  5660 D PowerManagerService: updateDisplayPowerStateLocked: mDisplayReady=true, policy=3, mWakefulness=2, mWakeLockSummary=0x3, mUserActivitySummary=0x4, mBootCompleted=true, screenBrightnessOverride=-1, useAutoBrightness=false, mScreenBrightnessBoostInProgress=false, mIsVrModeEnabled= false, sQuiescent=false
 
08-22 06:22:03.093  3064  3089 D PowerManagerService: handleUserActivityTimeout
08-22 06:22:03.093  3064  3089 D PowerManagerService: updateUserActivitySummaryLocked: mWakefulness=Dreaming, mUserActivitySummary=0x0, nextTimeout=146181 (1 ms ago)
08-22 06:22:03.093  3064  3089 D PowerManagerService: updateDisplayPowerStateLocked: mDisplayReady=true, policy=3, mWakefulness=2, mWakeLockSummary=0x3, mUserActivitySummary=0x0, mBootCompleted=true, screenBrightnessOverride=-1, useAutoBrightness=false, mScreenBrightnessBoostInProgress=false, mIsVrModeEnabled= false, sQuiescent=false
08-22 06:22:03.093  3064  3089 D PowerManagerService: goToSleepNoUpdateLocked: eventTime=146182, reason=2, flags=0, uid=1000
08-22 06:22:03.093  3064  3089 I PowerManagerService: Going to sleep due to screen timeout (uid 1000)...
 
 
08-22 06:22:03.094  3064  3089 D PowerManagerService: updateWakeLockSummaryLocked: mWakefulness=Dozing, mWakeLockSummary=0x3
08-22 06:22:03.094  3064  3089 D PowerManagerService: updateUserActivitySummaryLocked: mWakefulness=Dozing, mUserActivitySummary=0x0, nextTimeout=146181 (2 ms ago)
08-22 06:22:03.094  3064  3089 D PowerManagerService: updateDisplayPowerStateLocked: mDisplayReady=true, policy=3, mWakefulness=3, mWakeLockSummary=0x3, mUserActivitySummary=0x0, mBootCompleted=true, screenBrightnessOverride=-1, useAutoBrightness=false, mScreenBrightnessBoostInProgress=false, mIsVrModeEnabled= false, sQuiescent=false
 
08-22 06:22:03.094  3064  3089 I DreamManagerService: Gently waking up from dream.
08-22 06:22:03.095  3064  3089 D PowerManagerService: reallyGoToSleepNoUpdateLocked: eventTime=146184, uid=1000
08-22 06:22:03.095  3064  3089 I PowerManagerService: Sleeping (uid 1000)...
08-22 06:22:03.095  3064  3089 D PowerManagerService: updateWakeLockSummaryLocked: mWakefulness=Asleep, mWakeLockSummary=0x1
08-22 06:22:03.095  3064  3089 D PowerManagerService: updateUserActivitySummaryLocked: mWakefulness=Asleep, mUserActivitySummary=0x0, nextTimeout=0 (146185 ms ago)
08-22 06:22:03.096  3064  3089 D PowerManagerService: updateDisplayPowerStateLocked: mDisplayReady=false, policy=0, mWakefulness=0, mWakeLockSummary=0x1, mUserActivitySummary=0x0, mBootCompleted=true, screenBrightnessOverride=-1, useAutoBrightness=false, mScreenBrightnessBoostInProgress=false, mIsVrModeEnabled= false, sQuiescent=false
08-22 06:22:03.096  3064  3085 I DreamManagerService: Performing gentle wake from dream.

 

这个分享很好,有些省略的知识都在里面了。

https://www.jianshu.com/p/9241f3a91095

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android PowerManagerService 中包含了一些 API,可帮助开发者监听屏保倒计时。 其中,最主要的 API 是 registerListener(),可以使用它来注册 PowerManager.OnThermalStatusChangedListener 类型的监听器。这个类型的监听器会在屏幕休眠时发出通知,在屏幕唤醒时则不触发。 另外,还可以使用 isScreenOn() 和 isInteractive() 这两个 API 来判断屏幕是否处于点亮状态和交互状态。如果屏幕都是关闭的,那么可以采取类似于下面的实现: ```java PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE); if (!powerManager.isInteractive()) { // 屏幕已关闭 } ``` 至于屏保倒计时的监测,可以使用下面这种方式来实现: ```java PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE); final long timeToScreenOff = powerManager.getScreenOffTimeout(); final long timeToScreenDim = powerManager.getScreenDimDuration(); final long timeUntilSleep = timeToScreenOff - timeToScreenDim; //屏保倒计时时间 final Handler mHandler = new Handler(Looper.getMainLooper()); final Runnable mRunnable = new Runnable() { @Override public void run() { //判断屏幕是否已关闭 if(!powerManager.isInteractive()){ Log.d(TAG, "屏幕已关闭"); mHandler.removeCallbacks(mRunnable); }else{ //屏保倒计时时间 long time = SystemClock.elapsedRealtime() - powerManager.getLastUserActivityTime(); //如果倒计时时间大于等于屏保倒计时时间,则触发屏保效果 if(time >= timeUntilSleep){ Log.d(TAG, "屏保效果触发"); mHandler.removeCallbacks(mRunnable); } } mHandler.postDelayed(mRunnable, 1000); } }; mRunnable.run(); //开启屏保倒计时的监测 ``` 这段代码的逻辑比较简单,就是每隔一秒检查一次屏幕是否关闭,并计算倒计时时间。如果倒计时时间大于等于屏保倒计时时间,则触发屏保效果。需要注意的是,在屏幕关闭后,该计时器会继续运行,因此需要在屏幕关闭时手动停止计时器。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值