Merge changes Ia5022310,Ia4529d08

* changes:
  Remove VCN Carrier Privilege grace period
  Update TelephonySubscriptionTracker to use CarrierPrivilegesListener
This commit is contained in:
Benedict Wong
2022-01-08 01:43:17 +00:00
committed by Gerrit Code Review
4 changed files with 201 additions and 148 deletions

View File

@@ -24,7 +24,6 @@ import static android.net.vcn.VcnManager.VCN_STATUS_CODE_ACTIVE;
import static android.net.vcn.VcnManager.VCN_STATUS_CODE_INACTIVE; import static android.net.vcn.VcnManager.VCN_STATUS_CODE_INACTIVE;
import static android.net.vcn.VcnManager.VCN_STATUS_CODE_NOT_CONFIGURED; import static android.net.vcn.VcnManager.VCN_STATUS_CODE_NOT_CONFIGURED;
import static android.net.vcn.VcnManager.VCN_STATUS_CODE_SAFE_MODE; import static android.net.vcn.VcnManager.VCN_STATUS_CODE_SAFE_MODE;
import static android.telephony.SubscriptionManager.isValidSubscriptionId;
import static com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot; import static com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot;
import static com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionTrackerCallback; import static com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionTrackerCallback;
@@ -164,10 +163,6 @@ public class VcnManagementService extends IVcnManagementService.Stub {
@VisibleForTesting(visibility = Visibility.PRIVATE) @VisibleForTesting(visibility = Visibility.PRIVATE)
static final String VCN_CONFIG_FILE = "/data/system/vcn/configs.xml"; static final String VCN_CONFIG_FILE = "/data/system/vcn/configs.xml";
// TODO(b/176956496): Directly use CarrierServiceBindHelper.UNBIND_DELAY_MILLIS
@VisibleForTesting(visibility = Visibility.PRIVATE)
static final long CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS = TimeUnit.SECONDS.toMillis(30);
/* Binder context for this service */ /* Binder context for this service */
@NonNull private final Context mContext; @NonNull private final Context mContext;
@NonNull private final Dependencies mDeps; @NonNull private final Dependencies mDeps;
@@ -372,12 +367,15 @@ public class VcnManagementService extends IVcnManagementService.Stub {
/** Notifies the VcnManagementService that external dependencies can be set up. */ /** Notifies the VcnManagementService that external dependencies can be set up. */
public void systemReady() { public void systemReady() {
// Always run on the handler thread to ensure consistency.
mHandler.post(() -> {
mNetworkProvider.register(); mNetworkProvider.register();
mContext.getSystemService(ConnectivityManager.class) mContext.getSystemService(ConnectivityManager.class)
.registerNetworkCallback( .registerNetworkCallback(
new NetworkRequest.Builder().clearCapabilities().build(), new NetworkRequest.Builder().clearCapabilities().build(),
mTrackingNetworkCallback); mTrackingNetworkCallback);
mTelephonySubscriptionTracker.register(); mTelephonySubscriptionTracker.register();
});
} }
private void enforcePrimaryUser() { private void enforcePrimaryUser() {
@@ -471,22 +469,15 @@ public class VcnManagementService extends IVcnManagementService.Stub {
if (!mVcns.containsKey(subGrp)) { if (!mVcns.containsKey(subGrp)) {
startVcnLocked(subGrp, entry.getValue()); startVcnLocked(subGrp, entry.getValue());
} }
// Cancel any scheduled teardowns for active subscriptions
mHandler.removeCallbacksAndMessages(mVcns.get(subGrp));
} }
} }
// Schedule teardown of any VCN instances that have lost carrier privileges (after a // Schedule teardown of any VCN instances that have lost carrier privileges
// delay)
for (Entry<ParcelUuid, Vcn> entry : mVcns.entrySet()) { for (Entry<ParcelUuid, Vcn> entry : mVcns.entrySet()) {
final ParcelUuid subGrp = entry.getKey(); final ParcelUuid subGrp = entry.getKey();
final VcnConfig config = mConfigs.get(subGrp); final VcnConfig config = mConfigs.get(subGrp);
final boolean isActiveSubGrp = isActiveSubGroup(subGrp, snapshot); final boolean isActiveSubGrp = isActiveSubGroup(subGrp, snapshot);
final boolean isValidActiveDataSubIdNotInVcnSubGrp =
isValidSubscriptionId(snapshot.getActiveDataSubscriptionId())
&& !isActiveSubGroup(subGrp, snapshot);
// TODO(b/193687515): Support multiple VCNs active at the same time // TODO(b/193687515): Support multiple VCNs active at the same time
if (config == null if (config == null
@@ -496,31 +487,12 @@ public class VcnManagementService extends IVcnManagementService.Stub {
final ParcelUuid uuidToTeardown = subGrp; final ParcelUuid uuidToTeardown = subGrp;
final Vcn instanceToTeardown = entry.getValue(); final Vcn instanceToTeardown = entry.getValue();
// TODO(b/193687515): Support multiple VCNs active at the same time
// If directly switching to a subscription not in the current group,
// teardown immediately to prevent other subscription's network from being
// outscored by the VCN. Otherwise, teardown after a delay to ensure that
// SIM profile switches do not trigger the VCN to cycle.
final long teardownDelayMs =
isValidActiveDataSubIdNotInVcnSubGrp
? 0
: CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS;
mHandler.postDelayed(() -> {
synchronized (mLock) {
// Guard against case where this is run after a old instance was
// torn down, and a new instance was started. Verify to ensure
// correct instance is torn down. This could happen as a result of a
// Carrier App manually removing/adding a VcnConfig.
if (mVcns.get(uuidToTeardown) == instanceToTeardown) {
stopVcnLocked(uuidToTeardown); stopVcnLocked(uuidToTeardown);
// TODO(b/181789060): invoke asynchronously after Vcn notifies // TODO(b/181789060): invoke asynchronously after Vcn notifies
// through VcnCallback // through VcnCallback
notifyAllPermissionedStatusCallbacksLocked( notifyAllPermissionedStatusCallbacksLocked(
uuidToTeardown, VCN_STATUS_CODE_INACTIVE); uuidToTeardown, VCN_STATUS_CODE_INACTIVE);
}
}
}, instanceToTeardown, teardownDelayMs);
} else { } else {
// If this VCN's status has not changed, update it with the new snapshot // If this VCN's status has not changed, update it with the new snapshot
entry.getValue().updateSubscriptionSnapshot(mLastSnapshot); entry.getValue().updateSubscriptionSnapshot(mLastSnapshot);

View File

@@ -21,6 +21,7 @@ import static android.telephony.CarrierConfigManager.EXTRA_SLOT_INDEX;
import static android.telephony.CarrierConfigManager.EXTRA_SUBSCRIPTION_INDEX; import static android.telephony.CarrierConfigManager.EXTRA_SUBSCRIPTION_INDEX;
import static android.telephony.SubscriptionManager.INVALID_SIM_SLOT_INDEX; import static android.telephony.SubscriptionManager.INVALID_SIM_SLOT_INDEX;
import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
import static android.telephony.TelephonyManager.ACTION_MULTI_SIM_CONFIG_CHANGED;
import android.annotation.NonNull; import android.annotation.NonNull;
import android.annotation.Nullable; import android.annotation.Nullable;
@@ -38,15 +39,19 @@ import android.telephony.SubscriptionManager;
import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener; import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener;
import android.telephony.TelephonyCallback; import android.telephony.TelephonyCallback;
import android.telephony.TelephonyManager; import android.telephony.TelephonyManager;
import android.telephony.TelephonyManager.CarrierPrivilegesListener;
import android.util.ArrayMap; import android.util.ArrayMap;
import android.util.ArraySet; import android.util.ArraySet;
import android.util.Slog;
import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.annotations.VisibleForTesting.Visibility; import com.android.internal.annotations.VisibleForTesting.Visibility;
import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.IndentingPrintWriter;
import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
@@ -92,6 +97,10 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver {
@NonNull private final Map<Integer, Integer> mReadySubIdsBySlotId = new HashMap<>(); @NonNull private final Map<Integer, Integer> mReadySubIdsBySlotId = new HashMap<>();
@NonNull private final OnSubscriptionsChangedListener mSubscriptionChangedListener; @NonNull private final OnSubscriptionsChangedListener mSubscriptionChangedListener;
@NonNull
private final List<CarrierPrivilegesListener> mCarrierPrivilegesChangedListeners =
new ArrayList<>();
@NonNull private TelephonySubscriptionSnapshot mCurrentSnapshot; @NonNull private TelephonySubscriptionSnapshot mCurrentSnapshot;
public TelephonySubscriptionTracker( public TelephonySubscriptionTracker(
@@ -126,22 +135,71 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver {
}; };
} }
/** Registers the receivers, and starts tracking subscriptions. */ /**
* Registers the receivers, and starts tracking subscriptions.
*
* <p>Must always be run on the VcnManagementService thread.
*/
public void register() { public void register() {
final HandlerExecutor executor = new HandlerExecutor(mHandler); final HandlerExecutor executor = new HandlerExecutor(mHandler);
final IntentFilter filter = new IntentFilter();
filter.addAction(ACTION_CARRIER_CONFIG_CHANGED);
filter.addAction(ACTION_MULTI_SIM_CONFIG_CHANGED);
mContext.registerReceiver( mContext.registerReceiver(this, filter, null, mHandler);
this, new IntentFilter(ACTION_CARRIER_CONFIG_CHANGED), null, mHandler);
mSubscriptionManager.addOnSubscriptionsChangedListener( mSubscriptionManager.addOnSubscriptionsChangedListener(
executor, mSubscriptionChangedListener); executor, mSubscriptionChangedListener);
mTelephonyManager.registerTelephonyCallback(executor, mActiveDataSubIdListener); mTelephonyManager.registerTelephonyCallback(executor, mActiveDataSubIdListener);
registerCarrierPrivilegesListeners();
} }
/** Unregisters the receivers, and stops tracking subscriptions. */ private void registerCarrierPrivilegesListeners() {
final HandlerExecutor executor = new HandlerExecutor(mHandler);
final int modemCount = mTelephonyManager.getActiveModemCount();
try {
for (int i = 0; i < modemCount; i++) {
CarrierPrivilegesListener carrierPrivilegesListener =
new CarrierPrivilegesListener() {
@Override
public void onCarrierPrivilegesChanged(
@NonNull List<String> privilegedPackageNames,
@NonNull int[] privilegedUids) {
// Re-trigger the synchronous check (which is also very cheap due
// to caching in CarrierPrivilegesTracker). This allows consistency
// with the onSubscriptionsChangedListener and broadcasts.
handleSubscriptionsChanged();
}
};
mTelephonyManager.addCarrierPrivilegesListener(
i, executor, carrierPrivilegesListener);
mCarrierPrivilegesChangedListeners.add(carrierPrivilegesListener);
}
} catch (IllegalArgumentException e) {
Slog.wtf(TAG, "Encounted exception registering carrier privileges listeners", e);
}
}
/**
* Unregisters the receivers, and stops tracking subscriptions.
*
* <p>Must always be run on the VcnManagementService thread.
*/
public void unregister() { public void unregister() {
mContext.unregisterReceiver(this); mContext.unregisterReceiver(this);
mSubscriptionManager.removeOnSubscriptionsChangedListener(mSubscriptionChangedListener); mSubscriptionManager.removeOnSubscriptionsChangedListener(mSubscriptionChangedListener);
mTelephonyManager.unregisterTelephonyCallback(mActiveDataSubIdListener); mTelephonyManager.unregisterTelephonyCallback(mActiveDataSubIdListener);
unregisterCarrierPrivilegesListeners();
}
private void unregisterCarrierPrivilegesListeners() {
for (CarrierPrivilegesListener carrierPrivilegesListener :
mCarrierPrivilegesChangedListeners) {
mTelephonyManager.removeCarrierPrivilegesListener(carrierPrivilegesListener);
}
mCarrierPrivilegesChangedListeners.clear();
} }
/** /**
@@ -178,8 +236,6 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver {
// group. // group.
if (subInfo.getSimSlotIndex() != INVALID_SIM_SLOT_INDEX if (subInfo.getSimSlotIndex() != INVALID_SIM_SLOT_INDEX
&& mReadySubIdsBySlotId.values().contains(subInfo.getSubscriptionId())) { && mReadySubIdsBySlotId.values().contains(subInfo.getSubscriptionId())) {
// TODO (b/172619301): Cache based on callbacks from CarrierPrivilegesTracker
final TelephonyManager subIdSpecificTelephonyManager = final TelephonyManager subIdSpecificTelephonyManager =
mTelephonyManager.createForSubscriptionId(subInfo.getSubscriptionId()); mTelephonyManager.createForSubscriptionId(subInfo.getSubscriptionId());
@@ -214,12 +270,39 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver {
*/ */
@Override @Override
public void onReceive(Context context, Intent intent) { public void onReceive(Context context, Intent intent) {
// Accept sticky broadcasts; if CARRIER_CONFIG_CHANGED was previously broadcast and it switch (intent.getAction()) {
// already was for an identified carrier, we can stop waiting for initial load to complete case ACTION_CARRIER_CONFIG_CHANGED:
if (!ACTION_CARRIER_CONFIG_CHANGED.equals(intent.getAction())) { handleActionCarrierConfigChanged(context, intent);
return; break;
case ACTION_MULTI_SIM_CONFIG_CHANGED:
handleActionMultiSimConfigChanged(context, intent);
break;
default:
Slog.v(TAG, "Unknown intent received with action: " + intent.getAction());
}
} }
private void handleActionMultiSimConfigChanged(Context context, Intent intent) {
unregisterCarrierPrivilegesListeners();
// Clear invalid slotIds from the mReadySubIdsBySlotId map.
final int modemCount = mTelephonyManager.getActiveModemCount();
final Iterator<Integer> slotIdIterator = mReadySubIdsBySlotId.keySet().iterator();
while (slotIdIterator.hasNext()) {
final int slotId = slotIdIterator.next();
if (slotId >= modemCount) {
slotIdIterator.remove();
}
}
registerCarrierPrivilegesListeners();
handleSubscriptionsChanged();
}
private void handleActionCarrierConfigChanged(Context context, Intent intent) {
// Accept sticky broadcasts; if CARRIER_CONFIG_CHANGED was previously broadcast and it
// already was for an identified carrier, we can stop waiting for initial load to complete
final int subId = intent.getIntExtra(EXTRA_SUBSCRIPTION_INDEX, INVALID_SUBSCRIPTION_ID); final int subId = intent.getIntExtra(EXTRA_SUBSCRIPTION_INDEX, INVALID_SUBSCRIPTION_ID);
final int slotId = intent.getIntExtra(EXTRA_SLOT_INDEX, INVALID_SIM_SLOT_INDEX); final int slotId = intent.getIntExtra(EXTRA_SLOT_INDEX, INVALID_SIM_SLOT_INDEX);

View File

@@ -23,7 +23,6 @@ import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
import static android.net.NetworkCapabilities.TRANSPORT_WIFI; import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
import static android.net.vcn.VcnManager.VCN_STATUS_CODE_ACTIVE; import static android.net.vcn.VcnManager.VCN_STATUS_CODE_ACTIVE;
import static android.net.vcn.VcnManager.VCN_STATUS_CODE_SAFE_MODE; import static android.net.vcn.VcnManager.VCN_STATUS_CODE_SAFE_MODE;
import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
import static android.telephony.TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS; import static android.telephony.TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS;
import static android.telephony.TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS; import static android.telephony.TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS;
@@ -264,6 +263,7 @@ public class VcnManagementServiceTest {
@Test @Test
public void testSystemReady() throws Exception { public void testSystemReady() throws Exception {
mVcnMgmtSvc.systemReady(); mVcnMgmtSvc.systemReady();
mTestLooper.dispatchAll();
verify(mConnMgr).registerNetworkProvider(any(VcnNetworkProvider.class)); verify(mConnMgr).registerNetworkProvider(any(VcnNetworkProvider.class));
verify(mSubscriptionTracker).register(); verify(mSubscriptionTracker).register();
@@ -475,10 +475,8 @@ public class VcnManagementServiceTest {
mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener); mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);
triggerSubscriptionTrackerCbAndGetSnapshot(null, Collections.emptySet()); triggerSubscriptionTrackerCbAndGetSnapshot(null, Collections.emptySet());
// Verify teardown after delay
mTestLooper.moveTimeForward(VcnManagementService.CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS);
mTestLooper.dispatchAll(); mTestLooper.dispatchAll();
verify(vcn).teardownAsynchronously(); verify(vcn).teardownAsynchronously();
verify(mMockPolicyListener).onPolicyChanged(); verify(mMockPolicyListener).onPolicyChanged();
} }
@@ -504,92 +502,6 @@ public class VcnManagementServiceTest {
assertEquals(0, mVcnMgmtSvc.getAllVcns().size()); assertEquals(0, mVcnMgmtSvc.getAllVcns().size());
} }
/**
* Tests an intermediate state where carrier privileges are marked as lost before active data
* subId changes during a SIM ejection.
*
* <p>The expected outcome is that the VCN is torn down after a delay, as opposed to
* immediately.
*/
@Test
public void testTelephonyNetworkTrackerCallbackLostCarrierPrivilegesBeforeActiveDataSubChanges()
throws Exception {
setupActiveSubscription(TEST_UUID_2);
final TelephonySubscriptionTrackerCallback cb = getTelephonySubscriptionTrackerCallback();
final Vcn vcn = startAndGetVcnInstance(TEST_UUID_2);
// Simulate privileges lost
triggerSubscriptionTrackerCbAndGetSnapshot(
TEST_SUBSCRIPTION_ID,
TEST_UUID_2,
Collections.emptySet(),
Collections.emptyMap(),
false /* hasCarrierPrivileges */);
// Verify teardown after delay
mTestLooper.moveTimeForward(VcnManagementService.CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS);
mTestLooper.dispatchAll();
verify(vcn).teardownAsynchronously();
}
@Test
public void testTelephonyNetworkTrackerCallbackSimSwitchesDoNotKillVcnInstances()
throws Exception {
setupActiveSubscription(TEST_UUID_2);
final TelephonySubscriptionTrackerCallback cb = getTelephonySubscriptionTrackerCallback();
final Vcn vcn = startAndGetVcnInstance(TEST_UUID_2);
// Simulate SIM unloaded
triggerSubscriptionTrackerCbAndGetSnapshot(
INVALID_SUBSCRIPTION_ID,
null /* activeDataSubscriptionGroup */,
Collections.emptySet(),
Collections.emptyMap(),
false /* hasCarrierPrivileges */);
// Simulate new SIM loaded right during teardown delay.
mTestLooper.moveTimeForward(
VcnManagementService.CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS / 2);
mTestLooper.dispatchAll();
triggerSubscriptionTrackerCbAndGetSnapshot(TEST_UUID_2, Collections.singleton(TEST_UUID_2));
// Verify that even after the full timeout duration, the VCN instance is not torn down
mTestLooper.moveTimeForward(VcnManagementService.CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS);
mTestLooper.dispatchAll();
verify(vcn, never()).teardownAsynchronously();
}
@Test
public void testTelephonyNetworkTrackerCallbackDoesNotKillNewVcnInstances() throws Exception {
setupActiveSubscription(TEST_UUID_2);
final TelephonySubscriptionTrackerCallback cb = getTelephonySubscriptionTrackerCallback();
final Vcn oldInstance = startAndGetVcnInstance(TEST_UUID_2);
// Simulate SIM unloaded
triggerSubscriptionTrackerCbAndGetSnapshot(null, Collections.emptySet());
// Config cleared, SIM reloaded & config re-added right before teardown delay, staring new
// vcnInstance.
mTestLooper.moveTimeForward(
VcnManagementService.CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS / 2);
mTestLooper.dispatchAll();
mVcnMgmtSvc.clearVcnConfig(TEST_UUID_2, TEST_PACKAGE_NAME);
triggerSubscriptionTrackerCbAndGetSnapshot(TEST_UUID_2, Collections.singleton(TEST_UUID_2));
final Vcn newInstance = startAndGetVcnInstance(TEST_UUID_2);
// Verify that new instance was different, and the old one was torn down
assertTrue(oldInstance != newInstance);
verify(oldInstance).teardownAsynchronously();
// Verify that even after the full timeout duration, the new VCN instance is not torn down
mTestLooper.moveTimeForward(VcnManagementService.CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS);
mTestLooper.dispatchAll();
verify(newInstance, never()).teardownAsynchronously();
}
@Test @Test
public void testPackageChangeListenerRegistered() throws Exception { public void testPackageChangeListenerRegistered() throws Exception {
verify(mMockContext).registerReceiver(any(BroadcastReceiver.class), argThat(filter -> { verify(mMockContext).registerReceiver(any(BroadcastReceiver.class), argThat(filter -> {
@@ -925,6 +837,8 @@ public class VcnManagementServiceTest {
private void setupSubscriptionAndStartVcn( private void setupSubscriptionAndStartVcn(
int subId, ParcelUuid subGrp, boolean isVcnActive, boolean hasCarrierPrivileges) { int subId, ParcelUuid subGrp, boolean isVcnActive, boolean hasCarrierPrivileges) {
mVcnMgmtSvc.systemReady(); mVcnMgmtSvc.systemReady();
mTestLooper.dispatchAll();
triggerSubscriptionTrackerCbAndGetSnapshot( triggerSubscriptionTrackerCbAndGetSnapshot(
subGrp, subGrp,
Collections.singleton(subGrp), Collections.singleton(subGrp),
@@ -1020,6 +934,7 @@ public class VcnManagementServiceTest {
private void setupTrackedCarrierWifiNetwork(NetworkCapabilities caps) { private void setupTrackedCarrierWifiNetwork(NetworkCapabilities caps) {
mVcnMgmtSvc.systemReady(); mVcnMgmtSvc.systemReady();
mTestLooper.dispatchAll();
final ArgumentCaptor<NetworkCallback> captor = final ArgumentCaptor<NetworkCallback> captor =
ArgumentCaptor.forClass(NetworkCallback.class); ArgumentCaptor.forClass(NetworkCallback.class);
@@ -1264,15 +1179,14 @@ public class VcnManagementServiceTest {
true /* isActive */, true /* isActive */,
true /* hasCarrierPrivileges */); true /* hasCarrierPrivileges */);
// VCN is currently active. Lose carrier privileges for TEST_PACKAGE and hit teardown // VCN is currently active. Lose carrier privileges for TEST_PACKAGE so the VCN goes
// timeout so the VCN goes inactive. // inactive.
final TelephonySubscriptionSnapshot snapshot = final TelephonySubscriptionSnapshot snapshot =
triggerSubscriptionTrackerCbAndGetSnapshot( triggerSubscriptionTrackerCbAndGetSnapshot(
TEST_UUID_1, TEST_UUID_1,
Collections.singleton(TEST_UUID_1), Collections.singleton(TEST_UUID_1),
Collections.singletonMap(TEST_SUBSCRIPTION_ID, TEST_UUID_1), Collections.singletonMap(TEST_SUBSCRIPTION_ID, TEST_UUID_1),
false /* hasCarrierPrivileges */); false /* hasCarrierPrivileges */);
mTestLooper.moveTimeForward(VcnManagementService.CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS);
mTestLooper.dispatchAll(); mTestLooper.dispatchAll();
// Giving TEST_PACKAGE privileges again will restart the VCN (which will indicate ACTIVE // Giving TEST_PACKAGE privileges again will restart the VCN (which will indicate ACTIVE

View File

@@ -22,6 +22,7 @@ import static android.telephony.CarrierConfigManager.EXTRA_SUBSCRIPTION_INDEX;
import static android.telephony.SubscriptionManager.INVALID_SIM_SLOT_INDEX; import static android.telephony.SubscriptionManager.INVALID_SIM_SLOT_INDEX;
import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
import static android.telephony.TelephonyCallback.ActiveDataSubscriptionIdListener; import static android.telephony.TelephonyCallback.ActiveDataSubscriptionIdListener;
import static android.telephony.TelephonyManager.ACTION_MULTI_SIM_CONFIG_CHANGED;
import static com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot; import static com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot;
import static com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionTrackerCallback; import static com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionTrackerCallback;
@@ -34,8 +35,10 @@ import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.verifyNoMoreInteractions;
@@ -57,6 +60,8 @@ import android.telephony.SubscriptionManager;
import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener; import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener;
import android.telephony.TelephonyCallback; import android.telephony.TelephonyCallback;
import android.telephony.TelephonyManager; import android.telephony.TelephonyManager;
import android.telephony.TelephonyManager.CarrierPrivilegesListener;
import android.util.ArrayMap;
import android.util.ArraySet; import android.util.ArraySet;
import androidx.test.filters.SmallTest; import androidx.test.filters.SmallTest;
@@ -83,7 +88,7 @@ public class TelephonySubscriptionTrackerTest {
private static final String PACKAGE_NAME = private static final String PACKAGE_NAME =
TelephonySubscriptionTrackerTest.class.getPackage().getName(); TelephonySubscriptionTrackerTest.class.getPackage().getName();
private static final ParcelUuid TEST_PARCEL_UUID = new ParcelUuid(UUID.randomUUID()); private static final ParcelUuid TEST_PARCEL_UUID = new ParcelUuid(UUID.randomUUID());
private static final int TEST_SIM_SLOT_INDEX = 1; private static final int TEST_SIM_SLOT_INDEX = 0;
private static final int TEST_SUBSCRIPTION_ID_1 = 2; private static final int TEST_SUBSCRIPTION_ID_1 = 2;
private static final SubscriptionInfo TEST_SUBINFO_1 = mock(SubscriptionInfo.class); private static final SubscriptionInfo TEST_SUBINFO_1 = mock(SubscriptionInfo.class);
private static final int TEST_SUBSCRIPTION_ID_2 = 3; private static final int TEST_SUBSCRIPTION_ID_2 = 3;
@@ -151,6 +156,8 @@ public class TelephonySubscriptionTrackerTest {
@Before @Before
public void setUp() throws Exception { public void setUp() throws Exception {
doReturn(2).when(mTelephonyManager).getActiveModemCount();
mCallback = mock(TelephonySubscriptionTrackerCallback.class); mCallback = mock(TelephonySubscriptionTrackerCallback.class);
mTelephonySubscriptionTracker = mTelephonySubscriptionTracker =
new TelephonySubscriptionTracker(mContext, mHandler, mCallback, mDeps); new TelephonySubscriptionTracker(mContext, mHandler, mCallback, mDeps);
@@ -180,6 +187,15 @@ public class TelephonySubscriptionTrackerTest {
return captor.getValue(); return captor.getValue();
} }
private List<CarrierPrivilegesListener> getCarrierPrivilegesListeners() {
final ArgumentCaptor<CarrierPrivilegesListener> captor =
ArgumentCaptor.forClass(CarrierPrivilegesListener.class);
verify(mTelephonyManager, atLeastOnce())
.addCarrierPrivilegesListener(anyInt(), any(), captor.capture());
return captor.getAllValues();
}
private ActiveDataSubscriptionIdListener getActiveDataSubscriptionIdListener() { private ActiveDataSubscriptionIdListener getActiveDataSubscriptionIdListener() {
final ArgumentCaptor<TelephonyCallback> captor = final ArgumentCaptor<TelephonyCallback> captor =
ArgumentCaptor.forClass(TelephonyCallback.class); ArgumentCaptor.forClass(TelephonyCallback.class);
@@ -188,6 +204,11 @@ public class TelephonySubscriptionTrackerTest {
return (ActiveDataSubscriptionIdListener) captor.getValue(); return (ActiveDataSubscriptionIdListener) captor.getValue();
} }
private Intent buildTestMultiSimConfigBroadcastIntent() {
Intent intent = new Intent(ACTION_MULTI_SIM_CONFIG_CHANGED);
return intent;
}
private Intent buildTestBroadcastIntent(boolean hasValidSubscription) { private Intent buildTestBroadcastIntent(boolean hasValidSubscription) {
Intent intent = new Intent(ACTION_CARRIER_CONFIG_CHANGED); Intent intent = new Intent(ACTION_CARRIER_CONFIG_CHANGED);
intent.putExtra(EXTRA_SLOT_INDEX, TEST_SIM_SLOT_INDEX); intent.putExtra(EXTRA_SLOT_INDEX, TEST_SIM_SLOT_INDEX);
@@ -239,12 +260,21 @@ public class TelephonySubscriptionTrackerTest {
any(), any(),
eq(mHandler)); eq(mHandler));
final IntentFilter filter = getIntentFilter(); final IntentFilter filter = getIntentFilter();
assertEquals(1, filter.countActions()); assertEquals(2, filter.countActions());
assertTrue(filter.hasAction(ACTION_CARRIER_CONFIG_CHANGED)); assertTrue(filter.hasAction(ACTION_CARRIER_CONFIG_CHANGED));
assertTrue(filter.hasAction(ACTION_MULTI_SIM_CONFIG_CHANGED));
verify(mSubscriptionManager) verify(mSubscriptionManager)
.addOnSubscriptionsChangedListener(any(HandlerExecutor.class), any()); .addOnSubscriptionsChangedListener(any(HandlerExecutor.class), any());
assertNotNull(getOnSubscriptionsChangedListener()); assertNotNull(getOnSubscriptionsChangedListener());
verify(mTelephonyManager, times(2))
.addCarrierPrivilegesListener(anyInt(), any(HandlerExecutor.class), any());
verify(mTelephonyManager)
.addCarrierPrivilegesListener(eq(0), any(HandlerExecutor.class), any());
verify(mTelephonyManager)
.addCarrierPrivilegesListener(eq(1), any(HandlerExecutor.class), any());
assertEquals(2, getCarrierPrivilegesListeners().size());
} }
@Test @Test
@@ -255,6 +285,49 @@ public class TelephonySubscriptionTrackerTest {
final OnSubscriptionsChangedListener listener = getOnSubscriptionsChangedListener(); final OnSubscriptionsChangedListener listener = getOnSubscriptionsChangedListener();
verify(mSubscriptionManager).removeOnSubscriptionsChangedListener(eq(listener)); verify(mSubscriptionManager).removeOnSubscriptionsChangedListener(eq(listener));
for (CarrierPrivilegesListener carrierPrivilegesListener :
getCarrierPrivilegesListeners()) {
verify(mTelephonyManager)
.removeCarrierPrivilegesListener(eq(carrierPrivilegesListener));
}
}
@Test
public void testMultiSimConfigChanged() throws Exception {
final ArrayMap<Integer, Integer> readySubIdsBySlotId = new ArrayMap<>();
readySubIdsBySlotId.put(TEST_SIM_SLOT_INDEX, TEST_SUBSCRIPTION_ID_1);
readySubIdsBySlotId.put(TEST_SIM_SLOT_INDEX + 1, TEST_SUBSCRIPTION_ID_1);
mTelephonySubscriptionTracker.setReadySubIdsBySlotId(readySubIdsBySlotId);
doReturn(1).when(mTelephonyManager).getActiveModemCount();
List<CarrierPrivilegesListener> carrierPrivilegesListeners =
getCarrierPrivilegesListeners();
mTelephonySubscriptionTracker.onReceive(mContext, buildTestMultiSimConfigBroadcastIntent());
mTestLooper.dispatchAll();
for (CarrierPrivilegesListener carrierPrivilegesListener : carrierPrivilegesListeners) {
verify(mTelephonyManager)
.removeCarrierPrivilegesListener(eq(carrierPrivilegesListener));
}
// Expect cache cleared for inactive slots.
assertNull(
mTelephonySubscriptionTracker
.getReadySubIdsBySlotId()
.get(TEST_SIM_SLOT_INDEX + 1));
// Expect a new CarrierPrivilegesListener to have been registered for slot 0, and none other
// (2 previously registered during startup, for slots 0 & 1)
verify(mTelephonyManager, times(3))
.addCarrierPrivilegesListener(anyInt(), any(HandlerExecutor.class), any());
verify(mTelephonyManager, times(2))
.addCarrierPrivilegesListener(eq(0), any(HandlerExecutor.class), any());
// Verify that this triggers a re-evaluation
verify(mCallback).onNewSnapshot(eq(buildExpectedSnapshot(TEST_PRIVILEGED_PACKAGES)));
} }
@Test @Test
@@ -313,6 +386,17 @@ public class TelephonySubscriptionTrackerTest {
verify(mCallback).onNewSnapshot(eq(buildExpectedSnapshot(TEST_PRIVILEGED_PACKAGES))); verify(mCallback).onNewSnapshot(eq(buildExpectedSnapshot(TEST_PRIVILEGED_PACKAGES)));
} }
@Test
public void testOnCarrierPrivilegesChanged() throws Exception {
setupReadySubIds();
final CarrierPrivilegesListener listener = getCarrierPrivilegesListeners().get(0);
listener.onCarrierPrivilegesChanged(Collections.emptyList(), new int[] {});
mTestLooper.dispatchAll();
verify(mCallback).onNewSnapshot(eq(buildExpectedSnapshot(TEST_PRIVILEGED_PACKAGES)));
}
@Test @Test
public void testReceiveBroadcast_ConfigReadyWithSubscriptions() throws Exception { public void testReceiveBroadcast_ConfigReadyWithSubscriptions() throws Exception {
mTelephonySubscriptionTracker.onReceive(mContext, buildTestBroadcastIntent(true)); mTelephonySubscriptionTracker.onReceive(mContext, buildTestBroadcastIntent(true));