Loading services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java +10 −3 Original line number Diff line number Diff line Loading @@ -100,11 +100,16 @@ public class NetworkStatsSubscriptionsMonitor extends if (match != null) continue; // Create listener for every newly added sub. Also store subscriberId into it to // prevent binder call to telephony when querying RAT. // prevent binder call to telephony when querying RAT. If the subscriberId is empty // for any reason, such as SIM PIN locked, skip registration. // SubscriberId will be unavailable again if 1. modem crashed 2. reboot // 3. re-insert SIM. If that happens, the listeners will be eventually synchronized // with active sub list once all subscriberIds are ready. final String subscriberId = mTeleManager.getSubscriberId(subId); if (TextUtils.isEmpty(subscriberId)) { Log.wtf(NetworkStatsService.TAG, "Empty subscriberId for newly added sub: " + subId); Log.d(NetworkStatsService.TAG, "Empty subscriberId for newly added sub " + subId + ", skip listener registration"); continue; } final RatTypeListener listener = new RatTypeListener(mExecutor, this, subId, subscriberId); Loading @@ -113,6 +118,7 @@ public class NetworkStatsSubscriptionsMonitor extends // Register listener to the telephony manager that associated with specific sub. mTeleManager.createForSubscriptionId(subId) .listen(listener, PhoneStateListener.LISTEN_SERVICE_STATE); Log.d(NetworkStatsService.TAG, "RAT type listener registered for sub " + subId); } for (final RatTypeListener listener : new ArrayList<>(mRatListeners)) { Loading Loading @@ -165,6 +171,7 @@ public class NetworkStatsSubscriptionsMonitor extends private void handleRemoveRatTypeListener(@NonNull RatTypeListener listener) { mTeleManager.createForSubscriptionId(listener.mSubId) .listen(listener, PhoneStateListener.LISTEN_NONE); Log.d(NetworkStatsService.TAG, "RAT type listener unregistered for sub " + listener.mSubId); mRatListeners.remove(listener); // Removal of subscriptions doesn't generate RAT changed event, fire it for every Loading tests/net/java/com/android/server/net/NetworkStatsSubscriptionsMonitorTest.java +56 −0 Original line number Diff line number Diff line Loading @@ -30,6 +30,7 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; import android.net.NetworkTemplate; import android.os.test.TestLooper; Loading Loading @@ -135,6 +136,11 @@ public final class NetworkStatsSubscriptionsMonitorTest { mMonitor.onSubscriptionsChanged(); } private void updateSubscriberIdForTestSub(int subId, @Nullable final String subscriberId) { when(mTelephonyManager.getSubscriberId(subId)).thenReturn(subscriberId); mMonitor.onSubscriptionsChanged(); } private void removeTestSub(int subId) { // Remove subId from TestSubList. mTestSubList.removeIf(it -> it == subId); Loading Loading @@ -268,4 +274,54 @@ public final class NetworkStatsSubscriptionsMonitorTest { listener.onServiceStateChanged(serviceState); assertRatTypeNotChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_NR); } @Test public void testSubscriberIdUnavailable() { final ArgumentCaptor<RatTypeListener> ratTypeListenerCaptor = ArgumentCaptor.forClass(RatTypeListener.class); mMonitor.start(); // Insert sim1, set subscriberId to null which is normal in SIM PIN locked case. // Verify RAT type is NETWORK_TYPE_UNKNOWN and service will not perform listener // registration. addTestSub(TEST_SUBID1, null); verify(mTelephonyManager, never()).listen(any(), anyInt()); assertRatTypeNotChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_UNKNOWN); // Set IMSI for sim1, verify the listener will be registered. updateSubscriberIdForTestSub(TEST_SUBID1, TEST_IMSI1); verify(mTelephonyManager, times(1)).listen(ratTypeListenerCaptor.capture(), eq(PhoneStateListener.LISTEN_SERVICE_STATE)); reset(mTelephonyManager); when(mTelephonyManager.createForSubscriptionId(anyInt())).thenReturn(mTelephonyManager); // Set RAT type of sim1 to UMTS. Verify RAT type of sim1 is changed. setRatTypeForSub(ratTypeListenerCaptor.getAllValues(), TEST_SUBID1, TelephonyManager.NETWORK_TYPE_UMTS); assertRatTypeChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_UMTS); reset(mDelegate); // Set IMSI to null again to simulate somehow IMSI is not available, such as // modem crash. Verify service should not unregister listener. updateSubscriberIdForTestSub(TEST_SUBID1, null); verify(mTelephonyManager, never()).listen(any(), anyInt()); assertRatTypeNotChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_UMTS); reset(mDelegate); // 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, TelephonyManager.NETWORK_TYPE_LTE); assertRatTypeChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_LTE); reset(mDelegate); mMonitor.stop(); verify(mTelephonyManager, times(1)).listen(eq(ratTypeListenerCaptor.getValue()), eq(PhoneStateListener.LISTEN_NONE)); assertRatTypeChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_UNKNOWN); } } Loading
services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java +10 −3 Original line number Diff line number Diff line Loading @@ -100,11 +100,16 @@ public class NetworkStatsSubscriptionsMonitor extends if (match != null) continue; // Create listener for every newly added sub. Also store subscriberId into it to // prevent binder call to telephony when querying RAT. // prevent binder call to telephony when querying RAT. If the subscriberId is empty // for any reason, such as SIM PIN locked, skip registration. // SubscriberId will be unavailable again if 1. modem crashed 2. reboot // 3. re-insert SIM. If that happens, the listeners will be eventually synchronized // with active sub list once all subscriberIds are ready. final String subscriberId = mTeleManager.getSubscriberId(subId); if (TextUtils.isEmpty(subscriberId)) { Log.wtf(NetworkStatsService.TAG, "Empty subscriberId for newly added sub: " + subId); Log.d(NetworkStatsService.TAG, "Empty subscriberId for newly added sub " + subId + ", skip listener registration"); continue; } final RatTypeListener listener = new RatTypeListener(mExecutor, this, subId, subscriberId); Loading @@ -113,6 +118,7 @@ public class NetworkStatsSubscriptionsMonitor extends // Register listener to the telephony manager that associated with specific sub. mTeleManager.createForSubscriptionId(subId) .listen(listener, PhoneStateListener.LISTEN_SERVICE_STATE); Log.d(NetworkStatsService.TAG, "RAT type listener registered for sub " + subId); } for (final RatTypeListener listener : new ArrayList<>(mRatListeners)) { Loading Loading @@ -165,6 +171,7 @@ public class NetworkStatsSubscriptionsMonitor extends private void handleRemoveRatTypeListener(@NonNull RatTypeListener listener) { mTeleManager.createForSubscriptionId(listener.mSubId) .listen(listener, PhoneStateListener.LISTEN_NONE); Log.d(NetworkStatsService.TAG, "RAT type listener unregistered for sub " + listener.mSubId); mRatListeners.remove(listener); // Removal of subscriptions doesn't generate RAT changed event, fire it for every Loading
tests/net/java/com/android/server/net/NetworkStatsSubscriptionsMonitorTest.java +56 −0 Original line number Diff line number Diff line Loading @@ -30,6 +30,7 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; import android.net.NetworkTemplate; import android.os.test.TestLooper; Loading Loading @@ -135,6 +136,11 @@ public final class NetworkStatsSubscriptionsMonitorTest { mMonitor.onSubscriptionsChanged(); } private void updateSubscriberIdForTestSub(int subId, @Nullable final String subscriberId) { when(mTelephonyManager.getSubscriberId(subId)).thenReturn(subscriberId); mMonitor.onSubscriptionsChanged(); } private void removeTestSub(int subId) { // Remove subId from TestSubList. mTestSubList.removeIf(it -> it == subId); Loading Loading @@ -268,4 +274,54 @@ public final class NetworkStatsSubscriptionsMonitorTest { listener.onServiceStateChanged(serviceState); assertRatTypeNotChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_NR); } @Test public void testSubscriberIdUnavailable() { final ArgumentCaptor<RatTypeListener> ratTypeListenerCaptor = ArgumentCaptor.forClass(RatTypeListener.class); mMonitor.start(); // Insert sim1, set subscriberId to null which is normal in SIM PIN locked case. // Verify RAT type is NETWORK_TYPE_UNKNOWN and service will not perform listener // registration. addTestSub(TEST_SUBID1, null); verify(mTelephonyManager, never()).listen(any(), anyInt()); assertRatTypeNotChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_UNKNOWN); // Set IMSI for sim1, verify the listener will be registered. updateSubscriberIdForTestSub(TEST_SUBID1, TEST_IMSI1); verify(mTelephonyManager, times(1)).listen(ratTypeListenerCaptor.capture(), eq(PhoneStateListener.LISTEN_SERVICE_STATE)); reset(mTelephonyManager); when(mTelephonyManager.createForSubscriptionId(anyInt())).thenReturn(mTelephonyManager); // Set RAT type of sim1 to UMTS. Verify RAT type of sim1 is changed. setRatTypeForSub(ratTypeListenerCaptor.getAllValues(), TEST_SUBID1, TelephonyManager.NETWORK_TYPE_UMTS); assertRatTypeChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_UMTS); reset(mDelegate); // Set IMSI to null again to simulate somehow IMSI is not available, such as // modem crash. Verify service should not unregister listener. updateSubscriberIdForTestSub(TEST_SUBID1, null); verify(mTelephonyManager, never()).listen(any(), anyInt()); assertRatTypeNotChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_UMTS); reset(mDelegate); // 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, TelephonyManager.NETWORK_TYPE_LTE); assertRatTypeChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_LTE); reset(mDelegate); mMonitor.stop(); verify(mTelephonyManager, times(1)).listen(eq(ratTypeListenerCaptor.getValue()), eq(PhoneStateListener.LISTEN_NONE)); assertRatTypeChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_UNKNOWN); } }