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

Commit ffff1370 authored by Diaesh Antony's avatar Diaesh Antony Committed by Automerger Merge Worker
Browse files

Get action and duration from global settings am: 6bd6a5a1 am: 594889e5

parents 5641f07d 594889e5
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);
    }
}