PhoneSubInfo.java revision 4e286c0da881ea725221aa6d5d4feec891e338f0
1/* 2 * Copyright (C) 2007 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16package com.android.internal.telephony; 17 18import java.io.FileDescriptor; 19import java.io.PrintWriter; 20 21import android.app.AppOpsManager; 22import android.content.Context; 23import android.content.pm.PackageManager; 24import android.os.Binder; 25import android.telephony.PhoneNumberUtils; 26import android.telephony.Rlog; 27 28import com.android.internal.telephony.uicc.IsimRecords; 29import com.android.internal.telephony.uicc.UiccCard; 30import com.android.internal.telephony.uicc.UiccCardApplication; 31 32public class PhoneSubInfo { 33 static final String LOG_TAG = "PhoneSubInfo"; 34 private static final boolean DBG = true; 35 private static final boolean VDBG = false; // STOPSHIP if true 36 37 private Phone mPhone; 38 private Context mContext; 39 private AppOpsManager mAppOps; 40 private static final String READ_PHONE_STATE = 41 android.Manifest.permission.READ_PHONE_STATE; 42 // TODO: change getCompleteVoiceMailNumber() to require READ_PRIVILEGED_PHONE_STATE 43 private static final String CALL_PRIVILEGED = 44 android.Manifest.permission.CALL_PRIVILEGED; 45 private static final String READ_PRIVILEGED_PHONE_STATE = 46 android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE; 47 48 public PhoneSubInfo(Phone phone) { 49 mPhone = phone; 50 mContext = phone.getContext(); 51 mAppOps = mContext.getSystemService(AppOpsManager.class); 52 } 53 54 public void dispose() { 55 } 56 57 @Override 58 protected void finalize() { 59 try { 60 super.finalize(); 61 } catch (Throwable throwable) { 62 loge("Error while finalizing:", throwable); 63 } 64 if (DBG) log("PhoneSubInfo finalized"); 65 } 66 67 /** 68 * Retrieves the unique device ID, e.g., IMEI for GSM phones and MEID for CDMA phones. 69 */ 70 public String getDeviceId(String callingPackage) { 71 if (!checkReadPhoneState(callingPackage, "getDeviceId")) { 72 return null; 73 } 74 return mPhone.getDeviceId(); 75 } 76 77 /** 78 * Retrieves the IMEI. 79 */ 80 public String getImei(String callingPackage) { 81 if (!checkReadPhoneState(callingPackage, "getImei")) { 82 return null; 83 } 84 return mPhone.getImei(); 85 } 86 87 /** 88 * Retrieves the NAI. 89 */ 90 public String getNai(String callingPackage) { 91 if (!checkReadPhoneState(callingPackage, "getNai")) { 92 return null; 93 } 94 return mPhone.getNai(); 95 } 96 97 /** 98 * Retrieves the software version number for the device, e.g., IMEI/SV 99 * for GSM phones. 100 */ 101 public String getDeviceSvn(String callingPackage) { 102 if (!checkReadPhoneState(callingPackage, "getDeviceSvn")) { 103 return null; 104 } 105 106 return mPhone.getDeviceSvn(); 107 } 108 109 /** 110 * Retrieves the unique subscriber ID, e.g., IMSI for GSM phones. 111 */ 112 public String getSubscriberId(String callingPackage) { 113 if (!checkReadPhoneState(callingPackage, "getSubscriberId")) { 114 return null; 115 } 116 return mPhone.getSubscriberId(); 117 } 118 119 /** 120 * Retrieves the Group Identifier Level1 for GSM phones. 121 */ 122 public String getGroupIdLevel1(String callingPackage) { 123 if (!checkReadPhoneState(callingPackage, "getGroupIdLevel1")) { 124 return null; 125 } 126 return mPhone.getGroupIdLevel1(); 127 } 128 129 /** 130 * Retrieves the serial number of the ICC, if applicable. 131 */ 132 public String getIccSerialNumber(String callingPackage) { 133 if (!checkReadPhoneState(callingPackage, "getIccSerialNumber")) { 134 return null; 135 } 136 return mPhone.getIccSerialNumber(); 137 } 138 139 /** 140 * Retrieves the phone number string for line 1. 141 */ 142 public String getLine1Number(String callingPackage) { 143 if (!checkReadPhoneState(callingPackage, "getLine1Number")) { 144 return null; 145 } 146 return mPhone.getLine1Number(); 147 } 148 149 /** 150 * Retrieves the alpha identifier for line 1. 151 */ 152 public String getLine1AlphaTag(String callingPackage) { 153 if (!checkReadPhoneState(callingPackage, "getLine1AlphaTag")) { 154 return null; 155 } 156 return mPhone.getLine1AlphaTag(); 157 } 158 159 /** 160 * Retrieves the MSISDN string. 161 */ 162 public String getMsisdn(String callingPackage) { 163 if (!checkReadPhoneState(callingPackage, "getMsisdn")) { 164 return null; 165 } 166 return mPhone.getMsisdn(); 167 } 168 169 /** 170 * Retrieves the voice mail number. 171 */ 172 public String getVoiceMailNumber(String callingPackage) { 173 if (!checkReadPhoneState(callingPackage, "getVoiceMailNumber")) { 174 return null; 175 } 176 String number = PhoneNumberUtils.extractNetworkPortion(mPhone.getVoiceMailNumber()); 177 if (VDBG) log("VM: PhoneSubInfo.getVoiceMailNUmber: " + number); 178 return number; 179 } 180 181 /** 182 * Retrieves the complete voice mail number. 183 * 184 * @hide 185 */ 186 public String getCompleteVoiceMailNumber() { 187 mContext.enforceCallingOrSelfPermission(CALL_PRIVILEGED, 188 "Requires CALL_PRIVILEGED"); 189 String number = mPhone.getVoiceMailNumber(); 190 if (VDBG) log("VM: PhoneSubInfo.getCompleteVoiceMailNUmber: " + number); 191 return number; 192 } 193 194 /** 195 * Retrieves the alpha identifier associated with the voice mail number. 196 */ 197 public String getVoiceMailAlphaTag(String callingPackage) { 198 if (!checkReadPhoneState(callingPackage, "getVoiceMailAlphaTag")) { 199 return null; 200 } 201 return mPhone.getVoiceMailAlphaTag(); 202 } 203 204 /** 205 * Returns the IMS private user identity (IMPI) that was loaded from the ISIM. 206 * @return the IMPI, or null if not present or not loaded 207 */ 208 public String getIsimImpi() { 209 mContext.enforceCallingOrSelfPermission(READ_PRIVILEGED_PHONE_STATE, 210 "Requires READ_PRIVILEGED_PHONE_STATE"); 211 IsimRecords isim = mPhone.getIsimRecords(); 212 if (isim != null) { 213 return isim.getIsimImpi(); 214 } else { 215 return null; 216 } 217 } 218 219 /** 220 * Returns the IMS home network domain name that was loaded from the ISIM. 221 * @return the IMS domain name, or null if not present or not loaded 222 */ 223 public String getIsimDomain() { 224 mContext.enforceCallingOrSelfPermission(READ_PRIVILEGED_PHONE_STATE, 225 "Requires READ_PRIVILEGED_PHONE_STATE"); 226 IsimRecords isim = mPhone.getIsimRecords(); 227 if (isim != null) { 228 return isim.getIsimDomain(); 229 } else { 230 return null; 231 } 232 } 233 234 /** 235 * Returns the IMS public user identities (IMPU) that were loaded from the ISIM. 236 * @return an array of IMPU strings, with one IMPU per string, or null if 237 * not present or not loaded 238 */ 239 public String[] getIsimImpu() { 240 mContext.enforceCallingOrSelfPermission(READ_PRIVILEGED_PHONE_STATE, 241 "Requires READ_PRIVILEGED_PHONE_STATE"); 242 IsimRecords isim = mPhone.getIsimRecords(); 243 if (isim != null) { 244 return isim.getIsimImpu(); 245 } else { 246 return null; 247 } 248 } 249 250 /** 251 * Returns the IMS Service Table (IST) that was loaded from the ISIM. 252 * @return IMS Service Table or null if not present or not loaded 253 */ 254 public String getIsimIst(){ 255 mContext.enforceCallingOrSelfPermission(READ_PRIVILEGED_PHONE_STATE, 256 "Requires READ_PRIVILEGED_PHONE_STATE"); 257 IsimRecords isim = mPhone.getIsimRecords(); 258 if (isim != null) { 259 return isim.getIsimIst(); 260 } else { 261 return null; 262 } 263 } 264 265 /** 266 * Returns the IMS Proxy Call Session Control Function(PCSCF) that were loaded from the ISIM. 267 * @return an array of PCSCF strings with one PCSCF per string, or null if 268 * not present or not loaded 269 */ 270 public String[] getIsimPcscf() { 271 mContext.enforceCallingOrSelfPermission(READ_PRIVILEGED_PHONE_STATE, 272 "Requires READ_PRIVILEGED_PHONE_STATE"); 273 IsimRecords isim = mPhone.getIsimRecords(); 274 if (isim != null) { 275 return isim.getIsimPcscf(); 276 } else { 277 return null; 278 } 279 } 280 281 /** 282 * Returns the response of ISIM Authetification through RIL. 283 * Returns null if the Authentification hasn't been successed or isn't present iphonesubinfo. 284 * @return the response of ISIM Authetification, or null if not available 285 */ 286 public String getIsimChallengeResponse(String nonce){ 287 mContext.enforceCallingOrSelfPermission(READ_PRIVILEGED_PHONE_STATE, 288 "Requires READ_PRIVILEGED_PHONE_STATE"); 289 IsimRecords isim = mPhone.getIsimRecords(); 290 if (isim != null) { 291 return isim.getIsimChallengeResponse(nonce); 292 } else { 293 return null; 294 } 295 } 296 297 /** 298 * Returns the response of the SIM application on the UICC to authentication 299 * challenge/response algorithm. The data string and challenge response are 300 * Base64 encoded Strings. 301 * Can support EAP-SIM, EAP-AKA with results encoded per 3GPP TS 31.102. 302 * 303 * @param appType ICC application family (@see com.android.internal.telephony.PhoneConstants#APPTYPE_xxx) 304 * @param data authentication challenge data 305 * @return challenge response 306 */ 307 public String getIccSimChallengeResponse(int subId, int appType, String data) { 308 // FIXME: use subId!! 309 mContext.enforceCallingOrSelfPermission(READ_PRIVILEGED_PHONE_STATE, 310 "Requires READ_PRIVILEGED_PHONE_STATE"); 311 312 UiccCard uiccCard = mPhone.getUiccCard(); 313 if (uiccCard == null) { 314 Rlog.e(LOG_TAG, "getIccSimChallengeResponse() UiccCard is null"); 315 return null; 316 } 317 318 UiccCardApplication uiccApp = uiccCard.getApplicationByType(appType); 319 if (uiccApp == null) { 320 Rlog.e(LOG_TAG, "getIccSimChallengeResponse() no app with specified type -- " + 321 appType); 322 return null; 323 } else { 324 Rlog.e(LOG_TAG, "getIccSimChallengeResponse() found app " + uiccApp.getAid() 325 + "specified type -- " + appType); 326 } 327 328 int authContext = uiccApp.getAuthContext(); 329 330 if (data.length() < 32) { 331 /* must use EAP_SIM context */ 332 Rlog.e(LOG_TAG, "data is too small to use EAP_AKA, using EAP_SIM instead"); 333 authContext = UiccCardApplication.AUTH_CONTEXT_EAP_SIM; 334 } 335 336 if(authContext == UiccCardApplication.AUTH_CONTEXT_UNDEFINED) { 337 Rlog.e(LOG_TAG, "getIccSimChallengeResponse() authContext undefined for app type " + 338 appType); 339 return null; 340 } 341 342 return uiccApp.getIccRecords().getIccSimChallengeResponse(authContext, data); 343 } 344 345 private void log(String s) { 346 Rlog.d(LOG_TAG, s); 347 } 348 349 private void loge(String s, Throwable e) { 350 Rlog.e(LOG_TAG, s, e); 351 } 352 353 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 354 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) 355 != PackageManager.PERMISSION_GRANTED) { 356 pw.println("Permission Denial: can't dump PhoneSubInfo from from pid=" 357 + Binder.getCallingPid() 358 + ", uid=" + Binder.getCallingUid()); 359 return; 360 } 361 362 pw.println("Phone Subscriber Info:"); 363 pw.println(" Phone Type = " + mPhone.getPhoneName()); 364 pw.println(" Device ID = " + mPhone.getDeviceId()); 365 } 366 367 private boolean checkReadPhoneState(String callingPackage, String message) { 368 try { 369 mContext.enforceCallingOrSelfPermission( 370 android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, message); 371 372 // SKIP checking run-time OP_READ_PHONE_STATE since self or using PRIVILEGED 373 return true; 374 } catch (SecurityException e) { 375 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.READ_PHONE_STATE, 376 message); 377 } 378 379 return mAppOps.noteOp(AppOpsManager.OP_READ_PHONE_STATE, Binder.getCallingUid(), 380 callingPackage) == AppOpsManager.MODE_ALLOWED; 381 } 382} 383