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

Commit 5e7b7772 authored by Jack Yu's avatar Jack Yu
Browse files

Fixed that data network not entering disconnecting

When the network is being torn down gracefully, it should
enter disconnecting state and send the corresponding
PreciseDataConnectionState for IMS service to perform
IMS de-registration work.

Fix: 225971458
Test: Manual & atest DataNetworkControllerTest
Merged-In: I5c9678c63cfae0f72d4c70a3d656e6d581efd0e0
Change-Id: I5c9678c63cfae0f72d4c70a3d656e6d581efd0e0
parent c9092789
Loading
Loading
Loading
Loading
+29 −4
Original line number Diff line number Diff line
@@ -211,6 +211,12 @@ public class DataNetwork extends StateMachine {
     */
    private static final int EVENT_STUCK_IN_TRANSIENT_STATE = 20;

    /**
     * Event for waiting for tearing down condition met. This will cause data network entering
     * disconnecting state.
     */
    private static final int EVENT_WAITING_FOR_TEARING_DOWN_CONDITION_MET = 21;

    /** The default MTU for IPv4 network. */
    private static final int DEFAULT_MTU_V4 = 1280;

@@ -995,7 +1001,9 @@ public class DataNetwork extends StateMachine {
                case EVENT_PCO_DATA_RECEIVED:
                case EVENT_STUCK_IN_TRANSIENT_STATE:
                case EVENT_DISPLAY_INFO_CHANGED:
                case EVENT_WAITING_FOR_TEARING_DOWN_CONDITION_MET:
                    // Ignore the events when not in the correct state.
                    log("Ignored " + eventToString(msg.what));
                    break;
                case EVENT_START_HANDOVER:
                    log("Ignore the handover to " + AccessNetworkConstants
@@ -1068,6 +1076,7 @@ public class DataNetwork extends StateMachine {
                case EVENT_START_HANDOVER:
                case EVENT_TEAR_DOWN_NETWORK:
                case EVENT_PCO_DATA_RECEIVED:
                case EVENT_WAITING_FOR_TEARING_DOWN_CONDITION_MET:
                    // Defer the request until connected or disconnected.
                    deferMessage(msg);
                    break;
@@ -1187,6 +1196,10 @@ public class DataNetwork extends StateMachine {
                    int resultCode = msg.arg1;
                    onDeactivateResponse(resultCode);
                    break;
                case EVENT_WAITING_FOR_TEARING_DOWN_CONDITION_MET:
                    transitionTo(mDisconnectingState);
                    sendMessageDelayed(EVENT_TEAR_DOWN_NETWORK, msg.arg1, msg.arg2);
                    break;
                default:
                    return NOT_HANDLED;
            }
@@ -1224,6 +1237,7 @@ public class DataNetwork extends StateMachine {
                        deferMessage(msg);
                    }
                    break;
                case EVENT_WAITING_FOR_TEARING_DOWN_CONDITION_MET:
                case EVENT_DISPLAY_INFO_CHANGED:
                case EVENT_TEAR_DOWN_NETWORK:
                    // Defer the request until handover succeeds or fails.
@@ -1325,6 +1339,15 @@ public class DataNetwork extends StateMachine {
        public boolean processMessage(Message msg) {
            logv("event=" + eventToString(msg.what));
            switch (msg.what) {
                case EVENT_TEAR_DOWN_NETWORK:
                    if (mInvokedDataDeactivation) {
                        log("Ignore tear down request because network is being torn down.");
                        break;
                    }
                    removeMessages(EVENT_TEAR_DOWN_NETWORK);
                    removeDeferredMessages(EVENT_TEAR_DOWN_NETWORK);
                    onTearDown(msg.arg1);
                    break;
                case EVENT_DEACTIVATE_DATA_NETWORK_RESPONSE:
                    int resultCode = msg.arg1;
                    onDeactivateResponse(resultCode);
@@ -2162,15 +2185,15 @@ public class DataNetwork extends StateMachine {
     * will be performed. {@code null} if the data network is already disconnected or being
     * disconnected.
     */
    public @Nullable Runnable tearDownWithCondition(@TearDownReason int reason,
    public @Nullable Runnable tearDownWhenConditionMet(@TearDownReason int reason,
            long timeoutMillis) {
        if (getCurrentState() == null || isDisconnected() || isDisconnecting()) {
            loge("tearDownGracefully: Not in the right state. State=" + getCurrentState());
            loge("tearDownWhenConditionMet: Not in the right state. State=" + getCurrentState());
            return null;
        }
        logl("tearDownWithCondition: reason=" + tearDownReasonToString(reason) + ", timeout="
        logl("tearDownWhenConditionMet: reason=" + tearDownReasonToString(reason) + ", timeout="
                + timeoutMillis + "ms.");
        sendMessageDelayed(EVENT_TEAR_DOWN_NETWORK, reason, timeoutMillis);
        sendMessage(EVENT_WAITING_FOR_TEARING_DOWN_CONDITION_MET, reason, (int) timeoutMillis);
        return () -> this.tearDown(reason);
    }

@@ -2895,6 +2918,8 @@ public class DataNetwork extends StateMachine {
                return "EVENT_DEACTIVATE_DATA_NETWORK_RESPONSE";
            case EVENT_STUCK_IN_TRANSIENT_STATE:
                return "EVENT_STUCK_IN_TRANSIENT_STATE";
            case EVENT_WAITING_FOR_TEARING_DOWN_CONDITION_MET:
                return "EVENT_WAITING_FOR_TEARING_DOWN_CONDITION_MET";
            default:
                return "Unknown(" + event + ")";
        }
+4 −5
Original line number Diff line number Diff line
@@ -890,9 +890,8 @@ public class DataNetworkController extends Handler {
            }
        });

        mPhone.getServiceStateTracker().registerForDataRegStateOrRatChanged(
                AccessNetworkConstants.TRANSPORT_TYPE_WWAN, this, EVENT_SERVICE_STATE_CHANGED,
                AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
        mPhone.getServiceStateTracker().registerForServiceStateChanged(this,
                EVENT_SERVICE_STATE_CHANGED);
        mDataConfigManager.registerForConfigUpdate(this, EVENT_DATA_CONFIG_UPDATED);
        mPhone.getServiceStateTracker().registerForPsRestrictedEnabled(this,
                EVENT_PS_RESTRICT_ENABLED, null);
@@ -1960,7 +1959,7 @@ public class DataNetworkController extends Handler {
    }

    /**
     * Unregister IMS faeture state callbacks.
     * Unregister IMS feature state callbacks.
     *
     * @param subId Subscription index.
     */
@@ -3044,7 +3043,7 @@ public class DataNetworkController extends Handler {
                    ? "registered" : "not registered")
            );
            mPendingImsDeregDataNetworks.put(dataNetwork,
                    dataNetwork.tearDownWithCondition(reason, deregDelay));
                    dataNetwork.tearDownWhenConditionMet(reason, deregDelay));
        } else {
            // Graceful tear down is not turned on. Tear down the network immediately.
            log("tearDownGracefully: Safe to tear down " + dataNetwork);
+3 −0
Original line number Diff line number Diff line
@@ -303,6 +303,8 @@ public class ContextFixture implements TestFixture<Context> {
                    return mLocationManager;
                case Context.NETWORK_POLICY_SERVICE:
                    return mNetworkPolicyManager;
                case Context.TELEPHONY_IMS_SERVICE:
                    return mImsManager;
                default:
                    return null;
            }
@@ -717,6 +719,7 @@ public class ContextFixture implements TestFixture<Context> {
    private final KeyguardManager mKeyguardManager = mock(KeyguardManager.class);
    private final VcnManager mVcnManager = mock(VcnManager.class);
    private final NetworkPolicyManager mNetworkPolicyManager = mock(NetworkPolicyManager.class);
    private final ImsManager mImsManager = mock(ImsManager.class);
    private final Configuration mConfiguration = new Configuration();
    private final DisplayMetrics mDisplayMetrics = new DisplayMetrics();
    private final SharedPreferences mSharedPreferences = PreferenceManager
+149 −6
Original line number Diff line number Diff line
@@ -68,6 +68,7 @@ import android.telephony.DataSpecificRegistrationInfo;
import android.telephony.LteVopsSupportInfo;
import android.telephony.NetworkRegistrationInfo;
import android.telephony.NetworkRegistrationInfo.RegistrationState;
import android.telephony.PreciseDataConnectionState;
import android.telephony.ServiceState;
import android.telephony.SubscriptionPlan;
import android.telephony.TelephonyDisplayInfo;
@@ -78,6 +79,15 @@ import android.telephony.data.DataCallResponse.LinkStatus;
import android.telephony.data.DataProfile;
import android.telephony.data.DataServiceCallback;
import android.telephony.data.ThrottleStatus;
import android.telephony.ims.ImsManager;
import android.telephony.ims.ImsMmTelManager;
import android.telephony.ims.ImsRcsManager;
import android.telephony.ims.ImsReasonInfo;
import android.telephony.ims.ImsRegistrationAttributes;
import android.telephony.ims.ImsStateCallback;
import android.telephony.ims.RegistrationManager.RegistrationCallback;
import android.telephony.ims.feature.ImsFeature;
import android.telephony.ims.stub.ImsRegistrationImplBase;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.util.ArraySet;
@@ -90,6 +100,7 @@ import com.android.internal.telephony.TelephonyTest;
import com.android.internal.telephony.data.AccessNetworksManager.AccessNetworksManagerCallback;
import com.android.internal.telephony.data.DataNetworkController.HandoverRule;
import com.android.internal.telephony.data.DataRetryManager.DataRetryManagerCallback;
import com.android.internal.telephony.ims.ImsResolver;

import org.junit.After;
import org.junit.Before;
@@ -115,11 +126,23 @@ public class DataNetworkControllerTest extends TelephonyTest {
    private static final String IPV4_ADDRESS = "10.0.2.15";
    private static final String IPV6_ADDRESS = "2607:fb90:a620:651d:eabe:f8da:c107:44be";

    private static final String FAKE_MMTEL_PACKAGE = "fake.mmtel.package";
    private static final String FAKE_RCS_PACKAGE = "fake.rcs.package";

    // Mocked classes
    private PhoneSwitcher mMockedPhoneSwitcher;
    protected ISub mIsub;
    protected ISub mMockedIsub;
    private DataNetworkControllerCallback mMockedDataNetworkControllerCallback;
    private DataRetryManagerCallback mMockedDataRetryManagerCallback;
    private ImsResolver mMockedImsResolver;

    private ImsManager mMockedImsManager;
    private ImsMmTelManager mMockedImsMmTelManager;
    private ImsRcsManager mMockedImsRcsManager;
    private ImsStateCallback mMmtelStateCallback;
    private ImsStateCallback mRcsStateCallback;
    private RegistrationCallback mMmtelRegCallback;
    private RegistrationCallback mRcsRegCallback;

    private int mNetworkRequestId = 0;

@@ -334,6 +357,36 @@ public class DataNetworkControllerTest extends TelephonyTest {
        processAllMessages();
    }

    private void setImsRegistered(boolean registered) {
        if (registered) {
            final ArraySet<String> features = new ArraySet<>();
            features.add("feature1");
            features.add("feature2");
            ImsRegistrationAttributes attr = new ImsRegistrationAttributes.Builder(
                    ImsRegistrationImplBase.REGISTRATION_TECH_LTE).setFeatureTags(features).build();

            mMmtelRegCallback.onRegistered(attr);
        } else {
            ImsReasonInfo info = new ImsReasonInfo(ImsReasonInfo.CODE_LOCAL_ILLEGAL_STATE, -1, "");
            mMmtelRegCallback.onUnregistered(info);
        }
    }

    private void setRcsRegistered(boolean registered) {
        if (registered) {
            final ArraySet<String> features = new ArraySet<>();
            features.add("feature1");
            features.add("feature2");
            ImsRegistrationAttributes attr = new ImsRegistrationAttributes.Builder(
                    ImsRegistrationImplBase.REGISTRATION_TECH_LTE).setFeatureTags(features).build();

            mRcsRegCallback.onRegistered(attr);
        } else {
            ImsReasonInfo info = new ImsReasonInfo(ImsReasonInfo.CODE_LOCAL_ILLEGAL_STATE, -1, "");
            mRcsRegCallback.onUnregistered(info);
        }
    }

    private void serviceStateChanged(@NetworkType int networkType,
            @RegistrationState int regState) {
        serviceStateChanged(networkType, regState, null);
@@ -426,6 +479,9 @@ public class DataNetworkControllerTest extends TelephonyTest {

        mContextFixture.putResource(com.android.internal.R.string.config_bandwidthEstimateSource,
                "bandwidth_estimator");

        mContextFixture.putIntResource(com.android.internal.R.integer
                        .config_delay_for_ims_dereg_millis, 3000);
    }

    @Before
@@ -433,12 +489,18 @@ public class DataNetworkControllerTest extends TelephonyTest {
        logd("DataNetworkControllerTest +Setup!");
        super.setUp(getClass().getSimpleName());
        mMockedPhoneSwitcher = Mockito.mock(PhoneSwitcher.class);
        mIsub = Mockito.mock(ISub.class);
        mMockedIsub = Mockito.mock(ISub.class);
        mMockedImsManager = mContext.getSystemService(ImsManager.class);
        mMockedImsMmTelManager = Mockito.mock(ImsMmTelManager.class);
        mMockedImsRcsManager = Mockito.mock(ImsRcsManager.class);
        mMockedImsResolver = Mockito.mock(ImsResolver.class);
        mMockedDataNetworkControllerCallback = Mockito.mock(DataNetworkControllerCallback.class);
        mMockedDataRetryManagerCallback = Mockito.mock(DataRetryManagerCallback.class);
        when(mTelephonyComponentFactory.makeDataSettingsManager(any(Phone.class),
                any(DataNetworkController.class), any(Looper.class),
                any(DataSettingsManager.DataSettingsManagerCallback.class))).thenCallRealMethod();
        doReturn(mMockedImsMmTelManager).when(mMockedImsManager).getImsMmTelManager(anyInt());
        doReturn(mMockedImsRcsManager).when(mMockedImsManager).getImsRcsManager(anyInt());

        initializeConfig();
        mMockedDataServiceManagers.put(AccessNetworkConstants.TRANSPORT_TYPE_WWAN,
@@ -447,8 +509,8 @@ public class DataNetworkControllerTest extends TelephonyTest {
                mMockedWlanDataServiceManager);

        replaceInstance(PhoneSwitcher.class, "sPhoneSwitcher", null, mMockedPhoneSwitcher);
        doReturn(1).when(mIsub).getDefaultDataSubId();
        doReturn(mIsub).when(mIBinder).queryLocalInterface(anyString());
        doReturn(1).when(mMockedIsub).getDefaultDataSubId();
        doReturn(mMockedIsub).when(mIBinder).queryLocalInterface(anyString());
        doReturn(mPhone).when(mPhone).getImsPhone();
        mServiceManagerMockedServices.put("isub", mIBinder);
        doReturn(new SubscriptionPlan[]{}).when(mNetworkPolicyManager)
@@ -482,6 +544,8 @@ public class DataNetworkControllerTest extends TelephonyTest {
                    Handler.class), anyInt());
        }

        doReturn(-1).when(mPhone).getSubId();

        // Note that creating a "real" data network controller will also result in creating
        // real DataRetryManager, DataConfigManager, etc...Normally in unit test we should isolate
        // other modules and make them mocked, but only focusing on testing the unit we would like
@@ -490,6 +554,10 @@ public class DataNetworkControllerTest extends TelephonyTest {
        // as well, except some modules below we replaced with mocks.
        mDataNetworkControllerUT = new DataNetworkController(mPhone, Looper.myLooper());
        doReturn(mDataNetworkControllerUT).when(mPhone).getDataNetworkController();

        doReturn(1).when(mPhone).getSubId();
        mDataNetworkControllerUT.obtainMessage(15/*EVENT_SUBSCRIPTION_CHANGED*/).sendToTarget();

        processAllMessages();
        // Clear the callbacks created by the real sub-modules created by DataNetworkController.
        clearCallbacks();
@@ -504,6 +572,7 @@ public class DataNetworkControllerTest extends TelephonyTest {
                mDataNetworkControllerUT, mDataProfileManager);
        replaceInstance(DataNetworkController.class, "mAccessNetworksManager",
                mDataNetworkControllerUT, mAccessNetworksManager);
        replaceInstance(ImsResolver.class, "sInstance", null, mMockedImsResolver);

        ArgumentCaptor<AccessNetworksManagerCallback> callbackCaptor =
                ArgumentCaptor.forClass(AccessNetworksManagerCallback.class);
@@ -556,11 +625,41 @@ public class DataNetworkControllerTest extends TelephonyTest {
                new AsyncResult(AccessNetworkConstants.TRANSPORT_TYPE_WLAN, true, null))
                .sendToTarget();

        ArgumentCaptor<ImsStateCallback> imsCallbackCaptor =
                ArgumentCaptor.forClass(ImsStateCallback.class);
        verify(mMockedImsMmTelManager).registerImsStateCallback(any(Executor.class),
                imsCallbackCaptor.capture());
        mMmtelStateCallback = imsCallbackCaptor.getValue();

        verify(mMockedImsRcsManager).registerImsStateCallback(any(Executor.class),
                imsCallbackCaptor.capture());
        mRcsStateCallback = imsCallbackCaptor.getValue();

        carrierConfigChanged();

        serviceStateChanged(TelephonyManager.NETWORK_TYPE_LTE,
                NetworkRegistrationInfo.REGISTRATION_STATE_HOME);

        // IMS registration
        doReturn(FAKE_MMTEL_PACKAGE).when(mMockedImsResolver).getConfiguredImsServicePackageName(
                anyInt(), eq(ImsFeature.FEATURE_MMTEL));
        doReturn(FAKE_RCS_PACKAGE).when(mMockedImsResolver).getConfiguredImsServicePackageName(
                anyInt(), eq(ImsFeature.FEATURE_RCS));

        mMmtelStateCallback.onAvailable();
        mRcsStateCallback.onAvailable();

        ArgumentCaptor<RegistrationCallback> regCallbackCaptor =
                ArgumentCaptor.forClass(RegistrationCallback.class);

        verify(mMockedImsMmTelManager).registerImsRegistrationCallback(any(Executor.class),
                regCallbackCaptor.capture());
        mMmtelRegCallback = regCallbackCaptor.getValue();

        verify(mMockedImsRcsManager).registerImsRegistrationCallback(any(Executor.class),
                regCallbackCaptor.capture());
        mRcsRegCallback = regCallbackCaptor.getValue();

        processAllMessages();

        logd("DataNetworkControllerTest -Setup!");
@@ -740,7 +839,6 @@ public class DataNetworkControllerTest extends TelephonyTest {
        verifyConnectedNetworkHasCapabilities(NetworkCapabilities.NET_CAPABILITY_IMS);
        verifyConnectedNetworkHasDataProfile(mImsDataProfile);
        List<DataNetwork> dataNetworkList = getDataNetworks();
        DataNetwork dataNetwork = dataNetworkList.get(0);
        assertThat(dataNetworkList.get(0).getLinkProperties().getAddresses()).containsExactly(
                InetAddresses.parseNumericAddress(IPV4_ADDRESS),
                InetAddresses.parseNumericAddress(IPV6_ADDRESS));
@@ -1922,4 +2020,49 @@ public class DataNetworkControllerTest extends TelephonyTest {
        verifyConnectedNetworkHasCapabilities(NetworkCapabilities.NET_CAPABILITY_DUN);
        verifyNoConnectedNetworkHasCapability(NetworkCapabilities.NET_CAPABILITY_FOTA);
    }

    @Test
    public void testImsGracefulTearDown() throws Exception {
        setImsRegistered(true);
        setRcsRegistered(true);

        NetworkCapabilities netCaps = new NetworkCapabilities();
        netCaps.addCapability(NetworkCapabilities.NET_CAPABILITY_IMS);
        netCaps.setRequestorPackageName(FAKE_MMTEL_PACKAGE);

        NetworkRequest nativeNetworkRequest = new NetworkRequest(netCaps,
                ConnectivityManager.TYPE_MOBILE, ++mNetworkRequestId, NetworkRequest.Type.REQUEST);
        TelephonyNetworkRequest networkRequest = new TelephonyNetworkRequest(
                nativeNetworkRequest, mPhone);

        mDataNetworkControllerUT.addNetworkRequest(networkRequest);

        processAllMessages();
        Mockito.clearInvocations(mPhone);

        // SIM removal
        mDataNetworkControllerUT.obtainMessage(9/*EVENT_SIM_STATE_CHANGED*/,
                TelephonyManager.SIM_STATE_ABSENT, 0).sendToTarget();
        processAllMessages();

        // Make sure data network enters disconnecting state
        ArgumentCaptor<PreciseDataConnectionState> pdcsCaptor =
                ArgumentCaptor.forClass(PreciseDataConnectionState.class);
        verify(mPhone).notifyDataConnection(pdcsCaptor.capture());
        PreciseDataConnectionState pdcs = pdcsCaptor.getValue();
        assertThat(pdcs.getState()).isEqualTo(TelephonyManager.DATA_DISCONNECTING);

        // IMS de-registered. Now data network is safe to be torn down.
        Mockito.clearInvocations(mPhone);
        setImsRegistered(false);
        setRcsRegistered(false);
        processAllMessages();

        // All data should be disconnected.
        verifyAllDataDisconnected();
        verifyNoConnectedNetworkHasCapability(NetworkCapabilities.NET_CAPABILITY_IMS);
        verify(mPhone).notifyDataConnection(pdcsCaptor.capture());
        pdcs = pdcsCaptor.getValue();
        assertThat(pdcs.getState()).isEqualTo(TelephonyManager.DATA_DISCONNECTED);
    }
}