Add lock on mCallbacks in ServiceBinder

Add locking for access to mCallbacks to avoid concurrent modification
shenanigans.

Change-Id: I66eb84cb5c3396b2325f7ea2bb870d3afb9ead86
Fixes: 122085348
Test: manual
diff --git a/src/com/android/server/telecom/ServiceBinder.java b/src/com/android/server/telecom/ServiceBinder.java
index cf5407d..a322a5e 100644
--- a/src/com/android/server/telecom/ServiceBinder.java
+++ b/src/com/android/server/telecom/ServiceBinder.java
@@ -73,13 +73,15 @@
             // Reset any abort request if we're asked to bind again.
             clearAbort();
 
-            if (!mCallbacks.isEmpty()) {
-                // Binding already in progress, append to the list of callbacks and bail out.
+            synchronized (mCallbacks) {
+                if (!mCallbacks.isEmpty()) {
+                    // Binding already in progress, append to the list of callbacks and bail out.
+                    mCallbacks.add(callback);
+                    return;
+                }
                 mCallbacks.add(callback);
-                return;
             }
 
-            mCallbacks.add(callback);
             if (mServiceConnection == null) {
                 Intent serviceIntent = new Intent(mServiceAction).setComponent(mComponentName);
                 ServiceConnection connection = new ServiceBinderConnection(call);
@@ -351,10 +353,16 @@
      * outstanding callbacks is cleared afterwards.
      */
     private void handleSuccessfulConnection() {
-        for (BindCallback callback : mCallbacks) {
+        // Make a copy so that we don't have a deadlock inside one of the callbacks.
+        Set<BindCallback> callbacksCopy = new ArraySet<>();
+        synchronized (mCallbacks) {
+            callbacksCopy.addAll(mCallbacks);
+            mCallbacks.clear();
+        }
+
+        for (BindCallback callback : callbacksCopy) {
             callback.onSuccess();
         }
-        mCallbacks.clear();
     }
 
     /**
@@ -362,10 +370,16 @@
      * outstanding callbacks is cleared afterwards.
      */
     private void handleFailedConnection() {
-        for (BindCallback callback : mCallbacks) {
+        // Make a copy so that we don't have a deadlock inside one of the callbacks.
+        Set<BindCallback> callbacksCopy = new ArraySet<>();
+        synchronized (mCallbacks) {
+            callbacksCopy.addAll(mCallbacks);
+            mCallbacks.clear();
+        }
+
+        for (BindCallback callback : callbacksCopy) {
             callback.onFailure();
         }
-        mCallbacks.clear();
     }
 
     /**