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