From 0b843a077d5c526f9f981eed31a698a390baf675 Mon Sep 17 00:00:00 2001 From: junyulai Date: Tue, 18 Aug 2020 18:50:13 +0800 Subject: Skip RAT type listener registration if IMSI is not available Currently, if SIM is inserted but IMSI is not available, such as SIM PIN locked state. Information of such SIM will still be available but IMSI is not. Which makes NetworkStatsSubscriptionMonitor failed to store IMSI locally for later RAT type query. Hence, NETWORK_TYPE_UNKNOWN is always returned for such SIM. Skip the registration until the IMSI is available. This is safe since there will be another onSubscriptionsChanged event when that happens. Test: enable SIM PIN and manually test Test: atest NetworkStatsSubscriptionsMonitorTest#testSubscriberIdUnavailable Test: ./out/host/linux-x86/bin/statsd_testdrive 10082 Bug: 160941101 Merged-In: I408379b3c432d9e62e0837d6b4f6551cc7838e29 Change-Id: I408379b3c432d9e62e0837d6b4f6551cc7838e29 (cherry-picked from ag/12400327) (cherry picked from commit 6afd939ba562ca463c29db805646eba6fe4e4297) --- .../net/NetworkStatsSubscriptionsMonitor.java | 13 +++-- .../net/NetworkStatsSubscriptionsMonitorTest.java | 56 ++++++++++++++++++++++ 2 files changed, 66 insertions(+), 3 deletions(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java b/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java index cb1c7e4fd0de..1c79332e9895 100644 --- a/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java +++ b/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java @@ -99,11 +99,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); @@ -112,6 +117,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)) { @@ -164,6 +170,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 diff --git a/tests/net/java/com/android/server/net/NetworkStatsSubscriptionsMonitorTest.java b/tests/net/java/com/android/server/net/NetworkStatsSubscriptionsMonitorTest.java index c91dfecf041b..7726c6637e0a 100644 --- a/tests/net/java/com/android/server/net/NetworkStatsSubscriptionsMonitorTest.java +++ b/tests/net/java/com/android/server/net/NetworkStatsSubscriptionsMonitorTest.java @@ -29,6 +29,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.Looper; @@ -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); @@ -268,4 +274,54 @@ public final class NetworkStatsSubscriptionsMonitorTest { listener.onServiceStateChanged(serviceState); assertRatTypeNotChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_NR); } + + @Test + public void testSubscriberIdUnavailable() { + final ArgumentCaptor 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); + } } -- cgit v1.2.3