Loading media/java/android/media/metrics/PlaybackMetrics.java +525 −21 Original line number Diff line number Diff line Loading @@ -16,11 +16,19 @@ package android.media.metrics; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.os.Parcel; import android.os.Parcelable; import com.android.internal.util.AnnotationValidations; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Objects; /** Loading @@ -28,38 +36,323 @@ import java.util.Objects; * @hide */ public final class PlaybackMetrics implements Parcelable { private int mStreamSourceType; // TODO(b/177209128): JavaDoc for the constants. public static final int STREAM_SOURCE_UNKNOWN = 0; public static final int STREAM_SOURCE_NETWORK = 1; public static final int STREAM_SOURCE_DEVICE = 2; public static final int STREAM_SOURCE_MIXED = 3; public static final int STREAM_TYPE_UNKNOWN = 0; public static final int STREAM_TYPE_OTHER = 1; public static final int STREAM_TYPE_PROGRESSIVE = 2; public static final int STREAM_TYPE_DASH = 3; public static final int STREAM_TYPE_HLS = 4; public static final int STREAM_TYPE_SS = 5; public static final int PLAYBACK_TYPE_VOD = 0; public static final int PLAYBACK_TYPE_LIVE = 1; public static final int PLAYBACK_TYPE_OTHER = 2; public static final int DRM_TYPE_NONE = 0; public static final int DRM_TYPE_OTHER = 1; public static final int DRM_TYPE_PLAY_READY = 2; public static final int DRM_TYPE_WIDEVINE_L1 = 3; public static final int DRM_TYPE_WIDEVINE_L3 = 4; // TODO: add DRM_TYPE_CLEARKEY public static final int CONTENT_TYPE_MAIN = 0; public static final int CONTENT_TYPE_AD = 1; public static final int CONTENT_TYPE_OTHER = 2; /** @hide */ @IntDef(prefix = "STREAM_SOURCE_", value = { STREAM_SOURCE_UNKNOWN, STREAM_SOURCE_NETWORK, STREAM_SOURCE_DEVICE, STREAM_SOURCE_MIXED }) @Retention(RetentionPolicy.SOURCE) public @interface StreamSource {} /** @hide */ @IntDef(prefix = "STREAM_TYPE_", value = { STREAM_TYPE_UNKNOWN, STREAM_TYPE_OTHER, STREAM_TYPE_PROGRESSIVE, STREAM_TYPE_DASH, STREAM_TYPE_HLS, STREAM_TYPE_SS }) @Retention(RetentionPolicy.SOURCE) public @interface StreamType {} /** @hide */ @IntDef(prefix = "PLAYBACK_TYPE_", value = { PLAYBACK_TYPE_VOD, PLAYBACK_TYPE_LIVE, PLAYBACK_TYPE_OTHER }) @Retention(RetentionPolicy.SOURCE) public @interface PlaybackType {} /** @hide */ @IntDef(prefix = "DRM_TYPE_", value = { DRM_TYPE_NONE, DRM_TYPE_OTHER, DRM_TYPE_PLAY_READY, DRM_TYPE_WIDEVINE_L1, DRM_TYPE_WIDEVINE_L3 }) @Retention(RetentionPolicy.SOURCE) public @interface DrmType {} /** @hide */ @IntDef(prefix = "CONTENT_TYPE_", value = { CONTENT_TYPE_MAIN, CONTENT_TYPE_AD, CONTENT_TYPE_OTHER }) @Retention(RetentionPolicy.SOURCE) public @interface ContentType {} private final long mMediaDurationMillis; private final int mStreamSource; private final int mStreamType; private final int mPlaybackType; private final int mDrmType; private final int mContentType; private final @Nullable String mPlayerName; private final @Nullable String mPlayerVersion; private final @NonNull long[] mExperimentIds; private final int mVideoFramesPlayed; private final int mVideoFramesDropped; private final int mAudioUnderrunCount; private final long mNetworkBytesRead; private final long mLocalBytesRead; private final long mNetworkTransferDurationMillis; /** * Creates a new PlaybackMetrics. * * @hide */ public PlaybackMetrics(int streamSourceType) { this.mStreamSourceType = streamSourceType; public PlaybackMetrics( long mediaDurationMillis, int streamSource, int streamType, int playbackType, int drmType, int contentType, @Nullable String playerName, @Nullable String playerVersion, @NonNull long[] experimentIds, int videoFramesPlayed, int videoFramesDropped, int audioUnderrunCount, long networkBytesRead, long localBytesRead, long networkTransferDurationMillis) { this.mMediaDurationMillis = mediaDurationMillis; this.mStreamSource = streamSource; this.mStreamType = streamType; this.mPlaybackType = playbackType; this.mDrmType = drmType; this.mContentType = contentType; this.mPlayerName = playerName; this.mPlayerVersion = playerVersion; this.mExperimentIds = experimentIds; AnnotationValidations.validate(NonNull.class, null, mExperimentIds); this.mVideoFramesPlayed = videoFramesPlayed; this.mVideoFramesDropped = videoFramesDropped; this.mAudioUnderrunCount = audioUnderrunCount; this.mNetworkBytesRead = networkBytesRead; this.mLocalBytesRead = localBytesRead; this.mNetworkTransferDurationMillis = networkTransferDurationMillis; } public long getMediaDurationMillis() { return mMediaDurationMillis; } /** * Gets stream source type. */ @StreamSource public int getStreamSource() { return mStreamSource; } /** * Gets stream type. */ @StreamType public int getStreamType() { return mStreamType; } /** * Gets playback type. */ @PlaybackType public int getPlaybackType() { return mPlaybackType; } /** * Gets DRM type. */ @DrmType public int getDrmType() { return mDrmType; } public int getStreamSourceType() { return mStreamSourceType; /** * Gets content type. */ @ContentType public int getContentType() { return mContentType; } /** * Gets player name. */ public @Nullable String getPlayerName() { return mPlayerName; } /** * Gets player version. */ public @Nullable String getPlayerVersion() { return mPlayerVersion; } /** * Gets experiment IDs. */ public @NonNull long[] getExperimentIds() { return Arrays.copyOf(mExperimentIds, mExperimentIds.length); } /** * Gets video frames played. */ public int getVideoFramesPlayed() { return mVideoFramesPlayed; } /** * Gets video frames dropped. */ public int getVideoFramesDropped() { return mVideoFramesDropped; } /** * Gets audio underrun count. */ public int getAudioUnderrunCount() { return mAudioUnderrunCount; } /** * Gets number of network bytes read. */ public long getNetworkBytesRead() { return mNetworkBytesRead; } /** * Gets number of local bytes read. */ public long getLocalBytesRead() { return mLocalBytesRead; } /** * Gets network transfer duration in milliseconds. */ public long getNetworkTransferDurationMillis() { return mNetworkTransferDurationMillis; } @Override public boolean equals(@Nullable Object o) { public String toString() { return "PlaybackMetrics { " + "mediaDurationMillis = " + mMediaDurationMillis + ", " + "streamSource = " + mStreamSource + ", " + "streamType = " + mStreamType + ", " + "playbackType = " + mPlaybackType + ", " + "drmType = " + mDrmType + ", " + "contentType = " + mContentType + ", " + "playerName = " + mPlayerName + ", " + "playerVersion = " + mPlayerVersion + ", " + "experimentIds = " + Arrays.toString(mExperimentIds) + ", " + "videoFramesPlayed = " + mVideoFramesPlayed + ", " + "videoFramesDropped = " + mVideoFramesDropped + ", " + "audioUnderrunCount = " + mAudioUnderrunCount + ", " + "networkBytesRead = " + mNetworkBytesRead + ", " + "localBytesRead = " + mLocalBytesRead + ", " + "networkTransferDurationMillis = " + mNetworkTransferDurationMillis + " }"; } @Override public boolean equals(@Nullable Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; PlaybackMetrics that = (PlaybackMetrics) o; return mStreamSourceType == that.mStreamSourceType; return mMediaDurationMillis == that.mMediaDurationMillis && mStreamSource == that.mStreamSource && mStreamType == that.mStreamType && mPlaybackType == that.mPlaybackType && mDrmType == that.mDrmType && mContentType == that.mContentType && Objects.equals(mPlayerName, that.mPlayerName) && Objects.equals(mPlayerVersion, that.mPlayerVersion) && Arrays.equals(mExperimentIds, that.mExperimentIds) && mVideoFramesPlayed == that.mVideoFramesPlayed && mVideoFramesDropped == that.mVideoFramesDropped && mAudioUnderrunCount == that.mAudioUnderrunCount && mNetworkBytesRead == that.mNetworkBytesRead && mLocalBytesRead == that.mLocalBytesRead && mNetworkTransferDurationMillis == that.mNetworkTransferDurationMillis; } @Override public int hashCode() { return Objects.hash(mStreamSourceType); return Objects.hash(mMediaDurationMillis, mStreamSource, mStreamType, mPlaybackType, mDrmType, mContentType, mPlayerName, mPlayerVersion, mExperimentIds, mVideoFramesPlayed, mVideoFramesDropped, mAudioUnderrunCount, mNetworkBytesRead, mLocalBytesRead, mNetworkTransferDurationMillis); } @Override public void writeToParcel(@NonNull Parcel dest, int flags) { dest.writeInt(mStreamSourceType); long flg = 0; if (mPlayerName != null) flg |= 0x80; if (mPlayerVersion != null) flg |= 0x100; dest.writeLong(flg); dest.writeLong(mMediaDurationMillis); dest.writeInt(mStreamSource); dest.writeInt(mStreamType); dest.writeInt(mPlaybackType); dest.writeInt(mDrmType); dest.writeInt(mContentType); if (mPlayerName != null) dest.writeString(mPlayerName); if (mPlayerVersion != null) dest.writeString(mPlayerVersion); dest.writeLongArray(mExperimentIds); dest.writeInt(mVideoFramesPlayed); dest.writeInt(mVideoFramesDropped); dest.writeInt(mAudioUnderrunCount); dest.writeLong(mNetworkBytesRead); dest.writeLong(mLocalBytesRead); dest.writeLong(mNetworkTransferDurationMillis); } @Override Loading @@ -69,8 +362,39 @@ public final class PlaybackMetrics implements Parcelable { /** @hide */ /* package-private */ PlaybackMetrics(@NonNull Parcel in) { int streamSourceType = in.readInt(); this.mStreamSourceType = streamSourceType; long flg = in.readLong(); long mediaDurationMillis = in.readLong(); int streamSource = in.readInt(); int streamType = in.readInt(); int playbackType = in.readInt(); int drmType = in.readInt(); int contentType = in.readInt(); String playerName = (flg & 0x80) == 0 ? null : in.readString(); String playerVersion = (flg & 0x100) == 0 ? null : in.readString(); long[] experimentIds = in.createLongArray(); int videoFramesPlayed = in.readInt(); int videoFramesDropped = in.readInt(); int audioUnderrunCount = in.readInt(); long networkBytesRead = in.readLong(); long localBytesRead = in.readLong(); long networkTransferDurationMillis = in.readLong(); this.mMediaDurationMillis = mediaDurationMillis; this.mStreamSource = streamSource; this.mStreamType = streamType; this.mPlaybackType = playbackType; this.mDrmType = drmType; this.mContentType = contentType; this.mPlayerName = playerName; this.mPlayerVersion = playerVersion; this.mExperimentIds = experimentIds; AnnotationValidations.validate(NonNull.class, null, mExperimentIds); this.mVideoFramesPlayed = videoFramesPlayed; this.mVideoFramesDropped = videoFramesDropped; this.mAudioUnderrunCount = audioUnderrunCount; this.mNetworkBytesRead = networkBytesRead; this.mLocalBytesRead = localBytesRead; this.mNetworkTransferDurationMillis = networkTransferDurationMillis; } public static final @NonNull Parcelable.Creator<PlaybackMetrics> CREATOR = Loading @@ -85,4 +409,184 @@ public final class PlaybackMetrics implements Parcelable { return new PlaybackMetrics(in); } }; /** * A builder for {@link PlaybackMetrics} */ public static final class Builder { private long mMediaDurationMillis; private int mStreamSource; private int mStreamType; private int mPlaybackType; private int mDrmType; private int mContentType; private @Nullable String mPlayerName; private @Nullable String mPlayerVersion; private @NonNull List<Long> mExperimentIds = new ArrayList<>(); private int mVideoFramesPlayed; private int mVideoFramesDropped; private int mAudioUnderrunCount; private long mNetworkBytesRead; private long mLocalBytesRead; private long mNetworkTransferDurationMillis; /** * Creates a new Builder. * * @hide */ public Builder() { } /** * Sets the media duration in milliseconds. */ public @NonNull Builder setMediaDurationMillis(long value) { mMediaDurationMillis = value; return this; } /** * Sets the stream source type. */ public @NonNull Builder setStreamSource(@StreamSource int value) { mStreamSource = value; return this; } /** * Sets the stream type. */ public @NonNull Builder setStreamType(@StreamType int value) { mStreamType = value; return this; } /** * Sets the playback type. */ public @NonNull Builder setPlaybackType(@PlaybackType int value) { mPlaybackType = value; return this; } /** * Sets the DRM type. */ public @NonNull Builder setDrmType(@StreamType int value) { mDrmType = value; return this; } /** * Sets the content type. */ public @NonNull Builder setContentType(@ContentType int value) { mContentType = value; return this; } /** * Sets the player name. */ public @NonNull Builder setPlayerName(@NonNull String value) { mPlayerName = value; return this; } /** * Sets the player version. */ public @NonNull Builder setPlayerVersion(@NonNull String value) { mPlayerVersion = value; return this; } /** * Adds the experiment ID. */ public @NonNull Builder addExperimentId(long value) { mExperimentIds.add(value); return this; } /** * Sets the video frames played. */ public @NonNull Builder setVideoFramesPlayed(int value) { mVideoFramesPlayed = value; return this; } /** * Sets the video frames dropped. */ public @NonNull Builder setVideoFramesDropped(int value) { mVideoFramesDropped = value; return this; } /** * Sets the audio underrun count. */ public @NonNull Builder setAudioUnderrunCount(int value) { mAudioUnderrunCount = value; return this; } /** * Sets the number of network bytes read. */ public @NonNull Builder setNetworkBytesRead(long value) { mNetworkBytesRead = value; return this; } /** * Sets the number of local bytes read. */ public @NonNull Builder setLocalBytesRead(long value) { mLocalBytesRead = value; return this; } /** * Sets the network transfer duration in milliseconds. */ public @NonNull Builder setNetworkTransferDurationMillis(long value) { mNetworkTransferDurationMillis = value; return this; } /** Builds the instance. This builder should not be touched after calling this! */ public @NonNull PlaybackMetrics build() { PlaybackMetrics o = new PlaybackMetrics( mMediaDurationMillis, mStreamSource, mStreamType, mPlaybackType, mDrmType, mContentType, mPlayerName, mPlayerVersion, idsToLongArray(), mVideoFramesPlayed, mVideoFramesDropped, mAudioUnderrunCount, mNetworkBytesRead, mLocalBytesRead, mNetworkTransferDurationMillis); return o; } private long[] idsToLongArray() { long[] ids = new long[mExperimentIds.size()]; for (int i = 0; i < mExperimentIds.size(); i++) { ids[i] = mExperimentIds.get(i); } return ids; } } } services/core/java/com/android/server/media/metrics/PlaybackMetricsManagerService.java +23 −1 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ import android.media.metrics.IPlaybackMetricsManager; import android.media.metrics.NetworkEvent; import android.media.metrics.PlaybackErrorEvent; import android.media.metrics.PlaybackMetrics; import android.os.Binder; import android.util.Base64; import android.util.StatsEvent; import android.util.StatsLog; Loading Loading @@ -54,7 +55,28 @@ public final class PlaybackMetricsManagerService extends SystemService { private final class BinderService extends IPlaybackMetricsManager.Stub { @Override public void reportPlaybackMetrics(String sessionId, PlaybackMetrics metrics, int userId) { // TODO: log it to statsd StatsEvent statsEvent = StatsEvent.newBuilder() .setAtomId(320) .writeInt(Binder.getCallingUid()) .writeString(sessionId) .writeLong(metrics.getMediaDurationMillis()) .writeInt(metrics.getStreamSource()) .writeInt(metrics.getStreamType()) .writeInt(metrics.getPlaybackType()) .writeInt(metrics.getDrmType()) .writeInt(metrics.getContentType()) .writeString(metrics.getPlayerName()) .writeString(metrics.getPlayerVersion()) .writeByteArray(new byte[0]) // TODO: write experiments proto .writeInt(metrics.getVideoFramesPlayed()) .writeInt(metrics.getVideoFramesDropped()) .writeInt(metrics.getAudioUnderrunCount()) .writeLong(metrics.getNetworkBytesRead()) .writeLong(metrics.getLocalBytesRead()) .writeLong(metrics.getNetworkTransferDurationMillis()) .usePooledBuffer() .build(); StatsLog.write(statsEvent); } @Override Loading Loading
media/java/android/media/metrics/PlaybackMetrics.java +525 −21 Original line number Diff line number Diff line Loading @@ -16,11 +16,19 @@ package android.media.metrics; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.os.Parcel; import android.os.Parcelable; import com.android.internal.util.AnnotationValidations; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Objects; /** Loading @@ -28,38 +36,323 @@ import java.util.Objects; * @hide */ public final class PlaybackMetrics implements Parcelable { private int mStreamSourceType; // TODO(b/177209128): JavaDoc for the constants. public static final int STREAM_SOURCE_UNKNOWN = 0; public static final int STREAM_SOURCE_NETWORK = 1; public static final int STREAM_SOURCE_DEVICE = 2; public static final int STREAM_SOURCE_MIXED = 3; public static final int STREAM_TYPE_UNKNOWN = 0; public static final int STREAM_TYPE_OTHER = 1; public static final int STREAM_TYPE_PROGRESSIVE = 2; public static final int STREAM_TYPE_DASH = 3; public static final int STREAM_TYPE_HLS = 4; public static final int STREAM_TYPE_SS = 5; public static final int PLAYBACK_TYPE_VOD = 0; public static final int PLAYBACK_TYPE_LIVE = 1; public static final int PLAYBACK_TYPE_OTHER = 2; public static final int DRM_TYPE_NONE = 0; public static final int DRM_TYPE_OTHER = 1; public static final int DRM_TYPE_PLAY_READY = 2; public static final int DRM_TYPE_WIDEVINE_L1 = 3; public static final int DRM_TYPE_WIDEVINE_L3 = 4; // TODO: add DRM_TYPE_CLEARKEY public static final int CONTENT_TYPE_MAIN = 0; public static final int CONTENT_TYPE_AD = 1; public static final int CONTENT_TYPE_OTHER = 2; /** @hide */ @IntDef(prefix = "STREAM_SOURCE_", value = { STREAM_SOURCE_UNKNOWN, STREAM_SOURCE_NETWORK, STREAM_SOURCE_DEVICE, STREAM_SOURCE_MIXED }) @Retention(RetentionPolicy.SOURCE) public @interface StreamSource {} /** @hide */ @IntDef(prefix = "STREAM_TYPE_", value = { STREAM_TYPE_UNKNOWN, STREAM_TYPE_OTHER, STREAM_TYPE_PROGRESSIVE, STREAM_TYPE_DASH, STREAM_TYPE_HLS, STREAM_TYPE_SS }) @Retention(RetentionPolicy.SOURCE) public @interface StreamType {} /** @hide */ @IntDef(prefix = "PLAYBACK_TYPE_", value = { PLAYBACK_TYPE_VOD, PLAYBACK_TYPE_LIVE, PLAYBACK_TYPE_OTHER }) @Retention(RetentionPolicy.SOURCE) public @interface PlaybackType {} /** @hide */ @IntDef(prefix = "DRM_TYPE_", value = { DRM_TYPE_NONE, DRM_TYPE_OTHER, DRM_TYPE_PLAY_READY, DRM_TYPE_WIDEVINE_L1, DRM_TYPE_WIDEVINE_L3 }) @Retention(RetentionPolicy.SOURCE) public @interface DrmType {} /** @hide */ @IntDef(prefix = "CONTENT_TYPE_", value = { CONTENT_TYPE_MAIN, CONTENT_TYPE_AD, CONTENT_TYPE_OTHER }) @Retention(RetentionPolicy.SOURCE) public @interface ContentType {} private final long mMediaDurationMillis; private final int mStreamSource; private final int mStreamType; private final int mPlaybackType; private final int mDrmType; private final int mContentType; private final @Nullable String mPlayerName; private final @Nullable String mPlayerVersion; private final @NonNull long[] mExperimentIds; private final int mVideoFramesPlayed; private final int mVideoFramesDropped; private final int mAudioUnderrunCount; private final long mNetworkBytesRead; private final long mLocalBytesRead; private final long mNetworkTransferDurationMillis; /** * Creates a new PlaybackMetrics. * * @hide */ public PlaybackMetrics(int streamSourceType) { this.mStreamSourceType = streamSourceType; public PlaybackMetrics( long mediaDurationMillis, int streamSource, int streamType, int playbackType, int drmType, int contentType, @Nullable String playerName, @Nullable String playerVersion, @NonNull long[] experimentIds, int videoFramesPlayed, int videoFramesDropped, int audioUnderrunCount, long networkBytesRead, long localBytesRead, long networkTransferDurationMillis) { this.mMediaDurationMillis = mediaDurationMillis; this.mStreamSource = streamSource; this.mStreamType = streamType; this.mPlaybackType = playbackType; this.mDrmType = drmType; this.mContentType = contentType; this.mPlayerName = playerName; this.mPlayerVersion = playerVersion; this.mExperimentIds = experimentIds; AnnotationValidations.validate(NonNull.class, null, mExperimentIds); this.mVideoFramesPlayed = videoFramesPlayed; this.mVideoFramesDropped = videoFramesDropped; this.mAudioUnderrunCount = audioUnderrunCount; this.mNetworkBytesRead = networkBytesRead; this.mLocalBytesRead = localBytesRead; this.mNetworkTransferDurationMillis = networkTransferDurationMillis; } public long getMediaDurationMillis() { return mMediaDurationMillis; } /** * Gets stream source type. */ @StreamSource public int getStreamSource() { return mStreamSource; } /** * Gets stream type. */ @StreamType public int getStreamType() { return mStreamType; } /** * Gets playback type. */ @PlaybackType public int getPlaybackType() { return mPlaybackType; } /** * Gets DRM type. */ @DrmType public int getDrmType() { return mDrmType; } public int getStreamSourceType() { return mStreamSourceType; /** * Gets content type. */ @ContentType public int getContentType() { return mContentType; } /** * Gets player name. */ public @Nullable String getPlayerName() { return mPlayerName; } /** * Gets player version. */ public @Nullable String getPlayerVersion() { return mPlayerVersion; } /** * Gets experiment IDs. */ public @NonNull long[] getExperimentIds() { return Arrays.copyOf(mExperimentIds, mExperimentIds.length); } /** * Gets video frames played. */ public int getVideoFramesPlayed() { return mVideoFramesPlayed; } /** * Gets video frames dropped. */ public int getVideoFramesDropped() { return mVideoFramesDropped; } /** * Gets audio underrun count. */ public int getAudioUnderrunCount() { return mAudioUnderrunCount; } /** * Gets number of network bytes read. */ public long getNetworkBytesRead() { return mNetworkBytesRead; } /** * Gets number of local bytes read. */ public long getLocalBytesRead() { return mLocalBytesRead; } /** * Gets network transfer duration in milliseconds. */ public long getNetworkTransferDurationMillis() { return mNetworkTransferDurationMillis; } @Override public boolean equals(@Nullable Object o) { public String toString() { return "PlaybackMetrics { " + "mediaDurationMillis = " + mMediaDurationMillis + ", " + "streamSource = " + mStreamSource + ", " + "streamType = " + mStreamType + ", " + "playbackType = " + mPlaybackType + ", " + "drmType = " + mDrmType + ", " + "contentType = " + mContentType + ", " + "playerName = " + mPlayerName + ", " + "playerVersion = " + mPlayerVersion + ", " + "experimentIds = " + Arrays.toString(mExperimentIds) + ", " + "videoFramesPlayed = " + mVideoFramesPlayed + ", " + "videoFramesDropped = " + mVideoFramesDropped + ", " + "audioUnderrunCount = " + mAudioUnderrunCount + ", " + "networkBytesRead = " + mNetworkBytesRead + ", " + "localBytesRead = " + mLocalBytesRead + ", " + "networkTransferDurationMillis = " + mNetworkTransferDurationMillis + " }"; } @Override public boolean equals(@Nullable Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; PlaybackMetrics that = (PlaybackMetrics) o; return mStreamSourceType == that.mStreamSourceType; return mMediaDurationMillis == that.mMediaDurationMillis && mStreamSource == that.mStreamSource && mStreamType == that.mStreamType && mPlaybackType == that.mPlaybackType && mDrmType == that.mDrmType && mContentType == that.mContentType && Objects.equals(mPlayerName, that.mPlayerName) && Objects.equals(mPlayerVersion, that.mPlayerVersion) && Arrays.equals(mExperimentIds, that.mExperimentIds) && mVideoFramesPlayed == that.mVideoFramesPlayed && mVideoFramesDropped == that.mVideoFramesDropped && mAudioUnderrunCount == that.mAudioUnderrunCount && mNetworkBytesRead == that.mNetworkBytesRead && mLocalBytesRead == that.mLocalBytesRead && mNetworkTransferDurationMillis == that.mNetworkTransferDurationMillis; } @Override public int hashCode() { return Objects.hash(mStreamSourceType); return Objects.hash(mMediaDurationMillis, mStreamSource, mStreamType, mPlaybackType, mDrmType, mContentType, mPlayerName, mPlayerVersion, mExperimentIds, mVideoFramesPlayed, mVideoFramesDropped, mAudioUnderrunCount, mNetworkBytesRead, mLocalBytesRead, mNetworkTransferDurationMillis); } @Override public void writeToParcel(@NonNull Parcel dest, int flags) { dest.writeInt(mStreamSourceType); long flg = 0; if (mPlayerName != null) flg |= 0x80; if (mPlayerVersion != null) flg |= 0x100; dest.writeLong(flg); dest.writeLong(mMediaDurationMillis); dest.writeInt(mStreamSource); dest.writeInt(mStreamType); dest.writeInt(mPlaybackType); dest.writeInt(mDrmType); dest.writeInt(mContentType); if (mPlayerName != null) dest.writeString(mPlayerName); if (mPlayerVersion != null) dest.writeString(mPlayerVersion); dest.writeLongArray(mExperimentIds); dest.writeInt(mVideoFramesPlayed); dest.writeInt(mVideoFramesDropped); dest.writeInt(mAudioUnderrunCount); dest.writeLong(mNetworkBytesRead); dest.writeLong(mLocalBytesRead); dest.writeLong(mNetworkTransferDurationMillis); } @Override Loading @@ -69,8 +362,39 @@ public final class PlaybackMetrics implements Parcelable { /** @hide */ /* package-private */ PlaybackMetrics(@NonNull Parcel in) { int streamSourceType = in.readInt(); this.mStreamSourceType = streamSourceType; long flg = in.readLong(); long mediaDurationMillis = in.readLong(); int streamSource = in.readInt(); int streamType = in.readInt(); int playbackType = in.readInt(); int drmType = in.readInt(); int contentType = in.readInt(); String playerName = (flg & 0x80) == 0 ? null : in.readString(); String playerVersion = (flg & 0x100) == 0 ? null : in.readString(); long[] experimentIds = in.createLongArray(); int videoFramesPlayed = in.readInt(); int videoFramesDropped = in.readInt(); int audioUnderrunCount = in.readInt(); long networkBytesRead = in.readLong(); long localBytesRead = in.readLong(); long networkTransferDurationMillis = in.readLong(); this.mMediaDurationMillis = mediaDurationMillis; this.mStreamSource = streamSource; this.mStreamType = streamType; this.mPlaybackType = playbackType; this.mDrmType = drmType; this.mContentType = contentType; this.mPlayerName = playerName; this.mPlayerVersion = playerVersion; this.mExperimentIds = experimentIds; AnnotationValidations.validate(NonNull.class, null, mExperimentIds); this.mVideoFramesPlayed = videoFramesPlayed; this.mVideoFramesDropped = videoFramesDropped; this.mAudioUnderrunCount = audioUnderrunCount; this.mNetworkBytesRead = networkBytesRead; this.mLocalBytesRead = localBytesRead; this.mNetworkTransferDurationMillis = networkTransferDurationMillis; } public static final @NonNull Parcelable.Creator<PlaybackMetrics> CREATOR = Loading @@ -85,4 +409,184 @@ public final class PlaybackMetrics implements Parcelable { return new PlaybackMetrics(in); } }; /** * A builder for {@link PlaybackMetrics} */ public static final class Builder { private long mMediaDurationMillis; private int mStreamSource; private int mStreamType; private int mPlaybackType; private int mDrmType; private int mContentType; private @Nullable String mPlayerName; private @Nullable String mPlayerVersion; private @NonNull List<Long> mExperimentIds = new ArrayList<>(); private int mVideoFramesPlayed; private int mVideoFramesDropped; private int mAudioUnderrunCount; private long mNetworkBytesRead; private long mLocalBytesRead; private long mNetworkTransferDurationMillis; /** * Creates a new Builder. * * @hide */ public Builder() { } /** * Sets the media duration in milliseconds. */ public @NonNull Builder setMediaDurationMillis(long value) { mMediaDurationMillis = value; return this; } /** * Sets the stream source type. */ public @NonNull Builder setStreamSource(@StreamSource int value) { mStreamSource = value; return this; } /** * Sets the stream type. */ public @NonNull Builder setStreamType(@StreamType int value) { mStreamType = value; return this; } /** * Sets the playback type. */ public @NonNull Builder setPlaybackType(@PlaybackType int value) { mPlaybackType = value; return this; } /** * Sets the DRM type. */ public @NonNull Builder setDrmType(@StreamType int value) { mDrmType = value; return this; } /** * Sets the content type. */ public @NonNull Builder setContentType(@ContentType int value) { mContentType = value; return this; } /** * Sets the player name. */ public @NonNull Builder setPlayerName(@NonNull String value) { mPlayerName = value; return this; } /** * Sets the player version. */ public @NonNull Builder setPlayerVersion(@NonNull String value) { mPlayerVersion = value; return this; } /** * Adds the experiment ID. */ public @NonNull Builder addExperimentId(long value) { mExperimentIds.add(value); return this; } /** * Sets the video frames played. */ public @NonNull Builder setVideoFramesPlayed(int value) { mVideoFramesPlayed = value; return this; } /** * Sets the video frames dropped. */ public @NonNull Builder setVideoFramesDropped(int value) { mVideoFramesDropped = value; return this; } /** * Sets the audio underrun count. */ public @NonNull Builder setAudioUnderrunCount(int value) { mAudioUnderrunCount = value; return this; } /** * Sets the number of network bytes read. */ public @NonNull Builder setNetworkBytesRead(long value) { mNetworkBytesRead = value; return this; } /** * Sets the number of local bytes read. */ public @NonNull Builder setLocalBytesRead(long value) { mLocalBytesRead = value; return this; } /** * Sets the network transfer duration in milliseconds. */ public @NonNull Builder setNetworkTransferDurationMillis(long value) { mNetworkTransferDurationMillis = value; return this; } /** Builds the instance. This builder should not be touched after calling this! */ public @NonNull PlaybackMetrics build() { PlaybackMetrics o = new PlaybackMetrics( mMediaDurationMillis, mStreamSource, mStreamType, mPlaybackType, mDrmType, mContentType, mPlayerName, mPlayerVersion, idsToLongArray(), mVideoFramesPlayed, mVideoFramesDropped, mAudioUnderrunCount, mNetworkBytesRead, mLocalBytesRead, mNetworkTransferDurationMillis); return o; } private long[] idsToLongArray() { long[] ids = new long[mExperimentIds.size()]; for (int i = 0; i < mExperimentIds.size(); i++) { ids[i] = mExperimentIds.get(i); } return ids; } } }
services/core/java/com/android/server/media/metrics/PlaybackMetricsManagerService.java +23 −1 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ import android.media.metrics.IPlaybackMetricsManager; import android.media.metrics.NetworkEvent; import android.media.metrics.PlaybackErrorEvent; import android.media.metrics.PlaybackMetrics; import android.os.Binder; import android.util.Base64; import android.util.StatsEvent; import android.util.StatsLog; Loading Loading @@ -54,7 +55,28 @@ public final class PlaybackMetricsManagerService extends SystemService { private final class BinderService extends IPlaybackMetricsManager.Stub { @Override public void reportPlaybackMetrics(String sessionId, PlaybackMetrics metrics, int userId) { // TODO: log it to statsd StatsEvent statsEvent = StatsEvent.newBuilder() .setAtomId(320) .writeInt(Binder.getCallingUid()) .writeString(sessionId) .writeLong(metrics.getMediaDurationMillis()) .writeInt(metrics.getStreamSource()) .writeInt(metrics.getStreamType()) .writeInt(metrics.getPlaybackType()) .writeInt(metrics.getDrmType()) .writeInt(metrics.getContentType()) .writeString(metrics.getPlayerName()) .writeString(metrics.getPlayerVersion()) .writeByteArray(new byte[0]) // TODO: write experiments proto .writeInt(metrics.getVideoFramesPlayed()) .writeInt(metrics.getVideoFramesDropped()) .writeInt(metrics.getAudioUnderrunCount()) .writeLong(metrics.getNetworkBytesRead()) .writeLong(metrics.getLocalBytesRead()) .writeLong(metrics.getNetworkTransferDurationMillis()) .usePooledBuffer() .build(); StatsLog.write(statsEvent); } @Override Loading