From b4d741a262e81bbea3e766d9945f81666818deb4 Mon Sep 17 00:00:00 2001 From: shubang Date: Wed, 3 Mar 2021 01:06:08 -0800 Subject: [PATCH] Add 1.extras, 2.recording session, 3.ID wrapper to MediaMetrics Test: mmm; Bug: 167036690 Change-Id: I9d514db5cdb6ed71e8e6c4d0ee75623c2b6d133d --- media/java/android/media/metrics/Event.java | 15 ++- .../media/metrics/IMediaMetricsManager.aidl | 3 +- .../android/media/metrics/LogSessionId.java | 34 ++++++ .../media/metrics/MediaMetricsManager.java | 17 ++- .../android/media/metrics/NetworkEvent.java | 36 +++++- .../media/metrics/PlaybackErrorEvent.java | 23 +++- .../media/metrics/PlaybackMetrics.java | 65 +++++++++- .../media/metrics/PlaybackSession.java | 9 ++ .../media/metrics/PlaybackStateEvent.java | 26 +++- .../media/metrics/RecordingSession.java | 62 ++++++++++ .../media/metrics/TrackChangeEvent.java | 114 +++++++++++++++--- .../metrics/MediaMetricsManagerService.java | 13 +- 12 files changed, 387 insertions(+), 30 deletions(-) create mode 100644 media/java/android/media/metrics/LogSessionId.java create mode 100644 media/java/android/media/metrics/RecordingSession.java diff --git a/media/java/android/media/metrics/Event.java b/media/java/android/media/metrics/Event.java index 5646dcdb6c9cf..96b61d2eaf4d0 100644 --- a/media/java/android/media/metrics/Event.java +++ b/media/java/android/media/metrics/Event.java @@ -17,22 +17,30 @@ package android.media.metrics; import android.annotation.IntRange; +import android.os.Bundle; /** * Abstract class for metrics events. */ public abstract class Event { - private final long mTimeSinceCreatedMillis; + final long mTimeSinceCreatedMillis; + Bundle mExtras; // hide default constructor /* package */ Event() { mTimeSinceCreatedMillis = MediaMetricsManager.INVALID_TIMESTAMP; } + // TODO: remove protected Event(long timeSinceCreatedMillis) { mTimeSinceCreatedMillis = timeSinceCreatedMillis; } + /* package */ Event(long timeSinceCreatedMillis, Bundle extras) { + mTimeSinceCreatedMillis = timeSinceCreatedMillis; + mExtras = extras; + } + /** * Gets time since the corresponding instance is created in millisecond. * @return the timestamp since the instance is created, or -1 if unknown. @@ -41,4 +49,9 @@ public abstract class Event { public long getTimeSinceCreatedMillis() { return mTimeSinceCreatedMillis; } + + /** @hide */ + public Bundle getExtras() { + return mExtras; + } } diff --git a/media/java/android/media/metrics/IMediaMetricsManager.aidl b/media/java/android/media/metrics/IMediaMetricsManager.aidl index 2cb2ab5c42b5e..f2c0d44a00b1e 100644 --- a/media/java/android/media/metrics/IMediaMetricsManager.aidl +++ b/media/java/android/media/metrics/IMediaMetricsManager.aidl @@ -28,7 +28,8 @@ import android.media.metrics.TrackChangeEvent; */ interface IMediaMetricsManager { void reportPlaybackMetrics(in String sessionId, in PlaybackMetrics metrics, int userId); - String getSessionId(int userId); + String getPlaybackSessionId(int userId); + String getRecordingSessionId(int userId); void reportNetworkEvent(in String sessionId, in NetworkEvent event, int userId); void reportPlaybackErrorEvent(in String sessionId, in PlaybackErrorEvent event, int userId); void reportPlaybackStateEvent(in String sessionId, in PlaybackStateEvent event, int userId); diff --git a/media/java/android/media/metrics/LogSessionId.java b/media/java/android/media/metrics/LogSessionId.java new file mode 100644 index 0000000000000..7ddb259f7f282 --- /dev/null +++ b/media/java/android/media/metrics/LogSessionId.java @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2021 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.media.metrics; + +/** + * An instances of this class represents the ID of a log session. + * @hide + */ +public class LogSessionId { + private final String mSessionId; + + /* package */ LogSessionId(String id) { + mSessionId = id; + } + + /** @hide */ + public String getStringId() { + return mSessionId; + } +} diff --git a/media/java/android/media/metrics/MediaMetricsManager.java b/media/java/android/media/metrics/MediaMetricsManager.java index de780f672b28e..9710e88cf24bb 100644 --- a/media/java/android/media/metrics/MediaMetricsManager.java +++ b/media/java/android/media/metrics/MediaMetricsManager.java @@ -94,7 +94,7 @@ public class MediaMetricsManager { @NonNull public PlaybackSession createPlaybackSession() { try { - String id = mService.getSessionId(mUserId); + String id = mService.getPlaybackSessionId(mUserId); PlaybackSession session = new PlaybackSession(id, this); return session; } catch (RemoteException e) { @@ -102,6 +102,21 @@ public class MediaMetricsManager { } } + /** + * Creates a recording session. + * @hide + */ + @NonNull + public RecordingSession createRecordingSession() { + try { + String id = mService.getRecordingSessionId(mUserId); + RecordingSession session = new RecordingSession(id, this); + return session; + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + /** * Reports error event. * @hide diff --git a/media/java/android/media/metrics/NetworkEvent.java b/media/java/android/media/metrics/NetworkEvent.java index 029edeb933749..098885cc9bdd3 100644 --- a/media/java/android/media/metrics/NetworkEvent.java +++ b/media/java/android/media/metrics/NetworkEvent.java @@ -20,6 +20,7 @@ import android.annotation.IntDef; import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; +import android.os.Bundle; import android.os.Parcel; import android.os.Parcelable; @@ -33,6 +34,9 @@ import java.util.Objects; public final class NetworkEvent extends Event implements Parcelable { /** Network type is not specified. Default type. */ public static final int NETWORK_TYPE_NONE = 0; + // TODO: replace NONE with UNKNOWN + /** @hide */ + public static final int NETWORK_TYPE_UNKNOWN = 0; /** Other network type */ public static final int NETWORK_TYPE_OTHER = 1; /** Wi-Fi network */ @@ -49,6 +53,9 @@ public final class NetworkEvent extends Event implements Parcelable { public static final int NETWORK_TYPE_5G_NSA = 7; /** 5G SA network */ public static final int NETWORK_TYPE_5G_SA = 8; + /** Not network connected */ + /** @hide */ + public static final int NETWORK_TYPE_OFFLINE = 9; private final int mNetworkType; private final long mTimeSinceCreatedMillis; @@ -56,6 +63,7 @@ public final class NetworkEvent extends Event implements Parcelable { /** @hide */ @IntDef(prefix = "NETWORK_TYPE_", value = { NETWORK_TYPE_NONE, + NETWORK_TYPE_UNKNOWN, NETWORK_TYPE_OTHER, NETWORK_TYPE_WIFI, NETWORK_TYPE_ETHERNET, @@ -63,7 +71,8 @@ public final class NetworkEvent extends Event implements Parcelable { NETWORK_TYPE_3G, NETWORK_TYPE_4G, NETWORK_TYPE_5G_NSA, - NETWORK_TYPE_5G_SA + NETWORK_TYPE_5G_SA, + NETWORK_TYPE_OFFLINE }) @Retention(RetentionPolicy.SOURCE) public @interface NetworkType {} @@ -92,6 +101,8 @@ public final class NetworkEvent extends Event implements Parcelable { return "NETWORK_TYPE_5G_NSA"; case NETWORK_TYPE_5G_SA: return "NETWORK_TYPE_5G_SA"; + case NETWORK_TYPE_OFFLINE: + return "NETWORK_TYPE_OFFLINE"; default: return Integer.toHexString(value); } @@ -102,9 +113,10 @@ public final class NetworkEvent extends Event implements Parcelable { * * @hide */ - public NetworkEvent(@NetworkType int type, long timeSinceCreatedMillis) { + public NetworkEvent(@NetworkType int type, long timeSinceCreatedMillis, Bundle extras) { this.mNetworkType = type; this.mTimeSinceCreatedMillis = timeSinceCreatedMillis; + this.mExtras = extras.deepCopy(); } /** @@ -149,8 +161,12 @@ public final class NetworkEvent extends Event implements Parcelable { @Override public void writeToParcel(@NonNull android.os.Parcel dest, int flags) { + byte flg = 0; + if (mExtras != null) flg |= 0x1; + dest.writeByte(flg); dest.writeInt(mNetworkType); dest.writeLong(mTimeSinceCreatedMillis); + if (mExtras != null) dest.writeBundle(mExtras); } @Override @@ -160,11 +176,14 @@ public final class NetworkEvent extends Event implements Parcelable { /** @hide */ /* package-private */ NetworkEvent(@NonNull android.os.Parcel in) { + byte flg = in.readByte(); int type = in.readInt(); long timeSinceCreatedMillis = in.readLong(); + Bundle extras = (flg & 0x2) == 0 ? null : in.readBundle(); this.mNetworkType = type; this.mTimeSinceCreatedMillis = timeSinceCreatedMillis; + this.mExtras = extras; } /** @@ -189,6 +208,7 @@ public final class NetworkEvent extends Event implements Parcelable { public static final class Builder { private int mNetworkType = NETWORK_TYPE_NONE; private long mTimeSinceCreatedMillis = -1; + private Bundle mExtras; /** * Creates a new Builder. @@ -214,9 +234,19 @@ public final class NetworkEvent extends Event implements Parcelable { return this; } + /** + * Set extras for compatibility. + *

Should be used by support library only. + * @hide + */ + public @NonNull Builder setExtras(@NonNull Bundle extras) { + mExtras = extras; + return this; + } + /** Builds the instance. */ public @NonNull NetworkEvent build() { - NetworkEvent o = new NetworkEvent(mNetworkType, mTimeSinceCreatedMillis); + NetworkEvent o = new NetworkEvent(mNetworkType, mTimeSinceCreatedMillis, mExtras); return o; } } diff --git a/media/java/android/media/metrics/PlaybackErrorEvent.java b/media/java/android/media/metrics/PlaybackErrorEvent.java index 5a0820d16cb9e..b23b4d2728b4e 100644 --- a/media/java/android/media/metrics/PlaybackErrorEvent.java +++ b/media/java/android/media/metrics/PlaybackErrorEvent.java @@ -21,6 +21,7 @@ import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SuppressLint; +import android.os.Bundle; import android.os.Parcel; import android.os.Parcelable; @@ -63,11 +64,13 @@ public final class PlaybackErrorEvent extends Event implements Parcelable { @Nullable String exceptionStack, int errorCode, int subErrorCode, - long timeSinceCreatedMillis) { + long timeSinceCreatedMillis, + Bundle extras) { this.mExceptionStack = exceptionStack; this.mErrorCode = errorCode; this.mSubErrorCode = subErrorCode; this.mTimeSinceCreatedMillis = timeSinceCreatedMillis; + this.mExtras = extras.deepCopy(); } /** @hide */ @@ -135,11 +138,13 @@ public final class PlaybackErrorEvent extends Event implements Parcelable { public void writeToParcel(@NonNull Parcel dest, int flags) { byte flg = 0; if (mExceptionStack != null) flg |= 0x1; + if (mExtras != null) flg |= 0x2; dest.writeByte(flg); if (mExceptionStack != null) dest.writeString(mExceptionStack); dest.writeInt(mErrorCode); dest.writeInt(mSubErrorCode); dest.writeLong(mTimeSinceCreatedMillis); + if (mExtras != null) dest.writeBundle(mExtras); } @Override @@ -154,11 +159,13 @@ public final class PlaybackErrorEvent extends Event implements Parcelable { int errorCode = in.readInt(); int subErrorCode = in.readInt(); long timeSinceCreatedMillis = in.readLong(); + Bundle extras = (flg & 0x2) == 0 ? null : in.readBundle(); this.mExceptionStack = exceptionStack; this.mErrorCode = errorCode; this.mSubErrorCode = subErrorCode; this.mTimeSinceCreatedMillis = timeSinceCreatedMillis; + this.mExtras = extras; } @@ -183,6 +190,7 @@ public final class PlaybackErrorEvent extends Event implements Parcelable { private int mErrorCode; private int mSubErrorCode; private long mTimeSinceCreatedMillis = -1; + private Bundle mExtras; /** * Creates a new Builder. @@ -226,6 +234,16 @@ public final class PlaybackErrorEvent extends Event implements Parcelable { return this; } + /** + * Set extras for compatibility. + *

Should be used by support library only. + * @hide + */ + public @NonNull Builder setExtras(@NonNull Bundle extras) { + mExtras = extras; + return this; + } + /** Builds the instance. */ public @NonNull PlaybackErrorEvent build() { @@ -241,7 +259,8 @@ public final class PlaybackErrorEvent extends Event implements Parcelable { stack, mErrorCode, mSubErrorCode, - mTimeSinceCreatedMillis); + mTimeSinceCreatedMillis, + mExtras); return o; } } diff --git a/media/java/android/media/metrics/PlaybackMetrics.java b/media/java/android/media/metrics/PlaybackMetrics.java index 4aa61662ba52b..7e7f44a97b9c5 100644 --- a/media/java/android/media/metrics/PlaybackMetrics.java +++ b/media/java/android/media/metrics/PlaybackMetrics.java @@ -20,6 +20,7 @@ import android.annotation.IntDef; import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; +import android.os.Bundle; import android.os.Parcel; import android.os.Parcelable; @@ -58,6 +59,10 @@ public final class PlaybackMetrics implements Parcelable { /** SS (HTTP Smooth Streaming) stream type. */ public static final int STREAM_TYPE_SS = 5; + /** Unknown playback type. */ + // TODO: change the PLAYBACK_TYPE_ values + /** @hide */ + public static final int PLAYBACK_TYPE_UNKNOWN = 0; /** VOD (Video on Demand) playback type. */ public static final int PLAYBACK_TYPE_VOD = 0; /** Live playback type. */ @@ -80,6 +85,10 @@ public final class PlaybackMetrics implements Parcelable { /** Clear key DRM type. */ public static final int DRM_TYPE_CLEARKEY = 6; + /** Unknown content type. */ + // TODO: change the CONTENT_TYPE_ values + /** @hide */ + public static final int CONTENT_TYPE_UNKNOWN = 0; /** Main contents. */ public static final int CONTENT_TYPE_MAIN = 0; /** Advertisement contents. */ @@ -112,6 +121,7 @@ public final class PlaybackMetrics implements Parcelable { /** @hide */ @IntDef(prefix = "PLAYBACK_TYPE_", value = { + PLAYBACK_TYPE_UNKNOWN, PLAYBACK_TYPE_VOD, PLAYBACK_TYPE_LIVE, PLAYBACK_TYPE_OTHER @@ -134,6 +144,7 @@ public final class PlaybackMetrics implements Parcelable { /** @hide */ @IntDef(prefix = "CONTENT_TYPE_", value = { + CONTENT_TYPE_UNKNOWN, CONTENT_TYPE_MAIN, CONTENT_TYPE_AD, CONTENT_TYPE_OTHER @@ -158,6 +169,8 @@ public final class PlaybackMetrics implements Parcelable { private final long mNetworkBytesRead; private final long mLocalBytesRead; private final long mNetworkTransferDurationMillis; + private final byte[] mDrmSessionId; + private final Bundle mExtras; /** * Creates a new PlaybackMetrics. @@ -179,7 +192,9 @@ public final class PlaybackMetrics implements Parcelable { int audioUnderrunCount, long networkBytesRead, long localBytesRead, - long networkTransferDurationMillis) { + long networkTransferDurationMillis, + byte[] drmSessionId, + Bundle extras) { this.mMediaDurationMillis = mediaDurationMillis; this.mStreamSource = streamSource; this.mStreamType = streamType; @@ -196,6 +211,8 @@ public final class PlaybackMetrics implements Parcelable { this.mNetworkBytesRead = networkBytesRead; this.mLocalBytesRead = localBytesRead; this.mNetworkTransferDurationMillis = networkTransferDurationMillis; + this.mDrmSessionId = drmSessionId; + this.mExtras = extras.deepCopy(); } /** @@ -321,6 +338,12 @@ public final class PlaybackMetrics implements Parcelable { return mNetworkTransferDurationMillis; } + /** @hide */ + @NonNull + public byte[] getDrmSessionId() { + return mDrmSessionId; + } + @Override public String toString() { return "PlaybackMetrics { " @@ -339,6 +362,7 @@ public final class PlaybackMetrics implements Parcelable { + "networkBytesRead = " + mNetworkBytesRead + ", " + "localBytesRead = " + mLocalBytesRead + ", " + "networkTransferDurationMillis = " + mNetworkTransferDurationMillis + + "drmSessionId = " + Arrays.toString(mDrmSessionId) + " }"; } @@ -361,7 +385,8 @@ public final class PlaybackMetrics implements Parcelable { && mAudioUnderrunCount == that.mAudioUnderrunCount && mNetworkBytesRead == that.mNetworkBytesRead && mLocalBytesRead == that.mLocalBytesRead - && mNetworkTransferDurationMillis == that.mNetworkTransferDurationMillis; + && mNetworkTransferDurationMillis == that.mNetworkTransferDurationMillis + && Arrays.equals(mDrmSessionId, that.mDrmSessionId); } @Override @@ -369,7 +394,7 @@ public final class PlaybackMetrics implements Parcelable { return Objects.hash(mMediaDurationMillis, mStreamSource, mStreamType, mPlaybackType, mDrmType, mContentType, mPlayerName, mPlayerVersion, mExperimentIds, mVideoFramesPlayed, mVideoFramesDropped, mAudioUnderrunCount, mNetworkBytesRead, - mLocalBytesRead, mNetworkTransferDurationMillis); + mLocalBytesRead, mNetworkTransferDurationMillis, mDrmSessionId); } @Override @@ -377,6 +402,7 @@ public final class PlaybackMetrics implements Parcelable { long flg = 0; if (mPlayerName != null) flg |= 0x80; if (mPlayerVersion != null) flg |= 0x100; + if (mExtras != null) flg |= 0x200; dest.writeLong(flg); dest.writeLong(mMediaDurationMillis); dest.writeInt(mStreamSource); @@ -386,6 +412,7 @@ public final class PlaybackMetrics implements Parcelable { dest.writeInt(mContentType); if (mPlayerName != null) dest.writeString(mPlayerName); if (mPlayerVersion != null) dest.writeString(mPlayerVersion); + if (mExtras != null) dest.writeBundle(mExtras); dest.writeLongArray(mExperimentIds); dest.writeInt(mVideoFramesPlayed); dest.writeInt(mVideoFramesDropped); @@ -393,6 +420,8 @@ public final class PlaybackMetrics implements Parcelable { dest.writeLong(mNetworkBytesRead); dest.writeLong(mLocalBytesRead); dest.writeLong(mNetworkTransferDurationMillis); + dest.writeInt(mDrmSessionId.length); + dest.writeByteArray(mDrmSessionId); } @Override @@ -411,6 +440,7 @@ public final class PlaybackMetrics implements Parcelable { int contentType = in.readInt(); String playerName = (flg & 0x80) == 0 ? null : in.readString(); String playerVersion = (flg & 0x100) == 0 ? null : in.readString(); + Bundle extras = (flg & 0x200) == 0 ? null : in.readBundle(); long[] experimentIds = in.createLongArray(); int videoFramesPlayed = in.readInt(); int videoFramesDropped = in.readInt(); @@ -418,6 +448,9 @@ public final class PlaybackMetrics implements Parcelable { long networkBytesRead = in.readLong(); long localBytesRead = in.readLong(); long networkTransferDurationMillis = in.readLong(); + int drmSessionIdLen = in.readInt(); + byte[] drmSessionId = new byte[drmSessionIdLen]; + in.readByteArray(drmSessionId); this.mMediaDurationMillis = mediaDurationMillis; this.mStreamSource = streamSource; @@ -435,6 +468,8 @@ public final class PlaybackMetrics implements Parcelable { this.mNetworkBytesRead = networkBytesRead; this.mLocalBytesRead = localBytesRead; this.mNetworkTransferDurationMillis = networkTransferDurationMillis; + this.mDrmSessionId = drmSessionId; + this.mExtras = extras; } public static final @NonNull Parcelable.Creator CREATOR = @@ -470,6 +505,8 @@ public final class PlaybackMetrics implements Parcelable { private long mNetworkBytesRead = -1; private long mLocalBytesRead = -1; private long mNetworkTransferDurationMillis = -1; + private byte[] mDrmSessionId = new byte[0]; + private Bundle mExtras; /** * Creates a new Builder. @@ -608,6 +645,24 @@ public final class PlaybackMetrics implements Parcelable { return this; } + /** + * @hide + */ + public @NonNull Builder setDrmSessionId(@NonNull byte[] drmSessionId) { + mDrmSessionId = drmSessionId; + return this; + } + + /** + * Set extras for compatibility. + *

Should be used by support library only. + * @hide + */ + public @NonNull Builder setExtras(@NonNull Bundle extras) { + mExtras = extras; + return this; + } + /** Builds the instance. This builder should not be touched after calling this! */ public @NonNull PlaybackMetrics build() { @@ -626,7 +681,9 @@ public final class PlaybackMetrics implements Parcelable { mAudioUnderrunCount, mNetworkBytesRead, mLocalBytesRead, - mNetworkTransferDurationMillis); + mNetworkTransferDurationMillis, + mDrmSessionId, + mExtras); return o; } diff --git a/media/java/android/media/metrics/PlaybackSession.java b/media/java/android/media/metrics/PlaybackSession.java index 4ee8a45fe1960..272fd9bd55767 100644 --- a/media/java/android/media/metrics/PlaybackSession.java +++ b/media/java/android/media/metrics/PlaybackSession.java @@ -29,6 +29,7 @@ import java.util.Objects; public final class PlaybackSession implements AutoCloseable { private final @NonNull String mId; private final @NonNull MediaMetricsManager mManager; + private final @NonNull LogSessionId mLogSessionId; private boolean mClosed = false; /** @@ -41,6 +42,7 @@ public final class PlaybackSession implements AutoCloseable { mManager = manager; AnnotationValidations.validate(NonNull.class, null, mId); AnnotationValidations.validate(NonNull.class, null, mManager); + mLogSessionId = new LogSessionId(mId); } /** @@ -79,9 +81,16 @@ public final class PlaybackSession implements AutoCloseable { } public @NonNull String getId() { + // TODO: remove this method and use getSessionId(); return mId; } + /** @hide */ + public @NonNull LogSessionId getSessionId() { + // TODO: remove getId() and use this method; + return mLogSessionId; + } + @Override public boolean equals(@Nullable Object o) { if (this == o) return true; diff --git a/media/java/android/media/metrics/PlaybackStateEvent.java b/media/java/android/media/metrics/PlaybackStateEvent.java index 8ca5b75dec988..dea8c1db71def 100644 --- a/media/java/android/media/metrics/PlaybackStateEvent.java +++ b/media/java/android/media/metrics/PlaybackStateEvent.java @@ -20,6 +20,7 @@ import android.annotation.IntDef; import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; +import android.os.Bundle; import android.os.Parcel; import android.os.Parcelable; @@ -136,9 +137,11 @@ public final class PlaybackStateEvent extends Event implements Parcelable { */ public PlaybackStateEvent( int state, - long timeSinceCreatedMillis) { + long timeSinceCreatedMillis, + Bundle extras) { this.mTimeSinceCreatedMillis = timeSinceCreatedMillis; this.mState = state; + this.mExtras = extras.deepCopy(); } /** @@ -174,8 +177,12 @@ public final class PlaybackStateEvent extends Event implements Parcelable { @Override public void writeToParcel(@NonNull Parcel dest, int flags) { + byte flg = 0; + if (mExtras != null) flg |= 0x1; + dest.writeByte(flg); dest.writeInt(mState); dest.writeLong(mTimeSinceCreatedMillis); + if (mExtras != null) dest.writeBundle(mExtras); } @Override @@ -185,11 +192,14 @@ public final class PlaybackStateEvent extends Event implements Parcelable { /** @hide */ /* package-private */ PlaybackStateEvent(@NonNull Parcel in) { + byte flg = in.readByte(); int state = in.readInt(); long timeSinceCreatedMillis = in.readLong(); + Bundle extras = (flg & 0x1) == 0 ? null : in.readBundle(); this.mState = state; this.mTimeSinceCreatedMillis = timeSinceCreatedMillis; + this.mExtras = extras; } public static final @NonNull Parcelable.Creator CREATOR = @@ -211,6 +221,7 @@ public final class PlaybackStateEvent extends Event implements Parcelable { public static final class Builder { private int mState = STATE_NOT_STARTED; private long mTimeSinceCreatedMillis = -1; + private Bundle mExtras; /** * Creates a new Builder. @@ -236,11 +247,22 @@ public final class PlaybackStateEvent extends Event implements Parcelable { return this; } + /** + * Set extras for compatibility. + *

Should be used by support library only. + * @hide + */ + public @NonNull Builder setExtras(@NonNull Bundle extras) { + mExtras = extras; + return this; + } + /** Builds the instance. */ public @NonNull PlaybackStateEvent build() { PlaybackStateEvent o = new PlaybackStateEvent( mState, - mTimeSinceCreatedMillis); + mTimeSinceCreatedMillis, + mExtras); return o; } } diff --git a/media/java/android/media/metrics/RecordingSession.java b/media/java/android/media/metrics/RecordingSession.java new file mode 100644 index 0000000000000..541d129604ad3 --- /dev/null +++ b/media/java/android/media/metrics/RecordingSession.java @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2021 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.media.metrics; + +import android.annotation.NonNull; +import android.annotation.Nullable; + +import com.android.internal.util.AnnotationValidations; + +import java.util.Objects; + +/** + * An instances of this class represents a session of media recording. + * @hide + */ +public final class RecordingSession implements AutoCloseable { + private final @NonNull String mId; + private final @NonNull MediaMetricsManager mManager; + private final @NonNull LogSessionId mLogSessionId; + private boolean mClosed = false; + + /** @hide */ + public RecordingSession(@NonNull String id, @NonNull MediaMetricsManager manager) { + mId = id; + mManager = manager; + AnnotationValidations.validate(NonNull.class, null, mId); + AnnotationValidations.validate(NonNull.class, null, mManager); + mLogSessionId = new LogSessionId(mId); + } + + @Override + public boolean equals(@Nullable Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + RecordingSession that = (RecordingSession) o; + return Objects.equals(mId, that.mId); + } + + @Override + public int hashCode() { + return Objects.hash(mId); + } + + @Override + public void close() { + mClosed = true; + } +} diff --git a/media/java/android/media/metrics/TrackChangeEvent.java b/media/java/android/media/metrics/TrackChangeEvent.java index ef25357457c55..aa519782ec80b 100644 --- a/media/java/android/media/metrics/TrackChangeEvent.java +++ b/media/java/android/media/metrics/TrackChangeEvent.java @@ -16,10 +16,12 @@ package android.media.metrics; +import android.annotation.FloatRange; import android.annotation.IntDef; import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; +import android.os.Bundle; import android.os.Parcel; import android.os.Parcelable; @@ -65,9 +67,10 @@ public final class TrackChangeEvent extends Event implements Parcelable { private final @Nullable String mLanguage; private final @Nullable String mLanguageRegion; private final int mChannelCount; - private final int mSampleRate; + private final int mAudioSampleRate; private final int mWidth; private final int mHeight; + private final float mVideoFrameRate; @@ -99,6 +102,7 @@ public final class TrackChangeEvent extends Event implements Parcelable { @Retention(RetentionPolicy.SOURCE) public @interface TrackType {} + // TODO: remove this constructor. Use the private one below. public TrackChangeEvent( int state, int reason, @@ -125,9 +129,45 @@ public final class TrackChangeEvent extends Event implements Parcelable { this.mLanguage = language; this.mLanguageRegion = languageRegion; this.mChannelCount = channelCount; - this.mSampleRate = sampleRate; + this.mAudioSampleRate = sampleRate; this.mWidth = width; this.mHeight = height; + this.mVideoFrameRate = -1; + } + + private TrackChangeEvent( + int state, + int reason, + @Nullable String containerMimeType, + @Nullable String sampleMimeType, + @Nullable String codecName, + int bitrate, + long timeSinceCreatedMillis, + int type, + @Nullable String language, + @Nullable String languageRegion, + int channelCount, + int sampleRate, + int width, + int height, + float videoFrameRate, + @Nullable Bundle extras) { + this.mState = state; + this.mReason = reason; + this.mContainerMimeType = containerMimeType; + this.mSampleMimeType = sampleMimeType; + this.mCodecName = codecName; + this.mBitrate = bitrate; + this.mTimeSinceCreatedMillis = timeSinceCreatedMillis; + this.mType = type; + this.mLanguage = language; + this.mLanguageRegion = languageRegion; + this.mChannelCount = channelCount; + this.mAudioSampleRate = sampleRate; + this.mWidth = width; + this.mHeight = height; + this.mVideoFrameRate = videoFrameRate; + this.mExtras = extras.deepCopy(); } /** @@ -223,7 +263,7 @@ public final class TrackChangeEvent extends Event implements Parcelable { */ @IntRange(from = -1, to = Integer.MAX_VALUE) public int getSampleRate() { - return mSampleRate; + return mAudioSampleRate; } /** @@ -244,6 +284,16 @@ public final class TrackChangeEvent extends Event implements Parcelable { return mHeight; } + /** + * Gets video frame rate. + * @return the video frame rate, or -1 if unknown. + * @hide + */ + @FloatRange(from = -1, to = Float.MAX_VALUE) + public float getVideoFrameRate() { + return mVideoFrameRate; + } + @Override public void writeToParcel(@NonNull Parcel dest, int flags) { int flg = 0; @@ -252,6 +302,7 @@ public final class TrackChangeEvent extends Event implements Parcelable { if (mCodecName != null) flg |= 0x10; if (mLanguage != null) flg |= 0x100; if (mLanguageRegion != null) flg |= 0x200; + if (mExtras != null) flg |= 0x400; dest.writeInt(flg); dest.writeInt(mState); dest.writeInt(mReason); @@ -264,9 +315,11 @@ public final class TrackChangeEvent extends Event implements Parcelable { if (mLanguage != null) dest.writeString(mLanguage); if (mLanguageRegion != null) dest.writeString(mLanguageRegion); dest.writeInt(mChannelCount); - dest.writeInt(mSampleRate); + dest.writeInt(mAudioSampleRate); dest.writeInt(mWidth); dest.writeInt(mHeight); + dest.writeFloat(mVideoFrameRate); + if (mExtras != null) dest.writeBundle(mExtras); } @Override @@ -291,6 +344,8 @@ public final class TrackChangeEvent extends Event implements Parcelable { int sampleRate = in.readInt(); int width = in.readInt(); int height = in.readInt(); + float videoFrameRate = in.readFloat(); + Bundle extras = (flg & 0x400) == 0 ? null : in.readBundle(); this.mState = state; this.mReason = reason; @@ -303,9 +358,11 @@ public final class TrackChangeEvent extends Event implements Parcelable { this.mLanguage = language; this.mLanguageRegion = languageRegion; this.mChannelCount = channelCount; - this.mSampleRate = sampleRate; + this.mAudioSampleRate = sampleRate; this.mWidth = width; this.mHeight = height; + this.mVideoFrameRate = videoFrameRate; + this.mExtras = extras; } public static final @NonNull Parcelable.Creator CREATOR = @@ -335,9 +392,10 @@ public final class TrackChangeEvent extends Event implements Parcelable { + "language = " + mLanguage + ", " + "languageRegion = " + mLanguageRegion + ", " + "channelCount = " + mChannelCount + ", " - + "sampleRate = " + mSampleRate + ", " + + "sampleRate = " + mAudioSampleRate + ", " + "width = " + mWidth + ", " - + "height = " + mHeight + + "height = " + mHeight + ", " + + "videoFrameRate = " + mVideoFrameRate + " }"; } @@ -357,16 +415,17 @@ public final class TrackChangeEvent extends Event implements Parcelable { && Objects.equals(mLanguage, that.mLanguage) && Objects.equals(mLanguageRegion, that.mLanguageRegion) && mChannelCount == that.mChannelCount - && mSampleRate == that.mSampleRate + && mAudioSampleRate == that.mAudioSampleRate && mWidth == that.mWidth - && mHeight == that.mHeight; + && mHeight == that.mHeight + && mVideoFrameRate == that.mVideoFrameRate; } @Override public int hashCode() { return Objects.hash(mState, mReason, mContainerMimeType, mSampleMimeType, mCodecName, mBitrate, mTimeSinceCreatedMillis, mType, mLanguage, mLanguageRegion, - mChannelCount, mSampleRate, mWidth, mHeight); + mChannelCount, mAudioSampleRate, mWidth, mHeight, mVideoFrameRate); } /** @@ -385,9 +444,11 @@ public final class TrackChangeEvent extends Event implements Parcelable { private @Nullable String mLanguage; private @Nullable String mLanguageRegion; private int mChannelCount = -1; - private int mSampleRate = -1; + private int mAudioSampleRate = -1; private int mWidth = -1; private int mHeight = -1; + private float mVideoFrameRate = -1; + private Bundle mExtras; private long mBuilderFieldsSet = 0L; @@ -512,9 +573,10 @@ public final class TrackChangeEvent extends Event implements Parcelable { */ public @NonNull Builder setSampleRate( @IntRange(from = -1, to = Integer.MAX_VALUE) int value) { + // TODO: rename it to setAudioSampleRate checkNotUsed(); mBuilderFieldsSet |= 0x800; - mSampleRate = value; + mAudioSampleRate = value; return this; } @@ -540,6 +602,28 @@ public final class TrackChangeEvent extends Event implements Parcelable { return this; } + /** + * Sets video frame rate. + * @param value the video frame rate. -1 indicates the value is unknown. + * @hide + */ + public @NonNull Builder setVideoFrameRate( + @FloatRange(from = -1, to = Float.MAX_VALUE) float value) { + checkNotUsed(); + mVideoFrameRate = value; + return this; + } + + /** + * Set extras for compatibility. + *

Should be used by support library only. + * @hide + */ + public @NonNull Builder setExtras(@NonNull Bundle extras) { + mExtras = extras; + return this; + } + /** Builds the instance. This builder should not be touched after calling this! */ public @NonNull TrackChangeEvent build() { checkNotUsed(); @@ -557,9 +641,11 @@ public final class TrackChangeEvent extends Event implements Parcelable { mLanguage, mLanguageRegion, mChannelCount, - mSampleRate, + mAudioSampleRate, mWidth, - mHeight); + mHeight, + mVideoFrameRate, + mExtras); return o; } diff --git a/services/core/java/com/android/server/media/metrics/MediaMetricsManagerService.java b/services/core/java/com/android/server/media/metrics/MediaMetricsManagerService.java index 639dda6f8981c..23195bbe5d7eb 100644 --- a/services/core/java/com/android/server/media/metrics/MediaMetricsManagerService.java +++ b/services/core/java/com/android/server/media/metrics/MediaMetricsManagerService.java @@ -93,14 +93,23 @@ public final class MediaMetricsManagerService extends SystemService { StatsLog.write(statsEvent); } - @Override - public String getSessionId(int userId) { + private String getSessionIdInternal(int userId) { byte[] byteId = new byte[16]; // 128 bits mSecureRandom.nextBytes(byteId); String id = Base64.encodeToString(byteId, Base64.DEFAULT); return id; } + @Override + public String getPlaybackSessionId(int userId) { + return getSessionIdInternal(userId); + } + + @Override + public String getRecordingSessionId(int userId) { + return getSessionIdInternal(userId); + } + @Override public void reportPlaybackErrorEvent( String sessionId, PlaybackErrorEvent event, int userId) {