• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2024 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 android.app.jank;
18 
19 import android.annotation.FlaggedApi;
20 import android.annotation.NonNull;
21 import android.annotation.Nullable;
22 import android.annotation.StringDef;
23 
24 import java.lang.annotation.ElementType;
25 import java.lang.annotation.Retention;
26 import java.lang.annotation.RetentionPolicy;
27 import java.lang.annotation.Target;
28 
29 /**
30  *  This class stores detailed jank statistics for an individual UI widget. These statistics
31  *  provide performance insights for specific UI widget states by correlating the number of
32  *  "Janky frames" with the total frames rendered while the widget is in that state. This class
33  *  can be used by library widgets to provide the system with more detailed information about
34  *  where jank is happening for diagnostic purposes.
35  */
36 @FlaggedApi(Flags.FLAG_DETAILED_APP_JANK_METRICS_API)
37 public final class AppJankStats {
38     // UID of the app
39     private int mUid;
40 
41     // The id that has been set for the widget.
42     private String mWidgetId;
43 
44     // A general category the widget falls into based on the functions it performs or helps
45     // facilitate.
46     private String mWidgetCategory;
47 
48     // The states that the UI elements can report
49     private String mWidgetState;
50 
51     // The number of frames reported during this state.
52     private long mTotalFrames;
53 
54     // Total number of frames determined to be janky during the reported state.
55     private long mJankyFrames;
56 
57     // Histogram of relative frame times encoded in predetermined buckets.
58     private RelativeFrameTimeHistogram mRelativeFrameTimeHistogram;
59 
60     // Navigation component associated to this stat.
61     private String mNavigationComponent;
62 
63     /** Used to indicate no widget category has been set. */
64     public static final String WIDGET_CATEGORY_UNSPECIFIED = "unspecified";
65 
66     /** UI elements that facilitate scrolling. */
67     public static final String WIDGET_CATEGORY_SCROLL = "scroll";
68 
69     /** UI elements that facilitate playing animations. */
70     public static final String WIDGET_CATEGORY_ANIMATION = "animation";
71 
72     /** UI elements that facilitate media playback. */
73     public static final String WIDGET_CATEGORY_MEDIA = "media";
74 
75     /** UI elements that facilitate in-app navigation. */
76     public static final String WIDGET_CATEGORY_NAVIGATION = "navigation";
77 
78     /** UI elements that facilitate displaying, hiding or interacting with keyboard. */
79     public static final String WIDGET_CATEGORY_KEYBOARD = "keyboard";
80 
81     /** UI elements that don't fall in one or any of the other categories. */
82     public static final String WIDGET_CATEGORY_OTHER = "other";
83 
84     /** Used to indicate no widget state has been set. */
85     public static final String WIDGET_STATE_UNSPECIFIED = "unspecified";
86 
87     /** Used to indicate the UI element currently has no state and is idle. */
88     public static final String WIDGET_STATE_NONE = "none";
89 
90     /** Used to indicate the UI element is currently scrolling. */
91     public static final String WIDGET_STATE_SCROLLING = "scrolling";
92 
93     /** Used to indicate the UI element is currently being flung. */
94     public static final String WIDGET_STATE_FLINGING = "flinging";
95 
96     /** Used to indicate the UI element is currently being swiped. */
97     public static final String WIDGET_STATE_SWIPING = "swiping";
98 
99     /** Used to indicate the UI element is currently being dragged. */
100     public static final String WIDGET_STATE_DRAGGING = "dragging";
101 
102     /** Used to indicate the UI element is currently zooming. */
103     public static final String WIDGET_STATE_ZOOMING = "zooming";
104 
105     /** Used to indicate the UI element is currently animating. */
106     public static final String WIDGET_STATE_ANIMATING = "animating";
107 
108     /** Used to indicate the UI element is currently playing media. */
109     public static final String WIDGET_STATE_PLAYBACK = "playback";
110 
111     /** Used to indicate the UI element is currently being tapped on, for example on a keyboard. */
112     public static final String WIDGET_STATE_TAPPING = "tapping";
113 
114     /** Used to indicate predictive back navigation is currently being used */
115     public static final String WIDGET_STATE_PREDICTIVE_BACK = "predictive_back";
116 
117 
118     /**
119      * Provide an organized way to group widgets that have similar purposes or perform related
120      * functions.
121      * @hide
122      */
123     @StringDef(prefix = {"WIDGET_CATEGORY_"}, value = {
124             WIDGET_CATEGORY_UNSPECIFIED,
125             WIDGET_CATEGORY_SCROLL,
126             WIDGET_CATEGORY_ANIMATION,
127             WIDGET_CATEGORY_MEDIA,
128             WIDGET_CATEGORY_NAVIGATION,
129             WIDGET_CATEGORY_KEYBOARD,
130             WIDGET_CATEGORY_OTHER
131     })
132     @Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
133     @Retention(RetentionPolicy.SOURCE)
134     public @interface WidgetCategory {
135     }
136     /**
137      * @hide
138      */
139     @StringDef(prefix = {"WIDGET_STATE_"}, value = {
140             WIDGET_STATE_UNSPECIFIED,
141             WIDGET_STATE_NONE,
142             WIDGET_STATE_SCROLLING,
143             WIDGET_STATE_FLINGING,
144             WIDGET_STATE_SWIPING,
145             WIDGET_STATE_DRAGGING,
146             WIDGET_STATE_ZOOMING,
147             WIDGET_STATE_ANIMATING,
148             WIDGET_STATE_PLAYBACK,
149             WIDGET_STATE_TAPPING,
150             WIDGET_STATE_PREDICTIVE_BACK
151     })
152     @Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
153     @Retention(RetentionPolicy.SOURCE)
154     public @interface WidgetState {
155     }
156 
157 
158     /**
159      * Creates a new AppJankStats object.
160      *
161      * @param appUid the Uid of the App that is collecting jank stats.
162      * @param widgetId the widget id that frames will be associated to.
163      * @param navigationComponent the intended navigation target within the activity, this could be
164      *                            a navigation destination, screen and/or pane.
165      * @param widgetCategory a category used to organize widgets in a structured way that indicates
166      *                       they serve a similar purpose or perform related functions. Must be
167      *                       prefixed with WIDGET_CATEGORY_ and have a suffix of one of the
168      *                       following:SCROLL, ANIMATION, MEDIA, NAVIGATION, KEYBOARD, OTHER or
169      *                       will be set to UNSPECIFIED if no value is passed.
170      * @param widgetState the state the widget was in while frames were counted. Must be prefixed
171      *                    with WIDGET_STATE_ and have a suffix of one of the following:
172      *                    NONE, SCROLLING, FLINGING, SWIPING, DRAGGING, ZOOMING, ANIMATING,
173      *                    PLAYBACK, TAPPING, PREDICTIVE_BACK or will be set to
174      *                    WIDGET_STATE_UNSPECIFIED if no value is passed.
175      * @param totalFrames the total number of frames that were counted for this stat.
176      * @param jankyFrames the total number of janky frames that were counted for this stat.
177      * @param relativeFrameTimeHistogram the histogram with predefined buckets. See
178      * {@link #getRelativeFrameTimeHistogram()} for details.
179      */
AppJankStats(int appUid, @NonNull String widgetId, @Nullable String navigationComponent, @Nullable @WidgetCategory String widgetCategory, @Nullable @WidgetState String widgetState, long totalFrames, long jankyFrames, @NonNull RelativeFrameTimeHistogram relativeFrameTimeHistogram)180     public AppJankStats(int appUid, @NonNull String widgetId, @Nullable String navigationComponent,
181             @Nullable @WidgetCategory String widgetCategory,
182             @Nullable @WidgetState String widgetState, long totalFrames, long jankyFrames,
183             @NonNull RelativeFrameTimeHistogram relativeFrameTimeHistogram) {
184         mUid = appUid;
185         mWidgetId = widgetId;
186         mNavigationComponent = navigationComponent;
187         mWidgetCategory = widgetCategory != null ? widgetCategory : WIDGET_CATEGORY_UNSPECIFIED;
188         mWidgetState = widgetState != null ? widgetState : WIDGET_STATE_UNSPECIFIED;
189         mTotalFrames = totalFrames;
190         mJankyFrames = jankyFrames;
191         mRelativeFrameTimeHistogram = relativeFrameTimeHistogram;
192     }
193 
194     /**
195      * Returns the app uid.
196      *
197      * @return the app uid.
198      */
getUid()199     public int getUid() {
200         return mUid;
201     }
202 
203     /**
204      * Returns the id of the widget that reported state changes.
205      *
206      * @return the id of the widget that reported state changes. This value cannot be null.
207      */
getWidgetId()208     public @NonNull String getWidgetId() {
209         return mWidgetId;
210     }
211 
212     /**
213      * Returns the category that the widget's functionality generally falls into, or
214      * {@link #WIDGET_CATEGORY_UNSPECIFIED} if no value was passed in.
215      *
216      * @return the category that the widget's functionality generally falls into, this value cannot
217      * be null.
218      */
getWidgetCategory()219     public @NonNull @WidgetCategory String getWidgetCategory() {
220         return mWidgetCategory;
221     }
222 
223     /**
224      * Returns the widget's state that was reported for this stat, or
225      * {@link #WIDGET_STATE_UNSPECIFIED} if no value was passed in.
226      *
227      * @return the widget's state that was reported for this stat. This value cannot be null.
228      */
getWidgetState()229     public @NonNull @WidgetState String getWidgetState() {
230         return mWidgetState;
231     }
232 
233     /**
234      * Returns the number of frames that were determined to be janky for this stat.
235      *
236      * @return the number of frames that were determined to be janky for this stat.
237      */
getJankyFrameCount()238     public long getJankyFrameCount() {
239         return mJankyFrames;
240     }
241 
242     /**
243      * Returns the total number of frames counted for this stat.
244      *
245      * @return the total number of frames counted for this stat.
246      */
getTotalFrameCount()247     public long getTotalFrameCount() {
248         return mTotalFrames;
249     }
250 
251     /**
252      * Returns a Histogram containing relative frame times in millis grouped into predefined
253      * buckets. See {@link RelativeFrameTimeHistogram} for more information.
254      *
255      * @return Histogram containing relative frame times in predefined buckets. This value cannot
256      * be null.
257      */
getRelativeFrameTimeHistogram()258     public @NonNull RelativeFrameTimeHistogram getRelativeFrameTimeHistogram() {
259         return mRelativeFrameTimeHistogram;
260     }
261 
262     /**
263      * Returns the navigation component if it exists that this stat applies to.
264      *
265      * @return the navigation component if it exists that this stat applies to.
266      */
getNavigationComponent()267     public @Nullable String getNavigationComponent() {
268         return mNavigationComponent;
269     }
270 }
271