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