Destroy fill UI when app dies.

This is a regression caused by the autofill compat feature change, as the
Fill UI window was changed from a sub-panel which is auto managed by the window
manager to an overlay, to ensure the fill UI covers all app windows, so compat
mode would work for apps without app changes.

Test: atest CtsAutoFillServiceTestCases:SessionLifecycleTest#testDatasetGoesAwayWhenAutofilledAppIsKilled
Test: atest CtsAutoFillServiceTestCases:SessionLifecycleTest#testSaveRemainsWhenAutofilledAppIsKilled
Test: atest CtsAutoFillServiceTestCases # usual flakiness
Test: manual verification by adb shell kiling an app while UI is shown

Fixes: 73566982

Change-Id: I42f0acbaf3d0b19c081b8cb3613bebb01ceb487a
(cherry picked from commit 57dae0b6f0678d2c43e4556fe7a9efee5214dbd8)
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index bcfe1b6..5eee9ed 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -52,6 +52,7 @@
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
+import android.os.IBinder.DeathRecipient;
 import android.os.Parcelable;
 import android.os.RemoteCallback;
 import android.os.RemoteException;
@@ -87,7 +88,6 @@
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-import com.android.internal.os.HandlerCaller;
 import com.android.internal.util.ArrayUtils;
 import com.android.server.autofill.ui.AutoFillUI;
 import com.android.server.autofill.ui.PendingUi;
@@ -158,6 +158,9 @@
     @GuardedBy("mLock")
     private IAutoFillManagerClient mClient;
 
+    @GuardedBy("mLock")
+    private DeathRecipient mClientVulture;
+
     private final RemoteFillService mRemoteFillService;
 
     @GuardedBy("mLock")
@@ -509,7 +512,7 @@
         mWtfHistory = wtfHistory;
         mComponentName = componentName;
         mCompatMode = compatMode;
-        mClient = IAutoFillManagerClient.Stub.asInterface(client);
+        setClientLocked(client);
 
         mMetricsLogger.write(newLogMaker(MetricsEvent.AUTOFILL_SESSION_STARTED)
                 .addTaggedData(MetricsEvent.FIELD_FLAGS, flags));
@@ -539,13 +542,44 @@
                 return;
             }
             mActivityToken = newActivity;
-            mClient = IAutoFillManagerClient.Stub.asInterface(newClient);
+            setClientLocked(newClient);
 
             // The tracked id are not persisted in the client, hence update them
             updateTrackedIdsLocked();
         }
     }
 
+    @GuardedBy("mLock")
+    private void setClientLocked(@NonNull IBinder client) {
+        unlinkClientVultureLocked();
+        mClient = IAutoFillManagerClient.Stub.asInterface(client);
+        mClientVulture = () -> {
+            Slog.d(TAG, "handling death of " + mActivityToken + " when saving=" + mIsSaving);
+            synchronized (mLock) {
+                if (mIsSaving) {
+                    mUi.hideFillUi(this);
+                } else {
+                    mUi.destroyAll(mPendingSaveUi, this, false);
+                }
+            }
+        };
+        try {
+            mClient.asBinder().linkToDeath(mClientVulture, 0);
+        } catch (RemoteException e) {
+            Slog.w(TAG, "could not set binder death listener on autofill client: " + e);
+        }
+    }
+
+    @GuardedBy("mLock")
+    private void unlinkClientVultureLocked() {
+        if (mClient != null && mClientVulture != null) {
+            final boolean unlinked = mClient.asBinder().unlinkToDeath(mClientVulture, 0);
+            if (!unlinked) {
+                Slog.w(TAG, "unlinking vulture from death failed for " + mActivityToken);
+            }
+        }
+    }
+
     // FillServiceCallbacks
     @Override
     public void onFillRequestSuccess(int requestFlags, @Nullable FillResponse response,
@@ -2443,6 +2477,7 @@
         if (mDestroyed) {
             return null;
         }
+        unlinkClientVultureLocked();
         mUi.destroyAll(mPendingSaveUi, this, true);
         mUi.clearCallback(this);
         mDestroyed = true;
diff --git a/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java b/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java
index e28a204..21a39e4 100644
--- a/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java
+++ b/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java
@@ -136,7 +136,7 @@
      * Hides the fill UI.
      */
     public void hideFillUi(@NonNull AutoFillUiCallback callback) {
-        mHandler.post(() -> hideFillUiUiThread(callback));
+        mHandler.post(() -> hideFillUiUiThread(callback, true));
     }
 
     /**
@@ -189,7 +189,7 @@
                 @Override
                 public void onResponsePicked(FillResponse response) {
                     log.setType(MetricsEvent.TYPE_DETAIL);
-                    hideFillUiUiThread(callback);
+                    hideFillUiUiThread(callback, true);
                     if (mCallback != null) {
                         mCallback.authenticate(response.getRequestId(),
                                 AutofillManager.AUTHENTICATION_ID_DATASET_ID_UNDEFINED,
@@ -200,7 +200,7 @@
                 @Override
                 public void onDatasetPicked(Dataset dataset) {
                     log.setType(MetricsEvent.TYPE_ACTION);
-                    hideFillUiUiThread(callback);
+                    hideFillUiUiThread(callback, true);
                     if (mCallback != null) {
                         final int datasetIndex = response.getDatasets().indexOf(dataset);
                         mCallback.fill(response.getRequestId(), datasetIndex, dataset);
@@ -210,7 +210,7 @@
                 @Override
                 public void onCanceled() {
                     log.setType(MetricsEvent.TYPE_DISMISS);
-                    hideFillUiUiThread(callback);
+                    hideFillUiUiThread(callback, true);
                 }
 
                 @Override
@@ -367,9 +367,9 @@
     }
 
     @android.annotation.UiThread
-    private void hideFillUiUiThread(@Nullable AutoFillUiCallback callback) {
+    private void hideFillUiUiThread(@Nullable AutoFillUiCallback callback, boolean notifyClient) {
         if (mFillUi != null && (callback == null || callback == mCallback)) {
-            mFillUi.destroy();
+            mFillUi.destroy(notifyClient);
             mFillUi = null;
         }
     }
@@ -413,13 +413,13 @@
     @android.annotation.UiThread
     private void destroyAllUiThread(@Nullable PendingUi pendingSaveUi,
             @Nullable AutoFillUiCallback callback, boolean notifyClient) {
-        hideFillUiUiThread(callback);
+        hideFillUiUiThread(callback, notifyClient);
         destroySaveUiUiThread(pendingSaveUi, notifyClient);
     }
 
     @android.annotation.UiThread
     private void hideAllUiThread(@Nullable AutoFillUiCallback callback) {
-        hideFillUiUiThread(callback);
+        hideFillUiUiThread(callback, true);
         final PendingUi pendingSaveUi = hideSaveUiUiThread(callback);
         if (pendingSaveUi != null && pendingSaveUi.getState() == PendingUi.STATE_FINISHED) {
             if (sDebug) {
diff --git a/services/autofill/java/com/android/server/autofill/ui/FillUi.java b/services/autofill/java/com/android/server/autofill/ui/FillUi.java
index a32078c..ef4656b 100644
--- a/services/autofill/java/com/android/server/autofill/ui/FillUi.java
+++ b/services/autofill/java/com/android/server/autofill/ui/FillUi.java
@@ -415,10 +415,15 @@
         applyNewFilterText();
     }
 
-    public void destroy() {
+    public void destroy(boolean notifyClient) {
         throwIfDestroyed();
+        if (mWindow != null) {
+            mWindow.hide(false);
+        }
         mCallback.onDestroy();
-        mCallback.requestHideFillUi();
+        if (notifyClient) {
+            mCallback.requestHideFillUi();
+        }
         mDestroyed = true;
     }
 
@@ -644,6 +649,10 @@
          * Hides the window.
          */
         void hide() {
+            hide(true);
+        }
+
+        void hide(boolean destroyCallbackOnError) {
             try {
                 if (mShowing) {
                     mWm.removeView(mContentView);
@@ -654,7 +663,9 @@
                 // happen - since show() and hide() are always called in the UIThread - but if it
                 // does, it should not crash the system.
                 Slog.e(TAG, "Exception hiding window ", e);
-                mCallback.onDestroy();
+                if (destroyCallbackOnError) {
+                    mCallback.onDestroy();
+                }
             } finally {
                 mOverlayControl.showOverlays();
             }