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