From 430e11a9f0d1e566ddf7edbceb8c52bce8d22a71 Mon Sep 17 00:00:00 2001 From: junyulai Date: Thu, 20 Aug 2020 18:23:57 +0800 Subject: [PATCH] Support dynamically update IMSI Currently, NetworkStatsSubscriptionsMonitor will skip the listener registration until the IMSI is available to deal with SIM PIN locked case. However, this solution can only handle the case that IMSI changes from/to null. And it also relies on the assumption that IMSI never changes for a subId. Thus, support dynamically update IMSI to handle IMSI changes more robustly. This patch also address leftover comments at ag/12400327. Test: enable SIM PIN and manually test Test: atest NetworkStatsSubscriptionsMonitorTest#testSubscriberIdUnavailable Test: atest NetworkStatsSubscriptionsMonitorTest#testSubscriberIdChanged Test: ./out/host/linux-x86/bin/statsd_testdrive 10082 Bug: 160941101 Change-Id: I625a5b10ee4806f6fee99c2d9d6c5e7977ff785e --- .../NetworkStatsSubscriptionsMonitorTest.java | 83 ++++++++++++++++--- 1 file changed, 71 insertions(+), 12 deletions(-) diff --git a/tests/net/java/com/android/server/net/NetworkStatsSubscriptionsMonitorTest.java b/tests/net/java/com/android/server/net/NetworkStatsSubscriptionsMonitorTest.java index 8f093779da..6d2c7dc39f 100644 --- a/tests/net/java/com/android/server/net/NetworkStatsSubscriptionsMonitorTest.java +++ b/tests/net/java/com/android/server/net/NetworkStatsSubscriptionsMonitorTest.java @@ -21,6 +21,7 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.fail; import static org.mockito.Mockito.any; import static org.mockito.Mockito.anyInt; +import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; @@ -150,7 +151,7 @@ public final class NetworkStatsSubscriptionsMonitorTest { } private void assertRatTypeChangedForSub(String subscriberId, int ratType) { - assertEquals(mMonitor.getRatTypeForSubscriberId(subscriberId), ratType); + assertEquals(ratType, mMonitor.getRatTypeForSubscriberId(subscriberId)); final ArgumentCaptor typeCaptor = ArgumentCaptor.forClass(Integer.class); // Verify callback with the subscriberId and the RAT type should be as expected. // It will fail if get a callback with an unexpected RAT type. @@ -302,26 +303,84 @@ public final class NetworkStatsSubscriptionsMonitorTest { reset(mDelegate); // Set IMSI to null again to simulate somehow IMSI is not available, such as - // modem crash. Verify service should not unregister listener. + // modem crash. Verify service should unregister listener. updateSubscriberIdForTestSub(TEST_SUBID1, null); - verify(mTelephonyManager, never()).listen(any(), anyInt()); - assertRatTypeNotChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_UMTS); + verify(mTelephonyManager, times(1)).listen(eq(ratTypeListenerCaptor.getValue()), + eq(PhoneStateListener.LISTEN_NONE)); + assertRatTypeChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_UNKNOWN); reset(mDelegate); + clearInvocations(mTelephonyManager); - // Set RAT type of sim1 to LTE. Verify RAT type of sim1 is still changed even if the IMSI - // is not available. The monitor keeps the listener even if the IMSI disappears because - // the IMSI can never change for any given subId, therefore even if the IMSI is updated - // to null, the monitor should continue accepting updates of the RAT type. However, - // telephony is never actually supposed to do this, if the IMSI disappears there should - // not be updates, but it's still the right thing to do theoretically. - setRatTypeForSub(ratTypeListenerCaptor.getAllValues(), TEST_SUBID1, + // Simulate somehow IMSI is back. Verify service will register with + // another listener and fire callback accordingly. + final ArgumentCaptor ratTypeListenerCaptor2 = + ArgumentCaptor.forClass(RatTypeListener.class); + updateSubscriberIdForTestSub(TEST_SUBID1, TEST_IMSI1); + verify(mTelephonyManager, times(1)).listen(ratTypeListenerCaptor2.capture(), + eq(PhoneStateListener.LISTEN_SERVICE_STATE)); + assertRatTypeNotChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_UNKNOWN); + reset(mDelegate); + clearInvocations(mTelephonyManager); + + // Set RAT type of sim1 to LTE. Verify RAT type of sim1 still works. + setRatTypeForSub(ratTypeListenerCaptor2.getAllValues(), TEST_SUBID1, TelephonyManager.NETWORK_TYPE_LTE); assertRatTypeChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_LTE); reset(mDelegate); mMonitor.stop(); - verify(mTelephonyManager, times(1)).listen(eq(ratTypeListenerCaptor.getValue()), + verify(mTelephonyManager, times(1)).listen(eq(ratTypeListenerCaptor2.getValue()), eq(PhoneStateListener.LISTEN_NONE)); assertRatTypeChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_UNKNOWN); } + + /** + * Verify that when IMSI suddenly changed for a given subId, the service will register a new + * listener and unregister the old one, and report changes on updated IMSI. This is for modem + * feature that may be enabled for certain carrier, which changes to use a different IMSI while + * roaming on certain networks for multi-IMSI SIM cards, but the subId stays the same. + */ + @Test + public void testSubscriberIdChanged() { + mMonitor.start(); + // Insert sim1, verify RAT type is NETWORK_TYPE_UNKNOWN, and never get any callback + // before changing RAT type. + addTestSub(TEST_SUBID1, TEST_IMSI1); + final ArgumentCaptor ratTypeListenerCaptor = + ArgumentCaptor.forClass(RatTypeListener.class); + verify(mTelephonyManager, times(1)).listen(ratTypeListenerCaptor.capture(), + eq(PhoneStateListener.LISTEN_SERVICE_STATE)); + assertRatTypeNotChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_UNKNOWN); + + // Set RAT type of sim1 to UMTS. + // Verify RAT type of sim1 changes accordingly. + setRatTypeForSub(ratTypeListenerCaptor.getAllValues(), TEST_SUBID1, + TelephonyManager.NETWORK_TYPE_UMTS); + assertRatTypeChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_UMTS); + reset(mDelegate); + clearInvocations(mTelephonyManager); + + // Simulate IMSI of sim1 changed to IMSI2. Verify the service will register with + // another listener and remove the old one. The RAT type of new IMSI stays at + // NETWORK_TYPE_UNKNOWN until received initial callback from telephony. + final ArgumentCaptor ratTypeListenerCaptor2 = + ArgumentCaptor.forClass(RatTypeListener.class); + updateSubscriberIdForTestSub(TEST_SUBID1, TEST_IMSI2); + verify(mTelephonyManager, times(1)).listen(ratTypeListenerCaptor2.capture(), + eq(PhoneStateListener.LISTEN_SERVICE_STATE)); + verify(mTelephonyManager, times(1)).listen(eq(ratTypeListenerCaptor.getValue()), + eq(PhoneStateListener.LISTEN_NONE)); + assertRatTypeChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_UNKNOWN); + assertRatTypeNotChangedForSub(TEST_IMSI2, TelephonyManager.NETWORK_TYPE_UNKNOWN); + reset(mDelegate); + + // Set RAT type of sim1 to UMTS for new listener to simulate the initial callback received + // from telephony after registration. Verify RAT type of sim1 changes with IMSI2 + // accordingly. + setRatTypeForSub(ratTypeListenerCaptor2.getAllValues(), TEST_SUBID1, + TelephonyManager.NETWORK_TYPE_UMTS); + assertRatTypeNotChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_UNKNOWN); + assertRatTypeChangedForSub(TEST_IMSI2, TelephonyManager.NETWORK_TYPE_UMTS); + reset(mDelegate); + } }