diff options
author | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2022-06-15 08:10:18 +0000 |
---|---|---|
committer | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2022-06-15 08:10:18 +0000 |
commit | 7c77830cb277ae12c40ccc83fe2e2a700e0462a6 (patch) | |
tree | 2e082d09eede6b444ff6e9653c0930e4ee9cd8f1 | |
parent | 3fa75d9b27ed5db8bde6014746296c39b1585941 (diff) | |
parent | 1018e40f2dea81997b3420352d4349b7c78d1696 (diff) | |
download | telephony-7c77830cb277ae12c40ccc83fe2e2a700e0462a6.tar.gz |
Snap for 8727584 from 1018e40f2dea81997b3420352d4349b7c78d1696 to mainline-tzdata3-release
Change-Id: I45e2878ae1f9125a537e37bf654b37841b94448b
22 files changed, 851 insertions, 324 deletions
diff --git a/src/java/com/android/internal/telephony/CarrierPrivilegesTracker.java b/src/java/com/android/internal/telephony/CarrierPrivilegesTracker.java index dd9faa81ab..31442297b1 100644 --- a/src/java/com/android/internal/telephony/CarrierPrivilegesTracker.java +++ b/src/java/com/android/internal/telephony/CarrierPrivilegesTracker.java @@ -31,6 +31,8 @@ import static android.telephony.TelephonyManager.SIM_STATE_NOT_READY; import static android.telephony.TelephonyManager.SIM_STATE_READY; import static android.telephony.TelephonyManager.SIM_STATE_UNKNOWN; +import static com.android.internal.telephony.SubscriptionInfoUpdater.simStateString; + import android.annotation.ElapsedRealtimeLong; import android.annotation.NonNull; import android.annotation.Nullable; @@ -106,11 +108,14 @@ public class CarrierPrivilegesTracker extends Handler { private static final String SHA_1 = "SHA-1"; private static final String SHA_256 = "SHA-256"; + // TODO(b/232273884): Turn feature on when find solution to handle the inter-carriers switching /** * Time delay to clear UICC rules after UICC is gone. * This introduces the grace period to retain carrier privileges when SIM is removed. + * + * This feature is off by default due to the security concern during inter-carriers switching. */ - private static final long CLEAR_UICC_RULES_DELAY_MILLIS = TimeUnit.SECONDS.toMillis(30); + private static final long CLEAR_UICC_RULES_DELAY_MILLIS = TimeUnit.SECONDS.toMillis(0); /** * PackageManager flags used to query installed packages. @@ -178,6 +183,11 @@ public class CarrierPrivilegesTracker extends Handler { */ private static final int ACTION_CLEAR_UICC_RULES = 9; + /** + * Action to handle the case when UiccAccessRules has been loaded. + */ + private static final int ACTION_UICC_ACCESS_RULES_LOADED = 10; + private final Context mContext; private final Phone mPhone; private final PackageManager mPackageManager; @@ -430,6 +440,10 @@ public class CarrierPrivilegesTracker extends Handler { handleClearUiccRules(); break; } + case ACTION_UICC_ACCESS_RULES_LOADED: { + handleUiccAccessRulesLoaded(); + break; + } default: { Rlog.e(TAG, "Received unknown msg type: " + msg.what); break; @@ -502,16 +516,8 @@ public class CarrierPrivilegesTracker extends Handler { // Only include the UICC rules if the SIM is fully loaded if (simState == SIM_STATE_LOADED) { - mClearUiccRulesUptimeMillis = CLEAR_UICC_RULE_NOT_SCHEDULED; - removeMessages(ACTION_CLEAR_UICC_RULES); - - updatedUiccRules = getSimRules(); - - mLocalLog.log("SIM fully loaded:" - + " slotId=" + slotId - + " simState=" + simState - + " updated SIM-loaded rules=" + updatedUiccRules); - maybeUpdateRulesAndNotifyRegistrants(mUiccRules, updatedUiccRules); + mLocalLog.log("SIM fully loaded, handleUiccAccessRulesLoaded."); + handleUiccAccessRulesLoaded(); } else { if (!mUiccRules.isEmpty() && mClearUiccRulesUptimeMillis == CLEAR_UICC_RULE_NOT_SCHEDULED) { @@ -519,7 +525,8 @@ public class CarrierPrivilegesTracker extends Handler { SystemClock.uptimeMillis() + CLEAR_UICC_RULES_DELAY_MILLIS; sendMessageAtTime(obtainMessage(ACTION_CLEAR_UICC_RULES), mClearUiccRulesUptimeMillis); - mLocalLog.log("SIM is gone. Delay " + TimeUnit.MILLISECONDS.toSeconds( + mLocalLog.log("SIM is gone, simState=" + simStateString(simState) + + ". Delay " + TimeUnit.MILLISECONDS.toSeconds( CLEAR_UICC_RULES_DELAY_MILLIS) + " seconds to clear UICC rules."); } else { mLocalLog.log( @@ -528,6 +535,21 @@ public class CarrierPrivilegesTracker extends Handler { } } + private void handleUiccAccessRulesLoaded() { + mClearUiccRulesUptimeMillis = CLEAR_UICC_RULE_NOT_SCHEDULED; + removeMessages(ACTION_CLEAR_UICC_RULES); + + List<UiccAccessRule> updatedUiccRules = getSimRules(); + mLocalLog.log("UiccAccessRules loaded:" + + " updated SIM-loaded rules=" + updatedUiccRules); + maybeUpdateRulesAndNotifyRegistrants(mUiccRules, updatedUiccRules); + } + + /** Called when UiccAccessRules has been loaded */ + public void onUiccAccessRulesLoaded() { + sendEmptyMessage(ACTION_UICC_ACCESS_RULES_LOADED); + } + private void handleClearUiccRules() { mClearUiccRulesUptimeMillis = CLEAR_UICC_RULE_NOT_SCHEDULED; removeMessages(ACTION_CLEAR_UICC_RULES); @@ -574,9 +596,11 @@ public class CarrierPrivilegesTracker extends Handler { // installed for a user it wasn't installed in before, which means there will be an // additional UID. getUidsForPackage(pkg.packageName, /* invalidateCache= */ true); - mLocalLog.log("Package added/replaced/changed:" - + " pkg=" + Rlog.pii(TAG, pkgName) - + " cert hashes=" + mInstalledPackageCerts.get(pkgName)); + if (VDBG) { + Rlog.d(TAG, "Package added/replaced/changed:" + + " pkg=" + Rlog.pii(TAG, pkgName) + + " cert hashes=" + mInstalledPackageCerts.get(pkgName)); + } maybeUpdatePrivilegedPackagesAndNotifyRegistrants(); } @@ -603,7 +627,9 @@ public class CarrierPrivilegesTracker extends Handler { return; } - mLocalLog.log("Package removed or disabled by user: pkg=" + Rlog.pii(TAG, pkgName)); + if (VDBG) { + Rlog.d(TAG, "Package removed or disabled by user: pkg=" + Rlog.pii(TAG, pkgName)); + } maybeUpdatePrivilegedPackagesAndNotifyRegistrants(); } diff --git a/src/java/com/android/internal/telephony/CarrierServiceBindHelper.java b/src/java/com/android/internal/telephony/CarrierServiceBindHelper.java index 16d0dd9d29..dfa53b3958 100644 --- a/src/java/com/android/internal/telephony/CarrierServiceBindHelper.java +++ b/src/java/com/android/internal/telephony/CarrierServiceBindHelper.java @@ -29,6 +29,7 @@ import android.content.pm.ResolveInfo; import android.os.Build; import android.os.Bundle; import android.os.Handler; +import android.os.HandlerExecutor; import android.os.IBinder; import android.os.Message; import android.os.Process; @@ -47,6 +48,8 @@ import com.android.internal.telephony.util.TelephonyUtils; import java.io.FileDescriptor; import java.io.PrintWriter; +import java.util.Arrays; +import java.util.Set; /** * Manages long-lived bindings to carrier services @@ -71,6 +74,8 @@ public class CarrierServiceBindHelper { public SparseArray<AppBinding> mBindings = new SparseArray(); @VisibleForTesting public SparseArray<String> mLastSimState = new SparseArray<>(); + // TODO(b/201423849): Clean up PackageChangeReceiver/UserUnlockedReceiver/SIM State change if + // CarrierServiceChangeCallback can cover the cases private final PackageChangeReceiver mPackageMonitor = new CarrierServicePackageMonitor(); private final LocalLog mLocalLog = new LocalLog(100); @@ -90,6 +95,30 @@ public class CarrierServiceBindHelper { } }; + private class CarrierServiceChangeCallback implements + TelephonyManager.CarrierPrivilegesCallback { + final int mPhoneId; + + CarrierServiceChangeCallback(int phoneId) { + this.mPhoneId = phoneId; + } + + @Override + public void onCarrierPrivilegesChanged(Set<String> privilegedPackageNames, + Set<Integer> privilegedUids) { + // Ignored, not interested here + } + + @Override + public void onCarrierServiceChanged(String carrierServicePackageName, + int carrierServiceUid) { + logdWithLocalLog("onCarrierServiceChanged, carrierServicePackageName=" + + carrierServicePackageName + ", carrierServiceUid=" + carrierServiceUid + + ", mPhoneId=" + mPhoneId); + mHandler.sendMessage(mHandler.obtainMessage(EVENT_REBIND, mPhoneId)); + } + } + private static final int EVENT_REBIND = 0; @VisibleForTesting public static final int EVENT_PERFORM_IMMEDIATE_UNBIND = 1; @@ -123,6 +152,8 @@ public class CarrierServiceBindHelper { case EVENT_MULTI_SIM_CONFIG_CHANGED: updateBindingsAndSimStates(); break; + default: + Log.e(LOG_TAG, "Unsupported event received: " + msg.what); } } }; @@ -162,6 +193,7 @@ public class CarrierServiceBindHelper { // If prevLen > newLen, dispose AppBinding and simState objects. for (int phoneId = newLen; phoneId < prevLen; phoneId++) { + mBindings.get(phoneId).tearDown(); mBindings.get(phoneId).unbind(true); mBindings.delete(phoneId); mLastSimState.delete(phoneId); @@ -193,9 +225,23 @@ public class CarrierServiceBindHelper { private String carrierPackage; private String carrierServiceClass; private long mUnbindScheduledUptimeMillis = -1; + private final CarrierServiceChangeCallback mCarrierServiceChangeCallback; public AppBinding(int phoneId) { this.phoneId = phoneId; + this.mCarrierServiceChangeCallback = new CarrierServiceChangeCallback(phoneId); + TelephonyManager tm = mContext.getSystemService(TelephonyManager.class); + if (tm != null) { + tm.registerCarrierPrivilegesCallback(phoneId, new HandlerExecutor(mHandler), + mCarrierServiceChangeCallback); + } + } + + public void tearDown() { + TelephonyManager tm = mContext.getSystemService(TelephonyManager.class); + if (tm != null && mCarrierServiceChangeCallback != null) { + tm.unregisterCarrierPrivilegesCallback(mCarrierServiceChangeCallback); + } } public int getPhoneId() { @@ -365,6 +411,7 @@ public class CarrierServiceBindHelper { pw.println(" unbindCount: " + unbindCount); pw.println(" lastUnbindMillis: " + lastUnbindMillis); pw.println(" mUnbindScheduledUptimeMillis: " + mUnbindScheduledUptimeMillis); + pw.println(" mCarrierServiceChangeCallback: " + mCarrierServiceChangeCallback); pw.println(); } } @@ -405,27 +452,32 @@ public class CarrierServiceBindHelper { private class CarrierServicePackageMonitor extends PackageChangeReceiver { @Override public void onPackageAdded(String packageName) { + logdWithLocalLog("onPackageAdded: " + packageName); evaluateBinding(packageName, true /* forceUnbind */); } @Override public void onPackageRemoved(String packageName) { + logdWithLocalLog("onPackageRemoved: " + packageName); evaluateBinding(packageName, true /* forceUnbind */); } @Override public void onPackageUpdateFinished(String packageName) { + logdWithLocalLog("onPackageUpdateFinished: " + packageName); evaluateBinding(packageName, true /* forceUnbind */); } @Override public void onPackageModified(String packageName) { + logdWithLocalLog("onPackageModified: " + packageName); evaluateBinding(packageName, false /* forceUnbind */); } @Override public void onHandleForceStop(String[] packages, boolean doit) { if (doit) { + logdWithLocalLog("onHandleForceStop: " + Arrays.toString(packages)); for (String packageName : packages) { evaluateBinding(packageName, true /* forceUnbind */); } diff --git a/src/java/com/android/internal/telephony/NetworkTypeController.java b/src/java/com/android/internal/telephony/NetworkTypeController.java index af9d233e9a..2260d3456a 100644 --- a/src/java/com/android/internal/telephony/NetworkTypeController.java +++ b/src/java/com/android/internal/telephony/NetworkTypeController.java @@ -543,10 +543,12 @@ public class NetworkTypeController extends StateMachine { switch (msg.what) { case EVENT_UPDATE: case EVENT_PREFERRED_NETWORK_MODE_CHANGED: + if (DBG) log("Reset timers since preferred network mode changed."); resetAllTimers(); transitionToCurrentState(); break; case EVENT_QUIT: + if (DBG) log("Reset timers on state machine quitting."); resetAllTimers(); unRegisterForAllEvents(); quit(); @@ -585,25 +587,32 @@ public class NetworkTypeController extends StateMachine { log("mIsPhysicalChannelConfigOn changed to: " + mIsPhysicalChannelConfigOn); } if (!mIsPhysicalChannelConfigOn) { + if (DBG) { + log("Reset timers since physical channel config indications are off."); + } resetAllTimers(); } transitionToCurrentState(); break; case EVENT_CARRIER_CONFIG_CHANGED: parseCarrierConfigs(); + if (DBG) log("Reset timers since carrier configurations changed."); resetAllTimers(); transitionToCurrentState(); break; case EVENT_PRIMARY_TIMER_EXPIRED: + if (DBG) log("Primary timer expired for state: " + mPrimaryTimerState); transitionWithSecondaryTimerTo((IState) msg.obj); break; case EVENT_SECONDARY_TIMER_EXPIRED: + if (DBG) log("Secondary timer expired for state: " + mSecondaryTimerState); mIsSecondaryTimerActive = false; mSecondaryTimerState = ""; updateTimers(); updateOverrideNetworkType(); break; case EVENT_RADIO_OFF_OR_UNAVAILABLE: + if (DBG) log("Reset timers since radio is off or unavailable."); resetAllTimers(); transitionTo(mLegacyState); break; @@ -614,6 +623,7 @@ public class NetworkTypeController extends StateMachine { log("mIsDeviceIdleMode changed to: " + mIsDeviceIdleMode); } if (mIsDeviceIdleMode) { + if (DBG) log("Reset timers since device is in idle mode."); resetAllTimers(); } transitionToCurrentState(); @@ -637,7 +647,7 @@ public class NetworkTypeController extends StateMachine { * This is the initial state. */ private final class LegacyState extends State { - private Boolean mIsNrRestricted = false; + private boolean mIsNrRestricted = false; @Override public void enter() { @@ -664,7 +674,7 @@ public class NetworkTypeController extends StateMachine { ? mLteConnectedState : mIdleState); } else { if (!isLte(rat)) { - // Rat is 3G or 2G, and it doesn't need NR timer. + if (DBG) log("Reset timers since 2G and 3G don't need NR timers."); resetAllTimers(); } updateOverrideNetworkType(); @@ -689,6 +699,7 @@ public class NetworkTypeController extends StateMachine { if (isUsingPhysicalChannelConfigForRrcDetection()) { mPhysicalLinkStatus = getPhysicalLinkStatusFromPhysicalChannelConfig(); if (mIsTimerResetEnabledForLegacyStateRRCIdle && !isPhysicalLinkActive()) { + if (DBG) log("Reset timers since timer reset is enabled for RRC idle."); resetAllTimers(); } } @@ -699,6 +710,7 @@ public class NetworkTypeController extends StateMachine { AsyncResult ar = (AsyncResult) msg.obj; mPhysicalLinkStatus = (int) ar.result; if (mIsTimerResetEnabledForLegacyStateRRCIdle && !isPhysicalLinkActive()) { + if (DBG) log("Reset timers since timer reset is enabled for RRC idle."); resetAllTimers(); updateOverrideNetworkType(); } @@ -714,7 +726,7 @@ public class NetworkTypeController extends StateMachine { @Override public String getName() { - return mIsNrRestricted ? STATE_RESTRICTED : STATE_LEGACY; + return mIsNrRestricted ? STATE_RESTRICTED : STATE_LEGACY; } } @@ -889,14 +901,14 @@ public class NetworkTypeController extends StateMachine { private final LteConnectedState mLteConnectedState = new LteConnectedState(); /** - * Device is connected to 5G NR as the secondary cell. + * Device is connected to 5G NR as the primary or secondary cell. */ private final class NrConnectedState extends State { - private Boolean mIsNrAdvanced = false; + private boolean mIsNrAdvanced = false; @Override public void enter() { - if (DBG) log("Entering NrConnectedState"); + if (DBG) log("Entering NrConnectedState(" + getName() + ")"); updateTimers(); updateOverrideNetworkType(); if (!mIsPrimaryTimerActive && !mIsSecondaryTimerActive) { @@ -907,7 +919,7 @@ public class NetworkTypeController extends StateMachine { @Override public boolean processMessage(Message msg) { - if (DBG) log("NrConnectedState: process " + getEventName(msg.what)); + if (DBG) log("NrConnectedState(" + getName() + "): process " + getEventName(msg.what)); updateTimers(); int rat = getDataNetworkType(); switch (msg.what) { @@ -974,10 +986,10 @@ public class NetworkTypeController extends StateMachine { return; } if (!isNrAdvanced()) { - // STATE_CONNECTED_NR_ADVANCED -> STATE_CONNECTED + if (DBG) log("updateNrAdvancedState: CONNECTED_NR_ADVANCED -> CONNECTED"); transitionWithTimerTo(mNrConnectedState); } else { - // STATE_CONNECTED -> STATE_CONNECTED_NR_ADVANCED + if (DBG) log("updateNrAdvancedState: CONNECTED -> CONNECTED_NR_ADVANCED"); transitionTo(mNrConnectedState); } mIsNrAdvanced = isNrAdvanced(); @@ -1002,10 +1014,10 @@ public class NetworkTypeController extends StateMachine { && mNrAdvancedCapablePcoId > 0 && pcodata.pcoId == mNrAdvancedCapablePcoId ) { - log("EVENT_PCO_DATA_CHANGED: Nr Advanced is allowed by PCO. length:" + log("EVENT_PCO_DATA_CHANGED: NR_ADVANCED is allowed by PCO. length:" + pcodata.contents.length + ",value: " + Arrays.toString(pcodata.contents)); - mIsNrAdvancedAllowedByPco = (pcodata.contents.length > 0) - ? pcodata.contents[pcodata.contents.length - 1] == 1 : false; + mIsNrAdvancedAllowedByPco = pcodata.contents.length > 0 + && pcodata.contents[pcodata.contents.length - 1] == 1; updateNrAdvancedState(); } } @@ -1015,14 +1027,15 @@ public class NetworkTypeController extends StateMachine { private void transitionWithTimerTo(IState destState) { String destName = destState.getName(); + if (DBG) log("Transition with primary timer from " + mPreviousState + " to " + destName); OverrideTimerRule rule = mOverrideTimerRules.get(mPreviousState); if (!mIsDeviceIdleMode && rule != null && rule.getTimer(destName) > 0) { - if (DBG) log("Primary timer started for state: " + mPreviousState); + int duration = rule.getTimer(destName); + if (DBG) log(duration + "s primary timer started for state: " + mPreviousState); mPrimaryTimerState = mPreviousState; mPreviousState = getCurrentState().getName(); mIsPrimaryTimerActive = true; - sendMessageDelayed(EVENT_PRIMARY_TIMER_EXPIRED, destState, - rule.getTimer(destName) * 1000L); + sendMessageDelayed(EVENT_PRIMARY_TIMER_EXPIRED, destState, duration * 1000L); } transitionTo(destState); } @@ -1030,13 +1043,17 @@ public class NetworkTypeController extends StateMachine { private void transitionWithSecondaryTimerTo(IState destState) { String currentName = getCurrentState().getName(); OverrideTimerRule rule = mOverrideTimerRules.get(mPrimaryTimerState); + if (DBG) { + log("Transition with secondary timer from " + currentName + " to " + + destState.getName()); + } if (!mIsDeviceIdleMode && rule != null && rule.getSecondaryTimer(currentName) > 0) { - if (DBG) log("Secondary timer started for state: " + currentName); + int duration = rule.getSecondaryTimer(currentName); + if (DBG) log(duration + "s secondary timer started for state: " + currentName); mSecondaryTimerState = currentName; mPreviousState = currentName; mIsSecondaryTimerActive = true; - sendMessageDelayed(EVENT_SECONDARY_TIMER_EXPIRED, destState, - rule.getSecondaryTimer(currentName) * 1000L); + sendMessageDelayed(EVENT_SECONDARY_TIMER_EXPIRED, destState, duration * 1000L); } mIsPrimaryTimerActive = false; transitionTo(getCurrentState()); @@ -1070,6 +1087,7 @@ public class NetworkTypeController extends StateMachine { private void updateTimers() { if ((mPhone.getCachedAllowedNetworkTypesBitmask() & TelephonyManager.NETWORK_TYPE_BITMASK_NR) == 0) { + if (DBG) log("Reset timers since NR is not allowed."); resetAllTimers(); return; } @@ -1098,21 +1116,21 @@ public class NetworkTypeController extends StateMachine { mSecondaryTimerState = ""; } - if (currentState.equals(STATE_CONNECTED_NR_ADVANCED)) { - resetAllTimers(); - } + if (mIsPrimaryTimerActive || mIsSecondaryTimerActive) { + if (currentState.equals(STATE_CONNECTED_NR_ADVANCED)) { + if (DBG) log("Reset timers since state is NR_ADVANCED."); + resetAllTimers(); + } - int rat = getDataNetworkType(); - if (!isLte(rat) && rat != TelephonyManager.NETWORK_TYPE_NR) { - // Rat is 3G or 2G, and it doesn't need NR timer. - resetAllTimers(); + int rat = getDataNetworkType(); + if (!isLte(rat) && rat != TelephonyManager.NETWORK_TYPE_NR) { + if (DBG) log("Reset timers since 2G and 3G don't need NR timers."); + resetAllTimers(); + } } } private void resetAllTimers() { - if (DBG) { - log("Remove all timers"); - } removeMessages(EVENT_PRIMARY_TIMER_EXPIRED); removeMessages(EVENT_SECONDARY_TIMER_EXPIRED); mIsPrimaryTimerActive = false; @@ -1125,7 +1143,7 @@ public class NetworkTypeController extends StateMachine { * Private class defining timer rules between states to prevent flickering. These rules are * created in {@link #parseCarrierConfigs()} based on various carrier configs. */ - private class OverrideTimerRule { + private static class OverrideTimerRule { /** The 5G state this timer rule applies for. See {@link #ALL_STATES}. */ final String mState; @@ -1320,7 +1338,7 @@ public class NetworkTypeController extends StateMachine { + ", mPrimaryTimerState=" + mPrimaryTimerState + ", mSecondaryTimerState=" + mSecondaryTimerState + ", mPreviousState=" + mPreviousState - + ", misNrAdvanced=" + isNrAdvanced(); + + ", mIsNrAdvanced=" + isNrAdvanced(); } @Override diff --git a/src/java/com/android/internal/telephony/RIL.java b/src/java/com/android/internal/telephony/RIL.java index 00e88fc0cc..49e8297c45 100644 --- a/src/java/com/android/internal/telephony/RIL.java +++ b/src/java/com/android/internal/telephony/RIL.java @@ -186,7 +186,7 @@ public class RIL extends BaseCommands implements CommandsInterface { int mLastRadioPowerResult = RadioError.NONE; - boolean mHidlSetResponseFunctionsCalled = false; + boolean mIsRadioProxyInitialized = false; // When we are testing emergency calls using ril.test.emergencynumber, this will trigger test // ECbM when the call is ended. @@ -354,7 +354,7 @@ public class RIL extends BaseCommands implements CommandsInterface { + ", service = " + serviceToString(service) + ", service cookie = " + mServiceCookies.get(service)); if ((long) msg.obj == mServiceCookies.get(service).get()) { - mHidlSetResponseFunctionsCalled = false; + mIsRadioProxyInitialized = false; resetProxyAndRequestList(service); } break; @@ -366,7 +366,7 @@ public class RIL extends BaseCommands implements CommandsInterface { + ", service = " + serviceToString(aidlService) + ", cookie = " + mServiceCookies.get(aidlService)); if (obj.get() == mServiceCookies.get(aidlService).get()) { - mHidlSetResponseFunctionsCalled = false; + mIsRadioProxyInitialized = false; resetProxyAndRequestList(aidlService); } break; @@ -526,7 +526,7 @@ public class RIL extends BaseCommands implements CommandsInterface { } if (serviceBound) { - mHidlSetResponseFunctionsCalled = false; + mIsRadioProxyInitialized = false; for (int service = MIN_SERVICE_IDX; service <= MAX_SERVICE_IDX; service++) { resetProxyAndRequestList(service); } @@ -668,10 +668,10 @@ public class RIL extends BaseCommands implements CommandsInterface { } if (mRadioProxy != null) { - mRadioProxy.linkToDeath(mRadioProxyDeathRecipient, - mServiceCookies.get(RADIO_SERVICE).incrementAndGet()); - if (!mHidlSetResponseFunctionsCalled) { - mHidlSetResponseFunctionsCalled = true; + if (!mIsRadioProxyInitialized) { + mIsRadioProxyInitialized = true; + mRadioProxy.linkToDeath(mRadioProxyDeathRecipient, + mServiceCookies.get(RADIO_SERVICE).incrementAndGet()); mRadioProxy.setResponseFunctions(mRadioResponse, mRadioIndication); } } else { @@ -964,10 +964,10 @@ public class RIL extends BaseCommands implements CommandsInterface { if (mRadioVersion.greaterOrEqual(RADIO_HAL_VERSION_2_0)) { throw new AssertionError("serviceProxy shouldn't be HIDL with HAL 2.0"); } - serviceProxy.getHidl().linkToDeath(mRadioProxyDeathRecipient, - mServiceCookies.get(service).incrementAndGet()); - if (!mHidlSetResponseFunctionsCalled) { - mHidlSetResponseFunctionsCalled = true; + if (!mIsRadioProxyInitialized) { + mIsRadioProxyInitialized = true; + serviceProxy.getHidl().linkToDeath(mRadioProxyDeathRecipient, + mServiceCookies.get(service).incrementAndGet()); serviceProxy.getHidl().setResponseFunctions( mRadioResponse, mRadioIndication); } @@ -998,7 +998,7 @@ public class RIL extends BaseCommands implements CommandsInterface { @Override public synchronized void onSlotActiveStatusChange(boolean active) { - mHidlSetResponseFunctionsCalled = false; + mIsRadioProxyInitialized = false; for (int service = MIN_SERVICE_IDX; service <= MAX_SERVICE_IDX; service++) { if (active) { // Try to connect to RIL services and set response functions. @@ -1184,7 +1184,7 @@ public class RIL extends BaseCommands implements CommandsInterface { private void handleRadioProxyExceptionForRR(int service, String caller, Exception e) { riljLoge(caller + ": " + e); e.printStackTrace(); - mHidlSetResponseFunctionsCalled = false; + mIsRadioProxyInitialized = false; resetProxyAndRequestList(service); } diff --git a/src/java/com/android/internal/telephony/SubscriptionController.java b/src/java/com/android/internal/telephony/SubscriptionController.java index d0c0b624fb..7e762d7af0 100644 --- a/src/java/com/android/internal/telephony/SubscriptionController.java +++ b/src/java/com/android/internal/telephony/SubscriptionController.java @@ -28,9 +28,6 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.app.AppOpsManager; import android.app.PendingIntent; -import android.app.compat.CompatChanges; -import android.compat.annotation.ChangeId; -import android.compat.annotation.EnabledSince; import android.compat.annotation.UnsupportedAppUsage; import android.content.ContentResolver; import android.content.ContentValues; @@ -170,15 +167,6 @@ public class SubscriptionController extends ISub.Stub { // Allows test mocks to avoid SELinux failures on invalidate calls. private static boolean sCachingEnabled = true; - /** - * Apps targeting on Android T and beyond will get exception if there is no - * {@link Manifest.permission#USE_ICC_AUTH_WITH_DEVICE_IDENTIFIER} permission - * when calling SubscriptionManager#getSubscriptionsInGroup. - */ - @ChangeId - @EnabledSince(targetSdkVersion = Build.VERSION_CODES.TIRAMISU) - public static final long REQUIRE_ICC_AUTH_DEVICE_IDENTIFIERS_FOR_GROUP_UUID = 213902861L; - // Each slot can have multiple subs. private static class WatchedSlotIndexToSubIds { private Map<Integer, ArrayList<Integer>> mSlotIndexToSubIds = new ConcurrentHashMap<>(); @@ -473,11 +461,10 @@ public class SubscriptionController extends ISub.Stub { /** * Returns whether the {@code callingPackage} has access to subscriber identifiers on the * specified {@code subId} using the provided {@code message} in any resulting - * SecurityException. {@code throwException} flag to indicate if throw exception. + * SecurityException. */ private boolean hasSubscriberIdentifierAccess(int subId, String callingPackage, - String callingFeatureId, String message, boolean reportFailure, - boolean throwException) { + String callingFeatureId, String message, boolean reportFailure) { try { return TelephonyPermissions.checkCallingOrSelfReadSubscriberIdentifiers(mContext, subId, callingPackage, callingFeatureId, message, reportFailure); @@ -485,9 +472,6 @@ public class SubscriptionController extends ISub.Stub { // A SecurityException indicates that the calling package is targeting at least the // minimum level that enforces identifier access restrictions and the new access // requirements are not met. - if (throwException) { - throw e; - } return false; } } @@ -2845,7 +2829,8 @@ public class SubscriptionController extends ISub.Stub { if (subId == SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) { throw new RuntimeException("setDefaultVoiceSubId called with DEFAULT_SUB_ID"); } - if (DBG) logdl("[setDefaultVoiceSubId] subId=" + subId); + + logdl("[setDefaultVoiceSubId] subId=" + subId); int previousDefaultSub = getDefaultSubId(); @@ -3975,21 +3960,10 @@ public class SubscriptionController extends ISub.Stub { * Get subscriptionInfo list of subscriptions that are in the same group of given subId. * See {@link #createSubscriptionGroup(int[], String)} for more details. * - * Caller must have {@link android.Manifest.permission#READ_PHONE_STATE} - * or carrier privilege permission on the subscription. + * Caller will either have {@link android.Manifest.permission#READ_PHONE_STATE} + * permission or had carrier privilege permission on the subscription. * {@link TelephonyManager#hasCarrierPrivileges(int)} * - * <p>Starting with API level 33, the caller needs the additional permission - * {@link Manifest.permission#USE_ICC_AUTH_WITH_DEVICE_IDENTIFIER} - * to get the list of subscriptions associated with a group UUID. - * This method can be invoked if one of the following requirements is met: - * <ul> - * <li>If the app has carrier privilege permission. - * {@link TelephonyManager#hasCarrierPrivileges()} - * <li>If the app has {@link android.Manifest.permission#READ_PHONE_STATE} and - * {@link Manifest.permission#USE_ICC_AUTH_WITH_DEVICE_IDENTIFIER} permission. - * </ul> - * * @throws SecurityException if the caller doesn't meet the requirements * outlined above. * @@ -4017,29 +3991,15 @@ public class SubscriptionController extends ISub.Stub { } return subInfoList.stream().filter(info -> { - int subId = info.getSubscriptionId(); - boolean permission = checkPermissionForGroupUuid(subId, callingPackage, - callingFeatureId, Binder.getCallingUid()); if (!groupUuid.equals(info.getGroupUuid())) return false; - return permission || info.canManageSubscription(mContext, callingPackage); + int subId = info.getSubscriptionId(); + return TelephonyPermissions.checkCallingOrSelfReadPhoneState(mContext, subId, + callingPackage, callingFeatureId, "getSubscriptionsInGroup") + || info.canManageSubscription(mContext, callingPackage); }).map(subscriptionInfo -> conditionallyRemoveIdentifiers(subscriptionInfo, callingPackage, callingFeatureId, "getSubscriptionsInGroup")) .collect(Collectors.toList()); - } - - private boolean checkPermissionForGroupUuid(int subId, String callingPackage, - String callingFeatureId, int uid) { - if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(mContext, subId, - callingPackage, callingFeatureId, "getSubscriptionsInGroup")) { - return false; - } - if (CompatChanges.isChangeEnabled( - REQUIRE_ICC_AUTH_DEVICE_IDENTIFIERS_FOR_GROUP_UUID, uid)) { - return hasSubscriberIdentifierAccess(subId, callingPackage, - callingFeatureId, "getSubscriptionsInGroup", true, true); - } - return true; } /** @@ -4353,7 +4313,7 @@ public class SubscriptionController extends ISub.Stub { if (canReadPhoneState) { canReadIdentifiers = hasSubscriberIdentifierAccess( SubscriptionManager.INVALID_SUBSCRIPTION_ID, callingPackage, - callingFeatureId, "getSubscriptionInfoList", false, false); + callingFeatureId, "getSubscriptionInfoList", false); canReadPhoneNumber = hasPhoneNumberAccess( SubscriptionManager.INVALID_SUBSCRIPTION_ID, callingPackage, callingFeatureId, "getSubscriptionInfoList"); @@ -4405,7 +4365,7 @@ public class SubscriptionController extends ISub.Stub { SubscriptionInfo result = subInfo; int subId = subInfo.getSubscriptionId(); boolean hasIdentifierAccess = hasSubscriberIdentifierAccess(subId, callingPackage, - callingFeatureId, message, true, false); + callingFeatureId, message, true); boolean hasPhoneNumberAccess = hasPhoneNumberAccess(subId, callingPackage, callingFeatureId, message); return conditionallyRemoveIdentifiers(subInfo, hasIdentifierAccess, hasPhoneNumberAccess); diff --git a/src/java/com/android/internal/telephony/data/DataConfigManager.java b/src/java/com/android/internal/telephony/data/DataConfigManager.java index 1504960581..82a4ccdce6 100644 --- a/src/java/com/android/internal/telephony/data/DataConfigManager.java +++ b/src/java/com/android/internal/telephony/data/DataConfigManager.java @@ -70,6 +70,9 @@ import java.util.stream.Collectors; * {@link CarrierConfigManager}. All the data config will be loaded once and stored here. */ public class DataConfigManager extends Handler { + /** The default timeout in ms for data network stuck in a transit state. */ + private static final int DEFAULT_NETWORK_TRANSIT_STATE_TIMEOUT_MS = 300000; + /** Event for carrier config changed. */ private static final int EVENT_CARRIER_CONFIG_CHANGED = 1; @@ -347,22 +350,23 @@ public class DataConfigManager extends Handler { mImsReleaseRequestAnomalyReportThreshold = parseSlidingWindowCounterThreshold( properties.getString(KEY_ANOMALY_IMS_RELEASE_REQUEST, null), - 300000, + 0, 12); mNetworkUnwantedAnomalyReportThreshold = parseSlidingWindowCounterThreshold( properties.getString(KEY_ANOMALY_NETWORK_UNWANTED, null), - 300000, + 0, 12); mSetupDataCallAnomalyReportThreshold = parseSlidingWindowCounterThreshold( properties.getString(KEY_ANOMALY_SETUP_DATA_CALL_FAILURE, null), 0, 2); mNetworkConnectingTimeout = properties.getInt( - KEY_ANOMALY_NETWORK_CONNECTING_TIMEOUT, 86400000); + KEY_ANOMALY_NETWORK_CONNECTING_TIMEOUT, DEFAULT_NETWORK_TRANSIT_STATE_TIMEOUT_MS); mNetworkDisconnectingTimeout = properties.getInt( - KEY_ANOMALY_NETWORK_DISCONNECTING_TIMEOUT, 86400000); + KEY_ANOMALY_NETWORK_DISCONNECTING_TIMEOUT, + DEFAULT_NETWORK_TRANSIT_STATE_TIMEOUT_MS); mNetworkHandoverTimeout = properties.getInt( - KEY_ANOMALY_NETWORK_HANDOVER_TIMEOUT, 86400000); + KEY_ANOMALY_NETWORK_HANDOVER_TIMEOUT, DEFAULT_NETWORK_TRANSIT_STATE_TIMEOUT_MS); } /** diff --git a/src/java/com/android/internal/telephony/data/DataNetwork.java b/src/java/com/android/internal/telephony/data/DataNetwork.java index 0d4b210e9c..f85bc13cae 100644 --- a/src/java/com/android/internal/telephony/data/DataNetwork.java +++ b/src/java/com/android/internal/telephony/data/DataNetwork.java @@ -59,6 +59,7 @@ import android.telephony.NetworkRegistrationInfo; import android.telephony.PcoData; import android.telephony.PreciseDataConnectionState; import android.telephony.ServiceState; +import android.telephony.SubscriptionManager; import android.telephony.SubscriptionPlan; import android.telephony.TelephonyDisplayInfo; import android.telephony.TelephonyManager; @@ -230,12 +231,6 @@ public class DataNetwork extends StateMachine { /** Event for CSS indicator changed. */ private static final int EVENT_CSS_INDICATOR_CHANGED = 24; - /** The default MTU for IPv4 network. */ - private static final int DEFAULT_MTU_V4 = 1280; - - /** The default MTU for IPv6 network. */ - private static final int DEFAULT_MTU_V6 = 1280; - /** Invalid context id. */ private static final int INVALID_CID = -1; @@ -280,6 +275,7 @@ public class DataNetwork extends StateMachine { TEAR_DOWN_REASON_NOT_ALLOWED_BY_POLICY, TEAR_DOWN_REASON_ILLEGAL_STATE, TEAR_DOWN_REASON_ONLY_ALLOWED_SINGLE_NETWORK, + TEAR_DOWN_REASON_PREFERRED_DATA_SWITCHED, }) public @interface TearDownReason {} @@ -369,6 +365,9 @@ public class DataNetwork extends StateMachine { /** Data network tear down due to only allowed single network. */ public static final int TEAR_DOWN_REASON_ONLY_ALLOWED_SINGLE_NETWORK = 29; + /** Data network tear down due to preferred data switched to another phone. */ + public static final int TEAR_DOWN_REASON_PREFERRED_DATA_SWITCHED = 30; + @IntDef(prefix = {"BANDWIDTH_SOURCE_"}, value = { BANDWIDTH_SOURCE_UNKNOWN, @@ -467,6 +466,9 @@ public class DataNetwork extends StateMachine { */ private final int mSubId; + /** The network score of this network. */ + private int mNetworkScore; + /** * Indicates that * {@link DataService.DataServiceProvider#deactivateDataCall(int, int, DataServiceCallback)} @@ -955,8 +957,10 @@ public class DataNetwork extends StateMachine { mPhone.getPhoneId()); final NetworkProvider provider = (null == factory) ? null : factory.getProvider(); + mNetworkScore = getNetworkScore(); return new TelephonyNetworkAgent(mPhone, getHandler().getLooper(), this, - getNetworkScore(), configBuilder.build(), provider, + new NetworkScore.Builder().setLegacyInt(mNetworkScore).build(), + configBuilder.build(), provider, new TelephonyNetworkAgentCallback(getHandler()::post) { @Override public void onValidationStatus(@ValidationStatus int status, @@ -1047,13 +1051,12 @@ public class DataNetwork extends StateMachine { } case EVENT_ATTACH_NETWORK_REQUEST: { onAttachNetworkRequests((NetworkRequestList) msg.obj); + updateNetworkScore(); break; } case EVENT_DETACH_NETWORK_REQUEST: { - TelephonyNetworkRequest networkRequest = (TelephonyNetworkRequest) msg.obj; - mAttachedNetworkRequestList.remove(networkRequest); - networkRequest.setState(TelephonyNetworkRequest.REQUEST_STATE_UNSATISFIED); - networkRequest.setAttachedNetwork(null); + onDetachNetworkRequest((TelephonyNetworkRequest) msg.obj); + updateNetworkScore(); break; } case EVENT_DETACH_ALL_NETWORK_REQUESTS: { @@ -1291,8 +1294,6 @@ public class DataNetwork extends StateMachine { case EVENT_VOICE_CALL_STARTED: case EVENT_VOICE_CALL_ENDED: case EVENT_CSS_INDICATOR_CHANGED: - // We might entered non-VoPS network. Need to update the network capability to - // remove MMTEL capability. updateSuspendState(); updateNetworkCapabilities(); break; @@ -1469,8 +1470,6 @@ public class DataNetwork extends StateMachine { case EVENT_CSS_INDICATOR_CHANGED: case EVENT_VOICE_CALL_STARTED: case EVENT_VOICE_CALL_ENDED: - // We might entered non-VoPS network. Need to update the network capability to - // remove MMTEL capability. updateSuspendState(); updateNetworkCapabilities(); break; @@ -1619,6 +1618,31 @@ public class DataNetwork extends StateMachine { } /** + * Called when detaching the network request from this data network. + * + * @param networkRequest Network request to detach. + */ + private void onDetachNetworkRequest(@NonNull TelephonyNetworkRequest networkRequest) { + mAttachedNetworkRequestList.remove(networkRequest); + networkRequest.setState(TelephonyNetworkRequest.REQUEST_STATE_UNSATISFIED); + networkRequest.setAttachedNetwork(null); + + if (mAttachedNetworkRequestList.isEmpty()) { + log("All network requests are detached."); + + // If there is no network request attached, and we are not preferred data phone, then + // this detach is likely due to temp DDS switch. We should tear down the network when + // all requests are detached so the other network on preferred data sub can be + // established properly. + int preferredDataPhoneId = PhoneSwitcher.getInstance().getPreferredDataPhoneId(); + if (preferredDataPhoneId != SubscriptionManager.INVALID_PHONE_INDEX + && preferredDataPhoneId != mPhone.getPhoneId()) { + tearDown(TEAR_DOWN_REASON_PREFERRED_DATA_SWITCHED); + } + } + } + + /** * Detach the network request from this data network. Note that this will not tear down the * network. * @@ -1777,14 +1801,13 @@ public class DataNetwork extends StateMachine { } } - // If voice call is on-going, do not change MMTEL capability, which is an immutable - // capability. Changing it will result in CS tearing down IMS network, and the voice - // call will drop. - if (shouldDelayImsTearDown() && mNetworkCapabilities != null + // Once we set the MMTEL capability, we should never remove it because it's an immutable + // capability defined by connectivity service. When the device enters from VoPS to non-VoPS, + // we should perform grace tear down from data network controller if needed. + if (mNetworkCapabilities != null && mNetworkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_MMTEL)) { // Previous capability has MMTEL, so add it again. builder.addCapability(NetworkCapabilities.NET_CAPABILITY_MMTEL); - log("Delayed IMS tear down. Reporting MMTEL capability for now."); } else { // Always add MMTEL capability on IMS network unless network explicitly indicates VoPS // not supported. @@ -2191,7 +2214,7 @@ public class DataNetwork extends StateMachine { mtuV4 = mDataProfile.getApnSetting().getMtuV4(); } if (mtuV4 <= 0) { - mtuV4 = DEFAULT_MTU_V4; + mtuV4 = mDataConfigManager.getDefaultMtu(); } } @@ -2203,7 +2226,7 @@ public class DataNetwork extends StateMachine { mtuV6 = mDataProfile.getApnSetting().getMtuV6(); } if (mtuV6 <= 0) { - mtuV6 = DEFAULT_MTU_V6; + mtuV6 = mDataConfigManager.getDefaultMtu(); } } @@ -2440,7 +2463,7 @@ public class DataNetwork extends StateMachine { public boolean shouldDelayImsTearDown() { return mDataConfigManager.isImsDelayTearDownEnabled() && mNetworkCapabilities != null - && mNetworkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_IMS) + && mNetworkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_MMTEL) && mPhone.getImsPhone() != null && mPhone.getImsPhone().getCallTracker().getState() != PhoneConstants.State.IDLE; @@ -2759,16 +2782,27 @@ public class DataNetwork extends StateMachine { } /** + * Update the network score and report to connectivity service if necessary. + */ + private void updateNetworkScore() { + int networkScore = getNetworkScore(); + if (networkScore != mNetworkScore) { + logl("Updating score from " + mNetworkScore + " to " + networkScore); + mNetworkScore = networkScore; + mNetworkAgent.sendNetworkScore(mNetworkScore); + } + } + + /** * @return The network score. The higher score of the network has higher chance to be * selected by the connectivity service as active network. */ - private @NonNull NetworkScore getNetworkScore() { + private int getNetworkScore() { // If it's serving a network request that asks NET_CAPABILITY_INTERNET and doesn't have // specify a sub id, this data network is considered to be default internet data // connection. In this case we assign a slightly higher score of 50. The intention is // it will not be replaced by other data networks accidentally in DSDS use case. int score = OTHER_NETWORK_SCORE; - // TODO: Should update the score when attached list changed. for (TelephonyNetworkRequest networkRequest : mAttachedNetworkRequestList) { if (networkRequest.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) && networkRequest.getNetworkSpecifier() == null) { @@ -2776,7 +2810,7 @@ public class DataNetwork extends StateMachine { } } - return new NetworkScore.Builder().setLegacyInt(score).build(); + return score; } /** @@ -2935,6 +2969,14 @@ public class DataNetwork extends StateMachine { } /** + * @return {@code true} if this network was setup for SUPL during emergency call. {@code false} + * otherwise. + */ + public boolean isEmergencySupl() { + return mDataAllowedReason == DataAllowedReason.EMERGENCY_SUPL; + } + + /** * Get precise data connection state * * @return The {@link PreciseDataConnectionState} @@ -3207,6 +3249,8 @@ public class DataNetwork extends StateMachine { return "TEAR_DOWN_REASON_ILLEGAL_STATE"; case TEAR_DOWN_REASON_ONLY_ALLOWED_SINGLE_NETWORK: return "TEAR_DOWN_REASON_ONLY_ALLOWED_SINGLE_NETWORK"; + case TEAR_DOWN_REASON_PREFERRED_DATA_SWITCHED: + return "TEAR_DOWN_REASON_PREFERRED_DATA_SWITCHED"; default: return "UNKNOWN(" + reason + ")"; } @@ -3351,6 +3395,7 @@ public class DataNetwork extends StateMachine { pw.println("mTransport=" + AccessNetworkConstants.transportTypeToString(mTransport)); pw.println("WWAN cid=" + mCid.get(AccessNetworkConstants.TRANSPORT_TYPE_WWAN)); pw.println("WLAN cid=" + mCid.get(AccessNetworkConstants.TRANSPORT_TYPE_WLAN)); + pw.println("mNetworkScore=" + mNetworkScore); pw.println("mDataAllowedReason=" + mDataAllowedReason); pw.println("mPduSessionId=" + mPduSessionId); pw.println("mDataProfile=" + mDataProfile); diff --git a/src/java/com/android/internal/telephony/data/DataNetworkController.java b/src/java/com/android/internal/telephony/data/DataNetworkController.java index 2b0507c4a6..7be0a4d8de 100644 --- a/src/java/com/android/internal/telephony/data/DataNetworkController.java +++ b/src/java/com/android/internal/telephony/data/DataNetworkController.java @@ -934,8 +934,13 @@ public class DataNetworkController extends Handler { + DataUtils.networkCapabilityToString(capability) + " preferred on " + AccessNetworkConstants.transportTypeToString(preferredTransport)); DataNetworkController.this.onEvaluatePreferredTransport(capability); - sendMessage(obtainMessage(EVENT_REEVALUATE_UNSATISFIED_NETWORK_REQUESTS, - DataEvaluationReason.PREFERRED_TRANSPORT_CHANGED)); + if (!hasMessages(EVENT_REEVALUATE_UNSATISFIED_NETWORK_REQUESTS)) { + sendMessage(obtainMessage(EVENT_REEVALUATE_UNSATISFIED_NETWORK_REQUESTS, + DataEvaluationReason.PREFERRED_TRANSPORT_CHANGED)); + } else { + log("onPreferredTransportChanged: Skipped evaluating unsatisfied network " + + "requests because another evaluation was already scheduled."); + } } }); @@ -1649,6 +1654,31 @@ public class DataNetworkController extends Handler { } } + // If the data network is IMS that supports voice call, and has MMTEL request (client + // specified VoPS is required.) + if (dataNetwork.getAttachedNetworkRequestList().get( + new int[]{NetworkCapabilities.NET_CAPABILITY_MMTEL}) != null) { + // When reaching here, it means the network supports MMTEL, and also has MMTEL request + // attached to it. + if (!dataNetwork.shouldDelayImsTearDown()) { + if (dataNetwork.getTransport() == AccessNetworkConstants.TRANSPORT_TYPE_WWAN) { + NetworkRegistrationInfo nri = mServiceState.getNetworkRegistrationInfo( + NetworkRegistrationInfo.DOMAIN_PS, + AccessNetworkConstants.TRANSPORT_TYPE_WWAN); + if (nri != null) { + DataSpecificRegistrationInfo dsri = nri.getDataSpecificInfo(); + if (dsri != null && dsri.getVopsSupportInfo() != null + && !dsri.getVopsSupportInfo().isVopsSupported()) { + evaluation.addDataDisallowedReason( + DataDisallowedReason.VOPS_NOT_SUPPORTED); + } + } + } + } else { + log("Ignored VoPS check due to delay IMS tear down until call ends."); + } + } + // Check if data is disabled boolean dataDisabled = false; if (!mDataSettingsManager.isDataEnabled()) { @@ -1716,9 +1746,7 @@ public class DataNetworkController extends Handler { // If there are reasons we should tear down the network, check if those are hard reasons // or soft reasons. In some scenarios, we can make exceptions if they are soft // disallowed reasons. - if ((mPhone.isInEmergencyCall() || mPhone.isInEcm()) - && dataNetwork.getNetworkCapabilities().hasCapability( - NetworkCapabilities.NET_CAPABILITY_SUPL)) { + if ((mPhone.isInEmergencyCall() || mPhone.isInEcm()) && dataNetwork.isEmergencySupl()) { // Check if it's SUPL during emergency call. evaluation.addDataAllowedReason(DataAllowedReason.EMERGENCY_SUPL); } else if (!dataNetwork.getNetworkCapabilities().hasCapability( @@ -1989,16 +2017,24 @@ public class DataNetworkController extends Handler { sendMessage(obtainMessage(EVENT_REMOVE_NETWORK_REQUEST, networkRequest)); } - private void onRemoveNetworkRequest(@NonNull TelephonyNetworkRequest networkRequest) { + private void onRemoveNetworkRequest(@NonNull TelephonyNetworkRequest request) { + // The request generated from telephony network factory does not contain the information + // the original request has, for example, attached data network. We need to find the + // original one. + TelephonyNetworkRequest networkRequest = mAllNetworkRequestList.stream() + .filter(r -> r.equals(request)) + .findFirst() + .orElse(null); + if (networkRequest == null || !mAllNetworkRequestList.remove(networkRequest)) { + loge("onRemoveNetworkRequest: Network request does not exist. " + networkRequest); + return; + } + if (networkRequest.hasCapability(NetworkCapabilities.NET_CAPABILITY_IMS)) { mImsThrottleCounter.addOccurrence(); mLastReleasedImsRequestCapabilities = networkRequest.getCapabilities(); mLastImsOperationIsRelease = true; } - if (!mAllNetworkRequestList.remove(networkRequest)) { - loge("onRemoveNetworkRequest: Network request does not exist. " + networkRequest); - return; - } if (networkRequest.getAttachedNetwork() != null) { networkRequest.getAttachedNetwork().detachNetworkRequest(networkRequest); @@ -3376,8 +3412,12 @@ public class DataNetworkController extends Handler { + (mRegisteredImsFeatures.contains(ImsFeature.FEATURE_RCS) ? "registered" : "not registered") ); - mPendingImsDeregDataNetworks.put(dataNetwork, - dataNetwork.tearDownWhenConditionMet(reason, deregDelay)); + Runnable runnable = dataNetwork.tearDownWhenConditionMet(reason, deregDelay); + if (runnable != null) { + mPendingImsDeregDataNetworks.put(dataNetwork, runnable); + } else { + log(dataNetwork + " is being torn down already."); + } } else { // Graceful tear down is not turned on. Tear down the network immediately. log("tearDownGracefully: Safe to tear down " + dataNetwork); diff --git a/src/java/com/android/internal/telephony/data/DataProfileManager.java b/src/java/com/android/internal/telephony/data/DataProfileManager.java index f459b82e71..1ec345c943 100644 --- a/src/java/com/android/internal/telephony/data/DataProfileManager.java +++ b/src/java/com/android/internal/telephony/data/DataProfileManager.java @@ -273,7 +273,7 @@ public class DataProfileManager extends Handler { } // Check if any of the profile already supports IMS, if not, add the default one. - DataProfile dataProfile = profiles.stream() + dataProfile = profiles.stream() .filter(dp -> dp.canSatisfy(NetworkCapabilities.NET_CAPABILITY_IMS)) .findFirst() .orElse(null); @@ -312,14 +312,15 @@ public class DataProfileManager extends Handler { profilesChanged = true; } + // Reload the latest preferred data profile from either database or config. + profilesChanged |= updatePreferredDataProfile(); + int setId = getPreferredDataProfileSetId(); if (setId != mPreferredDataProfileSetId) { logl("Changed preferred data profile set id to " + setId); mPreferredDataProfileSetId = setId; profilesChanged = true; } - // Reload the latest preferred data profile from either database or config. - profilesChanged |= updatePreferredDataProfile(); updateDataProfilesAtModem(); updateInitialAttachDataProfileAtModem(); @@ -461,6 +462,10 @@ public class DataProfileManager extends Handler { preferredDataProfile = getPreferredDataProfileFromDb(); if (preferredDataProfile == null) { preferredDataProfile = getPreferredDataProfileFromConfig(); + if (preferredDataProfile != null) { + // Save the carrier specified preferred data profile into database + setPreferredDataProfile(preferredDataProfile); + } } } else { preferredDataProfile = null; diff --git a/src/java/com/android/internal/telephony/data/DataSettingsManager.java b/src/java/com/android/internal/telephony/data/DataSettingsManager.java index 68c1b5d110..e2c1aff05a 100644 --- a/src/java/com/android/internal/telephony/data/DataSettingsManager.java +++ b/src/java/com/android/internal/telephony/data/DataSettingsManager.java @@ -228,14 +228,8 @@ public class DataSettingsManager extends Handler { } case EVENT_SET_DATA_ROAMING_ENABLED: { boolean enabled = (boolean) msg.obj; - // Will trigger handleDataOnRoamingChange() through observer - boolean changed = GlobalSettingsHelper.setBoolean(mPhone.getContext(), - Settings.Global.DATA_ROAMING, mSubId, enabled); - if (changed) { - logl("DataRoamingEnabled changed to " + enabled); - mDataSettingsManagerCallbacks.forEach(callback -> callback.invokeFromExecutor( - () -> callback.onDataRoamingEnabledChanged(enabled))); - } + setDataRoamingEnabledInternal(enabled); + setDataRoamingFromUserAction(); break; } case EVENT_SET_ALWAYS_ALLOW_MMS_DATA: { @@ -501,7 +495,7 @@ public class DataSettingsManager extends Handler { } /** - * Enable or disable data roaming. + * Enable or disable data roaming from user settings. * @param enabled {@code true} to enable data roaming and {@code false} to disable. */ public void setDataRoamingEnabled(boolean enabled) { @@ -509,6 +503,21 @@ public class DataSettingsManager extends Handler { } /** + * Enable or disable data roaming. + * @param enabled {@code true} to enable data roaming and {@code false} to disable. + */ + private void setDataRoamingEnabledInternal(boolean enabled) { + // Will trigger handleDataOnRoamingChange() through observer + boolean changed = GlobalSettingsHelper.setBoolean(mPhone.getContext(), + Settings.Global.DATA_ROAMING, mSubId, enabled); + if (changed) { + logl("DataRoamingEnabled changed to " + enabled); + mDataSettingsManagerCallbacks.forEach(callback -> callback.invokeFromExecutor( + () -> callback.onDataRoamingEnabledChanged(enabled))); + } + } + + /** * Check whether data roaming is enabled for the device based on the current * {@link Settings.Global#DATA_ROAMING} value. * @return {@code true} if data roaming is enabled and {@code false} otherwise. @@ -537,7 +546,7 @@ public class DataSettingsManager extends Handler { public void setDefaultDataRoamingEnabled() { // For SSSS, this is a per-phone property from DATA_ROAMING_IS_USER_SETTING_KEY. // For DSDS, this is a per-sub property from Settings.Global.DATA_ROAMING + subId. - // If the user has not manually set the value, use the default from carrier configurations. + // If the user has not manually set the value, use the default value. boolean useCarrierSpecificDefault = false; if (mPhone.getContext().getSystemService(TelephonyManager.class).getSimCount() != 1) { String setting = Settings.Global.DATA_ROAMING + mPhone.getSubId(); @@ -554,7 +563,7 @@ public class DataSettingsManager extends Handler { log("setDefaultDataRoamingEnabled: useCarrierSpecificDefault=" + useCarrierSpecificDefault); if (useCarrierSpecificDefault) { boolean defaultVal = isDefaultDataRoamingEnabled(); - setDataRoamingEnabled(defaultVal); + setDataRoamingEnabledInternal(defaultVal); } } @@ -573,6 +582,17 @@ public class DataSettingsManager extends Handler { return sp.getBoolean(Phone.DATA_ROAMING_IS_USER_SETTING_KEY, true); } + /** + * Indicate that the user has manually enabled or disabled the data roaming value from settings. + * If the user has not manually set the data roaming value, the default value from + * {@link #isDefaultDataRoamingEnabled()} will continue to be used. + */ + private void setDataRoamingFromUserAction() { + final SharedPreferences.Editor sp = PreferenceManager + .getDefaultSharedPreferences(mPhone.getContext()).edit(); + sp.putBoolean(Phone.DATA_ROAMING_IS_USER_SETTING_KEY, true).commit(); + } + private @NonNull DataEnabledOverride getDataEnabledOverride() { return new DataEnabledOverride(SubscriptionController.getInstance() .getDataEnabledOverrideRules(mSubId)); @@ -724,6 +744,9 @@ public class DataSettingsManager extends Handler { pw.println("isDataEnabled(internet)=" + isDataEnabled(ApnSetting.TYPE_DEFAULT)); pw.println("isDataEnabled(mms)=" + isDataEnabled(ApnSetting.TYPE_MMS)); pw.println("isUserDataEnabled=" + isUserDataEnabled()); + pw.println("isDataRoamingEnabled=" + isDataRoamingEnabled()); + pw.println("isDefaultDataRoamingEnabled=" + isDefaultDataRoamingEnabled()); + pw.println("isDataRoamingFromUserAction=" + isDataRoamingFromUserAction()); pw.println("device_provisioned=" + Settings.Global.getInt( mResolver, Settings.Global.DEVICE_PROVISIONED, 0)); pw.println("isProvisioningDataEnabled=" + isProvisioningDataEnabled()); diff --git a/src/java/com/android/internal/telephony/data/PhoneSwitcher.java b/src/java/com/android/internal/telephony/data/PhoneSwitcher.java index bb0ee8b793..cc5f44738b 100644 --- a/src/java/com/android/internal/telephony/data/PhoneSwitcher.java +++ b/src/java/com/android/internal/telephony/data/PhoneSwitcher.java @@ -312,7 +312,7 @@ public class PhoneSwitcher extends Handler { protected RadioConfig mRadioConfig; - private static final int MAX_LOCAL_LOG_LINES = 32; + private static final int MAX_LOCAL_LOG_LINES = 256; // Default timeout value of network validation in millisecond. private final static int DEFAULT_VALIDATION_EXPIRATION_TIME = 2000; @@ -958,7 +958,7 @@ public class PhoneSwitcher extends Handler { mPrioritizedDcRequests.add(dcRequest); Collections.sort(mPrioritizedDcRequests); onEvaluate(REQUESTS_CHANGED, "netRequest"); - log("Added DcRequest, size: " + mPrioritizedDcRequests.size()); + if (VDBG) log("Added DcRequest, size: " + mPrioritizedDcRequests.size()); } } } @@ -979,7 +979,7 @@ public class PhoneSwitcher extends Handler { if (mPrioritizedDcRequests.remove(dcRequest)) { onEvaluate(REQUESTS_CHANGED, "netReleased"); collectReleaseNetworkMetrics(networkRequest); - log("Removed DcRequest, size: " + mPrioritizedDcRequests.size()); + if (VDBG) log("Removed DcRequest, size: " + mPrioritizedDcRequests.size()); } } } @@ -1264,7 +1264,7 @@ public class PhoneSwitcher extends Handler { protected void sendRilCommands(int phoneId) { if (!SubscriptionManager.isValidPhoneId(phoneId)) { - log("sendRilCommands: skip dds switch due to invalid phoneid=" + phoneId); + log("sendRilCommands: skip dds switch due to invalid phoneId=" + phoneId); return; } @@ -1674,8 +1674,54 @@ public class PhoneSwitcher extends Handler { mLocalLog.log(l); } + /** + * Convert data switch reason into string. + * + * @param reason The switch reason. + * @return The switch reason in string format. + */ + private static @NonNull String switchReasonToString(int reason) { + switch(reason) { + case TelephonyEvent.DataSwitch.Reason.DATA_SWITCH_REASON_UNKNOWN: + return "UNKNOWN"; + case TelephonyEvent.DataSwitch.Reason.DATA_SWITCH_REASON_MANUAL: + return "MANUAL"; + case TelephonyEvent.DataSwitch.Reason.DATA_SWITCH_REASON_IN_CALL: + return "IN_CALL"; + case TelephonyEvent.DataSwitch.Reason.DATA_SWITCH_REASON_CBRS: + return "CBRS"; + default: return "UNKNOWN(" + reason + ")"; + } + } + + /** + * Concert switching state to string + * + * @param state The switching state. + * @return The switching state in string format. + */ + private static @NonNull String switchStateToString(int state) { + switch(state) { + case TelephonyEvent.EventState.EVENT_STATE_UNKNOWN: + return "UNKNOWN"; + case TelephonyEvent.EventState.EVENT_STATE_START: + return "START"; + case TelephonyEvent.EventState.EVENT_STATE_END: + return "END"; + default: return "UNKNOWN(" + state + ")"; + } + } + + /** + * Log data switch event + * + * @param subId Subscription index. + * @param state The switching state. + * @param reason The switching reason. + */ private void logDataSwitchEvent(int subId, int state, int reason) { - log("logDataSwitchEvent subId " + subId + " state " + state + " reason " + reason); + log("Data switch event. subId=" + subId + ", state=" + switchStateToString(state) + + ", reason=" + switchReasonToString(reason)); DataSwitch dataSwitch = new DataSwitch(); dataSwitch.state = state; dataSwitch.reason = reason; @@ -1708,6 +1754,7 @@ public class PhoneSwitcher extends Handler { public void dump(FileDescriptor fd, PrintWriter writer, String[] args) { final IndentingPrintWriter pw = new IndentingPrintWriter(writer, " "); pw.println("PhoneSwitcher:"); + pw.increaseIndent(); Calendar c = Calendar.getInstance(); for (int i = 0; i < mActiveModemCount; i++) { PhoneState ps = mPhoneStates[i]; @@ -1716,14 +1763,29 @@ public class PhoneSwitcher extends Handler { (ps.lastRequested == 0 ? "never" : String.format("%tm-%td %tH:%tM:%tS.%tL", c, c, c, c, c, c))); } + pw.println("mPreferredDataPhoneId=" + mPreferredDataPhoneId); + pw.println("mPreferredDataSubId=" + mPreferredDataSubId.get()); + pw.println("DefaultDataSubId=" + mSubscriptionController.getDefaultDataSubId()); + pw.println("DefaultDataPhoneId=" + mSubscriptionController.getPhoneId( + mSubscriptionController.getDefaultDataSubId())); + pw.println("mPrimaryDataSubId=" + mPrimaryDataSubId); + pw.println("mOpptDataSubId=" + mOpptDataSubId); + pw.println("mIsRegisteredForImsRadioTechChange=" + mIsRegisteredForImsRadioTechChange); + pw.println("mPendingSwitchNeedValidation=" + mPendingSwitchNeedValidation); + pw.println("mMaxDataAttachModemCount=" + mMaxDataAttachModemCount); + pw.println("mActiveModemCount=" + mActiveModemCount); + pw.println("mPhoneIdInVoiceCall=" + mPhoneIdInVoiceCall); + pw.println("mCurrentDdsSwitchFailure=" + mCurrentDdsSwitchFailure); + pw.println("Local logs:"); pw.increaseIndent(); mLocalLog.dump(fd, pw, args); pw.decreaseIndent(); + pw.decreaseIndent(); } private boolean isAnyVoiceCallActiveOnDevice() { boolean ret = mPhoneIdInVoiceCall != SubscriptionManager.INVALID_PHONE_INDEX; - log("isAnyVoiceCallActiveOnDevice: " + ret); + if (VDBG) log("isAnyVoiceCallActiveOnDevice: " + ret); return ret; } diff --git a/src/java/com/android/internal/telephony/data/TelephonyNetworkFactory.java b/src/java/com/android/internal/telephony/data/TelephonyNetworkFactory.java index a56bbcdba1..85f0ae1f0d 100644 --- a/src/java/com/android/internal/telephony/data/TelephonyNetworkFactory.java +++ b/src/java/com/android/internal/telephony/data/TelephonyNetworkFactory.java @@ -58,7 +58,7 @@ public class TelephonyNetworkFactory extends NetworkFactory { public final String LOG_TAG; protected static final boolean DBG = true; - private static final int REQUEST_LOG_SIZE = 32; + private static final int REQUEST_LOG_SIZE = 256; private static final int ACTION_NO_OP = 0; private static final int ACTION_REQUEST = 1; @@ -302,6 +302,7 @@ public class TelephonyNetworkFactory extends NetworkFactory { // apply or revoke requests if our active-ness changes private void onActivePhoneSwitch() { + logl("onActivePhoneSwitch"); for (Map.Entry<TelephonyNetworkRequest, Integer> entry : mNetworkRequests.entrySet()) { TelephonyNetworkRequest networkRequest = entry.getKey(); boolean applied = entry.getValue() != AccessNetworkConstants.TRANSPORT_TYPE_INVALID; @@ -338,7 +339,7 @@ public class TelephonyNetworkFactory extends NetworkFactory { final int newSubscriptionId = mSubscriptionController.getSubIdUsingPhoneId( mPhone.getPhoneId()); if (mSubscriptionId != newSubscriptionId) { - if (DBG) log("onSubIdChange " + mSubscriptionId + "->" + newSubscriptionId); + if (DBG) logl("onSubIdChange " + mSubscriptionId + "->" + newSubscriptionId); mSubscriptionId = newSubscriptionId; setCapabilityFilter(makeNetworkFilter(mSubscriptionId)); } @@ -535,6 +536,8 @@ public class TelephonyNetworkFactory extends NetworkFactory { */ public void dump(FileDescriptor fd, PrintWriter writer, String[] args) { final IndentingPrintWriter pw = new IndentingPrintWriter(writer, " "); + pw.println("TelephonyNetworkFactory-" + mPhone.getPhoneId()); + pw.increaseIndent(); pw.println("Network Requests:"); pw.increaseIndent(); for (Map.Entry<TelephonyNetworkRequest, Integer> entry : mNetworkRequests.entrySet()) { @@ -543,7 +546,11 @@ public class TelephonyNetworkFactory extends NetworkFactory { pw.println(nr + (transport != AccessNetworkConstants.TRANSPORT_TYPE_INVALID ? (" applied on " + transport) : " not applied")); } + pw.decreaseIndent(); + pw.print("Local logs:"); + pw.increaseIndent(); mLocalLog.dump(fd, pw, args); pw.decreaseIndent(); + pw.decreaseIndent(); } } diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java index ce2198de33..cc8af38cdd 100644 --- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java +++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java @@ -220,6 +220,7 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { isUssd |= extras.getBoolean(ImsManager.EXTRA_USSD, false); if (isUssd) { if (DBG) log("processIncomingCall: USSD"); + mOperationLocalLog.log("processIncomingCall: USSD"); mUssdSession = mImsManager.takeCall(c, mImsUssdListener); if (mUssdSession != null) { mUssdSession.accept(ImsCallProfile.CALL_TYPE_VOICE); @@ -271,6 +272,7 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { if (cause == DisconnectCause.INCOMING_AUTO_REJECTED) { conn.setDisconnectCause(cause); if (DBG) log("onIncomingCall : incoming call auto rejected"); + mOperationLocalLog.log("processIncomingCall: auto rejected"); } } catch (NumberFormatException e) { Rlog.e(LOG_TAG, "Exception in parsing Integer Data: " + e); @@ -310,9 +312,9 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { updatePhoneState(); mPhone.notifyPreciseCallStateChanged(); - } catch (ImsException e) { + } catch (ImsException | RemoteException e) { loge("processIncomingCall: exception " + e); - } catch (RemoteException e) { + mOperationLocalLog.log("onIncomingCall: exception processing: " + e); } } @@ -504,6 +506,8 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { PENDING_RESUME_FOREGROUND_AFTER_FAILURE, // Pending holding a call to dial another outgoing call HOLDING_TO_DIAL_OUTGOING, + // Pending resuming the foreground call after it has completed an ongoing hold operation. + PENDING_RESUME_FOREGROUND_AFTER_HOLD } //***** Instance Variables @@ -1451,7 +1455,6 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { int videoState = dialArgs.videoState; if (DBG) log("dial clirMode=" + clirMode); - mOperationLocalLog.log("dial requested."); String origNumber = dialString; if (isEmergencyNumber) { clirMode = CommandsInterface.CLIR_SUPPRESSION; @@ -1483,6 +1486,7 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { mLastDialArgs = dialArgs; mPendingMO = new ImsPhoneConnection(mPhone, dialString, this, mForegroundCall, isEmergencyNumber, isWpsCall); + mOperationLocalLog.log("dial requested. connId=" + System.identityHashCode(mPendingMO)); if (isEmergencyNumber && dialArgs != null && dialArgs.intentExtras != null) { Rlog.i(LOG_TAG, "dial ims emergency dialer: " + dialArgs.intentExtras.getBoolean( TelecomManager.EXTRA_IS_USER_INTENT_EMERGENCY_CALL)); @@ -2066,9 +2070,15 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { //they were switched before holding ImsCall imsCall = mForegroundCall.getImsCall(); if (imsCall != null) { - imsCall.resume(); - mMetrics.writeOnImsCommand(mPhone.getPhoneId(), imsCall.getSession(), - ImsCommand.IMS_CMD_RESUME); + if (!imsCall.isPendingHold()) { + imsCall.resume(); + mMetrics.writeOnImsCommand(mPhone.getPhoneId(), imsCall.getSession(), + ImsCommand.IMS_CMD_RESUME); + } else { + mHoldSwitchingState = + HoldSwapState.PENDING_RESUME_FOREGROUND_AFTER_HOLD; + logHoldSwapState("resumeForegroundCall - unhold pending; resume request again"); + } } } @@ -2525,34 +2535,33 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { } ImsCall imsCall = call.getImsCall(); + ImsPhoneConnection conn = findConnection(imsCall); boolean rejectCall = false; + String logResult = "(undefined)"; if (call == mRingingCall) { - if (Phone.DEBUG_PHONE) log("(ringing) hangup incoming"); + logResult = "(ringing) hangup incoming"; rejectCall = true; } else if (call == mForegroundCall) { if (call.isDialingOrAlerting()) { - if (Phone.DEBUG_PHONE) { - log("(foregnd) hangup dialing or alerting..."); - } + logResult = "(foregnd) hangup dialing or alerting..."; } else { - if (Phone.DEBUG_PHONE) { - log("(foregnd) hangup foreground"); - } + logResult = "(foregnd) hangup foreground"; //held call will be resumed by onCallTerminated } } else if (call == mBackgroundCall) { - if (Phone.DEBUG_PHONE) { - log("(backgnd) hangup waiting or background"); - } + logResult = "(backgnd) hangup waiting or background"; } else if (call == mHandoverCall) { - if (Phone.DEBUG_PHONE) { - log("(handover) hangup handover (SRVCC) call"); - } + logResult = "(handover) hangup handover (SRVCC) call"; } else { + mOperationLocalLog.log("hangup: ImsPhoneCall " + System.identityHashCode(conn) + + " does not belong to ImsPhoneCallTracker " + this); throw new CallStateException ("ImsPhoneCall " + call + "does not belong to ImsPhoneCallTracker " + this); } + if (Phone.DEBUG_PHONE) log(logResult); + mOperationLocalLog.log("hangup: " + logResult + ", connId=" + + System.identityHashCode(conn)); call.onHangupLocal(); @@ -2581,6 +2590,7 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { removeMessages(EVENT_DIAL_PENDINGMO); } } catch (ImsException e) { + mOperationLocalLog.log("hangup: ImsException=" + e); throw new CallStateException(e.getMessage()); } @@ -2754,6 +2764,10 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { return; } + // Do not log operations that do not change the state + mOperationLocalLog.log("processCallStateChange: state=" + state + " cause=" + cause + + " connId=" + System.identityHashCode(conn)); + changed = conn.update(imsCall, state); if (state == ImsPhoneCall.State.DISCONNECTED) { changed = conn.onDisconnect(cause) || changed; @@ -3443,7 +3457,12 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { // processCallStateChange above may have caused the mBackgroundCall and // mForegroundCall references below to change meaning. Watch out for this if you // are reading through this code. - if (oldState == ImsPhoneCall.State.ACTIVE) { + if (mHoldSwitchingState + == HoldSwapState.PENDING_RESUME_FOREGROUND_AFTER_HOLD) { + sendEmptyMessage(EVENT_RESUME_NOW_FOREGROUND_CALL); + mHoldSwitchingState = HoldSwapState.INACTIVE; + mCallExpectedToResume = null; + } else if (oldState == ImsPhoneCall.State.ACTIVE) { // Note: This case comes up when we have just held a call in response to a // switchWaitingOrHoldingAndActive. We now need to resume the background call. if (mForegroundCall.getState() == ImsPhoneCall.State.HOLDING @@ -3488,7 +3507,10 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { synchronized (mSyncHold) { ImsPhoneCall.State bgState = mBackgroundCall.getState(); - if (reasonInfo.getCode() == ImsReasonInfo.CODE_LOCAL_CALL_TERMINATED) { + if (mHoldSwitchingState + == HoldSwapState.PENDING_RESUME_FOREGROUND_AFTER_HOLD) { + mHoldSwitchingState = HoldSwapState.INACTIVE; + } else if (reasonInfo.getCode() == ImsReasonInfo.CODE_LOCAL_CALL_TERMINATED) { // disconnected while processing hold if (mPendingMO != null) { dialPendingMO(); @@ -4585,6 +4607,9 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { case HOLDING_TO_DIAL_OUTGOING: holdSwapState = "HOLDING_TO_DIAL_OUTGOING"; break; + case PENDING_RESUME_FOREGROUND_AFTER_HOLD: + holdSwapState = "PENDING_RESUME_FOREGROUND_AFTER_HOLD"; + break; } logi("holdSwapState set to " + holdSwapState + " at " + loc); } diff --git a/src/java/com/android/internal/telephony/uicc/UiccController.java b/src/java/com/android/internal/telephony/uicc/UiccController.java index 9ce271ea54..70cfce00b6 100644 --- a/src/java/com/android/internal/telephony/uicc/UiccController.java +++ b/src/java/com/android/internal/telephony/uicc/UiccController.java @@ -36,6 +36,7 @@ import android.os.Registrant; import android.os.RegistrantList; import android.preference.PreferenceManager; import android.sysprop.TelephonyProperties; +import android.telephony.AnomalyReporter; import android.telephony.CarrierConfigManager; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; @@ -65,6 +66,7 @@ import java.io.PrintWriter; import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.UUID; import java.util.stream.IntStream; /** @@ -910,8 +912,13 @@ public class UiccController extends Handler { cardId = convertToPublicCardId(eid); } else { // In case of non Euicc, use default port index to get the IccId. - String iccId = card.getUiccPort(TelephonyManager.DEFAULT_PORT_INDEX).getIccId(); - // leave eid null if the UICC is not embedded + UiccPort port = card.getUiccPort(TelephonyManager.DEFAULT_PORT_INDEX); + if (port == null) { + AnomalyReporter.reportAnomaly( + UUID.fromString("92885ba7-98bb-490a-ba19-987b1c8b2055"), + "UiccController: Found UiccPort Null object."); + } + String iccId = (port != null) ? port.getIccId() : null; cardId = convertToPublicCardId(iccId); } } else { diff --git a/src/java/com/android/internal/telephony/uicc/UiccProfile.java b/src/java/com/android/internal/telephony/uicc/UiccProfile.java index 864b3cdc2d..2809895309 100644 --- a/src/java/com/android/internal/telephony/uicc/UiccProfile.java +++ b/src/java/com/android/internal/telephony/uicc/UiccProfile.java @@ -53,6 +53,7 @@ import android.util.ArraySet; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.CarrierAppUtils; +import com.android.internal.telephony.CarrierPrivilegesTracker; import com.android.internal.telephony.CommandsInterface; import com.android.internal.telephony.IccCard; import com.android.internal.telephony.IccCardConstants; @@ -238,6 +239,13 @@ public class UiccProfile extends IccCard { case EVENT_CARRIER_PRIVILEGES_LOADED: if (VDBG) log("handleMessage: EVENT_CARRIER_PRIVILEGES_LOADED"); + Phone phone = PhoneFactory.getPhone(mPhoneId); + if (phone != null) { + CarrierPrivilegesTracker cpt = phone.getCarrierPrivilegesTracker(); + if (cpt != null) { + cpt.onUiccAccessRulesLoaded(); + } + } onCarrierPrivilegesLoadedMessage(); updateExternalState(); break; diff --git a/tests/telephonytests/src/com/android/internal/telephony/CarrierPrivilegesTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/CarrierPrivilegesTrackerTest.java index 92faabd1d8..221b2b525e 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/CarrierPrivilegesTrackerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/CarrierPrivilegesTrackerTest.java @@ -73,6 +73,7 @@ import com.android.internal.telephony.uicc.IccUtils; import org.junit.After; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.InOrder; @@ -549,7 +550,8 @@ public class CarrierPrivilegesTrackerTest extends TelephonyTest { List.of(new Pair<>(PRIVILEGED_PACKAGES, PRIVILEGED_UIDS_SET))); } - @Test + // TODO(b/232273884): turn UT case on when grace period is on + @Ignore public void testSimStateChangedSimStateNotReady() throws Exception { // Start with privileges, verify clearing certs clears UIDs setupCarrierPrivilegesTrackerWithSimLoadedUids(); @@ -573,7 +575,8 @@ public class CarrierPrivilegesTrackerTest extends TelephonyTest { new Pair<>(Set.of(), Set.of()))); } - @Test + // TODO(b/232273884): turn UT case on when grace period is on + @Ignore public void testSimStateChangedSimStateAbsentThenLoadedWithSameRules() throws Exception { // Start with privileges setupCarrierPrivilegesTrackerWithSimLoadedUids(); @@ -642,7 +645,8 @@ public class CarrierPrivilegesTrackerTest extends TelephonyTest { List.of(new Pair<>(Set.of(), Set.of()))); } - @Test + // TODO(b/232273884): turn UT case on when grace period is on + @Ignore public void testSimStateChangedSimStateAbsentThenLoadedWithUpdatedRules() throws Exception { // Start with privileges setupCarrierPrivilegesTrackerWithSimLoadedUids(); diff --git a/tests/telephonytests/src/com/android/internal/telephony/CarrierServiceBindHelperTest.java b/tests/telephonytests/src/com/android/internal/telephony/CarrierServiceBindHelperTest.java index acae8592f3..8ce11aef7a 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/CarrierServiceBindHelperTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/CarrierServiceBindHelperTest.java @@ -18,10 +18,15 @@ package com.android.internal.telephony; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; +import static org.mockito.Mockito.any; import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.eq; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; import android.os.Message; +import android.telephony.TelephonyManager.CarrierPrivilegesCallback; import android.test.suitebuilder.annotation.SmallTest; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; @@ -30,10 +35,14 @@ import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper public class CarrierServiceBindHelperTest extends TelephonyTest { + private static final int PHONE_ID_0 = 0; + private static final int PHONE_ID_1 = 1; + CarrierServiceBindHelper mCarrierServiceBindHelper; @Before public void setUp() throws Exception { @@ -90,4 +99,38 @@ public class CarrierServiceBindHelperTest extends TelephonyTest { CarrierServiceBindHelper.EVENT_PERFORM_IMMEDIATE_UNBIND, new Integer(0))); } + + @Test + public void testCarrierPrivilegesCallbackRegistration() { + // Device starts with DSDS mode + doReturn(2).when(mTelephonyManager).getActiveModemCount(); + mCarrierServiceBindHelper = new CarrierServiceBindHelper(mContext); + processAllMessages(); + + // Verify that CarrierPrivilegesCallbacks are registered on both phones. + // Capture the callbacks for further verification + ArgumentCaptor<CarrierPrivilegesCallback> phone0CallbackCaptor = ArgumentCaptor.forClass( + CarrierPrivilegesCallback.class); + verify(mTelephonyManager).registerCarrierPrivilegesCallback(eq(PHONE_ID_0), any(), + phone0CallbackCaptor.capture()); + CarrierPrivilegesCallback phone0Callback = phone0CallbackCaptor.getAllValues().get(0); + assertNotNull(phone0Callback); + + ArgumentCaptor<CarrierPrivilegesCallback> phone1CallbackCaptor = ArgumentCaptor.forClass( + CarrierPrivilegesCallback.class); + verify(mTelephonyManager).registerCarrierPrivilegesCallback(eq(PHONE_ID_1), any(), + phone1CallbackCaptor.capture()); + CarrierPrivilegesCallback phone1Callback = phone1CallbackCaptor.getAllValues().get(0); + assertNotNull(phone1Callback); + + // Switch back to single SIM. + doReturn(1).when(mTelephonyManager).getActiveModemCount(); + PhoneConfigurationManager.notifyMultiSimConfigChange(1); + processAllMessages(); + + // Verify the callback for phone1 had been unregistered while phone0 didn't. + verify(mTelephonyManager).unregisterCarrierPrivilegesCallback(eq(phone1Callback)); + verify(mTelephonyManager, never()).unregisterCarrierPrivilegesCallback(eq(phone0Callback)); + } + // TODO (b/232461097): Add UT cases to cover more scenarios (user unlock, SIM state change...) } diff --git a/tests/telephonytests/src/com/android/internal/telephony/SubscriptionControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/SubscriptionControllerTest.java index 14e58c75d5..6a4c9c2010 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/SubscriptionControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/SubscriptionControllerTest.java @@ -17,7 +17,6 @@ package com.android.internal.telephony; import static android.telephony.TelephonyManager.SET_OPPORTUNISTIC_SUB_REMOTE_SERVICE_EXCEPTION; -import static com.android.internal.telephony.SubscriptionController.REQUIRE_ICC_AUTH_DEVICE_IDENTIFIERS_FOR_GROUP_UUID; import static com.android.internal.telephony.uicc.IccCardStatus.CardState.CARDSTATE_PRESENT; import static org.junit.Assert.assertEquals; @@ -34,9 +33,7 @@ import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.atLeast; -import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; @@ -44,7 +41,6 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.Manifest; -import android.compat.testing.PlatformCompatChangeRule; import android.content.ContentResolver; import android.content.ContentValues; import android.content.Intent; @@ -72,14 +68,9 @@ import com.android.internal.telephony.uicc.IccCardStatus; import com.android.internal.telephony.uicc.UiccController; import com.android.internal.telephony.uicc.UiccSlot; -import libcore.junit.util.compat.CoreCompatChangeRule.DisableCompatChanges; -import libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges; - import org.junit.After; import org.junit.Before; -import org.junit.Rule; import org.junit.Test; -import org.junit.rules.TestRule; import org.mockito.ArgumentCaptor; import java.util.ArrayList; @@ -117,9 +108,6 @@ public class SubscriptionControllerTest extends TelephonyTest { private static final String DISPLAY_NUMBER = "123456"; private static final String DISPLAY_NAME = "testing_display_name"; - @Rule - public TestRule mCompatChangeRule = new PlatformCompatChangeRule(); - @Before public void setUp() throws Exception { super.setUp(getClass().getSimpleName()); @@ -1111,7 +1099,6 @@ public class SubscriptionControllerTest extends TelephonyTest { @Test @SmallTest - @EnableCompatChanges({REQUIRE_ICC_AUTH_DEVICE_IDENTIFIERS_FOR_GROUP_UUID}) public void testAddSubscriptionIntoGroupWithCarrierPrivilegePermission() throws Exception { testInsertSim(); // Adding a second profile and mark as embedded. @@ -1163,7 +1150,6 @@ public class SubscriptionControllerTest extends TelephonyTest { @Test @SmallTest - @EnableCompatChanges({REQUIRE_ICC_AUTH_DEVICE_IDENTIFIERS_FOR_GROUP_UUID}) public void testUpdateSubscriptionGroupWithCarrierPrivilegePermission() throws Exception { testInsertSim(); // Adding a second profile and mark as embedded. @@ -1285,7 +1271,6 @@ public class SubscriptionControllerTest extends TelephonyTest { @Test @SmallTest - @EnableCompatChanges({REQUIRE_ICC_AUTH_DEVICE_IDENTIFIERS_FOR_GROUP_UUID}) public void testSetSubscriptionGroup() throws Exception { testInsertSim(); // Adding a second profile and mark as embedded. @@ -1720,81 +1705,42 @@ public class SubscriptionControllerTest extends TelephonyTest { } @Test - @DisableCompatChanges({REQUIRE_ICC_AUTH_DEVICE_IDENTIFIERS_FOR_GROUP_UUID}) - public void testGetSubscriptionsInGroupWithReadPhoneState() throws Exception { - // For backward compatibility test - ParcelUuid groupUuid = setupGetSubscriptionsInGroupTest(); - setupReadPhoneNumbersTest(); - setIdentifierAccess(false); - - List<SubscriptionInfo> subInfoList = mSubscriptionControllerUT.getSubscriptionsInGroup( - groupUuid, mCallingPackage, mCallingFeature); - - assertTrue(subInfoList.size() > 0); - for (SubscriptionInfo info : subInfoList) { - assertEquals(UNAVAILABLE_ICCID, info.getIccId()); - assertEquals(UNAVAILABLE_ICCID, info.getCardString()); - assertEquals(UNAVAILABLE_NUMBER, info.getNumber()); - } - } - - @Test - @EnableCompatChanges({REQUIRE_ICC_AUTH_DEVICE_IDENTIFIERS_FOR_GROUP_UUID}) - public void testGetSubscriptionsInGroupWithoutAppropriatePermission() throws Exception { + public void testGetSubscriptionsInGroupWithNoPermission() throws Exception { + // If the calling package does not have the READ_PHONE_STATE permission or carrier + // privileges then getSubscriptionsInGroup should throw a SecurityException when the + // READ_PHONE_STATE permission check is performed. ParcelUuid groupUuid = setupGetSubscriptionsInGroupTest(); + mContextFixture.removeCallingOrSelfPermission(ContextFixture.PERMISSION_ENABLE_ALL); - // no permission - setNoPermission(); try { mSubscriptionControllerUT.getSubscriptionsInGroup(groupUuid, mCallingPackage, mCallingFeature); fail("getSubscriptionsInGroup should fail when invoked with no permissions"); } catch (SecurityException expected) { } - - // only has the USE_ICC_AUTH_WITH_DEVICE_IDENTIFIER permission - setIdentifierAccess(true); - try { - mSubscriptionControllerUT.getSubscriptionsInGroup(groupUuid, mCallingPackage, - mCallingFeature); - fail("getSubscriptionsInGroup should fail when invoked with no" - + "READ_PHONE_STATE permissions"); - } catch (SecurityException expected) { - } - - // only has the READ_PHONE_STATE permission - setIdentifierAccess(false); - setReadPhoneState(); - try { - mSubscriptionControllerUT.getSubscriptionsInGroup(groupUuid, mCallingPackage, - mCallingFeature); - fail("getSubscriptionsInGroup should fail when invoked with no " - + "USE_ICC_AUTH_WITH_DEVICE_IDENTIFIER permissions"); - } catch (SecurityException expected) { - } } @Test - @EnableCompatChanges({REQUIRE_ICC_AUTH_DEVICE_IDENTIFIERS_FOR_GROUP_UUID}) - public void testGetSubscriptionsInGroupWithReadDeviceIdentifier() throws Exception { + public void testGetSubscriptionsInGroupWithReadPhoneState() throws Exception { + // If the calling package only has the READ_PHONE_STATE permission then + // getSubscriptionsInGroup should still return the list of SubscriptionInfo objects + // but the ICC ID should not be available via getIccId or getCardString. ParcelUuid groupUuid = setupGetSubscriptionsInGroupTest(); - setNoPermission(); - setCarrierPrivileges(false); - setIdentifierAccess(true); - setReadPhoneState(); + setupReadPhoneNumbersTest(); + setIdentifierAccess(false); List<SubscriptionInfo> subInfoList = mSubscriptionControllerUT.getSubscriptionsInGroup( groupUuid, mCallingPackage, mCallingFeature); assertTrue(subInfoList.size() > 0); for (SubscriptionInfo info : subInfoList) { - assertTrue(info.getIccId().length() > 0); - assertTrue(info.getCardString().length() > 0); + assertEquals(UNAVAILABLE_ICCID, info.getIccId()); + assertEquals(UNAVAILABLE_ICCID, info.getCardString()); + assertEquals(UNAVAILABLE_NUMBER, info.getNumber()); } } @Test - @EnableCompatChanges({REQUIRE_ICC_AUTH_DEVICE_IDENTIFIERS_FOR_GROUP_UUID}) public void testGetSubscriptionInGroupWithPhoneNumberAccess() throws Exception { // If the calling package meets any of the requirements for the // LegacyPermissionManager#checkPhoneNumberAccess test then the number should be available @@ -1812,7 +1758,6 @@ public class SubscriptionControllerTest extends TelephonyTest { } @Test - @EnableCompatChanges({REQUIRE_ICC_AUTH_DEVICE_IDENTIFIERS_FOR_GROUP_UUID}) public void testGetSubscriptionsInGroupWithCarrierPrivileges() throws Exception { // If the calling package has the READ_PRIVILEGED_PHONE_STATE permission or carrier // privileges the ICC ID should be available in the SubscriptionInfo objects in the List. @@ -1830,7 +1775,6 @@ public class SubscriptionControllerTest extends TelephonyTest { } @Test - @EnableCompatChanges({REQUIRE_ICC_AUTH_DEVICE_IDENTIFIERS_FOR_GROUP_UUID}) public void testGetSubscriptionsInGroupWithPrivilegedPermission() throws Exception { // If the calling package has the READ_PRIVILEGED_PHONE_STATE permission or carrier // privileges the ICC ID should be available in the SubscriptionInfo objects in the List. @@ -2110,14 +2054,4 @@ public class SubscriptionControllerTest extends TelephonyTest { assertTrue(mSubscriptionControllerUT.checkPhoneIdAndIccIdMatch(0, "test2")); assertFalse(mSubscriptionControllerUT.checkPhoneIdAndIccIdMatch(0, "test3")); } - - private void setNoPermission() { - doThrow(new SecurityException()).when(mContext) - .enforcePermission(anyString(), anyInt(), anyInt(), anyString()); - } - - private void setReadPhoneState() { - doNothing().when(mContext).enforcePermission( - eq(android.Manifest.permission.READ_PHONE_STATE), anyInt(), anyInt(), anyString()); - } } diff --git a/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkControllerTest.java index e05ec09f40..52b487af00 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkControllerTest.java @@ -2706,6 +2706,25 @@ public class DataNetworkControllerTest extends TelephonyTest { } @Test + public void testEmergencyCallDataDisabled() throws Exception { + doReturn(true).when(mPhone).isInEmergencyCall(); + mDataNetworkControllerUT.addNetworkRequest( + createNetworkRequest(NetworkCapabilities.NET_CAPABILITY_INTERNET)); + processAllMessages(); + + verifyInternetConnected(); + + // Data disabled + mDataNetworkControllerUT.getDataSettingsManager().setDataEnabled( + TelephonyManager.DATA_ENABLED_REASON_USER, false, mContext.getOpPackageName()); + processAllMessages(); + + // Make sure internet is not connected. (Previously it has a bug due to incorrect logic + // to determine it's for emergency SUPL). + verifyAllDataDisconnected(); + } + + @Test public void testDataActivity() { doReturn(TelephonyManager.DATA_ACTIVITY_IN).when(mLinkBandwidthEstimator).getDataActivity(); mLinkBandwidthEstimatorCallback.onDataActivityChanged(TelephonyManager.DATA_ACTIVITY_IN); @@ -2880,7 +2899,7 @@ public class DataNetworkControllerTest extends TelephonyTest { createNetworkRequest(NetworkCapabilities.NET_CAPABILITY_IMS)); processAllMessages(); - // Even though the network request deos not have MMTEL, but the network support it, so + // Even though the network request does not have MMTEL, but the network support it, so // the network capabilities should still have MMTEL. verifyConnectedNetworkHasCapabilities(NetworkCapabilities.NET_CAPABILITY_IMS, NetworkCapabilities.NET_CAPABILITY_MMTEL); @@ -2894,12 +2913,138 @@ public class DataNetworkControllerTest extends TelephonyTest { any(DataProfile.class), anyBoolean(), anyBoolean(), anyInt(), any(), anyInt(), any(), any(), anyBoolean(), any(Message.class)); - // The IMS network should only have IMS, but no MMTEL. + // The IMS network should still have IMS and MMTEL. verifyConnectedNetworkHasCapabilities(NetworkCapabilities.NET_CAPABILITY_IMS); + verifyConnectedNetworkHasCapabilities(NetworkCapabilities.NET_CAPABILITY_MMTEL); + } + + @Test + public void testMmtelImsDataNetworkMovingToNonVops() throws Exception { + ServiceState ss = new ServiceState(); + + // VoPS network + DataSpecificRegistrationInfo dsri = new DataSpecificRegistrationInfo(8, false, true, true, + new LteVopsSupportInfo(LteVopsSupportInfo.LTE_STATUS_SUPPORTED, + LteVopsSupportInfo.LTE_STATUS_SUPPORTED)); + + ss.addNetworkRegistrationInfo(new NetworkRegistrationInfo.Builder() + .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN) + .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_LTE) + .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME) + .setDomain(NetworkRegistrationInfo.DOMAIN_PS) + .setDataSpecificInfo(dsri) + .build()); + + ss.addNetworkRegistrationInfo(new NetworkRegistrationInfo.Builder() + .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WLAN) + .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_IWLAN) + .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME) + .setDomain(NetworkRegistrationInfo.DOMAIN_PS) + .build()); + + ss.addNetworkRegistrationInfo(new NetworkRegistrationInfo.Builder() + .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN) + .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_LTE) + .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME) + .setDomain(NetworkRegistrationInfo.DOMAIN_CS) + .build()); + doReturn(ss).when(mSST).getServiceState(); + doReturn(ss).when(mPhone).getServiceState(); + + doReturn(AccessNetworkConstants.TRANSPORT_TYPE_WWAN).when(mAccessNetworksManager) + .getPreferredTransportByNetworkCapability(NetworkCapabilities.NET_CAPABILITY_IMS); + + mDataNetworkControllerUT.obtainMessage(17/*EVENT_SERVICE_STATE_CHANGED*/).sendToTarget(); + processAllMessages(); + + // Bring up the IMS network that does require MMTEL + mDataNetworkControllerUT.addNetworkRequest( + createNetworkRequest(NetworkCapabilities.NET_CAPABILITY_IMS, + NetworkCapabilities.NET_CAPABILITY_MMTEL)); + processAllMessages(); + + // the network capabilities should have IMS and MMTEL. + verifyConnectedNetworkHasCapabilities(NetworkCapabilities.NET_CAPABILITY_IMS, + NetworkCapabilities.NET_CAPABILITY_MMTEL); + + ss = new ServiceState(); + // Non VoPS network + dsri = new DataSpecificRegistrationInfo(8, false, true, true, + new LteVopsSupportInfo(LteVopsSupportInfo.LTE_STATUS_NOT_SUPPORTED, + LteVopsSupportInfo.LTE_STATUS_NOT_SUPPORTED)); + + ss.addNetworkRegistrationInfo(new NetworkRegistrationInfo.Builder() + .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN) + .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_LTE) + .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME) + .setDomain(NetworkRegistrationInfo.DOMAIN_PS) + .setDataSpecificInfo(dsri) + .build()); + + ss.addNetworkRegistrationInfo(new NetworkRegistrationInfo.Builder() + .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WLAN) + .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_IWLAN) + .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME) + .setDomain(NetworkRegistrationInfo.DOMAIN_PS) + .build()); + + ss.addNetworkRegistrationInfo(new NetworkRegistrationInfo.Builder() + .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN) + .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_LTE) + .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME) + .setDomain(NetworkRegistrationInfo.DOMAIN_CS) + .build()); + doReturn(ss).when(mSST).getServiceState(); + doReturn(ss).when(mPhone).getServiceState(); + + mDataNetworkControllerUT.obtainMessage(17/*EVENT_SERVICE_STATE_CHANGED*/).sendToTarget(); + processAllMessages(); + + // The IMS network should be torn down by data network controller. + verifyNoConnectedNetworkHasCapability(NetworkCapabilities.NET_CAPABILITY_IMS); verifyNoConnectedNetworkHasCapability(NetworkCapabilities.NET_CAPABILITY_MMTEL); } @Test + public void testVoPStoNonVoPSDelayImsTearDown() throws Exception { + mCarrierConfig.putBoolean(CarrierConfigManager.KEY_DELAY_IMS_TEAR_DOWN_UNTIL_CALL_END_BOOL, + true); + carrierConfigChanged(); + + // VoPS supported + DataSpecificRegistrationInfo dsri = new DataSpecificRegistrationInfo(8, false, true, true, + new LteVopsSupportInfo(LteVopsSupportInfo.LTE_STATUS_SUPPORTED, + LteVopsSupportInfo.LTE_STATUS_SUPPORTED)); + serviceStateChanged(TelephonyManager.NETWORK_TYPE_LTE, + NetworkRegistrationInfo.REGISTRATION_STATE_HOME, dsri); + + mDataNetworkControllerUT.addNetworkRequest( + createNetworkRequest(NetworkCapabilities.NET_CAPABILITY_IMS, + NetworkCapabilities.NET_CAPABILITY_MMTEL)); + processAllMessages(); + verifyConnectedNetworkHasCapabilities(NetworkCapabilities.NET_CAPABILITY_IMS); + + doReturn(PhoneConstants.State.OFFHOOK).when(mCT).getState(); + + dsri = new DataSpecificRegistrationInfo(8, false, true, true, + new LteVopsSupportInfo(LteVopsSupportInfo.LTE_STATUS_NOT_SUPPORTED, + LteVopsSupportInfo.LTE_STATUS_NOT_SUPPORTED)); + serviceStateChanged(TelephonyManager.NETWORK_TYPE_LTE, + NetworkRegistrationInfo.REGISTRATION_STATE_HOME, dsri); + + // Make sure IMS is still connected. + verifyConnectedNetworkHasCapabilities(NetworkCapabilities.NET_CAPABILITY_IMS, + NetworkCapabilities.NET_CAPABILITY_MMTEL); + + // Call ends + doReturn(PhoneConstants.State.IDLE).when(mCT).getState(); + mDataNetworkControllerUT.obtainMessage(18/*EVENT_VOICE_CALL_ENDED*/).sendToTarget(); + processAllMessages(); + + verifyNoConnectedNetworkHasCapability(NetworkCapabilities.NET_CAPABILITY_IMS); + } + + @Test public void testDeactivateDataOnOldHal() throws Exception { doAnswer(invocation -> { // Only send the deactivation data response, no data call list changed event. @@ -2957,4 +3102,48 @@ public class DataNetworkControllerTest extends TelephonyTest { verifyConnectedNetworkHasCapabilities(NetworkCapabilities.NET_CAPABILITY_IMS, NetworkCapabilities.NET_CAPABILITY_MMTEL); } + + @Test + public void testRemoveNetworkRequest() throws Exception { + NetworkCapabilities netCaps = new NetworkCapabilities(); + netCaps.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); + + NetworkRequest nativeNetworkRequest = new NetworkRequest(netCaps, + ConnectivityManager.TYPE_MOBILE, 0, NetworkRequest.Type.REQUEST); + + mDataNetworkControllerUT.addNetworkRequest(new TelephonyNetworkRequest( + nativeNetworkRequest, mPhone)); + processAllMessages(); + + // Intentionally create a new telephony request with the original native network request. + TelephonyNetworkRequest request = new TelephonyNetworkRequest(nativeNetworkRequest, mPhone); + + mDataNetworkControllerUT.removeNetworkRequest(request); + processAllFutureMessages(); + + List<DataNetwork> dataNetworkList = getDataNetworks(); + // The data network should not be torn down after network request removal. + assertThat(dataNetworkList).hasSize(1); + // But should be detached from the data network. + assertThat(dataNetworkList.get(0).getAttachedNetworkRequestList()).isEmpty(); + assertThat(dataNetworkList.get(0).isConnected()).isTrue(); + } + + @Test + public void testTempDdsSwitchTearDown() throws Exception { + TelephonyNetworkRequest request = createNetworkRequest( + NetworkCapabilities.NET_CAPABILITY_INTERNET); + mDataNetworkControllerUT.addNetworkRequest(request); + processAllMessages(); + + // Now DDS temporarily switched to phone 1 + doReturn(1).when(mMockedPhoneSwitcher).getPreferredDataPhoneId(); + + // Simulate telephony network factory remove request due to switch. + mDataNetworkControllerUT.removeNetworkRequest(request); + processAllMessages(); + + // Data should be torn down on this non-preferred sub. + verifyAllDataDisconnected(); + } } diff --git a/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkTest.java b/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkTest.java index 6ae8f66e87..f53298d770 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkTest.java @@ -102,6 +102,8 @@ public class DataNetworkTest extends TelephonyTest { private static final int ADMIN_UID1 = 1234; private static final int ADMIN_UID2 = 5678; + private static final int DEFAULT_MTU = 1501; + private static final String FAKE_IMSI = "123456789"; private DataNetwork mDataNetworkUT; @@ -181,6 +183,7 @@ public class DataNetworkTest extends TelephonyTest { // Mocked classes private DataNetworkCallback mDataNetworkCallback; private DataCallSessionStats mDataCallSessionStats; + private PhoneSwitcher mMockedPhoneSwitcher; private final NetworkRegistrationInfo mIwlanNetworkRegistrationInfo = new NetworkRegistrationInfo.Builder() @@ -217,7 +220,6 @@ public class DataNetworkTest extends TelephonyTest { InetAddresses.parseNumericAddress("fd00:976a:c202:1d::7"), InetAddresses.parseNumericAddress("fd00:976a:c305:1d::5"))) .setMtuV4(1234) - .setMtuV6(5678) .setPduSessionId(1) .setQosBearerSessions(new ArrayList<>()) .setTrafficDescriptors(tds) @@ -300,6 +302,8 @@ public class DataNetworkTest extends TelephonyTest { mDataNetworkCallback = Mockito.mock(DataNetworkCallback.class); mDataCallSessionStats = Mockito.mock(DataCallSessionStats.class); + mMockedPhoneSwitcher = Mockito.mock(PhoneSwitcher.class); + replaceInstance(PhoneSwitcher.class, "sPhoneSwitcher", null, mMockedPhoneSwitcher); doAnswer(invocation -> { ((Runnable) invocation.getArguments()[0]).run(); return null; @@ -315,6 +319,7 @@ public class DataNetworkTest extends TelephonyTest { .when(mDataConfigManager).getBandwidthEstimateSource(); doReturn(true).when(mDataConfigManager).isTempNotMeteredSupportedByCarrier(); doReturn(true).when(mDataConfigManager).isImsDelayTearDownEnabled(); + doReturn(DEFAULT_MTU).when(mDataConfigManager).getDefaultMtu(); doReturn(FAKE_IMSI).when(mPhone).getSubscriberId(); doReturn(true).when(mDataNetworkController) .isNetworkRequestExisting(any(TelephonyNetworkRequest.class)); @@ -399,9 +404,10 @@ public class DataNetworkTest extends TelephonyTest { assertThat(lp.getRoutes().get(0).getMtu()).isEqualTo(1234); assertThat(lp.getRoutes().get(1).getGateway()).isEqualTo( InetAddresses.parseNumericAddress("fe80::2")); - assertThat(lp.getRoutes().get(1).getMtu()).isEqualTo(5678); + // The default from carrier configs should be used if MTU is not set. + assertThat(lp.getRoutes().get(1).getMtu()).isEqualTo(DEFAULT_MTU); // The higher value of v4 and v6 should be used. - assertThat(lp.getMtu()).isEqualTo(5678); + assertThat(lp.getMtu()).isEqualTo(DEFAULT_MTU); ArgumentCaptor<PreciseDataConnectionState> pdcsCaptor = ArgumentCaptor.forClass(PreciseDataConnectionState.class); @@ -1213,46 +1219,11 @@ public class DataNetworkTest extends TelephonyTest { logd("Trigger non VoPS"); serviceStateChanged(TelephonyManager.NETWORK_TYPE_LTE, NetworkRegistrationInfo.REGISTRATION_STATE_HOME, dsri); - assertThat(mDataNetworkUT.getNetworkCapabilities().hasCapability( - NetworkCapabilities.NET_CAPABILITY_MMTEL)).isFalse(); - } - - @Test - public void testMovingToNonVopsVoiceCallOngoing() throws Exception { - DataSpecificRegistrationInfo dsri = new DataSpecificRegistrationInfo(8, false, true, true, - new LteVopsSupportInfo(LteVopsSupportInfo.LTE_STATUS_SUPPORTED, - LteVopsSupportInfo.LTE_STATUS_SUPPORTED)); - serviceStateChanged(TelephonyManager.NETWORK_TYPE_LTE, - NetworkRegistrationInfo.REGISTRATION_STATE_HOME, dsri); - testCreateImsDataNetwork(); - + // MMTEL should not be removed. assertThat(mDataNetworkUT.getNetworkCapabilities().hasCapability( NetworkCapabilities.NET_CAPABILITY_MMTEL)).isTrue(); - - // Voice call ongoing. - doReturn(PhoneConstants.State.OFFHOOK).when(mImsCT).getState(); - - dsri = new DataSpecificRegistrationInfo(8, false, true, true, - new LteVopsSupportInfo(LteVopsSupportInfo.LTE_STATUS_NOT_SUPPORTED, - LteVopsSupportInfo.LTE_STATUS_NOT_SUPPORTED)); - serviceStateChanged(TelephonyManager.NETWORK_TYPE_LTE, - NetworkRegistrationInfo.REGISTRATION_STATE_HOME, dsri); - - // Should not lose MMTEL since voice call is ongoing - assertThat(mDataNetworkUT.getNetworkCapabilities().hasCapability( - NetworkCapabilities.NET_CAPABILITY_MMTEL)).isTrue(); - - // Voice call ended. - doReturn(PhoneConstants.State.IDLE).when(mImsCT).getState(); - mDataNetworkUT.sendMessage(23/*EVENT_VOICE_CALL_ENDED*/); - processAllMessages(); - - // MMTEL should be removed. - assertThat(mDataNetworkUT.getNetworkCapabilities().hasCapability( - NetworkCapabilities.NET_CAPABILITY_MMTEL)).isFalse(); } - @Test public void testCssIndicatorChanged() throws Exception { setupDataNetwork(); diff --git a/tests/telephonytests/src/com/android/internal/telephony/data/DataProfileManagerTest.java b/tests/telephonytests/src/com/android/internal/telephony/data/DataProfileManagerTest.java index c96d76dcc7..783df82e39 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/DataProfileManagerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/DataProfileManagerTest.java @@ -59,11 +59,13 @@ import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import org.mockito.Mockito; +import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Objects; +import java.util.stream.Collectors; @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper @@ -361,6 +363,16 @@ public class DataProfileManagerTest extends TelephonyTest { logd("ApnSettingContentProvider: uri=" + uri + ", values=" + values); if (uri.isPathPrefixMatch(Telephony.Carriers.PREFERRED_APN_URI)) { mPreferredApnId = values.getAsInteger(Telephony.Carriers.APN_ID); + if (mPreferredApnId != -1) { + for (Object apnSetting : mAllApnSettings) { + int id = (int) ((Object[]) apnSetting)[0]; + if (id == mPreferredApnId) { + mPreferredApnSet = (int) ((Object[]) apnSetting)[28]; //update setId too + } + } + } else { + mPreferredApnSet = 0; // db is emptied + } logd("mPreferredApnId=" + mPreferredApnId); } return null; @@ -400,6 +412,12 @@ public class DataProfileManagerTest extends TelephonyTest { method.invoke(mDataProfileManagerUT, dataProfiles); } + private @NonNull List<DataProfile> getAllDataProfiles() throws Exception { + Field field = DataProfileManager.class.getDeclaredField("mAllDataProfiles"); + field.setAccessible(true); + return (List<DataProfile>) field.get(mDataProfileManagerUT); + } + @Before public void setUp() throws Exception { logd("DataProfileManagerTest +Setup!"); @@ -856,6 +874,38 @@ public class DataProfileManagerTest extends TelephonyTest { } @Test + public void testResetApnWithPreferredConfig() { + // carrier configured preferred data profile should be picked + doReturn(GENERAL_PURPOSE_APN1).when(mDataConfigManager).getDefaultPreferredApn(); + TelephonyNetworkRequest tnr = new TelephonyNetworkRequest( + new NetworkRequest.Builder() + .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) + .build(), mPhone); + mSimInserted = true; + mDataProfileManagerUT.obtainMessage(2 /*EVENT_APN_DATABASE_CHANGED*/).sendToTarget(); + processAllMessages(); + + // The carrier configured data profile should be the preferred APN after APN reset + DataProfile dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest( + tnr, TelephonyManager.NETWORK_TYPE_LTE); + + assertThat(dataProfile.getApnSetting().getApnName()).isEqualTo(GENERAL_PURPOSE_APN1); + assertThat(mDataProfileManagerUT.isDataProfilePreferred(dataProfile)).isTrue(); + + // APN reset + mPreferredApnId = -1; + mDataProfileManagerUT.obtainMessage(2 /*EVENT_APN_DATABASE_CHANGED*/).sendToTarget(); + Mockito.clearInvocations(mDataConfigManager); + processAllMessages(); + + // The carrier configured data profile should be the preferred APN after APN reset + dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest( + tnr, TelephonyManager.NETWORK_TYPE_LTE); + assertThat(dataProfile.getApnSetting().getApnName()).isEqualTo(GENERAL_PURPOSE_APN1); + assertThat(mDataProfileManagerUT.isDataProfilePreferred(dataProfile)).isTrue(); + } + + @Test public void testTetheringApnExisting() { assertThat(mDataProfileManagerUT.isTetheringDataProfileExisting( TelephonyManager.NETWORK_TYPE_NR)).isTrue(); @@ -886,4 +936,15 @@ public class DataProfileManagerTest extends TelephonyTest { assertThat(mDataProfileManagerUT.isTetheringDataProfileExisting( TelephonyManager.NETWORK_TYPE_NR)).isFalse(); } + + @Test + public void testNoDefaultIms() throws Exception { + List<DataProfile> dataProfiles = getAllDataProfiles(); + + // Since the database already had IMS, there should not be default IMS created in the + // database. + assertThat(dataProfiles.stream() + .filter(dp -> dp.canSatisfy(NetworkCapabilities.NET_CAPABILITY_IMS)) + .collect(Collectors.toList())).hasSize(1); + } } diff --git a/tests/telephonytests/src/com/android/internal/telephony/data/DataProfileTest.java b/tests/telephonytests/src/com/android/internal/telephony/data/DataProfileTest.java index 86f8f907ff..4a2eb38702 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/DataProfileTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/DataProfileTest.java @@ -22,6 +22,7 @@ import android.net.NetworkCapabilities; import android.os.Parcel; import android.telephony.data.ApnSetting; import android.telephony.data.DataProfile; +import android.telephony.data.TrafficDescriptor; import org.junit.Test; @@ -99,6 +100,26 @@ public class DataProfileTest { .setMaxConnsTime(789) .build(); + // Disabled APN + private ApnSetting mApn5 = new ApnSetting.Builder() + .setId(2163) + .setOperatorNumeric("12345") + .setEntryName("fake_apn") + .setApnName("fake_apn") + .setUser("user") + .setPassword("passwd") + .setApnTypeBitmask(ApnSetting.TYPE_DEFAULT | ApnSetting.TYPE_SUPL) + .setProtocol(ApnSetting.PROTOCOL_IPV6) + .setRoamingProtocol(ApnSetting.PROTOCOL_IP) + .setCarrierEnabled(false) + .setNetworkTypeBitmask(0) + .setProfileId(1234) + .setMaxConns(321) + .setWaitTime(456) + .setMaxConnsTime(789) + .build(); + + @Test public void testCreateFromApnSetting() throws Exception { DataProfile dp = new DataProfile.Builder() @@ -196,4 +217,26 @@ public class DataProfileTest { parcel.recycle(); } + + @Test + public void testIsEnabled() { + TrafficDescriptor td = new TrafficDescriptor(null, new TrafficDescriptor.OsAppId( + TrafficDescriptor.OsAppId.ANDROID_OS_ID, "ENTERPRISE", 1).getBytes()); + + DataProfile dp = new DataProfile.Builder() + .setApnSetting(mApn5) + .setPreferred(false) + .build(); + assertThat(dp.isEnabled()).isFalse(); + + dp = new DataProfile.Builder() + .setApnSetting(mApn1) + .build(); + assertThat(dp.isEnabled()).isTrue(); + + dp = new DataProfile.Builder() + .setTrafficDescriptor(td) + .build(); + assertThat(dp.isEnabled()).isTrue(); + } } |