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

Commit 73316fe8 authored by Jack Yu's avatar Jack Yu
Browse files

Added handover failure fallback support

If data handover fails with specific fail cause
HANDOFF_PREFERENCE_CHANGED, then frameworks will
no tear down the original transport and will not
move the network requests to the new transport.

Test: Telephony sanity tests
Bug: 132367522
Merged-In: Iaa20f9a54e43abfc37ad02a68adbd167e9257b02
Change-Id: Iaa20f9a54e43abfc37ad02a68adbd167e9257b02
(cherry picked from commit b75186b0)
parent a0d3232d
Loading
Loading
Loading
Loading
+29 −14
Original line number Diff line number Diff line
@@ -69,6 +69,7 @@ import android.telephony.AccessNetworkConstants.TransportType;
import android.telephony.CarrierConfigManager;
import android.telephony.CellLocation;
import android.telephony.DataFailCause;
import android.telephony.DataFailCause.FailCause;
import android.telephony.NetworkRegistrationInfo;
import android.telephony.PcoData;
import android.telephony.Rlog;
@@ -161,15 +162,15 @@ public class DcTracker extends Handler {
    public @interface RequestNetworkType {}

    /**
     * Normal request for {@link #requestNetwork(NetworkRequest, int, LocalLog)}. For request
     * Normal request for {@link #requestNetwork(NetworkRequest, int, Message)}. For request
     * network, this adds the request to the {@link ApnContext}. If there were no network request
     * attached to the {@link ApnContext} earlier, this request setups a data connection.
     */
    public static final int REQUEST_TYPE_NORMAL = 1;

    /**
     * Handover request for {@link #requestNetwork(NetworkRequest, int, LocalLog)} or
     * {@link #releaseNetwork(NetworkRequest, int, LocalLog)}. For request network, this
     * Handover request for {@link #requestNetwork(NetworkRequest, int, Message)} or
     * {@link #releaseNetwork(NetworkRequest, int)}. For request network, this
     * initiates the handover data setup process. The existing data connection will be seamlessly
     * handover to the new network. For release network, this performs a data connection softly
     * clean up at the underlying layer (versus normal data release).
@@ -192,7 +193,7 @@ public class DcTracker extends Handler {
    public static final int RELEASE_TYPE_NORMAL = 1;

    /**
     * Detach request for {@link #releaseNetwork(NetworkRequest, int, LocalLog)} only. This
     * Detach request for {@link #releaseNetwork(NetworkRequest, int)} only. This
     * forces the APN context detach from the data connection. If this {@link ApnContext} is the
     * last one attached to the data connection, the data connection will be torn down, otherwise
     * the data connection remains active.
@@ -200,7 +201,7 @@ public class DcTracker extends Handler {
    public static final int RELEASE_TYPE_DETACH = 2;

    /**
     * Handover request for {@link #releaseNetwork(NetworkRequest, int, LocalLog)}. For release
     * Handover request for {@link #releaseNetwork(NetworkRequest, int)}. For release
     * network, this performs a data connection softly clean up at the underlying layer (versus
     * normal data release).
     */
@@ -211,6 +212,12 @@ public class DcTracker extends Handler {
    static final String DATA_COMPLETE_MSG_EXTRA_TRANSPORT_TYPE = "extra_transport_type";
    static final String DATA_COMPLETE_MSG_EXTRA_REQUEST_TYPE = "extra_request_type";
    static final String DATA_COMPLETE_MSG_EXTRA_SUCCESS = "extra_success";
    /**
     * The flag indicates whether after handover failure, the data connection should remain on the
     * original transport.
     */
    static final String DATA_COMPLETE_MSG_EXTRA_HANDOVER_FAILURE_FALLBACK =
            "extra_handover_failure_fallback";

    private final String mLogTag;

@@ -1829,7 +1836,7 @@ public class DcTracker extends Handler {
        }
    }

    boolean isPermanentFailure(@DataFailCause.FailCause int dcFailCause) {
    boolean isPermanentFailure(@FailCause int dcFailCause) {
        return (DataFailCause.isPermanentFailure(mPhone.getContext(), dcFailCause,
                mPhone.getSubId())
                && (mAttached.get() == false || dcFailCause != DataFailCause.SIGNAL_LOST));
@@ -2183,7 +2190,7 @@ public class DcTracker extends Handler {
                SystemClock.elapsedRealtime() + delay, alarmIntent);
    }

    private void notifyNoData(@DataFailCause.FailCause int lastFailCauseCode,
    private void notifyNoData(@FailCause int lastFailCauseCode,
                              ApnContext apnContext) {
        if (DBG) log( "notifyNoData: type=" + apnContext.getApnType());
        if (isPermanentFailure(lastFailCauseCode)
@@ -2313,13 +2320,19 @@ public class DcTracker extends Handler {

    private void sendRequestNetworkCompleteMsg(Message message, boolean success,
                                               @TransportType int transport,
                                               @RequestNetworkType int requestType) {
                                               @RequestNetworkType int requestType,
                                               @FailCause int cause) {
        if (message == null) return;

        Bundle b = message.getData();
        b.putBoolean(DATA_COMPLETE_MSG_EXTRA_SUCCESS, success);
        b.putInt(DATA_COMPLETE_MSG_EXTRA_REQUEST_TYPE, requestType);
        b.putInt(DATA_COMPLETE_MSG_EXTRA_TRANSPORT_TYPE, transport);
        // TODO: For now this is the only fail cause that we know modem keeps data connection on
        // original transport. Might add more complicated logic or mapping in the future.
        b.putBoolean(DATA_COMPLETE_MSG_EXTRA_HANDOVER_FAILURE_FALLBACK,
                (requestType == REQUEST_TYPE_HANDOVER
                        && cause == DataFailCause.HANDOFF_PREFERENCE_CHANGED));
        message.sendToTarget();
    }

@@ -2334,7 +2347,8 @@ public class DcTracker extends Handler {
        ApnContext apnContext = mApnContextsByType.get(apnType);
        if (apnContext == null) {
            loge("onEnableApn(" + apnType + "): NO ApnContext");
            sendRequestNetworkCompleteMsg(onCompleteMsg, false, mTransportType, requestType);
            sendRequestNetworkCompleteMsg(onCompleteMsg, false, mTransportType, requestType,
                    DataFailCause.NONE);
            return;
        }

@@ -2349,7 +2363,8 @@ public class DcTracker extends Handler {
            str = "onEnableApn: dependency is not met.";
            if (DBG) log(str);
            apnContext.requestLog(str);
            sendRequestNetworkCompleteMsg(onCompleteMsg, false, mTransportType, requestType);
            sendRequestNetworkCompleteMsg(onCompleteMsg, false, mTransportType, requestType,
                    DataFailCause.NONE);
            return;
        }

@@ -2366,13 +2381,13 @@ public class DcTracker extends Handler {
                    apnContext.requestLog("onEnableApn state=CONNECTED, so return");

                    sendRequestNetworkCompleteMsg(onCompleteMsg, true, mTransportType,
                            requestType);
                            requestType, DataFailCause.NONE);
                    return;
                case DISCONNECTING:
                    if (DBG) log("onEnableApn: 'DISCONNECTING' so return");
                    apnContext.requestLog("onEnableApn state=DISCONNECTING, so return");
                    sendRequestNetworkCompleteMsg(onCompleteMsg, false, mTransportType,
                            requestType);
                            requestType, DataFailCause.NONE);
                    return;
                case IDLE:
                    // fall through: this is unexpected but if it happens cleanup and try setup
@@ -2399,7 +2414,7 @@ public class DcTracker extends Handler {
            addRequestNetworkCompleteMsg(onCompleteMsg, apnType);
        } else {
            sendRequestNetworkCompleteMsg(onCompleteMsg, false, mTransportType,
                    requestType);
                    requestType, DataFailCause.NONE);
        }
    }

@@ -2689,7 +2704,7 @@ public class DcTracker extends Handler {
        List<Message> messageList = mRequestNetworkCompletionMsgs.get(apnType);
        if (messageList != null) {
            for (Message msg : messageList) {
                sendRequestNetworkCompleteMsg(msg, success, mTransportType, requestType);
                sendRequestNetworkCompleteMsg(msg, success, mTransportType, requestType, cause);
            }
            messageList.clear();
        }
+28 −22
Original line number Diff line number Diff line
@@ -181,9 +181,12 @@ public class TelephonyNetworkFactory extends NetworkFactory {
                                DcTracker.DATA_COMPLETE_MSG_EXTRA_SUCCESS);
                        int transport = bundle.getInt(
                                DcTracker.DATA_COMPLETE_MSG_EXTRA_TRANSPORT_TYPE);
                        boolean fallback = bundle.getBoolean(
                                DcTracker.DATA_COMPLETE_MSG_EXTRA_HANDOVER_FAILURE_FALLBACK);
                        HandoverParams handoverParams = mPendingHandovers.remove(msg);
                        if (handoverParams != null) {
                            onDataHandoverSetupCompleted(nr, success, transport, handoverParams);
                            onDataHandoverSetupCompleted(nr, success, transport, fallback,
                                    handoverParams);
                        } else {
                            logl("Handover completed but cannot find handover entry!");
                        }
@@ -375,20 +378,22 @@ public class TelephonyNetworkFactory extends NetworkFactory {

        if (!handoverPending) {
            log("No handover request pending. Handover process is now completed");
            handoverParams.callback.onCompleted(true);
            handoverParams.callback.onCompleted(true, false);
        }
    }

    private void onDataHandoverSetupCompleted(NetworkRequest networkRequest, boolean success,
                                              int targetTransport, HandoverParams handoverParams) {
                                              int targetTransport, boolean fallback,
                                              HandoverParams handoverParams) {
        log("onDataHandoverSetupCompleted: " + networkRequest + ", success=" + success
                + ", targetTransport="
                + AccessNetworkConstants.transportTypeToString(targetTransport));

        // At this point, handover setup has been completed on the target transport. No matter
        // succeeded or not, remove the request from the source transport because even the setup
        // failed on target transport, we can retry again there.
                + AccessNetworkConstants.transportTypeToString(targetTransport)
                + ", fallback=" + fallback);

        // At this point, handover setup has been completed on the target transport.
        // If it succeeded, or it failed without falling back to the original transport,
        // we should release the request from the original transport.
        if (!fallback) {
            int originTransport = (targetTransport == AccessNetworkConstants.TRANSPORT_TYPE_WWAN)
                    ? AccessNetworkConstants.TRANSPORT_TYPE_WLAN
                    : AccessNetworkConstants.TRANSPORT_TYPE_WWAN;
@@ -401,8 +406,9 @@ public class TelephonyNetworkFactory extends NetworkFactory {
                    : DcTracker.RELEASE_TYPE_NORMAL;
            releaseNetworkInternal(networkRequest, releaseType, originTransport);
            mNetworkRequests.put(networkRequest, targetTransport);
        }

        handoverParams.callback.onCompleted(success);
        handoverParams.callback.onCompleted(success, fallback);
    }

    protected void log(String s) {
+30 −23
Original line number Diff line number Diff line
@@ -199,8 +199,10 @@ public class TransportManager extends Handler {
             * Called when handover is completed.
             *
             * @param success {@true} if handover succeeded, otherwise failed.
             * @param fallback {@true} if handover failed, the data connection fallback to the
             * original transport
             */
            void onCompleted(boolean success);
            void onCompleted(boolean success, boolean fallback);
        }

        public final @ApnType int apnType;
@@ -347,7 +349,8 @@ public class TransportManager extends Handler {
                            + AccessNetworkConstants.transportTypeToString(targetTransport));
                    mPendingHandoverApns.put(networks.apnType, targetTransport);
                    mHandoverNeededEventRegistrants.notifyResult(
                            new HandoverParams(networks.apnType, targetTransport, success -> {
                            new HandoverParams(networks.apnType, targetTransport,
                                    (success, fallback) -> {
                                        // The callback for handover completed.
                                        if (success) {
                                            logl("Handover succeeded.");
@@ -356,15 +359,19 @@ public class TransportManager extends Handler {
                                                    + ApnSetting.getApnTypeString(networks.apnType)
                                                    + " handover to "
                                                    + AccessNetworkConstants.transportTypeToString(
                                                    targetTransport) + " failed.");
                                                    targetTransport) + " failed."
                                                    + ", fallback=" + fallback);
                                        }
                                // No matter succeeded or not, we need to set the current transport
                                // to the new one. If failed, there will be retry afterwards anyway.
                                        if (success || !fallback) {
                                            // If handover succeeds or failed without falling back
                                            // to the original transport, we should move to the new
                                            // transport (even if it is failed).
                                            setCurrentTransport(networks.apnType, targetTransport);
                                        }
                                        mPendingHandoverApns.delete(networks.apnType);

                                // If there are still pending available network changes, we need to
                                // process the rest.
                                        // If there are still pending available network changes, we
                                        // need to process the rest.
                                        if (mAvailableNetworksList.size() > 0) {
                                            sendEmptyMessage(EVENT_UPDATE_AVAILABLE_NETWORKS);
                                        }
+3 −3
Original line number Diff line number Diff line
@@ -129,7 +129,7 @@ public class TransportManagerTest extends TelephonyTest {
        assertEquals(AccessNetworkConstants.TRANSPORT_TYPE_WLAN, params.targetTransport);

        // Notify handover succeeded.
        params.callback.onCompleted(true);
        params.callback.onCompleted(true, false);
        assertEquals(AccessNetworkConstants.TRANSPORT_TYPE_WLAN,
                mTransportManager.getCurrentTransport(ApnSetting.TYPE_IMS));

@@ -158,7 +158,7 @@ public class TransportManagerTest extends TelephonyTest {
        assertEquals(AccessNetworkConstants.TRANSPORT_TYPE_WLAN,
                mTransportManager.getCurrentTransport(ApnSetting.TYPE_IMS));
        // Notify handover succeeded.
        params.callback.onCompleted(true);
        params.callback.onCompleted(true, false);
        assertEquals(AccessNetworkConstants.TRANSPORT_TYPE_WWAN,
                mTransportManager.getCurrentTransport(ApnSetting.TYPE_IMS));
    }
@@ -256,7 +256,7 @@ public class TransportManagerTest extends TelephonyTest {
        assertEquals(1, listQueue.size());

        // Notify handover succeeded.
        params.callback.onCompleted(true);
        params.callback.onCompleted(true, false);
        assertEquals(AccessNetworkConstants.TRANSPORT_TYPE_WLAN,
                mTransportManager.getCurrentTransport(ApnSetting.TYPE_IMS));
        waitForMs(100);