Loading src/java/com/android/internal/telephony/dataconnection/DataConnection.java +39 −27 Original line number Diff line number Diff line Loading @@ -16,9 +16,6 @@ package com.android.internal.telephony.dataconnection; import static android.net.NetworkPolicyManager.SUBSCRIPTION_OVERRIDE_CONGESTED; import static android.net.NetworkPolicyManager.SUBSCRIPTION_OVERRIDE_UNMETERED; import static com.android.internal.telephony.dataconnection.DcTracker.REQUEST_TYPE_HANDOVER; import android.annotation.IntDef; Loading Loading @@ -294,7 +291,7 @@ public class DataConnection extends StateMachine { private int mLastFailCause; private static final String NULL_IP = "0.0.0.0"; private Object mUserData; private int mSubscriptionOverride; private boolean mCongestedOverride; private boolean mUnmeteredOverride; private int mRilRat = ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN; private int mDataRegState = Integer.MAX_VALUE; Loading Loading @@ -344,7 +341,7 @@ public class DataConnection extends StateMachine { static final int EVENT_BW_REFRESH_RESPONSE = BASE + 14; static final int EVENT_DATA_CONNECTION_VOICE_CALL_STARTED = BASE + 15; static final int EVENT_DATA_CONNECTION_VOICE_CALL_ENDED = BASE + 16; static final int EVENT_DATA_CONNECTION_OVERRIDE_CHANGED = BASE + 17; static final int EVENT_DATA_CONNECTION_CONGESTEDNESS_CHANGED = BASE + 17; static final int EVENT_KEEPALIVE_STATUS = BASE + 18; static final int EVENT_KEEPALIVE_STARTED = BASE + 19; static final int EVENT_KEEPALIVE_STOPPED = BASE + 20; Loading Loading @@ -387,8 +384,8 @@ public class DataConnection extends StateMachine { "EVENT_DATA_CONNECTION_VOICE_CALL_STARTED"; sCmdToString[EVENT_DATA_CONNECTION_VOICE_CALL_ENDED - BASE] = "EVENT_DATA_CONNECTION_VOICE_CALL_ENDED"; sCmdToString[EVENT_DATA_CONNECTION_OVERRIDE_CHANGED - BASE] = "EVENT_DATA_CONNECTION_OVERRIDE_CHANGED"; sCmdToString[EVENT_DATA_CONNECTION_CONGESTEDNESS_CHANGED - BASE] = "EVENT_DATA_CONNECTION_CONGESTEDNESS_CHANGED"; sCmdToString[EVENT_KEEPALIVE_STATUS - BASE] = "EVENT_KEEPALIVE_STATUS"; sCmdToString[EVENT_KEEPALIVE_STARTED - BASE] = "EVENT_KEEPALIVE_STARTED"; sCmdToString[EVENT_KEEPALIVE_STOPPED - BASE] = "EVENT_KEEPALIVE_STOPPED"; Loading Loading @@ -1000,14 +997,16 @@ public class DataConnection extends StateMachine { setHandoverState(HANDOVER_STATE_IDLE); } public void onSubscriptionOverride(int overrideMask, int overrideValue) { mSubscriptionOverride = (mSubscriptionOverride & ~overrideMask) | (overrideValue & overrideMask); sendMessage(obtainMessage(EVENT_DATA_CONNECTION_OVERRIDE_CHANGED)); /** * Update NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED based on congested override * @param isCongested whether this DC should be set to congested or not */ public void onCongestednessChanged(boolean isCongested) { sendMessage(obtainMessage(EVENT_DATA_CONNECTION_CONGESTEDNESS_CHANGED, isCongested)); } /** * Update NetworkCapabilities.NET_CAPABILITY_NOT_METERED based on meteredness * Update NetworkCapabilities.NET_CAPABILITY_NOT_METERED based on metered override * @param isUnmetered whether this DC should be set to unmetered or not */ public void onMeterednessChanged(boolean isUnmetered) { Loading Loading @@ -1189,7 +1188,7 @@ public class DataConnection extends StateMachine { mDcFailCause = DataFailCause.NONE; mDisabledApnTypeBitMask = 0; mSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; mSubscriptionOverride = 0; mCongestedOverride = false; mUnmeteredOverride = false; mDownlinkBandwidth = 14; mUplinkBandwidth = 14; Loading Loading @@ -1721,15 +1720,9 @@ public class DataConnection extends StateMachine { result.setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING, !mPhone.getServiceState().getDataRoaming()); result.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED); // Override values set above when requested by policy if ((mSubscriptionOverride & SUBSCRIPTION_OVERRIDE_UNMETERED) != 0) { result.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED); } if ((mSubscriptionOverride & SUBSCRIPTION_OVERRIDE_CONGESTED) != 0) { result.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED); } result.setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED, !mCongestedOverride); //result.setCapability(NetworkCapabilities.NET_CAPABILITY_TEMPORARILY_NOT_METERED, // mUnmeteredOverride); // TODO: Remove this after b/176119724 is fixed. This is just a workaround to prevent // NET_CAPABILITY_TEMPORARILY_NOT_METERED incorrectly set on devices that are not supposed Loading Loading @@ -2771,10 +2764,29 @@ public class DataConnection extends StateMachine { break; } mUnmeteredOverride = isUnmetered; // fallthrough if (mNetworkAgent != null) { mNetworkAgent.updateLegacySubtype(DataConnection.this); mNetworkAgent.sendNetworkCapabilities(getNetworkCapabilities(), DataConnection.this); } retVal = HANDLED; break; case EVENT_DATA_CONNECTION_CONGESTEDNESS_CHANGED: boolean isCongested = (boolean) msg.obj; if (isCongested == mCongestedOverride) { retVal = HANDLED; break; } mCongestedOverride = isCongested; if (mNetworkAgent != null) { mNetworkAgent.updateLegacySubtype(DataConnection.this); mNetworkAgent.sendNetworkCapabilities(getNetworkCapabilities(), DataConnection.this); } retVal = HANDLED; break; case EVENT_DATA_CONNECTION_ROAM_ON: case EVENT_DATA_CONNECTION_ROAM_OFF: case EVENT_DATA_CONNECTION_OVERRIDE_CHANGED: { case EVENT_DATA_CONNECTION_ROAM_OFF: { if (mNetworkAgent != null) { mNetworkAgent.updateLegacySubtype(DataConnection.this); mNetworkAgent.sendNetworkCapabilities(getNetworkCapabilities(), Loading Loading @@ -3561,7 +3573,7 @@ public class DataConnection extends StateMachine { * Dump the current state. * * @param fd * @param pw * @param printWriter * @param args */ @Override Loading Loading @@ -3593,10 +3605,10 @@ public class DataConnection extends StateMachine { pw.println("mLastFailTime=" + TimeUtils.logTimeOfDay(mLastFailTime)); pw.println("mLastFailCause=" + DataFailCause.toString(mLastFailCause)); pw.println("mUserData=" + mUserData); pw.println("mSubscriptionOverride=" + Integer.toHexString(mSubscriptionOverride)); pw.println("mRestrictedNetworkOverride=" + mRestrictedNetworkOverride); pw.println("mUnmeteredUseOnly=" + mUnmeteredUseOnly); pw.println("mUnmeteredOverride=" + mUnmeteredOverride); pw.println("mCongestedOverride=" + mCongestedOverride); pw.println("mDownlinkBandwidth" + mDownlinkBandwidth); pw.println("mUplinkBandwidth=" + mUplinkBandwidth); pw.println("mDefaultQos=" + mDefaultQos); Loading src/java/com/android/internal/telephony/dataconnection/DcTracker.java +67 −9 Original line number Diff line number Diff line Loading @@ -17,6 +17,8 @@ package com.android.internal.telephony.dataconnection; import static android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE; import static android.net.NetworkPolicyManager.SUBSCRIPTION_OVERRIDE_CONGESTED; import static android.net.NetworkPolicyManager.SUBSCRIPTION_OVERRIDE_UNMETERED; import static android.telephony.TelephonyManager.NETWORK_TYPE_LTE; import static android.telephony.TelephonyManager.NETWORK_TYPE_NR; import static android.telephony.data.ApnSetting.PROTOCOL_IPV4V6; Loading Loading @@ -347,6 +349,16 @@ public class DcTracker extends Handler { /* List of SubscriptionPlans, updated when initialized and when plans are changed. */ private List<SubscriptionPlan> mSubscriptionPlans = null; /* List of network types an unmetered override applies to, set by onSubscriptionOverride * and cleared when the device is rebooted or the override expires. */ private List<Integer> mUnmeteredNetworkTypes = null; /* List of network types a congested override applies to, set by onSubscriptionOverride * and cleared when the device is rebooted or the override expires. */ private List<Integer> mCongestedNetworkTypes = null; /* Whether an unmetered override is currently active. */ private boolean mUnmeteredOverride = false; /* Whether a congested override is currently active. */ private boolean mCongestedOverride = false; @SimState private int mSimState = TelephonyManager.SIM_STATE_UNKNOWN; Loading Loading @@ -427,11 +439,26 @@ public class DcTracker extends Handler { private final NetworkPolicyManager.SubscriptionCallback mSubscriptionCallback = new NetworkPolicyManager.SubscriptionCallback() { @Override public void onSubscriptionOverride(int subId, int overrideMask, int overrideValue) { public void onSubscriptionOverride(int subId, int overrideMask, int overrideValue, int[] networkTypes) { if (mPhone == null || mPhone.getSubId() != subId) return; for (DataConnection dataConnection : mDataConnections.values()) { dataConnection.onSubscriptionOverride(overrideMask, overrideValue); List<Integer> tempList = new ArrayList<>(); for (int networkType : networkTypes) { tempList.add(networkType); } log("Subscription override: overrideMask=" + overrideMask + ", overrideValue=" + overrideValue + ", networkTypes=" + tempList); if (overrideMask == SUBSCRIPTION_OVERRIDE_UNMETERED) { mUnmeteredNetworkTypes = tempList; mUnmeteredOverride = overrideValue != 0; reevaluateUnmeteredConnections(); } else if (overrideMask == SUBSCRIPTION_OVERRIDE_CONGESTED) { mCongestedNetworkTypes = tempList; mCongestedOverride = overrideValue != 0; reevaluateCongestedConnections(); } } Loading Loading @@ -3960,6 +3987,7 @@ public class DcTracker extends Handler { reevaluateUnmeteredConnections(); break; case DctConstants.EVENT_TELEPHONY_DISPLAY_INFO_CHANGED: reevaluateCongestedConnections(); reevaluateUnmeteredConnections(); break; case DctConstants.EVENT_CARRIER_CONFIG_CHANGED: Loading Loading @@ -4134,6 +4162,18 @@ public class DcTracker extends Handler { } } private void reevaluateCongestedConnections() { log("reevaluateCongestedConnections"); int rat = mPhone.getDisplayInfoController().getTelephonyDisplayInfo().getNetworkType(); // congested override and either network is specified or unknown and all networks specified boolean isCongested = mCongestedOverride && (mCongestedNetworkTypes.contains(rat) || mUnmeteredNetworkTypes.containsAll(Arrays.stream( TelephonyManager.getAllNetworkTypes()).boxed().collect(Collectors.toSet()))); for (DataConnection dataConnection : mDataConnections.values()) { dataConnection.onCongestednessChanged(isCongested); } } private void reevaluateUnmeteredConnections() { log("reevaluateUnmeteredConnections"); int rat = mPhone.getDisplayInfoController().getTelephonyDisplayInfo().getNetworkType(); Loading @@ -4155,6 +4195,26 @@ public class DcTracker extends Handler { } private boolean isNetworkTypeUnmetered(@NetworkType int networkType) { boolean isUnmetered; if (mUnmeteredNetworkTypes == null || !mUnmeteredOverride) { // check SubscriptionPlans if override is not defined isUnmetered = isNetworkTypeUnmeteredViaSubscriptionPlan(networkType); log("isNetworkTypeUnmeteredViaSubscriptionPlan: networkType=" + networkType + ", isUnmetered=" + isUnmetered); return isUnmetered; } // unmetered override and either network is specified or unknown and all networks specified isUnmetered = mUnmeteredNetworkTypes.contains(networkType) || mUnmeteredNetworkTypes.containsAll(Arrays.stream( TelephonyManager.getAllNetworkTypes()).boxed().collect(Collectors.toSet())); if (DBG) { log("isNetworkTypeUnmetered: networkType=" + networkType + ", isUnmetered=" + isUnmetered); } return isUnmetered; } private boolean isNetworkTypeUnmeteredViaSubscriptionPlan(@NetworkType int networkType) { if (mSubscriptionPlans == null || mSubscriptionPlans.size() == 0) { // safe return false if unable to get subscription plans or plans don't exist return false; Loading Loading @@ -4186,9 +4246,7 @@ public class DcTracker extends Handler { } private boolean isPlanUnmetered(SubscriptionPlan plan) { return plan.getDataLimitBytes() == SubscriptionPlan.BYTES_UNLIMITED && (plan.getDataLimitBehavior() == SubscriptionPlan.LIMIT_BEHAVIOR_UNKNOWN || plan.getDataLimitBehavior() == SubscriptionPlan.LIMIT_BEHAVIOR_THROTTLED); return plan.getDataLimitBytes() == SubscriptionPlan.BYTES_UNLIMITED; } private boolean isNrUnmetered() { Loading @@ -4199,13 +4257,13 @@ public class DcTracker extends Handler { if (isNetworkTypeUnmetered(NETWORK_TYPE_NR)) { if (mNrNsaMmwaveUnmetered) { if (override == TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA_MMWAVE) { if (DBG) log("NR unmetered for mmwave only via SubscriptionPlans"); if (DBG) log("NR unmetered for mmwave only"); return true; } return false; } else if (mNrNsaSub6Unmetered) { if (override == TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA) { if (DBG) log("NR unmetered for sub6 only via SubscriptionPlans"); if (DBG) log("NR unmetered for sub6 only"); return true; } return false; Loading @@ -4213,7 +4271,7 @@ public class DcTracker extends Handler { if (override == TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA_MMWAVE || override == TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA || rat == NETWORK_TYPE_NR) { if (DBG) log("NR unmetered for all frequencies via SubscriptionPlans"); if (DBG) log("NR unmetered for all frequencies"); return true; } return false; Loading tests/telephonytests/src/com/android/internal/telephony/dataconnection/DataConnectionTest.java +23 −9 Original line number Diff line number Diff line Loading @@ -18,8 +18,7 @@ package com.android.internal.telephony.dataconnection; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED; import static android.net.NetworkPolicyManager.SUBSCRIPTION_OVERRIDE_CONGESTED; import static android.net.NetworkPolicyManager.SUBSCRIPTION_OVERRIDE_UNMETERED; import static android.net.NetworkCapabilities.NET_CAPABILITY_TEMPORARILY_NOT_METERED; import static com.android.internal.telephony.TelephonyTestUtils.waitForMs; import static com.android.internal.telephony.dataconnection.DcTrackerTest.FAKE_ADDRESS; Loading Loading @@ -54,6 +53,8 @@ import android.telephony.AccessNetworkConstants; import android.telephony.AccessNetworkConstants.AccessNetworkType; import android.telephony.CarrierConfigManager; import android.telephony.ServiceState; import android.telephony.TelephonyDisplayInfo; import android.telephony.TelephonyManager; import android.telephony.data.ApnSetting; import android.telephony.data.DataCallResponse; import android.telephony.data.DataProfile; Loading Loading @@ -635,20 +636,31 @@ public class DataConnectionTest extends TelephonyTest { mContextFixture.getCarrierConfigBundle().putStringArray( CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS, new String[] { "default" }); // TODO: Remove these checks after b/176119724 is fixed. doReturn((int) TelephonyManager.NETWORK_TYPE_BITMASK_NR) .when(mPhone).getRadioAccessFamily(); mContextFixture.getCarrierConfigBundle().putBoolean( CarrierConfigManager.KEY_NETWORK_TEMP_NOT_METERED_SUPPORTED_BOOL, true); doReturn(new TelephonyDisplayInfo(TelephonyManager.NETWORK_TYPE_LTE, TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA)) .when(mDisplayInfoController).getTelephonyDisplayInfo(); doReturn(TelephonyManager.NETWORK_TYPE_LTE).when(mServiceState).getDataNetworkType(); testConnectEvent(); assertFalse(getNetworkCapabilities().hasCapability(NET_CAPABILITY_NOT_METERED)); assertFalse(getNetworkCapabilities().hasCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED)); assertTrue(getNetworkCapabilities().hasCapability(NET_CAPABILITY_NOT_CONGESTED)); mDc.onSubscriptionOverride(SUBSCRIPTION_OVERRIDE_UNMETERED, SUBSCRIPTION_OVERRIDE_UNMETERED); mDc.onMeterednessChanged(true); assertTrue(getNetworkCapabilities().hasCapability(NET_CAPABILITY_NOT_METERED)); assertFalse(getNetworkCapabilities().hasCapability(NET_CAPABILITY_NOT_METERED)); assertTrue(getNetworkCapabilities().hasCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED)); assertTrue(getNetworkCapabilities().hasCapability(NET_CAPABILITY_NOT_CONGESTED)); mDc.onSubscriptionOverride(SUBSCRIPTION_OVERRIDE_UNMETERED, 0); mDc.onMeterednessChanged(false); assertFalse(getNetworkCapabilities().hasCapability(NET_CAPABILITY_NOT_METERED)); assertFalse(getNetworkCapabilities().hasCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED)); assertTrue(getNetworkCapabilities().hasCapability(NET_CAPABILITY_NOT_CONGESTED)); } Loading @@ -660,17 +672,19 @@ public class DataConnectionTest extends TelephonyTest { testConnectEvent(); assertFalse(getNetworkCapabilities().hasCapability(NET_CAPABILITY_NOT_METERED)); assertFalse(getNetworkCapabilities().hasCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED)); assertTrue(getNetworkCapabilities().hasCapability(NET_CAPABILITY_NOT_CONGESTED)); mDc.onSubscriptionOverride(SUBSCRIPTION_OVERRIDE_CONGESTED, SUBSCRIPTION_OVERRIDE_CONGESTED); mDc.onCongestednessChanged(true); assertFalse(getNetworkCapabilities().hasCapability(NET_CAPABILITY_NOT_METERED)); assertFalse(getNetworkCapabilities().hasCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED)); assertFalse(getNetworkCapabilities().hasCapability(NET_CAPABILITY_NOT_CONGESTED)); mDc.onSubscriptionOverride(SUBSCRIPTION_OVERRIDE_CONGESTED, 0); mDc.onCongestednessChanged(false); assertFalse(getNetworkCapabilities().hasCapability(NET_CAPABILITY_NOT_METERED)); assertFalse(getNetworkCapabilities().hasCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED)); assertTrue(getNetworkCapabilities().hasCapability(NET_CAPABILITY_NOT_CONGESTED)); } Loading tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcTrackerTest.java +46 −0 Original line number Diff line number Diff line Loading @@ -1838,6 +1838,24 @@ public class DcTrackerTest extends TelephonyTest { replaceInstance(DcTracker.class, "mSubscriptionPlans", mDct, null); } private void setUpSubscriptionOverride(int[] networkTypes, boolean isUnmetered) throws Exception { List<Integer> networkTypesList = null; if (networkTypes != null) { networkTypesList = new ArrayList<>(); for (int networkType : networkTypes) { networkTypesList.add(networkType); } } replaceInstance(DcTracker.class, "mUnmeteredNetworkTypes", mDct, networkTypesList); replaceInstance(DcTracker.class, "mUnmeteredOverride", mDct, isUnmetered); } private void resetSubscriptionOverride() throws Exception { replaceInstance(DcTracker.class, "mUnmeteredNetworkTypes", mDct, null); replaceInstance(DcTracker.class, "mUnmeteredOverride", mDct, false); } private boolean isNetworkTypeUnmetered(int networkType) throws Exception { Method method = DcTracker.class.getDeclaredMethod( "isNetworkTypeUnmetered", int.class); Loading Loading @@ -1881,6 +1899,34 @@ public class DcTrackerTest extends TelephonyTest { public void testIsNetworkTypeUnmetered() throws Exception { initApns(PhoneConstants.APN_TYPE_DEFAULT, new String[]{PhoneConstants.APN_TYPE_ALL}); // only 5G unmetered setUpSubscriptionOverride(new int[]{TelephonyManager.NETWORK_TYPE_NR}, true); assertTrue(isNetworkTypeUnmetered(TelephonyManager.NETWORK_TYPE_NR)); assertFalse(isNetworkTypeUnmetered(TelephonyManager.NETWORK_TYPE_LTE)); assertFalse(isNetworkTypeUnmetered(TelephonyManager.NETWORK_TYPE_UNKNOWN)); // all network types metered setUpSubscriptionOverride(TelephonyManager.getAllNetworkTypes(), false); assertFalse(isNetworkTypeUnmetered(TelephonyManager.NETWORK_TYPE_NR)); assertFalse(isNetworkTypeUnmetered(TelephonyManager.NETWORK_TYPE_LTE)); assertFalse(isNetworkTypeUnmetered(TelephonyManager.NETWORK_TYPE_UNKNOWN)); // all network types unmetered setUpSubscriptionOverride(TelephonyManager.getAllNetworkTypes(), true); assertTrue(isNetworkTypeUnmetered(TelephonyManager.NETWORK_TYPE_NR)); assertTrue(isNetworkTypeUnmetered(TelephonyManager.NETWORK_TYPE_LTE)); assertTrue(isNetworkTypeUnmetered(TelephonyManager.NETWORK_TYPE_UNKNOWN)); resetSubscriptionOverride(); } @Test public void testIsNetworkTypeUnmeteredViaSubscriptionPlans() throws Exception { initApns(PhoneConstants.APN_TYPE_DEFAULT, new String[]{PhoneConstants.APN_TYPE_ALL}); // only 5G unmetered setUpSubscriptionPlans(true); Loading Loading
src/java/com/android/internal/telephony/dataconnection/DataConnection.java +39 −27 Original line number Diff line number Diff line Loading @@ -16,9 +16,6 @@ package com.android.internal.telephony.dataconnection; import static android.net.NetworkPolicyManager.SUBSCRIPTION_OVERRIDE_CONGESTED; import static android.net.NetworkPolicyManager.SUBSCRIPTION_OVERRIDE_UNMETERED; import static com.android.internal.telephony.dataconnection.DcTracker.REQUEST_TYPE_HANDOVER; import android.annotation.IntDef; Loading Loading @@ -294,7 +291,7 @@ public class DataConnection extends StateMachine { private int mLastFailCause; private static final String NULL_IP = "0.0.0.0"; private Object mUserData; private int mSubscriptionOverride; private boolean mCongestedOverride; private boolean mUnmeteredOverride; private int mRilRat = ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN; private int mDataRegState = Integer.MAX_VALUE; Loading Loading @@ -344,7 +341,7 @@ public class DataConnection extends StateMachine { static final int EVENT_BW_REFRESH_RESPONSE = BASE + 14; static final int EVENT_DATA_CONNECTION_VOICE_CALL_STARTED = BASE + 15; static final int EVENT_DATA_CONNECTION_VOICE_CALL_ENDED = BASE + 16; static final int EVENT_DATA_CONNECTION_OVERRIDE_CHANGED = BASE + 17; static final int EVENT_DATA_CONNECTION_CONGESTEDNESS_CHANGED = BASE + 17; static final int EVENT_KEEPALIVE_STATUS = BASE + 18; static final int EVENT_KEEPALIVE_STARTED = BASE + 19; static final int EVENT_KEEPALIVE_STOPPED = BASE + 20; Loading Loading @@ -387,8 +384,8 @@ public class DataConnection extends StateMachine { "EVENT_DATA_CONNECTION_VOICE_CALL_STARTED"; sCmdToString[EVENT_DATA_CONNECTION_VOICE_CALL_ENDED - BASE] = "EVENT_DATA_CONNECTION_VOICE_CALL_ENDED"; sCmdToString[EVENT_DATA_CONNECTION_OVERRIDE_CHANGED - BASE] = "EVENT_DATA_CONNECTION_OVERRIDE_CHANGED"; sCmdToString[EVENT_DATA_CONNECTION_CONGESTEDNESS_CHANGED - BASE] = "EVENT_DATA_CONNECTION_CONGESTEDNESS_CHANGED"; sCmdToString[EVENT_KEEPALIVE_STATUS - BASE] = "EVENT_KEEPALIVE_STATUS"; sCmdToString[EVENT_KEEPALIVE_STARTED - BASE] = "EVENT_KEEPALIVE_STARTED"; sCmdToString[EVENT_KEEPALIVE_STOPPED - BASE] = "EVENT_KEEPALIVE_STOPPED"; Loading Loading @@ -1000,14 +997,16 @@ public class DataConnection extends StateMachine { setHandoverState(HANDOVER_STATE_IDLE); } public void onSubscriptionOverride(int overrideMask, int overrideValue) { mSubscriptionOverride = (mSubscriptionOverride & ~overrideMask) | (overrideValue & overrideMask); sendMessage(obtainMessage(EVENT_DATA_CONNECTION_OVERRIDE_CHANGED)); /** * Update NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED based on congested override * @param isCongested whether this DC should be set to congested or not */ public void onCongestednessChanged(boolean isCongested) { sendMessage(obtainMessage(EVENT_DATA_CONNECTION_CONGESTEDNESS_CHANGED, isCongested)); } /** * Update NetworkCapabilities.NET_CAPABILITY_NOT_METERED based on meteredness * Update NetworkCapabilities.NET_CAPABILITY_NOT_METERED based on metered override * @param isUnmetered whether this DC should be set to unmetered or not */ public void onMeterednessChanged(boolean isUnmetered) { Loading Loading @@ -1189,7 +1188,7 @@ public class DataConnection extends StateMachine { mDcFailCause = DataFailCause.NONE; mDisabledApnTypeBitMask = 0; mSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; mSubscriptionOverride = 0; mCongestedOverride = false; mUnmeteredOverride = false; mDownlinkBandwidth = 14; mUplinkBandwidth = 14; Loading Loading @@ -1721,15 +1720,9 @@ public class DataConnection extends StateMachine { result.setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING, !mPhone.getServiceState().getDataRoaming()); result.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED); // Override values set above when requested by policy if ((mSubscriptionOverride & SUBSCRIPTION_OVERRIDE_UNMETERED) != 0) { result.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED); } if ((mSubscriptionOverride & SUBSCRIPTION_OVERRIDE_CONGESTED) != 0) { result.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED); } result.setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED, !mCongestedOverride); //result.setCapability(NetworkCapabilities.NET_CAPABILITY_TEMPORARILY_NOT_METERED, // mUnmeteredOverride); // TODO: Remove this after b/176119724 is fixed. This is just a workaround to prevent // NET_CAPABILITY_TEMPORARILY_NOT_METERED incorrectly set on devices that are not supposed Loading Loading @@ -2771,10 +2764,29 @@ public class DataConnection extends StateMachine { break; } mUnmeteredOverride = isUnmetered; // fallthrough if (mNetworkAgent != null) { mNetworkAgent.updateLegacySubtype(DataConnection.this); mNetworkAgent.sendNetworkCapabilities(getNetworkCapabilities(), DataConnection.this); } retVal = HANDLED; break; case EVENT_DATA_CONNECTION_CONGESTEDNESS_CHANGED: boolean isCongested = (boolean) msg.obj; if (isCongested == mCongestedOverride) { retVal = HANDLED; break; } mCongestedOverride = isCongested; if (mNetworkAgent != null) { mNetworkAgent.updateLegacySubtype(DataConnection.this); mNetworkAgent.sendNetworkCapabilities(getNetworkCapabilities(), DataConnection.this); } retVal = HANDLED; break; case EVENT_DATA_CONNECTION_ROAM_ON: case EVENT_DATA_CONNECTION_ROAM_OFF: case EVENT_DATA_CONNECTION_OVERRIDE_CHANGED: { case EVENT_DATA_CONNECTION_ROAM_OFF: { if (mNetworkAgent != null) { mNetworkAgent.updateLegacySubtype(DataConnection.this); mNetworkAgent.sendNetworkCapabilities(getNetworkCapabilities(), Loading Loading @@ -3561,7 +3573,7 @@ public class DataConnection extends StateMachine { * Dump the current state. * * @param fd * @param pw * @param printWriter * @param args */ @Override Loading Loading @@ -3593,10 +3605,10 @@ public class DataConnection extends StateMachine { pw.println("mLastFailTime=" + TimeUtils.logTimeOfDay(mLastFailTime)); pw.println("mLastFailCause=" + DataFailCause.toString(mLastFailCause)); pw.println("mUserData=" + mUserData); pw.println("mSubscriptionOverride=" + Integer.toHexString(mSubscriptionOverride)); pw.println("mRestrictedNetworkOverride=" + mRestrictedNetworkOverride); pw.println("mUnmeteredUseOnly=" + mUnmeteredUseOnly); pw.println("mUnmeteredOverride=" + mUnmeteredOverride); pw.println("mCongestedOverride=" + mCongestedOverride); pw.println("mDownlinkBandwidth" + mDownlinkBandwidth); pw.println("mUplinkBandwidth=" + mUplinkBandwidth); pw.println("mDefaultQos=" + mDefaultQos); Loading
src/java/com/android/internal/telephony/dataconnection/DcTracker.java +67 −9 Original line number Diff line number Diff line Loading @@ -17,6 +17,8 @@ package com.android.internal.telephony.dataconnection; import static android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE; import static android.net.NetworkPolicyManager.SUBSCRIPTION_OVERRIDE_CONGESTED; import static android.net.NetworkPolicyManager.SUBSCRIPTION_OVERRIDE_UNMETERED; import static android.telephony.TelephonyManager.NETWORK_TYPE_LTE; import static android.telephony.TelephonyManager.NETWORK_TYPE_NR; import static android.telephony.data.ApnSetting.PROTOCOL_IPV4V6; Loading Loading @@ -347,6 +349,16 @@ public class DcTracker extends Handler { /* List of SubscriptionPlans, updated when initialized and when plans are changed. */ private List<SubscriptionPlan> mSubscriptionPlans = null; /* List of network types an unmetered override applies to, set by onSubscriptionOverride * and cleared when the device is rebooted or the override expires. */ private List<Integer> mUnmeteredNetworkTypes = null; /* List of network types a congested override applies to, set by onSubscriptionOverride * and cleared when the device is rebooted or the override expires. */ private List<Integer> mCongestedNetworkTypes = null; /* Whether an unmetered override is currently active. */ private boolean mUnmeteredOverride = false; /* Whether a congested override is currently active. */ private boolean mCongestedOverride = false; @SimState private int mSimState = TelephonyManager.SIM_STATE_UNKNOWN; Loading Loading @@ -427,11 +439,26 @@ public class DcTracker extends Handler { private final NetworkPolicyManager.SubscriptionCallback mSubscriptionCallback = new NetworkPolicyManager.SubscriptionCallback() { @Override public void onSubscriptionOverride(int subId, int overrideMask, int overrideValue) { public void onSubscriptionOverride(int subId, int overrideMask, int overrideValue, int[] networkTypes) { if (mPhone == null || mPhone.getSubId() != subId) return; for (DataConnection dataConnection : mDataConnections.values()) { dataConnection.onSubscriptionOverride(overrideMask, overrideValue); List<Integer> tempList = new ArrayList<>(); for (int networkType : networkTypes) { tempList.add(networkType); } log("Subscription override: overrideMask=" + overrideMask + ", overrideValue=" + overrideValue + ", networkTypes=" + tempList); if (overrideMask == SUBSCRIPTION_OVERRIDE_UNMETERED) { mUnmeteredNetworkTypes = tempList; mUnmeteredOverride = overrideValue != 0; reevaluateUnmeteredConnections(); } else if (overrideMask == SUBSCRIPTION_OVERRIDE_CONGESTED) { mCongestedNetworkTypes = tempList; mCongestedOverride = overrideValue != 0; reevaluateCongestedConnections(); } } Loading Loading @@ -3960,6 +3987,7 @@ public class DcTracker extends Handler { reevaluateUnmeteredConnections(); break; case DctConstants.EVENT_TELEPHONY_DISPLAY_INFO_CHANGED: reevaluateCongestedConnections(); reevaluateUnmeteredConnections(); break; case DctConstants.EVENT_CARRIER_CONFIG_CHANGED: Loading Loading @@ -4134,6 +4162,18 @@ public class DcTracker extends Handler { } } private void reevaluateCongestedConnections() { log("reevaluateCongestedConnections"); int rat = mPhone.getDisplayInfoController().getTelephonyDisplayInfo().getNetworkType(); // congested override and either network is specified or unknown and all networks specified boolean isCongested = mCongestedOverride && (mCongestedNetworkTypes.contains(rat) || mUnmeteredNetworkTypes.containsAll(Arrays.stream( TelephonyManager.getAllNetworkTypes()).boxed().collect(Collectors.toSet()))); for (DataConnection dataConnection : mDataConnections.values()) { dataConnection.onCongestednessChanged(isCongested); } } private void reevaluateUnmeteredConnections() { log("reevaluateUnmeteredConnections"); int rat = mPhone.getDisplayInfoController().getTelephonyDisplayInfo().getNetworkType(); Loading @@ -4155,6 +4195,26 @@ public class DcTracker extends Handler { } private boolean isNetworkTypeUnmetered(@NetworkType int networkType) { boolean isUnmetered; if (mUnmeteredNetworkTypes == null || !mUnmeteredOverride) { // check SubscriptionPlans if override is not defined isUnmetered = isNetworkTypeUnmeteredViaSubscriptionPlan(networkType); log("isNetworkTypeUnmeteredViaSubscriptionPlan: networkType=" + networkType + ", isUnmetered=" + isUnmetered); return isUnmetered; } // unmetered override and either network is specified or unknown and all networks specified isUnmetered = mUnmeteredNetworkTypes.contains(networkType) || mUnmeteredNetworkTypes.containsAll(Arrays.stream( TelephonyManager.getAllNetworkTypes()).boxed().collect(Collectors.toSet())); if (DBG) { log("isNetworkTypeUnmetered: networkType=" + networkType + ", isUnmetered=" + isUnmetered); } return isUnmetered; } private boolean isNetworkTypeUnmeteredViaSubscriptionPlan(@NetworkType int networkType) { if (mSubscriptionPlans == null || mSubscriptionPlans.size() == 0) { // safe return false if unable to get subscription plans or plans don't exist return false; Loading Loading @@ -4186,9 +4246,7 @@ public class DcTracker extends Handler { } private boolean isPlanUnmetered(SubscriptionPlan plan) { return plan.getDataLimitBytes() == SubscriptionPlan.BYTES_UNLIMITED && (plan.getDataLimitBehavior() == SubscriptionPlan.LIMIT_BEHAVIOR_UNKNOWN || plan.getDataLimitBehavior() == SubscriptionPlan.LIMIT_BEHAVIOR_THROTTLED); return plan.getDataLimitBytes() == SubscriptionPlan.BYTES_UNLIMITED; } private boolean isNrUnmetered() { Loading @@ -4199,13 +4257,13 @@ public class DcTracker extends Handler { if (isNetworkTypeUnmetered(NETWORK_TYPE_NR)) { if (mNrNsaMmwaveUnmetered) { if (override == TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA_MMWAVE) { if (DBG) log("NR unmetered for mmwave only via SubscriptionPlans"); if (DBG) log("NR unmetered for mmwave only"); return true; } return false; } else if (mNrNsaSub6Unmetered) { if (override == TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA) { if (DBG) log("NR unmetered for sub6 only via SubscriptionPlans"); if (DBG) log("NR unmetered for sub6 only"); return true; } return false; Loading @@ -4213,7 +4271,7 @@ public class DcTracker extends Handler { if (override == TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA_MMWAVE || override == TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA || rat == NETWORK_TYPE_NR) { if (DBG) log("NR unmetered for all frequencies via SubscriptionPlans"); if (DBG) log("NR unmetered for all frequencies"); return true; } return false; Loading
tests/telephonytests/src/com/android/internal/telephony/dataconnection/DataConnectionTest.java +23 −9 Original line number Diff line number Diff line Loading @@ -18,8 +18,7 @@ package com.android.internal.telephony.dataconnection; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED; import static android.net.NetworkPolicyManager.SUBSCRIPTION_OVERRIDE_CONGESTED; import static android.net.NetworkPolicyManager.SUBSCRIPTION_OVERRIDE_UNMETERED; import static android.net.NetworkCapabilities.NET_CAPABILITY_TEMPORARILY_NOT_METERED; import static com.android.internal.telephony.TelephonyTestUtils.waitForMs; import static com.android.internal.telephony.dataconnection.DcTrackerTest.FAKE_ADDRESS; Loading Loading @@ -54,6 +53,8 @@ import android.telephony.AccessNetworkConstants; import android.telephony.AccessNetworkConstants.AccessNetworkType; import android.telephony.CarrierConfigManager; import android.telephony.ServiceState; import android.telephony.TelephonyDisplayInfo; import android.telephony.TelephonyManager; import android.telephony.data.ApnSetting; import android.telephony.data.DataCallResponse; import android.telephony.data.DataProfile; Loading Loading @@ -635,20 +636,31 @@ public class DataConnectionTest extends TelephonyTest { mContextFixture.getCarrierConfigBundle().putStringArray( CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS, new String[] { "default" }); // TODO: Remove these checks after b/176119724 is fixed. doReturn((int) TelephonyManager.NETWORK_TYPE_BITMASK_NR) .when(mPhone).getRadioAccessFamily(); mContextFixture.getCarrierConfigBundle().putBoolean( CarrierConfigManager.KEY_NETWORK_TEMP_NOT_METERED_SUPPORTED_BOOL, true); doReturn(new TelephonyDisplayInfo(TelephonyManager.NETWORK_TYPE_LTE, TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA)) .when(mDisplayInfoController).getTelephonyDisplayInfo(); doReturn(TelephonyManager.NETWORK_TYPE_LTE).when(mServiceState).getDataNetworkType(); testConnectEvent(); assertFalse(getNetworkCapabilities().hasCapability(NET_CAPABILITY_NOT_METERED)); assertFalse(getNetworkCapabilities().hasCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED)); assertTrue(getNetworkCapabilities().hasCapability(NET_CAPABILITY_NOT_CONGESTED)); mDc.onSubscriptionOverride(SUBSCRIPTION_OVERRIDE_UNMETERED, SUBSCRIPTION_OVERRIDE_UNMETERED); mDc.onMeterednessChanged(true); assertTrue(getNetworkCapabilities().hasCapability(NET_CAPABILITY_NOT_METERED)); assertFalse(getNetworkCapabilities().hasCapability(NET_CAPABILITY_NOT_METERED)); assertTrue(getNetworkCapabilities().hasCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED)); assertTrue(getNetworkCapabilities().hasCapability(NET_CAPABILITY_NOT_CONGESTED)); mDc.onSubscriptionOverride(SUBSCRIPTION_OVERRIDE_UNMETERED, 0); mDc.onMeterednessChanged(false); assertFalse(getNetworkCapabilities().hasCapability(NET_CAPABILITY_NOT_METERED)); assertFalse(getNetworkCapabilities().hasCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED)); assertTrue(getNetworkCapabilities().hasCapability(NET_CAPABILITY_NOT_CONGESTED)); } Loading @@ -660,17 +672,19 @@ public class DataConnectionTest extends TelephonyTest { testConnectEvent(); assertFalse(getNetworkCapabilities().hasCapability(NET_CAPABILITY_NOT_METERED)); assertFalse(getNetworkCapabilities().hasCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED)); assertTrue(getNetworkCapabilities().hasCapability(NET_CAPABILITY_NOT_CONGESTED)); mDc.onSubscriptionOverride(SUBSCRIPTION_OVERRIDE_CONGESTED, SUBSCRIPTION_OVERRIDE_CONGESTED); mDc.onCongestednessChanged(true); assertFalse(getNetworkCapabilities().hasCapability(NET_CAPABILITY_NOT_METERED)); assertFalse(getNetworkCapabilities().hasCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED)); assertFalse(getNetworkCapabilities().hasCapability(NET_CAPABILITY_NOT_CONGESTED)); mDc.onSubscriptionOverride(SUBSCRIPTION_OVERRIDE_CONGESTED, 0); mDc.onCongestednessChanged(false); assertFalse(getNetworkCapabilities().hasCapability(NET_CAPABILITY_NOT_METERED)); assertFalse(getNetworkCapabilities().hasCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED)); assertTrue(getNetworkCapabilities().hasCapability(NET_CAPABILITY_NOT_CONGESTED)); } Loading
tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcTrackerTest.java +46 −0 Original line number Diff line number Diff line Loading @@ -1838,6 +1838,24 @@ public class DcTrackerTest extends TelephonyTest { replaceInstance(DcTracker.class, "mSubscriptionPlans", mDct, null); } private void setUpSubscriptionOverride(int[] networkTypes, boolean isUnmetered) throws Exception { List<Integer> networkTypesList = null; if (networkTypes != null) { networkTypesList = new ArrayList<>(); for (int networkType : networkTypes) { networkTypesList.add(networkType); } } replaceInstance(DcTracker.class, "mUnmeteredNetworkTypes", mDct, networkTypesList); replaceInstance(DcTracker.class, "mUnmeteredOverride", mDct, isUnmetered); } private void resetSubscriptionOverride() throws Exception { replaceInstance(DcTracker.class, "mUnmeteredNetworkTypes", mDct, null); replaceInstance(DcTracker.class, "mUnmeteredOverride", mDct, false); } private boolean isNetworkTypeUnmetered(int networkType) throws Exception { Method method = DcTracker.class.getDeclaredMethod( "isNetworkTypeUnmetered", int.class); Loading Loading @@ -1881,6 +1899,34 @@ public class DcTrackerTest extends TelephonyTest { public void testIsNetworkTypeUnmetered() throws Exception { initApns(PhoneConstants.APN_TYPE_DEFAULT, new String[]{PhoneConstants.APN_TYPE_ALL}); // only 5G unmetered setUpSubscriptionOverride(new int[]{TelephonyManager.NETWORK_TYPE_NR}, true); assertTrue(isNetworkTypeUnmetered(TelephonyManager.NETWORK_TYPE_NR)); assertFalse(isNetworkTypeUnmetered(TelephonyManager.NETWORK_TYPE_LTE)); assertFalse(isNetworkTypeUnmetered(TelephonyManager.NETWORK_TYPE_UNKNOWN)); // all network types metered setUpSubscriptionOverride(TelephonyManager.getAllNetworkTypes(), false); assertFalse(isNetworkTypeUnmetered(TelephonyManager.NETWORK_TYPE_NR)); assertFalse(isNetworkTypeUnmetered(TelephonyManager.NETWORK_TYPE_LTE)); assertFalse(isNetworkTypeUnmetered(TelephonyManager.NETWORK_TYPE_UNKNOWN)); // all network types unmetered setUpSubscriptionOverride(TelephonyManager.getAllNetworkTypes(), true); assertTrue(isNetworkTypeUnmetered(TelephonyManager.NETWORK_TYPE_NR)); assertTrue(isNetworkTypeUnmetered(TelephonyManager.NETWORK_TYPE_LTE)); assertTrue(isNetworkTypeUnmetered(TelephonyManager.NETWORK_TYPE_UNKNOWN)); resetSubscriptionOverride(); } @Test public void testIsNetworkTypeUnmeteredViaSubscriptionPlans() throws Exception { initApns(PhoneConstants.APN_TYPE_DEFAULT, new String[]{PhoneConstants.APN_TYPE_ALL}); // only 5G unmetered setUpSubscriptionPlans(true); Loading