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

Commit 7d0db95d authored by Jack Yu's avatar Jack Yu
Browse files

IWLAN handover optimization

Ignored preference change update from access network
manager if handover is ongoing, and then perform
handover evaluation again after handover completes to
prevent out-of-sync with QNS.

Also fixed the debug messages for setup data call
and deactivate data call.

Fix: 224743569
Test: Manual + atest DataNetworkControllerTest

Change-Id: Ic6ba2d662ca23b0c0f5b618ac7f04c546b49ff50
parent 49521daf
Loading
Loading
Loading
Loading
+5 −3
Original line number Diff line number Diff line
@@ -1982,10 +1982,11 @@ public class RIL extends BaseCommands implements CommandsInterface {

            if (RILJ_LOGD) {
                riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)
                        + ",reason=" + RILUtils.setupDataReasonToString(reason)
                        + ",accessNetworkType=" + AccessNetworkType.toString(accessNetworkType)
                        + ",dataProfile=" + dataProfile + ",isRoaming=" + isRoaming
                        + ",allowRoaming=" + allowRoaming + ",reason" + reason
                        + ",linkProerties=" + linkProperties + ",pduSessionId=" + pduSessionId
                        + ",allowRoaming=" + allowRoaming
                        + ",linkProperties=" + linkProperties + ",pduSessionId=" + pduSessionId
                        + ",sliceInfo=" + sliceInfo + ",trafficDescriptor=" + trafficDescriptor
                        + ",matchAllRuleAllowed=" + matchAllRuleAllowed);
            }
@@ -2249,7 +2250,8 @@ public class RIL extends BaseCommands implements CommandsInterface {

            if (RILJ_LOGD) {
                riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)
                        + " cid = " + cid + " reason = " + reason);
                        + " cid = " + cid + " reason = "
                        + RILUtils.deactivateDataReasonToString(reason));
            }

            try {
+43 −0
Original line number Diff line number Diff line
@@ -313,6 +313,9 @@ import android.telephony.UiccSlotMapping;
import android.telephony.data.ApnSetting;
import android.telephony.data.DataCallResponse;
import android.telephony.data.DataProfile;
import android.telephony.data.DataService;
import android.telephony.data.DataService.DeactivateDataReason;
import android.telephony.data.DataService.SetupDataReason;
import android.telephony.data.EpsQos;
import android.telephony.data.NetworkSliceInfo;
import android.telephony.data.NetworkSlicingConfig;
@@ -4626,6 +4629,46 @@ public class RILUtils {
        return string != null ? string : "";
    }

    /**
     * Convert setup data reason to string.
     *
     * @param reason The reason for setup data call.
     * @return The reason in string format.
     */
    public static String setupDataReasonToString(@SetupDataReason int reason) {
        switch (reason) {
            case DataService.REQUEST_REASON_NORMAL:
                return "NORMAL";
            case DataService.REQUEST_REASON_HANDOVER:
                return "HANDOVER";
            case DataService.REQUEST_REASON_UNKNOWN:
                return "UNKNOWN";
            default:
                return "UNKNOWN(" + reason + ")";
        }
    }

    /**
     * Convert deactivate data reason to string.
     *
     * @param reason The reason for deactivate data call.
     * @return The reason in string format.
     */
    public static String deactivateDataReasonToString(@DeactivateDataReason int reason) {
        switch (reason) {
            case DataService.REQUEST_REASON_NORMAL:
                return "NORMAL";
            case DataService.REQUEST_REASON_HANDOVER:
                return "HANDOVER";
            case DataService.REQUEST_REASON_SHUTDOWN:
                return "SHUTDOWN";
            case DataService.REQUEST_REASON_UNKNOWN:
                return "UNKNOWN";
            default:
                return "UNKNOWN(" + reason + ")";
        }
    }

    /**
     * RIL request to String
     * @param request request
+15 −23
Original line number Diff line number Diff line
@@ -104,6 +104,7 @@ import java.net.InetAddress;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
@@ -973,14 +974,18 @@ public class DataNetwork extends StateMachine {
                    mAdministratorUids = Arrays.copyOf(administratorUids, administratorUids.length);
                    break;
                }
                case EVENT_START_HANDOVER:
                case EVENT_BANDWIDTH_ESTIMATE_FROM_MODEM_CHANGED:
                case EVENT_BANDWIDTH_ESTIMATE_FROM_BANDWIDTH_ESTIMATOR_CHANGED:
                case EVENT_TEAR_DOWN_NETWORK:
                case EVENT_PCO_DATA_RECEIVED:
                case EVENT_STUCK_IN_TRANSIENT_STATE:
                case EVENT_DISPLAY_INFO_CHANGED:
                    // Ignore the events when not in the correct state.
                    break;
                case EVENT_START_HANDOVER:
                    log("Ignore the handover to " + AccessNetworkConstants
                            .transportTypeToString(msg.arg1) + " request.");
                    break;
                default:
                    loge("Unhandled event " + eventToString(msg.what));
                    break;
@@ -1206,7 +1211,6 @@ public class DataNetwork extends StateMachine {
                        deferMessage(msg);
                    }
                    break;
                case EVENT_START_HANDOVER:
                case EVENT_TEAR_DOWN_NETWORK:
                    // Defer the request until handover succeeds or fails.
                    deferMessage(msg);
@@ -2440,28 +2444,16 @@ public class DataNetwork extends StateMachine {
    }

    /**
     * Get the highest priority network capability from the network request. This is used to get
     * the representative APN-type capability for different purposes. It will never return a
     * non-APN-type capability.
     * Get the APN type network capability. If there are more than one capabilities that are
     * APN-types, then return the highest priority one.
     *
     * @return The highest priority network capability from this network.
     * @return The APN type network capability from this network.
     */
    public @NetCapability int getHighestPriorityNetworkCapability() {
        int highestPriority = 0;
        int highestPriorityCapability = -1;
        for (int capability : getNetworkCapabilities().getCapabilities()) {
            // Convert the capability to APN type. For non-APN-type capabilities, TYPE_NONE is
            // returned.
            int apnType = DataUtils.networkCapabilityToApnType(capability);
            if (apnType != ApnSetting.TYPE_NONE) {
                int priority = mDataConfigManager.getNetworkCapabilityPriority(capability);
                if (priority > highestPriority) {
                    highestPriority = priority;
                    highestPriorityCapability = capability;
                }
            }
        }
        return highestPriorityCapability;
    public @NetCapability int getApnTypeNetworkCapability() {
        return Arrays.stream(getNetworkCapabilities().getCapabilities()).boxed()
                .filter(cap -> DataUtils.networkCapabilityToApnType(cap) != ApnSetting.TYPE_NONE)
                .max(Comparator.comparingInt(mDataConfigManager::getNetworkCapabilityPriority))
                .orElse(-1);
    }

    /**
+38 −20
Original line number Diff line number Diff line
@@ -178,8 +178,8 @@ public class DataNetworkController extends Handler {
    /** Event for emergency call started or ended. */
    private static final int EVENT_EMERGENCY_CALL_CHANGED = 20;

    /** Event for preferred transport changed. */
    private static final int EVENT_PREFERRED_TRANSPORT_CHANGED = 21;
    /** Event for evaluating preferred transport. */
    private static final int EVENT_EVALUATE_PREFERRED_TRANSPORT = 21;

    /** Event for subscription plans changed. */
    private static final int EVENT_SUBSCRIPTION_PLANS_CHANGED = 22;
@@ -821,7 +821,12 @@ public class DataNetworkController extends Handler {
        mAccessNetworksManager.registerCallback(new AccessNetworksManagerCallback(this::post) {
            @Override
            public void onPreferredTransportChanged(@NetCapability int capability) {
                DataNetworkController.this.onPreferredTransportChanged(capability);
                int preferredTransport = mAccessNetworksManager
                        .getPreferredTransportByNetworkCapability(capability);
                logl("onPreferredTransportChanged: "
                        + DataUtils.networkCapabilityToString(capability) + " preferred on "
                        + AccessNetworkConstants.transportTypeToString(preferredTransport));
                DataNetworkController.this.onEvaluatePreferredTransport(capability);
                sendMessage(obtainMessage(EVENT_REEVALUATE_UNSATISFIED_NETWORK_REQUESTS,
                        DataEvaluationReason.PREFERRED_TRANSPORT_CHANGED));
            }
@@ -963,8 +968,8 @@ public class DataNetworkController extends Handler {
                            DataEvaluationReason.EMERGENCY_CALL_CHANGED));
                }
                break;
            case EVENT_PREFERRED_TRANSPORT_CHANGED:
                onPreferredTransportChanged(msg.arg1);
            case EVENT_EVALUATE_PREFERRED_TRANSPORT:
                onEvaluatePreferredTransport(msg.arg1);
                break;
            case EVENT_SUBSCRIPTION_PLANS_CHANGED:
                SubscriptionPlan[] plans = (SubscriptionPlan[]) msg.obj;
@@ -2182,7 +2187,7 @@ public class DataNetworkController extends Handler {
        }

        int preferredTransport = mAccessNetworksManager.getPreferredTransportByNetworkCapability(
                dataNetwork.getHighestPriorityNetworkCapability());
                dataNetwork.getApnTypeNetworkCapability());
        if (dataNetwork.getTransport() == preferredTransport) {
            log("onDataNetworkHandoverRetry: " + dataNetwork + " is already on the preferred "
                    + "transport " + AccessNetworkConstants.transportTypeToString(
@@ -2295,8 +2300,13 @@ public class DataNetworkController extends Handler {
     * @param dataNetwork The data network.
     */
    private void onDataNetworkHandoverSucceeded(@NonNull DataNetwork dataNetwork) {
        logl("Successfully handover " + dataNetwork + " to "
                + AccessNetworkConstants.transportTypeToString(dataNetwork.getTransport()));
        logl("Handover successfully. " + dataNetwork + " to " + AccessNetworkConstants
                .transportTypeToString(dataNetwork.getTransport()));
        // The preferred transport might be changed when handover was in progress. We need to
        // evaluate again to make sure we are not out-of-sync with the input from access network
        // manager.
        sendMessage(obtainMessage(EVENT_EVALUATE_PREFERRED_TRANSPORT,
                dataNetwork.getApnTypeNetworkCapability(), 0));
    }

    /**
@@ -2314,9 +2324,9 @@ public class DataNetworkController extends Handler {
    private void onDataNetworkHandoverFailed(@NonNull DataNetwork dataNetwork,
            @DataFailureCause int cause, long retryDelayMillis,
            @HandoverFailureMode int handoverFailureMode) {
        logl("onDataNetworkHandoverFailed: " + dataNetwork + ", cause="
                + DataFailCause.toString(cause) + "(0x" + Integer.toHexString(cause)
                + "), retryDelayMillis=" + retryDelayMillis + "ms, handoverFailureMode="
        logl("Handover failed. " + dataNetwork + ", cause=" + DataFailCause.toString(cause)
                + "(0x" + Integer.toHexString(cause) + "), retryDelayMillis=" + retryDelayMillis
                + "ms, handoverFailureMode="
                + DataCallResponse.failureModeToString(handoverFailureMode));
        if (handoverFailureMode == DataCallResponse.HANDOVER_FAILURE_MODE_DO_FALLBACK
                || (handoverFailureMode == DataCallResponse.HANDOVER_FAILURE_MODE_LEGACY
@@ -2325,8 +2335,8 @@ public class DataNetworkController extends Handler {
            // to the original one, but we should re-evaluate the preferred transport again to
            // make sure QNS does change it back, if not, we still need to perform handover at that
            // time.
            sendMessageDelayed(obtainMessage(EVENT_PREFERRED_TRANSPORT_CHANGED,
                    dataNetwork.getHighestPriorityNetworkCapability(), 0),
            sendMessageDelayed(obtainMessage(EVENT_EVALUATE_PREFERRED_TRANSPORT,
                    dataNetwork.getApnTypeNetworkCapability(), 0),
                    REEVALUATE_PREFERRED_TRANSPORT_DELAY_MILLIS);
        } else if (handoverFailureMode == DataCallResponse
                .HANDOVER_FAILURE_MODE_NO_FALLBACK_RETRY_SETUP_NORMAL || handoverFailureMode
@@ -2422,26 +2432,34 @@ public class DataNetworkController extends Handler {
    }

    /**
     * Called when preferred transport changed for certain capability.
     * Called when needed to evaluate the preferred transport for certain capability.
     *
     * @param capability The network capability that has preferred transport changed.
     * @param capability The network capability to evaluate.
     */
    private void onPreferredTransportChanged(@NetCapability int capability) {
    private void onEvaluatePreferredTransport(@NetCapability int capability) {
        int preferredTransport = mAccessNetworksManager
                .getPreferredTransportByNetworkCapability(capability);
        logl("onPreferredTransportChanged: " + DataUtils.networkCapabilityToString(capability)
        log("evaluatePreferredTransport: " + DataUtils.networkCapabilityToString(capability)
                + " preferred on "
                + AccessNetworkConstants.transportTypeToString(preferredTransport));
        for (DataNetwork dataNetwork : mDataNetworkList) {
            if (dataNetwork.getHighestPriorityNetworkCapability() == capability) {
            if (dataNetwork.getApnTypeNetworkCapability() == capability) {
                // Check if the data network's current transport is different than from the
                // preferred transport. If it's different, then handover is needed.
                if (dataNetwork.getTransport() == preferredTransport) {
                    log("onPreferredTransportChanged:" + dataNetwork + " already on "
                    log("evaluatePreferredTransport:" + dataNetwork + " already on "
                            + AccessNetworkConstants.transportTypeToString(preferredTransport));
                    continue;
                }

                // If handover is ongoing, ignore the preference change for now. After handover
                // succeeds or fails, preferred transport will be re-evaluate again. Handover will
                // be performed at that time if needed.
                if (dataNetwork.isHandoverInProgress()) {
                    log("evaluatePreferredTransport: " + dataNetwork + " handover in progress.");
                    continue;
                }

                DataEvaluation dataEvaluation = evaluateDataNetworkHandover(dataNetwork);
                if (!dataEvaluation.containsDisallowedReasons()) {
                    logl("Start handover " + dataNetwork + " to "
@@ -2449,7 +2467,7 @@ public class DataNetworkController extends Handler {
                    dataNetwork.startHandover(preferredTransport, null);
                } else if (dataEvaluation.containsOnly(
                        DataDisallowedReason.NOT_ALLOWED_BY_POLICY)) {
                    logl("onPreferredTransportChanged: Handover not allowed by policy. Tear "
                    logl("evaluatePreferredTransport: Handover not allowed by policy. Tear "
                            + "down the network so a new network can be setup on "
                            + AccessNetworkConstants.transportTypeToString(preferredTransport)
                            + ".");
+61 −5
Original line number Diff line number Diff line
@@ -86,6 +86,7 @@ import com.android.internal.telephony.ISub;
import com.android.internal.telephony.Phone;
import com.android.internal.telephony.PhoneConstants;
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;

@@ -126,6 +127,8 @@ public class DataNetworkControllerTest extends TelephonyTest {
    private DataNetworkController mDataNetworkControllerUT;
    private PersistableBundle mCarrierConfig;

    private AccessNetworksManagerCallback mAccessNetworksManagerCallback;

    private final DataProfile mGeneralPurposeDataProfile = new DataProfile.Builder()
            .setApnSetting(new ApnSetting.Builder()
                    .setId(2163)
@@ -501,6 +504,11 @@ public class DataNetworkControllerTest extends TelephonyTest {
        replaceInstance(DataNetworkController.class, "mAccessNetworksManager",
                mDataNetworkControllerUT, mAccessNetworksManager);

        ArgumentCaptor<AccessNetworksManagerCallback> callbackCaptor =
                ArgumentCaptor.forClass(AccessNetworksManagerCallback.class);
        verify(mAccessNetworksManager).registerCallback(callbackCaptor.capture());
        mAccessNetworksManagerCallback = callbackCaptor.getValue();

        doAnswer(invocation -> {
            TelephonyNetworkRequest networkRequest =
                    (TelephonyNetworkRequest) invocation.getArguments()[0];
@@ -1027,7 +1035,7 @@ public class DataNetworkControllerTest extends TelephonyTest {
                .getPreferredTransportByNetworkCapability(
                        eq(NetworkCapabilities.NET_CAPABILITY_INTERNET));
        // Data remain disabled, but trigger the preference evaluation.
        mDataNetworkControllerUT.obtainMessage(21 /*EVENT_PREFERRED_TRANSPORT_CHANGED*/,
        mDataNetworkControllerUT.obtainMessage(21 /*EVENT_EVALUATE_PREFERRED_TRANSPORT*/,
                NetworkCapabilities.NET_CAPABILITY_INTERNET, 0).sendToTarget();
        mDataNetworkControllerUT.obtainMessage(5 /*EVENT_REEVALUATE_UNSATISFIED_NETWORK_REQUESTS*/,
                DataEvaluation.DataEvaluationReason.PREFERRED_TRANSPORT_CHANGED).sendToTarget();
@@ -1295,8 +1303,8 @@ public class DataNetworkControllerTest extends TelephonyTest {

        doReturn(AccessNetworkConstants.TRANSPORT_TYPE_WLAN).when(mAccessNetworksManager)
                .getPreferredTransportByNetworkCapability(NetworkCapabilities.NET_CAPABILITY_IMS);
        mDataNetworkControllerUT.obtainMessage(21/*EVENT_EVALUATE_PREFERRED_TRANSPORT*/,
                NetworkCapabilities.NET_CAPABILITY_IMS, 0).sendToTarget();
        mAccessNetworksManagerCallback.onPreferredTransportChanged(
                NetworkCapabilities.NET_CAPABILITY_IMS);
        processAllMessages();

        DataNetwork dataNetwork = getDataNetworks().get(0);
@@ -1305,6 +1313,54 @@ public class DataNetworkControllerTest extends TelephonyTest {
                AccessNetworkConstants.TRANSPORT_TYPE_WLAN);
    }

    @Test
    public void testHandoverDataNetworkBackToBackPreferenceChanged() throws Exception {
        testSetupImsDataNetwork();

        Mockito.reset(mMockedWlanDataServiceManager);
        doReturn(AccessNetworkConstants.TRANSPORT_TYPE_WLAN).when(mAccessNetworksManager)
                .getPreferredTransportByNetworkCapability(NetworkCapabilities.NET_CAPABILITY_IMS);
        mAccessNetworksManagerCallback.onPreferredTransportChanged(
                NetworkCapabilities.NET_CAPABILITY_IMS);

        processAllMessages();

        // Capture the message for setup data call response. We want to delay it.
        ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class);
        verify(mMockedWlanDataServiceManager).setupDataCall(anyInt(), any(DataProfile.class),
                anyBoolean(), anyBoolean(), anyInt(), any(), anyInt(), any(), any(), anyBoolean(),
                messageCaptor.capture());

        // Before setup data call response, change the preference back to cellular.
        doReturn(AccessNetworkConstants.TRANSPORT_TYPE_WWAN).when(mAccessNetworksManager)
                .getPreferredTransportByNetworkCapability(NetworkCapabilities.NET_CAPABILITY_IMS);
        mAccessNetworksManagerCallback.onPreferredTransportChanged(
                NetworkCapabilities.NET_CAPABILITY_IMS);
        processAllMessages();

        // Before setup data call response, change the preference back to IWLAN.
        doReturn(AccessNetworkConstants.TRANSPORT_TYPE_WLAN).when(mAccessNetworksManager)
                .getPreferredTransportByNetworkCapability(NetworkCapabilities.NET_CAPABILITY_IMS);
        mAccessNetworksManagerCallback.onPreferredTransportChanged(
                NetworkCapabilities.NET_CAPABILITY_IMS);
        processAllMessages();

        // Finally handover is completed.
        Message msg = messageCaptor.getValue();
        DataCallResponse response = new DataCallResponse.Builder()
                .setCause(DataFailCause.NONE)
                .build();
        msg.getData().putParcelable("data_call_response", response);
        msg.arg1 = DataServiceCallback.RESULT_SUCCESS;
        msg.sendToTarget();
        processAllMessages();

        // Make sure handover request is only sent once.
        verify(mMockedWlanDataServiceManager, times(1)).setupDataCall(anyInt(),
                any(DataProfile.class), anyBoolean(), anyBoolean(), anyInt(), any(), anyInt(),
                any(), any(), anyBoolean(), messageCaptor.capture());
    }

    @Test
    public void testHandoverDataNetworkNotAllowedByPolicy() throws Exception {
        mCarrierConfig.putStringArray(CarrierConfigManager.KEY_IWLAN_HANDOVER_POLICY_STRING_ARRAY,
@@ -1318,8 +1374,8 @@ public class DataNetworkControllerTest extends TelephonyTest {

        doReturn(AccessNetworkConstants.TRANSPORT_TYPE_WLAN).when(mAccessNetworksManager)
                .getPreferredTransportByNetworkCapability(NetworkCapabilities.NET_CAPABILITY_IMS);
        mDataNetworkControllerUT.obtainMessage(21/*EVENT_PREFERRED_TRANSPORT_CHANGED*/,
                NetworkCapabilities.NET_CAPABILITY_IMS, 0).sendToTarget();
        mAccessNetworksManagerCallback.onPreferredTransportChanged(
                NetworkCapabilities.NET_CAPABILITY_IMS);
        // After this, IMS data network should be disconnected, and DNC should attempt to
        // establish a new one on IWLAN
        processAllMessages();