From: Felipe Leme Date: Mon, 26 Feb 2018 21:17:39 +0000 (-0800) Subject: Destroy fill UI when app dies. X-Git-Tag: android-x86-9.0-r1~188^2~5^2 X-Git-Url: http://git.osdn.net/view?a=commitdiff_plain;h=d71f90266d0e361ed5f814b4a7c4dbe3bdf3b913;p=android-x86%2Fframeworks-base.git 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 bcfe1b6eb1f3..5eee9ed6c9b2 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.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; 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 e28a204df787..21a39e483986 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 @@ 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) { 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 a32078cc8e9f..ef4656bd06bb 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 @@ 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(); }