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