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 mChosenProviderStatus = -1;
71     // Indicates if an exception was thrown by this provider, false by default
72     private boolean mHasException = false;
73     // Indicates a framework only exception that occurs in the final phase of the flow
74     private String mFrameworkException = "";
75 
76     // Stores the response credential information, as well as the response entry information which
77     // by default, contains empty info
78     private ResponseCollective mResponseCollective = new ResponseCollective(Map.of(), Map.of());
79     // Indicates if this chosen provider was the primary provider, false by default
80     private boolean mIsPrimary = false;
81 
82 
ChosenProviderFinalPhaseMetric(int sessionIdCaller, int sessionIdProvider)83     public ChosenProviderFinalPhaseMetric(int sessionIdCaller, int sessionIdProvider) {
84         mSessionIdCaller = sessionIdCaller;
85         mSessionIdProvider = sessionIdProvider;
86     }
87 
88     /* ------------------- UID ------------------- */
89 
getChosenUid()90     public int getChosenUid() {
91         return mChosenUid;
92     }
93 
setChosenUid(int chosenUid)94     public void setChosenUid(int chosenUid) {
95         mChosenUid = chosenUid;
96     }
97 
98     /* ---------------- Latencies ------------------ */
99 
100 
101     /* ----- Direct Delta Latencies for Local Utility ------- */
102 
103     /**
104      * In order for a chosen provider to be selected, the call must have successfully begun.
105      * Thus, the {@link InitialPhaseMetric} can directly pass this initial latency figure into
106      * this chosen provider metric.
107      *
108      * @param preQueryPhaseLatencyMicroseconds the millisecond latency for the service start,
109      *                                         typically passed in through the
110      *                                         {@link InitialPhaseMetric}
111      */
setPreQueryPhaseLatencyMicroseconds(int preQueryPhaseLatencyMicroseconds)112     public void setPreQueryPhaseLatencyMicroseconds(int preQueryPhaseLatencyMicroseconds) {
113         mPreQueryPhaseLatencyMicroseconds = preQueryPhaseLatencyMicroseconds;
114     }
115 
116     /**
117      * In order for a chosen provider to be selected, a candidate provider must exist. The
118      * candidate provider can directly pass the final latency figure into this chosen provider
119      * metric.
120      *
121      * @param queryPhaseLatencyMicroseconds the millisecond latency for the query phase, typically
122      *                                      passed in through the {@link CandidatePhaseMetric}
123      */
setQueryPhaseLatencyMicroseconds(int queryPhaseLatencyMicroseconds)124     public void setQueryPhaseLatencyMicroseconds(int queryPhaseLatencyMicroseconds) {
125         mQueryPhaseLatencyMicroseconds = queryPhaseLatencyMicroseconds;
126     }
127 
getPreQueryPhaseLatencyMicroseconds()128     public int getPreQueryPhaseLatencyMicroseconds() {
129         return mPreQueryPhaseLatencyMicroseconds;
130     }
131 
getQueryPhaseLatencyMicroseconds()132     public int getQueryPhaseLatencyMicroseconds() {
133         return mQueryPhaseLatencyMicroseconds;
134     }
135 
getUiPhaseLatencyMicroseconds()136     public int getUiPhaseLatencyMicroseconds() {
137         return (int) ((mUiCallEndTimeNanoseconds
138                 - mUiCallStartTimeNanoseconds) / 1000);
139     }
140 
141     /**
142      * Returns the full provider (invocation to response) latency in microseconds. Expects the
143      * start time to be provided, such as from {@link CandidatePhaseMetric}.
144      */
getEntireProviderLatencyMicroseconds()145     public int getEntireProviderLatencyMicroseconds() {
146         return (int) ((mFinalFinishTimeNanoseconds
147                 - mQueryStartTimeNanoseconds) / 1000);
148     }
149 
150     /**
151      * Returns the full (platform invoked to response) latency in microseconds. Expects the
152      * start time to be provided, such as from {@link InitialPhaseMetric}.
153      */
getEntireLatencyMicroseconds()154     public int getEntireLatencyMicroseconds() {
155         return (int) ((mFinalFinishTimeNanoseconds
156                 - mServiceBeganTimeNanoseconds) / 1000);
157     }
158 
159     /* ----- Timestamps for Latency ----- */
160 
161     /**
162      * In order for a chosen provider to be selected, the call must have successfully begun.
163      * Thus, the {@link InitialPhaseMetric} can directly pass this initial timestamp into this
164      * chosen provider metric.
165      *
166      * @param serviceBeganTimeNanoseconds the timestamp moment when the platform was called,
167      *                                    typically passed in through the {@link InitialPhaseMetric}
168      */
setServiceBeganTimeNanoseconds(long serviceBeganTimeNanoseconds)169     public void setServiceBeganTimeNanoseconds(long serviceBeganTimeNanoseconds) {
170         mServiceBeganTimeNanoseconds = serviceBeganTimeNanoseconds;
171     }
172 
setQueryStartTimeNanoseconds(long queryStartTimeNanoseconds)173     public void setQueryStartTimeNanoseconds(long queryStartTimeNanoseconds) {
174         mQueryStartTimeNanoseconds = queryStartTimeNanoseconds;
175     }
176 
setQueryEndTimeNanoseconds(long queryEndTimeNanoseconds)177     public void setQueryEndTimeNanoseconds(long queryEndTimeNanoseconds) {
178         mQueryEndTimeNanoseconds = queryEndTimeNanoseconds;
179     }
180 
setUiCallStartTimeNanoseconds(long uiCallStartTimeNanoseconds)181     public void setUiCallStartTimeNanoseconds(long uiCallStartTimeNanoseconds) {
182         mUiCallStartTimeNanoseconds = uiCallStartTimeNanoseconds;
183     }
184 
setUiCallEndTimeNanoseconds(long uiCallEndTimeNanoseconds)185     public void setUiCallEndTimeNanoseconds(long uiCallEndTimeNanoseconds) {
186         mUiCallEndTimeNanoseconds = uiCallEndTimeNanoseconds;
187     }
188 
setFinalFinishTimeNanoseconds(long finalFinishTimeNanoseconds)189     public void setFinalFinishTimeNanoseconds(long finalFinishTimeNanoseconds) {
190         mFinalFinishTimeNanoseconds = finalFinishTimeNanoseconds;
191     }
192 
getServiceBeganTimeNanoseconds()193     public long getServiceBeganTimeNanoseconds() {
194         return mServiceBeganTimeNanoseconds;
195     }
196 
getQueryStartTimeNanoseconds()197     public long getQueryStartTimeNanoseconds() {
198         return mQueryStartTimeNanoseconds;
199     }
200 
getQueryEndTimeNanoseconds()201     public long getQueryEndTimeNanoseconds() {
202         return mQueryEndTimeNanoseconds;
203     }
204 
getUiCallStartTimeNanoseconds()205     public long getUiCallStartTimeNanoseconds() {
206         return mUiCallStartTimeNanoseconds;
207     }
208 
getUiCallEndTimeNanoseconds()209     public long getUiCallEndTimeNanoseconds() {
210         return mUiCallEndTimeNanoseconds;
211     }
212 
getFinalFinishTimeNanoseconds()213     public long getFinalFinishTimeNanoseconds() {
214         return mFinalFinishTimeNanoseconds;
215     }
216 
217     /* --- Time Stamp Conversion to Microseconds from Reference Point --- */
218 
219     /**
220      * We collect raw timestamps in nanoseconds for ease of collection. However, given the scope
221      * of our logging timeframe, and size considerations of the metric, we require these to give us
222      * the microsecond timestamps from the start reference point.
223      *
224      * @param specificTimestamp the timestamp to consider, must be greater than the reference
225      * @return the microsecond integer timestamp from service start to query began
226      */
getTimestampFromReferenceStartMicroseconds(long specificTimestamp)227     public int getTimestampFromReferenceStartMicroseconds(long specificTimestamp) {
228         if (specificTimestamp < mServiceBeganTimeNanoseconds) {
229             Slog.i(TAG, "The timestamp is before service started, falling back to default int");
230             return MetricUtilities.DEFAULT_INT_32;
231         }
232         return (int) ((specificTimestamp
233                 - mServiceBeganTimeNanoseconds) / 1000);
234     }
235 
236     /* ----------- Provider Status -------------- */
237 
getChosenProviderStatus()238     public int getChosenProviderStatus() {
239         return mChosenProviderStatus;
240     }
241 
setChosenProviderStatus(int chosenProviderStatus)242     public void setChosenProviderStatus(int chosenProviderStatus) {
243         mChosenProviderStatus = chosenProviderStatus;
244     }
245 
246     /* ----------- Session ID -------------- */
247 
getSessionIdProvider()248     public int getSessionIdProvider() {
249         return mSessionIdProvider;
250     }
251 
252     /* ----------- UI Returned Successfully -------------- */
253 
setUiReturned(boolean uiReturned)254     public void setUiReturned(boolean uiReturned) {
255         mUiReturned = uiReturned;
256     }
257 
isUiReturned()258     public boolean isUiReturned() {
259         return mUiReturned;
260     }
261 
262     /* -------------- Has Exception ---------------- */
263 
setHasException(boolean hasException)264     public void setHasException(boolean hasException) {
265         mHasException = hasException;
266     }
267 
isHasException()268     public boolean isHasException() {
269         return mHasException;
270     }
271 
272     /* -------------- The Entries and Responses Gathered ---------------- */
273 
setResponseCollective(ResponseCollective responseCollective)274     public void setResponseCollective(ResponseCollective responseCollective) {
275         mResponseCollective = responseCollective;
276     }
277 
getResponseCollective()278     public ResponseCollective getResponseCollective() {
279         return mResponseCollective;
280     }
281 
282     /* -------------- Framework Exception ---------------- */
283 
setFrameworkException(String frameworkException)284     public void setFrameworkException(String frameworkException) {
285         mFrameworkException = frameworkException;
286     }
287 
getFrameworkException()288     public String getFrameworkException() {
289         return mFrameworkException;
290     }
291 
292     /* -------------- Session ID for Track One (Known Calling App) ---------------- */
293 
getSessionIdCaller()294     public int getSessionIdCaller() {
295         return mSessionIdCaller;
296     }
297 
setPrimary(boolean primary)298     public void setPrimary(boolean primary) {
299         mIsPrimary = primary;
300     }
301 
isPrimary()302     public boolean isPrimary() {
303         return mIsPrimary;
304     }
305 }
306