• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
19 package com.android.internal.telephony;
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.os.RemoteException;
26 import android.os.ServiceManager;
27 import android.telephony.PhoneNumberUtils;
28 import android.telephony.SubscriptionManager;
29 import android.telephony.Rlog;
30 
31 import com.android.internal.telephony.uicc.IsimRecords;
32 import com.android.internal.telephony.uicc.UiccCard;
33 import com.android.internal.telephony.uicc.UiccCardApplication;
34 
35 import static android.Manifest.permission.CALL_PRIVILEGED;
36 import static android.Manifest.permission.READ_PHONE_STATE;
37 import static android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE;
38 import static android.Manifest.permission.READ_SMS;
39 import static android.telephony.TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS;
40 
41 public 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 
PhoneSubInfoController(Context context, Phone[] phone)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 
getDeviceId(String callingPackage)59     public String getDeviceId(String callingPackage) {
60         return getDeviceIdForPhone(SubscriptionManager.getPhoneId(getDefaultSubscription()),
61                 callingPackage);
62     }
63 
getDeviceIdForPhone(int phoneId, String callingPackage)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 
getNaiForSubscriber(int subId, String callingPackage)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 
getImeiForSubscriber(int subId, String callingPackage)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 
getDeviceSvn(String callingPackage)106     public String getDeviceSvn(String callingPackage) {
107         return getDeviceSvnUsingSubId(getDefaultSubscription(), callingPackage);
108     }
109 
getDeviceSvnUsingSubId(int subId, String callingPackage)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 
getSubscriberId(String callingPackage)123     public String getSubscriberId(String callingPackage) {
124         return getSubscriberIdForSubscriber(getDefaultSubscription(), callingPackage);
125     }
126 
getSubscriberIdForSubscriber(int subId, String callingPackage)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      */
getIccSerialNumber(String callingPackage)143     public String getIccSerialNumber(String callingPackage) {
144         return getIccSerialNumberForSubscriber(getDefaultSubscription(), callingPackage);
145     }
146 
getIccSerialNumberForSubscriber(int subId, String callingPackage)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 
getLine1Number(String callingPackage)160     public String getLine1Number(String callingPackage) {
161         return getLine1NumberForSubscriber(getDefaultSubscription(), callingPackage);
162     }
163 
getLine1NumberForSubscriber(int subId, String callingPackage)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 
getLine1AlphaTag(String callingPackage)178     public String getLine1AlphaTag(String callingPackage) {
179         return getLine1AlphaTagForSubscriber(getDefaultSubscription(), callingPackage);
180     }
181 
getLine1AlphaTagForSubscriber(int subId, String callingPackage)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 
getMsisdn(String callingPackage)195     public String getMsisdn(String callingPackage) {
196         return getMsisdnForSubscriber(getDefaultSubscription(), callingPackage);
197     }
198 
getMsisdnForSubscriber(int subId, String callingPackage)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 
getVoiceMailNumber(String callingPackage)212     public String getVoiceMailNumber(String callingPackage) {
213         return getVoiceMailNumberForSubscriber(getDefaultSubscription(), callingPackage);
214     }
215 
getVoiceMailNumberForSubscriber(int subId, String callingPackage)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
getCompleteVoiceMailNumber()232     public String getCompleteVoiceMailNumber() {
233         return getCompleteVoiceMailNumberForSubscriber(getDefaultSubscription());
234     }
235 
getCompleteVoiceMailNumberForSubscriber(int subId)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 
getVoiceMailAlphaTag(String callingPackage)249     public String getVoiceMailAlphaTag(String callingPackage) {
250         return getVoiceMailAlphaTagForSubscriber(getDefaultSubscription(), callingPackage);
251     }
252 
getVoiceMailAlphaTagForSubscriber(int subId, String callingPackage)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      **/
getPhone(int subId)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      */
enforcePrivilegedPermissionOrCarrierPrivilege(Phone phone)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 
getDefaultSubscription()299     private int getDefaultSubscription() {
300         return  PhoneFactory.getDefaultSubscription();
301     }
302 
303 
getIsimImpi()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 
getIsimDomain()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 
getIsimImpu()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 
getIsimIst()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 
getIsimPcscf()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 
getIsimChallengeResponse(String nonce)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 
getIccSimChallengeResponse(int subId, int appType, int authType, String data)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 
getGroupIdLevel1(String callingPackage)405     public String getGroupIdLevel1(String callingPackage) {
406         return getGroupIdLevel1ForSubscriber(getDefaultSubscription(), callingPackage);
407     }
408 
getGroupIdLevel1ForSubscriber(int subId, String callingPackage)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 
checkReadPhoneState(String callingPackage, String message)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      */
checkReadPhoneNumber(String callingPackage, String message)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 
log(String s)462     private void log(String s) {
463         Rlog.d(TAG, s);
464     }
465 
loge(String s)466     private void loge(String s) {
467         Rlog.e(TAG, s);
468     }
469 }
470