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