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 19package com.android.internal.telephony; 20 21import android.app.AppOpsManager; 22import android.content.Context; 23import android.content.pm.PackageManager; 24import android.os.Binder; 25import android.os.RemoteException; 26import android.os.ServiceManager; 27import android.telephony.PhoneNumberUtils; 28import android.telephony.SubscriptionManager; 29import android.telephony.Rlog; 30 31import com.android.internal.telephony.uicc.IsimRecords; 32import com.android.internal.telephony.uicc.UiccCard; 33import com.android.internal.telephony.uicc.UiccCardApplication; 34 35import static android.Manifest.permission.CALL_PRIVILEGED; 36import static android.Manifest.permission.READ_PHONE_NUMBERS; 37import static android.Manifest.permission.READ_PHONE_STATE; 38import static android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE; 39import static android.Manifest.permission.READ_SMS; 40import static android.telephony.TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS; 41 42public class PhoneSubInfoController extends IPhoneSubInfo.Stub { 43 private static final String TAG = "PhoneSubInfoController"; 44 private static final boolean DBG = true; 45 private static final boolean VDBG = false; // STOPSHIP if true 46 47 private final Phone[] mPhone; 48 private final Context mContext; 49 private final AppOpsManager mAppOps; 50 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 60 public String getDeviceId(String callingPackage) { 61 return getDeviceIdForPhone(SubscriptionManager.getPhoneId(getDefaultSubscription()), 62 callingPackage); 63 } 64 65 public String getDeviceIdForPhone(int phoneId, String callingPackage) { 66 if (!checkReadPhoneState(callingPackage, "getDeviceId")) { 67 return null; 68 } 69 if (!SubscriptionManager.isValidPhoneId(phoneId)) { 70 phoneId = 0; 71 } 72 final Phone phone = mPhone[phoneId]; 73 if (phone != null) { 74 return phone.getDeviceId(); 75 } else { 76 loge("getDeviceIdForPhone phone " + phoneId + " is null"); 77 return null; 78 } 79 } 80 81 public String getNaiForSubscriber(int subId, String callingPackage) { 82 Phone phone = getPhone(subId); 83 if (phone != null) { 84 if (!checkReadPhoneState(callingPackage, "getNai")) { 85 return null; 86 } 87 return phone.getNai(); 88 } else { 89 loge("getNai phone is null for Subscription:" + subId); 90 return null; 91 } 92 } 93 94 public String getImeiForSubscriber(int subId, String callingPackage) { 95 Phone phone = getPhone(subId); 96 if (phone != null) { 97 if (!checkReadPhoneState(callingPackage, "getImei")) { 98 return null; 99 } 100 return phone.getImei(); 101 } else { 102 loge("getDeviceId phone is null for Subscription:" + subId); 103 return null; 104 } 105 } 106 107 public String getDeviceSvn(String callingPackage) { 108 return getDeviceSvnUsingSubId(getDefaultSubscription(), callingPackage); 109 } 110 111 public String getDeviceSvnUsingSubId(int subId, String callingPackage) { 112 Phone phone = getPhone(subId); 113 if (phone != null) { 114 if (!checkReadPhoneState(callingPackage, "getDeviceSvn")) { 115 return null; 116 } 117 return phone.getDeviceSvn(); 118 } else { 119 loge("getDeviceSvn phone is null"); 120 return null; 121 } 122 } 123 124 public String getSubscriberId(String callingPackage) { 125 return getSubscriberIdForSubscriber(getDefaultSubscription(), callingPackage); 126 } 127 128 public String getSubscriberIdForSubscriber(int subId, String callingPackage) { 129 Phone phone = getPhone(subId); 130 if (phone != null) { 131 if (!checkReadPhoneState(callingPackage, "getSubscriberId")) { 132 return null; 133 } 134 return phone.getSubscriberId(); 135 } else { 136 loge("getSubscriberId phone is null for Subscription:" + subId); 137 return null; 138 } 139 } 140 141 /** 142 * Retrieves the serial number of the ICC, if applicable. 143 */ 144 public String getIccSerialNumber(String callingPackage) { 145 return getIccSerialNumberForSubscriber(getDefaultSubscription(), callingPackage); 146 } 147 148 public String getIccSerialNumberForSubscriber(int subId, String callingPackage) { 149 Phone phone = getPhone(subId); 150 if (phone != null) { 151 if (!checkReadPhoneState(callingPackage, "getIccSerialNumber")) { 152 return null; 153 } 154 return phone.getIccSerialNumber(); 155 } else { 156 loge("getIccSerialNumber phone is null for Subscription:" + subId); 157 return null; 158 } 159 } 160 161 public String getLine1Number(String callingPackage) { 162 return getLine1NumberForSubscriber(getDefaultSubscription(), callingPackage); 163 } 164 165 public String getLine1NumberForSubscriber(int subId, String callingPackage) { 166 Phone phone = getPhone(subId); 167 if (phone != null) { 168 // This is open to apps with WRITE_SMS. 169 if (!checkReadPhoneNumber(callingPackage, "getLine1Number")) { 170 return null; 171 } 172 return phone.getLine1Number(); 173 } else { 174 loge("getLine1Number phone is null for Subscription:" + subId); 175 return null; 176 } 177 } 178 179 public String getLine1AlphaTag(String callingPackage) { 180 return getLine1AlphaTagForSubscriber(getDefaultSubscription(), callingPackage); 181 } 182 183 public String getLine1AlphaTagForSubscriber(int subId, String callingPackage) { 184 Phone phone = getPhone(subId); 185 if (phone != null) { 186 if (!checkReadPhoneState(callingPackage, "getLine1AlphaTag")) { 187 return null; 188 } 189 return phone.getLine1AlphaTag(); 190 } else { 191 loge("getLine1AlphaTag phone is null for Subscription:" + subId); 192 return null; 193 } 194 } 195 196 public String getMsisdn(String callingPackage) { 197 return getMsisdnForSubscriber(getDefaultSubscription(), callingPackage); 198 } 199 200 public String getMsisdnForSubscriber(int subId, String callingPackage) { 201 Phone phone = getPhone(subId); 202 if (phone != null) { 203 if (!checkReadPhoneState(callingPackage, "getMsisdn")) { 204 return null; 205 } 206 return phone.getMsisdn(); 207 } else { 208 loge("getMsisdn phone is null for Subscription:" + subId); 209 return null; 210 } 211 } 212 213 public String getVoiceMailNumber(String callingPackage) { 214 return getVoiceMailNumberForSubscriber(getDefaultSubscription(), callingPackage); 215 } 216 217 public String getVoiceMailNumberForSubscriber(int subId, String callingPackage) { 218 Phone phone = getPhone(subId); 219 if (phone != null) { 220 if (!checkReadPhoneState(callingPackage, "getVoiceMailNumber")) { 221 return null; 222 } 223 String number = PhoneNumberUtils.extractNetworkPortion(phone.getVoiceMailNumber()); 224 if (VDBG) log("VM: getVoiceMailNUmber: " + number); 225 return number; 226 } else { 227 loge("getVoiceMailNumber phone is null for Subscription:" + subId); 228 return null; 229 } 230 } 231 232 // TODO: change getCompleteVoiceMailNumber() to require READ_PRIVILEGED_PHONE_STATE 233 public String getCompleteVoiceMailNumber() { 234 return getCompleteVoiceMailNumberForSubscriber(getDefaultSubscription()); 235 } 236 237 public String getCompleteVoiceMailNumberForSubscriber(int subId) { 238 Phone phone = getPhone(subId); 239 if (phone != null) { 240 mContext.enforceCallingOrSelfPermission(CALL_PRIVILEGED, "Requires CALL_PRIVILEGED"); 241 String number = phone.getVoiceMailNumber(); 242 if (VDBG) log("VM: getCompleteVoiceMailNUmber: " + number); 243 return number; 244 } else { 245 loge("getCompleteVoiceMailNumber phone is null for Subscription:" + subId); 246 return null; 247 } 248 } 249 250 public String getVoiceMailAlphaTag(String callingPackage) { 251 return getVoiceMailAlphaTagForSubscriber(getDefaultSubscription(), callingPackage); 252 } 253 254 public String getVoiceMailAlphaTagForSubscriber(int subId, String callingPackage) { 255 Phone phone = getPhone(subId); 256 if (phone != null) { 257 if (!checkReadPhoneState(callingPackage, "getVoiceMailAlphaTag")) { 258 return null; 259 } 260 return phone.getVoiceMailAlphaTag(); 261 } else { 262 loge("getVoiceMailAlphaTag phone is null for Subscription:" + subId); 263 return null; 264 } 265 } 266 267 /** 268 * get Phone object based on subId. 269 **/ 270 private Phone getPhone(int subId) { 271 int phoneId = SubscriptionManager.getPhoneId(subId); 272 if (!SubscriptionManager.isValidPhoneId(phoneId)) { 273 phoneId = 0; 274 } 275 return mPhone[phoneId]; 276 } 277 278 /** 279 * Make sure caller has either read privileged phone permission or carrier privilege. 280 * 281 * @throws SecurityException if the caller does not have the required permission/privilege 282 */ 283 private void enforcePrivilegedPermissionOrCarrierPrivilege(Phone phone) { 284 int permissionResult = mContext.checkCallingOrSelfPermission( 285 READ_PRIVILEGED_PHONE_STATE); 286 if (permissionResult == PackageManager.PERMISSION_GRANTED) { 287 return; 288 } 289 log("No read privileged phone permission, check carrier privilege next."); 290 UiccCard uiccCard = phone.getUiccCard(); 291 if (uiccCard == null) { 292 throw new SecurityException("No Carrier Privilege: No UICC"); 293 } 294 if (uiccCard.getCarrierPrivilegeStatusForCurrentTransaction( 295 mContext.getPackageManager()) != CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) { 296 throw new SecurityException("No Carrier Privilege."); 297 } 298 } 299 300 private int getDefaultSubscription() { 301 return PhoneFactory.getDefaultSubscription(); 302 } 303 304 305 public String getIsimImpi() { 306 Phone phone = getPhone(getDefaultSubscription()); 307 mContext.enforceCallingOrSelfPermission(READ_PRIVILEGED_PHONE_STATE, 308 "Requires READ_PRIVILEGED_PHONE_STATE"); 309 IsimRecords isim = phone.getIsimRecords(); 310 if (isim != null) { 311 return isim.getIsimImpi(); 312 } else { 313 return null; 314 } 315 } 316 317 public String getIsimDomain() { 318 Phone phone = getPhone(getDefaultSubscription()); 319 mContext.enforceCallingOrSelfPermission(READ_PRIVILEGED_PHONE_STATE, 320 "Requires READ_PRIVILEGED_PHONE_STATE"); 321 IsimRecords isim = phone.getIsimRecords(); 322 if (isim != null) { 323 return isim.getIsimDomain(); 324 } else { 325 return null; 326 } 327 } 328 329 public String[] getIsimImpu() { 330 Phone phone = getPhone(getDefaultSubscription()); 331 mContext.enforceCallingOrSelfPermission(READ_PRIVILEGED_PHONE_STATE, 332 "Requires READ_PRIVILEGED_PHONE_STATE"); 333 IsimRecords isim = phone.getIsimRecords(); 334 if (isim != null) { 335 return isim.getIsimImpu(); 336 } else { 337 return null; 338 } 339 } 340 341 public String getIsimIst() throws RemoteException { 342 Phone phone = getPhone(getDefaultSubscription()); 343 mContext.enforceCallingOrSelfPermission(READ_PRIVILEGED_PHONE_STATE, 344 "Requires READ_PRIVILEGED_PHONE_STATE"); 345 IsimRecords isim = phone.getIsimRecords(); 346 if (isim != null) { 347 return isim.getIsimIst(); 348 } else { 349 return null; 350 } 351 } 352 353 public String[] getIsimPcscf() throws RemoteException { 354 Phone phone = getPhone(getDefaultSubscription()); 355 mContext.enforceCallingOrSelfPermission(READ_PRIVILEGED_PHONE_STATE, 356 "Requires READ_PRIVILEGED_PHONE_STATE"); 357 IsimRecords isim = phone.getIsimRecords(); 358 if (isim != null) { 359 return isim.getIsimPcscf(); 360 } else { 361 return null; 362 } 363 } 364 365 public String getIsimChallengeResponse(String nonce) throws RemoteException { 366 Phone phone = getPhone(getDefaultSubscription()); 367 mContext.enforceCallingOrSelfPermission(READ_PRIVILEGED_PHONE_STATE, 368 "Requires READ_PRIVILEGED_PHONE_STATE"); 369 IsimRecords isim = phone.getIsimRecords(); 370 if (isim != null) { 371 return isim.getIsimChallengeResponse(nonce); 372 } else { 373 return null; 374 } 375 } 376 377 public String getIccSimChallengeResponse(int subId, int appType, int authType, String data) 378 throws RemoteException { 379 Phone phone = getPhone(subId); 380 enforcePrivilegedPermissionOrCarrierPrivilege(phone); 381 UiccCard uiccCard = phone.getUiccCard(); 382 if (uiccCard == null) { 383 loge("getIccSimChallengeResponse() UiccCard is null"); 384 return null; 385 } 386 387 UiccCardApplication uiccApp = uiccCard.getApplicationByType(appType); 388 if (uiccApp == null) { 389 loge("getIccSimChallengeResponse() no app with specified type -- " + 390 appType); 391 return null; 392 } else { 393 loge("getIccSimChallengeResponse() found app " + uiccApp.getAid() 394 + " specified type -- " + appType); 395 } 396 397 if(authType != UiccCardApplication.AUTH_CONTEXT_EAP_SIM && 398 authType != UiccCardApplication.AUTH_CONTEXT_EAP_AKA) { 399 loge("getIccSimChallengeResponse() unsupported authType: " + authType); 400 return null; 401 } 402 403 return uiccApp.getIccRecords().getIccSimChallengeResponse(authType, data); 404 } 405 406 public String getGroupIdLevel1(String callingPackage) { 407 return getGroupIdLevel1ForSubscriber(getDefaultSubscription(), callingPackage); 408 } 409 410 public String getGroupIdLevel1ForSubscriber(int subId, String callingPackage) { 411 Phone phone = getPhone(subId); 412 if (phone != null) { 413 if (!checkReadPhoneState(callingPackage, "getGroupIdLevel1")) { 414 return null; 415 } 416 return phone.getGroupIdLevel1(); 417 } else { 418 loge("getGroupIdLevel1 phone is null for Subscription:" + subId); 419 return null; 420 } 421 } 422 423 private boolean checkReadPhoneState(String callingPackage, String message) { 424 try { 425 mContext.enforceCallingOrSelfPermission(READ_PRIVILEGED_PHONE_STATE, message); 426 427 // SKIP checking run-time OP_READ_PHONE_STATE since self or using PRIVILEGED 428 return true; 429 } catch (SecurityException e) { 430 mContext.enforceCallingOrSelfPermission(READ_PHONE_STATE, message); 431 } 432 433 return mAppOps.noteOp(AppOpsManager.OP_READ_PHONE_STATE, Binder.getCallingUid(), 434 callingPackage) == AppOpsManager.MODE_ALLOWED; 435 } 436 437 /** 438 * Besides READ_PHONE_STATE, READ_PHONE_NUMBERS, WRITE_SMS and READ_SMS also allow apps to get 439 * phone numbers. 440 */ 441 private boolean checkReadPhoneNumber(String callingPackage, String message) { 442 // Default SMS app can always read it. 443 if (mAppOps.noteOp(AppOpsManager.OP_WRITE_SMS, 444 Binder.getCallingUid(), callingPackage) == AppOpsManager.MODE_ALLOWED) { 445 return true; 446 } 447 try { 448 return checkReadPhoneState(callingPackage, message); 449 } catch (SecurityException readPhoneStateSecurityException) { 450 } 451 try { 452 // Can be read with READ_SMS too. 453 mContext.enforceCallingOrSelfPermission(READ_SMS, message); 454 int opCode = mAppOps.permissionToOpCode(READ_SMS); 455 if (opCode != AppOpsManager.OP_NONE) { 456 return mAppOps.noteOp(opCode, Binder.getCallingUid(), callingPackage) 457 == AppOpsManager.MODE_ALLOWED; 458 } else { 459 return true; 460 } 461 } catch (SecurityException readSmsSecurityException) { 462 } 463 try { 464 // Can be read with READ_PHONE_NUMBERS too. 465 mContext.enforceCallingOrSelfPermission(READ_PHONE_NUMBERS, message); 466 int opCode = mAppOps.permissionToOpCode(READ_PHONE_NUMBERS); 467 if (opCode != AppOpsManager.OP_NONE) { 468 return mAppOps.noteOp(opCode, Binder.getCallingUid(), callingPackage) 469 == AppOpsManager.MODE_ALLOWED; 470 } else { 471 return true; 472 } 473 } catch (SecurityException readPhoneNumberSecurityException) { 474 } 475 // Throw exception with message including READ_PHONE_STATE, READ_SMS, and READ_PHONE_NUMBERS 476 // permissions 477 throw new SecurityException(message + ": Neither user " + Binder.getCallingUid() + 478 " nor current process has " + READ_PHONE_STATE + ", " + 479 READ_SMS + ", or " + READ_PHONE_STATE + "."); 480 } 481 482 private void log(String s) { 483 Rlog.d(TAG, s); 484 } 485 486 private void loge(String s) { 487 Rlog.e(TAG, s); 488 } 489} 490