1 /* 2 * Copyright (C) 2022 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.autofill; 18 19 import static android.service.autofill.FillEventHistory.Event.UI_TYPE_DIALOG; 20 import static android.service.autofill.FillEventHistory.Event.UI_TYPE_INLINE; 21 import static android.service.autofill.FillEventHistory.Event.UI_TYPE_MENU; 22 import static android.service.autofill.FillEventHistory.Event.UiType; 23 import static android.view.autofill.AutofillManager.COMMIT_REASON_ACTIVITY_FINISHED; 24 import static android.view.autofill.AutofillManager.COMMIT_REASON_VIEW_CHANGED; 25 import static android.view.autofill.AutofillManager.COMMIT_REASON_VIEW_CLICKED; 26 import static android.view.autofill.AutofillManager.COMMIT_REASON_VIEW_COMMITTED; 27 28 import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_FILL_RESPONSE_REPORTED__DETECTION_PREFERENCE__DETECTION_PREFER_AUTOFILL_PROVIDER; 29 import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_FILL_RESPONSE_REPORTED__DETECTION_PREFERENCE__DETECTION_PREFER_PCC; 30 import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_FILL_RESPONSE_REPORTED__DETECTION_PREFERENCE__DETECTION_PREFER_UNKONWN; 31 import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED; 32 import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__AUTHENTICATION_RESULT__AUTHENTICATION_FAILURE; 33 import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__AUTHENTICATION_RESULT__AUTHENTICATION_RESULT_UNKNOWN; 34 import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__AUTHENTICATION_RESULT__AUTHENTICATION_SUCCESS; 35 import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__AUTHENTICATION_TYPE__AUTHENTICATION_TYPE_UNKNOWN; 36 import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__AUTHENTICATION_TYPE__DATASET_AUTHENTICATION; 37 import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__AUTHENTICATION_TYPE__FULL_AUTHENTICATION; 38 import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__DISPLAY_PRESENTATION_TYPE__DIALOG; 39 import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__DISPLAY_PRESENTATION_TYPE__INLINE; 40 import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__DISPLAY_PRESENTATION_TYPE__MENU; 41 import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__DISPLAY_PRESENTATION_TYPE__UNKNOWN_AUTOFILL_DISPLAY_PRESENTATION_TYPE; 42 import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__ANY_SHOWN; 43 import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__NONE_SHOWN_ACTIVITY_FINISHED; 44 import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__NONE_SHOWN_FILL_REQUEST_FAILED; 45 import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__NONE_SHOWN_NO_FOCUS; 46 import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__NONE_SHOWN_REQUEST_TIMEOUT; 47 import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__NONE_SHOWN_SESSION_COMMITTED_PREMATURELY; 48 import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__NONE_SHOWN_UNKNOWN_REASON; 49 import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__NONE_SHOWN_VIEW_CHANGED; 50 import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__NONE_SHOWN_VIEW_FOCUSED_BEFORE_FILL_DIALOG_RESPONSE; 51 import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__NONE_SHOWN_VIEW_FOCUS_CHANGED; 52 import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__SELECTED_DATASET_PICKED_REASON__PICK_REASON_NO_PCC; 53 import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__SELECTED_DATASET_PICKED_REASON__PICK_REASON_PCC_DETECTION_ONLY; 54 import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__SELECTED_DATASET_PICKED_REASON__PICK_REASON_PCC_DETECTION_PREFERRED_WITH_PROVIDER; 55 import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__SELECTED_DATASET_PICKED_REASON__PICK_REASON_PROVIDER_DETECTION_ONLY; 56 import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__SELECTED_DATASET_PICKED_REASON__PICK_REASON_PROVIDER_DETECTION_PREFERRED_WITH_PCC; 57 import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__SELECTED_DATASET_PICKED_REASON__PICK_REASON_UNKNOWN; 58 import static com.android.server.autofill.Helper.sVerbose; 59 60 import android.annotation.IntDef; 61 import android.annotation.Nullable; 62 import android.content.ComponentName; 63 import android.content.Context; 64 import android.content.pm.PackageManager; 65 import android.provider.Settings; 66 import android.service.autofill.Dataset; 67 import android.text.TextUtils; 68 import android.util.Slog; 69 import android.view.autofill.AutofillId; 70 import android.view.autofill.AutofillManager; 71 72 import com.android.internal.util.FrameworkStatsLog; 73 74 import java.lang.annotation.Retention; 75 import java.lang.annotation.RetentionPolicy; 76 import java.util.List; 77 import java.util.Optional; 78 79 /** Helper class to track and log Autofill presentation stats. */ 80 public final class PresentationStatsEventLogger { 81 private static final String TAG = "PresentationStatsEventLogger"; 82 83 /** 84 * Reasons why presentation was not shown. These are wrappers around 85 * {@link com.android.os.AtomsProto.AutofillPresentationEventReported.PresentationEventResult}. 86 */ 87 @IntDef(prefix = {"NOT_SHOWN_REASON"}, value = { 88 NOT_SHOWN_REASON_ANY_SHOWN, 89 NOT_SHOWN_REASON_VIEW_FOCUS_CHANGED, 90 NOT_SHOWN_REASON_VIEW_FOCUSED_BEFORE_FILL_DIALOG_RESPONSE, 91 NOT_SHOWN_REASON_VIEW_CHANGED, 92 NOT_SHOWN_REASON_ACTIVITY_FINISHED, 93 NOT_SHOWN_REASON_REQUEST_TIMEOUT, 94 NOT_SHOWN_REASON_REQUEST_FAILED, 95 NOT_SHOWN_REASON_NO_FOCUS, 96 NOT_SHOWN_REASON_SESSION_COMMITTED_PREMATURELY, 97 NOT_SHOWN_REASON_UNKNOWN 98 }) 99 @Retention(RetentionPolicy.SOURCE) 100 public @interface NotShownReason {} 101 102 /** 103 * Reasons why presentation was not shown. These are wrappers around 104 * {@link com.android.os.AtomsProto.AutofillPresentationEventReported.AuthenticationType}. 105 */ 106 @IntDef(prefix = {"AUTHENTICATION_TYPE"}, value = { 107 AUTHENTICATION_TYPE_UNKNOWN, 108 AUTHENTICATION_TYPE_DATASET_AUTHENTICATION, 109 AUTHENTICATION_TYPE_FULL_AUTHENTICATION 110 }) 111 @Retention(RetentionPolicy.SOURCE) 112 public @interface AuthenticationType { 113 } 114 115 /** 116 * Reasons why presentation was not shown. These are wrappers around 117 * {@link com.android.os.AtomsProto.AutofillPresentationEventReported.AuthenticationResult}. 118 */ 119 @IntDef(prefix = {"AUTHENTICATION_RESULT"}, value = { 120 AUTHENTICATION_RESULT_UNKNOWN, 121 AUTHENTICATION_RESULT_SUCCESS, 122 AUTHENTICATION_RESULT_FAILURE 123 }) 124 @Retention(RetentionPolicy.SOURCE) 125 public @interface AuthenticationResult { 126 } 127 128 /** 129 * Reasons why the picked dataset was present. These are wrappers around 130 * {@link com.android.os.AtomsProto.AutofillPresentationEventReported.DatasetPickedReason}. 131 * This enum is similar to {@link android.service.autofill.Dataset.DatasetEligibleReason} 132 */ 133 @IntDef(prefix = {"PICK_REASON"}, value = { 134 PICK_REASON_UNKNOWN, 135 PICK_REASON_NO_PCC, 136 PICK_REASON_PROVIDER_DETECTION_ONLY, 137 PICK_REASON_PROVIDER_DETECTION_PREFERRED_WITH_PCC, 138 PICK_REASON_PCC_DETECTION_ONLY, 139 PICK_REASON_PCC_DETECTION_PREFERRED_WITH_PROVIDER, 140 }) 141 @Retention(RetentionPolicy.SOURCE) 142 public @interface DatasetPickedReason {} 143 144 /** 145 * The type of detection that was preferred. These are wrappers around 146 * {@link com.android.os.AtomsProto.AutofillPresentationEventReported.DetectionPreference}. 147 */ 148 @IntDef(prefix = {"DETECTION_PREFER"}, value = { 149 DETECTION_PREFER_UNKNOWN, 150 DETECTION_PREFER_AUTOFILL_PROVIDER, 151 DETECTION_PREFER_PCC 152 }) 153 @Retention(RetentionPolicy.SOURCE) 154 public @interface DetectionPreference { 155 } 156 157 public static final int NOT_SHOWN_REASON_ANY_SHOWN = 158 AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__ANY_SHOWN; 159 public static final int NOT_SHOWN_REASON_VIEW_FOCUS_CHANGED = 160 AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__NONE_SHOWN_VIEW_FOCUS_CHANGED; 161 public static final int NOT_SHOWN_REASON_VIEW_FOCUSED_BEFORE_FILL_DIALOG_RESPONSE = 162 AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__NONE_SHOWN_VIEW_FOCUSED_BEFORE_FILL_DIALOG_RESPONSE; 163 public static final int NOT_SHOWN_REASON_VIEW_CHANGED = 164 AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__NONE_SHOWN_VIEW_CHANGED; 165 public static final int NOT_SHOWN_REASON_ACTIVITY_FINISHED = 166 AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__NONE_SHOWN_ACTIVITY_FINISHED; 167 public static final int NOT_SHOWN_REASON_REQUEST_TIMEOUT = 168 AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__NONE_SHOWN_REQUEST_TIMEOUT; 169 public static final int NOT_SHOWN_REASON_REQUEST_FAILED = 170 AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__NONE_SHOWN_FILL_REQUEST_FAILED; 171 public static final int NOT_SHOWN_REASON_NO_FOCUS = 172 AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__NONE_SHOWN_NO_FOCUS; 173 public static final int NOT_SHOWN_REASON_SESSION_COMMITTED_PREMATURELY = 174 AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__NONE_SHOWN_SESSION_COMMITTED_PREMATURELY; 175 public static final int NOT_SHOWN_REASON_UNKNOWN = 176 AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__NONE_SHOWN_UNKNOWN_REASON; 177 178 public static final int AUTHENTICATION_TYPE_UNKNOWN = 179 AUTOFILL_PRESENTATION_EVENT_REPORTED__AUTHENTICATION_TYPE__AUTHENTICATION_TYPE_UNKNOWN; 180 public static final int AUTHENTICATION_TYPE_DATASET_AUTHENTICATION = 181 AUTOFILL_PRESENTATION_EVENT_REPORTED__AUTHENTICATION_TYPE__DATASET_AUTHENTICATION; 182 public static final int AUTHENTICATION_TYPE_FULL_AUTHENTICATION = 183 AUTOFILL_PRESENTATION_EVENT_REPORTED__AUTHENTICATION_TYPE__FULL_AUTHENTICATION; 184 185 public static final int AUTHENTICATION_RESULT_UNKNOWN = 186 AUTOFILL_PRESENTATION_EVENT_REPORTED__AUTHENTICATION_RESULT__AUTHENTICATION_RESULT_UNKNOWN; 187 public static final int AUTHENTICATION_RESULT_SUCCESS = 188 AUTOFILL_PRESENTATION_EVENT_REPORTED__AUTHENTICATION_RESULT__AUTHENTICATION_SUCCESS; 189 public static final int AUTHENTICATION_RESULT_FAILURE = 190 AUTOFILL_PRESENTATION_EVENT_REPORTED__AUTHENTICATION_RESULT__AUTHENTICATION_FAILURE; 191 192 public static final int PICK_REASON_UNKNOWN = 193 AUTOFILL_PRESENTATION_EVENT_REPORTED__SELECTED_DATASET_PICKED_REASON__PICK_REASON_UNKNOWN; 194 public static final int PICK_REASON_NO_PCC = 195 AUTOFILL_PRESENTATION_EVENT_REPORTED__SELECTED_DATASET_PICKED_REASON__PICK_REASON_NO_PCC; 196 public static final int PICK_REASON_PROVIDER_DETECTION_ONLY = 197 AUTOFILL_PRESENTATION_EVENT_REPORTED__SELECTED_DATASET_PICKED_REASON__PICK_REASON_PROVIDER_DETECTION_ONLY; 198 public static final int PICK_REASON_PROVIDER_DETECTION_PREFERRED_WITH_PCC = 199 AUTOFILL_PRESENTATION_EVENT_REPORTED__SELECTED_DATASET_PICKED_REASON__PICK_REASON_PROVIDER_DETECTION_PREFERRED_WITH_PCC; 200 public static final int PICK_REASON_PCC_DETECTION_ONLY = 201 AUTOFILL_PRESENTATION_EVENT_REPORTED__SELECTED_DATASET_PICKED_REASON__PICK_REASON_PCC_DETECTION_ONLY; 202 public static final int PICK_REASON_PCC_DETECTION_PREFERRED_WITH_PROVIDER = 203 AUTOFILL_PRESENTATION_EVENT_REPORTED__SELECTED_DATASET_PICKED_REASON__PICK_REASON_PCC_DETECTION_PREFERRED_WITH_PROVIDER; 204 205 206 // Values for AutofillFillResponseReported.detection_preference 207 public static final int DETECTION_PREFER_UNKNOWN = 208 AUTOFILL_FILL_RESPONSE_REPORTED__DETECTION_PREFERENCE__DETECTION_PREFER_UNKONWN; 209 public static final int DETECTION_PREFER_AUTOFILL_PROVIDER = 210 AUTOFILL_FILL_RESPONSE_REPORTED__DETECTION_PREFERENCE__DETECTION_PREFER_AUTOFILL_PROVIDER; 211 public static final int DETECTION_PREFER_PCC = 212 AUTOFILL_FILL_RESPONSE_REPORTED__DETECTION_PREFERENCE__DETECTION_PREFER_PCC; 213 private final int mSessionId; 214 215 /** 216 * For app_package_uid. 217 */ 218 private final int mCallingAppUid; 219 private Optional<PresentationStatsEventInternal> mEventInternal; 220 PresentationStatsEventLogger(int sessionId, int callingAppUid)221 private PresentationStatsEventLogger(int sessionId, int callingAppUid) { 222 mSessionId = sessionId; 223 mCallingAppUid = callingAppUid; 224 mEventInternal = Optional.empty(); 225 } 226 227 /** 228 * Create PresentationStatsEventLogger, populated with sessionId and the callingAppUid 229 */ createPresentationLog( int sessionId, int callingAppUid)230 public static PresentationStatsEventLogger createPresentationLog( 231 int sessionId, int callingAppUid) { 232 return new PresentationStatsEventLogger(sessionId, callingAppUid); 233 } 234 startNewEvent()235 public void startNewEvent() { 236 if (mEventInternal.isPresent()) { 237 Slog.e(TAG, "Failed to start new event because already have active event."); 238 return; 239 } 240 mEventInternal = Optional.of(new PresentationStatsEventInternal()); 241 } 242 maybeSetRequestId(int requestId)243 public void maybeSetRequestId(int requestId) { 244 mEventInternal.ifPresent(event -> event.mRequestId = requestId); 245 } 246 maybeSetNoPresentationEventReason(@otShownReason int reason)247 public void maybeSetNoPresentationEventReason(@NotShownReason int reason) { 248 mEventInternal.ifPresent(event -> { 249 if (event.mCountShown == 0) { 250 event.mNoPresentationReason = reason; 251 } 252 }); 253 } 254 maybeSetNoPresentationEventReasonIfNoReasonExists(@otShownReason int reason)255 public void maybeSetNoPresentationEventReasonIfNoReasonExists(@NotShownReason int reason) { 256 mEventInternal.ifPresent(event -> { 257 if (event.mCountShown == 0 && event.mNoPresentationReason == NOT_SHOWN_REASON_UNKNOWN) { 258 event.mNoPresentationReason = reason; 259 } 260 }); 261 } 262 maybeSetAvailableCount(@ullable List<Dataset> datasetList, AutofillId currentViewId)263 public void maybeSetAvailableCount(@Nullable List<Dataset> datasetList, 264 AutofillId currentViewId) { 265 mEventInternal.ifPresent(event -> { 266 CountContainer container = getDatasetCountForAutofillId(datasetList, currentViewId); 267 event.mAvailableCount = container.mAvailableCount; 268 event.mAvailablePccCount = container.mAvailablePccCount; 269 event.mAvailablePccOnlyCount = container.mAvailablePccOnlyCount; 270 event.mIsDatasetAvailable = container.mAvailableCount > 0; 271 }); 272 } 273 maybeSetCountShown(@ullable List<Dataset> datasetList, AutofillId currentViewId)274 public void maybeSetCountShown(@Nullable List<Dataset> datasetList, 275 AutofillId currentViewId) { 276 mEventInternal.ifPresent(event -> { 277 CountContainer container = getDatasetCountForAutofillId(datasetList, currentViewId); 278 event.mCountShown = container.mAvailableCount; 279 if (container.mAvailableCount > 0) { 280 event.mNoPresentationReason = NOT_SHOWN_REASON_ANY_SHOWN; 281 } 282 }); 283 } 284 getDatasetCountForAutofillId(@ullable List<Dataset> datasetList, AutofillId currentViewId)285 private static CountContainer getDatasetCountForAutofillId(@Nullable List<Dataset> datasetList, 286 AutofillId currentViewId) { 287 288 CountContainer container = new CountContainer(); 289 if (datasetList != null) { 290 for (int i = 0; i < datasetList.size(); i++) { 291 Dataset data = datasetList.get(i); 292 if (data != null && data.getFieldIds() != null 293 && data.getFieldIds().contains(currentViewId)) { 294 container.mAvailableCount += 1; 295 if (data.getEligibleReason() == PICK_REASON_PCC_DETECTION_ONLY) { 296 container.mAvailablePccOnlyCount++; 297 container.mAvailablePccCount++; 298 } else if (data.getEligibleReason() 299 == PICK_REASON_PCC_DETECTION_PREFERRED_WITH_PROVIDER) { 300 container.mAvailablePccCount++; 301 } 302 } 303 } 304 } 305 return container; 306 } 307 308 private static class CountContainer{ 309 int mAvailableCount = 0; 310 int mAvailablePccCount = 0; 311 int mAvailablePccOnlyCount = 0; 312 CountContainer()313 CountContainer() {} 314 CountContainer(int availableCount, int availablePccCount, int availablePccOnlyCount)315 CountContainer(int availableCount, int availablePccCount, 316 int availablePccOnlyCount) { 317 mAvailableCount = availableCount; 318 mAvailablePccCount = availablePccCount; 319 mAvailablePccOnlyCount = availablePccOnlyCount; 320 } 321 } 322 maybeSetCountFilteredUserTyping(int countFilteredUserTyping)323 public void maybeSetCountFilteredUserTyping(int countFilteredUserTyping) { 324 mEventInternal.ifPresent(event -> { 325 event.mCountFilteredUserTyping = countFilteredUserTyping; 326 }); 327 } 328 maybeSetCountNotShownImePresentationNotDrawn( int countNotShownImePresentationNotDrawn)329 public void maybeSetCountNotShownImePresentationNotDrawn( 330 int countNotShownImePresentationNotDrawn) { 331 mEventInternal.ifPresent(event -> { 332 event.mCountNotShownImePresentationNotDrawn = countNotShownImePresentationNotDrawn; 333 }); 334 } 335 maybeSetCountNotShownImeUserNotSeen(int countNotShownImeUserNotSeen)336 public void maybeSetCountNotShownImeUserNotSeen(int countNotShownImeUserNotSeen) { 337 mEventInternal.ifPresent(event -> { 338 event.mCountNotShownImeUserNotSeen = countNotShownImeUserNotSeen; 339 }); 340 } 341 maybeSetDisplayPresentationType(@iType int uiType)342 public void maybeSetDisplayPresentationType(@UiType int uiType) { 343 mEventInternal.ifPresent(event -> { 344 event.mDisplayPresentationType = getDisplayPresentationType(uiType); 345 }); 346 } 347 maybeSetFillRequestSentTimestampMs(int timestamp)348 public void maybeSetFillRequestSentTimestampMs(int timestamp) { 349 mEventInternal.ifPresent(event -> { 350 event.mFillRequestSentTimestampMs = timestamp; 351 }); 352 } 353 maybeSetFillResponseReceivedTimestampMs(int timestamp)354 public void maybeSetFillResponseReceivedTimestampMs(int timestamp) { 355 mEventInternal.ifPresent(event -> { 356 event.mFillResponseReceivedTimestampMs = timestamp; 357 }); 358 } 359 maybeSetSuggestionSentTimestampMs(int timestamp)360 public void maybeSetSuggestionSentTimestampMs(int timestamp) { 361 mEventInternal.ifPresent(event -> { 362 event.mSuggestionSentTimestampMs = timestamp; 363 }); 364 } 365 maybeSetSuggestionPresentedTimestampMs(int timestamp)366 public void maybeSetSuggestionPresentedTimestampMs(int timestamp) { 367 mEventInternal.ifPresent(event -> { 368 event.mSuggestionPresentedTimestampMs = timestamp; 369 }); 370 } 371 maybeSetSelectedDatasetId(int selectedDatasetId)372 public void maybeSetSelectedDatasetId(int selectedDatasetId) { 373 mEventInternal.ifPresent(event -> { 374 event.mSelectedDatasetId = selectedDatasetId; 375 }); 376 } 377 maybeSetDialogDismissed(boolean dialogDismissed)378 public void maybeSetDialogDismissed(boolean dialogDismissed) { 379 mEventInternal.ifPresent(event -> { 380 event.mDialogDismissed = dialogDismissed; 381 }); 382 } 383 maybeSetNegativeCtaButtonClicked(boolean negativeCtaButtonClicked)384 public void maybeSetNegativeCtaButtonClicked(boolean negativeCtaButtonClicked) { 385 mEventInternal.ifPresent(event -> { 386 event.mNegativeCtaButtonClicked = negativeCtaButtonClicked; 387 }); 388 } 389 maybeSetPositiveCtaButtonClicked(boolean positiveCtaButtonClicked)390 public void maybeSetPositiveCtaButtonClicked(boolean positiveCtaButtonClicked) { 391 mEventInternal.ifPresent(event -> { 392 event.mPositiveCtaButtonClicked = positiveCtaButtonClicked; 393 }); 394 } 395 maybeSetInlinePresentationAndSuggestionHostUid(Context context, int userId)396 public void maybeSetInlinePresentationAndSuggestionHostUid(Context context, int userId) { 397 mEventInternal.ifPresent(event -> { 398 event.mDisplayPresentationType = 399 AUTOFILL_PRESENTATION_EVENT_REPORTED__DISPLAY_PRESENTATION_TYPE__INLINE; 400 String imeString = Settings.Secure.getStringForUser(context.getContentResolver(), 401 Settings.Secure.DEFAULT_INPUT_METHOD, userId); 402 if (TextUtils.isEmpty(imeString)) { 403 Slog.w(TAG, "No default IME found"); 404 return; 405 } 406 ComponentName imeComponent = ComponentName.unflattenFromString(imeString); 407 if (imeComponent == null) { 408 Slog.w(TAG, "No default IME found"); 409 return; 410 } 411 int imeUid; 412 String packageName = imeComponent.getPackageName(); 413 try { 414 imeUid = context.getPackageManager().getApplicationInfoAsUser(packageName, 415 PackageManager.ApplicationInfoFlags.of(0), userId).uid; 416 } catch (PackageManager.NameNotFoundException e) { 417 Slog.w(TAG, "Couldn't find packageName: " + packageName); 418 return; 419 } 420 event.mInlineSuggestionHostUid = imeUid; 421 }); 422 } 423 maybeSetAutofillServiceUid(int uid)424 public void maybeSetAutofillServiceUid(int uid) { 425 mEventInternal.ifPresent(event -> { 426 event.mAutofillServiceUid = uid; 427 }); 428 } 429 maybeSetIsNewRequest(boolean isRequestTriggered)430 public void maybeSetIsNewRequest(boolean isRequestTriggered) { 431 mEventInternal.ifPresent(event -> { 432 event.mIsRequestTriggered = isRequestTriggered; 433 }); 434 } 435 436 /** 437 * Set authentication_type as long as mEventInternal presents. 438 */ maybeSetAuthenticationType(@uthenticationType int val)439 public void maybeSetAuthenticationType(@AuthenticationType int val) { 440 mEventInternal.ifPresent(event -> { 441 event.mAuthenticationType = val; 442 }); 443 } 444 445 /** 446 * Set authentication_result as long as mEventInternal presents. 447 */ maybeSetAuthenticationResult(@uthenticationResult int val)448 public void maybeSetAuthenticationResult(@AuthenticationResult int val) { 449 mEventInternal.ifPresent(event -> { 450 event.mAuthenticationResult = val; 451 }); 452 } 453 454 /** 455 * Set latency_authentication_ui_display_millis as long as mEventInternal presents. 456 */ maybeSetLatencyAuthenticationUiDisplayMillis(int val)457 public void maybeSetLatencyAuthenticationUiDisplayMillis(int val) { 458 mEventInternal.ifPresent(event -> { 459 event.mLatencyAuthenticationUiDisplayMillis = val; 460 }); 461 } 462 463 /** 464 * Set latency_dataset_display_millis as long as mEventInternal presents. 465 */ maybeSetLatencyDatasetDisplayMillis(int val)466 public void maybeSetLatencyDatasetDisplayMillis(int val) { 467 mEventInternal.ifPresent(event -> { 468 event.mLatencyDatasetDisplayMillis = val; 469 }); 470 } 471 472 /** 473 * Set available_pcc_count. 474 */ maybeSetAvailablePccCount(int val)475 public void maybeSetAvailablePccCount(int val) { 476 mEventInternal.ifPresent(event -> { 477 event.mAvailablePccCount = val; 478 }); 479 } 480 481 /** 482 * Set available_pcc_only_count. 483 */ maybeSetAvailablePccOnlyCount(int val)484 public void maybeSetAvailablePccOnlyCount(int val) { 485 mEventInternal.ifPresent(event -> { 486 event.mAvailablePccOnlyCount = val; 487 }); 488 } 489 490 /** 491 * Set selected_dataset_picked_reason. 492 */ maybeSetSelectedDatasetPickReason(@ataset.DatasetEligibleReason int val)493 public void maybeSetSelectedDatasetPickReason(@Dataset.DatasetEligibleReason int val) { 494 mEventInternal.ifPresent(event -> { 495 event.mSelectedDatasetPickedReason = convertDatasetPickReason(val); 496 }); 497 } 498 499 /** 500 * Set detection_pref 501 */ maybeSetDetectionPreference(@etectionPreference int detectionPreference)502 public void maybeSetDetectionPreference(@DetectionPreference int detectionPreference) { 503 mEventInternal.ifPresent(event -> { 504 event.mDetectionPreference = detectionPreference; 505 }); 506 } 507 convertDatasetPickReason(@ataset.DatasetEligibleReason int val)508 private int convertDatasetPickReason(@Dataset.DatasetEligibleReason int val) { 509 switch (val) { 510 case 0: 511 case 1: 512 case 2: 513 case 3: 514 case 4: 515 case 5: 516 return val; 517 } 518 return PICK_REASON_UNKNOWN; 519 } 520 521 /** 522 * Set field_classification_request_id as long as mEventInternal presents. 523 */ maybeSetFieldClassificationRequestId(int requestId)524 public void maybeSetFieldClassificationRequestId(int requestId) { 525 mEventInternal.ifPresent(event -> { 526 event.mFieldClassificationRequestId = requestId; 527 }); 528 } 529 logAndEndEvent()530 public void logAndEndEvent() { 531 if (!mEventInternal.isPresent()) { 532 Slog.w(TAG, "Shouldn't be logging AutofillPresentationEventReported again for same " 533 + "event"); 534 return; 535 } 536 PresentationStatsEventInternal event = mEventInternal.get(); 537 if (sVerbose) { 538 Slog.v(TAG, "Log AutofillPresentationEventReported:" 539 + " requestId=" + event.mRequestId 540 + " sessionId=" + mSessionId 541 + " mNoPresentationEventReason=" + event.mNoPresentationReason 542 + " mAvailableCount=" + event.mAvailableCount 543 + " mCountShown=" + event.mCountShown 544 + " mCountFilteredUserTyping=" + event.mCountFilteredUserTyping 545 + " mCountNotShownImePresentationNotDrawn=" 546 + event.mCountNotShownImePresentationNotDrawn 547 + " mCountNotShownImeUserNotSeen=" + event.mCountNotShownImeUserNotSeen 548 + " mDisplayPresentationType=" + event.mDisplayPresentationType 549 + " mAutofillServiceUid=" + event.mAutofillServiceUid 550 + " mInlineSuggestionHostUid=" + event.mInlineSuggestionHostUid 551 + " mIsRequestTriggered=" + event.mIsRequestTriggered 552 + " mFillRequestSentTimestampMs=" + event.mFillRequestSentTimestampMs 553 + " mFillResponseReceivedTimestampMs=" + event.mFillResponseReceivedTimestampMs 554 + " mSuggestionSentTimestampMs=" + event.mSuggestionSentTimestampMs 555 + " mSuggestionPresentedTimestampMs=" + event.mSuggestionPresentedTimestampMs 556 + " mSelectedDatasetId=" + event.mSelectedDatasetId 557 + " mDialogDismissed=" + event.mDialogDismissed 558 + " mNegativeCtaButtonClicked=" + event.mNegativeCtaButtonClicked 559 + " mPositiveCtaButtonClicked=" + event.mPositiveCtaButtonClicked 560 + " mAuthenticationType=" + event.mAuthenticationType 561 + " mAuthenticationResult=" + event.mAuthenticationResult 562 + " mLatencyAuthenticationUiDisplayMillis=" 563 + event.mLatencyAuthenticationUiDisplayMillis 564 + " mLatencyDatasetDisplayMillis=" + event.mLatencyDatasetDisplayMillis 565 + " mAvailablePccCount=" + event.mAvailablePccCount 566 + " mAvailablePccOnlyCount=" + event.mAvailablePccOnlyCount 567 + " mSelectedDatasetPickedReason=" + event.mSelectedDatasetPickedReason 568 + " mDetectionPreference=" + event.mDetectionPreference 569 + " mFieldClassificationRequestId=" + event.mFieldClassificationRequestId 570 + " mAppPackageUid=" + mCallingAppUid); 571 } 572 573 // TODO(b/234185326): Distinguish empty responses from other no presentation reasons. 574 if (!event.mIsDatasetAvailable) { 575 mEventInternal = Optional.empty(); 576 return; 577 } 578 FrameworkStatsLog.write( 579 AUTOFILL_PRESENTATION_EVENT_REPORTED, 580 event.mRequestId, 581 mSessionId, 582 event.mNoPresentationReason, 583 event.mAvailableCount, 584 event.mCountShown, 585 event.mCountFilteredUserTyping, 586 event.mCountNotShownImePresentationNotDrawn, 587 event.mCountNotShownImeUserNotSeen, 588 event.mDisplayPresentationType, 589 event.mAutofillServiceUid, 590 event.mInlineSuggestionHostUid, 591 event.mIsRequestTriggered, 592 event.mFillRequestSentTimestampMs, 593 event.mFillResponseReceivedTimestampMs, 594 event.mSuggestionSentTimestampMs, 595 event.mSuggestionPresentedTimestampMs, 596 event.mSelectedDatasetId, 597 event.mDialogDismissed, 598 event.mNegativeCtaButtonClicked, 599 event.mPositiveCtaButtonClicked, 600 event.mAuthenticationType, 601 event.mAuthenticationResult, 602 event.mLatencyAuthenticationUiDisplayMillis, 603 event.mLatencyDatasetDisplayMillis, 604 event.mAvailablePccCount, 605 event.mAvailablePccOnlyCount, 606 event.mSelectedDatasetPickedReason, 607 event.mDetectionPreference, 608 event.mFieldClassificationRequestId, 609 mCallingAppUid); 610 mEventInternal = Optional.empty(); 611 } 612 613 private static final class PresentationStatsEventInternal { 614 int mRequestId; 615 @NotShownReason int mNoPresentationReason = NOT_SHOWN_REASON_UNKNOWN; 616 boolean mIsDatasetAvailable; 617 int mAvailableCount; 618 int mCountShown; 619 int mCountFilteredUserTyping; 620 int mCountNotShownImePresentationNotDrawn; 621 int mCountNotShownImeUserNotSeen; 622 int mDisplayPresentationType = AUTOFILL_PRESENTATION_EVENT_REPORTED__DISPLAY_PRESENTATION_TYPE__UNKNOWN_AUTOFILL_DISPLAY_PRESENTATION_TYPE; 623 int mAutofillServiceUid = -1; 624 int mInlineSuggestionHostUid = -1; 625 boolean mIsRequestTriggered; 626 int mFillRequestSentTimestampMs; 627 int mFillResponseReceivedTimestampMs; 628 int mSuggestionSentTimestampMs; 629 int mSuggestionPresentedTimestampMs; 630 int mSelectedDatasetId = -1; 631 boolean mDialogDismissed = false; 632 boolean mNegativeCtaButtonClicked = false; 633 boolean mPositiveCtaButtonClicked = false; 634 int mAuthenticationType = AUTHENTICATION_TYPE_UNKNOWN; 635 int mAuthenticationResult = AUTHENTICATION_RESULT_UNKNOWN; 636 int mLatencyAuthenticationUiDisplayMillis = -1; 637 int mLatencyDatasetDisplayMillis = -1; 638 int mAvailablePccCount = -1; 639 int mAvailablePccOnlyCount = -1; 640 @DatasetPickedReason int mSelectedDatasetPickedReason = PICK_REASON_UNKNOWN; 641 @DetectionPreference int mDetectionPreference = DETECTION_PREFER_UNKNOWN; 642 int mFieldClassificationRequestId = -1; 643 PresentationStatsEventInternal()644 PresentationStatsEventInternal() {} 645 } 646 getNoPresentationEventReason( @utofillManager.AutofillCommitReason int commitReason)647 static int getNoPresentationEventReason( 648 @AutofillManager.AutofillCommitReason int commitReason) { 649 switch (commitReason) { 650 case COMMIT_REASON_VIEW_COMMITTED: 651 return NOT_SHOWN_REASON_SESSION_COMMITTED_PREMATURELY; 652 case COMMIT_REASON_ACTIVITY_FINISHED: 653 return NOT_SHOWN_REASON_ACTIVITY_FINISHED; 654 case COMMIT_REASON_VIEW_CHANGED: 655 return NOT_SHOWN_REASON_VIEW_CHANGED; 656 case COMMIT_REASON_VIEW_CLICKED: 657 // TODO(b/234185326): Add separate reason for view clicked. 658 default: 659 return NOT_SHOWN_REASON_UNKNOWN; 660 } 661 } 662 getDisplayPresentationType(@iType int uiType)663 private static int getDisplayPresentationType(@UiType int uiType) { 664 switch (uiType) { 665 case UI_TYPE_MENU: 666 return AUTOFILL_PRESENTATION_EVENT_REPORTED__DISPLAY_PRESENTATION_TYPE__MENU; 667 case UI_TYPE_INLINE: 668 return AUTOFILL_PRESENTATION_EVENT_REPORTED__DISPLAY_PRESENTATION_TYPE__INLINE; 669 case UI_TYPE_DIALOG: 670 return AUTOFILL_PRESENTATION_EVENT_REPORTED__DISPLAY_PRESENTATION_TYPE__DIALOG; 671 default: 672 return AUTOFILL_PRESENTATION_EVENT_REPORTED__DISPLAY_PRESENTATION_TYPE__UNKNOWN_AUTOFILL_DISPLAY_PRESENTATION_TYPE; 673 } 674 } 675 } 676