Change session ID string to ID object

Based on API review feedback from jmtrivi@ to reduce unexpected
usage of the APIs.

And add some stub APIs

Reference CLs:
MediaDrm ag/13835091 by robertshih@
MediaExtractor: ag/13607751 by aquilescanta@
MediaParser: ag/13714647 by aquilescanta@
MediaRecorder: ag/13545885 by dichenzhang@
AudioTrack & AudioRecord: ag/13712857 by hunga@

Bug: 183095725
Test: pending CTS
CTS-Coverage-Bug: 183366721
Change-Id: I931edf021a5ec6b27a25bc6142a129b92da0fc9a
Merged-In: I931edf021a5ec6b27a25bc6142a129b92da0fc9a
diff --git a/apex/media/framework/api/current.txt b/apex/media/framework/api/current.txt
index 80698f7..bebf019 100644
--- a/apex/media/framework/api/current.txt
+++ b/apex/media/framework/api/current.txt
@@ -69,10 +69,12 @@
     method public boolean advance(@NonNull android.media.MediaParser.SeekableInputReader) throws java.io.IOException;
     method @NonNull public static android.media.MediaParser create(@NonNull android.media.MediaParser.OutputConsumer, @NonNull java.lang.String...);
     method @NonNull public static android.media.MediaParser createByName(@NonNull String, @NonNull android.media.MediaParser.OutputConsumer);
+    method @NonNull public android.media.metrics.LogSessionId getLogSessionId();
     method @NonNull public String getParserName();
     method @NonNull public static java.util.List<java.lang.String> getParserNames(@NonNull android.media.MediaFormat);
     method public void release();
     method public void seek(@NonNull android.media.MediaParser.SeekPoint);
+    method public void setLogSessionId(@NonNull android.media.metrics.LogSessionId);
     method @NonNull public android.media.MediaParser setParameter(@NonNull String, @NonNull Object);
     method public boolean supportsParameter(@NonNull String);
     field public static final String PARAMETER_ADTS_ENABLE_CBR_SEEKING = "android.media.mediaparser.adts.enableCbrSeeking";
diff --git a/apex/media/framework/java/android/media/MediaParser.java b/apex/media/framework/java/android/media/MediaParser.java
index 8bdca76..cff422d 100644
--- a/apex/media/framework/java/android/media/MediaParser.java
+++ b/apex/media/framework/java/android/media/MediaParser.java
@@ -21,6 +21,7 @@
 import android.annotation.Nullable;
 import android.annotation.StringDef;
 import android.media.MediaCodec.CryptoInfo;
+import android.media.metrics.LogSessionId;
 import android.os.Build;
 import android.text.TextUtils;
 import android.util.Log;
@@ -74,6 +75,7 @@
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 import java.util.UUID;
 import java.util.concurrent.ThreadLocalRandom;
 import java.util.function.Function;
@@ -1066,6 +1068,7 @@
     private boolean mReleased;
 
     // MediaMetrics fields.
+    @NonNull private LogSessionId mLogSessionId = LogSessionId.LOG_SESSION_ID_NONE;
     private final boolean mCreatedByName;
     private final SparseArray<Format> mTrackFormats;
     private String mLastObservedExceptionName;
@@ -1328,6 +1331,7 @@
                                 MEDIAMETRICS_PARAMETER_LIST_MAX_LENGTH));
 
         nativeSubmitMetrics(
+                // TODO: mLogSessionId,
                 mParserName,
                 mCreatedByName,
                 String.join(MEDIAMETRICS_ELEMENT_SEPARATOR, mParserNamesPool),
@@ -1341,6 +1345,15 @@
                 videoHeight);
     }
 
+    public void setLogSessionId(@NonNull LogSessionId sessionId) {
+        this.mLogSessionId = Objects.requireNonNull(sessionId);
+    }
+
+    @NonNull
+    public LogSessionId getLogSessionId() {
+        return mLogSessionId;
+    }
+
     // Private methods.
 
     private MediaParser(
@@ -2184,6 +2197,7 @@
     // Native methods.
 
     private native void nativeSubmitMetrics(
+            // TODO: String logSessionId,
             String parserName,
             boolean createdByName,
             String parserPool,
diff --git a/core/api/current.txt b/core/api/current.txt
index af0a739..f428a56 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -20579,6 +20579,7 @@
     method public int getChannelConfiguration();
     method public int getChannelCount();
     method @NonNull public android.media.AudioFormat getFormat();
+    method @NonNull public android.media.metrics.LogSessionId getLogSessionId();
     method public android.os.PersistableBundle getMetrics();
     method public static int getMinBufferSize(int, int, int);
     method public int getNotificationMarkerPosition();
@@ -20601,6 +20602,7 @@
     method public void release();
     method public void removeOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener);
     method @Deprecated public void removeOnRoutingChangedListener(android.media.AudioRecord.OnRoutingChangedListener);
+    method public void setLogSessionId(@NonNull android.media.metrics.LogSessionId);
     method public int setNotificationMarkerPosition(int);
     method public int setPositionNotificationPeriod(int);
     method public boolean setPreferredDevice(android.media.AudioDeviceInfo);
@@ -20716,6 +20718,7 @@
     method public int getChannelCount();
     method public int getDualMonoMode();
     method @NonNull public android.media.AudioFormat getFormat();
+    method @NonNull public android.media.metrics.LogSessionId getLogSessionId();
     method public static float getMaxVolume();
     method public android.os.PersistableBundle getMetrics();
     method public static int getMinBufferSize(int, int, int);
@@ -20753,6 +20756,7 @@
     method public int setAuxEffectSendLevel(@FloatRange(from=0.0) float);
     method public int setBufferSizeInFrames(@IntRange(from=0) int);
     method public boolean setDualMonoMode(int);
+    method public void setLogSessionId(@NonNull android.media.metrics.LogSessionId);
     method public int setLoopPoints(@IntRange(from=0) int, @IntRange(from=0) int, @IntRange(from=0xffffffff) int);
     method public int setNotificationMarkerPosition(int);
     method public void setOffloadDelayPadding(@IntRange(from=0) int, @IntRange(from=0) int);
@@ -21307,7 +21311,7 @@
     method @NonNull public String getDiagnosticInfo();
   }
 
-  public final class MediaCodec implements android.media.metrics.PlaybackComponent {
+  public final class MediaCodec {
     method public void configure(@Nullable android.media.MediaFormat, @Nullable android.view.Surface, @Nullable android.media.MediaCrypto, int);
     method public void configure(@Nullable android.media.MediaFormat, @Nullable android.view.Surface, int, @Nullable android.media.MediaDescrambler);
     method @NonNull public static android.media.MediaCodec createByCodecName(@NonNull String) throws java.io.IOException;
@@ -21333,7 +21337,6 @@
     method @NonNull public android.media.MediaFormat getOutputFormat(int);
     method @NonNull public android.media.MediaCodec.OutputFrame getOutputFrame(int);
     method @Nullable public android.media.Image getOutputImage(int);
-    method public String getPlaybackId();
     method @NonNull public android.media.MediaCodec.QueueRequest getQueueRequest(int);
     method @Nullable public static android.media.Image mapHardwareBuffer(@NonNull android.hardware.HardwareBuffer);
     method public void queueInputBuffer(int, int, int, long, int) throws android.media.MediaCodec.CryptoException;
@@ -21350,7 +21353,6 @@
     method public void setOnFrameRenderedListener(@Nullable android.media.MediaCodec.OnFrameRenderedListener, @Nullable android.os.Handler);
     method public void setOutputSurface(@NonNull android.view.Surface);
     method public void setParameters(@Nullable android.os.Bundle);
-    method public void setPlaybackId(@NonNull String);
     method public void setVideoScalingMode(int);
     method public void signalEndOfInputStream();
     method public void start();
@@ -21964,7 +21966,7 @@
     method @NonNull public java.util.List<byte[]> getOfflineLicenseKeySetIds();
     method public int getOfflineLicenseState(@NonNull byte[]);
     method public int getOpenSessionCount();
-    method @Nullable public android.media.metrics.PlaybackComponent getPlaybackComponent(@NonNull byte[]);
+    method @Nullable public android.media.MediaDrm.PlaybackComponent getPlaybackComponent(@NonNull byte[]);
     method @NonNull public byte[] getPropertyByteArray(String);
     method @NonNull public String getPropertyString(@NonNull String);
     method @NonNull public android.media.MediaDrm.ProvisionRequest getProvisionRequest();
@@ -22169,6 +22171,11 @@
     method public void onSessionLostState(@NonNull android.media.MediaDrm, @NonNull byte[]);
   }
 
+  public final class MediaDrm.PlaybackComponent {
+    method @NonNull public android.media.metrics.LogSessionId getLogSessionId();
+    method public void setLogSessionId(@NonNull android.media.metrics.LogSessionId);
+  }
+
   public static final class MediaDrm.ProvisionRequest {
     method @NonNull public byte[] getData();
     method @NonNull public String getDefaultUrl();
@@ -22201,6 +22208,7 @@
     method public long getCachedDuration();
     method public android.media.MediaExtractor.CasInfo getCasInfo(int);
     method public android.media.DrmInitData getDrmInitData();
+    method @NonNull public android.media.metrics.LogSessionId getLogSessionId();
     method public android.os.PersistableBundle getMetrics();
     method @Nullable public java.util.Map<java.util.UUID,byte[]> getPsshInfo();
     method public boolean getSampleCryptoInfo(@NonNull android.media.MediaCodec.CryptoInfo);
@@ -22222,6 +22230,7 @@
     method public void setDataSource(@NonNull android.content.res.AssetFileDescriptor) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException;
     method public void setDataSource(@NonNull java.io.FileDescriptor) throws java.io.IOException;
     method public void setDataSource(@NonNull java.io.FileDescriptor, long, long) throws java.io.IOException;
+    method public void setLogSessionId(@NonNull android.media.metrics.LogSessionId);
     method public void setMediaCas(@NonNull android.media.MediaCas);
     method public void unselectTrack(int);
     field public static final int SAMPLE_FLAG_ENCRYPTED = 2; // 0x2
@@ -22825,6 +22834,7 @@
     method public java.util.List<android.media.MicrophoneInfo> getActiveMicrophones() throws java.io.IOException;
     method @Nullable public android.media.AudioRecordingConfiguration getActiveRecordingConfiguration();
     method public static final int getAudioSourceMax();
+    method @NonNull public android.media.metrics.LogSessionId getLogSessionId();
     method public int getMaxAmplitude() throws java.lang.IllegalStateException;
     method public android.os.PersistableBundle getMetrics();
     method public android.media.AudioDeviceInfo getPreferredDevice();
@@ -22847,6 +22857,7 @@
     method public void setCaptureRate(double);
     method public void setInputSurface(@NonNull android.view.Surface);
     method public void setLocation(float, float);
+    method public void setLogSessionId(@NonNull android.media.metrics.LogSessionId);
     method public void setMaxDuration(int) throws java.lang.IllegalArgumentException;
     method public void setMaxFileSize(long) throws java.lang.IllegalArgumentException;
     method public void setNextOutputFile(java.io.FileDescriptor) throws java.io.IOException;
@@ -24478,6 +24489,8 @@
   }
 
   public final class LogSessionId {
+    method @NonNull public String getStringId();
+    field @NonNull public static final android.media.metrics.LogSessionId LOG_SESSION_ID_NONE;
   }
 
   public class MediaMetricsManager {
@@ -24511,11 +24524,6 @@
     method @NonNull public android.media.metrics.NetworkEvent.Builder setTimeSinceCreatedMillis(@IntRange(from=0xffffffff) long);
   }
 
-  public interface PlaybackComponent {
-    method @NonNull public String getPlaybackId();
-    method public void setPlaybackId(@NonNull String);
-  }
-
   public final class PlaybackErrorEvent extends android.media.metrics.Event implements android.os.Parcelable {
     method public int describeContents();
     method public int getErrorCode();
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 4d0c765..746a0b6 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -1478,7 +1478,7 @@
 package android.media.metrics {
 
   public final class LogSessionId {
-    method @NonNull public String getStringId();
+    ctor public LogSessionId(@NonNull String);
   }
 
 }
diff --git a/media/java/android/media/AudioRecord.java b/media/java/android/media/AudioRecord.java
index 0d61399..3399377 100644
--- a/media/java/android/media/AudioRecord.java
+++ b/media/java/android/media/AudioRecord.java
@@ -32,6 +32,7 @@
 import android.media.MediaRecorder.Source;
 import android.media.audiopolicy.AudioMix;
 import android.media.audiopolicy.AudioPolicy;
+import android.media.metrics.LogSessionId;
 import android.media.permission.Identity;
 import android.media.projection.MediaProjection;
 import android.os.Binder;
@@ -282,9 +283,9 @@
 
     /**
      * The log session id used for metrics.
-     * A null or empty string here means it is not set.
+     * {@link LogSessionId#LOG_SESSION_ID_NONE} here means it is not set.
      */
-    private String mLogSessionId;
+    @NonNull private LogSessionId mLogSessionId = LogSessionId.LOG_SESSION_ID_NONE;
 
     //---------------------------------------------------------
     // Constructor, Finalize
@@ -1963,24 +1964,34 @@
     }
 
     /**
-     * Sets a string handle to this AudioRecord for metrics collection.
+     * Sets a {@link LogSessionId} instance to this AudioRecord for metrics collection.
      *
-     * @param logSessionId a string which is used to identify this object
-     *        to the metrics service.  Proper generated Ids must be obtained
-     *        from the Java metrics service and should be considered opaque.
-     *        Use null to remove the logSessionId association.
+     * @param logSessionId a {@link LogSessionId} instance which is used to
+     *        identify this object to the metrics service. Proper generated
+     *        Ids must be obtained from the Java metrics service and should
+     *        be considered opaque. Use
+     *        {@link LogSessionId#LOG_SESSION_ID_NONE} to remove the
+     *        logSessionId association.
      * @throws IllegalStateException if AudioRecord not initialized.
-     *
-     * @hide
      */
-    public void setLogSessionId(@Nullable String logSessionId) {
+    public void setLogSessionId(@NonNull LogSessionId logSessionId) {
+        Objects.requireNonNull(logSessionId);
         if (mState == STATE_UNINITIALIZED) {
             throw new IllegalStateException("AudioRecord not initialized");
         }
-        native_setLogSessionId(logSessionId);
+        String stringId = logSessionId.getStringId();
+        native_setLogSessionId(stringId);
         mLogSessionId = logSessionId;
     }
 
+    /**
+     * Returns the {@link LogSessionId}.
+     */
+    @NonNull
+    public LogSessionId getLogSessionId() {
+        return mLogSessionId;
+    }
+
     //---------------------------------------------------------
     // Interface definitions
     //--------------------
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index bccefdf..7a2b022 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -26,6 +26,7 @@
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
 import android.compat.annotation.UnsupportedAppUsage;
+import android.media.metrics.LogSessionId;
 import android.os.Binder;
 import android.os.Build;
 import android.os.Handler;
@@ -45,6 +46,7 @@
 import java.nio.ByteOrder;
 import java.nio.NioUtils;
 import java.util.LinkedList;
+import java.util.Objects;
 import java.util.concurrent.Executor;
 
 /**
@@ -567,9 +569,9 @@
 
     /**
      * The log session id used for metrics.
-     * A null or empty string here means it is not set.
+     * {@link LogSessionId#LOG_SESSION_ID_NONE} here means it is not set.
      */
-    private String mLogSessionId;
+    @NonNull private LogSessionId mLogSessionId = LogSessionId.LOG_SESSION_ID_NONE;
 
     //--------------------------------
     // Used exclusively by native code
@@ -4044,24 +4046,35 @@
     }
 
     /**
-     * Sets a string handle to this AudioTrack for metrics collection.
+     * Sets a {@link LogSessionId} instance to this AudioTrack for metrics collection.
      *
-     * @param logSessionId a string which is used to identify this object
-     *        to the metrics service.  Proper generated Ids must be obtained
-     *        from the Java metrics service and should be considered opaque.
-     *        Use null to remove the logSessionId association.
+     * @param logSessionId a {@link LogSessionId} instance which is used to
+     *        identify this object to the metrics service. Proper generated
+     *        Ids must be obtained from the Java metrics service and should
+     *        be considered opaque. Use
+     *        {@link LogSessionId#LOG_SESSION_ID_NONE} to remove the
+     *        logSessionId association.
      * @throws IllegalStateException if AudioTrack not initialized.
      *
-     * @hide
      */
-    public void setLogSessionId(@Nullable String logSessionId) {
+    public void setLogSessionId(@NonNull LogSessionId logSessionId) {
+        Objects.requireNonNull(logSessionId);
         if (mState == STATE_UNINITIALIZED) {
             throw new IllegalStateException("track not initialized");
         }
-        native_setLogSessionId(logSessionId);
+        String stringId = logSessionId.getStringId();
+        native_setLogSessionId(stringId);
         mLogSessionId = logSessionId;
     }
 
+    /**
+     * Returns the {@link LogSessionId}.
+     */
+    @NonNull
+    public LogSessionId getLogSessionId() {
+        return mLogSessionId;
+    }
+
     //---------------------------------------------------------
     // Inner classes
     //--------------------
diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java
index a7e2b65..8db75d6 100644
--- a/media/java/android/media/MediaCodec.java
+++ b/media/java/android/media/MediaCodec.java
@@ -25,7 +25,6 @@
 import android.graphics.SurfaceTexture;
 import android.hardware.HardwareBuffer;
 import android.media.MediaCodecInfo.CodecCapabilities;
-import android.media.metrics.PlaybackComponent;
 import android.os.Build;
 import android.os.Bundle;
 import android.os.Handler;
@@ -1539,7 +1538,7 @@
   </tbody>
  </table>
  */
-final public class MediaCodec implements PlaybackComponent {
+final public class MediaCodec {
 
     /**
      * Per buffer metadata includes an offset and size specifying
@@ -1697,22 +1696,6 @@
     private static final int CB_OUTPUT_FORMAT_CHANGE = 4;
 
 
-    /**
-     * @hide
-     */
-    @Override
-    public void setPlaybackId(@NonNull String playbackId) {
-        // TODO: add a native method to pass the ID to the native code for logging.
-        mPlaybackId = playbackId;
-    }
-    /**
-     * @hide
-     */
-    @Override
-    public String getPlaybackId() {
-        return mPlaybackId;
-    }
-
     private class EventHandler extends Handler {
         private MediaCodec mCodec;
 
diff --git a/media/java/android/media/MediaDrm.java b/media/java/android/media/MediaDrm.java
index ae64c02..10b99dc 100644
--- a/media/java/android/media/MediaDrm.java
+++ b/media/java/android/media/MediaDrm.java
@@ -27,7 +27,7 @@
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.Signature;
-import android.media.metrics.PlaybackComponent;
+import android.media.metrics.LogSessionId;
 import android.os.Handler;
 import android.os.HandlerExecutor;
 import android.os.Looper;
@@ -50,6 +50,7 @@
 import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 import java.util.Set;
 import java.util.UUID;
 import java.util.concurrent.ConcurrentHashMap;
@@ -1379,7 +1380,7 @@
     public byte[] openSession(@SecurityLevel int level) throws
             NotProvisionedException, ResourceBusyException {
         byte[] sessionId = openSessionNative(level);
-        mPlaybackComponentMap.put(ByteBuffer.wrap(sessionId), new PlaybackComponentImpl(sessionId));
+        mPlaybackComponentMap.put(ByteBuffer.wrap(sessionId), new PlaybackComponent(sessionId));
         return sessionId;
     }
 
@@ -2929,8 +2930,8 @@
 
     /**
      * Obtain a {@link PlaybackComponent} associated with a DRM session.
-     * Call {@link PlaybackComponent#setPlaybackId(String)} on the returned object
-     * to associate a playback session with the DRM session.
+     * Call {@link PlaybackComponent#setLogSessionId(LogSessionId)} on
+     * the returned object to associate a playback session with the DRM session.
      *
      * @param sessionId a DRM session ID obtained from {@link #openSession()}
      * @return a {@link PlaybackComponent} associated with the session,
@@ -2945,28 +2946,37 @@
         return mPlaybackComponentMap.get(ByteBuffer.wrap(sessionId));
     }
 
-    private native void setPlaybackId(byte[] sessionId, String playbackId);
+    private native void setPlaybackId(byte[] sessionId, String logSessionId);
 
-    private final class PlaybackComponentImpl implements PlaybackComponent {
+    /** This class contains the Drm session ID and log session ID */
+    public final class PlaybackComponent {
         private final byte[] mSessionId;
-        private String mPlaybackId = "";
+        @NonNull private LogSessionId mLogSessionId = LogSessionId.LOG_SESSION_ID_NONE;
 
-        public PlaybackComponentImpl(byte[] sessionId) {
+        /** @hide */
+        public PlaybackComponent(byte[] sessionId) {
             mSessionId = sessionId;
         }
 
-        @Override
-        public void setPlaybackId(@NonNull String playbackId) {
-            if (playbackId == null) {
+
+        /**
+         * Gets the {@link LogSessionId}.
+         */
+        public void setLogSessionId(@NonNull LogSessionId logSessionId) {
+            Objects.requireNonNull(logSessionId);
+            if (logSessionId.getStringId() == null) {
                 throw new IllegalArgumentException("playbackId is null");
             }
-            MediaDrm.this.setPlaybackId(mSessionId, playbackId);
-            mPlaybackId = playbackId;
+            MediaDrm.this.setPlaybackId(mSessionId, logSessionId.getStringId());
+            mLogSessionId = logSessionId;
         }
 
-        @Override
-        @NonNull public String getPlaybackId() {
-            return mPlaybackId;
+
+        /**
+         * Returns the {@link LogSessionId}.
+         */
+        @NonNull public LogSessionId getLogSessionId() {
+            return mLogSessionId;
         }
     }
 
diff --git a/media/java/android/media/MediaExtractor.java b/media/java/android/media/MediaExtractor.java
index 8f60330..283f1f1 100644
--- a/media/java/android/media/MediaExtractor.java
+++ b/media/java/android/media/MediaExtractor.java
@@ -22,6 +22,7 @@
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.res.AssetFileDescriptor;
+import android.media.metrics.LogSessionId;
 import android.net.Uri;
 import android.os.IBinder;
 import android.os.IHwBinder;
@@ -40,6 +41,7 @@
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 import java.util.UUID;
 import java.util.stream.Collectors;
 
@@ -73,7 +75,7 @@
  * <p>This class requires the {@link android.Manifest.permission#INTERNET} permission
  * when used with network-based content.
  */
-final public class MediaExtractor {
+public final class MediaExtractor {
     public MediaExtractor() {
         native_setup();
     }
@@ -768,6 +770,22 @@
     public native boolean hasCacheReachedEndOfStream();
 
     /**
+     * Sets the {@link LogSessionId} for MediaExtractor.
+     */
+    public void setLogSessionId(@NonNull LogSessionId logSessionId) {
+        mLogSessionId = Objects.requireNonNull(logSessionId);
+        // TODO: implement native_setPlaybackId(playbackId);
+    }
+
+    /**
+     * Returns the {@link LogSessionId} for MediaExtractor.
+     */
+    @NonNull
+    public LogSessionId getLogSessionId() {
+        return mLogSessionId;
+    }
+
+    /**
      *  Return Metrics data about the current media container.
      *
      * @return a {@link PersistableBundle} containing the set of attributes and values
@@ -796,6 +814,7 @@
     }
 
     private MediaCas mMediaCas;
+    @NonNull private LogSessionId mLogSessionId = LogSessionId.LOG_SESSION_ID_NONE;
 
     private long mNativeContext;
 
diff --git a/media/java/android/media/MediaRecorder.java b/media/java/android/media/MediaRecorder.java
index dd08d8a..f960ff2 100644
--- a/media/java/android/media/MediaRecorder.java
+++ b/media/java/android/media/MediaRecorder.java
@@ -29,6 +29,7 @@
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.hardware.Camera;
+import android.media.metrics.LogSessionId;
 import android.media.permission.Identity;
 import android.os.Build;
 import android.os.Handler;
@@ -130,6 +131,8 @@
 
     private int mChannelCount;
 
+    @NonNull private LogSessionId mLogSessionId = LogSessionId.LOG_SESSION_ID_NONE;
+
     /**
      * Default constructor.
      *
@@ -165,6 +168,27 @@
     }
 
     /**
+     * Sets the {@link LogSessionId} for MediaRecorder.
+     *
+     * @param id the global ID for monitoring the MediaRecorder performance
+     */
+    public void setLogSessionId(@NonNull LogSessionId id) {
+        Objects.requireNonNull(id);
+        mLogSessionId = id;
+        setParameter("log-session-id=" + id.getStringId());
+    }
+
+    /**
+     * Returns the {@link LogSessionId} for MediaRecorder.
+     *
+     * @return the global ID for monitoring the MediaRecorder performance
+     */
+    @NonNull
+    public LogSessionId getLogSessionId() {
+        return mLogSessionId;
+    }
+
+    /**
      * Sets a {@link android.hardware.Camera} to use for recording.
      *
      * <p>Use this function to switch quickly between preview and capture mode without a teardown of
diff --git a/media/java/android/media/metrics/LogSessionId.java b/media/java/android/media/metrics/LogSessionId.java
index f68ef4b..41f3093 100644
--- a/media/java/android/media/metrics/LogSessionId.java
+++ b/media/java/android/media/metrics/LogSessionId.java
@@ -17,20 +17,29 @@
 package android.media.metrics;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.TestApi;
 
+import java.util.Objects;
+
 /**
  * An instances of this class represents the ID of a log session.
  */
 public final class LogSessionId {
-    private final String mSessionId;
+    @NonNull private final String mSessionId;
 
-    /* package */ LogSessionId(@NonNull String id) {
-        mSessionId = id;
-    }
+    /**
+     * A {@link LogSessionId} object which is used to clear any existing session ID.
+     */
+    @NonNull public static final LogSessionId LOG_SESSION_ID_NONE = new LogSessionId("");
 
     /** @hide */
     @TestApi
+    public LogSessionId(@NonNull String id) {
+        mSessionId = Objects.requireNonNull(id);
+    }
+
+    /** Returns the ID represented by a string. */
     @NonNull
     public String getStringId() {
         return mSessionId;
@@ -40,4 +49,17 @@
     public String toString() {
         return mSessionId;
     }
+
+    @Override
+    public boolean equals(@Nullable Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        LogSessionId that = (LogSessionId) o;
+        return Objects.equals(mSessionId, that.mSessionId);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mSessionId);
+    }
 }
diff --git a/media/java/android/media/metrics/PlaybackComponent.java b/media/java/android/media/metrics/PlaybackComponent.java
deleted file mode 100644
index 1cadf3b..0000000
--- a/media/java/android/media/metrics/PlaybackComponent.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (C) 2020 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;
-
-/**
- * Interface for playback related components used by playback metrics.
- */
-public interface PlaybackComponent {
-
-    /**
-     * Sets the playback ID of the component.
-     */
-    void setPlaybackId(@NonNull String playbackId);
-
-    /**
-     * Gets playback ID.
-     */
-    @NonNull String getPlaybackId();
-}