OSDN Git Service

Destroy fill UI when app dies.
authorFelipe Leme <felipeal@google.com>
Mon, 26 Feb 2018 21:17:39 +0000 (13:17 -0800)
committerFelipe Leme <felipeal@google.com>
Mon, 5 Mar 2018 21:59:09 +0000 (13:59 -0800)
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)

services/autofill/java/com/android/server/autofill/Session.java
services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java
services/autofill/java/com/android/server/autofill/ui/FillUi.java

index bcfe1b6..5eee9ed 100644 (file)
@@ -52,6 +52,7 @@ import android.os.Binder;
 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.R;
 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 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
     @GuardedBy("mLock")
     private IAutoFillManagerClient mClient;
 
+    @GuardedBy("mLock")
+    private DeathRecipient mClientVulture;
+
     private final RemoteFillService mRemoteFillService;
 
     @GuardedBy("mLock")
@@ -509,7 +512,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
         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 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
                 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 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
         if (mDestroyed) {
             return null;
         }
+        unlinkClientVultureLocked();
         mUi.destroyAll(mPendingSaveUi, this, true);
         mUi.clearCallback(this);
         mDestroyed = true;
index e28a204..21a39e4 100644 (file)
@@ -136,7 +136,7 @@ public final class AutoFillUI {
      * Hides the fill UI.
      */
     public void hideFillUi(@NonNull AutoFillUiCallback callback) {
-        mHandler.post(() -> hideFillUiUiThread(callback));
+        mHandler.post(() -> hideFillUiUiThread(callback, true));
     }
 
     /**
@@ -189,7 +189,7 @@ public final class AutoFillUI {
                 @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 @@ public final class AutoFillUI {
                 @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 @@ public final class AutoFillUI {
                 @Override
                 public void onCanceled() {
                     log.setType(MetricsEvent.TYPE_DISMISS);
-                    hideFillUiUiThread(callback);
+                    hideFillUiUiThread(callback, true);
                 }
 
                 @Override
@@ -367,9 +367,9 @@ public final class AutoFillUI {
     }
 
     @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 @@ public final class AutoFillUI {
     @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) {
index a32078c..ef4656b 100644 (file)
@@ -415,10 +415,15 @@ final class FillUi {
         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 @@ final class FillUi {
          * Hides the window.
          */
         void hide() {
+            hide(true);
+        }
+
+        void hide(boolean destroyCallbackOnError) {
             try {
                 if (mShowing) {
                     mWm.removeView(mContentView);
@@ -654,7 +663,9 @@ final class FillUi {
                 // 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();
             }