1 /*
2  * Copyright (C) 2010 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 com.android.server.sip;
18 
19 import android.net.sip.ISipSession;
20 import android.net.sip.ISipSessionListener;
21 import android.net.sip.SipProfile;
22 import android.os.DeadObjectException;
23 import android.telephony.Rlog;
24 
25 /** Class to help safely run a callback in a different thread. */
26 class SipSessionListenerProxy extends ISipSessionListener.Stub {
27     private static final String TAG = "SipSessionListnerProxy";
28 
29     private ISipSessionListener mListener;
30 
setListener(ISipSessionListener listener)31     public void setListener(ISipSessionListener listener) {
32         mListener = listener;
33     }
34 
getListener()35     public ISipSessionListener getListener() {
36         return mListener;
37     }
38 
proxy(Runnable runnable)39     private void proxy(Runnable runnable) {
40         // One thread for each calling back.
41         // Note: Guarantee ordering if the issue becomes important. Currently,
42         // the chance of handling two callback events at a time is none.
43         new Thread(runnable, "SipSessionCallbackThread").start();
44     }
45 
46     @Override
onCalling(final ISipSession session)47     public void onCalling(final ISipSession session) {
48         if (mListener == null) return;
49         proxy(new Runnable() {
50             @Override
51             public void run() {
52                 try {
53                     mListener.onCalling(session);
54                 } catch (Throwable t) {
55                     handle(t, "onCalling()");
56                 }
57             }
58         });
59     }
60 
61     @Override
onRinging(final ISipSession session, final SipProfile caller, final String sessionDescription)62     public void onRinging(final ISipSession session, final SipProfile caller,
63             final String sessionDescription) {
64         if (mListener == null) return;
65         proxy(new Runnable() {
66             @Override
67             public void run() {
68                 try {
69                     mListener.onRinging(session, caller, sessionDescription);
70                 } catch (Throwable t) {
71                     handle(t, "onRinging()");
72                 }
73             }
74         });
75     }
76 
77     @Override
onRingingBack(final ISipSession session)78     public void onRingingBack(final ISipSession session) {
79         if (mListener == null) return;
80         proxy(new Runnable() {
81             @Override
82             public void run() {
83                 try {
84                     mListener.onRingingBack(session);
85                 } catch (Throwable t) {
86                     handle(t, "onRingingBack()");
87                 }
88             }
89         });
90     }
91 
92     @Override
onCallEstablished(final ISipSession session, final String sessionDescription)93     public void onCallEstablished(final ISipSession session,
94             final String sessionDescription) {
95         if (mListener == null) return;
96         proxy(new Runnable() {
97             @Override
98             public void run() {
99                 try {
100                     mListener.onCallEstablished(session, sessionDescription);
101                 } catch (Throwable t) {
102                     handle(t, "onCallEstablished()");
103                 }
104             }
105         });
106     }
107 
108     @Override
onCallEnded(final ISipSession session)109     public void onCallEnded(final ISipSession session) {
110         if (mListener == null) return;
111         proxy(new Runnable() {
112             @Override
113             public void run() {
114                 try {
115                     mListener.onCallEnded(session);
116                 } catch (Throwable t) {
117                     handle(t, "onCallEnded()");
118                 }
119             }
120         });
121     }
122 
123     @Override
onCallTransferring(final ISipSession newSession, final String sessionDescription)124     public void onCallTransferring(final ISipSession newSession,
125             final String sessionDescription) {
126         if (mListener == null) return;
127         proxy(new Runnable() {
128             @Override
129             public void run() {
130                 try {
131                     mListener.onCallTransferring(newSession, sessionDescription);
132                 } catch (Throwable t) {
133                     handle(t, "onCallTransferring()");
134                 }
135             }
136         });
137     }
138 
139     @Override
onCallBusy(final ISipSession session)140     public void onCallBusy(final ISipSession session) {
141         if (mListener == null) return;
142         proxy(new Runnable() {
143             @Override
144             public void run() {
145                 try {
146                     mListener.onCallBusy(session);
147                 } catch (Throwable t) {
148                     handle(t, "onCallBusy()");
149                 }
150             }
151         });
152     }
153 
154     @Override
onCallChangeFailed(final ISipSession session, final int errorCode, final String message)155     public void onCallChangeFailed(final ISipSession session,
156             final int errorCode, final String message) {
157         if (mListener == null) return;
158         proxy(new Runnable() {
159             @Override
160             public void run() {
161                 try {
162                     mListener.onCallChangeFailed(session, errorCode, message);
163                 } catch (Throwable t) {
164                     handle(t, "onCallChangeFailed()");
165                 }
166             }
167         });
168     }
169 
170     @Override
onError(final ISipSession session, final int errorCode, final String message)171     public void onError(final ISipSession session, final int errorCode,
172             final String message) {
173         if (mListener == null) return;
174         proxy(new Runnable() {
175             @Override
176             public void run() {
177                 try {
178                     mListener.onError(session, errorCode, message);
179                 } catch (Throwable t) {
180                     handle(t, "onError()");
181                 }
182             }
183         });
184     }
185 
186     @Override
onRegistering(final ISipSession session)187     public void onRegistering(final ISipSession session) {
188         if (mListener == null) return;
189         proxy(new Runnable() {
190             @Override
191             public void run() {
192                 try {
193                     mListener.onRegistering(session);
194                 } catch (Throwable t) {
195                     handle(t, "onRegistering()");
196                 }
197             }
198         });
199     }
200 
201     @Override
onRegistrationDone(final ISipSession session, final int duration)202     public void onRegistrationDone(final ISipSession session,
203             final int duration) {
204         if (mListener == null) return;
205         proxy(new Runnable() {
206             @Override
207             public void run() {
208                 try {
209                     mListener.onRegistrationDone(session, duration);
210                 } catch (Throwable t) {
211                     handle(t, "onRegistrationDone()");
212                 }
213             }
214         });
215     }
216 
217     @Override
onRegistrationFailed(final ISipSession session, final int errorCode, final String message)218     public void onRegistrationFailed(final ISipSession session,
219             final int errorCode, final String message) {
220         if (mListener == null) return;
221         proxy(new Runnable() {
222             @Override
223             public void run() {
224                 try {
225                     mListener.onRegistrationFailed(session, errorCode, message);
226                 } catch (Throwable t) {
227                     handle(t, "onRegistrationFailed()");
228                 }
229             }
230         });
231     }
232 
233     @Override
onRegistrationTimeout(final ISipSession session)234     public void onRegistrationTimeout(final ISipSession session) {
235         if (mListener == null) return;
236         proxy(new Runnable() {
237             @Override
238             public void run() {
239                 try {
240                     mListener.onRegistrationTimeout(session);
241                 } catch (Throwable t) {
242                     handle(t, "onRegistrationTimeout()");
243                 }
244             }
245         });
246     }
247 
handle(Throwable t, String message)248     private void handle(Throwable t, String message) {
249         if (t instanceof DeadObjectException) {
250             mListener = null;
251             // This creates race but it's harmless. Just don't log the error
252             // when it happens.
253         } else if (mListener != null) {
254             loge(message, t);
255         }
256     }
257 
log(String s)258     private void log(String s) {
259         Rlog.d(TAG, s);
260     }
261 
loge(String s, Throwable t)262     private void loge(String s, Throwable t) {
263         Rlog.e(TAG, s, t);
264     }
265 }
266