• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2016 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.carrierapi.cts;
18 
19 import static android.carrierapi.cts.FcpTemplate.FILE_IDENTIFIER;
20 import static android.carrierapi.cts.IccUtils.bytesToHexString;
21 import static android.carrierapi.cts.IccUtils.hexStringToBytes;
22 import static android.telephony.IccOpenLogicalChannelResponse.INVALID_CHANNEL;
23 import static android.telephony.IccOpenLogicalChannelResponse.STATUS_NO_ERROR;
24 import static android.telephony.SubscriptionManager.PHONE_NUMBER_SOURCE_CARRIER;
25 import static android.telephony.TelephonyManager.DATA_ENABLED_REASON_THERMAL;
26 import static android.telephony.TelephonyManager.DATA_ENABLED_REASON_USER;
27 
28 import static com.android.compatibility.common.util.UiccUtil.UiccCertificate.CTS_UICC_2021;
29 
30 import static com.google.common.truth.Truth.assertThat;
31 import static com.google.common.truth.Truth.assertWithMessage;
32 
33 import static org.junit.Assert.fail;
34 import static org.junit.Assume.assumeTrue;
35 
36 import android.content.BroadcastReceiver;
37 import android.content.ContentProviderClient;
38 import android.content.ContentValues;
39 import android.content.Context;
40 import android.content.Intent;
41 import android.content.IntentFilter;
42 import android.content.pm.PackageManager;
43 import android.database.Cursor;
44 import android.net.Uri;
45 import android.os.AsyncTask;
46 import android.os.Build;
47 import android.os.Handler;
48 import android.os.HandlerThread;
49 import android.os.ParcelUuid;
50 import android.os.PersistableBundle;
51 import android.platform.test.annotations.SystemUserOnly;
52 import android.provider.Telephony;
53 import android.provider.VoicemailContract;
54 import android.telephony.AccessNetworkConstants;
55 import android.telephony.AvailableNetworkInfo;
56 import android.telephony.CarrierConfigManager;
57 import android.telephony.IccOpenLogicalChannelResponse;
58 import android.telephony.PhoneStateListener;
59 import android.telephony.SignalStrengthUpdateRequest;
60 import android.telephony.SignalThresholdInfo;
61 import android.telephony.SubscriptionInfo;
62 import android.telephony.SubscriptionManager;
63 import android.telephony.TelephonyManager;
64 import android.telephony.data.NetworkSlicingConfig;
65 import android.util.Base64;
66 import android.util.Log;
67 
68 import androidx.test.runner.AndroidJUnit4;
69 
70 import com.android.compatibility.common.util.PollingCheck;
71 import com.android.compatibility.common.util.ShellIdentityUtils;
72 import com.android.compatibility.common.util.UiccUtil;
73 
74 import com.google.common.collect.Range;
75 
76 import org.junit.After;
77 import org.junit.Before;
78 import org.junit.Test;
79 import org.junit.runner.RunWith;
80 
81 import java.util.ArrayList;
82 import java.util.Arrays;
83 import java.util.Collections;
84 import java.util.HashSet;
85 import java.util.List;
86 import java.util.Set;
87 import java.util.concurrent.CompletableFuture;
88 import java.util.concurrent.CountDownLatch;
89 import java.util.concurrent.TimeUnit;
90 import java.util.concurrent.atomic.AtomicReference;
91 import java.util.function.Consumer;
92 import java.util.stream.Collectors;
93 
94 import javax.annotation.Nonnull;
95 
96 /**
97  * Unit tests for various carrier-related APIs.
98  *
99  * <p>Test using `atest CtsCarrierApiTestCases:CarrierApiTest` or `make cts -j64 && cts-tradefed run
100  * cts -m CtsCarrierApiTestCases --test android.carrierapi.cts.CarrierApiTest`
101  */
102 // TODO(b/130187425): Split CarrierApiTest apart to have separate test classes for functionality
103 @RunWith(AndroidJUnit4.class)
104 public class CarrierApiTest extends BaseCarrierApiTest {
105     private static final String TAG = "CarrierApiTest";
106 
107     private TelephonyManager mTelephonyManager;
108     private CarrierConfigManager mCarrierConfigManager;
109     private SubscriptionManager mSubscriptionManager;
110     private ContentProviderClient mVoicemailProvider;
111     private ContentProviderClient mStatusProvider;
112     private Uri mVoicemailContentUri;
113     private Uri mStatusContentUri;
114     private String selfPackageName;
115     private HandlerThread mListenerThread;
116 
117     // The minimum allocatable logical channel number, per TS 102 221 Section 11.1.17.1
118     private static final int MIN_LOGICAL_CHANNEL = 1;
119     // The maximum allocatable logical channel number in the standard range, per TS 102 221 Section
120     // 11.1.17.1
121     private static final int MAX_LOGICAL_CHANNEL = 3;
122     // Class bytes. The logical channel used should be included for bits b2b1. TS 102 221 Table 11.5
123     private static final int CLA_GET_RESPONSE = 0x00;
124     private static final int CLA_MANAGE_CHANNEL = 0x00;
125     private static final int CLA_READ_BINARY = 0x00;
126     private static final int CLA_SELECT = 0x00;
127     private static final int CLA_STATUS = 0x80;
128     private static final String CLA_STATUS_STRING = "80";
129     // APDU Instruction Bytes. TS 102 221 Section 10.1.2
130     private static final int COMMAND_GET_RESPONSE = 0xC0;
131     private static final int COMMAND_MANAGE_CHANNEL = 0x70;
132     private static final int COMMAND_READ_BINARY = 0xB0;
133     private static final int COMMAND_SELECT = 0xA4;
134     private static final int COMMAND_STATUS = 0xF2;
135     private static final String COMMAND_STATUS_STRING = "F2";
136     // Status words. TS 102 221 Section 10.2.1
137     private static final byte[] STATUS_NORMAL = {(byte) 0x90, (byte) 0x00};
138     private static final String STATUS_NORMAL_STRING = "9000";
139     private static final String STATUS_BYTES_REMAINING = "61";
140     private static final String STATUS_WARNING_A = "62";
141     private static final String STATUS_WARNING_B = "63";
142     private static final String STATUS_FILE_NOT_FOUND = "6a82";
143     private static final String STATUS_INCORRECT_PARAMETERS = "6a86";
144     private static final String STATUS_WRONG_PARAMETERS = "6b00";
145     private static final Set<String> INVALID_PARAMETERS_STATUSES =
146             new HashSet<>(Arrays.asList(STATUS_INCORRECT_PARAMETERS, STATUS_WRONG_PARAMETERS));
147     private static final String STATUS_WRONG_CLASS = "6e00";
148     // File ID for the EF ICCID. TS 102 221
149     private static final String ICCID_FILE_ID = "2FE2";
150     // File ID for the master file. TS 102 221
151     private static final String MF_FILE_ID = "3F00";
152     private static final int MF_FILE_ID_HEX = 0x3F00;
153     // File ID for the MF Access Rule Reference. TS 102 221
154     private static final String MF_ARR_FILE_ID = "2F06";
155     private static final String ALPHA_TAG_A = "tagA";
156     private static final String ALPHA_TAG_B = "tagB";
157     private static final String NUMBER_A = "1234567890";
158     private static final String NUMBER_B = "0987654321";
159     private static final String TESTING_PLMN = "12345";
160 
161     private static final String EAP_SIM_AKA_RAND = "11111111111111111111111111111111";
162 
163     // Derived from TS 134 108#8.1.2. Based on EAP_SIM_AKA_RAND and assumed K value of
164     // 000102030405060708090A0B0C0D0E0F, per TS 134 108#8.2
165     private static final String EAP_AKA_AUTN = "12351417161900001130131215141716";
166 
167     // EAP-AKA Response Format: [DB][Length][RES][Length][CK][Length][IK]
168     private static final int EAP_AKA_RESPONSE_LENGTH = 1 + 1 + 16 + 1 + 16 + 1 + 16;
169 
170     // Derived from TS 134 108#8.1.2. Based on EAP_SIM_AKA_RAND and assumed K value of
171     // 000102030405060708090A0B0C0D0E0F, per TS 134 108#8.2.
172     // Format: [DB][Length][RES][Length][CK][Length][IK]
173     private static final String EXPECTED_EAP_AKA_RESULT =
174             "DB10111013121514171619181B1A1D1C1F1E"
175                     + "101013121514171619181B1A1D1C1F1E11"
176                     + "1013121514171619181B1A1D1C1F1E1110";
177 
178     // Derived from TS 134 108#8.1.2 and TS 133 102#6.8.1.2. Based on EAP_SIM_AKA_RAND and assumed K
179     // value of 000102030405060708090A0B0C0D0E0F, per TS 134 108#8.2.
180     // Format: [Length][SRES][Length][Kc]
181     private static final String EXPECTED_EAP_SIM_RESULT = "0400000000080000000000000000";
182 
183     private static final int DSDS_PHONE_COUNT = 2;
184 
185     @Before
setUp()186     public void setUp() throws Exception {
187         Context context = getContext();
188         mTelephonyManager = context.getSystemService(TelephonyManager.class);
189         mCarrierConfigManager = context.getSystemService(CarrierConfigManager.class);
190         mSubscriptionManager = context.getSystemService(SubscriptionManager.class);
191         selfPackageName = context.getPackageName();
192         mVoicemailContentUri = VoicemailContract.Voicemails.buildSourceUri(selfPackageName);
193         mVoicemailProvider =
194                 context.getContentResolver().acquireContentProviderClient(mVoicemailContentUri);
195         mStatusContentUri = VoicemailContract.Status.buildSourceUri(selfPackageName);
196         mStatusProvider =
197                 context.getContentResolver().acquireContentProviderClient(mStatusContentUri);
198         mListenerThread = new HandlerThread("CarrierApiTest");
199         mListenerThread.start();
200     }
201 
202     @After
tearDown()203     public void tearDown() throws Exception {
204         if (!werePreconditionsSatisfied()) return;
205 
206         mListenerThread.quit();
207         try {
208             mStatusProvider.delete(mStatusContentUri, null, null);
209             mVoicemailProvider.delete(mVoicemailContentUri, null, null);
210         } catch (Exception e) {
211             Log.w(TAG, "Failed to clean up voicemail tables in tearDown", e);
212         }
213     }
214 
215     @Test
testSimCardPresent()216     public void testSimCardPresent() {
217         assertWithMessage("This test requires a SIM card")
218                 .that(mTelephonyManager.getSimState())
219                 .isNotEqualTo(TelephonyManager.SIM_STATE_ABSENT);
220     }
221 
222     @Test
testHasCarrierPrivileges()223     public void testHasCarrierPrivileges() {
224         assertWithMessage(NO_CARRIER_PRIVILEGES_FAILURE_MESSAGE)
225                 .that(mTelephonyManager.hasCarrierPrivileges())
226                 .isTrue();
227     }
228 
assertUpdateAvailableNetworkSuccess(int value)229     private static void assertUpdateAvailableNetworkSuccess(int value) {
230         assertThat(value).isEqualTo(TelephonyManager.UPDATE_AVAILABLE_NETWORKS_SUCCESS);
231     }
232 
assertUpdateAvailableNetworkNoOpportunisticSubAvailable(int value)233     private static void assertUpdateAvailableNetworkNoOpportunisticSubAvailable(int value) {
234         assertThat(value)
235                 .isEqualTo(
236                         TelephonyManager.UPDATE_AVAILABLE_NETWORKS_NO_OPPORTUNISTIC_SUB_AVAILABLE);
237     }
238 
assertSetOpportunisticSubSuccess(int value)239     private static void assertSetOpportunisticSubSuccess(int value) {
240         assertThat(value).isEqualTo(TelephonyManager.SET_OPPORTUNISTIC_SUB_SUCCESS);
241     }
242 
getFirstActivateCarrierPrivilegedSubscriptionId()243     private int getFirstActivateCarrierPrivilegedSubscriptionId() {
244         int subId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
245         List<SubscriptionInfo> subscriptionInfos =
246                 mSubscriptionManager.getActiveSubscriptionInfoList();
247         if (subscriptionInfos != null) {
248             for (SubscriptionInfo info : subscriptionInfos) {
249                 TelephonyManager telephonyManager =
250                         mTelephonyManager.createForSubscriptionId(info.getSubscriptionId());
251                 if (telephonyManager.hasCarrierPrivileges()) {
252                     subId = info.getSubscriptionId();
253                     return subId;
254                 }
255             }
256         }
257         return subId;
258     }
259 
260     @Test
testUpdateAvailableNetworksWithCarrierPrivilege()261     public void testUpdateAvailableNetworksWithCarrierPrivilege() {
262         int subIdWithCarrierPrivilege = getFirstActivateCarrierPrivilegedSubscriptionId();
263         int activeSubscriptionInfoCount =
264                 ShellIdentityUtils.invokeMethodWithShellPermissions(
265                         mSubscriptionManager, (tm) -> tm.getActiveSubscriptionInfoCount());
266         if (mTelephonyManager.getPhoneCount() == 1) {
267             return;
268         }
269 
270         /* TODO: b/145993690 */
271         if (mTelephonyManager.getPhoneCount() == 2 && activeSubscriptionInfoCount != 2) {
272             /* This test requires two SIM cards */
273             return;
274         }
275         if (subIdWithCarrierPrivilege == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
276             /* This test requires SIM with carrier privilege */
277             return;
278         }
279 
280         List<SubscriptionInfo> subscriptionInfoList =
281                 mSubscriptionManager.getOpportunisticSubscriptions();
282         List<String> mccMncs = new ArrayList<String>();
283         List<Integer> bands = new ArrayList<Integer>();
284         List<AvailableNetworkInfo> availableNetworkInfos = new ArrayList<AvailableNetworkInfo>();
285         Consumer<Integer> callbackSuccess = CarrierApiTest::assertUpdateAvailableNetworkSuccess;
286         Consumer<Integer> callbackNoOpportunisticSubAvailable =
287                 CarrierApiTest::assertUpdateAvailableNetworkNoOpportunisticSubAvailable;
288         Consumer<Integer> setOpCallbackSuccess = CarrierApiTest::assertSetOpportunisticSubSuccess;
289         if (subscriptionInfoList == null
290                 || subscriptionInfoList.size() == 0
291                 || !mSubscriptionManager.isActiveSubscriptionId(
292                         subscriptionInfoList.get(0).getSubscriptionId())) {
293             try {
294                 AvailableNetworkInfo availableNetworkInfo =
295                         new AvailableNetworkInfo(
296                                 subIdWithCarrierPrivilege,
297                                 AvailableNetworkInfo.PRIORITY_HIGH,
298                                 mccMncs,
299                                 bands);
300                 availableNetworkInfos.add(availableNetworkInfo);
301                 // Call updateAvailableNetworks without opportunistic subscription.
302                 // callbackNoOpportunisticSubAvailable is expected to be triggered
303                 // and the return value will be checked against
304                 // UPDATE_AVAILABLE_NETWORKS_NO_OPPORTUNISTIC_SUB_AVAILABLE
305                 mTelephonyManager.updateAvailableNetworks(
306                         availableNetworkInfos,
307                         AsyncTask.SERIAL_EXECUTOR,
308                         callbackNoOpportunisticSubAvailable);
309             } finally {
310                 // clear all the operations at the end of test.
311                 availableNetworkInfos.clear();
312                 mTelephonyManager.updateAvailableNetworks(
313                         availableNetworkInfos,
314                         AsyncTask.SERIAL_EXECUTOR,
315                         callbackNoOpportunisticSubAvailable);
316             }
317         } else {
318             // This is case of DSDS phone, one active opportunistic subscription and one
319             // active primary subscription.
320             int resultSubId;
321             try {
322                 AvailableNetworkInfo availableNetworkInfo =
323                         new AvailableNetworkInfo(
324                                 subscriptionInfoList.get(0).getSubscriptionId(),
325                                 AvailableNetworkInfo.PRIORITY_HIGH,
326                                 mccMncs,
327                                 bands);
328                 availableNetworkInfos.add(availableNetworkInfo);
329                 mTelephonyManager.updateAvailableNetworks(
330                         availableNetworkInfos, AsyncTask.SERIAL_EXECUTOR, callbackSuccess);
331                 // wait for the data change to take effect
332                 waitForMs(500);
333                 // Call setPreferredData and reconfirm with getPreferred data
334                 // that the same is updated.
335                 int preferSubId = subscriptionInfoList.get(0).getSubscriptionId();
336                 mTelephonyManager.setPreferredOpportunisticDataSubscription(
337                         preferSubId, false, AsyncTask.SERIAL_EXECUTOR, setOpCallbackSuccess);
338                 // wait for the data change to take effect
339                 waitForMs(500);
340                 resultSubId = mTelephonyManager.getPreferredOpportunisticDataSubscription();
341                 assertThat(resultSubId).isEqualTo(preferSubId);
342             } finally {
343                 // clear all the operations at the end of test.
344                 availableNetworkInfos.clear();
345                 mTelephonyManager.updateAvailableNetworks(
346                         availableNetworkInfos, AsyncTask.SERIAL_EXECUTOR, callbackSuccess);
347                 waitForMs(500);
348                 mTelephonyManager.setPreferredOpportunisticDataSubscription(
349                         SubscriptionManager.DEFAULT_SUBSCRIPTION_ID,
350                         false,
351                         AsyncTask.SERIAL_EXECUTOR,
352                         callbackSuccess);
353                 waitForMs(500);
354                 resultSubId = mTelephonyManager.getPreferredOpportunisticDataSubscription();
355                 assertThat(resultSubId).isEqualTo(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID);
356             }
357         }
358     }
359 
waitForMs(long ms)360     public static void waitForMs(long ms) {
361         try {
362             Thread.sleep(ms);
363         } catch (InterruptedException e) {
364             Log.d(TAG, "InterruptedException while waiting: " + e);
365         }
366     }
367 
368     @Test
testGetIccAuthentication()369     public void testGetIccAuthentication() {
370         // EAP-SIM rand is 16 bytes.
371         String base64Challenge = "ECcTqwuo6OfY8ddFRboD9WM=";
372         String base64Challenge2 = "EMNxjsFrPCpm+KcgCmQGnwQ=";
373 
374         try {
375             assertWithMessage("getIccAuthentication should return null for empty data.")
376                     .that(
377                             mTelephonyManager.getIccAuthentication(
378                                     TelephonyManager.APPTYPE_USIM,
379                                     TelephonyManager.AUTHTYPE_EAP_AKA,
380                                     ""))
381                     .isNull();
382             String response =
383                     mTelephonyManager.getIccAuthentication(
384                             TelephonyManager.APPTYPE_USIM,
385                             TelephonyManager.AUTHTYPE_EAP_SIM,
386                             base64Challenge);
387             assertWithMessage("Response to EAP-SIM Challenge must not be Null.")
388                     .that(response)
389                     .isNotNull();
390             // response is base64 encoded. After decoding, the value should be:
391             // 1 length byte + SRES(4 bytes) + 1 length byte + Kc(8 bytes)
392             byte[] result = android.util.Base64.decode(response, android.util.Base64.DEFAULT);
393             assertThat(result).hasLength(14);
394             String response2 =
395                     mTelephonyManager.getIccAuthentication(
396                             TelephonyManager.APPTYPE_USIM,
397                             TelephonyManager.AUTHTYPE_EAP_SIM,
398                             base64Challenge2);
399             assertWithMessage("Two responses must be different")
400                     .that(response)
401                     .isNotEqualTo(response2);
402         } catch (SecurityException e) {
403             fail(NO_CARRIER_PRIVILEGES_FAILURE_MESSAGE);
404         }
405     }
406 
407     @Test
408     @SystemUserOnly(reason = "b/177921545, broadcast sent only to primary user")
testSendDialerSpecialCode()409     public void testSendDialerSpecialCode() {
410         IntentReceiver intentReceiver = new IntentReceiver();
411         final IntentFilter intentFilter = new IntentFilter();
412         intentFilter.addAction(Telephony.Sms.Intents.SECRET_CODE_ACTION);
413         intentFilter.addDataScheme("android_secret_code");
414 
415         Context context = getContext();
416         context.registerReceiver(intentReceiver, intentFilter);
417         try {
418             mTelephonyManager.sendDialerSpecialCode("4636");
419             assertWithMessage(
420                             "Did not receive expected Intent: "
421                                     + Telephony.Sms.Intents.SECRET_CODE_ACTION)
422                     .that(intentReceiver.waitForReceive())
423                     .isTrue();
424         } catch (SecurityException e) {
425             fail(NO_CARRIER_PRIVILEGES_FAILURE_MESSAGE);
426         } catch (InterruptedException e) {
427             Log.d(TAG, "Broadcast receiver wait was interrupted.");
428         } finally {
429             context.unregisterReceiver(intentReceiver);
430         }
431     }
432 
433     @Test
testSubscriptionInfoListing()434     public void testSubscriptionInfoListing() {
435         try {
436             assertThat(mSubscriptionManager.getActiveSubscriptionInfoCount()).isGreaterThan(0);
437             List<SubscriptionInfo> subInfoList =
438                     mSubscriptionManager.getActiveSubscriptionInfoList();
439             assertWithMessage("getActiveSubscriptionInfoList() returned null")
440                     .that(subInfoList)
441                     .isNotNull();
442             assertWithMessage("getActiveSubscriptionInfoList() returned an empty list")
443                     .that(subInfoList)
444                     .isNotEmpty();
445             for (SubscriptionInfo info : subInfoList) {
446                 TelephonyManager tm =
447                         mTelephonyManager.createForSubscriptionId(info.getSubscriptionId());
448                 assertWithMessage(
449                                 "getActiveSubscriptionInfoList() returned an inaccessible"
450                                         + " subscription")
451                         .that(tm.hasCarrierPrivileges())
452                         .isTrue();
453 
454                 // Check other APIs to make sure they are accessible and return consistent info.
455                 SubscriptionInfo infoForSlot =
456                         mSubscriptionManager.getActiveSubscriptionInfoForSimSlotIndex(
457                                 info.getSimSlotIndex());
458                 assertWithMessage("getActiveSubscriptionInfoForSimSlotIndex() returned null")
459                         .that(infoForSlot)
460                         .isNotNull();
461                 assertWithMessage(
462                                 "getActiveSubscriptionInfoForSimSlotIndex() returned inconsistent"
463                                         + " info")
464                         .that(infoForSlot.getSubscriptionId())
465                         .isEqualTo(info.getSubscriptionId());
466 
467                 SubscriptionInfo infoForSubId =
468                         mSubscriptionManager.getActiveSubscriptionInfo(info.getSubscriptionId());
469                 assertWithMessage("getActiveSubscriptionInfo() returned null")
470                         .that(infoForSubId)
471                         .isNotNull();
472                 assertWithMessage("getActiveSubscriptionInfo() returned inconsistent info")
473                         .that(infoForSubId.getSubscriptionId())
474                         .isEqualTo(info.getSubscriptionId());
475             }
476         } catch (SecurityException e) {
477             fail(NO_CARRIER_PRIVILEGES_FAILURE_MESSAGE);
478         }
479     }
480 
481     @Test
testCarrierConfigIsAccessible()482     public void testCarrierConfigIsAccessible() {
483         try {
484             PersistableBundle bundle = mCarrierConfigManager.getConfig();
485             assertWithMessage("CarrierConfigManager#getConfig() returned null")
486                     .that(bundle)
487                     .isNotNull();
488             assertWithMessage("CarrierConfigManager#getConfig() returned empty bundle")
489                     .that(bundle.isEmpty())
490                     .isFalse();
491 
492             int subId = SubscriptionManager.getDefaultSubscriptionId();
493             bundle = mCarrierConfigManager.getConfigForSubId(subId);
494             assertWithMessage("CarrierConfigManager#getConfigForSubId() returned null")
495                     .that(bundle)
496                     .isNotNull();
497             assertWithMessage("CarrierConfigManager#getConfigForSubId() returned empty bundle")
498                     .that(bundle.isEmpty())
499                     .isFalse();
500         } catch (SecurityException e) {
501             fail(NO_CARRIER_PRIVILEGES_FAILURE_MESSAGE);
502         }
503     }
504 
505     @Test
testTelephonyApisAreAccessible()506     public void testTelephonyApisAreAccessible() {
507         // The following methods may return any value depending on the state of the device. Simply
508         // call them to make sure they do not throw any exceptions. Methods that return a device
509         // identifier will be accessible to apps with carrier privileges in Q, but this may change
510         // in a future release.
511         try {
512             mTelephonyManager.getDeviceId();
513             mTelephonyManager.getImei();
514             mTelephonyManager.getMeid();
515             mTelephonyManager.getDeviceSoftwareVersion();
516             mTelephonyManager.getNai();
517             mTelephonyManager.getDataNetworkType();
518             mTelephonyManager.getVoiceNetworkType();
519             mTelephonyManager.getSimSerialNumber();
520             mTelephonyManager.getSubscriberId();
521             mTelephonyManager.getGroupIdLevel1();
522             mTelephonyManager.getLine1Number();
523             mTelephonyManager.getVoiceMailNumber();
524             mTelephonyManager.getVisualVoicemailPackageName();
525             mTelephonyManager.getVoiceMailAlphaTag();
526             mTelephonyManager.getForbiddenPlmns();
527             mTelephonyManager.getServiceState();
528             mTelephonyManager.getManualNetworkSelectionPlmn();
529             mTelephonyManager.setForbiddenPlmns(new ArrayList<String>());
530             // TODO(b/235490259): test all slots once TM#isModemEnabledForSlot allows
531             mTelephonyManager.isModemEnabledForSlot(
532                     SubscriptionManager.getSlotIndex(mTelephonyManager.getSubscriptionId()));
533         } catch (SecurityException e) {
534             fail(NO_CARRIER_PRIVILEGES_FAILURE_MESSAGE);
535         }
536     }
537 
538     @Test
testVoicemailTableIsAccessible()539     public void testVoicemailTableIsAccessible() throws Exception {
540         ContentValues value = new ContentValues();
541         value.put(VoicemailContract.Voicemails.NUMBER, "0123456789");
542         value.put(VoicemailContract.Voicemails.SOURCE_PACKAGE, selfPackageName);
543         try {
544             Uri uri = mVoicemailProvider.insert(mVoicemailContentUri, value);
545             assertThat(uri).isNotNull();
546             Cursor cursor =
547                     mVoicemailProvider.query(
548                             uri,
549                             new String[] {
550                                 VoicemailContract.Voicemails.NUMBER,
551                                 VoicemailContract.Voicemails.SOURCE_PACKAGE
552                             },
553                             null,
554                             null,
555                             null);
556             assertThat(cursor).isNotNull();
557             assertThat(cursor.moveToFirst()).isTrue();
558             assertThat(cursor.getString(0)).isEqualTo("0123456789");
559             assertThat(cursor.getString(1)).isEqualTo(selfPackageName);
560             assertThat(cursor.moveToNext()).isFalse();
561         } catch (SecurityException e) {
562             fail(NO_CARRIER_PRIVILEGES_FAILURE_MESSAGE);
563         }
564     }
565 
566     @Test
testVoicemailStatusTableIsAccessible()567     public void testVoicemailStatusTableIsAccessible() throws Exception {
568         ContentValues value = new ContentValues();
569         value.put(
570                 VoicemailContract.Status.CONFIGURATION_STATE,
571                 VoicemailContract.Status.CONFIGURATION_STATE_OK);
572         value.put(VoicemailContract.Status.SOURCE_PACKAGE, selfPackageName);
573         try {
574             Uri uri = mStatusProvider.insert(mStatusContentUri, value);
575             assertThat(uri).isNotNull();
576             Cursor cursor =
577                     mVoicemailProvider.query(
578                             uri,
579                             new String[] {
580                                 VoicemailContract.Status.CONFIGURATION_STATE,
581                                 VoicemailContract.Status.SOURCE_PACKAGE
582                             },
583                             null,
584                             null,
585                             null);
586             assertThat(cursor).isNotNull();
587             assertThat(cursor.moveToFirst()).isTrue();
588             assertThat(cursor.getInt(0)).isEqualTo(VoicemailContract.Status.CONFIGURATION_STATE_OK);
589             assertThat(cursor.getString(1)).isEqualTo(selfPackageName);
590             assertThat(cursor.moveToNext()).isFalse();
591         } catch (SecurityException e) {
592             fail(NO_CARRIER_PRIVILEGES_FAILURE_MESSAGE);
593         }
594     }
595 
596     static final int READ_PHONE_STATE_LISTENERS =
597             PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR
598                     | PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR
599                     | PhoneStateListener.LISTEN_EMERGENCY_NUMBER_LIST;
600 
601     static final int READ_PRECISE_PHONE_STATE_LISTENERS =
602             PhoneStateListener.LISTEN_PRECISE_DATA_CONNECTION_STATE
603                     | PhoneStateListener.LISTEN_CALL_DISCONNECT_CAUSES
604                     | PhoneStateListener.LISTEN_IMS_CALL_DISCONNECT_CAUSES
605                     | PhoneStateListener.LISTEN_REGISTRATION_FAILURE
606                     | PhoneStateListener.LISTEN_BARRING_INFO;
607 
608     static final int CARRIER_PRIVILEGE_LISTENERS =
609             READ_PHONE_STATE_LISTENERS | READ_PRECISE_PHONE_STATE_LISTENERS;
610 
611     @Test
testGetManualNetworkSelectionPlmnPersisted()612     public void testGetManualNetworkSelectionPlmnPersisted() throws Exception {
613         if (mTelephonyManager.getPhoneType() != TelephonyManager.PHONE_TYPE_GSM) return;
614 
615         try {
616             mTelephonyManager.setNetworkSelectionModeManual(
617                     TESTING_PLMN /* operatorNumeric */, true /* persistSelection */);
618             String plmn = mTelephonyManager.getManualNetworkSelectionPlmn();
619             assertThat(plmn).isEqualTo(TESTING_PLMN);
620         } finally {
621             mTelephonyManager.setNetworkSelectionModeAutomatic();
622         }
623     }
624 
625     @Test
testPhoneStateListener()626     public void testPhoneStateListener() throws Exception {
627         PhoneStateListener psl = new PhoneStateListener((Runnable r) -> {});
628         try {
629             mTelephonyManager.listen(psl, CARRIER_PRIVILEGE_LISTENERS);
630         } finally {
631             mTelephonyManager.listen(psl, PhoneStateListener.LISTEN_NONE);
632         }
633     }
634 
635     @Test
testIsManualNetworkSelectionAllowed()636     public void testIsManualNetworkSelectionAllowed() throws Exception {
637         if (mTelephonyManager.getPhoneType() != TelephonyManager.PHONE_TYPE_GSM) return;
638 
639         try {
640             assertThat(mTelephonyManager.isManualNetworkSelectionAllowed()).isTrue();
641         } catch (SecurityException e) {
642             fail(NO_CARRIER_PRIVILEGES_FAILURE_MESSAGE);
643         }
644     }
645 
646     @Test
testGetNetworkSelectionMode()647     public void testGetNetworkSelectionMode() throws Exception {
648         try {
649             ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(
650                     mTelephonyManager, (tm) -> tm.setNetworkSelectionModeAutomatic());
651             int networkMode = mTelephonyManager.getNetworkSelectionMode();
652             assertThat(networkMode).isEqualTo(TelephonyManager.NETWORK_SELECTION_MODE_AUTO);
653         } catch (SecurityException e) {
654             fail(NO_CARRIER_PRIVILEGES_FAILURE_MESSAGE);
655         }
656     }
657 
658     @Test
testSubscriptionInfoChangeListener()659     public void testSubscriptionInfoChangeListener() throws Exception {
660         final AtomicReference<SecurityException> error = new AtomicReference<>();
661         final CountDownLatch latch = new CountDownLatch(1);
662         new Handler(mListenerThread.getLooper())
663                 .post(
664                         () -> {
665                             SubscriptionManager.OnSubscriptionsChangedListener listener =
666                                     new SubscriptionManager.OnSubscriptionsChangedListener();
667                             try {
668                                 mSubscriptionManager.addOnSubscriptionsChangedListener(listener);
669                             } catch (SecurityException e) {
670                                 error.set(e);
671                             } finally {
672                                 mSubscriptionManager.removeOnSubscriptionsChangedListener(listener);
673                                 latch.countDown();
674                             }
675                         });
676         assertWithMessage("Test timed out").that(latch.await(30L, TimeUnit.SECONDS)).isTrue();
677         if (error.get() != null) {
678             fail(NO_CARRIER_PRIVILEGES_FAILURE_MESSAGE);
679         }
680     }
681 
682     /**
683      * Test that it's possible to open logical channels to the ICC. This mirrors the Manage Channel
684      * command described in TS 102 221 Section 11.1.17.
685      */
686     @Test
testIccOpenLogicalChannel()687     public void testIccOpenLogicalChannel() {
688         // The AID here doesn't matter - we just need to open a valid connection. In this case, the
689         // specified AID ("") opens a channel and selects the MF.
690         IccOpenLogicalChannelResponse response = mTelephonyManager.iccOpenLogicalChannel("");
691         final int logicalChannel = response.getChannel();
692         try {
693             verifyValidIccOpenLogicalChannelResponse(response);
694         } finally {
695             mTelephonyManager.iccCloseLogicalChannel(logicalChannel);
696         }
697     }
698 
699     @Test
testIccOpenLogicalChannelWithValidP2()700     public void testIccOpenLogicalChannelWithValidP2() {
701         // {@link TelephonyManager#iccOpenLogicalChannel} sends a Manage Channel (open) APDU
702         // followed by a Select APDU with the given AID and p2 values. See Open Mobile API
703         // Specification v3.2 Section 6.2.7.h and TS 102 221 for details.
704         int p2 = 0x0C; // '0C' for no data returned (TS 102 221 Section 11.1.1.2)
705         IccOpenLogicalChannelResponse response = mTelephonyManager.iccOpenLogicalChannel("", p2);
706         final int logicalChannel = response.getChannel();
707         try {
708             verifyValidIccOpenLogicalChannelResponse(response);
709         } finally {
710             mTelephonyManager.iccCloseLogicalChannel(logicalChannel);
711         }
712     }
713 
714     @Test
testIccOpenLogicalChannelWithInvalidP2()715     public void testIccOpenLogicalChannelWithInvalidP2() {
716         // Valid p2 values are defined in TS 102 221 Table 11.2. Per Table 11.2, 0xF0 should be
717         // invalid. Any p2 values that produce non '9000'/'62xx'/'63xx' status words are treated as
718         // an error and the channel is not opened. Due to compatibility issues with older devices,
719         // this check is only enabled for new devices launching on Q+.
720         if (Build.VERSION.DEVICE_INITIAL_SDK_INT >= Build.VERSION_CODES.Q) {
721             int p2 = 0xF0;
722             IccOpenLogicalChannelResponse response =
723                     mTelephonyManager.iccOpenLogicalChannel("", p2);
724             final int logicalChannel = response.getChannel();
725             assertThat(logicalChannel).isEqualTo(INVALID_CHANNEL);
726             assertThat(response.getStatus()).isNotEqualTo(STATUS_NO_ERROR);
727         }
728     }
729 
730     /**
731      * Test that it's possible to close logical channels to the ICC. This follows the Manage Channel
732      * command described in TS 102 221 Section 11.1.17.
733      */
734     @Test
testIccCloseLogicalChannel()735     public void testIccCloseLogicalChannel() {
736         // The directory here doesn't matter - we just need to open a valid connection that can
737         // later be closed. In this case, the specified AID ("") opens a channel and selects the MF.
738         IccOpenLogicalChannelResponse response = mTelephonyManager.iccOpenLogicalChannel("");
739 
740         // Check that the select command succeeded. This ensures that the logical channel is indeed
741         // open.
742         assertThat(response.getSelectResponse()).isEqualTo(STATUS_NORMAL);
743         assertThat(mTelephonyManager.iccCloseLogicalChannel(response.getChannel())).isTrue();
744 
745         // Close opened channel twice.
746         try {
747             boolean result = mTelephonyManager.iccCloseLogicalChannel(response.getChannel());
748             assertThat(result).isFalse();
749         } catch (IllegalArgumentException ex) {
750             //IllegalArgumentException is expected sometimes because of different behaviour of modem
751         }
752 
753         // Channel 0 is guaranteed to be always available and cannot be closed, per TS 102 221
754         // Section 11.1.17
755         try {
756             mTelephonyManager.iccCloseLogicalChannel(0);
757             fail("Expected IllegalArgumentException");
758         } catch (IllegalArgumentException ex) {
759             // IllegalArgumentException is expected
760         }
761     }
762 
763     /**
764      * This test ensures that valid APDU instructions can be sent and processed by the ICC. To do
765      * so, APDUs are sent to: - get the status of the MF - select the Access Rule Reference (ARR)
766      * for the MF - get the FCP template response for the select
767      */
768     @Test
testIccTransmitApduLogicalChannel()769     public void testIccTransmitApduLogicalChannel() {
770         // An open LC is required for transmitting APDU commands. This opens an LC to the MF.
771         IccOpenLogicalChannelResponse iccOpenLogicalChannelResponse =
772                 mTelephonyManager.iccOpenLogicalChannel("");
773 
774         // Get the status of the current directory. This should match the MF. TS 102 221 Section
775         // 11.1.2
776         final int logicalChannel = iccOpenLogicalChannelResponse.getChannel();
777 
778         try {
779             int cla = CLA_STATUS;
780             int p1 = 0; // no indication of application status
781             int p2 = 0; // same response parameters as the SELECT in the iccOpenLogicalChannel()
782             // above
783             int p3 = 0; // length of 'data' payload
784             String data = "";
785             String response =
786                     mTelephonyManager.iccTransmitApduLogicalChannel(
787                             logicalChannel, cla, COMMAND_STATUS, p1, p2, p3, data);
788             FcpTemplate fcpTemplate = FcpTemplate.parseFcpTemplate(response);
789             // Check that the FCP Template's file ID matches the MF
790             assertThat(containsFileId(fcpTemplate, MF_FILE_ID)).isTrue();
791             assertThat(fcpTemplate.getStatus()).isEqualTo(STATUS_NORMAL_STRING);
792 
793             // Select the Access Rule Reference for the MF. Similar to the MF, this will exist
794             // across all SIM cards. TS 102 221 Section 11.1.1
795             cla = CLA_SELECT;
796             p1 = 0; // select EF by FID
797             p2 = 0x04; // requesting FCP template
798             p3 = 2; // data (FID to be selected) is 2 bytes
799             data = MF_ARR_FILE_ID;
800             response =
801                     mTelephonyManager.iccTransmitApduLogicalChannel(
802                             logicalChannel, cla, COMMAND_SELECT, p1, p2, p3, data);
803 
804             // Devices launching with Q or later must immediately return the FCP template from the
805             // previous SELECT command. Some devices that launched before Q return TPDUs (instead of
806             // APDUs) - these devices must issue a subsequent GET RESPONSE command to get the FCP
807             // template.
808             if (Build.VERSION.DEVICE_INITIAL_SDK_INT < Build.VERSION_CODES.Q) {
809                 // Conditionally need to send GET RESPONSE apdu based on response from
810                 // TelephonyManager
811                 if (response.startsWith(STATUS_BYTES_REMAINING)) {
812                     // Read the FCP template from the ICC. TS 102 221 Section 12.1.1
813                     cla = CLA_GET_RESPONSE;
814                     p1 = 0;
815                     p2 = 0;
816                     p3 = 0;
817                     data = "";
818                     response =
819                             mTelephonyManager.iccTransmitApduLogicalChannel(
820                                     logicalChannel, cla, COMMAND_GET_RESPONSE, p1, p2, p3, data);
821                 }
822             }
823 
824             fcpTemplate = FcpTemplate.parseFcpTemplate(response);
825             // Check that the FCP Template's file ID matches the selected ARR
826             assertThat(containsFileId(fcpTemplate, MF_ARR_FILE_ID)).isTrue();
827             assertThat(fcpTemplate.getStatus()).isEqualTo(STATUS_NORMAL_STRING);
828         } finally {
829             mTelephonyManager.iccCloseLogicalChannel(logicalChannel);
830         }
831     }
832 
833     /**
834      * Tests several invalid APDU instructions over a logical channel and makes sure appropriate
835      * errors are returned from the UICC.
836      */
837     @Test
testIccTransmitApduLogicalChannelWithInvalidInputs()838     public void testIccTransmitApduLogicalChannelWithInvalidInputs() {
839         // An open LC is required for transmitting apdu commands. This opens an LC to the MF.
840         IccOpenLogicalChannelResponse iccOpenLogicalChannelResponse =
841                 mTelephonyManager.iccOpenLogicalChannel("");
842         final int logicalChannel = iccOpenLogicalChannelResponse.getChannel();
843 
844         try {
845             // Make some invalid APDU commands and make sure they fail as expected.
846             // Use an invalid p1 value for Status apdu
847             int cla = CLA_STATUS | logicalChannel;
848             int p1 = 0xFF; // only '00', '01', and '02' are allowed
849             int p2 = 0; // same response parameters as the SELECT in the iccOpenLogicalChannel()
850             // above
851             int p3 = 0; // length of 'data' payload
852             String data = "";
853             String response =
854                     mTelephonyManager.iccTransmitApduLogicalChannel(
855                             logicalChannel, cla, COMMAND_STATUS, p1, p2, p3, data);
856             assertThat(INVALID_PARAMETERS_STATUSES.contains(response)).isTrue();
857 
858             // Select a file that doesn't exist
859             cla = CLA_SELECT;
860             p1 = 0x00; // select by file ID
861             p2 = 0x0C; // no data returned
862             p3 = 0x02; // length of 'data' payload
863             data = "FFFF"; // invalid file ID
864             response =
865                     mTelephonyManager.iccTransmitApduLogicalChannel(
866                             logicalChannel, cla, COMMAND_SELECT, p1, p2, p3, data);
867             assertThat(response).isEqualTo(STATUS_FILE_NOT_FOUND);
868 
869             // Manage channel with incorrect p1 parameter
870             cla = CLA_MANAGE_CHANNEL | logicalChannel;
871             p1 = 0x83; // Only '80' or '00' allowed for Manage Channel p1
872             p2 = logicalChannel; // channel to be closed
873             p3 = 0; // length of 'data' payload
874             data = "";
875             response =
876                     mTelephonyManager.iccTransmitApduLogicalChannel(
877                             logicalChannel, cla, COMMAND_MANAGE_CHANNEL, p1, p2, p3, data);
878             assertThat(isErrorResponse(response)).isTrue();
879 
880             // Use an incorrect class byte for Status apdu
881             cla = 0xFF;
882             p1 = 0; // no indication of application status
883             p2 = 0; // same response parameters as the SELECT in the iccOpenLogicalChannel() above
884             p3 = 0; // length of 'data' payload
885             data = "";
886             response =
887                     mTelephonyManager.iccTransmitApduLogicalChannel(
888                             logicalChannel, cla, COMMAND_STATUS, p1, p2, p3, data);
889             assertThat(response).isEqualTo(STATUS_WRONG_CLASS);
890 
891             // Provide a data field that is longer than described for Select apdu
892             cla = CLA_SELECT | logicalChannel;
893             p1 = 0; // select by file ID
894             p2 = 0x0C; // no data returned
895             p3 = 0x04; // data passed is actually 2 bytes long
896             data = "3F00"; // valid ID
897             response =
898                     mTelephonyManager.iccTransmitApduLogicalChannel(
899                             logicalChannel, cla, COMMAND_SELECT, p1, p2, p3, data);
900             assertThat(isErrorResponse(response)).isTrue();
901 
902             // Use an invalid instruction
903             cla = 0;
904             p1 = 0;
905             p2 = 0;
906             p3 = 0;
907             data = "";
908             int invalidInstruction = 0xFF; // see TS 102 221 Table 10.5 for valid instructions
909             response =
910                     mTelephonyManager.iccTransmitApduLogicalChannel(
911                             logicalChannel, cla, invalidInstruction, p1, p2, p3, data);
912             assertThat(isErrorResponse(response)).isTrue();
913         } finally {
914             mTelephonyManager.iccCloseLogicalChannel(logicalChannel);
915         }
916     }
917 
918     /**
919      * This test ensures that files can be read off the UICC. This helps to test the SIM booting
920      * process, as it process involves several file-reads. The ICCID is one of the first files read.
921      */
922     @Test
testApduFileRead()923     public void testApduFileRead() {
924         // Open a logical channel and select the MF.
925         IccOpenLogicalChannelResponse iccOpenLogicalChannel =
926                 mTelephonyManager.iccOpenLogicalChannel("");
927         final int logicalChannel = iccOpenLogicalChannel.getChannel();
928 
929         try {
930             // Select the ICCID. TS 102 221 Section 13.2
931             int p1 = 0; // select by file ID
932             int p2 = 0x0C; // no data returned
933             int p3 = 2; // length of 'data' payload
934             String response =
935                     mTelephonyManager.iccTransmitApduLogicalChannel(
936                             logicalChannel, CLA_SELECT, COMMAND_SELECT, p1, p2, p3, ICCID_FILE_ID);
937             assertThat(response).isEqualTo(STATUS_NORMAL_STRING);
938 
939             // Read the contents of the ICCID.
940             p1 = 0; // 0-byte offset
941             p2 = 0; // 0-byte offset
942             p3 = 0; // length of 'data' payload
943             response =
944                     mTelephonyManager.iccTransmitApduLogicalChannel(
945                             logicalChannel, CLA_READ_BINARY, COMMAND_READ_BINARY, p1, p2, p3, "");
946             assertThat(response).endsWith(STATUS_NORMAL_STRING);
947         } finally {
948             mTelephonyManager.iccCloseLogicalChannel(logicalChannel);
949         }
950     }
951 
952     /** This test sends several valid APDU commands over the basic channel (channel 0). */
953     @Test
testIccTransmitApduBasicChannel()954     public void testIccTransmitApduBasicChannel() {
955         // select the MF
956         int cla = CLA_SELECT;
957         int p1 = 0; // select EF by FID
958         int p2 = 0x0C; // requesting FCP template
959         int p3 = 2; // length of 'data' payload
960         String data = MF_FILE_ID;
961         String response =
962                 mTelephonyManager.iccTransmitApduBasicChannel(
963                         cla, COMMAND_SELECT, p1, p2, p3, data);
964         assertThat(response).isEqualTo(STATUS_NORMAL_STRING);
965 
966         // get the Status of the current file/directory
967         cla = CLA_STATUS;
968         p1 = 0; // no indication of application status
969         p2 = 0; // same response parameters as the SELECT in the iccOpenLogicalChannel() above
970         p3 = 0; // length of 'data' payload
971         data = "";
972         response =
973                 mTelephonyManager.iccTransmitApduBasicChannel(
974                         cla, COMMAND_STATUS, p1, p2, p3, data);
975         FcpTemplate fcpTemplate = FcpTemplate.parseFcpTemplate(response);
976         assertThat(containsFileId(fcpTemplate, MF_FILE_ID)).isTrue();
977 
978         // Manually open a logical channel
979         cla = CLA_MANAGE_CHANNEL;
980         p1 = 0; // open a logical channel
981         p2 = 0; // '00' for open command
982         p3 = 0; // length of data payload
983         data = "";
984         response =
985                 mTelephonyManager.iccTransmitApduBasicChannel(
986                         cla, COMMAND_MANAGE_CHANNEL, p1, p2, p3, data);
987         // response is in the format | 1 byte: channel number | 2 bytes: status word |
988         String responseStatus = response.substring(2);
989         assertThat(responseStatus).isEqualTo(STATUS_NORMAL_STRING);
990 
991         // Close the open channel
992         byte[] responseBytes = hexStringToBytes(response);
993         int channel = responseBytes[0];
994         cla = CLA_MANAGE_CHANNEL;
995         p1 = 0x80; // close a logical channel
996         p2 = channel; // the channel to be closed
997         p3 = 0; // length of data payload
998         data = "";
999         response =
1000                 mTelephonyManager.iccTransmitApduBasicChannel(
1001                         cla, COMMAND_MANAGE_CHANNEL, p1, p2, p3, data);
1002         assertThat(response).isEqualTo(STATUS_NORMAL_STRING);
1003     }
1004 
1005     /**
1006      * This test verifies that {@link TelephonyManager#setLine1NumberForDisplay(String, String)}
1007      * correctly sets the Line 1 alpha tag and number when called, and the phone number
1008      * of {@link SubscriptionManager#PHONE_NUMBER_SOURCE_CARRIER}.
1009      */
1010     @Test
testLine1NumberForDisplay()1011     public void testLine1NumberForDisplay() {
1012         int subId = SubscriptionManager.getDefaultSubscriptionId();
1013         // Cache original alpha tag and number values.
1014         String originalAlphaTag = mTelephonyManager.getLine1AlphaTag();
1015         String originalNumber = mTelephonyManager.getLine1Number();
1016 
1017         try {
1018             // clear any potentially overridden values and cache defaults
1019             mTelephonyManager.setLine1NumberForDisplay(null, null);
1020             String defaultAlphaTag = mTelephonyManager.getLine1AlphaTag();
1021             String defaultNumber = mTelephonyManager.getLine1Number();
1022 
1023             assertThat(mTelephonyManager.setLine1NumberForDisplay(ALPHA_TAG_A, NUMBER_A)).isTrue();
1024             assertThat(mTelephonyManager.getLine1AlphaTag()).isEqualTo(ALPHA_TAG_A);
1025             assertThat(mTelephonyManager.getLine1Number()).isEqualTo(NUMBER_A);
1026             assertThat(mSubscriptionManager.getPhoneNumber(subId, PHONE_NUMBER_SOURCE_CARRIER))
1027                     .isEqualTo(NUMBER_A);
1028 
1029             assertThat(mTelephonyManager.setLine1NumberForDisplay(ALPHA_TAG_B, NUMBER_B)).isTrue();
1030             assertThat(mTelephonyManager.getLine1AlphaTag()).isEqualTo(ALPHA_TAG_B);
1031             assertThat(mTelephonyManager.getLine1Number()).isEqualTo(NUMBER_B);
1032             assertThat(mSubscriptionManager.getPhoneNumber(subId, PHONE_NUMBER_SOURCE_CARRIER))
1033                     .isEqualTo(NUMBER_B);
1034 
1035             // null is used to clear the Line 1 alpha tag and number values.
1036             assertThat(mTelephonyManager.setLine1NumberForDisplay(null, null)).isTrue();
1037             assertThat(mTelephonyManager.getLine1AlphaTag()).isEqualTo(defaultAlphaTag);
1038             assertThat(mTelephonyManager.getLine1Number()).isEqualTo(defaultNumber);
1039             assertThat(mSubscriptionManager.getPhoneNumber(subId, PHONE_NUMBER_SOURCE_CARRIER))
1040                     .isEqualTo("");
1041         } finally {
1042             // Reset original alpha tag and number values.
1043             mTelephonyManager.setLine1NumberForDisplay(originalAlphaTag, originalNumber);
1044         }
1045     }
1046 
1047     /**
1048      * This test verifies that {@link TelephonyManager#setVoiceMailNumber(String, String)} correctly
1049      * sets the VoiceMail alpha tag and number when called.
1050      */
1051     @Test
testVoiceMailNumber()1052     public void testVoiceMailNumber() {
1053         // Cache original alpha tag and number values.
1054         String originalAlphaTag = mTelephonyManager.getVoiceMailAlphaTag();
1055         String originalNumber = mTelephonyManager.getVoiceMailNumber();
1056 
1057         try {
1058             assertThat(mTelephonyManager.setVoiceMailNumber(ALPHA_TAG_A, NUMBER_A)).isTrue();
1059             assertThat(mTelephonyManager.getVoiceMailAlphaTag()).isEqualTo(ALPHA_TAG_A);
1060             assertThat(mTelephonyManager.getVoiceMailNumber()).isEqualTo(NUMBER_A);
1061 
1062             assertThat(mTelephonyManager.setVoiceMailNumber(ALPHA_TAG_B, NUMBER_B)).isTrue();
1063             assertThat(mTelephonyManager.getVoiceMailAlphaTag()).isEqualTo(ALPHA_TAG_B);
1064             assertThat(mTelephonyManager.getVoiceMailNumber()).isEqualTo(NUMBER_B);
1065         } finally {
1066             // Reset original alpha tag and number values.
1067             mTelephonyManager.setVoiceMailNumber(originalAlphaTag, originalNumber);
1068         }
1069     }
1070 
1071     /**
1072      * This test verifies that {@link SubscriptionManager#createSubscriptionGroup(List)} correctly
1073      * create a group with the given subscription id.
1074      *
1075      * <p>This also verifies that {@link SubscriptionManager#removeSubscriptionsFromGroup(List,
1076      * ParcelUuid)} correctly remove the given subscription group.
1077      */
1078     @Test
testCreateAndRemoveSubscriptionGroup()1079     public void testCreateAndRemoveSubscriptionGroup() {
1080         // Set subscription group with current sub Id.
1081         int subId = SubscriptionManager.getDefaultSubscriptionId();
1082         List<Integer> subGroup = Arrays.asList(subId);
1083         ParcelUuid uuid = mSubscriptionManager.createSubscriptionGroup(subGroup);
1084 
1085         // Getting subscriptions in group.
1086         List<SubscriptionInfo> infoList = mSubscriptionManager.getSubscriptionsInGroup(uuid);
1087 
1088         try {
1089             assertThat(infoList).hasSize(1);
1090             assertThat(infoList.get(0).getGroupUuid()).isEqualTo(uuid);
1091             assertThat(infoList.get(0).getSubscriptionId()).isEqualTo(subId);
1092         } finally {
1093             // Verify that the given subGroup has been removed.
1094             mSubscriptionManager.removeSubscriptionsFromGroup(subGroup, uuid);
1095             infoList = mSubscriptionManager.getSubscriptionsInGroup(uuid);
1096             assertThat(infoList).isEmpty();
1097         }
1098     }
1099 
1100     @Test
testAddSubscriptionToExistingGroupForMultipleSims()1101     public void testAddSubscriptionToExistingGroupForMultipleSims() {
1102         if (mTelephonyManager.getPhoneCount() < DSDS_PHONE_COUNT
1103                 || mSubscriptionManager.getActiveSubscriptionInfoList().size() < DSDS_PHONE_COUNT) {
1104             // This test requires at least two active subscriptions.
1105             return;
1106         }
1107 
1108         // Set subscription group with current sub Id.
1109         int subId = SubscriptionManager.getDefaultSubscriptionId();
1110         if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) return;
1111         ParcelUuid uuid = ShellIdentityUtils.invokeMethodWithShellPermissions(mSubscriptionManager,
1112                 (sm) -> sm.createSubscriptionGroup(Arrays.asList(subId)));
1113 
1114         try {
1115             // Get all active subscriptions.
1116             List<SubscriptionInfo> activeSubInfos =
1117                     ShellIdentityUtils.invokeMethodWithShellPermissions(mSubscriptionManager,
1118                     (sm) -> sm.getActiveSubscriptionInfoList());
1119 
1120             List<Integer> activeSubGroup = getSubscriptionIdList(activeSubInfos);
1121             activeSubGroup.removeIf(id -> id == subId);
1122 
1123             ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mSubscriptionManager,
1124                     (sm) -> sm.addSubscriptionsIntoGroup(activeSubGroup, uuid));
1125 
1126             List<Integer> infoList = ShellIdentityUtils.invokeMethodWithShellPermissions(
1127                     mSubscriptionManager,
1128                     (sm) -> getSubscriptionIdList(sm.getSubscriptionsInGroup(uuid)));
1129 
1130             activeSubGroup.add(subId);
1131             assertThat(infoList).containsExactlyElementsIn(activeSubGroup);
1132         } finally {
1133             removeSubscriptionsFromGroup(uuid);
1134         }
1135     }
1136 
1137     /**
1138      * This test verifies that {@link SubscriptionManager#addSubscriptionsIntoGroup(List,
1139      * ParcelUuid)}} correctly add some additional subscriptions to the existing group.
1140      *
1141      * <p>This test required the device has more than one subscription.
1142      */
1143     @Test
testAddSubscriptionToExistingGroupForEsim()1144     public void testAddSubscriptionToExistingGroupForEsim() {
1145         // Set subscription group with current sub Id.
1146         int subId = SubscriptionManager.getDefaultSubscriptionId();
1147         if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) return;
1148         ParcelUuid uuid = mSubscriptionManager.createSubscriptionGroup(Arrays.asList(subId));
1149 
1150         try {
1151             // Get all accessible eSim subscription.
1152             List<SubscriptionInfo> accessibleSubInfos =
1153                     mSubscriptionManager.getAccessibleSubscriptionInfoList();
1154             if (accessibleSubInfos != null && accessibleSubInfos.size() > 1) {
1155                 List<Integer> accessibleSubGroup = getSubscriptionIdList(accessibleSubInfos);
1156                 accessibleSubGroup.removeIf(id -> id == subId);
1157 
1158                 mSubscriptionManager.addSubscriptionsIntoGroup(accessibleSubGroup, uuid);
1159 
1160                 List<Integer> infoList =
1161                         getSubscriptionIdList(mSubscriptionManager.getSubscriptionsInGroup(uuid));
1162                 accessibleSubGroup.add(subId);
1163                 assertThat(infoList).containsExactlyElementsIn(accessibleSubGroup);
1164             }
1165         } finally {
1166             removeSubscriptionsFromGroup(uuid);
1167         }
1168     }
1169 
1170     /**
1171      * This test verifies that {@link SubscriptionManager#setOpportunistic(boolean, int)} correctly
1172      * set the opportunistic property of the given subscription.
1173      */
1174     @Test
testOpportunistic()1175     public void testOpportunistic() {
1176         int subId = SubscriptionManager.getDefaultSubscriptionId();
1177         if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) return;
1178         SubscriptionInfo info = mSubscriptionManager.getActiveSubscriptionInfo(subId);
1179         boolean oldOpportunistic = info.isOpportunistic();
1180         boolean newOpportunistic = !oldOpportunistic;
1181 
1182         try {
1183             // Mark the given subscription as opportunistic subscription.
1184             assertThat(mSubscriptionManager.setOpportunistic(newOpportunistic, subId)).isTrue();
1185 
1186             // Verify that the given subscription is opportunistic subscription.
1187             info = mSubscriptionManager.getActiveSubscriptionInfo(subId);
1188             assertThat(info.isOpportunistic()).isEqualTo(newOpportunistic);
1189         } finally {
1190             // Set back to original opportunistic property.
1191             mSubscriptionManager.setOpportunistic(oldOpportunistic, subId);
1192             info = mSubscriptionManager.getActiveSubscriptionInfo(subId);
1193             assertThat(info.isOpportunistic()).isEqualTo(oldOpportunistic);
1194 
1195             // As opportunistic subscription can not be the default data/voice/sms subscription,
1196             // when the test case set the active subscription as opportunistic, the default
1197             // subscription may set to INVALID_SUBSCRIPTION_ID. Although at the end, the test case
1198             // tries to recover it, it may take time to fully take effort and fail the following
1199             // test case. Add a polling check of carrier privilege on default subscription here to
1200             // make sure default subscription has recovered before ending the case.
1201             PollingCheck.waitFor(5000, () -> getContext().getSystemService(TelephonyManager.class)
1202                     .hasCarrierPrivileges(),
1203                     "Timeout when waiting to gain carrier privileges again.");
1204         }
1205     }
1206 
1207     /**
1208      * This test verifies that {@link TelephonyManager#iccExchangeSimIO(int, int, int, int, int,
1209      * String)} correctly transmits iccIO commands to the UICC card. First, the MF is selected via a
1210      * SELECT apdu via the basic channel, then a STATUS AT-command is sent.
1211      */
1212     @Test
testIccExchangeSimIO()1213     public void testIccExchangeSimIO() {
1214         // select the MF first. This makes sure the next STATUS AT-command returns a FCP template
1215         // for the right file.
1216         int cla = CLA_SELECT;
1217         int p1 = 0; // select EF by FID
1218         int p2 = 0x0C; // requesting FCP template
1219         int p3 = 2; // length of 'data' payload
1220         String data = MF_FILE_ID;
1221         String response =
1222                 mTelephonyManager.iccTransmitApduBasicChannel(
1223                         cla, COMMAND_SELECT, p1, p2, p3, data);
1224         assertThat(response).isEqualTo(STATUS_NORMAL_STRING);
1225 
1226         // The iccExchangeSimIO command implements the +CRSM command defined in TS 27.007 section
1227         // 8.18. A STATUS command is sent and the returned value will be an FCP template.
1228         byte[] result =
1229                 mTelephonyManager.iccExchangeSimIO(
1230                         0, // fileId: not required for STATUS
1231                         COMMAND_STATUS, // command: STATUS
1232                         0, // p1: not required for STATUS
1233                         0, // p2: not required for STATUS
1234                         0, // p3: not required for STATUS
1235                         ""); // filePath: not required for STATUS
1236         String resultString = bytesToHexString(result);
1237         FcpTemplate fcpTemplate = FcpTemplate.parseFcpTemplate(resultString);
1238         assertThat(containsFileId(fcpTemplate, MF_FILE_ID)).isTrue();
1239         assertWithMessage("iccExchangeSimIO returned non-normal Status byte: %s", resultString)
1240                 .that(fcpTemplate.getStatus())
1241                 .isEqualTo(STATUS_NORMAL_STRING);
1242     }
1243 
1244     /**
1245      * This test checks that a STATUS apdu can be sent as an encapsulated envelope to the UICC via
1246      * {@link TelephonyManager#sendEnvelopeWithStatus(String)}.
1247      */
1248     @Test
testSendEnvelopeWithStatus()1249     public void testSendEnvelopeWithStatus() {
1250         // STATUS apdu as hex String
1251         String envelope =
1252                 CLA_STATUS_STRING
1253                         + COMMAND_STATUS_STRING
1254                         + "00" // p1: no indication of application status
1255                         + "00"; // p2: identical parameters to
1256         String response = mTelephonyManager.sendEnvelopeWithStatus(envelope);
1257 
1258         // TODO(b/137963715): add more specific assertions on response from TelMan#sendEnvelope
1259         assertWithMessage("sendEnvelopeWithStatus is null for envelope=%s", envelope)
1260                 .that(response)
1261                 .isNotNull();
1262     }
1263 
1264     /**
1265      * This test checks that applications with carrier privilege can set/clear signal strength
1266      * update request via {@link
1267      * TelephonyManager#setSignalStrengthUpdateRequest(SignalStrengthUpdateRequest)} and {@link
1268      * TelephonyManager#clearSignalStrengthUpdateRequest} without {@link
1269      * android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}.
1270      */
1271     @Test
testSetClearSignalStrengthUpdateRequest()1272     public void testSetClearSignalStrengthUpdateRequest() {
1273         final SignalStrengthUpdateRequest request =
1274                 new SignalStrengthUpdateRequest.Builder()
1275                         .setSignalThresholdInfos(
1276                                 List.of(
1277                                         new SignalThresholdInfo.Builder()
1278                                                 .setRadioAccessNetworkType(
1279                                                         AccessNetworkConstants.AccessNetworkType
1280                                                                 .GERAN)
1281                                                 .setSignalMeasurementType(
1282                                                         SignalThresholdInfo
1283                                                                 .SIGNAL_MEASUREMENT_TYPE_RSSI)
1284                                                 .setThresholds(new int[] {-113, -103, -97, -51})
1285                                                 .setHysteresisDb(1)
1286                                                 .build()))
1287                         .setReportingRequestedWhileIdle(true)
1288                         .build();
1289         try {
1290             mTelephonyManager.setSignalStrengthUpdateRequest(request);
1291         } finally {
1292             mTelephonyManager.clearSignalStrengthUpdateRequest(request);
1293         }
1294     }
1295 
verifyValidIccOpenLogicalChannelResponse(IccOpenLogicalChannelResponse response)1296     private void verifyValidIccOpenLogicalChannelResponse(IccOpenLogicalChannelResponse response) {
1297         // The assigned channel should be between the min and max allowed channel numbers
1298         int channel = response.getChannel();
1299         assertThat(channel).isIn(Range.closed(MIN_LOGICAL_CHANNEL, MAX_LOGICAL_CHANNEL));
1300         assertThat(response.getStatus()).isEqualTo(STATUS_NO_ERROR);
1301         assertThat(response.getSelectResponse()).isEqualTo(STATUS_NORMAL);
1302     }
1303 
removeSubscriptionsFromGroup(ParcelUuid uuid)1304     private void removeSubscriptionsFromGroup(ParcelUuid uuid) {
1305         List<SubscriptionInfo> infoList = ShellIdentityUtils.invokeMethodWithShellPermissions(
1306                 mSubscriptionManager,
1307                 (sm) -> (sm.getSubscriptionsInGroup(uuid)));
1308         if (!infoList.isEmpty()) {
1309             List<Integer> subscriptionIdList = getSubscriptionIdList(infoList);
1310             ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mSubscriptionManager,
1311                     (sm) -> sm.removeSubscriptionsFromGroup(subscriptionIdList, uuid));
1312         }
1313         infoList = ShellIdentityUtils.invokeMethodWithShellPermissions(
1314                 mSubscriptionManager,
1315                 (sm) -> (sm.getSubscriptionsInGroup(uuid)));
1316         assertThat(infoList).isEmpty();
1317     }
1318 
getSubscriptionIdList(List<SubscriptionInfo> subInfoList)1319     private List<Integer> getSubscriptionIdList(List<SubscriptionInfo> subInfoList) {
1320         if (subInfoList == null || subInfoList.isEmpty()) return Collections.EMPTY_LIST;
1321         return subInfoList.stream()
1322                 .map(info -> info.getSubscriptionId())
1323                 .collect(Collectors.toList());
1324     }
1325 
1326     /**
1327      * Checks whether the a {@code fcpTemplate} contains the given {@code fileId}.
1328      *
1329      * @param fcpTemplate The FCP Template to be checked.
1330      * @param fileId The file ID that is being searched for
1331      * @return true iff fcpTemplate contains fileId.
1332      */
containsFileId(FcpTemplate fcpTemplate, String fileId)1333     private boolean containsFileId(FcpTemplate fcpTemplate, String fileId) {
1334         return fcpTemplate.getTlvs().stream()
1335                 .anyMatch(tlv -> tlv.getTag() == FILE_IDENTIFIER && tlv.getValue().equals(fileId));
1336     }
1337 
1338     /**
1339      * Returns true iff {@code response} indicates an error with the previous APDU.
1340      *
1341      * @param response The APDU response to be checked.
1342      * @return true iff the given response indicates an error occurred
1343      */
isErrorResponse(@onnull String response)1344     private boolean isErrorResponse(@Nonnull String response) {
1345         return !(STATUS_NORMAL_STRING.equals(response)
1346                 || response.startsWith(STATUS_WARNING_A)
1347                 || response.startsWith(STATUS_WARNING_B)
1348                 || response.startsWith(STATUS_BYTES_REMAINING));
1349     }
1350 
1351     private static class IntentReceiver extends BroadcastReceiver {
1352         private final CountDownLatch mReceiveLatch = new CountDownLatch(1);
1353 
1354         @Override
onReceive(Context context, Intent intent)1355         public void onReceive(Context context, Intent intent) {
1356             mReceiveLatch.countDown();
1357         }
1358 
waitForReceive()1359         public boolean waitForReceive() throws InterruptedException {
1360             return mReceiveLatch.await(30, TimeUnit.SECONDS);
1361         }
1362     }
1363 
1364     @Test
testEapSimAuthentication()1365     public void testEapSimAuthentication() {
1366         assumeTrue(
1367                 "testEapSimAuthentication requires a 2021 CTS UICC or newer",
1368                 UiccUtil.uiccHasCertificate(CTS_UICC_2021));
1369         // K: '000102030405060708090A0B0C0D0E0F', defined by TS 134 108#8.2
1370         // n: 128 (Bits to use for RES value)
1371         // Format: [Length][RAND]
1372         String challenge = "10" + EAP_SIM_AKA_RAND;
1373         String base64Challenge = Base64.encodeToString(hexStringToBytes(challenge), Base64.NO_WRAP);
1374         String base64Response =
1375                 mTelephonyManager.getIccAuthentication(
1376                         TelephonyManager.APPTYPE_USIM,
1377                         TelephonyManager.AUTHTYPE_EAP_SIM,
1378                         base64Challenge);
1379         byte[] response = Base64.decode(base64Response, Base64.DEFAULT);
1380         assertWithMessage("Results for AUTHTYPE_EAP_SIM failed")
1381                 .that(response)
1382                 .isEqualTo(hexStringToBytes(EXPECTED_EAP_SIM_RESULT));
1383     }
1384 
1385     @Test
testEapAkaAuthentication()1386     public void testEapAkaAuthentication() {
1387         // Wear devices do not yet support EapAkaAuthentication, so skip this test for now
1388         if (isWear()) {
1389             return;
1390         }
1391         assumeTrue(
1392                 "testEapAkaAuthentication requires a 2021 CTS UICC or newer",
1393                 UiccUtil.uiccHasCertificate(CTS_UICC_2021));
1394         // K: '000102030405060708090A0B0C0D0E0F', defined by TS 134 108#8.2
1395         // n: 128 (Bits to use for RES value)
1396         // Format: [Length][Rand][Length][Autn]
1397         String challenge = "10" + EAP_SIM_AKA_RAND + "10" + EAP_AKA_AUTN;
1398         String base64Challenge = Base64.encodeToString(hexStringToBytes(challenge), Base64.NO_WRAP);
1399         String base64Response =
1400                 mTelephonyManager.getIccAuthentication(
1401                         TelephonyManager.APPTYPE_USIM,
1402                         TelephonyManager.AUTHTYPE_EAP_AKA,
1403                         base64Challenge);
1404 
1405         assertWithMessage("UICC returned null for EAP-AKA auth").that(base64Response).isNotNull();
1406         byte[] response = Base64.decode(base64Response, Base64.NO_WRAP);
1407 
1408         // response may be formatted as: [DB][Length][RES][Length][CK][Length][IK][Length][Kc]
1409         byte[] akaResponse = Arrays.copyOfRange(response, 0, EAP_AKA_RESPONSE_LENGTH);
1410         assertWithMessage("Results for AUTHTYPE_EAP_AKA failed")
1411                 .that(akaResponse)
1412                 .isEqualTo(hexStringToBytes(EXPECTED_EAP_AKA_RESULT));
1413     }
1414 
1415     /**
1416      * This test checks that applications with carrier privilege can set/get data enable
1417      * state.
1418      */
1419     @Test
testDataEnableRequest()1420     public void testDataEnableRequest() {
1421         for (int i = DATA_ENABLED_REASON_USER; i <= DATA_ENABLED_REASON_THERMAL; i++) {
1422             mTelephonyManager.isDataEnabledForReason(i);
1423         }
1424         boolean isDataEnabled = mTelephonyManager.isDataEnabledForReason(
1425                 TelephonyManager.DATA_ENABLED_REASON_CARRIER);
1426         mTelephonyManager.setDataEnabledForReason(
1427                 TelephonyManager.DATA_ENABLED_REASON_CARRIER, !isDataEnabled);
1428         mTelephonyManager.setDataEnabledForReason(
1429                 TelephonyManager.DATA_ENABLED_REASON_CARRIER, isDataEnabled);
1430     }
1431 
1432     /**
1433      * This test checks that applications with carrier privileges can get network slicing
1434      * configuration.
1435      */
1436     @Test
testGetNetworkSlicingConfiguration()1437     public void testGetNetworkSlicingConfiguration() {
1438         CompletableFuture<NetworkSlicingConfig> resultFuture = new CompletableFuture<>();
1439         mTelephonyManager.getNetworkSlicingConfiguration(
1440                 AsyncTask.SERIAL_EXECUTOR, resultFuture::complete);
1441     }
1442 
isWear()1443     private boolean isWear() {
1444         return getContext().getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH);
1445     }
1446 }
1447