Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4ec8d9f3 authored by Brad Ebinger's avatar Brad Ebinger
Browse files

ImsResolver will wait for CarrierConfig changes to update

Previously, we would start binding to the default ImsService before
the CarrierConfig was loaded. This causes issues when a carrier
ImsService is found because it can cause a registration on the default
ImsService, followed by a dereg on the default, followed by a reg
on the same network using the carrier ImsService.

By waiting until CARRIER_CONFIG_CHANGED is received, we can ensure
that everything has been loaded before binding to IMS.

Bug: 117991176
Bug: 111609152
Test: atest FrameworksTelephonyTests:ImsResolverTest
Change-Id: If750bf628af0430b0297fec49b89f2e849cb364f
parent 1468bc2f
Loading
Loading
Loading
Loading
+79 −20
Original line number Diff line number Diff line
@@ -34,6 +34,7 @@ import android.os.RemoteException;
import android.os.UserHandle;
import android.telephony.CarrierConfigManager;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.telephony.ims.ImsService;
import android.telephony.ims.aidl.IImsConfig;
import android.telephony.ims.aidl.IImsMmTelFeature;
@@ -217,7 +218,19 @@ public class ImsResolver implements ImsServiceController.ImsServiceControllerCal
                    SubscriptionManager.INVALID_SIM_SLOT_INDEX);

            if (slotId == SubscriptionManager.INVALID_SIM_SLOT_INDEX) {
                Log.i(TAG, "Received SIM change for invalid slot id.");
                Log.i(TAG, "Received CCC for invalid slot id.");
                return;
            }

            int subId = intent.getIntExtra(CarrierConfigManager.EXTRA_SUBSCRIPTION_INDEX,
                    SubscriptionManager.INVALID_SUBSCRIPTION_ID);
            int slotSimState = mTelephonyManagerProxy.getSimState(mContext, slotId);
            if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID
                    && slotSimState != TelephonyManager.SIM_STATE_ABSENT) {
                // We only care about carrier config updates that happen when a slot is known to be
                // absent or populated and the carrier config has been loaded.
                Log.i(TAG, "Received CCC for slot " + slotId + " and sim state "
                        + slotSimState + ", ignoring.");
                return;
            }

@@ -254,6 +267,28 @@ public class ImsResolver implements ImsServiceController.ImsServiceControllerCal
        int getSlotIndex(int subId);
    }

    /**
     * Testing interface used to stub out TelephonyManager dependencies.
     */
    @VisibleForTesting
    public interface TelephonyManagerProxy {
        /**
         * @return the SIM state for the slot ID specified.
         */
        int getSimState(Context context, int slotId);
    }

    private TelephonyManagerProxy mTelephonyManagerProxy = new TelephonyManagerProxy() {
        @Override
        public int getSimState(Context context, int slotId) {
            TelephonyManager tm = context.getSystemService(TelephonyManager.class);
            if (tm == null) {
                return TelephonyManager.SIM_STATE_UNKNOWN;
            }
            return tm.getSimState(slotId);
        }
    };

    private SubscriptionManagerProxy mSubscriptionManagerProxy = new SubscriptionManagerProxy() {
        @Override
        public int getSubId(int slotId) {
@@ -496,6 +531,11 @@ public class ImsResolver implements ImsServiceController.ImsServiceControllerCal
        }
    }

    @VisibleForTesting
    public void setTelephonyManagerProxy(TelephonyManagerProxy proxy) {
        mTelephonyManagerProxy = proxy;
    }

    @VisibleForTesting
    public void setSubscriptionManagerProxy(SubscriptionManagerProxy proxy) {
        mSubscriptionManagerProxy = proxy;
@@ -520,13 +560,32 @@ public class ImsResolver implements ImsServiceController.ImsServiceControllerCal
     * Needs to be called after the constructor to kick off the process of binding to ImsServices.
     */
    public void initialize() {
        Log.i(TAG, "Initializing cache and binding.");
        Log.i(TAG, "Initializing cache.");
        mFeatureQueryManager = mDynamicQueryManagerFactory.create(mContext, mDynamicQueryListener);
        // Populates the CarrierConfig override package names for each slot
        mHandler.obtainMessage(HANDLER_CONFIG_CHANGED,
                SubscriptionManager.INVALID_SIM_SLOT_INDEX).sendToTarget();
        // Starts first bind to the system.
        mHandler.obtainMessage(HANDLER_ADD_PACKAGE, null).sendToTarget();

        // This will get all services with the correct intent filter from PackageManager
        List<ImsServiceInfo> infos = getImsServiceInfo(null);
        for (ImsServiceInfo info : infos) {
            if (!mInstalledServicesCache.containsKey(info.name)) {
                mInstalledServicesCache.put(info.name, info);
            }
        }
        // Update the package names of the carrier ImsServices if they do not exist already and
        // possibly bind if carrier configs exist. Otherwise wait for CarrierConfigChanged
        // indication.
        for (int i = 0; i < mNumSlots; i++) {
            int subId = mSubscriptionManagerProxy.getSubId(i);
            PersistableBundle config = mCarrierConfigManager.getConfigForSubId(subId);
            if (config != null && mCarrierServices[i] == null) {
                String newPackageName = config.getString(
                        CarrierConfigManager.KEY_CONFIG_IMS_PACKAGE_OVERRIDE_STRING, null);
                if (!TextUtils.isEmpty(newPackageName)) {
                    updateBoundCarrierServices(i, newPackageName);
                    Log.i(TAG, "Initializing, found package " + newPackageName + " on slot "
                            + i);
                }
            }
        }
    }

    /**
@@ -860,7 +919,7 @@ public class ImsResolver implements ImsServiceController.ImsServiceControllerCal
                    Log.d(TAG, "Updating Features - New Features: " + features);
                    controller.changeImsServiceFeatures(features);
                } else {
                    Log.i(TAG, "updateImsServiceFeatures: unbound with active features, rebinding");
                    Log.i(TAG, "updateImsServiceFeatures: unbound with active features, binding");
                    bindImsServiceWithFeatures(newInfo, features);
                }
                // If the carrier service features have changed, the device features will also
@@ -1068,6 +1127,7 @@ public class ImsResolver implements ImsServiceController.ImsServiceControllerCal
                // ImsService is retrieved from the cache. If the cache hasn't been populated yet,
                // the calls to unbind/bind will fail (intended during initial start up).
                unbindImsService(getImsServiceInfoFromCache(oldPackageName));
            }
            ImsServiceInfo newInfo = getImsServiceInfoFromCache(newPackageName);
            // if there is no carrier ImsService, newInfo is null. This we still want to update
            // bindings for device ImsService to pick up the missing features.
@@ -1082,7 +1142,6 @@ public class ImsResolver implements ImsServiceController.ImsServiceControllerCal
            }
        }
    }
    }

    /**
     * Schedules a query for dynamic ImsService features.
+3 −0
Original line number Diff line number Diff line
@@ -397,6 +397,9 @@ public class ImsServiceController {
            HashSet<ImsFeatureConfiguration.FeatureSlotPair> newImsFeatures)
            throws RemoteException {
        synchronized (mLock) {
            if (mImsFeatures.equals(newImsFeatures)) {
                return;
            }
            Log.i(LOG_TAG, "Features changed (" + mImsFeatures + "->" + newImsFeatures + ") for "
                    + "ImsService: " + mComponentName);
            HashSet<ImsFeatureConfiguration.FeatureSlotPair> oldImsFeatures =
+59 −35
Original line number Diff line number Diff line
@@ -46,6 +46,7 @@ import android.os.Bundle;
import android.os.PersistableBundle;
import android.os.RemoteException;
import android.telephony.CarrierConfigManager;
import android.telephony.TelephonyManager;
import android.telephony.ims.ImsService;
import android.telephony.ims.feature.ImsFeature;
import android.telephony.ims.stub.ImsFeatureConfiguration;
@@ -88,6 +89,8 @@ public class ImsResolverTest extends ImsTestBase {
    @Mock
    ImsResolver.SubscriptionManagerProxy mTestSubscriptionManagerProxy;
    @Mock
    ImsResolver.TelephonyManagerProxy mTestTelephonyManagerProxy;
    @Mock
    CarrierConfigManager mMockCarrierConfigManager;
    @Mock
    ImsResolver.ImsDynamicQueryManagerFactory mMockQueryManagerFactory;
@@ -129,7 +132,7 @@ public class ImsResolverTest extends ImsTestBase {
        setupController();

        // Complete package manager lookup and cache.
        startBind();
        startBindCarrierConfigAlreadySet();

        ImsResolver.ImsServiceInfo testCachedService =
                mTestImsResolver.getImsServiceInfoFromCache(
@@ -155,7 +158,7 @@ public class ImsResolverTest extends ImsTestBase {
        setupController();

        // Complete package manager lookup and cache.
        startBind();
        startBindCarrierConfigAlreadySet();

        ImsResolver.ImsServiceInfo testCachedService =
                mTestImsResolver.getImsServiceInfoFromCache(
@@ -185,7 +188,7 @@ public class ImsResolverTest extends ImsTestBase {
        ImsServiceController controller = setupController();

        // Start bind to carrier service
        startBind();
        startBindCarrierConfigAlreadySet();
        // setup features response
        setupDynamicQueryFeatures(TEST_CARRIER_DEFAULT_NAME, features, 1);

@@ -210,7 +213,7 @@ public class ImsResolverTest extends ImsTestBase {
        setupPackageQuery(TEST_CARRIER_DEFAULT_NAME, new HashSet<>(), true);
        ImsServiceController controller = setupController();

        startBind();
        startBindCarrierConfigAlreadySet();
        setupDynamicQueryFeatures(TEST_CARRIER_DEFAULT_NAME, features, 1);

        verify(controller).bind(features);
@@ -234,7 +237,7 @@ public class ImsResolverTest extends ImsTestBase {
        ImsServiceController controller = setupController();

        // Bind without emergency calling
        startBind();
        startBindCarrierConfigAlreadySet();
        setupDynamicQueryFeatures(TEST_CARRIER_DEFAULT_NAME, features, 1);
        verify(controller).bind(features);
        verify(controller, never()).unbind();
@@ -266,7 +269,7 @@ public class ImsResolverTest extends ImsTestBase {
        // Set the CarrierConfig string to null so that ImsResolver will not bind to the available
        // Services
        setConfigCarrierString(0, null);
        startBind();
        startBindCarrierConfigAlreadySet();

        waitForHandlerAction(mTestImsResolver.getHandler(), TEST_TIMEOUT);
        verify(mMockQueryManager, never()).startQuery(any(), any());
@@ -293,7 +296,7 @@ public class ImsResolverTest extends ImsTestBase {
        ImsServiceController controller = setupController();


        startBind();
        startBindNoCarrierConfig(1);
        // Wait to make sure that there are no dynamic queries that are being completed.
        waitForHandlerAction(mTestImsResolver.getHandler(), TEST_TIMEOUT);

@@ -333,7 +336,7 @@ public class ImsResolverTest extends ImsTestBase {
        ImsServiceController carrierController = mock(ImsServiceController.class);
        setImsServiceControllerFactory(deviceController, carrierController);

        startBind();
        startBindCarrierConfigAlreadySet();
        setupDynamicQueryFeatures(TEST_CARRIER_DEFAULT_NAME, carrierFeatures, 1);

        // Verify that all features that have been defined for the carrier override are bound
@@ -344,6 +347,7 @@ public class ImsResolverTest extends ImsTestBase {
        // device controller (including emergency voice for slot 0)
        HashSet<ImsFeatureConfiguration.FeatureSlotPair> deviceFeatureSet =
                convertToHashSet(deviceFeatures, 0);
        deviceFeatureSet.removeAll(carrierFeatures);
        verify(deviceController).bind(deviceFeatureSet);
        verify(deviceController, never()).unbind();
        assertEquals(TEST_DEVICE_DEFAULT_NAME, deviceController.getComponentName());
@@ -394,7 +398,7 @@ public class ImsResolverTest extends ImsTestBase {
        setupPackageQuery(info);
        ImsServiceController controller = setupController();
        // Bind using default features
        startBind();
        startBindNoCarrierConfig(2);
        HashSet<ImsFeatureConfiguration.FeatureSlotPair> featureSet =
                convertToHashSet(features, 0);
        featureSet.addAll(convertToHashSet(features, 1));
@@ -442,7 +446,7 @@ public class ImsResolverTest extends ImsTestBase {
        ImsServiceController carrierController = mock(ImsServiceController.class);
        setImsServiceControllerFactory(deviceController, carrierController);

        startBind();
        startBindCarrierConfigAlreadySet();
        setupDynamicQueryFeatures(TEST_CARRIER_DEFAULT_NAME, carrierFeatures, 1);

        // Verify that all features that have been defined for the carrier override are bound
@@ -455,9 +459,7 @@ public class ImsResolverTest extends ImsTestBase {
                convertToHashSet(deviceFeatures, 1);
        deviceFeatureSet.addAll(convertToHashSet(deviceFeatures, 0));
        deviceFeatureSet.removeAll(carrierFeatures);
        // we will first have bound to device and then the features will change once the dynamic
        // returns. So, instead of checking the bind parameters, we will check the change parameters
        verify(deviceController).changeImsServiceFeatures(deviceFeatureSet);
        verify(deviceController).bind(deviceFeatureSet);
        verify(deviceController, never()).unbind();
        assertEquals(TEST_DEVICE_DEFAULT_NAME, deviceController.getComponentName());

@@ -508,7 +510,7 @@ public class ImsResolverTest extends ImsTestBase {
        ImsServiceController carrierController = mock(ImsServiceController.class);
        setImsServiceControllerFactory(deviceController, carrierController);

        startBind();
        startBindCarrierConfigAlreadySet();
        setupDynamicQueryFeatures(TEST_CARRIER_DEFAULT_NAME, carrierFeatures, 1);
        // Verify that all features that have been defined for the carrier override are bound
        verify(carrierController).bind(carrierFeatures);
@@ -520,9 +522,7 @@ public class ImsResolverTest extends ImsTestBase {
                convertToHashSet(deviceFeatures, 1);
        deviceFeatureSet.addAll(convertToHashSet(deviceFeatures, 0));
        deviceFeatureSet.removeAll(carrierFeatures);
        // device ImsService will bind with all of its defined features first and then when the
        // carrier query comes back, it will change. So, checking change instead of bind here.
        verify(deviceController).changeImsServiceFeatures(deviceFeatureSet);
        verify(deviceController).bind(deviceFeatureSet);
        verify(deviceController, never()).unbind();
        assertEquals(TEST_DEVICE_DEFAULT_NAME, deviceController.getComponentName());

@@ -566,7 +566,7 @@ public class ImsResolverTest extends ImsTestBase {
        ImsServiceController carrierController = mock(ImsServiceController.class);
        setImsServiceControllerFactory(deviceController, carrierController);

        startBind();
        startBindCarrierConfigAlreadySet();
        setupDynamicQueryFeatures(TEST_CARRIER_DEFAULT_NAME, carrierFeatures, 1);
        // Verify that all features that have been defined for the carrier override are bound
        verify(carrierController).bind(carrierFeatures);
@@ -578,9 +578,7 @@ public class ImsResolverTest extends ImsTestBase {
                convertToHashSet(deviceFeatures, 1);
        deviceFeatureSet.addAll(convertToHashSet(deviceFeatures, 0));
        deviceFeatureSet.removeAll(carrierFeatures);
        // we will first have bound to device and then the features will change once the dynamic
        // returns. So, instead of checking the bind parameters, we will check the change parameters
        verify(deviceController).changeImsServiceFeatures(deviceFeatureSet);
        verify(deviceController).bind(deviceFeatureSet);
        verify(deviceController, never()).unbind();
        assertEquals(TEST_DEVICE_DEFAULT_NAME, deviceController.getComponentName());

@@ -624,7 +622,7 @@ public class ImsResolverTest extends ImsTestBase {
        ImsServiceController carrierController = mock(ImsServiceController.class);
        setImsServiceControllerFactory(deviceController, carrierController);

        startBind();
        startBindCarrierConfigAlreadySet();

        HashSet<ImsFeatureConfiguration.FeatureSlotPair> carrierFeatures = new HashSet<>();
        // Carrier service doesn't support the voice feature.
@@ -670,7 +668,7 @@ public class ImsResolverTest extends ImsTestBase {
        ImsServiceController carrierController = mock(ImsServiceController.class);
        setImsServiceControllerFactory(deviceController, carrierController);

        startBind();
        startBindCarrierConfigAlreadySet();
        setupDynamicQueryFeatures(TEST_CARRIER_DEFAULT_NAME, carrierFeatures, 1);

        // Tell the package manager that carrier app is uninstalled
@@ -714,14 +712,11 @@ public class ImsResolverTest extends ImsTestBase {
        ImsServiceController carrierController = mock(ImsServiceController.class);
        setImsServiceControllerFactory(deviceController, carrierController);

        startBind();
        startBindCarrierConfigAlreadySet();
        setupDynamicQueryFeatures(TEST_CARRIER_DEFAULT_NAME, carrierFeatures, 1);

        setConfigCarrierString(0, null);
        Intent carrierConfigIntent = new Intent();
        carrierConfigIntent.putExtra(CarrierConfigManager.EXTRA_SLOT_INDEX, 0);
        mTestCarrierConfigReceiver.onReceive(null, carrierConfigIntent);
        waitForHandlerAction(mTestImsResolver.getHandler(), TEST_TIMEOUT);
        sendCarrierConfigChanged(0, 0);

        // Verify that the carrier controller is unbound
        verify(carrierController).unbind();
@@ -768,14 +763,11 @@ public class ImsResolverTest extends ImsTestBase {
        ImsServiceController carrierController2 = mock(ImsServiceController.class);
        setImsServiceControllerFactory(deviceController, carrierController1, carrierController2);

        startBind();
        startBindCarrierConfigAlreadySet();
        setupDynamicQueryFeatures(TEST_CARRIER_DEFAULT_NAME, carrierFeatures1, 1);

        setConfigCarrierString(0, TEST_CARRIER_2_DEFAULT_NAME.getPackageName());
        Intent carrierConfigIntent = new Intent();
        carrierConfigIntent.putExtra(CarrierConfigManager.EXTRA_SLOT_INDEX, 0);
        mTestCarrierConfigReceiver.onReceive(null, carrierConfigIntent);
        waitForHandlerAction(mTestImsResolver.getHandler(), TEST_TIMEOUT);
        sendCarrierConfigChanged(0, 0);
        setupDynamicQueryFeatures(TEST_CARRIER_2_DEFAULT_NAME, carrierFeatures2, 1);

        // Verify that carrier 1 is unbound
@@ -816,7 +808,7 @@ public class ImsResolverTest extends ImsTestBase {
        setImsServiceControllerFactory(deviceController, carrierController);

        // Bind with device ImsService
        startBind();
        startBindCarrierConfigAlreadySet();

        // Boot complete happens and the Carrier ImsService is now available.
        HashSet<ImsFeatureConfiguration.FeatureSlotPair> carrierFeatures = new HashSet<>();
@@ -849,6 +841,8 @@ public class ImsResolverTest extends ImsTestBase {
                    mCarrierConfigs[i]);
            when(mTestSubscriptionManagerProxy.getSlotIndex(eq(i))).thenReturn(i);
            when(mTestSubscriptionManagerProxy.getSubId(eq(i))).thenReturn(i);
            when(mTestTelephonyManagerProxy.getSimState(any(Context.class), eq(i))).thenReturn(
                    TelephonyManager.SIM_STATE_READY);
        }

        mTestImsResolver = new ImsResolver(mMockContext, TEST_DEVICE_DEFAULT_NAME.getPackageName(),
@@ -865,6 +859,7 @@ public class ImsResolverTest extends ImsTestBase {
        mTestCarrierConfigReceiver = receiversCaptor.getAllValues().get(0);
        mTestBootCompleteReceiver = receiversCaptor.getAllValues().get(1);
        mTestImsResolver.setSubscriptionManagerProxy(mTestSubscriptionManagerProxy);
        mTestImsResolver.setTelephonyManagerProxy(mTestTelephonyManagerProxy);
        when(mMockQueryManagerFactory.create(any(Context.class),
                any(ImsServiceFeatureQueryManager.Listener.class))).thenReturn(mMockQueryManager);
        mTestImsResolver.setImsDynamicQueryManagerFactory(mMockQueryManagerFactory);
@@ -906,7 +901,11 @@ public class ImsResolverTest extends ImsTestBase {
        return controller;
    }

    private void startBind() {
    /**
     * In this case, there is a CarrierConfig already set for the sub/slot combo when initializing.
     * This automatically kicks off the binding internally.
     */
    private void startBindCarrierConfigAlreadySet() {
        mTestImsResolver.initialize();
        ArgumentCaptor<ImsServiceFeatureQueryManager.Listener> queryManagerCaptor =
                ArgumentCaptor.forClass(ImsServiceFeatureQueryManager.Listener.class);
@@ -915,6 +914,23 @@ public class ImsResolverTest extends ImsTestBase {
        waitForHandlerAction(mTestImsResolver.getHandler(), TEST_TIMEOUT);
    }

    /**
     * In this case, there is no carrier config override, send CarrierConfig loaded intent to all
     * slots, indicating that the SIMs are loaded and to bind the device default.
     */
    private void startBindNoCarrierConfig(int numSlots) {
        mTestImsResolver.initialize();
        ArgumentCaptor<ImsServiceFeatureQueryManager.Listener> queryManagerCaptor =
                ArgumentCaptor.forClass(ImsServiceFeatureQueryManager.Listener.class);
        verify(mMockQueryManagerFactory).create(any(Context.class), queryManagerCaptor.capture());
        mDynamicQueryListener = queryManagerCaptor.getValue();
        waitForHandlerAction(mTestImsResolver.getHandler(), TEST_TIMEOUT);
        // For ease of testing, slotId = subId
        for (int i = 0; i < numSlots; i++) {
            sendCarrierConfigChanged(i, i);
        }
    }

    private void setupDynamicQueryFeatures(ComponentName name,
            HashSet<ImsFeatureConfiguration.FeatureSlotPair> features, int times) {
        // wait for schedule to happen
@@ -1004,6 +1020,14 @@ public class ImsResolverTest extends ImsTestBase {
    }


    private void sendCarrierConfigChanged(int subId, int slotId) {
        Intent carrierConfigIntent = new Intent();
        carrierConfigIntent.putExtra(CarrierConfigManager.EXTRA_SUBSCRIPTION_INDEX, subId);
        carrierConfigIntent.putExtra(CarrierConfigManager.EXTRA_SLOT_INDEX, slotId);
        mTestCarrierConfigReceiver.onReceive(null, carrierConfigIntent);
        waitForHandlerAction(mTestImsResolver.getHandler(), TEST_TIMEOUT);
    }

    private void setConfigCarrierString(int subId, String packageName) {
        mCarrierConfigs[subId].putString(
                CarrierConfigManager.KEY_CONFIG_IMS_PACKAGE_OVERRIDE_STRING, packageName);