Android 8.1 Dozeモード分析(四)——Dozeモードの脱退


概要
Dozeの脱退は、より厳密に言えば、Dozeモードの状態が他の状態からACTIVE状態に変化する場合である.簡単に言えば、Dozeモードを終了するには、画面が明るくなったり、充電器が挿入されたり、デバイスが移動したりする3つのケースがあります.以下、この3つのケースについて分析する.
前述の解析では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();
    }
}