Merge "Support dynamically update IMSI"
This commit is contained in:
@@ -30,6 +30,7 @@ import android.telephony.SubscriptionManager;
|
|||||||
import android.telephony.TelephonyManager;
|
import android.telephony.TelephonyManager;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
import android.util.Pair;
|
||||||
|
|
||||||
import com.android.internal.annotations.VisibleForTesting;
|
import com.android.internal.annotations.VisibleForTesting;
|
||||||
import com.android.internal.util.CollectionUtils;
|
import com.android.internal.util.CollectionUtils;
|
||||||
@@ -94,39 +95,41 @@ public class NetworkStatsSubscriptionsMonitor extends
|
|||||||
// also needed to track CBRS.
|
// also needed to track CBRS.
|
||||||
final List<Integer> newSubs = getActiveSubIdList(mSubscriptionManager);
|
final List<Integer> newSubs = getActiveSubIdList(mSubscriptionManager);
|
||||||
|
|
||||||
for (final int subId : newSubs) {
|
// IMSI is needed for every newly added sub. Listener stores subscriberId into it to
|
||||||
final RatTypeListener match = CollectionUtils.find(mRatListeners,
|
// prevent binder call to telephony when querying RAT. Keep listener registration with empty
|
||||||
it -> it.mSubId == subId);
|
// IMSI is meaningless since the RAT type changed is ambiguous for multi-SIM if reported
|
||||||
if (match != null) continue;
|
// with empty IMSI. So filter the subs w/o a valid IMSI to prevent such registration.
|
||||||
|
final List<Pair<Integer, String>> filteredNewSubs =
|
||||||
|
CollectionUtils.mapNotNull(newSubs, subId -> {
|
||||||
|
final String subscriberId = mTeleManager.getSubscriberId(subId);
|
||||||
|
return TextUtils.isEmpty(subscriberId) ? null : new Pair(subId, subscriberId);
|
||||||
|
});
|
||||||
|
|
||||||
// Create listener for every newly added sub. Also store subscriberId into it to
|
for (final Pair<Integer, String> sub : filteredNewSubs) {
|
||||||
// prevent binder call to telephony when querying RAT. If the subscriberId is empty
|
// Fully match listener with subId and IMSI, since in some rare cases, IMSI might be
|
||||||
// for any reason, such as SIM PIN locked, skip registration.
|
// suddenly change regardless of subId, such as switch IMSI feature in modem side.
|
||||||
// SubscriberId will be unavailable again if 1. modem crashed 2. reboot
|
// If that happens, register new listener with new IMSI and remove old one later.
|
||||||
// 3. re-insert SIM. If that happens, the listeners will be eventually synchronized
|
if (CollectionUtils.find(mRatListeners,
|
||||||
// with active sub list once all subscriberIds are ready.
|
it -> it.equalsKey(sub.first, sub.second)) != null) {
|
||||||
final String subscriberId = mTeleManager.getSubscriberId(subId);
|
|
||||||
if (TextUtils.isEmpty(subscriberId)) {
|
|
||||||
Log.d(NetworkStatsService.TAG, "Empty subscriberId for newly added sub "
|
|
||||||
+ subId + ", skip listener registration");
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
final RatTypeListener listener =
|
final RatTypeListener listener =
|
||||||
new RatTypeListener(mExecutor, this, subId, subscriberId);
|
new RatTypeListener(mExecutor, this, sub.first, sub.second);
|
||||||
mRatListeners.add(listener);
|
mRatListeners.add(listener);
|
||||||
|
|
||||||
// Register listener to the telephony manager that associated with specific sub.
|
// Register listener to the telephony manager that associated with specific sub.
|
||||||
mTeleManager.createForSubscriptionId(subId)
|
mTeleManager.createForSubscriptionId(sub.first)
|
||||||
.listen(listener, PhoneStateListener.LISTEN_SERVICE_STATE);
|
.listen(listener, PhoneStateListener.LISTEN_SERVICE_STATE);
|
||||||
Log.d(NetworkStatsService.TAG, "RAT type listener registered for sub " + subId);
|
Log.d(NetworkStatsService.TAG, "RAT type listener registered for sub " + sub.first);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (final RatTypeListener listener : new ArrayList<>(mRatListeners)) {
|
for (final RatTypeListener listener : new ArrayList<>(mRatListeners)) {
|
||||||
// If the new list contains the subId of the listener, keeps it.
|
// If there is no subId and IMSI matched the listener, removes it.
|
||||||
final Integer match = CollectionUtils.find(newSubs, it -> it == listener.mSubId);
|
if (CollectionUtils.find(filteredNewSubs,
|
||||||
if (match != null) continue;
|
it -> listener.equalsKey(it.first, it.second)) == null) {
|
||||||
|
handleRemoveRatTypeListener(listener);
|
||||||
handleRemoveRatTypeListener(listener);
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -232,5 +235,9 @@ public class NetworkStatsSubscriptionsMonitor extends
|
|||||||
public int getSubId() {
|
public int getSubId() {
|
||||||
return mSubId;
|
return mSubId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean equalsKey(int subId, @NonNull String subscriberId) {
|
||||||
|
return mSubId == subId && TextUtils.equals(mSubscriberId, subscriberId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import static org.junit.Assert.assertNotNull;
|
|||||||
import static org.junit.Assert.fail;
|
import static org.junit.Assert.fail;
|
||||||
import static org.mockito.Mockito.any;
|
import static org.mockito.Mockito.any;
|
||||||
import static org.mockito.Mockito.anyInt;
|
import static org.mockito.Mockito.anyInt;
|
||||||
|
import static org.mockito.Mockito.clearInvocations;
|
||||||
import static org.mockito.Mockito.eq;
|
import static org.mockito.Mockito.eq;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
import static org.mockito.Mockito.never;
|
import static org.mockito.Mockito.never;
|
||||||
@@ -150,7 +151,7 @@ public final class NetworkStatsSubscriptionsMonitorTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void assertRatTypeChangedForSub(String subscriberId, int ratType) {
|
private void assertRatTypeChangedForSub(String subscriberId, int ratType) {
|
||||||
assertEquals(mMonitor.getRatTypeForSubscriberId(subscriberId), ratType);
|
assertEquals(ratType, mMonitor.getRatTypeForSubscriberId(subscriberId));
|
||||||
final ArgumentCaptor<Integer> typeCaptor = ArgumentCaptor.forClass(Integer.class);
|
final ArgumentCaptor<Integer> typeCaptor = ArgumentCaptor.forClass(Integer.class);
|
||||||
// Verify callback with the subscriberId and the RAT type should be as expected.
|
// 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.
|
// It will fail if get a callback with an unexpected RAT type.
|
||||||
@@ -302,26 +303,84 @@ public final class NetworkStatsSubscriptionsMonitorTest {
|
|||||||
reset(mDelegate);
|
reset(mDelegate);
|
||||||
|
|
||||||
// Set IMSI to null again to simulate somehow IMSI is not available, such as
|
// 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);
|
updateSubscriberIdForTestSub(TEST_SUBID1, null);
|
||||||
verify(mTelephonyManager, never()).listen(any(), anyInt());
|
verify(mTelephonyManager, times(1)).listen(eq(ratTypeListenerCaptor.getValue()),
|
||||||
assertRatTypeNotChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_UMTS);
|
eq(PhoneStateListener.LISTEN_NONE));
|
||||||
|
assertRatTypeChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_UNKNOWN);
|
||||||
reset(mDelegate);
|
reset(mDelegate);
|
||||||
|
clearInvocations(mTelephonyManager);
|
||||||
|
|
||||||
// Set RAT type of sim1 to LTE. Verify RAT type of sim1 is still changed even if the IMSI
|
// Simulate somehow IMSI is back. Verify service will register with
|
||||||
// is not available. The monitor keeps the listener even if the IMSI disappears because
|
// another listener and fire callback accordingly.
|
||||||
// the IMSI can never change for any given subId, therefore even if the IMSI is updated
|
final ArgumentCaptor<RatTypeListener> ratTypeListenerCaptor2 =
|
||||||
// to null, the monitor should continue accepting updates of the RAT type. However,
|
ArgumentCaptor.forClass(RatTypeListener.class);
|
||||||
// telephony is never actually supposed to do this, if the IMSI disappears there should
|
updateSubscriberIdForTestSub(TEST_SUBID1, TEST_IMSI1);
|
||||||
// not be updates, but it's still the right thing to do theoretically.
|
verify(mTelephonyManager, times(1)).listen(ratTypeListenerCaptor2.capture(),
|
||||||
setRatTypeForSub(ratTypeListenerCaptor.getAllValues(), TEST_SUBID1,
|
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);
|
TelephonyManager.NETWORK_TYPE_LTE);
|
||||||
assertRatTypeChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_LTE);
|
assertRatTypeChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_LTE);
|
||||||
reset(mDelegate);
|
reset(mDelegate);
|
||||||
|
|
||||||
mMonitor.stop();
|
mMonitor.stop();
|
||||||
verify(mTelephonyManager, times(1)).listen(eq(ratTypeListenerCaptor.getValue()),
|
verify(mTelephonyManager, times(1)).listen(eq(ratTypeListenerCaptor2.getValue()),
|
||||||
eq(PhoneStateListener.LISTEN_NONE));
|
eq(PhoneStateListener.LISTEN_NONE));
|
||||||
assertRatTypeChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_UNKNOWN);
|
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<RatTypeListener> 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<RatTypeListener> 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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user