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

Commit dbeef141 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
Merged-In: I60401a1500ee1eed404f76020a648936784981a2
Change-Id: I60401a1500ee1eed404f76020a648936784981a2
(cherry picked from commit 6e19653d)
parent 3482bc94
Loading
Loading
Loading
Loading
+1 −1
Original line number Original line Diff line number Diff line
@@ -477,7 +477,7 @@ public class AccessNetworksManager extends Handler {
            pw.println("APN type "
            pw.println("APN type "
                    + ApnSetting.getApnTypeStringInternal(mAvailableNetworks.keyAt(i))
                    + ApnSetting.getApnTypeStringInternal(mAvailableNetworks.keyAt(i))
                    + ": [" + Arrays.stream(mAvailableNetworks.valueAt(i))
                    + ": [" + Arrays.stream(mAvailableNetworks.valueAt(i))
                    .mapToObj(type -> AccessNetworkType.toString(type))
                    .mapToObj(AccessNetworkType::toString)
                    .collect(Collectors.joining(",")) + "]");
                    .collect(Collectors.joining(",")) + "]");
        }
        }
        pw.decreaseIndent();
        pw.decreaseIndent();
+27 −15
Original line number Original line Diff line number Diff line
@@ -50,12 +50,12 @@ public class DataConnectionReasons {
    public String toString() {
    public String toString() {
        StringBuilder reasonStr = new StringBuilder();
        StringBuilder reasonStr = new StringBuilder();
        if (mDataDisallowedReasonSet.size() > 0) {
        if (mDataDisallowedReasonSet.size() > 0) {
            reasonStr.append("Data disallowed, reasons:");
            reasonStr.append("Data disallowed reasons:");
            for (DataDisallowedReasonType reason : mDataDisallowedReasonSet) {
            for (DataDisallowedReasonType reason : mDataDisallowedReasonSet) {
                reasonStr.append(" ").append(reason);
                reasonStr.append(" ").append(reason);
            }
            }
        } else {
        } else {
            reasonStr.append("Data allowed, reason:");
            reasonStr.append("Data allowed reason:");
            reasonStr.append(" ").append(mDataAllowedReason);
            reasonStr.append(" ").append(mDataAllowedReason);
        }
        }
        return reasonStr.toString();
        return reasonStr.toString();
@@ -100,9 +100,13 @@ public class DataConnectionReasons {
    // Disallowed reasons. There could be multiple reasons if data connection is not allowed.
    // Disallowed reasons. There could be multiple reasons if data connection is not allowed.
    public enum DataDisallowedReasonType {
    public enum DataDisallowedReasonType {
        // Soft failure reasons. Normally the reasons from users or policy settings.
        // 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.
        // Data is disabled by the user or policy.
        DEFAULT_DATA_UNSELECTED(false),     // Default data not selected.
        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.
        // Belows are all hard failure reasons.
        NOT_ATTACHED(true),
        NOT_ATTACHED(true),
@@ -113,19 +117,27 @@ public class DataConnectionReasons {
        UNDESIRED_POWER_STATE(true),
        UNDESIRED_POWER_STATE(true),
        INTERNAL_DATA_DISABLED(true),
        INTERNAL_DATA_DISABLED(true),
        RADIO_DISABLED_BY_CARRIER(true),
        RADIO_DISABLED_BY_CARRIER(true),
        APN_NOT_CONNECTABLE(true),  // Not in the right state for data call setup.
        // Not in the right state for data call setup.
        DATA_IS_CONNECTING(true),   // Data is in connecting state. No need to send another setup
        APN_NOT_CONNECTABLE(true),
                                    // request.
        // Data is in connecting state. No need to send another setup request.
        DATA_IS_DISCONNECTING(true),    // Data is being disconnected. Telephony will retry after
        DATA_IS_CONNECTING(true),
                                        // disconnected.
        // Data is being disconnected. Telephony will retry after disconnected.
        DATA_ALREADY_CONNECTED(true),   // Data is already connected. No need to setup data again.
        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),
        ON_IWLAN(true),
        // certain APNs are only allowed when the device is camped on NR.
        NOT_ON_NR(true),
        NOT_ON_NR(true),
        // Data is not allowed while device is in emergency callback mode.
        IN_ECBM(true),
        IN_ECBM(true),
        ON_OTHER_TRANSPORT(true),   // When data retry occurs, the given APN type's preferred
        // The given APN type's preferred transport has switched.
                                    // transport might be already changed. In this case we
        ON_OTHER_TRANSPORT(true),
                                    // should disallow data retry.
        // Underlying data service is not bound.
        DATA_SERVICE_NOT_READY(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;
        private boolean mIsHardReason;


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


        if (apnContext != null) {
        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
            // 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
            // allow the data setup. The only exception is the handover case, where we setup
            // handover data connection before switching the transport.
            // handover data connection before switching the transport.
@@ -1578,6 +1591,15 @@ public class DcTracker extends Handler {
        String logStr = "trySetupData for APN type " + apnContext.getApnType() + ", reason: "
        String logStr = "trySetupData for APN type " + apnContext.getApnType() + ", reason: "
                + apnContext.getReason() + ", requestType=" + requestTypeToString(requestType)
                + apnContext.getReason() + ", requestType=" + requestTypeToString(requestType)
                + ". " + dataConnectionReasons.toString();
                + ". " + 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);
        if (DBG) log(logStr);
        apnContext.requestLog(logStr);
        apnContext.requestLog(logStr);
        if (!isDataAllowed) {
        if (!isDataAllowed) {
+74 −12
Original line number Original line Diff line number Diff line
@@ -26,6 +26,7 @@ import android.os.RegistrantList;
import android.os.SystemProperties;
import android.os.SystemProperties;
import android.telephony.AccessNetworkConstants;
import android.telephony.AccessNetworkConstants;
import android.telephony.AccessNetworkConstants.AccessNetworkType;
import android.telephony.AccessNetworkConstants.AccessNetworkType;
import android.telephony.AccessNetworkConstants.TransportType;
import android.telephony.Annotation.ApnType;
import android.telephony.Annotation.ApnType;
import android.telephony.CarrierConfigManager;
import android.telephony.CarrierConfigManager;
import android.telephony.data.ApnSetting;
import android.telephony.data.ApnSetting;
@@ -45,9 +46,10 @@ import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayDeque;
import java.util.Arrays;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Iterator;
import java.util.List;
import java.util.List;
import java.util.Map;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentHashMap;
@@ -168,7 +170,7 @@ public class TransportManager extends Handler {
    /**
    /**
     * The queued available networks list.
     * 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
     * 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<>();
        mCurrentTransports = new ConcurrentHashMap<>();
        mPendingHandoverApns = new SparseIntArray();
        mPendingHandoverApns = new SparseIntArray();
        mHandoverNeededEventRegistrants = new RegistrantList();
        mHandoverNeededEventRegistrants = new RegistrantList();
        mAvailableNetworksList = new LinkedList<>();
        mQueuedNetworksList = new ArrayDeque<>();
        mLogTag = TransportManager.class.getSimpleName() + "-" + mPhone.getPhoneId();
        mLogTag = TransportManager.class.getSimpleName() + "-" + mPhone.getPhoneId();


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


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


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


                                        // If there are still pending available network changes, we
                                        // If there are still pending available network changes, we
                                        // need to process the rest.
                                        // need to process the rest.
                                        if (mAvailableNetworksList.size() > 0) {
                                        if (mQueuedNetworksList.size() > 0) {
                                            sendEmptyMessage(EVENT_UPDATE_AVAILABLE_NETWORKS);
                                            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 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);
            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
     * Dump the state of transport manager
     *
     *
@@ -498,12 +545,27 @@ public class TransportManager extends Handler {
        pw.println(mLogTag);
        pw.println(mLogTag);
        pw.increaseIndent();
        pw.increaseIndent();
        pw.println("mAvailableTransports=[" + Arrays.stream(mAvailableTransports)
        pw.println("mAvailableTransports=[" + Arrays.stream(mAvailableTransports)
                .mapToObj(type -> AccessNetworkConstants.transportTypeToString(type))
                .mapToObj(AccessNetworkConstants::transportTypeToString)
                .collect(Collectors.joining(",")) + "]");
                .collect(Collectors.joining(",")) + "]");
        pw.println("mCurrentAvailableNetworks=" + mCurrentAvailableNetworks);
        pw.println("mCurrentAvailableNetworks=");
        pw.println("mAvailableNetworksList=" + mAvailableNetworksList);
        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("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("isInLegacy=" + isInLegacyMode());
        pw.println("IWLAN operation mode="
        pw.println("IWLAN operation mode="
                + SystemProperties.get(SYSTEM_PROPERTIES_IWLAN_OPERATION_MODE));
                + SystemProperties.get(SYSTEM_PROPERTIES_IWLAN_OPERATION_MODE));
+2 −0
Original line number Original line Diff line number Diff line
@@ -684,6 +684,8 @@ public class DcTrackerTest extends TelephonyTest {
        Settings.Global.putInt(mContext.getContentResolver(),
        Settings.Global.putInt(mContext.getContentResolver(),
                Settings.Global.DATA_STALL_RECOVERY_ON_BAD_NETWORK, 0);
                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(PhoneConstants.State.IDLE).when(mCT).getState();
        doReturn(true).when(mSST).getDesiredPowerState();
        doReturn(true).when(mSST).getDesiredPowerState();
        doReturn(true).when(mSST).getPowerStateFromCarrier();
        doReturn(true).when(mSST).getPowerStateFromCarrier();
Loading