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

Commit 6bd6a5a1 authored by Diaesh Antony's avatar Diaesh Antony Committed by Mars Lin
Browse files

Get action and duration from global settings



Get action and duration from global settings

Bug: 283897403
Test: Manual test
Change-Id: Ia14a59bc623d9e8427ccbe87cfe57cfed477d91d
Signed-off-by: default avatarDiaesh Antony <diaeshantony@google.com>
parent 1f4143f4
Loading
Loading
Loading
Loading
+150 −4
Original line number Diff line number Diff line
@@ -23,7 +23,9 @@ import android.annotation.ElapsedRealtimeLong;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.content.Intent;
import android.database.ContentObserver;
import android.net.NetworkAgent;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
@@ -35,6 +37,7 @@ import android.telephony.Annotation.ValidationStatus;
import android.telephony.CellSignalStrength;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.IndentingPrintWriter;
import android.util.LocalLog;

@@ -128,6 +131,9 @@ public class DataStallRecoveryManager extends Handler {
    /** The data stall recovered by user (Mobile Data Power off/on). */
    private static final int RECOVERED_REASON_USER = 3;

    /** The number of milliseconds to wait for the DSRM prediction to complete. */
    private static final int DSRM_PREDICT_WAITING_MILLIS = 1000;

    /** Event for send data stall broadcast. */
    private static final int EVENT_SEND_DATA_STALL_BROADCAST = 1;

@@ -137,6 +143,12 @@ public class DataStallRecoveryManager extends Handler {
    /** Event for radio state changed. */
    private static final int EVENT_RADIO_STATE_CHANGED = 3;

    /** Event for recovery actions changed. */
    private static final int EVENT_CONTENT_DSRM_ENABLED_ACTIONS_CHANGED = 4;

    /** Event for duration milliseconds changed. */
    private static final int EVENT_CONTENT_DSRM_DURATION_MILLIS_CHANGED = 5;

    private final @NonNull Phone mPhone;
    private final @NonNull String mLogTag;
    private final @NonNull LocalLog mLocalLog = new LocalLog(128);
@@ -189,10 +201,30 @@ public class DataStallRecoveryManager extends Handler {
    /** The boolean array for the flags. They are used to skip the recovery actions if needed. */
    private @NonNull boolean[] mSkipRecoveryActionArray;

    /**
     * The content URI for the DSRM recovery actions.
     *
     * @see Settings.Global#DSRM_ENABLED_ACTIONS
     */
    private static final Uri CONTENT_URL_DSRM_ENABLED_ACTIONS = Settings.Global.getUriFor(
            Settings.Global.DSRM_ENABLED_ACTIONS);

    /**
     * The content URI for the DSRM duration milliseconds.
     *
     * @see Settings.Global#DSRM_DURATION_MILLIS
     */
    private static final Uri CONTENT_URL_DSRM_DURATION_MILLIS = Settings.Global.getUriFor(
            Settings.Global.DSRM_DURATION_MILLIS);


    private DataStallRecoveryManagerCallback mDataStallRecoveryManagerCallback;

    private final DataStallRecoveryStats mStats;

    /** The number of milliseconds to wait for the DSRM prediction to complete. */
    private @ElapsedRealtimeLong long mPredictWaitingMillis = 0L;

    /**
     * The data stall recovery manager callback. Note this is only used for passing information
     * internally in the data stack, should not be used externally.
@@ -288,6 +320,13 @@ public class DataStallRecoveryManager extends Handler {
                    }
                });
        mPhone.mCi.registerForRadioStateChanged(this, EVENT_RADIO_STATE_CHANGED, null);

        // Register for DSRM global setting changes.
        mPhone.getContext().getContentResolver().registerContentObserver(
                CONTENT_URL_DSRM_ENABLED_ACTIONS, false, mContentObserver);
        mPhone.getContext().getContentResolver().registerContentObserver(
                CONTENT_URL_DSRM_DURATION_MILLIS, false, mContentObserver);

    }

    @Override
@@ -304,8 +343,9 @@ public class DataStallRecoveryManager extends Handler {
                }
                // Broadcast intent that data stall has been detected.
                broadcastDataStallDetected(getRecoveryAction());
                // Send EVENT_DO_RECOVERY to start recovery process.
                sendMessage(obtainMessage(EVENT_DO_RECOVERY));
                // Schedule the message to to wait for the predicted value.
                sendMessageDelayed(
                        obtainMessage(EVENT_DO_RECOVERY), mPredictWaitingMillis);
                break;
            case EVENT_DO_RECOVERY:
                doRecovery();
@@ -323,16 +363,119 @@ public class DataStallRecoveryManager extends Handler {
                    }
                }
                break;
            case EVENT_CONTENT_DSRM_ENABLED_ACTIONS_CHANGED:
                updateGlobalConfigActions();
                break;
            case EVENT_CONTENT_DSRM_DURATION_MILLIS_CHANGED:
                updateGlobalConfigDurations();
                break;
            default:
                loge("Unexpected message = " + msg);
                break;
        }
    }

    private final ContentObserver mContentObserver = new ContentObserver(this) {
        @Override
        public void onChange(boolean selfChange, Uri uri) {
            super.onChange(selfChange, uri);
            if (CONTENT_URL_DSRM_ENABLED_ACTIONS.equals(uri)) {
                log("onChange URI: " + uri);
                sendMessage(obtainMessage(EVENT_CONTENT_DSRM_ENABLED_ACTIONS_CHANGED));
            } else if (CONTENT_URL_DSRM_DURATION_MILLIS.equals(uri)) {
                log("onChange URI: " + uri);
                sendMessage(obtainMessage(EVENT_CONTENT_DSRM_DURATION_MILLIS_CHANGED));
            }
        }
    };


    @VisibleForTesting
    public ContentObserver getContentObserver() {
        return mContentObserver;
    }

    /**
     * Updates the skip recovery action array based on DSRM global configuration actions.
     *
     * @see Settings.Global#DSRM_ENABLED_ACTIONS
     */
    private void updateGlobalConfigActions() {
        String enabledActions = Settings.Global.getString(
                mPhone.getContext().getContentResolver(),
                Settings.Global.DSRM_ENABLED_ACTIONS);

        if (!TextUtils.isEmpty(enabledActions)) {
            String[] splitEnabledActions = enabledActions.split(",");
            boolean[] enabledActionsArray = new boolean[splitEnabledActions.length];
            for (int i = 0; i < enabledActionsArray.length; i++) {
                enabledActionsArray[i] = Boolean.parseBoolean(splitEnabledActions[i].trim());
            }

            int minLength = Math.min(enabledActionsArray.length,
                    mSkipRecoveryActionArray.length);

            // Update the skip recovery action array.
            for (int i = 0; i < minLength; i++) {
                mSkipRecoveryActionArray[i] = !enabledActionsArray[i];
            }
            log("SkipRecoveryAction: "
                    + Arrays.toString(mSkipRecoveryActionArray));
            mPredictWaitingMillis = DSRM_PREDICT_WAITING_MILLIS;
        } else {
            mPredictWaitingMillis = 0;
            log("Enabled actions is null");
        }
    }

    /**
     * Updates the duration millis array based on DSRM global configuration durations.
     *
     * @see Settings.Global#DSRM_DURATION_MILLIS
     */
    private void updateGlobalConfigDurations() {
        String durationMillis = Settings.Global.getString(
                mPhone.getContext().getContentResolver(),
                Settings.Global.DSRM_DURATION_MILLIS);

        if (!TextUtils.isEmpty(durationMillis)) {
            String[] splitDurationMillis = durationMillis.split(",");
            long[] durationMillisArray = new long[splitDurationMillis.length];
            for (int i = 0; i < durationMillisArray.length; i++) {
                try {
                    durationMillisArray[i] = Long.parseLong(splitDurationMillis[i].trim());
                } catch (NumberFormatException e) {
                    mPredictWaitingMillis = 0;
                    loge("Parsing duration millis error");
                    return;
                }
            }

            int minLength = Math.min(durationMillisArray.length,
                    mDataStallRecoveryDelayMillisArray.length);

            // Copy the values from the durationMillisArray array to the
            // mDataStallRecoveryDelayMillisArray array.
            for (int i = 0; i < minLength; i++) {
                mDataStallRecoveryDelayMillisArray[i] = durationMillisArray[i];
            }
            log("DataStallRecoveryDelayMillis: "
                    + Arrays.toString(mDataStallRecoveryDelayMillisArray));
            mPredictWaitingMillis = DSRM_PREDICT_WAITING_MILLIS;
        } else {
            mPredictWaitingMillis = 0;
            log("Duration millis is null");
        }
    }

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

        //Update Global settings
        updateGlobalConfigActions();
        updateGlobalConfigDurations();
    }

    /**
@@ -341,7 +484,8 @@ public class DataStallRecoveryManager extends Handler {
     * @param recoveryAction The recovery action to query.
     * @return the delay in milliseconds for the specific recovery action.
     */
    private long getDataStallRecoveryDelayMillis(@RecoveryAction int recoveryAction) {
    @VisibleForTesting
    public long getDataStallRecoveryDelayMillis(@RecoveryAction int recoveryAction) {
        return mDataStallRecoveryDelayMillisArray[recoveryAction];
    }

@@ -351,7 +495,8 @@ public class DataStallRecoveryManager extends Handler {
     * @param recoveryAction The recovery action.
     * @return {@code true} if the action needs to be skipped.
     */
    private boolean shouldSkipRecoveryAction(@RecoveryAction int recoveryAction) {
    @VisibleForTesting
    public boolean shouldSkipRecoveryAction(@RecoveryAction int recoveryAction) {
        return mSkipRecoveryActionArray[recoveryAction];
    }

@@ -902,6 +1047,7 @@ public class DataStallRecoveryManager extends Handler {
        pw.println(
                "mMobileDataChangedToEnabledDuringDataStall="
                        + mMobileDataChangedToEnabledDuringDataStall);
        pw.println("mPredictWaitingMillis=" + mPredictWaitingMillis);
        pw.println(
                "DataStallRecoveryDelayMillisArray="
                        + Arrays.toString(mDataStallRecoveryDelayMillisArray));
+99 −0
Original line number Diff line number Diff line
@@ -27,11 +27,15 @@ import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;

import android.content.Intent;
import android.database.ContentObserver;
import android.net.NetworkAgent;
import android.net.Uri;
import android.os.Bundle;
import android.provider.Settings;
import android.telephony.Annotation.ValidationStatus;
import android.telephony.CarrierConfigManager;
import android.telephony.TelephonyManager;
import android.test.mock.MockContentResolver;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;

@@ -46,21 +50,53 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;

@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
public class DataStallRecoveryManagerTest extends TelephonyTest {
    private FakeContentResolver mFakeContentResolver;

    // Mocked classes
    private DataStallRecoveryManagerCallback mDataStallRecoveryManagerCallback;

    private DataStallRecoveryManager mDataStallRecoveryManager;

    /**
     * The fake content resolver used to receive change event from global settings
     * and notify observer of a change in content in DataStallRecoveryManager
     */
    private class FakeContentResolver extends MockContentResolver {
        @Override
        public void notifyChange(Uri uri, ContentObserver observer) {
            super.notifyChange(uri, observer);
            logd("onChanged(uri=" + uri + ")" + observer);
            if (observer != null) {
                observer.dispatchChange(false, uri);
            } else {
                mDataStallRecoveryManager.getContentObserver().dispatchChange(false, uri);
            }
        }
    }

    @Before
    public void setUp() throws Exception {
        logd("DataStallRecoveryManagerTest +Setup!");
        super.setUp(getClass().getSimpleName());
        Field field = DataStallRecoveryManager.class.getDeclaredField("mPredictWaitingMillis");
        field.setAccessible(true);

        mFakeContentResolver = new FakeContentResolver();
        doReturn(mFakeContentResolver).when(mContext).getContentResolver();
        // Set the global settings for action enabled state and duration to
        // the default test values.
        Settings.Global.putString(mFakeContentResolver, Settings.Global.DSRM_DURATION_MILLIS,
                "100,100,100,100,0");
        Settings.Global.putString(mFakeContentResolver, Settings.Global.DSRM_ENABLED_ACTIONS,
                "true,true,false,true,true");

        mDataStallRecoveryManagerCallback = mock(DataStallRecoveryManagerCallback.class);
        mCarrierConfigManager = mPhone.getContext().getSystemService(CarrierConfigManager.class);
        long[] dataStallRecoveryTimersArray = new long[] {100, 100, 100, 100};
@@ -85,11 +121,15 @@ public class DataStallRecoveryManagerTest extends TelephonyTest {
                        mMockedWwanDataServiceManager,
                        mTestableLooper.getLooper(),
                        mDataStallRecoveryManagerCallback);

        field.set(mDataStallRecoveryManager, 0L);

        logd("DataStallRecoveryManagerTest -Setup!");
    }

    @After
    public void tearDown() throws Exception {
        mFakeContentResolver = null;
        mDataStallRecoveryManager = null;
        super.tearDown();
    }
@@ -409,4 +449,63 @@ public class DataStallRecoveryManagerTest extends TelephonyTest {
            assertThat(size).isEqualTo(19);
        }
    }

    /**
     * Tests update action enable state and duration from global settings.
     */
    @Test
    public void testUpdateGlobalSettings() throws Exception {
        Field field = DataStallRecoveryManager.class.getDeclaredField("mPredictWaitingMillis");
        field.setAccessible(true);

        // Set duration to 10000/20000/30000/40000
        Settings.Global.putString(
                mFakeContentResolver, Settings.Global.DSRM_DURATION_MILLIS,
                "10000,20000,30000,40000,0");
        // Send onChange event with Settings.Global.DSRM_DURATION_MILLIS to fake ContentResolver
        mFakeContentResolver.notifyChange(
                Settings.Global.getUriFor(Settings.Global.DSRM_DURATION_MILLIS), null);
        processAllFutureMessages();
        // Verify that the durations are correct values.
        assertThat(mDataStallRecoveryManager.getDataStallRecoveryDelayMillis(0)).isEqualTo(10000L);
        assertThat(mDataStallRecoveryManager.getDataStallRecoveryDelayMillis(1)).isEqualTo(20000L);
        assertThat(mDataStallRecoveryManager.getDataStallRecoveryDelayMillis(2)).isEqualTo(30000L);
        assertThat(mDataStallRecoveryManager.getDataStallRecoveryDelayMillis(3)).isEqualTo(40000L);

        // Set action enable state to true/false/false/false/true
        Settings.Global.putString(
                mFakeContentResolver, Settings.Global.DSRM_ENABLED_ACTIONS,
                "true,false,false,false,true");
        // Send onChange event with Settings.Global.DSRM_ENABLED_ACTIONS to fake ContentResolver
        mFakeContentResolver.notifyChange(
                Settings.Global.getUriFor(Settings.Global.DSRM_ENABLED_ACTIONS), null);
        processAllFutureMessages();
        // Verify that the action enable state are correct values.
        assertThat(mDataStallRecoveryManager.shouldSkipRecoveryAction(0)).isEqualTo(false);
        assertThat(mDataStallRecoveryManager.shouldSkipRecoveryAction(1)).isEqualTo(true);
        assertThat(mDataStallRecoveryManager.shouldSkipRecoveryAction(2)).isEqualTo(true);
        assertThat(mDataStallRecoveryManager.shouldSkipRecoveryAction(3)).isEqualTo(true);
        assertThat(mDataStallRecoveryManager.shouldSkipRecoveryAction(4)).isEqualTo(false);
        // Check the predict waiting millis
        assertThat(field.get(mDataStallRecoveryManager)).isEqualTo(1000L);
        // Test predict waiting millis to rollback to 0 if there is no global duration and action
        // Set duration to empty
        Settings.Global.putString(
                mFakeContentResolver, Settings.Global.DSRM_DURATION_MILLIS,
                "");
        // Send onChange event with Settings.Global.DSRM_DURATION_MILLIS to fake ContentResolver
        mFakeContentResolver.notifyChange(
                Settings.Global.getUriFor(Settings.Global.DSRM_DURATION_MILLIS), null);
        processAllFutureMessages();
        // Set action to empty
        Settings.Global.putString(
                mFakeContentResolver, Settings.Global.DSRM_ENABLED_ACTIONS,
                "");
        // Send onChange event with Settings.Global.DSRM_ENABLED_ACTIONS to fake ContentResolver
        mFakeContentResolver.notifyChange(
                Settings.Global.getUriFor(Settings.Global.DSRM_ENABLED_ACTIONS), null);
        processAllFutureMessages();
        // Check if predict waiting millis is 0
        assertThat(field.get(mDataStallRecoveryManager)).isEqualTo(0L);
    }
}