Home | History | Annotate | Download | only in ims
      1 /*
      2  * Copyright (C) 2017 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.internal.telephony.ims;
     18 
     19 import static junit.framework.Assert.assertEquals;
     20 import static junit.framework.Assert.assertFalse;
     21 import static junit.framework.Assert.assertTrue;
     22 
     23 import static org.mockito.Matchers.any;
     24 import static org.mockito.Matchers.anyInt;
     25 import static org.mockito.Matchers.eq;
     26 import static org.mockito.Mockito.never;
     27 import static org.mockito.Mockito.times;
     28 import static org.mockito.Mockito.verify;
     29 import static org.mockito.Mockito.when;
     30 
     31 import android.content.ComponentName;
     32 import android.content.Context;
     33 import android.content.Intent;
     34 import android.content.ServiceConnection;
     35 import android.os.Handler;
     36 import android.os.IBinder;
     37 import android.os.Looper;
     38 import android.os.RemoteException;
     39 import android.support.test.filters.FlakyTest;
     40 import android.support.test.runner.AndroidJUnit4;
     41 import android.telephony.ims.ImsService;
     42 import android.telephony.ims.stub.ImsFeatureConfiguration;
     43 
     44 import com.android.ims.internal.IImsServiceFeatureCallback;
     45 
     46 import org.junit.After;
     47 import org.junit.Before;
     48 import org.junit.Ignore;
     49 import org.junit.Test;
     50 import org.junit.runner.RunWith;
     51 import org.mockito.ArgumentCaptor;
     52 import org.mockito.Mock;
     53 import org.mockito.Spy;
     54 
     55 import java.util.HashSet;
     56 
     57 /**
     58  * Unit tests for ImsServiceController
     59  */
     60 @RunWith(AndroidJUnit4.class)
     61 @Ignore
     62 public class ImsServiceControllerTest extends ImsTestBase {
     63 
     64     private static final ImsServiceController.RebindRetry REBIND_RETRY =
     65             new ImsServiceController.RebindRetry() {
     66         @Override
     67         public long getStartDelay() {
     68             return 50;
     69         }
     70 
     71         @Override
     72         public long getMaximumDelay() {
     73             return 1000;
     74         }
     75     };
     76 
     77     @Spy TestImsServiceControllerAdapter mMockServiceControllerBinder;
     78     @Mock ImsServiceController.ImsServiceControllerCallbacks mMockCallbacks;
     79     @Mock IImsServiceFeatureCallback mMockProxyCallbacks;
     80     @Mock Context mMockContext;
     81     private final ComponentName mTestComponentName = new ComponentName("TestPkg",
     82             "ImsServiceControllerTest");
     83     private final Handler mHandler = new Handler(Looper.getMainLooper());
     84     private ImsServiceController mTestImsServiceController;
     85 
     86     @Before
     87     @Override
     88     public void setUp() throws Exception {
     89         super.setUp();
     90         mTestImsServiceController = new ImsServiceController(mMockContext, mTestComponentName,
     91                 mMockCallbacks, mHandler, REBIND_RETRY);
     92         mTestImsServiceController.addImsServiceFeatureCallback(mMockProxyCallbacks);
     93         when(mMockContext.bindService(any(), any(), anyInt())).thenReturn(true);
     94     }
     95 
     96 
     97     @After
     98     @Override
     99     public void tearDown() throws Exception {
    100         mTestImsServiceController = null;
    101         super.tearDown();
    102     }
    103 
    104     /**
    105      * Tests that Context.bindService is called with the correct parameters when we call bind.
    106      */
    107     @FlakyTest
    108     @Test
    109     public void testBindService() {
    110         HashSet<ImsFeatureConfiguration.FeatureSlotPair> testFeatures = new HashSet<>();
    111         // Slot 1, MMTel
    112         testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(1, 1));
    113         // Slot 1, RCS
    114         testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(1, 2));
    115         ArgumentCaptor<Intent> intentCaptor =
    116                 ArgumentCaptor.forClass(Intent.class);
    117 
    118         assertTrue(mTestImsServiceController.bind(testFeatures));
    119 
    120         int expectedFlags = Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE
    121                 | Context.BIND_IMPORTANT;
    122         verify(mMockContext).bindService(intentCaptor.capture(), any(), eq(expectedFlags));
    123         Intent testIntent = intentCaptor.getValue();
    124         assertEquals(ImsService.SERVICE_INTERFACE, testIntent.getAction());
    125         assertEquals(mTestComponentName, testIntent.getComponent());
    126     }
    127 
    128     /**
    129      * Verify that if bind is called multiple times, we only call bindService once.
    130      */
    131     @FlakyTest
    132     @Test
    133     public void testBindFailureWhenBound() {
    134         HashSet<ImsFeatureConfiguration.FeatureSlotPair> testFeatures = new HashSet<>();
    135         // Slot 1, MMTel
    136         testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(1, 1));
    137         bindAndConnectService(testFeatures);
    138 
    139         // already bound, should return false
    140         assertFalse(mTestImsServiceController.bind(testFeatures));
    141 
    142         verify(mMockContext, times(1)).bindService(any(), any(), anyInt());
    143     }
    144 
    145     /**
    146      * Tests ImsServiceController callbacks are properly called when an ImsService is bound and
    147      * connected.
    148      */
    149     @FlakyTest
    150     @Test
    151     public void testBindServiceAndConnected() throws RemoteException {
    152         HashSet<ImsFeatureConfiguration.FeatureSlotPair> testFeatures = new HashSet<>();
    153         // Slot 1, MMTel
    154         testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(1, 1));
    155         // Slot 1, RCS
    156         testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(1, 2));
    157 
    158         bindAndConnectService(testFeatures);
    159 
    160         IBinder binder = mMockServiceControllerBinder.getBinder().asBinder();
    161         verify(binder).linkToDeath(any(), anyInt());
    162         verify(mMockServiceControllerBinder).createMMTelFeature(eq(1));
    163         verify(mMockServiceControllerBinder).createRcsFeature(eq(1));
    164         verify(mMockCallbacks).imsServiceFeatureCreated(eq(1), eq(1),
    165                 eq(mTestImsServiceController));
    166         verify(mMockCallbacks).imsServiceFeatureCreated(eq(1), eq(2),
    167                 eq(mTestImsServiceController));
    168         verify(mMockProxyCallbacks).imsFeatureCreated(eq(1), eq(1));
    169         verify(mMockProxyCallbacks).imsFeatureCreated(eq(1), eq(2));
    170         assertEquals(mMockServiceControllerBinder.getBinder(),
    171                 mTestImsServiceController.getImsServiceControllerBinder());
    172     }
    173 
    174     /**
    175      * Tests Emergency MMTEL ImsServiceController callbacks are properly called when an ImsService
    176      * is bound and connected.
    177      */
    178     @FlakyTest
    179     @Test
    180     public void testBindEmergencyMmTel() throws RemoteException {
    181         HashSet<ImsFeatureConfiguration.FeatureSlotPair> testFeatures = new HashSet<>();
    182         // Slot 1, Emergency MMTel
    183         testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(1, 0));
    184         // Slot 1, MmTel
    185         testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(1, 1));
    186 
    187         bindAndConnectService(testFeatures);
    188 
    189         IBinder binder = mMockServiceControllerBinder.getBinder().asBinder();
    190         verify(binder).linkToDeath(any(), anyInt());
    191         verify(mMockServiceControllerBinder).createMMTelFeature(eq(1));
    192         // We do not want this callback to happen for emergency MMTEL
    193         verify(mMockCallbacks, never()).imsServiceFeatureCreated(eq(1), eq(0),
    194                 eq(mTestImsServiceController));
    195         verify(mMockCallbacks).imsServiceFeatureCreated(eq(1), eq(1),
    196                 eq(mTestImsServiceController));
    197         // Make sure this callback happens, which will notify the framework of emergency calling
    198         // availability.
    199         verify(mMockProxyCallbacks).imsFeatureCreated(eq(1), eq(0));
    200         verify(mMockProxyCallbacks).imsFeatureCreated(eq(1), eq(1));
    201         assertEquals(mMockServiceControllerBinder.getBinder(),
    202                 mTestImsServiceController.getImsServiceControllerBinder());
    203     }
    204 
    205     /**
    206      * Tests that if a callback is added after the ImsServiceController is already bound, we get a
    207      * imsFeatureCreated callback.
    208      */
    209     @FlakyTest
    210     @Test
    211     public void testCallbacksHappenWhenAddedAfterBind() throws RemoteException {
    212         HashSet<ImsFeatureConfiguration.FeatureSlotPair> testFeatures = new HashSet<>();
    213         // Slot 1, Emergency MMTel
    214         testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(1, 0));
    215         // Slot 1, MmTel
    216         testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(1, 1));
    217         mTestImsServiceController.removeImsServiceFeatureCallbacks();
    218 
    219         bindAndConnectService(testFeatures);
    220         // add the callback after bind
    221         mTestImsServiceController.addImsServiceFeatureCallback(mMockProxyCallbacks);
    222 
    223         // Make sure this callback happens for Emergency MMTEL and MMTEL
    224         verify(mMockProxyCallbacks).imsFeatureCreated(eq(1), eq(0));
    225         verify(mMockProxyCallbacks).imsFeatureCreated(eq(1), eq(1));
    226         assertEquals(mMockServiceControllerBinder.getBinder(),
    227                 mTestImsServiceController.getImsServiceControllerBinder());
    228     }
    229 
    230     /**
    231      * Tests ImsServiceController callbacks are properly called when an ImsService is bound and
    232      * connected.
    233      */
    234     @FlakyTest
    235     @Test
    236     public void testBindServiceAndConnectedDisconnected() throws RemoteException {
    237         HashSet<ImsFeatureConfiguration.FeatureSlotPair> testFeatures = new HashSet<>();
    238         // Slot 1, MMTel
    239         testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(1, 1));
    240         // Slot 1, RCS
    241         testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(1, 2));
    242         ServiceConnection conn = bindAndConnectService(testFeatures);
    243 
    244         conn.onServiceDisconnected(mTestComponentName);
    245 
    246         IBinder binder = mMockServiceControllerBinder.getBinder().asBinder();
    247         verify(binder).unlinkToDeath(any(), anyInt());
    248         // binder already disconnected, removeImsFeatures shouldn't be called.
    249         verify(mMockServiceControllerBinder, never()).removeImsFeature(anyInt(), anyInt());
    250         verify(mMockCallbacks).imsServiceFeatureRemoved(eq(1), eq(1),
    251                 eq(mTestImsServiceController));
    252         verify(mMockCallbacks).imsServiceFeatureRemoved(eq(1), eq(2),
    253                 eq(mTestImsServiceController));
    254         verify(mMockProxyCallbacks).imsFeatureRemoved(eq(1), eq(1));
    255         verify(mMockProxyCallbacks).imsFeatureRemoved(eq(1), eq(2));
    256     }
    257 
    258     /**
    259      * Tests ImsServiceController callbacks are properly called when an ImsService is bound and
    260      * connected.
    261      */
    262     @FlakyTest
    263     @Test
    264     public void testBindServiceBindUnbind() throws RemoteException {
    265         HashSet<ImsFeatureConfiguration.FeatureSlotPair> testFeatures = new HashSet<>();
    266         // Slot 1, MMTel
    267         testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(1, 1));
    268         // Slot 1, RCS
    269         testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(1, 2));
    270         ServiceConnection conn = bindAndConnectService(testFeatures);
    271 
    272         mTestImsServiceController.unbind();
    273 
    274         verify(mMockContext).unbindService(eq(conn));
    275         IBinder binder = mMockServiceControllerBinder.getBinder().asBinder();
    276         verify(binder).unlinkToDeath(any(), anyInt());
    277         verify(mMockServiceControllerBinder).removeImsFeature(eq(1), eq(1));
    278         verify(mMockServiceControllerBinder).removeImsFeature(eq(1), eq(2));
    279         verify(mMockCallbacks).imsServiceFeatureRemoved(eq(1), eq(1),
    280                 eq(mTestImsServiceController));
    281         verify(mMockCallbacks).imsServiceFeatureRemoved(eq(1), eq(2),
    282                 eq(mTestImsServiceController));
    283         verify(mMockProxyCallbacks).imsFeatureRemoved(eq(1), eq(1));
    284         verify(mMockProxyCallbacks).imsFeatureRemoved(eq(1), eq(2));
    285     }
    286 
    287     /**
    288      * Ensures that imsServiceFeatureRemoved is called when the binder dies in another process.
    289      */
    290     @FlakyTest
    291     @Test
    292     public void testBindServiceAndBinderDied() throws RemoteException {
    293         HashSet<ImsFeatureConfiguration.FeatureSlotPair> testFeatures = new HashSet<>();
    294         // Slot 1, MMTel
    295         testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(1, 1));
    296         // Slot 1, RCS
    297         testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(1, 2));
    298         bindAndConnectService(testFeatures);
    299         ArgumentCaptor<IBinder.DeathRecipient> deathCaptor =
    300                 ArgumentCaptor.forClass(IBinder.DeathRecipient.class);
    301         IBinder binder = mMockServiceControllerBinder.getBinder().asBinder();
    302         verify(binder).linkToDeath(deathCaptor.capture(), anyInt());
    303 
    304         deathCaptor.getValue().binderDied();
    305 
    306         verify(mMockCallbacks).imsServiceFeatureRemoved(eq(1), eq(1),
    307                 eq(mTestImsServiceController));
    308         verify(mMockCallbacks).imsServiceFeatureRemoved(eq(1), eq(2),
    309                 eq(mTestImsServiceController));
    310         verify(mMockProxyCallbacks).imsFeatureRemoved(eq(1), eq(1));
    311         verify(mMockProxyCallbacks).imsFeatureRemoved(eq(1), eq(2));
    312     }
    313 
    314     /**
    315      * Ensures ImsService and ImsResolver are notified when a feature is added.
    316      */
    317     @FlakyTest
    318     @Test
    319     public void testBindServiceAndAddFeature() throws RemoteException {
    320         HashSet<ImsFeatureConfiguration.FeatureSlotPair> testFeatures = new HashSet<>();
    321         // Slot 1, MMTel
    322         testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(1, 1));
    323         bindAndConnectService(testFeatures);
    324         verify(mMockServiceControllerBinder).createMMTelFeature(eq(1));
    325         verify(mMockCallbacks).imsServiceFeatureCreated(eq(1), eq(1),
    326                 eq(mTestImsServiceController));
    327         verify(mMockProxyCallbacks).imsFeatureCreated(eq(1), eq(1));
    328         // Create a new list with an additional item
    329         HashSet<ImsFeatureConfiguration.FeatureSlotPair> testFeaturesWithAddition = new HashSet<>(
    330                 testFeatures);
    331         testFeaturesWithAddition.add(new ImsFeatureConfiguration.FeatureSlotPair(2, 1));
    332 
    333         mTestImsServiceController.changeImsServiceFeatures(testFeaturesWithAddition);
    334 
    335         verify(mMockServiceControllerBinder).createMMTelFeature(eq(2));
    336         verify(mMockCallbacks).imsServiceFeatureCreated(eq(2), eq(1),
    337                 eq(mTestImsServiceController));
    338         verify(mMockProxyCallbacks).imsFeatureCreated(eq(2), eq(1));
    339     }
    340 
    341     /**
    342      * Ensures ImsService and ImsResolver are notified when a feature is added.
    343      */
    344     @FlakyTest
    345     @Test
    346     public void testBindServiceAndRemoveFeature() throws RemoteException {
    347         HashSet<ImsFeatureConfiguration.FeatureSlotPair> testFeatures = new HashSet<>();
    348         // Slot 1, MMTel
    349         testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(1, 1));
    350         // Slot 2, MMTel
    351         testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(2, 1));
    352         bindAndConnectService(testFeatures);
    353         verify(mMockServiceControllerBinder).createMMTelFeature(eq(1));
    354         verify(mMockCallbacks).imsServiceFeatureCreated(eq(1), eq(1),
    355                 eq(mTestImsServiceController));
    356         verify(mMockProxyCallbacks).imsFeatureCreated(eq(1), eq(1));
    357         verify(mMockServiceControllerBinder).createMMTelFeature(eq(2));
    358         verify(mMockCallbacks).imsServiceFeatureCreated(eq(2), eq(1),
    359                 eq(mTestImsServiceController));
    360         verify(mMockProxyCallbacks).imsFeatureCreated(eq(2), eq(1));
    361         // Create a new list with one less item
    362         HashSet<ImsFeatureConfiguration.FeatureSlotPair> testFeaturesWithSubtraction =
    363                 new HashSet<>(testFeatures);
    364         testFeaturesWithSubtraction.remove(new ImsFeatureConfiguration.FeatureSlotPair(2, 1));
    365 
    366         mTestImsServiceController.changeImsServiceFeatures(testFeaturesWithSubtraction);
    367 
    368         verify(mMockServiceControllerBinder).removeImsFeature(eq(2), eq(1));
    369         verify(mMockCallbacks).imsServiceFeatureRemoved(eq(2), eq(1),
    370                 eq(mTestImsServiceController));
    371         verify(mMockProxyCallbacks).imsFeatureRemoved(eq(2), eq(1));
    372     }
    373 
    374     /**
    375      * Ensures ImsService and ImsResolver are notified when all features are removed.
    376      */
    377     @FlakyTest
    378     @Test
    379     public void testBindServiceAndRemoveAllFeatures() throws RemoteException {
    380         HashSet<ImsFeatureConfiguration.FeatureSlotPair> testFeatures = new HashSet<>();
    381         // slot 1, MMTel
    382         testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(1, 1));
    383         // slot 2, MMTel
    384         testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(2, 1));
    385         bindAndConnectService(testFeatures);
    386         verify(mMockServiceControllerBinder).createMMTelFeature(eq(1));
    387         verify(mMockCallbacks).imsServiceFeatureCreated(eq(1), eq(1),
    388                 eq(mTestImsServiceController));
    389         verify(mMockProxyCallbacks).imsFeatureCreated(eq(1), eq(1));
    390         verify(mMockServiceControllerBinder).createMMTelFeature(eq(2));
    391         verify(mMockCallbacks).imsServiceFeatureCreated(eq(2), eq(1),
    392                 eq(mTestImsServiceController));
    393         verify(mMockProxyCallbacks).imsFeatureCreated(eq(2), eq(1));
    394 
    395         // Create a new empty list
    396         mTestImsServiceController.changeImsServiceFeatures(new HashSet<>());
    397 
    398         verify(mMockServiceControllerBinder).removeImsFeature(eq(1), eq(1));
    399         verify(mMockCallbacks).imsServiceFeatureRemoved(eq(1), eq(1),
    400                 eq(mTestImsServiceController));
    401         verify(mMockProxyCallbacks).imsFeatureRemoved(eq(1), eq(1));
    402         verify(mMockServiceControllerBinder).removeImsFeature(eq(2), eq(1));
    403         verify(mMockCallbacks).imsServiceFeatureRemoved(eq(2), eq(1),
    404                 eq(mTestImsServiceController));
    405         verify(mMockProxyCallbacks).imsFeatureRemoved(eq(2), eq(1));
    406     }
    407 
    408     /**
    409      * Verifies that nothing is notified of a feature change if the service is not bound.
    410      */
    411     @FlakyTest
    412     @Test
    413     public void testBindUnbindServiceAndAddFeature() throws RemoteException {
    414         HashSet<ImsFeatureConfiguration.FeatureSlotPair> testFeatures = new HashSet<>();
    415         // Slot 1, MMTel
    416         testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(1, 1));
    417         bindAndConnectService(testFeatures);
    418         mTestImsServiceController.unbind();
    419         // Create a new list with an additional item
    420         HashSet<ImsFeatureConfiguration.FeatureSlotPair> testFeaturesWithAddition = new HashSet<>(
    421                 testFeatures);
    422         // Try to create an RCS feature
    423         testFeaturesWithAddition.add(new ImsFeatureConfiguration.FeatureSlotPair(1, 2));
    424 
    425         mTestImsServiceController.changeImsServiceFeatures(testFeaturesWithAddition);
    426 
    427         verify(mMockServiceControllerBinder, never()).createRcsFeature(eq(1));
    428         verify(mMockCallbacks, never()).imsServiceFeatureCreated(eq(1), eq(2),
    429                 eq(mTestImsServiceController));
    430         verify(mMockProxyCallbacks, never()).imsFeatureCreated(eq(1), eq(2));
    431     }
    432 
    433     /**
    434      * Verifies that the ImsServiceController automatically tries to bind again after an untimely
    435      * binder death.
    436      */
    437     @FlakyTest
    438     @Test
    439     public void testAutoBindAfterBinderDied() throws RemoteException {
    440         HashSet<ImsFeatureConfiguration.FeatureSlotPair> testFeatures = new HashSet<>();
    441         // Slot 1, MMTel
    442         testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(1, 1));
    443         // Slot 1, RCS
    444         testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(1, 2));
    445         bindAndConnectService(testFeatures);
    446 
    447         getDeathRecipient().binderDied();
    448 
    449         long delay = mTestImsServiceController.getRebindDelay();
    450         waitForHandlerActionDelayed(mHandler, delay, 2 * delay);
    451         // The service should autobind after rebind event occurs
    452         verify(mMockContext, times(2)).bindService(any(), any(), anyInt());
    453     }
    454 
    455     /**
    456      * Ensure that bindService has only been called once before automatic rebind occurs.
    457      */
    458     @FlakyTest
    459     @Test
    460     public void testNoAutoBindBeforeTimeout() throws RemoteException {
    461         HashSet<ImsFeatureConfiguration.FeatureSlotPair> testFeatures = new HashSet<>();
    462         // Slot 1, MMTel
    463         testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(1, 1));
    464         // Slot 1, RCS
    465         testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(1, 2));
    466         bindAndConnectService(testFeatures);
    467 
    468         getDeathRecipient().binderDied();
    469 
    470         // Be sure that there are no binds before the RETRY_TIMEOUT expires
    471         verify(mMockContext, times(1)).bindService(any(), any(), anyInt());
    472     }
    473 
    474     /**
    475      * Ensure that calling unbind stops automatic rebind of the ImsService from occuring.
    476      */
    477     @FlakyTest
    478     @Test
    479     public void testUnbindCauseAutoBindCancelAfterBinderDied() throws RemoteException {
    480         HashSet<ImsFeatureConfiguration.FeatureSlotPair> testFeatures = new HashSet<>();
    481         // Slot 1, MMTel
    482         testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(1, 1));
    483         // Slot 1, RCS
    484         testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(1, 2));
    485         bindAndConnectService(testFeatures);
    486 
    487         getDeathRecipient().binderDied();
    488         mTestImsServiceController.unbind();
    489 
    490         long delay = mTestImsServiceController.getRebindDelay();
    491         waitForHandlerActionDelayed(mHandler, delay, 2 * delay);
    492 
    493         // Unbind should stop the autobind from occurring.
    494         verify(mMockContext, times(1)).bindService(any(), any(), anyInt());
    495     }
    496 
    497     /**
    498      * Ensure that calling bind causes the automatic rebinding to be cancelled or not cause another
    499      * call to bindService.
    500      */
    501     @FlakyTest
    502     @Test
    503     public void testBindCauseAutoBindCancelAfterBinderDied() throws RemoteException {
    504         HashSet<ImsFeatureConfiguration.FeatureSlotPair> testFeatures = new HashSet<>();
    505         // Slot 1, MMTel
    506         testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(1, 1));
    507         // Slot 1, RCS
    508         testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(1, 2));
    509         bindAndConnectService(testFeatures);
    510         getDeathRecipient().binderDied();
    511         mTestImsServiceController.bind(testFeatures);
    512 
    513         long delay = mTestImsServiceController.getRebindDelay();
    514         waitForHandlerActionDelayed(mHandler, delay, 2 * delay);
    515         // Should only see two binds, not three from the auto rebind that occurs.
    516         verify(mMockContext, times(2)).bindService(any(), any(), anyInt());
    517     }
    518 
    519     private ServiceConnection bindAndConnectService(
    520             HashSet<ImsFeatureConfiguration.FeatureSlotPair> testFeatures) {
    521         ArgumentCaptor<ServiceConnection> serviceCaptor =
    522                 ArgumentCaptor.forClass(ServiceConnection.class);
    523         assertTrue(mTestImsServiceController.bind(testFeatures));
    524         verify(mMockContext).bindService(any(), serviceCaptor.capture(), anyInt());
    525         serviceCaptor.getValue().onServiceConnected(mTestComponentName,
    526                 mMockServiceControllerBinder.getBinder().asBinder());
    527         return serviceCaptor.getValue();
    528     }
    529 
    530     private IBinder.DeathRecipient getDeathRecipient() throws RemoteException {
    531         ArgumentCaptor<IBinder.DeathRecipient> deathCaptor =
    532                 ArgumentCaptor.forClass(IBinder.DeathRecipient.class);
    533         IBinder binder = mMockServiceControllerBinder.getBinder().asBinder();
    534         verify(binder).linkToDeath(deathCaptor.capture(), anyInt());
    535         return deathCaptor.getValue();
    536     }
    537 }
    538