1 /*
2  * Copyright (C) 2020 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 android.telephony.ims;
18 
19 import android.Manifest;
20 import android.annotation.IntDef;
21 import android.annotation.IntRange;
22 import android.annotation.NonNull;
23 import android.annotation.Nullable;
24 import android.annotation.RequiresPermission;
25 import android.annotation.SystemApi;
26 import android.content.Context;
27 import android.content.pm.PackageManager;
28 import android.os.RemoteException;
29 import android.os.ServiceSpecificException;
30 import android.telephony.BinderCacheManager;
31 import android.telephony.CarrierConfigManager;
32 import android.telephony.ims.aidl.IImsRcsController;
33 import android.telephony.ims.aidl.SipDelegateConnectionAidlWrapper;
34 import android.telephony.ims.stub.DelegateConnectionMessageCallback;
35 import android.telephony.ims.stub.DelegateConnectionStateCallback;
36 import android.telephony.ims.stub.SipDelegate;
37 import android.util.ArrayMap;
38 
39 import com.android.internal.annotations.VisibleForTesting;
40 
41 import java.lang.annotation.Retention;
42 import java.lang.annotation.RetentionPolicy;
43 import java.util.Objects;
44 import java.util.concurrent.Executor;
45 
46 /**
47  * Manages the creation and destruction of SipDelegates for the {@link ImsService} managing IMS
48  * for the subscription ID that this SipDelegateManager has been created for.
49  *
50  * This allows multiple IMS applications to forward SIP messages to/from their application for the
51  * purposes of providing a single IMS registration to the carrier's IMS network from potentially
52  * many IMS stacks implementing a subset of the supported MMTEL/RCS features.
53  * <p>
54  * This API is only supported if the device supports the
55  * {@link PackageManager#FEATURE_TELEPHONY_IMS_SINGLE_REGISTRATION} feature.
56  * @hide
57  */
58 @SystemApi
59 public class SipDelegateManager {
60 
61     /**
62      * The SIP message has failed being sent or received for an unknown reason.
63      * <p>
64      * The caller should retry a message that failed with this response.
65      */
66     public static final int MESSAGE_FAILURE_REASON_UNKNOWN = 0;
67 
68     /**
69      * The remote service associated with this connection has died and the message was not
70      * properly sent/received.
71      * <p>
72      * This is considered a permanent error and the system will automatically begin the teardown and
73      * destruction of the SipDelegate. No further messages should be sent on this transport.
74      */
75     public static final int MESSAGE_FAILURE_REASON_DELEGATE_DEAD = 1;
76 
77     /**
78      * The message has not been sent/received because the delegate is in the process of closing and
79      * has become unavailable. No further messages should be sent/received on this delegate.
80      */
81     public static final int MESSAGE_FAILURE_REASON_DELEGATE_CLOSED = 2;
82 
83     /**
84      * The SIP message has an invalid start line and the message can not be sent or the start line
85      * failed validation due to the request containing a restricted SIP request method.
86      * {@link SipDelegateConnection}s can not send SIP requests for the methods: REGISTER, PUBLISH,
87      * or OPTIONS.
88      */
89     public static final int MESSAGE_FAILURE_REASON_INVALID_START_LINE = 3;
90 
91     /**
92      * One or more of the header fields in the header section of the outgoing SIP message is invalid
93      * or contains a restricted header value and the SIP message can not be sent.
94      * {@link SipDelegateConnection}s can not send SIP SUBSCRIBE requests for the "Event" header
95      * value of "presence".
96      */
97     public static final int MESSAGE_FAILURE_REASON_INVALID_HEADER_FIELDS = 4;
98 
99     /**
100      * The body content of the SIP message is invalid and the message can not be sent.
101      */
102     public static final int MESSAGE_FAILURE_REASON_INVALID_BODY_CONTENT = 5;
103 
104     /**
105      * The feature tag associated with the outgoing message does not match any known feature tags
106      * or it matches a denied tag and this message can not be sent.
107      */
108     public static final int MESSAGE_FAILURE_REASON_INVALID_FEATURE_TAG = 6;
109 
110     /**
111      * The feature tag associated with the outgoing message is not enabled for the associated
112      * SipDelegateConnection and can not be sent.
113      */
114     public static final int MESSAGE_FAILURE_REASON_TAG_NOT_ENABLED_FOR_DELEGATE = 7;
115 
116     /**
117      * The link to the network has been lost and the outgoing message has failed to send.
118      * <p>
119      * This message should be retried when connectivity to the network is re-established. See
120      * {@link android.net.ConnectivityManager.NetworkCallback} for how this can be determined.
121      */
122     public static final int MESSAGE_FAILURE_REASON_NETWORK_NOT_AVAILABLE = 8;
123 
124     /**
125      * The outgoing SIP message has not been sent due to the SipDelegate not being registered for
126      * IMS at this time.
127      * <p>
128      * This is considered a temporary failure, the message should not be retried until an IMS
129      * registration change callback is received via
130      * {@link DelegateConnectionStateCallback#onFeatureTagStatusChanged}
131      */
132     public static final int MESSAGE_FAILURE_REASON_NOT_REGISTERED = 9;
133 
134     /**
135      * The outgoing SIP message has not been sent because the {@link SipDelegateConfiguration}
136      * version associated with the outgoing {@link SipMessage} is now stale and has failed
137      * validation checks.
138      * <p>
139      * The @link SipMessage} should be recreated using the newest
140      * {@link SipDelegateConfiguration} and sent again.
141      */
142     public static final int MESSAGE_FAILURE_REASON_STALE_IMS_CONFIGURATION = 10;
143 
144     /**
145      * The outgoing SIP message has not been sent because the internal state of the associated
146      * {@link SipDelegate} is changing and has temporarily brought the transport down.
147      * <p>
148      * This is considered a temporary error and the {@link SipDelegateConnection} should resend the
149      * message once {@link DelegateRegistrationState#DEREGISTERING_REASON_FEATURE_TAGS_CHANGING} is
150      * no longer reported.
151      */
152     public static final int MESSAGE_FAILURE_REASON_INTERNAL_DELEGATE_STATE_TRANSITION = 11;
153 
154     /** @hide */
155     @Retention(RetentionPolicy.SOURCE)
156     @IntDef(prefix = "MESSAGE_FAILURE_REASON_", value = {
157             MESSAGE_FAILURE_REASON_UNKNOWN,
158             MESSAGE_FAILURE_REASON_DELEGATE_DEAD,
159             MESSAGE_FAILURE_REASON_DELEGATE_CLOSED,
160             MESSAGE_FAILURE_REASON_INVALID_START_LINE,
161             MESSAGE_FAILURE_REASON_INVALID_HEADER_FIELDS,
162             MESSAGE_FAILURE_REASON_INVALID_BODY_CONTENT,
163             MESSAGE_FAILURE_REASON_INVALID_FEATURE_TAG,
164             MESSAGE_FAILURE_REASON_TAG_NOT_ENABLED_FOR_DELEGATE,
165             MESSAGE_FAILURE_REASON_NETWORK_NOT_AVAILABLE,
166             MESSAGE_FAILURE_REASON_NOT_REGISTERED,
167             MESSAGE_FAILURE_REASON_STALE_IMS_CONFIGURATION,
168             MESSAGE_FAILURE_REASON_INTERNAL_DELEGATE_STATE_TRANSITION
169     })
170     public @interface MessageFailureReason {}
171 
172     /**@hide*/
173     public static final ArrayMap<Integer, String> MESSAGE_FAILURE_REASON_STRING_MAP =
174             new ArrayMap<>(11);
175     static {
MESSAGE_FAILURE_REASON_STRING_MAP.append(MESSAGE_FAILURE_REASON_UNKNOWN, R)176         MESSAGE_FAILURE_REASON_STRING_MAP.append(MESSAGE_FAILURE_REASON_UNKNOWN,
177                 "MESSAGE_FAILURE_REASON_UNKNOWN");
MESSAGE_FAILURE_REASON_STRING_MAP.append(MESSAGE_FAILURE_REASON_DELEGATE_DEAD, R)178         MESSAGE_FAILURE_REASON_STRING_MAP.append(MESSAGE_FAILURE_REASON_DELEGATE_DEAD,
179                 "MESSAGE_FAILURE_REASON_DELEGATE_DEAD");
MESSAGE_FAILURE_REASON_STRING_MAP.append(MESSAGE_FAILURE_REASON_DELEGATE_CLOSED, R)180         MESSAGE_FAILURE_REASON_STRING_MAP.append(MESSAGE_FAILURE_REASON_DELEGATE_CLOSED,
181                 "MESSAGE_FAILURE_REASON_DELEGATE_CLOSED");
MESSAGE_FAILURE_REASON_STRING_MAP.append(MESSAGE_FAILURE_REASON_INVALID_HEADER_FIELDS, R)182         MESSAGE_FAILURE_REASON_STRING_MAP.append(MESSAGE_FAILURE_REASON_INVALID_HEADER_FIELDS,
183                 "MESSAGE_FAILURE_REASON_INVALID_HEADER_FIELDS");
MESSAGE_FAILURE_REASON_STRING_MAP.append(MESSAGE_FAILURE_REASON_INVALID_BODY_CONTENT, R)184         MESSAGE_FAILURE_REASON_STRING_MAP.append(MESSAGE_FAILURE_REASON_INVALID_BODY_CONTENT,
185                 "MESSAGE_FAILURE_REASON_INVALID_BODY_CONTENT");
MESSAGE_FAILURE_REASON_STRING_MAP.append(MESSAGE_FAILURE_REASON_INVALID_FEATURE_TAG, R)186         MESSAGE_FAILURE_REASON_STRING_MAP.append(MESSAGE_FAILURE_REASON_INVALID_FEATURE_TAG,
187                 "MESSAGE_FAILURE_REASON_INVALID_FEATURE_TAG");
MESSAGE_FAILURE_REASON_STRING_MAP.append( MESSAGE_FAILURE_REASON_TAG_NOT_ENABLED_FOR_DELEGATE, R)188         MESSAGE_FAILURE_REASON_STRING_MAP.append(
189                 MESSAGE_FAILURE_REASON_TAG_NOT_ENABLED_FOR_DELEGATE,
190                 "MESSAGE_FAILURE_REASON_TAG_NOT_ENABLED_FOR_DELEGATE");
MESSAGE_FAILURE_REASON_STRING_MAP.append(MESSAGE_FAILURE_REASON_NETWORK_NOT_AVAILABLE, R)191         MESSAGE_FAILURE_REASON_STRING_MAP.append(MESSAGE_FAILURE_REASON_NETWORK_NOT_AVAILABLE,
192                 "MESSAGE_FAILURE_REASON_NETWORK_NOT_AVAILABLE");
MESSAGE_FAILURE_REASON_STRING_MAP.append(MESSAGE_FAILURE_REASON_NOT_REGISTERED, R)193         MESSAGE_FAILURE_REASON_STRING_MAP.append(MESSAGE_FAILURE_REASON_NOT_REGISTERED,
194                 "MESSAGE_FAILURE_REASON_NOT_REGISTERED");
MESSAGE_FAILURE_REASON_STRING_MAP.append(MESSAGE_FAILURE_REASON_STALE_IMS_CONFIGURATION, R)195         MESSAGE_FAILURE_REASON_STRING_MAP.append(MESSAGE_FAILURE_REASON_STALE_IMS_CONFIGURATION,
196                 "MESSAGE_FAILURE_REASON_STALE_IMS_CONFIGURATION");
MESSAGE_FAILURE_REASON_STRING_MAP.append( MESSAGE_FAILURE_REASON_INTERNAL_DELEGATE_STATE_TRANSITION, R)197         MESSAGE_FAILURE_REASON_STRING_MAP.append(
198                 MESSAGE_FAILURE_REASON_INTERNAL_DELEGATE_STATE_TRANSITION,
199                 "MESSAGE_FAILURE_REASON_INTERNAL_DELEGATE_STATE_TRANSITION");
200     }
201 
202     /**
203      * Access to use this feature tag has been denied for an unknown reason.
204      */
205     public static final int DENIED_REASON_UNKNOWN = 0;
206 
207     /**
208      * This feature tag is allowed to be used by this SipDelegateConnection, but it is in use by
209      * another SipDelegateConnection and can not be associated with this delegate. The feature tag
210      * will stay in this state until the feature tag is release by the other application.
211      */
212     public static final int DENIED_REASON_IN_USE_BY_ANOTHER_DELEGATE = 1;
213 
214     /**
215      * Access to use this feature tag has been denied because this application does not have the
216      * permissions required to access this feature tag.
217      */
218     public static final int DENIED_REASON_NOT_ALLOWED = 2;
219 
220     /**
221      * Access to use this feature tag has been denied because single registration is not allowed by
222      * the carrier at this time. The application should fall back to dual registration if
223      * applicable.
224      */
225     public static final int DENIED_REASON_SINGLE_REGISTRATION_NOT_ALLOWED = 3;
226 
227     /**
228      * This feature tag is not recognized as a valid feature tag by the SipDelegate and has been
229      * denied.
230      */
231     public static final int DENIED_REASON_INVALID = 4;
232 
233     /** @hide */
234     @Retention(RetentionPolicy.SOURCE)
235     @IntDef(prefix = "DENIED_REASON_", value = {
236             DENIED_REASON_UNKNOWN,
237             DENIED_REASON_IN_USE_BY_ANOTHER_DELEGATE,
238             DENIED_REASON_NOT_ALLOWED,
239             DENIED_REASON_SINGLE_REGISTRATION_NOT_ALLOWED,
240             DENIED_REASON_INVALID
241     })
242     public @interface DeniedReason {}
243 
244     /**
245      * The SipDelegate has closed due to an unknown reason.
246      */
247     public static final int SIP_DELEGATE_DESTROY_REASON_UNKNOWN = 0;
248 
249     /**
250      * The SipDelegate has closed because the IMS service has died unexpectedly.
251      */
252     public static final int SIP_DELEGATE_DESTROY_REASON_SERVICE_DEAD = 1;
253 
254     /**
255      * The SipDelegate has closed because the IMS application has requested that the connection be
256      * destroyed.
257      */
258     public static final int SIP_DELEGATE_DESTROY_REASON_REQUESTED_BY_APP = 2;
259 
260     /**
261      * The SipDelegate has been closed due to the user disabling RCS.
262      */
263     public static final int SIP_DELEGATE_DESTROY_REASON_USER_DISABLED_RCS = 3;
264 
265     /**
266      * The SipDelegate has been closed due to the subscription associated with this delegate being
267      * torn down.
268      */
269     public static final int SIP_DELEGATE_DESTROY_REASON_SUBSCRIPTION_TORN_DOWN = 4;
270 
271     /** @hide */
272     @Retention(RetentionPolicy.SOURCE)
273     @IntDef(prefix = "SIP_DELEGATE_DESTROY_REASON", value = {
274             SIP_DELEGATE_DESTROY_REASON_UNKNOWN,
275             SIP_DELEGATE_DESTROY_REASON_SERVICE_DEAD,
276             SIP_DELEGATE_DESTROY_REASON_REQUESTED_BY_APP,
277             SIP_DELEGATE_DESTROY_REASON_USER_DISABLED_RCS,
278             SIP_DELEGATE_DESTROY_REASON_SUBSCRIPTION_TORN_DOWN
279     })
280     public @interface SipDelegateDestroyReason {}
281 
282     private final Context mContext;
283     private final int mSubId;
284     private final BinderCacheManager<IImsRcsController> mBinderCache;
285 
286     /**
287      * Only visible for testing. To instantiate an instance of this class, please use
288      * {@link ImsManager#getSipDelegateManager(int)}.
289      * @hide
290      */
291     @VisibleForTesting
SipDelegateManager(Context context, int subId, BinderCacheManager<IImsRcsController> binderCache)292     public SipDelegateManager(Context context, int subId,
293             BinderCacheManager<IImsRcsController> binderCache) {
294         mContext = context;
295         mSubId = subId;
296         mBinderCache = binderCache;
297     }
298 
299     /**
300      * Determines if creating SIP delegates are supported for the subscription specified.
301      * <p>
302      * If SIP delegates are not supported on this device or the carrier associated with this
303      * subscription, creating a SIP delegate will always fail, as this feature is not supported.
304      * @return true if this device supports creating a SIP delegate and the carrier associated with
305      * this subscription supports single registration, false if creating SIP delegates is not
306      * supported.
307      * @throws ImsException If the remote ImsService is not available for any reason or the
308      * subscription associated with this instance is no longer active. See
309      * {@link ImsException#getCode()} for more information.
310      *
311      * @see CarrierConfigManager.Ims#KEY_IMS_SINGLE_REGISTRATION_REQUIRED_BOOL
312      * @see PackageManager#FEATURE_TELEPHONY_IMS_SINGLE_REGISTRATION
313      */
314     @RequiresPermission(anyOf = {Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
315             Manifest.permission.PERFORM_IMS_SINGLE_REGISTRATION})
isSupported()316     public boolean isSupported() throws ImsException {
317         try {
318             IImsRcsController controller = mBinderCache.getBinder();
319             if (controller == null) {
320                 throw new ImsException("Telephony server is down",
321                         ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
322             }
323             return controller.isSipDelegateSupported(mSubId);
324         } catch (ServiceSpecificException e) {
325             throw new ImsException(e.getMessage(), e.errorCode);
326         } catch (RemoteException e) {
327             throw new ImsException(e.getMessage(),
328                     ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
329         }
330     }
331 
332     /**
333      * Request that the ImsService implementation create a SipDelegate, which will configure the
334      * ImsService to forward SIP traffic that matches the filtering criteria set in supplied
335      * {@link DelegateRequest} to the application that the supplied callbacks are registered for.
336      * <p>
337      * This API requires that the caller is running as part of a long-running process and will
338      * always be available to handle incoming messages. One mechanism that can be used for this is
339      * the {@link android.service.carrier.CarrierMessagingClientService}, which the framework keeps
340      * a persistent binding to when the app is the default SMS application.
341      * <p>
342      * Note: the ability to create SipDelegates is only available applications running as the
343      * primary user.
344      * @param request The parameters that are associated with the SipDelegate creation request that
345      *                will be used to create the SipDelegate connection.
346      * @param executor The executor that will be used to call the callbacks associated with this
347      *          SipDelegate.
348      * @param dc The callback that will be used to notify the listener of the creation/destruction
349      *           of the remote SipDelegate as well as changes to the state of the remote SipDelegate
350      *           connection.
351      * @param mc The callback that will be used to notify the listener of new incoming SIP messages
352      *           as well as the status of messages that were sent by the associated
353      *           SipDelegateConnection.
354      * @throws ImsException Thrown if there was a problem communicating with the ImsService
355      * associated with this SipDelegateManager. See {@link ImsException#getCode()}.
356      */
357     @RequiresPermission(Manifest.permission.PERFORM_IMS_SINGLE_REGISTRATION)
createSipDelegate(@onNull DelegateRequest request, @NonNull Executor executor, @NonNull DelegateConnectionStateCallback dc, @NonNull DelegateConnectionMessageCallback mc)358     public void createSipDelegate(@NonNull DelegateRequest request, @NonNull Executor executor,
359             @NonNull DelegateConnectionStateCallback dc,
360             @NonNull DelegateConnectionMessageCallback mc) throws ImsException {
361         Objects.requireNonNull(request, "The DelegateRequest must not be null.");
362         Objects.requireNonNull(executor, "The Executor must not be null.");
363         Objects.requireNonNull(dc, "The DelegateConnectionStateCallback must not be null.");
364         Objects.requireNonNull(mc, "The DelegateConnectionMessageCallback must not be null.");
365         try {
366             SipDelegateConnectionAidlWrapper wrapper =
367                     new SipDelegateConnectionAidlWrapper(executor, dc, mc);
368             IImsRcsController controller = mBinderCache.listenOnBinder(wrapper,
369                     wrapper::binderDied);
370             if (controller == null) {
371                 throw new ImsException("Telephony server is down",
372                         ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
373             }
374             controller.createSipDelegate(mSubId, request, mContext.getOpPackageName(),
375                     wrapper.getStateCallbackBinder(), wrapper.getMessageCallbackBinder());
376         } catch (ServiceSpecificException e) {
377             throw new ImsException(e.getMessage(), e.errorCode);
378         } catch (RemoteException e) {
379             throw new ImsException(e.getMessage(),
380                     ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
381         }
382     }
383 
384     /**
385      * Destroy a previously created {@link SipDelegateConnection} that was created using
386      * {@link #createSipDelegate}.
387      * <p>
388      * This will also clean up all related callbacks in the associated ImsService.
389      * @param delegateConnection The SipDelegateConnection to destroy.
390      * @param reason The reason for why this SipDelegateConnection was destroyed.
391      */
392     @RequiresPermission(Manifest.permission.PERFORM_IMS_SINGLE_REGISTRATION)
destroySipDelegate(@onNull SipDelegateConnection delegateConnection, @SipDelegateDestroyReason int reason)393     public void destroySipDelegate(@NonNull SipDelegateConnection delegateConnection,
394             @SipDelegateDestroyReason int reason) {
395         Objects.requireNonNull(delegateConnection, "SipDelegateConnection can not be null.");
396         if (delegateConnection instanceof SipDelegateConnectionAidlWrapper) {
397             SipDelegateConnectionAidlWrapper w =
398                     (SipDelegateConnectionAidlWrapper) delegateConnection;
399             try {
400                 IImsRcsController c = mBinderCache.removeRunnable(w);
401                 c.destroySipDelegate(mSubId, w.getSipDelegateBinder(), reason);
402             } catch (RemoteException e) {
403                 // Connection to telephony died, but this will signal destruction of SipDelegate
404                 // eventually anyway, so return normally.
405                 try {
406                     w.getStateCallbackBinder().onDestroyed(
407                             SipDelegateManager.SIP_DELEGATE_DESTROY_REASON_REQUESTED_BY_APP);
408                 } catch (RemoteException ignore) {
409                     // Local to process.
410                 }
411             }
412         } else {
413             throw new IllegalArgumentException("Unknown SipDelegateConnection implementation passed"
414                     + " into this method");
415         }
416     }
417 
418     /**
419      * Trigger a full network registration as required by receiving a SIP message containing a
420      * permanent error from the network or never receiving a response to a SIP transaction request.
421      *
422      * @param connection The {@link SipDelegateConnection} that was being used when this error was
423      *         received.
424      * @param sipCode The SIP code response associated with the SIP message request that
425      *         triggered this condition.
426      * @param sipReason The SIP reason code associated with the SIP message request that triggered
427      *         this condition. May be {@code null} if there was no reason String provided from the
428      *         network.
429      */
430     @RequiresPermission(Manifest.permission.PERFORM_IMS_SINGLE_REGISTRATION)
triggerFullNetworkRegistration(@onNull SipDelegateConnection connection, @IntRange(from = 100, to = 699) int sipCode, @Nullable String sipReason)431     public void triggerFullNetworkRegistration(@NonNull SipDelegateConnection connection,
432             @IntRange(from = 100, to = 699) int sipCode, @Nullable String sipReason) {
433         Objects.requireNonNull(connection, "SipDelegateConnection can not be null.");
434         if (connection instanceof SipDelegateConnectionAidlWrapper) {
435             SipDelegateConnectionAidlWrapper w = (SipDelegateConnectionAidlWrapper) connection;
436             try {
437                 IImsRcsController controller = mBinderCache.getBinder();
438                 controller.triggerNetworkRegistration(mSubId, w.getSipDelegateBinder(), sipCode,
439                         sipReason);
440             } catch (RemoteException e) {
441                 // Connection to telephony died, but this will signal destruction of SipDelegate
442                 // eventually anyway, so return.
443             }
444         } else {
445             throw new IllegalArgumentException("Unknown SipDelegateConnection implementation passed"
446                     + " into this method");
447         }
448     }
449 }
450