diff options
| author | 2017-09-18 21:26:55 +0000 | |
|---|---|---|
| committer | 2017-09-18 21:26:55 +0000 | |
| commit | f60da8690f7db73246fca677cb74358322170fe8 (patch) | |
| tree | d3baf2c5e67ba9c4e8abebf8ec9d660adb34d704 | |
| parent | 5134ab5cbd8ad2422a2ad8b3d95dcc964626fe8b (diff) | |
| parent | b093daa296a2e02f98f218e80c03c8636dc15eea (diff) | |
Merge "Added more metrics for Autofill:" into oc-mr1-dev am: d4f72ac3c4
am: b093daa296
Change-Id: Iae09ba2c6a082b87b74bd05320222955bde30dda
8 files changed, 306 insertions, 123 deletions
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java index 61cbce976844..27eeb2e67fb7 100644 --- a/core/java/android/view/autofill/AutofillManager.java +++ b/core/java/android/view/autofill/AutofillManager.java @@ -44,7 +44,7 @@ import android.view.View; import com.android.internal.annotations.GuardedBy; import com.android.internal.logging.MetricsLogger; -import com.android.internal.logging.nano.MetricsProto; +import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import java.io.PrintWriter; import java.lang.annotation.Retention; @@ -1245,10 +1245,10 @@ public final class AutofillManager { } } - final LogMaker log = new LogMaker(MetricsProto.MetricsEvent.AUTOFILL_DATASET_APPLIED); - log.addTaggedData(MetricsProto.MetricsEvent.FIELD_AUTOFILL_NUM_VALUES, itemCount); - log.addTaggedData(MetricsProto.MetricsEvent.FIELD_AUTOFILL_NUM_VIEWS_FILLED, - numApplied); + final LogMaker log = new LogMaker(MetricsEvent.AUTOFILL_DATASET_APPLIED) + .setPackageName(mContext.getPackageName()) + .addTaggedData(MetricsEvent.FIELD_AUTOFILL_NUM_VALUES, itemCount) + .addTaggedData(MetricsEvent.FIELD_AUTOFILL_NUM_VIEWS_FILLED, numApplied); mMetricsLogger.write(log); } } diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto index aa4217cec802..07302706d134 100644 --- a/proto/src/metrics_constants.proto +++ b/proto/src/metrics_constants.proto @@ -4451,6 +4451,82 @@ message MetricsEvent { // OS: O MR FIELD_SELECTION_SMART_RANGE = 1123; + // The value of an autofillable and savable view was reset + // Package: Package of app that was autofilled + // OS: O MR + // Tag FIELD_AUTOFILL_SERVICE: Package of service that processed the request + // Tag FIELD_AUTOFILL_PREVIOUS_LENGTH: the previous length of the value + AUTOFILL_VALUE_RESET = 1124; + + // Tag of AUTOFILL_VALUE_RESET + // OS: O MR + FIELD_AUTOFILL_PREVIOUS_LENGTH = 1125; + + // An autofill dataset authentification succeeded + // Package: Package of app that was autofilled + // OS: O MR + // Tag FIELD_AUTOFILL_SERVICE: Package of service that processed the request + AUTOFILL_DATASET_AUTHENTICATED = 1126; + + // An autofill service provided an invalid dataset authentification + // Package: Package of app that was autofilled + // OS: O MR + // Tag FIELD_AUTOFILL_SERVICE: Package of service that processed the request + AUTOFILL_INVALID_DATASET_AUTHENTICATION = 1127; + + // An autofill service provided an invalid authentification extra + // Package: Package of app that was autofilled + // OS: O MR + // Tag FIELD_AUTOFILL_SERVICE: Package of service that processed the request + AUTOFILL_INVALID_AUTHENTICATION = 1128; + + // An autofill service used a custom description (using RemoteViews) in the Save affordance + // Package: Package of app that is autofilled + // OS: O MR + // Tag FIELD_AUTOFILL_SERVICE: Package of service that processed the request + // Tag FIELD_AUTOFILL_SAVE_TYPE: Type of save object passed by the service + AUTOFILL_SAVE_CUSTOM_DESCRIPTION = 1129; + + // FIELD - Type of save object passed by the service when the Save UI is shown + // OS: O MR + FIELD_AUTOFILL_SAVE_TYPE = 1130; + + // An autofill service used a custom subtitle (String) in the Save affordance + // Package: Package of app that is autofilled + // OS: O MR + // Tag FIELD_AUTOFILL_SERVICE: Package of service that processed the request + // Tag FIELD_AUTOFILL_SAVE_TYPE: Type of save object passed by the service + AUTOFILL_SAVE_CUSTOM_SUBTITLE = 1131; + + // User tapped a link in the custom description of the Save affordance provided by an autofill service + // Package: Package of app that is autofilled + // OS: O MR + // Type TYPE_UNKNOWN: The link was not properly set by the service + // Type TYPE_OPEN: The link launched an activity + // Type TYPE_FAILURE: The link could not launc an activity + // Tag FIELD_AUTOFILL_SERVICE: Package of service that processed the request + // Tag FIELD_AUTOFILL_SAVE_TYPE: Type of save object passed by the service + AUTOFILL_SAVE_LINK_TAPPED = 1132; + + // Result of the validation on save when an autofill service provided a validator + // Package: Package of app that is autofilled + // OS: O MR + // Type TYPE_FAILURE: The validation could not be performed due to an error + // Type TYPE_SUCCESS: The validation passed + // Type TYPE_DISMISS: The validation failed + // Tag FIELD_AUTOFILL_SERVICE: Package of service that processed the request + // Tag FIELD_AUTOFILL_SAVE_TYPE: Type of save object passed by the service + AUTOFILL_SAVE_VALIDATION = 1133; + + // Result of an operation in the autofill save affordance after the user tapped a link in the custom description + // provided by the autofill service + // Package: Package of app that is autofilled + // OS: O MR + // Type TYPE_OPEN: The save affordance was restored + // Type TYPE_DISMISS: The save affordcance was destroyed + // Type TYPE_FAILURE: An invalid opperation was reported by the app's AutofillManager + AUTOFILL_PENDING_SAVE_UI_OPERATION = 1134; + // ---- End O-MR1 Constants, all O-MR1 constants go above this line ---- // OPEN: Settings > Network & Internet > Mobile network diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java index ddc819d39d5e..a1c75bfc16c0 100644 --- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java +++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java @@ -650,7 +650,7 @@ public final class AutofillManagerService extends SystemService { synchronized (mLock) { final AutofillManagerServiceImpl service = peekServiceForUserLocked(userId); if (service == null) return false; - return Objects.equals(packageName, service.getPackageName()); + return Objects.equals(packageName, service.getServicePackageName()); } } diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java index f2f96f824e5b..77ce87171a4b 100644 --- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java +++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java @@ -146,8 +146,9 @@ final class AutofillManagerServiceImpl { updateLocked(disabled); } + @Nullable CharSequence getServiceName() { - final String packageName = getPackageName(); + final String packageName = getServicePackageName(); if (packageName == null) { return null; } @@ -162,7 +163,8 @@ final class AutofillManagerServiceImpl { } } - String getPackageName() { + @Nullable + String getServicePackageName() { final ComponentName serviceComponent = getServiceComponentName(); if (serviceComponent != null) { return serviceComponent.getPackageName(); diff --git a/services/autofill/java/com/android/server/autofill/Helper.java b/services/autofill/java/com/android/server/autofill/Helper.java index 086dd29f0c97..236fbfd94f53 100644 --- a/services/autofill/java/com/android/server/autofill/Helper.java +++ b/services/autofill/java/com/android/server/autofill/Helper.java @@ -18,6 +18,7 @@ package com.android.server.autofill; import android.annotation.NonNull; import android.annotation.Nullable; +import android.metrics.LogMaker; import android.os.Bundle; import android.service.autofill.Dataset; import android.util.ArrayMap; @@ -25,6 +26,8 @@ import android.util.ArraySet; import android.view.autofill.AutofillId; import android.view.autofill.AutofillValue; +import com.android.internal.logging.nano.MetricsProto.MetricsEvent; + import java.util.ArrayList; import java.util.Arrays; import java.util.Objects; @@ -99,4 +102,14 @@ public final class Helper { } return fields; } + + @NonNull + public static LogMaker newLogMaker(int category, String packageName, + String servicePackageName) { + final LogMaker log = new LogMaker(category).setPackageName(packageName); + if (servicePackageName != null) { + log.addTaggedData(MetricsEvent.FIELD_AUTOFILL_SERVICE, servicePackageName); + } + return log; + } } diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java index 171053fd8ddf..09ecdd534da9 100644 --- a/services/autofill/java/com/android/server/autofill/Session.java +++ b/services/autofill/java/com/android/server/autofill/Session.java @@ -417,7 +417,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState mPackageName = packageName; mClient = IAutoFillManagerClient.Stub.asInterface(client); - mMetricsLogger.action(MetricsEvent.AUTOFILL_SESSION_STARTED, mPackageName); + writeLog(MetricsEvent.AUTOFILL_SESSION_STARTED); } /** @@ -477,13 +477,10 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState processResponseLocked(response, requestFlags); } - final LogMaker log = (new LogMaker(MetricsEvent.AUTOFILL_REQUEST)) + final LogMaker log = newLogMaker(MetricsEvent.AUTOFILL_REQUEST, servicePackageName) .setType(MetricsEvent.TYPE_SUCCESS) - .setPackageName(mPackageName) .addTaggedData(MetricsEvent.FIELD_AUTOFILL_NUM_DATASETS, - response.getDatasets() == null ? 0 : response.getDatasets().size()) - .addTaggedData(MetricsEvent.FIELD_AUTOFILL_SERVICE, - servicePackageName); + response.getDatasets() == null ? 0 : response.getDatasets().size()); mMetricsLogger.write(log); } @@ -499,10 +496,8 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState } mService.resetLastResponse(); } - LogMaker log = (new LogMaker(MetricsEvent.AUTOFILL_REQUEST)) - .setType(MetricsEvent.TYPE_FAILURE) - .setPackageName(mPackageName) - .addTaggedData(MetricsEvent.FIELD_AUTOFILL_SERVICE, servicePackageName); + LogMaker log = newLogMaker(MetricsEvent.AUTOFILL_REQUEST, servicePackageName) + .setType(MetricsEvent.TYPE_FAILURE); mMetricsLogger.write(log); getUiForShowing().showError(message, this); @@ -521,11 +516,8 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState return; } } - LogMaker log = (new LogMaker( - MetricsEvent.AUTOFILL_DATA_SAVE_REQUEST)) - .setType(MetricsEvent.TYPE_SUCCESS) - .setPackageName(mPackageName) - .addTaggedData(MetricsEvent.FIELD_AUTOFILL_SERVICE, servicePackageName); + LogMaker log = newLogMaker(MetricsEvent.AUTOFILL_DATA_SAVE_REQUEST, servicePackageName) + .setType(MetricsEvent.TYPE_SUCCESS); mMetricsLogger.write(log); // Nothing left to do... @@ -545,11 +537,8 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState return; } } - LogMaker log = (new LogMaker( - MetricsEvent.AUTOFILL_DATA_SAVE_REQUEST)) - .setType(MetricsEvent.TYPE_FAILURE) - .setPackageName(mPackageName) - .addTaggedData(MetricsEvent.FIELD_AUTOFILL_SERVICE, servicePackageName); + LogMaker log = newLogMaker(MetricsEvent.AUTOFILL_DATA_SAVE_REQUEST, servicePackageName) + .setType(MetricsEvent.TYPE_FAILURE); mMetricsLogger.write(log); getUiForShowing().showError(message, this); @@ -746,21 +735,22 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState final Parcelable result = data.getParcelable(AutofillManager.EXTRA_AUTHENTICATION_RESULT); if (sDebug) Slog.d(TAG, "setAuthenticationResultLocked(): result=" + result); if (result instanceof FillResponse) { - final FillResponse response = (FillResponse) result; - mMetricsLogger.action(MetricsEvent.AUTOFILL_AUTHENTICATED, mPackageName); - replaceResponseLocked(authenticatedResponse, response); + writeLog(MetricsEvent.AUTOFILL_AUTHENTICATED); + replaceResponseLocked(authenticatedResponse, (FillResponse) result); } else if (result instanceof Dataset) { - // TODO: add proper metric if (datasetIdx != AutofillManager.AUTHENTICATION_ID_DATASET_ID_UNDEFINED) { + writeLog(MetricsEvent.AUTOFILL_DATASET_AUTHENTICATED); final Dataset dataset = (Dataset) result; authenticatedResponse.getDatasets().set(datasetIdx, dataset); autoFill(requestId, datasetIdx, dataset, false); + } else { + writeLog(MetricsEvent.AUTOFILL_INVALID_DATASET_AUTHENTICATION); } } else { if (result != null) { Slog.w(TAG, "service returned invalid auth type: " + result); } - // TODO: add proper metric (on else) + writeLog(MetricsEvent.AUTOFILL_INVALID_AUTHENTICATION); processNullResponseLocked(0); } } @@ -774,43 +764,57 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState mHasCallback = hasIt; } - /** - * Shows the save UI, when session can be saved. - * - * @return {@code true} if session is done, or {@code false} if it's pending user action. - */ - public boolean showSaveLocked() { - if (mDestroyed) { - Slog.w(TAG, "Call to Session#showSaveLocked() rejected - session: " - + id + " destroyed"); - return false; - } + @Nullable + private FillResponse getLastResponseLocked(@Nullable String logPrefix) { if (mContexts == null) { - Slog.d(TAG, "showSaveLocked(): no contexts"); - return true; + if (sDebug && logPrefix != null) Slog.d(TAG, logPrefix + ": no contexts"); + return null; } if (mResponses == null) { // Happens when the activity / session was finished before the service replied, or // when the service cannot autofill it (and returned a null response). - if (sVerbose) { - Slog.v(TAG, "showSaveLocked(): no responses on session"); + if (sVerbose && logPrefix != null) { + Slog.v(TAG, logPrefix + ": no responses on session"); } - return true; + return null; } final int lastResponseIdx = getLastResponseIndexLocked(); if (lastResponseIdx < 0) { - Slog.w(TAG, "showSaveLocked(): did not get last response. mResponses=" + mResponses - + ", mViewStates=" + mViewStates); - return true; + if (logPrefix != null) { + Slog.w(TAG, logPrefix + ": did not get last response. mResponses=" + mResponses + + ", mViewStates=" + mViewStates); + } + return null; } final FillResponse response = mResponses.valueAt(lastResponseIdx); - final SaveInfo saveInfo = response.getSaveInfo(); - if (sVerbose) { - Slog.v(TAG, "showSaveLocked(): mResponses=" + mResponses + ", mContexts=" + mContexts + if (sVerbose && logPrefix != null) { + Slog.v(TAG, logPrefix + ": mResponses=" + mResponses + ", mContexts=" + mContexts + ", mViewStates=" + mViewStates); } + return response; + } + + @Nullable + private SaveInfo getSaveInfoLocked() { + final FillResponse response = getLastResponseLocked(null); + return response == null ? null : response.getSaveInfo(); + } + + /** + * Shows the save UI, when session can be saved. + * + * @return {@code true} if session is done, or {@code false} if it's pending user action. + */ + public boolean showSaveLocked() { + if (mDestroyed) { + Slog.w(TAG, "Call to Session#showSaveLocked() rejected - session: " + + id + " destroyed"); + return false; + } + final FillResponse response = getLastResponseLocked("showSaveLocked()"); + final SaveInfo saveInfo = response == null ? null : response.getSaveInfo(); /* * The Save dialog is only shown if all conditions below are met: @@ -922,15 +926,21 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState final InternalValidator validator = saveInfo.getValidator(); if (validator != null) { + final LogMaker log = newLogMaker(MetricsEvent.AUTOFILL_SAVE_VALIDATION); boolean isValid; try { isValid = validator.isValid(valueFinder); + log.setType(isValid + ? MetricsEvent.TYPE_SUCCESS + : MetricsEvent.TYPE_DISMISS); } catch (Exception e) { - Slog.e(TAG, "Not showing save UI because of exception during validation " - + e.getClass()); + Slog.e(TAG, "Not showing save UI because validation failed:", e); + log.setType(MetricsEvent.TYPE_FAILURE); + mMetricsLogger.write(log); return true; } + mMetricsLogger.write(log); if (!isValid) { Slog.i(TAG, "not showing save UI because fields failed validation"); return true; @@ -978,7 +988,8 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState final IAutoFillManagerClient client = getClient(); mPendingSaveUi = new PendingUi(mActivityToken, id, client); getUiForShowing().showSaveUi(mService.getServiceLabel(), mService.getServiceIcon(), - saveInfo, valueFinder, mPackageName, this, mPendingSaveUi); + mService.getServicePackageName(), saveInfo, valueFinder, mPackageName, this, + mPendingSaveUi); if (client != null) { try { client.setSaveUiState(id, true); @@ -1244,6 +1255,21 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState break; case ACTION_VALUE_CHANGED: if (value != null && !value.equals(viewState.getCurrentValue())) { + if (value.isEmpty() + && viewState.getCurrentValue() != null + && viewState.getCurrentValue().isText() + && viewState.getCurrentValue().getTextValue() != null + && getSaveInfoLocked() != null) { + final int length = viewState.getCurrentValue().getTextValue().length(); + if (sDebug) { + Slog.d(TAG, "updateLocked(" + id + "): resetting value that was " + + length + " chars long"); + } + final LogMaker log = newLogMaker(MetricsEvent.AUTOFILL_VALUE_RESET) + .addTaggedData(MetricsEvent.FIELD_AUTOFILL_PREVIOUS_LENGTH, length); + mMetricsLogger.write(log); + } + // Always update the internal state. viewState.setCurrentValue(value); @@ -1319,7 +1345,8 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState filterText = value.getTextValue().toString(); } - getUiForShowing().showFillUi(filledId, response, filterText, mPackageName, this); + getUiForShowing().showFillUi(filledId, response, filterText, + mService.getServicePackageName(), mPackageName, this); } boolean isDestroyed() { @@ -1735,7 +1762,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState mUi.destroyAll(mPendingSaveUi, this); mUi.clearCallback(this); mDestroyed = true; - mMetricsLogger.action(MetricsEvent.AUTOFILL_SESSION_FINISHED, mPackageName); + writeLog(MetricsEvent.AUTOFILL_SESSION_FINISHED); return mRemoteFillService; } @@ -1820,4 +1847,16 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState } return lastResponseIdx; } + + private LogMaker newLogMaker(int category) { + return newLogMaker(category, mService.getServicePackageName()); + } + + private LogMaker newLogMaker(int category, String servicePackageName) { + return Helper.newLogMaker(category, mPackageName, servicePackageName); + } + + private void writeLog(int category) { + mMetricsLogger.write(newLogMaker(category)); + } } 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 cac2bff579ed..434b590d2d12 100644 --- a/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java +++ b/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java @@ -40,8 +40,9 @@ import android.view.autofill.IAutofillWindowPresenter; import android.widget.Toast; import com.android.internal.logging.MetricsLogger; -import com.android.internal.logging.nano.MetricsProto; +import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.server.UiThread; +import com.android.server.autofill.Helper; import java.io.PrintWriter; @@ -158,21 +159,22 @@ public final class AutoFillUI { * @param focusedId the currently focused field * @param response the current fill response * @param filterText text of the view to be filled + * @param servicePackageName package name of the autofill service filling the activity * @param packageName package name of the activity that is filled * @param callback Identifier for the caller */ public void showFillUi(@NonNull AutofillId focusedId, @NonNull FillResponse response, - @Nullable String filterText, @NonNull String packageName, - @NonNull AutoFillUiCallback callback) { + @Nullable String filterText, @Nullable String servicePackageName, + @NonNull String packageName, @NonNull AutoFillUiCallback callback) { if (sDebug) { final int size = filterText == null ? 0 : filterText.length(); Slog.d(TAG, "showFillUi(): id=" + focusedId + ", filter=" + size + " chars"); } - final LogMaker log = (new LogMaker(MetricsProto.MetricsEvent.AUTOFILL_FILL_UI)) - .setPackageName(packageName) - .addTaggedData(MetricsProto.MetricsEvent.FIELD_AUTOFILL_FILTERTEXT_LEN, + final LogMaker log = + Helper.newLogMaker(MetricsEvent.AUTOFILL_FILL_UI, packageName, servicePackageName) + .addTaggedData(MetricsEvent.FIELD_AUTOFILL_FILTERTEXT_LEN, filterText == null ? 0 : filterText.length()) - .addTaggedData(MetricsProto.MetricsEvent.FIELD_AUTOFILL_NUM_DATASETS, + .addTaggedData(MetricsEvent.FIELD_AUTOFILL_NUM_DATASETS, response.getDatasets() == null ? 0 : response.getDatasets().size()); mHandler.post(() -> { @@ -184,7 +186,7 @@ public final class AutoFillUI { filterText, mOverlayControl, new FillUi.Callback() { @Override public void onResponsePicked(FillResponse response) { - log.setType(MetricsProto.MetricsEvent.TYPE_DETAIL); + log.setType(MetricsEvent.TYPE_DETAIL); hideFillUiUiThread(callback); if (mCallback != null) { mCallback.authenticate(response.getRequestId(), @@ -195,7 +197,7 @@ public final class AutoFillUI { @Override public void onDatasetPicked(Dataset dataset) { - log.setType(MetricsProto.MetricsEvent.TYPE_ACTION); + log.setType(MetricsEvent.TYPE_ACTION); hideFillUiUiThread(callback); if (mCallback != null) { final int datasetIndex = response.getDatasets().indexOf(dataset); @@ -205,14 +207,14 @@ public final class AutoFillUI { @Override public void onCanceled() { - log.setType(MetricsProto.MetricsEvent.TYPE_DISMISS); + log.setType(MetricsEvent.TYPE_DISMISS); hideFillUiUiThread(callback); } @Override public void onDestroy() { - if (log.getType() == MetricsProto.MetricsEvent.TYPE_UNKNOWN) { - log.setType(MetricsProto.MetricsEvent.TYPE_CLOSE); + if (log.getType() == MetricsEvent.TYPE_UNKNOWN) { + log.setType(MetricsEvent.TYPE_CLOSE); } mMetricsLogger.write(log); } @@ -246,27 +248,29 @@ public final class AutoFillUI { * Shows the UI asking the user to save for autofill. */ public void showSaveUi(@NonNull CharSequence serviceLabel, @NonNull Drawable serviceIcon, - @NonNull SaveInfo info,@NonNull ValueFinder valueFinder, @NonNull String packageName, + @Nullable String servicePackageName, @NonNull SaveInfo info, + @NonNull ValueFinder valueFinder, @NonNull String packageName, @NonNull AutoFillUiCallback callback, @NonNull PendingUi pendingSaveUi) { if (sVerbose) Slog.v(TAG, "showSaveUi() for " + packageName + ": " + info); int numIds = 0; numIds += info.getRequiredIds() == null ? 0 : info.getRequiredIds().length; numIds += info.getOptionalIds() == null ? 0 : info.getOptionalIds().length; - LogMaker log = (new LogMaker(MetricsProto.MetricsEvent.AUTOFILL_SAVE_UI)) - .setPackageName(packageName).addTaggedData( - MetricsProto.MetricsEvent.FIELD_AUTOFILL_NUM_IDS, numIds); + final LogMaker log = + Helper.newLogMaker(MetricsEvent.AUTOFILL_SAVE_UI, packageName, servicePackageName) + .addTaggedData(MetricsEvent.FIELD_AUTOFILL_NUM_IDS, numIds); mHandler.post(() -> { if (callback != mCallback) { return; } hideAllUiThread(callback); - mSaveUi = new SaveUi(mContext, pendingSaveUi, serviceLabel, serviceIcon, info, - valueFinder, mOverlayControl, new SaveUi.OnSaveListener() { + mSaveUi = new SaveUi(mContext, pendingSaveUi, serviceLabel, serviceIcon, + servicePackageName, packageName, info, valueFinder, mOverlayControl, + new SaveUi.OnSaveListener() { @Override public void onSave() { - log.setType(MetricsProto.MetricsEvent.TYPE_ACTION); + log.setType(MetricsEvent.TYPE_ACTION); hideSaveUiUiThread(mCallback); if (mCallback != null) { mCallback.save(); @@ -276,7 +280,7 @@ public final class AutoFillUI { @Override public void onCancel(IntentSender listener) { - log.setType(MetricsProto.MetricsEvent.TYPE_DISMISS); + log.setType(MetricsEvent.TYPE_DISMISS); hideSaveUiUiThread(mCallback); if (listener != null) { try { @@ -294,8 +298,8 @@ public final class AutoFillUI { @Override public void onDestroy() { - if (log.getType() == MetricsProto.MetricsEvent.TYPE_UNKNOWN) { - log.setType(MetricsProto.MetricsEvent.TYPE_CLOSE); + if (log.getType() == MetricsEvent.TYPE_UNKNOWN) { + log.setType(MetricsEvent.TYPE_CLOSE); if (mCallback != null) { mCallback.cancelSave(); diff --git a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java index d0b2e9240b58..256c3aecad3a 100644 --- a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java +++ b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java @@ -20,6 +20,7 @@ import static com.android.server.autofill.Helper.sDebug; import static com.android.server.autofill.Helper.sVerbose; import android.annotation.NonNull; +import android.annotation.Nullable; import android.app.Dialog; import android.app.PendingIntent; import android.content.Context; @@ -30,6 +31,7 @@ import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; +import android.metrics.LogMaker; import android.os.Handler; import android.os.IBinder; import android.os.RemoteException; @@ -53,6 +55,8 @@ import android.widget.ScrollView; import android.widget.TextView; import com.android.internal.R; +import com.android.internal.logging.MetricsLogger; +import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.server.UiThread; import java.io.PrintWriter; @@ -111,6 +115,7 @@ final class SaveUi { } private final Handler mHandler = UiThread.getHandler(); + private final MetricsLogger mMetricsLogger = new MetricsLogger(); private final @NonNull Dialog mDialog; @@ -121,16 +126,21 @@ final class SaveUi { private final CharSequence mTitle; private final CharSequence mSubTitle; private final PendingUi mPendingUi; + private final String mServicePackageName; + private final String mPackageName; private boolean mDestroyed; SaveUi(@NonNull Context context, @NonNull PendingUi pendingUi, @NonNull CharSequence serviceLabel, @NonNull Drawable serviceIcon, + @Nullable String servicePackageName, @NonNull String packageName, @NonNull SaveInfo info, @NonNull ValueFinder valueFinder, @NonNull OverlayControl overlayControl, @NonNull OnSaveListener listener) { mPendingUi= pendingUi; mListener = new OneTimeListener(listener); mOverlayControl = overlayControl; + mServicePackageName = servicePackageName; + mPackageName = packageName; final LayoutInflater inflater = LayoutInflater.from(context); final View view = inflater.inflate(R.layout.autofill_save, null); @@ -181,6 +191,8 @@ final class SaveUi { ScrollView subtitleContainer = null; final CustomDescription customDescription = info.getCustomDescription(); if (customDescription != null) { + writeLog(MetricsEvent.AUTOFILL_SAVE_CUSTOM_DESCRIPTION, type); + mSubTitle = null; if (sDebug) Slog.d(TAG, "Using custom description"); @@ -190,40 +202,35 @@ final class SaveUi { @Override public boolean onClickHandler(View view, PendingIntent pendingIntent, Intent intent) { + final LogMaker log = + newLogMaker(MetricsEvent.AUTOFILL_SAVE_LINK_TAPPED, type); // We need to hide the Save UI before launching the pending intent, and // restore back it once the activity is finished, and that's achieved by // adding a custom extra in the activity intent. - if (pendingIntent != null) { - if (intent == null) { - Slog.w(TAG, - "remote view on custom description does not have intent"); - return false; - } - if (!pendingIntent.isActivity()) { - Slog.w(TAG, "ignoring custom description pending intent that's not " - + "for an activity: " + pendingIntent); - return false; - } - if (sVerbose) { - Slog.v(TAG, - "Intercepting custom description intent: " + intent); - } - final IBinder token = mPendingUi.getToken(); - intent.putExtra(AutofillManager.EXTRA_RESTORE_SESSION_TOKEN, token); - try { - pendingUi.client.startIntentSender(pendingIntent.getIntentSender(), - intent); - mPendingUi.setState(PendingUi.STATE_PENDING); - if (sDebug) { - Slog.d(TAG, "hiding UI until restored with token " + token); - } - hide(); - } catch (RemoteException e) { - Slog.w(TAG, "error triggering pending intent: " + intent); - return false; - } + final boolean isValid = isValidLink(pendingIntent, intent); + if (!isValid) { + log.setType(MetricsEvent.TYPE_UNKNOWN); + mMetricsLogger.write(log); + return false; + } + if (sVerbose) Slog.v(TAG, "Intercepting custom description intent"); + final IBinder token = mPendingUi.getToken(); + intent.putExtra(AutofillManager.EXTRA_RESTORE_SESSION_TOKEN, token); + try { + pendingUi.client.startIntentSender(pendingIntent.getIntentSender(), + intent); + mPendingUi.setState(PendingUi.STATE_PENDING); + if (sDebug) Slog.d(TAG, "hiding UI until restored with token " + token); + hide(); + log.setType(MetricsEvent.TYPE_OPEN); + mMetricsLogger.write(log); + return true; + } catch (RemoteException e) { + Slog.w(TAG, "error triggering pending intent: " + intent); + log.setType(MetricsEvent.TYPE_FAILURE); + mMetricsLogger.write(log); + return false; } - return true; } }; @@ -241,6 +248,7 @@ final class SaveUi { } else { mSubTitle = info.getDescription(); if (mSubTitle != null) { + writeLog(MetricsEvent.AUTOFILL_SAVE_CUSTOM_SUBTITLE, type); subtitleContainer = view.findViewById(R.id.autofill_save_custom_subtitle); final TextView subtitleView = new TextView(context); subtitleView.setText(mSubTitle); @@ -313,6 +321,37 @@ final class SaveUi { } } + private static boolean isValidLink(PendingIntent pendingIntent, Intent intent) { + if (pendingIntent == null) { + Slog.w(TAG, "isValidLink(): custom description without pending intent"); + return false; + } + if (!pendingIntent.isActivity()) { + Slog.w(TAG, "isValidLink(): pending intent not for activity"); + return false; + } + if (intent == null) { + Slog.w(TAG, "isValidLink(): no intent"); + return false; + } + return true; + } + + private LogMaker newLogMaker(int category, int saveType) { + return newLogMaker(category) + .addTaggedData(MetricsEvent.FIELD_AUTOFILL_SAVE_TYPE, saveType); + } + + private LogMaker newLogMaker(int category) { + return new LogMaker(category) + .setPackageName(mPackageName) + .addTaggedData(MetricsEvent.FIELD_AUTOFILL_SERVICE, mServicePackageName); + } + + private void writeLog(int category, int saveType) { + mMetricsLogger.write(newLogMaker(category, saveType)); + } + /** * Update the pending UI, if any. * @@ -326,17 +365,25 @@ final class SaveUi { + mPendingUi.getToken()); return; } - switch (operation) { - case AutofillManager.PENDING_UI_OPERATION_RESTORE: - if (sDebug) Slog.d(TAG, "Restoring save dialog for " + token); - show(); - break; - case AutofillManager.PENDING_UI_OPERATION_CANCEL: - if (sDebug) Slog.d(TAG, "Cancelling pending save dialog for " + token); - hide(); - break; - default: - Slog.w(TAG, "restore(): invalid operation " + operation); + final LogMaker log = newLogMaker(MetricsEvent.AUTOFILL_PENDING_SAVE_UI_OPERATION); + try { + switch (operation) { + case AutofillManager.PENDING_UI_OPERATION_RESTORE: + if (sDebug) Slog.d(TAG, "Restoring save dialog for " + token); + log.setType(MetricsEvent.TYPE_OPEN); + show(); + break; + case AutofillManager.PENDING_UI_OPERATION_CANCEL: + log.setType(MetricsEvent.TYPE_DISMISS); + if (sDebug) Slog.d(TAG, "Cancelling pending save dialog for " + token); + hide(); + break; + default: + log.setType(MetricsEvent.TYPE_FAILURE); + Slog.w(TAG, "restore(): invalid operation " + operation); + } + } finally { + mMetricsLogger.write(log); } mPendingUi.setState(PendingUi.STATE_FINISHED); } @@ -385,6 +432,8 @@ final class SaveUi { pw.print(prefix); pw.print("title: "); pw.println(mTitle); pw.print(prefix); pw.print("subtitle: "); pw.println(mSubTitle); pw.print(prefix); pw.print("pendingUi: "); pw.println(mPendingUi); + pw.print(prefix); pw.print("service: "); pw.println(mServicePackageName); + pw.print(prefix); pw.print("app: "); pw.println(mPackageName); final View view = mDialog.getWindow().getDecorView(); final int[] loc = view.getLocationOnScreen(); |