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