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