Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c8360736 authored by Jack Yu's avatar Jack Yu Committed by Android (Google) Code Review
Browse files

Merge changes from topic "refactor_data_stall"

* changes:
  Implement the Functions for DataConfigManager
  Add the Skip Recovery Action Mechanism
parents 2dcc2090 b0e73da3
Loading
Loading
Loading
Loading
+20 −0
Original line number Diff line number Diff line
@@ -793,6 +793,26 @@ public class DataConfigManager extends Handler {
        }
    }

    /**
     * @return Get recovery action delay in milliseconds between recovery actions.
     *
     * @see CarrierConfigManager#KEY_DATA_STALL_RECOVERY_TIMERS_LONG_ARRAY
     */
    public @NonNull long[] getDataStallRecoveryDelayMillis() {
        return mCarrierConfig.getLongArray(
            CarrierConfigManager.KEY_DATA_STALL_RECOVERY_TIMERS_LONG_ARRAY);
    }

    /**
     * @return Get the data stall recovery should skip boolean array.
     *
     * @see CarrierConfigManager#KEY_DATA_STALL_RECOVERY_SHOULD_SKIP_BOOL_ARRAY
     */
    public @NonNull boolean[] getDataStallRecoveryShouldSkipArray() {
        return mCarrierConfig.getBooleanArray(
            CarrierConfigManager.KEY_DATA_STALL_RECOVERY_SHOULD_SKIP_BOOL_ARRAY);
    }

    /**
     * Registration point for subscription info ready
     *
+149 −44
Original line number Diff line number Diff line
@@ -38,6 +38,7 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.telephony.Phone;
import com.android.internal.telephony.PhoneConstants;
import com.android.internal.telephony.data.DataNetworkController.DataNetworkControllerCallback;
import com.android.internal.telephony.data.DataSettingsManager.DataSettingsManagerCallback;
import com.android.internal.telephony.metrics.DataStallRecoveryStats;
import com.android.internal.telephony.metrics.TelephonyMetrics;
import com.android.telephony.Rlog;
@@ -46,6 +47,7 @@ import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Arrays;
import java.util.concurrent.Executor;

/**
@@ -91,15 +93,11 @@ public class DataStallRecoveryManager extends Handler {
    /** Event for data config updated. */
    private static final int EVENT_DATA_CONFIG_UPDATED = 1;


    /** Event for triggering recovery action. */
    private static final int EVENT_DO_RECOVERY = 2;

    /** Event for mobile data setting changed. */
    private static final int EVENT_MOBILE_DATA_SETTINGS_CHANGED = 3;

    /** Event for radio state changed. */
    private static final int EVENT_RADIO_STATE_CHANGED = 4;
    private static final int EVENT_RADIO_STATE_CHANGED = 3;

    private final @NonNull Phone mPhone;
    private final @NonNull String mLogTag;
@@ -132,8 +130,17 @@ public class DataStallRecoveryManager extends Handler {
    private @RadioPowerState int mRadioPowerState;
    /** Whether the NetworkCheckTimer start. */
    private boolean mNetworkCheckTimerStarted = false;
    /** Whether radio state changed during data stall. */
    private boolean mRadioStateChangedDuringDataStall;
    /** Whether mobile data change to Enabled during data stall. */
    private boolean mMobileDataChangedToEnabledDuringDataStall;

    /** The array for the timers between recovery actions. */
    private @NonNull long[] mDataStallRecoveryDelayMillisArray;
    /** The boolean array for the flags. They are used to skip the recovery actions if needed. */
    private @NonNull boolean[] mSkipRecoveryActionArray;

    private @NonNull DataStallRecoveryManagerCallback mDataStallRecoveryManagerCallback;
    private DataStallRecoveryManagerCallback mDataStallRecoveryManagerCallback;

    /**
     * The data stall recovery manager callback. Note this is only used for passing information
@@ -175,11 +182,24 @@ public class DataStallRecoveryManager extends Handler {
        super(looper);
        mPhone = phone;
        mLogTag = "DSRM-" + mPhone.getPhoneId();
        log("DataStallRecoveryManager created.");
        mDataNetworkController = dataNetworkController;
        mWwanDataServiceManager = dataServiceManager;
        mDataConfigManager = mDataNetworkController.getDataConfigManager();
        mDataNetworkController
                .getDataSettingsManager()
                .registerCallback(
                        new DataSettingsManagerCallback(this::post) {
                            @Override
                            public void onDataEnabledChanged(
                                    boolean enabled,
                                    @TelephonyManager.DataEnabledChangedReason int reason) {
                                onMobileDataEnabledChanged(enabled);
                            }
                        });
        mDataStallRecoveryManagerCallback = callback;
        mRadioPowerState = mPhone.getRadioPowerState();
        updateDataStallRecoveryConfigs();

        registerAllEvents();
    }
@@ -197,12 +217,12 @@ public class DataStallRecoveryManager extends Handler {

                    @Override
                    public void onInternetDataNetworkConnected() {
                        // onInternetDataNetworkConnected();
                        // onInternetNetworkConnected();
                    }

                    @Override
                    public void onInternetDataNetworkDisconnected() {
                        // onInternetDataNetworkDisconnected();
                        // onInternetNetworkDisconnected();
                    }
                });
        mPhone.mCi.registerForRadioStateChanged(this, EVENT_RADIO_STATE_CHANGED, null);
@@ -218,11 +238,12 @@ public class DataStallRecoveryManager extends Handler {
            case EVENT_DO_RECOVERY:
                doRecovery();
                break;
            case EVENT_MOBILE_DATA_SETTINGS_CHANGED:
                onMobileDataSettingsChanged();
                break;
            case EVENT_RADIO_STATE_CHANGED:
                mRadioPowerState = mPhone.getRadioPowerState();
                if (mDataStalled) {
                    // Store the radio state changed flag only when data stall occurred.
                    mRadioStateChangedDuringDataStall = true;
                }
                break;
            default:
                loge("Unexpected message = " + msg);
@@ -230,9 +251,49 @@ public class DataStallRecoveryManager extends Handler {
        }
    }

    /** Update the data stall recovery configs from DataConfigManager. */
    private void updateDataStallRecoveryConfigs() {
        mDataStallRecoveryDelayMillisArray = mDataConfigManager.getDataStallRecoveryDelayMillis();
        mSkipRecoveryActionArray = mDataConfigManager.getDataStallRecoveryShouldSkipArray();
    }

    /**
     * Get the duration for specific data stall recovery action.
     *
     * @param recoveryAction The recovery action to query.
     * @return the delay in milliseconds for the specific recovery action.
     */
    private long getDataStallRecoveryDelayMillis(@RecoveryAction int recoveryAction) {
        return mDataStallRecoveryDelayMillisArray[recoveryAction];
    }

    /**
     * Check if the recovery action needs to be skipped.
     *
     * @param recoveryAction The recovery action.
     * @return {@code true} if the action needs to be skipped.
     */
    private boolean shouldSkipRecoveryAction(@RecoveryAction int recoveryAction) {
        return mSkipRecoveryActionArray[recoveryAction];
    }

    /** Called when data config was updated. */
    private void onDataConfigUpdated() {
        // TODO: (b/178670629): Get the new config from DataConfigManager.
        updateDataStallRecoveryConfigs();
    }

    /**
     * Called when mobile data setting changed.
     *
     * @param enabled true for mobile data settings enabled & false for disabled.
     */
    private void onMobileDataEnabledChanged(boolean enabled) {
        logl("onMobileDataEnabledChanged: DataEnabled:" + enabled + ",DataStalled:" + mDataStalled);
        // Store the mobile data changed flag (from disabled to enabled) as TRUE
        // during data stalled.
        if (mDataStalled && enabled) {
            mMobileDataChangedToEnabledDuringDataStall = true;
        }
    }

    /**
@@ -260,15 +321,11 @@ public class DataStallRecoveryManager extends Handler {
        }
    }

    /** Called when mobile data setiings changed. */
    private void onMobileDataSettingsChanged() {
        logv("onMobileDataSettingsChanged");
        // TODO: (b/178670629): Get mobile data settings from DataSettingsManager.
    }

    /** Reset the action to initial step. */
    private void resetAction() {
        mTimeLastRecoveryStartMs = 0;
        mMobileDataChangedToEnabledDuringDataStall = false;
        mRadioStateChangedDuringDataStall = false;
        setRecoveryAction(RECOVERY_ACTION_GET_DATA_CALL_LIST);
    }

@@ -292,6 +349,38 @@ public class DataStallRecoveryManager extends Handler {
    @VisibleForTesting
    public void setRecoveryAction(@RecoveryAction int action) {
        mRecovryAction = action;

        // Check if the mobile data enabled is TRUE, it means that the mobile data setting changed
        // from DISABLED to ENABLED, we will set the next recovery action to
        // RECOVERY_ACTION_RADIO_RESTART due to already did the RECOVERY_ACTION_CLEANUP.
        if (mMobileDataChangedToEnabledDuringDataStall
                && mRecovryAction < RECOVERY_ACTION_RADIO_RESTART) {
            mRecovryAction = RECOVERY_ACTION_RADIO_RESTART;
        }
        // Check if the radio state changed from off to on, it means that the modem already
        // did the radio restart, we will set the next action to RECOVERY_ACTION_RESET_MODEM.
        if (mRadioStateChangedDuringDataStall
                && mRadioPowerState == TelephonyManager.RADIO_POWER_ON) {
            mRecovryAction = RECOVERY_ACTION_RESET_MODEM;
        }
        // To check the flag from DataConfigManager if we need to skip the step.
        if (shouldSkipRecoveryAction(mRecovryAction)) {
            switch (mRecovryAction) {
                case RECOVERY_ACTION_GET_DATA_CALL_LIST:
                    setRecoveryAction(RECOVERY_ACTION_CLEANUP);
                    break;
                case RECOVERY_ACTION_CLEANUP:
                    setRecoveryAction(RECOVERY_ACTION_RADIO_RESTART);
                    break;
                case RECOVERY_ACTION_RADIO_RESTART:
                    setRecoveryAction(RECOVERY_ACTION_RESET_MODEM);
                    break;
                case RECOVERY_ACTION_RESET_MODEM:
                    resetAction();
                    break;
            }
        }

        log("setRecoveryAction: " + recoveryActionToString(mRecovryAction));
    }

@@ -313,16 +402,6 @@ public class DataStallRecoveryManager extends Handler {
        return (SystemClock.elapsedRealtime() - mTimeLastRecoveryStartMs);
    }

    /**
     * Get duration between recovery from DataStallRecoveryConfig.
     *
     * @return the time in milliseconds between recovery action.
     */
    private long getMinDurationBetweenRecovery() {
        // TODO: (b/178670629): Get the duration from DataConfigManager
        return 3 * 60 * 1000;
    }

    /**
     * Broadcast intent when data stall occurred.
     *
@@ -361,12 +440,19 @@ public class DataStallRecoveryManager extends Handler {
        mPhone.rebootModem(null);
    }

    /** Initialize the network check timer. */
    private void startNetworkCheckTimer() {
        log("startNetworkCheckTimer()");
    /**
     * Initialize the network check timer.
     *
     * @param action The recovery action to start the network check timer.
     */
    private void startNetworkCheckTimer(@RecoveryAction int action) {
        // Ignore send message delayed due to reached the last action.
        if (action == RECOVERY_ACTION_RESET_MODEM) return;
        log("startNetworkCheckTimer(): " + getDataStallRecoveryDelayMillis(action) + "ms");
        if (!mNetworkCheckTimerStarted) {
            mNetworkCheckTimerStarted = true;
            sendMessageDelayed(obtainMessage(EVENT_DO_RECOVERY), getMinDurationBetweenRecovery());
            sendMessageDelayed(
                    obtainMessage(EVENT_DO_RECOVERY), getDataStallRecoveryDelayMillis(action));
        }
    }

@@ -388,7 +474,7 @@ public class DataStallRecoveryManager extends Handler {
    private boolean isRecoveryNeeded() {
        logv("enter: isRecoveryNeeded()");
        // To avoid back to back recovery, wait for a grace period
        if (getElapsedTimeSinceRecoveryMs() < getMinDurationBetweenRecovery()) {
        if (getElapsedTimeSinceRecoveryMs() < getDataStallRecoveryDelayMillis(mLastAction)) {
            log("skip back to back data stall recovery");
            return false;
        }
@@ -407,8 +493,6 @@ public class DataStallRecoveryManager extends Handler {
            return false;
        }

        // TODO: (b/178670629): check the customized carrier config to skip the recovery action

        return true;
    }

@@ -488,7 +572,26 @@ public class DataStallRecoveryManager extends Handler {
                                + recoveryActionToString(recoveryAction));
        }

        startNetworkCheckTimer();
        startNetworkCheckTimer(mLastAction);
    }

    /**
     * Convert RadioPowerState to string
     *
     * @param state The radio power state
     * @return The radio power state in string format.
     */
    private static @NonNull String radioPowerStateToString(@RadioPowerState int state) {
        switch (state) {
            case TelephonyManager.RADIO_POWER_OFF:
                return "RADIO_POWER_OFF";
            case TelephonyManager.RADIO_POWER_ON:
                return "RADIO_POWER_ON";
            case TelephonyManager.RADIO_POWER_UNAVAILABLE:
                return "RADIO_POWER_UNAVAILABLE";
            default:
                return "Unknown(" + state + ")";
        }
    }

    /**
@@ -512,13 +615,6 @@ public class DataStallRecoveryManager extends Handler {
        }
    }

    /** The data stall recovery config. */
    public static final class DataStallRecoveryConfig {
        DataStallRecoveryConfig(String stringConfig) {
            // TODO: (b/178670629): Parsing the config string.
        }
    }

    /**
     * Log debug messages.
     *
@@ -572,10 +668,19 @@ public class DataStallRecoveryManager extends Handler {
        pw.println("mIsValidNetwork=" + mIsValidNetwork);
        pw.println("mDataStalled=" + mDataStalled);
        pw.println("mDataStallStartMs=" + mDataStallStartMs);
        pw.println("mRadioPowerState=" + mRadioPowerState);
        pw.println("mRadioPowerState=" + radioPowerStateToString(mRadioPowerState));
        pw.println("mLastActionReported=" + mLastActionReported);
        pw.println("mTimeLastRecoveryStartMs=" + mTimeLastRecoveryStartMs);
        pw.println("getRecoveryAction()=" + recoveryActionToString(getRecoveryAction()));
        pw.println("mRadioStateChangedDuringDataStall=" + mRadioStateChangedDuringDataStall);
        pw.println(
                "mMobileDataChangedToEnabledDuringDataStall="
                        + mMobileDataChangedToEnabledDuringDataStall);
        pw.println(
                "DataStallRecoveryDelayMillisArray="
                        + Arrays.toString(mDataStallRecoveryDelayMillisArray));
        pw.println("SkipRecoveryActionArray=" + Arrays.toString(mSkipRecoveryActionArray));
        pw.decreaseIndent();
        pw.println("");

        pw.println("Local logs:");
+1 −0
Original line number Diff line number Diff line
@@ -591,6 +591,7 @@ public abstract class TelephonyTest {
        doReturn(mAccessNetworksManager).when(mPhone).getAccessNetworksManager();
        doReturn(mDataEnabledSettings).when(mPhone).getDataEnabledSettings();
        doReturn(mDcTracker).when(mPhone).getDcTracker(anyInt());
        doReturn(mDataSettingsManager).when(mDataNetworkController).getDataSettingsManager();
        doReturn(mDataNetworkController).when(mPhone).getDataNetworkController();
        doReturn(mDataSettingsManager).when(mPhone).getDataSettingsManager();
        doReturn(mCarrierPrivilegesTracker).when(mPhone).getCarrierPrivilegesTracker();
+13 −1
Original line number Diff line number Diff line
@@ -16,17 +16,19 @@

package com.android.internal.telephony.data;

import static com.android.internal.telephony.data.DataNetworkController.DataNetworkControllerCallback;
import com.android.internal.telephony.data.DataNetworkController.DataNetworkControllerCallback;

import static com.google.common.truth.Truth.assertThat;

import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;

import android.net.NetworkAgent;
import android.telephony.CarrierConfigManager;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;

@@ -53,6 +55,15 @@ public class DataStallRecoveryManagerTest extends TelephonyTest {
        logd("DataStallRecoveryManagerTest +Setup!");
        super.setUp(getClass().getSimpleName());
        doReturn(true).when(mPhone).isUsingNewDataStack();
        mCarrierConfigManager = mPhone.getContext().getSystemService(CarrierConfigManager.class);
        long[] dataStallRecoveryTimersArray = new long[] {1, 1, 1};
        boolean[] dataStallRecoveryStepsArray = new boolean[] {false, false, false, false};
        doReturn(dataStallRecoveryTimersArray)
                .when(mDataConfigManager)
                .getDataStallRecoveryDelayMillis();
        doReturn(dataStallRecoveryStepsArray)
                .when(mDataConfigManager)
                .getDataStallRecoveryShouldSkipArray();
        doReturn(mSST).when(mPhone).getServiceStateTracker();
        doAnswer(
                invocation -> {
@@ -61,6 +72,7 @@ public class DataStallRecoveryManagerTest extends TelephonyTest {
                })
                .when(mDataStallRecoveryManagerCallback)
                .invokeFromExecutor(any(Runnable.class));
        doReturn("").when(mSubscriptionController).getDataEnabledOverrideRules(anyInt());

        mDataStallRecoveryManager =
                new DataStallRecoveryManager(