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

Commit 2be0d236 authored by Malcolm Chen's avatar Malcolm Chen
Browse files

For validation off case, do NOT switch data until new conn is up.

For validation off data switch, we will delay to tear down the old
connection until either 1) the new connection is brought up 2) new
connection failed to bring up in 2 seconds.

This is to shorten the disconnect gap during the switch.

Bug: 140070796
Test: unittest
Change-Id: I555f4d8d900fdd081738f3db8b02fb2728a3d88c
Merged-In: I555f4d8d900fdd081738f3db8b02fb2728a3d88c
parent 4d145841
Loading
Loading
Loading
Loading
+21 −11
Original line number Diff line number Diff line
@@ -156,11 +156,10 @@ public class CellularNetworkValidator {

        private String getValidationNetworkIdentity(int subId) {
            if (!SubscriptionManager.isUsableSubscriptionId(subId)) return null;
            Phone phone = PhoneFactory.getPhone(SubscriptionController.getInstance()
                    .getPhoneId(subId));
            if (phone == null) return null;

            if (phone.getServiceState() == null) return null;
            SubscriptionController subController = SubscriptionController.getInstance();
            if (subController == null) return null;
            Phone phone = PhoneFactory.getPhone(subController.getPhoneId(subId));
            if (phone == null || phone.getServiceState() == null) return null;

            NetworkRegistrationInfo regInfo = phone.getServiceState().getNetworkRegistrationInfo(
                    DOMAIN_PS, TRANSPORT_TYPE_WWAN);
@@ -190,7 +189,11 @@ public class CellularNetworkValidator {
        /**
         * Validation failed, passed or timed out.
         */
        void onValidationResult(boolean validated, int subId);
        void onValidationDone(boolean validated, int subId);
        /**
         * Called when a corresponding network becomes available.
         */
        void onNetworkAvailable(Network network, int subId);
    }

    /**
@@ -238,7 +241,7 @@ public class CellularNetworkValidator {

        if (!SubscriptionController.getInstance().isActiveSubId(subId)) {
            logd("Failed to start validation. Inactive subId " + subId);
            callback.onValidationResult(false, subId);
            callback.onValidationDone(false, subId);
            return;
        }

@@ -325,7 +328,7 @@ public class CellularNetworkValidator {
        // Deal with the result only when state is still VALIDATING. This is to avoid
        // receiving multiple callbacks in queue.
        if (mState == STATE_VALIDATING) {
            mValidationCallback.onValidationResult(passed, mSubId);
            mValidationCallback.onValidationDone(passed, mSubId);
            if (!mReleaseAfterValidation && passed) {
                mState = STATE_VALIDATED;
            } else {
@@ -341,6 +344,12 @@ public class CellularNetworkValidator {
        mSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
    }

    private synchronized void reportNetworkAvailable(Network network, int subId) {
        // If the validation result is not for current subId, do nothing.
        if (mSubId != subId) return;
        mValidationCallback.onNetworkAvailable(network, subId);
    }

    @VisibleForTesting
    public class ConnectivityNetworkCallback extends ConnectivityManager.NetworkCallback {
        private final int mSubId;
@@ -354,13 +363,14 @@ public class CellularNetworkValidator {
        @Override
        public void onAvailable(Network network) {
            logd("network onAvailable " + network);
            if (ConnectivityNetworkCallback.this.mSubId != CellularNetworkValidator.this.mSubId) {
                return;
            }
            TelephonyMetrics.getInstance().writeNetworkValidate(
                    TelephonyEvent.NetworkValidationState.NETWORK_VALIDATION_STATE_AVAILABLE);
            // If it hits validation cache, we report as validation passed; otherwise we report
            // network is available.
            if (mValidatedNetworkCache.isRecentlyValidated(mSubId)) {
                reportValidationResult(true, ConnectivityNetworkCallback.this.mSubId);
            } else {
                reportNetworkAvailable(network, ConnectivityNetworkCallback.this.mSubId);
            }
        }

+81 −21
Original line number Diff line number Diff line
@@ -163,10 +163,25 @@ public class PhoneSwitcher extends Handler {
    @VisibleForTesting
    public final PhoneStateListener mPhoneStateListener;
    private final CellularNetworkValidator mValidator;
    private int mPendingSwitchSubId = INVALID_SUBSCRIPTION_ID;
    private boolean mPendingSwitchNeedValidation;

    @VisibleForTesting
    public final CellularNetworkValidator.ValidationCallback mValidationCallback =
            (validated, subId) -> Message.obtain(PhoneSwitcher.this,
            new CellularNetworkValidator.ValidationCallback() {
                @Override
                public void onValidationDone(boolean validated, int subId) {
                    Message.obtain(PhoneSwitcher.this,
                            EVENT_NETWORK_VALIDATION_DONE, subId, validated ? 1 : 0).sendToTarget();
                }

                @Override
                public void onNetworkAvailable(Network network, int subId) {
                    Message.obtain(PhoneSwitcher.this,
                            EVENT_NETWORK_AVAILABLE, subId, 0, network).sendToTarget();

                }
            };

    @UnsupportedAppUsage
    // How many phones (correspondingly logical modems) are allowed for PS attach. This is used
@@ -243,6 +258,7 @@ public class PhoneSwitcher extends Handler {
    // If it exists, remove the current mEmergencyOverride DDS override.
    @VisibleForTesting
    public static final int EVENT_MULTI_SIM_CONFIG_CHANGED        = 117;
    private static final int EVENT_NETWORK_AVAILABLE              = 118;

    // Depending on version of IRadioConfig, we need to send either RIL_REQUEST_ALLOW_DATA if it's
    // 1.0, or RIL_REQUEST_SET_PREFERRED_DATA if it's 1.1 or later. So internally mHalCommandToUse
@@ -521,6 +537,12 @@ public class PhoneSwitcher extends Handler {
                onValidationDone(subId, passed);
                break;
            }
            case EVENT_NETWORK_AVAILABLE: {
                int subId = msg.arg1;
                Network network = (Network) msg.obj;
                onNetworkAvailable(subId, network);
                break;
            }
            case EVENT_REMOVE_DEFAULT_NETWORK_CHANGE_CALLBACK: {
                removeDefaultNetworkChangeCallback();
                break;
@@ -1142,10 +1164,13 @@ public class PhoneSwitcher extends Handler {
        // Remove EVENT_NETWORK_VALIDATION_DONE. Don't handle validation result of previously subId
        // if queued.
        removeMessages(EVENT_NETWORK_VALIDATION_DONE);
        removeMessages(EVENT_NETWORK_AVAILABLE);

        int subIdToValidate = (subId == SubscriptionManager.DEFAULT_SUBSCRIPTION_ID)
                ? mPrimaryDataSubId : subId;

        mPendingSwitchSubId = INVALID_SUBSCRIPTION_ID;

        if (mValidator.isValidating()) {
            mValidator.stopValidation();
            sendSetOpptCallbackHelper(mSetOpptSubCallback, SET_OPPORTUNISTIC_SUB_VALIDATION_FAILED);
@@ -1166,22 +1191,37 @@ public class PhoneSwitcher extends Handler {

        // If validation feature is not supported, set it directly. Otherwise,
        // start validation on the subscription first.
        if (mValidator.isValidationFeatureSupported() && needValidation) {
        if (!mValidator.isValidationFeatureSupported()) {
            setOpportunisticSubscriptionInternal(subId);
            sendSetOpptCallbackHelper(callback, SET_OPPORTUNISTIC_SUB_SUCCESS);
            return;
        }

        // Even if needValidation is false, we still send request to validator. The reason is we
        // want to delay data switch until network is available on the target sub, to have a
        // smoothest transition possible.
        // In this case, even if data connection eventually failed in 2 seconds, we still
        // confirm the switch, to maximally respect the request.
        mPendingSwitchSubId = subIdToValidate;
        mPendingSwitchNeedValidation = needValidation;
        mSetOpptSubCallback = callback;
        long validationTimeout = getValidationTimeout(subIdToValidate, needValidation);
        mValidator.validate(subIdToValidate, validationTimeout, false, mValidationCallback);
    }

    private long getValidationTimeout(int subId, boolean needValidation) {
        if (!needValidation) return DEFAULT_VALIDATION_EXPIRATION_TIME;

        long validationTimeout = DEFAULT_VALIDATION_EXPIRATION_TIME;
        CarrierConfigManager configManager = (CarrierConfigManager)
                mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE);
        if (configManager != null) {
                PersistableBundle b = configManager.getConfigForSubId(subIdToValidate);
            PersistableBundle b = configManager.getConfigForSubId(subId);
            if (b != null) {
                validationTimeout = b.getLong(KEY_DATA_SWITCH_VALIDATION_TIMEOUT_LONG);
            }
        }
            mValidator.validate(subIdToValidate, validationTimeout, false, mValidationCallback);
        } else {
            setOpportunisticSubscriptionInternal(subId);
            sendSetOpptCallbackHelper(callback, SET_OPPORTUNISTIC_SUB_SUCCESS);
        }
        return validationTimeout;
    }

    private void sendSetOpptCallbackHelper(ISetOpportunisticDataCallback callback, int result) {
@@ -1203,15 +1243,13 @@ public class PhoneSwitcher extends Handler {
        }
    }

    private void onValidationDone(int subId, boolean passed) {
        log("onValidationDone: " + (passed ? "passed" : "failed")
                + " on subId " + subId);
    private void confirmSwitch(int subId, boolean confirm) {
        log("confirmSwitch: subId " + subId + (confirm ? " confirmed." : " cancelled."));
        int resultForCallBack;

        if (!mSubscriptionController.isActiveSubId(subId)) {
            log("onValidationDone: subId " + subId + " is no longer active");
            log("confirmSwitch: subId " + subId + " is no longer active");
            resultForCallBack = SET_OPPORTUNISTIC_SUB_INACTIVE_SUBSCRIPTION;
        } else if (!passed) {
        } else if (!confirm) {
            resultForCallBack = SET_OPPORTUNISTIC_SUB_VALIDATION_FAILED;
        } else {
            if (mSubscriptionController.isOpportunistic(subId)) {
@@ -1226,6 +1264,28 @@ public class PhoneSwitcher extends Handler {
        // Trigger callback if needed
        sendSetOpptCallbackHelper(mSetOpptSubCallback, resultForCallBack);
        mSetOpptSubCallback = null;
        mPendingSwitchSubId = INVALID_SUBSCRIPTION_ID;
    }

    private void onNetworkAvailable(int subId, Network network) {
        log("onNetworkAvailable: on subId " + subId);
        // Do nothing unless pending switch matches target subId and it doesn't require
        // validation pass.
        if (mPendingSwitchSubId == INVALID_SUBSCRIPTION_ID || mPendingSwitchSubId != subId
                || mPendingSwitchNeedValidation) {
            return;
        }
        confirmSwitch(subId, true);
        mValidator.stopValidation();
    }

    private void onValidationDone(int subId, boolean passed) {
        log("onValidationDone: " + (passed ? "passed" : "failed") + " on subId " + subId);
        if (mPendingSwitchSubId == INVALID_SUBSCRIPTION_ID || mPendingSwitchSubId != subId) return;

        // If validation failed and mPendingSwitch.mNeedValidation is false, we still confirm
        // the switch.
        confirmSwitch(subId, passed || !mPendingSwitchNeedValidation);
    }

    /**
+43 −58
Original line number Diff line number Diff line
@@ -45,24 +45,20 @@ import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;

@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
public class CellularNetworkValidatorTest extends TelephonyTest {
    private boolean mValidated = false;
    private CellularNetworkValidator mValidatorUT;
    private int mValidatedSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
    private static final PhoneCapability CAPABILITY_WITH_VALIDATION_SUPPORTED =
            new PhoneCapability(0, 0, 0, 0, 1, 0, null, null, null, null, null, null, null);
    private static final PhoneCapability CAPABILITY_WITHOUT_VALIDATION_SUPPORTED =
            new PhoneCapability(0, 0, 0, 0, 0, 0, null, null, null, null, null, null, null);
    private final CellIdentityLte mCellIdentityLte1 = new CellIdentityLte(123, 456, 0, 0, 111);
    private final CellIdentityLte mCellIdentityLte2 = new CellIdentityLte(321, 654, 0, 0, 222);

    CellularNetworkValidator.ValidationCallback mCallback = (validated, subId) -> {
        mValidated = validated;
        mValidatedSubId = subId;
    };
    @Mock
    CellularNetworkValidator.ValidationCallback mCallback;

    @Before
    public void setUp() throws Exception {
@@ -77,6 +73,7 @@ public class CellularNetworkValidatorTest extends TelephonyTest {

    @After
    public void tearDown() throws Exception {
        mValidatorUT.stopValidation();
        super.tearDown();
    }

@@ -120,13 +117,7 @@ public class CellularNetworkValidatorTest extends TelephonyTest {
        mValidatorUT.mNetworkCallback.onCapabilitiesChanged(null, new NetworkCapabilities()
                .addCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED));

        assertTrue(mValidated);
        assertEquals(subId, mValidatedSubId);
        verify(mConnectivityManager).unregisterNetworkCallback(eq(mValidatorUT.mNetworkCallback));
        assertFalse(mValidatorUT.mHandler.hasCallbacks(mValidatorUT.mTimeoutCallback));
        assertFalse(mValidatorUT.isValidating());
        assertEquals(SubscriptionManager.INVALID_SUBSCRIPTION_ID,
                mValidatorUT.getSubIdInValidation());
        assertValidationResult(subId, true);
    }

    /**
@@ -145,23 +136,13 @@ public class CellularNetworkValidatorTest extends TelephonyTest {
                .build();

        mValidatorUT.validate(subId, timeout, true, mCallback);

        assertTrue(mValidatorUT.isValidating());
        assertEquals(subId, mValidatorUT.getSubIdInValidation());
        verify(mConnectivityManager).requestNetwork(
                eq(expectedRequest), eq(mValidatorUT.mNetworkCallback), any());
        assertInValidation(subId);

        // Wait for timeout
        moveTimeForward(timeout);
        processAllMessages();

        assertFalse(mValidated);
        assertEquals(subId, mValidatedSubId);
        verify(mConnectivityManager).unregisterNetworkCallback(eq(mValidatorUT.mNetworkCallback));
        assertFalse(mValidatorUT.mHandler.hasCallbacks(mValidatorUT.mTimeoutCallback));
        assertFalse(mValidatorUT.isValidating());
        assertEquals(SubscriptionManager.INVALID_SUBSCRIPTION_ID,
                mValidatorUT.getSubIdInValidation());
        assertValidationResult(subId, false);
    }

    /**
@@ -188,13 +169,7 @@ public class CellularNetworkValidatorTest extends TelephonyTest {

        mValidatorUT.mNetworkCallback.onUnavailable();

        assertFalse(mValidated);
        assertEquals(subId, mValidatedSubId);
        verify(mConnectivityManager).unregisterNetworkCallback(eq(mValidatorUT.mNetworkCallback));
        assertFalse(mValidatorUT.mHandler.hasCallbacks(mValidatorUT.mTimeoutCallback));
        assertFalse(mValidatorUT.isValidating());
        assertEquals(SubscriptionManager.INVALID_SUBSCRIPTION_ID,
                mValidatorUT.getSubIdInValidation());
        assertValidationResult(subId, false);
    }

    /**
@@ -220,6 +195,8 @@ public class CellularNetworkValidatorTest extends TelephonyTest {
                eq(expectedRequest), eq(mValidatorUT.mNetworkCallback), any());

        mValidatorUT.mNetworkCallback.onAvailable(new Network(100));
        assertInValidation(subId);

        // Wait for timeout
        moveTimeForward(timeout);
        processAllMessages();
@@ -244,13 +221,10 @@ public class CellularNetworkValidatorTest extends TelephonyTest {

        resetStates();
        mValidatorUT.validate(subId, timeout, true, mCallback);

        assertTrue(mValidatorUT.isValidating());
        assertEquals(subId, mValidatorUT.getSubIdInValidation());
        assertInValidation(subId);

        // As recently validated, onAvailable should trigger switch.
        mValidatorUT.mNetworkCallback.onAvailable(new Network(100));

        assertValidationResult(subId, true);
    }

@@ -318,17 +292,17 @@ public class CellularNetworkValidatorTest extends TelephonyTest {
        doReturn(mNetworkRegistrationInfo).when(mServiceState).getNetworkRegistrationInfo(
                anyInt(), anyInt());

        verifyNetworkRecentlyValidated(1, false);
        verifyNetworkRecentlyValidated(2, false);
        verifyNetworkRecentlyValidated(3, false);
        assertNetworkRecentlyValidated(1, false);
        assertNetworkRecentlyValidated(2, false);
        assertNetworkRecentlyValidated(3, false);
        // Validate sub 1, 2, and 3.
        mValidatorUT.validate(1, timeout, true, mCallback);
        mValidatorUT.mNetworkCallback.onCapabilitiesChanged(null, new NetworkCapabilities()
                .addCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED));
        assertValidationResult(1, true);
        verifyNetworkRecentlyValidated(1, true);
        verifyNetworkRecentlyValidated(2, false);
        verifyNetworkRecentlyValidated(3, false);
        assertNetworkRecentlyValidated(1, true);
        assertNetworkRecentlyValidated(2, false);
        assertNetworkRecentlyValidated(3, false);
        mValidatorUT.validate(2, timeout, true, mCallback);
        mValidatorUT.mNetworkCallback.onCapabilitiesChanged(null, new NetworkCapabilities()
                .addCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED));
@@ -337,9 +311,9 @@ public class CellularNetworkValidatorTest extends TelephonyTest {
        mValidatorUT.mNetworkCallback.onCapabilitiesChanged(null, new NetworkCapabilities()
                .addCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED));
        assertValidationResult(3, true);
        verifyNetworkRecentlyValidated(1, true);
        verifyNetworkRecentlyValidated(2, true);
        verifyNetworkRecentlyValidated(3, true);
        assertNetworkRecentlyValidated(1, true);
        assertNetworkRecentlyValidated(2, true);
        assertNetworkRecentlyValidated(3, true);

        // When re-validating sub 3, onAvailable should trigger validation callback.
        resetStates();
@@ -350,7 +324,7 @@ public class CellularNetworkValidatorTest extends TelephonyTest {
        resetStates();
        mValidatorUT.validate(2, timeout, true, mCallback);
        mValidatorUT.mNetworkCallback.onLost(new Network(100));
        verifyNetworkRecentlyValidated(2, false);
        assertNetworkRecentlyValidated(2, false);

        mNetworkRegistrationInfo = new NetworkRegistrationInfo.Builder()
                .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_LTE)
@@ -374,11 +348,11 @@ public class CellularNetworkValidatorTest extends TelephonyTest {
                anyInt(), anyInt());

        // Validate sub 1.
        verifyNetworkRecentlyValidated(1, false);
        assertNetworkRecentlyValidated(1, false);
        mValidatorUT.validate(1, timeout, true, mCallback);
        mValidatorUT.mNetworkCallback.onCapabilitiesChanged(null, new NetworkCapabilities()
                .addCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED));
        verifyNetworkRecentlyValidated(1, true);
        assertNetworkRecentlyValidated(1, true);

        // Change reg state to a different network.
        mNetworkRegistrationInfo = new NetworkRegistrationInfo.Builder()
@@ -390,7 +364,7 @@ public class CellularNetworkValidatorTest extends TelephonyTest {
                anyInt(), anyInt());

        // Should NOT skip validation.
        verifyNetworkRecentlyValidated(1, false);
        assertNetworkRecentlyValidated(1, false);
    }

    @Test
@@ -409,20 +383,33 @@ public class CellularNetworkValidatorTest extends TelephonyTest {
            mValidatorUT.validate(subId, timeout, true, mCallback);
            mValidatorUT.mNetworkCallback.onCapabilitiesChanged(null, new NetworkCapabilities()
                    .addCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED));
            verifyNetworkRecentlyValidated(subId, true);
            assertNetworkRecentlyValidated(subId, true);
        }

        // Last 10 subs are kept in cache.
        for (int subId = 1; subId <= 90; subId++) {
            verifyNetworkRecentlyValidated(subId, false);
            assertNetworkRecentlyValidated(subId, false);
        }
        // Last 10 subs are kept in cache.
        for (int subId = 91; subId <= 100; subId++) {
            verifyNetworkRecentlyValidated(subId, true);
            assertNetworkRecentlyValidated(subId, true);
        }
    }

    @Test
    @SmallTest
    public void testOnNetworkAvailable() {
        int subId = 1;
        int timeout = 1000;
        mValidatorUT.validate(subId, timeout, true, mCallback);
        Network network = new Network(100);
        mValidatorUT.mNetworkCallback.onAvailable(network);

        assertInValidation(subId);
        verify(mCallback).onNetworkAvailable(network, subId);
    }

    private void verifyNetworkRecentlyValidated(int subId, boolean shouldBeRecentlyValidated) {
    private void assertNetworkRecentlyValidated(int subId, boolean shouldBeRecentlyValidated) {
        // Start validation and send network available callback.
        resetStates();
        mValidatorUT.validate(subId, 1000, true, mCallback);
@@ -447,8 +434,7 @@ public class CellularNetworkValidatorTest extends TelephonyTest {
                mValidatorUT.getSubIdInValidation());

        // Verify result.
        assertEquals(shouldPass, mValidated);
        assertEquals(subId, mValidatedSubId);
        verify(mCallback).onValidationDone(shouldPass, subId);
    }

    private void assertInValidation(int subId) {
@@ -459,7 +445,6 @@ public class CellularNetworkValidatorTest extends TelephonyTest {

    private void resetStates() {
        clearInvocations(mConnectivityManager);
        mValidated = false;
        mValidatedSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
        clearInvocations(mCallback);
    }
}
+98 −9

File changed.

Preview size limit exceeded, changes collapsed.