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.UnsupportedAppUsage; 25 import android.app.AppOpsManager; 26 import android.content.Context; 27 import android.content.pm.PackageManager; 28 import android.os.Binder; 29 import android.os.RemoteException; 30 import android.os.ServiceManager; 31 import android.telephony.ImsiEncryptionInfo; 32 import android.telephony.PhoneNumberUtils; 33 import android.telephony.Rlog; 34 import android.telephony.SubscriptionManager; 35 36 import com.android.internal.telephony.uicc.IsimRecords; 37 import com.android.internal.telephony.uicc.UiccCard; 38 import com.android.internal.telephony.uicc.UiccCardApplication; 39 40 public class PhoneSubInfoController extends IPhoneSubInfo.Stub { 41 private static final String TAG = "PhoneSubInfoController"; 42 private static final boolean DBG = true; 43 private static final boolean VDBG = false; // STOPSHIP if true 44 45 @UnsupportedAppUsage 46 private final Phone[] mPhone; 47 @UnsupportedAppUsage 48 private final Context mContext; 49 private final AppOpsManager mAppOps; 50 PhoneSubInfoController(Context context, Phone[] phone)51 public PhoneSubInfoController(Context context, Phone[] phone) { 52 mPhone = phone; 53 if (ServiceManager.getService("iphonesubinfo") == null) { 54 ServiceManager.addService("iphonesubinfo", this); 55 } 56 mContext = context; 57 mAppOps = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE); 58 } 59 getDeviceId(String callingPackage)60 public String getDeviceId(String callingPackage) { 61 return getDeviceIdForPhone(SubscriptionManager.getPhoneId(getDefaultSubscription()), 62 callingPackage); 63 } 64 getDeviceIdForPhone(int phoneId, String callingPackage)65 public String getDeviceIdForPhone(int phoneId, String callingPackage) { 66 return callPhoneMethodForPhoneIdWithReadDeviceIdentifiersCheck(phoneId, callingPackage, 67 "getDeviceId", (phone)-> phone.getDeviceId()); 68 } 69 getNaiForSubscriber(int subId, String callingPackage)70 public String getNaiForSubscriber(int subId, String callingPackage) { 71 return callPhoneMethodForSubIdWithReadCheck(subId, callingPackage, "getNai", 72 (phone)-> phone.getNai()); 73 } 74 getImeiForSubscriber(int subId, String callingPackage)75 public String getImeiForSubscriber(int subId, String callingPackage) { 76 return callPhoneMethodForSubIdWithReadDeviceIdentifiersCheck(subId, callingPackage, 77 "getImei", (phone)-> phone.getImei()); 78 } 79 getCarrierInfoForImsiEncryption(int subId, int keyType, String callingPackage)80 public ImsiEncryptionInfo getCarrierInfoForImsiEncryption(int subId, int keyType, 81 String callingPackage) { 82 return callPhoneMethodForSubIdWithReadCheck(subId, callingPackage, 83 "getCarrierInfoForImsiEncryption", 84 (phone)-> phone.getCarrierInfoForImsiEncryption(keyType)); 85 } 86 setCarrierInfoForImsiEncryption(int subId, String callingPackage, ImsiEncryptionInfo imsiEncryptionInfo)87 public void setCarrierInfoForImsiEncryption(int subId, String callingPackage, 88 ImsiEncryptionInfo imsiEncryptionInfo) { 89 callPhoneMethodForSubIdWithModifyCheck(subId, callingPackage, 90 "setCarrierInfoForImsiEncryption", 91 (phone)-> { 92 phone.setCarrierInfoForImsiEncryption(imsiEncryptionInfo); 93 return null; 94 }); 95 } 96 97 /** 98 * Resets the Carrier Keys in the database. This involves 2 steps: 99 * 1. Delete the keys from the database. 100 * 2. Send an intent to download new Certificates. 101 * @param subId 102 * @param callingPackage 103 */ resetCarrierKeysForImsiEncryption(int subId, String callingPackage)104 public void resetCarrierKeysForImsiEncryption(int subId, String callingPackage) { 105 callPhoneMethodForSubIdWithModifyCheck(subId, callingPackage, 106 "setCarrierInfoForImsiEncryption", 107 (phone)-> { 108 phone.resetCarrierKeysForImsiEncryption(); 109 return null; 110 }); 111 } 112 113 getDeviceSvn(String callingPackage)114 public String getDeviceSvn(String callingPackage) { 115 return getDeviceSvnUsingSubId(getDefaultSubscription(), callingPackage); 116 } 117 getDeviceSvnUsingSubId(int subId, String callingPackage)118 public String getDeviceSvnUsingSubId(int subId, String callingPackage) { 119 return callPhoneMethodForSubIdWithReadCheck(subId, callingPackage, "getDeviceSvn", 120 (phone)-> phone.getDeviceSvn()); 121 } 122 getSubscriberId(String callingPackage)123 public String getSubscriberId(String callingPackage) { 124 return getSubscriberIdForSubscriber(getDefaultSubscription(), callingPackage); 125 } 126 getSubscriberIdForSubscriber(int subId, String callingPackage)127 public String getSubscriberIdForSubscriber(int subId, String callingPackage) { 128 String message = "getSubscriberId"; 129 long identity = Binder.clearCallingIdentity(); 130 boolean isActive; 131 try { 132 isActive = SubscriptionController.getInstance().isActiveSubId(subId, callingPackage); 133 } finally { 134 Binder.restoreCallingIdentity(identity); 135 } 136 if (isActive) { 137 return callPhoneMethodForSubIdWithReadSubscriberIdentifiersCheck(subId, callingPackage, 138 message, (phone) -> phone.getSubscriberId()); 139 } else { 140 if (!TelephonyPermissions.checkCallingOrSelfReadSubscriberIdentifiers( 141 mContext, subId, callingPackage, message)) { 142 return null; 143 } 144 identity = Binder.clearCallingIdentity(); 145 try { 146 return SubscriptionController.getInstance().getImsiPrivileged(subId); 147 } finally { 148 Binder.restoreCallingIdentity(identity); 149 } 150 } 151 } 152 153 /** 154 * Retrieves the serial number of the ICC, if applicable. 155 */ getIccSerialNumber(String callingPackage)156 public String getIccSerialNumber(String callingPackage) { 157 return getIccSerialNumberForSubscriber(getDefaultSubscription(), callingPackage); 158 } 159 getIccSerialNumberForSubscriber(int subId, String callingPackage)160 public String getIccSerialNumberForSubscriber(int subId, String callingPackage) { 161 return callPhoneMethodForSubIdWithReadSubscriberIdentifiersCheck(subId, callingPackage, 162 "getIccSerialNumber", (phone) -> phone.getIccSerialNumber()); 163 } 164 getLine1Number(String callingPackage)165 public String getLine1Number(String callingPackage) { 166 return getLine1NumberForSubscriber(getDefaultSubscription(), callingPackage); 167 } 168 getLine1NumberForSubscriber(int subId, String callingPackage)169 public String getLine1NumberForSubscriber(int subId, String callingPackage) { 170 return callPhoneMethodForSubIdWithReadPhoneNumberCheck( 171 subId, callingPackage, "getLine1Number", 172 (phone)-> phone.getLine1Number()); 173 } 174 getLine1AlphaTag(String callingPackage)175 public String getLine1AlphaTag(String callingPackage) { 176 return getLine1AlphaTagForSubscriber(getDefaultSubscription(), callingPackage); 177 } 178 getLine1AlphaTagForSubscriber(int subId, String callingPackage)179 public String getLine1AlphaTagForSubscriber(int subId, String callingPackage) { 180 return callPhoneMethodForSubIdWithReadCheck(subId, callingPackage, "getLine1AlphaTag", 181 (phone)-> phone.getLine1AlphaTag()); 182 } 183 getMsisdn(String callingPackage)184 public String getMsisdn(String callingPackage) { 185 return getMsisdnForSubscriber(getDefaultSubscription(), callingPackage); 186 } 187 getMsisdnForSubscriber(int subId, String callingPackage)188 public String getMsisdnForSubscriber(int subId, String callingPackage) { 189 return callPhoneMethodForSubIdWithReadCheck(subId, callingPackage, "getMsisdn", 190 (phone)-> phone.getMsisdn()); 191 } 192 getVoiceMailNumber(String callingPackage)193 public String getVoiceMailNumber(String callingPackage) { 194 return getVoiceMailNumberForSubscriber(getDefaultSubscription(), callingPackage); 195 } 196 getVoiceMailNumberForSubscriber(int subId, String callingPackage)197 public String getVoiceMailNumberForSubscriber(int subId, String callingPackage) { 198 return callPhoneMethodForSubIdWithReadCheck(subId, callingPackage, 199 "getVoiceMailNumber", (phone)-> { 200 String number = PhoneNumberUtils.extractNetworkPortion( 201 phone.getVoiceMailNumber()); 202 if (VDBG) log("VM: getVoiceMailNUmber: " + number); 203 return number; 204 }); 205 } 206 getVoiceMailAlphaTag(String callingPackage)207 public String getVoiceMailAlphaTag(String callingPackage) { 208 return getVoiceMailAlphaTagForSubscriber(getDefaultSubscription(), callingPackage); 209 } 210 getVoiceMailAlphaTagForSubscriber(int subId, String callingPackage)211 public String getVoiceMailAlphaTagForSubscriber(int subId, String callingPackage) { 212 return callPhoneMethodForSubIdWithReadCheck(subId, callingPackage, 213 "getVoiceMailAlphaTag", (phone)-> phone.getVoiceMailAlphaTag()); 214 } 215 216 /** 217 * get Phone object based on subId. 218 **/ 219 @UnsupportedAppUsage getPhone(int subId)220 private Phone getPhone(int subId) { 221 int phoneId = SubscriptionManager.getPhoneId(subId); 222 if (!SubscriptionManager.isValidPhoneId(phoneId)) { 223 phoneId = 0; 224 } 225 return mPhone[phoneId]; 226 } 227 228 /** 229 * Make sure caller has either read privileged phone permission or carrier privilege. 230 * 231 * @throws SecurityException if the caller does not have the required permission/privilege 232 */ enforcePrivilegedPermissionOrCarrierPrivilege(int subId, String message)233 private void enforcePrivilegedPermissionOrCarrierPrivilege(int subId, String message) { 234 // TODO(b/73660190): Migrate to 235 // TelephonyPermissions.enforceCallingOrSelfModifyPermissionOrCarrierPrivileges and delete 236 // this helper method. 237 int permissionResult = mContext.checkCallingOrSelfPermission( 238 READ_PRIVILEGED_PHONE_STATE); 239 if (permissionResult == PackageManager.PERMISSION_GRANTED) { 240 return; 241 } 242 if (VDBG) log("No read privileged phone permission, check carrier privilege next."); 243 TelephonyPermissions.enforceCallingOrSelfCarrierPrivilege(subId, message); 244 } 245 246 /** 247 * Make sure caller has modify phone state permission. 248 */ enforceModifyPermission()249 private void enforceModifyPermission() { 250 mContext.enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, 251 "Requires MODIFY_PHONE_STATE"); 252 } 253 254 @UnsupportedAppUsage getDefaultSubscription()255 private int getDefaultSubscription() { 256 return PhoneFactory.getDefaultSubscription(); 257 } 258 259 /** 260 * get the Isim Impi based on subId 261 */ getIsimImpi(int subId)262 public String getIsimImpi(int subId) { 263 return callPhoneMethodForSubIdWithPrivilegedCheck(subId, "getIsimImpi", 264 (phone) -> { 265 IsimRecords isim = phone.getIsimRecords(); 266 if (isim != null) { 267 return isim.getIsimImpi(); 268 } else { 269 return null; 270 } 271 }); 272 } 273 274 /** 275 * get the Isim Domain based on subId 276 */ 277 public String getIsimDomain(int subId) { 278 return callPhoneMethodForSubIdWithPrivilegedCheck(subId, "getIsimDomain", 279 (phone) -> { 280 IsimRecords isim = phone.getIsimRecords(); 281 if (isim != null) { 282 return isim.getIsimDomain(); 283 } else { 284 return null; 285 } 286 }); 287 } 288 289 /** 290 * get the Isim Impu based on subId 291 */ 292 public String[] getIsimImpu(int subId) { 293 return callPhoneMethodForSubIdWithPrivilegedCheck(subId, "getIsimImpu", 294 (phone) -> { 295 IsimRecords isim = phone.getIsimRecords(); 296 if (isim != null) { 297 return isim.getIsimImpu(); 298 } else { 299 return null; 300 } 301 }); 302 } 303 304 /** 305 * get the Isim Ist based on subId 306 */ 307 public String getIsimIst(int subId) throws RemoteException { 308 return callPhoneMethodForSubIdWithPrivilegedCheck(subId, "getIsimIst", 309 (phone) -> { 310 IsimRecords isim = phone.getIsimRecords(); 311 if (isim != null) { 312 return isim.getIsimIst(); 313 } else { 314 return null; 315 } 316 }); 317 } 318 319 /** 320 * get the Isim Pcscf based on subId 321 */ 322 public String[] getIsimPcscf(int subId) throws RemoteException { 323 return callPhoneMethodForSubIdWithPrivilegedCheck(subId, "getIsimPcscf", 324 (phone) -> { 325 IsimRecords isim = phone.getIsimRecords(); 326 if (isim != null) { 327 return isim.getIsimPcscf(); 328 } else { 329 return null; 330 } 331 }); 332 } 333 334 public String getIccSimChallengeResponse(int subId, int appType, int authType, String data) 335 throws RemoteException { 336 CallPhoneMethodHelper<String> toExecute = (phone)-> { 337 UiccCard uiccCard = phone.getUiccCard(); 338 if (uiccCard == null) { 339 loge("getIccSimChallengeResponse() UiccCard is null"); 340 return null; 341 } 342 343 UiccCardApplication uiccApp = uiccCard.getApplicationByType(appType); 344 if (uiccApp == null) { 345 loge("getIccSimChallengeResponse() no app with specified type -- " + appType); 346 return null; 347 } else { 348 loge("getIccSimChallengeResponse() found app " + uiccApp.getAid() 349 + " specified type -- " + appType); 350 } 351 352 if (authType != UiccCardApplication.AUTH_CONTEXT_EAP_SIM 353 && authType != UiccCardApplication.AUTH_CONTEXT_EAP_AKA) { 354 loge("getIccSimChallengeResponse() unsupported authType: " + authType); 355 return null; 356 } 357 return uiccApp.getIccRecords().getIccSimChallengeResponse(authType, data); 358 }; 359 360 return callPhoneMethodWithPermissionCheck( 361 subId, null, "getIccSimChallengeResponse", toExecute, 362 (aContext, aSubId, aCallingPackage, aMessage)-> { 363 enforcePrivilegedPermissionOrCarrierPrivilege(aSubId, aMessage); 364 return true; 365 }); 366 } 367 368 public String getGroupIdLevel1ForSubscriber(int subId, String callingPackage) { 369 return callPhoneMethodForSubIdWithReadCheck(subId, callingPackage, 370 "getGroupIdLevel1", (phone)-> phone.getGroupIdLevel1()); 371 } 372 373 /** Below are utility methods that abstracts the flow that many public methods use: 374 * 1. Check permission: pass, throw exception, or fails (returns false). 375 * 2. clearCallingIdentity. 376 * 3. Call a specified phone method and get return value. 377 * 4. restoreCallingIdentity and return. 378 */ 379 private interface CallPhoneMethodHelper<T> { 380 T callMethod(Phone phone); 381 } 382 383 private interface PermissionCheckHelper { 384 // Implemented to do whatever permission check it wants. 385 // If passes, it should return true. 386 // If permission is not granted, throws SecurityException. 387 // If permission is revoked by AppOps, return false. 388 boolean checkPermission(Context context, int subId, String callingPackage, String message); 389 } 390 391 // Base utility method that others use. 392 private <T> T callPhoneMethodWithPermissionCheck(int subId, String callingPackage, 393 String message, CallPhoneMethodHelper<T> callMethodHelper, 394 PermissionCheckHelper permissionCheckHelper) { 395 if (!permissionCheckHelper.checkPermission(mContext, subId, callingPackage, message)) { 396 return null; 397 } 398 399 final long identity = Binder.clearCallingIdentity(); 400 try { 401 Phone phone = getPhone(subId); 402 if (phone != null) { 403 return callMethodHelper.callMethod(phone); 404 } else { 405 loge(message + " phone is null for Subscription:" + subId); 406 return null; 407 } 408 } finally { 409 Binder.restoreCallingIdentity(identity); 410 } 411 } 412 413 private <T> T callPhoneMethodForSubIdWithReadCheck(int subId, String callingPackage, 414 String message, CallPhoneMethodHelper<T> callMethodHelper) { 415 return callPhoneMethodWithPermissionCheck(subId, callingPackage, message, callMethodHelper, 416 (aContext, aSubId, aCallingPackage, aMessage)-> 417 TelephonyPermissions.checkCallingOrSelfReadPhoneState( 418 aContext, aSubId, aCallingPackage, aMessage)); 419 } 420 421 private <T> T callPhoneMethodForSubIdWithReadDeviceIdentifiersCheck(int subId, 422 String callingPackage, String message, CallPhoneMethodHelper<T> callMethodHelper) { 423 return callPhoneMethodWithPermissionCheck(subId, callingPackage, message, callMethodHelper, 424 (aContext, aSubId, aCallingPackage, aMessage)-> 425 TelephonyPermissions.checkCallingOrSelfReadDeviceIdentifiers( 426 aContext, aSubId, aCallingPackage, aMessage)); 427 } 428 429 private <T> T callPhoneMethodForSubIdWithReadSubscriberIdentifiersCheck(int subId, 430 String callingPackage, String message, CallPhoneMethodHelper<T> callMethodHelper) { 431 return callPhoneMethodWithPermissionCheck(subId, callingPackage, message, callMethodHelper, 432 (aContext, aSubId, aCallingPackage, aMessage)-> 433 TelephonyPermissions.checkCallingOrSelfReadSubscriberIdentifiers( 434 aContext, aSubId, aCallingPackage, aMessage)); 435 } 436 437 438 private <T> T callPhoneMethodForSubIdWithPrivilegedCheck( 439 int subId, String message, CallPhoneMethodHelper<T> callMethodHelper) { 440 return callPhoneMethodWithPermissionCheck(subId, null, message, callMethodHelper, 441 (aContext, aSubId, aCallingPackage, aMessage)-> { 442 mContext.enforceCallingOrSelfPermission(READ_PRIVILEGED_PHONE_STATE, message); 443 return true; 444 }); 445 } 446 447 private <T> T callPhoneMethodForSubIdWithModifyCheck(int subId, String callingPackage, 448 String message, CallPhoneMethodHelper<T> callMethodHelper) { 449 return callPhoneMethodWithPermissionCheck(subId, null, message, callMethodHelper, 450 (aContext, aSubId, aCallingPackage, aMessage)-> { 451 enforceModifyPermission(); 452 return true; 453 }); 454 } 455 456 private <T> T callPhoneMethodForSubIdWithReadPhoneNumberCheck(int subId, String callingPackage, 457 String message, CallPhoneMethodHelper<T> callMethodHelper) { 458 return callPhoneMethodWithPermissionCheck(subId, callingPackage, message, callMethodHelper, 459 (aContext, aSubId, aCallingPackage, aMessage)-> 460 TelephonyPermissions.checkCallingOrSelfReadPhoneNumber( 461 aContext, aSubId, aCallingPackage, aMessage)); 462 } 463 464 private <T> T callPhoneMethodForPhoneIdWithReadDeviceIdentifiersCheck(int phoneId, 465 String callingPackage, String message, CallPhoneMethodHelper<T> callMethodHelper) { 466 // Getting subId before doing permission check. 467 if (!SubscriptionManager.isValidPhoneId(phoneId)) { 468 phoneId = 0; 469 } 470 final Phone phone = mPhone[phoneId]; 471 if (phone == null) { 472 return null; 473 } 474 if (!TelephonyPermissions.checkCallingOrSelfReadDeviceIdentifiers(mContext, 475 phone.getSubId(), callingPackage, message)) { 476 return null; 477 } 478 479 final long identity = Binder.clearCallingIdentity(); 480 try { 481 return callMethodHelper.callMethod(phone); 482 } finally { 483 Binder.restoreCallingIdentity(identity); 484 } 485 } 486 487 private void log(String s) { 488 Rlog.d(TAG, s); 489 } 490 491 @UnsupportedAppUsage 492 private void loge(String s) { 493 Rlog.e(TAG, s); 494 } 495 } 496