Merge "Throw IllegalStateException to fail fast in IMS"
diff --git a/telephony/java/android/telephony/ims/ImsUtListener.java b/telephony/java/android/telephony/ims/ImsUtListener.java
index baa0576..754814f 100644
--- a/telephony/java/android/telephony/ims/ImsUtListener.java
+++ b/telephony/java/android/telephony/ims/ImsUtListener.java
@@ -178,4 +178,11 @@
     public ImsUtListener(IImsUtListener serviceInterface) {
         mServiceInterface = serviceInterface;
     }
+
+    /**
+     * @hide
+     */
+    public IImsUtListener getListenerInterface() {
+        return mServiceInterface;
+    }
 }
diff --git a/telephony/java/android/telephony/ims/stub/ImsEcbmImplBase.java b/telephony/java/android/telephony/ims/stub/ImsEcbmImplBase.java
index 06c35ea..2e35d27 100644
--- a/telephony/java/android/telephony/ims/stub/ImsEcbmImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/ImsEcbmImplBase.java
@@ -23,6 +23,8 @@
 import com.android.ims.internal.IImsEcbm;
 import com.android.ims.internal.IImsEcbmListener;
 
+import java.util.Objects;
+
 /**
  * Base implementation of ImsEcbm, which implements stub versions of the methods
  * in the IImsEcbm AIDL. Override the methods that your implementation of ImsEcbm supports.
@@ -36,11 +38,27 @@
 public class ImsEcbmImplBase {
     private static final String TAG = "ImsEcbmImplBase";
 
+    private final Object mLock = new Object();
     private IImsEcbmListener mListener;
-    private IImsEcbm mImsEcbm = new IImsEcbm.Stub() {
+    private final IImsEcbm mImsEcbm = new IImsEcbm.Stub() {
         @Override
         public void setListener(IImsEcbmListener listener) {
-            mListener = listener;
+            synchronized (mLock) {
+                if (mImsEcbm != null && listener != null && Objects.equals(
+                        mImsEcbm.asBinder(), listener.asBinder())) {
+                    return;
+                }
+                if (listener == null) {
+                    mListener = null;
+                } else if (listener != null && mListener == null) {
+                    mListener = listener;
+                } else {
+                    // Fail fast here instead of silently overwriting the listener to another
+                    // listener due to another connection connecting.
+                    throw new IllegalStateException("ImsEcbmImplBase: Listener already set by "
+                            + "another connection.");
+                }
+            }
         }
 
         @Override
@@ -69,9 +87,13 @@
      */
     public final void enteredEcbm() {
         Log.d(TAG, "Entered ECBM.");
-        if (mListener != null) {
+        IImsEcbmListener listener;
+        synchronized (mLock) {
+            listener = mListener;
+        }
+        if (listener != null) {
             try {
-                mListener.enteredECBM();
+                listener.enteredECBM();
             } catch (RemoteException e) {
                 throw new RuntimeException(e);
             }
@@ -85,9 +107,13 @@
      */
     public final void exitedEcbm() {
         Log.d(TAG, "Exited ECBM.");
-        if (mListener != null) {
+        IImsEcbmListener listener;
+        synchronized (mLock) {
+            listener = mListener;
+        }
+        if (listener != null) {
             try {
-                mListener.exitedECBM();
+                listener.exitedECBM();
             } catch (RemoteException e) {
                 throw new RuntimeException(e);
             }
diff --git a/telephony/java/android/telephony/ims/stub/ImsMultiEndpointImplBase.java b/telephony/java/android/telephony/ims/stub/ImsMultiEndpointImplBase.java
index d002903..555a47e 100644
--- a/telephony/java/android/telephony/ims/stub/ImsMultiEndpointImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/ImsMultiEndpointImplBase.java
@@ -25,6 +25,7 @@
 import com.android.ims.internal.IImsMultiEndpoint;
 
 import java.util.List;
+import java.util.Objects;
 
 /**
  * Base implementation of ImsMultiEndpoint, which implements stub versions of the methods
@@ -41,10 +42,28 @@
     private static final String TAG = "MultiEndpointImplBase";
 
     private IImsExternalCallStateListener mListener;
-    private IImsMultiEndpoint mImsMultiEndpoint = new IImsMultiEndpoint.Stub() {
+    private final Object mLock = new Object();
+    private final IImsMultiEndpoint mImsMultiEndpoint = new IImsMultiEndpoint.Stub() {
+
         @Override
         public void setListener(IImsExternalCallStateListener listener) throws RemoteException {
-            mListener = listener;
+            synchronized (mLock) {
+                if (mListener != null && listener != null && Objects.equals(
+                        mListener.asBinder(), listener.asBinder())) {
+                    return;
+                }
+
+                if (listener == null) {
+                    mListener = null;
+                } else if (listener != null && mListener == null) {
+                    mListener = listener;
+                } else {
+                    // Fail fast here instead of silently overwriting the listener to another
+                    // listener due to another connection connecting.
+                    throw new IllegalStateException("ImsMultiEndpointImplBase: Listener already"
+                            + " set by another connection.");
+                }
+            }
         }
 
         @Override
@@ -65,9 +84,13 @@
      */
     public final void onImsExternalCallStateUpdate(List<ImsExternalCallState> externalCallDialogs) {
         Log.d(TAG, "ims external call state update triggered.");
-        if (mListener != null) {
+        IImsExternalCallStateListener listener;
+        synchronized (mLock) {
+            listener = mListener;
+        }
+        if (listener != null) {
             try {
-                mListener.onImsExternalCallStateUpdate(externalCallDialogs);
+                listener.onImsExternalCallStateUpdate(externalCallDialogs);
             } catch (RemoteException e) {
                 throw new RuntimeException(e);
             }
diff --git a/telephony/java/android/telephony/ims/stub/ImsUtImplBase.java b/telephony/java/android/telephony/ims/stub/ImsUtImplBase.java
index f5219d5..eef4fca 100644
--- a/telephony/java/android/telephony/ims/stub/ImsUtImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/ImsUtImplBase.java
@@ -29,6 +29,7 @@
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.util.Objects;
 
 /**
  * Base implementation of IMS UT interface, which implements stubs. Override these methods to
@@ -116,7 +117,10 @@
      */
     public static final int INVALID_RESULT = -1;
 
-    private IImsUt.Stub mServiceImpl = new IImsUt.Stub() {
+    private final IImsUt.Stub mServiceImpl = new IImsUt.Stub() {
+        private final Object mLock = new Object();
+        private ImsUtListener mUtListener;
+
         @Override
         public void close() throws RemoteException {
             ImsUtImplBase.this.close();
@@ -202,7 +206,26 @@
 
         @Override
         public void setListener(IImsUtListener listener) throws RemoteException {
-            ImsUtImplBase.this.setListener(new ImsUtListener(listener));
+            synchronized (mLock) {
+                if (mUtListener != null && listener != null && Objects.equals(
+                        mUtListener.getListenerInterface().asBinder(), listener.asBinder())) {
+                    return;
+                }
+
+                if (listener == null) {
+                    mUtListener = null;
+                } else if (listener != null && mUtListener == null) {
+                    mUtListener = new ImsUtListener(listener);
+                } else {
+                    // This is a limitation of the current API surface, there can only be one
+                    // listener connected. Fail fast instead of silently overwriting the other
+                    // listener.
+                    throw new IllegalStateException("ImsUtImplBase#setListener: listener already "
+                            + "set by another connected interface!");
+                }
+            }
+
+            ImsUtImplBase.this.setListener(mUtListener);
         }
 
         @Override