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

Commit b25da6fd authored by Jack Yu's avatar Jack Yu
Browse files

Fixed handover issues

1. If the reported network is unknown, ignore it.
2. If receiving handover requests back to back, gracefully
   ignore the 2nd one without changing the transport type
   immediately. Transport manager now will be notified the
   handover result.
3. Preserved the network agent before issuing handover request.
   This prevents some races that source data connection
   disappeared before handover is completed.
4. If no live data connection but there are already networks
   there, directly move the network requests to the new transport.
5. Do not notify connectivity service data disconnected if the data
   is being handovered to the new transport.
6. For auto attach, it should be only for cellular.
7. Retry handover setup when failed.
8. Immediately remove the network request from the source transport
   once handover is completed, whether succeeded or not. The reason
   is that qualified network service has reported the current transport.
   So even setup is failed, we should still stick on that transport.
   The setup can be retried later.

Test: Telephony sanity tests
Bug: 130366327
Bug: 130312660
Bug: 130538538
Bug: 130743820

Change-Id: Ie927bbfd7972b992a33abec7a3899d95a74b4f49
parent 0ea02d7f
Loading
Loading
Loading
Loading
+5 −4
Original line number Diff line number Diff line
@@ -214,13 +214,14 @@ public class NetworkRegistrationManager extends Handler {
    private class NetworkRegStateCallback extends INetworkServiceCallback.Stub {
        @Override
        public void onRequestNetworkRegistrationInfoComplete(
                int result, NetworkRegistrationInfo state) {
            logd("onRequestNetworkRegistrationInfoComplete result "
                    + result + " state " + state);
                int result, NetworkRegistrationInfo info) {
            logd("onRequestNetworkRegistrationInfoComplete result: "
                    + result + ", info: " + info);
            Message onCompleteMessage = mCallbackTable.remove(this);
            if (onCompleteMessage != null) {
                onCompleteMessage.arg1 = result;
                onCompleteMessage.obj = new AsyncResult(onCompleteMessage.obj, state, null);
                onCompleteMessage.obj = new AsyncResult(onCompleteMessage.obj,
                        new NetworkRegistrationInfo(info), null);
                onCompleteMessage.sendToTarget();
            } else {
                loge("onCompleteMessage is null");
+15 −19
Original line number Diff line number Diff line
@@ -1520,9 +1520,7 @@ public class ServiceStateTracker extends Handler {
                    boolean hasChanged =
                            updateNrFrequencyRangeFromPhysicalChannelConfigs(list, mSS);
                    hasChanged |= updateNrStateFromPhysicalChannelConfigs(
                            list,
                            mSS.getNetworkRegistrationInfo(NetworkRegistrationInfo.DOMAIN_PS,
                                    AccessNetworkType.EUTRAN));
                            list, mSS);

                    // Notify NR frequency, NR connection status or bandwidths changed.
                    if (hasChanged
@@ -1943,9 +1941,10 @@ public class ServiceStateTracker extends Handler {
    }

    private boolean updateNrStateFromPhysicalChannelConfigs(
            List<PhysicalChannelConfig> configs, NetworkRegistrationInfo regState) {

        if (regState == null || configs == null) return false;
            List<PhysicalChannelConfig> configs, ServiceState ss) {
        NetworkRegistrationInfo regInfo = ss.getNetworkRegistrationInfo(
                NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
        if (regInfo == null || configs == null) return false;

        boolean hasNrSecondaryServingCell = false;
        for (PhysicalChannelConfig config : configs) {
@@ -1956,19 +1955,20 @@ public class ServiceStateTracker extends Handler {
            }
        }

        int newNrState = regState.getNrState();
        int newNrState = regInfo.getNrState();
        if (hasNrSecondaryServingCell) {
            if (regState.getNrState() == NetworkRegistrationInfo.NR_STATE_NOT_RESTRICTED) {
            if (regInfo.getNrState() == NetworkRegistrationInfo.NR_STATE_NOT_RESTRICTED) {
                newNrState = NetworkRegistrationInfo.NR_STATE_CONNECTED;
            }
        } else {
            if (regState.getNrState() == NetworkRegistrationInfo.NR_STATE_CONNECTED) {
            if (regInfo.getNrState() == NetworkRegistrationInfo.NR_STATE_CONNECTED) {
                newNrState = NetworkRegistrationInfo.NR_STATE_NOT_RESTRICTED;
            }
        }

        boolean hasChanged = newNrState != regState.getNrState();
        regState.setNrState(newNrState);
        boolean hasChanged = newNrState != regInfo.getNrState();
        regInfo.setNrState(newNrState);
        ss.addNetworkRegistrationInfo(regInfo);
        return hasChanged;
    }

@@ -2000,8 +2000,6 @@ public class ServiceStateTracker extends Handler {
            // If the device is not camped on IWLAN, then we use cellular PS registration state
            // to compute reg state and rat.
            int regState = wwanPsRegState.getRegistrationState();
            int dataRat = ServiceState.networkTypeToRilRadioTechnology(
                    wwanPsRegState.getAccessNetworkTechnology());
            serviceState.setDataRegState(regCodeToServiceState(regState));
        }
        if (DBG) {
@@ -2083,8 +2081,7 @@ public class ServiceStateTracker extends Handler {
                mNewCellIdentity = networkRegState.getCellIdentity();

                if (DBG) {
                    log("handlPollVoiceRegResultMessage: regState=" + registrationState
                            + " radioTechnology=" + newVoiceRat);
                    log("handlePollStateResultMessage: CS cellular. " + networkRegState);
                }
                break;
            }
@@ -2094,7 +2091,7 @@ public class ServiceStateTracker extends Handler {
                mNewSS.addNetworkRegistrationInfo(networkRegState);

                if (DBG) {
                    log("handlPollStateResultMessage: PS IWLAN. " + networkRegState);
                    log("handlePollStateResultMessage: PS IWLAN. " + networkRegState);
                }
                break;
            }
@@ -2110,7 +2107,7 @@ public class ServiceStateTracker extends Handler {
                        networkRegState.getAccessNetworkTechnology());

                if (DBG) {
                    log("handlPollStateResultMessage: PS cellular. " + networkRegState);
                    log("handlePollStateResultMessage: PS cellular. " + networkRegState);
                }

                // When we receive OOS reset the PhyChanConfig list so that non-return-to-idle
@@ -2120,8 +2117,7 @@ public class ServiceStateTracker extends Handler {
                    mLastPhysicalChannelConfigList = null;
                    updateNrFrequencyRangeFromPhysicalChannelConfigs(null, mNewSS);
                }
                updateNrStateFromPhysicalChannelConfigs(
                        mLastPhysicalChannelConfigList, networkRegState);
                updateNrStateFromPhysicalChannelConfigs(mLastPhysicalChannelConfigList, mNewSS);
                setPhyCellInfoFromCellIdentity(mNewSS, networkRegState.getCellIdentity());

                if (mPhone.isPhoneTypeGsm()) {
+79 −33
Original line number Diff line number Diff line
@@ -19,6 +19,8 @@ package com.android.internal.telephony.dataconnection;
import static android.net.NetworkPolicyManager.OVERRIDE_CONGESTED;
import static android.net.NetworkPolicyManager.OVERRIDE_UNMETERED;

import android.annotation.IntDef;
import android.annotation.Nullable;
import android.app.PendingIntent;
import android.net.ConnectivityManager;
import android.net.KeepalivePacketData;
@@ -81,6 +83,8 @@ import com.android.internal.util.StateMachine;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
@@ -112,6 +116,32 @@ public class DataConnection extends StateMachine {
    private static final String RAT_NAME_5G = "nr";
    private static final String RAT_NAME_EVDO = "evdo";

    /**
     * The data connection is not being or been handovered. Note this is the state for the source
     * data connection, not destination data connection
     */
    private static final int HANDOVER_STATE_IDLE = 1;

    /**
     * The data connection is being handovered. Note this is the state for the source
     * data connection, not destination data connection.
     */
    private static final int HANDOVER_STATE_BEING_TRANSFERRED = 2;

    /**
     * The data connection is already handovered. Note this is the state for the source
     * data connection, not destination data connection.
     */
    private static final int HANDOVER_STATE_COMPLETED = 3;

    /** @hide */
    @Retention(RetentionPolicy.SOURCE)
    @IntDef(prefix = {"HANDOVER_STATE_"}, value = {
            HANDOVER_STATE_IDLE,
            HANDOVER_STATE_BEING_TRANSFERRED,
            HANDOVER_STATE_COMPLETED})
    public @interface HandoverState {}

    // The data connection providing default Internet connection will have a higher score of 50.
    // Other connections will have a slightly lower score of 45. The intention is other connections
    // will not cause ConnectivityService to tear down default internet connection. For example,
@@ -223,16 +253,23 @@ public class DataConnection extends StateMachine {
    private int mRilRat = Integer.MAX_VALUE;
    private int mDataRegState = Integer.MAX_VALUE;
    private NetworkInfo mNetworkInfo;

    /** The corresponding network agent for this data connection. */
    private DcNetworkAgent mNetworkAgent;

    /**
     * The network agent from handover source data connection. This is the potential network agent
     * that will be transferred here after handover completed.
     */
    private DcNetworkAgent mHandoverSourceNetworkAgent;

    private int mDisabledApnTypeBitMask = 0;

    int mTag;
    public int mCid;
    /**
     * Indicate this data connection has been transferred to the other transport type during
     * IWLAN and WWAN handover.
     */
    private boolean mHasTransferred;

    @HandoverState
    private int mHandoverState;
    private final Map<ApnContext, ConnectionParams> mApnContexts = new ConcurrentHashMap<>();
    PendingIntent mReconnectIntent = null;

@@ -367,7 +404,7 @@ public class DataConnection extends StateMachine {
    }

    boolean hasBeenTransferred() {
        return mHasTransferred;
        return mHandoverState == HANDOVER_STATE_COMPLETED;
    }

    int getCid() {
@@ -636,6 +673,11 @@ public class DataConnection extends StateMachine {
            }

            linkProperties = dc.getLinkProperties();
            // Preserve the potential network agent from the source data connection. The ownership
            // is not transferred at this moment.
            mHandoverSourceNetworkAgent = dc.getNetworkAgent();
            log("Get the handover source network agent: " + mHandoverSourceNetworkAgent);
            dc.setHandoverState(HANDOVER_STATE_BEING_TRANSFERRED);
            if (linkProperties == null) {
                loge("connect: Can't find link properties of handover data connection. dc="
                        + dc);
@@ -1613,6 +1655,9 @@ public class DataConnection extends StateMachine {
                    mApnSetting != null ? (long) mApnSetting.getApnTypeBitmask() : 0L,
                    mApnSetting != null
                        ? mApnSetting.canHandleType(ApnSetting.TYPE_DEFAULT) : false);
            if (mHandoverState == HANDOVER_STATE_BEING_TRANSFERRED) {
                mHandoverState = HANDOVER_STATE_COMPLETED;
            }

            if (mConnectionParams != null) {
                if (DBG) {
@@ -1710,7 +1755,7 @@ public class DataConnection extends StateMachine {
                    mApnSetting != null ? (long) mApnSetting.getApnTypeBitmask() : 0L,
                    mApnSetting != null
                        ? mApnSetting.canHandleType(ApnSetting.TYPE_DEFAULT) : false);
            mHasTransferred = false;
            setHandoverState(HANDOVER_STATE_IDLE);
        }
        @Override
        public boolean processMessage(Message msg) {
@@ -1875,23 +1920,25 @@ public class DataConnection extends StateMachine {
                DcTracker dcTracker = mPhone.getDcTracker(getHandoverSourceTransport());
                DataConnection dc = dcTracker.getDataConnectionByApnType(
                        mConnectionParams.mApnContext.getApnType());
                if (dc == null) {
                    loge("Cannot find the data connection for handover.");
                    return;
                }

                // It's possible that the source data connection has been disconnected by the modem
                // already. If not, set its handover state to completed.
                if (dc != null) {
                    // Transfer network agent from the original data connection as soon as the
                    // new handover data connection is connected.
                mNetworkAgent = dc.transferNetworkAgent(DataConnection.this, mTransportType);
                if (mNetworkAgent != null) {
                    log("Transfer the network agent from " + dc.getName()
                            + " successfully.");
                    dc.setHandoverState(HANDOVER_STATE_COMPLETED);
                }

                if (mHandoverSourceNetworkAgent != null) {
                    log("Transfer network agent successfully.");
                    mNetworkAgent = mHandoverSourceNetworkAgent;
                    mNetworkAgent.acquireOwnership(DataConnection.this, mTransportType);
                    mNetworkAgent.sendNetworkCapabilities(getNetworkCapabilities(),
                            DataConnection.this);
                    mNetworkAgent.sendLinkProperties(mLinkProperties, DataConnection.this);
                    mHandoverSourceNetworkAgent = null;
                } else {
                    loge("Failed to get network agent from original data connection. dc="
                            + dc.getName());
                    loge("Failed to get network agent from original data connection");
                    return;
                }
            } else {
                mScore = calculateScore();
@@ -1927,8 +1974,12 @@ public class DataConnection extends StateMachine {
            mPhone.getCallTracker().unregisterForVoiceCallStarted(getHandler());
            mPhone.getCallTracker().unregisterForVoiceCallEnded(getHandler());

            // If the data connection is being handover to other transport, we should not notify
            // disconnected to connectivity service.
            if (mHandoverState != HANDOVER_STATE_BEING_TRANSFERRED) {
                mNetworkInfo.setDetailedState(NetworkInfo.DetailedState.DISCONNECTED,
                        reason, mNetworkInfo.getExtraInfo());
            }

            if (mTransportType == AccessNetworkConstants.TRANSPORT_TYPE_WWAN) {
                mPhone.mCi.unregisterForNattKeepaliveStatus(getHandler());
@@ -2490,22 +2541,16 @@ public class DataConnection extends StateMachine {
        return new ArrayList<>(mApnContexts.keySet());
    }

    /**
     * Transfer the network agent to the other data connection. This is only used for IWLAN
     * data handover.
     *
     * @param dataConnection The new data connection on the other transport after handover.
     * @param transportType The transport after handover.
     *
     * @return Network agent
     */
    public DcNetworkAgent transferNetworkAgent(DataConnection dataConnection,
                                               @TransportType int transportType) {
        mNetworkAgent.acquireOwnership(dataConnection, transportType);
        this.mHasTransferred = true;
    /** Get the network agent of the data connection */
    @Nullable
    DcNetworkAgent getNetworkAgent() {
        return mNetworkAgent;
    }

    void setHandoverState(@HandoverState int state) {
        mHandoverState = state;
    }

    /**
     * @return the string for msg.what as our info.
     */
@@ -2727,6 +2772,7 @@ public class DataConnection extends StateMachine {
        pw.println("mLinkProperties=" + mLinkProperties);
        pw.flush();
        pw.println("mDataRegState=" + mDataRegState);
        pw.println("mHandoverState=" + mHandoverState);
        pw.println("mRilRat=" + mRilRat);
        pw.println("mNetworkCapabilities=" + getNetworkCapabilities());
        pw.println("mCreateTime=" + TimeUtils.logTimeOfDay(mCreateTime));
+20 −12
Original line number Diff line number Diff line
@@ -1462,6 +1462,7 @@ public class DcTracker extends Handler {
                apnContext.setState(DctConstants.State.IDLE);
            }
            int radioTech = getDataRat();
            log("service state=" + mPhone.getServiceState());
            apnContext.setConcurrentVoiceAndDataAllowed(mPhone.getServiceStateTracker()
                    .isConcurrentVoiceAndDataAllowed());
            if (apnContext.getState() == DctConstants.State.IDLE) {
@@ -2188,8 +2189,11 @@ public class DcTracker extends Handler {

    private void onRecordsLoadedOrSubIdChanged() {
        if (DBG) log("onRecordsLoadedOrSubIdChanged: createAllApnList");
        if (mTransportType == AccessNetworkConstants.TRANSPORT_TYPE_WWAN) {
            // Auto attach is for cellular only.
            mAutoAttachOnCreationConfig = mPhone.getContext().getResources()
                    .getBoolean(com.android.internal.R.bool.config_auto_attach_data_on_creation);
        }

        createAllApnList();
        setDataProfilesAsNeeded();
@@ -2795,8 +2799,7 @@ public class DcTracker extends Handler {
                    setRadio(false);
                }
                if (DBG) {
                    log("onDataSetupComplete: SETUP complete type=" + apnContext.getApnType()
                        + ", reason:" + apnContext.getReason());
                    log("onDataSetupComplete: SETUP complete type=" + apnContext.getApnType());
                }
                if (Build.IS_DEBUGGABLE) {
                    // adb shell setprop persist.radio.test.pco [pco_val]
@@ -2867,7 +2870,7 @@ public class DcTracker extends Handler {

        // Check if we need to retry or not.
        // TODO: We should support handover retry in the future.
        if (delay >= 0 && requestType != REQUEST_TYPE_HANDOVER) {
        if (delay >= 0) {
            if (DBG) log("onDataSetupCompleteError: Try next APN. delay = " + delay);
            apnContext.setState(DctConstants.State.RETRYING);
            // Wait a bit before trying the next APN, so that
@@ -3278,16 +3281,17 @@ public class DcTracker extends Handler {
            if (apn.canHandleType(requestedApnTypeBitmask)) {
                if (ServiceState.bitmaskHasTech(apn.getNetworkTypeBitmask(),
                        ServiceState.rilRadioTechnologyToNetworkType(radioTech))) {
                    if (DBG) log("buildWaitingApns: adding apn=" + apn);
                    if (VDBG) log("buildWaitingApns: adding apn=" + apn);
                    apnList.add(apn);
                } else {
                    if (DBG) {
                        log("buildWaitingApns: networkTypeBitmask:"
                                + apn.getNetworkTypeBitmask()
                                + " does not include radioTech:" + radioTech);
                                + " does not include radioTech:"
                                + ServiceState.rilRadioTechnologyToString(radioTech));
                    }
                }
            } else if (DBG) {
            } else if (VDBG) {
                log("buildWaitingApns: couldn't handle requested ApnType="
                        + requestedApnType);
            }
@@ -3378,17 +3382,21 @@ public class DcTracker extends Handler {
        } else {
            mCanSetPreferApn = false;
        }

        if (VDBG) {
            log("getPreferredApn: mRequestedApnType=" + mRequestedApnType + " cursor=" + cursor
                    + " cursor.count=" + ((cursor != null) ? cursor.getCount() : 0));
        }

        if (mCanSetPreferApn && cursor.getCount() > 0) {
            int pos;
            cursor.moveToFirst();
            pos = cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers._ID));
            for(ApnSetting p : mAllApnSettings) {
                log("getPreferredApn: apnSetting=" + p);
                if (p.getId() == pos && p.canHandleType(mRequestedApnType)) {
                    log("getPreferredApn: X found apnSetting" + p);
                    log("getPreferredApn: For APN type "
                            + ApnSetting.getApnTypeString(mRequestedApnType) + " found apnSetting "
                            + p);
                    cursor.close();
                    return p;
                }
+82 −58

File changed.

Preview size limit exceeded, changes collapsed.

Loading