Loading src/java/com/android/internal/telephony/PhoneFactory.java +1 −7 Original line number Diff line number Diff line Loading @@ -29,7 +29,6 @@ import android.content.SharedPreferences; import android.content.pm.PackageManager; import android.net.LocalServerSocket; import android.os.Looper; import android.os.ServiceManager; import android.preference.PreferenceManager; import android.provider.Settings; import android.provider.Settings.SettingNotFoundException; Loading Loading @@ -235,9 +234,6 @@ public class PhoneFactory { Rlog.i(LOG_TAG, "IMS is not supported on this device, skipping ImsResolver."); } ITelephonyRegistry tr = ITelephonyRegistry.Stub.asInterface( ServiceManager.getService("telephony.registry")); sPhoneConfigurationManager = PhoneConfigurationManager.init(sContext); sCellularNetworkValidator = CellularNetworkValidator.make(sContext); Loading @@ -245,9 +241,7 @@ public class PhoneFactory { int maxActivePhones = sPhoneConfigurationManager .getNumberOfModemsWithSimultaneousDataConnections(); sPhoneSwitcher = PhoneSwitcher.make(maxActivePhones, numPhones, sContext, sc, Looper.myLooper(), tr, sCommandsInterfaces, sPhones); sPhoneSwitcher = PhoneSwitcher.make(maxActivePhones, sContext, Looper.myLooper()); sProxyController = ProxyController.getInstance(context); Loading src/java/com/android/internal/telephony/PhoneSwitcher.java +105 −97 Original line number Diff line number Diff line Loading @@ -25,6 +25,8 @@ import static android.telephony.TelephonyManager.SET_OPPORTUNISTIC_SUB_INACTIVE_ import static android.telephony.TelephonyManager.SET_OPPORTUNISTIC_SUB_SUCCESS; import static android.telephony.TelephonyManager.SET_OPPORTUNISTIC_SUB_VALIDATION_FAILED; import static java.util.Arrays.copyOf; import android.annotation.UnsupportedAppUsage; import android.content.BroadcastReceiver; import android.content.Context; Loading @@ -46,7 +48,6 @@ import android.os.PersistableBundle; import android.os.Registrant; import android.os.RegistrantList; import android.os.RemoteException; import android.os.ServiceManager; import android.telephony.CarrierConfigManager; import android.telephony.PhoneCapability; import android.telephony.PhoneStateListener; Loading @@ -65,7 +66,6 @@ import com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent.DataSwi import com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent.OnDemandDataSwitch; import com.android.internal.util.IndentingPrintWriter; import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; Loading Loading @@ -156,15 +156,10 @@ public class PhoneSwitcher extends Handler { private final List<DcRequest> mPrioritizedDcRequests = new ArrayList<DcRequest>(); private final RegistrantList mActivePhoneRegistrants; private final SubscriptionController mSubscriptionController; private final int[] mPhoneSubscriptions; private final CommandsInterface[] mCommandsInterfaces; private final Context mContext; private final PhoneState[] mPhoneStates; @UnsupportedAppUsage private final int mNumPhones; @UnsupportedAppUsage private final Phone[] mPhones; private final LocalLog mLocalLog; private PhoneState[] mPhoneStates; private int[] mPhoneSubscriptions; @VisibleForTesting public final PhoneStateListener mPhoneStateListener; private final CellularNetworkValidator mValidator; Loading @@ -172,8 +167,14 @@ public class PhoneSwitcher extends Handler { public final CellularNetworkValidator.ValidationCallback mValidationCallback = (validated, subId) -> Message.obtain(PhoneSwitcher.this, EVENT_NETWORK_VALIDATION_DONE, subId, validated ? 1 : 0).sendToTarget(); @UnsupportedAppUsage private int mMaxActivePhones; // How many phones (correspondingly logical modems) are allowed for PS attach. This is used // when we specifically use setDataAllowed to initiate on-demand PS(data) attach for each phone. private int mMaxDataAttachModemCount; // Local cache of TelephonyManager#getActiveModemCount(). 1 if in single SIM mode, 2 if in dual // SIM mode. private int mActiveModemCount; private static PhoneSwitcher sPhoneSwitcher = null; // Which primary (non-opportunistic) subscription is set as data subscription among all primary Loading Loading @@ -239,6 +240,9 @@ public class PhoneSwitcher extends Handler { private static final int EVENT_OVERRIDE_DDS_FOR_EMERGENCY = 115; // If it exists, remove the current mEmergencyOverride DDS override. private static final int EVENT_REMOVE_DDS_EMERGENCY_OVERRIDE = 116; // If it exists, remove the current mEmergencyOverride DDS override. @VisibleForTesting public static final int EVENT_MULTI_SIM_CONFIG_CHANGED = 117; // Depending on version of IRadioConfig, we need to send either RIL_REQUEST_ALLOW_DATA if it's // 1.0, or RIL_REQUEST_SET_PREFERRED_DATA if it's 1.1 or later. So internally mHalCommandToUse Loading Loading @@ -290,47 +294,21 @@ public class PhoneSwitcher extends Handler { /** * Method to create singleton instance. */ public static PhoneSwitcher make(int maxActivePhones, int numPhones, Context context, SubscriptionController subscriptionController, Looper looper, ITelephonyRegistry tr, CommandsInterface[] cis, Phone[] phones) { public static PhoneSwitcher make(int maxDataAttachModemCount, Context context, Looper looper) { if (sPhoneSwitcher == null) { sPhoneSwitcher = new PhoneSwitcher(maxActivePhones, numPhones, context, subscriptionController, looper, cis, phones); sPhoneSwitcher = new PhoneSwitcher(maxDataAttachModemCount, context, looper); } return sPhoneSwitcher; } /** This constructor is only used for testing purpose. */ @VisibleForTesting public PhoneSwitcher(int numPhones, Looper looper) { super(looper); mMaxActivePhones = 0; mSubscriptionController = null; mCommandsInterfaces = null; mContext = null; mPhoneStates = null; mPhones = null; mLocalLog = null; mActivePhoneRegistrants = null; mNumPhones = numPhones; mPhoneSubscriptions = new int[numPhones]; mRadioConfig = RadioConfig.getInstance(mContext); mPhoneStateListener = new PhoneStateListener(looper) { public void onPhoneCapabilityChanged(PhoneCapability capability) { onPhoneCapabilityChangedInternal(capability); } }; mValidator = CellularNetworkValidator.getInstance(); } private boolean isPhoneInVoiceCallChanged() { int oldPhoneIdInVoiceCall = mPhoneIdInVoiceCall; // If there's no active call, the value will become INVALID_PHONE_INDEX // and internet data will be switched back to system selected or user selected // subscription. mPhoneIdInVoiceCall = SubscriptionManager.INVALID_PHONE_INDEX; for (Phone phone : mPhones) { for (Phone phone : PhoneFactory.getPhones()) { if (isPhoneInVoiceCall(phone) || isPhoneInVoiceCall(phone.getImsPhone())) { mPhoneIdInVoiceCall = phone.getPhoneId(); break; Loading @@ -347,18 +325,16 @@ public class PhoneSwitcher extends Handler { } @VisibleForTesting public PhoneSwitcher(int maxActivePhones, int numPhones, Context context, SubscriptionController subscriptionController, Looper looper, CommandsInterface[] cis, Phone[] phones) { public PhoneSwitcher(int maxActivePhones, Context context, Looper looper) { super(looper); mContext = context; mNumPhones = numPhones; mPhones = phones; mPhoneSubscriptions = new int[numPhones]; mMaxActivePhones = maxActivePhones; mActiveModemCount = getTm().getActiveModemCount(); mPhoneSubscriptions = new int[mActiveModemCount]; mPhoneStates = new PhoneState[mActiveModemCount]; mMaxDataAttachModemCount = maxActivePhones; mLocalLog = new LocalLog(MAX_LOCAL_LOG_LINES); mSubscriptionController = subscriptionController; mSubscriptionController = SubscriptionController.getInstance(); mRadioConfig = RadioConfig.getInstance(mContext); mPhoneStateListener = new PhoneStateListener(looper) { Loading @@ -371,27 +347,25 @@ public class PhoneSwitcher extends Handler { mValidator = CellularNetworkValidator.getInstance(); mActivePhoneRegistrants = new RegistrantList(); mPhoneStates = new PhoneState[numPhones]; for (int i = 0; i < numPhones; i++) { for (int i = 0; i < mActiveModemCount; i++) { mPhoneStates[i] = new PhoneState(); if (mPhones[i] != null) { mPhones[i].registerForEmergencyCallToggle(this, EVENT_EMERGENCY_TOGGLE, null); if (PhoneFactory.getPhone(i) != null) { PhoneFactory.getPhone(i).registerForEmergencyCallToggle( this, EVENT_EMERGENCY_TOGGLE, null); // TODO (b/135566422): combine register for both GsmCdmaPhone and ImsPhone. mPhones[i].registerForPreciseCallStateChanged( PhoneFactory.getPhone(i).registerForPreciseCallStateChanged( this, EVENT_PRECISE_CALL_STATE_CHANGED, null); if (mPhones[i].getImsPhone() != null) { mPhones[i].getImsPhone().registerForPreciseCallStateChanged( if (PhoneFactory.getPhone(i).getImsPhone() != null) { PhoneFactory.getPhone(i).getImsPhone().registerForPreciseCallStateChanged( this, EVENT_PRECISE_CALL_STATE_CHANGED, null); } mPhones[i].getDataEnabledSettings().registerForDataEnabledChanged( PhoneFactory.getPhone(i).getDataEnabledSettings().registerForDataEnabledChanged( this, EVENT_DATA_ENABLED_CHANGED, null); } } mCommandsInterfaces = cis; if (numPhones > 0) { mCommandsInterfaces[0].registerForAvailable(this, EVENT_RADIO_AVAILABLE, null); if (mActiveModemCount > 0) { PhoneFactory.getPhone(0).mCi.registerForAvailable(this, EVENT_RADIO_AVAILABLE, null); } TelephonyRegistryManager telephonyRegistryManager = (TelephonyRegistryManager) Loading @@ -405,6 +379,9 @@ public class PhoneSwitcher extends Handler { mContext.registerReceiver(mDefaultDataChangedReceiver, new IntentFilter(TelephonyIntents.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED)); PhoneConfigurationManager.registerForMultiSimConfigChange( this, EVENT_MULTI_SIM_CONFIG_CHANGED, null); NetworkCapabilities netCap = new NetworkCapabilities(); netCap.addTransportType(TRANSPORT_CELLULAR); netCap.addCapability(NetworkCapabilities.NET_CAPABILITY_MMS); Loading Loading @@ -620,11 +597,43 @@ public class PhoneSwitcher extends Handler { onEvaluate(REQUESTS_UNCHANGED, "emer_rm_override_dds"); break; } case EVENT_MULTI_SIM_CONFIG_CHANGED: { int activeModemCount = (int) ((AsyncResult) msg.obj).result; onMultiSimConfigChanged(activeModemCount); break; } } } private synchronized void onMultiSimConfigChanged(int activeModemCount) { // No change. if (mActiveModemCount == activeModemCount) return; int oldActiveModemCount = mActiveModemCount; mActiveModemCount = activeModemCount; mPhoneSubscriptions = copyOf(mPhoneSubscriptions, mActiveModemCount); mPhoneStates = copyOf(mPhoneStates, mActiveModemCount); // Single SIM -> dual SIM switch. for (int phoneId = oldActiveModemCount; phoneId < mActiveModemCount; phoneId++) { mPhoneStates[phoneId] = new PhoneState(); Phone phone = PhoneFactory.getPhone(phoneId); if (phone == null) continue; phone.registerForEmergencyCallToggle(this, EVENT_EMERGENCY_TOGGLE, null); // TODO (b/135566422): combine register for both GsmCdmaPhone and ImsPhone. phone.registerForPreciseCallStateChanged(this, EVENT_PRECISE_CALL_STATE_CHANGED, null); if (phone.getImsPhone() != null) { phone.getImsPhone().registerForPreciseCallStateChanged( this, EVENT_PRECISE_CALL_STATE_CHANGED, null); } phone.getDataEnabledSettings().registerForDataEnabledChanged( this, EVENT_DATA_ENABLED_CHANGED, null); } } private boolean isInEmergencyCallbackMode() { for (Phone p : mPhones) { for (Phone p : PhoneFactory.getPhones()) { if (p == null) continue; if (p.isInEcm()) return true; Phone imsPhone = p.getImsPhone(); Loading Loading @@ -699,7 +708,7 @@ public class PhoneSwitcher extends Handler { private void collectRequestNetworkMetrics(NetworkRequest networkRequest) { // Request network for MMS will temporary disable the network on default data subscription, // this only happen on multi-sim device. if (mNumPhones > 1 && networkRequest.networkCapabilities.hasCapability( if (mActiveModemCount > 1 && networkRequest.networkCapabilities.hasCapability( NetworkCapabilities.NET_CAPABILITY_MMS)) { OnDemandDataSwitch onDemandDataSwitch = new OnDemandDataSwitch(); onDemandDataSwitch.apn = TelephonyEvent.ApnType.APN_TYPE_MMS; Loading @@ -711,7 +720,7 @@ public class PhoneSwitcher extends Handler { private void collectReleaseNetworkMetrics(NetworkRequest networkRequest) { // Release network for MMS will recover the network on default data subscription, this only // happen on multi-sim device. if (mNumPhones > 1 && networkRequest.networkCapabilities.hasCapability( if (mActiveModemCount > 1 && networkRequest.networkCapabilities.hasCapability( NetworkCapabilities.NET_CAPABILITY_MMS)) { OnDemandDataSwitch onDemandDataSwitch = new OnDemandDataSwitch(); onDemandDataSwitch.apn = TelephonyEvent.ApnType.APN_TYPE_MMS; Loading @@ -720,6 +729,10 @@ public class PhoneSwitcher extends Handler { } } private TelephonyManager getTm() { return (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE); } private static final boolean REQUESTS_CHANGED = true; private static final boolean REQUESTS_UNCHANGED = false; /** Loading Loading @@ -749,7 +762,7 @@ public class PhoneSwitcher extends Handler { boolean hasAnyActiveSubscription = false; // Check if phoneId to subId mapping is changed. for (int i = 0; i < mNumPhones; i++) { for (int i = 0; i < mActiveModemCount; i++) { int sub = mSubscriptionController.getSubIdUsingPhoneId(i); if (SubscriptionManager.isValidSubscriptionId(sub)) hasAnyActiveSubscription = true; Loading Loading @@ -790,7 +803,7 @@ public class PhoneSwitcher extends Handler { // With HAL_COMMAND_PREFERRED_DATA, all phones are assumed to allow PS attach. // So marking all phone as active, and the phone with mPreferredDataPhoneId // will send radioConfig command. for (int phoneId = 0; phoneId < mNumPhones; phoneId++) { for (int phoneId = 0; phoneId < mActiveModemCount; phoneId++) { mPhoneStates[phoneId].active = true; } sendRilCommands(mPreferredDataPhoneId); Loading @@ -802,9 +815,9 @@ public class PhoneSwitcher extends Handler { * Otherwise, choose to activate phones according to requests. And * if list is not full, add mPreferredDataPhoneId. */ if (mMaxActivePhones == mPhones.length) { for (int i = 0; i < mMaxActivePhones; i++) { newActivePhones.add(mPhones[i].getPhoneId()); if (mMaxDataAttachModemCount == mActiveModemCount) { for (int i = 0; i < mMaxDataAttachModemCount; i++) { newActivePhones.add(i); } } else { // First try to activate phone in voice call. Loading @@ -812,17 +825,17 @@ public class PhoneSwitcher extends Handler { newActivePhones.add(mPhoneIdInVoiceCall); } if (newActivePhones.size() < mMaxActivePhones) { if (newActivePhones.size() < mMaxDataAttachModemCount) { for (DcRequest dcRequest : mPrioritizedDcRequests) { int phoneIdForRequest = phoneIdForRequest(dcRequest.networkRequest); if (phoneIdForRequest == INVALID_PHONE_INDEX) continue; if (newActivePhones.contains(phoneIdForRequest)) continue; newActivePhones.add(phoneIdForRequest); if (newActivePhones.size() >= mMaxActivePhones) break; if (newActivePhones.size() >= mMaxDataAttachModemCount) break; } } if (newActivePhones.size() < mMaxActivePhones if (newActivePhones.size() < mMaxDataAttachModemCount && newActivePhones.contains(mPreferredDataPhoneId) && SubscriptionManager.isUsableSubIdValue(mPreferredDataPhoneId)) { newActivePhones.add(mPreferredDataPhoneId); Loading @@ -832,14 +845,14 @@ public class PhoneSwitcher extends Handler { if (VDBG) { log("mPrimaryDataSubId = " + mPrimaryDataSubId); log("mOpptDataSubId = " + mOpptDataSubId); for (int i = 0; i < mNumPhones; i++) { for (int i = 0; i < mActiveModemCount; i++) { log(" phone[" + i + "] using sub[" + mPhoneSubscriptions[i] + "]"); } log(" newActivePhones:"); for (Integer i : newActivePhones) log(" " + i); } for (int phoneId = 0; phoneId < mNumPhones; phoneId++) { for (int phoneId = 0; phoneId < mActiveModemCount; phoneId++) { if (!newActivePhones.contains(phoneId)) { deactivate(phoneId); } Loading Loading @@ -888,7 +901,7 @@ public class PhoneSwitcher extends Handler { * want to resend setDataAllowed or setPreferredDataSubscriptionId */ public void onRadioCapChanged(int phoneId) { validatePhoneId(phoneId); if (!SubscriptionManager.isValidPhoneId(phoneId)) return; Message msg = obtainMessage(EVENT_RADIO_CAPABILITY_CHANGED); msg.arg1 = phoneId; msg.sendToTarget(); Loading @@ -913,7 +926,7 @@ public class PhoneSwitcher extends Handler { */ public void overrideDefaultDataForEmergency(int phoneId, int overrideTimeSec, CompletableFuture<Boolean> dataSwitchResult) { validatePhoneId(phoneId); if (!SubscriptionManager.isValidPhoneId(phoneId)) return; Message msg = obtainMessage(EVENT_OVERRIDE_DDS_FOR_EMERGENCY); EmergencyOverrideRequest request = new EmergencyOverrideRequest(); request.mPhoneId = phoneId; Loading @@ -924,13 +937,13 @@ public class PhoneSwitcher extends Handler { } private void sendRilCommands(int phoneId) { if (!SubscriptionManager.isValidPhoneId(phoneId) || phoneId >= mNumPhones) return; if (!SubscriptionManager.isValidPhoneId(phoneId)) return; Message message = Message.obtain(this, EVENT_MODEM_COMMAND_DONE, phoneId); if (mHalCommandToUse == HAL_COMMAND_ALLOW_DATA || mHalCommandToUse == HAL_COMMAND_UNKNOWN) { // Skip ALLOW_DATA for single SIM device if (mNumPhones > 1) { mCommandsInterfaces[phoneId].setDataAllowed(isPhoneActive(phoneId), message); if (mActiveModemCount > 1) { PhoneFactory.getPhone(phoneId).mCi.setDataAllowed(isPhoneActive(phoneId), message); } } else if (phoneId == mPreferredDataPhoneId) { // Only setPreferredDataModem if the phoneId equals to current mPreferredDataPhoneId. Loading @@ -939,11 +952,11 @@ public class PhoneSwitcher extends Handler { } private void onPhoneCapabilityChangedInternal(PhoneCapability capability) { int newMaxActivePhones = TelephonyManager.getDefault() int newMaxDataAttachModemCount = TelephonyManager.getDefault() .getNumberOfModemsWithSimultaneousDataConnections(); if (mMaxActivePhones != newMaxActivePhones) { mMaxActivePhones = newMaxActivePhones; log("Max active phones changed to " + mMaxActivePhones); if (mMaxDataAttachModemCount != newMaxDataAttachModemCount) { mMaxDataAttachModemCount = newMaxDataAttachModemCount; log("Max active phones changed to " + mMaxDataAttachModemCount); onEvaluate(REQUESTS_UNCHANGED, "phoneCfgChanged"); } } Loading @@ -955,7 +968,8 @@ public class PhoneSwitcher extends Handler { if (subId == DEFAULT_SUBSCRIPTION_ID) return mPreferredDataPhoneId; if (subId == INVALID_SUBSCRIPTION_ID) return INVALID_PHONE_INDEX; int preferredDataSubId = SubscriptionManager.isValidPhoneId(mPreferredDataPhoneId) int preferredDataSubId = (mPreferredDataPhoneId >= 0 && mPreferredDataPhoneId < mActiveModemCount) ? mPhoneSubscriptions[mPreferredDataPhoneId] : INVALID_SUBSCRIPTION_ID; // Currently we assume multi-SIM devices will only support one Internet PDN connection. So Loading @@ -973,7 +987,7 @@ public class PhoneSwitcher extends Handler { // Try to find matching phone ID. If it doesn't exist, we'll end up returning INVALID. int phoneId = INVALID_PHONE_INDEX; for (int i = 0; i < mNumPhones; i++) { for (int i = 0; i < mActiveModemCount; i++) { if (mPhoneSubscriptions[i] == subId) { phoneId = i; break; Loading Loading @@ -1036,7 +1050,7 @@ public class PhoneSwitcher extends Handler { int phoneId = SubscriptionManager.INVALID_PHONE_INDEX; if (SubscriptionManager.isUsableSubIdValue(subId)) { for (int i = 0; i < mNumPhones; i++) { for (int i = 0; i < mActiveModemCount; i++) { if (mPhoneSubscriptions[i] == subId) { phoneId = i; break; Loading @@ -1051,7 +1065,7 @@ public class PhoneSwitcher extends Handler { } private void transitionToEmergencyPhone() { if (mNumPhones <= 0) { if (mActiveModemCount <= 0) { log("No phones: unable to reset preferred phone for emergency"); return; } Loading @@ -1068,14 +1082,15 @@ public class PhoneSwitcher extends Handler { } private Phone findPhoneById(final int phoneId) { if (phoneId < 0 || phoneId >= mNumPhones) { if (!SubscriptionManager.isValidPhoneId(phoneId)) { return null; } return mPhones[phoneId]; return PhoneFactory.getPhone(phoneId); } public boolean shouldApplyNetworkRequest(NetworkRequest networkRequest, int phoneId) { validatePhoneId(phoneId); public synchronized boolean shouldApplyNetworkRequest( NetworkRequest networkRequest, int phoneId) { if (!SubscriptionManager.isValidPhoneId(phoneId)) return false; // In any case, if phone state is inactive, don't apply the network request. if (!isPhoneActive(phoneId) || ( Loading Loading @@ -1112,13 +1127,6 @@ public class PhoneSwitcher extends Handler { mActivePhoneRegistrants.remove(h); } @VisibleForTesting protected void validatePhoneId(int phoneId) { if (phoneId < 0 || phoneId >= mNumPhones) { throw new IllegalArgumentException("Invalid PhoneId"); } } /** * Set opportunistic data subscription. It's an indication to switch Internet data to this * subscription. It has to be an active subscription, and PhoneSwitcher will try to validate Loading Loading @@ -1319,7 +1327,7 @@ public class PhoneSwitcher extends Handler { final IndentingPrintWriter pw = new IndentingPrintWriter(writer, " "); pw.println("PhoneSwitcher:"); Calendar c = Calendar.getInstance(); for (int i = 0; i < mNumPhones; i++) { for (int i = 0; i < mActiveModemCount; i++) { PhoneState ps = mPhoneStates[i]; c.setTimeInMillis(ps.lastRequested); pw.println("PhoneId(" + i + ") active=" + ps.active + ", lastRequest=" + Loading Loading
src/java/com/android/internal/telephony/PhoneFactory.java +1 −7 Original line number Diff line number Diff line Loading @@ -29,7 +29,6 @@ import android.content.SharedPreferences; import android.content.pm.PackageManager; import android.net.LocalServerSocket; import android.os.Looper; import android.os.ServiceManager; import android.preference.PreferenceManager; import android.provider.Settings; import android.provider.Settings.SettingNotFoundException; Loading Loading @@ -235,9 +234,6 @@ public class PhoneFactory { Rlog.i(LOG_TAG, "IMS is not supported on this device, skipping ImsResolver."); } ITelephonyRegistry tr = ITelephonyRegistry.Stub.asInterface( ServiceManager.getService("telephony.registry")); sPhoneConfigurationManager = PhoneConfigurationManager.init(sContext); sCellularNetworkValidator = CellularNetworkValidator.make(sContext); Loading @@ -245,9 +241,7 @@ public class PhoneFactory { int maxActivePhones = sPhoneConfigurationManager .getNumberOfModemsWithSimultaneousDataConnections(); sPhoneSwitcher = PhoneSwitcher.make(maxActivePhones, numPhones, sContext, sc, Looper.myLooper(), tr, sCommandsInterfaces, sPhones); sPhoneSwitcher = PhoneSwitcher.make(maxActivePhones, sContext, Looper.myLooper()); sProxyController = ProxyController.getInstance(context); Loading
src/java/com/android/internal/telephony/PhoneSwitcher.java +105 −97 Original line number Diff line number Diff line Loading @@ -25,6 +25,8 @@ import static android.telephony.TelephonyManager.SET_OPPORTUNISTIC_SUB_INACTIVE_ import static android.telephony.TelephonyManager.SET_OPPORTUNISTIC_SUB_SUCCESS; import static android.telephony.TelephonyManager.SET_OPPORTUNISTIC_SUB_VALIDATION_FAILED; import static java.util.Arrays.copyOf; import android.annotation.UnsupportedAppUsage; import android.content.BroadcastReceiver; import android.content.Context; Loading @@ -46,7 +48,6 @@ import android.os.PersistableBundle; import android.os.Registrant; import android.os.RegistrantList; import android.os.RemoteException; import android.os.ServiceManager; import android.telephony.CarrierConfigManager; import android.telephony.PhoneCapability; import android.telephony.PhoneStateListener; Loading @@ -65,7 +66,6 @@ import com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent.DataSwi import com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent.OnDemandDataSwitch; import com.android.internal.util.IndentingPrintWriter; import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; Loading Loading @@ -156,15 +156,10 @@ public class PhoneSwitcher extends Handler { private final List<DcRequest> mPrioritizedDcRequests = new ArrayList<DcRequest>(); private final RegistrantList mActivePhoneRegistrants; private final SubscriptionController mSubscriptionController; private final int[] mPhoneSubscriptions; private final CommandsInterface[] mCommandsInterfaces; private final Context mContext; private final PhoneState[] mPhoneStates; @UnsupportedAppUsage private final int mNumPhones; @UnsupportedAppUsage private final Phone[] mPhones; private final LocalLog mLocalLog; private PhoneState[] mPhoneStates; private int[] mPhoneSubscriptions; @VisibleForTesting public final PhoneStateListener mPhoneStateListener; private final CellularNetworkValidator mValidator; Loading @@ -172,8 +167,14 @@ public class PhoneSwitcher extends Handler { public final CellularNetworkValidator.ValidationCallback mValidationCallback = (validated, subId) -> Message.obtain(PhoneSwitcher.this, EVENT_NETWORK_VALIDATION_DONE, subId, validated ? 1 : 0).sendToTarget(); @UnsupportedAppUsage private int mMaxActivePhones; // How many phones (correspondingly logical modems) are allowed for PS attach. This is used // when we specifically use setDataAllowed to initiate on-demand PS(data) attach for each phone. private int mMaxDataAttachModemCount; // Local cache of TelephonyManager#getActiveModemCount(). 1 if in single SIM mode, 2 if in dual // SIM mode. private int mActiveModemCount; private static PhoneSwitcher sPhoneSwitcher = null; // Which primary (non-opportunistic) subscription is set as data subscription among all primary Loading Loading @@ -239,6 +240,9 @@ public class PhoneSwitcher extends Handler { private static final int EVENT_OVERRIDE_DDS_FOR_EMERGENCY = 115; // If it exists, remove the current mEmergencyOverride DDS override. private static final int EVENT_REMOVE_DDS_EMERGENCY_OVERRIDE = 116; // If it exists, remove the current mEmergencyOverride DDS override. @VisibleForTesting public static final int EVENT_MULTI_SIM_CONFIG_CHANGED = 117; // Depending on version of IRadioConfig, we need to send either RIL_REQUEST_ALLOW_DATA if it's // 1.0, or RIL_REQUEST_SET_PREFERRED_DATA if it's 1.1 or later. So internally mHalCommandToUse Loading Loading @@ -290,47 +294,21 @@ public class PhoneSwitcher extends Handler { /** * Method to create singleton instance. */ public static PhoneSwitcher make(int maxActivePhones, int numPhones, Context context, SubscriptionController subscriptionController, Looper looper, ITelephonyRegistry tr, CommandsInterface[] cis, Phone[] phones) { public static PhoneSwitcher make(int maxDataAttachModemCount, Context context, Looper looper) { if (sPhoneSwitcher == null) { sPhoneSwitcher = new PhoneSwitcher(maxActivePhones, numPhones, context, subscriptionController, looper, cis, phones); sPhoneSwitcher = new PhoneSwitcher(maxDataAttachModemCount, context, looper); } return sPhoneSwitcher; } /** This constructor is only used for testing purpose. */ @VisibleForTesting public PhoneSwitcher(int numPhones, Looper looper) { super(looper); mMaxActivePhones = 0; mSubscriptionController = null; mCommandsInterfaces = null; mContext = null; mPhoneStates = null; mPhones = null; mLocalLog = null; mActivePhoneRegistrants = null; mNumPhones = numPhones; mPhoneSubscriptions = new int[numPhones]; mRadioConfig = RadioConfig.getInstance(mContext); mPhoneStateListener = new PhoneStateListener(looper) { public void onPhoneCapabilityChanged(PhoneCapability capability) { onPhoneCapabilityChangedInternal(capability); } }; mValidator = CellularNetworkValidator.getInstance(); } private boolean isPhoneInVoiceCallChanged() { int oldPhoneIdInVoiceCall = mPhoneIdInVoiceCall; // If there's no active call, the value will become INVALID_PHONE_INDEX // and internet data will be switched back to system selected or user selected // subscription. mPhoneIdInVoiceCall = SubscriptionManager.INVALID_PHONE_INDEX; for (Phone phone : mPhones) { for (Phone phone : PhoneFactory.getPhones()) { if (isPhoneInVoiceCall(phone) || isPhoneInVoiceCall(phone.getImsPhone())) { mPhoneIdInVoiceCall = phone.getPhoneId(); break; Loading @@ -347,18 +325,16 @@ public class PhoneSwitcher extends Handler { } @VisibleForTesting public PhoneSwitcher(int maxActivePhones, int numPhones, Context context, SubscriptionController subscriptionController, Looper looper, CommandsInterface[] cis, Phone[] phones) { public PhoneSwitcher(int maxActivePhones, Context context, Looper looper) { super(looper); mContext = context; mNumPhones = numPhones; mPhones = phones; mPhoneSubscriptions = new int[numPhones]; mMaxActivePhones = maxActivePhones; mActiveModemCount = getTm().getActiveModemCount(); mPhoneSubscriptions = new int[mActiveModemCount]; mPhoneStates = new PhoneState[mActiveModemCount]; mMaxDataAttachModemCount = maxActivePhones; mLocalLog = new LocalLog(MAX_LOCAL_LOG_LINES); mSubscriptionController = subscriptionController; mSubscriptionController = SubscriptionController.getInstance(); mRadioConfig = RadioConfig.getInstance(mContext); mPhoneStateListener = new PhoneStateListener(looper) { Loading @@ -371,27 +347,25 @@ public class PhoneSwitcher extends Handler { mValidator = CellularNetworkValidator.getInstance(); mActivePhoneRegistrants = new RegistrantList(); mPhoneStates = new PhoneState[numPhones]; for (int i = 0; i < numPhones; i++) { for (int i = 0; i < mActiveModemCount; i++) { mPhoneStates[i] = new PhoneState(); if (mPhones[i] != null) { mPhones[i].registerForEmergencyCallToggle(this, EVENT_EMERGENCY_TOGGLE, null); if (PhoneFactory.getPhone(i) != null) { PhoneFactory.getPhone(i).registerForEmergencyCallToggle( this, EVENT_EMERGENCY_TOGGLE, null); // TODO (b/135566422): combine register for both GsmCdmaPhone and ImsPhone. mPhones[i].registerForPreciseCallStateChanged( PhoneFactory.getPhone(i).registerForPreciseCallStateChanged( this, EVENT_PRECISE_CALL_STATE_CHANGED, null); if (mPhones[i].getImsPhone() != null) { mPhones[i].getImsPhone().registerForPreciseCallStateChanged( if (PhoneFactory.getPhone(i).getImsPhone() != null) { PhoneFactory.getPhone(i).getImsPhone().registerForPreciseCallStateChanged( this, EVENT_PRECISE_CALL_STATE_CHANGED, null); } mPhones[i].getDataEnabledSettings().registerForDataEnabledChanged( PhoneFactory.getPhone(i).getDataEnabledSettings().registerForDataEnabledChanged( this, EVENT_DATA_ENABLED_CHANGED, null); } } mCommandsInterfaces = cis; if (numPhones > 0) { mCommandsInterfaces[0].registerForAvailable(this, EVENT_RADIO_AVAILABLE, null); if (mActiveModemCount > 0) { PhoneFactory.getPhone(0).mCi.registerForAvailable(this, EVENT_RADIO_AVAILABLE, null); } TelephonyRegistryManager telephonyRegistryManager = (TelephonyRegistryManager) Loading @@ -405,6 +379,9 @@ public class PhoneSwitcher extends Handler { mContext.registerReceiver(mDefaultDataChangedReceiver, new IntentFilter(TelephonyIntents.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED)); PhoneConfigurationManager.registerForMultiSimConfigChange( this, EVENT_MULTI_SIM_CONFIG_CHANGED, null); NetworkCapabilities netCap = new NetworkCapabilities(); netCap.addTransportType(TRANSPORT_CELLULAR); netCap.addCapability(NetworkCapabilities.NET_CAPABILITY_MMS); Loading Loading @@ -620,11 +597,43 @@ public class PhoneSwitcher extends Handler { onEvaluate(REQUESTS_UNCHANGED, "emer_rm_override_dds"); break; } case EVENT_MULTI_SIM_CONFIG_CHANGED: { int activeModemCount = (int) ((AsyncResult) msg.obj).result; onMultiSimConfigChanged(activeModemCount); break; } } } private synchronized void onMultiSimConfigChanged(int activeModemCount) { // No change. if (mActiveModemCount == activeModemCount) return; int oldActiveModemCount = mActiveModemCount; mActiveModemCount = activeModemCount; mPhoneSubscriptions = copyOf(mPhoneSubscriptions, mActiveModemCount); mPhoneStates = copyOf(mPhoneStates, mActiveModemCount); // Single SIM -> dual SIM switch. for (int phoneId = oldActiveModemCount; phoneId < mActiveModemCount; phoneId++) { mPhoneStates[phoneId] = new PhoneState(); Phone phone = PhoneFactory.getPhone(phoneId); if (phone == null) continue; phone.registerForEmergencyCallToggle(this, EVENT_EMERGENCY_TOGGLE, null); // TODO (b/135566422): combine register for both GsmCdmaPhone and ImsPhone. phone.registerForPreciseCallStateChanged(this, EVENT_PRECISE_CALL_STATE_CHANGED, null); if (phone.getImsPhone() != null) { phone.getImsPhone().registerForPreciseCallStateChanged( this, EVENT_PRECISE_CALL_STATE_CHANGED, null); } phone.getDataEnabledSettings().registerForDataEnabledChanged( this, EVENT_DATA_ENABLED_CHANGED, null); } } private boolean isInEmergencyCallbackMode() { for (Phone p : mPhones) { for (Phone p : PhoneFactory.getPhones()) { if (p == null) continue; if (p.isInEcm()) return true; Phone imsPhone = p.getImsPhone(); Loading Loading @@ -699,7 +708,7 @@ public class PhoneSwitcher extends Handler { private void collectRequestNetworkMetrics(NetworkRequest networkRequest) { // Request network for MMS will temporary disable the network on default data subscription, // this only happen on multi-sim device. if (mNumPhones > 1 && networkRequest.networkCapabilities.hasCapability( if (mActiveModemCount > 1 && networkRequest.networkCapabilities.hasCapability( NetworkCapabilities.NET_CAPABILITY_MMS)) { OnDemandDataSwitch onDemandDataSwitch = new OnDemandDataSwitch(); onDemandDataSwitch.apn = TelephonyEvent.ApnType.APN_TYPE_MMS; Loading @@ -711,7 +720,7 @@ public class PhoneSwitcher extends Handler { private void collectReleaseNetworkMetrics(NetworkRequest networkRequest) { // Release network for MMS will recover the network on default data subscription, this only // happen on multi-sim device. if (mNumPhones > 1 && networkRequest.networkCapabilities.hasCapability( if (mActiveModemCount > 1 && networkRequest.networkCapabilities.hasCapability( NetworkCapabilities.NET_CAPABILITY_MMS)) { OnDemandDataSwitch onDemandDataSwitch = new OnDemandDataSwitch(); onDemandDataSwitch.apn = TelephonyEvent.ApnType.APN_TYPE_MMS; Loading @@ -720,6 +729,10 @@ public class PhoneSwitcher extends Handler { } } private TelephonyManager getTm() { return (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE); } private static final boolean REQUESTS_CHANGED = true; private static final boolean REQUESTS_UNCHANGED = false; /** Loading Loading @@ -749,7 +762,7 @@ public class PhoneSwitcher extends Handler { boolean hasAnyActiveSubscription = false; // Check if phoneId to subId mapping is changed. for (int i = 0; i < mNumPhones; i++) { for (int i = 0; i < mActiveModemCount; i++) { int sub = mSubscriptionController.getSubIdUsingPhoneId(i); if (SubscriptionManager.isValidSubscriptionId(sub)) hasAnyActiveSubscription = true; Loading Loading @@ -790,7 +803,7 @@ public class PhoneSwitcher extends Handler { // With HAL_COMMAND_PREFERRED_DATA, all phones are assumed to allow PS attach. // So marking all phone as active, and the phone with mPreferredDataPhoneId // will send radioConfig command. for (int phoneId = 0; phoneId < mNumPhones; phoneId++) { for (int phoneId = 0; phoneId < mActiveModemCount; phoneId++) { mPhoneStates[phoneId].active = true; } sendRilCommands(mPreferredDataPhoneId); Loading @@ -802,9 +815,9 @@ public class PhoneSwitcher extends Handler { * Otherwise, choose to activate phones according to requests. And * if list is not full, add mPreferredDataPhoneId. */ if (mMaxActivePhones == mPhones.length) { for (int i = 0; i < mMaxActivePhones; i++) { newActivePhones.add(mPhones[i].getPhoneId()); if (mMaxDataAttachModemCount == mActiveModemCount) { for (int i = 0; i < mMaxDataAttachModemCount; i++) { newActivePhones.add(i); } } else { // First try to activate phone in voice call. Loading @@ -812,17 +825,17 @@ public class PhoneSwitcher extends Handler { newActivePhones.add(mPhoneIdInVoiceCall); } if (newActivePhones.size() < mMaxActivePhones) { if (newActivePhones.size() < mMaxDataAttachModemCount) { for (DcRequest dcRequest : mPrioritizedDcRequests) { int phoneIdForRequest = phoneIdForRequest(dcRequest.networkRequest); if (phoneIdForRequest == INVALID_PHONE_INDEX) continue; if (newActivePhones.contains(phoneIdForRequest)) continue; newActivePhones.add(phoneIdForRequest); if (newActivePhones.size() >= mMaxActivePhones) break; if (newActivePhones.size() >= mMaxDataAttachModemCount) break; } } if (newActivePhones.size() < mMaxActivePhones if (newActivePhones.size() < mMaxDataAttachModemCount && newActivePhones.contains(mPreferredDataPhoneId) && SubscriptionManager.isUsableSubIdValue(mPreferredDataPhoneId)) { newActivePhones.add(mPreferredDataPhoneId); Loading @@ -832,14 +845,14 @@ public class PhoneSwitcher extends Handler { if (VDBG) { log("mPrimaryDataSubId = " + mPrimaryDataSubId); log("mOpptDataSubId = " + mOpptDataSubId); for (int i = 0; i < mNumPhones; i++) { for (int i = 0; i < mActiveModemCount; i++) { log(" phone[" + i + "] using sub[" + mPhoneSubscriptions[i] + "]"); } log(" newActivePhones:"); for (Integer i : newActivePhones) log(" " + i); } for (int phoneId = 0; phoneId < mNumPhones; phoneId++) { for (int phoneId = 0; phoneId < mActiveModemCount; phoneId++) { if (!newActivePhones.contains(phoneId)) { deactivate(phoneId); } Loading Loading @@ -888,7 +901,7 @@ public class PhoneSwitcher extends Handler { * want to resend setDataAllowed or setPreferredDataSubscriptionId */ public void onRadioCapChanged(int phoneId) { validatePhoneId(phoneId); if (!SubscriptionManager.isValidPhoneId(phoneId)) return; Message msg = obtainMessage(EVENT_RADIO_CAPABILITY_CHANGED); msg.arg1 = phoneId; msg.sendToTarget(); Loading @@ -913,7 +926,7 @@ public class PhoneSwitcher extends Handler { */ public void overrideDefaultDataForEmergency(int phoneId, int overrideTimeSec, CompletableFuture<Boolean> dataSwitchResult) { validatePhoneId(phoneId); if (!SubscriptionManager.isValidPhoneId(phoneId)) return; Message msg = obtainMessage(EVENT_OVERRIDE_DDS_FOR_EMERGENCY); EmergencyOverrideRequest request = new EmergencyOverrideRequest(); request.mPhoneId = phoneId; Loading @@ -924,13 +937,13 @@ public class PhoneSwitcher extends Handler { } private void sendRilCommands(int phoneId) { if (!SubscriptionManager.isValidPhoneId(phoneId) || phoneId >= mNumPhones) return; if (!SubscriptionManager.isValidPhoneId(phoneId)) return; Message message = Message.obtain(this, EVENT_MODEM_COMMAND_DONE, phoneId); if (mHalCommandToUse == HAL_COMMAND_ALLOW_DATA || mHalCommandToUse == HAL_COMMAND_UNKNOWN) { // Skip ALLOW_DATA for single SIM device if (mNumPhones > 1) { mCommandsInterfaces[phoneId].setDataAllowed(isPhoneActive(phoneId), message); if (mActiveModemCount > 1) { PhoneFactory.getPhone(phoneId).mCi.setDataAllowed(isPhoneActive(phoneId), message); } } else if (phoneId == mPreferredDataPhoneId) { // Only setPreferredDataModem if the phoneId equals to current mPreferredDataPhoneId. Loading @@ -939,11 +952,11 @@ public class PhoneSwitcher extends Handler { } private void onPhoneCapabilityChangedInternal(PhoneCapability capability) { int newMaxActivePhones = TelephonyManager.getDefault() int newMaxDataAttachModemCount = TelephonyManager.getDefault() .getNumberOfModemsWithSimultaneousDataConnections(); if (mMaxActivePhones != newMaxActivePhones) { mMaxActivePhones = newMaxActivePhones; log("Max active phones changed to " + mMaxActivePhones); if (mMaxDataAttachModemCount != newMaxDataAttachModemCount) { mMaxDataAttachModemCount = newMaxDataAttachModemCount; log("Max active phones changed to " + mMaxDataAttachModemCount); onEvaluate(REQUESTS_UNCHANGED, "phoneCfgChanged"); } } Loading @@ -955,7 +968,8 @@ public class PhoneSwitcher extends Handler { if (subId == DEFAULT_SUBSCRIPTION_ID) return mPreferredDataPhoneId; if (subId == INVALID_SUBSCRIPTION_ID) return INVALID_PHONE_INDEX; int preferredDataSubId = SubscriptionManager.isValidPhoneId(mPreferredDataPhoneId) int preferredDataSubId = (mPreferredDataPhoneId >= 0 && mPreferredDataPhoneId < mActiveModemCount) ? mPhoneSubscriptions[mPreferredDataPhoneId] : INVALID_SUBSCRIPTION_ID; // Currently we assume multi-SIM devices will only support one Internet PDN connection. So Loading @@ -973,7 +987,7 @@ public class PhoneSwitcher extends Handler { // Try to find matching phone ID. If it doesn't exist, we'll end up returning INVALID. int phoneId = INVALID_PHONE_INDEX; for (int i = 0; i < mNumPhones; i++) { for (int i = 0; i < mActiveModemCount; i++) { if (mPhoneSubscriptions[i] == subId) { phoneId = i; break; Loading Loading @@ -1036,7 +1050,7 @@ public class PhoneSwitcher extends Handler { int phoneId = SubscriptionManager.INVALID_PHONE_INDEX; if (SubscriptionManager.isUsableSubIdValue(subId)) { for (int i = 0; i < mNumPhones; i++) { for (int i = 0; i < mActiveModemCount; i++) { if (mPhoneSubscriptions[i] == subId) { phoneId = i; break; Loading @@ -1051,7 +1065,7 @@ public class PhoneSwitcher extends Handler { } private void transitionToEmergencyPhone() { if (mNumPhones <= 0) { if (mActiveModemCount <= 0) { log("No phones: unable to reset preferred phone for emergency"); return; } Loading @@ -1068,14 +1082,15 @@ public class PhoneSwitcher extends Handler { } private Phone findPhoneById(final int phoneId) { if (phoneId < 0 || phoneId >= mNumPhones) { if (!SubscriptionManager.isValidPhoneId(phoneId)) { return null; } return mPhones[phoneId]; return PhoneFactory.getPhone(phoneId); } public boolean shouldApplyNetworkRequest(NetworkRequest networkRequest, int phoneId) { validatePhoneId(phoneId); public synchronized boolean shouldApplyNetworkRequest( NetworkRequest networkRequest, int phoneId) { if (!SubscriptionManager.isValidPhoneId(phoneId)) return false; // In any case, if phone state is inactive, don't apply the network request. if (!isPhoneActive(phoneId) || ( Loading Loading @@ -1112,13 +1127,6 @@ public class PhoneSwitcher extends Handler { mActivePhoneRegistrants.remove(h); } @VisibleForTesting protected void validatePhoneId(int phoneId) { if (phoneId < 0 || phoneId >= mNumPhones) { throw new IllegalArgumentException("Invalid PhoneId"); } } /** * Set opportunistic data subscription. It's an indication to switch Internet data to this * subscription. It has to be an active subscription, and PhoneSwitcher will try to validate Loading Loading @@ -1319,7 +1327,7 @@ public class PhoneSwitcher extends Handler { final IndentingPrintWriter pw = new IndentingPrintWriter(writer, " "); pw.println("PhoneSwitcher:"); Calendar c = Calendar.getInstance(); for (int i = 0; i < mNumPhones; i++) { for (int i = 0; i < mActiveModemCount; i++) { PhoneState ps = mPhoneStates[i]; c.setTimeInMillis(ps.lastRequested); pw.println("PhoneId(" + i + ") active=" + ps.active + ", lastRequest=" + Loading