/*
* 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.view.Window;
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;
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,
})
@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,
};
/* 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 > FIRST_DRAW_FRAME) {
return -1;
}
if (mTimingData == null) {
return -1;
}
if (id == FIRST_DRAW_FRAME) {
return (mTimingData[Index.FLAGS] & FRAME_INFO_FLAG_FIRST_DRAW) != 0 ? 1 : 0;
}
int durationsIdx = 2 * id;
return mTimingData[DURATIONS[durationsIdx + 1]]
- mTimingData[DURATIONS[durationsIdx]];
}
}