Home | History | Annotate | Download | only in telephony
      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  */
     16 package com.android.internal.telephony;
     17 
     18 import java.io.FileDescriptor;
     19 import java.io.PrintWriter;
     20 
     21 import android.app.AppOpsManager;
     22 import android.content.Context;
     23 import android.content.pm.PackageManager;
     24 import android.os.Binder;
     25 import android.telephony.PhoneNumberUtils;
     26 import android.telephony.Rlog;
     27 
     28 import com.android.internal.telephony.uicc.IsimRecords;
     29 import com.android.internal.telephony.uicc.UiccCard;
     30 import com.android.internal.telephony.uicc.UiccCardApplication;
     31 
     32 public 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         // This is open to apps with WRITE_SMS.
    144         if (!checkReadPhoneNumber(callingPackage, "getLine1Number")) {
    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, "getLine1AlphaTag")) {
    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, "getMsisdn")) {
    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, "getVoiceMailNumber")) {
    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, "getVoiceMailAlphaTag")) {
    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         try {
    370             mContext.enforceCallingOrSelfPermission(
    371                     android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, message);
    372 
    373             // SKIP checking run-time OP_READ_PHONE_STATE since self or using PRIVILEGED
    374             return true;
    375         } catch (SecurityException e) {
    376             mContext.enforceCallingOrSelfPermission(android.Manifest.permission.READ_PHONE_STATE,
    377                     message);
    378         }
    379 
    380         return mAppOps.noteOp(AppOpsManager.OP_READ_PHONE_STATE, Binder.getCallingUid(),
    381             callingPackage) == AppOpsManager.MODE_ALLOWED;
    382     }
    383 
    384 
    385     /**
    386      * Besides READ_PHONE_STATE, WRITE_SMS also allows apps to get phone numbers.
    387      */
    388     private boolean checkReadPhoneNumber(String callingPackage, String message) {
    389         // Default SMS app can always read it.
    390         if (mAppOps.noteOp(AppOpsManager.OP_WRITE_SMS,
    391                 Binder.getCallingUid(), callingPackage) == AppOpsManager.MODE_ALLOWED) {
    392             return true;
    393         }
    394         try {
    395             return checkReadPhoneState(callingPackage, message);
    396         } catch (SecurityException e) {
    397             // Can be read with READ_SMS too.
    398             mContext.enforceCallingOrSelfPermission(android.Manifest.permission.READ_SMS, message);
    399             return mAppOps.noteOp(AppOpsManager.OP_READ_SMS,
    400                     Binder.getCallingUid(), callingPackage) == AppOpsManager.MODE_ALLOWED;
    401         }
    402     }
    403 }
    404