Android 8.1 Doze模式分析(四)——Doze模式的退出

概述

Doze的退出,说的更严格一点,就是当Doze模式的状态由其他状态变为ACTIVE状态。简而言之,退出Doze模式有三种情况:屏幕亮屏、插入充电器、设备有移动。下面就这三种情况进行下分析。

在前面的分析中我们有见到过becomeActiveLocked()方法,这个方法当时没有进行分析,这个方法就是用来退出Doze的,严格来说,是将Doze状态置为了ACTIVE状态,从而退出IDLE状态或MAINTENANCE状态。因此,不管是何种方式退出Doze,都会调用这个方法。该方法如下:

void becomeActiveLocked(String activeReason, int activeUid) {
    if (mState != STATE_ACTIVE || mLightState != STATE_ACTIVE) {
        //设置一个Handler,在Handler中通知PMS、发送idle changed 广播
        scheduleReportActiveLocked(activeReason, activeUid);
        //将DeepDoze状态值置为STATE_ACTIVE
        mState = STATE_ACTIVE;
        //将LightDoze状态值置为LIGHT_STATE_ACTIVE
        mLightState = LIGHT_STATE_ACTIVE;
        //多久后进入INACTIVE状态
        mInactiveTimeout = mConstants.INACTIVE_TIMEOUT;
        mCurIdleBudget = 0;
        mMaintenanceStartTime = 0;
        //重置DeepDoze相关属性值、alarm、listener等
        resetIdleManagementLocked();
        //重置LightDoze相关属性值、alarm、listener等
        resetLightIdleManagementLocked();
    }
}

1.屏幕亮灭屏

当亮屏或灭屏时,PMS发送亮灭屏广播,DIC中监听了亮灭屏的广播,负责接受该广播并进行屏幕状态改变后的操作:
注册广播:

filter = new IntentFilter();
filter.addAction(Intent.ACTION_SCREEN_OFF);
filter.addAction(Intent.ACTION_SCREEN_ON);
getContext().registerReceiver(mInteractivityReceiver, filter);

接收到广播后进行处理:

private final BroadcastReceiver mInteractivityReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        synchronized (DeviceIdleController.this) {
            updateInteractivityLocked();
        }
    }
};

updateInteractivityLocked()方法中更新LightDoze和DeepDoze的状态,这个方法在第一篇文章中分析过了。

2.充电状态改变

当电池状态时,在BatteryService中会发送广播,DIC也对该广播进行了监听:

IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_BATTERY_CHANGED);
getContext().registerReceiver(mReceiver, filter);

接收到广播后进行处理:

private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
    @Override public void onReceive(Context context, Intent intent) {
        switch (intent.getAction()) {
            ............
            case Intent.ACTION_BATTERY_CHANGED: {
                synchronized (DeviceIdleController.this) {
                    int plugged = intent.getIntExtra("plugged", 0);
                    updateChargingLocked(plugged != 0);
                }
            } break;
            ....................
        }
    }
};

当接收到该广播后,调用updateChargingLocked(plugged != 0)来更新状态,参数表示是否插有充电线,该方法如下:

void updateChargingLocked(boolean charging) {
    //由充电转变为放电
    if (!charging && mCharging) {
        mCharging = false;
        if (!mForceIdle) {
            //进入INACTIVE状态,开始Doze模式
            becomeInactiveIfAppropriateLocked();
        }
    } else if (charging) {//由放电转变为充电
        mCharging = charging;
        if (!mForceIdle) {
            //Doze状态退出ACTIVE状态,退出Doze模式
            becomeActiveLocked("charging", Process.myUid());
        }
    }
}

最终,也会调用becomeActiveLocked()退出Doze模式。

3.其他服务通过Binder调用

DeviceIdleController内部Binder也提供了用于退出Doze的接口:

@Override public void exitIdle(String reason) {
    getContext().enforceCallingOrSelfPermission(Manifest.permission.DEVICE_POWER,
            null);
    long ident = Binder.clearCallingIdentity();
    try {
        exitIdleInternal(reason);
    } finally {
        Binder.restoreCallingIdentity(ident);
    }
}

其内部也是通过调用becomeActiveLocked()方法退出Doze的:


public void exitIdleInternal(String reason) {
    synchronized (this) {
        becomeActiveLocked(reason, Binder.getCallingUid());
    }
}

4.MotionSensor检测状态发生

这种情况和以上几种情况略不同,这种情况下Doze的退出是瞬时的,会将两个状态值都转换为STATE_ACTIVE后,又会立即调用becomeInactiveIfAppropriateLocked()方法进入INACTIVE状态,可以说是个“瞬时”退出。当MotionSensor检测到有移动时,则会退出Doze,处理逻辑在handleMotionDetectedLocked()中:

void handleMotionDetectedLocked(long timeout, String type) {
    boolean becomeInactive = false;
    if (mState != STATE_ACTIVE) {
        //通过Handler通知PMS、NetworkPolicy、发送IDLE_CHANGED广播等
        scheduleReportActiveLocked(type, Process.myUid());
        mState = STATE_ACTIVE;//将DeepDoze状态变为ACTIVE状态
        mInactiveTimeout = timeout;
        mCurIdleBudget = 0;
        mMaintenanceStartTime = 0;
        becomeInactive = true;
    }
    if (mLightState == LIGHT_STATE_OVERRIDE) {
        mLightState = STATE_ACTIVE;//将LightDoze状态变为ACTIVE状态
        becomeInactive = true;
    }
    if (becomeInactive) {
        //进入INACTIVE状态
        becomeInactiveIfAppropriateLocked();
    }
}

你可能感兴趣的:(Android系统开发)