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.aidl; 18 19 import android.os.Binder; 20 import android.os.IBinder; 21 import android.os.RemoteException; 22 import android.telephony.ims.DelegateRegistrationState; 23 import android.telephony.ims.FeatureTagState; 24 import android.telephony.ims.SipDelegateConfiguration; 25 import android.telephony.ims.SipDelegateConnection; 26 import android.telephony.ims.SipDelegateImsConfiguration; 27 import android.telephony.ims.SipDelegateManager; 28 import android.telephony.ims.SipMessage; 29 import android.telephony.ims.stub.DelegateConnectionMessageCallback; 30 import android.telephony.ims.stub.DelegateConnectionStateCallback; 31 import android.telephony.ims.stub.SipDelegate; 32 import android.util.ArraySet; 33 import android.util.Log; 34 35 import java.util.List; 36 import java.util.NoSuchElementException; 37 import java.util.concurrent.Executor; 38 import java.util.concurrent.atomic.AtomicReference; 39 40 /** 41 * Wrapper class implementing {@link SipDelegateConnection} using AIDL, which is returned to the 42 * local process. Also holds a reference to incoming connection message and state AIDL impl to 43 * trampoline events to callbacks as well as notify the local process in the event that the remote 44 * process becomes unavailable. 45 * <p> 46 * When the remote {@link SipDelegate} is created, this instance tracks the 47 * {@link ISipDelegate} associated with it and implements the 48 * {@link SipDelegateConnection} sent back to the local callback. 49 * @hide 50 */ 51 public class SipDelegateConnectionAidlWrapper implements SipDelegateConnection, 52 IBinder.DeathRecipient { 53 private static final String LOG_TAG = "SipDelegateCAW"; 54 55 private final ISipDelegateConnectionStateCallback.Stub mStateBinder = 56 new ISipDelegateConnectionStateCallback.Stub() { 57 @Override 58 public void onCreated(ISipDelegate c) { 59 associateSipDelegate(c); 60 final long token = Binder.clearCallingIdentity(); 61 try { 62 mExecutor.execute(() -> 63 mStateCallback.onCreated(SipDelegateConnectionAidlWrapper.this)); 64 } finally { 65 Binder.restoreCallingIdentity(token); 66 } 67 } 68 69 @Override 70 public void onFeatureTagStatusChanged(DelegateRegistrationState registrationState, 71 List<FeatureTagState> deniedFeatureTags) { 72 final long token = Binder.clearCallingIdentity(); 73 try { 74 mExecutor.execute(() -> 75 mStateCallback.onFeatureTagStatusChanged(registrationState, 76 new ArraySet<>(deniedFeatureTags))); 77 } finally { 78 Binder.restoreCallingIdentity(token); 79 } 80 } 81 82 @Override 83 public void onImsConfigurationChanged(SipDelegateImsConfiguration registeredSipConfig) { 84 final long token = Binder.clearCallingIdentity(); 85 try { 86 mExecutor.execute(() -> 87 mStateCallback.onImsConfigurationChanged(registeredSipConfig)); 88 } finally { 89 Binder.restoreCallingIdentity(token); 90 } 91 } 92 93 @Override 94 public void onConfigurationChanged(SipDelegateConfiguration registeredSipConfig) { 95 final long token = Binder.clearCallingIdentity(); 96 try { 97 mExecutor.execute(() -> 98 mStateCallback.onConfigurationChanged(registeredSipConfig)); 99 } finally { 100 Binder.restoreCallingIdentity(token); 101 } 102 } 103 104 @Override 105 public void onDestroyed(int reason) { 106 invalidateSipDelegateBinder(); 107 final long token = Binder.clearCallingIdentity(); 108 try { 109 mExecutor.execute(() -> 110 mStateCallback.onDestroyed(reason)); 111 } finally { 112 Binder.restoreCallingIdentity(token); 113 } 114 } 115 }; 116 117 private final ISipDelegateMessageCallback.Stub mMessageBinder = 118 new ISipDelegateMessageCallback.Stub() { 119 @Override 120 public void onMessageReceived(SipMessage message) { 121 final long token = Binder.clearCallingIdentity(); 122 try { 123 mExecutor.execute(() -> 124 mMessageCallback.onMessageReceived(message)); 125 } finally { 126 Binder.restoreCallingIdentity(token); 127 } 128 } 129 130 @Override 131 public void onMessageSent(String viaTransactionId) { 132 final long token = Binder.clearCallingIdentity(); 133 try { 134 mExecutor.execute(() -> 135 mMessageCallback.onMessageSent(viaTransactionId)); 136 } finally { 137 Binder.restoreCallingIdentity(token); 138 } 139 } 140 141 @Override 142 public void onMessageSendFailure(String viaTransactionId, int reason) { 143 final long token = Binder.clearCallingIdentity(); 144 try { 145 mExecutor.execute(() -> 146 mMessageCallback.onMessageSendFailure(viaTransactionId, reason)); 147 } finally { 148 Binder.restoreCallingIdentity(token); 149 } 150 } 151 }; 152 153 154 private final Executor mExecutor; 155 private final DelegateConnectionStateCallback mStateCallback; 156 private final DelegateConnectionMessageCallback mMessageCallback; 157 private final AtomicReference<ISipDelegate> mDelegateBinder = 158 new AtomicReference<>(); 159 160 /** 161 * Wrap the local state and message callbacks, calling the implementation of these interfaces 162 * when the remote process calls these methods. 163 */ SipDelegateConnectionAidlWrapper(Executor executor, DelegateConnectionStateCallback stateCallback, DelegateConnectionMessageCallback messageCallback)164 public SipDelegateConnectionAidlWrapper(Executor executor, 165 DelegateConnectionStateCallback stateCallback, 166 DelegateConnectionMessageCallback messageCallback) { 167 mExecutor = executor; 168 mStateCallback = stateCallback; 169 mMessageCallback = messageCallback; 170 } 171 172 @Override sendMessage(SipMessage sipMessage, long configVersion)173 public void sendMessage(SipMessage sipMessage, long configVersion) { 174 try { 175 ISipDelegate conn = getSipDelegateBinder(); 176 if (conn == null) { 177 notifyLocalMessageFailedToSend(sipMessage, 178 SipDelegateManager.MESSAGE_FAILURE_REASON_DELEGATE_CLOSED); 179 return; 180 } 181 conn.sendMessage(sipMessage, configVersion); 182 } catch (RemoteException e) { 183 notifyLocalMessageFailedToSend(sipMessage, 184 SipDelegateManager.MESSAGE_FAILURE_REASON_DELEGATE_DEAD); 185 } 186 } 187 188 @Override notifyMessageReceived(String viaTransactionId)189 public void notifyMessageReceived(String viaTransactionId) { 190 try { 191 ISipDelegate conn = getSipDelegateBinder(); 192 if (conn == null) { 193 return; 194 } 195 conn.notifyMessageReceived(viaTransactionId); 196 } catch (RemoteException e) { 197 // Nothing to do here, app will eventually get remote death callback. 198 } 199 } 200 201 @Override notifyMessageReceiveError(String viaTransactionId, int reason)202 public void notifyMessageReceiveError(String viaTransactionId, int reason) { 203 try { 204 ISipDelegate conn = getSipDelegateBinder(); 205 if (conn == null) { 206 return; 207 } 208 conn.notifyMessageReceiveError(viaTransactionId, reason); 209 } catch (RemoteException e) { 210 // Nothing to do here, app will eventually get remote death callback. 211 } 212 } 213 214 @Override cleanupSession(String callId)215 public void cleanupSession(String callId) { 216 try { 217 ISipDelegate conn = getSipDelegateBinder(); 218 if (conn == null) { 219 return; 220 } 221 conn.cleanupSession(callId); 222 } catch (RemoteException e) { 223 // Nothing to do here, app will eventually get remote death callback. 224 } 225 } 226 227 // Also called upon IImsRcsController death (telephony process dies). 228 @Override binderDied()229 public void binderDied() { 230 invalidateSipDelegateBinder(); 231 mExecutor.execute(() -> mStateCallback.onDestroyed( 232 SipDelegateManager.SIP_DELEGATE_DESTROY_REASON_SERVICE_DEAD)); 233 } 234 235 /** 236 * @return Implementation of state binder. 237 */ getStateCallbackBinder()238 public ISipDelegateConnectionStateCallback getStateCallbackBinder() { 239 return mStateBinder; 240 } 241 242 /** 243 * @return Implementation of message binder. 244 */ getMessageCallbackBinder()245 public ISipDelegateMessageCallback getMessageCallbackBinder() { 246 return mMessageBinder; 247 } 248 249 /** 250 * @return The ISipDelegateConnection associated with this wrapper. 251 */ getSipDelegateBinder()252 public ISipDelegate getSipDelegateBinder() { 253 return mDelegateBinder.get(); 254 } 255 associateSipDelegate(ISipDelegate c)256 private void associateSipDelegate(ISipDelegate c) { 257 if (c != null) { 258 try { 259 c.asBinder().linkToDeath(this, 0 /*flags*/); 260 } catch (RemoteException e) { 261 // already dead. 262 c = null; 263 } 264 } 265 mDelegateBinder.set(c); 266 } 267 invalidateSipDelegateBinder()268 private void invalidateSipDelegateBinder() { 269 ISipDelegate oldVal = mDelegateBinder.getAndUpdate((unused) -> null); 270 if (oldVal != null) { 271 try { 272 oldVal.asBinder().unlinkToDeath(this, 0 /*flags*/); 273 } catch (NoSuchElementException e) { 274 Log.i(LOG_TAG, "invalidateSipDelegateBinder: " + e); 275 } 276 } 277 } 278 notifyLocalMessageFailedToSend(SipMessage m, int reason)279 private void notifyLocalMessageFailedToSend(SipMessage m, int reason) { 280 String transactionId = m.getViaBranchParameter(); 281 mExecutor.execute(() -> mMessageCallback.onMessageSendFailure(transactionId, reason)); 282 } 283 } 284