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