Loading src/java/com/android/internal/telephony/ServiceStateTracker.java +0 −2 Original line number Diff line number Diff line Loading @@ -3455,12 +3455,10 @@ public class ServiceStateTracker extends Handler { if (hasRegistered) { mNetworkAttachedRegistrants.notifyRegistrants(); mNitzState.handleNetworkAvailable(); } if (hasDeregistered) { mNetworkDetachedRegistrants.notifyRegistrants(); mNitzState.handleNetworkUnavailable(); } if (hasCssIndicatorChanged) { Loading src/java/com/android/internal/telephony/SubscriptionController.java +48 −47 Original line number Diff line number Diff line Loading @@ -899,11 +899,17 @@ public class SubscriptionController extends ISub.Stub { } } private List<SubscriptionInfo> makeCacheListCopyWithLock(List<SubscriptionInfo> cacheSubList) { synchronized (mSubInfoListLock) { return new ArrayList<>(cacheSubList); } } @Deprecated @UnsupportedAppUsage public List<SubscriptionInfo> getActiveSubscriptionInfoList(String callingPackage) { return getSubscriptionInfoListFromCacheHelper(callingPackage, null, mCacheActiveSubInfoList); makeCacheListCopyWithLock(mCacheActiveSubInfoList)); } /** Loading @@ -917,7 +923,7 @@ public class SubscriptionController extends ISub.Stub { public List<SubscriptionInfo> getActiveSubscriptionInfoList(String callingPackage, String callingFeatureId) { return getSubscriptionInfoListFromCacheHelper(callingPackage, callingFeatureId, mCacheActiveSubInfoList); makeCacheListCopyWithLock(mCacheActiveSubInfoList)); } /** Loading @@ -928,13 +934,13 @@ public class SubscriptionController extends ISub.Stub { public void refreshCachedActiveSubscriptionInfoList() { boolean opptSubListChanged; synchronized (mSubInfoListLock) { List<SubscriptionInfo> activeSubscriptionInfoList = getSubInfo( SubscriptionManager.SIM_SLOT_INDEX + ">=0 OR " + SubscriptionManager.SUBSCRIPTION_TYPE + "=" + SubscriptionManager.SUBSCRIPTION_TYPE_REMOTE_SIM, null); synchronized (mSubInfoListLock) { if (activeSubscriptionInfoList != null) { // Log when active sub info changes. if (mCacheActiveSubInfoList.size() != activeSubscriptionInfoList.size() Loading @@ -949,10 +955,6 @@ public class SubscriptionController extends ISub.Stub { logd("activeSubscriptionInfoList is null."); mCacheActiveSubInfoList.clear(); } // Refresh cached opportunistic sub list and detect whether it's changed. refreshCachedOpportunisticSubscriptionInfoList(); if (DBG_CACHE) { if (!mCacheActiveSubInfoList.isEmpty()) { for (SubscriptionInfo si : mCacheActiveSubInfoList) { Loading @@ -964,6 +966,9 @@ public class SubscriptionController extends ISub.Stub { } } } // Refresh cached opportunistic sub list and detect whether it's changed. refreshCachedOpportunisticSubscriptionInfoList(); } @Deprecated Loading Loading @@ -3252,8 +3257,8 @@ public class SubscriptionController extends ISub.Stub { @Override public List<SubscriptionInfo> getOpportunisticSubscriptions(String callingPackage, String callingFeatureId) { return getSubscriptionInfoListFromCacheHelper( callingPackage, callingFeatureId, mCacheOpportunisticSubInfoList); return getSubscriptionInfoListFromCacheHelper(callingPackage, callingFeatureId, makeCacheListCopyWithLock(mCacheOpportunisticSubInfoList)); } /** Loading Loading @@ -3946,10 +3951,8 @@ public class SubscriptionController extends ISub.Stub { // the identifier and phone number access checks are not required. } synchronized (mSubInfoListLock) { // If the caller can read all phone state, just return the full list. if (canReadIdentifiers && canReadPhoneNumber) { return new ArrayList<>(cacheSubList); return cacheSubList; } // Filter the list to only include subscriptions which the caller can manage. List<SubscriptionInfo> subscriptions = new ArrayList<>(cacheSubList.size()); Loading Loading @@ -3977,7 +3980,6 @@ public class SubscriptionController extends ISub.Stub { } return subscriptions; } } /** * Conditionally removes identifiers from the provided {@code subInfo} if the {@code Loading Loading @@ -4091,13 +4093,12 @@ public class SubscriptionController extends ISub.Stub { } private void refreshCachedOpportunisticSubscriptionInfoList() { synchronized (mSubInfoListLock) { List<SubscriptionInfo> oldOpptCachedList = mCacheOpportunisticSubInfoList; List<SubscriptionInfo> subList = getSubInfo( SubscriptionManager.IS_OPPORTUNISTIC + "=1 AND (" + SubscriptionManager.SIM_SLOT_INDEX + ">=0 OR " + SubscriptionManager.IS_EMBEDDED + "=1)", null); synchronized (mSubInfoListLock) { List<SubscriptionInfo> oldOpptCachedList = mCacheOpportunisticSubInfoList; if (subList != null) { subList.sort(SUBSCRIPTION_INFO_COMPARATOR); Loading src/java/com/android/internal/telephony/dataconnection/DcTracker.java +16 −20 Original line number Diff line number Diff line Loading @@ -2427,7 +2427,9 @@ public class DcTracker extends Handler { log("apnSetting: " + apnSetting); if (dunSettings != null && dunSettings.size() > 0) { for (ApnSetting dunSetting : dunSettings) { if (dunSetting.equals(apnSetting)) { //This ignore network type as a check which is ok because that's checked //when calculating dun candidates. if (areCompatible(dunSetting, apnSetting)) { if (curDc.isActive()) { if (DBG) { log("checkForCompatibleDataConnection:" Loading Loading @@ -4394,22 +4396,6 @@ public class DcTracker extends Handler { } } private boolean containsAllApns(List<ApnSetting> oldApnList, List<ApnSetting> newApnList) { for (ApnSetting newApnSetting : newApnList) { boolean canHandle = false; for (ApnSetting oldApnSetting : oldApnList) { // Make sure at least one of the APN from old list can cover the new APN if (oldApnSetting.equals(newApnSetting, mPhone.getServiceState().getDataRoamingFromRegistration())) { canHandle = true; break; } } if (!canHandle) return false; } return true; } private void cleanUpConnectionsOnUpdatedApns(boolean detach, String reason) { if (DBG) log("cleanUpConnectionsOnUpdatedApns: detach=" + detach); if (mAllApnSettings.isEmpty()) { Loading @@ -4428,8 +4414,7 @@ public class DcTracker extends Handler { apnContext.getApnType(), getDataRat()); apnContext.setWaitingApns(waitingApns); for (ApnSetting apnSetting : waitingApns) { if (apnSetting.equals(apnContext.getApnSetting(), mPhone.getServiceState().getDataRoamingFromRegistration())) { if (areCompatible(apnSetting, apnContext.getApnSetting())) { cleanupRequired = false; break; } Loading Loading @@ -4733,7 +4718,8 @@ public class DcTracker extends Handler { } // Skip recovery if it can cause a call to drop if (mInVoiceCall && getRecoveryAction() > RECOVERY_ACTION_CLEANUP) { if (mPhone.getState() != PhoneConstants.State.IDLE && getRecoveryAction() > RECOVERY_ACTION_CLEANUP) { if (VDBG_STALL) log("skip data stall recovery as there is an active call"); return false; } Loading Loading @@ -5189,6 +5175,16 @@ public class DcTracker extends Handler { mDcc.unregisterForPhysicalLinkStateChanged(h); } // We use a specialized equals function in Apn setting when checking if an active // data connection is still legitimate to use against a different apn setting. // This method is extracted to a function to ensure that any future changes to this check will // be applied to both cleanUpConnectionsOnUpdatedApns and checkForCompatibleDataConnection. // Fix for b/158908392. private boolean areCompatible(ApnSetting apnSetting1, ApnSetting apnSetting2) { return apnSetting1.equals(apnSetting2, mPhone.getServiceState().getDataRoamingFromRegistration()); } @NonNull private PersistableBundle getCarrierConfig() { CarrierConfigManager configManager = (CarrierConfigManager) mPhone.getContext() Loading tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcTrackerTest.java +97 −15 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ import static com.android.internal.telephony.dataconnection.ApnSettingTest.creat import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.mockito.Matchers.any; Loading Loading @@ -109,9 +110,11 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Optional; import java.util.concurrent.atomic.AtomicInteger; import java.util.stream.Collectors; public class DcTrackerTest extends TelephonyTest { public static final String FAKE_APN1 = "FAKE APN 1"; Loading Loading @@ -197,6 +200,18 @@ public class DcTrackerTest extends TelephonyTest { private class ApnSettingContentProvider extends MockContentProvider { private int mPreferredApnSet = 0; private String mFakeApn1Types = "default,supl"; private int mRowIdOffset = 0; public void setFakeApn1Types(String apnTypes) { mFakeApn1Types = apnTypes; } public void setRowIdOffset(int rowIdOffset) { mRowIdOffset = rowIdOffset; } @Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { Loading Loading @@ -241,7 +256,7 @@ public class DcTrackerTest extends TelephonyTest { Telephony.Carriers.SKIP_464XLAT}); mc.addRow(new Object[]{ 2163, // id 2163 + mRowIdOffset, // id FAKE_PLMN, // numeric "sp-mode", // name FAKE_APN1, // apn Loading @@ -253,7 +268,7 @@ public class DcTrackerTest extends TelephonyTest { "", // user "", // password -1, // authtype "default,supl", // types mFakeApn1Types, // types "IP", // protocol "IP", // roaming_protocol 1, // carrier_enabled Loading @@ -274,7 +289,7 @@ public class DcTrackerTest extends TelephonyTest { }); mc.addRow(new Object[]{ 2164, // id 2164 + mRowIdOffset, // id FAKE_PLMN, // numeric "mopera U", // name FAKE_APN2, // apn Loading Loading @@ -307,7 +322,7 @@ public class DcTrackerTest extends TelephonyTest { }); mc.addRow(new Object[]{ 2165, // id 2165 + mRowIdOffset, // id FAKE_PLMN, // numeric "b-mobile for Nexus", // name FAKE_APN3, // apn Loading Loading @@ -340,7 +355,7 @@ public class DcTrackerTest extends TelephonyTest { }); mc.addRow(new Object[]{ 2166, // id 2166 + mRowIdOffset, // id FAKE_PLMN, // numeric "sp-mode ehrpd", // name FAKE_APN4, // apn Loading Loading @@ -373,7 +388,7 @@ public class DcTrackerTest extends TelephonyTest { }); mc.addRow(new Object[]{ 2167, // id 2167 + mRowIdOffset, // id FAKE_PLMN, // numeric "b-mobile for Nexus", // name FAKE_APN5, // apn Loading Loading @@ -406,7 +421,7 @@ public class DcTrackerTest extends TelephonyTest { }); mc.addRow(new Object[]{ 2168, // id 2168 + mRowIdOffset, // id FAKE_PLMN, // numeric "sp-mode", // name FAKE_APN6, // apn Loading Loading @@ -628,20 +643,32 @@ public class DcTrackerTest extends TelephonyTest { } private void sendInitializationEvents() { logd("Sending EVENT_CARRIER_CONFIG_CHANGED"); sendCarrierConfigChanged(""); sendSimStateUpdated(""); sendEventDataConnectionAttached(""); waitForMs(200); } private void sendCarrierConfigChanged(String messagePrefix) { logd(messagePrefix + "Sending EVENT_CARRIER_CONFIG_CHANGED"); mDct.sendEmptyMessage(DctConstants.EVENT_CARRIER_CONFIG_CHANGED); waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); } logd("Sending EVENT_SIM_STATE_UPDATED"); private void sendSimStateUpdated(String messagePrefix) { logd(messagePrefix + "Sending EVENT_SIM_STATE_UPDATED"); mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_SIM_STATE_UPDATED, TelephonyManager.SIM_STATE_LOADED, 0)); waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); } logd("Sending EVENT_DATA_CONNECTION_ATTACHED"); private void sendEventDataConnectionAttached(String messagePrefix) { logd(messagePrefix + "Sending EVENT_DATA_CONNECTION_ATTACHED"); mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_DATA_CONNECTION_ATTACHED, null)); waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); waitForMs(200); } // Test the unmetered APN setup when data is disabled. Loading Loading @@ -1344,9 +1371,7 @@ public class DcTrackerTest extends TelephonyTest { @Test @SmallTest public void testFetchDunApnWithPreferredApnSet() { logd("Sending EVENT_CARRIER_CONFIG_CHANGED"); mDct.sendEmptyMessage(DctConstants.EVENT_CARRIER_CONFIG_CHANGED); waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); sendCarrierConfigChanged("testFetchDunApnWithPreferredApnSet: "); // apnSetId=1 String dunApnString1 = "[ApnSettingV5]HOT mobile PC,pc.hotm,,,,,,,,,440,10,,DUN,,,true," Loading Loading @@ -1413,6 +1438,61 @@ public class DcTrackerTest extends TelephonyTest { Settings.Global.TETHER_DUN_APN, null); } // This tests simulates the race case where the sim status change event is triggered, the // default data connection is attached, and then the carrier config gets changed which bumps // the database id which we want to ignore when cleaning up connections and matching against // the dun APN. Tests b/158908392. @Test @SmallTest public void testCheckForCompatibleDataConnectionWithDunWhenIdsChange() throws Exception { //Set dun as a support apn type of FAKE_APN1 mApnSettingContentProvider.setFakeApn1Types("default,supl,dun"); // Enable the default apn mSimulatedCommands.setDataCallResult(true, createSetupDataCallResult()); mDct.enableApn(ApnSetting.TYPE_DEFAULT, DcTracker.REQUEST_TYPE_NORMAL, null); waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); //Load the sim and attach the data connection without firing the carrier changed event final String logMsgPrefix = "testCheckForCompatibleDataConnectionWithDunWhenIdsChange: "; sendSimStateUpdated(logMsgPrefix); sendEventDataConnectionAttached(logMsgPrefix); waitForMs(200); // Confirm that FAKE_APN1 comes up as a dun candidate ApnSetting dunApn = mDct.fetchDunApns().get(0); assertEquals(dunApn.getApnName(), FAKE_APN1); Map<Integer, ApnContext> apnContexts = mDct.getApnContexts() .stream().collect(Collectors.toMap(ApnContext::getApnTypeBitmask, x -> x)); //Double check that the default apn content is connected while the dun apn context is not assertEquals(apnContexts.get(ApnSetting.TYPE_DEFAULT).getState(), DctConstants.State.CONNECTED); assertNotEquals(apnContexts.get(ApnSetting.TYPE_DUN).getState(), DctConstants.State.CONNECTED); //Change the row ids the same way as what happens when we have old apn values in the //carrier table mApnSettingContentProvider.setRowIdOffset(100); sendCarrierConfigChanged(logMsgPrefix); waitForMs(200); mDct.enableApn(ApnSetting.TYPE_DUN, DcTracker.REQUEST_TYPE_NORMAL, null); waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); Map<Integer, ApnContext> apnContextsAfterRowIdsChanged = mDct.getApnContexts() .stream().collect(Collectors.toMap(ApnContext::getApnTypeBitmask, x -> x)); //Make sure that the data connection used earlier wasn't cleaned up and still in use. assertEquals(apnContexts.get(ApnSetting.TYPE_DEFAULT).getDataConnection(), apnContextsAfterRowIdsChanged.get(ApnSetting.TYPE_DEFAULT).getDataConnection()); //Check that the DUN is using the same active data connection assertEquals(apnContexts.get(ApnSetting.TYPE_DEFAULT).getDataConnection(), apnContextsAfterRowIdsChanged.get(ApnSetting.TYPE_DUN).getDataConnection()); } // Test oos @Test @SmallTest Loading Loading @@ -1668,6 +1748,7 @@ public class DcTrackerTest extends TelephonyTest { Settings.Global.MIN_DURATION_BETWEEN_RECOVERY_STEPS_IN_MS, 100); Settings.System.putInt(resolver, "radio.data.stall.recovery.action", 2); doReturn(new SignalStrength()).when(mPhone).getSignalStrength(); doReturn(PhoneConstants.State.IDLE).when(mPhone).getState(); mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS, new String[]{PhoneConstants.APN_TYPE_DEFAULT, PhoneConstants.APN_TYPE_MMS}); Loading Loading @@ -1700,6 +1781,7 @@ public class DcTrackerTest extends TelephonyTest { Settings.Global.MIN_DURATION_BETWEEN_RECOVERY_STEPS_IN_MS, 100); Settings.System.putInt(resolver, "radio.data.stall.recovery.action", 3); doReturn(new SignalStrength()).when(mPhone).getSignalStrength(); doReturn(PhoneConstants.State.IDLE).when(mPhone).getState(); mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS, new String[]{PhoneConstants.APN_TYPE_DEFAULT, PhoneConstants.APN_TYPE_MMS}); Loading Loading
src/java/com/android/internal/telephony/ServiceStateTracker.java +0 −2 Original line number Diff line number Diff line Loading @@ -3455,12 +3455,10 @@ public class ServiceStateTracker extends Handler { if (hasRegistered) { mNetworkAttachedRegistrants.notifyRegistrants(); mNitzState.handleNetworkAvailable(); } if (hasDeregistered) { mNetworkDetachedRegistrants.notifyRegistrants(); mNitzState.handleNetworkUnavailable(); } if (hasCssIndicatorChanged) { Loading
src/java/com/android/internal/telephony/SubscriptionController.java +48 −47 Original line number Diff line number Diff line Loading @@ -899,11 +899,17 @@ public class SubscriptionController extends ISub.Stub { } } private List<SubscriptionInfo> makeCacheListCopyWithLock(List<SubscriptionInfo> cacheSubList) { synchronized (mSubInfoListLock) { return new ArrayList<>(cacheSubList); } } @Deprecated @UnsupportedAppUsage public List<SubscriptionInfo> getActiveSubscriptionInfoList(String callingPackage) { return getSubscriptionInfoListFromCacheHelper(callingPackage, null, mCacheActiveSubInfoList); makeCacheListCopyWithLock(mCacheActiveSubInfoList)); } /** Loading @@ -917,7 +923,7 @@ public class SubscriptionController extends ISub.Stub { public List<SubscriptionInfo> getActiveSubscriptionInfoList(String callingPackage, String callingFeatureId) { return getSubscriptionInfoListFromCacheHelper(callingPackage, callingFeatureId, mCacheActiveSubInfoList); makeCacheListCopyWithLock(mCacheActiveSubInfoList)); } /** Loading @@ -928,13 +934,13 @@ public class SubscriptionController extends ISub.Stub { public void refreshCachedActiveSubscriptionInfoList() { boolean opptSubListChanged; synchronized (mSubInfoListLock) { List<SubscriptionInfo> activeSubscriptionInfoList = getSubInfo( SubscriptionManager.SIM_SLOT_INDEX + ">=0 OR " + SubscriptionManager.SUBSCRIPTION_TYPE + "=" + SubscriptionManager.SUBSCRIPTION_TYPE_REMOTE_SIM, null); synchronized (mSubInfoListLock) { if (activeSubscriptionInfoList != null) { // Log when active sub info changes. if (mCacheActiveSubInfoList.size() != activeSubscriptionInfoList.size() Loading @@ -949,10 +955,6 @@ public class SubscriptionController extends ISub.Stub { logd("activeSubscriptionInfoList is null."); mCacheActiveSubInfoList.clear(); } // Refresh cached opportunistic sub list and detect whether it's changed. refreshCachedOpportunisticSubscriptionInfoList(); if (DBG_CACHE) { if (!mCacheActiveSubInfoList.isEmpty()) { for (SubscriptionInfo si : mCacheActiveSubInfoList) { Loading @@ -964,6 +966,9 @@ public class SubscriptionController extends ISub.Stub { } } } // Refresh cached opportunistic sub list and detect whether it's changed. refreshCachedOpportunisticSubscriptionInfoList(); } @Deprecated Loading Loading @@ -3252,8 +3257,8 @@ public class SubscriptionController extends ISub.Stub { @Override public List<SubscriptionInfo> getOpportunisticSubscriptions(String callingPackage, String callingFeatureId) { return getSubscriptionInfoListFromCacheHelper( callingPackage, callingFeatureId, mCacheOpportunisticSubInfoList); return getSubscriptionInfoListFromCacheHelper(callingPackage, callingFeatureId, makeCacheListCopyWithLock(mCacheOpportunisticSubInfoList)); } /** Loading Loading @@ -3946,10 +3951,8 @@ public class SubscriptionController extends ISub.Stub { // the identifier and phone number access checks are not required. } synchronized (mSubInfoListLock) { // If the caller can read all phone state, just return the full list. if (canReadIdentifiers && canReadPhoneNumber) { return new ArrayList<>(cacheSubList); return cacheSubList; } // Filter the list to only include subscriptions which the caller can manage. List<SubscriptionInfo> subscriptions = new ArrayList<>(cacheSubList.size()); Loading Loading @@ -3977,7 +3980,6 @@ public class SubscriptionController extends ISub.Stub { } return subscriptions; } } /** * Conditionally removes identifiers from the provided {@code subInfo} if the {@code Loading Loading @@ -4091,13 +4093,12 @@ public class SubscriptionController extends ISub.Stub { } private void refreshCachedOpportunisticSubscriptionInfoList() { synchronized (mSubInfoListLock) { List<SubscriptionInfo> oldOpptCachedList = mCacheOpportunisticSubInfoList; List<SubscriptionInfo> subList = getSubInfo( SubscriptionManager.IS_OPPORTUNISTIC + "=1 AND (" + SubscriptionManager.SIM_SLOT_INDEX + ">=0 OR " + SubscriptionManager.IS_EMBEDDED + "=1)", null); synchronized (mSubInfoListLock) { List<SubscriptionInfo> oldOpptCachedList = mCacheOpportunisticSubInfoList; if (subList != null) { subList.sort(SUBSCRIPTION_INFO_COMPARATOR); Loading
src/java/com/android/internal/telephony/dataconnection/DcTracker.java +16 −20 Original line number Diff line number Diff line Loading @@ -2427,7 +2427,9 @@ public class DcTracker extends Handler { log("apnSetting: " + apnSetting); if (dunSettings != null && dunSettings.size() > 0) { for (ApnSetting dunSetting : dunSettings) { if (dunSetting.equals(apnSetting)) { //This ignore network type as a check which is ok because that's checked //when calculating dun candidates. if (areCompatible(dunSetting, apnSetting)) { if (curDc.isActive()) { if (DBG) { log("checkForCompatibleDataConnection:" Loading Loading @@ -4394,22 +4396,6 @@ public class DcTracker extends Handler { } } private boolean containsAllApns(List<ApnSetting> oldApnList, List<ApnSetting> newApnList) { for (ApnSetting newApnSetting : newApnList) { boolean canHandle = false; for (ApnSetting oldApnSetting : oldApnList) { // Make sure at least one of the APN from old list can cover the new APN if (oldApnSetting.equals(newApnSetting, mPhone.getServiceState().getDataRoamingFromRegistration())) { canHandle = true; break; } } if (!canHandle) return false; } return true; } private void cleanUpConnectionsOnUpdatedApns(boolean detach, String reason) { if (DBG) log("cleanUpConnectionsOnUpdatedApns: detach=" + detach); if (mAllApnSettings.isEmpty()) { Loading @@ -4428,8 +4414,7 @@ public class DcTracker extends Handler { apnContext.getApnType(), getDataRat()); apnContext.setWaitingApns(waitingApns); for (ApnSetting apnSetting : waitingApns) { if (apnSetting.equals(apnContext.getApnSetting(), mPhone.getServiceState().getDataRoamingFromRegistration())) { if (areCompatible(apnSetting, apnContext.getApnSetting())) { cleanupRequired = false; break; } Loading Loading @@ -4733,7 +4718,8 @@ public class DcTracker extends Handler { } // Skip recovery if it can cause a call to drop if (mInVoiceCall && getRecoveryAction() > RECOVERY_ACTION_CLEANUP) { if (mPhone.getState() != PhoneConstants.State.IDLE && getRecoveryAction() > RECOVERY_ACTION_CLEANUP) { if (VDBG_STALL) log("skip data stall recovery as there is an active call"); return false; } Loading Loading @@ -5189,6 +5175,16 @@ public class DcTracker extends Handler { mDcc.unregisterForPhysicalLinkStateChanged(h); } // We use a specialized equals function in Apn setting when checking if an active // data connection is still legitimate to use against a different apn setting. // This method is extracted to a function to ensure that any future changes to this check will // be applied to both cleanUpConnectionsOnUpdatedApns and checkForCompatibleDataConnection. // Fix for b/158908392. private boolean areCompatible(ApnSetting apnSetting1, ApnSetting apnSetting2) { return apnSetting1.equals(apnSetting2, mPhone.getServiceState().getDataRoamingFromRegistration()); } @NonNull private PersistableBundle getCarrierConfig() { CarrierConfigManager configManager = (CarrierConfigManager) mPhone.getContext() Loading
tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcTrackerTest.java +97 −15 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ import static com.android.internal.telephony.dataconnection.ApnSettingTest.creat import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.mockito.Matchers.any; Loading Loading @@ -109,9 +110,11 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Optional; import java.util.concurrent.atomic.AtomicInteger; import java.util.stream.Collectors; public class DcTrackerTest extends TelephonyTest { public static final String FAKE_APN1 = "FAKE APN 1"; Loading Loading @@ -197,6 +200,18 @@ public class DcTrackerTest extends TelephonyTest { private class ApnSettingContentProvider extends MockContentProvider { private int mPreferredApnSet = 0; private String mFakeApn1Types = "default,supl"; private int mRowIdOffset = 0; public void setFakeApn1Types(String apnTypes) { mFakeApn1Types = apnTypes; } public void setRowIdOffset(int rowIdOffset) { mRowIdOffset = rowIdOffset; } @Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { Loading Loading @@ -241,7 +256,7 @@ public class DcTrackerTest extends TelephonyTest { Telephony.Carriers.SKIP_464XLAT}); mc.addRow(new Object[]{ 2163, // id 2163 + mRowIdOffset, // id FAKE_PLMN, // numeric "sp-mode", // name FAKE_APN1, // apn Loading @@ -253,7 +268,7 @@ public class DcTrackerTest extends TelephonyTest { "", // user "", // password -1, // authtype "default,supl", // types mFakeApn1Types, // types "IP", // protocol "IP", // roaming_protocol 1, // carrier_enabled Loading @@ -274,7 +289,7 @@ public class DcTrackerTest extends TelephonyTest { }); mc.addRow(new Object[]{ 2164, // id 2164 + mRowIdOffset, // id FAKE_PLMN, // numeric "mopera U", // name FAKE_APN2, // apn Loading Loading @@ -307,7 +322,7 @@ public class DcTrackerTest extends TelephonyTest { }); mc.addRow(new Object[]{ 2165, // id 2165 + mRowIdOffset, // id FAKE_PLMN, // numeric "b-mobile for Nexus", // name FAKE_APN3, // apn Loading Loading @@ -340,7 +355,7 @@ public class DcTrackerTest extends TelephonyTest { }); mc.addRow(new Object[]{ 2166, // id 2166 + mRowIdOffset, // id FAKE_PLMN, // numeric "sp-mode ehrpd", // name FAKE_APN4, // apn Loading Loading @@ -373,7 +388,7 @@ public class DcTrackerTest extends TelephonyTest { }); mc.addRow(new Object[]{ 2167, // id 2167 + mRowIdOffset, // id FAKE_PLMN, // numeric "b-mobile for Nexus", // name FAKE_APN5, // apn Loading Loading @@ -406,7 +421,7 @@ public class DcTrackerTest extends TelephonyTest { }); mc.addRow(new Object[]{ 2168, // id 2168 + mRowIdOffset, // id FAKE_PLMN, // numeric "sp-mode", // name FAKE_APN6, // apn Loading Loading @@ -628,20 +643,32 @@ public class DcTrackerTest extends TelephonyTest { } private void sendInitializationEvents() { logd("Sending EVENT_CARRIER_CONFIG_CHANGED"); sendCarrierConfigChanged(""); sendSimStateUpdated(""); sendEventDataConnectionAttached(""); waitForMs(200); } private void sendCarrierConfigChanged(String messagePrefix) { logd(messagePrefix + "Sending EVENT_CARRIER_CONFIG_CHANGED"); mDct.sendEmptyMessage(DctConstants.EVENT_CARRIER_CONFIG_CHANGED); waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); } logd("Sending EVENT_SIM_STATE_UPDATED"); private void sendSimStateUpdated(String messagePrefix) { logd(messagePrefix + "Sending EVENT_SIM_STATE_UPDATED"); mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_SIM_STATE_UPDATED, TelephonyManager.SIM_STATE_LOADED, 0)); waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); } logd("Sending EVENT_DATA_CONNECTION_ATTACHED"); private void sendEventDataConnectionAttached(String messagePrefix) { logd(messagePrefix + "Sending EVENT_DATA_CONNECTION_ATTACHED"); mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_DATA_CONNECTION_ATTACHED, null)); waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); waitForMs(200); } // Test the unmetered APN setup when data is disabled. Loading Loading @@ -1344,9 +1371,7 @@ public class DcTrackerTest extends TelephonyTest { @Test @SmallTest public void testFetchDunApnWithPreferredApnSet() { logd("Sending EVENT_CARRIER_CONFIG_CHANGED"); mDct.sendEmptyMessage(DctConstants.EVENT_CARRIER_CONFIG_CHANGED); waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); sendCarrierConfigChanged("testFetchDunApnWithPreferredApnSet: "); // apnSetId=1 String dunApnString1 = "[ApnSettingV5]HOT mobile PC,pc.hotm,,,,,,,,,440,10,,DUN,,,true," Loading Loading @@ -1413,6 +1438,61 @@ public class DcTrackerTest extends TelephonyTest { Settings.Global.TETHER_DUN_APN, null); } // This tests simulates the race case where the sim status change event is triggered, the // default data connection is attached, and then the carrier config gets changed which bumps // the database id which we want to ignore when cleaning up connections and matching against // the dun APN. Tests b/158908392. @Test @SmallTest public void testCheckForCompatibleDataConnectionWithDunWhenIdsChange() throws Exception { //Set dun as a support apn type of FAKE_APN1 mApnSettingContentProvider.setFakeApn1Types("default,supl,dun"); // Enable the default apn mSimulatedCommands.setDataCallResult(true, createSetupDataCallResult()); mDct.enableApn(ApnSetting.TYPE_DEFAULT, DcTracker.REQUEST_TYPE_NORMAL, null); waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); //Load the sim and attach the data connection without firing the carrier changed event final String logMsgPrefix = "testCheckForCompatibleDataConnectionWithDunWhenIdsChange: "; sendSimStateUpdated(logMsgPrefix); sendEventDataConnectionAttached(logMsgPrefix); waitForMs(200); // Confirm that FAKE_APN1 comes up as a dun candidate ApnSetting dunApn = mDct.fetchDunApns().get(0); assertEquals(dunApn.getApnName(), FAKE_APN1); Map<Integer, ApnContext> apnContexts = mDct.getApnContexts() .stream().collect(Collectors.toMap(ApnContext::getApnTypeBitmask, x -> x)); //Double check that the default apn content is connected while the dun apn context is not assertEquals(apnContexts.get(ApnSetting.TYPE_DEFAULT).getState(), DctConstants.State.CONNECTED); assertNotEquals(apnContexts.get(ApnSetting.TYPE_DUN).getState(), DctConstants.State.CONNECTED); //Change the row ids the same way as what happens when we have old apn values in the //carrier table mApnSettingContentProvider.setRowIdOffset(100); sendCarrierConfigChanged(logMsgPrefix); waitForMs(200); mDct.enableApn(ApnSetting.TYPE_DUN, DcTracker.REQUEST_TYPE_NORMAL, null); waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); Map<Integer, ApnContext> apnContextsAfterRowIdsChanged = mDct.getApnContexts() .stream().collect(Collectors.toMap(ApnContext::getApnTypeBitmask, x -> x)); //Make sure that the data connection used earlier wasn't cleaned up and still in use. assertEquals(apnContexts.get(ApnSetting.TYPE_DEFAULT).getDataConnection(), apnContextsAfterRowIdsChanged.get(ApnSetting.TYPE_DEFAULT).getDataConnection()); //Check that the DUN is using the same active data connection assertEquals(apnContexts.get(ApnSetting.TYPE_DEFAULT).getDataConnection(), apnContextsAfterRowIdsChanged.get(ApnSetting.TYPE_DUN).getDataConnection()); } // Test oos @Test @SmallTest Loading Loading @@ -1668,6 +1748,7 @@ public class DcTrackerTest extends TelephonyTest { Settings.Global.MIN_DURATION_BETWEEN_RECOVERY_STEPS_IN_MS, 100); Settings.System.putInt(resolver, "radio.data.stall.recovery.action", 2); doReturn(new SignalStrength()).when(mPhone).getSignalStrength(); doReturn(PhoneConstants.State.IDLE).when(mPhone).getState(); mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS, new String[]{PhoneConstants.APN_TYPE_DEFAULT, PhoneConstants.APN_TYPE_MMS}); Loading Loading @@ -1700,6 +1781,7 @@ public class DcTrackerTest extends TelephonyTest { Settings.Global.MIN_DURATION_BETWEEN_RECOVERY_STEPS_IN_MS, 100); Settings.System.putInt(resolver, "radio.data.stall.recovery.action", 3); doReturn(new SignalStrength()).when(mPhone).getSignalStrength(); doReturn(PhoneConstants.State.IDLE).when(mPhone).getState(); mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS, new String[]{PhoneConstants.APN_TYPE_DEFAULT, PhoneConstants.APN_TYPE_MMS}); Loading