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