• 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 static android.Manifest.permission.MODIFY_PHONE_STATE;
22 import static android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE;
23 
24 import android.annotation.UnsupportedAppUsage;
25 import android.app.AppOpsManager;
26 import android.content.Context;
27 import android.content.pm.PackageManager;
28 import android.os.Binder;
29 import android.os.RemoteException;
30 import android.os.ServiceManager;
31 import android.telephony.ImsiEncryptionInfo;
32 import android.telephony.PhoneNumberUtils;
33 import android.telephony.Rlog;
34 import android.telephony.SubscriptionManager;
35 
36 import com.android.internal.telephony.uicc.IsimRecords;
37 import com.android.internal.telephony.uicc.UiccCard;
38 import com.android.internal.telephony.uicc.UiccCardApplication;
39 
40 public class PhoneSubInfoController extends IPhoneSubInfo.Stub {
41     private static final String TAG = "PhoneSubInfoController";
42     private static final boolean DBG = true;
43     private static final boolean VDBG = false; // STOPSHIP if true
44 
45     @UnsupportedAppUsage
46     private final Phone[] mPhone;
47     @UnsupportedAppUsage
48     private final Context mContext;
49     private final AppOpsManager mAppOps;
50 
PhoneSubInfoController(Context context, Phone[] phone)51     public PhoneSubInfoController(Context context, Phone[] phone) {
52         mPhone = phone;
53         if (ServiceManager.getService("iphonesubinfo") == null) {
54             ServiceManager.addService("iphonesubinfo", this);
55         }
56         mContext = context;
57         mAppOps = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
58     }
59 
getDeviceId(String callingPackage)60     public String getDeviceId(String callingPackage) {
61         return getDeviceIdForPhone(SubscriptionManager.getPhoneId(getDefaultSubscription()),
62                 callingPackage);
63     }
64 
getDeviceIdForPhone(int phoneId, String callingPackage)65     public String getDeviceIdForPhone(int phoneId, String callingPackage) {
66         return callPhoneMethodForPhoneIdWithReadDeviceIdentifiersCheck(phoneId, callingPackage,
67                 "getDeviceId", (phone)-> phone.getDeviceId());
68     }
69 
getNaiForSubscriber(int subId, String callingPackage)70     public String getNaiForSubscriber(int subId, String callingPackage) {
71         return callPhoneMethodForSubIdWithReadCheck(subId, callingPackage, "getNai",
72                 (phone)-> phone.getNai());
73     }
74 
getImeiForSubscriber(int subId, String callingPackage)75     public String getImeiForSubscriber(int subId, String callingPackage) {
76         return callPhoneMethodForSubIdWithReadDeviceIdentifiersCheck(subId, callingPackage,
77                 "getImei", (phone)-> phone.getImei());
78     }
79 
getCarrierInfoForImsiEncryption(int subId, int keyType, String callingPackage)80     public ImsiEncryptionInfo getCarrierInfoForImsiEncryption(int subId, int keyType,
81                                                               String callingPackage) {
82         return callPhoneMethodForSubIdWithReadCheck(subId, callingPackage,
83                 "getCarrierInfoForImsiEncryption",
84                 (phone)-> phone.getCarrierInfoForImsiEncryption(keyType));
85     }
86 
setCarrierInfoForImsiEncryption(int subId, String callingPackage, ImsiEncryptionInfo imsiEncryptionInfo)87     public void setCarrierInfoForImsiEncryption(int subId, String callingPackage,
88                                                 ImsiEncryptionInfo imsiEncryptionInfo) {
89         callPhoneMethodForSubIdWithModifyCheck(subId, callingPackage,
90                 "setCarrierInfoForImsiEncryption",
91                 (phone)-> {
92                     phone.setCarrierInfoForImsiEncryption(imsiEncryptionInfo);
93                     return null;
94                 });
95     }
96 
97     /**
98      *  Resets the Carrier Keys in the database. This involves 2 steps:
99      *  1. Delete the keys from the database.
100      *  2. Send an intent to download new Certificates.
101      *  @param subId
102      *  @param callingPackage
103      */
resetCarrierKeysForImsiEncryption(int subId, String callingPackage)104     public void resetCarrierKeysForImsiEncryption(int subId, String callingPackage) {
105         callPhoneMethodForSubIdWithModifyCheck(subId, callingPackage,
106                 "setCarrierInfoForImsiEncryption",
107                 (phone)-> {
108                     phone.resetCarrierKeysForImsiEncryption();
109                     return null;
110                 });
111     }
112 
113 
getDeviceSvn(String callingPackage)114     public String getDeviceSvn(String callingPackage) {
115         return getDeviceSvnUsingSubId(getDefaultSubscription(), callingPackage);
116     }
117 
getDeviceSvnUsingSubId(int subId, String callingPackage)118     public String getDeviceSvnUsingSubId(int subId, String callingPackage) {
119         return callPhoneMethodForSubIdWithReadCheck(subId, callingPackage, "getDeviceSvn",
120                 (phone)-> phone.getDeviceSvn());
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         String message = "getSubscriberId";
129         long identity = Binder.clearCallingIdentity();
130         boolean isActive;
131         try {
132             isActive = SubscriptionController.getInstance().isActiveSubId(subId, callingPackage);
133         } finally {
134             Binder.restoreCallingIdentity(identity);
135         }
136         if (isActive) {
137             return callPhoneMethodForSubIdWithReadSubscriberIdentifiersCheck(subId, callingPackage,
138                     message, (phone) -> phone.getSubscriberId());
139         } else {
140             if (!TelephonyPermissions.checkCallingOrSelfReadSubscriberIdentifiers(
141                     mContext, subId, callingPackage, message)) {
142                 return null;
143             }
144             identity = Binder.clearCallingIdentity();
145             try {
146                 return SubscriptionController.getInstance().getImsiPrivileged(subId);
147             } finally {
148                 Binder.restoreCallingIdentity(identity);
149             }
150         }
151     }
152 
153     /**
154      * Retrieves the serial number of the ICC, if applicable.
155      */
getIccSerialNumber(String callingPackage)156     public String getIccSerialNumber(String callingPackage) {
157         return getIccSerialNumberForSubscriber(getDefaultSubscription(), callingPackage);
158     }
159 
getIccSerialNumberForSubscriber(int subId, String callingPackage)160     public String getIccSerialNumberForSubscriber(int subId, String callingPackage) {
161         return callPhoneMethodForSubIdWithReadSubscriberIdentifiersCheck(subId, callingPackage,
162                 "getIccSerialNumber", (phone) -> phone.getIccSerialNumber());
163     }
164 
getLine1Number(String callingPackage)165     public String getLine1Number(String callingPackage) {
166         return getLine1NumberForSubscriber(getDefaultSubscription(), callingPackage);
167     }
168 
getLine1NumberForSubscriber(int subId, String callingPackage)169     public String getLine1NumberForSubscriber(int subId, String callingPackage) {
170         return callPhoneMethodForSubIdWithReadPhoneNumberCheck(
171                 subId, callingPackage, "getLine1Number",
172                 (phone)-> phone.getLine1Number());
173     }
174 
getLine1AlphaTag(String callingPackage)175     public String getLine1AlphaTag(String callingPackage) {
176         return getLine1AlphaTagForSubscriber(getDefaultSubscription(), callingPackage);
177     }
178 
getLine1AlphaTagForSubscriber(int subId, String callingPackage)179     public String getLine1AlphaTagForSubscriber(int subId, String callingPackage) {
180         return callPhoneMethodForSubIdWithReadCheck(subId, callingPackage, "getLine1AlphaTag",
181                 (phone)-> phone.getLine1AlphaTag());
182     }
183 
getMsisdn(String callingPackage)184     public String getMsisdn(String callingPackage) {
185         return getMsisdnForSubscriber(getDefaultSubscription(), callingPackage);
186     }
187 
getMsisdnForSubscriber(int subId, String callingPackage)188     public String getMsisdnForSubscriber(int subId, String callingPackage) {
189         return callPhoneMethodForSubIdWithReadCheck(subId, callingPackage, "getMsisdn",
190                 (phone)-> phone.getMsisdn());
191     }
192 
getVoiceMailNumber(String callingPackage)193     public String getVoiceMailNumber(String callingPackage) {
194         return getVoiceMailNumberForSubscriber(getDefaultSubscription(), callingPackage);
195     }
196 
getVoiceMailNumberForSubscriber(int subId, String callingPackage)197     public String getVoiceMailNumberForSubscriber(int subId, String callingPackage) {
198         return callPhoneMethodForSubIdWithReadCheck(subId, callingPackage,
199                 "getVoiceMailNumber", (phone)-> {
200                     String number = PhoneNumberUtils.extractNetworkPortion(
201                             phone.getVoiceMailNumber());
202                     if (VDBG) log("VM: getVoiceMailNUmber: " + number);
203                     return number;
204                 });
205     }
206 
getVoiceMailAlphaTag(String callingPackage)207     public String getVoiceMailAlphaTag(String callingPackage) {
208         return getVoiceMailAlphaTagForSubscriber(getDefaultSubscription(), callingPackage);
209     }
210 
getVoiceMailAlphaTagForSubscriber(int subId, String callingPackage)211     public String getVoiceMailAlphaTagForSubscriber(int subId, String callingPackage) {
212         return callPhoneMethodForSubIdWithReadCheck(subId, callingPackage,
213                 "getVoiceMailAlphaTag", (phone)-> phone.getVoiceMailAlphaTag());
214     }
215 
216     /**
217      * get Phone object based on subId.
218      **/
219     @UnsupportedAppUsage
getPhone(int subId)220     private Phone getPhone(int subId) {
221         int phoneId = SubscriptionManager.getPhoneId(subId);
222         if (!SubscriptionManager.isValidPhoneId(phoneId)) {
223             phoneId = 0;
224         }
225         return mPhone[phoneId];
226     }
227 
228     /**
229      * Make sure caller has either read privileged phone permission or carrier privilege.
230      *
231      * @throws SecurityException if the caller does not have the required permission/privilege
232      */
enforcePrivilegedPermissionOrCarrierPrivilege(int subId, String message)233     private void enforcePrivilegedPermissionOrCarrierPrivilege(int subId, String message) {
234         // TODO(b/73660190): Migrate to
235         // TelephonyPermissions.enforceCallingOrSelfModifyPermissionOrCarrierPrivileges and delete
236         // this helper method.
237         int permissionResult = mContext.checkCallingOrSelfPermission(
238                 READ_PRIVILEGED_PHONE_STATE);
239         if (permissionResult == PackageManager.PERMISSION_GRANTED) {
240             return;
241         }
242         if (VDBG) log("No read privileged phone permission, check carrier privilege next.");
243         TelephonyPermissions.enforceCallingOrSelfCarrierPrivilege(subId, message);
244     }
245 
246     /**
247      * Make sure caller has modify phone state permission.
248      */
enforceModifyPermission()249     private void enforceModifyPermission() {
250         mContext.enforceCallingOrSelfPermission(MODIFY_PHONE_STATE,
251                 "Requires MODIFY_PHONE_STATE");
252     }
253 
254     @UnsupportedAppUsage
getDefaultSubscription()255     private int getDefaultSubscription() {
256         return  PhoneFactory.getDefaultSubscription();
257     }
258 
259     /**
260     * get the Isim Impi based on subId
261     */
getIsimImpi(int subId)262     public String getIsimImpi(int subId) {
263         return callPhoneMethodForSubIdWithPrivilegedCheck(subId, "getIsimImpi",
264                 (phone) -> {
265                     IsimRecords isim = phone.getIsimRecords();
266                     if (isim != null) {
267                         return isim.getIsimImpi();
268                     } else {
269                         return null;
270                     }
271                 });
272     }
273 
274     /**
275     * get the Isim Domain based on subId
276     */
277     public String getIsimDomain(int subId) {
278         return callPhoneMethodForSubIdWithPrivilegedCheck(subId, "getIsimDomain",
279                 (phone) -> {
280                     IsimRecords isim = phone.getIsimRecords();
281                     if (isim != null) {
282                         return isim.getIsimDomain();
283                     } else {
284                         return null;
285                     }
286                 });
287     }
288 
289     /**
290     * get the Isim Impu based on subId
291     */
292     public String[] getIsimImpu(int subId) {
293         return callPhoneMethodForSubIdWithPrivilegedCheck(subId, "getIsimImpu",
294                 (phone) -> {
295                     IsimRecords isim = phone.getIsimRecords();
296                     if (isim != null) {
297                         return isim.getIsimImpu();
298                     } else {
299                         return null;
300                     }
301                 });
302     }
303 
304     /**
305     * get the Isim Ist based on subId
306     */
307     public String getIsimIst(int subId) throws RemoteException {
308         return callPhoneMethodForSubIdWithPrivilegedCheck(subId, "getIsimIst",
309                 (phone) -> {
310                     IsimRecords isim = phone.getIsimRecords();
311                     if (isim != null) {
312                         return isim.getIsimIst();
313                     } else {
314                         return null;
315                     }
316                 });
317     }
318 
319     /**
320     * get the Isim Pcscf based on subId
321     */
322     public String[] getIsimPcscf(int subId) throws RemoteException {
323         return callPhoneMethodForSubIdWithPrivilegedCheck(subId, "getIsimPcscf",
324                 (phone) -> {
325                     IsimRecords isim = phone.getIsimRecords();
326                     if (isim != null) {
327                         return isim.getIsimPcscf();
328                     } else {
329                         return null;
330                     }
331                 });
332     }
333 
334     public String getIccSimChallengeResponse(int subId, int appType, int authType, String data)
335             throws RemoteException {
336         CallPhoneMethodHelper<String> toExecute = (phone)-> {
337             UiccCard uiccCard = phone.getUiccCard();
338             if (uiccCard == null) {
339                 loge("getIccSimChallengeResponse() UiccCard is null");
340                 return null;
341             }
342 
343             UiccCardApplication uiccApp = uiccCard.getApplicationByType(appType);
344             if (uiccApp == null) {
345                 loge("getIccSimChallengeResponse() no app with specified type -- " + appType);
346                 return null;
347             } else {
348                 loge("getIccSimChallengeResponse() found app " + uiccApp.getAid()
349                         + " specified type -- " + appType);
350             }
351 
352             if (authType != UiccCardApplication.AUTH_CONTEXT_EAP_SIM
353                     && authType != UiccCardApplication.AUTH_CONTEXT_EAP_AKA) {
354                 loge("getIccSimChallengeResponse() unsupported authType: " + authType);
355                 return null;
356             }
357             return uiccApp.getIccRecords().getIccSimChallengeResponse(authType, data);
358         };
359 
360         return callPhoneMethodWithPermissionCheck(
361                 subId, null, "getIccSimChallengeResponse", toExecute,
362                 (aContext, aSubId, aCallingPackage, aMessage)-> {
363                     enforcePrivilegedPermissionOrCarrierPrivilege(aSubId, aMessage);
364                     return true;
365                 });
366     }
367 
368     public String getGroupIdLevel1ForSubscriber(int subId, String callingPackage) {
369         return callPhoneMethodForSubIdWithReadCheck(subId, callingPackage,
370                 "getGroupIdLevel1", (phone)-> phone.getGroupIdLevel1());
371     }
372 
373     /** Below are utility methods that abstracts the flow that many public methods use:
374      *  1. Check permission: pass, throw exception, or fails (returns false).
375      *  2. clearCallingIdentity.
376      *  3. Call a specified phone method and get return value.
377      *  4. restoreCallingIdentity and return.
378      */
379     private interface CallPhoneMethodHelper<T> {
380         T callMethod(Phone phone);
381     }
382 
383     private interface PermissionCheckHelper {
384         // Implemented to do whatever permission check it wants.
385         // If passes, it should return true.
386         // If permission is not granted, throws SecurityException.
387         // If permission is revoked by AppOps, return false.
388         boolean checkPermission(Context context, int subId, String callingPackage, String message);
389     }
390 
391     // Base utility method that others use.
392     private <T> T callPhoneMethodWithPermissionCheck(int subId, String callingPackage,
393             String message, CallPhoneMethodHelper<T> callMethodHelper,
394             PermissionCheckHelper permissionCheckHelper) {
395         if (!permissionCheckHelper.checkPermission(mContext, subId, callingPackage, message)) {
396             return null;
397         }
398 
399         final long identity = Binder.clearCallingIdentity();
400         try {
401             Phone phone = getPhone(subId);
402             if (phone != null) {
403                 return callMethodHelper.callMethod(phone);
404             } else {
405                 loge(message + " phone is null for Subscription:" + subId);
406                 return null;
407             }
408         } finally {
409             Binder.restoreCallingIdentity(identity);
410         }
411     }
412 
413     private <T> T callPhoneMethodForSubIdWithReadCheck(int subId, String callingPackage,
414             String message, CallPhoneMethodHelper<T> callMethodHelper) {
415         return callPhoneMethodWithPermissionCheck(subId, callingPackage, message, callMethodHelper,
416                 (aContext, aSubId, aCallingPackage, aMessage)->
417                         TelephonyPermissions.checkCallingOrSelfReadPhoneState(
418                                 aContext, aSubId, aCallingPackage, aMessage));
419     }
420 
421     private <T> T callPhoneMethodForSubIdWithReadDeviceIdentifiersCheck(int subId,
422             String callingPackage, String message, CallPhoneMethodHelper<T> callMethodHelper) {
423         return callPhoneMethodWithPermissionCheck(subId, callingPackage, message, callMethodHelper,
424                 (aContext, aSubId, aCallingPackage, aMessage)->
425                         TelephonyPermissions.checkCallingOrSelfReadDeviceIdentifiers(
426                                 aContext, aSubId, aCallingPackage, aMessage));
427     }
428 
429     private <T> T callPhoneMethodForSubIdWithReadSubscriberIdentifiersCheck(int subId,
430             String callingPackage, String message, CallPhoneMethodHelper<T> callMethodHelper) {
431         return callPhoneMethodWithPermissionCheck(subId, callingPackage, message, callMethodHelper,
432                 (aContext, aSubId, aCallingPackage, aMessage)->
433                         TelephonyPermissions.checkCallingOrSelfReadSubscriberIdentifiers(
434                                 aContext, aSubId, aCallingPackage, aMessage));
435     }
436 
437 
438     private <T> T callPhoneMethodForSubIdWithPrivilegedCheck(
439             int subId, String message, CallPhoneMethodHelper<T> callMethodHelper) {
440         return callPhoneMethodWithPermissionCheck(subId, null, message, callMethodHelper,
441                 (aContext, aSubId, aCallingPackage, aMessage)-> {
442                     mContext.enforceCallingOrSelfPermission(READ_PRIVILEGED_PHONE_STATE, message);
443                     return true;
444                 });
445     }
446 
447     private <T> T callPhoneMethodForSubIdWithModifyCheck(int subId, String callingPackage,
448             String message, CallPhoneMethodHelper<T> callMethodHelper) {
449         return callPhoneMethodWithPermissionCheck(subId, null, message, callMethodHelper,
450                 (aContext, aSubId, aCallingPackage, aMessage)-> {
451                     enforceModifyPermission();
452                     return true;
453                 });
454     }
455 
456     private <T> T callPhoneMethodForSubIdWithReadPhoneNumberCheck(int subId, String callingPackage,
457             String message, CallPhoneMethodHelper<T> callMethodHelper) {
458         return callPhoneMethodWithPermissionCheck(subId, callingPackage, message, callMethodHelper,
459                 (aContext, aSubId, aCallingPackage, aMessage)->
460                         TelephonyPermissions.checkCallingOrSelfReadPhoneNumber(
461                                 aContext, aSubId, aCallingPackage, aMessage));
462     }
463 
464     private <T> T callPhoneMethodForPhoneIdWithReadDeviceIdentifiersCheck(int phoneId,
465             String callingPackage, String message, CallPhoneMethodHelper<T> callMethodHelper) {
466         // Getting subId before doing permission check.
467         if (!SubscriptionManager.isValidPhoneId(phoneId)) {
468             phoneId = 0;
469         }
470         final Phone phone = mPhone[phoneId];
471         if (phone == null) {
472             return null;
473         }
474         if (!TelephonyPermissions.checkCallingOrSelfReadDeviceIdentifiers(mContext,
475                 phone.getSubId(), callingPackage, message)) {
476             return null;
477         }
478 
479         final long identity = Binder.clearCallingIdentity();
480         try {
481             return callMethodHelper.callMethod(phone);
482         } finally {
483             Binder.restoreCallingIdentity(identity);
484         }
485     }
486 
487     private void log(String s) {
488         Rlog.d(TAG, s);
489     }
490 
491     @UnsupportedAppUsage
492     private void loge(String s) {
493         Rlog.e(TAG, s);
494     }
495 }
496