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

Commit 7464741d authored by Jack Yu's avatar Jack Yu Committed by android-build-merger
Browse files

Merge "Added unmetered use only data connection support" am: 1b0205b0

am: 4237c12e

Change-Id: I05bf489b221cbea384111c04549c7b93efaf7744
parents 435c39ab 4237c12e
Loading
Loading
Loading
Loading
+19 −6
Original line number Diff line number Diff line
@@ -104,14 +104,17 @@ public class DataConnection extends StateMachine {
        ApnContext mApnContext;
        int mProfileId;
        int mRilRat;
        final boolean mUnmeteredUseOnly;
        Message mOnCompletedMsg;
        final int mConnectionGeneration;

        ConnectionParams(ApnContext apnContext, int profileId,
                int rilRadioTechnology, Message onCompletedMsg, int connectionGeneration) {
        ConnectionParams(ApnContext apnContext, int profileId, int rilRadioTechnology,
                         boolean unmeteredUseOnly,  Message onCompletedMsg,
                         int connectionGeneration) {
            mApnContext = apnContext;
            mProfileId = profileId;
            mRilRat = rilRadioTechnology;
            mUnmeteredUseOnly = unmeteredUseOnly;
            mOnCompletedMsg = onCompletedMsg;
            mConnectionGeneration = connectionGeneration;
        }
@@ -121,6 +124,7 @@ public class DataConnection extends StateMachine {
            return "{mTag=" + mTag + " mApnContext=" + mApnContext
                    + " mProfileId=" + mProfileId
                    + " mRat=" + mRilRat
                    + " mUnmeteredUseOnly=" + mUnmeteredUseOnly
                    + " mOnCompletedMsg=" + msgToString(mOnCompletedMsg) + "}";
        }
    }
@@ -858,7 +862,7 @@ public class DataConnection extends StateMachine {
        }

        // Is data disabled?
        mRestrictedNetworkOverride = (mDct.isDataEnabled(true) == false);
        mRestrictedNetworkOverride = !mDct.isDataEnabled();
    }

    private NetworkCapabilities makeNetworkCapabilities() {
@@ -867,6 +871,13 @@ public class DataConnection extends StateMachine {

        if (mApnSetting != null) {
            for (String type : mApnSetting.types) {
                if (!mRestrictedNetworkOverride
                        && mConnectionParams.mUnmeteredUseOnly && ApnSetting.isMeteredApnType(type,
                        mPhone.getContext(), mPhone.getSubId(),
                        mPhone.getServiceState().getDataRoaming())) {
                    log("Dropped the metered " + type + " for the unmetered data call.");
                    continue;
                }
                switch (type) {
                    case PhoneConstants.APN_TYPE_ALL: {
                        result.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
@@ -921,9 +932,11 @@ public class DataConnection extends StateMachine {
                }
            }

            // If none of the APN types associated with this APN setting is metered,
            // then we apply NOT_METERED capability to the network.
            if (!mApnSetting.isMetered(mPhone.getContext(), mPhone.getSubId(),
            // Mark NOT_METERED in the following cases,
            // 1. All APNs in APN settings are unmetered.
            // 2. The non-restricted data and is intended for unmetered use only.
            if ((mConnectionParams.mUnmeteredUseOnly && !mRestrictedNetworkOverride)
                    || !mApnSetting.isMetered(mPhone.getContext(), mPhone.getSubId(),
                    mPhone.getServiceState().getDataRoaming())) {
                result.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
                mNetworkInfo.setMetered(false);
+12 −14
Original line number Diff line number Diff line
@@ -64,9 +64,9 @@ public class DataEnabledSettings {
    private final RegistrantList mDataEnabledChangedRegistrants = new RegistrantList();

    public synchronized void setInternalDataEnabled(boolean enabled) {
        boolean prevDataEnabled = isDataEnabled(true);
        boolean prevDataEnabled = isDataEnabled();
        mInternalDataEnabled = enabled;
        if (prevDataEnabled != isDataEnabled(true)) {
        if (prevDataEnabled != isDataEnabled()) {
            notifyDataEnabledChanged(!prevDataEnabled, REASON_INTERNAL_DATA_ENABLED);
        }
    }
@@ -75,9 +75,9 @@ public class DataEnabledSettings {
    }

    public synchronized void setUserDataEnabled(boolean enabled) {
        boolean prevDataEnabled = isDataEnabled(true);
        boolean prevDataEnabled = isDataEnabled();
        mUserDataEnabled = enabled;
        if (prevDataEnabled != isDataEnabled(true)) {
        if (prevDataEnabled != isDataEnabled()) {
            notifyDataEnabledChanged(!prevDataEnabled, REASON_USER_DATA_ENABLED);
        }
    }
@@ -86,9 +86,9 @@ public class DataEnabledSettings {
    }

    public synchronized void setPolicyDataEnabled(boolean enabled) {
        boolean prevDataEnabled = isDataEnabled(true);
        boolean prevDataEnabled = isDataEnabled();
        mPolicyDataEnabled = enabled;
        if (prevDataEnabled != isDataEnabled(true)) {
        if (prevDataEnabled != isDataEnabled()) {
            notifyDataEnabledChanged(!prevDataEnabled, REASON_POLICY_DATA_ENABLED);
        }
    }
@@ -97,9 +97,9 @@ public class DataEnabledSettings {
    }

    public synchronized void setCarrierDataEnabled(boolean enabled) {
        boolean prevDataEnabled = isDataEnabled(true);
        boolean prevDataEnabled = isDataEnabled();
        mCarrierDataEnabled = enabled;
        if (prevDataEnabled != isDataEnabled(true)) {
        if (prevDataEnabled != isDataEnabled()) {
            notifyDataEnabledChanged(!prevDataEnabled, REASON_DATA_ENABLED_BY_CARRIER);
        }
    }
@@ -107,11 +107,9 @@ public class DataEnabledSettings {
        return mCarrierDataEnabled;
    }

    public synchronized boolean isDataEnabled(boolean checkUserDataEnabled) {
        return (mInternalDataEnabled
                && (!checkUserDataEnabled || mUserDataEnabled)
                && (!checkUserDataEnabled || mPolicyDataEnabled)
                && (!checkUserDataEnabled || mCarrierDataEnabled));
    public synchronized boolean isDataEnabled() {
        return (mInternalDataEnabled && mUserDataEnabled && mPolicyDataEnabled
                && mCarrierDataEnabled);
    }

    private void notifyDataEnabledChanged(boolean enabled, int reason) {
@@ -120,7 +118,7 @@ public class DataEnabledSettings {

    public void registerForDataEnabledChanged(Handler h, int what, Object obj) {
        mDataEnabledChangedRegistrants.addUnique(h, what, obj);
        notifyDataEnabledChanged(isDataEnabled(true), REASON_REGISTERED);
        notifyDataEnabledChanged(isDataEnabled(), REASON_REGISTERED);
    }

    public void unregisterForDataEnabledChanged(Handler h) {
+20 −14
Original line number Diff line number Diff line
@@ -16,16 +16,16 @@

package com.android.internal.telephony.dataconnection;

import com.android.internal.telephony.dataconnection.DataConnection.ConnectionParams;
import com.android.internal.telephony.dataconnection.DataConnection.DisconnectParams;
import com.android.internal.util.AsyncChannel;
import com.android.internal.util.Protocol;

import android.net.LinkProperties;
import android.net.NetworkCapabilities;
import android.net.ProxyInfo;
import android.os.Message;

import com.android.internal.telephony.dataconnection.DataConnection.ConnectionParams;
import com.android.internal.telephony.dataconnection.DataConnection.DisconnectParams;
import com.android.internal.util.AsyncChannel;
import com.android.internal.util.Protocol;

/**
 * AsyncChannel to a DataConnection
 */
@@ -319,7 +319,7 @@ public class DcAsyncChannel extends AsyncChannel {
     * Evaluate RSP_GET_NETWORK_CAPABILITIES
     *
     * @param response
     * @return NetworkCapabilites, maybe null.
     * @return NetworkCapabilities, maybe null.
     */
    public NetworkCapabilities rspNetworkCapabilities(Message response) {
        NetworkCapabilities retVal = (NetworkCapabilities) response.obj;
@@ -357,23 +357,29 @@ public class DcAsyncChannel extends AsyncChannel {

    /**
     * Bring up a connection to the apn and return an AsyncResult in onCompletedMsg.
     * Used for cellular networks that use Acesss Point Names (APN) such
     * Used for cellular networks that use Access Point Names (APN) such
     * as GSM networks.
     *
     * @param apnContext is the Access Point Name to bring up a connection to
     * @param profileId for the conneciton
     * @param profileId for the connection
     * @param rilRadioTechnology Radio technology for the data connection
     * @param unmeteredUseOnly Indicates the data connection can only used for unmetered purposes
     * @param onCompletedMsg is sent with its msg.obj as an AsyncResult object.
     *                       With AsyncResult.userObj set to the original msg.obj,
     *                       AsyncResult.result = FailCause and AsyncResult.exception = Exception().
     * @param connectionGeneration used to track a single connection request so disconnects can get
     *                             ignored if obsolete.
     */
    public void bringUp(ApnContext apnContext, int profileId, int rilRadioTechnology,
                        Message onCompletedMsg, int connectionGeneration) {
                        boolean unmeteredUseOnly, Message onCompletedMsg,
                        int connectionGeneration) {
        if (DBG) {
            log("bringUp: apnContext=" + apnContext + " onCompletedMsg=" + onCompletedMsg);
            log("bringUp: apnContext=" + apnContext + "unmeteredUseOnly=" + unmeteredUseOnly
                    + " onCompletedMsg=" + onCompletedMsg);
        }
        sendMessage(DataConnection.EVENT_CONNECT,
                new ConnectionParams(apnContext, profileId, rilRadioTechnology, onCompletedMsg,
                        connectionGeneration));
                new ConnectionParams(apnContext, profileId, rilRadioTechnology, unmeteredUseOnly,
                        onCompletedMsg, connectionGeneration));
    }

    /**
+101 −61
Original line number Diff line number Diff line
@@ -911,7 +911,7 @@ public class DcTracker extends Handler {
                // TODO: We should register for DataEnabledSetting's data enabled/disabled event and
                // handle the rest from there.
                if (enabled) {
                    teardownRestrictedMeteredConnections();
                    reevaluateDataConnections();
                    onTrySetupData(Phone.REASON_DATA_ENABLED);
                } else {
                    onCleanUpAllConnections(Phone.REASON_DATA_SPECIFIC_DISABLED);
@@ -921,42 +921,58 @@ public class DcTracker extends Handler {
    }

    /**
     * Handle reverting restricted networks back to unrestricted.
     * If we're changing user data to enabled and this makes data
     * truely enabled (not disabled by other factors) we need to
     * tear down any metered apn type that was enabled anyway by
     * a privileged request.  This allows us to reconnect
     * to it in an unrestricted way.
     * Reevaluate existing data connections when conditions change.
     *
     * For example, handle reverting restricted networks back to unrestricted. If we're changing
     * user data to enabled and this makes data truly enabled (not disabled by other factors) we
     * need to tear down any metered apn type that was enabled anyway by a privileged request.
     * This allows us to reconnect to it in an unrestricted way.
     *
     * Or when we brought up a unmetered data connection while data is off, we only limit this
     * data connection for unmetered use only. When data is turned back on, we need to tear that
     * down so a full capable data connection can be re-established.
     */
    private void teardownRestrictedMeteredConnections() {
        if (mDataEnabledSettings.isDataEnabled(true)) {
    private void reevaluateDataConnections() {
        if (mDataEnabledSettings.isDataEnabled()) {
            for (ApnContext apnContext : mApnContexts.values()) {
                if (apnContext.isConnectedOrConnecting() &&
                        apnContext.getApnSetting().isMetered(mPhone.getContext(),
                        mPhone.getSubId(), mPhone.getServiceState().getDataRoaming())) {

                    final DcAsyncChannel dataConnectionAc = apnContext.getDcAc();
                    if (dataConnectionAc != null) {
                        final NetworkCapabilities nc =
                                dataConnectionAc.getNetworkCapabilitiesSync();
                        if (nc != null && nc.hasCapability(NetworkCapabilities.
                              NET_CAPABILITY_NOT_RESTRICTED)) {
                            if (DBG) log("not tearing down unrestricted metered net:" + apnContext);
                            continue;
                if (apnContext.isConnectedOrConnecting()) {
                    final DcAsyncChannel dcac = apnContext.getDcAc();
                    if (dcac != null) {
                        final NetworkCapabilities netCaps = dcac.getNetworkCapabilitiesSync();
                        if (netCaps != null && !netCaps.hasCapability(NetworkCapabilities
                                .NET_CAPABILITY_NOT_RESTRICTED)) {
                            if (DBG) {
                                log("Tearing down restricted net:" + apnContext);
                            }
                            // Tearing down the restricted data call (metered or unmetered) when
                            // conditions change. This will allow reestablishing a new unrestricted
                            // data connection.
                            apnContext.setReason(Phone.REASON_DATA_ENABLED);
                            cleanUpConnection(true, apnContext);
                        } else if (apnContext.getApnSetting().isMetered(mPhone.getContext(),
                                mPhone.getSubId(), mPhone.getServiceState().getDataRoaming())
                                && (netCaps != null && netCaps.hasCapability(
                                        NetworkCapabilities.NET_CAPABILITY_NOT_METERED))) {
                            if (DBG) {
                                log("Tearing down unmetered net:" + apnContext);
                            }
                    if (DBG) log("tearing down restricted metered net: " + apnContext);
                            // The APN settings is metered, but the data was still marked as
                            // unmetered data, must be the unmetered data connection brought up when
                            // data is off. We need to tear that down when data is enabled again.
                            // This will allow reestablishing a new full capability data connection.
                            apnContext.setReason(Phone.REASON_DATA_ENABLED);
                            cleanUpConnection(true, apnContext);
                        }
                    }
                }
            }
        }
    }

    private void onDeviceProvisionedChange() {
        if (getDataEnabled()) {
            mDataEnabledSettings.setUserDataEnabled(true);
            teardownRestrictedMeteredConnections();
            reevaluateDataConnections();
            onTrySetupData(Phone.REASON_DATA_ENABLED);
        } else {
            mDataEnabledSettings.setUserDataEnabled(false);
@@ -1297,7 +1313,7 @@ public class DcTracker extends Handler {
     * {@code true} otherwise.
     */
    public boolean getAnyDataEnabled() {
        if (!mDataEnabledSettings.isDataEnabled(true)) return false;
        if (!mDataEnabledSettings.isDataEnabled()) return false;
        DataAllowFailReason failureReason = new DataAllowFailReason();
        if (!isDataAllowed(failureReason)) {
            if (DBG) log(failureReason.getDataAllowFailReason());
@@ -1314,8 +1330,8 @@ public class DcTracker extends Handler {
    }

    @VisibleForTesting
    public boolean isDataEnabled(boolean checkUserDataEnabled) {
        return mDataEnabledSettings.isDataEnabled(checkUserDataEnabled);
    public boolean isDataEnabled() {
        return mDataEnabledSettings.isDataEnabled();
    }

    private boolean isDataAllowedForApn(ApnContext apnContext) {
@@ -1547,29 +1563,53 @@ public class DcTracker extends Handler {
        boolean isEmergencyApn = apnContext.getApnType().equals(PhoneConstants.APN_TYPE_EMERGENCY);
        final ServiceStateTracker sst = mPhone.getServiceStateTracker();

        // set to false if apn type is non-metered or if we have a restricted (priveleged)
        // request for the network.
        // TODO - may want restricted requests to only apply to carrier-limited data access
        //        rather than applying to user limited as well.
        // Exclude DUN for the purposes of the override until we get finer grained
        // intention in NetworkRequests
        boolean checkUserDataEnabled =
                ApnSetting.isMeteredApnType(apnContext.getApnType(), mPhone.getContext(),
                        mPhone.getSubId(), mPhone.getServiceState().getDataRoaming()) &&
                apnContext.hasNoRestrictedRequests(true /*exclude DUN */);

        DataAllowFailReason failureReason = new DataAllowFailReason();

        // allow data if currently in roaming service, roaming setting disabled
        // and requested apn type is non-metered for roaming.
        boolean isDataAllowed = isDataAllowed(failureReason) ||
                (failureReason.isFailForSingleReason(DataAllowFailReasonType.ROAMING_DISABLED) &&
                !(ApnSetting.isMeteredApnType(apnContext.getApnType(), mPhone.getContext(),
                mPhone.getSubId(), mPhone.getServiceState().getDataRoaming())));

        if (apnContext.isConnectable() && (isEmergencyApn ||
                (isDataAllowed && isDataAllowedForApn(apnContext) &&
                        mDataEnabledSettings.isDataEnabled(checkUserDataEnabled) && !isEmergency()))) {
        boolean unmeteredUseOnly = false;
        boolean isDataAllowed = isDataAllowed(failureReason);
        boolean isMeteredApnType = ApnSetting.isMeteredApnType(apnContext.getApnType(),
                mPhone.getContext(), mPhone.getSubId(), mPhone.getServiceState().getDataRoaming());
        if (!isDataAllowed) {
            // If the data not allowed due to roaming disabled, but the request APN type is not
            // metered, we should allow data (because the user won't be charged anyway)
            if (failureReason.isFailForSingleReason(DataAllowFailReasonType.ROAMING_DISABLED)
                    && !isMeteredApnType) {
                isDataAllowed = true;
                unmeteredUseOnly = true;
            }
        }

        if (isDataAllowed) {
            if (!mDataEnabledSettings.isDataEnabled()) {
                // If the data is turned off, we should not allow a data connection.
                isDataAllowed = false;

                // But there are some exceptions we should allow data even when data is turned off.
                if (!apnContext.hasNoRestrictedRequests(true /*exclude DUN */)) {
                    // A restricted request can request data even when data is turned off.
                    // Note this takes precedence over unmetered request.
                    isDataAllowed = true;
                    unmeteredUseOnly = false;
                } else if (!isMeteredApnType) {
                    // If the APN is unmetered, we should allow data even if data is turned off.
                    // This will allow users to make VoLTE calls or send MMS while data is
                    // turned off.
                    isDataAllowed = true;

                    // When data is off, if we allow a data call because it's unmetered, we
                    // should restrict it for unmetered use only. For example, if one
                    // carrier has both internet (metered) and MMS (unmetered) APNs mixed in one
                    // APN setting, when we bring up a data call for MMS purpose, we should
                    // restrict it for unmetered use only. We should not allow it for other
                    // metered purposes such as internet.
                    unmeteredUseOnly = true;
                }
            }
        }

        if (apnContext.isConnectable()
                && (isEmergencyApn
                || (isDataAllowed && isDataAllowedForApn(apnContext) && !isEmergency()))) {
            if (apnContext.getState() == DctConstants.State.FAILED) {
                String str = "trySetupData: make a FAILED ApnContext IDLE so its reusable";
                if (DBG) log(str);
@@ -1598,7 +1638,7 @@ public class DcTracker extends Handler {
                }
            }

            boolean retValue = setupData(apnContext, radioTech);
            boolean retValue = setupData(apnContext, radioTech, unmeteredUseOnly);
            notifyOffApnsOfAvailability(apnContext.getReason());

            if (DBG) log("trySetupData: X retValue=" + retValue);
@@ -1627,13 +1667,13 @@ public class DcTracker extends Handler {
                str.append("isDataAllowedForApn = false. RAT = " +
                        mPhone.getServiceState().getRilDataRadioTechnology());
            }
            if (!mDataEnabledSettings.isDataEnabled(checkUserDataEnabled)) {
                str.append("isDataEnabled(" + checkUserDataEnabled + ") = false. " +
                        "isInternalDataEnabled = " + mDataEnabledSettings.isInternalDataEnabled() +
                        ", userDataEnabled = " + mDataEnabledSettings.isUserDataEnabled() +
                        ", isPolicyDataEnabled = " + mDataEnabledSettings.isPolicyDataEnabled() +
                        ", isCarrierDataEnabled = " +
                        mDataEnabledSettings.isCarrierDataEnabled());
            if (!mDataEnabledSettings.isDataEnabled()) {
                str.append("isDataEnabled() = false. "
                        + "isInternalDataEnabled = " + mDataEnabledSettings.isInternalDataEnabled()
                        + ", userDataEnabled = " + mDataEnabledSettings.isUserDataEnabled()
                        + ", isPolicyDataEnabled = " + mDataEnabledSettings.isPolicyDataEnabled()
                        + ", isCarrierDataEnabled = "
                        + mDataEnabledSettings.isCarrierDataEnabled());
            }
            if (isEmergency()) {
                str.append("emergency = true");
@@ -2059,7 +2099,7 @@ public class DcTracker extends Handler {
        return null;
    }

    private boolean setupData(ApnContext apnContext, int radioTech) {
    private boolean setupData(ApnContext apnContext, int radioTech, boolean unmeteredUseOnly) {
        if (DBG) log("setupData: apnContext=" + apnContext);
        apnContext.requestLog("setupData");
        ApnSetting apnSetting;
@@ -2141,7 +2181,7 @@ public class DcTracker extends Handler {
        Message msg = obtainMessage();
        msg.what = DctConstants.EVENT_DATA_SETUP_COMPLETE;
        msg.obj = new Pair<ApnContext, Integer>(apnContext, generation);
        dcac.bringUp(apnContext, profileId, radioTech, msg, generation);
        dcac.bringUp(apnContext, profileId, radioTech, unmeteredUseOnly, msg, generation);

        if (DBG) log("setupData: initing!");
        return true;
@@ -2424,11 +2464,11 @@ public class DcTracker extends Handler {
                    // Tear down all metered apns
                    cleanUpAllConnections(true, Phone.REASON_CARRIER_ACTION_DISABLE_METERED_APN);
                } else {
                    // Re-evauluate Otasp state
                    // Re-evaluate Otasp state
                    int otaspState = mPhone.getServiceStateTracker().getOtasp();
                    mPhone.notifyOtaspChanged(otaspState);

                    teardownRestrictedMeteredConnections();
                    reevaluateDataConnections();
                    setupDataOnConnectableApns(Phone.REASON_DATA_ENABLED);
                }
            }
@@ -2479,7 +2519,7 @@ public class DcTracker extends Handler {
                // handle the rest from there.
                if (prevEnabled != getAnyDataEnabled()) {
                    if (!prevEnabled) {
                        teardownRestrictedMeteredConnections();
                        reevaluateDataConnections();
                        onTrySetupData(Phone.REASON_DATA_ENABLED);
                    } else {
                        onCleanUpAllConnections(Phone.REASON_DATA_SPECIFIC_DISABLED);