1 /* 2 * Copyright (C) 2006 The Android Open Source Project 3 * Copyright (c) 2011-2013, The Linux Foundation. All rights reserved. 4 * Not a Contribution. 5 * 6 * Licensed under the Apache License, Version 2.0 (the "License"); 7 * you may not use this file except in compliance with the License. 8 * You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, software 13 * distributed under the License is distributed on an "AS IS" BASIS, 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 * See the License for the specific language governing permissions and 16 * limitations under the License. 17 */ 18 19 package com.android.internal.telephony; 20 21 import static android.Manifest.permission.MODIFY_PHONE_STATE; 22 import static android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE; 23 24 import android.annotation.NonNull; 25 import android.annotation.Nullable; 26 import android.app.AppOpsManager; 27 import android.compat.annotation.UnsupportedAppUsage; 28 import android.content.Context; 29 import android.content.pm.PackageManager; 30 import android.net.Uri; 31 import android.os.Binder; 32 import android.os.Build; 33 import android.os.RemoteException; 34 import android.os.TelephonyServiceManager.ServiceRegisterer; 35 import android.telephony.ImsiEncryptionInfo; 36 import android.telephony.PhoneNumberUtils; 37 import android.telephony.SubscriptionManager; 38 import android.telephony.TelephonyFrameworkInitializer; 39 import android.text.TextUtils; 40 import android.util.EventLog; 41 42 import com.android.internal.telephony.subscription.SubscriptionInfoInternal; 43 import com.android.internal.telephony.subscription.SubscriptionManagerService; 44 import com.android.internal.telephony.uicc.IsimRecords; 45 import com.android.internal.telephony.uicc.SIMRecords; 46 import com.android.internal.telephony.uicc.UiccCardApplication; 47 import com.android.internal.telephony.uicc.UiccPort; 48 import com.android.telephony.Rlog; 49 50 import java.util.ArrayList; 51 import java.util.List; 52 53 public class PhoneSubInfoController extends IPhoneSubInfo.Stub { 54 private static final String TAG = "PhoneSubInfoController"; 55 private static final boolean DBG = true; 56 private static final boolean VDBG = false; // STOPSHIP if true 57 58 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 59 private final Context mContext; 60 private AppOpsManager mAppOps; 61 PhoneSubInfoController(Context context)62 public PhoneSubInfoController(Context context) { 63 ServiceRegisterer phoneSubServiceRegisterer = TelephonyFrameworkInitializer 64 .getTelephonyServiceManager() 65 .getPhoneSubServiceRegisterer(); 66 if (phoneSubServiceRegisterer.get() == null) { 67 phoneSubServiceRegisterer.register(this); 68 } 69 mAppOps = context.getSystemService(AppOpsManager.class); 70 mContext = context; 71 } 72 73 @Deprecated getDeviceId(String callingPackage)74 public String getDeviceId(String callingPackage) { 75 return getDeviceIdWithFeature(callingPackage, null); 76 } 77 getDeviceIdWithFeature(String callingPackage, String callingFeatureId)78 public String getDeviceIdWithFeature(String callingPackage, String callingFeatureId) { 79 return getDeviceIdForPhone(SubscriptionManager.getPhoneId(getDefaultSubscription()), 80 callingPackage, callingFeatureId); 81 } 82 getDeviceIdForPhone(int phoneId, String callingPackage, String callingFeatureId)83 public String getDeviceIdForPhone(int phoneId, String callingPackage, 84 String callingFeatureId) { 85 enforceCallingPackageUidMatched(callingPackage); 86 return callPhoneMethodForPhoneIdWithReadDeviceIdentifiersCheck(phoneId, callingPackage, 87 callingFeatureId, "getDeviceId", (phone) -> phone.getDeviceId()); 88 } 89 getNaiForSubscriber(int subId, String callingPackage, String callingFeatureId)90 public String getNaiForSubscriber(int subId, String callingPackage, String callingFeatureId) { 91 return callPhoneMethodForSubIdWithReadSubscriberIdentifiersCheck(subId, callingPackage, 92 callingFeatureId, "getNai", (phone)-> phone.getNai()); 93 } 94 getImeiForSubscriber(int subId, String callingPackage, String callingFeatureId)95 public String getImeiForSubscriber(int subId, String callingPackage, 96 String callingFeatureId) { 97 return callPhoneMethodForSubIdWithReadDeviceIdentifiersCheck(subId, callingPackage, 98 callingFeatureId, "getImei", (phone) -> phone.getImei()); 99 } 100 getCarrierInfoForImsiEncryption(int subId, int keyType, String callingPackage)101 public ImsiEncryptionInfo getCarrierInfoForImsiEncryption(int subId, int keyType, 102 String callingPackage) { 103 return callPhoneMethodForSubIdWithPrivilegedCheck(subId, 104 "getCarrierInfoForImsiEncryption", 105 (phone)-> phone.getCarrierInfoForImsiEncryption(keyType, true)); 106 } 107 setCarrierInfoForImsiEncryption(int subId, String callingPackage, ImsiEncryptionInfo imsiEncryptionInfo)108 public void setCarrierInfoForImsiEncryption(int subId, String callingPackage, 109 ImsiEncryptionInfo imsiEncryptionInfo) { 110 callPhoneMethodForSubIdWithModifyCheck(subId, callingPackage, 111 "setCarrierInfoForImsiEncryption", 112 (phone)-> { 113 phone.setCarrierInfoForImsiEncryption(imsiEncryptionInfo); 114 return null; 115 }); 116 } 117 118 /** 119 * Resets the Carrier Keys in the database. This involves 2 steps: 120 * 1. Delete the keys from the database. 121 * 2. Send an intent to download new Certificates. 122 * @param subId 123 * @param callingPackage 124 */ resetCarrierKeysForImsiEncryption(int subId, String callingPackage)125 public void resetCarrierKeysForImsiEncryption(int subId, String callingPackage) { 126 callPhoneMethodForSubIdWithModifyCheck(subId, callingPackage, 127 "resetCarrierKeysForImsiEncryption", 128 (phone)-> { 129 phone.resetCarrierKeysForImsiEncryption(); 130 return null; 131 }); 132 } 133 getDeviceSvn(String callingPackage, String callingFeatureId)134 public String getDeviceSvn(String callingPackage, String callingFeatureId) { 135 return getDeviceSvnUsingSubId(getDefaultSubscription(), callingPackage, callingFeatureId); 136 } 137 getDeviceSvnUsingSubId(int subId, String callingPackage, String callingFeatureId)138 public String getDeviceSvnUsingSubId(int subId, String callingPackage, 139 String callingFeatureId) { 140 return callPhoneMethodForSubIdWithReadCheck(subId, callingPackage, callingFeatureId, 141 "getDeviceSvn", (phone)-> phone.getDeviceSvn()); 142 } 143 144 @Deprecated getSubscriberId(String callingPackage)145 public String getSubscriberId(String callingPackage) { 146 return getSubscriberIdWithFeature(callingPackage, null); 147 } 148 getSubscriberIdWithFeature(String callingPackage, String callingFeatureId)149 public String getSubscriberIdWithFeature(String callingPackage, String callingFeatureId) { 150 return getSubscriberIdForSubscriber(getDefaultSubscription(), callingPackage, 151 callingFeatureId); 152 } 153 getSubscriberIdForSubscriber(int subId, String callingPackage, String callingFeatureId)154 public String getSubscriberIdForSubscriber(int subId, String callingPackage, 155 String callingFeatureId) { 156 String message = "getSubscriberIdForSubscriber"; 157 mAppOps.checkPackage(Binder.getCallingUid(), callingPackage); 158 159 long identity = Binder.clearCallingIdentity(); 160 boolean isActive; 161 try { 162 isActive = SubscriptionManagerService.getInstance().isActiveSubId(subId, 163 callingPackage, callingFeatureId); 164 } finally { 165 Binder.restoreCallingIdentity(identity); 166 } 167 if (isActive) { 168 return callPhoneMethodForSubIdWithReadSubscriberIdentifiersCheck(subId, callingPackage, 169 callingFeatureId, message, (phone) -> phone.getSubscriberId()); 170 } else { 171 if (!TelephonyPermissions.checkCallingOrSelfReadSubscriberIdentifiers( 172 mContext, subId, callingPackage, callingFeatureId, message)) { 173 return null; 174 } 175 identity = Binder.clearCallingIdentity(); 176 try { 177 SubscriptionInfoInternal subInfo = SubscriptionManagerService.getInstance() 178 .getSubscriptionInfoInternal(subId); 179 if (subInfo != null && !TextUtils.isEmpty(subInfo.getImsi())) { 180 return subInfo.getImsi(); 181 } 182 return null; 183 } finally { 184 Binder.restoreCallingIdentity(identity); 185 } 186 } 187 } 188 189 @Deprecated getIccSerialNumber(String callingPackage)190 public String getIccSerialNumber(String callingPackage) { 191 return getIccSerialNumberWithFeature(callingPackage, null); 192 } 193 194 /** 195 * Retrieves the serial number of the ICC, if applicable. 196 */ getIccSerialNumberWithFeature(String callingPackage, String callingFeatureId)197 public String getIccSerialNumberWithFeature(String callingPackage, String callingFeatureId) { 198 return getIccSerialNumberForSubscriber(getDefaultSubscription(), callingPackage, 199 callingFeatureId); 200 } 201 getIccSerialNumberForSubscriber(int subId, String callingPackage, String callingFeatureId)202 public String getIccSerialNumberForSubscriber(int subId, String callingPackage, 203 String callingFeatureId) { 204 return callPhoneMethodForSubIdWithReadSubscriberIdentifiersCheck(subId, callingPackage, 205 callingFeatureId, "getIccSerialNumber", (phone) -> phone.getIccSerialNumber()); 206 } 207 getLine1Number(String callingPackage, String callingFeatureId)208 public String getLine1Number(String callingPackage, String callingFeatureId) { 209 return getLine1NumberForSubscriber(getDefaultSubscription(), callingPackage, 210 callingFeatureId); 211 } 212 213 // In R and beyond, READ_PHONE_NUMBERS includes READ_PHONE_NUMBERS and READ_SMS only. 214 // Prior to R, it also included READ_PHONE_STATE. Maintain that for compatibility. getLine1NumberForSubscriber(int subId, String callingPackage, String callingFeatureId)215 public String getLine1NumberForSubscriber(int subId, String callingPackage, 216 String callingFeatureId) { 217 return callPhoneMethodForSubIdWithReadPhoneNumberCheck( 218 subId, callingPackage, callingFeatureId, "getLine1Number", 219 (phone)-> phone.getLine1Number()); 220 } 221 getLine1AlphaTag(String callingPackage, String callingFeatureId)222 public String getLine1AlphaTag(String callingPackage, String callingFeatureId) { 223 return getLine1AlphaTagForSubscriber(getDefaultSubscription(), callingPackage, 224 callingFeatureId); 225 } 226 getLine1AlphaTagForSubscriber(int subId, String callingPackage, String callingFeatureId)227 public String getLine1AlphaTagForSubscriber(int subId, String callingPackage, 228 String callingFeatureId) { 229 return callPhoneMethodForSubIdWithReadCheck(subId, callingPackage, callingFeatureId, 230 "getLine1AlphaTag", (phone)-> phone.getLine1AlphaTag()); 231 } 232 getMsisdn(String callingPackage, String callingFeatureId)233 public String getMsisdn(String callingPackage, String callingFeatureId) { 234 return getMsisdnForSubscriber(getDefaultSubscription(), callingPackage, callingFeatureId); 235 } 236 237 // In R and beyond this will require READ_PHONE_NUMBERS. 238 // Prior to R it needed READ_PHONE_STATE. Maintain that for compatibility. getMsisdnForSubscriber(int subId, String callingPackage, String callingFeatureId)239 public String getMsisdnForSubscriber(int subId, String callingPackage, 240 String callingFeatureId) { 241 return callPhoneMethodForSubIdWithReadPhoneNumberCheck( 242 subId, callingPackage, callingFeatureId, "getMsisdn", (phone)-> phone.getMsisdn()); 243 } 244 getVoiceMailNumber(String callingPackage, String callingFeatureId)245 public String getVoiceMailNumber(String callingPackage, String callingFeatureId) { 246 return getVoiceMailNumberForSubscriber(getDefaultSubscription(), callingPackage, 247 callingFeatureId); 248 } 249 getVoiceMailNumberForSubscriber(int subId, String callingPackage, String callingFeatureId)250 public String getVoiceMailNumberForSubscriber(int subId, String callingPackage, 251 String callingFeatureId) { 252 return callPhoneMethodForSubIdWithReadCheck(subId, callingPackage, callingFeatureId, 253 "getVoiceMailNumber", (phone)-> { 254 String number = PhoneNumberUtils.extractNetworkPortion( 255 phone.getVoiceMailNumber()); 256 if (VDBG) log("VM: getVoiceMailNUmber: " + number); 257 return number; 258 }); 259 } 260 getVoiceMailAlphaTag(String callingPackage, String callingFeatureId)261 public String getVoiceMailAlphaTag(String callingPackage, String callingFeatureId) { 262 return getVoiceMailAlphaTagForSubscriber(getDefaultSubscription(), callingPackage, 263 callingFeatureId); 264 } 265 getVoiceMailAlphaTagForSubscriber(int subId, String callingPackage, String callingFeatureId)266 public String getVoiceMailAlphaTagForSubscriber(int subId, String callingPackage, 267 String callingFeatureId) { 268 return callPhoneMethodForSubIdWithReadCheck(subId, callingPackage, callingFeatureId, 269 "getVoiceMailAlphaTag", (phone)-> phone.getVoiceMailAlphaTag()); 270 } 271 272 /** 273 * get Phone object based on subId. 274 **/ 275 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) getPhone(int subId)276 private Phone getPhone(int subId) { 277 int phoneId = SubscriptionManager.getPhoneId(subId); 278 if (!SubscriptionManager.isValidPhoneId(phoneId)) { 279 return null; 280 } 281 return PhoneFactory.getPhone(phoneId); 282 } 283 enforceCallingPackageUidMatched(String callingPackage)284 private void enforceCallingPackageUidMatched(String callingPackage) { 285 try { 286 mAppOps.checkPackage(Binder.getCallingUid(), callingPackage); 287 } catch (SecurityException se) { 288 EventLog.writeEvent(0x534e4554, "188677422", Binder.getCallingUid()); 289 throw se; 290 } 291 } 292 enforceIccSimChallengeResponsePermission(Context context, int subId, String callingPackage, String callingFeatureId, String message)293 private boolean enforceIccSimChallengeResponsePermission(Context context, int subId, 294 String callingPackage, String callingFeatureId, String message) { 295 if (TelephonyPermissions.checkCallingOrSelfUseIccAuthWithDeviceIdentifier(context, 296 callingPackage, callingFeatureId, message)) { 297 return true; 298 } 299 if (VDBG) log("No USE_ICC_AUTH_WITH_DEVICE_IDENTIFIER permission."); 300 enforcePrivilegedPermissionOrCarrierPrivilege(subId, message); 301 return true; 302 } 303 304 /** 305 * Make sure caller has either read privileged phone permission or carrier privilege. 306 * 307 * @throws SecurityException if the caller does not have the required permission/privilege 308 */ enforcePrivilegedPermissionOrCarrierPrivilege(int subId, String message)309 private void enforcePrivilegedPermissionOrCarrierPrivilege(int subId, String message) { 310 // TODO(b/73660190): Migrate to 311 // TelephonyPermissions.enforceCallingOrSelfModifyPermissionOrCarrierPrivileges and delete 312 // this helper method. 313 int permissionResult = mContext.checkCallingOrSelfPermission( 314 READ_PRIVILEGED_PHONE_STATE); 315 if (permissionResult == PackageManager.PERMISSION_GRANTED) { 316 return; 317 } 318 if (VDBG) log("No read privileged phone permission, check carrier privilege next."); 319 TelephonyPermissions.enforceCallingOrSelfCarrierPrivilege(mContext, subId, message); 320 } 321 322 /** 323 * Make sure caller has modify phone state permission. 324 */ enforceModifyPermission()325 private void enforceModifyPermission() { 326 mContext.enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, 327 "Requires MODIFY_PHONE_STATE"); 328 } 329 330 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) getDefaultSubscription()331 private int getDefaultSubscription() { 332 return PhoneFactory.getDefaultSubscription(); 333 } 334 335 /** 336 * get the Isim Impi based on subId 337 */ getIsimImpi(int subId)338 public String getIsimImpi(int subId) { 339 return callPhoneMethodForSubIdWithPrivilegedCheck(subId, "getIsimImpi", 340 (phone) -> { 341 IsimRecords isim = phone.getIsimRecords(); 342 if (isim != null) { 343 return isim.getIsimImpi(); 344 } else { 345 return null; 346 } 347 }); 348 } 349 350 /** 351 * Fetches the IMS private user identity (EF_IMPI) based on subscriptionId. 352 * 353 * @param subId subscriptionId 354 * @return IMPI (IMS private user identity) of type string. 355 * @throws IllegalArgumentException if the subscriptionId is not valid 356 * @throws IllegalStateException in case the ISIM hasn’t been loaded. 357 * @throws SecurityException if the caller does not have the required permission 358 */ 359 public String getImsPrivateUserIdentity(int subId, String callingPackage, 360 String callingFeatureId) { 361 if (!SubscriptionManager.isValidSubscriptionId(subId)) { 362 throw new IllegalArgumentException("Invalid SubscriptionID = " + subId); 363 } 364 if (!TelephonyPermissions.checkCallingOrSelfUseIccAuthWithDeviceIdentifier(mContext, 365 callingPackage, callingFeatureId, "getImsPrivateUserIdentity")) { 366 throw (new SecurityException("No permissions to the caller")); 367 } 368 Phone phone = getPhone(subId); 369 assert phone != null; 370 IsimRecords isim = phone.getIsimRecords(); 371 if (isim != null) { 372 return isim.getIsimImpi(); 373 } else { 374 throw new IllegalStateException("ISIM is not loaded"); 375 } 376 } 377 378 /** 379 * get the Isim Domain based on subId 380 */ 381 public String getIsimDomain(int subId) { 382 return callPhoneMethodForSubIdWithPrivilegedCheck(subId, "getIsimDomain", 383 (phone) -> { 384 IsimRecords isim = phone.getIsimRecords(); 385 if (isim != null) { 386 return isim.getIsimDomain(); 387 } else { 388 return null; 389 } 390 }); 391 } 392 393 /** 394 * get the Isim Impu based on subId 395 */ 396 public String[] getIsimImpu(int subId) { 397 return callPhoneMethodForSubIdWithPrivilegedCheck(subId, "getIsimImpu", 398 (phone) -> { 399 IsimRecords isim = phone.getIsimRecords(); 400 if (isim != null) { 401 return isim.getIsimImpu(); 402 } else { 403 return null; 404 } 405 }); 406 } 407 408 /** 409 * Fetches the ISIM public user identities (EF_IMPU) from UICC based on subId 410 * 411 * @param subId subscriptionId 412 * @param callingPackage package name of the caller 413 * @param callingFeatureId feature Id of the caller 414 * @return List of public user identities of type android.net.Uri or empty list if 415 * EF_IMPU is not available. 416 * @throws IllegalArgumentException if the subscriptionId is not valid 417 * @throws IllegalStateException in case the ISIM hasn’t been loaded. 418 * @throws SecurityException if the caller does not have the required permission 419 */ 420 public List<Uri> getImsPublicUserIdentities(int subId, String callingPackage, 421 String callingFeatureId) { 422 if (TelephonyPermissions. 423 checkCallingOrSelfReadPrivilegedPhoneStatePermissionOrReadPhoneNumber( 424 mContext, subId, callingPackage, callingFeatureId, "getImsPublicUserIdentities")) { 425 Phone phone = getPhone(subId); 426 assert phone != null; 427 IsimRecords isimRecords = phone.getIsimRecords(); 428 if (isimRecords != null) { 429 String[] impus = isimRecords.getIsimImpu(); 430 List<Uri> impuList = new ArrayList<>(); 431 for (String impu : impus) { 432 if (impu != null && impu.trim().length() > 0) { 433 impuList.add(Uri.parse(impu)); 434 } 435 } 436 return impuList; 437 } 438 throw new IllegalStateException("ISIM is not loaded"); 439 } else { 440 throw new IllegalArgumentException("Invalid SubscriptionID = " + subId); 441 } 442 } 443 444 /** 445 * get the Isim Ist based on subId 446 */ 447 public String getIsimIst(int subId) throws RemoteException { 448 return callPhoneMethodForSubIdWithPrivilegedCheck(subId, "getIsimIst", 449 (phone) -> { 450 IsimRecords isim = phone.getIsimRecords(); 451 if (isim != null) { 452 return isim.getIsimIst(); 453 } else { 454 return null; 455 } 456 }); 457 } 458 459 /** 460 * get the Isim Pcscf based on subId 461 */ 462 public String[] getIsimPcscf(int subId) throws RemoteException { 463 return callPhoneMethodForSubIdWithPrivilegedCheck(subId, "getIsimPcscf", 464 (phone) -> { 465 IsimRecords isim = phone.getIsimRecords(); 466 if (isim != null) { 467 return isim.getIsimPcscf(); 468 } else { 469 return null; 470 } 471 }); 472 } 473 474 /** 475 * Returns the USIM service table that fetched from EFUST elementary field that are loaded 476 * based on the appType. 477 */ 478 public String getSimServiceTable(int subId, int appType) throws RemoteException { 479 return callPhoneMethodForSubIdWithPrivilegedCheck(subId, "getSimServiceTable", 480 (phone) -> { 481 UiccPort uiccPort = phone.getUiccPort(); 482 if (uiccPort == null || uiccPort.getUiccProfile() == null) { 483 loge("getSimServiceTable(): uiccPort or uiccProfile is null"); 484 return null; 485 } 486 UiccCardApplication uiccApp = uiccPort.getUiccProfile().getApplicationByType( 487 appType); 488 if (uiccApp == null) { 489 loge("getSimServiceTable(): no app with specified apptype=" 490 + appType); 491 return null; 492 } 493 return ((SIMRecords)uiccApp.getIccRecords()).getSimServiceTable(); 494 }); 495 } 496 497 @Override 498 public String getIccSimChallengeResponse(int subId, int appType, int authType, String data, 499 String callingPackage, String callingFeatureId) throws RemoteException { 500 CallPhoneMethodHelper<String> toExecute = (phone)-> { 501 UiccPort uiccPort = phone.getUiccPort(); 502 if (uiccPort == null) { 503 loge("getIccSimChallengeResponse() uiccPort is null"); 504 return null; 505 } 506 507 UiccCardApplication uiccApp = uiccPort.getApplicationByType(appType); 508 if (uiccApp == null) { 509 loge("getIccSimChallengeResponse() no app with specified type -- " + appType); 510 return null; 511 } else { 512 loge("getIccSimChallengeResponse() found app " + uiccApp.getAid() 513 + " specified type -- " + appType); 514 } 515 516 if (authType != UiccCardApplication.AUTH_CONTEXT_EAP_SIM 517 && authType != UiccCardApplication.AUTH_CONTEXT_EAP_AKA 518 && authType != UiccCardApplication.AUTH_CONTEXT_GBA_BOOTSTRAP 519 && authType != UiccCardApplication.AUTHTYPE_GBA_NAF_KEY_EXTERNAL) { 520 loge("getIccSimChallengeResponse() unsupported authType: " + authType); 521 return null; 522 } 523 return uiccApp.getIccRecords().getIccSimChallengeResponse(authType, data); 524 }; 525 526 return callPhoneMethodWithPermissionCheck(subId, callingPackage, callingFeatureId, 527 "getIccSimChallengeResponse", toExecute, 528 this::enforceIccSimChallengeResponsePermission); 529 } 530 531 public String getGroupIdLevel1ForSubscriber(int subId, String callingPackage, 532 String callingFeatureId) { 533 return callPhoneMethodForSubIdWithReadCheck(subId, callingPackage, callingFeatureId, 534 "getGroupIdLevel1", (phone)-> phone.getGroupIdLevel1()); 535 } 536 537 /** Below are utility methods that abstracts the flow that many public methods use: 538 * 1. Check permission: pass, throw exception, or fails (returns false). 539 * 2. clearCallingIdentity. 540 * 3. Call a specified phone method and get return value. 541 * 4. restoreCallingIdentity and return. 542 */ 543 private interface CallPhoneMethodHelper<T> { 544 T callMethod(Phone phone); 545 } 546 547 private interface PermissionCheckHelper { 548 // Implemented to do whatever permission check it wants. 549 // If passes, it should return true. 550 // If permission is not granted, throws SecurityException. 551 // If permission is revoked by AppOps, return false. 552 boolean checkPermission(Context context, int subId, String callingPackage, 553 @Nullable String callingFeatureId, String message); 554 } 555 556 // Base utility method that others use. 557 private <T> T callPhoneMethodWithPermissionCheck(int subId, String callingPackage, 558 @Nullable String callingFeatureId, String message, 559 CallPhoneMethodHelper<T> callMethodHelper, 560 PermissionCheckHelper permissionCheckHelper) { 561 if (!permissionCheckHelper.checkPermission(mContext, subId, callingPackage, 562 callingFeatureId, message)) { 563 return null; 564 } 565 566 final long identity = Binder.clearCallingIdentity(); 567 try { 568 Phone phone = getPhone(subId); 569 if (phone != null) { 570 return callMethodHelper.callMethod(phone); 571 } else { 572 if (VDBG) loge(message + " phone is null for Subscription:" + subId); 573 return null; 574 } 575 } finally { 576 Binder.restoreCallingIdentity(identity); 577 } 578 } 579 580 private <T> T callPhoneMethodForSubIdWithReadCheck(int subId, String callingPackage, 581 @Nullable String callingFeatureId, String message, 582 CallPhoneMethodHelper<T> callMethodHelper) { 583 return callPhoneMethodWithPermissionCheck(subId, callingPackage, callingFeatureId, 584 message, callMethodHelper, 585 (aContext, aSubId, aCallingPackage, aCallingFeatureId, aMessage)-> 586 TelephonyPermissions.checkCallingOrSelfReadPhoneState( 587 aContext, aSubId, aCallingPackage, aCallingFeatureId, aMessage)); 588 } 589 590 private <T> T callPhoneMethodForSubIdWithReadDeviceIdentifiersCheck(int subId, 591 String callingPackage, @Nullable String callingFeatureId, String message, 592 CallPhoneMethodHelper<T> callMethodHelper) { 593 return callPhoneMethodWithPermissionCheck(subId, callingPackage, callingFeatureId, 594 message, callMethodHelper, 595 (aContext, aSubId, aCallingPackage, aCallingFeatureId, aMessage)-> 596 TelephonyPermissions.checkCallingOrSelfReadDeviceIdentifiers( 597 aContext, aSubId, aCallingPackage, aCallingFeatureId, aMessage)); 598 } 599 600 private <T> T callPhoneMethodForSubIdWithReadSubscriberIdentifiersCheck(int subId, 601 String callingPackage, @Nullable String callingFeatureId, String message, 602 CallPhoneMethodHelper<T> callMethodHelper) { 603 return callPhoneMethodWithPermissionCheck(subId, callingPackage, callingFeatureId, 604 message, callMethodHelper, 605 (aContext, aSubId, aCallingPackage, aCallingFeatureId, aMessage)-> 606 TelephonyPermissions.checkCallingOrSelfReadSubscriberIdentifiers( 607 aContext, aSubId, aCallingPackage, aCallingFeatureId, aMessage)); 608 } 609 610 private <T> T callPhoneMethodForSubIdWithPrivilegedCheck( 611 int subId, String message, CallPhoneMethodHelper<T> callMethodHelper) { 612 return callPhoneMethodWithPermissionCheck(subId, null, null, message, callMethodHelper, 613 (aContext, aSubId, aCallingPackage, aCallingFeatureId, aMessage) -> { 614 mContext.enforceCallingOrSelfPermission(READ_PRIVILEGED_PHONE_STATE, message); 615 return true; 616 }); 617 } 618 619 private <T> T callPhoneMethodForSubIdWithModifyCheck(int subId, String callingPackage, 620 String message, CallPhoneMethodHelper<T> callMethodHelper) { 621 return callPhoneMethodWithPermissionCheck(subId, null, null, message, callMethodHelper, 622 (aContext, aSubId, aCallingPackage, aCallingFeatureId, aMessage)-> { 623 enforceModifyPermission(); 624 return true; 625 }); 626 } 627 628 private <T> T callPhoneMethodForSubIdWithReadPhoneNumberCheck(int subId, String callingPackage, 629 @NonNull String callingFeatureId, String message, 630 CallPhoneMethodHelper<T> callMethodHelper) { 631 return callPhoneMethodWithPermissionCheck(subId, callingPackage, callingFeatureId, 632 message, callMethodHelper, 633 (aContext, aSubId, aCallingPackage, aCallingFeatureId, aMessage) -> 634 TelephonyPermissions.checkCallingOrSelfReadPhoneNumber( 635 aContext, aSubId, aCallingPackage, aCallingFeatureId, aMessage)); 636 } 637 638 private <T> T callPhoneMethodForPhoneIdWithReadDeviceIdentifiersCheck(int phoneId, 639 String callingPackage, @Nullable String callingFeatureId, String message, 640 CallPhoneMethodHelper<T> callMethodHelper) { 641 // Getting subId before doing permission check. 642 if (!SubscriptionManager.isValidPhoneId(phoneId)) { 643 phoneId = 0; 644 } 645 final Phone phone = PhoneFactory.getPhone(phoneId); 646 if (phone == null) { 647 return null; 648 } 649 if (!TelephonyPermissions.checkCallingOrSelfReadDeviceIdentifiers(mContext, 650 phone.getSubId(), callingPackage, callingFeatureId, message)) { 651 return null; 652 } 653 654 final long identity = Binder.clearCallingIdentity(); 655 try { 656 return callMethodHelper.callMethod(phone); 657 } finally { 658 Binder.restoreCallingIdentity(identity); 659 } 660 } 661 662 /** 663 * Returns SIP URI or tel URI of the Public Service Identity of the SM-SC fetched from 664 * EF_PSISMSC elementary field as defined in Section 4.5.9 (3GPP TS 31.102). 665 * @throws IllegalStateException in case if phone or UiccApplication is not available. 666 */ 667 public Uri getSmscIdentity(int subId, int appType) throws RemoteException { 668 Uri smscIdentityUri = callPhoneMethodForSubIdWithPrivilegedCheck(subId, "getSmscIdentity", 669 (phone) -> { 670 try { 671 String smscIdentity = null; 672 UiccPort uiccPort = phone.getUiccPort(); 673 UiccCardApplication uiccApp = 674 uiccPort.getUiccProfile().getApplicationByType( 675 appType); 676 smscIdentity = (uiccApp != null) ? uiccApp.getIccRecords().getSmscIdentity() 677 : null; 678 if (TextUtils.isEmpty(smscIdentity)) { 679 return Uri.EMPTY; 680 } 681 return Uri.parse(smscIdentity); 682 } catch (NullPointerException ex) { 683 Rlog.e(TAG, "getSmscIdentity(): Exception = " + ex); 684 return null; 685 } 686 }); 687 if (smscIdentityUri == null) { 688 throw new IllegalStateException("Telephony service error"); 689 } 690 return smscIdentityUri; 691 } 692 693 private void log(String s) { 694 Rlog.d(TAG, s); 695 } 696 697 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 698 private void loge(String s) { 699 Rlog.e(TAG, s); 700 } 701 } 702