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.carrierapi.cts.IccUtils.isSeriouslyLetterOrDigit; 23 import static android.telephony.IccOpenLogicalChannelResponse.INVALID_CHANNEL; 24 import static android.telephony.IccOpenLogicalChannelResponse.STATUS_MISSING_RESOURCE; 25 import static android.telephony.IccOpenLogicalChannelResponse.STATUS_NO_ERROR; 26 import static android.telephony.SubscriptionManager.PHONE_NUMBER_SOURCE_CARRIER; 27 import static android.telephony.TelephonyManager.DATA_ENABLED_REASON_THERMAL; 28 import static android.telephony.TelephonyManager.DATA_ENABLED_REASON_USER; 29 30 import static com.android.compatibility.common.util.UiccUtil.UiccCertificate.CTS_UICC_2021; 31 32 import static com.google.common.truth.Truth.assertThat; 33 import static com.google.common.truth.Truth.assertWithMessage; 34 35 import static org.junit.Assert.assertEquals; 36 import static org.junit.Assert.assertNotNull; 37 import static org.junit.Assert.assertTrue; 38 import static org.junit.Assert.fail; 39 import static org.junit.Assume.assumeFalse; 40 import static org.junit.Assume.assumeNoException; 41 import static org.junit.Assume.assumeTrue; 42 43 import android.content.BroadcastReceiver; 44 import android.content.ContentProviderClient; 45 import android.content.ContentValues; 46 import android.content.Context; 47 import android.content.Intent; 48 import android.content.IntentFilter; 49 import android.content.pm.PackageManager; 50 import android.database.Cursor; 51 import android.net.Uri; 52 import android.os.AsyncTask; 53 import android.os.Build; 54 import android.os.Handler; 55 import android.os.HandlerThread; 56 import android.os.ParcelUuid; 57 import android.os.PersistableBundle; 58 import android.platform.test.annotations.SystemUserOnly; 59 import android.platform.test.flag.junit.CheckFlagsRule; 60 import android.platform.test.flag.junit.DeviceFlagsValueProvider; 61 import android.provider.Telephony; 62 import android.provider.VoicemailContract; 63 import android.telephony.AccessNetworkConstants; 64 import android.telephony.AvailableNetworkInfo; 65 import android.telephony.CarrierConfigManager; 66 import android.telephony.IccOpenLogicalChannelResponse; 67 import android.telephony.PhoneStateListener; 68 import android.telephony.SignalStrengthUpdateRequest; 69 import android.telephony.SignalThresholdInfo; 70 import android.telephony.SubscriptionInfo; 71 import android.telephony.SubscriptionManager; 72 import android.telephony.SubscriptionPlan; 73 import android.telephony.TelephonyManager; 74 import android.telephony.data.NetworkSlicingConfig; 75 import android.telephony.ims.ImsException; 76 import android.telephony.ims.ImsManager; 77 import android.telephony.ims.ImsMmTelManager; 78 import android.telephony.ims.ImsStateCallback; 79 import android.telephony.ims.RegistrationManager; 80 import android.util.Base64; 81 import android.util.Log; 82 83 import androidx.test.runner.AndroidJUnit4; 84 85 import com.android.compatibility.common.util.MediaUtils; 86 import com.android.compatibility.common.util.PollingCheck; 87 import com.android.compatibility.common.util.ShellIdentityUtils; 88 import com.android.compatibility.common.util.UiccUtil; 89 import com.android.internal.telephony.flags.Flags; 90 91 import com.google.common.collect.Range; 92 93 import org.junit.After; 94 import org.junit.Before; 95 import org.junit.Rule; 96 import org.junit.Test; 97 import org.junit.runner.RunWith; 98 99 import java.io.IOException; 100 import java.time.ZonedDateTime; 101 import java.util.ArrayList; 102 import java.util.Arrays; 103 import java.util.Collections; 104 import java.util.HashSet; 105 import java.util.List; 106 import java.util.Set; 107 import java.util.concurrent.CompletableFuture; 108 import java.util.concurrent.CountDownLatch; 109 import java.util.concurrent.TimeUnit; 110 import java.util.concurrent.atomic.AtomicReference; 111 import java.util.function.Consumer; 112 import java.util.stream.Collectors; 113 114 import javax.annotation.Nonnull; 115 116 /** 117 * Unit tests for various carrier-related APIs. 118 * 119 * <p>Test using `atest CtsCarrierApiTestCases:CarrierApiTest` or `make cts -j64 && cts-tradefed run 120 * cts -m CtsCarrierApiTestCases --test android.carrierapi.cts.CarrierApiTest` 121 */ 122 // TODO(b/130187425): Split CarrierApiTest apart to have separate test classes for functionality 123 @RunWith(AndroidJUnit4.class) 124 public class CarrierApiTest extends BaseCarrierApiTest { 125 @Rule 126 public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule(); 127 128 private static final String TAG = "CarrierApiTest"; 129 130 private TelephonyManager mTelephonyManager; 131 private CarrierConfigManager mCarrierConfigManager; 132 private SubscriptionManager mSubscriptionManager; 133 private ContentProviderClient mVoicemailProvider; 134 private ContentProviderClient mStatusProvider; 135 private PackageManager mPackageManager; 136 private Uri mVoicemailContentUri; 137 private Uri mStatusContentUri; 138 private String selfPackageName; 139 private HandlerThread mListenerThread; 140 private ImsManager mImsManager; 141 private ImsMmTelManager mMmTelManager; 142 143 private static final int MAX_RETRIES = 10; 144 // The minimum allocatable logical channel number, per TS 102 221 Section 11.1.17.1 145 private static final int MIN_LOGICAL_CHANNEL = 1; 146 // The maximum allocatable logical channel number in the standard range, per TS 102 221 Section 147 // 11.1.17.1 148 private static final int MAX_LOGICAL_CHANNEL = 3; 149 private static final int MAX_LOGICAL_CHANNEL_EXTENDED = 19; 150 // Class bytes. The logical channel used should be included for bits b2b1. TS 102 221 Table 11.5 151 private static final int CLA_GET_RESPONSE = 0x00; 152 private static final int CLA_MANAGE_CHANNEL = 0x00; 153 private static final int CLA_READ_BINARY = 0x00; 154 private static final int CLA_SELECT = 0x00; 155 private static final int CLA_STATUS = 0x80; 156 private static final String CLA_STATUS_STRING = "80"; 157 // APDU Instruction Bytes. TS 102 221 Section 10.1.2 158 private static final int COMMAND_GET_RESPONSE = 0xC0; 159 private static final int COMMAND_MANAGE_CHANNEL = 0x70; 160 private static final int COMMAND_READ_BINARY = 0xB0; 161 private static final int COMMAND_SELECT = 0xA4; 162 private static final int COMMAND_STATUS = 0xF2; 163 private static final String COMMAND_STATUS_STRING = "F2"; 164 // Status words. TS 102 221 Section 10.2.1 165 private static final byte[] STATUS_NORMAL = {(byte) 0x90, (byte) 0x00}; 166 private static final String STATUS_NORMAL_STRING = "9000"; 167 private static final String STATUS_BYTES_REMAINING = "61"; 168 private static final String STATUS_WARNING_A = "62"; 169 private static final String STATUS_WARNING_B = "63"; 170 private static final String STATUS_CHANNEL_NOT_SUPPORTED = "6881"; 171 private static final String STATUS_FILE_NOT_FOUND = "6a82"; 172 private static final String STATUS_INCORRECT_PARAMETERS = "6a86"; 173 private static final String STATUS_WRONG_PARAMETERS = "6b00"; 174 private static final Set<String> INVALID_PARAMETERS_STATUSES = 175 new HashSet<>(Arrays.asList(STATUS_INCORRECT_PARAMETERS, STATUS_WRONG_PARAMETERS)); 176 private static final String STATUS_WRONG_CLASS = "6e00"; 177 private static final String STATUS_TECHNICAL_PROBLEM = "6f00"; 178 // File ID for the EF ICCID. TS 102 221 179 private static final String ICCID_FILE_ID = "2FE2"; 180 // File ID for the EF_PL. TS 131 102 Annex A 181 private static final String PL_FILE_ID = "2F05"; 182 // File ID for the master file. TS 102 221 183 private static final String MF_FILE_ID = "3F00"; 184 private static final int MF_FILE_ID_HEX = 0x3F00; 185 // File ID for the MF Access Rule Reference. TS 102 221 186 private static final String MF_ARR_FILE_ID = "2F06"; 187 private static final String ALPHA_TAG_A = "tagA"; 188 private static final String ALPHA_TAG_B = "tagB"; 189 private static final String NUMBER_A = "1234567890"; 190 private static final String NUMBER_B = "0987654321"; 191 private static final String TESTING_PLMN = "12345"; 192 private static final int PL_ENTRY_LENGTH = 2; 193 private static final int HEX_BYTES_PER_CHAR = 2; 194 195 private static final String EAP_SIM_AKA_RAND = "11111111111111111111111111111111"; 196 197 // Derived from TS 134 108#8.1.2. Based on EAP_SIM_AKA_RAND and assumed K value of 198 // 000102030405060708090A0B0C0D0E0F, per TS 134 108#8.2 199 private static final String EAP_AKA_AUTN = "12351417161900001130131215141716"; 200 201 // EAP-AKA Response Format: [DB][Length][RES][Length][CK][Length][IK] 202 private static final int EAP_AKA_RESPONSE_LENGTH = 1 + 1 + 16 + 1 + 16 + 1 + 16; 203 204 // Derived from TS 134 108#8.1.2. Based on EAP_SIM_AKA_RAND and assumed K value of 205 // 000102030405060708090A0B0C0D0E0F, per TS 134 108#8.2. 206 // Format: [DB][Length][RES][Length][CK][Length][IK] 207 private static final String EXPECTED_EAP_AKA_RESULT = 208 "DB10111013121514171619181B1A1D1C1F1E" 209 + "101013121514171619181B1A1D1C1F1E11" 210 + "1013121514171619181B1A1D1C1F1E1110"; 211 212 // 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 213 // value of 000102030405060708090A0B0C0D0E0F, per TS 134 108#8.2. 214 // Format: [Length][SRES][Length][Kc] 215 private static final String EXPECTED_EAP_SIM_RESULT = "0400000000080000000000000000"; 216 217 private static final int DSDS_PHONE_COUNT = 2; 218 private static final String PLMN_A = "123456"; 219 private static final String PLMN_B = "78901"; 220 private static final List<String> FPLMN_TEST = Arrays.asList(PLMN_A, PLMN_B); 221 private static final int MAX_FPLMN_NUM = 1000; 222 private static final int MIN_FPLMN_NUM = 3; 223 224 private static final ZonedDateTime SUB_PLAN_START = 225 ZonedDateTime.parse("2024-01-01T00:00:00.000Z"); 226 private static final ZonedDateTime SUB_PLAN_END = 227 ZonedDateTime.parse("2029-12-31T00:00:00.000Z"); 228 private static final CharSequence SUB_PLAN_TITLE = "CTS test subscription plan"; 229 private static final CharSequence SUB_PLAN_SUMMARY = "CTS test subscription plan summary"; 230 private static final long SUB_PLAN_EXPIRATION_DURATION = 36000L; 231 private static final long SUB_PLAN_DATA_LIMIT_BYTES = 1200000L; 232 233 @Before setUp()234 public void setUp() throws Exception { 235 Context context = getContext(); 236 mTelephonyManager = context.getSystemService(TelephonyManager.class); 237 mCarrierConfigManager = context.getSystemService(CarrierConfigManager.class); 238 mSubscriptionManager = context.getSystemService(SubscriptionManager.class); 239 selfPackageName = context.getPackageName(); 240 mVoicemailContentUri = VoicemailContract.Voicemails.buildSourceUri(selfPackageName); 241 mVoicemailProvider = 242 context.getContentResolver().acquireContentProviderClient(mVoicemailContentUri); 243 mStatusContentUri = VoicemailContract.Status.buildSourceUri(selfPackageName); 244 mStatusProvider = 245 context.getContentResolver().acquireContentProviderClient(mStatusContentUri); 246 mPackageManager = context.getPackageManager(); 247 mImsManager = context.getSystemService(ImsManager.class); 248 if (mImsManager != null) { 249 final int subId = SubscriptionManager.getDefaultSubscriptionId(); 250 mMmTelManager = mImsManager.getImsMmTelManager(subId); 251 } 252 mListenerThread = new HandlerThread("CarrierApiTest"); 253 mListenerThread.start(); 254 } 255 256 @After tearDown()257 public void tearDown() throws Exception { 258 if (!werePreconditionsSatisfied()) return; 259 260 if (mListenerThread != null) { 261 mListenerThread.quit(); 262 } 263 try { 264 mStatusProvider.delete(mStatusContentUri, null, null); 265 mVoicemailProvider.delete(mVoicemailContentUri, null, null); 266 } catch (Exception e) { 267 Log.w(TAG, "Failed to clean up voicemail tables in tearDown", e); 268 } 269 } 270 271 @Test testSimCardPresent()272 public void testSimCardPresent() { 273 assertWithMessage("This test requires a SIM card") 274 .that(mTelephonyManager.getSimState()) 275 .isNotEqualTo(TelephonyManager.SIM_STATE_ABSENT); 276 } 277 278 @Test testHasCarrierPrivileges()279 public void testHasCarrierPrivileges() { 280 assertWithMessage(NO_CARRIER_PRIVILEGES_FAILURE_MESSAGE) 281 .that(mTelephonyManager.hasCarrierPrivileges()) 282 .isTrue(); 283 } 284 assertUpdateAvailableNetworkSuccess(int value)285 private static void assertUpdateAvailableNetworkSuccess(int value) { 286 assertThat(value).isEqualTo(TelephonyManager.UPDATE_AVAILABLE_NETWORKS_SUCCESS); 287 } 288 assertUpdateAvailableNetworkNoOpportunisticSubAvailable(int value)289 private static void assertUpdateAvailableNetworkNoOpportunisticSubAvailable(int value) { 290 assertThat(value) 291 .isEqualTo( 292 TelephonyManager.UPDATE_AVAILABLE_NETWORKS_NO_OPPORTUNISTIC_SUB_AVAILABLE); 293 } 294 assertSetOpportunisticSubSuccess(int value)295 private static void assertSetOpportunisticSubSuccess(int value) { 296 assertThat(value).isEqualTo(TelephonyManager.SET_OPPORTUNISTIC_SUB_SUCCESS); 297 } 298 getFirstActivateCarrierPrivilegedSubscriptionId()299 private int getFirstActivateCarrierPrivilegedSubscriptionId() { 300 int subId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; 301 List<SubscriptionInfo> subscriptionInfos = 302 mSubscriptionManager.getActiveSubscriptionInfoList(); 303 if (subscriptionInfos != null) { 304 for (SubscriptionInfo info : subscriptionInfos) { 305 TelephonyManager telephonyManager = 306 mTelephonyManager.createForSubscriptionId(info.getSubscriptionId()); 307 if (telephonyManager.hasCarrierPrivileges()) { 308 subId = info.getSubscriptionId(); 309 return subId; 310 } 311 } 312 } 313 return subId; 314 } 315 316 @Test testUpdateAvailableNetworksWithCarrierPrivilege()317 public void testUpdateAvailableNetworksWithCarrierPrivilege() { 318 int subIdWithCarrierPrivilege = getFirstActivateCarrierPrivilegedSubscriptionId(); 319 int activeSubscriptionInfoCount = 320 ShellIdentityUtils.invokeMethodWithShellPermissions( 321 mSubscriptionManager, (tm) -> tm.getActiveSubscriptionInfoCount()); 322 if (mTelephonyManager.getPhoneCount() == 1) { 323 return; 324 } 325 326 /* TODO: b/145993690 */ 327 if (mTelephonyManager.getPhoneCount() == 2 && activeSubscriptionInfoCount != 2) { 328 /* This test requires two SIM cards */ 329 return; 330 } 331 if (subIdWithCarrierPrivilege == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { 332 /* This test requires SIM with carrier privilege */ 333 return; 334 } 335 336 List<SubscriptionInfo> subscriptionInfoList = 337 mSubscriptionManager.getOpportunisticSubscriptions(); 338 List<String> mccMncs = new ArrayList<String>(); 339 List<Integer> bands = new ArrayList<Integer>(); 340 List<AvailableNetworkInfo> availableNetworkInfos = new ArrayList<AvailableNetworkInfo>(); 341 Consumer<Integer> callbackSuccess = CarrierApiTest::assertUpdateAvailableNetworkSuccess; 342 Consumer<Integer> callbackNoOpportunisticSubAvailable = 343 CarrierApiTest::assertUpdateAvailableNetworkNoOpportunisticSubAvailable; 344 Consumer<Integer> setOpCallbackSuccess = CarrierApiTest::assertSetOpportunisticSubSuccess; 345 if (subscriptionInfoList == null 346 || subscriptionInfoList.size() == 0 347 || !mSubscriptionManager.isActiveSubscriptionId( 348 subscriptionInfoList.get(0).getSubscriptionId())) { 349 try { 350 AvailableNetworkInfo availableNetworkInfo = 351 new AvailableNetworkInfo( 352 subIdWithCarrierPrivilege, 353 AvailableNetworkInfo.PRIORITY_HIGH, 354 mccMncs, 355 bands); 356 availableNetworkInfos.add(availableNetworkInfo); 357 // Call updateAvailableNetworks without opportunistic subscription. 358 // callbackNoOpportunisticSubAvailable is expected to be triggered 359 // and the return value will be checked against 360 // UPDATE_AVAILABLE_NETWORKS_NO_OPPORTUNISTIC_SUB_AVAILABLE 361 mTelephonyManager.updateAvailableNetworks( 362 availableNetworkInfos, 363 AsyncTask.SERIAL_EXECUTOR, 364 callbackNoOpportunisticSubAvailable); 365 } finally { 366 // clear all the operations at the end of test. 367 availableNetworkInfos.clear(); 368 mTelephonyManager.updateAvailableNetworks( 369 availableNetworkInfos, 370 AsyncTask.SERIAL_EXECUTOR, 371 callbackNoOpportunisticSubAvailable); 372 } 373 } else { 374 // This is case of DSDS phone, one active opportunistic subscription and one 375 // active primary subscription. 376 int resultSubId; 377 try { 378 AvailableNetworkInfo availableNetworkInfo = 379 new AvailableNetworkInfo( 380 subscriptionInfoList.get(0).getSubscriptionId(), 381 AvailableNetworkInfo.PRIORITY_HIGH, 382 mccMncs, 383 bands); 384 availableNetworkInfos.add(availableNetworkInfo); 385 mTelephonyManager.updateAvailableNetworks( 386 availableNetworkInfos, AsyncTask.SERIAL_EXECUTOR, callbackSuccess); 387 // wait for the data change to take effect 388 waitForMs(500); 389 // Call setPreferredData and reconfirm with getPreferred data 390 // that the same is updated. 391 int preferSubId = subscriptionInfoList.get(0).getSubscriptionId(); 392 mTelephonyManager.setPreferredOpportunisticDataSubscription( 393 preferSubId, false, AsyncTask.SERIAL_EXECUTOR, setOpCallbackSuccess); 394 // wait for the data change to take effect 395 waitForMs(500); 396 resultSubId = mTelephonyManager.getPreferredOpportunisticDataSubscription(); 397 assertThat(resultSubId).isEqualTo(preferSubId); 398 } finally { 399 // clear all the operations at the end of test. 400 availableNetworkInfos.clear(); 401 mTelephonyManager.updateAvailableNetworks( 402 availableNetworkInfos, AsyncTask.SERIAL_EXECUTOR, callbackSuccess); 403 waitForMs(500); 404 mTelephonyManager.setPreferredOpportunisticDataSubscription( 405 SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, 406 false, 407 AsyncTask.SERIAL_EXECUTOR, 408 callbackSuccess); 409 waitForMs(500); 410 resultSubId = mTelephonyManager.getPreferredOpportunisticDataSubscription(); 411 assertThat(resultSubId).isEqualTo(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID); 412 } 413 } 414 } 415 waitForMs(long ms)416 public static void waitForMs(long ms) { 417 try { 418 Thread.sleep(ms); 419 } catch (InterruptedException e) { 420 Log.d(TAG, "InterruptedException while waiting: " + e); 421 } 422 } 423 424 @Test testGetIccAuthentication()425 public void testGetIccAuthentication() { 426 // EAP-SIM rand is 16 bytes. 427 String base64Challenge = "ECcTqwuo6OfY8ddFRboD9WM="; 428 String base64Challenge2 = "EMNxjsFrPCpm+KcgCmQGnwQ="; 429 430 try { 431 assertWithMessage("getIccAuthentication should return null for empty data.") 432 .that( 433 mTelephonyManager.getIccAuthentication( 434 TelephonyManager.APPTYPE_USIM, 435 TelephonyManager.AUTHTYPE_EAP_AKA, 436 "")) 437 .isNull(); 438 String response = 439 mTelephonyManager.getIccAuthentication( 440 TelephonyManager.APPTYPE_USIM, 441 TelephonyManager.AUTHTYPE_EAP_SIM, 442 base64Challenge); 443 assertWithMessage("UICC returned null for EAP-SIM auth").that(response).isNotNull(); 444 // response is base64 encoded. After decoding, the value should be: 445 // 1 length byte + SRES(4 bytes) + 1 length byte + Kc(8 bytes) 446 byte[] result = android.util.Base64.decode(response, android.util.Base64.DEFAULT); 447 assertThat(result).hasLength(14); 448 String response2 = 449 mTelephonyManager.getIccAuthentication( 450 TelephonyManager.APPTYPE_USIM, 451 TelephonyManager.AUTHTYPE_EAP_SIM, 452 base64Challenge2); 453 assertWithMessage("Two responses must be different") 454 .that(response) 455 .isNotEqualTo(response2); 456 } catch (UnsupportedOperationException e) { 457 assumeNoException("EAP-SIM/AKA not supported", e); 458 } catch (SecurityException e) { 459 fail(NO_CARRIER_PRIVILEGES_FAILURE_MESSAGE); 460 } 461 } 462 463 @Test 464 @SystemUserOnly(reason = "b/177921545, broadcast sent only to primary user") testSendDialerSpecialCode()465 public void testSendDialerSpecialCode() { 466 assumeTrue(hasTelephonyCalling()); 467 468 IntentReceiver intentReceiver = new IntentReceiver(); 469 final IntentFilter intentFilter = new IntentFilter(); 470 intentFilter.addAction(Telephony.Sms.Intents.SECRET_CODE_ACTION); 471 intentFilter.addDataScheme("android_secret_code"); 472 473 Context context = getContext(); 474 context.registerReceiver(intentReceiver, intentFilter); 475 try { 476 mTelephonyManager.sendDialerSpecialCode("4636"); 477 assertWithMessage( 478 "Did not receive expected Intent: " 479 + Telephony.Sms.Intents.SECRET_CODE_ACTION) 480 .that(intentReceiver.waitForReceive()) 481 .isTrue(); 482 } catch (SecurityException e) { 483 fail(NO_CARRIER_PRIVILEGES_FAILURE_MESSAGE); 484 } catch (InterruptedException e) { 485 Log.d(TAG, "Broadcast receiver wait was interrupted."); 486 } finally { 487 context.unregisterReceiver(intentReceiver); 488 } 489 } 490 491 @Test testSubscriptionInfoListing()492 public void testSubscriptionInfoListing() { 493 try { 494 assertThat(mSubscriptionManager.getActiveSubscriptionInfoCount()).isGreaterThan(0); 495 List<SubscriptionInfo> subInfoList = 496 mSubscriptionManager.getActiveSubscriptionInfoList(); 497 assertWithMessage("getActiveSubscriptionInfoList() returned null") 498 .that(subInfoList) 499 .isNotNull(); 500 assertWithMessage("getActiveSubscriptionInfoList() returned an empty list") 501 .that(subInfoList) 502 .isNotEmpty(); 503 for (SubscriptionInfo info : subInfoList) { 504 TelephonyManager tm = 505 mTelephonyManager.createForSubscriptionId(info.getSubscriptionId()); 506 assertWithMessage( 507 "getActiveSubscriptionInfoList() returned an inaccessible" 508 + " subscription") 509 .that(tm.hasCarrierPrivileges()) 510 .isTrue(); 511 512 // Check other APIs to make sure they are accessible and return consistent info. 513 SubscriptionInfo infoForSlot = 514 mSubscriptionManager.getActiveSubscriptionInfoForSimSlotIndex( 515 info.getSimSlotIndex()); 516 assertWithMessage("getActiveSubscriptionInfoForSimSlotIndex() returned null") 517 .that(infoForSlot) 518 .isNotNull(); 519 assertWithMessage( 520 "getActiveSubscriptionInfoForSimSlotIndex() returned inconsistent" 521 + " info") 522 .that(infoForSlot.getSubscriptionId()) 523 .isEqualTo(info.getSubscriptionId()); 524 525 SubscriptionInfo infoForSubId = 526 mSubscriptionManager.getActiveSubscriptionInfo(info.getSubscriptionId()); 527 assertWithMessage("getActiveSubscriptionInfo() returned null") 528 .that(infoForSubId) 529 .isNotNull(); 530 assertWithMessage("getActiveSubscriptionInfo() returned inconsistent info") 531 .that(infoForSubId.getSubscriptionId()) 532 .isEqualTo(info.getSubscriptionId()); 533 } 534 } catch (SecurityException e) { 535 fail(NO_CARRIER_PRIVILEGES_FAILURE_MESSAGE); 536 } 537 } 538 539 @Test testCarrierConfigIsAccessible()540 public void testCarrierConfigIsAccessible() { 541 try { 542 PersistableBundle bundle = mCarrierConfigManager.getConfig(); 543 assertWithMessage("CarrierConfigManager#getConfig() returned null") 544 .that(bundle) 545 .isNotNull(); 546 assertWithMessage("CarrierConfigManager#getConfig() returned empty bundle") 547 .that(bundle.isEmpty()) 548 .isFalse(); 549 550 int subId = SubscriptionManager.getDefaultSubscriptionId(); 551 bundle = mCarrierConfigManager.getConfigForSubId(subId); 552 assertWithMessage("CarrierConfigManager#getConfigForSubId() returned null") 553 .that(bundle) 554 .isNotNull(); 555 assertWithMessage("CarrierConfigManager#getConfigForSubId() returned empty bundle") 556 .that(bundle.isEmpty()) 557 .isFalse(); 558 } catch (SecurityException e) { 559 fail(NO_CARRIER_PRIVILEGES_FAILURE_MESSAGE); 560 } 561 } 562 563 @Test testTelephonyApisAreAccessibleWithFeatureMapping()564 public void testTelephonyApisAreAccessibleWithFeatureMapping() { 565 // The following methods may return any value depending on the state of the device. Simply 566 // call them to make sure they do not throw any exceptions. Methods that return a device 567 // identifier will be accessible to apps with carrier privileges in Q, but this may change 568 // in a future release. 569 try { 570 mTelephonyManager.getDeviceId(); 571 mTelephonyManager.getDeviceSoftwareVersion(); 572 mTelephonyManager.getImei(); 573 574 if (hasFeature(PackageManager.FEATURE_TELEPHONY_CDMA)) { 575 mTelephonyManager.getMeid(); 576 } 577 if (hasFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION)) { 578 mTelephonyManager.getNai(); 579 mTelephonyManager.getSimSerialNumber(); 580 mTelephonyManager.getSubscriberId(); 581 mTelephonyManager.getGroupIdLevel1(); 582 mTelephonyManager.getLine1Number(); 583 mTelephonyManager.getForbiddenPlmns(); 584 mTelephonyManager.setForbiddenPlmns(new ArrayList<String>()); 585 // TODO(b/235490259): test all slots once TM#isModemEnabledForSlot allows 586 mTelephonyManager.isModemEnabledForSlot( 587 SubscriptionManager.getSlotIndex(mTelephonyManager.getSubscriptionId())); 588 } 589 if (hasFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS)) { 590 mTelephonyManager.getDataNetworkType(); 591 mTelephonyManager.getServiceState(); 592 mTelephonyManager.getManualNetworkSelectionPlmn(); 593 } 594 if (hasFeature(PackageManager.FEATURE_TELEPHONY_CALLING)) { 595 mTelephonyManager.getVoiceNetworkType(); 596 mTelephonyManager.getVoiceMailNumber(); 597 mTelephonyManager.getVisualVoicemailPackageName(); 598 mTelephonyManager.getVoiceMailAlphaTag(); 599 } 600 } catch (SecurityException e) { 601 fail(NO_CARRIER_PRIVILEGES_FAILURE_MESSAGE); 602 } 603 } 604 605 @Test testImsApisAreAccessibleWithFeatureMapping()606 public void testImsApisAreAccessibleWithFeatureMapping() { 607 assumeTrue(hasFeature(PackageManager.FEATURE_TELEPHONY_IMS)); 608 final int subId = mTelephonyManager.getSubscriptionId(); 609 try { 610 mMmTelManager.createForSubscriptionId(subId); 611 612 RegistrationManager.RegistrationCallback rc = 613 new RegistrationManager.RegistrationCallback() {}; 614 try { 615 mMmTelManager.registerImsRegistrationCallback(r -> r.run(), rc); 616 } catch (ImsException ignored) { 617 } finally { 618 mMmTelManager.unregisterImsRegistrationCallback(rc); 619 } 620 if (Flags.emergencyRegistrationState()) { 621 try { 622 mMmTelManager.registerImsEmergencyRegistrationCallback(r -> r.run(), rc); 623 } catch (ImsException ignored) { 624 } finally { 625 mMmTelManager.unregisterImsEmergencyRegistrationCallback(rc); 626 } 627 } 628 629 mMmTelManager.getRegistrationTransportType(r -> r.run(), (i) -> {}); 630 631 ImsMmTelManager.CapabilityCallback cc = 632 new ImsMmTelManager.CapabilityCallback() {}; 633 try { 634 mMmTelManager.registerMmTelCapabilityCallback(r -> r.run(), cc); 635 } catch (ImsException ignored) { 636 } finally { 637 mMmTelManager.unregisterMmTelCapabilityCallback(cc); 638 } 639 640 mMmTelManager.isAdvancedCallingSettingEnabled(); 641 mMmTelManager.isVtSettingEnabled(); 642 mMmTelManager.setVoWiFiSettingEnabled(mMmTelManager.isVoWiFiSettingEnabled()); 643 644 try { 645 mMmTelManager.setCrossSimCallingEnabled( 646 mMmTelManager.isCrossSimCallingEnabled()); 647 } catch (ImsException ignored) { 648 } 649 650 mMmTelManager.setVoWiFiRoamingSettingEnabled( 651 mMmTelManager.isVoWiFiRoamingSettingEnabled()); 652 mMmTelManager.setVoWiFiModeSetting(mMmTelManager.getVoWiFiModeSetting()); 653 mMmTelManager.isTtyOverVolteEnabled(); 654 655 ImsStateCallback ic = new ImsStateCallback() { 656 @Override 657 public void onUnavailable(int reason) { 658 } 659 @Override 660 public void onAvailable() { 661 } 662 @Override 663 public void onError() { 664 } 665 }; 666 try { 667 mMmTelManager.registerImsStateCallback(r -> r.run(), ic); 668 } catch (ImsException ignored) { 669 } finally { 670 mMmTelManager.unregisterImsStateCallback(ic); 671 } 672 } catch (SecurityException e) { 673 fail(NO_CARRIER_PRIVILEGES_FAILURE_MESSAGE); 674 } 675 } 676 677 @Test testVoicemailTableIsAccessible()678 public void testVoicemailTableIsAccessible() throws Exception { 679 ContentValues value = new ContentValues(); 680 value.put(VoicemailContract.Voicemails.NUMBER, "0123456789"); 681 value.put(VoicemailContract.Voicemails.SOURCE_PACKAGE, selfPackageName); 682 try { 683 Uri uri = mVoicemailProvider.insert(mVoicemailContentUri, value); 684 assertThat(uri).isNotNull(); 685 Cursor cursor = 686 mVoicemailProvider.query( 687 uri, 688 new String[] { 689 VoicemailContract.Voicemails.NUMBER, 690 VoicemailContract.Voicemails.SOURCE_PACKAGE 691 }, 692 null, 693 null, 694 null); 695 assertThat(cursor).isNotNull(); 696 assertThat(cursor.moveToFirst()).isTrue(); 697 assertThat(cursor.getString(0)).isEqualTo("0123456789"); 698 assertThat(cursor.getString(1)).isEqualTo(selfPackageName); 699 assertThat(cursor.moveToNext()).isFalse(); 700 } catch (SecurityException e) { 701 fail(NO_CARRIER_PRIVILEGES_FAILURE_MESSAGE); 702 } 703 } 704 705 @Test testVoicemailStatusTableIsAccessible()706 public void testVoicemailStatusTableIsAccessible() throws Exception { 707 ContentValues value = new ContentValues(); 708 value.put( 709 VoicemailContract.Status.CONFIGURATION_STATE, 710 VoicemailContract.Status.CONFIGURATION_STATE_OK); 711 value.put(VoicemailContract.Status.SOURCE_PACKAGE, selfPackageName); 712 try { 713 Uri uri = mStatusProvider.insert(mStatusContentUri, value); 714 assertThat(uri).isNotNull(); 715 Cursor cursor = 716 mVoicemailProvider.query( 717 uri, 718 new String[] { 719 VoicemailContract.Status.CONFIGURATION_STATE, 720 VoicemailContract.Status.SOURCE_PACKAGE 721 }, 722 null, 723 null, 724 null); 725 assertThat(cursor).isNotNull(); 726 assertThat(cursor.moveToFirst()).isTrue(); 727 assertThat(cursor.getInt(0)).isEqualTo(VoicemailContract.Status.CONFIGURATION_STATE_OK); 728 assertThat(cursor.getString(1)).isEqualTo(selfPackageName); 729 assertThat(cursor.moveToNext()).isFalse(); 730 } catch (SecurityException e) { 731 fail(NO_CARRIER_PRIVILEGES_FAILURE_MESSAGE); 732 } 733 } 734 735 static final int READ_PHONE_STATE_LISTENERS = 736 PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR 737 | PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR 738 | PhoneStateListener.LISTEN_EMERGENCY_NUMBER_LIST; 739 740 static final int READ_PRECISE_PHONE_STATE_LISTENERS = 741 PhoneStateListener.LISTEN_PRECISE_DATA_CONNECTION_STATE 742 | PhoneStateListener.LISTEN_CALL_DISCONNECT_CAUSES 743 | PhoneStateListener.LISTEN_IMS_CALL_DISCONNECT_CAUSES 744 | PhoneStateListener.LISTEN_REGISTRATION_FAILURE 745 | PhoneStateListener.LISTEN_BARRING_INFO; 746 747 static final int CARRIER_PRIVILEGE_LISTENERS = 748 READ_PHONE_STATE_LISTENERS | READ_PRECISE_PHONE_STATE_LISTENERS; 749 750 @Test testGetManualNetworkSelectionPlmnPersisted()751 public void testGetManualNetworkSelectionPlmnPersisted() throws Exception { 752 if (mTelephonyManager.getPhoneType() != TelephonyManager.PHONE_TYPE_GSM) return; 753 754 try { 755 mTelephonyManager.setNetworkSelectionModeManual( 756 TESTING_PLMN /* operatorNumeric */, true /* persistSelection */); 757 String plmn = mTelephonyManager.getManualNetworkSelectionPlmn(); 758 assertThat(plmn).isEqualTo(TESTING_PLMN); 759 } finally { 760 mTelephonyManager.setNetworkSelectionModeAutomatic(); 761 } 762 } 763 764 @Test testPhoneStateListener()765 public void testPhoneStateListener() throws Exception { 766 PhoneStateListener psl = new PhoneStateListener((Runnable r) -> {}); 767 try { 768 mTelephonyManager.listen(psl, CARRIER_PRIVILEGE_LISTENERS); 769 } finally { 770 mTelephonyManager.listen(psl, PhoneStateListener.LISTEN_NONE); 771 } 772 } 773 774 @Test testIsManualNetworkSelectionAllowed()775 public void testIsManualNetworkSelectionAllowed() throws Exception { 776 if (mTelephonyManager.getPhoneType() != TelephonyManager.PHONE_TYPE_GSM) return; 777 778 try { 779 assertThat(mTelephonyManager.isManualNetworkSelectionAllowed()).isTrue(); 780 } catch (SecurityException e) { 781 fail(NO_CARRIER_PRIVILEGES_FAILURE_MESSAGE); 782 } 783 } 784 785 @Test testGetNetworkSelectionMode()786 public void testGetNetworkSelectionMode() throws Exception { 787 try { 788 ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn( 789 mTelephonyManager, (tm) -> tm.setNetworkSelectionModeAutomatic()); 790 int networkMode = mTelephonyManager.getNetworkSelectionMode(); 791 assertThat(networkMode).isEqualTo(TelephonyManager.NETWORK_SELECTION_MODE_AUTO); 792 } catch (SecurityException e) { 793 fail(NO_CARRIER_PRIVILEGES_FAILURE_MESSAGE); 794 } 795 } 796 797 @Test testSubscriptionInfoChangeListener()798 public void testSubscriptionInfoChangeListener() throws Exception { 799 final AtomicReference<SecurityException> error = new AtomicReference<>(); 800 final CountDownLatch latch = new CountDownLatch(1); 801 new Handler(mListenerThread.getLooper()) 802 .post( 803 () -> { 804 SubscriptionManager.OnSubscriptionsChangedListener listener = 805 new SubscriptionManager.OnSubscriptionsChangedListener(); 806 try { 807 mSubscriptionManager.addOnSubscriptionsChangedListener(listener); 808 } catch (SecurityException e) { 809 error.set(e); 810 } finally { 811 mSubscriptionManager.removeOnSubscriptionsChangedListener(listener); 812 latch.countDown(); 813 } 814 }); 815 assertWithMessage("Test timed out").that(latch.await(30L, TimeUnit.SECONDS)).isTrue(); 816 if (error.get() != null) { 817 fail(NO_CARRIER_PRIVILEGES_FAILURE_MESSAGE); 818 } 819 } 820 821 /** 822 * Test that it's possible to open logical channels to the ICC. This mirrors the Manage Channel 823 * command described in TS 102 221 Section 11.1.17. 824 */ 825 @Test testIccOpenLogicalChannel()826 public void testIccOpenLogicalChannel() { 827 // The AID here doesn't matter - we just need to open a valid connection. In this case, the 828 // specified AID ("") opens a channel and selects the MF. 829 IccOpenLogicalChannelResponse response = mTelephonyManager.iccOpenLogicalChannel(""); 830 assertThat(response.getStatus()).isEqualTo(STATUS_NO_ERROR); 831 final int logicalChannel = response.getChannel(); 832 try { 833 verifyValidIccOpenLogicalChannelResponse(response); 834 } finally { 835 mTelephonyManager.iccCloseLogicalChannel(logicalChannel); 836 } 837 } 838 839 @Test testIccOpenLogicalChannelWithValidP2()840 public void testIccOpenLogicalChannelWithValidP2() { 841 // {@link TelephonyManager#iccOpenLogicalChannel} sends a Manage Channel (open) APDU 842 // followed by a Select APDU with the given AID and p2 values. See Open Mobile API 843 // Specification v3.2 Section 6.2.7.h and TS 102 221 for details. 844 int p2 = 0x0C; // '0C' for no data returned (TS 102 221 Section 11.1.1.2) 845 IccOpenLogicalChannelResponse response = mTelephonyManager.iccOpenLogicalChannel("", p2); 846 assertThat(response.getStatus()).isEqualTo(STATUS_NO_ERROR); 847 final int logicalChannel = response.getChannel(); 848 try { 849 verifyValidIccOpenLogicalChannelResponse(response); 850 } finally { 851 mTelephonyManager.iccCloseLogicalChannel(logicalChannel); 852 } 853 } 854 855 @Test testIccOpenLogicalChannelWithInvalidP2()856 public void testIccOpenLogicalChannelWithInvalidP2() { 857 // Valid p2 values are defined in TS 102 221 Table 11.2. Per Table 11.2, 0xF0 should be 858 // invalid. Any p2 values that produce non '9000'/'62xx'/'63xx' status words are treated as 859 // an error and the channel is not opened. Due to compatibility issues with older devices, 860 // this check is only enabled for new devices launching on Q+. 861 if (Build.VERSION.DEVICE_INITIAL_SDK_INT >= Build.VERSION_CODES.Q) { 862 int p2 = 0xF0; 863 IccOpenLogicalChannelResponse response = 864 mTelephonyManager.iccOpenLogicalChannel("", p2); 865 final int logicalChannel = response.getChannel(); 866 assertThat(logicalChannel).isEqualTo(INVALID_CHANNEL); 867 assertThat(response.getStatus()).isNotEqualTo(STATUS_NO_ERROR); 868 } 869 } 870 871 @Test testIccOpenTooManyLogicalChannels()872 public void testIccOpenTooManyLogicalChannels() throws IOException { 873 Set<Integer> channels = new HashSet<Integer>(); 874 boolean failedOnce = false; 875 try { 876 for (int i = MIN_LOGICAL_CHANNEL; i <= MAX_LOGICAL_CHANNEL_EXTENDED + 1; i++) { 877 IccOpenLogicalChannelResponse response = 878 mTelephonyManager.iccOpenLogicalChannel(""); 879 int channel = response.getChannel(); 880 if (channel > 0) { 881 // TODO(b/375102360): CF should implement handling more than one logical channel 882 assumeFalse(channels.contains(channel) && MediaUtils.onCuttlefish()); 883 assertWithMessage("Logical channel " + channel + " was returned twice") 884 .that(channels.add(channel)).isTrue(); 885 } 886 if (response.getStatus() == STATUS_MISSING_RESOURCE) { 887 assertThat(response.getSelectResponse()).isNull(); 888 assertThat(channel).isEqualTo(INVALID_CHANNEL); 889 failedOnce = true; 890 break; 891 } 892 assertThat(response.getStatus()).isEqualTo(STATUS_NO_ERROR); 893 assertThat(response.getSelectResponse()).isEqualTo(STATUS_NORMAL); 894 assertThat(channel).isIn(Range.closed(MIN_LOGICAL_CHANNEL, 895 MAX_LOGICAL_CHANNEL_EXTENDED)); 896 } 897 } finally { 898 for (Integer channel : channels) { 899 mTelephonyManager.iccCloseLogicalChannel(channel); 900 } 901 } 902 assertTrue(failedOnce); 903 904 // Make sure you can open logical channel after closing old ones. 905 testIccOpenLogicalChannel(); 906 } 907 908 /** 909 * Test that it's possible to close logical channels to the ICC. This follows the Manage Channel 910 * command described in TS 102 221 Section 11.1.17. 911 */ 912 @Test testIccCloseLogicalChannel()913 public void testIccCloseLogicalChannel() { 914 // The directory here doesn't matter - we just need to open a valid connection that can 915 // later be closed. In this case, the specified AID ("") opens a channel and selects the MF. 916 IccOpenLogicalChannelResponse response = mTelephonyManager.iccOpenLogicalChannel(""); 917 918 // Check that the select command succeeded. This ensures that the logical channel is indeed 919 // open. 920 assertThat(response.getSelectResponse()).isEqualTo(STATUS_NORMAL); 921 assertThat(mTelephonyManager.iccCloseLogicalChannel(response.getChannel())).isTrue(); 922 923 // Close opened channel twice. 924 try { 925 boolean result = mTelephonyManager.iccCloseLogicalChannel(response.getChannel()); 926 assertThat(result).isFalse(); 927 } catch (IllegalArgumentException ex) { 928 //IllegalArgumentException is expected sometimes because of different behaviour of modem 929 } 930 931 // Channel 0 is guaranteed to be always available and cannot be closed, per TS 102 221 932 // Section 11.1.17 933 try { 934 mTelephonyManager.iccCloseLogicalChannel(0); 935 fail("Expected IllegalArgumentException"); 936 } catch (IllegalArgumentException ex) { 937 // IllegalArgumentException is expected 938 } 939 } 940 941 /** 942 * This test ensures that valid APDU instructions can be sent and processed by the ICC. To do 943 * so, APDUs are sent to: - get the status of the MF - select the Access Rule Reference (ARR) 944 * for the MF - get the FCP template response for the select 945 */ 946 @Test testIccTransmitApduLogicalChannel()947 public void testIccTransmitApduLogicalChannel() { 948 // An open LC is required for transmitting APDU commands. This opens an LC to the MF. 949 IccOpenLogicalChannelResponse iccOpenLogicalChannelResponse = 950 mTelephonyManager.iccOpenLogicalChannel(""); 951 assertThat(iccOpenLogicalChannelResponse.getStatus()).isEqualTo(STATUS_NO_ERROR); 952 953 // Get the status of the current directory. This should match the MF. TS 102 221 Section 954 // 11.1.2 955 final int logicalChannel = iccOpenLogicalChannelResponse.getChannel(); 956 957 try { 958 int cla = CLA_STATUS; 959 int p1 = 0; // no indication of application status 960 int p2 = 0; // same response parameters as the SELECT in the iccOpenLogicalChannel() 961 // above 962 int p3 = 0; // length of 'data' payload 963 String data = ""; 964 String response = 965 mTelephonyManager.iccTransmitApduLogicalChannel( 966 logicalChannel, cla, COMMAND_STATUS, p1, p2, p3, data); 967 FcpTemplate fcpTemplate = FcpTemplate.parseFcpTemplate(response); 968 // Check that the FCP Template's file ID matches the MF 969 assertThat(containsFileId(fcpTemplate, MF_FILE_ID)).isTrue(); 970 assertThat(fcpTemplate.getStatus()).isEqualTo(STATUS_NORMAL_STRING); 971 972 // Select the Access Rule Reference for the MF. Similar to the MF, this will exist 973 // across all SIM cards. TS 102 221 Section 11.1.1 974 cla = CLA_SELECT; 975 p1 = 0; // select EF by FID 976 p2 = 0x04; // requesting FCP template 977 p3 = 2; // data (FID to be selected) is 2 bytes 978 data = MF_ARR_FILE_ID; 979 response = 980 mTelephonyManager.iccTransmitApduLogicalChannel( 981 logicalChannel, cla, COMMAND_SELECT, p1, p2, p3, data); 982 983 // Devices launching with Q or later must immediately return the FCP template from the 984 // previous SELECT command. Some devices that launched before Q return TPDUs (instead of 985 // APDUs) - these devices must issue a subsequent GET RESPONSE command to get the FCP 986 // template. 987 if (Build.VERSION.DEVICE_INITIAL_SDK_INT < Build.VERSION_CODES.Q) { 988 // Conditionally need to send GET RESPONSE apdu based on response from 989 // TelephonyManager 990 if (response.startsWith(STATUS_BYTES_REMAINING)) { 991 // Read the FCP template from the ICC. TS 102 221 Section 12.1.1 992 cla = CLA_GET_RESPONSE; 993 p1 = 0; 994 p2 = 0; 995 p3 = 0; 996 data = ""; 997 response = 998 mTelephonyManager.iccTransmitApduLogicalChannel( 999 logicalChannel, cla, COMMAND_GET_RESPONSE, p1, p2, p3, data); 1000 } 1001 } 1002 1003 fcpTemplate = FcpTemplate.parseFcpTemplate(response); 1004 // Check that the FCP Template's file ID matches the selected ARR 1005 assertThat(containsFileId(fcpTemplate, MF_ARR_FILE_ID)).isTrue(); 1006 assertThat(fcpTemplate.getStatus()).isEqualTo(STATUS_NORMAL_STRING); 1007 } finally { 1008 mTelephonyManager.iccCloseLogicalChannel(logicalChannel); 1009 } 1010 } 1011 1012 /** 1013 * Tests several invalid APDU instructions over a logical channel and makes sure appropriate 1014 * errors are returned from the UICC. 1015 */ 1016 @Test testIccTransmitApduLogicalChannelWithInvalidInputs()1017 public void testIccTransmitApduLogicalChannelWithInvalidInputs() { 1018 // An open LC is required for transmitting apdu commands. This opens an LC to the MF. 1019 IccOpenLogicalChannelResponse iccOpenLogicalChannelResponse = 1020 mTelephonyManager.iccOpenLogicalChannel(""); 1021 assertThat(iccOpenLogicalChannelResponse.getStatus()).isEqualTo(STATUS_NO_ERROR); 1022 final int logicalChannel = iccOpenLogicalChannelResponse.getChannel(); 1023 1024 try { 1025 // Make some invalid APDU commands and make sure they fail as expected. 1026 // Use an invalid p1 value for Status apdu 1027 int cla = CLA_STATUS | logicalChannel; 1028 int p1 = 0xFF; // only '00', '01', and '02' are allowed 1029 int p2 = 0; // same response parameters as the SELECT in the iccOpenLogicalChannel() 1030 // above 1031 int p3 = 0; // length of 'data' payload 1032 String data = ""; 1033 String response = 1034 mTelephonyManager.iccTransmitApduLogicalChannel( 1035 logicalChannel, cla, COMMAND_STATUS, p1, p2, p3, data); 1036 assertThat(INVALID_PARAMETERS_STATUSES.contains(response)).isTrue(); 1037 1038 // Select a file that doesn't exist 1039 cla = CLA_SELECT; 1040 p1 = 0x00; // select by file ID 1041 p2 = 0x0C; // no data returned 1042 p3 = 0x02; // length of 'data' payload 1043 data = "FFFF"; // invalid file ID 1044 response = 1045 mTelephonyManager.iccTransmitApduLogicalChannel( 1046 logicalChannel, cla, COMMAND_SELECT, p1, p2, p3, data); 1047 assertThat(response).isEqualTo(STATUS_FILE_NOT_FOUND); 1048 1049 // Manage channel with incorrect p1 parameter 1050 cla = CLA_MANAGE_CHANNEL | logicalChannel; 1051 p1 = 0x83; // Only '80' or '00' allowed for Manage Channel p1 1052 p2 = logicalChannel; // channel to be closed 1053 p3 = 0; // length of 'data' payload 1054 data = ""; 1055 response = 1056 mTelephonyManager.iccTransmitApduLogicalChannel( 1057 logicalChannel, cla, COMMAND_MANAGE_CHANNEL, p1, p2, p3, data); 1058 assertThat(isErrorResponse(response)).isTrue(); 1059 1060 // Use an incorrect class byte for Status apdu 1061 cla = 0xFF; 1062 p1 = 0; // no indication of application status 1063 p2 = 0; // same response parameters as the SELECT in the iccOpenLogicalChannel() above 1064 p3 = 0; // length of 'data' payload 1065 data = ""; 1066 response = 1067 mTelephonyManager.iccTransmitApduLogicalChannel( 1068 logicalChannel, cla, COMMAND_STATUS, p1, p2, p3, data); 1069 assertThat(response).isEqualTo(STATUS_WRONG_CLASS); 1070 1071 // Provide a data field that is longer than described for Select apdu 1072 cla = CLA_SELECT | logicalChannel; 1073 p1 = 0; // select by file ID 1074 p2 = 0x0C; // no data returned 1075 p3 = 0x04; // data passed is actually 2 bytes long 1076 data = "3F00"; // valid ID 1077 response = 1078 mTelephonyManager.iccTransmitApduLogicalChannel( 1079 logicalChannel, cla, COMMAND_SELECT, p1, p2, p3, data); 1080 assertThat(isErrorResponse(response)).isTrue(); 1081 1082 // Use an invalid instruction 1083 cla = 0; 1084 p1 = 0; 1085 p2 = 0; 1086 p3 = 0; 1087 data = ""; 1088 int invalidInstruction = 0xFF; // see TS 102 221 Table 10.5 for valid instructions 1089 response = 1090 mTelephonyManager.iccTransmitApduLogicalChannel( 1091 logicalChannel, cla, invalidInstruction, p1, p2, p3, data); 1092 assertThat(isErrorResponse(response)).isTrue(); 1093 } finally { 1094 mTelephonyManager.iccCloseLogicalChannel(logicalChannel); 1095 } 1096 } 1097 1098 @Test testIccTransmitApduLogicalChannelWithInvalidChannel()1099 public void testIccTransmitApduLogicalChannelWithInvalidChannel() throws IOException { 1100 IccOpenLogicalChannelResponse iccOpenLogicalChannelResponse = 1101 mTelephonyManager.iccOpenLogicalChannel(""); 1102 assertThat(iccOpenLogicalChannelResponse.getStatus()).isEqualTo(STATUS_NO_ERROR); 1103 final int closedCh = iccOpenLogicalChannelResponse.getChannel(); 1104 mTelephonyManager.iccCloseLogicalChannel(closedCh); 1105 1106 int[] badChannels = { 1107 // use after close 1108 closedCh, 1109 1110 // common wrong values 1111 -2, 1112 -1, 1113 50, 1114 100, 1115 1116 // int8_t max and max + 1 1117 127, 1118 128, 1119 1120 // uint8_t max - 1 to + 2, 1121 254, 1122 255, 1123 256, 1124 257, 1125 1126 // int16_t max and max + 1, 1127 32767, 1128 32768, 1129 1130 // uint16_t max + 1, 1131 65536, 1132 1133 // int32_t max 1134 2147483647, 1135 }; 1136 1137 for (int channel : badChannels) { 1138 String response = mTelephonyManager.iccTransmitApduLogicalChannel( 1139 channel, CLA_STATUS, COMMAND_STATUS, 0, 0, 0, ""); 1140 assertWithMessage("Unexpected response when transmitting on invalid channel " + channel) 1141 .that(response) 1142 .isAnyOf(STATUS_CHANNEL_NOT_SUPPORTED, STATUS_TECHNICAL_PROBLEM); 1143 } 1144 } 1145 1146 /** 1147 * This test ensures that files can be read off the UICC. This helps to test the SIM booting 1148 * process, as it process involves several file-reads. The ICCID is one of the first files read. 1149 */ 1150 @Test testApduFileRead()1151 public void testApduFileRead() { 1152 // Open a logical channel and select the MF. 1153 IccOpenLogicalChannelResponse iccOpenLogicalChannel = 1154 mTelephonyManager.iccOpenLogicalChannel(""); 1155 assertThat(iccOpenLogicalChannel.getStatus()).isEqualTo(STATUS_NO_ERROR); 1156 final int logicalChannel = iccOpenLogicalChannel.getChannel(); 1157 1158 try { 1159 // Select the ICCID. TS 102 221 Section 13.2 1160 int p1 = 0; // select by file ID 1161 int p2 = 0x0C; // no data returned 1162 int p3 = 2; // length of 'data' payload 1163 String response = 1164 mTelephonyManager.iccTransmitApduLogicalChannel( 1165 logicalChannel, CLA_SELECT, COMMAND_SELECT, p1, p2, p3, ICCID_FILE_ID); 1166 assertThat(response).isEqualTo(STATUS_NORMAL_STRING); 1167 1168 // Read the contents of the ICCID. 1169 p1 = 0; // 0-byte offset 1170 p2 = 0; // 0-byte offset 1171 p3 = 0; // length of 'data' payload 1172 response = 1173 mTelephonyManager.iccTransmitApduLogicalChannel( 1174 logicalChannel, CLA_READ_BINARY, COMMAND_READ_BINARY, p1, p2, p3, ""); 1175 assertThat(response).endsWith(STATUS_NORMAL_STRING); 1176 } finally { 1177 mTelephonyManager.iccCloseLogicalChannel(logicalChannel); 1178 } 1179 } 1180 1181 // ETSI TS 102 221 13.2 verifyValidIccId(String iccid)1182 private void verifyValidIccId(String iccid) { 1183 assertThat(iccid).hasLength(20); 1184 } 1185 1186 // ETSI TS 102 221 13.3 verifyValidPl(String pl)1187 private void verifyValidPl(String pl) { 1188 final int hexEntryLength = PL_ENTRY_LENGTH * HEX_BYTES_PER_CHAR; 1189 assertThat(pl.length() % hexEntryLength).isEqualTo(0); 1190 assertThat(pl.length()).isAtLeast(hexEntryLength); 1191 for (int i = 0; i < pl.length(); i += hexEntryLength) { 1192 String langHex = pl.substring(i, i + hexEntryLength); 1193 assertThat(langHex).hasLength(hexEntryLength); 1194 1195 byte[] lang = hexStringToBytes(langHex); 1196 assertThat(lang).hasLength(PL_ENTRY_LENGTH); 1197 int ch1 = Byte.toUnsignedInt(lang[0]); 1198 int ch2 = Byte.toUnsignedInt(lang[1]); 1199 if (ch1 == 0xFF && ch2 == 0xFF) continue; 1200 1201 assertTrue("Language code is not alphanumeric: " + langHex, 1202 isSeriouslyLetterOrDigit(ch1) && isSeriouslyLetterOrDigit(ch2)); 1203 } 1204 } 1205 openLogicalChannelWithRetries(String aid)1206 private IccOpenLogicalChannelResponse openLogicalChannelWithRetries(String aid) { 1207 for (int retries = 0; retries < MAX_RETRIES; retries++) { 1208 IccOpenLogicalChannelResponse response = mTelephonyManager.iccOpenLogicalChannel(aid); 1209 if (response.getStatus() != STATUS_MISSING_RESOURCE) return response; 1210 assertThat(response.getChannel()).isEqualTo(INVALID_CHANNEL); 1211 try { 1212 // Let's give other processes time to finish and release occupied channels. 1213 Thread.sleep(100); 1214 } catch (InterruptedException ex) { 1215 break; 1216 } 1217 } 1218 fail("Couldn't open logical channel: no resources"); 1219 return null; 1220 } 1221 1222 /** 1223 * This test verifies if two files can be read off the UICC at the same time through two 1224 * different channels. 1225 */ 1226 @Test testApduFileReadTwoChannels()1227 public void testApduFileReadTwoChannels() throws IOException { 1228 int channel1 = INVALID_CHANNEL; 1229 int channel2 = INVALID_CHANNEL; 1230 try { 1231 IccOpenLogicalChannelResponse channel1rsp = openLogicalChannelWithRetries(""); 1232 verifyValidIccOpenLogicalChannelResponse(channel1rsp); 1233 channel1 = channel1rsp.getChannel(); 1234 1235 IccOpenLogicalChannelResponse channel2rsp = openLogicalChannelWithRetries(""); 1236 verifyValidIccOpenLogicalChannelResponse(channel2rsp); 1237 channel2 = channel2rsp.getChannel(); 1238 1239 // TODO(b/375102360): CF should implement handling more than one logical channel 1240 assumeFalse(channel1 == channel2 && MediaUtils.onCuttlefish()); 1241 assertWithMessage("Two concurrently opened channels should be different") 1242 .that(channel2).isNotEqualTo(channel1); 1243 1244 // p1, p2, p3 - see testApduFileRead 1245 String selResponse = mTelephonyManager.iccTransmitApduLogicalChannel( 1246 channel1, CLA_SELECT, COMMAND_SELECT, 0, 0x0C, 2, PL_FILE_ID); 1247 assertThat(selResponse).isEqualTo(STATUS_NORMAL_STRING); 1248 1249 selResponse = mTelephonyManager.iccTransmitApduLogicalChannel( 1250 channel2, CLA_SELECT, COMMAND_SELECT, 0, 0x0C, 2, ICCID_FILE_ID); 1251 assertThat(selResponse).isEqualTo(STATUS_NORMAL_STRING); 1252 1253 // Read from two channels out of order -- SELECT command shouldn't affect other channels 1254 String contents2 = mTelephonyManager.iccTransmitApduLogicalChannel( 1255 channel2, CLA_READ_BINARY, COMMAND_READ_BINARY, 0, 0, 0, ""); 1256 assertThat(contents2).endsWith(STATUS_NORMAL_STRING); 1257 1258 String contents1 = mTelephonyManager.iccTransmitApduLogicalChannel( 1259 channel1, CLA_READ_BINARY, COMMAND_READ_BINARY, 0, 0, 0, ""); 1260 assertThat(contents1).endsWith(STATUS_NORMAL_STRING); 1261 1262 assertWithMessage("Contents of EF_PL and EF_ICCID shouldn't be the same") 1263 .that(contents1).isNotEqualTo(contents2); 1264 verifyValidPl(contents1.substring(0, contents1.length() - 4)); 1265 verifyValidIccId(contents2.substring(0, contents2.length() - 4)); 1266 } finally { 1267 if (channel1 != INVALID_CHANNEL) { 1268 mTelephonyManager.iccCloseLogicalChannel(channel1); 1269 } 1270 if (channel2 != INVALID_CHANNEL && channel1 != channel2) { 1271 mTelephonyManager.iccCloseLogicalChannel(channel2); 1272 } 1273 } 1274 } 1275 1276 /** This test sends several valid APDU commands over the basic channel (channel 0). */ 1277 @Test testIccTransmitApduBasicChannel()1278 public void testIccTransmitApduBasicChannel() { 1279 // select the MF 1280 int cla = CLA_SELECT; 1281 int p1 = 0; // select EF by FID 1282 int p2 = 0x0C; // requesting FCP template 1283 int p3 = 2; // length of 'data' payload 1284 String data = MF_FILE_ID; 1285 String response = 1286 mTelephonyManager.iccTransmitApduBasicChannel( 1287 cla, COMMAND_SELECT, p1, p2, p3, data); 1288 assertThat(response).isEqualTo(STATUS_NORMAL_STRING); 1289 1290 // get the Status of the current file/directory 1291 cla = CLA_STATUS; 1292 p1 = 0; // no indication of application status 1293 p2 = 0; // same response parameters as the SELECT in the iccOpenLogicalChannel() above 1294 p3 = 0; // length of 'data' payload 1295 data = ""; 1296 response = 1297 mTelephonyManager.iccTransmitApduBasicChannel( 1298 cla, COMMAND_STATUS, p1, p2, p3, data); 1299 FcpTemplate fcpTemplate = FcpTemplate.parseFcpTemplate(response); 1300 assertThat(containsFileId(fcpTemplate, MF_FILE_ID)).isTrue(); 1301 1302 // Manually open a logical channel 1303 cla = CLA_MANAGE_CHANNEL; 1304 p1 = 0; // open a logical channel 1305 p2 = 0; // '00' for open command 1306 p3 = 0; // length of data payload 1307 data = ""; 1308 response = 1309 mTelephonyManager.iccTransmitApduBasicChannel( 1310 cla, COMMAND_MANAGE_CHANNEL, p1, p2, p3, data); 1311 // response is in the format | 1 byte: channel number | 2 bytes: status word | 1312 String responseStatus = response.substring(response.length() - 4); 1313 assertThat(responseStatus).isEqualTo(STATUS_NORMAL_STRING); 1314 1315 // Close the open channel 1316 byte[] responseBytes = hexStringToBytes(response); 1317 int channel = responseBytes[0]; 1318 cla = CLA_MANAGE_CHANNEL; 1319 p1 = 0x80; // close a logical channel 1320 p2 = channel; // the channel to be closed 1321 p3 = 0; // length of data payload 1322 data = ""; 1323 response = 1324 mTelephonyManager.iccTransmitApduBasicChannel( 1325 cla, COMMAND_MANAGE_CHANNEL, p1, p2, p3, data); 1326 assertThat(response).isEqualTo(STATUS_NORMAL_STRING); 1327 } 1328 1329 /** 1330 * This test verifies that {@link TelephonyManager#setLine1NumberForDisplay(String, String)} 1331 * correctly sets the Line 1 alpha tag and number when called, and the phone number 1332 * of {@link SubscriptionManager#PHONE_NUMBER_SOURCE_CARRIER}. 1333 */ 1334 @Test testLine1NumberForDisplay()1335 public void testLine1NumberForDisplay() { 1336 int subId = SubscriptionManager.getDefaultSubscriptionId(); 1337 // Cache original alpha tag and number values. 1338 String originalAlphaTag = mTelephonyManager.getLine1AlphaTag(); 1339 String originalNumber = mTelephonyManager.getLine1Number(); 1340 1341 try { 1342 // clear any potentially overridden values and cache defaults 1343 mTelephonyManager.setLine1NumberForDisplay(null, null); 1344 String defaultAlphaTag = mTelephonyManager.getLine1AlphaTag(); 1345 String defaultNumber = mTelephonyManager.getLine1Number(); 1346 1347 assertThat(mTelephonyManager.setLine1NumberForDisplay(ALPHA_TAG_A, NUMBER_A)).isTrue(); 1348 assertThat(mTelephonyManager.getLine1AlphaTag()).isEqualTo(ALPHA_TAG_A); 1349 assertThat(mTelephonyManager.getLine1Number()).isEqualTo(NUMBER_A); 1350 assertThat(mSubscriptionManager.getPhoneNumber(subId, PHONE_NUMBER_SOURCE_CARRIER)) 1351 .isEqualTo(NUMBER_A); 1352 1353 assertThat(mTelephonyManager.setLine1NumberForDisplay(ALPHA_TAG_B, NUMBER_B)).isTrue(); 1354 assertThat(mTelephonyManager.getLine1AlphaTag()).isEqualTo(ALPHA_TAG_B); 1355 assertThat(mTelephonyManager.getLine1Number()).isEqualTo(NUMBER_B); 1356 assertThat(mSubscriptionManager.getPhoneNumber(subId, PHONE_NUMBER_SOURCE_CARRIER)) 1357 .isEqualTo(NUMBER_B); 1358 1359 // null is used to clear the Line 1 alpha tag and number values. 1360 assertThat(mTelephonyManager.setLine1NumberForDisplay(null, null)).isTrue(); 1361 assertThat(mTelephonyManager.getLine1AlphaTag()).isEqualTo(defaultAlphaTag); 1362 assertThat(mTelephonyManager.getLine1Number()).isEqualTo(defaultNumber); 1363 assertThat(mSubscriptionManager.getPhoneNumber(subId, PHONE_NUMBER_SOURCE_CARRIER)) 1364 .isEqualTo(""); 1365 } finally { 1366 // Reset original alpha tag and number values. 1367 mTelephonyManager.setLine1NumberForDisplay(originalAlphaTag, originalNumber); 1368 } 1369 } 1370 1371 /** 1372 * This test verifies that {@link TelephonyManager#setVoiceMailNumber(String, String)} correctly 1373 * sets the VoiceMail alpha tag and number when called. 1374 */ 1375 @Test testVoiceMailNumber()1376 public void testVoiceMailNumber() { 1377 assumeTrue(hasTelephonyCalling()); 1378 1379 // Cache original alpha tag and number values. 1380 String originalAlphaTag = mTelephonyManager.getVoiceMailAlphaTag(); 1381 String originalNumber = mTelephonyManager.getVoiceMailNumber(); 1382 1383 try { 1384 assertThat(mTelephonyManager.setVoiceMailNumber(ALPHA_TAG_A, NUMBER_A)).isTrue(); 1385 assertThat(mTelephonyManager.getVoiceMailAlphaTag()).isEqualTo(ALPHA_TAG_A); 1386 assertThat(mTelephonyManager.getVoiceMailNumber()).isEqualTo(NUMBER_A); 1387 1388 assertThat(mTelephonyManager.setVoiceMailNumber(ALPHA_TAG_B, NUMBER_B)).isTrue(); 1389 assertThat(mTelephonyManager.getVoiceMailAlphaTag()).isEqualTo(ALPHA_TAG_B); 1390 assertThat(mTelephonyManager.getVoiceMailNumber()).isEqualTo(NUMBER_B); 1391 } finally { 1392 // Reset original alpha tag and number values. 1393 mTelephonyManager.setVoiceMailNumber(originalAlphaTag, originalNumber); 1394 } 1395 } 1396 1397 /** 1398 * This test verifies that {@link SubscriptionManager#createSubscriptionGroup(List)} correctly 1399 * create a group with the given subscription id. 1400 * 1401 * <p>This also verifies that {@link SubscriptionManager#removeSubscriptionsFromGroup(List, 1402 * ParcelUuid)} correctly remove the given subscription group. 1403 */ 1404 @Test testCreateAndRemoveSubscriptionGroup()1405 public void testCreateAndRemoveSubscriptionGroup() { 1406 // Set subscription group with current sub Id. 1407 int subId = SubscriptionManager.getDefaultSubscriptionId(); 1408 List<Integer> subGroup = Arrays.asList(subId); 1409 ParcelUuid uuid = mSubscriptionManager.createSubscriptionGroup(subGroup); 1410 1411 // Getting subscriptions in group. 1412 List<SubscriptionInfo> infoList = mSubscriptionManager.getSubscriptionsInGroup(uuid); 1413 1414 try { 1415 assertThat(infoList).hasSize(1); 1416 assertThat(infoList.get(0).getGroupUuid()).isEqualTo(uuid); 1417 assertThat(infoList.get(0).getSubscriptionId()).isEqualTo(subId); 1418 } finally { 1419 // Verify that the given subGroup has been removed. 1420 mSubscriptionManager.removeSubscriptionsFromGroup(subGroup, uuid); 1421 infoList = mSubscriptionManager.getSubscriptionsInGroup(uuid); 1422 assertThat(infoList).isEmpty(); 1423 } 1424 } 1425 1426 @Test testAddSubscriptionToExistingGroupForMultipleSims()1427 public void testAddSubscriptionToExistingGroupForMultipleSims() { 1428 if (mTelephonyManager.getPhoneCount() < DSDS_PHONE_COUNT 1429 || mSubscriptionManager.getActiveSubscriptionInfoList().size() < DSDS_PHONE_COUNT) { 1430 // This test requires at least two active subscriptions. 1431 return; 1432 } 1433 1434 // Set subscription group with current sub Id. 1435 int subId = SubscriptionManager.getDefaultSubscriptionId(); 1436 if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) return; 1437 ParcelUuid uuid = ShellIdentityUtils.invokeMethodWithShellPermissions(mSubscriptionManager, 1438 (sm) -> sm.createSubscriptionGroup(Arrays.asList(subId))); 1439 1440 try { 1441 // Get all active subscriptions. 1442 List<SubscriptionInfo> activeSubInfos = 1443 ShellIdentityUtils.invokeMethodWithShellPermissions(mSubscriptionManager, 1444 (sm) -> sm.getActiveSubscriptionInfoList()); 1445 1446 List<Integer> activeSubGroup = getSubscriptionIdList(activeSubInfos); 1447 activeSubGroup.removeIf(id -> id == subId); 1448 1449 ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mSubscriptionManager, 1450 (sm) -> sm.addSubscriptionsIntoGroup(activeSubGroup, uuid)); 1451 1452 List<Integer> infoList = ShellIdentityUtils.invokeMethodWithShellPermissions( 1453 mSubscriptionManager, 1454 (sm) -> getSubscriptionIdList(sm.getSubscriptionsInGroup(uuid))); 1455 1456 activeSubGroup.add(subId); 1457 assertThat(infoList).containsExactlyElementsIn(activeSubGroup); 1458 } finally { 1459 removeSubscriptionsFromGroup(uuid); 1460 } 1461 } 1462 1463 /** 1464 * This test verifies that {@link SubscriptionManager#addSubscriptionsIntoGroup(List, 1465 * ParcelUuid)}} correctly add some additional subscriptions to the existing group. 1466 * 1467 * <p>This test required the device has more than one subscription. 1468 */ 1469 @Test testAddSubscriptionToExistingGroupForEsim()1470 public void testAddSubscriptionToExistingGroupForEsim() { 1471 assumeTrue(hasFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION)); 1472 assumeTrue(hasFeature(PackageManager.FEATURE_TELEPHONY_EUICC)); 1473 // Set subscription group with current sub Id. 1474 int subId = SubscriptionManager.getDefaultSubscriptionId(); 1475 if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) return; 1476 ParcelUuid uuid = mSubscriptionManager.createSubscriptionGroup(Arrays.asList(subId)); 1477 1478 try { 1479 // Get all accessible eSim subscription. 1480 List<SubscriptionInfo> accessibleSubInfos = 1481 mSubscriptionManager.getAccessibleSubscriptionInfoList(); 1482 if (accessibleSubInfos != null && accessibleSubInfos.size() > 1) { 1483 List<Integer> accessibleSubGroup = getSubscriptionIdList(accessibleSubInfos); 1484 accessibleSubGroup.removeIf(id -> id == subId); 1485 1486 mSubscriptionManager.addSubscriptionsIntoGroup(accessibleSubGroup, uuid); 1487 1488 List<Integer> infoList = 1489 getSubscriptionIdList(mSubscriptionManager.getSubscriptionsInGroup(uuid)); 1490 accessibleSubGroup.add(subId); 1491 assertThat(infoList).containsExactlyElementsIn(accessibleSubGroup); 1492 } 1493 } finally { 1494 removeSubscriptionsFromGroup(uuid); 1495 } 1496 } 1497 1498 /** 1499 * This test verifies that {@link SubscriptionManager#setOpportunistic(boolean, int)} correctly 1500 * set the opportunistic property of the given subscription. 1501 */ 1502 @Test testOpportunistic()1503 public void testOpportunistic() { 1504 int subId = SubscriptionManager.getDefaultSubscriptionId(); 1505 if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) return; 1506 SubscriptionInfo info = mSubscriptionManager.getActiveSubscriptionInfo(subId); 1507 boolean oldOpportunistic = info.isOpportunistic(); 1508 boolean newOpportunistic = !oldOpportunistic; 1509 1510 try { 1511 // Mark the given subscription as opportunistic subscription. 1512 assertThat(mSubscriptionManager.setOpportunistic(newOpportunistic, subId)).isTrue(); 1513 1514 // Verify that the given subscription is opportunistic subscription. 1515 info = mSubscriptionManager.getActiveSubscriptionInfo(subId); 1516 assertThat(info.isOpportunistic()).isEqualTo(newOpportunistic); 1517 } finally { 1518 // Set back to original opportunistic property. 1519 mSubscriptionManager.setOpportunistic(oldOpportunistic, subId); 1520 info = mSubscriptionManager.getActiveSubscriptionInfo(subId); 1521 assertThat(info.isOpportunistic()).isEqualTo(oldOpportunistic); 1522 1523 // As opportunistic subscription can not be the default data/voice/sms subscription, 1524 // when the test case set the active subscription as opportunistic, the default 1525 // subscription may set to INVALID_SUBSCRIPTION_ID. Although at the end, the test case 1526 // tries to recover it, it may take time to fully take effort and fail the following 1527 // test case. Add a polling check of carrier privilege on default subscription here to 1528 // make sure default subscription has recovered before ending the case. 1529 PollingCheck.waitFor(5000, () -> getContext().getSystemService(TelephonyManager.class) 1530 .hasCarrierPrivileges(), 1531 "Timeout when waiting to gain carrier privileges again."); 1532 } 1533 } 1534 1535 /** 1536 * This test verifies that {@link TelephonyManager#iccExchangeSimIO(int, int, int, int, int, 1537 * String)} correctly transmits iccIO commands to the UICC card. First, the MF is selected via a 1538 * SELECT apdu via the basic channel, then a STATUS AT-command is sent. 1539 */ 1540 @Test testIccExchangeSimIO()1541 public void testIccExchangeSimIO() { 1542 // select the MF first. This makes sure the next STATUS AT-command returns a FCP template 1543 // for the right file. 1544 int cla = CLA_SELECT; 1545 int p1 = 0; // select EF by FID 1546 int p2 = 0x0C; // requesting FCP template 1547 int p3 = 2; // length of 'data' payload 1548 String data = MF_FILE_ID; 1549 String response = 1550 mTelephonyManager.iccTransmitApduBasicChannel( 1551 cla, COMMAND_SELECT, p1, p2, p3, data); 1552 assertThat(response).isEqualTo(STATUS_NORMAL_STRING); 1553 1554 // The iccExchangeSimIO command implements the +CRSM command defined in TS 27.007 section 1555 // 8.18. A STATUS command is sent and the returned value will be an FCP template. 1556 byte[] result = 1557 mTelephonyManager.iccExchangeSimIO( 1558 0, // fileId: not required for STATUS 1559 COMMAND_STATUS, // command: STATUS 1560 0, // p1: not required for STATUS 1561 0, // p2: not required for STATUS 1562 0, // p3: not required for STATUS 1563 ""); // filePath: not required for STATUS 1564 String resultString = bytesToHexString(result); 1565 FcpTemplate fcpTemplate = FcpTemplate.parseFcpTemplate(resultString); 1566 assertThat(containsFileId(fcpTemplate, MF_FILE_ID)).isTrue(); 1567 assertWithMessage("iccExchangeSimIO returned non-normal Status byte: %s", resultString) 1568 .that(fcpTemplate.getStatus()) 1569 .isEqualTo(STATUS_NORMAL_STRING); 1570 } 1571 1572 /** 1573 * This test checks that a STATUS apdu can be sent as an encapsulated envelope to the UICC via 1574 * {@link TelephonyManager#sendEnvelopeWithStatus(String)}. 1575 */ 1576 @Test testSendEnvelopeWithStatus()1577 public void testSendEnvelopeWithStatus() { 1578 // STATUS apdu as hex String 1579 String envelope = 1580 CLA_STATUS_STRING 1581 + COMMAND_STATUS_STRING 1582 + "00" // p1: no indication of application status 1583 + "00"; // p2: identical parameters to 1584 String response = mTelephonyManager.sendEnvelopeWithStatus(envelope); 1585 1586 // TODO(b/137963715): add more specific assertions on response from TelMan#sendEnvelope 1587 assertWithMessage("sendEnvelopeWithStatus is null for envelope=%s", envelope) 1588 .that(response) 1589 .isNotNull(); 1590 } 1591 1592 /** 1593 * This test checks that applications with carrier privilege can set/clear signal strength 1594 * update request via {@link 1595 * TelephonyManager#setSignalStrengthUpdateRequest(SignalStrengthUpdateRequest)} and {@link 1596 * TelephonyManager#clearSignalStrengthUpdateRequest} without {@link 1597 * android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}. 1598 */ 1599 @Test testSetClearSignalStrengthUpdateRequest()1600 public void testSetClearSignalStrengthUpdateRequest() { 1601 final SignalStrengthUpdateRequest request = 1602 new SignalStrengthUpdateRequest.Builder() 1603 .setSignalThresholdInfos( 1604 List.of( 1605 new SignalThresholdInfo.Builder() 1606 .setRadioAccessNetworkType( 1607 AccessNetworkConstants.AccessNetworkType 1608 .GERAN) 1609 .setSignalMeasurementType( 1610 SignalThresholdInfo 1611 .SIGNAL_MEASUREMENT_TYPE_RSSI) 1612 .setThresholds(new int[] {-113, -103, -97, -51}) 1613 .setHysteresisDb(1) 1614 .build())) 1615 .setReportingRequestedWhileIdle(true) 1616 .build(); 1617 try { 1618 mTelephonyManager.setSignalStrengthUpdateRequest(request); 1619 } finally { 1620 mTelephonyManager.clearSignalStrengthUpdateRequest(request); 1621 } 1622 } 1623 verifyValidIccOpenLogicalChannelResponse(IccOpenLogicalChannelResponse response)1624 private void verifyValidIccOpenLogicalChannelResponse(IccOpenLogicalChannelResponse response) { 1625 assertThat(response.getStatus()).isEqualTo(STATUS_NO_ERROR); 1626 assertThat(response.getSelectResponse()).isEqualTo(STATUS_NORMAL); 1627 1628 // The assigned channel should be between the min and max allowed channel numbers 1629 int channel = response.getChannel(); 1630 assertThat(channel).isIn(Range.closed(MIN_LOGICAL_CHANNEL, MAX_LOGICAL_CHANNEL)); 1631 } 1632 removeSubscriptionsFromGroup(ParcelUuid uuid)1633 private void removeSubscriptionsFromGroup(ParcelUuid uuid) { 1634 List<SubscriptionInfo> infoList = ShellIdentityUtils.invokeMethodWithShellPermissions( 1635 mSubscriptionManager, 1636 (sm) -> (sm.getSubscriptionsInGroup(uuid))); 1637 if (!infoList.isEmpty()) { 1638 List<Integer> subscriptionIdList = getSubscriptionIdList(infoList); 1639 ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mSubscriptionManager, 1640 (sm) -> sm.removeSubscriptionsFromGroup(subscriptionIdList, uuid)); 1641 } 1642 infoList = ShellIdentityUtils.invokeMethodWithShellPermissions( 1643 mSubscriptionManager, 1644 (sm) -> (sm.getSubscriptionsInGroup(uuid))); 1645 assertThat(infoList).isEmpty(); 1646 } 1647 getSubscriptionIdList(List<SubscriptionInfo> subInfoList)1648 private List<Integer> getSubscriptionIdList(List<SubscriptionInfo> subInfoList) { 1649 if (subInfoList == null || subInfoList.isEmpty()) return Collections.EMPTY_LIST; 1650 return subInfoList.stream() 1651 .map(info -> info.getSubscriptionId()) 1652 .collect(Collectors.toList()); 1653 } 1654 1655 /** 1656 * Checks whether the a {@code fcpTemplate} contains the given {@code fileId}. 1657 * 1658 * @param fcpTemplate The FCP Template to be checked. 1659 * @param fileId The file ID that is being searched for 1660 * @return true iff fcpTemplate contains fileId. 1661 */ containsFileId(FcpTemplate fcpTemplate, String fileId)1662 private boolean containsFileId(FcpTemplate fcpTemplate, String fileId) { 1663 return fcpTemplate.getTlvs().stream() 1664 .anyMatch(tlv -> tlv.getTag() == FILE_IDENTIFIER && tlv.getValue().equals(fileId)); 1665 } 1666 1667 /** 1668 * Returns true iff {@code response} indicates an error with the previous APDU. 1669 * 1670 * @param response The APDU response to be checked. 1671 * @return true iff the given response indicates an error occurred 1672 */ isErrorResponse(@onnull String response)1673 private boolean isErrorResponse(@Nonnull String response) { 1674 return !(STATUS_NORMAL_STRING.equals(response) 1675 || response.startsWith(STATUS_WARNING_A) 1676 || response.startsWith(STATUS_WARNING_B) 1677 || response.startsWith(STATUS_BYTES_REMAINING)); 1678 } 1679 1680 private static class IntentReceiver extends BroadcastReceiver { 1681 private final CountDownLatch mReceiveLatch = new CountDownLatch(1); 1682 1683 @Override onReceive(Context context, Intent intent)1684 public void onReceive(Context context, Intent intent) { 1685 mReceiveLatch.countDown(); 1686 } 1687 waitForReceive()1688 public boolean waitForReceive() throws InterruptedException { 1689 return mReceiveLatch.await(30, TimeUnit.SECONDS); 1690 } 1691 } 1692 1693 @Test testEapSimAuthentication()1694 public void testEapSimAuthentication() { 1695 assumeTrue( 1696 "testEapSimAuthentication requires a 2021 CTS UICC or newer", 1697 UiccUtil.uiccHasCertificate(CTS_UICC_2021)); 1698 // K: '000102030405060708090A0B0C0D0E0F', defined by TS 134 108#8.2 1699 // n: 128 (Bits to use for RES value) 1700 // Format: [Length][RAND] 1701 String challenge = "10" + EAP_SIM_AKA_RAND; 1702 String base64Challenge = Base64.encodeToString(hexStringToBytes(challenge), Base64.NO_WRAP); 1703 String base64Response = null; 1704 try { 1705 base64Response = mTelephonyManager.getIccAuthentication( 1706 TelephonyManager.APPTYPE_USIM, 1707 TelephonyManager.AUTHTYPE_EAP_SIM, 1708 base64Challenge); 1709 } catch (UnsupportedOperationException e) { 1710 assumeNoException("EAP-SIM not supported", e); 1711 } 1712 assertWithMessage("UICC returned null for EAP-SIM auth").that(base64Response).isNotNull(); 1713 byte[] response = Base64.decode(base64Response, Base64.DEFAULT); 1714 assertWithMessage("Results for AUTHTYPE_EAP_SIM failed") 1715 .that(response) 1716 .isEqualTo(hexStringToBytes(EXPECTED_EAP_SIM_RESULT)); 1717 } 1718 1719 @Test testEapAkaAuthentication()1720 public void testEapAkaAuthentication() { 1721 // Wear devices do not yet support EapAkaAuthentication, so skip this test for now 1722 // TODO: use REQUEST_NOT_SUPPORTED on Wear instead of skipping this test 1723 if (isWear()) { 1724 return; 1725 } 1726 assumeTrue( 1727 "testEapAkaAuthentication requires a 2021 CTS UICC or newer", 1728 UiccUtil.uiccHasCertificate(CTS_UICC_2021)); 1729 // K: '000102030405060708090A0B0C0D0E0F', defined by TS 134 108#8.2 1730 // n: 128 (Bits to use for RES value) 1731 // Format: [Length][Rand][Length][Autn] 1732 String challenge = "10" + EAP_SIM_AKA_RAND + "10" + EAP_AKA_AUTN; 1733 String base64Challenge = Base64.encodeToString(hexStringToBytes(challenge), Base64.NO_WRAP); 1734 String base64Response = null; 1735 try { 1736 base64Response = mTelephonyManager.getIccAuthentication( 1737 TelephonyManager.APPTYPE_USIM, 1738 TelephonyManager.AUTHTYPE_EAP_AKA, 1739 base64Challenge); 1740 } catch (UnsupportedOperationException ex) { 1741 assumeNoException("EAP-AKA not supported", ex); 1742 } 1743 1744 assertWithMessage("UICC returned null for EAP-AKA auth").that(base64Response).isNotNull(); 1745 byte[] response = Base64.decode(base64Response, Base64.NO_WRAP); 1746 1747 // response may be formatted as: [DB][Length][RES][Length][CK][Length][IK][Length][Kc] 1748 byte[] akaResponse = Arrays.copyOfRange(response, 0, EAP_AKA_RESPONSE_LENGTH); 1749 assertWithMessage("Results for AUTHTYPE_EAP_AKA failed") 1750 .that(akaResponse) 1751 .isEqualTo(hexStringToBytes(EXPECTED_EAP_AKA_RESULT)); 1752 } 1753 1754 /** 1755 * This test checks that applications with carrier privilege can set/get data enable 1756 * state. 1757 */ 1758 @Test testDataEnableRequest()1759 public void testDataEnableRequest() { 1760 for (int i = DATA_ENABLED_REASON_USER; i <= DATA_ENABLED_REASON_THERMAL; i++) { 1761 mTelephonyManager.isDataEnabledForReason(i); 1762 } 1763 boolean isDataEnabled = mTelephonyManager.isDataEnabledForReason( 1764 TelephonyManager.DATA_ENABLED_REASON_CARRIER); 1765 mTelephonyManager.setDataEnabledForReason( 1766 TelephonyManager.DATA_ENABLED_REASON_CARRIER, !isDataEnabled); 1767 mTelephonyManager.setDataEnabledForReason( 1768 TelephonyManager.DATA_ENABLED_REASON_CARRIER, isDataEnabled); 1769 } 1770 1771 /** 1772 * This test checks that applications with carrier privileges can get network slicing 1773 * configuration. 1774 */ 1775 @Test testGetNetworkSlicingConfiguration()1776 public void testGetNetworkSlicingConfiguration() { 1777 CompletableFuture<NetworkSlicingConfig> resultFuture = new CompletableFuture<>(); 1778 mTelephonyManager.getNetworkSlicingConfiguration( 1779 AsyncTask.SERIAL_EXECUTOR, resultFuture::complete); 1780 } 1781 isWear()1782 private boolean isWear() { 1783 return getContext().getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH); 1784 } 1785 1786 /** Checks whether the telephony feature is supported. */ hasFeature(String feature)1787 private boolean hasFeature(String feature) { 1788 return mPackageManager == null ? false : mPackageManager.hasSystemFeature(feature); 1789 } 1790 1791 /** 1792 * Tests that the device properly sets and pads the contents of EF_FPLMN 1793 */ 1794 @Test testSetForbiddenPlmns()1795 public void testSetForbiddenPlmns() { 1796 assumeTrue(supportSetFplmn()); 1797 1798 String[] originalFplmns = mTelephonyManager.getForbiddenPlmns(); 1799 assertNotNull(originalFplmns); 1800 try { 1801 int numFplmnsSet = mTelephonyManager.setForbiddenPlmns(FPLMN_TEST); 1802 String[] writtenFplmns = mTelephonyManager.getForbiddenPlmns(); 1803 assertEquals("Wrong return value for setFplmns with less than required fplmns: " 1804 + numFplmnsSet, FPLMN_TEST.size(), numFplmnsSet); 1805 assertEquals("Wrong Fplmns content written", FPLMN_TEST, Arrays.asList(writtenFplmns)); 1806 } finally { 1807 // Restore 1808 mTelephonyManager.setForbiddenPlmns(Arrays.asList(originalFplmns)); 1809 } 1810 } 1811 1812 /** 1813 * Tests that the device properly truncates the contents of EF_FPLMN when provided size 1814 * is too big. 1815 */ 1816 @Test testSetForbiddenPlmnsTruncate()1817 public void testSetForbiddenPlmnsTruncate() { 1818 assumeTrue(supportSetFplmn()); 1819 1820 String[] originalFplmns = mTelephonyManager.getForbiddenPlmns(); 1821 assertNotNull(originalFplmns); 1822 try { 1823 List<String> targetFplmns = new ArrayList<>(); 1824 for (int i = 0; i < MIN_FPLMN_NUM; i++) { 1825 targetFplmns.add(PLMN_A); 1826 } 1827 for (int i = MIN_FPLMN_NUM; i < MAX_FPLMN_NUM; i++) { 1828 targetFplmns.add(PLMN_B); 1829 } 1830 int numFplmnsSet = mTelephonyManager.setForbiddenPlmns(targetFplmns); 1831 String[] writtenFplmns = mTelephonyManager.getForbiddenPlmns(); 1832 assertTrue("Wrong return value for setFplmns with overflowing fplmns: " + numFplmnsSet, 1833 numFplmnsSet < MAX_FPLMN_NUM); 1834 assertEquals("Number of Fplmns set does not equal number of Fplmns available", 1835 numFplmnsSet, writtenFplmns.length); 1836 assertEquals("Wrong Fplmns content written", targetFplmns.subList(0, numFplmnsSet), 1837 Arrays.asList(writtenFplmns)); 1838 } finally { 1839 // Restore 1840 mTelephonyManager.setForbiddenPlmns(Arrays.asList(originalFplmns)); 1841 } 1842 } 1843 1844 /** 1845 * Tests that the device properly deletes the contents of EF_FPLMN 1846 */ 1847 @Test testSetForbiddenPlmnsDelete()1848 public void testSetForbiddenPlmnsDelete() { 1849 assumeTrue(supportSetFplmn()); 1850 1851 String[] originalFplmns = mTelephonyManager.getForbiddenPlmns(); 1852 assertNotNull(originalFplmns); 1853 try { 1854 // Support test for empty SIM 1855 List<String> targetDummyFplmns = new ArrayList<>(); 1856 for (int i = 0; i < MIN_FPLMN_NUM; i++) { 1857 targetDummyFplmns.add(PLMN_A); 1858 } 1859 mTelephonyManager.setForbiddenPlmns(targetDummyFplmns); 1860 String[] writtenDummyFplmns = mTelephonyManager.getForbiddenPlmns(); 1861 assertEquals(targetDummyFplmns, Arrays.asList(writtenDummyFplmns)); 1862 1863 List<String> targetFplmns = new ArrayList<>(); 1864 int numFplmnsSet = mTelephonyManager.setForbiddenPlmns(targetFplmns); 1865 String[] writtenFplmns = mTelephonyManager.getForbiddenPlmns(); 1866 assertEquals("Wrong return value for setFplmns with empty list", 0, numFplmnsSet); 1867 assertEquals("Wrong number of Fplmns written", 0, writtenFplmns.length); 1868 // TODO wait for 10 minutes or so for the FPLMNS list to grow back 1869 } finally { 1870 // Restore 1871 mTelephonyManager.setForbiddenPlmns(Arrays.asList(originalFplmns)); 1872 } 1873 } 1874 1875 /** 1876 * Tests that setForbiddenPlmns properly handles null input 1877 */ 1878 @Test testSetForbiddenPlmnsVoid()1879 public void testSetForbiddenPlmnsVoid() { 1880 assumeTrue(supportSetFplmn()); 1881 1882 String[] originalFplmns = mTelephonyManager.getForbiddenPlmns(); 1883 assertNotNull(originalFplmns); 1884 try { 1885 mTelephonyManager.setForbiddenPlmns(null); 1886 fail("Expected IllegalArgumentException. Null input is not allowed"); 1887 } catch (IllegalArgumentException expected) { 1888 } finally { 1889 mTelephonyManager.setForbiddenPlmns(Arrays.asList(originalFplmns)); 1890 } 1891 } 1892 1893 @Test testSetAndGetSubscriptionPlan()1894 public void testSetAndGetSubscriptionPlan() { 1895 final int subId = getFirstActivateCarrierPrivilegedSubscriptionId(); 1896 // This test case requires subscription with carrier privileges 1897 assumeFalse(subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID); 1898 1899 final SubscriptionPlan plan = createTestSubscriptionPlan(); 1900 try { 1901 mSubscriptionManager.setSubscriptionPlans( 1902 subId, List.of(plan), SUB_PLAN_EXPIRATION_DURATION); 1903 } catch (SecurityException se) { 1904 fail("setSubscriptionPlans with carrier privilege throws " + se); 1905 } 1906 1907 try { 1908 List<SubscriptionPlan> plans = mSubscriptionManager.getSubscriptionPlans(subId); 1909 assertThat(plans).isNotEmpty(); 1910 SubscriptionPlan retrievedPlan = plans.get(0); 1911 assertThat(retrievedPlan).isEqualTo(plan); 1912 } catch (SecurityException se) { 1913 fail("getSubscriptionPlans with carrier privilege throws " + se); 1914 } 1915 } 1916 1917 @Test testSetSubscriptionOverrideUnmetered()1918 public void testSetSubscriptionOverrideUnmetered() { 1919 final int subId = getFirstActivateCarrierPrivilegedSubscriptionId(); 1920 // This test case requires subscription with carrier privileges 1921 assumeFalse(subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID); 1922 1923 try { 1924 mSubscriptionManager.setSubscriptionOverrideUnmetered( 1925 subId, true, SUB_PLAN_EXPIRATION_DURATION); 1926 } catch (SecurityException se) { 1927 fail("setSubscriptionOverrideUnmetered with carrier privilege throws " + se); 1928 } 1929 } 1930 1931 @Test testSetSubscriptionOverrideCongested()1932 public void testSetSubscriptionOverrideCongested() { 1933 final int subId = getFirstActivateCarrierPrivilegedSubscriptionId(); 1934 // This test case requires subscription with carrier privileges 1935 assumeFalse(subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID); 1936 1937 SubscriptionPlan plan = createTestSubscriptionPlan(); 1938 try { 1939 mSubscriptionManager.setSubscriptionPlans( 1940 subId, List.of(plan), SUB_PLAN_EXPIRATION_DURATION); 1941 mSubscriptionManager.setSubscriptionOverrideCongested( 1942 subId, true, SUB_PLAN_EXPIRATION_DURATION); 1943 } catch (SecurityException se) { 1944 fail("setSubscriptionOverrideCongested with carrier privilege throws " + se); 1945 } 1946 } 1947 1948 /** 1949 * Verify that the phone is supporting the action of setForbiddenPlmn. 1950 * 1951 * @return whether to proceed the test 1952 */ supportSetFplmn()1953 private boolean supportSetFplmn() { 1954 if (!hasFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION)) { 1955 return false; 1956 } 1957 return mTelephonyManager.getPhoneType() == TelephonyManager.PHONE_TYPE_GSM; 1958 } 1959 createTestSubscriptionPlan()1960 private SubscriptionPlan createTestSubscriptionPlan() { 1961 return SubscriptionPlan.Builder.createNonrecurring(SUB_PLAN_START, SUB_PLAN_END) 1962 .setDataLimit(SUB_PLAN_DATA_LIMIT_BYTES, SubscriptionPlan.LIMIT_BEHAVIOR_THROTTLED) 1963 .setTitle(SUB_PLAN_TITLE) 1964 .setSummary(SUB_PLAN_SUMMARY) 1965 .build(); 1966 } 1967 } 1968