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.credentials.metrics;
18 
19 import android.util.Slog;
20 
21 import com.android.server.credentials.MetricUtilities;
22 import com.android.server.credentials.metrics.shared.ResponseCollective;
23 
24 import java.util.Map;
25 
26 /**
27  * The central chosen provider metric object that mimics our defined metric setup. This is used
28  * in the final phase of the flow and emits final status metrics.
29  * Some types are redundant across these metric collectors, but that has debug use-cases as
30  * these data-types are available at different moments of the flow (and typically, one can feed
31  * into the next).
32  */
33 public class ChosenProviderFinalPhaseMetric {
34     private static final String TAG = "ChosenFinalPhaseMetric";
35     // The session id associated with this API call, used to unite split emits, for the flow
36     // where we know the calling app
37     private final int mSessionIdCaller;
38     // The session id associated with this API call, used to unite split emits, for the flow
39     // where we know the provider apps
40     private final int mSessionIdProvider;
41     // Reveals if the UI was returned, false by default
42     private boolean mUiReturned = false;
43     private int mChosenUid = -1;
44 
45     // Latency figures typically fed in from prior CandidateProviderMetric
46 
47     private int mPreQueryPhaseLatencyMicroseconds = -1;
48     private int mQueryPhaseLatencyMicroseconds = -1;
49 
50     // Timestamps kept in raw nanoseconds. Expected to be converted to microseconds from using
51     // reference 'mServiceBeganTimeNanoseconds' during metric log point
52 
53     // Kept for local reference purposes, the initial timestamp of the service called passed in
54     private long mServiceBeganTimeNanoseconds = -1;
55     // The first query timestamp, which upon emit is normalized to microseconds using the reference
56     // start timestamp
57     private long mQueryStartTimeNanoseconds = -1;
58     // The timestamp at query end, which upon emit will be normalized to microseconds with reference
59     private long mQueryEndTimeNanoseconds = -1;
60     // The UI call timestamp, which upon emit will be normalized to microseconds using reference
61     private long mUiCallStartTimeNanoseconds = -1;
62     // The UI return timestamp, which upon emit will be normalized to microseconds using reference
63     private long mUiCallEndTimeNanoseconds = -1;
64     // The final finish timestamp, which upon emit will be normalized to microseconds with reference
65     private long mFinalFinishTimeNanoseconds = -1;
66     // The status of this provider after selection
67 
68     // Other General Information, such as final api status, provider status, entry info, etc...
69 
70     private int mOemUiUid = -1;
71     private int mFallbackUiUid = -1;
72     private OemUiUsageStatus mOemUiUsageStatus = OemUiUsageStatus.UNKNOWN;
73 
74     private int mChosenProviderStatus = -1;
75     // Indicates if an exception was thrown by this provider, false by default
76     private boolean mHasException = false;
77     // Indicates a framework only exception that occurs in the final phase of the flow
78     private String mFrameworkException = "";
79 
80     // Stores the response credential information, as well as the response entry information which
81     // by default, contains empty info
82     private ResponseCollective mResponseCollective = new ResponseCollective(Map.of(), Map.of());
83     // Indicates if this chosen provider was the primary provider, false by default
84     private boolean mIsPrimary = false;
85 
86 
ChosenProviderFinalPhaseMetric(int sessionIdCaller, int sessionIdProvider)87     public ChosenProviderFinalPhaseMetric(int sessionIdCaller, int sessionIdProvider) {
88         mSessionIdCaller = sessionIdCaller;
89         mSessionIdProvider = sessionIdProvider;
90     }
91 
92     /* ------------------- UID ------------------- */
93 
getChosenUid()94     public int getChosenUid() {
95         return mChosenUid;
96     }
97 
setChosenUid(int chosenUid)98     public void setChosenUid(int chosenUid) {
99         mChosenUid = chosenUid;
100     }
101 
102     /* ---------------- Latencies ------------------ */
103 
104 
105     /* ----- Direct Delta Latencies for Local Utility ------- */
106 
107     /**
108      * In order for a chosen provider to be selected, the call must have successfully begun.
109      * Thus, the {@link InitialPhaseMetric} can directly pass this initial latency figure into
110      * this chosen provider metric.
111      *
112      * @param preQueryPhaseLatencyMicroseconds the millisecond latency for the service start,
113      *                                         typically passed in through the
114      *                                         {@link InitialPhaseMetric}
115      */
setPreQueryPhaseLatencyMicroseconds(int preQueryPhaseLatencyMicroseconds)116     public void setPreQueryPhaseLatencyMicroseconds(int preQueryPhaseLatencyMicroseconds) {
117         mPreQueryPhaseLatencyMicroseconds = preQueryPhaseLatencyMicroseconds;
118     }
119 
120     /**
121      * In order for a chosen provider to be selected, a candidate provider must exist. The
122      * candidate provider can directly pass the final latency figure into this chosen provider
123      * metric.
124      *
125      * @param queryPhaseLatencyMicroseconds the millisecond latency for the query phase, typically
126      *                                      passed in through the {@link CandidatePhaseMetric}
127      */
setQueryPhaseLatencyMicroseconds(int queryPhaseLatencyMicroseconds)128     public void setQueryPhaseLatencyMicroseconds(int queryPhaseLatencyMicroseconds) {
129         mQueryPhaseLatencyMicroseconds = queryPhaseLatencyMicroseconds;
130     }
131 
getPreQueryPhaseLatencyMicroseconds()132     public int getPreQueryPhaseLatencyMicroseconds() {
133         return mPreQueryPhaseLatencyMicroseconds;
134     }
135 
getQueryPhaseLatencyMicroseconds()136     public int getQueryPhaseLatencyMicroseconds() {
137         return mQueryPhaseLatencyMicroseconds;
138     }
139 
getUiPhaseLatencyMicroseconds()140     public int getUiPhaseLatencyMicroseconds() {
141         return (int) ((mUiCallEndTimeNanoseconds
142                 - mUiCallStartTimeNanoseconds) / 1000);
143     }
144 
145     /**
146      * Returns the full provider (invocation to response) latency in microseconds. Expects the
147      * start time to be provided, such as from {@link CandidatePhaseMetric}.
148      */
getEntireProviderLatencyMicroseconds()149     public int getEntireProviderLatencyMicroseconds() {
150         return (int) ((mFinalFinishTimeNanoseconds
151                 - mQueryStartTimeNanoseconds) / 1000);
152     }
153 
154     /**
155      * Returns the full (platform invoked to response) latency in microseconds. Expects the
156      * start time to be provided, such as from {@link InitialPhaseMetric}.
157      */
getEntireLatencyMicroseconds()158     public int getEntireLatencyMicroseconds() {
159         return (int) ((mFinalFinishTimeNanoseconds
160                 - mServiceBeganTimeNanoseconds) / 1000);
161     }
162 
163     /* ----- Timestamps for Latency ----- */
164 
165     /**
166      * In order for a chosen provider to be selected, the call must have successfully begun.
167      * Thus, the {@link InitialPhaseMetric} can directly pass this initial timestamp into this
168      * chosen provider metric.
169      *
170      * @param serviceBeganTimeNanoseconds the timestamp moment when the platform was called,
171      *                                    typically passed in through the {@link InitialPhaseMetric}
172      */
setServiceBeganTimeNanoseconds(long serviceBeganTimeNanoseconds)173     public void setServiceBeganTimeNanoseconds(long serviceBeganTimeNanoseconds) {
174         mServiceBeganTimeNanoseconds = serviceBeganTimeNanoseconds;
175     }
176 
setQueryStartTimeNanoseconds(long queryStartTimeNanoseconds)177     public void setQueryStartTimeNanoseconds(long queryStartTimeNanoseconds) {
178         mQueryStartTimeNanoseconds = queryStartTimeNanoseconds;
179     }
180 
setQueryEndTimeNanoseconds(long queryEndTimeNanoseconds)181     public void setQueryEndTimeNanoseconds(long queryEndTimeNanoseconds) {
182         mQueryEndTimeNanoseconds = queryEndTimeNanoseconds;
183     }
184 
setUiCallStartTimeNanoseconds(long uiCallStartTimeNanoseconds)185     public void setUiCallStartTimeNanoseconds(long uiCallStartTimeNanoseconds) {
186         mUiCallStartTimeNanoseconds = uiCallStartTimeNanoseconds;
187     }
188 
setUiCallEndTimeNanoseconds(long uiCallEndTimeNanoseconds)189     public void setUiCallEndTimeNanoseconds(long uiCallEndTimeNanoseconds) {
190         mUiCallEndTimeNanoseconds = uiCallEndTimeNanoseconds;
191     }
192 
setFinalFinishTimeNanoseconds(long finalFinishTimeNanoseconds)193     public void setFinalFinishTimeNanoseconds(long finalFinishTimeNanoseconds) {
194         mFinalFinishTimeNanoseconds = finalFinishTimeNanoseconds;
195     }
196 
getServiceBeganTimeNanoseconds()197     public long getServiceBeganTimeNanoseconds() {
198         return mServiceBeganTimeNanoseconds;
199     }
200 
getQueryStartTimeNanoseconds()201     public long getQueryStartTimeNanoseconds() {
202         return mQueryStartTimeNanoseconds;
203     }
204 
getQueryEndTimeNanoseconds()205     public long getQueryEndTimeNanoseconds() {
206         return mQueryEndTimeNanoseconds;
207     }
208 
getUiCallStartTimeNanoseconds()209     public long getUiCallStartTimeNanoseconds() {
210         return mUiCallStartTimeNanoseconds;
211     }
212 
getUiCallEndTimeNanoseconds()213     public long getUiCallEndTimeNanoseconds() {
214         return mUiCallEndTimeNanoseconds;
215     }
216 
getFinalFinishTimeNanoseconds()217     public long getFinalFinishTimeNanoseconds() {
218         return mFinalFinishTimeNanoseconds;
219     }
220 
221     /* --- Time Stamp Conversion to Microseconds from Reference Point --- */
222 
223     /**
224      * We collect raw timestamps in nanoseconds for ease of collection. However, given the scope
225      * of our logging timeframe, and size considerations of the metric, we require these to give us
226      * the microsecond timestamps from the start reference point.
227      *
228      * @param specificTimestamp the timestamp to consider, must be greater than the reference
229      * @return the microsecond integer timestamp from service start to query began
230      */
getTimestampFromReferenceStartMicroseconds(long specificTimestamp)231     public int getTimestampFromReferenceStartMicroseconds(long specificTimestamp) {
232         if (specificTimestamp < mServiceBeganTimeNanoseconds) {
233             Slog.i(TAG, "The timestamp is before service started, falling back to default int");
234             return MetricUtilities.DEFAULT_INT_32;
235         }
236         return (int) ((specificTimestamp
237                 - mServiceBeganTimeNanoseconds) / 1000);
238     }
239 
240     /* ----------- Provider Status -------------- */
241 
getChosenProviderStatus()242     public int getChosenProviderStatus() {
243         return mChosenProviderStatus;
244     }
245 
setChosenProviderStatus(int chosenProviderStatus)246     public void setChosenProviderStatus(int chosenProviderStatus) {
247         mChosenProviderStatus = chosenProviderStatus;
248     }
249 
250     /* ----------- Session ID -------------- */
251 
getSessionIdProvider()252     public int getSessionIdProvider() {
253         return mSessionIdProvider;
254     }
255 
256     /* ----------- UI Returned Successfully -------------- */
257 
setUiReturned(boolean uiReturned)258     public void setUiReturned(boolean uiReturned) {
259         mUiReturned = uiReturned;
260     }
261 
isUiReturned()262     public boolean isUiReturned() {
263         return mUiReturned;
264     }
265 
266     /* -------------- Has Exception ---------------- */
267 
setHasException(boolean hasException)268     public void setHasException(boolean hasException) {
269         mHasException = hasException;
270     }
271 
isHasException()272     public boolean isHasException() {
273         return mHasException;
274     }
275 
276     /* -------------- The Entries and Responses Gathered ---------------- */
277 
setResponseCollective(ResponseCollective responseCollective)278     public void setResponseCollective(ResponseCollective responseCollective) {
279         mResponseCollective = responseCollective;
280     }
281 
getResponseCollective()282     public ResponseCollective getResponseCollective() {
283         return mResponseCollective;
284     }
285 
286     /* -------------- Framework Exception ---------------- */
287 
setFrameworkException(String frameworkException)288     public void setFrameworkException(String frameworkException) {
289         mFrameworkException = frameworkException;
290     }
291 
getFrameworkException()292     public String getFrameworkException() {
293         return mFrameworkException;
294     }
295 
296     /* -------------- Session ID for Track One (Known Calling App) ---------------- */
297 
getSessionIdCaller()298     public int getSessionIdCaller() {
299         return mSessionIdCaller;
300     }
301 
setPrimary(boolean primary)302     public void setPrimary(boolean primary) {
303         mIsPrimary = primary;
304     }
305 
isPrimary()306     public boolean isPrimary() {
307         return mIsPrimary;
308     }
309 
setOemUiUid(int oemUiUid)310     public void setOemUiUid(int oemUiUid) {
311         mOemUiUid = oemUiUid;
312     }
313 
getOemUiUid()314     public int getOemUiUid() {
315         return mOemUiUid;
316     }
317 
setFallbackUiUid(int fallbackUiUid)318     public void setFallbackUiUid(int fallbackUiUid) {
319         mFallbackUiUid = fallbackUiUid;
320     }
321 
getFallbackUiUid()322     public int getFallbackUiUid() {
323         return mFallbackUiUid;
324     }
325 
setOemUiUsageStatus(OemUiUsageStatus oemUiUsageStatus)326     public void setOemUiUsageStatus(OemUiUsageStatus oemUiUsageStatus) {
327         mOemUiUsageStatus = oemUiUsageStatus;
328     }
329 
getOemUiUsageStatus()330     public int getOemUiUsageStatus() {
331         return mOemUiUsageStatus.getLoggingInt();
332     }
333 }
334