• 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.NonNull;
25 import android.annotation.Nullable;
26 import android.app.AppOpsManager;
27 import android.compat.annotation.UnsupportedAppUsage;
28 import android.content.Context;
29 import android.content.pm.PackageManager;
30 import android.net.Uri;
31 import android.os.Binder;
32 import android.os.Build;
33 import android.os.RemoteException;
34 import android.os.TelephonyServiceManager.ServiceRegisterer;
35 import android.telephony.ImsiEncryptionInfo;
36 import android.telephony.PhoneNumberUtils;
37 import android.telephony.SubscriptionManager;
38 import android.telephony.TelephonyFrameworkInitializer;
39 import android.text.TextUtils;
40 import android.util.EventLog;
41 
42 import com.android.internal.telephony.subscription.SubscriptionInfoInternal;
43 import com.android.internal.telephony.subscription.SubscriptionManagerService;
44 import com.android.internal.telephony.uicc.IsimRecords;
45 import com.android.internal.telephony.uicc.SIMRecords;
46 import com.android.internal.telephony.uicc.UiccCardApplication;
47 import com.android.internal.telephony.uicc.UiccPort;
48 import com.android.telephony.Rlog;
49 
50 import java.util.ArrayList;
51 import java.util.List;
52 
53 public class PhoneSubInfoController extends IPhoneSubInfo.Stub {
54     private static final String TAG = "PhoneSubInfoController";
55     private static final boolean DBG = true;
56     private static final boolean VDBG = false; // STOPSHIP if true
57 
58     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
59     private final Context mContext;
60     private AppOpsManager mAppOps;
61 
PhoneSubInfoController(Context context)62     public PhoneSubInfoController(Context context) {
63         ServiceRegisterer phoneSubServiceRegisterer = TelephonyFrameworkInitializer
64                 .getTelephonyServiceManager()
65                 .getPhoneSubServiceRegisterer();
66         if (phoneSubServiceRegisterer.get() == null) {
67             phoneSubServiceRegisterer.register(this);
68         }
69         mAppOps = context.getSystemService(AppOpsManager.class);
70         mContext = context;
71     }
72 
73     @Deprecated
getDeviceId(String callingPackage)74     public String getDeviceId(String callingPackage) {
75         return getDeviceIdWithFeature(callingPackage, null);
76     }
77 
getDeviceIdWithFeature(String callingPackage, String callingFeatureId)78     public String getDeviceIdWithFeature(String callingPackage, String callingFeatureId) {
79         return getDeviceIdForPhone(SubscriptionManager.getPhoneId(getDefaultSubscription()),
80                 callingPackage, callingFeatureId);
81     }
82 
getDeviceIdForPhone(int phoneId, String callingPackage, String callingFeatureId)83     public String getDeviceIdForPhone(int phoneId, String callingPackage,
84             String callingFeatureId) {
85         enforceCallingPackageUidMatched(callingPackage);
86         return callPhoneMethodForPhoneIdWithReadDeviceIdentifiersCheck(phoneId, callingPackage,
87                 callingFeatureId, "getDeviceId", (phone) -> phone.getDeviceId());
88     }
89 
getNaiForSubscriber(int subId, String callingPackage, String callingFeatureId)90     public String getNaiForSubscriber(int subId, String callingPackage, String callingFeatureId) {
91         return callPhoneMethodForSubIdWithReadSubscriberIdentifiersCheck(subId, callingPackage,
92                 callingFeatureId, "getNai", (phone)-> phone.getNai());
93     }
94 
getImeiForSubscriber(int subId, String callingPackage, String callingFeatureId)95     public String getImeiForSubscriber(int subId, String callingPackage,
96             String callingFeatureId) {
97         return callPhoneMethodForSubIdWithReadDeviceIdentifiersCheck(subId, callingPackage,
98                 callingFeatureId, "getImei", (phone) -> phone.getImei());
99     }
100 
getCarrierInfoForImsiEncryption(int subId, int keyType, String callingPackage)101     public ImsiEncryptionInfo getCarrierInfoForImsiEncryption(int subId, int keyType,
102                                                               String callingPackage) {
103         return callPhoneMethodForSubIdWithPrivilegedCheck(subId,
104                 "getCarrierInfoForImsiEncryption",
105                 (phone)-> phone.getCarrierInfoForImsiEncryption(keyType, true));
106     }
107 
setCarrierInfoForImsiEncryption(int subId, String callingPackage, ImsiEncryptionInfo imsiEncryptionInfo)108     public void setCarrierInfoForImsiEncryption(int subId, String callingPackage,
109                                                 ImsiEncryptionInfo imsiEncryptionInfo) {
110         callPhoneMethodForSubIdWithModifyCheck(subId, callingPackage,
111                 "setCarrierInfoForImsiEncryption",
112                 (phone)-> {
113                     phone.setCarrierInfoForImsiEncryption(imsiEncryptionInfo);
114                     return null;
115                 });
116     }
117 
118     /**
119      *  Resets the Carrier Keys in the database. This involves 2 steps:
120      *  1. Delete the keys from the database.
121      *  2. Send an intent to download new Certificates.
122      *  @param subId
123      *  @param callingPackage
124      */
resetCarrierKeysForImsiEncryption(int subId, String callingPackage)125     public void resetCarrierKeysForImsiEncryption(int subId, String callingPackage) {
126         callPhoneMethodForSubIdWithModifyCheck(subId, callingPackage,
127                 "resetCarrierKeysForImsiEncryption",
128                 (phone)-> {
129                     phone.resetCarrierKeysForImsiEncryption();
130                     return null;
131                 });
132     }
133 
getDeviceSvn(String callingPackage, String callingFeatureId)134     public String getDeviceSvn(String callingPackage, String callingFeatureId) {
135         return getDeviceSvnUsingSubId(getDefaultSubscription(), callingPackage, callingFeatureId);
136     }
137 
getDeviceSvnUsingSubId(int subId, String callingPackage, String callingFeatureId)138     public String getDeviceSvnUsingSubId(int subId, String callingPackage,
139             String callingFeatureId) {
140         return callPhoneMethodForSubIdWithReadCheck(subId, callingPackage, callingFeatureId,
141                 "getDeviceSvn", (phone)-> phone.getDeviceSvn());
142     }
143 
144     @Deprecated
getSubscriberId(String callingPackage)145     public String getSubscriberId(String callingPackage) {
146         return getSubscriberIdWithFeature(callingPackage, null);
147     }
148 
getSubscriberIdWithFeature(String callingPackage, String callingFeatureId)149     public String getSubscriberIdWithFeature(String callingPackage, String callingFeatureId) {
150         return getSubscriberIdForSubscriber(getDefaultSubscription(), callingPackage,
151                 callingFeatureId);
152     }
153 
getSubscriberIdForSubscriber(int subId, String callingPackage, String callingFeatureId)154     public String getSubscriberIdForSubscriber(int subId, String callingPackage,
155             String callingFeatureId) {
156         String message = "getSubscriberIdForSubscriber";
157         mAppOps.checkPackage(Binder.getCallingUid(), callingPackage);
158 
159         long identity = Binder.clearCallingIdentity();
160         boolean isActive;
161         try {
162             isActive = SubscriptionManagerService.getInstance().isActiveSubId(subId,
163                     callingPackage, callingFeatureId);
164         } finally {
165             Binder.restoreCallingIdentity(identity);
166         }
167         if (isActive) {
168             return callPhoneMethodForSubIdWithReadSubscriberIdentifiersCheck(subId, callingPackage,
169                     callingFeatureId, message, (phone) -> phone.getSubscriberId());
170         } else {
171             if (!TelephonyPermissions.checkCallingOrSelfReadSubscriberIdentifiers(
172                     mContext, subId, callingPackage, callingFeatureId, message)) {
173                 return null;
174             }
175             identity = Binder.clearCallingIdentity();
176             try {
177                 SubscriptionInfoInternal subInfo = SubscriptionManagerService.getInstance()
178                         .getSubscriptionInfoInternal(subId);
179                 if (subInfo != null && !TextUtils.isEmpty(subInfo.getImsi())) {
180                     return subInfo.getImsi();
181                 }
182                 return null;
183             } finally {
184                 Binder.restoreCallingIdentity(identity);
185             }
186         }
187     }
188 
189     @Deprecated
getIccSerialNumber(String callingPackage)190     public String getIccSerialNumber(String callingPackage) {
191         return getIccSerialNumberWithFeature(callingPackage, null);
192     }
193 
194     /**
195      * Retrieves the serial number of the ICC, if applicable.
196      */
getIccSerialNumberWithFeature(String callingPackage, String callingFeatureId)197     public String getIccSerialNumberWithFeature(String callingPackage, String callingFeatureId) {
198         return getIccSerialNumberForSubscriber(getDefaultSubscription(), callingPackage,
199                 callingFeatureId);
200     }
201 
getIccSerialNumberForSubscriber(int subId, String callingPackage, String callingFeatureId)202     public String getIccSerialNumberForSubscriber(int subId, String callingPackage,
203             String callingFeatureId) {
204         return callPhoneMethodForSubIdWithReadSubscriberIdentifiersCheck(subId, callingPackage,
205                 callingFeatureId, "getIccSerialNumber", (phone) -> phone.getIccSerialNumber());
206     }
207 
getLine1Number(String callingPackage, String callingFeatureId)208     public String getLine1Number(String callingPackage, String callingFeatureId) {
209         return getLine1NumberForSubscriber(getDefaultSubscription(), callingPackage,
210                 callingFeatureId);
211     }
212 
213     // In R and beyond, READ_PHONE_NUMBERS includes READ_PHONE_NUMBERS and READ_SMS only.
214     // Prior to R, it also included READ_PHONE_STATE.  Maintain that for compatibility.
getLine1NumberForSubscriber(int subId, String callingPackage, String callingFeatureId)215     public String getLine1NumberForSubscriber(int subId, String callingPackage,
216             String callingFeatureId) {
217         return callPhoneMethodForSubIdWithReadPhoneNumberCheck(
218                 subId, callingPackage, callingFeatureId, "getLine1Number",
219                 (phone)-> phone.getLine1Number());
220     }
221 
getLine1AlphaTag(String callingPackage, String callingFeatureId)222     public String getLine1AlphaTag(String callingPackage, String callingFeatureId) {
223         return getLine1AlphaTagForSubscriber(getDefaultSubscription(), callingPackage,
224                 callingFeatureId);
225     }
226 
getLine1AlphaTagForSubscriber(int subId, String callingPackage, String callingFeatureId)227     public String getLine1AlphaTagForSubscriber(int subId, String callingPackage,
228             String callingFeatureId) {
229         return callPhoneMethodForSubIdWithReadCheck(subId, callingPackage, callingFeatureId,
230                 "getLine1AlphaTag", (phone)-> phone.getLine1AlphaTag());
231     }
232 
getMsisdn(String callingPackage, String callingFeatureId)233     public String getMsisdn(String callingPackage, String callingFeatureId) {
234         return getMsisdnForSubscriber(getDefaultSubscription(), callingPackage, callingFeatureId);
235     }
236 
237     // In R and beyond this will require READ_PHONE_NUMBERS.
238     // Prior to R it needed READ_PHONE_STATE.  Maintain that for compatibility.
getMsisdnForSubscriber(int subId, String callingPackage, String callingFeatureId)239     public String getMsisdnForSubscriber(int subId, String callingPackage,
240             String callingFeatureId) {
241         return callPhoneMethodForSubIdWithReadPhoneNumberCheck(
242                 subId, callingPackage, callingFeatureId, "getMsisdn", (phone)-> phone.getMsisdn());
243     }
244 
getVoiceMailNumber(String callingPackage, String callingFeatureId)245     public String getVoiceMailNumber(String callingPackage, String callingFeatureId) {
246         return getVoiceMailNumberForSubscriber(getDefaultSubscription(), callingPackage,
247                 callingFeatureId);
248     }
249 
getVoiceMailNumberForSubscriber(int subId, String callingPackage, String callingFeatureId)250     public String getVoiceMailNumberForSubscriber(int subId, String callingPackage,
251             String callingFeatureId) {
252         return callPhoneMethodForSubIdWithReadCheck(subId, callingPackage, callingFeatureId,
253                 "getVoiceMailNumber", (phone)-> {
254                     String number = PhoneNumberUtils.extractNetworkPortion(
255                             phone.getVoiceMailNumber());
256                     if (VDBG) log("VM: getVoiceMailNUmber: " + number);
257                     return number;
258                 });
259     }
260 
getVoiceMailAlphaTag(String callingPackage, String callingFeatureId)261     public String getVoiceMailAlphaTag(String callingPackage, String callingFeatureId) {
262         return getVoiceMailAlphaTagForSubscriber(getDefaultSubscription(), callingPackage,
263                 callingFeatureId);
264     }
265 
getVoiceMailAlphaTagForSubscriber(int subId, String callingPackage, String callingFeatureId)266     public String getVoiceMailAlphaTagForSubscriber(int subId, String callingPackage,
267             String callingFeatureId) {
268         return callPhoneMethodForSubIdWithReadCheck(subId, callingPackage, callingFeatureId,
269                 "getVoiceMailAlphaTag", (phone)-> phone.getVoiceMailAlphaTag());
270     }
271 
272     /**
273      * get Phone object based on subId.
274      **/
275     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
getPhone(int subId)276     private Phone getPhone(int subId) {
277         int phoneId = SubscriptionManager.getPhoneId(subId);
278         if (!SubscriptionManager.isValidPhoneId(phoneId)) {
279             return null;
280         }
281         return PhoneFactory.getPhone(phoneId);
282     }
283 
enforceCallingPackageUidMatched(String callingPackage)284     private void enforceCallingPackageUidMatched(String callingPackage) {
285         try {
286             mAppOps.checkPackage(Binder.getCallingUid(), callingPackage);
287         } catch (SecurityException se) {
288             EventLog.writeEvent(0x534e4554, "188677422", Binder.getCallingUid());
289             throw se;
290         }
291     }
292 
enforceIccSimChallengeResponsePermission(Context context, int subId, String callingPackage, String callingFeatureId, String message)293     private boolean enforceIccSimChallengeResponsePermission(Context context, int subId,
294             String callingPackage, String callingFeatureId, String message) {
295         if (TelephonyPermissions.checkCallingOrSelfUseIccAuthWithDeviceIdentifier(context,
296                 callingPackage, callingFeatureId, message)) {
297             return true;
298         }
299         if (VDBG) log("No USE_ICC_AUTH_WITH_DEVICE_IDENTIFIER permission.");
300         enforcePrivilegedPermissionOrCarrierPrivilege(subId, message);
301         return true;
302     }
303 
304     /**
305      * Make sure caller has either read privileged phone permission or carrier privilege.
306      *
307      * @throws SecurityException if the caller does not have the required permission/privilege
308      */
enforcePrivilegedPermissionOrCarrierPrivilege(int subId, String message)309     private void enforcePrivilegedPermissionOrCarrierPrivilege(int subId, String message) {
310         // TODO(b/73660190): Migrate to
311         // TelephonyPermissions.enforceCallingOrSelfModifyPermissionOrCarrierPrivileges and delete
312         // this helper method.
313         int permissionResult = mContext.checkCallingOrSelfPermission(
314                 READ_PRIVILEGED_PHONE_STATE);
315         if (permissionResult == PackageManager.PERMISSION_GRANTED) {
316             return;
317         }
318         if (VDBG) log("No read privileged phone permission, check carrier privilege next.");
319         TelephonyPermissions.enforceCallingOrSelfCarrierPrivilege(mContext, subId, message);
320     }
321 
322     /**
323      * Make sure caller has modify phone state permission.
324      */
enforceModifyPermission()325     private void enforceModifyPermission() {
326         mContext.enforceCallingOrSelfPermission(MODIFY_PHONE_STATE,
327                 "Requires MODIFY_PHONE_STATE");
328     }
329 
330     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
getDefaultSubscription()331     private int getDefaultSubscription() {
332         return  PhoneFactory.getDefaultSubscription();
333     }
334 
335     /**
336     * get the Isim Impi based on subId
337     */
getIsimImpi(int subId)338     public String getIsimImpi(int subId) {
339         return callPhoneMethodForSubIdWithPrivilegedCheck(subId, "getIsimImpi",
340                 (phone) -> {
341                     IsimRecords isim = phone.getIsimRecords();
342                     if (isim != null) {
343                         return isim.getIsimImpi();
344                     } else {
345                         return null;
346                     }
347                 });
348     }
349 
350     /**
351      * Fetches the IMS private user identity (EF_IMPI) based on subscriptionId.
352      *
353      * @param subId subscriptionId
354      * @return IMPI (IMS private user identity) of type string.
355      * @throws IllegalArgumentException if the subscriptionId is not valid
356      * @throws IllegalStateException in case the ISIM hasn’t been loaded.
357      * @throws SecurityException if the caller does not have the required permission
358      */
359     public String getImsPrivateUserIdentity(int subId, String callingPackage,
360             String callingFeatureId) {
361         if (!SubscriptionManager.isValidSubscriptionId(subId)) {
362             throw new IllegalArgumentException("Invalid SubscriptionID  = " + subId);
363         }
364         if (!TelephonyPermissions.checkCallingOrSelfUseIccAuthWithDeviceIdentifier(mContext,
365                 callingPackage, callingFeatureId, "getImsPrivateUserIdentity")) {
366             throw (new SecurityException("No permissions to the caller"));
367         }
368         Phone phone = getPhone(subId);
369         assert phone != null;
370         IsimRecords isim = phone.getIsimRecords();
371         if (isim != null) {
372             return isim.getIsimImpi();
373         } else {
374             throw new IllegalStateException("ISIM is not loaded");
375         }
376     }
377 
378     /**
379     * get the Isim Domain based on subId
380     */
381     public String getIsimDomain(int subId) {
382         return callPhoneMethodForSubIdWithPrivilegedCheck(subId, "getIsimDomain",
383                 (phone) -> {
384                     IsimRecords isim = phone.getIsimRecords();
385                     if (isim != null) {
386                         return isim.getIsimDomain();
387                     } else {
388                         return null;
389                     }
390                 });
391     }
392 
393     /**
394     * get the Isim Impu based on subId
395     */
396     public String[] getIsimImpu(int subId) {
397         return callPhoneMethodForSubIdWithPrivilegedCheck(subId, "getIsimImpu",
398                 (phone) -> {
399                     IsimRecords isim = phone.getIsimRecords();
400                     if (isim != null) {
401                         return isim.getIsimImpu();
402                     } else {
403                         return null;
404                     }
405                 });
406     }
407 
408     /**
409      * Fetches the ISIM public user identities (EF_IMPU) from UICC based on subId
410      *
411      * @param subId subscriptionId
412      * @param callingPackage package name of the caller
413      * @param callingFeatureId feature Id of the caller
414      * @return List of public user identities of type android.net.Uri or empty list  if
415      * EF_IMPU is not available.
416      * @throws IllegalArgumentException if the subscriptionId is not valid
417      * @throws IllegalStateException in case the ISIM hasn’t been loaded.
418      * @throws SecurityException if the caller does not have the required permission
419      */
420     public List<Uri> getImsPublicUserIdentities(int subId, String callingPackage,
421             String callingFeatureId) {
422         if (TelephonyPermissions.
423                 checkCallingOrSelfReadPrivilegedPhoneStatePermissionOrReadPhoneNumber(
424                 mContext, subId, callingPackage, callingFeatureId, "getImsPublicUserIdentities")) {
425             Phone phone = getPhone(subId);
426             assert phone != null;
427             IsimRecords isimRecords = phone.getIsimRecords();
428             if (isimRecords != null) {
429                 String[] impus = isimRecords.getIsimImpu();
430                 List<Uri> impuList = new ArrayList<>();
431                 for (String impu : impus) {
432                     if (impu != null && impu.trim().length() > 0) {
433                         impuList.add(Uri.parse(impu));
434                     }
435                 }
436                 return impuList;
437             }
438             throw new IllegalStateException("ISIM is not loaded");
439         } else {
440             throw new IllegalArgumentException("Invalid SubscriptionID  = " + subId);
441         }
442     }
443 
444     /**
445     * get the Isim Ist based on subId
446     */
447     public String getIsimIst(int subId) throws RemoteException {
448         return callPhoneMethodForSubIdWithPrivilegedCheck(subId, "getIsimIst",
449                 (phone) -> {
450                     IsimRecords isim = phone.getIsimRecords();
451                     if (isim != null) {
452                         return isim.getIsimIst();
453                     } else {
454                         return null;
455                     }
456                 });
457     }
458 
459     /**
460     * get the Isim Pcscf based on subId
461     */
462     public String[] getIsimPcscf(int subId) throws RemoteException {
463         return callPhoneMethodForSubIdWithPrivilegedCheck(subId, "getIsimPcscf",
464                 (phone) -> {
465                     IsimRecords isim = phone.getIsimRecords();
466                     if (isim != null) {
467                         return isim.getIsimPcscf();
468                     } else {
469                         return null;
470                     }
471                 });
472     }
473 
474     /**
475      * Returns the USIM service table that fetched from EFUST elementary field that are loaded
476      * based on the appType.
477      */
478     public String getSimServiceTable(int subId, int appType) throws RemoteException {
479         return callPhoneMethodForSubIdWithPrivilegedCheck(subId, "getSimServiceTable",
480                 (phone) -> {
481                     UiccPort uiccPort = phone.getUiccPort();
482                     if (uiccPort == null || uiccPort.getUiccProfile() == null) {
483                         loge("getSimServiceTable(): uiccPort or uiccProfile is null");
484                         return null;
485                     }
486                     UiccCardApplication uiccApp = uiccPort.getUiccProfile().getApplicationByType(
487                             appType);
488                     if (uiccApp == null) {
489                         loge("getSimServiceTable(): no app with specified apptype="
490                                 + appType);
491                         return null;
492                     }
493                     return ((SIMRecords)uiccApp.getIccRecords()).getSimServiceTable();
494                 });
495     }
496 
497     @Override
498     public String getIccSimChallengeResponse(int subId, int appType, int authType, String data,
499             String callingPackage, String callingFeatureId) throws RemoteException {
500         CallPhoneMethodHelper<String> toExecute = (phone)-> {
501             UiccPort uiccPort = phone.getUiccPort();
502             if (uiccPort == null) {
503                 loge("getIccSimChallengeResponse() uiccPort is null");
504                 return null;
505             }
506 
507             UiccCardApplication uiccApp = uiccPort.getApplicationByType(appType);
508             if (uiccApp == null) {
509                 loge("getIccSimChallengeResponse() no app with specified type -- " + appType);
510                 return null;
511             } else {
512                 loge("getIccSimChallengeResponse() found app " + uiccApp.getAid()
513                         + " specified type -- " + appType);
514             }
515 
516             if (authType != UiccCardApplication.AUTH_CONTEXT_EAP_SIM
517                     && authType != UiccCardApplication.AUTH_CONTEXT_EAP_AKA
518                     && authType != UiccCardApplication.AUTH_CONTEXT_GBA_BOOTSTRAP
519                     && authType != UiccCardApplication.AUTHTYPE_GBA_NAF_KEY_EXTERNAL) {
520                 loge("getIccSimChallengeResponse() unsupported authType: " + authType);
521                 return null;
522             }
523             return uiccApp.getIccRecords().getIccSimChallengeResponse(authType, data);
524         };
525 
526         return callPhoneMethodWithPermissionCheck(subId, callingPackage, callingFeatureId,
527                 "getIccSimChallengeResponse", toExecute,
528                 this::enforceIccSimChallengeResponsePermission);
529     }
530 
531     public String getGroupIdLevel1ForSubscriber(int subId, String callingPackage,
532             String callingFeatureId) {
533         return callPhoneMethodForSubIdWithReadCheck(subId, callingPackage, callingFeatureId,
534                 "getGroupIdLevel1", (phone)-> phone.getGroupIdLevel1());
535     }
536 
537     /** Below are utility methods that abstracts the flow that many public methods use:
538      *  1. Check permission: pass, throw exception, or fails (returns false).
539      *  2. clearCallingIdentity.
540      *  3. Call a specified phone method and get return value.
541      *  4. restoreCallingIdentity and return.
542      */
543     private interface CallPhoneMethodHelper<T> {
544         T callMethod(Phone phone);
545     }
546 
547     private interface PermissionCheckHelper {
548         // Implemented to do whatever permission check it wants.
549         // If passes, it should return true.
550         // If permission is not granted, throws SecurityException.
551         // If permission is revoked by AppOps, return false.
552         boolean checkPermission(Context context, int subId, String callingPackage,
553                 @Nullable String callingFeatureId, String message);
554     }
555 
556     // Base utility method that others use.
557     private <T> T callPhoneMethodWithPermissionCheck(int subId, String callingPackage,
558             @Nullable String callingFeatureId, String message,
559             CallPhoneMethodHelper<T> callMethodHelper,
560             PermissionCheckHelper permissionCheckHelper) {
561         if (!permissionCheckHelper.checkPermission(mContext, subId, callingPackage,
562                 callingFeatureId, message)) {
563             return null;
564         }
565 
566         final long identity = Binder.clearCallingIdentity();
567         try {
568             Phone phone = getPhone(subId);
569             if (phone != null) {
570                 return callMethodHelper.callMethod(phone);
571             } else {
572                 if (VDBG) loge(message + " phone is null for Subscription:" + subId);
573                 return null;
574             }
575         } finally {
576             Binder.restoreCallingIdentity(identity);
577         }
578     }
579 
580     private <T> T callPhoneMethodForSubIdWithReadCheck(int subId, String callingPackage,
581             @Nullable String callingFeatureId, String message,
582             CallPhoneMethodHelper<T> callMethodHelper) {
583         return callPhoneMethodWithPermissionCheck(subId, callingPackage, callingFeatureId,
584                 message, callMethodHelper,
585                 (aContext, aSubId, aCallingPackage, aCallingFeatureId, aMessage)->
586                         TelephonyPermissions.checkCallingOrSelfReadPhoneState(
587                                 aContext, aSubId, aCallingPackage, aCallingFeatureId, aMessage));
588     }
589 
590     private <T> T callPhoneMethodForSubIdWithReadDeviceIdentifiersCheck(int subId,
591             String callingPackage, @Nullable String callingFeatureId, String message,
592             CallPhoneMethodHelper<T> callMethodHelper) {
593         return callPhoneMethodWithPermissionCheck(subId, callingPackage, callingFeatureId,
594                 message, callMethodHelper,
595                 (aContext, aSubId, aCallingPackage, aCallingFeatureId, aMessage)->
596                         TelephonyPermissions.checkCallingOrSelfReadDeviceIdentifiers(
597                                 aContext, aSubId, aCallingPackage, aCallingFeatureId, aMessage));
598     }
599 
600     private <T> T callPhoneMethodForSubIdWithReadSubscriberIdentifiersCheck(int subId,
601             String callingPackage, @Nullable String callingFeatureId, String message,
602             CallPhoneMethodHelper<T> callMethodHelper) {
603         return callPhoneMethodWithPermissionCheck(subId, callingPackage, callingFeatureId,
604                 message, callMethodHelper,
605                 (aContext, aSubId, aCallingPackage, aCallingFeatureId, aMessage)->
606                         TelephonyPermissions.checkCallingOrSelfReadSubscriberIdentifiers(
607                                 aContext, aSubId, aCallingPackage, aCallingFeatureId, aMessage));
608     }
609 
610     private <T> T callPhoneMethodForSubIdWithPrivilegedCheck(
611             int subId, String message, CallPhoneMethodHelper<T> callMethodHelper) {
612         return callPhoneMethodWithPermissionCheck(subId, null, null, message, callMethodHelper,
613                 (aContext, aSubId, aCallingPackage, aCallingFeatureId, aMessage) -> {
614                     mContext.enforceCallingOrSelfPermission(READ_PRIVILEGED_PHONE_STATE, message);
615                     return true;
616                 });
617     }
618 
619     private <T> T callPhoneMethodForSubIdWithModifyCheck(int subId, String callingPackage,
620             String message, CallPhoneMethodHelper<T> callMethodHelper) {
621         return callPhoneMethodWithPermissionCheck(subId, null, null, message, callMethodHelper,
622                 (aContext, aSubId, aCallingPackage, aCallingFeatureId, aMessage)-> {
623                     enforceModifyPermission();
624                     return true;
625                 });
626     }
627 
628     private <T> T callPhoneMethodForSubIdWithReadPhoneNumberCheck(int subId, String callingPackage,
629             @NonNull String callingFeatureId, String message,
630             CallPhoneMethodHelper<T> callMethodHelper) {
631         return callPhoneMethodWithPermissionCheck(subId, callingPackage, callingFeatureId,
632                 message, callMethodHelper,
633                 (aContext, aSubId, aCallingPackage, aCallingFeatureId, aMessage) ->
634                         TelephonyPermissions.checkCallingOrSelfReadPhoneNumber(
635                                 aContext, aSubId, aCallingPackage, aCallingFeatureId, aMessage));
636     }
637 
638     private <T> T callPhoneMethodForPhoneIdWithReadDeviceIdentifiersCheck(int phoneId,
639             String callingPackage, @Nullable String callingFeatureId, String message,
640             CallPhoneMethodHelper<T> callMethodHelper) {
641         // Getting subId before doing permission check.
642         if (!SubscriptionManager.isValidPhoneId(phoneId)) {
643             phoneId = 0;
644         }
645         final Phone phone = PhoneFactory.getPhone(phoneId);
646         if (phone == null) {
647             return null;
648         }
649         if (!TelephonyPermissions.checkCallingOrSelfReadDeviceIdentifiers(mContext,
650                 phone.getSubId(), callingPackage, callingFeatureId, message)) {
651             return null;
652         }
653 
654         final long identity = Binder.clearCallingIdentity();
655         try {
656             return callMethodHelper.callMethod(phone);
657         } finally {
658             Binder.restoreCallingIdentity(identity);
659         }
660     }
661 
662     /**
663      * Returns SIP URI or tel URI of the Public Service Identity of the SM-SC fetched from
664      * EF_PSISMSC elementary field as defined in Section 4.5.9 (3GPP TS 31.102).
665      * @throws IllegalStateException in case if phone or UiccApplication is not available.
666      */
667     public Uri getSmscIdentity(int subId, int appType) throws RemoteException {
668         Uri smscIdentityUri = callPhoneMethodForSubIdWithPrivilegedCheck(subId, "getSmscIdentity",
669                 (phone) -> {
670                     try {
671                         String smscIdentity = null;
672                         UiccPort uiccPort = phone.getUiccPort();
673                         UiccCardApplication uiccApp =
674                                 uiccPort.getUiccProfile().getApplicationByType(
675                                         appType);
676                         smscIdentity = (uiccApp != null) ? uiccApp.getIccRecords().getSmscIdentity()
677                                 : null;
678                         if (TextUtils.isEmpty(smscIdentity)) {
679                             return Uri.EMPTY;
680                         }
681                         return Uri.parse(smscIdentity);
682                     } catch (NullPointerException ex) {
683                         Rlog.e(TAG, "getSmscIdentity(): Exception = " + ex);
684                         return null;
685                     }
686                 });
687         if (smscIdentityUri == null) {
688             throw new IllegalStateException("Telephony service error");
689         }
690         return smscIdentityUri;
691     }
692 
693     private void log(String s) {
694         Rlog.d(TAG, s);
695     }
696 
697     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
698     private void loge(String s) {
699         Rlog.e(TAG, s);
700     }
701 }
702