In PhoneFactory, dynamically allocate 2nd phone when switching to dsds
Test: Manual and unittest
Bug: 142514392
Merged-In: Ia8496a8d297c4512dbe4266b171388ff8d3cbcdd
Change-Id: Ia8496a8d297c4512dbe4266b171388ff8d3cbcdd
diff --git a/src/java/com/android/internal/telephony/PhoneConfigurationManager.java b/src/java/com/android/internal/telephony/PhoneConfigurationManager.java
index df73ef8..2ad6056 100644
--- a/src/java/com/android/internal/telephony/PhoneConfigurationManager.java
+++ b/src/java/com/android/internal/telephony/PhoneConfigurationManager.java
@@ -30,6 +30,7 @@
import android.os.storage.StorageManager;
import android.telephony.PhoneCapability;
import android.telephony.Rlog;
+import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.util.Log;
@@ -130,19 +131,6 @@
}
/**
- * Whether the phoneId has a corresponding active slot / logical modem. If a DSDS capable
- * device is in single SIM mode, phoneId=1 is valid but not active.
- *
- * TODO: b/139642279 combine with SubscriptionManager#isValidPhoneId when phone objects
- * are dynamically allocated instead of always based on getMaxPhoneCount.
- * @hide
- */
- public static boolean isPhoneActive(int phoneId) {
- // Currently it simply depends on getPhoneCount. In future it can be generalized.
- return phoneId >= 0 && phoneId < TelephonyManager.getDefault().getPhoneCount();
- }
-
- /**
* Handler class to handle callbacks
*/
private final class ConfigManagerHandler extends Handler {
@@ -366,11 +354,12 @@
pm.reboot("Multi-SIM config changed.");
} else {
log("onMultiSimConfigChanged: Rebooting is not required.");
+ mMi.notifyPhoneFactoryOnMultiSimConfigChanged(mContext, numOfActiveModems);
broadcastMultiSimConfigChange(numOfActiveModems);
// Register to RIL service if needed.
for (int i = 0; i < mPhones.length; i++) {
Phone phone = mPhones[i];
- phone.mCi.onSlotActiveStatusChange(isPhoneActive(i));
+ phone.mCi.onSlotActiveStatusChange(SubscriptionManager.isValidPhoneId(i));
}
}
}
@@ -426,6 +415,9 @@
*/
@VisibleForTesting
public static class MockableInterface {
+ /**
+ * Wrapper function to decide whether reboot is required for modem config change.
+ */
@VisibleForTesting
public boolean isRebootRequiredForModemConfigChange() {
String rebootRequired = SystemProperties.get(
@@ -434,6 +426,9 @@
return !rebootRequired.equals("false");
}
+ /**
+ * Wrapper function to call setMultiSimProperties.
+ */
@VisibleForTesting
public void setMultiSimProperties(int numOfActiveModems) {
String multiSimConfig;
@@ -451,6 +446,15 @@
log("setMultiSimProperties to " + multiSimConfig);
SystemProperties.set(TelephonyProperties.PROPERTY_MULTI_SIM_CONFIG, multiSimConfig);
}
+
+ /**
+ * Wrapper function to call PhoneFactory.onMultiSimConfigChanged.
+ */
+ @VisibleForTesting
+ public void notifyPhoneFactoryOnMultiSimConfigChanged(
+ Context context, int numOfActiveModems) {
+ PhoneFactory.onMultiSimConfigChanged(context, numOfActiveModems);
+ }
}
private static void log(String s) {
diff --git a/src/java/com/android/internal/telephony/PhoneFactory.java b/src/java/com/android/internal/telephony/PhoneFactory.java
index a3177c6..8a84921 100644
--- a/src/java/com/android/internal/telephony/PhoneFactory.java
+++ b/src/java/com/android/internal/telephony/PhoneFactory.java
@@ -19,6 +19,8 @@
import static com.android.internal.telephony.PhoneConstants.PHONE_TYPE_CDMA;
import static com.android.internal.telephony.PhoneConstants.PHONE_TYPE_CDMA_LTE;
+import static java.util.Arrays.copyOf;
+
import android.annotation.Nullable;
import android.annotation.UnsupportedAppUsage;
import android.content.ComponentName;
@@ -148,7 +150,7 @@
/* In case of multi SIM mode two instances of Phone, RIL are created,
where as in single SIM mode only instance. isMultiSimEnabled() function checks
whether it is single SIM or multi SIM mode */
- int numPhones = TelephonyManager.getDefault().getSupportedModemCount();
+ int numPhones = TelephonyManager.getDefault().getActiveModemCount();
int[] networkModes = new int[numPhones];
sPhones = new Phone[numPhones];
@@ -186,7 +188,7 @@
// Set the default phone in base class.
// FIXME: This is a first best guess at what the defaults will be. It
// FIXME: needs to be done in a more controlled manner in the future.
- sPhone = sPhones[0];
+ if (numPhones > 0) sPhone = sPhones[0];
// Ensure that we have a default SMS app. Requesting the app with
// updateIfNeeded set to true is enough to configure a default SMS app.
@@ -206,7 +208,6 @@
Rlog.i(LOG_TAG, "Creating SubInfoRecordUpdater ");
sSubInfoRecordUpdater = new SubscriptionInfoUpdater(
BackgroundThread.get().getLooper(), context, sCommandsInterfaces);
- sc.updatePhonesAvailability(sPhones);
// Only bring up IMS if the device supports having an IMS stack.
if (context.getPackageManager().hasSystemFeature(
@@ -262,6 +263,41 @@
}
}
+ /**
+ * Upon single SIM to dual SIM switch or vice versa, we dynamically allocate or de-allocate
+ * Phone and CommandInterface objects.
+ * @param context
+ * @param activeModemCount
+ */
+ public static void onMultiSimConfigChanged(Context context, int activeModemCount) {
+ synchronized (sLockProxyPhones) {
+ int prevActiveModemCount = sPhones.length;
+ if (prevActiveModemCount == activeModemCount) return;
+
+ // TODO: clean up sPhones, sCommandsInterfaces and sTelephonyNetworkFactories objects.
+ // Currently we will not clean up the 2nd Phone object, so that it can be re-used if
+ // user switches back.
+ if (prevActiveModemCount > activeModemCount) return;
+
+ sPhones = copyOf(sPhones, activeModemCount);
+ sCommandsInterfaces = copyOf(sCommandsInterfaces, activeModemCount);
+ sTelephonyNetworkFactories = copyOf(sTelephonyNetworkFactories, activeModemCount);
+
+ int cdmaSubscription = CdmaSubscriptionSourceManager.getDefault(context);
+ for (int i = prevActiveModemCount; i < activeModemCount; i++) {
+ sCommandsInterfaces[i] = new RIL(context, RILConstants.PREFERRED_NETWORK_MODE,
+ cdmaSubscription, i);
+ sPhones[i] = createPhone(context, i);
+ if (context.getPackageManager().hasSystemFeature(
+ PackageManager.FEATURE_TELEPHONY_IMS)) {
+ sPhones[i].startMonitoringImsService();
+ }
+ sTelephonyNetworkFactories[i] = new TelephonyNetworkFactory(
+ Looper.myLooper(), sPhones[i]);
+ }
+ }
+ }
+
private static Phone createPhone(Context context, int phoneId) {
int phoneType = TelephonyManager.getPhoneType(RILConstants.PREFERRED_NETWORK_MODE);
Rlog.i(LOG_TAG, "Creating Phone with type = " + phoneType + " phoneId = " + phoneId);
diff --git a/src/java/com/android/internal/telephony/ProxyController.java b/src/java/com/android/internal/telephony/ProxyController.java
index bd8689a..69f8a0b 100644
--- a/src/java/com/android/internal/telephony/ProxyController.java
+++ b/src/java/com/android/internal/telephony/ProxyController.java
@@ -209,7 +209,7 @@
*/
public boolean setRadioCapability(RadioAccessFamily[] rafs) {
if (rafs.length != mPhones.length) {
- throw new RuntimeException("Length of input rafs must equal to total phone count");
+ return false;
}
// Check if there is any ongoing transaction and throw an exception if there
// is one as this is a programming error.
diff --git a/src/java/com/android/internal/telephony/RIL.java b/src/java/com/android/internal/telephony/RIL.java
index 4d7a687..e7201e4 100644
--- a/src/java/com/android/internal/telephony/RIL.java
+++ b/src/java/com/android/internal/telephony/RIL.java
@@ -91,6 +91,7 @@
import android.telephony.ServiceState;
import android.telephony.SignalStrength;
import android.telephony.SmsManager;
+import android.telephony.SubscriptionManager;
import android.telephony.TelephonyHistogram;
import android.telephony.TelephonyManager;
import android.telephony.TelephonyManager.PrefNetworkMode;
@@ -413,7 +414,7 @@
/** Returns a {@link IRadio} instance or null if the service is not available. */
@VisibleForTesting
public synchronized IRadio getRadioProxy(Message result) {
- if (!PhoneConfigurationManager.isPhoneActive(mPhoneId)) return null;
+ if (!SubscriptionManager.isValidPhoneId(mPhoneId)) return null;
if (!mIsMobileNetworkSupported) {
if (RILJ_LOGV) riljLog("getRadioProxy: Not calling getService(): wifi-only");
if (result != null) {
@@ -510,13 +511,15 @@
// Try to connect to RIL services and set response functions.
getRadioProxy(null);
getOemHookProxy(null);
+ } else {
+ resetProxyAndRequestList();
}
}
/** Returns an {@link IOemHook} instance or null if the service is not available. */
@VisibleForTesting
public synchronized IOemHook getOemHookProxy(Message result) {
- if (!PhoneConfigurationManager.isPhoneActive(mPhoneId)) return null;
+ if (!SubscriptionManager.isValidPhoneId((mPhoneId))) return null;
if (!mIsMobileNetworkSupported) {
if (RILJ_LOGV) riljLog("getOemHookProxy: Not calling getService(): wifi-only");
if (result != null) {
diff --git a/src/java/com/android/internal/telephony/SubscriptionController.java b/src/java/com/android/internal/telephony/SubscriptionController.java
index 24bb42d..ab24988 100644
--- a/src/java/com/android/internal/telephony/SubscriptionController.java
+++ b/src/java/com/android/internal/telephony/SubscriptionController.java
@@ -133,7 +133,6 @@
/** The singleton instance. */
private static SubscriptionController sInstance = null;
- protected static Phone[] sPhones;
@UnsupportedAppUsage
protected Context mContext;
protected TelephonyManager mTelephonyManager;
@@ -1185,7 +1184,7 @@
}
// Once the records are loaded, notify DcTracker
- sPhones[slotIndex].updateDataConnectionTracker();
+ PhoneFactory.getPhone(slotIndex).updateDataConnectionTracker();
if (DBG) logdl("[addSubInfoRecord]- info size=" + sSlotIndexToSubIds.size());
}
@@ -2244,7 +2243,7 @@
}
ProxyController proxyController = ProxyController.getInstance();
- int len = sPhones.length;
+ int len = TelephonyManager.from(mContext).getActiveModemCount();
logdl("[setDefaultDataSubId] num phones=" + len + ", subId=" + subId);
if (SubscriptionManager.isValidSubscriptionId(subId)) {
@@ -2252,7 +2251,7 @@
RadioAccessFamily[] rafs = new RadioAccessFamily[len];
boolean atLeastOneMatch = false;
for (int phoneId = 0; phoneId < len; phoneId++) {
- Phone phone = sPhones[phoneId];
+ Phone phone = PhoneFactory.getPhone(phoneId);
int raf;
int id = phone.getSubId();
if (id == subId) {
@@ -2293,11 +2292,11 @@
@UnsupportedAppUsage
private void updateAllDataConnectionTrackers() {
// Tell Phone Proxies to update data connection tracker
- int len = sPhones.length;
- if (DBG) logd("[updateAllDataConnectionTrackers] sPhones.length=" + len);
+ int len = TelephonyManager.from(mContext).getActiveModemCount();
+ if (DBG) logd("[updateAllDataConnectionTrackers] activeModemCount=" + len);
for (int phoneId = 0; phoneId < len; phoneId++) {
if (DBG) logd("[updateAllDataConnectionTrackers] phoneId=" + phoneId);
- sPhones[phoneId].updateDataConnectionTracker();
+ PhoneFactory.getPhone(phoneId).updateDataConnectionTracker();
}
}
@@ -2433,10 +2432,6 @@
}
}
- public void updatePhonesAvailability(Phone[] phones) {
- sPhones = phones;
- }
-
private synchronized ArrayList<Integer> getActiveSubIdArrayList() {
// Clone the sub id list so it can't change out from under us while iterating
List<Entry<Integer, ArrayList<Integer>>> simInfoList =
diff --git a/tests/telephonytests/src/com/android/internal/telephony/PhoneConfigurationManagerTest.java b/tests/telephonytests/src/com/android/internal/telephony/PhoneConfigurationManagerTest.java
index 6f01a47..08e5a0a 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/PhoneConfigurationManagerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/PhoneConfigurationManagerTest.java
@@ -168,6 +168,7 @@
// Verify set system property being called.
verify(mMi).setMultiSimProperties(MODEM_COUNT_DUAL_MODEM);
+ verify(mMi).notifyPhoneFactoryOnMultiSimConfigChanged(any(), eq(MODEM_COUNT_DUAL_MODEM));
// Capture and verify registration notification.
verify(mHandler).sendMessageAtTime(captor.capture(), anyLong());
diff --git a/tests/telephonytests/src/com/android/internal/telephony/SubscriptionControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/SubscriptionControllerTest.java
index ce3281d..75b3534 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/SubscriptionControllerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/SubscriptionControllerTest.java
@@ -97,8 +97,6 @@
doReturn(1).when(mProxyController).getMaxRafSupported();
mContextFixture.putIntArrayResource(com.android.internal.R.array.sim_colors, new int[]{5});
-
- mSubscriptionControllerUT.updatePhonesAvailability(new Phone[] {mPhone});
}
@After
diff --git a/tests/telephonytests/src/com/android/internal/telephony/mocks/SubscriptionControllerMock.java b/tests/telephonytests/src/com/android/internal/telephony/mocks/SubscriptionControllerMock.java
index 03ef19d..d3804d3 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/mocks/SubscriptionControllerMock.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/mocks/SubscriptionControllerMock.java
@@ -27,7 +27,6 @@
import android.telephony.SubscriptionInfo;
import com.android.internal.telephony.ITelephonyRegistry;
-import com.android.internal.telephony.Phone;
import com.android.internal.telephony.PhoneConstants;
import com.android.internal.telephony.SubscriptionController;
import com.android.internal.telephony.TelephonyIntents;
@@ -243,10 +242,6 @@
}
}
@Override
- public void updatePhonesAvailability(Phone[] phones) {
- throw new RuntimeException("not implemented");
- }
- @Override
public int[] getActiveSubIdList(boolean visibleOnly) {
throw new RuntimeException("not implemented");
}