Merge "Camera: keep camera device alive during dump"
diff --git a/Android.bp b/Android.bp
index a3679b1..e4f12c8 100644
--- a/Android.bp
+++ b/Android.bp
@@ -2,5 +2,6 @@
     "camera",
     "drm/*",
     "media/*",
+    "services/*",
     "soundtrigger",
 ]
diff --git a/camera/ndk/impl/ACameraDevice.cpp b/camera/ndk/impl/ACameraDevice.cpp
index af977b8..907802c 100644
--- a/camera/ndk/impl/ACameraDevice.cpp
+++ b/camera/ndk/impl/ACameraDevice.cpp
@@ -59,7 +59,8 @@
         mWrapper(wrapper),
         mInError(false),
         mError(ACAMERA_OK),
-        mIdle(true) {
+        mIdle(true),
+        mCurrentSession(nullptr) {
     mClosing = false;
     // Setup looper thread to perfrom device callbacks to app
     mCbLooper = new ALooper;
@@ -98,18 +99,30 @@
 
 // Device close implementaiton
 CameraDevice::~CameraDevice() {
-    Mutex::Autolock _l(mDeviceLock);
-    if (!isClosed()) {
-        disconnectLocked();
-    }
-    if (mCbLooper != nullptr) {
-        mCbLooper->unregisterHandler(mHandler->id());
-        mCbLooper->stop();
+    sp<ACameraCaptureSession> session = mCurrentSession.promote();
+    {
+        Mutex::Autolock _l(mDeviceLock);
+        if (!isClosed()) {
+            disconnectLocked(session);
+        }
+        mCurrentSession = nullptr;
+        if (mCbLooper != nullptr) {
+            mCbLooper->unregisterHandler(mHandler->id());
+            mCbLooper->stop();
+        }
     }
     mCbLooper.clear();
     mHandler.clear();
 }
 
+void
+CameraDevice::postSessionMsgAndCleanup(sp<AMessage>& msg) {
+    msg->post();
+    msg.clear();
+    sp<AMessage> cleanupMsg = new AMessage(kWhatCleanUpSessions, mHandler);
+    cleanupMsg->post();
+}
+
 // TODO: cached created request?
 camera_status_t
 CameraDevice::createCaptureRequest(
@@ -146,14 +159,15 @@
         const ACaptureSessionOutputContainer*       outputs,
         const ACameraCaptureSession_stateCallbacks* callbacks,
         /*out*/ACameraCaptureSession** session) {
+    sp<ACameraCaptureSession> currentSession = mCurrentSession.promote();
     Mutex::Autolock _l(mDeviceLock);
     camera_status_t ret = checkCameraClosedOrErrorLocked();
     if (ret != ACAMERA_OK) {
         return ret;
     }
 
-    if (mCurrentSession != nullptr) {
-        mCurrentSession->closeByDevice();
+    if (currentSession != nullptr) {
+        currentSession->closeByDevice();
         stopRepeatingLocked();
     }
 
@@ -264,7 +278,7 @@
         msg->setPointer(kContextKey, session->mUserSessionCallback.context);
         msg->setObject(kSessionSpKey, session);
         msg->setPointer(kCallbackFpKey, (void*) session->mUserSessionCallback.onActive);
-        msg->post();
+        postSessionMsgAndCleanup(msg);
     }
     mIdle = false;
     mBusySession = session;
@@ -328,7 +342,7 @@
         return;
     }
 
-    if (session != mCurrentSession) {
+    if (mCurrentSession != session) {
         // Session has been replaced by other seesion or device is closed
         return;
     }
@@ -349,7 +363,7 @@
 }
 
 void
-CameraDevice::disconnectLocked() {
+CameraDevice::disconnectLocked(sp<ACameraCaptureSession>& session) {
     if (mClosing.exchange(true)) {
         // Already closing, just return
         ALOGW("Camera device %s is already closing.", getId());
@@ -361,9 +375,8 @@
     }
     mRemote = nullptr;
 
-    if (mCurrentSession != nullptr) {
-        mCurrentSession->closeByDevice();
-        mCurrentSession = nullptr;
+    if (session != nullptr) {
+        session->closeByDevice();
     }
 }
 
@@ -404,7 +417,7 @@
     // This should never happen because creating a new session will close
     // previous one and thus reject any API call from previous session.
     // But still good to check here in case something unexpected happen.
-    if (session != mCurrentSession) {
+    if (mCurrentSession != session) {
         ALOGE("Camera %s session %p is not current active session!", getId(), session);
         return ACAMERA_ERROR_INVALID_OPERATION;
     }
@@ -415,12 +428,13 @@
     }
 
     mFlushing = true;
+
     // Send onActive callback to guarantee there is always active->ready transition
     sp<AMessage> msg = new AMessage(kWhatSessionStateCb, mHandler);
     msg->setPointer(kContextKey, session->mUserSessionCallback.context);
     msg->setObject(kSessionSpKey, session);
     msg->setPointer(kCallbackFpKey, (void*) session->mUserSessionCallback.onActive);
-    msg->post();
+    postSessionMsgAndCleanup(msg);
 
     // If device is already idling, send callback and exit early
     if (mIdle) {
@@ -428,7 +442,7 @@
         msg->setPointer(kContextKey, session->mUserSessionCallback.context);
         msg->setObject(kSessionSpKey, session);
         msg->setPointer(kCallbackFpKey, (void*) session->mUserSessionCallback.onReady);
-        msg->post();
+        postSessionMsgAndCleanup(msg);
         mFlushing = false;
         return ACAMERA_OK;
     }
@@ -568,7 +582,7 @@
         msg->setObject(kSessionSpKey, mBusySession);
         msg->setPointer(kCallbackFpKey, (void*) mBusySession->mUserSessionCallback.onReady);
         mBusySession.clear();
-        msg->post();
+        postSessionMsgAndCleanup(msg);
     }
     mIdle = true;
 
@@ -728,7 +742,7 @@
         msg->setObject(kCaptureRequestKey, request);
         msg->setPointer(kAnwKey, (void*) anw);
         msg->setInt64(kFrameNumberKey, frameNumber);
-        msg->post();
+        postSessionMsgAndCleanup(msg);
     } else { // Handle other capture failures
         // Fire capture failure callback if there is one registered
         ACameraCaptureSession_captureCallback_failed onError = cbh.mCallbacks.onCaptureFailed;
@@ -746,7 +760,7 @@
         msg->setPointer(kCallbackFpKey, (void*) onError);
         msg->setObject(kCaptureRequestKey, request);
         msg->setObject(kCaptureFailureKey, failure);
-        msg->post();
+        postSessionMsgAndCleanup(msg);
 
         // Update tracker
         mFrameNumberTracker.updateTracker(frameNumber, /*isError*/true);
@@ -769,6 +783,9 @@
         case kWhatCaptureBufferLost:
             ALOGV("%s: Received msg %d", __FUNCTION__, msg->what());
             break;
+        case kWhatCleanUpSessions:
+            mCachedSessions.clear();
+            return;
         default:
             ALOGE("%s:Error: unknown device callback %d", __FUNCTION__, msg->what());
             return;
@@ -842,6 +859,7 @@
                 return;
             }
             sp<ACameraCaptureSession> session(static_cast<ACameraCaptureSession*>(obj.get()));
+            mCachedSessions.push(session);
             sp<CaptureRequest> requestSp = nullptr;
             switch (msg->what()) {
                 case kWhatCaptureStart:
@@ -1053,7 +1071,7 @@
         msg->setObject(kSessionSpKey, cbh.mSession);
         msg->setPointer(kCallbackFpKey, (void*) cbh.mCallbacks.onCaptureSequenceAborted);
         msg->setInt32(kSequenceIdKey, sequenceId);
-        msg->post();
+        postSessionMsgAndCleanup(msg);
     } else {
         // Use mSequenceLastFrameNumberMap to track
         mSequenceLastFrameNumberMap.insert(std::make_pair(sequenceId, lastFrameNumber));
@@ -1110,7 +1128,7 @@
             // before cbh goes out of scope and causing we call the session
             // destructor while holding device lock
             cbh.mSession.clear();
-            msg->post();
+            postSessionMsgAndCleanup(msg);
         }
 
         // No need to track sequence complete if there is no callback registered
@@ -1137,6 +1155,7 @@
         return ret; // device has been closed
     }
 
+    sp<ACameraCaptureSession> session = dev->mCurrentSession.promote();
     Mutex::Autolock _l(dev->mDeviceLock);
     if (dev->mRemote == nullptr) {
         return ret; // device has been closed
@@ -1145,10 +1164,10 @@
         case ERROR_CAMERA_DISCONNECTED:
         {
             // Camera is disconnected, close the session and expect no more callbacks
-            if (dev->mCurrentSession != nullptr) {
-                dev->mCurrentSession->closeByDevice();
-                dev->mCurrentSession = nullptr;
+            if (session != nullptr) {
+                session->closeByDevice();
             }
+            dev->mCurrentSession = nullptr;
             sp<AMessage> msg = new AMessage(kWhatOnDisconnected, dev->mHandler);
             msg->setPointer(kContextKey, dev->mAppCallbacks.context);
             msg->setPointer(kDeviceKey, (void*) dev->getWrapper());
@@ -1216,6 +1235,7 @@
             dev->setCameraDeviceErrorLocked(ACAMERA_ERROR_CAMERA_DEVICE);
             return ret;
         }
+
         sp<AMessage> msg = new AMessage(kWhatSessionStateCb, dev->mHandler);
         msg->setPointer(kContextKey, dev->mBusySession->mUserSessionCallback.context);
         msg->setObject(kSessionSpKey, dev->mBusySession);
@@ -1223,7 +1243,7 @@
         // Make sure we clear the sp first so the session destructor can
         // only happen on handler thread (where we don't hold device/session lock)
         dev->mBusySession.clear();
-        msg->post();
+        dev->postSessionMsgAndCleanup(msg);
     }
     dev->mIdle = true;
     dev->mFlushing = false;
@@ -1265,7 +1285,7 @@
         msg->setPointer(kCallbackFpKey, (void*) onStart);
         msg->setObject(kCaptureRequestKey, request);
         msg->setInt64(kTimeStampKey, timestamp);
-        msg->post();
+        dev->postSessionMsgAndCleanup(msg);
     }
     return ret;
 }
@@ -1328,7 +1348,7 @@
         msg->setPointer(kCallbackFpKey, (void*) onResult);
         msg->setObject(kCaptureRequestKey, request);
         msg->setObject(kCaptureResultKey, result);
-        msg->post();
+        dev->postSessionMsgAndCleanup(msg);
     }
 
     if (!isPartialResult) {
diff --git a/camera/ndk/impl/ACameraDevice.h b/camera/ndk/impl/ACameraDevice.h
index 78a7891..6ed3881 100644
--- a/camera/ndk/impl/ACameraDevice.h
+++ b/camera/ndk/impl/ACameraDevice.h
@@ -96,7 +96,7 @@
     // device goes into fatal error state after this
     void setCameraDeviceErrorLocked(camera_status_t error);
 
-    void disconnectLocked(); // disconnect from camera service
+    void disconnectLocked(sp<ACameraCaptureSession>& session); // disconnect from camera service
 
     camera_status_t stopRepeatingLocked();
 
@@ -138,6 +138,9 @@
 
     camera_status_t configureStreamsLocked(const ACaptureSessionOutputContainer* outputs);
 
+    // Input message will be posted and cleared after this returns
+    void postSessionMsgAndCleanup(sp<AMessage>& msg);
+
     static camera_status_t getIGBPfromAnw(
             ANativeWindow* anw, sp<IGraphicBufferProducer>& out);
 
@@ -185,7 +188,9 @@
         kWhatCaptureFail,      // onCaptureFailed
         kWhatCaptureSeqEnd,    // onCaptureSequenceCompleted
         kWhatCaptureSeqAbort,  // onCaptureSequenceAborted
-        kWhatCaptureBufferLost // onCaptureBufferLost
+        kWhatCaptureBufferLost,// onCaptureBufferLost
+        // Internal cleanup
+        kWhatCleanUpSessions   // Cleanup cached sp<ACameraCaptureSession>
     };
     static const char* kContextKey;
     static const char* kDeviceKey;
@@ -199,10 +204,16 @@
     static const char* kSequenceIdKey;
     static const char* kFrameNumberKey;
     static const char* kAnwKey;
+
     class CallbackHandler : public AHandler {
       public:
-        CallbackHandler() {}
         void onMessageReceived(const sp<AMessage> &msg) override;
+
+      private:
+        // This handler will cache all capture session sp until kWhatCleanUpSessions
+        // is processed. This is used to guarantee the last session reference is always
+        // being removed in callback thread without holding camera device lock
+        Vector<sp<ACameraCaptureSession>> mCachedSessions;
     };
     sp<CallbackHandler> mHandler;
 
@@ -210,7 +221,7 @@
      * Capture session related members *
      ***********************************/
     // The current active session
-    ACameraCaptureSession* mCurrentSession = nullptr;
+    wp<ACameraCaptureSession> mCurrentSession;
     bool mFlushing = false;
 
     int mNextSessionId = 0;
diff --git a/camera/ndk/include/camera/NdkCameraDevice.h b/camera/ndk/include/camera/NdkCameraDevice.h
index 9b7f6f4..6c9e85a 100644
--- a/camera/ndk/include/camera/NdkCameraDevice.h
+++ b/camera/ndk/include/camera/NdkCameraDevice.h
@@ -90,18 +90,18 @@
 };
 
 /**
- * Camera device state callbacks to be used in {@link ACameraDevice_stateCallbacks}.
+ * Camera device state callbacks to be used in {@link ACameraDevice_StateCallbacks}.
  *
- * @param context The optional context in {@link ACameraDevice_stateCallbacks} will be
+ * @param context The optional context in {@link ACameraDevice_StateCallbacks} will be
  *                passed to this callback.
  * @param device The {@link ACameraDevice} that is being disconnected.
  */
 typedef void (*ACameraDevice_StateCallback)(void* context, ACameraDevice* device);
 
 /**
- * Camera device error state callbacks to be used in {@link ACameraDevice_stateCallbacks}.
+ * Camera device error state callbacks to be used in {@link ACameraDevice_StateCallbacks}.
  *
- * @param context The optional context in {@link ACameraDevice_stateCallbacks} will be
+ * @param context The optional context in {@link ACameraDevice_StateCallbacks} will be
  *                passed to this callback.
  * @param device The {@link ACameraDevice} that is being disconnected.
  * @param error The error code describes the cause of this error callback. See the folowing
@@ -150,7 +150,7 @@
      *
      */
     ACameraDevice_ErrorStateCallback  onError;
-} ACameraDevice_stateCallbacks;
+} ACameraDevice_StateCallbacks;
 
 /**
  * Close the connection and free this ACameraDevice synchronously. Access to the ACameraDevice
diff --git a/camera/ndk/include/camera/NdkCameraManager.h b/camera/ndk/include/camera/NdkCameraManager.h
index 5b5c98b..e5b3ad8 100644
--- a/camera/ndk/include/camera/NdkCameraManager.h
+++ b/camera/ndk/include/camera/NdkCameraManager.h
@@ -232,18 +232,18 @@
  * priority when accessing the camera, and this method will succeed even if the camera device is
  * in use by another camera API client. Any lower-priority application that loses control of the
  * camera in this way will receive an
- * {@link ACameraDevice_stateCallbacks#onDisconnected} callback.</p>
+ * {@link ACameraDevice_StateCallbacks#onDisconnected} callback.</p>
  *
  * <p>Once the camera is successfully opened,the ACameraDevice can then be set up
  * for operation by calling {@link ACameraDevice_createCaptureSession} and
  * {@link ACameraDevice_createCaptureRequest}.</p>
  *
  * <p>If the camera becomes disconnected after this function call returns,
- * {@link ACameraDevice_stateCallbacks#onDisconnected} with a
+ * {@link ACameraDevice_StateCallbacks#onDisconnected} with a
  * ACameraDevice in the disconnected state will be called.</p>
  *
  * <p>If the camera runs into error after this function call returns,
- * {@link ACameraDevice_stateCallbacks#onError} with a
+ * {@link ACameraDevice_StateCallbacks#onError} with a
  * ACameraDevice in the error state will be called.</p>
  *
  * @param manager the {@link ACameraManager} of interest.
diff --git a/cmds/screenrecord/Android.mk b/cmds/screenrecord/Android.mk
index fa9466c..5e83ed6 100644
--- a/cmds/screenrecord/Android.mk
+++ b/cmds/screenrecord/Android.mk
@@ -25,7 +25,7 @@
 	Program.cpp
 
 LOCAL_SHARED_LIBRARIES := \
-	libstagefright libmedia libutils libbinder libstagefright_foundation \
+	libstagefright libmedia libmedia_omx libutils libbinder libstagefright_foundation \
 	libjpeg libui libgui libcutils liblog libEGL libGLESv2
 
 LOCAL_C_INCLUDES := \
diff --git a/cmds/stagefright/Android.mk b/cmds/stagefright/Android.mk
index 51eef59..283bcb4 100644
--- a/cmds/stagefright/Android.mk
+++ b/cmds/stagefright/Android.mk
@@ -7,16 +7,16 @@
         jpeg.cpp        \
         SineSource.cpp
 
+LOCAL_HEADER_LIBRARIES := \
+        media_plugin_headers \
+
 LOCAL_SHARED_LIBRARIES := \
-        libstagefright libmedia libutils libbinder libstagefright_foundation \
-        libjpeg libui libgui libcutils liblog \
-        libhidlmemory \
+        libstagefright libmedia libmedia_omx libmediaextractor libutils libbinder \
+        libstagefright_foundation libjpeg libui libgui libcutils liblog \
+        libhidlbase \
         android.hardware.media.omx@1.0 \
 
 LOCAL_C_INCLUDES:= \
-        frameworks/av/media/libstagefright \
-        frameworks/av/media/libstagefright/include \
-        frameworks/native/include/media/openmax \
         external/jpeg \
 
 LOCAL_CFLAGS += -Wno-multichar -Werror -Wall
@@ -35,13 +35,12 @@
         SineSource.cpp    \
         record.cpp
 
-LOCAL_SHARED_LIBRARIES := \
-        libstagefright libmedia liblog libutils libbinder libstagefright_foundation
+LOCAL_HEADER_LIBRARIES := \
+        media_plugin_headers \
 
-LOCAL_C_INCLUDES:= \
-        frameworks/av/media/libstagefright \
-        frameworks/native/include/media/openmax \
-        frameworks/native/include/media/hardware
+LOCAL_SHARED_LIBRARIES := \
+        libstagefright libmedia libmediaextractor liblog libutils libbinder \
+        libstagefright_foundation
 
 LOCAL_CFLAGS += -Wno-multichar -Werror -Wall
 
@@ -59,13 +58,12 @@
         SineSource.cpp    \
         recordvideo.cpp
 
-LOCAL_SHARED_LIBRARIES := \
-        libstagefright libmedia liblog libutils libbinder libstagefright_foundation
+LOCAL_HEADER_LIBRARIES := \
+        media_plugin_headers \
 
-LOCAL_C_INCLUDES:= \
-        frameworks/av/media/libstagefright \
-        frameworks/native/include/media/openmax \
-        frameworks/native/include/media/hardware
+LOCAL_SHARED_LIBRARIES := \
+        libstagefright libmedia libmediaextractor liblog libutils libbinder \
+        libstagefright_foundation
 
 LOCAL_CFLAGS += -Wno-multichar -Werror -Wall
 
@@ -84,12 +82,12 @@
         SineSource.cpp    \
         audioloop.cpp
 
-LOCAL_SHARED_LIBRARIES := \
-        libstagefright libmedia liblog libutils libbinder libstagefright_foundation
+LOCAL_HEADER_LIBRARIES := \
+        media_plugin_headers \
 
-LOCAL_C_INCLUDES:= \
-        frameworks/av/media/libstagefright \
-        frameworks/native/include/media/openmax
+LOCAL_SHARED_LIBRARIES := \
+        libstagefright libmedia libmediaextractor liblog libutils libbinder \
+        libstagefright_foundation
 
 LOCAL_CFLAGS += -Wno-multichar -Werror -Wall
 
@@ -106,14 +104,13 @@
 LOCAL_SRC_FILES:=         \
         stream.cpp    \
 
+LOCAL_HEADER_LIBRARIES := \
+        media_plugin_headers \
+
 LOCAL_SHARED_LIBRARIES := \
         libstagefright liblog libutils libbinder libui libgui \
         libstagefright_foundation libmedia libcutils
 
-LOCAL_C_INCLUDES:= \
-        frameworks/av/media/libstagefright \
-        frameworks/native/include/media/openmax
-
 LOCAL_CFLAGS += -Wno-multichar -Werror -Wall
 
 LOCAL_MODULE_TAGS := optional
@@ -130,13 +127,12 @@
         codec.cpp               \
         SimplePlayer.cpp        \
 
+LOCAL_HEADER_LIBRARIES := \
+        media_plugin_headers \
+
 LOCAL_SHARED_LIBRARIES := \
         libstagefright liblog libutils libbinder libstagefright_foundation \
-        libmedia libaudioclient libui libgui libcutils
-
-LOCAL_C_INCLUDES:= \
-        frameworks/av/media/libstagefright \
-        frameworks/native/include/media/openmax
+        libmedia libmedia_omx libaudioclient libui libgui libcutils
 
 LOCAL_CFLAGS += -Wno-multichar -Werror -Wall
 
@@ -156,6 +152,9 @@
         filters/saturation.rs \
         mediafilter.cpp \
 
+LOCAL_HEADER_LIBRARIES := \
+        media_plugin_headers \
+
 LOCAL_SHARED_LIBRARIES := \
         libstagefright \
         liblog \
@@ -163,19 +162,15 @@
         libbinder \
         libstagefright_foundation \
         libmedia \
+        libmedia_omx \
         libui \
         libgui \
         libcutils \
         libRScpp \
 
-LOCAL_C_INCLUDES:= \
-        frameworks/av/media/libstagefright \
-        frameworks/native/include/media/openmax \
-        frameworks/rs/cpp \
-        frameworks/rs \
-
 intermediates := $(call intermediates-dir-for,STATIC_LIBRARIES,libRS,TARGET,)
 LOCAL_C_INCLUDES += $(intermediates)
+LOCAL_C_INCLUDES += frameworks/av/media/libstagefright/filters
 
 LOCAL_STATIC_LIBRARIES:= \
         libstagefright_mediafilter
@@ -198,14 +193,13 @@
 LOCAL_SRC_FILES:=               \
         muxer.cpp            \
 
+LOCAL_HEADER_LIBRARIES := \
+        media_plugin_headers \
+
 LOCAL_SHARED_LIBRARIES := \
         libstagefright liblog libutils libbinder libstagefright_foundation \
         libcutils libc
 
-LOCAL_C_INCLUDES:= \
-        frameworks/av/media/libstagefright \
-        frameworks/native/include/media/openmax
-
 LOCAL_CFLAGS += -Wno-multichar -Werror -Wall
 
 LOCAL_MODULE_TAGS := optional
diff --git a/cmds/stagefright/SineSource.h b/cmds/stagefright/SineSource.h
index be05661..f1fb96d 100644
--- a/cmds/stagefright/SineSource.h
+++ b/cmds/stagefright/SineSource.h
@@ -2,7 +2,7 @@
 
 #define SINE_SOURCE_H_
 
-#include <media/stagefright/MediaSource.h>
+#include <media/MediaSource.h>
 #include <utils/Compat.h>
 
 namespace android {
diff --git a/cmds/stagefright/mediafilter.cpp b/cmds/stagefright/mediafilter.cpp
index f24d2dd..c90a2e4 100644
--- a/cmds/stagefright/mediafilter.cpp
+++ b/cmds/stagefright/mediafilter.cpp
@@ -20,7 +20,7 @@
 #include <inttypes.h>
 
 #include <binder/ProcessState.h>
-#include <filters/ColorConvert.h>
+#include <ColorConvert.h>
 #include <gui/ISurfaceComposer.h>
 #include <gui/SurfaceComposerClient.h>
 #include <gui/Surface.h>
diff --git a/cmds/stagefright/record.cpp b/cmds/stagefright/record.cpp
index 69b00c9..073ee6b 100644
--- a/cmds/stagefright/record.cpp
+++ b/cmds/stagefright/record.cpp
@@ -17,6 +17,7 @@
 #include "SineSource.h"
 
 #include <binder/ProcessState.h>
+#include <media/MediaExtractor.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/ALooper.h>
 #include <media/stagefright/foundation/AMessage.h>
@@ -27,7 +28,7 @@
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaCodecSource.h>
 #include <media/stagefright/MetaData.h>
-#include <media/stagefright/MediaExtractor.h>
+#include <media/stagefright/MediaExtractorFactory.h>
 #include <media/stagefright/MPEG4Writer.h>
 #include <media/stagefright/SimpleDecodingSource.h>
 #include <media/MediaPlayerInterface.h>
@@ -120,7 +121,7 @@
     sp<MediaSource> source;
 
     sp<MediaExtractor> extractor =
-        MediaExtractor::Create(new FileSource(filename));
+        MediaExtractorFactory::Create(new FileSource(filename));
     if (extractor == NULL) {
         return NULL;
     }
diff --git a/cmds/stagefright/stagefright.cpp b/cmds/stagefright/stagefright.cpp
index 0090c55..f873ba5 100644
--- a/cmds/stagefright/stagefright.cpp
+++ b/cmds/stagefright/stagefright.cpp
@@ -31,24 +31,26 @@
 
 #include <binder/IServiceManager.h>
 #include <binder/ProcessState.h>
+#include <media/DataSource.h>
+#include <media/MediaExtractor.h>
+#include <media/MediaSource.h>
 #include <media/ICrypto.h>
 #include <media/IMediaHTTPService.h>
-#include <media/IMediaCodecService.h>
 #include <media/IMediaPlayerService.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ALooper.h>
 #include <media/stagefright/foundation/AMessage.h>
 #include <media/stagefright/foundation/AUtils.h>
-#include "include/NuCachedSource2.h"
+#include <NuCachedSource2.h>
 #include <media/stagefright/AudioPlayer.h>
-#include <media/stagefright/DataSource.h>
+#include <media/stagefright/DataSourceFactory.h>
 #include <media/stagefright/JPEGSource.h>
+#include <media/stagefright/InterfaceUtils.h>
 #include <media/stagefright/MediaCodec.h>
 #include <media/stagefright/MediaCodecList.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/MediaExtractor.h>
-#include <media/stagefright/MediaSource.h>
+#include <media/stagefright/MediaExtractorFactory.h>
 #include <media/stagefright/MetaData.h>
 #include <media/stagefright/SimpleDecodingSource.h>
 #include <media/stagefright/Utils.h>
@@ -65,7 +67,6 @@
 #include <gui/SurfaceComposerClient.h>
 
 #include <android/hardware/media/omx/1.0/IOmx.h>
-#include <media/omx/1.0/WOmx.h>
 
 using namespace android;
 
@@ -909,37 +910,24 @@
     }
 
     if (listComponents) {
-        sp<IOMX> omx;
-        if (property_get_bool("persist.media.treble_omx", true)) {
-            using namespace ::android::hardware::media::omx::V1_0;
-            sp<IOmx> tOmx = IOmx::getService();
+        using ::android::hardware::hidl_vec;
+        using ::android::hardware::hidl_string;
+        using namespace ::android::hardware::media::omx::V1_0;
+        sp<IOmx> omx = IOmx::getService();
+        CHECK(omx.get() != nullptr);
 
-            CHECK(tOmx.get() != NULL);
-
-            omx = new utils::LWOmx(tOmx);
-        } else {
-            sp<IServiceManager> sm = defaultServiceManager();
-            sp<IBinder> binder = sm->getService(String16("media.codec"));
-            sp<IMediaCodecService> service = interface_cast<IMediaCodecService>(binder);
-
-            CHECK(service.get() != NULL);
-
-            omx = service->getOMX();
-        }
-        CHECK(omx.get() != NULL);
-
-        List<IOMX::ComponentInfo> list;
-        omx->listNodes(&list);
-
-        for (List<IOMX::ComponentInfo>::iterator it = list.begin();
-             it != list.end(); ++it) {
-            printf("%s\t Roles: ", (*it).mName.string());
-            for (List<String8>::iterator itRoles = (*it).mRoles.begin() ;
-                    itRoles != (*it).mRoles.end() ; ++itRoles) {
-                printf("%s\t", (*itRoles).string());
-            }
-            printf("\n");
-        }
+        hidl_vec<IOmx::ComponentInfo> nodeList;
+        auto transStatus = omx->listNodes([](
+                const auto& status, const auto& nodeList) {
+                    CHECK(status == Status::OK);
+                    for (const auto& info : nodeList) {
+                        printf("%s\t Roles: ", info.mName.c_str());
+                        for (const auto& role : info.mRoles) {
+                            printf("%s\t", role.c_str());
+                        }
+                    }
+                });
+        CHECK(transStatus.isOk());
     }
 
     sp<SurfaceComposerClient> composerClient;
@@ -988,7 +976,7 @@
         const char *filename = argv[k];
 
         sp<DataSource> dataSource =
-            DataSource::CreateFromURI(NULL /* httpService */, filename);
+            DataSourceFactory::CreateFromURI(NULL /* httpService */, filename);
 
         if (strncasecmp(filename, "sine:", 5) && dataSource == NULL) {
             fprintf(stderr, "Unable to create data source.\n");
@@ -1022,7 +1010,7 @@
                 mediaSources.push(mediaSource);
             }
         } else {
-            sp<IMediaExtractor> extractor = MediaExtractor::Create(dataSource);
+            sp<IMediaExtractor> extractor = MediaExtractorFactory::Create(dataSource);
 
             if (extractor == NULL) {
                 fprintf(stderr, "could not create extractor.\n");
@@ -1049,7 +1037,7 @@
                 bool haveAudio = false;
                 bool haveVideo = false;
                 for (size_t i = 0; i < numTracks; ++i) {
-                    sp<MediaSource> source = MediaSource::CreateFromIMediaSource(
+                    sp<MediaSource> source = CreateMediaSourceFromIMediaSource(
                             extractor->getTrack(i));
                     if (source == nullptr) {
                         fprintf(stderr, "skip NULL track %zu, track count %zu.\n", i, numTracks);
@@ -1116,7 +1104,7 @@
                            thumbTimeUs, thumbTimeUs / 1E6);
                 }
 
-                mediaSource = MediaSource::CreateFromIMediaSource(extractor->getTrack(i));
+                mediaSource = CreateMediaSourceFromIMediaSource(extractor->getTrack(i));
                 if (mediaSource == nullptr) {
                     fprintf(stderr, "skip NULL track %zu, total tracks %zu.\n", i, numTracks);
                     return -1;
diff --git a/cmds/stagefright/stream.cpp b/cmds/stagefright/stream.cpp
index dd8b997..b0199d8 100644
--- a/cmds/stagefright/stream.cpp
+++ b/cmds/stagefright/stream.cpp
@@ -21,15 +21,18 @@
 #include <binder/ProcessState.h>
 #include <cutils/properties.h> // for property_get
 
+#include <media/DataSource.h>
 #include <media/IMediaHTTPService.h>
 #include <media/IStreamSource.h>
+#include <media/MediaExtractor.h>
 #include <media/mediaplayer.h>
+#include <media/MediaSource.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
-#include <media/stagefright/DataSource.h>
+#include <media/stagefright/DataSourceFactory.h>
+#include <media/stagefright/InterfaceUtils.h>
 #include <media/stagefright/MPEG2TSWriter.h>
-#include <media/stagefright/MediaExtractor.h>
-#include <media/stagefright/MediaSource.h>
+#include <media/stagefright/MediaExtractorFactory.h>
 #include <media/stagefright/MetaData.h>
 
 #include <binder/IServiceManager.h>
@@ -161,11 +164,11 @@
     : mCurrentBufferIndex(-1),
       mCurrentBufferOffset(0) {
     sp<DataSource> dataSource =
-        DataSource::CreateFromURI(NULL /* httpService */, filename);
+        DataSourceFactory::CreateFromURI(NULL /* httpService */, filename);
 
     CHECK(dataSource != NULL);
 
-    sp<IMediaExtractor> extractor = MediaExtractor::Create(dataSource);
+    sp<IMediaExtractor> extractor = MediaExtractorFactory::Create(dataSource);
     CHECK(extractor != NULL);
 
     mWriter = new MPEG2TSWriter(
@@ -182,7 +185,7 @@
             continue;
         }
 
-        sp<MediaSource> track = MediaSource::CreateFromIMediaSource(extractor->getTrack(i));
+        sp<MediaSource> track = CreateMediaSourceFromIMediaSource(extractor->getTrack(i));
         if (track == nullptr) {
             fprintf(stderr, "skip NULL track %zu, total tracks %zu\n", i, numTracks);
             continue;
diff --git a/drm/common/Android.bp b/drm/common/Android.bp
index 0098c89..1552c3f 100644
--- a/drm/common/Android.bp
+++ b/drm/common/Android.bp
@@ -33,6 +33,8 @@
         "ReadWriteUtils.cpp",
     ],
 
+    cflags: ["-Wall", "-Werror"],
+
     static_libs: ["libbinder"],
 
     export_include_dirs: ["include"],
diff --git a/drm/libdrmframework/plugins/common/util/Android.bp b/drm/libdrmframework/plugins/common/util/Android.bp
index 0c0b6f2..7372eb7 100644
--- a/drm/libdrmframework/plugins/common/util/Android.bp
+++ b/drm/libdrmframework/plugins/common/util/Android.bp
@@ -19,5 +19,7 @@
 
     srcs: ["src/MimeTypeUtil.cpp"],
 
+    cflags: ["-Wall", "-Werror"],
+
     export_include_dirs: ["include"],
 }
diff --git a/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/Android.bp b/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/Android.bp
index 3f0f5f7..28a78aa 100644
--- a/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/Android.bp
+++ b/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/Android.bp
@@ -21,6 +21,9 @@
         "-DUSE_64BIT_DRM_API",
         // The flag below turns on local debug printouts
         //"-DDRM_OMA_FL_ENGINE_DEBUG",
+        "-Wall",
+        "-Werror",
+        "-Wno-unused-variable",
     ],
 
     srcs: ["src/FwdLockEngine.cpp"],
diff --git a/drm/libdrmframework/plugins/forward-lock/internal-format/common/Android.bp b/drm/libdrmframework/plugins/forward-lock/internal-format/common/Android.bp
index 698f278..3be327a 100644
--- a/drm/libdrmframework/plugins/forward-lock/internal-format/common/Android.bp
+++ b/drm/libdrmframework/plugins/forward-lock/internal-format/common/Android.bp
@@ -19,6 +19,8 @@
 
     srcs: ["FwdLockGlue.c"],
 
+    cflags: ["-Wall", "-Werror"],
+
     shared_libs: ["libcrypto"],
 
     export_include_dirs: ["."],
diff --git a/drm/libdrmframework/plugins/forward-lock/internal-format/converter/Android.bp b/drm/libdrmframework/plugins/forward-lock/internal-format/converter/Android.bp
index 33f2fe0..d4e04b8 100644
--- a/drm/libdrmframework/plugins/forward-lock/internal-format/converter/Android.bp
+++ b/drm/libdrmframework/plugins/forward-lock/internal-format/converter/Android.bp
@@ -19,6 +19,8 @@
 
     srcs: ["FwdLockConv.c"],
 
+    cflags: ["-Wall", "-Werror"],
+
     shared_libs: ["libcrypto"],
     static_libs: ["libfwdlock-common"],
 
diff --git a/drm/libdrmframework/plugins/forward-lock/internal-format/decoder/Android.bp b/drm/libdrmframework/plugins/forward-lock/internal-format/decoder/Android.bp
index b6d7a06..0bf2737 100644
--- a/drm/libdrmframework/plugins/forward-lock/internal-format/decoder/Android.bp
+++ b/drm/libdrmframework/plugins/forward-lock/internal-format/decoder/Android.bp
@@ -19,6 +19,8 @@
 
     srcs: ["FwdLockFile.c"],
 
+    cflags: ["-Wall", "-Werror"],
+
     shared_libs: ["libcrypto"],
     static_libs: ["libfwdlock-common"],
 
diff --git a/drm/libdrmframework/plugins/passthru/Android.bp b/drm/libdrmframework/plugins/passthru/Android.bp
index 1dcf89c..05b6440 100644
--- a/drm/libdrmframework/plugins/passthru/Android.bp
+++ b/drm/libdrmframework/plugins/passthru/Android.bp
@@ -32,5 +32,7 @@
     cflags: [
         // Set the following flag to enable the decryption passthru flow
         //"-DENABLE_PASSTHRU_DECRYPTION",
+        "-Wall",
+        "-Werror",
     ],
 }
diff --git a/drm/libmediadrm/Android.bp b/drm/libmediadrm/Android.bp
index f906564..0c14201 100644
--- a/drm/libmediadrm/Android.bp
+++ b/drm/libmediadrm/Android.bp
@@ -34,8 +34,8 @@
         "libstagefright_foundation",
         "libutils",
         "android.hardware.drm@1.0",
+        "libhidlallocatorutils",
         "libhidlbase",
-        "libhidlmemory",
         "libhidltransport",
     ],
 
diff --git a/drm/libmediadrm/CryptoHal.cpp b/drm/libmediadrm/CryptoHal.cpp
index d613a5b..b9b3685 100644
--- a/drm/libmediadrm/CryptoHal.cpp
+++ b/drm/libmediadrm/CryptoHal.cpp
@@ -29,6 +29,7 @@
 #include <media/stagefright/foundation/AString.h>
 #include <media/stagefright/foundation/hexdump.h>
 #include <media/stagefright/MediaErrors.h>
+#include <hidlmemory/FrameworkUtils.h>
 
 using ::android::hardware::drm::V1_0::BufferType;
 using ::android::hardware::drm::V1_0::DestinationBuffer;
@@ -227,6 +228,9 @@
  * are sent by providing an offset into the heap and a buffer size.
  */
 int32_t CryptoHal::setHeapBase(const sp<IMemoryHeap>& heap) {
+    using ::android::hardware::fromHeap;
+    using ::android::hardware::HidlMemory;
+
     if (heap == NULL) {
         ALOGE("setHeapBase(): heap is NULL");
         return -1;
@@ -240,12 +244,9 @@
     Mutex::Autolock autoLock(mLock);
 
     int32_t seqNum = mHeapSeqNum++;
-    int fd = heap->getHeapID();
-    nativeHandle->data[0] = fd;
-    auto hidlHandle = hidl_handle(nativeHandle);
-    auto hidlMemory = hidl_memory("ashmem", hidlHandle, heap->getSize());
+    sp<HidlMemory> hidlMemory = fromHeap(heap);
     mHeapBases.add(seqNum, mNextBufferId);
-    Return<void> hResult = mPlugin->setSharedBufferBase(hidlMemory, mNextBufferId++);
+    Return<void> hResult = mPlugin->setSharedBufferBase(*hidlMemory, mNextBufferId++);
     ALOGE_IF(!hResult.isOk(), "setSharedBufferBase(): remote call failed");
     return seqNum;
 }
diff --git a/drm/libmediadrm/IDrm.cpp b/drm/libmediadrm/IDrm.cpp
index 4e47112..8ff6e6a 100644
--- a/drm/libmediadrm/IDrm.cpp
+++ b/drm/libmediadrm/IDrm.cpp
@@ -561,8 +561,13 @@
 
 void BnDrm::readVector(const Parcel &data, Vector<uint8_t> &vector) const {
     uint32_t size = data.readInt32();
-    vector.insertAt((size_t)0, size);
-    data.read(vector.editArray(), size);
+    if (vector.insertAt((size_t)0, size) < 0) {
+        vector.clear();
+    }
+    if (data.read(vector.editArray(), size) != NO_ERROR) {
+        vector.clear();
+        android_errorWriteWithInfoLog(0x534e4554, "62872384", -1, NULL, 0);
+    }
 }
 
 void BnDrm::writeVector(Parcel *reply, Vector<uint8_t> const &vector) const {
diff --git a/drm/mediadrm/plugins/clearkey/AesCtrDecryptor.cpp b/drm/mediadrm/plugins/clearkey/AesCtrDecryptor.cpp
index 01f8d65..f7106b2 100644
--- a/drm/mediadrm/plugins/clearkey/AesCtrDecryptor.cpp
+++ b/drm/mediadrm/plugins/clearkey/AesCtrDecryptor.cpp
@@ -36,6 +36,11 @@
     uint8_t previousEncryptedCounter[kBlockSize];
     memset(previousEncryptedCounter, 0, kBlockSize);
 
+    if (key.size() != kBlockSize || (sizeof(Iv) / sizeof(uint8_t)) != kBlockSize) {
+        android_errorWriteLog(0x534e4554, "63982768");
+        return android::ERROR_DRM_DECRYPT;
+    }
+
     size_t offset = 0;
     AES_KEY opensslKey;
     AES_set_encrypt_key(key.array(), kBlockBitCount, &opensslKey);
diff --git a/drm/mediadrm/plugins/clearkey/AesCtrDecryptor.h b/drm/mediadrm/plugins/clearkey/AesCtrDecryptor.h
index b416266..edb8445 100644
--- a/drm/mediadrm/plugins/clearkey/AesCtrDecryptor.h
+++ b/drm/mediadrm/plugins/clearkey/AesCtrDecryptor.h
@@ -18,6 +18,7 @@
 #define CLEARKEY_AES_CTR_DECRYPTOR_H_
 
 #include <media/stagefright/foundation/ABase.h>
+#include <media/stagefright/MediaErrors.h>
 #include <Utils.h>
 #include <utils/Errors.h>
 #include <utils/Vector.h>
diff --git a/drm/mediadrm/plugins/clearkey/Android.bp b/drm/mediadrm/plugins/clearkey/Android.bp
index 2973fcf..4b7a63c 100644
--- a/drm/mediadrm/plugins/clearkey/Android.bp
+++ b/drm/mediadrm/plugins/clearkey/Android.bp
@@ -35,6 +35,8 @@
     vendor: true,
     relative_install_path: "mediadrm",
 
+    cflags: ["-Wall", "-Werror"],
+
     shared_libs: [
         "libcrypto",
         "liblog",
@@ -51,6 +53,10 @@
 
     export_include_dirs: ["."],
     export_static_lib_headers: ["libjsmn"],
+
+    sanitize: {
+        integer_overflow: true,
+    },
 }
 
 //########################################################################
diff --git a/drm/mediadrm/plugins/clearkey/tests/AesCtrDecryptorUnittest.cpp b/drm/mediadrm/plugins/clearkey/tests/AesCtrDecryptorUnittest.cpp
index 039e402..5db8290 100644
--- a/drm/mediadrm/plugins/clearkey/tests/AesCtrDecryptorUnittest.cpp
+++ b/drm/mediadrm/plugins/clearkey/tests/AesCtrDecryptorUnittest.cpp
@@ -34,7 +34,7 @@
                             uint8_t* destination, const SubSample* subSamples,
                             size_t numSubSamples, size_t* bytesDecryptedOut) {
         Vector<uint8_t> keyVector;
-        keyVector.appendArray(key, kBlockSize);
+        keyVector.appendArray(key, sizeof(key) / sizeof(uint8_t));
 
         AesCtrDecryptor decryptor;
         return decryptor.decrypt(keyVector, iv, source, destination, subSamples,
@@ -57,6 +57,67 @@
     }
 };
 
+TEST_F(AesCtrDecryptorTest, DecryptsWithEmptyKey) {
+    const size_t kTotalSize = 64;
+    const size_t kNumSubsamples = 1;
+
+    // Test vectors from NIST-800-38A
+    Iv iv = {
+        0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
+        0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
+    };
+
+    uint8_t source[kTotalSize] = { 0 };
+    uint8_t destination[kTotalSize] = { 0 };
+    SubSample subSamples[kNumSubsamples] = {
+        {0, 64}
+    };
+
+    size_t bytesDecrypted = 0;
+    Vector<uint8_t> keyVector;
+    keyVector.clear();
+
+    AesCtrDecryptor decryptor;
+    ASSERT_EQ(android::ERROR_DRM_DECRYPT, decryptor.decrypt(keyVector, iv,
+              &source[0], &destination[0],
+              &subSamples[0], kNumSubsamples, &bytesDecrypted));
+    ASSERT_EQ(0u, bytesDecrypted);
+}
+
+TEST_F(AesCtrDecryptorTest, DecryptsWithKeyTooLong) {
+    const size_t kTotalSize = 64;
+    const size_t kNumSubsamples = 1;
+
+    // Test vectors from NIST-800-38A
+    uint8_t key[kBlockSize * 2] = {
+        0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
+        0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c,
+        0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
+        0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c
+    };
+
+    Iv iv = {
+        0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
+        0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
+    };
+
+    uint8_t source[kTotalSize] = { 0 };
+    uint8_t destination[kTotalSize] = { 0 };
+    SubSample subSamples[kNumSubsamples] = {
+        {0, 64}
+    };
+
+    size_t bytesDecrypted = 0;
+    Vector<uint8_t> keyVector;
+    keyVector.appendArray(key, sizeof(key) / sizeof(uint8_t));
+
+    AesCtrDecryptor decryptor;
+    ASSERT_EQ(android::ERROR_DRM_DECRYPT, decryptor.decrypt(keyVector, iv,
+              &source[0], &destination[0],
+              &subSamples[0], kNumSubsamples, &bytesDecrypted));
+    ASSERT_EQ(0u, bytesDecrypted);
+}
+
 TEST_F(AesCtrDecryptorTest, DecryptsContiguousEncryptedBlock) {
     const size_t kTotalSize = 64;
     const size_t kNumSubsamples = 1;
diff --git a/drm/mediadrm/plugins/clearkey/tests/Android.bp b/drm/mediadrm/plugins/clearkey/tests/Android.bp
index 0fcfc64..ea17bbb 100644
--- a/drm/mediadrm/plugins/clearkey/tests/Android.bp
+++ b/drm/mediadrm/plugins/clearkey/tests/Android.bp
@@ -21,6 +21,8 @@
     name: "ClearKeyDrmUnitTest",
     vendor: true,
 
+    cflags: ["-Wall", "-Werror"],
+
     srcs: [
         "AesCtrDecryptorUnittest.cpp",
         "InitDataParserUnittest.cpp",
diff --git a/drm/mediadrm/plugins/mock/Android.bp b/drm/mediadrm/plugins/mock/Android.bp
index abd1884..dd2ad7b 100644
--- a/drm/mediadrm/plugins/mock/Android.bp
+++ b/drm/mediadrm/plugins/mock/Android.bp
@@ -32,5 +32,7 @@
     cflags: [
         // Set the following flag to enable the decryption passthru flow
         //"-DENABLE_PASSTHRU_DECRYPTION",
+        "-Wall",
+        "-Werror",
     ],
 }
diff --git a/include/media/DataSource.h b/include/media/DataSource.h
new file mode 120000
index 0000000..905bec1
--- /dev/null
+++ b/include/media/DataSource.h
@@ -0,0 +1 @@
+../../media/libmediaextractor/include/media/DataSource.h
\ No newline at end of file
diff --git a/include/media/MediaExtractor.h b/include/media/MediaExtractor.h
new file mode 120000
index 0000000..4b35fe1
--- /dev/null
+++ b/include/media/MediaExtractor.h
@@ -0,0 +1 @@
+../../media/libmediaextractor/include/media/MediaExtractor.h
\ No newline at end of file
diff --git a/include/media/MediaSource.h b/include/media/MediaSource.h
new file mode 120000
index 0000000..2e147c4
--- /dev/null
+++ b/include/media/MediaSource.h
@@ -0,0 +1 @@
+../../media/libmediaextractor/include/media/MediaSource.h
\ No newline at end of file
diff --git a/media/extractors/aac/AACExtractor.cpp b/media/extractors/aac/AACExtractor.cpp
index ce5f976..716fe31 100644
--- a/media/extractors/aac/AACExtractor.cpp
+++ b/media/extractors/aac/AACExtractor.cpp
@@ -19,16 +19,15 @@
 #include <utils/Log.h>
 
 #include "AACExtractor.h"
-#include "include/avc_utils.h"
-
+#include <media/DataSource.h>
+#include <media/MediaSource.h>
+#include <media/stagefright/foundation/avc_utils.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/AMessage.h>
 #include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/DataSource.h>
 #include <media/stagefright/MediaBufferGroup.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/MediaSource.h>
 #include <media/stagefright/MetaData.h>
 #include <utils/String8.h>
 
diff --git a/media/extractors/aac/AACExtractor.h b/media/extractors/aac/AACExtractor.h
index 91e2eed..aede185 100644
--- a/media/extractors/aac/AACExtractor.h
+++ b/media/extractors/aac/AACExtractor.h
@@ -18,7 +18,7 @@
 
 #define AAC_EXTRACTOR_H_
 
-#include <media/stagefright/MediaExtractor.h>
+#include <media/MediaExtractor.h>
 
 #include <utils/Vector.h>
 
diff --git a/media/extractors/aac/Android.bp b/media/extractors/aac/Android.bp
index b4ef53e..65f9b96 100644
--- a/media/extractors/aac/Android.bp
+++ b/media/extractors/aac/Android.bp
@@ -7,11 +7,10 @@
     ],
 
     shared_libs: [
-        "libstagefright",
-        "libmedia",
+        "liblog",
+        "libmediaextractor",
         "libstagefright_foundation",
         "libutils",
-        "liblog",
     ],
 
     name: "libaacextractor",
diff --git a/media/extractors/amr/AMRExtractor.cpp b/media/extractors/amr/AMRExtractor.cpp
index d8b92bd..b8967bd 100644
--- a/media/extractors/amr/AMRExtractor.cpp
+++ b/media/extractors/amr/AMRExtractor.cpp
@@ -20,12 +20,12 @@
 
 #include "AMRExtractor.h"
 
+#include <media/DataSource.h>
+#include <media/MediaSource.h>
 #include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/DataSource.h>
 #include <media/stagefright/MediaBufferGroup.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/MediaSource.h>
 #include <media/stagefright/MetaData.h>
 #include <utils/String8.h>
 
diff --git a/media/extractors/amr/AMRExtractor.h b/media/extractors/amr/AMRExtractor.h
index 06cd387..79b22d6 100644
--- a/media/extractors/amr/AMRExtractor.h
+++ b/media/extractors/amr/AMRExtractor.h
@@ -19,7 +19,7 @@
 #define AMR_EXTRACTOR_H_
 
 #include <utils/Errors.h>
-#include <media/stagefright/MediaExtractor.h>
+#include <media/MediaExtractor.h>
 
 namespace android {
 
diff --git a/media/extractors/amr/Android.bp b/media/extractors/amr/Android.bp
index 85e4777..01bbfa2 100644
--- a/media/extractors/amr/Android.bp
+++ b/media/extractors/amr/Android.bp
@@ -7,11 +7,10 @@
     ],
 
     shared_libs: [
-        "libstagefright",
-        "libmedia",
+        "liblog",
+        "libmediaextractor",
         "libstagefright_foundation",
         "libutils",
-        "liblog",
     ],
 
     name: "libamrextractor",
diff --git a/media/extractors/flac/Android.bp b/media/extractors/flac/Android.bp
index 5edc182..80a4125 100644
--- a/media/extractors/flac/Android.bp
+++ b/media/extractors/flac/Android.bp
@@ -8,11 +8,10 @@
     ],
 
     shared_libs: [
-        "libstagefright",
-        "libmedia",
+        "liblog",
+        "libmediaextractor",
         "libstagefright_foundation",
         "libutils",
-        "liblog",
     ],
 
     static_libs: [
diff --git a/media/extractors/flac/FLACExtractor.cpp b/media/extractors/flac/FLACExtractor.cpp
index 518041d..0c88246 100644
--- a/media/extractors/flac/FLACExtractor.cpp
+++ b/media/extractors/flac/FLACExtractor.cpp
@@ -22,15 +22,15 @@
 // libFLAC parser
 #include "FLAC/stream_decoder.h"
 
+#include <media/DataSource.h>
+#include <media/MediaSource.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/base64.h>
 #include <media/stagefright/foundation/ByteUtils.h>
-#include <media/stagefright/DataSource.h>
 #include <media/stagefright/MediaBufferGroup.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MetaData.h>
-#include <media/stagefright/MediaSource.h>
 #include <media/stagefright/MediaBuffer.h>
 
 namespace android {
diff --git a/media/extractors/flac/FLACExtractor.h b/media/extractors/flac/FLACExtractor.h
index e945cf6..6907ceb 100644
--- a/media/extractors/flac/FLACExtractor.h
+++ b/media/extractors/flac/FLACExtractor.h
@@ -17,8 +17,8 @@
 #ifndef FLAC_EXTRACTOR_H_
 #define FLAC_EXTRACTOR_H_
 
-#include <media/stagefright/DataSource.h>
-#include <media/stagefright/MediaExtractor.h>
+#include <media/DataSource.h>
+#include <media/MediaExtractor.h>
 #include <utils/String8.h>
 
 namespace android {
diff --git a/media/extractors/midi/Android.bp b/media/extractors/midi/Android.bp
index 1b84b94..68f8766 100644
--- a/media/extractors/midi/Android.bp
+++ b/media/extractors/midi/Android.bp
@@ -7,14 +7,16 @@
     ],
 
     shared_libs: [
-        "libsonivox",
-        "libstagefright",
-        "libmedia",
+        "liblog",
+        "libmediaextractor",
         "libstagefright_foundation",
         "libutils",
-        "liblog",
     ],
 
+    static_libs: [
+        "libmedia_midiiowrapper",
+        "libsonivox",
+    ],
     name: "libmidiextractor",
     relative_install_path: "extractors",
 
diff --git a/media/extractors/midi/MidiExtractor.cpp b/media/extractors/midi/MidiExtractor.cpp
index 1f32cb3..a8509fc 100644
--- a/media/extractors/midi/MidiExtractor.cpp
+++ b/media/extractors/midi/MidiExtractor.cpp
@@ -25,7 +25,7 @@
 #include <media/stagefright/MediaBufferGroup.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MetaData.h>
-#include <media/stagefright/MediaSource.h>
+#include <media/MediaSource.h>
 #include <libsonivox/eas_reverb.h>
 
 namespace android {
diff --git a/media/extractors/midi/MidiExtractor.h b/media/extractors/midi/MidiExtractor.h
index 87a4a02..0fae94a 100644
--- a/media/extractors/midi/MidiExtractor.h
+++ b/media/extractors/midi/MidiExtractor.h
@@ -17,8 +17,8 @@
 #ifndef MIDI_EXTRACTOR_H_
 #define MIDI_EXTRACTOR_H_
 
-#include <media/stagefright/DataSource.h>
-#include <media/stagefright/MediaExtractor.h>
+#include <media/DataSource.h>
+#include <media/MediaExtractor.h>
 #include <media/stagefright/MediaBuffer.h>
 #include <media/stagefright/MediaBufferGroup.h>
 #include <media/MidiIoWrapper.h>
diff --git a/media/extractors/mkv/Android.bp b/media/extractors/mkv/Android.bp
index f855bbb..350c6fe 100644
--- a/media/extractors/mkv/Android.bp
+++ b/media/extractors/mkv/Android.bp
@@ -5,20 +5,19 @@
     include_dirs: [
         "external/flac/include",
         "external/libvpx/libwebm",
-        "frameworks/av/media/libstagefright/include",
         "frameworks/av/media/libstagefright/flac/dec",
+        "frameworks/av/media/libstagefright/include",
     ],
 
     shared_libs: [
-        "libstagefright",
-        "libmedia",
-        "libstagefright_foundation",
-        "libstagefright_flacdec",
-        "libutils",
         "liblog",
+        "libmediaextractor",
+        "libstagefright_foundation",
+        "libutils",
     ],
 
     static_libs: [
+        "libstagefright_flacdec",
         "libwebm",
     ],
 
diff --git a/media/extractors/mkv/MatroskaExtractor.cpp b/media/extractors/mkv/MatroskaExtractor.cpp
index 060ce35..e199f03 100644
--- a/media/extractors/mkv/MatroskaExtractor.cpp
+++ b/media/extractors/mkv/MatroskaExtractor.cpp
@@ -20,19 +20,19 @@
 
 #include "FLACDecoder.h"
 #include "MatroskaExtractor.h"
-#include "avc_utils.h"
 
+#include <media/DataSource.h>
+#include <media/MediaSource.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AUtils.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ByteUtils.h>
 #include <media/stagefright/foundation/ColorUtils.h>
+#include <media/stagefright/foundation/avc_utils.h>
 #include <media/stagefright/foundation/hexdump.h>
-#include <media/stagefright/DataSource.h>
 #include <media/stagefright/MediaBuffer.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/MediaSource.h>
 #include <media/stagefright/MetaData.h>
 #include <utils/String8.h>
 
@@ -703,18 +703,22 @@
 
     int64_t seekTimeUs;
     ReadOptions::SeekMode mode;
-    if (options && options->getSeekTo(&seekTimeUs, &mode)
-            && !mExtractor->isLiveStreaming()) {
-        clearPendingFrames();
+    if (options && options->getSeekTo(&seekTimeUs, &mode)) {
+        if (mode == ReadOptions::SEEK_FRAME_INDEX) {
+            return ERROR_UNSUPPORTED;
+        }
 
-        // The audio we want is located by using the Cues to seek the video
-        // stream to find the target Cluster then iterating to finalize for
-        // audio.
-        int64_t actualFrameTimeUs;
-        mBlockIter.seek(seekTimeUs, mIsAudio, &actualFrameTimeUs);
+        if (!mExtractor->isLiveStreaming()) {
+            clearPendingFrames();
 
-        if (mode == ReadOptions::SEEK_CLOSEST) {
-            targetSampleTimeUs = actualFrameTimeUs;
+            // The audio we want is located by using the Cues to seek the video
+            // stream to find the target Cluster then iterating to finalize for
+            // audio.
+            int64_t actualFrameTimeUs;
+            mBlockIter.seek(seekTimeUs, mIsAudio, &actualFrameTimeUs);
+            if (mode == ReadOptions::SEEK_CLOSEST) {
+                targetSampleTimeUs = actualFrameTimeUs;
+            }
         }
     }
 
@@ -1459,6 +1463,14 @@
                 continue;
         }
 
+        const char *language = track->GetLanguage();
+        if (language != NULL) {
+           char lang[4];
+           strncpy(lang, language, 3);
+           lang[3] = '\0';
+           meta->setCString(kKeyMediaLanguage, lang);
+        }
+
         if (err != OK) {
             ALOGE("skipping track, codec specific data was malformed.");
             continue;
diff --git a/media/extractors/mkv/MatroskaExtractor.h b/media/extractors/mkv/MatroskaExtractor.h
index 832463f..26f8d19 100644
--- a/media/extractors/mkv/MatroskaExtractor.h
+++ b/media/extractors/mkv/MatroskaExtractor.h
@@ -20,7 +20,7 @@
 
 #include "mkvparser/mkvparser.h"
 
-#include <media/stagefright/MediaExtractor.h>
+#include <media/MediaExtractor.h>
 #include <utils/Vector.h>
 #include <utils/threads.h>
 
diff --git a/media/extractors/mp3/Android.bp b/media/extractors/mp3/Android.bp
index b189ddf..6912ef1 100644
--- a/media/extractors/mp3/Android.bp
+++ b/media/extractors/mp3/Android.bp
@@ -11,11 +11,10 @@
     ],
 
     shared_libs: [
-        "libstagefright",
-        "libmedia",
+        "liblog",
+        "libmediaextractor",
         "libstagefright_foundation",
         "libutils",
-        "liblog",
     ],
 
     static_libs: [
diff --git a/media/extractors/mp3/MP3Extractor.cpp b/media/extractors/mp3/MP3Extractor.cpp
index 10ebda8..2731f0f 100644
--- a/media/extractors/mp3/MP3Extractor.cpp
+++ b/media/extractors/mp3/MP3Extractor.cpp
@@ -20,20 +20,20 @@
 
 #include "MP3Extractor.h"
 
-#include "avc_utils.h"
 #include "ID3.h"
 #include "VBRISeeker.h"
 #include "XINGSeeker.h"
 
+#include <media/DataSource.h>
+#include <media/MediaSource.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/foundation/avc_utils.h>
 #include <media/stagefright/foundation/ByteUtils.h>
-#include <media/stagefright/DataSource.h>
 #include <media/stagefright/MediaBuffer.h>
 #include <media/stagefright/MediaBufferGroup.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/MediaSource.h>
 #include <media/stagefright/MetaData.h>
 #include <utils/String8.h>
 
diff --git a/media/extractors/mp3/MP3Extractor.h b/media/extractors/mp3/MP3Extractor.h
index 2b16c24..f0ab6b0 100644
--- a/media/extractors/mp3/MP3Extractor.h
+++ b/media/extractors/mp3/MP3Extractor.h
@@ -19,7 +19,7 @@
 #define MP3_EXTRACTOR_H_
 
 #include <utils/Errors.h>
-#include <media/stagefright/MediaExtractor.h>
+#include <media/MediaExtractor.h>
 
 namespace android {
 
diff --git a/media/extractors/mp3/VBRISeeker.cpp b/media/extractors/mp3/VBRISeeker.cpp
index 42cebfe..e7db6fd 100644
--- a/media/extractors/mp3/VBRISeeker.cpp
+++ b/media/extractors/mp3/VBRISeeker.cpp
@@ -23,11 +23,11 @@
 
 #include "VBRISeeker.h"
 
-#include "avc_utils.h"
+#include <media/stagefright/foundation/avc_utils.h>
 
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/ByteUtils.h>
-#include <media/stagefright/DataSource.h>
+#include <media/DataSource.h>
 
 namespace android {
 
diff --git a/media/extractors/mp3/XINGSeeker.cpp b/media/extractors/mp3/XINGSeeker.cpp
index 2be62bf..fa59701 100644
--- a/media/extractors/mp3/XINGSeeker.cpp
+++ b/media/extractors/mp3/XINGSeeker.cpp
@@ -18,10 +18,10 @@
 #include <utils/Log.h>
 
 #include "XINGSeeker.h"
-#include "avc_utils.h"
+#include <media/stagefright/foundation/avc_utils.h>
 
 #include <media/stagefright/foundation/ByteUtils.h>
-#include <media/stagefright/DataSource.h>
+#include <media/DataSource.h>
 
 namespace android {
 
diff --git a/media/extractors/mp4/Android.bp b/media/extractors/mp4/Android.bp
index a957e98..49a3714 100644
--- a/media/extractors/mp4/Android.bp
+++ b/media/extractors/mp4/Android.bp
@@ -12,14 +12,14 @@
     ],
 
     shared_libs: [
-        "libstagefright",
-        "libmedia",
+        "liblog",
+        "libmediaextractor",
         "libstagefright_foundation",
         "libutils",
-        "liblog",
     ],
 
     static_libs: [
+        "libstagefright_esds",
         "libstagefright_id3",
     ],
 
diff --git a/media/extractors/mp4/ItemTable.cpp b/media/extractors/mp4/ItemTable.cpp
index b476c75..9a6cb64 100644
--- a/media/extractors/mp4/ItemTable.cpp
+++ b/media/extractors/mp4/ItemTable.cpp
@@ -18,7 +18,7 @@
 #define LOG_TAG "ItemTable"
 
 #include <ItemTable.h>
-#include <media/stagefright/DataSource.h>
+#include <media/DataSource.h>
 #include <media/stagefright/MetaData.h>
 #include <media/stagefright/MediaErrors.h>
 #include <media/stagefright/foundation/ABuffer.h>
@@ -40,8 +40,9 @@
     friend struct ItemReference;
     friend struct ItemProperty;
 
-    ImageItem() : ImageItem(0) {}
-    ImageItem(uint32_t _type) : type(_type),
+    ImageItem() : ImageItem(0, 0, false) {}
+    ImageItem(uint32_t _type, uint32_t _id, bool _hidden) :
+            type(_type), itemId(_id), hidden(_hidden),
             rows(0), columns(0), width(0), height(0), rotation(0),
             offset(0), size(0), nextTileIndex(0) {}
 
@@ -61,6 +62,8 @@
     }
 
     uint32_t type;
+    uint32_t itemId;
+    bool hidden;
     int32_t rows;
     int32_t columns;
     int32_t width;
@@ -496,7 +499,25 @@
             ALOGW("dimgRefs if not clean!");
         }
         derivedImage.dimgRefs.appendVector(mRefs);
+
+        for (size_t i = 0; i < mRefs.size(); i++) {
+            itemIndex = itemIdToItemMap.indexOfKey(mRefs[i]);
+
+            // ignore non-image items
+            if (itemIndex < 0) {
+                continue;
+            }
+            ImageItem &sourceImage = itemIdToItemMap.editValueAt(itemIndex);
+
+            // mark the source image of the derivation as hidden
+            sourceImage.hidden = true;
+        }
     } else if (type() == FOURCC('t', 'h', 'm', 'b')) {
+        // mark thumbnail image as hidden, these can be retrieved if the client
+        // request thumbnail explicitly, but won't be exposed as displayables.
+        ImageItem &thumbImage = itemIdToItemMap.editValueAt(itemIndex);
+        thumbImage.hidden = true;
+
         for (size_t i = 0; i < mRefs.size(); i++) {
             itemIndex = itemIdToItemMap.indexOfKey(mRefs[i]);
 
@@ -511,6 +532,10 @@
             }
             masterImage.thumbnails.push_back(mItemId);
         }
+    } else if (type() == FOURCC('a', 'u', 'x', 'l')) {
+        // mark auxiliary image as hidden
+        ImageItem &auxImage = itemIdToItemMap.editValueAt(itemIndex);
+        auxImage.hidden = true;
     } else {
         ALOGW("ignoring unsupported ref type 0x%x", type());
     }
@@ -942,6 +967,7 @@
 struct ItemInfo {
     uint32_t itemId;
     uint32_t itemType;
+    bool hidden;
 };
 
 struct InfeBox : public FullBox {
@@ -1012,6 +1038,9 @@
 
         itemInfo->itemId = item_id;
         itemInfo->itemType = item_type;
+        // According to HEIF spec, (flags & 1) indicates the image is hidden
+        // and not supposed to be displayed.
+        itemInfo->hidden = (flags() & 1);
 
         char itemTypeString[5];
         MakeFourCCString(item_type, itemTypeString);
@@ -1108,7 +1137,9 @@
         mItemInfos->push_back(itemInfo);
         mHasGrids |= (itemInfo.itemType == FOURCC('g', 'r', 'i', 'd'));
     }
-    return OK;
+    // InfeBox parse returns ERROR_UNSUPPORTED if the box if an unsupported
+    // version. Ignore this error as it's not fatal.
+    return (err == ERROR_UNSUPPORTED) ? OK : err;
 }
 
 //////////////////////////////////////////////////////////////////
@@ -1293,7 +1324,7 @@
             return ERROR_MALFORMED;
         }
 
-        ImageItem image(info.itemType);
+        ImageItem image(info.itemType, info.itemId, info.hidden);
 
         ALOGV("adding %s: itemId %d", image.isGrid() ? "grid" : "image", info.itemId);
 
@@ -1325,6 +1356,29 @@
         mItemReferences[i]->apply(mItemIdToItemMap);
     }
 
+    bool foundPrimary = false;
+    for (size_t i = 0; i < mItemIdToItemMap.size(); i++) {
+        // add all non-hidden images, also add the primary even if it's marked
+        // hidden, in case the primary is set to a thumbnail
+        bool isPrimary = (mItemIdToItemMap[i].itemId == mPrimaryItemId);
+        if (!mItemIdToItemMap[i].hidden || isPrimary) {
+            mDisplayables.push_back(i);
+        }
+        foundPrimary |= isPrimary;
+    }
+
+    ALOGV("found %zu displayables", mDisplayables.size());
+
+    // fail if no displayables are found
+    if (mDisplayables.empty()) {
+        return ERROR_MALFORMED;
+    }
+
+    // if the primary item id is invalid, set primary to the first displayable
+    if (!foundPrimary) {
+        mPrimaryItemId = mItemIdToItemMap[mDisplayables[0]].itemId;
+    }
+
     mImageItemsValid = true;
     return OK;
 }
@@ -1346,29 +1400,36 @@
     ALOGV("attach property %d to item id %d)",
             propertyIndex, association.itemId);
 
-    mItemProperties[propertyIndex]->attachTo(
-            mItemIdToItemMap.editValueAt(itemIndex));
+    mItemProperties[propertyIndex]->attachTo(mItemIdToItemMap.editValueAt(itemIndex));
 }
 
-sp<MetaData> ItemTable::getImageMeta() {
+uint32_t ItemTable::countImages() const {
+    return mImageItemsValid ? mDisplayables.size() : 0;
+}
+
+sp<MetaData> ItemTable::getImageMeta(const uint32_t imageIndex) {
     if (!mImageItemsValid) {
         return NULL;
     }
 
-    ssize_t itemIndex = mItemIdToItemMap.indexOfKey(mPrimaryItemId);
-    if (itemIndex < 0) {
-        ALOGE("Primary item id %d not found!", mPrimaryItemId);
+    if (imageIndex >= mDisplayables.size()) {
+        ALOGE("%s: invalid image index %u", __FUNCTION__, imageIndex);
         return NULL;
     }
-
-    ALOGV("primary item index %zu", itemIndex);
+    const uint32_t itemIndex = mDisplayables[imageIndex];
+    ALOGV("image[%u]: item index %u", imageIndex, itemIndex);
 
     const ImageItem *image = &mItemIdToItemMap[itemIndex];
 
     sp<MetaData> meta = new MetaData;
-    meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_HEVC);
+    meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_IMAGE_ANDROID_HEIC);
 
-    ALOGV("setting image size %dx%d", image->width, image->height);
+    if (image->itemId == mPrimaryItemId) {
+        meta->setInt32(kKeyIsPrimaryImage, 1);
+    }
+
+    ALOGV("image[%u]: size %dx%d", imageIndex, image->width, image->height);
+
     meta->setInt32(kKeyWidth, image->width);
     meta->setInt32(kKeyHeight, image->height);
     if (image->rotation != 0) {
@@ -1392,8 +1453,8 @@
             meta->setInt32(kKeyThumbnailHeight, thumbnail.height);
             meta->setData(kKeyThumbnailHVCC, kTypeHVCC,
                     thumbnail.hvcc->data(), thumbnail.hvcc->size());
-            ALOGV("thumbnail meta: %dx%d, item index %zd",
-                    thumbnail.width, thumbnail.height, thumbItemIndex);
+            ALOGV("image[%u]: thumbnail: size %dx%d, item index %zd",
+                    imageIndex, thumbnail.width, thumbnail.height, thumbItemIndex);
         } else {
             ALOGW("%s: Referenced thumbnail does not exist!", __FUNCTION__);
         }
@@ -1404,23 +1465,18 @@
         if (tileItemIndex < 0) {
             return NULL;
         }
-        // when there are tiles, (kKeyWidth, kKeyHeight) is the full tiled area,
-        // and (kKeyDisplayWidth, kKeyDisplayHeight) may be smaller than that.
-        meta->setInt32(kKeyDisplayWidth, image->width);
-        meta->setInt32(kKeyDisplayHeight, image->height);
-        int32_t gridRows = image->rows, gridCols = image->columns;
+        meta->setInt32(kKeyGridRows, image->rows);
+        meta->setInt32(kKeyGridCols, image->columns);
 
         // point image to the first tile for grid size and HVCC
         image = &mItemIdToItemMap.editValueAt(tileItemIndex);
-        meta->setInt32(kKeyWidth, image->width * gridCols);
-        meta->setInt32(kKeyHeight, image->height * gridRows);
         meta->setInt32(kKeyGridWidth, image->width);
         meta->setInt32(kKeyGridHeight, image->height);
         meta->setInt32(kKeyMaxInputSize, image->width * image->height * 1.5);
     }
 
     if (image->hvcc == NULL) {
-        ALOGE("%s: hvcc is missing for item index %zd!", __FUNCTION__, itemIndex);
+        ALOGE("%s: hvcc is missing for image[%u]!", __FUNCTION__, imageIndex);
         return NULL;
     }
     meta->setData(kKeyHVCC, kTypeHVCC, image->hvcc->data(), image->hvcc->size());
@@ -1431,48 +1487,46 @@
     return meta;
 }
 
-uint32_t ItemTable::countImages() const {
-    return mImageItemsValid ? mItemIdToItemMap.size() : 0;
-}
-
-status_t ItemTable::findPrimaryImage(uint32_t *itemIndex) {
+status_t ItemTable::findImageItem(const uint32_t imageIndex, uint32_t *itemIndex) {
     if (!mImageItemsValid) {
         return INVALID_OPERATION;
     }
 
-    ssize_t index = mItemIdToItemMap.indexOfKey(mPrimaryItemId);
-    if (index < 0) {
-        return ERROR_MALFORMED;
+    if (imageIndex >= mDisplayables.size()) {
+        ALOGE("%s: invalid image index %d", __FUNCTION__, imageIndex);
+        return BAD_VALUE;
     }
 
-    *itemIndex = index;
+    *itemIndex = mDisplayables[imageIndex];
+
+    ALOGV("image[%u]: item index %u", imageIndex, *itemIndex);
     return OK;
 }
 
-status_t ItemTable::findThumbnail(uint32_t *itemIndex) {
+status_t ItemTable::findThumbnailItem(const uint32_t imageIndex, uint32_t *itemIndex) {
     if (!mImageItemsValid) {
         return INVALID_OPERATION;
     }
 
-    ssize_t primaryItemIndex = mItemIdToItemMap.indexOfKey(mPrimaryItemId);
-    if (primaryItemIndex < 0) {
-        ALOGE("%s: Primary item id %d not found!", __FUNCTION__, mPrimaryItemId);
-        return ERROR_MALFORMED;
+    if (imageIndex >= mDisplayables.size()) {
+        ALOGE("%s: invalid image index %d", __FUNCTION__, imageIndex);
+        return BAD_VALUE;
     }
 
-    const ImageItem &primaryImage = mItemIdToItemMap[primaryItemIndex];
-    if (primaryImage.thumbnails.empty()) {
-        ALOGW("%s: Using primary in place of thumbnail.", __FUNCTION__);
-        *itemIndex = primaryItemIndex;
+    uint32_t masterItemIndex = mDisplayables[imageIndex];
+
+    const ImageItem &masterImage = mItemIdToItemMap[masterItemIndex];
+    if (masterImage.thumbnails.empty()) {
+        *itemIndex = masterItemIndex;
         return OK;
     }
 
-    ssize_t thumbItemIndex = mItemIdToItemMap.indexOfKey(
-            primaryImage.thumbnails[0]);
+    ssize_t thumbItemIndex = mItemIdToItemMap.indexOfKey(masterImage.thumbnails[0]);
     if (thumbItemIndex < 0) {
-        ALOGE("%s: Thumbnail item id %d not found!",
-                __FUNCTION__, primaryImage.thumbnails[0]);
-        return ERROR_MALFORMED;
+        ALOGW("%s: Thumbnail item id %d not found, use master instead",
+                __FUNCTION__, masterImage.thumbnails[0]);
+        *itemIndex = masterItemIndex;
+        return OK;
     }
 
     *itemIndex = thumbItemIndex;
diff --git a/media/extractors/mp4/ItemTable.h b/media/extractors/mp4/ItemTable.h
index 6591271..3d2e2ae 100644
--- a/media/extractors/mp4/ItemTable.h
+++ b/media/extractors/mp4/ItemTable.h
@@ -49,12 +49,12 @@
     status_t parse(uint32_t type, off64_t offset, size_t size);
 
     bool isValid() { return mImageItemsValid; }
-    sp<MetaData> getImageMeta();
     uint32_t countImages() const;
-    status_t findPrimaryImage(uint32_t *imageIndex);
-    status_t findThumbnail(uint32_t *thumbnailIndex);
+    sp<MetaData> getImageMeta(const uint32_t imageIndex);
+    status_t findImageItem(const uint32_t imageIndex, uint32_t *itemIndex);
+    status_t findThumbnailItem(const uint32_t imageIndex, uint32_t *itemIndex);
     status_t getImageOffsetAndSize(
-            uint32_t *imageIndex, off64_t *offset, size_t *size);
+            uint32_t *itemIndex, off64_t *offset, size_t *size);
 
 protected:
     ~ItemTable();
@@ -78,6 +78,7 @@
     bool mImageItemsValid;
     uint32_t mCurrentItemIndex;
     KeyedVector<uint32_t, ImageItem> mItemIdToItemMap;
+    Vector<uint32_t> mDisplayables;
 
     status_t parseIlocBox(off64_t offset, size_t size);
     status_t parseIinfBox(off64_t offset, size_t size);
diff --git a/media/extractors/mp4/MPEG4Extractor.cpp b/media/extractors/mp4/MPEG4Extractor.cpp
index 1c0516d..6671956 100644
--- a/media/extractors/mp4/MPEG4Extractor.cpp
+++ b/media/extractors/mp4/MPEG4Extractor.cpp
@@ -31,6 +31,7 @@
 #include "ItemTable.h"
 #include "include/ESDS.h"
 
+#include <media/MediaSource.h>
 #include <media/stagefright/foundation/ABitReader.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
@@ -38,17 +39,16 @@
 #include <media/stagefright/foundation/AUtils.h>
 #include <media/stagefright/foundation/ByteUtils.h>
 #include <media/stagefright/foundation/ColorUtils.h>
+#include <media/stagefright/foundation/avc_utils.h>
 #include <media/stagefright/foundation/hexdump.h>
 #include <media/stagefright/MediaBuffer.h>
 #include <media/stagefright/MediaBufferGroup.h>
 #include <media/stagefright/MediaDefs.h>
-#include <media/stagefright/MediaSource.h>
 #include <media/stagefright/MetaData.h>
 #include <utils/String8.h>
 
 #include <byteswap.h>
 #include "include/ID3.h"
-#include "include/avc_utils.h"
 
 #ifndef UINT32_MAX
 #define UINT32_MAX       (4294967295U)
@@ -138,7 +138,7 @@
 
     uint8_t *mSrcBuffer;
 
-    bool mIsHEIF;
+    bool mIsHeif;
     sp<ItemTable> mItemTable;
 
     size_t parseNALSize(const uint8_t *data) const;
@@ -338,7 +338,7 @@
     return false;
 }
 
-MPEG4Extractor::MPEG4Extractor(const sp<DataSource> &source)
+MPEG4Extractor::MPEG4Extractor(const sp<DataSource> &source, const char *mime)
     : mMoofOffset(0),
       mMoofFound(false),
       mMdatFound(false),
@@ -346,12 +346,15 @@
       mInitCheck(NO_INIT),
       mHeaderTimescale(0),
       mIsQT(false),
-      mIsHEIF(false),
+      mIsHeif(false),
+      mIsHeifSequence(false),
+      mPreferHeif(mime != NULL && !strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_HEIF)),
       mFirstTrack(NULL),
       mLastTrack(NULL),
       mFileMetaData(new MetaData),
       mFirstSINF(NULL),
       mIsDrm(false) {
+    ALOGV("mime=%s, mPreferHeif=%d", mime, mPreferHeif);
 }
 
 MPEG4Extractor::~MPEG4Extractor() {
@@ -560,8 +563,9 @@
     status_t err;
     bool sawMoovOrSidx = false;
 
-    while (!((sawMoovOrSidx && (mMdatFound || mMoofFound)) ||
-            (mIsHEIF && (mItemTable != NULL) && mItemTable->isValid()))) {
+    while (!((!mIsHeif && sawMoovOrSidx && (mMdatFound || mMoofFound)) ||
+             (mIsHeif && (mPreferHeif || !mIsHeifSequence)
+                     && (mItemTable != NULL) && mItemTable->isValid()))) {
         off64_t orig_offset = offset;
         err = parseChunk(&offset, 0);
 
@@ -578,12 +582,47 @@
         }
     }
 
+    if (mIsHeif) {
+        uint32_t imageCount = mItemTable->countImages();
+        if (imageCount == 0) {
+            ALOGE("found no image in heif!");
+        } else {
+            for (uint32_t imageIndex = 0; imageIndex < imageCount; imageIndex++) {
+                sp<MetaData> meta = mItemTable->getImageMeta(imageIndex);
+                if (meta == NULL) {
+                    ALOGE("heif image %u has no meta!", imageIndex);
+                    continue;
+                }
+
+                ALOGV("adding HEIF image track %u", imageIndex);
+                Track *track = new Track;
+                track->next = NULL;
+                if (mLastTrack != NULL) {
+                    mLastTrack->next = track;
+                } else {
+                    mFirstTrack = track;
+                }
+                mLastTrack = track;
+
+                track->meta = meta;
+                track->meta->setInt32(kKeyTrackID, imageIndex);
+                track->includes_expensive_metadata = false;
+                track->skipTrack = false;
+                track->timescale = 0;
+            }
+        }
+    }
+
     if (mInitCheck == OK) {
         if (findTrackByMimePrefix("video/") != NULL) {
             mFileMetaData->setCString(
                     kKeyMIMEType, MEDIA_MIMETYPE_CONTAINER_MPEG4);
         } else if (findTrackByMimePrefix("audio/") != NULL) {
             mFileMetaData->setCString(kKeyMIMEType, "audio/mp4");
+        } else if (findTrackByMimePrefix(
+                MEDIA_MIMETYPE_IMAGE_ANDROID_HEIC) != NULL) {
+            mFileMetaData->setCString(
+                    kKeyMIMEType, MEDIA_MIMETYPE_CONTAINER_HEIF);
         } else {
             mFileMetaData->setCString(kKeyMIMEType, "application/octet-stream");
         }
@@ -614,28 +653,6 @@
         free(buf);
     }
 
-    if (mIsHEIF) {
-        sp<MetaData> meta = mItemTable->getImageMeta();
-        if (meta == NULL) {
-            return ERROR_MALFORMED;
-        }
-
-        Track *track = mLastTrack;
-        if (track != NULL) {
-            ALOGW("track is set before metadata is fully processed");
-        } else {
-            track = new Track;
-            track->next = NULL;
-            mFirstTrack = mLastTrack = track;
-        }
-
-        track->meta = meta;
-        track->meta->setInt32(kKeyTrackID, 0);
-        track->includes_expensive_metadata = false;
-        track->skipTrack = false;
-        track->timescale = 0;
-    }
-
     return mInitCheck;
 }
 
@@ -1037,6 +1054,7 @@
                 }
                 isTrack = true;
 
+                ALOGV("adding new track");
                 Track *track = new Track;
                 track->next = NULL;
                 if (mLastTrack) {
@@ -1084,6 +1102,7 @@
                 }
 
                 if (mLastTrack->skipTrack) {
+                    ALOGV("skipping this track...");
                     Track *cur = mFirstTrack;
 
                     if (cur == mLastTrack) {
@@ -1260,6 +1279,25 @@
             break;
         }
 
+        case FOURCC('t', 'r', 'e', 'f'):
+        {
+            *offset += chunk_size;
+
+            if (mLastTrack == NULL) {
+                return ERROR_MALFORMED;
+            }
+
+            // Skip thumbnail track for now since we don't have an
+            // API to retrieve it yet.
+            // The thumbnail track can't be accessed by negative index or time,
+            // because each timed sample has its own corresponding thumbnail
+            // in the thumbnail track. We'll need a dedicated API to retrieve
+            // thumbnail at time instead.
+            mLastTrack->skipTrack = true;
+
+            break;
+        }
+
         case FOURCC('p', 's', 's', 'h'):
         {
             *offset += chunk_size;
@@ -1721,6 +1759,9 @@
                     // ratio. Use compression ratio of 1.
                     max_size = width * height * 3 / 2;
                 }
+                // HACK: allow 10% overhead
+                // TODO: read sample size from traf atom for fragmented MPEG4.
+                max_size += max_size / 10;
                 mLastTrack->meta->setInt32(kKeyMaxInputSize, max_size);
             }
 
@@ -1755,6 +1796,8 @@
                             mLastTrack->meta->setInt32(kKeyFrameRate, frameRate);
                         }
                     }
+                    ALOGV("setting frame count %zu", nSamples);
+                    mLastTrack->meta->setInt32(kKeyFrameCount, nSamples);
                 }
             }
 
@@ -2086,7 +2129,7 @@
         case FOURCC('i', 'r', 'e', 'f'):
         case FOURCC('i', 'p', 'r', 'o'):
         {
-            if (mIsHEIF) {
+            if (mIsHeif) {
                 if (mItemTable == NULL) {
                     mItemTable = new ItemTable(mDataSource);
                 }
@@ -2466,10 +2509,17 @@
 
             if (brandSet.count(FOURCC('q', 't', ' ', ' ')) > 0) {
                 mIsQT = true;
-            } else if (brandSet.count(FOURCC('m', 'i', 'f', '1')) > 0
-                    && brandSet.count(FOURCC('h', 'e', 'i', 'c')) > 0) {
-                mIsHEIF = true;
-                ALOGV("identified HEIF image");
+            } else {
+                if (brandSet.count(FOURCC('m', 'i', 'f', '1')) > 0
+                 && brandSet.count(FOURCC('h', 'e', 'i', 'c')) > 0) {
+                    mIsHeif = true;
+                    ALOGV("identified HEIF image");
+                }
+                if (brandSet.count(FOURCC('m', 's', 'f', '1')) > 0
+                 && brandSet.count(FOURCC('h', 'e', 'v', 'c')) > 0) {
+                    mIsHeifSequence = true;
+                    ALOGV("identified HEIF image sequence");
+                }
             }
 
             *offset = stop_offset;
@@ -3388,6 +3438,7 @@
         return NULL;
     }
 
+    sp<ItemTable> itemTable;
     if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)) {
         uint32_t type;
         const void *data;
@@ -3401,7 +3452,8 @@
         if (size < 7 || ptr[0] != 1) {  // configurationVersion == 1
             return NULL;
         }
-    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_HEVC)) {
+    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_HEVC)
+            || !strcasecmp(mime, MEDIA_MIMETYPE_IMAGE_ANDROID_HEIC)) {
         uint32_t type;
         const void *data;
         size_t size;
@@ -3414,11 +3466,14 @@
         if (size < 22 || ptr[0] != 1) {  // configurationVersion == 1
             return NULL;
         }
+        if (!strcasecmp(mime, MEDIA_MIMETYPE_IMAGE_ANDROID_HEIC)) {
+            itemTable = mItemTable;
+        }
     }
 
     sp<MPEG4Source> source =  new MPEG4Source(this,
             track->meta, mDataSource, track->timescale, track->sampleTable,
-            mSidxEntries, trex, mMoofOffset, mItemTable);
+            mSidxEntries, trex, mMoofOffset, itemTable);
     if (source->init() != OK) {
         return NULL;
     }
@@ -3846,7 +3901,7 @@
       mBuffer(NULL),
       mWantsNALFragments(false),
       mSrcBuffer(NULL),
-      mIsHEIF(itemTable != NULL),
+      mIsHeif(itemTable != NULL),
       mItemTable(itemTable) {
 
     memset(&mTrackFragmentHeaderInfo, 0, sizeof(mTrackFragmentHeaderInfo));
@@ -3868,7 +3923,8 @@
     CHECK(success);
 
     mIsAVC = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC);
-    mIsHEVC = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_HEVC);
+    mIsHEVC = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_HEVC) ||
+              !strcasecmp(mime, MEDIA_MIMETYPE_IMAGE_ANDROID_HEIC);
 
     if (mIsAVC) {
         uint32_t type;
@@ -4622,15 +4678,19 @@
     int64_t seekTimeUs;
     ReadOptions::SeekMode mode;
     if (options && options->getSeekTo(&seekTimeUs, &mode)) {
-        if (mIsHEIF) {
+        if (mIsHeif) {
             CHECK(mSampleTable == NULL);
             CHECK(mItemTable != NULL);
+            int32_t imageIndex;
+            if (!mFormat->findInt32(kKeyTrackID, &imageIndex)) {
+                return ERROR_MALFORMED;
+            }
 
             status_t err;
             if (seekTimeUs >= 0) {
-                err = mItemTable->findPrimaryImage(&mCurrentSampleIndex);
+                err = mItemTable->findImageItem(imageIndex, &mCurrentSampleIndex);
             } else {
-                err = mItemTable->findThumbnail(&mCurrentSampleIndex);
+                err = mItemTable->findThumbnailItem(imageIndex, &mCurrentSampleIndex);
             }
             if (err != OK) {
                 return err;
@@ -4648,6 +4708,9 @@
                 case ReadOptions::SEEK_CLOSEST:
                     findFlags = SampleTable::kFlagClosest;
                     break;
+                case ReadOptions::SEEK_FRAME_INDEX:
+                    findFlags = SampleTable::kFlagFrameIndex;
+                    break;
                 default:
                     CHECK(!"Should not be here.");
                     break;
@@ -4658,7 +4721,8 @@
                     seekTimeUs, 1000000, mTimescale,
                     &sampleIndex, findFlags);
 
-            if (mode == ReadOptions::SEEK_CLOSEST) {
+            if (mode == ReadOptions::SEEK_CLOSEST
+                    || mode == ReadOptions::SEEK_FRAME_INDEX) {
                 // We found the closest sample already, now we want the sync
                 // sample preceding it (or the sample itself of course), even
                 // if the subsequent sync sample is closer.
@@ -4690,7 +4754,8 @@
                 return err;
             }
 
-            if (mode == ReadOptions::SEEK_CLOSEST) {
+            if (mode == ReadOptions::SEEK_CLOSEST
+                || mode == ReadOptions::SEEK_FRAME_INDEX) {
                 targetSampleTimeUs = (sampleTime * 1000000ll) / mTimescale;
             }
 
@@ -4726,7 +4791,7 @@
         newBuffer = true;
 
         status_t err;
-        if (!mIsHEIF) {
+        if (!mIsHeif) {
             err = mSampleTable->getMetaDataForSample(
                     mCurrentSampleIndex, &offset, &size, &cts, &isSyncSample, &stts);
         } else {
@@ -4751,6 +4816,8 @@
         }
         if (size > mBuffer->size()) {
             ALOGE("buffer too small: %zu > %zu", size, mBuffer->size());
+            mBuffer->release();
+            mBuffer = NULL;
             return ERROR_BUFFER_TOO_SMALL;
         }
     }
@@ -5043,6 +5110,8 @@
         }
         if (size > mBuffer->size()) {
             ALOGE("buffer too small: %zu > %zu", size, mBuffer->size());
+            mBuffer->release();
+            mBuffer = NULL;
             return ERROR_BUFFER_TOO_SMALL;
         }
     }
@@ -5309,7 +5378,8 @@
         || !memcmp(header, "ftypisom", 8) || !memcmp(header, "ftypM4V ", 8)
         || !memcmp(header, "ftypM4A ", 8) || !memcmp(header, "ftypf4v ", 8)
         || !memcmp(header, "ftypkddi", 8) || !memcmp(header, "ftypM4VP", 8)
-        || !memcmp(header, "ftypmif1", 8) || !memcmp(header, "ftypheic", 8)) {
+        || !memcmp(header, "ftypmif1", 8) || !memcmp(header, "ftypheic", 8)
+        || !memcmp(header, "ftypmsf1", 8) || !memcmp(header, "ftyphevc", 8)) {
         *mimeType = MEDIA_MIMETYPE_CONTAINER_MPEG4;
         *confidence = 0.4;
 
@@ -5340,6 +5410,8 @@
         FOURCC('3', 'g', '2', 'b'),
         FOURCC('m', 'i', 'f', '1'),  // HEIF image
         FOURCC('h', 'e', 'i', 'c'),  // HEIF image
+        FOURCC('m', 's', 'f', '1'),  // HEIF image sequence
+        FOURCC('h', 'e', 'v', 'c'),  // HEIF image sequence
     };
 
     for (size_t i = 0;
diff --git a/media/extractors/mp4/MPEG4Extractor.h b/media/extractors/mp4/MPEG4Extractor.h
index 0e33ded..d4f17e3 100644
--- a/media/extractors/mp4/MPEG4Extractor.h
+++ b/media/extractors/mp4/MPEG4Extractor.h
@@ -20,8 +20,8 @@
 
 #include <arpa/inet.h>
 
-#include <media/stagefright/DataSource.h>
-#include <media/stagefright/MediaExtractor.h>
+#include <media/DataSource.h>
+#include <media/MediaExtractor.h>
 #include <utils/List.h>
 #include <utils/Vector.h>
 #include <utils/String8.h>
@@ -52,7 +52,7 @@
 class MPEG4Extractor : public MediaExtractor {
 public:
     // Extractor assumes ownership of "source".
-    explicit MPEG4Extractor(const sp<DataSource> &source);
+    explicit MPEG4Extractor(const sp<DataSource> &source, const char *mime = NULL);
 
     virtual size_t countTracks();
     virtual sp<MediaSource> getTrack(size_t index);
@@ -103,7 +103,9 @@
     status_t mInitCheck;
     uint32_t mHeaderTimescale;
     bool mIsQT;
-    bool mIsHEIF;
+    bool mIsHeif;
+    bool mIsHeifSequence;
+    bool mPreferHeif;
 
     Track *mFirstTrack, *mLastTrack;
 
diff --git a/media/extractors/mp4/SampleIterator.cpp b/media/extractors/mp4/SampleIterator.cpp
index 1fc6666..78cc691 100644
--- a/media/extractors/mp4/SampleIterator.cpp
+++ b/media/extractors/mp4/SampleIterator.cpp
@@ -22,9 +22,9 @@
 
 #include <arpa/inet.h>
 
+#include <media/DataSource.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/ByteUtils.h>
-#include <media/stagefright/DataSource.h>
 
 #include "SampleTable.h"
 
diff --git a/media/extractors/mp4/SampleTable.cpp b/media/extractors/mp4/SampleTable.cpp
index 6d64519..378d63a 100644
--- a/media/extractors/mp4/SampleTable.cpp
+++ b/media/extractors/mp4/SampleTable.cpp
@@ -25,9 +25,9 @@
 
 #include <arpa/inet.h>
 
+#include <media/DataSource.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/ByteUtils.h>
-#include <media/stagefright/DataSource.h>
 
 /* TODO: remove after being merged into other branches */
 #ifndef UINT32_MAX
@@ -724,6 +724,14 @@
         return ERROR_OUT_OF_RANGE;
     }
 
+    if (flags == kFlagFrameIndex) {
+        if (req_time >= mNumSampleSizes) {
+            return ERROR_OUT_OF_RANGE;
+        }
+        *sample_index = mSampleTimeEntries[req_time].mSampleIndex;
+        return OK;
+    }
+
     uint32_t left = 0;
     uint32_t right_plus_one = mNumSampleSizes;
     while (left < right_plus_one) {
diff --git a/media/extractors/mp4/SampleTable.h b/media/extractors/mp4/SampleTable.h
index eb1a674..466e26b 100644
--- a/media/extractors/mp4/SampleTable.h
+++ b/media/extractors/mp4/SampleTable.h
@@ -72,7 +72,8 @@
     enum {
         kFlagBefore,
         kFlagAfter,
-        kFlagClosest
+        kFlagClosest,
+        kFlagFrameIndex,
     };
     status_t findSampleAtTime(
             uint64_t req_time, uint64_t scale_num, uint64_t scale_den,
diff --git a/media/extractors/mpeg2/Android.bp b/media/extractors/mpeg2/Android.bp
index e69afd8..50f740b 100644
--- a/media/extractors/mpeg2/Android.bp
+++ b/media/extractors/mpeg2/Android.bp
@@ -12,19 +12,19 @@
     ],
 
     shared_libs: [
-        "libbinder",
-        "libstagefright",
-        "libmedia",
-        "libstagefright_foundation",
-        "libcutils",
-        "libutils",
-        "liblog",
-        "libcrypto",
-        "libmedia",
-        "libhidlbase",
-        "android.hidl.token@1.0-utils",
         "android.hardware.cas@1.0",
         "android.hardware.cas.native@1.0",
+        "android.hidl.token@1.0-utils",
+        "libbinder",
+        "libcrypto",
+        "libcutils",
+        "libhidlbase",
+        "liblog",
+        "libmedia",  // Needed for IStreamListener
+        "libmediaextractor",
+        "libstagefright",  // Needed for AnotherPacketSource and more
+        "libstagefright_foundation",
+        "libutils",
     ],
 
     static_libs: [
diff --git a/media/extractors/mpeg2/ExtractorBundle.cpp b/media/extractors/mpeg2/ExtractorBundle.cpp
index 076515e..d5682e9 100644
--- a/media/extractors/mpeg2/ExtractorBundle.cpp
+++ b/media/extractors/mpeg2/ExtractorBundle.cpp
@@ -18,7 +18,7 @@
 #define LOG_TAG "MPEG2ExtractorBundle"
 #include <utils/Log.h>
 
-#include <media/stagefright/MediaExtractor.h>
+#include <media/MediaExtractor.h>
 #include "MPEG2PSExtractor.h"
 #include "MPEG2TSExtractor.h"
 
diff --git a/media/extractors/mpeg2/MPEG2PSExtractor.cpp b/media/extractors/mpeg2/MPEG2PSExtractor.cpp
index 2b5b5e8..c519caf 100644
--- a/media/extractors/mpeg2/MPEG2PSExtractor.cpp
+++ b/media/extractors/mpeg2/MPEG2PSExtractor.cpp
@@ -23,16 +23,16 @@
 #include "mpeg2ts/AnotherPacketSource.h"
 #include "mpeg2ts/ESQueue.h"
 
+#include <media/DataSource.h>
+#include <media/MediaSource.h>
 #include <media/stagefright/foundation/ABitReader.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
 #include <media/stagefright/foundation/ByteUtils.h>
 #include <media/stagefright/foundation/hexdump.h>
-#include <media/stagefright/DataSource.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/MediaSource.h>
 #include <media/stagefright/MetaData.h>
 #include <utils/String8.h>
 
diff --git a/media/extractors/mpeg2/MPEG2PSExtractor.h b/media/extractors/mpeg2/MPEG2PSExtractor.h
index 75e1346..ab3ab05 100644
--- a/media/extractors/mpeg2/MPEG2PSExtractor.h
+++ b/media/extractors/mpeg2/MPEG2PSExtractor.h
@@ -19,7 +19,7 @@
 #define MPEG2_PS_EXTRACTOR_H_
 
 #include <media/stagefright/foundation/ABase.h>
-#include <media/stagefright/MediaExtractor.h>
+#include <media/MediaExtractor.h>
 #include <utils/threads.h>
 #include <utils/KeyedVector.h>
 
diff --git a/media/extractors/mpeg2/MPEG2TSExtractor.cpp b/media/extractors/mpeg2/MPEG2TSExtractor.cpp
index d42e901..4f61e16 100644
--- a/media/extractors/mpeg2/MPEG2TSExtractor.cpp
+++ b/media/extractors/mpeg2/MPEG2TSExtractor.cpp
@@ -22,16 +22,16 @@
 
 #include "MPEG2TSExtractor.h"
 
+#include <media/DataSource.h>
+#include <media/IStreamSource.h>
+#include <media/MediaSource.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/ALooper.h>
 #include <media/stagefright/foundation/AUtils.h>
-#include <media/stagefright/DataSource.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/MediaSource.h>
 #include <media/stagefright/MetaData.h>
-#include <media/IStreamSource.h>
 #include <utils/String8.h>
 
 #include "mpeg2ts/AnotherPacketSource.h"
@@ -512,6 +512,8 @@
                 --index;
             }
             break;
+        default:
+            return ERROR_UNSUPPORTED;
     }
     if (!shouldSeekBeyond || mOffset <= mSeekSyncPoints->valueAt(index)) {
         int64_t actualSeekTimeUs = mSeekSyncPoints->keyAt(index);
diff --git a/media/extractors/mpeg2/MPEG2TSExtractor.h b/media/extractors/mpeg2/MPEG2TSExtractor.h
index 1702157..55356bf 100644
--- a/media/extractors/mpeg2/MPEG2TSExtractor.h
+++ b/media/extractors/mpeg2/MPEG2TSExtractor.h
@@ -19,8 +19,8 @@
 #define MPEG2_TS_EXTRACTOR_H_
 
 #include <media/stagefright/foundation/ABase.h>
-#include <media/stagefright/MediaExtractor.h>
-#include <media/stagefright/MediaSource.h>
+#include <media/MediaExtractor.h>
+#include <media/MediaSource.h>
 #include <utils/threads.h>
 #include <utils/KeyedVector.h>
 #include <utils/Vector.h>
diff --git a/media/extractors/ogg/Android.bp b/media/extractors/ogg/Android.bp
index 17b939a..6bd8025 100644
--- a/media/extractors/ogg/Android.bp
+++ b/media/extractors/ogg/Android.bp
@@ -8,11 +8,13 @@
     ],
 
     shared_libs: [
-        "libstagefright",
-        "libmedia",
+        "liblog",
+        "libmediaextractor",
         "libstagefright_foundation",
         "libutils",
-        "liblog",
+    ],
+
+    static_libs: [
         "libvorbisidec",
     ],
 
diff --git a/media/extractors/ogg/OggExtractor.cpp b/media/extractors/ogg/OggExtractor.cpp
index f8e501a..f42a6a8 100644
--- a/media/extractors/ogg/OggExtractor.cpp
+++ b/media/extractors/ogg/OggExtractor.cpp
@@ -21,16 +21,16 @@
 #include "OggExtractor.h"
 
 #include <cutils/properties.h>
+#include <media/DataSource.h>
+#include <media/MediaSource.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/base64.h>
 #include <media/stagefright/foundation/ByteUtils.h>
-#include <media/stagefright/DataSource.h>
 #include <media/stagefright/MediaBuffer.h>
 #include <media/stagefright/MediaBufferGroup.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/MediaSource.h>
 #include <media/stagefright/MetaData.h>
 #include <utils/String8.h>
 
diff --git a/media/extractors/ogg/OggExtractor.h b/media/extractors/ogg/OggExtractor.h
index f42c105..0f7fe5f 100644
--- a/media/extractors/ogg/OggExtractor.h
+++ b/media/extractors/ogg/OggExtractor.h
@@ -19,7 +19,7 @@
 #define OGG_EXTRACTOR_H_
 
 #include <utils/Errors.h>
-#include <media/stagefright/MediaExtractor.h>
+#include <media/MediaExtractor.h>
 
 namespace android {
 
diff --git a/media/extractors/wav/Android.bp b/media/extractors/wav/Android.bp
index ead02a9..f310892 100644
--- a/media/extractors/wav/Android.bp
+++ b/media/extractors/wav/Android.bp
@@ -7,11 +7,10 @@
     ],
 
     shared_libs: [
-        "libstagefright",
-        "libmedia",
+        "liblog",
+        "libmediaextractor",
         "libstagefright_foundation",
         "libutils",
-        "liblog",
     ],
 
     static_libs: [
diff --git a/media/extractors/wav/WAVExtractor.cpp b/media/extractors/wav/WAVExtractor.cpp
index cce488b..6c5f893 100644
--- a/media/extractors/wav/WAVExtractor.cpp
+++ b/media/extractors/wav/WAVExtractor.cpp
@@ -21,12 +21,12 @@
 #include "WAVExtractor.h"
 
 #include <audio_utils/primitives.h>
+#include <media/DataSource.h>
+#include <media/MediaSource.h>
 #include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/DataSource.h>
 #include <media/stagefright/MediaBufferGroup.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/MediaSource.h>
 #include <media/stagefright/MetaData.h>
 #include <utils/String8.h>
 #include <cutils/bitops.h>
diff --git a/media/extractors/wav/WAVExtractor.h b/media/extractors/wav/WAVExtractor.h
index 9fe0335..98a2dfa 100644
--- a/media/extractors/wav/WAVExtractor.h
+++ b/media/extractors/wav/WAVExtractor.h
@@ -19,7 +19,7 @@
 #define WAV_EXTRACTOR_H_
 
 #include <utils/Errors.h>
-#include <media/stagefright/MediaExtractor.h>
+#include <media/MediaExtractor.h>
 
 namespace android {
 
diff --git a/media/libaaudio/Android.bp b/media/libaaudio/Android.bp
index 6e60f24..f00f7a8 100644
--- a/media/libaaudio/Android.bp
+++ b/media/libaaudio/Android.bp
@@ -28,3 +28,10 @@
     first_version: "26",
     unversioned_until: "current",
 }
+
+cc_library_headers {
+    name: "libaaudio_headers",
+    export_include_dirs: ["include"],
+}
+
+subdirs = ["*"]
diff --git a/media/libaaudio/Android.mk b/media/libaaudio/Android.mk
deleted file mode 100644
index 5053e7d..0000000
--- a/media/libaaudio/Android.mk
+++ /dev/null
@@ -1 +0,0 @@
-include $(call all-subdir-makefiles)
diff --git a/media/libaaudio/examples/Android.bp b/media/libaaudio/examples/Android.bp
new file mode 100644
index 0000000..639fab2
--- /dev/null
+++ b/media/libaaudio/examples/Android.bp
@@ -0,0 +1,6 @@
+subdirs = ["*"]
+
+cc_library_headers {
+    name: "libaaudio_example_utils",
+    export_include_dirs: ["utils"],
+}
diff --git a/media/libaaudio/examples/Android.mk b/media/libaaudio/examples/Android.mk
deleted file mode 100644
index 5053e7d..0000000
--- a/media/libaaudio/examples/Android.mk
+++ /dev/null
@@ -1 +0,0 @@
-include $(call all-subdir-makefiles)
diff --git a/media/libaaudio/examples/input_monitor/Android.bp b/media/libaaudio/examples/input_monitor/Android.bp
new file mode 100644
index 0000000..2c3418d
--- /dev/null
+++ b/media/libaaudio/examples/input_monitor/Android.bp
@@ -0,0 +1,15 @@
+cc_test {
+    name: "input_monitor",
+    gtest: false,
+    srcs: ["src/input_monitor.cpp"],
+    shared_libs: ["libaaudio"],
+    header_libs: ["libaaudio_example_utils"],
+}
+
+cc_test {
+    name: "input_monitor_callback",
+    gtest: false,
+    srcs: ["src/input_monitor_callback.cpp"],
+    shared_libs: ["libaaudio"],
+    header_libs: ["libaaudio_example_utils"],
+}
diff --git a/media/libaaudio/examples/input_monitor/Android.mk b/media/libaaudio/examples/input_monitor/Android.mk
deleted file mode 100644
index 5053e7d..0000000
--- a/media/libaaudio/examples/input_monitor/Android.mk
+++ /dev/null
@@ -1 +0,0 @@
-include $(call all-subdir-makefiles)
diff --git a/media/libaaudio/examples/input_monitor/jni/Android.mk b/media/libaaudio/examples/input_monitor/jni/Android.mk
index 9b1ce2c..a0b981c 100644
--- a/media/libaaudio/examples/input_monitor/jni/Android.mk
+++ b/media/libaaudio/examples/input_monitor/jni/Android.mk
@@ -10,6 +10,7 @@
 
 # NDK recommends using this kind of relative path instead of an absolute path.
 LOCAL_SRC_FILES:= ../src/input_monitor.cpp
+LOCAL_CFLAGS := -Wall -Werror
 LOCAL_SHARED_LIBRARIES := libaaudio
 LOCAL_MODULE := input_monitor
 include $(BUILD_EXECUTABLE)
@@ -22,6 +23,7 @@
     frameworks/av/media/libaaudio/examples/utils
 
 LOCAL_SRC_FILES:= ../src/input_monitor_callback.cpp
+LOCAL_CFLAGS := -Wall -Werror
 LOCAL_SHARED_LIBRARIES := libaaudio
 LOCAL_MODULE := input_monitor_callback
 include $(BUILD_EXECUTABLE)
diff --git a/media/libaaudio/examples/input_monitor/src/input_monitor.cpp b/media/libaaudio/examples/input_monitor/src/input_monitor.cpp
index 9feb118..e5ad2d9 100644
--- a/media/libaaudio/examples/input_monitor/src/input_monitor.cpp
+++ b/media/libaaudio/examples/input_monitor/src/input_monitor.cpp
@@ -40,7 +40,6 @@
     int actualSamplesPerFrame;
     int actualSampleRate;
     aaudio_format_t       actualDataFormat;
-    aaudio_sharing_mode_t actualSharingMode;
 
     AAudioStream *aaudioStream = nullptr;
     aaudio_stream_state_t state;
@@ -54,7 +53,6 @@
     int64_t previousFramePosition = -1;
     int16_t *data = nullptr;
     float peakLevel = 0.0;
-    int loopCounter = 0;
     int32_t deviceId;
 
     // Make printf print immediately so that debug info is not stuck
diff --git a/media/libaaudio/examples/loopback/Android.bp b/media/libaaudio/examples/loopback/Android.bp
new file mode 100644
index 0000000..2b624a8
--- /dev/null
+++ b/media/libaaudio/examples/loopback/Android.bp
@@ -0,0 +1,7 @@
+cc_test {
+    name: "aaudio_loopback",
+    gtest: false,
+    srcs: ["src/loopback.cpp"],
+    shared_libs: ["libaaudio"],
+    header_libs: ["libaaudio_example_utils"],
+}
diff --git a/media/libaaudio/examples/loopback/Android.mk b/media/libaaudio/examples/loopback/Android.mk
deleted file mode 100644
index 5053e7d..0000000
--- a/media/libaaudio/examples/loopback/Android.mk
+++ /dev/null
@@ -1 +0,0 @@
-include $(call all-subdir-makefiles)
diff --git a/media/libaaudio/examples/loopback/jni/Android.mk b/media/libaaudio/examples/loopback/jni/Android.mk
index d78f286..1fe3def 100644
--- a/media/libaaudio/examples/loopback/jni/Android.mk
+++ b/media/libaaudio/examples/loopback/jni/Android.mk
@@ -9,6 +9,7 @@
 
 # NDK recommends using this kind of relative path instead of an absolute path.
 LOCAL_SRC_FILES:= ../src/loopback.cpp
+LOCAL_CFLAGS := -Wall -Werror
 LOCAL_SHARED_LIBRARIES := libaaudio
 LOCAL_MODULE := aaudio_loopback
 include $(BUILD_EXECUTABLE)
diff --git a/media/libaaudio/examples/loopback/src/LoopbackAnalyzer.h b/media/libaaudio/examples/loopback/src/LoopbackAnalyzer.h
index 21cf341..276b45f 100644
--- a/media/libaaudio/examples/loopback/src/LoopbackAnalyzer.h
+++ b/media/libaaudio/examples/loopback/src/LoopbackAnalyzer.h
@@ -432,9 +432,7 @@
             int needleSize = (int) (sizeof(s_Impulse) / sizeof(float));
             float *haystack = audioRecorder.getData();
             int haystackSize = audioRecorder.size();
-            int result = measureLatencyFromEchos(haystack, haystackSize,
-                                                 needle, needleSize,
-                                                 &latencyReport);
+            measureLatencyFromEchos(haystack, haystackSize, needle, needleSize, &latencyReport);
             if (latencyReport.confidence < 0.01) {
                 printf("   ERROR - confidence too low = %f\n", latencyReport.confidence);
             } else {
@@ -580,7 +578,6 @@
 
     int           mDownCounter = 500;
     int           mLoopCounter = 0;
-    int           mLoopStart = 1000;
     float         mPulseThreshold = 0.02f;
     float         mSilenceThreshold = 0.002f;
     float         mMeasuredLoopGain = 0.0f;
@@ -651,7 +648,6 @@
     void process(float *inputData, int inputChannelCount,
                  float *outputData, int outputChannelCount,
                  int numFrames) override {
-        float sample;
         float peak = measurePeakAmplitude(inputData, inputChannelCount, numFrames);
         if (peak > mPeakAmplitude) {
             mPeakAmplitude = peak;
@@ -779,8 +775,6 @@
     int32_t mFrameCounter = 0;
     float   mOutputAmplitude = 0.75;
 
-    int32_t mZeroCrossings = 0;
-
     PseudoRandom  mWhiteNoise;
     float   mNoiseAmplitude = 0.00; // Used to experiment with warbling caused by DRC.
 
diff --git a/media/libaaudio/examples/loopback/src/loopback.cpp b/media/libaaudio/examples/loopback/src/loopback.cpp
index be833e6..ac6024e 100644
--- a/media/libaaudio/examples/loopback/src/loopback.cpp
+++ b/media/libaaudio/examples/loopback/src/loopback.cpp
@@ -159,21 +159,27 @@
 }
 
 static void usage() {
-    printf("loopback: -n{numBursts} -p{outPerf} -P{inPerf} -t{test} -g{gain} -f{freq}\n");
-    printf("          -c{inputChannels}\n");
-    printf("          -f{freq}  sine frequency\n");
-    printf("          -g{gain}  recirculating loopback gain\n");
-    printf("          -m enable MMAP mode\n");
-    printf("          -n{numBursts} buffer size, for example 2 for double buffered\n");
-    printf("          -p{outPerf}  set output AAUDIO_PERFORMANCE_MODE*\n");
-    printf("          -P{inPerf}   set input AAUDIO_PERFORMANCE_MODE*\n");
+    printf("Usage: aaudio_loopback [OPTION]...\n\n");
+    printf("          -c{channels}      number of output channels\n");
+    printf("          -C{channels}      number of input channels\n");
+    printf("          -g{gain}          recirculating loopback gain\n");
+    printf("          -m{0|1|2|3}       set MMAP policy\n");
+    printf("              0 = _UNSPECIFIED\n");
+    printf("              1 = _NEVER\n");
+    printf("              2 = _AUTO, also if -m is used with no number\n");
+    printf("              3 = _ALWAYS\n");
+    printf("          -n{numBursts}     buffer size, for example 2 for double buffered\n");
+    printf("          -p{outPerf}       set output AAUDIO_PERFORMANCE_MODE*\n");
+    printf("          -P{inPerf}        set input AAUDIO_PERFORMANCE_MODE*\n");
     printf("              n for _NONE\n");
     printf("              l for _LATENCY\n");
-    printf("              p for _POWER_SAVING;\n");
-    printf("          -t{test}   select test mode\n");
+    printf("              p for _POWER_SAVING\n");
+    printf("          -t{test}          select test mode\n");
     printf("              m for sine magnitude\n");
-    printf("              e for echo latency (default)\n");
-    printf("For example:  loopback -b2 -pl -Pn\n");
+    printf("              e for echo latency (default)\n\n");
+    printf("          -x                use EXCLUSIVE mode for output\n");
+    printf("          -X                use EXCLUSIVE mode for input\n");
+    printf("Example:  aaudio_loopback -n2 -pl -Pl -x\n");
 }
 
 static aaudio_performance_mode_t parsePerformanceMode(char c) {
@@ -257,24 +263,17 @@
     aaudio_result_t      result = AAUDIO_OK;
     aaudio_sharing_mode_t requestedInputSharingMode     = AAUDIO_SHARING_MODE_SHARED;
     int                   requestedInputChannelCount = NUM_INPUT_CHANNELS;
-    const int             requestedOutputChannelCount = AAUDIO_UNSPECIFIED;
-    int                   actualSampleRate = 0;
     const aaudio_format_t requestedInputFormat = AAUDIO_FORMAT_PCM_I16;
     const aaudio_format_t requestedOutputFormat = AAUDIO_FORMAT_PCM_FLOAT;
     aaudio_format_t       actualInputFormat;
     aaudio_format_t       actualOutputFormat;
-    aaudio_performance_mode_t outputPerformanceLevel = AAUDIO_PERFORMANCE_MODE_LOW_LATENCY;
     aaudio_performance_mode_t inputPerformanceLevel = AAUDIO_PERFORMANCE_MODE_LOW_LATENCY;
 
     int testMode = TEST_ECHO_LATENCY;
     double gain = 1.0;
 
-    aaudio_stream_state_t state = AAUDIO_STREAM_STATE_UNINITIALIZED;
     int32_t framesPerBurst = 0;
     float *outputData = NULL;
-    double deviation;
-    double latency;
-    int32_t burstsPerBuffer = 1; // single buffered
 
     // Make printf print immediately so that debug info is not stuck
     // in a buffer if we hang or crash.
diff --git a/media/libaaudio/examples/utils/AAudioArgsParser.h b/media/libaaudio/examples/utils/AAudioArgsParser.h
index ada37e2..142b295 100644
--- a/media/libaaudio/examples/utils/AAudioArgsParser.h
+++ b/media/libaaudio/examples/utils/AAudioArgsParser.h
@@ -17,6 +17,8 @@
 #ifndef AAUDIO_EXAMPLE_ARGS_PARSER_H
 #define AAUDIO_EXAMPLE_ARGS_PARSER_H
 
+#define MAX_CHANNELS                     8
+
 #include <cctype>
 #include <unistd.h>
 #include <stdio.h>
@@ -39,6 +41,10 @@
     }
 
     void setChannelCount(int32_t channelCount) {
+        if (channelCount > MAX_CHANNELS) {
+            printf("Sorry, MAX of %d channels!\n", MAX_CHANNELS);
+            channelCount = MAX_CHANNELS;
+        }
         mChannelCount = channelCount;
     }
 
diff --git a/media/libaaudio/examples/utils/AAudioExampleUtils.h b/media/libaaudio/examples/utils/AAudioExampleUtils.h
index d817664..2671c3a 100644
--- a/media/libaaudio/examples/utils/AAudioExampleUtils.h
+++ b/media/libaaudio/examples/utils/AAudioExampleUtils.h
@@ -80,13 +80,15 @@
     return text;
 }
 
-static void convertNanosecondsToTimespec(int64_t nanoseconds, struct timespec *time) {
+template <class T = int64_t>
+void convertNanosecondsToTimespec(int64_t nanoseconds, struct timespec *time) {
     time->tv_sec = nanoseconds / NANOS_PER_SECOND;
     // Calculate the fractional nanoseconds. Avoids expensive % operation.
     time->tv_nsec = nanoseconds - (time->tv_sec * NANOS_PER_SECOND);
 }
 
-static int64_t getNanoseconds(clockid_t clockId = CLOCK_MONOTONIC) {
+template <class T = clockid_t>
+int64_t getNanoseconds(clockid_t clockId = CLOCK_MONOTONIC) {
     struct timespec time;
     int result = clock_gettime(clockId, &time);
     if (result < 0) {
@@ -95,7 +97,8 @@
     return (time.tv_sec * NANOS_PER_SECOND) + time.tv_nsec;
 }
 
-static void displayPeakLevel(float peakLevel) {
+template <class T = float>
+void displayPeakLevel(float peakLevel) {
     printf("%5.3f ", peakLevel);
     const int maxStars = 50; // arbitrary, fits on one line
     int numStars = (int) (peakLevel * maxStars);
@@ -113,7 +116,8 @@
  * @param sampleRate
  * @return latency in milliseconds
  */
-static double calculateLatencyMillis(int64_t position1, int64_t nanoseconds1,
+template <class T = int64_t>
+double calculateLatencyMillis(int64_t position1, int64_t nanoseconds1,
                               int64_t position2, int64_t nanoseconds2,
                               int64_t sampleRate) {
     int64_t deltaFrames = position2 - position1;
@@ -127,7 +131,8 @@
 
 // ================================================================================
 // These Futex calls are common online examples.
-static android::status_t sys_futex(void *addr1, int op, int val1,
+template <class T = int>
+android::status_t sys_futex(void *addr1, int op, int val1,
                       struct timespec *timeout, void *addr2, int val3) {
     android::status_t result = (android::status_t) syscall(SYS_futex, addr1,
                                                            op, val1, timeout,
@@ -135,12 +140,14 @@
     return (result == 0) ? 0 : -errno;
 }
 
-static android::status_t futex_wake(void *addr, int numWake) {
+template <class T = int>
+android::status_t futex_wake(void *addr, int numWake) {
     // Use _PRIVATE because we are just using the futex in one process.
     return sys_futex(addr, FUTEX_WAKE_PRIVATE, numWake, NULL, NULL, 0);
 }
 
-static android::status_t futex_wait(void *addr, int current, struct timespec *time) {
+template <class T = int>
+android::status_t futex_wait(void *addr, int current, struct timespec *time) {
     // Use _PRIVATE because we are just using the futex in one process.
     return sys_futex(addr, FUTEX_WAIT_PRIVATE, current, time, NULL, 0);
 }
diff --git a/media/libaaudio/examples/utils/AAudioSimplePlayer.h b/media/libaaudio/examples/utils/AAudioSimplePlayer.h
index 606c4ba..1061e42 100644
--- a/media/libaaudio/examples/utils/AAudioSimplePlayer.h
+++ b/media/libaaudio/examples/utils/AAudioSimplePlayer.h
@@ -19,11 +19,10 @@
 #ifndef AAUDIO_SIMPLE_PLAYER_H
 #define AAUDIO_SIMPLE_PLAYER_H
 
-#include <unistd.h>
 #include <sched.h>
+#include <unistd.h>
 
 #include <aaudio/AAudio.h>
-#include <atomic>
 #include "AAudioArgsParser.h"
 #include "SineGenerator.h"
 
@@ -36,7 +35,7 @@
 // How long to sleep in a callback to cause an intentional glitch. For testing.
 #define FORCED_UNDERRUN_SLEEP_MICROS     (10 * 1000)
 
-#define MAX_TIMESTAMPS   16
+#define MAX_TIMESTAMPS                   16
 
 typedef struct Timestamp {
     int64_t position;
@@ -70,13 +69,6 @@
     }
 
     // TODO Extract a common base class for record and playback.
-    /**
-     * Also known as "sample rate"
-     * Only call this after open() has been called.
-     */
-    int32_t getFramesPerSecond() const {
-        return getSampleRate(); // alias
-    }
 
     /**
      * Only call this after open() has been called.
@@ -172,6 +164,7 @@
         result = AAudioStreamBuilder_openStream(builder, &mStream);
 
         AAudioStreamBuilder_delete(builder);
+
         return result;
     }
 
@@ -212,13 +205,35 @@
         aaudio_result_t result = AAudioStream_requestStop(mStream);
         if (result != AAUDIO_OK) {
             printf("ERROR - AAudioStream_requestStop() returned %d %s\n",
-                    result, AAudio_convertResultToText(result));
+                   result, AAudio_convertResultToText(result));
         }
         int32_t xRunCount = AAudioStream_getXRunCount(mStream);
         printf("AAudioStream_getXRunCount %d\n", xRunCount);
         return result;
     }
 
+    // Pause the stream. AAudio will stop calling your callback function.
+    aaudio_result_t pause() {
+        aaudio_result_t result = AAudioStream_requestPause(mStream);
+        if (result != AAUDIO_OK) {
+            printf("ERROR - AAudioStream_requestPause() returned %d %s\n",
+                   result, AAudio_convertResultToText(result));
+        }
+        int32_t xRunCount = AAudioStream_getXRunCount(mStream);
+        printf("AAudioStream_getXRunCount %d\n", xRunCount);
+        return result;
+    }
+
+    // Flush the stream. AAudio will stop calling your callback function.
+    aaudio_result_t flush() {
+        aaudio_result_t result = AAudioStream_requestFlush(mStream);
+        if (result != AAUDIO_OK) {
+            printf("ERROR - AAudioStream_requestFlush() returned %d %s\n",
+                   result, AAudio_convertResultToText(result));
+        }
+        return result;
+    }
+
     AAudioStream *getStream() const {
         return mStream;
     }
@@ -232,23 +247,49 @@
 
 typedef struct SineThreadedData_s {
 
-    SineGenerator  sineOsc1;
-    SineGenerator  sineOsc2;
-    Timestamp      timestamps[MAX_TIMESTAMPS];
-    int64_t        framesTotal = 0;
-    int64_t        nextFrameToGlitch = FORCED_UNDERRUN_PERIOD_FRAMES;
-    int32_t        minNumFrames = INT32_MAX;
-    int32_t        maxNumFrames = 0;
-    int32_t        timestampCount = 0; // in timestamps
+    SineGenerator      sineOscillators[MAX_CHANNELS];
+    Timestamp          timestamps[MAX_TIMESTAMPS];
+    int64_t            framesTotal = 0;
+    int64_t            nextFrameToGlitch = FORCED_UNDERRUN_PERIOD_FRAMES;
+    int32_t            minNumFrames = INT32_MAX;
+    int32_t            maxNumFrames = 0;
+    int32_t            timestampCount = 0; // in timestamps
+    int32_t            sampleRate = 48000;
+    int32_t            prefixToneFrames = 0;
+    bool               sweepSetup = false;
 
-    int            scheduler = 0;
-    bool           schedulerChecked = false;
-    bool           forceUnderruns = false;
+    int                scheduler = 0;
+    bool               schedulerChecked = false;
+    bool               forceUnderruns = false;
 
     AAudioSimplePlayer simplePlayer;
     int32_t            callbackCount = 0;
     WakeUp             waker{AAUDIO_OK};
 
+    /**
+     * Set sampleRate first.
+     */
+    void setupSineBlip() {
+        for (int i = 0; i < MAX_CHANNELS; ++i) {
+            double centerFrequency = 880.0 * (i + 2);
+            sineOscillators[i].setup(centerFrequency, sampleRate);
+            sineOscillators[i].setSweep(centerFrequency, centerFrequency, 0.0);
+        }
+    }
+
+    void setupSineSweeps() {
+        for (int i = 0; i < MAX_CHANNELS; ++i) {
+            double centerFrequency = 220.0 * (i + 2);
+            sineOscillators[i].setup(centerFrequency, sampleRate);
+            double minFrequency = centerFrequency * 2.0 / 3.0;
+            // Change range slightly so they will go out of phase.
+            double maxFrequency = centerFrequency * 3.0 / 2.0;
+            double sweepSeconds = 5.0 + i;
+            sineOscillators[i].setSweep(minFrequency, maxFrequency, sweepSeconds);
+        }
+        sweepSetup = true;
+    }
+
 } SineThreadedData_t;
 
 // Callback function that fills the audio output buffer.
@@ -265,9 +306,11 @@
         return AAUDIO_CALLBACK_RESULT_STOP;
     }
     SineThreadedData_t *sineData = (SineThreadedData_t *) userData;
-    sineData->callbackCount++;
 
-    sineData->framesTotal += numFrames;
+    // Play an initial high tone so we can tell whether the beginning was truncated.
+    if (!sineData->sweepSetup && sineData->framesTotal >= sineData->prefixToneFrames) {
+        sineData->setupSineSweeps();
+    }
 
     if (sineData->forceUnderruns) {
         if (sineData->framesTotal > sineData->nextFrameToGlitch) {
@@ -301,33 +344,32 @@
     }
 
     int32_t samplesPerFrame = AAudioStream_getChannelCount(stream);
-    // This code only plays on the first one or two channels.
-    // TODO Support arbitrary number of channels.
+
+
+    int numActiveOscilators = (samplesPerFrame > MAX_CHANNELS) ? MAX_CHANNELS : samplesPerFrame;
     switch (AAudioStream_getFormat(stream)) {
         case AAUDIO_FORMAT_PCM_I16: {
             int16_t *audioBuffer = (int16_t *) audioData;
-            // Render sine waves as shorts to first channel.
-            sineData->sineOsc1.render(&audioBuffer[0], samplesPerFrame, numFrames);
-            // Render sine waves to second channel if there is one.
-            if (samplesPerFrame > 1) {
-                sineData->sineOsc2.render(&audioBuffer[1], samplesPerFrame, numFrames);
+            for (int i = 0; i < numActiveOscilators; ++i) {
+                sineData->sineOscillators[i].render(&audioBuffer[i], samplesPerFrame,
+                                                    numFrames);
             }
         }
-        break;
+            break;
         case AAUDIO_FORMAT_PCM_FLOAT: {
             float *audioBuffer = (float *) audioData;
-            // Render sine waves as floats to first channel.
-            sineData->sineOsc1.render(&audioBuffer[0], samplesPerFrame, numFrames);
-            // Render sine waves to second channel if there is one.
-            if (samplesPerFrame > 1) {
-                sineData->sineOsc2.render(&audioBuffer[1], samplesPerFrame, numFrames);
+            for (int i = 0; i < numActiveOscilators; ++i) {
+                sineData->sineOscillators[i].render(&audioBuffer[i], samplesPerFrame,
+                                                    numFrames);
             }
         }
-        break;
+            break;
         default:
             return AAUDIO_CALLBACK_RESULT_STOP;
     }
 
+    sineData->callbackCount++;
+    sineData->framesTotal += numFrames;
     return AAUDIO_CALLBACK_RESULT_CONTINUE;
 }
 
diff --git a/media/libaaudio/examples/utils/SineGenerator.h b/media/libaaudio/examples/utils/SineGenerator.h
index a755582..9e6d46d 100644
--- a/media/libaaudio/examples/utils/SineGenerator.h
+++ b/media/libaaudio/examples/utils/SineGenerator.h
@@ -31,20 +31,20 @@
     }
 
     void setSweep(double frequencyLow, double frequencyHigh, double seconds) {
-        mPhaseIncrementLow = frequencyLow * M_PI * 2 / mFrameRate;
-        mPhaseIncrementHigh = frequencyHigh * M_PI * 2 / mFrameRate;
-
-        double numFrames = seconds * mFrameRate;
-        mUpScaler = pow((frequencyHigh / frequencyLow), (1.0 / numFrames));
-        mDownScaler = 1.0 / mUpScaler;
-        mGoingUp = true;
-        mSweeping = true;
+        mSweeping = seconds > 0.0;
+        if (mSweeping) {
+            mPhaseIncrementLow = frequencyLow * M_PI * 2 / mFrameRate;
+            mPhaseIncrementHigh = frequencyHigh * M_PI * 2 / mFrameRate;
+            double numFrames = seconds * mFrameRate;
+            mUpScaler = pow((frequencyHigh / frequencyLow), (1.0 / numFrames));
+            mDownScaler = 1.0 / mUpScaler;
+        }
     }
 
     void render(int16_t *buffer, int32_t channelStride, int32_t numFrames) {
         int sampleIndex = 0;
         for (int i = 0; i < numFrames; i++) {
-            buffer[sampleIndex] = (int16_t) (32767 * sin(mPhase) * mAmplitude);
+            buffer[sampleIndex] = (int16_t) (INT16_MAX * sin(mPhase) * mAmplitude);
             sampleIndex += channelStride;
             advancePhase();
         }
@@ -61,6 +61,7 @@
     void setAmplitude(double amplitude) {
         mAmplitude = amplitude;
     }
+
     double getAmplitude() const {
         return mAmplitude;
     }
diff --git a/media/libaaudio/examples/write_sine/Android.bp b/media/libaaudio/examples/write_sine/Android.bp
new file mode 100644
index 0000000..f162e85
--- /dev/null
+++ b/media/libaaudio/examples/write_sine/Android.bp
@@ -0,0 +1,13 @@
+cc_test {
+    name: "write_sine",
+    srcs: ["src/write_sine.cpp"],
+    shared_libs: ["libaaudio"],
+    header_libs: ["libaaudio_example_utils"],
+}
+
+cc_test {
+    name: "write_sine_callback",
+    srcs: ["src/write_sine_callback.cpp"],
+    shared_libs: ["libaaudio"],
+    header_libs: ["libaaudio_example_utils"],
+}
diff --git a/media/libaaudio/examples/write_sine/Android.mk b/media/libaaudio/examples/write_sine/Android.mk
deleted file mode 100644
index 5053e7d..0000000
--- a/media/libaaudio/examples/write_sine/Android.mk
+++ /dev/null
@@ -1 +0,0 @@
-include $(call all-subdir-makefiles)
diff --git a/media/libaaudio/examples/write_sine/jni/Android.mk b/media/libaaudio/examples/write_sine/jni/Android.mk
index d630e76..1a1bd43 100644
--- a/media/libaaudio/examples/write_sine/jni/Android.mk
+++ b/media/libaaudio/examples/write_sine/jni/Android.mk
@@ -10,6 +10,7 @@
 
 # NDK recommends using this kind of relative path instead of an absolute path.
 LOCAL_SRC_FILES:= ../src/write_sine.cpp
+LOCAL_CFLAGS := -Wall -Werror
 LOCAL_SHARED_LIBRARIES := libaaudio
 LOCAL_MODULE := write_sine
 include $(BUILD_EXECUTABLE)
@@ -22,6 +23,7 @@
     frameworks/av/media/libaaudio/examples/utils
 
 LOCAL_SRC_FILES:= ../src/write_sine_callback.cpp
+LOCAL_CFLAGS := -Wall -Werror
 LOCAL_SHARED_LIBRARIES := libaaudio
 LOCAL_MODULE := write_sine_callback
 include $(BUILD_EXECUTABLE)
diff --git a/media/libaaudio/examples/write_sine/src/write_sine.cpp b/media/libaaudio/examples/write_sine/src/write_sine.cpp
index 677fb6c..38e1e4c 100644
--- a/media/libaaudio/examples/write_sine/src/write_sine.cpp
+++ b/media/libaaudio/examples/write_sine/src/write_sine.cpp
@@ -44,10 +44,10 @@
     AAudioStream *aaudioStream = nullptr;
     int32_t  framesPerBurst = 0;
     int32_t  framesPerWrite = 0;
-    int32_t  bufferCapacity = 0;
     int32_t  framesToPlay = 0;
     int32_t  framesLeft = 0;
     int32_t  xRunCount = 0;
+    int      numActiveOscilators = 0;
     float   *floatData = nullptr;
     int16_t *shortData = nullptr;
 
@@ -77,8 +77,8 @@
     actualSampleRate = AAudioStream_getSampleRate(aaudioStream);
     actualDataFormat = AAudioStream_getFormat(aaudioStream);
 
-    myData.sineOsc1.setup(440.0, actualSampleRate);
-    myData.sineOsc2.setup(660.0, actualSampleRate);
+    myData.sampleRate = actualSampleRate;
+    myData.setupSineSweeps();
 
     // Some DMA might use very short bursts of 16 frames. We don't need to write such small
     // buffers. But it helps to use a multiple of the burst size for predictable scheduling.
@@ -117,19 +117,18 @@
     // Play for a while.
     framesToPlay = actualSampleRate * argParser.getDurationSeconds();
     framesLeft = framesToPlay;
+    numActiveOscilators = (actualChannelCount > MAX_CHANNELS) ? MAX_CHANNELS : actualChannelCount;
     while (framesLeft > 0) {
-
+        // Render as FLOAT or PCM
         if (actualDataFormat == AAUDIO_FORMAT_PCM_FLOAT) {
-            // Render sine waves to left and right channels.
-            myData.sineOsc1.render(&floatData[0], actualChannelCount, framesPerWrite);
-            if (actualChannelCount > 1) {
-                myData.sineOsc2.render(&floatData[1], actualChannelCount, framesPerWrite);
+            for (int i = 0; i < numActiveOscilators; ++i) {
+                myData.sineOscillators[i].render(&floatData[i], actualChannelCount,
+                                                  framesPerWrite);
             }
         } else if (actualDataFormat == AAUDIO_FORMAT_PCM_I16) {
-            // Render sine waves to left and right channels.
-            myData.sineOsc1.render(&shortData[0], actualChannelCount, framesPerWrite);
-            if (actualChannelCount > 1) {
-                myData.sineOsc2.render(&shortData[1], actualChannelCount, framesPerWrite);
+            for (int i = 0; i < numActiveOscilators; ++i) {
+                myData.sineOscillators[i].render(&shortData[i], actualChannelCount,
+                                                  framesPerWrite);
             }
         }
 
diff --git a/media/libaaudio/examples/write_sine/src/write_sine_callback.cpp b/media/libaaudio/examples/write_sine/src/write_sine_callback.cpp
index 4f9cde6..c2dd7af 100644
--- a/media/libaaudio/examples/write_sine/src/write_sine_callback.cpp
+++ b/media/libaaudio/examples/write_sine/src/write_sine_callback.cpp
@@ -28,7 +28,6 @@
 #include <aaudio/AAudio.h>
 #include "AAudioExampleUtils.h"
 #include "AAudioSimplePlayer.h"
-#include "../../utils/AAudioSimplePlayer.h"
 
 /**
  * Open stream, play some sine waves, then close the stream.
@@ -36,37 +35,39 @@
  * @param argParser
  * @return AAUDIO_OK or negative error code
  */
-static aaudio_result_t testOpenPlayClose(AAudioArgsParser &argParser)
+static aaudio_result_t testOpenPlayClose(AAudioArgsParser &argParser,
+                                         int32_t loopCount,
+                                         int32_t prefixToneMsec)
 {
     SineThreadedData_t myData;
     AAudioSimplePlayer &player = myData.simplePlayer;
     aaudio_result_t    result = AAUDIO_OK;
     bool               disconnected = false;
+    bool               bailOut = false;
     int64_t            startedAtNanos;
 
     printf("----------------------- run complete test --------------------------\n");
     myData.schedulerChecked = false;
     myData.callbackCount = 0;
+    // TODO add a command line option for the forceUnderruns
     myData.forceUnderruns = false; // set true to test AAudioStream_getXRunCount()
 
     result = player.open(argParser,
                          SimplePlayerDataCallbackProc, SimplePlayerErrorCallbackProc, &myData);
     if (result != AAUDIO_OK) {
-        fprintf(stderr, "ERROR -  player.open() returned %d\n", result);
+        fprintf(stderr, "ERROR -  player.open() returned %s\n",
+                AAudio_convertResultToText(result));
         goto error;
     }
 
     argParser.compareWithStream(player.getStream());
 
-    // Setup sine wave generators.
-    {
-        int32_t actualSampleRate = player.getSampleRate();
-        myData.sineOsc1.setup(440.0, actualSampleRate);
-        myData.sineOsc1.setSweep(300.0, 600.0, 5.0);
-        myData.sineOsc1.setAmplitude(0.2);
-        myData.sineOsc2.setup(660.0, actualSampleRate);
-        myData.sineOsc2.setSweep(350.0, 900.0, 7.0);
-        myData.sineOsc2.setAmplitude(0.2);
+    myData.sampleRate = player.getSampleRate();
+    myData.prefixToneFrames = prefixToneMsec * myData.sampleRate / 1000;
+    if (myData.prefixToneFrames > 0) {
+        myData.setupSineBlip();
+    } else {
+        myData.setupSineSweeps();
     }
 
 #if 0
@@ -78,42 +79,93 @@
     }
 #endif
 
-    result = player.start();
-    if (result != AAUDIO_OK) {
-        fprintf(stderr, "ERROR - player.start() returned %d\n", result);
-        goto error;
-    }
+    for (int loopIndex = 0; loopIndex < loopCount; loopIndex++) {
+        // Only play data on every other loop so we can hear if there is stale data.
+        double amplitude;
+        int32_t durationSeconds;
+        if ((loopIndex & 1) == 0) {
+            printf("--------------- SINE ------\n");
+            amplitude = 0.2;
+            durationSeconds = argParser.getDurationSeconds();
+        } else {
+            printf("--------------- QUIET -----\n");
+            amplitude = 0.0;
+            durationSeconds = 2; // just wait briefly when quiet
+        }
+        for (int i = 0; i < MAX_CHANNELS; ++i) {
+            myData.sineOscillators[i].setAmplitude(amplitude);
+        }
 
-    // Play a sine wave in the background.
-    printf("Sleep for %d seconds while audio plays in a callback thread.\n",
-           argParser.getDurationSeconds());
-    startedAtNanos = getNanoseconds(CLOCK_MONOTONIC);
-    for (int second = 0; second < argParser.getDurationSeconds(); second++)
-    {
-        // Sleep a while. Wake up early if there is an error, for example a DISCONNECT.
-        long ret = myData.waker.wait(AAUDIO_OK, NANOS_PER_SECOND);
-        int64_t millis = (getNanoseconds(CLOCK_MONOTONIC) - startedAtNanos) / NANOS_PER_MILLISECOND;
-        result = myData.waker.get();
-        printf("wait() returns %ld, aaudio_result = %d, at %6d millis"
-               ", second = %d, framesWritten = %8d, underruns = %d\n",
-               ret, result, (int) millis,
-               second,
-               (int) AAudioStream_getFramesWritten(player.getStream()),
-               (int) AAudioStream_getXRunCount(player.getStream()));
+        result = player.start();
         if (result != AAUDIO_OK) {
-            if (result == AAUDIO_ERROR_DISCONNECTED) {
-                disconnected = true;
+            fprintf(stderr, "ERROR - player.start() returned %d\n", result);
+            goto error;
+        }
+
+        // Play a sine wave in the background.
+        printf("Sleep for %d seconds while audio plays in a callback thread. %d of %d\n",
+               argParser.getDurationSeconds(), (loopIndex + 1), loopCount);
+        startedAtNanos = getNanoseconds(CLOCK_MONOTONIC);
+        for (int second = 0; second < durationSeconds; second++) {
+            // Sleep a while. Wake up early if there is an error, for example a DISCONNECT.
+            long ret = myData.waker.wait(AAUDIO_OK, NANOS_PER_SECOND);
+            int64_t millis =
+                    (getNanoseconds(CLOCK_MONOTONIC) - startedAtNanos) / NANOS_PER_MILLISECOND;
+            result = myData.waker.get();
+            printf("wait() returns %ld, aaudio_result = %d, at %6d millis"
+                           ", second = %3d, framesWritten = %8d, underruns = %d\n",
+                   ret, result, (int) millis,
+                   second,
+                   (int) AAudioStream_getFramesWritten(player.getStream()),
+                   (int) AAudioStream_getXRunCount(player.getStream()));
+            if (result != AAUDIO_OK) {
+                disconnected = (result == AAUDIO_ERROR_DISCONNECTED);
+                bailOut = true;
+                break;
             }
+        }
+        printf("AAudio result = %d = %s\n", result, AAudio_convertResultToText(result));
+
+        // Alternate between using stop or pause for each sine/quiet pair.
+        // Repeat this pattern: {sine-stop-quiet-stop-sine-pause-quiet-pause}
+        if ((loopIndex & 2) == 0) {
+            printf("STOP, callback # = %d\n", myData.callbackCount);
+            result = player.stop();
+        } else {
+            printf("PAUSE/FLUSH, callback # = %d\n", myData.callbackCount);
+            result = player.pause();
+            if (result != AAUDIO_OK) {
+                goto error;
+            }
+            result = player.flush();
+        }
+        if (result != AAUDIO_OK) {
+            goto error;
+        }
+
+        if (bailOut) {
             break;
         }
-    }
-    printf("AAudio result = %d = %s\n", result, AAudio_convertResultToText(result));
 
-    printf("call stop() callback # = %d\n", myData.callbackCount);
-    result = player.stop();
-    if (result != AAUDIO_OK) {
-        goto error;
+        {
+            aaudio_stream_state_t state = AAudioStream_getState(player.getStream());
+            aaudio_stream_state_t finalState = AAUDIO_STREAM_STATE_UNINITIALIZED;
+            int64_t timeoutNanos = 2000 * NANOS_PER_MILLISECOND;
+            result = AAudioStream_waitForStateChange(player.getStream(), state,
+                                                     &finalState, timeoutNanos);
+            printf("waitForStateChange returns %s, state = %s\n",
+                   AAudio_convertResultToText(result),
+                   AAudio_convertStreamStateToText(finalState));
+            int64_t written = AAudioStream_getFramesWritten(player.getStream());
+            int64_t read = AAudioStream_getFramesRead(player.getStream());
+            printf("   framesWritten = %lld, framesRead = %lld, diff = %d\n",
+                   (long long) written,
+                   (long long) read,
+                   (int) (written - read));
+        }
+
     }
+
     printf("call close()\n");
     result = player.close();
     if (result != AAUDIO_OK) {
@@ -147,23 +199,54 @@
     return disconnected ? AAUDIO_ERROR_DISCONNECTED : result;
 }
 
+static void usage() {
+    AAudioArgsParser::usage();
+    printf("      -l{count} loopCount start/stop, every other one is silent\n");
+    printf("      -t{msec} play a high pitched tone at the beginning\n");
+}
+
 int main(int argc, const char **argv)
 {
     AAudioArgsParser   argParser;
     aaudio_result_t    result;
+    int32_t            loopCount = 1;
+    int32_t            prefixToneMsec = 0;
 
     // Make printf print immediately so that debug info is not stuck
     // in a buffer if we hang or crash.
     setvbuf(stdout, nullptr, _IONBF, (size_t) 0);
 
-    printf("%s - Play a sine sweep using an AAudio callback V0.1.2\n", argv[0]);
+    printf("%s - Play a sine sweep using an AAudio callback V0.1.3\n", argv[0]);
 
-    if (argParser.parseArgs(argc, argv)) {
-        return EXIT_FAILURE;
+    for (int i = 1; i < argc; i++) {
+        const char *arg = argv[i];
+        if (argParser.parseArg(arg)) {
+            // Handle options that are not handled by the ArgParser
+            if (arg[0] == '-') {
+                char option = arg[1];
+                switch (option) {
+                    case 'l':
+                        loopCount = atoi(&arg[2]);
+                        break;
+                    case 't':
+                        prefixToneMsec = atoi(&arg[2]);
+                        break;
+                    default:
+                        usage();
+                        exit(EXIT_FAILURE);
+                        break;
+                }
+            } else {
+                usage();
+                exit(EXIT_FAILURE);
+                break;
+            }
+        }
     }
 
     // Keep looping until we can complete the test without disconnecting.
-    while((result = testOpenPlayClose(argParser)) == AAUDIO_ERROR_DISCONNECTED);
+    while((result = testOpenPlayClose(argParser, loopCount, prefixToneMsec))
+            == AAUDIO_ERROR_DISCONNECTED);
 
     return (result) ? EXIT_FAILURE : EXIT_SUCCESS;
 }
diff --git a/media/libaaudio/src/Android.bp b/media/libaaudio/src/Android.bp
new file mode 100644
index 0000000..788833b
--- /dev/null
+++ b/media/libaaudio/src/Android.bp
@@ -0,0 +1,66 @@
+cc_library {
+    name: "libaaudio",
+
+    local_include_dirs: [
+        "binding",
+        "client",
+        "core",
+        "fifo",
+        "legacy",
+        "utility",
+    ],
+    export_include_dirs: ["."],
+    header_libs: ["libaaudio_headers"],
+    export_header_lib_headers: ["libaaudio_headers"],
+
+    srcs: [
+        "core/AudioStream.cpp",
+        "core/AudioStreamBuilder.cpp",
+        "core/AAudioAudio.cpp",
+        "core/AAudioStreamParameters.cpp",
+        "legacy/AudioStreamLegacy.cpp",
+        "legacy/AudioStreamRecord.cpp",
+        "legacy/AudioStreamTrack.cpp",
+        "utility/AAudioUtilities.cpp",
+        "utility/FixedBlockAdapter.cpp",
+        "utility/FixedBlockReader.cpp",
+        "utility/FixedBlockWriter.cpp",
+        "utility/LinearRamp.cpp",
+        "fifo/FifoBuffer.cpp",
+        "fifo/FifoControllerBase.cpp",
+        "client/AudioEndpoint.cpp",
+        "client/AudioStreamInternal.cpp",
+        "client/AudioStreamInternalCapture.cpp",
+        "client/AudioStreamInternalPlay.cpp",
+        "client/IsochronousClockModel.cpp",
+        "binding/AudioEndpointParcelable.cpp",
+        "binding/AAudioBinderClient.cpp",
+        "binding/AAudioStreamRequest.cpp",
+        "binding/AAudioStreamConfiguration.cpp",
+        "binding/IAAudioClient.cpp",
+        "binding/IAAudioService.cpp",
+        "binding/RingBufferParcelable.cpp",
+        "binding/SharedMemoryParcelable.cpp",
+        "binding/SharedRegionParcelable.cpp",
+    ],
+
+    cflags: [
+        "-Wno-unused-parameter",
+        "-Wall",
+        "-Werror",
+
+        // By default, all symbols are hidden.
+        // "-fvisibility=hidden",
+        // AAUDIO_API is used to explicitly export a function or a variable as a visible symbol.
+        "-DAAUDIO_API=__attribute__((visibility(\"default\")))",
+    ],
+
+    shared_libs: [
+        "libaudioclient",
+        "liblog",
+        "libcutils",
+        "libutils",
+        "libbinder",
+        "libaudiomanager",
+    ],
+}
diff --git a/media/libaaudio/src/Android.mk b/media/libaaudio/src/Android.mk
deleted file mode 100644
index f7a5f9b..0000000
--- a/media/libaaudio/src/Android.mk
+++ /dev/null
@@ -1,132 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-
-# ======================= STATIC LIBRARY ==========================
-# This is being built because it make AAudio testing very easy with a complete executable.
-# TODO Remove this target later, when not needed.
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := libaaudio
-LOCAL_MODULE_TAGS := optional
-
-LIBAAUDIO_DIR := $(TOP)/frameworks/av/media/libaaudio
-LIBAAUDIO_SRC_DIR := $(LIBAAUDIO_DIR)/src
-
-LOCAL_C_INCLUDES := \
-    $(call include-path-for, audio-utils) \
-    frameworks/native/include \
-    system/core/base/include \
-    frameworks/native/media/libaaudio/include/include \
-    frameworks/av/media/libaaudio/include \
-    frameworks/native/include \
-    frameworks/av/media/libaudioclient/include \
-    $(LOCAL_PATH) \
-    $(LOCAL_PATH)/binding \
-    $(LOCAL_PATH)/client \
-    $(LOCAL_PATH)/core \
-    $(LOCAL_PATH)/fifo \
-    $(LOCAL_PATH)/legacy \
-    $(LOCAL_PATH)/utility
-
-LOCAL_AIDL_INCLUDES := frameworks/av/media/libaudioclient/aidl
-
-# If you add a file here then also add it below in the SHARED target
-LOCAL_SRC_FILES = \
-    core/AudioStream.cpp \
-    core/AudioStreamBuilder.cpp \
-    core/AAudioAudio.cpp \
-    core/AAudioStreamParameters.cpp \
-    legacy/AudioStreamLegacy.cpp \
-    legacy/AudioStreamRecord.cpp \
-    legacy/AudioStreamTrack.cpp \
-    utility/AAudioUtilities.cpp \
-    utility/FixedBlockAdapter.cpp \
-    utility/FixedBlockReader.cpp \
-    utility/FixedBlockWriter.cpp \
-    utility/LinearRamp.cpp \
-    fifo/FifoBuffer.cpp \
-    fifo/FifoControllerBase.cpp \
-    client/AudioEndpoint.cpp \
-    client/AudioStreamInternal.cpp \
-    client/AudioStreamInternalCapture.cpp \
-    client/AudioStreamInternalPlay.cpp \
-    client/IsochronousClockModel.cpp \
-    binding/AudioEndpointParcelable.cpp \
-    binding/AAudioBinderClient.cpp \
-    binding/AAudioStreamRequest.cpp \
-    binding/AAudioStreamConfiguration.cpp \
-    binding/IAAudioClient.cpp \
-    binding/IAAudioService.cpp \
-    binding/RingBufferParcelable.cpp \
-    binding/SharedMemoryParcelable.cpp \
-    binding/SharedRegionParcelable.cpp \
-    ../../libaudioclient/aidl/android/media/IAudioRecord.aidl \
-    ../../libaudioclient/aidl/android/media/IPlayer.aidl
-
-LOCAL_CFLAGS += -Wno-unused-parameter -Wall -Werror
-
-# By default, all symbols are hidden.
-# LOCAL_CFLAGS += -fvisibility=hidden
-# AAUDIO_API is used to explicitly export a function or a variable as a visible symbol.
-LOCAL_CFLAGS += -DAAUDIO_API='__attribute__((visibility("default")))'
-
-include $(BUILD_STATIC_LIBRARY)
-
-# ======================= SHARED LIBRARY ==========================
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := libaaudio
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_C_INCLUDES := \
-    $(call include-path-for, audio-utils) \
-    frameworks/native/include \
-    system/core/base/include \
-    frameworks/native/media/libaaudio/include/include \
-    frameworks/av/media/libaaudio/include \
-    $(LOCAL_PATH) \
-    $(LOCAL_PATH)/binding \
-    $(LOCAL_PATH)/client \
-    $(LOCAL_PATH)/core \
-    $(LOCAL_PATH)/fifo \
-    $(LOCAL_PATH)/legacy \
-    $(LOCAL_PATH)/utility
-
-LOCAL_SRC_FILES = core/AudioStream.cpp \
-    core/AudioStreamBuilder.cpp \
-    core/AAudioAudio.cpp \
-    core/AAudioStreamParameters.cpp \
-    legacy/AudioStreamLegacy.cpp \
-    legacy/AudioStreamRecord.cpp \
-    legacy/AudioStreamTrack.cpp \
-    utility/AAudioUtilities.cpp \
-    utility/FixedBlockAdapter.cpp \
-    utility/FixedBlockReader.cpp \
-    utility/FixedBlockWriter.cpp \
-    utility/LinearRamp.cpp \
-    fifo/FifoBuffer.cpp \
-    fifo/FifoControllerBase.cpp \
-    client/AudioEndpoint.cpp \
-    client/AudioStreamInternal.cpp \
-    client/AudioStreamInternalCapture.cpp \
-    client/AudioStreamInternalPlay.cpp \
-    client/IsochronousClockModel.cpp \
-    binding/AudioEndpointParcelable.cpp \
-    binding/AAudioBinderClient.cpp \
-    binding/AAudioStreamRequest.cpp \
-    binding/AAudioStreamConfiguration.cpp \
-    binding/IAAudioClient.cpp \
-    binding/IAAudioService.cpp \
-    binding/RingBufferParcelable.cpp \
-    binding/SharedMemoryParcelable.cpp \
-    binding/SharedRegionParcelable.cpp
-
-LOCAL_CFLAGS += -Wno-unused-parameter -Wall -Werror
-
-# By default, all symbols are hidden.
-# LOCAL_CFLAGS += -fvisibility=hidden
-# AAUDIO_API is used to explicitly export a function or a variable as a visible symbol.
-LOCAL_CFLAGS += -DAAUDIO_API='__attribute__((visibility("default")))'
-
-LOCAL_SHARED_LIBRARIES := libaudioclient liblog libcutils libutils libbinder libaudiomanager
-
-include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libaaudio/src/binding/AAudioBinderClient.cpp b/media/libaaudio/src/binding/AAudioBinderClient.cpp
index 07ee2de..dd620e3 100644
--- a/media/libaaudio/src/binding/AAudioBinderClient.cpp
+++ b/media/libaaudio/src/binding/AAudioBinderClient.cpp
@@ -15,7 +15,7 @@
  */
 
 
-#define LOG_TAG "AAudio"
+#define LOG_TAG "AAudioBinderClient"
 //#define LOG_NDEBUG 0
 #include <utils/Log.h>
 
@@ -61,11 +61,11 @@
         , Singleton<AAudioBinderClient>() {
     gKeepBinderClient = this; // so this singleton won't get deleted
     mAAudioClient = new AAudioClient(this);
-    ALOGV("AAudioBinderClient() this = %p, created mAAudioClient = %p", this, mAAudioClient.get());
+    ALOGV("%s - this = %p, created mAAudioClient = %p", __func__, this, mAAudioClient.get());
 }
 
 AAudioBinderClient::~AAudioBinderClient() {
-    ALOGV("AAudioBinderClient()::~AAudioBinderClient() destroying %p", this);
+    ALOGV("%s - destroying %p", __func__, this);
     Mutex::Autolock _l(mServiceLock);
     if (mAAudioService != 0) {
         IInterface::asBinder(mAAudioService)->unlinkToDeath(mAAudioClient);
@@ -137,7 +137,7 @@
         stream = service->openStream(request, configurationOutput);
 
         if (stream == AAUDIO_ERROR_NO_SERVICE) {
-            ALOGE("AAudioBinderClient::openStream lost connection to AAudioService.");
+            ALOGE("openStream lost connection to AAudioService.");
             dropAAudioService(); // force a reconnect
         } else {
             break;
diff --git a/media/libaaudio/src/binding/AAudioStreamRequest.cpp b/media/libaaudio/src/binding/AAudioStreamRequest.cpp
index 1200ab2..c30c5b9 100644
--- a/media/libaaudio/src/binding/AAudioStreamRequest.cpp
+++ b/media/libaaudio/src/binding/AAudioStreamRequest.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "AAudio"
+#define LOG_TAG "AAudioStreamRequest"
 //#define LOG_NDEBUG 0
 #include <utils/Log.h>
 
@@ -58,7 +58,7 @@
     return NO_ERROR;
 
 error:
-    ALOGE("AAudioStreamRequest.writeToParcel(): write failed = %d", status);
+    ALOGE("writeToParcel(): write failed = %d", status);
     return status;
 }
 
@@ -80,7 +80,7 @@
     return NO_ERROR;
 
 error:
-    ALOGE("AAudioStreamRequest.readFromParcel(): read failed = %d", status);
+    ALOGE("readFromParcel(): read failed = %d", status);
     return status;
 }
 
@@ -89,9 +89,9 @@
 }
 
 void AAudioStreamRequest::dump() const {
-    ALOGD("AAudioStreamRequest mUserId    = %d", mUserId);
-    ALOGD("AAudioStreamRequest mProcessId = %d", mProcessId);
-    ALOGD("AAudioStreamRequest mSharingModeMatchRequired = %d", mSharingModeMatchRequired);
-    ALOGD("AAudioStreamRequest mInService = %d", mInService);
+    ALOGD("mUserId    = %d", mUserId);
+    ALOGD("mProcessId = %d", mProcessId);
+    ALOGD("mSharingModeMatchRequired = %d", mSharingModeMatchRequired);
+    ALOGD("mInService = %d", mInService);
     mConfiguration.dump();
 }
diff --git a/media/libaaudio/src/binding/AudioEndpointParcelable.cpp b/media/libaaudio/src/binding/AudioEndpointParcelable.cpp
index 1a97555..9eed96d 100644
--- a/media/libaaudio/src/binding/AudioEndpointParcelable.cpp
+++ b/media/libaaudio/src/binding/AudioEndpointParcelable.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "AAudio"
+#define LOG_TAG "AudioEndpointParcelable"
 //#define LOG_NDEBUG 0
 #include <utils/Log.h>
 
@@ -112,49 +112,49 @@
 aaudio_result_t AudioEndpointParcelable::validate() {
     aaudio_result_t result;
     if (mNumSharedMemories < 0 || mNumSharedMemories >= MAX_SHARED_MEMORIES) {
-        ALOGE("AudioEndpointParcelable invalid mNumSharedMemories = %d", mNumSharedMemories);
+        ALOGE("invalid mNumSharedMemories = %d", mNumSharedMemories);
         return AAUDIO_ERROR_INTERNAL;
     }
     for (int i = 0; i < mNumSharedMemories; i++) {
         result = mSharedMemories[i].validate();
         if (result != AAUDIO_OK) {
-            ALOGE("AudioEndpointParcelable invalid mSharedMemories[%d] = %d", i, result);
+            ALOGE("invalid mSharedMemories[%d] = %d", i, result);
             return result;
         }
     }
     if ((result = mUpMessageQueueParcelable.validate()) != AAUDIO_OK) {
-        ALOGE("AudioEndpointParcelable invalid mUpMessageQueueParcelable = %d", result);
+        ALOGE("invalid mUpMessageQueueParcelable = %d", result);
         return result;
     }
     if ((result = mDownMessageQueueParcelable.validate()) != AAUDIO_OK) {
-        ALOGE("AudioEndpointParcelable invalid mDownMessageQueueParcelable = %d", result);
+        ALOGE("invalid mDownMessageQueueParcelable = %d", result);
         return result;
     }
     if ((result = mUpDataQueueParcelable.validate()) != AAUDIO_OK) {
-        ALOGE("AudioEndpointParcelable invalid mUpDataQueueParcelable = %d", result);
+        ALOGE("invalid mUpDataQueueParcelable = %d", result);
         return result;
     }
     if ((result = mDownDataQueueParcelable.validate()) != AAUDIO_OK) {
-        ALOGE("AudioEndpointParcelable invalid mDownDataQueueParcelable = %d", result);
+        ALOGE("invalid mDownDataQueueParcelable = %d", result);
         return result;
     }
     return AAUDIO_OK;
 }
 
 void AudioEndpointParcelable::dump() {
-    ALOGD("AudioEndpointParcelable ======================================= BEGIN");
-    ALOGD("AudioEndpointParcelable mNumSharedMemories = %d", mNumSharedMemories);
+    ALOGD("======================================= BEGIN");
+    ALOGD("mNumSharedMemories = %d", mNumSharedMemories);
     for (int i = 0; i < mNumSharedMemories; i++) {
         mSharedMemories[i].dump();
     }
-    ALOGD("AudioEndpointParcelable mUpMessageQueueParcelable =========");
+    ALOGD("mUpMessageQueueParcelable =========");
     mUpMessageQueueParcelable.dump();
-    ALOGD("AudioEndpointParcelable mDownMessageQueueParcelable =======");
+    ALOGD("mDownMessageQueueParcelable =======");
     mDownMessageQueueParcelable.dump();
-    ALOGD("AudioEndpointParcelable mUpDataQueueParcelable ============");
+    ALOGD("mUpDataQueueParcelable ============");
     mUpDataQueueParcelable.dump();
-    ALOGD("AudioEndpointParcelable mDownDataQueueParcelable ==========");
+    ALOGD("mDownDataQueueParcelable ==========");
     mDownDataQueueParcelable.dump();
-    ALOGD("AudioEndpointParcelable ======================================= END");
+    ALOGD("======================================= END");
 }
 
diff --git a/media/libaaudio/src/binding/RingBufferParcelable.cpp b/media/libaaudio/src/binding/RingBufferParcelable.cpp
index 6b74b21..2babbff 100644
--- a/media/libaaudio/src/binding/RingBufferParcelable.cpp
+++ b/media/libaaudio/src/binding/RingBufferParcelable.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "AAudio"
+#define LOG_TAG "RingBufferParcelable"
 //#define LOG_NDEBUG 0
 #include <utils/Log.h>
 
@@ -97,7 +97,7 @@
     }
     return NO_ERROR;
 error:
-    ALOGE("RingBufferParcelable::writeToParcel() error = %d", status);
+    ALOGE("writeToParcel() error = %d", status);
     return status;
 }
 
@@ -120,7 +120,7 @@
     }
     return NO_ERROR;
 error:
-    ALOGE("RingBufferParcelable::readFromParcel() error = %d", status);
+    ALOGE("readFromParcel() error = %d", status);
     return status;
 }
 
@@ -154,27 +154,27 @@
 aaudio_result_t RingBufferParcelable::validate() {
     aaudio_result_t result;
     if (mCapacityInFrames < 0 || mCapacityInFrames >= 32 * 1024) {
-        ALOGE("RingBufferParcelable invalid mCapacityInFrames = %d", mCapacityInFrames);
+        ALOGE("invalid mCapacityInFrames = %d", mCapacityInFrames);
         return AAUDIO_ERROR_INTERNAL;
     }
     if (mBytesPerFrame < 0 || mBytesPerFrame >= 256) {
-        ALOGE("RingBufferParcelable invalid mBytesPerFrame = %d", mBytesPerFrame);
+        ALOGE("invalid mBytesPerFrame = %d", mBytesPerFrame);
         return AAUDIO_ERROR_INTERNAL;
     }
     if (mFramesPerBurst < 0 || mFramesPerBurst >= 16 * 1024) {
-        ALOGE("RingBufferParcelable invalid mFramesPerBurst = %d", mFramesPerBurst);
+        ALOGE("invalid mFramesPerBurst = %d", mFramesPerBurst);
         return AAUDIO_ERROR_INTERNAL;
     }
     if ((result = mReadCounterParcelable.validate()) != AAUDIO_OK) {
-        ALOGE("RingBufferParcelable invalid mReadCounterParcelable = %d", result);
+        ALOGE("invalid mReadCounterParcelable = %d", result);
         return result;
     }
     if ((result = mWriteCounterParcelable.validate()) != AAUDIO_OK) {
-        ALOGE("RingBufferParcelable invalid mWriteCounterParcelable = %d", result);
+        ALOGE("invalid mWriteCounterParcelable = %d", result);
         return result;
     }
     if ((result = mDataParcelable.validate()) != AAUDIO_OK) {
-        ALOGE("RingBufferParcelable invalid mDataParcelable = %d", result);
+        ALOGE("invalid mDataParcelable = %d", result);
         return result;
     }
     return AAUDIO_OK;
@@ -182,11 +182,11 @@
 
 
 void RingBufferParcelable::dump() {
-    ALOGD("RingBufferParcelable mCapacityInFrames = %d ---------", mCapacityInFrames);
+    ALOGD("mCapacityInFrames = %d ---------", mCapacityInFrames);
     if (mCapacityInFrames > 0) {
-        ALOGD("RingBufferParcelable mBytesPerFrame = %d", mBytesPerFrame);
-        ALOGD("RingBufferParcelable mFramesPerBurst = %d", mFramesPerBurst);
-        ALOGD("RingBufferParcelable mFlags = %u", mFlags);
+        ALOGD("mBytesPerFrame = %d", mBytesPerFrame);
+        ALOGD("mFramesPerBurst = %d", mFramesPerBurst);
+        ALOGD("mFlags = %u", mFlags);
         mReadCounterParcelable.dump();
         mWriteCounterParcelable.dump();
         mDataParcelable.dump();
diff --git a/media/libaaudio/src/binding/SharedMemoryParcelable.cpp b/media/libaaudio/src/binding/SharedMemoryParcelable.cpp
index 90217ab..4e3e5d1 100644
--- a/media/libaaudio/src/binding/SharedMemoryParcelable.cpp
+++ b/media/libaaudio/src/binding/SharedMemoryParcelable.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "AAudio"
+#define LOG_TAG "SharedMemoryParcelable"
 //#define LOG_NDEBUG 0
 #include <utils/Log.h>
 
@@ -43,8 +43,7 @@
 
 void SharedMemoryParcelable::setup(const unique_fd& fd, int32_t sizeInBytes) {
     mFd.reset(dup(fd.get())); // store a duplicate fd
-    ALOGV("SharedMemoryParcelable::setup(%d -> %d, %d) this = %p\n",
-          fd.get(), mFd.get(), sizeInBytes, this);
+    ALOGV("setup(%d -> %d, %d) this = %p\n", fd.get(), mFd.get(), sizeInBytes, this);
     mSizeInBytes = sizeInBytes;
 }
 
@@ -52,7 +51,7 @@
     status_t status = parcel->writeInt32(mSizeInBytes);
     if (status != NO_ERROR) return status;
     if (mSizeInBytes > 0) {
-        ALOGV("SharedMemoryParcelable::writeToParcel() mFd = %d, this = %p\n", mFd.get(), this);
+        ALOGV("writeToParcel() mFd = %d, this = %p\n", mFd.get(), this);
         status = parcel->writeUniqueFileDescriptor(mFd);
         ALOGE_IF(status != NO_ERROR, "SharedMemoryParcelable writeDupFileDescriptor failed : %d",
                  status);
@@ -70,8 +69,7 @@
         unique_fd mmapFd;
         status = parcel->readUniqueFileDescriptor(&mmapFd);
         if (status != NO_ERROR) {
-            ALOGE("SharedMemoryParcelable::readFromParcel() readUniqueFileDescriptor() failed : %d",
-                  status);
+            ALOGE("readFromParcel() readUniqueFileDescriptor() failed : %d", status);
         } else {
             // Resolve the memory now while we still have the FD from the Parcel.
             // Closing the FD will not affect the shared memory once mmap() has been called.
@@ -85,7 +83,7 @@
     if (mResolvedAddress != MMAP_UNRESOLVED_ADDRESS) {
         int err = munmap(mResolvedAddress, mSizeInBytes);
         if (err < 0) {
-            ALOGE("SharedMemoryParcelable::close() munmap() failed %d", err);
+            ALOGE("close() munmap() failed %d", err);
             return AAudioConvert_androidToAAudioResult(err);
         }
         mResolvedAddress = MMAP_UNRESOLVED_ADDRESS;
@@ -97,8 +95,7 @@
     mResolvedAddress = (uint8_t *) mmap(0, mSizeInBytes, PROT_READ | PROT_WRITE,
                                         MAP_SHARED, fd.get(), 0);
     if (mResolvedAddress == MMAP_UNRESOLVED_ADDRESS) {
-        ALOGE("SharedMemoryParcelable mmap() failed for fd = %d, errno = %s",
-              fd.get(), strerror(errno));
+        ALOGE("mmap() failed for fd = %d, errno = %s", fd.get(), strerror(errno));
         return AAUDIO_ERROR_INTERNAL;
     }
     return AAUDIO_OK;
@@ -107,10 +104,10 @@
 aaudio_result_t SharedMemoryParcelable::resolve(int32_t offsetInBytes, int32_t sizeInBytes,
                                               void **regionAddressPtr) {
     if (offsetInBytes < 0) {
-        ALOGE("SharedMemoryParcelable illegal offsetInBytes = %d", offsetInBytes);
+        ALOGE("illegal offsetInBytes = %d", offsetInBytes);
         return AAUDIO_ERROR_OUT_OF_RANGE;
     } else if ((offsetInBytes + sizeInBytes) > mSizeInBytes) {
-        ALOGE("SharedMemoryParcelable out of range, offsetInBytes = %d, "
+        ALOGE("out of range, offsetInBytes = %d, "
                       "sizeInBytes = %d, mSizeInBytes = %d",
               offsetInBytes, sizeInBytes, mSizeInBytes);
         return AAUDIO_ERROR_OUT_OF_RANGE;
@@ -122,16 +119,15 @@
         if (mFd.get() != -1) {
             result = resolveSharedMemory(mFd);
         } else {
-            ALOGE("SharedMemoryParcelable has no file descriptor for shared memory.");
+            ALOGE("has no file descriptor for shared memory.");
             result = AAUDIO_ERROR_INTERNAL;
         }
     }
 
     if (result == AAUDIO_OK && mResolvedAddress != MMAP_UNRESOLVED_ADDRESS) {
         *regionAddressPtr = mResolvedAddress + offsetInBytes;
-        ALOGV("SharedMemoryParcelable mResolvedAddress = %p", mResolvedAddress);
-        ALOGV("SharedMemoryParcelable offset by %d, *regionAddressPtr = %p",
-              offsetInBytes, *regionAddressPtr);
+        ALOGV("mResolvedAddress = %p", mResolvedAddress);
+        ALOGV("offset by %d, *regionAddressPtr = %p", offsetInBytes, *regionAddressPtr);
     }
     return result;
 }
@@ -142,14 +138,14 @@
 
 aaudio_result_t SharedMemoryParcelable::validate() {
     if (mSizeInBytes < 0 || mSizeInBytes >= MAX_MMAP_SIZE_BYTES) {
-        ALOGE("SharedMemoryParcelable invalid mSizeInBytes = %d", mSizeInBytes);
+        ALOGE("invalid mSizeInBytes = %d", mSizeInBytes);
         return AAUDIO_ERROR_OUT_OF_RANGE;
     }
     return AAUDIO_OK;
 }
 
 void SharedMemoryParcelable::dump() {
-    ALOGD("SharedMemoryParcelable mFd = %d", mFd.get());
-    ALOGD("SharedMemoryParcelable mSizeInBytes = %d", mSizeInBytes);
-    ALOGD("SharedMemoryParcelable mResolvedAddress = %p", mResolvedAddress);
+    ALOGD("mFd = %d", mFd.get());
+    ALOGD("mSizeInBytes = %d", mSizeInBytes);
+    ALOGD("mResolvedAddress = %p", mResolvedAddress);
 }
diff --git a/media/libaaudio/src/binding/SharedRegionParcelable.cpp b/media/libaaudio/src/binding/SharedRegionParcelable.cpp
index 7381dcb..7aa80bf 100644
--- a/media/libaaudio/src/binding/SharedRegionParcelable.cpp
+++ b/media/libaaudio/src/binding/SharedRegionParcelable.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "AAudio"
+#define LOG_TAG "SharedRegionParcelable"
 //#define LOG_NDEBUG 0
 #include <utils/Log.h>
 
@@ -71,7 +71,7 @@
         return AAUDIO_OK;
     }
     if (mSharedMemoryIndex < 0) {
-        ALOGE("SharedRegionParcelable invalid mSharedMemoryIndex = %d", mSharedMemoryIndex);
+        ALOGE("invalid mSharedMemoryIndex = %d", mSharedMemoryIndex);
         return AAUDIO_ERROR_INTERNAL;
     }
     SharedMemoryParcelable *memoryParcel = &memoryParcels[mSharedMemoryIndex];
@@ -80,16 +80,16 @@
 
 aaudio_result_t SharedRegionParcelable::validate() {
     if (mSizeInBytes < 0 || mSizeInBytes >= MAX_MMAP_SIZE_BYTES) {
-        ALOGE("SharedRegionParcelable invalid mSizeInBytes = %d", mSizeInBytes);
+        ALOGE("invalid mSizeInBytes = %d", mSizeInBytes);
         return AAUDIO_ERROR_OUT_OF_RANGE;
     }
     if (mSizeInBytes > 0) {
         if (mOffsetInBytes < 0 || mOffsetInBytes >= MAX_MMAP_OFFSET_BYTES) {
-            ALOGE("SharedRegionParcelable invalid mOffsetInBytes = %d", mOffsetInBytes);
+            ALOGE("invalid mOffsetInBytes = %d", mOffsetInBytes);
             return AAUDIO_ERROR_OUT_OF_RANGE;
         }
         if (mSharedMemoryIndex < 0 || mSharedMemoryIndex >= MAX_SHARED_MEMORIES) {
-            ALOGE("SharedRegionParcelable invalid mSharedMemoryIndex = %d", mSharedMemoryIndex);
+            ALOGE("invalid mSharedMemoryIndex = %d", mSharedMemoryIndex);
             return AAUDIO_ERROR_INTERNAL;
         }
     }
@@ -97,9 +97,9 @@
 }
 
 void SharedRegionParcelable::dump() {
-    ALOGD("SharedRegionParcelable mSizeInBytes = %d -----", mSizeInBytes);
+    ALOGD("mSizeInBytes = %d -----", mSizeInBytes);
     if (mSizeInBytes > 0) {
-        ALOGD("SharedRegionParcelable mSharedMemoryIndex = %d", mSharedMemoryIndex);
-        ALOGD("SharedRegionParcelable mOffsetInBytes = %d", mOffsetInBytes);
+        ALOGD("mSharedMemoryIndex = %d", mSharedMemoryIndex);
+        ALOGD("mOffsetInBytes = %d", mOffsetInBytes);
     }
 }
diff --git a/media/libaaudio/src/client/AudioEndpoint.cpp b/media/libaaudio/src/client/AudioEndpoint.cpp
index 604eed5..f8e34d1 100644
--- a/media/libaaudio/src/client/AudioEndpoint.cpp
+++ b/media/libaaudio/src/client/AudioEndpoint.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "AAudio"
+#define LOG_TAG "AudioEndpoint"
 //#define LOG_NDEBUG 0
 #include <utils/Log.h>
 
@@ -45,6 +45,7 @@
     delete mUpCommandQueue;
 }
 
+// TODO Consider moving to a method in RingBufferDescriptor
 static aaudio_result_t AudioEndpoint_validateQueueDescriptor(const char *type,
                                                   const RingBufferDescriptor *descriptor) {
     if (descriptor == nullptr) {
@@ -127,19 +128,19 @@
     // ============================ up message queue =============================
     const RingBufferDescriptor *descriptor = &pEndpointDescriptor->upMessageQueueDescriptor;
     if(descriptor->bytesPerFrame != sizeof(AAudioServiceMessage)) {
-        ALOGE("AudioEndpoint.configure() bytesPerFrame != sizeof(AAudioServiceMessage) = %d",
+        ALOGE("configure() bytesPerFrame != sizeof(AAudioServiceMessage) = %d",
               descriptor->bytesPerFrame);
         return AAUDIO_ERROR_INTERNAL;
     }
 
     if(descriptor->readCounterAddress == nullptr || descriptor->writeCounterAddress == nullptr) {
-        ALOGE("AudioEndpoint.configure() NULL counter address");
+        ALOGE("configure() NULL counter address");
         return AAUDIO_ERROR_NULL;
     }
 
     // Prevent memory leak and reuse.
     if(mUpCommandQueue != nullptr || mDataQueue != nullptr) {
-        ALOGE("AudioEndpoint.configure() endpoint already used");
+        ALOGE("configure() endpoint already used");
         return AAUDIO_ERROR_INTERNAL;
     }
 
@@ -153,8 +154,8 @@
 
     // ============================ data queue =============================
     descriptor = &pEndpointDescriptor->dataQueueDescriptor;
-    ALOGV("AudioEndpoint.configure() data framesPerBurst = %d", descriptor->framesPerBurst);
-    ALOGV("AudioEndpoint.configure() data readCounterAddress = %p",
+    ALOGV("configure() data framesPerBurst = %d", descriptor->framesPerBurst);
+    ALOGV("configure() data readCounterAddress = %p",
           descriptor->readCounterAddress);
 
     // An example of free running is when the other side is read or written by hardware DMA
@@ -163,7 +164,7 @@
                              ? descriptor->readCounterAddress // read by other side
                              : descriptor->writeCounterAddress; // written by other side
     mFreeRunning = (remoteCounter == nullptr);
-    ALOGV("AudioEndpoint.configure() mFreeRunning = %d", mFreeRunning ? 1 : 0);
+    ALOGV("configure() mFreeRunning = %d", mFreeRunning ? 1 : 0);
 
     int64_t *readCounterAddress = (descriptor->readCounterAddress == nullptr)
                                   ? &mDataReadCounter
@@ -258,8 +259,8 @@
 }
 
 void AudioEndpoint::dump() const {
-    ALOGD("AudioEndpoint: data readCounter  = %lld", (long long) mDataQueue->getReadCounter());
-    ALOGD("AudioEndpoint: data writeCounter = %lld", (long long) mDataQueue->getWriteCounter());
+    ALOGD("data readCounter  = %lld", (long long) mDataQueue->getReadCounter());
+    ALOGD("data writeCounter = %lld", (long long) mDataQueue->getWriteCounter());
 }
 
 void AudioEndpoint::eraseDataMemory() {
diff --git a/media/libaaudio/src/client/AudioStreamInternal.cpp b/media/libaaudio/src/client/AudioStreamInternal.cpp
index 2fdbfaf..1944d5b 100644
--- a/media/libaaudio/src/client/AudioStreamInternal.cpp
+++ b/media/libaaudio/src/client/AudioStreamInternal.cpp
@@ -68,8 +68,8 @@
         , mWakeupDelayNanos(AAudioProperty_getWakeupDelayMicros() * AAUDIO_NANOS_PER_MICROSECOND)
         , mMinimumSleepNanos(AAudioProperty_getMinimumSleepMicros() * AAUDIO_NANOS_PER_MICROSECOND)
         {
-    ALOGD("AudioStreamInternal(): mWakeupDelayNanos = %d, mMinimumSleepNanos = %d",
-          mWakeupDelayNanos, mMinimumSleepNanos);
+    ALOGD("%s - mWakeupDelayNanos = %d, mMinimumSleepNanos = %d",
+          __func__, mWakeupDelayNanos, mMinimumSleepNanos);
 }
 
 AudioStreamInternal::~AudioStreamInternal() {
@@ -83,7 +83,7 @@
     AAudioStreamConfiguration configurationOutput;
 
     if (getState() != AAUDIO_STREAM_STATE_UNINITIALIZED) {
-        ALOGE("AudioStreamInternal::open(): already open! state = %d", getState());
+        ALOGE("%s - already open! state = %d", __func__, getState());
         return AAUDIO_ERROR_INVALID_STATE;
     }
 
@@ -117,7 +117,7 @@
     mServiceStreamHandle = mServiceInterface.openStream(request, configurationOutput);
     if (mServiceStreamHandle < 0) {
         result = mServiceStreamHandle;
-        ALOGE("AudioStreamInternal::open(): openStream() returned %d", result);
+        ALOGE("%s - openStream() returned %d", __func__, result);
         return result;
     }
 
@@ -156,12 +156,12 @@
 
     // Validate result from server.
     if (mFramesPerBurst < 16 || mFramesPerBurst > 16 * 1024) {
-        ALOGE("AudioStreamInternal::open(): framesPerBurst out of range = %d", mFramesPerBurst);
+        ALOGE("%s - framesPerBurst out of range = %d", __func__, mFramesPerBurst);
         result = AAUDIO_ERROR_OUT_OF_RANGE;
         goto error;
     }
     if (capacity < mFramesPerBurst || capacity > 32 * 1024) {
-        ALOGE("AudioStreamInternal::open(): bufferCapacity out of range = %d", capacity);
+        ALOGE("%s - bufferCapacity out of range = %d", __func__, capacity);
         result = AAUDIO_ERROR_OUT_OF_RANGE;
         goto error;
     }
@@ -172,13 +172,13 @@
     if (getDataCallbackProc()) {
         mCallbackFrames = builder.getFramesPerDataCallback();
         if (mCallbackFrames > getBufferCapacity() / 2) {
-            ALOGE("AudioStreamInternal::open(): framesPerCallback too big = %d, capacity = %d",
-                  mCallbackFrames, getBufferCapacity());
+            ALOGE("%s - framesPerCallback too big = %d, capacity = %d",
+                  __func__, mCallbackFrames, getBufferCapacity());
             result = AAUDIO_ERROR_OUT_OF_RANGE;
             goto error;
 
         } else if (mCallbackFrames < 0) {
-            ALOGE("AudioStreamInternal::open(): framesPerCallback negative");
+            ALOGE("%s - framesPerCallback negative", __func__);
             result = AAUDIO_ERROR_OUT_OF_RANGE;
             goto error;
 
@@ -240,7 +240,7 @@
 static void *aaudio_callback_thread_proc(void *context)
 {
     AudioStreamInternal *stream = (AudioStreamInternal *)context;
-    //LOGD("AudioStreamInternal(): oboe_callback_thread, stream = %p", stream);
+    //LOGD("oboe_callback_thread, stream = %p", stream);
     if (stream != NULL) {
         return stream->callbackLoop();
     } else {
@@ -448,32 +448,32 @@
     aaudio_result_t result = AAUDIO_OK;
     switch (message->event.event) {
         case AAUDIO_SERVICE_EVENT_STARTED:
-            ALOGD("AudioStreamInternal::onEventFromServer() got AAUDIO_SERVICE_EVENT_STARTED");
+            ALOGD("%s - got AAUDIO_SERVICE_EVENT_STARTED", __func__);
             if (getState() == AAUDIO_STREAM_STATE_STARTING) {
                 setState(AAUDIO_STREAM_STATE_STARTED);
             }
             break;
         case AAUDIO_SERVICE_EVENT_PAUSED:
-            ALOGD("AudioStreamInternal::onEventFromServer() got AAUDIO_SERVICE_EVENT_PAUSED");
+            ALOGD("%s - got AAUDIO_SERVICE_EVENT_PAUSED", __func__);
             if (getState() == AAUDIO_STREAM_STATE_PAUSING) {
                 setState(AAUDIO_STREAM_STATE_PAUSED);
             }
             break;
         case AAUDIO_SERVICE_EVENT_STOPPED:
-            ALOGD("AudioStreamInternal::onEventFromServer() got AAUDIO_SERVICE_EVENT_STOPPED");
+            ALOGD("%s - got AAUDIO_SERVICE_EVENT_STOPPED", __func__);
             if (getState() == AAUDIO_STREAM_STATE_STOPPING) {
                 setState(AAUDIO_STREAM_STATE_STOPPED);
             }
             break;
         case AAUDIO_SERVICE_EVENT_FLUSHED:
-            ALOGD("AudioStreamInternal::onEventFromServer() got AAUDIO_SERVICE_EVENT_FLUSHED");
+            ALOGD("%s - got AAUDIO_SERVICE_EVENT_FLUSHED", __func__);
             if (getState() == AAUDIO_STREAM_STATE_FLUSHING) {
                 setState(AAUDIO_STREAM_STATE_FLUSHED);
                 onFlushFromServer();
             }
             break;
         case AAUDIO_SERVICE_EVENT_CLOSED:
-            ALOGD("AudioStreamInternal::onEventFromServer() got AAUDIO_SERVICE_EVENT_CLOSED");
+            ALOGD("%s - got AAUDIO_SERVICE_EVENT_CLOSED", __func__);
             setState(AAUDIO_STREAM_STATE_CLOSED);
             break;
         case AAUDIO_SERVICE_EVENT_DISCONNECTED:
@@ -483,18 +483,15 @@
             }
             result = AAUDIO_ERROR_DISCONNECTED;
             setState(AAUDIO_STREAM_STATE_DISCONNECTED);
-            ALOGW("WARNING - AudioStreamInternal::onEventFromServer()"
-                          " AAUDIO_SERVICE_EVENT_DISCONNECTED - FIFO cleared");
+            ALOGW("%s - AAUDIO_SERVICE_EVENT_DISCONNECTED - FIFO cleared", __func__);
             break;
         case AAUDIO_SERVICE_EVENT_VOLUME:
             mStreamVolume = (float)message->event.dataDouble;
             doSetVolume();
-            ALOGD("AudioStreamInternal::onEventFromServer() AAUDIO_SERVICE_EVENT_VOLUME %lf",
-                     message->event.dataDouble);
+            ALOGD("%s - AAUDIO_SERVICE_EVENT_VOLUME %lf", __func__, message->event.dataDouble);
             break;
         default:
-            ALOGW("WARNING - AudioStreamInternal::onEventFromServer() Unrecognized event = %d",
-                 (int) message->event.event);
+            ALOGE("%s - Unrecognized event = %d", __func__, (int) message->event.event);
             break;
     }
     return result;
@@ -519,8 +516,7 @@
                 break;
 
             default:
-                ALOGE("WARNING - drainTimestampsFromService() Unrecognized what = %d",
-                      (int) message.what);
+                ALOGE("%s - unrecognized message.what = %d", __func__, (int) message.what);
                 result = AAUDIO_ERROR_INTERNAL;
                 break;
         }
@@ -533,7 +529,6 @@
     aaudio_result_t result = AAUDIO_OK;
 
     while (result == AAUDIO_OK) {
-        //ALOGD("AudioStreamInternal::processCommands() - looping, %d", result);
         AAudioServiceMessage message;
         if (mAudioEndpoint.readUpCommand(&message) != 1) {
             break; // no command this time, no problem
@@ -552,8 +547,7 @@
             break;
 
         default:
-            ALOGE("WARNING - processCommands() Unrecognized what = %d",
-                 (int) message.what);
+            ALOGE("%s - unrecognized message.what = %d", __func__, (int) message.what);
             result = AAUDIO_ERROR_INTERNAL;
             break;
         }
@@ -614,13 +608,13 @@
             if (wakeTimeNanos > deadlineNanos) {
                 // If we time out, just return the framesWritten so far.
                 // TODO remove after we fix the deadline bug
-                ALOGW("AudioStreamInternal::processData(): entered at %lld nanos, currently %lld",
+                ALOGW("processData(): entered at %lld nanos, currently %lld",
                       (long long) entryTimeNanos, (long long) currentTimeNanos);
-                ALOGW("AudioStreamInternal::processData(): TIMEOUT after %lld nanos",
+                ALOGW("processData(): TIMEOUT after %lld nanos",
                       (long long) timeoutNanoseconds);
-                ALOGW("AudioStreamInternal::processData(): wakeTime = %lld, deadline = %lld nanos",
+                ALOGW("processData(): wakeTime = %lld, deadline = %lld nanos",
                       (long long) wakeTimeNanos, (long long) deadlineNanos);
-                ALOGW("AudioStreamInternal::processData(): past deadline by %d micros",
+                ALOGW("processData(): past deadline by %d micros",
                       (int)((wakeTimeNanos - deadlineNanos) / AAUDIO_NANOS_PER_MICROSECOND));
                 mClockModel.dump();
                 mAudioEndpoint.dump();
diff --git a/media/libaaudio/src/client/AudioStreamInternalCapture.cpp b/media/libaaudio/src/client/AudioStreamInternalCapture.cpp
index b792ecd..77a481b 100644
--- a/media/libaaudio/src/client/AudioStreamInternalCapture.cpp
+++ b/media/libaaudio/src/client/AudioStreamInternalCapture.cpp
@@ -14,7 +14,8 @@
  * limitations under the License.
  */
 
-#define LOG_TAG (mInService ? "AAudioService" : "AAudio")
+#define LOG_TAG (mInService ? "AudioStreamInternalCapture_Service" \
+                          : "AudioStreamInternalCapture_Client")
 //#define LOG_NDEBUG 0
 #include <utils/Log.h>
 
@@ -152,7 +153,7 @@
 
 aaudio_result_t AudioStreamInternalCapture::readNowWithConversion(void *buffer,
                                                                 int32_t numFrames) {
-    // ALOGD("AudioStreamInternalCapture::readNowWithConversion(%p, %d)",
+    // ALOGD("readNowWithConversion(%p, %d)",
     //              buffer, numFrames);
     WrappingBuffer wrappingBuffer;
     uint8_t *destination = (uint8_t *) buffer;
@@ -201,7 +202,7 @@
     int32_t framesProcessed = numFrames - framesLeft;
     mAudioEndpoint.advanceReadIndex(framesProcessed);
 
-    //ALOGD("AudioStreamInternalCapture::readNowWithConversion() returns %d", framesProcessed);
+    //ALOGD("readNowWithConversion() returns %d", framesProcessed);
     return framesProcessed;
 }
 
@@ -215,14 +216,14 @@
     // Prevent retrograde motion.
     mLastFramesWritten = std::max(mLastFramesWritten,
                                   framesWrittenHardware + mFramesOffsetFromService);
-    //ALOGD("AudioStreamInternalCapture::getFramesWritten() returns %lld",
+    //ALOGD("getFramesWritten() returns %lld",
     //      (long long)mLastFramesWritten);
     return mLastFramesWritten;
 }
 
 int64_t AudioStreamInternalCapture::getFramesRead() {
     int64_t frames = mAudioEndpoint.getDataReadCounter() + mFramesOffsetFromService;
-    //ALOGD("AudioStreamInternalCapture::getFramesRead() returns %lld", (long long)frames);
+    //ALOGD("getFramesRead() returns %lld", (long long)frames);
     return frames;
 }
 
@@ -242,7 +243,7 @@
         // This is a BLOCKING READ!
         result = read(mCallbackBuffer, mCallbackFrames, timeoutNanos);
         if ((result != mCallbackFrames)) {
-            ALOGE("AudioStreamInternalCapture(): callbackLoop: read() returned %d", result);
+            ALOGE("callbackLoop: read() returned %d", result);
             if (result >= 0) {
                 // Only read some of the frames requested. Must have timed out.
                 result = AAUDIO_ERROR_TIMEOUT;
@@ -265,12 +266,12 @@
                 mCallbackFrames);
 
         if (callbackResult == AAUDIO_CALLBACK_RESULT_STOP) {
-            ALOGD("AudioStreamInternalCapture(): callback returned AAUDIO_CALLBACK_RESULT_STOP");
+            ALOGD("callback returned AAUDIO_CALLBACK_RESULT_STOP");
             break;
         }
     }
 
-    ALOGD("AudioStreamInternalCapture(): callbackLoop() exiting, result = %d, isActive() = %d",
+    ALOGD("callbackLoop() exiting, result = %d, isActive() = %d",
           result, (int) isActive());
     return NULL;
 }
diff --git a/media/libaaudio/src/client/AudioStreamInternalPlay.cpp b/media/libaaudio/src/client/AudioStreamInternalPlay.cpp
index 1e02eee..1cf2c72 100644
--- a/media/libaaudio/src/client/AudioStreamInternalPlay.cpp
+++ b/media/libaaudio/src/client/AudioStreamInternalPlay.cpp
@@ -14,7 +14,8 @@
  * limitations under the License.
  */
 
-#define LOG_TAG (mInService ? "AAudioService" : "AAudio")
+#define LOG_TAG (mInService ? "AudioStreamInternalPlay_Service" \
+                          : "AudioStreamInternalPlay_Client")
 //#define LOG_NDEBUG 0
 #include <utils/Log.h>
 
diff --git a/media/libaaudio/src/client/IsochronousClockModel.cpp b/media/libaaudio/src/client/IsochronousClockModel.cpp
index bac69f1..95b52be 100644
--- a/media/libaaudio/src/client/IsochronousClockModel.cpp
+++ b/media/libaaudio/src/client/IsochronousClockModel.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "AAudio"
+#define LOG_TAG "IsochronousClockModel"
 //#define LOG_NDEBUG 0
 #include <log/log.h>
 
@@ -41,20 +41,20 @@
 }
 
 void IsochronousClockModel::setPositionAndTime(int64_t framePosition, int64_t nanoTime) {
-    ALOGV("IsochronousClockModel::setPositionAndTime(%lld, %lld)",
+    ALOGV("setPositionAndTime(%lld, %lld)",
           (long long) framePosition, (long long) nanoTime);
     mMarkerFramePosition = framePosition;
     mMarkerNanoTime = nanoTime;
 }
 
 void IsochronousClockModel::start(int64_t nanoTime) {
-    ALOGV("IsochronousClockModel::start(nanos = %lld)\n", (long long) nanoTime);
+    ALOGV("start(nanos = %lld)\n", (long long) nanoTime);
     mMarkerNanoTime = nanoTime;
     mState = STATE_STARTING;
 }
 
 void IsochronousClockModel::stop(int64_t nanoTime) {
-    ALOGV("IsochronousClockModel::stop(nanos = %lld)\n", (long long) nanoTime);
+    ALOGV("stop(nanos = %lld)\n", (long long) nanoTime);
     setPositionAndTime(convertTimeToPosition(nanoTime), nanoTime);
     // TODO should we set position?
     mState = STATE_STOPPED;
@@ -156,7 +156,7 @@
     int64_t framesDelta = nextBurstPosition - mMarkerFramePosition;
     int64_t nanosDelta = convertDeltaPositionToTime(framesDelta);
     int64_t time = mMarkerNanoTime + nanosDelta;
-//    ALOGD("IsochronousClockModel::convertPositionToTime: pos = %llu --> time = %llu",
+//    ALOGD("convertPositionToTime: pos = %llu --> time = %llu",
 //         (unsigned long long)framePosition,
 //         (unsigned long long)time);
     return time;
@@ -171,19 +171,19 @@
     int64_t nextBurstPosition = mMarkerFramePosition + framesDelta;
     int64_t nextBurstIndex = nextBurstPosition / mFramesPerBurst;
     int64_t position = nextBurstIndex * mFramesPerBurst;
-//    ALOGD("IsochronousClockModel::convertTimeToPosition: time = %llu --> pos = %llu",
+//    ALOGD("convertTimeToPosition: time = %llu --> pos = %llu",
 //         (unsigned long long)nanoTime,
 //         (unsigned long long)position);
-//    ALOGD("IsochronousClockModel::convertTimeToPosition: framesDelta = %llu, mFramesPerBurst = %d",
+//    ALOGD("convertTimeToPosition: framesDelta = %llu, mFramesPerBurst = %d",
 //         (long long) framesDelta, mFramesPerBurst);
     return position;
 }
 
 void IsochronousClockModel::dump() const {
-    ALOGD("IsochronousClockModel::mMarkerFramePosition = %lld", (long long) mMarkerFramePosition);
-    ALOGD("IsochronousClockModel::mMarkerNanoTime      = %lld", (long long) mMarkerNanoTime);
-    ALOGD("IsochronousClockModel::mSampleRate          = %6d", mSampleRate);
-    ALOGD("IsochronousClockModel::mFramesPerBurst      = %6d", mFramesPerBurst);
-    ALOGD("IsochronousClockModel::mMaxLatenessInNanos  = %6d", mMaxLatenessInNanos);
-    ALOGD("IsochronousClockModel::mState               = %6d", mState);
+    ALOGD("mMarkerFramePosition = %lld", (long long) mMarkerFramePosition);
+    ALOGD("mMarkerNanoTime      = %lld", (long long) mMarkerNanoTime);
+    ALOGD("mSampleRate          = %6d", mSampleRate);
+    ALOGD("mFramesPerBurst      = %6d", mFramesPerBurst);
+    ALOGD("mMaxLatenessInNanos  = %6d", mMaxLatenessInNanos);
+    ALOGD("mState               = %6d", mState);
 }
diff --git a/media/libaaudio/src/core/AAudioStreamParameters.cpp b/media/libaaudio/src/core/AAudioStreamParameters.cpp
index 82445e7..6400eb4 100644
--- a/media/libaaudio/src/core/AAudioStreamParameters.cpp
+++ b/media/libaaudio/src/core/AAudioStreamParameters.cpp
@@ -15,7 +15,7 @@
  */
 
 
-#define LOG_TAG "AAudio"
+#define LOG_TAG "AAudioStreamParameters"
 #include <utils/Log.h>
 #include <hardware/audio.h>
 
@@ -47,12 +47,12 @@
 aaudio_result_t AAudioStreamParameters::validate() const {
     if (mSamplesPerFrame != AAUDIO_UNSPECIFIED
         && (mSamplesPerFrame < SAMPLES_PER_FRAME_MIN || mSamplesPerFrame > SAMPLES_PER_FRAME_MAX)) {
-        ALOGE("AAudioStreamParameters: channelCount out of range = %d", mSamplesPerFrame);
+        ALOGE("channelCount out of range = %d", mSamplesPerFrame);
         return AAUDIO_ERROR_OUT_OF_RANGE;
     }
 
     if (mDeviceId < 0) {
-        ALOGE("AAudioStreamParameters: deviceId out of range = %d", mDeviceId);
+        ALOGE("deviceId out of range = %d", mDeviceId);
         return AAUDIO_ERROR_OUT_OF_RANGE;
     }
 
@@ -61,7 +61,7 @@
         case AAUDIO_SHARING_MODE_SHARED:
             break;
         default:
-            ALOGE("AAudioStreamParameters: illegal sharingMode = %d", mSharingMode);
+            ALOGE("illegal sharingMode = %d", mSharingMode);
             return AAUDIO_ERROR_ILLEGAL_ARGUMENT;
             // break;
     }
@@ -72,19 +72,19 @@
         case AAUDIO_FORMAT_PCM_FLOAT:
             break; // valid
         default:
-            ALOGE("AAudioStreamParameters: audioFormat not valid = %d", mAudioFormat);
+            ALOGE("audioFormat not valid = %d", mAudioFormat);
             return AAUDIO_ERROR_INVALID_FORMAT;
             // break;
     }
 
     if (mSampleRate != AAUDIO_UNSPECIFIED
         && (mSampleRate < SAMPLE_RATE_HZ_MIN || mSampleRate > SAMPLE_RATE_HZ_MAX)) {
-        ALOGE("AAudioStreamParameters: sampleRate out of range = %d", mSampleRate);
+        ALOGE("sampleRate out of range = %d", mSampleRate);
         return AAUDIO_ERROR_INVALID_RATE;
     }
 
     if (mBufferCapacity < 0) {
-        ALOGE("AAudioStreamParameters: bufferCapacity out of range = %d", mBufferCapacity);
+        ALOGE("bufferCapacity out of range = %d", mBufferCapacity);
         return AAUDIO_ERROR_OUT_OF_RANGE;
     }
 
@@ -93,7 +93,7 @@
         case AAUDIO_DIRECTION_OUTPUT:
             break; // valid
         default:
-            ALOGE("AAudioStreamParameters: direction not valid = %d", mDirection);
+            ALOGE("direction not valid = %d", mDirection);
             return AAUDIO_ERROR_ILLEGAL_ARGUMENT;
             // break;
     }
@@ -102,12 +102,12 @@
 }
 
 void AAudioStreamParameters::dump() const {
-    ALOGD("AAudioStreamParameters mDeviceId        = %d", mDeviceId);
-    ALOGD("AAudioStreamParameters mSampleRate      = %d", mSampleRate);
-    ALOGD("AAudioStreamParameters mSamplesPerFrame = %d", mSamplesPerFrame);
-    ALOGD("AAudioStreamParameters mSharingMode     = %d", (int)mSharingMode);
-    ALOGD("AAudioStreamParameters mAudioFormat     = %d", (int)mAudioFormat);
-    ALOGD("AAudioStreamParameters mDirection       = %d", mDirection);
-    ALOGD("AAudioStreamParameters mBufferCapacity  = %d", mBufferCapacity);
+    ALOGD("mDeviceId        = %6d", mDeviceId);
+    ALOGD("mSampleRate      = %6d", mSampleRate);
+    ALOGD("mSamplesPerFrame = %6d", mSamplesPerFrame);
+    ALOGD("mSharingMode     = %6d", (int)mSharingMode);
+    ALOGD("mAudioFormat     = %6d", (int)mAudioFormat);
+    ALOGD("mDirection       = %6d", mDirection);
+    ALOGD("mBufferCapacity  = %6d", mBufferCapacity);
 }
 
diff --git a/media/libaaudio/src/core/AudioStream.cpp b/media/libaaudio/src/core/AudioStream.cpp
index 8dcc37a..27c36e1 100644
--- a/media/libaaudio/src/core/AudioStream.cpp
+++ b/media/libaaudio/src/core/AudioStream.cpp
@@ -91,11 +91,11 @@
     mErrorCallbackUserData = builder.getErrorCallbackUserData();
 
     // This is very helpful for debugging in the future. Please leave it in.
-    ALOGI("AudioStream::open() rate = %d, channels = %d, format = %d, sharing = %s, dir = %s",
+    ALOGI("open() rate = %d, channels = %d, format = %d, sharing = %s, dir = %s",
           mSampleRate, mSamplesPerFrame, mFormat,
           AudioStream_convertSharingModeToShortText(mSharingMode),
           (getDirection() == AAUDIO_DIRECTION_OUTPUT) ? "OUTPUT" : "INPUT");
-    ALOGI("AudioStream::open() device = %d, perfMode = %d, callback: %s with frames = %d",
+    ALOGI("open() device = %d, perfMode = %d, callback: %s with frames = %d",
           mDeviceId, mPerformanceMode,
           (mDataCallbackProc == nullptr ? "OFF" : "ON"),
           mFramesPerDataCallback);
@@ -163,7 +163,7 @@
                                      void* threadArg)
 {
     if (mHasThread) {
-        ALOGE("AudioStream::createThread() - mHasThread already true");
+        ALOGE("createThread() - mHasThread already true");
         return AAUDIO_ERROR_INVALID_STATE;
     }
     if (threadProc == nullptr) {
@@ -185,7 +185,7 @@
 aaudio_result_t AudioStream::joinThread(void** returnArg, int64_t timeoutNanoseconds)
 {
     if (!mHasThread) {
-        ALOGE("AudioStream::joinThread() - but has no thread");
+        ALOGE("joinThread() - but has no thread");
         return AAUDIO_ERROR_INVALID_STATE;
     }
 #if 0
diff --git a/media/libaaudio/src/core/AudioStreamBuilder.cpp b/media/libaaudio/src/core/AudioStreamBuilder.cpp
index 09ebb3e..f7cb8d6 100644
--- a/media/libaaudio/src/core/AudioStreamBuilder.cpp
+++ b/media/libaaudio/src/core/AudioStreamBuilder.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "AAudio"
+#define LOG_TAG "AudioStreamBuilder"
 //#define LOG_NDEBUG 0
 #include <utils/Log.h>
 
@@ -87,7 +87,7 @@
             break;
 
         default:
-            ALOGE("AudioStreamBuilder(): bad direction = %d", direction);
+            ALOGE("bad direction = %d", direction);
             result = AAUDIO_ERROR_ILLEGAL_ARGUMENT;
     }
     return result;
@@ -99,7 +99,7 @@
 aaudio_result_t AudioStreamBuilder::build(AudioStream** streamPtr) {
     AudioStream *audioStream = nullptr;
     if (streamPtr == nullptr) {
-        ALOGE("AudioStreamBuilder::build() streamPtr is null");
+        ALOGE("build() streamPtr is null");
         return AAUDIO_ERROR_NULL;
     }
     *streamPtr = nullptr;
@@ -124,13 +124,13 @@
     if (mapExclusivePolicy == AAUDIO_UNSPECIFIED) {
         mapExclusivePolicy = AAUDIO_MMAP_EXCLUSIVE_POLICY_DEFAULT;
     }
-    ALOGD("AudioStreamBuilder(): mmapPolicy = %d, mapExclusivePolicy = %d",
+    ALOGD("mmapPolicy = %d, mapExclusivePolicy = %d",
           mmapPolicy, mapExclusivePolicy);
 
     aaudio_sharing_mode_t sharingMode = getSharingMode();
     if ((sharingMode == AAUDIO_SHARING_MODE_EXCLUSIVE)
         && (mapExclusivePolicy == AAUDIO_POLICY_NEVER)) {
-        ALOGW("AudioStreamBuilder(): EXCLUSIVE sharing mode not supported. Use SHARED.");
+        ALOGW("EXCLUSIVE sharing mode not supported. Use SHARED.");
         sharingMode = AAUDIO_SHARING_MODE_SHARED;
         setSharingMode(sharingMode);
     }
@@ -156,7 +156,7 @@
             audioStream = nullptr;
 
             if (isMMap && allowLegacy) {
-                ALOGD("AudioStreamBuilder.build() MMAP stream did not open so try Legacy path");
+                ALOGD("build() MMAP stream did not open so try Legacy path");
                 // If MMAP stream failed to open then TRY using a legacy stream.
                 result = builder_createStream(getDirection(), sharingMode,
                                               false, &audioStream);
@@ -190,7 +190,7 @@
         case AAUDIO_PERFORMANCE_MODE_LOW_LATENCY:
             break;
         default:
-            ALOGE("AudioStreamBuilder: illegal performanceMode = %d", mPerformanceMode);
+            ALOGE("illegal performanceMode = %d", mPerformanceMode);
             return AAUDIO_ERROR_ILLEGAL_ARGUMENT;
             // break;
     }
@@ -199,7 +199,7 @@
     if (mFramesPerDataCallback != AAUDIO_UNSPECIFIED
         && (mFramesPerDataCallback < FRAMES_PER_DATA_CALLBACK_MIN
             || mFramesPerDataCallback > FRAMES_PER_DATA_CALLBACK_MAX)) {
-        ALOGE("AudioStreamBuilder: framesPerDataCallback out of range = %d",
+        ALOGE("framesPerDataCallback out of range = %d",
               mFramesPerDataCallback);
         return AAUDIO_ERROR_OUT_OF_RANGE;
     }
diff --git a/media/libaaudio/src/fifo/FifoBuffer.cpp b/media/libaaudio/src/fifo/FifoBuffer.cpp
index a869886..e6e7c8e 100644
--- a/media/libaaudio/src/fifo/FifoBuffer.cpp
+++ b/media/libaaudio/src/fifo/FifoBuffer.cpp
@@ -43,7 +43,7 @@
     int32_t bytesPerBuffer = bytesPerFrame * capacityInFrames;
     mStorage = new uint8_t[bytesPerBuffer];
     mStorageOwned = true;
-    ALOGD("FifoBuffer: capacityInFrames = %d, bytesPerFrame = %d",
+    ALOGD("capacityInFrames = %d, bytesPerFrame = %d",
           capacityInFrames, bytesPerFrame);
 }
 
diff --git a/media/libaaudio/src/legacy/AudioStreamRecord.cpp b/media/libaaudio/src/legacy/AudioStreamRecord.cpp
index bc6e60c..6d98ed3 100644
--- a/media/libaaudio/src/legacy/AudioStreamRecord.cpp
+++ b/media/libaaudio/src/legacy/AudioStreamRecord.cpp
@@ -96,7 +96,7 @@
     }
     mCallbackBufferSize = builder.getFramesPerDataCallback();
 
-    ALOGD("AudioStreamRecord::open(), request notificationFrames = %u, frameCount = %u",
+    ALOGD("open(), request notificationFrames = %u, frameCount = %u",
           notificationFrames, (uint)frameCount);
     mAudioRecord = new AudioRecord(
             mOpPackageName // const String16& opPackageName TODO does not compile
@@ -126,7 +126,7 @@
     status_t status = mAudioRecord->initCheck();
     if (status != OK) {
         close();
-        ALOGE("AudioStreamRecord::open(), initCheck() returned %d", status);
+        ALOGE("open(), initCheck() returned %d", status);
         return AAudioConvert_androidToAAudioResult(status);
     }
 
@@ -136,7 +136,7 @@
 
     int32_t actualSampleRate = mAudioRecord->getSampleRate();
     ALOGW_IF(actualSampleRate != getSampleRate(),
-             "AudioStreamRecord::open() sampleRate changed from %d to %d",
+             "open() sampleRate changed from %d to %d",
              getSampleRate(), actualSampleRate);
     setSampleRate(actualSampleRate);
 
@@ -164,10 +164,10 @@
 
     // Log warning if we did not get what we asked for.
     ALOGW_IF(actualFlags != flags,
-             "AudioStreamRecord::open() flags changed from 0x%08X to 0x%08X",
+             "open() flags changed from 0x%08X to 0x%08X",
              flags, actualFlags);
     ALOGW_IF(actualPerformanceMode != perfMode,
-             "AudioStreamRecord::open() perfMode changed from %d to %d",
+             "open() perfMode changed from %d to %d",
              perfMode, actualPerformanceMode);
 
     setState(AAUDIO_STREAM_STATE_OPEN);
diff --git a/media/libaaudio/src/legacy/AudioStreamTrack.cpp b/media/libaaudio/src/legacy/AudioStreamTrack.cpp
index 0e9aaef..c2ce9a2 100644
--- a/media/libaaudio/src/legacy/AudioStreamTrack.cpp
+++ b/media/libaaudio/src/legacy/AudioStreamTrack.cpp
@@ -113,7 +113,7 @@
     }
     mCallbackBufferSize = builder.getFramesPerDataCallback();
 
-    ALOGD("AudioStreamTrack::open(), request notificationFrames = %d, frameCount = %u",
+    ALOGD("open(), request notificationFrames = %d, frameCount = %u",
           notificationFrames, (uint)frameCount);
     mAudioTrack = new AudioTrack(); // TODO review
     if (getDeviceId() != AAUDIO_UNSPECIFIED) {
@@ -139,7 +139,7 @@
     status_t status = mAudioTrack->initCheck();
     if (status != NO_ERROR) {
         close();
-        ALOGE("AudioStreamTrack::open(), initCheck() returned %d", status);
+        ALOGE("open(), initCheck() returned %d", status);
         return AAudioConvert_androidToAAudioResult(status);
     }
 
@@ -153,7 +153,7 @@
 
     int32_t actualSampleRate = mAudioTrack->getSampleRate();
     ALOGW_IF(actualSampleRate != getSampleRate(),
-             "AudioStreamTrack::open() sampleRate changed from %d to %d",
+             "open() sampleRate changed from %d to %d",
              getSampleRate(), actualSampleRate);
     setSampleRate(actualSampleRate);
 
@@ -186,10 +186,10 @@
 
     // Log warning if we did not get what we asked for.
     ALOGW_IF(actualFlags != flags,
-             "AudioStreamTrack::open() flags changed from 0x%08X to 0x%08X",
+             "open() flags changed from 0x%08X to 0x%08X",
              flags, actualFlags);
     ALOGW_IF(actualPerformanceMode != perfMode,
-             "AudioStreamTrack::open() perfMode changed from %d to %d",
+             "open() perfMode changed from %d to %d",
              perfMode, actualPerformanceMode);
 
     return AAUDIO_OK;
@@ -227,7 +227,7 @@
     std::lock_guard<std::mutex> lock(mStreamMutex);
 
     if (mAudioTrack.get() == nullptr) {
-        ALOGE("AudioStreamTrack::requestStart() no AudioTrack");
+        ALOGE("requestStart() no AudioTrack");
         return AAUDIO_ERROR_INVALID_STATE;
     }
     // Get current position so we can detect when the track is playing.
@@ -273,10 +273,10 @@
     std::lock_guard<std::mutex> lock(mStreamMutex);
 
     if (mAudioTrack.get() == nullptr) {
-        ALOGE("AudioStreamTrack::requestFlush() no AudioTrack");
+        ALOGE("requestFlush() no AudioTrack");
         return AAUDIO_ERROR_INVALID_STATE;
     } else if (getState() != AAUDIO_STREAM_STATE_PAUSED) {
-        ALOGE("AudioStreamTrack::requestFlush() not paused");
+        ALOGE("requestFlush() not paused");
         return AAUDIO_ERROR_INVALID_STATE;
     }
     setState(AAUDIO_STREAM_STATE_FLUSHING);
@@ -291,7 +291,7 @@
     std::lock_guard<std::mutex> lock(mStreamMutex);
 
     if (mAudioTrack.get() == nullptr) {
-        ALOGE("AudioStreamTrack::requestStop() no AudioTrack");
+        ALOGE("requestStop() no AudioTrack");
         return AAUDIO_ERROR_INVALID_STATE;
     }
     onStop();
diff --git a/media/libaaudio/src/utility/MonotonicCounter.h b/media/libaaudio/src/utility/MonotonicCounter.h
index 13c92a2..5833eab 100644
--- a/media/libaaudio/src/utility/MonotonicCounter.h
+++ b/media/libaaudio/src/utility/MonotonicCounter.h
@@ -89,6 +89,18 @@
         mCounter32 = 0;
     }
 
+    /**
+     * Round 64-bit counter up to a multiple of the period.
+     *
+     * @param period might be, for example, a buffer capacity
+     */
+    void roundUp64(int32_t period) {
+        if (period > 0) {
+            int64_t numPeriods = (mCounter64 + period - 1) / period;
+            mCounter64 = numPeriods * period;
+        }
+    }
+
 private:
     int64_t mCounter64 = 0;
     int32_t mCounter32 = 0;
diff --git a/media/libaaudio/tests/Android.bp b/media/libaaudio/tests/Android.bp
new file mode 100644
index 0000000..87a4273
--- /dev/null
+++ b/media/libaaudio/tests/Android.bp
@@ -0,0 +1,101 @@
+cc_defaults {
+    name: "libaaudio_tests_defaults",
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
+}
+
+cc_test {
+    name: "test_aaudio_marshalling",
+    defaults: ["libaaudio_tests_defaults"],
+    srcs: ["test_marshalling.cpp"],
+    shared_libs: [
+        "libaaudio",
+        "libbinder",
+        "libcutils",
+        "libutils",
+    ],
+}
+
+cc_test {
+    name: "test_block_adapter",
+    defaults: ["libaaudio_tests_defaults"],
+    srcs: ["test_block_adapter.cpp"],
+    shared_libs: ["libaaudio"],
+}
+
+cc_test {
+    name: "test_timestamps",
+    defaults: ["libaaudio_tests_defaults"],
+    srcs: ["test_timestamps.cpp"],
+    header_libs: ["libaaudio_example_utils"],
+    shared_libs: ["libaaudio"],
+}
+
+cc_test {
+    name: "test_linear_ramp",
+    defaults: ["libaaudio_tests_defaults"],
+    srcs: ["test_linear_ramp.cpp"],
+    shared_libs: ["libaaudio"],
+}
+
+cc_test {
+    name: "test_open_params",
+    defaults: ["libaaudio_tests_defaults"],
+    srcs: ["test_open_params.cpp"],
+    shared_libs: [
+        "libaaudio",
+        "libbinder",
+        "libcutils",
+        "libutils",
+    ],
+}
+
+cc_test {
+    name: "test_no_close",
+    defaults: ["libaaudio_tests_defaults"],
+    srcs: ["test_no_close.cpp"],
+    shared_libs: [
+        "libaaudio",
+        "libbinder",
+        "libcutils",
+        "libutils",
+    ],
+}
+
+cc_test {
+    name: "test_aaudio_recovery",
+    defaults: ["libaaudio_tests_defaults"],
+    srcs: ["test_recovery.cpp"],
+    shared_libs: [
+        "libaaudio",
+        "libbinder",
+        "libcutils",
+        "libutils",
+    ],
+}
+
+cc_test {
+    name: "test_n_streams",
+    defaults: ["libaaudio_tests_defaults"],
+    srcs: ["test_n_streams.cpp"],
+    shared_libs: [
+        "libaaudio",
+        "libbinder",
+        "libcutils",
+        "libutils",
+    ],
+}
+
+cc_test {
+    name: "test_bad_disconnect",
+    defaults: ["libaaudio_tests_defaults"],
+    srcs: ["test_bad_disconnect.cpp"],
+    shared_libs: [
+        "libaaudio",
+        "libbinder",
+        "libcutils",
+        "libutils",
+    ],
+}
diff --git a/media/libaaudio/tests/Android.mk b/media/libaaudio/tests/Android.mk
deleted file mode 100644
index 37b010d..0000000
--- a/media/libaaudio/tests/Android.mk
+++ /dev/null
@@ -1,82 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_C_INCLUDES := \
-    $(call include-path-for, audio-utils) \
-    frameworks/av/media/libaaudio/include \
-    frameworks/av/media/libaaudio/src
-LOCAL_SRC_FILES:= test_marshalling.cpp
-LOCAL_SHARED_LIBRARIES := libaaudio libbinder libcutils libutils
-LOCAL_MODULE := test_aaudio_marshalling
-include $(BUILD_NATIVE_TEST)
-
-include $(CLEAR_VARS)
-LOCAL_C_INCLUDES := \
-    $(call include-path-for, audio-utils) \
-    frameworks/av/media/libaaudio/include \
-    frameworks/av/media/libaaudio/src
-LOCAL_SRC_FILES:= test_block_adapter.cpp
-LOCAL_SHARED_LIBRARIES := libaaudio
-LOCAL_MODULE := test_block_adapter
-include $(BUILD_NATIVE_TEST)
-
-include $(CLEAR_VARS)
-LOCAL_C_INCLUDES := \
-    $(call include-path-for, audio-utils) \
-    frameworks/av/media/libaaudio/include \
-    frameworks/av/media/libaaudio/src \
-    frameworks/av/media/libaaudio/examples
-LOCAL_SRC_FILES:= test_timestamps.cpp
-LOCAL_SHARED_LIBRARIES := libaaudio
-LOCAL_MODULE := test_timestamps
-include $(BUILD_NATIVE_TEST)
-
-include $(CLEAR_VARS)
-LOCAL_C_INCLUDES := \
-    $(call include-path-for, audio-utils) \
-    frameworks/av/media/libaaudio/include \
-    frameworks/av/media/libaaudio/src
-LOCAL_SRC_FILES:= test_linear_ramp.cpp
-LOCAL_SHARED_LIBRARIES := libaaudio
-LOCAL_MODULE := test_linear_ramp
-include $(BUILD_NATIVE_TEST)
-
-include $(CLEAR_VARS)
-LOCAL_C_INCLUDES := \
-    $(call include-path-for, audio-utils) \
-    frameworks/av/media/libaaudio/include \
-    frameworks/av/media/libaaudio/src
-LOCAL_SRC_FILES:= test_open_params.cpp
-LOCAL_SHARED_LIBRARIES := libaaudio libbinder libcutils libutils
-LOCAL_MODULE := test_open_params
-include $(BUILD_NATIVE_TEST)
-
-include $(CLEAR_VARS)
-LOCAL_C_INCLUDES := \
-    $(call include-path-for, audio-utils) \
-    frameworks/av/media/libaaudio/include \
-    frameworks/av/media/libaaudio/src
-LOCAL_SRC_FILES:= test_no_close.cpp
-LOCAL_SHARED_LIBRARIES := libaaudio libbinder libcutils libutils
-LOCAL_MODULE := test_no_close
-include $(BUILD_NATIVE_TEST)
-
-include $(CLEAR_VARS)
-LOCAL_C_INCLUDES := \
-    $(call include-path-for, audio-utils) \
-    frameworks/av/media/libaaudio/include \
-    frameworks/av/media/libaaudio/src
-LOCAL_SRC_FILES:= test_recovery.cpp
-LOCAL_SHARED_LIBRARIES := libaaudio libbinder libcutils libutils
-LOCAL_MODULE := test_aaudio_recovery
-include $(BUILD_NATIVE_TEST)
-
-include $(CLEAR_VARS)
-LOCAL_C_INCLUDES := \
-    $(call include-path-for, audio-utils) \
-    frameworks/av/media/libaaudio/include \
-    frameworks/av/media/libaaudio/src
-LOCAL_SRC_FILES:= test_n_streams.cpp
-LOCAL_SHARED_LIBRARIES := libaaudio libbinder libcutils libutils
-LOCAL_MODULE := test_n_streams
-include $(BUILD_NATIVE_TEST)
diff --git a/media/libaaudio/tests/test_bad_disconnect.cpp b/media/libaaudio/tests/test_bad_disconnect.cpp
new file mode 100644
index 0000000..435990d
--- /dev/null
+++ b/media/libaaudio/tests/test_bad_disconnect.cpp
@@ -0,0 +1,168 @@
+/*
+ * 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.
+ */
+
+/**
+ * Handle a DISCONNECT by only opening and starting a new stream
+ * without stopping and closing the old one.
+ * This caused the new stream to use the old disconnected device.
+ */
+
+#include <stdio.h>
+#include <thread>
+#include <unistd.h>
+
+#include <aaudio/AAudio.h>
+
+#define DEFAULT_TIMEOUT_NANOS  ((int64_t)1000000000)
+
+static void s_myErrorCallbackProc(
+        AAudioStream *stream,
+        void *userData,
+        aaudio_result_t error);
+
+struct AudioEngine {
+    AAudioStreamBuilder *builder = nullptr;
+    AAudioStream *stream = nullptr;
+    std::thread *thread = nullptr;
+    int64_t framesRead = 0;
+};
+
+AudioEngine s_AudioEngine;
+
+// Callback function that fills the audio output buffer.
+static aaudio_data_callback_result_t s_myDataCallbackProc(
+        AAudioStream *stream,
+        void *userData,
+        void *audioData,
+        int32_t numFrames
+) {
+    (void) userData;
+    (void) audioData;
+    (void) numFrames;
+    s_AudioEngine.framesRead = AAudioStream_getFramesRead(stream);
+    return AAUDIO_CALLBACK_RESULT_CONTINUE;
+}
+
+static aaudio_result_t s_StartAudio() {
+    int32_t framesPerBurst = 0;
+    int32_t deviceId = 0;
+
+    // Use an AAudioStreamBuilder to contain requested parameters.
+    aaudio_result_t result = AAudio_createStreamBuilder(&s_AudioEngine.builder);
+    if (result != AAUDIO_OK) {
+        printf("AAudio_createStreamBuilder returned %s",
+               AAudio_convertResultToText(result));
+        return result;
+    }
+
+    // Request stream properties.
+    AAudioStreamBuilder_setFormat(s_AudioEngine.builder, AAUDIO_FORMAT_PCM_FLOAT);
+    AAudioStreamBuilder_setPerformanceMode(s_AudioEngine.builder, AAUDIO_PERFORMANCE_MODE_LOW_LATENCY);
+    AAudioStreamBuilder_setDataCallback(s_AudioEngine.builder, s_myDataCallbackProc, nullptr);
+    AAudioStreamBuilder_setErrorCallback(s_AudioEngine.builder, s_myErrorCallbackProc, nullptr);
+
+    // Create an AAudioStream using the Builder.
+    result = AAudioStreamBuilder_openStream(s_AudioEngine.builder, &s_AudioEngine.stream);
+    if (result != AAUDIO_OK) {
+        printf("AAudioStreamBuilder_openStream returned %s",
+               AAudio_convertResultToText(result));
+        return result;
+    }
+
+    result = AAudioStream_requestStart(s_AudioEngine.stream);
+    if (result != AAUDIO_OK) {
+        printf("AAudioStream_requestStart returned %s",
+               AAudio_convertResultToText(result));
+    }
+
+    // Check to see what kind of stream we actually got.
+    deviceId = AAudioStream_getDeviceId(s_AudioEngine.stream);
+    framesPerBurst = AAudioStream_getFramesPerBurst(s_AudioEngine.stream);
+
+    printf("-------- started: deviceId = %3d, framesPerBurst = %3d\n", deviceId, framesPerBurst);
+
+    return result;
+}
+
+static aaudio_result_t s_StopAudio() {
+    aaudio_result_t result = AAUDIO_OK;
+    if (s_AudioEngine.stream != nullptr) {
+        result = AAudioStream_requestStop(s_AudioEngine.stream);
+        if (result != AAUDIO_OK) {
+            printf("AAudioStream_requestStop returned %s\n",
+                   AAudio_convertResultToText(result));
+        }
+        result = AAudioStream_close(s_AudioEngine.stream);
+        if (result != AAUDIO_OK) {
+            printf("AAudioStream_close returned %s\n",
+                   AAudio_convertResultToText(result));
+        }
+        s_AudioEngine.stream = nullptr;
+        AAudioStreamBuilder_delete(s_AudioEngine.builder);
+        s_AudioEngine.builder = nullptr;
+    }
+    return result;
+}
+
+static void s_StartThreadProc() {
+    // A good app would call s_StopAudio here! This test simulates a bad app.
+    s_StartAudio();
+    s_AudioEngine.thread = nullptr;
+}
+
+static void s_myErrorCallbackProc(
+        AAudioStream *stream __unused,
+        void *userData __unused,
+        aaudio_result_t error) {
+    if (error == AAUDIO_ERROR_DISCONNECTED) {
+        // Handle stream restart on a separate thread
+        if (s_AudioEngine.thread == nullptr) {
+            s_AudioEngine.thread = new std::thread(s_StartThreadProc);
+        }
+    }
+}
+
+int main(int argc, char **argv) {
+    (void) argc;
+    (void) argv;
+
+    aaudio_result_t result = AAUDIO_OK;
+
+    // Make printf print immediately so that debug info is not stuck
+    // in a buffer if we hang or crash.
+    setvbuf(stdout, nullptr, _IONBF, (size_t) 0);
+
+    printf("Test Bad Disconnect V1.0\n");
+    printf("\n=========== Please PLUG and UNPLUG headphones! ==============\n\n");
+    printf("You should see the deviceID change on each plug event.\n");
+    printf("Headphones will generally get a new deviceId each time.\n");
+    printf("Speakers will have the same deviceId each time.\n");
+    printf("The framesRead should reset on each plug event then increase over time.\n");
+    printf("\n");
+
+    result = s_StartAudio();
+
+    if (result == AAUDIO_OK) {
+        for (int i = 20; i > 0; i--) {
+            sleep(1);
+            printf("playing silence #%d, framesRead = %d\n", i, (int) s_AudioEngine.framesRead);
+        }
+    }
+
+    s_StopAudio();
+
+    printf("result = %d = %s\n", result, AAudio_convertResultToText(result));
+}
diff --git a/media/libaaudio/tests/test_n_streams.cpp b/media/libaaudio/tests/test_n_streams.cpp
index 271d024..e2d4a82 100644
--- a/media/libaaudio/tests/test_n_streams.cpp
+++ b/media/libaaudio/tests/test_n_streams.cpp
@@ -71,7 +71,6 @@
 
     AAudioStreamBuilder_delete(aaudioBuilder);
 
-finish:
     return result;
 }
 
diff --git a/media/libaaudio/tests/test_open_params.cpp b/media/libaaudio/tests/test_open_params.cpp
index 01b8799..3451242 100644
--- a/media/libaaudio/tests/test_open_params.cpp
+++ b/media/libaaudio/tests/test_open_params.cpp
@@ -25,21 +25,6 @@
 
 #include <gtest/gtest.h>
 
-static const char *getSharingModeText(aaudio_sharing_mode_t mode) {
-    const char *modeText = "unknown";
-    switch (mode) {
-    case AAUDIO_SHARING_MODE_EXCLUSIVE:
-        modeText = "EXCLUSIVE";
-        break;
-    case AAUDIO_SHARING_MODE_SHARED:
-        modeText = "SHARED";
-        break;
-    default:
-        break;
-    }
-    return modeText;
-}
-
 // Callback function that fills the audio output buffer.
 aaudio_data_callback_result_t MyDataCallbackProc(
         AAudioStream *stream,
@@ -67,7 +52,6 @@
     int32_t actualChannelCount = 0;
     int32_t actualSampleRate = 0;
     aaudio_format_t actualDataFormat = AAUDIO_FORMAT_UNSPECIFIED;
-    aaudio_sharing_mode_t actualSharingMode = AAUDIO_SHARING_MODE_SHARED;
     aaudio_direction_t actualDirection;
 
     AAudioStreamBuilder *aaudioBuilder = nullptr;
diff --git a/media/libaaudio/tests/test_recovery.cpp b/media/libaaudio/tests/test_recovery.cpp
index 7268a30..6e89f83 100644
--- a/media/libaaudio/tests/test_recovery.cpp
+++ b/media/libaaudio/tests/test_recovery.cpp
@@ -23,24 +23,9 @@
 
 #define DEFAULT_TIMEOUT_NANOS  ((int64_t)1000000000)
 
-static const char *getSharingModeText(aaudio_sharing_mode_t mode) {
-    const char *modeText = "unknown";
-    switch (mode) {
-        case AAUDIO_SHARING_MODE_EXCLUSIVE:
-            modeText = "EXCLUSIVE";
-            break;
-        case AAUDIO_SHARING_MODE_SHARED:
-            modeText = "SHARED";
-            break;
-        default:
-            break;
-    }
-    return modeText;
-}
-
 int main(int argc, char **argv) {
     (void) argc;
-    (void *)argv;
+    (void) argv;
 
     aaudio_result_t result = AAUDIO_OK;
 
@@ -52,7 +37,6 @@
     int32_t actualChannelCount = 0;
     int32_t actualSampleRate = 0;
     aaudio_format_t actualDataFormat = AAUDIO_FORMAT_PCM_FLOAT;
-    aaudio_sharing_mode_t actualSharingMode = AAUDIO_SHARING_MODE_SHARED;
 
     AAudioStreamBuilder *aaudioBuilder = nullptr;
     AAudioStream *aaudioStream = nullptr;
diff --git a/media/libaaudio/tests/test_timestamps.cpp b/media/libaaudio/tests/test_timestamps.cpp
index fb363e7..dfa7815 100644
--- a/media/libaaudio/tests/test_timestamps.cpp
+++ b/media/libaaudio/tests/test_timestamps.cpp
@@ -22,8 +22,7 @@
 
 #include <aaudio/AAudio.h>
 #include <aaudio/AAudioTesting.h>
-#include "utils/AAudioExampleUtils.h"
-#include "../examples/utils/AAudioExampleUtils.h"
+#include "AAudioExampleUtils.h"
 
 // Arbitrary period for glitches, once per second at 48000 Hz.
 #define FORCED_UNDERRUN_PERIOD_FRAMES    48000
@@ -111,8 +110,6 @@
     aaudio_result_t result = AAUDIO_OK;
 
     int32_t framesPerBurst = 0;
-    float *buffer = nullptr;
-
     int32_t actualChannelCount = 0;
     int32_t actualSampleRate = 0;
     int32_t originalBufferSize = 0;
@@ -287,7 +284,7 @@
 
 int main(int argc, char **argv) {
     (void) argc;
-    (void *) argv;
+    (void) argv;
 
     aaudio_result_t result = AAUDIO_OK;
 
diff --git a/media/libaudioclient/AudioSystem.cpp b/media/libaudioclient/AudioSystem.cpp
index cdc75ac..58330ae 100644
--- a/media/libaudioclient/AudioSystem.cpp
+++ b/media/libaudioclient/AudioSystem.cpp
@@ -822,16 +822,11 @@
 }
 
 
-audio_io_handle_t AudioSystem::getOutput(audio_stream_type_t stream,
-                                    uint32_t samplingRate,
-                                    audio_format_t format,
-                                    audio_channel_mask_t channelMask,
-                                    audio_output_flags_t flags,
-                                    const audio_offload_info_t *offloadInfo)
+audio_io_handle_t AudioSystem::getOutput(audio_stream_type_t stream)
 {
     const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
     if (aps == 0) return 0;
-    return aps->getOutput(stream, samplingRate, format, channelMask, flags, offloadInfo);
+    return aps->getOutput(stream);
 }
 
 status_t AudioSystem::getOutputForAttr(const audio_attributes_t *attr,
diff --git a/media/libaudioclient/AudioTrack.cpp b/media/libaudioclient/AudioTrack.cpp
index 6206be0..356b321 100644
--- a/media/libaudioclient/AudioTrack.cpp
+++ b/media/libaudioclient/AudioTrack.cpp
@@ -216,19 +216,19 @@
         pid_t pid,
         const audio_attributes_t* pAttributes,
         bool doNotReconnect,
-        float maxRequiredSpeed)
+        float maxRequiredSpeed,
+        audio_port_handle_t selectedDeviceId)
     : mStatus(NO_INIT),
       mState(STATE_STOPPED),
       mPreviousPriority(ANDROID_PRIORITY_NORMAL),
       mPreviousSchedulingGroup(SP_DEFAULT),
       mPausedPosition(0),
-      mSelectedDeviceId(AUDIO_PORT_HANDLE_NONE),
       mPortId(AUDIO_PORT_HANDLE_NONE)
 {
     mStatus = set(streamType, sampleRate, format, channelMask,
             frameCount, flags, cbf, user, notificationFrames,
             0 /*sharedBuffer*/, false /*threadCanCallJava*/, sessionId, transferType,
-            offloadInfo, uid, pid, pAttributes, doNotReconnect, maxRequiredSpeed);
+            offloadInfo, uid, pid, pAttributes, doNotReconnect, maxRequiredSpeed, selectedDeviceId);
 }
 
 AudioTrack::AudioTrack(
@@ -310,7 +310,8 @@
         pid_t pid,
         const audio_attributes_t* pAttributes,
         bool doNotReconnect,
-        float maxRequiredSpeed)
+        float maxRequiredSpeed,
+        audio_port_handle_t selectedDeviceId)
 {
     ALOGV("set(): streamType %d, sampleRate %u, format %#x, channelMask %#x, frameCount %zu, "
           "flags #%x, notificationFrames %d, sessionId %d, transferType %d, uid %d, pid %d",
@@ -318,6 +319,7 @@
           sessionId, transferType, uid, pid);
 
     mThreadCanCallJava = threadCanCallJava;
+    mSelectedDeviceId = selectedDeviceId;
 
     switch (transferType) {
     case TRANSFER_DEFAULT:
@@ -1221,6 +1223,7 @@
         mSelectedDeviceId = deviceId;
         if (mStatus == NO_ERROR) {
             android_atomic_or(CBLK_INVALID, &mCblk->mFlags);
+            mProxy->interrupt();
         }
     }
     return NO_ERROR;
@@ -1393,14 +1396,14 @@
 
         bool useCaseAllowed = sharedBuffer || transferAllowed;
         if (!useCaseAllowed) {
-            ALOGW("AUDIO_OUTPUT_FLAG_FAST denied, not shared buffer and transfer = %s",
+            ALOGW("AUDIO_OUTPUT_FLAG_FAST denied by client, not shared buffer and transfer = %s",
                   convertTransferToText(mTransfer));
         }
 
         // sample rates must also match
         bool sampleRateAllowed = mSampleRate == mAfSampleRate;
         if (!sampleRateAllowed) {
-            ALOGW("AUDIO_OUTPUT_FLAG_FAST denied, rates do not match %u Hz, require %u Hz",
+            ALOGW("AUDIO_OUTPUT_FLAG_FAST denied by client, sample rate %u Hz but HAL needs %u Hz",
                   mSampleRate, mAfSampleRate);
         }
 
@@ -1578,6 +1581,15 @@
             // or at least triple-buffering if there is sample rate conversion
             const int nBuffering = mOriginalSampleRate == mAfSampleRate ? 2 : 3;
             maxNotificationFrames = frameCount / nBuffering;
+            // If client requested a fast track but this was denied, then use the smaller maximum.
+            // FMS_20 is the minimum task wakeup period in ms for which CFS operates reliably.
+#define FMS_20 20   // FIXME share a common declaration with the same symbol in Threads.cpp
+            if (mOrigFlags & AUDIO_OUTPUT_FLAG_FAST) {
+                size_t maxNotificationFramesFastDenied = FMS_20 * mSampleRate / 1000;
+                if (maxNotificationFrames > maxNotificationFramesFastDenied) {
+                    maxNotificationFrames = maxNotificationFramesFastDenied;
+                }
+            }
         }
         if (mNotificationFramesAct == 0 || mNotificationFramesAct > maxNotificationFrames) {
             if (mNotificationFramesAct == 0) {
diff --git a/media/libaudioclient/IAudioPolicyService.cpp b/media/libaudioclient/IAudioPolicyService.cpp
index ceba211..0397eec 100644
--- a/media/libaudioclient/IAudioPolicyService.cpp
+++ b/media/libaudioclient/IAudioPolicyService.cpp
@@ -160,28 +160,11 @@
         return static_cast <audio_policy_forced_cfg_t> (reply.readInt32());
     }
 
-    virtual audio_io_handle_t getOutput(
-                                        audio_stream_type_t stream,
-                                        uint32_t samplingRate,
-                                        audio_format_t format,
-                                        audio_channel_mask_t channelMask,
-                                        audio_output_flags_t flags,
-                                        const audio_offload_info_t *offloadInfo)
+    virtual audio_io_handle_t getOutput(audio_stream_type_t stream)
     {
         Parcel data, reply;
         data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
         data.writeInt32(static_cast <uint32_t>(stream));
-        data.writeInt32(samplingRate);
-        data.writeInt32(static_cast <uint32_t>(format));
-        data.writeInt32(channelMask);
-        data.writeInt32(static_cast <uint32_t>(flags));
-        // hasOffloadInfo
-        if (offloadInfo == NULL) {
-            data.writeInt32(0);
-        } else {
-            data.writeInt32(1);
-            data.write(offloadInfo, sizeof(audio_offload_info_t));
-        }
         remote()->transact(GET_OUTPUT, data, &reply);
         return static_cast <audio_io_handle_t> (reply.readInt32());
     }
@@ -934,22 +917,7 @@
             CHECK_INTERFACE(IAudioPolicyService, data, reply);
             audio_stream_type_t stream =
                     static_cast <audio_stream_type_t>(data.readInt32());
-            uint32_t samplingRate = data.readInt32();
-            audio_format_t format = (audio_format_t) data.readInt32();
-            audio_channel_mask_t channelMask = data.readInt32();
-            audio_output_flags_t flags =
-                    static_cast <audio_output_flags_t>(data.readInt32());
-            bool hasOffloadInfo = data.readInt32() != 0;
-            audio_offload_info_t offloadInfo;
-            if (hasOffloadInfo) {
-                data.read(&offloadInfo, sizeof(audio_offload_info_t));
-            }
-            audio_io_handle_t output = getOutput(stream,
-                                                 samplingRate,
-                                                 format,
-                                                 channelMask,
-                                                 flags,
-                                                 hasOffloadInfo ? &offloadInfo : NULL);
+            audio_io_handle_t output = getOutput(stream);
             reply->writeInt32(static_cast <int>(output));
             return NO_ERROR;
         } break;
diff --git a/media/libaudioclient/include/media/AudioSystem.h b/media/libaudioclient/include/media/AudioSystem.h
index 5a81d83..327eba8 100644
--- a/media/libaudioclient/include/media/AudioSystem.h
+++ b/media/libaudioclient/include/media/AudioSystem.h
@@ -211,12 +211,6 @@
 
     // Client must successfully hand off the handle reference to AudioFlinger via createTrack(),
     // or release it with releaseOutput().
-    static audio_io_handle_t getOutput(audio_stream_type_t stream,
-                                        uint32_t samplingRate = 0,
-                                        audio_format_t format = AUDIO_FORMAT_DEFAULT,
-                                        audio_channel_mask_t channelMask = AUDIO_CHANNEL_OUT_STEREO,
-                                        audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE,
-                                        const audio_offload_info_t *offloadInfo = NULL);
     static status_t getOutputForAttr(const audio_attributes_t *attr,
                                      audio_io_handle_t *output,
                                      audio_session_t session,
@@ -450,6 +444,7 @@
         Vector <sp <AudioPortCallback> >    mAudioPortCallbacks;
     };
 
+    static audio_io_handle_t getOutput(audio_stream_type_t stream);
     static const sp<AudioFlingerClient> getAudioFlingerClient();
     static sp<AudioIoDescriptor> getIoDescriptor(audio_io_handle_t ioHandle);
 
diff --git a/media/libaudioclient/include/media/AudioTrack.h b/media/libaudioclient/include/media/AudioTrack.h
index 2adacd7..8973133 100644
--- a/media/libaudioclient/include/media/AudioTrack.h
+++ b/media/libaudioclient/include/media/AudioTrack.h
@@ -218,6 +218,8 @@
      *                     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.
+     * selectedDeviceId:   Selected device id of the app which initially requested the AudioTrack
+     *                     to open with a specific device.
      * threadCanCallJava:  Not present in parameter list, and so is fixed at false.
      */
 
@@ -237,7 +239,8 @@
                                     pid_t pid = -1,
                                     const audio_attributes_t* pAttributes = NULL,
                                     bool doNotReconnect = false,
-                                    float maxRequiredSpeed = 1.0f);
+                                    float maxRequiredSpeed = 1.0f,
+                                    audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE);
 
     /* Creates an audio track and registers it with AudioFlinger.
      * With this constructor, the track is configured for static buffer mode.
@@ -313,7 +316,8 @@
                             pid_t pid = -1,
                             const audio_attributes_t* pAttributes = NULL,
                             bool doNotReconnect = false,
-                            float maxRequiredSpeed = 1.0f);
+                            float maxRequiredSpeed = 1.0f,
+                            audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE);
 
     /* Result of constructing the AudioTrack. This must be checked for successful initialization
      * before using any AudioTrack API (except for set()), because using
@@ -990,7 +994,7 @@
     sp<IAudioTrack>         mAudioTrack;
     sp<IMemory>             mCblkMemory;
     audio_track_cblk_t*     mCblk;                  // re-load after mLock.unlock()
-    audio_io_handle_t       mOutput;                // returned by AudioSystem::getOutput()
+    audio_io_handle_t       mOutput;                // returned by AudioSystem::getOutputForAttr()
 
     sp<AudioTrackThread>    mAudioTrackThread;
     bool                    mThreadCanCallJava;
diff --git a/media/libaudioclient/include/media/IAudioPolicyService.h b/media/libaudioclient/include/media/IAudioPolicyService.h
index 9b3e35e..7c88e57 100644
--- a/media/libaudioclient/include/media/IAudioPolicyService.h
+++ b/media/libaudioclient/include/media/IAudioPolicyService.h
@@ -55,12 +55,7 @@
     virtual status_t setForceUse(audio_policy_force_use_t usage,
                                     audio_policy_forced_cfg_t config) = 0;
     virtual audio_policy_forced_cfg_t getForceUse(audio_policy_force_use_t usage) = 0;
-    virtual audio_io_handle_t getOutput(audio_stream_type_t stream,
-                                        uint32_t samplingRate = 0,
-                                        audio_format_t format = AUDIO_FORMAT_DEFAULT,
-                                        audio_channel_mask_t channelMask = 0,
-                                        audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE,
-                                        const audio_offload_info_t *offloadInfo = NULL) = 0;
+    virtual audio_io_handle_t getOutput(audio_stream_type_t stream) = 0;
     virtual status_t getOutputForAttr(const audio_attributes_t *attr,
                                       audio_io_handle_t *output,
                                       audio_session_t session,
diff --git a/media/libaudiohal/Android.bp b/media/libaudiohal/Android.bp
new file mode 100644
index 0000000..700de8e
--- /dev/null
+++ b/media/libaudiohal/Android.bp
@@ -0,0 +1,47 @@
+cc_library_shared {
+    name: "libaudiohal",
+
+    srcs: [
+        "DeviceHalLocal.cpp",
+        "DevicesFactoryHalHybrid.cpp",
+        "DevicesFactoryHalLocal.cpp",
+        "StreamHalLocal.cpp",
+
+        "ConversionHelperHidl.cpp",
+        "HalDeathHandlerHidl.cpp",
+        "DeviceHalHidl.cpp",
+        "DevicesFactoryHalHidl.cpp",
+        "EffectBufferHalHidl.cpp",
+        "EffectHalHidl.cpp",
+        "EffectsFactoryHalHidl.cpp",
+        "StreamHalHidl.cpp",
+    ],
+
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
+    export_include_dirs: ["include"],
+
+    shared_libs: [
+        "libaudioutils",
+        "libcutils",
+        "liblog",
+        "libutils",
+        "libhardware",
+        "libbase",
+        "libfmq",
+        "libhwbinder",
+        "libhidlbase",
+        "libhidlmemory",
+        "libhidltransport",
+        "android.hardware.audio@2.0",
+        "android.hardware.audio.common@2.0",
+        "android.hardware.audio.common@2.0-util",
+        "android.hardware.audio.effect@2.0",
+        "android.hidl.allocator@1.0",
+        "android.hidl.memory@1.0",
+        "libmedia_helper",
+        "libmediautils",
+    ],
+}
diff --git a/media/libaudiohal/Android.mk b/media/libaudiohal/Android.mk
deleted file mode 100644
index 827908e..0000000
--- a/media/libaudiohal/Android.mk
+++ /dev/null
@@ -1,71 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_SHARED_LIBRARIES := \
-    libaudioutils \
-    libcutils   \
-    liblog      \
-    libutils    \
-    libhardware
-
-LOCAL_SRC_FILES := \
-    DeviceHalLocal.cpp          \
-    DevicesFactoryHalHybrid.cpp \
-    DevicesFactoryHalLocal.cpp  \
-    StreamHalLocal.cpp
-
-LOCAL_CFLAGS := -Wall -Werror
-
-ifeq ($(USE_LEGACY_LOCAL_AUDIO_HAL), true)
-
-# Use audiohal directly w/o hwbinder middleware.
-# This is for performance comparison and debugging only.
-
-LOCAL_SRC_FILES += \
-    EffectBufferHalLocal.cpp    \
-    EffectsFactoryHalLocal.cpp  \
-    EffectHalLocal.cpp
-
-LOCAL_SHARED_LIBRARIES += \
-    libeffects
-
-LOCAL_CFLAGS += -DUSE_LEGACY_LOCAL_AUDIO_HAL
-
-else  # if !USE_LEGACY_LOCAL_AUDIO_HAL
-
-LOCAL_SRC_FILES += \
-    ConversionHelperHidl.cpp   \
-    HalDeathHandlerHidl.cpp    \
-    DeviceHalHidl.cpp          \
-    DevicesFactoryHalHidl.cpp  \
-    EffectBufferHalHidl.cpp    \
-    EffectHalHidl.cpp          \
-    EffectsFactoryHalHidl.cpp  \
-    StreamHalHidl.cpp
-
-LOCAL_SHARED_LIBRARIES += \
-    libbase          \
-    libfmq           \
-    libhwbinder      \
-    libhidlbase      \
-    libhidlmemory    \
-    libhidltransport \
-    android.hardware.audio@2.0             \
-    android.hardware.audio.common@2.0      \
-    android.hardware.audio.common@2.0-util \
-    android.hardware.audio.effect@2.0      \
-    android.hidl.allocator@1.0             \
-    android.hidl.memory@1.0                \
-    libmedia_helper  \
-    libmediautils
-
-endif  # USE_LEGACY_LOCAL_AUDIO_HAL
-
-LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
-
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
-
-LOCAL_MODULE := libaudiohal
-
-include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libaudiohal/DevicesFactoryHalHybrid.cpp b/media/libaudiohal/DevicesFactoryHalHybrid.cpp
index 454b03b..8dc1434 100644
--- a/media/libaudiohal/DevicesFactoryHalHybrid.cpp
+++ b/media/libaudiohal/DevicesFactoryHalHybrid.cpp
@@ -19,9 +19,7 @@
 
 #include "DevicesFactoryHalHybrid.h"
 #include "DevicesFactoryHalLocal.h"
-#ifndef USE_LEGACY_LOCAL_AUDIO_HAL
 #include "DevicesFactoryHalHidl.h"
-#endif
 
 namespace android {
 
@@ -32,13 +30,7 @@
 
 DevicesFactoryHalHybrid::DevicesFactoryHalHybrid()
         : mLocalFactory(new DevicesFactoryHalLocal()),
-          mHidlFactory(
-#ifdef USE_LEGACY_LOCAL_AUDIO_HAL
-                  nullptr
-#else
-                  new DevicesFactoryHalHidl()
-#endif
-                       ) {
+          mHidlFactory(new DevicesFactoryHalHidl()) {
 }
 
 DevicesFactoryHalHybrid::~DevicesFactoryHalHybrid() {
diff --git a/media/libaudiohal/EffectBufferHalLocal.cpp b/media/libaudiohal/EffectBufferHalLocal.cpp
deleted file mode 100644
index 7951c8e..0000000
--- a/media/libaudiohal/EffectBufferHalLocal.cpp
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * 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.
- */
-
-#define LOG_TAG "EffectBufferHalLocal"
-//#define LOG_NDEBUG 0
-
-#include <utils/Log.h>
-
-#include "EffectBufferHalLocal.h"
-
-namespace android {
-
-// static
-status_t EffectBufferHalInterface::allocate(
-        size_t size, sp<EffectBufferHalInterface>* buffer) {
-    *buffer = new EffectBufferHalLocal(size);
-    return OK;
-}
-
-// static
-status_t EffectBufferHalInterface::mirror(
-        void* external, size_t size, sp<EffectBufferHalInterface>* buffer) {
-    *buffer = new EffectBufferHalLocal(external, size);
-    return OK;
-}
-
-EffectBufferHalLocal::EffectBufferHalLocal(size_t size)
-        : mOwnBuffer(new uint8_t[size]),
-          mBufferSize(size), mFrameCountChanged(false),
-          mAudioBuffer{0, {mOwnBuffer.get()}} {
-}
-
-EffectBufferHalLocal::EffectBufferHalLocal(void* external, size_t size)
-        : mOwnBuffer(nullptr),
-          mBufferSize(size), mFrameCountChanged(false),
-          mAudioBuffer{0, {external}} {
-}
-
-EffectBufferHalLocal::~EffectBufferHalLocal() {
-}
-
-audio_buffer_t* EffectBufferHalLocal::audioBuffer() {
-    return &mAudioBuffer;
-}
-
-void* EffectBufferHalLocal::externalData() const {
-    return mAudioBuffer.raw;
-}
-
-void EffectBufferHalLocal::setFrameCount(size_t frameCount) {
-    mAudioBuffer.frameCount = frameCount;
-    mFrameCountChanged = true;
-}
-
-void EffectBufferHalLocal::setExternalData(void* external) {
-    ALOGE_IF(mOwnBuffer != nullptr, "Attempt to set external data for allocated buffer");
-    mAudioBuffer.raw = external;
-}
-
-bool EffectBufferHalLocal::checkFrameCountChange() {
-    bool result = mFrameCountChanged;
-    mFrameCountChanged = false;
-    return result;
-}
-
-void EffectBufferHalLocal::update() {
-}
-
-void EffectBufferHalLocal::commit() {
-}
-
-void EffectBufferHalLocal::update(size_t) {
-}
-
-void EffectBufferHalLocal::commit(size_t) {
-}
-
-} // namespace android
diff --git a/media/libaudiohal/EffectBufferHalLocal.h b/media/libaudiohal/EffectBufferHalLocal.h
deleted file mode 100644
index d2b624b..0000000
--- a/media/libaudiohal/EffectBufferHalLocal.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef ANDROID_HARDWARE_EFFECT_BUFFER_HAL_LOCAL_H
-#define ANDROID_HARDWARE_EFFECT_BUFFER_HAL_LOCAL_H
-
-#include <memory>
-
-#include <media/audiohal/EffectBufferHalInterface.h>
-#include <system/audio_effect.h>
-
-namespace android {
-
-class EffectBufferHalLocal : public EffectBufferHalInterface
-{
-  public:
-    virtual audio_buffer_t* audioBuffer();
-    virtual void* externalData() const;
-
-    virtual void setExternalData(void* external);
-    virtual void setFrameCount(size_t frameCount);
-    virtual bool checkFrameCountChange();
-
-    virtual void update();
-    virtual void commit();
-    virtual void update(size_t size);
-    virtual void commit(size_t size);
-
-  private:
-    friend class EffectBufferHalInterface;
-
-    std::unique_ptr<uint8_t[]> mOwnBuffer;
-    const size_t mBufferSize;
-    bool mFrameCountChanged;
-    audio_buffer_t mAudioBuffer;
-
-    // Can not be constructed directly by clients.
-    explicit EffectBufferHalLocal(size_t size);
-    EffectBufferHalLocal(void* external, size_t size);
-
-    virtual ~EffectBufferHalLocal();
-
-    status_t init();
-};
-
-} // namespace android
-
-#endif // ANDROID_HARDWARE_EFFECT_BUFFER_HAL_LOCAL_H
diff --git a/media/libaudiohal/EffectHalLocal.cpp b/media/libaudiohal/EffectHalLocal.cpp
deleted file mode 100644
index dd465c3..0000000
--- a/media/libaudiohal/EffectHalLocal.cpp
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright (C) 2016 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 "EffectHalLocal"
-//#define LOG_NDEBUG 0
-
-#include <media/EffectsFactoryApi.h>
-#include <utils/Log.h>
-
-#include "EffectHalLocal.h"
-
-namespace android {
-
-EffectHalLocal::EffectHalLocal(effect_handle_t handle)
-        : mHandle(handle) {
-}
-
-EffectHalLocal::~EffectHalLocal() {
-    int status = EffectRelease(mHandle);
-    ALOGW_IF(status, "Error releasing effect %p: %s", mHandle, strerror(-status));
-    mHandle = 0;
-}
-
-status_t EffectHalLocal::setInBuffer(const sp<EffectBufferHalInterface>& buffer) {
-    mInBuffer = buffer;
-    return OK;
-}
-
-status_t EffectHalLocal::setOutBuffer(const sp<EffectBufferHalInterface>& buffer) {
-    mOutBuffer = buffer;
-    return OK;
-}
-
-status_t EffectHalLocal::process() {
-    if (mInBuffer == nullptr || mOutBuffer == nullptr) {
-        ALOGE_IF(mInBuffer == nullptr, "Input buffer not set");
-        ALOGE_IF(mOutBuffer == nullptr, "Output buffer not set");
-        return NO_INIT;
-    }
-    return (*mHandle)->process(mHandle, mInBuffer->audioBuffer(), mOutBuffer->audioBuffer());
-}
-
-status_t EffectHalLocal::processReverse() {
-    if ((*mHandle)->process_reverse != NULL) {
-        if (mInBuffer == nullptr || mOutBuffer == nullptr) {
-            ALOGE_IF(mInBuffer == nullptr, "Input buffer not set");
-            ALOGE_IF(mOutBuffer == nullptr, "Output buffer not set");
-            return NO_INIT;
-        }
-        return (*mHandle)->process_reverse(
-                mHandle, mInBuffer->audioBuffer(), mOutBuffer->audioBuffer());
-    } else {
-        return INVALID_OPERATION;
-    }
-}
-
-status_t EffectHalLocal::command(uint32_t cmdCode, uint32_t cmdSize, void *pCmdData,
-        uint32_t *replySize, void *pReplyData) {
-    return (*mHandle)->command(mHandle, cmdCode, cmdSize, pCmdData, replySize, pReplyData);
-}
-
-status_t EffectHalLocal::getDescriptor(effect_descriptor_t *pDescriptor) {
-    return (*mHandle)->get_descriptor(mHandle, pDescriptor);
-}
-
-status_t EffectHalLocal::close() {
-    return OK;
-}
-
-} // namespace android
diff --git a/media/libaudiohal/EffectHalLocal.h b/media/libaudiohal/EffectHalLocal.h
deleted file mode 100644
index 693fb50..0000000
--- a/media/libaudiohal/EffectHalLocal.h
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright (C) 2016 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_HARDWARE_EFFECT_HAL_LOCAL_H
-#define ANDROID_HARDWARE_EFFECT_HAL_LOCAL_H
-
-#include <hardware/audio_effect.h>
-#include <media/audiohal/EffectHalInterface.h>
-
-namespace android {
-
-class EffectHalLocal : public EffectHalInterface
-{
-  public:
-    // Set the input buffer.
-    virtual status_t setInBuffer(const sp<EffectBufferHalInterface>& buffer);
-
-    // Set the output buffer.
-    virtual status_t setOutBuffer(const sp<EffectBufferHalInterface>& buffer);
-
-    // Effect process function.
-    virtual status_t process();
-
-    // Process reverse stream function. This function is used to pass
-    // a reference stream to the effect engine.
-    virtual status_t processReverse();
-
-    // Send a command and receive a response to/from effect engine.
-    virtual status_t command(uint32_t cmdCode, uint32_t cmdSize, void *pCmdData,
-            uint32_t *replySize, void *pReplyData);
-
-    // Returns the effect descriptor.
-    virtual status_t getDescriptor(effect_descriptor_t *pDescriptor);
-
-    // Free resources on the remote side.
-    virtual status_t close();
-
-    // Whether it's a local implementation.
-    virtual bool isLocal() const { return true; }
-
-    effect_handle_t handle() const { return mHandle; }
-
-  private:
-    effect_handle_t mHandle;
-    sp<EffectBufferHalInterface> mInBuffer;
-    sp<EffectBufferHalInterface> mOutBuffer;
-
-    friend class EffectsFactoryHalLocal;
-
-    // Can not be constructed directly by clients.
-    explicit EffectHalLocal(effect_handle_t handle);
-
-    // The destructor automatically releases the effect.
-    virtual ~EffectHalLocal();
-};
-
-} // namespace android
-
-#endif // ANDROID_HARDWARE_EFFECT_HAL_LOCAL_H
diff --git a/media/libaudiohal/EffectsFactoryHalLocal.cpp b/media/libaudiohal/EffectsFactoryHalLocal.cpp
deleted file mode 100644
index bbdef5d..0000000
--- a/media/libaudiohal/EffectsFactoryHalLocal.cpp
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (C) 2016 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.
- */
-
-#include <media/EffectsFactoryApi.h>
-
-#include "EffectHalLocal.h"
-#include "EffectsFactoryHalLocal.h"
-
-namespace android {
-
-// static
-sp<EffectsFactoryHalInterface> EffectsFactoryHalInterface::create() {
-    return new EffectsFactoryHalLocal();
-}
-
-// static
-bool EffectsFactoryHalInterface::isNullUuid(const effect_uuid_t *pEffectUuid) {
-    return EffectIsNullUuid(pEffectUuid);
-}
-
-status_t EffectsFactoryHalLocal::queryNumberEffects(uint32_t *pNumEffects) {
-    return EffectQueryNumberEffects(pNumEffects);
-}
-
-status_t EffectsFactoryHalLocal::getDescriptor(
-        uint32_t index, effect_descriptor_t *pDescriptor) {
-    return EffectQueryEffect(index, pDescriptor);
-}
-
-status_t EffectsFactoryHalLocal::getDescriptor(
-        const effect_uuid_t *pEffectUuid, effect_descriptor_t *pDescriptor) {
-    return EffectGetDescriptor(pEffectUuid, pDescriptor);
-}
-
-status_t EffectsFactoryHalLocal::createEffect(
-        const effect_uuid_t *pEffectUuid, int32_t sessionId, int32_t ioId,
-        sp<EffectHalInterface> *effect) {
-    effect_handle_t handle;
-    int result = EffectCreate(pEffectUuid, sessionId, ioId, &handle);
-    if (result == 0) {
-        *effect = new EffectHalLocal(handle);
-    }
-    return result;
-}
-
-status_t EffectsFactoryHalLocal::dumpEffects(int fd) {
-    return EffectDumpEffects(fd);
-}
-
-} // namespace android
diff --git a/media/libaudiohal/EffectsFactoryHalLocal.h b/media/libaudiohal/EffectsFactoryHalLocal.h
deleted file mode 100644
index d5b81be..0000000
--- a/media/libaudiohal/EffectsFactoryHalLocal.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2016 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_HARDWARE_EFFECTS_FACTORY_HAL_LOCAL_H
-#define ANDROID_HARDWARE_EFFECTS_FACTORY_HAL_LOCAL_H
-
-#include <media/audiohal/EffectsFactoryHalInterface.h>
-
-namespace android {
-
-class EffectsFactoryHalLocal : public EffectsFactoryHalInterface
-{
-  public:
-    // Returns the number of different effects in all loaded libraries.
-    virtual status_t queryNumberEffects(uint32_t *pNumEffects);
-
-    // Returns a descriptor of the next available effect.
-    virtual status_t getDescriptor(uint32_t index,
-            effect_descriptor_t *pDescriptor);
-
-    virtual status_t getDescriptor(const effect_uuid_t *pEffectUuid,
-            effect_descriptor_t *pDescriptor);
-
-    // Creates an effect engine of the specified type.
-    // To release the effect engine, it is necessary to release references
-    // to the returned effect object.
-    virtual status_t createEffect(const effect_uuid_t *pEffectUuid,
-            int32_t sessionId, int32_t ioId,
-            sp<EffectHalInterface> *effect);
-
-    virtual status_t dumpEffects(int fd);
-
-  private:
-    friend class EffectsFactoryHalInterface;
-
-    // Can not be constructed directly by clients.
-    EffectsFactoryHalLocal() {}
-
-    virtual ~EffectsFactoryHalLocal() {}
-};
-
-} // namespace android
-
-#endif // ANDROID_HARDWARE_EFFECTS_FACTORY_HAL_LOCAL_H
diff --git a/media/libaudiohal/StreamHalLocal.cpp b/media/libaudiohal/StreamHalLocal.cpp
index dc17f5c..8d61e24 100644
--- a/media/libaudiohal/StreamHalLocal.cpp
+++ b/media/libaudiohal/StreamHalLocal.cpp
@@ -21,7 +21,6 @@
 #include <utils/Log.h>
 
 #include "DeviceHalLocal.h"
-#include "EffectHalLocal.h"
 #include "StreamHalLocal.h"
 
 namespace android {
@@ -86,16 +85,14 @@
     return OK;
 }
 
-status_t StreamHalLocal::addEffect(sp<EffectHalInterface> effect) {
-    LOG_ALWAYS_FATAL_IF(!effect->isLocal(), "Only local effects can be added for a local stream");
-    return mStream->add_audio_effect(mStream,
-            static_cast<EffectHalLocal*>(effect.get())->handle());
+status_t StreamHalLocal::addEffect(sp<EffectHalInterface>) {
+    LOG_ALWAYS_FATAL("Local streams can not have effects");
+    return INVALID_OPERATION;
 }
 
-status_t StreamHalLocal::removeEffect(sp<EffectHalInterface> effect) {
-    LOG_ALWAYS_FATAL_IF(!effect->isLocal(), "Only local effects can be removed for a local stream");
-    return mStream->remove_audio_effect(mStream,
-            static_cast<EffectHalLocal*>(effect.get())->handle());
+status_t StreamHalLocal::removeEffect(sp<EffectHalInterface>) {
+    LOG_ALWAYS_FATAL("Local streams can not have effects");
+    return INVALID_OPERATION;
 }
 
 status_t StreamHalLocal::standby() {
diff --git a/media/libaudioprocessing/AudioResamplerDyn.cpp b/media/libaudioprocessing/AudioResamplerDyn.cpp
index 8f7b982..eeeecce 100644
--- a/media/libaudioprocessing/AudioResamplerDyn.cpp
+++ b/media/libaudioprocessing/AudioResamplerDyn.cpp
@@ -38,6 +38,9 @@
 
 //#define DEBUG_RESAMPLER
 
+// use this for our buffer alignment.  Should be at least 32 bytes.
+constexpr size_t CACHE_LINE_SIZE = 64;
+
 namespace android {
 
 /*
@@ -94,7 +97,10 @@
 
     // create new buffer
     TI* state = NULL;
-    (void)posix_memalign(reinterpret_cast<void**>(&state), 32, stateCount*sizeof(*state));
+    (void)posix_memalign(
+            reinterpret_cast<void **>(&state),
+            CACHE_LINE_SIZE /* alignment */,
+            stateCount * sizeof(*state));
     memset(state, 0, stateCount*sizeof(*state));
 
     // attempt to preserve state
@@ -185,6 +191,16 @@
     // setSampleRate() for 1:1. (May be removed if precalculated filters are used.)
     mInSampleRate = 0;
     mConstants.set(128, 8, mSampleRate, mSampleRate); // TODO: set better
+
+    // fetch property based resampling parameters
+    mPropertyEnableAtSampleRate = property_get_int32(
+            "ro.audio.resampler.psd.enable_at_samplerate", mPropertyEnableAtSampleRate);
+    mPropertyHalfFilterLength = property_get_int32(
+            "ro.audio.resampler.psd.halflength", mPropertyHalfFilterLength);
+    mPropertyStopbandAttenuation = property_get_int32(
+            "ro.audio.resampler.psd.stopband", mPropertyStopbandAttenuation);
+    mPropertyCutoffPercent = property_get_int32(
+            "ro.audio.resampler.psd.cutoff_percent", mPropertyCutoffPercent);
 }
 
 template<typename TC, typename TI, typename TO>
@@ -215,6 +231,8 @@
     }
 }
 
+// TODO: update to C++11
+
 template<typename T> T max(T a, T b) {return a > b ? a : b;}
 
 template<typename T> T absdiff(T a, T b) {return a > b ? a - b : b - a;}
@@ -223,37 +241,74 @@
 void AudioResamplerDyn<TC, TI, TO>::createKaiserFir(Constants &c,
         double stopBandAtten, int inSampleRate, int outSampleRate, double tbwCheat)
 {
-    TC* buf = NULL;
-    static const double atten = 0.9998;   // to avoid ripple overflow
-    double fcr;
-    double tbw = firKaiserTbw(c.mHalfNumCoefs, stopBandAtten);
+    // compute the normalized transition bandwidth
+    const double tbw = firKaiserTbw(c.mHalfNumCoefs, stopBandAtten);
+    const double halfbw = tbw / 2.;
 
-    (void)posix_memalign(reinterpret_cast<void**>(&buf), 32, (c.mL+1)*c.mHalfNumCoefs*sizeof(TC));
+    double fcr; // compute fcr, the 3 dB amplitude cut-off.
     if (inSampleRate < outSampleRate) { // upsample
-        fcr = max(0.5*tbwCheat - tbw/2, tbw/2);
+        fcr = max(0.5 * tbwCheat - halfbw, halfbw);
     } else { // downsample
-        fcr = max(0.5*tbwCheat*outSampleRate/inSampleRate - tbw/2, tbw/2);
+        fcr = max(0.5 * tbwCheat * outSampleRate / inSampleRate - halfbw, halfbw);
     }
-    // create and set filter
-    firKaiserGen(buf, c.mL, c.mHalfNumCoefs, stopBandAtten, fcr, atten);
-    c.mFirCoefs = buf;
-    if (mCoefBuffer) {
-        free(mCoefBuffer);
-    }
-    mCoefBuffer = buf;
-#ifdef DEBUG_RESAMPLER
+    createKaiserFir(c, stopBandAtten, fcr);
+}
+
+template<typename TC, typename TI, typename TO>
+void AudioResamplerDyn<TC, TI, TO>::createKaiserFir(Constants &c,
+        double stopBandAtten, double fcr) {
+    // compute the normalized transition bandwidth
+    const double tbw = firKaiserTbw(c.mHalfNumCoefs, stopBandAtten);
+    const int phases = c.mL;
+    const int halfLength = c.mHalfNumCoefs;
+
+    // create buffer
+    TC *coefs = nullptr;
+    int ret = posix_memalign(
+            reinterpret_cast<void **>(&coefs),
+            CACHE_LINE_SIZE /* alignment */,
+            (phases + 1) * halfLength * sizeof(TC));
+    LOG_ALWAYS_FATAL_IF(ret != 0, "Cannot allocate buffer memory, ret %d", ret);
+    c.mFirCoefs = coefs;
+    free(mCoefBuffer);
+    mCoefBuffer = coefs;
+
+    // square the computed minimum passband value (extra safety).
+    double attenuation =
+            computeWindowedSincMinimumPassbandValue(stopBandAtten);
+    attenuation *= attenuation;
+
+    // design filter
+    firKaiserGen(coefs, phases, halfLength, stopBandAtten, fcr, attenuation);
+
+    // update the design criteria
+    mNormalizedCutoffFrequency = fcr;
+    mNormalizedTransitionBandwidth = tbw;
+    mFilterAttenuation = attenuation;
+    mStopbandAttenuationDb = stopBandAtten;
+    mPassbandRippleDb = computeWindowedSincPassbandRippleDb(stopBandAtten);
+
+#if 0
+    // Keep this debug code in case an app causes resampler design issues.
+    const double halfbw = tbw / 2.;
     // print basic filter stats
-    printf("L:%d  hnc:%d  stopBandAtten:%lf  fcr:%lf  atten:%lf  tbw:%lf\n",
-            c.mL, c.mHalfNumCoefs, stopBandAtten, fcr, atten, tbw);
-    // test the filter and report results
-    double fp = (fcr - tbw/2)/c.mL;
-    double fs = (fcr + tbw/2)/c.mL;
+    ALOGD("L:%d  hnc:%d  stopBandAtten:%lf  fcr:%lf  atten:%lf  tbw:%lf\n",
+            c.mL, c.mHalfNumCoefs, stopBandAtten, fcr, attenuation, tbw);
+
+    // test the filter and report results.
+    // Since this is a polyphase filter, normalized fp and fs must be scaled.
+    const double fp = (fcr - halfbw) / phases;
+    const double fs = (fcr + halfbw) / phases;
+
     double passMin, passMax, passRipple;
     double stopMax, stopRipple;
-    testFir(buf, c.mL, c.mHalfNumCoefs, fp, fs, /*passSteps*/ 1000, /*stopSteps*/ 100000,
+
+    const int32_t passSteps = 1000;
+
+    testFir(coefs, c.mL, c.mHalfNumCoefs, fp, fs, passSteps, passSteps * c.ML /*stopSteps*/,
             passMin, passMax, passRipple, stopMax, stopRipple);
-    printf("passband(%lf, %lf): %.8lf %.8lf %.8lf\n", 0., fp, passMin, passMax, passRipple);
-    printf("stopband(%lf, %lf): %.8lf %.3lf\n", fs, 0.5, stopMax, stopRipple);
+    ALOGD("passband(%lf, %lf): %.8lf %.8lf %.8lf\n", 0., fp, passMin, passMax, passRipple);
+    ALOGD("stopband(%lf, %lf): %.8lf %.3lf\n", fs, 0.5, stopMax, stopRipple);
 #endif
 }
 
@@ -304,6 +359,11 @@
         mFilterSampleRate = inSampleRate;
         mFilterQuality = getQuality();
 
+        double stopBandAtten;
+        double tbwCheat = 1.; // how much we "cheat" into aliasing
+        int halfLength;
+        double fcr = 0.;
+
         // Begin Kaiser Filter computation
         //
         // The quantization floor for S16 is about 96db - 10*log_10(#length) + 3dB.
@@ -313,52 +373,60 @@
         // 96-98dB
         //
 
-        double stopBandAtten;
-        double tbwCheat = 1.; // how much we "cheat" into aliasing
-        int halfLength;
-        if (mFilterQuality == DYN_HIGH_QUALITY) {
-            // 32b coefficients, 64 length
+        if (mPropertyEnableAtSampleRate >= 0 && mSampleRate >= mPropertyEnableAtSampleRate) {
+            // An alternative method which allows allows a greater fcr
+            // at the expense of potential aliasing.
+            halfLength = mPropertyHalfFilterLength;
+            stopBandAtten = mPropertyStopbandAttenuation;
             useS32 = true;
-            stopBandAtten = 98.;
-            if (inSampleRate >= mSampleRate * 4) {
-                halfLength = 48;
-            } else if (inSampleRate >= mSampleRate * 2) {
-                halfLength = 40;
-            } else {
-                halfLength = 32;
-            }
-        } else if (mFilterQuality == DYN_LOW_QUALITY) {
-            // 16b coefficients, 16-32 length
-            useS32 = false;
-            stopBandAtten = 80.;
-            if (inSampleRate >= mSampleRate * 4) {
-                halfLength = 24;
-            } else if (inSampleRate >= mSampleRate * 2) {
-                halfLength = 16;
-            } else {
-                halfLength = 8;
-            }
-            if (inSampleRate <= mSampleRate) {
-                tbwCheat = 1.05;
-            } else {
-                tbwCheat = 1.03;
-            }
-        } else { // DYN_MED_QUALITY
-            // 16b coefficients, 32-64 length
-            // note: > 64 length filters with 16b coefs can have quantization noise problems
-            useS32 = false;
-            stopBandAtten = 84.;
-            if (inSampleRate >= mSampleRate * 4) {
-                halfLength = 32;
-            } else if (inSampleRate >= mSampleRate * 2) {
-                halfLength = 24;
-            } else {
-                halfLength = 16;
-            }
-            if (inSampleRate <= mSampleRate) {
-                tbwCheat = 1.03;
-            } else {
-                tbwCheat = 1.01;
+            fcr = mInSampleRate <= mSampleRate
+                    ? 0.5 : 0.5 * mSampleRate / mInSampleRate;
+            fcr *= mPropertyCutoffPercent / 100.;
+        } else {
+            if (mFilterQuality == DYN_HIGH_QUALITY) {
+                // 32b coefficients, 64 length
+                useS32 = true;
+                stopBandAtten = 98.;
+                if (inSampleRate >= mSampleRate * 4) {
+                    halfLength = 48;
+                } else if (inSampleRate >= mSampleRate * 2) {
+                    halfLength = 40;
+                } else {
+                    halfLength = 32;
+                }
+            } else if (mFilterQuality == DYN_LOW_QUALITY) {
+                // 16b coefficients, 16-32 length
+                useS32 = false;
+                stopBandAtten = 80.;
+                if (inSampleRate >= mSampleRate * 4) {
+                    halfLength = 24;
+                } else if (inSampleRate >= mSampleRate * 2) {
+                    halfLength = 16;
+                } else {
+                    halfLength = 8;
+                }
+                if (inSampleRate <= mSampleRate) {
+                    tbwCheat = 1.05;
+                } else {
+                    tbwCheat = 1.03;
+                }
+            } else { // DYN_MED_QUALITY
+                // 16b coefficients, 32-64 length
+                // note: > 64 length filters with 16b coefs can have quantization noise problems
+                useS32 = false;
+                stopBandAtten = 84.;
+                if (inSampleRate >= mSampleRate * 4) {
+                    halfLength = 32;
+                } else if (inSampleRate >= mSampleRate * 2) {
+                    halfLength = 24;
+                } else {
+                    halfLength = 16;
+                }
+                if (inSampleRate <= mSampleRate) {
+                    tbwCheat = 1.03;
+                } else {
+                    tbwCheat = 1.01;
+                }
             }
         }
 
@@ -390,8 +458,12 @@
 
         // create the filter
         mConstants.set(phases, halfLength, inSampleRate, mSampleRate);
-        createKaiserFir(mConstants, stopBandAtten,
-                inSampleRate, mSampleRate, tbwCheat);
+        if (fcr > 0.) {
+            createKaiserFir(mConstants, stopBandAtten, fcr);
+        } else {
+            createKaiserFir(mConstants, stopBandAtten,
+                    inSampleRate, mSampleRate, tbwCheat);
+        }
     } // End Kaiser filter
 
     // update phase and state based on the new filter.
diff --git a/media/libaudioprocessing/AudioResamplerDyn.h b/media/libaudioprocessing/AudioResamplerDyn.h
index 1840fc7..92144d0 100644
--- a/media/libaudioprocessing/AudioResamplerDyn.h
+++ b/media/libaudioprocessing/AudioResamplerDyn.h
@@ -55,6 +55,39 @@
     virtual size_t resample(int32_t* out, size_t outFrameCount,
             AudioBufferProvider* provider);
 
+    // Make available key design criteria for testing
+    int getHalfLength() const {
+        return mConstants.mHalfNumCoefs;
+    }
+
+    const TC *getFilterCoefs() const {
+        return mConstants.mFirCoefs;
+    }
+
+    int getPhases() const {
+        return mConstants.mL;
+    }
+
+    double getStopbandAttenuationDb() const {
+        return mStopbandAttenuationDb;
+    }
+
+    double getPassbandRippleDb() const {
+        return mPassbandRippleDb;
+    }
+
+    double getNormalizedTransitionBandwidth() const {
+        return mNormalizedTransitionBandwidth;
+    }
+
+    double getFilterAttenuation() const {
+        return mFilterAttenuation;
+    }
+
+    double getNormalizedCutoffFrequency() const {
+        return mNormalizedCutoffFrequency;
+    }
+
 private:
 
     class Constants { // stores the filter constants.
@@ -112,6 +145,8 @@
     void createKaiserFir(Constants &c, double stopBandAtten,
             int inSampleRate, int outSampleRate, double tbwCheat);
 
+    void createKaiserFir(Constants &c, double stopBandAtten, double fcr);
+
     template<int CHANNELS, bool LOCKED, int STRIDE>
     size_t resample(TO* out, size_t outFrameCount, AudioBufferProvider* provider);
 
@@ -127,6 +162,38 @@
             int32_t mFilterSampleRate; // designed filter sample rate.
         src_quality mFilterQuality;    // designed filter quality.
               void* mCoefBuffer;       // if a filter is created, this is not null
+
+    // Property selected design parameters.
+              // This will enable fixed high quality resampling.
+
+              // 32 char PROP_NAME_MAX limit enforced before Android O
+
+              // Use for sample rates greater than or equal to this value.
+              // Set to non-negative to enable, negative to disable.
+              int32_t mPropertyEnableAtSampleRate = 48000;
+                      // "ro.audio.resampler.psd.enable_at_samplerate"
+
+              // Specify HALF the resampling filter length.
+              // Set to a value which is a multiple of 4.
+              int32_t mPropertyHalfFilterLength = 32;
+                      // "ro.audio.resampler.psd.halflength"
+
+              // Specify the stopband attenuation in positive dB.
+              // Set to a value greater or equal to 20.
+              int32_t mPropertyStopbandAttenuation = 90;
+                      // "ro.audio.resampler.psd.stopband"
+
+              // Specify the cutoff frequency as a percentage of Nyquist.
+              // Set to a value between 50 and 100.
+              int32_t mPropertyCutoffPercent = 100;
+                      // "ro.audio.resampler.psd.cutoff_percent"
+
+    // Filter creation design parameters, see setSampleRate()
+             double mStopbandAttenuationDb = 0.;
+             double mPassbandRippleDb = 0.;
+             double mNormalizedTransitionBandwidth = 0.;
+             double mFilterAttenuation = 0.;
+             double mNormalizedCutoffFrequency = 0.;
 };
 
 } // namespace android
diff --git a/media/libaudioprocessing/AudioResamplerFirGen.h b/media/libaudioprocessing/AudioResamplerFirGen.h
index ad18965..39cafeb 100644
--- a/media/libaudioprocessing/AudioResamplerFirGen.h
+++ b/media/libaudioprocessing/AudioResamplerFirGen.h
@@ -546,8 +546,9 @@
         }
         wstart += wstep;
     }
-    // renormalize - this is only needed for integer filter types
-    double norm = 1./((1ULL<<(sizeof(T)*8-1))*L);
+    // renormalize - this is needed for integer filter types, use 1 for float or double.
+    constexpr int64_t integralShift = std::is_integral<T>::value ? (sizeof(T) * 8 - 1) : 0;
+    const double norm = 1. / (L << integralShift);
 
     firMin = fmin * norm;
     firMax = fmax * norm;
@@ -557,9 +558,12 @@
  * evaluates the |H(f)| lowpass band characteristics.
  *
  * This function tests the lowpass characteristics for the overall polyphase filter,
- * and is used to verify the design.  For this case, fp should be set to the
+ * and is used to verify the design.
+ *
+ * For a polyphase filter (L > 1), typically fp should be set to the
  * passband normalized frequency from 0 to 0.5 for the overall filter (thus it
  * is the designed polyphase bank value / L).  Likewise for fs.
+ * Similarly the stopSteps should be L * passSteps for equivalent accuracy.
  *
  * @param coef is the designed polyphase filter banks
  *
@@ -610,6 +614,74 @@
 }
 
 /*
+ * Estimate the windowed sinc minimum passband value.
+ *
+ * This is the minimum value for a windowed sinc filter in its passband,
+ * which is identical to the scaling required not to cause overflow of a 0dBFS signal.
+ * The actual value used to attenuate the filter amplitude should be slightly
+ * smaller than this (suggest squaring) as this is just an estimate.
+ *
+ * As a windowed sinc has a passband ripple commensurate to the stopband attenuation
+ * due to Gibb's phenomenon from truncating the sinc, we derive this value from
+ * the design stopbandAttenuationDb (a positive value).
+ */
+static inline double computeWindowedSincMinimumPassbandValue(
+        double stopBandAttenuationDb) {
+    return 1. - pow(10. /* base */, stopBandAttenuationDb * (-1. / 20.));
+}
+
+/*
+ * Compute the windowed sinc passband ripple from stopband attenuation.
+ *
+ * As a windowed sinc has an passband ripple commensurate to the stopband attenuation
+ * due to Gibb's phenomenon from truncating the sinc, we derive this value from
+ * the design stopbandAttenuationDb (a positive value).
+ */
+static inline double computeWindowedSincPassbandRippleDb(
+        double stopBandAttenuationDb) {
+    return -20. * log10(computeWindowedSincMinimumPassbandValue(stopBandAttenuationDb));
+}
+
+/*
+ * Kaiser window Beta value
+ *
+ * Formula 3.2.5, 3.2.7, Vaidyanathan, _Multirate Systems and Filter Banks_, p. 48
+ * Formula 7.75, Oppenheim and Schafer, _Discrete-time Signal Processing, 3e_, p. 542
+ *
+ * See also: http://melodi.ee.washington.edu/courses/ee518/notes/lec17.pdf
+ *
+ * Kaiser window and beta parameter
+ *
+ *         | 0.1102*(A - 8.7)                         A > 50
+ *  Beta = | 0.5842*(A - 21)^0.4 + 0.07886*(A - 21)   21 < A <= 50
+ *         | 0.                                       A <= 21
+ *
+ * with A is the desired stop-band attenuation in positive dBFS
+ *
+ *    30 dB    2.210
+ *    40 dB    3.384
+ *    50 dB    4.538
+ *    60 dB    5.658
+ *    70 dB    6.764
+ *    80 dB    7.865
+ *    90 dB    8.960
+ *   100 dB   10.056
+ *
+ * For some values of stopBandAttenuationDb the function may be computed
+ * at compile time.
+ */
+static inline constexpr double computeBeta(double stopBandAttenuationDb) {
+    if (stopBandAttenuationDb > 50.) {
+        return 0.1102 * (stopBandAttenuationDb - 8.7);
+    }
+    const double offset = stopBandAttenuationDb - 21.;
+    if (offset > 0.) {
+        return 0.5842 * pow(offset, 0.4) + 0.07886 * offset;
+    }
+    return 0.;
+}
+
+/*
  * Calculates the overall polyphase filter based on a windowed sinc function.
  *
  * The windowed sinc is an odd length symmetric filter of exactly L*halfNumCoef*2+1
@@ -642,31 +714,8 @@
 template <typename T>
 static inline void firKaiserGen(T* coef, int L, int halfNumCoef,
         double stopBandAtten, double fcr, double atten) {
-    //
-    // Formula 3.2.5, 3.2.7, Vaidyanathan, _Multirate Systems and Filter Banks_, p. 48
-    // Formula 7.75, Oppenheim and Schafer, _Discrete-time Signal Processing, 3e_, p. 542
-    //
-    // See also: http://melodi.ee.washington.edu/courses/ee518/notes/lec17.pdf
-    //
-    // Kaiser window and beta parameter
-    //
-    //         | 0.1102*(A - 8.7)                         A > 50
-    //  beta = | 0.5842*(A - 21)^0.4 + 0.07886*(A - 21)   21 <= A <= 50
-    //         | 0.                                       A < 21
-    //
-    // with A is the desired stop-band attenuation in dBFS
-    //
-    //    30 dB    2.210
-    //    40 dB    3.384
-    //    50 dB    4.538
-    //    60 dB    5.658
-    //    70 dB    6.764
-    //    80 dB    7.865
-    //    90 dB    8.960
-    //   100 dB   10.056
-
     const int N = L * halfNumCoef; // non-negative half
-    const double beta = 0.1102 * (stopBandAtten - 8.7); // >= 50dB always
+    const double beta = computeBeta(stopBandAtten);
     const double xstep = (2. * M_PI) * fcr / L;
     const double xfrac = 1. / N;
     const double yscale = atten * L / (I0(beta) * M_PI);
@@ -696,9 +745,9 @@
                 sg.advance();
             }
 
-            if (is_same<T, int16_t>::value) { // int16_t needs noise shaping
+            if (std::is_same<T, int16_t>::value) { // int16_t needs noise shaping
                 *coef++ = static_cast<T>(toint(y, 1ULL<<(sizeof(T)*8-1), err));
-            } else if (is_same<T, int32_t>::value) {
+            } else if (std::is_same<T, int32_t>::value) {
                 *coef++ = static_cast<T>(toint(y, 1ULL<<(sizeof(T)*8-1)));
             } else { // assumed float or double
                 *coef++ = static_cast<T>(y);
diff --git a/media/libaudioprocessing/tests/build_and_run_all_unit_tests.sh b/media/libaudioprocessing/tests/build_and_run_all_unit_tests.sh
index 704d095..efef417 100755
--- a/media/libaudioprocessing/tests/build_and_run_all_unit_tests.sh
+++ b/media/libaudioprocessing/tests/build_and_run_all_unit_tests.sh
@@ -14,8 +14,8 @@
 
 echo "waiting for device"
 adb root && adb wait-for-device remount
-adb push $OUT/system/lib/libaudioresampler.so /system/lib
-adb push $OUT/system/lib64/libaudioresampler.so /system/lib64
+adb push $OUT/system/lib/libaudioprocessing.so /system/lib
+adb push $OUT/system/lib64/libaudioprocessing.so /system/lib64
 adb push $OUT/data/nativetest/resampler_tests/resampler_tests /data/nativetest/resampler_tests/resampler_tests
 adb push $OUT/data/nativetest64/resampler_tests/resampler_tests /data/nativetest64/resampler_tests/resampler_tests
 
diff --git a/media/libaudioprocessing/tests/resampler_tests.cpp b/media/libaudioprocessing/tests/resampler_tests.cpp
index a23c000..e1623f7 100644
--- a/media/libaudioprocessing/tests/resampler_tests.cpp
+++ b/media/libaudioprocessing/tests/resampler_tests.cpp
@@ -29,6 +29,7 @@
 #include <unistd.h>
 
 #include <iostream>
+#include <memory>
 #include <utility>
 #include <vector>
 
@@ -37,6 +38,8 @@
 #include <media/AudioBufferProvider.h>
 
 #include <media/AudioResampler.h>
+#include "../AudioResamplerDyn.h"
+#include "../AudioResamplerFirGen.h"
 #include "test_utils.h"
 
 template <typename T>
@@ -242,6 +245,60 @@
     delete resampler;
 }
 
+void testFilterResponse(
+        size_t channels, unsigned inputFreq, unsigned outputFreq)
+{
+    // create resampler
+    using ResamplerType = android::AudioResamplerDyn<float, float, float>;
+    std::unique_ptr<ResamplerType> rdyn(
+            static_cast<ResamplerType *>(
+                    android::AudioResampler::create(
+                            AUDIO_FORMAT_PCM_FLOAT,
+                            channels,
+                            outputFreq,
+                            android::AudioResampler::DYN_HIGH_QUALITY)));
+    rdyn->setSampleRate(inputFreq);
+
+    // get design parameters
+    const int phases = rdyn->getPhases();
+    const int halfLength = rdyn->getHalfLength();
+    const float *coefs = rdyn->getFilterCoefs();
+    const double fcr = rdyn->getNormalizedCutoffFrequency();
+    const double tbw = rdyn->getNormalizedTransitionBandwidth();
+    const double attenuation = rdyn->getFilterAttenuation();
+    const double stopbandDb = rdyn->getStopbandAttenuationDb();
+    const double passbandDb = rdyn->getPassbandRippleDb();
+    const double fp = fcr - tbw / 2;
+    const double fs = fcr + tbw / 2;
+
+    printf("inputFreq:%d outputFreq:%d design"
+            " phases:%d halfLength:%d"
+            " fcr:%lf fp:%lf fs:%lf tbw:%lf"
+            " attenuation:%lf stopRipple:%.lf passRipple:%lf"
+            "\n",
+            inputFreq, outputFreq,
+            phases, halfLength,
+            fcr, fp, fs, tbw,
+            attenuation, stopbandDb, passbandDb);
+
+    // verify design parameters
+    constexpr int32_t passSteps = 1000;
+    double passMin, passMax, passRipple, stopMax, stopRipple;
+    android::testFir(coefs, phases, halfLength, fp / phases, fs / phases,
+            passSteps, phases * passSteps /* stopSteps */,
+            passMin, passMax, passRipple,
+            stopMax, stopRipple);
+    printf("inputFreq:%d outputFreq:%d verify"
+            " passMin:%lf passMax:%lf passRipple:%lf stopMax:%lf stopRipple:%lf"
+            "\n",
+            inputFreq, outputFreq,
+            passMin, passMax, passRipple, stopMax, stopRipple);
+
+    ASSERT_GT(stopRipple, 60.);  // enough stopband attenuation
+    ASSERT_LT(passRipple, 0.2);  // small passband ripple
+    ASSERT_GT(passMin, 0.99);    // we do not attenuate the signal (ideally 1.)
+}
+
 /* Buffer increment test
  *
  * We compare a reference output, where we consume and process the entire
@@ -484,3 +541,30 @@
     }
 }
 
+TEST(audioflinger_resampler, filterresponse) {
+    std::vector<int> inSampleRates{
+        8000,
+        11025,
+        12000,
+        16000,
+        22050,
+        24000,
+        32000,
+        44100,
+        48000,
+        88200,
+        96000,
+        176400,
+        192000,
+    };
+    std::vector<int> outSampleRates{
+        48000,
+        96000,
+    };
+
+    for (int outSampleRate : outSampleRates) {
+        for (int inSampleRate : inSampleRates) {
+            testFilterResponse(2 /* channels */, inSampleRate, outSampleRate);
+        }
+    }
+}
diff --git a/media/libeffects/config/include/media/EffectsConfig.h b/media/libeffects/config/include/media/EffectsConfig.h
index 811730c..55b946f 100644
--- a/media/libeffects/config/include/media/EffectsConfig.h
+++ b/media/libeffects/config/include/media/EffectsConfig.h
@@ -32,8 +32,13 @@
 namespace android {
 namespace effectsConfig {
 
-/** Default path of effect configuration file. */
-constexpr char DEFAULT_PATH[] = "/vendor/etc/audio_effects.xml";
+/** Default path of effect configuration file. Relative to DEFAULT_LOCATIONS. */
+constexpr const char* DEFAULT_NAME = "audio_effects.xml";
+
+/** Default path of effect configuration file.
+ * The /vendor partition is the recommended one, the others are deprecated.
+ */
+constexpr const char* DEFAULT_LOCATIONS[] = {"/odm/etc", "/vendor/etc", "/system/etc"};
 
 /** Directories where the effect libraries will be search for. */
 constexpr const char* LD_EFFECT_LIBRARY_PATH[] =
@@ -91,13 +96,16 @@
     /** Parsed config, nullptr if the xml lib could not load the file */
     std::unique_ptr<Config> parsedConfig;
     size_t nbSkippedElement; //< Number of skipped invalid library, effect or processing chain
+    const char* configPath; //< Path to the loaded configuration
 };
 
 /** Parses the provided effect configuration.
  * Parsing do not stop of first invalid element, but continues to the next.
+ * @param[in] path of the configuration file do load
+ *                 if nullptr, look for DEFAULT_NAME in DEFAULT_LOCATIONS.
  * @see ParsingResult::nbSkippedElement
  */
-ParsingResult parse(const char* path = DEFAULT_PATH);
+ParsingResult parse(const char* path = nullptr);
 
 } // namespace effectsConfig
 } // namespace android
diff --git a/media/libeffects/config/src/EffectsConfig.cpp b/media/libeffects/config/src/EffectsConfig.cpp
index 97462f8..18c406d 100644
--- a/media/libeffects/config/src/EffectsConfig.cpp
+++ b/media/libeffects/config/src/EffectsConfig.cpp
@@ -20,6 +20,7 @@
 #include <cstdint>
 #include <functional>
 #include <string>
+#include <unistd.h>
 
 #include <tinyxml2.h>
 #include <log/log.h>
@@ -85,7 +86,7 @@
 constexpr std::enable_if<false, Enum> STREAM_NAME_MAP;
 
 /** All output stream types which support effects.
- * This need to be kept in sink with the xsd streamOutputType.
+ * This need to be kept in sync with the xsd streamOutputType.
  */
 template <>
 constexpr std::pair<audio_stream_type_t, const char*> STREAM_NAME_MAP<audio_stream_type_t>[] = {
@@ -102,7 +103,7 @@
 };
 
 /** All input stream types which support effects.
- * This need to be kept in sink with the xsd streamOutputType.
+ * This need to be kept in sync with the xsd streamOutputType.
  */
 template <>
 constexpr std::pair<audio_source_t, const char*> STREAM_NAME_MAP<audio_source_t>[] = {
@@ -142,7 +143,7 @@
 }
 
 /** Find an element in a collection by its name.
- * @return nullptr if not found, the ellements address if found.
+ * @return nullptr if not found, the element address if found.
  */
 template <class T>
 T* findByName(const char* name, std::vector<T>& collection) {
@@ -249,15 +250,14 @@
     return true;
 }
 
-}; // namespace
-
-ParsingResult parse(const char* path) {
+/** Internal version of the public parse(const char* path) with precondition `path != nullptr`. */
+ParsingResult parseWithPath(const char* path) {
     XMLDocument doc;
     doc.LoadFile(path);
     if (doc.Error()) {
         ALOGE("Failed to parse %s: Tinyxml2 error (%d): %s %s", path,
               doc.ErrorID(), doc.GetErrorStr1(), doc.GetErrorStr2());
-        return {nullptr, 0};
+        return {nullptr, 0, path};
     }
 
     auto config = std::make_unique<Config>();
@@ -295,7 +295,29 @@
             }
         }
     }
-    return {std::move(config), nbSkippedElements};
+    return {std::move(config), nbSkippedElements, path};
+}
+
+}; // namespace
+
+ParsingResult parse(const char* path) {
+    if (path != nullptr) {
+        return parseWithPath(path);
+    }
+
+    for (std::string location : DEFAULT_LOCATIONS) {
+        std::string defaultPath = location + '/' + DEFAULT_NAME;
+        if (access(defaultPath.c_str(), R_OK) != 0) {
+            continue;
+        }
+        auto result = parseWithPath(defaultPath.c_str());
+        if (result.parsedConfig != nullptr) {
+            return result;
+        }
+    }
+
+    ALOGE("Could not parse effect configuration in any of the default locations.");
+    return {nullptr, 0, nullptr};
 }
 
 } // namespace effectsConfig
diff --git a/media/libeffects/factory/EffectsXmlConfigLoader.cpp b/media/libeffects/factory/EffectsXmlConfigLoader.cpp
index 438b787..7a7d431 100644
--- a/media/libeffects/factory/EffectsXmlConfigLoader.cpp
+++ b/media/libeffects/factory/EffectsXmlConfigLoader.cpp
@@ -327,7 +327,7 @@
                                            &gSkippedEffects, &gSubEffectList);
 
     ALOGE_IF(result.nbSkippedElement != 0, "%zu errors during loading of configuration: %s",
-             result.nbSkippedElement, path ?: effectsConfig::DEFAULT_PATH);
+             result.nbSkippedElement, result.configPath ?: "No config file found");
 
     return result.nbSkippedElement;
 }
diff --git a/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp b/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp
index ee9406d..3d8e982 100644
--- a/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp
+++ b/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp
@@ -1889,6 +1889,10 @@
         if (param != REVERB_PARAM_PRESET) {
             return -EINVAL;
         }
+        if (vsize < (int)sizeof(uint16_t)) {
+            android_errorWriteLog(0x534e4554, "67647856");
+            return -EINVAL;
+        }
 
         uint16_t preset = *(uint16_t *)pValue;
         ALOGV("set REVERB_PARAM_PRESET, preset %d", preset);
diff --git a/media/libheif/HeifDecoderImpl.cpp b/media/libheif/HeifDecoderImpl.cpp
index 4b131a7..a63a2df 100644
--- a/media/libheif/HeifDecoderImpl.cpp
+++ b/media/libheif/HeifDecoderImpl.cpp
@@ -25,8 +25,8 @@
 #include <drm/drm_framework_common.h>
 #include <media/IDataSource.h>
 #include <media/mediametadataretriever.h>
+#include <media/MediaSource.h>
 #include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/MediaSource.h>
 #include <private/media/VideoFrame.h>
 #include <utils/Log.h>
 #include <utils/RefBase.h>
@@ -270,7 +270,9 @@
     // it's not, default to HAL_PIXEL_FORMAT_RGB_565.
     mOutputColor(HAL_PIXEL_FORMAT_RGB_565),
     mCurScanline(0),
-    mFrameDecoded(false) {
+    mFrameDecoded(false),
+    mHasImage(false),
+    mHasVideo(false) {
 }
 
 HeifDecoderImpl::~HeifDecoderImpl() {
@@ -278,6 +280,8 @@
 
 bool HeifDecoderImpl::init(HeifStream* stream, HeifFrameInfo* frameInfo) {
     mFrameDecoded = false;
+    mFrameMemory.clear();
+
     sp<HeifDataSource> dataSource = new HeifDataSource(stream);
     if (!dataSource->init()) {
         return false;
@@ -285,7 +289,7 @@
     mDataSource = dataSource;
 
     mRetriever = new MediaMetadataRetriever();
-    status_t err = mRetriever->setDataSource(mDataSource, "video/mp4");
+    status_t err = mRetriever->setDataSource(mDataSource, "image/heif");
     if (err != OK) {
         ALOGE("failed to set data source!");
 
@@ -295,15 +299,21 @@
     }
     ALOGV("successfully set data source.");
 
+    const char* hasImage = mRetriever->extractMetadata(METADATA_KEY_HAS_IMAGE);
     const char* hasVideo = mRetriever->extractMetadata(METADATA_KEY_HAS_VIDEO);
-    if (!hasVideo || strcasecmp(hasVideo, "yes")) {
-        ALOGE("no video: %s", hasVideo ? hasVideo : "null");
-        return false;
+
+    mHasImage = hasImage && !strcasecmp(hasImage, "yes");
+    mHasVideo = hasVideo && !strcasecmp(hasVideo, "yes");
+    if (mHasImage) {
+        // image index < 0 to retrieve primary image
+        mFrameMemory = mRetriever->getImageAtIndex(
+                -1, mOutputColor, true /*metaOnly*/);
+    } else if (mHasVideo) {
+        mFrameMemory = mRetriever->getFrameAtTime(0,
+                MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC,
+                mOutputColor, true /*metaOnly*/);
     }
 
-    mFrameMemory = mRetriever->getFrameAtTime(0,
-            IMediaSource::ReadOptions::SEEK_PREVIOUS_SYNC,
-            mOutputColor, true /*metaOnly*/);
     if (mFrameMemory == nullptr || mFrameMemory->pointer() == nullptr) {
         ALOGE("getFrameAtTime: videoFrame is a nullptr");
         return false;
@@ -368,8 +378,14 @@
         return true;
     }
 
-    mFrameMemory = mRetriever->getFrameAtTime(0,
-            IMediaSource::ReadOptions::SEEK_PREVIOUS_SYNC, mOutputColor);
+    if (mHasImage) {
+        // image index < 0 to retrieve primary image
+        mFrameMemory = mRetriever->getImageAtIndex(-1, mOutputColor);
+    } else if (mHasVideo) {
+        mFrameMemory = mRetriever->getFrameAtTime(0,
+                MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC, mOutputColor);
+    }
+
     if (mFrameMemory == nullptr || mFrameMemory->pointer() == nullptr) {
         ALOGE("getFrameAtTime: videoFrame is a nullptr");
         return false;
diff --git a/media/libheif/HeifDecoderImpl.h b/media/libheif/HeifDecoderImpl.h
index c2e4ff3..406c2c1 100644
--- a/media/libheif/HeifDecoderImpl.h
+++ b/media/libheif/HeifDecoderImpl.h
@@ -55,6 +55,8 @@
     android_pixel_format_t mOutputColor;
     size_t mCurScanline;
     bool mFrameDecoded;
+    bool mHasImage;
+    bool mHasVideo;
 };
 
 } // namespace android
diff --git a/media/libmedia/Android.bp b/media/libmedia/Android.bp
index 80280ae..1f4bd0a 100644
--- a/media/libmedia/Android.bp
+++ b/media/libmedia/Android.bp
@@ -33,19 +33,19 @@
     clang: true,
 }
 
-// TODO(b/35449087): merge back with libmedia when OMX implementatoins
-// no longer use aidl wrappers (or remove OMX component form libmedia)
-cc_defaults {
-    name: "libmedia_omx_defaults",
+cc_library_shared {
+    name: "libmedia_omx",
+    vendor_available: true,
+    vndk: {
+        enabled: true,
+    },
 
     srcs: [
         "aidl/android/IGraphicBufferSource.aidl",
         "aidl/android/IOMXBufferSource.aidl",
 
         "IMediaCodecList.cpp",
-        "IMediaCodecService.cpp",
         "IOMX.cpp",
-        "IOMXStore.cpp",
         "MediaCodecBuffer.cpp",
         "MediaCodecInfo.cpp",
         "OMXBuffer.cpp",
@@ -112,19 +112,35 @@
     },
 }
 
-cc_library_shared {
-    name: "libmedia_omx",
-    vendor_available: true,
-    vndk: {
-        enabled: true,
-    },
+cc_library_static {
+    name: "libmedia_midiiowrapper",
 
-    defaults: ["libmedia_omx_defaults"],
+    srcs: ["MidiIoWrapper.cpp"],
+
+    static_libs: [
+        "libsonivox",
+    ],
+
+    cflags: [
+        "-Werror",
+        "-Wno-error=deprecated-declarations",
+        "-Wall",
+    ],
+
+    sanitize: {
+        misc_undefined: [
+            "unsigned-integer-overflow",
+            "signed-integer-overflow",
+        ],
+        cfi: true,
+        diag: {
+            cfi: true,
+        },
+    },
 }
 
 cc_library_shared {
     name: "libmedia",
-    defaults: ["libmedia_omx_defaults"],
 
     srcs: [
         "IDataSource.cpp",
@@ -151,7 +167,6 @@
         "IMediaMetadataRetriever.cpp",
         "mediametadataretriever.cpp",
         "MidiDeviceInfo.cpp",
-        "MidiIoWrapper.cpp",
         "JetPlayer.cpp",
         "MediaScanner.cpp",
         "MediaScannerClient.cpp",
@@ -176,12 +191,14 @@
         "libexpat",
         "libcamera_client",
         "libstagefright_foundation",
+        "libmediaextractor",
         "libgui",
         "libdl",
         "libaudioutils",
         "libaudioclient",
         "libhidlbase",
         "libhidltransport",
+        "libmedia_omx",
     ],
 
     export_shared_lib_headers: [
@@ -190,11 +207,12 @@
         "libicuuc",
         "libicui18n",
         "libsonivox",
+        "libmedia_omx",
     ],
 
-    // for memory heap analysis
     static_libs: [
-        "libc_malloc_debug_backtrace",
+        "libc_malloc_debug_backtrace",  // for memory heap analysis
+        "libmedia_midiiowrapper",
     ],
 
     export_include_dirs: [
diff --git a/media/libmedia/IMediaCodecService.cpp b/media/libmedia/IMediaCodecService.cpp
deleted file mode 100644
index adfa93d..0000000
--- a/media/libmedia/IMediaCodecService.cpp
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
-**
-** Copyright 2015, 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 "IMediaCodecService"
-//#define LOG_NDEBUG 0
-
-#include <utils/Log.h>
-#include <stdint.h>
-#include <sys/types.h>
-#include <binder/Parcel.h>
-#include <media/IMediaCodecService.h>
-
-namespace android {
-
-enum {
-    GET_OMX = IBinder::FIRST_CALL_TRANSACTION,
-    GET_OMX_STORE
-};
-
-class BpMediaCodecService : public BpInterface<IMediaCodecService>
-{
-public:
-    explicit BpMediaCodecService(const sp<IBinder>& impl)
-        : BpInterface<IMediaCodecService>(impl)
-    {
-    }
-
-    virtual sp<IOMX> getOMX() {
-        Parcel data, reply;
-        data.writeInterfaceToken(IMediaCodecService::getInterfaceDescriptor());
-        remote()->transact(GET_OMX, data, &reply);
-        return interface_cast<IOMX>(reply.readStrongBinder());
-    }
-
-    virtual sp<IOMXStore> getOMXStore() {
-        Parcel data, reply;
-        data.writeInterfaceToken(IMediaCodecService::getInterfaceDescriptor());
-        remote()->transact(GET_OMX_STORE, data, &reply);
-        return interface_cast<IOMXStore>(reply.readStrongBinder());
-    }
-
-};
-
-IMPLEMENT_META_INTERFACE(MediaCodecService, "android.media.IMediaCodecService");
-
-// ----------------------------------------------------------------------
-
-status_t BnMediaCodecService::onTransact(
-    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
-{
-    switch (code) {
-
-        case GET_OMX: {
-            CHECK_INTERFACE(IMediaCodecService, data, reply);
-            sp<IOMX> omx = getOMX();
-            reply->writeStrongBinder(IInterface::asBinder(omx));
-            return NO_ERROR;
-        }
-        case GET_OMX_STORE: {
-            CHECK_INTERFACE(IMediaCodecService, data, reply);
-            sp<IOMXStore> omxStore = getOMXStore();
-            reply->writeStrongBinder(IInterface::asBinder(omxStore));
-            return NO_ERROR;
-        }
-        default:
-            return BBinder::onTransact(code, data, reply, flags);
-    }
-}
-
-// ----------------------------------------------------------------------------
-
-} // namespace android
diff --git a/media/libmedia/IMediaExtractor.cpp b/media/libmedia/IMediaExtractor.cpp
index 3c43a72..a8a7b82 100644
--- a/media/libmedia/IMediaExtractor.cpp
+++ b/media/libmedia/IMediaExtractor.cpp
@@ -23,6 +23,7 @@
 
 #include <binder/IPCThreadState.h>
 #include <binder/Parcel.h>
+#include <binder/PermissionCache.h>
 #include <media/IMediaExtractor.h>
 #include <media/stagefright/MetaData.h>
 
@@ -323,13 +324,21 @@
 
 status_t dumpExtractors(int fd, const Vector<String16>&) {
     String8 out;
-    out.append("Recent extractors, most recent first:\n");
-    {
-        Mutex::Autolock lock(sExtractorsLock);
-        for (size_t i = 0; i < sExtractors.size(); i++) {
-            const ExtractorInstance &instance = sExtractors.itemAt(i);
-            out.append("  ");
-            out.append(instance.toString());
+    const IPCThreadState* ipc = IPCThreadState::self();
+    const int pid = ipc->getCallingPid();
+    const int uid = ipc->getCallingUid();
+    if (!PermissionCache::checkPermission(String16("android.permission.DUMP"), pid, uid)) {
+        out.appendFormat("Permission Denial: "
+                "can't dump MediaExtractor from pid=%d, uid=%d\n", pid, uid);
+    } else {
+        out.append("Recent extractors, most recent first:\n");
+        {
+            Mutex::Autolock lock(sExtractorsLock);
+            for (size_t i = 0; i < sExtractors.size(); i++) {
+                const ExtractorInstance &instance = sExtractors.itemAt(i);
+                out.append("  ");
+                out.append(instance.toString());
+            }
         }
     }
     write(fd, out.string(), out.size());
diff --git a/media/libmedia/IMediaExtractorService.cpp b/media/libmedia/IMediaExtractorService.cpp
index 7c0d08d..d7533ca 100644
--- a/media/libmedia/IMediaExtractorService.cpp
+++ b/media/libmedia/IMediaExtractorService.cpp
@@ -23,7 +23,7 @@
 #include <sys/types.h>
 #include <binder/Parcel.h>
 #include <media/IMediaExtractorService.h>
-#include <media/stagefright/MediaExtractor.h>
+#include <media/MediaExtractor.h>
 
 namespace android {
 
diff --git a/media/libmedia/IMediaMetadataRetriever.cpp b/media/libmedia/IMediaMetadataRetriever.cpp
index 5ea2e8b..f725c97 100644
--- a/media/libmedia/IMediaMetadataRetriever.cpp
+++ b/media/libmedia/IMediaMetadataRetriever.cpp
@@ -68,6 +68,8 @@
     SET_DATA_SOURCE_FD,
     SET_DATA_SOURCE_CALLBACK,
     GET_FRAME_AT_TIME,
+    GET_IMAGE_AT_INDEX,
+    GET_FRAME_AT_INDEX,
     EXTRACT_ALBUM_ART,
     EXTRACT_METADATA,
 };
@@ -164,6 +166,55 @@
         return interface_cast<IMemory>(reply.readStrongBinder());
     }
 
+    sp<IMemory> getImageAtIndex(int index, int colorFormat, bool metaOnly)
+    {
+        ALOGV("getImageAtIndex: index %d, colorFormat(%d) metaOnly(%d)",
+                index, colorFormat, metaOnly);
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor());
+        data.writeInt32(index);
+        data.writeInt32(colorFormat);
+        data.writeInt32(metaOnly);
+#ifndef DISABLE_GROUP_SCHEDULE_HACK
+        sendSchedPolicy(data);
+#endif
+        remote()->transact(GET_IMAGE_AT_INDEX, data, &reply);
+        status_t ret = reply.readInt32();
+        if (ret != NO_ERROR) {
+            return NULL;
+        }
+        return interface_cast<IMemory>(reply.readStrongBinder());
+    }
+
+    status_t getFrameAtIndex(std::vector<sp<IMemory> > *frames,
+            int frameIndex, int numFrames, int colorFormat, bool metaOnly)
+    {
+        ALOGV("getFrameAtIndex: frameIndex(%d), numFrames(%d), colorFormat(%d) metaOnly(%d)",
+                frameIndex, numFrames, colorFormat, metaOnly);
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor());
+        data.writeInt32(frameIndex);
+        data.writeInt32(numFrames);
+        data.writeInt32(colorFormat);
+        data.writeInt32(metaOnly);
+#ifndef DISABLE_GROUP_SCHEDULE_HACK
+        sendSchedPolicy(data);
+#endif
+        remote()->transact(GET_FRAME_AT_INDEX, data, &reply);
+        status_t ret = reply.readInt32();
+        if (ret != NO_ERROR) {
+            return ret;
+        }
+        int retNumFrames = reply.readInt32();
+        if (retNumFrames < numFrames) {
+            numFrames = retNumFrames;
+        }
+        for (int i = 0; i < numFrames; i++) {
+            frames->push_back(interface_cast<IMemory>(reply.readStrongBinder()));
+        }
+        return OK;
+    }
+
     sp<IMemory> extractAlbumArt()
     {
         Parcel data, reply;
@@ -300,6 +351,54 @@
 #endif
             return NO_ERROR;
         } break;
+        case GET_IMAGE_AT_INDEX: {
+            CHECK_INTERFACE(IMediaMetadataRetriever, data, reply);
+            int index = data.readInt32();
+            int colorFormat = data.readInt32();
+            bool metaOnly = (data.readInt32() != 0);
+            ALOGV("getImageAtIndex: index(%d), colorFormat(%d), metaOnly(%d)",
+                    index, colorFormat, metaOnly);
+#ifndef DISABLE_GROUP_SCHEDULE_HACK
+            setSchedPolicy(data);
+#endif
+            sp<IMemory> bitmap = getImageAtIndex(index, colorFormat, metaOnly);
+            if (bitmap != 0) {  // Don't send NULL across the binder interface
+                reply->writeInt32(NO_ERROR);
+                reply->writeStrongBinder(IInterface::asBinder(bitmap));
+            } else {
+                reply->writeInt32(UNKNOWN_ERROR);
+            }
+#ifndef DISABLE_GROUP_SCHEDULE_HACK
+            restoreSchedPolicy();
+#endif
+            return NO_ERROR;
+        } break;
+        case GET_FRAME_AT_INDEX: {
+            CHECK_INTERFACE(IMediaMetadataRetriever, data, reply);
+            int frameIndex = data.readInt32();
+            int numFrames = data.readInt32();
+            int colorFormat = data.readInt32();
+            bool metaOnly = (data.readInt32() != 0);
+            ALOGV("getFrameAtIndex: frameIndex(%d), numFrames(%d), colorFormat(%d), metaOnly(%d)",
+                    frameIndex, numFrames, colorFormat, metaOnly);
+#ifndef DISABLE_GROUP_SCHEDULE_HACK
+            setSchedPolicy(data);
+#endif
+            std::vector<sp<IMemory> > frames;
+            status_t err = getFrameAtIndex(
+                    &frames, frameIndex, numFrames, colorFormat, metaOnly);
+            reply->writeInt32(err);
+            if (OK == err) {
+                reply->writeInt32(frames.size());
+                for (size_t i = 0; i < frames.size(); i++) {
+                    reply->writeStrongBinder(IInterface::asBinder(frames[i]));
+                }
+            }
+#ifndef DISABLE_GROUP_SCHEDULE_HACK
+            restoreSchedPolicy();
+#endif
+            return NO_ERROR;
+        } break;
         case EXTRACT_ALBUM_ART: {
             CHECK_INTERFACE(IMediaMetadataRetriever, data, reply);
 #ifndef DISABLE_GROUP_SCHEDULE_HACK
diff --git a/media/libmedia/IMediaPlayer.cpp b/media/libmedia/IMediaPlayer.cpp
index 903e503..3fb1d7a 100644
--- a/media/libmedia/IMediaPlayer.cpp
+++ b/media/libmedia/IMediaPlayer.cpp
@@ -78,6 +78,10 @@
     // Modular DRM
     PREPARE_DRM,
     RELEASE_DRM,
+    // AudioRouting
+    SET_OUTPUT_DEVICE,
+    GET_ROUTED_DEVICE_ID,
+    ENABLE_AUDIO_DEVICE_CALLBACK,
 };
 
 // ModDrm helpers
@@ -559,6 +563,59 @@
 
         return reply.readInt32();
     }
+
+    status_t setOutputDevice(audio_port_handle_t deviceId)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
+
+        data.writeInt32(deviceId);
+
+        status_t status = remote()->transact(SET_OUTPUT_DEVICE, data, &reply);
+        if (status != OK) {
+            ALOGE("setOutputDevice: binder call failed: %d", status);
+            return status;
+        }
+
+        return reply.readInt32();
+    }
+
+    status_t getRoutedDeviceId(audio_port_handle_t* deviceId)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
+
+        status_t status = remote()->transact(GET_ROUTED_DEVICE_ID, data, &reply);
+        if (status != OK) {
+            ALOGE("getRoutedDeviceid: binder call failed: %d", status);
+            *deviceId = AUDIO_PORT_HANDLE_NONE;
+            return status;
+        }
+
+        status = reply.readInt32();
+        if (status != NO_ERROR) {
+            *deviceId = AUDIO_PORT_HANDLE_NONE;
+        } else {
+            *deviceId = reply.readInt32();
+        }
+        return status;
+    }
+
+    status_t enableAudioDeviceCallback(bool enabled)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
+
+        data.writeBool(enabled);
+
+        status_t status = remote()->transact(ENABLE_AUDIO_DEVICE_CALLBACK, data, &reply);
+        if (status != OK) {
+            ALOGE("enableAudioDeviceCallback: binder call failed: %d, %d", enabled, status);
+            return status;
+        }
+
+        return reply.readInt32();
+    }
 };
 
 IMPLEMENT_META_INTERFACE(MediaPlayer, "android.media.IMediaPlayer");
@@ -916,6 +973,41 @@
             reply->writeInt32(result);
             return OK;
         }
+
+        // AudioRouting
+        case SET_OUTPUT_DEVICE: {
+            CHECK_INTERFACE(IMediaPlayer, data, reply);
+            int deviceId;
+            status_t status = data.readInt32(&deviceId);
+            if (status == NO_ERROR) {
+                reply->writeInt32(setOutputDevice(deviceId));
+            } else {
+                reply->writeInt32(BAD_VALUE);
+            }
+            return NO_ERROR;
+        }
+        case GET_ROUTED_DEVICE_ID: {
+            CHECK_INTERFACE(IMediaPlayer, data, reply);
+            audio_port_handle_t deviceId;
+            status_t ret = getRoutedDeviceId(&deviceId);
+            reply->writeInt32(ret);
+            if (ret == NO_ERROR) {
+                reply->writeInt32(deviceId);
+            }
+            return NO_ERROR;
+        } break;
+        case ENABLE_AUDIO_DEVICE_CALLBACK: {
+            CHECK_INTERFACE(IMediaPlayer, data, reply);
+            bool enabled;
+            status_t status = data.readBool(&enabled);
+            if (status == NO_ERROR) {
+                reply->writeInt32(enableAudioDeviceCallback(enabled));
+            } else {
+                reply->writeInt32(BAD_VALUE);
+            }
+            return NO_ERROR;
+        } break;
+
         default:
             return BBinder::onTransact(code, data, reply, flags);
     }
diff --git a/media/libmedia/IMediaSource.cpp b/media/libmedia/IMediaSource.cpp
index 724b3a0..bc78892 100644
--- a/media/libmedia/IMediaSource.cpp
+++ b/media/libmedia/IMediaSource.cpp
@@ -26,7 +26,7 @@
 #include <media/IMediaSource.h>
 #include <media/stagefright/MediaBuffer.h>
 #include <media/stagefright/MediaBufferGroup.h>
-#include <media/stagefright/MediaSource.h>
+#include <media/MediaSource.h>
 #include <media/stagefright/MetaData.h>
 
 namespace android {
@@ -113,7 +113,8 @@
         return NULL;
     }
 
-    virtual status_t read(MediaBuffer **buffer, const ReadOptions *options) {
+    virtual status_t read(MediaBuffer **buffer,
+            const MediaSource::ReadOptions *options) {
         Vector<MediaBuffer *> buffers;
         status_t ret = readMultiple(&buffers, 1 /* maxNumBuffers */, options);
         *buffer = buffers.size() == 0 ? nullptr : buffers[0];
@@ -123,7 +124,8 @@
     }
 
     virtual status_t readMultiple(
-            Vector<MediaBuffer *> *buffers, uint32_t maxNumBuffers, const ReadOptions *options) {
+            Vector<MediaBuffer *> *buffers, uint32_t maxNumBuffers,
+            const MediaSource::ReadOptions *options) {
         ALOGV("readMultiple");
         if (buffers == NULL || !buffers->isEmpty()) {
             return BAD_VALUE;
@@ -330,7 +332,7 @@
             }
 
             // Get read options, if any.
-            ReadOptions opts;
+            MediaSource::ReadOptions opts;
             uint32_t len;
             const bool useOptions =
                     data.readUint32(&len) == NO_ERROR
@@ -449,58 +451,5 @@
     }
 }
 
-////////////////////////////////////////////////////////////////////////////////
-
-IMediaSource::ReadOptions::ReadOptions() {
-    reset();
-}
-
-void IMediaSource::ReadOptions::reset() {
-    mOptions = 0;
-    mSeekTimeUs = 0;
-    mLatenessUs = 0;
-    mNonBlocking = false;
-}
-
-void IMediaSource::ReadOptions::setNonBlocking() {
-    mNonBlocking = true;
-}
-
-void IMediaSource::ReadOptions::clearNonBlocking() {
-    mNonBlocking = false;
-}
-
-bool IMediaSource::ReadOptions::getNonBlocking() const {
-    return mNonBlocking;
-}
-
-void IMediaSource::ReadOptions::setSeekTo(int64_t time_us, SeekMode mode) {
-    mOptions |= kSeekTo_Option;
-    mSeekTimeUs = time_us;
-    mSeekMode = mode;
-}
-
-void IMediaSource::ReadOptions::clearSeekTo() {
-    mOptions &= ~kSeekTo_Option;
-    mSeekTimeUs = 0;
-    mSeekMode = SEEK_CLOSEST_SYNC;
-}
-
-bool IMediaSource::ReadOptions::getSeekTo(
-        int64_t *time_us, SeekMode *mode) const {
-    *time_us = mSeekTimeUs;
-    *mode = mSeekMode;
-    return (mOptions & kSeekTo_Option) != 0;
-}
-
-void IMediaSource::ReadOptions::setLateBy(int64_t lateness_us) {
-    mLatenessUs = lateness_us;
-}
-
-int64_t IMediaSource::ReadOptions::getLateBy() const {
-    return mLatenessUs;
-}
-
-
 }  // namespace android
 
diff --git a/media/libmedia/IOMXStore.cpp b/media/libmedia/IOMXStore.cpp
deleted file mode 100644
index 4948f1a..0000000
--- a/media/libmedia/IOMXStore.cpp
+++ /dev/null
@@ -1,367 +0,0 @@
-/*
- * Copyright (c) 2009 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_NDEBUG 0
-#define LOG_TAG "IOMXStore"
-
-#include <utils/Log.h>
-
-#include <media/IOMX.h>
-#include <media/IOMXStore.h>
-#include <android/hardware/media/omx/1.0/IOmxStore.h>
-
-#include <binder/IInterface.h>
-#include <binder/IBinder.h>
-#include <binder/Parcel.h>
-
-#include <vector>
-#include <string>
-
-namespace android {
-
-namespace {
-
-enum {
-    CONNECT = IBinder::FIRST_CALL_TRANSACTION,
-    LIST_SERVICE_ATTRIBUTES,
-    GET_NODE_PREFIX,
-    LIST_ROLES,
-    GET_OMX,
-};
-
-// Forward declarations of std::vector<T> <-> Parcel conversion funcitons that
-// depend on writeToParcel() and readToParcel() for T <-> Parcel.
-
-template <typename T>
-status_t writeToParcel(const std::vector<T>& v, Parcel* p);
-
-template <typename T>
-status_t readFromParcel(std::vector<T>* v, const Parcel& p);
-
-// std::string <-> Parcel
-
-status_t writeToParcel(const std::string& s, Parcel* p) {
-    if (s.size() > INT32_MAX) {
-        return BAD_VALUE;
-    }
-    return p->writeByteArray(
-            s.size(), reinterpret_cast<const uint8_t*>(s.c_str()));
-}
-
-status_t readFromParcel(std::string* s, const Parcel& p) {
-    int32_t len;
-    status_t status = p.readInt32(&len);
-    if (status != NO_ERROR) {
-        return status;
-    } else if ((len < 0) || (static_cast<uint64_t>(len) > SIZE_MAX)) {
-        return BAD_VALUE;
-    }
-    s->resize(len);
-    if (len == 0) {
-        return NO_ERROR;
-    }
-    return p.read(static_cast<void*>(&s->front()), static_cast<size_t>(len));
-}
-
-// IOMXStore::Attribute <-> Parcel
-
-status_t writeToParcel(const IOMXStore::Attribute& a, Parcel* p) {
-    status_t status = writeToParcel(a.key, p);
-    if (status != NO_ERROR) {
-        return status;
-    }
-    return writeToParcel(a.value, p);
-}
-
-status_t readFromParcel(IOMXStore::Attribute* a, const Parcel& p) {
-    status_t status = readFromParcel(&(a->key), p);
-    if (status != NO_ERROR) {
-        return status;
-    }
-    return readFromParcel(&(a->value), p);
-}
-
-// IOMXStore::NodeInfo <-> Parcel
-
-status_t writeToParcel(const IOMXStore::NodeInfo& n, Parcel* p) {
-    status_t status = writeToParcel(n.name, p);
-    if (status != NO_ERROR) {
-        return status;
-    }
-    status = writeToParcel(n.owner, p);
-    if (status != NO_ERROR) {
-        return status;
-    }
-    return writeToParcel(n.attributes, p);
-}
-
-status_t readFromParcel(IOMXStore::NodeInfo* n, const Parcel& p) {
-    status_t status = readFromParcel(&(n->name), p);
-    if (status != NO_ERROR) {
-        return status;
-    }
-    status = readFromParcel(&(n->owner), p);
-    if (status != NO_ERROR) {
-        return status;
-    }
-    return readFromParcel(&(n->attributes), p);
-}
-
-// IOMXStore::RoleInfo <-> Parcel
-
-status_t writeToParcel(const IOMXStore::RoleInfo& r, Parcel* p) {
-    status_t status = writeToParcel(r.role, p);
-    if (status != NO_ERROR) {
-        return status;
-    }
-    status = writeToParcel(r.type, p);
-    if (status != NO_ERROR) {
-        return status;
-    }
-    status = p->writeBool(r.isEncoder);
-    if (status != NO_ERROR) {
-        return status;
-    }
-    status = p->writeBool(r.preferPlatformNodes);
-    if (status != NO_ERROR) {
-        return status;
-    }
-    return writeToParcel(r.nodes, p);
-}
-
-status_t readFromParcel(IOMXStore::RoleInfo* r, const Parcel& p) {
-    status_t status = readFromParcel(&(r->role), p);
-    if (status != NO_ERROR) {
-        return status;
-    }
-    status = readFromParcel(&(r->type), p);
-    if (status != NO_ERROR) {
-        return status;
-    }
-    status = p.readBool(&(r->isEncoder));
-    if (status != NO_ERROR) {
-        return status;
-    }
-    status = p.readBool(&(r->preferPlatformNodes));
-    if (status != NO_ERROR) {
-        return status;
-    }
-    return readFromParcel(&(r->nodes), p);
-}
-
-// std::vector<NodeInfo> <-> Parcel
-// std::vector<RoleInfo> <-> Parcel
-
-template <typename T>
-status_t writeToParcel(const std::vector<T>& v, Parcel* p) {
-    status_t status = p->writeVectorSize(v);
-    if (status != NO_ERROR) {
-        return status;
-    }
-    for (const T& x : v) {
-        status = writeToParcel(x, p);
-        if (status != NO_ERROR) {
-            return status;
-        }
-    }
-    return NO_ERROR;
-}
-
-template <typename T>
-status_t readFromParcel(std::vector<T>* v, const Parcel& p) {
-    status_t status = p.resizeOutVector(v);
-    if (status != NO_ERROR) {
-        return status;
-    }
-    for (T& x : *v) {
-        status = readFromParcel(&x, p);
-        if (status != NO_ERROR) {
-            return status;
-        }
-    }
-    return NO_ERROR;
-}
-
-} // unnamed namespace
-
-////////////////////////////////////////////////////////////////////////////////
-
-class BpOMXStore : public BpInterface<IOMXStore> {
-public:
-    explicit BpOMXStore(const sp<IBinder> &impl)
-        : BpInterface<IOMXStore>(impl) {
-    }
-
-    status_t listServiceAttributes(
-            std::vector<Attribute>* attributes) override {
-        Parcel data, reply;
-        status_t status;
-        status = data.writeInterfaceToken(IOMXStore::getInterfaceDescriptor());
-        if (status != NO_ERROR) {
-            return status;
-        }
-        status = remote()->transact(LIST_SERVICE_ATTRIBUTES, data, &reply);
-        if (status != NO_ERROR) {
-            return status;
-        }
-        return readFromParcel(attributes, reply);
-    }
-
-    status_t getNodePrefix(std::string* prefix) override {
-        Parcel data, reply;
-        status_t status;
-        status = data.writeInterfaceToken(IOMXStore::getInterfaceDescriptor());
-        if (status != NO_ERROR) {
-            return status;
-        }
-        status = remote()->transact(GET_NODE_PREFIX, data, &reply);
-        if (status != NO_ERROR) {
-            return status;
-        }
-        return readFromParcel(prefix, reply);
-    }
-
-    status_t listRoles(std::vector<RoleInfo>* roleList) override {
-        Parcel data, reply;
-        status_t status;
-        status = data.writeInterfaceToken(IOMXStore::getInterfaceDescriptor());
-        if (status != NO_ERROR) {
-            return status;
-        }
-        status = remote()->transact(LIST_ROLES, data, &reply);
-        if (status != NO_ERROR) {
-            return status;
-        }
-        return readFromParcel(roleList, reply);
-    }
-
-    status_t getOmx(const std::string& name, sp<IOMX>* omx) override {
-        Parcel data, reply;
-        status_t status;
-        status = data.writeInterfaceToken(IOMXStore::getInterfaceDescriptor());
-        if (status != NO_ERROR) {
-            return status;
-        }
-        status = writeToParcel(name, &data);
-        if (status != NO_ERROR) {
-            return status;
-        }
-        status = remote()->transact(GET_OMX, data, &reply);
-        if (status != NO_ERROR) {
-            return status;
-        }
-        return reply.readStrongBinder(omx);
-    }
-
-};
-
-IMPLEMENT_META_INTERFACE(OMXStore, "android.hardware.IOMXStore");
-
-////////////////////////////////////////////////////////////////////////////////
-
-#define CHECK_OMX_INTERFACE(interface, data, reply) \
-        do { if (!(data).enforceInterface(interface::getInterfaceDescriptor())) { \
-            ALOGW("Call incorrectly routed to " #interface); \
-            return PERMISSION_DENIED; \
-        } } while (0)
-
-status_t BnOMXStore::onTransact(
-    uint32_t code, const Parcel &data, Parcel *reply, uint32_t flags) {
-    switch (code) {
-        case LIST_SERVICE_ATTRIBUTES: {
-            CHECK_OMX_INTERFACE(IOMXStore, data, reply);
-            status_t status;
-            std::vector<Attribute> attributes;
-
-            status = listServiceAttributes(&attributes);
-            if (status != NO_ERROR) {
-                ALOGE("listServiceAttributes() fails with status %d",
-                        static_cast<int>(status));
-                return NO_ERROR;
-            }
-            status = writeToParcel(attributes, reply);
-            if (status != NO_ERROR) {
-                ALOGE("listServiceAttributes() fails to send reply");
-                return NO_ERROR;
-            }
-            return NO_ERROR;
-        }
-        case GET_NODE_PREFIX: {
-            CHECK_OMX_INTERFACE(IOMXStore, data, reply);
-            status_t status;
-            std::string prefix;
-
-            status = getNodePrefix(&prefix);
-            if (status != NO_ERROR) {
-                ALOGE("getNodePrefix() fails with status %d",
-                        static_cast<int>(status));
-                return NO_ERROR;
-            }
-            status = writeToParcel(prefix, reply);
-            if (status != NO_ERROR) {
-                ALOGE("getNodePrefix() fails to send reply");
-                return NO_ERROR;
-            }
-            return NO_ERROR;
-        }
-        case LIST_ROLES: {
-            CHECK_OMX_INTERFACE(IOMXStore, data, reply);
-            status_t status;
-            std::vector<RoleInfo> roleList;
-
-            status = listRoles(&roleList);
-            if (status != NO_ERROR) {
-                ALOGE("listRoles() fails with status %d",
-                        static_cast<int>(status));
-                return NO_ERROR;
-            }
-            status = writeToParcel(roleList, reply);
-            if (status != NO_ERROR) {
-                ALOGE("listRoles() fails to send reply");
-                return NO_ERROR;
-            }
-            return NO_ERROR;
-        }
-        case GET_OMX: {
-            CHECK_OMX_INTERFACE(IOMXStore, data, reply);
-            status_t status;
-            std::string name;
-            sp<IOMX> omx;
-
-            status = readFromParcel(&name, data);
-            if (status != NO_ERROR) {
-                ALOGE("getOmx() fails to retrieve name");
-                return NO_ERROR;
-            }
-            status = getOmx(name, &omx);
-            if (status != NO_ERROR) {
-                ALOGE("getOmx() fails with status %d",
-                        static_cast<int>(status));
-                return NO_ERROR;
-            }
-            status = reply->writeStrongBinder(IInterface::asBinder(omx));
-            if (status != NO_ERROR) {
-                ALOGE("getOmx() fails to send reply");
-                return NO_ERROR;
-            }
-            return NO_ERROR;
-        }
-        default:
-            return BBinder::onTransact(code, data, reply, flags);
-    }
-}
-
-}  // namespace android
diff --git a/media/libmedia/include/media/IMediaCodecService.h b/media/libmedia/include/media/IMediaCodecService.h
deleted file mode 100644
index 59fb1c0..0000000
--- a/media/libmedia/include/media/IMediaCodecService.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (C) 2015 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_IMEDIACODECSERVICE_H
-#define ANDROID_IMEDIACODECSERVICE_H
-
-#include <binder/IInterface.h>
-#include <binder/IMemory.h>
-#include <binder/Parcel.h>
-#include <media/IDataSource.h>
-#include <media/IOMX.h>
-#include <media/IOMXStore.h>
-
-namespace android {
-
-class IMediaCodecService: public IInterface
-{
-public:
-    DECLARE_META_INTERFACE(MediaCodecService);
-
-    virtual sp<IOMX> getOMX() = 0;
-    virtual sp<IOMXStore> getOMXStore() = 0;
-};
-
-class BnMediaCodecService: public BnInterface<IMediaCodecService>
-{
-public:
-    virtual status_t    onTransact(uint32_t code, const Parcel& data, Parcel* reply,
-                                uint32_t flags = 0);
-};
-
-}   // namespace android
-
-#endif  // ANDROID_IMEDIACODECSERVICE_H
diff --git a/media/libmedia/include/media/IMediaExtractor.h b/media/libmedia/include/media/IMediaExtractor.h
index 0ac7673..44f8c1d 100644
--- a/media/libmedia/include/media/IMediaExtractor.h
+++ b/media/libmedia/include/media/IMediaExtractor.h
@@ -18,8 +18,8 @@
 
 #define IMEDIA_EXTRACTOR_BASE_H_
 
+#include <media/DataSource.h>
 #include <media/IMediaSource.h>
-#include <media/stagefright/DataSource.h>
 #include <vector>
 
 namespace android {
diff --git a/media/libmedia/include/media/IMediaMetadataRetriever.h b/media/libmedia/include/media/IMediaMetadataRetriever.h
index ea95161..5491535 100644
--- a/media/libmedia/include/media/IMediaMetadataRetriever.h
+++ b/media/libmedia/include/media/IMediaMetadataRetriever.h
@@ -44,6 +44,11 @@
             const sp<IDataSource>& dataSource, const char *mime) = 0;
     virtual sp<IMemory>     getFrameAtTime(
             int64_t timeUs, int option, int colorFormat, bool metaOnly) = 0;
+    virtual sp<IMemory>     getImageAtIndex(
+            int index, int colorFormat, bool metaOnly) = 0;
+    virtual status_t        getFrameAtIndex(
+            std::vector<sp<IMemory> > *frames,
+            int frameIndex, int numFrames, int colorFormat, bool metaOnly) = 0;
     virtual sp<IMemory>     extractAlbumArt() = 0;
     virtual const char*     extractMetadata(int keyCode) = 0;
 };
diff --git a/media/libmedia/include/media/IMediaPlayer.h b/media/libmedia/include/media/IMediaPlayer.h
index e181338..2129222 100644
--- a/media/libmedia/include/media/IMediaPlayer.h
+++ b/media/libmedia/include/media/IMediaPlayer.h
@@ -23,7 +23,7 @@
 #include <utils/KeyedVector.h>
 #include <system/audio.h>
 
-#include <media/IMediaSource.h>
+#include <media/MediaSource.h>
 #include <media/VolumeShaper.h>
 
 // Fwd decl to make sure everyone agrees that the scope of struct sockaddr_in is
@@ -42,7 +42,7 @@
 struct AVSyncSettings;
 struct BufferingSettings;
 
-typedef IMediaSource::ReadOptions::SeekMode MediaPlayerSeekMode;
+typedef MediaSource::ReadOptions::SeekMode MediaPlayerSeekMode;
 
 class IMediaPlayer: public IInterface
 {
@@ -131,6 +131,11 @@
     virtual status_t        getMetadata(bool update_only,
                                         bool apply_filter,
                                         Parcel *metadata) = 0;
+
+    // AudioRouting
+    virtual status_t        setOutputDevice(audio_port_handle_t deviceId) = 0;
+    virtual status_t        getRoutedDeviceId(audio_port_handle_t *deviceId) = 0;
+    virtual status_t        enableAudioDeviceCallback(bool enabled) = 0;
 };
 
 // ----------------------------------------------------------------------------
diff --git a/media/libmedia/include/media/IMediaSource.h b/media/libmedia/include/media/IMediaSource.h
index 2bde782..7aea90c 100644
--- a/media/libmedia/include/media/IMediaSource.h
+++ b/media/libmedia/include/media/IMediaSource.h
@@ -22,12 +22,12 @@
 
 #include <binder/IInterface.h>
 #include <binder/IMemory.h>
+#include <media/MediaSource.h>
 #include <media/stagefright/MediaBuffer.h>
 #include <media/stagefright/MediaErrors.h>
 
 namespace android {
 
-struct MediaSource;
 class MetaData;
 class MediaBufferGroup;
 
@@ -55,51 +55,6 @@
     // Returns the format of the data output by this media source.
     virtual sp<MetaData> getFormat() = 0;
 
-    // Options that modify read() behaviour. The default is to
-    // a) not request a seek
-    // b) not be late, i.e. lateness_us = 0
-    struct ReadOptions {
-        enum SeekMode : int32_t {
-            SEEK_PREVIOUS_SYNC,
-            SEEK_NEXT_SYNC,
-            SEEK_CLOSEST_SYNC,
-            SEEK_CLOSEST,
-        };
-
-        ReadOptions();
-
-        // Reset everything back to defaults.
-        void reset();
-
-        void setSeekTo(int64_t time_us, SeekMode mode = SEEK_CLOSEST_SYNC);
-        void clearSeekTo();
-        bool getSeekTo(int64_t *time_us, SeekMode *mode) const;
-
-        // TODO: remove this if unused.
-        void setLateBy(int64_t lateness_us);
-        int64_t getLateBy() const;
-
-        void setNonBlocking();
-        void clearNonBlocking();
-        bool getNonBlocking() const;
-
-        // Used to clear all non-persistent options for multiple buffer reads.
-        void clearNonPersistent() {
-            clearSeekTo();
-        }
-
-    private:
-        enum Options {
-            kSeekTo_Option      = 1,
-        };
-
-        uint32_t mOptions;
-        int64_t mSeekTimeUs;
-        SeekMode mSeekMode;
-        int64_t mLatenessUs;
-        bool mNonBlocking;
-    } __attribute__((packed)); // sent through Binder
-
     // Returns a new buffer of data. Call blocks until a
     // buffer is available, an error is encountered or the end of the stream
     // is reached.
@@ -110,7 +65,8 @@
     //
     // TODO: consider removing read() in favor of readMultiple().
     virtual status_t read(
-            MediaBuffer **buffer, const ReadOptions *options = NULL) = 0;
+            MediaBuffer **buffer,
+            const MediaSource::ReadOptions *options = NULL) = 0;
 
     // Returns a vector of new buffers of data, where the new buffers are added
     // to the end of the vector.
@@ -126,7 +82,7 @@
     // non-persistent options (e.g. seek) apply only to the first read.
     virtual status_t readMultiple(
             Vector<MediaBuffer *> *buffers, uint32_t maxNumBuffers = 1,
-            const ReadOptions *options = nullptr) = 0;
+            const MediaSource::ReadOptions *options = nullptr) = 0;
 
     // Returns true if |readMultiple| is supported, otherwise false.
     virtual bool supportReadMultiple() = 0;
@@ -168,7 +124,7 @@
     // TODO: Implement this for local media sources.
     virtual status_t readMultiple(
             Vector<MediaBuffer *> * /* buffers */, uint32_t /* maxNumBuffers = 1 */,
-            const ReadOptions * /* options = nullptr */) {
+            const MediaSource::ReadOptions * /* options = nullptr */) {
         return ERROR_UNSUPPORTED;
     }
 
diff --git a/media/libmedia/include/media/IOMXStore.h b/media/libmedia/include/media/IOMXStore.h
deleted file mode 100644
index 628db70..0000000
--- a/media/libmedia/include/media/IOMXStore.h
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Copyright (C) 2009 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_IOMXSTORE_H_
-
-#define ANDROID_IOMXSTORE_H_
-
-#include <media/IOMX.h>
-#include <android/hardware/media/omx/1.0/IOmxStore.h>
-
-#include <binder/IInterface.h>
-#include <binder/IBinder.h>
-
-#include <vector>
-#include <string>
-
-namespace android {
-
-using hardware::media::omx::V1_0::IOmxStore;
-
-class IOMXStore : public IInterface {
-public:
-    DECLARE_META_INTERFACE(OMXStore);
-
-    struct Attribute {
-        std::string key;
-        std::string value;
-    };
-
-    struct NodeInfo {
-        std::string name;
-        std::string owner;
-        std::vector<Attribute> attributes;
-    };
-
-    struct RoleInfo {
-        std::string role;
-        std::string type;
-        bool isEncoder;
-        bool preferPlatformNodes;
-        std::vector<NodeInfo> nodes;
-    };
-
-    virtual status_t listServiceAttributes(
-            std::vector<Attribute>* attributes) = 0;
-
-    virtual status_t getNodePrefix(std::string* prefix) = 0;
-
-    virtual status_t listRoles(std::vector<RoleInfo>* roleList) = 0;
-
-    virtual status_t getOmx(const std::string& name, sp<IOMX>* omx) = 0;
-};
-
-
-////////////////////////////////////////////////////////////////////////////////
-
-class BnOMXStore : public BnInterface<IOMXStore> {
-public:
-    virtual status_t onTransact(
-            uint32_t code, const Parcel &data, Parcel *reply,
-            uint32_t flags = 0);
-};
-
-}  // namespace android
-
-#endif  // ANDROID_IOMX_H_
diff --git a/media/libmedia/include/media/MediaMetadataRetrieverInterface.h b/media/libmedia/include/media/MediaMetadataRetrieverInterface.h
index 257002d..fc9e53c 100644
--- a/media/libmedia/include/media/MediaMetadataRetrieverInterface.h
+++ b/media/libmedia/include/media/MediaMetadataRetrieverInterface.h
@@ -22,6 +22,7 @@
 #include <media/mediametadataretriever.h>
 #include <media/mediascanner.h>
 #include <private/media/VideoFrame.h>
+#include <media/stagefright/MediaErrors.h>
 
 namespace android {
 
@@ -41,9 +42,14 @@
             const KeyedVector<String8, String8> *headers = NULL) = 0;
 
     virtual status_t    setDataSource(int fd, int64_t offset, int64_t length) = 0;
-    virtual status_t setDataSource(const sp<DataSource>& source, const char *mime) = 0;
+    virtual status_t    setDataSource(const sp<DataSource>& source, const char *mime) = 0;
     virtual VideoFrame* getFrameAtTime(
             int64_t timeUs, int option, int colorFormat, bool metaOnly) = 0;
+    virtual VideoFrame* getImageAtIndex(
+            int index, int colorFormat, bool metaOnly) = 0;
+    virtual status_t getFrameAtIndex(
+            std::vector<VideoFrame*>* frames,
+            int frameIndex, int numFrames, int colorFormat, bool metaOnly);
     virtual MediaAlbumArt* extractAlbumArt() = 0;
     virtual const char* extractMetadata(int keyCode) = 0;
 };
@@ -58,6 +64,13 @@
     virtual VideoFrame* getFrameAtTime(
             int64_t /*timeUs*/, int /*option*/, int /*colorFormat*/, bool /*metaOnly*/)
     { return NULL; }
+    virtual VideoFrame* getImageAtIndex(
+            int /*index*/, int /*colorFormat*/, bool /*metaOnly*/)
+    { return NULL; }
+    virtual status_t getFrameAtIndex(
+            std::vector<VideoFrame*>* /*frames*/,
+            int /*frameIndex*/, int /*numFrames*/, int /*colorFormat*/, bool /*metaOnly*/)
+    { return ERROR_UNSUPPORTED; }
     virtual MediaAlbumArt* extractAlbumArt() { return NULL; }
     virtual const char* extractMetadata(int /*keyCode*/) { return NULL; }
 };
diff --git a/media/libmedia/include/media/MidiIoWrapper.h b/media/libmedia/include/media/MidiIoWrapper.h
index e6f8cf7..2754b2c 100644
--- a/media/libmedia/include/media/MidiIoWrapper.h
+++ b/media/libmedia/include/media/MidiIoWrapper.h
@@ -19,7 +19,7 @@
 
 #include <libsonivox/eas_types.h>
 
-#include "media/stagefright/DataSource.h"
+#include <media/DataSource.h>
 
 namespace android {
 
diff --git a/media/libmedia/include/media/mediametadataretriever.h b/media/libmedia/include/media/mediametadataretriever.h
index 65c266b..3511253 100644
--- a/media/libmedia/include/media/mediametadataretriever.h
+++ b/media/libmedia/include/media/mediametadataretriever.h
@@ -59,6 +59,13 @@
     METADATA_KEY_LOCATION        = 23,
     METADATA_KEY_VIDEO_ROTATION  = 24,
     METADATA_KEY_CAPTURE_FRAMERATE = 25,
+    METADATA_KEY_HAS_IMAGE       = 26,
+    METADATA_KEY_IMAGE_COUNT     = 27,
+    METADATA_KEY_IMAGE_PRIMARY   = 28,
+    METADATA_KEY_IMAGE_WIDTH     = 29,
+    METADATA_KEY_IMAGE_HEIGHT    = 30,
+    METADATA_KEY_IMAGE_ROTATION  = 31,
+    METADATA_KEY_VIDEO_FRAME_COUNT  = 32,
 
     // Add more here...
 };
@@ -80,6 +87,11 @@
             const sp<IDataSource>& dataSource, const char *mime = NULL);
     sp<IMemory> getFrameAtTime(int64_t timeUs, int option,
             int colorFormat = HAL_PIXEL_FORMAT_RGB_565, bool metaOnly = false);
+    sp<IMemory> getImageAtIndex(int index,
+            int colorFormat = HAL_PIXEL_FORMAT_RGB_565, bool metaOnly = false);
+    status_t getFrameAtIndex(
+            std::vector<sp<IMemory> > *frames, int frameIndex, int numFrames = 1,
+            int colorFormat = HAL_PIXEL_FORMAT_RGB_565, bool metaOnly = false);
     sp<IMemory> extractAlbumArt();
     const char* extractMetadata(int keyCode);
 
diff --git a/media/libmedia/include/media/mediaplayer.h b/media/libmedia/include/media/mediaplayer.h
index 25741d3..6d39ded 100644
--- a/media/libmedia/include/media/mediaplayer.h
+++ b/media/libmedia/include/media/mediaplayer.h
@@ -57,6 +57,7 @@
     MEDIA_SUBTITLE_DATA     = 201,
     MEDIA_META_DATA         = 202,
     MEDIA_DRM_INFO          = 210,
+    MEDIA_AUDIO_ROUTING_CHANGED = 10000,
 };
 
 // Generic error codes for the media player framework.  Errors are fatal, the
@@ -275,6 +276,10 @@
             // Modular DRM
             status_t        prepareDrm(const uint8_t uuid[16], const Vector<uint8_t>& drmSessionId);
             status_t        releaseDrm();
+            // AudioRouting
+            status_t        setOutputDevice(audio_port_handle_t deviceId);
+            audio_port_handle_t getRoutedDeviceId();
+            status_t        enableAudioDeviceCallback(bool enabled);
 
 private:
             void            clear_l();
diff --git a/media/libmedia/mediametadataretriever.cpp b/media/libmedia/mediametadataretriever.cpp
index 7d27d57..6a4204b 100644
--- a/media/libmedia/mediametadataretriever.cpp
+++ b/media/libmedia/mediametadataretriever.cpp
@@ -154,6 +154,32 @@
     return mRetriever->getFrameAtTime(timeUs, option, colorFormat, metaOnly);
 }
 
+sp<IMemory> MediaMetadataRetriever::getImageAtIndex(
+        int index, int colorFormat, bool metaOnly) {
+    ALOGV("getImageAtIndex: index(%d) colorFormat(%d) metaOnly(%d)",
+            index, colorFormat, metaOnly);
+    Mutex::Autolock _l(mLock);
+    if (mRetriever == 0) {
+        ALOGE("retriever is not initialized");
+        return NULL;
+    }
+    return mRetriever->getImageAtIndex(index, colorFormat, metaOnly);
+}
+
+status_t MediaMetadataRetriever::getFrameAtIndex(
+        std::vector<sp<IMemory> > *frames,
+        int frameIndex, int numFrames, int colorFormat, bool metaOnly) {
+    ALOGV("getFrameAtIndex: frameIndex(%d), numFrames(%d), colorFormat(%d) metaOnly(%d)",
+            frameIndex, numFrames, colorFormat, metaOnly);
+    Mutex::Autolock _l(mLock);
+    if (mRetriever == 0) {
+        ALOGE("retriever is not initialized");
+        return INVALID_OPERATION;
+    }
+    return mRetriever->getFrameAtIndex(
+            frames, frameIndex, numFrames, colorFormat, metaOnly);
+}
+
 const char* MediaMetadataRetriever::extractMetadata(int keyCode)
 {
     ALOGV("extractMetadata(%d)", keyCode);
diff --git a/media/libmedia/mediaplayer.cpp b/media/libmedia/mediaplayer.cpp
index 00084c1..a6cdb13 100644
--- a/media/libmedia/mediaplayer.cpp
+++ b/media/libmedia/mediaplayer.cpp
@@ -1094,4 +1094,39 @@
     return status;
 }
 
+status_t MediaPlayer::setOutputDevice(audio_port_handle_t deviceId)
+{
+    Mutex::Autolock _l(mLock);
+    if (mPlayer == NULL) {
+        ALOGV("setOutputDevice: player not init");
+        return NO_INIT;
+    }
+    return mPlayer->setOutputDevice(deviceId);
+}
+
+audio_port_handle_t MediaPlayer::getRoutedDeviceId()
+{
+    Mutex::Autolock _l(mLock);
+    if (mPlayer == NULL) {
+        ALOGV("getRoutedDeviceId: player not init");
+        return AUDIO_PORT_HANDLE_NONE;
+    }
+    audio_port_handle_t deviceId;
+    status_t status = mPlayer->getRoutedDeviceId(&deviceId);
+    if (status != NO_ERROR) {
+        return AUDIO_PORT_HANDLE_NONE;
+    }
+    return deviceId;
+}
+
+status_t MediaPlayer::enableAudioDeviceCallback(bool enabled)
+{
+    Mutex::Autolock _l(mLock);
+    if (mPlayer == NULL) {
+        ALOGV("addAudioDeviceCallback: player not init");
+        return NO_INIT;
+    }
+    return mPlayer->enableAudioDeviceCallback(enabled);
+}
+
 } // namespace android
diff --git a/media/libmediaextractor/Android.bp b/media/libmediaextractor/Android.bp
new file mode 100644
index 0000000..c57cd41
--- /dev/null
+++ b/media/libmediaextractor/Android.bp
@@ -0,0 +1,42 @@
+cc_library_shared {
+    name: "libmediaextractor",
+    include_dirs: [
+        "frameworks/av/include",
+        "frameworks/av/media/libmediaextractor/include",
+    ],
+
+    export_include_dirs: ["include"],
+
+    cflags: [
+        "-Wno-multichar",
+        "-Werror",
+        "-Wall",
+    ],
+
+    shared_libs: [
+        "libmediametrics",
+        "libstagefright_foundation",
+        "libutils",
+        "libcutils",
+        "liblog",
+    ],
+
+    srcs: [
+        "DataSource.cpp",
+        "MediaSource.cpp",
+        "MediaExtractor.cpp",
+    ],
+
+    clang: true,
+
+    sanitize: {
+        misc_undefined: [
+            "unsigned-integer-overflow",
+            "signed-integer-overflow",
+        ],
+        cfi: true,
+        diag: {
+            cfi: true,
+        },
+    },
+}
diff --git a/media/libmediaextractor/DataSource.cpp b/media/libmediaextractor/DataSource.cpp
new file mode 100644
index 0000000..c22e4cb
--- /dev/null
+++ b/media/libmediaextractor/DataSource.cpp
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2009 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_NDEBUG 0
+#define LOG_TAG "DataSource"
+
+#include <media/DataSource.h>
+#include <media/IDataSource.h>
+#include <media/stagefright/foundation/ByteUtils.h>
+#include <media/stagefright/MediaErrors.h>
+#include <utils/String8.h>
+
+namespace android {
+
+bool DataSource::getUInt16(off64_t offset, uint16_t *x) {
+    *x = 0;
+
+    uint8_t byte[2];
+    if (readAt(offset, byte, 2) != 2) {
+        return false;
+    }
+
+    *x = (byte[0] << 8) | byte[1];
+
+    return true;
+}
+
+bool DataSource::getUInt24(off64_t offset, uint32_t *x) {
+    *x = 0;
+
+    uint8_t byte[3];
+    if (readAt(offset, byte, 3) != 3) {
+        return false;
+    }
+
+    *x = (byte[0] << 16) | (byte[1] << 8) | byte[2];
+
+    return true;
+}
+
+bool DataSource::getUInt32(off64_t offset, uint32_t *x) {
+    *x = 0;
+
+    uint32_t tmp;
+    if (readAt(offset, &tmp, 4) != 4) {
+        return false;
+    }
+
+    *x = ntohl(tmp);
+
+    return true;
+}
+
+bool DataSource::getUInt64(off64_t offset, uint64_t *x) {
+    *x = 0;
+
+    uint64_t tmp;
+    if (readAt(offset, &tmp, 8) != 8) {
+        return false;
+    }
+
+    *x = ntoh64(tmp);
+
+    return true;
+}
+
+bool DataSource::getUInt16Var(off64_t offset, uint16_t *x, size_t size) {
+    if (size == 2) {
+        return getUInt16(offset, x);
+    }
+    if (size == 1) {
+        uint8_t tmp;
+        if (readAt(offset, &tmp, 1) == 1) {
+            *x = tmp;
+            return true;
+        }
+    }
+    return false;
+}
+
+bool DataSource::getUInt32Var(off64_t offset, uint32_t *x, size_t size) {
+    if (size == 4) {
+        return getUInt32(offset, x);
+    }
+    if (size == 2) {
+        uint16_t tmp;
+        if (getUInt16(offset, &tmp)) {
+            *x = tmp;
+            return true;
+        }
+    }
+    return false;
+}
+
+bool DataSource::getUInt64Var(off64_t offset, uint64_t *x, size_t size) {
+    if (size == 8) {
+        return getUInt64(offset, x);
+    }
+    if (size == 4) {
+        uint32_t tmp;
+        if (getUInt32(offset, &tmp)) {
+            *x = tmp;
+            return true;
+        }
+    }
+    return false;
+}
+
+status_t DataSource::getSize(off64_t *size) {
+    *size = 0;
+
+    return ERROR_UNSUPPORTED;
+}
+
+sp<IDataSource> DataSource::getIDataSource() const {
+    return nullptr;
+}
+
+String8 DataSource::getMIMEType() const {
+    return String8("application/octet-stream");
+}
+
+}  // namespace android
diff --git a/media/libmediaextractor/MediaExtractor.cpp b/media/libmediaextractor/MediaExtractor.cpp
new file mode 100644
index 0000000..6ba7c0e
--- /dev/null
+++ b/media/libmediaextractor/MediaExtractor.cpp
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2009 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_NDEBUG 0
+#define LOG_TAG "MediaExtractor"
+#include <utils/Log.h>
+#include <pwd.h>
+
+#include <media/MediaAnalyticsItem.h>
+#include <media/MediaExtractor.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/MetaData.h>
+
+namespace android {
+
+// key for media statistics
+static const char *kKeyExtractor = "extractor";
+
+MediaExtractor::MediaExtractor() {
+    if (!LOG_NDEBUG) {
+        uid_t uid = getuid();
+        struct passwd *pw = getpwuid(uid);
+        ALOGV("extractor created in uid: %d (%s)", getuid(), pw->pw_name);
+    }
+
+    mAnalyticsItem = NULL;
+    if (MEDIA_LOG) {
+        mAnalyticsItem = new MediaAnalyticsItem(kKeyExtractor);
+        (void) mAnalyticsItem->generateSessionID();
+    }
+}
+
+MediaExtractor::~MediaExtractor() {
+
+    // log the current record, provided it has some information worth recording
+    if (MEDIA_LOG) {
+        if (mAnalyticsItem != NULL) {
+            if (mAnalyticsItem->count() > 0) {
+                mAnalyticsItem->setFinalized(true);
+                mAnalyticsItem->selfrecord();
+            }
+        }
+    }
+    if (mAnalyticsItem != NULL) {
+        delete mAnalyticsItem;
+        mAnalyticsItem = NULL;
+    }
+}
+
+sp<MetaData> MediaExtractor::getMetaData() {
+    return new MetaData;
+}
+
+status_t MediaExtractor::getMetrics(Parcel *reply) {
+
+    if (mAnalyticsItem == NULL || reply == NULL) {
+        return UNKNOWN_ERROR;
+    }
+
+    populateMetrics();
+    mAnalyticsItem->writeToParcel(reply);
+
+    return OK;
+}
+
+void MediaExtractor::populateMetrics() {
+    ALOGV("MediaExtractor::populateMetrics");
+    // normally overridden in subclasses
+}
+
+uint32_t MediaExtractor::flags() const {
+    return CAN_SEEK_BACKWARD | CAN_SEEK_FORWARD | CAN_PAUSE | CAN_SEEK;
+}
+
+}  // namespace android
diff --git a/media/libmediaextractor/MediaSource.cpp b/media/libmediaextractor/MediaSource.cpp
new file mode 100644
index 0000000..8038a59
--- /dev/null
+++ b/media/libmediaextractor/MediaSource.cpp
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2009 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.
+ */
+
+#include <media/MediaSource.h>
+#include <media/IMediaSource.h>
+
+namespace android {
+
+MediaSource::MediaSource() {}
+
+MediaSource::~MediaSource() {}
+
+////////////////////////////////////////////////////////////////////////////////
+
+MediaSource::ReadOptions::ReadOptions() {
+    reset();
+}
+
+void MediaSource::ReadOptions::reset() {
+    mOptions = 0;
+    mSeekTimeUs = 0;
+    mLatenessUs = 0;
+    mNonBlocking = false;
+}
+
+void MediaSource::ReadOptions::setNonBlocking() {
+    mNonBlocking = true;
+}
+
+void MediaSource::ReadOptions::clearNonBlocking() {
+    mNonBlocking = false;
+}
+
+bool MediaSource::ReadOptions::getNonBlocking() const {
+    return mNonBlocking;
+}
+
+void MediaSource::ReadOptions::setSeekTo(int64_t time_us, SeekMode mode) {
+    mOptions |= kSeekTo_Option;
+    mSeekTimeUs = time_us;
+    mSeekMode = mode;
+}
+
+void MediaSource::ReadOptions::clearSeekTo() {
+    mOptions &= ~kSeekTo_Option;
+    mSeekTimeUs = 0;
+    mSeekMode = SEEK_CLOSEST_SYNC;
+}
+
+bool MediaSource::ReadOptions::getSeekTo(
+        int64_t *time_us, SeekMode *mode) const {
+    *time_us = mSeekTimeUs;
+    *mode = mSeekMode;
+    return (mOptions & kSeekTo_Option) != 0;
+}
+
+void MediaSource::ReadOptions::setLateBy(int64_t lateness_us) {
+    mLatenessUs = lateness_us;
+}
+
+int64_t MediaSource::ReadOptions::getLateBy() const {
+    return mLatenessUs;
+}
+
+}  // namespace android
diff --git a/media/libstagefright/include/media/stagefright/DataSource.h b/media/libmediaextractor/include/media/DataSource.h
similarity index 89%
rename from media/libstagefright/include/media/stagefright/DataSource.h
rename to media/libmediaextractor/include/media/DataSource.h
index bd863ba..e917f4e 100644
--- a/media/libstagefright/include/media/stagefright/DataSource.h
+++ b/media/libmediaextractor/include/media/DataSource.h
@@ -47,17 +47,6 @@
         kIsLocalFileSource     = 16,
     };
 
-    static sp<DataSource> CreateFromURI(
-            const sp<IMediaHTTPService> &httpService,
-            const char *uri,
-            const KeyedVector<String8, String8> *headers = NULL,
-            String8 *contentType = NULL,
-            HTTPBase *httpSource = NULL);
-
-    static sp<DataSource> CreateMediaHTTP(const sp<IMediaHTTPService> &httpService);
-    static sp<DataSource> CreateFromIDataSource(const sp<IDataSource> &source);
-    static sp<DataSource> CreateFromFd(int fd, int64_t offset, int64_t length);
-
     DataSource() {}
 
     virtual status_t initCheck() const = 0;
@@ -123,9 +112,6 @@
 
     virtual void close() {};
 
-    // creates an IDataSource wrapper to the DataSource.
-    virtual sp<IDataSource> asIDataSource();
-
     // returns a pointer to IDataSource if it is wrapped.
     virtual sp<IDataSource> getIDataSource() const;
 
diff --git a/media/libstagefright/include/media/stagefright/MediaExtractor.h b/media/libmediaextractor/include/media/MediaExtractor.h
similarity index 88%
rename from media/libstagefright/include/media/stagefright/MediaExtractor.h
rename to media/libmediaextractor/include/media/MediaExtractor.h
index 441c6d7..2dcced3 100644
--- a/media/libstagefright/include/media/stagefright/MediaExtractor.h
+++ b/media/libmediaextractor/include/media/MediaExtractor.h
@@ -19,23 +19,29 @@
 #define MEDIA_EXTRACTOR_H_
 
 #include <stdio.h>
+#include <vector>
 
-#include <media/IMediaExtractor.h>
-#include <media/MediaAnalyticsItem.h>
+#include <utils/Errors.h>
+#include <utils/RefBase.h>
+
+// still doing some on/off toggling here.
+#define MEDIA_LOG       1
 
 namespace android {
 
 class DataSource;
-struct MediaSource;
+class IMediaSource;
+class MediaAnalyticsItem;
+class MediaExtractorFactory;
 class MetaData;
+class Parcel;
+class String8;
+struct AMessage;
+struct MediaSource;
+typedef std::vector<uint8_t> HInterfaceToken;
 
 class MediaExtractor : public RefBase {
 public:
-    static sp<IMediaExtractor> Create(
-            const sp<DataSource> &source, const char *mime = NULL);
-    static sp<MediaExtractor> CreateFromService(
-            const sp<DataSource> &source, const char *mime = NULL);
-
     virtual size_t countTracks() = 0;
     virtual sp<MediaSource> getTrack(size_t index) = 0;
 
@@ -62,9 +68,6 @@
     // CAN_SEEK_BACKWARD | CAN_SEEK_FORWARD | CAN_SEEK | CAN_PAUSE
     virtual uint32_t flags() const;
 
-    // Creates an IMediaExtractor wrapper to this MediaExtractor.
-    virtual sp<IMediaExtractor> asIMediaExtractor();
-
     // for DRM
     virtual char* getDrmTrackInfo(size_t /*trackID*/, int * /*len*/) {
         return NULL;
@@ -125,20 +128,9 @@
     virtual void populateMetrics();
 
 private:
-
-    static Mutex gSnifferMutex;
-    static List<ExtractorDef> gSniffers;
-    static bool gSniffersRegistered;
-
-    static void RegisterSniffer_l(const ExtractorDef &def);
-
-    static CreatorFunc sniff(const sp<DataSource> &source,
-            String8 *mimeType, float *confidence, sp<AMessage> *meta);
-
-    static void RegisterDefaultSniffers();
-
     MediaExtractor(const MediaExtractor &);
     MediaExtractor &operator=(const MediaExtractor &);
+    friend class MediaExtractorFactory;
 };
 
 // purposely not defined anywhere so that this will fail to link if
diff --git a/media/libstagefright/include/media/stagefright/MediaSource.h b/media/libmediaextractor/include/media/MediaSource.h
similarity index 76%
rename from media/libstagefright/include/media/stagefright/MediaSource.h
rename to media/libmediaextractor/include/media/MediaSource.h
index 7e30e30..504653b 100644
--- a/media/libstagefright/include/media/stagefright/MediaSource.h
+++ b/media/libmediaextractor/include/media/MediaSource.h
@@ -20,7 +20,8 @@
 
 #include <sys/types.h>
 
-#include <media/IMediaSource.h>
+#include <binder/IMemory.h>
+#include <binder/MemoryDealer.h>
 #include <media/stagefright/MediaErrors.h>
 #include <media/stagefright/MetaData.h>
 #include <utils/RefBase.h>
@@ -33,15 +34,6 @@
 class IMediaSource;
 
 struct MediaSource : public virtual RefBase {
-    // TODO: Move ReadOptions implementation from IMediaSource to MediaSource
-    // once this class moves to a separate extractor lib on which both libmedia
-    // and libstagefright rely. For now, alias is added to avoid circular
-    // dependency.
-    using ReadOptions = IMediaSource::ReadOptions;
-
-    // Creates a MediaSource which wraps the given IMediaSource object.
-    static sp<MediaSource> CreateFromIMediaSource(const sp<IMediaSource> &source);
-
     MediaSource();
 
     // To be called before any other methods on this object, except
@@ -59,6 +51,52 @@
     // Returns the format of the data output by this media source.
     virtual sp<MetaData> getFormat() = 0;
 
+    // Options that modify read() behaviour. The default is to
+    // a) not request a seek
+    // b) not be late, i.e. lateness_us = 0
+    struct ReadOptions {
+        enum SeekMode : int32_t {
+            SEEK_PREVIOUS_SYNC,
+            SEEK_NEXT_SYNC,
+            SEEK_CLOSEST_SYNC,
+            SEEK_CLOSEST,
+            SEEK_FRAME_INDEX,
+        };
+
+        ReadOptions();
+
+        // Reset everything back to defaults.
+        void reset();
+
+        void setSeekTo(int64_t time_us, SeekMode mode = SEEK_CLOSEST_SYNC);
+        void clearSeekTo();
+        bool getSeekTo(int64_t *time_us, SeekMode *mode) const;
+
+        // TODO: remove this if unused.
+        void setLateBy(int64_t lateness_us);
+        int64_t getLateBy() const;
+
+        void setNonBlocking();
+        void clearNonBlocking();
+        bool getNonBlocking() const;
+
+        // Used to clear all non-persistent options for multiple buffer reads.
+        void clearNonPersistent() {
+            clearSeekTo();
+        }
+
+    private:
+        enum Options {
+            kSeekTo_Option      = 1,
+        };
+
+        uint32_t mOptions;
+        int64_t mSeekTimeUs;
+        SeekMode mSeekMode;
+        int64_t mLatenessUs;
+        bool mNonBlocking;
+    } __attribute__((packed)); // sent through Binder
+
     // Returns a new buffer of data. Call blocks until a
     // buffer is available, an error is encountered of the end of the stream
     // is reached.
@@ -103,9 +141,6 @@
         return ERROR_UNSUPPORTED;
     }
 
-    // Creates an IMediaSource wrapper to this MediaSource.
-    virtual sp<IMediaSource> asIMediaSource();
-
 protected:
     virtual ~MediaSource();
 
diff --git a/media/libmediametrics/MediaAnalyticsItem.cpp b/media/libmediametrics/MediaAnalyticsItem.cpp
index f968c09..f7df2b4 100644
--- a/media/libmediametrics/MediaAnalyticsItem.cpp
+++ b/media/libmediametrics/MediaAnalyticsItem.cpp
@@ -279,8 +279,10 @@
         prop = &mProps[i];
     } else {
         if (i == mPropSize) {
-            growProps();
-            // XXX: verify success
+            if (growProps() == false) {
+                ALOGE("failed allocation for new props");
+                return NULL;
+            }
         }
         i = mPropCount++;
         prop = &mProps[i];
@@ -312,41 +314,54 @@
 // set the values
 void MediaAnalyticsItem::setInt32(MediaAnalyticsItem::Attr name, int32_t value) {
     Prop *prop = allocateProp(name);
-    prop->mType = kTypeInt32;
-    prop->u.int32Value = value;
+    if (prop != NULL) {
+        prop->mType = kTypeInt32;
+        prop->u.int32Value = value;
+    }
 }
 
 void MediaAnalyticsItem::setInt64(MediaAnalyticsItem::Attr name, int64_t value) {
     Prop *prop = allocateProp(name);
-    prop->mType = kTypeInt64;
-    prop->u.int64Value = value;
+    if (prop != NULL) {
+        prop->mType = kTypeInt64;
+        prop->u.int64Value = value;
+    }
 }
 
 void MediaAnalyticsItem::setDouble(MediaAnalyticsItem::Attr name, double value) {
     Prop *prop = allocateProp(name);
-    prop->mType = kTypeDouble;
-    prop->u.doubleValue = value;
+    if (prop != NULL) {
+        prop->mType = kTypeDouble;
+        prop->u.doubleValue = value;
+    }
 }
 
 void MediaAnalyticsItem::setCString(MediaAnalyticsItem::Attr name, const char *value) {
 
     Prop *prop = allocateProp(name);
     // any old value will be gone
-    prop->mType = kTypeCString;
-    prop->u.CStringValue = strdup(value);
+    if (prop != NULL) {
+        prop->mType = kTypeCString;
+        prop->u.CStringValue = strdup(value);
+    }
 }
 
 void MediaAnalyticsItem::setRate(MediaAnalyticsItem::Attr name, int64_t count, int64_t duration) {
     Prop *prop = allocateProp(name);
-    prop->mType = kTypeRate;
-    prop->u.rate.count = count;
-    prop->u.rate.duration = duration;
+    if (prop != NULL) {
+        prop->mType = kTypeRate;
+        prop->u.rate.count = count;
+        prop->u.rate.duration = duration;
+    }
 }
 
 
 // find/add/set fused into a single operation
 void MediaAnalyticsItem::addInt32(MediaAnalyticsItem::Attr name, int32_t value) {
     Prop *prop = allocateProp(name);
+    if (prop == NULL) {
+        return;
+    }
     switch (prop->mType) {
         case kTypeInt32:
             prop->u.int32Value += value;
@@ -361,6 +376,9 @@
 
 void MediaAnalyticsItem::addInt64(MediaAnalyticsItem::Attr name, int64_t value) {
     Prop *prop = allocateProp(name);
+    if (prop == NULL) {
+        return;
+    }
     switch (prop->mType) {
         case kTypeInt64:
             prop->u.int64Value += value;
@@ -375,6 +393,9 @@
 
 void MediaAnalyticsItem::addRate(MediaAnalyticsItem::Attr name, int64_t count, int64_t duration) {
     Prop *prop = allocateProp(name);
+    if (prop == NULL) {
+        return;
+    }
     switch (prop->mType) {
         case kTypeRate:
             prop->u.rate.count += count;
@@ -391,6 +412,9 @@
 
 void MediaAnalyticsItem::addDouble(MediaAnalyticsItem::Attr name, double value) {
     Prop *prop = allocateProp(name);
+    if (prop == NULL) {
+        return;
+    }
     switch (prop->mType) {
         case kTypeDouble:
             prop->u.doubleValue += value;
@@ -585,7 +609,7 @@
     }
 }
 
-void MediaAnalyticsItem::growProps(int increment)
+bool MediaAnalyticsItem::growProps(int increment)
 {
     if (increment <= 0) {
         increment = kGrowProps;
@@ -599,6 +623,10 @@
         }
         mProps = ni;
         mPropSize = nsize;
+        return true;
+    } else {
+        ALOGW("MediaAnalyticsItem::growProps fails");
+        return false;
     }
 }
 
@@ -963,32 +991,26 @@
     int nattr = incoming->mPropCount;
     for (int i = 0 ; i < nattr; i++ ) {
         Prop *iprop = &incoming->mProps[i];
-        Prop *oprop = findProp(iprop->mName);
         const char *p = iprop->mName;
         size_t len = strlen(p);
-        char semantic = p[len-1];
+
+        // should ignore a zero length name...
+        if (len == 0) {
+            continue;
+        }
+
+        Prop *oprop = findProp(iprop->mName);
 
         if (oprop == NULL) {
             // no oprop, so we insert the new one
             oprop = allocateProp(p);
-            copyProp(oprop, iprop);
-        } else {
-            // merge iprop into oprop
-            switch (semantic) {
-                case '<':       // first  aka keep old)
-                    /* nop */
-                    break;
-
-                default:        // default is 'last'
-                case '>':       // last (aka keep new)
-                    copyProp(oprop, iprop);
-                    break;
-
-                case '+':       /* sum */
-                    // XXX validate numeric types, sum in place
-                    break;
-
+            if (oprop != NULL) {
+                copyProp(oprop, iprop);
+            } else {
+                ALOGW("dropped property '%s'", iprop->mName);
             }
+        } else {
+            copyProp(oprop, iprop);
         }
     }
 
diff --git a/media/libmediametrics/include/MediaAnalyticsItem.h b/media/libmediametrics/include/MediaAnalyticsItem.h
index dd7452f..5f9b916 100644
--- a/media/libmediametrics/include/MediaAnalyticsItem.h
+++ b/media/libmediametrics/include/MediaAnalyticsItem.h
@@ -243,7 +243,7 @@
         enum {
             kGrowProps = 10
         };
-        void growProps(int increment = kGrowProps);
+        bool growProps(int increment = kGrowProps);
         size_t findPropIndex(const char *name, size_t len);
         Prop *findProp(const char *name);
         Prop *allocateProp(const char *name);
diff --git a/media/libmediaplayerservice/Android.bp b/media/libmediaplayerservice/Android.bp
index fee3df6..a37973b 100644
--- a/media/libmediaplayerservice/Android.bp
+++ b/media/libmediaplayerservice/Android.bp
@@ -23,6 +23,8 @@
         "libhidlmemory",
         "liblog",
         "libmedia",
+        "libmedia_omx",
+        "libmediaextractor",
         "libmediadrm",
         "libmediametrics",
         "libmediautils",
diff --git a/media/libmediaplayerservice/MediaPlayerFactory.cpp b/media/libmediaplayerservice/MediaPlayerFactory.cpp
index 6da1ec1..055d5ab 100644
--- a/media/libmediaplayerservice/MediaPlayerFactory.cpp
+++ b/media/libmediaplayerservice/MediaPlayerFactory.cpp
@@ -20,8 +20,8 @@
 #include <utils/Log.h>
 
 #include <cutils/properties.h>
+#include <media/DataSource.h>
 #include <media/IMediaPlayer.h>
-#include <media/stagefright/DataSource.h>
 #include <media/stagefright/FileSource.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <utils/Errors.h>
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index 07dff50..34df384 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -55,6 +55,7 @@
 #include <media/Metadata.h>
 #include <media/AudioTrack.h>
 #include <media/MemoryLeakTrackUtil.h>
+#include <media/stagefright/InterfaceUtils.h>
 #include <media/stagefright/MediaCodecList.h>
 #include <media/stagefright/MediaErrors.h>
 #include <media/stagefright/Utils.h>
@@ -581,17 +582,15 @@
 MediaPlayerService::Client::~Client()
 {
     ALOGV("Client(%d) destructor pid = %d", mConnId, mPid);
-    {
-        Mutex::Autolock l(mLock);
-        mAudioOutput.clear();
-    }
+    mAudioOutput.clear();
     wp<Client> client(this);
     disconnect();
     mService->removeClient(client);
     if (mAudioAttributes != NULL) {
         free(mAudioAttributes);
     }
-    clearDeathNotifiers();
+    clearDeathNotifiers_l();
+    mAudioDeviceUpdatedListener.clear();
 }
 
 void MediaPlayerService::Client::disconnect()
@@ -619,7 +618,10 @@
         p->reset();
     }
 
-    disconnectNativeWindow();
+    {
+        Mutex::Autolock l(mLock);
+        disconnectNativeWindow_l();
+    }
 
     IPCThreadState::self()->flushCommands();
 }
@@ -696,7 +698,18 @@
     }
 }
 
-void MediaPlayerService::Client::clearDeathNotifiers() {
+void MediaPlayerService::Client::AudioDeviceUpdatedNotifier::onAudioDeviceUpdate(
+        audio_io_handle_t audioIo,
+        audio_port_handle_t deviceId) {
+    sp<MediaPlayerBase> listener = mListener.promote();
+    if (listener != NULL) {
+        listener->sendEvent(MEDIA_AUDIO_ROUTING_CHANGED, audioIo, deviceId);
+    } else {
+        ALOGW("listener for process %d death is gone", MEDIA_AUDIO_ROUTING_CHANGED);
+    }
+}
+
+void MediaPlayerService::Client::clearDeathNotifiers_l() {
     if (mExtractorDeathListener != nullptr) {
         mExtractorDeathListener->unlinkToDeath();
         mExtractorDeathListener = nullptr;
@@ -711,7 +724,6 @@
         player_type playerType)
 {
     ALOGV("player type = %d", playerType);
-    clearDeathNotifiers();
 
     // create the right type of player
     sp<MediaPlayerBase> p = createPlayer(playerType);
@@ -725,62 +737,58 @@
         ALOGE("extractor service not available");
         return NULL;
     }
-    mExtractorDeathListener = new ServiceDeathNotifier(binder, p, MEDIAEXTRACTOR_PROCESS_DEATH);
-    binder->linkToDeath(mExtractorDeathListener);
+    sp<ServiceDeathNotifier> extractorDeathListener =
+            new ServiceDeathNotifier(binder, p, MEDIAEXTRACTOR_PROCESS_DEATH);
+    binder->linkToDeath(extractorDeathListener);
 
-    if (property_get_bool("persist.media.treble_omx", true)) {
-        // Treble IOmx
-        sp<IOmx> omx = IOmx::getService();
-        if (omx == nullptr) {
-            ALOGE("Treble IOmx not available");
-            return NULL;
-        }
-        mCodecDeathListener = new ServiceDeathNotifier(omx, p, MEDIACODEC_PROCESS_DEATH);
-        omx->linkToDeath(mCodecDeathListener, 0);
-    } else {
-        // Legacy IOMX
-        binder = sm->getService(String16("media.codec"));
-        if (binder == NULL) {
-            ALOGE("codec service not available");
-            return NULL;
-        }
-        mCodecDeathListener = new ServiceDeathNotifier(binder, p, MEDIACODEC_PROCESS_DEATH);
-        binder->linkToDeath(mCodecDeathListener);
+    sp<IOmx> omx = IOmx::getService();
+    if (omx == nullptr) {
+        ALOGE("IOmx service is not available");
+        return NULL;
     }
+    sp<ServiceDeathNotifier> codecDeathListener =
+            new ServiceDeathNotifier(omx, p, MEDIACODEC_PROCESS_DEATH);
+    omx->linkToDeath(codecDeathListener, 0);
+
+    Mutex::Autolock lock(mLock);
+
+    clearDeathNotifiers_l();
+    mExtractorDeathListener = extractorDeathListener;
+    mCodecDeathListener = codecDeathListener;
+    mAudioDeviceUpdatedListener = new AudioDeviceUpdatedNotifier(p);
 
     if (!p->hardwareOutput()) {
-        Mutex::Autolock l(mLock);
         mAudioOutput = new AudioOutput(mAudioSessionId, IPCThreadState::self()->getCallingUid(),
-                mPid, mAudioAttributes);
+                mPid, mAudioAttributes, mAudioDeviceUpdatedListener);
         static_cast<MediaPlayerInterface*>(p.get())->setAudioSink(mAudioOutput);
     }
 
     return p;
 }
 
-void MediaPlayerService::Client::setDataSource_post(
+status_t MediaPlayerService::Client::setDataSource_post(
         const sp<MediaPlayerBase>& p,
         status_t status)
 {
     ALOGV(" setDataSource");
-    mStatus = status;
-    if (mStatus != OK) {
-        ALOGE("  error: %d", mStatus);
-        return;
+    if (status != OK) {
+        ALOGE("  error: %d", status);
+        return status;
     }
 
     // Set the re-transmission endpoint if one was chosen.
     if (mRetransmitEndpointValid) {
-        mStatus = p->setRetransmitEndpoint(&mRetransmitEndpoint);
-        if (mStatus != NO_ERROR) {
-            ALOGE("setRetransmitEndpoint error: %d", mStatus);
+        status = p->setRetransmitEndpoint(&mRetransmitEndpoint);
+        if (status != NO_ERROR) {
+            ALOGE("setRetransmitEndpoint error: %d", status);
         }
     }
 
-    if (mStatus == OK) {
-        Mutex::Autolock l(mLock);
+    if (status == OK) {
+        Mutex::Autolock lock(mLock);
         mPlayer = p;
     }
+    return status;
 }
 
 status_t MediaPlayerService::Client::setDataSource(
@@ -811,9 +819,9 @@
             ALOGE("Couldn't open fd for %s", url);
             return UNKNOWN_ERROR;
         }
-        setDataSource(fd, 0, 0x7fffffffffLL); // this sets mStatus
+        status_t status = setDataSource(fd, 0, 0x7fffffffffLL); // this sets mStatus
         close(fd);
-        return mStatus;
+        return mStatus = status;
     } else {
         player_type playerType = MediaPlayerFactory::getPlayerType(this, url);
         sp<MediaPlayerBase> p = setDataSource_pre(playerType);
@@ -821,8 +829,9 @@
             return NO_INIT;
         }
 
-        setDataSource_post(p, p->setDataSource(httpService, url, headers));
-        return mStatus;
+        return mStatus =
+                setDataSource_post(
+                p, p->setDataSource(httpService, url, headers));
     }
 }
 
@@ -862,8 +871,7 @@
     }
 
     // now set data source
-    setDataSource_post(p, p->setDataSource(fd, offset, length));
-    return mStatus;
+    return mStatus = setDataSource_post(p, p->setDataSource(fd, offset, length));
 }
 
 status_t MediaPlayerService::Client::setDataSource(
@@ -876,24 +884,22 @@
     }
 
     // now set data source
-    setDataSource_post(p, p->setDataSource(source));
-    return mStatus;
+    return mStatus = setDataSource_post(p, p->setDataSource(source));
 }
 
 status_t MediaPlayerService::Client::setDataSource(
         const sp<IDataSource> &source) {
-    sp<DataSource> dataSource = DataSource::CreateFromIDataSource(source);
+    sp<DataSource> dataSource = CreateDataSourceFromIDataSource(source);
     player_type playerType = MediaPlayerFactory::getPlayerType(this, dataSource);
     sp<MediaPlayerBase> p = setDataSource_pre(playerType);
     if (p == NULL) {
         return NO_INIT;
     }
     // now set data source
-    setDataSource_post(p, p->setDataSource(dataSource));
-    return mStatus;
+    return mStatus = setDataSource_post(p, p->setDataSource(dataSource));
 }
 
-void MediaPlayerService::Client::disconnectNativeWindow() {
+void MediaPlayerService::Client::disconnectNativeWindow_l() {
     if (mConnectedWindow != NULL) {
         status_t err = nativeWindowDisconnect(
                 mConnectedWindow.get(), "disconnectNativeWindow");
@@ -930,7 +936,8 @@
             // ANW, which may result in errors.
             reset();
 
-            disconnectNativeWindow();
+            Mutex::Autolock lock(mLock);
+            disconnectNativeWindow_l();
 
             return err;
         }
@@ -941,14 +948,22 @@
     // on the disconnected ANW, which may result in errors.
     status_t err = p->setVideoSurfaceTexture(bufferProducer);
 
-    disconnectNativeWindow();
-
-    mConnectedWindow = anw;
+    mLock.lock();
+    disconnectNativeWindow_l();
 
     if (err == OK) {
+        mConnectedWindow = anw;
         mConnectedWindowBinder = binder;
+        mLock.unlock();
     } else {
-        disconnectNativeWindow();
+        mLock.unlock();
+        status_t err = nativeWindowDisconnect(
+                anw.get(), "disconnectNativeWindow");
+
+        if (err != OK) {
+            ALOGW("nativeWindowDisconnect returned an error: %s (%d)",
+                    strerror(-err), err);
+        }
     }
 
     return err;
@@ -1374,9 +1389,11 @@
     if (p != 0) return INVALID_OPERATION;
 
     if (NULL != endpoint) {
+        Mutex::Autolock lock(mLock);
         mRetransmitEndpoint = *endpoint;
         mRetransmitEndpointValid = true;
     } else {
+        Mutex::Autolock lock(mLock);
         mRetransmitEndpointValid = false;
     }
 
@@ -1394,6 +1411,7 @@
     if (p != NULL)
         return p->getRetransmitEndpoint(endpoint);
 
+    Mutex::Autolock lock(mLock);
     if (!mRetransmitEndpointValid)
         return NO_INIT;
 
@@ -1511,6 +1529,42 @@
     return ret;
 }
 
+status_t MediaPlayerService::Client::setOutputDevice(audio_port_handle_t deviceId)
+{
+    ALOGV("[%d] setOutputDevice", mConnId);
+    {
+        Mutex::Autolock l(mLock);
+        if (mAudioOutput.get() != nullptr) {
+            return mAudioOutput->setOutputDevice(deviceId);
+        }
+    }
+    return NO_INIT;
+}
+
+status_t MediaPlayerService::Client::getRoutedDeviceId(audio_port_handle_t* deviceId)
+{
+    ALOGV("[%d] getRoutedDeviceId", mConnId);
+    {
+        Mutex::Autolock l(mLock);
+        if (mAudioOutput.get() != nullptr) {
+            return mAudioOutput->getRoutedDeviceId(deviceId);
+        }
+    }
+    return NO_INIT;
+}
+
+status_t MediaPlayerService::Client::enableAudioDeviceCallback(bool enabled)
+{
+    ALOGV("[%d] enableAudioDeviceCallback, %d", mConnId, enabled);
+    {
+        Mutex::Autolock l(mLock);
+        if (mAudioOutput.get() != nullptr) {
+            return mAudioOutput->enableAudioDeviceCallback(enabled);
+        }
+    }
+    return NO_INIT;
+}
+
 #if CALLBACK_ANTAGONIZER
 const int Antagonizer::interval = 10000; // 10 msecs
 
@@ -1549,7 +1603,7 @@
 #undef LOG_TAG
 #define LOG_TAG "AudioSink"
 MediaPlayerService::AudioOutput::AudioOutput(audio_session_t sessionId, uid_t uid, int pid,
-        const audio_attributes_t* attr)
+        const audio_attributes_t* attr, const sp<AudioSystem::AudioDeviceCallback>& deviceCallback)
     : mCallback(NULL),
       mCallbackCookie(NULL),
       mCallbackData(NULL),
@@ -1566,7 +1620,10 @@
       mSendLevel(0.0),
       mAuxEffectId(0),
       mFlags(AUDIO_OUTPUT_FLAG_NONE),
-      mVolumeHandler(new media::VolumeHandler())
+      mVolumeHandler(new media::VolumeHandler()),
+      mSelectedDeviceId(AUDIO_PORT_HANDLE_NONE),
+      mDeviceCallbackEnabled(false),
+      mDeviceCallback(deviceCallback)
 {
     ALOGV("AudioOutput(%d)", sessionId);
     if (attr != NULL) {
@@ -1952,7 +2009,9 @@
                     mUid,
                     mPid,
                     mAttributes,
-                    doNotReconnect);
+                    doNotReconnect,
+                    1.0f,  // default value for maxRequiredSpeed
+                    mSelectedDeviceId);
         } else {
             // TODO: Due to buffer memory concerns, we use a max target playback speed
             // based on mPlaybackRate at the time of open (instead of kMaxRequiredSpeed),
@@ -1979,7 +2038,8 @@
                     mPid,
                     mAttributes,
                     doNotReconnect,
-                    targetSpeed);
+                    targetSpeed,
+                    mSelectedDeviceId);
         }
 
         if ((t == 0) || (t->initCheck() != NO_ERROR)) {
@@ -2073,6 +2133,10 @@
             res = mTrack->attachAuxEffect(mAuxEffectId);
         }
     }
+    mTrack->setOutputDevice(mSelectedDeviceId);
+    if (mDeviceCallbackEnabled) {
+        mTrack->addAudioDeviceCallback(mDeviceCallback.promote());
+    }
     ALOGV("updateTrack() DONE status %d", res);
     return res;
 }
@@ -2288,6 +2352,45 @@
     return NO_ERROR;
 }
 
+status_t MediaPlayerService::AudioOutput::setOutputDevice(audio_port_handle_t deviceId)
+{
+    ALOGV("setOutputDevice(%d)", deviceId);
+    Mutex::Autolock lock(mLock);
+    mSelectedDeviceId = deviceId;
+    if (mTrack != 0) {
+        return mTrack->setOutputDevice(deviceId);
+    }
+    return NO_ERROR;
+}
+
+status_t MediaPlayerService::AudioOutput::getRoutedDeviceId(audio_port_handle_t* deviceId)
+{
+    ALOGV("getRoutedDeviceId");
+    Mutex::Autolock lock(mLock);
+    if (mTrack != 0) {
+        *deviceId = mTrack->getRoutedDeviceId();
+        return NO_ERROR;
+    }
+    return NO_INIT;
+}
+
+status_t MediaPlayerService::AudioOutput::enableAudioDeviceCallback(bool enabled)
+{
+    ALOGV("enableAudioDeviceCallback, %d", enabled);
+    Mutex::Autolock lock(mLock);
+    mDeviceCallbackEnabled = enabled;
+    if (mTrack != 0) {
+        status_t status;
+        if (enabled) {
+            status = mTrack->addAudioDeviceCallback(mDeviceCallback.promote());
+        } else {
+            status = mTrack->removeAudioDeviceCallback(mDeviceCallback.promote());
+        }
+        return status;
+    }
+    return NO_ERROR;
+}
+
 VolumeShaper::Status MediaPlayerService::AudioOutput::applyVolumeShaper(
                 const sp<VolumeShaper::Configuration>& configuration,
                 const sp<VolumeShaper::Operation>& operation)
diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h
index f1d43a2..7f8ec85 100644
--- a/media/libmediaplayerservice/MediaPlayerService.h
+++ b/media/libmediaplayerservice/MediaPlayerService.h
@@ -78,8 +78,12 @@
         class CallbackData;
 
      public:
-                                AudioOutput(audio_session_t sessionId, uid_t uid, int pid,
-                                        const audio_attributes_t * attr);
+                                AudioOutput(
+                                        audio_session_t sessionId,
+                                        uid_t uid,
+                                        int pid,
+                                        const audio_attributes_t * attr,
+                                        const sp<AudioSystem::AudioDeviceCallback>& deviceCallback);
         virtual                 ~AudioOutput();
 
         virtual bool            ready() const { return mTrack != 0; }
@@ -137,6 +141,11 @@
                                         const sp<media::VolumeShaper::Operation>& operation) override;
         virtual sp<media::VolumeShaper::State> getVolumeShaperState(int id) override;
 
+        // AudioRouting
+        virtual status_t        setOutputDevice(audio_port_handle_t deviceId);
+        virtual status_t        getRoutedDeviceId(audio_port_handle_t* deviceId);
+        virtual status_t        enableAudioDeviceCallback(bool enabled);
+
     private:
         static void             setMinBufferCount();
         static void             CallbackWrapper(
@@ -166,6 +175,9 @@
         int                     mAuxEffectId;
         audio_output_flags_t    mFlags;
         sp<media::VolumeHandler>       mVolumeHandler;
+        audio_port_handle_t     mSelectedDeviceId;
+        bool                    mDeviceCallbackEnabled;
+        wp<AudioSystem::AudioDeviceCallback>        mDeviceCallback;
         mutable Mutex           mLock;
 
         // static variables below not protected by mutex
@@ -361,7 +373,7 @@
 
 
         sp<MediaPlayerBase>     setDataSource_pre(player_type playerType);
-        void                    setDataSource_post(const sp<MediaPlayerBase>& p,
+        status_t                setDataSource_post(const sp<MediaPlayerBase>& p,
                                                    status_t status);
 
         static  void            notify(void* cookie, int msg,
@@ -374,6 +386,10 @@
         // Modular DRM
         virtual status_t prepareDrm(const uint8_t uuid[16], const Vector<uint8_t>& drmSessionId);
         virtual status_t releaseDrm();
+        // AudioRouting
+        virtual status_t setOutputDevice(audio_port_handle_t deviceId);
+        virtual status_t getRoutedDeviceId(audio_port_handle_t* deviceId);
+        virtual status_t enableAudioDeviceCallback(bool enabled);
 
     private:
         class ServiceDeathNotifier:
@@ -403,7 +419,22 @@
             wp<MediaPlayerBase> mListener;
         };
 
-        void clearDeathNotifiers();
+        class AudioDeviceUpdatedNotifier: public AudioSystem::AudioDeviceCallback
+        {
+        public:
+            AudioDeviceUpdatedNotifier(const sp<MediaPlayerBase>& listener) {
+                mListener = listener;
+            }
+            ~AudioDeviceUpdatedNotifier() {}
+
+            virtual void onAudioDeviceUpdate(audio_io_handle_t audioIo,
+                                             audio_port_handle_t deviceId);
+
+        private:
+            wp<MediaPlayerBase> mListener;
+        };
+
+        void clearDeathNotifiers_l();
 
         friend class MediaPlayerService;
                                 Client( const sp<MediaPlayerService>& service,
@@ -432,7 +463,7 @@
         void addNewMetadataUpdate(media::Metadata::Type type);
 
         // Disconnect from the currently connected ANativeWindow.
-        void disconnectNativeWindow();
+        void disconnectNativeWindow_l();
 
         status_t setAudioAttributes_l(const Parcel &request);
 
@@ -466,6 +497,7 @@
 
         sp<ServiceDeathNotifier> mExtractorDeathListener;
         sp<ServiceDeathNotifier> mCodecDeathListener;
+        sp<AudioDeviceUpdatedNotifier> mAudioDeviceUpdatedListener;
 #if CALLBACK_ANTAGONIZER
                     Antagonizer*                mAntagonizer;
 #endif
diff --git a/media/libmediaplayerservice/MediaRecorderClient.cpp b/media/libmediaplayerservice/MediaRecorderClient.cpp
index 6400481..a423fee 100644
--- a/media/libmediaplayerservice/MediaRecorderClient.cpp
+++ b/media/libmediaplayerservice/MediaRecorderClient.cpp
@@ -339,7 +339,7 @@
         wp<MediaRecorderClient> client(this);
         mMediaPlayerService->removeMediaRecorderClient(client);
     }
-    clearDeathNotifiers();
+    clearDeathNotifiers_l();
     return NO_ERROR;
 }
 
@@ -411,7 +411,7 @@
     }
 }
 
-void MediaRecorderClient::clearDeathNotifiers() {
+void MediaRecorderClient::clearDeathNotifiers_l() {
     if (mCameraDeathListener != nullptr) {
         mCameraDeathListener->unlinkToDeath();
         mCameraDeathListener = nullptr;
@@ -425,8 +425,8 @@
 status_t MediaRecorderClient::setListener(const sp<IMediaRecorderClient>& listener)
 {
     ALOGV("setListener");
-    clearDeathNotifiers();
     Mutex::Autolock lock(mLock);
+    clearDeathNotifiers_l();
     if (mRecorder == NULL) {
         ALOGE("recorder is not initialized");
         return NO_INIT;
@@ -450,27 +450,14 @@
     }
     sCameraChecked = true;
 
-    if (property_get_bool("persist.media.treble_omx", true)) {
-        // Treble IOmx
-        sp<IOmx> omx = IOmx::getService();
-        if (omx == nullptr) {
-            ALOGE("Treble IOmx not available");
-            return NO_INIT;
-        }
-        mCodecDeathListener = new ServiceDeathNotifier(omx, listener,
-                MediaPlayerService::MEDIACODEC_PROCESS_DEATH);
-        omx->linkToDeath(mCodecDeathListener, 0);
-    } else {
-        // Legacy IOMX
-        binder = sm->getService(String16("media.codec"));
-        if (binder == NULL) {
-           ALOGE("Unable to connect to media codec service");
-           return NO_INIT;
-        }
-        mCodecDeathListener = new ServiceDeathNotifier(binder, listener,
-                MediaPlayerService::MEDIACODEC_PROCESS_DEATH);
-        binder->linkToDeath(mCodecDeathListener);
+    sp<IOmx> omx = IOmx::getService();
+    if (omx == nullptr) {
+        ALOGE("IOmx service is not available");
+        return NO_INIT;
     }
+    mCodecDeathListener = new ServiceDeathNotifier(omx, listener,
+            MediaPlayerService::MEDIACODEC_PROCESS_DEATH);
+    omx->linkToDeath(mCodecDeathListener, 0);
 
     return OK;
 }
diff --git a/media/libmediaplayerservice/MediaRecorderClient.h b/media/libmediaplayerservice/MediaRecorderClient.h
index 7868a91..711db2c 100644
--- a/media/libmediaplayerservice/MediaRecorderClient.h
+++ b/media/libmediaplayerservice/MediaRecorderClient.h
@@ -58,7 +58,7 @@
         wp<IMediaRecorderClient> mListener;
     };
 
-    void clearDeathNotifiers();
+    void clearDeathNotifiers_l();
 
 public:
     virtual     status_t   setCamera(const sp<hardware::ICamera>& camera,
diff --git a/media/libmediaplayerservice/MetadataRetrieverClient.cpp b/media/libmediaplayerservice/MetadataRetrieverClient.cpp
index 5a468f3..16ed530 100644
--- a/media/libmediaplayerservice/MetadataRetrieverClient.cpp
+++ b/media/libmediaplayerservice/MetadataRetrieverClient.cpp
@@ -31,10 +31,11 @@
 #include <binder/MemoryHeapBase.h>
 #include <binder/IPCThreadState.h>
 #include <binder/IServiceManager.h>
+#include <media/DataSource.h>
 #include <media/IMediaHTTPService.h>
 #include <media/MediaMetadataRetrieverInterface.h>
 #include <media/MediaPlayerInterface.h>
-#include <media/stagefright/DataSource.h>
+#include <media/stagefright/InterfaceUtils.h>
 #include <media/stagefright/Utils.h>
 #include <private/media/VideoFrame.h>
 #include "MetadataRetrieverClient.h"
@@ -180,7 +181,7 @@
     ALOGV("setDataSource(IDataSource)");
     Mutex::Autolock lock(mLock);
 
-    sp<DataSource> dataSource = DataSource::CreateFromIDataSource(source);
+    sp<DataSource> dataSource = CreateDataSourceFromIDataSource(source);
     player_type playerType =
         MediaPlayerFactory::getPlayerType(NULL /* client */, dataSource);
     ALOGV("player type = %d", playerType);
@@ -193,6 +194,25 @@
 
 Mutex MetadataRetrieverClient::sLock;
 
+static sp<IMemory> getThumbnail(VideoFrame* frame) {
+    std::unique_ptr<VideoFrame> frameDeleter(frame);
+
+    size_t size = frame->getFlattenedSize();
+    sp<MemoryHeapBase> heap = new MemoryHeapBase(size, 0, "MetadataRetrieverClient");
+    if (heap == NULL) {
+        ALOGE("failed to create MemoryDealer");
+        return NULL;
+    }
+    sp<IMemory> thrumbnail = new MemoryBase(heap, 0, size);
+    if (thrumbnail == NULL) {
+        ALOGE("not enough memory for VideoFrame size=%zu", size);
+        return NULL;
+    }
+    VideoFrame *frameCopy = static_cast<VideoFrame *>(thrumbnail->pointer());
+    frameCopy->copyFlattened(*frame);
+    return thrumbnail;
+}
+
 sp<IMemory> MetadataRetrieverClient::getFrameAtTime(
         int64_t timeUs, int option, int colorFormat, bool metaOnly)
 {
@@ -205,29 +225,55 @@
         ALOGE("retriever is not initialized");
         return NULL;
     }
-    VideoFrame *frame = mRetriever->getFrameAtTime(
-            timeUs, option, colorFormat, metaOnly);
+    VideoFrame *frame = mRetriever->getFrameAtTime(timeUs, option, colorFormat, metaOnly);
     if (frame == NULL) {
         ALOGE("failed to capture a video frame");
         return NULL;
     }
-    size_t size = frame->getFlattenedSize();
-    sp<MemoryHeapBase> heap = new MemoryHeapBase(size, 0, "MetadataRetrieverClient");
-    if (heap == NULL) {
-        ALOGE("failed to create MemoryDealer");
-        delete frame;
+    return getThumbnail(frame);
+}
+
+sp<IMemory> MetadataRetrieverClient::getImageAtIndex(
+        int index, int colorFormat, bool metaOnly) {
+    ALOGV("getFrameAtTime: index(%d) colorFormat(%d), metaOnly(%d)",
+            index, colorFormat, metaOnly);
+    Mutex::Autolock lock(mLock);
+    Mutex::Autolock glock(sLock);
+    mThumbnail.clear();
+    if (mRetriever == NULL) {
+        ALOGE("retriever is not initialized");
         return NULL;
     }
-    mThumbnail = new MemoryBase(heap, 0, size);
-    if (mThumbnail == NULL) {
-        ALOGE("not enough memory for VideoFrame size=%zu", size);
-        delete frame;
+    VideoFrame *frame = mRetriever->getImageAtIndex(index, colorFormat, metaOnly);
+    if (frame == NULL) {
+        ALOGE("failed to extract image");
         return NULL;
     }
-    VideoFrame *frameCopy = static_cast<VideoFrame *>(mThumbnail->pointer());
-    frameCopy->copyFlattened(*frame);
-    delete frame;  // Fix memory leakage
-    return mThumbnail;
+    return getThumbnail(frame);
+}
+
+status_t MetadataRetrieverClient::getFrameAtIndex(
+            std::vector<sp<IMemory> > *frames,
+            int frameIndex, int numFrames, int colorFormat, bool metaOnly) {
+    ALOGV("getFrameAtIndex: frameIndex(%d), numFrames(%d), colorFormat(%d), metaOnly(%d)",
+            frameIndex, numFrames, colorFormat, metaOnly);
+    Mutex::Autolock lock(mLock);
+    Mutex::Autolock glock(sLock);
+    if (mRetriever == NULL) {
+        ALOGE("retriever is not initialized");
+        return INVALID_OPERATION;
+    }
+
+    std::vector<VideoFrame*> videoFrames;
+    status_t err = mRetriever->getFrameAtIndex(
+            &videoFrames, frameIndex, numFrames, colorFormat, metaOnly);
+    if (err != OK) {
+        return err;
+    }
+    for (size_t i = 0; i < videoFrames.size(); i++) {
+        frames->push_back(getThumbnail(videoFrames[i]));
+    }
+    return OK;
 }
 
 sp<IMemory> MetadataRetrieverClient::extractAlbumArt()
diff --git a/media/libmediaplayerservice/MetadataRetrieverClient.h b/media/libmediaplayerservice/MetadataRetrieverClient.h
index c78cd4b..f71891a 100644
--- a/media/libmediaplayerservice/MetadataRetrieverClient.h
+++ b/media/libmediaplayerservice/MetadataRetrieverClient.h
@@ -52,6 +52,11 @@
     virtual status_t                setDataSource(const sp<IDataSource>& source, const char *mime);
     virtual sp<IMemory>             getFrameAtTime(
             int64_t timeUs, int option, int colorFormat, bool metaOnly);
+    virtual sp<IMemory>             getImageAtIndex(
+            int index, int colorFormat, bool metaOnly);
+    virtual status_t getFrameAtIndex(
+                std::vector<sp<IMemory> > *frames,
+                int frameIndex, int numFrames, int colorFormat, bool metaOnly);
     virtual sp<IMemory>             extractAlbumArt();
     virtual const char*             extractMetadata(int keyCode);
 
diff --git a/media/libmediaplayerservice/include/MediaPlayerInterface.h b/media/libmediaplayerservice/include/MediaPlayerInterface.h
index 764df70..1bd9a88 100644
--- a/media/libmediaplayerservice/include/MediaPlayerInterface.h
+++ b/media/libmediaplayerservice/include/MediaPlayerInterface.h
@@ -150,6 +150,11 @@
                                     const sp<media::VolumeShaper::Configuration>& configuration,
                                     const sp<media::VolumeShaper::Operation>& operation);
         virtual sp<media::VolumeShaper::State> getVolumeShaperState(int id);
+
+        // AudioRouting
+        virtual status_t    setOutputDevice(audio_port_handle_t deviceId);
+        virtual status_t    getRoutedDeviceId(audio_port_handle_t* deviceId);
+        virtual status_t    enableAudioDeviceCallback(bool enabled);
     };
 
                         MediaPlayerBase() : mCookie(0), mNotify(0) {}
diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
index 45a5f27..b30d82a 100644
--- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
@@ -23,18 +23,21 @@
 #include "AnotherPacketSource.h"
 #include <binder/IServiceManager.h>
 #include <cutils/properties.h>
+#include <media/DataSource.h>
+#include <media/MediaExtractor.h>
+#include <media/MediaSource.h>
 #include <media/IMediaExtractorService.h>
 #include <media/IMediaHTTPService.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
-#include <media/stagefright/DataSource.h>
+#include <media/stagefright/DataSourceFactory.h>
 #include <media/stagefright/FileSource.h>
+#include <media/stagefright/InterfaceUtils.h>
 #include <media/stagefright/MediaBuffer.h>
 #include <media/stagefright/MediaClock.h>
 #include <media/stagefright/MediaDefs.h>
-#include <media/stagefright/MediaExtractor.h>
-#include <media/stagefright/MediaSource.h>
+#include <media/stagefright/MediaExtractorFactory.h>
 #include <media/stagefright/MetaData.h>
 #include <media/stagefright/Utils.h>
 #include "../../libstagefright/include/NuCachedSource2.h"
@@ -46,9 +49,6 @@
 static const int kHighWaterMarkMs         = 5000;  // 5secs
 static const int kHighWaterMarkRebufferMs = 15000;  // 15secs
 
-static const int kLowWaterMarkKB  = 40;
-static const int kHighWaterMarkKB = 200;
-
 NuPlayer::GenericSource::GenericSource(
         const sp<AMessage> &notify,
         bool uidValid,
@@ -59,6 +59,11 @@
       mAudioLastDequeueTimeUs(0),
       mVideoTimeUs(0),
       mVideoLastDequeueTimeUs(0),
+      mPrevBufferPercentage(-1),
+      mPollBufferingGeneration(0),
+      mSentPauseOnBuffering(false),
+      mAudioDataGeneration(0),
+      mVideoDataGeneration(0),
       mFetchSubtitleDataGeneration(0),
       mFetchTimedTextDataGeneration(0),
       mDurationUs(-1ll),
@@ -74,7 +79,7 @@
     ALOGV("GenericSource");
     CHECK(mediaClock != NULL);
 
-    mBufferingMonitor = new BufferingMonitor(notify);
+    getDefaultBufferingSettings(&mBufferingSettings);
     resetDataSource();
 }
 
@@ -83,6 +88,7 @@
 
     mHTTPService.clear();
     mHttpSource.clear();
+    mDisconnected = false;
     mUri.clear();
     mUriHeaders.clear();
     if (mFd >= 0) {
@@ -92,14 +98,7 @@
     mOffset = 0;
     mLength = 0;
     mStarted = false;
-    mStopRead = true;
-
-    if (mBufferingMonitorLooper != NULL) {
-        mBufferingMonitorLooper->unregisterHandler(mBufferingMonitor->id());
-        mBufferingMonitorLooper->stop();
-        mBufferingMonitorLooper = NULL;
-    }
-    mBufferingMonitor->stop();
+    mPreparing = false;
 
     mIsDrmProtected = false;
     mIsDrmReleased = false;
@@ -111,6 +110,7 @@
         const sp<IMediaHTTPService> &httpService,
         const char *url,
         const KeyedVector<String8, String8> *headers) {
+    Mutex::Autolock _l(mLock);
     ALOGV("setDataSource url: %s", url);
 
     resetDataSource();
@@ -129,6 +129,7 @@
 
 status_t NuPlayer::GenericSource::setDataSource(
         int fd, int64_t offset, int64_t length) {
+    Mutex::Autolock _l(mLock);
     ALOGV("setDataSource %d/%lld/%lld", fd, (long long)offset, (long long)length);
 
     resetDataSource();
@@ -143,6 +144,7 @@
 }
 
 status_t NuPlayer::GenericSource::setDataSource(const sp<DataSource>& source) {
+    Mutex::Autolock _l(mLock);
     ALOGV("setDataSource (source: %p)", source.get());
 
     resetDataSource();
@@ -151,21 +153,34 @@
 }
 
 sp<MetaData> NuPlayer::GenericSource::getFileFormatMeta() const {
+    Mutex::Autolock _l(mLock);
     return mFileMeta;
 }
 
 status_t NuPlayer::GenericSource::initFromDataSource() {
     sp<IMediaExtractor> extractor;
     CHECK(mDataSource != NULL);
+    sp<DataSource> dataSource = mDataSource;
 
-    extractor = MediaExtractor::Create(mDataSource, NULL);
+    mLock.unlock();
+    // This might take long time if data source is not reliable.
+    extractor = MediaExtractorFactory::Create(dataSource, NULL);
 
     if (extractor == NULL) {
         ALOGE("initFromDataSource, cannot create extractor!");
         return UNKNOWN_ERROR;
     }
 
-    mFileMeta = extractor->getMetaData();
+    sp<MetaData> fileMeta = extractor->getMetaData();
+
+    size_t numtracks = extractor->countTracks();
+    if (numtracks == 0) {
+        ALOGE("initFromDataSource, source has no track!");
+        return UNKNOWN_ERROR;
+    }
+
+    mLock.lock();
+    mFileMeta = fileMeta;
     if (mFileMeta != NULL) {
         int64_t duration;
         if (mFileMeta->findInt64(kKeyDuration, &duration)) {
@@ -175,12 +190,6 @@
 
     int32_t totalBitrate = 0;
 
-    size_t numtracks = extractor->countTracks();
-    if (numtracks == 0) {
-        ALOGE("initFromDataSource, source has no track!");
-        return UNKNOWN_ERROR;
-    }
-
     mMimes.clear();
 
     for (size_t i = 0; i < numtracks; ++i) {
@@ -265,12 +274,36 @@
 
 status_t NuPlayer::GenericSource::getDefaultBufferingSettings(
         BufferingSettings* buffering /* nonnull */) {
-    mBufferingMonitor->getDefaultBufferingSettings(buffering);
+    buffering->mInitialBufferingMode = BUFFERING_MODE_TIME_ONLY;
+    buffering->mRebufferingMode = BUFFERING_MODE_TIME_ONLY;
+    buffering->mInitialWatermarkMs = kHighWaterMarkMs;
+    buffering->mRebufferingWatermarkLowMs = kLowWaterMarkMs;
+    buffering->mRebufferingWatermarkHighMs = kHighWaterMarkRebufferMs;
+
+    ALOGV("getDefaultBufferingSettings{%s}", buffering->toString().string());
     return OK;
 }
 
 status_t NuPlayer::GenericSource::setBufferingSettings(const BufferingSettings& buffering) {
-    return mBufferingMonitor->setBufferingSettings(buffering);
+    ALOGV("setBufferingSettings{%s}", buffering.toString().string());
+
+    if (buffering.IsSizeBasedBufferingMode(buffering.mInitialBufferingMode)
+            || buffering.IsSizeBasedBufferingMode(buffering.mRebufferingMode)
+            || (buffering.IsTimeBasedBufferingMode(buffering.mRebufferingMode)
+                && buffering.mRebufferingWatermarkLowMs > buffering.mRebufferingWatermarkHighMs)) {
+        return BAD_VALUE;
+    }
+
+    Mutex::Autolock _l(mLock);
+    mBufferingSettings = buffering;
+    if (mBufferingSettings.mInitialBufferingMode == BUFFERING_MODE_NONE) {
+        mBufferingSettings.mInitialWatermarkMs = BufferingSettings::kNoWatermark;
+    }
+    if (mBufferingSettings.mRebufferingMode == BUFFERING_MODE_NONE) {
+        mBufferingSettings.mRebufferingWatermarkLowMs = BufferingSettings::kNoWatermark;
+        mBufferingSettings.mRebufferingWatermarkHighMs = INT32_MAX;
+    }
+    return OK;
 }
 
 status_t NuPlayer::GenericSource::startSources() {
@@ -306,6 +339,7 @@
 
 status_t NuPlayer::GenericSource::setBuffers(
         bool audio, Vector<MediaBuffer *> &buffers) {
+    Mutex::Autolock _l(mLock);
     if (mIsSecure && !audio && mVideoTrack.mSource != NULL) {
         return mVideoTrack.mSource->setBuffers(buffers);
     }
@@ -313,13 +347,10 @@
 }
 
 bool NuPlayer::GenericSource::isStreaming() const {
+    Mutex::Autolock _l(mLock);
     return mIsStreaming;
 }
 
-void NuPlayer::GenericSource::setOffloadAudio(bool offload) {
-    mBufferingMonitor->setOffloadAudio(offload);
-}
-
 NuPlayer::GenericSource::~GenericSource() {
     ALOGV("~GenericSource");
     if (mLooper != NULL) {
@@ -330,6 +361,7 @@
 }
 
 void NuPlayer::GenericSource::prepareAsync() {
+    Mutex::Autolock _l(mLock);
     ALOGV("prepareAsync: (looper: %d)", (mLooper != NULL));
 
     if (mLooper == NULL) {
@@ -358,7 +390,7 @@
             String8 contentType;
 
             if (!strncasecmp("http://", uri, 7) || !strncasecmp("https://", uri, 8)) {
-                mHttpSource = DataSource::CreateMediaHTTP(mHTTPService);
+                mHttpSource = DataSourceFactory::CreateMediaHTTP(mHTTPService);
                 if (mHttpSource == NULL) {
                     ALOGE("Failed to create http source!");
                     notifyPreparedAndCleanup(UNKNOWN_ERROR);
@@ -366,9 +398,15 @@
                 }
             }
 
-            mDataSource = DataSource::CreateFromURI(
+            mLock.unlock();
+            // This might take long time if connection has some issue.
+            sp<DataSource> dataSource = DataSourceFactory::CreateFromURI(
                    mHTTPService, uri, &mUriHeaders, &contentType,
                    static_cast<HTTPBase *>(mHttpSource.get()));
+            mLock.lock();
+            if (!mDisconnected) {
+                mDataSource = dataSource;
+            }
         } else {
             if (property_get_bool("media.stagefright.extractremote", true) &&
                     !FileSource::requiresDrm(mFd, mOffset, mLength, nullptr /* mime */)) {
@@ -383,7 +421,7 @@
                     ALOGV("IDataSource(FileSource): %p %d %lld %lld",
                             source.get(), mFd, (long long)mOffset, (long long)mLength);
                     if (source.get() != nullptr) {
-                        mDataSource = DataSource::CreateFromIDataSource(source);
+                        mDataSource = CreateDataSourceFromIDataSource(source);
                         if (mDataSource != nullptr) {
                             // Close the local file descriptor as it is not needed anymore.
                             close(mFd);
@@ -401,7 +439,7 @@
                 mDataSource = new FileSource(mFd, mOffset, mLength);
             }
             // TODO: close should always be done on mFd, see the lines following
-            // DataSource::CreateFromIDataSource above,
+            // CreateDataSourceFromIDataSource above,
             // and the FileSource constructor should dup the mFd argument as needed.
             mFd = -1;
         }
@@ -431,7 +469,7 @@
     }
 
     if (mVideoTrack.mSource != NULL) {
-        sp<MetaData> meta = doGetFormatMeta(false /* audio */);
+        sp<MetaData> meta = getFormatMeta_l(false /* audio */);
         sp<AMessage> msg = new AMessage;
         err = convertMetaDataToMessage(meta, &msg);
         if(err != OK) {
@@ -465,47 +503,39 @@
     }
 
     if (mIsStreaming) {
-        if (mBufferingMonitorLooper == NULL) {
-            mBufferingMonitor->prepare(mCachedSource, mDurationUs, mBitrate,
-                    mIsStreaming);
-
-            mBufferingMonitorLooper = new ALooper;
-            mBufferingMonitorLooper->setName("GSBMonitor");
-            mBufferingMonitorLooper->start();
-            mBufferingMonitorLooper->registerHandler(mBufferingMonitor);
-        }
-
-        mBufferingMonitor->ensureCacheIsFetching();
-        mBufferingMonitor->restartPollBuffering();
+        mCachedSource->resumeFetchingIfNecessary();
+        mPreparing = true;
+        schedulePollBuffering();
     } else {
         notifyPrepared();
     }
+
+    if (mAudioTrack.mSource != NULL) {
+        postReadBuffer(MEDIA_TRACK_TYPE_AUDIO);
+    }
+
+    if (mVideoTrack.mSource != NULL) {
+        postReadBuffer(MEDIA_TRACK_TYPE_VIDEO);
+    }
 }
 
 void NuPlayer::GenericSource::notifyPreparedAndCleanup(status_t err) {
     if (err != OK) {
-        {
-            sp<DataSource> dataSource = mDataSource;
-            sp<NuCachedSource2> cachedSource = mCachedSource;
-            sp<DataSource> httpSource = mHttpSource;
-            {
-                Mutex::Autolock _l(mDisconnectLock);
-                mDataSource.clear();
-                mCachedSource.clear();
-                mHttpSource.clear();
-            }
-        }
-        mBitrate = -1;
+        mDataSource.clear();
+        mCachedSource.clear();
+        mHttpSource.clear();
 
-        mBufferingMonitor->cancelPollBuffering();
+        mBitrate = -1;
+        mPrevBufferPercentage = -1;
+        ++mPollBufferingGeneration;
     }
     notifyPrepared(err);
 }
 
 void NuPlayer::GenericSource::start() {
+    Mutex::Autolock _l(mLock);
     ALOGI("start");
 
-    mStopRead = false;
     if (mAudioTrack.mSource != NULL) {
         postReadBuffer(MEDIA_TRACK_TYPE_AUDIO);
     }
@@ -515,30 +545,30 @@
     }
 
     mStarted = true;
-
-    (new AMessage(kWhatStart, this))->post();
 }
 
 void NuPlayer::GenericSource::stop() {
+    Mutex::Autolock _l(mLock);
     mStarted = false;
 }
 
 void NuPlayer::GenericSource::pause() {
+    Mutex::Autolock _l(mLock);
     mStarted = false;
 }
 
 void NuPlayer::GenericSource::resume() {
+    Mutex::Autolock _l(mLock);
     mStarted = true;
-
-    (new AMessage(kWhatResume, this))->post();
 }
 
 void NuPlayer::GenericSource::disconnect() {
     sp<DataSource> dataSource, httpSource;
     {
-        Mutex::Autolock _l(mDisconnectLock);
+        Mutex::Autolock _l(mLock);
         dataSource = mDataSource;
         httpSource = mHttpSource;
+        mDisconnected = true;
     }
 
     if (dataSource != NULL) {
@@ -555,7 +585,24 @@
     return OK;
 }
 
+void NuPlayer::GenericSource::sendCacheStats() {
+    int32_t kbps = 0;
+    status_t err = UNKNOWN_ERROR;
+
+    if (mCachedSource != NULL) {
+        err = mCachedSource->getEstimatedBandwidthKbps(&kbps);
+    }
+
+    if (err == OK) {
+        sp<AMessage> notify = dupNotify();
+        notify->setInt32("what", kWhatCacheStats);
+        notify->setInt32("bandwidth", kbps);
+        notify->post();
+    }
+}
+
 void NuPlayer::GenericSource::onMessageReceived(const sp<AMessage> &msg) {
+    Mutex::Autolock _l(mLock);
     switch (msg->what()) {
       case kWhatPrepareAsync:
       {
@@ -624,6 +671,8 @@
           track->mSource = source;
           track->mSource->start();
           track->mIndex = trackIndex;
+          ++mAudioDataGeneration;
+          ++mVideoDataGeneration;
 
           int64_t timeUs, actualTimeUs;
           const bool formatChange = true;
@@ -641,68 +690,19 @@
           break;
       }
 
-      case kWhatStart:
-      case kWhatResume:
-      {
-          mBufferingMonitor->restartPollBuffering();
-          break;
-      }
-
-      case kWhatGetFormat:
-      {
-          onGetFormatMeta(msg);
-          break;
-      }
-
-      case kWhatGetSelectedTrack:
-      {
-          onGetSelectedTrack(msg);
-          break;
-      }
-
-      case kWhatGetTrackInfo:
-      {
-          onGetTrackInfo(msg);
-          break;
-      }
-
-      case kWhatSelectTrack:
-      {
-          onSelectTrack(msg);
-          break;
-      }
-
-      case kWhatSeek:
-      {
-          onSeek(msg);
-          break;
-      }
-
       case kWhatReadBuffer:
       {
           onReadBuffer(msg);
           break;
       }
 
-      case kWhatPrepareDrm:
+      case kWhatPollBuffering:
       {
-          status_t status = onPrepareDrm(msg);
-          sp<AMessage> response = new AMessage;
-          response->setInt32("status", status);
-          sp<AReplyToken> replyID;
-          CHECK(msg->senderAwaitsResponse(&replyID));
-          response->postReply(replyID);
-          break;
-      }
-
-      case kWhatReleaseDrm:
-      {
-          status_t status = onReleaseDrm();
-          sp<AMessage> response = new AMessage;
-          response->setInt32("status", status);
-          sp<AReplyToken> replyID;
-          CHECK(msg->senderAwaitsResponse(&replyID));
-          response->postReply(replyID);
+          int32_t generation;
+          CHECK(msg->findInt32("generation", &generation));
+          if (generation == mPollBufferingGeneration) {
+              onPollBuffering();
+          }
           break;
       }
 
@@ -817,34 +817,11 @@
 }
 
 sp<MetaData> NuPlayer::GenericSource::getFormatMeta(bool audio) {
-    sp<AMessage> msg = new AMessage(kWhatGetFormat, this);
-    msg->setInt32("audio", audio);
-
-    sp<AMessage> response;
-    sp<RefBase> format;
-    status_t err = msg->postAndAwaitResponse(&response);
-    if (err == OK && response != NULL) {
-        CHECK(response->findObject("format", &format));
-        return static_cast<MetaData*>(format.get());
-    } else {
-        return NULL;
-    }
+    Mutex::Autolock _l(mLock);
+    return getFormatMeta_l(audio);
 }
 
-void NuPlayer::GenericSource::onGetFormatMeta(const sp<AMessage>& msg) const {
-    int32_t audio;
-    CHECK(msg->findInt32("audio", &audio));
-
-    sp<AMessage> response = new AMessage;
-    sp<MetaData> format = doGetFormatMeta(audio);
-    response->setObject("format", format);
-
-    sp<AReplyToken> replyID;
-    CHECK(msg->senderAwaitsResponse(&replyID));
-    response->postReply(replyID);
-}
-
-sp<MetaData> NuPlayer::GenericSource::doGetFormatMeta(bool audio) const {
+sp<MetaData> NuPlayer::GenericSource::getFormatMeta_l(bool audio) {
     sp<IMediaSource> source = audio ? mAudioTrack.mSource : mVideoTrack.mSource;
 
     if (source == NULL) {
@@ -856,6 +833,7 @@
 
 status_t NuPlayer::GenericSource::dequeueAccessUnit(
         bool audio, sp<ABuffer> *accessUnit) {
+    Mutex::Autolock _l(mLock);
     // If has gone through stop/releaseDrm sequence, we no longer send down any buffer b/c
     // the codec's crypto object has gone away (b/37960096).
     // Note: This will be unnecessary when stop() changes behavior and releases codec (b/35248283).
@@ -881,10 +859,30 @@
 
     status_t result = track->mPackets->dequeueAccessUnit(accessUnit);
 
-    // start pulling in more buffers if we only have one (or no) buffer left
+    // start pulling in more buffers if cache is running low
     // so that decoder has less chance of being starved
-    if (track->mPackets->getAvailableBufferCount(&finalResult) < 2) {
-        postReadBuffer(audio? MEDIA_TRACK_TYPE_AUDIO : MEDIA_TRACK_TYPE_VIDEO);
+    if (!mIsStreaming) {
+        if (track->mPackets->getAvailableBufferCount(&finalResult) < 2) {
+            postReadBuffer(audio? MEDIA_TRACK_TYPE_AUDIO : MEDIA_TRACK_TYPE_VIDEO);
+        }
+    } else {
+        int64_t durationUs = track->mPackets->getBufferedDurationUs(&finalResult);
+        int64_t restartBufferingMarkUs =
+             mBufferingSettings.mRebufferingWatermarkHighMs * 1000ll / 2;
+        if (finalResult == OK) {
+            if (durationUs < restartBufferingMarkUs) {
+                postReadBuffer(audio? MEDIA_TRACK_TYPE_AUDIO : MEDIA_TRACK_TYPE_VIDEO);
+            }
+            if (track->mPackets->getAvailableBufferCount(&finalResult) < 2
+                && !mSentPauseOnBuffering && !mPreparing) {
+                mCachedSource->resumeFetchingIfNecessary();
+                sendCacheStats();
+                mSentPauseOnBuffering = true;
+                sp<AMessage> notify = dupNotify();
+                notify->setInt32("what", kWhatPauseOnBufferingStart);
+                notify->post();
+            }
+        }
     }
 
     if (result != OK) {
@@ -904,7 +902,6 @@
     CHECK((*accessUnit)->meta()->findInt64("timeUs", &timeUs));
     if (audio) {
         mAudioLastDequeueTimeUs = timeUs;
-        mBufferingMonitor->updateDequeuedBufferTime(timeUs);
     } else {
         mVideoLastDequeueTimeUs = timeUs;
     }
@@ -929,43 +926,18 @@
 }
 
 status_t NuPlayer::GenericSource::getDuration(int64_t *durationUs) {
+    Mutex::Autolock _l(mLock);
     *durationUs = mDurationUs;
     return OK;
 }
 
 size_t NuPlayer::GenericSource::getTrackCount() const {
+    Mutex::Autolock _l(mLock);
     return mSources.size();
 }
 
 sp<AMessage> NuPlayer::GenericSource::getTrackInfo(size_t trackIndex) const {
-    sp<AMessage> msg = new AMessage(kWhatGetTrackInfo, this);
-    msg->setSize("trackIndex", trackIndex);
-
-    sp<AMessage> response;
-    sp<RefBase> format;
-    status_t err = msg->postAndAwaitResponse(&response);
-    if (err == OK && response != NULL) {
-        CHECK(response->findObject("format", &format));
-        return static_cast<AMessage*>(format.get());
-    } else {
-        return NULL;
-    }
-}
-
-void NuPlayer::GenericSource::onGetTrackInfo(const sp<AMessage>& msg) const {
-    size_t trackIndex;
-    CHECK(msg->findSize("trackIndex", &trackIndex));
-
-    sp<AMessage> response = new AMessage;
-    sp<AMessage> format = doGetTrackInfo(trackIndex);
-    response->setObject("format", format);
-
-    sp<AReplyToken> replyID;
-    CHECK(msg->senderAwaitsResponse(&replyID));
-    response->postReply(replyID);
-}
-
-sp<AMessage> NuPlayer::GenericSource::doGetTrackInfo(size_t trackIndex) const {
+    Mutex::Autolock _l(mLock);
     size_t trackCount = mSources.size();
     if (trackIndex >= trackCount) {
         return NULL;
@@ -1015,35 +987,7 @@
 }
 
 ssize_t NuPlayer::GenericSource::getSelectedTrack(media_track_type type) const {
-    sp<AMessage> msg = new AMessage(kWhatGetSelectedTrack, this);
-    msg->setInt32("type", type);
-
-    sp<AMessage> response;
-    int32_t index;
-    status_t err = msg->postAndAwaitResponse(&response);
-    if (err == OK && response != NULL) {
-        CHECK(response->findInt32("index", &index));
-        return index;
-    } else {
-        return -1;
-    }
-}
-
-void NuPlayer::GenericSource::onGetSelectedTrack(const sp<AMessage>& msg) const {
-    int32_t tmpType;
-    CHECK(msg->findInt32("type", &tmpType));
-    media_track_type type = (media_track_type)tmpType;
-
-    sp<AMessage> response = new AMessage;
-    ssize_t index = doGetSelectedTrack(type);
-    response->setInt32("index", index);
-
-    sp<AReplyToken> replyID;
-    CHECK(msg->senderAwaitsResponse(&replyID));
-    response->postReply(replyID);
-}
-
-ssize_t NuPlayer::GenericSource::doGetSelectedTrack(media_track_type type) const {
+    Mutex::Autolock _l(mLock);
     const Track *track = NULL;
     switch (type) {
     case MEDIA_TRACK_TYPE_VIDEO:
@@ -1070,38 +1014,9 @@
 }
 
 status_t NuPlayer::GenericSource::selectTrack(size_t trackIndex, bool select, int64_t timeUs) {
+    Mutex::Autolock _l(mLock);
     ALOGV("%s track: %zu", select ? "select" : "deselect", trackIndex);
-    sp<AMessage> msg = new AMessage(kWhatSelectTrack, this);
-    msg->setInt32("trackIndex", trackIndex);
-    msg->setInt32("select", select);
-    msg->setInt64("timeUs", timeUs);
 
-    sp<AMessage> response;
-    status_t err = msg->postAndAwaitResponse(&response);
-    if (err == OK && response != NULL) {
-        CHECK(response->findInt32("err", &err));
-    }
-
-    return err;
-}
-
-void NuPlayer::GenericSource::onSelectTrack(const sp<AMessage>& msg) {
-    int32_t trackIndex, select;
-    int64_t timeUs;
-    CHECK(msg->findInt32("trackIndex", &trackIndex));
-    CHECK(msg->findInt32("select", &select));
-    CHECK(msg->findInt64("timeUs", &timeUs));
-
-    sp<AMessage> response = new AMessage;
-    status_t err = doSelectTrack(trackIndex, select, timeUs);
-    response->setInt32("err", err);
-
-    sp<AReplyToken> replyID;
-    CHECK(msg->senderAwaitsResponse(&replyID));
-    response->postReply(replyID);
-}
-
-status_t NuPlayer::GenericSource::doSelectTrack(size_t trackIndex, bool select, int64_t timeUs) {
     if (trackIndex >= mSources.size()) {
         return BAD_INDEX;
     }
@@ -1193,46 +1108,11 @@
 }
 
 status_t NuPlayer::GenericSource::seekTo(int64_t seekTimeUs, MediaPlayerSeekMode mode) {
-    sp<AMessage> msg = new AMessage(kWhatSeek, this);
-    msg->setInt64("seekTimeUs", seekTimeUs);
-    msg->setInt32("mode", mode);
-
-    sp<AMessage> response;
-    status_t err = msg->postAndAwaitResponse(&response);
-    if (err == OK && response != NULL) {
-        CHECK(response->findInt32("err", &err));
-    }
-
-    return err;
-}
-
-void NuPlayer::GenericSource::onSeek(const sp<AMessage>& msg) {
-    int64_t seekTimeUs;
-    int32_t mode;
-    CHECK(msg->findInt64("seekTimeUs", &seekTimeUs));
-    CHECK(msg->findInt32("mode", &mode));
-
-    sp<AMessage> response = new AMessage;
-    status_t err = doSeek(seekTimeUs, (MediaPlayerSeekMode)mode);
-    response->setInt32("err", err);
-
-    sp<AReplyToken> replyID;
-    CHECK(msg->senderAwaitsResponse(&replyID));
-    response->postReply(replyID);
-}
-
-status_t NuPlayer::GenericSource::doSeek(int64_t seekTimeUs, MediaPlayerSeekMode mode) {
-    mBufferingMonitor->updateDequeuedBufferTime(-1ll);
-
-    // If the Widevine source is stopped, do not attempt to read any
-    // more buffers.
-    //
-    // TODO: revisit after widevine is removed.  May be able to
-    // combine mStopRead with mStarted.
-    if (mStopRead) {
-        return INVALID_OPERATION;
-    }
+    Mutex::Autolock _l(mLock);
+    ALOGV("seekTo: %lld, %d", (long long)seekTimeUs, mode);
     if (mVideoTrack.mSource != NULL) {
+        ++mVideoDataGeneration;
+
         int64_t actualTimeUs;
         readBuffer(MEDIA_TRACK_TYPE_VIDEO, seekTimeUs, mode, &actualTimeUs);
 
@@ -1243,6 +1123,7 @@
     }
 
     if (mAudioTrack.mSource != NULL) {
+        ++mAudioDataGeneration;
         readBuffer(MEDIA_TRACK_TYPE_AUDIO, seekTimeUs, MediaPlayerSeekMode::SEEK_CLOSEST);
         mAudioLastDequeueTimeUs = seekTimeUs;
     }
@@ -1257,12 +1138,8 @@
         mFetchTimedTextDataGeneration++;
     }
 
-    // If currently buffering, post kWhatBufferingEnd first, so that
-    // NuPlayer resumes. Otherwise, if cache hits high watermark
-    // before new polling happens, no one will resume the playback.
-    mBufferingMonitor->stopBufferingIfNecessary();
-    mBufferingMonitor->restartPollBuffering();
-
+    ++mPollBufferingGeneration;
+    schedulePollBuffering();
     return OK;
 }
 
@@ -1365,9 +1242,29 @@
     return ab;
 }
 
-void NuPlayer::GenericSource::postReadBuffer(media_track_type trackType) {
-    Mutex::Autolock _l(mReadBufferLock);
+int32_t NuPlayer::GenericSource::getDataGeneration(media_track_type type) const {
+    int32_t generation = -1;
+    switch (type) {
+    case MEDIA_TRACK_TYPE_VIDEO:
+        generation = mVideoDataGeneration;
+        break;
+    case MEDIA_TRACK_TYPE_AUDIO:
+        generation = mAudioDataGeneration;
+        break;
+    case MEDIA_TRACK_TYPE_TIMEDTEXT:
+        generation = mFetchTimedTextDataGeneration;
+        break;
+    case MEDIA_TRACK_TYPE_SUBTITLE:
+        generation = mFetchSubtitleDataGeneration;
+        break;
+    default:
+        break;
+    }
 
+    return generation;
+}
+
+void NuPlayer::GenericSource::postReadBuffer(media_track_type trackType) {
     if ((mPendingReadBufferTypes & (1 << trackType)) == 0) {
         mPendingReadBufferTypes |= (1 << trackType);
         sp<AMessage> msg = new AMessage(kWhatReadBuffer, this);
@@ -1380,25 +1277,13 @@
     int32_t tmpType;
     CHECK(msg->findInt32("trackType", &tmpType));
     media_track_type trackType = (media_track_type)tmpType;
+    mPendingReadBufferTypes &= ~(1 << trackType);
     readBuffer(trackType);
-    {
-        // only protect the variable change, as readBuffer may
-        // take considerable time.
-        Mutex::Autolock _l(mReadBufferLock);
-        mPendingReadBufferTypes &= ~(1 << trackType);
-    }
 }
 
 void NuPlayer::GenericSource::readBuffer(
         media_track_type trackType, int64_t seekTimeUs, MediaPlayerSeekMode mode,
         int64_t *actualTimeUs, bool formatChange) {
-    // Do not read data if Widevine source is stopped
-    //
-    // TODO: revisit after widevine is removed.  May be able to
-    // combine mStopRead with mStarted.
-    if (mStopRead) {
-        return;
-    }
     Track *track;
     size_t maxBuffers = 1;
     switch (trackType) {
@@ -1442,10 +1327,12 @@
         options.setNonBlocking();
     }
 
+    int32_t generation = getDataGeneration(trackType);
     for (size_t numBuffers = 0; numBuffers < maxBuffers; ) {
         Vector<MediaBuffer *> mediaBuffers;
         status_t err = NO_ERROR;
 
+        mLock.unlock();
         if (couldReadMultiple) {
             err = track->mSource->readMultiple(
                     &mediaBuffers, maxBuffers - numBuffers, &options);
@@ -1456,11 +1343,21 @@
                 mediaBuffers.push_back(mbuf);
             }
         }
+        mLock.lock();
 
         options.clearNonPersistent();
 
         size_t id = 0;
         size_t count = mediaBuffers.size();
+
+        // in case track has been changed since we don't have lock for some time.
+        if (generation != getDataGeneration(trackType)) {
+            for (; id < count; ++id) {
+                mediaBuffers[id]->release();
+            }
+            break;
+        }
+
         for (; id < count; ++id) {
             int64_t timeUs;
             MediaBuffer *mbuf = mediaBuffers[id];
@@ -1471,10 +1368,8 @@
             }
             if (trackType == MEDIA_TRACK_TYPE_AUDIO) {
                 mAudioTimeUs = timeUs;
-                mBufferingMonitor->updateQueuedTime(true /* isAudio */, timeUs);
             } else if (trackType == MEDIA_TRACK_TYPE_VIDEO) {
                 mVideoTimeUs = timeUs;
-                mBufferingMonitor->updateQueuedTime(false /* isAudio */, timeUs);
             }
 
             queueDiscontinuityIfNeeded(seeking, formatChange, trackType, track);
@@ -1521,6 +1416,39 @@
             break;
         }
     }
+
+    if (mIsStreaming
+        && (trackType == MEDIA_TRACK_TYPE_VIDEO || trackType == MEDIA_TRACK_TYPE_AUDIO)) {
+        status_t finalResult;
+        int64_t durationUs = track->mPackets->getBufferedDurationUs(&finalResult);
+
+        int64_t markUs = (mPreparing ? mBufferingSettings.mInitialWatermarkMs
+            : mBufferingSettings.mRebufferingWatermarkHighMs) * 1000ll;
+        if (finalResult == ERROR_END_OF_STREAM || durationUs >= markUs) {
+            if (mPreparing || mSentPauseOnBuffering) {
+                Track *counterTrack =
+                    (trackType == MEDIA_TRACK_TYPE_VIDEO ? &mAudioTrack : &mVideoTrack);
+                if (counterTrack->mSource != NULL) {
+                    durationUs = counterTrack->mPackets->getBufferedDurationUs(&finalResult);
+                }
+                if (finalResult == ERROR_END_OF_STREAM || durationUs >= markUs) {
+                    if (mPreparing) {
+                        notifyPrepared();
+                        mPreparing = false;
+                    } else {
+                        sendCacheStats();
+                        mSentPauseOnBuffering = false;
+                        sp<AMessage> notify = dupNotify();
+                        notify->setInt32("what", kWhatResumeOnBufferingEnd);
+                        notify->post();
+                    }
+                }
+            }
+            return;
+        }
+
+        postReadBuffer(trackType);
+    }
 }
 
 void NuPlayer::GenericSource::queueDiscontinuityIfNeeded(
@@ -1538,160 +1466,7 @@
     }
 }
 
-NuPlayer::GenericSource::BufferingMonitor::BufferingMonitor(const sp<AMessage> &notify)
-    : mNotify(notify),
-      mDurationUs(-1ll),
-      mBitrate(-1ll),
-      mIsStreaming(false),
-      mAudioTimeUs(0),
-      mVideoTimeUs(0),
-      mPollBufferingGeneration(0),
-      mPrepareBuffering(false),
-      mBuffering(false),
-      mPrevBufferPercentage(-1),
-      mOffloadAudio(false),
-      mFirstDequeuedBufferRealUs(-1ll),
-      mFirstDequeuedBufferMediaUs(-1ll),
-      mlastDequeuedBufferMediaUs(-1ll) {
-      getDefaultBufferingSettings(&mSettings);
-}
-
-NuPlayer::GenericSource::BufferingMonitor::~BufferingMonitor() {
-}
-
-void NuPlayer::GenericSource::BufferingMonitor::getDefaultBufferingSettings(
-        BufferingSettings *buffering /* nonnull */) {
-    buffering->mInitialBufferingMode = BUFFERING_MODE_TIME_ONLY;
-    buffering->mRebufferingMode = BUFFERING_MODE_TIME_THEN_SIZE;
-    buffering->mInitialWatermarkMs = kHighWaterMarkMs;
-    buffering->mRebufferingWatermarkLowMs = kLowWaterMarkMs;
-    buffering->mRebufferingWatermarkHighMs = kHighWaterMarkRebufferMs;
-    buffering->mRebufferingWatermarkLowKB = kLowWaterMarkKB;
-    buffering->mRebufferingWatermarkHighKB = kHighWaterMarkKB;
-
-    ALOGV("BufferingMonitor::getDefaultBufferingSettings{%s}",
-            buffering->toString().string());
-}
-
-status_t NuPlayer::GenericSource::BufferingMonitor::setBufferingSettings(
-        const BufferingSettings &buffering) {
-    ALOGV("BufferingMonitor::setBufferingSettings{%s}",
-            buffering.toString().string());
-
-    Mutex::Autolock _l(mLock);
-    if (buffering.IsSizeBasedBufferingMode(buffering.mInitialBufferingMode)
-            || (buffering.IsTimeBasedBufferingMode(buffering.mRebufferingMode)
-                && buffering.mRebufferingWatermarkLowMs > buffering.mRebufferingWatermarkHighMs)
-            || (buffering.IsSizeBasedBufferingMode(buffering.mRebufferingMode)
-                && buffering.mRebufferingWatermarkLowKB > buffering.mRebufferingWatermarkHighKB)) {
-        return BAD_VALUE;
-    }
-    mSettings = buffering;
-    if (mSettings.mInitialBufferingMode == BUFFERING_MODE_NONE) {
-        mSettings.mInitialWatermarkMs = BufferingSettings::kNoWatermark;
-    }
-    if (!mSettings.IsTimeBasedBufferingMode(mSettings.mRebufferingMode)) {
-        mSettings.mRebufferingWatermarkLowMs = BufferingSettings::kNoWatermark;
-        mSettings.mRebufferingWatermarkHighMs = INT32_MAX;
-    }
-    if (!mSettings.IsSizeBasedBufferingMode(mSettings.mRebufferingMode)) {
-        mSettings.mRebufferingWatermarkLowKB = BufferingSettings::kNoWatermark;
-        mSettings.mRebufferingWatermarkHighKB = INT32_MAX;
-    }
-    return OK;
-}
-
-void NuPlayer::GenericSource::BufferingMonitor::prepare(
-        const sp<NuCachedSource2> &cachedSource,
-        int64_t durationUs,
-        int64_t bitrate,
-        bool isStreaming) {
-    Mutex::Autolock _l(mLock);
-    prepare_l(cachedSource, durationUs, bitrate, isStreaming);
-}
-
-void NuPlayer::GenericSource::BufferingMonitor::stop() {
-    Mutex::Autolock _l(mLock);
-    prepare_l(NULL /* cachedSource */, -1 /* durationUs */,
-            -1 /* bitrate */, false /* isStreaming */);
-}
-
-void NuPlayer::GenericSource::BufferingMonitor::cancelPollBuffering() {
-    Mutex::Autolock _l(mLock);
-    cancelPollBuffering_l();
-}
-
-void NuPlayer::GenericSource::BufferingMonitor::restartPollBuffering() {
-    Mutex::Autolock _l(mLock);
-    if (mIsStreaming) {
-        cancelPollBuffering_l();
-        onPollBuffering_l();
-    }
-}
-
-void NuPlayer::GenericSource::BufferingMonitor::stopBufferingIfNecessary() {
-    Mutex::Autolock _l(mLock);
-    stopBufferingIfNecessary_l();
-}
-
-void NuPlayer::GenericSource::BufferingMonitor::ensureCacheIsFetching() {
-    Mutex::Autolock _l(mLock);
-    ensureCacheIsFetching_l();
-}
-
-void NuPlayer::GenericSource::BufferingMonitor::updateQueuedTime(bool isAudio, int64_t timeUs) {
-    Mutex::Autolock _l(mLock);
-    if (isAudio) {
-        mAudioTimeUs = timeUs;
-    } else {
-        mVideoTimeUs = timeUs;
-    }
-}
-
-void NuPlayer::GenericSource::BufferingMonitor::setOffloadAudio(bool offload) {
-    Mutex::Autolock _l(mLock);
-    mOffloadAudio = offload;
-}
-
-void NuPlayer::GenericSource::BufferingMonitor::updateDequeuedBufferTime(int64_t mediaUs) {
-    Mutex::Autolock _l(mLock);
-    if (mediaUs < 0) {
-        mFirstDequeuedBufferRealUs = -1ll;
-        mFirstDequeuedBufferMediaUs = -1ll;
-    } else if (mFirstDequeuedBufferRealUs < 0) {
-        mFirstDequeuedBufferRealUs = ALooper::GetNowUs();
-        mFirstDequeuedBufferMediaUs = mediaUs;
-    }
-    mlastDequeuedBufferMediaUs = mediaUs;
-}
-
-void NuPlayer::GenericSource::BufferingMonitor::prepare_l(
-        const sp<NuCachedSource2> &cachedSource,
-        int64_t durationUs,
-        int64_t bitrate,
-        bool isStreaming) {
-
-    mCachedSource = cachedSource;
-    mDurationUs = durationUs;
-    mBitrate = bitrate;
-    mIsStreaming = isStreaming;
-    mAudioTimeUs = 0;
-    mVideoTimeUs = 0;
-    mPrepareBuffering = (cachedSource != NULL);
-    cancelPollBuffering_l();
-    mOffloadAudio = false;
-    mFirstDequeuedBufferRealUs = -1ll;
-    mFirstDequeuedBufferMediaUs = -1ll;
-    mlastDequeuedBufferMediaUs = -1ll;
-}
-
-void NuPlayer::GenericSource::BufferingMonitor::cancelPollBuffering_l() {
-    mBuffering = false;
-    ++mPollBufferingGeneration;
-    mPrevBufferPercentage = -1;
-}
-
-void NuPlayer::GenericSource::BufferingMonitor::notifyBufferingUpdate_l(int32_t percentage) {
+void NuPlayer::GenericSource::notifyBufferingUpdate(int32_t percentage) {
     // Buffering percent could go backward as it's estimated from remaining
     // data and last access time. This could cause the buffering position
     // drawn on media control to jitter slightly. Remember previously reported
@@ -1704,106 +1479,28 @@
 
     mPrevBufferPercentage = percentage;
 
-    ALOGV("notifyBufferingUpdate_l: buffering %d%%", percentage);
+    ALOGV("notifyBufferingUpdate: buffering %d%%", percentage);
 
-    sp<AMessage> msg = mNotify->dup();
-    msg->setInt32("what", kWhatBufferingUpdate);
-    msg->setInt32("percentage", percentage);
-    msg->post();
+    sp<AMessage> notify = dupNotify();
+    notify->setInt32("what", kWhatBufferingUpdate);
+    notify->setInt32("percentage", percentage);
+    notify->post();
 }
 
-void NuPlayer::GenericSource::BufferingMonitor::startBufferingIfNecessary_l() {
-    if (mPrepareBuffering) {
-        return;
-    }
-
-    if (!mBuffering) {
-        ALOGD("startBufferingIfNecessary_l");
-
-        mBuffering = true;
-
-        ensureCacheIsFetching_l();
-        sendCacheStats_l();
-
-        sp<AMessage> notify = mNotify->dup();
-        notify->setInt32("what", kWhatPauseOnBufferingStart);
-        notify->post();
-    }
-}
-
-void NuPlayer::GenericSource::BufferingMonitor::stopBufferingIfNecessary_l() {
-    if (mPrepareBuffering) {
-        ALOGD("stopBufferingIfNecessary_l, mBuffering=%d", mBuffering);
-
-        mPrepareBuffering = false;
-
-        sp<AMessage> notify = mNotify->dup();
-        notify->setInt32("what", kWhatPrepared);
-        notify->setInt32("err", OK);
-        notify->post();
-
-        return;
-    }
-
-    if (mBuffering) {
-        ALOGD("stopBufferingIfNecessary_l");
-        mBuffering = false;
-
-        sendCacheStats_l();
-
-        sp<AMessage> notify = mNotify->dup();
-        notify->setInt32("what", kWhatResumeOnBufferingEnd);
-        notify->post();
-    }
-}
-
-void NuPlayer::GenericSource::BufferingMonitor::sendCacheStats_l() {
-    int32_t kbps = 0;
-    status_t err = UNKNOWN_ERROR;
-
-    if (mCachedSource != NULL) {
-        err = mCachedSource->getEstimatedBandwidthKbps(&kbps);
-    }
-
-    if (err == OK) {
-        sp<AMessage> notify = mNotify->dup();
-        notify->setInt32("what", kWhatCacheStats);
-        notify->setInt32("bandwidth", kbps);
-        notify->post();
-    }
-}
-
-void NuPlayer::GenericSource::BufferingMonitor::ensureCacheIsFetching_l() {
-    if (mCachedSource != NULL) {
-        mCachedSource->resumeFetchingIfNecessary();
-    }
-}
-
-void NuPlayer::GenericSource::BufferingMonitor::schedulePollBuffering_l() {
+void NuPlayer::GenericSource::schedulePollBuffering() {
     sp<AMessage> msg = new AMessage(kWhatPollBuffering, this);
     msg->setInt32("generation", mPollBufferingGeneration);
     // Enquires buffering status every second.
     msg->post(1000000ll);
 }
 
-int64_t NuPlayer::GenericSource::BufferingMonitor::getLastReadPosition_l() {
-    if (mAudioTimeUs > 0) {
-        return mAudioTimeUs;
-    } else if (mVideoTimeUs > 0) {
-        return mVideoTimeUs;
-    } else {
-        return 0;
-    }
-}
-
-void NuPlayer::GenericSource::BufferingMonitor::onPollBuffering_l() {
+void NuPlayer::GenericSource::onPollBuffering() {
     status_t finalStatus = UNKNOWN_ERROR;
     int64_t cachedDurationUs = -1ll;
     ssize_t cachedDataRemaining = -1;
 
     if (mCachedSource != NULL) {
-        cachedDataRemaining =
-                mCachedSource->approxDataRemaining(&finalStatus);
+        cachedDataRemaining = mCachedSource->approxDataRemaining(&finalStatus);
 
         if (finalStatus == OK) {
             off64_t size;
@@ -1821,157 +1518,49 @@
     }
 
     if (finalStatus != OK) {
-        ALOGV("onPollBuffering_l: EOS (finalStatus = %d)", finalStatus);
+        ALOGV("onPollBuffering: EOS (finalStatus = %d)", finalStatus);
 
         if (finalStatus == ERROR_END_OF_STREAM) {
-            notifyBufferingUpdate_l(100);
+            notifyBufferingUpdate(100);
         }
 
-        stopBufferingIfNecessary_l();
         return;
     }
 
     if (cachedDurationUs >= 0ll) {
         if (mDurationUs > 0ll) {
-            int64_t cachedPosUs = getLastReadPosition_l() + cachedDurationUs;
+            int64_t cachedPosUs = getLastReadPosition() + cachedDurationUs;
             int percentage = 100.0 * cachedPosUs / mDurationUs;
             if (percentage > 100) {
                 percentage = 100;
             }
 
-            notifyBufferingUpdate_l(percentage);
+            notifyBufferingUpdate(percentage);
         }
 
-        ALOGV("onPollBuffering_l: cachedDurationUs %.1f sec", cachedDurationUs / 1000000.0f);
-
-        if (mPrepareBuffering) {
-            if (cachedDurationUs > mSettings.mInitialWatermarkMs * 1000) {
-                stopBufferingIfNecessary_l();
-            }
-        } else if (mSettings.IsTimeBasedBufferingMode(mSettings.mRebufferingMode)) {
-            if (cachedDurationUs < mSettings.mRebufferingWatermarkLowMs * 1000) {
-                // Take into account the data cached in downstream components to try to avoid
-                // unnecessary pause.
-                if (mOffloadAudio && mFirstDequeuedBufferRealUs >= 0) {
-                    int64_t downStreamCacheUs =
-                        mlastDequeuedBufferMediaUs - mFirstDequeuedBufferMediaUs
-                            - (ALooper::GetNowUs() - mFirstDequeuedBufferRealUs);
-                    if (downStreamCacheUs > 0) {
-                        cachedDurationUs += downStreamCacheUs;
-                    }
-                }
-
-                if (cachedDurationUs < mSettings.mRebufferingWatermarkLowMs * 1000) {
-                    startBufferingIfNecessary_l();
-                }
-            } else if (cachedDurationUs > mSettings.mRebufferingWatermarkHighMs * 1000) {
-                stopBufferingIfNecessary_l();
-            }
-        }
-    } else if (cachedDataRemaining >= 0
-            && mSettings.IsSizeBasedBufferingMode(mSettings.mRebufferingMode)) {
-        ALOGV("onPollBuffering_l: cachedDataRemaining %zd bytes",
-                cachedDataRemaining);
-
-        if (cachedDataRemaining < (mSettings.mRebufferingWatermarkLowKB << 10)) {
-            startBufferingIfNecessary_l();
-        } else if (cachedDataRemaining > (mSettings.mRebufferingWatermarkHighKB << 10)) {
-            stopBufferingIfNecessary_l();
-        }
+        ALOGV("onPollBuffering: cachedDurationUs %.1f sec", cachedDurationUs / 1000000.0f);
     }
 
-    schedulePollBuffering_l();
-}
-
-void NuPlayer::GenericSource::BufferingMonitor::onMessageReceived(const sp<AMessage> &msg) {
-    switch (msg->what()) {
-      case kWhatPollBuffering:
-      {
-          int32_t generation;
-          CHECK(msg->findInt32("generation", &generation));
-          Mutex::Autolock _l(mLock);
-          if (generation == mPollBufferingGeneration) {
-              onPollBuffering_l();
-          }
-          break;
-      }
-      default:
-          TRESPASS();
-          break;
-    }
+    schedulePollBuffering();
 }
 
 // Modular DRM
 status_t NuPlayer::GenericSource::prepareDrm(
-        const uint8_t uuid[16], const Vector<uint8_t> &drmSessionId, sp<ICrypto> *crypto)
-{
+        const uint8_t uuid[16], const Vector<uint8_t> &drmSessionId, sp<ICrypto> *outCrypto) {
+    Mutex::Autolock _l(mLock);
     ALOGV("prepareDrm");
 
-    sp<AMessage> msg = new AMessage(kWhatPrepareDrm, this);
-    // synchronous call so just passing the address but with local copies of "const" args
-    uint8_t UUID[16];
-    memcpy(UUID, uuid, sizeof(UUID));
-    Vector<uint8_t> sessionId = drmSessionId;
-    msg->setPointer("uuid", (void*)UUID);
-    msg->setPointer("drmSessionId", (void*)&sessionId);
-    msg->setPointer("crypto", (void*)crypto);
-
-    sp<AMessage> response;
-    status_t status = msg->postAndAwaitResponse(&response);
-
-    if (status == OK && response != NULL) {
-        CHECK(response->findInt32("status", &status));
-        ALOGV_IF(status == OK, "prepareDrm: mCrypto: %p (%d)", crypto->get(),
-                (*crypto != NULL ? (*crypto)->getStrongCount() : 0));
-        ALOGD("prepareDrm ret: %d ", status);
-    } else {
-        ALOGE("prepareDrm err: %d", status);
-    }
-
-    return status;
-}
-
-status_t NuPlayer::GenericSource::releaseDrm()
-{
-    ALOGV("releaseDrm");
-
-    sp<AMessage> msg = new AMessage(kWhatReleaseDrm, this);
-
-    // synchronous call to update the source states before the player proceedes with crypto cleanup
-    sp<AMessage> response;
-    status_t status = msg->postAndAwaitResponse(&response);
-
-    if (status == OK && response != NULL) {
-        ALOGD("releaseDrm ret: OK ");
-    } else {
-        ALOGE("releaseDrm err: %d", status);
-    }
-
-    return status;
-}
-
-status_t NuPlayer::GenericSource::onPrepareDrm(const sp<AMessage> &msg)
-{
-    ALOGV("onPrepareDrm ");
-
     mIsDrmProtected = false;
     mIsDrmReleased = false;
     mIsSecure = false;
 
-    uint8_t *uuid;
-    Vector<uint8_t> *drmSessionId;
-    sp<ICrypto> *outCrypto;
-    CHECK(msg->findPointer("uuid", (void**)&uuid));
-    CHECK(msg->findPointer("drmSessionId", (void**)&drmSessionId));
-    CHECK(msg->findPointer("crypto", (void**)&outCrypto));
-
     status_t status = OK;
-    sp<ICrypto> crypto = NuPlayerDrm::createCryptoAndPlugin(uuid, *drmSessionId, status);
+    sp<ICrypto> crypto = NuPlayerDrm::createCryptoAndPlugin(uuid, drmSessionId, status);
     if (crypto == NULL) {
-        ALOGE("onPrepareDrm: createCrypto failed. status: %d", status);
+        ALOGE("prepareDrm: createCrypto failed. status: %d", status);
         return status;
     }
-    ALOGV("onPrepareDrm: createCryptoAndPlugin succeeded for uuid: %s",
+    ALOGV("prepareDrm: createCryptoAndPlugin succeeded for uuid: %s",
             DrmUUID::toHexString(uuid).string());
 
     *outCrypto = crypto;
@@ -1980,14 +1569,14 @@
 
     if (mMimes.size() == 0) {
         status = UNKNOWN_ERROR;
-        ALOGE("onPrepareDrm: Unexpected. Must have at least one track. status: %d", status);
+        ALOGE("prepareDrm: Unexpected. Must have at least one track. status: %d", status);
         return status;
     }
 
     // first mime in this list is either the video track, or the first audio track
     const char *mime = mMimes[0].string();
     mIsSecure = crypto->requiresSecureDecoderComponent(mime);
-    ALOGV("onPrepareDrm: requiresSecureDecoderComponent mime: %s  isSecure: %d",
+    ALOGV("prepareDrm: requiresSecureDecoderComponent mime: %s  isSecure: %d",
             mime, mIsSecure);
 
     // Checking the member flags while in the looper to send out the notification.
@@ -2001,18 +1590,27 @@
             FLAG_CAN_SEEK_FORWARD |
             FLAG_CAN_SEEK);
 
+    if (status == OK) {
+        ALOGV("prepareDrm: mCrypto: %p (%d)", outCrypto->get(),
+                (*outCrypto != NULL ? (*outCrypto)->getStrongCount() : 0));
+        ALOGD("prepareDrm ret: %d ", status);
+    } else {
+        ALOGE("prepareDrm err: %d", status);
+    }
     return status;
 }
 
-status_t NuPlayer::GenericSource::onReleaseDrm()
-{
+status_t NuPlayer::GenericSource::releaseDrm() {
+    Mutex::Autolock _l(mLock);
+    ALOGV("releaseDrm");
+
     if (mIsDrmProtected) {
         mIsDrmProtected = false;
         // to prevent returning any more buffer after stop/releaseDrm (b/37960096)
         mIsDrmReleased = true;
-        ALOGV("onReleaseDrm: mIsDrmProtected is reset.");
+        ALOGV("releaseDrm: mIsDrmProtected is reset.");
     } else {
-        ALOGE("onReleaseDrm: mIsDrmProtected is already false.");
+        ALOGE("releaseDrm: mIsDrmProtected is already false.");
     }
 
     return OK;
diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.h b/media/libmediaplayerservice/nuplayer/GenericSource.h
index 381bcac..807b620 100644
--- a/media/libmediaplayerservice/nuplayer/GenericSource.h
+++ b/media/libmediaplayerservice/nuplayer/GenericSource.h
@@ -24,6 +24,7 @@
 #include "ATSParser.h"
 
 #include <media/mediaplayer.h>
+#include <media/stagefright/MediaBuffer.h>
 
 namespace android {
 
@@ -85,13 +86,11 @@
 
     virtual bool isStreaming() const;
 
-    virtual void setOffloadAudio(bool offload);
-
     // Modular DRM
     virtual void signalBufferReturned(MediaBuffer *buffer);
 
     virtual status_t prepareDrm(
-            const uint8_t uuid[16], const Vector<uint8_t> &drmSessionId, sp<ICrypto> *crypto);
+            const uint8_t uuid[16], const Vector<uint8_t> &drmSessionId, sp<ICrypto> *outCrypto);
 
     virtual status_t releaseDrm();
 
@@ -113,17 +112,10 @@
         kWhatSendTimedTextData,
         kWhatChangeAVSource,
         kWhatPollBuffering,
-        kWhatGetFormat,
-        kWhatGetSelectedTrack,
-        kWhatSelectTrack,
-        kWhatSeek,
         kWhatReadBuffer,
         kWhatStart,
         kWhatResume,
         kWhatSecureDecodersInstantiated,
-        // Modular DRM
-        kWhatPrepareDrm,
-        kWhatReleaseDrm,
     };
 
     struct Track {
@@ -132,84 +124,6 @@
         sp<AnotherPacketSource> mPackets;
     };
 
-    // Helper to monitor buffering status. The polling happens every second.
-    // When necessary, it will send out buffering events to the player.
-    struct BufferingMonitor : public AHandler {
-    public:
-        explicit BufferingMonitor(const sp<AMessage> &notify);
-
-        void getDefaultBufferingSettings(BufferingSettings *buffering /* nonnull */);
-        status_t setBufferingSettings(const BufferingSettings &buffering);
-
-        // Set up state.
-        void prepare(const sp<NuCachedSource2> &cachedSource,
-                int64_t durationUs,
-                int64_t bitrate,
-                bool isStreaming);
-        // Stop and reset buffering monitor.
-        void stop();
-        // Cancel the current monitor task.
-        void cancelPollBuffering();
-        // Restart the monitor task.
-        void restartPollBuffering();
-        // Stop buffering task and send out corresponding events.
-        void stopBufferingIfNecessary();
-        // Make sure data source is getting data.
-        void ensureCacheIsFetching();
-        // Update media time of just extracted buffer from data source.
-        void updateQueuedTime(bool isAudio, int64_t timeUs);
-
-        // Set the offload mode.
-        void setOffloadAudio(bool offload);
-        // Update media time of last dequeued buffer which is sent to the decoder.
-        void updateDequeuedBufferTime(int64_t mediaUs);
-
-    protected:
-        virtual ~BufferingMonitor();
-        virtual void onMessageReceived(const sp<AMessage> &msg);
-
-    private:
-        enum {
-            kWhatPollBuffering,
-        };
-
-        sp<AMessage> mNotify;
-
-        sp<NuCachedSource2> mCachedSource;
-        int64_t mDurationUs;
-        int64_t mBitrate;
-        bool mIsStreaming;
-
-        int64_t mAudioTimeUs;
-        int64_t mVideoTimeUs;
-        int32_t mPollBufferingGeneration;
-        bool mPrepareBuffering;
-        bool mBuffering;
-        int32_t mPrevBufferPercentage;
-
-        mutable Mutex mLock;
-
-        BufferingSettings mSettings;
-        bool mOffloadAudio;
-        int64_t mFirstDequeuedBufferRealUs;
-        int64_t mFirstDequeuedBufferMediaUs;
-        int64_t mlastDequeuedBufferMediaUs;
-
-        void prepare_l(const sp<NuCachedSource2> &cachedSource,
-                int64_t durationUs,
-                int64_t bitrate,
-                bool isStreaming);
-        void cancelPollBuffering_l();
-        void notifyBufferingUpdate_l(int32_t percentage);
-        void startBufferingIfNecessary_l();
-        void stopBufferingIfNecessary_l();
-        void sendCacheStats_l();
-        void ensureCacheIsFetching_l();
-        int64_t getLastReadPosition_l();
-        void onPollBuffering_l();
-        void schedulePollBuffering_l();
-    };
-
     Vector<sp<IMediaSource> > mSources;
     Track mAudioTrack;
     int64_t mAudioTimeUs;
@@ -220,6 +134,13 @@
     Track mSubtitleTrack;
     Track mTimedTextTrack;
 
+    BufferingSettings mBufferingSettings;
+    int32_t mPrevBufferPercentage;
+    int32_t mPollBufferingGeneration;
+    bool mSentPauseOnBuffering;
+
+    int32_t mAudioDataGeneration;
+    int32_t mVideoDataGeneration;
     int32_t mFetchSubtitleDataGeneration;
     int32_t mFetchTimedTextDataGeneration;
     int64_t mDurationUs;
@@ -237,22 +158,20 @@
     int64_t mOffset;
     int64_t mLength;
 
+    bool mDisconnected;
     sp<DataSource> mDataSource;
     sp<NuCachedSource2> mCachedSource;
     sp<DataSource> mHttpSource;
     sp<MetaData> mFileMeta;
     bool mStarted;
-    bool mStopRead;
+    bool mPreparing;
     int64_t mBitrate;
-    sp<BufferingMonitor> mBufferingMonitor;
     uint32_t mPendingReadBufferTypes;
     sp<ABuffer> mGlobalTimedText;
 
-    mutable Mutex mReadBufferLock;
-    mutable Mutex mDisconnectLock;
+    mutable Mutex mLock;
 
     sp<ALooper> mLooper;
-    sp<ALooper> mBufferingMonitorLooper;
 
     void resetDataSource();
 
@@ -264,21 +183,6 @@
     void finishPrepareAsync();
     status_t startSources();
 
-    void onGetFormatMeta(const sp<AMessage>& msg) const;
-    sp<MetaData> doGetFormatMeta(bool audio) const;
-
-    void onGetTrackInfo(const sp<AMessage>& msg) const;
-    sp<AMessage> doGetTrackInfo(size_t trackIndex) const;
-
-    void onGetSelectedTrack(const sp<AMessage>& msg) const;
-    ssize_t doGetSelectedTrack(media_track_type type) const;
-
-    void onSelectTrack(const sp<AMessage>& msg);
-    status_t doSelectTrack(size_t trackIndex, bool select, int64_t timeUs);
-
-    void onSeek(const sp<AMessage>& msg);
-    status_t doSeek(int64_t seekTimeUs, MediaPlayerSeekMode mode);
-
     void onPrepareAsync();
 
     void fetchTextData(
@@ -313,6 +217,15 @@
     void queueDiscontinuityIfNeeded(
             bool seeking, bool formatChange, media_track_type trackType, Track *track);
 
+    void schedulePollBuffering();
+    void onPollBuffering();
+    void notifyBufferingUpdate(int32_t percentage);
+
+    void sendCacheStats();
+
+    sp<MetaData> getFormatMeta_l(bool audio);
+    int32_t getDataGeneration(media_track_type type) const;
+
     // Modular DRM
     // The source is DRM protected and is prepared for DRM.
     bool mIsDrmProtected;
@@ -321,8 +234,6 @@
     Vector<String8> mMimes;
 
     status_t checkDrmInfo();
-    status_t onPrepareDrm(const sp<AMessage> &msg);
-    status_t onReleaseDrm();
 
     DISALLOW_EVIL_CONSTRUCTORS(GenericSource);
 };
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
index 29b1781..2aa5c40 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
@@ -48,6 +48,7 @@
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/foundation/avc_utils.h>
 #include <media/stagefright/MediaBuffer.h>
 #include <media/stagefright/MediaClock.h>
 #include <media/stagefright/MediaDefs.h>
@@ -57,7 +58,6 @@
 #include <gui/IGraphicBufferProducer.h>
 #include <gui/Surface.h>
 
-#include "avc_utils.h"
 
 #include "ESDS.h"
 #include <media/stagefright/Utils.h>
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerCCDecoder.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerCCDecoder.cpp
index 73b07bb..0a8b97f 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerCCDecoder.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerCCDecoder.cpp
@@ -19,13 +19,13 @@
 #include <utils/Log.h>
 #include <inttypes.h>
 
-#include "avc_utils.h"
 #include "NuPlayerCCDecoder.h"
 
 #include <media/stagefright/foundation/ABitReader.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/foundation/avc_utils.h>
 #include <media/stagefright/MediaDefs.h>
 
 namespace android {
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
index cd770b6..a84d0e5 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
@@ -33,6 +33,7 @@
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/foundation/avc_utils.h>
 #include <media/stagefright/MediaBuffer.h>
 #include <media/stagefright/MediaCodec.h>
 #include <media/stagefright/MediaDefs.h>
@@ -40,7 +41,6 @@
 #include <media/stagefright/SurfaceUtils.h>
 #include <gui/Surface.h>
 
-#include "avc_utils.h"
 #include "ATSParser.h"
 
 namespace android {
@@ -945,7 +945,8 @@
                             mCurrentMaxVideoTemporalLayerId);
                 } else if (layerId > mCurrentMaxVideoTemporalLayerId) {
                     mCurrentMaxVideoTemporalLayerId = layerId;
-                } else if (layerId == 0 && mNumVideoTemporalLayerTotal > 1 && IsIDR(accessUnit)) {
+                } else if (layerId == 0 && mNumVideoTemporalLayerTotal > 1
+                        && IsIDR(accessUnit->data(), accessUnit->size())) {
                     mCurrentMaxVideoTemporalLayerId = mNumVideoTemporalLayerTotal - 1;
                 }
             }
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
index de2c6db..cc7f688 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
@@ -110,6 +110,7 @@
       mAnchorTimeMediaUs(-1),
       mAnchorNumFramesWritten(-1),
       mVideoLateByUs(0ll),
+      mNextVideoTimeMediaUs(-1),
       mHasAudio(false),
       mHasVideo(false),
       mNotifyCompleteAudio(false),
@@ -301,6 +302,7 @@
 
         mMediaClock->clearAnchor();
         mVideoLateByUs = 0;
+        mNextVideoTimeMediaUs = -1;
         mSyncQueues = false;
     }
 
@@ -1277,9 +1279,10 @@
             mAnchorTimeMediaUs = mediaTimeUs;
         }
     }
+    mNextVideoTimeMediaUs = mediaTimeUs + 100000;
     if (!mHasAudio) {
         // smooth out videos >= 10fps
-        mMediaClock->updateMaxTimeMedia(mediaTimeUs + 100000);
+        mMediaClock->updateMaxTimeMedia(mNextVideoTimeMediaUs);
     }
 
     if (!mVideoSampleReceived || mediaTimeUs < mAudioFirstAnchorTimeMediaUs) {
@@ -1411,6 +1414,13 @@
         // Video might outlive audio. Clear anchor to enable video only case.
         mAnchorTimeMediaUs = -1;
         mHasAudio = false;
+        if (mNextVideoTimeMediaUs >= 0) {
+            int64_t mediaUs = 0;
+            mMediaClock->getMediaTime(ALooper::GetNowUs(), &mediaUs);
+            if (mNextVideoTimeMediaUs > mediaUs) {
+                mMediaClock->updateMaxTimeMedia(mNextVideoTimeMediaUs);
+            }
+        }
     }
 }
 
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
index 567f8f1..a047975 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
@@ -177,6 +177,7 @@
     int64_t mAnchorTimeMediaUs;
     int64_t mAnchorNumFramesWritten;
     int64_t mVideoLateByUs;
+    int64_t mNextVideoTimeMediaUs;
     bool mHasAudio;
     bool mHasVideo;
 
diff --git a/media/libmediaplayerservice/nuplayer/StreamingSource.cpp b/media/libmediaplayerservice/nuplayer/StreamingSource.cpp
index fc0803b..36abcdd 100644
--- a/media/libmediaplayerservice/nuplayer/StreamingSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/StreamingSource.cpp
@@ -24,10 +24,10 @@
 #include "AnotherPacketSource.h"
 #include "NuPlayerStreamListener.h"
 
+#include <media/MediaSource.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
-#include <media/stagefright/MediaSource.h>
 #include <media/stagefright/MetaData.h>
 #include <media/stagefright/Utils.h>
 
diff --git a/media/libstagefright/AACWriter.cpp b/media/libstagefright/AACWriter.cpp
index 9d90dbd..281af47 100644
--- a/media/libstagefright/AACWriter.cpp
+++ b/media/libstagefright/AACWriter.cpp
@@ -30,8 +30,8 @@
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/MediaSource.h>
 #include <media/stagefright/MetaData.h>
+#include <media/MediaSource.h>
 #include <media/mediarecorder.h>
 
 namespace android {
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index a2eb9a8..d9fdfe3 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -28,8 +28,7 @@
 
 #include <media/stagefright/ACodec.h>
 
-#include <binder/MemoryDealer.h>
-
+#include <media/stagefright/foundation/avc_utils.h>
 #include <media/stagefright/foundation/hexdump.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
@@ -55,7 +54,6 @@
 #include <media/openmax/OMX_IndexExt.h>
 #include <media/openmax/OMX_AsString.h>
 
-#include "include/avc_utils.h"
 #include "include/ACodecBufferChannel.h"
 #include "include/DataConverter.h"
 #include "include/SecureBuffer.h"
@@ -575,8 +573,6 @@
     memset(&mLastNativeWindowCrop, 0, sizeof(mLastNativeWindowCrop));
 
     changeState(mUninitializedState);
-
-    mTrebleFlag = false;
 }
 
 ACodec::~ACodec() {
@@ -828,11 +824,7 @@
 status_t ACodec::allocateBuffersOnPort(OMX_U32 portIndex) {
     CHECK(portIndex == kPortIndexInput || portIndex == kPortIndexOutput);
 
-    if (getTrebleFlag()) {
-        CHECK(mAllocator[portIndex] == NULL);
-    } else {
-        CHECK(mDealer[portIndex] == NULL);
-    }
+    CHECK(mAllocator[portIndex] == NULL);
     CHECK(mBuffers[portIndex].isEmpty());
 
     status_t err;
@@ -874,7 +866,10 @@
                 }
             }
 
-            size_t alignment = MemoryDealer::getAllocationAlignment();
+            size_t alignment = 32; // This is the value currently returned by
+                                   // MemoryDealer::getAllocationAlignment().
+                                   // TODO: Fix this when Treble has
+                                   // MemoryHeap/MemoryDealer.
 
             ALOGV("[%s] Allocating %u buffers of size %zu (from %u using %s) on %s port",
                     mComponentName.c_str(),
@@ -896,18 +891,15 @@
             }
 
             if (mode != IOMX::kPortModePresetSecureBuffer) {
-                if (getTrebleFlag()) {
-                    mAllocator[portIndex] = TAllocator::getService("ashmem");
-                    if (mAllocator[portIndex] == nullptr) {
-                        ALOGE("hidl allocator on port %d is null",
-                                (int)portIndex);
-                        return NO_MEMORY;
-                    }
-                } else {
-                    size_t totalSize = def.nBufferCountActual *
-                            (alignedSize + alignedConvSize);
-                    mDealer[portIndex] = new MemoryDealer(totalSize, "ACodec");
+                mAllocator[portIndex] = TAllocator::getService("ashmem");
+                if (mAllocator[portIndex] == nullptr) {
+                    ALOGE("hidl allocator on port %d is null",
+                            (int)portIndex);
+                    return NO_MEMORY;
                 }
+                // TODO: When Treble has MemoryHeap/MemoryDealer, we should
+                // specify the heap size to be
+                // def.nBufferCountActual * (alignedSize + alignedConvSize).
             }
 
             const sp<AMessage> &format =
@@ -936,23 +928,55 @@
                             : new SecureBuffer(format, native_handle, bufSize);
                     info.mCodecData = info.mData;
                 } else {
-                    if (getTrebleFlag()) {
+                    bool success;
+                    auto transStatus = mAllocator[portIndex]->allocate(
+                            bufSize,
+                            [&success, &hidlMemToken](
+                                    bool s,
+                                    hidl_memory const& m) {
+                                success = s;
+                                hidlMemToken = m;
+                            });
+
+                    if (!transStatus.isOk()) {
+                        ALOGE("hidl's AshmemAllocator failed at the "
+                                "transport: %s",
+                                transStatus.description().c_str());
+                        return NO_MEMORY;
+                    }
+                    if (!success) {
+                        return NO_MEMORY;
+                    }
+                    hidlMem = mapMemory(hidlMemToken);
+                    if (hidlMem == nullptr) {
+                        return NO_MEMORY;
+                    }
+                    err = mOMXNode->useBuffer(
+                            portIndex, hidlMemToken, &info.mBufferID);
+
+                    if (mode == IOMX::kPortModeDynamicANWBuffer) {
+                        VideoNativeMetadata* metaData = (VideoNativeMetadata*)(
+                                (void*)hidlMem->getPointer());
+                        metaData->nFenceFd = -1;
+                    }
+
+                    info.mCodecData = new SharedMemoryBuffer(
+                            format, hidlMem);
+                    info.mCodecRef = hidlMem;
+
+                    // if we require conversion, allocate conversion buffer for client use;
+                    // otherwise, reuse codec buffer
+                    if (mConverter[portIndex] != NULL) {
+                        CHECK_GT(conversionBufferSize, (size_t)0);
                         bool success;
-                        auto transStatus = mAllocator[portIndex]->allocate(
-                                bufSize,
+                        mAllocator[portIndex]->allocate(
+                                conversionBufferSize,
                                 [&success, &hidlMemToken](
                                         bool s,
                                         hidl_memory const& m) {
                                     success = s;
                                     hidlMemToken = m;
                                 });
-
-                        if (!transStatus.isOk()) {
-                            ALOGE("hidl's AshmemAllocator failed at the "
-                                    "transport: %s",
-                                    transStatus.description().c_str());
-                            return NO_MEMORY;
-                        }
                         if (!success) {
                             return NO_MEMORY;
                         }
@@ -960,67 +984,8 @@
                         if (hidlMem == nullptr) {
                             return NO_MEMORY;
                         }
-                        err = mOMXNode->useBuffer(
-                                portIndex, hidlMemToken, &info.mBufferID);
-                    } else {
-                        mem = mDealer[portIndex]->allocate(bufSize);
-                        if (mem == NULL || mem->pointer() == NULL) {
-                            return NO_MEMORY;
-                        }
-
-                        err = mOMXNode->useBuffer(
-                                portIndex, mem, &info.mBufferID);
-                    }
-
-                    if (mode == IOMX::kPortModeDynamicANWBuffer) {
-                        VideoNativeMetadata* metaData = (VideoNativeMetadata*)(
-                                getTrebleFlag() ?
-                                (void*)hidlMem->getPointer() : mem->pointer());
-                        metaData->nFenceFd = -1;
-                    }
-
-                    if (getTrebleFlag()) {
-                        info.mCodecData = new SharedMemoryBuffer(
-                                format, hidlMem);
-                        info.mCodecRef = hidlMem;
-                    } else {
-                        info.mCodecData = new SharedMemoryBuffer(
-                                format, mem);
-                        info.mCodecRef = mem;
-                    }
-
-                    // if we require conversion, allocate conversion buffer for client use;
-                    // otherwise, reuse codec buffer
-                    if (mConverter[portIndex] != NULL) {
-                        CHECK_GT(conversionBufferSize, (size_t)0);
-                        if (getTrebleFlag()) {
-                            bool success;
-                            mAllocator[portIndex]->allocate(
-                                    conversionBufferSize,
-                                    [&success, &hidlMemToken](
-                                            bool s,
-                                            hidl_memory const& m) {
-                                        success = s;
-                                        hidlMemToken = m;
-                                    });
-                            if (!success) {
-                                return NO_MEMORY;
-                            }
-                            hidlMem = mapMemory(hidlMemToken);
-                            if (hidlMem == nullptr) {
-                                return NO_MEMORY;
-                            }
-                            info.mData = new SharedMemoryBuffer(format, hidlMem);
-                            info.mMemRef = hidlMem;
-                        } else {
-                            mem = mDealer[portIndex]->allocate(
-                                    conversionBufferSize);
-                            if (mem == NULL|| mem->pointer() == NULL) {
-                                return NO_MEMORY;
-                            }
-                            info.mData = new SharedMemoryBuffer(format, mem);
-                            info.mMemRef = mem;
-                        }
+                        info.mData = new SharedMemoryBuffer(format, hidlMem);
+                        info.mMemRef = hidlMem;
                     } else {
                         info.mData = info.mCodecData;
                         info.mMemRef = info.mCodecRef;
@@ -1581,11 +1546,7 @@
         }
     }
 
-    if (getTrebleFlag()) {
-        mAllocator[portIndex].clear();
-    } else {
-        mDealer[portIndex].clear();
-    }
+    mAllocator[portIndex].clear();
     return err;
 }
 
@@ -3781,6 +3742,8 @@
     } else {
         mFps = (double)framerate;
     }
+    // propagate framerate to the output so that the muxer has it
+    outputFormat->setInt32("frame-rate", (int32_t)mFps);
 
     video_def->xFramerate = (OMX_U32)(mFps * 65536);
     video_def->eCompressionFormat = OMX_VIDEO_CodingUnused;
@@ -6052,7 +6015,7 @@
             }
 #if 0
             if (mCodec->mNativeWindow == NULL) {
-                if (IsIDR(info->mData)) {
+                if (IsIDR(info->mData->data(), info->mData->size())) {
                     ALOGI("IDR frame");
                 }
             }
@@ -6249,13 +6212,8 @@
 
     if (mDeathNotifier != NULL) {
         if (mCodec->mOMXNode != NULL) {
-            if (mCodec->getTrebleFlag()) {
-                auto tOmxNode = mCodec->mOMXNode->getHalInterface();
-                tOmxNode->unlinkToDeath(mDeathNotifier);
-            } else {
-                sp<IBinder> binder = IInterface::asBinder(mCodec->mOMXNode);
-                binder->unlinkToDeath(mDeathNotifier);
-            }
+            auto tOmxNode = mCodec->mOMXNode->getHalInterface();
+            tOmxNode->unlinkToDeath(mDeathNotifier);
         }
         mDeathNotifier.clear();
     }
@@ -6403,8 +6361,7 @@
         componentName = matchingCodecs[matchIndex];
 
         OMXClient client;
-        bool trebleFlag;
-        if (client.connect(owners[matchIndex].c_str(), &trebleFlag) != OK) {
+        if (client.connect(owners[matchIndex].c_str()) != OK) {
             mCodec->signalError(OMX_ErrorUndefined, NO_INIT);
             return false;
         }
@@ -6417,7 +6374,6 @@
         androidSetThreadPriority(tid, prevPriority);
 
         if (err == OK) {
-            mCodec->setTrebleFlag(trebleFlag);
             break;
         } else {
             ALOGW("Allocating component '%s' failed, try next one.", componentName.c_str());
@@ -6439,17 +6395,9 @@
     }
 
     mDeathNotifier = new DeathNotifier(notify);
-    if (mCodec->getTrebleFlag()) {
-        auto tOmxNode = omxNode->getHalInterface();
-        if (!tOmxNode->linkToDeath(mDeathNotifier, 0)) {
-            mDeathNotifier.clear();
-        }
-    } else {
-        if (IInterface::asBinder(omxNode)->linkToDeath(mDeathNotifier) != OK) {
-            // This was a local binder, if it dies so do we, we won't care
-            // about any notifications in the afterlife.
-            mDeathNotifier.clear();
-        }
+    auto tOmxNode = omxNode->getHalInterface();
+    if (!tOmxNode->linkToDeath(mDeathNotifier, 0)) {
+        mDeathNotifier.clear();
     }
 
     notify = new AMessage(kWhatOMXMessageList, mCodec);
@@ -7856,11 +7804,7 @@
                             mCodec->mBuffers[kPortIndexOutput].size());
                     err = FAILED_TRANSACTION;
                 } else {
-                    if (mCodec->getTrebleFlag()) {
-                        mCodec->mAllocator[kPortIndexOutput].clear();
-                    } else {
-                        mCodec->mDealer[kPortIndexOutput].clear();
-                    }
+                    mCodec->mAllocator[kPortIndexOutput].clear();
                 }
 
                 if (err == OK) {
@@ -8462,12 +8406,4 @@
     return OK;
 }
 
-void ACodec::setTrebleFlag(bool trebleFlag) {
-    mTrebleFlag = trebleFlag;
-}
-
-bool ACodec::getTrebleFlag() const {
-    return mTrebleFlag;
-}
-
 }  // namespace android
diff --git a/media/libstagefright/AMRWriter.cpp b/media/libstagefright/AMRWriter.cpp
index f53d7f0..910abc6 100644
--- a/media/libstagefright/AMRWriter.cpp
+++ b/media/libstagefright/AMRWriter.cpp
@@ -25,8 +25,8 @@
 #include <media/stagefright/MediaBuffer.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/MediaSource.h>
 #include <media/stagefright/MetaData.h>
+#include <media/MediaSource.h>
 #include <media/mediarecorder.h>
 
 namespace android {
diff --git a/media/libstagefright/AVIExtractor.cpp b/media/libstagefright/AVIExtractor.cpp
index 5a6211e..406074b 100644
--- a/media/libstagefright/AVIExtractor.cpp
+++ b/media/libstagefright/AVIExtractor.cpp
@@ -18,14 +18,14 @@
 #define LOG_TAG "AVIExtractor"
 #include <utils/Log.h>
 
-#include "include/avc_utils.h"
 #include "include/AVIExtractor.h"
 
 #include <binder/ProcessState.h>
+#include <media/DataSource.h>
+#include <media/stagefright/foundation/avc_utils.h>
 #include <media/stagefright/foundation/hexdump.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/DataSource.h>
 #include <media/stagefright/MediaBuffer.h>
 #include <media/stagefright/MediaBufferGroup.h>
 #include <media/stagefright/MediaDefs.h>
diff --git a/media/libstagefright/Android.bp b/media/libstagefright/Android.bp
index fc2bff3..7ba4b7d 100644
--- a/media/libstagefright/Android.bp
+++ b/media/libstagefright/Android.bp
@@ -4,6 +4,28 @@
     vendor_available: true,
 }
 
+cc_library_static {
+    name: "libstagefright_esds",
+
+    srcs: ["ESDS.cpp"],
+
+    cflags: [
+        "-Werror",
+        "-Wall",
+    ],
+    sanitize: {
+        misc_undefined: [
+            "signed-integer-overflow",
+        ],
+        cfi: true,
+        diag: {
+            cfi: true,
+        },
+    },
+
+    shared_libs: ["libmedia"],
+}
+
 cc_library_shared {
     name: "libstagefright",
 
@@ -21,13 +43,14 @@
         "CameraSource.cpp",
         "CameraSourceTimeLapse.cpp",
         "DataConverter.cpp",
-        "DataSource.cpp",
+        "DataSourceFactory.cpp",
         "DataURISource.cpp",
-        "ESDS.cpp",
         "FileSource.cpp",
+        "FrameDecoder.cpp",
         "FrameRenderTracker.cpp",
         "HTTPBase.cpp",
         "HevcUtils.cpp",
+        "InterfaceUtils.cpp",
         "JPEGSource.cpp",
         "MPEG2TSWriter.cpp",
         "MPEG4Writer.cpp",
@@ -37,11 +60,10 @@
         "MediaCodecList.cpp",
         "MediaCodecListOverrides.cpp",
         "MediaCodecSource.cpp",
-        "MediaExtractor.cpp",
+        "MediaExtractorFactory.cpp",
         "MediaSync.cpp",
         "http/MediaHTTP.cpp",
         "MediaMuxer.cpp",
-        "MediaSource.cpp",
         "NuCachedSource2.cpp",
         "NuMediaExtractor.cpp",
         "OMXClient.cpp",
@@ -57,7 +79,6 @@
         "ThrottledSource.cpp",
         "Utils.cpp",
         "VideoFrameScheduler.cpp",
-        "avc_utils.cpp",
     ],
 
     shared_libs: [
@@ -70,7 +91,9 @@
         "libgui",
         "liblog",
         "libmedia",
+        "libmedia_omx",
         "libaudioclient",
+        "libmediaextractor",
         "libmediametrics",
         "libmediautils",
         "libnetd_client",
@@ -97,6 +120,7 @@
         "libvpx",
         "libwebm",
         "libstagefright_mpeg2support",
+        "libstagefright_esds",
         "libstagefright_id3",
         "libFLAC",
     ],
diff --git a/media/libstagefright/AudioPlayer.cpp b/media/libstagefright/AudioPlayer.cpp
index 1d441eb..16ea5b5 100644
--- a/media/libstagefright/AudioPlayer.cpp
+++ b/media/libstagefright/AudioPlayer.cpp
@@ -23,6 +23,7 @@
 
 #include <binder/IPCThreadState.h>
 #include <media/AudioTrack.h>
+#include <media/MediaSource.h>
 #include <media/openmax/OMX_Audio.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/ALookup.h>
@@ -30,7 +31,6 @@
 #include <media/stagefright/AudioPlayer.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/MediaSource.h>
 #include <media/stagefright/MetaData.h>
 #include <media/stagefright/Utils.h>
 
diff --git a/media/libstagefright/CallbackMediaSource.cpp b/media/libstagefright/CallbackMediaSource.cpp
index cc7147e..54e6142 100644
--- a/media/libstagefright/CallbackMediaSource.cpp
+++ b/media/libstagefright/CallbackMediaSource.cpp
@@ -15,6 +15,7 @@
  */
 
 #include <media/stagefright/CallbackMediaSource.h>
+#include <media/IMediaSource.h>
 
 namespace android {
 
@@ -36,7 +37,7 @@
 }
 
 status_t CallbackMediaSource::read(MediaBuffer **buffer, const ReadOptions *options) {
-    return mSource->read(buffer, reinterpret_cast<const MediaSource::ReadOptions*>(options));
+    return mSource->read(buffer, reinterpret_cast<const ReadOptions*>(options));
 }
 
 status_t CallbackMediaSource::pause() {
diff --git a/media/libstagefright/DataSource.cpp b/media/libstagefright/DataSource.cpp
deleted file mode 100644
index e9aaa84..0000000
--- a/media/libstagefright/DataSource.cpp
+++ /dev/null
@@ -1,246 +0,0 @@
-/*
- * Copyright (C) 2009 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_NDEBUG 0
-#define LOG_TAG "DataSource"
-
-#include "include/CallbackDataSource.h"
-#include "include/HTTPBase.h"
-#include "include/NuCachedSource2.h"
-
-#include <media/IDataSource.h>
-#include <media/IMediaHTTPConnection.h>
-#include <media/IMediaHTTPService.h>
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/foundation/AMessage.h>
-#include <media/stagefright/foundation/ByteUtils.h>
-#include <media/stagefright/DataSource.h>
-#include <media/stagefright/DataURISource.h>
-#include <media/stagefright/FileSource.h>
-#include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/MediaHTTP.h>
-#include <media/stagefright/RemoteDataSource.h>
-#include <utils/String8.h>
-
-#include <cutils/properties.h>
-
-#include <private/android_filesystem_config.h>
-
-namespace android {
-
-bool DataSource::getUInt16(off64_t offset, uint16_t *x) {
-    *x = 0;
-
-    uint8_t byte[2];
-    if (readAt(offset, byte, 2) != 2) {
-        return false;
-    }
-
-    *x = (byte[0] << 8) | byte[1];
-
-    return true;
-}
-
-bool DataSource::getUInt24(off64_t offset, uint32_t *x) {
-    *x = 0;
-
-    uint8_t byte[3];
-    if (readAt(offset, byte, 3) != 3) {
-        return false;
-    }
-
-    *x = (byte[0] << 16) | (byte[1] << 8) | byte[2];
-
-    return true;
-}
-
-bool DataSource::getUInt32(off64_t offset, uint32_t *x) {
-    *x = 0;
-
-    uint32_t tmp;
-    if (readAt(offset, &tmp, 4) != 4) {
-        return false;
-    }
-
-    *x = ntohl(tmp);
-
-    return true;
-}
-
-bool DataSource::getUInt64(off64_t offset, uint64_t *x) {
-    *x = 0;
-
-    uint64_t tmp;
-    if (readAt(offset, &tmp, 8) != 8) {
-        return false;
-    }
-
-    *x = ntoh64(tmp);
-
-    return true;
-}
-
-bool DataSource::getUInt16Var(off64_t offset, uint16_t *x, size_t size) {
-    if (size == 2) {
-        return getUInt16(offset, x);
-    }
-    if (size == 1) {
-        uint8_t tmp;
-        if (readAt(offset, &tmp, 1) == 1) {
-            *x = tmp;
-            return true;
-        }
-    }
-    return false;
-}
-
-bool DataSource::getUInt32Var(off64_t offset, uint32_t *x, size_t size) {
-    if (size == 4) {
-        return getUInt32(offset, x);
-    }
-    if (size == 2) {
-        uint16_t tmp;
-        if (getUInt16(offset, &tmp)) {
-            *x = tmp;
-            return true;
-        }
-    }
-    return false;
-}
-
-bool DataSource::getUInt64Var(off64_t offset, uint64_t *x, size_t size) {
-    if (size == 8) {
-        return getUInt64(offset, x);
-    }
-    if (size == 4) {
-        uint32_t tmp;
-        if (getUInt32(offset, &tmp)) {
-            *x = tmp;
-            return true;
-        }
-    }
-    return false;
-}
-
-status_t DataSource::getSize(off64_t *size) {
-    *size = 0;
-
-    return ERROR_UNSUPPORTED;
-}
-
-sp<IDataSource> DataSource::getIDataSource() const {
-    return nullptr;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-
-// static
-sp<DataSource> DataSource::CreateFromURI(
-        const sp<IMediaHTTPService> &httpService,
-        const char *uri,
-        const KeyedVector<String8, String8> *headers,
-        String8 *contentType,
-        HTTPBase *httpSource) {
-    if (contentType != NULL) {
-        *contentType = "";
-    }
-
-    sp<DataSource> source;
-    if (!strncasecmp("file://", uri, 7)) {
-        source = new FileSource(uri + 7);
-    } else if (!strncasecmp("http://", uri, 7) || !strncasecmp("https://", uri, 8)) {
-        if (httpService == NULL) {
-            ALOGE("Invalid http service!");
-            return NULL;
-        }
-
-        if (httpSource == NULL) {
-            sp<IMediaHTTPConnection> conn = httpService->makeHTTPConnection();
-            if (conn == NULL) {
-                ALOGE("Failed to make http connection from http service!");
-                return NULL;
-            }
-            httpSource = new MediaHTTP(conn);
-        }
-
-        String8 cacheConfig;
-        bool disconnectAtHighwatermark = false;
-        KeyedVector<String8, String8> nonCacheSpecificHeaders;
-        if (headers != NULL) {
-            nonCacheSpecificHeaders = *headers;
-            NuCachedSource2::RemoveCacheSpecificHeaders(
-                    &nonCacheSpecificHeaders,
-                    &cacheConfig,
-                    &disconnectAtHighwatermark);
-        }
-
-        if (httpSource->connect(uri, &nonCacheSpecificHeaders) != OK) {
-            ALOGE("Failed to connect http source!");
-            return NULL;
-        }
-
-        if (contentType != NULL) {
-            *contentType = httpSource->getMIMEType();
-        }
-
-        source = NuCachedSource2::Create(
-                httpSource,
-                cacheConfig.isEmpty() ? NULL : cacheConfig.string(),
-                disconnectAtHighwatermark);
-    } else if (!strncasecmp("data:", uri, 5)) {
-        source = DataURISource::Create(uri);
-    } else {
-        // Assume it's a filename.
-        source = new FileSource(uri);
-    }
-
-    if (source == NULL || source->initCheck() != OK) {
-        return NULL;
-    }
-
-    return source;
-}
-
-sp<DataSource> DataSource::CreateFromFd(int fd, int64_t offset, int64_t length) {
-    sp<FileSource> source = new FileSource(fd, offset, length);
-    return source->initCheck() != OK ? nullptr : source;
-}
-
-sp<DataSource> DataSource::CreateMediaHTTP(const sp<IMediaHTTPService> &httpService) {
-    if (httpService == NULL) {
-        return NULL;
-    }
-
-    sp<IMediaHTTPConnection> conn = httpService->makeHTTPConnection();
-    if (conn == NULL) {
-        return NULL;
-    } else {
-        return new MediaHTTP(conn);
-    }
-}
-
-sp<DataSource> DataSource::CreateFromIDataSource(const sp<IDataSource> &source) {
-    return new TinyCacheSource(new CallbackDataSource(source));
-}
-
-String8 DataSource::getMIMEType() const {
-    return String8("application/octet-stream");
-}
-
-sp<IDataSource> DataSource::asIDataSource() {
-    return RemoteDataSource::wrap(sp<DataSource>(this));
-}
-
-}  // namespace android
diff --git a/media/libstagefright/DataSourceFactory.cpp b/media/libstagefright/DataSourceFactory.cpp
new file mode 100644
index 0000000..aee858c
--- /dev/null
+++ b/media/libstagefright/DataSourceFactory.cpp
@@ -0,0 +1,117 @@
+/*
+ * 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.
+ */
+//#define LOG_NDEBUG 0
+#define LOG_TAG "DataSource"
+
+#include "include/HTTPBase.h"
+#include "include/NuCachedSource2.h"
+
+#include <media/IMediaHTTPConnection.h>
+#include <media/IMediaHTTPService.h>
+#include <media/stagefright/DataSourceFactory.h>
+#include <media/stagefright/DataURISource.h>
+#include <media/stagefright/FileSource.h>
+#include <media/stagefright/MediaHTTP.h>
+#include <utils/String8.h>
+
+namespace android {
+
+// static
+sp<DataSource> DataSourceFactory::CreateFromURI(
+        const sp<IMediaHTTPService> &httpService,
+        const char *uri,
+        const KeyedVector<String8, String8> *headers,
+        String8 *contentType,
+        HTTPBase *httpSource) {
+    if (contentType != NULL) {
+        *contentType = "";
+    }
+
+    sp<DataSource> source;
+    if (!strncasecmp("file://", uri, 7)) {
+        source = new FileSource(uri + 7);
+    } else if (!strncasecmp("http://", uri, 7) || !strncasecmp("https://", uri, 8)) {
+        if (httpService == NULL) {
+            ALOGE("Invalid http service!");
+            return NULL;
+        }
+
+        if (httpSource == NULL) {
+            sp<IMediaHTTPConnection> conn = httpService->makeHTTPConnection();
+            if (conn == NULL) {
+                ALOGE("Failed to make http connection from http service!");
+                return NULL;
+            }
+            httpSource = new MediaHTTP(conn);
+        }
+
+        String8 cacheConfig;
+        bool disconnectAtHighwatermark = false;
+        KeyedVector<String8, String8> nonCacheSpecificHeaders;
+        if (headers != NULL) {
+            nonCacheSpecificHeaders = *headers;
+            NuCachedSource2::RemoveCacheSpecificHeaders(
+                    &nonCacheSpecificHeaders,
+                    &cacheConfig,
+                    &disconnectAtHighwatermark);
+        }
+
+        if (httpSource->connect(uri, &nonCacheSpecificHeaders) != OK) {
+            ALOGE("Failed to connect http source!");
+            return NULL;
+        }
+
+        if (contentType != NULL) {
+            *contentType = httpSource->getMIMEType();
+        }
+
+        source = NuCachedSource2::Create(
+                httpSource,
+                cacheConfig.isEmpty() ? NULL : cacheConfig.string(),
+                disconnectAtHighwatermark);
+    } else if (!strncasecmp("data:", uri, 5)) {
+        source = DataURISource::Create(uri);
+    } else {
+        // Assume it's a filename.
+        source = new FileSource(uri);
+    }
+
+    if (source == NULL || source->initCheck() != OK) {
+        return NULL;
+    }
+
+    return source;
+}
+
+sp<DataSource> DataSourceFactory::CreateFromFd(int fd, int64_t offset, int64_t length) {
+    sp<FileSource> source = new FileSource(fd, offset, length);
+    return source->initCheck() != OK ? nullptr : source;
+}
+
+sp<DataSource> DataSourceFactory::CreateMediaHTTP(const sp<IMediaHTTPService> &httpService) {
+    if (httpService == NULL) {
+        return NULL;
+    }
+
+    sp<IMediaHTTPConnection> conn = httpService->makeHTTPConnection();
+    if (conn == NULL) {
+        return NULL;
+    } else {
+        return new MediaHTTP(conn);
+    }
+}
+
+}  // namespace android
diff --git a/media/libstagefright/FrameDecoder.cpp b/media/libstagefright/FrameDecoder.cpp
new file mode 100644
index 0000000..fa5f37ec
--- /dev/null
+++ b/media/libstagefright/FrameDecoder.cpp
@@ -0,0 +1,608 @@
+/*
+ * 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "FrameDecoder"
+
+#include <inttypes.h>
+
+#include <utils/Log.h>
+#include <gui/Surface.h>
+
+#include "include/FrameDecoder.h"
+#include <media/ICrypto.h>
+#include <media/IMediaSource.h>
+#include <media/MediaCodecBuffer.h>
+#include <media/stagefright/foundation/avc_utils.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/ColorConverter.h>
+#include <media/stagefright/MediaBuffer.h>
+#include <media/stagefright/MediaCodec.h>
+#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/Utils.h>
+#include <private/media/VideoFrame.h>
+
+namespace android {
+
+static const int64_t kBufferTimeOutUs = 30000ll; // 30 msec
+static const size_t kRetryCount = 20; // must be >0
+
+VideoFrame *FrameDecoder::allocVideoFrame(
+        int32_t width, int32_t height, bool metaOnly) {
+    int32_t rotationAngle;
+    if (!mTrackMeta->findInt32(kKeyRotation, &rotationAngle)) {
+        rotationAngle = 0;  // By default, no rotation
+    }
+
+    uint32_t type;
+    const void *iccData;
+    size_t iccSize;
+    if (!mTrackMeta->findData(kKeyIccProfile, &type, &iccData, &iccSize)){
+        iccData = NULL;
+        iccSize = 0;
+    }
+
+    int32_t sarWidth, sarHeight;
+    int32_t displayWidth, displayHeight;
+    if (mTrackMeta->findInt32(kKeySARWidth, &sarWidth)
+            && mTrackMeta->findInt32(kKeySARHeight, &sarHeight)
+            && sarHeight != 0) {
+        displayWidth = (width * sarWidth) / sarHeight;
+        displayHeight = height;
+    } else if (mTrackMeta->findInt32(kKeyDisplayWidth, &displayWidth)
+                && mTrackMeta->findInt32(kKeyDisplayHeight, &displayHeight)
+                && displayWidth > 0 && displayHeight > 0
+                && width > 0 && height > 0) {
+        ALOGV("found display size %dx%d", displayWidth, displayHeight);
+    } else {
+        displayWidth = width;
+        displayHeight = height;
+    }
+
+    return new VideoFrame(width, height, displayWidth, displayHeight,
+            rotationAngle, mDstBpp, !metaOnly, iccData, iccSize);
+}
+
+bool FrameDecoder::setDstColorFormat(android_pixel_format_t colorFormat) {
+    switch (colorFormat) {
+        case HAL_PIXEL_FORMAT_RGB_565:
+        {
+            mDstFormat = OMX_COLOR_Format16bitRGB565;
+            mDstBpp = 2;
+            return true;
+        }
+        case HAL_PIXEL_FORMAT_RGBA_8888:
+        {
+            mDstFormat = OMX_COLOR_Format32BitRGBA8888;
+            mDstBpp = 4;
+            return true;
+        }
+        case HAL_PIXEL_FORMAT_BGRA_8888:
+        {
+            mDstFormat = OMX_COLOR_Format32bitBGRA8888;
+            mDstBpp = 4;
+            return true;
+        }
+        default:
+        {
+            ALOGE("Unsupported color format: %d", colorFormat);
+            break;
+        }
+    }
+    return false;
+}
+
+VideoFrame* FrameDecoder::extractFrame(
+        int64_t frameTimeUs, int option, int colorFormat, bool metaOnly) {
+    if (!setDstColorFormat((android_pixel_format_t)colorFormat)) {
+        return NULL;
+    }
+
+    if (metaOnly) {
+        int32_t width, height;
+        CHECK(trackMeta()->findInt32(kKeyWidth, &width));
+        CHECK(trackMeta()->findInt32(kKeyHeight, &height));
+        return allocVideoFrame(width, height, true);
+    }
+
+    status_t err = extractInternal(frameTimeUs, 1, option);
+    if (err != OK) {
+        return NULL;
+    }
+
+    return mFrames.size() > 0 ? mFrames[0].release() : NULL;
+}
+
+status_t FrameDecoder::extractFrames(
+        int64_t frameTimeUs, size_t numFrames, int option, int colorFormat,
+        std::vector<VideoFrame*>* frames) {
+    if (!setDstColorFormat((android_pixel_format_t)colorFormat)) {
+        return ERROR_UNSUPPORTED;
+    }
+
+    status_t err = extractInternal(frameTimeUs, numFrames, option);
+    if (err != OK) {
+        return err;
+    }
+
+    for (size_t i = 0; i < mFrames.size(); i++) {
+        frames->push_back(mFrames[i].release());
+    }
+    return OK;
+}
+
+status_t FrameDecoder::extractInternal(
+        int64_t frameTimeUs, size_t numFrames, int option) {
+
+    MediaSource::ReadOptions options;
+    sp<AMessage> videoFormat = onGetFormatAndSeekOptions(
+            frameTimeUs, numFrames, option, &options);
+    if (videoFormat == NULL) {
+        ALOGE("video format or seek mode not supported");
+        return ERROR_UNSUPPORTED;
+    }
+
+    status_t err;
+    sp<ALooper> looper = new ALooper;
+    looper->start();
+    sp<MediaCodec> decoder = MediaCodec::CreateByComponentName(
+            looper, mComponentName, &err);
+    if (decoder.get() == NULL || err != OK) {
+        ALOGW("Failed to instantiate decoder [%s]", mComponentName.c_str());
+        return (decoder.get() == NULL) ? NO_MEMORY : err;
+    }
+
+    err = decoder->configure(videoFormat, NULL /* surface */, NULL /* crypto */, 0 /* flags */);
+    if (err != OK) {
+        ALOGW("configure returned error %d (%s)", err, asString(err));
+        decoder->release();
+        return err;
+    }
+
+    err = decoder->start();
+    if (err != OK) {
+        ALOGW("start returned error %d (%s)", err, asString(err));
+        decoder->release();
+        return err;
+    }
+
+    err = mSource->start();
+    if (err != OK) {
+        ALOGW("source failed to start: %d (%s)", err, asString(err));
+        decoder->release();
+        return err;
+    }
+
+    Vector<sp<MediaCodecBuffer> > inputBuffers;
+    err = decoder->getInputBuffers(&inputBuffers);
+    if (err != OK) {
+        ALOGW("failed to get input buffers: %d (%s)", err, asString(err));
+        decoder->release();
+        mSource->stop();
+        return err;
+    }
+
+    Vector<sp<MediaCodecBuffer> > outputBuffers;
+    err = decoder->getOutputBuffers(&outputBuffers);
+    if (err != OK) {
+        ALOGW("failed to get output buffers: %d (%s)", err, asString(err));
+        decoder->release();
+        mSource->stop();
+        return err;
+    }
+
+    sp<AMessage> outputFormat = NULL;
+    bool haveMoreInputs = true;
+    size_t index, offset, size;
+    int64_t timeUs;
+    size_t retriesLeft = kRetryCount;
+    bool done = false;
+    bool firstSample = true;
+    do {
+        size_t inputIndex = -1;
+        int64_t ptsUs = 0ll;
+        uint32_t flags = 0;
+        sp<MediaCodecBuffer> codecBuffer = NULL;
+
+        while (haveMoreInputs) {
+            err = decoder->dequeueInputBuffer(&inputIndex, kBufferTimeOutUs);
+            if (err != OK) {
+                ALOGW("Timed out waiting for input");
+                if (retriesLeft) {
+                    err = OK;
+                }
+                break;
+            }
+            codecBuffer = inputBuffers[inputIndex];
+
+            MediaBuffer *mediaBuffer = NULL;
+
+            err = mSource->read(&mediaBuffer, &options);
+            options.clearSeekTo();
+            if (err != OK) {
+                ALOGW("Input Error or EOS");
+                haveMoreInputs = false;
+                if (!firstSample && err == ERROR_END_OF_STREAM) {
+                    err = OK;
+                }
+                break;
+            }
+
+            if (mediaBuffer->range_length() > codecBuffer->capacity()) {
+                ALOGE("buffer size (%zu) too large for codec input size (%zu)",
+                        mediaBuffer->range_length(), codecBuffer->capacity());
+                haveMoreInputs = false;
+                err = BAD_VALUE;
+            } else {
+                codecBuffer->setRange(0, mediaBuffer->range_length());
+
+                CHECK(mediaBuffer->meta_data()->findInt64(kKeyTime, &ptsUs));
+                memcpy(codecBuffer->data(),
+                        (const uint8_t*)mediaBuffer->data() + mediaBuffer->range_offset(),
+                        mediaBuffer->range_length());
+
+                onInputReceived(codecBuffer, mediaBuffer->meta_data(), firstSample, &flags);
+                firstSample = false;
+            }
+
+            mediaBuffer->release();
+            break;
+        }
+
+        if (haveMoreInputs && inputIndex < inputBuffers.size()) {
+            ALOGV("QueueInput: size=%zu ts=%" PRId64 " us flags=%x",
+                    codecBuffer->size(), ptsUs, flags);
+
+            err = decoder->queueInputBuffer(
+                    inputIndex,
+                    codecBuffer->offset(),
+                    codecBuffer->size(),
+                    ptsUs,
+                    flags);
+
+            if (flags & MediaCodec::BUFFER_FLAG_EOS) {
+                haveMoreInputs = false;
+            }
+
+            // we don't expect an output from codec config buffer
+            if (flags & MediaCodec::BUFFER_FLAG_CODECCONFIG) {
+                continue;
+            }
+        }
+
+        while (err == OK) {
+            // wait for a decoded buffer
+            err = decoder->dequeueOutputBuffer(
+                    &index,
+                    &offset,
+                    &size,
+                    &timeUs,
+                    &flags,
+                    kBufferTimeOutUs);
+
+            if (err == INFO_FORMAT_CHANGED) {
+                ALOGV("Received format change");
+                err = decoder->getOutputFormat(&outputFormat);
+            } else if (err == INFO_OUTPUT_BUFFERS_CHANGED) {
+                ALOGV("Output buffers changed");
+                err = decoder->getOutputBuffers(&outputBuffers);
+            } else {
+                if (err == -EAGAIN /* INFO_TRY_AGAIN_LATER */ && --retriesLeft > 0) {
+                    ALOGV("Timed-out waiting for output.. retries left = %zu", retriesLeft);
+                    err = OK;
+                } else if (err == OK) {
+                    // If we're seeking with CLOSEST option and obtained a valid targetTimeUs
+                    // from the extractor, decode to the specified frame. Otherwise we're done.
+                    ALOGV("Received an output buffer, timeUs=%lld", (long long)timeUs);
+                    sp<MediaCodecBuffer> videoFrameBuffer = outputBuffers.itemAt(index);
+
+                    err = onOutputReceived(videoFrameBuffer, outputFormat, timeUs, &done);
+
+                    decoder->releaseOutputBuffer(index);
+                } else {
+                    ALOGW("Received error %d (%s) instead of output", err, asString(err));
+                    done = true;
+                }
+                break;
+            }
+        }
+    } while (err == OK && !done);
+
+    mSource->stop();
+    decoder->release();
+
+    if (err != OK) {
+        ALOGE("failed to get video frame (err %d)", err);
+    }
+
+    return err;
+}
+
+sp<AMessage> VideoFrameDecoder::onGetFormatAndSeekOptions(
+        int64_t frameTimeUs, size_t numFrames, int seekMode, MediaSource::ReadOptions *options) {
+    mSeekMode = static_cast<MediaSource::ReadOptions::SeekMode>(seekMode);
+    if (mSeekMode < MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC ||
+            mSeekMode > MediaSource::ReadOptions::SEEK_FRAME_INDEX) {
+        ALOGE("Unknown seek mode: %d", mSeekMode);
+        return NULL;
+    }
+    mNumFrames = numFrames;
+
+    const char *mime;
+    if (!trackMeta()->findCString(kKeyMIMEType, &mime)) {
+        ALOGE("Could not find mime type");
+        return NULL;
+    }
+
+    mIsAvcOrHevc = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)
+            || !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_HEVC);
+
+    if (frameTimeUs < 0) {
+        int64_t thumbNailTime;
+        if (!trackMeta()->findInt64(kKeyThumbnailTime, &thumbNailTime)
+                || thumbNailTime < 0) {
+            thumbNailTime = 0;
+        }
+        options->setSeekTo(thumbNailTime, mSeekMode);
+    } else {
+        options->setSeekTo(frameTimeUs, mSeekMode);
+    }
+
+    sp<AMessage> videoFormat;
+    if (convertMetaDataToMessage(trackMeta(), &videoFormat) != OK) {
+        ALOGE("b/23680780");
+        ALOGW("Failed to convert meta data to message");
+        return NULL;
+    }
+
+    // TODO: Use Flexible color instead
+    videoFormat->setInt32("color-format", OMX_COLOR_FormatYUV420Planar);
+
+    // For the thumbnail extraction case, try to allocate single buffer in both
+    // input and output ports, if seeking to a sync frame. NOTE: This request may
+    // fail if component requires more than that for decoding.
+    bool isSeekingClosest = (mSeekMode == MediaSource::ReadOptions::SEEK_CLOSEST)
+            || (mSeekMode == MediaSource::ReadOptions::SEEK_FRAME_INDEX);
+    if (!isSeekingClosest) {
+        videoFormat->setInt32("android._num-input-buffers", 1);
+        videoFormat->setInt32("android._num-output-buffers", 1);
+    }
+    return videoFormat;
+}
+
+status_t VideoFrameDecoder::onInputReceived(
+        const sp<MediaCodecBuffer> &codecBuffer,
+        const sp<MetaData> &sampleMeta, bool firstSample, uint32_t *flags) {
+    bool isSeekingClosest = (mSeekMode == MediaSource::ReadOptions::SEEK_CLOSEST)
+            || (mSeekMode == MediaSource::ReadOptions::SEEK_FRAME_INDEX);
+
+    if (firstSample && isSeekingClosest) {
+        sampleMeta->findInt64(kKeyTargetTime, &mTargetTimeUs);
+        ALOGV("Seeking closest: targetTimeUs=%lld", (long long)mTargetTimeUs);
+    }
+
+    if (mIsAvcOrHevc && !isSeekingClosest
+            && IsIDR(codecBuffer->data(), codecBuffer->size())) {
+        // Only need to decode one IDR frame, unless we're seeking with CLOSEST
+        // option, in which case we need to actually decode to targetTimeUs.
+        *flags |= MediaCodec::BUFFER_FLAG_EOS;
+    }
+    return OK;
+}
+
+status_t VideoFrameDecoder::onOutputReceived(
+        const sp<MediaCodecBuffer> &videoFrameBuffer,
+        const sp<AMessage> &outputFormat,
+        int64_t timeUs, bool *done) {
+    bool shouldOutput = (mTargetTimeUs < 0ll) || (timeUs >= mTargetTimeUs);
+
+    // If this is not the target frame, skip color convert.
+    if (!shouldOutput) {
+        *done = false;
+        return OK;
+    }
+
+    *done = (++mNumFramesDecoded >= mNumFrames);
+
+    int32_t width, height;
+    CHECK(outputFormat != NULL);
+    CHECK(outputFormat->findInt32("width", &width));
+    CHECK(outputFormat->findInt32("height", &height));
+
+    int32_t crop_left, crop_top, crop_right, crop_bottom;
+    if (!outputFormat->findRect("crop", &crop_left, &crop_top, &crop_right, &crop_bottom)) {
+        crop_left = crop_top = 0;
+        crop_right = width - 1;
+        crop_bottom = height - 1;
+    }
+
+    VideoFrame *frame = allocVideoFrame(
+            (crop_right - crop_left + 1),
+            (crop_bottom - crop_top + 1),
+            false /*metaOnly*/);
+    addFrame(frame);
+
+    int32_t srcFormat;
+    CHECK(outputFormat->findInt32("color-format", &srcFormat));
+
+    ColorConverter converter((OMX_COLOR_FORMATTYPE)srcFormat, dstFormat());
+
+    if (converter.isValid()) {
+        converter.convert(
+                (const uint8_t *)videoFrameBuffer->data(),
+                width, height,
+                crop_left, crop_top, crop_right, crop_bottom,
+                frame->mData,
+                frame->mWidth,
+                frame->mHeight,
+                crop_left, crop_top, crop_right, crop_bottom);
+        return OK;
+    }
+
+    ALOGE("Unable to convert from format 0x%08x to 0x%08x",
+                srcFormat, dstFormat());
+    return ERROR_UNSUPPORTED;
+}
+
+sp<AMessage> ImageDecoder::onGetFormatAndSeekOptions(
+        int64_t frameTimeUs, size_t /*numFrames*/,
+        int /*seekMode*/, MediaSource::ReadOptions *options) {
+    sp<MetaData> overrideMeta;
+    if (frameTimeUs < 0) {
+        uint32_t type;
+        const void *data;
+        size_t size;
+        int64_t thumbNailTime = 0;
+        int32_t thumbnailWidth, thumbnailHeight;
+
+        // if we have a stand-alone thumbnail, set up the override meta,
+        // and set seekTo time to -1.
+        if (trackMeta()->findInt32(kKeyThumbnailWidth, &thumbnailWidth)
+         && trackMeta()->findInt32(kKeyThumbnailHeight, &thumbnailHeight)
+         && trackMeta()->findData(kKeyThumbnailHVCC, &type, &data, &size)){
+            overrideMeta = new MetaData(*(trackMeta()));
+            overrideMeta->remove(kKeyDisplayWidth);
+            overrideMeta->remove(kKeyDisplayHeight);
+            overrideMeta->setInt32(kKeyWidth, thumbnailWidth);
+            overrideMeta->setInt32(kKeyHeight, thumbnailHeight);
+            overrideMeta->setData(kKeyHVCC, type, data, size);
+            thumbNailTime = -1ll;
+            ALOGV("thumbnail: %dx%d", thumbnailWidth, thumbnailHeight);
+        }
+        options->setSeekTo(thumbNailTime);
+    } else {
+        options->setSeekTo(frameTimeUs);
+    }
+
+    mGridRows = mGridCols = 1;
+    if (overrideMeta == NULL) {
+        // check if we're dealing with a tiled heif
+        int32_t gridWidth, gridHeight, gridRows, gridCols;
+        if (trackMeta()->findInt32(kKeyGridWidth, &gridWidth) && gridWidth > 0
+         && trackMeta()->findInt32(kKeyGridHeight, &gridHeight) && gridHeight > 0
+         && trackMeta()->findInt32(kKeyGridRows, &gridRows) && gridRows > 0
+         && trackMeta()->findInt32(kKeyGridCols, &gridCols) && gridCols > 0) {
+            int32_t width, height;
+            CHECK(trackMeta()->findInt32(kKeyWidth, &width));
+            CHECK(trackMeta()->findInt32(kKeyHeight, &height));
+
+            if (width <= gridWidth * gridCols && height <= gridHeight * gridRows) {
+                ALOGV("grid: %dx%d, size: %dx%d, picture size: %dx%d",
+                        gridCols, gridRows, gridWidth, gridHeight, width, height);
+
+                overrideMeta = new MetaData(*(trackMeta()));
+                overrideMeta->setInt32(kKeyWidth, gridWidth);
+                overrideMeta->setInt32(kKeyHeight, gridHeight);
+                mGridCols = gridCols;
+                mGridRows = gridRows;
+            } else {
+                ALOGE("bad grid: %dx%d, size: %dx%d, picture size: %dx%d",
+                        gridCols, gridRows, gridWidth, gridHeight, width, height);
+            }
+        }
+        if (overrideMeta == NULL) {
+            overrideMeta = trackMeta();
+        }
+    }
+
+    sp<AMessage> videoFormat;
+    if (convertMetaDataToMessage(overrideMeta, &videoFormat) != OK) {
+        ALOGE("b/23680780");
+        ALOGW("Failed to convert meta data to message");
+        return NULL;
+    }
+
+    // TODO: Use Flexible color instead
+    videoFormat->setInt32("color-format", OMX_COLOR_FormatYUV420Planar);
+
+    if ((mGridRows == 1) && (mGridCols == 1)) {
+        videoFormat->setInt32("android._num-input-buffers", 1);
+        videoFormat->setInt32("android._num-output-buffers", 1);
+    }
+    return videoFormat;
+}
+
+status_t ImageDecoder::onOutputReceived(
+        const sp<MediaCodecBuffer> &videoFrameBuffer,
+        const sp<AMessage> &outputFormat, int64_t /*timeUs*/, bool *done) {
+    int32_t width, height;
+    CHECK(outputFormat != NULL);
+    CHECK(outputFormat->findInt32("width", &width));
+    CHECK(outputFormat->findInt32("height", &height));
+
+    int32_t imageWidth, imageHeight;
+    CHECK(trackMeta()->findInt32(kKeyWidth, &imageWidth));
+    CHECK(trackMeta()->findInt32(kKeyHeight, &imageHeight));
+
+    if (mFrame == NULL) {
+        mFrame = allocVideoFrame(imageWidth, imageHeight, false /*metaOnly*/);
+
+        addFrame(mFrame);
+    }
+
+    int32_t srcFormat;
+    CHECK(outputFormat->findInt32("color-format", &srcFormat));
+
+    ColorConverter converter((OMX_COLOR_FORMATTYPE)srcFormat, dstFormat());
+
+    int32_t dstLeft, dstTop, dstRight, dstBottom;
+    int32_t numTiles = mGridRows * mGridCols;
+
+    dstLeft = mTilesDecoded % mGridCols * width;
+    dstTop = mTilesDecoded / mGridCols * height;
+    dstRight = dstLeft + width - 1;
+    dstBottom = dstTop + height - 1;
+
+    int32_t crop_left, crop_top, crop_right, crop_bottom;
+    if (!outputFormat->findRect("crop", &crop_left, &crop_top, &crop_right, &crop_bottom)) {
+        crop_left = crop_top = 0;
+        crop_right = width - 1;
+        crop_bottom = height - 1;
+    }
+
+    // apply crop on bottom-right
+    // TODO: need to move this into the color converter itself.
+    if (dstRight >= imageWidth) {
+        crop_right = imageWidth - dstLeft - 1;
+        dstRight = dstLeft + crop_right;
+    }
+    if (dstBottom >= imageHeight) {
+        crop_bottom = imageHeight - dstTop - 1;
+        dstBottom = dstTop + crop_bottom;
+    }
+
+    *done = (++mTilesDecoded >= numTiles);
+
+    if (converter.isValid()) {
+        converter.convert(
+                (const uint8_t *)videoFrameBuffer->data(),
+                width, height,
+                crop_left, crop_top, crop_right, crop_bottom,
+                mFrame->mData,
+                mFrame->mWidth,
+                mFrame->mHeight,
+                dstLeft, dstTop, dstRight, dstBottom);
+        return OK;
+    }
+
+    ALOGE("Unable to convert from format 0x%08x to 0x%08x",
+                srcFormat, dstFormat());
+    return ERROR_UNSUPPORTED;
+}
+
+}  // namespace android
diff --git a/media/libstagefright/HevcUtils.cpp b/media/libstagefright/HevcUtils.cpp
index 7d463a9..91deca5 100644
--- a/media/libstagefright/HevcUtils.cpp
+++ b/media/libstagefright/HevcUtils.cpp
@@ -21,12 +21,12 @@
 #include <utility>
 
 #include "include/HevcUtils.h"
-#include "include/avc_utils.h"
 
 #include <media/stagefright/foundation/ABitReader.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/foundation/avc_utils.h>
 #include <media/stagefright/MediaErrors.h>
 #include <media/stagefright/Utils.h>
 
diff --git a/media/libstagefright/InterfaceUtils.cpp b/media/libstagefright/InterfaceUtils.cpp
new file mode 100644
index 0000000..cf9fdf8
--- /dev/null
+++ b/media/libstagefright/InterfaceUtils.cpp
@@ -0,0 +1,62 @@
+/*
+ * 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.
+ */
+
+#include "include/CallbackDataSource.h"
+
+#include <media/stagefright/CallbackMediaSource.h>
+#include <media/stagefright/InterfaceUtils.h>
+#include <media/stagefright/RemoteDataSource.h>
+#include <media/stagefright/RemoteMediaExtractor.h>
+#include <media/stagefright/RemoteMediaSource.h>
+
+namespace android {
+
+sp<DataSource> CreateDataSourceFromIDataSource(const sp<IDataSource> &source) {
+    if (source == nullptr) {
+        return nullptr;
+    }
+    return new TinyCacheSource(new CallbackDataSource(source));
+}
+
+sp<IDataSource> CreateIDataSourceFromDataSource(const sp<DataSource> &source) {
+    if (source == nullptr) {
+        return nullptr;
+    }
+    return RemoteDataSource::wrap(source);
+}
+
+sp<IMediaExtractor> CreateIMediaExtractorFromMediaExtractor(const sp<MediaExtractor> &extractor) {
+    if (extractor == nullptr) {
+        return nullptr;
+    }
+    return RemoteMediaExtractor::wrap(extractor);
+}
+
+sp<MediaSource> CreateMediaSourceFromIMediaSource(const sp<IMediaSource> &source) {
+    if (source == nullptr) {
+        return nullptr;
+    }
+    return new CallbackMediaSource(source);
+}
+
+sp<IMediaSource> CreateIMediaSourceFromMediaSource(const sp<MediaSource> &source) {
+    if (source == nullptr) {
+        return nullptr;
+    }
+    return RemoteMediaSource::wrap(source);
+}
+
+}  // namespace android
diff --git a/media/libstagefright/JPEGSource.cpp b/media/libstagefright/JPEGSource.cpp
index bafa4b2..ee3aedb 100644
--- a/media/libstagefright/JPEGSource.cpp
+++ b/media/libstagefright/JPEGSource.cpp
@@ -18,8 +18,8 @@
 #define LOG_TAG "JPEGSource"
 #include <utils/Log.h>
 
+#include <media/DataSource.h>
 #include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/DataSource.h>
 #include <media/stagefright/JPEGSource.h>
 #include <media/stagefright/MediaBufferGroup.h>
 #include <media/stagefright/MediaDefs.h>
diff --git a/media/libstagefright/MPEG2TSWriter.cpp b/media/libstagefright/MPEG2TSWriter.cpp
index 494f135..4c85b0d 100644
--- a/media/libstagefright/MPEG2TSWriter.cpp
+++ b/media/libstagefright/MPEG2TSWriter.cpp
@@ -16,8 +16,9 @@
 
 //#define LOG_NDEBUG 0
 #define LOG_TAG "MPEG2TSWriter"
-#include <media/stagefright/foundation/ADebug.h>
 
+#include <media/MediaSource.h>
+#include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/hexdump.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/AMessage.h>
@@ -26,7 +27,6 @@
 #include <media/stagefright/MediaBuffer.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/MediaSource.h>
 #include <media/stagefright/MetaData.h>
 #include <arpa/inet.h>
 
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index a60392a..a132873 100644
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -32,24 +32,24 @@
 
 #include <functional>
 
+#include <media/MediaSource.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
 #include <media/stagefright/foundation/AUtils.h>
 #include <media/stagefright/foundation/ByteUtils.h>
 #include <media/stagefright/foundation/ColorUtils.h>
+#include <media/stagefright/foundation/avc_utils.h>
 #include <media/stagefright/MPEG4Writer.h>
 #include <media/stagefright/MediaBuffer.h>
 #include <media/stagefright/MetaData.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/MediaSource.h>
 #include <media/stagefright/Utils.h>
 #include <media/mediarecorder.h>
 #include <cutils/properties.h>
 
 #include "include/ESDS.h"
 #include "include/HevcUtils.h"
-#include "include/avc_utils.h"
 
 #ifndef __predict_false
 #define __predict_false(exp) __builtin_expect((exp) != 0, 0)
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index 759e42d..4fedab6 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -18,7 +18,6 @@
 #define LOG_TAG "MediaCodec"
 #include <inttypes.h>
 
-#include "include/avc_utils.h"
 #include "include/SecureBuffer.h"
 #include "include/SharedMemoryBuffer.h"
 #include "include/SoftwareRenderer.h"
@@ -41,6 +40,7 @@
 #include <media/stagefright/foundation/AMessage.h>
 #include <media/stagefright/foundation/AString.h>
 #include <media/stagefright/foundation/AUtils.h>
+#include <media/stagefright/foundation/avc_utils.h>
 #include <media/stagefright/foundation/hexdump.h>
 #include <media/stagefright/ACodec.h>
 #include <media/stagefright/BufferProducerWrapper.h>
diff --git a/media/libstagefright/MediaCodecList.cpp b/media/libstagefright/MediaCodecList.cpp
index 4feba37..54265a4 100644
--- a/media/libstagefright/MediaCodecList.cpp
+++ b/media/libstagefright/MediaCodecList.cpp
@@ -24,7 +24,6 @@
 
 #include <media/IMediaCodecList.h>
 #include <media/IMediaPlayerService.h>
-#include <media/IMediaCodecService.h>
 #include <media/MediaCodecInfo.h>
 
 #include <media/stagefright/foundation/ADebug.h>
diff --git a/media/libstagefright/MediaCodecSource.cpp b/media/libstagefright/MediaCodecSource.cpp
index d808e5b..5852dd4 100644
--- a/media/libstagefright/MediaCodecSource.cpp
+++ b/media/libstagefright/MediaCodecSource.cpp
@@ -24,6 +24,7 @@
 #include <gui/Surface.h>
 #include <media/ICrypto.h>
 #include <media/MediaCodecBuffer.h>
+#include <media/MediaSource.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/ALooper.h>
@@ -33,7 +34,6 @@
 #include <media/stagefright/MediaCodecList.h>
 #include <media/stagefright/MediaCodecSource.h>
 #include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/MediaSource.h>
 #include <media/stagefright/MetaData.h>
 #include <media/stagefright/Utils.h>
 
diff --git a/media/libstagefright/MediaExtractor.cpp b/media/libstagefright/MediaExtractorFactory.cpp
similarity index 69%
rename from media/libstagefright/MediaExtractor.cpp
rename to media/libstagefright/MediaExtractorFactory.cpp
index cc2fa63..1b12510 100644
--- a/media/libstagefright/MediaExtractor.cpp
+++ b/media/libstagefright/MediaExtractorFactory.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2009 The Android Open Source Project
+ * 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.
@@ -17,113 +17,40 @@
 //#define LOG_NDEBUG 0
 #define LOG_TAG "MediaExtractor"
 #include <utils/Log.h>
-#include <inttypes.h>
-#include <pwd.h>
 
 #include <binder/IServiceManager.h>
-#include <binder/MemoryDealer.h>
-
+#include <media/DataSource.h>
 #include <media/MediaAnalyticsItem.h>
-#include <media/stagefright/foundation/ADebug.h>
+#include <media/MediaExtractor.h>
 #include <media/stagefright/foundation/AMessage.h>
-#include <media/stagefright/DataSource.h>
-#include <media/stagefright/MediaDefs.h>
-#include <media/stagefright/MediaExtractor.h>
+#include <media/stagefright/InterfaceUtils.h>
+#include <media/stagefright/MediaExtractorFactory.h>
 #include <media/stagefright/MetaData.h>
-#include <media/stagefright/RemoteMediaExtractor.h>
 #include <media/IMediaExtractor.h>
 #include <media/IMediaExtractorService.h>
-#include <media/IMediaSource.h>
 #include <cutils/properties.h>
 #include <utils/String8.h>
-#include <private/android_filesystem_config.h>
 
-// still doing some on/off toggling here.
-#define MEDIA_LOG       1
-
-#include <sys/types.h>
 #include <dirent.h>
 #include <dlfcn.h>
 
 namespace android {
 
-// key for media statistics
-static const char *kKeyExtractor = "extractor";
 // attrs for media statistics
 static const char *kExtractorMime = "android.media.mediaextractor.mime";
 static const char *kExtractorTracks = "android.media.mediaextractor.ntrk";
 static const char *kExtractorFormat = "android.media.mediaextractor.fmt";
 
-MediaExtractor::MediaExtractor() {
-    if (!LOG_NDEBUG) {
-        uid_t uid = getuid();
-        struct passwd *pw = getpwuid(uid);
-        ALOGV("extractor created in uid: %d (%s)", getuid(), pw->pw_name);
-    }
-
-    mAnalyticsItem = NULL;
-    if (MEDIA_LOG) {
-        mAnalyticsItem = new MediaAnalyticsItem(kKeyExtractor);
-        (void) mAnalyticsItem->generateSessionID();
-    }
-}
-
-MediaExtractor::~MediaExtractor() {
-
-    // log the current record, provided it has some information worth recording
-    if (MEDIA_LOG) {
-        if (mAnalyticsItem != NULL) {
-            if (mAnalyticsItem->count() > 0) {
-                mAnalyticsItem->setFinalized(true);
-                mAnalyticsItem->selfrecord();
-            }
-        }
-    }
-    if (mAnalyticsItem != NULL) {
-        delete mAnalyticsItem;
-        mAnalyticsItem = NULL;
-    }
-}
-
-sp<IMediaExtractor> MediaExtractor::asIMediaExtractor() {
-    return RemoteMediaExtractor::wrap(sp<MediaExtractor>(this));
-}
-
-sp<MetaData> MediaExtractor::getMetaData() {
-    return new MetaData;
-}
-
-status_t MediaExtractor::getMetrics(Parcel *reply) {
-
-    if (mAnalyticsItem == NULL || reply == NULL) {
-        return UNKNOWN_ERROR;
-    }
-
-    populateMetrics();
-    mAnalyticsItem->writeToParcel(reply);
-
-    return OK;
-}
-
-void MediaExtractor::populateMetrics() {
-    ALOGV("MediaExtractor::populateMetrics");
-    // normally overridden in subclasses
-}
-
-uint32_t MediaExtractor::flags() const {
-    return CAN_SEEK_BACKWARD | CAN_SEEK_FORWARD | CAN_PAUSE | CAN_SEEK;
-}
-
 // static
-sp<IMediaExtractor> MediaExtractor::Create(
+sp<IMediaExtractor> MediaExtractorFactory::Create(
         const sp<DataSource> &source, const char *mime) {
-    ALOGV("MediaExtractor::Create %s", mime);
+    ALOGV("MediaExtractorFactory::Create %s", mime);
 
     if (!property_get_bool("media.stagefright.extractremote", true)) {
         // local extractor
         ALOGW("creating media extractor in calling process");
         sp<MediaExtractor> extractor = CreateFromService(source, mime);
-        return (extractor.get() == nullptr) ? nullptr : extractor->asIMediaExtractor();
+        return CreateIMediaExtractorFromMediaExtractor(extractor);
     } else {
         // remote extractor
         ALOGV("get service manager");
@@ -131,7 +58,8 @@
 
         if (binder != 0) {
             sp<IMediaExtractorService> mediaExService(interface_cast<IMediaExtractorService>(binder));
-            sp<IMediaExtractor> ex = mediaExService->makeExtractor(source->asIDataSource(), mime);
+            sp<IMediaExtractor> ex = mediaExService->makeExtractor(
+                    CreateIDataSourceFromDataSource(source), mime);
             return ex;
         } else {
             ALOGE("extractor service not running");
@@ -141,10 +69,10 @@
     return NULL;
 }
 
-sp<MediaExtractor> MediaExtractor::CreateFromService(
+sp<MediaExtractor> MediaExtractorFactory::CreateFromService(
         const sp<DataSource> &source, const char *mime) {
 
-    ALOGV("MediaExtractor::CreateFromService %s", mime);
+    ALOGV("MediaExtractorFactory::CreateFromService %s", mime);
     RegisterDefaultSniffers();
 
     // initialize source decryption if needed
@@ -152,7 +80,7 @@
 
     sp<AMessage> meta;
 
-    CreatorFunc creator = NULL;
+    MediaExtractor::CreatorFunc creator = NULL;
     String8 tmp;
     float confidence;
     creator = sniff(source, &tmp, &confidence, &meta);
@@ -194,12 +122,12 @@
     return ret;
 }
 
-Mutex MediaExtractor::gSnifferMutex;
-List<MediaExtractor::ExtractorDef> MediaExtractor::gSniffers;
-bool MediaExtractor::gSniffersRegistered = false;
+Mutex MediaExtractorFactory::gSnifferMutex;
+List<MediaExtractor::ExtractorDef> MediaExtractorFactory::gSniffers;
+bool MediaExtractorFactory::gSniffersRegistered = false;
 
 // static
-MediaExtractor::CreatorFunc MediaExtractor::sniff(
+MediaExtractor::CreatorFunc MediaExtractorFactory::sniff(
         const sp<DataSource> &source, String8 *mimeType, float *confidence, sp<AMessage> *meta) {
     *mimeType = "";
     *confidence = 0.0f;
@@ -212,9 +140,9 @@
         }
     }
 
-    CreatorFunc curCreator = NULL;
-    CreatorFunc bestCreator = NULL;
-    for (List<ExtractorDef>::iterator it = gSniffers.begin();
+    MediaExtractor::CreatorFunc curCreator = NULL;
+    MediaExtractor::CreatorFunc bestCreator = NULL;
+    for (List<MediaExtractor::ExtractorDef>::iterator it = gSniffers.begin();
          it != gSniffers.end(); ++it) {
         String8 newMimeType;
         float newConfidence;
@@ -233,9 +161,9 @@
 }
 
 // static
-void MediaExtractor::RegisterSniffer_l(const ExtractorDef &def) {
+void MediaExtractorFactory::RegisterSniffer_l(const MediaExtractor::ExtractorDef &def) {
     // sanity check check struct version, uuid, name
-    if (def.def_version == 0 || def.def_version > EXTRACTORDEF_VERSION) {
+    if (def.def_version == 0 || def.def_version > MediaExtractor::EXTRACTORDEF_VERSION) {
         ALOGE("don't understand extractor format %u, ignoring.", def.def_version);
         return;
     }
@@ -248,7 +176,7 @@
         return;
     }
 
-    for (List<ExtractorDef>::iterator it = gSniffers.begin();
+    for (List<MediaExtractor::ExtractorDef>::iterator it = gSniffers.begin();
             it != gSniffers.end(); ++it) {
         if (memcmp(&((*it).extractor_uuid), &def.extractor_uuid, 16) == 0) {
             // there's already an extractor with the same uuid
@@ -274,7 +202,7 @@
 }
 
 // static
-void MediaExtractor::RegisterDefaultSniffers() {
+void MediaExtractorFactory::RegisterDefaultSniffers() {
     Mutex::Autolock autoLock(gSnifferMutex);
     if (gSniffersRegistered) {
         return;
@@ -288,7 +216,8 @@
                 String8 libPath = String8(libDirPath) + libEntry->d_name;
                 void *libHandle = dlopen(libPath.string(), RTLD_NOW | RTLD_LOCAL);
                 if (libHandle) {
-                    GetExtractorDef getsniffer = (GetExtractorDef) dlsym(libHandle, "GETEXTRACTORDEF");
+                    MediaExtractor::GetExtractorDef getsniffer =
+                            (MediaExtractor::GetExtractorDef) dlsym(libHandle, "GETEXTRACTORDEF");
                     if (getsniffer) {
                         ALOGV("registering sniffer for %s", libPath.string());
                         RegisterSniffer_l(getsniffer());
diff --git a/media/libstagefright/MediaMuxer.cpp b/media/libstagefright/MediaMuxer.cpp
index c7b8888..fb048fe 100644
--- a/media/libstagefright/MediaMuxer.cpp
+++ b/media/libstagefright/MediaMuxer.cpp
@@ -23,6 +23,7 @@
 
 #include <media/stagefright/MediaMuxer.h>
 
+#include <media/MediaSource.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
@@ -31,7 +32,6 @@
 #include <media/stagefright/MediaCodec.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/MediaSource.h>
 #include <media/stagefright/MetaData.h>
 #include <media/stagefright/MPEG4Writer.h>
 #include <media/stagefright/Utils.h>
diff --git a/media/libstagefright/MediaSource.cpp b/media/libstagefright/MediaSource.cpp
deleted file mode 100644
index 8b92a6b..0000000
--- a/media/libstagefright/MediaSource.cpp
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2009 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.
- */
-
-#include <media/stagefright/CallbackMediaSource.h>
-#include <media/stagefright/MediaSource.h>
-#include <media/stagefright/RemoteMediaSource.h>
-
-namespace android {
-
-MediaSource::MediaSource() {}
-
-MediaSource::~MediaSource() {}
-
-// static
-sp<MediaSource> MediaSource::CreateFromIMediaSource(const sp<IMediaSource> &source) {
-    if (source == nullptr) {
-        return nullptr;
-    }
-    return new CallbackMediaSource(source);
-}
-
-sp<IMediaSource> MediaSource::asIMediaSource() {
-    return RemoteMediaSource::wrap(sp<MediaSource>(this));
-}
-
-}  // namespace android
diff --git a/media/libstagefright/NuMediaExtractor.cpp b/media/libstagefright/NuMediaExtractor.cpp
index 640cb82..a176382 100644
--- a/media/libstagefright/NuMediaExtractor.cpp
+++ b/media/libstagefright/NuMediaExtractor.cpp
@@ -23,28 +23,40 @@
 #include "include/ESDS.h"
 #include "include/NuCachedSource2.h"
 
+#include <media/DataSource.h>
+#include <media/MediaExtractor.h>
+#include <media/MediaSource.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
-#include <media/stagefright/DataSource.h>
+#include <media/stagefright/DataSourceFactory.h>
 #include <media/stagefright/FileSource.h>
 #include <media/stagefright/MediaBuffer.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/MediaExtractor.h>
-#include <media/stagefright/MediaSource.h>
+#include <media/stagefright/MediaExtractorFactory.h>
 #include <media/stagefright/MetaData.h>
 #include <media/stagefright/Utils.h>
 
 namespace android {
 
+NuMediaExtractor::Sample::Sample()
+    : mBuffer(NULL),
+      mSampleTimeUs(-1ll) {
+}
+
+NuMediaExtractor::Sample::Sample(MediaBuffer *buffer, int64_t timeUs)
+    : mBuffer(buffer),
+      mSampleTimeUs(timeUs) {
+}
+
 NuMediaExtractor::NuMediaExtractor()
     : mTotalBitrate(-1ll),
       mDurationUs(-1ll) {
 }
 
 NuMediaExtractor::~NuMediaExtractor() {
-    releaseTrackSamples();
+    releaseAllTrackSamples();
 
     for (size_t i = 0; i < mSelectedTracks.size(); ++i) {
         TrackInfo *info = &mSelectedTracks.editItemAt(i);
@@ -70,13 +82,13 @@
     }
 
     sp<DataSource> dataSource =
-        DataSource::CreateFromURI(httpService, path, headers);
+        DataSourceFactory::CreateFromURI(httpService, path, headers);
 
     if (dataSource == NULL) {
         return -ENOENT;
     }
 
-    mImpl = MediaExtractor::Create(dataSource);
+    mImpl = MediaExtractorFactory::Create(dataSource);
 
     if (mImpl == NULL) {
         return ERROR_UNSUPPORTED;
@@ -112,7 +124,7 @@
         return err;
     }
 
-    mImpl = MediaExtractor::Create(fileSource);
+    mImpl = MediaExtractorFactory::Create(fileSource);
 
     if (mImpl == NULL) {
         return ERROR_UNSUPPORTED;
@@ -142,7 +154,7 @@
         return err;
     }
 
-    mImpl = MediaExtractor::Create(source);
+    mImpl = MediaExtractorFactory::Create(source);
 
     if (mImpl == NULL) {
         return ERROR_UNSUPPORTED;
@@ -286,7 +298,8 @@
     return OK;
 }
 
-status_t NuMediaExtractor::selectTrack(size_t index) {
+status_t NuMediaExtractor::selectTrack(size_t index,
+        int64_t startTimeUs, MediaSource::ReadOptions::SeekMode mode) {
     Mutex::Autolock autoLock(mLock);
 
     if (mImpl == NULL) {
@@ -309,31 +322,56 @@
     sp<IMediaSource> source = mImpl->getTrack(index);
 
     if (source == nullptr) {
+        ALOGE("track %zu is empty", index);
         return ERROR_MALFORMED;
     }
 
     status_t ret = source->start();
     if (ret != OK) {
+        ALOGE("track %zu failed to start", index);
         return ret;
     }
 
+    sp<MetaData> meta = source->getFormat();
+    if (meta == NULL) {
+        ALOGE("track %zu has no meta data", index);
+        return ERROR_MALFORMED;
+    }
+
+    const char *mime;
+    if (!meta->findCString(kKeyMIMEType, &mime)) {
+        ALOGE("track %zu has no mime type in meta data", index);
+        return ERROR_MALFORMED;
+    }
+    ALOGV("selectTrack, track[%zu]: %s", index, mime);
+
     mSelectedTracks.push();
     TrackInfo *info = &mSelectedTracks.editItemAt(mSelectedTracks.size() - 1);
 
     info->mSource = source;
     info->mTrackIndex = index;
+    if (!strncasecmp(mime, "audio/", 6)) {
+        info->mTrackType = MEDIA_TRACK_TYPE_AUDIO;
+        info->mMaxFetchCount = 64;
+    } else if (!strncasecmp(mime, "video/", 6)) {
+        info->mTrackType = MEDIA_TRACK_TYPE_VIDEO;
+        info->mMaxFetchCount = 8;
+    } else {
+        info->mTrackType = MEDIA_TRACK_TYPE_UNKNOWN;
+        info->mMaxFetchCount = 1;
+    }
     info->mFinalResult = OK;
-    info->mSample = NULL;
-    info->mSampleTimeUs = -1ll;
+    releaseTrackSamples(info);
     info->mTrackFlags = 0;
 
-    const char *mime;
-    CHECK(source->getFormat()->findCString(kKeyMIMEType, &mime));
-
     if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_VORBIS)) {
         info->mTrackFlags |= kIsVorbis;
     }
 
+    if (startTimeUs >= 0) {
+        fetchTrackSamples(info, startTimeUs, mode);
+    }
+
     return OK;
 }
 
@@ -364,12 +402,7 @@
 
     TrackInfo *info = &mSelectedTracks.editItemAt(i);
 
-    if (info->mSample != NULL) {
-        info->mSample->release();
-        info->mSample = NULL;
-
-        info->mSampleTimeUs = -1ll;
-    }
+    releaseTrackSamples(info);
 
     CHECK_EQ((status_t)OK, info->mSource->stop());
 
@@ -378,79 +411,136 @@
     return OK;
 }
 
-void NuMediaExtractor::releaseTrackSamples() {
-    for (size_t i = 0; i < mSelectedTracks.size(); ++i) {
-        TrackInfo *info = &mSelectedTracks.editItemAt(i);
+void NuMediaExtractor::releaseOneSample(TrackInfo *info) {
+    if (info == NULL || info->mSamples.empty()) {
+        return;
+    }
 
-        if (info->mSample != NULL) {
-            info->mSample->release();
-            info->mSample = NULL;
+    auto it = info->mSamples.begin();
+    if (it->mBuffer != NULL) {
+        it->mBuffer->release();
+    }
+    info->mSamples.erase(it);
+}
 
-            info->mSampleTimeUs = -1ll;
+void NuMediaExtractor::releaseTrackSamples(TrackInfo *info) {
+    if (info == NULL) {
+        return;
+    }
+
+    auto it = info->mSamples.begin();
+    while (it != info->mSamples.end()) {
+        if (it->mBuffer != NULL) {
+            it->mBuffer->release();
         }
+        it = info->mSamples.erase(it);
     }
 }
 
-ssize_t NuMediaExtractor::fetchTrackSamples(
+void NuMediaExtractor::releaseAllTrackSamples() {
+    for (size_t i = 0; i < mSelectedTracks.size(); ++i) {
+        releaseTrackSamples(&mSelectedTracks.editItemAt(i));
+    }
+}
+
+ssize_t NuMediaExtractor::fetchAllTrackSamples(
         int64_t seekTimeUs, MediaSource::ReadOptions::SeekMode mode) {
     TrackInfo *minInfo = NULL;
     ssize_t minIndex = -1;
 
     for (size_t i = 0; i < mSelectedTracks.size(); ++i) {
         TrackInfo *info = &mSelectedTracks.editItemAt(i);
+        fetchTrackSamples(info, seekTimeUs, mode);
 
-        if (seekTimeUs >= 0ll) {
-            info->mFinalResult = OK;
-
-            if (info->mSample != NULL) {
-                info->mSample->release();
-                info->mSample = NULL;
-                info->mSampleTimeUs = -1ll;
-            }
-        } else if (info->mFinalResult != OK) {
+        if (info->mSamples.empty()) {
             continue;
         }
 
-        if (info->mSample == NULL) {
-            MediaSource::ReadOptions options;
-            if (seekTimeUs >= 0ll) {
-                options.setSeekTo(seekTimeUs, mode);
-            }
-            status_t err = info->mSource->read(&info->mSample, &options);
-
-            if (err != OK) {
-                CHECK(info->mSample == NULL);
-
-                info->mFinalResult = err;
-
-                if (info->mFinalResult != ERROR_END_OF_STREAM) {
-                    ALOGW("read on track %zu failed with error %d",
-                          info->mTrackIndex, err);
-                }
-
-                info->mSampleTimeUs = -1ll;
-                continue;
-            } else {
-                CHECK(info->mSample != NULL);
-                CHECK(info->mSample->meta_data()->findInt64(
-                            kKeyTime, &info->mSampleTimeUs));
-            }
-        }
-
-        if (minInfo == NULL  || info->mSampleTimeUs < minInfo->mSampleTimeUs) {
+        if (minInfo == NULL) {
             minInfo = info;
             minIndex = i;
+        } else {
+            auto it = info->mSamples.begin();
+            auto itMin = minInfo->mSamples.begin();
+            if (it->mSampleTimeUs < itMin->mSampleTimeUs) {
+                minInfo = info;
+                minIndex = i;
+            }
         }
     }
 
     return minIndex;
 }
 
+void NuMediaExtractor::fetchTrackSamples(TrackInfo *info,
+        int64_t seekTimeUs, MediaSource::ReadOptions::SeekMode mode) {
+    if (info == NULL) {
+        return;
+    }
+
+    MediaSource::ReadOptions options;
+    if (seekTimeUs >= 0ll) {
+        options.setSeekTo(seekTimeUs, mode);
+        info->mFinalResult = OK;
+        releaseTrackSamples(info);
+    } else if (info->mFinalResult != OK || !info->mSamples.empty()) {
+        return;
+    }
+
+    status_t err = OK;
+    Vector<MediaBuffer *> mediaBuffers;
+    if (info->mSource->supportReadMultiple()) {
+        options.setNonBlocking();
+        err = info->mSource->readMultiple(&mediaBuffers, info->mMaxFetchCount, &options);
+    } else {
+        MediaBuffer *mbuf = NULL;
+        err = info->mSource->read(&mbuf, &options);
+        if (err == OK && mbuf != NULL) {
+            mediaBuffers.push_back(mbuf);
+        }
+    }
+
+    info->mFinalResult = err;
+    if (err != OK && err != ERROR_END_OF_STREAM) {
+        ALOGW("read on track %zu failed with error %d", info->mTrackIndex, err);
+        size_t count = mediaBuffers.size();
+        for (size_t id = 0; id < count; ++id) {
+            MediaBuffer *mbuf = mediaBuffers[id];
+            if (mbuf != NULL) {
+                mbuf->release();
+            }
+        }
+        return;
+    }
+
+    size_t count = mediaBuffers.size();
+    bool releaseRemaining = false;
+    for (size_t id = 0; id < count; ++id) {
+        int64_t timeUs;
+        MediaBuffer *mbuf = mediaBuffers[id];
+        if (mbuf == NULL) {
+            continue;
+        }
+        if (releaseRemaining) {
+            mbuf->release();
+            continue;
+        }
+        if (mbuf->meta_data()->findInt64(kKeyTime, &timeUs)) {
+            info->mSamples.emplace_back(mbuf, timeUs);
+        } else {
+            mbuf->meta_data()->dumpToLog();
+            info->mFinalResult = ERROR_MALFORMED;
+            mbuf->release();
+            releaseRemaining = true;
+        }
+    }
+}
+
 status_t NuMediaExtractor::seekTo(
         int64_t timeUs, MediaSource::ReadOptions::SeekMode mode) {
     Mutex::Autolock autoLock(mLock);
 
-    ssize_t minIndex = fetchTrackSamples(timeUs, mode);
+    ssize_t minIndex = fetchAllTrackSamples(timeUs, mode);
 
     if (minIndex < 0) {
         return ERROR_END_OF_STREAM;
@@ -462,7 +552,7 @@
 status_t NuMediaExtractor::advance() {
     Mutex::Autolock autoLock(mLock);
 
-    ssize_t minIndex = fetchTrackSamples();
+    ssize_t minIndex = fetchAllTrackSamples();
 
     if (minIndex < 0) {
         return ERROR_END_OF_STREAM;
@@ -470,28 +560,26 @@
 
     TrackInfo *info = &mSelectedTracks.editItemAt(minIndex);
 
-    info->mSample->release();
-    info->mSample = NULL;
-    info->mSampleTimeUs = -1ll;
+    releaseOneSample(info);
 
     return OK;
 }
 
-status_t NuMediaExtractor::appendVorbisNumPageSamples(TrackInfo *info, const sp<ABuffer> &buffer) {
+status_t NuMediaExtractor::appendVorbisNumPageSamples(MediaBuffer *mbuf, const sp<ABuffer> &buffer) {
     int32_t numPageSamples;
-    if (!info->mSample->meta_data()->findInt32(
+    if (!mbuf->meta_data()->findInt32(
             kKeyValidSamples, &numPageSamples)) {
         numPageSamples = -1;
     }
 
-    memcpy((uint8_t *)buffer->data() + info->mSample->range_length(),
+    memcpy((uint8_t *)buffer->data() + mbuf->range_length(),
            &numPageSamples,
            sizeof(numPageSamples));
 
     uint32_t type;
     const void *data;
     size_t size, size2;
-    if (info->mSample->meta_data()->findData(kKeyEncryptedSizes, &type, &data, &size)) {
+    if (mbuf->meta_data()->findData(kKeyEncryptedSizes, &type, &data, &size)) {
         // Signal numPageSamples (a plain int32_t) is appended at the end,
         // i.e. sizeof(numPageSamples) plain bytes + 0 encrypted bytes
         if (SIZE_MAX - size < sizeof(int32_t)) {
@@ -509,9 +597,9 @@
         int32_t zero = 0;
         memcpy(adata, data, size);
         memcpy(adata + size, &zero, sizeof(zero));
-        info->mSample->meta_data()->setData(kKeyEncryptedSizes, type, adata, newSize);
+        mbuf->meta_data()->setData(kKeyEncryptedSizes, type, adata, newSize);
 
-        if (info->mSample->meta_data()->findData(kKeyPlainSizes, &type, &data, &size2)) {
+        if (mbuf->meta_data()->findData(kKeyPlainSizes, &type, &data, &size2)) {
             if (size2 != size) {
                 return ERROR_MALFORMED;
             }
@@ -524,7 +612,7 @@
         // append sizeof(numPageSamples) to plain sizes.
         int32_t int32Size = sizeof(numPageSamples);
         memcpy(adata + size, &int32Size, sizeof(int32Size));
-        info->mSample->meta_data()->setData(kKeyPlainSizes, type, adata, newSize);
+        mbuf->meta_data()->setData(kKeyPlainSizes, type, adata, newSize);
     }
 
     return OK;
@@ -533,7 +621,7 @@
 status_t NuMediaExtractor::readSampleData(const sp<ABuffer> &buffer) {
     Mutex::Autolock autoLock(mLock);
 
-    ssize_t minIndex = fetchTrackSamples();
+    ssize_t minIndex = fetchAllTrackSamples();
 
     if (minIndex < 0) {
         return ERROR_END_OF_STREAM;
@@ -541,7 +629,8 @@
 
     TrackInfo *info = &mSelectedTracks.editItemAt(minIndex);
 
-    size_t sampleSize = info->mSample->range_length();
+    auto it = info->mSamples.begin();
+    size_t sampleSize = it->mBuffer->range_length();
 
     if (info->mTrackFlags & kIsVorbis) {
         // Each sample's data is suffixed by the number of page samples
@@ -554,14 +643,14 @@
     }
 
     const uint8_t *src =
-        (const uint8_t *)info->mSample->data()
-            + info->mSample->range_offset();
+        (const uint8_t *)it->mBuffer->data()
+            + it->mBuffer->range_offset();
 
-    memcpy((uint8_t *)buffer->data(), src, info->mSample->range_length());
+    memcpy((uint8_t *)buffer->data(), src, it->mBuffer->range_length());
 
     status_t err = OK;
     if (info->mTrackFlags & kIsVorbis) {
-        err = appendVorbisNumPageSamples(info, buffer);
+        err = appendVorbisNumPageSamples(it->mBuffer, buffer);
     }
 
     if (err == OK) {
@@ -574,7 +663,7 @@
 status_t NuMediaExtractor::getSampleTrackIndex(size_t *trackIndex) {
     Mutex::Autolock autoLock(mLock);
 
-    ssize_t minIndex = fetchTrackSamples();
+    ssize_t minIndex = fetchAllTrackSamples();
 
     if (minIndex < 0) {
         return ERROR_END_OF_STREAM;
@@ -589,14 +678,14 @@
 status_t NuMediaExtractor::getSampleTime(int64_t *sampleTimeUs) {
     Mutex::Autolock autoLock(mLock);
 
-    ssize_t minIndex = fetchTrackSamples();
+    ssize_t minIndex = fetchAllTrackSamples();
 
     if (minIndex < 0) {
         return ERROR_END_OF_STREAM;
     }
 
     TrackInfo *info = &mSelectedTracks.editItemAt(minIndex);
-    *sampleTimeUs = info->mSampleTimeUs;
+    *sampleTimeUs = info->mSamples.begin()->mSampleTimeUs;
 
     return OK;
 }
@@ -606,14 +695,14 @@
 
     *sampleMeta = NULL;
 
-    ssize_t minIndex = fetchTrackSamples();
+    ssize_t minIndex = fetchAllTrackSamples();
 
     if (minIndex < 0) {
         return ERROR_END_OF_STREAM;
     }
 
     TrackInfo *info = &mSelectedTracks.editItemAt(minIndex);
-    *sampleMeta = info->mSample->meta_data();
+    *sampleMeta = info->mSamples.begin()->mBuffer->meta_data();
 
     return OK;
 }
@@ -624,7 +713,7 @@
 }
 
 bool NuMediaExtractor::getTotalBitrate(int64_t *bitrate) const {
-    if (mTotalBitrate >= 0) {
+    if (mTotalBitrate > 0) {
         *bitrate = mTotalBitrate;
         return true;
     }
diff --git a/media/libstagefright/OMXClient.cpp b/media/libstagefright/OMXClient.cpp
index 5f50e46..cd07262 100644
--- a/media/libstagefright/OMXClient.cpp
+++ b/media/libstagefright/OMXClient.cpp
@@ -25,7 +25,6 @@
 #include <cutils/properties.h>
 
 #include <binder/IServiceManager.h>
-#include <media/IMediaCodecService.h>
 #include <media/stagefright/OMXClient.h>
 
 #include <media/IOMX.h>
@@ -37,71 +36,22 @@
 OMXClient::OMXClient() {
 }
 
-status_t OMXClient::connect() {
-    return connect("default", nullptr);
-}
-
-status_t OMXClient::connect(bool* trebleFlag) {
-    if (property_get_bool("persist.media.treble_omx", true)) {
-        if (trebleFlag != nullptr) {
-            *trebleFlag = true;
-        }
-        return connectTreble();
-    }
-    if (trebleFlag != nullptr) {
-        *trebleFlag = false;
-    }
-    return connectLegacy();
-}
-
-status_t OMXClient::connect(const char* name, bool* trebleFlag) {
-    if (property_get_bool("persist.media.treble_omx", true)) {
-        if (trebleFlag != nullptr) {
-            *trebleFlag = true;
-        }
-        return connectTreble(name);
-    }
-    if (trebleFlag != nullptr) {
-        *trebleFlag = false;
-    }
-    return connectLegacy();
-}
-
-status_t OMXClient::connectLegacy() {
-    sp<IServiceManager> sm = defaultServiceManager();
-    sp<IBinder> codecbinder = sm->getService(String16("media.codec"));
-    sp<IMediaCodecService> codecservice = interface_cast<IMediaCodecService>(codecbinder);
-
-    if (codecservice.get() == NULL) {
-        ALOGE("Cannot obtain IMediaCodecService");
-        return NO_INIT;
-    }
-
-    mOMX = codecservice->getOMX();
-    if (mOMX.get() == NULL) {
-        ALOGE("Cannot obtain mediacodec IOMX");
-        return NO_INIT;
-    }
-
-    return OK;
-}
-
-status_t OMXClient::connectTreble(const char* name) {
+status_t OMXClient::connect(const char* name) {
     using namespace ::android::hardware::media::omx::V1_0;
     if (name == nullptr) {
         name = "default";
     }
     sp<IOmx> tOmx = IOmx::getService(name);
     if (tOmx.get() == nullptr) {
-        ALOGE("Cannot obtain Treble IOmx.");
+        ALOGE("Cannot obtain IOmx service.");
         return NO_INIT;
     }
     if (!tOmx->isRemote()) {
-        ALOGE("Treble IOmx is in passthrough mode.");
+        ALOGE("IOmx service running in passthrough mode.");
         return NO_INIT;
     }
     mOMX = new utils::LWOmx(tOmx);
-    ALOGI("Treble IOmx obtained");
+    ALOGI("IOmx service obtained");
     return OK;
 }
 
@@ -109,4 +59,8 @@
     mOMX.clear();
 }
 
+sp<IOMX> OMXClient::interface() {
+    return mOMX;
+}
+
 }  // namespace android
diff --git a/media/libstagefright/OmxInfoBuilder.cpp b/media/libstagefright/OmxInfoBuilder.cpp
index 063d13e..c174371 100644
--- a/media/libstagefright/OmxInfoBuilder.cpp
+++ b/media/libstagefright/OmxInfoBuilder.cpp
@@ -24,8 +24,6 @@
 #include <utils/Log.h>
 #include <cutils/properties.h>
 
-#include <binder/IServiceManager.h>
-#include <media/IMediaCodecService.h>
 #include <media/stagefright/foundation/MediaDefs.h>
 #include <media/stagefright/OmxInfoBuilder.h>
 #include <media/stagefright/ACodec.h>
@@ -35,7 +33,6 @@
 #include <android/hardware/media/omx/1.0/IOmxNode.h>
 #include <media/stagefright/omx/OMXUtils.h>
 
-#include <media/IOMXStore.h>
 #include <media/IOMX.h>
 #include <media/omx/1.0/WOmx.h>
 
@@ -48,10 +45,18 @@
 
 namespace android {
 
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using namespace ::android::hardware::media::omx::V1_0;
+
 namespace /* unnamed */ {
 
+bool hasPrefix(const hidl_string& s, const char* prefix) {
+    return strncmp(s.c_str(), prefix, strlen(prefix)) == 0;
+}
+
 status_t queryCapabilities(
-        const IOMXStore::NodeInfo& node, const char* mime, bool isEncoder,
+        const IOmxStore::NodeInfo& node, const char* mime, bool isEncoder,
         MediaCodecInfo::CapabilitiesWriter* caps) {
     sp<ACodec> codec = new ACodec();
     status_t err = codec->queryCapabilities(
@@ -62,14 +67,13 @@
     for (const auto& attribute : node.attributes) {
         // All features have an int32 value except
         // "feature-bitrate-modes", which has a string value.
-        if ((attribute.key.compare(0, 8, "feature-") == 0) &&
-                (attribute.key.compare(8, 15, "bitrate-modes")
-                 != 0)) {
-            // If this attribute.key is a feature that is not a bitrate
-            // control, add an int32 value.
+        if (hasPrefix(attribute.key, "feature-") &&
+                !hasPrefix(attribute.key, "feature-bitrate-modes")) {
+            // If this attribute.key is a feature that is not bitrate modes,
+            // add an int32 value.
             caps->addDetail(
                     attribute.key.c_str(),
-                    attribute.value == "1" ? 1 : 0);
+                    hasPrefix(attribute.value, "1") ? 1 : 0);
         } else {
             // Non-feature attributes
             caps->addDetail(
@@ -85,138 +89,53 @@
 }
 
 status_t OmxInfoBuilder::buildMediaCodecList(MediaCodecListWriter* writer) {
-    bool treble;
-    sp<IOMX> omx;
-    std::vector<IOMXStore::RoleInfo> roles;
+    hidl_vec<IOmxStore::RoleInfo> roles;
 
-    treble = property_get_bool("persist.media.treble_omx", true);
-    if (treble) {
-        using namespace ::android::hardware::media::omx::V1_0;
-        using ::android::hardware::hidl_vec;
-        using ::android::hardware::hidl_string;
+    // Obtain IOmxStore
+    sp<IOmxStore> omxStore = IOmxStore::getService();
+    if (omxStore == nullptr) {
+        ALOGE("Cannot find an IOmxStore service.");
+        return NO_INIT;
+    }
 
-        // Obtain IOmxStore
-        sp<IOmxStore> omxStore = IOmxStore::getService();
-        if (omxStore == nullptr) {
-            ALOGE("Cannot connect to an IOmxStore instance.");
-            return NO_INIT;
-        }
+    // List service attributes (global settings)
+    Status status;
+    hidl_vec<IOmxStore::ServiceAttribute> serviceAttributes;
+    auto transStatus = omxStore->listServiceAttributes(
+            [&status, &serviceAttributes] (
+            Status inStatus,
+            const hidl_vec<IOmxStore::ServiceAttribute>& inAttributes) {
+                status = inStatus;
+                serviceAttributes = inAttributes;
+            });
+    if (!transStatus.isOk()) {
+        ALOGE("Fail to obtain global settings from IOmxStore.");
+        return NO_INIT;
+    }
+    if (status != Status::OK) {
+        ALOGE("IOmxStore reports parsing error.");
+        return NO_INIT;
+    }
+    for (const auto& p : serviceAttributes) {
+        writer->addGlobalSetting(
+                p.key.c_str(), p.value.c_str());
+    }
 
-        // List service attributes (global settings)
-        Status status;
-        hidl_vec<IOmxStore::ServiceAttribute> serviceAttributes;
-        auto transStatus = omxStore->listServiceAttributes(
-                [&status, &serviceAttributes]
-                (Status inStatus, const hidl_vec<IOmxStore::ServiceAttribute>&
-                        inAttributes) {
-                    status = inStatus;
-                    serviceAttributes = inAttributes;
-                });
-        if (!transStatus.isOk()) {
-            ALOGE("Fail to obtain global settings from IOmxStore.");
-            return NO_INIT;
-        }
-        if (status != Status::OK) {
-            ALOGE("IOmxStore reports parsing error.");
-            return NO_INIT;
-        }
-        for (const auto& p : serviceAttributes) {
-            writer->addGlobalSetting(
-                    p.key.c_str(), p.value.c_str());
-        }
-
-        // List roles and convert to IOMXStore's format
-        transStatus = omxStore->listRoles(
-                [&roles]
-                (const hidl_vec<IOmxStore::RoleInfo>& inRoleList) {
-                    roles.reserve(inRoleList.size());
-                    for (const auto& inRole : inRoleList) {
-                        IOMXStore::RoleInfo role;
-                        role.role = inRole.role;
-                        role.type = inRole.type;
-                        role.isEncoder = inRole.isEncoder;
-                        role.preferPlatformNodes = inRole.preferPlatformNodes;
-                        std::vector<IOMXStore::NodeInfo>& nodes =
-                                role.nodes;
-                        nodes.reserve(inRole.nodes.size());
-                        for (const auto& inNode : inRole.nodes) {
-                            IOMXStore::NodeInfo node;
-                            node.name = inNode.name;
-                            node.owner = inNode.owner;
-                            std::vector<IOMXStore::Attribute>& attributes =
-                                    node.attributes;
-                            attributes.reserve(inNode.attributes.size());
-                            for (const auto& inAttr : inNode.attributes) {
-                                IOMXStore::Attribute attr;
-                                attr.key = inAttr.key;
-                                attr.value = inAttr.value;
-                                attributes.push_back(std::move(attr));
-                            }
-                            nodes.push_back(std::move(node));
-                        }
-                        roles.push_back(std::move(role));
-                    }
-                });
-        if (!transStatus.isOk()) {
-            ALOGE("Fail to obtain codec roles from IOmxStore.");
-            return NO_INIT;
-        }
-    } else {
-        // Obtain IOMXStore
-        sp<IServiceManager> sm = defaultServiceManager();
-        if (sm == nullptr) {
-            ALOGE("Cannot obtain the default service manager.");
-            return NO_INIT;
-        }
-        sp<IBinder> codecBinder = sm->getService(String16("media.codec"));
-        if (codecBinder == nullptr) {
-            ALOGE("Cannot obtain the media codec service.");
-            return NO_INIT;
-        }
-        sp<IMediaCodecService> codecService =
-                interface_cast<IMediaCodecService>(codecBinder);
-        if (codecService == nullptr) {
-            ALOGE("Wrong type of media codec service obtained.");
-            return NO_INIT;
-        }
-        omx = codecService->getOMX();
-        if (omx == nullptr) {
-            ALOGE("Cannot connect to an IOMX instance.");
-        }
-        sp<IOMXStore> omxStore = codecService->getOMXStore();
-        if (omxStore == nullptr) {
-            ALOGE("Cannot connect to an IOMXStore instance.");
-            return NO_INIT;
-        }
-
-        // List service attributes (global settings)
-        std::vector<IOMXStore::Attribute> serviceAttributes;
-        status_t status = omxStore->listServiceAttributes(&serviceAttributes);
-        if (status != OK) {
-            ALOGE("Fail to obtain global settings from IOMXStore.");
-            return NO_INIT;
-        }
-        for (const auto& p : serviceAttributes) {
-            writer->addGlobalSetting(
-                    p.key.c_str(), p.value.c_str());
-        }
-
-        // List roles
-        status = omxStore->listRoles(&roles);
-        if (status != OK) {
-            ALOGE("Fail to obtain codec roles from IOMXStore.");
-            return NO_INIT;
-        }
+    transStatus = omxStore->listRoles(
+            [&roles] (
+            const hidl_vec<IOmxStore::RoleInfo>& inRoleList) {
+                roles = inRoleList;
+            });
+    if (!transStatus.isOk()) {
+        ALOGE("Fail to obtain codec roles from IOmxStore.");
+        return NO_INIT;
     }
 
     // Convert roles to lists of codecs
 
-    // codec name -> index into swCodecs
-    std::map<std::string, std::unique_ptr<MediaCodecInfoWriter> >
-            swCodecName2Info;
-    // codec name -> index into hwCodecs
-    std::map<std::string, std::unique_ptr<MediaCodecInfoWriter> >
-            hwCodecName2Info;
+    // codec name -> index into swCodecs/hwCodecs
+    std::map<hidl_string, std::unique_ptr<MediaCodecInfoWriter>>
+            swCodecName2Info, hwCodecName2Info;
     // owner name -> MediaCodecInfo
     // This map will be used to obtain the correct IOmx service(s) needed for
     // creating IOmxNode instances and querying capabilities.
@@ -230,10 +149,10 @@
         // If preferPlatformNodes is true, hardware nodes must be added after
         // platform (software) nodes. hwCodecs is used to hold hardware nodes
         // that need to be added after software nodes for the same role.
-        std::vector<const IOMXStore::NodeInfo*> hwCodecs;
+        std::vector<const IOmxStore::NodeInfo*> hwCodecs;
         for (const auto& node : role.nodes) {
             const auto& nodeName = node.name;
-            bool isSoftware = nodeName.compare(0, 10, "OMX.google") == 0;
+            bool isSoftware = hasPrefix(nodeName, "OMX.google");
             MediaCodecInfoWriter* info;
             if (isSoftware) {
                 auto c2i = swCodecName2Info.find(nodeName);
diff --git a/media/libstagefright/RemoteMediaExtractor.cpp b/media/libstagefright/RemoteMediaExtractor.cpp
index db2c20c..1dd7986 100644
--- a/media/libstagefright/RemoteMediaExtractor.cpp
+++ b/media/libstagefright/RemoteMediaExtractor.cpp
@@ -14,8 +14,9 @@
  * limitations under the License.
  */
 
+#include <media/stagefright/InterfaceUtils.h>
+#include <media/MediaSource.h>
 #include <media/stagefright/RemoteMediaExtractor.h>
-#include <media/stagefright/MediaSource.h>
 
 namespace android {
 
@@ -30,7 +31,7 @@
 
 sp<IMediaSource> RemoteMediaExtractor::getTrack(size_t index) {
     sp<MediaSource> source = mExtractor->getTrack(index);
-    return (source.get() == nullptr) ? nullptr : source->asIMediaSource();
+    return (source.get() == nullptr) ? nullptr : CreateIMediaSourceFromMediaSource(source);
 }
 
 sp<MetaData> RemoteMediaExtractor::getTrackMetaData(size_t index, uint32_t flags) {
diff --git a/media/libstagefright/RemoteMediaSource.cpp b/media/libstagefright/RemoteMediaSource.cpp
index 4060526..7a2a46b 100644
--- a/media/libstagefright/RemoteMediaSource.cpp
+++ b/media/libstagefright/RemoteMediaSource.cpp
@@ -15,6 +15,7 @@
  */
 
 #include <media/stagefright/RemoteMediaSource.h>
+#include <media/IMediaSource.h>
 
 namespace android {
 
@@ -35,7 +36,7 @@
     return mSource->getFormat();
 }
 
-status_t RemoteMediaSource::read(MediaBuffer **buffer, const ReadOptions *options) {
+status_t RemoteMediaSource::read(MediaBuffer **buffer, const MediaSource::ReadOptions *options) {
     return mSource->read(buffer, reinterpret_cast<const MediaSource::ReadOptions*>(options));
 }
 
diff --git a/media/libstagefright/StagefrightMetadataRetriever.cpp b/media/libstagefright/StagefrightMetadataRetriever.cpp
index 103da95..dfaa8b6 100644
--- a/media/libstagefright/StagefrightMetadataRetriever.cpp
+++ b/media/libstagefright/StagefrightMetadataRetriever.cpp
@@ -20,37 +20,24 @@
 #include <inttypes.h>
 
 #include <utils/Log.h>
-#include <gui/Surface.h>
 
-#include "include/avc_utils.h"
+#include "include/FrameDecoder.h"
 #include "include/StagefrightMetadataRetriever.h"
 
-#include <media/ICrypto.h>
 #include <media/IMediaHTTPService.h>
-#include <media/MediaCodecBuffer.h>
-
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
-#include <media/stagefright/ColorConverter.h>
-#include <media/stagefright/DataSource.h>
+#include <media/stagefright/DataSourceFactory.h>
 #include <media/stagefright/FileSource.h>
-#include <media/stagefright/MediaBuffer.h>
-#include <media/stagefright/MediaCodec.h>
 #include <media/stagefright/MediaCodecList.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/MediaExtractor.h>
-#include <media/stagefright/MediaSource.h>
+#include <media/stagefright/MediaExtractorFactory.h>
 #include <media/stagefright/MetaData.h>
-#include <media/stagefright/Utils.h>
-
 #include <media/CharacterEncodingDetector.h>
 
 namespace android {
 
-static const int64_t kBufferTimeOutUs = 30000ll; // 30 msec
-static const size_t kRetryCount = 20; // must be >0
-
 StagefrightMetadataRetriever::StagefrightMetadataRetriever()
     : mParsedMetaData(false),
       mAlbumArt(NULL) {
@@ -78,14 +65,14 @@
     ALOGV("setDataSource(%s)", uri);
 
     clearMetadata();
-    mSource = DataSource::CreateFromURI(httpService, uri, headers);
+    mSource = DataSourceFactory::CreateFromURI(httpService, uri, headers);
 
     if (mSource == NULL) {
         ALOGE("Unable to create data source for '%s'.", uri);
         return UNKNOWN_ERROR;
     }
 
-    mExtractor = MediaExtractor::Create(mSource);
+    mExtractor = MediaExtractorFactory::Create(mSource);
 
     if (mExtractor == NULL) {
         ALOGE("Unable to instantiate an extractor for '%s'.", uri);
@@ -115,7 +102,7 @@
         return err;
     }
 
-    mExtractor = MediaExtractor::Create(mSource);
+    mExtractor = MediaExtractorFactory::Create(mSource);
 
     if (mExtractor == NULL) {
         mSource.clear();
@@ -132,7 +119,7 @@
 
     clearMetadata();
     mSource = source;
-    mExtractor = MediaExtractor::Create(mSource, mime);
+    mExtractor = MediaExtractorFactory::Create(mSource, mime);
 
     if (mExtractor == NULL) {
         ALOGE("Failed to instantiate a MediaExtractor.");
@@ -143,469 +130,123 @@
     return OK;
 }
 
-static VideoFrame *allocVideoFrame(
-        const sp<MetaData> &trackMeta, int32_t width, int32_t height, int32_t bpp, bool metaOnly) {
-    int32_t rotationAngle;
-    if (!trackMeta->findInt32(kKeyRotation, &rotationAngle)) {
-        rotationAngle = 0;  // By default, no rotation
-    }
+VideoFrame* StagefrightMetadataRetriever::getImageAtIndex(
+        int index, int colorFormat, bool metaOnly) {
 
-    uint32_t type;
-    const void *iccData;
-    size_t iccSize;
-    if (!trackMeta->findData(kKeyIccProfile, &type, &iccData, &iccSize)){
-        iccData = NULL;
-        iccSize = 0;
-    }
+    ALOGV("getImageAtIndex: index: %d colorFormat: %d, metaOnly: %d",
+            index, colorFormat, metaOnly);
 
-    int32_t sarWidth, sarHeight;
-    int32_t displayWidth, displayHeight;
-    if (trackMeta->findInt32(kKeySARWidth, &sarWidth)
-            && trackMeta->findInt32(kKeySARHeight, &sarHeight)
-            && sarHeight != 0) {
-        displayWidth = (width * sarWidth) / sarHeight;
-        displayHeight = height;
-    } else if (trackMeta->findInt32(kKeyDisplayWidth, &displayWidth)
-                && trackMeta->findInt32(kKeyDisplayHeight, &displayHeight)
-                && displayWidth > 0 && displayHeight > 0
-                && width > 0 && height > 0) {
-        ALOGV("found display size %dx%d", displayWidth, displayHeight);
-    } else {
-        displayWidth = width;
-        displayHeight = height;
-    }
-
-    return new VideoFrame(width, height, displayWidth, displayHeight,
-            rotationAngle, bpp, !metaOnly, iccData, iccSize);
-}
-
-static bool getDstColorFormat(android_pixel_format_t colorFormat,
-        OMX_COLOR_FORMATTYPE *omxColorFormat, int32_t *bpp) {
-    switch (colorFormat) {
-        case HAL_PIXEL_FORMAT_RGB_565:
-        {
-            *omxColorFormat = OMX_COLOR_Format16bitRGB565;
-            *bpp = 2;
-            return true;
-        }
-        case HAL_PIXEL_FORMAT_RGBA_8888:
-        {
-            *omxColorFormat = OMX_COLOR_Format32BitRGBA8888;
-            *bpp = 4;
-            return true;
-        }
-        case HAL_PIXEL_FORMAT_BGRA_8888:
-        {
-            *omxColorFormat = OMX_COLOR_Format32bitBGRA8888;
-            *bpp = 4;
-            return true;
-        }
-        default:
-        {
-            ALOGE("Unsupported color format: %d", colorFormat);
-            break;
-        }
-    }
-    return false;
-}
-
-static VideoFrame *extractVideoFrame(
-        const AString &componentName,
-        const sp<MetaData> &trackMeta,
-        const sp<IMediaSource> &source,
-        int64_t frameTimeUs,
-        int seekMode,
-        int colorFormat,
-        bool metaOnly) {
-    sp<MetaData> format = source->getFormat();
-
-    MediaSource::ReadOptions::SeekMode mode =
-            static_cast<MediaSource::ReadOptions::SeekMode>(seekMode);
-    if (seekMode < MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC ||
-        seekMode > MediaSource::ReadOptions::SEEK_CLOSEST) {
-        ALOGE("Unknown seek mode: %d", seekMode);
+    if (mExtractor.get() == NULL) {
+        ALOGE("no extractor.");
         return NULL;
     }
 
-    int32_t dstBpp;
-    OMX_COLOR_FORMATTYPE dstFormat;
-    if (!getDstColorFormat(
-            (android_pixel_format_t)colorFormat, &dstFormat, &dstBpp)) {
-        return NULL;
-    }
+    size_t n = mExtractor->countTracks();
+    size_t i;
+    int imageCount = 0;
 
-    if (metaOnly) {
-        int32_t width, height;
-        CHECK(trackMeta->findInt32(kKeyWidth, &width));
-        CHECK(trackMeta->findInt32(kKeyHeight, &height));
-        return allocVideoFrame(trackMeta, width, height, dstBpp, true);
-    }
+    for (i = 0; i < n; ++i) {
+        sp<MetaData> meta = mExtractor->getTrackMetaData(i);
+        ALOGV("getting track %zu of %zu, meta=%s", i, n, meta->toString().c_str());
 
-    MediaSource::ReadOptions options;
-    sp<MetaData> overrideMeta;
-    if (frameTimeUs < 0) {
-        uint32_t type;
-        const void *data;
-        size_t size;
-        int64_t thumbNailTime;
-        int32_t thumbnailWidth, thumbnailHeight;
+        const char *mime;
+        CHECK(meta->findCString(kKeyMIMEType, &mime));
 
-        // if we have a stand-alone thumbnail, set up the override meta,
-        // and set seekTo time to -1.
-        if (trackMeta->findInt32(kKeyThumbnailWidth, &thumbnailWidth)
-         && trackMeta->findInt32(kKeyThumbnailHeight, &thumbnailHeight)
-         && trackMeta->findData(kKeyThumbnailHVCC, &type, &data, &size)){
-            overrideMeta = new MetaData(*trackMeta);
-            overrideMeta->remove(kKeyDisplayWidth);
-            overrideMeta->remove(kKeyDisplayHeight);
-            overrideMeta->setInt32(kKeyWidth, thumbnailWidth);
-            overrideMeta->setInt32(kKeyHeight, thumbnailHeight);
-            overrideMeta->setData(kKeyHVCC, type, data, size);
-            thumbNailTime = -1ll;
-            ALOGV("thumbnail: %dx%d", thumbnailWidth, thumbnailHeight);
-        } else if (!trackMeta->findInt64(kKeyThumbnailTime, &thumbNailTime)
-                || thumbNailTime < 0) {
-            thumbNailTime = 0;
-        }
-
-        options.setSeekTo(thumbNailTime, mode);
-    } else {
-        options.setSeekTo(frameTimeUs, mode);
-    }
-
-    int32_t gridRows = 1, gridCols = 1;
-    if (overrideMeta == NULL) {
-        // check if we're dealing with a tiled heif
-        int32_t gridWidth, gridHeight;
-        if (trackMeta->findInt32(kKeyGridWidth, &gridWidth) && gridWidth > 0
-         && trackMeta->findInt32(kKeyGridHeight, &gridHeight) && gridHeight > 0) {
-            int32_t width, height, displayWidth, displayHeight;
-            CHECK(trackMeta->findInt32(kKeyWidth, &width));
-            CHECK(trackMeta->findInt32(kKeyHeight, &height));
-            CHECK(trackMeta->findInt32(kKeyDisplayWidth, &displayWidth));
-            CHECK(trackMeta->findInt32(kKeyDisplayHeight, &displayHeight));
-
-            if (width >= displayWidth && height >= displayHeight
-                    && (width % gridWidth == 0) && (height % gridHeight == 0)) {
-                ALOGV("grid config: %dx%d, display %dx%d, grid %dx%d",
-                        width, height, displayWidth, displayHeight, gridWidth, gridHeight);
-
-                overrideMeta = new MetaData(*trackMeta);
-                overrideMeta->remove(kKeyDisplayWidth);
-                overrideMeta->remove(kKeyDisplayHeight);
-                overrideMeta->setInt32(kKeyWidth, gridWidth);
-                overrideMeta->setInt32(kKeyHeight, gridHeight);
-                gridCols = width / gridWidth;
-                gridRows = height / gridHeight;
-            } else {
-                ALOGE("Bad grid config: %dx%d, display %dx%d, grid %dx%d",
-                        width, height, displayWidth, displayHeight, gridWidth, gridHeight);
+        if (!strncasecmp(mime, "image/", 6)) {
+            int32_t isPrimary;
+            if ((index < 0 && meta->findInt32(kKeyIsPrimaryImage, &isPrimary) && isPrimary)
+                    || (index == imageCount++)) {
+                break;
             }
         }
-        if (overrideMeta == NULL) {
-            overrideMeta = trackMeta;
-        }
     }
-    int32_t numTiles = gridRows * gridCols;
 
-    sp<AMessage> videoFormat;
-    if (convertMetaDataToMessage(overrideMeta, &videoFormat) != OK) {
-        ALOGE("b/23680780");
-        ALOGW("Failed to convert meta data to message");
+    if (i == n) {
+        ALOGE("image track not found.");
         return NULL;
     }
 
-    // TODO: Use Flexible color instead
-    videoFormat->setInt32("color-format", OMX_COLOR_FormatYUV420Planar);
+    sp<MetaData> trackMeta = mExtractor->getTrackMetaData(i);
 
-    // For the thumbnail extraction case, try to allocate single buffer in both
-    // input and output ports, if seeking to a sync frame. NOTE: This request may
-    // fail if component requires more than that for decoding.
-    bool isSeekingClosest = (seekMode == MediaSource::ReadOptions::SEEK_CLOSEST);
-    bool decodeSingleFrame = !isSeekingClosest && (numTiles == 1);
-    if (decodeSingleFrame) {
-        videoFormat->setInt32("android._num-input-buffers", 1);
-        videoFormat->setInt32("android._num-output-buffers", 1);
-    }
+    sp<IMediaSource> source = mExtractor->getTrack(i);
 
-    status_t err;
-    sp<ALooper> looper = new ALooper;
-    looper->start();
-    sp<MediaCodec> decoder = MediaCodec::CreateByComponentName(
-            looper, componentName, &err);
-
-    if (decoder.get() == NULL || err != OK) {
-        ALOGW("Failed to instantiate decoder [%s]", componentName.c_str());
+    if (source.get() == NULL) {
+        ALOGE("unable to instantiate image track.");
         return NULL;
     }
 
-    err = decoder->configure(videoFormat, NULL /* surface */, NULL /* crypto */, 0 /* flags */);
-    if (err != OK) {
-        ALOGW("configure returned error %d (%s)", err, asString(err));
-        decoder->release();
-        return NULL;
-    }
-
-    err = decoder->start();
-    if (err != OK) {
-        ALOGW("start returned error %d (%s)", err, asString(err));
-        decoder->release();
-        return NULL;
-    }
-
-    err = source->start();
-    if (err != OK) {
-        ALOGW("source failed to start: %d (%s)", err, asString(err));
-        decoder->release();
-        return NULL;
-    }
-
-    Vector<sp<MediaCodecBuffer> > inputBuffers;
-    err = decoder->getInputBuffers(&inputBuffers);
-    if (err != OK) {
-        ALOGW("failed to get input buffers: %d (%s)", err, asString(err));
-        decoder->release();
-        source->stop();
-        return NULL;
-    }
-
-    Vector<sp<MediaCodecBuffer> > outputBuffers;
-    err = decoder->getOutputBuffers(&outputBuffers);
-    if (err != OK) {
-        ALOGW("failed to get output buffers: %d (%s)", err, asString(err));
-        decoder->release();
-        source->stop();
-        return NULL;
-    }
-
-    sp<AMessage> outputFormat = NULL;
-    bool haveMoreInputs = true;
-    size_t index, offset, size;
-    int64_t timeUs;
-    size_t retriesLeft = kRetryCount;
-    bool done = false;
     const char *mime;
-    bool success = format->findCString(kKeyMIMEType, &mime);
-    if (!success) {
-        ALOGE("Could not find mime type");
-        return NULL;
+    CHECK(trackMeta->findCString(kKeyMIMEType, &mime));
+    ALOGV("extracting from %s track", mime);
+    if (!strcasecmp(mime, MEDIA_MIMETYPE_IMAGE_ANDROID_HEIC)) {
+        mime = MEDIA_MIMETYPE_VIDEO_HEVC;
+        trackMeta = new MetaData(*trackMeta);
+        trackMeta->setCString(kKeyMIMEType, mime);
     }
 
-    bool isAvcOrHevc = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)
-            || !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_HEVC);
+    Vector<AString> matchingCodecs;
+    MediaCodecList::findMatchingCodecs(
+            mime,
+            false, /* encoder */
+            MediaCodecList::kPreferSoftwareCodecs,
+            &matchingCodecs);
 
-    bool firstSample = true;
-    int64_t targetTimeUs = -1ll;
+    for (size_t i = 0; i < matchingCodecs.size(); ++i) {
+        const AString &componentName = matchingCodecs[i];
+        ImageDecoder decoder(componentName, trackMeta, source);
+        VideoFrame* frame = decoder.extractFrame(
+                0 /*frameTimeUs*/, 0 /*seekMode*/, colorFormat, metaOnly);
 
-    VideoFrame *frame = NULL;
-    int32_t tilesDecoded = 0;
-
-    do {
-        size_t inputIndex = -1;
-        int64_t ptsUs = 0ll;
-        uint32_t flags = 0;
-        sp<MediaCodecBuffer> codecBuffer = NULL;
-
-        while (haveMoreInputs) {
-            err = decoder->dequeueInputBuffer(&inputIndex, kBufferTimeOutUs);
-            if (err != OK) {
-                ALOGW("Timed out waiting for input");
-                if (retriesLeft) {
-                    err = OK;
-                }
-                break;
-            }
-            codecBuffer = inputBuffers[inputIndex];
-
-            MediaBuffer *mediaBuffer = NULL;
-
-            err = source->read(&mediaBuffer, &options);
-            options.clearSeekTo();
-            if (err != OK) {
-                ALOGW("Input Error or EOS");
-                haveMoreInputs = false;
-                if (err == ERROR_END_OF_STREAM) {
-                    err = OK;
-                }
-                break;
-            }
-            if (firstSample && isSeekingClosest) {
-                mediaBuffer->meta_data()->findInt64(kKeyTargetTime, &targetTimeUs);
-                ALOGV("Seeking closest: targetTimeUs=%lld", (long long)targetTimeUs);
-            }
-            firstSample = false;
-
-            if (mediaBuffer->range_length() > codecBuffer->capacity()) {
-                ALOGE("buffer size (%zu) too large for codec input size (%zu)",
-                        mediaBuffer->range_length(), codecBuffer->capacity());
-                haveMoreInputs = false;
-                err = BAD_VALUE;
-            } else {
-                codecBuffer->setRange(0, mediaBuffer->range_length());
-
-                CHECK(mediaBuffer->meta_data()->findInt64(kKeyTime, &ptsUs));
-                memcpy(codecBuffer->data(),
-                        (const uint8_t*)mediaBuffer->data() + mediaBuffer->range_offset(),
-                        mediaBuffer->range_length());
-            }
-
-            mediaBuffer->release();
-            break;
+        if (frame != NULL) {
+            return frame;
         }
-
-        if (haveMoreInputs && inputIndex < inputBuffers.size()) {
-            if (isAvcOrHevc && IsIDR(codecBuffer) && decodeSingleFrame) {
-                // Only need to decode one IDR frame, unless we're seeking with CLOSEST
-                // option, in which case we need to actually decode to targetTimeUs.
-                haveMoreInputs = false;
-                flags |= MediaCodec::BUFFER_FLAG_EOS;
-            }
-
-            ALOGV("QueueInput: size=%zu ts=%" PRId64 " us flags=%x",
-                    codecBuffer->size(), ptsUs, flags);
-            err = decoder->queueInputBuffer(
-                    inputIndex,
-                    codecBuffer->offset(),
-                    codecBuffer->size(),
-                    ptsUs,
-                    flags);
-
-            // we don't expect an output from codec config buffer
-            if (flags & MediaCodec::BUFFER_FLAG_CODECCONFIG) {
-                continue;
-            }
-        }
-
-        while (err == OK) {
-            // wait for a decoded buffer
-            err = decoder->dequeueOutputBuffer(
-                    &index,
-                    &offset,
-                    &size,
-                    &timeUs,
-                    &flags,
-                    kBufferTimeOutUs);
-
-            if (err == INFO_FORMAT_CHANGED) {
-                ALOGV("Received format change");
-                err = decoder->getOutputFormat(&outputFormat);
-            } else if (err == INFO_OUTPUT_BUFFERS_CHANGED) {
-                ALOGV("Output buffers changed");
-                err = decoder->getOutputBuffers(&outputBuffers);
-            } else {
-                if (err == -EAGAIN /* INFO_TRY_AGAIN_LATER */ && --retriesLeft > 0) {
-                    ALOGV("Timed-out waiting for output.. retries left = %zu", retriesLeft);
-                    err = OK;
-                } else if (err == OK) {
-                    // If we're seeking with CLOSEST option and obtained a valid targetTimeUs
-                    // from the extractor, decode to the specified frame. Otherwise we're done.
-                    ALOGV("Received an output buffer, timeUs=%lld", (long long)timeUs);
-                    sp<MediaCodecBuffer> videoFrameBuffer = outputBuffers.itemAt(index);
-
-                    int32_t width, height;
-                    CHECK(outputFormat != NULL);
-                    CHECK(outputFormat->findInt32("width", &width));
-                    CHECK(outputFormat->findInt32("height", &height));
-
-                    int32_t crop_left, crop_top, crop_right, crop_bottom;
-                    if (!outputFormat->findRect("crop", &crop_left, &crop_top, &crop_right, &crop_bottom)) {
-                        crop_left = crop_top = 0;
-                        crop_right = width - 1;
-                        crop_bottom = height - 1;
-                    }
-
-                    if (frame == NULL) {
-                        frame = allocVideoFrame(
-                                trackMeta,
-                                (crop_right - crop_left + 1) * gridCols,
-                                (crop_bottom - crop_top + 1) * gridRows,
-                                dstBpp,
-                                false /*metaOnly*/);
-                    }
-
-                    int32_t srcFormat;
-                    CHECK(outputFormat->findInt32("color-format", &srcFormat));
-
-                    ColorConverter converter((OMX_COLOR_FORMATTYPE)srcFormat, dstFormat);
-
-                    int32_t dstLeft, dstTop, dstRight, dstBottom;
-                    if (numTiles == 1) {
-                        dstLeft = crop_left;
-                        dstTop = crop_top;
-                        dstRight = crop_right;
-                        dstBottom = crop_bottom;
-                    } else {
-                        dstLeft = tilesDecoded % gridCols * width;
-                        dstTop = tilesDecoded / gridCols * height;
-                        dstRight = dstLeft + width - 1;
-                        dstBottom = dstTop + height - 1;
-                    }
-
-                    if (converter.isValid()) {
-                        err = converter.convert(
-                                (const uint8_t *)videoFrameBuffer->data(),
-                                width, height,
-                                crop_left, crop_top, crop_right, crop_bottom,
-                                frame->mData,
-                                frame->mWidth,
-                                frame->mHeight,
-                                dstLeft, dstTop, dstRight, dstBottom);
-                    } else {
-                        ALOGE("Unable to convert from format 0x%08x to 0x%08x",
-                                srcFormat, dstFormat);
-
-                        err = ERROR_UNSUPPORTED;
-                    }
-
-                    done = (targetTimeUs < 0ll) || (timeUs >= targetTimeUs);
-                    if (numTiles > 1) {
-                        tilesDecoded++;
-                        done &= (tilesDecoded >= numTiles);
-                    }
-                    err = decoder->releaseOutputBuffer(index);
-                } else {
-                    ALOGW("Received error %d (%s) instead of output", err, asString(err));
-                    done = true;
-                }
-                break;
-            }
-        }
-    } while (err == OK && !done);
-
-    source->stop();
-    decoder->release();
-
-    if (err != OK) {
-        ALOGE("failed to get video frame (err %d)", err);
-        delete frame;
-        frame = NULL;
+        ALOGV("%s failed to extract thumbnail, trying next decoder.", componentName.c_str());
     }
 
-    return frame;
+    return NULL;
 }
 
-VideoFrame *StagefrightMetadataRetriever::getFrameAtTime(
+VideoFrame* StagefrightMetadataRetriever::getFrameAtTime(
         int64_t timeUs, int option, int colorFormat, bool metaOnly) {
-
     ALOGV("getFrameAtTime: %" PRId64 " us option: %d colorFormat: %d, metaOnly: %d",
             timeUs, option, colorFormat, metaOnly);
 
+    VideoFrame *frame;
+    status_t err = getFrameInternal(
+            timeUs, 1, option, colorFormat, metaOnly, &frame, NULL /*outFrames*/);
+    return (err == OK) ? frame : NULL;
+}
+
+status_t StagefrightMetadataRetriever::getFrameAtIndex(
+        std::vector<VideoFrame*>* frames,
+        int frameIndex, int numFrames, int colorFormat, bool metaOnly) {
+    ALOGV("getFrameAtIndex: frameIndex %d, numFrames %d, colorFormat: %d, metaOnly: %d",
+            frameIndex, numFrames, colorFormat, metaOnly);
+
+    return getFrameInternal(
+            frameIndex, numFrames, MediaSource::ReadOptions::SEEK_FRAME_INDEX,
+            colorFormat, metaOnly, NULL /*outFrame*/, frames);
+}
+
+status_t StagefrightMetadataRetriever::getFrameInternal(
+        int64_t timeUs, int numFrames, int option, int colorFormat, bool metaOnly,
+        VideoFrame **outFrame, std::vector<VideoFrame*>* outFrames) {
     if (mExtractor.get() == NULL) {
-        ALOGV("no extractor.");
-        return NULL;
+        ALOGE("no extractor.");
+        return NO_INIT;
     }
 
     sp<MetaData> fileMeta = mExtractor->getMetaData();
 
     if (fileMeta == NULL) {
-        ALOGV("extractor doesn't publish metadata, failed to initialize?");
-        return NULL;
+        ALOGE("extractor doesn't publish metadata, failed to initialize?");
+        return NO_INIT;
     }
 
     int32_t drm = 0;
     if (fileMeta->findInt32(kKeyIsDRM, &drm) && drm != 0) {
         ALOGE("frame grab not allowed.");
-        return NULL;
+        return ERROR_DRM_UNKNOWN;
     }
 
     size_t n = mExtractor->countTracks();
@@ -622,8 +263,8 @@
     }
 
     if (i == n) {
-        ALOGV("no video track found.");
-        return NULL;
+        ALOGE("no video track found.");
+        return INVALID_OPERATION;
     }
 
     sp<MetaData> trackMeta = mExtractor->getTrackMetaData(
@@ -633,7 +274,7 @@
 
     if (source.get() == NULL) {
         ALOGV("unable to instantiate video track.");
-        return NULL;
+        return UNKNOWN_ERROR;
     }
 
     const void *data;
@@ -656,16 +297,25 @@
 
     for (size_t i = 0; i < matchingCodecs.size(); ++i) {
         const AString &componentName = matchingCodecs[i];
-        VideoFrame *frame = extractVideoFrame(
-                componentName, trackMeta, source, timeUs, option, colorFormat, metaOnly);
-
-        if (frame != NULL) {
-            return frame;
+        VideoFrameDecoder decoder(componentName, trackMeta, source);
+        if (outFrame != NULL) {
+            *outFrame = decoder.extractFrame(
+                    timeUs, option, colorFormat, metaOnly);
+            if (*outFrame != NULL) {
+                return OK;
+            }
+        } else if (outFrames != NULL) {
+            status_t err = decoder.extractFrames(
+                    timeUs, numFrames, option, colorFormat, outFrames);
+            if (err == OK) {
+                return OK;
+            }
         }
-        ALOGV("%s failed to extract thumbnail, trying next decoder.", componentName.c_str());
+        ALOGV("%s failed to extract frame, trying next decoder.", componentName.c_str());
     }
 
-    return NULL;
+    ALOGE("all codecs failed to extract frame.");
+    return UNKNOWN_ERROR;
 }
 
 MediaAlbumArt *StagefrightMetadataRetriever::extractAlbumArt() {
@@ -797,8 +447,14 @@
     bool hasVideo = false;
     int32_t videoWidth = -1;
     int32_t videoHeight = -1;
+    int32_t videoFrameCount = 0;
     int32_t audioBitrate = -1;
     int32_t rotationAngle = -1;
+    int32_t imageCount = 0;
+    int32_t imagePrimary = 0;
+    int32_t imageWidth = -1;
+    int32_t imageHeight = -1;
+    int32_t imageRotation = -1;
 
     // The overall duration is the duration of the longest track.
     int64_t maxDurationUs = 0;
@@ -829,6 +485,20 @@
                 if (!trackMeta->findInt32(kKeyRotation, &rotationAngle)) {
                     rotationAngle = 0;
                 }
+                if (!trackMeta->findInt32(kKeyFrameCount, &videoFrameCount)) {
+                    videoFrameCount = 0;
+                }
+            } else if (!strncasecmp("image/", mime, 6)) {
+                int32_t isPrimary;
+                if (trackMeta->findInt32(kKeyIsPrimaryImage, &isPrimary) && isPrimary) {
+                    imagePrimary = imageCount;
+                    CHECK(trackMeta->findInt32(kKeyWidth, &imageWidth));
+                    CHECK(trackMeta->findInt32(kKeyHeight, &imageHeight));
+                    if (!trackMeta->findInt32(kKeyRotation, &imageRotation)) {
+                        imageRotation = 0;
+                    }
+                }
+                imageCount++;
             } else if (!strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP)) {
                 const char *lang;
                 if (trackMeta->findCString(kKeyMediaLanguage, &lang)) {
@@ -867,6 +537,30 @@
 
         sprintf(tmp, "%d", rotationAngle);
         mMetaData.add(METADATA_KEY_VIDEO_ROTATION, String8(tmp));
+
+        if (videoFrameCount > 0) {
+            sprintf(tmp, "%d", videoFrameCount);
+            mMetaData.add(METADATA_KEY_VIDEO_FRAME_COUNT, String8(tmp));
+        }
+    }
+
+    if (imageCount > 0) {
+        mMetaData.add(METADATA_KEY_HAS_IMAGE, String8("yes"));
+
+        sprintf(tmp, "%d", imageCount);
+        mMetaData.add(METADATA_KEY_IMAGE_COUNT, String8(tmp));
+
+        sprintf(tmp, "%d", imagePrimary);
+        mMetaData.add(METADATA_KEY_IMAGE_PRIMARY, String8(tmp));
+
+        sprintf(tmp, "%d", imageWidth);
+        mMetaData.add(METADATA_KEY_IMAGE_WIDTH, String8(tmp));
+
+        sprintf(tmp, "%d", imageHeight);
+        mMetaData.add(METADATA_KEY_IMAGE_HEIGHT, String8(tmp));
+
+        sprintf(tmp, "%d", imageRotation);
+        mMetaData.add(METADATA_KEY_IMAGE_ROTATION, String8(tmp));
     }
 
     if (numTracks == 1 && hasAudio && audioBitrate >= 0) {
diff --git a/media/libstagefright/Utils.cpp b/media/libstagefright/Utils.cpp
index bd80e45..6e77f15 100644
--- a/media/libstagefright/Utils.cpp
+++ b/media/libstagefright/Utils.cpp
@@ -639,7 +639,8 @@
         msg->setString("language", lang);
     }
 
-    if (!strncasecmp("video/", mime, 6)) {
+    if (!strncasecmp("video/", mime, 6) ||
+            !strncasecmp("image/", mime, 6)) {
         int32_t width, height;
         if (!meta->findInt32(kKeyWidth, &width)
                 || !meta->findInt32(kKeyHeight, &height)) {
@@ -663,6 +664,19 @@
             msg->setInt32("sar-height", sarHeight);
         }
 
+        if (!strncasecmp("image/", mime, 6)) {
+            int32_t gridWidth, gridHeight, gridRows, gridCols;
+            if (meta->findInt32(kKeyGridWidth, &gridWidth)
+                    && meta->findInt32(kKeyHeight, &gridHeight)
+                    && meta->findInt32(kKeyGridRows, &gridRows)
+                    && meta->findInt32(kKeyGridCols, &gridCols)) {
+                msg->setInt32("grid-width", gridWidth);
+                msg->setInt32("grid-height", gridHeight);
+                msg->setInt32("grid-rows", gridRows);
+                msg->setInt32("grid-cols", gridCols);
+            }
+        }
+
         int32_t colorFormat;
         if (meta->findInt32(kKeyColorFormat, &colorFormat)) {
             msg->setInt32("color-format", colorFormat);
diff --git a/media/libstagefright/codec2/include/C2Component.h b/media/libstagefright/codec2/include/C2Component.h
index f536132..a9b1702 100644
--- a/media/libstagefright/codec2/include/C2Component.h
+++ b/media/libstagefright/codec2/include/C2Component.h
@@ -518,15 +518,20 @@
 public:
     // TBD
 
-    enum Type {
-        LINEAR,     ///< basic linear allocator type
-        GRALLOC,    ///< basic gralloc allocator type
+    typedef uint32_t ID;
+
+    enum ID_ : uint32_t {
+        DEFAULT_LINEAR,     ///< basic linear allocator type
+        DEFAULT_GRAPHIC,    ///< basic graphic allocator type
+        PLATFORM_START = 0x10,
+        VENDOR_START   = 0x100,
     };
 
     /**
      * Creates an allocator.
      *
-     * \param type      the type of allocator to create
+     * \param id      the ID of the allocator to create. This is defined by the store, but
+     *                the ID of the default linear and graphic allocators is formalized.
      * \param allocator shared pointer where the created allocator is stored. Cleared on failure
      *                  and updated on success.
      *
@@ -537,7 +542,7 @@
      * \retval C2_NOT_FOUND no such allocator
      * \retval C2_NO_MEMORY not enough memory to create the allocator
      */
-    virtual status_t createAllocator(Type type, std::shared_ptr<C2Allocator>* const allocator) = 0;
+    virtual status_t createAllocator(ID id, std::shared_ptr<C2Allocator>* const allocator) = 0;
 
     virtual ~C2AllocatorStore() = default;
 };
@@ -612,16 +617,16 @@
      *
      * \note Parameter values do not depend on the order of query.
      *
-     * This method MUST be "non-blocking" and return within 1ms.
+     * This method may be momentarily blocking, but MUST return within 5ms.
      *
-     * \param stackParams     a list of params queried. These are initialized specific to each
+     * \param stackParams   a list of params queried. These are initialized specific to each
      *                      setting; e.g. size and index are set and rest of the members are
      *                      cleared.
      *                      NOTE: Flexible settings that are of incorrect size will be invalidated.
      * \param heapParamIndices a vector of param indices for params to be queried and returned on the
      *                      heap. These parameters will be returned in heapParams. Unsupported param
      *                      indices will be ignored.
-     * \param heapParams      a list of params where to which the supported heap parameters will be
+     * \param heapParams    a list of params where to which the supported heap parameters will be
      *                      appended in the order they appear in heapParamIndices.
      *
      * \retval C2_OK        all parameters could be queried
@@ -631,10 +636,10 @@
      * \retval C2_CORRUPTED some unknown error prevented the querying of the parameters
      *                      (unexpected)
      */
-    virtual status_t query_nb(
+    virtual status_t query_sm(
         const std::vector<C2Param* const> &stackParams,
         const std::vector<C2Param::Index> &heapParamIndices,
-        std::vector<std::unique_ptr<C2Param>>* const heapParams) = 0;
+        std::vector<std::unique_ptr<C2Param>>* const heapParams) const = 0;
 
     /**
      * Sets a set of system-wide parameters.
diff --git a/media/libstagefright/codec2/include/C2Param.h b/media/libstagefright/codec2/include/C2Param.h
index 7d0155a..753c665 100644
--- a/media/libstagefright/codec2/include/C2Param.h
+++ b/media/libstagefright/codec2/include/C2Param.h
@@ -933,6 +933,7 @@
     enum : uint32_t { baseIndex = kParamIndex##name | C2Param::BaseIndex::_kFlexibleFlag }; \
     DEFINE_C2STRUCT_NO_BASE(name)
 
+#ifdef __C2_GENERATE_GLOBAL_VARS__
 /// \ingroup internal
 /// Describe a structure of a templated structure.
 #define DESCRIBE_TEMPLATED_C2STRUCT(strukt, list) \
@@ -943,6 +944,12 @@
 /// Describe the fields of a structure using an initializer list.
 #define DESCRIBE_C2STRUCT(name, list) \
     const std::initializer_list<const C2FieldDescriptor> C2##name##Struct::fieldList = list;
+#else
+/// \if 0
+#define DESCRIBE_TEMPLATED_C2STRUCT(strukt, list)
+#define DESCRIBE_C2STRUCT(name, list)
+/// \endif
+#endif
 
 /**
  * Describe a field of a structure.
@@ -1022,6 +1029,7 @@
  *  ~~~~~~~~~~~~~
  *
  */
+#ifdef __C2_GENERATE_GLOBAL_VARS__
 #define C2FIELD(member, name) \
   C2FieldDescriptor(&((_type*)(nullptr))->member, name),
 
@@ -1032,7 +1040,7 @@
 /// Define a structure with matching baseIndex and start describing its fields.
 /// This must be at the end of the structure definition.
 #define DEFINE_AND_DESCRIBE_C2STRUCT(name) \
-    DEFINE_C2STRUCT(name) }  C2_PACK; \
+    DEFINE_C2STRUCT(name) } C2_PACK; \
     const std::initializer_list<const C2FieldDescriptor> C2##name##Struct::fieldList = {
 
 /// Define a flexible structure with matching baseIndex and start describing its fields.
@@ -1040,6 +1048,24 @@
 #define DEFINE_AND_DESCRIBE_FLEX_C2STRUCT(name, flexMember) \
     DEFINE_FLEX_C2STRUCT(name, flexMember) } C2_PACK; \
     const std::initializer_list<const C2FieldDescriptor> C2##name##Struct::fieldList = {
+#else
+/// \if 0
+/* Alternate declaration of field definitions in case no field list is to be generated.
+   TRICKY: use namespace declaration to handle closing bracket that is normally after
+   these macros. */
+#define C2FIELD(member, name)
+/// \deprecated
+#define C2SOLE_FIELD(member, name)
+/// Define a structure with matching baseIndex and start describing its fields.
+/// This must be at the end of the structure definition.
+#define DEFINE_AND_DESCRIBE_C2STRUCT(name) \
+    DEFINE_C2STRUCT(name) }  C2_PACK; namespace ignored {
+/// Define a flexible structure with matching baseIndex and start describing its fields.
+/// This must be at the end of the structure definition.
+#define DEFINE_AND_DESCRIBE_FLEX_C2STRUCT(name, flexMember) \
+    DEFINE_FLEX_C2STRUCT(name, flexMember) } C2_PACK; namespace ignored {
+/// \endif
+#endif
 
 /**
  * Parameter reflector class.
@@ -1074,48 +1100,6 @@
 };
 
 /**
- * A useable supported values for a field.
- *
- * This can be either a range or a set of values. The range can be linear or geometric with a
- * clear minimum and maximum value, and can have an optional step size or geometric ratio. Values
- * can optionally represent flags.
- *
- * \note Do not use flags to represent bitfields. Use individual values or separate fields instead.
- */
-template<typename T>
-struct C2TypedFieldSupportedValues {
-//public:
-    enum Type {
-        RANGE,      ///< a numeric range that can be continuous or discrete
-        VALUES,     ///< a list of values
-        FLAGS       ///< a list of flags that can be OR-ed
-    };
-
-    Type type;
-
-    struct {
-        T min;
-        T max;
-        T step;
-        T nom;
-        T denom;
-    } range;
-    std::vector<T> values;
-
-    C2TypedFieldSupportedValues(T min, T max, T step = T(std::is_floating_point<T>::value ? 0 : 1))
-        : type(RANGE),
-          range{min, max, step, (T)1, (T)1} { }
-
-    C2TypedFieldSupportedValues(T min, T max, T nom, T den) :
-        type(RANGE),
-        range{min, max, (T)0, nom, den} { }
-
-    C2TypedFieldSupportedValues(bool flags, std::initializer_list<T> list) :
-        type(flags ? FLAGS : VALUES),
-        values(list) {}
-};
-
-/**
  * Generic supported values for a field.
  *
  * This can be either a range or a set of values. The range can be linear or geometric with a
@@ -1164,6 +1148,15 @@
         }
     }
 
+    template<typename T>
+    C2FieldSupportedValues(bool flags, const std::vector<T>& list)
+        : type(flags ? FLAGS : VALUES),
+          range{(T)0, (T)0, (T)0, (T)0, (T)0} {
+        for(T value : list) {
+            values.emplace_back(value);
+        }
+    }
+
     template<typename T, typename E=decltype(C2FieldDescriptor::namedValuesFor(*(T*)0))>
     C2FieldSupportedValues(bool flags, const T*)
         : type(flags ? FLAGS : VALUES),
diff --git a/media/libstagefright/codec2/tests/Android.bp b/media/libstagefright/codec2/tests/Android.bp
index 8a18f7d..cf75061 100644
--- a/media/libstagefright/codec2/tests/Android.bp
+++ b/media/libstagefright/codec2/tests/Android.bp
@@ -1,4 +1,35 @@
 cc_test {
+    name: "codec2_param_test",
+
+    tags: [
+        "tests",
+    ],
+
+    srcs: [
+        "C2Param_test.cpp",
+        "vndk/C2UtilTest.cpp",
+    ],
+
+    include_dirs: [
+        "frameworks/av/media/libstagefright/codec2/include",
+        "frameworks/av/media/libstagefright/codec2/vndk/include",
+    ],
+
+    // param tests must not depend on any codec2 libraries as all params should be templated
+    shared_libs: [
+    ],
+
+    static_libs: [
+    ],
+
+    cflags: [
+        "-Werror",
+        "-Wall",
+        "-std=c++14",
+    ],
+}
+
+cc_test {
     name: "codec2_test",
 
     tags: [
@@ -7,9 +38,7 @@
 
     srcs: [
         "vndk/C2BufferTest.cpp",
-        "vndk/C2UtilTest.cpp",
         "C2_test.cpp",
-        "C2Param_test.cpp",
     ],
 
     include_dirs: [
diff --git a/media/libstagefright/codec2/tests/C2Param_test.cpp b/media/libstagefright/codec2/tests/C2Param_test.cpp
index 9165aad..83f67d5 100644
--- a/media/libstagefright/codec2/tests/C2Param_test.cpp
+++ b/media/libstagefright/codec2/tests/C2Param_test.cpp
@@ -19,6 +19,7 @@
 
 #include <gtest/gtest.h>
 
+#define __C2_GENERATE_GLOBAL_VARS__
 #include <util/C2ParamUtils.h>
 #include <C2ParamDef.h>
 
@@ -2196,36 +2197,6 @@
 
 typedef C2PortParam<C2Tuning, C2VideoConfigStruct> C2VideoConfigPortTuning;
 
-class MyReflector : public C2ParamReflector {
-private:
-    std::unique_ptr<C2VideoConfigPortTuning::input> inputVideoConfigTuning;
-    std::unique_ptr<C2VideoConfigPortTuning::output> outputVideoConfigTuning;
-
-public:
-    void describeSupportedValues() {
-        C2TypedFieldSupportedValues<int32_t> supportedWidths(16, 1920, 8);
-        C2FieldSupportedValues supportedWidths2(16, 1920, 8);
-
-
-        std::list<C2FieldSupportedValues> supported;
-        //supported.emplace_push(inputVideoConfigTuning->mNumber, range(16, 1920, 8));
-        //supported.emplace_push(inputVideoConfigTuning->mHeight, range(16, 1088, 8));
-        //supported.emplace_push(inputVideoConfigTuning->mMetadataType, all_enums);
-        //supported.emplace_push(inputVideoConfigTuning->mSupportedFormats, { 0, 1, 5, 7 });
-    }
-
-    virtual std::unique_ptr<android::C2StructDescriptor> describe(C2Param::BaseIndex paramType) {
-        switch (paramType.baseIndex()) {
-        case C2VideoConfigPortTuning::baseIndex:
-            return std::unique_ptr<C2StructDescriptor>(new C2StructDescriptor{
-                paramType.baseIndex(),
-                C2VideoConfigPortTuning::fieldList,
-            });
-        }
-        return nullptr;
-    }
-};
-
 class MyComponentInstance : public C2ComponentInterface {
 public:
     virtual C2String getName() const {
@@ -2405,9 +2376,9 @@
 template<typename T>
 void dumpFSV(const C2FieldSupportedValues &sv, T*t) {
     using namespace std;
-    cout << (std::is_enum<T>::value ? (std::is_signed<typename std::underlying_type<T>::type>::value ? "i" : "u")
+    cout << (std::is_enum<T>::value ? (std::is_signed<typename lax_underlying_type<T>::type>::value ? "i" : "u")
              : std::is_integral<T>::value ? std::is_signed<T>::value ? "i" : "u" : "f")
-        << (8 * sizeof(T));
+         << (8 * sizeof(T));
     if (sv.type == sv.RANGE) {
         cout << ".range(" << get(sv.range.min, t);
         if (get(sv.range.step, t) != std::is_integral<T>::value) {
@@ -2552,6 +2523,22 @@
     }
 }
 
+TEST_F(C2ParamTest, FieldSupportedValuesTest) {
+    typedef C2GlobalParam<C2Info, C2Uint32Value, 0> Uint32TestInfo;
+    Uint32TestInfo t;
+    std::vector<C2FieldSupportedValues> values;
+    values.push_back(C2FieldSupportedValues(0, 10, 1));  // min, max, step
+    values.push_back(C2FieldSupportedValues(1, 64, 2, 1));  // min, max, nom, den
+    values.push_back(C2FieldSupportedValues(false, {1, 2, 3}));  // flags, std::initializer_list
+    uint32_t val[] = {1, 3, 5, 7};
+    std::vector<uint32_t> v(std::begin(val), std::end(val));
+    values.push_back(C2FieldSupportedValues(false, v));  // flags, std::vector
+
+    for (const C2FieldSupportedValues &sv : values) {
+        dumpFSV(sv, &t.mValue);
+    }
+}
+
 C2ENUM(Enum1, uint32_t,
     Enum1Value1,
     Enum1Value2,
diff --git a/media/libstagefright/codec2/tests/vndk/C2BufferTest.cpp b/media/libstagefright/codec2/tests/vndk/C2BufferTest.cpp
index 18d0841..a185880 100644
--- a/media/libstagefright/codec2/tests/vndk/C2BufferTest.cpp
+++ b/media/libstagefright/codec2/tests/vndk/C2BufferTest.cpp
@@ -16,6 +16,8 @@
 
 #include <gtest/gtest.h>
 
+#include <C2AllocatorIon.h>
+#include <C2AllocatorGralloc.h>
 #include <C2Buffer.h>
 #include <C2BufferPriv.h>
 #include <C2ParamDef.h>
diff --git a/media/libstagefright/codec2/vndk/Android.bp b/media/libstagefright/codec2/vndk/Android.bp
index 916a6a9..64ce5e6 100644
--- a/media/libstagefright/codec2/vndk/Android.bp
+++ b/media/libstagefright/codec2/vndk/Android.bp
@@ -1,7 +1,13 @@
 cc_library_static {
     name: "libstagefright_codec2_vndk",
 
-    srcs: ["C2Buffer.cpp"],
+    srcs: [
+        "C2AllocatorIon.cpp",
+        "C2AllocatorGralloc.cpp",
+        "C2Buffer.cpp",
+        "C2Config.cpp",
+        "C2Store.cpp",
+    ],
 
     include_dirs: [
         "frameworks/av/media/libstagefright/codec2/include",
diff --git a/media/libstagefright/codec2/vndk/C2AllocatorGralloc.cpp b/media/libstagefright/codec2/vndk/C2AllocatorGralloc.cpp
new file mode 100644
index 0000000..baa6637
--- /dev/null
+++ b/media/libstagefright/codec2/vndk/C2AllocatorGralloc.cpp
@@ -0,0 +1,340 @@
+/*
+ * Copyright (C) 2016 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_NDEBUG 0
+#define LOG_TAG "C2AllocatorGralloc"
+#include <utils/Log.h>
+
+#include <android/hardware/graphics/allocator/2.0/IAllocator.h>
+#include <android/hardware/graphics/mapper/2.0/IMapper.h>
+#include <hardware/gralloc.h>
+
+#include <C2AllocatorGralloc.h>
+#include <C2Buffer.h>
+
+namespace android {
+
+using ::android::hardware::graphics::allocator::V2_0::IAllocator;
+using ::android::hardware::graphics::common::V1_0::BufferUsage;
+using ::android::hardware::graphics::common::V1_0::PixelFormat;
+using ::android::hardware::graphics::mapper::V2_0::BufferDescriptor;
+using ::android::hardware::graphics::mapper::V2_0::Error;
+using ::android::hardware::graphics::mapper::V2_0::IMapper;
+using ::android::hardware::graphics::mapper::V2_0::YCbCrLayout;
+using ::android::hardware::hidl_handle;
+using ::android::hardware::hidl_vec;
+
+/* ===================================== GRALLOC ALLOCATION ==================================== */
+static C2Error maperr2error(Error maperr) {
+    switch (maperr) {
+        case Error::NONE:           return C2_OK;
+        case Error::BAD_DESCRIPTOR: return C2_BAD_VALUE;
+        case Error::BAD_BUFFER:     return C2_BAD_VALUE;
+        case Error::BAD_VALUE:      return C2_BAD_VALUE;
+        case Error::NO_RESOURCES:   return C2_NO_MEMORY;
+        case Error::UNSUPPORTED:    return C2_UNSUPPORTED;
+    }
+    return C2_CORRUPTED;
+}
+
+class C2AllocationGralloc : public C2GraphicAllocation {
+public:
+    virtual ~C2AllocationGralloc();
+
+    virtual C2Error map(
+            C2Rect rect, C2MemoryUsage usage, int *fenceFd,
+            C2PlaneLayout *layout /* nonnull */, uint8_t **addr /* nonnull */) override;
+    virtual C2Error unmap(C2Fence *fenceFd /* nullable */) override;
+    virtual bool isValid() const override { return true; }
+    virtual const C2Handle *handle() const override { return mHandle; }
+    virtual bool equals(const std::shared_ptr<const C2GraphicAllocation> &other) const override;
+
+    // internal methods
+    // |handle| will be moved.
+    C2AllocationGralloc(
+              const IMapper::BufferDescriptorInfo &info,
+              const sp<IMapper> &mapper,
+              hidl_handle &handle);
+    int dup() const;
+    C2Error status() const;
+
+private:
+    const IMapper::BufferDescriptorInfo mInfo;
+    const sp<IMapper> mMapper;
+    const hidl_handle mHandle;
+    buffer_handle_t mBuffer;
+    bool mLocked;
+};
+
+C2AllocationGralloc::C2AllocationGralloc(
+          const IMapper::BufferDescriptorInfo &info,
+          const sp<IMapper> &mapper,
+          hidl_handle &handle)
+    : C2GraphicAllocation(info.width, info.height),
+      mInfo(info),
+      mMapper(mapper),
+      mHandle(std::move(handle)),
+      mBuffer(nullptr),
+      mLocked(false) {}
+
+C2AllocationGralloc::~C2AllocationGralloc() {
+    if (!mBuffer) {
+        return;
+    }
+    if (mLocked) {
+        unmap(nullptr);
+    }
+    mMapper->freeBuffer(const_cast<native_handle_t *>(mBuffer));
+}
+
+C2Error C2AllocationGralloc::map(
+        C2Rect rect, C2MemoryUsage usage, int *fenceFd,
+        C2PlaneLayout *layout /* nonnull */, uint8_t **addr /* nonnull */) {
+    // TODO
+    (void) fenceFd;
+    (void) usage;
+
+    if (mBuffer && mLocked) {
+        return C2_DUPLICATE;
+    }
+    if (!layout || !addr) {
+        return C2_BAD_VALUE;
+    }
+
+    C2Error err = C2_OK;
+    if (!mBuffer) {
+        mMapper->importBuffer(
+                mHandle, [&err, this](const auto &maperr, const auto &buffer) {
+                    err = maperr2error(maperr);
+                    if (err == C2_OK) {
+                        mBuffer = static_cast<buffer_handle_t>(buffer);
+                    }
+                });
+        if (err != C2_OK) {
+            return err;
+        }
+    }
+
+    if (mInfo.format == PixelFormat::YCBCR_420_888 || mInfo.format == PixelFormat::YV12) {
+        YCbCrLayout ycbcrLayout;
+        mMapper->lockYCbCr(
+                const_cast<native_handle_t *>(mBuffer),
+                BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN,
+                { (int32_t)rect.mLeft, (int32_t)rect.mTop, (int32_t)rect.mWidth, (int32_t)rect.mHeight },
+                // TODO: fence
+                hidl_handle(),
+                [&err, &ycbcrLayout](const auto &maperr, const auto &mapLayout) {
+                    err = maperr2error(maperr);
+                    if (err == C2_OK) {
+                        ycbcrLayout = mapLayout;
+                    }
+                });
+        if (err != C2_OK) {
+            return err;
+        }
+        addr[C2PlaneLayout::Y] = (uint8_t *)ycbcrLayout.y;
+        addr[C2PlaneLayout::U] = (uint8_t *)ycbcrLayout.cb;
+        addr[C2PlaneLayout::V] = (uint8_t *)ycbcrLayout.cr;
+        layout->mType = C2PlaneLayout::MEDIA_IMAGE_TYPE_YUV;
+        layout->mNumPlanes = 3;
+        layout->mPlanes[C2PlaneLayout::Y] = {
+            C2PlaneInfo::Y,                 // mChannel
+            1,                              // mColInc
+            (int32_t)ycbcrLayout.yStride,   // mRowInc
+            1,                              // mHorizSubsampling
+            1,                              // mVertSubsampling
+            8,                              // mBitDepth
+            8,                              // mAllocatedDepth
+        };
+        layout->mPlanes[C2PlaneLayout::U] = {
+            C2PlaneInfo::Cb,                  // mChannel
+            (int32_t)ycbcrLayout.chromaStep,  // mColInc
+            (int32_t)ycbcrLayout.cStride,     // mRowInc
+            2,                                // mHorizSubsampling
+            2,                                // mVertSubsampling
+            8,                                // mBitDepth
+            8,                                // mAllocatedDepth
+        };
+        layout->mPlanes[C2PlaneLayout::V] = {
+            C2PlaneInfo::Cr,                  // mChannel
+            (int32_t)ycbcrLayout.chromaStep,  // mColInc
+            (int32_t)ycbcrLayout.cStride,     // mRowInc
+            2,                                // mHorizSubsampling
+            2,                                // mVertSubsampling
+            8,                                // mBitDepth
+            8,                                // mAllocatedDepth
+        };
+    } else {
+        void *pointer = nullptr;
+        mMapper->lock(
+                const_cast<native_handle_t *>(mBuffer),
+                BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN,
+                { (int32_t)rect.mLeft, (int32_t)rect.mTop, (int32_t)rect.mWidth, (int32_t)rect.mHeight },
+                // TODO: fence
+                hidl_handle(),
+                [&err, &pointer](const auto &maperr, const auto &mapPointer) {
+                    err = maperr2error(maperr);
+                    if (err == C2_OK) {
+                        pointer = mapPointer;
+                    }
+                });
+        if (err != C2_OK) {
+            return err;
+        }
+        // TODO
+        return C2_UNSUPPORTED;
+    }
+    mLocked = true;
+
+    return C2_OK;
+}
+
+C2Error C2AllocationGralloc::unmap(C2Fence *fenceFd /* nullable */) {
+    // TODO: fence
+    C2Error err = C2_OK;
+    mMapper->unlock(
+            const_cast<native_handle_t *>(mBuffer),
+            [&err, &fenceFd](const auto &maperr, const auto &releaseFence) {
+                // TODO
+                (void) fenceFd;
+                (void) releaseFence;
+                err = maperr2error(maperr);
+                if (err == C2_OK) {
+                    // TODO: fence
+                }
+            });
+    if (err == C2_OK) {
+        mLocked = false;
+    }
+    return err;
+}
+
+bool C2AllocationGralloc::equals(const std::shared_ptr<const C2GraphicAllocation> &other) const {
+    return other && other->handle() == handle();
+}
+
+/* ===================================== GRALLOC ALLOCATOR ==================================== */
+class C2AllocatorGralloc::Impl {
+public:
+    Impl();
+
+    C2Error allocateGraphicBuffer(
+            uint32_t width, uint32_t height, uint32_t format, const C2MemoryUsage &usage,
+            std::shared_ptr<C2GraphicAllocation> *allocation);
+
+    C2Error recreateGraphicBuffer(
+            const C2Handle *handle,
+            std::shared_ptr<C2GraphicAllocation> *allocation);
+
+    C2Error status() const { return mInit; }
+
+private:
+    C2Error mInit;
+    sp<IAllocator> mAllocator;
+    sp<IMapper> mMapper;
+};
+
+C2AllocatorGralloc::Impl::Impl() : mInit(C2_OK) {
+    // TODO: share a global service
+    mAllocator = IAllocator::getService();
+    mMapper = IMapper::getService();
+    if (mAllocator == nullptr || mMapper == nullptr) {
+        mInit = C2_CORRUPTED;
+    }
+}
+
+C2Error C2AllocatorGralloc::Impl::allocateGraphicBuffer(
+        uint32_t width, uint32_t height, uint32_t format, const C2MemoryUsage &usage,
+        std::shared_ptr<C2GraphicAllocation> *allocation) {
+    // TODO: buffer usage should be determined according to |usage|
+    (void) usage;
+
+    IMapper::BufferDescriptorInfo info = {
+        width,
+        height,
+        1u,  // layerCount
+        (PixelFormat)format,
+        BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN,
+    };
+    C2Error err = C2_OK;
+    BufferDescriptor desc;
+    mMapper->createDescriptor(
+            info, [&err, &desc](const auto &maperr, const auto &descriptor) {
+                err = maperr2error(maperr);
+                if (err == C2_OK) {
+                    desc = descriptor;
+                }
+            });
+    if (err != C2_OK) {
+        return err;
+    }
+
+    // IAllocator shares IMapper error codes.
+    hidl_handle buffer;
+    mAllocator->allocate(
+            desc,
+            1u,
+            [&err, &buffer](const auto &maperr, const auto &stride, auto &buffers) {
+                (void) stride;
+                err = maperr2error(maperr);
+                if (err != C2_OK) {
+                    return;
+                }
+                if (buffers.size() != 1u) {
+                    err = C2_CORRUPTED;
+                    return;
+                }
+                buffer = std::move(buffers[0]);
+            });
+    if (err != C2_OK) {
+        return err;
+    }
+
+    allocation->reset(new C2AllocationGralloc(info, mMapper, buffer));
+    return C2_OK;
+}
+
+C2Error C2AllocatorGralloc::Impl::recreateGraphicBuffer(
+        const C2Handle *handle,
+        std::shared_ptr<C2GraphicAllocation> *allocation) {
+    (void) handle;
+
+    // TODO: need to figure out BufferDescriptorInfo from the handle.
+    allocation->reset();
+    return C2_UNSUPPORTED;
+}
+
+C2AllocatorGralloc::C2AllocatorGralloc() : mImpl(new Impl) {}
+
+C2AllocatorGralloc::~C2AllocatorGralloc() { delete mImpl; }
+
+C2Error C2AllocatorGralloc::allocateGraphicBuffer(
+        uint32_t width, uint32_t height, uint32_t format, C2MemoryUsage usage,
+        std::shared_ptr<C2GraphicAllocation> *allocation) {
+    return mImpl->allocateGraphicBuffer(width, height, format, usage, allocation);
+}
+
+C2Error C2AllocatorGralloc::recreateGraphicBuffer(
+        const C2Handle *handle,
+        std::shared_ptr<C2GraphicAllocation> *allocation) {
+    return mImpl->recreateGraphicBuffer(handle, allocation);
+}
+
+C2Error C2AllocatorGralloc::status() const {
+    return mImpl->status();
+}
+
+} // namespace android
diff --git a/media/libstagefright/codec2/vndk/C2AllocatorIon.cpp b/media/libstagefright/codec2/vndk/C2AllocatorIon.cpp
new file mode 100644
index 0000000..7aa7769
--- /dev/null
+++ b/media/libstagefright/codec2/vndk/C2AllocatorIon.cpp
@@ -0,0 +1,344 @@
+/*
+ * Copyright (C) 2016 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_NDEBUG 0
+#define LOG_TAG "C2AllocatorIon"
+#include <utils/Log.h>
+
+#include <ion/ion.h>
+#include <sys/mman.h>
+
+#include <C2AllocatorIon.h>
+#include <C2Buffer.h>
+#include <C2ErrnoUtils.h>
+
+namespace android {
+
+/* ========================================= ION HANDLE ======================================== */
+struct C2HandleIon : public C2Handle {
+    C2HandleIon(int ionFd, ion_user_handle_t buffer) : C2Handle(cHeader),
+          mFds{ ionFd, buffer },
+          mInts{ kMagic } { }
+
+    static bool isValid(const C2Handle * const o);
+
+    int ionFd() const { return mFds.mIon; }
+    ion_user_handle_t buffer() const { return mFds.mBuffer; }
+
+    void setBuffer(ion_user_handle_t bufferFd) { mFds.mBuffer = bufferFd; }
+
+protected:
+    struct {
+        int mIon;
+        int mBuffer; // ion_user_handle_t
+    } mFds;
+    struct {
+        int mMagic;
+    } mInts;
+
+private:
+    typedef C2HandleIon _type;
+    enum {
+        kMagic = 'ion1',
+        numFds = sizeof(mFds) / sizeof(int),
+        numInts = sizeof(mInts) / sizeof(int),
+        version = sizeof(C2Handle) + sizeof(mFds) + sizeof(mInts)
+    };
+    //constexpr static C2Handle cHeader = { version, numFds, numInts, {} };
+    const static C2Handle cHeader;
+};
+
+const C2Handle C2HandleIon::cHeader = {
+    C2HandleIon::version,
+    C2HandleIon::numFds,
+    C2HandleIon::numInts,
+    {}
+};
+
+// static
+bool C2HandleIon::isValid(const C2Handle * const o) {
+    if (!o || memcmp(o, &cHeader, sizeof(cHeader))) {
+        return false;
+    }
+    const C2HandleIon *other = static_cast<const C2HandleIon*>(o);
+    return other->mInts.mMagic == kMagic;
+}
+
+// TODO: is the dup of an ion fd identical to ion_share?
+
+/* ======================================= ION ALLOCATION ====================================== */
+class C2AllocationIon : public C2LinearAllocation {
+public:
+    virtual C2Error map(
+        size_t offset, size_t size, C2MemoryUsage usage, int *fence,
+        void **addr /* nonnull */);
+    virtual C2Error unmap(void *addr, size_t size, int *fenceFd);
+    virtual bool isValid() const;
+    virtual ~C2AllocationIon();
+    virtual const C2Handle *handle() const;
+    virtual bool equals(const std::shared_ptr<C2LinearAllocation> &other) const;
+
+    // internal methods
+    C2AllocationIon(int ionFd, size_t size, size_t align, unsigned heapMask, unsigned flags);
+    C2AllocationIon(int ionFd, size_t size, int shareFd);
+    int dup() const;
+    C2Error status() const;
+
+protected:
+    class Impl;
+    Impl *mImpl;
+};
+
+class C2AllocationIon::Impl {
+public:
+    // NOTE: using constructor here instead of a factory method as we will need the
+    // error value and this simplifies the error handling by the wrapper.
+    Impl(int ionFd, size_t capacity, size_t align, unsigned heapMask, unsigned flags)
+        : mInit(C2_OK),
+          mHandle(ionFd, -1),
+          mMapFd(-1),
+          mCapacity(capacity) {
+        ion_user_handle_t buffer = -1;
+        int ret = ion_alloc(mHandle.ionFd(), mCapacity, align, heapMask, flags, &buffer);
+        if (ret == 0) {
+            mHandle.setBuffer(buffer);
+        } else {
+            mInit = c2_map_errno<ENOMEM, EACCES, EINVAL>(-ret);
+        }
+    }
+
+    Impl(int ionFd, size_t capacity, int shareFd)
+        : mHandle(ionFd, -1),
+          mMapFd(-1),
+          mCapacity(capacity) {
+        ion_user_handle_t buffer;
+        mInit = ion_import(mHandle.ionFd(), shareFd, &buffer);
+        if (mInit == 0) {
+            mHandle.setBuffer(buffer);
+        }
+        (void)mCapacity; // TODO
+    }
+
+    C2Error map(size_t offset, size_t size, C2MemoryUsage usage, int *fenceFd, void **addr) {
+        (void)fenceFd; // TODO: wait for fence
+        *addr = nullptr;
+        int prot = PROT_NONE;
+        int flags = MAP_PRIVATE;
+        if (usage.mConsumer & GRALLOC_USAGE_SW_READ_MASK) {
+            prot |= PROT_READ;
+        }
+        if (usage.mProducer & GRALLOC_USAGE_SW_WRITE_MASK) {
+            prot |= PROT_WRITE;
+            flags = MAP_SHARED;
+        }
+
+        size_t alignmentBytes = offset % PAGE_SIZE;
+        size_t mapOffset = offset - alignmentBytes;
+        size_t mapSize = size + alignmentBytes;
+
+        C2Error err = C2_OK;
+        if (mMapFd == -1) {
+            int ret = ion_map(mHandle.ionFd(), mHandle.buffer(), mapSize, prot,
+                              flags, mapOffset, (unsigned char**)&mMapAddr, &mMapFd);
+            if (ret) {
+                mMapFd = -1;
+                *addr = nullptr;
+                err = c2_map_errno<EINVAL>(-ret);
+            } else {
+                *addr = (uint8_t *)mMapAddr + alignmentBytes;
+                mMapAlignmentBytes = alignmentBytes;
+                mMapSize = mapSize;
+            }
+        } else {
+            mMapAddr = mmap(nullptr, mapSize, prot, flags, mMapFd, mapOffset);
+            if (mMapAddr == MAP_FAILED) {
+                mMapAddr = *addr = nullptr;
+                err = c2_map_errno<EINVAL>(errno);
+            } else {
+                *addr = (uint8_t *)mMapAddr + alignmentBytes;
+                mMapAlignmentBytes = alignmentBytes;
+                mMapSize = mapSize;
+            }
+        }
+        return err;
+    }
+
+    C2Error unmap(void *addr, size_t size, int *fenceFd) {
+        if (addr != (uint8_t *)mMapAddr + mMapAlignmentBytes ||
+                size + mMapAlignmentBytes != mMapSize) {
+            return C2_BAD_VALUE;
+        }
+        int err = munmap(mMapAddr, mMapSize);
+        if (err != 0) {
+            return c2_map_errno<EINVAL>(errno);
+        }
+        if (fenceFd) {
+            *fenceFd = -1;
+        }
+        return C2_OK;
+    }
+
+    ~Impl() {
+        if (mMapFd != -1) {
+            close(mMapFd);
+            mMapFd = -1;
+        }
+
+        (void)ion_free(mHandle.ionFd(), mHandle.buffer());
+    }
+
+    C2Error status() const {
+        return mInit;
+    }
+
+    const C2Handle * handle() const {
+        return &mHandle;
+    }
+
+    int dup() const {
+        int fd = -1;
+        if (mInit != 0 || ion_share(mHandle.ionFd(), mHandle.buffer(), &fd) != 0) {
+            fd = -1;
+        }
+        return fd;
+    }
+
+private:
+    C2Error mInit;
+    C2HandleIon mHandle;
+    int mMapFd; // only one for now
+    void *mMapAddr;
+    size_t mMapAlignmentBytes;
+    size_t mMapSize;
+    size_t mCapacity;
+};
+
+C2Error C2AllocationIon::map(
+    size_t offset, size_t size, C2MemoryUsage usage, int *fenceFd, void **addr) {
+    return mImpl->map(offset, size, usage, fenceFd, addr);
+}
+
+C2Error C2AllocationIon::unmap(void *addr, size_t size, int *fenceFd) {
+    return mImpl->unmap(addr, size, fenceFd);
+}
+
+bool C2AllocationIon::isValid() const {
+    return mImpl->status() == C2_OK;
+}
+
+C2Error C2AllocationIon::status() const {
+    return mImpl->status();
+}
+
+bool C2AllocationIon::equals(const std::shared_ptr<C2LinearAllocation> &other) const {
+    return other != nullptr &&
+        other->handle(); // TODO
+}
+
+const C2Handle *C2AllocationIon::handle() const {
+    return mImpl->handle();
+}
+
+C2AllocationIon::~C2AllocationIon() {
+    delete mImpl;
+}
+
+C2AllocationIon::C2AllocationIon(int ionFd, size_t size, size_t align, unsigned heapMask, unsigned flags)
+    : C2LinearAllocation(size),
+      mImpl(new Impl(ionFd, size, align, heapMask, flags)) { }
+
+C2AllocationIon::C2AllocationIon(int ionFd, size_t size, int shareFd)
+    : C2LinearAllocation(size),
+      mImpl(new Impl(ionFd, size, shareFd)) { }
+
+int C2AllocationIon::dup() const {
+    return mImpl->dup();
+}
+
+/* ======================================= ION ALLOCATOR ====================================== */
+C2AllocatorIon::C2AllocatorIon() : mInit(C2_OK), mIonFd(ion_open()) {
+    if (mIonFd < 0) {
+        switch (errno) {
+        case ENOENT:    mInit = C2_UNSUPPORTED; break;
+        default:        mInit = c2_map_errno<EACCES>(errno); break;
+        }
+    }
+}
+
+C2AllocatorIon::~C2AllocatorIon() {
+    if (mInit == C2_OK) {
+        ion_close(mIonFd);
+    }
+}
+
+C2Error C2AllocatorIon::allocateLinearBuffer(
+        uint32_t capacity, C2MemoryUsage usage, std::shared_ptr<C2LinearAllocation> *allocation) {
+    if (allocation == nullptr) {
+        return C2_BAD_VALUE;
+    }
+
+    allocation->reset();
+    if (mInit != C2_OK) {
+        return C2_UNSUPPORTED;
+    }
+
+    // get align, heapMask and flags
+    //size_t align = 1;
+    size_t align = 0;
+    unsigned heapMask = ~0;
+    unsigned flags = 0;
+    //TODO
+    (void) usage;
+#if 0
+    int err = mUsageMapper(usage, capacity, &align, &heapMask, &flags);
+    if (err < 0) {
+        return c2_map_errno<EINVAL, ENOMEM, EACCES>(-err);
+    }
+#endif
+
+    std::shared_ptr<C2AllocationIon> alloc
+        = std::make_shared<C2AllocationIon>(mIonFd, capacity, align, heapMask, flags);
+    C2Error ret = alloc->status();
+    if (ret == C2_OK) {
+        *allocation = alloc;
+    }
+    return ret;
+}
+
+C2Error C2AllocatorIon::recreateLinearBuffer(
+        const C2Handle *handle, std::shared_ptr<C2LinearAllocation> *allocation) {
+    *allocation = nullptr;
+    if (mInit != C2_OK) {
+        return C2_UNSUPPORTED;
+    }
+
+    if (!C2HandleIon::isValid(handle)) {
+        return C2_BAD_VALUE;
+    }
+
+    // TODO: get capacity and validate it
+    const C2HandleIon *h = static_cast<const C2HandleIon*>(handle);
+    std::shared_ptr<C2AllocationIon> alloc
+        = std::make_shared<C2AllocationIon>(mIonFd, 0 /* capacity */, h->buffer());
+    C2Error ret = alloc->status();
+    if (ret == C2_OK) {
+        *allocation = alloc;
+    }
+    return ret;
+}
+
+} // namespace android
+
diff --git a/media/libstagefright/codec2/vndk/C2Buffer.cpp b/media/libstagefright/codec2/vndk/C2Buffer.cpp
index 92ccfd1..1ffbf49 100644
--- a/media/libstagefright/codec2/vndk/C2Buffer.cpp
+++ b/media/libstagefright/codec2/vndk/C2Buffer.cpp
@@ -18,57 +18,12 @@
 #define LOG_TAG "C2Buffer"
 #include <utils/Log.h>
 
+#include <map>
+
 #include <C2BufferPriv.h>
 
-#include <android/hardware/graphics/allocator/2.0/IAllocator.h>
-#include <android/hardware/graphics/mapper/2.0/IMapper.h>
-
-#include <ion/ion.h>
-#include <hardware/gralloc.h>
-#include <sys/mman.h>
-
 namespace android {
 
-using ::android::hardware::graphics::allocator::V2_0::IAllocator;
-using ::android::hardware::graphics::common::V1_0::BufferUsage;
-using ::android::hardware::graphics::common::V1_0::PixelFormat;
-using ::android::hardware::graphics::mapper::V2_0::BufferDescriptor;
-using ::android::hardware::graphics::mapper::V2_0::Error;
-using ::android::hardware::graphics::mapper::V2_0::IMapper;
-using ::android::hardware::graphics::mapper::V2_0::YCbCrLayout;
-using ::android::hardware::hidl_handle;
-using ::android::hardware::hidl_vec;
-
-// standard ERRNO mappings
-template<int N> constexpr C2Error _c2_errno2error_impl();
-template<> constexpr C2Error _c2_errno2error_impl<0>()       { return C2_OK; }
-template<> constexpr C2Error _c2_errno2error_impl<EINVAL>()  { return C2_BAD_VALUE; }
-template<> constexpr C2Error _c2_errno2error_impl<EACCES>()  { return C2_NO_PERMISSION; }
-template<> constexpr C2Error _c2_errno2error_impl<EPERM>()   { return C2_NO_PERMISSION; }
-template<> constexpr C2Error _c2_errno2error_impl<ENOMEM>()  { return C2_NO_MEMORY; }
-
-// map standard errno-s to the equivalent C2Error
-template<int... N> struct _c2_map_errno_impl;
-template<int E, int ... N> struct _c2_map_errno_impl<E, N...> {
-    static C2Error map(int result) {
-        if (result == E) {
-            return _c2_errno2error_impl<E>();
-        } else {
-            return _c2_map_errno_impl<N...>::map(result);
-        }
-    }
-};
-template<> struct _c2_map_errno_impl<> {
-    static C2Error map(int result) {
-        return result == 0 ? C2_OK : C2_CORRUPTED;
-    }
-};
-
-template<int... N>
-C2Error c2_map_errno(int result) {
-    return _c2_map_errno_impl<N...>::map(result);
-}
-
 namespace {
 
 // Inherit from the parent, share with the friend.
@@ -142,357 +97,6 @@
 
 }  // namespace
 
-/* ======================================= ION ALLOCATION ====================================== */
-
-/**
- * ION handle
- */
-struct C2HandleIon : public C2Handle {
-    C2HandleIon(int ionFd, ion_user_handle_t buffer) : C2Handle(cHeader),
-          mFds{ ionFd, buffer },
-          mInts{ kMagic } { }
-
-    static bool isValid(const C2Handle * const o);
-
-    int ionFd() const { return mFds.mIon; }
-    ion_user_handle_t buffer() const { return mFds.mBuffer; }
-
-    void setBuffer(ion_user_handle_t bufferFd) { mFds.mBuffer = bufferFd; }
-
-protected:
-    struct {
-        int mIon;
-        int mBuffer; // ion_user_handle_t
-    } mFds;
-    struct {
-        int mMagic;
-    } mInts;
-
-private:
-    typedef C2HandleIon _type;
-    enum {
-        kMagic = 'ion1',
-        numFds = sizeof(mFds) / sizeof(int),
-        numInts = sizeof(mInts) / sizeof(int),
-        version = sizeof(C2Handle) + sizeof(mFds) + sizeof(mInts)
-    };
-    //constexpr static C2Handle cHeader = { version, numFds, numInts, {} };
-    const static C2Handle cHeader;
-};
-
-const C2Handle C2HandleIon::cHeader = {
-    C2HandleIon::version,
-    C2HandleIon::numFds,
-    C2HandleIon::numInts,
-    {}
-};
-
-// static
-bool C2HandleIon::isValid(const C2Handle * const o) {
-    if (!o || memcmp(o, &cHeader, sizeof(cHeader))) {
-        return false;
-    }
-    const C2HandleIon *other = static_cast<const C2HandleIon*>(o);
-    return other->mInts.mMagic == kMagic;
-}
-
-// TODO: is the dup of an ion fd identical to ion_share?
-
-class C2AllocationIon : public C2LinearAllocation {
-public:
-    virtual C2Error map(
-        size_t offset, size_t size, C2MemoryUsage usage, int *fence,
-        void **addr /* nonnull */);
-    virtual C2Error unmap(void *addr, size_t size, int *fenceFd);
-    virtual bool isValid() const;
-    virtual ~C2AllocationIon();
-    virtual const C2Handle *handle() const;
-    virtual bool equals(const std::shared_ptr<C2LinearAllocation> &other) const;
-
-    // internal methods
-    C2AllocationIon(int ionFd, size_t size, size_t align, unsigned heapMask, unsigned flags);
-    C2AllocationIon(int ionFd, size_t size, int shareFd);
-    int dup() const;
-    C2Error status() const;
-
-protected:
-    class Impl;
-    Impl *mImpl;
-};
-
-class C2AllocationIon::Impl {
-public:
-    // NOTE: using constructor here instead of a factory method as we will need the
-    // error value and this simplifies the error handling by the wrapper.
-    Impl(int ionFd, size_t capacity, size_t align, unsigned heapMask, unsigned flags)
-        : mInit(C2_OK),
-          mHandle(ionFd, -1),
-          mMapFd(-1),
-          mCapacity(capacity) {
-        ion_user_handle_t buffer = -1;
-        int ret = ion_alloc(mHandle.ionFd(), mCapacity, align, heapMask, flags, &buffer);
-        if (ret == 0) {
-            mHandle.setBuffer(buffer);
-        } else {
-            mInit = c2_map_errno<ENOMEM, EACCES, EINVAL>(-ret);
-        }
-    }
-
-    Impl(int ionFd, size_t capacity, int shareFd)
-        : mHandle(ionFd, -1),
-          mMapFd(-1),
-          mCapacity(capacity) {
-        ion_user_handle_t buffer;
-        mInit = ion_import(mHandle.ionFd(), shareFd, &buffer);
-        if (mInit == 0) {
-            mHandle.setBuffer(buffer);
-        }
-        (void)mCapacity; // TODO
-    }
-
-    C2Error map(size_t offset, size_t size, C2MemoryUsage usage, int *fenceFd, void **addr) {
-        (void)fenceFd; // TODO: wait for fence
-        *addr = nullptr;
-        int prot = PROT_NONE;
-        int flags = MAP_PRIVATE;
-        if (usage.mConsumer & GRALLOC_USAGE_SW_READ_MASK) {
-            prot |= PROT_READ;
-        }
-        if (usage.mProducer & GRALLOC_USAGE_SW_WRITE_MASK) {
-            prot |= PROT_WRITE;
-            flags = MAP_SHARED;
-        }
-
-        size_t alignmentBytes = offset % PAGE_SIZE;
-        size_t mapOffset = offset - alignmentBytes;
-        size_t mapSize = size + alignmentBytes;
-
-        C2Error err = C2_OK;
-        if (mMapFd == -1) {
-            int ret = ion_map(mHandle.ionFd(), mHandle.buffer(), mapSize, prot,
-                              flags, mapOffset, (unsigned char**)&mMapAddr, &mMapFd);
-            if (ret) {
-                mMapFd = -1;
-                *addr = nullptr;
-                err = c2_map_errno<EINVAL>(-ret);
-            } else {
-                *addr = (uint8_t *)mMapAddr + alignmentBytes;
-                mMapAlignmentBytes = alignmentBytes;
-                mMapSize = mapSize;
-            }
-        } else {
-            mMapAddr = mmap(nullptr, mapSize, prot, flags, mMapFd, mapOffset);
-            if (mMapAddr == MAP_FAILED) {
-                mMapAddr = *addr = nullptr;
-                err = c2_map_errno<EINVAL>(errno);
-            } else {
-                *addr = (uint8_t *)mMapAddr + alignmentBytes;
-                mMapAlignmentBytes = alignmentBytes;
-                mMapSize = mapSize;
-            }
-        }
-        return err;
-    }
-
-    C2Error unmap(void *addr, size_t size, int *fenceFd) {
-        if (addr != (uint8_t *)mMapAddr + mMapAlignmentBytes ||
-                size + mMapAlignmentBytes != mMapSize) {
-            return C2_BAD_VALUE;
-        }
-        int err = munmap(mMapAddr, mMapSize);
-        if (err != 0) {
-            return c2_map_errno<EINVAL>(errno);
-        }
-        if (fenceFd) {
-            *fenceFd = -1;
-        }
-        return C2_OK;
-    }
-
-    ~Impl() {
-        if (mMapFd != -1) {
-            close(mMapFd);
-            mMapFd = -1;
-        }
-
-        (void)ion_free(mHandle.ionFd(), mHandle.buffer());
-    }
-
-    C2Error status() const {
-        return mInit;
-    }
-
-    const C2Handle * handle() const {
-        return &mHandle;
-    }
-
-    int dup() const {
-        int fd = -1;
-        if (mInit != 0 || ion_share(mHandle.ionFd(), mHandle.buffer(), &fd) != 0) {
-            fd = -1;
-        }
-        return fd;
-    }
-
-private:
-    C2Error mInit;
-    C2HandleIon mHandle;
-    int mMapFd; // only one for now
-    void *mMapAddr;
-    size_t mMapAlignmentBytes;
-    size_t mMapSize;
-    size_t mCapacity;
-};
-
-C2Error C2AllocationIon::map(
-    size_t offset, size_t size, C2MemoryUsage usage, int *fenceFd, void **addr) {
-    return mImpl->map(offset, size, usage, fenceFd, addr);
-}
-
-C2Error C2AllocationIon::unmap(void *addr, size_t size, int *fenceFd) {
-    return mImpl->unmap(addr, size, fenceFd);
-}
-
-bool C2AllocationIon::isValid() const {
-    return mImpl->status() == C2_OK;
-}
-
-C2Error C2AllocationIon::status() const {
-    return mImpl->status();
-}
-
-bool C2AllocationIon::equals(const std::shared_ptr<C2LinearAllocation> &other) const {
-    return other != nullptr &&
-        other->handle(); // TODO
-}
-
-const C2Handle *C2AllocationIon::handle() const {
-    return mImpl->handle();
-}
-
-C2AllocationIon::~C2AllocationIon() {
-    delete mImpl;
-}
-
-C2AllocationIon::C2AllocationIon(int ionFd, size_t size, size_t align, unsigned heapMask, unsigned flags)
-    : C2LinearAllocation(size),
-      mImpl(new Impl(ionFd, size, align, heapMask, flags)) { }
-
-C2AllocationIon::C2AllocationIon(int ionFd, size_t size, int shareFd)
-    : C2LinearAllocation(size),
-      mImpl(new Impl(ionFd, size, shareFd)) { }
-
-int C2AllocationIon::dup() const {
-    return mImpl->dup();
-}
-
-/* ======================================= ION ALLOCATOR ====================================== */
-
-C2AllocatorIon::C2AllocatorIon() : mInit(C2_OK), mIonFd(ion_open()) {
-    if (mIonFd < 0) {
-        switch (errno) {
-        case ENOENT:    mInit = C2_UNSUPPORTED; break;
-        default:        mInit = c2_map_errno<EACCES>(errno); break;
-        }
-    }
-}
-
-C2AllocatorIon::~C2AllocatorIon() {
-    if (mInit == C2_OK) {
-        ion_close(mIonFd);
-    }
-}
-
-/**
- * Allocates a 1D allocation of given |capacity| and |usage|. If successful, the allocation is
- * stored in |allocation|. Otherwise, |allocation| is set to 'nullptr'.
- *
- * \param capacity        the size of requested allocation (the allocation could be slightly
- *                      larger, e.g. to account for any system-required alignment)
- * \param usage           the memory usage info for the requested allocation. \note that the
- *                      returned allocation may be later used/mapped with different usage.
- *                      The allocator should layout the buffer to be optimized for this usage,
- *                      but must support any usage. One exception: protected buffers can
- *                      only be used in a protected scenario.
- * \param allocation      pointer to where the allocation shall be stored on success. nullptr
- *                      will be stored here on failure
- *
- * \retval C2_OK        the allocation was successful
- * \retval C2_NO_MEMORY not enough memory to complete the allocation
- * \retval C2_TIMED_OUT the allocation timed out
- * \retval C2_NO_PERMISSION     no permission to complete the allocation
- * \retval C2_BAD_VALUE capacity or usage are not supported (invalid) (caller error)
- * \retval C2_UNSUPPORTED       this allocator does not support 1D allocations
- * \retval C2_CORRUPTED some unknown, unrecoverable error occured during allocation (unexpected)
- */
-C2Error C2AllocatorIon::allocateLinearBuffer(
-        uint32_t capacity, C2MemoryUsage usage, std::shared_ptr<C2LinearAllocation> *allocation) {
-    *allocation = nullptr;
-    if (mInit != C2_OK) {
-        return C2_UNSUPPORTED;
-    }
-
-    // get align, heapMask and flags
-    //size_t align = 1;
-    size_t align = 0;
-    unsigned heapMask = ~0;
-    unsigned flags = 0;
-    //TODO
-    (void) usage;
-#if 0
-    int err = mUsageMapper(usage, capacity, &align, &heapMask, &flags);
-    if (err < 0) {
-        return c2_map_errno<EINVAL, ENOMEM, EACCES>(-err);
-    }
-#endif
-
-    std::shared_ptr<C2AllocationIon> alloc
-        = std::make_shared<C2AllocationIon>(mIonFd, capacity, align, heapMask, flags);
-    C2Error ret = alloc->status();
-    if (ret == C2_OK) {
-        *allocation = alloc;
-    }
-    return ret;
-}
-
-/**
- * (Re)creates a 1D allocation from a native |handle|. If successful, the allocation is stored
- * in |allocation|. Otherwise, |allocation| is set to 'nullptr'.
- *
- * \param handle      the handle for the existing allocation
- * \param allocation  pointer to where the allocation shall be stored on success. nullptr
- *                  will be stored here on failure
- *
- * \retval C2_OK        the allocation was recreated successfully
- * \retval C2_NO_MEMORY not enough memory to recreate the allocation
- * \retval C2_TIMED_OUT the recreation timed out (unexpected)
- * \retval C2_NO_PERMISSION     no permission to recreate the allocation
- * \retval C2_BAD_VALUE invalid handle (caller error)
- * \retval C2_UNSUPPORTED       this allocator does not support 1D allocations
- * \retval C2_CORRUPTED some unknown, unrecoverable error occured during allocation (unexpected)
- */
-C2Error C2AllocatorIon::recreateLinearBuffer(
-        const C2Handle *handle, std::shared_ptr<C2LinearAllocation> *allocation) {
-    *allocation = nullptr;
-    if (mInit != C2_OK) {
-        return C2_UNSUPPORTED;
-    }
-
-    if (!C2HandleIon::isValid(handle)) {
-        return C2_BAD_VALUE;
-    }
-
-    // TODO: get capacity and validate it
-    const C2HandleIon *h = static_cast<const C2HandleIon*>(handle);
-    std::shared_ptr<C2AllocationIon> alloc
-        = std::make_shared<C2AllocationIon>(mIonFd, 0 /* capacity */, h->buffer());
-    C2Error ret = alloc->status();
-    if (ret == C2_OK) {
-        *allocation = alloc;
-    }
-    return ret;
-}
-
 /* ========================================== 1D BLOCK ========================================= */
 
 class C2Block1D::Impl {
@@ -762,304 +366,6 @@
     return C2_OK;
 }
 
-/* ===================================== GRALLOC ALLOCATION ==================================== */
-
-static C2Error maperr2error(Error maperr) {
-    switch (maperr) {
-        case Error::NONE:           return C2_OK;
-        case Error::BAD_DESCRIPTOR: return C2_BAD_VALUE;
-        case Error::BAD_BUFFER:     return C2_BAD_VALUE;
-        case Error::BAD_VALUE:      return C2_BAD_VALUE;
-        case Error::NO_RESOURCES:   return C2_NO_MEMORY;
-        case Error::UNSUPPORTED:    return C2_UNSUPPORTED;
-    }
-    return C2_CORRUPTED;
-}
-
-class C2AllocationGralloc : public C2GraphicAllocation {
-public:
-    virtual ~C2AllocationGralloc();
-
-    virtual C2Error map(
-            C2Rect rect, C2MemoryUsage usage, int *fenceFd,
-            C2PlaneLayout *layout /* nonnull */, uint8_t **addr /* nonnull */) override;
-    virtual C2Error unmap(C2Fence *fenceFd /* nullable */) override;
-    virtual bool isValid() const override { return true; }
-    virtual const C2Handle *handle() const override { return mHandle; }
-    virtual bool equals(const std::shared_ptr<const C2GraphicAllocation> &other) const override;
-
-    // internal methods
-    // |handle| will be moved.
-    C2AllocationGralloc(
-              const IMapper::BufferDescriptorInfo &info,
-              const sp<IMapper> &mapper,
-              hidl_handle &handle);
-    int dup() const;
-    C2Error status() const;
-
-private:
-    const IMapper::BufferDescriptorInfo mInfo;
-    const sp<IMapper> mMapper;
-    const hidl_handle mHandle;
-    buffer_handle_t mBuffer;
-    bool mLocked;
-};
-
-C2AllocationGralloc::C2AllocationGralloc(
-          const IMapper::BufferDescriptorInfo &info,
-          const sp<IMapper> &mapper,
-          hidl_handle &handle)
-    : C2GraphicAllocation(info.width, info.height),
-      mInfo(info),
-      mMapper(mapper),
-      mHandle(std::move(handle)),
-      mBuffer(nullptr),
-      mLocked(false) {}
-
-C2AllocationGralloc::~C2AllocationGralloc() {
-    if (!mBuffer) {
-        return;
-    }
-    if (mLocked) {
-        unmap(nullptr);
-    }
-    mMapper->freeBuffer(const_cast<native_handle_t *>(mBuffer));
-}
-
-C2Error C2AllocationGralloc::map(
-        C2Rect rect, C2MemoryUsage usage, int *fenceFd,
-        C2PlaneLayout *layout /* nonnull */, uint8_t **addr /* nonnull */) {
-    // TODO
-    (void) fenceFd;
-    (void) usage;
-
-    if (mBuffer && mLocked) {
-        return C2_DUPLICATE;
-    }
-    if (!layout || !addr) {
-        return C2_BAD_VALUE;
-    }
-
-    C2Error err = C2_OK;
-    if (!mBuffer) {
-        mMapper->importBuffer(
-                mHandle, [&err, this](const auto &maperr, const auto &buffer) {
-                    err = maperr2error(maperr);
-                    if (err == C2_OK) {
-                        mBuffer = static_cast<buffer_handle_t>(buffer);
-                    }
-                });
-        if (err != C2_OK) {
-            return err;
-        }
-    }
-
-    if (mInfo.format == PixelFormat::YCBCR_420_888 || mInfo.format == PixelFormat::YV12) {
-        YCbCrLayout ycbcrLayout;
-        mMapper->lockYCbCr(
-                const_cast<native_handle_t *>(mBuffer),
-                BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN,
-                { (int32_t)rect.mLeft, (int32_t)rect.mTop, (int32_t)rect.mWidth, (int32_t)rect.mHeight },
-                // TODO: fence
-                hidl_handle(),
-                [&err, &ycbcrLayout](const auto &maperr, const auto &mapLayout) {
-                    err = maperr2error(maperr);
-                    if (err == C2_OK) {
-                        ycbcrLayout = mapLayout;
-                    }
-                });
-        if (err != C2_OK) {
-            return err;
-        }
-        addr[C2PlaneLayout::Y] = (uint8_t *)ycbcrLayout.y;
-        addr[C2PlaneLayout::U] = (uint8_t *)ycbcrLayout.cb;
-        addr[C2PlaneLayout::V] = (uint8_t *)ycbcrLayout.cr;
-        layout->mType = C2PlaneLayout::MEDIA_IMAGE_TYPE_YUV;
-        layout->mNumPlanes = 3;
-        layout->mPlanes[C2PlaneLayout::Y] = {
-            C2PlaneInfo::Y,                 // mChannel
-            1,                              // mColInc
-            (int32_t)ycbcrLayout.yStride,   // mRowInc
-            1,                              // mHorizSubsampling
-            1,                              // mVertSubsampling
-            8,                              // mBitDepth
-            8,                              // mAllocatedDepth
-        };
-        layout->mPlanes[C2PlaneLayout::U] = {
-            C2PlaneInfo::Cb,                  // mChannel
-            (int32_t)ycbcrLayout.chromaStep,  // mColInc
-            (int32_t)ycbcrLayout.cStride,     // mRowInc
-            2,                                // mHorizSubsampling
-            2,                                // mVertSubsampling
-            8,                                // mBitDepth
-            8,                                // mAllocatedDepth
-        };
-        layout->mPlanes[C2PlaneLayout::V] = {
-            C2PlaneInfo::Cr,                  // mChannel
-            (int32_t)ycbcrLayout.chromaStep,  // mColInc
-            (int32_t)ycbcrLayout.cStride,     // mRowInc
-            2,                                // mHorizSubsampling
-            2,                                // mVertSubsampling
-            8,                                // mBitDepth
-            8,                                // mAllocatedDepth
-        };
-    } else {
-        void *pointer = nullptr;
-        mMapper->lock(
-                const_cast<native_handle_t *>(mBuffer),
-                BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN,
-                { (int32_t)rect.mLeft, (int32_t)rect.mTop, (int32_t)rect.mWidth, (int32_t)rect.mHeight },
-                // TODO: fence
-                hidl_handle(),
-                [&err, &pointer](const auto &maperr, const auto &mapPointer) {
-                    err = maperr2error(maperr);
-                    if (err == C2_OK) {
-                        pointer = mapPointer;
-                    }
-                });
-        if (err != C2_OK) {
-            return err;
-        }
-        // TODO
-        return C2_UNSUPPORTED;
-    }
-    mLocked = true;
-
-    return C2_OK;
-}
-
-C2Error C2AllocationGralloc::unmap(C2Fence *fenceFd /* nullable */) {
-    // TODO: fence
-    C2Error err = C2_OK;
-    mMapper->unlock(
-            const_cast<native_handle_t *>(mBuffer),
-            [&err, &fenceFd](const auto &maperr, const auto &releaseFence) {
-                // TODO
-                (void) fenceFd;
-                (void) releaseFence;
-                err = maperr2error(maperr);
-                if (err == C2_OK) {
-                    // TODO: fence
-                }
-            });
-    if (err == C2_OK) {
-        mLocked = false;
-    }
-    return err;
-}
-
-bool C2AllocationGralloc::equals(const std::shared_ptr<const C2GraphicAllocation> &other) const {
-    return other && other->handle() == handle();
-}
-
-/* ===================================== GRALLOC ALLOCATOR ==================================== */
-
-class C2AllocatorGralloc::Impl {
-public:
-    Impl();
-
-    C2Error allocateGraphicBuffer(
-            uint32_t width, uint32_t height, uint32_t format, const C2MemoryUsage &usage,
-            std::shared_ptr<C2GraphicAllocation> *allocation);
-
-    C2Error recreateGraphicBuffer(
-            const C2Handle *handle,
-            std::shared_ptr<C2GraphicAllocation> *allocation);
-
-    C2Error status() const { return mInit; }
-
-private:
-    C2Error mInit;
-    sp<IAllocator> mAllocator;
-    sp<IMapper> mMapper;
-};
-
-C2AllocatorGralloc::Impl::Impl() : mInit(C2_OK) {
-    mAllocator = IAllocator::getService();
-    mMapper = IMapper::getService();
-    if (mAllocator == nullptr || mMapper == nullptr) {
-        mInit = C2_CORRUPTED;
-    }
-}
-
-C2Error C2AllocatorGralloc::Impl::allocateGraphicBuffer(
-        uint32_t width, uint32_t height, uint32_t format, const C2MemoryUsage &usage,
-        std::shared_ptr<C2GraphicAllocation> *allocation) {
-    // TODO: buffer usage should be determined according to |usage|
-    (void) usage;
-
-    IMapper::BufferDescriptorInfo info = {
-        width,
-        height,
-        1u,  // layerCount
-        (PixelFormat)format,
-        BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN,
-    };
-    C2Error err = C2_OK;
-    BufferDescriptor desc;
-    mMapper->createDescriptor(
-            info, [&err, &desc](const auto &maperr, const auto &descriptor) {
-                err = maperr2error(maperr);
-                if (err == C2_OK) {
-                    desc = descriptor;
-                }
-            });
-    if (err != C2_OK) {
-        return err;
-    }
-
-    // IAllocator shares IMapper error codes.
-    hidl_handle buffer;
-    mAllocator->allocate(
-            desc,
-            1u,
-            [&err, &buffer](const auto &maperr, const auto &stride, auto &buffers) {
-                (void) stride;
-                err = maperr2error(maperr);
-                if (err != C2_OK) {
-                    return;
-                }
-                if (buffers.size() != 1u) {
-                    err = C2_CORRUPTED;
-                    return;
-                }
-                buffer = std::move(buffers[0]);
-            });
-    if (err != C2_OK) {
-        return err;
-    }
-
-    allocation->reset(new C2AllocationGralloc(info, mMapper, buffer));
-    return C2_OK;
-}
-
-C2Error C2AllocatorGralloc::Impl::recreateGraphicBuffer(
-        const C2Handle *handle,
-        std::shared_ptr<C2GraphicAllocation> *allocation) {
-    (void) handle;
-
-    // TODO: need to figure out BufferDescriptorInfo from the handle.
-    allocation->reset();
-    return C2_UNSUPPORTED;
-}
-
-C2AllocatorGralloc::C2AllocatorGralloc() : mImpl(new Impl) {}
-C2AllocatorGralloc::~C2AllocatorGralloc() { delete mImpl; }
-
-C2Error C2AllocatorGralloc::allocateGraphicBuffer(
-        uint32_t width, uint32_t height, uint32_t format, C2MemoryUsage usage,
-        std::shared_ptr<C2GraphicAllocation> *allocation) {
-    return mImpl->allocateGraphicBuffer(width, height, format, usage, allocation);
-}
-
-C2Error C2AllocatorGralloc::recreateGraphicBuffer(
-        const C2Handle *handle,
-        std::shared_ptr<C2GraphicAllocation> *allocation) {
-    return mImpl->recreateGraphicBuffer(handle, allocation);
-}
-
-C2Error C2AllocatorGralloc::status() const { return mImpl->status(); }
-
 /* ========================================== 2D BLOCK ========================================= */
 
 class C2Block2D::Impl {
diff --git a/media/libstagefright/codec2/vndk/C2Config.cpp b/media/libstagefright/codec2/vndk/C2Config.cpp
new file mode 100644
index 0000000..6acf524
--- /dev/null
+++ b/media/libstagefright/codec2/vndk/C2Config.cpp
@@ -0,0 +1,24 @@
+/*
+ * 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "C2Config"
+
+/**
+ * Define and initialize global config field descriptors in this cpp file
+ */
+#define __C2_GENERATE_GLOBAL_VARS__
+#include <C2Config.h>
diff --git a/media/libstagefright/codec2/vndk/C2Store.cpp b/media/libstagefright/codec2/vndk/C2Store.cpp
new file mode 100644
index 0000000..f21a3f0
--- /dev/null
+++ b/media/libstagefright/codec2/vndk/C2Store.cpp
@@ -0,0 +1,103 @@
+/*
+ * 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.
+ */
+
+#include <C2AllocatorGralloc.h>
+#include <C2AllocatorIon.h>
+#include <C2Component.h>
+#include <C2PlatformSupport.h>
+
+#include <map>
+#include <memory>
+#include <mutex>
+
+namespace android {
+
+class C2PlatformAllocatorStore : public C2AllocatorStore {
+public:
+    enum ID_ : uint32_t {
+        ION = PLATFORM_START,
+        GRALLOC,
+    };
+
+    C2PlatformAllocatorStore(
+        /* ionmapper */
+    );
+    virtual status_t createAllocator(ID id, std::shared_ptr<C2Allocator> *const allocator);
+
+private:
+    // returns a shared-singleton ion allocator
+    std::shared_ptr<C2Allocator> getIonAllocator();
+
+    // returns a shared-singleton gralloc allocator
+    std::shared_ptr<C2Allocator> getGrallocAllocator();
+};
+
+C2PlatformAllocatorStore::C2PlatformAllocatorStore() {
+}
+
+status_t C2PlatformAllocatorStore::createAllocator(
+        ID id, std::shared_ptr<C2Allocator> *const allocator) {
+    allocator->reset();
+    switch (id) {
+    // TODO: should we implement a generic registry for all, and use that?
+    case C2PlatformAllocatorStore::ION:
+    case C2AllocatorStore::DEFAULT_LINEAR:
+        *allocator = getIonAllocator();
+        break;
+
+    case C2PlatformAllocatorStore::GRALLOC:
+    case C2AllocatorStore::DEFAULT_GRAPHIC:
+        *allocator = getGrallocAllocator();
+        break;
+
+    default:
+        return C2_NOT_FOUND;
+    }
+    if (*allocator == nullptr) {
+        return C2_NO_MEMORY;
+    }
+    return C2_OK;
+}
+
+std::shared_ptr<C2Allocator> C2PlatformAllocatorStore::getIonAllocator() {
+    static std::mutex mutex;
+    static std::weak_ptr<C2Allocator> ionAllocator;
+    std::lock_guard<std::mutex> lock(mutex);
+    std::shared_ptr<C2Allocator> allocator = ionAllocator.lock();
+    if (allocator == nullptr) {
+        allocator = std::make_shared<C2AllocatorIon>();
+        ionAllocator = allocator;
+    }
+    return allocator;
+}
+
+std::shared_ptr<C2Allocator> C2PlatformAllocatorStore::getGrallocAllocator() {
+    static std::mutex mutex;
+    static std::weak_ptr<C2Allocator> grallocAllocator;
+    std::lock_guard<std::mutex> lock(mutex);
+    std::shared_ptr<C2Allocator> allocator = grallocAllocator.lock();
+    if (allocator == nullptr) {
+        allocator = std::make_shared<C2AllocatorGralloc>();
+        grallocAllocator = allocator;
+    }
+    return allocator;
+}
+
+std::shared_ptr<C2AllocatorStore> GetCodec2PlatformAllocatorStore() {
+    return std::make_shared<C2PlatformAllocatorStore>();
+}
+
+} // namespace android
\ No newline at end of file
diff --git a/media/libstagefright/codec2/vndk/include/C2AllocatorGralloc.h b/media/libstagefright/codec2/vndk/include/C2AllocatorGralloc.h
new file mode 100644
index 0000000..94f74c8
--- /dev/null
+++ b/media/libstagefright/codec2/vndk/include/C2AllocatorGralloc.h
@@ -0,0 +1,68 @@
+
+/*
+ * Copyright (C) 2016 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 STAGEFRIGHT_CODEC2_ALLOCATOR_GRALLOC_H_
+#define STAGEFRIGHT_CODEC2_ALLOCATOR_GRALLOC_H_
+
+#include <functional>
+
+#include <C2Buffer.h>
+
+namespace android {
+
+class C2AllocatorGralloc : public C2Allocator {
+public:
+    // (usage, capacity) => (align, heapMask, flags)
+    typedef std::function<int (C2MemoryUsage, size_t,
+                      /* => */ size_t*, unsigned*, unsigned*)> usage_mapper_fn;
+
+    virtual C2Error allocateGraphicBuffer(
+            uint32_t width, uint32_t height, uint32_t format, C2MemoryUsage usage,
+            std::shared_ptr<C2GraphicAllocation> *allocation) override;
+
+    virtual C2Error recreateGraphicBuffer(
+            const C2Handle *handle,
+            std::shared_ptr<C2GraphicAllocation> *allocation) override;
+
+    C2AllocatorGralloc();
+
+    C2Error status() const;
+
+    virtual ~C2AllocatorGralloc();
+
+private:
+    class Impl;
+    Impl *mImpl;
+};
+
+#if 0
+class C2Allocation::Impl {
+public:
+    Impl() : mMapped(false), mBase(nullptr) { }
+    uint8_t* base() { return mMapped ? mBase : nullptr; }
+
+    // TODO: call map...
+
+private:
+    bool mMapped;
+    uint8_t *mBase;
+};
+#endif
+
+} // namespace android
+
+#endif // STAGEFRIGHT_CODEC2_ALLOCATOR_GRALLOC_H_
diff --git a/media/libstagefright/codec2/vndk/include/C2AllocatorIon.h b/media/libstagefright/codec2/vndk/include/C2AllocatorIon.h
new file mode 100644
index 0000000..a453a7d
--- /dev/null
+++ b/media/libstagefright/codec2/vndk/include/C2AllocatorIon.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2016 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 STAGEFRIGHT_CODEC2_ALLOCATOR_ION_H_
+#define STAGEFRIGHT_CODEC2_ALLOCATOR_ION_H_
+
+#include <functional>
+
+#include <C2Buffer.h>
+
+namespace android {
+
+class C2AllocatorIon : public C2Allocator {
+public:
+    // (usage, capacity) => (align, heapMask, flags)
+    typedef std::function<int (C2MemoryUsage, size_t,
+                      /* => */ size_t*, unsigned*, unsigned*)> usage_mapper_fn;
+
+    virtual C2Error allocateLinearBuffer(
+            uint32_t capacity, C2MemoryUsage usage,
+            std::shared_ptr<C2LinearAllocation> *allocation) override;
+
+    virtual C2Error recreateLinearBuffer(
+            const C2Handle *handle,
+            std::shared_ptr<C2LinearAllocation> *allocation) override;
+
+    C2AllocatorIon();
+
+    C2Error status() const { return mInit; }
+
+    virtual ~C2AllocatorIon();
+
+private:
+    C2Error mInit;
+    int mIonFd;
+    usage_mapper_fn mUsageMapper;
+};
+
+} // namespace android
+
+#endif // STAGEFRIGHT_CODEC2_ALLOCATOR_ION_H_
diff --git a/media/libstagefright/codec2/vndk/include/C2BufferPriv.h b/media/libstagefright/codec2/vndk/include/C2BufferPriv.h
index b7c752f..6a8f94e 100644
--- a/media/libstagefright/codec2/vndk/include/C2BufferPriv.h
+++ b/media/libstagefright/codec2/vndk/include/C2BufferPriv.h
@@ -23,32 +23,6 @@
 
 namespace android {
 
-class C2AllocatorIon : public C2Allocator {
-public:
-    // (usage, capacity) => (align, heapMask, flags)
-    typedef std::function<int (C2MemoryUsage, size_t,
-                      /* => */ size_t*, unsigned*, unsigned*)> usage_mapper_fn;
-
-    virtual C2Error allocateLinearBuffer(
-            uint32_t capacity, C2MemoryUsage usage,
-            std::shared_ptr<C2LinearAllocation> *allocation) override;
-
-    virtual C2Error recreateLinearBuffer(
-            const C2Handle *handle,
-            std::shared_ptr<C2LinearAllocation> *allocation) override;
-
-    C2AllocatorIon();
-
-    C2Error status() const { return mInit; }
-
-    virtual ~C2AllocatorIon();
-
-private:
-    C2Error mInit;
-    int mIonFd;
-    usage_mapper_fn mUsageMapper;
-};
-
 class C2DefaultBlockAllocator : public C2BlockAllocator {
 public:
     explicit C2DefaultBlockAllocator(const std::shared_ptr<C2Allocator> &allocator);
@@ -65,31 +39,6 @@
     const std::shared_ptr<C2Allocator> mAllocator;
 };
 
-class C2AllocatorGralloc : public C2Allocator {
-public:
-    // (usage, capacity) => (align, heapMask, flags)
-    typedef std::function<int (C2MemoryUsage, size_t,
-                      /* => */ size_t*, unsigned*, unsigned*)> usage_mapper_fn;
-
-    virtual C2Error allocateGraphicBuffer(
-            uint32_t width, uint32_t height, uint32_t format, C2MemoryUsage usage,
-            std::shared_ptr<C2GraphicAllocation> *allocation) override;
-
-    virtual C2Error recreateGraphicBuffer(
-            const C2Handle *handle,
-            std::shared_ptr<C2GraphicAllocation> *allocation) override;
-
-    C2AllocatorGralloc();
-
-    C2Error status() const;
-
-    virtual ~C2AllocatorGralloc();
-
-private:
-    class Impl;
-    Impl *mImpl;
-};
-
 class C2DefaultGraphicBlockAllocator : public C2BlockAllocator {
 public:
     explicit C2DefaultGraphicBlockAllocator(const std::shared_ptr<C2Allocator> &allocator);
diff --git a/media/libstagefright/codec2/vndk/include/C2ErrnoUtils.h b/media/libstagefright/codec2/vndk/include/C2ErrnoUtils.h
new file mode 100644
index 0000000..f834cdb
--- /dev/null
+++ b/media/libstagefright/codec2/vndk/include/C2ErrnoUtils.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2016 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 STAGEFRIGHT_CODEC2_ERRNO_UTILS_H_
+#define STAGEFRIGHT_CODEC2_ERRNO_UTILS_H_
+
+#include <errno.h>
+#include <C2.h>
+
+namespace android {
+
+// standard ERRNO mappings
+template<int N> constexpr C2Error _c2_errno2error_impl();
+template<> constexpr C2Error _c2_errno2error_impl<0>()       { return C2_OK; }
+template<> constexpr C2Error _c2_errno2error_impl<EINVAL>()  { return C2_BAD_VALUE; }
+template<> constexpr C2Error _c2_errno2error_impl<EACCES>()  { return C2_NO_PERMISSION; }
+template<> constexpr C2Error _c2_errno2error_impl<EPERM>()   { return C2_NO_PERMISSION; }
+template<> constexpr C2Error _c2_errno2error_impl<ENOMEM>()  { return C2_NO_MEMORY; }
+
+// map standard errno-s to the equivalent C2Error
+template<int... N> struct _c2_map_errno_impl;
+template<int E, int ... N> struct _c2_map_errno_impl<E, N...> {
+    static C2Error map(int result) {
+        if (result == E) {
+            return _c2_errno2error_impl<E>();
+        } else {
+            return _c2_map_errno_impl<N...>::map(result);
+        }
+    }
+};
+template<> struct _c2_map_errno_impl<> {
+    static C2Error map(int result) {
+        return result == 0 ? C2_OK : C2_CORRUPTED;
+    }
+};
+
+template<int... N>
+C2Error c2_map_errno(int result) {
+    return _c2_map_errno_impl<N...>::map(result);
+}
+
+} // namespace android
+
+#endif // STAGEFRIGHT_CODEC2_ERRNO_UTILS_H_
+
diff --git a/media/libstagefright/codec2/vndk/include/C2PlatformSupport.h b/media/libstagefright/codec2/vndk/include/C2PlatformSupport.h
new file mode 100644
index 0000000..9402050
--- /dev/null
+++ b/media/libstagefright/codec2/vndk/include/C2PlatformSupport.h
@@ -0,0 +1,33 @@
+/*
+ * 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.
+ */
+
+#ifndef STAGEFRIGHT_CODEC2_PLATFORM_SUPPORT_H_
+#define STAGEFRIGHT_CODEC2_PLATFORM_SUPPORT_H_
+
+#include <C2Component.h>
+
+#include <memory>
+
+namespace android {
+
+/**
+ * Returns the platform allocator store.
+ */
+std::shared_ptr<C2AllocatorStore> GetCodec2PlatformAllocatorStore();
+
+} // namespace android
+
+#endif // STAGEFRIGHT_CODEC2_PLATFORM_SUPPORT_H_
diff --git a/media/libstagefright/codecs/amrnb/dec/Android.bp b/media/libstagefright/codecs/amrnb/dec/Android.bp
index d266dc2..b493e21 100644
--- a/media/libstagefright/codecs/amrnb/dec/Android.bp
+++ b/media/libstagefright/codecs/amrnb/dec/Android.bp
@@ -114,6 +114,8 @@
 
     srcs: ["test/amrnbdec_test.cpp"],
 
+    cflags: ["-Wall", "-Werror"],
+
     local_include_dirs: ["src"],
 
     static_libs: [
diff --git a/media/libstagefright/codecs/amrnb/enc/Android.bp b/media/libstagefright/codecs/amrnb/enc/Android.bp
index 6dc2dc1..1e8fd31 100644
--- a/media/libstagefright/codecs/amrnb/enc/Android.bp
+++ b/media/libstagefright/codecs/amrnb/enc/Android.bp
@@ -126,6 +126,8 @@
 
     srcs: ["test/amrnb_enc_test.cpp"],
 
+    cflags: ["-Wall", "-Werror"],
+
     local_include_dirs: ["src"],
 
     static_libs: ["libstagefright_amrnbenc"],
diff --git a/media/libstagefright/codecs/amrwb/Android.bp b/media/libstagefright/codecs/amrwb/Android.bp
index b932ccc..14a73d6 100644
--- a/media/libstagefright/codecs/amrwb/Android.bp
+++ b/media/libstagefright/codecs/amrwb/Android.bp
@@ -69,6 +69,8 @@
 
     srcs: ["test/amrwbdec_test.cpp"],
 
+    cflags: ["-Wall", "-Werror"],
+
     static_libs: [
         "libstagefright_amrwbdec",
         "libsndfile",
diff --git a/media/libstagefright/codecs/amrwbenc/SampleCode/Android.bp b/media/libstagefright/codecs/amrwbenc/SampleCode/Android.bp
index d52fed3..81b3f69 100644
--- a/media/libstagefright/codecs/amrwbenc/SampleCode/Android.bp
+++ b/media/libstagefright/codecs/amrwbenc/SampleCode/Android.bp
@@ -4,6 +4,8 @@
 
     srcs: ["AMRWB_E_SAMPLE.c"],
 
+    cflags: ["-Wall", "-Werror"],
+
     arch: {
         arm: {
             instruction_set: "arm",
diff --git a/media/libstagefright/codecs/avcdec/Android.bp b/media/libstagefright/codecs/avcdec/Android.bp
index 44f5e4f..3b2602d 100644
--- a/media/libstagefright/codecs/avcdec/Android.bp
+++ b/media/libstagefright/codecs/avcdec/Android.bp
@@ -8,6 +8,12 @@
     static_libs: ["libavcdec"],
     srcs: ["SoftAVCDec.cpp"],
 
+    cflags: [
+        "-Wall",
+        "-Werror",
+        "-Wno-unused-variable",
+    ],
+
     include_dirs: [
         "external/libavc/decoder",
         "external/libavc/common",
diff --git a/media/libstagefright/codecs/avcdec/SoftAVCDec.cpp b/media/libstagefright/codecs/avcdec/SoftAVCDec.cpp
index c342b6c..1622561 100644
--- a/media/libstagefright/codecs/avcdec/SoftAVCDec.cpp
+++ b/media/libstagefright/codecs/avcdec/SoftAVCDec.cpp
@@ -171,7 +171,7 @@
 status_t SoftAVC::resetPlugin() {
     mIsInFlush = false;
     mReceivedEOS = false;
-    mInputOffset = 0;
+
     memset(mTimeStamps, 0, sizeof(mTimeStamps));
     memset(mTimeStampsValid, 0, sizeof(mTimeStampsValid));
 
@@ -274,10 +274,6 @@
 
         status = ivdec_api_function(mCodecCtx, (void *)&s_create_ip, (void *)&s_create_op);
 
-        mCodecCtx = (iv_obj_t*)s_create_op.s_ivd_create_op_t.pv_handle;
-        mCodecCtx->pv_fxns = dec_fxns;
-        mCodecCtx->u4_size = sizeof(iv_obj_t);
-
         if (status != IV_SUCCESS) {
             ALOGE("Error in create: 0x%x",
                     s_create_op.s_ivd_create_op_t.u4_error_code);
@@ -285,6 +281,10 @@
             mCodecCtx = NULL;
             return UNKNOWN_ERROR;
         }
+
+        mCodecCtx = (iv_obj_t*)s_create_op.s_ivd_create_op_t.pv_handle;
+        mCodecCtx->pv_fxns = dec_fxns;
+        mCodecCtx->u4_size = sizeof(iv_obj_t);
     }
 
     /* Reset the plugin state */
@@ -334,6 +334,7 @@
     SoftVideoDecoderOMXComponent::onReset();
 
     mSignalledError = false;
+    mInputOffset = 0;
     resetDecoder();
     resetPlugin();
 }
@@ -465,7 +466,8 @@
             free(mFlushOutBuffer);
             mFlushOutBuffer = NULL;
         }
-
+    } else {
+        mInputOffset = 0;
     }
 }
 
@@ -530,7 +532,7 @@
                 notifyEmptyBufferDone(inHeader);
 
                 if (!(inHeader->nFlags & OMX_BUFFERFLAG_EOS)) {
-                    continue;
+                    return;
                 }
 
                 mReceivedEOS = true;
diff --git a/media/libstagefright/codecs/avcenc/Android.bp b/media/libstagefright/codecs/avcenc/Android.bp
index 7a8e1b7..4a0411e 100644
--- a/media/libstagefright/codecs/avcenc/Android.bp
+++ b/media/libstagefright/codecs/avcenc/Android.bp
@@ -33,6 +33,11 @@
         },
     },
 
+    cflags: [
+        "-Wall",
+        "-Werror",
+        "-Wno-unused-variable",
+    ],
     ldflags: ["-Wl,-Bsymbolic"],
     compile_multilib: "32",
 }
diff --git a/media/libstagefright/codecs/cmds/codec2.cpp b/media/libstagefright/codecs/cmds/codec2.cpp
index f64887d..29669aa 100644
--- a/media/libstagefright/codecs/cmds/codec2.cpp
+++ b/media/libstagefright/codecs/cmds/codec2.cpp
@@ -30,17 +30,19 @@
 
 #include <binder/IServiceManager.h>
 #include <binder/ProcessState.h>
+#include <media/DataSource.h>
 #include <media/ICrypto.h>
 #include <media/IMediaHTTPService.h>
+#include <media/MediaExtractor.h>
+#include <media/MediaSource.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ALooper.h>
 #include <media/stagefright/foundation/AMessage.h>
 #include <media/stagefright/foundation/AUtils.h>
-#include <media/stagefright/DataSource.h>
+#include <media/stagefright/DataSourceFactory.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/MediaExtractor.h>
-#include <media/stagefright/MediaSource.h>
+#include <media/stagefright/MediaExtractorFactory.h>
 #include <media/stagefright/MetaData.h>
 #include <media/stagefright/Utils.h>
 
@@ -53,6 +55,7 @@
 #include <C2Buffer.h>
 #include <C2BufferPriv.h>
 #include <C2Component.h>
+#include <C2PlatformSupport.h>
 #include <C2Work.h>
 
 #include "../avcdec/C2SoftAvcDec.h"
@@ -137,13 +140,16 @@
 SimplePlayer::SimplePlayer()
     : mListener(new Listener(this)),
       mProducerListener(new DummyProducerListener),
-      mAllocIon(new C2AllocatorIon),
-      mAllocGralloc(new C2AllocatorGralloc),
-      mLinearAlloc(new C2DefaultBlockAllocator(mAllocIon)),
-      mGraphicAlloc(new C2DefaultGraphicBlockAllocator(mAllocGralloc)),
       mComposerClient(new SurfaceComposerClient) {
     CHECK_EQ(mComposerClient->initCheck(), (status_t)OK);
 
+    std::shared_ptr<C2AllocatorStore> store = GetCodec2PlatformAllocatorStore();
+    CHECK_EQ(store->createAllocator(C2AllocatorStore::DEFAULT_LINEAR, &mAllocIon), C2_OK);
+    CHECK_EQ(store->createAllocator(C2AllocatorStore::DEFAULT_GRAPHIC, &mAllocGralloc), C2_OK);
+
+    mLinearAlloc = std::make_shared<C2DefaultBlockAllocator>(mAllocIon);
+    mGraphicAlloc = std::make_shared<C2DefaultGraphicBlockAllocator>(mAllocGralloc);
+
     mControl = mComposerClient->createSurface(
             String8("A Surface"),
             1280,
@@ -398,7 +404,7 @@
         const char *filename = argv[k];
 
         sp<DataSource> dataSource =
-            DataSource::CreateFromURI(NULL /* httpService */, filename);
+            DataSourceFactory::CreateFromURI(NULL /* httpService */, filename);
 
         if (strncasecmp(filename, "sine:", 5) && dataSource == NULL) {
             fprintf(stderr, "Unable to create data source.\n");
@@ -408,7 +414,7 @@
         Vector<sp<IMediaSource> > mediaSources;
         sp<IMediaSource> mediaSource;
 
-        sp<IMediaExtractor> extractor = MediaExtractor::Create(dataSource);
+        sp<IMediaExtractor> extractor = MediaExtractorFactory::Create(dataSource);
 
         if (extractor == NULL) {
             fprintf(stderr, "could not create extractor.\n");
diff --git a/media/libstagefright/codecs/hevcdec/Android.bp b/media/libstagefright/codecs/hevcdec/Android.bp
index e63a2f8..f19ba00 100644
--- a/media/libstagefright/codecs/hevcdec/Android.bp
+++ b/media/libstagefright/codecs/hevcdec/Android.bp
@@ -8,6 +8,12 @@
     static_libs: ["libhevcdec"],
     srcs: ["SoftHEVC.cpp"],
 
+    cflags: [
+        "-Wall",
+        "-Werror",
+        "-Wno-unused-variable",
+    ],
+
     include_dirs: [
         "external/libhevc/decoder",
         "external/libhevc/common",
diff --git a/media/libstagefright/codecs/hevcdec/SoftHEVC.cpp b/media/libstagefright/codecs/hevcdec/SoftHEVC.cpp
index 2745087..103fc22 100644
--- a/media/libstagefright/codecs/hevcdec/SoftHEVC.cpp
+++ b/media/libstagefright/codecs/hevcdec/SoftHEVC.cpp
@@ -312,10 +312,6 @@
 
         status = ivdec_api_function(mCodecCtx, (void *)&s_create_ip, (void *)&s_create_op);
 
-        mCodecCtx = (iv_obj_t*)s_create_op.s_ivd_create_op_t.pv_handle;
-        mCodecCtx->pv_fxns = dec_fxns;
-        mCodecCtx->u4_size = sizeof(iv_obj_t);
-
         if (status != IV_SUCCESS) {
             ALOGE("Error in create: 0x%x",
                     s_create_op.s_ivd_create_op_t.u4_error_code);
@@ -323,6 +319,10 @@
             mCodecCtx = NULL;
             return UNKNOWN_ERROR;
         }
+
+        mCodecCtx = (iv_obj_t*)s_create_op.s_ivd_create_op_t.pv_handle;
+        mCodecCtx->pv_fxns = dec_fxns;
+        mCodecCtx->u4_size = sizeof(iv_obj_t);
     }
 
     /* Reset the plugin state */
diff --git a/media/libstagefright/codecs/m4v_h263/dec/src/vlc_decode.cpp b/media/libstagefright/codecs/m4v_h263/dec/src/vlc_decode.cpp
index f7192b1c..7202f98 100644
--- a/media/libstagefright/codecs/m4v_h263/dec/src/vlc_decode.cpp
+++ b/media/libstagefright/codecs/m4v_h263/dec/src/vlc_decode.cpp
@@ -560,7 +560,7 @@
 
     BitstreamShow13Bits(stream, &code);
 
-    if (code == 0)
+    if (code < 8)
     {
         return VLC_CODE_ERROR;
     }
diff --git a/media/libstagefright/codecs/m4v_h263/enc/Android.bp b/media/libstagefright/codecs/m4v_h263/enc/Android.bp
index 7c5c61c..8a3fe34 100644
--- a/media/libstagefright/codecs/m4v_h263/enc/Android.bp
+++ b/media/libstagefright/codecs/m4v_h263/enc/Android.bp
@@ -111,6 +111,8 @@
         "-DOSCL_EXPORT_REF=",
         "-DOSCL_IMPORT_REF=",
         "-DBX_RC",
+        "-Wall",
+        "-Werror",
     ],
 
     sanitize: {
diff --git a/media/libstagefright/codecs/mp3dec/Android.bp b/media/libstagefright/codecs/mp3dec/Android.bp
index 32c0753..5a0e282 100644
--- a/media/libstagefright/codecs/mp3dec/Android.bp
+++ b/media/libstagefright/codecs/mp3dec/Android.bp
@@ -127,6 +127,8 @@
         "test/mp3reader.cpp",
     ],
 
+    cflags: ["-Wall", "-Werror"],
+
     local_include_dirs: [
         "src",
         "include",
diff --git a/media/libstagefright/codecs/mpeg2dec/Android.bp b/media/libstagefright/codecs/mpeg2dec/Android.bp
index 0520559..9b8a188 100644
--- a/media/libstagefright/codecs/mpeg2dec/Android.bp
+++ b/media/libstagefright/codecs/mpeg2dec/Android.bp
@@ -8,6 +8,12 @@
     static_libs: ["libmpeg2dec"],
     srcs: ["SoftMPEG2.cpp"],
 
+    cflags: [
+        "-Wall",
+        "-Werror",
+        "-Wno-unused-variable",
+    ],
+
     include_dirs: [
         "external/libmpeg2/decoder",
         "external/libmpeg2/common",
diff --git a/media/libstagefright/codecs/on2/enc/Android.bp b/media/libstagefright/codecs/on2/enc/Android.bp
index 5c9872a..b21ffa1 100644
--- a/media/libstagefright/codecs/on2/enc/Android.bp
+++ b/media/libstagefright/codecs/on2/enc/Android.bp
@@ -11,6 +11,8 @@
         "SoftVP9Encoder.cpp",
     ],
 
+    cflags: ["-Wall", "-Werror"],
+
     include_dirs: [
         "frameworks/av/media/libstagefright/include",
         "frameworks/native/include/media/openmax",
diff --git a/media/libstagefright/codecs/on2/h264dec/Android.bp b/media/libstagefright/codecs/on2/h264dec/Android.bp
index 6d558b6..f484509 100644
--- a/media/libstagefright/codecs/on2/h264dec/Android.bp
+++ b/media/libstagefright/codecs/on2/h264dec/Android.bp
@@ -96,6 +96,8 @@
         },
     },
 
+    cflags: ["-Wall", "-Werror"],
+
     include_dirs: [
         "frameworks/av/media/libstagefright/include",
         "frameworks/native/include/media/openmax",
@@ -115,6 +117,7 @@
 
     shared_libs: [
         "libmedia",
+        "libmedia_omx",
         "libstagefright_omx",
         "libstagefright_foundation",
         "libutils",
@@ -133,5 +136,7 @@
 
     srcs: ["source/DecTestBench.c"],
 
+    cflags: ["-Wall", "-Werror"],
+
     shared_libs: ["libstagefright_soft_h264dec"],
 }
diff --git a/media/libstagefright/colorconversion/ColorConverter.cpp b/media/libstagefright/colorconversion/ColorConverter.cpp
index 0982006..cbb38fd 100644
--- a/media/libstagefright/colorconversion/ColorConverter.cpp
+++ b/media/libstagefright/colorconversion/ColorConverter.cpp
@@ -129,6 +129,12 @@
             dstWidth, dstHeight,
             dstCropLeft, dstCropTop, dstCropRight, dstCropBottom, mDstFormat);
 
+    if (!((src.mCropLeft & 1) == 0
+        && src.cropWidth() == dst.cropWidth()
+        && src.cropHeight() == dst.cropHeight())) {
+        return ERROR_UNSUPPORTED;
+    }
+
     status_t err;
 
     switch (mSrcFormat) {
@@ -172,12 +178,6 @@
 
     uint8_t *kAdjustedClip = initClip();
 
-    if (!((src.mCropLeft & 1) == 0
-        && src.cropWidth() == dst.cropWidth()
-        && src.cropHeight() == dst.cropHeight())) {
-        return ERROR_UNSUPPORTED;
-    }
-
     uint16_t *dst_ptr = (uint16_t *)dst.mBits
         + dst.mCropTop * dst.mWidth + dst.mCropLeft;
 
@@ -232,12 +232,6 @@
 
 status_t ColorConverter::convertYUV420PlanarUseLibYUV(
         const BitmapParams &src, const BitmapParams &dst) {
-    if (!((src.mCropLeft & 1) == 0
-            && src.cropWidth() == dst.cropWidth()
-            && src.cropHeight() == dst.cropHeight())) {
-        return ERROR_UNSUPPORTED;
-    }
-
     uint8_t *dst_ptr = (uint8_t *)dst.mBits
         + dst.mCropTop * dst.mStride + dst.mCropLeft * dst.mBpp;
 
@@ -338,12 +332,6 @@
 }
 status_t ColorConverter::convertYUV420Planar(
         const BitmapParams &src, const BitmapParams &dst) {
-    if (!((src.mCropLeft & 1) == 0
-            && src.cropWidth() == dst.cropWidth()
-            && src.cropHeight() == dst.cropHeight())) {
-        return ERROR_UNSUPPORTED;
-    }
-
     uint8_t *kAdjustedClip = initClip();
 
     uint8_t *dst_ptr = (uint8_t *)dst.mBits
@@ -422,12 +410,6 @@
         const BitmapParams &src, const BitmapParams &dst) {
     uint8_t *kAdjustedClip = initClip();
 
-    if (!((src.mCropLeft & 1) == 0
-            && src.cropWidth() == dst.cropWidth()
-            && src.cropHeight() == dst.cropHeight())) {
-        return ERROR_UNSUPPORTED;
-    }
-
     uint16_t *dst_ptr = (uint16_t *)dst.mBits
         + dst.mCropTop * dst.mWidth + dst.mCropLeft;
 
@@ -496,12 +478,6 @@
 
     uint8_t *kAdjustedClip = initClip();
 
-    if (!((src.mCropLeft & 1) == 0
-            && src.cropWidth() == dst.cropWidth()
-            && src.cropHeight() == dst.cropHeight())) {
-        return ERROR_UNSUPPORTED;
-    }
-
     uint16_t *dst_ptr = (uint16_t *)dst.mBits
         + dst.mCropTop * dst.mWidth + dst.mCropLeft;
 
@@ -568,12 +544,6 @@
         const BitmapParams &src, const BitmapParams &dst) {
     uint8_t *kAdjustedClip = initClip();
 
-    if (!((src.mCropLeft & 1) == 0
-            && src.cropWidth() == dst.cropWidth()
-            && src.cropHeight() == dst.cropHeight())) {
-        return ERROR_UNSUPPORTED;
-    }
-
     uint16_t *dst_ptr = (uint16_t *)dst.mBits
         + dst.mCropTop * dst.mWidth + dst.mCropLeft;
 
diff --git a/media/libstagefright/filters/Android.bp b/media/libstagefright/filters/Android.bp
index e944224..a0af4f6 100644
--- a/media/libstagefright/filters/Android.bp
+++ b/media/libstagefright/filters/Android.bp
@@ -13,8 +13,12 @@
         "ZeroFilter.cpp",
     ],
 
-    include_dirs: [
-        "frameworks/native/include/media/openmax",
+    header_libs: [
+        "media_plugin_headers",
+    ],
+
+    export_header_lib_headers: [
+        "media_plugin_headers",
     ],
 
     cflags: [
diff --git a/media/libstagefright/flac/dec/Android.bp b/media/libstagefright/flac/dec/Android.bp
index bbbd8c0..581e51b 100644
--- a/media/libstagefright/flac/dec/Android.bp
+++ b/media/libstagefright/flac/dec/Android.bp
@@ -1,4 +1,4 @@
-cc_library_shared {
+cc_library {
     name: "libstagefright_flacdec",
     vendor_available: true,
     vndk: {
@@ -27,7 +27,13 @@
         },
     },
 
-    static_libs: ["libFLAC"],
+    static: {
+        whole_static_libs: ["libFLAC"],
+    },
+
+    shared: {
+        static_libs: ["libFLAC"],
+    },
 
     shared_libs: [
         "liblog",
diff --git a/media/libstagefright/foundation/Android.bp b/media/libstagefright/foundation/Android.bp
index 6ae9a95..c087a27 100644
--- a/media/libstagefright/foundation/Android.bp
+++ b/media/libstagefright/foundation/Android.bp
@@ -67,6 +67,7 @@
         "MediaDefs.cpp",
         "MetaData.cpp",
         "ParsedMessage.cpp",
+        "avc_utils.cpp",
         "base64.cpp",
         "hexdump.cpp",
     ],
diff --git a/media/libstagefright/foundation/MediaDefs.cpp b/media/libstagefright/foundation/MediaDefs.cpp
index 7caebc6..1695c75 100644
--- a/media/libstagefright/foundation/MediaDefs.cpp
+++ b/media/libstagefright/foundation/MediaDefs.cpp
@@ -19,6 +19,7 @@
 namespace android {
 
 const char *MEDIA_MIMETYPE_IMAGE_JPEG = "image/jpeg";
+const char *MEDIA_MIMETYPE_IMAGE_ANDROID_HEIC = "image/vnd.android.heic";
 
 const char *MEDIA_MIMETYPE_VIDEO_VP8 = "video/x-vnd.on2.vp8";
 const char *MEDIA_MIMETYPE_VIDEO_VP9 = "video/x-vnd.on2.vp9";
@@ -58,6 +59,7 @@
 const char *MEDIA_MIMETYPE_CONTAINER_MPEG2TS = "video/mp2ts";
 const char *MEDIA_MIMETYPE_CONTAINER_AVI = "video/avi";
 const char *MEDIA_MIMETYPE_CONTAINER_MPEG2PS = "video/mp2p";
+const char *MEDIA_MIMETYPE_CONTAINER_HEIF = "image/heif";
 
 const char *MEDIA_MIMETYPE_TEXT_3GPP = "text/3gpp-tt";
 const char *MEDIA_MIMETYPE_TEXT_SUBRIP = "application/x-subrip";
diff --git a/media/libstagefright/avc_utils.cpp b/media/libstagefright/foundation/avc_utils.cpp
similarity index 98%
rename from media/libstagefright/avc_utils.cpp
rename to media/libstagefright/foundation/avc_utils.cpp
index b75b468..bfaeb21 100644
--- a/media/libstagefright/avc_utils.cpp
+++ b/media/libstagefright/foundation/avc_utils.cpp
@@ -18,10 +18,10 @@
 #define LOG_TAG "avc_utils"
 #include <utils/Log.h>
 
-#include "include/avc_utils.h"
 
 #include <media/stagefright/foundation/ABitReader.h>
 #include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/avc_utils.h>
 #include <media/stagefright/foundation/hexdump.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaErrors.h>
@@ -468,11 +468,9 @@
     return meta;
 }
 
-template <typename T>
-bool IsIDRInternal(const sp<T> &buffer) {
-    const uint8_t *data = buffer->data();
-    size_t size = buffer->size();
-
+bool IsIDR(const uint8_t *data, size_t size) {
+//    const uint8_t *data = buffer->data();
+//    size_t size = buffer->size();
     bool foundIDR = false;
 
     const uint8_t *nalStart;
@@ -494,14 +492,6 @@
     return foundIDR;
 }
 
-bool IsIDR(const sp<ABuffer> &buffer) {
-    return IsIDRInternal(buffer);
-}
-
-bool IsIDR(const sp<MediaCodecBuffer> &buffer) {
-    return IsIDRInternal(buffer);
-}
-
 bool IsAVCReferenceFrame(const sp<ABuffer> &accessUnit) {
     const uint8_t *data = accessUnit->data();
     size_t size = accessUnit->size();
diff --git a/media/libstagefright/foundation/include/media/stagefright/foundation/MediaDefs.h b/media/libstagefright/foundation/include/media/stagefright/foundation/MediaDefs.h
index 7f17013..25be89f 100644
--- a/media/libstagefright/foundation/include/media/stagefright/foundation/MediaDefs.h
+++ b/media/libstagefright/foundation/include/media/stagefright/foundation/MediaDefs.h
@@ -21,6 +21,7 @@
 namespace android {
 
 extern const char *MEDIA_MIMETYPE_IMAGE_JPEG;
+extern const char *MEDIA_MIMETYPE_IMAGE_ANDROID_HEIC;
 
 extern const char *MEDIA_MIMETYPE_VIDEO_VP8;
 extern const char *MEDIA_MIMETYPE_VIDEO_VP9;
@@ -60,6 +61,7 @@
 extern const char *MEDIA_MIMETYPE_CONTAINER_MPEG2TS;
 extern const char *MEDIA_MIMETYPE_CONTAINER_AVI;
 extern const char *MEDIA_MIMETYPE_CONTAINER_MPEG2PS;
+extern const char *MEDIA_MIMETYPE_CONTAINER_HEIF;
 
 extern const char *MEDIA_MIMETYPE_TEXT_3GPP;
 extern const char *MEDIA_MIMETYPE_TEXT_SUBRIP;
diff --git a/media/libstagefright/include/avc_utils.h b/media/libstagefright/foundation/include/media/stagefright/foundation/avc_utils.h
similarity index 97%
rename from media/libstagefright/include/avc_utils.h
rename to media/libstagefright/foundation/include/media/stagefright/foundation/avc_utils.h
index d05906a..f4eb692 100644
--- a/media/libstagefright/include/avc_utils.h
+++ b/media/libstagefright/foundation/include/media/stagefright/foundation/avc_utils.h
@@ -84,8 +84,7 @@
 class MetaData;
 sp<MetaData> MakeAVCCodecSpecificData(const sp<ABuffer> &accessUnit);
 
-bool IsIDR(const sp<ABuffer> &accessUnit);
-bool IsIDR(const sp<MediaCodecBuffer> &accessUnit);
+bool IsIDR(const uint8_t *data, size_t size);
 bool IsAVCReferenceFrame(const sp<ABuffer> &accessUnit);
 uint32_t FindAVCLayerId(const uint8_t *data, size_t size);
 
diff --git a/media/libstagefright/httplive/Android.bp b/media/libstagefright/httplive/Android.bp
index b10585e..ac113b8 100644
--- a/media/libstagefright/httplive/Android.bp
+++ b/media/libstagefright/httplive/Android.bp
@@ -36,6 +36,7 @@
         "libcrypto",
         "libcutils",
         "libmedia",
+        "libmediaextractor",
         "libstagefright",
         "libstagefright_foundation",
         "libutils",
diff --git a/media/libstagefright/httplive/HTTPDownloader.cpp b/media/libstagefright/httplive/HTTPDownloader.cpp
index 793695a..3fef764 100644
--- a/media/libstagefright/httplive/HTTPDownloader.cpp
+++ b/media/libstagefright/httplive/HTTPDownloader.cpp
@@ -21,12 +21,12 @@
 #include "HTTPDownloader.h"
 #include "M3UParser.h"
 
+#include <media/DataSource.h>
 #include <media/IMediaHTTPConnection.h>
 #include <media/IMediaHTTPService.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/MediaHTTP.h>
-#include <media/stagefright/DataSource.h>
 #include <media/stagefright/FileSource.h>
 #include <openssl/aes.h>
 #include <openssl/md5.h>
diff --git a/media/libstagefright/httplive/LiveDataSource.h b/media/libstagefright/httplive/LiveDataSource.h
index b7be637..91e9f9f 100644
--- a/media/libstagefright/httplive/LiveDataSource.h
+++ b/media/libstagefright/httplive/LiveDataSource.h
@@ -18,8 +18,8 @@
 
 #define LIVE_DATA_SOURCE_H_
 
+#include <media/DataSource.h>
 #include <media/stagefright/foundation/ABase.h>
-#include <media/stagefright/DataSource.h>
 #include <utils/threads.h>
 #include <utils/List.h>
 
diff --git a/media/libstagefright/httplive/PlaylistFetcher.cpp b/media/libstagefright/httplive/PlaylistFetcher.cpp
index a789b35..b46694b 100644
--- a/media/libstagefright/httplive/PlaylistFetcher.cpp
+++ b/media/libstagefright/httplive/PlaylistFetcher.cpp
@@ -23,7 +23,6 @@
 #include "HTTPDownloader.h"
 #include "LiveSession.h"
 #include "M3UParser.h"
-#include "include/avc_utils.h"
 #include "include/ID3.h"
 #include "mpeg2ts/AnotherPacketSource.h"
 #include "mpeg2ts/HlsSampleDecryptor.h"
@@ -32,6 +31,7 @@
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/ByteUtils.h>
+#include <media/stagefright/foundation/avc_utils.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MetaData.h>
 #include <media/stagefright/Utils.h>
@@ -1829,7 +1829,7 @@
                             (long long)timeUs - mStartTimeUs,
                             mIDRFound);
                     if (isAvc) {
-                        if (IsIDR(accessUnit)) {
+                        if (IsIDR(accessUnit->data(), accessUnit->size())) {
                             mVideoBuffer->clear();
                             FSLOGV(stream, "found IDR, clear mVideoBuffer");
                             mIDRFound = true;
diff --git a/media/libstagefright/id3/ID3.cpp b/media/libstagefright/id3/ID3.cpp
index 1fd51a5..61403be 100644
--- a/media/libstagefright/id3/ID3.cpp
+++ b/media/libstagefright/id3/ID3.cpp
@@ -20,9 +20,9 @@
 
 #include "../include/ID3.h"
 
+#include <media/DataSource.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/ByteUtils.h>
-#include <media/stagefright/DataSource.h>
 #include <utils/String8.h>
 #include <byteswap.h>
 
@@ -392,7 +392,12 @@
                     --mSize;
                     --dataSize;
                 }
-                mData[writeOffset++] = mData[readOffset++];
+                if (i + 1 < dataSize) {
+                    // Only move data if there's actually something to move.
+                    // This handles the special case of the data being only [0xff, 0x00]
+                    // which should be converted to just 0xff if unsynchronization is on.
+                    mData[writeOffset++] = mData[readOffset++];
+                }
             }
             // move the remaining data following this frame
             if (readOffset <= oldSize) {
diff --git a/media/libstagefright/include/AVIExtractor.h b/media/libstagefright/include/AVIExtractor.h
index 3be505c..1223c80 100644
--- a/media/libstagefright/include/AVIExtractor.h
+++ b/media/libstagefright/include/AVIExtractor.h
@@ -18,9 +18,9 @@
 
 #define AVI_EXTRACTOR_H_
 
+#include <media/MediaExtractor.h>
+#include <media/MediaSource.h>
 #include <media/stagefright/foundation/ABase.h>
-#include <media/stagefright/MediaExtractor.h>
-#include <media/stagefright/MediaSource.h>
 #include <utils/Vector.h>
 
 namespace android {
diff --git a/media/libstagefright/include/CallbackDataSource.h b/media/libstagefright/include/CallbackDataSource.h
index 0d775e6..9f413cd 100644
--- a/media/libstagefright/include/CallbackDataSource.h
+++ b/media/libstagefright/include/CallbackDataSource.h
@@ -17,7 +17,7 @@
 #ifndef ANDROID_CALLBACKDATASOURCE_H
 #define ANDROID_CALLBACKDATASOURCE_H
 
-#include <media/stagefright/DataSource.h>
+#include <media/DataSource.h>
 #include <media/stagefright/foundation/ADebug.h>
 
 namespace android {
diff --git a/media/libstagefright/include/FrameDecoder.h b/media/libstagefright/include/FrameDecoder.h
new file mode 100644
index 0000000..d7c074c
--- /dev/null
+++ b/media/libstagefright/include/FrameDecoder.h
@@ -0,0 +1,176 @@
+/*
+ * 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.
+ */
+
+#ifndef FRAME_DECODER_H_
+#define FRAME_DECODER_H_
+
+#include <media/stagefright/foundation/AString.h>
+#include <media/stagefright/foundation/ABase.h>
+#include <media/MediaSource.h>
+#include <media/openmax/OMX_Video.h>
+#include <system/graphics-base.h>
+
+namespace android {
+
+struct AMessage;
+class MediaCodecBuffer;
+class VideoFrame;
+
+struct FrameDecoder {
+    FrameDecoder(
+            const AString &componentName,
+            const sp<MetaData> &trackMeta,
+            const sp<IMediaSource> &source) :
+                mComponentName(componentName),
+                mTrackMeta(trackMeta),
+                mSource(source),
+                mDstFormat(OMX_COLOR_Format16bitRGB565),
+                mDstBpp(2) {}
+
+    VideoFrame* extractFrame(
+            int64_t frameTimeUs,
+            int option,
+            int colorFormat,
+            bool metaOnly);
+
+    status_t extractFrames(
+            int64_t frameTimeUs,
+            size_t numFrames,
+            int option,
+            int colorFormat,
+            std::vector<VideoFrame*>* frames);
+
+protected:
+    virtual ~FrameDecoder() {}
+
+    virtual sp<AMessage> onGetFormatAndSeekOptions(
+            int64_t frameTimeUs,
+            size_t numFrames,
+            int seekMode,
+            MediaSource::ReadOptions *options) = 0;
+
+    virtual status_t onInputReceived(
+            const sp<MediaCodecBuffer> &codecBuffer,
+            const sp<MetaData> &sampleMeta,
+            bool firstSample,
+            uint32_t *flags) = 0;
+
+    virtual status_t onOutputReceived(
+            const sp<MediaCodecBuffer> &videoFrameBuffer,
+            const sp<AMessage> &outputFormat,
+            int64_t timeUs,
+            bool *done) = 0;
+
+    VideoFrame *allocVideoFrame(int32_t width, int32_t height, bool metaOnly);
+
+    sp<MetaData> trackMeta()     const      { return mTrackMeta; }
+    OMX_COLOR_FORMATTYPE dstFormat() const  { return mDstFormat; }
+    int32_t dstBpp()             const      { return mDstBpp; }
+
+    void addFrame(VideoFrame *frame) {
+        mFrames.push_back(std::unique_ptr<VideoFrame>(frame));
+    }
+
+private:
+    AString mComponentName;
+    sp<MetaData> mTrackMeta;
+    sp<IMediaSource> mSource;
+    OMX_COLOR_FORMATTYPE mDstFormat;
+    int32_t mDstBpp;
+    std::vector<std::unique_ptr<VideoFrame> > mFrames;
+
+    bool setDstColorFormat(android_pixel_format_t colorFormat);
+    status_t extractInternal(int64_t frameTimeUs, size_t numFrames, int option);
+
+    DISALLOW_EVIL_CONSTRUCTORS(FrameDecoder);
+};
+
+struct VideoFrameDecoder : public FrameDecoder {
+    VideoFrameDecoder(
+            const AString &componentName,
+            const sp<MetaData> &trackMeta,
+            const sp<IMediaSource> &source) :
+                FrameDecoder(componentName, trackMeta, source),
+                mIsAvcOrHevc(false),
+                mSeekMode(MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC),
+                mTargetTimeUs(-1ll),
+                mNumFrames(0),
+                mNumFramesDecoded(0) {}
+
+protected:
+    virtual sp<AMessage> onGetFormatAndSeekOptions(
+            int64_t frameTimeUs,
+            size_t numFrames,
+            int seekMode,
+            MediaSource::ReadOptions *options) override;
+
+    virtual status_t onInputReceived(
+            const sp<MediaCodecBuffer> &codecBuffer,
+            const sp<MetaData> &sampleMeta,
+            bool firstSample,
+            uint32_t *flags) override;
+
+    virtual status_t onOutputReceived(
+            const sp<MediaCodecBuffer> &videoFrameBuffer,
+            const sp<AMessage> &outputFormat,
+            int64_t timeUs,
+            bool *done) override;
+
+private:
+    bool mIsAvcOrHevc;
+    MediaSource::ReadOptions::SeekMode mSeekMode;
+    int64_t mTargetTimeUs;
+    size_t mNumFrames;
+    size_t mNumFramesDecoded;
+};
+
+struct ImageDecoder : public FrameDecoder {
+    ImageDecoder(
+            const AString &componentName,
+            const sp<MetaData> &trackMeta,
+            const sp<IMediaSource> &source) :
+                FrameDecoder(componentName, trackMeta, source),
+                mFrame(NULL), mGridRows(1), mGridCols(1), mTilesDecoded(0) {}
+
+protected:
+    virtual sp<AMessage> onGetFormatAndSeekOptions(
+            int64_t frameTimeUs,
+            size_t numFrames,
+            int seekMode,
+            MediaSource::ReadOptions *options) override;
+
+    virtual status_t onInputReceived(
+            const sp<MediaCodecBuffer> &codecBuffer __unused,
+            const sp<MetaData> &sampleMeta __unused,
+            bool firstSample __unused,
+            uint32_t *flags __unused) override { return OK; }
+
+    virtual status_t onOutputReceived(
+            const sp<MediaCodecBuffer> &videoFrameBuffer,
+            const sp<AMessage> &outputFormat,
+            int64_t timeUs,
+            bool *done) override;
+
+private:
+    VideoFrame *mFrame;
+    int32_t mGridRows;
+    int32_t mGridCols;
+    int32_t mTilesDecoded;
+};
+
+}  // namespace android
+
+#endif  // FRAME_DECODER_H_
diff --git a/media/libstagefright/include/HTTPBase.h b/media/libstagefright/include/HTTPBase.h
index d325e30..26d7e8a 100644
--- a/media/libstagefright/include/HTTPBase.h
+++ b/media/libstagefright/include/HTTPBase.h
@@ -18,8 +18,8 @@
 
 #define HTTP_BASE_H_
 
+#include <media/DataSource.h>
 #include <media/stagefright/foundation/ABase.h>
-#include <media/stagefright/DataSource.h>
 #include <media/stagefright/MediaErrors.h>
 #include <utils/threads.h>
 
diff --git a/media/libstagefright/include/NuCachedSource2.h b/media/libstagefright/include/NuCachedSource2.h
index 2639280..1a34817 100644
--- a/media/libstagefright/include/NuCachedSource2.h
+++ b/media/libstagefright/include/NuCachedSource2.h
@@ -18,9 +18,9 @@
 
 #define NU_CACHED_SOURCE_2_H_
 
+#include <media/DataSource.h>
 #include <media/stagefright/foundation/ABase.h>
 #include <media/stagefright/foundation/AHandlerReflector.h>
-#include <media/stagefright/DataSource.h>
 
 namespace android {
 
diff --git a/media/libstagefright/include/OmxNodeOwner.h b/media/libstagefright/include/OmxNodeOwner.h
deleted file mode 100644
index 64ec7f7..0000000
--- a/media/libstagefright/include/OmxNodeOwner.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2016 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 OMX_NODE_OWNER_H_
-
-#define OMX_NODE_OWNER_H_
-
-namespace android {
-
-struct OMXNodeInstance;
-
-/**
- * This struct is needed to separate OMX from OMXNodeInstance.
- *
- * TODO: This might not be needed after Treble transition is complete.
- */
-struct OmxNodeOwner {
-    virtual status_t freeNode(const sp<OMXNodeInstance> &instance) = 0;
-    virtual ~OmxNodeOwner() {}
-};
-
-}
-
-#endif  // OMX_NODE_OWNER_H_
diff --git a/media/libstagefright/include/StagefrightMetadataRetriever.h b/media/libstagefright/include/StagefrightMetadataRetriever.h
index 277eb3e..58442fe 100644
--- a/media/libstagefright/include/StagefrightMetadataRetriever.h
+++ b/media/libstagefright/include/StagefrightMetadataRetriever.h
@@ -40,7 +40,14 @@
     virtual status_t setDataSource(int fd, int64_t offset, int64_t length);
     virtual status_t setDataSource(const sp<DataSource>& source, const char *mime);
 
-    virtual VideoFrame *getFrameAtTime(int64_t timeUs, int option, int colorFormat, bool metaOnly);
+    virtual VideoFrame* getFrameAtTime(
+            int64_t timeUs, int option, int colorFormat, bool metaOnly);
+    virtual VideoFrame* getImageAtIndex(
+            int index, int colorFormat, bool metaOnly);
+    virtual status_t getFrameAtIndex(
+            std::vector<VideoFrame*>* frames,
+            int frameIndex, int numFrames, int colorFormat, bool metaOnly);
+
     virtual MediaAlbumArt *extractAlbumArt();
     virtual const char *extractMetadata(int keyCode);
 
@@ -56,6 +63,10 @@
     // Delete album art and clear metadata.
     void clearMetadata();
 
+    status_t getFrameInternal(
+            int64_t timeUs, int numFrames, int option, int colorFormat, bool metaOnly,
+            VideoFrame **outFrame, std::vector<VideoFrame*>* outFrames);
+
     StagefrightMetadataRetriever(const StagefrightMetadataRetriever &);
 
     StagefrightMetadataRetriever &operator=(
diff --git a/media/libstagefright/include/ThrottledSource.h b/media/libstagefright/include/ThrottledSource.h
index 673268b..8ef298a 100644
--- a/media/libstagefright/include/ThrottledSource.h
+++ b/media/libstagefright/include/ThrottledSource.h
@@ -18,7 +18,7 @@
 
 #define THROTTLED_SOURCE_H_
 
-#include <media/stagefright/DataSource.h>
+#include <media/DataSource.h>
 #include <utils/threads.h>
 
 namespace android {
diff --git a/media/libstagefright/include/media/stagefright/ACodec.h b/media/libstagefright/include/media/stagefright/ACodec.h
index 424246d..d1a9d25 100644
--- a/media/libstagefright/include/media/stagefright/ACodec.h
+++ b/media/libstagefright/include/media/stagefright/ACodec.h
@@ -95,11 +95,6 @@
 
     static status_t getOMXChannelMapping(size_t numChannels, OMX_AUDIO_CHANNELTYPE map[]);
 
-    // Save the flag.
-    void setTrebleFlag(bool trebleFlag);
-    // Return the saved flag.
-    bool getTrebleFlag() const;
-
 protected:
     virtual ~ACodec();
 
@@ -233,9 +228,7 @@
     sp<IOMX> mOMX;
     sp<IOMXNode> mOMXNode;
     int32_t mNodeGeneration;
-    bool mTrebleFlag;
     sp<TAllocator> mAllocator[2];
-    sp<MemoryDealer> mDealer[2];
 
     bool mUsingNativeWindow;
     sp<ANativeWindow> mNativeWindow;
diff --git a/media/libstagefright/include/media/stagefright/AudioPlayer.h b/media/libstagefright/include/media/stagefright/AudioPlayer.h
index 581ead9..e971762 100644
--- a/media/libstagefright/include/media/stagefright/AudioPlayer.h
+++ b/media/libstagefright/include/media/stagefright/AudioPlayer.h
@@ -18,9 +18,9 @@
 
 #define AUDIO_PLAYER_H_
 
+#include <media/MediaSource.h>
 #include <media/MediaPlayerInterface.h>
 #include <media/stagefright/MediaBuffer.h>
-#include <media/stagefright/MediaSource.h>
 #include <utils/threads.h>
 
 namespace android {
diff --git a/media/libstagefright/include/media/stagefright/AudioSource.h b/media/libstagefright/include/media/stagefright/AudioSource.h
index 1595be4..4984f69 100644
--- a/media/libstagefright/include/media/stagefright/AudioSource.h
+++ b/media/libstagefright/include/media/stagefright/AudioSource.h
@@ -20,7 +20,7 @@
 
 #include <media/AudioRecord.h>
 #include <media/AudioSystem.h>
-#include <media/stagefright/MediaSource.h>
+#include <media/MediaSource.h>
 #include <media/stagefright/MediaBuffer.h>
 #include <utils/List.h>
 
diff --git a/media/libstagefright/include/media/stagefright/CallbackMediaSource.h b/media/libstagefright/include/media/stagefright/CallbackMediaSource.h
index 17fca4e..a09348f 100644
--- a/media/libstagefright/include/media/stagefright/CallbackMediaSource.h
+++ b/media/libstagefright/include/media/stagefright/CallbackMediaSource.h
@@ -17,7 +17,7 @@
 #ifndef CALLBACK_MEDIA_SOURCE_H_
 #define CALLBACK_MEDIA_SOURCE_H_
 
-#include <media/stagefright/MediaSource.h>
+#include <media/MediaSource.h>
 #include <media/stagefright/foundation/ABase.h>
 
 namespace android {
diff --git a/media/libstagefright/include/media/stagefright/CameraSource.h b/media/libstagefright/include/media/stagefright/CameraSource.h
index d6149c0..945e1be 100644
--- a/media/libstagefright/include/media/stagefright/CameraSource.h
+++ b/media/libstagefright/include/media/stagefright/CameraSource.h
@@ -19,8 +19,8 @@
 #define CAMERA_SOURCE_H_
 
 #include <deque>
+#include <media/MediaSource.h>
 #include <media/stagefright/MediaBuffer.h>
-#include <media/stagefright/MediaSource.h>
 #include <camera/android/hardware/ICamera.h>
 #include <camera/ICameraRecordingProxy.h>
 #include <camera/ICameraRecordingProxyListener.h>
diff --git a/media/libstagefright/include/media/stagefright/DataSourceFactory.h b/media/libstagefright/include/media/stagefright/DataSourceFactory.h
new file mode 100644
index 0000000..89add13
--- /dev/null
+++ b/media/libstagefright/include/media/stagefright/DataSourceFactory.h
@@ -0,0 +1,45 @@
+/*
+ * 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.
+ */
+
+#ifndef DATA_SOURCE_FACTORY_H_
+
+#define DATA_SOURCE_FACTORY_H_
+
+#include <sys/types.h>
+#include <utils/RefBase.h>
+
+namespace android {
+
+struct IMediaHTTPService;
+class String8;
+struct HTTPBase;
+
+class DataSourceFactory {
+public:
+    static sp<DataSource> CreateFromURI(
+            const sp<IMediaHTTPService> &httpService,
+            const char *uri,
+            const KeyedVector<String8, String8> *headers = NULL,
+            String8 *contentType = NULL,
+            HTTPBase *httpSource = NULL);
+
+    static sp<DataSource> CreateMediaHTTP(const sp<IMediaHTTPService> &httpService);
+    static sp<DataSource> CreateFromFd(int fd, int64_t offset, int64_t length);
+};
+
+}  // namespace android
+
+#endif  // DATA_SOURCE_FACTORY_H_
diff --git a/media/libstagefright/include/media/stagefright/DataURISource.h b/media/libstagefright/include/media/stagefright/DataURISource.h
index 693562e..cf8d68e 100644
--- a/media/libstagefright/include/media/stagefright/DataURISource.h
+++ b/media/libstagefright/include/media/stagefright/DataURISource.h
@@ -18,7 +18,7 @@
 
 #define DATA_URI_SOURCE_H_
 
-#include <media/stagefright/DataSource.h>
+#include <media/DataSource.h>
 #include <media/stagefright/foundation/ABase.h>
 
 namespace android {
diff --git a/media/libstagefright/include/media/stagefright/FileSource.h b/media/libstagefright/include/media/stagefright/FileSource.h
index 7267e9a..b4b5c3c 100644
--- a/media/libstagefright/include/media/stagefright/FileSource.h
+++ b/media/libstagefright/include/media/stagefright/FileSource.h
@@ -20,7 +20,7 @@
 
 #include <stdio.h>
 
-#include <media/stagefright/DataSource.h>
+#include <media/DataSource.h>
 #include <media/stagefright/MediaErrors.h>
 #include <utils/threads.h>
 #include <drm/DrmManagerClient.h>
diff --git a/media/libstagefright/include/media/stagefright/InterfaceUtils.h b/media/libstagefright/include/media/stagefright/InterfaceUtils.h
new file mode 100644
index 0000000..783f109
--- /dev/null
+++ b/media/libstagefright/include/media/stagefright/InterfaceUtils.h
@@ -0,0 +1,44 @@
+/*
+ * 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.
+ */
+
+#ifndef INTERFACE_UTILS_H_
+#define INTERFACE_UTILS_H_
+
+#include <media/MediaExtractor.h>
+#include <media/MediaSource.h>
+#include <media/IMediaExtractor.h>
+#include <media/IMediaSource.h>
+
+namespace android {
+
+// Creates a DataSource which wraps the given IDataSource object.
+sp<DataSource> CreateDataSourceFromIDataSource(const sp<IDataSource> &source);
+
+// creates an IDataSource wrapper to the DataSource.
+sp<IDataSource> CreateIDataSourceFromDataSource(const sp<DataSource> &source);
+
+// Creates an IMediaExtractor wrapper to the given MediaExtractor.
+sp<IMediaExtractor> CreateIMediaExtractorFromMediaExtractor(const sp<MediaExtractor> &extractor);
+
+// 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);
+
+}  // namespace android
+
+#endif  // INTERFACE_UTILS_H_
diff --git a/media/libstagefright/include/media/stagefright/JPEGSource.h b/media/libstagefright/include/media/stagefright/JPEGSource.h
index 1b7e91b..9fcbfc2 100644
--- a/media/libstagefright/include/media/stagefright/JPEGSource.h
+++ b/media/libstagefright/include/media/stagefright/JPEGSource.h
@@ -18,7 +18,7 @@
 
 #define JPEG_SOURCE_H_
 
-#include <media/stagefright/MediaSource.h>
+#include <media/MediaSource.h>
 
 namespace android {
 
diff --git a/media/libstagefright/include/media/stagefright/MediaAdapter.h b/media/libstagefright/include/media/stagefright/MediaAdapter.h
index 369fce6..4b47160 100644
--- a/media/libstagefright/include/media/stagefright/MediaAdapter.h
+++ b/media/libstagefright/include/media/stagefright/MediaAdapter.h
@@ -17,8 +17,8 @@
 #ifndef MEDIA_ADAPTER_H
 #define MEDIA_ADAPTER_H
 
+#include <media/MediaSource.h>
 #include <media/stagefright/foundation/ABase.h>
-#include <media/stagefright/MediaSource.h>
 #include <media/stagefright/MediaBuffer.h>
 #include <media/stagefright/MetaData.h>
 #include <utils/threads.h>
diff --git a/media/libstagefright/include/media/stagefright/MediaCodecSource.h b/media/libstagefright/include/media/stagefright/MediaCodecSource.h
index 3ac539e..bc0653d 100644
--- a/media/libstagefright/include/media/stagefright/MediaCodecSource.h
+++ b/media/libstagefright/include/media/stagefright/MediaCodecSource.h
@@ -17,10 +17,10 @@
 #ifndef MediaCodecSource_H_
 #define MediaCodecSource_H_
 
+#include <media/MediaSource.h>
 #include <media/stagefright/foundation/ABase.h>
 #include <media/stagefright/foundation/AHandlerReflector.h>
 #include <media/stagefright/foundation/Mutexed.h>
-#include <media/stagefright/MediaSource.h>
 #include <media/stagefright/PersistentSurface.h>
 
 namespace android {
diff --git a/media/libstagefright/include/media/stagefright/MediaExtractorFactory.h b/media/libstagefright/include/media/stagefright/MediaExtractorFactory.h
new file mode 100644
index 0000000..96298f9
--- /dev/null
+++ b/media/libstagefright/include/media/stagefright/MediaExtractorFactory.h
@@ -0,0 +1,52 @@
+/*
+ * 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.
+ */
+
+#ifndef MEDIA_EXTRACTOR_FACTORY_H_
+
+#define MEDIA_EXTRACTOR_FACTORY_H_
+
+#include <stdio.h>
+
+#include <media/IMediaExtractor.h>
+#include <media/MediaExtractor.h>
+
+namespace android {
+
+class DataSource;
+
+class MediaExtractorFactory {
+public:
+    static sp<IMediaExtractor> Create(
+            const sp<DataSource> &source, const char *mime = NULL);
+    static sp<MediaExtractor> CreateFromService(
+            const sp<DataSource> &source, const char *mime = NULL);
+
+private:
+    static Mutex gSnifferMutex;
+    static List<MediaExtractor::ExtractorDef> gSniffers;
+    static bool gSniffersRegistered;
+
+    static void RegisterSniffer_l(const MediaExtractor::ExtractorDef &def);
+
+    static MediaExtractor::CreatorFunc sniff(const sp<DataSource> &source,
+            String8 *mimeType, float *confidence, sp<AMessage> *meta);
+
+    static void RegisterDefaultSniffers();
+};
+
+}  // namespace android
+
+#endif  // MEDIA_EXTRACTOR_FACTORY_H_
diff --git a/media/libstagefright/include/media/stagefright/MediaWriter.h b/media/libstagefright/include/media/stagefright/MediaWriter.h
index 80c5358..c4bba0e 100644
--- a/media/libstagefright/include/media/stagefright/MediaWriter.h
+++ b/media/libstagefright/include/media/stagefright/MediaWriter.h
@@ -19,8 +19,8 @@
 #define MEDIA_WRITER_H_
 
 #include <utils/RefBase.h>
+#include <media/MediaSource.h>
 #include <media/IMediaRecorderClient.h>
-#include <media/stagefright/MediaSource.h>
 
 namespace android {
 
diff --git a/media/libstagefright/include/media/stagefright/MetaData.h b/media/libstagefright/include/media/stagefright/MetaData.h
index 6cfde9c..3438c56 100644
--- a/media/libstagefright/include/media/stagefright/MetaData.h
+++ b/media/libstagefright/include/media/stagefright/MetaData.h
@@ -215,7 +215,11 @@
 
     kKeyGridWidth        = 'grdW', // int32_t, HEIF grid width
     kKeyGridHeight       = 'grdH', // int32_t, HEIF grid height
+    kKeyGridRows         = 'grdR', // int32_t, HEIF grid rows
+    kKeyGridCols         = 'grdC', // int32_t, HEIF grid columns
     kKeyIccProfile       = 'prof', // raw data, ICC prifile data
+    kKeyIsPrimaryImage   = 'prim', // bool (int32_t), image track is the primary image
+    kKeyFrameCount       = 'nfrm', // int32_t, total number of frame in video track
 };
 
 enum {
diff --git a/media/libstagefright/include/media/stagefright/NuMediaExtractor.h b/media/libstagefright/include/media/stagefright/NuMediaExtractor.h
index 6a93bd5..5af0745 100644
--- a/media/libstagefright/include/media/stagefright/NuMediaExtractor.h
+++ b/media/libstagefright/include/media/stagefright/NuMediaExtractor.h
@@ -17,9 +17,11 @@
 #ifndef NU_MEDIA_EXTRACTOR_H_
 #define NU_MEDIA_EXTRACTOR_H_
 
+#include <list>
+#include <media/mediaplayer.h>
 #include <media/stagefright/foundation/ABase.h>
-#include <media/stagefright/MediaSource.h>
 #include <media/IMediaExtractor.h>
+#include <media/MediaSource.h>
 #include <utils/Errors.h>
 #include <utils/KeyedVector.h>
 #include <utils/RefBase.h>
@@ -67,7 +69,9 @@
 
     status_t getFileFormat(sp<AMessage> *format) const;
 
-    status_t selectTrack(size_t index);
+    status_t selectTrack(size_t index, int64_t startTimeUs = -1ll,
+            MediaSource::ReadOptions::SeekMode mode =
+                MediaSource::ReadOptions::SEEK_CLOSEST_SYNC);
     status_t unselectTrack(size_t index);
 
     status_t seekTo(
@@ -75,8 +79,12 @@
             MediaSource::ReadOptions::SeekMode mode =
                 MediaSource::ReadOptions::SEEK_CLOSEST_SYNC);
 
+    // Each selected track has a read pointer.
+    // advance() advances the read pointer with the lowest timestamp.
     status_t advance();
+    // readSampleData() reads the sample with the lowest timestamp.
     status_t readSampleData(const sp<ABuffer> &buffer);
+
     status_t getSampleTrackIndex(size_t *trackIndex);
     status_t getSampleTime(int64_t *sampleTimeUs);
     status_t getSampleMeta(sp<MetaData> *sampleMeta);
@@ -96,12 +104,20 @@
         kMaxTrackCount = 16384,
     };
 
+    struct Sample {
+        Sample();
+        Sample(MediaBuffer *buffer, int64_t timeUs);
+        MediaBuffer *mBuffer;
+        int64_t mSampleTimeUs;
+    };
+
     struct TrackInfo {
         sp<IMediaSource> mSource;
         size_t mTrackIndex;
+        media_track_type mTrackType;
+        size_t mMaxFetchCount;
         status_t mFinalResult;
-        MediaBuffer *mSample;
-        int64_t mSampleTimeUs;
+        std::list<Sample> mSamples;
 
         uint32_t mTrackFlags;  // bitmask of "TrackFlags"
     };
@@ -117,16 +133,23 @@
     int64_t mTotalBitrate;  // in bits/sec
     int64_t mDurationUs;
 
-    ssize_t fetchTrackSamples(
+    ssize_t fetchAllTrackSamples(
+            int64_t seekTimeUs = -1ll,
+            MediaSource::ReadOptions::SeekMode mode =
+                MediaSource::ReadOptions::SEEK_CLOSEST_SYNC);
+    void fetchTrackSamples(
+            TrackInfo *info,
             int64_t seekTimeUs = -1ll,
             MediaSource::ReadOptions::SeekMode mode =
                 MediaSource::ReadOptions::SEEK_CLOSEST_SYNC);
 
-    void releaseTrackSamples();
+    void releaseOneSample(TrackInfo *info);
+    void releaseTrackSamples(TrackInfo *info);
+    void releaseAllTrackSamples();
 
     bool getTotalBitrate(int64_t *bitRate) const;
     status_t updateDurationAndBitrate();
-    status_t appendVorbisNumPageSamples(TrackInfo *info, const sp<ABuffer> &buffer);
+    status_t appendVorbisNumPageSamples(MediaBuffer *mbuf, const sp<ABuffer> &buffer);
 
     DISALLOW_EVIL_CONSTRUCTORS(NuMediaExtractor);
 };
diff --git a/media/libstagefright/include/media/stagefright/OMXClient.h b/media/libstagefright/include/media/stagefright/OMXClient.h
index b1864b8..e7b9be5 100644
--- a/media/libstagefright/include/media/stagefright/OMXClient.h
+++ b/media/libstagefright/include/media/stagefright/OMXClient.h
@@ -18,25 +18,19 @@
 
 #define OMX_CLIENT_H_
 
-#include <media/IOMX.h>
-
 namespace android {
 
+class IOMX;
+
 class OMXClient {
 public:
     OMXClient();
 
-    status_t connect();
-    status_t connect(bool* trebleFlag);
-    status_t connect(const char* name, bool* trebleFlag = nullptr);
+    status_t connect(const char* name = "default");
 
-    status_t connectLegacy();
-    status_t connectTreble(const char* name = "default");
     void disconnect();
 
-    sp<IOMX> interface() {
-        return mOMX;
-    }
+    sp<IOMX> interface();
 
 private:
     sp<IOMX> mOMX;
diff --git a/media/libstagefright/include/media/stagefright/RemoteDataSource.h b/media/libstagefright/include/media/stagefright/RemoteDataSource.h
index c91ddfc..e191e6a 100644
--- a/media/libstagefright/include/media/stagefright/RemoteDataSource.h
+++ b/media/libstagefright/include/media/stagefright/RemoteDataSource.h
@@ -19,8 +19,8 @@
 
 #include <binder/IMemory.h>
 #include <binder/MemoryDealer.h>
+#include <media/DataSource.h>
 #include <media/IDataSource.h>
-#include <media/stagefright/DataSource.h>
 
 namespace android {
 
diff --git a/media/libstagefright/include/media/stagefright/RemoteMediaExtractor.h b/media/libstagefright/include/media/stagefright/RemoteMediaExtractor.h
index 96611d1..b5a4b34 100644
--- a/media/libstagefright/include/media/stagefright/RemoteMediaExtractor.h
+++ b/media/libstagefright/include/media/stagefright/RemoteMediaExtractor.h
@@ -18,7 +18,7 @@
 #define REMOTE_MEDIA_EXTRACTOR_H_
 
 #include <media/IMediaExtractor.h>
-#include <media/stagefright/MediaExtractor.h>
+#include <media/MediaExtractor.h>
 
 namespace android {
 
diff --git a/media/libstagefright/include/media/stagefright/RemoteMediaSource.h b/media/libstagefright/include/media/stagefright/RemoteMediaSource.h
index 2731114..ba5414a 100644
--- a/media/libstagefright/include/media/stagefright/RemoteMediaSource.h
+++ b/media/libstagefright/include/media/stagefright/RemoteMediaSource.h
@@ -18,7 +18,7 @@
 #define REMOTE_MEDIA_SOURCE_H_
 
 #include <media/IMediaSource.h>
-#include <media/stagefright/MediaSource.h>
+#include <media/MediaSource.h>
 #include <media/stagefright/foundation/ABase.h>
 
 namespace android {
@@ -32,7 +32,8 @@
     virtual status_t stop();
     virtual sp<MetaData> getFormat();
     virtual status_t read(
-            MediaBuffer **buffer, const ReadOptions *options = NULL);
+            MediaBuffer **buffer,
+            const MediaSource::ReadOptions *options = NULL);
     virtual status_t pause();
     virtual status_t setBuffers(const Vector<MediaBuffer *> &buffers);
     virtual status_t setStopTimeUs(int64_t stopTimeUs);
diff --git a/media/libstagefright/include/media/stagefright/SimpleDecodingSource.h b/media/libstagefright/include/media/stagefright/SimpleDecodingSource.h
index b8d141a..5060dc1 100644
--- a/media/libstagefright/include/media/stagefright/SimpleDecodingSource.h
+++ b/media/libstagefright/include/media/stagefright/SimpleDecodingSource.h
@@ -17,7 +17,7 @@
 #ifndef SIMPLE_DECODING_SOURCE_H_
 #define SIMPLE_DECODING_SOURCE_H_
 
-#include <media/stagefright/MediaSource.h>
+#include <media/MediaSource.h>
 #include <media/stagefright/foundation/AString.h>
 #include <media/stagefright/foundation/Mutexed.h>
 
diff --git a/media/libstagefright/include/media/stagefright/SurfaceMediaSource.h b/media/libstagefright/include/media/stagefright/SurfaceMediaSource.h
index d1677fa..2e495f9 100644
--- a/media/libstagefright/include/media/stagefright/SurfaceMediaSource.h
+++ b/media/libstagefright/include/media/stagefright/SurfaceMediaSource.h
@@ -22,7 +22,7 @@
 
 #include <utils/threads.h>
 #include <utils/Vector.h>
-#include <media/stagefright/MediaSource.h>
+#include <media/MediaSource.h>
 #include <media/stagefright/MediaBuffer.h>
 
 #include <media/hardware/MetadataBufferType.h>
diff --git a/media/libstagefright/mpeg2ts/ATSParser.cpp b/media/libstagefright/mpeg2ts/ATSParser.cpp
index 4c95ecf..cd60a6c 100644
--- a/media/libstagefright/mpeg2ts/ATSParser.cpp
+++ b/media/libstagefright/mpeg2ts/ATSParser.cpp
@@ -21,7 +21,6 @@
 #include "AnotherPacketSource.h"
 #include "CasManager.h"
 #include "ESQueue.h"
-#include "include/avc_utils.h"
 
 #include <android/hardware/cas/native/1.0/IDescrambler.h>
 #include <cutils/native_handle.h>
@@ -30,6 +29,7 @@
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
 #include <media/stagefright/foundation/ByteUtils.h>
+#include <media/stagefright/foundation/avc_utils.h>
 #include <media/stagefright/foundation/hexdump.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaErrors.h>
diff --git a/media/libstagefright/mpeg2ts/ATSParser.h b/media/libstagefright/mpeg2ts/ATSParser.h
index 41c19cd..6079afc 100644
--- a/media/libstagefright/mpeg2ts/ATSParser.h
+++ b/media/libstagefright/mpeg2ts/ATSParser.h
@@ -20,9 +20,9 @@
 
 #include <sys/types.h>
 
+#include <media/MediaSource.h>
 #include <media/stagefright/foundation/ABase.h>
 #include <media/stagefright/foundation/AMessage.h>
-#include <media/stagefright/MediaSource.h>
 #include <utils/KeyedVector.h>
 #include <utils/Vector.h>
 #include <utils/RefBase.h>
diff --git a/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp b/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp
index 433b1fc..1dac171 100644
--- a/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp
+++ b/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp
@@ -19,13 +19,12 @@
 
 #include "AnotherPacketSource.h"
 
-#include "include/avc_utils.h"
-
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
 #include <media/stagefright/foundation/AString.h>
 #include <media/stagefright/foundation/hexdump.h>
+#include <media/stagefright/foundation/avc_utils.h>
 #include <media/stagefright/MediaBuffer.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MetaData.h>
@@ -663,7 +662,7 @@
                         && !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC);
             }
         }
-        if (isAvc && !IsIDR(buffer)) {
+        if (isAvc && !IsIDR(buffer->data(), buffer->size())) {
             continue;
         }
 
diff --git a/media/libstagefright/mpeg2ts/AnotherPacketSource.h b/media/libstagefright/mpeg2ts/AnotherPacketSource.h
index b0890d7..3abd573 100644
--- a/media/libstagefright/mpeg2ts/AnotherPacketSource.h
+++ b/media/libstagefright/mpeg2ts/AnotherPacketSource.h
@@ -18,8 +18,8 @@
 
 #define ANOTHER_PACKET_SOURCE_H_
 
+#include <media/MediaSource.h>
 #include <media/stagefright/foundation/ABase.h>
-#include <media/stagefright/MediaSource.h>
 #include <utils/threads.h>
 #include <utils/List.h>
 
diff --git a/media/libstagefright/mpeg2ts/ESQueue.cpp b/media/libstagefright/mpeg2ts/ESQueue.cpp
index 243358d..b621fd0 100644
--- a/media/libstagefright/mpeg2ts/ESQueue.cpp
+++ b/media/libstagefright/mpeg2ts/ESQueue.cpp
@@ -25,14 +25,13 @@
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/AMessage.h>
 #include <media/stagefright/foundation/ByteUtils.h>
+#include <media/stagefright/foundation/avc_utils.h>
 #include <media/stagefright/MediaErrors.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MetaData.h>
 #include <media/cas/DescramblerAPI.h>
 #include <media/hardware/CryptoAPI.h>
 
-#include "include/avc_utils.h"
-
 #include <inttypes.h>
 #include <netinet/in.h>
 
diff --git a/media/libstagefright/omx/Android.bp b/media/libstagefright/omx/Android.bp
index a464681..8539864 100644
--- a/media/libstagefright/omx/Android.bp
+++ b/media/libstagefright/omx/Android.bp
@@ -9,8 +9,6 @@
         "FrameDropper.cpp",
         "GraphicBufferSource.cpp",
         "BWGraphicBufferSource.cpp",
-        "OMX.cpp",
-        "OMXStore.cpp",
         "OMXMaster.cpp",
         "OMXNodeInstance.cpp",
         "OMXUtils.cpp",
@@ -121,6 +119,7 @@
             cfi: true,
         },
     },
+    cflags: ["-Wall", "-Werror"],
 }
 
 //###############################################################################
diff --git a/media/libstagefright/omx/GraphicBufferSource.cpp b/media/libstagefright/omx/GraphicBufferSource.cpp
index 1917d2a..a70005e 100644
--- a/media/libstagefright/omx/GraphicBufferSource.cpp
+++ b/media/libstagefright/omx/GraphicBufferSource.cpp
@@ -1199,7 +1199,8 @@
     Mutex::Autolock autoLock(mMutex);
 
     mSkipFramesBeforeNs =
-            (skipFramesBeforeUs > 0) ? (skipFramesBeforeUs * 1000) : -1ll;
+            (skipFramesBeforeUs > 0 && skipFramesBeforeUs <= INT64_MAX / 1000) ?
+            (skipFramesBeforeUs * 1000) : -1ll;
 
     return OK;
 }
diff --git a/media/libstagefright/omx/OMX.cpp b/media/libstagefright/omx/OMX.cpp
deleted file mode 100644
index 09c4019..0000000
--- a/media/libstagefright/omx/OMX.cpp
+++ /dev/null
@@ -1,198 +0,0 @@
-/*
- * Copyright (C) 2009 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.
- */
-
-#include <inttypes.h>
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "OMX"
-#include <utils/Log.h>
-
-#include <dlfcn.h>
-
-#include <media/stagefright/omx/OMX.h>
-#include <media/stagefright/omx/OMXNodeInstance.h>
-#include <media/stagefright/omx/BWGraphicBufferSource.h>
-#include <media/stagefright/omx/OMXMaster.h>
-#include <media/stagefright/omx/OMXUtils.h>
-#include <media/stagefright/foundation/ADebug.h>
-
-namespace android {
-
-// node ids are created by concatenating the pid with a 16-bit counter
-static size_t kMaxNodeInstances = (1 << 16);
-
-OMX::OMX() : mMaster(new OMXMaster), mParser() {
-}
-
-OMX::~OMX() {
-    delete mMaster;
-    mMaster = NULL;
-}
-
-void OMX::binderDied(const wp<IBinder> &the_late_who) {
-    sp<OMXNodeInstance> instance;
-
-    {
-        Mutex::Autolock autoLock(mLock);
-
-        ssize_t index = mLiveNodes.indexOfKey(the_late_who);
-
-        if (index < 0) {
-            ALOGE("b/27597103, nonexistent observer on binderDied");
-            android_errorWriteLog(0x534e4554, "27597103");
-            return;
-        }
-
-        instance = mLiveNodes.editValueAt(index);
-        mLiveNodes.removeItemsAt(index);
-    }
-
-    instance->onObserverDied();
-}
-
-status_t OMX::listNodes(List<ComponentInfo> *list) {
-    list->clear();
-
-    OMX_U32 index = 0;
-    char componentName[256];
-    while (mMaster->enumerateComponents(
-                componentName, sizeof(componentName), index) == OMX_ErrorNone) {
-        list->push_back(ComponentInfo());
-        ComponentInfo &info = *--list->end();
-
-        info.mName = componentName;
-
-        Vector<String8> roles;
-        OMX_ERRORTYPE err =
-            mMaster->getRolesOfComponent(componentName, &roles);
-
-        if (err == OMX_ErrorNone) {
-            for (OMX_U32 i = 0; i < roles.size(); ++i) {
-                info.mRoles.push_back(roles[i]);
-            }
-        }
-
-        ++index;
-    }
-
-    return OK;
-}
-
-status_t OMX::allocateNode(
-        const char *name, const sp<IOMXObserver> &observer,
-        sp<IOMXNode> *omxNode) {
-    Mutex::Autolock autoLock(mLock);
-
-    omxNode->clear();
-
-    if (mLiveNodes.size() == kMaxNodeInstances) {
-        return NO_MEMORY;
-    }
-
-    sp<OMXNodeInstance> instance = new OMXNodeInstance(this, observer, name);
-
-    OMX_COMPONENTTYPE *handle;
-    OMX_ERRORTYPE err = mMaster->makeComponentInstance(
-            name, &OMXNodeInstance::kCallbacks,
-            instance.get(), &handle);
-
-    if (err != OMX_ErrorNone) {
-        ALOGE("FAILED to allocate omx component '%s' err=%s(%#x)", name, asString(err), err);
-
-        return StatusFromOMXError(err);
-    }
-    instance->setHandle(handle);
-
-    // Find quirks from mParser
-    const auto& codec = mParser.getCodecMap().find(name);
-    if (codec == mParser.getCodecMap().cend()) {
-        ALOGW("Failed to obtain quirks for omx component '%s' from XML files",
-                name);
-    } else {
-        uint32_t quirks = 0;
-        for (const auto& quirk : codec->second.quirkSet) {
-            if (quirk == "requires-allocate-on-input-ports") {
-                quirks |= OMXNodeInstance::
-                        kRequiresAllocateBufferOnInputPorts;
-            }
-            if (quirk == "requires-allocate-on-output-ports") {
-                quirks |= OMXNodeInstance::
-                        kRequiresAllocateBufferOnOutputPorts;
-            }
-        }
-        instance->setQuirks(quirks);
-    }
-
-    mLiveNodes.add(IInterface::asBinder(observer), instance);
-    IInterface::asBinder(observer)->linkToDeath(this);
-
-    *omxNode = instance;
-
-    return OK;
-}
-
-status_t OMX::freeNode(const sp<OMXNodeInstance> &instance) {
-    if (instance == NULL) {
-        return OK;
-    }
-
-    {
-        Mutex::Autolock autoLock(mLock);
-        ssize_t index = mLiveNodes.indexOfKey(IInterface::asBinder(instance->observer()));
-        if (index < 0) {
-            // This could conceivably happen if the observer dies at roughly the
-            // same time that a client attempts to free the node explicitly.
-
-            // NOTE: it's guaranteed that this method is called at most once per
-            //       instance.
-            ALOGV("freeNode: instance already removed from book-keeping.");
-        } else {
-            mLiveNodes.removeItemsAt(index);
-            IInterface::asBinder(instance->observer())->unlinkToDeath(this);
-        }
-    }
-
-    CHECK(instance->handle() != NULL);
-    OMX_ERRORTYPE err = mMaster->destroyComponentInstance(
-            static_cast<OMX_COMPONENTTYPE *>(instance->handle()));
-    ALOGV("freeNode: handle destroyed: %p", instance->handle());
-
-    return StatusFromOMXError(err);
-}
-
-status_t OMX::createInputSurface(
-        sp<IGraphicBufferProducer> *bufferProducer,
-        sp<IGraphicBufferSource> *bufferSource) {
-    if (bufferProducer == NULL || bufferSource == NULL) {
-        ALOGE("b/25884056");
-        return BAD_VALUE;
-    }
-
-    sp<GraphicBufferSource> graphicBufferSource = new GraphicBufferSource();
-    status_t err = graphicBufferSource->initCheck();
-    if (err != OK) {
-        ALOGE("Failed to create persistent input surface: %s (%d)",
-                strerror(-err), err);
-        return err;
-    }
-
-    *bufferProducer = graphicBufferSource->getIGraphicBufferProducer();
-    *bufferSource = new BWGraphicBufferSource(graphicBufferSource);
-
-    return OK;
-}
-
-}  // namespace android
diff --git a/media/libstagefright/omx/OMXNodeInstance.cpp b/media/libstagefright/omx/OMXNodeInstance.cpp
index 015a148..ff58eb6 100644
--- a/media/libstagefright/omx/OMXNodeInstance.cpp
+++ b/media/libstagefright/omx/OMXNodeInstance.cpp
@@ -344,7 +344,7 @@
 ////////////////////////////////////////////////////////////////////////////////
 
 OMXNodeInstance::OMXNodeInstance(
-        OmxNodeOwner *owner, const sp<IOMXObserver> &observer, const char *name)
+        Omx *owner, const sp<IOMXObserver> &observer, const char *name)
     : mOwner(owner),
       mHandle(NULL),
       mObserver(observer),
diff --git a/media/libstagefright/omx/OMXStore.cpp b/media/libstagefright/omx/OMXStore.cpp
deleted file mode 100644
index 345336d..0000000
--- a/media/libstagefright/omx/OMXStore.cpp
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * Copyright (C) 2009 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_NDEBUG 0
-#define LOG_TAG "OMXStore"
-#include <utils/Log.h>
-
-#include <media/stagefright/omx/OMXUtils.h>
-#include <media/stagefright/omx/OMX.h>
-#include <media/stagefright/omx/OMXStore.h>
-#include <media/stagefright/xmlparser/MediaCodecsXmlParser.h>
-
-#include <map>
-#include <string>
-
-namespace android {
-
-namespace {
-    struct RoleProperties {
-        std::string type;
-        bool isEncoder;
-        bool preferPlatformNodes;
-        std::multimap<size_t, IOMXStore::NodeInfo> nodeList;
-    };
-}  // Unnamed namespace
-
-OMXStore::OMXStore(
-        const char* owner,
-        const char* const* searchDirs,
-        const char* mainXmlName,
-        const char* performanceXmlName,
-        const char* profilingResultsXmlPath) {
-    MediaCodecsXmlParser parser(
-            searchDirs,
-            mainXmlName,
-            performanceXmlName,
-            profilingResultsXmlPath);
-    mParsingStatus = parser.getParsingStatus();
-
-    const auto& serviceAttributeMap = parser.getServiceAttributeMap();
-    mServiceAttributeList.reserve(serviceAttributeMap.size());
-    for (const auto& attributePair : serviceAttributeMap) {
-        Attribute attribute;
-        attribute.key = attributePair.first;
-        attribute.value = attributePair.second;
-        mServiceAttributeList.push_back(std::move(attribute));
-    }
-
-    const auto& roleMap = parser.getRoleMap();
-    mRoleList.reserve(roleMap.size());
-    for (const auto& rolePair : roleMap) {
-        RoleInfo role;
-        role.role = rolePair.first;
-        role.type = rolePair.second.type;
-        role.isEncoder = rolePair.second.isEncoder;
-        // TODO: Currently, preferPlatformNodes information is not available in
-        // the xml file. Once we have a way to provide this information, it
-        // should be parsed properly.
-        role.preferPlatformNodes = rolePair.first.compare(0, 5, "audio") == 0;
-        std::vector<NodeInfo>& nodeList = role.nodes;
-        nodeList.reserve(rolePair.second.nodeList.size());
-        for (const auto& nodePair : rolePair.second.nodeList) {
-            NodeInfo node;
-            node.name = nodePair.second.name;
-            node.owner = owner;
-            std::vector<Attribute>& attributeList = node.attributes;
-            attributeList.reserve(nodePair.second.attributeList.size());
-            for (const auto& attributePair : nodePair.second.attributeList) {
-                Attribute attribute;
-                attribute.key = attributePair.first;
-                attribute.value = attributePair.second;
-                attributeList.push_back(std::move(attribute));
-            }
-            nodeList.push_back(std::move(node));
-        }
-        mRoleList.push_back(std::move(role));
-    }
-
-    mPrefix = parser.getCommonPrefix();
-}
-
-status_t OMXStore::listServiceAttributes(std::vector<Attribute>* attributes) {
-    *attributes = mServiceAttributeList;
-    return mParsingStatus;
-}
-
-status_t OMXStore::getNodePrefix(std::string* prefix) {
-    *prefix = mPrefix;
-    return mParsingStatus;
-}
-
-status_t OMXStore::listRoles(std::vector<RoleInfo>* roleList) {
-    *roleList = mRoleList;
-    return mParsingStatus;
-}
-
-status_t OMXStore::getOmx(const std::string& name, sp<IOMX>* omx) {
-    *omx = new OMX();
-    return NO_ERROR;
-}
-
-OMXStore::~OMXStore() {
-}
-
-}  // namespace android
-
diff --git a/media/libstagefright/omx/include/media/stagefright/omx/1.0/Omx.h b/media/libstagefright/omx/include/media/stagefright/omx/1.0/Omx.h
index a6a9d3e..baa7b81 100644
--- a/media/libstagefright/omx/include/media/stagefright/omx/1.0/Omx.h
+++ b/media/libstagefright/omx/include/media/stagefright/omx/1.0/Omx.h
@@ -20,13 +20,13 @@
 #include <hidl/MQDescriptor.h>
 #include <hidl/Status.h>
 
-#include <media/stagefright/omx/OMXNodeInstance.h>
 #include <media/stagefright/xmlparser/MediaCodecsXmlParser.h>
 #include <android/hardware/media/omx/1.0/IOmx.h>
 
 namespace android {
 
 struct OMXMaster;
+struct OMXNodeInstance;
 
 namespace hardware {
 namespace media {
@@ -50,10 +50,9 @@
 using ::android::wp;
 
 using ::android::OMXMaster;
-using ::android::OmxNodeOwner;
 using ::android::OMXNodeInstance;
 
-struct Omx : public IOmx, public hidl_death_recipient, public OmxNodeOwner {
+struct Omx : public IOmx, public hidl_death_recipient {
     Omx();
     virtual ~Omx();
 
@@ -68,8 +67,8 @@
     // Method from hidl_death_recipient
     void serviceDied(uint64_t cookie, const wp<IBase>& who) override;
 
-    // Method from OmxNodeOwner
-    virtual status_t freeNode(sp<OMXNodeInstance> const& instance) override;
+    // Method for OMXNodeInstance
+    status_t freeNode(sp<OMXNodeInstance> const& instance);
 
 protected:
     OMXMaster* mMaster;
diff --git a/media/libstagefright/omx/include/media/stagefright/omx/OMX.h b/media/libstagefright/omx/include/media/stagefright/omx/OMX.h
deleted file mode 100644
index 594b4c0..0000000
--- a/media/libstagefright/omx/include/media/stagefright/omx/OMX.h
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (C) 2009 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_OMX_H_
-#define ANDROID_OMX_H_
-
-#include <media/IOMX.h>
-#include <utils/threads.h>
-#include <utils/KeyedVector.h>
-#include <media/stagefright/xmlparser/MediaCodecsXmlParser.h>
-#include "OmxNodeOwner.h"
-
-namespace android {
-
-struct OMXMaster;
-struct OMXNodeInstance;
-
-class OMX : public BnOMX,
-            public OmxNodeOwner,
-            public IBinder::DeathRecipient {
-public:
-    OMX();
-
-    virtual status_t listNodes(List<ComponentInfo> *list);
-
-    virtual status_t allocateNode(
-            const char *name, const sp<IOMXObserver> &observer,
-            sp<IOMXNode> *omxNode);
-
-    virtual status_t createInputSurface(
-            sp<IGraphicBufferProducer> *bufferProducer,
-            sp<IGraphicBufferSource> *bufferSource);
-
-    virtual void binderDied(const wp<IBinder> &the_late_who);
-
-    virtual status_t freeNode(const sp<OMXNodeInstance>& instance);
-
-protected:
-    virtual ~OMX();
-
-private:
-    Mutex mLock;
-    OMXMaster *mMaster;
-    MediaCodecsXmlParser mParser;
-
-    KeyedVector<wp<IBinder>, sp<OMXNodeInstance> > mLiveNodes;
-
-    OMX(const OMX &);
-    OMX &operator=(const OMX &);
-};
-
-}  // namespace android
-
-#endif  // ANDROID_OMX_H_
diff --git a/media/libstagefright/omx/include/media/stagefright/omx/OMXNodeInstance.h b/media/libstagefright/omx/include/media/stagefright/omx/OMXNodeInstance.h
index 1065ca5..c436121 100644
--- a/media/libstagefright/omx/include/media/stagefright/omx/OMXNodeInstance.h
+++ b/media/libstagefright/omx/include/media/stagefright/omx/OMXNodeInstance.h
@@ -25,9 +25,9 @@
 #include <utils/threads.h>
 #include <utils/KeyedVector.h>
 #include <utils/SortedVector.h>
-#include "OmxNodeOwner.h"
 
 #include <android/hidl/memory/1.0/IMemory.h>
+#include <media/stagefright/omx/1.0/Omx.h>
 
 namespace android {
 class GraphicBuffer;
@@ -35,11 +35,12 @@
 class IOMXObserver;
 struct OMXMaster;
 class OMXBuffer;
-typedef hidl::memory::V1_0::IMemory IHidlMemory;
+using IHidlMemory = hidl::memory::V1_0::IMemory;
+using hardware::media::omx::V1_0::implementation::Omx;
 
 struct OMXNodeInstance : public BnOMXNode {
     OMXNodeInstance(
-            OmxNodeOwner *owner, const sp<IOMXObserver> &observer, const char *name);
+            Omx *owner, const sp<IOMXObserver> &observer, const char *name);
 
     void setHandle(OMX_HANDLETYPE handle);
 
@@ -122,7 +123,7 @@
 
     Mutex mLock;
 
-    OmxNodeOwner *mOwner;
+    Omx *mOwner;
     OMX_HANDLETYPE mHandle;
     sp<IOMXObserver> mObserver;
     sp<CallbackDispatcher> mDispatcher;
diff --git a/media/libstagefright/omx/include/media/stagefright/omx/OMXStore.h b/media/libstagefright/omx/include/media/stagefright/omx/OMXStore.h
deleted file mode 100644
index e00d713..0000000
--- a/media/libstagefright/omx/include/media/stagefright/omx/OMXStore.h
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (C) 2009 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_OMXSTORE_H_
-#define ANDROID_OMXSTORE_H_
-
-#include <media/IOMXStore.h>
-#include <media/IOMX.h>
-#include <media/stagefright/xmlparser/MediaCodecsXmlParser.h>
-
-#include <vector>
-#include <string>
-
-namespace android {
-
-class OMXStore : public BnOMXStore {
-public:
-    OMXStore(
-            const char* owner = "default",
-            const char* const* searchDirs
-                = MediaCodecsXmlParser::defaultSearchDirs,
-            const char* mainXmlName
-                = MediaCodecsXmlParser::defaultMainXmlName,
-            const char* performanceXmlName
-                = MediaCodecsXmlParser::defaultPerformanceXmlName,
-            const char* profilingResultsXmlPath
-                = MediaCodecsXmlParser::defaultProfilingResultsXmlPath);
-
-    status_t listServiceAttributes(
-            std::vector<Attribute>* attributes) override;
-
-    status_t getNodePrefix(std::string* prefix) override;
-
-    status_t listRoles(std::vector<RoleInfo>* roleList) override;
-
-    status_t getOmx(const std::string& name, sp<IOMX>* omx) override;
-
-    ~OMXStore() override;
-
-protected:
-    status_t mParsingStatus;
-    std::string mPrefix;
-    std::vector<Attribute> mServiceAttributeList;
-    std::vector<RoleInfo> mRoleList;
-};
-
-}  // namespace android
-
-#endif  // ANDROID_OMXSTORE_H_
diff --git a/media/libstagefright/omx/tests/Android.bp b/media/libstagefright/omx/tests/Android.bp
index 8bcb99e..999d9d4 100644
--- a/media/libstagefright/omx/tests/Android.bp
+++ b/media/libstagefright/omx/tests/Android.bp
@@ -8,6 +8,8 @@
         "libstagefright",
         "libbinder",
         "libmedia",
+        "libmedia_omx",
+        "libmediaextractor",
         "libutils",
         "liblog",
         "libstagefright_foundation",
diff --git a/media/libstagefright/omx/tests/OMXHarness.cpp b/media/libstagefright/omx/tests/OMXHarness.cpp
index 4b624f2..86c7211 100644
--- a/media/libstagefright/omx/tests/OMXHarness.cpp
+++ b/media/libstagefright/omx/tests/OMXHarness.cpp
@@ -25,20 +25,22 @@
 
 #include <binder/ProcessState.h>
 #include <binder/IServiceManager.h>
-#include <binder/MemoryDealer.h>
+#include <cutils/properties.h>
+#include <media/DataSource.h>
 #include <media/IMediaHTTPService.h>
-#include <media/IMediaCodecService.h>
+#include <media/MediaExtractor.h>
+#include <media/MediaSource.h>
+#include <media/OMXBuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/ALooper.h>
-#include <media/stagefright/DataSource.h>
+#include <media/stagefright/DataSourceFactory.h>
+#include <media/stagefright/InterfaceUtils.h>
 #include <media/stagefright/MediaBuffer.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/MediaExtractor.h>
-#include <media/stagefright/MediaSource.h>
+#include <media/stagefright/MediaExtractorFactory.h>
 #include <media/stagefright/MetaData.h>
 #include <media/stagefright/SimpleDecodingSource.h>
-#include <media/OMXBuffer.h>
 #include <android/hardware/media/omx/1.0/IOmx.h>
 #include <media/omx/1.0/WOmx.h>
 #include <system/window.h>
@@ -67,7 +69,7 @@
 /////////////////////////////////////////////////////////////////////
 
 Harness::Harness()
-    : mInitCheck(NO_INIT), mUseTreble(false) {
+    : mInitCheck(NO_INIT) {
     mInitCheck = initOMX();
 }
 
@@ -79,21 +81,12 @@
 }
 
 status_t Harness::initOMX() {
-    if (property_get_bool("persist.media.treble_omx", true)) {
-        using namespace ::android::hardware::media::omx::V1_0;
-        sp<IOmx> tOmx = IOmx::getService();
-        if (tOmx == nullptr) {
-            return NO_INIT;
-        }
-        mOMX = new utils::LWOmx(tOmx);
-        mUseTreble = true;
-    } else {
-        sp<IServiceManager> sm = defaultServiceManager();
-        sp<IBinder> binder = sm->getService(String16("media.codec"));
-        sp<IMediaCodecService> service = interface_cast<IMediaCodecService>(binder);
-        mOMX = service->getOMX();
-        mUseTreble = false;
+    using namespace ::android::hardware::media::omx::V1_0;
+    sp<IOmx> tOmx = IOmx::getService();
+    if (tOmx == nullptr) {
+        return NO_INIT;
     }
+    mOMX = new utils::LWOmx(tOmx);
 
     return mOMX != 0 ? OK : NO_INIT;
 }
@@ -221,25 +214,19 @@
     for (OMX_U32 i = 0; i < def.nBufferCountActual; ++i) {
         Buffer buffer;
         buffer.mFlags = 0;
-        if (mUseTreble) {
-            bool success;
-            auto transStatus = mAllocator->allocate(def.nBufferSize,
-                    [&success, &buffer](
-                            bool s,
-                            hidl_memory const& m) {
-                        success = s;
-                        buffer.mHidlMemory = m;
-                    });
-            EXPECT(transStatus.isOk(),
-                    "Cannot call allocator");
-            EXPECT(success,
-                    "Cannot allocate memory");
-            err = mOMXNode->useBuffer(portIndex, buffer.mHidlMemory, &buffer.mID);
-        } else {
-            buffer.mMemory = mDealer->allocate(def.nBufferSize);
-            CHECK(buffer.mMemory != NULL);
-            err = mOMXNode->useBuffer(portIndex, buffer.mMemory, &buffer.mID);
-        }
+        bool success;
+        auto transStatus = mAllocator->allocate(def.nBufferSize,
+                [&success, &buffer](
+                        bool s,
+                        hidl_memory const& m) {
+                    success = s;
+                    buffer.mHidlMemory = m;
+                });
+        EXPECT(transStatus.isOk(),
+                "Cannot call allocator");
+        EXPECT(success,
+                "Cannot allocate memory");
+        err = mOMXNode->useBuffer(portIndex, buffer.mHidlMemory, &buffer.mID);
 
         EXPECT_SUCCESS(err, "useBuffer");
 
@@ -291,13 +278,13 @@
 
 static sp<IMediaExtractor> CreateExtractorFromURI(const char *uri) {
     sp<DataSource> source =
-        DataSource::CreateFromURI(NULL /* httpService */, uri);
+        DataSourceFactory::CreateFromURI(NULL /* httpService */, uri);
 
     if (source == NULL) {
         return NULL;
     }
 
-    return MediaExtractor::Create(source);
+    return MediaExtractorFactory::Create(source);
 }
 
 status_t Harness::testStateTransitions(
@@ -308,13 +295,11 @@
         return OK;
     }
 
-    if (mUseTreble) {
-        mAllocator = IAllocator::getService("ashmem");
-        EXPECT(mAllocator != nullptr,
-                "Cannot obtain hidl AshmemAllocator");
-    } else {
-        mDealer = new MemoryDealer(16 * 1024 * 1024, "OMXHarness");
-    }
+    mAllocator = IAllocator::getService("ashmem");
+    EXPECT(mAllocator != nullptr,
+            "Cannot obtain hidl AshmemAllocator");
+    // TODO: When Treble has MemoryHeap/MemoryDealer, we should specify the heap
+    // size to be 16 * 1024 * 1024.
 
     sp<CodecObserver> observer = new CodecObserver(this, ++mCurGeneration);
 
@@ -564,7 +549,7 @@
         CHECK(meta->findCString(kKeyMIMEType, &trackMime));
 
         if (!strcasecmp(mime, trackMime)) {
-            return MediaSource::CreateFromIMediaSource(extractor->getTrack(i));
+            return CreateMediaSourceFromIMediaSource(extractor->getTrack(i));
         }
     }
 
diff --git a/media/libstagefright/omx/tests/OMXHarness.h b/media/libstagefright/omx/tests/OMXHarness.h
index 4fc0f79..dca787c 100644
--- a/media/libstagefright/omx/tests/OMXHarness.h
+++ b/media/libstagefright/omx/tests/OMXHarness.h
@@ -93,8 +93,6 @@
     Condition mMessageAddedCondition;
     int32_t mLastMsgGeneration;
     int32_t mCurGeneration;
-    bool mUseTreble;
-    sp<MemoryDealer> mDealer;
     sp<IAllocator> mAllocator;
 
     status_t initOMX();
diff --git a/media/libstagefright/rtsp/APacketSource.cpp b/media/libstagefright/rtsp/APacketSource.cpp
index 8ba9e02..68f8bdd 100644
--- a/media/libstagefright/rtsp/APacketSource.cpp
+++ b/media/libstagefright/rtsp/APacketSource.cpp
@@ -23,8 +23,6 @@
 #include "ARawAudioAssembler.h"
 #include "ASessionDescription.h"
 
-#include "include/avc_utils.h"
-
 #include <ctype.h>
 
 #include <media/stagefright/foundation/ABitReader.h>
@@ -32,6 +30,7 @@
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
 #include <media/stagefright/foundation/AString.h>
+#include <media/stagefright/foundation/avc_utils.h>
 #include <media/stagefright/foundation/base64.h>
 #include <media/stagefright/foundation/hexdump.h>
 #include <media/stagefright/MediaDefs.h>
diff --git a/media/libstagefright/rtsp/ARTPWriter.cpp b/media/libstagefright/rtsp/ARTPWriter.cpp
index 56c4aa6..8604b69 100644
--- a/media/libstagefright/rtsp/ARTPWriter.cpp
+++ b/media/libstagefright/rtsp/ARTPWriter.cpp
@@ -22,13 +22,13 @@
 
 #include <fcntl.h>
 
+#include <media/MediaSource.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
 #include <media/stagefright/foundation/hexdump.h>
 #include <media/stagefright/MediaBuffer.h>
 #include <media/stagefright/MediaDefs.h>
-#include <media/stagefright/MediaSource.h>
 #include <media/stagefright/MetaData.h>
 #include <utils/ByteOrder.h>
 
diff --git a/media/libstagefright/rtsp/VideoSource.h b/media/libstagefright/rtsp/VideoSource.h
index ae0c85b..4be9bf6 100644
--- a/media/libstagefright/rtsp/VideoSource.h
+++ b/media/libstagefright/rtsp/VideoSource.h
@@ -18,9 +18,9 @@
 
 #define VIDEO_SOURCE_H_
 
+#include <media/MediaSource.h>
 #include <media/stagefright/MediaBufferGroup.h>
 #include <media/stagefright/MediaDefs.h>
-#include <media/stagefright/MediaSource.h>
 #include <media/stagefright/MetaData.h>
 
 namespace android {
diff --git a/media/libstagefright/rtsp/rtp_test.cpp b/media/libstagefright/rtsp/rtp_test.cpp
index e612a8d..98a8fb4 100644
--- a/media/libstagefright/rtsp/rtp_test.cpp
+++ b/media/libstagefright/rtsp/rtp_test.cpp
@@ -20,10 +20,10 @@
 
 #include <binder/ProcessState.h>
 
+#include <media/DataSource.h>
 #include <media/stagefright/foundation/base64.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/ALooper.h>
-#include <media/stagefright/DataSource.h>
 #include <media/stagefright/MediaBuffer.h>
 #include <media/stagefright/MetaData.h>
 #include <media/stagefright/SimpleDecodingSource.h>
diff --git a/media/libstagefright/tests/DummyRecorder.cpp b/media/libstagefright/tests/DummyRecorder.cpp
index 8f17088..4f560cb 100644
--- a/media/libstagefright/tests/DummyRecorder.cpp
+++ b/media/libstagefright/tests/DummyRecorder.cpp
@@ -17,8 +17,8 @@
 #define LOG_TAG "DummyRecorder"
 // #define LOG_NDEBUG 0
 
+#include <media/MediaSource.h>
 #include <media/stagefright/MediaBuffer.h>
-#include <media/stagefright/MediaSource.h>
 #include "DummyRecorder.h"
 
 #include <utils/Log.h>
diff --git a/media/libstagefright/webm/WebmFrameThread.h b/media/libstagefright/webm/WebmFrameThread.h
index d65d9b7..76c91f1 100644
--- a/media/libstagefright/webm/WebmFrameThread.h
+++ b/media/libstagefright/webm/WebmFrameThread.h
@@ -20,8 +20,8 @@
 #include "WebmFrame.h"
 #include "LinkedBlockingQueue.h"
 
+#include <media/MediaSource.h>
 #include <media/stagefright/FileSource.h>
-#include <media/stagefright/MediaSource.h>
 
 #include <utils/List.h>
 #include <utils/Errors.h>
diff --git a/media/libstagefright/webm/WebmWriter.h b/media/libstagefright/webm/WebmWriter.h
index ed5bc4c..ffe4c79 100644
--- a/media/libstagefright/webm/WebmWriter.h
+++ b/media/libstagefright/webm/WebmWriter.h
@@ -21,7 +21,7 @@
 #include "WebmFrameThread.h"
 #include "LinkedBlockingQueue.h"
 
-#include <media/stagefright/MediaSource.h>
+#include <media/MediaSource.h>
 #include <media/stagefright/MediaWriter.h>
 
 #include <utils/Errors.h>
diff --git a/media/mtp/Android.bp b/media/mtp/Android.bp
index 543ad5c..acea373 100644
--- a/media/mtp/Android.bp
+++ b/media/mtp/Android.bp
@@ -19,6 +19,7 @@
     srcs: [
         "MtpDataPacket.cpp",
         "MtpDebug.cpp",
+        "MtpDescriptors.cpp",
         "MtpDevHandle.cpp",
         "MtpDevice.cpp",
         "MtpDeviceInfo.cpp",
diff --git a/media/mtp/MtpDatabase.h b/media/mtp/MtpDatabase.h
index c7021df..2395f4f 100644
--- a/media/mtp/MtpDatabase.h
+++ b/media/mtp/MtpDatabase.h
@@ -104,7 +104,7 @@
     virtual MtpProperty*            getDevicePropertyDesc(MtpDeviceProperty property) = 0;
 
     virtual MtpResponseCode         moveObject(MtpObjectHandle handle, MtpObjectHandle newParent,
-                                            MtpString& newPath) = 0;
+                                            MtpStorageID newStorage, MtpString& newPath) = 0;
 
     virtual void                    sessionStarted() = 0;
 
diff --git a/media/mtp/MtpDescriptors.cpp b/media/mtp/MtpDescriptors.cpp
new file mode 100644
index 0000000..d9b6060
--- /dev/null
+++ b/media/mtp/MtpDescriptors.cpp
@@ -0,0 +1,260 @@
+/*
+ * 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.
+ */
+
+#include "MtpDescriptors.h"
+
+namespace android {
+
+const struct usb_interface_descriptor mtp_interface_desc = {
+    .bLength = USB_DT_INTERFACE_SIZE,
+    .bDescriptorType = USB_DT_INTERFACE,
+    .bInterfaceNumber = 0,
+    .bNumEndpoints = 3,
+    .bInterfaceClass = USB_CLASS_STILL_IMAGE,
+    .bInterfaceSubClass = 1,
+    .bInterfaceProtocol = 1,
+    .iInterface = 1,
+};
+
+const struct usb_interface_descriptor ptp_interface_desc = {
+    .bLength = USB_DT_INTERFACE_SIZE,
+    .bDescriptorType = USB_DT_INTERFACE,
+    .bInterfaceNumber = 0,
+    .bNumEndpoints = 3,
+    .bInterfaceClass = USB_CLASS_STILL_IMAGE,
+    .bInterfaceSubClass = 1,
+    .bInterfaceProtocol = 1,
+};
+
+const struct usb_endpoint_descriptor_no_audio fs_sink = {
+    .bLength = USB_DT_ENDPOINT_SIZE,
+    .bDescriptorType = USB_DT_ENDPOINT,
+    .bEndpointAddress = 1 | USB_DIR_IN,
+    .bmAttributes = USB_ENDPOINT_XFER_BULK,
+    .wMaxPacketSize = MAX_PACKET_SIZE_FS,
+};
+
+const struct usb_endpoint_descriptor_no_audio fs_source = {
+    .bLength = USB_DT_ENDPOINT_SIZE,
+    .bDescriptorType = USB_DT_ENDPOINT,
+    .bEndpointAddress = 2 | USB_DIR_OUT,
+    .bmAttributes = USB_ENDPOINT_XFER_BULK,
+    .wMaxPacketSize = MAX_PACKET_SIZE_FS,
+};
+
+const struct usb_endpoint_descriptor_no_audio intr = {
+    .bLength = USB_DT_ENDPOINT_SIZE,
+    .bDescriptorType = USB_DT_ENDPOINT,
+    .bEndpointAddress = 3 | USB_DIR_IN,
+    .bmAttributes = USB_ENDPOINT_XFER_INT,
+    .wMaxPacketSize = MAX_PACKET_SIZE_EV,
+    .bInterval = 6,
+};
+
+const struct usb_endpoint_descriptor_no_audio hs_sink = {
+    .bLength = USB_DT_ENDPOINT_SIZE,
+    .bDescriptorType = USB_DT_ENDPOINT,
+    .bEndpointAddress = 1 | USB_DIR_IN,
+    .bmAttributes = USB_ENDPOINT_XFER_BULK,
+    .wMaxPacketSize = MAX_PACKET_SIZE_HS,
+};
+
+const struct usb_endpoint_descriptor_no_audio hs_source = {
+    .bLength = USB_DT_ENDPOINT_SIZE,
+    .bDescriptorType = USB_DT_ENDPOINT,
+    .bEndpointAddress = 2 | USB_DIR_OUT,
+    .bmAttributes = USB_ENDPOINT_XFER_BULK,
+    .wMaxPacketSize = MAX_PACKET_SIZE_HS,
+};
+
+const struct usb_endpoint_descriptor_no_audio ss_sink = {
+    .bLength = USB_DT_ENDPOINT_SIZE,
+    .bDescriptorType = USB_DT_ENDPOINT,
+    .bEndpointAddress = 1 | USB_DIR_IN,
+    .bmAttributes = USB_ENDPOINT_XFER_BULK,
+    .wMaxPacketSize = MAX_PACKET_SIZE_SS,
+};
+
+const struct usb_endpoint_descriptor_no_audio ss_source = {
+    .bLength = USB_DT_ENDPOINT_SIZE,
+    .bDescriptorType = USB_DT_ENDPOINT,
+    .bEndpointAddress = 2 | USB_DIR_OUT,
+    .bmAttributes = USB_ENDPOINT_XFER_BULK,
+    .wMaxPacketSize = MAX_PACKET_SIZE_SS,
+};
+
+const struct usb_ss_ep_comp_descriptor ss_sink_comp = {
+    .bLength = sizeof(ss_sink_comp),
+    .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
+    .bMaxBurst = 6,
+};
+
+const struct usb_ss_ep_comp_descriptor ss_source_comp = {
+    .bLength = sizeof(ss_source_comp),
+    .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
+    .bMaxBurst = 6,
+};
+
+const struct usb_ss_ep_comp_descriptor ss_intr_comp = {
+    .bLength = sizeof(ss_intr_comp),
+    .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
+};
+
+const struct func_desc mtp_fs_descriptors = {
+    .intf = mtp_interface_desc,
+    .sink = fs_sink,
+    .source = fs_source,
+    .intr = intr,
+};
+
+const struct func_desc mtp_hs_descriptors = {
+    .intf = mtp_interface_desc,
+    .sink = hs_sink,
+    .source = hs_source,
+    .intr = intr,
+};
+
+const struct ss_func_desc mtp_ss_descriptors = {
+    .intf = mtp_interface_desc,
+    .sink = ss_sink,
+    .sink_comp = ss_sink_comp,
+    .source = ss_source,
+    .source_comp = ss_source_comp,
+    .intr = intr,
+    .intr_comp = ss_intr_comp,
+};
+
+const struct func_desc ptp_fs_descriptors = {
+    .intf = ptp_interface_desc,
+    .sink = fs_sink,
+    .source = fs_source,
+    .intr = intr,
+};
+
+const struct func_desc ptp_hs_descriptors = {
+    .intf = ptp_interface_desc,
+    .sink = hs_sink,
+    .source = hs_source,
+    .intr = intr,
+};
+
+const struct ss_func_desc ptp_ss_descriptors = {
+    .intf = ptp_interface_desc,
+    .sink = ss_sink,
+    .sink_comp = ss_sink_comp,
+    .source = ss_source,
+    .source_comp = ss_source_comp,
+    .intr = intr,
+    .intr_comp = ss_intr_comp,
+};
+
+const struct functionfs_strings mtp_strings = {
+    .header = {
+        .magic = htole32(FUNCTIONFS_STRINGS_MAGIC),
+        .length = htole32(sizeof(mtp_strings)),
+        .str_count = htole32(1),
+        .lang_count = htole32(1),
+    },
+    .lang0 = {
+        .code = htole16(0x0409),
+        .str1 = STR_INTERFACE,
+    },
+};
+
+const struct usb_os_desc_header mtp_os_desc_header = {
+    .interface = htole32(1),
+    .dwLength = htole32(sizeof(usb_os_desc_header) + sizeof(usb_ext_compat_desc)),
+    .bcdVersion = htole16(1),
+    .wIndex = htole16(4),
+    .bCount = htole16(1),
+    .Reserved = htole16(0),
+};
+
+const struct usb_ext_compat_desc mtp_os_desc_compat = {
+    .bFirstInterfaceNumber = 0,
+    .Reserved1 = htole32(1),
+    .CompatibleID = { 'M', 'T', 'P' },
+    .SubCompatibleID = {0},
+    .Reserved2 = {0},
+};
+
+const struct usb_ext_compat_desc ptp_os_desc_compat = {
+    .bFirstInterfaceNumber = 0,
+    .Reserved1 = htole32(1),
+    .CompatibleID = { 'P', 'T', 'P' },
+    .SubCompatibleID = {0},
+    .Reserved2 = {0},
+};
+
+const struct desc_v2 mtp_desc_v2 = {
+    .header = {
+        .magic = htole32(FUNCTIONFS_DESCRIPTORS_MAGIC_V2),
+        .length = htole32(sizeof(struct desc_v2)),
+        .flags = FUNCTIONFS_HAS_FS_DESC | FUNCTIONFS_HAS_HS_DESC |
+                 FUNCTIONFS_HAS_SS_DESC | FUNCTIONFS_HAS_MS_OS_DESC,
+    },
+    .fs_count = 4,
+    .hs_count = 4,
+    .ss_count = 7,
+    .os_count = 1,
+    .fs_descs = mtp_fs_descriptors,
+    .hs_descs = mtp_hs_descriptors,
+    .ss_descs = mtp_ss_descriptors,
+    .os_header = mtp_os_desc_header,
+    .os_desc = mtp_os_desc_compat,
+};
+
+const struct desc_v2 ptp_desc_v2 = {
+    .header = {
+        .magic = htole32(FUNCTIONFS_DESCRIPTORS_MAGIC_V2),
+        .length = htole32(sizeof(struct desc_v2)),
+        .flags = FUNCTIONFS_HAS_FS_DESC | FUNCTIONFS_HAS_HS_DESC |
+                 FUNCTIONFS_HAS_SS_DESC | FUNCTIONFS_HAS_MS_OS_DESC,
+    },
+    .fs_count = 4,
+    .hs_count = 4,
+    .ss_count = 7,
+    .os_count = 1,
+    .fs_descs = ptp_fs_descriptors,
+    .hs_descs = ptp_hs_descriptors,
+    .ss_descs = ptp_ss_descriptors,
+    .os_header = mtp_os_desc_header,
+    .os_desc = ptp_os_desc_compat,
+};
+
+const struct desc_v1 mtp_desc_v1 = {
+    .header = {
+        .magic = htole32(FUNCTIONFS_DESCRIPTORS_MAGIC),
+        .length = htole32(sizeof(struct desc_v1)),
+        .fs_count = 4,
+        .hs_count = 4,
+    },
+    .fs_descs = mtp_fs_descriptors,
+    .hs_descs = mtp_hs_descriptors,
+};
+
+const struct desc_v1 ptp_desc_v1 = {
+    .header = {
+        .magic = htole32(FUNCTIONFS_DESCRIPTORS_MAGIC),
+        .length = htole32(sizeof(struct desc_v1)),
+        .fs_count = 4,
+        .hs_count = 4,
+    },
+    .fs_descs = ptp_fs_descriptors,
+    .hs_descs = ptp_hs_descriptors,
+};
+
+}; // namespace android
diff --git a/media/mtp/MtpDescriptors.h b/media/mtp/MtpDescriptors.h
new file mode 100644
index 0000000..cfc3930
--- /dev/null
+++ b/media/mtp/MtpDescriptors.h
@@ -0,0 +1,96 @@
+/*
+ * 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.
+ */
+
+#ifndef MTP_DESCRIPTORS_H
+#define MTP_DESCRIPTORS_H
+
+#include <linux/usb/ch9.h>
+#include <linux/usb/functionfs.h>
+#include <sys/endian.h>
+
+namespace android {
+
+constexpr int MAX_PACKET_SIZE_FS = 64;
+constexpr int MAX_PACKET_SIZE_HS = 512;
+constexpr int MAX_PACKET_SIZE_SS = 1024;
+constexpr int MAX_PACKET_SIZE_EV = 28;
+
+struct func_desc {
+    struct usb_interface_descriptor intf;
+    struct usb_endpoint_descriptor_no_audio sink;
+    struct usb_endpoint_descriptor_no_audio source;
+    struct usb_endpoint_descriptor_no_audio intr;
+} __attribute__((packed));
+
+struct ss_func_desc {
+    struct usb_interface_descriptor intf;
+    struct usb_endpoint_descriptor_no_audio sink;
+    struct usb_ss_ep_comp_descriptor sink_comp;
+    struct usb_endpoint_descriptor_no_audio source;
+    struct usb_ss_ep_comp_descriptor source_comp;
+    struct usb_endpoint_descriptor_no_audio intr;
+    struct usb_ss_ep_comp_descriptor intr_comp;
+} __attribute__((packed));
+
+struct desc_v1 {
+    struct usb_functionfs_descs_head_v1 {
+        __le32 magic;
+        __le32 length;
+        __le32 fs_count;
+        __le32 hs_count;
+    } __attribute__((packed)) header;
+    struct func_desc fs_descs, hs_descs;
+} __attribute__((packed));
+
+struct desc_v2 {
+    struct usb_functionfs_descs_head_v2 header;
+    // The rest of the structure depends on the flags in the header.
+    __le32 fs_count;
+    __le32 hs_count;
+    __le32 ss_count;
+    __le32 os_count;
+    struct func_desc fs_descs, hs_descs;
+    struct ss_func_desc ss_descs;
+    struct usb_os_desc_header os_header;
+    struct usb_ext_compat_desc os_desc;
+} __attribute__((packed));
+
+// OS descriptor contents should not be changed. See b/64790536.
+static_assert(sizeof(struct desc_v2) == sizeof(usb_functionfs_descs_head_v2) +
+        16 + 2 * sizeof(struct func_desc) + sizeof(struct ss_func_desc) +
+        sizeof(usb_os_desc_header) + sizeof(usb_ext_compat_desc),
+        "Size of mtp descriptor is incorrect!");
+
+#define STR_INTERFACE "MTP"
+struct functionfs_lang {
+    __le16 code;
+    char str1[sizeof(STR_INTERFACE)];
+} __attribute__((packed));
+
+struct functionfs_strings {
+    struct usb_functionfs_strings_head header;
+    struct functionfs_lang lang0;
+} __attribute__((packed));
+
+extern const struct desc_v2 mtp_desc_v2;
+extern const struct desc_v2 ptp_desc_v2;
+extern const struct desc_v1 mtp_desc_v1;
+extern const struct desc_v1 ptp_desc_v1;
+extern const struct functionfs_strings mtp_strings;
+
+}; // namespace android
+
+#endif // MTP_DESCRIPTORS_H
diff --git a/media/mtp/MtpFfsHandle.cpp b/media/mtp/MtpFfsHandle.cpp
index 965985d..cb9827f 100644
--- a/media/mtp/MtpFfsHandle.cpp
+++ b/media/mtp/MtpFfsHandle.cpp
@@ -20,13 +20,10 @@
 #include <dirent.h>
 #include <errno.h>
 #include <fcntl.h>
-#include <linux/usb/ch9.h>
-#include <linux/usb/functionfs.h>
 #include <memory>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <sys/endian.h>
 #include <sys/eventfd.h>
 #include <sys/ioctl.h>
 #include <sys/mman.h>
@@ -36,6 +33,7 @@
 #include <unistd.h>
 
 #include "PosixAsyncIO.h"
+#include "MtpDescriptors.h"
 #include "MtpFfsHandle.h"
 #include "mtp.h"
 
@@ -45,11 +43,6 @@
 constexpr char FFS_MTP_EP_OUT[] = "/dev/usb-ffs/mtp/ep2";
 constexpr char FFS_MTP_EP_INTR[] = "/dev/usb-ffs/mtp/ep3";
 
-constexpr int MAX_PACKET_SIZE_FS = 64;
-constexpr int MAX_PACKET_SIZE_HS = 512;
-constexpr int MAX_PACKET_SIZE_SS = 1024;
-constexpr int MAX_PACKET_SIZE_EV = 28;
-
 constexpr unsigned AIO_BUFS_MAX = 128;
 constexpr unsigned AIO_BUF_LEN = 16384;
 
@@ -61,234 +54,6 @@
 
 struct timespec ZERO_TIMEOUT = { 0, 0 };
 
-struct func_desc {
-    struct usb_interface_descriptor intf;
-    struct usb_endpoint_descriptor_no_audio sink;
-    struct usb_endpoint_descriptor_no_audio source;
-    struct usb_endpoint_descriptor_no_audio intr;
-} __attribute__((packed));
-
-struct ss_func_desc {
-    struct usb_interface_descriptor intf;
-    struct usb_endpoint_descriptor_no_audio sink;
-    struct usb_ss_ep_comp_descriptor sink_comp;
-    struct usb_endpoint_descriptor_no_audio source;
-    struct usb_ss_ep_comp_descriptor source_comp;
-    struct usb_endpoint_descriptor_no_audio intr;
-    struct usb_ss_ep_comp_descriptor intr_comp;
-} __attribute__((packed));
-
-struct desc_v1 {
-    struct usb_functionfs_descs_head_v1 {
-        __le32 magic;
-        __le32 length;
-        __le32 fs_count;
-        __le32 hs_count;
-    } __attribute__((packed)) header;
-    struct func_desc fs_descs, hs_descs;
-} __attribute__((packed));
-
-struct desc_v2 {
-    struct usb_functionfs_descs_head_v2 header;
-    // The rest of the structure depends on the flags in the header.
-    __le32 fs_count;
-    __le32 hs_count;
-    __le32 ss_count;
-    __le32 os_count;
-    struct func_desc fs_descs, hs_descs;
-    struct ss_func_desc ss_descs;
-    struct usb_os_desc_header os_header;
-    struct usb_ext_compat_desc os_desc;
-} __attribute__((packed));
-
-const struct usb_interface_descriptor mtp_interface_desc = {
-    .bLength = USB_DT_INTERFACE_SIZE,
-    .bDescriptorType = USB_DT_INTERFACE,
-    .bInterfaceNumber = 0,
-    .bNumEndpoints = 3,
-    .bInterfaceClass = USB_CLASS_STILL_IMAGE,
-    .bInterfaceSubClass = 1,
-    .bInterfaceProtocol = 1,
-    .iInterface = 1,
-};
-
-const struct usb_interface_descriptor ptp_interface_desc = {
-    .bLength = USB_DT_INTERFACE_SIZE,
-    .bDescriptorType = USB_DT_INTERFACE,
-    .bInterfaceNumber = 0,
-    .bNumEndpoints = 3,
-    .bInterfaceClass = USB_CLASS_STILL_IMAGE,
-    .bInterfaceSubClass = 1,
-    .bInterfaceProtocol = 1,
-};
-
-const struct usb_endpoint_descriptor_no_audio fs_sink = {
-    .bLength = USB_DT_ENDPOINT_SIZE,
-    .bDescriptorType = USB_DT_ENDPOINT,
-    .bEndpointAddress = 1 | USB_DIR_IN,
-    .bmAttributes = USB_ENDPOINT_XFER_BULK,
-    .wMaxPacketSize = MAX_PACKET_SIZE_FS,
-};
-
-const struct usb_endpoint_descriptor_no_audio fs_source = {
-    .bLength = USB_DT_ENDPOINT_SIZE,
-    .bDescriptorType = USB_DT_ENDPOINT,
-    .bEndpointAddress = 2 | USB_DIR_OUT,
-    .bmAttributes = USB_ENDPOINT_XFER_BULK,
-    .wMaxPacketSize = MAX_PACKET_SIZE_FS,
-};
-
-const struct usb_endpoint_descriptor_no_audio intr = {
-    .bLength = USB_DT_ENDPOINT_SIZE,
-    .bDescriptorType = USB_DT_ENDPOINT,
-    .bEndpointAddress = 3 | USB_DIR_IN,
-    .bmAttributes = USB_ENDPOINT_XFER_INT,
-    .wMaxPacketSize = MAX_PACKET_SIZE_EV,
-    .bInterval = 6,
-};
-
-const struct usb_endpoint_descriptor_no_audio hs_sink = {
-    .bLength = USB_DT_ENDPOINT_SIZE,
-    .bDescriptorType = USB_DT_ENDPOINT,
-    .bEndpointAddress = 1 | USB_DIR_IN,
-    .bmAttributes = USB_ENDPOINT_XFER_BULK,
-    .wMaxPacketSize = MAX_PACKET_SIZE_HS,
-};
-
-const struct usb_endpoint_descriptor_no_audio hs_source = {
-    .bLength = USB_DT_ENDPOINT_SIZE,
-    .bDescriptorType = USB_DT_ENDPOINT,
-    .bEndpointAddress = 2 | USB_DIR_OUT,
-    .bmAttributes = USB_ENDPOINT_XFER_BULK,
-    .wMaxPacketSize = MAX_PACKET_SIZE_HS,
-};
-
-const struct usb_endpoint_descriptor_no_audio ss_sink = {
-    .bLength = USB_DT_ENDPOINT_SIZE,
-    .bDescriptorType = USB_DT_ENDPOINT,
-    .bEndpointAddress = 1 | USB_DIR_IN,
-    .bmAttributes = USB_ENDPOINT_XFER_BULK,
-    .wMaxPacketSize = MAX_PACKET_SIZE_SS,
-};
-
-const struct usb_endpoint_descriptor_no_audio ss_source = {
-    .bLength = USB_DT_ENDPOINT_SIZE,
-    .bDescriptorType = USB_DT_ENDPOINT,
-    .bEndpointAddress = 2 | USB_DIR_OUT,
-    .bmAttributes = USB_ENDPOINT_XFER_BULK,
-    .wMaxPacketSize = MAX_PACKET_SIZE_SS,
-};
-
-const struct usb_ss_ep_comp_descriptor ss_sink_comp = {
-    .bLength = sizeof(ss_sink_comp),
-    .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
-    .bMaxBurst = 6,
-};
-
-const struct usb_ss_ep_comp_descriptor ss_source_comp = {
-    .bLength = sizeof(ss_source_comp),
-    .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
-    .bMaxBurst = 6,
-};
-
-const struct usb_ss_ep_comp_descriptor ss_intr_comp = {
-    .bLength = sizeof(ss_intr_comp),
-    .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
-};
-
-const struct func_desc mtp_fs_descriptors = {
-    .intf = mtp_interface_desc,
-    .sink = fs_sink,
-    .source = fs_source,
-    .intr = intr,
-};
-
-const struct func_desc mtp_hs_descriptors = {
-    .intf = mtp_interface_desc,
-    .sink = hs_sink,
-    .source = hs_source,
-    .intr = intr,
-};
-
-const struct ss_func_desc mtp_ss_descriptors = {
-    .intf = mtp_interface_desc,
-    .sink = ss_sink,
-    .sink_comp = ss_sink_comp,
-    .source = ss_source,
-    .source_comp = ss_source_comp,
-    .intr = intr,
-    .intr_comp = ss_intr_comp,
-};
-
-const struct func_desc ptp_fs_descriptors = {
-    .intf = ptp_interface_desc,
-    .sink = fs_sink,
-    .source = fs_source,
-    .intr = intr,
-};
-
-const struct func_desc ptp_hs_descriptors = {
-    .intf = ptp_interface_desc,
-    .sink = hs_sink,
-    .source = hs_source,
-    .intr = intr,
-};
-
-const struct ss_func_desc ptp_ss_descriptors = {
-    .intf = ptp_interface_desc,
-    .sink = ss_sink,
-    .sink_comp = ss_sink_comp,
-    .source = ss_source,
-    .source_comp = ss_source_comp,
-    .intr = intr,
-    .intr_comp = ss_intr_comp,
-};
-
-#define STR_INTERFACE "MTP"
-const struct {
-    struct usb_functionfs_strings_head header;
-    struct {
-        __le16 code;
-        const char str1[sizeof(STR_INTERFACE)];
-    } __attribute__((packed)) lang0;
-} __attribute__((packed)) strings = {
-    .header = {
-        .magic = htole32(FUNCTIONFS_STRINGS_MAGIC),
-        .length = htole32(sizeof(strings)),
-        .str_count = htole32(1),
-        .lang_count = htole32(1),
-    },
-    .lang0 = {
-        .code = htole16(0x0409),
-        .str1 = STR_INTERFACE,
-    },
-};
-
-struct usb_os_desc_header mtp_os_desc_header = {
-    .interface = htole32(1),
-    .dwLength = htole32(sizeof(usb_os_desc_header) + sizeof(usb_ext_compat_desc)),
-    .bcdVersion = htole16(1),
-    .wIndex = htole16(4),
-    .bCount = htole16(1),
-    .Reserved = htole16(0),
-};
-
-struct usb_ext_compat_desc mtp_os_desc_compat = {
-    .bFirstInterfaceNumber = 0,
-    .Reserved1 = htole32(1),
-    .CompatibleID = { 'M', 'T', 'P' },
-    .SubCompatibleID = {0},
-    .Reserved2 = {0},
-};
-
-struct usb_ext_compat_desc ptp_os_desc_compat = {
-    .bFirstInterfaceNumber = 0,
-    .Reserved1 = htole32(1),
-    .CompatibleID = { 'P', 'T', 'P' },
-    .SubCompatibleID = {0},
-    .Reserved2 = {0},
-};
-
 struct mtp_device_status {
     uint16_t  wLength;
     uint16_t  wCode;
@@ -357,58 +122,38 @@
 }
 
 bool MtpFfsHandle::initFunctionfs() {
-    ssize_t ret;
-    struct desc_v1 v1_descriptor;
-    struct desc_v2 v2_descriptor;
-
-    v2_descriptor.header.magic = htole32(FUNCTIONFS_DESCRIPTORS_MAGIC_V2);
-    v2_descriptor.header.length = htole32(sizeof(v2_descriptor));
-    v2_descriptor.header.flags = FUNCTIONFS_HAS_FS_DESC | FUNCTIONFS_HAS_HS_DESC |
-                                 FUNCTIONFS_HAS_SS_DESC | FUNCTIONFS_HAS_MS_OS_DESC;
-    v2_descriptor.fs_count = 4;
-    v2_descriptor.hs_count = 4;
-    v2_descriptor.ss_count = 7;
-    v2_descriptor.os_count = 1;
-    v2_descriptor.fs_descs = mPtp ? ptp_fs_descriptors : mtp_fs_descriptors;
-    v2_descriptor.hs_descs = mPtp ? ptp_hs_descriptors : mtp_hs_descriptors;
-    v2_descriptor.ss_descs = mPtp ? ptp_ss_descriptors : mtp_ss_descriptors;
-    v2_descriptor.os_header = mtp_os_desc_header;
-    v2_descriptor.os_desc = mPtp ? ptp_os_desc_compat : mtp_os_desc_compat;
-
     if (mControl < 0) { // might have already done this before
         mControl.reset(TEMP_FAILURE_RETRY(open(FFS_MTP_EP0, O_RDWR)));
         if (mControl < 0) {
             PLOG(ERROR) << FFS_MTP_EP0 << ": cannot open control endpoint";
-            goto err;
+            return false;
         }
-
-        ret = TEMP_FAILURE_RETRY(::write(mControl, &v2_descriptor, sizeof(v2_descriptor)));
-        if (ret < 0) {
-            v1_descriptor.header.magic = htole32(FUNCTIONFS_DESCRIPTORS_MAGIC);
-            v1_descriptor.header.length = htole32(sizeof(v1_descriptor));
-            v1_descriptor.header.fs_count = 4;
-            v1_descriptor.header.hs_count = 4;
-            v1_descriptor.fs_descs = mPtp ? ptp_fs_descriptors : mtp_fs_descriptors;
-            v1_descriptor.hs_descs = mPtp ? ptp_hs_descriptors : mtp_hs_descriptors;
-            PLOG(ERROR) << FFS_MTP_EP0 << "Switching to V1 descriptor format";
-            ret = TEMP_FAILURE_RETRY(::write(mControl, &v1_descriptor, sizeof(v1_descriptor)));
-            if (ret < 0) {
-                PLOG(ERROR) << FFS_MTP_EP0 << "Writing descriptors failed";
-                goto err;
-            }
-        }
-        ret = TEMP_FAILURE_RETRY(::write(mControl, &strings, sizeof(strings)));
-        if (ret < 0) {
-            PLOG(ERROR) << FFS_MTP_EP0 << "Writing strings failed";
-            goto err;
+        if (!writeDescriptors()) {
+            closeConfig();
+            return false;
         }
     }
-
     return true;
+}
 
-err:
-    closeConfig();
-    return false;
+bool MtpFfsHandle::writeDescriptors() {
+    ssize_t ret = TEMP_FAILURE_RETRY(::write(mControl,
+                &(mPtp ? ptp_desc_v2 : mtp_desc_v2), sizeof(desc_v2)));
+    if (ret < 0) {
+        PLOG(ERROR) << FFS_MTP_EP0 << "Switching to V1 descriptor format";
+        ret = TEMP_FAILURE_RETRY(::write(mControl,
+                    &(mPtp ? ptp_desc_v1 : mtp_desc_v1), sizeof(desc_v1)));
+        if (ret < 0) {
+            PLOG(ERROR) << FFS_MTP_EP0 << "Writing descriptors failed";
+            return false;
+        }
+    }
+    ret = TEMP_FAILURE_RETRY(::write(mControl, &mtp_strings, sizeof(mtp_strings)));
+    if (ret < 0) {
+        PLOG(ERROR) << FFS_MTP_EP0 << "Writing strings failed";
+        return false;
+    }
+    return true;
 }
 
 void MtpFfsHandle::closeConfig() {
diff --git a/media/mtp/MtpFfsHandle.h b/media/mtp/MtpFfsHandle.h
index 2f90bd1..2347000 100644
--- a/media/mtp/MtpFfsHandle.h
+++ b/media/mtp/MtpFfsHandle.h
@@ -42,11 +42,14 @@
 };
 
 template <class T> class MtpFfsHandleTest;
+template <class T> class MtpFfsHandleTest_testControl_Test;
 
 class MtpFfsHandle : public IMtpHandle {
-    template <class T> friend class android::MtpFfsHandleTest;
+    template <class T> friend class MtpFfsHandleTest;
+    template <class T> friend class MtpFfsHandleTest_testControl_Test;
 protected:
     bool initFunctionfs();
+    bool writeDescriptors();
     void closeConfig();
     void closeEndpoints();
     void advise(int fd);
diff --git a/media/mtp/MtpServer.cpp b/media/mtp/MtpServer.cpp
index 236f3a9..7b3e96e 100644
--- a/media/mtp/MtpServer.cpp
+++ b/media/mtp/MtpServer.cpp
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#include <android-base/logging.h>
 #include <android-base/properties.h>
 #include <chrono>
 #include <dirent.h>
@@ -99,16 +100,12 @@
 };
 
 MtpServer::MtpServer(MtpDatabase* database, bool ptp,
-                    int fileGroup, int filePerm, int directoryPerm,
                     const MtpString& deviceInfoManufacturer,
                     const MtpString& deviceInfoModel,
                     const MtpString& deviceInfoDeviceVersion,
                     const MtpString& deviceInfoSerialNumber)
     :   mDatabase(database),
         mPtp(ptp),
-        mFileGroup(fileGroup),
-        mFilePermission(filePerm),
-        mDirectoryPermission(directoryPerm),
         mDeviceInfoManufacturer(deviceInfoManufacturer),
         mDeviceInfoModel(deviceInfoModel),
         mDeviceInfoDeviceVersion(deviceInfoDeviceVersion),
@@ -1002,12 +999,9 @@
     }
 
   if (format == MTP_FORMAT_ASSOCIATION) {
-        mode_t mask = umask(0);
-        int ret = mkdir((const char *)path, mDirectoryPermission);
-        umask(mask);
-        if (ret && ret != -EEXIST)
+        int ret = makeFolder((const char *)path);
+        if (ret)
             return MTP_RESPONSE_GENERAL_ERROR;
-        chown((const char *)path, getuid(), mFileGroup);
 
         // SendObject does not get sent for directories, so call endSendObject here instead
         mDatabase->endSendObject(path, handle, MTP_FORMAT_ASSOCIATION, MTP_RESPONSE_OK);
@@ -1068,29 +1062,34 @@
         path += "/";
     path += info.mName;
 
-    result = mDatabase->moveObject(objectHandle, parent, path);
-    if (result != MTP_RESPONSE_OK)
-        return result;
-
     if (info.mStorageID == storageID) {
         ALOGV("Moving file from %s to %s", (const char*)fromPath, (const char*)path);
         if (rename(fromPath, path)) {
-            ALOGE("rename() failed from %s to %s", (const char*)fromPath, (const char*)path);
+            PLOG(ERROR) << "rename() failed from " << fromPath << " to " << path;
             result = MTP_RESPONSE_GENERAL_ERROR;
         }
     } else {
         ALOGV("Moving across storages from %s to %s", (const char*)fromPath, (const char*)path);
-        if (copyFile(fromPath, path)) {
-            result = MTP_RESPONSE_GENERAL_ERROR;
+        if (format == MTP_FORMAT_ASSOCIATION) {
+            int ret = makeFolder((const char *)path);
+            ret += copyRecursive(fromPath, path);
+            if (ret) {
+                result = MTP_RESPONSE_GENERAL_ERROR;
+            } else {
+                deletePath(fromPath);
+            }
         } else {
-            deletePath(fromPath);
+            if (copyFile(fromPath, path)) {
+                result = MTP_RESPONSE_GENERAL_ERROR;
+            } else {
+                deletePath(fromPath);
+            }
         }
     }
 
     // If the move failed, undo the database change
-    if (result != MTP_RESPONSE_OK)
-        if (mDatabase->moveObject(objectHandle, info.mParent, fromPath) != MTP_RESPONSE_OK)
-            ALOGE("Couldn't undo failed move");
+    if (result == MTP_RESPONSE_OK)
+        result = mDatabase->moveObject(objectHandle, parent, storageID, path);
 
     return result;
 }
@@ -1148,8 +1147,15 @@
     }
 
     ALOGV("Copying file from %s to %s", (const char*)fromPath, (const char*)path);
-    if (copyFile(fromPath, path)) {
-        result = MTP_RESPONSE_GENERAL_ERROR;
+    if (format == MTP_FORMAT_ASSOCIATION) {
+        int ret = makeFolder((const char *)path);
+        if (ret) {
+            result = MTP_RESPONSE_GENERAL_ERROR;
+        }
+    } else {
+        if (copyFile(fromPath, path)) {
+            result = MTP_RESPONSE_GENERAL_ERROR;
+        }
     }
 
     mDatabase->endSendObject(path, handle, format, result);
@@ -1188,10 +1194,10 @@
         result = MTP_RESPONSE_GENERAL_ERROR;
         goto done;
     }
-    fchown(mfr.fd, getuid(), mFileGroup);
+    fchown(mfr.fd, getuid(), FILE_GROUP);
     // set permissions
     mask = umask(0);
-    fchmod(mfr.fd, mFilePermission);
+    fchmod(mfr.fd, FILE_PERM);
     umask(mask);
 
     if (initialData > 0) {
diff --git a/media/mtp/MtpServer.h b/media/mtp/MtpServer.h
index aafc753..0204b09 100644
--- a/media/mtp/MtpServer.h
+++ b/media/mtp/MtpServer.h
@@ -43,12 +43,6 @@
     // appear as a PTP device
     bool                mPtp;
 
-    // group to own new files and folders
-    int                 mFileGroup;
-    // permissions for new files and directories
-    int                 mFilePermission;
-    int                 mDirectoryPermission;
-
     // Manufacturer to report in DeviceInfo
     MtpString           mDeviceInfoManufacturer;
     // Model to report in DeviceInfo
@@ -105,7 +99,6 @@
 
 public:
                         MtpServer(MtpDatabase* database, bool ptp,
-                                    int fileGroup, int filePerm, int directoryPerm,
                                     const MtpString& deviceInfoManufacturer,
                                     const MtpString& deviceInfoModel,
                                     const MtpString& deviceInfoDeviceVersion,
diff --git a/media/mtp/MtpUtils.cpp b/media/mtp/MtpUtils.cpp
index 036ffe7..3f5648b 100644
--- a/media/mtp/MtpUtils.cpp
+++ b/media/mtp/MtpUtils.cpp
@@ -20,6 +20,7 @@
 #include <android-base/unique_fd.h>
 #include <dirent.h>
 #include <fcntl.h>
+#include <string>
 #include <sys/sendfile.h>
 #include <sys/stat.h>
 #include <sys/types.h>
@@ -29,6 +30,8 @@
 
 #include "MtpUtils.h"
 
+using namespace std;
+
 namespace android {
 
 constexpr unsigned long FILE_COPY_SIZE = 262144;
@@ -88,6 +91,60 @@
         tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec);
 }
 
+int makeFolder(const char *path) {
+    mode_t mask = umask(0);
+    int ret = mkdir((const char *)path, DIR_PERM);
+    umask(mask);
+    if (ret && ret != -EEXIST) {
+        PLOG(ERROR) << "Failed to create folder " << path;
+        ret = -1;
+    } else {
+        chown((const char *)path, getuid(), FILE_GROUP);
+    }
+    return ret;
+}
+
+/**
+ * Copies target path and all children to destination path.
+ *
+ * Returns 0 on success or a negative value indicating number of failures
+ */
+int copyRecursive(const char *fromPath, const char *toPath) {
+    int ret = 0;
+    string fromPathStr(fromPath);
+    string toPathStr(toPath);
+
+    DIR* dir = opendir(fromPath);
+    if (!dir) {
+        PLOG(ERROR) << "opendir " << fromPath << " failed";
+        return -1;
+    }
+    if (fromPathStr[fromPathStr.size()-1] != '/')
+        fromPathStr += '/';
+    if (toPathStr[toPathStr.size()-1] != '/')
+        toPathStr += '/';
+
+    struct dirent* entry;
+    while ((entry = readdir(dir))) {
+        const char* name = entry->d_name;
+
+        // ignore "." and ".."
+        if (name[0] == '.' && (name[1] == 0 || (name[1] == '.' && name[2] == 0))) {
+            continue;
+        }
+        string oldFile = fromPathStr + name;
+        string newFile = toPathStr + name;
+
+        if (entry->d_type == DT_DIR) {
+            ret += makeFolder(newFile.c_str());
+            ret += copyRecursive(oldFile.c_str(), newFile.c_str());
+        } else {
+            ret += copyFile(oldFile.c_str(), newFile.c_str());
+        }
+    }
+    return ret;
+}
+
 int copyFile(const char *fromPath, const char *toPath) {
     auto start = std::chrono::steady_clock::now();
 
@@ -96,7 +153,7 @@
         PLOG(ERROR) << "Failed to open copy from " << fromPath;
         return -1;
     }
-    android::base::unique_fd toFd(open(toPath, O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR));
+    android::base::unique_fd toFd(open(toPath, O_CREAT | O_WRONLY, FILE_PERM));
     if (toFd == -1) {
         PLOG(ERROR) << "Failed to open copy to " << toPath;
         return -1;
@@ -121,23 +178,17 @@
     }
     auto end = std::chrono::steady_clock::now();
     std::chrono::duration<double> diff = end - start;
-    LOG(INFO) << "Copied a file with MTP. Time: " << diff.count() << " s, Size: " << length <<
+    LOG(DEBUG) << "Copied a file with MTP. Time: " << diff.count() << " s, Size: " << length <<
         ", Rate: " << ((double) length) / diff.count() << " bytes/s";
+    chown(toPath, getuid(), FILE_GROUP);
     return ret == -1 ? -1 : 0;
 }
 
 void deleteRecursive(const char* path) {
-    char pathbuf[PATH_MAX];
-    size_t pathLength = strlen(path);
-    if (pathLength >= sizeof(pathbuf) - 1) {
-        LOG(ERROR) << "path too long: " << path;
+    string pathStr(path);
+    if (pathStr[pathStr.size()-1] != '/') {
+        pathStr += '/';
     }
-    strcpy(pathbuf, path);
-    if (pathbuf[pathLength - 1] != '/') {
-        pathbuf[pathLength++] = '/';
-    }
-    char* fileSpot = pathbuf + pathLength;
-    int pathRemaining = sizeof(pathbuf) - pathLength - 1;
 
     DIR* dir = opendir(path);
     if (!dir) {
@@ -153,19 +204,12 @@
         if (name[0] == '.' && (name[1] == 0 || (name[1] == '.' && name[2] == 0))) {
             continue;
         }
-
-        int nameLength = strlen(name);
-        if (nameLength > pathRemaining) {
-            LOG(ERROR) << "path " << path << "/" << name << " too long";
-            continue;
-        }
-        strcpy(fileSpot, name);
-
+        pathStr.append(name);
         if (entry->d_type == DT_DIR) {
-            deleteRecursive(pathbuf);
-            rmdir(pathbuf);
+            deleteRecursive(pathStr.c_str());
+            rmdir(pathStr.c_str());
         } else {
-            unlink(pathbuf);
+            unlink(pathStr.c_str());
         }
     }
     closedir(dir);
diff --git a/media/mtp/MtpUtils.h b/media/mtp/MtpUtils.h
index a2bb7e1..b7c72f5 100644
--- a/media/mtp/MtpUtils.h
+++ b/media/mtp/MtpUtils.h
@@ -17,13 +17,21 @@
 #ifndef _MTP_UTILS_H
 #define _MTP_UTILS_H
 
+#include "private/android_filesystem_config.h"
+
 #include <stdint.h>
 
 namespace android {
 
+constexpr int FILE_GROUP = AID_MEDIA_RW;
+constexpr int FILE_PERM = 0664;
+constexpr int DIR_PERM = 0775;
+
 bool parseDateTime(const char* dateTime, time_t& outSeconds);
 void formatDateTime(time_t seconds, char* buffer, int bufferLength);
 
+int makeFolder(const char *path);
+int copyRecursive(const char *fromPath, const char *toPath);
 int copyFile(const char *fromPath, const char *toPath);
 void deleteRecursive(const char* path);
 void deletePath(const char* path);
diff --git a/media/mtp/OWNERS b/media/mtp/OWNERS
new file mode 100644
index 0000000..219307b
--- /dev/null
+++ b/media/mtp/OWNERS
@@ -0,0 +1 @@
+zhangjerry@google.com
diff --git a/media/mtp/tests/MtpFfsHandle_test.cpp b/media/mtp/tests/MtpFfsHandle_test.cpp
index 8d7301d..9c916b7 100644
--- a/media/mtp/tests/MtpFfsHandle_test.cpp
+++ b/media/mtp/tests/MtpFfsHandle_test.cpp
@@ -25,6 +25,7 @@
 #include <unistd.h>
 #include <utils/Log.h>
 
+#include "MtpDescriptors.h"
 #include "MtpFfsHandle.h"
 #include "MtpFfsCompatHandle.h"
 
@@ -66,8 +67,8 @@
         handle = std::make_unique<T>();
 
         EXPECT_EQ(pipe(fd), 0);
-        handle->mControl.reset(fd[0]);
-        control.reset(fd[1]);
+        control.reset(fd[0]);
+        handle->mControl.reset(fd[1]);
 
         EXPECT_EQ(pipe(fd), 0);
         EXPECT_EQ(fcntl(fd[0], F_SETPIPE_SZ, 1048576), 1048576);
@@ -83,7 +84,7 @@
         intr.reset(fd[0]);
         handle->mIntr.reset(fd[1]);
 
-        handle->start();
+        EXPECT_EQ(handle->start(), 0);
     }
 
     ~MtpFfsHandleTest() {
@@ -94,6 +95,16 @@
 typedef ::testing::Types<MtpFfsHandle, MtpFfsCompatHandle> mtpHandles;
 TYPED_TEST_CASE(MtpFfsHandleTest, mtpHandles);
 
+TYPED_TEST(MtpFfsHandleTest, testControl) {
+    EXPECT_TRUE(this->handle->writeDescriptors());
+    struct desc_v2 desc;
+    struct functionfs_strings strings;
+    EXPECT_EQ(read(this->control, &desc, sizeof(desc)), (long)sizeof(desc));
+    EXPECT_EQ(read(this->control, &strings, sizeof(strings)), (long)sizeof(strings));
+    EXPECT_TRUE(std::memcmp(&desc, &mtp_desc_v2, sizeof(desc)) == 0);
+    EXPECT_TRUE(std::memcmp(&strings, &mtp_strings, sizeof(strings)) == 0);
+}
+
 TYPED_TEST(MtpFfsHandleTest, testRead) {
     EXPECT_EQ(write(this->bulk_out, dummyDataStr.c_str(), TEST_PACKET_SIZE), TEST_PACKET_SIZE);
     char buf[TEST_PACKET_SIZE + 1];
diff --git a/media/ndk/Android.bp b/media/ndk/Android.bp
index 116f156..cea2f9e 100644
--- a/media/ndk/Android.bp
+++ b/media/ndk/Android.bp
@@ -67,6 +67,7 @@
     shared_libs: [
         "libbinder",
         "libmedia",
+        "libmedia_omx",
         "libmedia_jni",
         "libmediadrm",
         "libstagefright",
diff --git a/media/ndk/NdkImage.cpp b/media/ndk/NdkImage.cpp
index 87b649a..c4ff537 100644
--- a/media/ndk/NdkImage.cpp
+++ b/media/ndk/NdkImage.cpp
@@ -53,7 +53,6 @@
 
 void
 AImage::close(int releaseFenceFd) {
-    lockReader();
     Mutex::Autolock _l(mLock);
     if (mIsClosed) {
         return;
@@ -71,7 +70,6 @@
     mBuffer = nullptr;
     mLockedBuffer = nullptr;
     mIsClosed = true;
-    unlockReader();
 }
 
 void
@@ -622,7 +620,9 @@
 void AImage_deleteAsync(AImage* image, int releaseFenceFd) {
     ALOGV("%s", __FUNCTION__);
     if (image != nullptr) {
+        image->lockReader();
         image->close(releaseFenceFd);
+        image->unlockReader();
         if (!image->isClosed()) {
             LOG_ALWAYS_FATAL("Image close failed!");
         }
diff --git a/media/ndk/NdkImageReader.cpp b/media/ndk/NdkImageReader.cpp
index ee6f2c8..be635ff 100644
--- a/media/ndk/NdkImageReader.cpp
+++ b/media/ndk/NdkImageReader.cpp
@@ -349,8 +349,8 @@
     for (auto it = mAcquiredImages.begin();
               it != mAcquiredImages.end(); it++) {
         AImage* image = *it;
+        Mutex::Autolock _l(image->mLock);
         releaseImageLocked(image, /*releaseFenceFd*/-1);
-        image->close();
     }
 
     // Delete Buffer Items
@@ -502,6 +502,8 @@
     mBufferItemConsumer->releaseBuffer(*buffer, bufferFence);
     returnBufferItemLocked(buffer);
     image->mBuffer = nullptr;
+    image->mLockedBuffer = nullptr;
+    image->mIsClosed = true;
 
     bool found = false;
     // cleanup acquired image list
diff --git a/media/ndk/NdkImageReaderPriv.h b/media/ndk/NdkImageReaderPriv.h
index 989b937..bed8a21 100644
--- a/media/ndk/NdkImageReaderPriv.h
+++ b/media/ndk/NdkImageReaderPriv.h
@@ -85,7 +85,7 @@
     // Called by AImageReader_acquireXXX to acquire a Buffer and setup AImage.
     media_status_t acquireImageLocked(/*out*/AImage** image, /*out*/int* fenceFd);
 
-    // Called by AImage to close image
+    // Called by AImage/~AImageReader to close image. Caller is responsible to grab AImage::mLock
     void releaseImageLocked(AImage* image, int releaseFenceFd);
 
     static int getBufferWidth(BufferItem* buffer);
diff --git a/media/ndk/include/media/NdkImageReader.h b/media/ndk/include/media/NdkImageReader.h
index a8667c9..e3b99d0 100644
--- a/media/ndk/include/media/NdkImageReader.h
+++ b/media/ndk/include/media/NdkImageReader.h
@@ -305,9 +305,9 @@
 /**
  * AImageReader constructor similar to {@link AImageReader_new} that takes an additional parameter
  * for the consumer usage. All other parameters and the return values are identical to those passed
- * to {@line AImageReader_new}.
+ * to {@link AImageReader_new}.
  *
- * <p>If the {@code format} is {@link AIMAGE_FORMAT_PRIVATE}, the created {@link AImageReader}
+ * <p>If the \c format is {@link AIMAGE_FORMAT_PRIVATE}, the created {@link AImageReader}
  * will produce images whose contents are not directly accessible by the application. The application can
  * still acquire images from this {@link AImageReader} and access {@link AHardwareBuffer} via
  * {@link AImage_getHardwareBuffer()}. The {@link AHardwareBuffer} gained this way can then
@@ -322,7 +322,7 @@
  * AImageReader}s using other format such as {@link AIMAGE_FORMAT_YUV_420_888}.</p>
  *
  * <p>Note that not all format and usage flag combination is supported by the {@link AImageReader},
- * especially if {@code format} is {@link AIMAGE_FORMAT_PRIVATE}, {@code usage} must not include either
+ * especially if \c format is {@link AIMAGE_FORMAT_PRIVATE}, \c usage must not include either
  * {@link AHARDWAREBUFFER_USAGE_READ_RARELY} or {@link AHARDWAREBUFFER_USAGE_READ_OFTEN}</p>
  *
  * @param width The default width in pixels of the Images that this reader will produce.
@@ -367,7 +367,7 @@
         int32_t width, int32_t height, int32_t format, uint64_t usage, int32_t maxImages,
         /*out*/ AImageReader** reader);
 
-/*
+/**
  * Acquire the next {@link AImage} from the image reader's queue asynchronously.
  *
  * <p>AImageReader acquire method similar to {@link AImageReader_acquireNextImage} that takes an
@@ -377,7 +377,7 @@
  * @param acquireFenceFd A sync fence fd defined in {@link sync.h}, which is used to signal when the
  *         buffer is ready to consume. When synchronization fence is not needed, fence will be set
  *         to -1 and the {@link AImage} returned is ready for use immediately. Otherwise, user shall
- *         use syscalls such as {@code poll()}, {@code epoll()}, {@code select()} to wait for the
+ *         use syscalls such as \c poll(), \c epoll(), \c select() to wait for the
  *         fence fd to change status before attempting to access the {@link AImage} returned.
  *
  * @see sync.h
@@ -386,7 +386,7 @@
 media_status_t AImageReader_acquireNextImageAsync(
         AImageReader* reader, /*out*/AImage** image, /*out*/int* acquireFenceFd);
 
-/*
+/**
  * Acquire the latest {@link AImage} from the image reader's queue asynchronously, dropping older
  * images.
  *
@@ -397,7 +397,7 @@
  * @param acquireFenceFd A sync fence fd defined in {@link sync.h}, which is used to signal when the
  *         buffer is ready to consume. When synchronization fence is not needed, fence will be set
  *         to -1 and the {@link AImage} returned is ready for use immediately. Otherwise, user shall
- *         use syscalls such as {@code poll()}, {@code epoll()}, {@code select()} to wait for the
+ *         use syscalls such as \c poll(), \c epoll(), \c select() to wait for the
  *         fence fd to change status before attempting to access the {@link AImage} returned.
  *
  * @see sync.h
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 1e88ab2..8c7c830 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -3312,10 +3312,14 @@
                         // 2. threadLoop_mix (significant for heavy mixing, especially
                         //                    on low tier processors)
 
-                        // it's OK if deltaMs is an overestimate.
-                        const int32_t deltaMs =
-                                (lastWriteFinished - previousLastWriteFinished) / 1000000;
-                        const int32_t throttleMs = mHalfBufferMs - deltaMs;
+                        // it's OK if deltaMs (and deltaNs) is an overestimate.
+                        nsecs_t deltaNs;
+                        // deltaNs = lastWriteFinished - previousLastWriteFinished;
+                        __builtin_sub_overflow(
+                            lastWriteFinished,previousLastWriteFinished, &deltaNs);
+                        const int32_t deltaMs = deltaNs / 1000000;
+
+                        const int32_t throttleMs = (int32_t)mHalfBufferMs - deltaMs;
                         if ((signed)mHalfBufferMs >= throttleMs && throttleMs > 0) {
                             usleep(throttleMs * 1000);
                             // notify of throttle start on verbose log
diff --git a/services/audioflinger/TypedLogger.h b/services/audioflinger/TypedLogger.h
index cae74b1..38c3c02 100644
--- a/services/audioflinger/TypedLogger.h
+++ b/services/audioflinger/TypedLogger.h
@@ -64,7 +64,8 @@
 }
 
 template <typename T, size_t n>
-constexpr T fnv1a(const char (&file)[n], int i = n - 1) {
+__attribute__((no_sanitize("unsigned-integer-overflow")))
+constexpr T fnv1a(const char (&file)[n], ssize_t i = (ssize_t)n - 1) {
     return i == -1 ? offset_basis<T>() : (fnv1a<T>(file, i - 1) ^ file[i]) * FNV_prime<T>();
 }
 
diff --git a/services/audiopolicy/AudioPolicyInterface.h b/services/audiopolicy/AudioPolicyInterface.h
index 7b19f58..1a32433 100644
--- a/services/audiopolicy/AudioPolicyInterface.h
+++ b/services/audiopolicy/AudioPolicyInterface.h
@@ -109,12 +109,7 @@
     //
 
     // request an output appropriate for playback of the supplied stream type and parameters
-    virtual audio_io_handle_t getOutput(audio_stream_type_t stream,
-                                        uint32_t samplingRate,
-                                        audio_format_t format,
-                                        audio_channel_mask_t channelMask,
-                                        audio_output_flags_t flags,
-                                        const audio_offload_info_t *offloadInfo) = 0;
+    virtual audio_io_handle_t getOutput(audio_stream_type_t stream) = 0;
     virtual status_t getOutputForAttr(const audio_attributes_t *attr,
                                         audio_io_handle_t *output,
                                         audio_session_t session,
diff --git a/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp b/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp
index a224004..0908ffc 100644
--- a/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp
@@ -140,19 +140,19 @@
     }
 
     string minValueMBLiteral = getXmlAttribute(root, Attributes::minValueMB);
-    uint32_t minValueMB;
+    int32_t minValueMB;
     if (!minValueMBLiteral.empty() && convertTo(minValueMBLiteral, minValueMB)) {
         gain->setMinValueInMb(minValueMB);
     }
 
     string maxValueMBLiteral = getXmlAttribute(root, Attributes::maxValueMB);
-    uint32_t maxValueMB;
+    int32_t maxValueMB;
     if (!maxValueMBLiteral.empty() && convertTo(maxValueMBLiteral, maxValueMB)) {
         gain->setMaxValueInMb(maxValueMB);
     }
 
     string defaultValueMBLiteral = getXmlAttribute(root, Attributes::defaultValueMB);
-    uint32_t defaultValueMB;
+    int32_t defaultValueMB;
     if (!defaultValueMBLiteral.empty() && convertTo(defaultValueMBLiteral, defaultValueMB)) {
         gain->setDefaultValueInMb(defaultValueMB);
     }
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 906e05a..9c24641 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -751,20 +751,15 @@
     return profile;
 }
 
-audio_io_handle_t AudioPolicyManager::getOutput(audio_stream_type_t stream,
-                                                uint32_t samplingRate,
-                                                audio_format_t format,
-                                                audio_channel_mask_t channelMask,
-                                                audio_output_flags_t flags,
-                                                const audio_offload_info_t *offloadInfo)
+audio_io_handle_t AudioPolicyManager::getOutput(audio_stream_type_t stream)
 {
     routing_strategy strategy = getStrategy(stream);
     audio_devices_t device = getDeviceForStrategy(strategy, false /*fromCache*/);
-    ALOGV("getOutput() device %d, stream %d, samplingRate %d, format %x, channelMask %x, flags %x",
-          device, stream, samplingRate, format, channelMask, flags);
+    SortedVector<audio_io_handle_t> outputs = getOutputsForDevice(device, mOutputs);
+    audio_io_handle_t output = selectOutput(outputs, AUDIO_OUTPUT_FLAG_NONE, AUDIO_FORMAT_INVALID);
 
-    return getOutputForDevice(device, AUDIO_SESSION_ALLOCATE, stream, samplingRate, format,
-                              channelMask, flags, offloadInfo);
+    ALOGV("getOutput() stream %d selected device %08x, output %d", stream, device, output);
+    return output;
 }
 
 status_t AudioPolicyManager::getOutputForAttr(const audio_attributes_t *attr,
@@ -942,12 +937,12 @@
                     (channelMask == outputDesc->mChannelMask)) {
                   if (session == outputDesc->mDirectClientSession) {
                       outputDesc->mDirectOpenCount++;
-                      ALOGV("getOutput() reusing direct output %d for session %d",
+                      ALOGV("getOutputForDevice() reusing direct output %d for session %d",
                             mOutputs.keyAt(i), session);
                       return mOutputs.keyAt(i);
                   } else {
-                      ALOGV("getOutput() do not reuse direct output because current client (%d) "
-                            "is not the same as requesting client (%d)",
+                      ALOGV("getOutputForDevice() do not reuse direct output because"
+                              "current client (%d) is not the same as requesting client (%d)",
                             outputDesc->mDirectClientSession, session);
                       goto non_direct_output;
                   }
@@ -1002,7 +997,7 @@
             (samplingRate != 0 && samplingRate != config.sample_rate) ||
             (format != AUDIO_FORMAT_DEFAULT && !audio_formats_match(format, config.format)) ||
             (channelMask != 0 && channelMask != config.channel_mask)) {
-            ALOGV("getOutput() failed opening direct output: output %d samplingRate %d %d,"
+            ALOGV("getOutputForDevice() failed opening direct output: output %d samplingRate %d %d,"
                     "format %d %d, channelMask %04x %04x", output, samplingRate,
                     outputDesc->mSamplingRate, format, outputDesc->mFormat, channelMask,
                     outputDesc->mChannelMask);
@@ -1025,7 +1020,7 @@
 
         addOutput(output, outputDesc);
         mPreviousOutputs = mOutputs;
-        ALOGV("getOutput() returns new direct output %d", output);
+        ALOGV("getOutputForDevice() returns new direct output %d", output);
         mpClientInterface->onAudioPortListUpdate();
         return output;
     }
@@ -1052,8 +1047,9 @@
         flags = (audio_output_flags_t)(flags & ~AUDIO_OUTPUT_FLAG_DIRECT);
         output = selectOutput(outputs, flags, format);
     }
-    ALOGW_IF((output == 0), "getOutput() could not find output for stream %d, samplingRate %d, "
-            "format %d, channels %x, flags %x", stream, samplingRate, format, channelMask, flags);
+    ALOGW_IF((output == 0), "getOutputForDevice() could not find output for stream %d, "
+            "samplingRate %d, format %d, channels %x, flags %x",
+            stream, samplingRate, format, channelMask, flags);
 
     return output;
 }
@@ -1224,6 +1220,12 @@
     bool force = !outputDesc->isActive() &&
             (outputDesc->getPatchHandle() == AUDIO_PATCH_HANDLE_NONE);
 
+    // requiresMuteCheck is false when we can bypass mute strategy.
+    // It covers a common case when there is no materially active audio
+    // and muting would result in unnecessary delay and dropped audio.
+    const uint32_t outputLatencyMs = outputDesc->latency();
+    bool requiresMuteCheck = outputDesc->isActive(outputLatencyMs * 2);  // account for drain
+
     // increment usage count for this stream on the requested output:
     // NOTE that the usage count is the same for duplicated output and hardware output which is
     // necessary for a correct control of hardware output routing by startOutput() and stopOutput()
@@ -1247,29 +1249,44 @@
         for (size_t i = 0; i < mOutputs.size(); i++) {
             sp<AudioOutputDescriptor> desc = mOutputs.valueAt(i);
             if (desc != outputDesc) {
+                // An output has a shared device if
+                // - managed by the same hw module
+                // - supports the currently selected device
+                const bool sharedDevice = outputDesc->sharesHwModuleWith(desc)
+                        && (desc->supportedDevices() & device) != AUDIO_DEVICE_NONE;
+
                 // force a device change if any other output is:
                 // - managed by the same hw module
-                // - has a current device selection that differs from selected device.
                 // - supports currently selected device
+                // - has a current device selection that differs from selected device.
                 // - has an active audio patch
                 // In this case, the audio HAL must receive the new device selection so that it can
-                // change the device currently selected by the other active output.
-                if (outputDesc->sharesHwModuleWith(desc) &&
+                // change the device currently selected by the other output.
+                if (sharedDevice &&
                         desc->device() != device &&
-                        desc->supportedDevices() & device &&
                         desc->getPatchHandle() != AUDIO_PATCH_HANDLE_NONE) {
                     force = true;
                 }
                 // wait for audio on other active outputs to be presented when starting
                 // a notification so that audio focus effect can propagate, or that a mute/unmute
                 // event occurred for beacon
-                uint32_t latency = desc->latency();
-                if (shouldWait && desc->isActive(latency * 2) && (waitMs < latency)) {
-                    waitMs = latency;
+                const uint32_t latencyMs = desc->latency();
+                const bool isActive = desc->isActive(latencyMs * 2);  // account for drain
+
+                if (shouldWait && isActive && (waitMs < latencyMs)) {
+                    waitMs = latencyMs;
                 }
+
+                // Require mute check if another output is on a shared device
+                // and currently active to have proper drain and avoid pops.
+                // Note restoring AudioTracks onto this output needs to invoke
+                // a volume ramp if there is no mute.
+                requiresMuteCheck |= sharedDevice && isActive;
             }
         }
-        uint32_t muteWaitMs = setOutputDevice(outputDesc, device, force, 0, NULL, address);
+
+        const uint32_t muteWaitMs =
+                setOutputDevice(outputDesc, device, force, 0, NULL, address, requiresMuteCheck);
 
         // handle special case for sonification while in call
         if (isInCall()) {
@@ -1294,6 +1311,14 @@
         if (waitMs > muteWaitMs) {
             *delayMs = waitMs - muteWaitMs;
         }
+
+        // FIXME: A device change (muteWaitMs > 0) likely introduces a volume change.
+        // A volume change enacted by APM with 0 delay is not synchronous, as it goes
+        // via AudioCommandThread to AudioFlinger.  Hence it is possible that the volume
+        // change occurs after the MixerThread starts and causes a stream volume
+        // glitch.
+        //
+        // We do not introduce additional delay here.
     }
 
     return NO_ERROR;
@@ -4812,21 +4837,24 @@
                                              bool force,
                                              int delayMs,
                                              audio_patch_handle_t *patchHandle,
-                                             const char* address)
+                                             const char *address,
+                                             bool requiresMuteCheck)
 {
     ALOGV("setOutputDevice() device %04x delayMs %d", device, delayMs);
     AudioParameter param;
     uint32_t muteWaitMs;
 
     if (outputDesc->isDuplicated()) {
-        muteWaitMs = setOutputDevice(outputDesc->subOutput1(), device, force, delayMs);
-        muteWaitMs += setOutputDevice(outputDesc->subOutput2(), device, force, delayMs);
+        muteWaitMs = setOutputDevice(outputDesc->subOutput1(), device, force, delayMs,
+                nullptr /* patchHandle */, nullptr /* address */, requiresMuteCheck);
+        muteWaitMs += setOutputDevice(outputDesc->subOutput2(), device, force, delayMs,
+                nullptr /* patchHandle */, nullptr /* address */, requiresMuteCheck);
         return muteWaitMs;
     }
     // no need to proceed if new device is not AUDIO_DEVICE_NONE and not supported by current
     // output profile
     if ((device != AUDIO_DEVICE_NONE) &&
-            ((device & outputDesc->supportedDevices()) == 0)) {
+            ((device & outputDesc->supportedDevices()) == AUDIO_DEVICE_NONE)) {
         return 0;
     }
 
@@ -4840,7 +4868,14 @@
     if (device != AUDIO_DEVICE_NONE) {
         outputDesc->mDevice = device;
     }
-    muteWaitMs = checkDeviceMuteStrategies(outputDesc, prevDevice, delayMs);
+
+    // if the outputs are not materially active, there is no need to mute.
+    if (requiresMuteCheck) {
+        muteWaitMs = checkDeviceMuteStrategies(outputDesc, prevDevice, delayMs);
+    } else {
+        ALOGV("%s: suppressing checkDeviceMuteStrategies", __func__);
+        muteWaitMs = 0;
+    }
 
     // Do not change the routing if:
     //      the requested device is AUDIO_DEVICE_NONE
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
index 7ba0669..11894dc 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -99,12 +99,7 @@
 
         virtual void setSystemProperty(const char* property, const char* value);
         virtual status_t initCheck();
-        virtual audio_io_handle_t getOutput(audio_stream_type_t stream,
-                                            uint32_t samplingRate,
-                                            audio_format_t format,
-                                            audio_channel_mask_t channelMask,
-                                            audio_output_flags_t flags,
-                                            const audio_offload_info_t *offloadInfo);
+        virtual audio_io_handle_t getOutput(audio_stream_type_t stream);
         virtual status_t getOutputForAttr(const audio_attributes_t *attr,
                                           audio_io_handle_t *output,
                                           audio_session_t session,
@@ -300,7 +295,8 @@
                              bool force = false,
                              int delayMs = 0,
                              audio_patch_handle_t *patchHandle = NULL,
-                             const char* address = NULL);
+                             const char *address = nullptr,
+                             bool requiresMuteCheck = true);
         status_t resetOutputDevice(const sp<AudioOutputDescriptor>& outputDesc,
                                    int delayMs = 0,
                                    audio_patch_handle_t *patchHandle = NULL);
diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
index b7bce55..bd94e3e 100644
--- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
@@ -141,12 +141,7 @@
     return mAudioPolicyManager->getForceUse(usage);
 }
 
-audio_io_handle_t AudioPolicyService::getOutput(audio_stream_type_t stream,
-                                    uint32_t samplingRate,
-                                    audio_format_t format,
-                                    audio_channel_mask_t channelMask,
-                                    audio_output_flags_t flags,
-                                    const audio_offload_info_t *offloadInfo)
+audio_io_handle_t AudioPolicyService::getOutput(audio_stream_type_t stream)
 {
     if (uint32_t(stream) >= AUDIO_STREAM_PUBLIC_CNT) {
         return AUDIO_IO_HANDLE_NONE;
@@ -156,8 +151,7 @@
     }
     ALOGV("getOutput()");
     Mutex::Autolock _l(mLock);
-    return mAudioPolicyManager->getOutput(stream, samplingRate,
-                                    format, channelMask, flags, offloadInfo);
+    return mAudioPolicyManager->getOutput(stream);
 }
 
 status_t AudioPolicyService::getOutputForAttr(const audio_attributes_t *attr,
@@ -173,7 +167,7 @@
     if (mAudioPolicyManager == NULL) {
         return NO_INIT;
     }
-    ALOGV("getOutput()");
+    ALOGV("getOutputForAttr()");
     Mutex::Autolock _l(mLock);
 
     const uid_t callingUid = IPCThreadState::self()->getCallingUid();
diff --git a/services/audiopolicy/service/AudioPolicyService.cpp b/services/audiopolicy/service/AudioPolicyService.cpp
index b417631..7af2e74 100644
--- a/services/audiopolicy/service/AudioPolicyService.cpp
+++ b/services/audiopolicy/service/AudioPolicyService.cpp
@@ -859,7 +859,7 @@
     }
 
     // check same pending commands with later time stamps and eliminate them
-    for (i = mAudioCommands.size()-1; i >= 0; i--) {
+    for (i = (ssize_t)mAudioCommands.size()-1; i >= 0; i--) {
         sp<AudioCommand> command2 = mAudioCommands[i];
         // commands are sorted by increasing time stamp: no need to scan the rest of mAudioCommands
         if (command2->mTime <= command->mTime) break;
diff --git a/services/audiopolicy/service/AudioPolicyService.h b/services/audiopolicy/service/AudioPolicyService.h
index 38d4b17..268697e 100644
--- a/services/audiopolicy/service/AudioPolicyService.h
+++ b/services/audiopolicy/service/AudioPolicyService.h
@@ -68,13 +68,7 @@
     virtual status_t setPhoneState(audio_mode_t state);
     virtual status_t setForceUse(audio_policy_force_use_t usage, audio_policy_forced_cfg_t config);
     virtual audio_policy_forced_cfg_t getForceUse(audio_policy_force_use_t usage);
-    virtual audio_io_handle_t getOutput(audio_stream_type_t stream,
-                                        uint32_t samplingRate = 0,
-                                        audio_format_t format = AUDIO_FORMAT_DEFAULT,
-                                        audio_channel_mask_t channelMask = 0,
-                                        audio_output_flags_t flags =
-                                                AUDIO_OUTPUT_FLAG_NONE,
-                                        const audio_offload_info_t *offloadInfo = NULL);
+    virtual audio_io_handle_t getOutput(audio_stream_type_t stream);
     virtual status_t getOutputForAttr(const audio_attributes_t *attr,
                                       audio_io_handle_t *output,
                                       audio_session_t session,
diff --git a/services/mediaanalytics/MediaAnalyticsService.cpp b/services/mediaanalytics/MediaAnalyticsService.cpp
index c7f9270..f08be50 100644
--- a/services/mediaanalytics/MediaAnalyticsService.cpp
+++ b/services/mediaanalytics/MediaAnalyticsService.cpp
@@ -299,6 +299,8 @@
 
     bool finalizing = item->getFinalized();
 
+    Mutex::Autolock _l(mLock);
+
     // if finalizing, we'll remove it
     MediaAnalyticsItem *oitem = findItem(mOpen, item, finalizing | forcenew);
     if (oitem != NULL) {
@@ -609,10 +611,9 @@
 // XXX: rewrite this to manage persistence, etc.
 
 // insert appropriately into queue
+// caller should hold mLock
 void MediaAnalyticsService::saveItem(List<MediaAnalyticsItem *> *l, MediaAnalyticsItem * item, int front) {
 
-    Mutex::Autolock _l(mLock);
-
     // adding at back of queue (fifo order)
     if (front)  {
         l->push_front(item);
@@ -682,6 +683,7 @@
 }
 
 // find the incomplete record that this will overlay
+// caller should hold mLock
 MediaAnalyticsItem *MediaAnalyticsService::findItem(List<MediaAnalyticsItem*> *theList, MediaAnalyticsItem *nitem, bool removeit) {
     if (nitem == NULL) {
         return NULL;
@@ -689,8 +691,6 @@
 
     MediaAnalyticsItem *item = NULL;
 
-    Mutex::Autolock _l(mLock);
-
     for (List<MediaAnalyticsItem *>::iterator it = theList->begin();
         it != theList->end(); it++) {
         MediaAnalyticsItem *tmp = (*it);
@@ -711,10 +711,9 @@
 
 
 // delete the indicated record
+// caller should hold mLock
 void MediaAnalyticsService::deleteItem(List<MediaAnalyticsItem *> *l, MediaAnalyticsItem *item) {
 
-    Mutex::Autolock _l(mLock);
-
     for (List<MediaAnalyticsItem *>::iterator it = l->begin();
         it != l->end(); it++) {
         if ((*it)->getSessionID() != item->getSessionID())
diff --git a/services/mediacodec/Android.mk b/services/mediacodec/Android.mk
index faeb0a7..9348ecd 100644
--- a/services/mediacodec/Android.mk
+++ b/services/mediacodec/Android.mk
@@ -1,28 +1,11 @@
 LOCAL_PATH := $(call my-dir)
 
-# service library
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := MediaCodecService.cpp
-LOCAL_SHARED_LIBRARIES := \
-    libmedia_omx \
-    libbinder \
-    libgui \
-    libutils \
-    liblog \
-    libstagefright_omx \
-    libstagefright_xmlparser
-LOCAL_MODULE:= libmediacodecservice
-LOCAL_VENDOR_MODULE := true
-LOCAL_32_BIT_ONLY := true
-include $(BUILD_SHARED_LIBRARY)
-
 # service executable
 include $(CLEAR_VARS)
 LOCAL_REQUIRED_MODULES_arm := mediacodec.policy
 LOCAL_SRC_FILES := main_codecservice.cpp
 LOCAL_SHARED_LIBRARIES := \
     libmedia_omx \
-    libmediacodecservice \
     libbinder \
     libutils \
     libgui \
@@ -42,6 +25,11 @@
 LOCAL_VENDOR_MODULE := true
 LOCAL_32_BIT_ONLY := true
 LOCAL_INIT_RC := android.hardware.media.omx@1.0-service.rc
+
+ifeq ($(PRODUCT_FULL_TREBLE),true)
+LOCAL_CFLAGS += -DUSE_VNDBINDER
+endif
+
 include $(BUILD_EXECUTABLE)
 
 # service seccomp policy
diff --git a/services/mediacodec/MediaCodecService.cpp b/services/mediacodec/MediaCodecService.cpp
deleted file mode 100644
index 6b510c6..0000000
--- a/services/mediacodec/MediaCodecService.cpp
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (C) 2015 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 "MediaCodecService"
-//#define LOG_NDEBUG 0
-#include <utils/Log.h>
-
-#include "MediaCodecService.h"
-
-namespace android {
-
-sp<IOMX> MediaCodecService::getOMX() {
-
-    Mutex::Autolock autoLock(mOMXLock);
-
-    if (mOMX.get() == NULL) {
-        mOMX = new OMX();
-    }
-
-    return mOMX;
-}
-
-sp<IOMXStore> MediaCodecService::getOMXStore() {
-
-    Mutex::Autolock autoLock(mOMXStoreLock);
-
-    if (mOMXStore.get() == NULL) {
-        mOMXStore = new OMXStore();
-    }
-
-    return mOMXStore;
-}
-
-status_t MediaCodecService::onTransact(uint32_t code, const Parcel& data, Parcel* reply,
-        uint32_t flags)
-{
-    return BnMediaCodecService::onTransact(code, data, reply, flags);
-}
-
-}   // namespace android
diff --git a/services/mediacodec/MediaCodecService.h b/services/mediacodec/MediaCodecService.h
deleted file mode 100644
index 9301135..0000000
--- a/services/mediacodec/MediaCodecService.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (C) 2015 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_CODEC_SERVICE_H
-#define ANDROID_MEDIA_CODEC_SERVICE_H
-
-#include <binder/BinderService.h>
-#include <media/IMediaCodecService.h>
-#include <media/stagefright/omx/OMX.h>
-#include <media/stagefright/omx/OMXStore.h>
-
-namespace android {
-
-class MediaCodecService : public BinderService<MediaCodecService>,
-        public BnMediaCodecService
-{
-    friend class BinderService<MediaCodecService>;    // for MediaCodecService()
-public:
-    MediaCodecService() : BnMediaCodecService() { }
-    virtual ~MediaCodecService() { }
-    virtual void onFirstRef() { }
-
-    static const char*    getServiceName() { return "media.codec"; }
-
-    virtual sp<IOMX>      getOMX();
-
-    virtual sp<IOMXStore> getOMXStore();
-
-    virtual status_t      onTransact(uint32_t code, const Parcel& data,
-                                     Parcel* reply, uint32_t flags);
-
-private:
-    Mutex                 mOMXLock;
-    sp<IOMX>              mOMX;
-    Mutex                 mOMXStoreLock;
-    sp<IOMXStore>         mOMXStore;
-};
-
-}   // namespace android
-
-#endif  // ANDROID_MEDIA_CODEC_SERVICE_H
diff --git a/services/mediacodec/main_codecservice.cpp b/services/mediacodec/main_codecservice.cpp
index 79d6da5..6bb3fa2 100644
--- a/services/mediacodec/main_codecservice.cpp
+++ b/services/mediacodec/main_codecservice.cpp
@@ -15,22 +15,12 @@
 ** limitations under the License.
 */
 
-#include <fcntl.h>
-#include <sys/prctl.h>
-#include <sys/wait.h>
-#include <binder/IPCThreadState.h>
-#include <binder/ProcessState.h>
-#include <binder/IServiceManager.h>
-#include <cutils/properties.h>
-
-#include <string>
-
 #include <android-base/logging.h>
 
 // from LOCAL_C_INCLUDES
-#include "MediaCodecService.h"
 #include "minijail.h"
 
+#include <binder/ProcessState.h>
 #include <hidl/HidlTransportSupport.h>
 #include <media/stagefright/omx/1.0/Omx.h>
 #include <media/stagefright/omx/1.0/OmxStore.h>
@@ -46,10 +36,11 @@
 int main(int argc __unused, char** argv)
 {
     LOG(INFO) << "mediacodecservice starting";
-    bool treble = property_get_bool("persist.media.treble_omx", true);
-    if (treble) {
-      android::ProcessState::initWithDriver("/dev/vndbinder");
-    }
+
+#ifdef USE_VNDBINDER
+    android::ProcessState::initWithDriver("/dev/vndbinder");
+    android::ProcessState::self()->startThreadPool();
+#endif // USE_VNDBINDER
 
     signal(SIGPIPE, SIG_IGN);
     SetUpMinijail(kSystemSeccompPolicyPath, kVendorSeccompPolicyPath);
@@ -57,29 +48,22 @@
     strcpy(argv[0], "media.codec");
 
     ::android::hardware::configureRpcThreadpool(64, false);
-    sp<ProcessState> proc(ProcessState::self());
 
-    if (treble) {
-        using namespace ::android::hardware::media::omx::V1_0;
-        sp<IOmxStore> omxStore = new implementation::OmxStore();
-        if (omxStore == nullptr) {
-            LOG(ERROR) << "Cannot create IOmxStore HAL service.";
-        } else if (omxStore->registerAsService() != OK) {
-            LOG(ERROR) << "Cannot register IOmxStore HAL service.";
-        }
-        sp<IOmx> omx = new implementation::Omx();
-        if (omx == nullptr) {
-            LOG(ERROR) << "Cannot create IOmx HAL service.";
-        } else if (omx->registerAsService() != OK) {
-            LOG(ERROR) << "Cannot register IOmx HAL service.";
-        } else {
-            LOG(INFO) << "Treble OMX service created.";
-        }
+    using namespace ::android::hardware::media::omx::V1_0;
+    sp<IOmxStore> omxStore = new implementation::OmxStore();
+    if (omxStore == nullptr) {
+        LOG(ERROR) << "Cannot create IOmxStore HAL service.";
+    } else if (omxStore->registerAsService() != OK) {
+        LOG(ERROR) << "Cannot register IOmxStore HAL service.";
+    }
+    sp<IOmx> omx = new implementation::Omx();
+    if (omx == nullptr) {
+        LOG(ERROR) << "Cannot create IOmx HAL service.";
+    } else if (omx->registerAsService() != OK) {
+        LOG(ERROR) << "Cannot register IOmx HAL service.";
     } else {
-        MediaCodecService::instantiate();
-        LOG(INFO) << "Non-Treble OMX service created.";
+        LOG(INFO) << "IOmx HAL service created.";
     }
 
-    ProcessState::self()->startThreadPool();
-    IPCThreadState::self()->joinThreadPool();
+    ::android::hardware::joinRpcThreadpool();
 }
diff --git a/services/mediaextractor/MediaExtractorService.cpp b/services/mediaextractor/MediaExtractorService.cpp
index 50a4191..f09d7cf 100644
--- a/services/mediaextractor/MediaExtractorService.cpp
+++ b/services/mediaextractor/MediaExtractorService.cpp
@@ -20,8 +20,11 @@
 
 #include <utils/Vector.h>
 
-#include <media/stagefright/DataSource.h>
-#include <media/stagefright/MediaExtractor.h>
+#include <media/DataSource.h>
+#include <media/MediaExtractor.h>
+#include <media/stagefright/DataSourceFactory.h>
+#include <media/stagefright/InterfaceUtils.h>
+#include <media/stagefright/MediaExtractorFactory.h>
 #include <media/stagefright/RemoteDataSource.h>
 #include "MediaExtractorService.h"
 
@@ -31,16 +34,16 @@
         const sp<IDataSource> &remoteSource, const char *mime) {
     ALOGV("@@@ MediaExtractorService::makeExtractor for %s", mime);
 
-    sp<DataSource> localSource = DataSource::CreateFromIDataSource(remoteSource);
+    sp<DataSource> localSource = CreateDataSourceFromIDataSource(remoteSource);
 
-    sp<MediaExtractor> extractor = MediaExtractor::CreateFromService(localSource, mime);
+    sp<MediaExtractor> extractor = MediaExtractorFactory::CreateFromService(localSource, mime);
 
     ALOGV("extractor service created %p (%s)",
             extractor.get(),
             extractor == nullptr ? "" : extractor->name());
 
     if (extractor != nullptr) {
-        sp<IMediaExtractor> ret = extractor->asIMediaExtractor();
+        sp<IMediaExtractor> ret = CreateIMediaExtractorFromMediaExtractor(extractor);
         registerMediaExtractor(ret, localSource, mime);
         return ret;
     }
@@ -49,8 +52,8 @@
 
 sp<IDataSource> MediaExtractorService::makeIDataSource(int fd, int64_t offset, int64_t length)
 {
-    sp<DataSource> source = DataSource::CreateFromFd(fd, offset, length);
-    return source.get() != nullptr ? source->asIDataSource() : nullptr;
+    sp<DataSource> source = DataSourceFactory::CreateFromFd(fd, offset, length);
+    return CreateIDataSourceFromDataSource(source);
 }
 
 status_t MediaExtractorService::dump(int fd, const Vector<String16>& args) {
diff --git a/services/mediaextractor/seccomp_policy/mediaextractor-arm.policy b/services/mediaextractor/seccomp_policy/mediaextractor-arm.policy
index 4fa69d7..a9ee98d 100644
--- a/services/mediaextractor/seccomp_policy/mediaextractor-arm.policy
+++ b/services/mediaextractor/seccomp_policy/mediaextractor-arm.policy
@@ -41,6 +41,9 @@
 nanosleep: 1
 getrandom: 1
 
+# for dynamically loading extractors
+pread64: 1
+
 # for FileSource
 readlinkat: 1
 _llseek: 1
diff --git a/services/mediaextractor/seccomp_policy/mediaextractor-arm64.policy b/services/mediaextractor/seccomp_policy/mediaextractor-arm64.policy
index 438a332..dd71ed7 100644
--- a/services/mediaextractor/seccomp_policy/mediaextractor-arm64.policy
+++ b/services/mediaextractor/seccomp_policy/mediaextractor-arm64.policy
@@ -19,6 +19,7 @@
 setpriority: 1
 sigaltstack: 1
 clone: 1
+sched_setscheduler: 1
 lseek: 1
 newfstatat: 1
 faccessat: 1
diff --git a/services/medialog/Android.bp b/services/medialog/Android.bp
new file mode 100644
index 0000000..29e6dfc
--- /dev/null
+++ b/services/medialog/Android.bp
@@ -0,0 +1,22 @@
+cc_library_shared {
+    name: "libmedialogservice",
+
+    srcs: [
+        "IMediaLogService.cpp",
+        "MediaLogService.cpp",
+    ],
+
+    shared_libs: [
+        "libaudioutils",
+        "libbinder",
+        "liblog",
+        "libnbaio",
+        "libnblog",
+        "libutils",
+    ],
+
+    cflags: [
+        "-Werror",
+        "-Wall",
+    ],
+}
diff --git a/services/medialog/Android.mk b/services/medialog/Android.mk
deleted file mode 100644
index 4f2630e..0000000
--- a/services/medialog/Android.mk
+++ /dev/null
@@ -1,17 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := MediaLogService.cpp IMediaLogService.cpp
-
-LOCAL_SHARED_LIBRARIES := libbinder libutils liblog libnbaio libnblog libaudioutils
-
-LOCAL_MULTILIB := $(AUDIOSERVER_MULTILIB)
-
-LOCAL_MODULE:= libmedialogservice
-
-LOCAL_C_INCLUDES := $(call include-path-for, audio-utils)
-
-LOCAL_CFLAGS := -Werror -Wall
-
-include $(BUILD_SHARED_LIBRARY)
diff --git a/services/minijail/Android.mk b/services/minijail/Android.mk
index 6b35d91..67055a8 100644
--- a/services/minijail/Android.mk
+++ b/services/minijail/Android.mk
@@ -1,9 +1,12 @@
 LOCAL_PATH := $(call my-dir)
 
+minijail_common_cflags := -Wall -Werror
+
 # Small library for media.extractor and media.codec sandboxing.
 include $(CLEAR_VARS)
 LOCAL_MODULE := libavservices_minijail
 LOCAL_SRC_FILES := minijail.cpp
+LOCAL_CFLAGS := $(minijail_common_cflags)
 LOCAL_SHARED_LIBRARIES := libbase libminijail
 LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)
 include $(BUILD_SHARED_LIBRARY)
@@ -13,6 +16,7 @@
 LOCAL_MODULE := libavservices_minijail_vendor
 LOCAL_VENDOR_MODULE := true
 LOCAL_SRC_FILES := minijail.cpp
+LOCAL_CFLAGS := $(minijail_common_cflags)
 LOCAL_SHARED_LIBRARIES := libbase libminijail
 LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)
 include $(BUILD_SHARED_LIBRARY)
@@ -21,5 +25,6 @@
 include $(CLEAR_VARS)
 LOCAL_MODULE := libavservices_minijail_unittest
 LOCAL_SRC_FILES := minijail.cpp av_services_minijail_unittest.cpp
+LOCAL_CFLAGS := $(minijail_common_cflags)
 LOCAL_SHARED_LIBRARIES := libbase libminijail
 include $(BUILD_NATIVE_TEST)
diff --git a/services/oboeservice/AAudioClientTracker.cpp b/services/oboeservice/AAudioClientTracker.cpp
index a3d5ea1..549a4e9 100644
--- a/services/oboeservice/AAudioClientTracker.cpp
+++ b/services/oboeservice/AAudioClientTracker.cpp
@@ -15,7 +15,7 @@
  */
 
 
-#define LOG_TAG "AAudioService"
+#define LOG_TAG "AAudioClientTracker"
 //#define LOG_NDEBUG 0
 #include <utils/Log.h>
 
@@ -64,8 +64,7 @@
 // Create a tracker for the client.
 aaudio_result_t AAudioClientTracker::registerClient(pid_t pid,
                                          const sp<IAAudioClient>& client) {
-    ALOGV("AAudioClientTracker::registerClient(), calling pid = %d, getpid() = %d\n",
-          pid, getpid());
+    ALOGV("registerClient(), calling pid = %d, getpid() = %d\n", pid, getpid());
 
     std::lock_guard<std::mutex> lock(mLock);
     if (mNotificationClients.count(pid) == 0) {
@@ -74,18 +73,16 @@
 
         sp<IBinder> binder = IInterface::asBinder(client);
         status_t status = binder->linkToDeath(notificationClient);
-        ALOGW_IF(status != NO_ERROR,
-                 "AAudioClientTracker::registerClient() linkToDeath = %d\n", status);
+        ALOGW_IF(status != NO_ERROR, "registerClient() linkToDeath = %d\n", status);
         return AAudioConvert_androidToAAudioResult(status);
     } else {
-        ALOGW("AAudioClientTracker::registerClient(%d) already registered!", pid);
+        ALOGW("registerClient(%d) already registered!", pid);
         return AAUDIO_OK; // TODO should this be considered an error
     }
 }
 
 void AAudioClientTracker::unregisterClient(pid_t pid) {
-    ALOGV("AAudioClientTracker::unregisterClient(), calling pid = %d, getpid() = %d\n",
-          pid, getpid());
+    ALOGV("unregisterClient(), calling pid = %d, getpid() = %d\n", pid, getpid());
     std::lock_guard<std::mutex> lock(mLock);
     mNotificationClients.erase(pid);
 }
@@ -103,12 +100,12 @@
 aaudio_result_t
 AAudioClientTracker::registerClientStream(pid_t pid, sp<AAudioServiceStreamBase> serviceStream) {
     aaudio_result_t result = AAUDIO_OK;
-    ALOGV("AAudioClientTracker::registerClientStream(%d, %p)\n", pid, serviceStream.get());
+    ALOGV("registerClientStream(%d, %p)\n", pid, serviceStream.get());
     std::lock_guard<std::mutex> lock(mLock);
     sp<NotificationClient> notificationClient = mNotificationClients[pid];
     if (notificationClient == 0) {
         // This will get called the first time the audio server registers an internal stream.
-        ALOGV("AAudioClientTracker::registerClientStream(%d,) unrecognized pid\n", pid);
+        ALOGV("registerClientStream(%d,) unrecognized pid\n", pid);
         notificationClient = new NotificationClient(pid);
         mNotificationClients[pid] = notificationClient;
     }
@@ -120,15 +117,15 @@
 aaudio_result_t
 AAudioClientTracker::unregisterClientStream(pid_t pid,
                                             sp<AAudioServiceStreamBase> serviceStream) {
-    ALOGV("AAudioClientTracker::unregisterClientStream(%d, %p)\n", pid, serviceStream.get());
+    ALOGV("unregisterClientStream(%d, %p)\n", pid, serviceStream.get());
     std::lock_guard<std::mutex> lock(mLock);
     auto it = mNotificationClients.find(pid);
     if (it != mNotificationClients.end()) {
-        ALOGV("AAudioClientTracker::unregisterClientStream(%d, %p) found NotificationClient\n",
+        ALOGV("unregisterClientStream(%d, %p) found NotificationClient\n",
               pid, serviceStream.get());
         it->second->unregisterClientStream(serviceStream);
     } else {
-        ALOGE("AAudioClientTracker::unregisterClientStream(%d, %p) missing NotificationClient\n",
+        ALOGE("unregisterClientStream(%d, %p) missing NotificationClient\n",
               pid, serviceStream.get());
     }
     return AAUDIO_OK;
@@ -136,11 +133,11 @@
 
 AAudioClientTracker::NotificationClient::NotificationClient(pid_t pid)
         : mProcessId(pid) {
-    //ALOGD("AAudioClientTracker::NotificationClient(%d) created %p\n", pid, this);
+    //ALOGD("NotificationClient(%d) created %p\n", pid, this);
 }
 
 AAudioClientTracker::NotificationClient::~NotificationClient() {
-    //ALOGD("AAudioClientTracker::~NotificationClient() destroyed %p\n", this);
+    //ALOGD("~NotificationClient() destroyed %p\n", this);
 }
 
 int32_t AAudioClientTracker::NotificationClient::getStreamCount() {
@@ -179,7 +176,7 @@
 
         for (const auto& serviceStream : streamsToClose) {
             aaudio_handle_t handle = serviceStream->getHandle();
-            ALOGW("AAudioClientTracker::binderDied() close abandoned stream 0x%08X\n", handle);
+            ALOGW("binderDied() close abandoned stream 0x%08X\n", handle);
             aaudioService->closeStream(handle);
         }
         // mStreams should be empty now
diff --git a/services/oboeservice/AAudioEndpointManager.cpp b/services/oboeservice/AAudioEndpointManager.cpp
index f996f74..b0c3771 100644
--- a/services/oboeservice/AAudioEndpointManager.cpp
+++ b/services/oboeservice/AAudioEndpointManager.cpp
@@ -102,7 +102,7 @@
         }
     }
 
-    ALOGV("AAudioEndpointManager.findExclusiveEndpoint_l(), found %p for device = %d",
+    ALOGV("findExclusiveEndpoint_l(), found %p for device = %d",
           endpoint.get(), configuration.getDeviceId());
     return endpoint;
 }
@@ -118,7 +118,7 @@
         }
     }
 
-    ALOGV("AAudioEndpointManager.findSharedEndpoint_l(), found %p for device = %d",
+    ALOGV("findSharedEndpoint_l(), found %p for device = %d",
           endpoint.get(), configuration.getDeviceId());
     return endpoint;
 }
@@ -146,23 +146,23 @@
 
     // If we find an existing one then this one cannot be exclusive.
     if (endpoint.get() != nullptr) {
-        ALOGE("AAudioEndpointManager.openExclusiveEndpoint() already in use");
+        ALOGE("openExclusiveEndpoint() already in use");
         // Already open so do not allow a second stream.
         return nullptr;
     } else {
         sp<AAudioServiceEndpointMMAP> endpointMMap = new AAudioServiceEndpointMMAP();
-        ALOGE("AAudioEndpointManager.openEndpoint(),created MMAP %p", endpointMMap.get());
+        ALOGD("openEndpoint(),created MMAP %p", endpointMMap.get());
         endpoint = endpointMMap;
 
         aaudio_result_t result = endpoint->open(request);
         if (result != AAUDIO_OK) {
-            ALOGE("AAudioEndpointManager.openEndpoint(), open failed");
+            ALOGE("openEndpoint(), open failed");
             endpoint.clear();
         } else {
             mExclusiveStreams.push_back(endpointMMap);
         }
 
-        ALOGD("AAudioEndpointManager.openEndpoint(), created %p for device = %d",
+        ALOGD("openEndpoint(), created %p for device = %d",
               endpoint.get(), configuration.getDeviceId());
     }
 
@@ -203,13 +203,13 @@
         if (endpoint.get() != nullptr) {
             aaudio_result_t result = endpoint->open(request);
             if (result != AAUDIO_OK) {
-                ALOGE("AAudioEndpointManager.openEndpoint(), open failed");
+                ALOGE("openSharedEndpoint(), open failed");
                 endpoint.clear();
             } else {
                 mSharedStreams.push_back(endpoint);
             }
         }
-        ALOGD("AAudioEndpointManager.openSharedEndpoint(), created %p for device = %d, dir = %d",
+        ALOGD("openSharedEndpoint(), created %p for device = %d, dir = %d",
               endpoint.get(), configuration.getDeviceId(), (int)direction);
         IPCThreadState::self()->restoreCallingIdentity(token);
     }
@@ -239,14 +239,14 @@
     int32_t newRefCount = serviceEndpoint->getOpenCount() - 1;
     serviceEndpoint->setOpenCount(newRefCount);
 
-    // If no longer in use then close and delete it.
+    // If no longer in use then actually close it.
     if (newRefCount <= 0) {
         mExclusiveStreams.erase(
                 std::remove(mExclusiveStreams.begin(), mExclusiveStreams.end(), serviceEndpoint),
                 mExclusiveStreams.end());
 
         serviceEndpoint->close();
-        ALOGD("AAudioEndpointManager::closeExclusiveEndpoint() %p for device %d",
+        ALOGD("closeExclusiveEndpoint() %p for device %d",
               serviceEndpoint.get(), serviceEndpoint->getDeviceId());
     }
 }
@@ -261,14 +261,14 @@
     int32_t newRefCount = serviceEndpoint->getOpenCount() - 1;
     serviceEndpoint->setOpenCount(newRefCount);
 
-    // If no longer in use then close and delete it.
+    // If no longer in use then actually close it.
     if (newRefCount <= 0) {
         mSharedStreams.erase(
                 std::remove(mSharedStreams.begin(), mSharedStreams.end(), serviceEndpoint),
                 mSharedStreams.end());
 
         serviceEndpoint->close();
-        ALOGD("AAudioEndpointManager::closeSharedEndpoint() %p for device %d",
+        ALOGD("closeSharedEndpoint() %p for device %d",
               serviceEndpoint.get(), serviceEndpoint->getDeviceId());
     }
 }
diff --git a/services/oboeservice/AAudioMixer.cpp b/services/oboeservice/AAudioMixer.cpp
index 952aa82..57241a1 100644
--- a/services/oboeservice/AAudioMixer.cpp
+++ b/services/oboeservice/AAudioMixer.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "AAudioService"
+#define LOG_TAG "AAudioMixer"
 //#define LOG_NDEBUG 0
 #include <utils/Log.h>
 
@@ -49,10 +49,9 @@
     memset(mOutputBuffer, 0, mBufferSizeInBytes);
 }
 
-bool AAudioMixer::mix(int trackIndex, FifoBuffer *fifo, float volume) {
+bool AAudioMixer::mix(int streamIndex, FifoBuffer *fifo, bool allowUnderflow) {
     WrappingBuffer wrappingBuffer;
     float *destination = mOutputBuffer;
-    fifo_frames_t framesLeft = mFramesPerBurst;
 
 #if AAUDIO_MIXER_ATRACE_ENABLED
     ATRACE_BEGIN("aaMix");
@@ -63,35 +62,44 @@
 #if AAUDIO_MIXER_ATRACE_ENABLED
     if (ATRACE_ENABLED()) {
         char rdyText[] = "aaMixRdy#";
-        char letter = 'A' + (trackIndex % 26);
+        char letter = 'A' + (streamIndex % 26);
         rdyText[sizeof(rdyText) - 2] = letter;
         ATRACE_INT(rdyText, fullFrames);
     }
 #else /* MIXER_ATRACE_ENABLED */
     (void) trackIndex;
-    (void) fullFrames;
 #endif /* AAUDIO_MIXER_ATRACE_ENABLED */
 
+    // If allowUnderflow then always advance by one burst even if we do not have the data.
+    // Otherwise the stream timing will drift whenever there is an underflow.
+    // This actual underflow can then be detected by the client for XRun counting.
+    //
+    // Generally, allowUnderflow will be false when stopping a stream and we want to
+    // use up whatever data is in the queue.
+    fifo_frames_t framesDesired = mFramesPerBurst;
+    if (!allowUnderflow && fullFrames < framesDesired) {
+        framesDesired = fullFrames; // just use what is available then stop
+    }
+
     // Mix data in one or two parts.
     int partIndex = 0;
+    int32_t framesLeft = framesDesired;
     while (framesLeft > 0 && partIndex < WrappingBuffer::SIZE) {
-        fifo_frames_t framesToMix = framesLeft;
-        fifo_frames_t framesAvailable = wrappingBuffer.numFrames[partIndex];
-        if (framesAvailable > 0) {
-            if (framesToMix > framesAvailable) {
-                framesToMix = framesAvailable;
+        fifo_frames_t framesToMixFromPart = framesLeft;
+        fifo_frames_t framesAvailableFromPart = wrappingBuffer.numFrames[partIndex];
+        if (framesAvailableFromPart > 0) {
+            if (framesToMixFromPart > framesAvailableFromPart) {
+                framesToMixFromPart = framesAvailableFromPart;
             }
-            mixPart(destination, (float *)wrappingBuffer.data[partIndex], framesToMix, volume);
+            mixPart(destination, (float *)wrappingBuffer.data[partIndex],
+                    framesToMixFromPart);
 
-            destination += framesToMix * mSamplesPerFrame;
-            framesLeft -= framesToMix;
+            destination += framesToMixFromPart * mSamplesPerFrame;
+            framesLeft -= framesToMixFromPart;
         }
         partIndex++;
     }
-    // Always advance by one burst even if we do not have the data.
-    // Otherwise the stream timing will drift whenever there is an underflow.
-    // This actual underflow can then be detected by the client for XRun counting.
-    fifo->getFifoControllerBase()->advanceReadIndex(mFramesPerBurst);
+    fifo->getFifoControllerBase()->advanceReadIndex(framesDesired);
 
 #if AAUDIO_MIXER_ATRACE_ENABLED
     ATRACE_END();
@@ -100,11 +108,11 @@
     return (framesLeft > 0); // did not get all the frames we needed, ie. "underflow"
 }
 
-void AAudioMixer::mixPart(float *destination, float *source, int32_t numFrames, float volume) {
+void AAudioMixer::mixPart(float *destination, float *source, int32_t numFrames) {
     int32_t numSamples = numFrames * mSamplesPerFrame;
     // TODO maybe optimize using SIMD
     for (int sampleIndex = 0; sampleIndex < numSamples; sampleIndex++) {
-        *destination++ += *source++ * volume;
+        *destination++ += *source++;
     }
 }
 
diff --git a/services/oboeservice/AAudioMixer.h b/services/oboeservice/AAudioMixer.h
index a8090bc..5625d4d 100644
--- a/services/oboeservice/AAudioMixer.h
+++ b/services/oboeservice/AAudioMixer.h
@@ -33,13 +33,14 @@
 
     /**
      * Mix from this FIFO
-     * @param fifo
-     * @param volume
-     * @return true if underflowed
+     * @param streamIndex for marking stream variables in systrace
+     * @param fifo to read from
+     * @param allowUnderflow if true then allow mixer to advance read index past the write index
+     * @return true if actually underflowed
      */
-    bool mix(int trackIndex, android::FifoBuffer *fifo, float volume);
+    bool mix(int streamIndex, android::FifoBuffer *fifo, bool allowUnderflow);
 
-    void mixPart(float *destination, float *source, int32_t numFrames, float volume);
+    void mixPart(float *destination, float *source, int32_t numFrames);
 
     float *getOutputBuffer();
 
@@ -50,5 +51,4 @@
     int32_t  mBufferSizeInBytes = 0;
 };
 
-
 #endif //AAUDIO_AAUDIO_MIXER_H
diff --git a/services/oboeservice/AAudioService.cpp b/services/oboeservice/AAudioService.cpp
index 5a3488d..51ae665 100644
--- a/services/oboeservice/AAudioService.cpp
+++ b/services/oboeservice/AAudioService.cpp
@@ -92,14 +92,14 @@
     if (pid != mAudioClient.clientPid) {
         int32_t count = AAudioClientTracker::getInstance().getStreamCount(pid);
         if (count >= MAX_STREAMS_PER_PROCESS) {
-            ALOGE("AAudioService::openStream(): exceeded max streams per process %d >= %d",
+            ALOGE("openStream(): exceeded max streams per process %d >= %d",
                   count,  MAX_STREAMS_PER_PROCESS);
             return AAUDIO_ERROR_UNAVAILABLE;
         }
     }
 
     if (sharingMode != AAUDIO_SHARING_MODE_EXCLUSIVE && sharingMode != AAUDIO_SHARING_MODE_SHARED) {
-        ALOGE("AAudioService::openStream(): unrecognized sharing mode = %d", sharingMode);
+        ALOGE("openStream(): unrecognized sharing mode = %d", sharingMode);
         return AAUDIO_ERROR_ILLEGAL_ARGUMENT;
     }
 
@@ -114,7 +114,7 @@
         result = serviceStream->open(request);
         if (result != AAUDIO_OK) {
             // Clear it so we can possibly fall back to using a shared stream.
-            ALOGW("AAudioService::openStream(), could not open in EXCLUSIVE mode");
+            ALOGW("openStream(), could not open in EXCLUSIVE mode");
             serviceStream.clear();
         }
     }
@@ -128,12 +128,12 @@
 
     if (result != AAUDIO_OK) {
         serviceStream.clear();
-        ALOGE("AAudioService::openStream(): failed, return %d = %s",
+        ALOGE("openStream(): failed, return %d = %s",
               result, AAudio_convertResultToText(result));
         return result;
     } else {
         aaudio_handle_t handle = mStreamTracker.addStreamForHandle(serviceStream.get());
-        ALOGD("AAudioService::openStream(): handle = 0x%08X", handle);
+        ALOGD("openStream(): handle = 0x%08X", handle);
         serviceStream->setHandle(handle);
         pid_t pid = request.getProcessId();
         AAudioClientTracker::getInstance().registerClientStream(pid, serviceStream);
@@ -146,11 +146,11 @@
     // Check permission and ownership first.
     sp<AAudioServiceStreamBase> serviceStream = convertHandleToServiceStream(streamHandle);
     if (serviceStream.get() == nullptr) {
-        ALOGE("AAudioService::closeStream(0x%0x), illegal stream handle", streamHandle);
+        ALOGE("closeStream(0x%0x), illegal stream handle", streamHandle);
         return AAUDIO_ERROR_INVALID_HANDLE;
     }
 
-    ALOGD("AAudioService.closeStream(0x%08X)", streamHandle);
+    ALOGD("closeStream(0x%08X)", streamHandle);
     // Remove handle from tracker so that we cannot look up the raw address any more.
     // removeStreamByHandle() uses a lock so that if there are two simultaneous closes
     // then only one will get the pointer and do the close.
@@ -161,7 +161,7 @@
         AAudioClientTracker::getInstance().unregisterClientStream(pid, serviceStream);
         return AAUDIO_OK;
     } else {
-        ALOGW("AAudioService::closeStream(0x%0x) being handled by another thread", streamHandle);
+        ALOGW("closeStream(0x%0x) being handled by another thread", streamHandle);
         return AAUDIO_ERROR_INVALID_HANDLE;
     }
 }
@@ -192,7 +192,7 @@
                 aaudio::AudioEndpointParcelable &parcelable) {
     sp<AAudioServiceStreamBase> serviceStream = convertHandleToServiceStream(streamHandle);
     if (serviceStream.get() == nullptr) {
-        ALOGE("AAudioService::getStreamDescription(), illegal stream handle = 0x%0x", streamHandle);
+        ALOGE("getStreamDescription(), illegal stream handle = 0x%0x", streamHandle);
         return AAUDIO_ERROR_INVALID_HANDLE;
     }
 
@@ -204,7 +204,7 @@
 aaudio_result_t AAudioService::startStream(aaudio_handle_t streamHandle) {
     sp<AAudioServiceStreamBase> serviceStream = convertHandleToServiceStream(streamHandle);
     if (serviceStream.get() == nullptr) {
-        ALOGE("AAudioService::startStream(), illegal stream handle = 0x%0x", streamHandle);
+        ALOGE("startStream(), illegal stream handle = 0x%0x", streamHandle);
         return AAUDIO_ERROR_INVALID_HANDLE;
     }
 
@@ -214,7 +214,7 @@
 aaudio_result_t AAudioService::pauseStream(aaudio_handle_t streamHandle) {
     sp<AAudioServiceStreamBase> serviceStream = convertHandleToServiceStream(streamHandle);
     if (serviceStream.get() == nullptr) {
-        ALOGE("AAudioService::pauseStream(), illegal stream handle = 0x%0x", streamHandle);
+        ALOGE("pauseStream(), illegal stream handle = 0x%0x", streamHandle);
         return AAUDIO_ERROR_INVALID_HANDLE;
     }
     aaudio_result_t result = serviceStream->pause();
@@ -224,7 +224,7 @@
 aaudio_result_t AAudioService::stopStream(aaudio_handle_t streamHandle) {
     sp<AAudioServiceStreamBase> serviceStream = convertHandleToServiceStream(streamHandle);
     if (serviceStream.get() == nullptr) {
-        ALOGE("AAudioService::stopStream(), illegal stream handle = 0x%0x", streamHandle);
+        ALOGE("stopStream(), illegal stream handle = 0x%0x", streamHandle);
         return AAUDIO_ERROR_INVALID_HANDLE;
     }
     aaudio_result_t result = serviceStream->stop();
@@ -234,7 +234,7 @@
 aaudio_result_t AAudioService::flushStream(aaudio_handle_t streamHandle) {
     sp<AAudioServiceStreamBase> serviceStream = convertHandleToServiceStream(streamHandle);
     if (serviceStream.get() == nullptr) {
-        ALOGE("AAudioService::flushStream(), illegal stream handle = 0x%0x", streamHandle);
+        ALOGE("flushStream(), illegal stream handle = 0x%0x", streamHandle);
         return AAUDIO_ERROR_INVALID_HANDLE;
     }
     return serviceStream->flush();
@@ -245,11 +245,11 @@
                                                    int64_t periodNanoseconds) {
     sp<AAudioServiceStreamBase> serviceStream = convertHandleToServiceStream(streamHandle);
     if (serviceStream.get() == nullptr) {
-        ALOGE("AAudioService::registerAudioThread(), illegal stream handle = 0x%0x", streamHandle);
+        ALOGE("registerAudioThread(), illegal stream handle = 0x%0x", streamHandle);
         return AAUDIO_ERROR_INVALID_HANDLE;
     }
     if (serviceStream->getRegisteredThread() != AAudioServiceStreamBase::ILLEGAL_THREAD_ID) {
-        ALOGE("AAudioService::registerAudioThread(), thread already registered");
+        ALOGE("registerAudioThread(), thread already registered");
         return AAUDIO_ERROR_INVALID_STATE;
     }
 
@@ -258,7 +258,7 @@
     int err = android::requestPriority(ownerPid, clientThreadId,
                                        DEFAULT_AUDIO_PRIORITY, true /* isForApp */);
     if (err != 0){
-        ALOGE("AAudioService::registerAudioThread(%d) failed, errno = %d, priority = %d",
+        ALOGE("registerAudioThread(%d) failed, errno = %d, priority = %d",
               clientThreadId, errno, DEFAULT_AUDIO_PRIORITY);
         return AAUDIO_ERROR_INTERNAL;
     } else {
@@ -270,12 +270,11 @@
                                                      pid_t clientThreadId) {
     sp<AAudioServiceStreamBase> serviceStream = convertHandleToServiceStream(streamHandle);
     if (serviceStream.get() == nullptr) {
-        ALOGE("AAudioService::unregisterAudioThread(), illegal stream handle = 0x%0x",
-              streamHandle);
+        ALOGE("unregisterAudioThread(), illegal stream handle = 0x%0x", streamHandle);
         return AAUDIO_ERROR_INVALID_HANDLE;
     }
     if (serviceStream->getRegisteredThread() != clientThreadId) {
-        ALOGE("AAudioService::unregisterAudioThread(), wrong thread");
+        ALOGE("unregisterAudioThread(), wrong thread");
         return AAUDIO_ERROR_ILLEGAL_ARGUMENT;
     }
     serviceStream->setRegisteredThread(0);
@@ -287,8 +286,7 @@
                                   audio_port_handle_t *clientHandle) {
     sp<AAudioServiceStreamBase> serviceStream = convertHandleToServiceStream(streamHandle);
     if (serviceStream.get() == nullptr) {
-        ALOGE("AAudioService::startClient(), illegal stream handle = 0x%0x",
-              streamHandle);
+        ALOGE("startClient(), illegal stream handle = 0x%0x", streamHandle);
         return AAUDIO_ERROR_INVALID_HANDLE;
     }
     return serviceStream->startClient(client, clientHandle);
@@ -298,8 +296,7 @@
                                           audio_port_handle_t clientHandle) {
     sp<AAudioServiceStreamBase> serviceStream = convertHandleToServiceStream(streamHandle);
     if (serviceStream.get() == nullptr) {
-        ALOGE("AAudioService::stopClient(), illegal stream handle = 0x%0x",
-              streamHandle);
+        ALOGE("stopClient(), illegal stream handle = 0x%0x", streamHandle);
         return AAUDIO_ERROR_INVALID_HANDLE;
     }
     return serviceStream->stopClient(clientHandle);
diff --git a/services/oboeservice/AAudioServiceEndpoint.cpp b/services/oboeservice/AAudioServiceEndpoint.cpp
index 3095bc9..f917675 100644
--- a/services/oboeservice/AAudioServiceEndpoint.cpp
+++ b/services/oboeservice/AAudioServiceEndpoint.cpp
@@ -60,6 +60,7 @@
     result << "    Reference Count:      " << mOpenCount << "\n";
     result << "    Requested Device Id:  " << mRequestedDeviceId << "\n";
     result << "    Device Id:            " << getDeviceId() << "\n";
+    result << "    Connected:            " << mConnected.load() << "\n";
     result << "    Registered Streams:" << "\n";
     result << AAudioServiceStreamShared::dumpHeader() << "\n";
     for (const auto stream : mRegisteredStreams) {
@@ -74,7 +75,9 @@
 
 void AAudioServiceEndpoint::disconnectRegisteredStreams() {
     std::lock_guard<std::mutex> lock(mLockStreams);
+    mConnected.store(false);
     for (const auto stream : mRegisteredStreams) {
+        ALOGD("disconnectRegisteredStreams() stop and disconnect %p", stream.get());
         stream->stop();
         stream->disconnect();
     }
@@ -96,6 +99,9 @@
 }
 
 bool AAudioServiceEndpoint::matches(const AAudioStreamConfiguration& configuration) {
+    if (!mConnected.load()) {
+        return false; // Only use an endpoint if it is connected to a device.
+    }
     if (configuration.getDirection() != getDirection()) {
         return false;
     }
diff --git a/services/oboeservice/AAudioServiceEndpoint.h b/services/oboeservice/AAudioServiceEndpoint.h
index 2ef6234..6312c51 100644
--- a/services/oboeservice/AAudioServiceEndpoint.h
+++ b/services/oboeservice/AAudioServiceEndpoint.h
@@ -97,6 +97,10 @@
         mOpenCount = count;
     }
 
+    bool isConnected() const {
+        return mConnected;
+    }
+
 protected:
     void                     disconnectRegisteredStreams();
 
@@ -111,6 +115,8 @@
     int32_t                  mOpenCount = 0;
     int32_t                  mRequestedDeviceId = 0;
 
+    std::atomic<bool>        mConnected{true};
+
 };
 
 } /* namespace aaudio */
diff --git a/services/oboeservice/AAudioServiceEndpointCapture.cpp b/services/oboeservice/AAudioServiceEndpointCapture.cpp
index c7d9b8e..f902bef 100644
--- a/services/oboeservice/AAudioServiceEndpointCapture.cpp
+++ b/services/oboeservice/AAudioServiceEndpointCapture.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "AAudioService"
+#define LOG_TAG "AAudioServiceEndpointCapture"
 //#define LOG_NDEBUG 0
 #include <utils/Log.h>
 
@@ -57,7 +57,7 @@
 
 // Read data from the shared MMAP stream and then distribute it to the client streams.
 void *AAudioServiceEndpointCapture::callbackLoop() {
-    ALOGD("AAudioServiceEndpointCapture(): callbackLoop() entering");
+    ALOGD("callbackLoop() entering");
     int32_t underflowCount = 0;
     aaudio_result_t result = AAUDIO_OK;
     int64_t timeoutNanos = getStreamInternal()->calculateReasonableTimeout();
@@ -73,7 +73,7 @@
             disconnectRegisteredStreams();
             break;
         } else if (result != getFramesPerBurst()) {
-            ALOGW("AAudioServiceEndpointCapture(): callbackLoop() read %d / %d",
+            ALOGW("callbackLoop() read %d / %d",
                   result, getFramesPerBurst());
             break;
         }
@@ -125,6 +125,6 @@
         }
     }
 
-    ALOGD("AAudioServiceEndpointCapture(): callbackLoop() exiting, %d underflows", underflowCount);
+    ALOGD("callbackLoop() exiting, %d underflows", underflowCount);
     return NULL; // TODO review
 }
diff --git a/services/oboeservice/AAudioServiceEndpointMMAP.cpp b/services/oboeservice/AAudioServiceEndpointMMAP.cpp
index 4be25c8..a61994d 100644
--- a/services/oboeservice/AAudioServiceEndpointMMAP.cpp
+++ b/services/oboeservice/AAudioServiceEndpointMMAP.cpp
@@ -140,7 +140,7 @@
                                                           this, // callback
                                                           mMmapStream,
                                                           &mPortHandle);
-    ALOGD("AAudioServiceEndpointMMAP::open() mMapClient.uid = %d, pid = %d => portHandle = %d\n",
+    ALOGD("open() mMapClient.uid = %d, pid = %d => portHandle = %d\n",
           mMmapClient.clientUid,  mMmapClient.clientPid, mPortHandle);
     if (status != OK) {
         ALOGE("openMmapStream returned status %d", status);
@@ -148,7 +148,7 @@
     }
 
     if (deviceId == AAUDIO_UNSPECIFIED) {
-        ALOGW("AAudioServiceEndpointMMAP::open() - openMmapStream() failed to set deviceId");
+        ALOGW("open() - openMmapStream() failed to set deviceId");
     }
     setDeviceId(deviceId);
 
@@ -159,7 +159,7 @@
     }
     status = mMmapStream->createMmapBuffer(minSizeFrames, &mMmapBufferinfo);
     if (status != OK) {
-        ALOGE("AAudioServiceEndpointMMAP::open() - createMmapBuffer() failed with status %d %s",
+        ALOGE("open() - createMmapBuffer() failed with status %d %s",
               status, strerror(-status));
         result = AAUDIO_ERROR_UNAVAILABLE;
         goto error;
@@ -186,7 +186,7 @@
             // Fallback is handled by caller but indicate what is possible in case
             // this is used in the future
             setSharingMode(AAUDIO_SHARING_MODE_SHARED);
-            ALOGW("AAudioServiceEndpointMMAP::open() - exclusive FD cannot be used by client");
+            ALOGW("open() - exclusive FD cannot be used by client");
             result = AAUDIO_ERROR_UNAVAILABLE;
             goto error;
         }
@@ -201,7 +201,7 @@
     // Assume that AudioFlinger will close the original shared_memory_fd.
     mAudioDataFileDescriptor.reset(dup(mMmapBufferinfo.shared_memory_fd));
     if (mAudioDataFileDescriptor.get() == -1) {
-        ALOGE("AAudioServiceEndpointMMAP::open() - could not dup shared_memory_fd");
+        ALOGE("open() - could not dup shared_memory_fd");
         result = AAUDIO_ERROR_INTERNAL;
         goto error;
     }
@@ -219,10 +219,10 @@
         burstMicros = mFramesPerBurst * static_cast<int64_t>(1000000) / getSampleRate();
     } while (burstMicros < burstMinMicros);
 
-    ALOGD("AAudioServiceEndpointMMAP::open() original burst = %d, minMicros = %d, to burst = %d\n",
+    ALOGD("open() original burst = %d, minMicros = %d, to burst = %d\n",
           mMmapBufferinfo.burst_size_frames, burstMinMicros, mFramesPerBurst);
 
-    ALOGD("AAudioServiceEndpointMMAP::open() actual rate = %d, channels = %d"
+    ALOGD("open() actual rate = %d, channels = %d"
           ", deviceId = %d, capacity = %d\n",
           getSampleRate(), getSamplesPerFrame(), deviceId, getBufferCapacity());
 
@@ -236,7 +236,7 @@
 aaudio_result_t AAudioServiceEndpointMMAP::close() {
 
     if (mMmapStream != 0) {
-        ALOGD("AAudioServiceEndpointMMAP::close() clear() endpoint");
+        ALOGD("close() clear() endpoint");
         // Needs to be explicitly cleared or CTS will fail but it is not clear why.
         mMmapStream.clear();
         // Apparently the above close is asynchronous. An attempt to open a new device
@@ -258,18 +258,25 @@
 aaudio_result_t AAudioServiceEndpointMMAP::stopStream(sp<AAudioServiceStreamBase> stream,
                                                   audio_port_handle_t clientHandle) {
     mFramesTransferred.reset32();
+
+    // Round 64-bit counter up to a multiple of the buffer capacity.
+    // This is required because the 64-bit counter is used as an index
+    // into a circular buffer and the actual HW position is reset to zero
+    // when the stream is stopped.
+    mFramesTransferred.roundUp64(getBufferCapacity());
+
     return stopClient(mPortHandle);
 }
 
 aaudio_result_t AAudioServiceEndpointMMAP::startClient(const android::AudioClient& client,
                                                        audio_port_handle_t *clientHandle) {
     if (mMmapStream == nullptr) return AAUDIO_ERROR_NULL;
-    ALOGD("AAudioServiceEndpointMMAP::startClient(%p(uid=%d, pid=%d))",
+    ALOGD("startClient(%p(uid=%d, pid=%d))",
           &client, client.clientUid, client.clientPid);
     audio_port_handle_t originalHandle =  *clientHandle;
     status_t status = mMmapStream->start(client, clientHandle);
     aaudio_result_t result = AAudioConvert_androidToAAudioResult(status);
-    ALOGD("AAudioServiceEndpointMMAP::startClient() , %d => %d returns %d",
+    ALOGD("startClient() , %d => %d returns %d",
           originalHandle, *clientHandle, result);
     return result;
 }
@@ -277,7 +284,7 @@
 aaudio_result_t AAudioServiceEndpointMMAP::stopClient(audio_port_handle_t clientHandle) {
     if (mMmapStream == nullptr) return AAUDIO_ERROR_NULL;
     aaudio_result_t result = AAudioConvert_androidToAAudioResult(mMmapStream->stop(clientHandle));
-    ALOGD("AAudioServiceEndpointMMAP::stopClient(%d) returns %d", clientHandle, result);
+    ALOGD("stopClient(%d) returns %d", clientHandle, result);
     return result;
 }
 
@@ -289,7 +296,7 @@
         return AAUDIO_ERROR_NULL;
     }
     status_t status = mMmapStream->getMmapPosition(&position);
-    ALOGV("AAudioServiceEndpointMMAP::getFreeRunningPosition() status= %d, pos = %d, nanos = %lld\n",
+    ALOGV("getFreeRunningPosition() status= %d, pos = %d, nanos = %lld\n",
           status, position.position_frames, (long long) position.time_nanoseconds);
     aaudio_result_t result = AAudioConvert_androidToAAudioResult(status);
     if (result == AAUDIO_ERROR_UNAVAILABLE) {
@@ -312,7 +319,7 @@
 
 
 void AAudioServiceEndpointMMAP::onTearDown() {
-    ALOGD("AAudioServiceEndpointMMAP::onTearDown() called");
+    ALOGD("onTearDown() called");
     disconnectRegisteredStreams();
 };
 
@@ -320,7 +327,7 @@
                                               android::Vector<float> values) {
     // TODO do we really need a different volume for each channel?
     float volume = values[0];
-    ALOGD("AAudioServiceEndpointMMAP::onVolumeChanged() volume[0] = %f", volume);
+    ALOGD("onVolumeChanged() volume[0] = %f", volume);
     std::lock_guard<std::mutex> lock(mLockStreams);
     for(const auto stream : mRegisteredStreams) {
         stream->onVolumeChanged(volume);
@@ -328,7 +335,7 @@
 };
 
 void AAudioServiceEndpointMMAP::onRoutingChanged(audio_port_handle_t deviceId) {
-    ALOGD("AAudioServiceEndpointMMAP::onRoutingChanged() called with %d, old = %d",
+    ALOGD("onRoutingChanged() called with dev %d, old = %d",
           deviceId, getDeviceId());
     if (getDeviceId() != AUDIO_PORT_HANDLE_NONE  && getDeviceId() != deviceId) {
         disconnectRegisteredStreams();
diff --git a/services/oboeservice/AAudioServiceEndpointPlay.cpp b/services/oboeservice/AAudioServiceEndpointPlay.cpp
index 9b1833a..c2feb6b 100644
--- a/services/oboeservice/AAudioServiceEndpointPlay.cpp
+++ b/services/oboeservice/AAudioServiceEndpointPlay.cpp
@@ -82,9 +82,13 @@
             std::lock_guard <std::mutex> lock(mLockStreams);
             for (const auto clientStream : mRegisteredStreams) {
                 int64_t clientFramesRead = 0;
+                bool allowUnderflow = true;
 
-                if (!clientStream->isRunning()) {
-                    continue;
+                aaudio_stream_state_t state = clientStream->getState();
+                if (state == AAUDIO_STREAM_STATE_STOPPING) {
+                    allowUnderflow = false; // just read what is already in the FIFO
+                } else if (state != AAUDIO_STREAM_STATE_STARTED) {
+                    continue; // this stream is not running so skip it.
                 }
 
                 sp<AAudioServiceStreamShared> streamShared =
@@ -104,8 +108,7 @@
                         int64_t positionOffset = mmapFramesWritten - clientFramesRead;
                         streamShared->setTimestampPositionOffset(positionOffset);
 
-                        float volume = 1.0; // to match legacy volume
-                        bool underflowed = mMixer.mix(index, fifo, volume);
+                        bool underflowed = mMixer.mix(index, fifo, allowUnderflow);
                         if (underflowed) {
                             streamShared->incrementXRunCount();
                         }
@@ -132,7 +135,7 @@
             AAudioServiceEndpointShared::disconnectRegisteredStreams();
             break;
         } else if (result != getFramesPerBurst()) {
-            ALOGW("AAudioServiceEndpoint(): callbackLoop() wrote %d / %d",
+            ALOGW("callbackLoop() wrote %d / %d",
                   result, getFramesPerBurst());
             break;
         }
diff --git a/services/oboeservice/AAudioServiceEndpointShared.cpp b/services/oboeservice/AAudioServiceEndpointShared.cpp
index cd40066..820ed28 100644
--- a/services/oboeservice/AAudioServiceEndpointShared.cpp
+++ b/services/oboeservice/AAudioServiceEndpointShared.cpp
@@ -91,7 +91,12 @@
 static void *aaudio_endpoint_thread_proc(void *context) {
     AAudioServiceEndpointShared *endpoint = (AAudioServiceEndpointShared *) context;
     if (endpoint != NULL) {
-        return endpoint->callbackLoop();
+        void *result = endpoint->callbackLoop();
+        // Close now so that the HW resource is freed and we can open a new device.
+        if (!endpoint->isConnected()) {
+            endpoint->close();
+        }
+        return result;
     } else {
         return NULL;
     }
diff --git a/services/oboeservice/AAudioServiceEndpointShared.h b/services/oboeservice/AAudioServiceEndpointShared.h
index e3bd2c1..74cd817 100644
--- a/services/oboeservice/AAudioServiceEndpointShared.h
+++ b/services/oboeservice/AAudioServiceEndpointShared.h
@@ -30,8 +30,7 @@
 namespace aaudio {
 
 /**
- * This Service class corresponds to a Client stream that shares an MMAP device through a mixer
- * or an input distributor.
+ * This manages an internal stream that is shared by multiple Client streams.
  */
 class AAudioServiceEndpointShared : public AAudioServiceEndpoint {
 
diff --git a/services/oboeservice/AAudioServiceStreamBase.cpp b/services/oboeservice/AAudioServiceStreamBase.cpp
index e670129..6652cc9 100644
--- a/services/oboeservice/AAudioServiceStreamBase.cpp
+++ b/services/oboeservice/AAudioServiceStreamBase.cpp
@@ -51,7 +51,7 @@
 }
 
 AAudioServiceStreamBase::~AAudioServiceStreamBase() {
-    ALOGD("AAudioServiceStreamBase::~AAudioServiceStreamBase() destroying %p", this);
+    ALOGD("~AAudioServiceStreamBase() destroying %p", this);
     // If the stream is deleted when OPEN or in use then audio resources will leak.
     // This would indicate an internal error. So we want to find this ASAP.
     LOG_ALWAYS_FATAL_IF(!(getState() == AAUDIO_STREAM_STATE_CLOSED
@@ -93,7 +93,7 @@
     {
         std::lock_guard<std::mutex> lock(mUpMessageQueueLock);
         if (mUpMessageQueue != nullptr) {
-            ALOGE("AAudioServiceStreamBase::open() called twice");
+            ALOGE("open() called twice");
             return AAUDIO_ERROR_INVALID_STATE;
         }
 
@@ -108,7 +108,7 @@
                                                          request,
                                                          sharingMode);
         if (mServiceEndpoint == nullptr) {
-            ALOGE("AAudioServiceStreamBase::open() openEndpoint() failed");
+            ALOGE("open() openEndpoint() failed");
             result = AAUDIO_ERROR_UNAVAILABLE;
             goto error;
         }
@@ -167,7 +167,7 @@
     }
 
     if (mServiceEndpoint == nullptr) {
-        ALOGE("AAudioServiceStreamBase::start() missing endpoint");
+        ALOGE("start() missing endpoint");
         result = AAUDIO_ERROR_INVALID_STATE;
         goto error;
     }
@@ -199,22 +199,26 @@
         return result;
     }
     if (mServiceEndpoint == nullptr) {
-        ALOGE("AAudioServiceStreamShared::pause() missing endpoint");
+        ALOGE("pause() missing endpoint");
         return AAUDIO_ERROR_INVALID_STATE;
     }
-    result = mServiceEndpoint->stopStream(this, mClientHandle);
-    if (result != AAUDIO_OK) {
-        ALOGE("AAudioServiceStreamShared::pause() mServiceEndpoint returned %d", result);
-        disconnect(); // TODO should we return or pause Base first?
-    }
 
+    // Send it now because the timestamp gets rounded up when stopStream() is called below.
+    // Also we don't need the timestamps while we are shutting down.
     sendCurrentTimestamp();
-    mThreadEnabled.store(false);
-    result = mTimestampThread.stop();
+
+    result = stopTimestampThread();
     if (result != AAUDIO_OK) {
         disconnect();
         return result;
     }
+
+    result = mServiceEndpoint->stopStream(this, mClientHandle);
+    if (result != AAUDIO_OK) {
+        ALOGE("pause() mServiceEndpoint returned %d", result);
+        disconnect(); // TODO should we return or pause Base first?
+    }
+
     sendServiceEvent(AAUDIO_SERVICE_EVENT_PAUSED);
     setState(AAUDIO_STREAM_STATE_PAUSED);
     return result;
@@ -227,10 +231,14 @@
     }
 
     if (mServiceEndpoint == nullptr) {
-        ALOGE("AAudioServiceStreamShared::stop() missing endpoint");
+        ALOGE("stop() missing endpoint");
         return AAUDIO_ERROR_INVALID_STATE;
     }
 
+    setState(AAUDIO_STREAM_STATE_STOPPING);
+
+    // Send it now because the timestamp gets rounded up when stopStream() is called below.
+    // Also we don't need the timestamps while we are shutting down.
     sendCurrentTimestamp(); // warning - this calls a virtual function
     result = stopTimestampThread();
     if (result != AAUDIO_OK) {
@@ -241,7 +249,7 @@
     // TODO wait for data to be played out
     result = mServiceEndpoint->stopStream(this, mClientHandle);
     if (result != AAUDIO_OK) {
-        ALOGE("AAudioServiceStreamShared::stop() mServiceEndpoint returned %d", result);
+        ALOGE("stop() mServiceEndpoint returned %d", result);
         disconnect();
         // TODO what to do with result here?
     }
@@ -262,7 +270,7 @@
 
 aaudio_result_t AAudioServiceStreamBase::flush() {
     if (getState() != AAUDIO_STREAM_STATE_PAUSED) {
-        ALOGE("AAudioServiceStreamBase::flush() stream not paused, state = %s",
+        ALOGE("flush() stream not paused, state = %s",
               AAudio_convertStreamStateToText(mState));
         return AAUDIO_ERROR_INVALID_STATE;
     }
@@ -274,7 +282,7 @@
 
 // implement Runnable, periodically send timestamps to client
 void AAudioServiceStreamBase::run() {
-    ALOGD("AAudioServiceStreamBase::run() entering ----------------");
+    ALOGD("run() entering ----------------");
     TimestampScheduler timestampScheduler;
     timestampScheduler.setBurstPeriod(mFramesPerBurst, getSampleRate());
     timestampScheduler.start(AudioClock::getNanoseconds());
@@ -292,7 +300,7 @@
             AudioClock::sleepUntilNanoTime(nextTime);
         }
     }
-    ALOGD("AAudioServiceStreamBase::run() exiting ----------------");
+    ALOGD("run() exiting ----------------");
 }
 
 void AAudioServiceStreamBase::disconnect() {
diff --git a/services/oboeservice/AAudioServiceStreamMMAP.cpp b/services/oboeservice/AAudioServiceStreamMMAP.cpp
index 44ba1ca..34ddb4b 100644
--- a/services/oboeservice/AAudioServiceStreamMMAP.cpp
+++ b/services/oboeservice/AAudioServiceStreamMMAP.cpp
@@ -81,9 +81,7 @@
     return AAUDIO_OK;
 }
 
-/**
- * Start the flow of data.
- */
+// Start the flow of data.
 aaudio_result_t AAudioServiceStreamMMAP::startDevice() {
     aaudio_result_t result = AAudioServiceStreamBase::startDevice();
     if (!mInService && result == AAUDIO_OK) {
@@ -93,9 +91,7 @@
     return result;
 }
 
-/**
- * Stop the flow of data such that start() can resume with loss of data.
- */
+// Stop the flow of data such that start() can resume with loss of data.
 aaudio_result_t AAudioServiceStreamMMAP::pause() {
     if (!isRunning()) {
         return AAUDIO_OK;
@@ -165,9 +161,7 @@
     }
 }
 
-/**
- * Get an immutable description of the data queue from the HAL.
- */
+// Get an immutable description of the data queue from the HAL.
 aaudio_result_t AAudioServiceStreamMMAP::getAudioDataDescription(
         AudioEndpointParcelable &parcelable)
 {
diff --git a/services/oboeservice/AAudioServiceStreamShared.cpp b/services/oboeservice/AAudioServiceStreamShared.cpp
index 084f996..75d88cf 100644
--- a/services/oboeservice/AAudioServiceStreamShared.cpp
+++ b/services/oboeservice/AAudioServiceStreamShared.cpp
@@ -74,7 +74,7 @@
                                                            int32_t framesPerBurst) {
 
     if (requestedCapacityFrames > MAX_FRAMES_PER_BUFFER) {
-        ALOGE("AAudioServiceStreamShared::calculateBufferCapacity() requested capacity %d > max %d",
+        ALOGE("calculateBufferCapacity() requested capacity %d > max %d",
               requestedCapacityFrames, MAX_FRAMES_PER_BUFFER);
         return AAUDIO_ERROR_OUT_OF_RANGE;
     }
@@ -99,7 +99,7 @@
     }
     // Check for numeric overflow.
     if (numBursts > 0x8000 || framesPerBurst > 0x8000) {
-        ALOGE("AAudioServiceStreamShared::calculateBufferCapacity() overflow, capacity = %d * %d",
+        ALOGE("calculateBufferCapacity() overflow, capacity = %d * %d",
               numBursts, framesPerBurst);
         return AAUDIO_ERROR_OUT_OF_RANGE;
     }
@@ -107,11 +107,11 @@
 
     // Final sanity check.
     if (capacityInFrames > MAX_FRAMES_PER_BUFFER) {
-        ALOGE("AAudioServiceStreamShared::calculateBufferCapacity() calc capacity %d > max %d",
+        ALOGE("calculateBufferCapacity() calc capacity %d > max %d",
               capacityInFrames, MAX_FRAMES_PER_BUFFER);
         return AAUDIO_ERROR_OUT_OF_RANGE;
     }
-    ALOGD("AAudioServiceStreamShared::calculateBufferCapacity() requested %d frames, actual = %d",
+    ALOGD("calculateBufferCapacity() requested %d frames, actual = %d",
           requestedCapacityFrames, capacityInFrames);
     return capacityInFrames;
 }
@@ -122,7 +122,7 @@
 
     aaudio_result_t result = AAudioServiceStreamBase::open(request, AAUDIO_SHARING_MODE_SHARED);
     if (result != AAUDIO_OK) {
-        ALOGE("AAudioServiceStreamBase open() returned %d", result);
+        ALOGE("open() returned %d", result);
         return result;
     }
 
@@ -134,7 +134,7 @@
     if (getFormat() == AAUDIO_FORMAT_UNSPECIFIED) {
         setFormat(AAUDIO_FORMAT_PCM_FLOAT);
     } else if (getFormat() != AAUDIO_FORMAT_PCM_FLOAT) {
-        ALOGE("AAudioServiceStreamShared::open() mAudioFormat = %d, need FLOAT", getFormat());
+        ALOGE("open() mAudioFormat = %d, need FLOAT", getFormat());
         result = AAUDIO_ERROR_INVALID_FORMAT;
         goto error;
     }
@@ -143,7 +143,7 @@
     if (getSampleRate() == AAUDIO_UNSPECIFIED) {
         setSampleRate(mServiceEndpoint->getSampleRate());
     } else if (getSampleRate() != mServiceEndpoint->getSampleRate()) {
-        ALOGE("AAudioServiceStreamShared::open() mSampleRate = %d, need %d",
+        ALOGE("open() mSampleRate = %d, need %d",
               getSampleRate(), mServiceEndpoint->getSampleRate());
         result = AAUDIO_ERROR_INVALID_RATE;
         goto error;
@@ -153,7 +153,7 @@
     if (getSamplesPerFrame() == AAUDIO_UNSPECIFIED) {
         setSamplesPerFrame(mServiceEndpoint->getSamplesPerFrame());
     } else if (getSamplesPerFrame() != mServiceEndpoint->getSamplesPerFrame()) {
-        ALOGE("AAudioServiceStreamShared::open() mSamplesPerFrame = %d, need %d",
+        ALOGE("open() mSamplesPerFrame = %d, need %d",
               getSamplesPerFrame(), mServiceEndpoint->getSamplesPerFrame());
         result = AAUDIO_ERROR_OUT_OF_RANGE;
         goto error;
@@ -173,14 +173,14 @@
         mAudioDataQueue = new SharedRingBuffer();
         result = mAudioDataQueue->allocate(calculateBytesPerFrame(), getBufferCapacity());
         if (result != AAUDIO_OK) {
-            ALOGE("AAudioServiceStreamShared::open() could not allocate FIFO with %d frames",
+            ALOGE("open() could not allocate FIFO with %d frames",
                   getBufferCapacity());
             result = AAUDIO_ERROR_NO_MEMORY;
             goto error;
         }
     }
 
-    ALOGD("AAudioServiceStreamShared::open() actual rate = %d, channels = %d, deviceId = %d",
+    ALOGD("open() actual rate = %d, channels = %d, deviceId = %d",
           getSampleRate(), getSamplesPerFrame(), mServiceEndpoint->getDeviceId());
 
     result = mServiceEndpoint->registerStream(keep);
diff --git a/services/oboeservice/AAudioThread.cpp b/services/oboeservice/AAudioThread.cpp
index c6fb57d..fbb0da4 100644
--- a/services/oboeservice/AAudioThread.cpp
+++ b/services/oboeservice/AAudioThread.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "AAudioService"
+#define LOG_TAG "AAudioThread"
 //#define LOG_NDEBUG 0
 #include <utils/Log.h>
 
@@ -53,7 +53,7 @@
 
 aaudio_result_t AAudioThread::start(Runnable *runnable) {
     if (mHasThread) {
-        ALOGE("AAudioThread::start() - mHasThread already true");
+        ALOGE("start() - mHasThread already true");
         return AAUDIO_ERROR_INVALID_STATE;
     }
     // mRunnable will be read by the new thread when it starts.
@@ -61,7 +61,7 @@
     mRunnable = runnable;
     int err = pthread_create(&mThread, nullptr, AAudioThread_internalThreadProc, this);
     if (err != 0) {
-        ALOGE("AAudioThread::start() - pthread_create() returned %d %s", err, strerror(err));
+        ALOGE("start() - pthread_create() returned %d %s", err, strerror(err));
         return AAudioConvert_androidToAAudioResult(-err);
     } else {
         mHasThread = true;
@@ -71,13 +71,13 @@
 
 aaudio_result_t AAudioThread::stop() {
     if (!mHasThread) {
-        ALOGE("AAudioThread::stop() but no thread running");
+        ALOGE("stop() but no thread running");
         return AAUDIO_ERROR_INVALID_STATE;
     }
     int err = pthread_join(mThread, nullptr);
     mHasThread = false;
     if (err != 0) {
-        ALOGE("AAudioThread::stop() - pthread_join() returned %d %s", err, strerror(err));
+        ALOGE("stop() - pthread_join() returned %d %s", err, strerror(err));
         return AAudioConvert_androidToAAudioResult(-err);
     } else {
         return AAUDIO_OK;
diff --git a/services/oboeservice/SharedMemoryProxy.cpp b/services/oboeservice/SharedMemoryProxy.cpp
index fb991bb..c43ed22 100644
--- a/services/oboeservice/SharedMemoryProxy.cpp
+++ b/services/oboeservice/SharedMemoryProxy.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "AAudioService"
+#define LOG_TAG "SharedMemoryProxy"
 //#define LOG_NDEBUG 0
 #include <log/log.h>
 
@@ -45,12 +45,12 @@
 
     mProxyFileDescriptor = ashmem_create_region("AAudioProxyDataBuffer", mSharedMemorySizeInBytes);
     if (mProxyFileDescriptor < 0) {
-        ALOGE("SharedMemoryProxy::open() ashmem_create_region() failed %d", errno);
+        ALOGE("open() ashmem_create_region() failed %d", errno);
         return AAUDIO_ERROR_INTERNAL;
     }
     int err = ashmem_set_prot_region(mProxyFileDescriptor, PROT_READ|PROT_WRITE);
     if (err < 0) {
-        ALOGE("SharedMemoryProxy::open() ashmem_set_prot_region() failed %d", errno);
+        ALOGE("open() ashmem_set_prot_region() failed %d", errno);
         close(mProxyFileDescriptor);
         mProxyFileDescriptor = -1;
         return AAUDIO_ERROR_INTERNAL; // TODO convert errno to a better AAUDIO_ERROR;
@@ -62,7 +62,7 @@
                          MAP_SHARED,
                          mOriginalFileDescriptor, 0);
     if (mOriginalSharedMemory == MAP_FAILED) {
-        ALOGE("SharedMemoryProxy::open() original mmap(%d) failed %d (%s)",
+        ALOGE("open() original mmap(%d) failed %d (%s)",
                 mOriginalFileDescriptor, errno, strerror(errno));
         return AAUDIO_ERROR_INTERNAL; // TODO convert errno to a better AAUDIO_ERROR;
     }
@@ -73,7 +73,7 @@
                          MAP_SHARED,
                          mProxyFileDescriptor, 0);
     if (mProxySharedMemory != mOriginalSharedMemory) {
-        ALOGE("SharedMemoryProxy::open() proxy mmap(%d) failed %d", mProxyFileDescriptor, errno);
+        ALOGE("open() proxy mmap(%d) failed %d", mProxyFileDescriptor, errno);
         munmap(mOriginalSharedMemory, mSharedMemorySizeInBytes);
         mOriginalSharedMemory = nullptr;
         close(mProxyFileDescriptor);
diff --git a/services/oboeservice/SharedRingBuffer.cpp b/services/oboeservice/SharedRingBuffer.cpp
index 83b25b3..2454446 100644
--- a/services/oboeservice/SharedRingBuffer.cpp
+++ b/services/oboeservice/SharedRingBuffer.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "AAudioService"
+#define LOG_TAG "SharedRingBuffer"
 //#define LOG_NDEBUG 0
 #include <utils/Log.h>
 
@@ -46,14 +46,14 @@
     mSharedMemorySizeInBytes = mDataMemorySizeInBytes + (2 * (sizeof(fifo_counter_t)));
     mFileDescriptor.reset(ashmem_create_region("AAudioSharedRingBuffer", mSharedMemorySizeInBytes));
     if (mFileDescriptor.get() == -1) {
-        ALOGE("SharedRingBuffer::allocate() ashmem_create_region() failed %d", errno);
+        ALOGE("allocate() ashmem_create_region() failed %d", errno);
         return AAUDIO_ERROR_INTERNAL;
     }
-    ALOGV("SharedRingBuffer::allocate() mFileDescriptor = %d\n", mFileDescriptor.get());
+    ALOGV("allocate() mFileDescriptor = %d\n", mFileDescriptor.get());
 
     int err = ashmem_set_prot_region(mFileDescriptor.get(), PROT_READ|PROT_WRITE); // TODO error handling?
     if (err < 0) {
-        ALOGE("SharedRingBuffer::allocate() ashmem_set_prot_region() failed %d", errno);
+        ALOGE("allocate() ashmem_set_prot_region() failed %d", errno);
         mFileDescriptor.reset();
         return AAUDIO_ERROR_INTERNAL; // TODO convert errno to a better AAUDIO_ERROR;
     }
@@ -64,7 +64,7 @@
                          MAP_SHARED,
                          mFileDescriptor.get(), 0);
     if (mSharedMemory == MAP_FAILED) {
-        ALOGE("SharedRingBuffer::allocate() mmap() failed %d", errno);
+        ALOGE("allocate() mmap() failed %d", errno);
         mFileDescriptor.reset();
         return AAUDIO_ERROR_INTERNAL; // TODO convert errno to a better AAUDIO_ERROR;
     }
diff --git a/services/soundtrigger/SoundTriggerHwService.cpp b/services/soundtrigger/SoundTriggerHwService.cpp
index 22519a3..6d833aa 100644
--- a/services/soundtrigger/SoundTriggerHwService.cpp
+++ b/services/soundtrigger/SoundTriggerHwService.cpp
@@ -206,9 +206,10 @@
     service->sendRecognitionEvent(event, module);
 }
 
-sp<IMemory> SoundTriggerHwService::prepareRecognitionEvent_l(
+sp<IMemory> SoundTriggerHwService::prepareRecognitionEvent(
                                                     struct sound_trigger_recognition_event *event)
 {
+    AutoMutex lock(mMemoryDealerLock);
     sp<IMemory> eventMemory;
 
     //sanitize event
@@ -216,21 +217,21 @@
     case SOUND_MODEL_TYPE_KEYPHRASE:
         ALOGW_IF(event->data_size != 0 && event->data_offset !=
                     sizeof(struct sound_trigger_phrase_recognition_event),
-                    "prepareRecognitionEvent_l(): invalid data offset %u for keyphrase event type",
+                    "prepareRecognitionEvent(): invalid data offset %u for keyphrase event type",
                     event->data_offset);
         event->data_offset = sizeof(struct sound_trigger_phrase_recognition_event);
         break;
     case SOUND_MODEL_TYPE_GENERIC:
         ALOGW_IF(event->data_size != 0 && event->data_offset !=
                     sizeof(struct sound_trigger_generic_recognition_event),
-                    "prepareRecognitionEvent_l(): invalid data offset %u for generic event type",
+                    "prepareRecognitionEvent(): invalid data offset %u for generic event type",
                     event->data_offset);
         event->data_offset = sizeof(struct sound_trigger_generic_recognition_event);
         break;
     case SOUND_MODEL_TYPE_UNKNOWN:
         ALOGW_IF(event->data_size != 0 && event->data_offset !=
                     sizeof(struct sound_trigger_recognition_event),
-                    "prepareRecognitionEvent_l(): invalid data offset %u for unknown event type",
+                    "prepareRecognitionEvent(): invalid data offset %u for unknown event type",
                     event->data_offset);
         event->data_offset = sizeof(struct sound_trigger_recognition_event);
         break;
@@ -251,30 +252,19 @@
 
 void SoundTriggerHwService::sendRecognitionEvent(struct sound_trigger_recognition_event *event,
                                                  Module *module)
- {
-     AutoMutex lock(mServiceLock);
-     if (module == NULL) {
-         return;
-     }
-     sp<IMemory> eventMemory = prepareRecognitionEvent_l(event);
-     if (eventMemory == 0) {
-         return;
-     }
-     sp<Module> strongModule;
-     for (size_t i = 0; i < mModules.size(); i++) {
-         if (mModules.valueAt(i).get() == module) {
-             strongModule = mModules.valueAt(i);
-             break;
-         }
-     }
-     if (strongModule == 0) {
-         return;
-     }
+{
+    if (module == NULL) {
+        return;
+    }
+    sp<IMemory> eventMemory = prepareRecognitionEvent(event);
+    if (eventMemory == 0) {
+        return;
+    }
 
     sp<CallbackEvent> callbackEvent = new CallbackEvent(CallbackEvent::TYPE_RECOGNITION,
                                                         eventMemory);
-    callbackEvent->setModule(strongModule);
-    sendCallbackEvent_l(callbackEvent);
+    callbackEvent->setModule(module);
+    sendCallbackEvent(callbackEvent);
 }
 
 // static
@@ -293,8 +283,9 @@
     service->sendSoundModelEvent(event, module);
 }
 
-sp<IMemory> SoundTriggerHwService::prepareSoundModelEvent_l(struct sound_trigger_model_event *event)
+sp<IMemory> SoundTriggerHwService::prepareSoundModelEvent(struct sound_trigger_model_event *event)
 {
+    AutoMutex lock(mMemoryDealerLock);
     sp<IMemory> eventMemory;
 
     size_t size = event->data_offset + event->data_size;
@@ -311,30 +302,20 @@
 void SoundTriggerHwService::sendSoundModelEvent(struct sound_trigger_model_event *event,
                                                 Module *module)
 {
-    AutoMutex lock(mServiceLock);
-    sp<IMemory> eventMemory = prepareSoundModelEvent_l(event);
+    sp<IMemory> eventMemory = prepareSoundModelEvent(event);
     if (eventMemory == 0) {
         return;
     }
-    sp<Module> strongModule;
-    for (size_t i = 0; i < mModules.size(); i++) {
-        if (mModules.valueAt(i).get() == module) {
-            strongModule = mModules.valueAt(i);
-            break;
-        }
-    }
-    if (strongModule == 0) {
-        return;
-    }
     sp<CallbackEvent> callbackEvent = new CallbackEvent(CallbackEvent::TYPE_SOUNDMODEL,
                                                         eventMemory);
-    callbackEvent->setModule(strongModule);
-    sendCallbackEvent_l(callbackEvent);
+    callbackEvent->setModule(module);
+    sendCallbackEvent(callbackEvent);
 }
 
 
 sp<IMemory> SoundTriggerHwService::prepareServiceStateEvent_l(sound_trigger_service_state_t state)
 {
+    AutoMutex lock(mMemoryDealerLock);
     sp<IMemory> eventMemory;
 
     size_t size = sizeof(sound_trigger_service_state_t);
@@ -368,7 +349,7 @@
     sp<CallbackEvent> callbackEvent = new CallbackEvent(CallbackEvent::TYPE_SERVICE_STATE,
                                                         eventMemory);
     callbackEvent->setModule(strongModule);
-    sendCallbackEvent_l(callbackEvent);
+    sendCallbackEvent(callbackEvent);
 }
 
 void SoundTriggerHwService::sendServiceStateEvent_l(sound_trigger_service_state_t state,
@@ -381,11 +362,10 @@
     sp<CallbackEvent> callbackEvent = new CallbackEvent(CallbackEvent::TYPE_SERVICE_STATE,
                                                         eventMemory);
     callbackEvent->setModuleClient(moduleClient);
-    sendCallbackEvent_l(callbackEvent);
+    sendCallbackEvent(callbackEvent);
 }
 
-// call with mServiceLock held
-void SoundTriggerHwService::sendCallbackEvent_l(const sp<CallbackEvent>& event)
+void SoundTriggerHwService::sendCallbackEvent(const sp<CallbackEvent>& event)
 {
     mCallbackThread->sendCallbackEvent(event);
 }
@@ -404,6 +384,19 @@
             if (moduleClient == 0) {
                 return;
             }
+        } else {
+            // Sanity check on this being a Module we know about.
+            bool foundModule = false;
+            for (size_t i = 0; i < mModules.size(); i++) {
+                if (mModules.valueAt(i).get() == module.get()) {
+                    foundModule = true;
+                    break;
+                }
+            }
+            if (!foundModule) {
+                ALOGE("onCallbackEvent for unknown module");
+                return;
+            }
         }
     }
     if (module != 0) {
@@ -757,11 +750,12 @@
         return;
     }
 
+    Vector< sp<ModuleClient> > clients;
+
     switch (event->mType) {
     case CallbackEvent::TYPE_RECOGNITION: {
         struct sound_trigger_recognition_event *recognitionEvent =
                 (struct sound_trigger_recognition_event *)eventMemory->pointer();
-        sp<ISoundTriggerClient> client;
         {
             AutoMutex lock(mLock);
             sp<Model> model = getModel(recognitionEvent->model);
@@ -776,16 +770,12 @@
 
             recognitionEvent->capture_session = model->mCaptureSession;
             model->mState = Model::STATE_IDLE;
-            client = model->mModuleClient->client();
-        }
-        if (client != 0) {
-            client->onRecognitionEvent(eventMemory);
+            clients.add(model->mModuleClient);
         }
     } break;
     case CallbackEvent::TYPE_SOUNDMODEL: {
         struct sound_trigger_model_event *soundmodelEvent =
                 (struct sound_trigger_model_event *)eventMemory->pointer();
-        sp<ISoundTriggerClient> client;
         {
             AutoMutex lock(mLock);
             sp<Model> model = getModel(soundmodelEvent->model);
@@ -793,29 +783,26 @@
                 ALOGW("%s model == 0", __func__);
                 return;
             }
-            client = model->mModuleClient->client();
-        }
-        if (client != 0) {
-            client->onSoundModelEvent(eventMemory);
+            clients.add(model->mModuleClient);
         }
     } break;
     case CallbackEvent::TYPE_SERVICE_STATE: {
-        Vector< sp<ISoundTriggerClient> > clients;
         {
             AutoMutex lock(mLock);
             for (size_t i = 0; i < mModuleClients.size(); i++) {
                 if (mModuleClients[i] != 0) {
-                    clients.add(mModuleClients[i]->client());
+                    clients.add(mModuleClients[i]);
                 }
             }
         }
-        for (size_t i = 0; i < clients.size(); i++) {
-            clients[i]->onServiceStateChange(eventMemory);
-        }
     } break;
     default:
         LOG_ALWAYS_FATAL("onCallbackEvent unknown event type %d", event->mType);
     }
+
+    for (size_t i = 0; i < clients.size(); i++) {
+        clients[i]->onCallbackEvent(event);
+    }
 }
 
 sp<SoundTriggerHwService::Model> SoundTriggerHwService::Module::getModel(
@@ -878,7 +865,7 @@
                     event.common.type = model->mType;
                     event.common.model = model->mHandle;
                     event.common.data_size = 0;
-                    sp<IMemory> eventMemory = service->prepareRecognitionEvent_l(&event.common);
+                    sp<IMemory> eventMemory = service->prepareRecognitionEvent(&event.common);
                     if (eventMemory != 0) {
                         events.add(eventMemory);
                     }
@@ -889,7 +876,7 @@
                     event.common.type = model->mType;
                     event.common.model = model->mHandle;
                     event.common.data_size = 0;
-                    sp<IMemory> eventMemory = service->prepareRecognitionEvent_l(&event.common);
+                    sp<IMemory> eventMemory = service->prepareRecognitionEvent(&event.common);
                     if (eventMemory != 0) {
                         events.add(eventMemory);
                     }
@@ -900,7 +887,7 @@
                     event.common.type = model->mType;
                     event.common.model = model->mHandle;
                     event.common.data_size = 0;
-                    sp<IMemory> eventMemory = service->prepareRecognitionEvent_l(&event.common);
+                    sp<IMemory> eventMemory = service->prepareRecognitionEvent(&event.common);
                     if (eventMemory != 0) {
                         events.add(eventMemory);
                     }
@@ -915,7 +902,7 @@
         sp<CallbackEvent> callbackEvent = new CallbackEvent(CallbackEvent::TYPE_RECOGNITION,
                                                             events[i]);
         callbackEvent->setModule(this);
-        service->sendCallbackEvent_l(callbackEvent);
+        service->sendCallbackEvent(callbackEvent);
     }
 
 exit:
@@ -1077,19 +1064,26 @@
         return;
     }
 
-    switch (event->mType) {
-    case CallbackEvent::TYPE_SERVICE_STATE: {
-        sp<ISoundTriggerClient> client;
-        {
-            AutoMutex lock(mLock);
-            client = mClient;
-        }
-        if (client !=0 ) {
+    sp<ISoundTriggerClient> client;
+    {
+        AutoMutex lock(mLock);
+        client = mClient;
+    }
+
+    if (client != 0) {
+        switch (event->mType) {
+        case CallbackEvent::TYPE_RECOGNITION: {
+            client->onRecognitionEvent(eventMemory);
+        } break;
+        case CallbackEvent::TYPE_SOUNDMODEL: {
+            client->onSoundModelEvent(eventMemory);
+        } break;
+        case CallbackEvent::TYPE_SERVICE_STATE: {
             client->onServiceStateChange(eventMemory);
+        } break;
+        default:
+            LOG_ALWAYS_FATAL("onCallbackEvent unknown event type %d", event->mType);
         }
-    } break;
-    default:
-        LOG_ALWAYS_FATAL("onCallbackEvent unknown event type %d", event->mType);
     }
 }
 
diff --git a/services/soundtrigger/SoundTriggerHwService.h b/services/soundtrigger/SoundTriggerHwService.h
index 95efc4b..a955f40 100644
--- a/services/soundtrigger/SoundTriggerHwService.h
+++ b/services/soundtrigger/SoundTriggerHwService.h
@@ -214,11 +214,11 @@
     };
 
     static void recognitionCallback(struct sound_trigger_recognition_event *event, void *cookie);
-           sp<IMemory> prepareRecognitionEvent_l(struct sound_trigger_recognition_event *event);
+           sp<IMemory> prepareRecognitionEvent(struct sound_trigger_recognition_event *event);
            void sendRecognitionEvent(struct sound_trigger_recognition_event *event, Module *module);
 
     static void soundModelCallback(struct sound_trigger_model_event *event, void *cookie);
-           sp<IMemory> prepareSoundModelEvent_l(struct sound_trigger_model_event *event);
+           sp<IMemory> prepareSoundModelEvent(struct sound_trigger_model_event *event);
            void sendSoundModelEvent(struct sound_trigger_model_event *event, Module *module);
 
            sp<IMemory> prepareServiceStateEvent_l(sound_trigger_service_state_t state);
@@ -226,7 +226,7 @@
            void sendServiceStateEvent_l(sound_trigger_service_state_t state,
                                         ModuleClient *moduleClient);
 
-           void sendCallbackEvent_l(const sp<CallbackEvent>& event);
+           void sendCallbackEvent(const sp<CallbackEvent>& event);
            void onCallbackEvent(const sp<CallbackEvent>& event);
 
 private:
@@ -238,6 +238,7 @@
     DefaultKeyedVector< sound_trigger_module_handle_t, sp<Module> >     mModules;
     sp<CallbackThread>  mCallbackThread;
     sp<MemoryDealer>    mMemoryDealer;
+    Mutex               mMemoryDealerLock;
     bool                mCaptureState;
 };