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_FIELD_CLASSIFICATION_EVENT_REPORTED;
20 import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_FIELD_CLASSIFICATION_EVENT_REPORTED__STATUS__STATUS_CANCELLED;
21 import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_FIELD_CLASSIFICATION_EVENT_REPORTED__STATUS__STATUS_FAIL;
22 import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_FIELD_CLASSIFICATION_EVENT_REPORTED__STATUS__STATUS_SUCCESS;
23 import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_FIELD_CLASSIFICATION_EVENT_REPORTED__STATUS__STATUS_UNKNOWN;
24 import static com.android.server.autofill.Helper.sVerbose;
25 
26 import android.annotation.IntDef;
27 import android.util.Slog;
28 
29 import com.android.internal.util.FrameworkStatsLog;
30 
31 import java.lang.annotation.Retention;
32 import java.lang.annotation.RetentionPolicy;
33 import java.util.Optional;
34 
35 /**
36  * Helper class to log Field Classification stats.
37  */
38 public final class FieldClassificationEventLogger {
39     private static final String TAG = "FieldClassificationEventLogger";
40     private Optional<FieldClassificationEventInternal> mEventInternal;
41 
FieldClassificationEventLogger()42     private FieldClassificationEventLogger() {
43         mEventInternal = Optional.empty();
44     }
45 
46     public static final int STATUS_SUCCESS =
47             AUTOFILL_FIELD_CLASSIFICATION_EVENT_REPORTED__STATUS__STATUS_SUCCESS;
48     public static final int STATUS_UNKNOWN =
49             AUTOFILL_FIELD_CLASSIFICATION_EVENT_REPORTED__STATUS__STATUS_UNKNOWN;
50     public static final int STATUS_FAIL =
51             AUTOFILL_FIELD_CLASSIFICATION_EVENT_REPORTED__STATUS__STATUS_FAIL;
52     public static final int STATUS_CANCELLED =
53             AUTOFILL_FIELD_CLASSIFICATION_EVENT_REPORTED__STATUS__STATUS_CANCELLED;
54 
55     /**
56      * Status of the FieldClassification IPC request. These are wrappers around
57      * {@link com.android.os.AtomsProto.AutofillFieldClassificationEventReported.FieldClassificationRequestStatus}.
58      */
59     @IntDef(prefix = {"STATUS"}, value = {
60             STATUS_UNKNOWN,
61             STATUS_SUCCESS,
62             STATUS_FAIL,
63             STATUS_CANCELLED
64     })
65     @Retention(RetentionPolicy.SOURCE)
66     public @interface FieldClassificationStatus {
67     }
68 
69     /**
70      * A factory constructor to create FieldClassificationEventLogger.
71      */
createLogger()72     public static FieldClassificationEventLogger createLogger() {
73         return new FieldClassificationEventLogger();
74     }
75 
76     /**
77      * Reset mEventInternal before logging for a new request. It shall be called for each
78      * FieldClassification request.
79      */
startNewLogForRequest()80     public void startNewLogForRequest() {
81         if (!mEventInternal.isEmpty()) {
82             Slog.w(TAG, "FieldClassificationEventLogger is not empty before starting for a new "
83                     + "request");
84         }
85         mEventInternal = Optional.of(new FieldClassificationEventInternal());
86     }
87 
88     /**
89      * Set latency_millis as long as mEventInternal presents.
90      */
maybeSetLatencyMillis(long timestamp)91     public void maybeSetLatencyMillis(long timestamp) {
92         mEventInternal.ifPresent(event -> {
93             event.mLatencyClassificationRequestMillis = timestamp;
94         });
95     }
96 
97     /**
98      * Set count_classifications as long as mEventInternal presents.
99      */
maybeSetCountClassifications(int countClassifications)100     public void maybeSetCountClassifications(int countClassifications) {
101         mEventInternal.ifPresent(event -> {
102             event.mCountClassifications = countClassifications;
103         });
104     }
105 
106     /**
107      * Set session_id as long as mEventInternal presents.
108      */
maybeSetSessionId(int sessionId)109     public void maybeSetSessionId(int sessionId) {
110         mEventInternal.ifPresent(event -> {
111             event.mSessionId = sessionId;
112         });
113     }
114 
115     /**
116      * Set request_id as long as mEventInternal presents.
117      */
maybeSetRequestId(int requestId)118     public void maybeSetRequestId(int requestId) {
119         mEventInternal.ifPresent(event -> {
120             event.mRequestId = requestId;
121         });
122     }
123 
124     /**
125      * Set next_fill_request_id as long as mEventInternal presents.
126      */
maybeSetNextFillRequestId(int nextFillRequestId)127     public void maybeSetNextFillRequestId(int nextFillRequestId) {
128         mEventInternal.ifPresent(event -> {
129             event.mNextFillRequestId = nextFillRequestId;
130         });
131     }
132 
133     /**
134      * Set app_package_uid as long as mEventInternal presents.
135      */
maybeSetAppPackageUid(int uid)136     public void maybeSetAppPackageUid(int uid) {
137         mEventInternal.ifPresent(event -> {
138             event.mAppPackageUid = uid;
139         });
140     }
141 
142     /**
143      * Set status as long as mEventInternal presents.
144      */
maybeSetRequestStatus(@ieldClassificationStatus int status)145     public void maybeSetRequestStatus(@FieldClassificationStatus int status) {
146         mEventInternal.ifPresent(event -> {
147             event.mStatus = status;
148         });
149     }
150 
151     /**
152      * Set is_session_gc as long as mEventInternal presents.
153      */
maybeSetSessionGc(boolean isSessionGc)154     public void maybeSetSessionGc(boolean isSessionGc) {
155         mEventInternal.ifPresent(event -> {
156             event.mIsSessionGc = isSessionGc;
157         });
158     }
159 
160     /**
161      * Log an AUTOFILL_FIELD_CLASSIFICATION_EVENT_REPORTED event.
162      */
logAndEndEvent()163     public void logAndEndEvent() {
164         if (!mEventInternal.isPresent()) {
165             Slog.w(TAG, "Shouldn't be logging AutofillFieldClassificationEventInternal again for "
166                     + "same event");
167             return;
168         }
169         FieldClassificationEventInternal event = mEventInternal.get();
170         if (sVerbose) {
171             Slog.v(TAG, "Log AutofillFieldClassificationEventReported:"
172                     + " mLatencyClassificationRequestMillis="
173                     + event.mLatencyClassificationRequestMillis
174                     + " mCountClassifications=" + event.mCountClassifications
175                     + " mSessionId=" + event.mSessionId
176                     + " mRequestId=" + event.mRequestId
177                     + " mNextFillRequestId=" + event.mNextFillRequestId
178                     + " mAppPackageUid=" + event.mAppPackageUid
179                     + " mStatus=" + event.mStatus
180                     + " mIsSessionGc=" + event.mIsSessionGc);
181         }
182         FrameworkStatsLog.write(
183                 AUTOFILL_FIELD_CLASSIFICATION_EVENT_REPORTED,
184                 event.mLatencyClassificationRequestMillis,
185                 event.mCountClassifications,
186                 event.mSessionId,
187                 event.mRequestId,
188                 event.mNextFillRequestId,
189                 event.mAppPackageUid,
190                 event.mStatus,
191                 event.mIsSessionGc);
192         mEventInternal = Optional.empty();
193     }
194 
195     private static final class FieldClassificationEventInternal {
196         long mLatencyClassificationRequestMillis = -1;
197         int mCountClassifications = -1;
198         int mSessionId = -1;
199         int mRequestId = -1;
200         int mNextFillRequestId = -1;
201         int mAppPackageUid = -1;
202         int mStatus;
203         boolean mIsSessionGc;
204 
FieldClassificationEventInternal()205         FieldClassificationEventInternal() {
206         }
207     }
208 }
209