Android 屏保时间的介绍

Android 屏保时间的介绍

屏保 当Android 系统处于无操作一段时间之后就会处于一个屏保的状态,当再过一点时间Android 就会进入一个休眠状体。

默认时间的设置

SettingsProvider 里面设置默认的超时时间。defaults.xml 里面配置的默认值,

    <integer name="def_screen_off_timeout">60000</integer> // 1分钟

DatabaseHelper 里面loadSystemSettings 里面对默认值进行设置。

private void loadSystemSettings(SQLiteDatabase db) {
        SQLiteStatement stmt = null;
        try {
            stmt = db.compileStatement("INSERT OR IGNORE INTO system(name,value)"
                    + " VALUES(?,?);");
            ···
            loadIntegerSetting(stmt, Settings.System.SCREEN_OFF_TIMEOUT,
                    R.integer.def_screen_off_timeout); // 本地化保存
            ···
        } finally {
            if (stmt != null) stmt.close();
        }
    }

如何对默认值进行设置。可以使用Overlay 进行设置,Overlay怎么设置 就可以参考google/atv/overlay/TvSettingsProviderOverlay 参考google 怎么设置的。
我们只对TvSettingsProvider 里面的defaults 进行重写把需要设置的 def_screen_off_timeout 重新赋值就行。

    <integer name="def_screen_off_timeout">120000</integer> // 2分钟

应用的设置和使用

这种设置功能只在设置里面进行设置,其他的应用里面正常不会操作。

  • 获取当前的默认时间
    Settings.System.getInt(getContentResolver(), SCREEN_OFF_TIMEOUT,
    DEFAULT_DREAM_TIME_MS);
  • 修改默认时间
    Settings.System.putInt(mView.provideContext().getContentResolver(), SCREEN_OFF_TIMEOUT, time);

普通应用 当我们页面不像进入屏保是 使用 keep_screen_on。
1 manifest 里面 设置 android:keepScreenOn="true"
2 时java 代码里面进行设置。
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
3 是使用PowerManager WakeLock 使用,这种我没使用过,
pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK, "MyTag");
wl.acquire();
wl.release();

屏保的计算

PowerManagerService里面
updatePowerStateLocked 这个方法是PowerManagerService 的核心方法 里面是对 屏幕的各种状态,用户活动,电源情况等各种情况的梳理都在这个方法里面。
属性 mScreenOffTimeoutSetting 是对屏保时间的记录,正常应该会有初始值的获取和值变化的更新。

 public void systemReady(IAppOpsService appOps) {
        synchronized (mLock) {
            mSystemReady = true;
            ···
            mSettingsObserver = new SettingsObserver(mHandler);
           ···
            updateSettingsLocked(); // 初始化 
            mDirty |= DIRTY_BATTERY_STATE;
            updatePowerStateLocked(); // 更新各种状态
        }

        final ContentResolver resolver = mContext.getContentResolver();
        ···
        resolver.registerContentObserver(Settings.System.getUriFor(
                Settings.System.SCREEN_OFF_TIMEOUT),
                false, mSettingsObserver, UserHandle.USER_ALL); // 监听变化
      ···
    }

  private final class SettingsObserver extends ContentObserver {
        @Override
        public void onChange(boolean selfChange, Uri uri) {
            synchronized (mLock) {
                handleSettingsChangedLocked(); // 变化时候进行
            }
        }
    }

void handleSettingsChangedLocked() {
        updateSettingsLocked(); // 监听变化
        updatePowerStateLocked(); // 更新各种状态
    }

updateSettingsLocked 里面 对 mScreenOffTimeoutSetting进行赋值。
mScreenOffTimeoutSetting = Settings.System.getIntForUser(resolver,
Settings.System.SCREEN_OFF_TIMEOUT, DEFAULT_SCREEN_OFF_TIMEOUT,
UserHandle.USER_CURRENT);

mSettingsObserver 里面监听到变化之后 立马调用 updateSettingsLocked 更新值的变化,之后调用updatePowerStateLocked,根据最新的值取更新各个状态。

updatePowerStateLocked 方法

/**
    * Updates the global power state based on dirty bits recorded in mDirty.
    *
    * This is the main function that performs power state transitions.
    * We centralize them here so that we can recompute the power state completely
    * each time something important changes, and ensure that we do it the same
    * way each time.  The point is to gather all of the transition logic here.
    */
   private void updatePowerStateLocked() {
    ···

       Trace.traceBegin(Trace.TRACE_TAG_POWER, "updatePowerState");
// 查询了一下 Trace   成对出现 key 一样 记录 cpu 线程 耗时等信息
// 类似于 android studio 的 profile 下抓取信息

       try {
           // Phase 0: Basic state updates.
           updateIsPoweredLocked(mDirty); // 更新电源信息 是否 插入电源 电源类型 电池的状态  有变化的话 更新mDirty 的值 。 
           updateStayOnLocked(mDirty); // 更新屏幕唤醒 
           updateScreenBrightnessBoostLocked(mDirty);// 更新屏幕亮度 时间 增强结束 里面通过 handler 发送时间

           // Phase 1: Update wakefulness.
           // Loop because the wake lock and user activity computations are influenced
           // by changes in wakefulness.
           final long now = mClock.uptimeMillis();
           int dirtyPhase2 = 0;
           for (;;) {
               int dirtyPhase1 = mDirty;
               dirtyPhase2 |= dirtyPhase1;
               mDirty = 0;
               updateWakeLockSummaryLocked(dirtyPhase1); // 更新 mWakeLockSummary 遍历 所有的 mWakeLocks 把 WakeLock 信息都保存到 mWakeLockSummary 。
               updateUserActivitySummaryLocked(now, dirtyPhase1); // 更新用户时间
               updateAttentiveStateLocked(now, dirtyPhase1);
               if (!updateWakefulnessLocked(dirtyPhase1)) { // 设置Wakefulness 状态 包含dream
                   break; 
               }
           }

           // Phase 2: Lock profiles that became inactive/not kept awake.
           updateProfilesLocked(now);

           // Phase 3: Update display power state.
           final boolean displayBecameReady = updateDisplayPowerStateLocked(dirtyPhase2); // 请求display 进行变化操作

           // Phase 4: Update dream state (depends on display ready signal).
           updateDreamLocked(dirtyPhase2, displayBecameReady); // dream 操作

           // Phase 5: Send notifications, if needed.
           finishWakefulnessChangeIfNeededLocked(); // 发送通知

           // Phase 6: Update suspend blocker.
           // Because we might release the last suspend blocker here, we need to make sure
           // we finished everything else first!
           updateSuspendBlockerLocked();
       } finally {
           Trace.traceEnd(Trace.TRACE_TAG_POWER);
       }
   }

updatePowerStateLocked 方法里面有四个方法对屏保设置有关。
1 updateUserActivitySummaryLocked
方法 updateUserActivitySummaryLocked 更新mUserActivitySummary 用来总结用户请求系统状态,比如设置屏幕 bright dream dim 等。
注意 nextTimeout hasUserActivitySummary 循环内部 groupUserActivitySummary 和groupNextTimeout 内部变量。
内部循环 通过 groupUserActivitySummary groupNextTimeout 计算出 nextTimeout hasUserActivitySummary 。
最终调用 scheduleUserInactivityTimeout-- 》 mHandler ==〉》MSG_USER_ACTIVITY_TIMEOUT --》 handleUserActivityTimeout(){
mDirty |= DIRTY_USER_ACTIVITY;
updatePowerStateLocked();}

 /**
     * Updates the value of mUserActivitySummary to summarize the user requested
     * state of the system such as whether the screen should be bright or dim.
     * Note that user activity is ignored when the system is asleep.
      
     *
     */
    private void updateUserActivitySummaryLocked(long now, int dirty) {
        // Update the status of the user activity timeout timer.
        if ((dirty & (DIRTY_DISPLAY_GROUP_WAKEFULNESS | DIRTY_WAKE_LOCKS
                | DIRTY_USER_ACTIVITY | DIRTY_WAKEFULNESS | DIRTY_SETTINGS)) == 0) {
            return;
        }
        mHandler.removeMessages(MSG_USER_ACTIVITY_TIMEOUT);

        final long attentiveTimeout = getAttentiveTimeoutLocked();// 进入Sleep 之前得提示得延时时间
     // 获取休眠 超时时长
        final long sleepTimeout = getSleepTimeoutLocked(attentiveTimeout);
      // 获取屏保超时时长
        long screenOffTimeout = getScreenOffTimeoutLocked(sleepTimeout,
                attentiveTimeout);
// 获取dim时长 由 休眠市场 乘以 dim 百分比 获取再与默认值 做对比取最大值
        final long screenDimDuration = getScreenDimDurationLocked(screenOffTimeout);
// 根据 faceDown 标记 重新设置 屏保超时时长  脸部朝下的判断
        screenOffTimeout =
                getScreenOffTimeoutWithFaceDownLocked(screenOffTimeout, screenDimDuration);
        final boolean userInactiveOverride = mUserInactiveOverrideFromWindowManager;
        long nextTimeout = -1; // 最终 nextTime  计算下面Inactivity 的时间
        boolean hasUserActivitySummary = false; // 用户请求是否变化
        for (int groupId : mDisplayGroupPowerStateMapper.getDisplayGroupIdsLocked()) {
            int groupUserActivitySummary = 0; // 循环内部 用户请求屏幕变化
            long groupNextTimeout = 0; // 循环内部 next inactivity 的时间 
            if (mDisplayGroupPowerStateMapper.getWakefulnessLocked(groupId) != WAKEFULNESS_ASLEEP) {
                final long lastUserActivityTime =
                         mDisplayGroupPowerStateMapper.getLastUserActivityTimeLocked(groupId); 
                final long lastUserActivityTimeNoChangeLights =
                        mDisplayGroupPowerStateMapper.getLastUserActivityTimeNoChangeLightsLocked(
                                groupId);
// 判断接下来是 继续 screen 还是 进入 dim
                if (lastUserActivityTime >= mLastWakeTime) { // 判断 上次用户活动时间 大于上次wake 时间
                    groupNextTimeout = lastUserActivityTime + screenOffTimeout - screenDimDuration;
                    if (now < groupNextTimeout) { // 没到dim 时间 继续 亮屏
                        groupUserActivitySummary = USER_ACTIVITY_SCREEN_BRIGHT;
                    } else {
                        groupNextTimeout = lastUserActivityTime + screenOffTimeout;
                        if (now < groupNextTimeout) { // 到了dim 时间 标记dim                            groupUserActivitySummary = USER_ACTIVITY_SCREEN_DIM;
                        }
                    }
                }

         //  根据 DisplayPowerRequest 来设置 显示类型
                if (groupUserActivitySummary == 0
                        && lastUserActivityTimeNoChangeLights >= mLastWakeTime) {
                    groupNextTimeout = lastUserActivityTimeNoChangeLights + screenOffTimeout;
                    if (now < groupNextTimeout) {
                        final DisplayPowerRequest displayPowerRequest =
                                mDisplayGroupPowerStateMapper.getPowerRequestLocked(groupId);
                        if (displayPowerRequest.policy == DisplayPowerRequest.POLICY_BRIGHT
                                || displayPowerRequest.policy == DisplayPowerRequest.POLICY_VR) {
                            groupUserActivitySummary = USER_ACTIVITY_SCREEN_BRIGHT;
                        } else if (displayPowerRequest.policy == DisplayPowerRequest.POLICY_DIM) {
                            groupUserActivitySummary = USER_ACTIVITY_SCREEN_DIM;
                        }
                    }
                }

                if (groupUserActivitySummary == 0) {
                    if (sleepTimeout >= 0) { // 休眠时常 
                        final long anyUserActivity = Math.max(lastUserActivityTime,
                                lastUserActivityTimeNoChangeLights);
                        if (anyUserActivity >= mLastWakeTime) {
                            groupNextTimeout = anyUserActivity + sleepTimeout;
                            if (now < groupNextTimeout) { // 还没超过休眠的时间
                                groupUserActivitySummary = USER_ACTIVITY_SCREEN_DREAM;
                            }
                        }
                    } else {
                        groupUserActivitySummary = USER_ACTIVITY_SCREEN_DREAM;// 一直休眠
                        groupNextTimeout = -1;
                    }
                }

                if (groupUserActivitySummary != USER_ACTIVITY_SCREEN_DREAM
                        && userInactiveOverride) {
                    if ((groupUserActivitySummary &
                            (USER_ACTIVITY_SCREEN_BRIGHT | USER_ACTIVITY_SCREEN_DIM)) != 0) {// 保持 bright 或者dim
                        // Device is being kept awake by recent user activity
                        if (mOverriddenTimeout == -1) {
                            // Save when the next timeout would have occurred
                            mOverriddenTimeout = groupNextTimeout;
                        }
                    }
                    groupUserActivitySummary = USER_ACTIVITY_SCREEN_DREAM;
                    groupNextTimeout = -1;
                }

                if ((groupUserActivitySummary & USER_ACTIVITY_SCREEN_BRIGHT) != 0
                        && (mDisplayGroupPowerStateMapper.getWakeLockSummaryLocked(groupId)
                        & WAKE_LOCK_STAY_AWAKE) == 0) { // 保持亮度并且 没有 STAY_AWAKE 的情况
                    groupNextTimeout = mAttentionDetector.updateUserActivity(groupNextTimeout,
                            screenDimDuration); // 获取下次检查dim 时间
                }

                hasUserActivitySummary |= groupUserActivitySummary != 0;

                if (nextTimeout == -1) {
                    nextTimeout = groupNextTimeout;
                } else if (groupNextTimeout != -1) {
                    nextTimeout = Math.min(nextTimeout, groupNextTimeout);
                }
            }

            mDisplayGroupPowerStateMapper.setUserActivitySummaryLocked(groupId,
                    groupUserActivitySummary);

            if (DEBUG_SPEW) {
                Slog.d(TAG, "updateUserActivitySummaryLocked: groupId=" + groupId
                        + ", mWakefulness=" + wakefulnessToString(
                        mDisplayGroupPowerStateMapper.getWakefulnessLocked(groupId))
                        + ", mUserActivitySummary=0x" + Integer.toHexString(
                        groupUserActivitySummary)
                        + ", nextTimeout=" + TimeUtils.formatUptime(groupNextTimeout));
            }
        }

        final long nextProfileTimeout = getNextProfileTimeoutLocked(now);
        if (nextProfileTimeout > 0) {
            nextTimeout = Math.min(nextTimeout, nextProfileTimeout);
        }

        if (hasUserActivitySummary && nextTimeout >= 0) {
            scheduleUserInactivityTimeout(nextTimeout);
        }
    }

2 updateWakefulnessLocked
方法。updateWakefulnessLocked 返回 false 退出循环
for 循环最多走一次 dirty = 0 时候 退出 有第二次的话 dirty 被重新赋值为0。
里面 sleepDisplayGroupNoUpdateLocked 和sleepDisplayGroupNoUpdateLocked 更新 wakefullness 的状态。

 private boolean updateWakefulnessLocked(int dirty) {
        boolean changed = false;
        if ((dirty & (DIRTY_WAKE_LOCKS | DIRTY_USER_ACTIVITY | DIRTY_BOOT_COMPLETED
                | DIRTY_WAKEFULNESS | DIRTY_STAY_ON | DIRTY_PROXIMITY_POSITIVE
                | DIRTY_DOCK_STATE | DIRTY_ATTENTIVE | DIRTY_SETTINGS
                | DIRTY_SCREEN_BRIGHTNESS_BOOST)) != 0) {
            final long time = mClock.uptimeMillis();
            for (int id : mDisplayGroupPowerStateMapper.getDisplayGroupIdsLocked()) {
//屏幕是唤醒状态并且将要推出唤醒 (屏保或者休眠) 
                if (mDisplayGroupPowerStateMapper.getWakefulnessLocked(id) == WAKEFULNESS_AWAKE
                        && isItBedTimeYetLocked(id)) {.
                    if (DEBUG_SPEW) {
                        Slog.d(TAG, "updateWakefulnessLocked: Bed time for group " + id);
                    }
                    if (isAttentiveTimeoutExpired(id, time)) { // 提醒时间到了
                        changed = sleepDisplayGroupNoUpdateLocked(id, time,
                                PowerManager.GO_TO_SLEEP_REASON_TIMEOUT,
                                PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE, Process.SYSTEM_UID);
                    } else if (shouldNapAtBedTimeLocked()) {
//是否支持屏保
                        changed = dreamDisplayGroupNoUpdateLocked(id, time, Process.SYSTEM_UID);
                    } else {
// 正常灭屏 超市自动灭屏
                        changed = sleepDisplayGroupNoUpdateLocked(id, time,
                                PowerManager.GO_TO_SLEEP_REASON_TIMEOUT, 0, Process.SYSTEM_UID);
                    }
                }
            }
        }
        return changed;
    }

dreamDisplayGroupNoUpdateLocked 设置当前之后的状态是 dream 状态。

 private boolean dreamDisplayGroupNoUpdateLocked(int groupId, long eventTime, int uid) {
       ···
            mDisplayGroupPowerStateMapper.setSandmanSummoned(groupId, true);
            setWakefulnessLocked(groupId, WAKEFULNESS_DREAMING, eventTime, uid, /* reason= */
                    0, /* opUid= */ 0, /* opPackageName= */ null, /* details= */ null);

      ···
        return true;
    }

3 updateDisplayPowerStateLocked 方法 里面声明了对DisplayPower 的进行的设置 初始化 DisplayPowerRequest displayPowerRequest 然后对他进行搁置参数的设置
然后请求请求成功后 final boolean ready = mDisplayManagerInternal.requestPowerState(groupId,
displayPowerRequest, mRequestWaitForNegativeProximity); mDisplayGroupPowerStateMapper.setDisplayGroupReadyLocked(groupId, ready);
这里对setReady 对后面 更新Dream 的时候 有个使用的判断。

 private boolean updateDisplayPowerStateLocked(int dirty) {
        final boolean oldDisplayReady = mDisplayGroupPowerStateMapper.areAllDisplaysReadyLocked();
        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 | DIRTY_DISPLAY_GROUP_WAKEFULNESS)) != 0) {
            if ((dirty & DIRTY_QUIESCENT) != 0) {
                if (mDisplayGroupPowerStateMapper.areAllDisplaysReadyLocked()) {
                    sQuiescent = false;
                } else {
                    mDirty |= DIRTY_QUIESCENT;
                }
            }

            for (final int groupId : mDisplayGroupPowerStateMapper.getDisplayGroupIdsLocked()) {
                final DisplayPowerRequest displayPowerRequest =
                        mDisplayGroupPowerStateMapper.getPowerRequestLocked(groupId);
                displayPowerRequest.policy = getDesiredScreenPolicyLocked(groupId);

                // Determine appropriate screen brightness and auto-brightness adjustments.
                final boolean autoBrightness;
                final float screenBrightnessOverride;
                if (!mBootCompleted) {
                    // Keep the brightness steady during boot. This requires the
                    // bootloader brightness and the default brightness to be identical.
                    autoBrightness = false;
                    screenBrightnessOverride = mScreenBrightnessDefault;
                } else if (isValidBrightness(mScreenBrightnessOverrideFromWindowManager)) {
                    autoBrightness = false;
                    screenBrightnessOverride = mScreenBrightnessOverrideFromWindowManager;
                } else {
                    autoBrightness = (mScreenBrightnessModeSetting
                            == Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC);
                    screenBrightnessOverride = PowerManager.BRIGHTNESS_INVALID_FLOAT;
                }

                // Update display power request.
                displayPowerRequest.screenBrightnessOverride = screenBrightnessOverride;
                displayPowerRequest.useAutoBrightness = autoBrightness;
                displayPowerRequest.useProximitySensor = shouldUseProximitySensorLocked();
                displayPowerRequest.boostScreenBrightness = shouldBoostScreenBrightness();

                updatePowerRequestFromBatterySaverPolicy(displayPowerRequest);

                if (displayPowerRequest.policy == DisplayPowerRequest.POLICY_DOZE) {
                    displayPowerRequest.dozeScreenState = mDozeScreenStateOverrideFromDreamManager;
                    if ((mDisplayGroupPowerStateMapper.getWakeLockSummaryLocked(groupId)
                            & WAKE_LOCK_DRAW) != 0 && !mDrawWakeLockOverrideFromSidekick) {
                        if (displayPowerRequest.dozeScreenState == Display.STATE_DOZE_SUSPEND) {
                            displayPowerRequest.dozeScreenState = Display.STATE_DOZE;
                        }
                        if (displayPowerRequest.dozeScreenState == Display.STATE_ON_SUSPEND) {
                            displayPowerRequest.dozeScreenState = Display.STATE_ON;
                        }
                    }
                    displayPowerRequest.dozeScreenBrightness =
                            mDozeScreenBrightnessOverrideFromDreamManagerFloat;
                } else {
                    displayPowerRequest.dozeScreenState = Display.STATE_UNKNOWN;
                    displayPowerRequest.dozeScreenBrightness =
                            PowerManager.BRIGHTNESS_INVALID_FLOAT;
                }

                final boolean ready = mDisplayManagerInternal.requestPowerState(groupId,
                        displayPowerRequest, mRequestWaitForNegativeProximity);
                mNotifier.onScreenPolicyUpdate(displayPowerRequest.policy);

                final boolean displayReadyStateChanged =
                        mDisplayGroupPowerStateMapper.setDisplayGroupReadyLocked(groupId, ready);
                final boolean poweringOn =
                        mDisplayGroupPowerStateMapper.isPoweringOnLocked(groupId);
                if (ready && displayReadyStateChanged && poweringOn
                        && mDisplayGroupPowerStateMapper.getWakefulnessLocked(
                        groupId) == WAKEFULNESS_AWAKE) {
                    mDisplayGroupPowerStateMapper.setPoweringOnLocked(groupId, false);
                    Trace.asyncTraceEnd(Trace.TRACE_TAG_POWER, TRACE_SCREEN_ON, groupId);
                    final int latencyMs = (int) (mClock.uptimeMillis()
                            - mDisplayGroupPowerStateMapper.getLastPowerOnTimeLocked(groupId));
                    if (latencyMs >= SCREEN_ON_LATENCY_WARNING_MS) {
                        Slog.w(TAG, "Screen on took " + latencyMs + " ms");
                    }
                }
            }
            mRequestWaitForNegativeProximity = false;
        }

        return mDisplayGroupPowerStateMapper.areAllDisplaysReadyLocked() && !oldDisplayReady;
    }

4 updateDreamLocked 方法

里面 调用到 scheduleSandmanLocked(); 里面 handler 发送 MSG_SANDMAN

 if (mDisplayGroupPowerStateMapper.isSandmanSupported(id)) { // 是否支持dream
                    Message msg = mHandler.obtainMessage(MSG_SANDMAN);
                    msg.arg1 = id;
                    msg.setAsynchronous(true);
                    mHandler.sendMessage(msg);
                }

handleSandman 对 是否start dream 进行了判断

上面 dreamDisplayGroupNoUpdateLocked 对 wakefulness 和 isSandmanSummoned 两个条件进行了设置
sleepDisplayGroupNoUpdateLocked 里面也对 WAKEFULNESS_DOZING 进行了设置。
mDisplayGroupPowerStateMapper.isReady(groupId))判断 updateDisplayPowerStateLocked 对这个ready 进行了设置

canDreamLocked对dream 的条件进行判断,主要是一些电量和状态,开关,后面有介绍。
canDozeLocked 对Doz条件的判断。

startDreaming 是true 的时候 DreamManager来进行 dream 开启。

private void handleSandman(int groupId) { // runs on handler thread
        // Handle preconditions.
        final boolean startDreaming;
        final int wakefulness;
        synchronized (mLock) {
            mSandmanScheduled = false;
            final int[] ids = mDisplayGroupPowerStateMapper.getDisplayGroupIdsLocked();
            if (!ArrayUtils.contains(ids, groupId)) {
                // Group has been removed.
                return;
            }
            wakefulness = mDisplayGroupPowerStateMapper.getWakefulnessLocked(groupId);
            if ((wakefulness == WAKEFULNESS_DREAMING || wakefulness == WAKEFULNESS_DOZING) &&
                    mDisplayGroupPowerStateMapper.isSandmanSummoned(groupId)
                    && mDisplayGroupPowerStateMapper.isReady(groupId)) {
                startDreaming = canDreamLocked(groupId) || canDozeLocked();
                mDisplayGroupPowerStateMapper.setSandmanSummoned(groupId, false);
            } else {
                startDreaming = false;
            }
        }
// 上面判断是否dream  上面 dreamDisplayGroupNoUpdateLocked 对 wakefulness 和 isSandmanSummoned 两个条件进行了设置。

        // Start dreaming if needed.
        // We only control the dream on the handler thread, so we don't need to worry about
        // concurrent attempts to start or stop the dream.
        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);
            }
            isDreaming = mDreamManager.isDreaming();
        } else {
            isDreaming = false;
        }

        // At this point, we either attempted to start the dream or no attempt will be made,
        // so stop holding the display suspend blocker for Doze.
        mDozeStartInProgress = false;

        // Update dream state.
        synchronized (mLock) {
            final int[] ids = mDisplayGroupPowerStateMapper.getDisplayGroupIdsLocked();
            if (!ArrayUtils.contains(ids, groupId)) {
                // Group has been removed.
                return;
            }

            // Remember the initial battery level when the dream started.
            if (startDreaming && isDreaming) {// 记录当前电池水平
                mBatteryLevelWhenDreamStarted = mBatteryLevel;
                if (wakefulness == WAKEFULNESS_DOZING) {
                    Slog.i(TAG, "Dozing...");
                } else {
                    Slog.i(TAG, "Dreaming...");
                }
            }

            // If preconditions changed, wait for the next iteration to determine
            // whether the dream should continue (or be restarted).
            if (mDisplayGroupPowerStateMapper.isSandmanSummoned(groupId) // 如果是 start dream 的话 上面判断startdream 的时候 设置成false 了
                    || mDisplayGroupPowerStateMapper.getWakefulnessLocked(groupId) != wakefulness) { // getWakefulnessLocked 改变的话return 
                return; // wait for next cycle
            }

            // Determine whether the dream should continue.
            long now = mClock.uptimeMillis();
            if (wakefulness == WAKEFULNESS_DREAMING) {
                if (isDreaming && canDreamLocked(groupId)) {
                    // 当前 掉电比较快  mDreamsBatteryLevelDrainCutoffConfig  掉电一个标记 大于这个值 就要停止掉dream
                    if (mDreamsBatteryLevelDrainCutoffConfig >= 0
                            && mBatteryLevel < mBatteryLevelWhenDreamStarted
                                    - mDreamsBatteryLevelDrainCutoffConfig
                            && !isBeingKeptAwakeLocked(groupId)) {
                        // If the user activity timeout expired and the battery appears
                        // to be draining faster than it is charging then stop dreaming
                        // and go to sleep.
                        Slog.i(TAG, "Stopping dream because the battery appears to "
                                + "be draining faster than it is charging.  "
                                + "Battery level when dream started: "
                                + mBatteryLevelWhenDreamStarted + "%.  "
                                + "Battery level now: " + mBatteryLevel + "%.");
                    } else {
                        return; // continue dreaming
                    }
                }
               // 停止 dream
                // Dream has ended or will be stopped.  Update the power state.
                if (isItBedTimeYetLocked(groupId)) {
                    final int flags = isAttentiveTimeoutExpired(groupId, now)
                            ? PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE : 0;
// 休眠
                    sleepDisplayGroupNoUpdateLocked(groupId, now,
                            PowerManager.GO_TO_SLEEP_REASON_TIMEOUT, flags, Process.SYSTEM_UID);
                } else {
//唤醒 
                    wakeDisplayGroupNoUpdateLocked(groupId, now, 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
                }
                // 跟新 power state 
                // Doze has ended or will be stopped.  Update the power state.
                reallySleepDisplayGroupNoUpdateLocked(groupId, now, Process.SYSTEM_UID);
                updatePowerStateLocked();
            }
        }

        // Stop dream.
        if (isDreaming) {
            mDreamManager.stopDream(false /*immediate*/);
        }
    }

canDreamLocked

private boolean canDreamLocked(int groupId) {
        final DisplayPowerRequest displayPowerRequest =
                mDisplayGroupPowerStateMapper.getPowerRequestLocked(groupId);
        if (!mBootCompleted // 初始化走完
                || getWakefulnessLocked() != WAKEFULNESS_DREAMING // wakefullness 是 WAKEFULNESS_DREAMING
                || !mDreamsSupportedConfig  // 设备支持 
                || !mDreamsEnabledSetting // dream开关开启
                || !displayPowerRequest.isBrightOrDim() // 没有request Bright 或者是Dim
                || displayPowerRequest.isVr()
                || (mDisplayGroupPowerStateMapper.getUserActivitySummaryLocked(groupId) & (
                USER_ACTIVITY_SCREEN_BRIGHT | USER_ACTIVITY_SCREEN_DIM
                        | USER_ACTIVITY_SCREEN_DREAM)) == 0) {
            return false;
        }
        if (!isBeingKeptAwakeLocked(groupId)) { // 不处于唤醒状态
            if (!mIsPowered && !mDreamsEnabledOnBatteryConfig) { //  没充电 电源选项没配置 不可dream
                return false;
            }
            if (!mIsPowered
                    && mDreamsBatteryLevelMinimumWhenNotPoweredConfig >= 0
                    && mBatteryLevel < mDreamsBatteryLevelMinimumWhenNotPoweredConfig) { // 没充电 电量过低
                return false;
            }
//  1 充电 2  dream充电最小电池水平小与0  3 当前电量水平大于dream充电最小电池水平 三个 满足一个是true
            return !mIsPowered
                    || mDreamsBatteryLevelMinimumWhenPoweredConfig < 0
                    || mBatteryLevel >= mDreamsBatteryLevelMinimumWhenPoweredConfig;
        }
        return true;
    }

canDozeLocked 判断就计较简单 判断wakefulness

  private boolean canDozeLocked() {
        return getWakefulnessLocked() == WAKEFULNESS_DOZING;
    }
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,802评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,109评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,683评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,458评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,452评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,505评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,901评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,550评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,763评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,556评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,629评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,330评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,898评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,897评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,140评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,807评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,339评论 2 342

推荐阅读更多精彩内容

  • 安卓电源状态 首先安卓将电源分为以下几种情况: 1.sleep:休眠 从代码看,安卓将系统的休眠原因分为以下几种:...
    superme_阅读 4,919评论 0 1
  • https://juejin.cn/post/6946581970960793613 在Andorid Frame...
    superme_阅读 1,924评论 0 1
  • 在Andorid Framework层中,PowerManagerService(以下简称PMS)模块负责协调、管...
    Andriod采码蜂阅读 1,414评论 0 0
  • 我们按下电源键就会灭屏,再按一下就会唤醒屏幕,这个是怎样的过程呢。 电源键有许多额外功能,为了能让这个主题更加清晰...
    CocoDoll阅读 6,307评论 0 7
  • 分析了PMS部分的亮屏流程。PMS模块中也提供了灭屏接口goTosleep(),方法给其他组件或应用来关闭屏幕,这...
    superme_阅读 2,869评论 1 1