1 /*
2  * Copyright (C) 2020 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.services.telephony.rcs;
18 
19 import static org.junit.Assert.assertEquals;
20 import static org.junit.Assert.assertFalse;
21 import static org.junit.Assert.assertNotNull;
22 import static org.junit.Assert.assertTrue;
23 import static org.junit.Assert.fail;
24 import static org.mockito.ArgumentMatchers.any;
25 import static org.mockito.ArgumentMatchers.anyInt;
26 import static org.mockito.ArgumentMatchers.anyString;
27 import static org.mockito.ArgumentMatchers.eq;
28 import static org.mockito.Mockito.doAnswer;
29 import static org.mockito.Mockito.doReturn;
30 import static org.mockito.Mockito.doThrow;
31 import static org.mockito.Mockito.mock;
32 import static org.mockito.Mockito.never;
33 import static org.mockito.Mockito.times;
34 import static org.mockito.Mockito.verify;
35 
36 import android.app.role.RoleManager;
37 import android.os.IBinder;
38 import android.os.PersistableBundle;
39 import android.os.UserHandle;
40 import android.telephony.CarrierConfigManager;
41 import android.telephony.ims.DelegateRequest;
42 import android.telephony.ims.FeatureTagState;
43 import android.telephony.ims.ImsException;
44 import android.telephony.ims.SipDelegateManager;
45 import android.telephony.ims.aidl.IImsRegistration;
46 import android.telephony.ims.aidl.ISipDelegate;
47 import android.telephony.ims.aidl.ISipDelegateConnectionStateCallback;
48 import android.telephony.ims.aidl.ISipDelegateMessageCallback;
49 import android.telephony.ims.aidl.ISipTransport;
50 import android.util.ArraySet;
51 import android.util.Pair;
52 
53 import androidx.test.filters.SmallTest;
54 import androidx.test.runner.AndroidJUnit4;
55 
56 import com.android.TelephonyTestBase;
57 import com.android.TestExecutorService;
58 import com.android.ims.RcsFeatureManager;
59 import com.android.phone.RcsProvisioningMonitor;
60 
61 import org.junit.After;
62 import org.junit.Before;
63 import org.junit.Test;
64 import org.junit.runner.RunWith;
65 import org.mockito.ArgumentCaptor;
66 import org.mockito.Mock;
67 
68 import java.util.ArrayList;
69 import java.util.Collections;
70 import java.util.Set;
71 import java.util.concurrent.CompletableFuture;
72 import java.util.concurrent.CountDownLatch;
73 import java.util.concurrent.Executors;
74 import java.util.concurrent.ScheduledExecutorService;
75 import java.util.concurrent.TimeUnit;
76 import java.util.stream.Collectors;
77 
78 @RunWith(AndroidJUnit4.class)
79 public class SipTransportControllerTest extends TelephonyTestBase {
80     private static final int TEST_SUB_ID = 1;
81     private static final int TEST_UID = 1001;
82     private static final String TEST_PACKAGE_NAME = "com.test_pkg";
83     private static final String TEST_PACKAGE_NAME_2 = "com.test_pkg2";
84     private static final int TIMEOUT_MS = 200;
85     private static final int THROTTLE_MS = 50;
86 
87     private class SipDelegateControllerContainer {
88         public final int subId;
89         public final String packageName;
90         public final DelegateRequest delegateRequest;
91         public final SipDelegateController delegateController;
92         private final ISipDelegate mMockDelegate;
93         public final IBinder mockDelegateBinder;
94         public final ISipDelegateConnectionStateCallback mockDelegateConnectionCallback;
95         public final ISipDelegateMessageCallback mockMessageCallback;
96         public final IBinder mockMessageCallbackBinder;
97 
SipDelegateControllerContainer(int id, String name, DelegateRequest request)98         SipDelegateControllerContainer(int id, String name, DelegateRequest request) {
99             delegateController = mock(SipDelegateController.class);
100             mMockDelegate = mock(ISipDelegate.class);
101             mockDelegateBinder = mock(IBinder.class);
102             doReturn(mockDelegateBinder).when(mMockDelegate).asBinder();
103             mockDelegateConnectionCallback = mock(ISipDelegateConnectionStateCallback.class);
104             mockMessageCallback = mock(ISipDelegateMessageCallback.class);
105             mockMessageCallbackBinder = mock(IBinder.class);
106             doReturn(mockMessageCallbackBinder).when(mockMessageCallback).asBinder();
107             doReturn(name).when(delegateController).getPackageName();
108             doReturn(request).when(delegateController).getInitialRequest();
109             doReturn(mMockDelegate).when(delegateController).getSipDelegateInterface();
110             doReturn(mockMessageCallback).when(delegateController).getAppMessageCallback();
111             subId = id;
112             packageName = name;
113             delegateRequest = request;
114         }
115     }
116 
117     @Mock private RcsFeatureManager mRcsManager;
118     @Mock private ISipTransport mSipTransport;
119     @Mock private IImsRegistration mImsRegistration;
120     @Mock private SipTransportController.SipDelegateControllerFactory
121             mMockDelegateControllerFactory;
122     @Mock private SipTransportController.RoleManagerAdapter mMockRoleManager;
123 
124     private ScheduledExecutorService mExecutorService = null;
125     private final ArrayList<SipDelegateControllerContainer> mMockControllers = new ArrayList<>();
126     private final ArrayList<String> mSmsPackageName = new ArrayList<>(1);
127 
128     @Before
setUp()129     public void setUp() throws Exception {
130         super.setUp();
131         doReturn(mSmsPackageName).when(mMockRoleManager).getRoleHolders(RoleManager.ROLE_SMS);
132         doReturn(mImsRegistration).when(mRcsManager).getImsRegistration();
133         mSmsPackageName.add(TEST_PACKAGE_NAME);
134         doAnswer(invocation -> {
135             Integer subId = invocation.getArgument(0);
136             String packageName = invocation.getArgument(3);
137             DelegateRequest request = invocation.getArgument(2);
138             SipDelegateController c = getMockDelegateController(subId, packageName, request);
139             assertNotNull("create called with no corresponding controller set up", c);
140             return c;
141         }).when(mMockDelegateControllerFactory).create(anyInt(), anyInt(), any(), anyString(),
142                 any(), any(), any(), any(), any());
143         setFeatureAllowedConfig(TEST_SUB_ID, new String[]{ImsSignallingUtils.MMTEL_TAG,
144                 ImsSignallingUtils.ONE_TO_ONE_CHAT_TAG, ImsSignallingUtils.GROUP_CHAT_TAG,
145                 ImsSignallingUtils.FILE_TRANSFER_HTTP_TAG});
146     }
147 
148     @After
tearDown()149     public void tearDown() throws Exception {
150         var monitor = RcsProvisioningMonitor.getInstance();
151         if (monitor != null) {
152             monitor.overrideImsFeatureValidation(TEST_SUB_ID, null);
153         }
154 
155         if (mExecutorService != null && !mExecutorService.isShutdown()) {
156             mExecutorService.shutdownNow();
157         }
158 
159         super.tearDown();
160     }
161 
162     @SmallTest
163     @Test
isSupportedRcsNotConnected()164     public void isSupportedRcsNotConnected() {
165         SipTransportController controller = createController(new TestExecutorService());
166         try {
167             controller.isSupported(TEST_SUB_ID);
168             fail();
169         } catch (ImsException e) {
170             assertEquals(ImsException.CODE_ERROR_SERVICE_UNAVAILABLE, e.getCode());
171         }
172     }
173 
174     @SmallTest
175     @Test
isSupportedInvalidSubId()176     public void isSupportedInvalidSubId() {
177         SipTransportController controller = createController(new TestExecutorService());
178         try {
179             controller.isSupported(TEST_SUB_ID + 1);
180             fail();
181         } catch (ImsException e) {
182             assertEquals(ImsException.CODE_ERROR_INVALID_SUBSCRIPTION, e.getCode());
183         }
184     }
185 
186     @SmallTest
187     @Test
isSupportedSubIdChanged()188     public void isSupportedSubIdChanged() {
189         SipTransportController controller = createController(new TestExecutorService());
190         controller.onAssociatedSubscriptionUpdated(TEST_SUB_ID + 1);
191         try {
192             controller.isSupported(TEST_SUB_ID);
193             fail();
194         } catch (ImsException e) {
195             assertEquals(ImsException.CODE_ERROR_INVALID_SUBSCRIPTION, e.getCode());
196         }
197     }
198 
199     @SmallTest
200     @Test
isSupportedSipTransportAvailableRcsConnected()201     public void isSupportedSipTransportAvailableRcsConnected() throws Exception {
202         SipTransportController controller = createController(new TestExecutorService());
203         doReturn(mSipTransport).when(mRcsManager).getSipTransport();
204         controller.onRcsConnected(mRcsManager);
205         try {
206             assertTrue(controller.isSupported(TEST_SUB_ID));
207         } catch (ImsException e) {
208             fail();
209         }
210     }
211 
212     @SmallTest
213     @Test
isSupportedSipTransportNotAvailableRcsDisconnected()214     public void isSupportedSipTransportNotAvailableRcsDisconnected() throws Exception {
215         SipTransportController controller = createController(new TestExecutorService());
216         doReturn(mSipTransport).when(mRcsManager).getSipTransport();
217         controller.onRcsConnected(mRcsManager);
218         controller.onRcsDisconnected();
219         try {
220             controller.isSupported(TEST_SUB_ID);
221             fail();
222         } catch (ImsException e) {
223             assertEquals(ImsException.CODE_ERROR_SERVICE_UNAVAILABLE, e.getCode());
224         }
225     }
226 
227     @SmallTest
228     @Test
isSupportedSipTransportNotAvailableRcsConnected()229     public void isSupportedSipTransportNotAvailableRcsConnected() throws Exception {
230         SipTransportController controller = createController(new TestExecutorService());
231         doReturn(null).when(mRcsManager).getSipTransport();
232         controller.onRcsConnected(mRcsManager);
233         try {
234             assertFalse(controller.isSupported(TEST_SUB_ID));
235         } catch (ImsException e) {
236             fail();
237         }
238     }
239 
240     @SmallTest
241     @Test
isSupportedImsServiceNotAvailableRcsConnected()242     public void isSupportedImsServiceNotAvailableRcsConnected() throws Exception {
243         SipTransportController controller = createController(new TestExecutorService());
244         doThrow(new ImsException("", ImsException.CODE_ERROR_SERVICE_UNAVAILABLE))
245                 .when(mRcsManager).getSipTransport();
246         controller.onRcsConnected(mRcsManager);
247         try {
248             controller.isSupported(TEST_SUB_ID);
249             fail();
250         } catch (ImsException e) {
251             assertEquals(ImsException.CODE_ERROR_SERVICE_UNAVAILABLE, e.getCode());
252         }
253     }
254 
255     @SmallTest
256     @Test
createImsServiceAvailableSubIdIncorrect()257     public void createImsServiceAvailableSubIdIncorrect() throws Exception {
258         SipTransportController controller = createController(new TestExecutorService());
259         doReturn(mSipTransport).when(mRcsManager).getSipTransport();
260         controller.onRcsConnected(mRcsManager);
261         try {
262             controller.createSipDelegate(TEST_SUB_ID + 1, TEST_UID,
263                     new DelegateRequest(Collections.emptySet()), TEST_PACKAGE_NAME,
264                     mock(ISipDelegateConnectionStateCallback.class),
265                     mock(ISipDelegateMessageCallback.class));
266             fail();
267         } catch (ImsException e) {
268             assertEquals(ImsException.CODE_ERROR_INVALID_SUBSCRIPTION, e.getCode());
269         }
270     }
271 
272     @SmallTest
273     @Test
createImsServiceDoesntSupportTransport()274     public void createImsServiceDoesntSupportTransport() throws Exception {
275         SipTransportController controller = createController(new TestExecutorService());
276         doReturn(null).when(mRcsManager).getSipTransport();
277         controller.onRcsConnected(mRcsManager);
278         try {
279             controller.createSipDelegate(TEST_SUB_ID, TEST_UID,
280                     new DelegateRequest(Collections.emptySet()), TEST_PACKAGE_NAME,
281                     mock(ISipDelegateConnectionStateCallback.class),
282                     mock(ISipDelegateMessageCallback.class));
283             fail();
284         } catch (ImsException e) {
285             assertEquals(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION, e.getCode());
286         }
287     }
288 
289     @SmallTest
290     @Test
createImsServiceNotAvailable()291     public void createImsServiceNotAvailable() throws Exception {
292         SipTransportController controller = createController(new TestExecutorService());
293         doThrow(new ImsException("", ImsException.CODE_ERROR_SERVICE_UNAVAILABLE))
294                 .when(mRcsManager).getSipTransport();
295         // No RCS connected message
296         try {
297             controller.createSipDelegate(TEST_SUB_ID, TEST_UID,
298                     new DelegateRequest(Collections.emptySet()), TEST_PACKAGE_NAME,
299                     mock(ISipDelegateConnectionStateCallback.class),
300                     mock(ISipDelegateMessageCallback.class));
301             fail();
302         } catch (ImsException e) {
303             assertEquals(ImsException.CODE_ERROR_SERVICE_UNAVAILABLE, e.getCode());
304         }
305     }
306 
307     @SmallTest
308     @Test
basicCreate()309     public void basicCreate() throws Exception {
310         SipTransportController controller = setupLiveTransportController();
311 
312         DelegateRequest r = getBaseDelegateRequest();
313 
314         SipDelegateControllerContainer c = injectMockDelegateController(TEST_PACKAGE_NAME, r);
315         createDelegateAndVerify(controller, c, r.getFeatureTags(), Collections.emptySet());
316         verifyDelegateRegistrationChangedEvent(1 /*times*/, 0 /*waitMs*/);
317         triggerFullNetworkRegistrationAndVerify(controller, c);
318     }
319 
320     @SmallTest
321     @Test
basicCreateDestroy()322     public void basicCreateDestroy() throws Exception {
323         SipTransportController controller = setupLiveTransportController();
324 
325         DelegateRequest r = getBaseDelegateRequest();
326         SipDelegateControllerContainer c = injectMockDelegateController(TEST_PACKAGE_NAME, r);
327         createDelegateAndVerify(controller, c, r.getFeatureTags(), Collections.emptySet());
328         verify(c.mockMessageCallbackBinder).linkToDeath(any(), anyInt());
329         verifyDelegateRegistrationChangedEvent(1, 0 /*throttle*/);
330 
331         destroyDelegateAndVerify(controller, c, false,
332                 SipDelegateManager.SIP_DELEGATE_DESTROY_REASON_REQUESTED_BY_APP);
333         verify(c.mockMessageCallbackBinder).unlinkToDeath(any(), anyInt());
334         verifyDelegateRegistrationChangedEvent(2 /*times*/, 0 /*waitMs*/);
335         triggerFullNetworkRegistrationAndVerifyNever(controller, c);
336     }
337 
338     @SmallTest
339     @Test
createDestroyAppDied()340     public void createDestroyAppDied() throws Exception {
341         SipTransportController controller = setupLiveTransportController();
342         DelegateRequest r = getBaseDelegateRequest();
343         SipDelegateControllerContainer c = injectMockDelegateController(TEST_PACKAGE_NAME, r);
344         createDelegateAndVerify(controller, c, r.getFeatureTags(), Collections.emptySet());
345         ArgumentCaptor<IBinder.DeathRecipient> captor =
346                 ArgumentCaptor.forClass(IBinder.DeathRecipient.class);
347         verify(c.mockMessageCallbackBinder).linkToDeath(captor.capture(), anyInt());
348         IBinder.DeathRecipient deathRecipient = captor.getValue();
349         assertNotNull(deathRecipient);
350         verifyDelegateRegistrationChangedEvent(1, 0 /*throttle*/);
351 
352         CompletableFuture<Integer> pendingDestroy = setDestroyFuture(c.delegateController, true,
353                 SipDelegateManager.SIP_DELEGATE_DESTROY_REASON_SERVICE_DEAD);
354         // Simulate app dying
355         deathRecipient.binderDied();
356         waitForExecutorAction(mExecutorService, TIMEOUT_MS);
357         verifyDestroyDelegate(c.delegateController, pendingDestroy, true,
358                 SipDelegateManager.SIP_DELEGATE_DESTROY_REASON_SERVICE_DEAD);
359         // If binderDied is called, then unregister does not lead to unlinkToDeath
360         triggerFullNetworkRegistrationAndVerifyNever(controller, c);
361     }
362 
363     @SmallTest
364     @Test
testCreateButNotInRole()365     public void testCreateButNotInRole() throws Exception {
366         SipTransportController controller = setupLiveTransportController();
367 
368         DelegateRequest r = getBaseDelegateRequest();
369         Set<FeatureTagState> getDeniedTags = getDeniedTagsForReason(r.getFeatureTags(),
370                 SipDelegateManager.DENIED_REASON_NOT_ALLOWED);
371 
372         // Try to create a SipDelegate for a package that is not the default sms role.
373         SipDelegateControllerContainer c = injectMockDelegateController(TEST_PACKAGE_NAME_2, r);
374         createDelegateAndVerify(controller, c, Collections.emptySet(), getDeniedTags);
375     }
376 
377     @SmallTest
378     @Test
createTwoAndDenyOverlappingTags()379     public void createTwoAndDenyOverlappingTags() throws Exception {
380         SipTransportController controller = setupLiveTransportController(0 /*reeval*/,
381                 THROTTLE_MS);
382 
383         // First delegate requests RCS message + File transfer
384         ArraySet<String> firstDelegate = new ArraySet<>(getBaseDelegateRequest().getFeatureTags());
385         firstDelegate.remove(ImsSignallingUtils.GROUP_CHAT_TAG);
386         DelegateRequest firstDelegateRequest = new DelegateRequest(firstDelegate);
387         SipDelegateControllerContainer c1 = injectMockDelegateController(TEST_PACKAGE_NAME,
388                 firstDelegateRequest);
389         createDelegateAndVerify(controller, c1, firstDelegate, Collections.emptySet());
390         // there is a delay in the indication to update reg, so it should not happen yet.
391         verifyNoDelegateRegistrationChangedEvent();
392 
393         // First delegate requests RCS message + Group RCS message. For this delegate, single RCS
394         // message should be denied.
395         ArraySet<String> secondDelegate = new ArraySet<>(getBaseDelegateRequest().getFeatureTags());
396         secondDelegate.remove(ImsSignallingUtils.FILE_TRANSFER_HTTP_TAG);
397         DelegateRequest secondDelegateRequest = new DelegateRequest(secondDelegate);
398         Pair<Set<String>, Set<FeatureTagState>> grantedAndDenied = getAllowedAndDeniedTagsForConfig(
399                 secondDelegateRequest, SipDelegateManager.DENIED_REASON_IN_USE_BY_ANOTHER_DELEGATE,
400                 firstDelegate);
401         SipDelegateControllerContainer c2 = injectMockDelegateController(TEST_PACKAGE_NAME,
402                 secondDelegateRequest);
403         createDelegateAndVerify(controller, c2, grantedAndDenied.first,
404                 grantedAndDenied.second, 1);
405         // a reg changed event should happen after wait.
406         verifyDelegateRegistrationChangedEvent(1, 2 * THROTTLE_MS);
407     }
408 
409     @SmallTest
410     @Test
createTwoAndTriggerRoleChange()411     public void createTwoAndTriggerRoleChange() throws Exception {
412         SipTransportController controller = setupLiveTransportController(0 /*reeval*/, THROTTLE_MS);
413 
414         DelegateRequest firstDelegateRequest = getBaseDelegateRequest();
415         Set<FeatureTagState> firstDeniedTags = getDeniedTagsForReason(
416                 firstDelegateRequest.getFeatureTags(),
417                 SipDelegateManager.DENIED_REASON_NOT_ALLOWED);
418         SipDelegateControllerContainer c1 = injectMockDelegateController(TEST_PACKAGE_NAME,
419                 firstDelegateRequest);
420         createDelegateAndVerify(controller, c1, firstDelegateRequest.getFeatureTags(),
421                 Collections.emptySet());
422         verifyDelegateRegistrationChangedEvent(1 /*times*/, THROTTLE_MS);
423 
424         DelegateRequest secondDelegateRequest = getBaseDelegateRequest();
425         Set<FeatureTagState> secondDeniedTags = getDeniedTagsForReason(
426                 secondDelegateRequest.getFeatureTags(),
427                 SipDelegateManager.DENIED_REASON_NOT_ALLOWED);
428         // Try to create a SipDelegate for a package that is not the default sms role.
429         SipDelegateControllerContainer c2 = injectMockDelegateController(TEST_PACKAGE_NAME_2,
430                 secondDelegateRequest);
431         createDelegateAndVerify(controller, c2, Collections.emptySet(), secondDeniedTags, 1);
432 
433         // now swap the SMS role.
434         CompletableFuture<Boolean> pendingC1Change = setChangeSupportedFeatureTagsFuture(
435                 c1.delegateController, Collections.emptySet(), firstDeniedTags);
436         CompletableFuture<Boolean> pendingC2Change = setChangeSupportedFeatureTagsFuture(
437                 c2.delegateController, secondDelegateRequest.getFeatureTags(),
438                 Collections.emptySet());
439         setSmsRoleAndEvaluate(controller, TEST_PACKAGE_NAME_2);
440         // swapping roles should trigger a deregistration event on the ImsService side.
441         verifyDelegateDeregistrationEvent();
442         // there should also not be any new registration changed events
443         verifyDelegateRegistrationChangedEvent(1 /*times*/, THROTTLE_MS);
444         // trigger completion stage to run
445         waitForExecutorAction(mExecutorService, TIMEOUT_MS);
446         verify(c1.delegateController).changeSupportedFeatureTags(Collections.emptySet(),
447                 firstDeniedTags);
448         // we should not get a change for c2 until pendingC1Change completes.
449         verify(c2.delegateController, never()).changeSupportedFeatureTags(
450                 secondDelegateRequest.getFeatureTags(), Collections.emptySet());
451         // ensure we are not blocking executor here
452         waitForExecutorAction(mExecutorService, TIMEOUT_MS);
453         completePendingChange(pendingC1Change, true);
454         // trigger completion stage to run
455         waitForExecutorAction(mExecutorService, TIMEOUT_MS);
456         verify(c2.delegateController).changeSupportedFeatureTags(
457                 secondDelegateRequest.getFeatureTags(), Collections.emptySet());
458         // ensure we are not blocking executor here
459         waitForExecutorAction(mExecutorService, TIMEOUT_MS);
460         completePendingChange(pendingC2Change, true);
461         // verify we now get a second registration changed event
462         verifyDelegateRegistrationChangedEvent(2 /*times*/, THROTTLE_MS);
463     }
464 
465     @SmallTest
466     @Test
createTwoAndDestroyOlder()467     public void createTwoAndDestroyOlder() throws Exception {
468         SipTransportController controller = setupLiveTransportController(0 /*reeval*/, THROTTLE_MS);
469 
470         // First delegate requests RCS message + File transfer
471         ArraySet<String> firstDelegate = new ArraySet<>(getBaseDelegateRequest().getFeatureTags());
472         firstDelegate.remove(ImsSignallingUtils.GROUP_CHAT_TAG);
473         DelegateRequest firstDelegateRequest = new DelegateRequest(firstDelegate);
474         SipDelegateControllerContainer c1 = injectMockDelegateController(TEST_PACKAGE_NAME,
475                 firstDelegateRequest);
476         createDelegateAndVerify(controller, c1, firstDelegate, Collections.emptySet());
477         verifyNoDelegateRegistrationChangedEvent();
478 
479         // First delegate requests RCS message + Group RCS message. For this delegate, single RCS
480         // message should be denied.
481         ArraySet<String> secondDelegate = new ArraySet<>(getBaseDelegateRequest().getFeatureTags());
482         secondDelegate.remove(ImsSignallingUtils.FILE_TRANSFER_HTTP_TAG);
483         DelegateRequest secondDelegateRequest = new DelegateRequest(secondDelegate);
484         Pair<Set<String>, Set<FeatureTagState>> grantedAndDenied = getAllowedAndDeniedTagsForConfig(
485                 secondDelegateRequest, SipDelegateManager.DENIED_REASON_IN_USE_BY_ANOTHER_DELEGATE,
486                 firstDelegate);
487         SipDelegateControllerContainer c2 = injectMockDelegateController(TEST_PACKAGE_NAME,
488                 secondDelegateRequest);
489         createDelegateAndVerify(controller, c2, grantedAndDenied.first, grantedAndDenied.second, 1);
490         verifyNoDelegateRegistrationChangedEvent();
491 
492         // Destroy the firstDelegate, which should now cause all previously denied tags to be
493         // granted to the new delegate.
494         CompletableFuture<Boolean> pendingC2Change = setChangeSupportedFeatureTagsFuture(
495                 c2.delegateController, secondDelegate, Collections.emptySet());
496         destroyDelegateAndVerify(controller, c1, false /*force*/,
497                 SipDelegateManager.SIP_DELEGATE_DESTROY_REASON_REQUESTED_BY_APP);
498         // wait for create to be processed.
499         assertTrue(waitForExecutorAction(mExecutorService, TIMEOUT_MS));
500         verify(c2.delegateController).changeSupportedFeatureTags(secondDelegate,
501                 Collections.emptySet());
502         completePendingChange(pendingC2Change, true);
503 
504         verifyDelegateRegistrationChangedEvent(1 /*times*/, THROTTLE_MS);
505     }
506 
507     @SmallTest
508     @Test
testThrottling()509     public void testThrottling() throws Exception {
510         SipTransportController controller = setupLiveTransportController(THROTTLE_MS, THROTTLE_MS);
511 
512         // First delegate requests RCS message + File transfer
513         ArraySet<String> firstDelegate = new ArraySet<>(getBaseDelegateRequest().getFeatureTags());
514         firstDelegate.remove(ImsSignallingUtils.GROUP_CHAT_TAG);
515         DelegateRequest firstDelegateRequest = new DelegateRequest(firstDelegate);
516         SipDelegateControllerContainer c1 = injectMockDelegateController(TEST_PACKAGE_NAME,
517                 firstDelegateRequest);
518         CompletableFuture<Boolean> pendingC1Change = createDelegate(controller, c1,
519                 firstDelegate, Collections.emptySet());
520 
521         // Request RCS message + group RCS Message. For this delegate, single RCS message should be
522         // denied.
523         ArraySet<String> secondDelegate = new ArraySet<>(getBaseDelegateRequest().getFeatureTags());
524         secondDelegate.remove(ImsSignallingUtils.FILE_TRANSFER_HTTP_TAG);
525         DelegateRequest secondDelegateRequest = new DelegateRequest(secondDelegate);
526         Pair<Set<String>, Set<FeatureTagState>> grantedAndDeniedC2 =
527                 getAllowedAndDeniedTagsForConfig(secondDelegateRequest,
528                         SipDelegateManager.DENIED_REASON_IN_USE_BY_ANOTHER_DELEGATE, firstDelegate);
529         SipDelegateControllerContainer c2 = injectMockDelegateController(TEST_PACKAGE_NAME,
530                 secondDelegateRequest);
531         CompletableFuture<Boolean> pendingC2Change = createDelegate(controller, c2,
532                 grantedAndDeniedC2.first, grantedAndDeniedC2.second);
533 
534         // Request group RCS message + file transfer. All should be denied at first
535         ArraySet<String> thirdDelegate = new ArraySet<>(getBaseDelegateRequest().getFeatureTags());
536         thirdDelegate.remove(ImsSignallingUtils.ONE_TO_ONE_CHAT_TAG);
537         DelegateRequest thirdDelegateRequest = new DelegateRequest(thirdDelegate);
538         Pair<Set<String>, Set<FeatureTagState>> grantedAndDeniedC3 =
539                 getAllowedAndDeniedTagsForConfig(thirdDelegateRequest,
540                         SipDelegateManager.DENIED_REASON_IN_USE_BY_ANOTHER_DELEGATE, firstDelegate,
541                         grantedAndDeniedC2.first);
542         SipDelegateControllerContainer c3 = injectMockDelegateController(TEST_PACKAGE_NAME,
543                 thirdDelegateRequest);
544         CompletableFuture<Boolean> pendingC3Change = createDelegate(controller, c3,
545                 grantedAndDeniedC3.first, grantedAndDeniedC3.second);
546 
547         verifyNoDelegateRegistrationChangedEvent();
548         assertTrue(scheduleDelayedWait(2 * THROTTLE_MS));
549         verifyDelegateChanged(c1.delegateController, pendingC1Change, firstDelegate,
550                 Collections.emptySet(), 0);
551         verifyDelegateChanged(c2.delegateController, pendingC2Change, grantedAndDeniedC2.first,
552                 grantedAndDeniedC2.second, 0);
553         verifyDelegateChanged(c3.delegateController, pendingC3Change, grantedAndDeniedC3.first,
554                 grantedAndDeniedC3.second, 0);
555         verifyDelegateRegistrationChangedEvent(1, 2 * THROTTLE_MS);
556 
557         // Destroy the first and second controller in quick succession, this should only generate
558         // one reevaluate for the third controller.
559         CompletableFuture<Boolean> pendingChangeC3 = setChangeSupportedFeatureTagsFuture(
560                 c3.delegateController, thirdDelegate, Collections.emptySet());
561         CompletableFuture<Integer> pendingDestroyC1 = destroyDelegate(controller,
562                 c1.delegateController, false /*force*/,
563                 SipDelegateManager.SIP_DELEGATE_DESTROY_REASON_REQUESTED_BY_APP);
564         CompletableFuture<Integer> pendingDestroyC2 = destroyDelegate(controller,
565                 c2.delegateController, false /*force*/,
566                 SipDelegateManager.SIP_DELEGATE_DESTROY_REASON_REQUESTED_BY_APP);
567         assertTrue(scheduleDelayedWait(2 * THROTTLE_MS));
568         verifyDestroyDelegate(c1.delegateController, pendingDestroyC1, false /*force*/,
569                 SipDelegateManager.SIP_DELEGATE_DESTROY_REASON_REQUESTED_BY_APP);
570         verifyDestroyDelegate(c2.delegateController, pendingDestroyC2, false /*force*/,
571                 SipDelegateManager.SIP_DELEGATE_DESTROY_REASON_REQUESTED_BY_APP);
572 
573         // All requested features should now be granted
574         completePendingChange(pendingChangeC3, true);
575         verify(c3.delegateController)
576                 .changeSupportedFeatureTags(thirdDelegate, Collections.emptySet());
577         // In total reeval should have only been called twice.
578         verify(c3.delegateController, times(2))
579                 .changeSupportedFeatureTags(any(), any());
580         verifyDelegateRegistrationChangedEvent(2 /*times*/, 2 * THROTTLE_MS);
581     }
582 
583     @SmallTest
584     @Test
testSubIdChangeDestroyTriggered()585     public void testSubIdChangeDestroyTriggered() throws Exception {
586         SipTransportController controller = setupLiveTransportController();
587 
588         ArraySet<String> firstDelegate = new ArraySet<>(getBaseDelegateRequest().getFeatureTags());
589         DelegateRequest firstDelegateRequest = new DelegateRequest(firstDelegate);
590         SipDelegateControllerContainer c = injectMockDelegateController(TEST_PACKAGE_NAME,
591                 firstDelegateRequest);
592         createDelegateAndVerify(controller, c, firstDelegate, Collections.emptySet());
593         verifyDelegateRegistrationChangedEvent(1 /*times*/, 0 /*waitMs*/);
594 
595         CompletableFuture<Integer> pendingDestroy =  setDestroyFuture(c.delegateController, true,
596                 SipDelegateManager.SIP_DELEGATE_DESTROY_REASON_SUBSCRIPTION_TORN_DOWN);
597         controller.onAssociatedSubscriptionUpdated(TEST_SUB_ID + 1);
598         waitForExecutorAction(mExecutorService, TIMEOUT_MS);
599         verifyDestroyDelegate(c.delegateController, pendingDestroy, true /*force*/,
600                 SipDelegateManager.SIP_DELEGATE_DESTROY_REASON_SUBSCRIPTION_TORN_DOWN);
601         verifyDelegateRegistrationChangedEvent(2 /*times*/, 0 /*waitMs*/);
602     }
603 
604     @SmallTest
605     @Test
testRcsManagerGoneDestroyTriggered()606     public void testRcsManagerGoneDestroyTriggered() throws Exception {
607         SipTransportController controller = setupLiveTransportController();
608 
609         ArraySet<String> firstDelegate = new ArraySet<>(getBaseDelegateRequest().getFeatureTags());
610         DelegateRequest firstDelegateRequest = new DelegateRequest(firstDelegate);
611         SipDelegateControllerContainer c = injectMockDelegateController(TEST_PACKAGE_NAME,
612                 firstDelegateRequest);
613         createDelegateAndVerify(controller, c, firstDelegate, Collections.emptySet());
614 
615         CompletableFuture<Integer> pendingDestroy =  setDestroyFuture(c.delegateController, true,
616                 SipDelegateManager.SIP_DELEGATE_DESTROY_REASON_SERVICE_DEAD);
617         controller.onRcsDisconnected();
618         waitForExecutorAction(mExecutorService, TIMEOUT_MS);
619         verifyDestroyDelegate(c.delegateController, pendingDestroy, true /*force*/,
620                 SipDelegateManager.SIP_DELEGATE_DESTROY_REASON_SERVICE_DEAD);
621         verifyDelegateRegistrationChangedEvent(1, 0 /*waitMs*/);
622     }
623 
624     @SmallTest
625     @Test
testDestroyTriggered()626     public void testDestroyTriggered() throws Exception {
627         SipTransportController controller = setupLiveTransportController();
628 
629         ArraySet<String> firstDelegate = new ArraySet<>(getBaseDelegateRequest().getFeatureTags());
630         DelegateRequest firstDelegateRequest = new DelegateRequest(firstDelegate);
631         SipDelegateControllerContainer c = injectMockDelegateController(TEST_PACKAGE_NAME,
632                 firstDelegateRequest);
633         createDelegateAndVerify(controller, c, firstDelegate, Collections.emptySet());
634 
635         CompletableFuture<Integer> pendingDestroy =  setDestroyFuture(c.delegateController,
636                 true, SipDelegateManager.SIP_DELEGATE_DESTROY_REASON_SUBSCRIPTION_TORN_DOWN);
637         controller.onDestroy();
638         waitForExecutorAction(mExecutorService, TIMEOUT_MS);
639         verifyDelegateDeregistrationEvent();
640         // verify change was called.
641         verify(c.delegateController).destroy(true /*force*/,
642                 SipDelegateManager.SIP_DELEGATE_DESTROY_REASON_SUBSCRIPTION_TORN_DOWN);
643         // ensure thread is not blocked while waiting for pending complete.
644         waitForExecutorAction(mExecutorService, TIMEOUT_MS);
645         completePendingDestroy(pendingDestroy,
646                 SipDelegateManager.SIP_DELEGATE_DESTROY_REASON_SUBSCRIPTION_TORN_DOWN);
647     }
648 
649     @SmallTest
650     @Test
testTimingSubIdChangedAndCreateNewSubId()651     public void testTimingSubIdChangedAndCreateNewSubId() throws Exception {
652         SipTransportController controller = setupLiveTransportController(THROTTLE_MS, 0);
653         setFeatureAllowedConfig(TEST_SUB_ID + 1, new String[]{ImsSignallingUtils.MMTEL_TAG,
654                 ImsSignallingUtils.ONE_TO_ONE_CHAT_TAG, ImsSignallingUtils.GROUP_CHAT_TAG,
655                 ImsSignallingUtils.FILE_TRANSFER_HTTP_TAG});
656 
657         ArraySet<String> firstDelegate = new ArraySet<>(getBaseDelegateRequest().getFeatureTags());
658         DelegateRequest firstDelegateRequest = new DelegateRequest(firstDelegate);
659         SipDelegateControllerContainer c1 = injectMockDelegateController(TEST_PACKAGE_NAME,
660                 firstDelegateRequest);
661         CompletableFuture<Boolean> pendingC1Change = createDelegate(controller, c1,
662                 firstDelegate, Collections.emptySet());
663         assertTrue(scheduleDelayedWait(2 * THROTTLE_MS));
664         verifyDelegateChanged(c1.delegateController, pendingC1Change, firstDelegate,
665                 Collections.emptySet(), 0);
666 
667 
668         CompletableFuture<Integer> pendingDestroy =  setDestroyFuture(c1.delegateController,
669                 true, SipDelegateManager.SIP_DELEGATE_DESTROY_REASON_SUBSCRIPTION_TORN_DOWN);
670         // triggers reeval now.
671         controller.onAssociatedSubscriptionUpdated(TEST_SUB_ID + 1);
672         waitForExecutorAction(mExecutorService, TIMEOUT_MS);
673 
674         // mock a second delegate with the new subId associated with the slot.
675         ArraySet<String> secondDelegate = new ArraySet<>();
676         secondDelegate.add(ImsSignallingUtils.ONE_TO_ONE_CHAT_TAG);
677         secondDelegate.add(ImsSignallingUtils.FILE_TRANSFER_HTTP_TAG);
678         DelegateRequest secondDelegateRequest = new DelegateRequest(secondDelegate);
679         SipDelegateControllerContainer c2 = injectMockDelegateController(TEST_SUB_ID + 1,
680                 TEST_PACKAGE_NAME, secondDelegateRequest);
681         CompletableFuture<Boolean> pendingC2Change = createDelegate(controller, c2, secondDelegate,
682                 Collections.emptySet());
683         assertTrue(scheduleDelayedWait(THROTTLE_MS));
684 
685         //trigger destroyed event
686         verifyDestroyDelegate(c1.delegateController, pendingDestroy, true /*force*/,
687                 SipDelegateManager.SIP_DELEGATE_DESTROY_REASON_SUBSCRIPTION_TORN_DOWN);
688         assertTrue(scheduleDelayedWait(2 * THROTTLE_MS));
689         verifyDelegateChanged(c2.delegateController, pendingC2Change, secondDelegate,
690                 Collections.emptySet(), 0);
691     }
692 
693     @SmallTest
694     @Test
testFeatureTagsDeniedByConfig()695     public void testFeatureTagsDeniedByConfig() throws Exception {
696         setFeatureAllowedConfig(TEST_SUB_ID, new String[]{ImsSignallingUtils.GROUP_CHAT_TAG,
697                 ImsSignallingUtils.FILE_TRANSFER_HTTP_TAG});
698         SipTransportController controller = setupLiveTransportController(THROTTLE_MS, 0);
699 
700         ArraySet<String> requestTags = new ArraySet<>(getBaseDelegateRequest().getFeatureTags());
701         ArraySet<String> allowedTags = new ArraySet<>(requestTags);
702         ArraySet<String> deniedTags = new ArraySet<>();
703         DelegateRequest delegateRequest = new DelegateRequest(requestTags);
704         SipDelegateControllerContainer c = injectMockDelegateController(TEST_PACKAGE_NAME,
705                 delegateRequest);
706         CompletableFuture<Boolean> pendingScChange = createDelegate(controller, c, requestTags,
707                 Collections.emptySet());
708         allowedTags.remove(ImsSignallingUtils.ONE_TO_ONE_CHAT_TAG);
709         deniedTags.add(ImsSignallingUtils.ONE_TO_ONE_CHAT_TAG);
710 
711         assertTrue(scheduleDelayedWait(2 * THROTTLE_MS));
712         verifyDelegateChanged(c.delegateController, pendingScChange, allowedTags,
713                 getDeniedTagsForReason(deniedTags,
714                         SipDelegateManager.DENIED_REASON_NOT_ALLOWED), 0);
715     }
716 
717     @SmallTest
718     @Test
testFeatureTagsDeniedByOverride()719     public void testFeatureTagsDeniedByOverride() throws Exception {
720         RcsProvisioningMonitor.getInstance().overrideImsFeatureValidation(TEST_SUB_ID, false);
721         SipTransportController controller = setupLiveTransportController(THROTTLE_MS, 0);
722 
723         ArraySet<String> requestTags = new ArraySet<>(getBaseDelegateRequest().getFeatureTags());
724         ArraySet<String> deniedTags = new ArraySet<>(requestTags);
725         DelegateRequest delegateRequest = new DelegateRequest(requestTags);
726         SipDelegateControllerContainer c = injectMockDelegateController(TEST_PACKAGE_NAME,
727                 delegateRequest);
728         CompletableFuture<Boolean> pendingScChange = createDelegate(controller, c, requestTags,
729                 Collections.emptySet());
730 
731         assertTrue(scheduleDelayedWait(2 * THROTTLE_MS));
732         verifyDelegateChanged(c.delegateController, pendingScChange, Collections.emptySet(),
733                 getDeniedTagsForReason(deniedTags,
734                         SipDelegateManager.DENIED_REASON_NOT_ALLOWED), 0);
735     }
736 
737     @SmallTest
738     @Test
testFeatureTagsDeniedByConfigAllowedByOverride()739     public void testFeatureTagsDeniedByConfigAllowedByOverride() throws Exception {
740         setFeatureAllowedConfig(TEST_SUB_ID, new String[]{});
741         RcsProvisioningMonitor.getInstance().overrideImsFeatureValidation(TEST_SUB_ID, true);
742         SipTransportController controller = setupLiveTransportController(THROTTLE_MS, 0);
743 
744         ArraySet<String> requestTags = new ArraySet<>(getBaseDelegateRequest().getFeatureTags());
745         ArraySet<String> allowedTags = new ArraySet<>(requestTags);
746         DelegateRequest delegateRequest = new DelegateRequest(requestTags);
747         SipDelegateControllerContainer controllerContainer =
748                 injectMockDelegateController(TEST_PACKAGE_NAME, delegateRequest);
749         CompletableFuture<Boolean> pendingScChange = createDelegate(controller, controllerContainer,
750                 requestTags, Collections.emptySet());
751 
752         assertTrue(scheduleDelayedWait(2 * THROTTLE_MS));
753         verifyDelegateChanged(controllerContainer.delegateController, pendingScChange, allowedTags,
754                 Collections.emptySet(), 0);
755     }
756 
757     @SafeVarargs
getAllowedAndDeniedTagsForConfig( DelegateRequest r, int denyReason, Set<String>... previousRequestedTagSets)758     private final Pair<Set<String>, Set<FeatureTagState>> getAllowedAndDeniedTagsForConfig(
759             DelegateRequest r, int denyReason, Set<String>... previousRequestedTagSets) {
760         ArraySet<String> rejectedTags = new ArraySet<>(r.getFeatureTags());
761         ArraySet<String> grantedTags = new ArraySet<>(r.getFeatureTags());
762         Set<String> previousRequestedTags = new ArraySet<>();
763         for (Set<String> s : previousRequestedTagSets) {
764             previousRequestedTags.addAll(s);
765         }
766         rejectedTags.retainAll(previousRequestedTags);
767         grantedTags.removeAll(previousRequestedTags);
768         Set<FeatureTagState> deniedTags = getDeniedTagsForReason(rejectedTags, denyReason);
769         return new Pair<>(grantedTags, deniedTags);
770     }
771 
completePendingChange(CompletableFuture<Boolean> change, boolean result)772     private void completePendingChange(CompletableFuture<Boolean> change, boolean result) {
773         mExecutorService.execute(() -> change.complete(result));
774         waitForExecutorAction(mExecutorService, TIMEOUT_MS);
775     }
776 
completePendingDestroy(CompletableFuture<Integer> destroy, int result)777     private void completePendingDestroy(CompletableFuture<Integer> destroy, int result) {
778         mExecutorService.execute(() -> destroy.complete(result));
779         waitForExecutorAction(mExecutorService, TIMEOUT_MS);
780     }
781 
setupLiveTransportController()782     private SipTransportController setupLiveTransportController() throws Exception {
783         return setupLiveTransportController(0 /*throttleMs*/, 0 /*regDelayMs*/);
784     }
785 
setupLiveTransportController(int throttleMs, int regDelayMs)786     private SipTransportController setupLiveTransportController(int throttleMs, int regDelayMs)
787             throws Exception {
788         mExecutorService = Executors.newSingleThreadScheduledExecutor();
789         SipTransportController controller = createControllerAndThrottle(mExecutorService,
790                 throttleMs, regDelayMs);
791         doReturn(mSipTransport).when(mRcsManager).getSipTransport();
792         controller.onAssociatedSubscriptionUpdated(TEST_SUB_ID);
793         controller.onRcsConnected(mRcsManager);
794         waitForExecutorAction(mExecutorService, TIMEOUT_MS);
795         return controller;
796     }
797 
createDelegateAndVerify(SipTransportController controller, SipDelegateControllerContainer controllerContainer, Set<String> allowedTags, Set<FeatureTagState> deniedTags, int numPreviousChanges)798     private void createDelegateAndVerify(SipTransportController controller,
799             SipDelegateControllerContainer controllerContainer, Set<String> allowedTags,
800             Set<FeatureTagState> deniedTags, int numPreviousChanges) {
801 
802         CompletableFuture<Boolean> pendingChange = createDelegate(controller, controllerContainer,
803                 allowedTags, deniedTags);
804         verifyDelegateChanged(controllerContainer.delegateController, pendingChange, allowedTags,
805                 deniedTags, numPreviousChanges);
806     }
807 
createDelegateAndVerify(SipTransportController controller, SipDelegateControllerContainer controllerContainer, Set<String> allowedTags, Set<FeatureTagState> deniedTags)808     private void createDelegateAndVerify(SipTransportController controller,
809             SipDelegateControllerContainer controllerContainer, Set<String> allowedTags,
810             Set<FeatureTagState> deniedTags) {
811         createDelegateAndVerify(controller, controllerContainer, allowedTags, deniedTags, 0);
812     }
813 
createDelegate(SipTransportController controller, SipDelegateControllerContainer delegateControllerContainer, Set<String> allowedTags, Set<FeatureTagState> deniedTags)814     private CompletableFuture<Boolean> createDelegate(SipTransportController controller,
815             SipDelegateControllerContainer delegateControllerContainer, Set<String> allowedTags,
816             Set<FeatureTagState> deniedTags) {
817         CompletableFuture<Boolean> pendingChange = setChangeSupportedFeatureTagsFuture(
818                 delegateControllerContainer.delegateController, allowedTags, deniedTags);
819         try {
820             controller.createSipDelegate(delegateControllerContainer.subId, TEST_UID,
821                     delegateControllerContainer.delegateRequest,
822                     delegateControllerContainer.packageName,
823                     delegateControllerContainer.mockDelegateConnectionCallback,
824                     delegateControllerContainer.mockMessageCallback);
825         } catch (ImsException e) {
826             fail("ImsException thrown:" + e);
827         }
828         // move to internal & schedule eval
829         waitForExecutorAction(mExecutorService, TIMEOUT_MS);
830         // reeval
831         waitForExecutorAction(mExecutorService, TIMEOUT_MS);
832         return pendingChange;
833     }
834 
verifyDelegateChanged(SipDelegateController delegateController, CompletableFuture<Boolean> pendingChange, Set<String> allowedTags, Set<FeatureTagState> deniedTags, int numPreviousChangeStages)835     private void verifyDelegateChanged(SipDelegateController delegateController,
836             CompletableFuture<Boolean> pendingChange, Set<String> allowedTags,
837             Set<FeatureTagState> deniedTags, int numPreviousChangeStages) {
838         // empty the queue of pending changeSupportedFeatureTags before running the one we are
839         // interested in, since the reevaluate waits for one stage to complete before moving to the
840         // next.
841         for (int i = 0; i < numPreviousChangeStages + 1; i++) {
842             assertTrue(waitForExecutorAction(mExecutorService, TIMEOUT_MS));
843         }
844         // verify change was called.
845         verify(delegateController).changeSupportedFeatureTags(allowedTags, deniedTags);
846         // ensure thread is not blocked while waiting for pending complete.
847         assertTrue(waitForExecutorAction(mExecutorService, TIMEOUT_MS));
848         completePendingChange(pendingChange, true);
849         // process pending change.
850         assertTrue(waitForExecutorAction(mExecutorService, TIMEOUT_MS));
851     }
852 
destroyDelegateAndVerify(SipTransportController controller, SipDelegateControllerContainer controllerContainer, boolean force, int reason)853     private void destroyDelegateAndVerify(SipTransportController controller,
854             SipDelegateControllerContainer controllerContainer, boolean force, int reason) {
855         SipDelegateController delegateController = controllerContainer.delegateController;
856         CompletableFuture<Integer> pendingDestroy =  destroyDelegate(controller, delegateController,
857                 force, reason);
858         verifyDestroyDelegate(delegateController, pendingDestroy, force, reason);
859     }
860 
destroyDelegate(SipTransportController controller, SipDelegateController delegateController, boolean force, int reason)861     private CompletableFuture<Integer> destroyDelegate(SipTransportController controller,
862             SipDelegateController delegateController, boolean force, int reason) {
863         CompletableFuture<Integer> pendingDestroy =  setDestroyFuture(delegateController, force,
864                 reason);
865         controller.destroySipDelegate(TEST_SUB_ID, delegateController.getSipDelegateInterface(),
866                 reason);
867         // move to internal & schedule eval
868         waitForExecutorAction(mExecutorService, TIMEOUT_MS);
869         // reeval
870         waitForExecutorAction(mExecutorService, TIMEOUT_MS);
871         return pendingDestroy;
872     }
873 
verifyDestroyDelegate(SipDelegateController delegateController, CompletableFuture<Integer> pendingDestroy, boolean force, int reason)874     private void verifyDestroyDelegate(SipDelegateController delegateController,
875             CompletableFuture<Integer> pendingDestroy, boolean force, int reason) {
876         // verify destroy was called.
877         verify(delegateController).destroy(force, reason);
878         // ensure thread is not blocked while waiting for pending complete.
879         waitForExecutorAction(mExecutorService, TIMEOUT_MS);
880         completePendingDestroy(pendingDestroy, reason);
881     }
882 
triggerFullNetworkRegistrationAndVerify(SipTransportController controller, SipDelegateControllerContainer controllerContainer)883     private void triggerFullNetworkRegistrationAndVerify(SipTransportController controller,
884             SipDelegateControllerContainer controllerContainer) {
885         SipDelegateController delegateController = controllerContainer.delegateController;
886         controller.triggerFullNetworkRegistration(TEST_SUB_ID,
887                 delegateController.getSipDelegateInterface(), 403, "forbidden");
888         // move to internal & trigger event
889         waitForExecutorAction(mExecutorService, TIMEOUT_MS);
890         verify(delegateController).triggerFullNetworkRegistration(403, "forbidden");
891     }
892 
triggerFullNetworkRegistrationAndVerifyNever(SipTransportController controller, SipDelegateControllerContainer controllerContainer)893     private void triggerFullNetworkRegistrationAndVerifyNever(SipTransportController controller,
894             SipDelegateControllerContainer controllerContainer) {
895         SipDelegateController delegateController = controllerContainer.delegateController;
896         controller.triggerFullNetworkRegistration(TEST_SUB_ID,
897                 delegateController.getSipDelegateInterface(), 403, "forbidden");
898         // move to internal & potentially trigger event
899         waitForExecutorAction(mExecutorService, TIMEOUT_MS);
900         verify(delegateController, never()).triggerFullNetworkRegistration(anyInt(), anyString());
901     }
902 
getBaseDelegateRequest()903     private DelegateRequest getBaseDelegateRequest() {
904         Set<String> featureTags = new ArraySet<>();
905         featureTags.add(ImsSignallingUtils.ONE_TO_ONE_CHAT_TAG);
906         featureTags.add(ImsSignallingUtils.GROUP_CHAT_TAG);
907         featureTags.add(ImsSignallingUtils.FILE_TRANSFER_HTTP_TAG);
908         return new DelegateRequest(featureTags);
909     }
910 
getDeniedTagsForReason(Set<String> deniedTags, int reason)911     private Set<FeatureTagState> getDeniedTagsForReason(Set<String> deniedTags, int reason) {
912         return deniedTags.stream().map(t -> new FeatureTagState(t, reason))
913                 .collect(Collectors.toSet());
914     }
915 
injectMockDelegateController(String packageName, DelegateRequest r)916     private SipDelegateControllerContainer injectMockDelegateController(String packageName,
917             DelegateRequest r) {
918         return injectMockDelegateController(TEST_SUB_ID, packageName, r);
919     }
920 
injectMockDelegateController(int subId, String packageName, DelegateRequest r)921     private SipDelegateControllerContainer injectMockDelegateController(int subId,
922             String packageName, DelegateRequest r) {
923         SipDelegateControllerContainer c = new SipDelegateControllerContainer(subId,
924                 packageName, r);
925         mMockControllers.add(c);
926         return c;
927     }
928 
getMockDelegateController(int subId, String packageName, DelegateRequest r)929     private SipDelegateController getMockDelegateController(int subId, String packageName,
930             DelegateRequest r) {
931         return mMockControllers.stream()
932                 .filter(c -> c.subId == subId && c.packageName.equals(packageName)
933                         && c.delegateRequest.equals(r))
934                 .map(c -> c.delegateController).findFirst().orElse(null);
935     }
936 
setChangeSupportedFeatureTagsFuture(SipDelegateController c, Set<String> supportedSet, Set<FeatureTagState> deniedSet)937     private CompletableFuture<Boolean> setChangeSupportedFeatureTagsFuture(SipDelegateController c,
938             Set<String> supportedSet, Set<FeatureTagState> deniedSet) {
939         CompletableFuture<Boolean> result = new CompletableFuture<>();
940         doReturn(result).when(c).changeSupportedFeatureTags(eq(supportedSet), eq(deniedSet));
941         return result;
942     }
943 
setDestroyFuture(SipDelegateController c, boolean force, int destroyReason)944     private CompletableFuture<Integer> setDestroyFuture(SipDelegateController c, boolean force,
945             int destroyReason) {
946         CompletableFuture<Integer> result = new CompletableFuture<>();
947         doReturn(result).when(c).destroy(force, destroyReason);
948         return result;
949     }
950 
setSmsRoleAndEvaluate(SipTransportController c, String packageName)951     private void setSmsRoleAndEvaluate(SipTransportController c, String packageName) {
952         verify(mMockRoleManager).addOnRoleHoldersChangedListenerAsUser(any(), any(), any());
953         mSmsPackageName.clear();
954         mSmsPackageName.add(packageName);
955         c.onRoleHoldersChanged(RoleManager.ROLE_SMS, UserHandle.SYSTEM);
956         // finish internal throttled re-evaluate
957         waitForExecutorAction(mExecutorService, TIMEOUT_MS);
958     }
959 
verifyNoDelegateRegistrationChangedEvent()960     private void verifyNoDelegateRegistrationChangedEvent() throws Exception {
961         // event is scheduled and then executed.
962         waitForExecutorAction(mExecutorService, TIMEOUT_MS);
963         verify(mImsRegistration, never()).triggerUpdateSipDelegateRegistration();
964     }
965 
verifyDelegateRegistrationChangedEvent(int times, int waitMs)966     private void verifyDelegateRegistrationChangedEvent(int times, int waitMs)
967             throws Exception {
968         // event is scheduled and then executed.
969         assertTrue(scheduleDelayedWait(waitMs));
970         waitForExecutorAction(mExecutorService, TIMEOUT_MS);
971         verify(mImsRegistration, times(times)).triggerUpdateSipDelegateRegistration();
972     }
973 
974 
verifyDelegateDeregistrationEvent()975     private void verifyDelegateDeregistrationEvent() throws Exception {
976         verify(mImsRegistration).triggerSipDelegateDeregistration();
977     }
978 
createController(ScheduledExecutorService e)979     private SipTransportController createController(ScheduledExecutorService e) {
980         return createControllerAndThrottle(e, 0 /*throttleMs*/, 0 /*regDelayMs*/);
981     }
982 
createControllerAndThrottle(ScheduledExecutorService e, int throttleMs, int regDelayMs)983     private SipTransportController createControllerAndThrottle(ScheduledExecutorService e,
984             int throttleMs, int regDelayMs) {
985         return new SipTransportController(mContext, 0 /*slotId*/, TEST_SUB_ID,
986                 mMockDelegateControllerFactory, mMockRoleManager,
987                 // Remove delays for testing.
988                 new SipTransportController.TimerAdapter() {
989                     @Override
990                     public int getReevaluateThrottleTimerMilliseconds() {
991                         return throttleMs;
992                     }
993 
994                     @Override
995                     public int getUpdateRegistrationDelayMilliseconds() {
996                         return regDelayMs;
997                     }
998                 }, e);
999     }
1000 
1001     private boolean scheduleDelayedWait(long timeMs) {
1002         CountDownLatch l = new CountDownLatch(1);
1003         mExecutorService.schedule(l::countDown, timeMs, TimeUnit.MILLISECONDS);
1004         while (l.getCount() > 0) {
1005             try {
1006                 return l.await(TIMEOUT_MS, TimeUnit.MILLISECONDS);
1007             } catch (InterruptedException e) {
1008                 // try again
1009             }
1010         }
1011         return true;
1012     }
1013 
1014     private void setFeatureAllowedConfig(int subId, String[] tags) {
1015         PersistableBundle bundle = mContext.getCarrierConfig(subId);
1016         bundle.putStringArray(
1017                 CarrierConfigManager.Ims.KEY_RCS_FEATURE_TAG_ALLOWED_STRING_ARRAY, tags);
1018     }
1019 }
1020