Merge "Cleanup the SipDelegates associated with an app if it dies" am: 95e5e3b3a9 am: 549b8da748 am: 96b1ecbc3c

Original change: https://android-review.googlesource.com/c/platform/packages/services/Telephony/+/1685288

Change-Id: Ie485f459e8cb773368ae055992af19c8033b6c24
diff --git a/src/com/android/services/telephony/rcs/MessageTransportStateTracker.java b/src/com/android/services/telephony/rcs/MessageTransportStateTracker.java
index b2dcfe8..e640735 100644
--- a/src/com/android/services/telephony/rcs/MessageTransportStateTracker.java
+++ b/src/com/android/services/telephony/rcs/MessageTransportStateTracker.java
@@ -361,6 +361,13 @@
     }
 
     /**
+     * @return The remote application's message callback.
+     */
+    public ISipDelegateMessageCallback getAppMessageCallback() {
+        return mAppCallback;
+    }
+
+    /**
      * @return MessageCallback implementation to be sent to the ImsService.
      */
     public ISipDelegateMessageCallback getMessageCallback() {
diff --git a/src/com/android/services/telephony/rcs/SipDelegateController.java b/src/com/android/services/telephony/rcs/SipDelegateController.java
index 2d6d4f0..8cd4365 100644
--- a/src/com/android/services/telephony/rcs/SipDelegateController.java
+++ b/src/com/android/services/telephony/rcs/SipDelegateController.java
@@ -136,11 +136,21 @@
         return mPackageName;
     }
 
+    /**
+     * @return The ImsService's SIP delegate binder impl associated with this controller.
+     */
     public ISipDelegate getSipDelegateInterface() {
         return mMessageTransportStateTracker.getDelegateConnection();
     }
 
     /**
+     * @return The IMS app's message callback binder.
+     */
+    public ISipDelegateMessageCallback getAppMessageCallback() {
+        return mMessageTransportStateTracker.getAppMessageCallback();
+    }
+
+    /**
      * Create the underlying SipDelegate.
      * <p>
      * This may not happen instantly, The CompletableFuture returned will not complete until
diff --git a/src/com/android/services/telephony/rcs/SipTransportController.java b/src/com/android/services/telephony/rcs/SipTransportController.java
index cecc8a2..6ffffaf 100644
--- a/src/com/android/services/telephony/rcs/SipTransportController.java
+++ b/src/com/android/services/telephony/rcs/SipTransportController.java
@@ -20,6 +20,7 @@
 import android.app.role.RoleManager;
 import android.content.Context;
 import android.os.PersistableBundle;
+import android.os.RemoteCallbackList;
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.telephony.CarrierConfigManager;
@@ -172,6 +173,34 @@
     }
 
     /**
+     * Extends RemoteCallbackList to track callbacks to the IMS applications with
+     * SipDelegateConnections and cleans them up if they die.
+     */
+    private class TrackedAppBinders extends RemoteCallbackList<ISipDelegateMessageCallback> {
+        @Override
+        public void onCallbackDied(ISipDelegateMessageCallback callback, Object cookie) {
+            mExecutorService.execute(() -> {
+                if (cookie instanceof SipDelegateController) {
+                    SipDelegateController c = (SipDelegateController) cookie;
+                    logi("onCallbackDied - Cleaning up delegates associated with package: "
+                            + c.getPackageName());
+                    boolean isNewDestroyQueued = addPendingDestroy(c,
+                            SipDelegateManager.SIP_DELEGATE_DESTROY_REASON_SERVICE_DEAD);
+                    if (isNewDestroyQueued) {
+                        CompletableFuture<Void> f = new CompletableFuture<>();
+                        scheduleReevaluateNow(f);
+                        f.thenRun(() -> logi("onCallbackDied - clean up complete for package: "
+                                + c.getPackageName()));
+                    }
+                } else {
+                    logw("onCallbackDied: unexpected - cookie is not an instance of "
+                            + "SipDelegateController");
+                }
+            });
+        }
+    }
+
+    /**
      * Used in {@link #destroySipDelegate(int, ISipDelegate, int)} to store pending destroy
      * requests.
      */
@@ -190,13 +219,16 @@
             if (this == o) return true;
             if (o == null || getClass() != o.getClass()) return false;
             DestroyRequest that = (DestroyRequest) o;
-            return reason == that.reason
-                    && controller.equals(that.controller);
+            // Only use controller for comparison, as we want to only have one DestroyRequest active
+            // per controller.
+            return controller.equals(that.controller);
         }
 
         @Override
         public int hashCode() {
-            return java.util.Objects.hash(controller, reason);
+            // Only use controller for hash, as we want to only have one DestroyRequest active per
+            // controller.
+            return java.util.Objects.hash(controller);
         }
 
         @Override
@@ -233,6 +265,8 @@
     private final List<SipDelegateController> mDelegatePendingCreate = new ArrayList<>();
     // SipDelegateControllers that are pending to be destroyed.
     private final List<DestroyRequest> mDelegatePendingDestroy = new ArrayList<>();
+    // Cache of Binders to remote IMS applications for tracking their potential death
+    private final TrackedAppBinders mActiveAppBinders = new TrackedAppBinders();
 
     // Future scheduled for operations that require the list of SipDelegateControllers to
     // be evaluated. When the timer expires and triggers the reevaluate method, this controller
@@ -254,7 +288,7 @@
     // Callback to monitor rcs provisioning change
     private CarrierConfigManager mCarrierConfigManager;
     // Cached allowed feature tags from carrier config
-    ArraySet<String> mFeatureTagsAllowed = new ArraySet<>();
+    private ArraySet<String> mFeatureTagsAllowed = new ArraySet<>();
 
     /**
      * Create an instance of SipTransportController.
@@ -660,6 +694,11 @@
             return;
         }
 
+        // Remove tracking for all SipDelegates being destroyed first
+        for (DestroyRequest d : mDelegatePendingDestroy) {
+            logi("reevaluateDelegates: starting destroy for: " + d.controller.getPackageName());
+            mActiveAppBinders.unregister(d.controller.getAppMessageCallback());
+        }
         // Destroy all pending destroy delegates first. Order doesn't matter.
         List<CompletableFuture<Void>> pendingDestroyList = mDelegatePendingDestroy.stream()
                 .map(d -> triggerDestroy(d.controller, d.reason)).collect(
@@ -673,7 +712,8 @@
         // Add newly created SipDelegates to end of queue before evaluating associated features.
         mDelegatePriorityQueue.addAll(mDelegatePendingCreate);
         for (SipDelegateController c : mDelegatePendingCreate) {
-            logi("reevaluateDelegates: pending create: " + c);
+            logi("reevaluateDelegates: pending create: " + c.getPackageName());
+            mActiveAppBinders.register(c.getAppMessageCallback(), c);
         }
         mDelegatePendingCreate.clear();
 
@@ -704,8 +744,12 @@
 
         // Executor doesn't matter here, schedule an event to update the IMS registration.
         mEvaluateCompleteFuture = pendingChange
-                .thenAccept((associatedFeatures) -> {
-                    logi("reevaluateDelegates: reevaluate complete," + " feature tags associated: "
+                .whenComplete((f, ex) -> {
+                    if (ex != null) {
+                        logw("reevaluateDelegates: Exception caught: " + ex);
+                    }
+                }).thenAccept((associatedFeatures) -> {
+                    logi("reevaluateDelegates: reevaluate complete, feature tags associated: "
                             + associatedFeatures);
                     scheduleUpdateRegistration();
                 });
diff --git a/tests/src/com/android/services/telephony/rcs/SipTransportControllerTest.java b/tests/src/com/android/services/telephony/rcs/SipTransportControllerTest.java
index d364fe4..0f139f8 100644
--- a/tests/src/com/android/services/telephony/rcs/SipTransportControllerTest.java
+++ b/tests/src/com/android/services/telephony/rcs/SipTransportControllerTest.java
@@ -62,6 +62,7 @@
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
 
 import java.util.ArrayList;
@@ -87,17 +88,25 @@
         public final String packageName;
         public final DelegateRequest delegateRequest;
         public final SipDelegateController delegateController;
-        public final ISipDelegate mMockDelegate;
-        public final IBinder mMockDelegateBinder;
+        private final ISipDelegate mMockDelegate;
+        public final IBinder mockDelegateBinder;
+        public final ISipDelegateConnectionStateCallback mockDelegateConnectionCallback;
+        public final ISipDelegateMessageCallback mockMessageCallback;
+        public final IBinder mockMessageCallbackBinder;
 
         SipDelegateControllerContainer(int id, String name, DelegateRequest request) {
             delegateController = mock(SipDelegateController.class);
             mMockDelegate = mock(ISipDelegate.class);
-            mMockDelegateBinder = mock(IBinder.class);
-            doReturn(mMockDelegateBinder).when(mMockDelegate).asBinder();
+            mockDelegateBinder = mock(IBinder.class);
+            doReturn(mockDelegateBinder).when(mMockDelegate).asBinder();
+            mockDelegateConnectionCallback = mock(ISipDelegateConnectionStateCallback.class);
+            mockMessageCallback = mock(ISipDelegateMessageCallback.class);
+            mockMessageCallbackBinder = mock(IBinder.class);
+            doReturn(mockMessageCallbackBinder).when(mockMessageCallback).asBinder();
             doReturn(name).when(delegateController).getPackageName();
             doReturn(request).when(delegateController).getInitialRequest();
             doReturn(mMockDelegate).when(delegateController).getSipDelegateInterface();
+            doReturn(mockMessageCallback).when(delegateController).getAppMessageCallback();
             subId = id;
             packageName = name;
             delegateRequest = request;
@@ -107,8 +116,6 @@
     @Mock private RcsFeatureManager mRcsManager;
     @Mock private ISipTransport mSipTransport;
     @Mock private IImsRegistration mImsRegistration;
-    @Mock private ISipDelegateConnectionStateCallback mMockStateCallback;
-    @Mock private ISipDelegateMessageCallback mMockMessageCallback;
     @Mock private SipTransportController.SipDelegateControllerFactory
             mMockDelegateControllerFactory;
     @Mock private SipTransportController.RoleManagerAdapter mMockRoleManager;
@@ -249,7 +256,8 @@
         try {
             controller.createSipDelegate(TEST_SUB_ID + 1,
                     new DelegateRequest(Collections.emptySet()), TEST_PACKAGE_NAME,
-                    mMockStateCallback, mMockMessageCallback);
+                    mock(ISipDelegateConnectionStateCallback.class),
+                    mock(ISipDelegateMessageCallback.class));
             fail();
         } catch (ImsException e) {
             assertEquals(ImsException.CODE_ERROR_INVALID_SUBSCRIPTION, e.getCode());
@@ -265,7 +273,8 @@
         try {
             controller.createSipDelegate(TEST_SUB_ID,
                     new DelegateRequest(Collections.emptySet()), TEST_PACKAGE_NAME,
-                    mMockStateCallback, mMockMessageCallback);
+                    mock(ISipDelegateConnectionStateCallback.class),
+                    mock(ISipDelegateMessageCallback.class));
             fail();
         } catch (ImsException e) {
             assertEquals(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION, e.getCode());
@@ -282,7 +291,8 @@
         try {
             controller.createSipDelegate(TEST_SUB_ID,
                     new DelegateRequest(Collections.emptySet()), TEST_PACKAGE_NAME,
-                    mMockStateCallback, mMockMessageCallback);
+                    mock(ISipDelegateConnectionStateCallback.class),
+                    mock(ISipDelegateMessageCallback.class));
             fail();
         } catch (ImsException e) {
             assertEquals(ImsException.CODE_ERROR_SERVICE_UNAVAILABLE, e.getCode());
@@ -296,9 +306,8 @@
 
         DelegateRequest r = getBaseDelegateRequest();
 
-        SipDelegateController c = injectMockDelegateController(TEST_PACKAGE_NAME, r);
-        createDelegateAndVerify(controller, c, r, r.getFeatureTags(), Collections.emptySet(),
-                TEST_PACKAGE_NAME);
+        SipDelegateControllerContainer c = injectMockDelegateController(TEST_PACKAGE_NAME, r);
+        createDelegateAndVerify(controller, c, r.getFeatureTags(), Collections.emptySet());
         verifyDelegateRegistrationChangedEvent(1 /*times*/, 0 /*waitMs*/);
         triggerFullNetworkRegistrationAndVerify(controller, c);
     }
@@ -309,19 +318,45 @@
         SipTransportController controller = setupLiveTransportController();
 
         DelegateRequest r = getBaseDelegateRequest();
-        SipDelegateController c = injectMockDelegateController(TEST_PACKAGE_NAME, r);
-        createDelegateAndVerify(controller, c, r, r.getFeatureTags(), Collections.emptySet(),
-                TEST_PACKAGE_NAME);
+        SipDelegateControllerContainer c = injectMockDelegateController(TEST_PACKAGE_NAME, r);
+        createDelegateAndVerify(controller, c, r.getFeatureTags(), Collections.emptySet());
+        verify(c.mockMessageCallbackBinder).linkToDeath(any(), anyInt());
         verifyDelegateRegistrationChangedEvent(1, 0 /*throttle*/);
 
         destroyDelegateAndVerify(controller, c, false,
                 SipDelegateManager.SIP_DELEGATE_DESTROY_REASON_REQUESTED_BY_APP);
+        verify(c.mockMessageCallbackBinder).unlinkToDeath(any(), anyInt());
         verifyDelegateRegistrationChangedEvent(2 /*times*/, 0 /*waitMs*/);
         triggerFullNetworkRegistrationAndVerifyNever(controller, c);
     }
 
     @SmallTest
     @Test
+    public void createDestroyAppDied() throws Exception {
+        SipTransportController controller = setupLiveTransportController();
+        DelegateRequest r = getBaseDelegateRequest();
+        SipDelegateControllerContainer c = injectMockDelegateController(TEST_PACKAGE_NAME, r);
+        createDelegateAndVerify(controller, c, r.getFeatureTags(), Collections.emptySet());
+        ArgumentCaptor<IBinder.DeathRecipient> captor =
+                ArgumentCaptor.forClass(IBinder.DeathRecipient.class);
+        verify(c.mockMessageCallbackBinder).linkToDeath(captor.capture(), anyInt());
+        IBinder.DeathRecipient deathRecipient = captor.getValue();
+        assertNotNull(deathRecipient);
+        verifyDelegateRegistrationChangedEvent(1, 0 /*throttle*/);
+
+        CompletableFuture<Integer> pendingDestroy = setDestroyFuture(c.delegateController, true,
+                SipDelegateManager.SIP_DELEGATE_DESTROY_REASON_SERVICE_DEAD);
+        // Simulate app dying
+        deathRecipient.binderDied();
+        waitForExecutorAction(mExecutorService, TIMEOUT_MS);
+        verifyDestroyDelegate(c.delegateController, pendingDestroy, true,
+                SipDelegateManager.SIP_DELEGATE_DESTROY_REASON_SERVICE_DEAD);
+        // If binderDied is called, then unregister does not lead to unlinkToDeath
+        triggerFullNetworkRegistrationAndVerifyNever(controller, c);
+    }
+
+    @SmallTest
+    @Test
     public void testCreateButNotInRole() throws Exception {
         SipTransportController controller = setupLiveTransportController();
 
@@ -330,9 +365,8 @@
                 SipDelegateManager.DENIED_REASON_NOT_ALLOWED);
 
         // Try to create a SipDelegate for a package that is not the default sms role.
-        SipDelegateController c = injectMockDelegateController(TEST_PACKAGE_NAME_2, r);
-        createDelegateAndVerify(controller, c, r, Collections.emptySet(), getDeniedTags,
-                TEST_PACKAGE_NAME_2);
+        SipDelegateControllerContainer c = injectMockDelegateController(TEST_PACKAGE_NAME_2, r);
+        createDelegateAndVerify(controller, c, Collections.emptySet(), getDeniedTags);
     }
 
     @SmallTest
@@ -345,10 +379,9 @@
         ArraySet<String> firstDelegate = new ArraySet<>(getBaseDelegateRequest().getFeatureTags());
         firstDelegate.remove(ImsSignallingUtils.GROUP_CHAT_TAG);
         DelegateRequest firstDelegateRequest = new DelegateRequest(firstDelegate);
-        SipDelegateController c1 = injectMockDelegateController(TEST_PACKAGE_NAME,
+        SipDelegateControllerContainer c1 = injectMockDelegateController(TEST_PACKAGE_NAME,
                 firstDelegateRequest);
-        createDelegateAndVerify(controller, c1, firstDelegateRequest, firstDelegate,
-                Collections.emptySet(), TEST_PACKAGE_NAME);
+        createDelegateAndVerify(controller, c1, firstDelegate, Collections.emptySet());
         // there is a delay in the indication to update reg, so it should not happen yet.
         verifyNoDelegateRegistrationChangedEvent();
 
@@ -360,10 +393,10 @@
         Pair<Set<String>, Set<FeatureTagState>> grantedAndDenied = getAllowedAndDeniedTagsForConfig(
                 secondDelegateRequest, SipDelegateManager.DENIED_REASON_IN_USE_BY_ANOTHER_DELEGATE,
                 firstDelegate);
-        SipDelegateController c2 = injectMockDelegateController(TEST_PACKAGE_NAME,
+        SipDelegateControllerContainer c2 = injectMockDelegateController(TEST_PACKAGE_NAME,
                 secondDelegateRequest);
-        createDelegateAndVerify(controller, c2, secondDelegateRequest, grantedAndDenied.first,
-                grantedAndDenied.second, TEST_PACKAGE_NAME, 1);
+        createDelegateAndVerify(controller, c2, grantedAndDenied.first,
+                grantedAndDenied.second, 1);
         // a reg changed event should happen after wait.
         verifyDelegateRegistrationChangedEvent(1, 2 * THROTTLE_MS);
     }
@@ -377,10 +410,10 @@
         Set<FeatureTagState> firstDeniedTags = getDeniedTagsForReason(
                 firstDelegateRequest.getFeatureTags(),
                 SipDelegateManager.DENIED_REASON_NOT_ALLOWED);
-        SipDelegateController c1 = injectMockDelegateController(TEST_PACKAGE_NAME,
+        SipDelegateControllerContainer c1 = injectMockDelegateController(TEST_PACKAGE_NAME,
                 firstDelegateRequest);
-        createDelegateAndVerify(controller, c1, firstDelegateRequest,
-                firstDelegateRequest.getFeatureTags(), Collections.emptySet(), TEST_PACKAGE_NAME);
+        createDelegateAndVerify(controller, c1, firstDelegateRequest.getFeatureTags(),
+                Collections.emptySet());
         verifyDelegateRegistrationChangedEvent(1 /*times*/, THROTTLE_MS);
 
         DelegateRequest secondDelegateRequest = getBaseDelegateRequest();
@@ -388,16 +421,16 @@
                 secondDelegateRequest.getFeatureTags(),
                 SipDelegateManager.DENIED_REASON_NOT_ALLOWED);
         // Try to create a SipDelegate for a package that is not the default sms role.
-        SipDelegateController c2 = injectMockDelegateController(TEST_PACKAGE_NAME_2,
+        SipDelegateControllerContainer c2 = injectMockDelegateController(TEST_PACKAGE_NAME_2,
                 secondDelegateRequest);
-        createDelegateAndVerify(controller, c2, secondDelegateRequest, Collections.emptySet(),
-                secondDeniedTags, TEST_PACKAGE_NAME_2, 1);
+        createDelegateAndVerify(controller, c2, Collections.emptySet(), secondDeniedTags, 1);
 
         // now swap the SMS role.
-        CompletableFuture<Boolean> pendingC1Change = setChangeSupportedFeatureTagsFuture(c1,
-                Collections.emptySet(), firstDeniedTags);
-        CompletableFuture<Boolean> pendingC2Change = setChangeSupportedFeatureTagsFuture(c2,
-                secondDelegateRequest.getFeatureTags(), Collections.emptySet());
+        CompletableFuture<Boolean> pendingC1Change = setChangeSupportedFeatureTagsFuture(
+                c1.delegateController, Collections.emptySet(), firstDeniedTags);
+        CompletableFuture<Boolean> pendingC2Change = setChangeSupportedFeatureTagsFuture(
+                c2.delegateController, secondDelegateRequest.getFeatureTags(),
+                Collections.emptySet());
         setSmsRoleAndEvaluate(controller, TEST_PACKAGE_NAME_2);
         // swapping roles should trigger a deregistration event on the ImsService side.
         verifyDelegateDeregistrationEvent();
@@ -405,17 +438,18 @@
         verifyDelegateRegistrationChangedEvent(1 /*times*/, THROTTLE_MS);
         // trigger completion stage to run
         waitForExecutorAction(mExecutorService, TIMEOUT_MS);
-        verify(c1).changeSupportedFeatureTags(Collections.emptySet(), firstDeniedTags);
+        verify(c1.delegateController).changeSupportedFeatureTags(Collections.emptySet(),
+                firstDeniedTags);
         // we should not get a change for c2 until pendingC1Change completes.
-        verify(c2, never()).changeSupportedFeatureTags(secondDelegateRequest.getFeatureTags(),
-                Collections.emptySet());
+        verify(c2.delegateController, never()).changeSupportedFeatureTags(
+                secondDelegateRequest.getFeatureTags(), Collections.emptySet());
         // ensure we are not blocking executor here
         waitForExecutorAction(mExecutorService, TIMEOUT_MS);
         completePendingChange(pendingC1Change, true);
         // trigger completion stage to run
         waitForExecutorAction(mExecutorService, TIMEOUT_MS);
-        verify(c2).changeSupportedFeatureTags(secondDelegateRequest.getFeatureTags(),
-                Collections.emptySet());
+        verify(c2.delegateController).changeSupportedFeatureTags(
+                secondDelegateRequest.getFeatureTags(), Collections.emptySet());
         // ensure we are not blocking executor here
         waitForExecutorAction(mExecutorService, TIMEOUT_MS);
         completePendingChange(pendingC2Change, true);
@@ -432,10 +466,9 @@
         ArraySet<String> firstDelegate = new ArraySet<>(getBaseDelegateRequest().getFeatureTags());
         firstDelegate.remove(ImsSignallingUtils.GROUP_CHAT_TAG);
         DelegateRequest firstDelegateRequest = new DelegateRequest(firstDelegate);
-        SipDelegateController c1 = injectMockDelegateController(TEST_PACKAGE_NAME,
+        SipDelegateControllerContainer c1 = injectMockDelegateController(TEST_PACKAGE_NAME,
                 firstDelegateRequest);
-        createDelegateAndVerify(controller, c1, firstDelegateRequest, firstDelegate,
-                Collections.emptySet(), TEST_PACKAGE_NAME);
+        createDelegateAndVerify(controller, c1, firstDelegate, Collections.emptySet());
         verifyNoDelegateRegistrationChangedEvent();
 
         // First delegate requests RCS message + Group RCS message. For this delegate, single RCS
@@ -446,21 +479,21 @@
         Pair<Set<String>, Set<FeatureTagState>> grantedAndDenied = getAllowedAndDeniedTagsForConfig(
                 secondDelegateRequest, SipDelegateManager.DENIED_REASON_IN_USE_BY_ANOTHER_DELEGATE,
                 firstDelegate);
-        SipDelegateController c2 = injectMockDelegateController(TEST_PACKAGE_NAME,
+        SipDelegateControllerContainer c2 = injectMockDelegateController(TEST_PACKAGE_NAME,
                 secondDelegateRequest);
-        createDelegateAndVerify(controller, c2, secondDelegateRequest, grantedAndDenied.first,
-                grantedAndDenied.second, TEST_PACKAGE_NAME, 1);
+        createDelegateAndVerify(controller, c2, grantedAndDenied.first, grantedAndDenied.second, 1);
         verifyNoDelegateRegistrationChangedEvent();
 
         // Destroy the firstDelegate, which should now cause all previously denied tags to be
         // granted to the new delegate.
-        CompletableFuture<Boolean> pendingC2Change = setChangeSupportedFeatureTagsFuture(c2,
-                secondDelegate, Collections.emptySet());
+        CompletableFuture<Boolean> pendingC2Change = setChangeSupportedFeatureTagsFuture(
+                c2.delegateController, secondDelegate, Collections.emptySet());
         destroyDelegateAndVerify(controller, c1, false /*force*/,
                 SipDelegateManager.SIP_DELEGATE_DESTROY_REASON_REQUESTED_BY_APP);
         // wait for create to be processed.
         assertTrue(waitForExecutorAction(mExecutorService, TIMEOUT_MS));
-        verify(c2).changeSupportedFeatureTags(secondDelegate, Collections.emptySet());
+        verify(c2.delegateController).changeSupportedFeatureTags(secondDelegate,
+                Collections.emptySet());
         completePendingChange(pendingC2Change, true);
 
         verifyDelegateRegistrationChangedEvent(1 /*times*/, THROTTLE_MS);
@@ -475,10 +508,10 @@
         ArraySet<String> firstDelegate = new ArraySet<>(getBaseDelegateRequest().getFeatureTags());
         firstDelegate.remove(ImsSignallingUtils.GROUP_CHAT_TAG);
         DelegateRequest firstDelegateRequest = new DelegateRequest(firstDelegate);
-        SipDelegateController c1 = injectMockDelegateController(TEST_PACKAGE_NAME,
+        SipDelegateControllerContainer c1 = injectMockDelegateController(TEST_PACKAGE_NAME,
                 firstDelegateRequest);
         CompletableFuture<Boolean> pendingC1Change = createDelegate(controller, c1,
-                firstDelegateRequest, firstDelegate, Collections.emptySet(), TEST_PACKAGE_NAME);
+                firstDelegate, Collections.emptySet());
 
         // Request RCS message + group RCS Message. For this delegate, single RCS message should be
         // denied.
@@ -488,11 +521,10 @@
         Pair<Set<String>, Set<FeatureTagState>> grantedAndDeniedC2 =
                 getAllowedAndDeniedTagsForConfig(secondDelegateRequest,
                         SipDelegateManager.DENIED_REASON_IN_USE_BY_ANOTHER_DELEGATE, firstDelegate);
-        SipDelegateController c2 = injectMockDelegateController(TEST_PACKAGE_NAME,
+        SipDelegateControllerContainer c2 = injectMockDelegateController(TEST_PACKAGE_NAME,
                 secondDelegateRequest);
         CompletableFuture<Boolean> pendingC2Change = createDelegate(controller, c2,
-                secondDelegateRequest, grantedAndDeniedC2.first, grantedAndDeniedC2.second,
-                TEST_PACKAGE_NAME);
+                grantedAndDeniedC2.first, grantedAndDeniedC2.second);
 
         // Request group RCS message + file transfer. All should be denied at first
         ArraySet<String> thirdDelegate = new ArraySet<>(getBaseDelegateRequest().getFeatureTags());
@@ -502,42 +534,44 @@
                 getAllowedAndDeniedTagsForConfig(thirdDelegateRequest,
                         SipDelegateManager.DENIED_REASON_IN_USE_BY_ANOTHER_DELEGATE, firstDelegate,
                         grantedAndDeniedC2.first);
-        SipDelegateController c3 = injectMockDelegateController(TEST_PACKAGE_NAME,
+        SipDelegateControllerContainer c3 = injectMockDelegateController(TEST_PACKAGE_NAME,
                 thirdDelegateRequest);
         CompletableFuture<Boolean> pendingC3Change = createDelegate(controller, c3,
-                thirdDelegateRequest, grantedAndDeniedC3.first, grantedAndDeniedC3.second,
-                TEST_PACKAGE_NAME);
+                grantedAndDeniedC3.first, grantedAndDeniedC3.second);
 
         verifyNoDelegateRegistrationChangedEvent();
         assertTrue(scheduleDelayedWait(2 * THROTTLE_MS));
-        verifyDelegateChanged(c1, pendingC1Change, firstDelegate, Collections.emptySet(), 0);
-        verifyDelegateChanged(c2, pendingC2Change, grantedAndDeniedC2.first,
+        verifyDelegateChanged(c1.delegateController, pendingC1Change, firstDelegate,
+                Collections.emptySet(), 0);
+        verifyDelegateChanged(c2.delegateController, pendingC2Change, grantedAndDeniedC2.first,
                 grantedAndDeniedC2.second, 0);
-        verifyDelegateChanged(c3, pendingC3Change, grantedAndDeniedC3.first,
+        verifyDelegateChanged(c3.delegateController, pendingC3Change, grantedAndDeniedC3.first,
                 grantedAndDeniedC3.second, 0);
         verifyDelegateRegistrationChangedEvent(1, 2 * THROTTLE_MS);
 
         // Destroy the first and second controller in quick succession, this should only generate
         // one reevaluate for the third controller.
         CompletableFuture<Boolean> pendingChangeC3 = setChangeSupportedFeatureTagsFuture(
-                c3, thirdDelegate, Collections.emptySet());
-        CompletableFuture<Integer> pendingDestroyC1 = destroyDelegate(controller, c1,
-                false /*force*/,
+                c3.delegateController, thirdDelegate, Collections.emptySet());
+        CompletableFuture<Integer> pendingDestroyC1 = destroyDelegate(controller,
+                c1.delegateController, false /*force*/,
                 SipDelegateManager.SIP_DELEGATE_DESTROY_REASON_REQUESTED_BY_APP);
-        CompletableFuture<Integer> pendingDestroyC2 = destroyDelegate(controller, c2,
-                false /*force*/,
+        CompletableFuture<Integer> pendingDestroyC2 = destroyDelegate(controller,
+                c2.delegateController, false /*force*/,
                 SipDelegateManager.SIP_DELEGATE_DESTROY_REASON_REQUESTED_BY_APP);
         assertTrue(scheduleDelayedWait(2 * THROTTLE_MS));
-        verifyDestroyDelegate(controller, c1, pendingDestroyC1, false /*force*/,
+        verifyDestroyDelegate(c1.delegateController, pendingDestroyC1, false /*force*/,
                 SipDelegateManager.SIP_DELEGATE_DESTROY_REASON_REQUESTED_BY_APP);
-        verifyDestroyDelegate(controller, c2, pendingDestroyC2, false /*force*/,
+        verifyDestroyDelegate(c2.delegateController, pendingDestroyC2, false /*force*/,
                 SipDelegateManager.SIP_DELEGATE_DESTROY_REASON_REQUESTED_BY_APP);
 
         // All requested features should now be granted
         completePendingChange(pendingChangeC3, true);
-        verify(c3).changeSupportedFeatureTags(thirdDelegate, Collections.emptySet());
+        verify(c3.delegateController)
+                .changeSupportedFeatureTags(thirdDelegate, Collections.emptySet());
         // In total reeval should have only been called twice.
-        verify(c3, times(2)).changeSupportedFeatureTags(any(), any());
+        verify(c3.delegateController, times(2))
+                .changeSupportedFeatureTags(any(), any());
         verifyDelegateRegistrationChangedEvent(2 /*times*/, 2 * THROTTLE_MS);
     }
 
@@ -548,17 +582,16 @@
 
         ArraySet<String> firstDelegate = new ArraySet<>(getBaseDelegateRequest().getFeatureTags());
         DelegateRequest firstDelegateRequest = new DelegateRequest(firstDelegate);
-        SipDelegateController c1 = injectMockDelegateController(TEST_PACKAGE_NAME,
+        SipDelegateControllerContainer c = injectMockDelegateController(TEST_PACKAGE_NAME,
                 firstDelegateRequest);
-        createDelegateAndVerify(controller, c1, firstDelegateRequest, firstDelegate,
-                Collections.emptySet(), TEST_PACKAGE_NAME);
+        createDelegateAndVerify(controller, c, firstDelegate, Collections.emptySet());
         verifyDelegateRegistrationChangedEvent(1 /*times*/, 0 /*waitMs*/);
 
-        CompletableFuture<Integer> pendingDestroy =  setDestroyFuture(c1, true,
+        CompletableFuture<Integer> pendingDestroy =  setDestroyFuture(c.delegateController, true,
                 SipDelegateManager.SIP_DELEGATE_DESTROY_REASON_SUBSCRIPTION_TORN_DOWN);
         controller.onAssociatedSubscriptionUpdated(TEST_SUB_ID + 1);
         waitForExecutorAction(mExecutorService, TIMEOUT_MS);
-        verifyDestroyDelegate(controller, c1, pendingDestroy, true /*force*/,
+        verifyDestroyDelegate(c.delegateController, pendingDestroy, true /*force*/,
                 SipDelegateManager.SIP_DELEGATE_DESTROY_REASON_SUBSCRIPTION_TORN_DOWN);
         verifyDelegateRegistrationChangedEvent(2 /*times*/, 0 /*waitMs*/);
     }
@@ -570,16 +603,15 @@
 
         ArraySet<String> firstDelegate = new ArraySet<>(getBaseDelegateRequest().getFeatureTags());
         DelegateRequest firstDelegateRequest = new DelegateRequest(firstDelegate);
-        SipDelegateController c1 = injectMockDelegateController(TEST_PACKAGE_NAME,
+        SipDelegateControllerContainer c = injectMockDelegateController(TEST_PACKAGE_NAME,
                 firstDelegateRequest);
-        createDelegateAndVerify(controller, c1, firstDelegateRequest, firstDelegate,
-                Collections.emptySet(), TEST_PACKAGE_NAME);
+        createDelegateAndVerify(controller, c, firstDelegate, Collections.emptySet());
 
-        CompletableFuture<Integer> pendingDestroy =  setDestroyFuture(c1, true,
+        CompletableFuture<Integer> pendingDestroy =  setDestroyFuture(c.delegateController, true,
                 SipDelegateManager.SIP_DELEGATE_DESTROY_REASON_SERVICE_DEAD);
         controller.onRcsDisconnected();
         waitForExecutorAction(mExecutorService, TIMEOUT_MS);
-        verifyDestroyDelegate(controller, c1, pendingDestroy, true /*force*/,
+        verifyDestroyDelegate(c.delegateController, pendingDestroy, true /*force*/,
                 SipDelegateManager.SIP_DELEGATE_DESTROY_REASON_SERVICE_DEAD);
         verifyDelegateRegistrationChangedEvent(1, 0 /*waitMs*/);
     }
@@ -591,18 +623,17 @@
 
         ArraySet<String> firstDelegate = new ArraySet<>(getBaseDelegateRequest().getFeatureTags());
         DelegateRequest firstDelegateRequest = new DelegateRequest(firstDelegate);
-        SipDelegateController c1 = injectMockDelegateController(TEST_PACKAGE_NAME,
+        SipDelegateControllerContainer c = injectMockDelegateController(TEST_PACKAGE_NAME,
                 firstDelegateRequest);
-        createDelegateAndVerify(controller, c1, firstDelegateRequest, firstDelegate,
-                Collections.emptySet(), TEST_PACKAGE_NAME);
+        createDelegateAndVerify(controller, c, firstDelegate, Collections.emptySet());
 
-        CompletableFuture<Integer> pendingDestroy =  setDestroyFuture(c1, true,
-                SipDelegateManager.SIP_DELEGATE_DESTROY_REASON_SUBSCRIPTION_TORN_DOWN);
+        CompletableFuture<Integer> pendingDestroy =  setDestroyFuture(c.delegateController,
+                true, SipDelegateManager.SIP_DELEGATE_DESTROY_REASON_SUBSCRIPTION_TORN_DOWN);
         controller.onDestroy();
         waitForExecutorAction(mExecutorService, TIMEOUT_MS);
         verifyDelegateDeregistrationEvent();
         // verify change was called.
-        verify(c1).destroy(true /*force*/,
+        verify(c.delegateController).destroy(true /*force*/,
                 SipDelegateManager.SIP_DELEGATE_DESTROY_REASON_SUBSCRIPTION_TORN_DOWN);
         // ensure thread is not blocked while waiting for pending complete.
         waitForExecutorAction(mExecutorService, TIMEOUT_MS);
@@ -620,16 +651,17 @@
 
         ArraySet<String> firstDelegate = new ArraySet<>(getBaseDelegateRequest().getFeatureTags());
         DelegateRequest firstDelegateRequest = new DelegateRequest(firstDelegate);
-        SipDelegateController c1 = injectMockDelegateController(TEST_PACKAGE_NAME,
+        SipDelegateControllerContainer c1 = injectMockDelegateController(TEST_PACKAGE_NAME,
                 firstDelegateRequest);
         CompletableFuture<Boolean> pendingC1Change = createDelegate(controller, c1,
-                firstDelegateRequest, firstDelegate, Collections.emptySet(), TEST_PACKAGE_NAME);
+                firstDelegate, Collections.emptySet());
         assertTrue(scheduleDelayedWait(2 * THROTTLE_MS));
-        verifyDelegateChanged(c1, pendingC1Change, firstDelegate, Collections.emptySet(), 0);
+        verifyDelegateChanged(c1.delegateController, pendingC1Change, firstDelegate,
+                Collections.emptySet(), 0);
 
 
-        CompletableFuture<Integer> pendingDestroy =  setDestroyFuture(c1, true,
-                SipDelegateManager.SIP_DELEGATE_DESTROY_REASON_SUBSCRIPTION_TORN_DOWN);
+        CompletableFuture<Integer> pendingDestroy =  setDestroyFuture(c1.delegateController,
+                true, SipDelegateManager.SIP_DELEGATE_DESTROY_REASON_SUBSCRIPTION_TORN_DOWN);
         // triggers reeval now.
         controller.onAssociatedSubscriptionUpdated(TEST_SUB_ID + 1);
         waitForExecutorAction(mExecutorService, TIMEOUT_MS);
@@ -639,18 +671,18 @@
         secondDelegate.add(ImsSignallingUtils.ONE_TO_ONE_CHAT_TAG);
         secondDelegate.add(ImsSignallingUtils.FILE_TRANSFER_HTTP_TAG);
         DelegateRequest secondDelegateRequest = new DelegateRequest(secondDelegate);
-        SipDelegateController c2 = injectMockDelegateController(TEST_SUB_ID + 1,
+        SipDelegateControllerContainer c2 = injectMockDelegateController(TEST_SUB_ID + 1,
                 TEST_PACKAGE_NAME, secondDelegateRequest);
-        CompletableFuture<Boolean> pendingC2Change = createDelegate(controller, c2,
-                TEST_SUB_ID + 1, secondDelegateRequest, secondDelegate,
-                Collections.emptySet(), TEST_PACKAGE_NAME);
+        CompletableFuture<Boolean> pendingC2Change = createDelegate(controller, c2, secondDelegate,
+                Collections.emptySet());
         assertTrue(scheduleDelayedWait(THROTTLE_MS));
 
         //trigger destroyed event
-        verifyDestroyDelegate(controller, c1, pendingDestroy, true /*force*/,
+        verifyDestroyDelegate(c1.delegateController, pendingDestroy, true /*force*/,
                 SipDelegateManager.SIP_DELEGATE_DESTROY_REASON_SUBSCRIPTION_TORN_DOWN);
         assertTrue(scheduleDelayedWait(2 * THROTTLE_MS));
-        verifyDelegateChanged(c2, pendingC2Change, secondDelegate, Collections.emptySet(), 0);
+        verifyDelegateChanged(c2.delegateController, pendingC2Change, secondDelegate,
+                Collections.emptySet(), 0);
     }
 
     @SmallTest
@@ -664,16 +696,17 @@
         ArraySet<String> allowedTags = new ArraySet<>(requestTags);
         ArraySet<String> deniedTags = new ArraySet<>();
         DelegateRequest delegateRequest = new DelegateRequest(requestTags);
-        SipDelegateController sc = injectMockDelegateController(TEST_PACKAGE_NAME,
+        SipDelegateControllerContainer c = injectMockDelegateController(TEST_PACKAGE_NAME,
                 delegateRequest);
-        CompletableFuture<Boolean> pendingScChange = createDelegate(controller, sc,
-                delegateRequest, requestTags, Collections.emptySet(), TEST_PACKAGE_NAME);
+        CompletableFuture<Boolean> pendingScChange = createDelegate(controller, c, requestTags,
+                Collections.emptySet());
         allowedTags.remove(ImsSignallingUtils.ONE_TO_ONE_CHAT_TAG);
         deniedTags.add(ImsSignallingUtils.ONE_TO_ONE_CHAT_TAG);
 
         assertTrue(scheduleDelayedWait(2 * THROTTLE_MS));
-        verifyDelegateChanged(sc, pendingScChange, allowedTags, getDeniedTagsForReason(
-                deniedTags, SipDelegateManager.DENIED_REASON_NOT_ALLOWED), 0);
+        verifyDelegateChanged(c.delegateController, pendingScChange, allowedTags,
+                getDeniedTagsForReason(deniedTags,
+                        SipDelegateManager.DENIED_REASON_NOT_ALLOWED), 0);
     }
 
     @SmallTest
@@ -685,14 +718,15 @@
         ArraySet<String> requestTags = new ArraySet<>(getBaseDelegateRequest().getFeatureTags());
         ArraySet<String> deniedTags = new ArraySet<>(requestTags);
         DelegateRequest delegateRequest = new DelegateRequest(requestTags);
-        SipDelegateController sc = injectMockDelegateController(TEST_PACKAGE_NAME,
+        SipDelegateControllerContainer c = injectMockDelegateController(TEST_PACKAGE_NAME,
                 delegateRequest);
-        CompletableFuture<Boolean> pendingScChange = createDelegate(controller, sc,
-                delegateRequest, requestTags, Collections.emptySet(), TEST_PACKAGE_NAME);
+        CompletableFuture<Boolean> pendingScChange = createDelegate(controller, c, requestTags,
+                Collections.emptySet());
 
         assertTrue(scheduleDelayedWait(2 * THROTTLE_MS));
-        verifyDelegateChanged(sc, pendingScChange, Collections.emptySet(), getDeniedTagsForReason(
-                deniedTags, SipDelegateManager.DENIED_REASON_NOT_ALLOWED), 0);
+        verifyDelegateChanged(c.delegateController, pendingScChange, Collections.emptySet(),
+                getDeniedTagsForReason(deniedTags,
+                        SipDelegateManager.DENIED_REASON_NOT_ALLOWED), 0);
     }
 
     @SmallTest
@@ -705,13 +739,14 @@
         ArraySet<String> requestTags = new ArraySet<>(getBaseDelegateRequest().getFeatureTags());
         ArraySet<String> allowedTags = new ArraySet<>(requestTags);
         DelegateRequest delegateRequest = new DelegateRequest(requestTags);
-        SipDelegateController sc = injectMockDelegateController(TEST_PACKAGE_NAME,
-                delegateRequest);
-        CompletableFuture<Boolean> pendingScChange = createDelegate(controller, sc,
-                delegateRequest, requestTags, Collections.emptySet(), TEST_PACKAGE_NAME);
+        SipDelegateControllerContainer controllerContainer =
+                injectMockDelegateController(TEST_PACKAGE_NAME, delegateRequest);
+        CompletableFuture<Boolean> pendingScChange = createDelegate(controller, controllerContainer,
+                requestTags, Collections.emptySet());
 
         assertTrue(scheduleDelayedWait(2 * THROTTLE_MS));
-        verifyDelegateChanged(sc, pendingScChange, allowedTags, Collections.emptySet(), 0);
+        verifyDelegateChanged(controllerContainer.delegateController, pendingScChange, allowedTags,
+                Collections.emptySet(), 0);
     }
 
     @SafeVarargs
@@ -756,31 +791,32 @@
     }
 
     private void createDelegateAndVerify(SipTransportController controller,
-            SipDelegateController delegateController, DelegateRequest r, Set<String> allowedTags,
-            Set<FeatureTagState> deniedTags, String packageName,
-            int numPreviousChanges) throws ImsException {
+            SipDelegateControllerContainer controllerContainer, Set<String> allowedTags,
+            Set<FeatureTagState> deniedTags, int numPreviousChanges) {
 
-        CompletableFuture<Boolean> pendingChange = createDelegate(controller, delegateController, r,
-                allowedTags, deniedTags, packageName);
-        verifyDelegateChanged(delegateController, pendingChange, allowedTags, deniedTags,
-                numPreviousChanges);
+        CompletableFuture<Boolean> pendingChange = createDelegate(controller, controllerContainer,
+                allowedTags, deniedTags);
+        verifyDelegateChanged(controllerContainer.delegateController, pendingChange, allowedTags,
+                deniedTags, numPreviousChanges);
     }
 
     private void createDelegateAndVerify(SipTransportController controller,
-            SipDelegateController delegateController, DelegateRequest r, Set<String> allowedTags,
-            Set<FeatureTagState> deniedTags, String packageName) throws ImsException {
-        createDelegateAndVerify(controller, delegateController, r, allowedTags, deniedTags,
-                packageName, 0);
+            SipDelegateControllerContainer controllerContainer, Set<String> allowedTags,
+            Set<FeatureTagState> deniedTags) {
+        createDelegateAndVerify(controller, controllerContainer, allowedTags, deniedTags, 0);
     }
 
     private CompletableFuture<Boolean> createDelegate(SipTransportController controller,
-            SipDelegateController delegateController, int subId, DelegateRequest r,
-            Set<String> allowedTags, Set<FeatureTagState> deniedTags, String packageName) {
+            SipDelegateControllerContainer delegateControllerContainer, Set<String> allowedTags,
+            Set<FeatureTagState> deniedTags) {
         CompletableFuture<Boolean> pendingChange = setChangeSupportedFeatureTagsFuture(
-                delegateController, allowedTags, deniedTags);
+                delegateControllerContainer.delegateController, allowedTags, deniedTags);
         try {
-            controller.createSipDelegate(subId, r, packageName, mMockStateCallback,
-                    mMockMessageCallback);
+            controller.createSipDelegate(delegateControllerContainer.subId,
+                    delegateControllerContainer.delegateRequest,
+                    delegateControllerContainer.packageName,
+                    delegateControllerContainer.mockDelegateConnectionCallback,
+                    delegateControllerContainer.mockMessageCallback);
         } catch (ImsException e) {
             fail("ImsException thrown:" + e);
         }
@@ -791,13 +827,6 @@
         return pendingChange;
     }
 
-    private CompletableFuture<Boolean> createDelegate(SipTransportController controller,
-            SipDelegateController delegateController, DelegateRequest r, Set<String> allowedTags,
-            Set<FeatureTagState> deniedTags, String packageName) throws ImsException {
-        return createDelegate(controller, delegateController, TEST_SUB_ID, r, allowedTags,
-                deniedTags, packageName);
-    }
-
     private void verifyDelegateChanged(SipDelegateController delegateController,
             CompletableFuture<Boolean> pendingChange, Set<String> allowedTags,
             Set<FeatureTagState> deniedTags, int numPreviousChangeStages) {
@@ -817,10 +846,11 @@
     }
 
     private void destroyDelegateAndVerify(SipTransportController controller,
-            SipDelegateController delegateController, boolean force, int reason) {
+            SipDelegateControllerContainer controllerContainer, boolean force, int reason) {
+        SipDelegateController delegateController = controllerContainer.delegateController;
         CompletableFuture<Integer> pendingDestroy =  destroyDelegate(controller, delegateController,
                 force, reason);
-        verifyDestroyDelegate(controller, delegateController, pendingDestroy, force, reason);
+        verifyDestroyDelegate(delegateController, pendingDestroy, force, reason);
     }
 
     private CompletableFuture<Integer> destroyDelegate(SipTransportController controller,
@@ -836,9 +866,8 @@
         return pendingDestroy;
     }
 
-    private void verifyDestroyDelegate(SipTransportController controller,
-            SipDelegateController delegateController, CompletableFuture<Integer> pendingDestroy,
-            boolean force, int reason) {
+    private void verifyDestroyDelegate(SipDelegateController delegateController,
+            CompletableFuture<Integer> pendingDestroy, boolean force, int reason) {
         // verify destroy was called.
         verify(delegateController).destroy(force, reason);
         // ensure thread is not blocked while waiting for pending complete.
@@ -847,7 +876,8 @@
     }
 
     private void triggerFullNetworkRegistrationAndVerify(SipTransportController controller,
-            SipDelegateController delegateController) {
+            SipDelegateControllerContainer controllerContainer) {
+        SipDelegateController delegateController = controllerContainer.delegateController;
         controller.triggerFullNetworkRegistration(TEST_SUB_ID,
                 delegateController.getSipDelegateInterface(), 403, "forbidden");
         // move to internal & trigger event
@@ -856,7 +886,8 @@
     }
 
     private void triggerFullNetworkRegistrationAndVerifyNever(SipTransportController controller,
-            SipDelegateController delegateController) {
+            SipDelegateControllerContainer controllerContainer) {
+        SipDelegateController delegateController = controllerContainer.delegateController;
         controller.triggerFullNetworkRegistration(TEST_SUB_ID,
                 delegateController.getSipDelegateInterface(), 403, "forbidden");
         // move to internal & potentially trigger event
@@ -872,29 +903,22 @@
         return new DelegateRequest(featureTags);
     }
 
-    private Set<FeatureTagState> getBaseDeniedSet() {
-        Set<FeatureTagState> deniedTags = new ArraySet<>();
-        deniedTags.add(new FeatureTagState(ImsSignallingUtils.MMTEL_TAG,
-                SipDelegateManager.DENIED_REASON_IN_USE_BY_ANOTHER_DELEGATE));
-        return deniedTags;
-    }
-
     private Set<FeatureTagState> getDeniedTagsForReason(Set<String> deniedTags, int reason) {
         return deniedTags.stream().map(t -> new FeatureTagState(t, reason))
                 .collect(Collectors.toSet());
     }
 
-    private SipDelegateController injectMockDelegateController(String packageName,
+    private SipDelegateControllerContainer injectMockDelegateController(String packageName,
             DelegateRequest r) {
         return injectMockDelegateController(TEST_SUB_ID, packageName, r);
     }
 
-    private SipDelegateController injectMockDelegateController(int subId, String packageName,
-            DelegateRequest r) {
+    private SipDelegateControllerContainer injectMockDelegateController(int subId,
+            String packageName, DelegateRequest r) {
         SipDelegateControllerContainer c = new SipDelegateControllerContainer(subId,
                 packageName, r);
         mMockControllers.add(c);
-        return c.delegateController;
+        return c;
     }
 
     private SipDelegateController getMockDelegateController(int subId, String packageName,