Handle Dead Objects from Phone Crashes better

1) Check to make sure ImsService is available when calling
changeMmTelCapability.
2) Remove caching of ImsConfig in ImsManager. It is already
cached properly in MmTelFeatureConnection.
3) Create a DeathRecipient for MmTelFeature in
MmTelFeatureConnection that cleans up all caches and notifies
ImsManager that the connection is now unavailable.

Bug: 77941698
Test: Manual
Change-Id: I9c3721fe275a94f7f8841e8e84a2f9d8a3c4823b
diff --git a/src/java/com/android/ims/MmTelFeatureConnection.java b/src/java/com/android/ims/MmTelFeatureConnection.java
index 0706921..d6954f3 100644
--- a/src/java/com/android/ims/MmTelFeatureConnection.java
+++ b/src/java/com/android/ims/MmTelFeatureConnection.java
@@ -75,6 +75,11 @@
     private IImsRegistration mRegistrationBinder;
     private IImsConfig mConfigBinder;
 
+    private IBinder.DeathRecipient mDeathRecipient = () -> {
+            Log.w(TAG, "DeathRecipient triggered, binder died.");
+            onRemovedOrDied();
+    };
+
     private abstract class CallbackAdapterManager<T> {
         private static final String TAG = "CallbackAdapterManager";
 
@@ -337,14 +342,8 @@
                 }
                 switch (feature) {
                     case ImsFeature.FEATURE_MMTEL: {
-                        if (mIsAvailable) {
-                            Log.i(TAG, "MmTel disabled on slotId: " + slotId);
-                            mIsAvailable = false;
-                            mmTelFeatureRemoved();
-                            if (mStatusCallback != null) {
-                                mStatusCallback.notifyUnavailable();
-                            }
-                        }
+                        Log.i(TAG, "MmTel removed on slotId: " + slotId);
+                        onRemovedOrDied();
                         break;
                     }
                     case ImsFeature.FEATURE_EMERGENCY_MMTEL : {
@@ -376,12 +375,23 @@
         mContext = context;
     }
 
-    // Called when the MmTelFeatureConnection has received an unavailable notification.
-    private void mmTelFeatureRemoved() {
+    /**
+     * Called when the MmTelFeature has either been removed by Telephony or crashed.
+     */
+    private void onRemovedOrDied() {
         synchronized (mLock) {
-            // invalidate caches.
-            mRegistrationBinder = null;
-            mConfigBinder = null;
+            if (mIsAvailable) {
+                mIsAvailable = false;
+                // invalidate caches.
+                mRegistrationBinder = null;
+                mConfigBinder = null;
+                if (mBinder != null) {
+                    mBinder.unlinkToDeath(mDeathRecipient, 0);
+                }
+                if (mStatusCallback != null) {
+                    mStatusCallback.notifyUnavailable();
+                }
+            }
         }
     }
 
@@ -434,7 +444,16 @@
     }
 
     public void setBinder(IBinder binder) {
-        mBinder = binder;
+        synchronized (mLock) {
+            mBinder = binder;
+            try {
+                if (mBinder != null) {
+                    mBinder.linkToDeath(mDeathRecipient, 0);
+                }
+            } catch (RemoteException e) {
+                // No need to do anything if the binder is already dead.
+            }
+        }
     }
 
     /**