content: /*
   * Copyright (C) 2016 The Android Open Source Project
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *      http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  package android.view;
  
  import android.annotation.IntDef;
  import android.annotation.UnsupportedAppUsage;
  
  import java.lang.annotation.Retention;
  import java.lang.annotation.RetentionPolicy;
  
  /**
   * Class containing timing data for various milestones in a frame
   * lifecycle reported by the rendering subsystem.
   * <p>
   * Supported metrics can be queried via their corresponding identifier.
   * </p>
   */
  public final class FrameMetrics {
  
      /**
       * Metric identifier for unknown delay.
       * <p>
       * Represents the number of nanoseconds elapsed waiting for the
       * UI thread to become responsive and process the frame. This
       * should be 0 most of the time.
       * </p>
       */
      public static final int UNKNOWN_DELAY_DURATION = 0;
  
      /**
       * Metric identifier for input handling duration.
       * <p>
       * Represents the number of nanoseconds elapsed issuing
       * input handling callbacks.
       * </p>
       */
      public static final int INPUT_HANDLING_DURATION = 1;
  
      /**
       * Metric identifier for animation callback duration.
       * <p>
       * Represents the number of nanoseconds elapsed issuing
       * animation callbacks.
       * </p>
       */
      public static final int ANIMATION_DURATION = 2;
  
      /**
       * Metric identifier for layout/measure duration.
       * <p>
       * Represents the number of nanoseconds elapsed measuring
       * and laying out the invalidated pieces of the view hierarchy.
       * </p>
       */
      public static final int LAYOUT_MEASURE_DURATION = 3;
      /**
       * Metric identifier for draw duration.
       * <p>
       * Represents the number of nanoseconds elapsed computing
       * DisplayLists for transformations applied to the view
       * hierarchy.
       * </p>
       */
      public static final int DRAW_DURATION = 4;
  
      /**
       * Metric identifier for sync duration.
       * <p>
       * Represents the number of nanoseconds elapsed
       * synchronizing the computed display lists with the render
       * thread.
       * </p>
       */
      public static final int SYNC_DURATION = 5;
  
      /**
       * Metric identifier for command issue duration.
       * <p>
       * Represents the number of nanoseconds elapsed
       * issuing draw commands to the GPU.
       * </p>
       */
      public static final int COMMAND_ISSUE_DURATION = 6;
  
      /**
       * Metric identifier for swap buffers duration.
       * <p>
       * Represents the number of nanoseconds elapsed issuing
       * the frame buffer for this frame to the display
       * subsystem.
       * </p>
       */
      public static final int SWAP_BUFFERS_DURATION = 7;
  
      /**
       * Metric identifier for total frame duration.
       * <p>
       * Represents the total time in nanoseconds this frame took to render
       * and be issued to the display subsystem.
       * </p>
       * <p>
       * Equal to the sum of the values of all other time-valued metric
       * identifiers.
       * </p>
       */
      public static final int TOTAL_DURATION = 8;
  
      /**
       * Metric identifier for a boolean value determining whether this frame was
       * the first to draw in a new Window layout.
       * <p>
       * {@link #getMetric(int)} will return 0 for false, 1 for true.
       * </p>
       * <p>
       * First draw frames are expected to be slow and should usually be exempt
       * from display jank calculations as they do not cause skips in animations
       * and are usually hidden by window animations or other tricks.
       * </p>
       */
      public static final int FIRST_DRAW_FRAME = 9;
  
      /**
       * Metric identifier for the timestamp of the intended vsync for this frame.
       * <p>
       * The intended start point for the frame. If this value is different from
       * {@link #VSYNC_TIMESTAMP}, there was work occurring on the UI thread that
       * prevented it from responding to the vsync signal in a timely fashion.
       * </p>
       */
      public static final int INTENDED_VSYNC_TIMESTAMP = 10;
  
      /**
       * Metric identifier for the timestamp of the actual vsync for this frame.
       * <p>
       * The time value that was used in all the vsync listeners and drawing for
       * the frame (Choreographer frame callbacks, animations,
       * {@link View#getDrawingTime()}, etc…)
       * </p>
       */
      public static final int VSYNC_TIMESTAMP = 11;
  
      private static final int FRAME_INFO_FLAG_FIRST_DRAW = 1 << 0;
  
      /**
       * Identifiers for metrics available for each frame.
       *
       * {@see #getMetric(int)}
       * @hide
       */
      @IntDef({
              UNKNOWN_DELAY_DURATION,
              INPUT_HANDLING_DURATION,
              ANIMATION_DURATION,
              LAYOUT_MEASURE_DURATION,
              DRAW_DURATION,
              SYNC_DURATION,
              COMMAND_ISSUE_DURATION,
              SWAP_BUFFERS_DURATION,
              TOTAL_DURATION,
              FIRST_DRAW_FRAME,
              INTENDED_VSYNC_TIMESTAMP,
              VSYNC_TIMESTAMP,
      })
      @Retention(RetentionPolicy.SOURCE)
      public @interface Metric {}
  
      /**
       * Timestamp indices for frame milestones.
       *
       * May change from release to release.
       *
       * Must be kept in sync with frameworks/base/libs/hwui/FrameInfo.h.
       *
       * @hide
       */
      @IntDef ({
              Index.FLAGS,
              Index.INTENDED_VSYNC,
              Index.VSYNC,
              Index.OLDEST_INPUT_EVENT,
              Index.NEWEST_INPUT_EVENT,
              Index.HANDLE_INPUT_START,
              Index.ANIMATION_START,
              Index.PERFORM_TRAVERSALS_START,
              Index.DRAW_START,
              Index.SYNC_QUEUED,
              Index.SYNC_START,
              Index.ISSUE_DRAW_COMMANDS_START,
              Index.SWAP_BUFFERS,
              Index.FRAME_COMPLETED,
      })
      @Retention(RetentionPolicy.SOURCE)
      private @interface Index {
          int FLAGS = 0;
          int INTENDED_VSYNC = 1;
          int VSYNC = 2;
          int OLDEST_INPUT_EVENT = 3;
          int NEWEST_INPUT_EVENT = 4;
          int HANDLE_INPUT_START = 5;
          int ANIMATION_START = 6;
          int PERFORM_TRAVERSALS_START = 7;
          int DRAW_START = 8;
          int SYNC_QUEUED = 9;
          int SYNC_START = 10;
          int ISSUE_DRAW_COMMANDS_START = 11;
          int SWAP_BUFFERS = 12;
          int FRAME_COMPLETED = 13;
  
          int FRAME_STATS_COUNT = 16; // must always be last
      }
  
      /*
       * Bucket endpoints for each Metric defined above.
       *
       * Each defined metric *must* have a corresponding entry
       * in this list.
       */
      private static final int[] DURATIONS = new int[] {
          // UNKNOWN_DELAY
          Index.INTENDED_VSYNC, Index.HANDLE_INPUT_START,
          // INPUT_HANDLING
          Index.HANDLE_INPUT_START, Index.ANIMATION_START,
          // ANIMATION
          Index.ANIMATION_START, Index.PERFORM_TRAVERSALS_START,
          // LAYOUT_MEASURE
          Index.PERFORM_TRAVERSALS_START, Index.DRAW_START,
          // DRAW
          Index.DRAW_START, Index.SYNC_QUEUED,
          // SYNC
          Index.SYNC_START, Index.ISSUE_DRAW_COMMANDS_START,
          // COMMAND_ISSUE
          Index.ISSUE_DRAW_COMMANDS_START, Index.SWAP_BUFFERS,
          // SWAP_BUFFERS
          Index.SWAP_BUFFERS, Index.FRAME_COMPLETED,
          // TOTAL_DURATION
          Index.INTENDED_VSYNC, Index.FRAME_COMPLETED,
      };
  
      @UnsupportedAppUsage
      /* package */ final long[] mTimingData;
  
      /**
       * Constructs a FrameMetrics object as a copy.
       * <p>
       * Use this method to copy out metrics reported by
       * {@link Window.OnFrameMetricsAvailableListener#onFrameMetricsAvailable(
       * Window, FrameMetrics, int)}
       * </p>
       * @param other the FrameMetrics object to copy.
       */
      public FrameMetrics(FrameMetrics other) {
          mTimingData = new long[Index.FRAME_STATS_COUNT];
          System.arraycopy(other.mTimingData, 0, mTimingData, 0, mTimingData.length);
      }
  
      /**
       * @hide
       */
      FrameMetrics() {
          mTimingData = new long[Index.FRAME_STATS_COUNT];
      }
  
      /**
       * Retrieves the value associated with Metric identifier {@code id}
       * for this frame.
       * <p>
       * Boolean metrics are represented in [0,1], with 0 corresponding to
       * false, and 1 corresponding to true.
       * </p>
       * @param id the metric to retrieve
       * @return the value of the metric or -1 if it is not available.
       */
      public long getMetric(@Metric int id) {
          if (id < UNKNOWN_DELAY_DURATION || id > VSYNC_TIMESTAMP) {
              return -1;
          }
  
          if (mTimingData == null) {
              return -1;
          }
  
          if (id == FIRST_DRAW_FRAME) {
              return (mTimingData[Index.FLAGS] & FRAME_INFO_FLAG_FIRST_DRAW) != 0 ? 1 : 0;
          } else if (id == INTENDED_VSYNC_TIMESTAMP) {
              return mTimingData[Index.INTENDED_VSYNC];
          } else if (id == VSYNC_TIMESTAMP) {
              return mTimingData[Index.VSYNC];
          }
  
          int durationsIdx = 2 * id;
          return mTimingData[DURATIONS[durationsIdx + 1]]
                  - mTimingData[DURATIONS[durationsIdx]];
      }
  }
  
  