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

Commit 1d2d57d0 authored by Jack Yu's avatar Jack Yu Committed by Sarah Chin
Browse files

Fixed IMS network disconnected when data disabled

When evaluating data network, also check if the not
allowed reasons are soft reasons. If yes, check if
data networks are unmetered or restricted uses.

Also using capabilities instead of APN type when
doing unmetered check.

Test: Manual + atest DataNetworkControllerTest
Fix: 218485054

Change-Id: Ie58c08653b390589764d2ab03c196b400c5345db
Merged-In: Ie58c08653b390589764d2ab03c196b400c5345db
parent 7c7fdda3
Loading
Loading
Loading
Loading
+32 −6
Original line number Diff line number Diff line
@@ -424,17 +424,43 @@ public class DataConfigManager extends Handler {
    }

    /**
     * @return The metered APN types when connected to a home network
     * Get the metered network capabilities.
     *
     * @param isRoaming {@code true} for roaming scenario.
     *
     * @return The metered network capabilities when connected to a home network.
     */
    public @NonNull @ApnType Set<Integer> getMeteredApnTypes() {
        return Collections.unmodifiableSet(mMeteredApnTypes);
    public @NonNull @NetCapability Set<Integer> getMeteredNetworkCapabilities(boolean isRoaming) {
        Set<Integer> meteredApnTypes = isRoaming ? mRoamingMeteredApnTypes : mMeteredApnTypes;
        return meteredApnTypes.stream()
                .map(DataUtils::apnTypeToNetworkCapability)
                .filter(cap -> cap >= 0)
                .collect(Collectors.toUnmodifiableSet());
    }

    /**
     * @return The metered APN types when roaming
     * Check if the network capability metered.
     *
     * @param networkCapability The network capability.
     * @param isRoaming {@code true} for roaming scenario.
     * @return {@code true} if the network capability is metered.
     */
    public @NonNull @ApnType Set<Integer> getMeteredApnTypesWhenRoaming() {
        return Collections.unmodifiableSet(mRoamingMeteredApnTypes);
    public boolean isMeteredCapability(@NetCapability int networkCapability, boolean isRoaming) {
        return getMeteredNetworkCapabilities(isRoaming).contains(networkCapability);
    }

    /**
     * Check if the network capabilities are metered. If one of the capabilities is metered, then
     * the capabilities are metered.
     *
     * @param networkCapabilities The network capabilities.
     * @param isRoaming {@code true} for roaming scenario.
     * @return {@code true} if the capabilities are metered.
     */
    public boolean isAnyMeteredCapability(@NonNull @NetCapability int[] networkCapabilities,
            boolean isRoaming) {
        return Arrays.stream(networkCapabilities).boxed()
                .anyMatch(cap -> isMeteredCapability(cap, isRoaming));
    }

    /**
+3 −3
Original line number Diff line number Diff line
@@ -120,10 +120,10 @@ public class DataEvaluation {
    }

    /**
     * @return {@code true} if the operation is allowed.
     * @return {@code true} if the evaluation contains disallowed reasons.
     */
    public boolean isDataAllowed() {
        return mDataDisallowedReasons.size() == 0;
    public boolean containsDisallowedReasons() {
        return mDataDisallowedReasons.size() != 0;
    }

    /**
+17 −16
Original line number Diff line number Diff line
@@ -1331,18 +1331,12 @@ public class DataNetwork extends StateMachine {
        builder.setSubscriptionIds(Collections.singleton(mSubId));

        ApnSetting apnSetting = mDataProfile.getApnSetting();
        boolean meteredApn = false;

        if (apnSetting != null) {
            for (int apnType : apnSetting.getApnTypes()) {
                if (!(roaming ? mDataConfigManager.getMeteredApnTypesWhenRoaming()
                        : mDataConfigManager.getMeteredApnTypes()).contains(apnType)) {
                    meteredApn = true;
                }
                int cap = DataUtils.apnTypeToNetworkCapability(apnType);
                if (cap >= 0) {
                    builder.addCapability(cap);
                }
            }
            apnSetting.getApnTypes().stream()
                    .map(DataUtils::apnTypeToNetworkCapability)
                    .filter(cap -> cap >= 0)
                    .forEach(builder::addCapability);
        }

        // Extract network capabilities from the traffic descriptor.
@@ -1377,10 +1371,6 @@ public class DataNetwork extends StateMachine {
            }
        }

        // TODO: Support NET_CAPABILITY_NOT_METERED when non-restricted data is for unmetered use
        if (!meteredApn) {
            builder.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
        }
        // TODO: Support NET_CAPABILITY_NOT_RESTRICTED
        if (!mCongested) {
            builder.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED);
@@ -1409,6 +1399,17 @@ public class DataNetwork extends StateMachine {
            builder.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);
        }

        Set<Integer> meteredCapabilities = mDataConfigManager
                .getMeteredNetworkCapabilities(roaming);
        boolean unmeteredNetwork = meteredCapabilities.stream().noneMatch(
                Arrays.stream(builder.build().getCapabilities()).boxed()
                        .collect(Collectors.toSet())::contains);

        // TODO: Support NET_CAPABILITY_NOT_METERED when non-restricted data is for unmetered use
        if (unmeteredNetwork) {
            builder.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
        }

        // Set the bandwidth information.
        builder.setLinkDownstreamBandwidthKbps(mNetworkBandwidth.downlinkBandwidthKbps);
        builder.setLinkUpstreamBandwidthKbps(mNetworkBandwidth.uplinkBandwidthKbps);
@@ -1845,7 +1846,7 @@ public class DataNetwork extends StateMachine {
        }
        logl("tearDownWithCondition: reason=" + tearDownReasonToString(reason) + ", timeout="
                + timeoutMillis + "ms.");
        sendMessageDelayed(EVENT_TEAR_DOWN_NETWORK, timeoutMillis);
        sendMessageDelayed(EVENT_TEAR_DOWN_NETWORK, reason, timeoutMillis);
        return () -> this.tearDown(reason);
    }

+34 −15
Original line number Diff line number Diff line
@@ -1046,7 +1046,7 @@ public class DataNetworkController extends Handler {
        // of them.
        DataEvaluation evaluation = evaluateNetworkRequest(networkRequest,
                DataEvaluationReason.NEW_REQUEST);
        if (evaluation.isDataAllowed()) {
        if (!evaluation.containsDisallowedReasons()) {
            DataProfile dataProfile = evaluation.getCandidateDataProfile();
            if (dataProfile != null) {
                setupDataNetwork(dataProfile, null);
@@ -1224,7 +1224,7 @@ public class DataNetworkController extends Handler {
        }

        // Check whether to allow data in certain situations if data is disallowed for soft reasons
        if (evaluation.isDataAllowed()) {
        if (!evaluation.containsDisallowedReasons()) {
            evaluation.addDataAllowedReason(DataAllowedReason.NORMAL);
        } else if (!evaluation.containsHardDisallowedReasons()) {
            // Check if request is MMS and MMS is always allowed
@@ -1237,12 +1237,7 @@ public class DataNetworkController extends Handler {
            if (transport == AccessNetworkConstants.TRANSPORT_TYPE_WLAN) {
                evaluation.addDataAllowedReason(DataAllowedReason.UNMETERED_USAGE);
            } else if (transport == AccessNetworkConstants.TRANSPORT_TYPE_WWAN) {
                int apnType = DataUtils.networkCapabilityToApnType(
                        networkRequest.getApnTypeNetworkCapability());
                Set<Integer> meteredApns = mServiceState.getDataRoaming()
                        ? mDataConfigManager.getMeteredApnTypesWhenRoaming()
                        : mDataConfigManager.getMeteredApnTypes();
                if (!meteredApns.contains(apnType)) {
                if (!networkRequest.isMeteredRequest()) {
                    evaluation.addDataAllowedReason(DataAllowedReason.UNMETERED_USAGE);
                }
            }
@@ -1269,7 +1264,7 @@ public class DataNetworkController extends Handler {
            evaluation.addDataDisallowedReason(DataDisallowedReason.DATA_THROTTLED);
        }

        if (evaluation.isDataAllowed()) {
        if (!evaluation.containsDisallowedReasons()) {
            evaluation.setCandidateDataProfile(dataProfile);
        }

@@ -1321,7 +1316,7 @@ public class DataNetworkController extends Handler {
            // all the requests in the list have the same capabilities, we can only evaluate one
            // of them.
            DataEvaluation evaluation = evaluateNetworkRequest(requestList.get(0), reason);
            if (evaluation.isDataAllowed()) {
            if (!evaluation.containsDisallowedReasons()) {
                DataProfile dataProfile = evaluation.getCandidateDataProfile();
                if (dataProfile != null) {
                    setupDataNetwork(dataProfile, null);
@@ -1421,8 +1416,32 @@ public class DataNetworkController extends Handler {
            evaluation.addDataDisallowedReason(DataDisallowedReason.DATA_PROFILE_NOT_PREFERRED);
        }

        if (evaluation.isDataAllowed()) {
        // Check whether if there are any reason we should tear down the network.
        if (!evaluation.containsDisallowedReasons()) {
            // The data is allowed in the current condition.
            evaluation.addDataAllowedReason(DataAllowedReason.NORMAL);
        } else if (!evaluation.containsHardDisallowedReasons()) {
            // If there are reasons we should tear down the network, check if those are hard reasons
            // or soft reasons. In some scenarios, we can make exceptions if they are soft
            // disallowed reasons.

            // Check if request is unmetered (WiFi or unmetered APN)
            if (dataNetwork.getTransport() == AccessNetworkConstants.TRANSPORT_TYPE_WLAN) {
                evaluation.addDataAllowedReason(DataAllowedReason.UNMETERED_USAGE);
            } else {
                boolean unmeteredNetwork = !mDataConfigManager.isAnyMeteredCapability(
                        dataNetwork.getNetworkCapabilities()
                                .getCapabilities(), mServiceState.getDataRoaming());
                if (unmeteredNetwork) {
                    evaluation.addDataAllowedReason(DataAllowedReason.UNMETERED_USAGE);
                }
            }

            // Check if request is restricted
            if (!dataNetwork.getNetworkCapabilities().hasCapability(
                    NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)) {
                evaluation.addDataAllowedReason(DataAllowedReason.RESTRICTED_REQUEST);
            }
        }

        log("Evaluated " + dataNetwork + ", " + evaluation.toString());
@@ -1444,7 +1463,7 @@ public class DataNetworkController extends Handler {
        for (DataNetwork dataNetwork : mDataNetworkList) {
            if (dataNetwork.isConnecting() || dataNetwork.isConnected()) {
                DataEvaluation dataEvaluation = evaluateDataNetwork(dataNetwork, reason);
                if (!dataEvaluation.isDataAllowed()) {
                if (dataEvaluation.containsDisallowedReasons()) {
                    tearDownGracefully(dataNetwork, getTearDownReason(dataEvaluation));
                }
            }
@@ -1520,7 +1539,7 @@ public class DataNetworkController extends Handler {
     * @return The tear down reason.
     */
    private @TearDownReason int getTearDownReason(@NonNull DataEvaluation dataEvaluation) {
        if (!dataEvaluation.isDataAllowed()) {
        if (dataEvaluation.containsDisallowedReasons()) {
            switch (dataEvaluation.getDataDisallowedReasons().get(0)) {
                case DATA_DISABLED:
                    return DataNetwork.TEAR_DOWN_REASON_DATA_DISABLED;
@@ -1980,7 +1999,7 @@ public class DataNetworkController extends Handler {

        DataEvaluation evaluation = evaluateNetworkRequest(
                telephonyNetworkRequest, DataEvaluationReason.DATA_RETRY);
        if (evaluation.isDataAllowed()) {
        if (!evaluation.containsDisallowedReasons()) {
            DataProfile dataProfile = dataSetupRetryEntry.dataProfile;
            if (dataProfile == null) {
                dataProfile = evaluation.getCandidateDataProfile();
@@ -2273,7 +2292,7 @@ public class DataNetworkController extends Handler {
                }

                DataEvaluation dataEvaluation = evaluateDataNetworkHandover(dataNetwork);
                if (dataEvaluation.isDataAllowed()) {
                if (!dataEvaluation.containsDisallowedReasons()) {
                    logl("Start handover " + dataNetwork + " to "
                            + AccessNetworkConstants.transportTypeToString(preferredTransport));
                    dataNetwork.startHandover(preferredTransport, null);
+5 −0
Original line number Diff line number Diff line
@@ -169,6 +169,9 @@ public class DataSettingsManager extends Handler {
        mDataEnabledSettings.put(TelephonyManager.DATA_ENABLED_REASON_CARRIER, true);
        mDataEnabledSettings.put(TelephonyManager.DATA_ENABLED_REASON_THERMAL, true);

        mIsDataEnabled = isDataEnabled(ApnSetting.TYPE_ALL);
        log("mIsDataEnabled=" + mIsDataEnabled);

        // Instead of calling onRegisterAllEvents directly from the constructor, send the event.
        // The reason is that getImsPhone is null when we are still in the constructor here.
        sendEmptyMessage(EVENT_REGISTER_ALL_EVENTS);
@@ -220,6 +223,7 @@ public class DataSettingsManager extends Handler {
                if (isStandAloneOpportunistic(mSubId, mPhone.getContext()) && !enabled) return;
                boolean changed = GlobalSettingsHelper.setInt(mPhone.getContext(),
                        Settings.Global.MOBILE_DATA, mSubId, (enabled ? 1 : 0));
                log("Set user data enabled to " + enabled + ", changed=" + changed);
                if (changed) {
                    logl("UserDataEnabled changed to " + enabled);
                    mPhone.notifyUserMobileDataStateChanged(enabled);
@@ -304,6 +308,7 @@ public class DataSettingsManager extends Handler {
            case EVENT_UPDATE_DATA_ENABLED: {
                boolean prevDataEnabled = mIsDataEnabled;
                mIsDataEnabled = isDataEnabled(ApnSetting.TYPE_ALL);
                log("mIsDataEnabled=" + mIsDataEnabled + ", prevDataEnabled=" + prevDataEnabled);
                if (prevDataEnabled != mIsDataEnabled) {
                    notifyDataEnabledChanged(mIsDataEnabled, (int) msg.obj);
                }
Loading