Loading src/java/com/android/internal/telephony/dataconnection/DataConnection.java +74 −22 Original line number Diff line number Diff line Loading @@ -563,7 +563,9 @@ public class DataConnection extends StateMachine { ERROR_RADIO_NOT_AVAILABLE, ERROR_INVALID_ARG, ERROR_STALE, ERROR_DATA_SERVICE_SPECIFIC_ERROR; ERROR_DATA_SERVICE_SPECIFIC_ERROR, ERROR_DUPLICATE_CID, ERROR_NO_DEFAULT_CONNECTION; public int mFailCause; Loading Loading @@ -636,7 +638,7 @@ public class DataConnection extends StateMachine { public void updateQosParameters(final @Nullable DataCallResponse response) { if (response == null) { mDefaultQos = null; mQosBearerSessions = null; mQosBearerSessions.clear(); return; } Loading Loading @@ -879,7 +881,7 @@ public class DataConnection extends StateMachine { String dnn = null; String osAppId = null; if (cp.mApnContext.getApnTypeBitmask() == ApnSetting.TYPE_ENTERPRISE) { // TODO: update osAppId to use NetworkCapability API once it's available // TODO(b/181916712): update osAppId to use NetworkCapability API once it's available osAppId = ApnSetting.getApnTypesStringFromBitmask(mApnSetting.getApnTypeBitmask()); } else { dnn = mApnSetting.getApnName(); Loading Loading @@ -1308,6 +1310,7 @@ public class DataConnection extends StateMachine { mApnContexts.clear(); mApnSetting = null; mUnmeteredUseOnly = false; mEnterpriseUse = false; mRestrictedNetworkOverride = false; mDcFailCause = DataFailCause.NONE; mDisabledApnTypeBitMask = 0; Loading @@ -1319,6 +1322,10 @@ public class DataConnection extends StateMachine { mIsSuspended = false; mHandoverState = HANDOVER_STATE_IDLE; mHandoverFailureMode = DataCallResponse.HANDOVER_FAILURE_MODE_UNKNOWN; mSliceInfo = null; mDefaultQos = null; mQosBearerSessions.clear(); mTrafficDescriptors.clear(); } /** Loading Loading @@ -1351,6 +1358,14 @@ public class DataConnection extends StateMachine { result = SetupResult.ERROR_DATA_SERVICE_SPECIFIC_ERROR; result.mFailCause = DataFailCause.getFailCause(response.getCause()); } } else if (cp.mApnContext.getApnTypeBitmask() == ApnSetting.TYPE_ENTERPRISE && mDcController.getActiveDcByCid(response.getId()) != null) { if (DBG) log("DataConnection already exists for cid: " + response.getId()); result = SetupResult.ERROR_DUPLICATE_CID; } else if (cp.mApnContext.getApnTypeBitmask() == ApnSetting.TYPE_ENTERPRISE && !mDcController.isDefaultDataActive()) { if (DBG) log("No default data connection currently active"); result = SetupResult.ERROR_NO_DEFAULT_CONNECTION; } else { if (DBG) log("onSetupConnectionCompleted received successful DataCallResponse"); mCid = response.getId(); Loading Loading @@ -1615,6 +1630,14 @@ public class DataConnection extends StateMachine { */ private boolean mRestrictedNetworkOverride = false; /** * Indicates if this data connection supports enterprise use. Note that this flag should be * populated when data becomes active. Once it is set, the value cannot be changed because * setting it will cause this data connection to lose immutable network capabilities, which can * cause issues in connectivity service. */ private boolean mEnterpriseUse = false; /** * Check if this data connection should be restricted. We should call this when data connection * becomes active, or when we want to re-evaluate the conditions to decide if we need to Loading @@ -1622,7 +1645,6 @@ public class DataConnection extends StateMachine { * * @return True if this data connection needs to be restricted. */ private boolean shouldRestrictNetwork() { // first, check if there is any network request that containing restricted capability // (i.e. Do not have NET_CAPABILITY_NOT_RESTRICTED in the request) Loading Loading @@ -1692,6 +1714,25 @@ public class DataConnection extends StateMachine { return true; } /** * Check if this data connection supports enterprise use. We call this when the data connection * becomes active or when we want to reevaluate the conditions to decide if we need to update * the network agent capabilities. * * @return True if this data connection supports enterprise use. */ private boolean isEnterpriseUse() { // TODO(b/181916712): update osAppId to use NetworkCapability API once it's available boolean enterpriseTrafficDescriptor = mTrafficDescriptors .stream() .anyMatch(td -> td.getOsAppId() != null && td.getOsAppId().equals( ApnSetting.TYPE_ENTERPRISE_STRING)); boolean enterpriseApnContext = mApnContexts.keySet() .stream() .anyMatch(ac -> ac.getApnTypeBitmask() == ApnSetting.TYPE_ENTERPRISE); return enterpriseTrafficDescriptor || enterpriseApnContext; } /** * Get the network capabilities for this data connection. * Loading @@ -1701,8 +1742,9 @@ public class DataConnection extends StateMachine { final NetworkCapabilities.Builder builder = new NetworkCapabilities.Builder() .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR); boolean hasInternet = false; boolean unmeteredApns = false; if (mApnSetting != null) { if (mApnSetting != null && !mEnterpriseUse) { final String[] types = ApnSetting.getApnTypesStringFromBitmask( mApnSetting.getApnTypeBitmask() & ~mDisabledApnTypeBitMask).split(","); for (String type : types) { Loading Loading @@ -1776,11 +1818,15 @@ public class DataConnection extends StateMachine { builder.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); } if (!ApnSettingUtils.isMetered(mApnSetting, mPhone)) { unmeteredApns = true; } } // Mark NOT_METERED in the following cases: // 1. All APNs in the APN settings are unmetered. // 2. The non-restricted data is intended for unmetered use only. if ((mUnmeteredUseOnly && !mRestrictedNetworkOverride) || !ApnSettingUtils.isMetered(mApnSetting, mPhone)) { if (unmeteredApns || (mUnmeteredUseOnly && !mRestrictedNetworkOverride)) { builder.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED); } else { builder.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED); Loading @@ -1790,13 +1836,10 @@ public class DataConnection extends StateMachine { if (builder.build().deduceRestrictedCapability()) { builder.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED); } } for (ApnContext ctx : mApnContexts.keySet()) { if (ctx.getApnTypeBitmask() == ApnSetting.TYPE_ENTERPRISE) { if (mEnterpriseUse) { builder.addCapability(NetworkCapabilities.NET_CAPABILITY_ENTERPRISE); } } if (mRestrictedNetworkOverride) { builder.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED); Loading Loading @@ -2529,6 +2572,12 @@ public class DataConnection extends StateMachine { DataCallResponse.HANDOVER_FAILURE_MODE_UNKNOWN); transitionTo(mInactiveState); break; case ERROR_DUPLICATE_CID: // TODO (b/180988471): Properly handle the case when an existing cid is // returned by tearing down the network agent if enterprise changed. case ERROR_NO_DEFAULT_CONNECTION: // TODO (b/180988471): Properly handle the case when a default data // connection doesn't exist. case ERROR_INVALID_ARG: // The addresses given from the RIL are bad tearDownData(cp); Loading Loading @@ -2659,10 +2708,12 @@ public class DataConnection extends StateMachine { } mUnmeteredUseOnly = isUnmeteredUseOnly(); mEnterpriseUse = isEnterpriseUse(); if (DBG) { log("mRestrictedNetworkOverride = " + mRestrictedNetworkOverride + ", mUnmeteredUseOnly = " + mUnmeteredUseOnly); + ", mUnmeteredUseOnly = " + mUnmeteredUseOnly + ", mEnterpriseUse = " + mEnterpriseUse); } // Always register a VcnNetworkPolicyChangeListener, regardless of whether this is a Loading Loading @@ -3773,6 +3824,7 @@ public class DataConnection extends StateMachine { pw.println("mUserData=" + mUserData); pw.println("mRestrictedNetworkOverride=" + mRestrictedNetworkOverride); pw.println("mUnmeteredUseOnly=" + mUnmeteredUseOnly); pw.println("mEnterpriseUse=" + mEnterpriseUse); pw.println("mUnmeteredOverride=" + mUnmeteredOverride); pw.println("mCongestedOverride=" + mCongestedOverride); pw.println("mDownlinkBandwidth" + mDownlinkBandwidth); Loading src/java/com/android/internal/telephony/dataconnection/DcController.java +9 −0 Original line number Diff line number Diff line Loading @@ -26,6 +26,7 @@ import android.os.Message; import android.os.RegistrantList; import android.telephony.AccessNetworkConstants; import android.telephony.DataFailCause; import android.telephony.data.ApnSetting; import android.telephony.data.DataCallResponse; import com.android.internal.telephony.DctConstants; Loading Loading @@ -161,6 +162,14 @@ public class DcController extends Handler { } } boolean isDefaultDataActive() { synchronized (mDcListAll) { return mDcListActiveByCid.values().stream() .anyMatch(dc -> dc.getApnContexts().stream() .anyMatch(apn -> apn.getApnTypeBitmask() == ApnSetting.TYPE_DEFAULT)); } } @Override public void handleMessage(Message msg) { AsyncResult ar; Loading tests/telephonytests/src/com/android/internal/telephony/SimulatedCommands.java +0 −9 Original line number Diff line number Diff line Loading @@ -47,7 +47,6 @@ import android.telephony.ServiceState; import android.telephony.SignalStrength; import android.telephony.SignalThresholdInfo; import android.telephony.TelephonyManager; import android.telephony.data.ApnSetting; import android.telephony.data.DataCallResponse; import android.telephony.data.DataProfile; import android.telephony.data.SliceInfo; Loading Loading @@ -1216,14 +1215,6 @@ public class SimulatedCommands extends BaseCommands } } // Store different cids to simulate concurrent IMS and default data calls if ((dataProfile.getSupportedApnTypesBitmask() & ApnSetting.TYPE_IMS) == ApnSetting.TYPE_IMS) { mSetupDataCallResult.cid = 0; } else { mSetupDataCallResult.cid = 1; } DataCallResponse response = RIL.convertDataCallResult(mSetupDataCallResult); if (mDcSuccess) { resultSuccess(result, response); Loading tests/telephonytests/src/com/android/internal/telephony/dataconnection/DataConnectionTest.java +153 −17 Original line number Diff line number Diff line Loading @@ -42,6 +42,7 @@ import static org.mockito.Mockito.verify; import android.content.IntentFilter; import android.content.pm.ServiceInfo; import android.hardware.radio.V1_0.SetupDataCallResult; import android.net.InetAddresses; import android.net.KeepalivePacketData; import android.net.LinkAddress; Loading Loading @@ -86,6 +87,7 @@ import java.util.Arrays; import java.util.Collections; public class DataConnectionTest extends TelephonyTest { private static final int DEFAULT_DC_CID = 10; @Mock DcTesterFailBringUpAll mDcTesterFailBringUpAll; Loading @@ -96,9 +98,13 @@ public class DataConnectionTest extends TelephonyTest { @Mock ApnContext mApnContext; @Mock ApnContext mEnterpriseApnContext; @Mock DcFailBringUp mDcFailBringUp; @Mock DataCallSessionStats mDataCallSessionStats; @Mock DataConnection mDefaultDc; private DataConnection mDc; private DataConnectionTestHandler mDataConnectionTestHandler; Loading Loading @@ -290,6 +296,7 @@ public class DataConnectionTest extends TelephonyTest { ServiceState.RIL_RADIO_TECHNOLOGY_UMTS); doReturn(mApn1).when(mApnContext).getApnSetting(); doReturn(ApnSetting.TYPE_DEFAULT_STRING).when(mApnContext).getApnType(); doReturn(ApnSetting.TYPE_DEFAULT).when(mApnContext).getApnTypeBitmask(); mDcFailBringUp.saveParameters(0, 0, -2); doReturn(mDcFailBringUp).when(mDcTesterFailBringUpAll).getDcFailBringUp(); Loading Loading @@ -353,8 +360,13 @@ public class DataConnectionTest extends TelephonyTest { return (boolean) method.invoke(mDc); } private SetupResult setLinkProperties(DataCallResponse response, LinkProperties linkProperties) private boolean isEnterpriseUse() throws Exception { Method method = DataConnection.class.getDeclaredMethod("isEnterpriseUse"); method.setAccessible(true); return (boolean) method.invoke(mDc); } private SetupResult setLinkProperties(DataCallResponse response, LinkProperties linkProperties) throws Exception { Class[] cArgs = new Class[2]; cArgs[0] = DataCallResponse.class; Loading @@ -374,9 +386,7 @@ public class DataConnectionTest extends TelephonyTest { @SmallTest public void testConnectEvent() throws Exception { testSanity(); mDc.sendMessage(DataConnection.EVENT_CONNECT, mCp); waitForMs(200); connectEvent(true); verify(mCT, times(1)).registerForVoiceCallStarted(any(Handler.class), eq(DataConnection.EVENT_DATA_CONNECTION_VOICE_CALL_STARTED), eq(null)); Loading Loading @@ -417,7 +427,7 @@ public class DataConnectionTest extends TelephonyTest { assertEquals(null, tdCaptor.getValue().getOsAppId()); } } assertEquals("DcActiveState", getCurrentState().getName()); assertTrue(mDc.isActive()); assertEquals(mDc.getPduSessionId(), 1); assertEquals(3, mDc.getPcscfAddresses().length); Loading @@ -426,14 +436,86 @@ public class DataConnectionTest extends TelephonyTest { assertTrue(Arrays.stream(mDc.getPcscfAddresses()).anyMatch("fd00:976a:c305:1d::5"::equals)); } @Test public void testConnectEventDuplicateContextIds() throws Exception { setUpDefaultData(); // Create successful result with the same CID as default SetupDataCallResult result = new SetupDataCallResult(); result.status = 0; result.suggestedRetryTime = -1; result.cid = DEFAULT_DC_CID; result.active = 2; result.type = "IP"; result.ifname = FAKE_IFNAME; result.addresses = FAKE_ADDRESS; result.dnses = FAKE_DNS; result.gateways = FAKE_GATEWAY; result.pcscf = FAKE_PCSCF_ADDRESS; result.mtu = 1440; mSimulatedCommands.setDataCallResult(true, result); // Try to connect ENTERPRISE with the same CID as default replaceInstance(ConnectionParams.class, "mApnContext", mCp, mEnterpriseApnContext); doReturn(mApn1).when(mEnterpriseApnContext).getApnSetting(); doReturn(ApnSetting.TYPE_ENTERPRISE_STRING).when(mEnterpriseApnContext).getApnType(); doReturn(ApnSetting.TYPE_ENTERPRISE).when(mEnterpriseApnContext).getApnTypeBitmask(); // Verify that ENTERPRISE wasn't set up connectEvent(false); assertEquals("DcInactiveState", getCurrentState().getName()); // Change the CID result.cid = DEFAULT_DC_CID + 1; mSimulatedCommands.setDataCallResult(true, result); // Verify that ENTERPRISE was set up connectEvent(true); assertTrue(mDc.getNetworkCapabilities().hasCapability( NetworkCapabilities.NET_CAPABILITY_ENTERPRISE)); } @Test public void testConnectEventNoDefaultData() throws Exception { assertFalse(mDefaultDc.isActive()); // Try to connect ENTERPRISE when default data doesn't exist replaceInstance(ConnectionParams.class, "mApnContext", mCp, mEnterpriseApnContext); doReturn(mApn1).when(mEnterpriseApnContext).getApnSetting(); doReturn(ApnSetting.TYPE_ENTERPRISE_STRING).when(mEnterpriseApnContext).getApnType(); doReturn(ApnSetting.TYPE_ENTERPRISE).when(mEnterpriseApnContext).getApnTypeBitmask(); // Verify that ENTERPRISE wasn't set up connectEvent(false); assertEquals("DcInactiveState", getCurrentState().getName()); // Set up default data replaceInstance(ConnectionParams.class, "mApnContext", mCp, mApnContext); setUpDefaultData(); // Verify that ENTERPRISE was set up replaceInstance(ConnectionParams.class, "mApnContext", mCp, mEnterpriseApnContext); connectEvent(true); assertTrue(mDc.getNetworkCapabilities().hasCapability( NetworkCapabilities.NET_CAPABILITY_ENTERPRISE)); } private void setUpDefaultData() throws Exception { replaceInstance(DataConnection.class, "mCid", mDefaultDc, DEFAULT_DC_CID); doReturn(true).when(mDefaultDc).isActive(); doReturn(Arrays.asList(mApnContext)).when(mDefaultDc).getApnContexts(); mDcc.addActiveDcByCid(mDefaultDc); assertTrue(mDefaultDc.getApnContexts().stream() .anyMatch(apn -> apn.getApnTypeBitmask() == ApnSetting.TYPE_DEFAULT)); } @Test @SmallTest public void testDisconnectEvent() throws Exception { testConnectEvent(); mDc.setPduSessionId(5); mDc.sendMessage(DataConnection.EVENT_DISCONNECT, mDcp); waitForMs(100); disconnectEvent(); verify(mSimulatedCommandsVerifier, times(1)).unregisterForLceInfo(any(Handler.class)); verify(mSimulatedCommandsVerifier, times(1)) Loading Loading @@ -618,12 +700,9 @@ public class DataConnectionTest extends TelephonyTest { CarrierConfigManager.KEY_CARRIER_WWAN_DISALLOWED_APN_TYPES_STRING_ARRAY, new String[] {"supl"}); mDc.sendMessage(DataConnection.EVENT_DISCONNECT, mDcp); waitForMs(100); disconnectEvent(); doReturn(mApn1).when(mApnContext).getApnSetting(); doReturn(ApnSetting.TYPE_ENTERPRISE).when(mApnContext).getApnTypeBitmask(); mDc.sendMessage(DataConnection.EVENT_CONNECT, mCp); waitForMs(200); connectEvent(true); assertFalse("capabilities: " + getNetworkCapabilities(), getNetworkCapabilities() .hasCapability(NetworkCapabilities.NET_CAPABILITY_DUN)); Loading @@ -631,6 +710,42 @@ public class DataConnectionTest extends TelephonyTest { .hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)); assertFalse("capabilities: " + getNetworkCapabilities(), getNetworkCapabilities() .hasCapability(NetworkCapabilities.NET_CAPABILITY_SUPL)); assertFalse("capabilities: " + getNetworkCapabilities(), getNetworkCapabilities() .hasCapability(NetworkCapabilities.NET_CAPABILITY_ENTERPRISE)); } @Test @SmallTest public void testEnterpriseNetworkCapability() throws Exception { mContextFixture.getCarrierConfigBundle().putStringArray( CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS, new String[] { "default" }); doReturn(mApn2).when(mApnContext).getApnSetting(); testConnectEvent(); assertTrue("capabilities: " + getNetworkCapabilities(), getNetworkCapabilities() .hasCapability(NetworkCapabilities.NET_CAPABILITY_DUN)); assertTrue("capabilities: " + getNetworkCapabilities(), getNetworkCapabilities() .hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)); assertFalse("capabilities: " + getNetworkCapabilities(), getNetworkCapabilities() .hasCapability(NetworkCapabilities.NET_CAPABILITY_MMS)); assertFalse("capabilities: " + getNetworkCapabilities(), getNetworkCapabilities() .hasCapability(NetworkCapabilities.NET_CAPABILITY_ENTERPRISE)); disconnectEvent(); setUpDefaultData(); replaceInstance(ConnectionParams.class, "mApnContext", mCp, mEnterpriseApnContext); doReturn(mApn1).when(mEnterpriseApnContext).getApnSetting(); doReturn(ApnSetting.TYPE_ENTERPRISE_STRING).when(mEnterpriseApnContext).getApnType(); doReturn(ApnSetting.TYPE_ENTERPRISE).when(mEnterpriseApnContext).getApnTypeBitmask(); connectEvent(true); assertFalse("capabilities: " + getNetworkCapabilities(), getNetworkCapabilities() .hasCapability(NetworkCapabilities.NET_CAPABILITY_DUN)); assertFalse("capabilities: " + getNetworkCapabilities(), getNetworkCapabilities() .hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)); assertFalse("capabilities: " + getNetworkCapabilities(), getNetworkCapabilities() .hasCapability(NetworkCapabilities.NET_CAPABILITY_SUPL)); assertTrue("capabilities: " + getNetworkCapabilities(), getNetworkCapabilities() .hasCapability(NetworkCapabilities.NET_CAPABILITY_ENTERPRISE)); } Loading Loading @@ -740,16 +855,19 @@ public class DataConnectionTest extends TelephonyTest { method.setAccessible(true); doReturn(apn).when(mApnContext).getApnSetting(); connectEvent(); doReturn(apn.getApnTypeBitmask()).when(mApnContext).getApnTypeBitmask(); connectEvent(true); logd(getNetworkCapabilities().toString()); return (Boolean) method.invoke(mDc); } private void connectEvent() throws Exception { private void connectEvent(boolean validate) { mDc.sendMessage(DataConnection.EVENT_CONNECT, mCp); waitForMs(200); assertEquals("DcActiveState", getCurrentState().getName()); if (validate) { assertTrue(mDc.isActive()); } } private void disconnectEvent() throws Exception { Loading @@ -760,7 +878,7 @@ public class DataConnectionTest extends TelephonyTest { @Test @SmallTest public void testIsIpAddress() throws Exception { public void testIsIpAddress() { // IPv4 assertTrue(DataConnection.isIpAddress("1.2.3.4")); assertTrue(DataConnection.isIpAddress("127.0.0.1")); Loading Loading @@ -1066,6 +1184,24 @@ public class DataConnectionTest extends TelephonyTest { assertTrue(isUnmeteredUseOnly()); } @Test public void testIsEnterpriseUse() throws Exception { assertFalse(isEnterpriseUse()); assertFalse(mDc.getNetworkCapabilities().hasCapability( NetworkCapabilities.NET_CAPABILITY_ENTERPRISE)); setUpDefaultData(); replaceInstance(ConnectionParams.class, "mApnContext", mCp, mEnterpriseApnContext); doReturn(mApn1).when(mEnterpriseApnContext).getApnSetting(); doReturn(ApnSetting.TYPE_ENTERPRISE_STRING).when(mEnterpriseApnContext).getApnType(); doReturn(ApnSetting.TYPE_ENTERPRISE).when(mEnterpriseApnContext).getApnTypeBitmask(); connectEvent(true); assertTrue(isEnterpriseUse()); assertTrue(mDc.getNetworkCapabilities().hasCapability( NetworkCapabilities.NET_CAPABILITY_ENTERPRISE)); } @Test @SmallTest public void testGetDisallowedApnTypes() throws Exception { Loading tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcTrackerTest.java +54 −25 File changed.Preview size limit exceeded, changes collapsed. Show changes Loading
src/java/com/android/internal/telephony/dataconnection/DataConnection.java +74 −22 Original line number Diff line number Diff line Loading @@ -563,7 +563,9 @@ public class DataConnection extends StateMachine { ERROR_RADIO_NOT_AVAILABLE, ERROR_INVALID_ARG, ERROR_STALE, ERROR_DATA_SERVICE_SPECIFIC_ERROR; ERROR_DATA_SERVICE_SPECIFIC_ERROR, ERROR_DUPLICATE_CID, ERROR_NO_DEFAULT_CONNECTION; public int mFailCause; Loading Loading @@ -636,7 +638,7 @@ public class DataConnection extends StateMachine { public void updateQosParameters(final @Nullable DataCallResponse response) { if (response == null) { mDefaultQos = null; mQosBearerSessions = null; mQosBearerSessions.clear(); return; } Loading Loading @@ -879,7 +881,7 @@ public class DataConnection extends StateMachine { String dnn = null; String osAppId = null; if (cp.mApnContext.getApnTypeBitmask() == ApnSetting.TYPE_ENTERPRISE) { // TODO: update osAppId to use NetworkCapability API once it's available // TODO(b/181916712): update osAppId to use NetworkCapability API once it's available osAppId = ApnSetting.getApnTypesStringFromBitmask(mApnSetting.getApnTypeBitmask()); } else { dnn = mApnSetting.getApnName(); Loading Loading @@ -1308,6 +1310,7 @@ public class DataConnection extends StateMachine { mApnContexts.clear(); mApnSetting = null; mUnmeteredUseOnly = false; mEnterpriseUse = false; mRestrictedNetworkOverride = false; mDcFailCause = DataFailCause.NONE; mDisabledApnTypeBitMask = 0; Loading @@ -1319,6 +1322,10 @@ public class DataConnection extends StateMachine { mIsSuspended = false; mHandoverState = HANDOVER_STATE_IDLE; mHandoverFailureMode = DataCallResponse.HANDOVER_FAILURE_MODE_UNKNOWN; mSliceInfo = null; mDefaultQos = null; mQosBearerSessions.clear(); mTrafficDescriptors.clear(); } /** Loading Loading @@ -1351,6 +1358,14 @@ public class DataConnection extends StateMachine { result = SetupResult.ERROR_DATA_SERVICE_SPECIFIC_ERROR; result.mFailCause = DataFailCause.getFailCause(response.getCause()); } } else if (cp.mApnContext.getApnTypeBitmask() == ApnSetting.TYPE_ENTERPRISE && mDcController.getActiveDcByCid(response.getId()) != null) { if (DBG) log("DataConnection already exists for cid: " + response.getId()); result = SetupResult.ERROR_DUPLICATE_CID; } else if (cp.mApnContext.getApnTypeBitmask() == ApnSetting.TYPE_ENTERPRISE && !mDcController.isDefaultDataActive()) { if (DBG) log("No default data connection currently active"); result = SetupResult.ERROR_NO_DEFAULT_CONNECTION; } else { if (DBG) log("onSetupConnectionCompleted received successful DataCallResponse"); mCid = response.getId(); Loading Loading @@ -1615,6 +1630,14 @@ public class DataConnection extends StateMachine { */ private boolean mRestrictedNetworkOverride = false; /** * Indicates if this data connection supports enterprise use. Note that this flag should be * populated when data becomes active. Once it is set, the value cannot be changed because * setting it will cause this data connection to lose immutable network capabilities, which can * cause issues in connectivity service. */ private boolean mEnterpriseUse = false; /** * Check if this data connection should be restricted. We should call this when data connection * becomes active, or when we want to re-evaluate the conditions to decide if we need to Loading @@ -1622,7 +1645,6 @@ public class DataConnection extends StateMachine { * * @return True if this data connection needs to be restricted. */ private boolean shouldRestrictNetwork() { // first, check if there is any network request that containing restricted capability // (i.e. Do not have NET_CAPABILITY_NOT_RESTRICTED in the request) Loading Loading @@ -1692,6 +1714,25 @@ public class DataConnection extends StateMachine { return true; } /** * Check if this data connection supports enterprise use. We call this when the data connection * becomes active or when we want to reevaluate the conditions to decide if we need to update * the network agent capabilities. * * @return True if this data connection supports enterprise use. */ private boolean isEnterpriseUse() { // TODO(b/181916712): update osAppId to use NetworkCapability API once it's available boolean enterpriseTrafficDescriptor = mTrafficDescriptors .stream() .anyMatch(td -> td.getOsAppId() != null && td.getOsAppId().equals( ApnSetting.TYPE_ENTERPRISE_STRING)); boolean enterpriseApnContext = mApnContexts.keySet() .stream() .anyMatch(ac -> ac.getApnTypeBitmask() == ApnSetting.TYPE_ENTERPRISE); return enterpriseTrafficDescriptor || enterpriseApnContext; } /** * Get the network capabilities for this data connection. * Loading @@ -1701,8 +1742,9 @@ public class DataConnection extends StateMachine { final NetworkCapabilities.Builder builder = new NetworkCapabilities.Builder() .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR); boolean hasInternet = false; boolean unmeteredApns = false; if (mApnSetting != null) { if (mApnSetting != null && !mEnterpriseUse) { final String[] types = ApnSetting.getApnTypesStringFromBitmask( mApnSetting.getApnTypeBitmask() & ~mDisabledApnTypeBitMask).split(","); for (String type : types) { Loading Loading @@ -1776,11 +1818,15 @@ public class DataConnection extends StateMachine { builder.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); } if (!ApnSettingUtils.isMetered(mApnSetting, mPhone)) { unmeteredApns = true; } } // Mark NOT_METERED in the following cases: // 1. All APNs in the APN settings are unmetered. // 2. The non-restricted data is intended for unmetered use only. if ((mUnmeteredUseOnly && !mRestrictedNetworkOverride) || !ApnSettingUtils.isMetered(mApnSetting, mPhone)) { if (unmeteredApns || (mUnmeteredUseOnly && !mRestrictedNetworkOverride)) { builder.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED); } else { builder.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED); Loading @@ -1790,13 +1836,10 @@ public class DataConnection extends StateMachine { if (builder.build().deduceRestrictedCapability()) { builder.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED); } } for (ApnContext ctx : mApnContexts.keySet()) { if (ctx.getApnTypeBitmask() == ApnSetting.TYPE_ENTERPRISE) { if (mEnterpriseUse) { builder.addCapability(NetworkCapabilities.NET_CAPABILITY_ENTERPRISE); } } if (mRestrictedNetworkOverride) { builder.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED); Loading Loading @@ -2529,6 +2572,12 @@ public class DataConnection extends StateMachine { DataCallResponse.HANDOVER_FAILURE_MODE_UNKNOWN); transitionTo(mInactiveState); break; case ERROR_DUPLICATE_CID: // TODO (b/180988471): Properly handle the case when an existing cid is // returned by tearing down the network agent if enterprise changed. case ERROR_NO_DEFAULT_CONNECTION: // TODO (b/180988471): Properly handle the case when a default data // connection doesn't exist. case ERROR_INVALID_ARG: // The addresses given from the RIL are bad tearDownData(cp); Loading Loading @@ -2659,10 +2708,12 @@ public class DataConnection extends StateMachine { } mUnmeteredUseOnly = isUnmeteredUseOnly(); mEnterpriseUse = isEnterpriseUse(); if (DBG) { log("mRestrictedNetworkOverride = " + mRestrictedNetworkOverride + ", mUnmeteredUseOnly = " + mUnmeteredUseOnly); + ", mUnmeteredUseOnly = " + mUnmeteredUseOnly + ", mEnterpriseUse = " + mEnterpriseUse); } // Always register a VcnNetworkPolicyChangeListener, regardless of whether this is a Loading Loading @@ -3773,6 +3824,7 @@ public class DataConnection extends StateMachine { pw.println("mUserData=" + mUserData); pw.println("mRestrictedNetworkOverride=" + mRestrictedNetworkOverride); pw.println("mUnmeteredUseOnly=" + mUnmeteredUseOnly); pw.println("mEnterpriseUse=" + mEnterpriseUse); pw.println("mUnmeteredOverride=" + mUnmeteredOverride); pw.println("mCongestedOverride=" + mCongestedOverride); pw.println("mDownlinkBandwidth" + mDownlinkBandwidth); Loading
src/java/com/android/internal/telephony/dataconnection/DcController.java +9 −0 Original line number Diff line number Diff line Loading @@ -26,6 +26,7 @@ import android.os.Message; import android.os.RegistrantList; import android.telephony.AccessNetworkConstants; import android.telephony.DataFailCause; import android.telephony.data.ApnSetting; import android.telephony.data.DataCallResponse; import com.android.internal.telephony.DctConstants; Loading Loading @@ -161,6 +162,14 @@ public class DcController extends Handler { } } boolean isDefaultDataActive() { synchronized (mDcListAll) { return mDcListActiveByCid.values().stream() .anyMatch(dc -> dc.getApnContexts().stream() .anyMatch(apn -> apn.getApnTypeBitmask() == ApnSetting.TYPE_DEFAULT)); } } @Override public void handleMessage(Message msg) { AsyncResult ar; Loading
tests/telephonytests/src/com/android/internal/telephony/SimulatedCommands.java +0 −9 Original line number Diff line number Diff line Loading @@ -47,7 +47,6 @@ import android.telephony.ServiceState; import android.telephony.SignalStrength; import android.telephony.SignalThresholdInfo; import android.telephony.TelephonyManager; import android.telephony.data.ApnSetting; import android.telephony.data.DataCallResponse; import android.telephony.data.DataProfile; import android.telephony.data.SliceInfo; Loading Loading @@ -1216,14 +1215,6 @@ public class SimulatedCommands extends BaseCommands } } // Store different cids to simulate concurrent IMS and default data calls if ((dataProfile.getSupportedApnTypesBitmask() & ApnSetting.TYPE_IMS) == ApnSetting.TYPE_IMS) { mSetupDataCallResult.cid = 0; } else { mSetupDataCallResult.cid = 1; } DataCallResponse response = RIL.convertDataCallResult(mSetupDataCallResult); if (mDcSuccess) { resultSuccess(result, response); Loading
tests/telephonytests/src/com/android/internal/telephony/dataconnection/DataConnectionTest.java +153 −17 Original line number Diff line number Diff line Loading @@ -42,6 +42,7 @@ import static org.mockito.Mockito.verify; import android.content.IntentFilter; import android.content.pm.ServiceInfo; import android.hardware.radio.V1_0.SetupDataCallResult; import android.net.InetAddresses; import android.net.KeepalivePacketData; import android.net.LinkAddress; Loading Loading @@ -86,6 +87,7 @@ import java.util.Arrays; import java.util.Collections; public class DataConnectionTest extends TelephonyTest { private static final int DEFAULT_DC_CID = 10; @Mock DcTesterFailBringUpAll mDcTesterFailBringUpAll; Loading @@ -96,9 +98,13 @@ public class DataConnectionTest extends TelephonyTest { @Mock ApnContext mApnContext; @Mock ApnContext mEnterpriseApnContext; @Mock DcFailBringUp mDcFailBringUp; @Mock DataCallSessionStats mDataCallSessionStats; @Mock DataConnection mDefaultDc; private DataConnection mDc; private DataConnectionTestHandler mDataConnectionTestHandler; Loading Loading @@ -290,6 +296,7 @@ public class DataConnectionTest extends TelephonyTest { ServiceState.RIL_RADIO_TECHNOLOGY_UMTS); doReturn(mApn1).when(mApnContext).getApnSetting(); doReturn(ApnSetting.TYPE_DEFAULT_STRING).when(mApnContext).getApnType(); doReturn(ApnSetting.TYPE_DEFAULT).when(mApnContext).getApnTypeBitmask(); mDcFailBringUp.saveParameters(0, 0, -2); doReturn(mDcFailBringUp).when(mDcTesterFailBringUpAll).getDcFailBringUp(); Loading Loading @@ -353,8 +360,13 @@ public class DataConnectionTest extends TelephonyTest { return (boolean) method.invoke(mDc); } private SetupResult setLinkProperties(DataCallResponse response, LinkProperties linkProperties) private boolean isEnterpriseUse() throws Exception { Method method = DataConnection.class.getDeclaredMethod("isEnterpriseUse"); method.setAccessible(true); return (boolean) method.invoke(mDc); } private SetupResult setLinkProperties(DataCallResponse response, LinkProperties linkProperties) throws Exception { Class[] cArgs = new Class[2]; cArgs[0] = DataCallResponse.class; Loading @@ -374,9 +386,7 @@ public class DataConnectionTest extends TelephonyTest { @SmallTest public void testConnectEvent() throws Exception { testSanity(); mDc.sendMessage(DataConnection.EVENT_CONNECT, mCp); waitForMs(200); connectEvent(true); verify(mCT, times(1)).registerForVoiceCallStarted(any(Handler.class), eq(DataConnection.EVENT_DATA_CONNECTION_VOICE_CALL_STARTED), eq(null)); Loading Loading @@ -417,7 +427,7 @@ public class DataConnectionTest extends TelephonyTest { assertEquals(null, tdCaptor.getValue().getOsAppId()); } } assertEquals("DcActiveState", getCurrentState().getName()); assertTrue(mDc.isActive()); assertEquals(mDc.getPduSessionId(), 1); assertEquals(3, mDc.getPcscfAddresses().length); Loading @@ -426,14 +436,86 @@ public class DataConnectionTest extends TelephonyTest { assertTrue(Arrays.stream(mDc.getPcscfAddresses()).anyMatch("fd00:976a:c305:1d::5"::equals)); } @Test public void testConnectEventDuplicateContextIds() throws Exception { setUpDefaultData(); // Create successful result with the same CID as default SetupDataCallResult result = new SetupDataCallResult(); result.status = 0; result.suggestedRetryTime = -1; result.cid = DEFAULT_DC_CID; result.active = 2; result.type = "IP"; result.ifname = FAKE_IFNAME; result.addresses = FAKE_ADDRESS; result.dnses = FAKE_DNS; result.gateways = FAKE_GATEWAY; result.pcscf = FAKE_PCSCF_ADDRESS; result.mtu = 1440; mSimulatedCommands.setDataCallResult(true, result); // Try to connect ENTERPRISE with the same CID as default replaceInstance(ConnectionParams.class, "mApnContext", mCp, mEnterpriseApnContext); doReturn(mApn1).when(mEnterpriseApnContext).getApnSetting(); doReturn(ApnSetting.TYPE_ENTERPRISE_STRING).when(mEnterpriseApnContext).getApnType(); doReturn(ApnSetting.TYPE_ENTERPRISE).when(mEnterpriseApnContext).getApnTypeBitmask(); // Verify that ENTERPRISE wasn't set up connectEvent(false); assertEquals("DcInactiveState", getCurrentState().getName()); // Change the CID result.cid = DEFAULT_DC_CID + 1; mSimulatedCommands.setDataCallResult(true, result); // Verify that ENTERPRISE was set up connectEvent(true); assertTrue(mDc.getNetworkCapabilities().hasCapability( NetworkCapabilities.NET_CAPABILITY_ENTERPRISE)); } @Test public void testConnectEventNoDefaultData() throws Exception { assertFalse(mDefaultDc.isActive()); // Try to connect ENTERPRISE when default data doesn't exist replaceInstance(ConnectionParams.class, "mApnContext", mCp, mEnterpriseApnContext); doReturn(mApn1).when(mEnterpriseApnContext).getApnSetting(); doReturn(ApnSetting.TYPE_ENTERPRISE_STRING).when(mEnterpriseApnContext).getApnType(); doReturn(ApnSetting.TYPE_ENTERPRISE).when(mEnterpriseApnContext).getApnTypeBitmask(); // Verify that ENTERPRISE wasn't set up connectEvent(false); assertEquals("DcInactiveState", getCurrentState().getName()); // Set up default data replaceInstance(ConnectionParams.class, "mApnContext", mCp, mApnContext); setUpDefaultData(); // Verify that ENTERPRISE was set up replaceInstance(ConnectionParams.class, "mApnContext", mCp, mEnterpriseApnContext); connectEvent(true); assertTrue(mDc.getNetworkCapabilities().hasCapability( NetworkCapabilities.NET_CAPABILITY_ENTERPRISE)); } private void setUpDefaultData() throws Exception { replaceInstance(DataConnection.class, "mCid", mDefaultDc, DEFAULT_DC_CID); doReturn(true).when(mDefaultDc).isActive(); doReturn(Arrays.asList(mApnContext)).when(mDefaultDc).getApnContexts(); mDcc.addActiveDcByCid(mDefaultDc); assertTrue(mDefaultDc.getApnContexts().stream() .anyMatch(apn -> apn.getApnTypeBitmask() == ApnSetting.TYPE_DEFAULT)); } @Test @SmallTest public void testDisconnectEvent() throws Exception { testConnectEvent(); mDc.setPduSessionId(5); mDc.sendMessage(DataConnection.EVENT_DISCONNECT, mDcp); waitForMs(100); disconnectEvent(); verify(mSimulatedCommandsVerifier, times(1)).unregisterForLceInfo(any(Handler.class)); verify(mSimulatedCommandsVerifier, times(1)) Loading Loading @@ -618,12 +700,9 @@ public class DataConnectionTest extends TelephonyTest { CarrierConfigManager.KEY_CARRIER_WWAN_DISALLOWED_APN_TYPES_STRING_ARRAY, new String[] {"supl"}); mDc.sendMessage(DataConnection.EVENT_DISCONNECT, mDcp); waitForMs(100); disconnectEvent(); doReturn(mApn1).when(mApnContext).getApnSetting(); doReturn(ApnSetting.TYPE_ENTERPRISE).when(mApnContext).getApnTypeBitmask(); mDc.sendMessage(DataConnection.EVENT_CONNECT, mCp); waitForMs(200); connectEvent(true); assertFalse("capabilities: " + getNetworkCapabilities(), getNetworkCapabilities() .hasCapability(NetworkCapabilities.NET_CAPABILITY_DUN)); Loading @@ -631,6 +710,42 @@ public class DataConnectionTest extends TelephonyTest { .hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)); assertFalse("capabilities: " + getNetworkCapabilities(), getNetworkCapabilities() .hasCapability(NetworkCapabilities.NET_CAPABILITY_SUPL)); assertFalse("capabilities: " + getNetworkCapabilities(), getNetworkCapabilities() .hasCapability(NetworkCapabilities.NET_CAPABILITY_ENTERPRISE)); } @Test @SmallTest public void testEnterpriseNetworkCapability() throws Exception { mContextFixture.getCarrierConfigBundle().putStringArray( CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS, new String[] { "default" }); doReturn(mApn2).when(mApnContext).getApnSetting(); testConnectEvent(); assertTrue("capabilities: " + getNetworkCapabilities(), getNetworkCapabilities() .hasCapability(NetworkCapabilities.NET_CAPABILITY_DUN)); assertTrue("capabilities: " + getNetworkCapabilities(), getNetworkCapabilities() .hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)); assertFalse("capabilities: " + getNetworkCapabilities(), getNetworkCapabilities() .hasCapability(NetworkCapabilities.NET_CAPABILITY_MMS)); assertFalse("capabilities: " + getNetworkCapabilities(), getNetworkCapabilities() .hasCapability(NetworkCapabilities.NET_CAPABILITY_ENTERPRISE)); disconnectEvent(); setUpDefaultData(); replaceInstance(ConnectionParams.class, "mApnContext", mCp, mEnterpriseApnContext); doReturn(mApn1).when(mEnterpriseApnContext).getApnSetting(); doReturn(ApnSetting.TYPE_ENTERPRISE_STRING).when(mEnterpriseApnContext).getApnType(); doReturn(ApnSetting.TYPE_ENTERPRISE).when(mEnterpriseApnContext).getApnTypeBitmask(); connectEvent(true); assertFalse("capabilities: " + getNetworkCapabilities(), getNetworkCapabilities() .hasCapability(NetworkCapabilities.NET_CAPABILITY_DUN)); assertFalse("capabilities: " + getNetworkCapabilities(), getNetworkCapabilities() .hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)); assertFalse("capabilities: " + getNetworkCapabilities(), getNetworkCapabilities() .hasCapability(NetworkCapabilities.NET_CAPABILITY_SUPL)); assertTrue("capabilities: " + getNetworkCapabilities(), getNetworkCapabilities() .hasCapability(NetworkCapabilities.NET_CAPABILITY_ENTERPRISE)); } Loading Loading @@ -740,16 +855,19 @@ public class DataConnectionTest extends TelephonyTest { method.setAccessible(true); doReturn(apn).when(mApnContext).getApnSetting(); connectEvent(); doReturn(apn.getApnTypeBitmask()).when(mApnContext).getApnTypeBitmask(); connectEvent(true); logd(getNetworkCapabilities().toString()); return (Boolean) method.invoke(mDc); } private void connectEvent() throws Exception { private void connectEvent(boolean validate) { mDc.sendMessage(DataConnection.EVENT_CONNECT, mCp); waitForMs(200); assertEquals("DcActiveState", getCurrentState().getName()); if (validate) { assertTrue(mDc.isActive()); } } private void disconnectEvent() throws Exception { Loading @@ -760,7 +878,7 @@ public class DataConnectionTest extends TelephonyTest { @Test @SmallTest public void testIsIpAddress() throws Exception { public void testIsIpAddress() { // IPv4 assertTrue(DataConnection.isIpAddress("1.2.3.4")); assertTrue(DataConnection.isIpAddress("127.0.0.1")); Loading Loading @@ -1066,6 +1184,24 @@ public class DataConnectionTest extends TelephonyTest { assertTrue(isUnmeteredUseOnly()); } @Test public void testIsEnterpriseUse() throws Exception { assertFalse(isEnterpriseUse()); assertFalse(mDc.getNetworkCapabilities().hasCapability( NetworkCapabilities.NET_CAPABILITY_ENTERPRISE)); setUpDefaultData(); replaceInstance(ConnectionParams.class, "mApnContext", mCp, mEnterpriseApnContext); doReturn(mApn1).when(mEnterpriseApnContext).getApnSetting(); doReturn(ApnSetting.TYPE_ENTERPRISE_STRING).when(mEnterpriseApnContext).getApnType(); doReturn(ApnSetting.TYPE_ENTERPRISE).when(mEnterpriseApnContext).getApnTypeBitmask(); connectEvent(true); assertTrue(isEnterpriseUse()); assertTrue(mDc.getNetworkCapabilities().hasCapability( NetworkCapabilities.NET_CAPABILITY_ENTERPRISE)); } @Test @SmallTest public void testGetDisallowedApnTypes() throws Exception { Loading
tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcTrackerTest.java +54 −25 File changed.Preview size limit exceeded, changes collapsed. Show changes