1 /*
2  * Copyright (C) 2021 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 android.telecom.cts;
18 
19 import static android.telecom.PhoneAccount.CAPABILITY_CALL_PROVIDER;
20 import static android.telecom.PhoneAccount.CAPABILITY_SELF_MANAGED;
21 
22 import android.content.ComponentName;
23 import android.content.Context;
24 import android.content.Intent;
25 import android.content.ServiceConnection;
26 import android.net.Uri;
27 import android.os.IBinder;
28 import android.os.Process;
29 import android.os.RemoteException;
30 import android.os.UserHandle;
31 import android.os.UserManager;
32 import android.telecom.PhoneAccount;
33 import android.telecom.PhoneAccountHandle;
34 import android.telecom.TelecomManager;
35 import android.telecom.cts.carmodetestapp.ICtsCarModeInCallServiceControl;
36 import android.telecom.cts.carmodetestappselfmanaged.CtsCarModeInCallServiceControlSelfManaged;
37 import android.util.ArraySet;
38 import android.util.Log;
39 
40 import com.android.compatibility.common.util.ApiTest;
41 import com.android.compatibility.common.util.ShellIdentityUtils;
42 import com.android.internal.telephony.flags.Flags;
43 
44 import java.util.ArrayList;
45 import java.util.List;
46 import java.util.Random;
47 import java.util.concurrent.CountDownLatch;
48 import java.util.concurrent.TimeUnit;
49 
50 public class PhoneAccountRegistrarTest extends BaseTelecomTestWithMockServices {
51 
52     private static final String TAG = "PhoneAccountRegistrarTest";
53     private static final long TIMEOUT = 3000L;
54     private static final int LARGE_ACCT_HANDLE_ID_MIN_SIZE = 50000;
55     private static final String RANDOM_CHAR_VALUE = "a";
56     private static final String TEL_PREFIX = "tel:";
57     private static final String TELECOM_CLEANUP_ACCTS_CMD = "telecom cleanup-orphan-phone-accounts";
58     public static final long SEED = 52L; // random seed chosen
59     public static final int MAX_PHONE_ACCOUNT_REGISTRATIONS = 10; // mirrors constant in...
60     // PhoneAccountRegistrar called MAX_PHONE_ACCOUNT_REGISTRATIONS
61 
62     // permissions
63     private static final String READ_PRIVILEGED_PHONE_STATE =
64             "android.permission.READ_PRIVILEGED_PHONE_STATE";
65     private static final String MODIFY_PHONE_STATE_PERMISSION =
66             "android.permission.MODIFY_PHONE_STATE";
67     private static final String REGISTER_SIM_SUBSCRIPTION_PERMISSION =
68             "android.permission.REGISTER_SIM_SUBSCRIPTION";
69     private static final String INTERACT_ACROSS_PROFILES =
70             "android.permission.INTERACT_ACROSS_PROFILES";
71 
72     // telecom cts test package (default package that registers phoneAccounts)
73     private static final ComponentName TEST_COMPONENT_NAME =
74             new ComponentName(TestUtils.PACKAGE, TestUtils.COMPONENT);
75 
76     // secondary test package (extra package that can be set up to register phoneAccounts)
77     private static final String SELF_MANAGED_CAR_PACKAGE =
78             CtsCarModeInCallServiceControlSelfManaged.class.getPackage().getName();
79     private static final ComponentName SELF_MANAGED_CAR_RELATIVE_COMPONENT = ComponentName
80             .createRelative(SELF_MANAGED_CAR_PACKAGE,
81                     CtsCarModeInCallServiceControlSelfManaged.class.getName());
82     private static final ComponentName CAR_COMPONENT = new ComponentName(SELF_MANAGED_CAR_PACKAGE,
83             TestUtils.SELF_MANAGED_COMPONENT);
84     private static final String CAR_MODE_CONTROL =
85             "android.telecom.cts.carmodetestapp.ACTION_CAR_MODE_CONTROL";
86     // variables to interface with the second test package
87     TestServiceConnection mControl;
88     ICtsCarModeInCallServiceControl mSecondaryTestPackageControl;
89 
90     @Override
setUp()91     public void setUp() throws Exception {
92         // Sets up this package as default dialer in super.
93         super.setUp();
94         NewOutgoingCallBroadcastReceiver.reset();
95         if (!mShouldTestTelecom) return;
96         setupConnectionService(null, 0);
97         // cleanup any accounts registered to the test package before starting tests
98         cleanupPhoneAccounts();
99     }
100 
101     @Override
tearDown()102     public void tearDown() throws Exception {
103         // cleanup any accounts registered to the test package after testing to avoid crashing other
104         // tests.
105         cleanupPhoneAccounts();
106         super.tearDown();
107     }
108 
109     /**
110      * Test scenario where a single package can register MAX_PHONE_ACCOUNT_REGISTRATIONS via
111      * {@link android.telecom.TelecomManager#registerPhoneAccount(PhoneAccount)}  without an
112      * exception being thrown.
113      */
testRegisterMaxPhoneAccountsWithoutException()114     public void testRegisterMaxPhoneAccountsWithoutException() {
115         if (!mShouldTestTelecom) return;
116 
117         // ensure the test starts without any phone accounts registered to the test package
118         cleanupPhoneAccounts();
119 
120         //  determine the number of phone accounts that can be registered before hitting limit
121         int numberOfAccountsThatCanBeRegistered = MAX_PHONE_ACCOUNT_REGISTRATIONS
122                 - getNumberOfPhoneAccountsRegisteredToTestPackage();
123 
124         // create the remaining number of phone accounts via helper function
125         // in order to reach the upper bound MAX_PHONE_ACCOUNT_REGISTRATIONS
126         ArrayList<PhoneAccount> accounts = TestUtils.generateRandomPhoneAccounts(SEED,
127                 numberOfAccountsThatCanBeRegistered, TestUtils.PACKAGE, TestUtils.COMPONENT);
128         try {
129             // register all accounts created
130             accounts.stream().forEach(a -> mTelecomManager.registerPhoneAccount(a));
131             // assert the maximum accounts that can be registered were registered successfully
132             assertEquals(MAX_PHONE_ACCOUNT_REGISTRATIONS,
133                     getNumberOfPhoneAccountsRegisteredToTestPackage());
134         } finally {
135             // cleanup accounts registered
136             accounts.stream().forEach(
137                     d -> mTelecomManager.unregisterPhoneAccount(d.getAccountHandle()));
138         }
139     }
140 
141     /**
142      * Tests a scenario where a PhoneAccount with more than MAX_PHONE_ACCOUNT_REGISTRATIONS
143      * PhoneAccountHandles set as a simultaneous calling restriction throws an
144      * {@link IllegalArgumentException}.
145      */
testExceptionThrownDueToInvalidSimultaneousCallRestriction_tooManyAccounts()146     public void testExceptionThrownDueToInvalidSimultaneousCallRestriction_tooManyAccounts() {
147         if (!mShouldTestTelecom || !Flags.simultaneousCallingIndications()) return;
148 
149         // ensure the test starts without any phone accounts registered to the test package
150         cleanupPhoneAccounts();
151 
152         // Create MAX_PHONE_ACCOUNT_REGISTRATIONS + 1 via helper function
153         ArrayList<PhoneAccountHandle> restrictionHandles =
154                 TestUtils.generateRandomPhoneAccountHandles(SEED,
155                 MAX_PHONE_ACCOUNT_REGISTRATIONS + 1, TestUtils.PACKAGE, TestUtils.COMPONENT);
156         PhoneAccountHandle acctHandle = TestUtils.makePhoneAccountHandle(
157                 TestUtils.DEFAULT_TEST_ACCOUNT_1_ID);
158         PhoneAccount acct = TestUtils.buildSelfManagedPhoneAccount(acctHandle,
159                         TestUtils.ACCOUNT_LABEL)
160                 .setSimultaneousCallingRestriction(new ArraySet<>(restrictionHandles)).build();
161 
162         try {
163             // Try to register more phone accounts than allowed by the upper bound limit
164             // MAX_PHONE_ACCOUNT_REGISTRATIONS
165             mTelecomManager.registerPhoneAccount(acct);
166             // A successful test should never reach this line of execution.
167             // However, if it does, fail the test by throwing a fail(...)
168             fail("Test failed. The test did not throw an IllegalArgumentException when "
169                     + "registering a phone account where the Set of PhoneAccountHandles in the "
170                     + "simultaneous calling restriction is over the upper bound: "
171                     + "MAX_PHONE_ACCOUNT_REGISTRATIONS");
172         } catch (IllegalArgumentException e) {
173             // Assert the IllegalArgumentException was thrown
174             assertNotNull(e.toString());
175         } finally {
176             // Cleanup accounts registered
177             mTelecomManager.unregisterPhoneAccount(acctHandle);
178         }
179     }
180 
181     /**
182      * Tests a scenario where a PhoneAccount contains a simultaneous calling restriction and the
183      * associated PhoneAccountHandle contains an ID where the field exceeds the maximum size.
184      */
testExceptionThrownDueToInvalidSimultaneousCallRestriction_invalidId()185     public void testExceptionThrownDueToInvalidSimultaneousCallRestriction_invalidId() {
186         if (!mShouldTestTelecom || !Flags.simultaneousCallingIndications()) return;
187 
188         // ensure the test starts without any phone accounts registered to the test package
189         cleanupPhoneAccounts();
190 
191         // Exceed the field size for the ID
192         ArraySet<PhoneAccountHandle> invalidRestrictionHandles = new ArraySet<>(1);
193         invalidRestrictionHandles.add(TestUtils.makePhoneAccountHandle("a".repeat(257)));
194         PhoneAccountHandle acctHandle = TestUtils.makePhoneAccountHandle(
195                 TestUtils.DEFAULT_TEST_ACCOUNT_1_ID);
196         PhoneAccount acct = TestUtils.buildSelfManagedPhoneAccount(acctHandle,
197                         TestUtils.ACCOUNT_LABEL)
198                 .setSimultaneousCallingRestriction(invalidRestrictionHandles).build();
199 
200         try {
201             // Try to register more phone accounts than allowed by the upper bound limit
202             // MAX_PHONE_ACCOUNT_REGISTRATIONS
203             mTelecomManager.registerPhoneAccount(acct);
204             // A successful test should never reach this line of execution.
205             // However, if it does, fail the test by throwing a fail(...)
206             fail("Test failed. The test did not throw an IllegalArgumentException when "
207                     + "registering a phone account where the Set of PhoneAccountHandles in the "
208                     + "simultaneous calling restriction is over the upper bound: "
209                     + "MAX_PHONE_ACCOUNT_REGISTRATIONS");
210         } catch (IllegalArgumentException e) {
211             // Assert the IllegalArgumentException was thrown
212             assertNotNull(e.toString());
213         } finally {
214             // Cleanup accounts registered
215             mTelecomManager.unregisterPhoneAccount(acctHandle);
216         }
217     }
218 
219     /**
220      * Tests a scenario where a single package exceeds MAX_PHONE_ACCOUNT_REGISTRATIONS and
221      * an {@link IllegalArgumentException}  is thrown. Will fail if no exception is thrown.
222      */
testExceptionThrownDueUserExceededMaxPhoneAccountRegistrations()223     public void testExceptionThrownDueUserExceededMaxPhoneAccountRegistrations()
224             throws IllegalArgumentException {
225         if (!mShouldTestTelecom) return;
226 
227         // ensure the test starts without any phone accounts registered to the test package
228         cleanupPhoneAccounts();
229 
230         // Create MAX_PHONE_ACCOUNT_REGISTRATIONS + 1 via helper function
231         ArrayList<PhoneAccount> accounts = TestUtils.generateRandomPhoneAccounts(SEED,
232                 MAX_PHONE_ACCOUNT_REGISTRATIONS + 1, TestUtils.PACKAGE,
233                 TestUtils.COMPONENT);
234 
235         try {
236             // Try to register more phone accounts than allowed by the upper bound limit
237             // MAX_PHONE_ACCOUNT_REGISTRATIONS
238             accounts.stream().forEach(a -> mTelecomManager.registerPhoneAccount(a));
239             // A successful test should never reach this line of execution.
240             // However, if it does, fail the test by throwing a fail(...)
241             fail("Test failed. The test did not throw an IllegalArgumentException when "
242                     + "registering phone accounts over the upper bound: "
243                     + "MAX_PHONE_ACCOUNT_REGISTRATIONS");
244         } catch (IllegalArgumentException e) {
245             // Assert the IllegalArgumentException was thrown
246             assertNotNull(e.toString());
247         } finally {
248             // Cleanup accounts registered
249             accounts.stream().forEach(d -> mTelecomManager.unregisterPhoneAccount(
250                     d.getAccountHandle()));
251         }
252     }
253 
254     /**
255      * Ensure an app does not register accounts over the upper bound limit by disabling them
256      */
testDisablingAccountsAfterRegStillThrowsException()257     public void testDisablingAccountsAfterRegStillThrowsException() throws Exception {
258         if (!mShouldTestTelecom) return;
259 
260         // ensure the test starts without any phone accounts registered to the test package
261         cleanupPhoneAccounts();
262 
263         // Create MAX_PHONE_ACCOUNT_REGISTRATIONS + 1 via helper function
264         ArrayList<PhoneAccount> accounts = TestUtils.generateRandomPhoneAccounts(SEED,
265                 MAX_PHONE_ACCOUNT_REGISTRATIONS + 1, TestUtils.PACKAGE,
266                 TestUtils.COMPONENT);
267 
268         try {
269             // Try to register more phone accounts than allowed by the upper bound limit
270             for (PhoneAccount pa : accounts) {
271                 mTelecomManager.registerPhoneAccount(pa);
272                 TestUtils.disablePhoneAccount(getInstrumentation(), pa.getAccountHandle());
273                 // verify the account is both registered and disabled
274                 verifyAccountIsDisabled(pa);
275             }
276 
277             // A successful test should never reach this line of execution.
278             // However, if it does, fail the test by throwing a fail(...)
279             fail("Test failed. The test did not throw an IllegalArgumentException when "
280                     + "registering phone accounts over the upper bound: "
281                     + "MAX_PHONE_ACCOUNT_REGISTRATIONS");
282         } catch (IllegalArgumentException e) {
283             // Assert the IllegalArgumentException was thrown
284             assertNotNull(e.toString());
285         } finally {
286             // Cleanup accounts registered
287             accounts.stream().forEach(d -> mTelecomManager.unregisterPhoneAccount(
288                     d.getAccountHandle()));
289         }
290     }
291 
292     /**
293      * Ensure an app does not register accounts that will be auto-disabled upon registered and
294      * bypass the limit. Note: CAPABILITY_CALL_PROVIDER will register the account as disabled.
295      */
testDisabledAccountsThrowsException()296     public void testDisabledAccountsThrowsException() throws Exception {
297         if (!mShouldTestTelecom) return;
298 
299         // ensure the test starts without any phone accounts registered to the test package
300         cleanupPhoneAccounts();
301 
302         // Create MAX_PHONE_ACCOUNT_REGISTRATIONS + 1
303         ArrayList<PhoneAccount> accounts = new ArrayList<>();
304         for (int i = 0; i < MAX_PHONE_ACCOUNT_REGISTRATIONS + 1; i++) {
305             accounts.add(new PhoneAccount.Builder(
306                     TestUtils.makePhoneAccountHandle(Integer.toString(i)),
307                     TestUtils.ACCOUNT_LABEL)
308                     .setCapabilities(CAPABILITY_CALL_PROVIDER)
309                     .build());
310         }
311 
312         try {
313             // Try to register more phone accounts than allowed by the upper bound limit
314             for (PhoneAccount pa : accounts) {
315                 mTelecomManager.registerPhoneAccount(pa);
316                 // verify the account is both registered and disabled
317                 verifyAccountIsDisabled(pa);
318             }
319             // A successful test should never reach this line of execution.
320             // However, if it does, fail the test by throwing a fail(...)
321             fail("Test failed. The test did not throw an IllegalArgumentException when "
322                     + "registering phone accounts over the upper bound: "
323                     + "MAX_PHONE_ACCOUNT_REGISTRATIONS");
324         } catch (IllegalArgumentException e) {
325             // Assert the IllegalArgumentException was thrown
326             assertNotNull(e.toString());
327         } finally {
328             // Cleanup accounts registered
329             accounts.stream().forEach(d -> mTelecomManager.unregisterPhoneAccount(
330                     d.getAccountHandle()));
331         }
332     }
333 
334     /**
335      * Test scenario where two distinct packages register MAX_PHONE_ACCOUNT_REGISTRATIONS via
336      * {@link
337      * android.telecom.TelecomManager#registerPhoneAccount(PhoneAccount)} without an exception being
338      * thrown.
339      * This ensures that PhoneAccountRegistrar is handling {@link PhoneAccount} registrations
340      * to distinct packages correctly.
341      */
testTwoPackagesRegisterMax()342     public void testTwoPackagesRegisterMax() throws Exception {
343         if (!mShouldTestTelecom) return;
344 
345         // ensure the test starts without any phone accounts registered to the test package
346         cleanupPhoneAccounts();
347 
348         //  determine the number of phone accounts that can be registered to package 1
349         int numberOfAccountsThatCanBeRegisteredToPackage1 = MAX_PHONE_ACCOUNT_REGISTRATIONS
350                 - getNumberOfPhoneAccountsRegisteredToTestPackage();
351 
352         // Create MAX phone accounts for package 1
353         ArrayList<PhoneAccount> accountsPackage1 = TestUtils.generateRandomPhoneAccounts(SEED,
354                 numberOfAccountsThatCanBeRegisteredToPackage1, TestUtils.PACKAGE,
355                 TestUtils.COMPONENT);
356 
357         // Constants for creating a second package to register phone accounts
358         final String carPkgSelfManaged =
359                 CtsCarModeInCallServiceControlSelfManaged.class
360                         .getPackage().getName();
361         final ComponentName carComponentSelfManaged = ComponentName.createRelative(
362                 carPkgSelfManaged, CtsCarModeInCallServiceControlSelfManaged.class.getName());
363         final String carModeControl =
364                 "android.telecom.cts.carmodetestapp.ACTION_CAR_MODE_CONTROL";
365 
366         // Set up binding for second package. This is needed in order to bypass a SecurityException
367         // thrown by a second test package registering phone accounts.
368         TestServiceConnection control = setUpControl(carModeControl,
369                 carComponentSelfManaged);
370 
371         ICtsCarModeInCallServiceControl carModeIncallServiceControlSelfManaged =
372                 ICtsCarModeInCallServiceControl.Stub
373                         .asInterface(control.getService());
374 
375         carModeIncallServiceControlSelfManaged.reset(); //... done setting up binding
376 
377         // Create MAX phone accounts for package 2
378         ArrayList<PhoneAccount> accountsPackage2 = TestUtils.generateRandomPhoneAccounts(SEED,
379                 MAX_PHONE_ACCOUNT_REGISTRATIONS, carPkgSelfManaged,
380                 TestUtils.SELF_MANAGED_COMPONENT);
381 
382         try {
383 
384             // register all accounts for package 1
385             accountsPackage1.stream().forEach(a -> mTelecomManager.registerPhoneAccount(a));
386 
387 
388             // register all phone accounts for package 2
389             for (int i = 0; i < MAX_PHONE_ACCOUNT_REGISTRATIONS; i++) {
390                 carModeIncallServiceControlSelfManaged.registerPhoneAccount(
391                         accountsPackage2.get(i));
392             }
393 
394         } finally {
395             // cleanup all phone accounts registered. Note, unregisterPhoneAccount will not
396             // cause a runtime error if no phone account is found when trying to unregister.
397 
398             accountsPackage1.stream().forEach(d -> mTelecomManager.unregisterPhoneAccount(
399                     d.getAccountHandle()));
400 
401             for (int i = 0; i < MAX_PHONE_ACCOUNT_REGISTRATIONS; i++) {
402                 carModeIncallServiceControlSelfManaged.unregisterPhoneAccount(
403                         accountsPackage2.get(i).getAccountHandle());
404             }
405         }
406         // unbind from second package
407         mContext.unbindService(control);
408     }
409 
410     /**
411      * Test the scenario where {@link android.telecom.TelecomManager
412      * #getCallCapablePhoneAccounts(boolean)} is called with a heavy payload
413      * that could cause a {@link android.os.TransactionTooLargeException}.  Telecom is expected to
414      * handle this by splitting the parcels via {@link android.content.pm.ParceledListSlice}.
415      */
testGettingLargeCallCapablePhoneAccountHandlePayload()416     public void testGettingLargeCallCapablePhoneAccountHandlePayload() throws Exception {
417         if (!mShouldTestTelecom) return;
418         // ensure the test starts without any phone accounts registered to the test package
419         cleanupPhoneAccounts();
420 
421         // generate a large phoneAccountHandle id string to create a large payload
422         String largeAccountHandleId = generateLargeString(
423                 LARGE_ACCT_HANDLE_ID_MIN_SIZE, RANDOM_CHAR_VALUE);
424         assertEquals(LARGE_ACCT_HANDLE_ID_MIN_SIZE, largeAccountHandleId.length());
425 
426         // create handles for package 1
427         List<PhoneAccount> phoneAccountsForPackage1 =
428                 generatePhoneAccountsForPackage(TEST_COMPONENT_NAME, largeAccountHandleId,
429                         numberOfPhoneAccountsCtsPackageCanRegister(), CAPABILITY_CALL_PROVIDER);
430 
431         //create handles for package 2
432         List<PhoneAccount> phoneAccountsForPackage2 =
433                 generatePhoneAccountsForPackage(CAR_COMPONENT, largeAccountHandleId,
434                         MAX_PHONE_ACCOUNT_REGISTRATIONS, CAPABILITY_CALL_PROVIDER);
435         try {
436             // register all accounts for package 1
437             phoneAccountsForPackage1.stream()
438                     .forEach(a -> mTelecomManager.registerPhoneAccount(a));
439             // verify all can be fetched
440             verifyCanFetchCallCapableAccounts();
441             // register all accounts for package 2
442             bindToSecondTestPackageAndRegisterAccounts(phoneAccountsForPackage2);
443             // verify all can be fetched
444             verifyCanFetchCallCapableAccounts();
445         } catch (IllegalArgumentException e) {
446             // allow test pass ...
447             Log.i(TAG, "testGettingLargeCallCapablePhoneAccountHandlePayload:"
448                     + " illegal arg exception thrown.");
449         } finally {
450             unbindSecondTestPackageAndUnregisterAccounts(phoneAccountsForPackage2);
451             cleanupPhoneAccounts();
452         }
453     }
454 
455     /**
456      * Test the scenario where {@link android.telecom.TelecomManager#getSelfManagedPhoneAccounts()}
457      * is called with a heavy payload that could cause a {@link
458      * android.os.TransactionTooLargeException}.  Telecom is expected to handle this by splitting
459      * the parcels via {@link android.content.pm.ParceledListSlice}.
460      */
testGettingLargeSelfManagedPhoneAccountHandlePayload()461     public void testGettingLargeSelfManagedPhoneAccountHandlePayload() throws Exception {
462         if (!mShouldTestTelecom) return;
463         // ensure the test starts without any phone accounts registered to the test package
464         cleanupPhoneAccounts();
465 
466         // generate a large phoneAccountHandle id string to create a large payload
467         String largeAccountHandleId = generateLargeString(
468                 LARGE_ACCT_HANDLE_ID_MIN_SIZE, RANDOM_CHAR_VALUE);
469         assertEquals(LARGE_ACCT_HANDLE_ID_MIN_SIZE, largeAccountHandleId.length());
470 
471         // create handles for package 1
472         List<PhoneAccount> phoneAccountsForPackage1 =
473                 generatePhoneAccountsForPackage(TEST_COMPONENT_NAME, largeAccountHandleId,
474                         numberOfPhoneAccountsCtsPackageCanRegister(), CAPABILITY_SELF_MANAGED);
475 
476         //create handles for package 2
477         List<PhoneAccount> phoneAccountsForPackage2 =
478                 generatePhoneAccountsForPackage(CAR_COMPONENT, largeAccountHandleId,
479                         MAX_PHONE_ACCOUNT_REGISTRATIONS, CAPABILITY_SELF_MANAGED);
480         try {
481             // register all accounts for package 1
482             phoneAccountsForPackage1.stream()
483                     .forEach(a -> mTelecomManager.registerPhoneAccount(a));
484             // verify all can be fetched
485             verifyCanFetchSelfManagedPhoneAccounts();
486             // register all accounts for package 2
487             bindToSecondTestPackageAndRegisterAccounts(phoneAccountsForPackage2);
488             // verify all can be fetched
489             verifyCanFetchSelfManagedPhoneAccounts();
490         } catch (IllegalArgumentException e) {
491             // allow test pass ...
492             Log.i(TAG, "testGettingLargeSelfManagedPhoneAccountHandlePayload:"
493                     + " illegal arg exception thrown.");
494         } finally {
495             unbindSecondTestPackageAndUnregisterAccounts(phoneAccountsForPackage2);
496             cleanupPhoneAccounts();
497         }
498     }
499 
500     /**
501      * Test the scenario where {@link android.telecom.TelecomManager#getAllPhoneAccountHandles()}
502      * is called with a heavy payload that could cause a {@link
503      * android.os.TransactionTooLargeException}.  Telecom is expected to handle this by splitting
504      * the parcels via {@link android.content.pm.ParceledListSlice}.
505      */
testGettingAllPhoneAccountHandlesWithLargePayload()506     public void testGettingAllPhoneAccountHandlesWithLargePayload() throws Exception {
507         if (!mShouldTestTelecom) return;
508 
509         // ensure the test starts without any phone accounts registered to the test package
510         cleanupPhoneAccounts();
511 
512         // generate a large phoneAccountHandle id string to create a large payload
513         String largeAccountHandleId = generateLargeString(
514                 LARGE_ACCT_HANDLE_ID_MIN_SIZE, RANDOM_CHAR_VALUE);
515         assertEquals(LARGE_ACCT_HANDLE_ID_MIN_SIZE, largeAccountHandleId.length());
516 
517         // create handles for package 1
518         List<PhoneAccount> phoneAccountsForPackage1 =
519                 generatePhoneAccountsForPackage(TEST_COMPONENT_NAME, largeAccountHandleId,
520                         numberOfPhoneAccountsCtsPackageCanRegister(), CAPABILITY_SELF_MANAGED);
521 
522         //create handles for package 2
523         List<PhoneAccount> phoneAccountsForPackage2 =
524                 generatePhoneAccountsForPackage(CAR_COMPONENT, largeAccountHandleId,
525                         MAX_PHONE_ACCOUNT_REGISTRATIONS, CAPABILITY_SELF_MANAGED);
526         try {
527             // register all accounts for package 1
528             phoneAccountsForPackage1.stream()
529                     .forEach(a -> mTelecomManager.registerPhoneAccount(a));
530             // verify all can be fetched
531             verifyCanFetchAllPhoneAccountHandles();
532             // register all accounts for package 2
533             bindToSecondTestPackageAndRegisterAccounts(phoneAccountsForPackage2);
534             // verify all can be fetched
535             verifyCanFetchAllPhoneAccountHandles();
536         } catch (IllegalArgumentException e) {
537             // allow test pass ...
538         } finally {
539 
540             unbindSecondTestPackageAndUnregisterAccounts(phoneAccountsForPackage2);
541             cleanupPhoneAccounts();
542         }
543     }
544 
545     /**
546      * Test the scenario where {@link TelecomManager#getAllPhoneAccounts()}
547      * is called with a heavy payload that could cause a {@link
548      * android.os.TransactionTooLargeException}.  Telecom is expected to handle this by splitting
549      * the parcels via {@link android.content.pm.ParceledListSlice}.
550      */
testGetAllPhoneAccountsWithLargePayload()551     public void testGetAllPhoneAccountsWithLargePayload() throws Exception {
552         if (!mShouldTestTelecom) return;
553 
554         // ensure the test starts without any phone accounts registered to the test package
555         cleanupPhoneAccounts();
556 
557         // generate a large phoneAccountHandle id string to create a large payload
558         String largeAccountHandleId = generateLargeString(
559                 LARGE_ACCT_HANDLE_ID_MIN_SIZE, RANDOM_CHAR_VALUE);
560         assertEquals(LARGE_ACCT_HANDLE_ID_MIN_SIZE, largeAccountHandleId.length());
561 
562         // create handles for package 1
563         List<PhoneAccount> phoneAccountsForPackage1 =
564                 generatePhoneAccountsForPackage(TEST_COMPONENT_NAME, largeAccountHandleId,
565                         numberOfPhoneAccountsCtsPackageCanRegister(),
566                         CAPABILITY_CALL_PROVIDER
567                                 | PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION);
568 
569         //create handles for package 2
570         List<PhoneAccount> phoneAccountsForPackage2 =
571                 generatePhoneAccountsForPackage(CAR_COMPONENT, largeAccountHandleId,
572                         MAX_PHONE_ACCOUNT_REGISTRATIONS,
573                         CAPABILITY_SELF_MANAGED);
574         try {
575             // register all accounts for package 1
576             for (PhoneAccount pa : phoneAccountsForPackage1) {
577                 ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mTelecomManager,
578                         tm -> tm.registerPhoneAccount(pa), REGISTER_SIM_SUBSCRIPTION_PERMISSION);
579             }
580             // verify all can be fetched
581             verifyCanFetchAllPhoneAccounts();
582             // register all accounts for package 2
583             bindToSecondTestPackageAndRegisterAccounts(phoneAccountsForPackage2);
584             // verify all can be fetched
585             verifyCanFetchAllPhoneAccounts();
586         } catch (IllegalArgumentException e) {
587             // allow test pass ...
588         } finally {
589             unbindSecondTestPackageAndUnregisterAccounts(phoneAccountsForPackage2);
590             cleanupPhoneAccounts();
591         }
592     }
593 
594     @ApiTest(apis = {
595             "android.telecom.TelecomManager#getCallCapablePhoneAccounts",
596             "android.telecom.TelecomManager#getCallCapablePhoneAccountsAcrossProfiles"})
testGetCallCapablePhoneAccountsAcrossProfiles()597     public void testGetCallCapablePhoneAccountsAcrossProfiles() throws Exception {
598         if (!mShouldTestTelecom || !Flags.workProfileApiSplit()) {
599             return;
600         }
601 
602         // ensure the test starts without any phone accounts registered to the test package
603         cleanupPhoneAccounts();
604 
605         List<PhoneAccountHandle> handles = mTelecomManager.getCallCapablePhoneAccounts();
606         List<PhoneAccountHandle> handlesAcrossProfiles = ShellIdentityUtils
607                 .invokeMethodWithShellPermissions(mTelecomManager,
608                         (tm) -> tm.getCallCapablePhoneAccountsAcrossProfiles(),
609                                 INTERACT_ACROSS_PROFILES);
610 
611         assertEquals(handles.size(), handlesAcrossProfiles.size());
612 
613         Random random = new Random(SEED);
614         PhoneAccountHandle handle1 = TestUtils.createPhoneAccountHandle(
615                 random, TestUtils.PACKAGE, TestUtils.REMOTE_COMPONENT,
616                 Process.myUserHandle().getIdentifier());
617         PhoneAccountHandle handle2 = TestUtils.createPhoneAccountHandle(
618                 random, TestUtils.PACKAGE, TestUtils.REMOTE_COMPONENT,
619                 Process.myUserHandle().getIdentifier());
620         PhoneAccount account1 = new PhoneAccount.Builder(
621                 handle1, this.getClass().getName())
622                 .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER)
623                 .build();
624         PhoneAccount account2 = new PhoneAccount.Builder(
625                 handle2, this.getClass().getName())
626                 .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER)
627                 .build();
628 
629         try {
630             mTelecomManager.registerPhoneAccount(account1);
631             mTelecomManager.registerPhoneAccount(account2);
632             TestUtils.enablePhoneAccount(getInstrumentation(), handle1);
633             TestUtils.enablePhoneAccount(getInstrumentation(), handle2);
634 
635             handles = mTelecomManager.getCallCapablePhoneAccounts();
636             handlesAcrossProfiles = ShellIdentityUtils
637                     .invokeMethodWithShellPermissions(mTelecomManager,
638                             (tm) -> tm.getCallCapablePhoneAccountsAcrossProfiles(),
639                                     INTERACT_ACROSS_PROFILES);
640 
641             assertEquals(handles, handlesAcrossProfiles);
642             assertTrue(handles.contains(handle1));
643             assertTrue(handles.contains(handle2));
644 
645             //test for disabled account
646             TestUtils.disablePhoneAccount(getInstrumentation(), handle2);
647 
648             handles = mTelecomManager.getCallCapablePhoneAccounts();
649             handlesAcrossProfiles = ShellIdentityUtils
650                     .invokeMethodWithShellPermissions(mTelecomManager,
651                             (tm) -> tm.getCallCapablePhoneAccountsAcrossProfiles(),
652                                     INTERACT_ACROSS_PROFILES);
653             List<PhoneAccountHandle> handlesAcrossProfilesWithDisabledAccount = ShellIdentityUtils
654                     .invokeMethodWithShellPermissions(mTelecomManager,
655                             (tm) -> tm.getCallCapablePhoneAccountsAcrossProfiles(true),
656                                     INTERACT_ACROSS_PROFILES);
657 
658             assertEquals(handles, handlesAcrossProfiles);
659             assertEquals(handles.size() + 1, handlesAcrossProfilesWithDisabledAccount.size());
660             assertTrue(handlesAcrossProfiles.containsAll(handles));
661             assertTrue(handlesAcrossProfilesWithDisabledAccount.contains(handle2));
662         } catch (IllegalArgumentException e) {
663             // allow test pass ...
664         } finally {
665             cleanupPhoneAccounts();
666         }
667     }
668 
669     @ApiTest(apis = {
670             "android.telecom.TelecomManager#getCallCapablePhoneAccounts",
671             "android.telecom.TelecomManager#getCallCapablePhoneAccountsAcrossProfiles"})
testGetCallCapablePhoneAccountsAcrossProfilesWithWorkProfile()672     public void testGetCallCapablePhoneAccountsAcrossProfilesWithWorkProfile() throws Exception {
673         if (!mShouldTestTelecom || !Flags.workProfileApiSplit() || !hasWorkProfile()) {
674             return;
675         }
676 
677         // ensure the test starts without any phone accounts registered to the test package
678         cleanupPhoneAccounts();
679 
680         Random random = new Random(SEED);
681         PhoneAccountHandle currentHandle = TestUtils.createPhoneAccountHandle(
682                 random, TestUtils.PACKAGE, TestUtils.REMOTE_COMPONENT,
683                 Process.myUserHandle().getIdentifier());
684         PhoneAccountHandle otherHandle = TestUtils.createPhoneAccountHandle(
685                 random, TestUtils.PACKAGE, TestUtils.REMOTE_COMPONENT,
686                 UserHandle.MIN_SECONDARY_USER_ID);
687 
688         PhoneAccount currentAccount = new PhoneAccount.Builder(
689                 currentHandle, this.getClass().getName())
690                 .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER)
691                 .build();
692         PhoneAccount otherAccount = new PhoneAccount.Builder(
693                 otherHandle, this.getClass().getName())
694                 .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER)
695                 .build();
696 
697         try {
698             mTelecomManager.registerPhoneAccount(currentAccount);
699             mTelecomManager.registerPhoneAccount(otherAccount);
700 
701             TestUtils.enablePhoneAccount(getInstrumentation(), currentHandle);
702             TestUtils.enablePhoneAccount(getInstrumentation(), otherHandle);
703 
704             List<PhoneAccountHandle> handlesCurrent = mTelecomManager.getCallCapablePhoneAccounts();
705             List<PhoneAccountHandle> handlesAcrossProfiles = ShellIdentityUtils
706                     .invokeMethodWithShellPermissions(mTelecomManager,
707                             (tm) -> tm.getCallCapablePhoneAccountsAcrossProfiles(),
708                                     INTERACT_ACROSS_PROFILES);
709 
710             assertEquals(handlesAcrossProfiles.size(), handlesCurrent.size() + 1);
711             assertTrue(handlesAcrossProfiles.containsAll(handlesCurrent));
712             assertTrue(handlesAcrossProfiles.contains(otherHandle));
713 
714             //test for disabled account
715             TestUtils.disablePhoneAccount(getInstrumentation(), currentHandle);
716 
717             handlesCurrent = mTelecomManager.getCallCapablePhoneAccounts();
718             handlesAcrossProfiles = ShellIdentityUtils
719                     .invokeMethodWithShellPermissions(mTelecomManager,
720                             (tm) -> tm.getCallCapablePhoneAccountsAcrossProfiles(),
721                                     INTERACT_ACROSS_PROFILES);
722             List<PhoneAccountHandle> handlesAcrossProfilesWithDisabledAccount = ShellIdentityUtils
723                     .invokeMethodWithShellPermissions(mTelecomManager,
724                             (tm) -> tm.getCallCapablePhoneAccountsAcrossProfiles(true),
725                                     INTERACT_ACROSS_PROFILES);
726 
727             assertEquals(handlesAcrossProfiles.size(), handlesCurrent.size() + 1);
728             assertEquals(handlesAcrossProfilesWithDisabledAccount.size(),
729                     handlesAcrossProfiles.size() + 1);
730             assertTrue(handlesAcrossProfiles.containsAll(handlesCurrent));
731             assertTrue(handlesAcrossProfilesWithDisabledAccount.containsAll(handlesAcrossProfiles));
732             assertTrue(handlesAcrossProfilesWithDisabledAccount.contains(currentHandle));
733         } catch (IllegalArgumentException e) {
734             // allow test pass ...
735         } finally {
736             cleanupPhoneAccounts();
737         }
738     }
739 
740     // -- The following are helper methods for this testing class. --
741 
generateLargeString(int size, String repeatStrValue)742     private String generateLargeString(int size, String repeatStrValue) {
743         StringBuilder sb = new StringBuilder();
744         for (int i = 0; i < size; i++) {
745             sb.append(repeatStrValue);
746         }
747         return sb.toString();
748     }
749 
generatePhoneAccountsForPackage(ComponentName cn, String baseId, int numOfAccountsToRegister, int capabilities)750     private List<PhoneAccount> generatePhoneAccountsForPackage(ComponentName cn, String baseId,
751             int numOfAccountsToRegister, int capabilities) {
752         List<PhoneAccount> accounts = new ArrayList<>();
753 
754         for (int i = 0; i < numOfAccountsToRegister; i++) {
755             String id = baseId + i;
756             PhoneAccountHandle pah = new PhoneAccountHandle(cn, id);
757             // create phoneAccount
758             String number = TEL_PREFIX + i;
759             PhoneAccount pa = PhoneAccount.builder(pah, TestUtils.ACCOUNT_LABEL)
760                     .setAddress(Uri.parse(number))
761                     .setSubscriptionAddress(Uri.parse(number))
762                     .addSupportedUriScheme(PhoneAccount.SCHEME_TEL)
763                     .setCapabilities(capabilities)
764                     .build();
765             accounts.add(pa);
766         }
767         return accounts;
768     }
769 
bindToSecondTestPackageAndRegisterAccounts(List<PhoneAccount> accounts)770     public void bindToSecondTestPackageAndRegisterAccounts(List<PhoneAccount> accounts)
771             throws Exception {
772         bindToSecondTestPackage();
773         registerAccountsToSecondTestPackage(accounts);
774     }
775 
unbindSecondTestPackageAndUnregisterAccounts(List<PhoneAccount> accounts)776     public void unbindSecondTestPackageAndUnregisterAccounts(List<PhoneAccount> accounts) {
777         try {
778             mContext.unbindService(mControl);
779             unRegisterAccountsForSecondTestPackage(accounts);
780         } catch (Exception e) {
781             Log.d(TAG,
782                     "exception thrown while trying to unbind and unregister accts for 2nd package");
783         }
784     }
785 
bindToSecondTestPackage()786     public void bindToSecondTestPackage() throws RemoteException {
787         // Set up binding for second package. This is needed in order to bypass a SecurityException
788         // thrown by a second test package registering phone accounts.
789         mControl = setUpControl(CAR_MODE_CONTROL, SELF_MANAGED_CAR_RELATIVE_COMPONENT);
790         mSecondaryTestPackageControl =
791                 ICtsCarModeInCallServiceControl.Stub.asInterface(mControl.getService());
792         // reset all package variables etc.
793         if (mSecondaryTestPackageControl != null) {
794             mSecondaryTestPackageControl.reset(); //... done setting up binding
795         }
796     }
797 
registerAccountsToSecondTestPackage(List<PhoneAccount> accounts)798     public void registerAccountsToSecondTestPackage(List<PhoneAccount> accounts)
799             throws Exception {
800         if (mSecondaryTestPackageControl != null) {
801             for (PhoneAccount p : accounts) {
802                 mSecondaryTestPackageControl.registerPhoneAccount(p);
803                 TestUtils.enablePhoneAccount(getInstrumentation(), p.getAccountHandle());
804             }
805         }
806     }
807 
unRegisterAccountsForSecondTestPackage(List<PhoneAccount> accounts)808     public void unRegisterAccountsForSecondTestPackage(List<PhoneAccount> accounts)
809             throws RemoteException {
810         if (mSecondaryTestPackageControl != null) {
811             for (PhoneAccount p : accounts) {
812                 mSecondaryTestPackageControl.unregisterPhoneAccount(p.getAccountHandle());
813             }
814         }
815     }
816 
verifyAccountIsDisabled(PhoneAccount account)817     public void verifyAccountIsDisabled(PhoneAccount account) {
818         PhoneAccount phoneAccount = mTelecomManager.getPhoneAccount(account.getAccountHandle());
819         assertNotNull(phoneAccount);
820         assertFalse(phoneAccount.isEnabled());
821     }
822 
verifyCanFetchCallCapableAccounts()823     public void verifyCanFetchCallCapableAccounts() {
824         List<PhoneAccountHandle> res =
825                 mTelecomManager.getCallCapablePhoneAccounts(true);
826         assertNotNull(res);
827         assertTrue(res.size() > 0);
828     }
829 
verifyCanFetchAllPhoneAccountHandles()830     public void verifyCanFetchAllPhoneAccountHandles() {
831         List<PhoneAccountHandle> res =
832                 ShellIdentityUtils.invokeMethodWithShellPermissions(
833                         mTelecomManager, (tm) -> tm.getAllPhoneAccountHandles(),
834                         MODIFY_PHONE_STATE_PERMISSION);
835         assertNotNull(res);
836         assertTrue(res.size() > 0);
837     }
838 
verifyCanFetchAllPhoneAccounts()839     public void verifyCanFetchAllPhoneAccounts() {
840         List<PhoneAccount> res =
841                 ShellIdentityUtils.invokeMethodWithShellPermissions(
842                         mTelecomManager, (tm) -> tm.getAllPhoneAccounts(),
843                         MODIFY_PHONE_STATE_PERMISSION);
844         assertNotNull(res);
845         assertTrue(res.size() > 0);
846     }
847 
verifyCanFetchSelfManagedPhoneAccounts()848     public void verifyCanFetchSelfManagedPhoneAccounts() {
849         List<PhoneAccountHandle> res =
850                 mTelecomManager.getSelfManagedPhoneAccounts();
851         assertNotNull(res);
852         assertTrue(res.size() > 0);
853     }
854 
numberOfPhoneAccountsCtsPackageCanRegister()855     private int numberOfPhoneAccountsCtsPackageCanRegister() {
856         return MAX_PHONE_ACCOUNT_REGISTRATIONS - getNumberOfPhoneAccountsRegisteredToTestPackage();
857     }
858 
setUpControl(String action, ComponentName componentName)859     private TestServiceConnection setUpControl(String action, ComponentName componentName) {
860         Intent bindIntent = new Intent(action);
861         bindIntent.setComponent(componentName);
862 
863         TestServiceConnection
864                 serviceConnection = new TestServiceConnection();
865         mContext.bindService(bindIntent, serviceConnection, Context.BIND_AUTO_CREATE);
866         if (!serviceConnection.waitBind()) {
867             fail("fail bind to service");
868         }
869         return serviceConnection;
870     }
871 
872     private class TestServiceConnection implements ServiceConnection {
873         private IBinder mService;
874         private CountDownLatch mLatch = new CountDownLatch(1);
875         private boolean mIsConnected;
876 
877         @Override
onServiceConnected(ComponentName componentName, IBinder service)878         public void onServiceConnected(ComponentName componentName, IBinder service) {
879             Log.i(TAG, "Service Connected: " + componentName);
880             mService = service;
881             mIsConnected = true;
882             mLatch.countDown();
883         }
884 
885         @Override
onServiceDisconnected(ComponentName componentName)886         public void onServiceDisconnected(ComponentName componentName) {
887             mService = null;
888         }
889 
getService()890         public IBinder getService() {
891             return mService;
892         }
893 
waitBind()894         public boolean waitBind() {
895             try {
896                 mLatch.await(TIMEOUT, TimeUnit.MILLISECONDS);
897                 return mIsConnected;
898             } catch (InterruptedException e) {
899                 return false;
900             }
901         }
902     }
903 
904     /**
905      * Helper that cleans up any phone accounts registered to this testing package.  Requires
906      * the permission READ_PRIVILEGED_PHONE_STATE in order to invoke the
907      * getPhoneAccountsForPackage() method.
908      */
cleanupPhoneAccounts()909     private void cleanupPhoneAccounts() {
910         try {
911             if (mTelecomManager != null) {
912                 // Get all handles registered to the testing package
913                 List<PhoneAccountHandle> handles =
914                         ShellIdentityUtils.invokeMethodWithShellPermissions(mTelecomManager,
915                                 (tm) -> tm.getPhoneAccountsForPackage(),
916                                 READ_PRIVILEGED_PHONE_STATE);
917 
918                 // cleanup any extra phone accounts registered to the testing package
919                 if (handles.size() > 0 && mTelecomManager != null) {
920                     handles.stream().forEach(
921                             d -> mTelecomManager.unregisterPhoneAccount(d));
922                 }
923 
924                 TestUtils.executeShellCommand(getInstrumentation(), TELECOM_CLEANUP_ACCTS_CMD);
925             }
926         } catch (Exception e) {
927             Log.d(TAG, "cleanupPhoneAccounts: hit exception while trying to clean");
928         }
929     }
930 
931     /**
932      * Helper that gets the number of phone accounts registered to the testing package. Requires
933      * the permission READ_PRIVILEGED_PHONE_STATE in order to invoke the
934      * getPhoneAccountsForPackage() method.
935      * @return number of phone accounts registered to the testing package.
936      */
getNumberOfPhoneAccountsRegisteredToTestPackage()937     private int getNumberOfPhoneAccountsRegisteredToTestPackage() {
938         if (mTelecomManager != null) {
939             return ShellIdentityUtils.invokeMethodWithShellPermissions(mTelecomManager,
940                     (tm) -> tm.getPhoneAccountsForPackage(),
941                     READ_PRIVILEGED_PHONE_STATE).size();
942         }
943         return 0;
944     }
945 
hasWorkProfile()946     private boolean hasWorkProfile() {
947         UserManager userManager = mContext.getSystemService(UserManager.class);
948         for (final UserHandle userHandle : userManager.getUserProfiles()) {
949             if (userManager.isManagedProfile(userHandle.getIdentifier())) {
950                 return true;
951             }
952         }
953 
954         return false;
955     }
956 }
957 
958