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

Commit 6e19653d authored by Jack Yu's avatar Jack Yu
Browse files

Disallow data when QNS switched the preference

When the preference has switched to another transport, do
not allow data setup. This avoid the case that data service
keeps asking telephony to retry while QNS already switched
the preference to another transport.

Test: Manual
Fix: 182899920, 175399007
Change-Id: I60401a1500ee1eed404f76020a648936784981a2
parent 29ae3dab
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -41,10 +41,10 @@ import android.telephony.data.IQualifiedNetworksServiceCallback;
import android.telephony.data.QualifiedNetworksService;
import android.telephony.data.ThrottleStatus;
import android.text.TextUtils;
import android.util.IndentingPrintWriter;
import android.util.SparseArray;

import com.android.internal.telephony.Phone;
import com.android.internal.util.IndentingPrintWriter;
import com.android.telephony.Rlog;

import java.io.FileDescriptor;
@@ -477,7 +477,7 @@ public class AccessNetworksManager extends Handler {
            pw.println("APN type "
                    + ApnSetting.getApnTypeStringInternal(mAvailableNetworks.keyAt(i))
                    + ": [" + Arrays.stream(mAvailableNetworks.valueAt(i))
                    .mapToObj(type -> AccessNetworkType.toString(type))
                    .mapToObj(AccessNetworkType::toString)
                    .collect(Collectors.joining(",")) + "]");
        }
        pw.decreaseIndent();
+27 −15
Original line number Diff line number Diff line
@@ -50,12 +50,12 @@ public class DataConnectionReasons {
    public String toString() {
        StringBuilder reasonStr = new StringBuilder();
        if (mDataDisallowedReasonSet.size() > 0) {
            reasonStr.append("Data disallowed, reasons:");
            reasonStr.append("Data disallowed reasons:");
            for (DataDisallowedReasonType reason : mDataDisallowedReasonSet) {
                reasonStr.append(" ").append(reason);
            }
        } else {
            reasonStr.append("Data allowed, reason:");
            reasonStr.append("Data allowed reason:");
            reasonStr.append(" ").append(mDataAllowedReason);
        }
        return reasonStr.toString();
@@ -100,9 +100,13 @@ public class DataConnectionReasons {
    // Disallowed reasons. There could be multiple reasons if data connection is not allowed.
    public enum DataDisallowedReasonType {
        // Soft failure reasons. Normally the reasons from users or policy settings.
        DATA_DISABLED(false),               // Data is disabled by the user or policy.
        ROAMING_DISABLED(false),            // Data roaming is disabled by the user.
        DEFAULT_DATA_UNSELECTED(false),     // Default data not selected.

        // Data is disabled by the user or policy.
        DATA_DISABLED(false),
        // Data roaming is disabled by the user.
        ROAMING_DISABLED(false),
        // Default data not selected.
        DEFAULT_DATA_UNSELECTED(false),

        // Belows are all hard failure reasons.
        NOT_ATTACHED(true),
@@ -113,19 +117,27 @@ public class DataConnectionReasons {
        UNDESIRED_POWER_STATE(true),
        INTERNAL_DATA_DISABLED(true),
        RADIO_DISABLED_BY_CARRIER(true),
        APN_NOT_CONNECTABLE(true),  // Not in the right state for data call setup.
        DATA_IS_CONNECTING(true),   // Data is in connecting state. No need to send another setup
                                    // request.
        DATA_IS_DISCONNECTING(true),    // Data is being disconnected. Telephony will retry after
                                        // disconnected.
        DATA_ALREADY_CONNECTED(true),   // Data is already connected. No need to setup data again.
        // Not in the right state for data call setup.
        APN_NOT_CONNECTABLE(true),
        // Data is in connecting state. No need to send another setup request.
        DATA_IS_CONNECTING(true),
        // Data is being disconnected. Telephony will retry after disconnected.
        DATA_IS_DISCONNECTING(true),
        // Data is already connected. No need to setup data again.
        DATA_ALREADY_CONNECTED(true),
        // certain APNs are not allowed on IWLAN in legacy mode.
        ON_IWLAN(true),
        // certain APNs are only allowed when the device is camped on NR.
        NOT_ON_NR(true),
        // Data is not allowed while device is in emergency callback mode.
        IN_ECBM(true),
        ON_OTHER_TRANSPORT(true),   // When data retry occurs, the given APN type's preferred
                                    // transport might be already changed. In this case we
                                    // should disallow data retry.
        DATA_SERVICE_NOT_READY(true);   // Underlying data service is not bound.
        // The given APN type's preferred transport has switched.
        ON_OTHER_TRANSPORT(true),
        // Underlying data service is not bound.
        DATA_SERVICE_NOT_READY(true),
        // Qualified networks service does not allow certain types of APN brought up on either
        // cellular or IWLAN.
        DISABLED_BY_QNS(true);

        private boolean mIsHardReason;

+22 −0
Original line number Diff line number Diff line
@@ -1419,6 +1419,19 @@ public class DcTracker extends Handler {
        }

        if (apnContext != null) {
            if (mPhone.getTransportManager().getPreferredTransport(
                    apnContext.getApnTypeBitmask())
                    == AccessNetworkConstants.TRANSPORT_TYPE_INVALID) {
                // If QNS explicitly specified this APN type is not allowed on either cellular or
                // IWLAN, we should not allow data setup.
                reasons.add(DataDisallowedReasonType.DISABLED_BY_QNS);
            } else if (mTransportType != mPhone.getTransportManager().getPreferredTransport(
                    apnContext.getApnTypeBitmask())) {
                // If the latest preference has already switched to other transport, we should not
                // allow data setup.
                reasons.add(DataDisallowedReasonType.ON_OTHER_TRANSPORT);
            }

            // If the transport has been already switched to the other transport, we should not
            // allow the data setup. The only exception is the handover case, where we setup
            // handover data connection before switching the transport.
@@ -1551,6 +1564,15 @@ public class DcTracker extends Handler {
        String logStr = "trySetupData for APN type " + apnContext.getApnType() + ", reason: "
                + apnContext.getReason() + ", requestType=" + requestTypeToString(requestType)
                + ". " + dataConnectionReasons.toString();
        if (dataConnectionReasons.contains(DataDisallowedReasonType.DISABLED_BY_QNS)
                || dataConnectionReasons.contains(DataDisallowedReasonType.ON_OTHER_TRANSPORT)) {
            logStr += ", current transport=" + AccessNetworkConstants.transportTypeToString(
                    mPhone.getTransportManager().getCurrentTransport(
                            apnContext.getApnTypeBitmask()));
            logStr += ", preferred transport=" + AccessNetworkConstants.transportTypeToString(
                    mPhone.getTransportManager().getPreferredTransport(
                            apnContext.getApnTypeBitmask()));
        }
        if (DBG) log(logStr);
        apnContext.requestLog(logStr);
        if (isDataAllowed) {
+75 −13
Original line number Diff line number Diff line
@@ -26,9 +26,11 @@ import android.os.RegistrantList;
import android.os.SystemProperties;
import android.telephony.AccessNetworkConstants;
import android.telephony.AccessNetworkConstants.AccessNetworkType;
import android.telephony.AccessNetworkConstants.TransportType;
import android.telephony.Annotation.ApnType;
import android.telephony.CarrierConfigManager;
import android.telephony.data.ApnSetting;
import android.util.IndentingPrintWriter;
import android.util.LocalLog;
import android.util.SparseArray;
import android.util.SparseIntArray;
@@ -38,16 +40,16 @@ import com.android.internal.telephony.Phone;
import com.android.internal.telephony.RIL;
import com.android.internal.telephony.dataconnection.AccessNetworksManager.QualifiedNetworks;
import com.android.internal.telephony.util.ArrayUtils;
import com.android.internal.util.IndentingPrintWriter;
import com.android.telephony.Rlog;

import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayDeque;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@@ -168,7 +170,7 @@ public class TransportManager extends Handler {
    /**
     * The queued available networks list.
     */
    private final LinkedList<List<QualifiedNetworks>> mAvailableNetworksList;
    private final ArrayDeque<List<QualifiedNetworks>> mQueuedNetworksList;

    /**
     * The current transport of the APN type. The key is the APN type, and the value is the
@@ -225,7 +227,7 @@ public class TransportManager extends Handler {
        mCurrentTransports = new ConcurrentHashMap<>();
        mPendingHandoverApns = new SparseIntArray();
        mHandoverNeededEventRegistrants = new RegistrantList();
        mAvailableNetworksList = new LinkedList<>();
        mQueuedNetworksList = new ArrayDeque<>();
        mLogTag = TransportManager.class.getSimpleName() + "-" + mPhone.getPhoneId();

        if (isInLegacyMode()) {
@@ -249,7 +251,7 @@ public class TransportManager extends Handler {
            case EVENT_QUALIFIED_NETWORKS_CHANGED:
                AsyncResult ar = (AsyncResult) msg.obj;
                List<QualifiedNetworks> networks = (List<QualifiedNetworks>) ar.result;
                mAvailableNetworksList.add(networks);
                mQueuedNetworksList.add(networks);
                sendEmptyMessage(EVENT_UPDATE_AVAILABLE_NETWORKS);
                break;
            case EVENT_UPDATE_AVAILABLE_NETWORKS:
@@ -333,12 +335,12 @@ public class TransportManager extends Handler {
            return;
        }

        if (mAvailableNetworksList.size() == 0) {
        if (mQueuedNetworksList.size() == 0) {
            log("Nothing in the available network list queue.");
            return;
        }

        List<QualifiedNetworks> networksList = mAvailableNetworksList.remove();
        List<QualifiedNetworks> networksList = mQueuedNetworksList.remove();
        logl("updateAvailableNetworks: " + networksList);
        for (QualifiedNetworks networks : networksList) {
            if (areNetworksValid(networks)) {
@@ -379,7 +381,7 @@ public class TransportManager extends Handler {

                                        // If there are still pending available network changes, we
                                        // need to process the rest.
                                        if (mAvailableNetworksList.size() > 0) {
                                        if (mQueuedNetworksList.size() > 0) {
                                            sendEmptyMessage(EVENT_UPDATE_AVAILABLE_NETWORKS);
                                        }
                                    }));
@@ -391,7 +393,7 @@ public class TransportManager extends Handler {
        }

        // If there are still pending available network changes, we need to process the rest.
        if (mAvailableNetworksList.size() > 0) {
        if (mQueuedNetworksList.size() > 0) {
            sendEmptyMessage(EVENT_UPDATE_AVAILABLE_NETWORKS);
        }
    }
@@ -486,6 +488,51 @@ public class TransportManager extends Handler {
        }
    }

    /**
     * Get the latest preferred transport. Note that the current transport only changed after
     * handover is completed, and there might be queued update network requests not processed yet.
     * This method is used to get the latest preference sent from qualified networks service.
     *
     * @param apnType APN type
     * @return The preferred transport. {@link AccessNetworkConstants#TRANSPORT_TYPE_INVALID} if
     * unknown, unavailable, or QNS explicitly specifies data connection of the APN type should not
     * be brought up on either cellular or IWLAN.
     */
    public @TransportType int getPreferredTransport(@ApnType int apnType) {
        // Since the latest updates from QNS is stored at the end of the queue, so if we want to
        // check what's the latest, we should iterate the queue reversely.
        Iterator<List<QualifiedNetworks>> it = mQueuedNetworksList.descendingIterator();
        while (it.hasNext()) {
            List<QualifiedNetworks> networksList = it.next();
            for (QualifiedNetworks networks : networksList) {
                if (networks.apnType == apnType) {
                    if (networks.qualifiedNetworks.length > 0) {
                        return ACCESS_NETWORK_TRANSPORT_TYPE_MAP.get(networks.qualifiedNetworks[0]);
                    }
                    // This is the case that QNS explicitly specifies no data allowed on neither
                    // cellular nor IWLAN.
                    return AccessNetworkConstants.TRANSPORT_TYPE_INVALID;
                }
            }
        }

        // if not found in the queue, see if it's in the current available networks.
        int[] currentNetworkList = mCurrentAvailableNetworks.get(apnType);
        if (currentNetworkList != null) {
            if (currentNetworkList.length > 0) {
                return ACCESS_NETWORK_TRANSPORT_TYPE_MAP.get(currentNetworkList[0]);
            }
            // This is the case that QNS explicitly specifies no data allowed on neither
            // cellular nor IWLAN.
            return AccessNetworkConstants.TRANSPORT_TYPE_INVALID;
        }

        // If no input from QNS, for example in legacy mode, the default preferred transport should
        // be cellular.
        return AccessNetworkConstants.TRANSPORT_TYPE_WWAN;
    }


    /**
     * Dump the state of transport manager
     *
@@ -498,12 +545,27 @@ public class TransportManager extends Handler {
        pw.println(mLogTag);
        pw.increaseIndent();
        pw.println("mAvailableTransports=[" + Arrays.stream(mAvailableTransports)
                .mapToObj(type -> AccessNetworkConstants.transportTypeToString(type))
                .mapToObj(AccessNetworkConstants::transportTypeToString)
                .collect(Collectors.joining(",")) + "]");
        pw.println("mCurrentAvailableNetworks=" + mCurrentAvailableNetworks);
        pw.println("mAvailableNetworksList=" + mAvailableNetworksList);
        pw.println("mCurrentAvailableNetworks=");
        pw.increaseIndent();
        for (int i = 0; i < mCurrentAvailableNetworks.size(); i++) {
            pw.println("APN type "
                    + ApnSetting.getApnTypeStringInternal(mCurrentAvailableNetworks.keyAt(i))
                    + ": [" + Arrays.stream(mCurrentAvailableNetworks.valueAt(i))
                    .mapToObj(AccessNetworkType::toString)
                    .collect(Collectors.joining(",")) + "]");
        }
        pw.decreaseIndent();
        pw.println("mQueuedNetworksList=" + mQueuedNetworksList);
        pw.println("mPendingHandoverApns=" + mPendingHandoverApns);
        pw.println("mCurrentTransports=" + mCurrentTransports);
        pw.println("mCurrentTransports=");
        pw.increaseIndent();
        for (Map.Entry<Integer, Integer> entry : mCurrentTransports.entrySet()) {
            pw.println("APN type " + ApnSetting.getApnTypeStringInternal(entry.getKey())
                    + ": " + AccessNetworkConstants.transportTypeToString(entry.getValue()));
        }
        pw.decreaseIndent();
        pw.println("isInLegacy=" + isInLegacyMode());
        pw.println("IWLAN operation mode="
                + SystemProperties.get(SYSTEM_PROPERTIES_IWLAN_OPERATION_MODE));
+2 −0
Original line number Diff line number Diff line
@@ -679,6 +679,8 @@ public class DcTrackerTest extends TelephonyTest {
        Settings.Global.putInt(mContext.getContentResolver(),
                Settings.Global.DATA_STALL_RECOVERY_ON_BAD_NETWORK, 0);

        doReturn(AccessNetworkConstants.TRANSPORT_TYPE_WWAN).when(mTransportManager)
                .getPreferredTransport(anyInt());
        doReturn(PhoneConstants.State.IDLE).when(mCT).getState();
        doReturn(true).when(mSST).getDesiredPowerState();
        doReturn(true).when(mSST).getPowerStateFromCarrier();
Loading