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

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

Merge "Added handover retry when previous data is still disconnecting" into sc-dev

parents 170b0478 9c4a76a2
Loading
Loading
Loading
Loading
+35 −9
Original line number Diff line number Diff line
@@ -1560,6 +1560,11 @@ public class DcTracker extends Handler {
        return isInEcm && !isInImsEcm;
    }

    private boolean isHandoverPending(@ApnType int apnType) {
        List<Message> messageList = mHandoverCompletionMsgs.get(apnType);
        return messageList != null && messageList.size() > 0;
    }

    private void trySetupData(ApnContext apnContext, @RequestNetworkType int requestType,
            @Nullable Message onHandoverCompleteMsg) {
        if (onHandoverCompleteMsg != null) {
@@ -1600,6 +1605,19 @@ public class DcTracker extends Handler {
                str.append("isDataEnabled() = false. " + mDataEnabledSettings);
            }

            // Check if it fails because of the existing data is still disconnecting.
            if (dataConnectionReasons.containsOnly(
                    DataDisallowedReasonType.DATA_IS_DISCONNECTING)
                    && isHandoverPending(apnContext.getApnTypeBitmask())) {
                // Normally we don't retry when isDataAllow() returns false, because that's consider
                // pre-condition not met, for example, data not enabled by the user, or airplane
                // mode is on. If we retry in those cases, there will be significant power impact.
                // DATA_IS_DISCONNECTING is a special case we want to retry, and for the handover
                // case only.
                log("Data is disconnecting. Will retry handover later.");
                return;
            }

            // If this is a data retry, we should set the APN state to FAILED so it won't stay
            // in RETRYING forever.
            if (apnContext.getState() == DctConstants.State.RETRYING) {
@@ -2369,9 +2387,10 @@ public class DcTracker extends Handler {
        sendMessageDelayed(msg, delay);

        if (DBG) {
            log("startReconnect: delay=" + delay + " apn="
                    + apnContext + "reason: " + apnContext.getReason()
                    + " subId=" + mPhone.getSubId() + " request type=" + requestType);
            log("startReconnect: delay=" + delay + ", apn="
                    + apnContext + ", reason=" + apnContext.getReason()
                    + ", subId=" + mPhone.getSubId() + ", request type="
                    + requestTypeToString(requestType));
        }
    }

@@ -2683,7 +2702,6 @@ public class DcTracker extends Handler {
            switch(state) {
                case CONNECTING:
                case CONNECTED:
                case DISCONNECTING:
                    if (DBG) log("onEnableApn: APN in " + state + " state. Exit now.");
                    if (onHandoverCompleteMsg != null) {
                        sendHandoverCompleteMsg(onHandoverCompleteMsg, false, mTransportType,
@@ -3288,12 +3306,20 @@ public class DcTracker extends Handler {
            // we're not tying up the RIL command channel.
            // This also helps in any external dependency to turn off the context.
            if (DBG) log("onDisconnectDone: attached, ready and retry after disconnect");

            // See if there are still handover request pending that we need to retry handover
            // after previous data gets disconnected.
            if (isHandoverPending(apnContext.getApnTypeBitmask())) {
                if (DBG) log("Handover request pending. Retry handover immediately.");
                startReconnect(0, apnContext, REQUEST_TYPE_HANDOVER);
            } else {
                long delay = apnContext.getRetryAfterDisconnectDelay();
                if (delay > 0) {
                    // Data connection is in IDLE state, so when we reconnect later, we'll rebuild
                    // the waiting APN list, which will also reset/reconfigure the retry manager.
                    startReconnect(delay, apnContext, REQUEST_TYPE_NORMAL);
                }
            }
        } else {
            boolean restartRadioAfterProvisioning = mPhone.getContext().getResources().getBoolean(
                    com.android.internal.R.bool.config_restartRadioAfterProvisioning);
+55 −0
Original line number Diff line number Diff line
@@ -86,6 +86,7 @@ import android.test.suitebuilder.annotation.MediumTest;
import android.test.suitebuilder.annotation.SmallTest;
import android.text.TextUtils;
import android.util.Pair;
import android.util.SparseArray;

import androidx.test.filters.FlakyTest;

@@ -101,6 +102,7 @@ import org.junit.Ignore;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;

@@ -115,6 +117,7 @@ import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

@@ -807,6 +810,18 @@ public class DcTrackerTest extends TelephonyTest {
        }
    }

    private boolean isHandoverPending(int apnType) {
        try {
            Method method = DcTracker.class.getDeclaredMethod("isHandoverPending",
                    int.class);
            method.setAccessible(true);
            return (boolean) method.invoke(mDct, apnType);
        } catch (Exception e) {
            fail(e.toString());
            return false;
        }
    }

    private void sendInitializationEvents() {
        sendCarrierConfigChanged("");

@@ -2737,4 +2752,44 @@ public class DcTrackerTest extends TelephonyTest {
        }
        waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler());
    }

    @Test
    public void testRetryHandoverWhenDisconnecting() throws Exception {
        initApns(ApnSetting.TYPE_IMS_STRING, new String[]{ApnSetting.TYPE_IMS_STRING});
        setUpDataConnection();
        SparseArray<ApnContext> apnContextsByType = Mockito.mock(SparseArray.class);
        ConcurrentHashMap<String, ApnContext> apnContexts = Mockito.mock(ConcurrentHashMap.class);
        doReturn(mApnContext).when(apnContextsByType).get(eq(ApnSetting.TYPE_IMS));
        doReturn(mApnContext).when(apnContexts).get(eq(ApnSetting.TYPE_IMS_STRING));
        doReturn(false).when(mApnContext).isConnectable();
        doReturn(DctConstants.State.DISCONNECTING).when(mApnContext).getState();
        replaceInstance(DcTracker.class, "mApnContextsByType", mDct, apnContextsByType);
        replaceInstance(DcTracker.class, "mApnContexts", mDct, apnContexts);

        sendInitializationEvents();

        logd("Sending EVENT_ENABLE_APN");
        // APN id 0 is APN_TYPE_DEFAULT
        mDct.enableApn(ApnSetting.TYPE_IMS, DcTracker.REQUEST_TYPE_HANDOVER,
                mDct.obtainMessage(12345));
        waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler());

        assertTrue(isHandoverPending(ApnSetting.TYPE_IMS));

        // Verify no handover request was sent
        verify(mDataConnection, never()).bringUp(any(ApnContext.class), anyInt(), anyInt(),
                any(Message.class), anyInt(), anyInt(), anyInt(), anyBoolean());

        doReturn(DctConstants.State.RETRYING).when(mApnContext).getState();
        // Data now is disconnected
        doReturn(true).when(mApnContext).isConnectable();
        mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_DISCONNECT_DONE,
                new AsyncResult(Pair.create(mApnContext, 0), null, null)));

        waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler());

        verify(mDataConnection).bringUp(any(ApnContext.class), anyInt(), anyInt(),
                any(Message.class), anyInt(), eq(DcTracker.REQUEST_TYPE_HANDOVER), anyInt(),
                anyBoolean());
    }
}