diff options
| author | 2018-08-31 14:32:18 -0700 | |
|---|---|---|
| committer | 2018-09-10 17:03:27 -0700 | |
| commit | ba15db8f7041981e520eb557a971b3d8af9aab51 (patch) | |
| tree | 09ce97e3df0aa2a81cdfbde553c57f3066a130dc | |
| parent | 91a6b8bfa97a4cd98307345c9df9e42f6d576460 (diff) | |
Use session id to uniquely identidy autofill ids for multi-session.
This change is need when integrating CustomDescription artifacts (like
CharSequenceTransformation) with SaveInfo.FLAG_DELAY_SAVE, as different
views might have the same autofill id on different activities.
Test: atest CtsAutoFillServiceTestCases:MultiScreenLoginTest
Test: atest CtsAutoFillServiceTestCases # to make sure it didn't break anything
Fixes: 113593220
Change-Id: I7db1df7a56dec7180a2172bb2022b042f115c7b8
7 files changed, 108 insertions, 31 deletions
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index bf2d86096773..041a5b071032 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -1461,7 +1461,7 @@ public class Activity extends ContextThemeWrapper */ @Override public AutofillId autofillClientGetNextAutofillId() { - return new AutofillId(getNextAutofillId()); + return new AutofillId(getAutofillManager(), getNextAutofillId()); } /** diff --git a/core/java/android/app/assist/AssistStructure.java b/core/java/android/app/assist/AssistStructure.java index 173b7667897e..ee6a81d9b6e1 100644 --- a/core/java/android/app/assist/AssistStructure.java +++ b/core/java/android/app/assist/AssistStructure.java @@ -32,6 +32,7 @@ import android.view.ViewStructure.HtmlInfo.Builder; import android.view.WindowManager; import android.view.WindowManagerGlobal; import android.view.autofill.AutofillId; +import android.view.autofill.AutofillManager; import android.view.autofill.AutofillValue; import com.android.internal.util.Preconditions; @@ -72,6 +73,8 @@ public class AssistStructure implements Parcelable { boolean mHaveData; ComponentName mActivityComponent; + // Not written to parcel, only used to set session id on virtual node children + private final int mAutofillSessionId; private boolean mIsHomeActivity; private int mFlags; @@ -1846,11 +1849,13 @@ public class AssistStructure implements Parcelable { @Override public void setAutofillId(@NonNull AutofillId id) { mNode.mAutofillId = id; + mNode.mAutofillId.setSessionId(mAssist.mAutofillSessionId); } @Override public void setAutofillId(@NonNull AutofillId parentId, int virtualId) { mNode.mAutofillId = new AutofillId(parentId, virtualId); + mNode.mAutofillId.setSessionId(mAssist.mAutofillSessionId); } @Override @@ -2040,6 +2045,8 @@ public class AssistStructure implements Parcelable { public AssistStructure(Activity activity, boolean forAutoFill, int flags) { mHaveData = true; mActivityComponent = activity.getComponentName(); + final AutofillManager afm = activity.getSystemService(AutofillManager.class); + mAutofillSessionId = afm == null ? AutofillManager.NO_SESSION : afm.getSessionId(); mFlags = flags; ArrayList<ViewRootImpl> views = WindowManagerGlobal.getInstance().getRootViews( activity.getActivityToken()); @@ -2056,6 +2063,7 @@ public class AssistStructure implements Parcelable { public AssistStructure() { mHaveData = true; mActivityComponent = null; + mAutofillSessionId = AutofillManager.NO_SESSION; mFlags = 0; } @@ -2063,6 +2071,7 @@ public class AssistStructure implements Parcelable { public AssistStructure(Parcel in) { mIsHomeActivity = in.readInt() == 1; mReceiveChannel = in.readStrongBinder(); + mAutofillSessionId = AutofillManager.NO_SESSION; } /** @@ -2082,6 +2091,10 @@ public class AssistStructure implements Parcelable { ensureData(); } Log.i(TAG, "Activity: " + mActivityComponent.flattenToShortString()); + if (mAutofillSessionId != AutofillManager.NO_SESSION) { + Log.i(TAG, "Autofill Session ID: " + mAutofillSessionId); + } + Log.i(TAG, "Sanitize on write: " + mSanitizeOnWrite); Log.i(TAG, "Flags: " + mFlags); final int N = getWindowNodeCount(); diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 9bc53ed5a851..4a619062765f 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -8251,7 +8251,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, if (mAutofillId == null) { // The autofill id needs to be unique, but its value doesn't matter, // so it's better to reuse the accessibility id to save space. - mAutofillId = new AutofillId(getAutofillViewId()); + mAutofillId = new AutofillId(getAutofillManager(), getAutofillViewId()); } return mAutofillId; } @@ -8313,11 +8313,15 @@ public class View implements Drawable.Callback, KeyEvent.Callback, // Ignore reset because it was never explicitly set before. return; } - mAutofillId = id; if (id != null) { + // Must create a new id so the session id is preserved. + final int oldSessionId = mAutofillId.getSessionId(); mAutofillViewId = id.getViewId(); + mAutofillId = new AutofillId(mAutofillViewId); + mAutofillId.setSessionId(oldSessionId); mPrivateFlags3 |= PFLAG3_AUTOFILLID_EXPLICITLY_SET; } else { + mAutofillId = null; mAutofillViewId = NO_ID; mPrivateFlags3 &= ~PFLAG3_AUTOFILLID_EXPLICITLY_SET; } @@ -8607,8 +8611,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback, structure.setContextClickable(true); } if (forAutofill) { - structure.setAutofillId(new AutofillId(getAutofillId(), - AccessibilityNodeInfo.getVirtualDescendantId(info.getSourceNodeId()))); + final AutofillId autofillId = new AutofillId(getAutofillId(), + AccessibilityNodeInfo.getVirtualDescendantId(info.getSourceNodeId())); + final AutofillManager afm = getAutofillManager(); + autofillId.setSessionId(afm == null ? AutofillManager.NO_SESSION : afm.getSessionId()); + structure.setAutofillId(autofillId); } CharSequence cname = info.getClassName(); structure.setClassName(cname != null ? cname.toString() : null); diff --git a/core/java/android/view/autofill/AutofillId.java b/core/java/android/view/autofill/AutofillId.java index cb1d89c54d9a..5ae91a543a52 100644 --- a/core/java/android/view/autofill/AutofillId.java +++ b/core/java/android/view/autofill/AutofillId.java @@ -15,6 +15,10 @@ */ package android.view.autofill; +import static android.view.autofill.Helper.sDebug; + +import android.annotation.NonNull; +import android.annotation.Nullable; import android.annotation.TestApi; import android.os.Parcel; import android.os.Parcelable; @@ -28,6 +32,7 @@ public final class AutofillId implements Parcelable { private final int mViewId; private final boolean mVirtual; private final int mVirtualId; + private int mSessionId = AutofillManager.NO_SESSION; /** @hide */ @TestApi @@ -38,18 +43,26 @@ public final class AutofillId implements Parcelable { } /** @hide */ + // NOTE: caller must set sessionId @TestApi - public AutofillId(AutofillId parent, int virtualChildId) { + public AutofillId(@NonNull AutofillId parent, int virtualChildId) { mVirtual = true; mViewId = parent.mViewId; mVirtualId = virtualChildId; } /** @hide */ - public AutofillId(int parentId, int virtualChildId) { + public AutofillId(int sessionId, int parentId, int virtualChildId) { mVirtual = true; mViewId = parentId; mVirtualId = virtualChildId; + mSessionId = sessionId; + } + + /** @hide */ + public AutofillId(@Nullable AutofillManager afm, int id) { + this(id); + mSessionId = afm == null ? AutofillManager.NO_SESSION : afm.getSessionId(); } /** @hide */ @@ -67,6 +80,16 @@ public final class AutofillId implements Parcelable { return mVirtual; } + /** @hide */ + public int getSessionId() { + return mSessionId; + } + + /** @hide */ + public void setSessionId(int sessionId) { + this.mSessionId = sessionId; + } + ///////////////////////////////// // Object "contract" methods. // ///////////////////////////////// @@ -77,6 +100,7 @@ public final class AutofillId implements Parcelable { int result = 1; result = prime * result + mViewId; result = prime * result + mVirtualId; + result = prime * result + mSessionId; return result; } @@ -88,6 +112,7 @@ public final class AutofillId implements Parcelable { final AutofillId other = (AutofillId) obj; if (mViewId != other.mViewId) return false; if (mVirtualId != other.mVirtualId) return false; + if (mSessionId != other.mSessionId) return false; return true; } @@ -97,6 +122,9 @@ public final class AutofillId implements Parcelable { if (mVirtual) { builder.append(':').append(mVirtualId); } + if (mSessionId != AutofillManager.NO_SESSION && sDebug) { + builder.append('<').append(mSessionId).append('>'); + } return builder.toString(); } @@ -110,12 +138,14 @@ public final class AutofillId implements Parcelable { parcel.writeInt(mViewId); parcel.writeInt(mVirtual ? 1 : 0); parcel.writeInt(mVirtualId); + parcel.writeInt(mSessionId); } private AutofillId(Parcel parcel) { mViewId = parcel.readInt(); mVirtual = parcel.readInt() == 1; mVirtualId = parcel.readInt(); + mSessionId = parcel.readInt(); } public static final Parcelable.Creator<AutofillId> CREATOR = diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java index 9419e93d0066..612888ef7eca 100644 --- a/core/java/android/view/autofill/AutofillManager.java +++ b/core/java/android/view/autofill/AutofillManager.java @@ -916,7 +916,7 @@ public final class AutofillManager { boolean isVisible, boolean virtual) { synchronized (mLock) { if (mEnabled && isActiveLocked()) { - final AutofillId id = virtual ? getAutofillId(view, virtualId) + final AutofillId id = virtual ? getAutofillIdLocked(view, virtualId) : view.getAutofillId(); if (sVerbose) Log.v(TAG, "visibility changed for " + id + ": " + isVisible); if (!isVisible && mFillableIds != null) { @@ -976,7 +976,7 @@ public final class AutofillManager { @GuardedBy("mLock") private AutofillCallback notifyViewEnteredLocked(View view, int virtualId, Rect bounds, int flags) { - final AutofillId id = getAutofillId(view, virtualId); + final AutofillId id = getAutofillIdLocked(view, virtualId); AutofillCallback callback = null; if (shouldIgnoreViewEnteredLocked(id, flags)) return callback; @@ -1033,7 +1033,7 @@ public final class AutofillManager { if (mEnabled && isActiveLocked()) { // don't notify exited when Activity is already in background if (!isClientDisablingEnterExitEvent()) { - final AutofillId id = getAutofillId(view, virtualId); + final AutofillId id = getAutofillIdLocked(view, virtualId); // Update focus on existing session. updateSessionLocked(id, null, null, ACTION_VIEW_EXITED, 0); @@ -1116,7 +1116,7 @@ public final class AutofillManager { return; } - final AutofillId id = getAutofillId(view, virtualId); + final AutofillId id = getAutofillIdLocked(view, virtualId); updateSessionLocked(id, null, value, ACTION_VALUE_CHANGED, 0); } } @@ -1137,7 +1137,11 @@ public final class AutofillManager { * @param virtualId id identifying the virtual child inside the parent view. */ public void notifyViewClicked(@NonNull View view, int virtualId) { - notifyViewClicked(getAutofillId(view, virtualId)); + final AutofillId id; + synchronized (mLock) { + id = getAutofillIdLocked(view, virtualId); + } + notifyViewClicked(id); } private void notifyViewClicked(AutofillId id) { @@ -1534,8 +1538,9 @@ public final class AutofillManager { return id; } - private static AutofillId getAutofillId(View parent, int virtualId) { - return new AutofillId(parent.getAutofillViewId(), virtualId); + @GuardedBy("mLock") + private AutofillId getAutofillIdLocked(View parent, int virtualId) { + return new AutofillId(mSessionId, parent.getAutofillViewId(), virtualId); } @GuardedBy("mLock") @@ -1566,6 +1571,8 @@ public final class AutofillManager { mSessionId = receiver.getIntResult(); if (mSessionId != NO_SESSION) { mState = STATE_ACTIVE; + // Need to update the view's autofill id with the session + id.setSessionId(mSessionId); } client.autofillClientResetableStateAvailable(); } catch (RemoteException e) { @@ -2210,6 +2217,13 @@ public final class AutofillManager { return getStateAsString(mState); } + /** @hide */ + public int getSessionId() { + synchronized (mLock) { + return mSessionId; + } + } + @NonNull private static String getStateAsString(int state) { switch (state) { diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java index 8c8352f81df5..c612c888d733 100644 --- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java +++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java @@ -378,6 +378,7 @@ final class AutofillManagerServiceImpl { if (newSession == null) { return NO_SESSION; } + autofillId.setSessionId(newSession.id); final String historyItem = "id=" + newSession.id + " uid=" + uid + " a=" + shortComponentName diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java index c9eb2d2a386f..a9257f65c025 100644 --- a/services/autofill/java/com/android/server/autofill/Session.java +++ b/services/autofill/java/com/android/server/autofill/Session.java @@ -23,6 +23,7 @@ import static android.view.autofill.AutofillManager.ACTION_START_SESSION; import static android.view.autofill.AutofillManager.ACTION_VALUE_CHANGED; import static android.view.autofill.AutofillManager.ACTION_VIEW_ENTERED; import static android.view.autofill.AutofillManager.ACTION_VIEW_EXITED; +import static android.view.autofill.AutofillManager.NO_SESSION; import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage; import static com.android.server.autofill.Helper.getNumericValue; @@ -75,7 +76,6 @@ import android.service.autofill.ValueFinder; import android.util.ArrayMap; import android.util.ArraySet; import android.util.LocalLog; -import android.util.Pair; import android.util.Slog; import android.util.SparseArray; import android.util.TimeUtils; @@ -128,7 +128,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState private final MetricsLogger mMetricsLogger = new MetricsLogger(); - private static AtomicInteger sIdCounter = new AtomicInteger(); + private static AtomicInteger sIdCounter = new AtomicInteger(1); /** ID of the session */ public final int id; @@ -385,6 +385,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState @Override public AutofillValue findRawValueByAutofillId(AutofillId id) { + if (id == null) return null; synchronized (mLock) { return findValueLocked(id); } @@ -397,39 +398,50 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState @GuardedBy("mLock") @Nullable private AutofillValue findValueLocked(@NonNull AutofillId autofillId) { - final AutofillValue value = findValueFromThisSessionOnlyLocked(autofillId); - if (value != null) return value; - - // TODO(b/113281366): rather than explicitly look for previous session, it might be better - // to merge the sessions when created (see note on mergePreviousSessionLocked()) - final ArrayList<Session> previousSessions = mService.getPreviousSessionsLocked(this); - if (previousSessions != null) { + // TODO(b/113281366): rather than explicitly look for previous session, it might be + // better to merge the sessions when created (see note on mergePreviousSessionLocked()) + final int requiredId = autofillId.getSessionId(); + Session rightSession = null; + if (requiredId == NO_SESSION || requiredId == id) { + rightSession = this; + } else { + final ArrayList<Session> previousSessions = mService.getPreviousSessionsLocked(this); + if (previousSessions == null) { + if (sVerbose) Slog.v(TAG, "findValue(): no previous sessions"); + return null; + } if (sDebug) { - Slog.d(TAG, "findValueLocked(): looking on " + previousSessions.size() + Slog.d(TAG, "findValue(): looking on " + previousSessions.size() + " previous sessions for autofillId " + autofillId); } for (int i = 0; i < previousSessions.size(); i++) { final Session previousSession = previousSessions.get(i); - final AutofillValue previousValue = previousSession - .findValueFromThisSessionOnlyLocked(autofillId); - if (previousValue != null) { - return previousValue; + if (previousSession.id == requiredId) { + rightSession = previousSession; + break; } } } - return null; + if (rightSession == null) { + Slog.w(TAG, "findValue(): no session with id" + requiredId); + return null; + } + return rightSession.findValueFromThisSessionOnlyLocked(autofillId); } + @GuardedBy("mLock") @Nullable private AutofillValue findValueFromThisSessionOnlyLocked(@NonNull AutofillId autofillId) { final ViewState state = mViewStates.get(autofillId); if (state == null) { - if (sDebug) Slog.d(TAG, "findValueLocked(): no view state for " + autofillId); + if (sDebug) { + Slog.d(TAG, "findValueLocked(): no view state for " + autofillId + " on " + id); + } return null; } AutofillValue value = state.getCurrentValue(); if (value == null) { - if (sDebug) Slog.d(TAG, "findValueLocked(): no current value for " + autofillId); + Slog.d(TAG, "findValueLocked(): no current value for " + autofillId + " on " + id); value = getValueFromContextsLocked(autofillId); } return value; |