Merge "Add final editing metrics" into main
diff --git a/core/api/current.txt b/core/api/current.txt
index 797f255..ec8bc96 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -25891,8 +25891,11 @@
@FlaggedApi("com.android.media.editing.flags.add_media_metrics_editing") public final class EditingEndedEvent extends android.media.metrics.Event implements android.os.Parcelable {
method public int describeContents();
method public int getErrorCode();
+ method @Nullable public String getExporterName();
+ method public float getFinalProgressPercent();
method public int getFinalState();
method @NonNull public java.util.List<android.media.metrics.MediaItemInfo> getInputMediaItemInfos();
+ method @Nullable public String getMuxerName();
method public long getOperationTypes();
method @Nullable public android.media.metrics.MediaItemInfo getOutputMediaItemInfo();
method public void writeToParcel(@NonNull android.os.Parcel, int);
@@ -25927,6 +25930,7 @@
field public static final long OPERATION_TYPE_VIDEO_EDIT = 4L; // 0x4L
field public static final long OPERATION_TYPE_VIDEO_TRANSCODE = 1L; // 0x1L
field public static final long OPERATION_TYPE_VIDEO_TRANSMUX = 16L; // 0x10L
+ field public static final int PROGRESS_PERCENT_UNKNOWN = -1; // 0xffffffff
field public static final int TIME_SINCE_CREATED_UNKNOWN = -1; // 0xffffffff
}
@@ -25936,7 +25940,10 @@
method @NonNull public android.media.metrics.EditingEndedEvent.Builder addOperationType(long);
method @NonNull public android.media.metrics.EditingEndedEvent build();
method @NonNull public android.media.metrics.EditingEndedEvent.Builder setErrorCode(int);
+ method @NonNull public android.media.metrics.EditingEndedEvent.Builder setExporterName(@NonNull String);
+ method @NonNull public android.media.metrics.EditingEndedEvent.Builder setFinalProgressPercent(@FloatRange(from=0, to=100) float);
method @NonNull public android.media.metrics.EditingEndedEvent.Builder setMetricsBundle(@NonNull android.os.Bundle);
+ method @NonNull public android.media.metrics.EditingEndedEvent.Builder setMuxerName(@NonNull String);
method @NonNull public android.media.metrics.EditingEndedEvent.Builder setOutputMediaItemInfo(@NonNull android.media.metrics.MediaItemInfo);
method @NonNull public android.media.metrics.EditingEndedEvent.Builder setTimeSinceCreatedMillis(@IntRange(from=android.media.metrics.EditingEndedEvent.TIME_SINCE_CREATED_UNKNOWN) long);
}
diff --git a/media/java/android/media/metrics/EditingEndedEvent.java b/media/java/android/media/metrics/EditingEndedEvent.java
index f1c5c9d..9b3477f 100644
--- a/media/java/android/media/metrics/EditingEndedEvent.java
+++ b/media/java/android/media/metrics/EditingEndedEvent.java
@@ -18,6 +18,7 @@
import static com.android.media.editing.flags.Flags.FLAG_ADD_MEDIA_METRICS_EDITING;
import android.annotation.FlaggedApi;
+import android.annotation.FloatRange;
import android.annotation.IntDef;
import android.annotation.IntRange;
import android.annotation.LongDef;
@@ -60,6 +61,8 @@
private final @FinalState int mFinalState;
+ private final float mFinalProgressPercent;
+
// The special value 0 is reserved for the field being unspecified in the proto.
/** Special value representing that no error occurred. */
@@ -155,10 +158,15 @@
/** Special value for unknown {@linkplain #getTimeSinceCreatedMillis() time since creation}. */
public static final int TIME_SINCE_CREATED_UNKNOWN = -1;
+ /** Special value for unknown {@linkplain #getFinalProgressPercent() final progress}. */
+ public static final int PROGRESS_PERCENT_UNKNOWN = -1;
+
private final @ErrorCode int mErrorCode;
@SuppressWarnings("HidingField") // Hiding field from superclass as for playback events.
private final long mTimeSinceCreatedMillis;
+ @Nullable private final String mExporterName;
+ @Nullable private final String mMuxerName;
private final ArrayList<MediaItemInfo> mInputMediaItemInfos;
@Nullable private final MediaItemInfo mOutputMediaItemInfo;
@@ -207,15 +215,21 @@
private EditingEndedEvent(
@FinalState int finalState,
+ float finalProgressPercent,
@ErrorCode int errorCode,
long timeSinceCreatedMillis,
+ @Nullable String exporterName,
+ @Nullable String muxerName,
ArrayList<MediaItemInfo> inputMediaItemInfos,
@Nullable MediaItemInfo outputMediaItemInfo,
@OperationType long operationTypes,
@NonNull Bundle extras) {
mFinalState = finalState;
+ mFinalProgressPercent = finalProgressPercent;
mErrorCode = errorCode;
mTimeSinceCreatedMillis = timeSinceCreatedMillis;
+ mExporterName = exporterName;
+ mMuxerName = muxerName;
mInputMediaItemInfos = inputMediaItemInfos;
mOutputMediaItemInfo = outputMediaItemInfo;
mOperationTypes = operationTypes;
@@ -228,6 +242,14 @@
return mFinalState;
}
+ /**
+ * Returns the progress of the editing operation in percent at the moment that it ended, or
+ * {@link #PROGRESS_PERCENT_UNKNOWN} if unknown.
+ */
+ public float getFinalProgressPercent() {
+ return mFinalProgressPercent;
+ }
+
/** Returns the error code for a {@linkplain #FINAL_STATE_ERROR failed} editing session. */
@ErrorCode
public int getErrorCode() {
@@ -249,6 +271,24 @@
return mTimeSinceCreatedMillis;
}
+ /**
+ * Returns the name of the library implementing the exporting operation, or {@code null} if
+ * unknown.
+ */
+ @Nullable
+ public String getExporterName() {
+ return mExporterName;
+ }
+
+ /**
+ * Returns the name of the library implementing the media muxing operation, or {@code null} if
+ * unknown.
+ */
+ @Nullable
+ public String getMuxerName() {
+ return mMuxerName;
+ }
+
/** Gets information about the input media items, or an empty list if unspecified. */
@NonNull
public List<MediaItemInfo> getInputMediaItemInfos() {
@@ -284,12 +324,21 @@
+ "finalState = "
+ mFinalState
+ ", "
+ + "finalProgressPercent = "
+ + mFinalProgressPercent
+ + ", "
+ "errorCode = "
+ mErrorCode
+ ", "
+ "timeSinceCreatedMillis = "
+ mTimeSinceCreatedMillis
+ ", "
+ + "exporterName = "
+ + mExporterName
+ + ", "
+ + "muxerName = "
+ + mMuxerName
+ + ", "
+ "inputMediaItemInfos = "
+ mInputMediaItemInfos
+ ", "
@@ -307,29 +356,38 @@
if (o == null || getClass() != o.getClass()) return false;
EditingEndedEvent that = (EditingEndedEvent) o;
return mFinalState == that.mFinalState
+ && mFinalProgressPercent == that.mFinalProgressPercent
&& mErrorCode == that.mErrorCode
&& Objects.equals(mInputMediaItemInfos, that.mInputMediaItemInfos)
&& Objects.equals(mOutputMediaItemInfo, that.mOutputMediaItemInfo)
&& mOperationTypes == that.mOperationTypes
- && mTimeSinceCreatedMillis == that.mTimeSinceCreatedMillis;
+ && mTimeSinceCreatedMillis == that.mTimeSinceCreatedMillis
+ && Objects.equals(mExporterName, that.mExporterName)
+ && Objects.equals(mMuxerName, that.mMuxerName);
}
@Override
public int hashCode() {
return Objects.hash(
mFinalState,
+ mFinalProgressPercent,
mErrorCode,
mInputMediaItemInfos,
mOutputMediaItemInfo,
mOperationTypes,
- mTimeSinceCreatedMillis);
+ mTimeSinceCreatedMillis,
+ mExporterName,
+ mMuxerName);
}
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeInt(mFinalState);
+ dest.writeFloat(mFinalProgressPercent);
dest.writeInt(mErrorCode);
dest.writeLong(mTimeSinceCreatedMillis);
+ dest.writeString(mExporterName);
+ dest.writeString(mMuxerName);
dest.writeTypedList(mInputMediaItemInfos);
dest.writeTypedObject(mOutputMediaItemInfo, /* parcelableFlags= */ 0);
dest.writeLong(mOperationTypes);
@@ -343,8 +401,11 @@
private EditingEndedEvent(@NonNull Parcel in) {
mFinalState = in.readInt();
+ mFinalProgressPercent = in.readFloat();
mErrorCode = in.readInt();
mTimeSinceCreatedMillis = in.readLong();
+ mExporterName = in.readString();
+ mMuxerName = in.readString();
mInputMediaItemInfos = new ArrayList<>();
in.readTypedList(mInputMediaItemInfos, MediaItemInfo.CREATOR);
mOutputMediaItemInfo = in.readTypedObject(MediaItemInfo.CREATOR);
@@ -370,8 +431,11 @@
public static final class Builder {
private final @FinalState int mFinalState;
private final ArrayList<MediaItemInfo> mInputMediaItemInfos;
+ private float mFinalProgressPercent;
private @ErrorCode int mErrorCode;
private long mTimeSinceCreatedMillis;
+ @Nullable private String mExporterName;
+ @Nullable private String mMuxerName;
@Nullable private MediaItemInfo mOutputMediaItemInfo;
private @OperationType long mOperationTypes;
private Bundle mMetricsBundle;
@@ -383,6 +447,7 @@
*/
public Builder(@FinalState int finalState) {
mFinalState = finalState;
+ mFinalProgressPercent = PROGRESS_PERCENT_UNKNOWN;
mErrorCode = ERROR_CODE_NONE;
mTimeSinceCreatedMillis = TIME_SINCE_CREATED_UNKNOWN;
mInputMediaItemInfos = new ArrayList<>();
@@ -390,6 +455,19 @@
}
/**
+ * Sets the progress of the editing operation in percent at the moment that it ended.
+ *
+ * @param finalProgressPercent The progress of the editing operation in percent at the
+ * moment that it ended.
+ * @see #getFinalProgressPercent()
+ */
+ public @NonNull Builder setFinalProgressPercent(
+ @FloatRange(from = 0, to = 100) float finalProgressPercent) {
+ mFinalProgressPercent = finalProgressPercent;
+ return this;
+ }
+
+ /**
* Sets the elapsed time since creating the editing session, in milliseconds.
*
* @param timeSinceCreatedMillis The elapsed time since creating the editing session, in
@@ -402,6 +480,30 @@
return this;
}
+ /**
+ * The name of the library implementing the exporting operation. For example, a Maven
+ * artifact ID like "androidx.media3.media3-transformer:1.3.0-beta01".
+ *
+ * @param exporterName The name of the library implementing the export operation.
+ * @see #getExporterName()
+ */
+ public @NonNull Builder setExporterName(@NonNull String exporterName) {
+ mExporterName = Objects.requireNonNull(exporterName);
+ return this;
+ }
+
+ /**
+ * The name of the library implementing the media muxing operation. For example, a Maven
+ * artifact ID like "androidx.media3.media3-muxer:1.3.0-beta01".
+ *
+ * @param muxerName The name of the library implementing the media muxing operation.
+ * @see #getMuxerName()
+ */
+ public @NonNull Builder setMuxerName(@NonNull String muxerName) {
+ mMuxerName = Objects.requireNonNull(muxerName);
+ return this;
+ }
+
/** Sets the error code for a {@linkplain #FINAL_STATE_ERROR failed} editing session. */
public @NonNull Builder setErrorCode(@ErrorCode int value) {
mErrorCode = value;
@@ -444,8 +546,11 @@
public @NonNull EditingEndedEvent build() {
return new EditingEndedEvent(
mFinalState,
+ mFinalProgressPercent,
mErrorCode,
mTimeSinceCreatedMillis,
+ mExporterName,
+ mMuxerName,
mInputMediaItemInfos,
mOutputMediaItemInfo,
mOperationTypes,
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 2cd8fe0..f60f55c 100644
--- a/services/core/java/com/android/server/media/metrics/MediaMetricsManagerService.java
+++ b/services/core/java/com/android/server/media/metrics/MediaMetricsManagerService.java
@@ -47,6 +47,7 @@
import java.security.SecureRandom;
import java.util.Arrays;
import java.util.List;
+import java.util.regex.Pattern;
/**
* System service manages media metrics.
@@ -79,6 +80,10 @@
private static final String FAILED_TO_GET = "failed_to_get";
private static final MediaItemInfo EMPTY_MEDIA_ITEM_INFO = new MediaItemInfo.Builder().build();
+ private static final Pattern PATTERN_KNOWN_EDITING_LIBRARY_NAMES =
+ Pattern.compile(
+ "androidx\\.media3:media3-(transformer|muxer):"
+ + "[\\d.]+(-(alpha|beta|rc)\\d\\d)?");
private static final int DURATION_BUCKETS_BELOW_ONE_MINUTE = 8;
private static final int DURATION_BUCKETS_COUNT = 13;
private static final String AUDIO_MIME_TYPE_PREFIX = "audio/";
@@ -415,8 +420,11 @@
.setAtomId(798)
.writeString(sessionId)
.writeInt(event.getFinalState())
+ .writeFloat(event.getFinalProgressPercent())
.writeInt(event.getErrorCode())
.writeLong(event.getTimeSinceCreatedMillis())
+ .writeString(getFilteredLibraryName(event.getExporterName()))
+ .writeString(getFilteredLibraryName(event.getMuxerName()))
.writeInt(getThroughputFps(event))
.writeInt(event.getInputMediaItemInfos().size())
.writeInt(inputMediaItemInfo.getSourceType())
@@ -629,6 +637,16 @@
}
}
+ private static String getFilteredLibraryName(String libraryName) {
+ if (TextUtils.isEmpty(libraryName)) {
+ return "";
+ }
+ if (!PATTERN_KNOWN_EDITING_LIBRARY_NAMES.matcher(libraryName).matches()) {
+ return "";
+ }
+ return libraryName;
+ }
+
private static int getThroughputFps(EditingEndedEvent event) {
MediaItemInfo outputMediaItemInfo = event.getOutputMediaItemInfo();
if (outputMediaItemInfo == null) {