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