Loading src/java/com/android/internal/telephony/dataconnection/ApnSetting.java +113 −0 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ import android.telephony.Rlog; import android.telephony.ServiceState; import android.text.TextUtils; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.Phone; import com.android.internal.telephony.PhoneConstants; import com.android.internal.telephony.RILConstants; Loading @@ -33,6 +34,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Objects; /** * This class represents a apn setting for create PDP link Loading @@ -42,6 +44,7 @@ public class ApnSetting { static final String LOG_TAG = "ApnSetting"; private static final boolean DBG = false; private static final boolean VDBG = false; static final String V2_FORMAT_REGEX = "^\\[ApnSettingV2\\]\\s*"; static final String V3_FORMAT_REGEX = "^\\[ApnSettingV3\\]\\s*"; Loading Loading @@ -544,6 +547,116 @@ public class ApnSetting { && mvnoMatchData.equals(other.mvnoMatchData); } /** * Compare two APN settings * * Note: This method does not compare 'id', 'bearer', 'bearerBitmask'. We only use this for * determining if tearing a data call is needed when conditions change. See * cleanUpConnectionsOnUpdatedApns in DcTracker. * * @param o the other object to compare * @param isDataRoaming True if the device is on data roaming * @return True if the two APN settings are same */ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) public boolean equals(Object o, boolean isDataRoaming) { if (!(o instanceof ApnSetting)) { return false; } ApnSetting other = (ApnSetting) o; return carrier.equals(other.carrier) && numeric.equals(other.numeric) && apn.equals(other.apn) && proxy.equals(other.proxy) && mmsc.equals(other.mmsc) && mmsProxy.equals(other.mmsProxy) && TextUtils.equals(mmsPort, other.mmsPort) && port.equals(other.port) && TextUtils.equals(user, other.user) && TextUtils.equals(password, other.password) && authType == other.authType && Arrays.deepEquals(types, other.types) && typesBitmap == other.typesBitmap && (isDataRoaming || protocol.equals(other.protocol)) && (!isDataRoaming || roamingProtocol.equals(other.roamingProtocol)) && carrierEnabled == other.carrierEnabled && profileId == other.profileId && modemCognitive == other.modemCognitive && maxConns == other.maxConns && waitTime == other.waitTime && maxConnsTime == other.maxConnsTime && mtu == other.mtu && mvnoType.equals(other.mvnoType) && mvnoMatchData.equals(other.mvnoMatchData); } /** * Check if neither mention DUN and are substantially similar * * @param other The other APN settings to compare * @return True if two APN settings are similar */ public boolean similar(ApnSetting other) { return (!this.canHandleType(PhoneConstants.APN_TYPE_DUN) && !other.canHandleType(PhoneConstants.APN_TYPE_DUN) && Objects.equals(this.apn, other.apn) && !typeSameAny(this, other) && xorEquals(this.proxy, other.proxy) && xorEquals(this.port, other.port) && xorEquals(this.protocol, other.protocol) && xorEquals(this.roamingProtocol, other.roamingProtocol) && this.carrierEnabled == other.carrierEnabled && this.bearerBitmask == other.bearerBitmask && this.profileId == other.profileId && Objects.equals(this.mvnoType, other.mvnoType) && Objects.equals(this.mvnoMatchData, other.mvnoMatchData) && xorEquals(this.mmsc, other.mmsc) && xorEquals(this.mmsProxy, other.mmsProxy) && xorEquals(this.mmsPort, other.mmsPort)); } // check whether the types of two APN same (even only one type of each APN is same) private boolean typeSameAny(ApnSetting first, ApnSetting second) { if (VDBG) { StringBuilder apnType1 = new StringBuilder(first.apn + ": "); for (int index1 = 0; index1 < first.types.length; index1++) { apnType1.append(first.types[index1]); apnType1.append(","); } StringBuilder apnType2 = new StringBuilder(second.apn + ": "); for (int index1 = 0; index1 < second.types.length; index1++) { apnType2.append(second.types[index1]); apnType2.append(","); } Rlog.d(LOG_TAG, "APN1: is " + apnType1); Rlog.d(LOG_TAG, "APN2: is " + apnType2); } for (int index1 = 0; index1 < first.types.length; index1++) { for (int index2 = 0; index2 < second.types.length; index2++) { if (first.types[index1].equals(PhoneConstants.APN_TYPE_ALL) || second.types[index2].equals(PhoneConstants.APN_TYPE_ALL) || first.types[index1].equals(second.types[index2])) { if (VDBG) Rlog.d(LOG_TAG, "typeSameAny: return true"); return true; } } } if (VDBG) Rlog.d(LOG_TAG, "typeSameAny: return false"); return false; } // equal or one is not specified private boolean xorEquals(String first, String second) { return (Objects.equals(first, second) || TextUtils.isEmpty(first) || TextUtils.isEmpty(second)); } // Helper function to convert APN string into a 32-bit bitmask. private static int getApnBitmask(String apn) { switch (apn) { Loading src/java/com/android/internal/telephony/dataconnection/DcTracker.java +22 −63 Original line number Diff line number Diff line Loading @@ -101,7 +101,6 @@ import java.util.Arrays; import java.util.Comparator; import java.util.HashMap; import java.util.Map.Entry; import java.util.Objects; import java.util.PriorityQueue; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; Loading Loading @@ -3371,7 +3370,7 @@ public class DcTracker extends Handler { int j = i + 1; while (j < mAllApnSettings.size()) { second = mAllApnSettings.get(j); if (apnsSimilar(first, second)) { if (first.similar(second)) { ApnSetting newApn = mergeApns(first, second); mAllApnSettings.set(i, newApn); first = newApn; Loading @@ -3384,66 +3383,6 @@ public class DcTracker extends Handler { } } //check whether the types of two APN same (even only one type of each APN is same) private boolean apnTypeSameAny(ApnSetting first, ApnSetting second) { if(VDBG) { StringBuilder apnType1 = new StringBuilder(first.apn + ": "); for(int index1 = 0; index1 < first.types.length; index1++) { apnType1.append(first.types[index1]); apnType1.append(","); } StringBuilder apnType2 = new StringBuilder(second.apn + ": "); for(int index1 = 0; index1 < second.types.length; index1++) { apnType2.append(second.types[index1]); apnType2.append(","); } log("APN1: is " + apnType1); log("APN2: is " + apnType2); } for(int index1 = 0; index1 < first.types.length; index1++) { for(int index2 = 0; index2 < second.types.length; index2++) { if(first.types[index1].equals(PhoneConstants.APN_TYPE_ALL) || second.types[index2].equals(PhoneConstants.APN_TYPE_ALL) || first.types[index1].equals(second.types[index2])) { if(VDBG)log("apnTypeSameAny: return true"); return true; } } } if(VDBG)log("apnTypeSameAny: return false"); return false; } // Check if neither mention DUN and are substantially similar private boolean apnsSimilar(ApnSetting first, ApnSetting second) { return (!first.canHandleType(PhoneConstants.APN_TYPE_DUN) && !second.canHandleType(PhoneConstants.APN_TYPE_DUN) && Objects.equals(first.apn, second.apn) && !apnTypeSameAny(first, second) && xorEquals(first.proxy, second.proxy) && xorEquals(first.port, second.port) && xorEquals(first.protocol, second.protocol) && xorEquals(first.roamingProtocol, second.roamingProtocol) && first.carrierEnabled == second.carrierEnabled && first.bearerBitmask == second.bearerBitmask && first.profileId == second.profileId && Objects.equals(first.mvnoType, second.mvnoType) && Objects.equals(first.mvnoMatchData, second.mvnoMatchData) && xorEquals(first.mmsc, second.mmsc) && xorEquals(first.mmsProxy, second.mmsProxy) && xorEquals(first.mmsPort, second.mmsPort)); } // equal or one is not specified private boolean xorEquals(String first, String second) { return (Objects.equals(first, second) || TextUtils.isEmpty(first) || TextUtils.isEmpty(second)); } private ApnSetting mergeApns(ApnSetting dest, ApnSetting src) { int id = dest.id; ArrayList<String> resultTypes = new ArrayList<String>(); Loading Loading @@ -4374,6 +4313,23 @@ public class DcTracker extends Handler { } } private boolean containsAllApns(ArrayList<ApnSetting> oldApnList, ArrayList<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 tearDown, String reason) { if (DBG) log("cleanUpConnectionsOnUpdatedApns: tearDown=" + tearDown); if (mAllApnSettings != null && mAllApnSettings.isEmpty()) { Loading @@ -4393,7 +4349,10 @@ public class DcTracker extends Handler { if (VDBG) log("new waitingApns:" + waitingApns); if ((currentWaitingApns != null) && ((waitingApns.size() != currentWaitingApns.size()) || (!currentWaitingApns.containsAll(waitingApns)))) { // Check if the existing waiting APN list can cover the newly built APN // list. If yes, then we don't need to tear down the existing data call. // TODO: We probably need to rebuild APN list when roaming status changes. || !containsAllApns(currentWaitingApns, waitingApns))) { if (VDBG) log("new waiting apn is different for " + apnContext); apnContext.setWaitingApns(waitingApns); if (!apnContext.isDisconnected()) { Loading tests/telephonytests/src/com/android/internal/telephony/dataconnection/ApnSettingTest.java +64 −1 Original line number Diff line number Diff line Loading @@ -749,4 +749,67 @@ public class ApnSettingTest extends TelephonyTest { } } } @Test @SmallTest public void testEqualsRoamingProtocol() throws Exception { ApnSetting apn1 = new ApnSetting( 1234, "310260", "", "ims", "", "", "", "", "", "", "", -1, new String[]{"ims"}, "IPV6", "", true, 0, 131071, 0, false, 0, 0, 0, 1440, "", ""); ApnSetting apn2 = new ApnSetting( 1235, "310260", "", "ims", "", "", "", "", "", "", "", -1, new String[]{"ims"}, "IPV6", "IPV6", true, 0, 131072, 0, false, 0, 0, 0, 1440, "", ""); assertTrue(apn1.equals(apn2, false)); assertFalse(apn1.equals(apn2, true)); } } No newline at end of file Loading
src/java/com/android/internal/telephony/dataconnection/ApnSetting.java +113 −0 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ import android.telephony.Rlog; import android.telephony.ServiceState; import android.text.TextUtils; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.Phone; import com.android.internal.telephony.PhoneConstants; import com.android.internal.telephony.RILConstants; Loading @@ -33,6 +34,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Objects; /** * This class represents a apn setting for create PDP link Loading @@ -42,6 +44,7 @@ public class ApnSetting { static final String LOG_TAG = "ApnSetting"; private static final boolean DBG = false; private static final boolean VDBG = false; static final String V2_FORMAT_REGEX = "^\\[ApnSettingV2\\]\\s*"; static final String V3_FORMAT_REGEX = "^\\[ApnSettingV3\\]\\s*"; Loading Loading @@ -544,6 +547,116 @@ public class ApnSetting { && mvnoMatchData.equals(other.mvnoMatchData); } /** * Compare two APN settings * * Note: This method does not compare 'id', 'bearer', 'bearerBitmask'. We only use this for * determining if tearing a data call is needed when conditions change. See * cleanUpConnectionsOnUpdatedApns in DcTracker. * * @param o the other object to compare * @param isDataRoaming True if the device is on data roaming * @return True if the two APN settings are same */ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) public boolean equals(Object o, boolean isDataRoaming) { if (!(o instanceof ApnSetting)) { return false; } ApnSetting other = (ApnSetting) o; return carrier.equals(other.carrier) && numeric.equals(other.numeric) && apn.equals(other.apn) && proxy.equals(other.proxy) && mmsc.equals(other.mmsc) && mmsProxy.equals(other.mmsProxy) && TextUtils.equals(mmsPort, other.mmsPort) && port.equals(other.port) && TextUtils.equals(user, other.user) && TextUtils.equals(password, other.password) && authType == other.authType && Arrays.deepEquals(types, other.types) && typesBitmap == other.typesBitmap && (isDataRoaming || protocol.equals(other.protocol)) && (!isDataRoaming || roamingProtocol.equals(other.roamingProtocol)) && carrierEnabled == other.carrierEnabled && profileId == other.profileId && modemCognitive == other.modemCognitive && maxConns == other.maxConns && waitTime == other.waitTime && maxConnsTime == other.maxConnsTime && mtu == other.mtu && mvnoType.equals(other.mvnoType) && mvnoMatchData.equals(other.mvnoMatchData); } /** * Check if neither mention DUN and are substantially similar * * @param other The other APN settings to compare * @return True if two APN settings are similar */ public boolean similar(ApnSetting other) { return (!this.canHandleType(PhoneConstants.APN_TYPE_DUN) && !other.canHandleType(PhoneConstants.APN_TYPE_DUN) && Objects.equals(this.apn, other.apn) && !typeSameAny(this, other) && xorEquals(this.proxy, other.proxy) && xorEquals(this.port, other.port) && xorEquals(this.protocol, other.protocol) && xorEquals(this.roamingProtocol, other.roamingProtocol) && this.carrierEnabled == other.carrierEnabled && this.bearerBitmask == other.bearerBitmask && this.profileId == other.profileId && Objects.equals(this.mvnoType, other.mvnoType) && Objects.equals(this.mvnoMatchData, other.mvnoMatchData) && xorEquals(this.mmsc, other.mmsc) && xorEquals(this.mmsProxy, other.mmsProxy) && xorEquals(this.mmsPort, other.mmsPort)); } // check whether the types of two APN same (even only one type of each APN is same) private boolean typeSameAny(ApnSetting first, ApnSetting second) { if (VDBG) { StringBuilder apnType1 = new StringBuilder(first.apn + ": "); for (int index1 = 0; index1 < first.types.length; index1++) { apnType1.append(first.types[index1]); apnType1.append(","); } StringBuilder apnType2 = new StringBuilder(second.apn + ": "); for (int index1 = 0; index1 < second.types.length; index1++) { apnType2.append(second.types[index1]); apnType2.append(","); } Rlog.d(LOG_TAG, "APN1: is " + apnType1); Rlog.d(LOG_TAG, "APN2: is " + apnType2); } for (int index1 = 0; index1 < first.types.length; index1++) { for (int index2 = 0; index2 < second.types.length; index2++) { if (first.types[index1].equals(PhoneConstants.APN_TYPE_ALL) || second.types[index2].equals(PhoneConstants.APN_TYPE_ALL) || first.types[index1].equals(second.types[index2])) { if (VDBG) Rlog.d(LOG_TAG, "typeSameAny: return true"); return true; } } } if (VDBG) Rlog.d(LOG_TAG, "typeSameAny: return false"); return false; } // equal or one is not specified private boolean xorEquals(String first, String second) { return (Objects.equals(first, second) || TextUtils.isEmpty(first) || TextUtils.isEmpty(second)); } // Helper function to convert APN string into a 32-bit bitmask. private static int getApnBitmask(String apn) { switch (apn) { Loading
src/java/com/android/internal/telephony/dataconnection/DcTracker.java +22 −63 Original line number Diff line number Diff line Loading @@ -101,7 +101,6 @@ import java.util.Arrays; import java.util.Comparator; import java.util.HashMap; import java.util.Map.Entry; import java.util.Objects; import java.util.PriorityQueue; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; Loading Loading @@ -3371,7 +3370,7 @@ public class DcTracker extends Handler { int j = i + 1; while (j < mAllApnSettings.size()) { second = mAllApnSettings.get(j); if (apnsSimilar(first, second)) { if (first.similar(second)) { ApnSetting newApn = mergeApns(first, second); mAllApnSettings.set(i, newApn); first = newApn; Loading @@ -3384,66 +3383,6 @@ public class DcTracker extends Handler { } } //check whether the types of two APN same (even only one type of each APN is same) private boolean apnTypeSameAny(ApnSetting first, ApnSetting second) { if(VDBG) { StringBuilder apnType1 = new StringBuilder(first.apn + ": "); for(int index1 = 0; index1 < first.types.length; index1++) { apnType1.append(first.types[index1]); apnType1.append(","); } StringBuilder apnType2 = new StringBuilder(second.apn + ": "); for(int index1 = 0; index1 < second.types.length; index1++) { apnType2.append(second.types[index1]); apnType2.append(","); } log("APN1: is " + apnType1); log("APN2: is " + apnType2); } for(int index1 = 0; index1 < first.types.length; index1++) { for(int index2 = 0; index2 < second.types.length; index2++) { if(first.types[index1].equals(PhoneConstants.APN_TYPE_ALL) || second.types[index2].equals(PhoneConstants.APN_TYPE_ALL) || first.types[index1].equals(second.types[index2])) { if(VDBG)log("apnTypeSameAny: return true"); return true; } } } if(VDBG)log("apnTypeSameAny: return false"); return false; } // Check if neither mention DUN and are substantially similar private boolean apnsSimilar(ApnSetting first, ApnSetting second) { return (!first.canHandleType(PhoneConstants.APN_TYPE_DUN) && !second.canHandleType(PhoneConstants.APN_TYPE_DUN) && Objects.equals(first.apn, second.apn) && !apnTypeSameAny(first, second) && xorEquals(first.proxy, second.proxy) && xorEquals(first.port, second.port) && xorEquals(first.protocol, second.protocol) && xorEquals(first.roamingProtocol, second.roamingProtocol) && first.carrierEnabled == second.carrierEnabled && first.bearerBitmask == second.bearerBitmask && first.profileId == second.profileId && Objects.equals(first.mvnoType, second.mvnoType) && Objects.equals(first.mvnoMatchData, second.mvnoMatchData) && xorEquals(first.mmsc, second.mmsc) && xorEquals(first.mmsProxy, second.mmsProxy) && xorEquals(first.mmsPort, second.mmsPort)); } // equal or one is not specified private boolean xorEquals(String first, String second) { return (Objects.equals(first, second) || TextUtils.isEmpty(first) || TextUtils.isEmpty(second)); } private ApnSetting mergeApns(ApnSetting dest, ApnSetting src) { int id = dest.id; ArrayList<String> resultTypes = new ArrayList<String>(); Loading Loading @@ -4374,6 +4313,23 @@ public class DcTracker extends Handler { } } private boolean containsAllApns(ArrayList<ApnSetting> oldApnList, ArrayList<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 tearDown, String reason) { if (DBG) log("cleanUpConnectionsOnUpdatedApns: tearDown=" + tearDown); if (mAllApnSettings != null && mAllApnSettings.isEmpty()) { Loading @@ -4393,7 +4349,10 @@ public class DcTracker extends Handler { if (VDBG) log("new waitingApns:" + waitingApns); if ((currentWaitingApns != null) && ((waitingApns.size() != currentWaitingApns.size()) || (!currentWaitingApns.containsAll(waitingApns)))) { // Check if the existing waiting APN list can cover the newly built APN // list. If yes, then we don't need to tear down the existing data call. // TODO: We probably need to rebuild APN list when roaming status changes. || !containsAllApns(currentWaitingApns, waitingApns))) { if (VDBG) log("new waiting apn is different for " + apnContext); apnContext.setWaitingApns(waitingApns); if (!apnContext.isDisconnected()) { Loading
tests/telephonytests/src/com/android/internal/telephony/dataconnection/ApnSettingTest.java +64 −1 Original line number Diff line number Diff line Loading @@ -749,4 +749,67 @@ public class ApnSettingTest extends TelephonyTest { } } } @Test @SmallTest public void testEqualsRoamingProtocol() throws Exception { ApnSetting apn1 = new ApnSetting( 1234, "310260", "", "ims", "", "", "", "", "", "", "", -1, new String[]{"ims"}, "IPV6", "", true, 0, 131071, 0, false, 0, 0, 0, 1440, "", ""); ApnSetting apn2 = new ApnSetting( 1235, "310260", "", "ims", "", "", "", "", "", "", "", -1, new String[]{"ims"}, "IPV6", "IPV6", true, 0, 131072, 0, false, 0, 0, 0, 1440, "", ""); assertTrue(apn1.equals(apn2, false)); assertFalse(apn1.equals(apn2, true)); } } No newline at end of file