Loading src/java/com/android/internal/telephony/data/DataNetwork.java +62 −5 Original line number Diff line number Diff line Loading @@ -98,6 +98,8 @@ import com.android.internal.util.ArrayUtils; import com.android.internal.util.IState; import com.android.internal.util.State; import com.android.internal.util.StateMachine; import com.android.net.module.util.LinkPropertiesUtils; import com.android.net.module.util.NetUtils; import com.android.net.module.util.NetworkCapabilitiesUtils; import com.android.telephony.Rlog; Loading Loading @@ -1690,6 +1692,41 @@ public class DataNetwork extends StateMachine { } } /** * Check if the new link properties are compatible with the old link properties. For example, * if IP changes, that's considered incompatible. * * @param oldLinkProperties Old link properties. * @param newLinkProperties New Link properties. * * @return {@code true} if the new link properties is compatible with the old link properties. */ private boolean isLinkPropertiesCompatible(@NonNull LinkProperties oldLinkProperties, @NonNull LinkProperties newLinkProperties) { if (Objects.equals(oldLinkProperties, newLinkProperties)) return true; if (!LinkPropertiesUtils.isIdenticalAddresses(oldLinkProperties, newLinkProperties)) { // If the same address type was removed and added we need to cleanup. LinkPropertiesUtils.CompareOrUpdateResult<Integer, LinkAddress> result = new LinkPropertiesUtils.CompareOrUpdateResult<>( oldLinkProperties.getLinkAddresses(), newLinkProperties.getLinkAddresses(), linkAddress -> Objects.hash(linkAddress.getAddress(), linkAddress.getPrefixLength(), linkAddress.getScope())); log("isLinkPropertiesCompatible: old=" + oldLinkProperties + " new=" + newLinkProperties + " result=" + result); for (LinkAddress added : result.added) { for (LinkAddress removed : result.removed) { if (NetUtils.addressTypeMatches(removed.getAddress(), added.getAddress())) { return false; } } } } return true; } /** * Check if there are immutable capabilities changed. The connectivity service is not able * to handle immutable capabilities changed, but in very rare scenarios, immutable capabilities Loading Loading @@ -2209,10 +2246,29 @@ public class DataNetwork extends StateMachine { } if (!linkProperties.equals(mLinkProperties)) { // If the new link properties is not compatible (e.g. IP changes, interface changes), // then we should de-register the network agent and re-create a new one. if ((isConnected() || isHandoverInProgress()) && !isLinkPropertiesCompatible(linkProperties, mLinkProperties)) { logl("updateDataNetwork: Incompatible link properties detected. Re-create the " + "network agent. Changed from " + mLinkProperties + " to " + linkProperties); mLinkProperties = linkProperties; // Abandon the network agent because we are going to create a new one. mNetworkAgent.abandon(); // Update the link properties first so the new network agent would be created with // the new link properties. mLinkProperties = linkProperties; mNetworkAgent = createNetworkAgent(); mNetworkAgent.markConnected(); } else { mLinkProperties = linkProperties; log("sendLinkProperties " + mLinkProperties); mNetworkAgent.sendLinkProperties(mLinkProperties); } } updateNetworkCapabilities(); } Loading Loading @@ -2361,8 +2417,9 @@ public class DataNetwork extends StateMachine { private void onTearDown(@TearDownReason int reason) { logl("onTearDown: reason=" + tearDownReasonToString(reason)); // track frequent networkUnwanted call of IMS and INTERNET if ((isConnected()) // track frequent NetworkAgent.onNetworkUnwanted() call of IMS and INTERNET if (reason == TEAR_DOWN_REASON_CONNECTIVITY_SERVICE_UNWANTED && isConnected() && (mNetworkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_IMS) || mNetworkCapabilities.hasCapability( NetworkCapabilities.NET_CAPABILITY_INTERNET))) { Loading src/java/com/android/internal/telephony/data/DataNetworkController.java +6 −10 Original line number Diff line number Diff line Loading @@ -2242,21 +2242,17 @@ public class DataNetworkController extends Handler { } /** * There have been several bugs where a RECONNECT loop kicks off where a DataConnection * connects to the Network, ConnectivityService indicates that the Network is unwanted, * and then the DataConnection reconnects. By the time we get the bug report it's too late * because there have already been hundreds of RECONNECTS. This is meant to capture the issue * when it first starts. * * The unwanted counter is configured to only take an anomaly report in extreme cases. * This is to avoid having the anomaly message show up on several devices. * * There have been several bugs where a RECONNECT loop kicks off where a data network * is brought up, but connectivity service indicates that the network is unwanted so telephony * tears down the network. But later telephony bring up the data network again and becomes an * infinite loop. By the time we get the bug report it's too late because there have already * been hundreds of bring up/tear down. This is meant to capture the issue when it first starts. */ private void onTrackNetworkUnwanted() { if (mNetworkUnwantedCounter.addOccurrence()) { reportAnomaly("Network Unwanted called " + mNetworkUnwantedCounter.getFrequencyString(), "9f3bc55b-bfa6-4e26-afaa-5031426a66d2"); "9f3bc55b-bfa6-4e26-afaa-5031426a66d3"); } } Loading tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkTest.java +280 −0 Original line number Diff line number Diff line Loading @@ -95,7 +95,9 @@ import java.util.concurrent.Executor; @TestableLooper.RunWithLooper public class DataNetworkTest extends TelephonyTest { private static final String IPV4_ADDRESS = "10.0.2.15"; private static final String IPV4_ADDRESS1 = "10.0.2.16"; private static final String IPV6_ADDRESS = "2607:fb90:a620:651d:eabe:f8da:c107:44be"; private static final String IPV6_ADDRESS1 = "2607:fb90:a620:651d:eabe:f8da:c107:44bf"; private static final int ADMIN_UID1 = 1234; private static final int ADMIN_UID2 = 5678; Loading Loading @@ -1340,4 +1342,282 @@ public class DataNetworkTest extends TelephonyTest { // Internet priority is 20 assertThat(mDataNetworkUT.getPriority()).isEqualTo(20); } @Test public void testIpChangedV4() throws Exception { testCreateDataNetwork(); DataCallResponse response = new DataCallResponse.Builder() .setCause(0) .setRetryDurationMillis(-1L) .setId(123) .setLinkStatus(2) .setProtocolType(ApnSetting.PROTOCOL_IPV4V6) .setInterfaceName("ifname") .setAddresses(Arrays.asList( new LinkAddress(InetAddresses.parseNumericAddress(IPV4_ADDRESS1), 32), new LinkAddress(IPV6_ADDRESS + "/64"))) .setDnsAddresses(Arrays.asList(InetAddresses.parseNumericAddress("10.0.2.3"), InetAddresses.parseNumericAddress("fd00:976a::9"))) .setGatewayAddresses(Arrays.asList( InetAddresses.parseNumericAddress("10.0.2.15"), InetAddresses.parseNumericAddress("fe80::2"))) .setPcscfAddresses(Arrays.asList( InetAddresses.parseNumericAddress("fd00:976a:c305:1d::8"), InetAddresses.parseNumericAddress("fd00:976a:c202:1d::7"), InetAddresses.parseNumericAddress("fd00:976a:c305:1d::5"))) .setMtuV4(1234) .setMtuV6(5678) .setPduSessionId(1) .setQosBearerSessions(new ArrayList<>()) .setTrafficDescriptors(Collections.emptyList()) .build(); // IP changes mDataNetworkUT.obtainMessage(8/*EVENT_DATA_STATE_CHANGED*/, new AsyncResult(AccessNetworkConstants.TRANSPORT_TYPE_WWAN, List.of(response), null)).sendToTarget(); processAllMessages(); ArgumentCaptor<LinkProperties> linkPropertiesCaptor = ArgumentCaptor.forClass(LinkProperties.class); // Agent re-created, so register should be called twice. verify(mConnectivityManager, times(2)).registerNetworkAgent(any(), any(NetworkInfo.class), linkPropertiesCaptor.capture(), any(NetworkCapabilities.class), any(), any(), anyInt()); // The new agent should have the new IP address. assertThat(linkPropertiesCaptor.getValue().getAllAddresses()).containsExactly( InetAddresses.parseNumericAddress(IPV4_ADDRESS1), InetAddresses.parseNumericAddress(IPV6_ADDRESS)); assertThat(linkPropertiesCaptor.getValue()).isEqualTo(mDataNetworkUT.getLinkProperties()); } @Test public void testIpChangedV6() throws Exception { testCreateDataNetwork(); DataCallResponse response = new DataCallResponse.Builder() .setCause(0) .setRetryDurationMillis(-1L) .setId(123) .setLinkStatus(2) .setProtocolType(ApnSetting.PROTOCOL_IPV4V6) .setInterfaceName("ifname") .setAddresses(Arrays.asList(new LinkAddress(IPV6_ADDRESS1 + "/64"))) .setDnsAddresses(Arrays.asList(InetAddresses.parseNumericAddress("10.0.2.3"), InetAddresses.parseNumericAddress("fd00:976a::9"))) .setGatewayAddresses(Arrays.asList( InetAddresses.parseNumericAddress("10.0.2.15"), InetAddresses.parseNumericAddress("fe80::2"))) .setPcscfAddresses(Arrays.asList( InetAddresses.parseNumericAddress("fd00:976a:c305:1d::8"), InetAddresses.parseNumericAddress("fd00:976a:c202:1d::7"), InetAddresses.parseNumericAddress("fd00:976a:c305:1d::5"))) .setMtuV4(1234) .setMtuV6(5678) .setPduSessionId(1) .setQosBearerSessions(new ArrayList<>()) .setTrafficDescriptors(Collections.emptyList()) .build(); // IP changes mDataNetworkUT.obtainMessage(8/*EVENT_DATA_STATE_CHANGED*/, new AsyncResult(AccessNetworkConstants.TRANSPORT_TYPE_WWAN, List.of(response), null)).sendToTarget(); processAllMessages(); ArgumentCaptor<LinkProperties> linkPropertiesCaptor = ArgumentCaptor.forClass(LinkProperties.class); // Agent re-created, so register should be called twice. verify(mConnectivityManager, times(2)).registerNetworkAgent(any(), any(NetworkInfo.class), linkPropertiesCaptor.capture(), any(NetworkCapabilities.class), any(), any(), anyInt()); // The new agent should have the new IP address. assertThat(linkPropertiesCaptor.getValue().getAllAddresses()).containsExactly( InetAddresses.parseNumericAddress(IPV6_ADDRESS1)); assertThat(linkPropertiesCaptor.getValue()).isEqualTo(mDataNetworkUT.getLinkProperties()); } @Test public void testIpChangedFromV4ToV6() throws Exception { doAnswer(invocation -> { final Message msg = (Message) invocation.getArguments()[10]; DataCallResponse response = new DataCallResponse.Builder() .setCause(0) .setRetryDurationMillis(-1L) .setId(123) .setLinkStatus(2) .setProtocolType(ApnSetting.PROTOCOL_IPV4V6) .setInterfaceName("ifname") .setAddresses(Arrays.asList( new LinkAddress(InetAddresses.parseNumericAddress(IPV4_ADDRESS), 32))) .setDnsAddresses(Arrays.asList(InetAddresses.parseNumericAddress("10.0.2.3"), InetAddresses.parseNumericAddress("fd00:976a::9"))) .setGatewayAddresses(Arrays.asList( InetAddresses.parseNumericAddress("10.0.2.15"), InetAddresses.parseNumericAddress("fe80::2"))) .setPcscfAddresses(Arrays.asList( InetAddresses.parseNumericAddress("fd00:976a:c305:1d::8"), InetAddresses.parseNumericAddress("fd00:976a:c202:1d::7"), InetAddresses.parseNumericAddress("fd00:976a:c305:1d::5"))) .setMtuV4(1234) .setMtuV6(5678) .setPduSessionId(1) .setQosBearerSessions(new ArrayList<>()) .setTrafficDescriptors(Collections.emptyList()) .build(); msg.getData().putParcelable("data_call_response", response); msg.arg1 = DataServiceCallback.RESULT_SUCCESS; msg.sendToTarget(); return null; }).when(mMockedWwanDataServiceManager).setupDataCall(anyInt(), any(DataProfile.class), anyBoolean(), anyBoolean(), anyInt(), any(), anyInt(), any(), any(), anyBoolean(), any(Message.class)); NetworkRequestList networkRequestList = new NetworkRequestList(); networkRequestList.add(new TelephonyNetworkRequest(new NetworkRequest.Builder() .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) .build(), mPhone)); mDataNetworkUT = new DataNetwork(mPhone, Looper.myLooper(), mDataServiceManagers, mInternetDataProfile, networkRequestList, AccessNetworkConstants.TRANSPORT_TYPE_WWAN, DataAllowedReason.NORMAL, mDataNetworkCallback); replaceInstance(DataNetwork.class, "mDataCallSessionStats", mDataNetworkUT, mDataCallSessionStats); processAllMessages(); DataCallResponse response = new DataCallResponse.Builder() .setCause(0) .setRetryDurationMillis(-1L) .setId(123) .setLinkStatus(2) .setProtocolType(ApnSetting.PROTOCOL_IPV4V6) .setInterfaceName("ifname") .setAddresses(Arrays.asList(new LinkAddress(IPV6_ADDRESS + "/64"))) .setDnsAddresses(Arrays.asList(InetAddresses.parseNumericAddress("10.0.2.3"), InetAddresses.parseNumericAddress("fd00:976a::9"))) .setGatewayAddresses(Arrays.asList( InetAddresses.parseNumericAddress("10.0.2.15"), InetAddresses.parseNumericAddress("fe80::2"))) .setPcscfAddresses(Arrays.asList( InetAddresses.parseNumericAddress("fd00:976a:c305:1d::8"), InetAddresses.parseNumericAddress("fd00:976a:c202:1d::7"), InetAddresses.parseNumericAddress("fd00:976a:c305:1d::5"))) .setMtuV4(1234) .setMtuV6(5678) .setPduSessionId(1) .setQosBearerSessions(new ArrayList<>()) .setTrafficDescriptors(Collections.emptyList()) .build(); // IP changes mDataNetworkUT.obtainMessage(8/*EVENT_DATA_STATE_CHANGED*/, new AsyncResult(AccessNetworkConstants.TRANSPORT_TYPE_WWAN, List.of(response), null)).sendToTarget(); processAllMessages(); // Agent should not be re-created, so register should be called ony once. verify(mConnectivityManager, times(1)).registerNetworkAgent(any(), any(NetworkInfo.class), any(LinkProperties.class), any(NetworkCapabilities.class), any(), any(), anyInt()); // The network should have IPv6 address now assertThat(mDataNetworkUT.getLinkProperties().getAllAddresses()).containsExactly( InetAddresses.parseNumericAddress(IPV6_ADDRESS)); } @Test public void testIpChangedV4Removed() throws Exception { testCreateDataNetwork(); DataCallResponse response = new DataCallResponse.Builder() .setCause(0) .setRetryDurationMillis(-1L) .setId(123) .setLinkStatus(2) .setProtocolType(ApnSetting.PROTOCOL_IPV4V6) .setInterfaceName("ifname") .setAddresses(Arrays.asList(new LinkAddress(IPV6_ADDRESS + "/64"))) .setDnsAddresses(Arrays.asList(InetAddresses.parseNumericAddress("10.0.2.3"), InetAddresses.parseNumericAddress("fd00:976a::9"))) .setGatewayAddresses(Arrays.asList( InetAddresses.parseNumericAddress("10.0.2.15"), InetAddresses.parseNumericAddress("fe80::2"))) .setPcscfAddresses(Arrays.asList( InetAddresses.parseNumericAddress("fd00:976a:c305:1d::8"), InetAddresses.parseNumericAddress("fd00:976a:c202:1d::7"), InetAddresses.parseNumericAddress("fd00:976a:c305:1d::5"))) .setMtuV4(1234) .setMtuV6(5678) .setPduSessionId(1) .setQosBearerSessions(new ArrayList<>()) .setTrafficDescriptors(Collections.emptyList()) .build(); // IP changes mDataNetworkUT.obtainMessage(8/*EVENT_DATA_STATE_CHANGED*/, new AsyncResult(AccessNetworkConstants.TRANSPORT_TYPE_WWAN, List.of(response), null)).sendToTarget(); processAllMessages(); // Agent should not be re-created, so register should be called ony once. verify(mConnectivityManager, times(1)).registerNetworkAgent(any(), any(NetworkInfo.class), any(LinkProperties.class), any(NetworkCapabilities.class), any(), any(), anyInt()); // The network should have IPv6 address now assertThat(mDataNetworkUT.getLinkProperties().getAllAddresses()).containsExactly( InetAddresses.parseNumericAddress(IPV6_ADDRESS)); } @Test public void testIpChangedV6Removed() throws Exception { testCreateDataNetwork(); DataCallResponse response = new DataCallResponse.Builder() .setCause(0) .setRetryDurationMillis(-1L) .setId(123) .setLinkStatus(2) .setProtocolType(ApnSetting.PROTOCOL_IPV4V6) .setInterfaceName("ifname") .setAddresses(Arrays.asList(new LinkAddress( InetAddresses.parseNumericAddress(IPV4_ADDRESS), 32))) .setDnsAddresses(Arrays.asList(InetAddresses.parseNumericAddress("10.0.2.3"), InetAddresses.parseNumericAddress("fd00:976a::9"))) .setGatewayAddresses(Arrays.asList( InetAddresses.parseNumericAddress("10.0.2.15"), InetAddresses.parseNumericAddress("fe80::2"))) .setPcscfAddresses(Arrays.asList( InetAddresses.parseNumericAddress("fd00:976a:c305:1d::8"), InetAddresses.parseNumericAddress("fd00:976a:c202:1d::7"), InetAddresses.parseNumericAddress("fd00:976a:c305:1d::5"))) .setMtuV4(1234) .setMtuV6(5678) .setPduSessionId(1) .setQosBearerSessions(new ArrayList<>()) .setTrafficDescriptors(Collections.emptyList()) .build(); // IP changes mDataNetworkUT.obtainMessage(8/*EVENT_DATA_STATE_CHANGED*/, new AsyncResult(AccessNetworkConstants.TRANSPORT_TYPE_WWAN, List.of(response), null)).sendToTarget(); processAllMessages(); // Agent should not be re-created, so register should be called ony once. verify(mConnectivityManager, times(1)).registerNetworkAgent(any(), any(NetworkInfo.class), any(LinkProperties.class), any(NetworkCapabilities.class), any(), any(), anyInt()); // The network should have IPv6 address now assertThat(mDataNetworkUT.getLinkProperties().getAllAddresses()).containsExactly( InetAddresses.parseNumericAddress(IPV4_ADDRESS)); } } Loading
src/java/com/android/internal/telephony/data/DataNetwork.java +62 −5 Original line number Diff line number Diff line Loading @@ -98,6 +98,8 @@ import com.android.internal.util.ArrayUtils; import com.android.internal.util.IState; import com.android.internal.util.State; import com.android.internal.util.StateMachine; import com.android.net.module.util.LinkPropertiesUtils; import com.android.net.module.util.NetUtils; import com.android.net.module.util.NetworkCapabilitiesUtils; import com.android.telephony.Rlog; Loading Loading @@ -1690,6 +1692,41 @@ public class DataNetwork extends StateMachine { } } /** * Check if the new link properties are compatible with the old link properties. For example, * if IP changes, that's considered incompatible. * * @param oldLinkProperties Old link properties. * @param newLinkProperties New Link properties. * * @return {@code true} if the new link properties is compatible with the old link properties. */ private boolean isLinkPropertiesCompatible(@NonNull LinkProperties oldLinkProperties, @NonNull LinkProperties newLinkProperties) { if (Objects.equals(oldLinkProperties, newLinkProperties)) return true; if (!LinkPropertiesUtils.isIdenticalAddresses(oldLinkProperties, newLinkProperties)) { // If the same address type was removed and added we need to cleanup. LinkPropertiesUtils.CompareOrUpdateResult<Integer, LinkAddress> result = new LinkPropertiesUtils.CompareOrUpdateResult<>( oldLinkProperties.getLinkAddresses(), newLinkProperties.getLinkAddresses(), linkAddress -> Objects.hash(linkAddress.getAddress(), linkAddress.getPrefixLength(), linkAddress.getScope())); log("isLinkPropertiesCompatible: old=" + oldLinkProperties + " new=" + newLinkProperties + " result=" + result); for (LinkAddress added : result.added) { for (LinkAddress removed : result.removed) { if (NetUtils.addressTypeMatches(removed.getAddress(), added.getAddress())) { return false; } } } } return true; } /** * Check if there are immutable capabilities changed. The connectivity service is not able * to handle immutable capabilities changed, but in very rare scenarios, immutable capabilities Loading Loading @@ -2209,10 +2246,29 @@ public class DataNetwork extends StateMachine { } if (!linkProperties.equals(mLinkProperties)) { // If the new link properties is not compatible (e.g. IP changes, interface changes), // then we should de-register the network agent and re-create a new one. if ((isConnected() || isHandoverInProgress()) && !isLinkPropertiesCompatible(linkProperties, mLinkProperties)) { logl("updateDataNetwork: Incompatible link properties detected. Re-create the " + "network agent. Changed from " + mLinkProperties + " to " + linkProperties); mLinkProperties = linkProperties; // Abandon the network agent because we are going to create a new one. mNetworkAgent.abandon(); // Update the link properties first so the new network agent would be created with // the new link properties. mLinkProperties = linkProperties; mNetworkAgent = createNetworkAgent(); mNetworkAgent.markConnected(); } else { mLinkProperties = linkProperties; log("sendLinkProperties " + mLinkProperties); mNetworkAgent.sendLinkProperties(mLinkProperties); } } updateNetworkCapabilities(); } Loading Loading @@ -2361,8 +2417,9 @@ public class DataNetwork extends StateMachine { private void onTearDown(@TearDownReason int reason) { logl("onTearDown: reason=" + tearDownReasonToString(reason)); // track frequent networkUnwanted call of IMS and INTERNET if ((isConnected()) // track frequent NetworkAgent.onNetworkUnwanted() call of IMS and INTERNET if (reason == TEAR_DOWN_REASON_CONNECTIVITY_SERVICE_UNWANTED && isConnected() && (mNetworkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_IMS) || mNetworkCapabilities.hasCapability( NetworkCapabilities.NET_CAPABILITY_INTERNET))) { Loading
src/java/com/android/internal/telephony/data/DataNetworkController.java +6 −10 Original line number Diff line number Diff line Loading @@ -2242,21 +2242,17 @@ public class DataNetworkController extends Handler { } /** * There have been several bugs where a RECONNECT loop kicks off where a DataConnection * connects to the Network, ConnectivityService indicates that the Network is unwanted, * and then the DataConnection reconnects. By the time we get the bug report it's too late * because there have already been hundreds of RECONNECTS. This is meant to capture the issue * when it first starts. * * The unwanted counter is configured to only take an anomaly report in extreme cases. * This is to avoid having the anomaly message show up on several devices. * * There have been several bugs where a RECONNECT loop kicks off where a data network * is brought up, but connectivity service indicates that the network is unwanted so telephony * tears down the network. But later telephony bring up the data network again and becomes an * infinite loop. By the time we get the bug report it's too late because there have already * been hundreds of bring up/tear down. This is meant to capture the issue when it first starts. */ private void onTrackNetworkUnwanted() { if (mNetworkUnwantedCounter.addOccurrence()) { reportAnomaly("Network Unwanted called " + mNetworkUnwantedCounter.getFrequencyString(), "9f3bc55b-bfa6-4e26-afaa-5031426a66d2"); "9f3bc55b-bfa6-4e26-afaa-5031426a66d3"); } } Loading
tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkTest.java +280 −0 Original line number Diff line number Diff line Loading @@ -95,7 +95,9 @@ import java.util.concurrent.Executor; @TestableLooper.RunWithLooper public class DataNetworkTest extends TelephonyTest { private static final String IPV4_ADDRESS = "10.0.2.15"; private static final String IPV4_ADDRESS1 = "10.0.2.16"; private static final String IPV6_ADDRESS = "2607:fb90:a620:651d:eabe:f8da:c107:44be"; private static final String IPV6_ADDRESS1 = "2607:fb90:a620:651d:eabe:f8da:c107:44bf"; private static final int ADMIN_UID1 = 1234; private static final int ADMIN_UID2 = 5678; Loading Loading @@ -1340,4 +1342,282 @@ public class DataNetworkTest extends TelephonyTest { // Internet priority is 20 assertThat(mDataNetworkUT.getPriority()).isEqualTo(20); } @Test public void testIpChangedV4() throws Exception { testCreateDataNetwork(); DataCallResponse response = new DataCallResponse.Builder() .setCause(0) .setRetryDurationMillis(-1L) .setId(123) .setLinkStatus(2) .setProtocolType(ApnSetting.PROTOCOL_IPV4V6) .setInterfaceName("ifname") .setAddresses(Arrays.asList( new LinkAddress(InetAddresses.parseNumericAddress(IPV4_ADDRESS1), 32), new LinkAddress(IPV6_ADDRESS + "/64"))) .setDnsAddresses(Arrays.asList(InetAddresses.parseNumericAddress("10.0.2.3"), InetAddresses.parseNumericAddress("fd00:976a::9"))) .setGatewayAddresses(Arrays.asList( InetAddresses.parseNumericAddress("10.0.2.15"), InetAddresses.parseNumericAddress("fe80::2"))) .setPcscfAddresses(Arrays.asList( InetAddresses.parseNumericAddress("fd00:976a:c305:1d::8"), InetAddresses.parseNumericAddress("fd00:976a:c202:1d::7"), InetAddresses.parseNumericAddress("fd00:976a:c305:1d::5"))) .setMtuV4(1234) .setMtuV6(5678) .setPduSessionId(1) .setQosBearerSessions(new ArrayList<>()) .setTrafficDescriptors(Collections.emptyList()) .build(); // IP changes mDataNetworkUT.obtainMessage(8/*EVENT_DATA_STATE_CHANGED*/, new AsyncResult(AccessNetworkConstants.TRANSPORT_TYPE_WWAN, List.of(response), null)).sendToTarget(); processAllMessages(); ArgumentCaptor<LinkProperties> linkPropertiesCaptor = ArgumentCaptor.forClass(LinkProperties.class); // Agent re-created, so register should be called twice. verify(mConnectivityManager, times(2)).registerNetworkAgent(any(), any(NetworkInfo.class), linkPropertiesCaptor.capture(), any(NetworkCapabilities.class), any(), any(), anyInt()); // The new agent should have the new IP address. assertThat(linkPropertiesCaptor.getValue().getAllAddresses()).containsExactly( InetAddresses.parseNumericAddress(IPV4_ADDRESS1), InetAddresses.parseNumericAddress(IPV6_ADDRESS)); assertThat(linkPropertiesCaptor.getValue()).isEqualTo(mDataNetworkUT.getLinkProperties()); } @Test public void testIpChangedV6() throws Exception { testCreateDataNetwork(); DataCallResponse response = new DataCallResponse.Builder() .setCause(0) .setRetryDurationMillis(-1L) .setId(123) .setLinkStatus(2) .setProtocolType(ApnSetting.PROTOCOL_IPV4V6) .setInterfaceName("ifname") .setAddresses(Arrays.asList(new LinkAddress(IPV6_ADDRESS1 + "/64"))) .setDnsAddresses(Arrays.asList(InetAddresses.parseNumericAddress("10.0.2.3"), InetAddresses.parseNumericAddress("fd00:976a::9"))) .setGatewayAddresses(Arrays.asList( InetAddresses.parseNumericAddress("10.0.2.15"), InetAddresses.parseNumericAddress("fe80::2"))) .setPcscfAddresses(Arrays.asList( InetAddresses.parseNumericAddress("fd00:976a:c305:1d::8"), InetAddresses.parseNumericAddress("fd00:976a:c202:1d::7"), InetAddresses.parseNumericAddress("fd00:976a:c305:1d::5"))) .setMtuV4(1234) .setMtuV6(5678) .setPduSessionId(1) .setQosBearerSessions(new ArrayList<>()) .setTrafficDescriptors(Collections.emptyList()) .build(); // IP changes mDataNetworkUT.obtainMessage(8/*EVENT_DATA_STATE_CHANGED*/, new AsyncResult(AccessNetworkConstants.TRANSPORT_TYPE_WWAN, List.of(response), null)).sendToTarget(); processAllMessages(); ArgumentCaptor<LinkProperties> linkPropertiesCaptor = ArgumentCaptor.forClass(LinkProperties.class); // Agent re-created, so register should be called twice. verify(mConnectivityManager, times(2)).registerNetworkAgent(any(), any(NetworkInfo.class), linkPropertiesCaptor.capture(), any(NetworkCapabilities.class), any(), any(), anyInt()); // The new agent should have the new IP address. assertThat(linkPropertiesCaptor.getValue().getAllAddresses()).containsExactly( InetAddresses.parseNumericAddress(IPV6_ADDRESS1)); assertThat(linkPropertiesCaptor.getValue()).isEqualTo(mDataNetworkUT.getLinkProperties()); } @Test public void testIpChangedFromV4ToV6() throws Exception { doAnswer(invocation -> { final Message msg = (Message) invocation.getArguments()[10]; DataCallResponse response = new DataCallResponse.Builder() .setCause(0) .setRetryDurationMillis(-1L) .setId(123) .setLinkStatus(2) .setProtocolType(ApnSetting.PROTOCOL_IPV4V6) .setInterfaceName("ifname") .setAddresses(Arrays.asList( new LinkAddress(InetAddresses.parseNumericAddress(IPV4_ADDRESS), 32))) .setDnsAddresses(Arrays.asList(InetAddresses.parseNumericAddress("10.0.2.3"), InetAddresses.parseNumericAddress("fd00:976a::9"))) .setGatewayAddresses(Arrays.asList( InetAddresses.parseNumericAddress("10.0.2.15"), InetAddresses.parseNumericAddress("fe80::2"))) .setPcscfAddresses(Arrays.asList( InetAddresses.parseNumericAddress("fd00:976a:c305:1d::8"), InetAddresses.parseNumericAddress("fd00:976a:c202:1d::7"), InetAddresses.parseNumericAddress("fd00:976a:c305:1d::5"))) .setMtuV4(1234) .setMtuV6(5678) .setPduSessionId(1) .setQosBearerSessions(new ArrayList<>()) .setTrafficDescriptors(Collections.emptyList()) .build(); msg.getData().putParcelable("data_call_response", response); msg.arg1 = DataServiceCallback.RESULT_SUCCESS; msg.sendToTarget(); return null; }).when(mMockedWwanDataServiceManager).setupDataCall(anyInt(), any(DataProfile.class), anyBoolean(), anyBoolean(), anyInt(), any(), anyInt(), any(), any(), anyBoolean(), any(Message.class)); NetworkRequestList networkRequestList = new NetworkRequestList(); networkRequestList.add(new TelephonyNetworkRequest(new NetworkRequest.Builder() .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) .build(), mPhone)); mDataNetworkUT = new DataNetwork(mPhone, Looper.myLooper(), mDataServiceManagers, mInternetDataProfile, networkRequestList, AccessNetworkConstants.TRANSPORT_TYPE_WWAN, DataAllowedReason.NORMAL, mDataNetworkCallback); replaceInstance(DataNetwork.class, "mDataCallSessionStats", mDataNetworkUT, mDataCallSessionStats); processAllMessages(); DataCallResponse response = new DataCallResponse.Builder() .setCause(0) .setRetryDurationMillis(-1L) .setId(123) .setLinkStatus(2) .setProtocolType(ApnSetting.PROTOCOL_IPV4V6) .setInterfaceName("ifname") .setAddresses(Arrays.asList(new LinkAddress(IPV6_ADDRESS + "/64"))) .setDnsAddresses(Arrays.asList(InetAddresses.parseNumericAddress("10.0.2.3"), InetAddresses.parseNumericAddress("fd00:976a::9"))) .setGatewayAddresses(Arrays.asList( InetAddresses.parseNumericAddress("10.0.2.15"), InetAddresses.parseNumericAddress("fe80::2"))) .setPcscfAddresses(Arrays.asList( InetAddresses.parseNumericAddress("fd00:976a:c305:1d::8"), InetAddresses.parseNumericAddress("fd00:976a:c202:1d::7"), InetAddresses.parseNumericAddress("fd00:976a:c305:1d::5"))) .setMtuV4(1234) .setMtuV6(5678) .setPduSessionId(1) .setQosBearerSessions(new ArrayList<>()) .setTrafficDescriptors(Collections.emptyList()) .build(); // IP changes mDataNetworkUT.obtainMessage(8/*EVENT_DATA_STATE_CHANGED*/, new AsyncResult(AccessNetworkConstants.TRANSPORT_TYPE_WWAN, List.of(response), null)).sendToTarget(); processAllMessages(); // Agent should not be re-created, so register should be called ony once. verify(mConnectivityManager, times(1)).registerNetworkAgent(any(), any(NetworkInfo.class), any(LinkProperties.class), any(NetworkCapabilities.class), any(), any(), anyInt()); // The network should have IPv6 address now assertThat(mDataNetworkUT.getLinkProperties().getAllAddresses()).containsExactly( InetAddresses.parseNumericAddress(IPV6_ADDRESS)); } @Test public void testIpChangedV4Removed() throws Exception { testCreateDataNetwork(); DataCallResponse response = new DataCallResponse.Builder() .setCause(0) .setRetryDurationMillis(-1L) .setId(123) .setLinkStatus(2) .setProtocolType(ApnSetting.PROTOCOL_IPV4V6) .setInterfaceName("ifname") .setAddresses(Arrays.asList(new LinkAddress(IPV6_ADDRESS + "/64"))) .setDnsAddresses(Arrays.asList(InetAddresses.parseNumericAddress("10.0.2.3"), InetAddresses.parseNumericAddress("fd00:976a::9"))) .setGatewayAddresses(Arrays.asList( InetAddresses.parseNumericAddress("10.0.2.15"), InetAddresses.parseNumericAddress("fe80::2"))) .setPcscfAddresses(Arrays.asList( InetAddresses.parseNumericAddress("fd00:976a:c305:1d::8"), InetAddresses.parseNumericAddress("fd00:976a:c202:1d::7"), InetAddresses.parseNumericAddress("fd00:976a:c305:1d::5"))) .setMtuV4(1234) .setMtuV6(5678) .setPduSessionId(1) .setQosBearerSessions(new ArrayList<>()) .setTrafficDescriptors(Collections.emptyList()) .build(); // IP changes mDataNetworkUT.obtainMessage(8/*EVENT_DATA_STATE_CHANGED*/, new AsyncResult(AccessNetworkConstants.TRANSPORT_TYPE_WWAN, List.of(response), null)).sendToTarget(); processAllMessages(); // Agent should not be re-created, so register should be called ony once. verify(mConnectivityManager, times(1)).registerNetworkAgent(any(), any(NetworkInfo.class), any(LinkProperties.class), any(NetworkCapabilities.class), any(), any(), anyInt()); // The network should have IPv6 address now assertThat(mDataNetworkUT.getLinkProperties().getAllAddresses()).containsExactly( InetAddresses.parseNumericAddress(IPV6_ADDRESS)); } @Test public void testIpChangedV6Removed() throws Exception { testCreateDataNetwork(); DataCallResponse response = new DataCallResponse.Builder() .setCause(0) .setRetryDurationMillis(-1L) .setId(123) .setLinkStatus(2) .setProtocolType(ApnSetting.PROTOCOL_IPV4V6) .setInterfaceName("ifname") .setAddresses(Arrays.asList(new LinkAddress( InetAddresses.parseNumericAddress(IPV4_ADDRESS), 32))) .setDnsAddresses(Arrays.asList(InetAddresses.parseNumericAddress("10.0.2.3"), InetAddresses.parseNumericAddress("fd00:976a::9"))) .setGatewayAddresses(Arrays.asList( InetAddresses.parseNumericAddress("10.0.2.15"), InetAddresses.parseNumericAddress("fe80::2"))) .setPcscfAddresses(Arrays.asList( InetAddresses.parseNumericAddress("fd00:976a:c305:1d::8"), InetAddresses.parseNumericAddress("fd00:976a:c202:1d::7"), InetAddresses.parseNumericAddress("fd00:976a:c305:1d::5"))) .setMtuV4(1234) .setMtuV6(5678) .setPduSessionId(1) .setQosBearerSessions(new ArrayList<>()) .setTrafficDescriptors(Collections.emptyList()) .build(); // IP changes mDataNetworkUT.obtainMessage(8/*EVENT_DATA_STATE_CHANGED*/, new AsyncResult(AccessNetworkConstants.TRANSPORT_TYPE_WWAN, List.of(response), null)).sendToTarget(); processAllMessages(); // Agent should not be re-created, so register should be called ony once. verify(mConnectivityManager, times(1)).registerNetworkAgent(any(), any(NetworkInfo.class), any(LinkProperties.class), any(NetworkCapabilities.class), any(), any(), anyInt()); // The network should have IPv6 address now assertThat(mDataNetworkUT.getLinkProperties().getAllAddresses()).containsExactly( InetAddresses.parseNumericAddress(IPV4_ADDRESS)); } }