Check to ensure an ImsService can handle an IMS request

Previously, if there was no ImsService available at the time of an
IMS request, we would send a not available exception, which is
documented to have the caller retry. This is inefficient because it
will cause apps to retry indefinitely on devices that support IMS
but do not have an ImsService configured for the active subscription.

This change adds a check in ImsResolver to first make sure there is
an ImsService configured for the ImsFeature type that the request
is for and if there isn't, we will instead send a
ImsException#CODE_ERROR_UNSUPPORTED_OPERATION error, which is a
permanent failure that apps can use to stop retrying.

Fixes: 184188331
Test: atest CtsTelephonyTestCases
Change-Id: I1b7a50c320e5bca59659561c5a0cfd928cd6e1c0
diff --git a/src/com/android/phone/ImsRcsController.java b/src/com/android/phone/ImsRcsController.java
index 2e4ee94..64e93a5 100644
--- a/src/com/android/phone/ImsRcsController.java
+++ b/src/com/android/phone/ImsRcsController.java
@@ -49,7 +49,6 @@
 import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.TelephonyPermissions;
 import com.android.internal.telephony.ims.ImsResolver;
-import com.android.internal.telephony.imsphone.ImsPhone;
 import com.android.services.telephony.rcs.RcsFeatureController;
 import com.android.services.telephony.rcs.SipTransportController;
 import com.android.services.telephony.rcs.TelephonyRcsService;
@@ -214,6 +213,8 @@
         final long token = Binder.clearCallingIdentity();
         try {
             getRcsFeatureController(subId).unregisterRcsAvailabilityCallback(subId, callback);
+        } catch (ServiceSpecificException e) {
+            Log.e(TAG, "unregisterRcsAvailabilityCallback: error=" + e.errorCode);
         } finally {
             Binder.restoreCallingIdentity(token);
         }
@@ -338,12 +339,16 @@
     public RcsContactUceCapability addUceRegistrationOverrideShell(int subId,
             Set<String> featureTags) throws ImsException {
         // Permission check happening in PhoneInterfaceManager.
-        UceControllerManager uceCtrlManager = getRcsFeatureController(subId).getFeature(
-                UceControllerManager.class);
-        if (uceCtrlManager == null) {
-            return null;
+        try {
+            UceControllerManager uceCtrlManager = getRcsFeatureController(subId).getFeature(
+                    UceControllerManager.class);
+            if (uceCtrlManager == null) {
+                return null;
+            }
+            return uceCtrlManager.addUceRegistrationOverride(featureTags);
+        } catch (ServiceSpecificException e) {
+            throw new ImsException(e.getMessage(), e.errorCode);
         }
-        return uceCtrlManager.addUceRegistrationOverride(featureTags);
     }
 
     /**
@@ -353,12 +358,16 @@
     public RcsContactUceCapability removeUceRegistrationOverrideShell(int subId,
             Set<String> featureTags) throws ImsException {
         // Permission check happening in PhoneInterfaceManager.
-        UceControllerManager uceCtrlManager = getRcsFeatureController(subId).getFeature(
-                UceControllerManager.class);
-        if (uceCtrlManager == null) {
-            return null;
+        try {
+            UceControllerManager uceCtrlManager = getRcsFeatureController(subId).getFeature(
+                    UceControllerManager.class);
+            if (uceCtrlManager == null) {
+                return null;
+            }
+            return uceCtrlManager.removeUceRegistrationOverride(featureTags);
+        } catch (ServiceSpecificException e) {
+            throw new ImsException(e.getMessage(), e.errorCode);
         }
-        return uceCtrlManager.removeUceRegistrationOverride(featureTags);
     }
 
     /**
@@ -367,13 +376,17 @@
     // Used for SHELL command only right now.
     public RcsContactUceCapability clearUceRegistrationOverrideShell(int subId)
             throws ImsException {
-        // Permission check happening in PhoneInterfaceManager.
-        UceControllerManager uceCtrlManager = getRcsFeatureController(subId).getFeature(
-                UceControllerManager.class);
-        if (uceCtrlManager == null) {
-            return null;
+        try {
+            // Permission check happening in PhoneInterfaceManager.
+            UceControllerManager uceCtrlManager = getRcsFeatureController(subId).getFeature(
+                    UceControllerManager.class);
+            if (uceCtrlManager == null) {
+                return null;
+            }
+            return uceCtrlManager.clearUceRegistrationOverride();
+        } catch (ServiceSpecificException e) {
+            throw new ImsException(e.getMessage(), e.errorCode);
         }
-        return uceCtrlManager.clearUceRegistrationOverride();
     }
 
     /**
@@ -382,13 +395,17 @@
     // Used for SHELL command only right now.
     public RcsContactUceCapability getLatestRcsContactUceCapabilityShell(int subId)
             throws ImsException {
-        // Permission check happening in PhoneInterfaceManager.
-        UceControllerManager uceCtrlManager = getRcsFeatureController(subId).getFeature(
-                UceControllerManager.class);
-        if (uceCtrlManager == null) {
-            return null;
+        try {
+            // Permission check happening in PhoneInterfaceManager.
+            UceControllerManager uceCtrlManager = getRcsFeatureController(subId).getFeature(
+                    UceControllerManager.class);
+            if (uceCtrlManager == null) {
+                return null;
+            }
+            return uceCtrlManager.getLatestRcsContactUceCapability();
+        } catch (ServiceSpecificException e) {
+            throw new ImsException(e.getMessage(), e.errorCode);
         }
-        return uceCtrlManager.getLatestRcsContactUceCapability();
     }
 
     /**
@@ -397,14 +414,18 @@
      */
     // Used for SHELL command only right now.
     public String getLastUcePidfXmlShell(int subId) throws ImsException {
-        // Permission check happening in PhoneInterfaceManager.
-        UceControllerManager uceCtrlManager = getRcsFeatureController(subId).getFeature(
-                UceControllerManager.class);
-        if (uceCtrlManager == null) {
-            return null;
+        try {
+            // Permission check happening in PhoneInterfaceManager.
+            UceControllerManager uceCtrlManager = getRcsFeatureController(subId).getFeature(
+                    UceControllerManager.class);
+            if (uceCtrlManager == null) {
+                return null;
+            }
+            String pidfXml = uceCtrlManager.getLastPidfXml();
+            return pidfXml == null ? "none" : pidfXml;
+        } catch (ServiceSpecificException e) {
+            throw new ImsException(e.getMessage(), e.errorCode);
         }
-        String pidfXml = uceCtrlManager.getLastPidfXml();
-        return pidfXml == null ? "none" : pidfXml;
     }
 
     /**
@@ -413,12 +434,16 @@
      */
     // Used for SHELL command only right now.
     public boolean removeUceRequestDisallowedStatus(int subId) throws ImsException {
-        UceControllerManager uceCtrlManager = getRcsFeatureController(subId).getFeature(
-                UceControllerManager.class);
-        if (uceCtrlManager == null) {
-            return false;
+        try {
+            UceControllerManager uceCtrlManager = getRcsFeatureController(subId).getFeature(
+                    UceControllerManager.class);
+            if (uceCtrlManager == null) {
+                return false;
+            }
+            return uceCtrlManager.removeUceRequestDisallowedStatus();
+        } catch (ServiceSpecificException e) {
+            throw new ImsException(e.getMessage(), e.errorCode);
         }
-        return uceCtrlManager.removeUceRequestDisallowedStatus();
     }
 
     /**
@@ -426,12 +451,16 @@
      */
     // Used for SHELL command only right now.
     public boolean setCapabilitiesRequestTimeout(int subId, long timeoutAfter) throws ImsException {
-        UceControllerManager uceCtrlManager = getRcsFeatureController(subId).getFeature(
-                UceControllerManager.class);
-        if (uceCtrlManager == null) {
-            return false;
+        try {
+            UceControllerManager uceCtrlManager = getRcsFeatureController(subId).getFeature(
+                    UceControllerManager.class);
+            if (uceCtrlManager == null) {
+                return false;
+            }
+            return uceCtrlManager.setCapabilitiesRequestTimeout(timeoutAfter);
+        } catch (ServiceSpecificException e) {
+            throw new ImsException(e.getMessage(), e.errorCode);
         }
-        return uceCtrlManager.setCapabilitiesRequestTimeout(timeoutAfter);
     }
 
     @Override
@@ -465,6 +494,8 @@
                         "This subscription does not support UCE.");
             }
             uceCtrlManager.unregisterPublishStateCallback(c);
+        } catch (ServiceSpecificException e) {
+            Log.e(TAG, "unregisterUcePublishStateCallback: error=" + e.errorCode);
         } finally {
             Binder.restoreCallingIdentity(token);
         }
@@ -580,6 +611,8 @@
                 return;
             }
             transport.destroySipDelegate(subId, connection, reason);
+        } catch (ServiceSpecificException e) {
+            Log.e(TAG, "destroySipDelegate: error=" + e.errorCode);
         } finally {
             Binder.restoreCallingIdentity(identity);
         }
@@ -598,6 +631,8 @@
                 return;
             }
             transport.triggerFullNetworkRegistration(subId, connection, sipCode, sipReason);
+        } catch (ServiceSpecificException e) {
+            Log.e(TAG, "triggerNetworkRegistration: error=" + e.errorCode);
         } finally {
             Binder.restoreCallingIdentity(identity);
         }
@@ -688,31 +723,6 @@
     }
 
     /**
-     * Retrieve ImsPhone instance.
-     *
-     * @param subId the subscription ID
-     * @return The ImsPhone instance
-     * @throws ServiceSpecificException if getting ImsPhone instance failed.
-     */
-    private ImsPhone getImsPhone(int subId) {
-        if (!ImsManager.isImsSupportedOnDevice(mApp)) {
-            throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION,
-                    "IMS is not available on device.");
-        }
-        Phone phone = PhoneGlobals.getPhone(subId);
-        if (phone == null) {
-            throw new ServiceSpecificException(ImsException.CODE_ERROR_INVALID_SUBSCRIPTION,
-                    "Invalid subscription Id: " + subId);
-        }
-        ImsPhone imsPhone = (ImsPhone) phone.getImsPhone();
-        if (imsPhone == null) {
-            throw new ServiceSpecificException(ImsException.CODE_ERROR_SERVICE_UNAVAILABLE,
-                    "Cannot find ImsPhone instance: " + subId);
-        }
-        return imsPhone;
-    }
-
-    /**
      * Retrieve RcsFeatureManager instance.
      *
      * @param subId the subscription ID
@@ -734,6 +744,7 @@
                     "Invalid subscription Id: " + subId);
         }
         int slotId = phone.getPhoneId();
+        verifyImsRcsConfiguredOrThrow(slotId);
         RcsFeatureController c = mRcsService.getFeatureController(slotId);
         if (c == null) {
             throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION,
@@ -742,6 +753,20 @@
         return c;
     }
 
+    /**
+     * Throw an ImsException if the IMS resolver does not have an ImsService configured for RCS
+     * for the given slot ID or no ImsResolver instance has been created.
+     * @param slotId The slot ID that the IMS service is created for.
+     * @throws ServiceSpecificException If there is no ImsService configured for this slot.
+     */
+    private void verifyImsRcsConfiguredOrThrow(int slotId) {
+        if (mImsResolver == null
+                || !mImsResolver.isImsServiceConfiguredForFeature(slotId, ImsFeature.FEATURE_RCS)) {
+            throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION,
+                    "This subscription does not support RCS");
+        }
+    }
+
     private boolean isImsSingleRegistrationSupportedOnDevice() {
         return mSingleRegistrationOverride != null ? mSingleRegistrationOverride
                 : mApp.getPackageManager().hasSystemFeature(