1 /*
2  * Copyright (C) 2023 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 com.android.internal.util.FrameworkStatsLog.AUTOFILL_SAVE_EVENT_REPORTED;
20 import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_SAVE_EVENT_REPORTED__SAVE_UI_NOT_SHOWN_REASON__NO_SAVE_REASON_DATASET_MATCH;
21 import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_SAVE_EVENT_REPORTED__SAVE_UI_NOT_SHOWN_REASON__NO_SAVE_REASON_FIELD_VALIDATION_FAILED;
22 import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_SAVE_EVENT_REPORTED__SAVE_UI_NOT_SHOWN_REASON__NO_SAVE_REASON_HAS_EMPTY_REQUIRED;
23 import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_SAVE_EVENT_REPORTED__SAVE_UI_NOT_SHOWN_REASON__NO_SAVE_REASON_NONE;
24 import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_SAVE_EVENT_REPORTED__SAVE_UI_NOT_SHOWN_REASON__NO_SAVE_REASON_NO_SAVE_INFO;
25 import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_SAVE_EVENT_REPORTED__SAVE_UI_NOT_SHOWN_REASON__NO_SAVE_REASON_NO_VALUE_CHANGED;
26 import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_SAVE_EVENT_REPORTED__SAVE_UI_NOT_SHOWN_REASON__NO_SAVE_REASON_SCREEN_HAS_CREDMAN_FIELD;
27 import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_SAVE_EVENT_REPORTED__SAVE_UI_NOT_SHOWN_REASON__NO_SAVE_REASON_SESSION_DESTROYED;
28 import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_SAVE_EVENT_REPORTED__SAVE_UI_NOT_SHOWN_REASON__NO_SAVE_REASON_UNKNOWN;
29 import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_SAVE_EVENT_REPORTED__SAVE_UI_NOT_SHOWN_REASON__NO_SAVE_REASON_WITH_DELAY_SAVE_FLAG;
30 import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_SAVE_EVENT_REPORTED__SAVE_UI_NOT_SHOWN_REASON__NO_SAVE_REASON_WITH_DONT_SAVE_ON_FINISH_FLAG;
31 import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_SAVE_EVENT_REPORTED__SAVE_UI_SHOWN_REASON__SAVE_UI_SHOWN_REASON_OPTIONAL_ID_CHANGE;
32 import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_SAVE_EVENT_REPORTED__SAVE_UI_SHOWN_REASON__SAVE_UI_SHOWN_REASON_REQUIRED_ID_CHANGE;
33 import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_SAVE_EVENT_REPORTED__SAVE_UI_SHOWN_REASON__SAVE_UI_SHOWN_REASON_TRIGGER_ID_SET;
34 import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_SAVE_EVENT_REPORTED__SAVE_UI_SHOWN_REASON__SAVE_UI_SHOWN_REASON_UNKNOWN;
35 import static com.android.server.autofill.Helper.sVerbose;
36 
37 import android.annotation.IntDef;
38 import android.os.SystemClock;
39 import android.util.Slog;
40 
41 import com.android.internal.util.FrameworkStatsLog;
42 
43 import java.lang.annotation.Retention;
44 import java.lang.annotation.RetentionPolicy;
45 import java.util.Optional;
46 
47 /**
48  * Helper class to log Autofill Save event stats.
49  */
50 public class SaveEventLogger {
51   private static final String TAG = "SaveEventLogger";
52 
53   /**
54    * Reasons why presentation was not shown. These are wrappers around
55    * {@link com.android.os.AtomsProto.AutofillSaveEventReported.SaveUiShownReason}.
56    */
57   @IntDef(prefix = {"SAVE_UI_SHOWN_REASON"}, value = {
58       SAVE_UI_SHOWN_REASON_UNKNOWN,
59       SAVE_UI_SHOWN_REASON_REQUIRED_ID_CHANGE,
60       SAVE_UI_SHOWN_REASON_OPTIONAL_ID_CHANGE,
61       SAVE_UI_SHOWN_REASON_TRIGGER_ID_SET
62   })
63   @Retention(RetentionPolicy.SOURCE)
64   public @interface SaveUiShownReason {
65   }
66 
67   /**
68    * Reasons why presentation was not shown. These are wrappers around
69    * {@link com.android.os.AtomsProto.AutofillSaveEventReported.SaveUiNotShownReason}.
70    */
71   @IntDef(prefix = {"SAVE_UI_NOT_SHOWN_REASON"}, value = {
72       NO_SAVE_REASON_UNKNOWN,
73       NO_SAVE_REASON_NONE,
74       NO_SAVE_REASON_NO_SAVE_INFO,
75       NO_SAVE_REASON_WITH_DELAY_SAVE_FLAG,
76       NO_SAVE_REASON_WITH_DONT_SAVE_ON_FINISH_FLAG,
77       NO_SAVE_REASON_HAS_EMPTY_REQUIRED,
78       NO_SAVE_REASON_NO_VALUE_CHANGED,
79       NO_SAVE_REASON_FIELD_VALIDATION_FAILED,
80       NO_SAVE_REASON_DATASET_MATCH,
81       NO_SAVE_REASON_SESSION_DESTROYED
82   })
83   @Retention(RetentionPolicy.SOURCE)
84   public @interface SaveUiNotShownReason {
85   }
86 
87   public static final int SAVE_UI_SHOWN_REASON_UNKNOWN =
88       AUTOFILL_SAVE_EVENT_REPORTED__SAVE_UI_SHOWN_REASON__SAVE_UI_SHOWN_REASON_UNKNOWN;
89   public static final int SAVE_UI_SHOWN_REASON_REQUIRED_ID_CHANGE =
90       AUTOFILL_SAVE_EVENT_REPORTED__SAVE_UI_SHOWN_REASON__SAVE_UI_SHOWN_REASON_REQUIRED_ID_CHANGE;
91   public static final int SAVE_UI_SHOWN_REASON_OPTIONAL_ID_CHANGE =
92       AUTOFILL_SAVE_EVENT_REPORTED__SAVE_UI_SHOWN_REASON__SAVE_UI_SHOWN_REASON_OPTIONAL_ID_CHANGE;
93   public static final int SAVE_UI_SHOWN_REASON_TRIGGER_ID_SET =
94       AUTOFILL_SAVE_EVENT_REPORTED__SAVE_UI_SHOWN_REASON__SAVE_UI_SHOWN_REASON_TRIGGER_ID_SET;
95 
96   public static final int NO_SAVE_REASON_UNKNOWN =
97       AUTOFILL_SAVE_EVENT_REPORTED__SAVE_UI_NOT_SHOWN_REASON__NO_SAVE_REASON_UNKNOWN;
98   public static final int NO_SAVE_REASON_NONE =
99       AUTOFILL_SAVE_EVENT_REPORTED__SAVE_UI_NOT_SHOWN_REASON__NO_SAVE_REASON_NONE;
100   public static final int NO_SAVE_REASON_NO_SAVE_INFO =
101       AUTOFILL_SAVE_EVENT_REPORTED__SAVE_UI_NOT_SHOWN_REASON__NO_SAVE_REASON_NO_SAVE_INFO;
102   public static final int NO_SAVE_REASON_WITH_DELAY_SAVE_FLAG =
103       AUTOFILL_SAVE_EVENT_REPORTED__SAVE_UI_NOT_SHOWN_REASON__NO_SAVE_REASON_WITH_DELAY_SAVE_FLAG;
104   public static final int NO_SAVE_REASON_HAS_EMPTY_REQUIRED =
105       AUTOFILL_SAVE_EVENT_REPORTED__SAVE_UI_NOT_SHOWN_REASON__NO_SAVE_REASON_HAS_EMPTY_REQUIRED;
106   public static final int NO_SAVE_REASON_NO_VALUE_CHANGED =
107       AUTOFILL_SAVE_EVENT_REPORTED__SAVE_UI_NOT_SHOWN_REASON__NO_SAVE_REASON_NO_VALUE_CHANGED;
108   public static final int NO_SAVE_REASON_FIELD_VALIDATION_FAILED =
109       AUTOFILL_SAVE_EVENT_REPORTED__SAVE_UI_NOT_SHOWN_REASON__NO_SAVE_REASON_FIELD_VALIDATION_FAILED;
110   public static final int NO_SAVE_REASON_DATASET_MATCH =
111       AUTOFILL_SAVE_EVENT_REPORTED__SAVE_UI_NOT_SHOWN_REASON__NO_SAVE_REASON_DATASET_MATCH;
112   public static final int NO_SAVE_REASON_SESSION_DESTROYED =
113       AUTOFILL_SAVE_EVENT_REPORTED__SAVE_UI_NOT_SHOWN_REASON__NO_SAVE_REASON_SESSION_DESTROYED;
114   public static final int NO_SAVE_REASON_WITH_DONT_SAVE_ON_FINISH_FLAG =
115       AUTOFILL_SAVE_EVENT_REPORTED__SAVE_UI_NOT_SHOWN_REASON__NO_SAVE_REASON_WITH_DONT_SAVE_ON_FINISH_FLAG;
116   public static final int NO_SAVE_REASON_SCREEN_HAS_CREDMAN_FIELD =
117       AUTOFILL_SAVE_EVENT_REPORTED__SAVE_UI_NOT_SHOWN_REASON__NO_SAVE_REASON_SCREEN_HAS_CREDMAN_FIELD;
118 
119   public static final long UNINITIATED_TIMESTAMP = Long.MIN_VALUE;
120 
121   private final int mSessionId;
122   private Optional<SaveEventInternal> mEventInternal;
123   private final long mSessionStartTimestamp;
124 
SaveEventLogger(int sessionId, long sessionStartTimestamp)125   private SaveEventLogger(int sessionId, long sessionStartTimestamp) {
126       mSessionId = sessionId;
127       mEventInternal = Optional.of(new SaveEventInternal());
128       mSessionStartTimestamp = sessionStartTimestamp;
129   }
130 
131   /** A factory constructor to create FillRequestEventLogger. */
forSessionId(int sessionId, long sessionStartTimestamp)132   public static SaveEventLogger forSessionId(int sessionId, long sessionStartTimestamp) {
133         return new SaveEventLogger(sessionId, sessionStartTimestamp);
134   }
135 
136   /**
137    * Set request_id as long as mEventInternal presents.
138    */
maybeSetRequestId(int requestId)139   public void maybeSetRequestId(int requestId) {
140     mEventInternal.ifPresent(event -> event.mRequestId = requestId);
141   }
142 
143   /**
144    * Set app_package_uid as long as mEventInternal presents.
145    */
maybeSetAppPackageUid(int val)146   public void maybeSetAppPackageUid(int val) {
147     mEventInternal.ifPresent(event -> {
148       event.mAppPackageUid = val;
149     });
150   }
151 
152   /**
153    * Set save_ui_trigger_ids as long as mEventInternal presents.
154    */
maybeSetSaveUiTriggerIds(int val)155   public void maybeSetSaveUiTriggerIds(int val) {
156     mEventInternal.ifPresent(event -> {
157       event.mSaveUiTriggerIds = val;
158     });
159   }
160 
161   /**
162    * Set flag as long as mEventInternal presents.
163    */
maybeSetFlag(int val)164   public void maybeSetFlag(int val) {
165     mEventInternal.ifPresent(event -> {
166       event.mFlag = val;
167     });
168   }
169 
170   /**
171    * Set is_new_field as long as mEventInternal presents.
172    */
maybeSetIsNewField(boolean val)173   public void maybeSetIsNewField(boolean val) {
174     mEventInternal.ifPresent(event -> {
175       event.mIsNewField = val;
176     });
177   }
178 
179   /**
180    * Set save_ui_shown_reason as long as mEventInternal presents.
181    */
maybeSetSaveUiShownReason(@aveUiShownReason int reason)182   public void maybeSetSaveUiShownReason(@SaveUiShownReason int reason) {
183     mEventInternal.ifPresent(event -> {
184       event.mSaveUiShownReason = reason;
185     });
186   }
187 
188   /**
189    * Set save_ui_not_shown_reason as long as mEventInternal presents.
190    */
maybeSetSaveUiNotShownReason(@aveUiNotShownReason int reason)191   public void maybeSetSaveUiNotShownReason(@SaveUiNotShownReason int reason) {
192     mEventInternal.ifPresent(event -> {
193       event.mSaveUiNotShownReason = reason;
194     });
195   }
196 
197   /**
198    * Set save_button_clicked as long as mEventInternal presents.
199    */
maybeSetSaveButtonClicked(boolean val)200   public void maybeSetSaveButtonClicked(boolean val) {
201     mEventInternal.ifPresent(event -> {
202       event.mSaveButtonClicked = val;
203     });
204   }
205 
206   /**
207    * Set cancel_button_clicked as long as mEventInternal presents.
208    */
maybeSetCancelButtonClicked(boolean val)209   public void maybeSetCancelButtonClicked(boolean val) {
210     mEventInternal.ifPresent(event -> {
211       event.mCancelButtonClicked = val;
212     });
213   }
214 
215   /**
216    * Set dialog_dismissed as long as mEventInternal presents.
217    */
maybeSetDialogDismissed(boolean val)218   public void maybeSetDialogDismissed(boolean val) {
219     mEventInternal.ifPresent(event -> {
220       event.mDialogDismissed = val;
221     });
222   }
223 
224   /**
225    * Set is_saved as long as mEventInternal presents.
226    */
maybeSetIsSaved(boolean val)227   public void maybeSetIsSaved(boolean val) {
228     mEventInternal.ifPresent(event -> {
229       event.mIsSaved = val;
230     });
231   }
232 
233   /**
234    * Returns timestamp (relative to mSessionStartTimestamp)
235    */
getElapsedTime()236   private long getElapsedTime() {
237     return SystemClock.elapsedRealtime() - mSessionStartTimestamp;
238   }
239 
240   /**
241    * Set latency_save_ui_display_millis as long as mEventInternal presents.
242    */
maybeSetLatencySaveUiDisplayMillis(long timestamp)243   public void maybeSetLatencySaveUiDisplayMillis(long timestamp) {
244     mEventInternal.ifPresent(event -> {
245       event.mLatencySaveUiDisplayMillis = timestamp;
246     });
247   }
248 
249   /** Set latency_save_ui_display_millis as long as mEventInternal presents. */
maybeSetLatencySaveUiDisplayMillis()250   public void maybeSetLatencySaveUiDisplayMillis() {
251     maybeSetLatencySaveUiDisplayMillis(getElapsedTime());
252   }
253 
254   /**
255    * Set latency_save_request_millis as long as mEventInternal presents.
256    */
maybeSetLatencySaveRequestMillis(long timestamp)257   public void maybeSetLatencySaveRequestMillis(long timestamp) {
258     mEventInternal.ifPresent(event -> {
259       event.mLatencySaveRequestMillis = timestamp;
260     });
261   }
262 
263   /** Set latency_save_request_millis as long as mEventInternal presents. */
maybeSetLatencySaveRequestMillis()264   public void maybeSetLatencySaveRequestMillis() {
265     maybeSetLatencySaveRequestMillis(getElapsedTime());
266   }
267 
268   /**
269    * Set latency_save_finish_millis as long as mEventInternal presents.
270    */
maybeSetLatencySaveFinishMillis(long timestamp)271   public void maybeSetLatencySaveFinishMillis(long timestamp) {
272     mEventInternal.ifPresent(event -> {
273       event.mLatencySaveFinishMillis = timestamp;
274     });
275   }
276 
277   /** Set latency_save_finish_millis as long as mEventInternal presents. */
maybeSetLatencySaveFinishMillis()278   public void maybeSetLatencySaveFinishMillis() {
279     maybeSetLatencySaveFinishMillis(getElapsedTime());
280   }
281 
282   /**
283    * Set is_framework_created_save_info as long as mEventInternal presents.
284    */
maybeSetIsFrameworkCreatedSaveInfo(boolean val)285   public void maybeSetIsFrameworkCreatedSaveInfo(boolean val) {
286     mEventInternal.ifPresent(event -> {
287       event.mIsFrameworkCreatedSaveInfo = val;
288     });
289   }
290 
291   /**
292    * Set autofill_service_uid as long as mEventInternal presents.
293    */
maybeSetAutofillServiceUid(int uid)294   public void maybeSetAutofillServiceUid(int uid) {
295         mEventInternal.ifPresent(
296                 event -> {
297                     event.mServiceUid = uid;
298                 });
299   }
300 
301   /**
302    * Log an AUTOFILL_SAVE_EVENT_REPORTED event.
303    */
logAndEndEvent()304   public void logAndEndEvent() {
305     if (!mEventInternal.isPresent()) {
306       Slog.w(TAG, "Shouldn't be logging AutofillSaveEventReported again for same "
307           + "event");
308       return;
309     }
310     SaveEventInternal event = mEventInternal.get();
311     if (sVerbose) {
312       Slog.v(TAG, "Log AutofillSaveEventReported:"
313           + " requestId=" + event.mRequestId
314           + " sessionId=" + mSessionId
315           + " mAppPackageUid=" + event.mAppPackageUid
316           + " mSaveUiTriggerIds=" + event.mSaveUiTriggerIds
317           + " mFlag=" + event.mFlag
318           + " mIsNewField=" + event.mIsNewField
319           + " mSaveUiShownReason=" + event.mSaveUiShownReason
320           + " mSaveUiNotShownReason=" + event.mSaveUiNotShownReason
321           + " mSaveButtonClicked=" + event.mSaveButtonClicked
322           + " mCancelButtonClicked=" + event.mCancelButtonClicked
323           + " mDialogDismissed=" + event.mDialogDismissed
324           + " mIsSaved=" + event.mIsSaved
325           + " mLatencySaveUiDisplayMillis=" + event.mLatencySaveUiDisplayMillis
326           + " mLatencySaveRequestMillis=" + event.mLatencySaveRequestMillis
327           + " mLatencySaveFinishMillis=" + event.mLatencySaveFinishMillis
328           + " mIsFrameworkCreatedSaveInfo=" + event.mIsFrameworkCreatedSaveInfo
329           + " mServiceUid=" + event.mServiceUid);
330     }
331     FrameworkStatsLog.write(
332         AUTOFILL_SAVE_EVENT_REPORTED,
333         event.mRequestId,
334         mSessionId,
335         event.mAppPackageUid,
336         event.mSaveUiTriggerIds,
337         event.mFlag,
338         event.mIsNewField,
339         event.mSaveUiShownReason,
340         event.mSaveUiNotShownReason,
341         event.mSaveButtonClicked,
342         event.mCancelButtonClicked,
343         event.mDialogDismissed,
344         event.mIsSaved,
345         event.mLatencySaveUiDisplayMillis,
346         event.mLatencySaveRequestMillis,
347         event.mLatencySaveFinishMillis,
348         event.mIsFrameworkCreatedSaveInfo,
349         event.mServiceUid);
350     mEventInternal = Optional.empty();
351   }
352 
353   private static final class SaveEventInternal {
354     int mRequestId;
355     int mAppPackageUid = -1;
356     int mSaveUiTriggerIds = -1;
357     long mFlag = -1;
358     boolean mIsNewField = false;
359     int mSaveUiShownReason = SAVE_UI_SHOWN_REASON_UNKNOWN;
360     int mSaveUiNotShownReason = NO_SAVE_REASON_UNKNOWN;
361     boolean mSaveButtonClicked = false;
362     boolean mCancelButtonClicked = false;
363     boolean mDialogDismissed = false;
364     boolean mIsSaved = false;
365     long mLatencySaveUiDisplayMillis = UNINITIATED_TIMESTAMP;
366     long mLatencySaveRequestMillis = UNINITIATED_TIMESTAMP;
367     long mLatencySaveFinishMillis = UNINITIATED_TIMESTAMP;
368     boolean mIsFrameworkCreatedSaveInfo = false;
369     int mServiceUid = -1;
SaveEventInternal()370     SaveEventInternal() {
371     }
372   }
373 }
374