Android 8.1 Dozeモード分析(3)LightDozeモードプロセス分析

最初のAndroid8.1 Dozeモード分析(1)では、デバイスが充電されておらず、画面がオフの場合、Light Dozeモードに入ることがわかっています。LightDozeモードでは、定期的なメンテナンスが実行されます。このメンテナンスはメンテナンス状態(メンテナンス)では、ネットワークアクセス、同期、JobSchedulerの操作が実行され、アイドル状態になり、何度も継続します。その後、静止しているとディープドーズモードになりますので、モーションセンサーがないとデバイスが静止しているかどうかが検出できず、ディープドーズモードになりません。

ライトドーズモードの関連値:

//表示轻度doze模式
private int mLightState;
//mLightState状态值,表示设备处于活动状态
private static final int LIGHT_STATE_ACTIVE = 0;
//mLightState状态值,表示设备处于不活动状态
private static final int LIGHT_STATE_INACTIVE = 1;
//mLightState状态值,表示设备进入空闲状态前,需要等待完成必要操作
private static final int LIGHT_STATE_PRE_IDLE = 3;
//mLightState状态值,表示设备处于空闲状态,该状态内将进行优化
private static final int LIGHT_STATE_IDLE = 4;
//mLightState状态值,表示设备处于空闲状态,要进入维护状态,先等待网络连接
private static final int LIGHT_STATE_WAITING_FOR_NETWORK = 5;
//mLightState状态值,表示设备处于维护状态
private static final int LIGHT_STATE_IDLE_MAINTENANCE = 6;
//mLightState状态值,表示设备处轻度Doze被覆盖,开始进入深度Doze模式
private static final int LIGHT_STATE_OVERRIDE = 7;

パターンプロセスの説明を始めましょう

アンドロイド8.1 Dozeモード解析(1)画面がオフになっているか、または端の充電時の話、それは)(becomeInactiveIfAppropriateLockedを呼び出します

DeviceIdleController.java-> becomeInactiveIfAppropriateLocked()

    void becomeInactiveIfAppropriateLocked() {
        if (DEBUG) Slog.d(TAG, "becomeInactiveIfAppropriateLocked()");
        //仅当屏幕灭屏且没充电且mVoWifiCalling为faslse时,才能进入Doze模式,mForceIdle是shell设置相关
        if ((!mScreenOn && !mCharging && !mVoWifiCalling) || mForceIdle) {
            // Screen has turned off; we are now going to become inactive and start
            // waiting to see if we will ultimately go idle.
            if (mState == STATE_ACTIVE && mDeepEnabled) {
                mState = STATE_INACTIVE;
                if (DEBUG) Slog.d(TAG, "Moved from STATE_ACTIVE to STATE_INACTIVE");
                 //重置
                resetIdleManagementLocked();
                 //设置DeepAlarm,时间为30mins
                scheduleAlarmLocked(mInactiveTimeout, false);
                EventLogTags.writeDeviceIdle(mState, "no activity");
            }
            if (mLightState == LIGHT_STATE_ACTIVE && mLightEnabled) {
                mLightState = LIGHT_STATE_INACTIVE;
                if (DEBUG) Slog.d(TAG, "Moved from LIGHT_STATE_ACTIVE to LIGHT_STATE_INACTIVE");
                 //重置
                resetLightIdleManagementLocked();
                 //设置LightDoze,时间为5mins
                scheduleLightAlarmLocked(mConstants.LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT);
                EventLogTags.writeDeviceIdleLight(mLightState, "no activity");
            }
        }
    }

LightDozeがLIGHT_STATE_ACTIVE状態にあり、mLightEnabledがtrueの場合、mLightStateをLIGHT_STATE_INACTIVE状態に変更します。これは、画面がインタラクティブではない(画面がオフ)ことを意味し、resetLightIdleManagementLocked()を呼び出してリセットし、最後にscheduleLightAlarmLocked()を呼び出して5-を送信します。分アラーム、

以下では、scheduleLightAlarmLocked()に焦点を当てます。

    void scheduleLightAlarmLocked(long delay) {
        if (DEBUG) Slog.d(TAG, "scheduleLightAlarmLocked(" + delay + ")");
        mNextLightAlarmTime = SystemClock.elapsedRealtime() + delay;
        mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
                mNextLightAlarmTime, "DeviceIdleController.light", mLightAlarmListener, mHandler);
    }

5分後にmLightAlarmListenerのコールバックメソッドonAlarm()に到達します

    private final AlarmManager.OnAlarmListener mLightAlarmListener
            = new AlarmManager.OnAlarmListener() {
        @Override
        public void onAlarm() {
            synchronized (DeviceIdleController.this) {
                stepLightIdleStateLocked("s:alarm");
            }
        }
    };

stepLightIdleStateLocked()を呼び出し、stepLightIdleStateLocked()メソッドはLightDozeモードの変更を担当します

void stepLightIdleStateLocked(String reason) {
        //LIGHT_STATE_OVERRIDE表示已经进入深度睡眠了,直接退出
        if (mLightState == LIGHT_STATE_OVERRIDE) {
            // If we are already in deep device idle mode, then
            // there is nothing left to do for light mode.
            return;
        }

        if (DEBUG) Slog.d(TAG, "stepLightIdleStateLocked: mLightState=" + mLightState);
        EventLogTags.writeDeviceIdleLightStep();

        switch (mLightState) {
            case LIGHT_STATE_INACTIVE:
                mCurIdleBudget = mConstants.LIGHT_IDLE_MAINTENANCE_MIN_BUDGET;
                // Reset the upcoming idle delays.
                //mNextLightIdleDelay 表示LightDoze 进入空闲(Idle)状态的时间,5分钟
                mNextLightIdleDelay = mConstants.LIGHT_IDLE_TIMEOUT;
                //LightDoze进入维护状态(maintenance)的开始时间
                mMaintenanceStartTime = 0;
                //表示还有活动进行,给它们5分钟时间处理,如果没有活动进行的话,就直接进入到idle
                if (!isOpsInactiveLocked()) {
                    // We have some active ops going on...  give them a chance to finish
                    // before going in to our first idle.
                    mLightState = LIGHT_STATE_PRE_IDLE;
                    EventLogTags.writeDeviceIdleLight(mLightState, reason);
                    scheduleLightAlarmLocked(mConstants.LIGHT_PRE_IDLE_TIMEOUT);
                    break;
                }
                // Nothing active, fall through to immediately idle.
            case LIGHT_STATE_PRE_IDLE:
            case LIGHT_STATE_IDLE_MAINTENANCE:
                if (mMaintenanceStartTime != 0) {
                    long duration = SystemClock.elapsedRealtime() - mMaintenanceStartTime;
                    if (duration < mConstants.LIGHT_IDLE_MAINTENANCE_MIN_BUDGET) {
                        // We didn't use up all of our minimum budget; add this to the reserve.
                        mCurIdleBudget += (mConstants.LIGHT_IDLE_MAINTENANCE_MIN_BUDGET-duration);
                    } else {
                        // We used more than our minimum budget; this comes out of the reserve.
                        mCurIdleBudget -= (duration-mConstants.LIGHT_IDLE_MAINTENANCE_MIN_BUDGET);
                    }
                }
                mMaintenanceStartTime = 0;
                scheduleLightAlarmLocked(mNextLightIdleDelay);
                mNextLightIdleDelay = Math.min(mConstants.LIGHT_MAX_IDLE_TIMEOUT,
                        (long)(mNextLightIdleDelay * mConstants.LIGHT_IDLE_FACTOR));
                if (mNextLightIdleDelay < mConstants.LIGHT_IDLE_TIMEOUT) {
                    mNextLightIdleDelay = mConstants.LIGHT_IDLE_TIMEOUT;
                }
                if (DEBUG) Slog.d(TAG, "Moved to LIGHT_STATE_IDLE.");
                //LightDoze状态设置为LIGHT_STATE_IDLE
                mLightState = LIGHT_STATE_IDLE;
                EventLogTags.writeDeviceIdleLight(mLightState, reason);
                addEvent(EVENT_LIGHT_IDLE);
                //申请一个wakelock锁,保持CPU唤醒
                mGoingIdleWakeLock.acquire();
                //处理LightDoze进入Idle状态前的操作
                mHandler.sendEmptyMessage(MSG_REPORT_IDLE_ON_LIGHT);
                break;
            case LIGHT_STATE_IDLE:
            case LIGHT_STATE_WAITING_FOR_NETWORK:
                if (mNetworkConnected || mLightState == LIGHT_STATE_WAITING_FOR_NETWORK) {
                    // We have been idling long enough, now it is time to do some work.
                    mActiveIdleOpCount = 1;
                    mActiveIdleWakeLock.acquire();
                    mMaintenanceStartTime = SystemClock.elapsedRealtime();
                    if (mCurIdleBudget < mConstants.LIGHT_IDLE_MAINTENANCE_MIN_BUDGET) {
                        mCurIdleBudget = mConstants.LIGHT_IDLE_MAINTENANCE_MIN_BUDGET;
                    } else if (mCurIdleBudget > mConstants.LIGHT_IDLE_MAINTENANCE_MAX_BUDGET) {
                        mCurIdleBudget = mConstants.LIGHT_IDLE_MAINTENANCE_MAX_BUDGET;
                    }
                    scheduleLightAlarmLocked(mCurIdleBudget);
                    if (DEBUG) Slog.d(TAG,
                            "Moved from LIGHT_STATE_IDLE to LIGHT_STATE_IDLE_MAINTENANCE.");
                    mLightState = LIGHT_STATE_IDLE_MAINTENANCE;
                    EventLogTags.writeDeviceIdleLight(mLightState, reason);
                    addEvent(EVENT_LIGHT_MAINTENANCE);
                    mHandler.sendEmptyMessage(MSG_REPORT_IDLE_OFF);
                } else {
                    // We'd like to do maintenance, but currently don't have network
                    // connectivity...  let's try to wait until the network comes back.
                    // We'll only wait for another full idle period, however, and then give up.
                    scheduleLightAlarmLocked(mNextLightIdleDelay);
                    if (DEBUG) Slog.d(TAG, "Moved to LIGHT_WAITING_FOR_NETWORK.");
                    mLightState = LIGHT_STATE_WAITING_FOR_NETWORK;
                    EventLogTags.writeDeviceIdleLight(mLightState, reason);
                }
                break;
        }
    }

ここから、ハンドラーがLIGHT_STATE_PRE_IDLE / LIGHT_STATE_IDLE_MAINTENANCEからLIGHT_STATE_IDLE / LIGHT_STATE_WAITING_FOR_NETWORKに、またはLIGHT_STATE_IDLE / LIGHT_STATE_WAITING_FOR_NETWORKからLIGHT_STATE_PRE_IDLE / LIGHT_STATE_IDLE_MAINに送信されることがわかります。

final class MyHandler extends Handler {
        MyHandler(Looper looper) {
            super(looper);
        }

        @Override public void handleMessage(Message msg) {
            if (DEBUG) Slog.d(TAG, "handleMessage(" + msg.what + ")");
            switch (msg.what) {
                case MSG_WRITE_CONFIG: {
                    // Does not hold a wakelock. Just let this happen whenever.
                    handleWriteConfigFile();
                } break;
                case MSG_REPORT_IDLE_ON:
                case MSG_REPORT_IDLE_ON_LIGHT: {
                    // mGoingIdleWakeLock is held at this point
                    EventLogTags.writeDeviceIdleOnStart();
                    final boolean deepChanged;
                    final boolean lightChanged;
                    if (msg.what == MSG_REPORT_IDLE_ON) {
                        deepChanged = mLocalPowerManager.setDeviceIdleMode(true);
                        lightChanged = mLocalPowerManager.setLightDeviceIdleMode(false);
                    } else {
                        deepChanged = mLocalPowerManager.setDeviceIdleMode(false);
                        lightChanged = mLocalPowerManager.setLightDeviceIdleMode(true);
                    }
                    try {
                        mNetworkPolicyManager.setDeviceIdleMode(true);
                        mBatteryStats.noteDeviceIdleMode(msg.what == MSG_REPORT_IDLE_ON
                                ? BatteryStats.DEVICE_IDLE_MODE_DEEP
                                : BatteryStats.DEVICE_IDLE_MODE_LIGHT, null, Process.myUid());
                    } catch (RemoteException e) {
                    }
                    if (deepChanged) {
                        getContext().sendBroadcastAsUser(mIdleIntent, UserHandle.ALL);
                    }
                    if (lightChanged) {
                        getContext().sendBroadcastAsUser(mLightIdleIntent, UserHandle.ALL);
                    }
                    EventLogTags.writeDeviceIdleOnComplete();
                    mGoingIdleWakeLock.release();
                } break;
                case MSG_REPORT_IDLE_OFF: {
                    // mActiveIdleWakeLock is held at this point
                    EventLogTags.writeDeviceIdleOffStart("unknown");
                    final boolean deepChanged = mLocalPowerManager.setDeviceIdleMode(false);
                    final boolean lightChanged = mLocalPowerManager.setLightDeviceIdleMode(false);
                    try {
                        mNetworkPolicyManager.setDeviceIdleMode(false);
                        mBatteryStats.noteDeviceIdleMode(BatteryStats.DEVICE_IDLE_MODE_OFF,
                                null, Process.myUid());
                    } catch (RemoteException e) {
                    }
                    if (deepChanged) {
                        incActiveIdleOps();
                        getContext().sendOrderedBroadcastAsUser(mIdleIntent, UserHandle.ALL,
                                null, mIdleStartedDoneReceiver, null, 0, null, null);
                    }
                    if (lightChanged) {
                        incActiveIdleOps();
                        getContext().sendOrderedBroadcastAsUser(mLightIdleIntent, UserHandle.ALL,
                                null, mIdleStartedDoneReceiver, null, 0, null, null);
                    }
                    // Always start with one active op for the message being sent here.
                    // Now we are done!
                    decActiveIdleOps();
                    EventLogTags.writeDeviceIdleOffComplete();
                } break;
                case MSG_REPORT_ACTIVE: {
                    // The device is awake at this point, so no wakelock necessary.
                    String activeReason = (String)msg.obj;
                    int activeUid = msg.arg1;
                    EventLogTags.writeDeviceIdleOffStart(
                            activeReason != null ? activeReason : "unknown");
                    final boolean deepChanged = mLocalPowerManager.setDeviceIdleMode(false);
                    final boolean lightChanged = mLocalPowerManager.setLightDeviceIdleMode(false);
                    try {
                        mNetworkPolicyManager.setDeviceIdleMode(false);
                        mBatteryStats.noteDeviceIdleMode(BatteryStats.DEVICE_IDLE_MODE_OFF,
                                activeReason, activeUid);
                    } catch (RemoteException e) {
                    }
                    if (deepChanged) {
                        getContext().sendBroadcastAsUser(mIdleIntent, UserHandle.ALL);
                    }
                    if (lightChanged) {
                        getContext().sendBroadcastAsUser(mLightIdleIntent, UserHandle.ALL);
                    }
                    EventLogTags.writeDeviceIdleOffComplete();
                } break;
                case MSG_TEMP_APP_WHITELIST_TIMEOUT: {
                    // TODO: What is keeping the device awake at this point? Does it need to be?
                    int uid = msg.arg1;
                    checkTempAppWhitelistTimeout(uid);
                } break;
                case MSG_REPORT_MAINTENANCE_ACTIVITY: {
                    // TODO: What is keeping the device awake at this point? Does it need to be?
                    boolean active = (msg.arg1 == 1);
                    final int size = mMaintenanceActivityListeners.beginBroadcast();
                    try {
                        for (int i = 0; i < size; i++) {
                            try {
                                mMaintenanceActivityListeners.getBroadcastItem(i)
                                        .onMaintenanceActivityChanged(active);
                            } catch (RemoteException ignored) {
                            }
                        }
                    } finally {
                        mMaintenanceActivityListeners.finishBroadcast();
                    }
                } break;
                case MSG_FINISH_IDLE_OP: {
                    // mActiveIdleWakeLock is held at this point
                    decActiveIdleOps();
                } break;
            }
        }
    }

このコードから、LightDozeがIDLE状態に入るとき、またはIDLE状態を終了するときに、最初にPMS、NetworkPolicyManagerにDeviceIdleModeをtrueまたはfalseに設定するように通知してから、mLightIdleIntentのインテントでブロードキャストを送信することがわかります。

LightDozeがIDLE / MAINTENANCE状態に入ると、ハンドラーで次のようになります。

  • 1.NetworkPolicyManagerServiceにネットワークを制限/開くように通知します。
  • 2.ブロードキャストを送信し、DeviceIdleJobsControllerで受け入れ、JobServiceを制限/実行します。

ネットワークを制限する方法は?

DeviceIdleControllerは、NetworkPolicyManagerServiceによって提供されるインターフェイスのみを呼び出します。NetworkPolicyManagerService内の実装を制限する方法:

mNetworkPolicyManager.setDeviceIdleMode(true)

フォローアッププロセスについては、Android 8.1 Dozeモード分析(2)ネットワークの制限を参照してください。

仕事を遅らせる方法は?

private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        final String action = intent.getAction();
        //当DeepDoze或LightDoze的IDLE状态改变时,都会执行updateIdleMode()
        if (PowerManager.ACTION_LIGHT_DEVICE_IDLE_MODE
                _CHANGED.equals(action)|| PowerManager.ACTION_DEVICE
                _IDLE_MODE_CHANGED.equals(action)) {
            updateIdleMode(mPowerManager != null
                    ? (mPowerManager.isDeviceIdleMode()
                            || mPowerManager.isLightDeviceIdleMode())
                    : false);
        } else if (PowerManager.ACTION_POWER_SAVE_WHITELIST_
            CHANGED.equals(action)) {
            updateWhitelist();
        }
    }
};

DeviceIdleJobsController.java-> updateIdleMode()

void updateIdleMode(boolean enabled) {
    boolean changed = false;
    // Need the whitelist to be ready when going into idle
    if (mDeviceIdleWhitelistAppIds == null) {
        updateWhitelist();//更新白名单列表
    }
    synchronized (mLock) {
        if (mDeviceIdleMode != enabled) {
            changed = true;
        }
        mDeviceIdleMode = enabled;
        //遍历所有的Job
        mJobSchedulerService.getJobStore().forEachJob(mUpdateFunctor);
    }
    if (changed) {
        //回调到JobSchedulerService中,停止或开始Job
        mStateChangedListener.onDeviceIdleStateChanged(enabled);
    }
}

 

おすすめ

転載: blog.csdn.net/liu362732346/article/details/86580670
おすすめ