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