PhoneSubInfo.java revision b507a182a281afc5d8c4d2f94a854a0333999fc6
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 if (!checkReadPhoneState(callingPackage, "Requires READ_PHONE_STATE")) { 155 return null; 156 } 157 return mPhone.getLine1AlphaTag(); 158 } 159 160 /** 161 * Retrieves the MSISDN string. 162 */ 163 public String getMsisdn(String callingPackage) { 164 if (!checkReadPhoneState(callingPackage, "Requires READ_PHONE_STATE")) { 165 return null; 166 } 167 return mPhone.getMsisdn(); 168 } 169 170 /** 171 * Retrieves the voice mail number. 172 */ 173 public String getVoiceMailNumber(String callingPackage) { 174 if (!checkReadPhoneState(callingPackage, "Requires READ_PHONE_STATE")) { 175 return null; 176 } 177 String number = PhoneNumberUtils.extractNetworkPortion(mPhone.getVoiceMailNumber()); 178 if (VDBG) log("VM: PhoneSubInfo.getVoiceMailNUmber: " + number); 179 return number; 180 } 181 182 /** 183 * Retrieves the complete voice mail number. 184 * 185 * @hide 186 */ 187 public String getCompleteVoiceMailNumber() { 188 mContext.enforceCallingOrSelfPermission(CALL_PRIVILEGED, 189 "Requires CALL_PRIVILEGED"); 190 String number = mPhone.getVoiceMailNumber(); 191 if (VDBG) log("VM: PhoneSubInfo.getCompleteVoiceMailNUmber: " + number); 192 return number; 193 } 194 195 /** 196 * Retrieves the alpha identifier associated with the voice mail number. 197 */ 198 public String getVoiceMailAlphaTag(String callingPackage) { 199 if (!checkReadPhoneState(callingPackage, "Requires READ_PHONE_STATE")) { 200 return null; 201 } 202 return mPhone.getVoiceMailAlphaTag(); 203 } 204 205 /** 206 * Returns the IMS private user identity (IMPI) that was loaded from the ISIM. 207 * @return the IMPI, or null if not present or not loaded 208 */ 209 public String getIsimImpi() { 210 mContext.enforceCallingOrSelfPermission(READ_PRIVILEGED_PHONE_STATE, 211 "Requires READ_PRIVILEGED_PHONE_STATE"); 212 IsimRecords isim = mPhone.getIsimRecords(); 213 if (isim != null) { 214 return isim.getIsimImpi(); 215 } else { 216 return null; 217 } 218 } 219 220 /** 221 * Returns the IMS home network domain name that was loaded from the ISIM. 222 * @return the IMS domain name, or null if not present or not loaded 223 */ 224 public String getIsimDomain() { 225 mContext.enforceCallingOrSelfPermission(READ_PRIVILEGED_PHONE_STATE, 226 "Requires READ_PRIVILEGED_PHONE_STATE"); 227 IsimRecords isim = mPhone.getIsimRecords(); 228 if (isim != null) { 229 return isim.getIsimDomain(); 230 } else { 231 return null; 232 } 233 } 234 235 /** 236 * Returns the IMS public user identities (IMPU) that were loaded from the ISIM. 237 * @return an array of IMPU strings, with one IMPU per string, or null if 238 * not present or not loaded 239 */ 240 public String[] getIsimImpu() { 241 mContext.enforceCallingOrSelfPermission(READ_PRIVILEGED_PHONE_STATE, 242 "Requires READ_PRIVILEGED_PHONE_STATE"); 243 IsimRecords isim = mPhone.getIsimRecords(); 244 if (isim != null) { 245 return isim.getIsimImpu(); 246 } else { 247 return null; 248 } 249 } 250 251 /** 252 * Returns the IMS Service Table (IST) that was loaded from the ISIM. 253 * @return IMS Service Table or null if not present or not loaded 254 */ 255 public String getIsimIst(){ 256 mContext.enforceCallingOrSelfPermission(READ_PRIVILEGED_PHONE_STATE, 257 "Requires READ_PRIVILEGED_PHONE_STATE"); 258 IsimRecords isim = mPhone.getIsimRecords(); 259 if (isim != null) { 260 return isim.getIsimIst(); 261 } else { 262 return null; 263 } 264 } 265 266 /** 267 * Returns the IMS Proxy Call Session Control Function(PCSCF) that were loaded from the ISIM. 268 * @return an array of PCSCF strings with one PCSCF per string, or null if 269 * not present or not loaded 270 */ 271 public String[] getIsimPcscf() { 272 mContext.enforceCallingOrSelfPermission(READ_PRIVILEGED_PHONE_STATE, 273 "Requires READ_PRIVILEGED_PHONE_STATE"); 274 IsimRecords isim = mPhone.getIsimRecords(); 275 if (isim != null) { 276 return isim.getIsimPcscf(); 277 } else { 278 return null; 279 } 280 } 281 282 /** 283 * Returns the response of ISIM Authetification through RIL. 284 * Returns null if the Authentification hasn't been successed or isn't present iphonesubinfo. 285 * @return the response of ISIM Authetification, or null if not available 286 */ 287 public String getIsimChallengeResponse(String nonce){ 288 mContext.enforceCallingOrSelfPermission(READ_PRIVILEGED_PHONE_STATE, 289 "Requires READ_PRIVILEGED_PHONE_STATE"); 290 IsimRecords isim = mPhone.getIsimRecords(); 291 if (isim != null) { 292 return isim.getIsimChallengeResponse(nonce); 293 } else { 294 return null; 295 } 296 } 297 298 /** 299 * Returns the response of the SIM application on the UICC to authentication 300 * challenge/response algorithm. The data string and challenge response are 301 * Base64 encoded Strings. 302 * Can support EAP-SIM, EAP-AKA with results encoded per 3GPP TS 31.102. 303 * 304 * @param appType ICC application family (@see com.android.internal.telephony.PhoneConstants#APPTYPE_xxx) 305 * @param data authentication challenge data 306 * @return challenge response 307 */ 308 public String getIccSimChallengeResponse(int subId, int appType, String data) { 309 // FIXME: use subId!! 310 mContext.enforceCallingOrSelfPermission(READ_PRIVILEGED_PHONE_STATE, 311 "Requires READ_PRIVILEGED_PHONE_STATE"); 312 313 UiccCard uiccCard = mPhone.getUiccCard(); 314 if (uiccCard == null) { 315 Rlog.e(LOG_TAG, "getIccSimChallengeResponse() UiccCard is null"); 316 return null; 317 } 318 319 UiccCardApplication uiccApp = uiccCard.getApplicationByType(appType); 320 if (uiccApp == null) { 321 Rlog.e(LOG_TAG, "getIccSimChallengeResponse() no app with specified type -- " + 322 appType); 323 return null; 324 } else { 325 Rlog.e(LOG_TAG, "getIccSimChallengeResponse() found app " + uiccApp.getAid() 326 + "specified type -- " + appType); 327 } 328 329 int authContext = uiccApp.getAuthContext(); 330 331 if (data.length() < 32) { 332 /* must use EAP_SIM context */ 333 Rlog.e(LOG_TAG, "data is too small to use EAP_AKA, using EAP_SIM instead"); 334 authContext = UiccCardApplication.AUTH_CONTEXT_EAP_SIM; 335 } 336 337 if(authContext == UiccCardApplication.AUTH_CONTEXT_UNDEFINED) { 338 Rlog.e(LOG_TAG, "getIccSimChallengeResponse() authContext undefined for app type " + 339 appType); 340 return null; 341 } 342 343 return uiccApp.getIccRecords().getIccSimChallengeResponse(authContext, data); 344 } 345 346 private void log(String s) { 347 Rlog.d(LOG_TAG, s); 348 } 349 350 private void loge(String s, Throwable e) { 351 Rlog.e(LOG_TAG, s, e); 352 } 353 354 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 355 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) 356 != PackageManager.PERMISSION_GRANTED) { 357 pw.println("Permission Denial: can't dump PhoneSubInfo from from pid=" 358 + Binder.getCallingPid() 359 + ", uid=" + Binder.getCallingUid()); 360 return; 361 } 362 363 pw.println("Phone Subscriber Info:"); 364 pw.println(" Phone Type = " + mPhone.getPhoneName()); 365 pw.println(" Device ID = " + mPhone.getDeviceId()); 366 } 367 368 private boolean checkReadPhoneState(String callingPackage, String message) { 369 mContext.enforceCallingOrSelfPermission( 370 android.Manifest.permission.READ_PHONE_STATE, message); 371 372 return true; 373 // TODO b/21726452 enforce OP_READ_PHONE_STATE once 374 // PhoneInterfaceManager.getMergedSubscriberIds got fixed 375 // return mAppOps.noteOp(AppOpsManager.OP_READ_PHONE_STATE, Binder.getCallingUid(), 376 // callingPackage) == AppOpsManager.MODE_ALLOWED; 377 } 378} 379