Merge changes from topics 'bug_62802026_take_2', 'bug_62802026' into oc-dev
* changes:
Don't add FillEventHistory events to the wrong session.
Fixed how FillEventHistory is reset and clarified javadoc.
diff --git a/core/java/android/service/autofill/AutofillService.java b/core/java/android/service/autofill/AutofillService.java
index 07c3503..394bd0a 100644
--- a/core/java/android/service/autofill/AutofillService.java
+++ b/core/java/android/service/autofill/AutofillService.java
@@ -208,12 +208,22 @@
}
/**
- * Returns the {@link FillEventHistory.Event events} since the last {@link FillResponse} was
- * returned.
+ * Gets the events that happened after the last
+ * {@link AutofillService#onFillRequest(FillRequest, android.os.CancellationSignal, FillCallback)}
+ * call.
*
- * <p>The history is not persisted over reboots.
+ * <p>This method is typically used to keep track of previous user actions to optimize further
+ * requests. For example, the service might return email addresses in alphabetical order by
+ * default, but change that order based on the address the user picked on previous requests.
*
- * @return The history or {@code null} if there are not events.
+ * <p>The history is not persisted over reboots, and it's cleared every time the service
+ * replies to a {@link #onFillRequest(FillRequest, CancellationSignal, FillCallback)} by calling
+ * {@link FillCallback#onSuccess(FillResponse)} or {@link FillCallback#onFailure(CharSequence)}
+ * (if the service doesn't call any of these methods, the history will clear out after some
+ * pre-defined time). Hence, the service should call {@link #getFillEventHistory()} before
+ * finishing the {@link FillCallback}.
+ *
+ * @return The history or {@code null} if there are no events.
*/
@Nullable public final FillEventHistory getFillEventHistory() {
AutofillManager afm = getSystemService(AutofillManager.class);
diff --git a/core/java/android/service/autofill/FillEventHistory.java b/core/java/android/service/autofill/FillEventHistory.java
index 3d72fcc..f7dc1c5 100644
--- a/core/java/android/service/autofill/FillEventHistory.java
+++ b/core/java/android/service/autofill/FillEventHistory.java
@@ -33,7 +33,20 @@
import java.util.List;
/**
- * Describes what happened after the latest call to {@link FillCallback#onSuccess(FillResponse)}.
+ * Describes what happened after the last
+ * {@link AutofillService#onFillRequest(FillRequest, android.os.CancellationSignal, FillCallback)}
+ * call.
+ *
+ * <p>This history is typically used to keep track of previous user actions to optimize further
+ * requests. For example, the service might return email addresses in alphabetical order by
+ * default, but change that order based on the address the user picked on previous requests.
+ *
+ * <p>The history is not persisted over reboots, and it's cleared every time the service
+ * replies to a
+ * {@link AutofillService#onFillRequest(FillRequest, android.os.CancellationSignal, FillCallback)}
+ * by calling {@link FillCallback#onSuccess(FillResponse)} or
+ * {@link FillCallback#onFailure(CharSequence)} (if the service doesn't call any of these methods,
+ * the history will clear out after some pre-defined time).
*/
public final class FillEventHistory implements Parcelable {
/**
@@ -41,6 +54,11 @@
*/
private final int mServiceUid;
+ /**
+ * Not in parcel. The ID of the autofill session that created the {@link FillResponse}.
+ */
+ private final int mSessionId;
+
@Nullable private final Bundle mClientState;
@Nullable List<Event> mEvents;
@@ -55,10 +73,17 @@
return mServiceUid;
}
+ /** @hide */
+ public int getSessionId() {
+ return mSessionId;
+ }
+
/**
- * Returns the client state of the {@link FillResponse}.
+ * Returns the client state set in the previous {@link FillResponse}.
*
- * @return The client state set by the last {@link FillResponse}
+ * <p><b>NOTE: </b>the state is associated with the app that was autofilled in the previous
+ * {@link AutofillService#onFillRequest(FillRequest, android.os.CancellationSignal, FillCallback)}
+ * , which is not necessary the same app being autofilled now.
*/
@Nullable public Bundle getClientState() {
return mClientState;
@@ -87,9 +112,10 @@
/**
* @hide
*/
- public FillEventHistory(int serviceUid, @Nullable Bundle clientState) {
+ public FillEventHistory(int serviceUid, int sessionId, @Nullable Bundle clientState) {
mClientState = clientState;
mServiceUid = serviceUid;
+ mSessionId = sessionId;
}
@Override
@@ -190,7 +216,7 @@
new Parcelable.Creator<FillEventHistory>() {
@Override
public FillEventHistory createFromParcel(Parcel parcel) {
- FillEventHistory selection = new FillEventHistory(0, parcel.readBundle());
+ FillEventHistory selection = new FillEventHistory(0, 0, parcel.readBundle());
int numEvents = parcel.readInt();
for (int i = 0; i < numEvents; i++) {
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index 38b796b..1a02e8d 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -489,46 +489,78 @@
* Initializes the last fill selection after an autofill service returned a new
* {@link FillResponse}.
*/
- void setLastResponse(int serviceUid, @NonNull FillResponse response) {
+ void setLastResponse(int serviceUid, int sessionId, @NonNull FillResponse response) {
synchronized (mLock) {
- mEventHistory = new FillEventHistory(serviceUid, response.getClientState());
+ mEventHistory = new FillEventHistory(serviceUid, sessionId, response.getClientState());
}
}
/**
+ * Resets the last fill selection.
+ */
+ void resetLastResponse() {
+ synchronized (mLock) {
+ mEventHistory = null;
+ }
+ }
+
+ private boolean isValidEventLocked(String method, int sessionId) {
+ if (mEventHistory == null) {
+ Slog.w(TAG, method + ": not logging event because history is null");
+ return false;
+ }
+ if (sessionId != mEventHistory.getSessionId()) {
+ if (sDebug) {
+ Slog.d(TAG, method + ": not logging event for session " + sessionId
+ + " because tracked session is " + mEventHistory.getSessionId());
+ }
+ return false;
+ }
+ return true;
+ }
+
+ /**
* Updates the last fill selection when an authentication was selected.
*/
- void setAuthenticationSelected() {
+ void setAuthenticationSelected(int sessionId) {
synchronized (mLock) {
- mEventHistory.addEvent(new Event(Event.TYPE_AUTHENTICATION_SELECTED, null));
+ if (isValidEventLocked("setAuthenticationSelected()", sessionId)) {
+ mEventHistory.addEvent(new Event(Event.TYPE_AUTHENTICATION_SELECTED, null));
+ }
}
}
/**
* Updates the last fill selection when an dataset authentication was selected.
*/
- void setDatasetAuthenticationSelected(@Nullable String selectedDataset) {
+ void setDatasetAuthenticationSelected(@Nullable String selectedDataset, int sessionId) {
synchronized (mLock) {
- mEventHistory.addEvent(
- new Event(Event.TYPE_DATASET_AUTHENTICATION_SELECTED, selectedDataset));
+ if (isValidEventLocked("setDatasetAuthenticationSelected()", sessionId)) {
+ mEventHistory.addEvent(
+ new Event(Event.TYPE_DATASET_AUTHENTICATION_SELECTED, selectedDataset));
+ }
}
}
/**
* Updates the last fill selection when an save Ui is shown.
*/
- void setSaveShown() {
+ void setSaveShown(int sessionId) {
synchronized (mLock) {
- mEventHistory.addEvent(new Event(Event.TYPE_SAVE_SHOWN, null));
+ if (isValidEventLocked("setSaveShown()", sessionId)) {
+ mEventHistory.addEvent(new Event(Event.TYPE_SAVE_SHOWN, null));
+ }
}
}
/**
* Updates the last fill response when a dataset was selected.
*/
- void setDatasetSelected(@Nullable String selectedDataset) {
+ void setDatasetSelected(@Nullable String selectedDataset, int sessionId) {
synchronized (mLock) {
- mEventHistory.addEvent(new Event(Event.TYPE_DATASET_SELECTED, selectedDataset));
+ if (isValidEventLocked("setDatasetSelected()", sessionId)) {
+ mEventHistory.addEvent(new Event(Event.TYPE_DATASET_SELECTED, selectedDataset));
+ }
}
}
diff --git a/services/autofill/java/com/android/server/autofill/RemoteFillService.java b/services/autofill/java/com/android/server/autofill/RemoteFillService.java
index 9aebf6d..aebe92e 100644
--- a/services/autofill/java/com/android/server/autofill/RemoteFillService.java
+++ b/services/autofill/java/com/android/server/autofill/RemoteFillService.java
@@ -427,6 +427,7 @@
mCompleted = true;
}
+ Slog.w(LOG_TAG, getClass().getSimpleName() + " timed out");
final RemoteFillService remoteService = mWeakService.get();
if (remoteService != null) {
fail(remoteService);
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 3ae0511..72ad752 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -407,13 +407,14 @@
if ((requestFlags & FLAG_MANUAL_REQUEST) != 0) {
getUiForShowing().showError(R.string.autofill_error_cannot_autofill, this);
}
+ mService.resetLastResponse();
// Nothing to be done, but need to notify client.
notifyUnavailableToClient();
removeSelf();
return;
}
- mService.setLastResponse(serviceUid, response);
+ mService.setLastResponse(serviceUid, id, response);
if ((response.getDatasets() == null || response.getDatasets().isEmpty())
&& response.getAuthentication() == null) {
@@ -444,6 +445,7 @@
+ id + " destroyed");
return;
}
+ mService.resetLastResponse();
}
LogMaker log = (new LogMaker(MetricsEvent.AUTOFILL_REQUEST))
.setType(MetricsEvent.TYPE_FAILURE)
@@ -542,7 +544,7 @@
getFillContextByRequestIdLocked(requestId).getStructure(), extras);
}
- mService.setAuthenticationSelected();
+ mService.setAuthenticationSelected(id);
final int authenticationId = AutofillManager.makeAuthenticationId(requestId, datasetIndex);
mHandlerCaller.getHandler().post(() -> startAuthentication(authenticationId,
@@ -831,7 +833,7 @@
}
if (atLeastOneChanged) {
if (sDebug) Slog.d(TAG, "at least one field changed - showing save UI");
- mService.setSaveShown();
+ mService.setSaveShown(id);
getUiForShowing().showSaveUi(mService.getServiceLabel(), saveInfo, mPackageName,
this);
@@ -1362,14 +1364,14 @@
}
// Autofill it directly...
if (dataset.getAuthentication() == null) {
- mService.setDatasetSelected(dataset.getId());
+ mService.setDatasetSelected(dataset.getId(), id);
autoFillApp(dataset);
return;
}
// ...or handle authentication.
- mService.setDatasetAuthenticationSelected(dataset.getId());
+ mService.setDatasetAuthenticationSelected(dataset.getId(), id);
setViewStatesLocked(null, dataset, ViewState.STATE_WAITING_DATASET_AUTH, false);
final Intent fillInIntent = createAuthFillInIntent(
getFillContextByRequestIdLocked(requestId).getStructure(), mClientState);