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.stub; 18 19 import android.annotation.NonNull; 20 import android.annotation.SuppressLint; 21 import android.annotation.SystemApi; 22 import android.os.Binder; 23 import android.os.IBinder; 24 import android.os.RemoteException; 25 import android.telephony.ims.DelegateMessageCallback; 26 import android.telephony.ims.DelegateRequest; 27 import android.telephony.ims.DelegateStateCallback; 28 import android.telephony.ims.SipDelegateManager; 29 import android.telephony.ims.aidl.ISipDelegate; 30 import android.telephony.ims.aidl.ISipDelegateMessageCallback; 31 import android.telephony.ims.aidl.ISipDelegateStateCallback; 32 import android.telephony.ims.aidl.ISipTransport; 33 import android.telephony.ims.aidl.SipDelegateAidlWrapper; 34 import android.util.Log; 35 36 import java.util.ArrayList; 37 import java.util.NoSuchElementException; 38 import java.util.Objects; 39 import java.util.concurrent.Executor; 40 41 /** 42 * The ImsService implements this class to manage the creation and destruction of 43 * {@link SipDelegate}s. 44 * 45 * {@link SipDelegate}s allow the ImsService to forward SIP traffic generated and consumed by IMS 46 * applications as a delegate to the associated carrier's IMS Network in order to support using a 47 * single IMS registration for all MMTEL and RCS signalling traffic. 48 * @hide 49 */ 50 @SystemApi 51 public class SipTransportImplBase { 52 private static final String LOG_TAG = "SipTransportIB"; 53 54 private final IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() { 55 @Override 56 public void binderDied() { 57 // Clean up all binders in this case. 58 mBinderExecutor.execute(() -> binderDiedInternal(null)); 59 } 60 @Override 61 public void binderDied(IBinder who) { 62 mBinderExecutor.execute(() -> binderDiedInternal(who)); 63 } 64 }; 65 66 private final ISipTransport.Stub mSipTransportImpl = new ISipTransport.Stub() { 67 @Override 68 public void createSipDelegate(int subId, DelegateRequest request, 69 ISipDelegateStateCallback dc, ISipDelegateMessageCallback mc) { 70 final long token = Binder.clearCallingIdentity(); 71 try { 72 mBinderExecutor.execute(() -> createSipDelegateInternal(subId, request, dc, mc)); 73 } finally { 74 Binder.restoreCallingIdentity(token); 75 } 76 } 77 78 @Override 79 public void destroySipDelegate(ISipDelegate delegate, int reason) { 80 final long token = Binder.clearCallingIdentity(); 81 try { 82 mBinderExecutor.execute(() -> destroySipDelegateInternal(delegate, reason)); 83 } finally { 84 Binder.restoreCallingIdentity(token); 85 } 86 } 87 }; 88 89 private final Executor mBinderExecutor; 90 private final ArrayList<SipDelegateAidlWrapper> mDelegates = new ArrayList<>(); 91 92 /** 93 * Create an implementation of SipTransportImplBase. 94 * 95 * @param executor The executor that remote calls from the framework will be called on. This 96 * includes the methods here as well as the methods in {@link SipDelegate}. 97 */ SipTransportImplBase(@onNull Executor executor)98 public SipTransportImplBase(@NonNull Executor executor) { 99 if (executor == null) { 100 throw new IllegalArgumentException("executor must not be null"); 101 } 102 103 mBinderExecutor = executor; 104 } 105 106 /** 107 * Called by the Telephony framework to request the creation of a new {@link SipDelegate}. 108 * <p> 109 * The implementation must call 110 * {@link DelegateStateCallback#onCreated(SipDelegate, java.util.Set)} with 111 * the {@link SipDelegate} that is associated with the {@link DelegateRequest}. 112 * <p> 113 * This method will be called on the Executor specified in 114 * {@link SipTransportImplBase#SipTransportImplBase(Executor)}. 115 * 116 * @param subscriptionId The subscription ID associated with the requested {@link SipDelegate}. 117 * @param request A SIP delegate request containing the parameters that the remote RCS 118 * application wishes to use. 119 * @param dc A callback back to the remote application to be used to communicate state callbacks 120 * for the SipDelegate. 121 * @param mc A callback back to the remote application to be used to send SIP messages to the 122 * remote application and acknowledge the sending of outgoing SIP messages. 123 */ 124 // executor used is defined in the constructor. 125 @SuppressLint("ExecutorRegistration") createSipDelegate(int subscriptionId, @NonNull DelegateRequest request, @NonNull DelegateStateCallback dc, @NonNull DelegateMessageCallback mc)126 public void createSipDelegate(int subscriptionId, @NonNull DelegateRequest request, 127 @NonNull DelegateStateCallback dc, @NonNull DelegateMessageCallback mc) { 128 throw new UnsupportedOperationException("createSipDelegate not implemented!"); 129 } 130 131 /** 132 * Destroys the SipDelegate associated with a remote IMS application. 133 * <p> 134 * After the delegate is destroyed, {@link DelegateStateCallback#onDestroyed(int)} must be 135 * called to notify listeners of its destruction to release associated resources. 136 * <p> 137 * This method will be called on the Executor specified in 138 * {@link SipTransportImplBase#SipTransportImplBase(Executor)}. 139 * @param delegate The delegate to be destroyed. 140 * @param reason The reason the remote connection to this {@link SipDelegate} is being 141 * destroyed. 142 */ destroySipDelegate(@onNull SipDelegate delegate, @SipDelegateManager.SipDelegateDestroyReason int reason)143 public void destroySipDelegate(@NonNull SipDelegate delegate, 144 @SipDelegateManager.SipDelegateDestroyReason int reason) { 145 throw new UnsupportedOperationException("destroySipDelegate not implemented!"); 146 } 147 createSipDelegateInternal(int subId, DelegateRequest r, ISipDelegateStateCallback cb, ISipDelegateMessageCallback mc)148 private void createSipDelegateInternal(int subId, DelegateRequest r, 149 ISipDelegateStateCallback cb, ISipDelegateMessageCallback mc) { 150 SipDelegateAidlWrapper wrapper = new SipDelegateAidlWrapper(mBinderExecutor, cb, mc); 151 mDelegates.add(wrapper); 152 linkDeathRecipient(wrapper); 153 createSipDelegate(subId, r, wrapper, wrapper); 154 } 155 destroySipDelegateInternal(ISipDelegate d, int reason)156 private void destroySipDelegateInternal(ISipDelegate d, int reason) { 157 SipDelegateAidlWrapper result = null; 158 for (SipDelegateAidlWrapper w : mDelegates) { 159 if (Objects.equals(d, w.getDelegateBinder())) { 160 result = w; 161 break; 162 } 163 } 164 165 if (result != null) { 166 unlinkDeathRecipient(result); 167 mDelegates.remove(result); 168 destroySipDelegate(result.getDelegate(), reason); 169 } else { 170 Log.w(LOG_TAG, "destroySipDelegateInternal, could not findSipDelegate corresponding to " 171 + d); 172 } 173 } 174 linkDeathRecipient(SipDelegateAidlWrapper w)175 private void linkDeathRecipient(SipDelegateAidlWrapper w) { 176 try { 177 w.getStateCallbackBinder().asBinder().linkToDeath(mDeathRecipient, 0); 178 } catch (RemoteException e) { 179 Log.w(LOG_TAG, "linkDeathRecipient, remote process already died, cleaning up."); 180 mDeathRecipient.binderDied(w.getStateCallbackBinder().asBinder()); 181 } 182 } 183 unlinkDeathRecipient(SipDelegateAidlWrapper w)184 private void unlinkDeathRecipient(SipDelegateAidlWrapper w) { 185 try { 186 w.getStateCallbackBinder().asBinder().unlinkToDeath(mDeathRecipient, 0); 187 } catch (NoSuchElementException e) { 188 // Ignore this case. 189 } 190 } 191 binderDiedInternal(IBinder who)192 private void binderDiedInternal(IBinder who) { 193 for (SipDelegateAidlWrapper w : mDelegates) { 194 // If the binder itself was not given from the platform, just clean up all binders. 195 if (who == null || w.getStateCallbackBinder().asBinder().equals(who)) { 196 Log.w(LOG_TAG, "Binder death detected for " + w + ", calling destroy and " 197 + "removing."); 198 mDelegates.remove(w); 199 destroySipDelegate(w.getDelegate(), 200 SipDelegateManager.SIP_DELEGATE_DESTROY_REASON_SERVICE_DEAD); 201 return; 202 } 203 } 204 Log.w(LOG_TAG, "Binder death detected for IBinder " + who + ", but couldn't find matching " 205 + "SipDelegate"); 206 } 207 208 /** 209 * @return The IInterface used by the framework. 210 * @hide 211 */ getBinder()212 public ISipTransport getBinder() { 213 return mSipTransportImpl; 214 } 215 } 216