Merge "hdr: enable VP9 profile2 in SoftVPX"
diff --git a/drm/libmediadrm/CryptoHal.cpp b/drm/libmediadrm/CryptoHal.cpp
index b9b3685..2114d40 100644
--- a/drm/libmediadrm/CryptoHal.cpp
+++ b/drm/libmediadrm/CryptoHal.cpp
@@ -332,10 +332,13 @@
             return status;
         }
         secure = false;
-    } else {
+    } else if (destination.mType == kDestinationTypeNativeHandle) {
         hDestination.type = BufferType::NATIVE_HANDLE;
         hDestination.secureMemory = hidl_handle(destination.mHandle);
         secure = true;
+    } else {
+        android_errorWriteLog(0x534e4554, "70526702");
+        return UNKNOWN_ERROR;
     }
 
     ::SharedBuffer hSource;
diff --git a/drm/libmediadrm/ICrypto.cpp b/drm/libmediadrm/ICrypto.cpp
index 37dc83b..1d70a4e 100644
--- a/drm/libmediadrm/ICrypto.cpp
+++ b/drm/libmediadrm/ICrypto.cpp
@@ -369,6 +369,10 @@
                     android_errorWriteLog(0x534e4554, "71389378");
                     return OK;
                 }
+            } else {
+                reply->writeInt32(BAD_VALUE);
+                android_errorWriteLog(0x534e4554, "70526702");
+                return OK;
             }
 
             AString errorDetailMsg;
diff --git a/drm/libmediadrm/PluginMetricsReporting.cpp b/drm/libmediadrm/PluginMetricsReporting.cpp
index 877cbd4..cc7fb72 100644
--- a/drm/libmediadrm/PluginMetricsReporting.cpp
+++ b/drm/libmediadrm/PluginMetricsReporting.cpp
@@ -47,7 +47,7 @@
 
     // Report the package name.
     if (metricsGroup.has_app_package_name()) {
-      AString app_package_name(metricsGroup.app_package_name().c_str(),
+        std::string app_package_name(metricsGroup.app_package_name().c_str(),
                                metricsGroup.app_package_name().size());
       analyticsItem.setPkgName(app_package_name);
     }
diff --git a/media/extractors/aac/AACExtractor.cpp b/media/extractors/aac/AACExtractor.cpp
index 716fe31..dfb54e2 100644
--- a/media/extractors/aac/AACExtractor.cpp
+++ b/media/extractors/aac/AACExtractor.cpp
@@ -288,6 +288,10 @@
     if (options && options->getSeekTo(&seekTimeUs, &mode)) {
         if (mFrameDurationUs > 0) {
             int64_t seekFrame = seekTimeUs / mFrameDurationUs;
+            if (seekFrame < 0 || seekFrame >= (int64_t)mOffsetVector.size()) {
+                android_errorWriteLog(0x534e4554, "70239507");
+                return ERROR_MALFORMED;
+            }
             mCurrentTimeUs = seekFrame * mFrameDurationUs;
 
             mOffset = mOffsetVector.itemAt(seekFrame);
diff --git a/media/libaaudio/include/aaudio/AAudio.h b/media/libaaudio/include/aaudio/AAudio.h
index 3c23736..00c43dc 100644
--- a/media/libaaudio/include/aaudio/AAudio.h
+++ b/media/libaaudio/include/aaudio/AAudio.h
@@ -137,6 +137,149 @@
 };
 typedef int32_t aaudio_performance_mode_t;
 
+/**
+ * The USAGE attribute expresses "why" you are playing a sound, what is this sound used for.
+ * This information is used by certain platforms or routing policies
+ * to make more refined volume or routing decisions.
+ *
+ * Note that these match the equivalent values in AudioAttributes in the Android Java API.
+ */
+enum {
+    /**
+     * Use this for streaming media, music performance, video, podcasts, etcetera.
+     */
+    AAUDIO_USAGE_MEDIA = 1,
+
+    /**
+     * Use this for voice over IP, telephony, etcetera.
+     */
+    AAUDIO_USAGE_VOICE_COMMUNICATION = 2,
+
+    /**
+     * Use this for sounds associated with telephony such as busy tones, DTMF, etcetera.
+     */
+    AAUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING = 3,
+
+    /**
+     * Use this to demand the users attention.
+     */
+    AAUDIO_USAGE_ALARM = 4,
+
+    /**
+     * Use this for notifying the user when a message has arrived or some
+     * other background event has occured.
+     */
+    AAUDIO_USAGE_NOTIFICATION = 5,
+
+    /**
+     * Use this when the phone rings.
+     */
+    AAUDIO_USAGE_NOTIFICATION_RINGTONE = 6,
+
+    /**
+     * Use this to attract the users attention when, for example, the battery is low.
+     */
+    AAUDIO_USAGE_NOTIFICATION_EVENT = 10,
+
+    /**
+     * Use this for screen readers, etcetera.
+     */
+    AAUDIO_USAGE_ASSISTANCE_ACCESSIBILITY = 11,
+
+    /**
+     * Use this for driving or navigation directions.
+     */
+    AAUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE = 12,
+
+    /**
+     * Use this for user interface sounds, beeps, etcetera.
+     */
+    AAUDIO_USAGE_ASSISTANCE_SONIFICATION = 13,
+
+    /**
+     * Use this for game audio and sound effects.
+     */
+    AAUDIO_USAGE_GAME = 14,
+
+    /**
+     * Use this for audio responses to user queries, audio instructions or help utterances.
+     */
+    AAUDIO_USAGE_ASSISTANT = 16
+};
+typedef int32_t aaudio_usage_t;
+
+/**
+ * The CONTENT_TYPE attribute describes "what" you are playing.
+ * It expresses the general category of the content. This information is optional.
+ * But in case it is known (for instance {@link #AAUDIO_CONTENT_TYPE_MOVIE} for a
+ * movie streaming service or {@link #AAUDIO_CONTENT_TYPE_SPEECH} for
+ * an audio book application) this information might be used by the audio framework to
+ * enforce audio focus.
+ *
+ * Note that these match the equivalent values in AudioAttributes in the Android Java API.
+ */
+enum {
+
+    /**
+     * Use this for spoken voice, audio books, etcetera.
+     */
+    AAUDIO_CONTENT_TYPE_SPEECH = 1,
+
+    /**
+     * Use this for pre-recorded or live music.
+     */
+    AAUDIO_CONTENT_TYPE_MUSIC = 2,
+
+    /**
+     * Use this for a movie or video soundtrack.
+     */
+    AAUDIO_CONTENT_TYPE_MOVIE = 3,
+
+    /**
+     * Use this for sound is designed to accompany a user action,
+     * such as a click or beep sound made when the user presses a button.
+     */
+    AAUDIO_CONTENT_TYPE_SONIFICATION = 4
+};
+typedef int32_t aaudio_content_type_t;
+
+/**
+ * Defines the audio source.
+ * An audio source defines both a default physical source of audio signal, and a recording
+ * configuration.
+ *
+ * Note that these match the equivalent values in MediaRecorder.AudioSource in the Android Java API.
+ */
+enum {
+    /**
+     * Use this preset when other presets do not apply.
+     */
+    AAUDIO_INPUT_PRESET_GENERIC = 1,
+
+    /**
+     * Use this preset when recording video.
+     */
+    AAUDIO_INPUT_PRESET_CAMCORDER = 5,
+
+    /**
+     * Use this preset when doing speech recognition.
+     */
+    AAUDIO_INPUT_PRESET_VOICE_RECOGNITION = 6,
+
+    /**
+     * Use this preset when doing telephony or voice messaging.
+     */
+    AAUDIO_INPUT_PRESET_VOICE_COMMUNICATION = 7,
+
+    /**
+     * Use this preset to obtain an input with no effects.
+     * Note that this input will not have automatic gain control
+     * so the recorded volume may be very low.
+     */
+    AAUDIO_INPUT_PRESET_UNPROCESSED = 9,
+};
+typedef int32_t aaudio_input_preset_t;
+
 typedef struct AAudioStreamStruct         AAudioStream;
 typedef struct AAudioStreamBuilderStruct  AAudioStreamBuilder;
 
@@ -308,6 +451,52 @@
                                                 aaudio_performance_mode_t mode);
 
 /**
+ * Set the intended use case for the stream.
+ *
+ * The AAudio system will use this information to optimize the
+ * behavior of the stream.
+ * This could, for example, affect how volume and focus is handled for the stream.
+ *
+ * The default, if you do not call this function, is AAUDIO_USAGE_MEDIA.
+ *
+ * @param builder reference provided by AAudio_createStreamBuilder()
+ * @param usage the desired usage, eg. AAUDIO_USAGE_GAME
+ */
+AAUDIO_API void AAudioStreamBuilder_setUsage(AAudioStreamBuilder* builder,
+                                                       aaudio_usage_t usage);
+
+/**
+ * Set the type of audio data that the stream will carry.
+ *
+ * The AAudio system will use this information to optimize the
+ * behavior of the stream.
+ * This could, for example, affect whether a stream is paused when a notification occurs.
+ *
+ * The default, if you do not call this function, is AAUDIO_CONTENT_TYPE_MUSIC.
+ *
+ * @param builder reference provided by AAudio_createStreamBuilder()
+ * @param contentType the type of audio data, eg. AAUDIO_CONTENT_TYPE_SPEECH
+ */
+AAUDIO_API void AAudioStreamBuilder_setContentType(AAudioStreamBuilder* builder,
+                                             aaudio_content_type_t contentType);
+
+/**
+ * Set the input (capture) preset for the stream.
+ *
+ * The AAudio system will use this information to optimize the
+ * behavior of the stream.
+ * This could, for example, affect which microphones are used and how the
+ * recorded data is processed.
+ *
+ * The default, if you do not call this function, is AAUDIO_INPUT_PRESET_GENERIC.
+ *
+ * @param builder reference provided by AAudio_createStreamBuilder()
+ * @param inputPreset the desired configuration for recording
+ */
+AAUDIO_API void AAudioStreamBuilder_setInputPreset(AAudioStreamBuilder* builder,
+                                                   aaudio_input_preset_t inputPreset);
+
+/**
  * Return one of these values from the data callback function.
  */
 enum {
@@ -820,6 +1009,30 @@
                                       int64_t *framePosition,
                                       int64_t *timeNanoseconds);
 
+/**
+ * Return the use case for the stream.
+ *
+ * @param stream reference provided by AAudioStreamBuilder_openStream()
+ * @return frames read
+ */
+AAUDIO_API aaudio_usage_t AAudioStream_getUsage(AAudioStream* stream);
+
+/**
+ * Return the content type for the stream.
+ *
+ * @param stream reference provided by AAudioStreamBuilder_openStream()
+ * @return content type, for example AAUDIO_CONTENT_TYPE_MUSIC
+ */
+AAUDIO_API aaudio_content_type_t AAudioStream_getContentType(AAudioStream* stream);
+
+/**
+ * Return the input preset for the stream.
+ *
+ * @param stream reference provided by AAudioStreamBuilder_openStream()
+ * @return input preset, for example AAUDIO_INPUT_PRESET_CAMCORDER
+ */
+AAUDIO_API aaudio_input_preset_t AAudioStream_getInputPreset(AAudioStream* stream);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/media/libaaudio/libaaudio.map.txt b/media/libaaudio/libaaudio.map.txt
index 2ba5250..98fbb6f 100644
--- a/media/libaaudio/libaaudio.map.txt
+++ b/media/libaaudio/libaaudio.map.txt
@@ -17,6 +17,9 @@
     AAudioStreamBuilder_setSharingMode;
     AAudioStreamBuilder_setDirection;
     AAudioStreamBuilder_setBufferCapacityInFrames;
+    AAudioStreamBuilder_setUsage;       # introduced=28
+    AAudioStreamBuilder_setContentType; # introduced=28
+    AAudioStreamBuilder_setInputPreset; # introduced=28
     AAudioStreamBuilder_openStream;
     AAudioStreamBuilder_delete;
     AAudioStream_close;
@@ -42,6 +45,9 @@
     AAudioStream_getFormat;
     AAudioStream_getSharingMode;
     AAudioStream_getDirection;
+    AAudioStream_getUsage;       # introduced=28
+    AAudioStream_getContentType; # introduced=28
+    AAudioStream_getInputPreset; # introduced=28
     AAudioStream_getFramesWritten;
     AAudioStream_getFramesRead;
     AAudioStream_getTimestamp;
diff --git a/media/libaaudio/src/binding/AAudioStreamConfiguration.cpp b/media/libaaudio/src/binding/AAudioStreamConfiguration.cpp
index 153fce3..97672a0 100644
--- a/media/libaaudio/src/binding/AAudioStreamConfiguration.cpp
+++ b/media/libaaudio/src/binding/AAudioStreamConfiguration.cpp
@@ -50,6 +50,12 @@
     if (status != NO_ERROR) goto error;
     status = parcel->writeInt32(getBufferCapacity());
     if (status != NO_ERROR) goto error;
+    status = parcel->writeInt32((int32_t) getUsage());
+    if (status != NO_ERROR) goto error;
+    status = parcel->writeInt32((int32_t) getContentType());
+    if (status != NO_ERROR) goto error;
+    status = parcel->writeInt32((int32_t) getInputPreset());
+    if (status != NO_ERROR) goto error;
     return NO_ERROR;
 error:
     ALOGE("AAudioStreamConfiguration.writeToParcel(): write failed = %d", status);
@@ -69,16 +75,25 @@
     setSamplesPerFrame(value);
     status = parcel->readInt32(&value);
     if (status != NO_ERROR) goto error;
-    setSharingMode(value);
+    setSharingMode((aaudio_sharing_mode_t) value);
     status = parcel->readInt32(&value);
     if (status != NO_ERROR) goto error;
-    setFormat(value);
+    setFormat((aaudio_format_t) value);
     status = parcel->readInt32(&value);
     if (status != NO_ERROR) goto error;
     setDirection((aaudio_direction_t) value);
     status = parcel->readInt32(&value);
     if (status != NO_ERROR) goto error;
     setBufferCapacity(value);
+    status = parcel->readInt32(&value);
+    if (status != NO_ERROR) goto error;
+    setUsage((aaudio_usage_t) value);
+    status = parcel->readInt32(&value);
+    if (status != NO_ERROR) goto error;
+    setContentType((aaudio_content_type_t) value);
+    status = parcel->readInt32(&value);
+    if (status != NO_ERROR) goto error;
+    setInputPreset((aaudio_input_preset_t) value);
     return NO_ERROR;
 error:
     ALOGE("AAudioStreamConfiguration.readFromParcel(): read failed = %d", status);
diff --git a/media/libaaudio/src/client/AudioStreamInternal.cpp b/media/libaaudio/src/client/AudioStreamInternal.cpp
index 6d5a64f..5856ec3 100644
--- a/media/libaaudio/src/client/AudioStreamInternal.cpp
+++ b/media/libaaudio/src/client/AudioStreamInternal.cpp
@@ -112,6 +112,10 @@
     request.getConfiguration().setDirection(getDirection());
     request.getConfiguration().setSharingMode(getSharingMode());
 
+    request.getConfiguration().setUsage(getUsage());
+    request.getConfiguration().setContentType(getContentType());
+    request.getConfiguration().setInputPreset(getInputPreset());
+
     request.getConfiguration().setBufferCapacity(builder.getBufferCapacity());
 
     mServiceStreamHandle = mServiceInterface.openStream(request, configurationOutput);
@@ -131,6 +135,10 @@
     setDeviceId(configurationOutput.getDeviceId());
     setSharingMode(configurationOutput.getSharingMode());
 
+    setUsage(configurationOutput.getUsage());
+    setContentType(configurationOutput.getContentType());
+    setInputPreset(configurationOutput.getInputPreset());
+
     // Save device format so we can do format conversion and volume scaling together.
     mDeviceFormat = configurationOutput.getFormat();
 
diff --git a/media/libaaudio/src/core/AAudioAudio.cpp b/media/libaaudio/src/core/AAudioAudio.cpp
index bb007ac..9e5ca8e 100644
--- a/media/libaaudio/src/core/AAudioAudio.cpp
+++ b/media/libaaudio/src/core/AAudioAudio.cpp
@@ -177,6 +177,24 @@
     streamBuilder->setSharingMode(sharingMode);
 }
 
+AAUDIO_API void AAudioStreamBuilder_setUsage(AAudioStreamBuilder* builder,
+                                             aaudio_usage_t usage) {
+    AudioStreamBuilder *streamBuilder = convertAAudioBuilderToStreamBuilder(builder);
+    streamBuilder->setUsage(usage);
+}
+
+AAUDIO_API void AAudioStreamBuilder_setContentType(AAudioStreamBuilder* builder,
+                                                   aaudio_content_type_t contentType) {
+    AudioStreamBuilder *streamBuilder = convertAAudioBuilderToStreamBuilder(builder);
+    streamBuilder->setContentType(contentType);
+}
+
+AAUDIO_API void AAudioStreamBuilder_setInputPreset(AAudioStreamBuilder* builder,
+                                                   aaudio_input_preset_t inputPreset) {
+    AudioStreamBuilder *streamBuilder = convertAAudioBuilderToStreamBuilder(builder);
+    streamBuilder->setInputPreset(inputPreset);
+}
+
 AAUDIO_API void AAudioStreamBuilder_setBufferCapacityInFrames(AAudioStreamBuilder* builder,
                                                         int32_t frames)
 {
@@ -447,6 +465,24 @@
     return audioStream->getSharingMode();
 }
 
+AAUDIO_API aaudio_usage_t AAudioStream_getUsage(AAudioStream* stream)
+{
+    AudioStream *audioStream = convertAAudioStreamToAudioStream(stream);
+    return audioStream->getUsage();
+}
+
+AAUDIO_API aaudio_content_type_t AAudioStream_getContentType(AAudioStream* stream)
+{
+    AudioStream *audioStream = convertAAudioStreamToAudioStream(stream);
+    return audioStream->getContentType();
+}
+
+AAUDIO_API aaudio_input_preset_t AAudioStream_getInputPreset(AAudioStream* stream)
+{
+    AudioStream *audioStream = convertAAudioStreamToAudioStream(stream);
+    return audioStream->getInputPreset();
+}
+
 AAUDIO_API int64_t AAudioStream_getFramesWritten(AAudioStream* stream)
 {
     AudioStream *audioStream = convertAAudioStreamToAudioStream(stream);
diff --git a/media/libaaudio/src/core/AAudioStreamParameters.cpp b/media/libaaudio/src/core/AAudioStreamParameters.cpp
index 6400eb4..23c4eb8 100644
--- a/media/libaaudio/src/core/AAudioStreamParameters.cpp
+++ b/media/libaaudio/src/core/AAudioStreamParameters.cpp
@@ -42,6 +42,9 @@
     mAudioFormat     = other.mAudioFormat;
     mDirection       = other.mDirection;
     mBufferCapacity  = other.mBufferCapacity;
+    mUsage           = other.mUsage;
+    mContentType     = other.mContentType;
+    mInputPreset     = other.mInputPreset;
 }
 
 aaudio_result_t AAudioStreamParameters::validate() const {
@@ -98,6 +101,54 @@
             // break;
     }
 
+    switch (mUsage) {
+        case AAUDIO_UNSPECIFIED:
+        case AAUDIO_USAGE_MEDIA:
+        case AAUDIO_USAGE_VOICE_COMMUNICATION:
+        case AAUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING:
+        case AAUDIO_USAGE_ALARM:
+        case AAUDIO_USAGE_NOTIFICATION:
+        case AAUDIO_USAGE_NOTIFICATION_RINGTONE:
+        case AAUDIO_USAGE_NOTIFICATION_EVENT:
+        case AAUDIO_USAGE_ASSISTANCE_ACCESSIBILITY:
+        case AAUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE:
+        case AAUDIO_USAGE_ASSISTANCE_SONIFICATION:
+        case AAUDIO_USAGE_GAME:
+        case AAUDIO_USAGE_ASSISTANT:
+            break; // valid
+        default:
+            ALOGE("usage not valid = %d", mUsage);
+            return AAUDIO_ERROR_ILLEGAL_ARGUMENT;
+            // break;
+    }
+
+    switch (mContentType) {
+        case AAUDIO_UNSPECIFIED:
+        case AAUDIO_CONTENT_TYPE_MUSIC:
+        case AAUDIO_CONTENT_TYPE_MOVIE:
+        case AAUDIO_CONTENT_TYPE_SONIFICATION:
+        case AAUDIO_CONTENT_TYPE_SPEECH:
+            break; // valid
+        default:
+            ALOGE("content type not valid = %d", mContentType);
+            return AAUDIO_ERROR_ILLEGAL_ARGUMENT;
+            // break;
+    }
+
+    switch (mInputPreset) {
+        case AAUDIO_UNSPECIFIED:
+        case AAUDIO_INPUT_PRESET_GENERIC:
+        case AAUDIO_INPUT_PRESET_CAMCORDER:
+        case AAUDIO_INPUT_PRESET_VOICE_COMMUNICATION:
+        case AAUDIO_INPUT_PRESET_VOICE_RECOGNITION:
+        case AAUDIO_INPUT_PRESET_UNPROCESSED:
+            break; // valid
+        default:
+            ALOGE("input preset not valid = %d", mInputPreset);
+            return AAUDIO_ERROR_ILLEGAL_ARGUMENT;
+            // break;
+    }
+
     return AAUDIO_OK;
 }
 
@@ -109,5 +160,8 @@
     ALOGD("mAudioFormat     = %6d", (int)mAudioFormat);
     ALOGD("mDirection       = %6d", mDirection);
     ALOGD("mBufferCapacity  = %6d", mBufferCapacity);
+    ALOGD("mUsage           = %6d", mUsage);
+    ALOGD("mContentType     = %6d", mContentType);
+    ALOGD("mInputPreset     = %6d", mInputPreset);
 }
 
diff --git a/media/libaaudio/src/core/AAudioStreamParameters.h b/media/libaaudio/src/core/AAudioStreamParameters.h
index 5e67c93..0c173f5 100644
--- a/media/libaaudio/src/core/AAudioStreamParameters.h
+++ b/media/libaaudio/src/core/AAudioStreamParameters.h
@@ -88,6 +88,30 @@
         mDirection = direction;
     }
 
+    aaudio_usage_t getUsage() const {
+        return mUsage;
+    }
+
+    void setUsage(aaudio_usage_t usage) {
+        mUsage = usage;
+    }
+
+    aaudio_content_type_t getContentType() const {
+        return mContentType;
+    }
+
+    void setContentType(aaudio_content_type_t contentType) {
+        mContentType = contentType;
+    }
+
+    aaudio_input_preset_t getInputPreset() const {
+        return mInputPreset;
+    }
+
+    void setInputPreset(aaudio_input_preset_t inputPreset) {
+        mInputPreset = inputPreset;
+    }
+
     int32_t calculateBytesPerFrame() const {
         return getSamplesPerFrame() * AAudioConvert_formatToSizeInBytes(getFormat());
     }
@@ -109,6 +133,9 @@
     aaudio_sharing_mode_t      mSharingMode     = AAUDIO_SHARING_MODE_SHARED;
     aaudio_format_t            mAudioFormat     = AAUDIO_FORMAT_UNSPECIFIED;
     aaudio_direction_t         mDirection       = AAUDIO_DIRECTION_OUTPUT;
+    aaudio_usage_t             mUsage           = AAUDIO_UNSPECIFIED;
+    aaudio_content_type_t      mContentType     = AAUDIO_UNSPECIFIED;
+    aaudio_input_preset_t      mInputPreset     = AAUDIO_UNSPECIFIED;
     int32_t                    mBufferCapacity  = AAUDIO_UNSPECIFIED;
 };
 
diff --git a/media/libaaudio/src/core/AudioStream.cpp b/media/libaaudio/src/core/AudioStream.cpp
index 8f5f5d3..1b2ca39 100644
--- a/media/libaaudio/src/core/AudioStream.cpp
+++ b/media/libaaudio/src/core/AudioStream.cpp
@@ -74,15 +74,28 @@
     }
 
     // Copy parameters from the Builder because the Builder may be deleted after this call.
+    // TODO AudioStream should be a subclass of AudioStreamParameters
     mSamplesPerFrame = builder.getSamplesPerFrame();
     mSampleRate = builder.getSampleRate();
     mDeviceId = builder.getDeviceId();
     mFormat = builder.getFormat();
     mSharingMode = builder.getSharingMode();
     mSharingModeMatchRequired = builder.isSharingModeMatchRequired();
-
     mPerformanceMode = builder.getPerformanceMode();
 
+    mUsage = builder.getUsage();
+    if (mUsage == AAUDIO_UNSPECIFIED) {
+        mUsage = AAUDIO_USAGE_MEDIA;
+    }
+    mContentType = builder.getContentType();
+    if (mContentType == AAUDIO_UNSPECIFIED) {
+        mContentType = AAUDIO_CONTENT_TYPE_MUSIC;
+    }
+    mInputPreset = builder.getInputPreset();
+    if (mInputPreset == AAUDIO_UNSPECIFIED) {
+        mInputPreset = AAUDIO_INPUT_PRESET_GENERIC;
+    }
+
     // callbacks
     mFramesPerDataCallback = builder.getFramesPerDataCallback();
     mDataCallbackProc = builder.getDataCallbackProc();
@@ -99,6 +112,8 @@
           mDeviceId, mPerformanceMode,
           (isDataCallbackSet() ? "ON" : "OFF"),
           mFramesPerDataCallback);
+    ALOGI("open() usage = %d, contentType = %d, inputPreset = %d",
+          mUsage, mContentType, mInputPreset);
 
     return AAUDIO_OK;
 }
@@ -221,6 +236,17 @@
     if (err != 0) {
         return AAudioConvert_androidToAAudioResult(-errno);
     } else {
+        // Name the thread with an increasing index, "AAudio_#", for debugging.
+        static std::atomic<uint32_t> nextThreadIndex{1};
+        char name[16]; // max length for a pthread_name
+        uint32_t index = nextThreadIndex++;
+        // Wrap the index so that we do not hit the 16 char limit
+        // and to avoid hard-to-read large numbers.
+        index = index % 100000;  // arbitrary
+        snprintf(name, sizeof(name), "AAudio_%u", index);
+        err = pthread_setname_np(mThread, name);
+        ALOGW_IF((err != 0), "Could not set name of AAudio thread. err = %d", err);
+
         mHasThread = true;
         return AAUDIO_OK;
     }
diff --git a/media/libaaudio/src/core/AudioStream.h b/media/libaaudio/src/core/AudioStream.h
index b5d7fd5..21fa595 100644
--- a/media/libaaudio/src/core/AudioStream.h
+++ b/media/libaaudio/src/core/AudioStream.h
@@ -204,6 +204,18 @@
 
     virtual aaudio_direction_t getDirection() const = 0;
 
+    aaudio_usage_t getUsage() const {
+        return mUsage;
+    }
+
+    aaudio_content_type_t getContentType() const {
+        return mContentType;
+    }
+
+    aaudio_input_preset_t getInputPreset() const {
+        return mInputPreset;
+    }
+
     /**
      * This is only valid after setSamplesPerFrame() and setFormat() have been called.
      */
@@ -408,6 +420,7 @@
 
     /**
      * This should not be called after the open() call.
+     * TODO for multiple setters: assert(mState == AAUDIO_STREAM_STATE_UNINITIALIZED)
      */
     void setSampleRate(int32_t sampleRate) {
         mSampleRate = sampleRate;
@@ -456,6 +469,27 @@
         return mPeriodNanoseconds.load(std::memory_order_acquire);
     }
 
+    /**
+     * This should not be called after the open() call.
+     */
+    void setUsage(aaudio_usage_t usage) {
+        mUsage = usage;
+    }
+
+    /**
+     * This should not be called after the open() call.
+     */
+    void setContentType(aaudio_content_type_t contentType) {
+        mContentType = contentType;
+    }
+
+    /**
+     * This should not be called after the open() call.
+     */
+    void setInputPreset(aaudio_input_preset_t inputPreset) {
+        mInputPreset = inputPreset;
+    }
+
 private:
 
     std::mutex                 mStreamLock;
@@ -471,6 +505,9 @@
     aaudio_format_t             mFormat = AAUDIO_FORMAT_UNSPECIFIED;
     aaudio_stream_state_t       mState = AAUDIO_STREAM_STATE_UNINITIALIZED;
     aaudio_performance_mode_t   mPerformanceMode = AAUDIO_PERFORMANCE_MODE_NONE;
+    aaudio_usage_t              mUsage           = AAUDIO_USAGE_MEDIA;
+    aaudio_content_type_t       mContentType     = AAUDIO_CONTENT_TYPE_MUSIC;
+    aaudio_input_preset_t       mInputPreset     = AAUDIO_INPUT_PRESET_GENERIC;
 
     // callback ----------------------------------
 
diff --git a/media/libaaudio/src/legacy/AudioStreamRecord.cpp b/media/libaaudio/src/legacy/AudioStreamRecord.cpp
index 55eed92..5f4ab9b 100644
--- a/media/libaaudio/src/legacy/AudioStreamRecord.cpp
+++ b/media/libaaudio/src/legacy/AudioStreamRecord.cpp
@@ -104,11 +104,24 @@
                                            ? AUDIO_PORT_HANDLE_NONE
                                            : getDeviceId();
 
+    const audio_content_type_t contentType =
+            AAudioConvert_contentTypeToInternal(builder.getContentType());
+    const audio_source_t source =
+            AAudioConvert_inputPresetToAudioSource(builder.getInputPreset());
+
+    const audio_attributes_t attributes = {
+            .content_type = contentType,
+            .usage = AUDIO_USAGE_UNKNOWN, // only used for output
+            .source = source,
+            .flags = flags, // If attributes are set then the other flags parameter is ignored.
+            .tags = ""
+    };
+
     mAudioRecord = new AudioRecord(
             mOpPackageName // const String16& opPackageName TODO does not compile
             );
     mAudioRecord->set(
-            AUDIO_SOURCE_VOICE_RECOGNITION,
+            AUDIO_SOURCE_DEFAULT, // ignored because we pass attributes below
             getSampleRate(),
             format,
             channelMask,
@@ -122,7 +135,7 @@
             flags,
             AUDIO_UID_INVALID, // DEFAULT uid
             -1,                // DEFAULT pid
-            NULL,              // DEFAULT audio_attributes_t
+            &attributes,
             selectedDeviceId
             );
 
diff --git a/media/libaaudio/src/legacy/AudioStreamTrack.cpp b/media/libaaudio/src/legacy/AudioStreamTrack.cpp
index 5113278..17a8d52 100644
--- a/media/libaaudio/src/legacy/AudioStreamTrack.cpp
+++ b/media/libaaudio/src/legacy/AudioStreamTrack.cpp
@@ -121,9 +121,22 @@
                                            ? AUDIO_PORT_HANDLE_NONE
                                            : getDeviceId();
 
+    const audio_content_type_t contentType =
+            AAudioConvert_contentTypeToInternal(builder.getContentType());
+    const audio_usage_t usage =
+            AAudioConvert_usageToInternal(builder.getUsage());
+
+    const audio_attributes_t attributes = {
+            .content_type = contentType,
+            .usage = usage,
+            .source = AUDIO_SOURCE_DEFAULT, // only used for recording
+            .flags = flags, // If attributes are set then the other flags parameter is ignored.
+            .tags = ""
+    };
+
     mAudioTrack = new AudioTrack();
     mAudioTrack->set(
-            (audio_stream_type_t) AUDIO_STREAM_MUSIC,
+            AUDIO_STREAM_DEFAULT,  // ignored because we pass attributes below
             getSampleRate(),
             format,
             channelMask,
@@ -139,7 +152,7 @@
             NULL,    // DEFAULT audio_offload_info_t
             AUDIO_UID_INVALID, // DEFAULT uid
             -1,      // DEFAULT pid
-            NULL,    // DEFAULT audio_attributes_t
+            &attributes,
             // WARNING - If doNotReconnect set true then audio stops after plugging and unplugging
             // headphones a few times.
             false,   // DEFAULT doNotReconnect,
diff --git a/media/libaaudio/src/utility/AAudioUtilities.cpp b/media/libaaudio/src/utility/AAudioUtilities.cpp
index f709f41..c6adf33 100644
--- a/media/libaaudio/src/utility/AAudioUtilities.cpp
+++ b/media/libaaudio/src/utility/AAudioUtilities.cpp
@@ -26,6 +26,7 @@
 #include "aaudio/AAudio.h"
 #include <aaudio/AAudioTesting.h>
 #include <math.h>
+#include <system/audio-base.h>
 
 #include "utility/AAudioUtilities.h"
 
@@ -283,6 +284,61 @@
     return aaudioFormat;
 }
 
+// Make a message string from the condition.
+#define STATIC_ASSERT(condition) static_assert(condition, #condition)
+
+audio_usage_t AAudioConvert_usageToInternal(aaudio_usage_t usage) {
+    // The public aaudio_content_type_t constants are supposed to have the same
+    // values as the internal audio_content_type_t values.
+    STATIC_ASSERT(AAUDIO_USAGE_MEDIA == AUDIO_USAGE_MEDIA);
+    STATIC_ASSERT(AAUDIO_USAGE_VOICE_COMMUNICATION == AUDIO_USAGE_VOICE_COMMUNICATION);
+    STATIC_ASSERT(AAUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING
+                  == AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING);
+    STATIC_ASSERT(AAUDIO_USAGE_ALARM == AUDIO_USAGE_ALARM);
+    STATIC_ASSERT(AAUDIO_USAGE_NOTIFICATION == AUDIO_USAGE_NOTIFICATION);
+    STATIC_ASSERT(AAUDIO_USAGE_NOTIFICATION_RINGTONE
+                  == AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE);
+    STATIC_ASSERT(AAUDIO_USAGE_NOTIFICATION_EVENT == AUDIO_USAGE_NOTIFICATION_EVENT);
+    STATIC_ASSERT(AAUDIO_USAGE_ASSISTANCE_ACCESSIBILITY == AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY);
+    STATIC_ASSERT(AAUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE
+                  == AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE);
+    STATIC_ASSERT(AAUDIO_USAGE_ASSISTANCE_SONIFICATION == AUDIO_USAGE_ASSISTANCE_SONIFICATION);
+    STATIC_ASSERT(AAUDIO_USAGE_GAME == AUDIO_USAGE_GAME);
+    STATIC_ASSERT(AAUDIO_USAGE_ASSISTANT == AUDIO_USAGE_ASSISTANT);
+    if (usage == AAUDIO_UNSPECIFIED) {
+        usage = AAUDIO_USAGE_MEDIA;
+    }
+    return (audio_usage_t) usage; // same value
+}
+
+audio_content_type_t AAudioConvert_contentTypeToInternal(aaudio_content_type_t contentType) {
+    // The public aaudio_content_type_t constants are supposed to have the same
+    // values as the internal audio_content_type_t values.
+    STATIC_ASSERT(AAUDIO_CONTENT_TYPE_MUSIC == AUDIO_CONTENT_TYPE_MUSIC);
+    STATIC_ASSERT(AAUDIO_CONTENT_TYPE_SPEECH == AUDIO_CONTENT_TYPE_SPEECH);
+    STATIC_ASSERT(AAUDIO_CONTENT_TYPE_SONIFICATION == AUDIO_CONTENT_TYPE_SONIFICATION);
+    STATIC_ASSERT(AAUDIO_CONTENT_TYPE_MOVIE == AUDIO_CONTENT_TYPE_MOVIE);
+    if (contentType == AAUDIO_UNSPECIFIED) {
+        contentType = AAUDIO_CONTENT_TYPE_MUSIC;
+    }
+    return (audio_content_type_t) contentType; // same value
+}
+
+audio_source_t AAudioConvert_inputPresetToAudioSource(aaudio_input_preset_t preset) {
+    // The public aaudio_input_preset_t constants are supposed to have the same
+    // values as the internal audio_source_t values.
+    STATIC_ASSERT(AAUDIO_UNSPECIFIED == AUDIO_SOURCE_DEFAULT);
+    STATIC_ASSERT(AAUDIO_INPUT_PRESET_GENERIC == AUDIO_SOURCE_MIC);
+    STATIC_ASSERT(AAUDIO_INPUT_PRESET_CAMCORDER == AUDIO_SOURCE_CAMCORDER);
+    STATIC_ASSERT(AAUDIO_INPUT_PRESET_VOICE_RECOGNITION == AUDIO_SOURCE_VOICE_RECOGNITION);
+    STATIC_ASSERT(AAUDIO_INPUT_PRESET_VOICE_COMMUNICATION == AUDIO_SOURCE_VOICE_COMMUNICATION);
+    STATIC_ASSERT(AAUDIO_INPUT_PRESET_UNPROCESSED == AUDIO_SOURCE_UNPROCESSED);
+    if (preset == AAUDIO_UNSPECIFIED) {
+        preset = AAUDIO_INPUT_PRESET_GENERIC;
+    }
+    return (audio_source_t) preset; // same value
+}
+
 int32_t AAudioConvert_framesToBytes(int32_t numFrames,
                                             int32_t bytesPerFrame,
                                             int32_t *sizeInBytes) {
diff --git a/media/libaaudio/src/utility/AAudioUtilities.h b/media/libaaudio/src/utility/AAudioUtilities.h
index 3afa976..f2347f5 100644
--- a/media/libaaudio/src/utility/AAudioUtilities.h
+++ b/media/libaaudio/src/utility/AAudioUtilities.h
@@ -167,6 +167,29 @@
 
 aaudio_format_t AAudioConvert_androidToAAudioDataFormat(audio_format_t format);
 
+
+/**
+ * Note that this function does not validate the passed in value.
+ * That is done somewhere else.
+ * @return internal value
+ */
+
+audio_usage_t AAudioConvert_usageToInternal(aaudio_usage_t usage);
+
+/**
+ * Note that this function does not validate the passed in value.
+ * That is done somewhere else.
+ * @return internal value
+ */
+audio_content_type_t AAudioConvert_contentTypeToInternal(aaudio_content_type_t contentType);
+
+/**
+ * Note that this function does not validate the passed in value.
+ * That is done somewhere else.
+ * @return internal audio source
+ */
+audio_source_t AAudioConvert_inputPresetToAudioSource(aaudio_input_preset_t preset);
+
 /**
  * @return the size of a sample of the given format in bytes or AAUDIO_ERROR_ILLEGAL_ARGUMENT
  */
diff --git a/media/libaaudio/tests/Android.bp b/media/libaaudio/tests/Android.bp
index 9f80695..33718fc 100644
--- a/media/libaaudio/tests/Android.bp
+++ b/media/libaaudio/tests/Android.bp
@@ -124,3 +124,15 @@
         "libutils",
     ],
 }
+
+cc_test {
+    name: "test_attributes",
+    defaults: ["libaaudio_tests_defaults"],
+    srcs: ["test_attributes.cpp"],
+    shared_libs: [
+        "libaaudio",
+        "libbinder",
+        "libcutils",
+        "libutils",
+    ],
+}
diff --git a/media/libaaudio/tests/test_attributes.cpp b/media/libaaudio/tests/test_attributes.cpp
new file mode 100644
index 0000000..9cbf113
--- /dev/null
+++ b/media/libaaudio/tests/test_attributes.cpp
@@ -0,0 +1,179 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+// Test AAudio attributes such as Usage, ContentType and InputPreset.
+
+#include <stdio.h>
+#include <unistd.h>
+
+#include <aaudio/AAudio.h>
+#include <gtest/gtest.h>
+
+constexpr int64_t kNanosPerSecond = 1000000000;
+constexpr int kNumFrames = 256;
+constexpr int kChannelCount = 2;
+
+constexpr int32_t DONT_SET = -1000;
+
+static void checkAttributes(aaudio_performance_mode_t perfMode,
+                            aaudio_usage_t usage,
+                            aaudio_content_type_t contentType,
+                            aaudio_input_preset_t preset = DONT_SET,
+                            aaudio_direction_t direction = AAUDIO_DIRECTION_OUTPUT) {
+
+    float *buffer = new float[kNumFrames * kChannelCount];
+
+    AAudioStreamBuilder *aaudioBuilder = nullptr;
+    AAudioStream *aaudioStream = nullptr;
+
+    // Use an AAudioStreamBuilder to contain requested parameters.
+    ASSERT_EQ(AAUDIO_OK, AAudio_createStreamBuilder(&aaudioBuilder));
+
+    // Request stream properties.
+    AAudioStreamBuilder_setPerformanceMode(aaudioBuilder, perfMode);
+    AAudioStreamBuilder_setDirection(aaudioBuilder, direction);
+
+    // Set the attribute in the builder.
+    if (usage != DONT_SET) {
+        AAudioStreamBuilder_setUsage(aaudioBuilder, usage);
+    }
+    if (contentType != DONT_SET) {
+        AAudioStreamBuilder_setContentType(aaudioBuilder, contentType);
+    }
+    if (preset != DONT_SET) {
+        AAudioStreamBuilder_setInputPreset(aaudioBuilder, preset);
+    }
+
+    // Create an AAudioStream using the Builder.
+    ASSERT_EQ(AAUDIO_OK, AAudioStreamBuilder_openStream(aaudioBuilder, &aaudioStream));
+    AAudioStreamBuilder_delete(aaudioBuilder);
+
+    // Make sure we get the same attributes back from the stream.
+    aaudio_usage_t expectedUsage =
+            (usage == DONT_SET || usage == AAUDIO_UNSPECIFIED)
+            ? AAUDIO_USAGE_MEDIA // default
+            : usage;
+    EXPECT_EQ(expectedUsage, AAudioStream_getUsage(aaudioStream));
+
+    aaudio_content_type_t expectedContentType =
+            (contentType == DONT_SET || contentType == AAUDIO_UNSPECIFIED)
+            ? AAUDIO_CONTENT_TYPE_MUSIC // default
+            : contentType;
+    EXPECT_EQ(expectedContentType, AAudioStream_getContentType(aaudioStream));
+
+    aaudio_input_preset_t expectedPreset =
+            (preset == DONT_SET || preset == AAUDIO_UNSPECIFIED)
+            ? AAUDIO_INPUT_PRESET_GENERIC // default
+            : preset;
+    EXPECT_EQ(expectedPreset, AAudioStream_getInputPreset(aaudioStream));
+
+    EXPECT_EQ(AAUDIO_OK, AAudioStream_requestStart(aaudioStream));
+
+    if (direction == AAUDIO_DIRECTION_INPUT) {
+        EXPECT_EQ(kNumFrames,
+                  AAudioStream_read(aaudioStream, buffer, kNumFrames, kNanosPerSecond));
+    } else {
+        EXPECT_EQ(kNumFrames,
+                  AAudioStream_write(aaudioStream, buffer, kNumFrames, kNanosPerSecond));
+    }
+
+    EXPECT_EQ(AAUDIO_OK, AAudioStream_requestStop(aaudioStream));
+
+    EXPECT_EQ(AAUDIO_OK, AAudioStream_close(aaudioStream));
+    delete[] buffer;
+}
+
+static const aaudio_usage_t sUsages[] = {
+    DONT_SET,
+    AAUDIO_UNSPECIFIED,
+    AAUDIO_USAGE_MEDIA,
+    AAUDIO_USAGE_VOICE_COMMUNICATION,
+    AAUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING,
+    AAUDIO_USAGE_ALARM,
+    AAUDIO_USAGE_NOTIFICATION,
+    AAUDIO_USAGE_NOTIFICATION_RINGTONE,
+    AAUDIO_USAGE_NOTIFICATION_EVENT,
+    AAUDIO_USAGE_ASSISTANCE_ACCESSIBILITY,
+    AAUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE,
+    AAUDIO_USAGE_ASSISTANCE_SONIFICATION,
+    AAUDIO_USAGE_GAME,
+    AAUDIO_USAGE_ASSISTANT
+};
+
+static const aaudio_content_type_t sContentypes[] = {
+    DONT_SET,
+    AAUDIO_UNSPECIFIED,
+    AAUDIO_CONTENT_TYPE_SPEECH,
+    AAUDIO_CONTENT_TYPE_MUSIC,
+    AAUDIO_CONTENT_TYPE_MOVIE,
+    AAUDIO_CONTENT_TYPE_SONIFICATION
+};
+
+static const aaudio_input_preset_t sInputPresets[] = {
+    DONT_SET,
+    AAUDIO_UNSPECIFIED,
+    AAUDIO_INPUT_PRESET_GENERIC,
+    AAUDIO_INPUT_PRESET_CAMCORDER,
+    AAUDIO_INPUT_PRESET_VOICE_RECOGNITION,
+    AAUDIO_INPUT_PRESET_VOICE_COMMUNICATION,
+    AAUDIO_INPUT_PRESET_UNPROCESSED,
+};
+
+static void checkAttributesUsage(aaudio_performance_mode_t perfMode) {
+    for (aaudio_usage_t usage : sUsages) {
+        checkAttributes(perfMode, usage, DONT_SET);
+    }
+}
+
+static void checkAttributesContentType(aaudio_input_preset_t perfMode) {
+    for (aaudio_content_type_t contentType : sContentypes) {
+        checkAttributes(perfMode, DONT_SET, contentType);
+    }
+}
+
+static void checkAttributesInputPreset(aaudio_performance_mode_t perfMode) {
+    for (aaudio_input_preset_t inputPreset : sInputPresets) {
+        checkAttributes(perfMode,
+                        DONT_SET,
+                        DONT_SET,
+                        inputPreset,
+                        AAUDIO_DIRECTION_INPUT);
+    }
+}
+
+TEST(test_attributes, aaudio_usage_perfnone) {
+    checkAttributesUsage(AAUDIO_PERFORMANCE_MODE_NONE);
+}
+
+TEST(test_attributes, aaudio_content_type_perfnone) {
+    checkAttributesContentType(AAUDIO_PERFORMANCE_MODE_NONE);
+}
+
+TEST(test_attributes, aaudio_input_preset_perfnone) {
+    checkAttributesInputPreset(AAUDIO_PERFORMANCE_MODE_NONE);
+}
+
+TEST(test_attributes, aaudio_usage_lowlat) {
+    checkAttributesUsage(AAUDIO_PERFORMANCE_MODE_LOW_LATENCY);
+}
+
+TEST(test_attributes, aaudio_content_type_lowlat) {
+    checkAttributesContentType(AAUDIO_PERFORMANCE_MODE_LOW_LATENCY);
+}
+
+TEST(test_attributes, aaudio_input_preset_lowlat) {
+    checkAttributesInputPreset(AAUDIO_PERFORMANCE_MODE_LOW_LATENCY);
+}
diff --git a/media/libaudioclient/Android.bp b/media/libaudioclient/Android.bp
index 94253a4..2df37a8 100644
--- a/media/libaudioclient/Android.bp
+++ b/media/libaudioclient/Android.bp
@@ -49,7 +49,6 @@
         "libaudiomanager",
         "libmedia_helper",
         "libmediametrics",
-        "libstagefright_foundation",
     ],
     export_shared_lib_headers: ["libbinder"],
 
diff --git a/media/libaudioclient/AudioRecord.cpp b/media/libaudioclient/AudioRecord.cpp
index 0d4b462..bc294c5 100644
--- a/media/libaudioclient/AudioRecord.cpp
+++ b/media/libaudioclient/AudioRecord.cpp
@@ -26,6 +26,8 @@
 #include <utils/Log.h>
 #include <private/media/AudioTrackShared.h>
 #include <media/IAudioFlinger.h>
+#include <media/MediaAnalyticsItem.h>
+#include <media/TypeConverter.h>
 
 #define WAIT_PERIOD_MS          10
 
@@ -65,6 +67,34 @@
 
 // ---------------------------------------------------------------------------
 
+static std::string audioFormatTypeString(audio_format_t value) {
+    std::string formatType;
+    if (FormatConverter::toString(value, formatType)) {
+        return formatType;
+    }
+    char rawbuffer[16];  // room for "%d"
+    snprintf(rawbuffer, sizeof(rawbuffer), "%d", value);
+    return rawbuffer;
+}
+
+void AudioRecord::MediaMetrics::gather(const AudioRecord *record)
+{
+    // key for media statistics is defined in the header
+    // attrs for media statistics
+    static constexpr char kAudioRecordChannelCount[] = "android.media.audiorecord.channels";
+    static constexpr char kAudioRecordFormat[] = "android.media.audiorecord.format";
+    static constexpr char kAudioRecordLatency[] = "android.media.audiorecord.latency";
+    static constexpr char kAudioRecordSampleRate[] = "android.media.audiorecord.samplerate";
+
+    // constructor guarantees mAnalyticsItem is valid
+
+    mAnalyticsItem->setInt32(kAudioRecordLatency, record->mLatency);
+    mAnalyticsItem->setInt32(kAudioRecordSampleRate, record->mSampleRate);
+    mAnalyticsItem->setInt32(kAudioRecordChannelCount, record->mChannelCount);
+    mAnalyticsItem->setCString(kAudioRecordFormat,
+                               audioFormatTypeString(record->mFormat).c_str());
+}
+
 AudioRecord::AudioRecord(const String16 &opPackageName)
     : mActive(false), mStatus(NO_INIT), mOpPackageName(opPackageName),
       mSessionId(AUDIO_SESSION_ALLOCATE),
@@ -105,6 +135,8 @@
 
 AudioRecord::~AudioRecord()
 {
+    mMediaMetrics.gather(this);
+
     if (mStatus == NO_ERROR) {
         // Make sure that callback function exits in the case where
         // it is looping on buffer empty condition in obtainBuffer().
diff --git a/media/libaudioclient/AudioTrack.cpp b/media/libaudioclient/AudioTrack.cpp
index 7670982..a3c66fe 100644
--- a/media/libaudioclient/AudioTrack.cpp
+++ b/media/libaudioclient/AudioTrack.cpp
@@ -189,16 +189,22 @@
     static constexpr char kAudioTrackUsage[] = "android.media.audiotrack.usage";
     static constexpr char kAudioTrackSampleRate[] = "android.media.audiotrack.samplerate";
     static constexpr char kAudioTrackChannelMask[] = "android.media.audiotrack.channelmask";
+#if 0
+    // XXX: disabled temporarily for b/72027185
     static constexpr char kAudioTrackUnderrunFrames[] = "android.media.audiotrack.underrunframes";
+#endif
     static constexpr char kAudioTrackStartupGlitch[] = "android.media.audiotrack.glitch.startup";
 
     // constructor guarantees mAnalyticsItem is valid
 
+#if 0
+    // XXX: disabled temporarily for b/72027185
     // must gather underrun info before cleaning mProxy information.
     const int32_t underrunFrames = track->getUnderrunFrames();
     if (underrunFrames != 0) {
         mAnalyticsItem->setInt32(kAudioTrackUnderrunFrames, underrunFrames);
     }
+#endif
 
     if (track->mTimestampStartupGlitchReported) {
         mAnalyticsItem->setInt32(kAudioTrackStartupGlitch, 1);
diff --git a/media/libaudioclient/include/media/AudioRecord.h b/media/libaudioclient/include/media/AudioRecord.h
index 074e547..fea973a 100644
--- a/media/libaudioclient/include/media/AudioRecord.h
+++ b/media/libaudioclient/include/media/AudioRecord.h
@@ -21,6 +21,7 @@
 #include <cutils/sched_policy.h>
 #include <media/AudioSystem.h>
 #include <media/AudioTimestamp.h>
+#include <media/MediaAnalyticsItem.h>
 #include <media/Modulo.h>
 #include <utils/RefBase.h>
 #include <utils/threads.h>
@@ -688,6 +689,24 @@
                                               // activity and connected devices
     wp<AudioSystem::AudioDeviceCallback> mDeviceCallback;
 
+private:
+    class MediaMetrics {
+      public:
+        MediaMetrics() : mAnalyticsItem(new MediaAnalyticsItem("audiorecord")) {
+        }
+        ~MediaMetrics() {
+            // mAnalyticsItem alloc failure will be flagged in the constructor
+            // don't log empty records
+            if (mAnalyticsItem->count() > 0) {
+                mAnalyticsItem->setFinalized(true);
+                mAnalyticsItem->selfrecord();
+            }
+        }
+        void gather(const AudioRecord *record);
+      private:
+        std::unique_ptr<MediaAnalyticsItem> mAnalyticsItem;
+    };
+    MediaMetrics mMediaMetrics;
 };
 
 }; // namespace android
diff --git a/media/libmedia/Android.bp b/media/libmedia/Android.bp
index 0b4fd25..e7dc0fe 100644
--- a/media/libmedia/Android.bp
+++ b/media/libmedia/Android.bp
@@ -139,10 +139,18 @@
     },
 }
 
+filegroup {
+    name: "mediaupdateservice_aidl",
+    srcs: [
+        "aidl/android/media/IMediaExtractorUpdateService.aidl",
+    ],
+}
+
 cc_library_shared {
     name: "libmedia",
 
     srcs: [
+        ":mediaupdateservice_aidl",
         "IDataSource.cpp",
         "BufferingSettings.cpp",
         "mediaplayer.cpp",
@@ -179,6 +187,11 @@
         "StringArray.cpp",
     ],
 
+    aidl: {
+        local_include_dirs: ["aidl"],
+        export_aidl_headers: true,
+    },
+
     shared_libs: [
         "liblog",
         "libcutils",
@@ -306,6 +319,7 @@
 
     srcs: [
         "AudioParameter.cpp",
+        "JAudioTrack.cpp",
         "MediaPlayer2Factory.cpp",
         "MediaPlayer2Manager.cpp",
         "TestPlayerStub.cpp",
@@ -314,6 +328,7 @@
     ],
 
     shared_libs: [
+        "libandroid_runtime",
         "libaudioclient",
         "libbinder",
         "libcutils",
diff --git a/media/libmedia/JAudioTrack.cpp b/media/libmedia/JAudioTrack.cpp
new file mode 100644
index 0000000..b228d8b
--- /dev/null
+++ b/media/libmedia/JAudioTrack.cpp
@@ -0,0 +1,520 @@
+/*
+ * Copyright 2018 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.
+ */
+
+#define LOG_TAG "JAudioTrack"
+
+#include "media/JAudioAttributes.h"
+#include "media/JAudioFormat.h"
+#include "media/JAudioTrack.h"
+
+#include <android_media_AudioErrors.h>
+#include <android_runtime/AndroidRuntime.h>
+
+namespace android {
+
+// TODO: Store Java class/methodID as a member variable in the class.
+// TODO: Add NULL && Exception checks after every JNI call.
+JAudioTrack::JAudioTrack(                             // < Usages of the arguments are below >
+        audio_stream_type_t streamType,               // AudioAudioAttributes
+        uint32_t sampleRate,                          // AudioFormat && bufferSizeInBytes
+        audio_format_t format,                        // AudioFormat && bufferSizeInBytes
+        audio_channel_mask_t channelMask,             // AudioFormat && bufferSizeInBytes
+        size_t frameCount,                            // bufferSizeInBytes
+        audio_session_t sessionId,                    // AudioTrack
+        const audio_attributes_t* pAttributes,        // AudioAttributes
+        float maxRequiredSpeed) {                     // bufferSizeInBytes
+
+    JNIEnv *env = AndroidRuntime::getJNIEnv();
+    jclass jAudioTrackCls = env->FindClass("android/media/AudioTrack");
+    mAudioTrackCls = (jclass) env->NewGlobalRef(jAudioTrackCls);
+
+    maxRequiredSpeed = std::min(std::max(maxRequiredSpeed, 1.0f), AUDIO_TIMESTRETCH_SPEED_MAX);
+
+    int bufferSizeInBytes = 0;
+    if (sampleRate == 0 || frameCount > 0) {
+        // Manually calculate buffer size.
+        bufferSizeInBytes = audio_channel_count_from_out_mask(channelMask)
+                * audio_bytes_per_sample(format) * (frameCount > 0 ? frameCount : 1);
+    } else if (sampleRate > 0) {
+        // Call Java AudioTrack::getMinBufferSize().
+        jmethodID jGetMinBufferSize =
+                env->GetStaticMethodID(mAudioTrackCls, "getMinBufferSize", "(III)I");
+        bufferSizeInBytes = env->CallStaticIntMethod(mAudioTrackCls, jGetMinBufferSize,
+                sampleRate, outChannelMaskFromNative(channelMask), audioFormatFromNative(format));
+    }
+    bufferSizeInBytes = (int) (bufferSizeInBytes * maxRequiredSpeed);
+
+    // Create a Java AudioTrack object through its Builder.
+    jclass jBuilderCls = env->FindClass("android/media/AudioTrack$Builder");
+    jmethodID jBuilderCtor = env->GetMethodID(jBuilderCls, "<init>", "()V");
+    jobject jBuilderObj = env->NewObject(jBuilderCls, jBuilderCtor);
+
+    jmethodID jSetAudioAttributes = env->GetMethodID(jBuilderCls, "setAudioAttributes",
+            "(Landroid/media/AudioAttributes;)Landroid/media/AudioTrack$Builder;");
+    jBuilderObj = env->CallObjectMethod(jBuilderObj, jSetAudioAttributes,
+            JAudioAttributes::createAudioAttributesObj(env, pAttributes, streamType));
+
+    jmethodID jSetAudioFormat = env->GetMethodID(jBuilderCls, "setAudioFormat",
+            "(Landroid/media/AudioFormat;)Landroid/media/AudioTrack$Builder;");
+    jBuilderObj = env->CallObjectMethod(jBuilderObj, jSetAudioFormat,
+            JAudioFormat::createAudioFormatObj(env, sampleRate, format, channelMask));
+
+    jmethodID jSetBufferSizeInBytes = env->GetMethodID(jBuilderCls, "setBufferSizeInBytes",
+            "(I)Landroid/media/AudioTrack$Builder;");
+    jBuilderObj = env->CallObjectMethod(jBuilderObj, jSetBufferSizeInBytes, bufferSizeInBytes);
+
+    // We only use streaming mode of Java AudioTrack.
+    jfieldID jModeStream = env->GetStaticFieldID(mAudioTrackCls, "MODE_STREAM", "I");
+    jint transferMode = env->GetStaticIntField(mAudioTrackCls, jModeStream);
+    jmethodID jSetTransferMode = env->GetMethodID(jBuilderCls, "setTransferMode",
+            "(I)Landroid/media/AudioTrack$Builder;");
+    jBuilderObj = env->CallObjectMethod(jBuilderObj, jSetTransferMode,
+            transferMode /* Java AudioTrack::MODE_STREAM */);
+
+    if (sessionId != 0) {
+        jmethodID jSetSessionId = env->GetMethodID(jBuilderCls, "setSessionId",
+                "(I)Landroid/media/AudioTrack$Builder;");
+        jBuilderObj = env->CallObjectMethod(jBuilderObj, jSetSessionId, sessionId);
+    }
+
+    jmethodID jBuild = env->GetMethodID(jBuilderCls, "build", "()Landroid/media/AudioTrack;");
+    mAudioTrackObj = env->CallObjectMethod(jBuilderObj, jBuild);
+}
+
+JAudioTrack::~JAudioTrack() {
+    JNIEnv *env = AndroidRuntime::getJNIEnv();
+    env->DeleteGlobalRef(mAudioTrackCls);
+}
+
+size_t JAudioTrack::frameCount() {
+    JNIEnv *env = AndroidRuntime::getJNIEnv();
+    jmethodID jGetBufferSizeInFrames = env->GetMethodID(
+            mAudioTrackCls, "getBufferSizeInFrames", "()I");
+    return env->CallIntMethod(mAudioTrackObj, jGetBufferSizeInFrames);
+}
+
+size_t JAudioTrack::channelCount() {
+    JNIEnv *env = AndroidRuntime::getJNIEnv();
+    jmethodID jGetChannelCount = env->GetMethodID(mAudioTrackCls, "getChannelCount", "()I");
+    return env->CallIntMethod(mAudioTrackObj, jGetChannelCount);
+}
+
+status_t JAudioTrack::getPosition(uint32_t *position) {
+    if (position == NULL) {
+        return BAD_VALUE;
+    }
+
+    JNIEnv *env = AndroidRuntime::getJNIEnv();
+    jmethodID jGetPlaybackHeadPosition = env->GetMethodID(
+            mAudioTrackCls, "getPlaybackHeadPosition", "()I");
+    *position = env->CallIntMethod(mAudioTrackObj, jGetPlaybackHeadPosition);
+
+    return NO_ERROR;
+}
+
+bool JAudioTrack::getTimeStamp(AudioTimestamp& timestamp) {
+    JNIEnv *env = AndroidRuntime::getJNIEnv();
+
+    jclass jAudioTimeStampCls = env->FindClass("android/media/AudioTimestamp");
+    jobject jAudioTimeStampObj = env->AllocObject(jAudioTimeStampCls);
+
+    jfieldID jFramePosition = env->GetFieldID(jAudioTimeStampCls, "framePosition", "L");
+    jfieldID jNanoTime = env->GetFieldID(jAudioTimeStampCls, "nanoTime", "L");
+
+    jmethodID jGetTimestamp = env->GetMethodID(mAudioTrackCls,
+            "getTimestamp", "(Landroid/media/AudioTimestamp)B");
+    bool success = env->CallBooleanMethod(mAudioTrackObj, jGetTimestamp, jAudioTimeStampObj);
+
+    if (!success) {
+        return false;
+    }
+
+    long long framePosition = env->GetLongField(jAudioTimeStampObj, jFramePosition);
+    long long nanoTime = env->GetLongField(jAudioTimeStampObj, jNanoTime);
+
+    struct timespec ts;
+    const long long secondToNano = 1000000000LL; // 1E9
+    ts.tv_sec = nanoTime / secondToNano;
+    ts.tv_nsec = nanoTime % secondToNano;
+    timestamp.mTime = ts;
+    timestamp.mPosition = (uint32_t) framePosition;
+
+    return true;
+}
+
+status_t JAudioTrack::setPlaybackRate(const AudioPlaybackRate &playbackRate) {
+    // TODO: existing native AudioTrack returns INVALID_OPERATION on offload/direct/fast tracks.
+    // Should we do the same thing?
+    JNIEnv *env = AndroidRuntime::getJNIEnv();
+
+    jclass jPlaybackParamsCls = env->FindClass("android/media/PlaybackParams");
+    jmethodID jPlaybackParamsCtor = env->GetMethodID(jPlaybackParamsCls, "<init>", "()V");
+    jobject jPlaybackParamsObj = env->NewObject(jPlaybackParamsCls, jPlaybackParamsCtor);
+
+    jmethodID jSetAudioFallbackMode = env->GetMethodID(
+            jPlaybackParamsCls, "setAudioFallbackMode", "(I)Landroid/media/PlaybackParams;");
+    jPlaybackParamsObj = env->CallObjectMethod(
+            jPlaybackParamsObj, jSetAudioFallbackMode, playbackRate.mFallbackMode);
+
+    jmethodID jSetAudioStretchMode = env->GetMethodID(
+                jPlaybackParamsCls, "setAudioStretchMode", "(I)Landroid/media/PlaybackParams;");
+    jPlaybackParamsObj = env->CallObjectMethod(
+            jPlaybackParamsObj, jSetAudioStretchMode, playbackRate.mStretchMode);
+
+    jmethodID jSetPitch = env->GetMethodID(
+            jPlaybackParamsCls, "setPitch", "(F)Landroid/media/PlaybackParams;");
+    jPlaybackParamsObj = env->CallObjectMethod(jPlaybackParamsObj, jSetPitch, playbackRate.mPitch);
+
+    jmethodID jSetSpeed = env->GetMethodID(
+            jPlaybackParamsCls, "setSpeed", "(F)Landroid/media/PlaybackParams;");
+    jPlaybackParamsObj = env->CallObjectMethod(jPlaybackParamsObj, jSetSpeed, playbackRate.mSpeed);
+
+
+    // Set this Java PlaybackParams object into Java AudioTrack.
+    jmethodID jSetPlaybackParams = env->GetMethodID(
+            mAudioTrackCls, "setPlaybackParams", "(Landroid/media/PlaybackParams;)V");
+    env->CallVoidMethod(mAudioTrackObj, jSetPlaybackParams, jPlaybackParamsObj);
+    // TODO: Should we catch the Java IllegalArgumentException?
+
+    return NO_ERROR;
+}
+
+const AudioPlaybackRate JAudioTrack::getPlaybackRate() {
+    JNIEnv *env = AndroidRuntime::getJNIEnv();
+
+    jmethodID jGetPlaybackParams = env->GetMethodID(
+            mAudioTrackCls, "getPlaybackParams", "()Landroid/media/PlaybackParams;");
+    jobject jPlaybackParamsObj = env->CallObjectMethod(mAudioTrackObj, jGetPlaybackParams);
+
+    AudioPlaybackRate playbackRate;
+    jclass jPlaybackParamsCls = env->FindClass("android/media/PlaybackParams");
+
+    jmethodID jGetAudioFallbackMode = env->GetMethodID(
+            jPlaybackParamsCls, "getAudioFallbackMode", "()I");
+    // TODO: Should we enable passing AUDIO_TIMESTRETCH_FALLBACK_CUT_REPEAT?
+    //       The enum is internal only, so it is not defined in PlaybackParmas.java.
+    // TODO: Is this right way to convert an int to an enum?
+    playbackRate.mFallbackMode = static_cast<AudioTimestretchFallbackMode>(
+            env->CallIntMethod(jPlaybackParamsObj, jGetAudioFallbackMode));
+
+    jmethodID jGetAudioStretchMode = env->GetMethodID(
+            jPlaybackParamsCls, "getAudioStretchMode", "()I");
+    playbackRate.mStretchMode = static_cast<AudioTimestretchStretchMode>(
+            env->CallIntMethod(jPlaybackParamsObj, jGetAudioStretchMode));
+
+    jmethodID jGetPitch = env->GetMethodID(jPlaybackParamsCls, "getPitch", "()F");
+    playbackRate.mPitch = env->CallFloatMethod(jPlaybackParamsObj, jGetPitch);
+
+    jmethodID jGetSpeed = env->GetMethodID(jPlaybackParamsCls, "getSpeed", "()F");
+    playbackRate.mSpeed = env->CallFloatMethod(jPlaybackParamsObj, jGetSpeed);
+
+    return playbackRate;
+}
+
+media::VolumeShaper::Status JAudioTrack::applyVolumeShaper(
+        const sp<media::VolumeShaper::Configuration>& configuration,
+        const sp<media::VolumeShaper::Operation>& operation) {
+
+    jobject jConfigurationObj = createVolumeShaperConfigurationObj(configuration);
+    jobject jOperationObj = createVolumeShaperOperationObj(operation);
+
+    if (jConfigurationObj == NULL || jOperationObj == NULL) {
+        return media::VolumeShaper::Status(BAD_VALUE);
+    }
+
+    JNIEnv *env = AndroidRuntime::getJNIEnv();
+
+    jmethodID jCreateVolumeShaper = env->GetMethodID(mAudioTrackCls, "createVolumeShaper",
+            "(Landroid/media/VolumeShaper$Configuration;)Landroid/media/VolumeShaper;");
+    jobject jVolumeShaperObj = env->CallObjectMethod(
+            mAudioTrackObj, jCreateVolumeShaper, jConfigurationObj);
+
+    jclass jVolumeShaperCls = env->FindClass("android/media/VolumeShaper");
+    jmethodID jApply = env->GetMethodID(jVolumeShaperCls, "apply",
+            "(Landroid/media/VolumeShaper$Operation;)V");
+    env->CallVoidMethod(jVolumeShaperObj, jApply, jOperationObj);
+
+    return media::VolumeShaper::Status(NO_ERROR);
+}
+
+status_t JAudioTrack::setAuxEffectSendLevel(float level) {
+    JNIEnv *env = AndroidRuntime::getJNIEnv();
+    jmethodID jSetAuxEffectSendLevel = env->GetMethodID(
+            mAudioTrackCls, "setAuxEffectSendLevel", "(F)I");
+    int result = env->CallIntMethod(mAudioTrackObj, jSetAuxEffectSendLevel, level);
+    return javaToNativeStatus(result);
+}
+
+status_t JAudioTrack::attachAuxEffect(int effectId) {
+    JNIEnv *env = AndroidRuntime::getJNIEnv();
+    jmethodID jAttachAuxEffect = env->GetMethodID(mAudioTrackCls, "attachAuxEffect", "(I)I");
+    int result = env->CallIntMethod(mAudioTrackObj, jAttachAuxEffect, effectId);
+    return javaToNativeStatus(result);
+}
+
+status_t JAudioTrack::setVolume(float left, float right) {
+    JNIEnv *env = AndroidRuntime::getJNIEnv();
+    // TODO: Java setStereoVolume is deprecated. Do we really need this method?
+    jmethodID jSetStereoVolume = env->GetMethodID(mAudioTrackCls, "setStereoVolume", "(FF)I");
+    int result = env->CallIntMethod(mAudioTrackObj, jSetStereoVolume, left, right);
+    return javaToNativeStatus(result);
+}
+
+status_t JAudioTrack::setVolume(float volume) {
+    JNIEnv *env = AndroidRuntime::getJNIEnv();
+    jmethodID jSetVolume = env->GetMethodID(mAudioTrackCls, "setVolume", "(F)I");
+    int result = env->CallIntMethod(mAudioTrackObj, jSetVolume, volume);
+    return javaToNativeStatus(result);
+}
+
+status_t JAudioTrack::start() {
+    JNIEnv *env = AndroidRuntime::getJNIEnv();
+    jmethodID jPlay = env->GetMethodID(mAudioTrackCls, "play", "()V");
+    // TODO: Should we catch the Java IllegalStateException from play()?
+    env->CallVoidMethod(mAudioTrackObj, jPlay);
+    return NO_ERROR;
+}
+
+ssize_t JAudioTrack::write(const void* buffer, size_t size, bool blocking) {
+    if (buffer == NULL) {
+        return BAD_VALUE;
+    }
+
+    JNIEnv *env = AndroidRuntime::getJNIEnv();
+    jbyteArray jAudioData = env->NewByteArray(size);
+    env->SetByteArrayRegion(jAudioData, 0, size, (jbyte *) buffer);
+
+    jclass jByteBufferCls = env->FindClass("java/nio/ByteBuffer");
+    jmethodID jWrap = env->GetStaticMethodID(jByteBufferCls, "wrap", "([B)Ljava/nio/ByteBuffer;");
+    jobject jByteBufferObj = env->CallStaticObjectMethod(jByteBufferCls, jWrap, jAudioData);
+
+    int writeMode = 0;
+    if (blocking) {
+        jfieldID jWriteBlocking = env->GetStaticFieldID(mAudioTrackCls, "WRITE_BLOCKING", "I");
+        writeMode = env->GetStaticIntField(mAudioTrackCls, jWriteBlocking);
+    } else {
+        jfieldID jWriteNonBlocking = env->GetStaticFieldID(
+                mAudioTrackCls, "WRITE_NON_BLOCKING", "I");
+        writeMode = env->GetStaticIntField(mAudioTrackCls, jWriteNonBlocking);
+    }
+
+    jmethodID jWrite = env->GetMethodID(mAudioTrackCls, "write", "(Ljava/nio/ByteBuffer;II)I");
+    int result = env->CallIntMethod(mAudioTrackObj, jWrite, jByteBufferObj, size, writeMode);
+
+    if (result >= 0) {
+        return result;
+    } else {
+        return javaToNativeStatus(result);
+    }
+}
+
+void JAudioTrack::stop() {
+    JNIEnv *env = AndroidRuntime::getJNIEnv();
+    jmethodID jStop = env->GetMethodID(mAudioTrackCls, "stop", "()V");
+    env->CallVoidMethod(mAudioTrackObj, jStop);
+    // TODO: Should we catch IllegalStateException?
+}
+
+// TODO: Is the right implementation?
+bool JAudioTrack::stopped() const {
+    return !isPlaying();
+}
+
+void JAudioTrack::flush() {
+    JNIEnv *env = AndroidRuntime::getJNIEnv();
+    jmethodID jFlush = env->GetMethodID(mAudioTrackCls, "flush", "()V");
+    env->CallVoidMethod(mAudioTrackObj, jFlush);
+}
+
+void JAudioTrack::pause() {
+    JNIEnv *env = AndroidRuntime::getJNIEnv();
+    jmethodID jPause = env->GetMethodID(mAudioTrackCls, "pause", "()V");
+    env->CallVoidMethod(mAudioTrackObj, jPause);
+    // TODO: Should we catch IllegalStateException?
+}
+
+bool JAudioTrack::isPlaying() const {
+    JNIEnv *env = AndroidRuntime::getJNIEnv();
+    jmethodID jGetPlayState = env->GetMethodID(mAudioTrackCls, "getPlayState", "()I");
+    int currentPlayState = env->CallIntMethod(mAudioTrackObj, jGetPlayState);
+
+    // TODO: In Java AudioTrack, there is no STOPPING state.
+    // This means while stopping, isPlaying() will return different value in two class.
+    //  - in existing native AudioTrack: true
+    //  - in JAudioTrack: false
+    // If not okay, also modify the implementation of stopped().
+    jfieldID jPlayStatePlaying = env->GetStaticFieldID(mAudioTrackCls, "PLAYSTATE_PLAYING", "I");
+    int statePlaying = env->GetStaticIntField(mAudioTrackCls, jPlayStatePlaying);
+    return currentPlayState == statePlaying;
+}
+
+uint32_t JAudioTrack::getSampleRate() {
+    JNIEnv *env = AndroidRuntime::getJNIEnv();
+    jmethodID jGetSampleRate = env->GetMethodID(mAudioTrackCls, "getSampleRate", "()I");
+    return env->CallIntMethod(mAudioTrackObj, jGetSampleRate);
+}
+
+status_t JAudioTrack::getBufferDurationInUs(int64_t *duration) {
+    if (duration == nullptr) {
+        return BAD_VALUE;
+    }
+
+    JNIEnv *env = AndroidRuntime::getJNIEnv();
+    jmethodID jGetBufferSizeInFrames = env->GetMethodID(
+            mAudioTrackCls, "getBufferSizeInFrames", "()I");
+    int bufferSizeInFrames = env->CallIntMethod(mAudioTrackObj, jGetBufferSizeInFrames);
+
+    const double secondToMicro = 1000000LL; // 1E6
+    int sampleRate = JAudioTrack::getSampleRate();
+    float speed = JAudioTrack::getPlaybackRate().mSpeed;
+
+    *duration = (int64_t) (bufferSizeInFrames * secondToMicro / (sampleRate * speed));
+    return NO_ERROR;
+}
+
+audio_format_t JAudioTrack::format() {
+    JNIEnv *env = AndroidRuntime::getJNIEnv();
+    jmethodID jGetAudioFormat = env->GetMethodID(mAudioTrackCls, "getAudioFormat", "()I");
+    int javaFormat = env->CallIntMethod(mAudioTrackObj, jGetAudioFormat);
+    return audioFormatToNative(javaFormat);
+}
+
+jobject JAudioTrack::createVolumeShaperConfigurationObj(
+        const sp<media::VolumeShaper::Configuration>& config) {
+
+    // TODO: Java VolumeShaper's setId() / setOptionFlags() are hidden.
+    if (config == NULL || config->getType() == media::VolumeShaper::Configuration::TYPE_ID) {
+        return NULL;
+    }
+
+    JNIEnv *env = AndroidRuntime::getJNIEnv();
+
+    // Referenced "android_media_VolumeShaper.h".
+    jfloatArray xarray = nullptr;
+    jfloatArray yarray = nullptr;
+    if (config->getType() == media::VolumeShaper::Configuration::TYPE_SCALE) {
+        // convert curve arrays
+        xarray = env->NewFloatArray(config->size());
+        yarray = env->NewFloatArray(config->size());
+        float * const x = env->GetFloatArrayElements(xarray, nullptr /* isCopy */);
+        float * const y = env->GetFloatArrayElements(yarray, nullptr /* isCopy */);
+        float *xptr = x, *yptr = y;
+        for (const auto &pt : *config.get()) {
+            *xptr++ = pt.first;
+            *yptr++ = pt.second;
+        }
+        env->ReleaseFloatArrayElements(xarray, x, 0 /* mode */);
+        env->ReleaseFloatArrayElements(yarray, y, 0 /* mode */);
+    }
+
+    jclass jBuilderCls = env->FindClass("android/media/VolumeShaper$Configuration$Builder");
+    jmethodID jBuilderCtor = env->GetMethodID(jBuilderCls, "<init>", "()V");
+    jobject jBuilderObj = env->NewObject(jBuilderCls, jBuilderCtor);
+
+    jmethodID jSetDuration = env->GetMethodID(jBuilderCls, "setDuration",
+            "(L)Landroid/media/VolumeShaper$Configuration$Builder;");
+    jBuilderObj = env->CallObjectMethod(jBuilderCls, jSetDuration, (jlong) config->getDurationMs());
+
+    jmethodID jSetInterpolatorType = env->GetMethodID(jBuilderCls, "setInterpolatorType",
+            "(I)Landroid/media/VolumeShaper$Configuration$Builder;");
+    jBuilderObj = env->CallObjectMethod(jBuilderCls, jSetInterpolatorType,
+            config->getInterpolatorType());
+
+    jmethodID jSetCurve = env->GetMethodID(jBuilderCls, "setCurve",
+            "([F[F)Landroid/media/VolumeShaper$Configuration$Builder;");
+    jBuilderObj = env->CallObjectMethod(jBuilderCls, jSetCurve, xarray, yarray);
+
+    jmethodID jBuild = env->GetMethodID(jBuilderCls, "build",
+            "()Landroid/media/VolumeShaper$Configuration;");
+    return env->CallObjectMethod(jBuilderObj, jBuild);
+}
+
+jobject JAudioTrack::createVolumeShaperOperationObj(
+        const sp<media::VolumeShaper::Operation>& operation) {
+
+    JNIEnv *env = AndroidRuntime::getJNIEnv();
+
+    jclass jBuilderCls = env->FindClass("android/media/VolumeShaper$Operation$Builder");
+    jmethodID jBuilderCtor = env->GetMethodID(jBuilderCls, "<init>", "()V");
+    jobject jBuilderObj = env->NewObject(jBuilderCls, jBuilderCtor);
+
+    // Set XOffset
+    jmethodID jSetXOffset = env->GetMethodID(jBuilderCls, "setXOffset",
+            "(F)Landroid/media/VolumeShaper$Operation$Builder;");
+    jBuilderObj = env->CallObjectMethod(jBuilderCls, jSetXOffset, operation->getXOffset());
+
+    int32_t flags = operation->getFlags();
+
+    if (operation->getReplaceId() >= 0) {
+        jmethodID jReplace = env->GetMethodID(jBuilderCls, "replace",
+                "(IB)Landroid/media/VolumeShaper$Operation$Builder;");
+        bool join = (flags | media::VolumeShaper::Operation::FLAG_JOIN) != 0;
+        jBuilderObj = env->CallObjectMethod(jBuilderCls, jReplace, operation->getReplaceId(), join);
+    }
+
+    if (flags | media::VolumeShaper::Operation::FLAG_REVERSE) {
+        jmethodID jReverse = env->GetMethodID(jBuilderCls, "reverse",
+                "()Landroid/media/VolumeShaper$Operation$Builder;");
+        jBuilderObj = env->CallObjectMethod(jBuilderCls, jReverse);
+    }
+
+    // TODO: VolumeShaper Javadoc says "Do not call terminate() directly". Can we call this?
+    if (flags | media::VolumeShaper::Operation::FLAG_TERMINATE) {
+        jmethodID jTerminate = env->GetMethodID(jBuilderCls, "terminate",
+                "()Landroid/media/VolumeShaper$Operation$Builder;");
+        jBuilderObj = env->CallObjectMethod(jBuilderCls, jTerminate);
+    }
+
+    if (flags | media::VolumeShaper::Operation::FLAG_DELAY) {
+        jmethodID jDefer = env->GetMethodID(jBuilderCls, "defer",
+                "()Landroid/media/VolumeShaper$Operation$Builder;");
+        jBuilderObj = env->CallObjectMethod(jBuilderCls, jDefer);
+    }
+
+    if (flags | media::VolumeShaper::Operation::FLAG_CREATE_IF_NECESSARY) {
+        jmethodID jCreateIfNeeded = env->GetMethodID(jBuilderCls, "createIfNeeded",
+                "()Landroid/media/VolumeShaper$Operation$Builder;");
+        jBuilderObj = env->CallObjectMethod(jBuilderCls, jCreateIfNeeded);
+    }
+
+    // TODO: Handle error case (can it be NULL?)
+    jmethodID jBuild = env->GetMethodID(jBuilderCls, "build",
+            "()Landroid/media/VolumeShaper$Operation;");
+    return env->CallObjectMethod(jBuilderObj, jBuild);
+}
+
+status_t JAudioTrack::javaToNativeStatus(int javaStatus) {
+    switch (javaStatus) {
+    case AUDIO_JAVA_SUCCESS:
+        return NO_ERROR;
+    case AUDIO_JAVA_BAD_VALUE:
+        return BAD_VALUE;
+    case AUDIO_JAVA_INVALID_OPERATION:
+        return INVALID_OPERATION;
+    case AUDIO_JAVA_PERMISSION_DENIED:
+        return PERMISSION_DENIED;
+    case AUDIO_JAVA_NO_INIT:
+        return NO_INIT;
+    case AUDIO_JAVA_WOULD_BLOCK:
+        return WOULD_BLOCK;
+    case AUDIO_JAVA_DEAD_OBJECT:
+        return DEAD_OBJECT;
+    default:
+        return UNKNOWN_ERROR;
+    }
+}
+
+} // namespace android
diff --git a/media/libmedia/aidl/android/media/IMediaExtractorUpdateService.aidl b/media/libmedia/aidl/android/media/IMediaExtractorUpdateService.aidl
new file mode 100644
index 0000000..57b1bc9
--- /dev/null
+++ b/media/libmedia/aidl/android/media/IMediaExtractorUpdateService.aidl
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2018 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;
+
+/**
+ * Service to reload extractor plugins when update package is installed/uninstalled.
+ * @hide
+ */
+interface IMediaExtractorUpdateService {
+    void loadPlugins(@utf8InCpp String apkPath);
+}
diff --git a/media/libmedia/include/media/JAudioAttributes.h b/media/libmedia/include/media/JAudioAttributes.h
new file mode 100644
index 0000000..fb11435
--- /dev/null
+++ b/media/libmedia/include/media/JAudioAttributes.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2018 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.
+ */
+
+#ifndef ANDROID_JAUDIOATTRIBUTES_H
+#define ANDROID_JAUDIOATTRIBUTES_H
+
+#include <jni.h>
+#include <system/audio.h>
+
+namespace android {
+
+class JAudioAttributes {
+public:
+    /* Creates a Java AudioAttributes object. */
+    static jobject createAudioAttributesObj(JNIEnv *env,
+                                            const audio_attributes_t* pAttributes,
+                                            audio_stream_type_t streamType) {
+
+        jclass jBuilderCls = env->FindClass("android/media/AudioAttributes$Builder");
+        jmethodID jBuilderCtor = env->GetMethodID(jBuilderCls, "<init>", "()V");
+        jobject jBuilderObj = env->NewObject(jBuilderCls, jBuilderCtor);
+
+        if (pAttributes != NULL) {
+            // If pAttributes is not null, streamType is ignored.
+            jmethodID jSetUsage = env->GetMethodID(
+                    jBuilderCls, "setUsage", "(I)Landroid/media/AudioAttributes$Builder;");
+            jBuilderObj = env->CallObjectMethod(jBuilderObj, jSetUsage, pAttributes->usage);
+
+            jmethodID jSetContentType = env->GetMethodID(jBuilderCls, "setContentType",
+                    "(I)Landroid/media/AudioAttributes$Builder;");
+            jBuilderObj = env->CallObjectMethod(jBuilderObj, jSetContentType,
+                    pAttributes->content_type);
+
+            // TODO: Java AudioAttributes.Builder.setCapturePreset() is systemApi and hidden.
+            // Can we use this method?
+//            jmethodID jSetCapturePreset = env->GetMethodID(jBuilderCls, "setCapturePreset",
+//                    "(I)Landroid/media/AudioAttributes$Builder;");
+//            jBuilderObj = env->CallObjectMethod(jBuilderObj, jSetCapturePreset,
+//                    pAttributes->source);
+
+            jmethodID jSetFlags = env->GetMethodID(jBuilderCls, "setFlags",
+                    "(I)Landroid/media/AudioAttributes$Builder;");
+            jBuilderObj = env->CallObjectMethod(jBuilderObj, jSetFlags, pAttributes->flags);
+
+            // TODO: Handle the 'tags' (char[] to HashSet<String>).
+            // How to parse the char[]? Is there any example of it?
+            // Also, the addTags() method is hidden.
+        } else {
+            // Call AudioAttributes.Builder.setLegacyStreamType().build()
+            jmethodID jSetLegacyStreamType = env->GetMethodID(jBuilderCls, "setLegacyStreamType",
+                    "(I)Landroid/media/AudioAttributes$Builder;");
+            jBuilderObj = env->CallObjectMethod(jBuilderObj, jSetLegacyStreamType, streamType);
+        }
+
+        jmethodID jBuild = env->GetMethodID(jBuilderCls, "build",
+                "()Landroid/media/AudioAttributes;");
+        return env->CallObjectMethod(jBuilderObj, jBuild);
+    }
+
+};
+
+} // namespace android
+
+#endif // ANDROID_JAUDIOATTRIBUTES_H
diff --git a/media/libmedia/include/media/JAudioFormat.h b/media/libmedia/include/media/JAudioFormat.h
new file mode 100644
index 0000000..00abdff
--- /dev/null
+++ b/media/libmedia/include/media/JAudioFormat.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2018 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.
+ */
+
+#ifndef ANDROID_JAUDIOFORMAT_H
+#define ANDROID_JAUDIOFORMAT_H
+
+#include <android_media_AudioFormat.h>
+#include <jni.h>
+
+namespace android {
+
+class JAudioFormat {
+public:
+    /* Creates a Java AudioFormat object. */
+    static jobject createAudioFormatObj(JNIEnv *env,
+                                        uint32_t sampleRate,
+                                        audio_format_t format,
+                                        audio_channel_mask_t channelMask) {
+
+        jclass jBuilderCls = env->FindClass("android/media/AudioFormat$Builder");
+        jmethodID jBuilderCtor = env->GetMethodID(jBuilderCls, "<init>", "()V");
+        jobject jBuilderObj = env->NewObject(jBuilderCls, jBuilderCtor);
+
+        if (sampleRate == 0) {
+            jclass jAudioFormatCls = env->FindClass("android/media/AudioFormat");
+            jfieldID jSampleRateUnspecified =
+                    env->GetStaticFieldID(jAudioFormatCls, "SAMPLE_RATE_UNSPECIFIED", "I");
+            sampleRate = env->GetStaticIntField(jAudioFormatCls, jSampleRateUnspecified);
+        }
+
+        jmethodID jSetEncoding = env->GetMethodID(jBuilderCls, "setEncoding",
+                "(I)Landroid/media/AudioFormat$Builder;");
+        jBuilderObj = env->CallObjectMethod(jBuilderObj, jSetEncoding,
+                audioFormatFromNative(format));
+
+        jmethodID jSetSampleRate = env->GetMethodID(jBuilderCls, "setSampleRate",
+                "(I)Landroid/media/AudioFormat$Builder;");
+        jBuilderObj = env->CallObjectMethod(jBuilderObj, jSetSampleRate, sampleRate);
+
+        jmethodID jSetChannelMask = env->GetMethodID(jBuilderCls, "setChannelMask",
+                "(I)Landroid/media/AudioFormat$Builder;");
+        jBuilderObj = env->CallObjectMethod(jBuilderObj, jSetChannelMask,
+                outChannelMaskFromNative(channelMask));
+
+        jmethodID jBuild = env->GetMethodID(jBuilderCls, "build", "()Landroid/media/AudioFormat;");
+        return env->CallObjectMethod(jBuilderObj, jBuild);
+    }
+
+};
+
+} // namespace android
+
+#endif // ANDROID_JAUDIOFORMAT_H
diff --git a/media/libmedia/include/media/JAudioTrack.h b/media/libmedia/include/media/JAudioTrack.h
new file mode 100644
index 0000000..8af30b7
--- /dev/null
+++ b/media/libmedia/include/media/JAudioTrack.h
@@ -0,0 +1,273 @@
+/*
+ * Copyright 2018 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.
+ */
+
+#ifndef ANDROID_JAUDIOTRACK_H
+#define ANDROID_JAUDIOTRACK_H
+
+#include <jni.h>
+#include <media/AudioResamplerPublic.h>
+#include <media/VolumeShaper.h>
+#include <system/audio.h>
+#include <utils/Errors.h>
+
+#include <media/AudioTimestamp.h>   // It has dependency on audio.h/Errors.h, but doesn't
+                                    // include them in it. Therefore it is included here at last.
+
+namespace android {
+
+class JAudioTrack {
+public:
+
+    /* Creates an JAudioTrack object for non-offload mode.
+     * Once created, the track needs to be started before it can be used.
+     * Unspecified values are set to appropriate default values.
+     *
+     * Parameters:
+     *
+     * streamType:         Select the type of audio stream this track is attached to
+     *                     (e.g. AUDIO_STREAM_MUSIC).
+     * sampleRate:         Data source sampling rate in Hz.  Zero means to use the sink sample rate.
+     *                     A non-zero value must be specified if AUDIO_OUTPUT_FLAG_DIRECT is set.
+     *                     0 will not work with current policy implementation for direct output
+     *                     selection where an exact match is needed for sampling rate.
+     *                     (TODO: Check direct output after flags can be used in Java AudioTrack.)
+     * format:             Audio format. For mixed tracks, any PCM format supported by server is OK.
+     *                     For direct and offloaded tracks, the possible format(s) depends on the
+     *                     output sink.
+     *                     (TODO: How can we check whether a format is supported?)
+     * channelMask:        Channel mask, such that audio_is_output_channel(channelMask) is true.
+     * frameCount:         Minimum size of track PCM buffer in frames. This defines the
+     *                     application's contribution to the latency of the track.
+     *                     The actual size selected by the JAudioTrack could be larger if the
+     *                     requested size is not compatible with current audio HAL configuration.
+     *                     Zero means to use a default value.
+     * sessionId:          Specific session ID, or zero to use default.
+     * pAttributes:        If not NULL, supersedes streamType for use case selection.
+     * maxRequiredSpeed:   For PCM tracks, this creates an appropriate buffer size that will allow
+     *                     maxRequiredSpeed playback. Values less than 1.0f and greater than
+     *                     AUDIO_TIMESTRETCH_SPEED_MAX will be clamped.  For non-PCM tracks
+     *                     and direct or offloaded tracks, this parameter is ignored.
+     *                     (TODO: Handle this after offload / direct track is supported.)
+     *
+     * TODO: Revive removed arguments after offload mode is supported.
+     */
+    JAudioTrack(audio_stream_type_t streamType,
+                uint32_t sampleRate,
+                audio_format_t format,
+                audio_channel_mask_t channelMask,
+                size_t frameCount = 0,
+                audio_session_t sessionId  = AUDIO_SESSION_ALLOCATE,
+                const audio_attributes_t* pAttributes = NULL,
+                float maxRequiredSpeed = 1.0f);
+
+    /*
+       Temporarily removed constructor arguments:
+
+       // Q. Values are in audio-base.h, but where can we find explanation for them?
+       audio_output_flags_t flags,
+
+       // Q. May be used in AudioTrack.setPreferredDevice(AudioDeviceInfo)?
+       audio_port_handle_t selectedDeviceId,
+
+       // Should be deleted, since we don't use Binder anymore.
+       bool doNotReconnect,
+
+       // Do we need UID and PID?
+       uid_t uid,
+       pid_t pid,
+
+       // TODO: Uses these values when Java AudioTrack supports the offload mode.
+       callback_t cbf,
+       void* user,
+       int32_t notificationFrames,
+       const audio_offload_info_t *offloadInfo,
+
+       // Fixed to false, but what is this?
+       threadCanCallJava
+    */
+
+    virtual ~JAudioTrack();
+
+    size_t frameCount();
+    size_t channelCount();
+
+    /* Return the total number of frames played since playback start.
+     * The counter will wrap (overflow) periodically, e.g. every ~27 hours at 44.1 kHz.
+     * It is reset to zero by flush(), reload(), and stop().
+     *
+     * Parameters:
+     *
+     * position: Address where to return play head position.
+     *
+     * Returned status (from utils/Errors.h) can be:
+     *  - NO_ERROR: successful operation
+     *  - BAD_VALUE: position is NULL
+     */
+    status_t getPosition(uint32_t *position);
+
+    // TODO: Does this comment apply same to Java AudioTrack::getTimestamp?
+    // Changed the return type from status_t to bool, since Java AudioTrack::getTimestamp returns
+    // boolean. Will Java getTimestampWithStatus() be public?
+    /* Poll for a timestamp on demand.
+     * Use if EVENT_NEW_TIMESTAMP is not delivered often enough for your needs,
+     * or if you need to get the most recent timestamp outside of the event callback handler.
+     * Caution: calling this method too often may be inefficient;
+     * if you need a high resolution mapping between frame position and presentation time,
+     * consider implementing that at application level, based on the low resolution timestamps.
+     * Returns true if timestamp is valid.
+     * The timestamp parameter is undefined on return, if false is returned.
+     */
+    bool getTimeStamp(AudioTimestamp& timestamp);
+
+    /* Set source playback rate for timestretch
+     * 1.0 is normal speed: < 1.0 is slower, > 1.0 is faster
+     * 1.0 is normal pitch: < 1.0 is lower pitch, > 1.0 is higher pitch
+     *
+     * AUDIO_TIMESTRETCH_SPEED_MIN <= speed <= AUDIO_TIMESTRETCH_SPEED_MAX
+     * AUDIO_TIMESTRETCH_PITCH_MIN <= pitch <= AUDIO_TIMESTRETCH_PITCH_MAX
+     *
+     * Speed increases the playback rate of media, but does not alter pitch.
+     * Pitch increases the "tonal frequency" of media, but does not affect the playback rate.
+     */
+    status_t setPlaybackRate(const AudioPlaybackRate &playbackRate);
+
+    /* Return current playback rate */
+    const AudioPlaybackRate getPlaybackRate();
+
+    /* Sets the volume shaper object */
+    media::VolumeShaper::Status applyVolumeShaper(
+            const sp<media::VolumeShaper::Configuration>& configuration,
+            const sp<media::VolumeShaper::Operation>& operation);
+
+    /* Set the send level for this track. An auxiliary effect should be attached
+     * to the track with attachEffect(). Level must be >= 0.0 and <= 1.0.
+     */
+    status_t setAuxEffectSendLevel(float level);
+
+    /* Attach track auxiliary output to specified effect. Use effectId = 0
+     * to detach track from effect.
+     *
+     * Parameters:
+     *
+     * effectId: effectId obtained from AudioEffect::id().
+     *
+     * Returned status (from utils/Errors.h) can be:
+     *  - NO_ERROR: successful operation
+     *  - INVALID_OPERATION: The effect is not an auxiliary effect.
+     *  - BAD_VALUE: The specified effect ID is invalid.
+     */
+    status_t attachAuxEffect(int effectId);
+
+    /* Set volume for this track, mostly used for games' sound effects
+     * left and right volumes. Levels must be >= 0.0 and <= 1.0.
+     * This is the older API.  New applications should use setVolume(float) when possible.
+     */
+    status_t setVolume(float left, float right);
+
+    /* Set volume for all channels. This is the preferred API for new applications,
+     * especially for multi-channel content.
+     */
+    status_t setVolume(float volume);
+
+    // TODO: Does this comment equally apply to the Java AudioTrack::play()?
+    /* After it's created the track is not active. Call start() to
+     * make it active. If set, the callback will start being called.
+     * If the track was previously paused, volume is ramped up over the first mix buffer.
+     */
+    status_t start();
+
+    // TODO: Does this comment still applies? It seems not. (obtainBuffer, AudioFlinger, ...)
+    /* As a convenience we provide a write() interface to the audio buffer.
+     * Input parameter 'size' is in byte units.
+     * This is implemented on top of obtainBuffer/releaseBuffer. For best
+     * performance use callbacks. Returns actual number of bytes written >= 0,
+     * or one of the following negative status codes:
+     *      INVALID_OPERATION   AudioTrack is configured for static buffer or streaming mode
+     *      BAD_VALUE           size is invalid
+     *      WOULD_BLOCK         when obtainBuffer() returns same, or
+     *                          AudioTrack was stopped during the write
+     *      DEAD_OBJECT         when AudioFlinger dies or the output device changes and
+     *                          the track cannot be automatically restored.
+     *                          The application needs to recreate the AudioTrack
+     *                          because the audio device changed or AudioFlinger died.
+     *                          This typically occurs for direct or offload tracks
+     *                          or if mDoNotReconnect is true.
+     *      or any other error code returned by IAudioTrack::start() or restoreTrack_l().
+     * Default behavior is to only return when all data has been transferred. Set 'blocking' to
+     * false for the method to return immediately without waiting to try multiple times to write
+     * the full content of the buffer.
+     */
+    ssize_t write(const void* buffer, size_t size, bool blocking = true);
+
+    // TODO: Does this comment equally apply to the Java AudioTrack::stop()?
+    /* Stop a track.
+     * In static buffer mode, the track is stopped immediately.
+     * In streaming mode, the callback will cease being called.  Note that obtainBuffer() still
+     * works and will fill up buffers until the pool is exhausted, and then will return WOULD_BLOCK.
+     * In streaming mode the stop does not occur immediately: any data remaining in the buffer
+     * is first drained, mixed, and output, and only then is the track marked as stopped.
+     */
+    void stop();
+    bool stopped() const;
+
+    // TODO: Does this comment equally apply to the Java AudioTrack::flush()?
+    /* Flush a stopped or paused track. All previously buffered data is discarded immediately.
+     * This has the effect of draining the buffers without mixing or output.
+     * Flush is intended for streaming mode, for example before switching to non-contiguous content.
+     * This function is a no-op if the track is not stopped or paused, or uses a static buffer.
+     */
+    void flush();
+
+    // TODO: Does this comment equally apply to the Java AudioTrack::pause()?
+    // At least we are not using obtainBuffer.
+    /* Pause a track. After pause, the callback will cease being called and
+     * obtainBuffer returns WOULD_BLOCK. Note that obtainBuffer() still works
+     * and will fill up buffers until the pool is exhausted.
+     * Volume is ramped down over the next mix buffer following the pause request,
+     * and then the track is marked as paused. It can be resumed with ramp up by start().
+     */
+    void pause();
+
+    bool isPlaying() const;
+
+    /* Return current source sample rate in Hz.
+     * If specified as zero in constructor, this will be the sink sample rate.
+     */
+    uint32_t getSampleRate();
+
+    /* Returns the buffer duration in microseconds at current playback rate. */
+    status_t getBufferDurationInUs(int64_t *duration);
+
+    audio_format_t format();
+
+private:
+    jclass mAudioTrackCls;
+    jobject mAudioTrackObj;
+
+    /* Creates a Java VolumeShaper.Configuration object from VolumeShaper::Configuration */
+    jobject createVolumeShaperConfigurationObj(
+            const sp<media::VolumeShaper::Configuration>& config);
+
+    /* Creates a Java VolumeShaper.Operation object from VolumeShaper::Operation */
+    jobject createVolumeShaperOperationObj(
+            const sp<media::VolumeShaper::Operation>& operation);
+
+    status_t javaToNativeStatus(int javaStatus);
+};
+
+}; // namespace android
+
+#endif // ANDROID_JAUDIOTRACK_H
diff --git a/media/libmediametrics/MediaAnalyticsItem.cpp b/media/libmediametrics/MediaAnalyticsItem.cpp
index 6b063e8..423dfb8 100644
--- a/media/libmediametrics/MediaAnalyticsItem.cpp
+++ b/media/libmediametrics/MediaAnalyticsItem.cpp
@@ -29,8 +29,6 @@
 #include <utils/SortedVector.h>
 #include <utils/threads.h>
 
-#include <media/stagefright/foundation/AString.h>
-
 #include <binder/IServiceManager.h>
 #include <media/IMediaAnalyticsService.h>
 #include <media/MediaAnalyticsItem.h>
@@ -205,15 +203,11 @@
     return mUid;
 }
 
-MediaAnalyticsItem &MediaAnalyticsItem::setPkgName(AString pkgName) {
+MediaAnalyticsItem &MediaAnalyticsItem::setPkgName(const std::string &pkgName) {
     mPkgName = pkgName;
     return *this;
 }
 
-AString MediaAnalyticsItem::getPkgName() const {
-    return mPkgName;
-}
-
 MediaAnalyticsItem &MediaAnalyticsItem::setPkgVersionCode(int64_t pkgVersionCode) {
     mPkgVersionCode = pkgVersionCode;
     return *this;
@@ -727,11 +721,11 @@
 }
 
 
-AString MediaAnalyticsItem::toString() {
+std::string MediaAnalyticsItem::toString() {
    return toString(-1);
 }
 
-AString MediaAnalyticsItem::toString(int version) {
+std::string MediaAnalyticsItem::toString(int version) {
 
     // v0 : released with 'o'
     // v1 : bug fix (missing pid/finalized separator),
@@ -744,7 +738,7 @@
         version = PROTO_LAST;
     }
 
-    AString result;
+    std::string result;
     char buffer[512];
 
     if (version == PROTO_V0) {
@@ -841,7 +835,7 @@
 bool MediaAnalyticsItem::selfrecord(bool forcenew) {
 
     if (DEBUG_API) {
-        AString p = this->toString();
+        std::string p = this->toString();
         ALOGD("selfrecord of: %s [forcenew=%d]", p.c_str(), forcenew);
     }
 
@@ -850,13 +844,13 @@
     if (svc != NULL) {
         MediaAnalyticsItem::SessionID_t newid = svc->submit(this, forcenew);
         if (newid == SessionIDInvalid) {
-            AString p = this->toString();
+            std::string p = this->toString();
             ALOGW("Failed to record: %s [forcenew=%d]", p.c_str(), forcenew);
             return false;
         }
         return true;
     } else {
-        AString p = this->toString();
+        std::string p = this->toString();
         ALOGW("Unable to record: %s [forcenew=%d]", p.c_str(), forcenew);
         return false;
     }
diff --git a/media/libmediametrics/include/MediaAnalyticsItem.h b/media/libmediametrics/include/MediaAnalyticsItem.h
index ec9b660..79ff093 100644
--- a/media/libmediametrics/include/MediaAnalyticsItem.h
+++ b/media/libmediametrics/include/MediaAnalyticsItem.h
@@ -18,6 +18,7 @@
 #define ANDROID_MEDIA_MEDIAANALYTICSITEM_H
 
 #include <cutils/properties.h>
+#include <string>
 #include <sys/types.h>
 #include <utils/Errors.h>
 #include <utils/KeyedVector.h>
@@ -25,13 +26,10 @@
 #include <utils/StrongPointer.h>
 #include <utils/Timers.h>
 
-#include <media/stagefright/foundation/AString.h>
-
 namespace android {
 
-
-
 class IMediaAnalyticsService;
+class Parcel;
 
 // the class interface
 //
@@ -66,7 +64,7 @@
         // values can be "component/component"
         // basic values: "video", "audio", "drm"
         // XXX: need to better define the format
-        typedef AString Key;
+        typedef std::string Key;
         static const Key kKeyNone;              // ""
         static const Key kKeyAny;               // "*"
 
@@ -170,8 +168,8 @@
         MediaAnalyticsItem &setUid(uid_t);
         uid_t getUid() const;
 
-        MediaAnalyticsItem &setPkgName(AString);
-        AString getPkgName() const;
+        MediaAnalyticsItem &setPkgName(const std::string &pkgName);
+        std::string getPkgName() const { return mPkgName; }
 
         MediaAnalyticsItem &setPkgVersionCode(int64_t);
         int64_t getPkgVersionCode() const;
@@ -180,8 +178,8 @@
         int32_t writeToParcel(Parcel *);
         int32_t readFromParcel(const Parcel&);
 
-        AString toString();
-        AString toString(int version);
+        std::string toString();
+        std::string toString(int version);
 
         // are we collecting analytics data
         static bool isEnabled();
@@ -204,7 +202,7 @@
         // to help validate that A doesn't mess with B's records
         pid_t     mPid;
         uid_t     mUid;
-        AString   mPkgName;
+        std::string   mPkgName;
         int64_t   mPkgVersionCode;
 
         // let's reuse a binder connection
diff --git a/media/libnblog/NBLog.cpp b/media/libnblog/NBLog.cpp
index c8c7195..d6fa3e3 100644
--- a/media/libnblog/NBLog.cpp
+++ b/media/libnblog/NBLog.cpp
@@ -259,7 +259,8 @@
     *(int*) (buffer + sizeof(entry) + sizeof(HistTsEntry)) = author;
     // Update lengths
     buffer[offsetof(entry, length)] = sizeof(HistTsEntryWithAuthor);
-    buffer[sizeof(buffer) + Entry::kPreviousLengthOffset] = sizeof(HistTsEntryWithAuthor);
+    buffer[offsetof(entry, data) + sizeof(HistTsEntryWithAuthor) + offsetof(ending, length)]
+        = sizeof(HistTsEntryWithAuthor);
     // Write new buffer into FIFO
     dst->write(buffer, sizeof(buffer));
     return EntryIterator(mEntry).next();
diff --git a/media/libstagefright/Android.bp b/media/libstagefright/Android.bp
index 484e310..e16db00 100644
--- a/media/libstagefright/Android.bp
+++ b/media/libstagefright/Android.bp
@@ -112,6 +112,7 @@
         "libRScpp",
         "libhidlbase",
         "libhidlmemory",
+        "libziparchive",
         "android.hidl.allocator@1.0",
         "android.hardware.cas.native@1.0",
         "android.hardware.media.omx@1.0",
@@ -211,6 +212,7 @@
         "libmedia_helper",
         "libstagefright_foundation",
         "libdl",
+        "libziparchive",
     ],
 
     static_libs: [
diff --git a/media/libstagefright/InterfaceUtils.cpp b/media/libstagefright/InterfaceUtils.cpp
index cf9fdf8..f174ba4 100644
--- a/media/libstagefright/InterfaceUtils.cpp
+++ b/media/libstagefright/InterfaceUtils.cpp
@@ -38,11 +38,12 @@
     return RemoteDataSource::wrap(source);
 }
 
-sp<IMediaExtractor> CreateIMediaExtractorFromMediaExtractor(const sp<MediaExtractor> &extractor) {
+sp<IMediaExtractor> CreateIMediaExtractorFromMediaExtractor(
+        const sp<MediaExtractor> &extractor, const sp<RefBase> &plugin) {
     if (extractor == nullptr) {
         return nullptr;
     }
-    return RemoteMediaExtractor::wrap(extractor);
+    return RemoteMediaExtractor::wrap(extractor, plugin);
 }
 
 sp<MediaSource> CreateMediaSourceFromIMediaSource(const sp<IMediaSource> &source) {
@@ -52,11 +53,12 @@
     return new CallbackMediaSource(source);
 }
 
-sp<IMediaSource> CreateIMediaSourceFromMediaSource(const sp<MediaSource> &source) {
+sp<IMediaSource> CreateIMediaSourceFromMediaSource(
+        const sp<MediaSource> &source, const sp<RefBase> &plugin) {
     if (source == nullptr) {
         return nullptr;
     }
-    return RemoteMediaSource::wrap(source);
+    return RemoteMediaSource::wrap(source, plugin);
 }
 
 }  // namespace android
diff --git a/media/libstagefright/MediaExtractorFactory.cpp b/media/libstagefright/MediaExtractorFactory.cpp
index 8a90e93..a777663 100644
--- a/media/libstagefright/MediaExtractorFactory.cpp
+++ b/media/libstagefright/MediaExtractorFactory.cpp
@@ -15,7 +15,7 @@
  */
 
 //#define LOG_NDEBUG 0
-#define LOG_TAG "MediaExtractor"
+#define LOG_TAG "MediaExtractorFactory"
 #include <utils/Log.h>
 
 #include <binder/IServiceManager.h>
@@ -31,12 +31,15 @@
 #include <media/IMediaExtractorService.h>
 #include <cutils/properties.h>
 #include <utils/String8.h>
+#include <ziparchive/zip_archive.h>
 
 #include <dirent.h>
 #include <dlfcn.h>
 
 namespace android {
 
+static const char *kSystemApkPath = "/system/app/MediaComponents/MediaComponents.apk";
+
 // static
 sp<IMediaExtractor> MediaExtractorFactory::Create(
         const sp<DataSource> &source, const char *mime) {
@@ -45,8 +48,7 @@
     if (!property_get_bool("media.stagefright.extractremote", true)) {
         // local extractor
         ALOGW("creating media extractor in calling process");
-        sp<MediaExtractor> extractor = CreateFromService(source, mime);
-        return CreateIMediaExtractorFromMediaExtractor(extractor);
+        return CreateFromService(source, mime);
     } else {
         // remote extractor
         ALOGV("get service manager");
@@ -103,11 +105,12 @@
     return Create(*out, mime);
 }
 
-sp<MediaExtractor> MediaExtractorFactory::CreateFromService(
+sp<IMediaExtractor> MediaExtractorFactory::CreateFromService(
         const sp<DataSource> &source, const char *mime) {
 
-    ALOGV("MediaExtractorFactory::%s %s", __func__, mime);
-    RegisterDefaultSniffers();
+    ALOGV("MediaExtractorFactory::CreateFromService %s", mime);
+
+    UpdateExtractors(nullptr);
 
     // initialize source decryption if needed
     source->DrmInitialization(nullptr /* mime */);
@@ -117,7 +120,8 @@
     MediaExtractor::CreatorFunc creator = NULL;
     String8 tmp;
     float confidence;
-    creator = sniff(source, &tmp, &confidence, &meta);
+    sp<ExtractorPlugin> plugin;
+    creator = sniff(source, &tmp, &confidence, &meta, plugin);
     if (!creator) {
         ALOGV("FAILED to autodetect media content.");
         return NULL;
@@ -128,39 +132,64 @@
          mime, confidence);
 
     MediaExtractor *ret = creator(source, meta);
-    return ret;
+    return CreateIMediaExtractorFromMediaExtractor(ret, plugin);
 }
 
-Mutex MediaExtractorFactory::gSnifferMutex;
-List<MediaExtractor::ExtractorDef> MediaExtractorFactory::gSniffers;
-bool MediaExtractorFactory::gSniffersRegistered = false;
+//static
+void MediaExtractorFactory::LoadPlugins(const ::std::string& apkPath) {
+    // TODO: Verify apk path with package manager in extractor process.
+    ALOGV("Load plugins from: %s", apkPath.c_str());
+    UpdateExtractors(apkPath.empty() ? nullptr : apkPath.c_str());
+}
+
+struct ExtractorPlugin : public RefBase {
+    MediaExtractor::ExtractorDef def;
+    void *libHandle;
+    String8 libPath;
+
+    ExtractorPlugin(MediaExtractor::ExtractorDef definition, void *handle, String8 &path)
+        : def(definition), libHandle(handle), libPath(path) { }
+    ~ExtractorPlugin() {
+        if (libHandle != nullptr) {
+            ALOGV("closing handle for %s %d", libPath.c_str(), def.extractor_version);
+            dlclose(libHandle);
+        }
+    }
+};
+
+Mutex MediaExtractorFactory::gPluginMutex;
+std::shared_ptr<List<sp<ExtractorPlugin>>> MediaExtractorFactory::gPlugins;
+bool MediaExtractorFactory::gPluginsRegistered = false;
 
 // static
 MediaExtractor::CreatorFunc MediaExtractorFactory::sniff(
-        const sp<DataSource> &source, String8 *mimeType, float *confidence, sp<AMessage> *meta) {
+        const sp<DataSource> &source, String8 *mimeType, float *confidence, sp<AMessage> *meta,
+        sp<ExtractorPlugin> &plugin) {
     *mimeType = "";
     *confidence = 0.0f;
     meta->clear();
 
+    std::shared_ptr<List<sp<ExtractorPlugin>>> plugins;
     {
-        Mutex::Autolock autoLock(gSnifferMutex);
-        if (!gSniffersRegistered) {
+        Mutex::Autolock autoLock(gPluginMutex);
+        if (!gPluginsRegistered) {
             return NULL;
         }
+        plugins = gPlugins;
     }
 
     MediaExtractor::CreatorFunc curCreator = NULL;
     MediaExtractor::CreatorFunc bestCreator = NULL;
-    for (List<MediaExtractor::ExtractorDef>::iterator it = gSniffers.begin();
-         it != gSniffers.end(); ++it) {
+    for (auto it = plugins->begin(); it != plugins->end(); ++it) {
         String8 newMimeType;
         float newConfidence;
         sp<AMessage> newMeta;
-        if ((curCreator = (*it).sniff(source, &newMimeType, &newConfidence, &newMeta))) {
+        if ((curCreator = (*it)->def.sniff(source, &newMimeType, &newConfidence, &newMeta))) {
             if (newConfidence > *confidence) {
                 *mimeType = newMimeType;
                 *confidence = newConfidence;
                 *meta = newMeta;
+                plugin = *it;
                 bestCreator = curCreator;
             }
         }
@@ -170,95 +199,112 @@
 }
 
 // static
-void MediaExtractorFactory::RegisterSniffer_l(const MediaExtractor::ExtractorDef &def) {
+void MediaExtractorFactory::RegisterExtractor(const sp<ExtractorPlugin> &plugin,
+        List<sp<ExtractorPlugin>> &pluginList) {
     // sanity check check struct version, uuid, name
-    if (def.def_version == 0 || def.def_version > MediaExtractor::EXTRACTORDEF_VERSION) {
-        ALOGE("don't understand extractor format %u, ignoring.", def.def_version);
+    if (plugin->def.def_version == 0
+            || plugin->def.def_version > MediaExtractor::EXTRACTORDEF_VERSION) {
+        ALOGE("don't understand extractor format %u, ignoring.", plugin->def.def_version);
         return;
     }
-    if (memcmp(&def.extractor_uuid, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 16) == 0) {
+    if (memcmp(&plugin->def.extractor_uuid, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 16) == 0) {
         ALOGE("invalid UUID, ignoring");
         return;
     }
-    if (def.extractor_name == NULL || strlen(def.extractor_name) == 0) {
+    if (plugin->def.extractor_name == NULL || strlen(plugin->def.extractor_name) == 0) {
         ALOGE("extractors should have a name, ignoring");
         return;
     }
 
-    for (List<MediaExtractor::ExtractorDef>::iterator it = gSniffers.begin();
-            it != gSniffers.end(); ++it) {
-        if (memcmp(&((*it).extractor_uuid), &def.extractor_uuid, 16) == 0) {
+    for (auto it = pluginList.begin(); it != pluginList.end(); ++it) {
+        if (memcmp(&((*it)->def.extractor_uuid), &plugin->def.extractor_uuid, 16) == 0) {
             // there's already an extractor with the same uuid
-            if ((*it).extractor_version < def.extractor_version) {
+            if ((*it)->def.extractor_version < plugin->def.extractor_version) {
                 // this one is newer, replace the old one
                 ALOGW("replacing extractor '%s' version %u with version %u",
-                        def.extractor_name,
-                        (*it).extractor_version,
-                        def.extractor_version);
-                gSniffers.erase(it);
+                        plugin->def.extractor_name,
+                        (*it)->def.extractor_version,
+                        plugin->def.extractor_version);
+                pluginList.erase(it);
                 break;
             } else {
                 ALOGW("ignoring extractor '%s' version %u in favor of version %u",
-                        def.extractor_name,
-                        def.extractor_version,
-                        (*it).extractor_version);
+                        plugin->def.extractor_name,
+                        plugin->def.extractor_version,
+                        (*it)->def.extractor_version);
                 return;
             }
         }
     }
-    ALOGV("registering extractor for %s", def.extractor_name);
-    gSniffers.push_back(def);
+    ALOGV("registering extractor for %s", plugin->def.extractor_name);
+    pluginList.push_back(plugin);
 }
 
-// static
-void MediaExtractorFactory::RegisterDefaultSniffers() {
-    Mutex::Autolock autoLock(gSnifferMutex);
-    if (gSniffersRegistered) {
-        return;
-    }
-
-    auto registerExtractors = [](const char *libDirPath) -> void {
-        DIR *libDir = opendir(libDirPath);
-        if (libDir) {
-            struct dirent* libEntry;
-            while ((libEntry = readdir(libDir))) {
-                String8 libPath = String8(libDirPath) + libEntry->d_name;
+//static
+void MediaExtractorFactory::RegisterExtractors(
+        const char *apkPath, List<sp<ExtractorPlugin>> &pluginList) {
+    ALOGV("search for plugins at %s", apkPath);
+    ZipArchiveHandle zipHandle;
+    int32_t ret = OpenArchive(apkPath, &zipHandle);
+    if (ret == 0) {
+        char abi[PROPERTY_VALUE_MAX];
+        property_get("ro.product.cpu.abi", abi, "arm64-v8a");
+        ZipString prefix(String8::format("lib/%s/", abi).c_str());
+        ZipString suffix("extractor.so");
+        void* cookie;
+        ret = StartIteration(zipHandle, &cookie, &prefix, &suffix);
+        if (ret == 0) {
+            ZipEntry entry;
+            ZipString name;
+            while (Next(cookie, &entry, &name) == 0) {
+                String8 libPath = String8(apkPath) + "!/" +
+                    String8(reinterpret_cast<const char*>(name.name), name.name_length);
                 void *libHandle = dlopen(libPath.string(), RTLD_NOW | RTLD_LOCAL);
                 if (libHandle) {
-                    MediaExtractor::GetExtractorDef getsniffer =
-                            (MediaExtractor::GetExtractorDef) dlsym(libHandle, "GETEXTRACTORDEF");
-                    if (getsniffer) {
+                    MediaExtractor::GetExtractorDef getDef =
+                        (MediaExtractor::GetExtractorDef) dlsym(libHandle, "GETEXTRACTORDEF");
+                    if (getDef) {
                         ALOGV("registering sniffer for %s", libPath.string());
-                        RegisterSniffer_l(getsniffer());
+                        RegisterExtractor(
+                                new ExtractorPlugin(getDef(), libHandle, libPath), pluginList);
                     } else {
                         ALOGW("%s does not contain sniffer", libPath.string());
                         dlclose(libHandle);
                     }
                 } else {
-                    ALOGW("couldn't dlopen(%s)", libPath.string());
+                    ALOGW("couldn't dlopen(%s) %s", libPath.string(), strerror(errno));
                 }
             }
-
-            closedir(libDir);
+            EndIteration(cookie);
         } else {
-            ALOGE("couldn't opendir(%s)", libDirPath);
+            ALOGW("couldn't find plugins from %s, %d", apkPath, ret);
         }
-    };
-
-    registerExtractors("/system/lib"
-#ifdef __LP64__
-            "64"
-#endif
-            "/extractors/");
-
-    registerExtractors("/vendor/lib"
-#ifdef __LP64__
-            "64"
-#endif
-            "/extractors/");
-
-    gSniffersRegistered = true;
+        CloseArchive(zipHandle);
+    } else {
+        ALOGW("couldn't open(%s) %d", apkPath, ret);
+    }
 }
 
+// static
+void MediaExtractorFactory::UpdateExtractors(const char *newUpdateApkPath) {
+    Mutex::Autolock autoLock(gPluginMutex);
+    if (newUpdateApkPath != nullptr) {
+        gPluginsRegistered = false;
+    }
+    if (gPluginsRegistered) {
+        return;
+    }
+
+    std::shared_ptr<List<sp<ExtractorPlugin>>> newList(new List<sp<ExtractorPlugin>>());
+
+    RegisterExtractors(kSystemApkPath, *newList);
+
+    if (newUpdateApkPath != nullptr) {
+        RegisterExtractors(newUpdateApkPath, *newList);
+    }
+
+    gPlugins = newList;
+    gPluginsRegistered = true;
+}
 
 }  // namespace android
diff --git a/media/libstagefright/RemoteMediaExtractor.cpp b/media/libstagefright/RemoteMediaExtractor.cpp
index 2a16e16..12654d9 100644
--- a/media/libstagefright/RemoteMediaExtractor.cpp
+++ b/media/libstagefright/RemoteMediaExtractor.cpp
@@ -36,8 +36,10 @@
 static const char *kExtractorTracks = "android.media.mediaextractor.ntrk";
 static const char *kExtractorFormat = "android.media.mediaextractor.fmt";
 
-RemoteMediaExtractor::RemoteMediaExtractor(const sp<MediaExtractor> &extractor)
-    :mExtractor(extractor) {
+RemoteMediaExtractor::RemoteMediaExtractor(
+        const sp<MediaExtractor> &extractor, const sp<RefBase> &plugin)
+    :mExtractor(extractor),
+    mExtractorPlugin(plugin) {
 
     mAnalyticsItem = nullptr;
     if (MEDIA_LOG) {
@@ -65,6 +67,8 @@
 }
 
 RemoteMediaExtractor::~RemoteMediaExtractor() {
+    mExtractor = nullptr;
+    mExtractorPlugin = nullptr;
     // log the current record, provided it has some information worth recording
     if (MEDIA_LOG) {
         if (mAnalyticsItem != nullptr) {
@@ -86,7 +90,8 @@
 
 sp<IMediaSource> RemoteMediaExtractor::getTrack(size_t index) {
     sp<MediaSource> source = mExtractor->getTrack(index);
-    return (source.get() == nullptr) ? nullptr : CreateIMediaSourceFromMediaSource(source);
+    return (source.get() == nullptr)
+            ? nullptr : CreateIMediaSourceFromMediaSource(source, mExtractorPlugin);
 }
 
 sp<MetaData> RemoteMediaExtractor::getTrackMetaData(size_t index, uint32_t flags) {
@@ -133,11 +138,12 @@
 ////////////////////////////////////////////////////////////////////////////////
 
 // static
-sp<IMediaExtractor> RemoteMediaExtractor::wrap(const sp<MediaExtractor> &extractor) {
+sp<IMediaExtractor> RemoteMediaExtractor::wrap(
+        const sp<MediaExtractor> &extractor, const sp<RefBase> &plugin) {
     if (extractor.get() == nullptr) {
         return nullptr;
     }
-    return new RemoteMediaExtractor(extractor);
+    return new RemoteMediaExtractor(extractor, plugin);
 }
 
 }  // namespace android
diff --git a/media/libstagefright/RemoteMediaSource.cpp b/media/libstagefright/RemoteMediaSource.cpp
index 866d163..d97329c 100644
--- a/media/libstagefright/RemoteMediaSource.cpp
+++ b/media/libstagefright/RemoteMediaSource.cpp
@@ -19,10 +19,14 @@
 
 namespace android {
 
-RemoteMediaSource::RemoteMediaSource(const sp<MediaSource> &source)
-    :mSource(source) {}
+RemoteMediaSource::RemoteMediaSource(const sp<MediaSource> &source, const sp<RefBase> &plugin)
+    :mSource(source),
+    mExtractorPlugin(plugin) {}
 
-RemoteMediaSource::~RemoteMediaSource() {}
+RemoteMediaSource::~RemoteMediaSource() {
+    mSource = nullptr;
+    mExtractorPlugin = nullptr;
+}
 
 status_t RemoteMediaSource::start(MetaData *params) {
     return mSource->start(params);
@@ -51,11 +55,11 @@
 ////////////////////////////////////////////////////////////////////////////////
 
 // static
-sp<IMediaSource> RemoteMediaSource::wrap(const sp<MediaSource> &source) {
+sp<IMediaSource> RemoteMediaSource::wrap(const sp<MediaSource> &source, const sp<RefBase> &plugin) {
     if (source.get() == nullptr) {
         return nullptr;
     }
-    return new RemoteMediaSource(source);
+    return new RemoteMediaSource(source, plugin);
 }
 
 }  // namespace android
diff --git a/media/libstagefright/include/media/stagefright/InterfaceUtils.h b/media/libstagefright/include/media/stagefright/InterfaceUtils.h
index 783f109..224c1f1 100644
--- a/media/libstagefright/include/media/stagefright/InterfaceUtils.h
+++ b/media/libstagefright/include/media/stagefright/InterfaceUtils.h
@@ -31,13 +31,15 @@
 sp<IDataSource> CreateIDataSourceFromDataSource(const sp<DataSource> &source);
 
 // Creates an IMediaExtractor wrapper to the given MediaExtractor.
-sp<IMediaExtractor> CreateIMediaExtractorFromMediaExtractor(const sp<MediaExtractor> &extractor);
+sp<IMediaExtractor> CreateIMediaExtractorFromMediaExtractor(
+        const sp<MediaExtractor> &extractor, const sp<RefBase> &plugin);
 
 // Creates a MediaSource which wraps the given IMediaSource object.
 sp<MediaSource> CreateMediaSourceFromIMediaSource(const sp<IMediaSource> &source);
 
 // Creates an IMediaSource wrapper to the given MediaSource.
-sp<IMediaSource> CreateIMediaSourceFromMediaSource(const sp<MediaSource> &source);
+sp<IMediaSource> CreateIMediaSourceFromMediaSource(
+        const sp<MediaSource> &source, const sp<RefBase> &plugin);
 
 }  // namespace android
 
diff --git a/media/libstagefright/include/media/stagefright/MediaExtractorFactory.h b/media/libstagefright/include/media/stagefright/MediaExtractorFactory.h
index f216ff8..7fddf80 100644
--- a/media/libstagefright/include/media/stagefright/MediaExtractorFactory.h
+++ b/media/libstagefright/include/media/stagefright/MediaExtractorFactory.h
@@ -26,6 +26,7 @@
 namespace android {
 
 class DataSource;
+struct ExtractorPlugin;
 
 class MediaExtractorFactory {
 public:
@@ -37,20 +38,25 @@
     // will be alsp returned with |out|.
     static sp<IMediaExtractor> CreateFromFd(
             int fd, int64_t offset, int64_t length, const char *mime, sp<DataSource> *out);
-    static sp<MediaExtractor> CreateFromService(
+    static sp<IMediaExtractor> CreateFromService(
             const sp<DataSource> &source, const char *mime = NULL);
+    static void LoadPlugins(const ::std::string& apkPath);
 
 private:
-    static Mutex gSnifferMutex;
-    static List<MediaExtractor::ExtractorDef> gSniffers;
-    static bool gSniffersRegistered;
+    static Mutex gPluginMutex;
+    static std::shared_ptr<List<sp<ExtractorPlugin>>> gPlugins;
+    static bool gPluginsRegistered;
 
-    static void RegisterSniffer_l(const MediaExtractor::ExtractorDef &def);
+    static void RegisterExtractors(
+            const char *apkPath, List<sp<ExtractorPlugin>> &pluginList);
+    static void RegisterExtractor(
+            const sp<ExtractorPlugin> &plugin, List<sp<ExtractorPlugin>> &pluginList);
 
     static MediaExtractor::CreatorFunc sniff(const sp<DataSource> &source,
-            String8 *mimeType, float *confidence, sp<AMessage> *meta);
+            String8 *mimeType, float *confidence, sp<AMessage> *meta,
+            sp<ExtractorPlugin> &plugin);
 
-    static void RegisterDefaultSniffers();
+    static void UpdateExtractors(const char *newUpdateApkPath);
 };
 
 }  // namespace android
diff --git a/media/libstagefright/include/media/stagefright/RemoteMediaExtractor.h b/media/libstagefright/include/media/stagefright/RemoteMediaExtractor.h
index 98b8b4d..2bd71ee 100644
--- a/media/libstagefright/include/media/stagefright/RemoteMediaExtractor.h
+++ b/media/libstagefright/include/media/stagefright/RemoteMediaExtractor.h
@@ -27,7 +27,7 @@
 // IMediaExtractor wrapper to the MediaExtractor.
 class RemoteMediaExtractor : public BnMediaExtractor {
 public:
-    static sp<IMediaExtractor> wrap(const sp<MediaExtractor> &extractor);
+    static sp<IMediaExtractor> wrap(const sp<MediaExtractor> &extractor, const sp<RefBase> &plugin);
 
     virtual ~RemoteMediaExtractor();
     virtual size_t countTracks();
@@ -44,10 +44,11 @@
 
 private:
     sp<MediaExtractor> mExtractor;
+    sp<RefBase> mExtractorPlugin;
 
     MediaAnalyticsItem *mAnalyticsItem;
 
-    explicit RemoteMediaExtractor(const sp<MediaExtractor> &extractor);
+    explicit RemoteMediaExtractor(const sp<MediaExtractor> &extractor, const sp<RefBase> &plugin);
 
     DISALLOW_EVIL_CONSTRUCTORS(RemoteMediaExtractor);
 };
diff --git a/media/libstagefright/include/media/stagefright/RemoteMediaSource.h b/media/libstagefright/include/media/stagefright/RemoteMediaSource.h
index 0a446a5..cb222cc 100644
--- a/media/libstagefright/include/media/stagefright/RemoteMediaSource.h
+++ b/media/libstagefright/include/media/stagefright/RemoteMediaSource.h
@@ -26,7 +26,7 @@
 // IMediaSrouce wrapper to the MediaSource.
 class RemoteMediaSource : public BnMediaSource {
 public:
-    static sp<IMediaSource> wrap(const sp<MediaSource> &source);
+    static sp<IMediaSource> wrap(const sp<MediaSource> &source, const sp<RefBase> &plugin);
     virtual ~RemoteMediaSource();
     virtual status_t start(MetaData *params = NULL);
     virtual status_t stop();
@@ -39,8 +39,9 @@
 
 private:
     sp<MediaSource> mSource;
+    sp<RefBase> mExtractorPlugin;
 
-    explicit RemoteMediaSource(const sp<MediaSource> &source);
+    explicit RemoteMediaSource(const sp<MediaSource> &source, const sp<RefBase> &plugin);
 
     DISALLOW_EVIL_CONSTRUCTORS(RemoteMediaSource);
 };
diff --git a/packages/MediaUpdate/Android.mk b/packages/MediaComponents/Android.mk
similarity index 63%
rename from packages/MediaUpdate/Android.mk
rename to packages/MediaComponents/Android.mk
index 4a71401..2fa4a82 100644
--- a/packages/MediaUpdate/Android.mk
+++ b/packages/MediaComponents/Android.mk
@@ -18,9 +18,8 @@
 
 include $(CLEAR_VARS)
 
-LOCAL_PACKAGE_NAME := MediaUpdate
+LOCAL_PACKAGE_NAME := MediaComponents
 LOCAL_MODULE_OWNER := google
-LOCAL_PRIVILEGED_MODULE := true
 
 # TODO: create a separate key for this package.
 LOCAL_CERTIFICATE := platform
@@ -31,4 +30,23 @@
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 LOCAL_PROGUARD_FLAG_FILES := proguard.cfg
 
+LOCAL_MULTILIB := first
+
+# Embed native libraries in package, rather than installing to /system/lib*.
+# TODO: Find a right way to include libs in the apk. b/72066556
+LOCAL_MODULE_TAGS := samples
+
+# To embed native libraries in package, uncomment the lines below.
+LOCAL_JNI_SHARED_LIBRARIES := \
+    libaacextractor \
+    libamrextractor \
+    libflacextractor \
+    libmidiextractor \
+    libmkvextractor \
+    libmp3extractor \
+    libmp4extractor \
+    libmpeg2extractor \
+    liboggextractor \
+    libwavextractor \
+
 include $(BUILD_PACKAGE)
diff --git a/packages/MediaUpdate/AndroidManifest.xml b/packages/MediaComponents/AndroidManifest.xml
similarity index 100%
rename from packages/MediaUpdate/AndroidManifest.xml
rename to packages/MediaComponents/AndroidManifest.xml
diff --git a/packages/MediaUpdate/proguard.cfg b/packages/MediaComponents/proguard.cfg
similarity index 100%
rename from packages/MediaUpdate/proguard.cfg
rename to packages/MediaComponents/proguard.cfg
diff --git a/packages/MediaUpdate/src/com/android/media/update/ApiFactory.java b/packages/MediaComponents/src/com/android/media/update/ApiFactory.java
similarity index 70%
rename from packages/MediaUpdate/src/com/android/media/update/ApiFactory.java
rename to packages/MediaComponents/src/com/android/media/update/ApiFactory.java
index 1cdd177..abff13e 100644
--- a/packages/MediaUpdate/src/com/android/media/update/ApiFactory.java
+++ b/packages/MediaComponents/src/com/android/media/update/ApiFactory.java
@@ -18,21 +18,21 @@
 
 import android.content.Context;
 import android.media.update.MediaController2Provider;
+import android.media.update.VideoView2Provider;
 import android.media.update.StaticProvider;
 import android.media.update.ViewProvider;
 import android.widget.MediaController2;
+import android.widget.VideoView2;
 
 import com.android.widget.MediaController2Impl;
+import com.android.widget.VideoView2Impl;
 
 public class ApiFactory implements StaticProvider {
-    private final Context mContext;
 
-    public ApiFactory(Context context) {
-        mContext = context;
-    }
-
-    public static Object initialize(Context context) throws ReflectiveOperationException {
-        return new ApiFactory(context);
+    public static Object initialize(Context appContext, Context libContext)
+            throws ReflectiveOperationException {
+        ApiHelper.initialize(appContext, libContext);
+        return new ApiFactory();
     }
 
     @Override
@@ -40,4 +40,9 @@
             MediaController2 instance, ViewProvider superProvider) {
         return new MediaController2Impl(instance, superProvider);
     }
+
+    @Override
+    public VideoView2Provider createVideoView2(VideoView2 instance, ViewProvider superProvider) {
+        return new VideoView2Impl(instance, superProvider);
+    }
 }
diff --git a/packages/MediaComponents/src/com/android/media/update/ApiHelper.java b/packages/MediaComponents/src/com/android/media/update/ApiHelper.java
new file mode 100644
index 0000000..550da86
--- /dev/null
+++ b/packages/MediaComponents/src/com/android/media/update/ApiHelper.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2018 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 com.android.media.update;
+
+import android.content.Context;
+import android.content.res.Resources;
+
+public class ApiHelper {
+    private static ApiHelper sInstance;
+    private final Context mAppContext;
+    private final Resources mLibResources;
+    private final Resources.Theme mLibTheme;
+
+    public static ApiHelper getInstance() {
+        return sInstance;
+    }
+
+    static void initialize(Context appContext, Context libContext) {
+        if (sInstance == null) {
+            sInstance = new ApiHelper(appContext, libContext);
+        }
+    }
+
+    private ApiHelper(Context appContext, Context libContext) {
+        mAppContext = appContext;
+        mLibResources = libContext.getResources();
+        mLibTheme = libContext.getTheme();
+    }
+
+    public Resources getLibResources() {
+        return mLibResources;
+    }
+
+    public Resources.Theme getLibTheme() {
+        return mLibTheme;
+    }
+}
diff --git a/packages/MediaUpdate/src/com/android/widget/MediaController2Impl.java b/packages/MediaComponents/src/com/android/widget/MediaController2Impl.java
similarity index 100%
rename from packages/MediaUpdate/src/com/android/widget/MediaController2Impl.java
rename to packages/MediaComponents/src/com/android/widget/MediaController2Impl.java
diff --git a/packages/MediaComponents/src/com/android/widget/VideoView2Impl.java b/packages/MediaComponents/src/com/android/widget/VideoView2Impl.java
new file mode 100644
index 0000000..66b5ed5
--- /dev/null
+++ b/packages/MediaComponents/src/com/android/widget/VideoView2Impl.java
@@ -0,0 +1,258 @@
+/*
+ * Copyright 2018 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 com.android.widget;
+
+import android.graphics.Canvas;
+import android.media.AudioAttributes;
+import android.media.AudioFocusRequest;
+import android.media.MediaPlayer;
+import android.media.update.VideoView2Provider;
+import android.media.update.ViewProvider;
+import android.net.Uri;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+import android.view.View;
+import android.widget.MediaController2;
+import android.widget.VideoView2;
+
+import java.util.Map;
+
+public class VideoView2Impl implements VideoView2Provider, VideoViewInterface.SurfaceListener {
+
+    private final VideoView2 mInstance;
+    private final ViewProvider mSuperProvider;
+
+    public VideoView2Impl(VideoView2 instance, ViewProvider superProvider) {
+        mInstance = instance;
+        mSuperProvider = superProvider;
+
+        // TODO: Implement
+    }
+
+    @Override
+    public void start_impl() {
+        // TODO: Implement
+    }
+
+    @Override
+    public void pause_impl() {
+        // TODO: Implement
+    }
+
+    @Override
+    public int getDuration_impl() {
+        // TODO: Implement
+        return -1;
+    }
+
+    @Override
+    public int getCurrentPosition_impl() {
+        // TODO: Implement
+        return 0;
+    }
+
+    @Override
+    public void seekTo_impl(int msec) {
+        // TODO: Implement
+    }
+
+    @Override
+    public boolean isPlaying_impl() {
+        // TODO: Implement
+        return false;
+    }
+
+    @Override
+    public int getBufferPercentage_impl() {
+        return -1;
+    }
+
+    @Override
+    public int getAudioSessionId_impl() {
+        // TODO: Implement
+        return 0;
+    }
+
+    @Override
+    public void showSubtitle_impl() {
+        // TODO: Implement
+    }
+
+    @Override
+    public void hideSubtitle_impl() {
+        // TODO: Implement
+    }
+
+    @Override
+    public void setAudioFocusRequest_impl(int focusGain) {
+        // TODO: Implement
+    }
+
+    @Override
+    public void setAudioAttributes_impl(AudioAttributes attributes) {
+        // TODO: Implement
+    }
+
+    @Override
+    public void setVideoPath_impl(String path) {
+        // TODO: Implement
+    }
+
+    @Override
+    public void setVideoURI_impl(Uri uri) {
+        // TODO: Implement
+    }
+
+    @Override
+    public void setVideoURI_impl(Uri uri, Map<String, String> headers) {
+        // TODO: Implement
+    }
+
+    @Override
+    public void setMediaController2_impl(MediaController2 controllerView) {
+        // TODO: Implement
+    }
+
+    @Override
+    public void setViewType_impl(int viewType) {
+        // TODO: Implement
+    }
+
+    @Override
+    public int getViewType_impl() {
+        // TODO: Implement
+        return -1;
+    }
+
+    @Override
+    public void stopPlayback_impl() {
+        // TODO: Implement
+    }
+
+    @Override
+    public void setOnPreparedListener_impl(MediaPlayer.OnPreparedListener l) {
+        // TODO: Implement
+    }
+
+    @Override
+    public void setOnCompletionListener_impl(MediaPlayer.OnCompletionListener l) {
+        // TODO: Implement
+    }
+
+    @Override
+    public void setOnErrorListener_impl(MediaPlayer.OnErrorListener l) {
+        // TODO: Implement
+    }
+
+    @Override
+    public void setOnInfoListener_impl(MediaPlayer.OnInfoListener l) {
+        // TODO: Implement
+    }
+
+    @Override
+    public void setOnViewTypeChangedListener_impl(VideoView2.OnViewTypeChangedListener l) {
+        // TODO: Implement
+    }
+
+    @Override
+    public void onAttachedToWindow_impl() {
+        mSuperProvider.onAttachedToWindow_impl();
+        // TODO: Implement
+    }
+
+    @Override
+    public void onDetachedFromWindow_impl() {
+        mSuperProvider.onDetachedFromWindow_impl();
+        // TODO: Implement
+    }
+
+    @Override
+    public void onLayout_impl(boolean changed, int left, int top, int right, int bottom) {
+        mSuperProvider.onLayout_impl(changed, left, top, right, bottom);
+        // TODO: Implement
+    }
+
+    @Override
+    public void draw_impl(Canvas canvas) {
+        mSuperProvider.draw_impl(canvas);
+        // TODO: Implement
+    }
+
+    @Override
+    public CharSequence getAccessibilityClassName_impl() {
+        // TODO: Implement
+        return null;
+    }
+
+    @Override
+    public boolean onTouchEvent_impl(MotionEvent ev) {
+        // TODO: Implement
+        return false;
+    }
+
+    @Override
+    public boolean onTrackballEvent_impl(MotionEvent ev) {
+        // TODO: Implement
+        return false;
+    }
+
+    @Override
+    public boolean onKeyDown_impl(int keyCode, KeyEvent event) {
+        // TODO: Implement
+        return false;
+    }
+
+    @Override
+    public void onFinishInflate_impl() {
+        // TODO: Implement
+    }
+
+    @Override
+    public boolean dispatchKeyEvent_impl(KeyEvent event) {
+        // TODO: Implement
+        return false;
+    }
+
+    @Override
+    public void setEnabled_impl(boolean enabled) {
+        // TODO: Implement
+    }
+
+    ///////////////////////////////////////////////////
+    // Implements VideoViewInterface.SurfaceListener
+    ///////////////////////////////////////////////////
+
+    @Override
+    public void onSurfaceCreated(View view, int width, int height) {
+        // TODO: Implement
+    }
+
+    @Override
+    public void onSurfaceDestroyed(View view) {
+        // TODO: Implement
+    }
+
+    @Override
+    public void onSurfaceChanged(View view, int width, int height) {
+        // TODO: Implement
+    }
+
+    @Override
+    public void onSurfaceTakeOverDone(VideoViewInterface view) {
+        // TODO: Implement
+    }
+}
diff --git a/packages/MediaComponents/src/com/android/widget/VideoViewInterface.java b/packages/MediaComponents/src/com/android/widget/VideoViewInterface.java
new file mode 100644
index 0000000..2a5eb94
--- /dev/null
+++ b/packages/MediaComponents/src/com/android/widget/VideoViewInterface.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2018 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 com.android.widget;
+
+import android.annotation.NonNull;
+import android.media.MediaPlayer;
+import android.view.View;
+
+interface VideoViewInterface {
+    /**
+     * Assigns the view's surface to the given MediaPlayer instance.
+     *
+     * @param mp MediaPlayer
+     * @return true if the surface is successfully assigned, false if not. It will fail to assign
+     *         if any of MediaPlayer or surface is unavailable.
+     */
+    boolean assignSurfaceToMediaPlayer(MediaPlayer mp);
+    void setSurfaceListener(SurfaceListener l);
+    int getViewType();
+    void setMediaPlayer(MediaPlayer mp);
+
+    /**
+     * Takes over oldView. It means that the MediaPlayer will start rendering on this view.
+     * The visibility of oldView will be set as {@link View.GONE}. If the view doesn't have a
+     * MediaPlayer instance or its surface is not available, the actual execution is deferred until
+     * a MediaPlayer instance is set by {@link #setMediaPlayer} or its surface becomes available.
+     * {@link SurfaceListener.onSurfaceTakeOverDone} will be called when the actual execution is
+     * done.
+     *
+     * @param oldView The view that MediaPlayer is currently rendering on.
+     */
+    void takeOver(@NonNull VideoViewInterface oldView);
+
+    /**
+     * Indicates if the view's surface is available.
+     *
+     * @return true if the surface is available.
+     */
+    boolean hasAvailableSurface();
+
+    /**
+     * An instance of VideoViewInterface calls these surface notification methods accordingly if
+     * a listener has been registered via {@link #setSurfaceListener(SurfaceListener)}.
+     */
+    interface SurfaceListener {
+        void onSurfaceCreated(View view, int width, int height);
+        void onSurfaceDestroyed(View view);
+        void onSurfaceChanged(View view, int width, int height);
+        void onSurfaceTakeOverDone(VideoViewInterface view);
+    }
+}
diff --git a/services/mediaanalytics/MediaAnalyticsService.cpp b/services/mediaanalytics/MediaAnalyticsService.cpp
index 7f42b1b..2954b3b 100644
--- a/services/mediaanalytics/MediaAnalyticsService.cpp
+++ b/services/mediaanalytics/MediaAnalyticsService.cpp
@@ -389,7 +389,7 @@
     nsecs_t ts_since = 0;
     String16 helpOption("-help");
     String16 onlyOption("-only");
-    AString only;
+    std::string only;
     int n = args.size();
 
     for (int i = 0; i < n; i++) {
@@ -553,7 +553,7 @@
                 if (only != NULL && strcmp(only, (*it)->getKey()) != 0) {
                     ALOGV("Told to omit '%s'", (*it)->getKey());
                 }
-                AString distilled = (*it)->dumpSummary(slot, only);
+                std::string distilled = (*it)->dumpSummary(slot, only);
                 result.append(distilled.c_str());
             }
         }
@@ -605,7 +605,7 @@
                 ALOGV("Omit '%s', it's not '%s'", (*it)->getKey().c_str(), only);
                 continue;
             }
-            AString entry = (*it)->toString(mDumpProto);
+            std::string entry = (*it)->toString(mDumpProto);
             result.appendFormat("%5d: %s\n", slot, entry.c_str());
             slot++;
         }
@@ -746,7 +746,7 @@
     }
 }
 
-static AString allowedKeys[] =
+static std::string allowedKeys[] =
 {
     "codec",
     "extractor"
@@ -760,7 +760,7 @@
     // untrusted uids can only send us a limited set of keys
     if (isTrusted == false) {
         // restrict to a specific set of keys
-        AString key = item->getKey();
+        std::string key = item->getKey();
 
         size_t i;
         for(i = 0; i < nAllowedKeys; i++) {
@@ -854,7 +854,7 @@
             return setPkgInfo(item, uid, setName, setVersion);
         }
     } else {
-        AString pkg;
+        std::string pkg;
         std::string installer = "";
         int64_t versionCode = 0;
 
@@ -896,7 +896,7 @@
             }
 
             // strip any leading "shared:" strings that came back
-            if (pkg.startsWith("shared:")) {
+            if (pkg.compare(0, 7, "shared:") == 0) {
                 pkg.erase(0, 7);
             }
 
diff --git a/services/mediaanalytics/MediaAnalyticsService.h b/services/mediaanalytics/MediaAnalyticsService.h
index fce7d08..1287835 100644
--- a/services/mediaanalytics/MediaAnalyticsService.h
+++ b/services/mediaanalytics/MediaAnalyticsService.h
@@ -136,8 +136,8 @@
     // mapping uids to package names
     struct UidToPkgMap {
         uid_t uid;
-        AString pkg;
-        AString installer;
+        std::string pkg;
+        std::string installer;
         int64_t versionCode;
         nsecs_t expiration;
     };
diff --git a/services/mediaanalytics/MetricsSummarizer.cpp b/services/mediaanalytics/MetricsSummarizer.cpp
index 93fe0ec..e7c26e3 100644
--- a/services/mediaanalytics/MetricsSummarizer.cpp
+++ b/services/mediaanalytics/MetricsSummarizer.cpp
@@ -19,6 +19,7 @@
 
 #include <stdlib.h>
 #include <stdint.h>
+#include <string>
 #include <inttypes.h>
 
 #include <utils/threads.h>
@@ -87,21 +88,21 @@
 {
     if (mKey == NULL)
         return true;
-    AString itemKey = item.getKey();
+    std::string itemKey = item.getKey();
     if (strcmp(mKey, itemKey.c_str()) != 0) {
         return false;
     }
     return true;
 }
 
-AString MetricsSummarizer::dumpSummary(int &slot)
+std::string MetricsSummarizer::dumpSummary(int &slot)
 {
     return dumpSummary(slot, NULL);
 }
 
-AString MetricsSummarizer::dumpSummary(int &slot, const char *only)
+std::string MetricsSummarizer::dumpSummary(int &slot, const char *only)
 {
-    AString value = "";
+    std::string value;
 
     List<MediaAnalyticsItem *>::iterator it = mSummaries->begin();
     if (it != mSummaries->end()) {
@@ -110,7 +111,7 @@
             if (only != NULL && strcmp(only, (*it)->getKey().c_str()) != 0) {
                 continue;
             }
-            AString entry = (*it)->toString();
+            std::string entry = (*it)->toString();
             snprintf(buf, sizeof(buf), "%5d: ", slot);
             value.append(buf);
             value.append(entry.c_str());
diff --git a/services/mediaanalytics/MetricsSummarizer.h b/services/mediaanalytics/MetricsSummarizer.h
index a9f0786..a16c7bc 100644
--- a/services/mediaanalytics/MetricsSummarizer.h
+++ b/services/mediaanalytics/MetricsSummarizer.h
@@ -18,10 +18,10 @@
 #ifndef ANDROID_METRICSSUMMARIZER_H
 #define ANDROID_METRICSSUMMARIZER_H
 
+#include <string>
 #include <utils/threads.h>
 #include <utils/Errors.h>
 #include <utils/KeyedVector.h>
-#include <utils/String8.h>
 #include <utils/List.h>
 
 #include <media/IMediaAnalyticsService.h>
@@ -49,8 +49,8 @@
     virtual void mergeRecord(MediaAnalyticsItem &have, MediaAnalyticsItem &incoming);
 
     // dump the summarized records (for dumpsys)
-    AString dumpSummary(int &slot);
-    AString dumpSummary(int &slot, const char *only);
+    std::string dumpSummary(int &slot);
+    std::string dumpSummary(int &slot, const char *only);
 
     void setIgnorables(const char **);
     const char **getIgnorables();
diff --git a/services/mediaextractor/Android.mk b/services/mediaextractor/Android.mk
index cd086f9..4980316 100644
--- a/services/mediaextractor/Android.mk
+++ b/services/mediaextractor/Android.mk
@@ -2,8 +2,11 @@
 
 # service library
 include $(CLEAR_VARS)
-LOCAL_SRC_FILES := MediaExtractorService.cpp
 LOCAL_CFLAGS := -Wall -Werror
+LOCAL_SRC_FILES := \
+    MediaExtractorService.cpp \
+    MediaExtractorUpdateService.cpp \
+
 LOCAL_SHARED_LIBRARIES := libmedia libstagefright libbinder libutils liblog
 LOCAL_MODULE:= libmediaextractorservice
 include $(BUILD_SHARED_LIBRARY)
@@ -18,16 +21,7 @@
 
 # extractor libraries
 LOCAL_REQUIRED_MODULES := \
-    libaacextractor \
-    libamrextractor \
-    libflacextractor \
-    libmidiextractor \
-    libmkvextractor \
-    libmp3extractor \
-    libmp4extractor \
-    libmpeg2extractor \
-    liboggextractor \
-    libwavextractor \
+    MediaComponents \
 
 LOCAL_SRC_FILES := main_extractorservice.cpp
 LOCAL_SHARED_LIBRARIES := libmedia libmediaextractorservice libbinder libutils \
diff --git a/services/mediaextractor/MediaExtractorService.cpp b/services/mediaextractor/MediaExtractorService.cpp
index f09d7cf..0dc1fce 100644
--- a/services/mediaextractor/MediaExtractorService.cpp
+++ b/services/mediaextractor/MediaExtractorService.cpp
@@ -36,16 +36,15 @@
 
     sp<DataSource> localSource = CreateDataSourceFromIDataSource(remoteSource);
 
-    sp<MediaExtractor> extractor = MediaExtractorFactory::CreateFromService(localSource, mime);
+    sp<IMediaExtractor> extractor = MediaExtractorFactory::CreateFromService(localSource, mime);
 
     ALOGV("extractor service created %p (%s)",
             extractor.get(),
             extractor == nullptr ? "" : extractor->name());
 
     if (extractor != nullptr) {
-        sp<IMediaExtractor> ret = CreateIMediaExtractorFromMediaExtractor(extractor);
-        registerMediaExtractor(ret, localSource, mime);
-        return ret;
+        registerMediaExtractor(extractor, localSource, mime);
+        return extractor;
     }
     return nullptr;
 }
diff --git a/services/mediaextractor/MediaExtractorUpdateService.cpp b/services/mediaextractor/MediaExtractorUpdateService.cpp
new file mode 100644
index 0000000..473a698
--- /dev/null
+++ b/services/mediaextractor/MediaExtractorUpdateService.cpp
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2018 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.
+ */
+
+#define LOG_TAG "MediaExtractorUpdateService"
+#define LOG_NDEBUG 0
+#include <utils/Log.h>
+
+#include <media/stagefright/MediaExtractorFactory.h>
+
+#include "MediaExtractorUpdateService.h"
+
+namespace android {
+namespace media {
+
+binder::Status MediaExtractorUpdateService::loadPlugins(const ::std::string& apkPath) {
+    ALOGV("loadPlugins %s", apkPath.c_str());
+    MediaExtractorFactory::LoadPlugins(apkPath);
+    return binder::Status::ok();
+}
+
+}   // namespace media
+}   // namespace android
diff --git a/services/mediaextractor/MediaExtractorUpdateService.h b/services/mediaextractor/MediaExtractorUpdateService.h
new file mode 100644
index 0000000..4115f6d
--- /dev/null
+++ b/services/mediaextractor/MediaExtractorUpdateService.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2018 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.
+ */
+
+#ifndef ANDROID_MEDIA_EXTRACTOR_UPDATE_SERVICE_H
+#define ANDROID_MEDIA_EXTRACTOR_UPDATE_SERVICE_H
+
+#include <binder/BinderService.h>
+#include <android/media/BnMediaExtractorUpdateService.h>
+
+namespace android {
+namespace media {
+
+class MediaExtractorUpdateService
+    : public BinderService<MediaExtractorUpdateService>, public BnMediaExtractorUpdateService
+{
+    friend class BinderService<MediaExtractorUpdateService>;
+public:
+    MediaExtractorUpdateService() : BnMediaExtractorUpdateService() { }
+    virtual ~MediaExtractorUpdateService() { }
+    static const char* getServiceName() { return "media.extractor.update"; }
+    binder::Status loadPlugins(const ::std::string& apkPath);
+};
+
+}   // namespace media
+}   // namespace android
+
+#endif  // ANDROID_MEDIA_EXTRACTOR_UPDATE_SERVICE_H
diff --git a/services/mediaextractor/main_extractorservice.cpp b/services/mediaextractor/main_extractorservice.cpp
index 6a5320d..0dc5e29 100644
--- a/services/mediaextractor/main_extractorservice.cpp
+++ b/services/mediaextractor/main_extractorservice.cpp
@@ -30,6 +30,7 @@
 // from LOCAL_C_INCLUDES
 #include "IcuUtils.h"
 #include "MediaExtractorService.h"
+#include "MediaExtractorUpdateService.h"
 #include "MediaUtils.h"
 #include "minijail.h"
 
@@ -63,6 +64,16 @@
     sp<ProcessState> proc(ProcessState::self());
     sp<IServiceManager> sm = defaultServiceManager();
     MediaExtractorService::instantiate();
+
+    // TODO: Uncomment below once sepolicy change is landed.
+    /*
+    char value[PROPERTY_VALUE_MAX];
+    property_get("ro.build.type", value, "unknown");
+    if (strcmp(value, "userdebug") == 0 || strcmp(value, "eng") == 0) {
+        media::MediaExtractorUpdateService::instantiate();
+    }
+    */
+
     ProcessState::self()->startThreadPool();
     IPCThreadState::self()->joinThreadPool();
 }
diff --git a/services/oboeservice/AAudioServiceEndpoint.cpp b/services/oboeservice/AAudioServiceEndpoint.cpp
index f917675..01e9c6f 100644
--- a/services/oboeservice/AAudioServiceEndpoint.cpp
+++ b/services/oboeservice/AAudioServiceEndpoint.cpp
@@ -55,11 +55,15 @@
 
     result << "    Direction:            " << ((getDirection() == AAUDIO_DIRECTION_OUTPUT)
                                    ? "OUTPUT" : "INPUT") << "\n";
-    result << "    Sample Rate:          " << getSampleRate() << "\n";
-    result << "    Frames Per Burst:     " << mFramesPerBurst << "\n";
-    result << "    Reference Count:      " << mOpenCount << "\n";
     result << "    Requested Device Id:  " << mRequestedDeviceId << "\n";
     result << "    Device Id:            " << getDeviceId() << "\n";
+    result << "    Sample Rate:          " << getSampleRate() << "\n";
+    result << "    Channel Count:        " << getSamplesPerFrame() << "\n";
+    result << "    Frames Per Burst:     " << mFramesPerBurst << "\n";
+    result << "    Usage:                " << getUsage() << "\n";
+    result << "    ContentType:          " << getContentType() << "\n";
+    result << "    InputPreset:          " << getInputPreset() << "\n";
+    result << "    Reference Count:      " << mOpenCount << "\n";
     result << "    Connected:            " << mConnected.load() << "\n";
     result << "    Registered Streams:" << "\n";
     result << AAudioServiceStreamShared::dumpHeader() << "\n";
diff --git a/services/oboeservice/AAudioServiceEndpointMMAP.cpp b/services/oboeservice/AAudioServiceEndpointMMAP.cpp
index a61994d..541be20 100644
--- a/services/oboeservice/AAudioServiceEndpointMMAP.cpp
+++ b/services/oboeservice/AAudioServiceEndpointMMAP.cpp
@@ -72,13 +72,6 @@
 
 aaudio_result_t AAudioServiceEndpointMMAP::open(const aaudio::AAudioStreamRequest &request) {
     aaudio_result_t result = AAUDIO_OK;
-    const audio_attributes_t attributes = {
-            .content_type = AUDIO_CONTENT_TYPE_MUSIC,
-            .usage = AUDIO_USAGE_MEDIA,
-            .source = AUDIO_SOURCE_VOICE_RECOGNITION,
-            .flags = AUDIO_FLAG_LOW_LATENCY,
-            .tags = ""
-    };
     audio_config_base_t config;
     audio_port_handle_t deviceId;
 
@@ -87,6 +80,27 @@
 
     copyFrom(request.getConstantConfiguration());
 
+    aaudio_direction_t direction = getDirection();
+
+    const audio_content_type_t contentType =
+            AAudioConvert_contentTypeToInternal(getContentType());
+    const audio_usage_t usage = (direction == AAUDIO_DIRECTION_OUTPUT)
+            ? AAudioConvert_usageToInternal(getUsage())
+            : AUDIO_USAGE_UNKNOWN;
+    const audio_source_t source = (direction == AAUDIO_DIRECTION_INPUT)
+            ? AAudioConvert_inputPresetToAudioSource(getInputPreset())
+            : AUDIO_SOURCE_DEFAULT;
+
+    const audio_attributes_t attributes = {
+            .content_type = contentType,
+            .usage = usage,
+            .source = source,
+            .flags = AUDIO_FLAG_LOW_LATENCY,
+            .tags = ""
+    };
+    ALOGV("open() MMAP attributes.usage = %d, content_type = %d, source = %d",
+          attributes.usage, attributes.content_type, attributes.source);
+
     mMmapClient.clientUid = request.getUserId();
     mMmapClient.clientPid = request.getProcessId();
     mMmapClient.packageName.setTo(String16(""));
@@ -108,7 +122,6 @@
 
     int32_t aaudioSamplesPerFrame = getSamplesPerFrame();
 
-    aaudio_direction_t direction = getDirection();
     if (direction == AAUDIO_DIRECTION_OUTPUT) {
         config.channel_mask = (aaudioSamplesPerFrame == AAUDIO_UNSPECIFIED)
                               ? AUDIO_CHANNEL_OUT_STEREO
diff --git a/services/oboeservice/AAudioServiceEndpointShared.cpp b/services/oboeservice/AAudioServiceEndpointShared.cpp
index 6af9e7e..2de537a 100644
--- a/services/oboeservice/AAudioServiceEndpointShared.cpp
+++ b/services/oboeservice/AAudioServiceEndpointShared.cpp
@@ -60,18 +60,16 @@
     aaudio_result_t result = AAUDIO_OK;
     const AAudioStreamConfiguration &configuration = request.getConstantConfiguration();
 
+    copyFrom(configuration);
     mRequestedDeviceId = configuration.getDeviceId();
-    setDirection(configuration.getDirection());
 
     AudioStreamBuilder builder;
+    builder.copyFrom(configuration);
+
     builder.setSharingMode(AAUDIO_SHARING_MODE_EXCLUSIVE);
     // Don't fall back to SHARED because that would cause recursion.
     builder.setSharingModeMatchRequired(true);
-    builder.setDeviceId(mRequestedDeviceId);
-    builder.setFormat(configuration.getFormat());
-    builder.setSampleRate(configuration.getSampleRate());
-    builder.setSamplesPerFrame(configuration.getSamplesPerFrame());
-    builder.setDirection(configuration.getDirection());
+
     builder.setBufferCapacity(DEFAULT_BUFFER_CAPACITY);
 
     result = mStreamInternal->open(builder);
diff --git a/services/oboeservice/AAudioServiceStreamBase.cpp b/services/oboeservice/AAudioServiceStreamBase.cpp
index 53d2860..864fc35 100644
--- a/services/oboeservice/AAudioServiceStreamBase.cpp
+++ b/services/oboeservice/AAudioServiceStreamBase.cpp
@@ -42,7 +42,7 @@
 
 AAudioServiceStreamBase::AAudioServiceStreamBase(AAudioService &audioService)
         : mUpMessageQueue(nullptr)
-        , mTimestampThread()
+        , mTimestampThread("AATime")
         , mAtomicTimestamp()
         , mAudioService(audioService) {
     mMmapClient.clientUid = -1;
diff --git a/services/oboeservice/AAudioThread.cpp b/services/oboeservice/AAudioThread.cpp
index fbb0da4..ed7895b 100644
--- a/services/oboeservice/AAudioThread.cpp
+++ b/services/oboeservice/AAudioThread.cpp
@@ -27,12 +27,26 @@
 
 using namespace aaudio;
 
+std::atomic<uint32_t> AAudioThread::mNextThreadIndex{1};
 
-AAudioThread::AAudioThread()
-    : mRunnable(nullptr)
-    , mHasThread(false) {
+AAudioThread::AAudioThread(const char *prefix) {
+    setup(prefix);
+}
+
+AAudioThread::AAudioThread() {
+    setup("AAudio");
+}
+
+void AAudioThread::setup(const char *prefix) {
     // mThread is a pthread_t of unknown size so we need memset().
     memset(&mThread, 0, sizeof(mThread));
+
+    // Name the thread with an increasing index, "prefix_#", for debugging.
+    uint32_t index = mNextThreadIndex++;
+    // Wrap the index so that we do not hit the 16 char limit
+    // and to avoid hard-to-read large numbers.
+    index = index % 100000; // arbitrary
+    snprintf(mName, sizeof(mName), "%s_%u", prefix, index);
 }
 
 void AAudioThread::dispatch() {
@@ -64,6 +78,8 @@
         ALOGE("start() - pthread_create() returned %d %s", err, strerror(err));
         return AAudioConvert_androidToAAudioResult(-err);
     } else {
+        int err = pthread_setname_np(mThread, mName);
+        ALOGW_IF((err != 0), "Could not set name of AAudioThread. err = %d", err);
         mHasThread = true;
         return AAUDIO_OK;
     }
diff --git a/services/oboeservice/AAudioThread.h b/services/oboeservice/AAudioThread.h
index 02f1459..ffc9b7b 100644
--- a/services/oboeservice/AAudioThread.h
+++ b/services/oboeservice/AAudioThread.h
@@ -43,7 +43,9 @@
 {
 public:
     AAudioThread();
-    AAudioThread(Runnable *runnable);
+
+    AAudioThread(const char *prefix);
+
     virtual ~AAudioThread() = default;
 
     /**
@@ -66,10 +68,15 @@
     void dispatch(); // called internally from 'C' thread wrapper
 
 private:
-    Runnable    *mRunnable;
-    bool         mHasThread;
+
+    void setup(const char *prefix);
+
+    Runnable    *mRunnable = nullptr;
+    bool         mHasThread = false;
     pthread_t    mThread; // initialized in constructor
 
+    static std::atomic<uint32_t> mNextThreadIndex;
+    char         mName[16]; // max length for a pthread_name
 };
 
 } /* namespace aaudio */