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

前面的博客中,我们已经分析过,当Android中的进程要使用电量时,需要向PMS申请WakeLock;当进程完成工作后,需要释放对应的WakeLock。
PMS收到申请和释放WakeLock的请求后,均需要调用updatePowerStateLocked来更新电源的状态,该函数是PMS的核心方法。
接下来,我们就结合代码,看一下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() {
    //未启动完毕或mDirty没有记录变化
    if (!mSystemReady || mDirty == 0) {
        return;
    }
    ..........
    try {
        // Basic state updates.
        // 1、更新基本状态
        updateIsPoweredLocked(mDirty);
        updateStayOnLocked(mDirty);
        updateScreenBrightnessBoostLocked(mDirty);

        // Update wakefulness.
        // Loop because the wake lock and user activity computations are influenced
        // by changes in wakefulness.
        // 2、更新wakelock和用户活动 
        final long now = SystemClock.uptimeMillis();
        int dirtyPhase2 = 0;
        for (;;) {
            int dirtyPhase1 = mDirty;
            dirtyPhase2 |= dirtyPhase1;
            mDirty = 0;

            updateWakeLockSummaryLocked(dirtyPhase1);
            updateUserActivitySummaryLocked(now, dirtyPhase1);
            if (!updateWakefulnessLocked(dirtyPhase1)) {
                break;
            }
        }

        // Update display power state.
        // 3、更新display power state
        boolean displayBecameReady = updateDisplayPowerStateLocked(dirtyPhase2);

        // Update dream state (depends on display ready signal).
        // 4、更新dream state
        updateDreamLocked(dirtyPhase2, displayBecameReady);

        // Send notifications, if needed.
        finishWakefulnessChangeIfNeededLocked();

        // Update suspend blocker.
        // Because we might release the last suspend blocker here, we need to make sure
        // we finished everything else first!
        // 5、更新suspend blocker
        updateSuspendBlockerLocked();
    } finally {
        ..........
    }
}

在PMS中有个很重要的变量mDirty,该变量按位存储PMS中的各种变化状态。
例如,之前介绍PMS的acquire WakeLock流程时,就进行了以下操作:

.........
mDirty |= DIRTY_WAKE_LOCKS;
........

每当PMS检测到一些重要事件发生时,就会更新mDirty的相应的位。
从updatePowerStateLocked的代码可以看出,它将根据mDirty中的信息,来更新手机中的电源状态。

根据Android源码中的注释,可以看出updatePowerStateLocked的工作主要分为几个步骤,接下来我们一个一个步骤的来进行分析。

一、更新基本状态信息
1、updateIsPoweredLocked
我们先来看看updateIsPoweredLocked函数:

private void updateIsPoweredLocked(int dirty) {
    //DIRTY_BATTERY_STATE位置1时,表示终端的电源状态发生了改变
    if ((dirty & DIRTY_BATTERY_STATE) != 0) {
        //记录过去的状态
        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;

            // Update wireless dock detection state.
            //无线充电相关,暂时不用管
            final boolean dockedOnWirelessCharger = mWirelessChargerDetector.update(
                    mIsPowered, mPlugType, mBatteryLevel);

            final long now = SystemClock.uptimeMillis();
            //判断插拔充电器或者USB是否需要唤醒屏幕  
            if (shouldWakeUpWhenPluggedOrUnpluggedLocked(wasPowered, oldPlugType,
                    dockedOnWirelessCharger)) {
                //之前的博客中已经分析过这个函数,主要是做好唤醒终端屏幕前的准备工作
                wakeUpNoUpdateLocked(now, "android.server.power:POWER", Process.SYSTEM_UID,
                        mContext.getOpPackageName(), Process.SYSTEM_UID);
            }
            //触发一次用户活动,修改PMS中记录用户活动事件的时间,同时通知BatteryStatsService等
            userActivityNoUpdateLocked(
                    now, PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, Process.SYSTEM_UID);

            // Tell the notifier whether wireless charging has started so that
            // it can provide feedback to the user.
            //无线充电相关的通知,暂时可以不管
            if (dockedOnWirelessCharger) {
                mNotifier.onWirelessChargingStarted();
            }
        }

        if (wasPowered != mIsPowered || oldLevelLow != mBatteryLevelLow) {
            //结束低电的状态
            if (oldLevelLow != mBatteryLevelLow && !mBatteryLevelLow) {
                ........
                //从命名来看,该标志用于决定终端在低电模式下是否“打盹”(接近休眠)
                mAutoLowPowerModeSnoozing = false;
            }
            //更新低电模式相关的操作
            updateLowPowerModeLocked();
        }
    }
}

从以上代码可以看出updateIsPoweredLocked主要用于:
更新PMS中的一些变量,包括记录终端是否在充电、充电的类型、电池的电量及电池电量是否处于低电状态;
当电源的充电状态,或者充电类型发生变化,判断出现插拔充电器等操作时,是否需要点亮或熄灭屏幕;
当电源充电状态发生变化,或者终端是否处于低电量的标志发生变化的时候,终端调用updateLowPowerModeLocked()更新低电模式相关的操作。

我们跟进一下updateLowPowerModeLocked函数:

private void updateLowPowerModeLocked() {
    //处于充电状态,并且设置过低电模式的标志位
    if (mIsPowered && mLowPowerModeSetting) {
        ........    
        // Turn setting off if powered
        //更新数据库,关闭低电模式
        Settings.Global.putInt(mContext.getContentResolver(),
                Settings.Global.LOW_POWER_MODE, 0);
        mLowPowerModeSetting = false;
    }

    //判断是否可以进入自动省电模式
    //要求是:未充电 && 进行了自动省电的配置 && 没有设置低电“打盹” && 电池电量低
    final boolean autoLowPowerModeEnabled = !mIsPowered && mAutoLowPowerModeConfigured
            && !mAutoLowPowerModeSnoozing && mBatteryLevelLow;

    //当前是否为低电模式
    final boolean lowPowerModeEnabled = mLowPowerModeSetting || autoLowPowerModeEnabled;

    if (mLowPowerModeEnabled != lowPowerModeEnabled) {
        mLowPowerModeEnabled = lowPowerModeEnabled;
        //调用底层动态库的powerHint函数
        powerHintInternal(POWER_HINT_LOW_POWER, lowPowerModeEnabled ? 1 : 0);

        //开机完成后才能执行的Runnable对象
        postAfterBootCompleted(new Runnable() {
            //发送低电模式CHANGING的广播
            Intent intent = new Intent(PowerManager.ACTION_POWER_SAVE_MODE_CHANGING)
                    .putExtra(PowerManager.EXTRA_POWER_SAVE_MODE, mLowPowerModeEnabled)
                    .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
            mContext.sendBroadcast(intent);

            //PMS提供了registerLowPowerModeObserver的接口
            //其它进程可以调用该接口,注册观察者
            synchronized (mLock) {
                listeners = new ArrayList<PowerManagerInternal.LowPowerModeListener>(
                        mLowPowerModeListeners);
            }
            for (int i=0; i<listeners.size(); i++) {
                //调用回调接口的onLowPowerModeChanged函数,通知其它进程低电模式发生改变
                listeners.get(i).onLowPowerModeChanged(lowPowerModeEnabled);
            }

            //再次发送CHANGED广播
            intent = new Intent(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED);
                intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
                mContext.sendBroadcast(intent);

            // Send internal version that requires signature permission.
            mContext.sendBroadcastAsUser(new Intent(
                    PowerManager.ACTION_POWER_SAVE_MODE_CHANGED_INTERNAL), UserHandle.ALL,
                    Manifest.permission.DEVICE_POWER);
        });
    }
}

从上面的代码可以看出updateLowPowerModeLocked函数,
首先判断手机是否在充电,如果手机在充电,退出LowPowerMode模式,同时更新数据库;
当手机的低电量模式发生了变化,就发送广播进行通知,并回调关于监听该模式变化的观察者的接口。
例如:UI对应的APK收到低电量省电模式的广播,就会弹出低电量省电模式的提醒界面。

可以看出这一部分除了更新PMS中的一些变量外,关注的重点还是集中在:
充电状态是否改变;
充电状态的改变,将引出对充电器插拔是否需要亮屏的考虑;
同样,充电状态的改变,将引出对终端的低电模式是否发生改变的考虑。
从这个角度来看,updateIsPoweredLocked函数的命名是实至名归的。

2、updateStayOnLocked
现在我们看看基本状态更新第二部分的updateStayOnLocked函数:

/**
* Updates the value of mStayOn.
* Sets DIRTY_STAY_ON if a change occurred.
*/
private void updateStayOnLocked(int dirty) {
    //电源状态或电源设置发生了改变
    if ((dirty & (DIRTY_BATTERY_STATE | DIRTY_SETTINGS)) != 0) {
        final boolean wasStayOn = mStayOn;
        //设置了充电器插入时亮屏(分为AC充电亮屏、USB充电亮屏或无线充电亮屏)
        if (mStayOnWhilePluggedInSetting != 0
                //判断mMaximumScreenOffTimeoutFromDeviceAdmin的是否处于0与Integer.MAX_VALUE之间
                //Android给出的注释是:
                //The maximum allowable screen off timeout according to the device
                // administration policy
                //初始为Integer.MAX_VALUE,因此这里是要求其它进程没有设置这个值
                //应该对应于强制息屏时间
                && !isMaximumScreenOffTimeoutFromDeviceAdminEnforcedLocked()) {
            //判断是否充电亮屏,定义于BatteryService.java中
            //从代码来看,只要mStayOnWhilePluggedInSetting设置了,就会亮屏
            mStayOn = mBatteryManagerInternal.isPowered(mStayOnWhilePluggedInSetting);
        } else {
            mStayOn = false;
        }

        if (mStayOn != wasStayOn) {
            mDirty |= DIRTY_STAY_ON;
        }
    }
}

这一部分的代码功能比较单一,主要用于更新变量mStayOn的值。
如果mStayOn如果为true,则屏幕保持长亮的状态。

3、updateScreenBrightnessBoostLocked
Android手机定义了一个最大屏幕亮度,用户可以手动或者让终端自动确定最大的屏幕亮度。
updateScreenBrightnessBoostLocked函数主要用于:更新终端可处于最大屏幕亮度的时间。

为了比较

  • 5
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值