1 /*
2  * Copyright (C) 2019 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.phone;
18 
19 import static android.content.pm.PackageManager.FEATURE_TELEPHONY_IMS;
20 import static android.content.pm.PackageManager.FEATURE_TELEPHONY_IMS_SINGLE_REGISTRATION;
21 import static android.telephony.TelephonyManager.ENABLE_FEATURE_MAPPING;
22 
23 import android.Manifest;
24 import android.annotation.NonNull;
25 import android.annotation.Nullable;
26 import android.app.compat.CompatChanges;
27 import android.compat.annotation.ChangeId;
28 import android.compat.annotation.EnabledAfter;
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.ServiceSpecificException;
35 import android.os.SystemProperties;
36 import android.os.UserHandle;
37 import android.telephony.SubscriptionManager;
38 import android.telephony.TelephonyFrameworkInitializer;
39 import android.telephony.ims.DelegateRequest;
40 import android.telephony.ims.ImsException;
41 import android.telephony.ims.RcsContactUceCapability;
42 import android.telephony.ims.RcsUceAdapter.PublishState;
43 import android.telephony.ims.RegistrationManager;
44 import android.telephony.ims.aidl.IImsCapabilityCallback;
45 import android.telephony.ims.aidl.IImsRcsController;
46 import android.telephony.ims.aidl.IImsRegistrationCallback;
47 import android.telephony.ims.aidl.IRcsUceControllerCallback;
48 import android.telephony.ims.aidl.IRcsUcePublishStateCallback;
49 import android.telephony.ims.aidl.ISipDelegate;
50 import android.telephony.ims.aidl.ISipDelegateConnectionStateCallback;
51 import android.telephony.ims.aidl.ISipDelegateMessageCallback;
52 import android.telephony.ims.feature.ImsFeature;
53 import android.telephony.ims.feature.RcsFeature;
54 import android.telephony.ims.stub.ImsRegistrationImplBase;
55 import android.util.Log;
56 
57 import com.android.ims.ImsManager;
58 import com.android.ims.internal.IImsServiceFeatureCallback;
59 import com.android.internal.telephony.IIntegerConsumer;
60 import com.android.internal.telephony.ISipDialogStateCallback;
61 import com.android.internal.telephony.Phone;
62 import com.android.internal.telephony.TelephonyPermissions;
63 import com.android.internal.telephony.flags.FeatureFlags;
64 import com.android.internal.telephony.ims.ImsResolver;
65 import com.android.services.telephony.rcs.RcsFeatureController;
66 import com.android.services.telephony.rcs.SipTransportController;
67 import com.android.services.telephony.rcs.TelephonyRcsService;
68 import com.android.services.telephony.rcs.UceControllerManager;
69 
70 import java.util.List;
71 import java.util.Set;
72 
73 /**
74  * Implementation of the IImsRcsController interface.
75  */
76 public class ImsRcsController extends IImsRcsController.Stub {
77     private static final String TAG = "ImsRcsController";
78 
79     /** The singleton instance. */
80     private static ImsRcsController sInstance;
81 
82     private PhoneGlobals mApp;
83     private TelephonyRcsService mRcsService;
84     private ImsResolver mImsResolver;
85     private FeatureFlags mFeatureFlags;
86     private PackageManager mPackageManager;
87     // set by shell cmd phone src set-device-enabled true/false
88     private Boolean mSingleRegistrationOverride;
89     private final int mVendorApiLevel;
90 
91     /**
92      * For apps targeting Android T and above, support the publishing state on APIs, such as
93      * {@code RcsUceAdapter#PUBLISH_STATE_PUBLISHING}
94      * @hide
95      */
96     @ChangeId
97     @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.S)
98     public static final long SUPPORT_PUBLISHING_STATE = 202894742;
99 
100     /**
101      * Initialize the singleton ImsRcsController instance.
102      * This is only done once, at startup, from PhoneApp.onCreate().
103      */
init(PhoneGlobals app, FeatureFlags featureFlags)104     static ImsRcsController init(PhoneGlobals app, FeatureFlags featureFlags) {
105         synchronized (ImsRcsController.class) {
106             if (sInstance == null) {
107                 sInstance = new ImsRcsController(app, featureFlags);
108             } else {
109                 Log.wtf(TAG, "init() called multiple times!  sInstance = " + sInstance);
110             }
111             return sInstance;
112         }
113     }
114 
115     /** Private constructor; @see init() */
ImsRcsController(PhoneGlobals app, FeatureFlags featureFlags)116     private ImsRcsController(PhoneGlobals app, FeatureFlags featureFlags) {
117         Log.i(TAG, "ImsRcsController");
118         mApp = app;
119         mFeatureFlags = featureFlags;
120         mPackageManager = mApp.getPackageManager();
121         TelephonyFrameworkInitializer
122                 .getTelephonyServiceManager().getTelephonyImsServiceRegisterer().register(this);
123         mImsResolver = ImsResolver.getInstance();
124         mVendorApiLevel = SystemProperties.getInt(
125                 "ro.vendor.api_level", Build.VERSION.DEVICE_INITIAL_SDK_INT);
126     }
127 
128     /**
129      * Register a {@link RegistrationManager.RegistrationCallback} to receive IMS network
130      * registration state.
131      */
132     @Override
registerImsRegistrationCallback(int subId, IImsRegistrationCallback callback)133     public void registerImsRegistrationCallback(int subId, IImsRegistrationCallback callback) {
134         TelephonyPermissions.enforceCallingOrSelfReadPrecisePhoneStatePermissionOrCarrierPrivilege(
135                 mApp, subId, "registerImsRegistrationCallback");
136 
137         enforceTelephonyFeatureWithException(getCurrentPackageName(),
138                 FEATURE_TELEPHONY_IMS, "registerImsRegistrationCallback");
139 
140         final long token = Binder.clearCallingIdentity();
141         try {
142             getRcsFeatureController(subId).registerImsRegistrationCallback(subId, callback);
143         } catch (ImsException e) {
144             Log.e(TAG, "registerImsRegistrationCallback: sudId=" + subId + ", " + e.getMessage());
145             throw new ServiceSpecificException(e.getCode());
146         } finally {
147             Binder.restoreCallingIdentity(token);
148         }
149     }
150 
151     /**
152      * Removes an existing {@link RegistrationManager.RegistrationCallback}.
153      */
154     @Override
unregisterImsRegistrationCallback(int subId, IImsRegistrationCallback callback)155     public void unregisterImsRegistrationCallback(int subId, IImsRegistrationCallback callback) {
156         TelephonyPermissions.enforceCallingOrSelfReadPrecisePhoneStatePermissionOrCarrierPrivilege(
157                 mApp, subId, "unregisterImsRegistrationCallback");
158 
159         enforceTelephonyFeatureWithException(getCurrentPackageName(),
160                 FEATURE_TELEPHONY_IMS, "unregisterImsRegistrationCallback");
161 
162         final long token = Binder.clearCallingIdentity();
163         try {
164             getRcsFeatureController(subId).unregisterImsRegistrationCallback(subId, callback);
165         } catch (ServiceSpecificException e) {
166             Log.e(TAG, "unregisterImsRegistrationCallback: error=" + e.errorCode);
167         } finally {
168             Binder.restoreCallingIdentity(token);
169         }
170     }
171 
172     /**
173      * Get the IMS service registration state for the RcsFeature associated with this sub id.
174      */
175     @Override
getImsRcsRegistrationState(int subId, IIntegerConsumer consumer)176     public void getImsRcsRegistrationState(int subId, IIntegerConsumer consumer) {
177         TelephonyPermissions.enforceCallingOrSelfReadPrecisePhoneStatePermissionOrCarrierPrivilege(
178                 mApp, subId, "getImsRcsRegistrationState");
179 
180         enforceTelephonyFeatureWithException(getCurrentPackageName(),
181                 FEATURE_TELEPHONY_IMS, "getImsRcsRegistrationState");
182 
183         final long token = Binder.clearCallingIdentity();
184         try {
185             getRcsFeatureController(subId).getRegistrationState(regState -> {
186                 try {
187                     consumer.accept((regState == null)
188                             ? RegistrationManager.REGISTRATION_STATE_NOT_REGISTERED : regState);
189                 } catch (RemoteException e) {
190                     Log.w(TAG, "getImsRcsRegistrationState: callback is not available.");
191                 }
192             });
193         } finally {
194             Binder.restoreCallingIdentity(token);
195         }
196     }
197 
198     /**
199      * Gets the Transport Type associated with the current IMS RCS registration.
200      */
201     @Override
getImsRcsRegistrationTransportType(int subId, IIntegerConsumer consumer)202     public void getImsRcsRegistrationTransportType(int subId, IIntegerConsumer consumer) {
203         TelephonyPermissions.enforceCallingOrSelfReadPrecisePhoneStatePermissionOrCarrierPrivilege(
204                 mApp, subId, "getImsRcsRegistrationTransportType");
205 
206         enforceTelephonyFeatureWithException(getCurrentPackageName(),
207                 FEATURE_TELEPHONY_IMS, "getImsRcsRegistrationTransportType");
208 
209         final long token = Binder.clearCallingIdentity();
210         try {
211             getRcsFeatureController(subId).getRegistrationTech(regTech -> {
212                 // Convert registration tech from ImsRegistrationImplBase -> RegistrationManager
213                 int regTechConverted = (regTech == null)
214                         ? ImsRegistrationImplBase.REGISTRATION_TECH_NONE : regTech;
215                 regTechConverted = RegistrationManager.IMS_REG_TO_ACCESS_TYPE_MAP.get(
216                         regTechConverted);
217                 try {
218                     consumer.accept(regTechConverted);
219                 } catch (RemoteException e) {
220                     Log.w(TAG, "getImsRcsRegistrationTransportType: callback is not available.");
221                 }
222             });
223         } finally {
224             Binder.restoreCallingIdentity(token);
225         }
226     }
227 
228     /**
229      * Register a capability callback which will provide RCS availability updates for the
230      * subscription specified.
231      *
232      * @param subId the subscription ID
233      * @param callback The ImsCapabilityCallback to be registered.
234      */
235     @Override
registerRcsAvailabilityCallback(int subId, IImsCapabilityCallback callback)236     public void registerRcsAvailabilityCallback(int subId, IImsCapabilityCallback callback) {
237         enforceReadPrivilegedPermission("registerRcsAvailabilityCallback");
238 
239         enforceTelephonyFeatureWithException(getCurrentPackageName(),
240                 FEATURE_TELEPHONY_IMS, "registerRcsAvailabilityCallback");
241 
242         final long token = Binder.clearCallingIdentity();
243         try {
244             getRcsFeatureController(subId).registerRcsAvailabilityCallback(subId, callback);
245         } catch (ImsException e) {
246             Log.e(TAG, "registerRcsAvailabilityCallback: sudId=" + subId + ", " + e.getMessage());
247             throw new ServiceSpecificException(e.getCode());
248         } finally {
249             Binder.restoreCallingIdentity(token);
250         }
251     }
252 
253     /**
254      * Remove the registered capability callback.
255      *
256      * @param subId the subscription ID
257      * @param callback The ImsCapabilityCallback to be removed.
258      */
259     @Override
unregisterRcsAvailabilityCallback(int subId, IImsCapabilityCallback callback)260     public void unregisterRcsAvailabilityCallback(int subId, IImsCapabilityCallback callback) {
261         enforceReadPrivilegedPermission("unregisterRcsAvailabilityCallback");
262 
263         enforceTelephonyFeatureWithException(getCurrentPackageName(),
264                 FEATURE_TELEPHONY_IMS, "unregisterRcsAvailabilityCallback");
265 
266         final long token = Binder.clearCallingIdentity();
267         try {
268             getRcsFeatureController(subId).unregisterRcsAvailabilityCallback(subId, callback);
269         } catch (ServiceSpecificException e) {
270             Log.e(TAG, "unregisterRcsAvailabilityCallback: error=" + e.errorCode);
271         } finally {
272             Binder.restoreCallingIdentity(token);
273         }
274     }
275 
276     /**
277      * Query for the capability of an IMS RCS service
278      *
279      * @param subId the subscription ID
280      * @param capability the RCS capability to query.
281      * @param radioTech the radio technology type that we are querying.
282      * @return true if the RCS capability is capable for this subscription, false otherwise.
283      */
284     @Override
isCapable(int subId, @RcsFeature.RcsImsCapabilities.RcsImsCapabilityFlag int capability, @ImsRegistrationImplBase.ImsRegistrationTech int radioTech)285     public boolean isCapable(int subId,
286             @RcsFeature.RcsImsCapabilities.RcsImsCapabilityFlag int capability,
287             @ImsRegistrationImplBase.ImsRegistrationTech int radioTech) {
288         enforceReadPrivilegedPermission("isCapable");
289 
290         enforceTelephonyFeatureWithException(getCurrentPackageName(),
291                 FEATURE_TELEPHONY_IMS, "isCapable");
292 
293         final long token = Binder.clearCallingIdentity();
294         try {
295             return getRcsFeatureController(subId).isCapable(capability, radioTech);
296         } catch (ImsException e) {
297             Log.e(TAG, "isCapable: sudId=" + subId
298                     + ", capability=" + capability + ", " + e.getMessage());
299             throw new ServiceSpecificException(e.getCode(), e.getMessage());
300         } finally {
301             Binder.restoreCallingIdentity(token);
302         }
303     }
304 
305     /**
306      * Query the availability of an IMS RCS capability.
307      *
308      * @param subId the subscription ID
309      * @param capability the RCS capability to query.
310      * @return true if the RCS capability is currently available for the associated subscription,
311      * @param radioTech the radio technology type that we are querying.
312      * false otherwise.
313      */
314     @Override
isAvailable(int subId, @RcsFeature.RcsImsCapabilities.RcsImsCapabilityFlag int capability, @ImsRegistrationImplBase.ImsRegistrationTech int radioTech)315     public boolean isAvailable(int subId,
316             @RcsFeature.RcsImsCapabilities.RcsImsCapabilityFlag int capability,
317             @ImsRegistrationImplBase.ImsRegistrationTech int radioTech) {
318         enforceReadPrivilegedPermission("isAvailable");
319 
320         enforceTelephonyFeatureWithException(getCurrentPackageName(),
321                 FEATURE_TELEPHONY_IMS, "isAvailable");
322 
323         final long token = Binder.clearCallingIdentity();
324         try {
325             return getRcsFeatureController(subId).isAvailable(capability, radioTech);
326         } catch (ImsException e) {
327             Log.e(TAG, "isAvailable: sudId=" + subId
328                     + ", capability=" + capability + ", " + e.getMessage());
329             throw new ServiceSpecificException(e.getCode(), e.getMessage());
330         } finally {
331             Binder.restoreCallingIdentity(token);
332         }
333     }
334 
335     @Override
requestCapabilities(int subId, String callingPackage, String callingFeatureId, List<Uri> contactNumbers, IRcsUceControllerCallback c)336     public void requestCapabilities(int subId, String callingPackage, String callingFeatureId,
337             List<Uri> contactNumbers, IRcsUceControllerCallback c) {
338         enforceAccessUserCapabilityExchangePermission("requestCapabilities");
339         enforceReadContactsPermission("requestCapabilities");
340 
341         enforceTelephonyFeatureWithException(callingPackage,
342                 FEATURE_TELEPHONY_IMS, "requestCapabilities");
343 
344         final long token = Binder.clearCallingIdentity();
345         try {
346             UceControllerManager uceCtrlManager = getRcsFeatureController(subId).getFeature(
347                     UceControllerManager.class);
348             if (uceCtrlManager == null) {
349                 throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION,
350                         "This subscription does not support UCE.");
351             }
352             uceCtrlManager.requestCapabilities(contactNumbers, c);
353         } catch (ImsException e) {
354             throw new ServiceSpecificException(e.getCode(), e.getMessage());
355         } finally {
356             Binder.restoreCallingIdentity(token);
357         }
358     }
359 
360     @Override
requestAvailability(int subId, String callingPackage, String callingFeatureId, Uri contactNumber, IRcsUceControllerCallback c)361     public void requestAvailability(int subId, String callingPackage,
362             String callingFeatureId, Uri contactNumber, IRcsUceControllerCallback c) {
363         enforceAccessUserCapabilityExchangePermission("requestAvailability");
364         enforceReadContactsPermission("requestAvailability");
365 
366         enforceTelephonyFeatureWithException(callingPackage,
367                 FEATURE_TELEPHONY_IMS, "requestAvailability");
368 
369         final long token = Binder.clearCallingIdentity();
370         try {
371             UceControllerManager uceCtrlManager = getRcsFeatureController(subId).getFeature(
372                     UceControllerManager.class);
373             if (uceCtrlManager == null) {
374                 throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION,
375                         "This subscription does not support UCE.");
376             }
377             uceCtrlManager.requestNetworkAvailability(contactNumber, c);
378         } catch (ImsException e) {
379             throw new ServiceSpecificException(e.getCode(), e.getMessage());
380         } finally {
381             Binder.restoreCallingIdentity(token);
382         }
383     }
384 
385     @Override
getUcePublishState(int subId)386     public @PublishState int getUcePublishState(int subId) {
387         enforceReadPrivilegedPermission("getUcePublishState");
388 
389         enforceTelephonyFeatureWithException(getCurrentPackageName(),
390                 FEATURE_TELEPHONY_IMS, "getUcePublishState");
391 
392         final int uid = Binder.getCallingUid();
393         final long token = Binder.clearCallingIdentity();
394         boolean isSupportPublishingState = false;
395         try {
396             UceControllerManager uceCtrlManager = getRcsFeatureController(subId).getFeature(
397                     UceControllerManager.class);
398             if (uceCtrlManager == null) {
399                 throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION,
400                         "This subscription does not support UCE.");
401             }
402             if (CompatChanges.isChangeEnabled(SUPPORT_PUBLISHING_STATE, uid)) {
403                 isSupportPublishingState = true;
404             }
405             return uceCtrlManager.getUcePublishState(isSupportPublishingState);
406         } catch (ImsException e) {
407             throw new ServiceSpecificException(e.getCode(), e.getMessage());
408         } finally {
409             Binder.restoreCallingIdentity(token);
410         }
411     }
412 
413     /**
414      * Add new feature tags to the Set used to calculate the capabilities in PUBLISH.
415      */
416     // Used for SHELL command only right now.
addUceRegistrationOverrideShell(int subId, Set<String> featureTags)417     public RcsContactUceCapability addUceRegistrationOverrideShell(int subId,
418             Set<String> featureTags) throws ImsException {
419         // Permission check happening in PhoneInterfaceManager.
420         try {
421             UceControllerManager uceCtrlManager = getRcsFeatureController(subId).getFeature(
422                     UceControllerManager.class);
423             if (uceCtrlManager == null) {
424                 return null;
425             }
426             return uceCtrlManager.addUceRegistrationOverride(featureTags);
427         } catch (ServiceSpecificException e) {
428             throw new ImsException(e.getMessage(), e.errorCode);
429         }
430     }
431 
432     /**
433      * Remove existing feature tags to the Set used to calculate the capabilities in PUBLISH.
434      */
435     // Used for SHELL command only right now.
removeUceRegistrationOverrideShell(int subId, Set<String> featureTags)436     public RcsContactUceCapability removeUceRegistrationOverrideShell(int subId,
437             Set<String> featureTags) throws ImsException {
438         // Permission check happening in PhoneInterfaceManager.
439         try {
440             UceControllerManager uceCtrlManager = getRcsFeatureController(subId).getFeature(
441                     UceControllerManager.class);
442             if (uceCtrlManager == null) {
443                 return null;
444             }
445             return uceCtrlManager.removeUceRegistrationOverride(featureTags);
446         } catch (ServiceSpecificException e) {
447             throw new ImsException(e.getMessage(), e.errorCode);
448         }
449     }
450 
451     /**
452      * Clear all overrides in the Set used to calculate the capabilities in PUBLISH.
453      */
454     // Used for SHELL command only right now.
clearUceRegistrationOverrideShell(int subId)455     public RcsContactUceCapability clearUceRegistrationOverrideShell(int subId)
456             throws ImsException {
457         try {
458             // Permission check happening in PhoneInterfaceManager.
459             UceControllerManager uceCtrlManager = getRcsFeatureController(subId).getFeature(
460                     UceControllerManager.class);
461             if (uceCtrlManager == null) {
462                 return null;
463             }
464             return uceCtrlManager.clearUceRegistrationOverride();
465         } catch (ServiceSpecificException e) {
466             throw new ImsException(e.getMessage(), e.errorCode);
467         }
468     }
469 
470     /**
471      * @return current RcsContactUceCapability instance that will be used for PUBLISH.
472      */
473     // Used for SHELL command only right now.
getLatestRcsContactUceCapabilityShell(int subId)474     public RcsContactUceCapability getLatestRcsContactUceCapabilityShell(int subId)
475             throws ImsException {
476         try {
477             // Permission check happening in PhoneInterfaceManager.
478             UceControllerManager uceCtrlManager = getRcsFeatureController(subId).getFeature(
479                     UceControllerManager.class);
480             if (uceCtrlManager == null) {
481                 return null;
482             }
483             return uceCtrlManager.getLatestRcsContactUceCapability();
484         } catch (ServiceSpecificException e) {
485             throw new ImsException(e.getMessage(), e.errorCode);
486         }
487     }
488 
489     /**
490      * @return the PIDf XML used in the last PUBLISH procedure or "none" if the device is not
491      * published. Returns {@code null} if the operation failed due to an error.
492      */
493     // Used for SHELL command only right now.
getLastUcePidfXmlShell(int subId)494     public String getLastUcePidfXmlShell(int subId) throws ImsException {
495         try {
496             // Permission check happening in PhoneInterfaceManager.
497             UceControllerManager uceCtrlManager = getRcsFeatureController(subId).getFeature(
498                     UceControllerManager.class);
499             if (uceCtrlManager == null) {
500                 return null;
501             }
502             String pidfXml = uceCtrlManager.getLastPidfXml();
503             return pidfXml == null ? "none" : pidfXml;
504         } catch (ServiceSpecificException e) {
505             throw new ImsException(e.getMessage(), e.errorCode);
506         }
507     }
508 
509     /**
510      * Remove UCE requests cannot be sent to the network status.
511      * @return true if this command is successful.
512      */
513     // Used for SHELL command only right now.
removeUceRequestDisallowedStatus(int subId)514     public boolean removeUceRequestDisallowedStatus(int subId) throws ImsException {
515         try {
516             UceControllerManager uceCtrlManager = getRcsFeatureController(subId, true).getFeature(
517                     UceControllerManager.class);
518             if (uceCtrlManager == null) {
519                 return false;
520             }
521             return uceCtrlManager.removeUceRequestDisallowedStatus();
522         } catch (ServiceSpecificException e) {
523             throw new ImsException(e.getMessage(), e.errorCode);
524         }
525     }
526 
527     /**
528      * Set the timeout for contact capabilities request.
529      */
530     // Used for SHELL command only right now.
setCapabilitiesRequestTimeout(int subId, long timeoutAfter)531     public boolean setCapabilitiesRequestTimeout(int subId, long timeoutAfter) throws ImsException {
532         try {
533             UceControllerManager uceCtrlManager = getRcsFeatureController(subId, true).getFeature(
534                     UceControllerManager.class);
535             if (uceCtrlManager == null) {
536                 return false;
537             }
538             return uceCtrlManager.setCapabilitiesRequestTimeout(timeoutAfter);
539         } catch (ServiceSpecificException e) {
540             throw new ImsException(e.getMessage(), e.errorCode);
541         }
542     }
543 
544     @Override
registerUcePublishStateCallback(int subId, IRcsUcePublishStateCallback c)545     public void registerUcePublishStateCallback(int subId, IRcsUcePublishStateCallback c) {
546         enforceReadPrivilegedPermission("registerUcePublishStateCallback");
547 
548         enforceTelephonyFeatureWithException(getCurrentPackageName(),
549                 FEATURE_TELEPHONY_IMS, "registerUcePublishStateCallback");
550 
551         final int uid = Binder.getCallingUid();
552         final long token = Binder.clearCallingIdentity();
553         boolean isSupportPublishingState = false;
554         try {
555             UceControllerManager uceCtrlManager = getRcsFeatureController(subId).getFeature(
556                     UceControllerManager.class);
557             if (uceCtrlManager == null) {
558                 throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION,
559                         "This subscription does not support UCE.");
560             }
561 
562             if (CompatChanges.isChangeEnabled(SUPPORT_PUBLISHING_STATE, uid)) {
563                 isSupportPublishingState = true;
564             }
565             uceCtrlManager.registerPublishStateCallback(c, isSupportPublishingState);
566         } catch (ImsException e) {
567             throw new ServiceSpecificException(e.getCode(), e.getMessage());
568         } finally {
569             Binder.restoreCallingIdentity(token);
570         }
571     }
572 
573     @Override
unregisterUcePublishStateCallback(int subId, IRcsUcePublishStateCallback c)574     public void unregisterUcePublishStateCallback(int subId, IRcsUcePublishStateCallback c) {
575         enforceReadPrivilegedPermission("unregisterUcePublishStateCallback");
576 
577         enforceTelephonyFeatureWithException(getCurrentPackageName(),
578                 FEATURE_TELEPHONY_IMS, "unregisterUcePublishStateCallback");
579 
580         final long token = Binder.clearCallingIdentity();
581         try {
582             UceControllerManager uceCtrlManager = getRcsFeatureController(subId).getFeature(
583                     UceControllerManager.class);
584             if (uceCtrlManager == null) {
585                 throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION,
586                         "This subscription does not support UCE.");
587             }
588             uceCtrlManager.unregisterPublishStateCallback(c);
589         } catch (ServiceSpecificException e) {
590             Log.e(TAG, "unregisterUcePublishStateCallback: error=" + e.errorCode);
591         } finally {
592             Binder.restoreCallingIdentity(token);
593         }
594     }
595 
596     @Override
isUceSettingEnabled(int subId, String callingPackage, String callingFeatureId)597     public boolean isUceSettingEnabled(int subId, String callingPackage, String callingFeatureId) {
598         if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(
599                 mApp, subId, callingPackage, callingFeatureId, "isUceSettingEnabled")) {
600             Log.w(TAG, "isUceSettingEnabled: READ_PHONE_STATE app op disabled when accessing "
601                     + "isUceSettingEnabled");
602             return false;
603         }
604 
605         enforceTelephonyFeatureWithException(callingPackage,
606                 FEATURE_TELEPHONY_IMS, "isUceSettingEnabled");
607 
608         final long token = Binder.clearCallingIdentity();
609         try {
610             return SubscriptionManager.getBooleanSubscriptionProperty(subId,
611                     SubscriptionManager.IMS_RCS_UCE_ENABLED, false /*defaultValue*/, mApp);
612         } finally {
613             Binder.restoreCallingIdentity(token);
614         }
615     }
616 
617     @Override
setUceSettingEnabled(int subId, boolean isEnabled)618     public void setUceSettingEnabled(int subId, boolean isEnabled) {
619         enforceModifyPermission();
620 
621         enforceTelephonyFeatureWithException(getCurrentPackageName(),
622                 FEATURE_TELEPHONY_IMS, "setUceSettingEnabled");
623 
624         final long token = Binder.clearCallingIdentity();
625         try {
626             SubscriptionManager.setSubscriptionProperty(subId,
627                     SubscriptionManager.IMS_RCS_UCE_ENABLED, (isEnabled ? "1" : "0"));
628         } finally {
629             Binder.restoreCallingIdentity(token);
630         }
631     }
632 
633     @Override
isSipDelegateSupported(int subId)634     public boolean isSipDelegateSupported(int subId) {
635         TelephonyPermissions.enforceAnyPermissionGranted(mApp, Binder.getCallingUid(),
636                 "isSipDelegateSupported",
637                 Manifest.permission.PERFORM_IMS_SINGLE_REGISTRATION,
638                 Manifest.permission.READ_PRIVILEGED_PHONE_STATE);
639         if (!isImsSingleRegistrationSupportedOnDevice()) {
640             return false;
641         }
642         final long token = Binder.clearCallingIdentity();
643         try {
644             SipTransportController transport = getRcsFeatureController(subId).getFeature(
645                     SipTransportController.class);
646             if (transport == null) {
647                 return false;
648             }
649             return transport.isSupported(subId);
650         } catch (ImsException e) {
651             throw new ServiceSpecificException(e.getCode(), e.getMessage());
652         } catch (ServiceSpecificException e) {
653             if (e.errorCode == ImsException.CODE_ERROR_UNSUPPORTED_OPERATION) {
654                 return false;
655             }
656             throw e;
657         } finally {
658             Binder.restoreCallingIdentity(token);
659         }
660     }
661 
662     @Override
createSipDelegate(int subId, DelegateRequest request, String packageName, ISipDelegateConnectionStateCallback delegateState, ISipDelegateMessageCallback delegateMessage)663     public void createSipDelegate(int subId, DelegateRequest request, String packageName,
664             ISipDelegateConnectionStateCallback delegateState,
665             ISipDelegateMessageCallback delegateMessage) {
666         enforceImsSingleRegistrationPermission("createSipDelegate");
667         if (!isImsSingleRegistrationSupportedOnDevice()) {
668             throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION,
669                     "SipDelegate creation is only supported for devices supporting IMS single "
670                             + "registration");
671         }
672         if (!UserHandle.getUserHandleForUid(Binder.getCallingUid()).isSystem()) {
673             throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION,
674                     "SipDelegate creation is only available to primary user.");
675         }
676         try {
677             int remoteUid = mApp.getPackageManager().getPackageUid(packageName, 0 /*flags*/);
678             if (Binder.getCallingUid() != remoteUid) {
679                 throw new SecurityException("passed in packageName does not match the caller");
680             }
681         } catch (PackageManager.NameNotFoundException e) {
682             throw new SecurityException("Passed in PackageName can not be found on device");
683         }
684 
685         final int uid = Binder.getCallingUid();
686         final long identity = Binder.clearCallingIdentity();
687         SipTransportController transport = getRcsFeatureController(subId).getFeature(
688                 SipTransportController.class);
689         if (transport == null) {
690             throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION,
691                     "This subscription does not support the creation of SIP delegates");
692         }
693         try {
694             transport.createSipDelegate(subId, uid, request, packageName, delegateState,
695                     delegateMessage);
696         } catch (ImsException e) {
697             throw new ServiceSpecificException(e.getCode(), e.getMessage());
698         } finally {
699             Binder.restoreCallingIdentity(identity);
700         }
701     }
702 
703     @Override
destroySipDelegate(int subId, ISipDelegate connection, int reason)704     public void destroySipDelegate(int subId, ISipDelegate connection, int reason) {
705         // Do not check permissions here - the caller needs to have a connection already from the
706         // create method to call this method.
707         if (connection == null) {
708             return;
709         }
710         final long identity = Binder.clearCallingIdentity();
711         try {
712             SipTransportController transport = getRcsFeatureController(subId).getFeature(
713                     SipTransportController.class);
714             if (transport == null) {
715                 return;
716             }
717             transport.destroySipDelegate(subId, connection, reason);
718         } catch (ServiceSpecificException e) {
719             Log.e(TAG, "destroySipDelegate: error=" + e.errorCode);
720         } finally {
721             Binder.restoreCallingIdentity(identity);
722         }
723     }
724 
725     @Override
triggerNetworkRegistration(int subId, ISipDelegate connection, int sipCode, String sipReason)726     public void triggerNetworkRegistration(int subId, ISipDelegate connection, int sipCode,
727             String sipReason) {
728         enforceImsSingleRegistrationPermission("triggerNetworkRegistration");
729 
730         final long identity = Binder.clearCallingIdentity();
731         try {
732             SipTransportController transport = getRcsFeatureController(subId).getFeature(
733                     SipTransportController.class);
734             if (transport == null) {
735                 return;
736             }
737             transport.triggerFullNetworkRegistration(subId, connection, sipCode, sipReason);
738         } catch (ServiceSpecificException e) {
739             Log.e(TAG, "triggerNetworkRegistration: error=" + e.errorCode);
740         } finally {
741             Binder.restoreCallingIdentity(identity);
742         }
743     }
744 
745     /**
746      * Register a state of Sip Dialog callback
747      */
748     @Override
registerSipDialogStateCallback(int subId, ISipDialogStateCallback cb)749     public void registerSipDialogStateCallback(int subId, ISipDialogStateCallback cb) {
750         enforceReadPrivilegedPermission("registerSipDialogStateCallback");
751         if (cb == null) {
752             throw new IllegalArgumentException("SipDialogStateCallback is null");
753         }
754         final long identity = Binder.clearCallingIdentity();
755         if (!SubscriptionManager.isValidSubscriptionId(subId)) {
756             throw new IllegalArgumentException("Invalid Subscription ID: " + subId);
757         }
758 
759         enforceTelephonyFeatureWithException(getCurrentPackageName(),
760                 FEATURE_TELEPHONY_IMS_SINGLE_REGISTRATION, "registerSipDialogStateCallback");
761 
762         try {
763             SipTransportController transport = getRcsFeatureController(subId).getFeature(
764                     SipTransportController.class);
765             if (transport == null) {
766                 throw new ServiceSpecificException(ImsException.CODE_ERROR_SERVICE_UNAVAILABLE,
767                         "This transport does not support the registerSipDialogStateCallback"
768                                 + " of SIP delegates");
769             }
770             transport.addCallbackForSipDialogState(subId, cb);
771         } finally {
772             Binder.restoreCallingIdentity(identity);
773         }
774     }
775 
776     /**
777      * Unregister a state of Sip Dialog callback
778      */
779     @Override
unregisterSipDialogStateCallback(int subId, ISipDialogStateCallback cb)780     public  void unregisterSipDialogStateCallback(int subId, ISipDialogStateCallback cb) {
781         enforceReadPrivilegedPermission("unregisterSipDialogStateCallback");
782         if (cb == null) {
783             throw new IllegalArgumentException("SipDialogStateCallback is null");
784         }
785         final long identity = Binder.clearCallingIdentity();
786         if (!SubscriptionManager.isValidSubscriptionId(subId)) {
787             throw new IllegalArgumentException("Invalid Subscription ID: " + subId);
788         }
789 
790         enforceTelephonyFeatureWithException(getCurrentPackageName(),
791                 FEATURE_TELEPHONY_IMS_SINGLE_REGISTRATION, "unregisterSipDialogStateCallback");
792 
793         try {
794             SipTransportController transport = getRcsFeatureController(subId).getFeature(
795                     SipTransportController.class);
796             if (transport == null) {
797                 throw new ServiceSpecificException(ImsException.CODE_ERROR_SERVICE_UNAVAILABLE,
798                         "This transport does not support the unregisterSipDialogStateCallback"
799                                 + " of SIP delegates");
800             }
801             transport.removeCallbackForSipDialogState(subId, cb);
802         } finally {
803             Binder.restoreCallingIdentity(identity);
804         }
805     }
806 
807     /**
808      * Registers for updates to the RcsFeature connection through the IImsServiceFeatureCallback
809      * callback.
810      */
811     @Override
registerRcsFeatureCallback(int slotId, IImsServiceFeatureCallback callback)812     public void registerRcsFeatureCallback(int slotId, IImsServiceFeatureCallback callback) {
813         enforceModifyPermission();
814 
815         final long identity = Binder.clearCallingIdentity();
816         try {
817             if (mImsResolver == null) {
818                 throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION,
819                         "Device does not support IMS");
820             }
821             mImsResolver.listenForFeature(slotId, ImsFeature.FEATURE_RCS, callback);
822         } finally {
823             Binder.restoreCallingIdentity(identity);
824         }
825     }
826 
827     /**
828      * Unregister a previously registered IImsServiceFeatureCallback associated with an ImsFeature.
829      */
830     @Override
unregisterImsFeatureCallback(IImsServiceFeatureCallback callback)831     public void unregisterImsFeatureCallback(IImsServiceFeatureCallback callback) {
832         enforceModifyPermission();
833 
834         final long identity = Binder.clearCallingIdentity();
835         try {
836             if (mImsResolver == null) return;
837             mImsResolver.unregisterImsFeatureCallback(callback);
838         } finally {
839             Binder.restoreCallingIdentity(identity);
840         }
841     }
842 
843     /**
844      * Make sure either called from same process as self (phone) or IPC caller has read privilege.
845      *
846      * @throws SecurityException if the caller does not have the required permission
847      */
enforceReadPrivilegedPermission(String message)848     private void enforceReadPrivilegedPermission(String message) {
849         mApp.enforceCallingOrSelfPermission(
850                 android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, message);
851     }
852 
853     /**
854      * @throws SecurityException if the caller does not have the required
855      *     PERFORM_IMS_SINGLE_REGISTRATION permission.
856      */
enforceImsSingleRegistrationPermission(String message)857     private void enforceImsSingleRegistrationPermission(String message) {
858         mApp.enforceCallingOrSelfPermission(
859                 Manifest.permission.PERFORM_IMS_SINGLE_REGISTRATION, message);
860     }
861 
862     /**
863      * Make sure the caller has the MODIFY_PHONE_STATE permission.
864      *
865      * @throws SecurityException if the caller does not have the required permission
866      */
enforceModifyPermission()867     private void enforceModifyPermission() {
868         mApp.enforceCallingOrSelfPermission(android.Manifest.permission.MODIFY_PHONE_STATE, null);
869     }
870 
871     /**
872      * Make sure the caller has the ACCESS_RCS_USER_CAPABILITY_EXCHANGE permission.
873      *
874      * @throws SecurityException if the caller does not have the required permission.
875      */
enforceAccessUserCapabilityExchangePermission(String message)876     private void enforceAccessUserCapabilityExchangePermission(String message) {
877         mApp.enforceCallingOrSelfPermission(
878                 android.Manifest.permission.ACCESS_RCS_USER_CAPABILITY_EXCHANGE, message);
879     }
880 
881     /**
882      * Make sure the caller has the READ_CONTACTS permission.
883      *
884      * @throws SecurityException if the caller does not have the required permission.
885      */
enforceReadContactsPermission(String message)886     private void enforceReadContactsPermission(String message) {
887         mApp.enforceCallingOrSelfPermission(
888                 android.Manifest.permission.READ_CONTACTS, message);
889     }
890 
891     /**
892      * Retrieve RcsFeatureManager instance.
893      *
894      * @param subId the subscription ID
895      * @return The RcsFeatureManager instance
896      * @throws ServiceSpecificException if getting RcsFeatureManager instance failed.
897      */
getRcsFeatureController(int subId)898     private RcsFeatureController getRcsFeatureController(int subId) {
899         return getRcsFeatureController(subId, false /* skipVerifyingConfig */);
900     }
901 
902     /**
903      * Retrieve RcsFeatureManager instance.
904      *
905      * @param subId the subscription ID
906      * @param skipVerifyingConfig If the RCS configuration can be skip.
907      * @return The RcsFeatureManager instance
908      * @throws ServiceSpecificException if getting RcsFeatureManager instance failed.
909      */
getRcsFeatureController(int subId, boolean skipVerifyingConfig)910     private RcsFeatureController getRcsFeatureController(int subId, boolean skipVerifyingConfig) {
911         if (!ImsManager.isImsSupportedOnDevice(mApp)) {
912             throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION,
913                     "IMS is not available on device.");
914         }
915         if (mRcsService == null) {
916             throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION,
917                     "IMS is not available on device.");
918         }
919         Phone phone = PhoneGlobals.getPhone(subId);
920         if (phone == null) {
921             throw new ServiceSpecificException(ImsException.CODE_ERROR_INVALID_SUBSCRIPTION,
922                     "Invalid subscription Id: " + subId);
923         }
924         int slotId = phone.getPhoneId();
925         if (!skipVerifyingConfig) {
926             verifyImsRcsConfiguredOrThrow(slotId);
927             verifyRcsSubIdActiveOrThrow(slotId, subId);
928         }
929         RcsFeatureController c = mRcsService.getFeatureController(slotId);
930         if (c == null) {
931             // If we hit this case, we have verified that TelephonyRcsService has processed any
932             // subId changes for the associated slot and applied configs. In this case, the configs
933             // do not have the RCS feature enabled.
934             throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION,
935                     "The requested operation is not supported for subId " + subId);
936         }
937         if (!skipVerifyingConfig && c.getAssociatedSubId() != subId) {
938             // If we hit this case, the ImsFeature has not finished setting up the RCS feature yet
939             // or the RCS feature has crashed and is being set up again.
940             Log.w(TAG, "getRcsFeatureController: service unavailable on slot " + slotId
941                     + " for subId " + subId);
942             throw new ServiceSpecificException(ImsException.CODE_ERROR_SERVICE_UNAVAILABLE,
943                     "The ImsService is not currently available for subid " + subId
944                             + ", please try again");
945         }
946         return c;
947     }
948 
949     /**
950      * Ensure the TelephonyRcsService is tracking the supplied subId for the supplied slotId and has
951      * set up the stack.
952      */
verifyRcsSubIdActiveOrThrow(int slotId, int subId)953     private void verifyRcsSubIdActiveOrThrow(int slotId, int subId) {
954         if (mRcsService.verifyActiveSubId(slotId, subId)) return;
955 
956         Log.w(TAG, "verifyRcsSubIdActiveOrThrow: verify failed, service not set up yet on "
957                 + "slot " + slotId + " for subId " + subId);
958         throw new ServiceSpecificException(ImsException.CODE_ERROR_SERVICE_UNAVAILABLE,
959                 "ImsService set up in progress for subId " + subId
960                         + ", please try again");
961     }
962 
963     /**
964      * Throw an ImsException if the IMS resolver does not have an ImsService configured for RCS
965      * for the given slot ID or no ImsResolver instance has been created.
966      * @param slotId The slot ID that the IMS service is created for.
967      * @throws ServiceSpecificException If there is no ImsService configured for this slot.
968      */
verifyImsRcsConfiguredOrThrow(int slotId)969     private void verifyImsRcsConfiguredOrThrow(int slotId) {
970         if (mImsResolver == null
971                 || !mImsResolver.isImsServiceConfiguredForFeature(slotId, ImsFeature.FEATURE_RCS)) {
972             throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION,
973                     "This subscription does not support RCS");
974         }
975     }
976 
isImsSingleRegistrationSupportedOnDevice()977     private boolean isImsSingleRegistrationSupportedOnDevice() {
978         return mSingleRegistrationOverride != null ? mSingleRegistrationOverride
979                 : mApp.getPackageManager().hasSystemFeature(
980                         PackageManager.FEATURE_TELEPHONY_IMS_SINGLE_REGISTRATION);
981     }
982 
983     /**
984      * Get the current calling package name.
985      * @return the current calling package name
986      */
987     @Nullable
getCurrentPackageName()988     private String getCurrentPackageName() {
989         if (mPackageManager == null) return null;
990         String[] callingUids = mPackageManager.getPackagesForUid(Binder.getCallingUid());
991         return (callingUids == null) ? null : callingUids[0];
992     }
993 
994     /**
995      * Make sure the device has required telephony feature
996      *
997      * @throws UnsupportedOperationException if the device does not have required telephony feature
998      */
enforceTelephonyFeatureWithException(@ullable String callingPackage, @NonNull String telephonyFeature, @NonNull String methodName)999     private void enforceTelephonyFeatureWithException(@Nullable String callingPackage,
1000             @NonNull String telephonyFeature, @NonNull String methodName) {
1001         if (callingPackage == null || mPackageManager == null) {
1002             return;
1003         }
1004 
1005         if (!mFeatureFlags.enforceTelephonyFeatureMappingForPublicApis()
1006                 || !CompatChanges.isChangeEnabled(ENABLE_FEATURE_MAPPING, callingPackage,
1007                 Binder.getCallingUserHandle())
1008                 || mVendorApiLevel < Build.VERSION_CODES.VANILLA_ICE_CREAM) {
1009             // Skip to check associated telephony feature,
1010             // if compatibility change is not enabled for the current process or
1011             // the SDK version of vendor partition is less than Android V.
1012             return;
1013         }
1014 
1015         if (!mPackageManager.hasSystemFeature(telephonyFeature)) {
1016             throw new UnsupportedOperationException(
1017                     methodName + " is unsupported without " + telephonyFeature);
1018         }
1019     }
1020 
setRcsService(TelephonyRcsService rcsService)1021     void setRcsService(TelephonyRcsService rcsService) {
1022         mRcsService = rcsService;
1023     }
1024 
1025     /**
1026      * Override device RCS single registration support check for CTS testing or remove override
1027      * if the Boolean is set to null.
1028      */
setDeviceSingleRegistrationSupportOverride(Boolean deviceOverrideValue)1029     void setDeviceSingleRegistrationSupportOverride(Boolean deviceOverrideValue) {
1030         mSingleRegistrationOverride = deviceOverrideValue;
1031     }
1032 }
1033