Loading src/com/android/server/telecom/TransactionalServiceRepository.java +13 −9 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package com.android.server.telecom; import android.telecom.Log; import android.telecom.PhoneAccountHandle; import com.android.internal.telecom.ICallEventCallback; Loading @@ -28,8 +29,8 @@ import java.util.Map; * more calls. */ public class TransactionalServiceRepository { private static final Map<PhoneAccountHandle, TransactionalServiceWrapper> lookupTable = private static final String TAG = TransactionalServiceRepository.class.getSimpleName(); private static final Map<PhoneAccountHandle, TransactionalServiceWrapper> mServiceLookupTable = new HashMap<>(); public TransactionalServiceRepository() { Loading @@ -38,12 +39,15 @@ public class TransactionalServiceRepository { public TransactionalServiceWrapper addNewCallForTransactionalServiceWrapper (PhoneAccountHandle phoneAccountHandle, ICallEventCallback callEventCallback, CallsManager callsManager, Call call) { TransactionalServiceWrapper service = null; TransactionalServiceWrapper service; // Only create a new TransactionalServiceWrapper if this is the first call for a package. // Otherwise, get the existing TSW and add the new call to the service. if (!hasExistingServiceWrapper(phoneAccountHandle)) { Log.d(TAG, "creating a new TSW; handle=[%s]", phoneAccountHandle); service = new TransactionalServiceWrapper(callEventCallback, callsManager, phoneAccountHandle, call, this); } else { Log.d(TAG, "add a new call to an existing TSW; handle=[%s]", phoneAccountHandle); service = getTransactionalServiceWrapper(phoneAccountHandle); if (service == null) { throw new IllegalStateException("service is null"); Loading @@ -52,25 +56,25 @@ public class TransactionalServiceRepository { } } lookupTable.put(phoneAccountHandle, service); mServiceLookupTable.put(phoneAccountHandle, service); return service; } public TransactionalServiceWrapper getTransactionalServiceWrapper(PhoneAccountHandle pah) { return lookupTable.get(pah); return mServiceLookupTable.get(pah); } public boolean hasExistingServiceWrapper(PhoneAccountHandle pah) { return lookupTable.containsKey(pah); return mServiceLookupTable.containsKey(pah); } public boolean removeServiceWrapper(PhoneAccountHandle pah) { Log.i(TAG, "removeServiceWrapper: for phoneAccountHandle=[%s]", pah); if (!hasExistingServiceWrapper(pah)) { return false; } lookupTable.remove(pah); mServiceLookupTable.remove(pah); return true; } } src/com/android/server/telecom/TransactionalServiceWrapper.java +32 −27 Original line number Diff line number Diff line Loading @@ -51,17 +51,17 @@ import com.android.server.telecom.voip.VoipCallTransaction; import com.android.server.telecom.voip.VoipCallTransactionResult; import java.util.ArrayList; import java.util.Hashtable; import java.util.List; import java.util.Locale; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; /** * Implements {@link android.telecom.CallEventCallback} and {@link android.telecom.CallControl} * on a per-client basis which is tied to a {@link PhoneAccountHandle} */ public class TransactionalServiceWrapper implements ConnectionServiceFocusManager.ConnectionServiceFocus, IBinder.DeathRecipient { ConnectionServiceFocusManager.ConnectionServiceFocus { private static final String TAG = TransactionalServiceWrapper.class.getSimpleName(); // CallControl : Client (ex. voip app) --> Telecom Loading @@ -84,13 +84,25 @@ public class TransactionalServiceWrapper implements private final TransactionalServiceRepository mRepository; private ConnectionServiceFocusManager.ConnectionServiceFocusListener mConnSvrFocusListener; // init when constructor is called private final Hashtable<String, Call> mTrackedCalls = new Hashtable<>(); private final ConcurrentHashMap<String, Call> mTrackedCalls = new ConcurrentHashMap<>(); private final TelecomSystem.SyncRoot mLock; private final String mPackageName; // needs to be non-final for testing private TransactionManager mTransactionManager; private CallStreamingController mStreamingController; // Each TransactionalServiceWrapper should have their own Binder.DeathRecipient to clean up // any calls in the event the application crashes or is force stopped. private final IBinder.DeathRecipient mAppDeathListener = new IBinder.DeathRecipient() { @Override public void binderDied() { Log.i(TAG, "binderDied: for package=[%s]; cleaning calls", mPackageName); cleanupTransactionalServiceWrapper(); mICallEventCallback.asBinder().unlinkToDeath(this, 0); } }; public TransactionalServiceWrapper(ICallEventCallback callEventCallback, CallsManager callsManager, PhoneAccountHandle phoneAccountHandle, Call call, TransactionalServiceRepository repo) { Loading @@ -105,6 +117,7 @@ public class TransactionalServiceWrapper implements mTransactionManager = TransactionManager.getInstance(); mStreamingController = mCallsManager.getCallStreamingController(); mLock = mCallsManager.getLock(); setDeathRecipient(callEventCallback); } @VisibleForTesting Loading @@ -128,12 +141,6 @@ public class TransactionalServiceWrapper implements } } public Call getCallById(String callId) { synchronized (mLock) { return mTrackedCalls.get(callId); } } @VisibleForTesting public boolean untrackCall(Call call) { Call removedCall = null; Loading @@ -158,24 +165,13 @@ public class TransactionalServiceWrapper implements return callCount; } @Override public void binderDied() { // remove all tacked calls from CallsManager && frameworks side for (String id : mTrackedCalls.keySet()) { Call call = mTrackedCalls.get(id); mCallsManager.markCallAsDisconnected(call, new DisconnectCause(DisconnectCause.ERROR)); mCallsManager.removeCall(call); // remove calls from Frameworks side if (mICallEventCallback != null) { try { mICallEventCallback.removeCallFromTransactionalServiceWrapper(call.getId()); } catch (RemoteException e) { // pass } public void cleanupTransactionalServiceWrapper() { for (Call call : mTrackedCalls.values()) { mCallsManager.markCallAsDisconnected(call, new DisconnectCause(DisconnectCause.ERROR, "process died")); mCallsManager.removeCall(call); // This will clear mTrackedCalls && ClientTWS } } mTrackedCalls.clear(); } /*** ********************************************************************************************* Loading Loading @@ -556,10 +552,10 @@ public class TransactionalServiceWrapper implements try { // remove the call from frameworks wrapper (client side) mICallEventCallback.removeCallFromTransactionalServiceWrapper(call.getId()); // remove the call from this class/wrapper (server side) untrackCall(call); } catch (RemoteException e) { } // remove the call from this class/wrapper (server side) untrackCall(call); } } Loading Loading @@ -605,6 +601,15 @@ public class TransactionalServiceWrapper implements return new SerialTransaction(transactions, mLock); } private void setDeathRecipient(ICallEventCallback callEventCallback) { try { callEventCallback.asBinder().linkToDeath(mAppDeathListener, 0); } catch (Exception e) { Log.w(TAG, "setDeathRecipient: hit exception=[%s] trying to link binder to death", e.toString()); } } /*** ********************************************************************************************* ** FocusManager ** Loading testapps/transactionalVoipApp/res/layout/in_call_activity.xml +6 −0 Original line number Diff line number Diff line Loading @@ -58,6 +58,12 @@ android:layout_height="wrap_content" android:text="@string/start_stream"/> <Button android:id="@+id/crash_app" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/crash_app"/> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" Loading testapps/transactionalVoipApp/res/values/strings.xml +1 −0 Original line number Diff line number Diff line Loading @@ -38,5 +38,6 @@ <string name="request_bluetooth_endpoint">Bluetooth</string> <!-- extra functionality --> <string name="start_stream">start streaming</string> <string name="crash_app">throw exception</string> </resources> No newline at end of file testapps/transactionalVoipApp/src/com/android/server/telecom/transactionalVoipApp/InCallActivity.java +24 −1 Original line number Diff line number Diff line Loading @@ -164,10 +164,28 @@ public class InCallActivity extends Activity { } } }); findViewById(R.id.crash_app).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // To test edge cases, it may be useful to crash the app. To do this, throwing a // RuntimeException is sufficient. throw new RuntimeException( "Intentionally throwing RuntimeException from InCallActivity"); } }); } @Override protected void onStop() { Log.i(TAG, "onStop: InCallActivity has stopped"); super.onStop(); } @Override protected void onDestroy() { Log.i(TAG, "onDestroy: InCallActivity has been destroyed"); disconnectAndStopAudio(); super.onDestroy(); } Loading Loading @@ -205,8 +223,13 @@ public class InCallActivity extends Activity { sb.append("Error Getting Id"); } sb.append("]"); try { view.setText(sb.toString()); } catch (Exception e){ // ignore updating the ui } } private void addCall() { mVoipCall = new MyVoipCall("123"); Loading Loading
src/com/android/server/telecom/TransactionalServiceRepository.java +13 −9 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package com.android.server.telecom; import android.telecom.Log; import android.telecom.PhoneAccountHandle; import com.android.internal.telecom.ICallEventCallback; Loading @@ -28,8 +29,8 @@ import java.util.Map; * more calls. */ public class TransactionalServiceRepository { private static final Map<PhoneAccountHandle, TransactionalServiceWrapper> lookupTable = private static final String TAG = TransactionalServiceRepository.class.getSimpleName(); private static final Map<PhoneAccountHandle, TransactionalServiceWrapper> mServiceLookupTable = new HashMap<>(); public TransactionalServiceRepository() { Loading @@ -38,12 +39,15 @@ public class TransactionalServiceRepository { public TransactionalServiceWrapper addNewCallForTransactionalServiceWrapper (PhoneAccountHandle phoneAccountHandle, ICallEventCallback callEventCallback, CallsManager callsManager, Call call) { TransactionalServiceWrapper service = null; TransactionalServiceWrapper service; // Only create a new TransactionalServiceWrapper if this is the first call for a package. // Otherwise, get the existing TSW and add the new call to the service. if (!hasExistingServiceWrapper(phoneAccountHandle)) { Log.d(TAG, "creating a new TSW; handle=[%s]", phoneAccountHandle); service = new TransactionalServiceWrapper(callEventCallback, callsManager, phoneAccountHandle, call, this); } else { Log.d(TAG, "add a new call to an existing TSW; handle=[%s]", phoneAccountHandle); service = getTransactionalServiceWrapper(phoneAccountHandle); if (service == null) { throw new IllegalStateException("service is null"); Loading @@ -52,25 +56,25 @@ public class TransactionalServiceRepository { } } lookupTable.put(phoneAccountHandle, service); mServiceLookupTable.put(phoneAccountHandle, service); return service; } public TransactionalServiceWrapper getTransactionalServiceWrapper(PhoneAccountHandle pah) { return lookupTable.get(pah); return mServiceLookupTable.get(pah); } public boolean hasExistingServiceWrapper(PhoneAccountHandle pah) { return lookupTable.containsKey(pah); return mServiceLookupTable.containsKey(pah); } public boolean removeServiceWrapper(PhoneAccountHandle pah) { Log.i(TAG, "removeServiceWrapper: for phoneAccountHandle=[%s]", pah); if (!hasExistingServiceWrapper(pah)) { return false; } lookupTable.remove(pah); mServiceLookupTable.remove(pah); return true; } }
src/com/android/server/telecom/TransactionalServiceWrapper.java +32 −27 Original line number Diff line number Diff line Loading @@ -51,17 +51,17 @@ import com.android.server.telecom.voip.VoipCallTransaction; import com.android.server.telecom.voip.VoipCallTransactionResult; import java.util.ArrayList; import java.util.Hashtable; import java.util.List; import java.util.Locale; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; /** * Implements {@link android.telecom.CallEventCallback} and {@link android.telecom.CallControl} * on a per-client basis which is tied to a {@link PhoneAccountHandle} */ public class TransactionalServiceWrapper implements ConnectionServiceFocusManager.ConnectionServiceFocus, IBinder.DeathRecipient { ConnectionServiceFocusManager.ConnectionServiceFocus { private static final String TAG = TransactionalServiceWrapper.class.getSimpleName(); // CallControl : Client (ex. voip app) --> Telecom Loading @@ -84,13 +84,25 @@ public class TransactionalServiceWrapper implements private final TransactionalServiceRepository mRepository; private ConnectionServiceFocusManager.ConnectionServiceFocusListener mConnSvrFocusListener; // init when constructor is called private final Hashtable<String, Call> mTrackedCalls = new Hashtable<>(); private final ConcurrentHashMap<String, Call> mTrackedCalls = new ConcurrentHashMap<>(); private final TelecomSystem.SyncRoot mLock; private final String mPackageName; // needs to be non-final for testing private TransactionManager mTransactionManager; private CallStreamingController mStreamingController; // Each TransactionalServiceWrapper should have their own Binder.DeathRecipient to clean up // any calls in the event the application crashes or is force stopped. private final IBinder.DeathRecipient mAppDeathListener = new IBinder.DeathRecipient() { @Override public void binderDied() { Log.i(TAG, "binderDied: for package=[%s]; cleaning calls", mPackageName); cleanupTransactionalServiceWrapper(); mICallEventCallback.asBinder().unlinkToDeath(this, 0); } }; public TransactionalServiceWrapper(ICallEventCallback callEventCallback, CallsManager callsManager, PhoneAccountHandle phoneAccountHandle, Call call, TransactionalServiceRepository repo) { Loading @@ -105,6 +117,7 @@ public class TransactionalServiceWrapper implements mTransactionManager = TransactionManager.getInstance(); mStreamingController = mCallsManager.getCallStreamingController(); mLock = mCallsManager.getLock(); setDeathRecipient(callEventCallback); } @VisibleForTesting Loading @@ -128,12 +141,6 @@ public class TransactionalServiceWrapper implements } } public Call getCallById(String callId) { synchronized (mLock) { return mTrackedCalls.get(callId); } } @VisibleForTesting public boolean untrackCall(Call call) { Call removedCall = null; Loading @@ -158,24 +165,13 @@ public class TransactionalServiceWrapper implements return callCount; } @Override public void binderDied() { // remove all tacked calls from CallsManager && frameworks side for (String id : mTrackedCalls.keySet()) { Call call = mTrackedCalls.get(id); mCallsManager.markCallAsDisconnected(call, new DisconnectCause(DisconnectCause.ERROR)); mCallsManager.removeCall(call); // remove calls from Frameworks side if (mICallEventCallback != null) { try { mICallEventCallback.removeCallFromTransactionalServiceWrapper(call.getId()); } catch (RemoteException e) { // pass } public void cleanupTransactionalServiceWrapper() { for (Call call : mTrackedCalls.values()) { mCallsManager.markCallAsDisconnected(call, new DisconnectCause(DisconnectCause.ERROR, "process died")); mCallsManager.removeCall(call); // This will clear mTrackedCalls && ClientTWS } } mTrackedCalls.clear(); } /*** ********************************************************************************************* Loading Loading @@ -556,10 +552,10 @@ public class TransactionalServiceWrapper implements try { // remove the call from frameworks wrapper (client side) mICallEventCallback.removeCallFromTransactionalServiceWrapper(call.getId()); // remove the call from this class/wrapper (server side) untrackCall(call); } catch (RemoteException e) { } // remove the call from this class/wrapper (server side) untrackCall(call); } } Loading Loading @@ -605,6 +601,15 @@ public class TransactionalServiceWrapper implements return new SerialTransaction(transactions, mLock); } private void setDeathRecipient(ICallEventCallback callEventCallback) { try { callEventCallback.asBinder().linkToDeath(mAppDeathListener, 0); } catch (Exception e) { Log.w(TAG, "setDeathRecipient: hit exception=[%s] trying to link binder to death", e.toString()); } } /*** ********************************************************************************************* ** FocusManager ** Loading
testapps/transactionalVoipApp/res/layout/in_call_activity.xml +6 −0 Original line number Diff line number Diff line Loading @@ -58,6 +58,12 @@ android:layout_height="wrap_content" android:text="@string/start_stream"/> <Button android:id="@+id/crash_app" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/crash_app"/> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" Loading
testapps/transactionalVoipApp/res/values/strings.xml +1 −0 Original line number Diff line number Diff line Loading @@ -38,5 +38,6 @@ <string name="request_bluetooth_endpoint">Bluetooth</string> <!-- extra functionality --> <string name="start_stream">start streaming</string> <string name="crash_app">throw exception</string> </resources> No newline at end of file
testapps/transactionalVoipApp/src/com/android/server/telecom/transactionalVoipApp/InCallActivity.java +24 −1 Original line number Diff line number Diff line Loading @@ -164,10 +164,28 @@ public class InCallActivity extends Activity { } } }); findViewById(R.id.crash_app).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // To test edge cases, it may be useful to crash the app. To do this, throwing a // RuntimeException is sufficient. throw new RuntimeException( "Intentionally throwing RuntimeException from InCallActivity"); } }); } @Override protected void onStop() { Log.i(TAG, "onStop: InCallActivity has stopped"); super.onStop(); } @Override protected void onDestroy() { Log.i(TAG, "onDestroy: InCallActivity has been destroyed"); disconnectAndStopAudio(); super.onDestroy(); } Loading Loading @@ -205,8 +223,13 @@ public class InCallActivity extends Activity { sb.append("Error Getting Id"); } sb.append("]"); try { view.setText(sb.toString()); } catch (Exception e){ // ignore updating the ui } } private void addCall() { mVoipCall = new MyVoipCall("123"); Loading