Merge "NuPlayer: handle audio output format change in a clean way."
diff --git a/camera/cameraserver/Android.mk b/camera/cameraserver/Android.mk
index 888862a..36e3927 100644
--- a/camera/cameraserver/Android.mk
+++ b/camera/cameraserver/Android.mk
@@ -22,7 +22,6 @@
 LOCAL_SHARED_LIBRARIES := \
 	libcameraservice \
 	liblog \
-	libcutils \
 	libutils \
 	libbinder \
 
diff --git a/cmds/stagefright/Android.mk b/cmds/stagefright/Android.mk
index b28d509..9a236fc 100644
--- a/cmds/stagefright/Android.mk
+++ b/cmds/stagefright/Android.mk
@@ -124,29 +124,6 @@
 
 include $(CLEAR_VARS)
 
-LOCAL_SRC_FILES:=         \
-	sf2.cpp    \
-
-LOCAL_SHARED_LIBRARIES := \
-	libstagefright liblog libutils libbinder libstagefright_foundation \
-	libmedia libgui libcutils
-
-LOCAL_C_INCLUDES:= \
-	frameworks/av/media/libstagefright \
-	$(TOP)/frameworks/native/include/media/openmax
-
-LOCAL_CFLAGS += -Wno-multichar -Werror -Wall
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_MODULE:= sf2
-
-include $(BUILD_EXECUTABLE)
-
-################################################################################
-
-include $(CLEAR_VARS)
-
 LOCAL_SRC_FILES:=               \
 	codec.cpp               \
 	SimplePlayer.cpp        \
diff --git a/cmds/stagefright/codec.cpp b/cmds/stagefright/codec.cpp
index 26135d7..3108a67 100644
--- a/cmds/stagefright/codec.cpp
+++ b/cmds/stagefright/codec.cpp
@@ -32,7 +32,6 @@
 #include <media/stagefright/foundation/ALooper.h>
 #include <media/stagefright/foundation/AMessage.h>
 #include <media/stagefright/foundation/AString.h>
-#include <media/stagefright/DataSource.h>
 #include <media/stagefright/MediaCodec.h>
 #include <media/stagefright/MediaCodecList.h>
 #include <media/stagefright/MediaDefs.h>
@@ -401,8 +400,6 @@
 
     ProcessState::self()->startThreadPool();
 
-    DataSource::RegisterDefaultSniffers();
-
     sp<ALooper> looper = new ALooper;
     looper->start();
 
diff --git a/cmds/stagefright/mediafilter.cpp b/cmds/stagefright/mediafilter.cpp
index 410dd69..f219e69 100644
--- a/cmds/stagefright/mediafilter.cpp
+++ b/cmds/stagefright/mediafilter.cpp
@@ -30,7 +30,6 @@
 #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/MediaCodec.h>
 #include <media/stagefright/NuMediaExtractor.h>
 #include <media/stagefright/RenderScriptWrapper.h>
@@ -738,8 +737,6 @@
 
     ProcessState::self()->startThreadPool();
 
-    DataSource::RegisterDefaultSniffers();
-
     android::sp<ALooper> looper = new ALooper;
     looper->start();
 
diff --git a/cmds/stagefright/muxer.cpp b/cmds/stagefright/muxer.cpp
index 0a3bdf3..4a83a4a 100644
--- a/cmds/stagefright/muxer.cpp
+++ b/cmds/stagefright/muxer.cpp
@@ -29,7 +29,6 @@
 #include <media/stagefright/foundation/ALooper.h>
 #include <media/stagefright/foundation/AMessage.h>
 #include <media/stagefright/foundation/AString.h>
-#include <media/stagefright/DataSource.h>
 #include <media/stagefright/MediaCodec.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaMuxer.h>
@@ -319,9 +318,6 @@
     }
     ProcessState::self()->startThreadPool();
 
-    // Make sure setDataSource() works.
-    DataSource::RegisterDefaultSniffers();
-
     sp<ALooper> looper = new ALooper;
     looper->start();
 
diff --git a/cmds/stagefright/record.cpp b/cmds/stagefright/record.cpp
index 9aa0156..94c2e96 100644
--- a/cmds/stagefright/record.cpp
+++ b/cmds/stagefright/record.cpp
@@ -170,8 +170,6 @@
 int main(int argc, char **argv) {
     android::ProcessState::self()->startThreadPool();
 
-    DataSource::RegisterDefaultSniffers();
-
 #if 1
     if (argc != 3) {
         fprintf(stderr, "usage: %s <filename> <input_color_format>\n", argv[0]);
diff --git a/cmds/stagefright/sf2.cpp b/cmds/stagefright/sf2.cpp
deleted file mode 100644
index 76dbb78..0000000
--- a/cmds/stagefright/sf2.cpp
+++ /dev/null
@@ -1,682 +0,0 @@
-/*
- * Copyright (C) 2010 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 "sf2"
-#include <inttypes.h>
-#include <utils/Log.h>
-
-#include <signal.h>
-
-#include <binder/ProcessState.h>
-
-#include <media/IMediaHTTPService.h>
-
-#include <media/stagefright/foundation/hexdump.h>
-#include <media/stagefright/foundation/ABuffer.h>
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/foundation/ALooper.h>
-#include <media/stagefright/foundation/AMessage.h>
-
-#include <media/stagefright/ACodec.h>
-#include <media/stagefright/DataSource.h>
-#include <media/stagefright/MediaBuffer.h>
-#include <media/stagefright/MediaDefs.h>
-#include <media/stagefright/MediaExtractor.h>
-#include <media/stagefright/MediaSource.h>
-#include <media/stagefright/MetaData.h>
-#include <media/stagefright/Utils.h>
-
-#include <gui/SurfaceComposerClient.h>
-#include <gui/Surface.h>
-
-#include "include/ESDS.h"
-
-using namespace android;
-
-volatile static bool ctrlc = false;
-
-static sighandler_t oldhandler = NULL;
-
-static void mysighandler(int signum) {
-    if (signum == SIGINT) {
-        ctrlc = true;
-        return;
-    }
-    oldhandler(signum);
-}
-
-struct Controller : public AHandler {
-    Controller(const char *uri, bool decodeAudio,
-               const sp<Surface> &surface, bool renderToSurface)
-        : mURI(uri),
-          mDecodeAudio(decodeAudio),
-          mSurface(surface),
-          mRenderToSurface(renderToSurface),
-          mCodec(new ACodec),
-          mIsVorbis(false) {
-        CHECK(!mDecodeAudio || mSurface == NULL);
-    }
-
-    void startAsync() {
-        (new AMessage(kWhatStart, this))->post();
-    }
-
-protected:
-    virtual ~Controller() {
-    }
-
-    virtual void printStatistics() {
-        int64_t delayUs = ALooper::GetNowUs() - mStartTimeUs;
-
-        if (mDecodeAudio) {
-            printf("%" PRId64 " bytes received. %.2f KB/sec\n",
-            mTotalBytesReceived,
-            mTotalBytesReceived * 1E6 / 1024 / delayUs);
-        } else {
-            printf("%d frames decoded, %.2f fps. %" PRId64 " bytes "
-                    "received. %.2f KB/sec\n",
-            mNumOutputBuffersReceived,
-            mNumOutputBuffersReceived * 1E6 / delayUs,
-            mTotalBytesReceived,
-            mTotalBytesReceived * 1E6 / 1024 / delayUs);
-        }
-    }
-
-    virtual void onMessageReceived(const sp<AMessage> &msg) {
-        if (ctrlc) {
-            printf("\n");
-            printStatistics();
-            (new AMessage(kWhatStop, this))->post();
-            ctrlc = false;
-        }
-        switch (msg->what()) {
-            case kWhatStart:
-            {
-#if 1
-                mDecodeLooper = looper();
-#else
-                mDecodeLooper = new ALooper;
-                mDecodeLooper->setName("sf2 decode looper");
-                mDecodeLooper->start();
-#endif
-
-                sp<DataSource> dataSource =
-                    DataSource::CreateFromURI(
-                            NULL /* httpService */, mURI.c_str());
-
-                sp<IMediaExtractor> extractor =
-                    MediaExtractor::Create(dataSource);
-
-                for (size_t i = 0; i < extractor->countTracks(); ++i) {
-                    sp<MetaData> meta = extractor->getTrackMetaData(i);
-
-                    const char *mime;
-                    CHECK(meta->findCString(kKeyMIMEType, &mime));
-
-                    if (!strncasecmp(mDecodeAudio ? "audio/" : "video/",
-                                     mime, 6)) {
-                        mSource = extractor->getTrack(i);
-
-                        if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_VORBIS)) {
-                            mIsVorbis = true;
-                        } else {
-                            mIsVorbis = false;
-                        }
-                        break;
-                    }
-                }
-                if (mSource == NULL) {
-                    printf("no %s track found\n", mDecodeAudio ? "audio" : "video");
-                    exit (1);
-                }
-
-                CHECK_EQ(mSource->start(), (status_t)OK);
-
-                mDecodeLooper->registerHandler(mCodec);
-
-                mCodec->setNotificationMessage(
-                        new AMessage(kWhatCodecNotify, this));
-
-                sp<AMessage> format = makeFormat(mSource->getFormat());
-
-                if (mSurface != NULL) {
-                    format->setObject("surface", mSurface);
-                }
-
-                mCodec->initiateSetup(format);
-
-                mCSDIndex = 0;
-                mStartTimeUs = ALooper::GetNowUs();
-                mNumOutputBuffersReceived = 0;
-                mTotalBytesReceived = 0;
-                mLeftOverBuffer = NULL;
-                mFinalResult = OK;
-                mSeekState = SEEK_NONE;
-
-                // (new AMessage(kWhatSeek, this))->post(5000000ll);
-                break;
-            }
-
-            case kWhatSeek:
-            {
-                printf("+");
-                fflush(stdout);
-
-                CHECK(mSeekState == SEEK_NONE
-                        || mSeekState == SEEK_FLUSH_COMPLETED);
-
-                if (mLeftOverBuffer != NULL) {
-                    mLeftOverBuffer->release();
-                    mLeftOverBuffer = NULL;
-                }
-
-                mSeekState = SEEK_FLUSHING;
-                mSeekTimeUs = 30000000ll;
-
-                mCodec->signalFlush();
-                break;
-            }
-
-            case kWhatStop:
-            {
-                if (mLeftOverBuffer != NULL) {
-                    mLeftOverBuffer->release();
-                    mLeftOverBuffer = NULL;
-                }
-
-                CHECK_EQ(mSource->stop(), (status_t)OK);
-                mSource.clear();
-
-                mCodec->initiateShutdown();
-                break;
-            }
-
-            case kWhatCodecNotify:
-            {
-                int32_t what;
-                CHECK(msg->findInt32("what", &what));
-
-                if (what == CodecBase::kWhatFillThisBuffer) {
-                    onFillThisBuffer(msg);
-                } else if (what == CodecBase::kWhatDrainThisBuffer) {
-                    if ((mNumOutputBuffersReceived++ % 16) == 0) {
-                        printf(".");
-                        fflush(stdout);
-                    }
-
-                    onDrainThisBuffer(msg);
-                } else if (what == CodecBase::kWhatEOS
-                        || what == CodecBase::kWhatError) {
-                    printf((what == CodecBase::kWhatEOS) ? "$\n" : "E\n");
-
-                    printStatistics();
-                    (new AMessage(kWhatStop, this))->post();
-                } else if (what == CodecBase::kWhatFlushCompleted) {
-                    mSeekState = SEEK_FLUSH_COMPLETED;
-                    mCodec->signalResume();
-
-                    (new AMessage(kWhatSeek, this))->post(5000000ll);
-                } else if (what == CodecBase::kWhatStopCompleted ||
-                        what == CodecBase::kWhatReleaseCompleted) {
-                    mDecodeLooper->unregisterHandler(mCodec->id());
-
-                    if (mDecodeLooper != looper()) {
-                        mDecodeLooper->stop();
-                    }
-
-                    looper()->stop();
-                }
-                break;
-            }
-
-            default:
-                TRESPASS();
-                break;
-        }
-    }
-
-private:
-    enum {
-        kWhatStart             = 'strt',
-        kWhatStop              = 'stop',
-        kWhatCodecNotify       = 'noti',
-        kWhatSeek              = 'seek',
-    };
-
-    sp<ALooper> mDecodeLooper;
-
-    AString mURI;
-    bool mDecodeAudio;
-    sp<Surface> mSurface;
-    bool mRenderToSurface;
-    sp<ACodec> mCodec;
-    sp<IMediaSource> mSource;
-    bool mIsVorbis;
-
-    Vector<sp<ABuffer> > mCSD;
-    size_t mCSDIndex;
-
-    MediaBuffer *mLeftOverBuffer;
-    status_t mFinalResult;
-
-    int64_t mStartTimeUs;
-    int32_t mNumOutputBuffersReceived;
-    int64_t mTotalBytesReceived;
-
-    enum SeekState {
-        SEEK_NONE,
-        SEEK_FLUSHING,
-        SEEK_FLUSH_COMPLETED,
-    };
-    SeekState mSeekState;
-    int64_t mSeekTimeUs;
-
-    sp<AMessage> makeFormat(const sp<MetaData> &meta) {
-        CHECK(mCSD.isEmpty());
-
-        const char *mime;
-        CHECK(meta->findCString(kKeyMIMEType, &mime));
-
-        sp<AMessage> msg = new AMessage;
-        msg->setString("mime", mime);
-
-        if (!strncasecmp("video/", mime, 6)) {
-            int32_t width, height;
-            CHECK(meta->findInt32(kKeyWidth, &width));
-            CHECK(meta->findInt32(kKeyHeight, &height));
-
-            msg->setInt32("width", width);
-            msg->setInt32("height", height);
-        } else {
-            CHECK(!strncasecmp("audio/", mime, 6));
-
-            int32_t numChannels, sampleRate;
-            CHECK(meta->findInt32(kKeyChannelCount, &numChannels));
-            CHECK(meta->findInt32(kKeySampleRate, &sampleRate));
-
-            msg->setInt32("channel-count", numChannels);
-            msg->setInt32("sample-rate", sampleRate);
-
-            int32_t isADTS;
-            if (meta->findInt32(kKeyIsADTS, &isADTS) && isADTS != 0) {
-                msg->setInt32("is-adts", true);
-            }
-        }
-
-        uint32_t type;
-        const void *data;
-        size_t size;
-        if (meta->findData(kKeyAVCC, &type, &data, &size)) {
-            // Parse the AVCDecoderConfigurationRecord
-
-            const uint8_t *ptr = (const uint8_t *)data;
-
-            CHECK(size >= 7);
-            CHECK_EQ((unsigned)ptr[0], 1u);  // configurationVersion == 1
-            uint8_t profile __unused = ptr[1];
-            uint8_t level __unused = ptr[3];
-
-            // There is decodable content out there that fails the following
-            // assertion, let's be lenient for now...
-            // CHECK((ptr[4] >> 2) == 0x3f);  // reserved
-
-            size_t lengthSize __unused = 1 + (ptr[4] & 3);
-
-            // commented out check below as H264_QVGA_500_NO_AUDIO.3gp
-            // violates it...
-            // CHECK((ptr[5] >> 5) == 7);  // reserved
-
-            size_t numSeqParameterSets = ptr[5] & 31;
-
-            ptr += 6;
-            size -= 6;
-
-            sp<ABuffer> buffer = new ABuffer(1024);
-            buffer->setRange(0, 0);
-
-            for (size_t i = 0; i < numSeqParameterSets; ++i) {
-                CHECK(size >= 2);
-                size_t length = U16_AT(ptr);
-
-                ptr += 2;
-                size -= 2;
-
-                CHECK(size >= length);
-
-                memcpy(buffer->data() + buffer->size(), "\x00\x00\x00\x01", 4);
-                memcpy(buffer->data() + buffer->size() + 4, ptr, length);
-                buffer->setRange(0, buffer->size() + 4 + length);
-
-                ptr += length;
-                size -= length;
-            }
-
-            buffer->meta()->setInt32("csd", true);
-            mCSD.push(buffer);
-
-            buffer = new ABuffer(1024);
-            buffer->setRange(0, 0);
-
-            CHECK(size >= 1);
-            size_t numPictureParameterSets = *ptr;
-            ++ptr;
-            --size;
-
-            for (size_t i = 0; i < numPictureParameterSets; ++i) {
-                CHECK(size >= 2);
-                size_t length = U16_AT(ptr);
-
-                ptr += 2;
-                size -= 2;
-
-                CHECK(size >= length);
-
-                memcpy(buffer->data() + buffer->size(), "\x00\x00\x00\x01", 4);
-                memcpy(buffer->data() + buffer->size() + 4, ptr, length);
-                buffer->setRange(0, buffer->size() + 4 + length);
-
-                ptr += length;
-                size -= length;
-            }
-
-            buffer->meta()->setInt32("csd", true);
-            mCSD.push(buffer);
-
-            msg->setBuffer("csd", buffer);
-        } else if (meta->findData(kKeyESDS, &type, &data, &size)) {
-            ESDS esds((const char *)data, size);
-            CHECK_EQ(esds.InitCheck(), (status_t)OK);
-
-            const void *codec_specific_data;
-            size_t codec_specific_data_size;
-            esds.getCodecSpecificInfo(
-                    &codec_specific_data, &codec_specific_data_size);
-
-            sp<ABuffer> buffer = new ABuffer(codec_specific_data_size);
-
-            memcpy(buffer->data(), codec_specific_data,
-                   codec_specific_data_size);
-
-            buffer->meta()->setInt32("csd", true);
-            mCSD.push(buffer);
-        } else if (meta->findData(kKeyVorbisInfo, &type, &data, &size)) {
-            sp<ABuffer> buffer = new ABuffer(size);
-            memcpy(buffer->data(), data, size);
-
-            buffer->meta()->setInt32("csd", true);
-            mCSD.push(buffer);
-
-            CHECK(meta->findData(kKeyVorbisBooks, &type, &data, &size));
-
-            buffer = new ABuffer(size);
-            memcpy(buffer->data(), data, size);
-
-            buffer->meta()->setInt32("csd", true);
-            mCSD.push(buffer);
-        }
-
-        int32_t maxInputSize;
-        if (meta->findInt32(kKeyMaxInputSize, &maxInputSize)) {
-            msg->setInt32("max-input-size", maxInputSize);
-        }
-
-        return msg;
-    }
-
-    void onFillThisBuffer(const sp<AMessage> &msg) {
-        sp<AMessage> reply;
-        CHECK(msg->findMessage("reply", &reply));
-
-        if (mSource == NULL || mSeekState == SEEK_FLUSHING) {
-            reply->setInt32("err", ERROR_END_OF_STREAM);
-            reply->post();
-            return;
-        }
-
-        sp<ABuffer> outBuffer;
-        CHECK(msg->findBuffer("buffer", &outBuffer));
-
-        if (mCSDIndex < mCSD.size()) {
-            outBuffer = mCSD.editItemAt(mCSDIndex++);
-            outBuffer->meta()->setInt64("timeUs", 0);
-        } else {
-            size_t sizeLeft = outBuffer->capacity();
-            outBuffer->setRange(0, 0);
-
-            int32_t n = 0;
-
-            for (;;) {
-                MediaBuffer *inBuffer;
-
-                if (mLeftOverBuffer != NULL) {
-                    inBuffer = mLeftOverBuffer;
-                    mLeftOverBuffer = NULL;
-                } else if (mFinalResult != OK) {
-                    break;
-                } else {
-                    MediaSource::ReadOptions options;
-                    if (mSeekState == SEEK_FLUSH_COMPLETED) {
-                        options.setSeekTo(mSeekTimeUs);
-                        mSeekState = SEEK_NONE;
-                    }
-                    status_t err = mSource->read(&inBuffer, &options);
-
-                    if (err != OK) {
-                        mFinalResult = err;
-                        break;
-                    }
-                }
-
-                size_t sizeNeeded = inBuffer->range_length();
-                if (mIsVorbis) {
-                    // Vorbis data is suffixed with the number of
-                    // valid samples on the page.
-                    sizeNeeded += sizeof(int32_t);
-                }
-
-                if (sizeNeeded > sizeLeft) {
-                    if (outBuffer->size() == 0) {
-                        ALOGE("Unable to fit even a single input buffer of size %zu.",
-                             sizeNeeded);
-                    }
-                    CHECK_GT(outBuffer->size(), 0u);
-
-                    mLeftOverBuffer = inBuffer;
-                    break;
-                }
-
-                ++n;
-
-                if (outBuffer->size() == 0) {
-                    int64_t timeUs;
-                    CHECK(inBuffer->meta_data()->findInt64(kKeyTime, &timeUs));
-
-                    outBuffer->meta()->setInt64("timeUs", timeUs);
-                }
-
-                memcpy(outBuffer->data() + outBuffer->size(),
-                       (const uint8_t *)inBuffer->data()
-                        + inBuffer->range_offset(),
-                       inBuffer->range_length());
-
-                if (mIsVorbis) {
-                    int32_t numPageSamples;
-                    if (!inBuffer->meta_data()->findInt32(
-                                kKeyValidSamples, &numPageSamples)) {
-                        numPageSamples = -1;
-                    }
-
-                    memcpy(outBuffer->data()
-                            + outBuffer->size() + inBuffer->range_length(),
-                           &numPageSamples, sizeof(numPageSamples));
-                }
-
-                outBuffer->setRange(
-                        0, outBuffer->size() + sizeNeeded);
-
-                sizeLeft -= sizeNeeded;
-
-                inBuffer->release();
-                inBuffer = NULL;
-
-                break;  // Don't coalesce
-            }
-
-            ALOGV("coalesced %d input buffers", n);
-
-            if (outBuffer->size() == 0) {
-                CHECK_NE(mFinalResult, (status_t)OK);
-
-                reply->setInt32("err", mFinalResult);
-                reply->post();
-                return;
-            }
-        }
-
-        reply->setBuffer("buffer", outBuffer);
-        reply->post();
-    }
-
-    void onDrainThisBuffer(const sp<AMessage> &msg) {
-        sp<ABuffer> buffer;
-        CHECK(msg->findBuffer("buffer", &buffer));
-
-        mTotalBytesReceived += buffer->size();
-
-        sp<AMessage> reply;
-        CHECK(msg->findMessage("reply", &reply));
-
-        if (mRenderToSurface) {
-            reply->setInt32("render", 1);
-        }
-
-        reply->post();
-    }
-
-    DISALLOW_EVIL_CONSTRUCTORS(Controller);
-};
-
-static void usage(const char *me) {
-    fprintf(stderr, "usage: %s\n", me);
-    fprintf(stderr, "       -h(elp)\n");
-    fprintf(stderr, "       -a(udio)\n");
-
-    fprintf(stderr,
-            "       -S(urface) Allocate output buffers on a surface.\n"
-            "       -R(ender)  Render surface-allocated buffers.\n");
-}
-
-int main(int argc, char **argv) {
-    android::ProcessState::self()->startThreadPool();
-
-    bool decodeAudio = false;
-    bool useSurface = false;
-    bool renderToSurface = false;
-
-    int res;
-    while ((res = getopt(argc, argv, "haSR")) >= 0) {
-        switch (res) {
-            case 'a':
-                decodeAudio = true;
-                break;
-
-            case 'S':
-                useSurface = true;
-                break;
-
-            case 'R':
-                renderToSurface = true;
-                break;
-
-            case '?':
-            case 'h':
-            default:
-            {
-                usage(argv[0]);
-                return 1;
-            }
-        }
-    }
-
-    argc -= optind;
-    argv += optind;
-
-    if (argc != 1) {
-        usage(argv[-optind]);
-        return 1;
-    }
-
-    DataSource::RegisterDefaultSniffers();
-
-    sp<ALooper> looper = new ALooper;
-    looper->setName("sf2");
-
-    sp<SurfaceComposerClient> composerClient;
-    sp<SurfaceControl> control;
-    sp<Surface> surface;
-
-    if (!decodeAudio && useSurface) {
-        composerClient = new SurfaceComposerClient;
-        CHECK_EQ(composerClient->initCheck(), (status_t)OK);
-
-        control = composerClient->createSurface(
-                String8("A Surface"),
-                1280,
-                800,
-                PIXEL_FORMAT_RGB_565,
-                0);
-
-        CHECK(control != NULL);
-        CHECK(control->isValid());
-
-        SurfaceComposerClient::openGlobalTransaction();
-        CHECK_EQ(control->setLayer(INT_MAX), (status_t)OK);
-        CHECK_EQ(control->show(), (status_t)OK);
-        SurfaceComposerClient::closeGlobalTransaction();
-
-        surface = control->getSurface();
-        CHECK(surface != NULL);
-
-        CHECK_EQ((status_t)OK,
-                 native_window_api_connect(
-                     surface.get(), NATIVE_WINDOW_API_MEDIA));
-    }
-
-    sp<Controller> controller =
-        new Controller(argv[0], decodeAudio, surface, renderToSurface);
-
-    looper->registerHandler(controller);
-
-    signal(SIGINT, mysighandler);
-
-    controller->startAsync();
-
-    CHECK_EQ(looper->start(true /* runOnCallingThread */), (status_t)OK);
-
-    looper->unregisterHandler(controller->id());
-
-    if (!decodeAudio && useSurface) {
-        CHECK_EQ((status_t)OK,
-                 native_window_api_disconnect(
-                     surface.get(), NATIVE_WINDOW_API_MEDIA));
-
-        composerClient->dispose();
-    }
-
-    return 0;
-}
-
diff --git a/cmds/stagefright/stagefright.cpp b/cmds/stagefright/stagefright.cpp
index 2bb35cb..5e3a859 100644
--- a/cmds/stagefright/stagefright.cpp
+++ b/cmds/stagefright/stagefright.cpp
@@ -965,8 +965,6 @@
         }
     }
 
-    DataSource::RegisterDefaultSniffers();
-
     status_t err = OK;
 
     for (int k = 0; k < argc && err == OK; ++k) {
diff --git a/cmds/stagefright/stream.cpp b/cmds/stagefright/stream.cpp
index 16ff39d..8f9333a 100644
--- a/cmds/stagefright/stream.cpp
+++ b/cmds/stagefright/stream.cpp
@@ -301,8 +301,6 @@
 int main(int argc, char **argv) {
     android::ProcessState::self()->startThreadPool();
 
-    DataSource::RegisterDefaultSniffers();
-
     if (argc != 2) {
         fprintf(stderr, "Usage: %s filename\n", argv[0]);
         return 1;
@@ -349,9 +347,7 @@
 
     sp<IStreamSource> source;
 
-    char prop[PROPERTY_VALUE_MAX];
-    bool usemp4 = property_get("media.stagefright.use-mp4source", prop, NULL) &&
-            (!strcmp(prop, "1") || !strcasecmp(prop, "true"));
+    bool usemp4 = property_get_bool("media.stagefright.use-mp4source", false);
 
     size_t len = strlen(argv[1]);
     if ((!usemp4 && len >= 3 && !strcasecmp(".ts", &argv[1][len - 3])) ||
diff --git a/include/drm/drm_framework_common.h b/include/drm/drm_framework_common.h
index 0750406..d75f71c 100644
--- a/include/drm/drm_framework_common.h
+++ b/include/drm/drm_framework_common.h
@@ -234,10 +234,6 @@
      * POSIX based Decrypt API set for container based DRM
      */
     static const int CONTAINER_BASED = 0x02;
-    /**
-     * Decrypt API for Widevine streams
-     */
-    static const int WV_BASED = 0x3;
 };
 
 /**
diff --git a/include/media/AudioParameter.h b/include/media/AudioParameter.h
index 9719efa..1ace607 100644
--- a/include/media/AudioParameter.h
+++ b/include/media/AudioParameter.h
@@ -88,6 +88,7 @@
     status_t get(const String8& key, String8& value) const;
     status_t getInt(const String8& key, int& value) const;
     status_t getFloat(const String8& key, float& value) const;
+    status_t getAt(size_t index, String8& key) const;
     status_t getAt(size_t index, String8& key, String8& value) const;
 
     size_t size() const { return mParameters.size(); }
diff --git a/include/media/BufferingSettings.h b/include/media/BufferingSettings.h
new file mode 100644
index 0000000..7dd9d40
--- /dev/null
+++ b/include/media/BufferingSettings.h
@@ -0,0 +1,73 @@
+/*
+ * 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 ANDROID_BUFFERING_SETTINGS_H
+#define ANDROID_BUFFERING_SETTINGS_H
+
+#include <binder/Parcelable.h>
+
+namespace android {
+
+enum BufferingMode : int {
+    // Do not support buffering.
+    BUFFERING_MODE_NONE             = 0,
+    // Support only time based buffering.
+    BUFFERING_MODE_TIME_ONLY        = 1,
+    // Support only size based buffering.
+    BUFFERING_MODE_SIZE_ONLY        = 2,
+    // Support both time and size based buffering, time based calculation precedes size based.
+    // Size based calculation will be used only when time information is not available for
+    // the stream.
+    BUFFERING_MODE_TIME_THEN_SIZE   = 3,
+    // Number of modes.
+    BUFFERING_MODE_COUNT            = 4,
+};
+
+struct BufferingSettings : public Parcelable {
+    static const int kNoWatermark = -1;
+
+    static bool IsValidBufferingMode(int mode);
+
+    BufferingMode mInitialBufferingMode;  // for prepare
+    BufferingMode mRebufferingMode;  // for playback
+
+    int mInitialWatermarkMs;  // time based
+    int mInitialWatermarkKB;  // size based
+
+    // When cached data is below this mark, playback will be paused for buffering
+    // till data reach |mRebufferingWatermarkHighMs| or end of stream.
+    int mRebufferingWatermarkLowMs;
+    // When cached data is above this mark, buffering will be paused.
+    int mRebufferingWatermarkHighMs;
+
+    // When cached data is below this mark, playback will be paused for buffering
+    // till data reach |mRebufferingWatermarkHighKB| or end of stream.
+    int mRebufferingWatermarkLowKB;
+    // When cached data is above this mark, buffering will be paused.
+    int mRebufferingWatermarkHighKB;
+
+    BufferingSettings();
+
+    status_t writeToParcel(Parcel* parcel) const override;
+    status_t readFromParcel(const Parcel* parcel) override;
+
+};
+
+} // namespace android
+
+// ---------------------------------------------------------------------------
+
+#endif // ANDROID_BUFFERING_SETTINGS_H
diff --git a/include/media/IMediaAnalyticsService.h b/include/media/IMediaAnalyticsService.h
new file mode 100644
index 0000000..21da6ad
--- /dev/null
+++ b/include/media/IMediaAnalyticsService.h
@@ -0,0 +1,76 @@
+/*
+ * 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_IMEDIAANALYTICSSERVICE_H
+#define ANDROID_IMEDIAANALYTICSSERVICE_H
+
+#include <utils/String8.h>
+#include <binder/IInterface.h>
+#include <binder/Parcel.h>
+
+#include <sys/types.h>
+#include <utils/Errors.h>
+#include <utils/Log.h>
+#include <utils/RefBase.h>
+#include <utils/List.h>
+
+#include <binder/IServiceManager.h>
+
+#include <media/MediaAnalyticsItem.h>
+// nope...#include <media/MediaAnalytics.h>
+
+namespace android {
+
+class IMediaAnalyticsService: public IInterface
+{
+public:
+    DECLARE_META_INTERFACE(MediaAnalyticsService);
+
+    // generate a unique sessionID to use across multiple requests
+    // 'unique' is within this device, since last reboot
+    virtual MediaAnalyticsItem::SessionID_t generateUniqueSessionID() = 0;
+
+    // submit the indicated record to the mediaanalytics service, where
+    // it will be merged (if appropriate) with incomplete records that
+    // share the same key and sessionid.
+    // 'forcenew' marks any matching incomplete record as complete before
+    // inserting this new record.
+    // returns the sessionID associated with that item.
+    virtual MediaAnalyticsItem::SessionID_t submit(sp<MediaAnalyticsItem> item, bool forcenew) = 0;
+
+
+    // return lists of records that match the supplied parameters.
+    // finished [or not] records since time 'ts' with key 'key'
+    // timestamp 'ts' is nanoseconds, unix time.
+    virtual List<sp<MediaAnalyticsItem>> *getMediaAnalyticsItemList(bool finished, int64_t ts) = 0;
+    virtual List<sp<MediaAnalyticsItem>> *getMediaAnalyticsItemList(bool finished, int64_t ts, MediaAnalyticsItem::Key key) = 0;
+
+};
+
+// ----------------------------------------------------------------------------
+
+class BnMediaAnalyticsService: public BnInterface<IMediaAnalyticsService>
+{
+public:
+    virtual status_t    onTransact( uint32_t code,
+                                    const Parcel& data,
+                                    Parcel* reply,
+                                    uint32_t flags = 0);
+};
+
+}; // namespace android
+
+#endif // ANDROID_IMEDIASTATISTICSSERVICE_H
diff --git a/include/media/IMediaPlayer.h b/include/media/IMediaPlayer.h
index 99ef59f..f642373 100644
--- a/include/media/IMediaPlayer.h
+++ b/include/media/IMediaPlayer.h
@@ -39,6 +39,7 @@
 struct IMediaHTTPService;
 struct AudioPlaybackRate;
 struct AVSyncSettings;
+struct BufferingSettings;
 
 typedef IMediaSource::ReadOptions::SeekMode MediaPlayerSeekMode;
 
@@ -59,6 +60,9 @@
     virtual status_t        setDataSource(const sp<IDataSource>& source) = 0;
     virtual status_t        setVideoSurfaceTexture(
                                     const sp<IGraphicBufferProducer>& bufferProducer) = 0;
+    virtual status_t        getDefaultBufferingSettings(
+                                    BufferingSettings* buffering /* nonnull */) = 0;
+    virtual status_t        setBufferingSettings(const BufferingSettings& buffering) = 0;
     virtual status_t        prepareAsync() = 0;
     virtual status_t        start() = 0;
     virtual status_t        stop() = 0;
diff --git a/include/media/MediaAnalyticsItem.h b/include/media/MediaAnalyticsItem.h
new file mode 100644
index 0000000..73c9dd4
--- /dev/null
+++ b/include/media/MediaAnalyticsItem.h
@@ -0,0 +1,218 @@
+/*
+ * 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_MEDIA_MEDIAANALYTICSITEM_H
+#define ANDROID_MEDIA_MEDIAANALYTICSITEM_H
+
+#include <cutils/properties.h>
+#include <sys/types.h>
+#include <utils/Errors.h>
+#include <utils/KeyedVector.h>
+#include <utils/RefBase.h>
+#include <utils/StrongPointer.h>
+#include <utils/Timers.h>
+
+#include <media/stagefright/foundation/AString.h>
+
+namespace android {
+
+
+
+class IMediaAnalyticsService;
+
+// the class interface
+//
+
+class MediaAnalyticsItem : public RefBase {
+
+    friend class MediaAnalyticsService;
+    friend class IMediaAnalyticsService;
+
+    public:
+
+        // sessionid
+        // unique within device, within boot,
+        typedef int64_t SessionID_t;
+        static constexpr SessionID_t SessionIDInvalid = -1;
+        static constexpr SessionID_t SessionIDNone = 0;
+
+        // Key: the record descriminator
+        // values for the record discriminator
+        // values can be "component/component"
+        // basic values: "video", "audio", "drm"
+        // XXX: need to better define the format
+        typedef AString Key;
+        static const Key kKeyNone;              // ""
+        static const Key kKeyAny;               // "*"
+
+        // Attr: names for attributes within a record
+        // format "prop1" or "prop/subprop"
+        // XXX: need to better define the format
+        typedef AString Attr;
+
+
+    public:
+
+        // access functions for the class
+        MediaAnalyticsItem();
+        MediaAnalyticsItem(Key);
+        ~MediaAnalyticsItem();
+
+        // so clients can send intermediate values to be overlaid later
+        MediaAnalyticsItem &setFinalized(bool);
+        bool getFinalized() const;
+
+        // SessionID ties multiple submissions for same key together
+        // so that if video "height" and "width" are known at one point
+        // and "framerate" is only known later, they can be be brought
+        // together.
+        MediaAnalyticsItem &setSessionID(SessionID_t);
+        MediaAnalyticsItem &clearSessionID();
+        SessionID_t getSessionID() const;
+        // generates and stores a new ID iff mSessionID == SessionIDNone
+        SessionID_t generateSessionID();
+
+        // reset all contents, discarding any extra data
+        void clear();
+
+        // set the key discriminator for the record.
+        // most often initialized as part of the constructor
+        MediaAnalyticsItem &setKey(MediaAnalyticsItem::Key);
+        MediaAnalyticsItem::Key getKey();
+
+        // # of attributes in the record
+        int32_t count() const;
+
+        // set values appropriately
+        // return values tell us whether we overwrote an existing value
+        bool setInt32(Attr, int32_t value);
+        bool setInt64(Attr, int64_t value);
+        bool setDouble(Attr, double value);
+        bool setCString(Attr, const char *value);
+
+        // fused get/add/set; if attr wasn't there, it's a simple set.
+        // type-mismatch counts as "wasn't there".
+        // return value tells us whether we overwrote an existing value
+        bool addInt32(Attr, int32_t value);
+        bool addInt64(Attr, int64_t value);
+        bool addDouble(Attr, double value);
+
+        // find & extract values
+        // return indicates whether attr exists (and thus value filled in)
+        bool getInt32(Attr, int32_t *value);
+        bool getInt64(Attr, int64_t *value);
+        bool getDouble(Attr, double *value);
+        bool getCString(Attr, char **value);
+
+        // parameter indicates whether to close any existing open
+        // record with same key before establishing a new record
+        bool selfrecord(bool);
+        bool selfrecord();
+
+        // remove indicated attributes and their values
+        // filterNot() could also be called keepOnly()
+        // return value is # attributes removed
+        // XXX: perhaps 'remove' instead of 'filter'
+        // XXX: filterNot would become 'keep'
+        int32_t filter(int count, Attr attrs[]);
+        int32_t filterNot(int count, Attr attrs[]);
+        int32_t filter(Attr attr);
+
+        // below here are used on server side or to talk to server
+        // clients need not worry about these.
+
+        // timestamp, pid, and uid only used on server side
+	// timestamp is in 'nanoseconds, unix time'
+        MediaAnalyticsItem &setTimestamp(nsecs_t);
+        nsecs_t getTimestamp() const;
+
+        MediaAnalyticsItem &setPid(pid_t);
+        pid_t getPid() const;
+
+        MediaAnalyticsItem &setUid(uid_t);
+        uid_t getUid() const;
+
+        // our serialization code for binder calls
+        int32_t writeToParcel(Parcel *);
+        int32_t readFromParcel(const Parcel&);
+
+        AString toString();
+
+        // are we collecting analytics data
+        static bool isEnabled();
+
+    protected:
+
+        // merge fields from arg into this
+        // with rules for first/last/add, etc
+        // XXX: document semantics and how they are indicated
+        bool merge(sp<MediaAnalyticsItem> );
+
+        // enabled 1, disabled 0
+        static const char * const EnabledProperty;
+        static const char * const EnabledPropertyPersist;
+        static const int   EnabledProperty_default;
+
+    private:
+
+        // to help validate that A doesn't mess with B's records
+        pid_t     mPid;
+        uid_t     mUid;
+
+        // let's reuse a binder connection
+        static sp<IMediaAnalyticsService> sAnalyticsService;
+        static sp<IMediaAnalyticsService> getInstance();
+
+        // tracking information
+        SessionID_t mSessionID;         // grouping similar records
+        nsecs_t mTimestamp;             // ns, system_time_monotonic
+
+        // will this record accept further updates
+        bool mFinalized;
+
+        Key mKey;
+
+        class Item : public RefBase {
+
+         public:
+
+            enum Type {
+                kTypeNone = 0,
+                kTypeInt32 = 1,
+                kTypeInt64 = 2,
+                kTypeDouble = 3,
+                kTypeCString = 4,
+            };
+
+            Item();
+            ~Item();
+            void clear();
+
+            Type mType;
+            union {
+                    int32_t int32Value;
+                    int64_t int64Value;
+                    double doubleValue;
+                    char *CStringValue;
+            } u;
+        };
+        KeyedVector<Attr, sp<Item>> mItems;
+
+};
+
+} // namespace android
+
+#endif
diff --git a/include/media/MediaDefs.h b/include/media/MediaDefs.h
index 5f2a32d..0682413 100644
--- a/include/media/MediaDefs.h
+++ b/include/media/MediaDefs.h
@@ -59,8 +59,6 @@
 extern const char *MEDIA_MIMETYPE_CONTAINER_AVI;
 extern const char *MEDIA_MIMETYPE_CONTAINER_MPEG2PS;
 
-extern const char *MEDIA_MIMETYPE_CONTAINER_WVM;
-
 extern const char *MEDIA_MIMETYPE_TEXT_3GPP;
 extern const char *MEDIA_MIMETYPE_TEXT_SUBRIP;
 extern const char *MEDIA_MIMETYPE_TEXT_VTT;
diff --git a/include/media/MediaPlayerInterface.h b/include/media/MediaPlayerInterface.h
index 4e4878a..0e815cb 100644
--- a/include/media/MediaPlayerInterface.h
+++ b/include/media/MediaPlayerInterface.h
@@ -30,6 +30,7 @@
 #include <media/AudioSystem.h>
 #include <media/AudioTimestamp.h>
 #include <media/AVSyncSettings.h>
+#include <media/BufferingSettings.h>
 #include <media/Metadata.h>
 
 // Fwd decl to make sure everyone agrees that the scope of struct sockaddr_in is
@@ -174,6 +175,15 @@
     virtual status_t    setVideoSurfaceTexture(
                                 const sp<IGraphicBufferProducer>& bufferProducer) = 0;
 
+    virtual status_t    getDefaultBufferingSettings(
+                                BufferingSettings* buffering /* nonnull */) {
+        *buffering = BufferingSettings();
+        return OK;
+    }
+    virtual status_t    setBufferingSettings(const BufferingSettings& /* buffering */) {
+        return OK;
+    }
+
     virtual status_t    prepare() = 0;
     virtual status_t    prepareAsync() = 0;
     virtual status_t    start() = 0;
diff --git a/include/media/audiohal/DevicesFactoryHalInterface.h b/include/media/audiohal/DevicesFactoryHalInterface.h
index 823a0da..14af384 100644
--- a/include/media/audiohal/DevicesFactoryHalInterface.h
+++ b/include/media/audiohal/DevicesFactoryHalInterface.h
@@ -26,8 +26,6 @@
 class DevicesFactoryHalInterface : public RefBase
 {
   public:
-    virtual ~DevicesFactoryHalInterface() {}
-
     // Opens a device with the specified name. To close the device, it is
     // necessary to release references to the returned object.
     virtual status_t openDevice(const char *name, sp<DeviceHalInterface> *device) = 0;
@@ -37,6 +35,8 @@
   protected:
     // Subclasses can not be constructed directly by clients.
     DevicesFactoryHalInterface() {}
+
+    virtual ~DevicesFactoryHalInterface() {}
 };
 
 } // namespace android
diff --git a/include/media/stagefright/ACodec.h b/include/media/stagefright/ACodec.h
index 8fc2809..cde188c 100644
--- a/include/media/stagefright/ACodec.h
+++ b/include/media/stagefright/ACodec.h
@@ -35,6 +35,7 @@
 namespace android {
 
 struct ABuffer;
+class ACodecBufferChannel;
 class MediaCodecBuffer;
 struct MemoryDealer;
 struct DescribeColorFormat2Params;
@@ -43,10 +44,9 @@
 struct ACodec : public AHierarchicalStateMachine, public CodecBase {
     ACodec();
 
-    virtual void setNotificationMessage(const sp<AMessage> &msg);
-
     void initiateSetup(const sp<AMessage> &msg);
 
+    virtual std::shared_ptr<BufferChannelBase> getBufferChannel() override;
     virtual void initiateAllocateComponent(const sp<AMessage> &msg);
     virtual void initiateConfigureComponent(const sp<AMessage> &msg);
     virtual void initiateCreateInputSurface();
@@ -72,23 +72,6 @@
         handleMessage(msg);
     }
 
-    struct PortDescription : public CodecBase::PortDescription {
-        size_t countBuffers();
-        IOMX::buffer_id bufferIDAt(size_t index) const;
-        sp<MediaCodecBuffer> bufferAt(size_t index) const;
-
-    private:
-        friend struct ACodec;
-
-        Vector<IOMX::buffer_id> mBufferIDs;
-        Vector<sp<MediaCodecBuffer> > mBuffers;
-
-        PortDescription();
-        void addBuffer(IOMX::buffer_id id, const sp<MediaCodecBuffer> &buffer);
-
-        DISALLOW_EVIL_CONSTRUCTORS(PortDescription);
-    };
-
     // Returns 0 if configuration is not supported.  NOTE: this is treated by
     // some OMX components as auto level, and by others as invalid level.
     static int /* OMX_VIDEO_AVCLEVELTYPE */ getAVCLevelFor(
@@ -188,6 +171,7 @@
         sp<RefBase> mCodecRef;            // and a reference to the IMemory
 
         sp<GraphicBuffer> mGraphicBuffer;
+        bool mNewGraphicBuffer;
         int mFenceFd;
         FrameRenderTracker::Info *mRenderInfo;
 
@@ -217,8 +201,6 @@
     KeyedVector<int64_t, BufferStats> mBufferStats;
 #endif
 
-    sp<AMessage> mNotify;
-
     sp<UninitializedState> mUninitializedState;
     sp<LoadedState> mLoadedState;
     sp<LoadedToIdleState> mLoadedToIdleState;
@@ -295,6 +277,8 @@
     OMX_INDEXTYPE mDescribeColorAspectsIndex;
     OMX_INDEXTYPE mDescribeHDRStaticInfoIndex;
 
+    std::shared_ptr<ACodecBufferChannel> mBufferChannel;
+
     status_t setCyclicIntraMacroblockRefresh(const sp<AMessage> &msg, int32_t mode);
     status_t allocateBuffersOnPort(OMX_U32 portIndex);
     status_t freeBuffersOnPort(OMX_U32 portIndex);
diff --git a/include/media/stagefright/CodecBase.h b/include/media/stagefright/CodecBase.h
index 39a9089..52daa9e 100644
--- a/include/media/stagefright/CodecBase.h
+++ b/include/media/stagefright/CodecBase.h
@@ -18,12 +18,16 @@
 
 #define CODEC_BASE_H_
 
+#include <memory>
+
 #include <stdint.h>
 
 #define STRINGIFY_ENUMS
 
+#include <media/ICrypto.h>
 #include <media/IOMX.h>
 #include <media/MediaCodecInfo.h>
+#include <media/stagefright/MediaErrors.h>
 #include <media/stagefright/foundation/AHandler.h>
 #include <media/stagefright/foundation/ColorUtils.h>
 #include <media/hardware/HardwareAPI.h>
@@ -34,33 +38,164 @@
 
 namespace android {
 
+class BufferChannelBase;
+class BufferProducerWrapper;
 class MediaCodecBuffer;
 struct PersistentSurface;
+struct RenderedFrameInfo;
 class Surface;
 
 struct CodecBase : public AHandler, /* static */ ColorUtils {
-    enum {
-        kWhatFillThisBuffer      = 'fill',
-        kWhatDrainThisBuffer     = 'drai',
-        kWhatEOS                 = 'eos ',
-        kWhatStopCompleted       = 'scom',
-        kWhatReleaseCompleted    = 'rcom',
-        kWhatFlushCompleted      = 'fcom',
-        kWhatError               = 'erro',
-        kWhatComponentAllocated  = 'cAll',
-        kWhatComponentConfigured = 'cCon',
-        kWhatInputSurfaceCreated = 'isfc',
-        kWhatInputSurfaceAccepted = 'isfa',
-        kWhatSignaledInputEOS    = 'seos',
-        kWhatBuffersAllocated    = 'allc',
-        kWhatOutputFramesRendered = 'outR',
+    /**
+     * This interface defines events firing from CodecBase back to MediaCodec.
+     * All methods must not block.
+     */
+    class CodecCallback {
+    public:
+        virtual ~CodecCallback() = default;
+
+        /**
+         * Notify MediaCodec for seeing an output EOS.
+         *
+         * @param err the underlying cause of the EOS. If the value is neither
+         *            OK nor ERROR_END_OF_STREAM, the EOS is declared
+         *            prematurely for that error.
+         */
+        virtual void onEos(status_t err) = 0;
+        /**
+         * Notify MediaCodec that start operation is complete.
+         */
+        virtual void onStartCompleted() = 0;
+        /**
+         * Notify MediaCodec that stop operation is complete.
+         */
+        virtual void onStopCompleted() = 0;
+        /**
+         * Notify MediaCodec that release operation is complete.
+         */
+        virtual void onReleaseCompleted() = 0;
+        /**
+         * Notify MediaCodec that flush operation is complete.
+         */
+        virtual void onFlushCompleted() = 0;
+        /**
+         * Notify MediaCodec that an error is occurred.
+         *
+         * @param err         an error code for the occurred error.
+         * @param actionCode  an action code for severity of the error.
+         */
+        virtual void onError(status_t err, enum ActionCode actionCode) = 0;
+        /**
+         * Notify MediaCodec that the underlying component is allocated.
+         *
+         * @param componentName the unique name of the component specified in
+         *                      MediaCodecList.
+         */
+        virtual void onComponentAllocated(const char *componentName) = 0;
+        /**
+         * Notify MediaCodec that the underlying component is configured.
+         *
+         * @param inputFormat   an input format at configure time.
+         * @param outputFormat  an output format at configure time.
+         */
+        virtual void onComponentConfigured(
+                const sp<AMessage> &inputFormat, const sp<AMessage> &outputFormat) = 0;
+        /**
+         * Notify MediaCodec that the input surface is created.
+         *
+         * @param inputFormat   an input format at surface creation. Formats
+         *                      could change from the previous state as a result
+         *                      of creating a surface.
+         * @param outputFormat  an output format at surface creation.
+         * @param inputSurface  the created surface.
+         */
+        virtual void onInputSurfaceCreated(
+                const sp<AMessage> &inputFormat,
+                const sp<AMessage> &outputFormat,
+                const sp<BufferProducerWrapper> &inputSurface) = 0;
+        /**
+         * Notify MediaCodec that the input surface creation is failed.
+         *
+         * @param err an error code of the cause.
+         */
+        virtual void onInputSurfaceCreationFailed(status_t err) = 0;
+        /**
+         * Notify MediaCodec that the component accepted the provided input
+         * surface.
+         *
+         * @param inputFormat   an input format at surface assignment. Formats
+         *                      could change from the previous state as a result
+         *                      of assigning a surface.
+         * @param outputFormat  an output format at surface assignment.
+         */
+        virtual void onInputSurfaceAccepted(
+                const sp<AMessage> &inputFormat,
+                const sp<AMessage> &outputFormat) = 0;
+        /**
+         * Notify MediaCodec that the component declined the provided input
+         * surface.
+         *
+         * @param err an error code of the cause.
+         */
+        virtual void onInputSurfaceDeclined(status_t err) = 0;
+        /**
+         * Noitfy MediaCodec that the requested input EOS is sent to the input
+         * surface.
+         *
+         * @param err an error code returned from the surface. If there is no
+         *            input surface, the value is INVALID_OPERATION.
+         */
+        virtual void onSignaledInputEOS(status_t err) = 0;
+        /**
+         * Notify MediaCodec that output frames are rendered with information on
+         * those frames.
+         *
+         * @param done  a list of rendered frames.
+         */
+        virtual void onOutputFramesRendered(const std::list<RenderedFrameInfo> &done) = 0;
+        /**
+         * Notify MediaCodec that output buffers are changed.
+         */
+        virtual void onOutputBuffersChanged() = 0;
     };
 
+    /**
+     * This interface defines events firing from BufferChannelBase back to MediaCodec.
+     * All methods must not block.
+     */
+    class BufferCallback {
+    public:
+        virtual ~BufferCallback() = default;
+
+        /**
+         * Notify MediaCodec that an input buffer is available with given index.
+         * When BufferChannelBase::getInputBufferArray() is not called,
+         * BufferChannelBase may report different buffers with the same index if
+         * MediaCodec already queued/discarded the buffer. After calling
+         * BufferChannelBase::getInputBufferArray(), the buffer and index match the
+         * returned array.
+         */
+        virtual void onInputBufferAvailable(
+                size_t index, const sp<MediaCodecBuffer> &buffer) = 0;
+        /**
+         * Notify MediaCodec that an output buffer is available with given index.
+         * When BufferChannelBase::getOutputBufferArray() is not called,
+         * BufferChannelBase may report different buffers with the same index if
+         * MediaCodec already queued/discarded the buffer. After calling
+         * BufferChannelBase::getOutputBufferArray(), the buffer and index match the
+         * returned array.
+         */
+        virtual void onOutputBufferAvailable(
+                size_t index, const sp<MediaCodecBuffer> &buffer) = 0;
+    };
     enum {
         kMaxCodecBufferSize = 8192 * 4096 * 4, // 8K RGBA
     };
 
-    virtual void setNotificationMessage(const sp<AMessage> &msg) = 0;
+    inline void setCallback(std::unique_ptr<CodecCallback> &&callback) {
+        mCallback = std::move(callback);
+    }
+    virtual std::shared_ptr<BufferChannelBase> getBufferChannel() = 0;
 
     virtual void initiateAllocateComponent(const sp<AMessage> &msg) = 0;
     virtual void initiateConfigureComponent(const sp<AMessage> &msg) = 0;
@@ -86,31 +221,104 @@
     virtual void signalSetParameters(const sp<AMessage> &msg) = 0;
     virtual void signalEndOfInputStream() = 0;
 
-    struct PortDescription : public RefBase {
-        virtual size_t countBuffers() = 0;
-        virtual IOMX::buffer_id bufferIDAt(size_t index) const = 0;
-        virtual sp<MediaCodecBuffer> bufferAt(size_t index) const = 0;
-
-    protected:
-        PortDescription();
-        virtual ~PortDescription();
-
-    private:
-        DISALLOW_EVIL_CONSTRUCTORS(PortDescription);
-    };
-
     /*
      * Codec-related defines
      */
 
 protected:
-    CodecBase();
-    virtual ~CodecBase();
+    CodecBase() = default;
+    virtual ~CodecBase() = default;
+
+    std::unique_ptr<CodecCallback> mCallback;
 
 private:
     DISALLOW_EVIL_CONSTRUCTORS(CodecBase);
 };
 
+/**
+ * A channel between MediaCodec and CodecBase object which manages buffer
+ * passing. Only MediaCodec is expected to call these methods, and
+ * underlying CodecBase implementation should define its own interface
+ * separately for itself.
+ *
+ * Concurrency assumptions:
+ *
+ * 1) Clients may access the object at multiple threads concurrently.
+ * 2) All methods do not call underlying CodecBase object while holding a lock.
+ * 3) Code inside critical section executes within 1ms.
+ */
+class BufferChannelBase {
+public:
+    virtual ~BufferChannelBase() = default;
+
+    inline void setCallback(std::unique_ptr<CodecBase::BufferCallback> &&callback) {
+        mCallback = std::move(callback);
+    }
+
+    inline void setCrypto(const sp<ICrypto> &crypto) {
+        mCrypto = crypto;
+    }
+
+    /**
+     * Queue an input buffer into the buffer channel.
+     *
+     * @return    OK if successful;
+     *            -ENOENT if the buffer is not known (TODO: this should be
+     *            handled gracefully in the future, here and below).
+     */
+    virtual status_t queueInputBuffer(const sp<MediaCodecBuffer> &buffer) = 0;
+    /**
+     * Queue a secure input buffer into the buffer channel.
+     *
+     * @return    OK if successful;
+     *            -ENOENT if the buffer is not known;
+     *            -ENOSYS if mCrypto is not set so that decryption is not
+     *            possible;
+     *            other errors if decryption failed.
+     */
+    virtual status_t queueSecureInputBuffer(
+            const sp<MediaCodecBuffer> &buffer,
+            bool secure,
+            const uint8_t *key,
+            const uint8_t *iv,
+            CryptoPlugin::Mode mode,
+            CryptoPlugin::Pattern pattern,
+            const CryptoPlugin::SubSample *subSamples,
+            size_t numSubSamples,
+            AString *errorDetailMsg) = 0;
+    /**
+     * Request buffer rendering at specified time.
+     *
+     * @param     timestampNs   nanosecond timestamp for rendering time.
+     * @return    OK if successful;
+     *            -ENOENT if the buffer is not known.
+     */
+    virtual status_t renderOutputBuffer(
+            const sp<MediaCodecBuffer> &buffer, int64_t timestampNs) = 0;
+    /**
+     * Discard a buffer to the underlying CodecBase object.
+     *
+     * TODO: remove once this operation can be handled by just clearing the
+     * reference.
+     *
+     * @return    OK if successful;
+     *            -ENOENT if the buffer is not known.
+     */
+    virtual status_t discardBuffer(const sp<MediaCodecBuffer> &buffer) = 0;
+    /**
+     * Clear and fill array with input buffers.
+     */
+    virtual void getInputBufferArray(Vector<sp<MediaCodecBuffer>> *array) = 0;
+    /**
+     * Clear and fill array with output buffers.
+     */
+    virtual void getOutputBufferArray(Vector<sp<MediaCodecBuffer>> *array) = 0;
+
+protected:
+    std::unique_ptr<CodecBase::BufferCallback> mCallback;
+    sp<ICrypto> mCrypto;
+};
+
 }  // namespace android
 
 #endif  // CODEC_BASE_H_
diff --git a/include/media/stagefright/DataSource.h b/include/media/stagefright/DataSource.h
index 0254545..a8dcbe0 100644
--- a/include/media/stagefright/DataSource.h
+++ b/include/media/stagefright/DataSource.h
@@ -44,6 +44,7 @@
         kStreamedFromLocalHost = 2,
         kIsCachingDataSource   = 4,
         kIsHTTPBasedSource     = 8,
+        kIsLocalFileSource     = 16,
     };
 
     static sp<DataSource> CreateFromURI(
@@ -102,17 +103,6 @@
 
     ////////////////////////////////////////////////////////////////////////////
 
-    bool sniff(String8 *mimeType, float *confidence, sp<AMessage> *meta);
-
-    // The sniffer can optionally fill in "meta" with an AMessage containing
-    // a dictionary of values that helps the corresponding extractor initialize
-    // its state without duplicating effort already exerted by the sniffer.
-    typedef bool (*SnifferFunc)(
-            const sp<DataSource> &source, String8 *mimeType,
-            float *confidence, sp<AMessage> *meta);
-
-    static void RegisterDefaultSniffers();
-
     // for DRM
     virtual sp<DecryptHandle> DrmInitialization(const char *mime = NULL) {
         return NULL;
@@ -131,12 +121,6 @@
     virtual ~DataSource() {}
 
 private:
-    static Mutex gSnifferMutex;
-    static List<SnifferFunc> gSniffers;
-    static bool gSniffersRegistered;
-
-    static void RegisterSniffer_l(SnifferFunc func);
-
     DataSource(const DataSource &);
     DataSource &operator=(const DataSource &);
 };
diff --git a/include/media/stagefright/FileSource.h b/include/media/stagefright/FileSource.h
index b6349e0..9f3bb5e 100644
--- a/include/media/stagefright/FileSource.h
+++ b/include/media/stagefright/FileSource.h
@@ -39,6 +39,10 @@
 
     virtual status_t getSize(off64_t *size);
 
+    virtual uint32_t flags() {
+        return kIsLocalFileSource;
+    }
+
     virtual sp<DecryptHandle> DrmInitialization(const char *mime);
 
     virtual void getDrmInfo(sp<DecryptHandle> &handle, DrmManagerClient **client);
diff --git a/include/media/stagefright/FrameRenderTracker.h b/include/media/stagefright/FrameRenderTracker.h
index 8396657..6c572b8 100644
--- a/include/media/stagefright/FrameRenderTracker.h
+++ b/include/media/stagefright/FrameRenderTracker.h
@@ -32,58 +32,61 @@
 class Fence;
 class GraphicBuffer;
 
+// Tracks the render information about a frame. Frames go through several states while
+// the render information is tracked:
+//
+// 1. queued frame: mMediaTime and mGraphicBuffer are set for the frame. mFence is the
+// queue fence (read fence). mIndex is negative, and mRenderTimeNs is invalid.
+// Key characteristics: mFence is not NULL and mIndex is negative.
+//
+// 2. dequeued frame: mFence is updated with the dequeue fence (write fence). mIndex is set.
+// Key characteristics: mFence is not NULL and mIndex is non-negative. mRenderTime is still
+// invalid.
+//
+// 3. rendered frame or frame: mFence is cleared, mRenderTimeNs is set.
+// Key characteristics: mFence is NULL.
+//
+struct RenderedFrameInfo {
+    // set by client during onFrameQueued or onFrameRendered
+    int64_t getMediaTimeUs() const  { return mMediaTimeUs; }
+
+    // -1 if frame is not yet rendered
+    nsecs_t getRenderTimeNs() const { return mRenderTimeNs; }
+
+    // set by client during updateRenderInfoForDequeuedBuffer; -1 otherwise
+    ssize_t getIndex() const        { return mIndex; }
+
+    // creates information for a queued frame
+    RenderedFrameInfo(int64_t mediaTimeUs, const sp<GraphicBuffer> &graphicBuffer,
+            const sp<Fence> &fence)
+        : mMediaTimeUs(mediaTimeUs),
+          mRenderTimeNs(-1),
+          mIndex(-1),
+          mGraphicBuffer(graphicBuffer),
+          mFence(fence) {
+    }
+
+    // creates information for a frame rendered on a tunneled surface
+    RenderedFrameInfo(int64_t mediaTimeUs, nsecs_t renderTimeNs)
+        : mMediaTimeUs(mediaTimeUs),
+          mRenderTimeNs(renderTimeNs),
+          mIndex(-1),
+          mGraphicBuffer(NULL),
+          mFence(NULL) {
+    }
+
+private:
+    int64_t mMediaTimeUs;
+    nsecs_t mRenderTimeNs;
+    ssize_t mIndex;         // to be used by client
+    sp<GraphicBuffer> mGraphicBuffer;
+    sp<Fence> mFence;
+
+    friend class FrameRenderTracker;
+};
+
 struct FrameRenderTracker {
-    // Tracks the render information about a frame. Frames go through several states while
-    // the render information is tracked:
-    //
-    // 1. queued frame: mMediaTime and mGraphicBuffer are set for the frame. mFence is the
-    // queue fence (read fence). mIndex is negative, and mRenderTimeNs is invalid.
-    // Key characteristics: mFence is not NULL and mIndex is negative.
-    //
-    // 2. dequeued frame: mFence is updated with the dequeue fence (write fence). mIndex is set.
-    // Key characteristics: mFence is not NULL and mIndex is non-negative. mRenderTime is still
-    // invalid.
-    //
-    // 3. rendered frame or frame: mFence is cleared, mRenderTimeNs is set.
-    // Key characteristics: mFence is NULL.
-    //
-    struct Info {
-        // set by client during onFrameQueued or onFrameRendered
-        int64_t getMediaTimeUs() const  { return mMediaTimeUs; }
-
-        // -1 if frame is not yet rendered
-        nsecs_t getRenderTimeNs() const { return mRenderTimeNs; }
-
-        // set by client during updateRenderInfoForDequeuedBuffer; -1 otherwise
-        ssize_t getIndex() const        { return mIndex; }
-
-        // creates information for a queued frame
-        Info(int64_t mediaTimeUs, const sp<GraphicBuffer> &graphicBuffer, const sp<Fence> &fence)
-            : mMediaTimeUs(mediaTimeUs),
-              mRenderTimeNs(-1),
-              mIndex(-1),
-              mGraphicBuffer(graphicBuffer),
-              mFence(fence) {
-        }
-
-        // creates information for a frame rendered on a tunneled surface
-        Info(int64_t mediaTimeUs, nsecs_t renderTimeNs)
-            : mMediaTimeUs(mediaTimeUs),
-              mRenderTimeNs(renderTimeNs),
-              mIndex(-1),
-              mGraphicBuffer(NULL),
-              mFence(NULL) {
-        }
-
-    private:
-        int64_t mMediaTimeUs;
-        nsecs_t mRenderTimeNs;
-        ssize_t mIndex;         // to be used by client
-        sp<GraphicBuffer> mGraphicBuffer;
-        sp<Fence> mFence;
-
-        friend class FrameRenderTracker;
-    };
+    typedef RenderedFrameInfo Info;
 
     FrameRenderTracker();
 
diff --git a/include/media/stagefright/MediaCodec.h b/include/media/stagefright/MediaCodec.h
index 89def5d..50fb312 100644
--- a/include/media/stagefright/MediaCodec.h
+++ b/include/media/stagefright/MediaCodec.h
@@ -18,6 +18,9 @@
 
 #define MEDIA_CODEC_H_
 
+#include <memory>
+#include <vector>
+
 #include <gui/IGraphicBufferProducer.h>
 #include <media/hardware/CryptoAPI.h>
 #include <media/MediaCodecInfo.h>
@@ -32,12 +35,12 @@
 struct AMessage;
 struct AReplyToken;
 struct AString;
+class BufferChannelBase;
 struct CodecBase;
 class IBatteryStats;
 struct ICrypto;
 class MediaCodecBuffer;
 class IMemory;
-struct MemoryDealer;
 class IResourceManagerClient;
 class IResourceManagerService;
 struct PersistentSurface;
@@ -151,8 +154,6 @@
     status_t getOutputFormat(sp<AMessage> *format) const;
     status_t getInputFormat(sp<AMessage> *format) const;
 
-    status_t getWidevineLegacyBuffers(Vector<sp<MediaCodecBuffer> > *buffers) const;
-
     status_t getInputBuffers(Vector<sp<MediaCodecBuffer> > *buffers) const;
     status_t getOutputBuffers(Vector<sp<MediaCodecBuffer> > *buffers) const;
 
@@ -254,11 +255,9 @@
     };
 
     struct BufferInfo {
-        uint32_t mBufferID;
+        BufferInfo();
+
         sp<MediaCodecBuffer> mData;
-        sp<MediaCodecBuffer> mSecureData;
-        sp<IMemory> mSharedEncryptedBuffer;
-        sp<AMessage> mNotify;
         bool mOwnedByClient;
     };
 
@@ -303,7 +302,6 @@
     sp<AMessage> mInputFormat;
     sp<AMessage> mCallback;
     sp<AMessage> mOnFrameRenderedNotification;
-    sp<MemoryDealer> mDealer;
 
     sp<IResourceManagerClient> mResourceManagerClient;
     sp<ResourceManagerServiceProxy> mResourceManagerService;
@@ -329,8 +327,7 @@
     Mutex mBufferLock;
 
     List<size_t> mAvailPortBuffers[2];
-    Vector<BufferInfo> mPortBuffers[2];
-    Vector<sp<MediaCodecBuffer>> mPortBufferArrays[2];
+    std::vector<BufferInfo> mPortBuffers[2];
 
     int32_t mDequeueInputTimeoutGeneration;
     sp<AReplyToken> mDequeueInputReplyID;
@@ -347,6 +344,8 @@
     bool mHaveInputSurface;
     bool mHavePendingInputBuffers;
 
+    std::shared_ptr<BufferChannelBase> mBufferChannel;
+
     MediaCodec(const sp<ALooper> &looper, pid_t pid, uid_t uid);
 
     static sp<CodecBase> GetCodecBase(const AString &name, bool nameIsType = false);
diff --git a/include/media/stagefright/MediaExtractor.h b/include/media/stagefright/MediaExtractor.h
index 6bf8c9e..e5ee72e 100644
--- a/include/media/stagefright/MediaExtractor.h
+++ b/include/media/stagefright/MediaExtractor.h
@@ -80,6 +80,24 @@
 private:
     bool mIsDrm;
 
+    typedef bool (*SnifferFunc)(
+            const sp<DataSource> &source, String8 *mimeType,
+            float *confidence, sp<AMessage> *meta);
+
+    static Mutex gSnifferMutex;
+    static List<SnifferFunc> gSniffers;
+    static bool gSniffersRegistered;
+
+    // The sniffer can optionally fill in "meta" with an AMessage containing
+    // a dictionary of values that helps the corresponding extractor initialize
+    // its state without duplicating effort already exerted by the sniffer.
+    static void RegisterSniffer_l(SnifferFunc func);
+
+    static bool sniff(const sp<DataSource> &source,
+            String8 *mimeType, float *confidence, sp<AMessage> *meta);
+
+    static void RegisterDefaultSniffers();
+
     MediaExtractor(const MediaExtractor &);
     MediaExtractor &operator=(const MediaExtractor &);
 };
diff --git a/include/media/stagefright/MediaFilter.h b/include/media/stagefright/MediaFilter.h
index 0e39431..0e4539b 100644
--- a/include/media/stagefright/MediaFilter.h
+++ b/include/media/stagefright/MediaFilter.h
@@ -21,6 +21,7 @@
 
 namespace android {
 
+class ACodecBufferChannel;
 struct GraphicBufferListener;
 struct MemoryDealer;
 struct SimpleFilter;
@@ -28,8 +29,7 @@
 struct MediaFilter : public CodecBase {
     MediaFilter();
 
-    virtual void setNotificationMessage(const sp<AMessage> &msg);
-
+    virtual std::shared_ptr<BufferChannelBase> getBufferChannel() override;
     virtual void initiateAllocateComponent(const sp<AMessage> &msg);
     virtual void initiateConfigureComponent(const sp<AMessage> &msg);
     virtual void initiateCreateInputSurface();
@@ -47,25 +47,6 @@
 
     virtual void onMessageReceived(const sp<AMessage> &msg);
 
-    struct PortDescription : public CodecBase::PortDescription {
-        virtual size_t countBuffers();
-        virtual IOMX::buffer_id bufferIDAt(size_t index) const;
-        virtual sp<MediaCodecBuffer> bufferAt(size_t index) const;
-
-    protected:
-        PortDescription();
-
-    private:
-        friend struct MediaFilter;
-
-        Vector<IOMX::buffer_id> mBufferIDs;
-        Vector<sp<MediaCodecBuffer> > mBuffers;
-
-        void addBuffer(IOMX::buffer_id id, const sp<MediaCodecBuffer> &buffer);
-
-        DISALLOW_EVIL_CONSTRUCTORS(PortDescription);
-    };
-
 protected:
     virtual ~MediaFilter();
 
@@ -120,7 +101,6 @@
     int32_t mColorFormatIn, mColorFormatOut;
     size_t mMaxInputSize, mMaxOutputSize;
     int32_t mGeneration;
-    sp<AMessage> mNotify;
     sp<AMessage> mInputFormat;
     sp<AMessage> mOutputFormat;
 
@@ -133,6 +113,8 @@
     sp<SimpleFilter> mFilter;
     sp<GraphicBufferListener> mGraphicBufferListener;
 
+    std::shared_ptr<ACodecBufferChannel> mBufferChannel;
+
     // helper functions
     void signalProcessBuffers();
     void signalError(status_t error);
diff --git a/include/media/stagefright/NuMediaExtractor.h b/include/media/stagefright/NuMediaExtractor.h
index 03e2185..a8aca5a 100644
--- a/include/media/stagefright/NuMediaExtractor.h
+++ b/include/media/stagefright/NuMediaExtractor.h
@@ -108,7 +108,6 @@
     sp<DataSource> mDataSource;
 
     sp<IMediaExtractor> mImpl;
-    bool mIsWidevineExtractor;
 
     Vector<TrackInfo> mSelectedTracks;
     int64_t mTotalBitrate;  // in bits/sec
diff --git a/include/media/stagefright/foundation/AData.h b/include/media/stagefright/foundation/AData.h
new file mode 100644
index 0000000..49aa0dc
--- /dev/null
+++ b/include/media/stagefright/foundation/AData.h
@@ -0,0 +1,843 @@
+/*
+ * 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_FOUNDATION_A_DATA_H_
+#define STAGEFRIGHT_FOUNDATION_A_DATA_H_
+
+#include <memory> // for std::shared_ptr, weak_ptr and unique_ptr
+#include <type_traits> // for std::aligned_union
+
+#include <utils/StrongPointer.h> // for android::sp and wp
+
+#include <media/stagefright/foundation/TypeTraits.h>
+#include <media/stagefright/foundation/Flagged.h>
+
+namespace android {
+
+/**
+ * AData is a flexible union type that supports non-POD members. It supports arbitrary types as long
+ * as they are either moveable or copyable.
+ *
+ * Internally, AData is using AUnion - a structure providing the union support. AUnion should not
+ * be used by generic code as it is very unsafe - it opens type aliasing errors where an object of
+ * one type can be easily accessed as an object of another type. AData prevents this.
+ *
+ * AData allows a custom type flagger to be used for future extensions (e.g. allowing automatic
+ * type conversion). A strict and a relaxed flagger are provided as internal types.
+ *
+ * Use as follows:
+ *
+ * AData<int, float>::Basic data; // strict type support
+ * int i = 1;
+ * float f = 7.0f;
+ *
+ * data.set(5);
+ * EXPECT_TRUE(data.find(&i));
+ * EXPECT_FALSE(data.find(&f));
+ * EXPECT_EQ(i, 5);
+ *
+ * data.set(6.0f);
+ * EXPECT_FALSE(data.find(&i));
+ * EXPECT_TRUE(data.find(&f));
+ * EXPECT_EQ(f, 6.0f);
+ *
+ * AData<int, sp<RefBase>>::RelaxedBasic objdata; // relaxed type support
+ * sp<ABuffer> buf = new ABuffer(16), buf2;
+ * sp<RefBase> obj;
+ *
+ * objdata.set(buf);
+ * EXPECT_TRUE(objdata.find(&buf2));
+ * EXPECT_EQ(buf, buf2);
+ * EXPECT_FALSE(objdata.find(&i));
+ * EXPECT_TRUE(objdata.find(&obj));
+ * EXPECT_TRUE(obj == buf);
+ *
+ * obj = buf;
+ * objdata.set(obj); // storing as sp<RefBase>
+ * EXPECT_FALSE(objdata.find(&buf2));  // not stored as ABuffer(!)
+ * EXPECT_TRUE(objdata.find(&obj));
+ */
+
+/// \cond Internal
+
+/**
+ * Helper class to call constructor and destructor for a specific type in AUnion.
+ * This class is needed as member function specialization is not allowed for a
+ * templated class.
+ */
+struct _AUnion_impl {
+    /**
+     * Calls placement constuctor for type T with arbitrary arguments for a storage at an address.
+     * Storage MUST be large enough to contain T.
+     * Also clears the slack space after type T. \todo This is not technically needed, so we may
+     * choose to do this just for debugging.
+     *
+     * \param totalSize size of the storage
+     * \param addr      pointer to where object T should be constructed
+     * \param args      arbitrary arguments for constructor
+     */
+    template<typename T, typename ...Args>
+    inline static void emplace(size_t totalSize, T *addr, Args&&... args) {
+        new(addr)T(std::forward<Args>(args)...);
+        // clear slack space - this is not technically required
+        constexpr size_t size = sizeof(T);
+        memset(reinterpret_cast<uint8_t*>(addr) + size, 0, totalSize - size);
+    }
+
+    /**
+     * Calls destuctor for an object of type T located at a specific address.
+     *
+     * \note we do not clear the storage in this case as the storage should not be used
+     * until another object is placed there, at which case the storage will be cleared.
+     *
+     * \param addr    pointer to where object T is stored
+     */
+    template<typename T>
+    inline static void del(T *addr) {
+        addr->~T();
+    }
+};
+
+/** Constructor specialization for void type */
+template<>
+inline void _AUnion_impl::emplace<void>(size_t totalSize, void *addr) {
+    memset(addr, 0, totalSize);
+}
+
+/** Destructor specialization for void type */
+template<>
+inline void _AUnion_impl::del<void>(void *) {
+}
+
+/// \endcond
+
+/**
+ * A templated union class that can contain specific types of data, and provides
+ * constructors, destructor and access methods strictly for those types.
+ *
+ * \note This class is VERY UNSAFE compared to a union, but it allows non-POD unions.
+ * In particular care must be taken that methods are called in a careful order to
+ * prevent accessing objects of one type as another type. This class provides no
+ * facilities to help with this ordering. This is meant to be wrapped by safer
+ * utility classes that do that.
+ *
+ * \param Ts types stored in this union.
+ */
+template<typename ...Ts>
+struct AUnion {
+private:
+    using _type = typename std::aligned_union<0, Ts...>::type; ///< storage type
+    _type mValue;                                              ///< storage
+
+public:
+    /**
+     * Constructs an object of type T with arbitrary arguments in this union. After this call,
+     * this union will contain this object.
+     *
+     * This method MUST be called only when either 1) no object or 2) a void object (equivalent to
+     * no object) is contained in this union.
+     *
+     * \param T     type of object to be constructed. This must be one of the template parameters of
+     *              the union class with the same cv-qualification, or void.
+     * \param args  arbitrary arguments for the constructor
+     */
+    template<
+            typename T, typename ...Args,
+            typename=typename std::enable_if<is_one_of<T, void, Ts...>::value>::type>
+    inline void emplace(Args&&... args) {
+        _AUnion_impl::emplace(
+                sizeof(_type), reinterpret_cast<T*>(&mValue), std::forward<Args>(args)...);
+    }
+
+    /**
+     * Destructs an object of type T in this union. After this call, this union will contain no
+     * object.
+     *
+     * This method MUST be called only when this union contains an object of type T.
+     *
+     * \param T     type of object to be destructed. This must be one of the template parameters of
+     *              the union class with the same cv-qualification, or void.
+     */
+    template<
+            typename T,
+            typename=typename std::enable_if<is_one_of<T, void, Ts...>::value>::type>
+    inline void del() {
+        _AUnion_impl::del(reinterpret_cast<T*>(&mValue));
+    }
+
+    /**
+     * Returns a const reference to the object of type T in this union.
+     *
+     * This method MUST be called only when this union contains an object of type T.
+     *
+     * \param T     type of object to be returned. This must be one of the template parameters of
+     *              the union class with the same cv-qualification.
+     */
+    template<
+            typename T,
+            typename=typename std::enable_if<is_one_of<T, Ts...>::value>::type>
+    inline const T &get() const {
+        return *reinterpret_cast<const T*>(&mValue);
+    }
+
+    /**
+     * Returns a reference to the object of type T in this union.
+     *
+     * This method MUST be called only when this union contains an object of type T.
+     *
+     * \param T     type of object to be returned. This must be one of the template parameters of
+     *              the union class with the same cv-qualification.
+     */
+    template<typename T>
+    inline T &get() {
+        return *reinterpret_cast<T*>(&mValue);
+    }
+};
+
+/**
+ * Helper utility class that copies an object of type T to a destination.
+ *
+ * T must be copy assignable or copy constructible.
+ *
+ * It provides:
+ *
+ * void assign(T*, const U&) // for copiable types - this leaves the source unchanged, hence const.
+ *
+ * \param T type of object to assign to
+ */
+template<
+        typename T,
+        bool=std::is_copy_assignable<T>::value>
+struct _AData_copier {
+    static_assert(std::is_copy_assignable<T>::value, "T must be copy assignable here");
+
+    /**
+     * Copies src to data without modifying data.
+     *
+     * \param data pointer to destination
+     * \param src source object
+     */
+    inline static void assign(T *data, const T &src) {
+        *data = src;
+    }
+
+    template<typename U>
+    using enable_if_T_is_same_as = typename std::enable_if<std::is_same<U, T>::value>::type;
+
+    /**
+     * Downcast specializations for sp<>, shared_ptr<> and weak_ptr<>
+     */
+    template<typename Tp, typename U, typename=enable_if_T_is_same_as<sp<Tp>>>
+    inline static void assign(sp<Tp> *data, const sp<U> &src) {
+        *data = static_cast<Tp*>(src.get());
+    }
+
+    template<typename Tp, typename U, typename=enable_if_T_is_same_as<wp<Tp>>>
+    inline static void assign(wp<Tp> *data, const wp<U> &src) {
+        sp<U> __tmp = src.promote();
+        *data = static_cast<Tp*>(__tmp.get());
+    }
+
+    template<typename Tp, typename U, typename=enable_if_T_is_same_as<sp<Tp>>>
+    inline static void assign(sp<Tp> *data, sp<U> &&src) {
+        sp<U> __tmp = std::move(src); // move src out as get cannot
+        *data = static_cast<Tp*>(__tmp.get());
+    }
+
+    template<typename Tp, typename U, typename=enable_if_T_is_same_as<std::shared_ptr<Tp>>>
+    inline static void assign(std::shared_ptr<Tp> *data, const std::shared_ptr<U> &src) {
+        *data = std::static_pointer_cast<Tp>(src);
+    }
+
+    template<typename Tp, typename U, typename=enable_if_T_is_same_as<std::shared_ptr<Tp>>>
+    inline static void assign(std::shared_ptr<Tp> *data, std::shared_ptr<U> &&src) {
+        std::shared_ptr<U> __tmp = std::move(src); // move src out as static_pointer_cast cannot
+        *data = std::static_pointer_cast<Tp>(__tmp);
+    }
+
+    template<typename Tp, typename U, typename=enable_if_T_is_same_as<std::weak_ptr<Tp>>>
+    inline static void assign(std::weak_ptr<Tp> *data, const std::weak_ptr<U> &src) {
+        *data = std::static_pointer_cast<Tp>(src.lock());
+    }
+
+    // shared_ptrs are implicitly convertible to weak_ptrs but not vice versa, but picking the
+    // first compatible type in Ts requires having shared_ptr types before weak_ptr types, so that
+    // they are stored as shared_ptrs.
+    /**
+     * Provide sensible error message if encountering shared_ptr/weak_ptr ambiguity. This method
+     * is not enough to detect this, only if someone is trying to find the shared_ptr.
+     */
+    template<typename Tp, typename U>
+    inline static void assign(std::shared_ptr<Tp> *, const std::weak_ptr<U> &) {
+        static_assert(std::is_same<Tp, void>::value,
+                      "shared/weak pointer ambiguity. move shared ptr types before weak_ptrs");
+    }
+};
+
+/**
+ * Template specialization for non copy assignable, but copy constructible types.
+ *
+ * \todo Test this. No basic classes are copy constructible but not assignable.
+ *
+ */
+template<typename T>
+struct _AData_copier<T, false> {
+    static_assert(!std::is_copy_assignable<T>::value, "T must not be copy assignable here");
+    static_assert(std::is_copy_constructible<T>::value, "T must be copy constructible here");
+
+    inline static void copy(T *data, const T &src) {
+        data->~T();
+        new(data)T(src);
+    }
+};
+
+/**
+ * Helper utility class that moves an object of type T to a destination.
+ *
+ * T must be move assignable or move constructible.
+ *
+ * It provides multiple methods:
+ *
+ * void assign(T*, T&&)
+ *
+ * \param T type of object to assign
+ */
+template<
+        typename T,
+        bool=std::is_move_assignable<T>::value>
+struct _AData_mover {
+    static_assert(std::is_move_assignable<T>::value, "T must be move assignable here");
+
+    /**
+     * Moves src to data while likely modifying it.
+     *
+     * \param data pointer to destination
+     * \param src source object
+     */
+    inline static void assign(T *data, T &&src) {
+        *data = std::move(src);
+    }
+
+    template<typename U>
+    using enable_if_T_is_same_as = typename std::enable_if<std::is_same<U, T>::value>::type;
+
+    /**
+     * Downcast specializations for sp<>, shared_ptr<> and weak_ptr<>
+     */
+    template<typename Tp, typename U, typename=enable_if_T_is_same_as<sp<Tp>>>
+    inline static void assign(sp<Tp> *data, sp<U> &&src) {
+        sp<U> __tmp = std::move(src); // move src out as get cannot
+        *data = static_cast<Tp*>(__tmp.get());
+    }
+
+    template<typename Tp, typename U, typename=enable_if_T_is_same_as<std::shared_ptr<Tp>>>
+    inline static void assign(std::shared_ptr<Tp> *data, std::shared_ptr<U> &&src) {
+        std::shared_ptr<U> __tmp = std::move(src); // move src out as static_pointer_cast cannot
+        *data = std::static_pointer_cast<Tp>(__tmp);
+    }
+
+    template<typename Tp, typename Td, typename U, typename Ud,
+            typename=enable_if_T_is_same_as<std::unique_ptr<Tp, Td>>>
+    inline static void assign(std::unique_ptr<Tp, Td> *data, std::unique_ptr<U, Ud> &&src) {
+        *data = std::unique_ptr<Tp, Td>(static_cast<Tp*>(src.release()));
+    }
+
+    // shared_ptrs are implicitly convertible to weak_ptrs but not vice versa, but picking the
+    // first compatible type in Ts requires having shared_ptr types before weak_ptr types, so that
+    // they are stored as shared_ptrs.
+    /**
+     * Provide sensible error message if encountering shared_ptr/weak_ptr ambiguity. This method
+     * is not enough to detect this, only if someone is trying to remove the shared_ptr.
+     */
+    template<typename Tp, typename U>
+    inline static void assign(std::shared_ptr<Tp> *, std::weak_ptr<U> &&) {
+        static_assert(std::is_same<Tp, void>::value,
+                      "shared/weak pointer ambiguity. move shared ptr types before weak_ptrs");
+    }
+
+    // unique_ptrs are implicitly convertible to shared_ptrs but not vice versa, but picking the
+    // first compatible type in Ts requires having unique_ptrs types before shared_ptrs types, so
+    // that they are stored as unique_ptrs.
+    /**
+     * Provide sensible error message if encountering shared_ptr/unique_ptr ambiguity. This method
+     * is not enough to detect this, only if someone is trying to remove the unique_ptr.
+     */
+    template<typename Tp, typename U>
+    inline static void assign(std::unique_ptr<Tp> *, std::shared_ptr<U> &&) {
+        static_assert(std::is_same<Tp, void>::value,
+                      "unique/shared pointer ambiguity. move unique ptr types before shared_ptrs");
+    }
+};
+
+/**
+ * Template specialization for non move assignable, but move constructible types.
+ *
+ * \todo Test this. No basic classes are move constructible but not assignable.
+ *
+ */
+template<typename T>
+struct _AData_mover<T, false> {
+    static_assert(!std::is_move_assignable<T>::value, "T must not be move assignable here");
+    static_assert(std::is_move_constructible<T>::value, "T must be move constructible here");
+
+    inline static void assign(T *data, T &&src) {
+        data->~T();
+        new(data)T(std::move(src));
+    }
+};
+
+/**
+ * Helper template that deletes an object of a specific type (member) in an AUnion.
+ *
+ * \param Flagger type flagger class (see AData)
+ * \param U AUnion object in which the member should be deleted
+ * \param Ts types to consider for the member
+ */
+template<typename Flagger, typename U, typename ...Ts>
+struct _AData_deleter;
+
+/**
+ * Template specialization when there are still types to consider (T and rest)
+ */
+template<typename Flagger, typename U, typename T, typename ...Ts>
+struct _AData_deleter<Flagger, U, T, Ts...> {
+    static bool del(typename Flagger::type flags, U &data) {
+        if (Flagger::canDeleteAs(flags, Flagger::flagFor((T*)0))) {
+            data.template del<T>();
+            return true;
+        }
+        return _AData_deleter<Flagger, U, Ts...>::del(flags, data);
+    }
+};
+
+/**
+ * Template specialization when there are no more types to consider.
+ */
+template<typename Flagger, typename U>
+struct _AData_deleter<Flagger, U> {
+    inline static bool del(typename Flagger::type, U &) {
+        return false;
+    }
+};
+
+/**
+ * Container that can store an arbitrary object of a set of specified types.
+ *
+ * This struct is an outer class that contains various inner classes based on desired type
+ * strictness. The following inner classes are supported:
+ *
+ * AData<types...>::Basic   - strict type support using uint32_t flag.
+ *
+ * AData<types...>::Strict<Flag> - strict type support using custom flag.
+ * AData<types...>::Relaxed<Flag, MaxSize, Align>
+ *                          - relaxed type support with compatible (usually derived) class support
+ *                            for pointer types with added size checking for minimal additional
+ *                            safety.
+ *
+ * AData<types...>::RelaxedBasic - strict type support using uint32_t flag.
+ *
+ * AData<types...>::Custom<flagger> - custom type support (flaggers determine the supported types
+ *                                    and the base type to use for each)
+ *
+ */
+template<typename ...Ts>
+struct AData {
+private:
+    static_assert(are_unique<Ts...>::value, "types must be unique");
+
+    static constexpr size_t num_types = sizeof...(Ts); ///< number of types to support
+
+public:
+    /**
+     * Default (strict) type flagger provided.
+     *
+     * The default flagger simply returns the index of the type within Ts, or 0 for void.
+     *
+     * Type flaggers return a flag for a supported type.
+     *
+     * They must provide:
+     *
+     * - a flagFor(T*) method for supported types _and_ for T=void. T=void is used to mark that no
+     *   object is stored in the container. For this, an arbitrary unique value may be returned.
+     * - a mask field that contains the flag mask.
+     * - a canDeleteAs(Flag, Flag) flag comparison method that checks if a type of a flag can be
+     *   deleted as another type.
+     *
+     * \param Flag the underlying unsigned integral to use for the flags.
+     */
+    template<typename Flag>
+    struct flagger {
+    private:
+        static_assert(std::is_unsigned<Flag>::value, "Flag must be unsigned");
+        static_assert(std::is_integral<Flag>::value, "Flag must be an integral type");
+
+        static constexpr Flag count = num_types + 1;
+
+    public:
+        typedef Flag type; ///< flag type
+
+        static constexpr Flag mask = _Flagged_helper::minMask<Flag>(count); ///< flag mask
+
+        /**
+         * Return the stored type for T. This is itself.
+         */
+        template<typename T>
+        struct store {
+            typedef T as_type; ///< the base type that T is stored as
+        };
+
+        /**
+         * Constexpr method that returns if two flags are compatible for deletion.
+         *
+         * \param objectFlag flag for object to be deleted
+         * \param deleteFlag flag for type that object is to be deleted as
+         */
+        static constexpr bool canDeleteAs(Flag objectFlag, Flag deleteFlag) {
+            // default flagger requires strict type equality
+            return objectFlag == deleteFlag;
+        }
+
+        /**
+         * Constexpr method that returns the flag to use for a given type.
+         *
+         * Function overload for void*.
+         */
+        static constexpr Flag flagFor(void*) {
+            return 0u;
+        }
+
+        /**
+         * Constexpr method that returns the flag to use for a given supported type (T).
+         */
+        template<typename T, typename=typename std::enable_if<is_one_of<T, Ts...>::value>::type>
+        static constexpr Flag flagFor(T*) {
+            return find_first<T, Ts...>::index;
+        }
+    };
+
+    /**
+     * Relaxed flagger returns the index of the type within Ts. However, for pointers T* it returns
+     * the first type in Ts that T* can be converted into (this is normally a base type, but also
+     * works for sp<>, shared_ptr<> or unique_ptr<>). For a bit more strictness, the flag also
+     * contains the size of the class to avoid finding objects that were stored as a different
+     * derived class of the same base class.
+     *
+     * Flag is basically the index of the (base) type in Ts multiplied by the max size stored plus
+     * the size of the type (divided by alignment) for derived pointer types.
+     *
+     * \param MaxSize max supported size for derived class pointers
+     * \param Align alignment to assume for derived class pointers
+     */
+    template<typename Flag, size_t MaxSize=1024, size_t Align=4>
+    struct relaxed_flagger {
+    private:
+        static_assert(std::is_unsigned<Flag>::value, "Flag must be unsigned");
+        static_assert(std::is_integral<Flag>::value, "Flag must be an integral type");
+
+        static constexpr Flag count = num_types + 1;
+        static_assert(std::numeric_limits<Flag>::max() / count > (MaxSize / Align),
+                      "not enough bits to fit into flag");
+
+        static constexpr Flag max_size_stored = MaxSize / Align + 1;
+
+        // T can be converted if it's size is <= MaxSize and it can be converted to one of the Ts
+        template<typename T, size_t size>
+        using enable_if_can_be_converted = typename std::enable_if<
+                (size / Align < max_size_stored
+                        && find_first_convertible_to<T, Ts...>::index)>::type;
+
+
+        template<typename W, typename T, typename=enable_if_can_be_converted<W, sizeof(T)>>
+        static constexpr Flag relaxedFlagFor(W*, T*) {
+            return find_first_convertible_to<W, Ts...>::index * max_size_stored
+                    + (is_one_of<W, Ts...>::value ? 0 : (sizeof(T) / Align));
+        }
+
+    public:
+        typedef Flag type; ///< flag type
+
+        static constexpr Flag mask =
+            _Flagged_helper::minMask<Flag>(count * max_size_stored); ///< flag mask
+
+        /**
+         * Constexpr method that returns if two flags are compatible for deletion.
+         *
+         * \param objectFlag flag for object to be deleted
+         * \param deleteFlag flag for type that object is to be deleted as
+         */
+        static constexpr bool canDeleteAs(Flag objectFlag, Flag deleteFlag) {
+            // can delete if objects have the same base type
+            return
+                objectFlag / max_size_stored == deleteFlag / max_size_stored &&
+                (deleteFlag % max_size_stored) == 0;
+        }
+
+        /**
+         * Constexpr method that returns the flag to use for a given type.
+         *
+         * Function overload for void*.
+         */
+        static constexpr Flag flagFor(void*) {
+            return 0u;
+        }
+
+        /**
+         * Constexpr method that returns the flag to use for a given supported type (T).
+         *
+         * This is a member method to enable both overloading as well as template specialization.
+         */
+        template<typename T, typename=typename std::enable_if<is_one_of<T, Ts...>::value>::type>
+        static constexpr Flag flagFor(T*) {
+            return find_first<T, Ts...>::index * max_size_stored;
+        }
+
+        /**
+         * For precaution, we only consider converting pointers to their base classes.
+         */
+
+        /**
+         * Template specialization for derived class pointers and managed pointers.
+         */
+        template<typename T>
+        static constexpr Flag flagFor(T**p) { return relaxedFlagFor(p, (T*)0); }
+        template<typename T>
+        static constexpr Flag flagFor(std::shared_ptr<T>*p) { return relaxedFlagFor(p, (T*)0); }
+        template<typename T>
+        static constexpr Flag flagFor(std::unique_ptr<T>*p) { return relaxedFlagFor(p, (T*)0); }
+        template<typename T>
+        static constexpr Flag flagFor(std::weak_ptr<T>*p) { return relaxedFlagFor(p, (T*)0); }
+        template<typename T>
+        static constexpr Flag flagFor(sp<T>*p) { return relaxedFlagFor(p, (T*)0); }
+        template<typename T>
+        static constexpr Flag flagFor(wp<T>*p) { return relaxedFlagFor(p, (T*)0); }
+
+        /**
+         * Type support template that provodes the stored type for T.
+         * This is itself if it is one of Ts, or the first type in Ts that T is convertible to.
+         *
+         * NOTE: This template may provide a base class for an unsupported type. Support is
+         * determined by flagFor().
+         */
+        template<typename T>
+        struct store {
+            typedef typename std::conditional<
+                    is_one_of<T, Ts...>::value,
+                    T,
+                    typename find_first_convertible_to<T, Ts...>::type>::type as_type;
+        };
+    };
+
+    /**
+     * Implementation of AData.
+     */
+    template<typename Flagger>
+    struct Custom : protected Flagged<AUnion<Ts...>, typename Flagger::type, Flagger::mask> {
+        using data_t = AUnion<Ts...>;
+        using base_t = Flagged<AUnion<Ts...>, typename Flagger::type, Flagger::mask>;
+
+        /**
+         * Constructor. Initializes this to a container that does not contain any object.
+         */
+        Custom() : base_t(Flagger::flagFor((void*)0)) { }
+
+        /**
+         * Removes the contained object, if any.
+         */
+        ~Custom() {
+            if (!this->clear()) {
+                __builtin_trap();
+                // std::cerr << "could not delete data of type " << this->flags() << std::endl;
+            }
+        }
+
+        /**
+         * Returns whether there is any object contained.
+         */
+        inline bool used() const {
+            return this->flags() != Flagger::flagFor((void*)0);
+        }
+
+        /**
+         * Removes the contained object, if any. Returns true if there are no objects contained,
+         * or false on any error (this is highly unexpected).
+         */
+        bool clear() {
+            if (this->used()) {
+                if (_AData_deleter<Flagger, data_t, Ts...>::del(this->flags(), this->get())) {
+                    this->setFlags(Flagger::flagFor((void*)0));
+                    return true;
+                }
+                return false;
+            }
+            return true;
+        }
+
+        template<typename T>
+        using is_supported_by_flagger =
+            typename std::enable_if<Flagger::flagFor((T*)0) != Flagger::flagFor((void*)0)>::type;
+
+        /**
+         * Checks if there is a copiable object of type T in this container. If there is, it copies
+         * that object into the provided address and returns true. Otherwise, it does nothing and
+         * returns false.
+         *
+         * This method normally requires a flag equality between the stored and retrieved types.
+         * However, it also allows retrieving the stored object as the stored type
+         * (usually base type).
+         *
+         * \param T type of object to sought
+         * \param data address at which the object should be retrieved
+         *
+         * \return true if the object was retrieved. false if it was not.
+         */
+        template<
+                typename T,
+                typename=is_supported_by_flagger<T>>
+        bool find(T *data) const {
+            using B = typename Flagger::template store<T>::as_type;
+            if (this->flags() == Flagger::flagFor((T*)0) ||
+                Flagger::canDeleteAs(this->flags(), Flagger::flagFor((T*)0))) {
+                _AData_copier<T>::assign(data, this->get().template get<B>());
+                return true;
+            }
+            return false;
+        }
+
+        /**
+         * Checks if there is an object of type T in this container. If there is, it moves that
+         * object into the provided address and returns true. Otherwise, it does nothing and returns
+         * false.
+         *
+         * This method normally requires a flag equality between the stored and retrieved types.
+         * However, it also allows retrieving the stored object as the stored type
+         * (usually base type).
+         *
+         * \param T type of object to sought
+         * \param data address at which the object should be retrieved.
+         *
+         * \return true if the object was retrieved. false if it was not.
+         */
+        template<
+                typename T,
+                typename=is_supported_by_flagger<T>>
+        bool remove(T *data) {
+            using B = typename Flagger::template store<T>::as_type;
+            if (this->flags() == Flagger::flagFor((T*)0) ||
+                Flagger::canDeleteAs(this->flags(), Flagger::flagFor((T*)0))) {
+                _AData_mover<T>::assign(data, std::move(this->get().template get<B>()));
+                return true;
+            }
+            return false;
+        }
+
+        /**
+         * Stores an object into this container by copying. If it was successful, returns true.
+         * Otherwise, (e.g. it could not destroy the already stored object) it returns false. This
+         * latter would be highly unexpected.
+         *
+         * \param T type of object to store
+         * \param data object to store
+         *
+         * \return true if the object was stored. false if it was not.
+         */
+        template<
+                typename T,
+                typename=is_supported_by_flagger<T>,
+                typename=typename std::enable_if<
+                        std::is_copy_constructible<T>::value ||
+                        (std::is_default_constructible<T>::value &&
+                                std::is_copy_assignable<T>::value)>::type>
+        bool set(const T &data) {
+            using B = typename Flagger::template store<T>::as_type;
+
+            // if already contains an object of this type, simply assign
+            if (this->flags() == Flagger::flagFor((T*)0) && std::is_same<T, B>::value) {
+                _AData_copier<B>::assign(&this->get().template get<B>(), data);
+                return true;
+            } else if (this->used()) {
+                // destroy previous object
+                if (!this->clear()) {
+                    return false;
+                }
+            }
+            this->get().template emplace<B>(data);
+            this->setFlags(Flagger::flagFor((T *)0));
+            return true;
+        }
+
+        /**
+         * Moves an object into this container. If it was successful, returns true. Otherwise,
+         * (e.g. it could not destroy the already stored object) it returns false. This latter
+         * would be highly unexpected.
+         *
+         * \param T type of object to store
+         * \param data object to store
+         *
+         * \return true if the object was stored. false if it was not.
+         */
+        template<
+                typename T,
+                typename=is_supported_by_flagger<T>>
+        bool set(T &&data) {
+            using B = typename Flagger::template store<T>::as_type;
+
+            // if already contains an object of this type, simply assign
+            if (this->flags() == Flagger::flagFor((T*)0) && std::is_same<T, B>::value) {
+                _AData_mover<B>::assign(&this->get().template get<B>(), std::forward<T&&>(data));
+                return true;
+            } else if (this->used()) {
+                // destroy previous object
+                if (!this->clear()) {
+                    return false;
+                }
+            }
+            this->get().template emplace<B>(std::forward<T&&>(data));
+            this->setFlags(Flagger::flagFor((T *)0));
+            return true;
+        }
+    };
+
+    /**
+     * Basic AData using the default type flagger and requested flag type.
+     *
+     * \param Flag desired flag type to use. Must be an unsigned and std::integral type.
+     */
+    template<typename Flag>
+    using Strict = Custom<flagger<Flag>>;
+
+    /**
+     * Basic AData using the default type flagger and uint32_t flag.
+     */
+    using Basic = Strict<uint32_t>;
+
+    /**
+     * AData using the relaxed type flagger for max size and requested flag type.
+     *
+     * \param Flag desired flag type to use. Must be an unsigned and std::integral type.
+     */
+    template<typename Flag, size_t MaxSize = 1024, size_t Align = 4>
+    using Relaxed = Custom<relaxed_flagger<Flag, MaxSize, Align>>;
+
+    /**
+     * Basic AData using the relaxed type flagger and uint32_t flag.
+     */
+    using RelaxedBasic = Relaxed<uint32_t>;
+};
+
+}  // namespace android
+
+#endif  // STAGEFRIGHT_FOUNDATION_A_DATA_H_
+
diff --git a/include/media/stagefright/foundation/TypeTraits.h b/include/media/stagefright/foundation/TypeTraits.h
index 2eaec35..1250e9b 100644
--- a/include/media/stagefright/foundation/TypeTraits.h
+++ b/include/media/stagefright/foundation/TypeTraits.h
@@ -85,6 +85,139 @@
             typename underlying_integral_type<T, signed>::type>::value> {
 };
 
+/**
+ * Type support relationship query template.
+ *
+ * If T occurs as one of the types in Us with the same const-volatile qualifications, provides the
+ * member constant |value| equal to true. Otherwise value is false.
+ */
+template<typename T, typename ...Us>
+struct is_one_of;
+
+/// \if 0
+/**
+ * Template specialization when first type matches the searched type.
+ */
+template<typename T, typename ...Us>
+struct is_one_of<T, T, Us...> : std::true_type {};
+
+/**
+ * Template specialization when first type does not match the searched type.
+ */
+template<typename T, typename U, typename ...Us>
+struct is_one_of<T, U, Us...> : is_one_of<T, Us...> {};
+
+/**
+ * Template specialization when there are no types to search.
+ */
+template<typename T>
+struct is_one_of<T> : std::false_type {};
+/// \endif
+
+/**
+ * Type support relationship query template.
+ *
+ * If all types in Us are unique, provides the member constant |value| equal to true.
+ * Otherwise value is false.
+ */
+template<typename ...Us>
+struct are_unique;
+
+/// \if 0
+/**
+ * Template specialization when there are no types.
+ */
+template<>
+struct are_unique<> : std::true_type {};
+
+/**
+ * Template specialization when there is at least one type to check.
+ */
+template<typename T, typename ...Us>
+struct are_unique<T, Us...>
+    : std::integral_constant<bool, are_unique<Us...>::value && !is_one_of<T, Us...>::value> {};
+/// \endif
+
+/// \if 0
+template<size_t Base, typename T, typename ...Us>
+struct _find_first_impl;
+
+/**
+ * Template specialization when there are no types to search.
+ */
+template<size_t Base, typename T>
+struct _find_first_impl<Base, T> : std::integral_constant<size_t, 0> {};
+
+/**
+ * Template specialization when T is the first type in Us.
+ */
+template<size_t Base, typename T, typename ...Us>
+struct _find_first_impl<Base, T, T, Us...> : std::integral_constant<size_t, Base> {};
+
+/**
+ * Template specialization when T is not the first type in Us.
+ */
+template<size_t Base, typename T, typename U, typename ...Us>
+struct _find_first_impl<Base, T, U, Us...>
+    : std::integral_constant<size_t, _find_first_impl<Base + 1, T, Us...>::value> {};
+
+/// \endif
+
+/**
+ * Type support relationship query template.
+ *
+ * If T occurs in Us, index is the 1-based left-most index of T in Us. Otherwise, index is 0.
+ */
+template<typename T, typename ...Us>
+struct find_first {
+    static constexpr size_t index = _find_first_impl<1, T, Us...>::value;
+};
+
+/// \if 0
+/**
+ * Helper class for find_first_convertible_to template.
+ *
+ * Adds a base index.
+ */
+template<size_t Base, typename T, typename ...Us>
+struct _find_first_convertible_to_helper;
+
+/**
+ * Template specialization for when there are more types to consider
+ */
+template<size_t Base, typename T, typename U, typename ...Us>
+struct _find_first_convertible_to_helper<Base, T, U, Us...> {
+    static constexpr size_t index =
+        std::is_convertible<T, U>::value ? Base :
+                _find_first_convertible_to_helper<Base + 1, T, Us...>::index;
+    typedef typename std::conditional<
+        std::is_convertible<T, U>::value, U,
+        typename _find_first_convertible_to_helper<Base + 1, T, Us...>::type>::type type;
+};
+
+/**
+ * Template specialization for when there are no more types to consider
+ */
+template<size_t Base, typename T>
+struct _find_first_convertible_to_helper<Base, T> {
+    static constexpr size_t index = 0;
+    typedef void type;
+};
+
+/// \endif
+
+/**
+ * Type support template that returns the type that T can be implicitly converted into, and its
+ * index, from a list of other types (Us).
+ *
+ * Returns index of 0 and type of void if there are no convertible types.
+ *
+ * \param T type that is converted
+ * \param Us types into which the conversion is considered
+ */
+template<typename T, typename ...Us>
+struct find_first_convertible_to : public _find_first_convertible_to_helper<1, T, Us...> { };
+
 }  // namespace android
 
 #endif  // STAGEFRIGHT_FOUNDATION_TYPE_TRAITS_H_
diff --git a/media/libaudioclient/AudioTrack.cpp b/media/libaudioclient/AudioTrack.cpp
index 3c7e8b7..aef7dfb 100644
--- a/media/libaudioclient/AudioTrack.cpp
+++ b/media/libaudioclient/AudioTrack.cpp
@@ -671,6 +671,8 @@
         mState = STATE_STOPPING;
     } else {
         mState = STATE_STOPPED;
+        ALOGD_IF(mSharedBuffer == nullptr,
+                "stop() called with %u frames delivered", mReleased.value());
         mReleased = 0;
     }
 
diff --git a/media/libaudioclient/IEffect.cpp b/media/libaudioclient/IEffect.cpp
index 115ca75..ce72dae 100644
--- a/media/libaudioclient/IEffect.cpp
+++ b/media/libaudioclient/IEffect.cpp
@@ -25,6 +25,9 @@
 
 namespace android {
 
+// Maximum command/reply size expected
+#define EFFECT_PARAM_SIZE_MAX       65536
+
 enum {
     ENABLE = IBinder::FIRST_CALL_TRANSACTION,
     DISABLE,
@@ -156,6 +159,10 @@
             uint32_t cmdSize = data.readInt32();
             char *cmd = NULL;
             if (cmdSize) {
+                if (cmdSize > EFFECT_PARAM_SIZE_MAX) {
+                    reply->writeInt32(NO_MEMORY);
+                    return NO_ERROR;
+                }
                 cmd = (char *)calloc(cmdSize, 1);
                 if (cmd == NULL) {
                     reply->writeInt32(NO_MEMORY);
@@ -167,6 +174,11 @@
             uint32_t replySz = replySize;
             char *resp = NULL;
             if (replySize) {
+                if (replySize > EFFECT_PARAM_SIZE_MAX) {
+                    free(cmd);
+                    reply->writeInt32(NO_MEMORY);
+                    return NO_ERROR;
+                }
                 resp = (char *)calloc(replySize, 1);
                 if (resp == NULL) {
                     free(cmd);
diff --git a/media/libaudiohal/Android.bp b/media/libaudiohal/Android.bp
deleted file mode 100644
index e943eed..0000000
--- a/media/libaudiohal/Android.bp
+++ /dev/null
@@ -1,24 +0,0 @@
-cc_library_shared {
-    name: "libaudiohal",
-
-    srcs: [
-        "DeviceHalLocal.cpp",
-        "DevicesFactoryHalLocal.cpp",
-        "EffectHalLocal.cpp",
-        "EffectsFactoryHalLocal.cpp",
-        "StreamHalLocal.cpp",
-    ],
-
-    shared_libs: [
-        "libcutils",
-        "libhardware",
-        "liblog",
-        "libeffects",
-        "libutils",
-    ],
-
-    cflags: [
-        "-Werror",
-        "-Wall",
-    ],
-}
diff --git a/media/libaudiohal/Android.mk b/media/libaudiohal/Android.mk
new file mode 100644
index 0000000..63aa9c6
--- /dev/null
+++ b/media/libaudiohal/Android.mk
@@ -0,0 +1,50 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SHARED_LIBRARIES := \
+    libcutils \
+    libhardware \
+    liblog \
+    libutils \
+    libeffects
+
+ifeq ($(ENABLE_TREBLE), true)
+
+LOCAL_CFLAGS += -DENABLE_TREBLE
+
+LOCAL_SRC_FILES := \
+    ConversionHelperHidl.cpp   \
+    DeviceHalHidl.cpp          \
+    DevicesFactoryHalHidl.cpp  \
+    EffectHalHidl.cpp          \
+    EffectsFactoryHalHidl.cpp  \
+    StreamHalHidl.cpp
+
+LOCAL_SHARED_LIBRARIES += \
+    libhwbinder      \
+    libhidlbase      \
+    libhidltransport \
+    libbase          \
+    android.hardware.audio@2.0             \
+    android.hardware.audio.common@2.0      \
+    android.hardware.audio.common@2.0-util \
+    android.hardware.audio.effect@2.0
+
+LOCAL_WHOLE_STATIC_LIBRARIES := libmedia_helper
+
+else  # if !ENABLE_TREBLE
+
+LOCAL_SRC_FILES := \
+    DeviceHalLocal.cpp          \
+    DevicesFactoryHalLocal.cpp  \
+    EffectHalLocal.cpp          \
+    EffectsFactoryHalLocal.cpp  \
+    StreamHalLocal.cpp
+endif  # ENABLE_TREBLE
+
+LOCAL_MODULE := libaudiohal
+
+LOCAL_CFLAGS := -Wall -Werror
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libaudiohal/ConversionHelperHidl.cpp b/media/libaudiohal/ConversionHelperHidl.cpp
new file mode 100644
index 0000000..ebbc02c
--- /dev/null
+++ b/media/libaudiohal/ConversionHelperHidl.cpp
@@ -0,0 +1,99 @@
+/*
+ * 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 <string.h>
+
+#define LOG_TAG "HalHidl"
+#include <media/AudioParameter.h>
+#include <utils/Log.h>
+
+#include "ConversionHelperHidl.h"
+
+using ::android::hardware::audio::V2_0::Result;
+
+namespace android {
+
+// static
+status_t ConversionHelperHidl::keysFromHal(const String8& keys, hidl_vec<hidl_string> *hidlKeys) {
+    AudioParameter halKeys(keys);
+    if (halKeys.size() == 0) return BAD_VALUE;
+    hidlKeys->resize(halKeys.size());
+    for (size_t i = 0; i < halKeys.size(); ++i) {
+        String8 key;
+        status_t status = halKeys.getAt(i, key);
+        if (status != OK) return status;
+        (*hidlKeys)[i] = key.string();
+    }
+    return OK;
+}
+
+// static
+status_t ConversionHelperHidl::parametersFromHal(
+        const String8& kvPairs, hidl_vec<ParameterValue> *hidlParams) {
+    AudioParameter params(kvPairs);
+    if (params.size() == 0) return BAD_VALUE;
+    hidlParams->resize(params.size());
+    for (size_t i = 0; i < params.size(); ++i) {
+        String8 key, value;
+        status_t status = params.getAt(i, key, value);
+        if (status != OK) return status;
+        (*hidlParams)[i].key = key.string();
+        (*hidlParams)[i].value = value.string();
+    }
+    return OK;
+}
+
+// static
+void ConversionHelperHidl::parametersToHal(
+        const hidl_vec<ParameterValue>& parameters, String8 *values) {
+    AudioParameter params;
+    for (size_t i = 0; i < parameters.size(); ++i) {
+        params.add(String8(parameters[i].key.c_str()), String8(parameters[i].value.c_str()));
+    }
+    values->setTo(params.toString());
+}
+
+ConversionHelperHidl::ConversionHelperHidl(const char* className)
+        : mClassName(className) {
+}
+
+// static
+status_t ConversionHelperHidl::analyzeResult(const Result& result) {
+    switch (result) {
+        case Result::OK: return OK;
+        case Result::INVALID_ARGUMENTS: return BAD_VALUE;
+        case Result::INVALID_STATE: return NOT_ENOUGH_DATA;
+        case Result::NOT_INITIALIZED: return NO_INIT;
+        case Result::NOT_SUPPORTED: return INVALID_OPERATION;
+        default: return NO_INIT;
+    }
+}
+
+status_t ConversionHelperHidl::processReturn(const char* funcName, const Status& status) {
+    const status_t st = status.transactionError();
+    ALOGE_IF(st, "%s %p %s: %s (from rpc)", mClassName, this, funcName, strerror(-st));
+    return st;
+}
+
+status_t ConversionHelperHidl::processReturn(
+        const char* funcName, const Status& status, hardware::audio::V2_0::Result retval) {
+    const status_t st = status.isOk() ? analyzeResult(retval) : status.transactionError();
+    ALOGE_IF(st, "%s %p %s: %s (from %s)",
+            mClassName, this, funcName, strerror(-st), status.isOk() ? "hal" : "rpc");
+    return st;
+}
+
+}  // namespace android
diff --git a/media/libaudiohal/ConversionHelperHidl.h b/media/libaudiohal/ConversionHelperHidl.h
new file mode 100644
index 0000000..628913a
--- /dev/null
+++ b/media/libaudiohal/ConversionHelperHidl.h
@@ -0,0 +1,75 @@
+/*
+ * 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_CONVERSION_HELPER_HIDL_H
+#define ANDROID_HARDWARE_CONVERSION_HELPER_HIDL_H
+
+#include <android/hardware/audio/2.0/types.h>
+#include <hidl/HidlSupport.h>
+#include <utils/String8.h>
+
+using ::android::hardware::audio::V2_0::ParameterValue;
+using ::android::hardware::Return;
+using ::android::hardware::Status;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+
+namespace android {
+
+class ConversionHelperHidl {
+  protected:
+    static status_t keysFromHal(const String8& keys, hidl_vec<hidl_string> *hidlKeys);
+    static status_t parametersFromHal(const String8& kvPairs, hidl_vec<ParameterValue> *hidlParams);
+    static void parametersToHal(const hidl_vec<ParameterValue>& parameters, String8 *values);
+
+    ConversionHelperHidl(const char* className);
+
+    status_t processReturn(const char* funcName, const Return<void>& ret) {
+        return processReturn(funcName, ret.getStatus());
+    }
+
+    template<typename R, typename T>
+    status_t processReturn(const char* funcName, const Return<R>& ret, T *retval) {
+        if (ret.getStatus().isOk()) {
+            // This way it also works for enum class to unscoped enum conversion.
+            *retval = static_cast<T>(static_cast<R>(ret));
+            return OK;
+        }
+        return processReturn(funcName, ret.getStatus());
+    }
+
+    status_t processReturn(const char* funcName, const Return<hardware::audio::V2_0::Result>& ret) {
+        return processReturn(funcName, ret, ret);
+    }
+
+    template<typename T>
+    status_t processReturn(
+            const char* funcName, const Return<T>& ret, hardware::audio::V2_0::Result retval) {
+        return processReturn(funcName, ret.getStatus(), retval);
+    }
+
+  private:
+    const char* mClassName;
+
+    static status_t analyzeResult(const hardware::audio::V2_0::Result& result);
+    status_t processReturn(const char* funcName, const Status& status);
+    status_t processReturn(
+            const char* funcName, const Status& status, hardware::audio::V2_0::Result retval);
+};
+
+}  // namespace android
+
+#endif // ANDROID_HARDWARE_CONVERSION_HELPER_HIDL_H
diff --git a/media/libaudiohal/DeviceHalHidl.cpp b/media/libaudiohal/DeviceHalHidl.cpp
new file mode 100644
index 0000000..a6ced12
--- /dev/null
+++ b/media/libaudiohal/DeviceHalHidl.cpp
@@ -0,0 +1,351 @@
+/*
+ * 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 <stdio.h>
+
+#define LOG_TAG "DeviceHalHidl"
+//#define LOG_NDEBUG 0
+
+#include <android/hardware/audio/2.0/IPrimaryDevice.h>
+#include <cutils/native_handle.h>
+#include <utils/Log.h>
+
+#include "DeviceHalHidl.h"
+#include "HidlUtils.h"
+#include "StreamHalHidl.h"
+
+using ::android::hardware::audio::common::V2_0::AudioConfig;
+using ::android::hardware::audio::common::V2_0::AudioDevice;
+using ::android::hardware::audio::common::V2_0::AudioInputFlag;
+using ::android::hardware::audio::common::V2_0::AudioOutputFlag;
+using ::android::hardware::audio::common::V2_0::AudioPatchHandle;
+using ::android::hardware::audio::common::V2_0::AudioPort;
+using ::android::hardware::audio::common::V2_0::AudioPortConfig;
+using ::android::hardware::audio::common::V2_0::AudioMode;
+using ::android::hardware::audio::common::V2_0::AudioSource;
+using ::android::hardware::audio::V2_0::DeviceAddress;
+using ::android::hardware::audio::V2_0::IPrimaryDevice;
+using ::android::hardware::audio::V2_0::ParameterValue;
+using ::android::hardware::audio::V2_0::Result;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+
+namespace android {
+
+namespace {
+
+status_t deviceAddressFromHal(
+        audio_devices_t device, const char* halAddress, DeviceAddress* address) {
+    address->device = AudioDevice(device);
+    const bool isInput = (device & AUDIO_DEVICE_BIT_IN) != 0;
+    if (isInput) device &= ~AUDIO_DEVICE_BIT_IN;
+    if ((!isInput && (device & AUDIO_DEVICE_OUT_ALL_A2DP) != 0)
+            || (isInput && (device & AUDIO_DEVICE_IN_BLUETOOTH_A2DP) != 0)) {
+        int status = sscanf(halAddress,
+                "%hhX:%hhX:%hhX:%hhX:%hhX:%hhX",
+                &address->address.mac[0], &address->address.mac[1], &address->address.mac[2],
+                &address->address.mac[3], &address->address.mac[4], &address->address.mac[5]);
+        return status == 6 ? OK : BAD_VALUE;
+    } else if ((!isInput && (device & AUDIO_DEVICE_OUT_IP) != 0)
+            || (isInput && (device & AUDIO_DEVICE_IN_IP) != 0)) {
+        int status = sscanf(halAddress,
+                "%hhu.%hhu.%hhu.%hhu",
+                &address->address.ipv4[0], &address->address.ipv4[1],
+                &address->address.ipv4[2], &address->address.ipv4[3]);
+        return status == 4 ? OK : BAD_VALUE;
+    } else if ((!isInput && (device & AUDIO_DEVICE_OUT_ALL_USB)) != 0
+            || (isInput && (device & AUDIO_DEVICE_IN_ALL_USB)) != 0) {
+        int status = sscanf(halAddress,
+                "card=%d;device=%d",
+                &address->address.alsa.card, &address->address.alsa.device);
+        return status == 2 ? OK : BAD_VALUE;
+    } else if ((!isInput && (device & AUDIO_DEVICE_OUT_BUS) != 0)
+            || (isInput && (device & AUDIO_DEVICE_IN_BUS) != 0)) {
+        if (halAddress != NULL) {
+            address->busAddress = halAddress;
+            return OK;
+        }
+        return BAD_VALUE;
+    } else if ((!isInput && (device & AUDIO_DEVICE_OUT_REMOTE_SUBMIX)) != 0
+            || (isInput && (device & AUDIO_DEVICE_IN_REMOTE_SUBMIX) != 0)) {
+        if (halAddress != NULL) {
+            address->rSubmixAddress = halAddress;
+            return OK;
+        }
+        return BAD_VALUE;
+    }
+    return OK;
+}
+
+}  // namespace
+
+DeviceHalHidl::DeviceHalHidl(const sp<IDevice>& device)
+        : ConversionHelperHidl("Device"), mDevice(device) {
+}
+
+DeviceHalHidl::~DeviceHalHidl() {
+}
+
+status_t DeviceHalHidl::getSupportedDevices(uint32_t*) {
+    // Obsolete.
+    return INVALID_OPERATION;
+}
+
+status_t DeviceHalHidl::initCheck() {
+    if (mDevice == 0) return NO_INIT;
+    return processReturn("initCheck", mDevice->initCheck());
+}
+
+status_t DeviceHalHidl::setVoiceVolume(float volume) {
+    if (mDevice == 0) return NO_INIT;
+    sp<IPrimaryDevice> primaryDev = IPrimaryDevice::castFrom(mDevice);
+    if (primaryDev == 0) return INVALID_OPERATION;
+    return processReturn("setVoiceVolume", primaryDev->setVoiceVolume(volume));
+}
+
+status_t DeviceHalHidl::setMasterVolume(float volume) {
+    if (mDevice == 0) return NO_INIT;
+    sp<IPrimaryDevice> primaryDev = IPrimaryDevice::castFrom(mDevice);
+    if (primaryDev == 0) return INVALID_OPERATION;
+    return processReturn("setMasterVolume", primaryDev->setMasterVolume(volume));
+}
+
+status_t DeviceHalHidl::getMasterVolume(float *volume) {
+    if (mDevice == 0) return NO_INIT;
+    sp<IPrimaryDevice> primaryDev = IPrimaryDevice::castFrom(mDevice);
+    if (primaryDev == 0) return INVALID_OPERATION;
+    Result retval;
+    Return<void> ret = primaryDev->getMasterVolume(
+            [&](Result r, float v) {
+                retval = r;
+                if (retval == Result::OK) {
+                    *volume = v;
+                }
+            });
+    return processReturn("getMasterVolume", ret, retval);
+}
+
+status_t DeviceHalHidl::setMode(audio_mode_t mode) {
+    if (mDevice == 0) return NO_INIT;
+    sp<IPrimaryDevice> primaryDev = IPrimaryDevice::castFrom(mDevice);
+    if (primaryDev == 0) return INVALID_OPERATION;
+    return processReturn("setMode", primaryDev->setMode(AudioMode(mode)));
+}
+
+status_t DeviceHalHidl::setMicMute(bool state) {
+    if (mDevice == 0) return NO_INIT;
+    return processReturn("setMicMute", mDevice->setMicMute(state));
+}
+
+status_t DeviceHalHidl::getMicMute(bool *state) {
+    if (mDevice == 0) return NO_INIT;
+    Result retval;
+    Return<void> ret = mDevice->getMicMute(
+            [&](Result r, bool mute) {
+                retval = r;
+                if (retval == Result::OK) {
+                    *state = mute;
+                }
+            });
+    return processReturn("getMicMute", ret, retval);
+}
+
+status_t DeviceHalHidl::setMasterMute(bool state) {
+    if (mDevice == 0) return NO_INIT;
+    return processReturn("setMasterMute", mDevice->setMasterMute(state));
+}
+
+status_t DeviceHalHidl::getMasterMute(bool *state) {
+    if (mDevice == 0) return NO_INIT;
+    Result retval;
+    Return<void> ret = mDevice->getMasterMute(
+            [&](Result r, bool mute) {
+                retval = r;
+                if (retval == Result::OK) {
+                    *state = mute;
+                }
+            });
+    return processReturn("getMasterMute", ret, retval);
+}
+
+status_t DeviceHalHidl::setParameters(const String8& kvPairs) {
+    if (mDevice == 0) return NO_INIT;
+    hidl_vec<ParameterValue> hidlParams;
+    status_t status = parametersFromHal(kvPairs, &hidlParams);
+    if (status != OK) return status;
+    return processReturn("setParameters", mDevice->setParameters(hidlParams));
+}
+
+status_t DeviceHalHidl::getParameters(const String8& keys, String8 *values) {
+    values->clear();
+    if (mDevice == 0) return NO_INIT;
+    hidl_vec<hidl_string> hidlKeys;
+    status_t status = keysFromHal(keys, &hidlKeys);
+    if (status != OK) return status;
+    Result retval;
+    Return<void> ret = mDevice->getParameters(
+            hidlKeys,
+            [&](Result r, const hidl_vec<ParameterValue>& parameters) {
+                retval = r;
+                if (retval == Result::OK) {
+                    parametersToHal(parameters, values);
+                }
+            });
+    return processReturn("getParameters", ret, retval);
+}
+
+status_t DeviceHalHidl::getInputBufferSize(
+        const struct audio_config *config, size_t *size) {
+    if (mDevice == 0) return NO_INIT;
+    AudioConfig hidlConfig;
+    HidlUtils::audioConfigFromHal(*config, &hidlConfig);
+    Result retval;
+    Return<void> ret = mDevice->getInputBufferSize(
+            hidlConfig,
+            [&](Result r, uint64_t bufferSize) {
+                retval = r;
+                if (retval == Result::OK) {
+                    *size = static_cast<size_t>(bufferSize);
+                }
+            });
+    return processReturn("getInputBufferSize", ret, retval);
+}
+
+status_t DeviceHalHidl::openOutputStream(
+        audio_io_handle_t handle,
+        audio_devices_t devices,
+        audio_output_flags_t flags,
+        struct audio_config *config,
+        const char *address,
+        sp<StreamOutHalInterface> *outStream) {
+    if (mDevice == 0) return NO_INIT;
+    DeviceAddress hidlDevice;
+    status_t status = deviceAddressFromHal(devices, address, &hidlDevice);
+    if (status != OK) return status;
+    AudioConfig hidlConfig;
+    HidlUtils::audioConfigFromHal(*config, &hidlConfig);
+    Result retval = Result::NOT_INITIALIZED;
+    Return<void> ret = mDevice->openOutputStream(
+            handle,
+            hidlDevice,
+            hidlConfig,
+            AudioOutputFlag(flags),
+            [&](Result r, const sp<IStreamOut>& result, const AudioConfig& suggestedConfig) {
+                retval = r;
+                if (retval == Result::OK) {
+                    *outStream = new StreamOutHalHidl(result);
+                }
+                HidlUtils::audioConfigToHal(suggestedConfig, config);
+            });
+    return processReturn("openOutputStream", ret, retval);
+}
+
+status_t DeviceHalHidl::openInputStream(
+        audio_io_handle_t handle,
+        audio_devices_t devices,
+        struct audio_config *config,
+        audio_input_flags_t flags,
+        const char *address,
+        audio_source_t source,
+        sp<StreamInHalInterface> *inStream) {
+    if (mDevice == 0) return NO_INIT;
+    DeviceAddress hidlDevice;
+    status_t status = deviceAddressFromHal(devices, address, &hidlDevice);
+    if (status != OK) return status;
+    AudioConfig hidlConfig;
+    HidlUtils::audioConfigFromHal(*config, &hidlConfig);
+    Result retval = Result::NOT_INITIALIZED;
+    Return<void> ret = mDevice->openInputStream(
+            handle,
+            hidlDevice,
+            hidlConfig,
+            AudioInputFlag(flags),
+            AudioSource(source),
+            [&](Result r, const sp<IStreamIn>& result, const AudioConfig& suggestedConfig) {
+                retval = r;
+                if (retval == Result::OK) {
+                    *inStream = new StreamInHalHidl(result);
+                }
+                HidlUtils::audioConfigToHal(suggestedConfig, config);
+            });
+    return processReturn("openInputStream", ret, retval);
+}
+
+status_t DeviceHalHidl::supportsAudioPatches(bool *supportsPatches) {
+    if (mDevice == 0) return NO_INIT;
+    return processReturn("supportsAudioPatches", mDevice->supportsAudioPatches(), supportsPatches);
+}
+
+status_t DeviceHalHidl::createAudioPatch(
+        unsigned int num_sources,
+        const struct audio_port_config *sources,
+        unsigned int num_sinks,
+        const struct audio_port_config *sinks,
+        audio_patch_handle_t *patch) {
+    if (mDevice == 0) return NO_INIT;
+    hidl_vec<AudioPortConfig> hidlSources, hidlSinks;
+    HidlUtils::audioPortConfigsFromHal(num_sources, sources, &hidlSources);
+    HidlUtils::audioPortConfigsFromHal(num_sinks, sinks, &hidlSinks);
+    Result retval;
+    Return<void> ret = mDevice->createAudioPatch(
+            hidlSources, hidlSinks,
+            [&](Result r, AudioPatchHandle hidlPatch) {
+                retval = r;
+                if (retval == Result::OK) {
+                    *patch = static_cast<audio_patch_handle_t>(hidlPatch);
+                }
+            });
+    return processReturn("createAudioPatch", ret, retval);
+}
+
+status_t DeviceHalHidl::releaseAudioPatch(audio_patch_handle_t patch) {
+    if (mDevice == 0) return NO_INIT;
+    return processReturn("releaseAudioPatch", mDevice->releaseAudioPatch(patch));
+}
+
+status_t DeviceHalHidl::getAudioPort(struct audio_port *port) {
+    if (mDevice == 0) return NO_INIT;
+    AudioPort hidlPort;
+    HidlUtils::audioPortFromHal(*port, &hidlPort);
+    Result retval;
+    Return<void> ret = mDevice->getAudioPort(
+            hidlPort,
+            [&](Result r, const AudioPort& p) {
+                retval = r;
+                if (retval == Result::OK) {
+                    HidlUtils::audioPortToHal(p, port);
+                }
+            });
+    return processReturn("getAudioPort", ret, retval);
+}
+
+status_t DeviceHalHidl::setAudioPortConfig(const struct audio_port_config *config) {
+    if (mDevice == 0) return NO_INIT;
+    AudioPortConfig hidlConfig;
+    HidlUtils::audioPortConfigFromHal(*config, &hidlConfig);
+    return processReturn("setAudioPortConfig", mDevice->setAudioPortConfig(hidlConfig));
+}
+
+status_t DeviceHalHidl::dump(int fd) {
+    if (mDevice == 0) return NO_INIT;
+    native_handle_t* hidlHandle = native_handle_create(1, 0);
+    hidlHandle->data[0] = fd;
+    Return<void> ret = mDevice->debugDump(hidlHandle);
+    native_handle_delete(hidlHandle);
+    return processReturn("dump", ret);
+}
+
+} // namespace android
diff --git a/media/libaudiohal/DeviceHalHidl.h b/media/libaudiohal/DeviceHalHidl.h
new file mode 100644
index 0000000..9da02a4
--- /dev/null
+++ b/media/libaudiohal/DeviceHalHidl.h
@@ -0,0 +1,123 @@
+/*
+ * 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_DEVICE_HAL_HIDL_H
+#define ANDROID_HARDWARE_DEVICE_HAL_HIDL_H
+
+#include <android/hardware/audio/2.0/IDevice.h>
+#include <media/audiohal/DeviceHalInterface.h>
+
+#include "ConversionHelperHidl.h"
+
+using ::android::hardware::audio::V2_0::IDevice;
+using ::android::hardware::Return;
+
+namespace android {
+
+class DeviceHalHidl : public DeviceHalInterface, public ConversionHelperHidl
+{
+  public:
+    // Sets the value of 'devices' to a bitmask of 1 or more values of audio_devices_t.
+    virtual status_t getSupportedDevices(uint32_t *devices);
+
+    // Check to see if the audio hardware interface has been initialized.
+    virtual status_t initCheck();
+
+    // Set the audio volume of a voice call. Range is between 0.0 and 1.0.
+    virtual status_t setVoiceVolume(float volume);
+
+    // Set the audio volume for all audio activities other than voice call.
+    virtual status_t setMasterVolume(float volume);
+
+    // Get the current master volume value for the HAL.
+    virtual status_t getMasterVolume(float *volume);
+
+    // Called when the audio mode changes.
+    virtual status_t setMode(audio_mode_t mode);
+
+    // Muting control.
+    virtual status_t setMicMute(bool state);
+    virtual status_t getMicMute(bool *state);
+    virtual status_t setMasterMute(bool state);
+    virtual status_t getMasterMute(bool *state);
+
+    // Set global audio parameters.
+    virtual status_t setParameters(const String8& kvPairs);
+
+    // Get global audio parameters.
+    virtual status_t getParameters(const String8& keys, String8 *values);
+
+    // Returns audio input buffer size according to parameters passed.
+    virtual status_t getInputBufferSize(const struct audio_config *config,
+            size_t *size);
+
+    // Creates and opens the audio hardware output stream. The stream is closed
+    // by releasing all references to the returned object.
+    virtual status_t openOutputStream(
+            audio_io_handle_t handle,
+            audio_devices_t devices,
+            audio_output_flags_t flags,
+            struct audio_config *config,
+            const char *address,
+            sp<StreamOutHalInterface> *outStream);
+
+    // Creates and opens the audio hardware input stream. The stream is closed
+    // by releasing all references to the returned object.
+    virtual status_t openInputStream(
+            audio_io_handle_t handle,
+            audio_devices_t devices,
+            struct audio_config *config,
+            audio_input_flags_t flags,
+            const char *address,
+            audio_source_t source,
+            sp<StreamInHalInterface> *inStream);
+
+    // Returns whether createAudioPatch and releaseAudioPatch operations are supported.
+    virtual status_t supportsAudioPatches(bool *supportsPatches);
+
+    // Creates an audio patch between several source and sink ports.
+    virtual status_t createAudioPatch(
+            unsigned int num_sources,
+            const struct audio_port_config *sources,
+            unsigned int num_sinks,
+            const struct audio_port_config *sinks,
+            audio_patch_handle_t *patch);
+
+    // Releases an audio patch.
+    virtual status_t releaseAudioPatch(audio_patch_handle_t patch);
+
+    // Fills the list of supported attributes for a given audio port.
+    virtual status_t getAudioPort(struct audio_port *port);
+
+    // Set audio port configuration.
+    virtual status_t setAudioPortConfig(const struct audio_port_config *config);
+
+    virtual status_t dump(int fd);
+
+  private:
+    friend class DevicesFactoryHalHidl;
+    sp<IDevice> mDevice;
+
+    // Can not be constructed directly by clients.
+    explicit DeviceHalHidl(const sp<IDevice>& device);
+
+    // The destructor automatically closes the device.
+    virtual ~DeviceHalHidl();
+};
+
+} // namespace android
+
+#endif // ANDROID_HARDWARE_DEVICE_HAL_HIDL_H
diff --git a/media/libaudiohal/DeviceHalLocal.cpp b/media/libaudiohal/DeviceHalLocal.cpp
index 78adfef..fc098f5 100644
--- a/media/libaudiohal/DeviceHalLocal.cpp
+++ b/media/libaudiohal/DeviceHalLocal.cpp
@@ -109,11 +109,17 @@
         const char *address,
         sp<StreamOutHalInterface> *outStream) {
     audio_stream_out_t *halStream;
+    ALOGV("open_output_stream handle: %d devices: %x flags: %#x"
+            "srate: %d format %#x channels %x address %s",
+            handle, devices, flags,
+            config->sample_rate, config->format, config->channel_mask,
+            address);
     int openResut = mDev->open_output_stream(
             mDev, handle, devices, flags, config, &halStream, address);
     if (openResut == OK) {
         *outStream = new StreamOutHalLocal(halStream, this);
     }
+    ALOGV("open_output_stream status %d stream %p", openResut, halStream);
     return openResut;
 }
 
@@ -126,11 +132,17 @@
         audio_source_t source,
         sp<StreamInHalInterface> *inStream) {
     audio_stream_in_t *halStream;
+    ALOGV("open_input_stream handle: %d devices: %x flags: %#x "
+            "srate: %d format %#x channels %x address %s source %d",
+            handle, devices, flags,
+            config->sample_rate, config->format, config->channel_mask,
+            address, source);
     int openResult = mDev->open_input_stream(
             mDev, handle, devices, config, &halStream, flags, address, source);
     if (openResult == OK) {
         *inStream = new StreamInHalLocal(halStream, this);
     }
+    ALOGV("open_input_stream status %d stream %p", openResult, inStream);
     return openResult;
 }
 
diff --git a/media/libaudiohal/DevicesFactoryHalHidl.cpp b/media/libaudiohal/DevicesFactoryHalHidl.cpp
new file mode 100644
index 0000000..155b1a8
--- /dev/null
+++ b/media/libaudiohal/DevicesFactoryHalHidl.cpp
@@ -0,0 +1,88 @@
+/*
+ * 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 <string.h>
+
+#define LOG_TAG "DevicesFactoryHalHidl"
+//#define LOG_NDEBUG 0
+
+#include <android/hardware/audio/2.0/IDevice.h>
+#include <utils/Log.h>
+
+#include "DeviceHalHidl.h"
+#include "DevicesFactoryHalHidl.h"
+
+using ::android::hardware::audio::V2_0::IDevice;
+using ::android::hardware::audio::V2_0::Result;
+using ::android::hardware::Return;
+using ::android::hardware::Status;
+
+namespace android {
+
+// static
+sp<DevicesFactoryHalInterface> DevicesFactoryHalInterface::create() {
+    return new DevicesFactoryHalHidl();
+}
+
+DevicesFactoryHalHidl::DevicesFactoryHalHidl() {
+    mDevicesFactory = IDevicesFactory::getService("audio_devices_factory");
+}
+
+DevicesFactoryHalHidl::~DevicesFactoryHalHidl() {
+}
+
+// static
+status_t DevicesFactoryHalHidl::nameFromHal(const char *name, IDevicesFactory::Device *device) {
+    if (strcmp(name, AUDIO_HARDWARE_MODULE_ID_PRIMARY) == 0) {
+        *device = IDevicesFactory::Device::PRIMARY;
+        return OK;
+    } else if(strcmp(name, AUDIO_HARDWARE_MODULE_ID_A2DP) == 0) {
+        *device = IDevicesFactory::Device::A2DP;
+        return OK;
+    } else if(strcmp(name, AUDIO_HARDWARE_MODULE_ID_USB) == 0) {
+        *device = IDevicesFactory::Device::USB;
+        return OK;
+    } else if(strcmp(name, AUDIO_HARDWARE_MODULE_ID_REMOTE_SUBMIX) == 0) {
+        *device = IDevicesFactory::Device::R_SUBMIX;
+        return OK;
+    }
+    ALOGE("Invalid device name %s", name);
+    return BAD_VALUE;
+}
+
+status_t DevicesFactoryHalHidl::openDevice(const char *name, sp<DeviceHalInterface> *device) {
+    if (mDevicesFactory == 0) return NO_INIT;
+    IDevicesFactory::Device hidlDevice;
+    status_t status = nameFromHal(name, &hidlDevice);
+    if (status != OK) return status;
+    Result retval = Result::NOT_INITIALIZED;
+    Return<void> ret = mDevicesFactory->openDevice(
+            hidlDevice,
+            [&](Result r, const sp<IDevice>& result) {
+                retval = r;
+                if (retval == Result::OK) {
+                    *device = new DeviceHalHidl(result);
+                }
+            });
+    if (ret.getStatus().isOk()) {
+        if (retval == Result::OK) return OK;
+        else if (retval == Result::INVALID_ARGUMENTS) return BAD_VALUE;
+        else return NO_INIT;
+    }
+    return ret.getStatus().transactionError();
+}
+
+} // namespace android
diff --git a/media/libaudiohal/DevicesFactoryHalHidl.h b/media/libaudiohal/DevicesFactoryHalHidl.h
new file mode 100644
index 0000000..a26dec1
--- /dev/null
+++ b/media/libaudiohal/DevicesFactoryHalHidl.h
@@ -0,0 +1,53 @@
+/*
+ * 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_DEVICES_FACTORY_HAL_HIDL_H
+#define ANDROID_HARDWARE_DEVICES_FACTORY_HAL_HIDL_H
+
+#include <android/hardware/audio/2.0/IDevicesFactory.h>
+#include <media/audiohal/DevicesFactoryHalInterface.h>
+#include <utils/Errors.h>
+#include <utils/RefBase.h>
+
+#include "DeviceHalHidl.h"
+
+using ::android::hardware::audio::V2_0::IDevicesFactory;
+
+namespace android {
+
+class DevicesFactoryHalHidl : public DevicesFactoryHalInterface
+{
+  public:
+    // Opens a device with the specified name. To close the device, it is
+    // necessary to release references to the returned object.
+    virtual status_t openDevice(const char *name, sp<DeviceHalInterface> *device);
+
+  private:
+    friend class DevicesFactoryHalInterface;
+
+    sp<IDevicesFactory> mDevicesFactory;
+
+    static status_t nameFromHal(const char *name, IDevicesFactory::Device *device);
+
+    // Can not be constructed directly by clients.
+    DevicesFactoryHalHidl();
+
+    virtual ~DevicesFactoryHalHidl();
+};
+
+} // namespace android
+
+#endif // ANDROID_HARDWARE_DEVICES_FACTORY_HAL_HIDL_H
diff --git a/media/libaudiohal/DevicesFactoryHalLocal.h b/media/libaudiohal/DevicesFactoryHalLocal.h
index 690cd34..58ce4ff 100644
--- a/media/libaudiohal/DevicesFactoryHalLocal.h
+++ b/media/libaudiohal/DevicesFactoryHalLocal.h
@@ -28,8 +28,6 @@
 class DevicesFactoryHalLocal : public DevicesFactoryHalInterface
 {
   public:
-    virtual ~DevicesFactoryHalLocal() {}
-
     // Opens a device with the specified name. To close the device, it is
     // necessary to release references to the returned object.
     virtual status_t openDevice(const char *name, sp<DeviceHalInterface> *device);
@@ -39,6 +37,8 @@
 
     // Can not be constructed directly by clients.
     DevicesFactoryHalLocal() {}
+
+    virtual ~DevicesFactoryHalLocal() {}
 };
 
 } // namespace android
diff --git a/media/libaudiohal/EffectHalHidl.cpp b/media/libaudiohal/EffectHalHidl.cpp
new file mode 100644
index 0000000..b508cb5
--- /dev/null
+++ b/media/libaudiohal/EffectHalHidl.cpp
@@ -0,0 +1,108 @@
+/*
+ * 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 "EffectHalHidl"
+//#define LOG_NDEBUG 0
+
+#include <media/EffectsFactoryApi.h>
+#include <utils/Log.h>
+
+#include "EffectHalHidl.h"
+#include "HidlUtils.h"
+
+using ::android::hardware::audio::effect::V2_0::Result;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Status;
+
+namespace android {
+
+EffectHalHidl::EffectHalHidl(const sp<IEffect>& effect, uint64_t effectId)
+        : mEffect(effect), mEffectId(effectId) {
+}
+
+EffectHalHidl::~EffectHalHidl() {
+}
+
+// static
+void EffectHalHidl::effectDescriptorToHal(
+        const EffectDescriptor& descriptor, effect_descriptor_t* halDescriptor) {
+    HidlUtils::uuidToHal(descriptor.type, &halDescriptor->type);
+    HidlUtils::uuidToHal(descriptor.uuid, &halDescriptor->uuid);
+    halDescriptor->flags = static_cast<uint32_t>(descriptor.flags);
+    halDescriptor->cpuLoad = descriptor.cpuLoad;
+    halDescriptor->memoryUsage = descriptor.memoryUsage;
+    memcpy(halDescriptor->name, descriptor.name.data(), descriptor.name.size());
+    memcpy(halDescriptor->implementor,
+            descriptor.implementor.data(), descriptor.implementor.size());
+}
+
+// static
+status_t EffectHalHidl::analyzeResult(const Result& result) {
+    switch (result) {
+        case Result::OK: return OK;
+        case Result::INVALID_ARGUMENTS: return BAD_VALUE;
+        case Result::INVALID_STATE: return NOT_ENOUGH_DATA;
+        case Result::NOT_INITIALIZED: return NO_INIT;
+        case Result::NOT_SUPPORTED: return INVALID_OPERATION;
+        case Result::RESULT_TOO_BIG: return NO_MEMORY;
+        default: return NO_INIT;
+    }
+}
+
+status_t EffectHalHidl::process(audio_buffer_t */*inBuffer*/, audio_buffer_t */*outBuffer*/) {
+    // Idea -- intercept set buffer config command, capture audio format, use it
+    // for determining frame size in bytes on input and output.
+    return OK;
+}
+
+status_t EffectHalHidl::processReverse(audio_buffer_t */*inBuffer*/, audio_buffer_t */*outBuffer*/) {
+    return OK;
+}
+
+status_t EffectHalHidl::command(uint32_t cmdCode, uint32_t cmdSize, void *pCmdData,
+        uint32_t *replySize, void *pReplyData) {
+    if (mEffect == 0) return NO_INIT;
+    hidl_vec<uint8_t> hidlData;
+    hidlData.setToExternal(reinterpret_cast<uint8_t*>(pCmdData), cmdSize);
+    status_t status;
+    Return<void> ret = mEffect->command(cmdCode, hidlData, *replySize,
+            [&](int32_t s, const hidl_vec<uint8_t>& result) {
+                status = s;
+                if (status == 0) {
+                    if (*replySize > result.size()) *replySize = result.size();
+                    if (pReplyData && *replySize > 0) {
+                        memcpy(pReplyData, &result[0], *replySize);
+                    }
+                }
+            });
+    return status;
+}
+
+status_t EffectHalHidl::getDescriptor(effect_descriptor_t *pDescriptor) {
+    if (mEffect == 0) return NO_INIT;
+    Result retval = Result::NOT_INITIALIZED;
+    Return<void> ret = mEffect->getDescriptor(
+            [&](Result r, const EffectDescriptor& result) {
+                retval = r;
+                if (retval == Result::OK) {
+                    effectDescriptorToHal(result, pDescriptor);
+                }
+            });
+    return ret.getStatus().isOk() ? analyzeResult(retval) : ret.getStatus().transactionError();
+}
+
+} // namespace android
diff --git a/media/libaudiohal/EffectHalHidl.h b/media/libaudiohal/EffectHalHidl.h
new file mode 100644
index 0000000..b79bee0
--- /dev/null
+++ b/media/libaudiohal/EffectHalHidl.h
@@ -0,0 +1,69 @@
+/*
+ * 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_HIDL_H
+#define ANDROID_HARDWARE_EFFECT_HAL_HIDL_H
+
+#include <android/hardware/audio/effect/2.0/IEffect.h>
+#include <media/audiohal/EffectHalInterface.h>
+#include <system/audio_effect.h>
+
+using ::android::hardware::audio::effect::V2_0::EffectDescriptor;
+using ::android::hardware::audio::effect::V2_0::IEffect;
+
+namespace android {
+
+class EffectHalHidl : public EffectHalInterface
+{
+  public:
+    // Effect process function. Takes input samples as specified
+    // in input buffer descriptor and output processed samples as specified
+    // in output buffer descriptor.
+    virtual status_t process(audio_buffer_t *inBuffer, audio_buffer_t *outBuffer);
+
+    // Process reverse stream function. This function is used to pass
+    // a reference stream to the effect engine.
+    virtual status_t processReverse(audio_buffer_t *inBuffer, audio_buffer_t *outBuffer);
+
+    // 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);
+
+    uint64_t effectId() const { return mEffectId; }
+
+    static void effectDescriptorToHal(
+            const EffectDescriptor& descriptor, effect_descriptor_t* halDescriptor);
+
+  private:
+    friend class EffectsFactoryHalHidl;
+    sp<IEffect> mEffect;
+    const uint64_t mEffectId;
+
+    static status_t analyzeResult(const hardware::audio::effect::V2_0::Result& result);
+
+    // Can not be constructed directly by clients.
+    EffectHalHidl(const sp<IEffect>& effect, uint64_t effectId);
+
+    // The destructor automatically releases the effect.
+    virtual ~EffectHalHidl();
+};
+
+} // namespace android
+
+#endif // ANDROID_HARDWARE_EFFECT_HAL_HIDL_H
diff --git a/media/libaudiohal/EffectsFactoryHalHidl.cpp b/media/libaudiohal/EffectsFactoryHalHidl.cpp
new file mode 100644
index 0000000..4f2eef0
--- /dev/null
+++ b/media/libaudiohal/EffectsFactoryHalHidl.cpp
@@ -0,0 +1,145 @@
+/*
+ * 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 "EffectsFactoryHalHidl"
+//#define LOG_NDEBUG 0
+
+#include <cutils/native_handle.h>
+#include <media/EffectsFactoryApi.h>
+
+#include "EffectHalHidl.h"
+#include "EffectsFactoryHalHidl.h"
+#include "HidlUtils.h"
+
+using ::android::hardware::audio::common::V2_0::Uuid;
+using ::android::hardware::audio::effect::V2_0::IEffect;
+using ::android::hardware::audio::effect::V2_0::Result;
+using ::android::hardware::Return;
+using ::android::hardware::Status;
+
+namespace android {
+
+// static
+sp<EffectsFactoryHalInterface> EffectsFactoryHalInterface::create() {
+    return new EffectsFactoryHalHidl();
+}
+
+// static
+bool EffectsFactoryHalInterface::isNullUuid(const effect_uuid_t *pEffectUuid) {
+    return EffectIsNullUuid(pEffectUuid);
+}
+
+EffectsFactoryHalHidl::EffectsFactoryHalHidl() {
+    mEffectsFactory = IEffectsFactory::getService("audio_effects_factory");
+}
+
+EffectsFactoryHalHidl::~EffectsFactoryHalHidl() {
+}
+
+status_t EffectsFactoryHalHidl::queryAllDescriptors() {
+    if (mEffectsFactory == 0) return NO_INIT;
+    Result retval = Result::NOT_INITIALIZED;
+    Return<void> ret = mEffectsFactory->getAllDescriptors(
+            [&](Result r, const hidl_vec<EffectDescriptor>& result) {
+                retval = r;
+                if (retval == Result::OK) {
+                    mLastDescriptors = result;
+                }
+            });
+    if (ret.getStatus().isOk()) {
+        return retval == Result::OK ? OK : NO_INIT;
+    }
+    mLastDescriptors.resize(0);
+    return ret.getStatus().transactionError();
+}
+
+status_t EffectsFactoryHalHidl::queryNumberEffects(uint32_t *pNumEffects) {
+    status_t queryResult = queryAllDescriptors();
+    if (queryResult == OK) {
+        *pNumEffects = mLastDescriptors.size();
+    }
+    return queryResult;
+}
+
+status_t EffectsFactoryHalHidl::getDescriptor(
+        uint32_t index, effect_descriptor_t *pDescriptor) {
+    // TODO: We need somehow to track the changes on the server side
+    // or figure out how to convert everybody to query all the descriptors at once.
+    // TODO: check for nullptr
+    if (mLastDescriptors.size() == 0) {
+        status_t queryResult = queryAllDescriptors();
+        if (queryResult != OK) return queryResult;
+    }
+    if (index >= mLastDescriptors.size()) return NAME_NOT_FOUND;
+    EffectHalHidl::effectDescriptorToHal(mLastDescriptors[index], pDescriptor);
+    return OK;
+}
+
+status_t EffectsFactoryHalHidl::getDescriptor(
+        const effect_uuid_t *pEffectUuid, effect_descriptor_t *pDescriptor) {
+    // TODO: check for nullptr
+    if (mEffectsFactory == 0) return NO_INIT;
+    Uuid hidlUuid;
+    HidlUtils::uuidFromHal(*pEffectUuid, &hidlUuid);
+    Result retval = Result::NOT_INITIALIZED;
+    Return<void> ret = mEffectsFactory->getDescriptor(hidlUuid,
+            [&](Result r, const EffectDescriptor& result) {
+                retval = r;
+                if (retval == Result::OK) {
+                    EffectHalHidl::effectDescriptorToHal(result, pDescriptor);
+                }
+            });
+    if (ret.getStatus().isOk()) {
+        if (retval == Result::OK) return OK;
+        else if (retval == Result::INVALID_ARGUMENTS) return NAME_NOT_FOUND;
+        else return NO_INIT;
+    }
+    return ret.getStatus().transactionError();
+}
+
+status_t EffectsFactoryHalHidl::createEffect(
+        const effect_uuid_t *pEffectUuid, int32_t sessionId, int32_t ioId,
+        sp<EffectHalInterface> *effect) {
+    if (mEffectsFactory == 0) return NO_INIT;
+    Uuid hidlUuid;
+    HidlUtils::uuidFromHal(*pEffectUuid, &hidlUuid);
+    Result retval = Result::NOT_INITIALIZED;
+    Return<void> ret = mEffectsFactory->createEffect(
+            hidlUuid, sessionId, ioId,
+            [&](Result r, const sp<IEffect>& result, uint64_t effectId) {
+                retval = r;
+                if (retval == Result::OK) {
+                    *effect = new EffectHalHidl(result, effectId);
+                }
+            });
+    if (ret.getStatus().isOk()) {
+        if (retval == Result::OK) return OK;
+        else if (retval == Result::INVALID_ARGUMENTS) return NAME_NOT_FOUND;
+        else return NO_INIT;
+    }
+    return ret.getStatus().transactionError();
+}
+
+status_t EffectsFactoryHalHidl::dumpEffects(int fd) {
+    if (mEffectsFactory == 0) return NO_INIT;
+    native_handle_t* hidlHandle = native_handle_create(1, 0);
+    hidlHandle->data[0] = fd;
+    Return<void> ret = mEffectsFactory->debugDump(hidlHandle);
+    native_handle_delete(hidlHandle);
+    return ret.getStatus().transactionError();
+}
+
+} // namespace android
diff --git a/media/libaudiohal/EffectsFactoryHalHidl.h b/media/libaudiohal/EffectsFactoryHalHidl.h
new file mode 100644
index 0000000..f16db17
--- /dev/null
+++ b/media/libaudiohal/EffectsFactoryHalHidl.h
@@ -0,0 +1,67 @@
+/*
+ * 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_HIDL_H
+#define ANDROID_HARDWARE_EFFECTS_FACTORY_HAL_HIDL_H
+
+#include <android/hardware/audio/effect/2.0/IEffectsFactory.h>
+#include <android/hardware/audio/effect/2.0/types.h>
+#include <media/audiohal/EffectsFactoryHalInterface.h>
+
+namespace android {
+
+using ::android::hardware::audio::effect::V2_0::EffectDescriptor;
+using ::android::hardware::audio::effect::V2_0::IEffectsFactory;
+using ::android::hardware::hidl_vec;
+
+class EffectsFactoryHalHidl : 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;
+
+    sp<IEffectsFactory> mEffectsFactory;
+    hidl_vec<EffectDescriptor> mLastDescriptors;
+
+    // Can not be constructed directly by clients.
+    EffectsFactoryHalHidl();
+    virtual ~EffectsFactoryHalHidl();
+
+    status_t queryAllDescriptors();
+};
+
+} // namespace android
+
+#endif // ANDROID_HARDWARE_EFFECTS_FACTORY_HAL_HIDL_H
diff --git a/media/libaudiohal/StreamHalHidl.cpp b/media/libaudiohal/StreamHalHidl.cpp
new file mode 100644
index 0000000..9383a36
--- /dev/null
+++ b/media/libaudiohal/StreamHalHidl.cpp
@@ -0,0 +1,384 @@
+/*
+ * 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 "StreamHalHidl"
+//#define LOG_NDEBUG 0
+
+#include <android/hardware/audio/2.0/IStreamOutCallback.h>
+#include <utils/Log.h>
+
+#include "DeviceHalHidl.h"
+#include "EffectHalHidl.h"
+#include "StreamHalHidl.h"
+
+using ::android::hardware::audio::common::V2_0::AudioChannelMask;
+using ::android::hardware::audio::common::V2_0::AudioFormat;
+using ::android::hardware::audio::V2_0::AudioDrain;
+using ::android::hardware::audio::V2_0::IStreamOutCallback;
+using ::android::hardware::audio::V2_0::ParameterValue;
+using ::android::hardware::audio::V2_0::Result;
+using ::android::hardware::audio::V2_0::TimeSpec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+
+namespace android {
+
+StreamHalHidl::StreamHalHidl(IStream *stream)
+        : ConversionHelperHidl("Stream"), mStream(stream) {
+}
+
+StreamHalHidl::~StreamHalHidl() {
+    mStream = nullptr;
+}
+
+status_t StreamHalHidl::getSampleRate(uint32_t *rate) {
+    if (!mStream) return NO_INIT;
+    return processReturn("getSampleRate", mStream->getSampleRate(), rate);
+}
+
+status_t StreamHalHidl::getBufferSize(size_t *size) {
+    if (!mStream) return NO_INIT;
+    return processReturn("getBufferSize", mStream->getBufferSize(), size);
+}
+
+status_t StreamHalHidl::getChannelMask(audio_channel_mask_t *mask) {
+    if (!mStream) return NO_INIT;
+    return processReturn("getChannelMask", mStream->getChannelMask(), mask);
+}
+
+status_t StreamHalHidl::getFormat(audio_format_t *format) {
+    if (!mStream) return NO_INIT;
+    return processReturn("getFormat", mStream->getFormat(), format);
+}
+
+status_t StreamHalHidl::getAudioProperties(
+        uint32_t *sampleRate, audio_channel_mask_t *mask, audio_format_t *format) {
+    if (!mStream) return NO_INIT;
+    Return<void> ret = mStream->getAudioProperties(
+            [&](uint32_t sr, AudioChannelMask m, AudioFormat f) {
+                *sampleRate = sr;
+                *mask = static_cast<audio_channel_mask_t>(m);
+                *format = static_cast<audio_format_t>(f);
+            });
+    return processReturn("getAudioProperties", ret);
+}
+
+status_t StreamHalHidl::setParameters(const String8& kvPairs) {
+    if (!mStream) return NO_INIT;
+    hidl_vec<ParameterValue> hidlParams;
+    status_t status = parametersFromHal(kvPairs, &hidlParams);
+    if (status != OK) return status;
+    return processReturn("setParameters", mStream->setParameters(hidlParams));
+}
+
+status_t StreamHalHidl::getParameters(const String8& keys, String8 *values) {
+    values->clear();
+    if (!mStream) return NO_INIT;
+    hidl_vec<hidl_string> hidlKeys;
+    status_t status = keysFromHal(keys, &hidlKeys);
+    if (status != OK) return status;
+    Result retval;
+    Return<void> ret = mStream->getParameters(
+            hidlKeys,
+            [&](Result r, const hidl_vec<ParameterValue>& parameters) {
+                retval = r;
+                if (retval == Result::OK) {
+                    parametersToHal(parameters, values);
+                }
+            });
+    return processReturn("getParameters", ret, retval);
+}
+
+status_t StreamHalHidl::addEffect(sp<EffectHalInterface> effect) {
+    if (!mStream) return NO_INIT;
+    return processReturn("addEffect", mStream->addEffect(
+                    static_cast<EffectHalHidl*>(effect.get())->effectId()));
+}
+
+status_t StreamHalHidl::removeEffect(sp<EffectHalInterface> effect) {
+    if (!mStream) return NO_INIT;
+    return processReturn("removeEffect", mStream->removeEffect(
+                    static_cast<EffectHalHidl*>(effect.get())->effectId()));
+}
+
+status_t StreamHalHidl::standby() {
+    if (!mStream) return NO_INIT;
+    return processReturn("standby", mStream->standby());
+}
+
+status_t StreamHalHidl::dump(int fd) {
+    if (!mStream) return NO_INIT;
+    native_handle_t* hidlHandle = native_handle_create(1, 0);
+    hidlHandle->data[0] = fd;
+    Return<void> ret = mStream->debugDump(hidlHandle);
+    native_handle_delete(hidlHandle);
+    return processReturn("dump", ret);
+}
+
+
+namespace {
+
+/* Notes on callback ownership.
+
+This is how (Hw)Binder ownership model looks like. The server implementation
+is owned by Binder framework (via sp<>). Proxies are owned by clients.
+When the last proxy disappears, Binder framework releases the server impl.
+
+Thus, it is not needed to keep any references to StreamOutCallback (this is
+the server impl) -- it will live as long as HAL server holds a strong ref to
+IStreamOutCallback proxy. We clear that reference by calling 'clearCallback'
+from the destructor of StreamOutHalHidl.
+
+The callback only keeps a weak reference to the stream. The stream is owned
+by AudioFlinger.
+
+*/
+
+struct StreamOutCallback : public IStreamOutCallback {
+    StreamOutCallback(const wp<StreamOutHalHidl>& stream) : mStream(stream) {}
+
+    // IStreamOutCallback implementation
+    Return<void> onWriteReady()  override {
+        sp<StreamOutHalHidl> stream = mStream.promote();
+        if (stream != 0) {
+            stream->onWriteReady();
+        }
+        return Void();
+    }
+
+    Return<void> onDrainReady()  override {
+        sp<StreamOutHalHidl> stream = mStream.promote();
+        if (stream != 0) {
+            stream->onDrainReady();
+        }
+        return Void();
+    }
+
+    Return<void> onError()  override {
+        sp<StreamOutHalHidl> stream = mStream.promote();
+        if (stream != 0) {
+            stream->onError();
+        }
+        return Void();
+    }
+
+  private:
+    wp<StreamOutHalHidl> mStream;
+};
+
+}  // namespace
+
+StreamOutHalHidl::StreamOutHalHidl(const sp<IStreamOut>& stream)
+        : StreamHalHidl(stream.get()), mStream(stream) {
+}
+
+StreamOutHalHidl::~StreamOutHalHidl() {
+    if (mCallback.unsafe_get() && mStream != 0) {
+        processReturn("clearCallback", mStream->clearCallback());
+    }
+    mCallback.clear();
+}
+
+status_t StreamOutHalHidl::getFrameSize(size_t *size) {
+    if (mStream == 0) return NO_INIT;
+    return processReturn("getFrameSize", mStream->getFrameSize(), size);
+}
+
+status_t StreamOutHalHidl::getLatency(uint32_t *latency) {
+    if (mStream == 0) return NO_INIT;
+    return processReturn("getLatency", mStream->getLatency(), latency);
+}
+
+status_t StreamOutHalHidl::setVolume(float left, float right) {
+    if (mStream == 0) return NO_INIT;
+    return processReturn("setVolume", mStream->setVolume(left, right));
+}
+
+status_t StreamOutHalHidl::write(const void *buffer, size_t bytes, size_t *written) {
+    if (mStream == 0) return NO_INIT;
+    hidl_vec<uint8_t> hidlData;
+    hidlData.setToExternal(static_cast<uint8_t*>(const_cast<void*>(buffer)), bytes);
+    Result retval;
+    Return<void> ret = mStream->write(
+            hidlData,
+            [&](Result r, uint64_t w) {
+                retval = r;
+                *written = w;
+            });
+    return processReturn("write", ret, retval);
+}
+
+status_t StreamOutHalHidl::getRenderPosition(uint32_t *dspFrames) {
+    if (mStream == 0) return NO_INIT;
+    Result retval;
+    Return<void> ret = mStream->getRenderPosition(
+            [&](Result r, uint32_t d) {
+                retval = r;
+                if (retval == Result::OK) {
+                    *dspFrames = d;
+                }
+            });
+    return processReturn("getRenderPosition", ret, retval);
+}
+
+status_t StreamOutHalHidl::getNextWriteTimestamp(int64_t *timestamp) {
+    if (mStream == 0) return NO_INIT;
+    Result retval;
+    Return<void> ret = mStream->getNextWriteTimestamp(
+            [&](Result r, int64_t t) {
+                retval = r;
+                if (retval == Result::OK) {
+                    *timestamp = t;
+                }
+            });
+    return processReturn("getRenderPosition", ret, retval);
+}
+
+status_t StreamOutHalHidl::setCallback(wp<StreamOutHalInterfaceCallback> callback) {
+    if (mStream == 0) return NO_INIT;
+    status_t status = processReturn(
+            "setCallback", mStream->setCallback(new StreamOutCallback(this)));
+    if (status == OK) {
+        mCallback = callback;
+    }
+    return status;
+}
+
+status_t StreamOutHalHidl::supportsPauseAndResume(bool *supportsPause, bool *supportsResume) {
+    if (mStream == 0) return NO_INIT;
+    Return<void> ret = mStream->supportsPauseAndResume(
+            [&](bool p, bool r) {
+                *supportsPause = p;
+                *supportsResume = r;
+            });
+    return processReturn("supportsPauseAndResume", ret);
+}
+
+status_t StreamOutHalHidl::pause() {
+    if (mStream == 0) return NO_INIT;
+    return processReturn("pause", mStream->pause());
+}
+
+status_t StreamOutHalHidl::resume() {
+    if (mStream == 0) return NO_INIT;
+    return processReturn("pause", mStream->resume());
+}
+
+status_t StreamOutHalHidl::supportsDrain(bool *supportsDrain) {
+    if (mStream == 0) return NO_INIT;
+    return processReturn("supportsDrain", mStream->supportsDrain(), supportsDrain);
+}
+
+status_t StreamOutHalHidl::drain(bool earlyNotify) {
+    if (mStream == 0) return NO_INIT;
+    return processReturn(
+            "drain", mStream->drain(earlyNotify ? AudioDrain::EARLY_NOTIFY : AudioDrain::ALL));
+}
+
+status_t StreamOutHalHidl::flush() {
+    if (mStream == 0) return NO_INIT;
+    return processReturn("pause", mStream->flush());
+}
+
+status_t StreamOutHalHidl::getPresentationPosition(uint64_t *frames, struct timespec *timestamp) {
+    if (mStream == 0) return NO_INIT;
+    Result retval;
+    Return<void> ret = mStream->getPresentationPosition(
+            [&](Result r, uint64_t hidlFrames, const TimeSpec& hidlTimeStamp) {
+                retval = r;
+                if (retval == Result::OK) {
+                    *frames = hidlFrames;
+                    timestamp->tv_sec = hidlTimeStamp.tvSec;
+                    timestamp->tv_nsec = hidlTimeStamp.tvNSec;
+                }
+            });
+    return processReturn("getPresentationPosition", ret, retval);
+}
+
+void StreamOutHalHidl::onWriteReady() {
+    sp<StreamOutHalInterfaceCallback> callback = mCallback.promote();
+    if (callback == 0) return;
+    ALOGV("asyncCallback onWriteReady");
+    callback->onWriteReady();
+}
+
+void StreamOutHalHidl::onDrainReady() {
+    sp<StreamOutHalInterfaceCallback> callback = mCallback.promote();
+    if (callback == 0) return;
+    ALOGV("asyncCallback onDrainReady");
+    callback->onDrainReady();
+}
+
+void StreamOutHalHidl::onError() {
+    sp<StreamOutHalInterfaceCallback> callback = mCallback.promote();
+    if (callback == 0) return;
+    ALOGV("asyncCallback onError");
+    callback->onError();
+}
+
+
+StreamInHalHidl::StreamInHalHidl(const sp<IStreamIn>& stream)
+        : StreamHalHidl(stream.get()), mStream(stream) {
+}
+
+StreamInHalHidl::~StreamInHalHidl() {
+}
+
+status_t StreamInHalHidl::getFrameSize(size_t *size) {
+    if (mStream == 0) return NO_INIT;
+    return processReturn("getFrameSize", mStream->getFrameSize(), size);
+}
+
+status_t StreamInHalHidl::setGain(float gain) {
+    if (mStream == 0) return NO_INIT;
+    return processReturn("setGain", mStream->setGain(gain));
+}
+
+status_t StreamInHalHidl::read(void *buffer, size_t bytes, size_t *read) {
+    if (mStream == 0) return NO_INIT;
+    Result retval;
+    Return<void> ret = mStream->read(
+            bytes,
+            [&](Result r, const hidl_vec<uint8_t>& hidlData) {
+                retval = r;
+                *read = std::min(hidlData.size(), bytes);
+                if (retval == Result::OK) {
+                    memcpy(buffer, &hidlData[0], *read);
+                }
+            });
+    return processReturn("read", ret, retval);
+}
+
+status_t StreamInHalHidl::getInputFramesLost(uint32_t *framesLost) {
+    if (mStream == 0) return NO_INIT;
+    return processReturn("getInputFramesLost", mStream->getInputFramesLost(), framesLost);
+}
+
+status_t StreamInHalHidl::getCapturePosition(int64_t *frames, int64_t *time) {
+    if (mStream == 0) return NO_INIT;
+    Result retval;
+    Return<void> ret = mStream->getCapturePosition(
+            [&](Result r, uint64_t hidlFrames, uint64_t hidlTime) {
+                retval = r;
+                if (retval == Result::OK) {
+                    *frames = hidlFrames;
+                    *time = hidlTime;
+                }
+            });
+    return processReturn("getCapturePosition", ret, retval);
+}
+
+} // namespace android
diff --git a/media/libaudiohal/StreamHalHidl.h b/media/libaudiohal/StreamHalHidl.h
new file mode 100644
index 0000000..e0a067e
--- /dev/null
+++ b/media/libaudiohal/StreamHalHidl.h
@@ -0,0 +1,174 @@
+/*
+ * 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_STREAM_HAL_HIDL_H
+#define ANDROID_HARDWARE_STREAM_HAL_HIDL_H
+
+#include <android/hardware/audio/2.0/IStream.h>
+#include <android/hardware/audio/2.0/IStreamIn.h>
+#include <android/hardware/audio/2.0/IStreamOut.h>
+#include <media/audiohal/StreamHalInterface.h>
+
+#include "ConversionHelperHidl.h"
+
+using ::android::hardware::audio::V2_0::IStream;
+using ::android::hardware::audio::V2_0::IStreamIn;
+using ::android::hardware::audio::V2_0::IStreamOut;
+using ::android::hardware::Return;
+
+namespace android {
+
+class DeviceHalHidl;
+
+class StreamHalHidl : public virtual StreamHalInterface, public ConversionHelperHidl
+{
+  public:
+    // Return the sampling rate in Hz - eg. 44100.
+    virtual status_t getSampleRate(uint32_t *rate);
+
+    // Return size of input/output buffer in bytes for this stream - eg. 4800.
+    virtual status_t getBufferSize(size_t *size);
+
+    // Return the channel mask.
+    virtual status_t getChannelMask(audio_channel_mask_t *mask);
+
+    // Return the audio format - e.g. AUDIO_FORMAT_PCM_16_BIT.
+    virtual status_t getFormat(audio_format_t *format);
+
+    // Convenience method.
+    virtual status_t getAudioProperties(
+            uint32_t *sampleRate, audio_channel_mask_t *mask, audio_format_t *format);
+
+    // Set audio stream parameters.
+    virtual status_t setParameters(const String8& kvPairs);
+
+    // Get audio stream parameters.
+    virtual status_t getParameters(const String8& keys, String8 *values);
+
+    // Add or remove the effect on the stream.
+    virtual status_t addEffect(sp<EffectHalInterface> effect);
+    virtual status_t removeEffect(sp<EffectHalInterface> effect);
+
+    // Put the audio hardware input/output into standby mode.
+    virtual status_t standby();
+
+    virtual status_t dump(int fd);
+
+  protected:
+    // Subclasses can not be constructed directly by clients.
+    explicit StreamHalHidl(IStream *stream);
+
+    // The destructor automatically closes the stream.
+    virtual ~StreamHalHidl();
+
+  private:
+    IStream *mStream;
+};
+
+class StreamOutHalHidl : public StreamOutHalInterface, public StreamHalHidl {
+  public:
+    // Return the frame size (number of bytes per sample) of a stream.
+    virtual status_t getFrameSize(size_t *size);
+
+    // Return the audio hardware driver estimated latency in milliseconds.
+    virtual status_t getLatency(uint32_t *latency);
+
+    // Use this method in situations where audio mixing is done in the hardware.
+    virtual status_t setVolume(float left, float right);
+
+    // Write audio buffer to driver.
+    virtual status_t write(const void *buffer, size_t bytes, size_t *written);
+
+    // Return the number of audio frames written by the audio dsp to DAC since
+    // the output has exited standby.
+    virtual status_t getRenderPosition(uint32_t *dspFrames);
+
+    // Get the local time at which the next write to the audio driver will be presented.
+    virtual status_t getNextWriteTimestamp(int64_t *timestamp);
+
+    // Set the callback for notifying completion of non-blocking write and drain.
+    virtual status_t setCallback(wp<StreamOutHalInterfaceCallback> callback);
+
+    // Returns whether pause and resume operations are supported.
+    virtual status_t supportsPauseAndResume(bool *supportsPause, bool *supportsResume);
+
+    // Notifies to the audio driver to resume playback following a pause.
+    virtual status_t pause();
+
+    // Notifies to the audio driver to resume playback following a pause.
+    virtual status_t resume();
+
+    // Returns whether drain operation is supported.
+    virtual status_t supportsDrain(bool *supportsDrain);
+
+    // Requests notification when data buffered by the driver/hardware has been played.
+    virtual status_t drain(bool earlyNotify);
+
+    // Notifies to the audio driver to flush the queued data.
+    virtual status_t flush();
+
+    // Return a recent count of the number of audio frames presented to an external observer.
+    virtual status_t getPresentationPosition(uint64_t *frames, struct timespec *timestamp);
+
+    // Methods used by StreamOutCallback (HIDL).
+    void onWriteReady();
+    void onDrainReady();
+    void onError();
+
+  private:
+    friend class DeviceHalHidl;
+
+    wp<StreamOutHalInterfaceCallback> mCallback;
+    sp<IStreamOut> mStream;
+
+    // Can not be constructed directly by clients.
+    StreamOutHalHidl(const sp<IStreamOut>& stream);
+
+    virtual ~StreamOutHalHidl();
+};
+
+class StreamInHalHidl : public StreamInHalInterface, public StreamHalHidl {
+  public:
+    // Return the frame size (number of bytes per sample) of a stream.
+    virtual status_t getFrameSize(size_t *size);
+
+    // Set the input gain for the audio driver.
+    virtual status_t setGain(float gain);
+
+    // Read audio buffer in from driver.
+    virtual status_t read(void *buffer, size_t bytes, size_t *read);
+
+    // Return the amount of input frames lost in the audio driver.
+    virtual status_t getInputFramesLost(uint32_t *framesLost);
+
+    // Return a recent count of the number of audio frames received and
+    // the clock time associated with that frame count.
+    virtual status_t getCapturePosition(int64_t *frames, int64_t *time);
+
+  private:
+    friend class DeviceHalHidl;
+
+    sp<IStreamIn> mStream;
+
+    // Can not be constructed directly by clients.
+    StreamInHalHidl(const sp<IStreamIn>& stream);
+
+    virtual ~StreamInHalHidl();
+};
+
+} // namespace android
+
+#endif // ANDROID_HARDWARE_STREAM_HAL_HIDL_H
diff --git a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
index a3d6761..af8cb50 100644
--- a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
+++ b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
@@ -3105,10 +3105,6 @@
             //ALOGV("\tEffect_command cmdCode Case: EFFECT_CMD_GET_PARAM start");
 
             effect_param_t *p = (effect_param_t *)pCmdData;
-            if (SIZE_MAX - sizeof(effect_param_t) < (size_t)p->psize) {
-                android_errorWriteLog(0x534e4554, "26347509");
-                return -EINVAL;
-            }
             if (pCmdData == NULL || cmdSize < sizeof(effect_param_t) ||
                     cmdSize < (sizeof(effect_param_t) + p->psize) ||
                     pReplyData == NULL || replySize == NULL ||
@@ -3116,13 +3112,32 @@
                 ALOGV("\tLVM_ERROR : EFFECT_CMD_GET_PARAM: ERROR");
                 return -EINVAL;
             }
+            if (EFFECT_PARAM_SIZE_MAX - sizeof(effect_param_t) < (size_t)p->psize) {
+                android_errorWriteLog(0x534e4554, "26347509");
+                ALOGV("\tLVM_ERROR : EFFECT_CMD_GET_PARAM: psize too big");
+                return -EINVAL;
+            }
+            uint32_t paddedParamSize = ((p->psize + sizeof(int32_t) - 1) / sizeof(int32_t)) *
+                    sizeof(int32_t);
+            if ((EFFECT_PARAM_SIZE_MAX - sizeof(effect_param_t) < paddedParamSize) ||
+                (EFFECT_PARAM_SIZE_MAX - sizeof(effect_param_t) - paddedParamSize <
+                    p->vsize)) {
+                ALOGV("\tLVM_ERROR : EFFECT_CMD_GET_PARAM: padded_psize or vsize too big");
+                return -EINVAL;
+            }
+            uint32_t expectedReplySize = sizeof(effect_param_t) + paddedParamSize + p->vsize;
+            if (*replySize < expectedReplySize) {
+                ALOGV("\tLVM_ERROR : EFFECT_CMD_GET_PARAM: min. replySize %u, got %u bytes",
+                        expectedReplySize, *replySize);
+                android_errorWriteLog(0x534e4554, "32705438");
+                return -EINVAL;
+            }
 
             memcpy(pReplyData, pCmdData, sizeof(effect_param_t) + p->psize);
 
             p = (effect_param_t *)pReplyData;
 
-            int voffset = ((p->psize - 1) / sizeof(int32_t) + 1) * sizeof(int32_t);
-
+            uint32_t voffset = paddedParamSize;
             if(pContext->EffectType == LVM_BASS_BOOST){
                 p->status = android::BassBoost_getParameter(pContext,
                                                             p->data,
diff --git a/media/libmedia/Android.mk b/media/libmedia/Android.mk
index 2e4cf7d..02947b0 100644
--- a/media/libmedia/Android.mk
+++ b/media/libmedia/Android.mk
@@ -12,6 +12,7 @@
 LOCAL_SRC_FILES += \
     IDataSource.cpp \
     IHDCP.cpp \
+    BufferingSettings.cpp \
     mediaplayer.cpp \
     IMediaCodecList.cpp \
     IMediaCodecService.cpp \
@@ -25,6 +26,7 @@
     IMediaPlayer.cpp \
     IMediaRecorder.cpp \
     IMediaSource.cpp \
+    IMediaAnalyticsService.cpp \
     IRemoteDisplay.cpp \
     IRemoteDisplayClient.cpp \
     IResourceManagerClient.cpp \
@@ -33,6 +35,7 @@
     MediaCodecBuffer.cpp \
     MediaCodecInfo.cpp \
     MediaDefs.cpp \
+    MediaAnalyticsItem.cpp \
     MediaUtils.cpp \
     Metadata.cpp \
     mediarecorder.cpp \
@@ -58,7 +61,7 @@
         libcamera_client libstagefright_foundation \
         libgui libdl libaudioutils libaudioclient
 
-LOCAL_EXPORT_SHARED_LIBRARY_HEADERS := libbinder
+LOCAL_EXPORT_SHARED_LIBRARY_HEADERS := libbinder libsonivox
 
 LOCAL_WHOLE_STATIC_LIBRARIES := libmedia_helper
 
diff --git a/media/libmedia/AudioParameter.cpp b/media/libmedia/AudioParameter.cpp
index d244a0a..65fc70b 100644
--- a/media/libmedia/AudioParameter.cpp
+++ b/media/libmedia/AudioParameter.cpp
@@ -189,6 +189,16 @@
     return result;
 }
 
+status_t AudioParameter::getAt(size_t index, String8& key) const
+{
+    if (mParameters.size() > index) {
+        key = mParameters.keyAt(index);
+        return NO_ERROR;
+    } else {
+        return BAD_VALUE;
+    }
+}
+
 status_t AudioParameter::getAt(size_t index, String8& key, String8& value) const
 {
     if (mParameters.size() > index) {
diff --git a/media/libmedia/BufferingSettings.cpp b/media/libmedia/BufferingSettings.cpp
new file mode 100644
index 0000000..6dc4a53
--- /dev/null
+++ b/media/libmedia/BufferingSettings.cpp
@@ -0,0 +1,73 @@
+/*
+ * 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 "BufferingSettings"
+//#define LOG_NDEBUG 0
+
+#include <binder/Parcel.h>
+
+#include <media/BufferingSettings.h>
+
+namespace android {
+
+// static
+bool BufferingSettings::IsValidBufferingMode(int mode) {
+    return (mode >= BUFFERING_MODE_NONE && mode < BUFFERING_MODE_COUNT);
+}
+
+BufferingSettings::BufferingSettings()
+        : mInitialBufferingMode(BUFFERING_MODE_NONE),
+          mRebufferingMode(BUFFERING_MODE_NONE),
+          mInitialWatermarkMs(kNoWatermark),
+          mInitialWatermarkKB(kNoWatermark),
+          mRebufferingWatermarkLowMs(kNoWatermark),
+          mRebufferingWatermarkHighMs(kNoWatermark),
+          mRebufferingWatermarkLowKB(kNoWatermark),
+          mRebufferingWatermarkHighKB(kNoWatermark) { }
+
+status_t BufferingSettings::readFromParcel(const Parcel* parcel) {
+    if (parcel == nullptr) {
+        return BAD_VALUE;
+    }
+    mInitialBufferingMode = (BufferingMode)parcel->readInt32();
+    mRebufferingMode = (BufferingMode)parcel->readInt32();
+    mInitialWatermarkMs = parcel->readInt32();
+    mInitialWatermarkKB = parcel->readInt32();
+    mRebufferingWatermarkLowMs = parcel->readInt32();
+    mRebufferingWatermarkHighMs = parcel->readInt32();
+    mRebufferingWatermarkLowKB = parcel->readInt32();
+    mRebufferingWatermarkHighKB = parcel->readInt32();
+
+    return OK;
+}
+
+status_t BufferingSettings::writeToParcel(Parcel* parcel) const {
+    if (parcel == nullptr) {
+        return BAD_VALUE;
+    }
+    parcel->writeInt32(mInitialBufferingMode);
+    parcel->writeInt32(mRebufferingMode);
+    parcel->writeInt32(mInitialWatermarkMs);
+    parcel->writeInt32(mInitialWatermarkKB);
+    parcel->writeInt32(mRebufferingWatermarkLowMs);
+    parcel->writeInt32(mRebufferingWatermarkHighMs);
+    parcel->writeInt32(mRebufferingWatermarkLowKB);
+    parcel->writeInt32(mRebufferingWatermarkHighKB);
+
+    return OK;
+}
+
+} // namespace android
diff --git a/media/libmedia/IMediaAnalyticsService.cpp b/media/libmedia/IMediaAnalyticsService.cpp
new file mode 100644
index 0000000..afe9c36
--- /dev/null
+++ b/media/libmedia/IMediaAnalyticsService.cpp
@@ -0,0 +1,241 @@
+/*
+ * 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 "MediaAnalytics"
+
+#include <stdint.h>
+#include <inttypes.h>
+#include <sys/types.h>
+
+#include <binder/Parcel.h>
+#include <binder/IMemory.h>
+#include <binder/IPCThreadState.h>
+#include <media/IHDCP.h>
+#include <media/IMediaCodecList.h>
+#include <media/IMediaHTTPService.h>
+#include <media/IMediaPlayerService.h>
+#include <media/IMediaRecorder.h>
+#include <media/IOMX.h>
+#include <media/IRemoteDisplay.h>
+#include <media/IRemoteDisplayClient.h>
+#include <media/IStreamSource.h>
+
+#include <utils/Errors.h>  // for status_t
+#include <utils/List.h>
+#include <utils/Log.h>
+#include <utils/String8.h>
+
+#include <media/MediaAnalyticsItem.h>
+#include <media/IMediaAnalyticsService.h>
+
+#define DEBUGGING               0
+#define DEBUGGING_FLOW          0
+#define DEBUGGING_RETURNS       0
+
+namespace android {
+
+enum {
+    GENERATE_UNIQUE_SESSIONID = IBinder::FIRST_CALL_TRANSACTION,
+    SUBMIT_ITEM,
+    GET_ITEM_LIST,
+};
+
+class BpMediaAnalyticsService: public BpInterface<IMediaAnalyticsService>
+{
+public:
+    explicit BpMediaAnalyticsService(const sp<IBinder>& impl)
+        : BpInterface<IMediaAnalyticsService>(impl)
+    {
+    }
+
+    virtual MediaAnalyticsItem::SessionID_t generateUniqueSessionID() {
+        Parcel data, reply;
+        status_t err;
+        MediaAnalyticsItem::SessionID_t sessionid =
+                        MediaAnalyticsItem::SessionIDInvalid;
+
+        data.writeInterfaceToken(IMediaAnalyticsService::getInterfaceDescriptor());
+        err = remote()->transact(GENERATE_UNIQUE_SESSIONID, data, &reply);
+        if (err != NO_ERROR) {
+            ALOGW("bad response from service");
+            return MediaAnalyticsItem::SessionIDInvalid;
+        }
+        sessionid = reply.readInt64();
+        if (DEBUGGING_RETURNS) {
+            ALOGD("the caller gets a sessionid of %" PRId64 " back", sessionid);
+        }
+        return sessionid;
+    }
+
+    virtual MediaAnalyticsItem::SessionID_t submit(sp<MediaAnalyticsItem> item, bool forcenew)
+    {
+        // have this record submit itself
+        // this will be a binder call with appropriate timing
+        // return value is the uuid that the system generated for it.
+        // the return value 0 and -1 are reserved.
+        // -1 to indicate that there was a problem recording...
+
+        Parcel data, reply;
+        status_t err;
+
+        if (item == NULL) {
+                return MediaAnalyticsItem::SessionIDInvalid;
+        }
+
+        data.writeInterfaceToken(IMediaAnalyticsService::getInterfaceDescriptor());
+        if(DEBUGGING_FLOW) {
+            ALOGD("client offers record: %s", item->toString().c_str());
+        }
+        data.writeBool(forcenew);
+        item->writeToParcel(&data);
+
+        err = remote()->transact(SUBMIT_ITEM, data, &reply);
+        if (err != NO_ERROR) {
+            return MediaAnalyticsItem::SessionIDInvalid;
+        }
+
+        // get an answer out of 'reply'
+        int64_t sessionid = reply.readInt64();
+        if (DEBUGGING_RETURNS) {
+            ALOGD("the caller gets sessionid=%" PRId64 "", sessionid);
+        }
+        return sessionid;
+    }
+
+    virtual List<sp<MediaAnalyticsItem>> *getMediaAnalyticsItemList(bool finished, nsecs_t ts)
+    {
+            return getMediaAnalyticsItemList(finished, ts, MediaAnalyticsItem::kKeyAny);
+    }
+
+    virtual List<sp<MediaAnalyticsItem>> *getMediaAnalyticsItemList(bool finished, nsecs_t ts, MediaAnalyticsItem::Key key)
+    {
+        Parcel data, reply;
+        status_t err;
+
+        data.writeInterfaceToken(IMediaAnalyticsService::getInterfaceDescriptor());
+        data.writeInt32(finished);
+        data.writeInt64(ts);
+        const char *str = key.c_str();
+        if (key.empty()) {
+            str = MediaAnalyticsItem::kKeyNone.c_str();
+        }
+        data.writeCString(str);
+        err = remote()->transact(GET_ITEM_LIST, data, &reply);
+	if (err != NO_ERROR) {
+	    return NULL;
+	}
+
+        // read a count
+        int32_t count = reply.readInt32();
+        List<sp<MediaAnalyticsItem>> *list = NULL;
+
+        if (count > 0) {
+            list = new List<sp<MediaAnalyticsItem>>();
+            for (int i=0;i<count;i++) {
+                sp<MediaAnalyticsItem> item = new MediaAnalyticsItem;
+                // XXX: watch for failures here
+                item->readFromParcel(reply);
+                list->push_back(item);
+            }
+        }
+
+        return list;
+    }
+};
+
+IMPLEMENT_META_INTERFACE(MediaAnalyticsService, "android.media.IMediaAnalyticsService");
+
+// ----------------------------------------------------------------------
+
+status_t BnMediaAnalyticsService::onTransact(
+    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+
+
+    // get calling pid/tid
+    IPCThreadState *ipc = IPCThreadState::self();
+    int clientPid = ipc->getCallingPid();
+    // permission checking
+
+    if(DEBUGGING_FLOW) {
+        ALOGD("running in service, code %d, pid %d; called from pid %d",
+            code, getpid(), clientPid);
+    }
+
+    switch (code) {
+
+        case GENERATE_UNIQUE_SESSIONID: {
+            CHECK_INTERFACE(IMediaAnalyticsService, data, reply);
+
+            MediaAnalyticsItem::SessionID_t sessionid = generateUniqueSessionID();
+            reply->writeInt64(sessionid);
+
+            return NO_ERROR;
+        } break;
+
+        case SUBMIT_ITEM: {
+            CHECK_INTERFACE(IMediaAnalyticsService, data, reply);
+
+            bool forcenew;
+            sp<MediaAnalyticsItem> item = new MediaAnalyticsItem;
+
+            data.readBool(&forcenew);
+            item->readFromParcel(data);
+
+            item->setPid(clientPid);
+
+	    // submit() takes ownership of / responsibility for the item
+            MediaAnalyticsItem::SessionID_t sessionid = submit(item, forcenew);
+            reply->writeInt64(sessionid);
+
+            return NO_ERROR;
+        } break;
+
+        case GET_ITEM_LIST: {
+            CHECK_INTERFACE(IMediaPlayerService, data, reply);
+            // get the parameters
+            bool finished = data.readInt32();
+            nsecs_t ts = data.readInt64();
+            MediaAnalyticsItem::Key key = data.readCString();
+
+            // find the (0 or more) items
+            List<sp<MediaAnalyticsItem>> *list =  getMediaAnalyticsItemList(finished, ts, key);
+            // encapsulate/serialize them
+            reply->writeInt32(list->size());
+            if (list->size() > 0) {
+                    for (List<sp<MediaAnalyticsItem>>::iterator it = list->begin();
+                         it != list->end(); it++) {
+                            (*it)->writeToParcel(reply);
+                    }
+
+
+            }
+
+            // avoid leakiness; organized discarding of list and its contents
+            list->clear();
+            delete list;
+
+            return NO_ERROR;
+        } break;
+
+        default:
+            return BBinder::onTransact(code, data, reply, flags);
+    }
+}
+
+// ----------------------------------------------------------------------------
+
+} // namespace android
diff --git a/media/libmedia/IMediaPlayer.cpp b/media/libmedia/IMediaPlayer.cpp
index dda2570..9ffde4e 100644
--- a/media/libmedia/IMediaPlayer.cpp
+++ b/media/libmedia/IMediaPlayer.cpp
@@ -23,6 +23,7 @@
 
 #include <media/AudioResamplerPublic.h>
 #include <media/AVSyncSettings.h>
+#include <media/BufferingSettings.h>
 
 #include <media/IDataSource.h>
 #include <media/IMediaHTTPService.h>
@@ -40,6 +41,8 @@
     SET_DATA_SOURCE_FD,
     SET_DATA_SOURCE_STREAM,
     SET_DATA_SOURCE_CALLBACK,
+    SET_BUFFERING_SETTINGS,
+    GET_DEFAULT_BUFFERING_SETTINGS,
     PREPARE_ASYNC,
     START,
     STOP,
@@ -148,6 +151,30 @@
         return reply.readInt32();
     }
 
+    status_t setBufferingSettings(const BufferingSettings& buffering)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
+        buffering.writeToParcel(&data);
+        remote()->transact(SET_BUFFERING_SETTINGS, data, &reply);
+        return reply.readInt32();
+    }
+
+    status_t getDefaultBufferingSettings(BufferingSettings* buffering /* nonnull */)
+    {
+        if (buffering == nullptr) {
+            return BAD_VALUE;
+        }
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
+        remote()->transact(GET_DEFAULT_BUFFERING_SETTINGS, data, &reply);
+        status_t err = reply.readInt32();
+        if (err == OK) {
+            err = buffering->readFromParcel(&reply);
+        }
+        return err;
+    }
+
     status_t prepareAsync()
     {
         Parcel data, reply;
@@ -497,6 +524,23 @@
             reply->writeInt32(setVideoSurfaceTexture(bufferProducer));
             return NO_ERROR;
         } break;
+        case SET_BUFFERING_SETTINGS: {
+            CHECK_INTERFACE(IMediaPlayer, data, reply);
+            BufferingSettings buffering;
+            buffering.readFromParcel(&data);
+            reply->writeInt32(setBufferingSettings(buffering));
+            return NO_ERROR;
+        } break;
+        case GET_DEFAULT_BUFFERING_SETTINGS: {
+            CHECK_INTERFACE(IMediaPlayer, data, reply);
+            BufferingSettings buffering;
+            status_t err = getDefaultBufferingSettings(&buffering);
+            reply->writeInt32(err);
+            if (err == OK) {
+                buffering.writeToParcel(reply);
+            }
+            return NO_ERROR;
+        } break;
         case PREPARE_ASYNC: {
             CHECK_INTERFACE(IMediaPlayer, data, reply);
             reply->writeInt32(prepareAsync());
diff --git a/media/libmedia/IOMX.cpp b/media/libmedia/IOMX.cpp
index c1fe87f..3d466b1 100644
--- a/media/libmedia/IOMX.cpp
+++ b/media/libmedia/IOMX.cpp
@@ -590,7 +590,7 @@
                     params = mmap(NULL, allocSize, PROT_READ | PROT_WRITE,
                             MAP_PRIVATE | MAP_ANONYMOUS, -1 /* fd */, 0 /* offset */);
                 }
-                if (params != MAP_FAILED) {
+                if (params != MAP_FAILED && params != NULL) {
                     err = data.read(params, size);
                     if (err != OK) {
                         android_errorWriteLog(0x534e4554, "26914474");
diff --git a/media/libmedia/MediaAnalyticsItem.cpp b/media/libmedia/MediaAnalyticsItem.cpp
new file mode 100644
index 0000000..5f05d5a
--- /dev/null
+++ b/media/libmedia/MediaAnalyticsItem.cpp
@@ -0,0 +1,703 @@
+/*
+ * 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.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "MediaAnalyticsItem"
+
+#include <sys/types.h>
+#include <inttypes.h>
+
+#include <binder/Parcel.h>
+#include <utils/Errors.h>
+#include <utils/Log.h>
+#include <utils/Mutex.h>
+#include <utils/RefBase.h>
+#include <utils/SortedVector.h>
+#include <utils/threads.h>
+
+#include <media/stagefright/foundation/AString.h>
+
+#include <binder/IServiceManager.h>
+#include <media/IMediaAnalyticsService.h>
+#include <media/MediaAnalyticsItem.h>
+
+namespace android {
+
+#define DEBUG_SERVICEACCESS     0
+
+// the few universal keys we have
+const MediaAnalyticsItem::Key MediaAnalyticsItem::kKeyAny  = "any";
+const MediaAnalyticsItem::Key MediaAnalyticsItem::kKeyNone  = "none";
+
+const char * const MediaAnalyticsItem::EnabledProperty  = "media.analytics.enabled";
+const char * const MediaAnalyticsItem::EnabledPropertyPersist  = "persist.media.analytics.enabled";
+const int MediaAnalyticsItem::EnabledProperty_default  = 0;
+
+
+// access functions for the class
+MediaAnalyticsItem::MediaAnalyticsItem()
+    : RefBase(),
+      mPid(0),
+      mUid(0),
+      mSessionID(MediaAnalyticsItem::SessionIDNone),
+      mTimestamp(0),
+      mFinalized(0) {
+    mKey = MediaAnalyticsItem::kKeyNone;
+}
+
+MediaAnalyticsItem::MediaAnalyticsItem(MediaAnalyticsItem::Key key)
+    : RefBase(),
+      mPid(0),
+      mUid(0),
+      mSessionID(MediaAnalyticsItem::SessionIDNone),
+      mTimestamp(0),
+      mFinalized(0) {
+    mKey = key;
+}
+
+MediaAnalyticsItem::~MediaAnalyticsItem() {
+    clear();
+}
+
+// so clients can send intermediate values to be overlaid later
+MediaAnalyticsItem &MediaAnalyticsItem::setFinalized(bool value) {
+    mFinalized = value;
+    return *this;
+}
+
+bool MediaAnalyticsItem::getFinalized() const {
+    return mFinalized;
+}
+
+MediaAnalyticsItem &MediaAnalyticsItem::setSessionID(MediaAnalyticsItem::SessionID_t id) {
+    mSessionID = id;
+    return *this;
+}
+
+MediaAnalyticsItem::SessionID_t MediaAnalyticsItem::getSessionID() const {
+    return mSessionID;
+}
+
+MediaAnalyticsItem::SessionID_t MediaAnalyticsItem::generateSessionID() {
+    MediaAnalyticsItem::SessionID_t newid = SessionIDNone;
+    ALOGD("generateSessionID()");
+
+    if (mSessionID == SessionIDNone) {
+        // get one from the server
+        sp<IMediaAnalyticsService> svc = getInstance();
+        if (svc != NULL) {
+            newid = svc->generateUniqueSessionID();
+        }
+        mSessionID = newid;
+    }
+
+    return mSessionID;
+}
+
+MediaAnalyticsItem &MediaAnalyticsItem::clearSessionID() {
+    mSessionID = MediaAnalyticsItem::SessionIDNone;
+    return *this;
+}
+
+MediaAnalyticsItem &MediaAnalyticsItem::setTimestamp(nsecs_t ts) {
+    mTimestamp = ts;
+    return *this;
+}
+
+nsecs_t MediaAnalyticsItem::getTimestamp() const {
+    return mTimestamp;
+}
+
+MediaAnalyticsItem &MediaAnalyticsItem::setPid(pid_t pid) {
+    mPid = pid;
+    return *this;
+}
+
+pid_t MediaAnalyticsItem::getPid() const {
+    return mPid;
+}
+
+MediaAnalyticsItem &MediaAnalyticsItem::setUid(uid_t uid) {
+    mUid = uid;
+    return *this;
+}
+
+uid_t MediaAnalyticsItem::getUid() const {
+    return mUid;
+}
+
+void MediaAnalyticsItem::clear() {
+
+    mKey.clear();
+
+#if 0
+    // not sure that I need to (or should) be doing this...
+    // seeing some strangeness in some records
+    int count = mItems.size();
+    for (int i = 0 ; i < count; i++ ) {
+        MediaAnalyticsItem::Attr attr = mItems.keyAt(i);
+        const sp<Item> value = mItems.valueAt(i);
+        value->clear();
+        attr.clear();
+    }
+    mItems.clear();
+#endif
+
+    return;
+}
+
+// this key is for the overall record -- "vid" or "aud"
+// assuming for the moment we use int32_t like the
+// media frameworks MetaData.cpp
+MediaAnalyticsItem &MediaAnalyticsItem::setKey(MediaAnalyticsItem::Key key) {
+    // XXX: possible validation of legal keys.
+    mKey = key;
+    return *this;
+}
+
+MediaAnalyticsItem::Key MediaAnalyticsItem::getKey() {
+    return mKey;
+}
+
+// number of keys we have in our dictionary
+// we won't upload empty records
+int32_t MediaAnalyticsItem::count() const {
+    return mItems.size();
+}
+
+// set the values
+bool MediaAnalyticsItem::setInt32(MediaAnalyticsItem::Attr attr, int32_t value) {
+    ssize_t i = mItems.indexOfKey(attr);
+    bool overwrote = true;
+    if (i<0) {
+        sp<Item> item = new Item();
+        i = mItems.add(attr, item);
+        overwrote = false;
+    }
+    sp<Item> &item = mItems.editValueAt(i);
+    item->mType = MediaAnalyticsItem::Item::kTypeInt32;
+    item->u.int32Value = value;
+    return overwrote;
+}
+
+bool MediaAnalyticsItem::setInt64(MediaAnalyticsItem::Attr attr, int64_t value) {
+    ssize_t i = mItems.indexOfKey(attr);
+    bool overwrote = true;
+    if (i<0) {
+        sp<Item> item = new Item();
+        i = mItems.add(attr, item);
+        overwrote = false;
+    }
+    sp<Item> &item = mItems.editValueAt(i);
+    item->mType = MediaAnalyticsItem::Item::kTypeInt64;
+    item->u.int64Value = value;
+    return overwrote;
+}
+
+bool MediaAnalyticsItem::setDouble(MediaAnalyticsItem::Attr attr, double value) {
+    ssize_t i = mItems.indexOfKey(attr);
+    bool overwrote = true;
+    if (i<0) {
+        sp<Item> item = new Item();
+        i = mItems.add(attr, item);
+        overwrote = false;
+    }
+    sp<Item> &item = mItems.editValueAt(i);
+    item->mType = MediaAnalyticsItem::Item::kTypeDouble;
+    item->u.doubleValue = value;
+    return overwrote;
+}
+
+bool MediaAnalyticsItem::setCString(MediaAnalyticsItem::Attr attr, const char *value) {
+    bool overwrote = true;
+    if (value == NULL) return false;
+    // we store our own copy of the supplied string
+    char *nvalue = strdup(value);
+    if (nvalue == NULL) {
+            return false;
+    }
+    ssize_t i = mItems.indexOfKey(attr);
+    if (i<0) {
+        sp<Item> item = new Item();
+        i = mItems.add(attr, item);
+        overwrote = false;
+    }
+    sp<Item> &item = mItems.editValueAt(i);
+    if (item->mType == MediaAnalyticsItem::Item::kTypeCString
+        && item->u.CStringValue != NULL) {
+            free(item->u.CStringValue);
+            item->u.CStringValue = NULL;
+    }
+    item->mType = MediaAnalyticsItem::Item::kTypeCString;
+    item->u.CStringValue = nvalue;
+    return true;
+}
+
+// find/add/set fused into a single operation
+bool MediaAnalyticsItem::addInt32(MediaAnalyticsItem::Attr attr, int32_t value) {
+    ssize_t i = mItems.indexOfKey(attr);
+    bool overwrote = true;
+    if (i<0) {
+        sp<Item> item = new Item();
+        i = mItems.add(attr, item);
+        overwrote = false;
+    }
+    sp<Item> &item = mItems.editValueAt(i);
+    if (overwrote
+        && item->mType == MediaAnalyticsItem::Item::kTypeInt32) {
+        item->u.int32Value += value;
+    } else {
+        // start clean if there was a type mismatch
+        item->u.int32Value = value;
+    }
+    item->mType = MediaAnalyticsItem::Item::kTypeInt32;
+    return overwrote;
+}
+
+bool MediaAnalyticsItem::addInt64(MediaAnalyticsItem::Attr attr, int64_t value) {
+    ssize_t i = mItems.indexOfKey(attr);
+    bool overwrote = true;
+    if (i<0) {
+        sp<Item> item = new Item();
+        i = mItems.add(attr, item);
+        overwrote = false;
+    }
+    sp<Item> &item = mItems.editValueAt(i);
+    if (overwrote
+        && item->mType == MediaAnalyticsItem::Item::kTypeInt64) {
+        item->u.int64Value += value;
+    } else {
+        // start clean if there was a type mismatch
+        item->u.int64Value = value;
+    }
+    item->mType = MediaAnalyticsItem::Item::kTypeInt64;
+    return overwrote;
+}
+
+bool MediaAnalyticsItem::addDouble(MediaAnalyticsItem::Attr attr, double value) {
+    ssize_t i = mItems.indexOfKey(attr);
+    bool overwrote = true;
+    if (i<0) {
+        sp<Item> item = new Item();
+        i = mItems.add(attr, item);
+        overwrote = false;
+    }
+    sp<Item> &item = mItems.editValueAt(i);
+    if (overwrote
+        && item->mType == MediaAnalyticsItem::Item::kTypeDouble) {
+        item->u.doubleValue += value;
+    } else {
+        // start clean if there was a type mismatch
+        item->u.doubleValue = value;
+    }
+    item->mType = MediaAnalyticsItem::Item::kTypeDouble;
+    return overwrote;
+}
+
+// find & extract values
+bool MediaAnalyticsItem::getInt32(MediaAnalyticsItem::Attr attr, int32_t *value) {
+    ssize_t i = mItems.indexOfKey(attr);
+    if (i < 0) {
+        return false;
+    }
+    sp<Item> &item = mItems.editValueAt(i);
+    *value = item->u.int32Value;
+    return true;
+}
+bool MediaAnalyticsItem::getInt64(MediaAnalyticsItem::Attr attr, int64_t *value) {
+    ssize_t i = mItems.indexOfKey(attr);
+    if (i < 0) {
+        return false;
+    }
+    sp<Item> &item = mItems.editValueAt(i);
+    *value = item->u.int64Value;
+    return true;
+}
+bool MediaAnalyticsItem::getDouble(MediaAnalyticsItem::Attr attr, double *value) {
+    ssize_t i = mItems.indexOfKey(attr);
+    if (i < 0) {
+        return false;
+    }
+    sp<Item> &item = mItems.editValueAt(i);
+    *value = item->u.doubleValue;
+    return true;
+}
+
+// caller responsible for the returned string
+bool MediaAnalyticsItem::getCString(MediaAnalyticsItem::Attr attr, char **value) {
+    ssize_t i = mItems.indexOfKey(attr);
+    if (i < 0) {
+        return false;
+    }
+    sp<Item> &item = mItems.editValueAt(i);
+    char *p = strdup(item->u.CStringValue);
+    *value = p;
+    return true;
+}
+
+// remove indicated keys and their values
+// return value is # keys removed
+int32_t MediaAnalyticsItem::filter(int n, MediaAnalyticsItem::Attr attrs[]) {
+    int zapped = 0;
+    if (attrs == NULL) {
+        return -1;
+    }
+    if (n <= 0) {
+        return -1;
+    }
+    for (ssize_t i = 0 ; i < n ;  i++) {
+        ssize_t j = mItems.indexOfKey(attrs[i]);
+        if (j >= 0) {
+            mItems.removeItemsAt(j);
+            zapped++;
+        }
+    }
+    return zapped;
+}
+
+// remove any keys NOT in the provided list
+// return value is # keys removed
+int32_t MediaAnalyticsItem::filterNot(int n, MediaAnalyticsItem::Attr attrs[]) {
+    int zapped = 0;
+    if (attrs == NULL) {
+        return -1;
+    }
+    if (n <= 0) {
+        return -1;
+    }
+    for (ssize_t i = mItems.size()-1 ; i >=0 ;  i--) {
+        const MediaAnalyticsItem::Attr& lattr = mItems.keyAt(i);
+        ssize_t j;
+        for (j= 0; j < n ; j++) {
+            if (lattr == attrs[j]) {
+                mItems.removeItemsAt(i);
+                zapped++;
+                break;
+            }
+        }
+    }
+    return zapped;
+}
+
+// remove a single key
+// return value is 0 (not found) or 1 (found and removed)
+int32_t MediaAnalyticsItem::filter(MediaAnalyticsItem::Attr attr) {
+    if (attr == 0) return -1;
+    ssize_t i = mItems.indexOfKey(attr);
+    if (i < 0) {
+        return 0;
+    }
+    mItems.removeItemsAt(i);
+    return 1;
+}
+
+
+// handle individual items/properties stored within the class
+//
+MediaAnalyticsItem::Item::Item()
+        : mType(kTypeNone)
+{
+}
+
+MediaAnalyticsItem::Item::~Item()
+{
+    clear();
+}
+
+void MediaAnalyticsItem::Item::clear()
+{
+    if (mType == kTypeCString && u.CStringValue != NULL) {
+        free(u.CStringValue);
+        u.CStringValue = NULL;
+    }
+    mType = kTypeNone;
+}
+
+// Parcel / serialize things for binder calls
+//
+
+int32_t MediaAnalyticsItem::readFromParcel(const Parcel& data) {
+    // into 'this' object
+    // .. we make a copy of the string to put away.
+    mKey = data.readCString();
+    mSessionID = data.readInt64();
+    mFinalized = data.readInt32();
+    mTimestamp = data.readInt64();
+
+    int count = data.readInt32();
+    for (int i = 0; i < count ; i++) {
+            MediaAnalyticsItem::Attr attr = data.readCString();
+            int32_t ztype = data.readInt32();
+                switch (ztype) {
+                    case MediaAnalyticsItem::Item::kTypeInt32:
+                            setInt32(attr, data.readInt32());
+                            break;
+                    case MediaAnalyticsItem::Item::kTypeInt64:
+                            setInt64(attr, data.readInt64());
+                            break;
+                    case MediaAnalyticsItem::Item::kTypeDouble:
+                            setDouble(attr, data.readDouble());
+                            break;
+                    case MediaAnalyticsItem::Item::kTypeCString:
+                            setCString(attr, data.readCString());
+                            break;
+                    default:
+                            ALOGE("reading bad item type: %d, idx %d",
+                                  ztype, i);
+                            return -1;
+                }
+    }
+
+    return 0;
+}
+
+int32_t MediaAnalyticsItem::writeToParcel(Parcel *data) {
+    if (data == NULL) return -1;
+
+
+    data->writeCString(mKey.c_str());
+    data->writeInt64(mSessionID);
+    data->writeInt32(mFinalized);
+    data->writeInt64(mTimestamp);
+
+    // set of items
+    int count = mItems.size();
+    data->writeInt32(count);
+    for (int i = 0 ; i < count; i++ ) {
+            MediaAnalyticsItem::Attr attr = mItems.keyAt(i);
+            sp<Item> value = mItems.valueAt(i);
+            {
+                data->writeCString(attr.c_str());
+                data->writeInt32(value->mType);
+                switch (value->mType) {
+                    case MediaAnalyticsItem::Item::kTypeInt32:
+                            data->writeInt32(value->u.int32Value);
+                            break;
+                    case MediaAnalyticsItem::Item::kTypeInt64:
+                            data->writeInt64(value->u.int64Value);
+                            break;
+                    case MediaAnalyticsItem::Item::kTypeDouble:
+                            data->writeDouble(value->u.doubleValue);
+                            break;
+                    case MediaAnalyticsItem::Item::kTypeCString:
+                            data->writeCString(value->u.CStringValue);
+                            break;
+                    default:
+                            ALOGE("found bad item type: %d, idx %d",
+                                  value->mType, i);
+                            break;
+                }
+            }
+    }
+
+    return 0;
+}
+
+
+
+AString MediaAnalyticsItem::toString() {
+
+    AString result = "(";
+    char buffer[256];
+
+    // same order as we spill into the parcel, although not required
+    // key+session are our primary matching criteria
+    result.append(mKey.c_str());
+    result.append(":");
+    snprintf(buffer, sizeof(buffer), "%" PRId64 ":", mSessionID);
+    result.append(buffer);
+
+    // we need these internally, but don't want to upload them
+    snprintf(buffer, sizeof(buffer), "%d:%d", mUid, mPid);
+    result.append(buffer);
+
+    snprintf(buffer, sizeof(buffer), "%d:", mFinalized);
+    result.append(buffer);
+    snprintf(buffer, sizeof(buffer), "%" PRId64 ":", mTimestamp);
+    result.append(buffer);
+
+    // set of items
+    int count = mItems.size();
+    snprintf(buffer, sizeof(buffer), "%d:", count);
+    result.append(buffer);
+    for (int i = 0 ; i < count; i++ ) {
+            const MediaAnalyticsItem::Attr attr = mItems.keyAt(i);
+            const sp<Item> value = mItems.valueAt(i);
+            switch (value->mType) {
+                case MediaAnalyticsItem::Item::kTypeInt32:
+                        snprintf(buffer,sizeof(buffer),
+                        "%s=%d:", attr.c_str(), value->u.int32Value);
+                        break;
+                case MediaAnalyticsItem::Item::kTypeInt64:
+                        snprintf(buffer,sizeof(buffer),
+                        "%s=%" PRId64 ":", attr.c_str(), value->u.int64Value);
+                        break;
+                case MediaAnalyticsItem::Item::kTypeDouble:
+                        snprintf(buffer,sizeof(buffer),
+                        "%s=%e:", attr.c_str(), value->u.doubleValue);
+                        break;
+                case MediaAnalyticsItem::Item::kTypeCString:
+                        // XXX: worry about escape chars
+                        // XXX: worry about overflowing buffer
+                        snprintf(buffer,sizeof(buffer), "%s=", attr.c_str());
+                        result.append(buffer);
+                        result.append(value->u.CStringValue);
+                        buffer[0] = ':';
+                        buffer[1] = '\0';
+                        break;
+                default:
+                        ALOGE("to_String bad item type: %d",
+                              value->mType);
+                        break;
+            }
+            result.append(buffer);
+    }
+
+    result.append(")");
+
+    return result;
+}
+
+// for the lazy, we offer methods that finds the service and
+// calls the appropriate daemon
+bool MediaAnalyticsItem::selfrecord() {
+    return selfrecord(false);
+}
+
+bool MediaAnalyticsItem::selfrecord(bool forcenew) {
+
+    AString p = this->toString();
+    ALOGD("selfrecord of: %s [forcenew=%d]", p.c_str(), forcenew);
+
+    sp<IMediaAnalyticsService> svc = getInstance();
+
+    if (svc != NULL) {
+        svc->submit(this, forcenew);
+        return true;
+    } else {
+        return false;
+    }
+}
+
+// get a connection we can reuse for most of our lifetime
+// static
+sp<IMediaAnalyticsService> MediaAnalyticsItem::sAnalyticsService;
+static Mutex sInitMutex;
+
+//static
+bool MediaAnalyticsItem::isEnabled() {
+    int enabled = property_get_int32(MediaAnalyticsItem::EnabledProperty, -1);
+
+    if (enabled == -1) {
+        enabled = property_get_int32(MediaAnalyticsItem::EnabledPropertyPersist, -1);
+    }
+    if (enabled == -1) {
+        enabled = MediaAnalyticsItem::EnabledProperty_default;
+    }
+    if (enabled <= 0) {
+        return false;
+    }
+    return true;
+}
+
+//static
+sp<IMediaAnalyticsService> MediaAnalyticsItem::getInstance() {
+    static const char *servicename = "media.analytics";
+    int enabled = isEnabled();
+
+    if (enabled == false) {
+        if (DEBUG_SERVICEACCESS) {
+                ALOGD("disabled");
+        }
+        return NULL;
+    }
+
+    {
+        Mutex::Autolock _l(sInitMutex);
+        const char *badness = "";
+
+
+        if (sAnalyticsService == NULL) {
+            sp<IServiceManager> sm = defaultServiceManager();
+            if (sm != NULL) {
+                sp<IBinder> binder = sm->getService(String16(servicename));
+                if (binder != NULL) {
+                    sAnalyticsService = interface_cast<IMediaAnalyticsService>(binder);
+                } else {
+                    badness = "did not find service";
+                }
+            } else {
+                badness = "No Service Manager access";
+            }
+            // always
+            if (1 || DEBUG_SERVICEACCESS) {
+                if (sAnalyticsService == NULL) {
+                    ALOGD("Unable to bind to service %s: %s", servicename, badness);
+                }
+            }
+        }
+        return sAnalyticsService;
+    }
+}
+
+
+// merge the info from 'incoming' into this record.
+// we finish with a union of this+incoming and special handling for collisions
+bool MediaAnalyticsItem::merge(sp<MediaAnalyticsItem> incoming) {
+
+    // if I don't have key or session id, take them from incoming
+    // 'this' should never be missing both of them...
+    if (mKey.empty()) {
+        mKey = incoming->mKey;
+    } else if (mSessionID == 0) {
+        mSessionID = incoming->mSessionID;
+    }
+
+    // we always take the more recent 'finalized' value
+    setFinalized(incoming->getFinalized());
+
+    // for each attribute from 'incoming', resolve appropriately
+    int nattr = incoming->mItems.size();
+    for (int i = 0 ; i < nattr; i++ ) {
+        const MediaAnalyticsItem::Attr attr = incoming->mItems.keyAt(i);
+        const sp<Item> value = incoming->mItems.valueAt(i);
+
+        const char *p = attr.c_str();
+        char semantic = p[strlen(p)-1];
+
+        switch (semantic) {
+            default:        // default operation is keep new
+            case '>':       // last aka keep new
+                mItems.replaceValueFor(attr, value);
+                break;
+
+            case '<':       /* first aka keep first*/
+                /* nop */
+                break;
+
+            case '+':       /* sum */
+                // XXX validate numeric types, sum in place
+                break;
+
+        }
+    }
+
+    // not sure when we'd return false...
+    return true;
+}
+
+} // namespace android
+
diff --git a/media/libmedia/MediaDefs.cpp b/media/libmedia/MediaDefs.cpp
index a2110c9..2ae71f7 100644
--- a/media/libmedia/MediaDefs.cpp
+++ b/media/libmedia/MediaDefs.cpp
@@ -57,8 +57,6 @@
 const char *MEDIA_MIMETYPE_CONTAINER_AVI = "video/avi";
 const char *MEDIA_MIMETYPE_CONTAINER_MPEG2PS = "video/mp2p";
 
-const char *MEDIA_MIMETYPE_CONTAINER_WVM = "video/wvm";
-
 const char *MEDIA_MIMETYPE_TEXT_3GPP = "text/3gpp-tt";
 const char *MEDIA_MIMETYPE_TEXT_SUBRIP = "application/x-subrip";
 const char *MEDIA_MIMETYPE_TEXT_VTT = "text/vtt";
diff --git a/media/libmediaanalyticsservice/Android.mk b/media/libmediaanalyticsservice/Android.mk
new file mode 100644
index 0000000..dd59651
--- /dev/null
+++ b/media/libmediaanalyticsservice/Android.mk
@@ -0,0 +1,44 @@
+LOCAL_PATH:= $(call my-dir)
+
+#
+# libmediaanalyticsservice
+#
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:=               \
+    MediaAnalyticsService.cpp      \
+
+LOCAL_SHARED_LIBRARIES :=       \
+    libbinder                   \
+    libcutils                   \
+    liblog                      \
+    libdl                       \
+    libgui                      \
+    libmedia                    \
+    libmediautils               \
+    libstagefright_foundation   \
+    libutils
+
+LOCAL_EXPORT_SHARED_LIBRARY_HEADERS := libmedia
+
+LOCAL_C_INCLUDES :=                                                 \
+    $(TOP)/frameworks/av/media/libstagefright/include               \
+    $(TOP)/frameworks/av/media/libstagefright/rtsp                  \
+    $(TOP)/frameworks/av/media/libstagefright/wifi-display          \
+    $(TOP)/frameworks/av/media/libstagefright/webm                  \
+    $(TOP)/frameworks/av/include/media                              \
+    $(TOP)/frameworks/av/include/camera                             \
+    $(TOP)/frameworks/native/include/media/openmax                  \
+    $(TOP)/frameworks/native/include/media/hardware                 \
+    $(TOP)/external/tremolo/Tremolo                                 \
+    libcore/include                                                 \
+
+LOCAL_CFLAGS += -Werror -Wno-error=deprecated-declarations -Wall
+LOCAL_CLANG := true
+
+LOCAL_MODULE:= libmediaanalyticsservice
+
+include $(BUILD_SHARED_LIBRARY)
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/media/libmediaanalyticsservice/MediaAnalyticsService.cpp b/media/libmediaanalyticsservice/MediaAnalyticsService.cpp
new file mode 100644
index 0000000..a039c6c
--- /dev/null
+++ b/media/libmediaanalyticsservice/MediaAnalyticsService.cpp
@@ -0,0 +1,459 @@
+/*
+ * 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.
+ */
+
+// Proxy for media player implementations
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "MediaAnalyticsService"
+#include <utils/Log.h>
+
+#include <inttypes.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <dirent.h>
+#include <unistd.h>
+
+#include <string.h>
+
+#include <cutils/atomic.h>
+#include <cutils/properties.h> // for property_get
+
+#include <utils/misc.h>
+
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <binder/MemoryHeapBase.h>
+#include <binder/MemoryBase.h>
+#include <gui/Surface.h>
+#include <utils/Errors.h>  // for status_t
+#include <utils/List.h>
+#include <utils/String8.h>
+#include <utils/SystemClock.h>
+#include <utils/Timers.h>
+#include <utils/Vector.h>
+
+#include <media/AudioPolicyHelper.h>
+#include <media/IMediaHTTPService.h>
+#include <media/IRemoteDisplay.h>
+#include <media/IRemoteDisplayClient.h>
+#include <media/MediaPlayerInterface.h>
+#include <media/mediarecorder.h>
+#include <media/MediaMetadataRetrieverInterface.h>
+#include <media/Metadata.h>
+#include <media/AudioTrack.h>
+#include <media/MemoryLeakTrackUtil.h>
+#include <media/stagefright/MediaCodecList.h>
+#include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/Utils.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/ALooperRoster.h>
+#include <mediautils/BatteryNotifier.h>
+
+//#include <memunreachable/memunreachable.h>
+#include <system/audio.h>
+
+#include <private/android_filesystem_config.h>
+
+#include "MediaAnalyticsService.h"
+
+
+namespace android {
+
+
+static int trackqueue = 0;
+
+//using android::status_t;
+//using android::OK;
+//using android::BAD_VALUE;
+//using android::NOT_ENOUGH_DATA;
+//using android::Parcel;
+
+
+void MediaAnalyticsService::instantiate() {
+    defaultServiceManager()->addService(
+            String16("media.analytics"), new MediaAnalyticsService());
+}
+
+// XXX: add dynamic controls for mMaxRecords
+MediaAnalyticsService::MediaAnalyticsService()
+        : mMaxRecords(100) {
+
+    ALOGD("MediaAnalyticsService created");
+    // clear our queues
+    mOpen = new List<sp<MediaAnalyticsItem>>();
+    mFinalized = new List<sp<MediaAnalyticsItem>>();
+
+    mItemsSubmitted = 0;
+    mItemsFinalized = 0;
+    mItemsDiscarded = 0;
+
+    mLastSessionID = 0;
+    // recover any persistency we set up
+    // etc
+}
+
+MediaAnalyticsService::~MediaAnalyticsService() {
+        ALOGD("MediaAnalyticsService destroyed");
+
+    // XXX: clean out mOpen and mFinalized
+}
+
+
+MediaAnalyticsItem::SessionID_t MediaAnalyticsService::generateUniqueSessionID() {
+    // generate a new sessionid
+
+    Mutex::Autolock _l(mLock_ids);
+    return (++mLastSessionID);
+}
+
+MediaAnalyticsItem::SessionID_t MediaAnalyticsService::submit(sp<MediaAnalyticsItem> item, bool forcenew) {
+
+    MediaAnalyticsItem::SessionID_t id = MediaAnalyticsItem::SessionIDInvalid;
+
+    // we control these, not using whatever the user might have sent
+    nsecs_t now = systemTime(SYSTEM_TIME_REALTIME);
+    item->setTimestamp(now);
+    int pid = IPCThreadState::self()->getCallingPid();
+    item->setPid(pid);
+    int uid = IPCThreadState::self()->getCallingUid();
+    item->setUid(uid);
+
+    mItemsSubmitted++;
+
+    // validate the record; we discard if we don't like it
+    if (contentValid(item) == false) {
+        return MediaAnalyticsItem::SessionIDInvalid;
+    }
+
+
+    // if we have a sesisonid in the new record, look to make
+    // sure it doesn't appear in the finalized list.
+    // XXX: this is for security / DOS prevention.
+    // may also require that we persist the unique sessionIDs
+    // across boots [instead of within a single boot]
+
+
+    // match this new record up against records in the open
+    // list...
+    // if there's a match, merge them together
+    // deal with moving the old / merged record into the finalized que
+
+    bool finalizing = item->getFinalized();
+
+    // if finalizing, we'll remove it
+    sp<MediaAnalyticsItem> oitem = findItem(mOpen, item, finalizing | forcenew);
+    if (oitem != NULL) {
+        if (forcenew) {
+            // old one gets finalized, then we insert the new one
+            // so we'll have 2 records at the end of this.
+            // but don't finalize an empty record
+            if (oitem->count() != 0) {
+                oitem->setFinalized(true);
+                saveItem(mFinalized, oitem, 0);
+            }
+            // new record could itself be marked finalized...
+            if (finalizing) {
+                saveItem(mFinalized, item, 0);
+                mItemsFinalized++;
+            } else {
+                saveItem(mOpen, item, 1);
+            }
+            id = item->getSessionID();
+        } else {
+            // combine the records, send it to finalized if appropriate
+            oitem->merge(item);
+            if (finalizing) {
+                saveItem(mFinalized, oitem, 0);
+                mItemsFinalized++;
+            }
+            id = oitem->getSessionID();
+        }
+    } else {
+            // nothing to merge, save the new record
+            if (finalizing) {
+                if (item->count() != 0) {
+                    // drop empty records
+                    saveItem(mFinalized, item, 0);
+                    mItemsFinalized++;
+                }
+            } else {
+                saveItem(mOpen, item, 1);
+            }
+            id = item->getSessionID();
+    }
+
+    return id;
+}
+
+List<sp<MediaAnalyticsItem>> *MediaAnalyticsService::getMediaAnalyticsItemList(bool finished, nsecs_t ts) {
+    // this might never get called; the binder interface maps to the full parm list
+    // on the client side before making the binder call.
+    // but this lets us be sure...
+    List<sp<MediaAnalyticsItem>> *list;
+    list = getMediaAnalyticsItemList(finished, ts, MediaAnalyticsItem::kKeyAny);
+    return list;
+}
+
+List<sp<MediaAnalyticsItem>> *MediaAnalyticsService::getMediaAnalyticsItemList(bool , nsecs_t , MediaAnalyticsItem::Key ) {
+
+    // XXX: implement the get-item-list semantics
+
+    List<sp<MediaAnalyticsItem>> *list = NULL;
+    // set up our query on the persistent data
+    // slurp in all of the pieces
+    // return that
+    return list;
+}
+
+// ignoring 2nd argument, name removed to keep compiler happy
+// XXX: arguments to parse:
+//     -- a timestamp (either since X or last X seconds) to bound search
+status_t MediaAnalyticsService::dump(int fd, const Vector<String16>&)
+{
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+    String8 result;
+
+    if (checkCallingPermission(String16("android.permission.DUMP")) == false) {
+        snprintf(buffer, SIZE, "Permission Denial: "
+                "can't dump MediaAnalyticsService from pid=%d, uid=%d\n",
+                IPCThreadState::self()->getCallingPid(),
+                IPCThreadState::self()->getCallingUid());
+        result.append(buffer);
+    } else {
+
+        // crack parameters
+
+
+        Mutex::Autolock _l(mLock);
+
+        snprintf(buffer, SIZE, "Dump of the mediaanalytics process:\n");
+        result.append(buffer);
+
+        int enabled = MediaAnalyticsItem::isEnabled();
+        if (enabled) {
+            snprintf(buffer, SIZE, "Analytics gathering: enabled\n");
+        } else {
+            snprintf(buffer, SIZE, "Analytics gathering: DISABLED via property\n");
+        }
+        result.append(buffer);
+
+        snprintf(buffer, SIZE,
+            "Since Boot: Submissions: %" PRId64
+	    " Finalizations: %" PRId64
+            " Discarded: %" PRId64 "\n",
+            mItemsSubmitted, mItemsFinalized, mItemsDiscarded);
+        result.append(buffer);
+
+        // show the recently recorded records
+        snprintf(buffer, sizeof(buffer), "\nFinalized Analytics (oldest first):\n");
+        result.append(buffer);
+        result.append(this->dumpQueue(mFinalized));
+
+        snprintf(buffer, sizeof(buffer), "\nIn-Progress Analytics (newest first):\n");
+        result.append(buffer);
+        result.append(this->dumpQueue(mOpen));
+
+        // show who is connected and injecting records?
+        // talk about # records fed to the 'readers'
+        // talk about # records we discarded, perhaps "discarded w/o reading" too
+
+    }
+    write(fd, result.string(), result.size());
+    return NO_ERROR;
+}
+
+// caller has locked mLock...
+String8 MediaAnalyticsService::dumpQueue(List<sp<MediaAnalyticsItem>> *theList) {
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+    String8 result;
+    int slot = 0;
+
+    if (theList->empty()) {
+            result.append("empty\n");
+    } else {
+        List<sp<MediaAnalyticsItem>>::iterator it = theList->begin();
+        for (; it != theList->end(); it++, slot++) {
+            AString entry = (*it)->toString();
+            snprintf(buffer, sizeof(buffer), "%4d: %s\n",
+                        slot, entry.c_str());
+            result.append(buffer);
+        }
+    }
+
+    return result;
+}
+
+//
+// Our Cheap in-core, non-persistent records management.
+// XXX: rewrite this to manage persistence, etc.
+
+// insert appropriately into queue
+void MediaAnalyticsService::saveItem(List<sp<MediaAnalyticsItem>> *l, sp<MediaAnalyticsItem> item, int front) {
+
+    Mutex::Autolock _l(mLock);
+
+    if (false)
+        ALOGD("Inject a record: session %" PRId64 " ts %" PRId64 "",
+            item->getSessionID(), item->getTimestamp());
+
+    if (trackqueue) {
+        String8 before = dumpQueue(l);
+        ALOGD("Q before insert: %s", before.string());
+    }
+
+    // adding at back of queue (fifo order)
+    if (front)  {
+        l->push_front(item);
+    } else {
+        l->push_back(item);
+    }
+
+    if (trackqueue) {
+        String8 after = dumpQueue(l);
+        ALOGD("Q after insert: %s", after.string());
+    }
+
+    // keep removing old records the front until we're in-bounds
+    if (mMaxRecords > 0) {
+        while (l->size() > (size_t) mMaxRecords) {
+            sp<MediaAnalyticsItem> oitem = *(l->begin());
+            if (trackqueue) {
+                ALOGD("zap old record: key %s sessionID %" PRId64 " ts %" PRId64 "",
+                    oitem->getKey().c_str(), oitem->getSessionID(),
+                    oitem->getTimestamp());
+            }
+            l->erase(l->begin());
+	    mItemsDiscarded++;
+        }
+    }
+
+    if (trackqueue) {
+        String8 after = dumpQueue(l);
+        ALOGD("Q after cleanup: %s", after.string());
+    }
+}
+
+// are they alike enough that nitem can be folded into oitem?
+static bool compatibleItems(sp<MediaAnalyticsItem> oitem, sp<MediaAnalyticsItem> nitem) {
+
+    if (0) {
+        ALOGD("Compare: o %s n %s",
+              oitem->toString().c_str(), nitem->toString().c_str());
+    }
+
+    // general safety
+    if (nitem->getUid() != oitem->getUid()) {
+        return false;
+    }
+    if (nitem->getPid() != oitem->getPid()) {
+        return false;
+    }
+
+    // key -- needs to match
+    if (nitem->getKey() == oitem->getKey()) {
+        // still in the game.
+    } else {
+        return false;
+    }
+
+    // session id -- empty field in new is allowed
+    MediaAnalyticsItem::SessionID_t osession = oitem->getSessionID();
+    MediaAnalyticsItem::SessionID_t nsession = nitem->getSessionID();
+    if (nsession != osession) {
+        // incoming '0' matches value in osession
+        if (nsession != 0) {
+            return false;
+        }
+    }
+
+    return true;
+}
+
+// find the incomplete record that this will overlay
+sp<MediaAnalyticsItem> MediaAnalyticsService::findItem(List<sp<MediaAnalyticsItem>> *theList, sp<MediaAnalyticsItem> nitem, bool removeit) {
+    sp<MediaAnalyticsItem> item;
+
+    if (nitem == NULL) {
+        return NULL;
+    }
+
+    Mutex::Autolock _l(mLock);
+
+    for (List<sp<MediaAnalyticsItem>>::iterator it = theList->begin();
+        it != theList->end(); it++) {
+        sp<MediaAnalyticsItem> tmp = (*it);
+
+        if (!compatibleItems(tmp, nitem)) {
+            continue;
+        }
+
+        // we match! this is the one I want.
+        if (removeit) {
+            theList->erase(it);
+        }
+        item = tmp;
+        break;
+    }
+    return item;
+}
+
+
+// delete the indicated record
+void MediaAnalyticsService::deleteItem(List<sp<MediaAnalyticsItem>> *l, sp<MediaAnalyticsItem> item) {
+
+    Mutex::Autolock _l(mLock);
+
+    if(trackqueue) {
+        String8 before = dumpQueue(l);
+        ALOGD("Q before delete: %s", before.string());
+    }
+
+    for (List<sp<MediaAnalyticsItem>>::iterator it = l->begin();
+        it != l->end(); it++) {
+        if ((*it)->getSessionID() != item->getSessionID())
+            continue;
+
+        ALOGD(" --- removing record for SessionID %" PRId64 "", item->getSessionID());
+        l->erase(it);
+        break;
+    }
+
+    if (trackqueue) {
+        String8 after = dumpQueue(l);
+        ALOGD("Q after delete: %s", after.string());
+    }
+}
+
+// are the contents good
+bool MediaAnalyticsService::contentValid(sp<MediaAnalyticsItem>) {
+
+    // certain keys require certain uids
+    // internal consistency
+
+    return true;
+}
+
+// are we rate limited, normally false
+bool MediaAnalyticsService::rateLimited(sp<MediaAnalyticsItem>) {
+
+    return false;
+}
+
+
+} // namespace android
diff --git a/media/libmediaanalyticsservice/MediaAnalyticsService.h b/media/libmediaanalyticsservice/MediaAnalyticsService.h
new file mode 100644
index 0000000..f9afeb2
--- /dev/null
+++ b/media/libmediaanalyticsservice/MediaAnalyticsService.h
@@ -0,0 +1,96 @@
+/*
+ * 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_MEDIAANALYTICSSERVICE_H
+#define ANDROID_MEDIAANALYTICSSERVICE_H
+
+#include <arpa/inet.h>
+
+#include <utils/threads.h>
+#include <utils/Errors.h>
+#include <utils/KeyedVector.h>
+#include <utils/String8.h>
+#include <utils/List.h>
+
+#include <media/IMediaAnalyticsService.h>
+
+
+namespace android {
+
+class MediaAnalyticsService : public BnMediaAnalyticsService
+{
+
+ public:
+
+    virtual int64_t submit(sp<MediaAnalyticsItem> item, bool forcenew);
+
+    virtual List<sp<MediaAnalyticsItem>>
+            *getMediaAnalyticsItemList(bool finished, int64_t ts);
+    virtual List<sp<MediaAnalyticsItem>>
+            *getMediaAnalyticsItemList(bool finished, int64_t ts, MediaAnalyticsItem::Key key);
+
+
+    static  void            instantiate();
+    virtual status_t        dump(int fd, const Vector<String16>& args);
+
+                            MediaAnalyticsService();
+    virtual                 ~MediaAnalyticsService();
+
+ private:
+    MediaAnalyticsItem::SessionID_t generateUniqueSessionID();
+
+    // statistics about our analytics
+    int64_t mItemsSubmitted;
+    int64_t mItemsFinalized;
+    int64_t mItemsDiscarded;
+    MediaAnalyticsItem::SessionID_t mLastSessionID;
+
+    // partitioned a bit so we don't over serialize
+    mutable Mutex           mLock;
+    mutable Mutex           mLock_ids;
+
+    // the most we hold in memory
+    // up to this many in each queue (open, finalized)
+    int32_t mMaxRecords;
+
+    // input validation after arrival from client
+    bool contentValid(sp<MediaAnalyticsItem>);
+    bool rateLimited(sp<MediaAnalyticsItem>);
+
+    // the ones that are still open
+    // (newest at front) since we keep looking for them
+    List<sp<MediaAnalyticsItem>> *mOpen;
+    // the ones we've finalized
+    // (oldest at front) so it prints nicely for dumpsys
+    List<sp<MediaAnalyticsItem>> *mFinalized;
+    // searching within these queues: queue, key
+    sp<MediaAnalyticsItem> findItem(List<sp<MediaAnalyticsItem>> *,
+                                     sp<MediaAnalyticsItem>, bool removeit);
+
+    void saveItem(sp<MediaAnalyticsItem>);
+    void saveItem(List<sp<MediaAnalyticsItem>>*, sp<MediaAnalyticsItem>, int);
+    void deleteItem(List<sp<MediaAnalyticsItem>>*, sp<MediaAnalyticsItem>);
+
+    String8 dumpQueue(List<sp<MediaAnalyticsItem>> *);
+
+};
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_MEDIAANALYTICSSERVICE_H
diff --git a/media/libmediaplayerservice/MediaPlayerFactory.cpp b/media/libmediaplayerservice/MediaPlayerFactory.cpp
index 605c710..0a9f791 100644
--- a/media/libmediaplayerservice/MediaPlayerFactory.cpp
+++ b/media/libmediaplayerservice/MediaPlayerFactory.cpp
@@ -26,7 +26,6 @@
 #include <media/stagefright/foundation/ADebug.h>
 #include <utils/Errors.h>
 #include <utils/misc.h>
-#include <../libstagefright/include/WVMExtractor.h>
 
 #include "MediaPlayerFactory.h"
 
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index 6e163d9..3ad461c 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -972,6 +972,42 @@
     return OK;
 }
 
+status_t MediaPlayerService::Client::setBufferingSettings(
+        const BufferingSettings& buffering)
+{
+    ALOGV("[%d] setBufferingSettings(%d, %d, %d, %d, %d, %d, %d, %d)",
+            mConnId, buffering.mInitialBufferingMode, buffering.mRebufferingMode,
+            buffering.mInitialWatermarkMs, buffering.mInitialWatermarkKB,
+            buffering.mRebufferingWatermarkLowMs,
+            buffering.mRebufferingWatermarkHighMs,
+            buffering.mRebufferingWatermarkLowKB,
+            buffering.mRebufferingWatermarkHighKB);
+    sp<MediaPlayerBase> p = getPlayer();
+    if (p == 0) return UNKNOWN_ERROR;
+    return p->setBufferingSettings(buffering);
+}
+
+status_t MediaPlayerService::Client::getDefaultBufferingSettings(
+        BufferingSettings* buffering /* nonnull */)
+{
+    sp<MediaPlayerBase> p = getPlayer();
+    // TODO: create mPlayer on demand.
+    if (p == 0) return UNKNOWN_ERROR;
+    status_t ret = p->getDefaultBufferingSettings(buffering);
+    if (ret == NO_ERROR) {
+        ALOGV("[%d] getDefaultBufferingSettings(%d, %d, %d, %d, %d, %d, %d, %d)",
+                mConnId, buffering->mInitialBufferingMode, buffering->mRebufferingMode,
+                buffering->mInitialWatermarkMs, buffering->mInitialWatermarkKB,
+                buffering->mRebufferingWatermarkLowMs,
+                buffering->mRebufferingWatermarkHighMs,
+                buffering->mRebufferingWatermarkLowKB,
+                buffering->mRebufferingWatermarkHighKB);
+    } else {
+        ALOGV("[%d] getDefaultBufferingSettings returned %d", mConnId, ret);
+    }
+    return ret;
+}
+
 status_t MediaPlayerService::Client::prepareAsync()
 {
     ALOGV("[%d] prepareAsync", mConnId);
diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h
index a4ea37f..8a6ada0 100644
--- a/media/libmediaplayerservice/MediaPlayerService.h
+++ b/media/libmediaplayerservice/MediaPlayerService.h
@@ -288,6 +288,9 @@
         virtual void            disconnect();
         virtual status_t        setVideoSurfaceTexture(
                                         const sp<IGraphicBufferProducer>& bufferProducer);
+        virtual status_t        setBufferingSettings(const BufferingSettings& buffering) override;
+        virtual status_t        getDefaultBufferingSettings(
+                                        BufferingSettings* buffering /* nonnull */) override;
         virtual status_t        prepareAsync();
         virtual status_t        start();
         virtual status_t        stop();
diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
index fce9ab5..8761e9d 100644
--- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
@@ -33,9 +33,7 @@
 #include <media/stagefright/MediaSource.h>
 #include <media/stagefright/MetaData.h>
 #include <media/stagefright/Utils.h>
-#include "../../libstagefright/include/DRMExtractor.h"
 #include "../../libstagefright/include/NuCachedSource2.h"
-#include "../../libstagefright/include/WVMExtractor.h"
 #include "../../libstagefright/include/HTTPBase.h"
 
 namespace android {
@@ -59,7 +57,6 @@
       mFetchTimedTextDataGeneration(0),
       mDurationUs(-1ll),
       mAudioIsVorbis(false),
-      mIsWidevine(false),
       mIsSecure(false),
       mIsStreaming(false),
       mUIDValid(uidValid),
@@ -70,7 +67,6 @@
       mPendingReadBufferTypes(0) {
     mBufferingMonitor = new BufferingMonitor(notify);
     resetDataSource();
-    DataSource::RegisterDefaultSniffers();
 }
 
 void NuPlayer::GenericSource::resetDataSource() {
@@ -141,44 +137,9 @@
 
 status_t NuPlayer::GenericSource::initFromDataSource() {
     sp<IMediaExtractor> extractor;
-    String8 mimeType;
-    float confidence;
-    sp<AMessage> dummy;
-    bool isWidevineStreaming = false;
-
     CHECK(mDataSource != NULL);
 
-    if (mIsWidevine) {
-        isWidevineStreaming = SniffWVM(
-                mDataSource, &mimeType, &confidence, &dummy);
-        if (!isWidevineStreaming ||
-                strcasecmp(
-                    mimeType.string(), MEDIA_MIMETYPE_CONTAINER_WVM)) {
-            ALOGE("unsupported widevine mime: %s", mimeType.string());
-            return UNKNOWN_ERROR;
-        }
-    } else if (mIsStreaming) {
-        if (!mDataSource->sniff(&mimeType, &confidence, &dummy)) {
-            return UNKNOWN_ERROR;
-        }
-        isWidevineStreaming = !strcasecmp(
-                mimeType.string(), MEDIA_MIMETYPE_CONTAINER_WVM);
-    }
-
-    if (isWidevineStreaming) {
-        // we don't want cached source for widevine streaming.
-        mCachedSource.clear();
-        mDataSource = mHttpSource;
-        mWVMExtractor = new WVMExtractor(mDataSource);
-        mWVMExtractor->setAdaptiveStreamingMode(true);
-        if (mUIDValid) {
-            mWVMExtractor->setUID(mUID);
-        }
-        extractor = mWVMExtractor;
-    } else {
-        extractor = MediaExtractor::Create(mDataSource,
-                mimeType.isEmpty() ? NULL : mimeType.string());
-    }
+    extractor = MediaExtractor::Create(mDataSource, NULL);
 
     if (extractor == NULL) {
         return UNKNOWN_ERROR;
@@ -194,17 +155,6 @@
         if (mFileMeta->findInt64(kKeyDuration, &duration)) {
             mDurationUs = duration;
         }
-
-        if (!mIsWidevine) {
-            // Check mime to see if we actually have a widevine source.
-            // If the data source is not URL-type (eg. file source), we
-            // won't be able to tell until now.
-            const char *fileMime;
-            if (mFileMeta->findCString(kKeyMIMEType, &fileMime)
-                    && !strncasecmp(fileMime, "video/wvm", 9)) {
-                mIsWidevine = true;
-            }
-        }
     }
 
     int32_t totalBitrate = 0;
@@ -296,6 +246,9 @@
     // Widevine sources might re-initialize crypto when starting, if we delay
     // this to start(), all data buffered during prepare would be wasted.
     // (We don't actually start reading until start().)
+    //
+    // TODO: this logic may no longer be relevant after the removal of widevine
+    // support
     if (mAudioTrack.mSource != NULL && mAudioTrack.mSource->start() != OK) {
         ALOGE("failed to start audio track!");
         return UNKNOWN_ERROR;
@@ -378,11 +331,8 @@
         if (!mUri.empty()) {
             const char* uri = mUri.c_str();
             String8 contentType;
-            mIsWidevine = !strncasecmp(uri, "widevine://", 11);
 
-            if (!strncasecmp("http://", uri, 7)
-                    || !strncasecmp("https://", uri, 8)
-                    || mIsWidevine) {
+            if (!strncasecmp("http://", uri, 7) || !strncasecmp("https://", uri, 8)) {
                 mHttpSource = DataSource::CreateMediaHTTP(mHTTPService);
                 if (mHttpSource == NULL) {
                     ALOGE("Failed to create http source!");
@@ -395,8 +345,6 @@
                    mHTTPService, uri, &mUriHeaders, &contentType,
                    static_cast<HTTPBase *>(mHttpSource.get()));
         } else {
-            mIsWidevine = false;
-
             mDataSource = new FileSource(mFd, mOffset, mLength);
             mFd = -1;
         }
@@ -412,13 +360,9 @@
         mCachedSource = static_cast<NuCachedSource2 *>(mDataSource.get());
     }
 
-    // For widevine or other cached streaming cases, we need to wait for
-    // enough buffering before reporting prepared.
-    // Note that even when URL doesn't start with widevine://, mIsWidevine
-    // could still be set to true later, if the streaming or file source
-    // is sniffed to be widevine. We don't want to buffer for file source
-    // in that case, so must check the flag now.
-    mIsStreaming = (mIsWidevine || mCachedSource != NULL);
+    // For cached streaming cases, we need to wait for enough
+    // buffering before reporting prepared.
+    mIsStreaming = (mCachedSource != NULL);
 
     // init extractor from data source
     status_t err = initFromDataSource();
@@ -450,6 +394,9 @@
 
     if (mIsSecure) {
         // secure decoders must be instantiated before starting widevine source
+        //
+        // TODO: mIsSecure and FLAG_SECURE may be obsolete, revisit after
+        // removing widevine
         sp<AMessage> reply = new AMessage(kWhatSecureDecodersInstantiated, this);
         notifyInstantiateSecureDecoders(reply);
     } else {
@@ -476,7 +423,7 @@
 
     if (mIsStreaming) {
         if (mBufferingMonitorLooper == NULL) {
-            mBufferingMonitor->prepare(mCachedSource, mWVMExtractor, mDurationUs, mBitrate,
+            mBufferingMonitor->prepare(mCachedSource, mDurationUs, mBitrate,
                     mIsStreaming);
 
             mBufferingMonitorLooper = new ALooper;
@@ -536,12 +483,6 @@
     // nothing to do, just account for DRM playback status
     setDrmPlaybackStatusIfNeeded(Playback::STOP, 0);
     mStarted = false;
-    if (mIsWidevine || mIsSecure) {
-        // For widevine or secure sources we need to prevent any further reads.
-        sp<AMessage> msg = new AMessage(kWhatStopWidevine, this);
-        sp<AMessage> response;
-        (void) msg->postAndAwaitResponse(&response);
-    }
 }
 
 void NuPlayer::GenericSource::pause() {
@@ -719,20 +660,6 @@
           break;
       }
 
-      case kWhatStopWidevine:
-      {
-          // mStopRead is only used for Widevine to prevent the video source
-          // from being read while the associated video decoder is shutting down.
-          mStopRead = true;
-          if (mVideoTrack.mSource != NULL) {
-              mVideoTrack.mPackets->clear();
-          }
-          sp<AMessage> response = new AMessage;
-          sp<AReplyToken> replyID;
-          CHECK(msg->senderAwaitsResponse(&replyID));
-          response->postReply(replyID);
-          break;
-      }
       default:
           Source::onMessageReceived(msg);
           break;
@@ -888,11 +815,6 @@
         return -EWOULDBLOCK;
     }
 
-    if (mIsWidevine && !audio) {
-        // try to read a buffer as we may not have been able to the last time
-        postReadBuffer(MEDIA_TRACK_TYPE_VIDEO);
-    }
-
     status_t finalResult;
     if (!track->mPackets->hasBufferAvailable(&finalResult)) {
         if (finalResult == OK) {
@@ -1222,6 +1144,9 @@
 
     // 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;
     }
@@ -1366,6 +1291,9 @@
         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;
     }
@@ -1374,19 +1302,11 @@
     switch (trackType) {
         case MEDIA_TRACK_TYPE_VIDEO:
             track = &mVideoTrack;
-            if (mIsWidevine) {
-                maxBuffers = 2;
-            } else {
-                maxBuffers = 8;  // too large of a number may influence seeks
-            }
+            maxBuffers = 8;  // too large of a number may influence seeks
             break;
         case MEDIA_TRACK_TYPE_AUDIO:
             track = &mAudioTrack;
-            if (mIsWidevine) {
-                maxBuffers = 8;
-            } else {
-                maxBuffers = 64;
-            }
+            maxBuffers = 64;
             break;
         case MEDIA_TRACK_TYPE_SUBTITLE:
             track = &mSubtitleTrack;
@@ -1414,9 +1334,9 @@
         seeking = true;
     }
 
-    const bool couldReadMultiple = (!mIsWidevine && track->mSource->supportReadMultiple());
+    const bool couldReadMultiple = (track->mSource->supportReadMultiple());
 
-    if (mIsWidevine || couldReadMultiple) {
+    if (couldReadMultiple) {
         options.setNonBlocking();
     }
 
@@ -1538,17 +1458,16 @@
 
 void NuPlayer::GenericSource::BufferingMonitor::prepare(
         const sp<NuCachedSource2> &cachedSource,
-        const sp<WVMExtractor> &wvmExtractor,
         int64_t durationUs,
         int64_t bitrate,
         bool isStreaming) {
     Mutex::Autolock _l(mLock);
-    prepare_l(cachedSource, wvmExtractor, durationUs, bitrate, isStreaming);
+    prepare_l(cachedSource, durationUs, bitrate, isStreaming);
 }
 
 void NuPlayer::GenericSource::BufferingMonitor::stop() {
     Mutex::Autolock _l(mLock);
-    prepare_l(NULL /* cachedSource */, NULL /* wvmExtractor */, -1 /* durationUs */,
+    prepare_l(NULL /* cachedSource */, -1 /* durationUs */,
             -1 /* bitrate */, false /* isStreaming */);
 }
 
@@ -1603,22 +1522,17 @@
 
 void NuPlayer::GenericSource::BufferingMonitor::prepare_l(
         const sp<NuCachedSource2> &cachedSource,
-        const sp<WVMExtractor> &wvmExtractor,
         int64_t durationUs,
         int64_t bitrate,
         bool isStreaming) {
-    ALOGW_IF(wvmExtractor != NULL && cachedSource != NULL,
-            "WVMExtractor and NuCachedSource are both present when "
-            "BufferingMonitor::prepare_l is called, ignore NuCachedSource");
 
     mCachedSource = cachedSource;
-    mWVMExtractor = wvmExtractor;
     mDurationUs = durationUs;
     mBitrate = bitrate;
     mIsStreaming = isStreaming;
     mAudioTimeUs = 0;
     mVideoTimeUs = 0;
-    mPrepareBuffering = (cachedSource != NULL || wvmExtractor != NULL);
+    mPrepareBuffering = (cachedSource != NULL);
     cancelPollBuffering_l();
     mOffloadAudio = false;
     mFirstDequeuedBufferRealUs = -1ll;
@@ -1702,9 +1616,7 @@
     int32_t kbps = 0;
     status_t err = UNKNOWN_ERROR;
 
-    if (mWVMExtractor != NULL) {
-        err = mWVMExtractor->getEstimatedBandwidthKbps(&kbps);
-    } else if (mCachedSource != NULL) {
+    if (mCachedSource != NULL) {
         err = mCachedSource->getEstimatedBandwidthKbps(&kbps);
     }
 
@@ -1744,10 +1656,7 @@
     int64_t cachedDurationUs = -1ll;
     ssize_t cachedDataRemaining = -1;
 
-    if (mWVMExtractor != NULL) {
-        cachedDurationUs =
-                mWVMExtractor->getCachedDurationUs(&finalStatus);
-    } else if (mCachedSource != NULL) {
+    if (mCachedSource != NULL) {
         cachedDataRemaining =
                 mCachedSource->approxDataRemaining(&finalStatus);
 
diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.h b/media/libmediaplayerservice/nuplayer/GenericSource.h
index d317c42..38d8616 100644
--- a/media/libmediaplayerservice/nuplayer/GenericSource.h
+++ b/media/libmediaplayerservice/nuplayer/GenericSource.h
@@ -37,7 +37,6 @@
 struct MediaSource;
 class MediaBuffer;
 struct NuCachedSource2;
-class WVMExtractor;
 
 struct NuPlayer::GenericSource : public NuPlayer::Source {
     GenericSource(const sp<AMessage> &notify, bool uidValid, uid_t uid);
@@ -103,7 +102,6 @@
         kWhatSelectTrack,
         kWhatSeek,
         kWhatReadBuffer,
-        kWhatStopWidevine,
         kWhatStart,
         kWhatResume,
         kWhatSecureDecodersInstantiated,
@@ -123,7 +121,6 @@
 
         // Set up state.
         void prepare(const sp<NuCachedSource2> &cachedSource,
-                const sp<WVMExtractor> &wvmExtractor,
                 int64_t durationUs,
                 int64_t bitrate,
                 bool isStreaming);
@@ -157,7 +154,6 @@
         sp<AMessage> mNotify;
 
         sp<NuCachedSource2> mCachedSource;
-        sp<WVMExtractor> mWVMExtractor;
         int64_t mDurationUs;
         int64_t mBitrate;
         bool mIsStreaming;
@@ -177,7 +173,6 @@
         int64_t mlastDequeuedBufferMediaUs;
 
         void prepare_l(const sp<NuCachedSource2> &cachedSource,
-                const sp<WVMExtractor> &wvmExtractor,
                 int64_t durationUs,
                 int64_t bitrate,
                 bool isStreaming);
@@ -206,7 +201,6 @@
     int32_t mFetchTimedTextDataGeneration;
     int64_t mDurationUs;
     bool mAudioIsVorbis;
-    bool mIsWidevine;
     bool mIsSecure;
     bool mIsStreaming;
     bool mUIDValid;
@@ -221,7 +215,6 @@
     sp<DataSource> mDataSource;
     sp<NuCachedSource2> mCachedSource;
     sp<DataSource> mHttpSource;
-    sp<WVMExtractor> mWVMExtractor;
     sp<MetaData> mFileMeta;
     DrmManagerClient *mDrmManagerClient;
     sp<DecryptHandle> mDecryptHandle;
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
index d240521..f8a6a4e 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
@@ -263,9 +263,6 @@
     } else {
         sp<GenericSource> genericSource =
                 new GenericSource(notify, mUIDValid, mUID);
-        // Don't set FLAG_SECURE on mSourceFlags here for widevine.
-        // The correct flags will be updated in Source::kWhatFlagsChanged
-        // handler when  GenericSource is prepared.
 
         status_t err = genericSource->setDataSource(httpService, url, headers);
 
@@ -1661,9 +1658,7 @@
         // directly queuing to display, as this will even improve textureview
         // playback.
         {
-            char value[PROPERTY_VALUE_MAX];
-            if (property_get("persist.sys.media.avsync", value, NULL) &&
-                    (!strcmp("1", value) || !strcasecmp("true", value))) {
+            if (property_get_bool("persist.sys.media.avsync", false)) {
                 format->setInt32("auto-frc", 1);
             }
         }
@@ -1671,29 +1666,6 @@
     (*decoder)->init();
     (*decoder)->configure(format);
 
-    // allocate buffers to decrypt widevine source buffers
-    if (!audio && (mSourceFlags & Source::FLAG_SECURE)) {
-        Vector<sp<MediaCodecBuffer> > inputBufs;
-        CHECK_EQ((*decoder)->getInputBuffers(&inputBufs), (status_t)OK);
-
-        Vector<MediaBuffer *> mediaBufs;
-        for (size_t i = 0; i < inputBufs.size(); i++) {
-            const sp<MediaCodecBuffer> &buffer = inputBufs[i];
-            MediaBuffer *mbuf = new MediaBuffer(buffer->data(), buffer->size());
-            mediaBufs.push(mbuf);
-        }
-
-        status_t err = mSource->setBuffers(audio, mediaBufs);
-        if (err != OK) {
-            for (size_t i = 0; i < mediaBufs.size(); ++i) {
-                mediaBufs[i]->release();
-            }
-            mediaBufs.clear();
-            ALOGE("Secure source didn't support secure mediaBufs.");
-            return err;
-        }
-    }
-
     if (!audio) {
         sp<AMessage> params = new AMessage();
         float rate = getFrameRate();
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
index 3da5030..1d62498 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
@@ -423,17 +423,7 @@
 }
 
 void NuPlayer::Decoder::onSetRenderer(const sp<Renderer> &renderer) {
-    bool hadNoRenderer = (mRenderer == NULL);
     mRenderer = renderer;
-    if (hadNoRenderer && mRenderer != NULL) {
-        // this means that the widevine legacy source is ready
-        onRequestInputBuffers();
-    }
-}
-
-void NuPlayer::Decoder::onGetInputBuffers(
-        Vector<sp<MediaCodecBuffer> > *dstBuffers) {
-    CHECK_EQ((status_t)OK, mCodec->getWidevineLegacyBuffers(dstBuffers));
 }
 
 void NuPlayer::Decoder::onResume(bool notifyComplete) {
@@ -530,9 +520,7 @@
  * returns true if we should request more data
  */
 bool NuPlayer::Decoder::doRequestBuffers() {
-    // mRenderer is only NULL if we have a legacy widevine source that
-    // is not yet ready. In this case we must not fetch input.
-    if (isDiscontinuityPending() || mRenderer == NULL) {
+    if (isDiscontinuityPending()) {
         return false;
     }
     status_t err = OK;
@@ -885,40 +873,6 @@
     bool hasBuffer = msg->findBuffer("buffer", &buffer);
     bool needsCopy = true;
 
-    // handle widevine classic source - that fills an arbitrary input buffer
-    MediaBuffer *mediaBuffer = NULL;
-    if (hasBuffer) {
-        mediaBuffer = (MediaBuffer *)(buffer->getMediaBufferBase());
-        if (mediaBuffer != NULL) {
-            // likely filled another buffer than we requested: adjust buffer index
-            size_t ix;
-            for (ix = 0; ix < mInputBuffers.size(); ix++) {
-                const sp<MediaCodecBuffer> &buf = mInputBuffers[ix];
-                if (buf->data() == mediaBuffer->data()) {
-                    // all input buffers are dequeued on start, hence the check
-                    if (!mInputBufferIsDequeued[ix]) {
-                        ALOGV("[%s] received MediaBuffer for #%zu instead of #%zu",
-                                mComponentName.c_str(), ix, bufferIx);
-                        mediaBuffer->release();
-                        return false;
-                    }
-
-                    // TRICKY: need buffer for the metadata, so instead, set
-                    // codecBuffer to the same (though incorrect) buffer to
-                    // avoid a memcpy into the codecBuffer
-                    codecBuffer = new MediaCodecBuffer(codecBuffer->format(), buffer);
-                    codecBuffer->setRange(
-                            mediaBuffer->range_offset(),
-                            mediaBuffer->range_length());
-                    bufferIx = ix;
-                    needsCopy = false;
-                    break;
-                }
-            }
-            CHECK(ix < mInputBuffers.size());
-        }
-    }
-
     if (buffer == NULL /* includes !hasBuffer */) {
         int32_t streamErr = ERROR_END_OF_STREAM;
         CHECK(msg->findInt32("err", &streamErr) || !hasBuffer);
@@ -988,18 +942,11 @@
                         timeUs,
                         flags);
         if (err != OK) {
-            if (mediaBuffer != NULL) {
-                mediaBuffer->release();
-            }
             ALOGE("Failed to queue input buffer for %s (err=%d)",
                     mComponentName.c_str(), err);
             handleError(err);
         } else {
             mInputBufferIsDequeued.editItemAt(bufferIx) = false;
-            if (mediaBuffer != NULL) {
-                CHECK(mMediaBuffers[bufferIx] == NULL);
-                mMediaBuffers.editItemAt(bufferIx) = mediaBuffer;
-            }
         }
     }
     return true;
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h
index 7217ed1..82db59c 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h
@@ -47,7 +47,6 @@
     virtual void onConfigure(const sp<AMessage> &format);
     virtual void onSetParameters(const sp<AMessage> &params);
     virtual void onSetRenderer(const sp<Renderer> &renderer);
-    virtual void onGetInputBuffers(Vector<sp<MediaCodecBuffer> > *dstBuffers);
     virtual void onResume(bool notifyComplete);
     virtual void onFlush();
     virtual void onShutdown(bool notifyComplete);
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.cpp
index 9c007ae..1210dc9 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.cpp
@@ -92,14 +92,6 @@
     PostAndAwaitResponse(msg, &response);
 }
 
-status_t NuPlayer::DecoderBase::getInputBuffers(Vector<sp<MediaCodecBuffer> > *buffers) const {
-    sp<AMessage> msg = new AMessage(kWhatGetInputBuffers, this);
-    msg->setPointer("buffers", buffers);
-
-    sp<AMessage> response;
-    return PostAndAwaitResponse(msg, &response);
-}
-
 void NuPlayer::DecoderBase::signalFlush() {
     (new AMessage(kWhatFlush, this))->post();
 }
@@ -166,20 +158,6 @@
             break;
         }
 
-        case kWhatGetInputBuffers:
-        {
-            sp<AReplyToken> replyID;
-            CHECK(msg->senderAwaitsResponse(&replyID));
-
-            Vector<sp<MediaCodecBuffer> > *dstBuffers;
-            CHECK(msg->findPointer("buffers", (void **)&dstBuffers));
-
-            onGetInputBuffers(dstBuffers);
-
-            (new AMessage)->postReply(replyID);
-            break;
-        }
-
         case kWhatRequestInputBuffers:
         {
             mRequestInputBuffersPending = false;
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.h b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.h
index 6f4ead6..6811903 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.h
@@ -43,7 +43,6 @@
     void setRenderer(const sp<Renderer> &renderer);
     virtual status_t setVideoSurface(const sp<Surface> &) { return INVALID_OPERATION; }
 
-    status_t getInputBuffers(Vector<sp<MediaCodecBuffer> > *dstBuffers) const;
     void signalFlush();
     void signalResume(bool notifyComplete);
     void initiateShutdown();
@@ -71,7 +70,6 @@
     virtual void onConfigure(const sp<AMessage> &format) = 0;
     virtual void onSetParameters(const sp<AMessage> &params) = 0;
     virtual void onSetRenderer(const sp<Renderer> &renderer) = 0;
-    virtual void onGetInputBuffers(Vector<sp<MediaCodecBuffer> > *dstBuffers) = 0;
     virtual void onResume(bool notifyComplete) = 0;
     virtual void onFlush() = 0;
     virtual void onShutdown(bool notifyComplete) = 0;
@@ -91,7 +89,6 @@
         kWhatSetParameters       = 'setP',
         kWhatSetRenderer         = 'setR',
         kWhatPause               = 'paus',
-        kWhatGetInputBuffers     = 'gInB',
         kWhatRequestInputBuffers = 'reqB',
         kWhatFlush               = 'flus',
         kWhatShutdown            = 'shuD',
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.cpp
index e4767ff..cb668e4 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.cpp
@@ -93,11 +93,6 @@
             "ignoring request to change renderer");
 }
 
-void NuPlayer::DecoderPassThrough::onGetInputBuffers(
-        Vector<sp<MediaCodecBuffer> > * /* dstBuffers */) {
-    ALOGE("onGetInputBuffers() called unexpectedly");
-}
-
 bool NuPlayer::DecoderPassThrough::isStaleReply(const sp<AMessage> &msg) {
     int32_t generation;
     CHECK(msg->findInt32("generation", &generation));
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.h b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.h
index 9af25ff..173387a 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.h
@@ -38,7 +38,6 @@
     virtual void onConfigure(const sp<AMessage> &format);
     virtual void onSetParameters(const sp<AMessage> &params);
     virtual void onSetRenderer(const sp<Renderer> &renderer);
-    virtual void onGetInputBuffers(Vector<sp<MediaCodecBuffer> > *dstBuffers);
     virtual void onResume(bool notifyComplete);
     virtual void onFlush();
     virtual void onShutdown(bool notifyComplete);
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
index 3efa54c..6ec79e6 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
@@ -478,9 +478,7 @@
         notifyListener_l(MEDIA_STOPPED);
     }
 
-    char value[PROPERTY_VALUE_MAX];
-    if (property_get("persist.debug.sf.stats", value, NULL) &&
-            (!strcmp("1", value) || !strcasecmp("true", value))) {
+    if (property_get_bool("persist.debug.sf.stats", false)) {
         Vector<String16> args;
         dump(-1, args);
     }
diff --git a/media/liboboe/README.md b/media/liboboe/README.md
new file mode 100644
index 0000000..80894c6
--- /dev/null
+++ b/media/liboboe/README.md
@@ -0,0 +1 @@
+Oboe Audio input/output API
diff --git a/media/liboboe/include/oboe/OboeAudio.h b/media/liboboe/include/oboe/OboeAudio.h
new file mode 100644
index 0000000..32fef1b
--- /dev/null
+++ b/media/liboboe/include/oboe/OboeAudio.h
@@ -0,0 +1,536 @@
+/*
+ * 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.
+ */
+
+/**
+ * This is the 'C' ABI for Oboe.
+ */
+#ifndef OBOE_OBOEAUDIO_H
+#define OBOE_OBOEAUDIO_H
+
+#include "OboeDefinitions.h"
+
+typedef int32_t OboeDeviceId;
+typedef oboe_handle_t OboeStream;
+typedef oboe_handle_t OboeStreamBuilder;
+typedef oboe_handle_t OboeThread;
+
+#define OBOE_STREAM_NONE         ((OboeStream)OBOE_HANDLE_INVALID)
+#define OBOE_STREAM_BUILDER_NONE ((OboeStreamBuilder)OBOE_HANDLE_INVALID)
+
+
+// ============================================================
+// Audio System
+// ============================================================
+
+/**
+ * @return time in the same clock domain as the timestamps
+ */
+oboe_nanoseconds_t Oboe_getNanoseconds(oboe_clockid_t clockid);
+
+/**
+ * The text is the ASCII symbol corresponding to the returnCode,
+ * or an English message saying the returnCode is unrecognized.
+ * This is intended for developers to use when debugging.
+ * It is not for display to users.
+ *
+ * @return pointer to a text representation of an Oboe result code.
+ */
+const char * Oboe_convertResultToText(oboe_result_t returnCode);
+
+/**
+ * The text is the ASCII symbol corresponding to the stream state,
+ * or an English message saying the state is unrecognized.
+ * This is intended for developers to use when debugging.
+ * It is not for display to users.
+ *
+ * @return pointer to a text representation of an Oboe state.
+ */
+const char * Oboe_convertStreamStateToText(oboe_stream_state_t state);
+
+// ============================================================
+// StreamBuilder
+// ============================================================
+
+/**
+ * Create a StreamBuilder that can be used to open a Stream.
+ *
+ * The deviceId is initially unspecified, meaning that the current default device will be used.
+ *
+ * The default direction is OBOE_DIRECTION_OUTPUT.
+ * The default sharing mode is OBOE_SHARING_MODE_LEGACY.
+ * The data format, samplesPerFrames and sampleRate are unspecified and will be
+ * chosen by the device when it is opened.
+ *
+ * OboeStreamBuilder_delete() must be called when you are done using the builder.
+ */
+oboe_result_t Oboe_createStreamBuilder(OboeStreamBuilder *builder);
+
+/**
+ * Request an audio device identified device using an ID.
+ * The ID is platform specific.
+ * On Android, for example, the ID could be obtained from the Java AudioManager.
+ *
+ * By default, the primary device will be used.
+ *
+ * @return OBOE_OK or a negative error.
+ */
+oboe_result_t OboeStreamBuilder_setDeviceId(OboeStreamBuilder builder, OboeDeviceId deviceId);
+
+/**
+ * Request a sample rate in Hz.
+ * The stream may be opened with a different sample rate.
+ * So the application should query for the actual rate after the stream is opened.
+ *
+ * Technically, this should be called the "frame rate" or "frames per second",
+ * because it refers to the number of complete frames transferred per second.
+ * But it is traditionally called "sample rate". Se we use that term.
+ *
+ * Default is OBOE_UNSPECIFIED.
+ *
+ * @return OBOE_OK or a negative error.
+ */
+oboe_result_t OboeStreamBuilder_setSampleRate(OboeStreamBuilder builder,
+                                              oboe_sample_rate_t sampleRate);
+
+/**
+ * Returns sample rate in Hertz (samples per second).
+ * @return OBOE_OK or a negative error.
+ */
+oboe_result_t OboeStreamBuilder_getSampleRate(OboeStreamBuilder builder,
+                                              oboe_sample_rate_t *sampleRate);
+
+
+/**
+ * Request a number of samples per frame.
+ * The stream may be opened with a different value.
+ * So the application should query for the actual value after the stream is opened.
+ *
+ * Default is OBOE_UNSPECIFIED.
+ *
+ * Note, this quantity is sometimes referred to as "channel count".
+ *
+ * @return OBOE_OK or a negative error.
+ */
+oboe_result_t OboeStreamBuilder_setSamplesPerFrame(OboeStreamBuilder builder,
+                                                   int32_t samplesPerFrame);
+
+/**
+ * Note, this quantity is sometimes referred to as "channel count".
+ *
+ * @param builder handle provided by Oboe_createStreamBuilder()
+ * @param samplesPerFrame pointer to a variable to be set to samplesPerFrame.
+ * @return OBOE_OK or a negative error.
+ */
+oboe_result_t OboeStreamBuilder_getSamplesPerFrame(OboeStreamBuilder builder,
+                                                   int32_t *samplesPerFrame);
+
+
+/**
+ * Request a sample data format, for example OBOE_AUDIO_FORMAT_PCM16.
+ * The application should query for the actual format after the stream is opened.
+ *
+ * @return OBOE_OK or a negative error.
+ */
+oboe_result_t OboeStreamBuilder_setFormat(OboeStreamBuilder builder, oboe_audio_format_t format);
+
+/**
+ * @return OBOE_OK or a negative error.
+ */
+oboe_result_t OboeStreamBuilder_getFormat(OboeStreamBuilder builder, oboe_audio_format_t *format);
+
+/**
+ * Request a mode for sharing the device.
+ * The requested sharing mode may not be available.
+ * So the application should query for the actual mode after the stream is opened.
+ *
+ * @param builder handle provided by Oboe_createStreamBuilder()
+ * @param sharingMode OBOE_SHARING_MODE_LEGACY or OBOE_SHARING_MODE_EXCLUSIVE
+ * @return OBOE_OK or a negative error.
+ */
+oboe_result_t OboeStreamBuilder_setSharingMode(OboeStreamBuilder builder,
+                                               oboe_sharing_mode_t sharingMode);
+
+/**
+ * Return requested sharing mode.
+ * @return OBOE_OK or a negative error
+ */
+oboe_result_t OboeStreamBuilder_getSharingMode(OboeStreamBuilder builder,
+                                               oboe_sharing_mode_t *sharingMode);
+
+/**
+ * Request the direction for a stream. The default is OBOE_DIRECTION_OUTPUT.
+ *
+ * @param builder handle provided by Oboe_createStreamBuilder()
+ * @param direction OBOE_DIRECTION_OUTPUT or OBOE_DIRECTION_INPUT
+ * @return OBOE_OK or a negative error.
+ */
+oboe_result_t OboeStreamBuilder_setDirection(OboeStreamBuilder builder,
+                                             oboe_direction_t direction);
+
+/**
+ * @param builder handle provided by Oboe_createStreamBuilder()
+ * @param direction pointer to a variable to be set to the currently requested direction.
+ * @return OBOE_OK or a negative error.
+ */
+oboe_result_t OboeStreamBuilder_getDirection(OboeStreamBuilder builder,
+                                             oboe_direction_t *direction);
+
+/**
+ * Open a stream based on the options in the StreamBuilder.
+ *
+ * OboeStream_close must be called when finished with the stream to recover
+ * the memory and to free the associated resources.
+ *
+ * @param builder handle provided by Oboe_createStreamBuilder()
+ * @param stream pointer to a variable to receive the new stream handle
+ * @return OBOE_OK or a negative error.
+ */
+oboe_result_t  OboeStreamBuilder_openStream(OboeStreamBuilder builder, OboeStream *stream);
+
+/**
+ * Delete the resources associated with the StreamBuilder.
+ *
+ * @param builder handle provided by Oboe_createStreamBuilder()
+ * @return OBOE_OK or a negative error.
+ */
+oboe_result_t  OboeStreamBuilder_delete(OboeStreamBuilder builder);
+
+// ============================================================
+// Stream Control
+// ============================================================
+
+/**
+ * Free the resources associated with a stream created by OboeStreamBuilder_openStream()
+ *
+ * @param stream handle provided by OboeStreamBuilder_openStream()
+ * @return OBOE_OK or a negative error.
+ */
+oboe_result_t  OboeStream_close(OboeStream stream);
+
+/**
+ * Asynchronously request to start playing the stream. For output streams, one should
+ * write to the stream to fill the buffer before starting.
+ * Otherwise it will underflow.
+ * After this call the state will be in OBOE_STREAM_STATE_STARTING or OBOE_STREAM_STATE_STARTED.
+ *
+ * @param stream handle provided by OboeStreamBuilder_openStream()
+ * @return OBOE_OK or a negative error.
+ */
+oboe_result_t  OboeStream_requestStart(OboeStream stream);
+
+/**
+ * Asynchronous request for the stream to pause.
+ * Pausing a stream will freeze the data flow but not flush any buffers.
+ * Use OboeStream_Start() to resume playback after a pause.
+ * After this call the state will be in OBOE_STREAM_STATE_PAUSING or OBOE_STREAM_STATE_PAUSED.
+ *
+ * @param stream handle provided by OboeStreamBuilder_openStream()
+ * @return OBOE_OK or a negative error.
+ */
+oboe_result_t  OboeStream_requestPause(OboeStream stream);
+
+/**
+ * Asynchronous request for the stream to flush.
+ * Flushing will discard any pending data.
+ * This call only works if the stream is pausing or paused. TODO review
+ * Frame counters are not reset by a flush. They may be advanced.
+ * After this call the state will be in OBOE_STREAM_STATE_FLUSHING or OBOE_STREAM_STATE_FLUSHED.
+ *
+ * @param stream handle provided by OboeStreamBuilder_openStream()
+ * @return OBOE_OK or a negative error.
+ */
+oboe_result_t  OboeStream_requestFlush(OboeStream stream);
+
+/**
+ * Asynchronous request for the stream to stop.
+ * The stream will stop after all of the data currently buffered has been played.
+ * After this call the state will be in OBOE_STREAM_STATE_STOPPING or OBOE_STREAM_STATE_STOPPED.
+ *
+ * @param stream handle provided by OboeStreamBuilder_openStream()
+ * @return OBOE_OK or a negative error.
+ */
+oboe_result_t  OboeStream_requestStop(OboeStream stream);
+
+/**
+ * Query the current state, eg. OBOE_STREAM_STATE_PAUSING
+ *
+ * @param stream handle provided by OboeStreamBuilder_openStream()
+ * @param state pointer to a variable that will be set to the current state
+ * @return OBOE_OK or a negative error.
+ */
+oboe_result_t OboeStream_getState(OboeStream stream, oboe_stream_state_t *state);
+
+/**
+ * Wait until the current state no longer matches the input state.
+ *
+ * <pre><code>
+ * oboe_stream_state_t currentState;
+ * oboe_result_t result = OboeStream_getState(stream, &currentState);
+ * while (result == OBOE_OK && currentState != OBOE_STREAM_STATE_PAUSING) {
+ *     result = OboeStream_waitForStateChange(
+ *                                   stream, currentState, &currentState, MY_TIMEOUT_NANOS);
+ * }
+ * </code></pre>
+ *
+ * @param stream A handle provided by OboeStreamBuilder_openStream()
+ * @param inputState The state we want to avoid.
+ * @param nextState Pointer to a variable that will be set to the new state.
+ * @param timeoutNanoseconds Maximum number of nanoseconds to wait for completion.
+ * @return OBOE_OK or a negative error.
+ */
+oboe_result_t OboeStream_waitForStateChange(OboeStream stream,
+                                            oboe_stream_state_t inputState,
+                                            oboe_stream_state_t *nextState,
+                                            oboe_nanoseconds_t timeoutNanoseconds);
+
+// ============================================================
+// Stream I/O
+// ============================================================
+
+/**
+ * Read data from the stream.
+ *
+ * The call will wait until the read is complete or until it runs out of time.
+ * If timeoutNanos is zero then this call will not wait.
+ *
+ * Note that timeoutNanoseconds is a relative duration in wall clock time.
+ * Time will not stop if the thread is asleep.
+ * So it will be implemented using CLOCK_BOOTTIME.
+ *
+ * This call is "strong non-blocking" unless it has to wait for data.
+ *
+ * @param stream A stream created using OboeStreamBuilder_openStream().
+ * @param buffer The address of the first sample.
+ * @param numFrames Number of frames to read. Only complete frames will be written.
+ * @param timeoutNanoseconds Maximum number of nanoseconds to wait for completion.
+ * @return The number of frames actually written or a negative error.
+ */
+oboe_result_t OboeStream_read(OboeStream stream,
+                               void *buffer,
+                               int32_t numFrames,
+                               oboe_nanoseconds_t timeoutNanoseconds);
+
+/**
+ * Write data to the stream.
+ *
+ * The call will wait until the write is complete or until it runs out of time.
+ * If timeoutNanos is zero then this call will not wait.
+ *
+ * Note that timeoutNanoseconds is a relative duration in wall clock time.
+ * Time will not stop if the thread is asleep.
+ * So it will be implemented using CLOCK_BOOTTIME.
+ *
+ * This call is "strong non-blocking" unless it has to wait for room in the buffer.
+ *
+ * @param stream A stream created using OboeStreamBuilder_openStream().
+ * @param buffer The address of the first sample.
+ * @param numFrames Number of frames to write. Only complete frames will be written.
+ * @param timeoutNanoseconds Maximum number of nanoseconds to wait for completion.
+ * @return The number of frames actually written or a negative error.
+ */
+oboe_result_t OboeStream_write(OboeStream stream,
+                               const void *buffer,
+                               int32_t numFrames,
+                               oboe_nanoseconds_t timeoutNanoseconds);
+
+
+// ============================================================
+// High priority audio threads
+// ============================================================
+
+/**
+ * Create a thread with special properties for low latency audio performance.
+ * This thread can be used to implement a callback API.
+ *
+ * Note that this API is in flux.
+ *
+ * @param threadHandlePtr a pointer to receive a thread handle
+ * @param periodNanoseconds the estimated period at which the audio thread will need to wake up
+ * @param start_routine your thread entry point
+ * @param arg an argument that will be passed to your thread entry point
+ * @return OBOE_OK or a negative error.
+ */
+oboe_result_t Oboe_createAudioThread(OboeThread *threadHandlePtr,
+                                     oboe_nanoseconds_t periodNanoseconds,
+                                     void *(*start_routine)(void *), void *arg);
+
+/**
+ * Wait until the thread exits or an error occurs.
+ * The thread handle will be deleted.
+ *
+ * @param thread the thread handle passed back from Oboe_createAudioThread()
+ * @param returnArg a pointer to a variable to receive the return value
+ * @param timeoutNanoseconds Maximum number of nanoseconds to wait for completion.
+ * @return OBOE_OK or a negative error.
+ */
+oboe_result_t Oboe_joinAudioThread(OboeThread thread,
+                                   void **returnArg,
+                                   oboe_nanoseconds_t timeoutNanoseconds);
+
+// ============================================================
+// Stream - queries
+// ============================================================
+
+
+/**
+ * This can be used to adjust the latency of the buffer by changing
+ * the threshold where blocking will occur.
+ * By combining this with OboeStream_getUnderrunCount(), the latency can be tuned
+ * at run-time for each device.
+ *
+ * This cannot be set higher than OboeStream_getBufferCapacity().
+ *
+ * @param stream handle provided by OboeStreamBuilder_openStream()
+ * @param frames requested number of frames that can be filled without blocking
+ * @return actual number of frames or a negative error
+ */
+oboe_result_t OboeStream_setBufferSize(OboeStream stream, oboe_size_frames_t frames);
+
+/**
+ * Query the maximum number of frames that can be filled without blocking.
+ *
+ * @param stream handle provided by OboeStreamBuilder_openStream()
+ * @param frames pointer to variable to receive the buffer size
+ * @return OBOE_OK or a negative error.
+ */
+oboe_result_t OboeStream_getBufferSize(OboeStream stream, oboe_size_frames_t *frames);
+
+/**
+ * Query the number of frames that are read or written by the endpoint at one time.
+ *
+ * @param stream handle provided by OboeStreamBuilder_openStream()
+ * @param frames pointer to variable to receive the burst size
+ * @return OBOE_OK or a negative error.
+ */
+oboe_result_t OboeStream_getFramesPerBurst(OboeStream stream, oboe_size_frames_t *frames);
+
+/**
+ * Query maximum buffer capacity in frames.
+ *
+ * @param stream handle provided by OboeStreamBuilder_openStream()
+ * @param frames pointer to variable to receive the buffer capacity
+ * @return OBOE_OK or a negative error.
+ */
+oboe_result_t OboeStream_getBufferCapacity(OboeStream stream, oboe_size_frames_t *frames);
+
+/**
+ * An XRun is an Underrun or an Overrun.
+ * During playing, an underrun will occur if the stream is not written in time
+ * and the system runs out of valid data.
+ * During recording, an overrun will occur if the stream is not read in time
+ * and there is no place to put the incoming data so it is discarded.
+ *
+ * An underrun or overrun can cause an audible "pop" or "glitch".
+ *
+ * @param stream handle provided by OboeStreamBuilder_openStream()
+ * @param xRunCount pointer to variable to receive the underrun or overrun count
+ * @return OBOE_OK or a negative error.
+ */
+oboe_result_t OboeStream_getXRunCount(OboeStream stream, int32_t *xRunCount);
+
+/**
+ * @param stream handle provided by OboeStreamBuilder_openStream()
+ * @param sampleRate pointer to variable to receive the actual sample rate
+ * @return OBOE_OK or a negative error.
+ */
+oboe_result_t OboeStream_getSampleRate(OboeStream stream, int32_t *sampleRate);
+
+/**
+ * The samplesPerFrame is also known as channelCount.
+ *
+ * @param stream handle provided by OboeStreamBuilder_openStream()
+ * @param samplesPerFrame pointer to variable to receive the actual samples per frame
+ * @return OBOE_OK or a negative error.
+ */
+oboe_result_t OboeStream_getSamplesPerFrame(OboeStream stream, int32_t *samplesPerFrame);
+
+/**
+ * @param stream handle provided by OboeStreamBuilder_openStream()
+ * @param format pointer to variable to receive the actual data format
+ * @return OBOE_OK or a negative error.
+ */
+oboe_result_t OboeStream_getFormat(OboeStream stream, oboe_audio_format_t *format);
+
+/**
+ * Provide actual sharing mode.
+ * @param stream handle provided by OboeStreamBuilder_openStream()
+ * @param sharingMode pointer to variable to receive the actual sharing mode
+ * @return OBOE_OK or a negative error.
+ */
+oboe_result_t OboeStream_getSharingMode(OboeStream stream,
+                                        oboe_sharing_mode_t *sharingMode);
+
+/**
+ * @param stream handle provided by OboeStreamBuilder_openStream()
+ * @param direction pointer to a variable to be set to the current direction.
+ * @return OBOE_OK or a negative error.
+ */
+oboe_result_t OboeStream_getDirection(OboeStream stream, uint32_t *direction);
+
+/**
+ * Passes back the number of frames that have been written since the stream was created.
+ * For an output stream, this will be advanced by the application calling write().
+ * For an input stream, this will be advanced by the device or service.
+ *
+ * The frame position is monotonically increasing.
+ *
+ * @param stream handle provided by OboeStreamBuilder_openStream()
+ * @param frames pointer to variable to receive the frames written
+ * @return OBOE_OK or a negative error.
+ */
+oboe_result_t OboeStream_getFramesWritten(OboeStream stream, oboe_position_frames_t *frames);
+
+/**
+ * Passes back the number of frames that have been read since the stream was created.
+ * For an output stream, this will be advanced by the device or service.
+ * For an input stream, this will be advanced by the application calling read().
+ *
+ * The frame position is monotonically increasing.
+ *
+ * @param stream handle provided by OboeStreamBuilder_openStream()
+ * @param frames pointer to variable to receive the frames written
+ * @return OBOE_OK or a negative error.
+ */
+oboe_result_t OboeStream_getFramesRead(OboeStream stream, oboe_position_frames_t *frames);
+
+/**
+ * Passes back the time at which a particular frame was presented.
+ * This can be used to synchronize audio with video or MIDI.
+ * It can also be used to align a recorded stream with a playback stream.
+ *
+ * Timestamps are only valid when the stream is in OBOE_STREAM_STATE_STARTED.
+ * OBOE_ERROR_INVALID_STATE will be returned if the stream is not started.
+ * Note that because requestStart() is asynchronous, timestamps will not be valid until
+ * a short time after calling requestStart().
+ * So OBOE_ERROR_INVALID_STATE should not be considered a fatal error.
+ * Just try calling again later.
+ *
+ * If an error occurs, then the position and time will not be modified.
+ *
+ * The position and time passed back are monotonically increasing.
+ *
+ * @param stream A handle provided by OboeStreamBuilder_openStream()
+ * @param clockId OBOE_CLOCK_MONOTONIC or OBOE_CLOCK_BOOTTIME
+ * @param framePosition pointer to a variable to receive the position
+ * @param timeNanoseconds pointer to a variable to receive the time
+ * @return OBOE_OK or a negative error
+ */
+oboe_result_t OboeStream_getTimestamp(OboeStream stream,
+                                      oboe_clockid_t clockid,
+                                      oboe_position_frames_t *framePosition,
+                                      oboe_nanoseconds_t *timeNanoseconds);
+
+#endif //NATIVEOBOE_OBOEAUDIO_H
diff --git a/media/liboboe/include/oboe/OboeDefinitions.h b/media/liboboe/include/oboe/OboeDefinitions.h
new file mode 100644
index 0000000..b3e2deb
--- /dev/null
+++ b/media/liboboe/include/oboe/OboeDefinitions.h
@@ -0,0 +1,177 @@
+/*
+ * 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 OBOE_OBOEDEFINITIONS_H
+#define OBOE_OBOEDEFINITIONS_H
+
+#include <stdint.h>
+
+typedef int32_t  oboe_handle_t;
+typedef int32_t  oboe_result_t;
+typedef int32_t  oboe_sample_rate_t;
+/** This is used for small quantities such as the number of frames in a buffer. */
+typedef int32_t  oboe_size_frames_t;
+/** This is used for large quantities, such as the number of frames that have
+ * been played since a stream was started.
+ * At 48000 Hz, a 32-bit integer would wrap around in just over 12 hours.
+ */
+typedef int64_t  oboe_position_frames_t;
+
+typedef int64_t  oboe_nanoseconds_t;
+typedef uint32_t oboe_audio_format_t;
+
+/**
+ * This is used to represent a value that has not been specified.
+ * For example, an application could use OBOE_UNSPECIFIED to indicate
+ * that is did not not care what the specific value of a parameter was
+ * and would accept whatever it was given.
+ */
+#define OBOE_UNSPECIFIED           0
+#define OBOE_NANOS_PER_MICROSECOND ((int64_t)1000)
+#define OBOE_NANOS_PER_MILLISECOND (OBOE_NANOS_PER_MICROSECOND * 1000)
+#define OBOE_MILLIS_PER_SECOND     1000
+#define OBOE_NANOS_PER_SECOND      (OBOE_NANOS_PER_MILLISECOND * OBOE_MILLIS_PER_SECOND)
+
+#define OBOE_HANDLE_INVALID     ((oboe_handle_t)-1)
+
+enum oboe_direction_t {
+    OBOE_DIRECTION_OUTPUT,
+    OBOE_DIRECTION_INPUT,
+    OBOE_DIRECTION_COUNT // This should always be last.
+};
+
+enum oboe_datatype_t {
+    OBOE_AUDIO_DATATYPE_INT16,
+    OBOE_AUDIO_DATATYPE_INT32,
+    OBOE_AUDIO_DATATYPE_INT824,
+    OBOE_AUDIO_DATATYPE_UINT8,
+    OBOE_AUDIO_DATATYPE_FLOAT32, // Add new values below.
+    OBOE_AUDIO_DATATYPE_COUNT // This should always be last.
+};
+
+enum oboe_content_t {
+    OBOE_AUDIO_CONTENT_PCM,
+    OBOE_AUDIO_CONTENT_MP3,
+    OBOE_AUDIO_CONTENT_AAC,
+    OBOE_AUDIO_CONTENT_AC3,
+    OBOE_AUDIO_CONTENT_EAC3,
+    OBOE_AUDIO_CONTENT_DTS,
+    OBOE_AUDIO_CONTENT_DTSHD, // Add new values below.
+    OBOE_AUDIO_CONTENT_COUNT // This should always be last.
+};
+
+enum oboe_wrapper_t {
+    OBOE_AUDIO_WRAPPER_NONE,
+    OBOE_AUDIO_WRAPPER_IEC61937, // Add new values below.
+    OBOE_AUDIO_WRAPPER_COUNT // This should always be last.
+};
+
+/**
+ * Fields packed into oboe_audio_format_t, from most to least significant bits.
+ *   Reserved:8
+ *   Wrapper:8
+ *   Content:8
+ *   Data Type:8
+ */
+#define OBOE_AUDIO_FORMAT(dataType, content, wrapper) \
+    ((oboe_audio_format_t)((wrapper << 16) | (content << 8) | dataType))
+
+#define OBOE_AUDIO_FORMAT_RAW(dataType, content) \
+                OBOE_AUDIO_FORMAT(dataType, content, OBOE_AUDIO_WRAPPER_NONE)
+
+#define OBOE_AUDIO_FORMAT_DATA_TYPE(format) \
+    (format & 0x0FF)
+
+// Define some common formats.
+#define OBOE_AUDIO_FORMAT_PCM16  \
+                OBOE_AUDIO_FORMAT_RAW(OBOE_AUDIO_DATATYPE_INT16, OBOE_AUDIO_CONTENT_PCM)
+#define OBOE_AUDIO_FORMAT_PCM_FLOAT \
+                OBOE_AUDIO_FORMAT_RAW(OBOE_AUDIO_DATATYPE_FLOAT32, OBOE_AUDIO_CONTENT_PCM)
+#define OBOE_AUDIO_FORMAT_PCM824 \
+                OBOE_AUDIO_FORMAT_RAW(OBOE_AUDIO_DATATYPE_INT824, OBOE_AUDIO_CONTENT_PCM)
+
+enum {
+    OBOE_OK,
+    OBOE_ERROR_BASE = -900, // TODO review
+    OBOE_ERROR_DISCONNECTED,
+    OBOE_ERROR_ILLEGAL_ARGUMENT,
+    OBOE_ERROR_INCOMPATIBLE,
+    OBOE_ERROR_INTERNAL, // an underlying API returned an error code
+    OBOE_ERROR_INVALID_STATE,
+    OBOE_ERROR_UNEXPECTED_STATE,
+    OBOE_ERROR_UNEXPECTED_VALUE,
+    OBOE_ERROR_INVALID_HANDLE,
+    OBOE_ERROR_INVALID_QUERY,
+    OBOE_ERROR_UNIMPLEMENTED,
+    OBOE_ERROR_UNAVAILABLE,
+    OBOE_ERROR_NO_FREE_HANDLES,
+    OBOE_ERROR_NO_MEMORY,
+    OBOE_ERROR_NULL,
+    OBOE_ERROR_TIMEOUT,
+    OBOE_ERROR_WOULD_BLOCK,
+    OBOE_ERROR_INVALID_ORDER
+};
+
+typedef enum {
+    OBOE_CLOCK_MONOTONIC, // Clock since booted, pauses when CPU is sleeping.
+    OBOE_CLOCK_BOOTTIME,  // Clock since booted, runs all the time.
+    OBOE_CLOCK_COUNT // This should always be last.
+} oboe_clockid_t;
+
+typedef enum
+{
+    OBOE_STREAM_STATE_UNINITIALIZED = 0,
+    OBOE_STREAM_STATE_OPEN,
+    OBOE_STREAM_STATE_STARTING,
+    OBOE_STREAM_STATE_STARTED,
+    OBOE_STREAM_STATE_PAUSING,
+    OBOE_STREAM_STATE_PAUSED,
+    OBOE_STREAM_STATE_FLUSHING,
+    OBOE_STREAM_STATE_FLUSHED,
+    OBOE_STREAM_STATE_STOPPING,
+    OBOE_STREAM_STATE_STOPPED,
+    OBOE_STREAM_STATE_CLOSING,
+    OBOE_STREAM_STATE_CLOSED,
+} oboe_stream_state_t;
+
+// TODO review API
+typedef enum {
+    /**
+     * This will use an AudioTrack object for playing audio
+     * and an AudioRecord for recording data.
+     */
+    OBOE_SHARING_MODE_LEGACY,
+    /**
+     * This will be the only stream using a particular source or sink.
+     * This mode will provide the lowest possible latency.
+     * You should close EXCLUSIVE streams immediately when you are not using them.
+     */
+    OBOE_SHARING_MODE_EXCLUSIVE,
+    /**
+     * Multiple applications will be mixed by the Oboe Server.
+     * This will have higher latency than the EXCLUSIVE mode.
+     */
+    OBOE_SHARING_MODE_SHARED,
+    /**
+     * Multiple applications will do their own mixing into a memory mapped buffer.
+     * It may be possible for malicious applications to read the data produced by
+     * other apps. So do not use this for private data such as telephony or messaging.
+     */
+    OBOE_SHARING_MODE_PUBLIC_MIX,
+    OBOE_SHARING_MODE_COUNT // This should always be last.
+} oboe_sharing_mode_t;
+
+#endif // OBOE_OBOEDEFINITIONS_H
diff --git a/media/liboboe/include/oboe/README.md b/media/liboboe/include/oboe/README.md
new file mode 100644
index 0000000..de60d03
--- /dev/null
+++ b/media/liboboe/include/oboe/README.md
@@ -0,0 +1,4 @@
+Oboe Audio headers
+
+This folder contains the public header files.
+
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index 21c90f0..f247475 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -53,6 +53,7 @@
 #include <OMX_AsString.h>
 
 #include "include/avc_utils.h"
+#include "include/ACodecBufferChannel.h"
 #include "include/DataConverter.h"
 #include "include/SecureBuffer.h"
 #include "include/SharedMemoryBuffer.h"
@@ -564,16 +565,21 @@
 ACodec::~ACodec() {
 }
 
-void ACodec::setNotificationMessage(const sp<AMessage> &msg) {
-    mNotify = msg;
-}
-
 void ACodec::initiateSetup(const sp<AMessage> &msg) {
     msg->setWhat(kWhatSetup);
     msg->setTarget(this);
     msg->post();
 }
 
+std::shared_ptr<BufferChannelBase> ACodec::getBufferChannel() {
+    if (!mBufferChannel) {
+        mBufferChannel = std::make_shared<ACodecBufferChannel>(
+                new AMessage(kWhatInputBufferFilled, this),
+                new AMessage(kWhatOutputBufferDrained, this));
+    }
+    return mBufferChannel;
+}
+
 void ACodec::signalSetParameters(const sp<AMessage> &params) {
     sp<AMessage> msg = new AMessage(kWhatSetParameters, this);
     msg->setMessage("params", params);
@@ -882,6 +888,8 @@
                 info.mStatus = BufferInfo::OWNED_BY_US;
                 info.mFenceFd = -1;
                 info.mRenderInfo = NULL;
+                info.mGraphicBuffer = NULL;
+                info.mNewGraphicBuffer = false;
 
                 if (mode == IOMX::kPortModePresetSecureBuffer) {
                     void *ptr = NULL;
@@ -934,20 +942,17 @@
         return err;
     }
 
-    sp<AMessage> notify = mNotify->dup();
-    notify->setInt32("what", CodecBase::kWhatBuffersAllocated);
-
-    notify->setInt32("portIndex", portIndex);
-
-    sp<PortDescription> desc = new PortDescription;
-
+    std::vector<ACodecBufferChannel::BufferAndId> array(mBuffers[portIndex].size());
     for (size_t i = 0; i < mBuffers[portIndex].size(); ++i) {
-        const BufferInfo &info = mBuffers[portIndex][i];
-        desc->addBuffer(info.mBufferID, info.mData);
+        array[i] = {mBuffers[portIndex][i].mData, mBuffers[portIndex][i].mBufferID};
     }
-
-    notify->setObject("portDesc", desc);
-    notify->post();
+    if (portIndex == kPortIndexInput) {
+        mBufferChannel->setInputBufferArray(array);
+    } else if (portIndex == kPortIndexOutput) {
+        mBufferChannel->setOutputBufferArray(array);
+    } else {
+        TRESPASS();
+    }
 
     return OK;
 }
@@ -1124,6 +1129,7 @@
         info.mIsReadFence = false;
         info.mRenderInfo = NULL;
         info.mGraphicBuffer = graphicBuffer;
+        info.mNewGraphicBuffer = false;
 
         // TODO: We shouln't need to create MediaCodecBuffer. In metadata mode
         //       OMX doesn't use the shared memory buffer, but some code still
@@ -1198,6 +1204,7 @@
         info.mFenceFd = -1;
         info.mRenderInfo = NULL;
         info.mGraphicBuffer = NULL;
+        info.mNewGraphicBuffer = false;
         info.mDequeuedAt = mDequeueCounter;
 
         info.mData = new MediaCodecBuffer(mOutputFormat, new ABuffer(bufferSize));
@@ -1229,7 +1236,7 @@
     }
 
     ALOGV("[%s] submitting output meta buffer ID %u for graphic buffer %p",
-          mComponentName.c_str(), info->mBufferID, info->mGraphicBuffer.get());
+          mComponentName.c_str(), info->mBufferID, info->mGraphicBuffer->handle);
 
     --mMetadataBuffersToSubmit;
     info->checkWriteFence("submitOutputMetadataBuffer");
@@ -1309,8 +1316,6 @@
 }
 
 void ACodec::notifyOfRenderedFrames(bool dropIncomplete, FrameRenderTracker::Info *until) {
-    sp<AMessage> msg = mNotify->dup();
-    msg->setInt32("what", CodecBase::kWhatOutputFramesRendered);
     std::list<FrameRenderTracker::Info> done =
         mRenderTracker.checkFencesAndGetRenderedFrames(until, dropIncomplete);
 
@@ -1326,9 +1331,7 @@
         }
     }
 
-    if (MediaCodec::CreateFramesRenderedMessage(done, msg)) {
-        msg->post();
-    }
+    mCallback->onOutputFramesRendered(done);
 }
 
 ACodec::BufferInfo *ACodec::dequeueBufferFromNativeWindow() {
@@ -1374,7 +1377,11 @@
                     break;
                 }
 
-                ALOGV("dequeued buffer %p", info->mGraphicBuffer->getNativeBuffer());
+                ALOGV("dequeued buffer #%u with age %u, graphicBuffer %p",
+                        (unsigned)(info - &mBuffers[kPortIndexOutput][0]),
+                        mDequeueCounter - info->mDequeuedAt,
+                        info->mGraphicBuffer->handle);
+
                 info->mStatus = BufferInfo::OWNED_BY_US;
                 info->setWriteFence(fenceFd, "dequeueBufferFromNativeWindow");
                 updateRenderInfoForDequeuedBuffer(buf, fenceFd, info);
@@ -1420,6 +1427,7 @@
 
     // discard buffer in LRU info and replace with new buffer
     oldest->mGraphicBuffer = new GraphicBuffer(buf, false);
+    oldest->mNewGraphicBuffer = true;
     oldest->mStatus = BufferInfo::OWNED_BY_US;
     oldest->setWriteFence(fenceFd, "dequeueBufferFromNativeWindow for oldest");
     mRenderTracker.untrackFrame(oldest->mRenderInfo);
@@ -1428,13 +1436,19 @@
     ALOGV("replaced oldest buffer #%u with age %u, graphicBuffer %p",
             (unsigned)(oldest - &mBuffers[kPortIndexOutput][0]),
             mDequeueCounter - oldest->mDequeuedAt,
-            oldest->mGraphicBuffer->getNativeBuffer());
+            oldest->mGraphicBuffer->handle);
 
     updateRenderInfoForDequeuedBuffer(buf, fenceFd, oldest);
     return oldest;
 }
 
 status_t ACodec::freeBuffersOnPort(OMX_U32 portIndex) {
+    if (portIndex == kPortIndexInput) {
+        mBufferChannel->setInputBufferArray({});
+    } else {
+        mBufferChannel->setOutputBufferArray({});
+    }
+
     status_t err = OK;
     for (size_t i = mBuffers[portIndex].size(); i > 0;) {
         i--;
@@ -1534,7 +1548,13 @@
 
 status_t ACodec::fillBuffer(BufferInfo *info) {
     status_t err;
-    if (!storingMetadataInDecodedBuffers()) {
+    // Even in dynamic ANW buffer mode, if the graphic buffer is not changing,
+    // send sPreset instead of the same graphic buffer, so that OMX server
+    // side doesn't update the meta. In theory it should make no difference,
+    // however when the same buffer is parcelled again, a new handle could be
+    // created on server side, and some decoder doesn't recognize the handle
+    // even if it's the same buffer.
+    if (!storingMetadataInDecodedBuffers() || !info->mNewGraphicBuffer) {
         err = mOMXNode->fillBuffer(
             info->mBufferID, OMXBuffer::sPreset, info->mFenceFd);
     } else {
@@ -1542,6 +1562,7 @@
             info->mBufferID, info->mGraphicBuffer, info->mFenceFd);
     }
 
+    info->mNewGraphicBuffer = false;
     info->mFenceFd = -1;
     if (err == OK) {
         info->mStatus = BufferInfo::OWNED_BY_COMPONENT;
@@ -5072,25 +5093,6 @@
     }
 }
 
-void ACodec::addKeyFormatChangesToRenderBufferNotification(sp<AMessage> &notify) {
-    AString mime;
-    CHECK(mOutputFormat->findString("mime", &mime));
-
-    if (mime == MEDIA_MIMETYPE_VIDEO_RAW && mNativeWindow != NULL) {
-        // notify renderer of the crop change and dataspace change
-        // NOTE: native window uses extended right-bottom coordinate
-        int32_t left, top, right, bottom;
-        if (mOutputFormat->findRect("crop", &left, &top, &right, &bottom)) {
-            notify->setRect("crop", left, top, right + 1, bottom + 1);
-        }
-
-        int32_t dataSpace;
-        if (mOutputFormat->findInt32("android._dataspace", &dataSpace)) {
-            notify->setInt32("dataspace", dataSpace);
-        }
-    }
-}
-
 void ACodec::sendFormatChange() {
     AString mime;
     CHECK(mOutputFormat->findString("mime", &mime));
@@ -5118,8 +5120,6 @@
 }
 
 void ACodec::signalError(OMX_ERRORTYPE error, status_t internalError) {
-    sp<AMessage> notify = mNotify->dup();
-    notify->setInt32("what", CodecBase::kWhatError);
     ALOGE("signalError(omxError %#x, internalError %d)", error, internalError);
 
     if (internalError == UNKNOWN_ERROR) { // find better error code
@@ -5132,10 +5132,7 @@
     }
 
     mFatalError = true;
-
-    notify->setInt32("err", internalError);
-    notify->setInt32("actionCode", ACTION_CODE_FATAL); // could translate from OMX error.
-    notify->post();
+    mCallback->onError(internalError, ACTION_CODE_FATAL);
 }
 
 status_t ACodec::requestIDRFrame() {
@@ -5157,29 +5154,6 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 
-ACodec::PortDescription::PortDescription() {
-}
-
-void ACodec::PortDescription::addBuffer(
-        IOMX::buffer_id id, const sp<MediaCodecBuffer> &buffer) {
-    mBufferIDs.push_back(id);
-    mBuffers.push_back(buffer);
-}
-
-size_t ACodec::PortDescription::countBuffers() {
-    return mBufferIDs.size();
-}
-
-IOMX::buffer_id ACodec::PortDescription::bufferIDAt(size_t index) const {
-    return mBufferIDs.itemAt(index);
-}
-
-sp<MediaCodecBuffer> ACodec::PortDescription::bufferAt(size_t index) const {
-    return mBuffers.itemAt(index);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-
 ACodec::BaseState::BaseState(ACodec *codec, const sp<AState> &parentState)
     : AState(parentState),
       mCodec(codec) {
@@ -5262,9 +5236,7 @@
             status_t err = mCodec->mOMXNode->freeNode();
             ALOGE_IF("[%s] failed to release codec instance: err=%d",
                        mCodec->mComponentName.c_str(), err);
-            sp<AMessage> notify = mCodec->mNotify->dup();
-            notify->setInt32("what", CodecBase::kWhatReleaseCompleted);
-            notify->post();
+            mCodec->mCallback->onReleaseCompleted();
             break;
         }
 
@@ -5488,21 +5460,9 @@
 
     CHECK_EQ((int)info->mStatus, (int)BufferInfo::OWNED_BY_US);
 
-    sp<AMessage> notify = mCodec->mNotify->dup();
-    notify->setInt32("what", CodecBase::kWhatFillThisBuffer);
-    notify->setInt32("buffer-id", info->mBufferID);
-
     info->mData->setFormat(mCodec->mInputFormat);
-    notify->setObject("buffer", info->mData);
+    mCodec->mBufferChannel->fillThisBuffer(info->mBufferID);
     info->mData.clear();
-
-    sp<AMessage> reply = new AMessage(kWhatInputBufferFilled, mCodec);
-    reply->setInt32("buffer-id", info->mBufferID);
-
-    notify->setMessage("reply", reply);
-
-    notify->post();
-
     info->mStatus = BufferInfo::OWNED_BY_UPSTREAM;
 }
 
@@ -5513,23 +5473,15 @@
     int32_t err = OK;
     bool eos = false;
     PortMode mode = getPortMode(kPortIndexInput);
-
-    sp<RefBase> obj;
-    if (!msg->findObject("buffer", &obj)) {
-        /* these are unfilled buffers returned by client */
-        CHECK(msg->findInt32("err", &err));
-
-        if (err == OK) {
-            /* buffers with no errors are returned on MediaCodec.flush */
-            mode = KEEP_BUFFERS;
-        } else {
-            ALOGV("[%s] saw error %d instead of an input buffer",
-                 mCodec->mComponentName.c_str(), err);
-            eos = true;
-        }
-    } else {
-        buffer = static_cast<MediaCodecBuffer *>(obj.get());
+    int32_t discarded = 0;
+    if (msg->findInt32("discarded", &discarded) && discarded) {
+        // these are unfilled buffers returned by client
+        // buffers are returned on MediaCodec.flush
+        mode = KEEP_BUFFERS;
     }
+    sp<RefBase> obj;
+    CHECK(msg->findObject("buffer", &obj));
+    buffer = static_cast<MediaCodecBuffer *>(obj.get());
 
     int32_t tmp;
     if (buffer != NULL && buffer->meta()->findInt32("eos", &tmp) && tmp) {
@@ -5852,8 +5804,6 @@
                 break;
             }
 
-            sp<AMessage> reply =
-                new AMessage(kWhatOutputBufferDrained, mCodec);
             sp<MediaCodecBuffer> buffer = info->mData;
 
             if (mCodec->mOutputFormat != mCodec->mLastOutputFormat && rangeLength > 0) {
@@ -5861,12 +5811,7 @@
                 if (mCodec->mBaseOutputFormat == mCodec->mOutputFormat) {
                     mCodec->onOutputFormatChanged(mCodec->mOutputFormat);
                 }
-                mCodec->addKeyFormatChangesToRenderBufferNotification(reply);
                 mCodec->sendFormatChange();
-            } else if (rangeLength > 0 && mCodec->mNativeWindow != NULL) {
-                // If potentially rendering onto a surface, always save key format data (crop &
-                // data space) so that we can set it if and once the buffer is rendered.
-                mCodec->addKeyFormatChangesToRenderBufferNotification(reply);
             }
             buffer->setFormat(mCodec->mOutputFormat);
 
@@ -5909,29 +5854,16 @@
             }
             buffer->meta()->setInt64("timeUs", timeUs);
 
-            sp<AMessage> notify = mCodec->mNotify->dup();
-            notify->setInt32("what", CodecBase::kWhatDrainThisBuffer);
-            notify->setInt32("buffer-id", info->mBufferID);
-            notify->setObject("buffer", buffer);
             info->mData.clear();
-            notify->setInt32("flags", flags);
 
-            reply->setInt32("buffer-id", info->mBufferID);
-
-            notify->setMessage("reply", reply);
-
-            notify->post();
+            mCodec->mBufferChannel->drainThisBuffer(info->mBufferID, flags);
 
             info->mStatus = BufferInfo::OWNED_BY_DOWNSTREAM;
 
             if (flags & OMX_BUFFERFLAG_EOS) {
                 ALOGV("[%s] saw output EOS", mCodec->mComponentName.c_str());
 
-                sp<AMessage> notify = mCodec->mNotify->dup();
-                notify->setInt32("what", CodecBase::kWhatEOS);
-                notify->setInt32("err", mCodec->mInputEOSResult);
-                notify->post();
-
+                mCodec->mCallback->onEos(mCodec->mInputEOSResult);
                 mCodec->mPortEOS[kPortIndexOutput] = true;
             }
             break;
@@ -5957,10 +5889,11 @@
     IOMX::buffer_id bufferID;
     CHECK(msg->findInt32("buffer-id", (int32_t*)&bufferID));
     sp<RefBase> obj;
-    sp<MediaCodecBuffer> buffer = nullptr;
-    if (msg->findObject("buffer", &obj)) {
-        buffer = static_cast<MediaCodecBuffer *>(obj.get());
-    }
+    CHECK(msg->findObject("buffer", &obj));
+    sp<MediaCodecBuffer> buffer = static_cast<MediaCodecBuffer *>(obj.get());
+    int32_t discarded = 0;
+    msg->findInt32("discarded", &discarded);
+
     ssize_t index;
     BufferInfo *info = mCodec->findBufferByID(kPortIndexOutput, bufferID, &index);
     BufferInfo::Status status = BufferInfo::getSafeStatus(info);
@@ -5971,31 +5904,34 @@
         return;
     }
     info->mData = buffer;
-
-    android_native_rect_t crop;
-    if (msg->findRect("crop", &crop.left, &crop.top, &crop.right, &crop.bottom)
-            && memcmp(&crop, &mCodec->mLastNativeWindowCrop, sizeof(crop)) != 0) {
-        mCodec->mLastNativeWindowCrop = crop;
-        status_t err = native_window_set_crop(mCodec->mNativeWindow.get(), &crop);
-        ALOGW_IF(err != NO_ERROR, "failed to set crop: %d", err);
-    }
-
-    int32_t dataSpace;
-    if (msg->findInt32("dataspace", &dataSpace)
-            && dataSpace != mCodec->mLastNativeWindowDataSpace) {
-        status_t err = native_window_set_buffers_data_space(
-                mCodec->mNativeWindow.get(), (android_dataspace)dataSpace);
-        mCodec->mLastNativeWindowDataSpace = dataSpace;
-        ALOGW_IF(err != NO_ERROR, "failed to set dataspace: %d", err);
-    }
-
     int32_t render;
     if (mCodec->mNativeWindow != NULL
             && msg->findInt32("render", &render) && render != 0
-            && buffer != NULL && buffer->size() != 0) {
+            && !discarded && buffer->size() != 0) {
         ATRACE_NAME("render");
         // The client wants this buffer to be rendered.
 
+        android_native_rect_t crop;
+        if (buffer->format()->findRect("crop", &crop.left, &crop.top, &crop.right, &crop.bottom)) {
+            // NOTE: native window uses extended right-bottom coordinate
+            ++crop.right;
+            ++crop.bottom;
+            if (memcmp(&crop, &mCodec->mLastNativeWindowCrop, sizeof(crop)) != 0) {
+                mCodec->mLastNativeWindowCrop = crop;
+                status_t err = native_window_set_crop(mCodec->mNativeWindow.get(), &crop);
+                ALOGW_IF(err != NO_ERROR, "failed to set crop: %d", err);
+            }
+        }
+
+        int32_t dataSpace;
+        if (buffer->format()->findInt32("android._dataspace", &dataSpace)
+                && dataSpace != mCodec->mLastNativeWindowDataSpace) {
+            status_t err = native_window_set_buffers_data_space(
+                    mCodec->mNativeWindow.get(), (android_dataspace)dataSpace);
+            mCodec->mLastNativeWindowDataSpace = dataSpace;
+            ALOGW_IF(err != NO_ERROR, "failed to set dataspace: %d", err);
+        }
+
         // save buffers sent to the surface so we can get render time when they return
         int64_t mediaTimeUs = -1;
         buffer->meta()->findInt64("timeUs", &mediaTimeUs);
@@ -6031,8 +5967,7 @@
             info->mIsReadFence = false;
         }
     } else {
-        if (mCodec->mNativeWindow != NULL &&
-            (buffer == NULL || buffer->size() != 0)) {
+        if (mCodec->mNativeWindow != NULL && (discarded || buffer->size() != 0)) {
             // move read fence into write fence to avoid clobbering
             info->mIsReadFence = false;
             ATRACE_NAME("frame-drop");
@@ -6150,22 +6085,18 @@
                         "keepComponentAllocated", &keepComponentAllocated));
             ALOGW_IF(keepComponentAllocated,
                      "cannot keep component allocated on shutdown in Uninitialized state");
-
-            sp<AMessage> notify = mCodec->mNotify->dup();
-            notify->setInt32("what", keepComponentAllocated ?
-                    CodecBase::kWhatStopCompleted : CodecBase::kWhatReleaseCompleted);
-            notify->post();
-
+            if (keepComponentAllocated) {
+                mCodec->mCallback->onStopCompleted();
+            } else {
+                mCodec->mCallback->onReleaseCompleted();
+            }
             handled = true;
             break;
         }
 
         case ACodec::kWhatFlush:
         {
-            sp<AMessage> notify = mCodec->mNotify->dup();
-            notify->setInt32("what", CodecBase::kWhatFlushCompleted);
-            notify->post();
-
+            mCodec->mCallback->onFlushCompleted();
             handled = true;
             break;
         }
@@ -6293,14 +6224,7 @@
     omxNode->setQuirks(quirks);
     mCodec->mOMX = omx;
     mCodec->mOMXNode = omxNode;
-
-    {
-        sp<AMessage> notify = mCodec->mNotify->dup();
-        notify->setInt32("what", CodecBase::kWhatComponentAllocated);
-        notify->setString("componentName", mCodec->mComponentName.c_str());
-        notify->post();
-    }
-
+    mCodec->mCallback->onComponentAllocated(mCodec->mComponentName.c_str());
     mCodec->changeState(mCodec->mLoadedState);
 
     return true;
@@ -6349,10 +6273,11 @@
     }
 
     if (mCodec->mExplicitShutdown) {
-        sp<AMessage> notify = mCodec->mNotify->dup();
-        notify->setInt32("what", keepComponentAllocated ?
-                CodecBase::kWhatStopCompleted : CodecBase::kWhatReleaseCompleted);
-        notify->post();
+        if (keepComponentAllocated) {
+            mCodec->mCallback->onStopCompleted();
+        } else {
+            mCodec->mCallback->onReleaseCompleted();
+        }
         mCodec->mExplicitShutdown = false;
     }
 }
@@ -6404,10 +6329,7 @@
 
         case ACodec::kWhatFlush:
         {
-            sp<AMessage> notify = mCodec->mNotify->dup();
-            notify->setInt32("what", CodecBase::kWhatFlushCompleted);
-            notify->post();
-
+            mCodec->mCallback->onFlushCompleted();
             handled = true;
             break;
         }
@@ -6440,13 +6362,7 @@
         return false;
     }
 
-    {
-        sp<AMessage> notify = mCodec->mNotify->dup();
-        notify->setInt32("what", CodecBase::kWhatComponentConfigured);
-        notify->setMessage("input-format", mCodec->mInputFormat);
-        notify->setMessage("output-format", mCodec->mOutputFormat);
-        notify->post();
-    }
+    mCodec->mCallback->onComponentConfigured(mCodec->mInputFormat, mCodec->mOutputFormat);
 
     return true;
 }
@@ -6568,9 +6484,6 @@
         const sp<AMessage> & /* msg */) {
     ALOGV("onCreateInputSurface");
 
-    sp<AMessage> notify = mCodec->mNotify->dup();
-    notify->setInt32("what", CodecBase::kWhatInputSurfaceCreated);
-
     sp<IGraphicBufferProducer> bufferProducer;
     status_t err = mCodec->mOMX->createInputSurface(
             &bufferProducer, &mCodec->mGraphicBufferSource);
@@ -6580,10 +6493,9 @@
     }
 
     if (err == OK) {
-        notify->setMessage("input-format", mCodec->mInputFormat);
-        notify->setMessage("output-format", mCodec->mOutputFormat);
-
-        notify->setObject("input-surface",
+        mCodec->mCallback->onInputSurfaceCreated(
+                mCodec->mInputFormat,
+                mCodec->mOutputFormat,
                 new BufferProducerWrapper(bufferProducer));
     } else {
         // Can't use mCodec->signalError() here -- MediaCodec won't forward
@@ -6591,18 +6503,13 @@
         // send a kWhatInputSurfaceCreated with an error value instead.
         ALOGE("[%s] onCreateInputSurface returning error %d",
                 mCodec->mComponentName.c_str(), err);
-        notify->setInt32("err", err);
+        mCodec->mCallback->onInputSurfaceCreationFailed(err);
     }
-    notify->post();
 }
 
-void ACodec::LoadedState::onSetInputSurface(
-        const sp<AMessage> &msg) {
+void ACodec::LoadedState::onSetInputSurface(const sp<AMessage> &msg) {
     ALOGV("onSetInputSurface");
 
-    sp<AMessage> notify = mCodec->mNotify->dup();
-    notify->setInt32("what", CodecBase::kWhatInputSurfaceAccepted);
-
     sp<RefBase> obj;
     CHECK(msg->findObject("input-surface", &obj));
     sp<PersistentSurface> surface = static_cast<PersistentSurface *>(obj.get());
@@ -6611,17 +6518,16 @@
     status_t err = setupInputSurface();
 
     if (err == OK) {
-        notify->setMessage("input-format", mCodec->mInputFormat);
-        notify->setMessage("output-format", mCodec->mOutputFormat);
+        mCodec->mCallback->onInputSurfaceAccepted(
+                mCodec->mInputFormat, mCodec->mOutputFormat);
     } else {
         // Can't use mCodec->signalError() here -- MediaCodec won't forward
         // the error through because it's in the "configured" state.  We
         // send a kWhatInputSurfaceAccepted with an error value instead.
         ALOGE("[%s] onSetInputSurface returning error %d",
                 mCodec->mComponentName.c_str(), err);
-        notify->setInt32("err", err);
+        mCodec->mCallback->onInputSurfaceDeclined(err);
     }
-    notify->post();
 }
 
 void ACodec::LoadedState::onStart() {
@@ -6667,12 +6573,18 @@
 
 status_t ACodec::LoadedToIdleState::allocateBuffers() {
     status_t err = mCodec->allocateBuffersOnPort(kPortIndexInput);
-
     if (err != OK) {
         return err;
     }
 
-    return mCodec->allocateBuffersOnPort(kPortIndexOutput);
+    err = mCodec->allocateBuffersOnPort(kPortIndexOutput);
+    if (err != OK) {
+        return err;
+    }
+
+    mCodec->mCallback->onStartCompleted();
+
+    return OK;
 }
 
 bool ACodec::LoadedToIdleState::onMessageReceived(const sp<AMessage> &msg) {
@@ -6699,9 +6611,7 @@
         case kWhatFlush:
         {
             // We haven't even started yet, so we're flushed alright...
-            sp<AMessage> notify = mCodec->mNotify->dup();
-            notify->setInt32("what", CodecBase::kWhatFlushCompleted);
-            notify->post();
+            mCodec->mCallback->onFlushCompleted();
             return true;
         }
 
@@ -6771,10 +6681,7 @@
         case kWhatFlush:
         {
             // We haven't even started yet, so we're flushed alright...
-            sp<AMessage> notify = mCodec->mNotify->dup();
-            notify->setInt32("what", CodecBase::kWhatFlushCompleted);
-            notify->post();
-
+            mCodec->mCallback->onFlushCompleted();
             return true;
         }
 
@@ -7149,17 +7056,11 @@
 }
 
 void ACodec::onSignalEndOfInputStream() {
-    sp<AMessage> notify = mNotify->dup();
-    notify->setInt32("what", CodecBase::kWhatSignaledInputEOS);
-
     status_t err = INVALID_OPERATION;
     if (mGraphicBufferSource != NULL) {
         err = statusFromBinderStatus(mGraphicBufferSource->signalEndOfInputStream());
     }
-    if (err != OK) {
-        notify->setInt32("err", err);
-    }
-    notify->post();
+    mCallback->onSignaledInputEOS(err);
 }
 
 bool ACodec::ExecutingState::onOMXFrameRendered(int64_t mediaTimeUs, nsecs_t systemNano) {
@@ -7291,6 +7192,7 @@
                     err = mCodec->allocateBuffersOnPort(kPortIndexOutput);
                     ALOGE_IF(err != OK, "Failed to allocate output port buffers after port "
                             "reconfiguration: (%d)", err);
+                    mCodec->mCallback->onOutputBuffersChanged();
                 }
 
                 if (err != OK) {
@@ -7636,9 +7538,7 @@
 
         mCodec->mRenderTracker.clear(systemTime(CLOCK_MONOTONIC));
 
-        sp<AMessage> notify = mCodec->mNotify->dup();
-        notify->setInt32("what", CodecBase::kWhatFlushCompleted);
-        notify->post();
+        mCodec->mCallback->onFlushCompleted();
 
         mCodec->mPortEOS[kPortIndexInput] =
             mCodec->mPortEOS[kPortIndexOutput] = false;
diff --git a/media/libstagefright/ACodecBufferChannel.cpp b/media/libstagefright/ACodecBufferChannel.cpp
new file mode 100644
index 0000000..1db7ab0
--- /dev/null
+++ b/media/libstagefright/ACodecBufferChannel.cpp
@@ -0,0 +1,308 @@
+/*
+ * 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "ACodecBufferChannel"
+#include <utils/Log.h>
+
+#include <numeric>
+
+#include <binder/MemoryDealer.h>
+#include <media/openmax/OMX_Core.h>
+#include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/foundation/AUtils.h>
+#include <media/stagefright/MediaCodec.h>
+#include <media/MediaCodecBuffer.h>
+#include <system/window.h>
+
+#include "include/ACodecBufferChannel.h"
+#include "include/SecureBuffer.h"
+#include "include/SharedMemoryBuffer.h"
+
+namespace android {
+
+using BufferInfo = ACodecBufferChannel::BufferInfo;
+using BufferInfoIterator = std::vector<const BufferInfo>::const_iterator;
+
+static BufferInfoIterator findClientBuffer(
+        const std::shared_ptr<const std::vector<const BufferInfo>> &array,
+        const sp<MediaCodecBuffer> &buffer) {
+    return std::find_if(
+            array->begin(), array->end(),
+            [buffer](const BufferInfo &info) { return info.mClientBuffer == buffer; });
+}
+
+static BufferInfoIterator findBufferId(
+        const std::shared_ptr<const std::vector<const BufferInfo>> &array,
+        IOMX::buffer_id bufferId) {
+    return std::find_if(
+            array->begin(), array->end(),
+            [bufferId](const BufferInfo &info) { return bufferId == info.mBufferId; });
+}
+
+ACodecBufferChannel::BufferInfo::BufferInfo(
+        const sp<MediaCodecBuffer> &buffer,
+        IOMX::buffer_id bufferId,
+        const sp<IMemory> &sharedEncryptedBuffer)
+    : mClientBuffer(
+          (sharedEncryptedBuffer == nullptr)
+          ? buffer
+          : new SharedMemoryBuffer(buffer->format(), sharedEncryptedBuffer)),
+      mCodecBuffer(buffer),
+      mBufferId(bufferId),
+      mSharedEncryptedBuffer(sharedEncryptedBuffer) {
+}
+
+ACodecBufferChannel::ACodecBufferChannel(
+        const sp<AMessage> &inputBufferFilled, const sp<AMessage> &outputBufferDrained)
+    : mInputBufferFilled(inputBufferFilled),
+      mOutputBufferDrained(outputBufferDrained) {
+}
+
+status_t ACodecBufferChannel::queueInputBuffer(const sp<MediaCodecBuffer> &buffer) {
+    std::shared_ptr<const std::vector<const BufferInfo>> array(
+            std::atomic_load(&mInputBuffers));
+    BufferInfoIterator it = findClientBuffer(array, buffer);
+    if (it == array->end()) {
+        return -ENOENT;
+    }
+    ALOGV("queueInputBuffer #%d", it->mBufferId);
+    sp<AMessage> msg = mInputBufferFilled->dup();
+    msg->setObject("buffer", it->mCodecBuffer);
+    msg->setInt32("buffer-id", it->mBufferId);
+    msg->post();
+    return OK;
+}
+
+status_t ACodecBufferChannel::queueSecureInputBuffer(
+        const sp<MediaCodecBuffer> &buffer,
+        bool secure,
+        const uint8_t *key,
+        const uint8_t *iv,
+        CryptoPlugin::Mode mode,
+        CryptoPlugin::Pattern pattern,
+        const CryptoPlugin::SubSample *subSamples,
+        size_t numSubSamples,
+        AString *errorDetailMsg) {
+    if (mCrypto == nullptr) {
+        return -ENOSYS;
+    }
+    std::shared_ptr<const std::vector<const BufferInfo>> array(
+            std::atomic_load(&mInputBuffers));
+    BufferInfoIterator it = findClientBuffer(array, buffer);
+    if (it == array->end()) {
+        return -ENOENT;
+    }
+
+    void *dst_pointer = nullptr;
+    ICrypto::DestinationType dst_type = ICrypto::kDestinationTypeOpaqueHandle;
+
+    if (secure) {
+        sp<SecureBuffer> secureData = static_cast<SecureBuffer *>(it->mCodecBuffer.get());
+        dst_pointer = secureData->getDestinationPointer();
+        dst_type = secureData->getDestinationType();
+    } else {
+        dst_pointer = it->mCodecBuffer->base();
+        dst_type = ICrypto::kDestinationTypeVmPointer;
+    }
+
+    ssize_t result = mCrypto->decrypt(
+            dst_type,
+            key,
+            iv,
+            mode,
+            pattern,
+            it->mSharedEncryptedBuffer,
+            it->mClientBuffer->offset(),
+            subSamples,
+            numSubSamples,
+            dst_pointer,
+            errorDetailMsg);
+
+    if (result < 0) {
+        return result;
+    }
+
+    it->mCodecBuffer->setRange(0, result);
+
+    // Copy metadata from client to codec buffer.
+    it->mCodecBuffer->meta()->clear();
+    int64_t timeUs;
+    CHECK(it->mClientBuffer->meta()->findInt64("timeUs", &timeUs));
+    it->mCodecBuffer->meta()->setInt64("timeUs", timeUs);
+    int32_t eos;
+    if (it->mClientBuffer->meta()->findInt32("eos", &eos)) {
+        it->mCodecBuffer->meta()->setInt32("eos", eos);
+    }
+    int32_t csd;
+    if (it->mClientBuffer->meta()->findInt32("csd", &csd)) {
+        it->mCodecBuffer->meta()->setInt32("csd", csd);
+    }
+
+    ALOGV("queueSecureInputBuffer #%d", it->mBufferId);
+    sp<AMessage> msg = mInputBufferFilled->dup();
+    msg->setObject("buffer", it->mCodecBuffer);
+    msg->setInt32("buffer-id", it->mBufferId);
+    msg->post();
+    return OK;
+}
+
+status_t ACodecBufferChannel::renderOutputBuffer(
+        const sp<MediaCodecBuffer> &buffer, int64_t timestampNs) {
+    std::shared_ptr<const std::vector<const BufferInfo>> array(
+            std::atomic_load(&mOutputBuffers));
+    BufferInfoIterator it = findClientBuffer(array, buffer);
+    if (it == array->end()) {
+        return -ENOENT;
+    }
+
+    ALOGV("renderOutputBuffer #%d", it->mBufferId);
+    sp<AMessage> msg = mOutputBufferDrained->dup();
+    msg->setObject("buffer", buffer);
+    msg->setInt32("buffer-id", it->mBufferId);
+    msg->setInt32("render", true);
+    msg->setInt64("timestampNs", timestampNs);
+    msg->post();
+    return OK;
+}
+
+status_t ACodecBufferChannel::discardBuffer(const sp<MediaCodecBuffer> &buffer) {
+    std::shared_ptr<const std::vector<const BufferInfo>> array(
+            std::atomic_load(&mInputBuffers));
+    bool input = true;
+    BufferInfoIterator it = findClientBuffer(array, buffer);
+    if (it == array->end()) {
+        array = std::atomic_load(&mOutputBuffers);
+        input = false;
+        it = findClientBuffer(array, buffer);
+        if (it == array->end()) {
+            return -ENOENT;
+        }
+    }
+    ALOGV("discardBuffer #%d", it->mBufferId);
+    sp<AMessage> msg = input ? mInputBufferFilled->dup() : mOutputBufferDrained->dup();
+    msg->setObject("buffer", it->mCodecBuffer);
+    msg->setInt32("buffer-id", it->mBufferId);
+    msg->setInt32("discarded", true);
+    msg->post();
+    return OK;
+}
+
+void ACodecBufferChannel::getInputBufferArray(Vector<sp<MediaCodecBuffer>> *array) {
+    std::shared_ptr<const std::vector<const BufferInfo>> inputBuffers(
+            std::atomic_load(&mInputBuffers));
+    array->clear();
+    for (const BufferInfo &elem : *inputBuffers) {
+        array->push_back(elem.mClientBuffer);
+    }
+}
+
+void ACodecBufferChannel::getOutputBufferArray(Vector<sp<MediaCodecBuffer>> *array) {
+    std::shared_ptr<const std::vector<const BufferInfo>> outputBuffers(
+            std::atomic_load(&mOutputBuffers));
+    array->clear();
+    for (const BufferInfo &elem : *outputBuffers) {
+        array->push_back(elem.mClientBuffer);
+    }
+}
+
+void ACodecBufferChannel::setInputBufferArray(const std::vector<BufferAndId> &array) {
+    bool secure = (mCrypto != nullptr);
+    if (secure) {
+        size_t totalSize = std::accumulate(
+                array.begin(), array.end(), 0u,
+                [alignment = MemoryDealer::getAllocationAlignment()]
+                (size_t sum, const BufferAndId& elem) {
+                    return sum + align(elem.mBuffer->capacity(), alignment);
+                });
+        mDealer = new MemoryDealer(totalSize, "ACodecBufferChannel");
+    }
+    std::vector<const BufferInfo> inputBuffers;
+    for (const BufferAndId &elem : array) {
+        sp<IMemory> sharedEncryptedBuffer;
+        if (secure) {
+            sharedEncryptedBuffer = mDealer->allocate(elem.mBuffer->capacity());
+        }
+        inputBuffers.emplace_back(elem.mBuffer, elem.mBufferId, sharedEncryptedBuffer);
+    }
+    std::atomic_store(
+            &mInputBuffers,
+            std::make_shared<const std::vector<const BufferInfo>>(inputBuffers));
+}
+
+void ACodecBufferChannel::setOutputBufferArray(const std::vector<BufferAndId> &array) {
+    std::vector<const BufferInfo> outputBuffers;
+    for (const BufferAndId &elem : array) {
+        outputBuffers.emplace_back(elem.mBuffer, elem.mBufferId, nullptr);
+    }
+    std::atomic_store(
+            &mOutputBuffers,
+            std::make_shared<const std::vector<const BufferInfo>>(outputBuffers));
+}
+
+void ACodecBufferChannel::fillThisBuffer(IOMX::buffer_id bufferId) {
+    ALOGV("fillThisBuffer #%d", bufferId);
+    std::shared_ptr<const std::vector<const BufferInfo>> array(
+            std::atomic_load(&mInputBuffers));
+    BufferInfoIterator it = findBufferId(array, bufferId);
+
+    if (it == array->end()) {
+        ALOGE("fillThisBuffer: unrecognized buffer #%d", bufferId);
+        return;
+    }
+    if (it->mClientBuffer != it->mCodecBuffer) {
+        it->mClientBuffer->setFormat(it->mCodecBuffer->format());
+    }
+
+    mCallback->onInputBufferAvailable(
+            std::distance(array->begin(), it),
+            it->mClientBuffer);
+}
+
+void ACodecBufferChannel::drainThisBuffer(
+        IOMX::buffer_id bufferId,
+        OMX_U32 omxFlags) {
+    ALOGV("drainThisBuffer #%d", bufferId);
+    std::shared_ptr<const std::vector<const BufferInfo>> array(
+            std::atomic_load(&mOutputBuffers));
+    BufferInfoIterator it = findBufferId(array, bufferId);
+
+    if (it == array->end()) {
+        ALOGE("drainThisBuffer: unrecognized buffer #%d", bufferId);
+        return;
+    }
+    if (it->mClientBuffer != it->mCodecBuffer) {
+        it->mClientBuffer->setFormat(it->mCodecBuffer->format());
+    }
+
+    uint32_t flags = 0;
+    if (omxFlags & OMX_BUFFERFLAG_SYNCFRAME) {
+        flags |= MediaCodec::BUFFER_FLAG_SYNCFRAME;
+    }
+    if (omxFlags & OMX_BUFFERFLAG_CODECCONFIG) {
+        flags |= MediaCodec::BUFFER_FLAG_CODECCONFIG;
+    }
+    if (omxFlags & OMX_BUFFERFLAG_EOS) {
+        flags |= MediaCodec::BUFFER_FLAG_EOS;
+    }
+    it->mClientBuffer->meta()->setInt32("flags", flags);
+
+    mCallback->onOutputBufferAvailable(
+            std::distance(array->begin(), it),
+            it->mClientBuffer);
+}
+
+}  // namespace android
diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk
index 5e921e3..bd837ae 100644
--- a/media/libstagefright/Android.mk
+++ b/media/libstagefright/Android.mk
@@ -4,6 +4,7 @@
 
 LOCAL_SRC_FILES:=                         \
         ACodec.cpp                        \
+        ACodecBufferChannel.cpp           \
         AACExtractor.cpp                  \
         AACWriter.cpp                     \
         AMRExtractor.cpp                  \
@@ -14,7 +15,6 @@
         CallbackDataSource.cpp            \
         CameraSource.cpp                  \
         CameraSourceTimeLapse.cpp         \
-        CodecBase.cpp                     \
         DataConverter.cpp                 \
         DataSource.cpp                    \
         DataURISource.cpp                 \
@@ -59,7 +59,6 @@
         VBRISeeker.cpp                    \
         VideoFrameScheduler.cpp           \
         WAVExtractor.cpp                  \
-        WVMExtractor.cpp                  \
         XINGSeeker.cpp                    \
         avc_utils.cpp                     \
 
diff --git a/media/libstagefright/CameraSource.cpp b/media/libstagefright/CameraSource.cpp
index 990d4b7..0fe44eb 100644
--- a/media/libstagefright/CameraSource.cpp
+++ b/media/libstagefright/CameraSource.cpp
@@ -770,9 +770,7 @@
         return mInitCheck;
     }
 
-    char value[PROPERTY_VALUE_MAX];
-    if (property_get("media.stagefright.record-stats", value, NULL)
-        && (!strcmp(value, "1") || !strcasecmp(value, "true"))) {
+    if (property_get_bool("media.stagefright.record-stats", false)) {
         mCollectStats = true;
     }
 
diff --git a/media/libstagefright/CodecBase.cpp b/media/libstagefright/CodecBase.cpp
deleted file mode 100644
index f729d4d..0000000
--- a/media/libstagefright/CodecBase.cpp
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright (C) 2014 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 "CodecBase"
-
-#include <inttypes.h>
-
-#include <media/stagefright/CodecBase.h>
-
-namespace android {
-
-CodecBase::CodecBase() {
-}
-
-CodecBase::~CodecBase() {
-}
-
-CodecBase::PortDescription::PortDescription() {
-}
-
-CodecBase::PortDescription::~PortDescription() {
-}
-
-}  // namespace android
diff --git a/media/libstagefright/DataSource.cpp b/media/libstagefright/DataSource.cpp
index 163a527..4a965ba 100644
--- a/media/libstagefright/DataSource.cpp
+++ b/media/libstagefright/DataSource.cpp
@@ -16,24 +16,9 @@
 //#define LOG_NDEBUG 0
 #define LOG_TAG "DataSource"
 
-#include "include/AMRExtractor.h"
-
-#include "include/AACExtractor.h"
 #include "include/CallbackDataSource.h"
-#include "include/DRMExtractor.h"
-#include "include/FLACExtractor.h"
 #include "include/HTTPBase.h"
-#include "include/MidiExtractor.h"
-#include "include/MP3Extractor.h"
-#include "include/MPEG2PSExtractor.h"
-#include "include/MPEG2TSExtractor.h"
-#include "include/MPEG4Extractor.h"
 #include "include/NuCachedSource2.h"
-#include "include/OggExtractor.h"
-#include "include/WAVExtractor.h"
-#include "include/WVMExtractor.h"
-
-#include "matroska/MatroskaExtractor.h"
 
 #include <media/IMediaHTTPConnection.h>
 #include <media/IMediaHTTPService.h>
@@ -44,12 +29,15 @@
 #include <media/stagefright/FileSource.h>
 #include <media/stagefright/MediaErrors.h>
 #include <media/stagefright/MediaHTTP.h>
+#include <media/stagefright/Utils.h>
 #include <utils/String8.h>
 
 #include <cutils/properties.h>
 
 #include <private/android_filesystem_config.h>
 
+#include <arpa/inet.h>
+
 namespace android {
 
 bool DataSource::getUInt16(off64_t offset, uint16_t *x) {
@@ -112,83 +100,6 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 
-Mutex DataSource::gSnifferMutex;
-List<DataSource::SnifferFunc> DataSource::gSniffers;
-bool DataSource::gSniffersRegistered = false;
-
-bool DataSource::sniff(
-        String8 *mimeType, float *confidence, sp<AMessage> *meta) {
-    *mimeType = "";
-    *confidence = 0.0f;
-    meta->clear();
-
-    {
-        Mutex::Autolock autoLock(gSnifferMutex);
-        if (!gSniffersRegistered) {
-            return false;
-        }
-    }
-
-    for (List<SnifferFunc>::iterator it = gSniffers.begin();
-         it != gSniffers.end(); ++it) {
-        String8 newMimeType;
-        float newConfidence;
-        sp<AMessage> newMeta;
-        if ((*it)(this, &newMimeType, &newConfidence, &newMeta)) {
-            if (newConfidence > *confidence) {
-                *mimeType = newMimeType;
-                *confidence = newConfidence;
-                *meta = newMeta;
-            }
-        }
-    }
-
-    return *confidence > 0.0;
-}
-
-// static
-void DataSource::RegisterSniffer_l(SnifferFunc func) {
-    for (List<SnifferFunc>::iterator it = gSniffers.begin();
-         it != gSniffers.end(); ++it) {
-        if (*it == func) {
-            return;
-        }
-    }
-
-    gSniffers.push_back(func);
-}
-
-// static
-void DataSource::RegisterDefaultSniffers() {
-    Mutex::Autolock autoLock(gSnifferMutex);
-    if (gSniffersRegistered) {
-        return;
-    }
-
-    RegisterSniffer_l(SniffMPEG4);
-    RegisterSniffer_l(SniffMatroska);
-    RegisterSniffer_l(SniffOgg);
-    RegisterSniffer_l(SniffWAV);
-    RegisterSniffer_l(SniffFLAC);
-    RegisterSniffer_l(SniffAMR);
-    RegisterSniffer_l(SniffMPEG2TS);
-    RegisterSniffer_l(SniffMP3);
-    RegisterSniffer_l(SniffAAC);
-    RegisterSniffer_l(SniffMPEG2PS);
-    if (getuid() == AID_MEDIA) {
-        // WVM only in the media server process
-        RegisterSniffer_l(SniffWVM);
-    }
-    RegisterSniffer_l(SniffMidi);
-
-    char value[PROPERTY_VALUE_MAX];
-    if (property_get("drm.service.enabled", value, NULL)
-            && (!strcmp(value, "1") || !strcasecmp(value, "true"))) {
-        RegisterSniffer_l(SniffDRM);
-    }
-    gSniffersRegistered = true;
-}
-
 // static
 sp<DataSource> DataSource::CreateFromURI(
         const sp<IMediaHTTPService> &httpService,
@@ -200,14 +111,10 @@
         *contentType = "";
     }
 
-    bool isWidevine = !strncasecmp("widevine://", uri, 11);
-
     sp<DataSource> source;
     if (!strncasecmp("file://", uri, 7)) {
         source = new FileSource(uri + 7);
-    } else if (!strncasecmp("http://", uri, 7)
-            || !strncasecmp("https://", uri, 8)
-            || isWidevine) {
+    } else if (!strncasecmp("http://", uri, 7) || !strncasecmp("https://", uri, 8)) {
         if (httpService == NULL) {
             ALOGE("Invalid http service!");
             return NULL;
@@ -222,14 +129,6 @@
             httpSource = new MediaHTTP(conn);
         }
 
-        String8 tmp;
-        if (isWidevine) {
-            tmp = String8("http://");
-            tmp.append(uri + 11);
-
-            uri = tmp.string();
-        }
-
         String8 cacheConfig;
         bool disconnectAtHighwatermark;
         KeyedVector<String8, String8> nonCacheSpecificHeaders;
@@ -246,20 +145,14 @@
             return NULL;
         }
 
-        if (!isWidevine) {
-            if (contentType != NULL) {
-                *contentType = httpSource->getMIMEType();
-            }
-
-            source = NuCachedSource2::Create(
-                    httpSource,
-                    cacheConfig.isEmpty() ? NULL : cacheConfig.string(),
-                    disconnectAtHighwatermark);
-        } else {
-            // We do not want that prefetching, caching, datasource wrapper
-            // in the widevine:// case.
-            source = httpSource;
+        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 {
diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp
index ee603a4..f9af5e1 100644
--- a/media/libstagefright/MPEG4Extractor.cpp
+++ b/media/libstagefright/MPEG4Extractor.cpp
@@ -1022,7 +1022,9 @@
                         while (cur && cur->next != mLastTrack) {
                             cur = cur->next;
                         }
-                        cur->next = NULL;
+                        if (cur) {
+                            cur->next = NULL;
+                        }
                         delete mLastTrack;
                         mLastTrack = cur;
                     }
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index 9978b76..e57057c 100644
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -1128,9 +1128,7 @@
 
     // Test mode is enabled only if rw.media.record.test system
     // property is enabled.
-    char value[PROPERTY_VALUE_MAX];
-    if (property_get("rw.media.record.test", value, NULL) &&
-        (!strcasecmp(value, "true") || !strcasecmp(value, "1"))) {
+    if (property_get_bool("rw.media.record.test", false)) {
         return true;
     }
     return false;
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index 7761fb1..24f0d20 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -37,6 +37,7 @@
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
 #include <media/stagefright/foundation/AString.h>
+#include <media/stagefright/foundation/AUtils.h>
 #include <media/stagefright/foundation/hexdump.h>
 #include <media/stagefright/ACodec.h>
 #include <media/stagefright/BufferProducerWrapper.h>
@@ -66,6 +67,9 @@
 
 static const int kMaxRetry = 2;
 static const int kMaxReclaimWaitTimeInUs = 500000;  // 0.5s
+static const int kNumBuffersAlign = 16;
+
+////////////////////////////////////////////////////////////////////////////////
 
 struct ResourceManagerClient : public BnResourceManagerClient {
     explicit ResourceManagerClient(MediaCodec* codec) : mMediaCodec(codec) {}
@@ -171,6 +175,216 @@
     return mService->reclaimResource(mPid, resources);
 }
 
+////////////////////////////////////////////////////////////////////////////////
+
+MediaCodec::BufferInfo::BufferInfo() : mOwnedByClient(false) {}
+
+////////////////////////////////////////////////////////////////////////////////
+
+namespace {
+
+enum {
+    kWhatFillThisBuffer      = 'fill',
+    kWhatDrainThisBuffer     = 'drai',
+    kWhatEOS                 = 'eos ',
+    kWhatStartCompleted      = 'Scom',
+    kWhatStopCompleted       = 'scom',
+    kWhatReleaseCompleted    = 'rcom',
+    kWhatFlushCompleted      = 'fcom',
+    kWhatError               = 'erro',
+    kWhatComponentAllocated  = 'cAll',
+    kWhatComponentConfigured = 'cCon',
+    kWhatInputSurfaceCreated = 'isfc',
+    kWhatInputSurfaceAccepted = 'isfa',
+    kWhatSignaledInputEOS    = 'seos',
+    kWhatOutputFramesRendered = 'outR',
+    kWhatOutputBuffersChanged = 'outC',
+};
+
+class BufferCallback : public CodecBase::BufferCallback {
+public:
+    explicit BufferCallback(const sp<AMessage> &notify);
+    virtual ~BufferCallback() = default;
+
+    virtual void onInputBufferAvailable(
+            size_t index, const sp<MediaCodecBuffer> &buffer) override;
+    virtual void onOutputBufferAvailable(
+            size_t index, const sp<MediaCodecBuffer> &buffer) override;
+private:
+    const sp<AMessage> mNotify;
+};
+
+BufferCallback::BufferCallback(const sp<AMessage> &notify)
+    : mNotify(notify) {}
+
+void BufferCallback::onInputBufferAvailable(
+        size_t index, const sp<MediaCodecBuffer> &buffer) {
+    sp<AMessage> notify(mNotify->dup());
+    notify->setInt32("what", kWhatFillThisBuffer);
+    notify->setSize("index", index);
+    notify->setObject("buffer", buffer);
+    notify->post();
+}
+
+void BufferCallback::onOutputBufferAvailable(
+        size_t index, const sp<MediaCodecBuffer> &buffer) {
+    sp<AMessage> notify(mNotify->dup());
+    notify->setInt32("what", kWhatDrainThisBuffer);
+    notify->setSize("index", index);
+    notify->setObject("buffer", buffer);
+    notify->post();
+}
+
+class CodecCallback : public CodecBase::CodecCallback {
+public:
+    explicit CodecCallback(const sp<AMessage> &notify);
+    virtual ~CodecCallback() = default;
+
+    virtual void onEos(status_t err) override;
+    virtual void onStartCompleted() override;
+    virtual void onStopCompleted() override;
+    virtual void onReleaseCompleted() override;
+    virtual void onFlushCompleted() override;
+    virtual void onError(status_t err, enum ActionCode actionCode) override;
+    virtual void onComponentAllocated(const char *componentName) override;
+    virtual void onComponentConfigured(
+            const sp<AMessage> &inputFormat, const sp<AMessage> &outputFormat) override;
+    virtual void onInputSurfaceCreated(
+            const sp<AMessage> &inputFormat,
+            const sp<AMessage> &outputFormat,
+            const sp<BufferProducerWrapper> &inputSurface) override;
+    virtual void onInputSurfaceCreationFailed(status_t err) override;
+    virtual void onInputSurfaceAccepted(
+            const sp<AMessage> &inputFormat,
+            const sp<AMessage> &outputFormat) override;
+    virtual void onInputSurfaceDeclined(status_t err) override;
+    virtual void onSignaledInputEOS(status_t err) override;
+    virtual void onOutputFramesRendered(const std::list<FrameRenderTracker::Info> &done) override;
+    virtual void onOutputBuffersChanged() override;
+private:
+    const sp<AMessage> mNotify;
+};
+
+CodecCallback::CodecCallback(const sp<AMessage> &notify) : mNotify(notify) {}
+
+void CodecCallback::onEos(status_t err) {
+    sp<AMessage> notify(mNotify->dup());
+    notify->setInt32("what", kWhatEOS);
+    notify->setInt32("err", err);
+    notify->post();
+}
+
+void CodecCallback::onStartCompleted() {
+    sp<AMessage> notify(mNotify->dup());
+    notify->setInt32("what", kWhatStartCompleted);
+    notify->post();
+}
+
+void CodecCallback::onStopCompleted() {
+    sp<AMessage> notify(mNotify->dup());
+    notify->setInt32("what", kWhatStopCompleted);
+    notify->post();
+}
+
+void CodecCallback::onReleaseCompleted() {
+    sp<AMessage> notify(mNotify->dup());
+    notify->setInt32("what", kWhatReleaseCompleted);
+    notify->post();
+}
+
+void CodecCallback::onFlushCompleted() {
+    sp<AMessage> notify(mNotify->dup());
+    notify->setInt32("what", kWhatFlushCompleted);
+    notify->post();
+}
+
+void CodecCallback::onError(status_t err, enum ActionCode actionCode) {
+    sp<AMessage> notify(mNotify->dup());
+    notify->setInt32("what", kWhatError);
+    notify->setInt32("err", err);
+    notify->setInt32("actionCode", actionCode);
+    notify->post();
+}
+
+void CodecCallback::onComponentAllocated(const char *componentName) {
+    sp<AMessage> notify(mNotify->dup());
+    notify->setInt32("what", kWhatComponentAllocated);
+    notify->setString("componentName", componentName);
+    notify->post();
+}
+
+void CodecCallback::onComponentConfigured(
+        const sp<AMessage> &inputFormat, const sp<AMessage> &outputFormat) {
+    sp<AMessage> notify(mNotify->dup());
+    notify->setInt32("what", kWhatComponentConfigured);
+    notify->setMessage("input-format", inputFormat);
+    notify->setMessage("output-format", outputFormat);
+    notify->post();
+}
+
+void CodecCallback::onInputSurfaceCreated(
+        const sp<AMessage> &inputFormat,
+        const sp<AMessage> &outputFormat,
+        const sp<BufferProducerWrapper> &inputSurface) {
+    sp<AMessage> notify(mNotify->dup());
+    notify->setInt32("what", kWhatInputSurfaceCreated);
+    notify->setMessage("input-format", inputFormat);
+    notify->setMessage("output-format", outputFormat);
+    notify->setObject("input-surface", inputSurface);
+    notify->post();
+}
+
+void CodecCallback::onInputSurfaceCreationFailed(status_t err) {
+    sp<AMessage> notify(mNotify->dup());
+    notify->setInt32("what", kWhatInputSurfaceCreated);
+    notify->setInt32("err", err);
+    notify->post();
+}
+
+void CodecCallback::onInputSurfaceAccepted(
+        const sp<AMessage> &inputFormat,
+        const sp<AMessage> &outputFormat) {
+    sp<AMessage> notify(mNotify->dup());
+    notify->setInt32("what", kWhatInputSurfaceAccepted);
+    notify->setMessage("input-format", inputFormat);
+    notify->setMessage("output-format", outputFormat);
+    notify->post();
+}
+
+void CodecCallback::onInputSurfaceDeclined(status_t err) {
+    sp<AMessage> notify(mNotify->dup());
+    notify->setInt32("what", kWhatInputSurfaceAccepted);
+    notify->setInt32("err", err);
+    notify->post();
+}
+
+void CodecCallback::onSignaledInputEOS(status_t err) {
+    sp<AMessage> notify(mNotify->dup());
+    notify->setInt32("what", kWhatSignaledInputEOS);
+    if (err != OK) {
+        notify->setInt32("err", err);
+    }
+    notify->post();
+}
+
+void CodecCallback::onOutputFramesRendered(const std::list<FrameRenderTracker::Info> &done) {
+    sp<AMessage> notify(mNotify->dup());
+    notify->setInt32("what", kWhatOutputFramesRendered);
+    if (MediaCodec::CreateFramesRenderedMessage(done, notify)) {
+        notify->post();
+    }
+}
+
+void CodecCallback::onOutputBuffersChanged() {
+    sp<AMessage> notify(mNotify->dup());
+    notify->setInt32("what", kWhatOutputBuffersChanged);
+    notify->post();
+}
+
+}  // namespace
+
+////////////////////////////////////////////////////////////////////////////////
+
 // static
 sp<MediaCodec> MediaCodec::CreateByType(
         const sp<ALooper> &looper, const AString &mime, bool encoder, status_t *err, pid_t pid,
@@ -370,7 +584,13 @@
 
     mLooper->registerHandler(this);
 
-    mCodec->setNotificationMessage(new AMessage(kWhatCodecNotify, this));
+    mCodec->setCallback(
+            std::unique_ptr<CodecBase::CodecCallback>(
+                    new CodecCallback(new AMessage(kWhatCodecNotify, this))));
+    mBufferChannel = mCodec->getBufferChannel();
+    mBufferChannel->setCallback(
+            std::unique_ptr<CodecBase::BufferCallback>(
+                    new BufferCallback(new AMessage(kWhatCodecNotify, this))));
 
     sp<AMessage> msg = new AMessage(kWhatInit, this);
     msg->setString("name", name);
@@ -597,14 +817,9 @@
 }
 
 bool MediaCodec::hasPendingBuffer(int portIndex) {
-    const Vector<BufferInfo> &buffers = mPortBuffers[portIndex];
-    for (size_t i = 0; i < buffers.size(); ++i) {
-        const BufferInfo &info = buffers.itemAt(i);
-        if (info.mOwnedByClient) {
-            return true;
-        }
-    }
-    return false;
+    return std::any_of(
+            mPortBuffers[portIndex].begin(), mPortBuffers[portIndex].end(),
+            [](const BufferInfo &info) { return info.mOwnedByClient; });
 }
 
 bool MediaCodec::hasPendingBuffer() {
@@ -843,16 +1058,6 @@
     return OK;
 }
 
-status_t MediaCodec::getWidevineLegacyBuffers(Vector<sp<MediaCodecBuffer> > *buffers) const {
-    sp<AMessage> msg = new AMessage(kWhatGetBuffers, this);
-    msg->setInt32("portIndex", kPortIndexInput);
-    msg->setPointer("buffers", buffers);
-    msg->setInt32("widevine", true);
-
-    sp<AMessage> response;
-    return PostAndAwaitResponse(msg, &response);
-}
-
 status_t MediaCodec::getInputBuffers(Vector<sp<MediaCodecBuffer> > *buffers) const {
     sp<AMessage> msg = new AMessage(kWhatGetBuffers, this);
     msg->setInt32("portIndex", kPortIndexInput);
@@ -921,14 +1126,14 @@
     // we also don't want mOwnedByClient to change during this
     Mutex::Autolock al(mBufferLock);
 
-    Vector<BufferInfo> *buffers = &mPortBuffers[portIndex];
-    if (index >= buffers->size()) {
+    std::vector<BufferInfo> &buffers = mPortBuffers[portIndex];
+    if (index >= buffers.size()) {
         ALOGE("getBufferAndFormat - trying to get buffer with "
-              "bad index (index=%zu buffer_size=%zu)", index, buffers->size());
+              "bad index (index=%zu buffer_size=%zu)", index, buffers.size());
         return INVALID_OPERATION;
     }
 
-    const BufferInfo &info = buffers->itemAt(index);
+    const BufferInfo &info = buffers[index];
     if (!info.mOwnedByClient) {
         ALOGE("getBufferAndFormat - invalid operation "
               "(the index %zu is not owned by client)", index);
@@ -1026,7 +1231,7 @@
         }
 
         const sp<MediaCodecBuffer> &buffer =
-            mPortBuffers[kPortIndexOutput].itemAt(index).mData;
+            mPortBuffers[kPortIndexOutput][index].mData;
 
         response->setSize("index", index);
         response->setSize("offset", buffer->offset());
@@ -1037,19 +1242,8 @@
 
         response->setInt64("timeUs", timeUs);
 
-        int32_t omxFlags;
-        CHECK(buffer->meta()->findInt32("omxFlags", &omxFlags));
-
-        uint32_t flags = 0;
-        if (omxFlags & OMX_BUFFERFLAG_SYNCFRAME) {
-            flags |= BUFFER_FLAG_SYNCFRAME;
-        }
-        if (omxFlags & OMX_BUFFERFLAG_CODECCONFIG) {
-            flags |= BUFFER_FLAG_CODECCONFIG;
-        }
-        if (omxFlags & OMX_BUFFERFLAG_EOS) {
-            flags |= BUFFER_FLAG_EOS;
-        }
+        int32_t flags;
+        CHECK(buffer->meta()->findInt32("flags", &flags));
 
         response->setInt32("flags", flags);
         response->postReply(replyID);
@@ -1066,7 +1260,7 @@
             CHECK(msg->findInt32("what", &what));
 
             switch (what) {
-                case CodecBase::kWhatError:
+                case kWhatError:
                 {
                     int32_t err, actionCode;
                     CHECK(msg->findInt32("err", &err));
@@ -1201,7 +1395,7 @@
                     break;
                 }
 
-                case CodecBase::kWhatComponentAllocated:
+                case kWhatComponentAllocated:
                 {
                     CHECK_EQ(mState, INITIALIZING);
                     setState(INITIALIZED);
@@ -1233,7 +1427,7 @@
                     break;
                 }
 
-                case CodecBase::kWhatComponentConfigured:
+                case kWhatComponentConfigured:
                 {
                     if (mState == UNINITIALIZED || mState == INITIALIZED) {
                         // In case a kWhatError message came in and replied with error,
@@ -1262,7 +1456,7 @@
                     break;
                 }
 
-                case CodecBase::kWhatInputSurfaceCreated:
+                case kWhatInputSurfaceCreated:
                 {
                     // response to initiateCreateInputSurface()
                     status_t err = NO_ERROR;
@@ -1286,7 +1480,7 @@
                     break;
                 }
 
-                case CodecBase::kWhatInputSurfaceAccepted:
+                case kWhatInputSurfaceAccepted:
                 {
                     // response to initiateSetInputSurface()
                     status_t err = NO_ERROR;
@@ -1302,7 +1496,7 @@
                     break;
                 }
 
-                case CodecBase::kWhatSignaledInputEOS:
+                case kWhatSignaledInputEOS:
                 {
                     // response to signalEndOfInputStream()
                     sp<AMessage> response = new AMessage;
@@ -1314,79 +1508,28 @@
                     break;
                 }
 
-
-                case CodecBase::kWhatBuffersAllocated:
+                case kWhatStartCompleted:
                 {
-                    Mutex::Autolock al(mBufferLock);
-                    int32_t portIndex;
-                    CHECK(msg->findInt32("portIndex", &portIndex));
-
-                    ALOGV("%s buffers allocated",
-                          portIndex == kPortIndexInput ? "input" : "output");
-
-                    CHECK(portIndex == kPortIndexInput
-                            || portIndex == kPortIndexOutput);
-
-                    mPortBuffers[portIndex].clear();
-                    mPortBufferArrays[portIndex].clear();
-
-                    Vector<BufferInfo> *buffers = &mPortBuffers[portIndex];
-
-                    sp<RefBase> obj;
-                    CHECK(msg->findObject("portDesc", &obj));
-
-                    sp<CodecBase::PortDescription> portDesc =
-                        static_cast<CodecBase::PortDescription *>(obj.get());
-
-                    size_t numBuffers = portDesc->countBuffers();
-
-                    size_t totalSize = 0;
-                    for (size_t i = 0; i < numBuffers; ++i) {
-                        if (portIndex == kPortIndexInput && mCrypto != NULL) {
-                            totalSize += portDesc->bufferAt(i)->capacity();
-                        }
+                    CHECK_EQ(mState, STARTING);
+                    if (mIsVideo) {
+                        addResource(
+                                MediaResource::kGraphicMemory,
+                                MediaResource::kUnspecifiedSubType,
+                                getGraphicBufferSize());
                     }
-
-                    if (totalSize) {
-                        mDealer = new MemoryDealer(totalSize, "MediaCodec");
-                    }
-
-                    for (size_t i = 0; i < numBuffers; ++i) {
-                        BufferInfo info;
-                        info.mBufferID = portDesc->bufferIDAt(i);
-                        info.mOwnedByClient = false;
-                        sp<MediaCodecBuffer> buffer = portDesc->bufferAt(i);
-                        if (portIndex == kPortIndexInput && mCrypto != NULL) {
-                            info.mSharedEncryptedBuffer = mDealer->allocate(buffer->capacity());
-                            buffer = new SharedMemoryBuffer(
-                                    mInputFormat, info.mSharedEncryptedBuffer);
-                        }
-                        buffers->push_back(info);
-                        mPortBufferArrays[portIndex].push_back(buffer);
-                    }
-
-                    if (portIndex == kPortIndexOutput) {
-                        if (mState == STARTING) {
-                            // We're always allocating output buffers after
-                            // allocating input buffers, so this is a good
-                            // indication that now all buffers are allocated.
-                            if (mIsVideo) {
-                                addResource(
-                                        MediaResource::kGraphicMemory,
-                                        MediaResource::kUnspecifiedSubType,
-                                        getGraphicBufferSize());
-                            }
-                            setState(STARTED);
-                            (new AMessage)->postReply(mReplyID);
-                        } else {
-                            mFlags |= kFlagOutputBuffersChanged;
-                            postActivityNotificationIfPossible();
-                        }
-                    }
+                    setState(STARTED);
+                    (new AMessage)->postReply(mReplyID);
                     break;
                 }
 
-                case CodecBase::kWhatOutputFramesRendered:
+                case kWhatOutputBuffersChanged:
+                {
+                    mFlags |= kFlagOutputBuffersChanged;
+                    postActivityNotificationIfPossible();
+                    break;
+                }
+
+                case kWhatOutputFramesRendered:
                 {
                     // ignore these in all states except running, and check that we have a
                     // notification set
@@ -1398,7 +1541,7 @@
                     break;
                 }
 
-                case CodecBase::kWhatFillThisBuffer:
+                case kWhatFillThisBuffer:
                 {
                     /* size_t index = */updateBuffers(kPortIndexInput, msg);
 
@@ -1409,9 +1552,6 @@
                         break;
                     }
 
-                    // TODO: hold reference of buffer from downstream when
-                    // mPortBuffers is removed.
-
                     if (!mCSD.empty()) {
                         ssize_t index = dequeuePortBuffer(kPortIndexInput);
                         CHECK_GE(index, 0);
@@ -1456,7 +1596,7 @@
                     break;
                 }
 
-                case CodecBase::kWhatDrainThisBuffer:
+                case kWhatDrainThisBuffer:
                 {
                     /* size_t index = */updateBuffers(kPortIndexOutput, msg);
 
@@ -1470,12 +1610,7 @@
                     sp<RefBase> obj;
                     CHECK(msg->findObject("buffer", &obj));
                     sp<MediaCodecBuffer> buffer = static_cast<MediaCodecBuffer *>(obj.get());
-                    // TODO: hold buffer's reference when we remove mPortBuffers
 
-                    int32_t omxFlags;
-                    CHECK(msg->findInt32("flags", &omxFlags));
-
-                    buffer->meta()->setInt32("omxFlags", omxFlags);
                     if (mOutputFormat != buffer->format()) {
                         mOutputFormat = buffer->format();
                         ALOGV("[%s] output format changed to: %s",
@@ -1508,7 +1643,9 @@
                             // Before we announce the format change we should
                             // collect codec specific data and amend the output
                             // format as necessary.
-                            if (omxFlags & OMX_BUFFERFLAG_CODECCONFIG) {
+                            int32_t flags = 0;
+                            (void) buffer->meta()->findInt32("flags", &flags);
+                            if (flags & BUFFER_FLAG_CODECCONFIG) {
                                 status_t err =
                                     amendOutputFormatWithCodecSpecificData(buffer);
 
@@ -1553,14 +1690,14 @@
                     break;
                 }
 
-                case CodecBase::kWhatEOS:
+                case kWhatEOS:
                 {
                     // We already notify the client of this by using the
                     // corresponding flag in "onOutputBufferReady".
                     break;
                 }
 
-                case CodecBase::kWhatStopCompleted:
+                case kWhatStopCompleted:
                 {
                     if (mState != STOPPING) {
                         ALOGW("Received kWhatStopCompleted in state %d", mState);
@@ -1571,7 +1708,7 @@
                     break;
                 }
 
-                case CodecBase::kWhatReleaseCompleted:
+                case kWhatReleaseCompleted:
                 {
                     if (mState != RELEASING) {
                         ALOGW("Received kWhatReleaseCompleted in state %d", mState);
@@ -1588,7 +1725,7 @@
                     break;
                 }
 
-                case CodecBase::kWhatFlushCompleted:
+                case kWhatFlushCompleted:
                 {
                     if (mState != FLUSHING) {
                         ALOGW("received FlushCompleted message in state %d",
@@ -1731,6 +1868,7 @@
             }
 
             mCrypto = static_cast<ICrypto *>(crypto);
+            mBufferChannel->setCrypto(mCrypto);
 
             uint32_t flags;
             CHECK(msg->findInt32("flags", (int32_t *)&flags));
@@ -2139,12 +2277,7 @@
         {
             sp<AReplyToken> replyID;
             CHECK(msg->senderAwaitsResponse(&replyID));
-            // Unfortunately widevine legacy source requires knowing all of the
-            // codec input buffers, so we have to provide them even in async mode.
-            int32_t widevine = 0;
-            msg->findInt32("widevine", &widevine);
-
-            if (!isExecuting() || ((mFlags & kFlagIsAsync) && !widevine)) {
+            if (!isExecuting() || (mFlags & kFlagIsAsync)) {
                 PostReplyWithError(replyID, INVALID_OPERATION);
                 break;
             } else if (mFlags & kFlagStickyError) {
@@ -2163,10 +2296,10 @@
             // createInputSurface(), or persistent set by setInputSurface()),
             // give the client an empty input buffers array.
             if (portIndex != kPortIndexInput || !mHaveInputSurface) {
-                const Vector<sp<MediaCodecBuffer>> &srcBuffers = mPortBufferArrays[portIndex];
-
-                for (size_t i = 0; i < srcBuffers.size(); ++i) {
-                    dstBuffers->push_back(srcBuffers[i]);
+                if (portIndex == kPortIndexInput) {
+                    mBufferChannel->getInputBufferArray(dstBuffers);
+                } else {
+                    mBufferChannel->getOutputBufferArray(dstBuffers);
                 }
             }
 
@@ -2295,13 +2428,12 @@
 status_t MediaCodec::queueCSDInputBuffer(size_t bufferIndex) {
     CHECK(!mCSD.empty());
 
-    const BufferInfo *info =
-        &mPortBuffers[kPortIndexInput].itemAt(bufferIndex);
+    const BufferInfo &info = mPortBuffers[kPortIndexInput][bufferIndex];
 
     sp<ABuffer> csd = *mCSD.begin();
     mCSD.erase(mCSD.begin());
 
-    const sp<MediaCodecBuffer> &codecInputData = info->mData;
+    const sp<MediaCodecBuffer> &codecInputData = info.mData;
 
     if (csd->size() > codecInputData->capacity()) {
         return -EINVAL;
@@ -2369,28 +2501,19 @@
     CHECK(portIndex == kPortIndexInput || portIndex == kPortIndexOutput);
     Mutex::Autolock al(mBufferLock);
 
-    Vector<BufferInfo> *buffers = &mPortBuffers[portIndex];
+    for (size_t i = 0; i < mPortBuffers[portIndex].size(); ++i) {
+        BufferInfo *info = &mPortBuffers[portIndex][i];
 
-    for (size_t i = 0; i < buffers->size(); ++i) {
-        BufferInfo *info = &buffers->editItemAt(i);
-
-        if (info->mNotify != NULL) {
-            sp<AMessage> msg = info->mNotify;
-            info->mNotify = NULL;
+        if (info->mData != nullptr) {
+            sp<MediaCodecBuffer> buffer = info->mData;
             if (isReclaim && info->mOwnedByClient) {
                 ALOGD("port %d buffer %zu still owned by client when codec is reclaimed",
                         portIndex, i);
             } else {
                 info->mOwnedByClient = false;
                 info->mData.clear();
-                info->mSecureData.clear();
             }
-
-            if (portIndex == kPortIndexInput) {
-                /* no error, just returning buffers */
-                msg->setInt32("err", OK);
-            }
-            msg->post();
+            mBufferChannel->discardBuffer(buffer);
         }
     }
 
@@ -2400,37 +2523,22 @@
 size_t MediaCodec::updateBuffers(
         int32_t portIndex, const sp<AMessage> &msg) {
     CHECK(portIndex == kPortIndexInput || portIndex == kPortIndexOutput);
-
-    uint32_t bufferID;
-    CHECK(msg->findInt32("buffer-id", (int32_t*)&bufferID));
+    size_t index;
+    CHECK(msg->findSize("index", &index));
     sp<RefBase> obj;
     CHECK(msg->findObject("buffer", &obj));
     sp<MediaCodecBuffer> buffer = static_cast<MediaCodecBuffer *>(obj.get());
 
-    Vector<BufferInfo> *buffers = &mPortBuffers[portIndex];
-
-    for (size_t i = 0; i < buffers->size(); ++i) {
-        BufferInfo *info = &buffers->editItemAt(i);
-
-        if (info->mBufferID == bufferID) {
-            CHECK(info->mNotify == NULL);
-            CHECK(msg->findMessage("reply", &info->mNotify));
-
-            if (portIndex == kPortIndexInput && mCrypto != NULL) {
-                info->mSecureData = buffer;
-                info->mData = mPortBufferArrays[portIndex][i];
-            } else {
-                info->mData = buffer;
-            }
-            mAvailPortBuffers[portIndex].push_back(i);
-
-            return i;
+    {
+        Mutex::Autolock al(mBufferLock);
+        if (mPortBuffers[portIndex].size() <= index) {
+            mPortBuffers[portIndex].resize(align(index + 1, kNumBuffersAlign));
         }
+        mPortBuffers[portIndex][index].mData = buffer;
     }
+    mAvailPortBuffers[portIndex].push_back(index);
 
-    TRESPASS();
-
-    return 0;
+    return index;
 }
 
 status_t MediaCodec::onQueueInputBuffer(const sp<AMessage> &msg) {
@@ -2495,9 +2603,9 @@
         return -ERANGE;
     }
 
-    BufferInfo *info = &mPortBuffers[kPortIndexInput].editItemAt(index);
+    BufferInfo *info = &mPortBuffers[kPortIndexInput][index];
 
-    if (info->mNotify == NULL || !info->mOwnedByClient) {
+    if (info->mData == nullptr || !info->mOwnedByClient) {
         return -EACCES;
     }
 
@@ -2505,69 +2613,44 @@
         return -EINVAL;
     }
 
-    sp<AMessage> reply = info->mNotify;
     info->mData->setRange(offset, size);
+    info->mData->meta()->setInt64("timeUs", timeUs);
+    if (flags & BUFFER_FLAG_EOS) {
+        info->mData->meta()->setInt32("eos", true);
+    }
 
-    sp<MediaCodecBuffer> buffer = info->mData;
+    if (flags & BUFFER_FLAG_CODECCONFIG) {
+        info->mData->meta()->setInt32("csd", true);
+    }
+
+    // synchronization boundary for getBufferAndFormat
+    sp<MediaCodecBuffer> buffer;
+    {
+        Mutex::Autolock al(mBufferLock);
+        info->mOwnedByClient = false;
+        buffer = info->mData;
+        info->mData.clear();
+    }
+    status_t err = OK;
     if (mCrypto != NULL) {
         AString *errorDetailMsg;
         CHECK(msg->findPointer("errorDetailMsg", (void **)&errorDetailMsg));
 
-        void *dst_pointer = nullptr;
-        ICrypto::DestinationType dst_type = ICrypto::kDestinationTypeOpaqueHandle;
-
-        if ((mFlags & kFlagIsSecure) == 0) {
-            dst_pointer = info->mSecureData->base();
-            dst_type = ICrypto::kDestinationTypeVmPointer;
-        } else {
-            sp<SecureBuffer> secureData = static_cast<SecureBuffer *>(info->mSecureData.get());
-            dst_pointer = secureData->getDestinationPointer();
-            dst_type = secureData->getDestinationType();
-        }
-
-        ssize_t result = mCrypto->decrypt(
-                dst_type,
+        err = mBufferChannel->queueSecureInputBuffer(
+                buffer,
+                (mFlags & kFlagIsSecure),
                 key,
                 iv,
                 mode,
                 pattern,
-                info->mSharedEncryptedBuffer,
-                offset,
                 subSamples,
                 numSubSamples,
-                dst_pointer,
                 errorDetailMsg);
-
-        if (result < 0) {
-            return result;
-        }
-
-        info->mSecureData->setRange(0, result);
-        buffer = info->mSecureData;
-    }
-    buffer->meta()->setInt64("timeUs", timeUs);
-
-    if (flags & BUFFER_FLAG_EOS) {
-        buffer->meta()->setInt32("eos", true);
+    } else {
+        err = mBufferChannel->queueInputBuffer(buffer);
     }
 
-    if (flags & BUFFER_FLAG_CODECCONFIG) {
-        buffer->meta()->setInt32("csd", true);
-    }
-
-    // synchronization boundary for getBufferAndFormat
-    {
-        Mutex::Autolock al(mBufferLock);
-        info->mOwnedByClient = false;
-    }
-    info->mData.clear();
-    info->mSecureData.clear();
-    reply->setObject("buffer", buffer);
-    reply->post();
-
-    info->mNotify = NULL;
-
-    return OK;
+    return err;
 }
 
 //static
@@ -2604,23 +2687,24 @@
         return -ERANGE;
     }
 
-    BufferInfo *info = &mPortBuffers[kPortIndexOutput].editItemAt(index);
+    BufferInfo *info = &mPortBuffers[kPortIndexOutput][index];
 
-    if (info->mNotify == NULL || !info->mOwnedByClient) {
+    if (info->mData == nullptr || !info->mOwnedByClient) {
         return -EACCES;
     }
 
     // synchronization boundary for getBufferAndFormat
+    sp<MediaCodecBuffer> buffer;
     {
         Mutex::Autolock al(mBufferLock);
         info->mOwnedByClient = false;
+        buffer = info->mData;
+        info->mData.clear();
     }
 
-    if (render && info->mData != NULL && info->mData->size() != 0) {
-        info->mNotify->setInt32("render", true);
-
+    if (render && buffer->size() != 0) {
         int64_t mediaTimeUs = -1;
-        info->mData->meta()->findInt64("timeUs", &mediaTimeUs);
+        buffer->meta()->findInt64("timeUs", &mediaTimeUs);
 
         int64_t renderTimeNs = 0;
         if (!msg->findInt64("timestampNs", &renderTimeNs)) {
@@ -2628,12 +2712,11 @@
             ALOGV("using buffer PTS of %lld", (long long)mediaTimeUs);
             renderTimeNs = mediaTimeUs * 1000;
         }
-        info->mNotify->setInt64("timestampNs", renderTimeNs);
 
         if (mSoftRenderer != NULL) {
             std::list<FrameRenderTracker::Info> doneFrames = mSoftRenderer->render(
-                    info->mData->data(), info->mData->size(),
-                    mediaTimeUs, renderTimeNs, NULL, info->mData->format());
+                    buffer->data(), buffer->size(),
+                    mediaTimeUs, renderTimeNs, NULL, buffer->format());
 
             // if we are running, notify rendered frames
             if (!doneFrames.empty() && mState == STARTED && mOnFrameRenderedNotification != NULL) {
@@ -2645,13 +2728,11 @@
                 }
             }
         }
+        mBufferChannel->renderOutputBuffer(buffer, renderTimeNs);
+    } else {
+        mBufferChannel->discardBuffer(buffer);
     }
 
-    info->mNotify->setObject("buffer", info->mData);
-    info->mData.clear();
-    info->mNotify->post();
-    info->mNotify.clear();
-
     return OK;
 }
 
@@ -2667,7 +2748,7 @@
     size_t index = *availBuffers->begin();
     availBuffers->erase(availBuffers->begin());
 
-    BufferInfo *info = &mPortBuffers[portIndex].editItemAt(index);
+    BufferInfo *info = &mPortBuffers[portIndex][index];
     CHECK(!info->mOwnedByClient);
     {
         Mutex::Autolock al(mBufferLock);
@@ -2771,7 +2852,7 @@
     int32_t index;
     while ((index = dequeuePortBuffer(kPortIndexOutput)) >= 0) {
         const sp<MediaCodecBuffer> &buffer =
-            mPortBuffers[kPortIndexOutput].itemAt(index).mData;
+            mPortBuffers[kPortIndexOutput][index].mData;
         sp<AMessage> msg = mCallback->dup();
         msg->setInt32("callbackID", CB_OUTPUT_AVAILABLE);
         msg->setInt32("index", index);
@@ -2783,19 +2864,8 @@
 
         msg->setInt64("timeUs", timeUs);
 
-        int32_t omxFlags;
-        CHECK(buffer->meta()->findInt32("omxFlags", &omxFlags));
-
-        uint32_t flags = 0;
-        if (omxFlags & OMX_BUFFERFLAG_SYNCFRAME) {
-            flags |= BUFFER_FLAG_SYNCFRAME;
-        }
-        if (omxFlags & OMX_BUFFERFLAG_CODECCONFIG) {
-            flags |= BUFFER_FLAG_CODECCONFIG;
-        }
-        if (omxFlags & OMX_BUFFERFLAG_EOS) {
-            flags |= BUFFER_FLAG_EOS;
-        }
+        int32_t flags;
+        CHECK(buffer->meta()->findInt32("flags", &flags));
 
         msg->setInt32("flags", flags);
 
@@ -2827,7 +2897,6 @@
     }
 }
 
-
 void MediaCodec::postActivityNotificationIfPossible() {
     if (mActivityNotify == NULL) {
         return;
diff --git a/media/libstagefright/MediaExtractor.cpp b/media/libstagefright/MediaExtractor.cpp
index f2fdbc9..aeaead5 100644
--- a/media/libstagefright/MediaExtractor.cpp
+++ b/media/libstagefright/MediaExtractor.cpp
@@ -28,7 +28,6 @@
 #include "include/MPEG2PSExtractor.h"
 #include "include/MPEG2TSExtractor.h"
 #include "include/DRMExtractor.h"
-#include "include/WVMExtractor.h"
 #include "include/FLACExtractor.h"
 #include "include/AACExtractor.h"
 #include "include/MidiExtractor.h"
@@ -144,22 +143,14 @@
         const sp<DataSource> &source, const char *mime) {
     ALOGV("MediaExtractor::Create %s", mime);
 
-    char value[PROPERTY_VALUE_MAX];
-    if (property_get("media.stagefright.extractremote", value, NULL)
-            && (!strcmp("0", value) || !strcasecmp("false", value))) {
+    if (!property_get_bool("media.stagefright.extractremote", true)) {
         // local extractor
         ALOGW("creating media extractor in calling process");
         return CreateFromService(source, mime);
     } else {
-        // Check if it's WVM, since WVMExtractor needs to be created in the media server process,
-        // not the extractor process.
         String8 mime8;
         float confidence;
         sp<AMessage> meta;
-        if (SniffWVM(source, &mime8, &confidence, &meta) &&
-                !strcasecmp(mime8, MEDIA_MIMETYPE_CONTAINER_WVM)) {
-            return new WVMExtractor(source);
-        }
 
         // Check if it's es-based DRM, since DRMExtractor needs to be created in the media server
         // process, not the extractor process.
@@ -192,14 +183,14 @@
         const sp<DataSource> &source, const char *mime) {
 
     ALOGV("MediaExtractor::CreateFromService %s", mime);
-    DataSource::RegisterDefaultSniffers();
+    RegisterDefaultSniffers();
 
     sp<AMessage> meta;
 
     String8 tmp;
     if (mime == NULL) {
         float confidence;
-        if (!source->sniff(&tmp, &confidence, &meta)) {
+        if (!sniff(source, &tmp, &confidence, &meta)) {
             ALOGV("FAILED to autodetect media content.");
 
             return NULL;
@@ -251,9 +242,6 @@
         ret = new MatroskaExtractor(source);
     } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG2TS)) {
         ret = new MPEG2TSExtractor(source);
-    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_WVM) && getuid() == AID_MEDIA) {
-        // Return now.  WVExtractor should not have the DrmFlag set in the block below.
-        return new WVMExtractor(source);
     } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC_ADTS)) {
         ret = new AACExtractor(source, meta);
     } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG2PS)) {
@@ -273,4 +261,77 @@
     return ret;
 }
 
+Mutex MediaExtractor::gSnifferMutex;
+List<MediaExtractor::SnifferFunc> MediaExtractor::gSniffers;
+bool MediaExtractor::gSniffersRegistered = false;
+
+// static
+bool MediaExtractor::sniff(
+        const sp<DataSource> &source, String8 *mimeType, float *confidence, sp<AMessage> *meta) {
+    *mimeType = "";
+    *confidence = 0.0f;
+    meta->clear();
+
+    {
+        Mutex::Autolock autoLock(gSnifferMutex);
+        if (!gSniffersRegistered) {
+            return false;
+        }
+    }
+
+    for (List<SnifferFunc>::iterator it = gSniffers.begin();
+         it != gSniffers.end(); ++it) {
+        String8 newMimeType;
+        float newConfidence;
+        sp<AMessage> newMeta;
+        if ((*it)(source, &newMimeType, &newConfidence, &newMeta)) {
+            if (newConfidence > *confidence) {
+                *mimeType = newMimeType;
+                *confidence = newConfidence;
+                *meta = newMeta;
+            }
+        }
+    }
+
+    return *confidence > 0.0;
+}
+
+// static
+void MediaExtractor::RegisterSniffer_l(SnifferFunc func) {
+    for (List<SnifferFunc>::iterator it = gSniffers.begin();
+         it != gSniffers.end(); ++it) {
+        if (*it == func) {
+            return;
+        }
+    }
+
+    gSniffers.push_back(func);
+}
+
+// static
+void MediaExtractor::RegisterDefaultSniffers() {
+    Mutex::Autolock autoLock(gSnifferMutex);
+    if (gSniffersRegistered) {
+        return;
+    }
+
+    RegisterSniffer_l(SniffMPEG4);
+    RegisterSniffer_l(SniffMatroska);
+    RegisterSniffer_l(SniffOgg);
+    RegisterSniffer_l(SniffWAV);
+    RegisterSniffer_l(SniffFLAC);
+    RegisterSniffer_l(SniffAMR);
+    RegisterSniffer_l(SniffMPEG2TS);
+    RegisterSniffer_l(SniffMP3);
+    RegisterSniffer_l(SniffAAC);
+    RegisterSniffer_l(SniffMPEG2PS);
+    RegisterSniffer_l(SniffMidi);
+
+    if (property_get_bool("drm.service.enabled", false)) {
+        RegisterSniffer_l(SniffDRM);
+    }
+    gSniffersRegistered = true;
+}
+
+
 }  // namespace android
diff --git a/media/libstagefright/NuMediaExtractor.cpp b/media/libstagefright/NuMediaExtractor.cpp
index e3270ed..6f8220f 100644
--- a/media/libstagefright/NuMediaExtractor.cpp
+++ b/media/libstagefright/NuMediaExtractor.cpp
@@ -22,7 +22,6 @@
 
 #include "include/ESDS.h"
 #include "include/NuCachedSource2.h"
-#include "include/WVMExtractor.h"
 
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
@@ -40,8 +39,7 @@
 namespace android {
 
 NuMediaExtractor::NuMediaExtractor()
-    : mIsWidevineExtractor(false),
-      mTotalBitrate(-1ll),
+    : mTotalBitrate(-1ll),
       mDurationUs(-1ll) {
 }
 
@@ -78,48 +76,15 @@
         return -ENOENT;
     }
 
-    mIsWidevineExtractor = false;
-    if (!strncasecmp("widevine://", path, 11)) {
-        String8 mimeType;
-        float confidence;
-        sp<AMessage> dummy;
-        bool success = SniffWVM(dataSource, &mimeType, &confidence, &dummy);
-
-        if (!success
-                || strcasecmp(
-                    mimeType.string(), MEDIA_MIMETYPE_CONTAINER_WVM)) {
-            return ERROR_UNSUPPORTED;
-        }
-
-        sp<WVMExtractor> extractor = new WVMExtractor(dataSource);
-        extractor->setAdaptiveStreamingMode(true);
-
-        mImpl = extractor;
-        mIsWidevineExtractor = true;
-    } else {
-        mImpl = MediaExtractor::Create(dataSource);
-    }
+    mImpl = MediaExtractor::Create(dataSource);
 
     if (mImpl == NULL) {
         return ERROR_UNSUPPORTED;
     }
 
     sp<MetaData> fileMeta = mImpl->getMetaData();
-    const char *containerMime;
-    if (fileMeta != NULL
-            && fileMeta->findCString(kKeyMIMEType, &containerMime)
-            && !strcasecmp(containerMime, "video/wvm")) {
-        // We always want to use "cryptoPluginMode" when using the wvm
-        // extractor. We can tell that it is this extractor by looking
-        // at the container mime type.
-        // The cryptoPluginMode ensures that the extractor will actually
-        // give us data in a call to MediaSource::read(), unlike its
-        // default mode that we used in AwesomePlayer.
-        // TODO: change default mode
-        static_cast<WVMExtractor *>(mImpl.get())->setCryptoPluginMode(true);
-    } else if (mImpl->getDrmFlag()) {
-        // For all other drm content, we don't want to expose decrypted
-        // content to Java application.
+    if (mImpl->getDrmFlag()) {
+        // Don't expose decrypted content to Java application
         mImpl.clear();
         mImpl = NULL;
         return ERROR_UNSUPPORTED;
@@ -633,15 +598,7 @@
     Mutex::Autolock autoLock(mLock);
 
     int64_t bitrate;
-    if (mIsWidevineExtractor) {
-        sp<WVMExtractor> wvmExtractor =
-            static_cast<WVMExtractor *>(mImpl.get());
-
-        status_t finalStatus;
-        *durationUs = wvmExtractor->getCachedDurationUs(&finalStatus);
-        *eos = (finalStatus != OK);
-        return true;
-    } else if ((mDataSource->flags() & DataSource::kIsCachingDataSource)
+    if ((mDataSource->flags() & DataSource::kIsCachingDataSource)
             && getTotalBitrate(&bitrate)) {
         sp<NuCachedSource2> cachedSource =
             static_cast<NuCachedSource2 *>(mDataSource.get());
diff --git a/media/libstagefright/StagefrightMetadataRetriever.cpp b/media/libstagefright/StagefrightMetadataRetriever.cpp
index d8fec5c..5e00c44 100644
--- a/media/libstagefright/StagefrightMetadataRetriever.cpp
+++ b/media/libstagefright/StagefrightMetadataRetriever.cpp
@@ -55,8 +55,6 @@
     : mParsedMetaData(false),
       mAlbumArt(NULL) {
     ALOGV("StagefrightMetadataRetriever()");
-
-    DataSource::RegisterDefaultSniffers();
 }
 
 StagefrightMetadataRetriever::~StagefrightMetadataRetriever() {
diff --git a/media/libstagefright/Utils.cpp b/media/libstagefright/Utils.cpp
index c593eb5..f2638ed 100644
--- a/media/libstagefright/Utils.cpp
+++ b/media/libstagefright/Utils.cpp
@@ -1659,9 +1659,7 @@
         return AString("<URI suppressed>");
     }
 
-    char prop[PROPERTY_VALUE_MAX];
-    if (property_get("media.stagefright.log-uri", prop, "false") &&
-        (!strcmp(prop, "1") || !strcmp(prop, "true"))) {
+    if (property_get_bool("media.stagefright.log-uri", false)) {
         return uri;
     }
 
diff --git a/media/libstagefright/WVMExtractor.cpp b/media/libstagefright/WVMExtractor.cpp
deleted file mode 100644
index d1b2f54..0000000
--- a/media/libstagefright/WVMExtractor.cpp
+++ /dev/null
@@ -1,197 +0,0 @@
-/*
- * Copyright (C) 2010 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 "WVMExtractor"
-#include <utils/Log.h>
-
-#include "include/WVMExtractor.h"
-
-#include <arpa/inet.h>
-#include <utils/String8.h>
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/Utils.h>
-#include <media/stagefright/DataSource.h>
-#include <media/stagefright/MediaSource.h>
-#include <media/stagefright/MediaDefs.h>
-#include <media/stagefright/MetaData.h>
-#include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/MediaBuffer.h>
-#include <dlfcn.h>
-
-#include <utils/Errors.h>
-
-/* The extractor lifetime is short - just long enough to get
- * the media sources constructed - so the shared lib needs to remain open
- * beyond the lifetime of the extractor.  So keep the handle as a global
- * rather than a member of the extractor
- */
-void *gVendorLibHandle = NULL;
-
-namespace android {
-
-static Mutex gWVMutex;
-
-WVMExtractor::WVMExtractor(const sp<DataSource> &source)
-    : mDataSource(source)
-{
-    Mutex::Autolock autoLock(gWVMutex);
-
-    if (!getVendorLibHandle()) {
-        return;
-    }
-
-    typedef WVMLoadableExtractor *(*GetInstanceFunc)(sp<DataSource>);
-    GetInstanceFunc getInstanceFunc =
-        (GetInstanceFunc) dlsym(gVendorLibHandle,
-                "_ZN7android11GetInstanceENS_2spINS_10DataSourceEEE");
-
-    if (getInstanceFunc) {
-        if (source->DrmInitialization(
-                MEDIA_MIMETYPE_CONTAINER_WVM) != NULL) {
-            mImpl = (*getInstanceFunc)(source);
-            CHECK(mImpl != NULL);
-            setDrmFlag(true);
-        } else {
-            ALOGE("Drm manager failed to initialize.");
-        }
-    } else {
-        ALOGE("Failed to locate GetInstance in libwvm.so");
-    }
-}
-
-static void init_routine()
-{
-    gVendorLibHandle = dlopen("libwvm.so", RTLD_NOW);
-    if (gVendorLibHandle == NULL) {
-        ALOGE("Failed to open libwvm.so: %s", dlerror());
-    }
-}
-
-bool WVMExtractor::getVendorLibHandle()
-{
-    static pthread_once_t sOnceControl = PTHREAD_ONCE_INIT;
-    pthread_once(&sOnceControl, init_routine);
-
-    return gVendorLibHandle != NULL;
-}
-
-WVMExtractor::~WVMExtractor() {
-}
-
-size_t WVMExtractor::countTracks() {
-    return (mImpl != NULL) ? mImpl->countTracks() : 0;
-}
-
-sp<IMediaSource> WVMExtractor::getTrack(size_t index) {
-    if (mImpl == NULL) {
-        return NULL;
-    }
-    return mImpl->getTrack(index);
-}
-
-sp<MetaData> WVMExtractor::getTrackMetaData(size_t index, uint32_t flags) {
-    if (mImpl == NULL) {
-        return NULL;
-    }
-    return mImpl->getTrackMetaData(index, flags);
-}
-
-sp<MetaData> WVMExtractor::getMetaData() {
-    if (mImpl == NULL) {
-        return NULL;
-    }
-    return mImpl->getMetaData();
-}
-
-int64_t WVMExtractor::getCachedDurationUs(status_t *finalStatus) {
-    if (mImpl == NULL) {
-        return 0;
-    }
-
-    return mImpl->getCachedDurationUs(finalStatus);
-}
-
-status_t WVMExtractor::getEstimatedBandwidthKbps(int32_t *kbps) {
-    if (mImpl == NULL) {
-        return UNKNOWN_ERROR;
-    }
-
-    return mImpl->getEstimatedBandwidthKbps(kbps);
-}
-
-
-void WVMExtractor::setAdaptiveStreamingMode(bool adaptive) {
-    if (mImpl != NULL) {
-        mImpl->setAdaptiveStreamingMode(adaptive);
-    }
-}
-
-void WVMExtractor::setCryptoPluginMode(bool cryptoPluginMode) {
-    if (mImpl != NULL) {
-        mImpl->setCryptoPluginMode(cryptoPluginMode);
-    }
-}
-
-void WVMExtractor::setUID(uid_t uid) {
-    if (mImpl != NULL) {
-        mImpl->setUID(uid);
-    }
-}
-
-status_t WVMExtractor::getError() {
-    if (mImpl == NULL) {
-       return UNKNOWN_ERROR;
-    }
-
-    return mImpl->getError();
-}
-
-void WVMExtractor::setError(status_t err) {
-    if (mImpl != NULL) {
-        mImpl->setError(err);
-    }
-}
-
-bool SniffWVM(
-    const sp<DataSource> &source, String8 *mimeType, float *confidence,
-        sp<AMessage> *) {
-
-    Mutex::Autolock autoLock(gWVMutex);
-
-    if (!WVMExtractor::getVendorLibHandle()) {
-        return false;
-    }
-
-    typedef WVMLoadableExtractor *(*SnifferFunc)(const sp<DataSource>&);
-    SnifferFunc snifferFunc =
-        (SnifferFunc) dlsym(gVendorLibHandle,
-                            "_ZN7android15IsWidevineMediaERKNS_2spINS_10DataSourceEEE");
-
-    if (snifferFunc) {
-        if ((*snifferFunc)(source)) {
-            *mimeType = MEDIA_MIMETYPE_CONTAINER_WVM;
-            *confidence = 10.0f;
-            return true;
-        }
-    } else {
-        ALOGE("IsWidevineMedia not found in libwvm.so");
-    }
-
-    return false;
-}
-
-} //namespace android
-
diff --git a/media/libstagefright/filters/MediaFilter.cpp b/media/libstagefright/filters/MediaFilter.cpp
index 877aead..777ab5b 100644
--- a/media/libstagefright/filters/MediaFilter.cpp
+++ b/media/libstagefright/filters/MediaFilter.cpp
@@ -42,6 +42,7 @@
 #include "SaturationFilter.h"
 #include "ZeroFilter.h"
 
+#include "../include/ACodecBufferChannel.h"
 #include "../include/SharedMemoryBuffer.h"
 
 namespace android {
@@ -53,6 +54,9 @@
     : mState(UNINITIALIZED),
       mGeneration(0),
       mGraphicBufferListener(NULL) {
+    mBufferChannel = std::make_shared<ACodecBufferChannel>(
+            new AMessage(kWhatInputBufferFilled, this),
+            new AMessage(kWhatOutputBufferDrained, this));
 }
 
 MediaFilter::~MediaFilter() {
@@ -60,8 +64,8 @@
 
 //////////////////// PUBLIC FUNCTIONS //////////////////////////////////////////
 
-void MediaFilter::setNotificationMessage(const sp<AMessage> &msg) {
-    mNotify = msg;
+std::shared_ptr<BufferChannelBase> MediaFilter::getBufferChannel() {
+    return mBufferChannel;
 }
 
 void MediaFilter::initiateAllocateComponent(const sp<AMessage> &msg) {
@@ -193,29 +197,6 @@
     }
 }
 
-//////////////////// PORT DESCRIPTION //////////////////////////////////////////
-
-MediaFilter::PortDescription::PortDescription() {
-}
-
-void MediaFilter::PortDescription::addBuffer(
-        IOMX::buffer_id id, const sp<MediaCodecBuffer> &buffer) {
-    mBufferIDs.push_back(id);
-    mBuffers.push_back(buffer);
-}
-
-size_t MediaFilter::PortDescription::countBuffers() {
-    return mBufferIDs.size();
-}
-
-IOMX::buffer_id MediaFilter::PortDescription::bufferIDAt(size_t index) const {
-    return mBufferIDs.itemAt(index);
-}
-
-sp<MediaCodecBuffer> MediaFilter::PortDescription::bufferAt(size_t index) const {
-    return mBuffers.itemAt(index);
-}
-
 //////////////////// HELPER FUNCTIONS //////////////////////////////////////////
 
 void MediaFilter::signalProcessBuffers() {
@@ -223,10 +204,7 @@
 }
 
 void MediaFilter::signalError(status_t error) {
-    sp<AMessage> notify = mNotify->dup();
-    notify->setInt32("what", CodecBase::kWhatError);
-    notify->setInt32("err", error);
-    notify->post();
+    mCallback->onError(error, ACTION_CODE_FATAL);
 }
 
 status_t MediaFilter::allocateBuffersOnPort(OMX_U32 portIndex) {
@@ -266,21 +244,15 @@
         }
     }
 
-    sp<AMessage> notify = mNotify->dup();
-    notify->setInt32("what", CodecBase::kWhatBuffersAllocated);
-
-    notify->setInt32("portIndex", portIndex);
-
-    sp<PortDescription> desc = new PortDescription;
-
+    std::vector<ACodecBufferChannel::BufferAndId> array(mBuffers[portIndex].size());
     for (size_t i = 0; i < mBuffers[portIndex].size(); ++i) {
-        const BufferInfo &info = mBuffers[portIndex][i];
-
-        desc->addBuffer(info.mBufferID, info.mData);
+        array[i] = {mBuffers[portIndex][i].mData, mBuffers[portIndex][i].mBufferID};
     }
-
-    notify->setObject("portDesc", desc);
-    notify->post();
+    if (portIndex == kPortIndexInput) {
+        mBufferChannel->setInputBufferArray(array);
+    } else {
+        mBufferChannel->setOutputBufferArray(array);
+    }
 
     return OK;
 }
@@ -314,20 +286,14 @@
 
     info->mGeneration = mGeneration;
 
-    sp<AMessage> notify = mNotify->dup();
-    notify->setInt32("what", CodecBase::kWhatFillThisBuffer);
-    notify->setInt32("buffer-id", info->mBufferID);
-
     info->mData->meta()->clear();
-    notify->setObject("buffer", info->mData);
 
     sp<AMessage> reply = new AMessage(kWhatInputBufferFilled, this);
     reply->setInt32("buffer-id", info->mBufferID);
 
-    notify->setMessage("reply", reply);
-
     info->mStatus = BufferInfo::OWNED_BY_UPSTREAM;
-    notify->post();
+
+    mBufferChannel->fillThisBuffer(info->mBufferID);
 }
 
 void MediaFilter::postDrainThisBuffer(BufferInfo *info) {
@@ -335,27 +301,16 @@
 
     info->mGeneration = mGeneration;
 
-    sp<AMessage> notify = mNotify->dup();
-    notify->setInt32("what", CodecBase::kWhatDrainThisBuffer);
-    notify->setInt32("buffer-id", info->mBufferID);
-    notify->setInt32("flags", info->mOutputFlags);
-    notify->setObject("buffer", info->mData);
-
     sp<AMessage> reply = new AMessage(kWhatOutputBufferDrained, this);
     reply->setInt32("buffer-id", info->mBufferID);
 
-    notify->setMessage("reply", reply);
-
-    notify->post();
+    mBufferChannel->drainThisBuffer(info->mBufferID, info->mOutputFlags);
 
     info->mStatus = BufferInfo::OWNED_BY_UPSTREAM;
 }
 
 void MediaFilter::postEOS() {
-    sp<AMessage> notify = mNotify->dup();
-    notify->setInt32("what", CodecBase::kWhatEOS);
-    notify->setInt32("err", ERROR_END_OF_STREAM);
-    notify->post();
+    mCallback->onEos(ERROR_END_OF_STREAM);
 
     ALOGV("Sent kWhatEOS.");
 }
@@ -445,11 +400,8 @@
         return;
     }
 
-    sp<AMessage> notify = mNotify->dup();
-    notify->setInt32("what", kWhatComponentAllocated);
     // HACK - need "OMX.google" to use MediaCodec's software renderer
-    notify->setString("componentName", "OMX.google.MediaFilter");
-    notify->post();
+    mCallback->onComponentAllocated("OMX.google.MediaFilter");
     mState = INITIALIZED;
     ALOGV("Handled kWhatAllocateComponent.");
 }
@@ -526,12 +478,7 @@
     mOutputFormat->setInt32("width", mWidth);
     mOutputFormat->setInt32("height", mHeight);
 
-    sp<AMessage> notify = mNotify->dup();
-    notify->setInt32("what", kWhatComponentConfigured);
-    notify->setString("componentName", "MediaFilter");
-    notify->setMessage("input-format", mInputFormat);
-    notify->setMessage("output-format", mOutputFormat);
-    notify->post();
+    mCallback->onComponentConfigured(mInputFormat, mOutputFormat);
     mState = CONFIGURED;
     ALOGV("Handled kWhatConfigureComponent.");
 }
@@ -543,6 +490,8 @@
 
     allocateBuffersOnPort(kPortIndexOutput);
 
+    mCallback->onStartCompleted();
+
     status_t err = mFilter->start();
     if (err != (status_t)OK) {
         ALOGE("Failed to start filter component, err %d", err);
@@ -675,10 +624,11 @@
         mState = INITIALIZED;
     }
 
-    sp<AMessage> notify = mNotify->dup();
-    notify->setInt32("what", keepComponentAllocated ?
-            CodecBase::kWhatStopCompleted : CodecBase::kWhatReleaseCompleted);
-    notify->post();
+    if (keepComponentAllocated) {
+        mCallback->onStopCompleted();
+    } else {
+        mCallback->onReleaseCompleted();
+    }
 }
 
 void MediaFilter::onFlush() {
@@ -700,9 +650,7 @@
     mPortEOS[kPortIndexOutput] = false;
     mInputEOSResult = OK;
 
-    sp<AMessage> notify = mNotify->dup();
-    notify->setInt32("what", CodecBase::kWhatFlushCompleted);
-    notify->post();
+    mCallback->onFlushCompleted();
     ALOGV("Posted kWhatFlushCompleted");
 
     // MediaCodec returns all input buffers after flush, so in
@@ -734,13 +682,10 @@
         return;
     }
 
-    sp<AMessage> reply = mNotify->dup();
-    reply->setInt32("what", CodecBase::kWhatInputSurfaceCreated);
-    reply->setObject(
-            "input-surface",
+    mCallback->onInputSurfaceCreated(
+            nullptr, nullptr,
             new BufferProducerWrapper(
                     mGraphicBufferListener->getIGraphicBufferProducer()));
-    reply->post();
 }
 
 void MediaFilter::onInputFrameAvailable() {
@@ -802,9 +747,7 @@
     }
 
     mPortEOS[kPortIndexOutput] = true;
-    sp<AMessage> notify = mNotify->dup();
-    notify->setInt32("what", CodecBase::kWhatSignaledInputEOS);
-    notify->post();
+    mCallback->onSignaledInputEOS(OK);
 
     ALOGV("Output stream saw EOS.");
 }
diff --git a/media/libstagefright/foundation/tests/AData_test.cpp b/media/libstagefright/foundation/tests/AData_test.cpp
new file mode 100644
index 0000000..f014c25
--- /dev/null
+++ b/media/libstagefright/foundation/tests/AData_test.cpp
@@ -0,0 +1,981 @@
+/*
+ * 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "AData_test"
+
+#include <gtest/gtest.h>
+#include <utils/RefBase.h>
+//#include <utils/StrongPointer.h>
+
+#include <media/stagefright/foundation/AData.h>
+#include <media/stagefright/foundation/ABuffer.h>
+
+namespace android {
+
+class ADataTest : public ::testing::Test {
+};
+
+// ============ AUnion
+
+struct Events {
+    int dtor;
+    int ctor_empty;
+    int ctor_copy;
+};
+
+struct EventCounter : public RefBase {
+    EventCounter(int *counter, int magic=1234) : mCounter(counter), mMagic(magic) { }
+    virtual ~EventCounter() { ++*mCounter; mMagic = 0; }
+    int magic() const { return mMagic; }
+private:
+    int *mCounter;
+    int mMagic;
+};
+
+struct DerivedCounter : public EventCounter {
+    DerivedCounter(int *counter, int magic=1234) : EventCounter(counter, magic) { }
+};
+
+TEST_F(ADataTest, AUnion_Test) {
+    AUnion<int, const char *, char> u;
+    u.emplace<int>(4);
+    u.del<int>();
+    EXPECT_EQ(4, u.get<int>()); // verify that del<> is a no-op for trivial types, such as int.
+                                // specifically, verify that it does not clear the objet memory
+
+    u.emplace<const char *>("hello");
+    EXPECT_STREQ("hello", u.get<const char *>());
+    u.del<const char *>();
+
+    // u.del<char *>();
+    // u.emplace<const int>(4);
+    u.emplace<void>();
+    u.del<void>();
+
+    u.emplace<int>(~0);
+    u.del<int>();
+    EXPECT_EQ(~0, u.get<int>());
+    u.emplace<char>(0x15);
+    // verify that rest of memory after char is cleared upon construction
+    EXPECT_EQ(0, memcmp((char *)(&u) + sizeof(char), "\0\0\0", 3));
+    EXPECT_EQ(0x15, u.get<char>());
+    u.del<char>();
+
+    AUnion<EventCounter, EventCounter *> d;
+    int destructions = 0;
+
+    d.emplace<EventCounter>(&destructions);
+    d.del<EventCounter>();
+    EXPECT_EQ(1, destructions);
+
+    EventCounter *ctr = new EventCounter(&destructions);
+    d.emplace<EventCounter *>(ctr);
+    d.del<EventCounter *>();
+    EXPECT_EQ(1, destructions);
+
+    delete ctr;
+    EXPECT_EQ(2, destructions);
+
+    AUnion<std::shared_ptr<EventCounter>, std::unique_ptr<EventCounter>> md;
+    md.emplace<std::shared_ptr<EventCounter>>(new EventCounter(&destructions));
+    std::shared_ptr<EventCounter> copy(md.get<std::shared_ptr<EventCounter>>());
+    std::weak_ptr<EventCounter> weak(copy);
+    EXPECT_EQ(2, destructions);
+
+    copy.reset();
+    EXPECT_EQ(2, destructions);
+    md.del<std::shared_ptr<EventCounter>>();
+    EXPECT_EQ(3, destructions);
+    EXPECT_TRUE(weak.expired());
+
+    md.emplace<std::unique_ptr<EventCounter>>(new EventCounter(&destructions));
+    EXPECT_EQ(3, destructions);
+
+    std::unique_ptr<EventCounter> unique = std::move(md.get<std::unique_ptr<EventCounter>>());
+    EXPECT_EQ(3, destructions);
+    EXPECT_FALSE((bool)md.get<std::unique_ptr<EventCounter>>());
+
+    md.del<std::unique_ptr<EventCounter>>();
+    EXPECT_EQ(3, destructions);
+    md.emplace<std::unique_ptr<EventCounter>>(std::move(unique));
+    EXPECT_TRUE((bool)md.get<std::unique_ptr<EventCounter>>());
+    EXPECT_EQ(3, destructions);
+
+    md.del<std::unique_ptr<EventCounter>>();
+    EXPECT_EQ(4, destructions);
+}
+
+TEST_F(ADataTest, AData_StaticTest) {
+    using namespace std;
+
+    static_assert(is_copy_assignable<shared_ptr<EventCounter>>::value, "");
+    static_assert(is_copy_constructible<shared_ptr<EventCounter>>::value, "");
+    static_assert(is_default_constructible<shared_ptr<EventCounter>>::value, "");
+
+    static_assert(is_copy_assignable<weak_ptr<DerivedCounter>>::value, "");
+    static_assert(is_copy_constructible<weak_ptr<DerivedCounter>>::value, "");
+    static_assert(is_default_constructible<weak_ptr<DerivedCounter>>::value, "");
+
+    static_assert(!is_copy_assignable<unique_ptr<DerivedCounter>>::value, "");
+    static_assert(!is_copy_constructible<unique_ptr<DerivedCounter>>::value, "");
+    static_assert(is_default_constructible<unique_ptr<DerivedCounter>>::value, "");
+
+    static_assert(is_copy_assignable<sp<EventCounter>>::value, "");
+    static_assert(is_copy_constructible<sp<EventCounter>>::value, "");
+    static_assert(is_default_constructible<sp<EventCounter>>::value, "");
+
+    static_assert(is_copy_assignable<wp<EventCounter>>::value, "");
+    static_assert(is_copy_constructible<wp<EventCounter>>::value, "");
+    static_assert(is_default_constructible<wp<EventCounter>>::value, "");
+
+    static_assert(is_convertible<shared_ptr<DerivedCounter>, shared_ptr<EventCounter>>::value, "");
+    static_assert(!is_convertible<shared_ptr<EventCounter>, shared_ptr<DerivedCounter>>::value, "");
+
+    static_assert(is_convertible<unique_ptr<DerivedCounter>, unique_ptr<EventCounter>>::value, "");
+    static_assert(!is_convertible<unique_ptr<EventCounter>, unique_ptr<DerivedCounter>>::value, "");
+
+    static_assert(is_convertible<unique_ptr<DerivedCounter>, shared_ptr<EventCounter>>::value, "");
+    static_assert(!is_convertible<shared_ptr<DerivedCounter>, unique_ptr<EventCounter>>::value, "");
+
+    static_assert(is_convertible<weak_ptr<DerivedCounter>, weak_ptr<EventCounter>>::value, "");
+    static_assert(!is_convertible<weak_ptr<EventCounter>, weak_ptr<DerivedCounter>>::value, "");
+
+    static_assert(is_convertible<shared_ptr<DerivedCounter>, weak_ptr<EventCounter>>::value, "");
+    static_assert(!is_convertible<weak_ptr<DerivedCounter>, shared_ptr<EventCounter>>::value, "");
+
+    static_assert(is_convertible<sp<EventCounter>, sp<RefBase>>::value, "");
+    static_assert(is_convertible<sp<RefBase>, sp<EventCounter>>::value, "YES");
+
+    static_assert(is_convertible<wp<EventCounter>, wp<RefBase>>::value, "");
+    static_assert(is_convertible<wp<RefBase>, wp<EventCounter>>::value, "YES");
+
+    static_assert(is_convertible<sp<EventCounter>, wp<RefBase>>::value, "");
+    static_assert(!is_convertible<wp<EventCounter>, sp<RefBase>>::value, "");
+}
+
+TEST_F(ADataTest, AData_SampleTest) {
+    AData<int, float>::Basic data;
+    int i = 1;
+    float f = 7.0f;
+
+    data.set(5);
+    EXPECT_TRUE(data.find(&i));
+    EXPECT_FALSE(data.find(&f));
+    EXPECT_EQ(i, 5);
+
+    data.set(6.0f);
+    EXPECT_FALSE(data.find(&i));
+    EXPECT_TRUE(data.find(&f));
+    EXPECT_EQ(f, 6.0f);
+
+    AData<int, sp<RefBase>>::RelaxedBasic objdata; // relaxed type support
+    sp<ABuffer> buf = new ABuffer(16), buf2;
+    sp<RefBase> obj;
+
+    objdata.set(buf);
+    EXPECT_TRUE(objdata.find(&buf2));
+    EXPECT_EQ(buf, buf2);
+    EXPECT_FALSE(objdata.find(&i));
+    EXPECT_TRUE(objdata.find(&obj));
+    EXPECT_TRUE(obj == buf);
+
+    obj = buf;
+    objdata.set(obj); // storing as sp<RefBase>
+    EXPECT_FALSE(objdata.find(&buf2));  // not stored as ABuffer(!)
+    EXPECT_TRUE(objdata.find(&obj));
+}
+
+struct SampleTypeFlagger {
+    typedef unsigned type;
+    enum Flags : type {
+        kEmpty = 100,
+        kInt,
+        kConstCharPtr,
+        kEventCounter,
+        kEventCounterPointer,
+        kEventCounterSharedPointer,
+        kEventCounterUniquePointer,
+        kEventCounterWeakPointer,
+        kEventCounterSP,
+        kEventCounterWP,
+    };
+    constexpr static type mask = ~Flags(0);
+    constexpr static type flagFor(void*) { return kEmpty; }
+    constexpr static type flagFor(int*) { return kInt; }
+    constexpr static type flagFor(const char**) { return kConstCharPtr; }
+    constexpr static type flagFor(EventCounter*) { return kEventCounter; }
+    constexpr static type flagFor(EventCounter**) { return kEventCounterPointer; }
+    constexpr static
+    type flagFor(std::shared_ptr<EventCounter>*) { return kEventCounterSharedPointer; }
+    constexpr static
+    type flagFor(std::unique_ptr<EventCounter>*) { return kEventCounterUniquePointer; }
+    constexpr static type flagFor(std::weak_ptr<EventCounter>*) { return kEventCounterWeakPointer; }
+    constexpr static type flagFor(sp<EventCounter>*) { return kEventCounterSP; }
+    constexpr static type flagFor(wp<EventCounter>*) { return kEventCounterWP; }
+    constexpr static bool canDeleteAs(type object, type del) { return del == object; }
+    template <typename T> struct store { typedef T as_type; };
+};
+
+TEST_F(ADataTest, AData_SimpleTest) {
+    int _int = 0;
+    const char *_constCharPtr = NULL;
+    AData<int, const char *>::Custom<SampleTypeFlagger> u;
+    EXPECT_FALSE(u.used());
+    EXPECT_FALSE(u.find<int>(&_int));
+    EXPECT_FALSE(u.find<const char *>(&_constCharPtr));
+
+    EXPECT_TRUE(u.set<int>(4));
+    EXPECT_TRUE(u.used());
+    EXPECT_TRUE(u.find<int>(&_int));
+    EXPECT_EQ(4, _int);
+    EXPECT_FALSE(u.find<const char *>(&_constCharPtr));
+    EXPECT_EQ(NULL, _constCharPtr);
+
+    EXPECT_TRUE(u.clear());
+    EXPECT_FALSE(u.used());
+    EXPECT_FALSE(u.find<int>(&_int));
+    EXPECT_FALSE(u.find<const char *>(&_constCharPtr));
+
+    EXPECT_TRUE(u.set<int>(5));
+    EXPECT_TRUE(u.set<int>(6));
+    EXPECT_TRUE(u.find<int>(&_int));
+    EXPECT_EQ(6, _int);
+
+    EXPECT_TRUE(u.set<const char *>("hello"));
+    EXPECT_TRUE(u.used());
+    EXPECT_FALSE(u.find<int>(&_int));
+    EXPECT_TRUE(u.find<const char *>(&_constCharPtr));
+    EXPECT_STREQ("hello", _constCharPtr);
+
+    EXPECT_TRUE(u.clear());
+    EXPECT_FALSE(u.used());
+    EXPECT_FALSE(u.find<int>(&_int));
+    EXPECT_FALSE(u.find<const char *>(&_constCharPtr));
+
+    EXPECT_TRUE(u.set<const char *>("world"));
+    EXPECT_TRUE(u.set<const char *>("!!"));
+    EXPECT_TRUE(u.used());
+    EXPECT_FALSE(u.find<int>(&_int));
+    EXPECT_TRUE(u.find<const char *>(&_constCharPtr));
+    EXPECT_STREQ("!!", _constCharPtr);
+
+    EXPECT_FALSE(u.find(&_int));
+    EXPECT_TRUE(u.find(&_constCharPtr));
+}
+
+void set(std::unique_ptr<int> &dst, std::unique_ptr<int> &&src) {
+    dst = std::move(src);
+}
+
+void set(std::unique_ptr<int> &dst, std::unique_ptr<int> &src) {
+    dst = std::move(src);
+}
+
+TEST_F(ADataTest, AData_CopyMoveTest) {
+    int destructions = 0;
+    int _int = 0;
+    std::shared_ptr<EventCounter> _shared;
+    std::unique_ptr<EventCounter> _unique;
+    std::weak_ptr<EventCounter> _weak;
+    const std::shared_ptr<EventCounter> _constShared(new EventCounter(&destructions));
+    const std::unique_ptr<EventCounter> _constUnique = nullptr;
+
+    AData<int, std::weak_ptr<EventCounter>, std::shared_ptr<EventCounter>,
+            std::unique_ptr<EventCounter>>::Basic u;
+
+    // test that data is empty
+    EXPECT_FALSE(u.used());
+    EXPECT_FALSE(u.find(&_int));
+    EXPECT_FALSE(u.find(&_shared));
+    EXPECT_FALSE(u.remove(&_unique));
+    EXPECT_FALSE(u.find(&_weak));
+
+    // test that integer can be stored and read
+    EXPECT_TRUE(u.set<int>(1));
+    EXPECT_TRUE(u.used());
+    EXPECT_TRUE(u.find(&_int));
+    EXPECT_EQ(1, _int);
+    EXPECT_FALSE(u.find(&_shared));
+    EXPECT_FALSE(u.remove(&_unique));
+    EXPECT_FALSE(u.find(&_weak));
+
+    // test that movable type (unique_ptr) can be moved in and read out, and it moves
+    _unique = std::unique_ptr<EventCounter>(new EventCounter(&destructions, 123));
+    EXPECT_TRUE(u.set(std::move(_unique)));
+    EXPECT_FALSE((bool)_unique);
+    EXPECT_TRUE(u.used());
+    EXPECT_FALSE(u.find(&_int));
+    EXPECT_FALSE(u.find(&_shared));
+    EXPECT_FALSE(u.find(&_weak));
+    EXPECT_TRUE(u.remove(&_unique));
+    EXPECT_TRUE((bool)_unique);
+    if (_unique) {
+        EXPECT_EQ(123, _unique->magic());
+    }
+
+    // the unique value should have been removed but still accessible as nullptr
+    EXPECT_TRUE(u.remove(&_unique));
+    EXPECT_FALSE((bool)_unique);
+    EXPECT_EQ(1, destructions);
+
+    // test that movable-only type (unique_ptr) can be stored without moving (and is still
+    // moved)
+    _unique = std::unique_ptr<EventCounter>(new EventCounter(&destructions, 321));
+    EXPECT_TRUE(u.set(std::move(_unique)));
+    EXPECT_FALSE((bool)_unique);
+    EXPECT_TRUE(u.set(std::unique_ptr<EventCounter>(new EventCounter(&destructions, 1234))));
+    EXPECT_EQ(2, destructions);
+    EXPECT_TRUE(u.remove(&_unique));
+    EXPECT_TRUE((bool)_unique);
+    if (_unique) {
+        EXPECT_EQ(1234, _unique->magic());
+    }
+    EXPECT_TRUE(u.set(std::move(_unique)));
+    EXPECT_EQ(2, destructions);
+    EXPECT_TRUE(u.clear());
+    EXPECT_EQ(3, destructions);
+    EXPECT_FALSE(u.find(&_int));
+    EXPECT_FALSE(u.find(&_shared));
+    EXPECT_FALSE(u.remove(&_unique));
+    EXPECT_FALSE(u.find(&_weak));
+
+    // u.set(_constUnique);
+
+    // test that copiable & movable type (shared_ptr) is copied unless explicitly moved.
+    _shared = std::make_shared<EventCounter>(&destructions, 234);
+    EXPECT_EQ(1L, _shared.use_count());
+    EXPECT_TRUE(u.set(_shared));
+    EXPECT_TRUE((bool)_shared);
+    if (_shared) {
+        EXPECT_EQ(234, _shared->magic());
+    }
+
+    EXPECT_EQ(2L, _shared.use_count());
+    EXPECT_FALSE(u.find(&_int));
+    EXPECT_FALSE(u.remove(&_unique));
+    EXPECT_FALSE(u.find(&_weak));
+    EXPECT_TRUE(u.find(&_shared));
+    EXPECT_EQ(2L, _shared.use_count());
+    EXPECT_TRUE((bool)_shared);
+    if (_shared) {
+        EXPECT_EQ(234, _shared->magic());
+    }
+
+    // explicitly move in shared_ptr
+    EXPECT_TRUE(u.set(std::move(_shared)));
+    EXPECT_EQ(0, _shared.use_count()); // shared should be nullptr
+    EXPECT_FALSE((bool)_shared);
+    EXPECT_TRUE(u.find(&_shared));
+    EXPECT_EQ(2L, _shared.use_count()); // now both u and _shared contains the object
+    EXPECT_TRUE((bool)_shared);
+    if (_shared) {
+        EXPECT_EQ(234, _shared->magic());
+    }
+    EXPECT_FALSE(u.find(&_int));
+    EXPECT_FALSE(u.remove(&_unique));
+    EXPECT_FALSE(u.find(&_weak));
+    EXPECT_TRUE(u.find(&_shared));
+    EXPECT_EQ(2L, _shared.use_count()); // still both u and _shared contains the object
+
+    EXPECT_TRUE(u.clear());
+    EXPECT_TRUE(_shared.unique()); // now only _shared contains the object
+
+    EXPECT_TRUE(u.set(_constShared));
+    EXPECT_EQ(2L, _constShared.use_count()); // even though it is const, we can add a use count
+    EXPECT_TRUE(u.find(&_shared));
+    EXPECT_EQ(3L, _shared.use_count()); // now u, _shared and _constShared contains the const object
+    EXPECT_TRUE((bool)_shared);
+    if (_shared) {
+        EXPECT_EQ(1234, _shared->magic());
+    }
+
+    // test that weak pointer can be copied in (support for moving is from C++14 only)
+    _weak = _shared;
+    EXPECT_EQ(_weak.use_count(), _shared.use_count());
+    EXPECT_TRUE(u.set(_weak));
+
+    _weak.reset();
+    EXPECT_EQ(_weak.use_count(), 0);
+
+    EXPECT_FALSE(u.find(&_int));
+    EXPECT_FALSE(u.remove(&_unique));
+    EXPECT_FALSE(u.find(&_shared));
+    EXPECT_TRUE(u.find(&_weak));
+    EXPECT_EQ(_weak.use_count(), _shared.use_count());
+    EXPECT_EQ(_weak.lock(), _shared);
+
+    // we can remove a weak pointer multiple times
+    _weak.reset();
+    EXPECT_TRUE(u.find(&_weak));
+    EXPECT_EQ(_weak.use_count(), _shared.use_count());
+    EXPECT_EQ(_weak.lock(), _shared);
+    EXPECT_TRUE(u.clear());
+    EXPECT_FALSE(u.find(&_int));
+    EXPECT_FALSE(u.remove(&_unique));
+    EXPECT_FALSE(u.find(&_shared));
+    EXPECT_FALSE(u.find(&_weak));
+};
+
+TEST_F(ADataTest, AData_RelaxedCopyMoveTest) {
+    int destructions = 0;
+    int _int = 0;
+    std::shared_ptr<DerivedCounter> _shared;
+    std::unique_ptr<DerivedCounter> _unique, _unique2;
+    std::weak_ptr<DerivedCounter> _weak;
+    std::shared_ptr<EventCounter> _shared_base;
+    std::unique_ptr<EventCounter> _unique_base;
+    std::weak_ptr<EventCounter> _weak_base;
+    const std::shared_ptr<DerivedCounter> _constShared(new DerivedCounter(&destructions));
+    const std::unique_ptr<DerivedCounter> _constUnique = nullptr;
+
+    AData<int, std::unique_ptr<EventCounter>, std::shared_ptr<EventCounter>,
+            std::weak_ptr<EventCounter>>::RelaxedBasic u;
+
+    // test that data is empty
+    EXPECT_FALSE(u.used());
+    EXPECT_FALSE(u.find(&_int));
+    EXPECT_FALSE(u.find(&_shared));
+    EXPECT_FALSE(u.remove(&_unique));
+    EXPECT_FALSE(u.find(&_weak));
+    EXPECT_FALSE(u.find(&_shared_base));
+    EXPECT_FALSE(u.remove(&_unique_base));
+    EXPECT_FALSE(u.find(&_weak_base));
+
+    // test that integer can be stored and read
+    EXPECT_TRUE(u.set<int>(1));
+    EXPECT_TRUE(u.used());
+    EXPECT_TRUE(u.find(&_int));
+    EXPECT_EQ(1, _int);
+    EXPECT_FALSE(u.find(&_shared));
+    EXPECT_FALSE(u.remove(&_unique));
+    EXPECT_FALSE(u.find(&_weak));
+    EXPECT_FALSE(u.find(&_shared_base));
+    EXPECT_FALSE(u.remove(&_unique_base));
+    EXPECT_FALSE(u.find(&_weak_base));
+
+    // test that movable type (unique_ptr) can be moved in and read out, and it moves
+    _unique = std::unique_ptr<DerivedCounter>(new DerivedCounter(&destructions, 123));
+    EXPECT_TRUE(u.set(std::move(_unique)));
+    EXPECT_FALSE((bool)_unique);
+    EXPECT_TRUE(u.used());
+    EXPECT_FALSE(u.find(&_int));
+    EXPECT_FALSE(u.find(&_shared));
+    EXPECT_FALSE(u.find(&_weak));
+    EXPECT_TRUE(u.remove(&_unique));
+    EXPECT_TRUE((bool)_unique);
+    if (_unique) {
+        EXPECT_EQ(123, _unique->magic());
+    }
+
+    // the unique value should have been removed but still accessible as nullptr
+    EXPECT_TRUE(u.remove(&_unique));
+    EXPECT_FALSE((bool)_unique);
+    EXPECT_EQ(1, destructions);
+
+    EXPECT_FALSE(u.find(&_shared_base));
+    EXPECT_TRUE(u.remove(&_unique_base));
+    EXPECT_FALSE((bool)_unique_base);
+    EXPECT_FALSE(u.find(&_weak_base));
+
+    // test that movable-only type (unique_ptr) can be stored without moving (and is still
+    // moved)
+    _unique = std::unique_ptr<DerivedCounter>(new DerivedCounter(&destructions, 321));
+    EXPECT_TRUE(u.set(std::move(_unique)));
+    EXPECT_FALSE((bool)_unique);
+    EXPECT_TRUE(u.set(std::unique_ptr<DerivedCounter>(new DerivedCounter(&destructions, 1234))));
+    EXPECT_EQ(2, destructions);
+    EXPECT_TRUE(u.remove(&_unique));
+    EXPECT_TRUE((bool)_unique);
+    if (_unique) {
+        EXPECT_EQ(1234, _unique->magic());
+    }
+    EXPECT_TRUE(u.set(std::move(_unique)));
+    EXPECT_EQ(2, destructions);
+    EXPECT_TRUE(u.clear());
+    EXPECT_EQ(3, destructions);
+    EXPECT_FALSE(u.find(&_int));
+    EXPECT_FALSE(u.find(&_shared));
+    EXPECT_FALSE(u.remove(&_unique));
+    EXPECT_FALSE(u.find(&_weak));
+    EXPECT_FALSE(u.find(&_shared_base));
+    EXPECT_FALSE(u.remove(&_unique_base));
+    EXPECT_FALSE(u.find(&_weak_base));
+
+    // test that unique pointer can be set and removed as base type (but removed as derived only
+    // if it was set as derived type)
+    _unique = std::unique_ptr<DerivedCounter>(new DerivedCounter(&destructions, 321));
+    EXPECT_TRUE(u.set(std::move(_unique)));
+    EXPECT_FALSE((bool)_unique);
+    EXPECT_TRUE(u.remove(&_unique_base));
+    EXPECT_TRUE((bool)_unique_base);
+    if (_unique_base) {
+        EXPECT_EQ(321, _unique_base->magic());
+    }
+    EXPECT_TRUE(u.remove(&_unique));
+    EXPECT_FALSE((bool)_unique);
+
+    EXPECT_TRUE(u.set(std::move(_unique_base)));
+    EXPECT_FALSE((bool)_unique_base);
+    EXPECT_FALSE(u.remove(&_unique));
+    EXPECT_FALSE((bool)_unique);
+    EXPECT_TRUE(u.remove(&_unique_base));
+    EXPECT_TRUE((bool)_unique_base);
+    if (_unique_base) {
+        EXPECT_EQ(321, _unique_base->magic());
+    }
+
+    EXPECT_EQ(3, destructions);
+    EXPECT_TRUE(u.remove(&_unique_base));
+    EXPECT_EQ(4, destructions);
+    EXPECT_FALSE((bool)_unique_base);
+    EXPECT_FALSE(u.find(&_int));
+    EXPECT_FALSE(u.find(&_shared));
+    EXPECT_FALSE(u.find(&_shared_base));
+    EXPECT_FALSE(u.find(&_weak));
+    EXPECT_FALSE(u.find(&_weak_base));
+
+    // u.set(_constUnique);
+
+    // test that copiable & movable type (shared_ptr) is copied unless explicitly moved.
+    _shared = std::make_shared<DerivedCounter>(&destructions, 234);
+    EXPECT_EQ(1L, _shared.use_count());
+    EXPECT_TRUE(u.set(_shared));
+    EXPECT_TRUE((bool)_shared);
+    if (_shared) {
+        EXPECT_EQ(234, _shared->magic());
+    }
+
+    EXPECT_EQ(2L, _shared.use_count());
+    EXPECT_FALSE(u.find(&_int));
+    EXPECT_FALSE(u.remove(&_unique));
+    EXPECT_FALSE(u.find(&_weak));
+    EXPECT_TRUE(u.find(&_shared));
+    EXPECT_FALSE(u.remove(&_unique_base));
+    EXPECT_FALSE(u.find(&_weak_base));
+    EXPECT_EQ(2L, _shared.use_count());
+    EXPECT_TRUE((bool)_shared);
+    if (_shared) {
+        EXPECT_EQ(234, _shared->magic());
+    }
+
+    // explicitly move in shared_ptr
+    EXPECT_TRUE(u.set(std::move(_shared)));
+    EXPECT_EQ(0, _shared.use_count()); // shared should be nullptr
+    EXPECT_FALSE((bool)_shared);
+    EXPECT_TRUE(u.find(&_shared));
+    EXPECT_EQ(2L, _shared.use_count()); // now both u and _shared contains the object
+    EXPECT_TRUE((bool)_shared);
+    if (_shared) {
+        EXPECT_EQ(234, _shared->magic());
+    }
+    EXPECT_FALSE(u.find(&_int));
+    EXPECT_FALSE(u.remove(&_unique));
+    EXPECT_FALSE(u.find(&_weak));
+    EXPECT_FALSE(u.remove(&_unique_base));
+    EXPECT_FALSE(u.find(&_weak_base));
+    EXPECT_TRUE(u.find(&_shared));
+    EXPECT_EQ(2L, _shared.use_count()); // still both u and _shared contains the object
+
+    EXPECT_TRUE(u.clear());
+    EXPECT_TRUE(_shared.unique()); // now only _shared contains the object
+
+    EXPECT_TRUE(u.set(_constShared));
+    EXPECT_EQ(2L, _constShared.use_count()); // even though it is const, we can add a use count
+    EXPECT_TRUE(u.find(&_shared));
+    EXPECT_EQ(3L, _shared.use_count()); // now u, _shared and _constShared contains the const object
+    EXPECT_TRUE((bool)_shared);
+    if (_shared) {
+        EXPECT_EQ(1234, _shared->magic());
+    }
+
+    // test that shared pointer can be set and removed as base type (but removed as derived only
+    // if it was set as derived type)
+    EXPECT_TRUE(u.find(&_shared_base));
+    EXPECT_TRUE((bool)_shared_base);
+    if (_shared_base) {
+        EXPECT_EQ(1234, _shared_base->magic());
+    }
+    EXPECT_EQ(4L, _shared.use_count()); // now u, _shared, _constShared and _shared_base contains
+                                        // the const object
+    _shared.reset();
+    EXPECT_EQ(3L, _shared_base.use_count()); // now u, _constShared and _shared_base contains it
+    EXPECT_TRUE(u.clear());
+    EXPECT_EQ(2L, _shared_base.use_count()); // now _constShared and _shared_base contains it
+
+    EXPECT_TRUE(u.set(_shared_base));        // now u_ also contains it as base class
+    EXPECT_EQ(3L, _shared_base.use_count());
+    EXPECT_FALSE(u.find(&_shared)); // cannot get it as derived type
+    EXPECT_FALSE((bool)_shared);
+    _shared_base.reset();
+    EXPECT_TRUE(u.find(&_shared_base)); // can still get it as base type
+    EXPECT_TRUE((bool)_shared_base);
+    if (_shared_base) {
+        EXPECT_EQ(1234, _shared_base->magic());
+    }
+    _shared = std::static_pointer_cast<DerivedCounter>(_shared_base);
+    EXPECT_FALSE(u.find(&_int));
+    EXPECT_FALSE(u.remove(&_unique));
+    EXPECT_FALSE(u.remove(&_unique_base));
+    EXPECT_FALSE(u.find(&_weak));
+    EXPECT_FALSE(u.find(&_weak_base));
+
+    // test that weak pointer can be copied in (support for moving is from C++14 only)
+    _weak = _shared;
+    EXPECT_EQ(_weak.use_count(), _shared.use_count());
+    EXPECT_TRUE(u.set(_weak));
+
+    _weak.reset();
+    EXPECT_EQ(_weak.use_count(), 0);
+
+    EXPECT_FALSE(u.find(&_int));
+    EXPECT_FALSE(u.remove(&_unique));
+    EXPECT_FALSE(u.find(&_shared));
+    EXPECT_FALSE(u.remove(&_unique_base));
+    EXPECT_FALSE(u.find(&_shared_base));
+    EXPECT_TRUE(u.find(&_weak));
+    EXPECT_EQ(_weak.use_count(), _shared.use_count());
+    EXPECT_EQ(_weak.lock(), _shared);
+
+    // we can remove a weak pointer multiple times
+    _weak.reset();
+    EXPECT_TRUE(u.find(&_weak));
+    EXPECT_EQ(_weak.use_count(), _shared.use_count());
+    EXPECT_EQ(_weak.lock(), _shared);
+    EXPECT_TRUE(u.clear());
+    EXPECT_FALSE(u.find(&_int));
+    EXPECT_FALSE(u.remove(&_unique));
+    EXPECT_FALSE(u.find(&_shared));
+    EXPECT_FALSE(u.find(&_weak));
+    EXPECT_FALSE(u.remove(&_unique_base));
+    EXPECT_FALSE(u.find(&_shared_base));
+    EXPECT_FALSE(u.find(&_weak_base));
+
+    // test that weak pointer can be set and removed as base type (but removed as derived only
+    // if it was set as derived type)
+    _weak = _shared;
+    EXPECT_TRUE(u.set(_weak));
+    EXPECT_TRUE(u.find(&_weak_base));
+    EXPECT_FALSE(_weak_base.expired());
+    if (!_weak_base.expired()) {
+        EXPECT_EQ(1234, _weak_base.lock()->magic());
+    }
+    // now _shared, _constShared and _shared_base contains the const object
+    EXPECT_EQ(3L, _weak.use_count());
+    _weak.reset();
+    EXPECT_EQ(3L, _weak_base.use_count()); // _weak did not hold a reference
+    _shared.reset();
+    EXPECT_EQ(2L, _weak_base.use_count()); // now u, _constShared and _shared_base contains it
+    EXPECT_TRUE(u.clear());
+    EXPECT_FALSE(u.find(&_int));
+    EXPECT_FALSE(u.remove(&_unique));
+    EXPECT_FALSE(u.find(&_shared));
+    EXPECT_FALSE(u.find(&_weak));
+    EXPECT_FALSE(u.remove(&_unique_base));
+    EXPECT_FALSE(u.find(&_shared_base));
+    EXPECT_FALSE(u.find(&_weak_base));
+
+    EXPECT_TRUE(u.set(_weak_base)); // now u_ also contains it as base class
+    EXPECT_FALSE(u.find(&_weak));   // cannot get it as derived type
+    EXPECT_TRUE(_weak.expired());
+    _weak_base.reset();
+    EXPECT_TRUE(u.find(&_weak_base)); // can still get it as base type
+    EXPECT_FALSE(_weak_base.expired());
+    if (!_weak_base.expired()) {
+        EXPECT_EQ(1234, _weak_base.lock()->magic());
+    }
+};
+
+TEST_F(ADataTest, AData_AndroidSpTest) {
+    int destructions = 0;
+    int _int = 0;
+    sp<EventCounter> _shared;
+    wp<EventCounter> _weak;
+    const sp<EventCounter> _constShared(new EventCounter(&destructions));
+
+    AData<int, sp<EventCounter>, wp<EventCounter>>::Strict<uint8_t> u;
+
+    // test that data is empty
+    EXPECT_FALSE(u.used());
+    EXPECT_FALSE(u.find(&_int));
+    EXPECT_FALSE(u.find(&_shared));
+    EXPECT_FALSE(u.find(&_weak));
+
+    // test that integer can be stored and read
+    EXPECT_TRUE(u.set<int>(1));
+    EXPECT_TRUE(u.used());
+    EXPECT_TRUE(u.find(&_int));
+    EXPECT_EQ(1, _int);
+    EXPECT_FALSE(u.find(&_shared));
+    EXPECT_FALSE(u.find(&_weak));
+
+    // test that copiable & movable type (shared_ptr) is copied unless explicitly moved.
+    _shared = new EventCounter(&destructions, 234);
+    _weak = _shared; // used for tracking #234
+
+    EXPECT_TRUE(u.set(_shared));
+    EXPECT_TRUE((bool)_shared.get());
+    if (_shared.get()) {
+        EXPECT_EQ(234, _shared->magic());
+    }
+
+    _shared.clear();
+    EXPECT_EQ(NULL, _shared.get());
+    EXPECT_NE(nullptr, _weak.promote().get()); // u still holds object
+
+    EXPECT_FALSE(u.find(&_int));
+    EXPECT_FALSE(u.find(&_weak));
+    EXPECT_TRUE(u.find(&_shared)); // now u and _shared both hold object
+    EXPECT_TRUE((bool)_shared.get());
+    if (_shared.get()) {
+        EXPECT_EQ(234, _shared->magic());
+    }
+    // verify the find did not move out object
+    _shared.clear();
+    EXPECT_EQ(NULL, _shared.get());
+    EXPECT_NE(nullptr, _weak.promote().get()); // u still holds object
+    EXPECT_TRUE(u.find(&_shared)); // now u and _shared both hold object
+    if (_shared.get()) {
+        EXPECT_EQ(234, _shared->magic());
+    }
+
+    // verify that we can set object multiple times
+    EXPECT_TRUE(u.set(_shared));
+
+    // explicitly move in sp
+    EXPECT_TRUE(u.set(std::move(_shared)));
+    EXPECT_FALSE((bool)_shared.get()); // android also clears sp<> on move...
+    EXPECT_TRUE(u.find(&_shared)); // still can get it back
+    EXPECT_TRUE((bool)_shared.get());
+    if (_shared.get()) {
+        EXPECT_EQ(234, _shared->magic());
+    }
+    EXPECT_FALSE(u.find(&_int));
+    EXPECT_FALSE(u.find(&_weak));
+
+    EXPECT_TRUE(u.used());
+    EXPECT_TRUE(u.clear()); // now only _shared contains the object
+    EXPECT_FALSE(u.used());
+
+    // we still hold a copy
+    EXPECT_TRUE((bool)_shared.get());
+    EXPECT_FALSE(u.find(&_int));
+    EXPECT_FALSE(u.find(&_shared)); // _shared still contains the object
+
+    EXPECT_TRUE(u.set(_constShared));
+    EXPECT_TRUE(u.find(&_shared)); // now _shared contains _constShared
+    EXPECT_EQ(NULL, _weak.promote().get()); // original _shared is now lost
+
+    EXPECT_TRUE((bool)_shared.get());
+    if (_shared.get()) {
+        EXPECT_EQ(1234, _shared->magic());
+    }
+    EXPECT_TRUE(u.clear());
+
+    // test that wp can be copied in
+    _weak = _shared;
+    EXPECT_TRUE(u.set(_weak));
+
+    _weak.clear();
+
+    EXPECT_FALSE(u.find(&_int));
+    EXPECT_FALSE(u.find(&_shared));
+    EXPECT_TRUE(u.find(&_weak));
+    EXPECT_EQ(_weak.promote(), _shared);
+
+    // we can remove a weak pointer multiple times
+    _weak.clear();
+    EXPECT_TRUE(u.find(&_weak));
+    EXPECT_EQ(_weak.promote(), _shared);
+    EXPECT_TRUE(u.clear());
+    EXPECT_FALSE(u.find(&_int));
+    EXPECT_FALSE(u.find(&_shared));
+    EXPECT_FALSE(u.find(&_weak));
+};
+
+TEST_F(ADataTest, AData_RelaxedAndroidSpTest) {
+    int destructions = 0;
+    int _int = 0;
+    sp<EventCounter> _shared;
+    wp<EventCounter> _weak;
+    sp<RefBase> _shared_base;
+    wp<RefBase> _weak_base;
+    const sp<EventCounter> _constShared(new EventCounter(&destructions));
+
+    AData<int, sp<RefBase>, wp<RefBase>>::Relaxed<uint16_t> u;
+
+    // test that data is empty
+    EXPECT_FALSE(u.used());
+    EXPECT_FALSE(u.find(&_int));
+    EXPECT_FALSE(u.find(&_shared));
+    EXPECT_FALSE(u.find(&_weak));
+    EXPECT_FALSE(u.find(&_shared_base));
+    EXPECT_FALSE(u.find(&_weak_base));
+
+    // test that integer can be stored and read
+    EXPECT_TRUE(u.set<int>(1));
+    EXPECT_TRUE(u.used());
+    EXPECT_TRUE(u.find(&_int));
+    EXPECT_EQ(1, _int);
+    EXPECT_FALSE(u.find(&_shared));
+    EXPECT_FALSE(u.find(&_weak));
+    EXPECT_FALSE(u.find(&_shared_base));
+    EXPECT_FALSE(u.find(&_weak_base));
+
+    // test that copiable & movable type (shared_ptr) is copied unless explicitly moved.
+    _shared = new EventCounter(&destructions, 234);
+    _weak = _shared; // used for tracking #234
+
+    EXPECT_TRUE(u.set(_shared));
+    EXPECT_TRUE((bool)_shared.get());
+    if (_shared.get()) {
+        EXPECT_EQ(234, _shared->magic());
+    }
+
+    _shared.clear();
+    EXPECT_EQ(NULL, _shared.get());
+    EXPECT_NE(nullptr, _weak.promote().get()); // u still holds object
+
+    EXPECT_FALSE(u.find(&_int));
+    EXPECT_TRUE(u.find(&_shared)); // now u and _shared both hold object
+    EXPECT_TRUE((bool)_shared.get());
+    if (_shared.get()) {
+        EXPECT_EQ(234, _shared->magic());
+    }
+    // verify the find did not move out object
+    _shared.clear();
+    EXPECT_EQ(NULL, _shared.get());
+    EXPECT_NE(nullptr, _weak.promote().get()); // u still holds object
+    EXPECT_TRUE(u.find(&_shared)); // now u and _shared both hold object
+    if (_shared.get()) {
+        EXPECT_EQ(234, _shared->magic());
+    }
+
+    // verify that we can set object multiple times
+    EXPECT_TRUE(u.set(_shared));
+
+    // explicitly move in sp
+    EXPECT_TRUE(u.set(std::move(_shared)));
+    EXPECT_FALSE((bool)_shared.get()); // android also clears sp<> on move...
+    EXPECT_TRUE(u.find(&_shared)); // still can get it back
+    EXPECT_TRUE((bool)_shared.get());
+    if (_shared.get()) {
+        EXPECT_EQ(234, _shared->magic());
+    }
+    EXPECT_FALSE(u.find(&_int));
+    EXPECT_FALSE(u.find(&_weak));
+    EXPECT_FALSE(u.find(&_weak_base));
+
+    EXPECT_TRUE(u.used());
+    EXPECT_TRUE(u.clear()); // now only _shared contains the object
+    EXPECT_FALSE(u.used());
+
+    // we still hold a copy
+    EXPECT_TRUE((bool)_shared.get());
+    EXPECT_FALSE(u.find(&_int));
+    EXPECT_FALSE(u.find(&_shared)); // _shared still contains the object
+
+    EXPECT_TRUE(u.set(_constShared));
+    EXPECT_TRUE(u.find(&_shared)); // now _shared contains _constShared
+    EXPECT_EQ(NULL, _weak.promote().get()); // original _shared is now lost
+
+    EXPECT_TRUE((bool)_shared.get());
+    if (_shared.get()) {
+        EXPECT_EQ(1234, _shared->magic());
+    }
+    EXPECT_TRUE(u.clear());
+
+    // test that shared pointer can be set and removed as base type (but removed as derived only
+    // if it was set as derived type)
+    EXPECT_TRUE(u.set(_constShared));
+    EXPECT_TRUE(u.find(&_shared_base));
+    EXPECT_TRUE((bool)_shared_base.get());
+    if (_shared_base.get()) {
+        EXPECT_EQ(1234, static_cast<EventCounter*>(_shared_base.get())->magic());
+    }
+    _shared.clear();
+    EXPECT_TRUE(u.clear());
+    EXPECT_TRUE((bool)_shared_base.get());
+    if (_shared_base.get()) {
+        EXPECT_EQ(1234, static_cast<EventCounter*>(_shared_base.get())->magic());
+    }
+
+    EXPECT_TRUE(u.set(_shared_base)); // now u contains it as base class
+    EXPECT_TRUE((bool)_shared_base.get());
+    EXPECT_FALSE(u.find(&_shared)); // cannot get it as derived type
+    EXPECT_FALSE((bool)_shared.get());
+    _shared_base.clear();
+    EXPECT_TRUE(u.find(&_shared_base)); // can still get it as base type
+    EXPECT_TRUE((bool)_shared_base.get());
+    if (_shared_base.get()) {
+        EXPECT_EQ(1234, static_cast<EventCounter*>(_shared_base.get())->magic());
+    }
+    _shared = static_cast<DerivedCounter*>(_shared_base.get());
+    EXPECT_FALSE(u.find(&_int));
+    EXPECT_FALSE(u.find(&_weak));
+    EXPECT_FALSE(u.find(&_weak_base));
+
+    // test that wp can be copied in
+    _weak = _shared;
+    EXPECT_TRUE(u.set(_weak));
+
+    _weak.clear();
+
+    EXPECT_FALSE(u.find(&_int));
+    EXPECT_FALSE(u.find(&_shared));
+    EXPECT_FALSE(u.find(&_shared_base));
+    EXPECT_TRUE(u.find(&_weak));
+    EXPECT_EQ(_weak.promote(), _shared);
+
+    // we can remove a weak pointer multiple times
+    _weak.clear();
+    EXPECT_TRUE(u.find(&_weak));
+    EXPECT_EQ(_weak.promote(), _shared);
+    EXPECT_TRUE(u.clear());
+    EXPECT_FALSE(u.find(&_int));
+    EXPECT_FALSE(u.find(&_shared));
+    EXPECT_FALSE(u.find(&_weak));
+    EXPECT_FALSE(u.find(&_shared_base));
+    EXPECT_FALSE(u.find(&_weak_base));
+
+    // test that weak pointer can be set and removed as base type (but removed as derived only
+    // if it was set as derived type)
+    _weak = _shared;
+    EXPECT_TRUE(u.set(_weak));
+    EXPECT_TRUE(u.find(&_weak_base));
+    EXPECT_TRUE(_weak_base.promote().get() == _shared.get());
+
+    _weak.clear();
+    _shared.clear();
+    EXPECT_TRUE(u.clear());
+    EXPECT_FALSE(u.find(&_int));
+    EXPECT_FALSE(u.find(&_shared));
+    EXPECT_FALSE(u.find(&_weak));
+    EXPECT_FALSE(u.find(&_shared_base));
+    EXPECT_FALSE(u.find(&_weak_base));
+
+    EXPECT_TRUE(u.set(_weak_base)); // now u_ also contains it as base class
+    EXPECT_FALSE(u.find(&_weak));   // cannot get it as derived type
+    EXPECT_FALSE(_weak.promote().get());
+    _weak_base.clear();
+    EXPECT_TRUE(u.find(&_weak_base)); // can still get it as base type
+    EXPECT_TRUE(_weak_base.promote().get());
+    if (_weak_base.promote().get()) {
+        EXPECT_EQ(1234, static_cast<EventCounter*>(_weak_base.promote().get())->magic());
+    }
+};
+
+} // namespace android
diff --git a/media/libstagefright/foundation/tests/Android.mk b/media/libstagefright/foundation/tests/Android.mk
index e7598ca..d741c6f 100644
--- a/media/libstagefright/foundation/tests/Android.mk
+++ b/media/libstagefright/foundation/tests/Android.mk
@@ -8,12 +8,14 @@
 LOCAL_MODULE_TAGS := tests
 
 LOCAL_SRC_FILES := \
+	AData_test.cpp \
 	Flagged_test.cpp \
 	TypeTraits_test.cpp \
 	Utils_test.cpp \
 
 LOCAL_SHARED_LIBRARIES := \
 	libstagefright_foundation \
+	libutils \
 
 LOCAL_C_INCLUDES := \
 	frameworks/av/include \
diff --git a/media/libstagefright/foundation/tests/TypeTraits_test.cpp b/media/libstagefright/foundation/tests/TypeTraits_test.cpp
index 9fba435..1e2049d 100644
--- a/media/libstagefright/foundation/tests/TypeTraits_test.cpp
+++ b/media/libstagefright/foundation/tests/TypeTraits_test.cpp
@@ -32,6 +32,9 @@
 
 // =========== basic sanity tests for type-support templates
 TEST_F(TypeTraitsTest, StaticTests) {
+
+    // ============ is_integral_or_enum
+
     static_assert(!std::is_integral<A>::value, "enums should not be integral");
     static_assert(!std::is_integral<UA>::value, "enums should not be integral");
     static_assert(!std::is_integral<IA>::value, "enums should not be integral");
@@ -42,6 +45,8 @@
     static_assert(is_integral_or_enum<unsigned>::value, "unsigned ints should be integral_or_enum");
     static_assert(!is_integral_or_enum<float>::value, "floats should not be integral_or_enum");
 
+    // ============ is_unsigned_integral
+
     static_assert(!std::is_unsigned<UA>::value,
                   "unsigned enums should not be unsigned");
     static_assert(!std::is_unsigned<IA>::value,
@@ -61,6 +66,8 @@
     static_assert(!is_unsigned_integral<float>::value,
                   "floats should not be unsigned_integral");
 
+    // ============ is_signed_integral
+
     static_assert(!std::is_signed<UA>::value,
                   "unsigned enums should not be signed");
     static_assert(!std::is_signed<IA>::value,
@@ -80,6 +87,8 @@
     static_assert(!is_signed_integral<float>::value,
                   "floats should not be signed_integral");
 
+    // ============ underlying_integral_type
+
     static_assert(std::is_same<uint64_t, typename underlying_integral_type<uint64_t>::type>::value,
                   "underlying integral type of uint64_t should be uint64_t");
     static_assert(std::is_same<uint32_t, typename underlying_integral_type<UA>::type>::value,
@@ -91,6 +100,68 @@
     //typedef underlying_integral_type<float>::type no_type;
     static_assert(std::is_same<void, typename underlying_integral_type<float, void>::type>::value,
                   "underlying integral type of float cannot be specified");
+
+    // ============ is_one_of
+
+    static_assert(!is_one_of<int>::value, "int shouldn't be one of {}");
+    static_assert(!is_one_of<int, unsigned>::value, "int shouldn't be one of {unsigned}");
+    static_assert(!is_one_of<int, unsigned, float>::value,
+                  "int shouldn't be one of {unsigned, float}");
+    static_assert(is_one_of<int, int>::value, "int should be one of {int}");
+    static_assert(is_one_of<int, int, float>::value, "int should be one of {int, float}");
+    static_assert(is_one_of<int, float, int>::value, "int should be one of {float, int}");
+    static_assert(is_one_of<int, float, int, unsigned>::value,
+                  "int should be one of {float, int, unsigned}");
+    static_assert(is_one_of<int, float, unsigned, int>::value,
+                  "int should be one of {float, unsigned, int}");
+    static_assert(!is_one_of<int, int&>::value, "int shouldn't be one of {int&}");
+
+    // ============ are_unique
+
+    static_assert(are_unique<>::value, "{} should be unique");
+    static_assert(are_unique<int>::value, "{int} should be unique");
+    static_assert(are_unique<int, float>::value, "{int, float} should be unique");
+    static_assert(!are_unique<int, int>::value, "{int, int} shouldn't be unique");
+    static_assert(!are_unique<int, float, int>::value, "{int, float, int} shouldn't be unique");
+    static_assert(!are_unique<float, int, int>::value, "{float, int, int} shouldn't be unique");
+    static_assert(!are_unique<int, int, float>::value, "{int, int, float} shouldn't be unique");
+
+    // ============ find_first
+
+    static_assert(find_first<int>::index == 0, "int is not in {}");
+    static_assert(find_first<int, unsigned>::index == 0, "int is not in {unsigned}");
+    static_assert(find_first<int, unsigned, float>::index == 0, "int is not in {unsigned, float}");
+    static_assert(find_first<int, int>::index == 1, "int is 1st in {int}");
+    static_assert(find_first<int, int, float>::index == 1, "int is 1st in {int, float}");
+    static_assert(find_first<int, float, int>::index == 2, "int is 2nd in {float, int}");
+    static_assert(find_first<int, float, int, unsigned>::index == 2,
+                  "int is 2nd in {float, int, unsigned}");
+    static_assert(find_first<int, float, int, unsigned>::index == 2,
+                  "int is 2nd and 3rd in {float, int, int, unsigned}");
+    static_assert(find_first<int, float, unsigned, int>::index == 3,
+                  "int is 3rd in {float, unsigned, int}");
+    static_assert(find_first<int, int&>::index == 0, "int is not in {int&}");
+
+    // ============ find_first_convertible_to
+
+    static_assert(find_first_convertible_to<int>::index == 0, "int is not convertible to {}");
+    static_assert(find_first_convertible_to<int, unsigned*>::index == 0,
+                  "int is not convertible to {unsigned*}");
+    static_assert(find_first_convertible_to<int, unsigned*, float&>::index == 0,
+                  "int is not convertible to {unsigned, float&}");
+    static_assert(find_first_convertible_to<int, int>::index == 1, "int is convertible to {int}");
+    static_assert(find_first_convertible_to<int, unsigned, int>::index == 1,
+                  "int is convertible to 1st of {unsigned, int}");
+    static_assert(find_first_convertible_to<int, int&, float>::index == 2,
+                  "int is convertible to 2nd of {int&, float}");
+    static_assert(find_first_convertible_to<float, float*, int, unsigned>::index == 2,
+                  "float is convertible to 2nd of {float*, int, unsigned}");
+    static_assert(find_first_convertible_to<float, void, float[1], int>::index == 3,
+                  "int is 3rd convertible to {void, float[], int}");
+    static_assert(find_first_convertible_to<int&, const int&>::index == 1,
+                  "int& is convertible to {const int&}");
+    static_assert(find_first_convertible_to<const int&, int&>::index == 0,
+                  "const int& is not convertible to {int&}");
 }
 
 } // namespace android
diff --git a/media/libstagefright/id3/testid3.cpp b/media/libstagefright/id3/testid3.cpp
index b2f4188..442a3ff 100644
--- a/media/libstagefright/id3/testid3.cpp
+++ b/media/libstagefright/id3/testid3.cpp
@@ -154,8 +154,6 @@
 int main(int argc, char **argv) {
     android::ProcessState::self()->startThreadPool();
 
-    DataSource::RegisterDefaultSniffers();
-
     for (int i = 1; i < argc; ++i) {
         scan(argv[i]);
     }
diff --git a/media/libstagefright/include/ACodecBufferChannel.h b/media/libstagefright/include/ACodecBufferChannel.h
new file mode 100644
index 0000000..d52ce53
--- /dev/null
+++ b/media/libstagefright/include/ACodecBufferChannel.h
@@ -0,0 +1,132 @@
+/*
+ * 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 A_BUFFER_CHANNEL_H_
+
+#define A_BUFFER_CHANNEL_H_
+
+#include <map>
+#include <memory>
+#include <mutex>
+#include <vector>
+
+#include <media/openmax/OMX_Types.h>
+#include <media/stagefright/CodecBase.h>
+#include <media/ICrypto.h>
+#include <media/IOMX.h>
+
+namespace android {
+
+/**
+ * BufferChannelBase implementation for ACodec.
+ */
+class ACodecBufferChannel : public BufferChannelBase {
+public:
+    struct BufferAndId {
+        sp<MediaCodecBuffer> mBuffer;
+        IOMX::buffer_id mBufferId;
+    };
+
+    struct BufferInfo {
+        BufferInfo(
+                const sp<MediaCodecBuffer> &buffer,
+                IOMX::buffer_id bufferId,
+                const sp<IMemory> &sharedEncryptedBuffer);
+
+        BufferInfo() = delete;
+
+        // Buffer facing MediaCodec and its clients.
+        const sp<MediaCodecBuffer> mClientBuffer;
+        // Buffer facing CodecBase.
+        const sp<MediaCodecBuffer> mCodecBuffer;
+        // OMX buffer ID.
+        const IOMX::buffer_id mBufferId;
+        // Encrypted buffer in case of secure input.
+        const sp<IMemory> mSharedEncryptedBuffer;
+    };
+
+    ACodecBufferChannel(
+            const sp<AMessage> &inputBufferFilled, const sp<AMessage> &outputBufferDrained);
+    virtual ~ACodecBufferChannel() = default;
+
+    // BufferChannelBase interface
+    virtual status_t queueInputBuffer(const sp<MediaCodecBuffer> &buffer) override;
+    virtual status_t queueSecureInputBuffer(
+            const sp<MediaCodecBuffer> &buffer,
+            bool secure,
+            const uint8_t *key,
+            const uint8_t *iv,
+            CryptoPlugin::Mode mode,
+            CryptoPlugin::Pattern pattern,
+            const CryptoPlugin::SubSample *subSamples,
+            size_t numSubSamples,
+            AString *errorDetailMsg) override;
+    virtual status_t renderOutputBuffer(
+            const sp<MediaCodecBuffer> &buffer, int64_t timestampNs) override;
+    virtual status_t discardBuffer(const sp<MediaCodecBuffer> &buffer) override;
+    virtual void getInputBufferArray(Vector<sp<MediaCodecBuffer>> *array) override;
+    virtual void getOutputBufferArray(Vector<sp<MediaCodecBuffer>> *array) override;
+
+    // Methods below are interface for ACodec to use.
+
+    /**
+     * Set input buffer array.
+     *
+     * @param array     Newly allocated buffers. Empty if buffers are
+     *                  deallocated.
+     */
+    void setInputBufferArray(const std::vector<BufferAndId> &array);
+    /**
+     * Set output buffer array.
+     *
+     * @param array     Newly allocated buffers. Empty if buffers are
+     *                  deallocated.
+     */
+    void setOutputBufferArray(const std::vector<BufferAndId> &array);
+    /**
+     * Request MediaCodec to fill the specified input buffer.
+     *
+     * @param bufferId  ID of the buffer, assigned by underlying component.
+     */
+    void fillThisBuffer(IOMX::buffer_id bufferID);
+    /**
+     * Request MediaCodec to drain the specified output buffer.
+     *
+     * @param bufferId  ID of the buffer, assigned by underlying component.
+     * @param omxFlags  flags associated with this buffer (e.g. EOS).
+     */
+    void drainThisBuffer(IOMX::buffer_id bufferID, OMX_U32 omxFlags);
+
+private:
+    const sp<AMessage> mInputBufferFilled;
+    const sp<AMessage> mOutputBufferDrained;
+
+    sp<MemoryDealer> mDealer;
+
+    // These should only be accessed via std::atomic_* functions.
+    //
+    // Note on thread safety: since the vector and BufferInfo are const, it's
+    // safe to read them at any thread once the shared_ptr object is atomically
+    // obtained. Inside BufferInfo, mBufferId and mSharedEncryptedBuffer are
+    // immutable objects. We write internal states of mClient/CodecBuffer when
+    // the caller has given up the reference, so that access is also safe.
+    std::shared_ptr<const std::vector<const BufferInfo>> mInputBuffers;
+    std::shared_ptr<const std::vector<const BufferInfo>> mOutputBuffers;
+};
+
+}  // namespace android
+
+#endif  // A_BUFFER_CHANNEL_H_
diff --git a/media/libstagefright/include/MPEG2TSExtractor.h b/media/libstagefright/include/MPEG2TSExtractor.h
index 93e9a4b..ef55620 100644
--- a/media/libstagefright/include/MPEG2TSExtractor.h
+++ b/media/libstagefright/include/MPEG2TSExtractor.h
@@ -89,6 +89,8 @@
     // Add a SynPoint derived from |event|.
     void addSyncPoint_l(const ATSParser::SyncEvent &event);
 
+    status_t  estimateDurationsFromTimesUsAtEnd();
+
     DISALLOW_EVIL_CONSTRUCTORS(MPEG2TSExtractor);
 };
 
diff --git a/media/libstagefright/include/OMX.h b/media/libstagefright/include/OMX.h
index 9edd0de..5b22a2f 100644
--- a/media/libstagefright/include/OMX.h
+++ b/media/libstagefright/include/OMX.h
@@ -21,12 +21,15 @@
 #include <utils/threads.h>
 #include <utils/KeyedVector.h>
 
+#include "OmxNodeOwner.h"
+
 namespace android {
 
 struct OMXMaster;
 struct OMXNodeInstance;
 
 class OMX : public BnOMX,
+            public OmxNodeOwner,
             public IBinder::DeathRecipient {
 public:
     OMX();
@@ -43,7 +46,7 @@
 
     virtual void binderDied(const wp<IBinder> &the_late_who);
 
-    status_t freeNode(const sp<OMXNodeInstance>& instance);
+    virtual status_t freeNode(const sp<OMXNodeInstance>& instance);
 
 protected:
     virtual ~OMX();
diff --git a/media/libstagefright/include/OMXNodeInstance.h b/media/libstagefright/include/OMXNodeInstance.h
index ab12a86..ca24c2f 100644
--- a/media/libstagefright/include/OMXNodeInstance.h
+++ b/media/libstagefright/include/OMXNodeInstance.h
@@ -18,11 +18,12 @@
 
 #define OMX_NODE_INSTANCE_H_
 
-#include "OMX.h"
-
+#include <media/IOMX.h>
 #include <utils/RefBase.h>
-#include <utils/SortedVector.h>
 #include <utils/threads.h>
+#include <utils/KeyedVector.h>
+#include <utils/SortedVector.h>
+#include "OmxNodeOwner.h"
 
 namespace android {
 class IOMXBufferSource;
@@ -32,7 +33,7 @@
 
 struct OMXNodeInstance : public BnOMXNode {
     OMXNodeInstance(
-            OMX *owner, const sp<IOMXObserver> &observer, const char *name);
+            OmxNodeOwner *owner, const sp<IOMXObserver> &observer, const char *name);
 
     void setHandle(OMX_HANDLETYPE handle);
 
@@ -66,7 +67,7 @@
             const sp<IOMXBufferSource> &bufferSource);
 
     status_t allocateSecureBuffer(
-            OMX_U32 portIndex, size_t size, OMX::buffer_id *buffer,
+            OMX_U32 portIndex, size_t size, IOMX::buffer_id *buffer,
             void **buffer_data, sp<NativeHandle> *native_handle);
 
     status_t useBuffer(
@@ -106,7 +107,7 @@
 
     Mutex mLock;
 
-    OMX *mOwner;
+    OmxNodeOwner *mOwner;
     OMX_HANDLETYPE mHandle;
     sp<IOMXObserver> mObserver;
     sp<CallbackDispatcher> mDispatcher;
@@ -125,14 +126,14 @@
 
     struct ActiveBuffer {
         OMX_U32 mPortIndex;
-        OMX::buffer_id mID;
+        IOMX::buffer_id mID;
     };
     Vector<ActiveBuffer> mActiveBuffers;
     // for buffer ptr to buffer id translation
     Mutex mBufferIDLock;
     uint32_t mBufferIDCount;
-    KeyedVector<OMX::buffer_id, OMX_BUFFERHEADERTYPE *> mBufferIDToBufferHeader;
-    KeyedVector<OMX_BUFFERHEADERTYPE *, OMX::buffer_id> mBufferHeaderToBufferID;
+    KeyedVector<IOMX::buffer_id, OMX_BUFFERHEADERTYPE *> mBufferIDToBufferHeader;
+    KeyedVector<OMX_BUFFERHEADERTYPE *, IOMX::buffer_id> mBufferHeaderToBufferID;
 
     bool mLegacyAdaptiveExperiment;
     IOMX::PortMode mPortMode[2];
@@ -167,45 +168,45 @@
 
     ~OMXNodeInstance();
 
-    void addActiveBuffer(OMX_U32 portIndex, OMX::buffer_id id);
-    void removeActiveBuffer(OMX_U32 portIndex, OMX::buffer_id id);
+    void addActiveBuffer(OMX_U32 portIndex, IOMX::buffer_id id);
+    void removeActiveBuffer(OMX_U32 portIndex, IOMX::buffer_id id);
     void freeActiveBuffers();
 
     // For buffer id management
-    OMX::buffer_id makeBufferID(OMX_BUFFERHEADERTYPE *bufferHeader);
-    OMX_BUFFERHEADERTYPE *findBufferHeader(OMX::buffer_id buffer, OMX_U32 portIndex);
-    OMX::buffer_id findBufferID(OMX_BUFFERHEADERTYPE *bufferHeader);
-    void invalidateBufferID(OMX::buffer_id buffer);
+    IOMX::buffer_id makeBufferID(OMX_BUFFERHEADERTYPE *bufferHeader);
+    OMX_BUFFERHEADERTYPE *findBufferHeader(IOMX::buffer_id buffer, OMX_U32 portIndex);
+    IOMX::buffer_id findBufferID(OMX_BUFFERHEADERTYPE *bufferHeader);
+    void invalidateBufferID(IOMX::buffer_id buffer);
 
     bool isProhibitedIndex_l(OMX_INDEXTYPE index);
 
     status_t useBuffer_l(
             OMX_U32 portIndex, const sp<IMemory> &params,
-            OMX::buffer_id *buffer);
+            IOMX::buffer_id *buffer);
 
     status_t useGraphicBuffer_l(
             OMX_U32 portIndex, const sp<GraphicBuffer> &graphicBuffer,
-            OMX::buffer_id *buffer);
+            IOMX::buffer_id *buffer);
 
     status_t useGraphicBufferWithMetadata_l(
             OMX_U32 portIndex, const sp<GraphicBuffer> &graphicBuffer,
-            OMX::buffer_id *buffer);
+            IOMX::buffer_id *buffer);
 
     status_t useGraphicBuffer2_l(
             OMX_U32 portIndex, const sp<GraphicBuffer> &graphicBuffer,
-            OMX::buffer_id *buffer);
+            IOMX::buffer_id *buffer);
 
     status_t emptyBuffer_l(
-            OMX::buffer_id buffer,
+            IOMX::buffer_id buffer,
             OMX_U32 rangeOffset, OMX_U32 rangeLength,
             OMX_U32 flags, OMX_TICKS timestamp, int fenceFd);
 
     status_t emptyGraphicBuffer_l(
-            OMX::buffer_id buffer, const sp<GraphicBuffer> &graphicBuffer,
+            IOMX::buffer_id buffer, const sp<GraphicBuffer> &graphicBuffer,
             OMX_U32 flags, OMX_TICKS timestamp, int fenceFd);
 
     status_t emptyNativeHandleBuffer_l(
-            OMX::buffer_id buffer, const sp<NativeHandle> &nativeHandle,
+            IOMX::buffer_id buffer, const sp<NativeHandle> &nativeHandle,
             OMX_U32 flags, OMX_TICKS timestamp, int fenceFd);
 
     status_t emptyBuffer_l(
@@ -252,11 +253,11 @@
     // buffer.)
     status_t updateGraphicBufferInMeta_l(
             OMX_U32 portIndex, const sp<GraphicBuffer> &graphicBuffer,
-            OMX::buffer_id buffer, OMX_BUFFERHEADERTYPE *header);
+            IOMX::buffer_id buffer, OMX_BUFFERHEADERTYPE *header);
 
     status_t updateNativeHandleInMeta_l(
             OMX_U32 portIndex, const sp<NativeHandle> &nativeHandle,
-            OMX::buffer_id buffer, OMX_BUFFERHEADERTYPE *header);
+            IOMX::buffer_id buffer, OMX_BUFFERHEADERTYPE *header);
 
     sp<IOMXBufferSource> getBufferSource();
     void setBufferSource(const sp<IOMXBufferSource> &bufferSource);
diff --git a/media/libstagefright/include/OmxNodeOwner.h b/media/libstagefright/include/OmxNodeOwner.h
new file mode 100644
index 0000000..64ec7f7
--- /dev/null
+++ b/media/libstagefright/include/OmxNodeOwner.h
@@ -0,0 +1,37 @@
+/*
+ * 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/WVMExtractor.h b/media/libstagefright/include/WVMExtractor.h
deleted file mode 100644
index 65cb99a..0000000
--- a/media/libstagefright/include/WVMExtractor.h
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Copyright (C) 2010 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 WVM_EXTRACTOR_H_
-
-#define WVM_EXTRACTOR_H_
-
-#include <media/stagefright/MediaExtractor.h>
-#include <utils/Errors.h>
-
-namespace android {
-
-struct AMessage;
-class String8;
-class DataSource;
-
-class WVMLoadableExtractor : public MediaExtractor {
-public:
-    WVMLoadableExtractor() {}
-    virtual ~WVMLoadableExtractor() {}
-
-    virtual int64_t getCachedDurationUs(status_t *finalStatus) = 0;
-    virtual status_t getError() = 0;
-    virtual status_t getEstimatedBandwidthKbps(int32_t *kbps) = 0;
-    virtual void setAdaptiveStreamingMode(bool adaptive) = 0;
-    virtual void setCryptoPluginMode(bool cryptoPluginMode) = 0;
-    virtual void setError(status_t err) = 0;
-    virtual void setUID(uid_t uid) = 0;
-};
-
-class WVMExtractor : public MediaExtractor {
-public:
-    explicit WVMExtractor(const sp<DataSource> &source);
-
-    virtual size_t countTracks();
-    virtual sp<IMediaSource> getTrack(size_t index);
-    virtual sp<MetaData> getTrackMetaData(size_t index, uint32_t flags);
-    virtual sp<MetaData> getMetaData();
-    virtual void setUID(uid_t uid);
-
-    // Return the amount of data cached from the current
-    // playback positiion (in us).
-    // While more data is still being fetched *finalStatus == OK,
-    // Once fetching is completed (no more data available), *finalStatus != OK
-    // If fetching completed normally (i.e. reached EOS instead of IO error)
-    // *finalStatus == ERROR_END_OF_STREAM
-    int64_t getCachedDurationUs(status_t *finalStatus);
-
-    // Return the current estimated bandwidth
-    status_t getEstimatedBandwidthKbps(int32_t *kbps);
-
-    // Set to use adaptive streaming mode by the WV component.
-    // If adaptive == true, adaptive streaming mode will be used.
-    // Default mode is non-adaptive streaming mode.
-    // Should set to use adaptive streaming mode only if widevine:// protocol
-    // is used.
-    void setAdaptiveStreamingMode(bool adaptive);
-
-    // setCryptoPluginMode(true) to select crypto plugin mode.
-    // In this mode, the extractor returns encrypted data for use
-    // with the MediaCodec model, which handles the decryption in the
-    // codec.
-    void setCryptoPluginMode(bool cryptoPluginMode);
-
-    static bool getVendorLibHandle();
-
-    status_t getError();
-
-    void setError(status_t err);
-
-protected:
-    virtual ~WVMExtractor();
-
-private:
-    sp<DataSource> mDataSource;
-    sp<WVMLoadableExtractor> mImpl;
-
-    WVMExtractor(const WVMExtractor &);
-    WVMExtractor &operator=(const WVMExtractor &);
-};
-
-bool SniffWVM(
-        const sp<DataSource> &source, String8 *mimeType, float *confidence,
-        sp<AMessage> *);
-
-}  // namespace android
-
-#endif  // DRM_EXTRACTOR_H_
-
diff --git a/media/libstagefright/mpeg2ts/ATSParser.cpp b/media/libstagefright/mpeg2ts/ATSParser.cpp
index 844479e..4975d9a 100644
--- a/media/libstagefright/mpeg2ts/ATSParser.cpp
+++ b/media/libstagefright/mpeg2ts/ATSParser.cpp
@@ -90,6 +90,10 @@
         return mParser->mFlags;
     }
 
+    uint64_t firstPTS() const {
+        return mFirstPTS;
+    }
+
 private:
     struct StreamInfo {
         unsigned mType;
@@ -135,6 +139,7 @@
 
     void signalEOS(status_t finalResult);
 
+    SourceType getSourceType();
     sp<MediaSource> getSource(SourceType type);
 
     bool isAudio() const;
@@ -208,11 +213,12 @@
     : mHasReturnedData(false), mOffset(offset), mTimeUs(0) {}
 
 void ATSParser::SyncEvent::init(off64_t offset, const sp<MediaSource> &source,
-        int64_t timeUs) {
+        int64_t timeUs, SourceType type) {
     mHasReturnedData = true;
     mOffset = offset;
     mMediaSource = source;
     mTimeUs = timeUs;
+    mType = type;
 }
 
 void ATSParser::SyncEvent::reset() {
@@ -1121,13 +1127,24 @@
                 int64_t timeUs;
                 if (accessUnit->meta()->findInt64("timeUs", &timeUs)) {
                     found = true;
-                    event->init(pesStartOffset, mSource, timeUs);
+                    event->init(pesStartOffset, mSource, timeUs, getSourceType());
                 }
             }
         }
     }
 }
 
+ATSParser::SourceType ATSParser::Stream::getSourceType() {
+    if (isVideo()) {
+        return VIDEO;
+    } else if (isAudio()) {
+        return AUDIO;
+    } else if (isMeta()) {
+        return META;
+    }
+    return NUM_SOURCE_TYPES;
+}
+
 sp<MediaSource> ATSParser::Stream::getSource(SourceType type) {
     switch (type) {
         case VIDEO:
@@ -1565,6 +1582,16 @@
     return mPrograms.editItemAt(0)->PTSTimeDeltaEstablished();
 }
 
+int64_t ATSParser::getFirstPTSTimeUs() {
+    for (size_t i = 0; i < mPrograms.size(); ++i) {
+        sp<ATSParser::Program> program = mPrograms.itemAt(i);
+        if (program->PTSTimeDeltaEstablished()) {
+            return (program->firstPTS() * 100) / 9;
+        }
+    }
+    return -1;
+}
+
 __attribute__((no_sanitize("integer")))
 void ATSParser::updatePCR(
         unsigned /* PID */, uint64_t PCR, uint64_t byteOffsetFromStart) {
diff --git a/media/libstagefright/mpeg2ts/ATSParser.h b/media/libstagefright/mpeg2ts/ATSParser.h
index 2b166f0..faae6c9 100644
--- a/media/libstagefright/mpeg2ts/ATSParser.h
+++ b/media/libstagefright/mpeg2ts/ATSParser.h
@@ -62,18 +62,26 @@
         ALIGNED_VIDEO_DATA         = 2,
     };
 
+    enum SourceType {
+        VIDEO = 0,
+        AUDIO = 1,
+        META  = 2,
+        NUM_SOURCE_TYPES = 3
+    };
+
     // Event is used to signal sync point event at feedTSPacket().
     struct SyncEvent {
         explicit SyncEvent(off64_t offset);
 
         void init(off64_t offset, const sp<MediaSource> &source,
-                int64_t timeUs);
+                int64_t timeUs, SourceType type);
 
         bool hasReturnedData() const { return mHasReturnedData; }
         void reset();
         off64_t getOffset() const { return mOffset; }
         const sp<MediaSource> &getMediaSource() const { return mMediaSource; }
         int64_t getTimeUs() const { return mTimeUs; }
+        SourceType getType() const { return mType; }
 
     private:
         bool mHasReturnedData;
@@ -87,6 +95,7 @@
         sp<MediaSource> mMediaSource;
         /* The timestamp of the sync frame. */
         int64_t mTimeUs;
+        SourceType mType;
     };
 
     explicit ATSParser(uint32_t flags = 0);
@@ -107,17 +116,13 @@
 
     void signalEOS(status_t finalResult);
 
-    enum SourceType {
-        VIDEO = 0,
-        AUDIO = 1,
-        META  = 2,
-        NUM_SOURCE_TYPES = 3
-    };
     sp<MediaSource> getSource(SourceType type);
     bool hasSource(SourceType type) const;
 
     bool PTSTimeDeltaEstablished();
 
+    int64_t getFirstPTSTimeUs();
+
     enum {
         // From ISO/IEC 13818-1: 2000 (E), Table 2-29
         STREAMTYPE_RESERVED             = 0x00,
diff --git a/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp b/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp
index 4fcf7b5..548f44e 100644
--- a/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp
+++ b/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp
@@ -44,6 +44,7 @@
       mEnabled(true),
       mFormat(NULL),
       mLastQueuedTimeUs(0),
+      mEstimatedBufferDurationUs(-1),
       mEOSResult(OK),
       mLatestEnqueuedMeta(NULL),
       mLatestDequeuedMeta(NULL) {
@@ -309,6 +310,8 @@
 
     mFormat = NULL;
     mLatestEnqueuedMeta = NULL;
+
+    mEstimatedBufferDurationUs = -1;
 }
 
 void AnotherPacketSource::queueDiscontinuity(
@@ -431,6 +434,31 @@
     return durationUs;
 }
 
+int64_t AnotherPacketSource::getEstimatedBufferDurationUs() {
+    Mutex::Autolock autoLock(mLock);
+    if (mEstimatedBufferDurationUs >= 0) {
+        return mEstimatedBufferDurationUs;
+    }
+
+    SortedVector<int64_t> maxTimesUs;
+    List<sp<ABuffer> >::iterator it;
+    int64_t t1 = 0, t2 = 0;
+    for (it = mBuffers.begin(); it != mBuffers.end(); ++it) {
+        int64_t timeUs = 0;
+        const sp<ABuffer> &buffer = *it;
+        if (!buffer->meta()->findInt64("timeUs", &timeUs)) {
+            continue;
+        }
+        maxTimesUs.add(timeUs);
+        while (maxTimesUs.size() > 2) {
+            maxTimesUs.removeAt(0);
+            t1 = maxTimesUs.itemAt(0);
+            t2 = maxTimesUs.itemAt(1);
+        }
+    }
+    return mEstimatedBufferDurationUs = t2 - t1;
+}
+
 status_t AnotherPacketSource::nextBufferTime(int64_t *timeUs) {
     *timeUs = 0;
 
diff --git a/media/libstagefright/mpeg2ts/AnotherPacketSource.h b/media/libstagefright/mpeg2ts/AnotherPacketSource.h
index dd6849e..b0890d7 100644
--- a/media/libstagefright/mpeg2ts/AnotherPacketSource.h
+++ b/media/libstagefright/mpeg2ts/AnotherPacketSource.h
@@ -57,6 +57,9 @@
     // presentation timestamps since the last discontinuity (if any).
     int64_t getBufferedDurationUs(status_t *finalResult);
 
+    // Returns the difference between the two largest timestamps queued
+    int64_t getEstimatedBufferDurationUs();
+
     status_t nextBufferTime(int64_t *timeUs);
 
     void queueAccessUnit(const sp<ABuffer> &buffer);
@@ -113,6 +116,7 @@
     bool mEnabled;
     sp<MetaData> mFormat;
     int64_t mLastQueuedTimeUs;
+    int64_t mEstimatedBufferDurationUs;
     List<sp<ABuffer> > mBuffers;
     status_t mEOSResult;
     sp<AMessage> mLatestEnqueuedMeta;
diff --git a/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp b/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp
index fb5e079..bde33dc 100644
--- a/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp
+++ b/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp
@@ -26,6 +26,7 @@
 #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>
@@ -40,6 +41,8 @@
 namespace android {
 
 static const size_t kTSPacketSize = 188;
+static const int kMaxDurationReadSize = 250000LL;
+static const int kMaxDurationRetry = 6;
 
 struct MPEG2TSSource : public MediaSource {
     MPEG2TSSource(
@@ -212,23 +215,22 @@
                         - mSeekSyncPoints->keyAt(0);
                 off64_t diffOffset = mSeekSyncPoints->valueAt(prevSyncSize - 1)
                         - mSeekSyncPoints->valueAt(0);
-                durationUs = size * diffUs / diffOffset;
-                durations.push_back(durationUs);
+                int64_t currentDurationUs = size * diffUs / diffOffset;
+                durations.push_back(currentDurationUs);
                 if (durations.size() > 5) {
                     durations.erase(durations.begin());
                     int64_t min = *durations.begin();
                     int64_t max = *durations.begin();
-                    for (List<int64_t>::iterator i = durations.begin();
-                            i != durations.end();
-                            ++i) {
-                        if (min > *i) {
-                            min = *i;
+                    for (auto duration : durations) {
+                        if (min > duration) {
+                            min = duration;
                         }
-                        if (max < *i) {
-                            max = *i;
+                        if (max < duration) {
+                            max = duration;
                         }
                     }
                     if (max - min < 500 * 1000) {
+                        durationUs = currentDurationUs;
                         break;
                     }
                 }
@@ -244,6 +246,8 @@
             const sp<MetaData> meta = impl->getFormat();
             meta->setInt64(kKeyDuration, durationUs);
             impl->setFormat(meta);
+        } else {
+            estimateDurationsFromTimesUsAtEnd();
         }
     }
 
@@ -302,6 +306,106 @@
     }
 }
 
+status_t MPEG2TSExtractor::estimateDurationsFromTimesUsAtEnd()  {
+    if (!(mDataSource->flags() & DataSource::kIsLocalFileSource)) {
+        return ERROR_UNSUPPORTED;
+    }
+
+    off64_t size = 0;
+    status_t err = mDataSource->getSize(&size);
+    if (err != OK) {
+        return err;
+    }
+
+    uint8_t packet[kTSPacketSize];
+    const off64_t zero = 0;
+    off64_t offset = max(zero, size - kMaxDurationReadSize);
+    if (mDataSource->readAt(offset, &packet, 0) < 0) {
+        return ERROR_IO;
+    }
+
+    int retry = 0;
+    bool allDurationsFound = false;
+    int64_t timeAnchorUs = mParser->getFirstPTSTimeUs();
+    do {
+        int bytesRead = 0;
+        sp<ATSParser> parser = new ATSParser(ATSParser::TS_TIMESTAMPS_ARE_ABSOLUTE);
+        ATSParser::SyncEvent ev(0);
+        offset = max(zero, size - (kMaxDurationReadSize << retry));
+        offset = (offset / kTSPacketSize) * kTSPacketSize;
+        for (;;) {
+            if (bytesRead >= kMaxDurationReadSize << max(0, retry - 1)) {
+                break;
+            }
+
+            ssize_t n = mDataSource->readAt(offset, packet, kTSPacketSize);
+            if (n < 0) {
+                return n;
+            } else if (n < (ssize_t)kTSPacketSize) {
+                break;
+            }
+
+            offset += kTSPacketSize;
+            bytesRead += kTSPacketSize;
+            err = parser->feedTSPacket(packet, kTSPacketSize, &ev);
+            if (err != OK) {
+                return err;
+            }
+
+            if (ev.hasReturnedData()) {
+                int64_t durationUs = ev.getTimeUs();
+                ATSParser::SourceType type = ev.getType();
+                ev.reset();
+
+                int64_t firstTimeUs;
+                sp<AnotherPacketSource> src =
+                    (AnotherPacketSource *)mParser->getSource(type).get();
+                if (src == NULL || src->nextBufferTime(&firstTimeUs) != OK) {
+                    continue;
+                }
+                durationUs += src->getEstimatedBufferDurationUs();
+                durationUs -= timeAnchorUs;
+                durationUs -= firstTimeUs;
+                if (durationUs > 0) {
+                    int64_t origDurationUs, lastDurationUs;
+                    const sp<MetaData> meta = src->getFormat();
+                    const uint32_t kKeyLastDuration = 'ldur';
+                    // Require two consecutive duration calculations to be within 1 sec before
+                    // updating; use MetaData to store previous duration estimate in per-stream
+                    // context.
+                    if (!meta->findInt64(kKeyDuration, &origDurationUs)
+                            || !meta->findInt64(kKeyLastDuration, &lastDurationUs)
+                            || (origDurationUs < durationUs
+                             && abs(durationUs - lastDurationUs) < 60000000)) {
+                        meta->setInt64(kKeyDuration, durationUs);
+                    }
+                    meta->setInt64(kKeyLastDuration, durationUs);
+                }
+            }
+        }
+
+        if (!allDurationsFound) {
+            allDurationsFound = true;
+            for (auto t: {ATSParser::VIDEO, ATSParser::AUDIO}) {
+                sp<AnotherPacketSource> src = (AnotherPacketSource *)mParser->getSource(t).get();
+                if (src == NULL) {
+                    continue;
+                }
+                int64_t durationUs;
+                const sp<MetaData> meta = src->getFormat();
+                if (!meta->findInt64(kKeyDuration, &durationUs)) {
+                    allDurationsFound = false;
+                    break;
+                }
+            }
+        }
+
+        ++retry;
+    } while(!allDurationsFound && offset > 0 && retry <= kMaxDurationRetry);
+
+    return allDurationsFound? OK : ERROR_UNSUPPORTED;
+}
+
 uint32_t MPEG2TSExtractor::flags() const {
     return CAN_PAUSE | CAN_SEEK_BACKWARD | CAN_SEEK_FORWARD;
 }
diff --git a/media/libstagefright/omx/OMXNodeInstance.cpp b/media/libstagefright/omx/OMXNodeInstance.cpp
index be4a932..c20e9fc 100644
--- a/media/libstagefright/omx/OMXNodeInstance.cpp
+++ b/media/libstagefright/omx/OMXNodeInstance.cpp
@@ -332,7 +332,7 @@
 ////////////////////////////////////////////////////////////////////////////////
 
 OMXNodeInstance::OMXNodeInstance(
-        OMX *owner, const sp<IOMXObserver> &observer, const char *name)
+        OmxNodeOwner *owner, const sp<IOMXObserver> &observer, const char *name)
     : mOwner(owner),
       mHandle(NULL),
       mObserver(observer),
@@ -799,9 +799,7 @@
         if (!graphic) {
             // Extension not supported, check for manual override with system property
             // This is a temporary workaround until partners support the OMX extension
-            char value[PROPERTY_VALUE_MAX];
-            if (property_get("media.mediadrmservice.enable", value, NULL)
-                && (!strcmp("1", value) || !strcasecmp("true", value))) {
+            if (property_get_bool("media.mediadrmservice.enable", false)) {
                 CLOG_CONFIG(enableNativeBuffers, "system property override: using native-handles");
                 mSecureBufferType[portIndex] = kSecureBufferTypeNativeHandle;
             } else if (mSecureBufferType[portIndex] == kSecureBufferTypeUnknown) {
@@ -1010,7 +1008,7 @@
 }
 
 status_t OMXNodeInstance::useBuffer(
-        OMX_U32 portIndex, const OMXBuffer &omxBuffer, OMX::buffer_id *buffer) {
+        OMX_U32 portIndex, const OMXBuffer &omxBuffer, IOMX::buffer_id *buffer) {
     if (buffer == NULL) {
         ALOGE("b/25884056");
         return BAD_VALUE;
@@ -1040,7 +1038,7 @@
 }
 
 status_t OMXNodeInstance::useBuffer_l(
-        OMX_U32 portIndex, const sp<IMemory> &params, OMX::buffer_id *buffer) {
+        OMX_U32 portIndex, const sp<IMemory> &params, IOMX::buffer_id *buffer) {
     BufferMeta *buffer_meta;
     OMX_BUFFERHEADERTYPE *header;
     OMX_ERRORTYPE err = OMX_ErrorNone;
@@ -1147,7 +1145,7 @@
 
 status_t OMXNodeInstance::useGraphicBuffer2_l(
         OMX_U32 portIndex, const sp<GraphicBuffer>& graphicBuffer,
-        OMX::buffer_id *buffer) {
+        IOMX::buffer_id *buffer) {
     if (graphicBuffer == NULL || buffer == NULL) {
         ALOGE("b/25884056");
         return BAD_VALUE;
@@ -1203,7 +1201,7 @@
 // can be renamed to useGraphicBuffer.
 status_t OMXNodeInstance::useGraphicBuffer_l(
         OMX_U32 portIndex, const sp<GraphicBuffer>& graphicBuffer,
-        OMX::buffer_id *buffer) {
+        IOMX::buffer_id *buffer) {
     if (graphicBuffer == NULL || buffer == NULL) {
         ALOGE("b/25884056");
         return BAD_VALUE;
@@ -1273,7 +1271,7 @@
 
 status_t OMXNodeInstance::useGraphicBufferWithMetadata_l(
         OMX_U32 portIndex, const sp<GraphicBuffer> &graphicBuffer,
-        OMX::buffer_id *buffer) {
+        IOMX::buffer_id *buffer) {
     if (portIndex != kPortIndexOutput) {
         return BAD_VALUE;
     }
@@ -1296,7 +1294,7 @@
 
 status_t OMXNodeInstance::updateGraphicBufferInMeta_l(
         OMX_U32 portIndex, const sp<GraphicBuffer>& graphicBuffer,
-        OMX::buffer_id buffer, OMX_BUFFERHEADERTYPE *header) {
+        IOMX::buffer_id buffer, OMX_BUFFERHEADERTYPE *header) {
     // No need to check |graphicBuffer| since NULL is valid for it as below.
     if (header == NULL) {
         ALOGE("b/25884056");
@@ -1336,7 +1334,7 @@
 
 status_t OMXNodeInstance::updateNativeHandleInMeta_l(
         OMX_U32 portIndex, const sp<NativeHandle>& nativeHandle,
-        OMX::buffer_id buffer, OMX_BUFFERHEADERTYPE *header) {
+        IOMX::buffer_id buffer, OMX_BUFFERHEADERTYPE *header) {
     // No need to check |nativeHandle| since NULL is valid for it as below.
     if (header == NULL) {
         ALOGE("b/25884056");
@@ -1423,7 +1421,7 @@
 }
 
 status_t OMXNodeInstance::allocateSecureBuffer(
-        OMX_U32 portIndex, size_t size, OMX::buffer_id *buffer,
+        OMX_U32 portIndex, size_t size, IOMX::buffer_id *buffer,
         void **buffer_data, sp<NativeHandle> *native_handle) {
     if (buffer == NULL || buffer_data == NULL || native_handle == NULL) {
         ALOGE("b/25884056");
@@ -1481,7 +1479,7 @@
 }
 
 status_t OMXNodeInstance::freeBuffer(
-        OMX_U32 portIndex, OMX::buffer_id buffer) {
+        OMX_U32 portIndex, IOMX::buffer_id buffer) {
     Mutex::Autolock autoLock(mLock);
     CLOG_BUFFER(freeBuffer, "%s:%u %#x", portString(portIndex), portIndex, buffer);
 
@@ -1505,7 +1503,7 @@
 }
 
 status_t OMXNodeInstance::fillBuffer(
-        OMX::buffer_id buffer, const OMXBuffer &omxBuffer, int fenceFd) {
+        IOMX::buffer_id buffer, const OMXBuffer &omxBuffer, int fenceFd) {
     Mutex::Autolock autoLock(mLock);
 
     OMX_BUFFERHEADERTYPE *header = findBufferHeader(buffer, kPortIndexOutput);
@@ -1579,7 +1577,7 @@
 }
 
 status_t OMXNodeInstance::emptyBuffer_l(
-        OMX::buffer_id buffer,
+        IOMX::buffer_id buffer,
         OMX_U32 rangeOffset, OMX_U32 rangeLength,
         OMX_U32 flags, OMX_TICKS timestamp, int fenceFd) {
 
@@ -1731,7 +1729,7 @@
 
 // like emptyBuffer, but the data is already in header->pBuffer
 status_t OMXNodeInstance::emptyGraphicBuffer_l(
-        OMX::buffer_id buffer, const sp<GraphicBuffer> &graphicBuffer,
+        IOMX::buffer_id buffer, const sp<GraphicBuffer> &graphicBuffer,
         OMX_U32 flags, OMX_TICKS timestamp, int fenceFd) {
     OMX_BUFFERHEADERTYPE *header = findBufferHeader(buffer, kPortIndexInput);
     if (header == NULL) {
@@ -1803,7 +1801,7 @@
 }
 
 status_t OMXNodeInstance::emptyNativeHandleBuffer_l(
-        OMX::buffer_id buffer, const sp<NativeHandle> &nativeHandle,
+        IOMX::buffer_id buffer, const sp<NativeHandle> &nativeHandle,
         OMX_U32 flags, OMX_TICKS timestamp, int fenceFd) {
     OMX_BUFFERHEADERTYPE *header = findBufferHeader(buffer, kPortIndexInput);
     if (header == NULL) {
@@ -2199,7 +2197,7 @@
     return OMX_ErrorNone;
 }
 
-void OMXNodeInstance::addActiveBuffer(OMX_U32 portIndex, OMX::buffer_id id) {
+void OMXNodeInstance::addActiveBuffer(OMX_U32 portIndex, IOMX::buffer_id id) {
     ActiveBuffer active;
     active.mPortIndex = portIndex;
     active.mID = id;
@@ -2211,7 +2209,7 @@
 }
 
 void OMXNodeInstance::removeActiveBuffer(
-        OMX_U32 portIndex, OMX::buffer_id id) {
+        OMX_U32 portIndex, IOMX::buffer_id id) {
     for (size_t i = 0; i < mActiveBuffers.size(); ++i) {
         if (mActiveBuffers[i].mPortIndex == portIndex
                 && mActiveBuffers[i].mID == id) {
@@ -2236,17 +2234,17 @@
     }
 }
 
-OMX::buffer_id OMXNodeInstance::makeBufferID(OMX_BUFFERHEADERTYPE *bufferHeader) {
+IOMX::buffer_id OMXNodeInstance::makeBufferID(OMX_BUFFERHEADERTYPE *bufferHeader) {
     if (bufferHeader == NULL) {
         return 0;
     }
     Mutex::Autolock autoLock(mBufferIDLock);
-    OMX::buffer_id buffer;
+    IOMX::buffer_id buffer;
     do { // handle the very unlikely case of ID overflow
         if (++mBufferIDCount == 0) {
             ++mBufferIDCount;
         }
-        buffer = (OMX::buffer_id)mBufferIDCount;
+        buffer = (IOMX::buffer_id)mBufferIDCount;
     } while (mBufferIDToBufferHeader.indexOfKey(buffer) >= 0);
     mBufferIDToBufferHeader.add(buffer, bufferHeader);
     mBufferHeaderToBufferID.add(bufferHeader, buffer);
@@ -2254,7 +2252,7 @@
 }
 
 OMX_BUFFERHEADERTYPE *OMXNodeInstance::findBufferHeader(
-        OMX::buffer_id buffer, OMX_U32 portIndex) {
+        IOMX::buffer_id buffer, OMX_U32 portIndex) {
     if (buffer == 0) {
         return NULL;
     }
@@ -2275,7 +2273,7 @@
     return header;
 }
 
-OMX::buffer_id OMXNodeInstance::findBufferID(OMX_BUFFERHEADERTYPE *bufferHeader) {
+IOMX::buffer_id OMXNodeInstance::findBufferID(OMX_BUFFERHEADERTYPE *bufferHeader) {
     if (bufferHeader == NULL) {
         return 0;
     }
@@ -2288,7 +2286,7 @@
     return mBufferHeaderToBufferID.valueAt(index);
 }
 
-void OMXNodeInstance::invalidateBufferID(OMX::buffer_id buffer) {
+void OMXNodeInstance::invalidateBufferID(IOMX::buffer_id buffer) {
     if (buffer == 0) {
         return;
     }
diff --git a/media/libstagefright/omx/hal/1.0/Android.mk b/media/libstagefright/omx/hal/1.0/Android.mk
new file mode 100644
index 0000000..b84d74b
--- /dev/null
+++ b/media/libstagefright/omx/hal/1.0/Android.mk
@@ -0,0 +1,22 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := android.hardware.media.omx@1.0-impl
+LOCAL_MODULE_RELATIVE_PATH := hw
+LOCAL_SRC_FILES := \
+    GraphicBufferSource.cpp \
+    Omx.cpp \
+    OmxBufferSource.cpp \
+    OmxNode.cpp \
+    OmxObserver.cpp \
+
+LOCAL_SHARED_LIBRARIES := \
+    libhidlbase \
+    libhidltransport \
+    libhwbinder \
+    libutils \
+    android.hardware.media.omx@1.0 \
+    android.hardware.graphics.common@1.0 \
+    android.hardware.media@1.0 \
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libstagefright/omx/hal/1.0/GraphicBufferSource.cpp b/media/libstagefright/omx/hal/1.0/GraphicBufferSource.cpp
new file mode 100644
index 0000000..6a43883
--- /dev/null
+++ b/media/libstagefright/omx/hal/1.0/GraphicBufferSource.cpp
@@ -0,0 +1,66 @@
+#include "GraphicBufferSource.h"
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace omx {
+namespace V1_0 {
+namespace implementation {
+
+// Methods from ::android::hardware::media::omx::V1_0::IGraphicBufferSource follow.
+Return<Status> GraphicBufferSource::configure(const sp<IOmxNode>& omxNode, Dataspace dataspace) {
+    // TODO implement
+    return ::android::hardware::media::omx::V1_0::Status {};
+}
+
+Return<Status> GraphicBufferSource::setSuspend(bool suspend) {
+    // TODO implement
+    return ::android::hardware::media::omx::V1_0::Status {};
+}
+
+Return<Status> GraphicBufferSource::setRepeatPreviousFrameDelayUs(int64_t repeatAfterUs) {
+    // TODO implement
+    return ::android::hardware::media::omx::V1_0::Status {};
+}
+
+Return<Status> GraphicBufferSource::setMaxFps(float maxFps) {
+    // TODO implement
+    return ::android::hardware::media::omx::V1_0::Status {};
+}
+
+Return<Status> GraphicBufferSource::setTimeLapseConfig(int64_t timePerFrameUs, int64_t timePerCaptureUs) {
+    // TODO implement
+    return ::android::hardware::media::omx::V1_0::Status {};
+}
+
+Return<Status> GraphicBufferSource::setStartTimeUs(int64_t startTimeUs) {
+    // TODO implement
+    return ::android::hardware::media::omx::V1_0::Status {};
+}
+
+Return<Status> GraphicBufferSource::setColorAspects(const ColorAspects& aspects) {
+    // TODO implement
+    return ::android::hardware::media::omx::V1_0::Status {};
+}
+
+Return<Status> GraphicBufferSource::setTimeOffsetUs(int64_t timeOffsetUs) {
+    // TODO implement
+    return ::android::hardware::media::omx::V1_0::Status {};
+}
+
+Return<Status> GraphicBufferSource::signalEndOfInputStream() {
+    // TODO implement
+    return ::android::hardware::media::omx::V1_0::Status {};
+}
+
+
+IGraphicBufferSource* HIDL_FETCH_IGraphicBufferSource(const char* /* name */) {
+    return new GraphicBufferSource();
+}
+
+} // namespace implementation
+}  // namespace V1_0
+}  // namespace omx
+}  // namespace media
+}  // namespace hardware
+}  // namespace android
diff --git a/media/libstagefright/omx/hal/1.0/GraphicBufferSource.h b/media/libstagefright/omx/hal/1.0/GraphicBufferSource.h
new file mode 100644
index 0000000..fb8c89d
--- /dev/null
+++ b/media/libstagefright/omx/hal/1.0/GraphicBufferSource.h
@@ -0,0 +1,50 @@
+#ifndef ANDROID_HARDWARE_MEDIA_OMX_V1_0__GRAPHICBUFFERSOURCE_H
+#define ANDROID_HARDWARE_MEDIA_OMX_V1_0__GRAPHICBUFFERSOURCE_H
+
+#include <android/hardware/media/omx/1.0/IGraphicBufferSource.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace omx {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::graphics::common::V1_0::Dataspace;
+using ::android::hardware::media::omx::V1_0::ColorAspects;
+using ::android::hardware::media::omx::V1_0::IGraphicBufferSource;
+using ::android::hardware::media::omx::V1_0::IOmxNode;
+using ::android::hardware::media::omx::V1_0::Status;
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::sp;
+
+struct GraphicBufferSource : public IGraphicBufferSource {
+    // Methods from ::android::hardware::media::omx::V1_0::IGraphicBufferSource follow.
+    Return<Status> configure(const sp<IOmxNode>& omxNode, Dataspace dataspace) override;
+    Return<Status> setSuspend(bool suspend) override;
+    Return<Status> setRepeatPreviousFrameDelayUs(int64_t repeatAfterUs) override;
+    Return<Status> setMaxFps(float maxFps) override;
+    Return<Status> setTimeLapseConfig(int64_t timePerFrameUs, int64_t timePerCaptureUs) override;
+    Return<Status> setStartTimeUs(int64_t startTimeUs) override;
+    Return<Status> setColorAspects(const ColorAspects& aspects) override;
+    Return<Status> setTimeOffsetUs(int64_t timeOffsetUs) override;
+    Return<Status> signalEndOfInputStream() override;
+
+};
+
+extern "C" IGraphicBufferSource* HIDL_FETCH_IGraphicBufferSource(const char* name);
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace omx
+}  // namespace media
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_MEDIA_OMX_V1_0__GRAPHICBUFFERSOURCE_H
diff --git a/media/libstagefright/omx/hal/1.0/Omx.cpp b/media/libstagefright/omx/hal/1.0/Omx.cpp
new file mode 100644
index 0000000..68040eb
--- /dev/null
+++ b/media/libstagefright/omx/hal/1.0/Omx.cpp
@@ -0,0 +1,31 @@
+#include "Omx.h"
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace omx {
+namespace V1_0 {
+namespace implementation {
+
+// Methods from ::android::hardware::media::omx::V1_0::IOmx follow.
+Return<void> Omx::listNodes(listNodes_cb _hidl_cb) {
+    // TODO implement
+    return Void();
+}
+
+Return<void> Omx::allocateNode(const hidl_string& name, const sp<IOmxObserver>& observer, allocateNode_cb _hidl_cb) {
+    // TODO implement
+    return Void();
+}
+
+
+IOmx* HIDL_FETCH_IOmx(const char* /* name */) {
+    return new Omx();
+}
+
+} // namespace implementation
+}  // namespace V1_0
+}  // namespace omx
+}  // namespace media
+}  // namespace hardware
+}  // namespace android
diff --git a/media/libstagefright/omx/hal/1.0/Omx.h b/media/libstagefright/omx/hal/1.0/Omx.h
new file mode 100644
index 0000000..02a0a01
--- /dev/null
+++ b/media/libstagefright/omx/hal/1.0/Omx.h
@@ -0,0 +1,42 @@
+#ifndef ANDROID_HARDWARE_MEDIA_OMX_V1_0__OMX_H
+#define ANDROID_HARDWARE_MEDIA_OMX_V1_0__OMX_H
+
+#include <android/hardware/media/omx/1.0/IOmx.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace omx {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::media::omx::V1_0::IOmx;
+using ::android::hardware::media::omx::V1_0::IOmxNode;
+using ::android::hardware::media::omx::V1_0::IOmxObserver;
+using ::android::hardware::media::omx::V1_0::Status;
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::sp;
+
+struct Omx : public IOmx {
+    // Methods from ::android::hardware::media::omx::V1_0::IOmx follow.
+    Return<void> listNodes(listNodes_cb _hidl_cb) override;
+    Return<void> allocateNode(const hidl_string& name, const sp<IOmxObserver>& observer, allocateNode_cb _hidl_cb) override;
+
+};
+
+extern "C" IOmx* HIDL_FETCH_IOmx(const char* name);
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace omx
+}  // namespace media
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_MEDIA_OMX_V1_0__OMX_H
diff --git a/media/libstagefright/omx/hal/1.0/OmxBufferSource.cpp b/media/libstagefright/omx/hal/1.0/OmxBufferSource.cpp
new file mode 100644
index 0000000..2885d0d
--- /dev/null
+++ b/media/libstagefright/omx/hal/1.0/OmxBufferSource.cpp
@@ -0,0 +1,46 @@
+#include "OmxBufferSource.h"
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace omx {
+namespace V1_0 {
+namespace implementation {
+
+// Methods from ::android::hardware::media::omx::V1_0::IOmxBufferSource follow.
+Return<void> OmxBufferSource::onOmxExecuting() {
+    // TODO implement
+    return Void();
+}
+
+Return<void> OmxBufferSource::onOmxIdle() {
+    // TODO implement
+    return Void();
+}
+
+Return<void> OmxBufferSource::onOmxLoaded() {
+    // TODO implement
+    return Void();
+}
+
+Return<void> OmxBufferSource::onInputBufferAdded(uint32_t buffer) {
+    // TODO implement
+    return Void();
+}
+
+Return<void> OmxBufferSource::onInputBufferEmptied(uint32_t buffer, const hidl_handle& fence) {
+    // TODO implement
+    return Void();
+}
+
+
+IOmxBufferSource* HIDL_FETCH_IOmxBufferSource(const char* /* name */) {
+    return new OmxBufferSource();
+}
+
+} // namespace implementation
+}  // namespace V1_0
+}  // namespace omx
+}  // namespace media
+}  // namespace hardware
+}  // namespace android
diff --git a/media/libstagefright/omx/hal/1.0/OmxBufferSource.h b/media/libstagefright/omx/hal/1.0/OmxBufferSource.h
new file mode 100644
index 0000000..5e4855b
--- /dev/null
+++ b/media/libstagefright/omx/hal/1.0/OmxBufferSource.h
@@ -0,0 +1,42 @@
+#ifndef ANDROID_HARDWARE_MEDIA_OMX_V1_0__OMXBUFFERSOURCE_H
+#define ANDROID_HARDWARE_MEDIA_OMX_V1_0__OMXBUFFERSOURCE_H
+
+#include <android/hardware/media/omx/1.0/IOmxBufferSource.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace omx {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::media::omx::V1_0::IOmxBufferSource;
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::sp;
+
+struct OmxBufferSource : public IOmxBufferSource {
+    // Methods from ::android::hardware::media::omx::V1_0::IOmxBufferSource follow.
+    Return<void> onOmxExecuting() override;
+    Return<void> onOmxIdle() override;
+    Return<void> onOmxLoaded() override;
+    Return<void> onInputBufferAdded(uint32_t buffer) override;
+    Return<void> onInputBufferEmptied(uint32_t buffer, const hidl_handle& fence) override;
+
+};
+
+extern "C" IOmxBufferSource* HIDL_FETCH_IOmxBufferSource(const char* name);
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace omx
+}  // namespace media
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_MEDIA_OMX_V1_0__OMXBUFFERSOURCE_H
diff --git a/media/libstagefright/omx/hal/1.0/OmxNode.cpp b/media/libstagefright/omx/hal/1.0/OmxNode.cpp
new file mode 100644
index 0000000..ba0e722
--- /dev/null
+++ b/media/libstagefright/omx/hal/1.0/OmxNode.cpp
@@ -0,0 +1,111 @@
+#include "OmxNode.h"
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace omx {
+namespace V1_0 {
+namespace implementation {
+
+// Methods from ::android::hardware::media::omx::V1_0::IOmxNode follow.
+Return<Status> OmxNode::freeNode() {
+    // TODO implement
+    return ::android::hardware::media::omx::V1_0::Status {};
+}
+
+Return<Status> OmxNode::sendCommand(uint32_t cmd, const hidl_vec<uint8_t>& info) {
+    // TODO implement
+    return ::android::hardware::media::omx::V1_0::Status {};
+}
+
+Return<void> OmxNode::getParameter(uint32_t index, const hidl_vec<uint8_t>& inParams, getParameter_cb _hidl_cb) {
+    // TODO implement
+    return Void();
+}
+
+Return<Status> OmxNode::setParameter(uint32_t index, const hidl_vec<uint8_t>& params) {
+    // TODO implement
+    return ::android::hardware::media::omx::V1_0::Status {};
+}
+
+Return<void> OmxNode::getConfig(uint32_t index, const hidl_vec<uint8_t>& inConfig, getConfig_cb _hidl_cb) {
+    // TODO implement
+    return Void();
+}
+
+Return<Status> OmxNode::setConfig(uint32_t index, const hidl_vec<uint8_t>& config) {
+    // TODO implement
+    return ::android::hardware::media::omx::V1_0::Status {};
+}
+
+Return<Status> OmxNode::setPortMode(uint32_t portIndex, PortMode mode) {
+    // TODO implement
+    return ::android::hardware::media::omx::V1_0::Status {};
+}
+
+Return<Status> OmxNode::prepareForAdaptivePlayback(uint32_t portIndex, bool enable, uint32_t maxFrameWidth, uint32_t maxFrameHeight) {
+    // TODO implement
+    return ::android::hardware::media::omx::V1_0::Status {};
+}
+
+Return<void> OmxNode::configureVideoTunnelMode(uint32_t portIndex, bool tunneled, uint32_t audioHwSync, configureVideoTunnelMode_cb _hidl_cb) {
+    // TODO implement
+    return Void();
+}
+
+Return<void> OmxNode::getGraphicBufferUsage(uint32_t portIndex, getGraphicBufferUsage_cb _hidl_cb) {
+    // TODO implement
+    return Void();
+}
+
+Return<Status> OmxNode::setInputSurface(const sp<IOmxBufferSource>& bufferSource) {
+    // TODO implement
+    return ::android::hardware::media::omx::V1_0::Status {};
+}
+
+Return<void> OmxNode::allocateSecureBuffer(uint32_t portIndex, uint64_t size, allocateSecureBuffer_cb _hidl_cb) {
+    // TODO implement
+    return Void();
+}
+
+Return<void> OmxNode::useBuffer(uint32_t portIndex, const CodecBuffer& omxBuffer, useBuffer_cb _hidl_cb) {
+    // TODO implement
+    return Void();
+}
+
+Return<Status> OmxNode::freeBuffer(uint32_t portIndex, uint32_t buffer) {
+    // TODO implement
+    return ::android::hardware::media::omx::V1_0::Status {};
+}
+
+Return<Status> OmxNode::fillBuffer(uint32_t buffer, const CodecBuffer& omxBuffer, const hidl_handle& fence) {
+    // TODO implement
+    return ::android::hardware::media::omx::V1_0::Status {};
+}
+
+Return<Status> OmxNode::emptyBuffer(uint32_t buffer, const CodecBuffer& omxBuffer, uint32_t flags, uint64_t timestampUs, const hidl_handle& fence) {
+    // TODO implement
+    return ::android::hardware::media::omx::V1_0::Status {};
+}
+
+Return<void> OmxNode::getExtensionIndex(const hidl_string& parameterName, getExtensionIndex_cb _hidl_cb) {
+    // TODO implement
+    return Void();
+}
+
+Return<Status> OmxNode::dispatchMessage(const Message& msg) {
+    // TODO implement
+    return ::android::hardware::media::omx::V1_0::Status {};
+}
+
+
+IOmxNode* HIDL_FETCH_IOmxNode(const char* /* name */) {
+    return new OmxNode();
+}
+
+} // namespace implementation
+}  // namespace V1_0
+}  // namespace omx
+}  // namespace media
+}  // namespace hardware
+}  // namespace android
diff --git a/media/libstagefright/omx/hal/1.0/OmxNode.h b/media/libstagefright/omx/hal/1.0/OmxNode.h
new file mode 100644
index 0000000..dd9e5b4
--- /dev/null
+++ b/media/libstagefright/omx/hal/1.0/OmxNode.h
@@ -0,0 +1,60 @@
+#ifndef ANDROID_HARDWARE_MEDIA_OMX_V1_0__OMXNODE_H
+#define ANDROID_HARDWARE_MEDIA_OMX_V1_0__OMXNODE_H
+
+#include <android/hardware/media/omx/1.0/IOmxNode.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace omx {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::media::omx::V1_0::CodecBuffer;
+using ::android::hardware::media::omx::V1_0::IOmxBufferSource;
+using ::android::hardware::media::omx::V1_0::IOmxNode;
+using ::android::hardware::media::omx::V1_0::Message;
+using ::android::hardware::media::omx::V1_0::PortMode;
+using ::android::hardware::media::omx::V1_0::Status;
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::sp;
+
+struct OmxNode : public IOmxNode {
+    // Methods from ::android::hardware::media::omx::V1_0::IOmxNode follow.
+    Return<Status> freeNode() override;
+    Return<Status> sendCommand(uint32_t cmd, const hidl_vec<uint8_t>& info) override;
+    Return<void> getParameter(uint32_t index, const hidl_vec<uint8_t>& inParams, getParameter_cb _hidl_cb) override;
+    Return<Status> setParameter(uint32_t index, const hidl_vec<uint8_t>& params) override;
+    Return<void> getConfig(uint32_t index, const hidl_vec<uint8_t>& inConfig, getConfig_cb _hidl_cb) override;
+    Return<Status> setConfig(uint32_t index, const hidl_vec<uint8_t>& config) override;
+    Return<Status> setPortMode(uint32_t portIndex, PortMode mode) override;
+    Return<Status> prepareForAdaptivePlayback(uint32_t portIndex, bool enable, uint32_t maxFrameWidth, uint32_t maxFrameHeight) override;
+    Return<void> configureVideoTunnelMode(uint32_t portIndex, bool tunneled, uint32_t audioHwSync, configureVideoTunnelMode_cb _hidl_cb) override;
+    Return<void> getGraphicBufferUsage(uint32_t portIndex, getGraphicBufferUsage_cb _hidl_cb) override;
+    Return<Status> setInputSurface(const sp<IOmxBufferSource>& bufferSource) override;
+    Return<void> allocateSecureBuffer(uint32_t portIndex, uint64_t size, allocateSecureBuffer_cb _hidl_cb) override;
+    Return<void> useBuffer(uint32_t portIndex, const CodecBuffer& omxBuffer, useBuffer_cb _hidl_cb) override;
+    Return<Status> freeBuffer(uint32_t portIndex, uint32_t buffer) override;
+    Return<Status> fillBuffer(uint32_t buffer, const CodecBuffer& omxBuffer, const hidl_handle& fence) override;
+    Return<Status> emptyBuffer(uint32_t buffer, const CodecBuffer& omxBuffer, uint32_t flags, uint64_t timestampUs, const hidl_handle& fence) override;
+    Return<void> getExtensionIndex(const hidl_string& parameterName, getExtensionIndex_cb _hidl_cb) override;
+    Return<Status> dispatchMessage(const Message& msg) override;
+
+};
+
+extern "C" IOmxNode* HIDL_FETCH_IOmxNode(const char* name);
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace omx
+}  // namespace media
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_MEDIA_OMX_V1_0__OMXNODE_H
diff --git a/media/libstagefright/omx/hal/1.0/OmxObserver.cpp b/media/libstagefright/omx/hal/1.0/OmxObserver.cpp
new file mode 100644
index 0000000..4e946cd
--- /dev/null
+++ b/media/libstagefright/omx/hal/1.0/OmxObserver.cpp
@@ -0,0 +1,26 @@
+#include "OmxObserver.h"
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace omx {
+namespace V1_0 {
+namespace implementation {
+
+// Methods from ::android::hardware::media::omx::V1_0::IOmxObserver follow.
+Return<void> OmxObserver::onMessages(const hidl_vec<Message>& messages) {
+    // TODO implement
+    return Void();
+}
+
+
+IOmxObserver* HIDL_FETCH_IOmxObserver(const char* /* name */) {
+    return new OmxObserver();
+}
+
+} // namespace implementation
+}  // namespace V1_0
+}  // namespace omx
+}  // namespace media
+}  // namespace hardware
+}  // namespace android
diff --git a/media/libstagefright/omx/hal/1.0/OmxObserver.h b/media/libstagefright/omx/hal/1.0/OmxObserver.h
new file mode 100644
index 0000000..630cae3
--- /dev/null
+++ b/media/libstagefright/omx/hal/1.0/OmxObserver.h
@@ -0,0 +1,39 @@
+#ifndef ANDROID_HARDWARE_MEDIA_OMX_V1_0__OMXOBSERVER_H
+#define ANDROID_HARDWARE_MEDIA_OMX_V1_0__OMXOBSERVER_H
+
+#include <android/hardware/media/omx/1.0/IOmxObserver.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace omx {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::media::omx::V1_0::IOmxObserver;
+using ::android::hardware::media::omx::V1_0::Message;
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::sp;
+
+struct OmxObserver : public IOmxObserver {
+    // Methods from ::android::hardware::media::omx::V1_0::IOmxObserver follow.
+    Return<void> onMessages(const hidl_vec<Message>& messages) override;
+
+};
+
+extern "C" IOmxObserver* HIDL_FETCH_IOmxObserver(const char* name);
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace omx
+}  // namespace media
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_MEDIA_OMX_V1_0__OMXOBSERVER_H
diff --git a/media/libstagefright/omx/tests/OMXHarness.cpp b/media/libstagefright/omx/tests/OMXHarness.cpp
index 935d7bf..1ce5d1a 100644
--- a/media/libstagefright/omx/tests/OMXHarness.cpp
+++ b/media/libstagefright/omx/tests/OMXHarness.cpp
@@ -800,7 +800,6 @@
     using namespace android;
 
     android::ProcessState::self()->startThreadPool();
-    DataSource::RegisterDefaultSniffers();
 
     const char *me = argv[0];
 
diff --git a/media/libstagefright/rtsp/rtp_test.cpp b/media/libstagefright/rtsp/rtp_test.cpp
index 24f529b..e612a8d 100644
--- a/media/libstagefright/rtsp/rtp_test.cpp
+++ b/media/libstagefright/rtsp/rtp_test.cpp
@@ -37,8 +37,6 @@
 int main(int argc, char **argv) {
     android::ProcessState::self()->startThreadPool();
 
-    DataSource::RegisterDefaultSniffers();
-
     const char *rtpFilename = NULL;
     const char *rtcpFilename = NULL;
 
diff --git a/media/libstagefright/wifi-display/source/PlaybackSession.cpp b/media/libstagefright/wifi-display/source/PlaybackSession.cpp
index 3587cb9..f1ecca0 100644
--- a/media/libstagefright/wifi-display/source/PlaybackSession.cpp
+++ b/media/libstagefright/wifi-display/source/PlaybackSession.cpp
@@ -36,7 +36,6 @@
 #include <media/stagefright/foundation/AMessage.h>
 #include <media/stagefright/foundation/hexdump.h>
 #include <media/stagefright/AudioSource.h>
-#include <media/stagefright/DataSource.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaErrors.h>
 #include <media/stagefright/MediaSource.h>
@@ -748,8 +747,6 @@
 
 status_t WifiDisplaySource::PlaybackSession::setupMediaPacketizer(
         bool enableAudio, bool enableVideo) {
-    DataSource::RegisterDefaultSniffers();
-
     mExtractor = new NuMediaExtractor;
 
     status_t err = mExtractor->setDataSource(
diff --git a/media/libstagefright/wifi-display/source/WifiDisplaySource.cpp b/media/libstagefright/wifi-display/source/WifiDisplaySource.cpp
index f0a4ded..9cda8dc 100644
--- a/media/libstagefright/wifi-display/source/WifiDisplaySource.cpp
+++ b/media/libstagefright/wifi-display/source/WifiDisplaySource.cpp
@@ -911,10 +911,8 @@
 
         bool supportsPCM = (modes & 2) != 0;  // LPCM 2ch 48kHz
 
-        char val[PROPERTY_VALUE_MAX];
         if (supportsPCM
-                && property_get("media.wfd.use-pcm-audio", val, NULL)
-                && (!strcasecmp("true", val) || !strcmp("1", val))) {
+                && property_get_bool("media.wfd.use-pcm-audio", false)) {
             ALOGI("Using PCM audio.");
             mUsingPCMAudio = true;
         } else if (supportsAAC) {
diff --git a/media/mediaserver/Android.mk b/media/mediaserver/Android.mk
index ffbfcbb..a4cb66d 100644
--- a/media/mediaserver/Android.mk
+++ b/media/mediaserver/Android.mk
@@ -17,7 +17,6 @@
 LOCAL_SHARED_LIBRARIES := \
 	libresourcemanagerservice \
 	liblog \
-	libcutils \
 	libmediaplayerservice \
 	libutils \
 	libbinder \
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 4d2049e..0e70ad9 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -1320,7 +1320,7 @@
     ALOGV("%d died, releasing its sessions", pid);
     size_t num = mAudioSessionRefs.size();
     bool removed = false;
-    for (size_t i = 0; i< num; ) {
+    for (size_t i = 0; i < num; ) {
         AudioSessionRef *ref = mAudioSessionRefs.itemAt(i);
         ALOGV(" pid %d @ %zu", ref->mPid, i);
         if (ref->mPid == pid) {
@@ -2087,9 +2087,10 @@
     sp<StreamInHalInterface> inStream;
     status_t status = inHwHal->openInputStream(
             *input, devices, &halconfig, flags, address.string(), source, &inStream);
-    ALOGV("openInput_l() openInputStream returned input %p, SamplingRate %d"
+    ALOGV("openInput_l() openInputStream returned input %p, devices %x, SamplingRate %d"
            ", Format %#x, Channels %x, flags %#x, status %d addr %s",
             inStream.get(),
+            devices,
             halconfig.sample_rate,
             halconfig.format,
             halconfig.channel_mask,
@@ -2315,7 +2316,7 @@
     }
 
     size_t num = mAudioSessionRefs.size();
-    for (size_t i = 0; i< num; i++) {
+    for (size_t i = 0; i < num; i++) {
         AudioSessionRef *ref = mAudioSessionRefs.editItemAt(i);
         if (ref->mSessionid == audioSession && ref->mPid == caller) {
             ref->mCnt++;
@@ -2336,7 +2337,7 @@
         caller = pid;
     }
     size_t num = mAudioSessionRefs.size();
-    for (size_t i = 0; i< num; i++) {
+    for (size_t i = 0; i < num; i++) {
         AudioSessionRef *ref = mAudioSessionRefs.itemAt(i);
         if (ref->mSessionid == audioSession && ref->mPid == caller) {
             ref->mCnt--;
@@ -2354,6 +2355,18 @@
     ALOGW_IF(caller != getpid_cached, "session id %d not found for pid %d", audioSession, caller);
 }
 
+bool AudioFlinger::isSessionAcquired_l(audio_session_t audioSession)
+{
+    size_t num = mAudioSessionRefs.size();
+    for (size_t i = 0; i < num; i++) {
+        AudioSessionRef *ref = mAudioSessionRefs.itemAt(i);
+        if (ref->mSessionid == audioSession) {
+            return true;
+        }
+    }
+    return false;
+}
+
 void AudioFlinger::purgeStaleEffects_l() {
 
     ALOGV("purging stale effects");
@@ -2767,8 +2780,9 @@
         sp<Client> client = registerPid(pid);
 
         // create effect on selected output thread
+        bool pinned = (sessionId > AUDIO_SESSION_OUTPUT_MIX) && isSessionAcquired_l(sessionId);
         handle = thread->createEffect_l(client, effectClient, priority, sessionId,
-                &desc, enabled, &lStatus);
+                &desc, enabled, &lStatus, pinned);
         if (handle != 0 && id != NULL) {
             *id = handle->id();
         }
@@ -2965,7 +2979,7 @@
     ALOGV("updateOrphanEffectChains session %d index %zd", session, index);
     if (index >= 0) {
         sp<EffectChain> chain = mOrphanEffectChains.valueAt(index);
-        if (chain->removeEffect_l(effect) == 0) {
+        if (chain->removeEffect_l(effect, true) == 0) {
             ALOGV("updateOrphanEffectChains removing effect chain at index %zd", index);
             mOrphanEffectChains.removeItemsAt(index);
         }
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index e9c0f93..c3bf1f9 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -19,6 +19,7 @@
 #define ANDROID_AUDIO_FLINGER_H
 
 #include "Configuration.h"
+#include <deque>
 #include <stdint.h>
 #include <sys/types.h>
 #include <limits.h>
@@ -589,6 +590,7 @@
                 void        removeNotificationClient(pid_t pid);
                 bool isNonOffloadableGlobalEffectEnabled_l();
                 void onNonOffloadableGlobalEffectEnable();
+                bool isSessionAcquired_l(audio_session_t audioSession);
 
                 // Store an effect chain to mOrphanEffectChains keyed vector.
                 // Called when a thread exits and effects are still attached to it.
diff --git a/services/audioflinger/AudioMixer.cpp b/services/audioflinger/AudioMixer.cpp
index 582a5e8..945f4b3 100644
--- a/services/audioflinger/AudioMixer.cpp
+++ b/services/audioflinger/AudioMixer.cpp
@@ -1611,8 +1611,13 @@
         // in == NULL can happen if the track was flushed just after having
         // been enabled for mixing.
         if (in == NULL || (((uintptr_t)in) & 3)) {
-            memset(out, 0, numFrames
-                    * t.mMixerChannelCount * audio_bytes_per_sample(t.mMixerFormat));
+            if ( AUDIO_FORMAT_PCM_FLOAT == t.mMixerFormat ) {
+                 memset((char*)fout, 0, numFrames
+                         * t.mMixerChannelCount * audio_bytes_per_sample(t.mMixerFormat));
+            } else {
+                 memset((char*)out, 0, numFrames
+                         * t.mMixerChannelCount * audio_bytes_per_sample(t.mMixerFormat));
+            }
             ALOGE_IF((((uintptr_t)in) & 3),
                     "process__OneTrack16BitsStereoNoResampling: misaligned buffer"
                     " %p track %d, channels %d, needs %08x, volume %08x vfl %f vfr %f",
diff --git a/services/audioflinger/Effects.cpp b/services/audioflinger/Effects.cpp
index 3a04651..128eaba 100644
--- a/services/audioflinger/Effects.cpp
+++ b/services/audioflinger/Effects.cpp
@@ -60,8 +60,9 @@
                                         const wp<AudioFlinger::EffectChain>& chain,
                                         effect_descriptor_t *desc,
                                         int id,
-                                        audio_session_t sessionId)
-    : mPinned(sessionId > AUDIO_SESSION_OUTPUT_MIX),
+                                        audio_session_t sessionId,
+                                        bool pinned)
+    : mPinned(pinned),
       mThread(thread), mChain(chain), mId(id), mSessionId(sessionId),
       mDescriptor(*desc),
       // mConfig is set by configure() and not used before then
@@ -71,7 +72,7 @@
       mSuspended(false),
       mAudioFlinger(thread->mAudioFlinger)
 {
-    ALOGV("Constructor %p", this);
+    ALOGV("Constructor %p pinned %d", this, pinned);
     int lStatus;
 
     // create effect engine from effect factory
@@ -94,7 +95,9 @@
         goto Error;
     }
 
+    setOffloaded(thread->type() == ThreadBase::OFFLOAD, thread->id());
     ALOGV("Constructor success name %s, Interface %p", mDescriptor.name, mEffectInterface.get());
+
     return;
 Error:
     mEffectInterface.clear();
@@ -105,10 +108,10 @@
 {
     ALOGV("Destructor %p", this);
     if (mEffectInterface != 0) {
-        remove_effect_from_hal_l();
-        // release effect engine
-        mEffectInterface.clear();
+        ALOGW("EffectModule %p destructor called with unreleased interface", this);
+        release_l();
     }
+
 }
 
 status_t AudioFlinger::EffectModule::addHandle(EffectHandle *handle)
@@ -122,7 +125,7 @@
     size_t i;
     for (i = 0; i < size; i++) {
         EffectHandle *h = mHandles[i];
-        if (h == NULL || h->destroyed_l()) {
+        if (h == NULL || h->disconnected()) {
             continue;
         }
         // first non destroyed handle is considered in control
@@ -150,9 +153,14 @@
     return status;
 }
 
-size_t AudioFlinger::EffectModule::removeHandle(EffectHandle *handle)
+ssize_t AudioFlinger::EffectModule::removeHandle(EffectHandle *handle)
 {
     Mutex::Autolock _l(mLock);
+    return removeHandle_l(handle);
+}
+
+ssize_t AudioFlinger::EffectModule::removeHandle_l(EffectHandle *handle)
+{
     size_t size = mHandles.size();
     size_t i;
     for (i = 0; i < size; i++) {
@@ -161,9 +169,10 @@
         }
     }
     if (i == size) {
-        return size;
+        ALOGW("%s %p handle not found %p", __FUNCTION__, this, handle);
+        return BAD_VALUE;
     }
-    ALOGV("removeHandle() %p removed handle %p in position %zu", this, handle, i);
+    ALOGV("removeHandle_l() %p removed handle %p in position %zu", this, handle, i);
 
     mHandles.removeAt(i);
     // if removed from first place, move effect control from this handle to next in line
@@ -190,7 +199,7 @@
     // the first valid handle in the list has control over the module
     for (size_t i = 0; i < mHandles.size(); i++) {
         EffectHandle *h = mHandles[i];
-        if (h != NULL && !h->destroyed_l()) {
+        if (h != NULL && !h->disconnected()) {
             return h;
         }
     }
@@ -198,29 +207,22 @@
     return NULL;
 }
 
-size_t AudioFlinger::EffectModule::disconnect(EffectHandle *handle, bool unpinIfLast)
+// unsafe method called when the effect parent thread has been destroyed
+ssize_t AudioFlinger::EffectModule::disconnectHandle(EffectHandle *handle, bool unpinIfLast)
 {
     ALOGV("disconnect() %p handle %p", this, handle);
-    // keep a strong reference on this EffectModule to avoid calling the
-    // destructor before we exit
-    sp<EffectModule> keep(this);
-    {
-        if (removeHandle(handle) == 0) {
-            if (!isPinned() || unpinIfLast) {
-                sp<ThreadBase> thread = mThread.promote();
-                if (thread != 0) {
-                    Mutex::Autolock _l(thread->mLock);
-                    thread->removeEffect_l(this);
-                }
-                sp<AudioFlinger> af = mAudioFlinger.promote();
-                if (af != 0) {
-                    af->updateOrphanEffectChains(this);
-                }
-                AudioSystem::unregisterEffect(mId);
-            }
+    Mutex::Autolock _l(mLock);
+    ssize_t numHandles = removeHandle_l(handle);
+    if ((numHandles == 0) && (!mPinned || unpinIfLast)) {
+        AudioSystem::unregisterEffect(mId);
+        sp<AudioFlinger> af = mAudioFlinger.promote();
+        if (af != 0) {
+            mLock.unlock();
+            af->updateOrphanEffectChains(this);
+            mLock.lock();
         }
     }
-    return mHandles.size();
+    return numHandles;
 }
 
 bool AudioFlinger::EffectModule::updateState() {
@@ -560,6 +562,16 @@
     return status;
 }
 
+// must be called with EffectChain::mLock held
+void AudioFlinger::EffectModule::release_l()
+{
+    if (mEffectInterface != 0) {
+        remove_effect_from_hal_l();
+        // release effect engine
+        mEffectInterface.clear();
+    }
+}
+
 status_t AudioFlinger::EffectModule::remove_effect_from_hal_l()
 {
     if ((mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_PRE_PROC ||
@@ -599,16 +611,33 @@
         return mStatus;
     }
     if (cmdCode == EFFECT_CMD_GET_PARAM &&
+            (sizeof(effect_param_t) > cmdSize ||
+                    ((effect_param_t *)pCmdData)->psize > cmdSize
+                                                          - sizeof(effect_param_t))) {
+        android_errorWriteLog(0x534e4554, "32438594");
+        android_errorWriteLog(0x534e4554, "33003822");
+        return -EINVAL;
+    }
+    if (cmdCode == EFFECT_CMD_GET_PARAM &&
             (*replySize < sizeof(effect_param_t) ||
                     ((effect_param_t *)pCmdData)->psize > *replySize - sizeof(effect_param_t))) {
         android_errorWriteLog(0x534e4554, "29251553");
         return -EINVAL;
     }
     if (cmdCode == EFFECT_CMD_GET_PARAM &&
-            (sizeof(effect_param_t) > cmdSize ||
-                    ((effect_param_t *)pCmdData)->psize > cmdSize
-                                                          - sizeof(effect_param_t))) {
-        android_errorWriteLog(0x534e4554, "32438594");
+        (sizeof(effect_param_t) > *replySize
+          || ((effect_param_t *)pCmdData)->psize > *replySize
+                                                   - sizeof(effect_param_t)
+          || ((effect_param_t *)pCmdData)->vsize > *replySize
+                                                   - sizeof(effect_param_t)
+                                                   - ((effect_param_t *)pCmdData)->psize
+          || roundUpDelta(((effect_param_t *)pCmdData)->psize, (uint32_t)sizeof(int)) >
+                                                   *replySize
+                                                   - sizeof(effect_param_t)
+                                                   - ((effect_param_t *)pCmdData)->psize
+                                                   - ((effect_param_t *)pCmdData)->vsize)) {
+        ALOGV("\tLVM_ERROR : EFFECT_CMD_GET_PARAM: reply size inconsistent");
+                     android_errorWriteLog(0x534e4554, "32705438");
         return -EINVAL;
     }
     if ((cmdCode == EFFECT_CMD_SET_PARAM
@@ -636,7 +665,7 @@
         uint32_t size = (replySize == NULL) ? 0 : *replySize;
         for (size_t i = 1; i < mHandles.size(); i++) {
             EffectHandle *h = mHandles[i];
-            if (h != NULL && !h->destroyed_l()) {
+            if (h != NULL && !h->disconnected()) {
                 h->commandExecuted(cmdCode, cmdSize, pCmdData, size, pReplyData);
             }
         }
@@ -689,7 +718,7 @@
         }
         for (size_t i = 1; i < mHandles.size(); i++) {
             EffectHandle *h = mHandles[i];
-            if (h != NULL && !h->destroyed_l()) {
+            if (h != NULL && !h->disconnected()) {
                 h->setEnabled(enabled);
             }
         }
@@ -849,8 +878,7 @@
     Mutex::Autolock _l(mLock);
     for (size_t i = 0; i < mHandles.size(); i++) {
         EffectHandle *handle = mHandles[i];
-        if (handle != NULL && !handle->destroyed_l()) {
-            handle->effect().clear();
+        if (handle != NULL && !handle->disconnected()) {
             if (handle->hasControl()) {
                 enabled = handle->enabled();
             }
@@ -1076,7 +1104,7 @@
     result.append("\t\t\t  Pid Priority Ctrl Locked client server\n");
     for (size_t i = 0; i < mHandles.size(); ++i) {
         EffectHandle *handle = mHandles[i];
-        if (handle != NULL && !handle->destroyed_l()) {
+        if (handle != NULL && !handle->disconnected()) {
             handle->dumpToBuffer(buffer, SIZE);
             result.append(buffer);
         }
@@ -1102,7 +1130,7 @@
                                         int32_t priority)
     : BnEffect(),
     mEffect(effect), mEffectClient(effectClient), mClient(client), mCblk(NULL),
-    mPriority(priority), mHasControl(false), mEnabled(false), mDestroyed(false)
+    mPriority(priority), mHasControl(false), mEnabled(false), mDisconnected(false)
 {
     ALOGV("constructor %p", this);
 
@@ -1125,14 +1153,6 @@
 AudioFlinger::EffectHandle::~EffectHandle()
 {
     ALOGV("Destructor %p", this);
-
-    if (mEffect == 0) {
-        mDestroyed = true;
-        return;
-    }
-    mEffect->lock();
-    mDestroyed = true;
-    mEffect->unlock();
     disconnect(false);
 }
 
@@ -1143,13 +1163,15 @@
 
 status_t AudioFlinger::EffectHandle::enable()
 {
+    AutoMutex _l(mLock);
     ALOGV("enable %p", this);
+    sp<EffectModule> effect = mEffect.promote();
+    if (effect == 0 || mDisconnected) {
+        return DEAD_OBJECT;
+    }
     if (!mHasControl) {
         return INVALID_OPERATION;
     }
-    if (mEffect == 0) {
-        return DEAD_OBJECT;
-    }
 
     if (mEnabled) {
         return NO_ERROR;
@@ -1157,20 +1179,20 @@
 
     mEnabled = true;
 
-    sp<ThreadBase> thread = mEffect->thread().promote();
+    sp<ThreadBase> thread = effect->thread().promote();
     if (thread != 0) {
-        thread->checkSuspendOnEffectEnabled(mEffect, true, mEffect->sessionId());
+        thread->checkSuspendOnEffectEnabled(effect, true, effect->sessionId());
     }
 
     // checkSuspendOnEffectEnabled() can suspend this same effect when enabled
-    if (mEffect->suspended()) {
+    if (effect->suspended()) {
         return NO_ERROR;
     }
 
-    status_t status = mEffect->setEnabled(true);
+    status_t status = effect->setEnabled(true);
     if (status != NO_ERROR) {
         if (thread != 0) {
-            thread->checkSuspendOnEffectEnabled(mEffect, false, mEffect->sessionId());
+            thread->checkSuspendOnEffectEnabled(effect, false, effect->sessionId());
         }
         mEnabled = false;
     } else {
@@ -1180,12 +1202,12 @@
                 Mutex::Autolock _l(t->mLock);
                 t->broadcast_l();
             }
-            if (!mEffect->isOffloadable()) {
+            if (!effect->isOffloadable()) {
                 if (thread->type() == ThreadBase::OFFLOAD) {
                     PlaybackThread *t = (PlaybackThread *)thread.get();
                     t->invalidateTracks(AUDIO_STREAM_MUSIC);
                 }
-                if (mEffect->sessionId() == AUDIO_SESSION_OUTPUT_MIX) {
+                if (effect->sessionId() == AUDIO_SESSION_OUTPUT_MIX) {
                     thread->mAudioFlinger->onNonOffloadableGlobalEffectEnable();
                 }
             }
@@ -1197,27 +1219,29 @@
 status_t AudioFlinger::EffectHandle::disable()
 {
     ALOGV("disable %p", this);
+    AutoMutex _l(mLock);
+    sp<EffectModule> effect = mEffect.promote();
+    if (effect == 0 || mDisconnected) {
+        return DEAD_OBJECT;
+    }
     if (!mHasControl) {
         return INVALID_OPERATION;
     }
-    if (mEffect == 0) {
-        return DEAD_OBJECT;
-    }
 
     if (!mEnabled) {
         return NO_ERROR;
     }
     mEnabled = false;
 
-    if (mEffect->suspended()) {
+    if (effect->suspended()) {
         return NO_ERROR;
     }
 
-    status_t status = mEffect->setEnabled(false);
+    status_t status = effect->setEnabled(false);
 
-    sp<ThreadBase> thread = mEffect->thread().promote();
+    sp<ThreadBase> thread = effect->thread().promote();
     if (thread != 0) {
-        thread->checkSuspendOnEffectEnabled(mEffect, false, mEffect->sessionId());
+        thread->checkSuspendOnEffectEnabled(effect, false, effect->sessionId());
         if (thread->type() == ThreadBase::OFFLOAD) {
             PlaybackThread *t = (PlaybackThread *)thread.get();
             Mutex::Autolock _l(t->mLock);
@@ -1230,25 +1254,39 @@
 
 void AudioFlinger::EffectHandle::disconnect()
 {
+    ALOGV("%s %p", __FUNCTION__, this);
     disconnect(true);
 }
 
 void AudioFlinger::EffectHandle::disconnect(bool unpinIfLast)
 {
-    ALOGV("disconnect(%s)", unpinIfLast ? "true" : "false");
-    if (mEffect == 0) {
+    AutoMutex _l(mLock);
+    ALOGV("disconnect(%s) %p", unpinIfLast ? "true" : "false", this);
+    if (mDisconnected) {
+        if (unpinIfLast) {
+            android_errorWriteLog(0x534e4554, "32707507");
+        }
         return;
     }
-    // restore suspended effects if the disconnected handle was enabled and the last one.
-    if ((mEffect->disconnect(this, unpinIfLast) == 0) && mEnabled) {
-        sp<ThreadBase> thread = mEffect->thread().promote();
-        if (thread != 0) {
-            thread->checkSuspendOnEffectEnabled(mEffect, false, mEffect->sessionId());
+    mDisconnected = true;
+    sp<ThreadBase> thread;
+    {
+        sp<EffectModule> effect = mEffect.promote();
+        if (effect != 0) {
+            thread = effect->thread().promote();
+        }
+    }
+    if (thread != 0) {
+        thread->disconnectEffectHandle(this, unpinIfLast);
+    } else {
+        ALOGW("%s Effect handle %p disconnected after thread destruction", __FUNCTION__, this);
+        // try to cleanup as much as we can
+        sp<EffectModule> effect = mEffect.promote();
+        if (effect != 0) {
+            effect->disconnectHandle(this, unpinIfLast);
         }
     }
 
-    // release sp on module => module destructor can be called now
-    mEffect.clear();
     if (mClient != 0) {
         if (mCblk != NULL) {
             // unlike ~TrackBase(), mCblk is never a local new, so don't delete
@@ -1268,15 +1306,17 @@
                                              void *pReplyData)
 {
     ALOGVV("command(), cmdCode: %d, mHasControl: %d, mEffect: %p",
-            cmdCode, mHasControl, (mEffect == 0) ? 0 : mEffect.get());
+            cmdCode, mHasControl, mEffect.unsafe_get());
 
+    AutoMutex _l(mLock);
+    sp<EffectModule> effect = mEffect.promote();
+    if (effect == 0 || mDisconnected) {
+        return DEAD_OBJECT;
+    }
     // only get parameter command is permitted for applications not controlling the effect
     if (!mHasControl && cmdCode != EFFECT_CMD_GET_PARAM) {
         return INVALID_OPERATION;
     }
-    if (mEffect == 0) {
-        return DEAD_OBJECT;
-    }
     if (mClient == 0) {
         return INVALID_OPERATION;
     }
@@ -1287,36 +1327,54 @@
         // particular client process:  no risk to block the whole media server process or mixer
         // threads if we are stuck here
         Mutex::Autolock _l(mCblk->lock);
-        if (mCblk->clientIndex > EFFECT_PARAM_BUFFER_SIZE ||
-            mCblk->serverIndex > EFFECT_PARAM_BUFFER_SIZE) {
+
+        // keep local copy of index in case of client corruption b/32220769
+        const uint32_t clientIndex = mCblk->clientIndex;
+        const uint32_t serverIndex = mCblk->serverIndex;
+        if (clientIndex > EFFECT_PARAM_BUFFER_SIZE ||
+            serverIndex > EFFECT_PARAM_BUFFER_SIZE) {
             mCblk->serverIndex = 0;
             mCblk->clientIndex = 0;
             return BAD_VALUE;
         }
         status_t status = NO_ERROR;
-        while (mCblk->serverIndex < mCblk->clientIndex) {
-            int reply;
-            uint32_t rsize = sizeof(int);
-            int *p = (int *)(mBuffer + mCblk->serverIndex);
-            int size = *p++;
-            if (((uint8_t *)p + size) > mBuffer + mCblk->clientIndex) {
+        effect_param_t *param = NULL;
+        for (uint32_t index = serverIndex; index < clientIndex;) {
+            int *p = (int *)(mBuffer + index);
+            const int size = *p++;
+            if (size < 0
+                    || size > EFFECT_PARAM_BUFFER_SIZE
+                    || ((uint8_t *)p + size) > mBuffer + clientIndex) {
                 ALOGW("command(): invalid parameter block size");
+                status = BAD_VALUE;
                 break;
             }
-            effect_param_t *param = (effect_param_t *)p;
-            if (param->psize == 0 || param->vsize == 0) {
-                ALOGW("command(): null parameter or value size");
-                mCblk->serverIndex += size;
-                continue;
+
+            // copy to local memory in case of client corruption b/32220769
+            param = (effect_param_t *)realloc(param, size);
+            if (param == NULL) {
+                ALOGW("command(): out of memory");
+                status = NO_MEMORY;
+                break;
             }
-            uint32_t psize = sizeof(effect_param_t) +
-                             ((param->psize - 1) / sizeof(int) + 1) * sizeof(int) +
-                             param->vsize;
-            status_t ret = mEffect->command(EFFECT_CMD_SET_PARAM,
-                                            psize,
-                                            p,
+            memcpy(param, p, size);
+
+            int reply = 0;
+            uint32_t rsize = sizeof(reply);
+            status_t ret = effect->command(EFFECT_CMD_SET_PARAM,
+                                            size,
+                                            param,
                                             &rsize,
                                             &reply);
+
+            // verify shared memory: server index shouldn't change; client index can't go back.
+            if (serverIndex != mCblk->serverIndex
+                    || clientIndex > mCblk->clientIndex) {
+                android_errorWriteLog(0x534e4554, "32220769");
+                status = BAD_VALUE;
+                break;
+            }
+
             // stop at first error encountered
             if (ret != NO_ERROR) {
                 status = ret;
@@ -1326,8 +1384,9 @@
                 *(int *)pReplyData = reply;
                 break;
             }
-            mCblk->serverIndex += size;
+            index += size;
         }
+        free(param);
         mCblk->serverIndex = 0;
         mCblk->clientIndex = 0;
         return status;
@@ -1339,7 +1398,7 @@
         return disable();
     }
 
-    return mEffect->command(cmdCode, cmdSize, pCmdData, replySize, pReplyData);
+    return effect->command(cmdCode, cmdSize, pCmdData, replySize, pReplyData);
 }
 
 void AudioFlinger::EffectHandle::setControl(bool hasControl, bool signal, bool enabled)
@@ -1421,7 +1480,6 @@
     if (mOwnInBuffer) {
         delete mInBuffer;
     }
-
 }
 
 // getEffectFromDesc_l() must be called with ThreadBase::mLock held
@@ -1537,13 +1595,38 @@
     }
 }
 
-// addEffect_l() must be called with PlaybackThread::mLock held
+// createEffect_l() must be called with ThreadBase::mLock held
+status_t AudioFlinger::EffectChain::createEffect_l(sp<EffectModule>& effect,
+                                                   ThreadBase *thread,
+                                                   effect_descriptor_t *desc,
+                                                   int id,
+                                                   audio_session_t sessionId,
+                                                   bool pinned)
+{
+    Mutex::Autolock _l(mLock);
+    effect = new EffectModule(thread, this, desc, id, sessionId, pinned);
+    status_t lStatus = effect->status();
+    if (lStatus == NO_ERROR) {
+        lStatus = addEffect_ll(effect);
+    }
+    if (lStatus != NO_ERROR) {
+        effect.clear();
+    }
+    return lStatus;
+}
+
+// addEffect_l() must be called with ThreadBase::mLock held
 status_t AudioFlinger::EffectChain::addEffect_l(const sp<EffectModule>& effect)
 {
+    Mutex::Autolock _l(mLock);
+    return addEffect_ll(effect);
+}
+// addEffect_l() must be called with ThreadBase::mLock and EffectChain::mLock held
+status_t AudioFlinger::EffectChain::addEffect_ll(const sp<EffectModule>& effect)
+{
     effect_descriptor_t desc = effect->desc();
     uint32_t insertPref = desc.flags & EFFECT_FLAG_INSERT_MASK;
 
-    Mutex::Autolock _l(mLock);
     effect->setChain(this);
     sp<ThreadBase> thread = mThread.promote();
     if (thread == 0) {
@@ -1653,8 +1736,9 @@
     return NO_ERROR;
 }
 
-// removeEffect_l() must be called with PlaybackThread::mLock held
-size_t AudioFlinger::EffectChain::removeEffect_l(const sp<EffectModule>& effect)
+// removeEffect_l() must be called with ThreadBase::mLock held
+size_t AudioFlinger::EffectChain::removeEffect_l(const sp<EffectModule>& effect,
+                                                 bool release)
 {
     Mutex::Autolock _l(mLock);
     size_t size = mEffects.size();
@@ -1669,6 +1753,10 @@
                     mEffects[i]->state() == EffectModule::STOPPING) {
                 mEffects[i]->stop();
             }
+            if (release) {
+                mEffects[i]->release_l();
+            }
+
             if (type == EFFECT_FLAG_TYPE_AUXILIARY) {
                 delete[] effect->inBuffer();
             } else {
@@ -1680,6 +1768,7 @@
             mEffects.removeAt(i);
             ALOGV("removeEffect_l() effect %p, removed from chain %p at rank %zu", effect.get(),
                     this, i);
+
             break;
         }
     }
@@ -1687,7 +1776,7 @@
     return mEffects.size();
 }
 
-// setDevice_l() must be called with PlaybackThread::mLock held
+// setDevice_l() must be called with ThreadBase::mLock held
 void AudioFlinger::EffectChain::setDevice_l(audio_devices_t device)
 {
     size_t size = mEffects.size();
@@ -1696,7 +1785,7 @@
     }
 }
 
-// setMode_l() must be called with PlaybackThread::mLock held
+// setMode_l() must be called with ThreadBase::mLock held
 void AudioFlinger::EffectChain::setMode_l(audio_mode_t mode)
 {
     size_t size = mEffects.size();
@@ -1705,7 +1794,7 @@
     }
 }
 
-// setAudioSource_l() must be called with PlaybackThread::mLock held
+// setAudioSource_l() must be called with ThreadBase::mLock held
 void AudioFlinger::EffectChain::setAudioSource_l(audio_source_t source)
 {
     size_t size = mEffects.size();
@@ -1714,7 +1803,7 @@
     }
 }
 
-// setVolume_l() must be called with PlaybackThread::mLock or EffectChain::mLock held
+// setVolume_l() must be called with ThreadBase::mLock or EffectChain::mLock held
 bool AudioFlinger::EffectChain::setVolume_l(uint32_t *left, uint32_t *right, bool force)
 {
     uint32_t newLeft = *left;
@@ -1775,7 +1864,7 @@
     return hasControl;
 }
 
-// resetVolume_l() must be called with PlaybackThread::mLock or EffectChain::mLock held
+// resetVolume_l() must be called with ThreadBase::mLock or EffectChain::mLock held
 void AudioFlinger::EffectChain::resetVolume_l()
 {
     if ((mLeftVolume != UINT_MAX) && (mRightVolume != UINT_MAX)) {
@@ -1876,7 +1965,7 @@
                     effect->setSuspended(false);
                     effect->lock();
                     EffectHandle *handle = effect->controlHandle_l();
-                    if (handle != NULL && !handle->destroyed_l()) {
+                    if (handle != NULL && !handle->disconnected()) {
                         effect->setEnabled_l(handle->enabled());
                     }
                     effect->unlock();
diff --git a/services/audioflinger/Effects.h b/services/audioflinger/Effects.h
index a19b7fd..dc29ce0 100644
--- a/services/audioflinger/Effects.h
+++ b/services/audioflinger/Effects.h
@@ -25,10 +25,11 @@
 // state changes or resource modifications. Always respect the following order
 // if multiple mutexes must be acquired to avoid cross deadlock:
 // AudioFlinger -> ThreadBase -> EffectChain -> EffectModule
+// AudioHandle -> ThreadBase -> EffectChain -> EffectModule
 // In addition, methods that lock the AudioPolicyService mutex (getOutputForEffect(),
-// startOutput()...) should never be called with AudioFlinger or Threadbase mutex locked
-// to avoid cross deadlock with other clients calling AudioPolicyService methods that in turn
-// call AudioFlinger thus locking the same mutexes in the reverse order.
+// startOutput(), getInputForAttr(), releaseInput()...) should never be called with AudioFlinger or
+// Threadbase mutex locked to avoid cross deadlock with other clients calling AudioPolicyService
+// methods that in turn call AudioFlinger thus locking the same mutexes in the reverse order.
 
 // The EffectModule class is a wrapper object controlling the effect engine implementation
 // in the effect library. It prevents concurrent calls to process() and command() functions
@@ -45,7 +46,8 @@
                     const wp<AudioFlinger::EffectChain>& chain,
                     effect_descriptor_t *desc,
                     int id,
-                    audio_session_t sessionId);
+                    audio_session_t sessionId,
+                    bool pinned);
     virtual ~EffectModule();
 
     enum effect_state {
@@ -93,8 +95,9 @@
     const wp<ThreadBase>& thread() { return mThread; }
 
     status_t addHandle(EffectHandle *handle);
-    size_t disconnect(EffectHandle *handle, bool unpinIfLast);
-    size_t removeHandle(EffectHandle *handle);
+    ssize_t  disconnectHandle(EffectHandle *handle, bool unpinIfLast);
+    ssize_t removeHandle(EffectHandle *handle);
+    ssize_t removeHandle_l(EffectHandle *handle);
 
     const effect_descriptor_t& desc() const { return mDescriptor; }
     wp<EffectChain>&     chain() { return mChain; }
@@ -124,6 +127,7 @@
     status_t         setOffloaded(bool offloaded, audio_io_handle_t io);
     bool             isOffloaded() const;
     void             addEffectToHal_l();
+    void             release_l();
 
     void             dump(int fd, const Vector<String16>& args);
 
@@ -208,12 +212,17 @@
     bool enabled() const { return mEnabled; }
 
     // Getters
-    int id() const { return mEffect->id(); }
+    wp<EffectModule> effect() const { return mEffect; }
+    int id() const {
+        sp<EffectModule> effect = mEffect.promote();
+        if (effect == 0) {
+            return 0;
+        }
+        return effect->id();
+    }
     int priority() const { return mPriority; }
     bool hasControl() const { return mHasControl; }
-    sp<EffectModule> effect() const { return mEffect; }
-    // destroyed_l() must be called with the associated EffectModule mLock held
-    bool destroyed_l() const { return mDestroyed; }
+    bool disconnected() const { return mDisconnected; }
 
     void dumpToBuffer(char* buffer, size_t size);
 
@@ -222,7 +231,8 @@
     EffectHandle(const EffectHandle&);
     EffectHandle& operator =(const EffectHandle&);
 
-    sp<EffectModule> mEffect;           // pointer to controlled EffectModule
+    Mutex mLock;                        // protects IEffect method calls
+    wp<EffectModule> mEffect;           // pointer to controlled EffectModule
     sp<IEffectClient> mEffectClient;    // callback interface for client notifications
     /*const*/ sp<Client> mClient;       // client for shared memory allocation, see disconnect()
     sp<IMemory>         mCblkMemory;    // shared memory for control block
@@ -233,8 +243,7 @@
     bool mHasControl;                   // true if this handle is controlling the effect
     bool mEnabled;                      // cached enable state: needed when the effect is
                                         // restored after being suspended
-    bool mDestroyed;                    // Set to true by destructor. Access with EffectModule
-                                        // mLock held
+    bool mDisconnected;                 // Set to true by disconnect()
 };
 
 // the EffectChain class represents a group of effects associated to one audio session.
@@ -269,8 +278,15 @@
         mLock.unlock();
     }
 
+    status_t createEffect_l(sp<EffectModule>& effect,
+                            ThreadBase *thread,
+                            effect_descriptor_t *desc,
+                            int id,
+                            audio_session_t sessionId,
+                            bool pinned);
     status_t addEffect_l(const sp<EffectModule>& handle);
-    size_t removeEffect_l(const sp<EffectModule>& handle);
+    status_t addEffect_ll(const sp<EffectModule>& handle);
+    size_t removeEffect_l(const sp<EffectModule>& handle, bool release = false);
 
     audio_session_t sessionId() const { return mSessionId; }
     void setSessionId(audio_session_t sessionId) { mSessionId = sessionId; }
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 1d7b946..9966eeb 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -1267,7 +1267,8 @@
         audio_session_t sessionId,
         effect_descriptor_t *desc,
         int *enabled,
-        status_t *status)
+        status_t *status,
+        bool pinned)
 {
     sp<EffectModule> effect;
     sp<EffectHandle> handle;
@@ -1317,14 +1318,7 @@
             }
             effectRegistered = true;
             // create a new effect module if none present in the chain
-            effect = new EffectModule(this, chain, desc, id, sessionId);
-            lStatus = effect->status();
-            if (lStatus != NO_ERROR) {
-                goto Exit;
-            }
-            effect->setOffloaded(mType == OFFLOAD, mId);
-
-            lStatus = chain->addEffect_l(effect);
+            lStatus = chain->createEffect_l(effect, this, desc, id, sessionId, pinned);
             if (lStatus != NO_ERROR) {
                 goto Exit;
             }
@@ -1365,6 +1359,33 @@
     return handle;
 }
 
+void AudioFlinger::ThreadBase::disconnectEffectHandle(EffectHandle *handle,
+                                                      bool unpinIfLast)
+{
+    bool remove = false;
+    sp<EffectModule> effect;
+    {
+        Mutex::Autolock _l(mLock);
+
+        effect = handle->effect().promote();
+        if (effect == 0) {
+            return;
+        }
+        // restore suspended effects if the disconnected handle was enabled and the last one.
+        remove = (effect->removeHandle(handle) == 0) && (!effect->isPinned() || unpinIfLast);
+        if (remove) {
+            removeEffect_l(effect, true);
+        }
+    }
+    if (remove) {
+        mAudioFlinger->updateOrphanEffectChains(effect);
+        AudioSystem::unregisterEffect(effect->id());
+        if (handle->enabled()) {
+            checkSuspendOnEffectEnabled(effect, false, effect->sessionId());
+        }
+    }
+}
+
 sp<AudioFlinger::EffectModule> AudioFlinger::ThreadBase::getEffect(audio_session_t sessionId,
         int effectId)
 {
@@ -1425,9 +1446,9 @@
     return NO_ERROR;
 }
 
-void AudioFlinger::ThreadBase::removeEffect_l(const sp<EffectModule>& effect) {
+void AudioFlinger::ThreadBase::removeEffect_l(const sp<EffectModule>& effect, bool release) {
 
-    ALOGV("removeEffect_l() %p effect %p", this, effect.get());
+    ALOGV("%s %p effect %p", __FUNCTION__, this, effect.get());
     effect_descriptor_t desc = effect->desc();
     if ((desc.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) {
         detachAuxEffect_l(effect->id());
@@ -1436,7 +1457,7 @@
     sp<EffectChain> chain = effect->chain().promote();
     if (chain != 0) {
         // remove effect chain if removing last effect
-        if (chain->removeEffect_l(effect) == 0) {
+        if (chain->removeEffect_l(effect, release) == 0) {
             removeEffectChain_l(chain);
         }
     } else {
@@ -1602,6 +1623,7 @@
     dumpInternals(fd, args);
     dumpTracks(fd, args);
     dumpEffectChains(fd, args);
+    mLocalLog.dump(fd, args, "  " /* prefix */);
 }
 
 void AudioFlinger::PlaybackThread::dumpTracks(int fd, const Vector<String16>& args __unused)
@@ -2072,6 +2094,10 @@
             chain->incActiveTrackCnt();
         }
 
+        char buffer[256];
+        track->dump(buffer, ARRAY_SIZE(buffer), false /* active */);
+        mLocalLog.log("addTrack_l    (%p) %s", track.get(), buffer + 4); // log for analysis
+
         status = NO_ERROR;
     }
 
@@ -2097,6 +2123,11 @@
 void AudioFlinger::PlaybackThread::removeTrack_l(const sp<Track>& track)
 {
     track->triggerEvents(AudioSystem::SYNC_EVENT_PRESENTATION_COMPLETE);
+
+    char buffer[256];
+    track->dump(buffer, ARRAY_SIZE(buffer), false /* active */);
+    mLocalLog.log("removeTrack_l (%p) %s", track.get(), buffer + 4); // log for analysis
+
     mTracks.remove(track);
     deleteTrackName_l(track->name());
     // redundant as track is about to be destroyed, for dumpsys only
@@ -3264,6 +3295,10 @@
             }
             if (track->isTerminated()) {
                 removeTrack_l(track);
+            } else { // inactive but not terminated
+                char buffer[256];
+                track->dump(buffer, ARRAY_SIZE(buffer), false /* active */);
+                mLocalLog.log("removeTracks_l(%p) %s", track.get(), buffer + 4);
             }
         }
     }
@@ -3710,6 +3745,15 @@
         FastMixerStateQueue *sq = mFastMixer->sq();
         FastMixerState *state = sq->begin();
         if (!(state->mCommand & FastMixerState::IDLE)) {
+            // Report any frames trapped in the Monopipe
+            MonoPipe *monoPipe = (MonoPipe *)mPipeSink.get();
+            const long long pipeFrames = monoPipe->maxFrames() - monoPipe->availableToWrite();
+            mLocalLog.log("threadLoop_standby: framesWritten:%lld  suspendedFrames:%lld  "
+                    "monoPipeWritten:%lld  monoPipeLeft:%lld",
+                    (long long)mFramesWritten, (long long)mSuspendedFrames,
+                    (long long)mPipeSink->framesWritten(), pipeFrames);
+            mLocalLog.log("threadLoop_standby: %s", mTimestamp.toString().c_str());
+
             state->mCommand = FastMixerState::COLD_IDLE;
             state->mColdFutexAddr = &mFastMixerFutex;
             state->mColdGen++;
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index 5235cde..d261ea5 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -295,7 +295,8 @@
                                     audio_session_t sessionId,
                                     effect_descriptor_t *desc,
                                     int *enabled,
-                                    status_t *status /*non-NULL*/);
+                                    status_t *status /*non-NULL*/,
+                                    bool pinned);
 
                 // return values for hasAudioSession (bit field)
                 enum effect_state {
@@ -334,7 +335,9 @@
                 status_t addEffect_l(const sp< EffectModule>& effect);
                 // remove and effect module. Also removes the effect chain is this was the last
                 // effect
-                void removeEffect_l(const sp< EffectModule>& effect);
+                void removeEffect_l(const sp< EffectModule>& effect, bool release = false);
+                // disconnect an effect handle from module and destroy module if last handle
+                void disconnectEffectHandle(EffectHandle *handle, bool unpinIfLast);
                 // detach all tracks connected to an auxiliary effect
     virtual     void detachAuxEffect_l(int effectId __unused) {}
                 // returns a combination of:
@@ -861,6 +864,78 @@
     uint32_t                mScreenState;   // cached copy of gScreenState
     static const size_t     kFastMixerLogSize = 4 * 1024;
     sp<NBLog::Writer>       mFastMixerNBLogWriter;
+
+    // Do not call from a sched_fifo thread as it uses a system time call
+    // and obtains a local mutex.
+    class LocalLog {
+    public:
+        void log(const char *fmt, ...) {
+            va_list val;
+            va_start(val, fmt);
+
+            // format to buffer
+            char buffer[512];
+            int length = vsnprintf(buffer, sizeof(buffer), fmt, val);
+            if (length >= (signed)sizeof(buffer)) {
+                length = sizeof(buffer) - 1;
+            }
+
+            // strip out trailing newline
+            while (length > 0 && buffer[length - 1] == '\n') {
+                buffer[--length] = 0;
+            }
+
+            // store in circular array
+            AutoMutex _l(mLock);
+            mLog.emplace_back(
+                    std::make_pair(systemTime(SYSTEM_TIME_REALTIME), std::string(buffer)));
+            if (mLog.size() > kLogSize) {
+                mLog.pop_front();
+            }
+
+            va_end(val);
+        }
+
+        void dump(int fd, const Vector<String16>& args, const char *prefix = "") {
+            if (!AudioFlinger::dumpTryLock(mLock)) return; // a local lock, shouldn't happen
+            if (mLog.size() > 0) {
+                bool dumpAll = false;
+                for (const auto &arg : args) {
+                    if (arg == String16("--locallog")) {
+                        dumpAll = true;
+                    }
+                }
+
+                dprintf(fd, "Local Log:\n");
+                auto it = mLog.begin();
+                if (!dumpAll && mLog.size() > kLogPrint) {
+                    it += (mLog.size() - kLogPrint);
+                }
+                for (; it != mLog.end(); ++it) {
+                    const int64_t ns = it->first;
+                    const int ns_per_sec = 1000000000;
+                    const time_t sec = ns / ns_per_sec;
+                    struct tm tm;
+                    localtime_r(&sec, &tm);
+
+                    dprintf(fd, "%s%02d-%02d %02d:%02d:%02d.%03d %s\n",
+                            prefix,
+                            tm.tm_mon + 1, // localtime_r uses months in 0 - 11 range
+                            tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec,
+                            (int)(ns % ns_per_sec / 1000000),
+                            it->second.c_str());
+                }
+            }
+            mLock.unlock();
+        }
+
+    private:
+        Mutex mLock;
+        static const size_t kLogSize = 256; // full history
+        static const size_t kLogPrint = 32; // default print history
+        std::deque<std::pair<int64_t, std::string>> mLog;
+    } mLocalLog;
+
 public:
     virtual     bool        hasFastMixer() const = 0;
     virtual     FastTrackUnderruns getFastTrackUnderruns(size_t fastIndex __unused) const
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index 8f134c1..e8e27e4 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -459,7 +459,7 @@
 /*static*/ void AudioFlinger::PlaybackThread::Track::appendDumpHeader(String8& result)
 {
     result.append("    Name Active Client Type      Fmt Chn mask Session fCount S F SRate  "
-                  "L dB  R dB    Server Main buf  Aux Buf Flags UndFrmCnt\n");
+                  "L dB  R dB    Server Main buf  Aux buf Flags UndFrmCnt  Flushed\n");
 }
 
 void AudioFlinger::PlaybackThread::Track::dump(char* buffer, size_t size, bool active)
@@ -526,7 +526,7 @@
         break;
     }
     snprintf(&buffer[8], size-8, " %6s %6u %4u %08X %08X %7u %6zu %1c %1d %5u %5.2g %5.2g  "
-                                 "%08X %p %p 0x%03X %9u%c\n",
+                                 "%08X %08zX %08zX 0x%03X %9u%c %7u\n",
             active ? "yes" : "no",
             (mClient == 0) ? getpid_cached : mClient->pid(),
             mStreamType,
@@ -540,11 +540,12 @@
             20.0 * log10(float_from_gain(gain_minifloat_unpack_left(vlr))),
             20.0 * log10(float_from_gain(gain_minifloat_unpack_right(vlr))),
             mCblk->mServer,
-            mMainBuffer,
-            mAuxBuffer,
+            (size_t)mMainBuffer, // use %zX as %p appends 0x
+            (size_t)mAuxBuffer,  // use %zX as %p appends 0x
             mCblk->mFlags,
             mAudioTrackServerProxy->getUnderrunFrames(),
-            nowInUnderrun);
+            nowInUnderrun,
+            (unsigned)mAudioTrackServerProxy->framesFlushed() % 10000000); // 7 digits
 }
 
 uint32_t AudioFlinger::PlaybackThread::Track::sampleRate() const {
diff --git a/services/audiopolicy/Android.mk b/services/audiopolicy/Android.mk
index 3fb545d..9f3488d 100644
--- a/services/audiopolicy/Android.mk
+++ b/services/audiopolicy/Android.mk
@@ -4,19 +4,9 @@
 
 LOCAL_SRC_FILES:= \
     service/AudioPolicyService.cpp \
-    service/AudioPolicyEffects.cpp
-
-ifeq ($(USE_LEGACY_AUDIO_POLICY), 1)
-LOCAL_SRC_FILES += \
-    service/AudioPolicyInterfaceImplLegacy.cpp \
-    service/AudioPolicyClientImplLegacy.cpp
-
-    LOCAL_CFLAGS += -DUSE_LEGACY_AUDIO_POLICY
-else
-LOCAL_SRC_FILES += \
+    service/AudioPolicyEffects.cpp \
     service/AudioPolicyInterfaceImpl.cpp \
     service/AudioPolicyClientImpl.cpp
-endif
 
 LOCAL_C_INCLUDES := \
     $(TOPDIR)frameworks/av/services/audioflinger \
@@ -32,12 +22,8 @@
     libbinder \
     libaudioclient \
     libhardware_legacy \
-    libserviceutility
-
-ifneq ($(USE_LEGACY_AUDIO_POLICY), 1)
-LOCAL_SHARED_LIBRARIES += \
+    libserviceutility \
     libaudiopolicymanager
-endif
 
 LOCAL_STATIC_LIBRARIES := \
     libmedia_helper \
@@ -52,8 +38,6 @@
 
 include $(BUILD_SHARED_LIBRARY)
 
-ifneq ($(USE_LEGACY_AUDIO_POLICY), 1)
-
 include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES:= managerdefault/AudioPolicyManager.cpp
@@ -136,7 +120,6 @@
 include $(BUILD_SHARED_LIBRARY)
 
 endif
-endif
 
 #######################################################################
 # Recursive call sub-folder Android.mk
diff --git a/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp b/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp
index 818da72..a224004 100644
--- a/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp
@@ -384,6 +384,7 @@
             sp<AudioPort> source = ctx->findPortByTagName(String8(devTag));
             if (source == NULL) {
                 ALOGE("%s: no source found with name=%s", __FUNCTION__, devTag);
+                free(sourcesLiteral);
                 return BAD_VALUE;
             }
             sources.add(source);
diff --git a/services/audiopolicy/config/a2dp_audio_policy_configuration.xml b/services/audiopolicy/config/a2dp_audio_policy_configuration.xml
index ced7463..7bcab5c 100644
--- a/services/audiopolicy/config/a2dp_audio_policy_configuration.xml
+++ b/services/audiopolicy/config/a2dp_audio_policy_configuration.xml
@@ -2,11 +2,7 @@
 <!-- A2dp Audio HAL Audio Policy Configuration file -->
 <module name="a2dp" halVersion="2.0">
     <mixPorts>
-        <mixPort name="a2dp output" role="source">
-            <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
-                     samplingRates="44100"
-                     channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
-        </mixPort>
+        <mixPort name="a2dp output" role="source"/>
         <mixPort name="a2dp input" role="sink">
             <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
                      samplingRates="44100,48000"
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 5ef0216..a714041 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -4477,9 +4477,7 @@
 
 bool AudioPolicyManager::streamsMatchForvolume(audio_stream_type_t stream1,
                                                audio_stream_type_t stream2) {
-    return ((stream1 == stream2) ||
-            ((stream1 == AUDIO_STREAM_ACCESSIBILITY) && (stream2 == AUDIO_STREAM_MUSIC)) ||
-            ((stream1 == AUDIO_STREAM_MUSIC) && (stream2 == AUDIO_STREAM_ACCESSIBILITY)));
+    return (stream1 == stream2);
 }
 
 uint32_t AudioPolicyManager::getStrategyForStream(audio_stream_type_t stream) {
diff --git a/services/audiopolicy/service/AudioPolicyClientImplLegacy.cpp b/services/audiopolicy/service/AudioPolicyClientImplLegacy.cpp
deleted file mode 100644
index aa228aa..0000000
--- a/services/audiopolicy/service/AudioPolicyClientImplLegacy.cpp
+++ /dev/null
@@ -1,316 +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_TAG "AudioPolicyService"
-//#define LOG_NDEBUG 0
-
-#include "Configuration.h"
-#undef __STRICT_ANSI__
-#define __STDINT_LIMITS
-#define __STDC_LIMIT_MACROS
-#include <stdint.h>
-
-#include <sys/time.h>
-#include <binder/IServiceManager.h>
-#include <utils/Log.h>
-#include <cutils/properties.h>
-#include <binder/IPCThreadState.h>
-#include <utils/String16.h>
-#include <utils/threads.h>
-#include "AudioPolicyService.h"
-#include "ServiceUtilities.h"
-#include <hardware_legacy/power.h>
-#include <media/AudioEffect.h>
-//#include <media/IAudioFlinger.h>
-
-#include <hardware/hardware.h>
-#include <system/audio.h>
-#include <system/audio_policy.h>
-#include <hardware/audio_policy.h>
-#include <audio_effects/audio_effects_conf.h>
-#include <media/AudioParameter.h>
-
-
-namespace android {
-
-/* implementation of the interface to the policy manager */
-extern "C" {
-
-audio_module_handle_t aps_load_hw_module(void *service __unused,
-                                             const char *name)
-{
-    sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
-    if (af == 0) {
-        ALOGW("%s: could not get AudioFlinger", __func__);
-        return AUDIO_MODULE_HANDLE_NONE;
-    }
-
-    return af->loadHwModule(name);
-}
-
-static audio_io_handle_t open_output(audio_module_handle_t module,
-                                    audio_devices_t *pDevices,
-                                    uint32_t *pSamplingRate,
-                                    audio_format_t *pFormat,
-                                    audio_channel_mask_t *pChannelMask,
-                                    uint32_t *pLatencyMs,
-                                    audio_output_flags_t flags,
-                                    const audio_offload_info_t *offloadInfo)
-{
-    sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
-    if (af == 0) {
-        ALOGW("%s: could not get AudioFlinger", __func__);
-        return AUDIO_IO_HANDLE_NONE;
-    }
-
-    if (pSamplingRate == NULL || pFormat == NULL || pChannelMask == NULL ||
-            pDevices == NULL || pLatencyMs == NULL) {
-        return AUDIO_IO_HANDLE_NONE;
-    }
-    audio_config_t config = AUDIO_CONFIG_INITIALIZER;
-    config.sample_rate = *pSamplingRate;
-    config.format = *pFormat;
-    config.channel_mask = *pChannelMask;
-    if (offloadInfo != NULL) {
-        config.offload_info = *offloadInfo;
-    }
-    audio_io_handle_t output = AUDIO_IO_HANDLE_NONE;
-    status_t status = af->openOutput(module, &output, &config, pDevices,
-                                     String8(""), pLatencyMs, flags);
-    if (status == NO_ERROR) {
-        *pSamplingRate = config.sample_rate;
-        *pFormat = config.format;
-        *pChannelMask = config.channel_mask;
-        if (offloadInfo != NULL) {
-            *((audio_offload_info_t *)offloadInfo) = config.offload_info;
-        }
-    }
-    return output;
-}
-
-// deprecated: replaced by aps_open_output_on_module()
-audio_io_handle_t aps_open_output(void *service __unused,
-                                         audio_devices_t *pDevices,
-                                         uint32_t *pSamplingRate,
-                                         audio_format_t *pFormat,
-                                         audio_channel_mask_t *pChannelMask,
-                                         uint32_t *pLatencyMs,
-                                         audio_output_flags_t flags)
-{
-    return open_output(AUDIO_MODULE_HANDLE_NONE, pDevices, pSamplingRate, pFormat, pChannelMask,
-                          pLatencyMs, flags, NULL);
-}
-
-audio_io_handle_t aps_open_output_on_module(void *service __unused,
-                                                   audio_module_handle_t module,
-                                                   audio_devices_t *pDevices,
-                                                   uint32_t *pSamplingRate,
-                                                   audio_format_t *pFormat,
-                                                   audio_channel_mask_t *pChannelMask,
-                                                   uint32_t *pLatencyMs,
-                                                   audio_output_flags_t flags,
-                                                   const audio_offload_info_t *offloadInfo)
-{
-    return open_output(module, pDevices, pSamplingRate, pFormat, pChannelMask,
-                          pLatencyMs, flags, offloadInfo);
-}
-
-audio_io_handle_t aps_open_dup_output(void *service __unused,
-                                                 audio_io_handle_t output1,
-                                                 audio_io_handle_t output2)
-{
-    sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
-    if (af == 0) {
-        ALOGW("%s: could not get AudioFlinger", __func__);
-        return 0;
-    }
-    return af->openDuplicateOutput(output1, output2);
-}
-
-int aps_close_output(void *service __unused, audio_io_handle_t output)
-{
-    sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
-    if (af == 0) {
-        return PERMISSION_DENIED;
-    }
-
-    return af->closeOutput(output);
-}
-
-int aps_suspend_output(void *service __unused, audio_io_handle_t output)
-{
-    sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
-    if (af == 0) {
-        ALOGW("%s: could not get AudioFlinger", __func__);
-        return PERMISSION_DENIED;
-    }
-
-    return af->suspendOutput(output);
-}
-
-int aps_restore_output(void *service __unused, audio_io_handle_t output)
-{
-    sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
-    if (af == 0) {
-        ALOGW("%s: could not get AudioFlinger", __func__);
-        return PERMISSION_DENIED;
-    }
-
-    return af->restoreOutput(output);
-}
-
-static audio_io_handle_t open_input(audio_module_handle_t module,
-                                    audio_devices_t *pDevices,
-                                    uint32_t *pSamplingRate,
-                                    audio_format_t *pFormat,
-                                    audio_channel_mask_t *pChannelMask)
-{
-    sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
-    if (af == 0) {
-        ALOGW("%s: could not get AudioFlinger", __func__);
-        return AUDIO_IO_HANDLE_NONE;
-    }
-
-    if (pSamplingRate == NULL || pFormat == NULL || pChannelMask == NULL || pDevices == NULL) {
-        return AUDIO_IO_HANDLE_NONE;
-    }
-
-    if (((*pDevices & AUDIO_DEVICE_IN_REMOTE_SUBMIX) == AUDIO_DEVICE_IN_REMOTE_SUBMIX)
-            && !captureAudioOutputAllowed(IPCThreadState::self()->getCallingPid(),
-                                          IPCThreadState::self()->getCallingUid())) {
-        ALOGE("open_input() permission denied: capture not allowed");
-        return AUDIO_IO_HANDLE_NONE;
-    }
-
-    audio_config_t config = AUDIO_CONFIG_INITIALIZER;;
-    config.sample_rate = *pSamplingRate;
-    config.format = *pFormat;
-    config.channel_mask = *pChannelMask;
-    audio_io_handle_t input = AUDIO_IO_HANDLE_NONE;
-    status_t status = af->openInput(module, &input, &config, pDevices,
-                                    String8(""), AUDIO_SOURCE_MIC, AUDIO_INPUT_FLAG_FAST /*FIXME*/);
-    if (status == NO_ERROR) {
-        *pSamplingRate = config.sample_rate;
-        *pFormat = config.format;
-        *pChannelMask = config.channel_mask;
-    }
-    return input;
-}
-
-
-// deprecated: replaced by aps_open_input_on_module(), and acoustics parameter is ignored
-audio_io_handle_t aps_open_input(void *service __unused,
-                                        audio_devices_t *pDevices,
-                                        uint32_t *pSamplingRate,
-                                        audio_format_t *pFormat,
-                                        audio_channel_mask_t *pChannelMask,
-                                        audio_in_acoustics_t acoustics __unused)
-{
-    return  open_input(AUDIO_MODULE_HANDLE_NONE, pDevices, pSamplingRate, pFormat, pChannelMask);
-}
-
-audio_io_handle_t aps_open_input_on_module(void *service __unused,
-                                                  audio_module_handle_t module,
-                                                  audio_devices_t *pDevices,
-                                                  uint32_t *pSamplingRate,
-                                                  audio_format_t *pFormat,
-                                                  audio_channel_mask_t *pChannelMask)
-{
-    return  open_input(module, pDevices, pSamplingRate, pFormat, pChannelMask);
-}
-
-int aps_close_input(void *service __unused, audio_io_handle_t input)
-{
-    sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
-    if (af == 0) {
-        return PERMISSION_DENIED;
-    }
-
-    return af->closeInput(input);
-}
-
-int aps_invalidate_stream(void *service __unused, audio_stream_type_t stream)
-{
-    sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
-    if (af == 0) {
-        return PERMISSION_DENIED;
-    }
-
-    return af->invalidateStream(stream);
-}
-
-int aps_move_effects(void *service __unused, audio_session_t session,
-                                audio_io_handle_t src_output,
-                                audio_io_handle_t dst_output)
-{
-    sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
-    if (af == 0) {
-        return PERMISSION_DENIED;
-    }
-
-    return af->moveEffects(session, src_output, dst_output);
-}
-
-char * aps_get_parameters(void *service __unused, audio_io_handle_t io_handle,
-                                     const char *keys)
-{
-    String8 result = AudioSystem::getParameters(io_handle, String8(keys));
-    return strdup(result.string());
-}
-
-void aps_set_parameters(void *service, audio_io_handle_t io_handle,
-                                   const char *kv_pairs, int delay_ms)
-{
-    AudioPolicyService *audioPolicyService = (AudioPolicyService *)service;
-
-    audioPolicyService->setParameters(io_handle, kv_pairs, delay_ms);
-}
-
-int aps_set_stream_volume(void *service, audio_stream_type_t stream,
-                                     float volume, audio_io_handle_t output,
-                                     int delay_ms)
-{
-    AudioPolicyService *audioPolicyService = (AudioPolicyService *)service;
-
-    return audioPolicyService->setStreamVolume(stream, volume, output,
-                                               delay_ms);
-}
-
-int aps_start_tone(void *service, audio_policy_tone_t tone,
-                              audio_stream_type_t stream)
-{
-    AudioPolicyService *audioPolicyService = (AudioPolicyService *)service;
-
-    return audioPolicyService->startTone(tone, stream);
-}
-
-int aps_stop_tone(void *service)
-{
-    AudioPolicyService *audioPolicyService = (AudioPolicyService *)service;
-
-    return audioPolicyService->stopTone();
-}
-
-int aps_set_voice_volume(void *service, float volume, int delay_ms)
-{
-    AudioPolicyService *audioPolicyService = (AudioPolicyService *)service;
-
-    return audioPolicyService->setVoiceVolume(volume, delay_ms);
-}
-
-}; // extern "C"
-
-}; // namespace android
diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
index 53c54bb..0c23080 100644
--- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
@@ -400,7 +400,6 @@
     sp<AudioPolicyEffects>audioPolicyEffects;
     {
         Mutex::Autolock _l(mLock);
-        mAudioPolicyManager->releaseInput(input, session);
         audioPolicyEffects = mAudioPolicyEffects;
     }
     if (audioPolicyEffects != 0) {
@@ -410,6 +409,10 @@
             ALOGW("Failed to release effects on input %d", input);
         }
     }
+    {
+        Mutex::Autolock _l(mLock);
+        mAudioPolicyManager->releaseInput(input, session);
+    }
 }
 
 status_t AudioPolicyService::initStreamVolume(audio_stream_type_t stream,
diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImplLegacy.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImplLegacy.cpp
deleted file mode 100644
index a5b96fe..0000000
--- a/services/audiopolicy/service/AudioPolicyInterfaceImplLegacy.cpp
+++ /dev/null
@@ -1,633 +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_TAG "AudioPolicyService"
-//#define LOG_NDEBUG 0
-
-#include <utils/Log.h>
-#include "AudioPolicyService.h"
-#include "ServiceUtilities.h"
-
-#include <system/audio.h>
-#include <system/audio_policy.h>
-#include <hardware/audio_policy.h>
-#include <media/AudioPolicyHelper.h>
-
-namespace android {
-
-
-// ----------------------------------------------------------------------------
-
-status_t AudioPolicyService::setDeviceConnectionState(audio_devices_t device,
-                                                  audio_policy_dev_state_t state,
-                                                  const char *device_address,
-                                                  const char *device_name __unused)
-{
-    if (mpAudioPolicy == NULL) {
-        return NO_INIT;
-    }
-    if (!settingsAllowed()) {
-        return PERMISSION_DENIED;
-    }
-    if (!audio_is_output_device(device) && !audio_is_input_device(device)) {
-        return BAD_VALUE;
-    }
-    if (state != AUDIO_POLICY_DEVICE_STATE_AVAILABLE &&
-            state != AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE) {
-        return BAD_VALUE;
-    }
-
-    ALOGV("setDeviceConnectionState()");
-    Mutex::Autolock _l(mLock);
-    return mpAudioPolicy->set_device_connection_state(mpAudioPolicy, device,
-                                                      state, device_address);
-}
-
-audio_policy_dev_state_t AudioPolicyService::getDeviceConnectionState(
-                                                              audio_devices_t device,
-                                                              const char *device_address)
-{
-    if (mpAudioPolicy == NULL) {
-        return AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE;
-    }
-    return mpAudioPolicy->get_device_connection_state(mpAudioPolicy, device,
-                                                      device_address);
-}
-
-status_t AudioPolicyService::setPhoneState(audio_mode_t state)
-{
-    if (mpAudioPolicy == NULL) {
-        return NO_INIT;
-    }
-    if (!settingsAllowed()) {
-        return PERMISSION_DENIED;
-    }
-    if (uint32_t(state) >= AUDIO_MODE_CNT) {
-        return BAD_VALUE;
-    }
-
-    ALOGV("setPhoneState()");
-
-    // TODO: check if it is more appropriate to do it in platform specific policy manager
-    AudioSystem::setMode(state);
-
-    Mutex::Autolock _l(mLock);
-    mpAudioPolicy->set_phone_state(mpAudioPolicy, state);
-    mPhoneState = state;
-    return NO_ERROR;
-}
-
-audio_mode_t AudioPolicyService::getPhoneState()
-{
-    Mutex::Autolock _l(mLock);
-    return mPhoneState;
-}
-
-status_t AudioPolicyService::setForceUse(audio_policy_force_use_t usage,
-                                         audio_policy_forced_cfg_t config)
-{
-    if (mpAudioPolicy == NULL) {
-        return NO_INIT;
-    }
-    if (!settingsAllowed()) {
-        return PERMISSION_DENIED;
-    }
-    if (usage < 0 || usage >= AUDIO_POLICY_FORCE_USE_CNT) {
-        return BAD_VALUE;
-    }
-    if (config < 0 || config >= AUDIO_POLICY_FORCE_CFG_CNT) {
-        return BAD_VALUE;
-    }
-    ALOGV("setForceUse()");
-    Mutex::Autolock _l(mLock);
-    mpAudioPolicy->set_force_use(mpAudioPolicy, usage, config);
-    return NO_ERROR;
-}
-
-audio_policy_forced_cfg_t AudioPolicyService::getForceUse(audio_policy_force_use_t usage)
-{
-    if (mpAudioPolicy == NULL) {
-        return AUDIO_POLICY_FORCE_NONE;
-    }
-    if (usage < 0 || usage >= AUDIO_POLICY_FORCE_USE_CNT) {
-        return AUDIO_POLICY_FORCE_NONE;
-    }
-    return mpAudioPolicy->get_force_use(mpAudioPolicy, 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)
-{
-    if (uint32_t(stream) >= AUDIO_STREAM_PUBLIC_CNT) {
-        return AUDIO_IO_HANDLE_NONE;
-    }
-    if (mpAudioPolicy == NULL) {
-        return AUDIO_IO_HANDLE_NONE;
-    }
-    ALOGV("getOutput()");
-    Mutex::Autolock _l(mLock);
-    return mpAudioPolicy->get_output(mpAudioPolicy, stream, samplingRate,
-                                    format, channelMask, flags, offloadInfo);
-}
-
-status_t AudioPolicyService::startOutput(audio_io_handle_t output,
-                                         audio_stream_type_t stream,
-                                         audio_session_t session)
-{
-    if (uint32_t(stream) >= AUDIO_STREAM_PUBLIC_CNT) {
-        return BAD_VALUE;
-    }
-    if (mpAudioPolicy == NULL) {
-        return NO_INIT;
-    }
-    ALOGV("startOutput()");
-    // create audio processors according to stream
-    sp<AudioPolicyEffects>audioPolicyEffects;
-    {
-        Mutex::Autolock _l(mLock);
-        audioPolicyEffects = mAudioPolicyEffects;
-    }
-    if (audioPolicyEffects != 0) {
-        status_t status = audioPolicyEffects->addOutputSessionEffects(output, stream, session);
-        if (status != NO_ERROR && status != ALREADY_EXISTS) {
-            ALOGW("Failed to add effects on session %d", session);
-        }
-    }
-
-    Mutex::Autolock _l(mLock);
-    return mpAudioPolicy->start_output(mpAudioPolicy, output, stream, session);
-}
-
-status_t AudioPolicyService::stopOutput(audio_io_handle_t output,
-                                        audio_stream_type_t stream,
-                                        audio_session_t session)
-{
-    if (uint32_t(stream) >= AUDIO_STREAM_PUBLIC_CNT) {
-        return BAD_VALUE;
-    }
-    if (mpAudioPolicy == NULL) {
-        return NO_INIT;
-    }
-    ALOGV("stopOutput()");
-    mOutputCommandThread->stopOutputCommand(output, stream, session);
-    return NO_ERROR;
-}
-
-status_t  AudioPolicyService::doStopOutput(audio_io_handle_t output,
-                                      audio_stream_type_t stream,
-                                      audio_session_t session)
-{
-    ALOGV("doStopOutput from tid %d", gettid());
-    // release audio processors from the stream
-    sp<AudioPolicyEffects>audioPolicyEffects;
-    {
-        Mutex::Autolock _l(mLock);
-        audioPolicyEffects = mAudioPolicyEffects;
-    }
-    if (audioPolicyEffects != 0) {
-        status_t status = audioPolicyEffects->releaseOutputSessionEffects(output, stream, session);
-        if (status != NO_ERROR && status != ALREADY_EXISTS) {
-            ALOGW("Failed to release effects on session %d", session);
-        }
-    }
-    Mutex::Autolock _l(mLock);
-    return mpAudioPolicy->stop_output(mpAudioPolicy, output, stream, session);
-}
-
-void AudioPolicyService::releaseOutput(audio_io_handle_t output,
-                                       audio_stream_type_t stream,
-                                       audio_session_t session)
-{
-    if (mpAudioPolicy == NULL) {
-        return;
-    }
-    ALOGV("releaseOutput()");
-    mOutputCommandThread->releaseOutputCommand(output, stream, session);
-}
-
-void AudioPolicyService::doReleaseOutput(audio_io_handle_t output,
-                                         audio_stream_type_t stream __unused,
-                                         audio_session_t session __unused)
-{
-    ALOGV("doReleaseOutput from tid %d", gettid());
-    Mutex::Autolock _l(mLock);
-    mpAudioPolicy->release_output(mpAudioPolicy, output);
-}
-
-status_t AudioPolicyService::getInputForAttr(const audio_attributes_t *attr,
-                                             audio_io_handle_t *input,
-                                             audio_session_t session,
-                                             pid_t pid __unused,
-                                             uid_t uid __unused,
-                                             uint32_t samplingRate,
-                                             audio_format_t format,
-                                             audio_channel_mask_t channelMask,
-                                             audio_input_flags_t flags __unused,
-                                             audio_port_handle_t selectedDeviceId __unused)
-{
-    if (mpAudioPolicy == NULL) {
-        return NO_INIT;
-    }
-
-    audio_source_t inputSource = attr->source;
-
-    // already checked by client, but double-check in case the client wrapper is bypassed
-    if (inputSource >= AUDIO_SOURCE_CNT && inputSource != AUDIO_SOURCE_HOTWORD &&
-        inputSource != AUDIO_SOURCE_FM_TUNER) {
-        return BAD_VALUE;
-    }
-
-    if (inputSource == AUDIO_SOURCE_DEFAULT) {
-        inputSource = AUDIO_SOURCE_MIC;
-    }
-
-    if ((inputSource == AUDIO_SOURCE_HOTWORD) && !captureHotwordAllowed()) {
-        return BAD_VALUE;
-    }
-
-    sp<AudioPolicyEffects>audioPolicyEffects;
-    {
-        Mutex::Autolock _l(mLock);
-        // the audio_in_acoustics_t parameter is ignored by get_input()
-        *input = mpAudioPolicy->get_input(mpAudioPolicy, inputSource, samplingRate,
-                                             format, channelMask, (audio_in_acoustics_t) 0);
-        audioPolicyEffects = mAudioPolicyEffects;
-    }
-    if (*input == AUDIO_IO_HANDLE_NONE) {
-        return INVALID_OPERATION;
-    }
-
-    if (audioPolicyEffects != 0) {
-        // create audio pre processors according to input source
-        status_t status = audioPolicyEffects->addInputEffects(*input, inputSource, session);
-        if (status != NO_ERROR && status != ALREADY_EXISTS) {
-            ALOGW("Failed to add effects on input %d", input);
-        }
-    }
-    return NO_ERROR;
-}
-
-status_t AudioPolicyService::startInput(audio_io_handle_t input,
-                                        audio_session_t session __unused)
-{
-    if (mpAudioPolicy == NULL) {
-        return NO_INIT;
-    }
-    Mutex::Autolock _l(mLock);
-
-    return mpAudioPolicy->start_input(mpAudioPolicy, input);
-}
-
-status_t AudioPolicyService::stopInput(audio_io_handle_t input,
-                                       audio_session_t session __unused)
-{
-    if (mpAudioPolicy == NULL) {
-        return NO_INIT;
-    }
-    Mutex::Autolock _l(mLock);
-
-    return mpAudioPolicy->stop_input(mpAudioPolicy, input);
-}
-
-void AudioPolicyService::releaseInput(audio_io_handle_t input,
-                                      audio_session_t session)
-{
-    if (mpAudioPolicy == NULL) {
-        return;
-    }
-
-    sp<AudioPolicyEffects>audioPolicyEffects;
-    {
-        Mutex::Autolock _l(mLock);
-        mpAudioPolicy->release_input(mpAudioPolicy, input);
-        audioPolicyEffects = mAudioPolicyEffects;
-    }
-    if (audioPolicyEffects != 0) {
-        // release audio processors from the input
-        status_t status = audioPolicyEffects->releaseInputEffects(input, session);
-        if(status != NO_ERROR) {
-            ALOGW("Failed to release effects on input %d", input);
-        }
-    }
-}
-
-status_t AudioPolicyService::initStreamVolume(audio_stream_type_t stream,
-                                            int indexMin,
-                                            int indexMax)
-{
-    if (mpAudioPolicy == NULL) {
-        return NO_INIT;
-    }
-    if (!settingsAllowed()) {
-        return PERMISSION_DENIED;
-    }
-    if (uint32_t(stream) >= AUDIO_STREAM_PUBLIC_CNT) {
-        return BAD_VALUE;
-    }
-    Mutex::Autolock _l(mLock);
-    mpAudioPolicy->init_stream_volume(mpAudioPolicy, stream, indexMin, indexMax);
-    return NO_ERROR;
-}
-
-status_t AudioPolicyService::setStreamVolumeIndex(audio_stream_type_t stream,
-                                                  int index,
-                                                  audio_devices_t device)
-{
-    if (mpAudioPolicy == NULL) {
-        return NO_INIT;
-    }
-    if (!settingsAllowed()) {
-        return PERMISSION_DENIED;
-    }
-    if (uint32_t(stream) >= AUDIO_STREAM_PUBLIC_CNT) {
-        return BAD_VALUE;
-    }
-    Mutex::Autolock _l(mLock);
-    if (mpAudioPolicy->set_stream_volume_index_for_device) {
-        return mpAudioPolicy->set_stream_volume_index_for_device(mpAudioPolicy,
-                                                                stream,
-                                                                index,
-                                                                device);
-    } else {
-        return mpAudioPolicy->set_stream_volume_index(mpAudioPolicy, stream, index);
-    }
-}
-
-status_t AudioPolicyService::getStreamVolumeIndex(audio_stream_type_t stream,
-                                                  int *index,
-                                                  audio_devices_t device)
-{
-    if (mpAudioPolicy == NULL) {
-        return NO_INIT;
-    }
-    if (uint32_t(stream) >= AUDIO_STREAM_PUBLIC_CNT) {
-        return BAD_VALUE;
-    }
-    Mutex::Autolock _l(mLock);
-    if (mpAudioPolicy->get_stream_volume_index_for_device) {
-        return mpAudioPolicy->get_stream_volume_index_for_device(mpAudioPolicy,
-                                                                stream,
-                                                                index,
-                                                                device);
-    } else {
-        return mpAudioPolicy->get_stream_volume_index(mpAudioPolicy, stream, index);
-    }
-}
-
-uint32_t AudioPolicyService::getStrategyForStream(audio_stream_type_t stream)
-{
-    if (uint32_t(stream) >= AUDIO_STREAM_PUBLIC_CNT) {
-        return 0;
-    }
-    if (mpAudioPolicy == NULL) {
-        return 0;
-    }
-    return mpAudioPolicy->get_strategy_for_stream(mpAudioPolicy, stream);
-}
-
-//audio policy: use audio_device_t appropriately
-
-audio_devices_t AudioPolicyService::getDevicesForStream(audio_stream_type_t stream)
-{
-    if (uint32_t(stream) >= AUDIO_STREAM_PUBLIC_CNT) {
-        return AUDIO_DEVICE_NONE;
-    }
-    if (mpAudioPolicy == NULL) {
-        return AUDIO_DEVICE_NONE;
-    }
-    return mpAudioPolicy->get_devices_for_stream(mpAudioPolicy, stream);
-}
-
-audio_io_handle_t AudioPolicyService::getOutputForEffect(const effect_descriptor_t *desc)
-{
-    // FIXME change return type to status_t, and return NO_INIT here
-    if (mpAudioPolicy == NULL) {
-        return 0;
-    }
-    Mutex::Autolock _l(mLock);
-    return mpAudioPolicy->get_output_for_effect(mpAudioPolicy, desc);
-}
-
-status_t AudioPolicyService::registerEffect(const effect_descriptor_t *desc,
-                                audio_io_handle_t io,
-                                uint32_t strategy,
-                                audio_session_t session,
-                                int id)
-{
-    if (mpAudioPolicy == NULL) {
-        return NO_INIT;
-    }
-    return mpAudioPolicy->register_effect(mpAudioPolicy, desc, io, strategy, session, id);
-}
-
-status_t AudioPolicyService::unregisterEffect(int id)
-{
-    if (mpAudioPolicy == NULL) {
-        return NO_INIT;
-    }
-    return mpAudioPolicy->unregister_effect(mpAudioPolicy, id);
-}
-
-status_t AudioPolicyService::setEffectEnabled(int id, bool enabled)
-{
-    if (mpAudioPolicy == NULL) {
-        return NO_INIT;
-    }
-    return mpAudioPolicy->set_effect_enabled(mpAudioPolicy, id, enabled);
-}
-
-bool AudioPolicyService::isStreamActive(audio_stream_type_t stream, uint32_t inPastMs) const
-{
-    if (uint32_t(stream) >= AUDIO_STREAM_PUBLIC_CNT) {
-        return false;
-    }
-    if (mpAudioPolicy == NULL) {
-        return false;
-    }
-    Mutex::Autolock _l(mLock);
-    return mpAudioPolicy->is_stream_active(mpAudioPolicy, stream, inPastMs);
-}
-
-bool AudioPolicyService::isStreamActiveRemotely(audio_stream_type_t stream, uint32_t inPastMs) const
-{
-    if (uint32_t(stream) >= AUDIO_STREAM_PUBLIC_CNT) {
-        return false;
-    }
-    if (mpAudioPolicy == NULL) {
-        return false;
-    }
-    Mutex::Autolock _l(mLock);
-    return mpAudioPolicy->is_stream_active_remotely(mpAudioPolicy, stream, inPastMs);
-}
-
-bool AudioPolicyService::isSourceActive(audio_source_t source) const
-{
-    if (mpAudioPolicy == NULL) {
-        return false;
-    }
-    if (mpAudioPolicy->is_source_active == 0) {
-        return false;
-    }
-    Mutex::Autolock _l(mLock);
-    return mpAudioPolicy->is_source_active(mpAudioPolicy, source);
-}
-
-status_t AudioPolicyService::queryDefaultPreProcessing(audio_session_t audioSession,
-                                                       effect_descriptor_t *descriptors,
-                                                       uint32_t *count)
-{
-    if (mpAudioPolicy == NULL) {
-        *count = 0;
-        return NO_INIT;
-    }
-    sp<AudioPolicyEffects>audioPolicyEffects;
-    {
-        Mutex::Autolock _l(mLock);
-        audioPolicyEffects = mAudioPolicyEffects;
-    }
-    if (audioPolicyEffects == 0) {
-        *count = 0;
-        return NO_INIT;
-    }
-    return audioPolicyEffects->queryDefaultInputEffects(audioSession, descriptors, count);
-}
-
-bool AudioPolicyService::isOffloadSupported(const audio_offload_info_t& info)
-{
-    if (mpAudioPolicy == NULL) {
-        ALOGV("mpAudioPolicy == NULL");
-        return false;
-    }
-
-    if (mpAudioPolicy->is_offload_supported == NULL) {
-        ALOGV("HAL does not implement is_offload_supported");
-        return false;
-    }
-
-    return mpAudioPolicy->is_offload_supported(mpAudioPolicy, &info);
-}
-
-status_t AudioPolicyService::listAudioPorts(audio_port_role_t role __unused,
-                                            audio_port_type_t type __unused,
-                                            unsigned int *num_ports,
-                                            struct audio_port *ports __unused,
-                                            unsigned int *generation __unused)
-{
-    *num_ports = 0;
-    return INVALID_OPERATION;
-}
-
-status_t AudioPolicyService::getAudioPort(struct audio_port *port __unused)
-{
-    return INVALID_OPERATION;
-}
-
-status_t AudioPolicyService::createAudioPatch(const struct audio_patch *patch __unused,
-        audio_patch_handle_t *handle __unused)
-{
-    return INVALID_OPERATION;
-}
-
-status_t AudioPolicyService::releaseAudioPatch(audio_patch_handle_t handle __unused)
-{
-    return INVALID_OPERATION;
-}
-
-status_t AudioPolicyService::listAudioPatches(unsigned int *num_patches,
-        struct audio_patch *patches __unused,
-        unsigned int *generation __unused)
-{
-    *num_patches = 0;
-    return INVALID_OPERATION;
-}
-
-status_t AudioPolicyService::setAudioPortConfig(const struct audio_port_config *config __unused)
-{
-    return INVALID_OPERATION;
-}
-
-status_t AudioPolicyService::getOutputForAttr(const audio_attributes_t *attr,
-                                              audio_io_handle_t *output,
-                                              audio_session_t session __unused,
-                                              audio_stream_type_t *stream,
-                                              uid_t uid __unused,
-                                              uint32_t samplingRate,
-                                              audio_format_t format,
-                                              audio_channel_mask_t channelMask,
-                                              audio_output_flags_t flags,
-                                              audio_port_handle_t selectedDeviceId __unused,
-                                              const audio_offload_info_t *offloadInfo)
-{
-    if (attr != NULL) {
-        *stream = audio_attributes_to_stream_type(attr);
-    } else {
-        if (*stream == AUDIO_STREAM_DEFAULT) {
-            return BAD_VALUE;
-        }
-    }
-    *output = getOutput(*stream, samplingRate, format, channelMask,
-                                          flags, offloadInfo);
-    if (*output == AUDIO_IO_HANDLE_NONE) {
-        return INVALID_OPERATION;
-    }
-    return NO_ERROR;
-}
-
-status_t AudioPolicyService::acquireSoundTriggerSession(audio_session_t *session __unused,
-                                       audio_io_handle_t *ioHandle __unused,
-                                       audio_devices_t *device __unused)
-{
-    return INVALID_OPERATION;
-}
-
-status_t AudioPolicyService::releaseSoundTriggerSession(audio_session_t session __unused)
-{
-    return INVALID_OPERATION;
-}
-
-status_t AudioPolicyService::registerPolicyMixes(const Vector<AudioMix>& mixes __unused,
-                                                 bool registration __unused)
-{
-    return INVALID_OPERATION;
-}
-
-status_t AudioPolicyService::startAudioSource(const struct audio_port_config *source,
-                                  const audio_attributes_t *attributes,
-                                  audio_patch_handle_t *handle)
-{
-    return INVALID_OPERATION;
-}
-
-status_t AudioPolicyService::stopAudioSource(audio_patch_handle_t handle)
-{
-    return INVALID_OPERATION;
-}
-
-status_t AudioPolicyService::setMasterMono(bool mono)
-{
-    return INVALID_OPERATION;
-}
-
-status_t AudioPolicyService::getMasterMono(bool *mono)
-{
-    return INVALID_OPERATION;
-}
-
-}; // namespace android
diff --git a/services/audiopolicy/service/AudioPolicyService.cpp b/services/audiopolicy/service/AudioPolicyService.cpp
index b6b6116..c4f6367 100644
--- a/services/audiopolicy/service/AudioPolicyService.cpp
+++ b/services/audiopolicy/service/AudioPolicyService.cpp
@@ -39,11 +39,6 @@
 #include <system/audio.h>
 #include <system/audio_policy.h>
 
-#ifdef USE_LEGACY_AUDIO_POLICY
-#include <hardware/hardware.h>
-#include <hardware/audio_policy.h>
-#endif
-
 namespace android {
 
 static const char kDeadlockedString[] = "AudioPolicyService may be deadlocked\n";
@@ -54,11 +49,6 @@
 
 static const nsecs_t kAudioCommandTimeoutNs = seconds(3); // 3 seconds
 
-#ifdef USE_LEGACY_AUDIO_POLICY
-namespace {
-    extern struct audio_policy_service_ops aps_ops;
-};
-#endif
 
 // ----------------------------------------------------------------------------
 
@@ -80,40 +70,8 @@
         // start output activity command thread
         mOutputCommandThread = new AudioCommandThread(String8("ApmOutput"), this);
 
-#ifdef USE_LEGACY_AUDIO_POLICY
-        ALOGI("AudioPolicyService CSTOR in legacy mode");
-
-        /* instantiate the audio policy manager */
-        const struct hw_module_t *module;
-        int rc = hw_get_module(AUDIO_POLICY_HARDWARE_MODULE_ID, &module);
-        if (rc) {
-            return;
-        }
-        rc = audio_policy_dev_open(module, &mpAudioPolicyDev);
-        ALOGE_IF(rc, "couldn't open audio policy device (%s)", strerror(-rc));
-        if (rc) {
-            return;
-        }
-
-        rc = mpAudioPolicyDev->create_audio_policy(mpAudioPolicyDev, &aps_ops, this,
-                                                   &mpAudioPolicy);
-        ALOGE_IF(rc, "couldn't create audio policy (%s)", strerror(-rc));
-        if (rc) {
-            return;
-        }
-
-        rc = mpAudioPolicy->init_check(mpAudioPolicy);
-        ALOGE_IF(rc, "couldn't init_check the audio policy (%s)", strerror(-rc));
-        if (rc) {
-            return;
-        }
-        ALOGI("Loaded audio policy from %s (%s)", module->name, module->id);
-#else
-        ALOGI("AudioPolicyService CSTOR in new mode");
-
         mAudioPolicyClient = new AudioPolicyClient(this);
         mAudioPolicyManager = createAudioPolicyManager(mAudioPolicyClient);
-#endif
     }
     // load audio processing modules
     sp<AudioPolicyEffects>audioPolicyEffects = new AudioPolicyEffects();
@@ -129,17 +87,8 @@
     mAudioCommandThread->exit();
     mOutputCommandThread->exit();
 
-#ifdef USE_LEGACY_AUDIO_POLICY
-    if (mpAudioPolicy != NULL && mpAudioPolicyDev != NULL) {
-        mpAudioPolicyDev->destroy_audio_policy(mpAudioPolicyDev, mpAudioPolicy);
-    }
-    if (mpAudioPolicyDev != NULL) {
-        audio_policy_dev_close(mpAudioPolicyDev);
-    }
-#else
     destroyAudioPolicyManager(mAudioPolicyManager);
     delete mAudioPolicyClient;
-#endif
 
     mNotificationClients.clear();
     mAudioPolicyEffects.clear();
@@ -187,14 +136,12 @@
         Mutex::Autolock _l(mNotificationClientsLock);
         mNotificationClients.removeItem(uid);
     }
-#ifndef USE_LEGACY_AUDIO_POLICY
     {
         Mutex::Autolock _l(mLock);
         if (mAudioPolicyManager) {
             mAudioPolicyManager->releaseResourcesForUid(uid);
         }
     }
-#endif
 }
 
 void AudioPolicyService::onAudioPortListUpdate()
@@ -360,11 +307,7 @@
     char buffer[SIZE];
     String8 result;
 
-#ifdef USE_LEGACY_AUDIO_POLICY
-    snprintf(buffer, SIZE, "PolicyManager Interface: %p\n", mpAudioPolicy);
-#else
     snprintf(buffer, SIZE, "AudioPolicyManager: %p\n", mAudioPolicyManager);
-#endif
     result.append(buffer);
     snprintf(buffer, SIZE, "Command Thread: %p\n", mAudioCommandThread.get());
     result.append(buffer);
@@ -394,15 +337,9 @@
             mTonePlaybackThread->dump(fd);
         }
 
-#ifdef USE_LEGACY_AUDIO_POLICY
-        if (mpAudioPolicy) {
-            mpAudioPolicy->dump(mpAudioPolicy, fd);
-        }
-#else
         if (mAudioPolicyManager) {
             mAudioPolicyManager->dump(fd);
         }
-#endif
 
         if (locked) mLock.unlock();
     }
@@ -1210,29 +1147,4 @@
 int aps_set_voice_volume(void *service, float volume, int delay_ms);
 };
 
-#ifdef USE_LEGACY_AUDIO_POLICY
-namespace {
-    struct audio_policy_service_ops aps_ops = {
-        .open_output           = aps_open_output,
-        .open_duplicate_output = aps_open_dup_output,
-        .close_output          = aps_close_output,
-        .suspend_output        = aps_suspend_output,
-        .restore_output        = aps_restore_output,
-        .open_input            = aps_open_input,
-        .close_input           = aps_close_input,
-        .set_stream_volume     = aps_set_stream_volume,
-        .invalidate_stream     = aps_invalidate_stream,
-        .set_parameters        = aps_set_parameters,
-        .get_parameters        = aps_get_parameters,
-        .start_tone            = aps_start_tone,
-        .stop_tone             = aps_stop_tone,
-        .set_voice_volume      = aps_set_voice_volume,
-        .move_effects          = aps_move_effects,
-        .load_hw_module        = aps_load_hw_module,
-        .open_output_on_module = aps_open_output_on_module,
-        .open_input_on_module  = aps_open_input_on_module,
-    };
-}; // namespace <unnamed>
-#endif
-
 }; // namespace android
diff --git a/services/audiopolicy/service/AudioPolicyService.h b/services/audiopolicy/service/AudioPolicyService.h
index a310735..8eb4f2d 100644
--- a/services/audiopolicy/service/AudioPolicyService.h
+++ b/services/audiopolicy/service/AudioPolicyService.h
@@ -30,10 +30,6 @@
 #include <media/ToneGenerator.h>
 #include <media/AudioEffect.h>
 #include <media/AudioPolicy.h>
-#ifdef USE_LEGACY_AUDIO_POLICY
-#include <hardware/audio_policy.h>
-#include <hardware_legacy/AudioPolicyInterface.h>
-#endif
 #include "AudioPolicyEffects.h"
 #include "managerdefault/AudioPolicyManager.h"
 
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index dd9029e..85faac6 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -470,8 +470,8 @@
         // CameraInfo is for android.hardware.Camera which does not
         // support external camera facing. The closest approximation would be
         // front camera.
-        if (cameraInfo->orientation == CAMERA_FACING_EXTERNAL) {
-            cameraInfo->orientation = CAMERA_FACING_FRONT;
+        if (cameraInfo->facing == CAMERA_FACING_EXTERNAL) {
+            cameraInfo->facing = CAMERA_FACING_FRONT;
         }
     }
     return rc;
@@ -2556,7 +2556,8 @@
                 write(fd, result.string(), result.size());
             } else {
                 result.appendFormat("  Facing: %s\n",
-                        info.facing == CAMERA_FACING_BACK ? "BACK" : "FRONT");
+                        info.facing == CAMERA_FACING_BACK ? "BACK" :
+                                info.facing == CAMERA_FACING_FRONT ? "FRONT" : "EXTERNAL");
                 result.appendFormat("  Orientation: %d\n", info.orientation);
                 int deviceVersion;
                 if (mModule->getModuleApiVersion() < CAMERA_MODULE_API_VERSION_2_0) {
diff --git a/services/camera/libcameraservice/api1/Camera2Client.cpp b/services/camera/libcameraservice/api1/Camera2Client.cpp
index bcd62d6..bfbf640 100644
--- a/services/camera/libcameraservice/api1/Camera2Client.cpp
+++ b/services/camera/libcameraservice/api1/Camera2Client.cpp
@@ -993,7 +993,7 @@
 }
 
 status_t Camera2Client::startRecordingL(Parameters &params, bool restart) {
-    status_t res;
+    status_t res = OK;
 
     ALOGV("%s: state == %d, restart = %d", __FUNCTION__, params.state, restart);
 
diff --git a/services/camera/libcameraservice/api1/client2/Parameters.cpp b/services/camera/libcameraservice/api1/client2/Parameters.cpp
index 9a7839b..32b99ca 100644
--- a/services/camera/libcameraservice/api1/client2/Parameters.cpp
+++ b/services/camera/libcameraservice/api1/client2/Parameters.cpp
@@ -911,9 +911,7 @@
             CameraParameters::FALSE);
     }
 
-    char value[PROPERTY_VALUE_MAX];
-    property_get("camera.disable_zsl_mode", value, "0");
-    if (!strcmp(value,"1") || slowJpegMode) {
+    if (slowJpegMode || property_get_bool("camera.disable_zsl_mode", false)) {
         ALOGI("Camera %d: Disabling ZSL mode", cameraId);
         allowZslMode = false;
     } else {
diff --git a/services/mediaanalytics/Android.mk b/services/mediaanalytics/Android.mk
new file mode 100644
index 0000000..76a5c1c
--- /dev/null
+++ b/services/mediaanalytics/Android.mk
@@ -0,0 +1,32 @@
+# Media Statistics service
+#
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+	main_mediaanalytics.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+	libcutils \
+	liblog \
+	libmedia \
+	libmediaanalyticsservice \
+	libutils \
+	libbinder \
+	libicuuc
+
+LOCAL_STATIC_LIBRARIES := \
+        libicuandroid_utils \
+        libregistermsext
+
+LOCAL_C_INCLUDES := \
+    frameworks/av/media/libmediaanalyticsservice
+
+LOCAL_MODULE:= mediaanalytics
+
+LOCAL_INIT_RC := mediaanalytics.rc
+
+LOCAL_CFLAGS := -Werror -Wall
+
+include $(BUILD_EXECUTABLE)
diff --git a/services/mediaanalytics/main_mediaanalytics.cpp b/services/mediaanalytics/main_mediaanalytics.cpp
new file mode 100644
index 0000000..ba601ee
--- /dev/null
+++ b/services/mediaanalytics/main_mediaanalytics.cpp
@@ -0,0 +1,44 @@
+/*
+ * 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 "mediaanalytics"
+//#define LOG_NDEBUG 0
+
+#include <binder/IPCThreadState.h>
+#include <binder/ProcessState.h>
+#include <binder/IServiceManager.h>
+#include <utils/Log.h>
+//#include "RegisterExtensions.h"
+
+// from LOCAL_C_INCLUDES
+#include "IcuUtils.h"
+#include "MediaAnalyticsService.h"
+
+using namespace android;
+
+int main(int argc __unused, char **argv __unused)
+{
+    signal(SIGPIPE, SIG_IGN);
+
+    sp<ProcessState> proc(ProcessState::self());
+    sp<IServiceManager> sm(defaultServiceManager());
+    ALOGI("ServiceManager: %p", sm.get());
+
+    InitializeIcuOrDie();
+    MediaAnalyticsService::instantiate();
+    ProcessState::self()->startThreadPool();
+    IPCThreadState::self()->joinThreadPool();
+}
diff --git a/services/mediaanalytics/mediaanalytics.rc b/services/mediaanalytics/mediaanalytics.rc
new file mode 100644
index 0000000..0af69f5
--- /dev/null
+++ b/services/mediaanalytics/mediaanalytics.rc
@@ -0,0 +1,5 @@
+service mediaanalytics /system/bin/mediaanalytics
+    class main
+    user media
+    ioprio rt 4
+    writepid /dev/cpuset/foreground/tasks /dev/stune/foreground/tasks
diff --git a/services/mediadrm/Android.mk b/services/mediadrm/Android.mk
index 38aa472..73109e1 100644
--- a/services/mediadrm/Android.mk
+++ b/services/mediadrm/Android.mk
@@ -23,7 +23,6 @@
 
 LOCAL_SHARED_LIBRARIES:= \
     libbinder \
-    libcutils \
     liblog \
     libmediadrm \
     libutils \
diff --git a/services/radio/Android.mk b/services/radio/Android.mk
index b4cda19..4344506 100644
--- a/services/radio/Android.mk
+++ b/services/radio/Android.mk
@@ -17,9 +17,8 @@
 include $(CLEAR_VARS)
 
 
-LOCAL_SRC_FILES:=               \
-    RadioService.cpp \
-    RadioHalLegacy.cpp
+LOCAL_SRC_FILES:= \
+    RadioService.cpp
 
 LOCAL_SHARED_LIBRARIES:= \
     liblog \
@@ -31,6 +30,26 @@
     libradio \
     libradio_metadata
 
+ifeq ($(ENABLE_TREBLE),true)
+# Treble configuration
+LOCAL_CFLAGS += -DENABLE_TREBLE
+LOCAL_SRC_FILES += \
+    HidlUtils.cpp \
+    RadioHalHidl.cpp
+
+LOCAL_SHARED_LIBRARIES += \
+    libhwbinder \
+    libhidlbase \
+    libhidltransport \
+    libbase \
+    android.hardware.broadcastradio@1.0
+else
+# libhardware configuration
+LOCAL_SRC_FILES +=               \
+    RadioHalLegacy.cpp
+endif
+
+
 LOCAL_CFLAGS += -Wall -Wextra -Werror
 
 LOCAL_MULTILIB := $(AUDIOSERVER_MULTILIB)
diff --git a/services/radio/HidlUtils.cpp b/services/radio/HidlUtils.cpp
new file mode 100644
index 0000000..bfced7a
--- /dev/null
+++ b/services/radio/HidlUtils.cpp
@@ -0,0 +1,179 @@
+/*
+ * 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 "HidlUtils"
+//#define LOG_NDEBUG 0
+
+#include <utils/Log.h>
+#include <utils/misc.h>
+#include <system/radio_metadata.h>
+
+#include "HidlUtils.h"
+
+namespace android {
+
+using android::hardware::broadcastradio::V1_0::MetadataType;
+using android::hardware::broadcastradio::V1_0::Band;
+using android::hardware::broadcastradio::V1_0::Deemphasis;
+using android::hardware::broadcastradio::V1_0::Rds;
+
+//static
+int HidlUtils::convertHalResult(Result result)
+{
+    switch (result) {
+        case Result::OK:
+            return 0;
+        case Result::INVALID_ARGUMENTS:
+            return -EINVAL;
+        case Result::INVALID_STATE:
+            return -ENOSYS;
+        case Result::TIMEOUT:
+            return -ETIMEDOUT;
+        case Result::NOT_INITIALIZED:
+        default:
+            return -ENODEV;
+    }
+}
+
+
+//static
+void HidlUtils::convertBandConfigToHal(BandConfig *halConfig,
+                                       const radio_hal_band_config_t *config)
+{
+    halConfig->type = static_cast<Band>(config->type);
+    halConfig->antennaConnected = config->antenna_connected;
+    halConfig->lowerLimit = config->lower_limit;
+    halConfig->upperLimit = config->upper_limit;
+    halConfig->spacings.setToExternal(const_cast<unsigned int *>(&config->spacings[0]),
+                                       config->num_spacings * sizeof(uint32_t));
+    // FIXME: transfer buffer ownership. should have a method for that in hidl_vec
+    halConfig->spacings.resize(config->num_spacings);
+
+    if (halConfig->type == Band::FM) {
+        halConfig->ext.fm.deemphasis = static_cast<Deemphasis>(config->fm.deemphasis);
+        halConfig->ext.fm.stereo = config->fm.stereo;
+        halConfig->ext.fm.rds = static_cast<Rds>(config->fm.rds);
+        halConfig->ext.fm.ta = config->fm.ta;
+        halConfig->ext.fm.af = config->fm.af;
+        halConfig->ext.fm.ea = config->fm.ea;
+    } else {
+        halConfig->ext.am.stereo = config->am.stereo;
+    }
+}
+
+//static
+void HidlUtils::convertPropertiesFromHal(radio_hal_properties_t *properties,
+                                         const Properties *halProperties)
+{
+    properties->class_id = static_cast<radio_class_t>(halProperties->classId);
+    strlcpy(properties->implementor, halProperties->implementor.c_str(), RADIO_STRING_LEN_MAX);
+    strlcpy(properties->product, halProperties->product.c_str(), RADIO_STRING_LEN_MAX);
+    strlcpy(properties->version, halProperties->version.c_str(), RADIO_STRING_LEN_MAX);
+    strlcpy(properties->serial, halProperties->serial.c_str(), RADIO_STRING_LEN_MAX);
+    properties->num_tuners = halProperties->numTuners;
+    properties->num_audio_sources = halProperties->numAudioSources;
+    properties->supports_capture = halProperties->supportsCapture;
+    properties->num_bands = halProperties->bands.size();
+
+    for (size_t i = 0; i < halProperties->bands.size(); i++) {
+        convertBandConfigFromHal(&properties->bands[i], &halProperties->bands[i]);
+    }
+}
+
+//static
+void HidlUtils::convertBandConfigFromHal(radio_hal_band_config_t *config,
+                                         const BandConfig *halConfig)
+{
+    config->type = static_cast<radio_band_t>(halConfig->type);
+    config->antenna_connected = halConfig->antennaConnected;
+    config->lower_limit = halConfig->lowerLimit;
+    config->upper_limit = halConfig->upperLimit;
+    config->num_spacings = halConfig->spacings.size();
+    if (config->num_spacings > RADIO_NUM_SPACINGS_MAX) {
+        config->num_spacings = RADIO_NUM_SPACINGS_MAX;
+    }
+    memcpy(config->spacings, halConfig->spacings.data(),
+           sizeof(uint32_t) * config->num_spacings);
+
+    if (halConfig->type == Band::FM) {
+        config->fm.deemphasis = static_cast<radio_deemphasis_t>(halConfig->ext.fm.deemphasis);
+        config->fm.stereo = halConfig->ext.fm.stereo;
+        config->fm.rds = static_cast<radio_rds_t>(halConfig->ext.fm.rds);
+        config->fm.ta = halConfig->ext.fm.ta;
+        config->fm.af = halConfig->ext.fm.af;
+        config->fm.ea = halConfig->ext.fm.ea;
+    } else {
+        config->am.stereo = halConfig->ext.am.stereo;
+    }
+}
+
+
+//static
+void HidlUtils::convertProgramInfoFromHal(radio_program_info_t *info,
+                                          const ProgramInfo *halInfo,
+                                          bool withMetadata)
+{
+    info->channel = halInfo->channel;
+    info->sub_channel = halInfo->subChannel;
+    info->tuned = halInfo->tuned;
+    info->stereo = halInfo->stereo;
+    info->digital = halInfo->digital;
+    info->signal_strength = halInfo->signalStrength;
+    if (withMetadata && halInfo->metadata.size() != 0) {
+        convertMetaDataFromHal(&info->metadata, halInfo->metadata,
+                               halInfo->channel, halInfo->subChannel);
+    }
+}
+
+//static
+void HidlUtils::convertMetaDataFromHal(radio_metadata_t **metadata,
+                                       const hidl_vec<MetaData>& halMetadata,
+                                       uint32_t channel,
+                                       uint32_t subChannel)
+{
+
+    radio_metadata_allocate(metadata, channel, subChannel);
+    for (size_t i = 0; i < halMetadata.size(); i++) {
+        radio_metadata_key_t key = static_cast<radio_metadata_key_t>(halMetadata[i].key);
+        radio_metadata_type_t type = static_cast<radio_metadata_key_t>(halMetadata[i].type);
+        radio_metadata_clock_t clock;
+
+        switch (type) {
+        case RADIO_METADATA_TYPE_INT:
+            radio_metadata_add_int(metadata, key, halMetadata[i].intValue);
+            break;
+        case RADIO_METADATA_TYPE_TEXT:
+            radio_metadata_add_text(metadata, key, halMetadata[i].stringValue.c_str());
+            break;
+        case RADIO_METADATA_TYPE_RAW:
+            radio_metadata_add_raw(metadata, key,
+                                   halMetadata[i].rawValue.data(),
+                                   halMetadata[i].rawValue.size());
+            break;
+        case RADIO_METADATA_TYPE_CLOCK:
+            clock.utc_seconds_since_epoch =
+                    halMetadata[i].clockValue.utcSecondsSinceEpoch;
+            clock.timezone_offset_in_minutes =
+                    halMetadata[i].clockValue.timezoneOffsetInMinutes;
+            radio_metadata_add_clock(metadata, key, &clock);
+            break;
+        default:
+            ALOGW("%s invalid metadata type %u",__FUNCTION__, halMetadata[i].type);
+            break;
+        }
+    }
+}
+
+}  // namespace android
diff --git a/services/radio/HidlUtils.h b/services/radio/HidlUtils.h
new file mode 100644
index 0000000..091abb7
--- /dev/null
+++ b/services/radio/HidlUtils.h
@@ -0,0 +1,51 @@
+/*
+ * 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_RADIO_HAL_HIDL_UTILS_H
+#define ANDROID_HARDWARE_RADIO_HAL_HIDL_UTILS_H
+
+#include <android/hardware/broadcastradio/1.0/types.h>
+#include <hardware/radio.h>
+
+namespace android {
+
+using android::hardware::hidl_vec;
+using android::hardware::broadcastradio::V1_0::Result;
+using android::hardware::broadcastradio::V1_0::Properties;
+using android::hardware::broadcastradio::V1_0::BandConfig;
+using android::hardware::broadcastradio::V1_0::ProgramInfo;
+using android::hardware::broadcastradio::V1_0::MetaData;
+
+class HidlUtils {
+public:
+    static int convertHalResult(Result result);
+    static void convertBandConfigFromHal(radio_hal_band_config_t *config,
+                                         const BandConfig *halConfig);
+    static void convertPropertiesFromHal(radio_hal_properties_t *properties,
+                                         const Properties *halProperties);
+    static void convertBandConfigToHal(BandConfig *halConfig,
+                                       const radio_hal_band_config_t *config);
+    static void convertProgramInfoFromHal(radio_program_info_t *info,
+                                          const ProgramInfo *halInfo,
+                                          bool withMetadata);
+    static void convertMetaDataFromHal(radio_metadata_t **metadata,
+                                       const hidl_vec<MetaData>& halMetadata,
+                                       uint32_t channel,
+                                       uint32_t subChannel);
+};
+
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_RADIO_HAL_HIDL_UTILS_H
diff --git a/services/radio/RadioHalHidl.cpp b/services/radio/RadioHalHidl.cpp
new file mode 100644
index 0000000..07cb4d5
--- /dev/null
+++ b/services/radio/RadioHalHidl.cpp
@@ -0,0 +1,388 @@
+/*
+ * 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 "RadioHalHidl"
+//#define LOG_NDEBUG 0
+
+#include <utils/Log.h>
+#include <utils/misc.h>
+#include <system/radio_metadata.h>
+#include <android/hardware/broadcastradio/1.0/IBroadcastRadioFactory.h>
+
+#include "RadioHalHidl.h"
+#include "HidlUtils.h"
+
+namespace android {
+
+using android::hardware::broadcastradio::V1_0::IBroadcastRadioFactory;
+using android::hardware::broadcastradio::V1_0::Class;
+using android::hardware::broadcastradio::V1_0::Direction;
+using android::hardware::broadcastradio::V1_0::Properties;
+
+
+/* static */
+sp<RadioInterface> RadioInterface::connectModule(radio_class_t classId)
+{
+    return new RadioHalHidl(classId);
+}
+
+int RadioHalHidl::getProperties(radio_hal_properties_t *properties)
+{
+    ALOGV("%s IN", __FUNCTION__);
+    sp<IBroadcastRadio> module = getService();
+    if (module == 0) {
+        return -ENODEV;
+    }
+    Properties halProperties;
+    Result halResult;
+    Return<void> hidlReturn =
+            module->getProperties([&](Result result, const Properties& properties) {
+                    halResult = result;
+                    if (result == Result::OK) {
+                        halProperties = properties;
+                    }
+                });
+
+    if (hidlReturn.getStatus().transactionError() == DEAD_OBJECT) {
+        clearService();
+        return -EPIPE;
+    }
+    if (halResult == Result::OK) {
+        HidlUtils::convertPropertiesFromHal(properties, &halProperties);
+    }
+    return HidlUtils::convertHalResult(halResult);
+}
+
+int RadioHalHidl::openTuner(const radio_hal_band_config_t *config,
+                            bool audio,
+                            sp<TunerCallbackInterface> callback,
+                            sp<TunerInterface>& tuner)
+{
+    sp<IBroadcastRadio> module = getService();
+    if (module == 0) {
+        return -ENODEV;
+    }
+    sp<Tuner> tunerImpl = new Tuner(callback, this);
+
+    BandConfig halConfig;
+    Result halResult;
+    sp<ITuner> halTuner;
+
+    HidlUtils::convertBandConfigToHal(&halConfig, config);
+    Return<void> hidlReturn =
+            module->openTuner(halConfig, audio, tunerImpl,
+                              [&](Result result, const sp<ITuner>& tuner) {
+                    halResult = result;
+                    if (result == Result::OK) {
+                        halTuner = tuner;
+                    }
+                });
+
+    if (hidlReturn.getStatus().transactionError() == DEAD_OBJECT) {
+        clearService();
+        return -EPIPE;
+    }
+    if (halResult == Result::OK) {
+        tunerImpl->setHalTuner(halTuner);
+        tuner = tunerImpl;
+    }
+
+    return HidlUtils::convertHalResult(halResult);
+}
+
+int RadioHalHidl::closeTuner(sp<TunerInterface>& tuner)
+{
+    sp<Tuner> tunerImpl = static_cast<Tuner *>(tuner.get());
+    sp<ITuner> clearTuner;
+    tunerImpl->setHalTuner(clearTuner);
+    return 0;
+}
+
+RadioHalHidl::RadioHalHidl(radio_class_t classId)
+    : mClassId(classId)
+{
+}
+
+RadioHalHidl::~RadioHalHidl()
+{
+}
+
+sp<IBroadcastRadio> RadioHalHidl::getService()
+{
+    if (mHalModule == 0) {
+        sp<IBroadcastRadioFactory> factory = IBroadcastRadioFactory::getService("broadcastradio");
+        if (factory != 0) {
+            factory->connectModule(static_cast<Class>(mClassId),
+                               [&](Result retval, const ::android::sp<IBroadcastRadio>& result) {
+                if (retval == Result::OK) {
+                    mHalModule = result;
+                }
+            });
+        }
+    }
+    ALOGV("%s OUT module %p", __FUNCTION__, mHalModule.get());
+    return mHalModule;
+}
+
+void RadioHalHidl::clearService()
+{
+    ALOGV("%s IN module %p", __FUNCTION__, mHalModule.get());
+    mHalModule.clear();
+}
+
+
+int RadioHalHidl::Tuner::setConfiguration(const radio_hal_band_config_t *config)
+{
+    ALOGV("%s IN mHalTuner %p", __FUNCTION__, mHalTuner.get());
+
+    if (mHalTuner == 0) {
+        return -ENODEV;
+    }
+    BandConfig halConfig;
+    HidlUtils::convertBandConfigToHal(&halConfig, config);
+
+    Return<Result> hidlResult = mHalTuner->setConfiguration(halConfig);
+    checkHidlStatus(hidlResult.getStatus());
+    return HidlUtils::convertHalResult(hidlResult);
+}
+
+int RadioHalHidl::Tuner::getConfiguration(radio_hal_band_config_t *config)
+{
+    ALOGV("%s IN mHalTuner %p", __FUNCTION__, mHalTuner.get());
+    if (mHalTuner == 0) {
+        return -ENODEV;
+    }
+    BandConfig halConfig;
+    Result halResult;
+    Return<void> hidlReturn =
+            mHalTuner->getConfiguration([&](Result result, const BandConfig& config) {
+                    halResult = result;
+                    if (result == Result::OK) {
+                        halConfig = config;
+                    }
+                });
+    status_t status = checkHidlStatus(hidlReturn.getStatus());
+    if (status == NO_ERROR && halResult == Result::OK) {
+        HidlUtils::convertBandConfigFromHal(config, &halConfig);
+    }
+    return HidlUtils::convertHalResult(halResult);
+}
+
+int RadioHalHidl::Tuner::scan(radio_direction_t direction, bool skip_sub_channel)
+{
+    ALOGV("%s IN mHalTuner %p", __FUNCTION__, mHalTuner.get());
+    if (mHalTuner == 0) {
+        return -ENODEV;
+    }
+    Return<Result> hidlResult =
+            mHalTuner->scan(static_cast<Direction>(direction), skip_sub_channel);
+    checkHidlStatus(hidlResult.getStatus());
+    return HidlUtils::convertHalResult(hidlResult);
+}
+
+int RadioHalHidl::Tuner::step(radio_direction_t direction, bool skip_sub_channel)
+{
+    ALOGV("%s IN mHalTuner %p", __FUNCTION__, mHalTuner.get());
+    if (mHalTuner == 0) {
+        return -ENODEV;
+    }
+    Return<Result> hidlResult =
+            mHalTuner->step(static_cast<Direction>(direction), skip_sub_channel);
+    checkHidlStatus(hidlResult.getStatus());
+    return HidlUtils::convertHalResult(hidlResult);
+}
+
+int RadioHalHidl::Tuner::tune(unsigned int channel, unsigned int sub_channel)
+{
+    ALOGV("%s IN mHalTuner %p", __FUNCTION__, mHalTuner.get());
+    if (mHalTuner == 0) {
+        return -ENODEV;
+    }
+    Return<Result> hidlResult =
+            mHalTuner->tune(channel, sub_channel);
+    checkHidlStatus(hidlResult.getStatus());
+    return HidlUtils::convertHalResult(hidlResult);
+}
+
+int RadioHalHidl::Tuner::cancel()
+{
+    ALOGV("%s IN mHalTuner %p", __FUNCTION__, mHalTuner.get());
+    if (mHalTuner == 0) {
+        return -ENODEV;
+    }
+    Return<Result> hidlResult = mHalTuner->cancel();
+    checkHidlStatus(hidlResult.getStatus());
+    return HidlUtils::convertHalResult(hidlResult);
+}
+
+int RadioHalHidl::Tuner::getProgramInformation(radio_program_info_t *info)
+{
+    ALOGV("%s IN mHalTuner %p", __FUNCTION__, mHalTuner.get());
+    if (mHalTuner == 0) {
+        return -ENODEV;
+    }
+    ProgramInfo halInfo;
+    Result halResult;
+    bool withMetaData = (info->metadata != NULL);
+    Return<void> hidlReturn = mHalTuner->getProgramInformation(
+                    withMetaData, [&](Result result, const ProgramInfo& info) {
+                        halResult = result;
+                        if (result == Result::OK) {
+                            halInfo = info;
+                        }
+    });
+    status_t status = checkHidlStatus(hidlReturn.getStatus());
+    if (status == NO_ERROR && halResult == Result::OK) {
+        HidlUtils::convertProgramInfoFromHal(info, &halInfo, withMetaData);
+    }
+    return HidlUtils::convertHalResult(halResult);
+}
+
+Return<void> RadioHalHidl::Tuner::hardwareFailure()
+{
+    ALOGV("%s IN", __FUNCTION__);
+    handleHwFailure();
+    return Return<void>();
+}
+
+Return<void> RadioHalHidl::Tuner::configChange(Result result, const BandConfig& config)
+{
+    ALOGV("%s IN", __FUNCTION__);
+    radio_hal_event_t event;
+    memset(&event, 0, sizeof(radio_hal_event_t));
+    event.type = RADIO_EVENT_CONFIG;
+    event.status = HidlUtils::convertHalResult(result);
+    HidlUtils::convertBandConfigFromHal(&event.config, &config);
+    onCallback(&event);
+    return Return<void>();
+}
+
+Return<void> RadioHalHidl::Tuner::tuneComplete(Result result, const ProgramInfo& info)
+{
+    ALOGV("%s IN", __FUNCTION__);
+    radio_hal_event_t event;
+    memset(&event, 0, sizeof(radio_hal_event_t));
+    event.type = RADIO_EVENT_TUNED;
+    event.status = HidlUtils::convertHalResult(result);
+    HidlUtils::convertProgramInfoFromHal(&event.info, &info, true);
+    onCallback(&event);
+    if (event.info.metadata != NULL) {
+        radio_metadata_deallocate(event.info.metadata);
+    }
+    return Return<void>();
+}
+
+Return<void> RadioHalHidl::Tuner::afSwitch(const ProgramInfo& info)
+{
+    ALOGV("%s IN", __FUNCTION__);
+    radio_hal_event_t event;
+    memset(&event, 0, sizeof(radio_hal_event_t));
+    event.type = RADIO_EVENT_AF_SWITCH;
+    HidlUtils::convertProgramInfoFromHal(&event.info, &info, true);
+    onCallback(&event);
+    if (event.info.metadata != NULL) {
+        radio_metadata_deallocate(event.info.metadata);
+    }
+    return Return<void>();
+}
+
+Return<void> RadioHalHidl::Tuner::antennaStateChange(bool connected)
+{
+    ALOGV("%s IN", __FUNCTION__);
+    radio_hal_event_t event;
+    memset(&event, 0, sizeof(radio_hal_event_t));
+    event.type = RADIO_EVENT_ANTENNA;
+    event.on = connected;
+    onCallback(&event);
+    return Return<void>();
+}
+Return<void> RadioHalHidl::Tuner::trafficAnnouncement(bool active)
+{
+    ALOGV("%s IN", __FUNCTION__);
+    radio_hal_event_t event;
+    memset(&event, 0, sizeof(radio_hal_event_t));
+    event.type = RADIO_EVENT_TA;
+    event.on = active;
+    onCallback(&event);
+    return Return<void>();
+}
+Return<void> RadioHalHidl::Tuner::emergencyAnnouncement(bool active)
+{
+    ALOGV("%s IN", __FUNCTION__);
+    radio_hal_event_t event;
+    memset(&event, 0, sizeof(radio_hal_event_t));
+    event.type = RADIO_EVENT_EA;
+    event.on = active;
+    onCallback(&event);
+    return Return<void>();
+}
+Return<void> RadioHalHidl::Tuner::newMetadata(uint32_t channel, uint32_t subChannel,
+                                          const ::android::hardware::hidl_vec<MetaData>& metadata)
+{
+    ALOGV("%s IN", __FUNCTION__);
+    radio_hal_event_t event;
+    memset(&event, 0, sizeof(radio_hal_event_t));
+    event.type = RADIO_EVENT_METADATA;
+    HidlUtils::convertMetaDataFromHal(&event.metadata, metadata, channel, subChannel);
+    onCallback(&event);
+    if (event.metadata != NULL) {
+        radio_metadata_deallocate(event.info.metadata);
+    }
+    return Return<void>();
+}
+
+
+RadioHalHidl::Tuner::Tuner(sp<TunerCallbackInterface> callback, sp<RadioHalHidl> module)
+    : TunerInterface(), mHalTuner(NULL), mCallback(callback), mParentModule(module)
+{
+}
+
+
+RadioHalHidl::Tuner::~Tuner()
+{
+}
+
+void RadioHalHidl::Tuner::handleHwFailure()
+{
+    ALOGV("%s IN", __FUNCTION__);
+    sp<RadioHalHidl> parentModule = mParentModule.promote();
+    if (parentModule != 0) {
+        parentModule->clearService();
+    }
+    radio_hal_event_t event;
+    memset(&event, 0, sizeof(radio_hal_event_t));
+    event.type = RADIO_EVENT_HW_FAILURE;
+    onCallback(&event);
+    mHalTuner.clear();
+}
+
+status_t RadioHalHidl::Tuner::checkHidlStatus(Status hidlStatus)
+{
+    status_t status = hidlStatus.transactionError();
+    if (status == DEAD_OBJECT) {
+        handleHwFailure();
+    }
+    return status;
+}
+
+void RadioHalHidl::Tuner::onCallback(radio_hal_event_t *halEvent)
+{
+    if (mCallback != 0) {
+        mCallback->onEvent(halEvent);
+    }
+}
+
+} // namespace android
diff --git a/services/radio/RadioHalHidl.h b/services/radio/RadioHalHidl.h
new file mode 100644
index 0000000..5211ee2
--- /dev/null
+++ b/services/radio/RadioHalHidl.h
@@ -0,0 +1,108 @@
+/*
+ * 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_RADIO_HAL_HIDL_H
+#define ANDROID_HARDWARE_RADIO_HAL_HIDL_H
+
+#include <utils/RefBase.h>
+#include <utils/threads.h>
+#include "RadioInterface.h"
+#include "TunerInterface.h"
+#include "TunerCallbackInterface.h"
+#include <android/hardware/broadcastradio/1.0/types.h>
+#include <android/hardware/broadcastradio/1.0/IBroadcastRadio.h>
+#include <android/hardware/broadcastradio/1.0/ITuner.h>
+#include <android/hardware/broadcastradio/1.0/ITunerCallback.h>
+
+namespace android {
+
+using android::hardware::Status;
+using android::hardware::Return;
+using android::hardware::broadcastradio::V1_0::Result;
+using android::hardware::broadcastradio::V1_0::IBroadcastRadio;
+using android::hardware::broadcastradio::V1_0::ITuner;
+using android::hardware::broadcastradio::V1_0::ITunerCallback;
+
+using android::hardware::broadcastradio::V1_0::BandConfig;
+using android::hardware::broadcastradio::V1_0::ProgramInfo;
+using android::hardware::broadcastradio::V1_0::MetaData;
+
+class RadioHalHidl : public RadioInterface
+{
+public:
+                    RadioHalHidl(radio_class_t classId);
+
+                    // RadioInterface
+        virtual int getProperties(radio_hal_properties_t *properties);
+        virtual int openTuner(const radio_hal_band_config_t *config,
+                              bool audio,
+                              sp<TunerCallbackInterface> callback,
+                              sp<TunerInterface>& tuner);
+        virtual int closeTuner(sp<TunerInterface>& tuner);
+
+        class Tuner  : public TunerInterface, public virtual ITunerCallback
+        {
+        public:
+                        Tuner(sp<TunerCallbackInterface> callback, sp<RadioHalHidl> module);
+
+                        // TunerInterface
+            virtual int setConfiguration(const radio_hal_band_config_t *config);
+            virtual int getConfiguration(radio_hal_band_config_t *config);
+            virtual int scan(radio_direction_t direction, bool skip_sub_channel);
+            virtual int step(radio_direction_t direction, bool skip_sub_channel);
+            virtual int tune(unsigned int channel, unsigned int sub_channel);
+            virtual int cancel();
+            virtual int getProgramInformation(radio_program_info_t *info);
+
+                        // ITunerCallback
+            virtual Return<void> hardwareFailure();
+            virtual Return<void> configChange(Result result, const BandConfig& config);
+            virtual Return<void> tuneComplete(Result result, const ProgramInfo& info);
+            virtual Return<void> afSwitch(const ProgramInfo& info);
+            virtual Return<void> antennaStateChange(bool connected);
+            virtual Return<void> trafficAnnouncement(bool active);
+            virtual Return<void> emergencyAnnouncement(bool active);
+            virtual Return<void> newMetadata(uint32_t channel, uint32_t subChannel,
+                                         const ::android::hardware::hidl_vec<MetaData>& metadata);
+
+            void setHalTuner(sp<ITuner>& halTuner) { mHalTuner = halTuner; }
+            sp<ITuner> getHalTuner() { return mHalTuner; }
+
+        private:
+            virtual          ~Tuner();
+
+                    void     onCallback(radio_hal_event_t *halEvent);
+                    void     handleHwFailure();
+                    status_t checkHidlStatus(Status hidlStatus);
+
+            sp<ITuner> mHalTuner;
+            sp<TunerCallbackInterface>  mCallback;
+            wp<RadioHalHidl> mParentModule;
+        };
+
+        sp<IBroadcastRadio> getService();
+        void clearService();
+
+private:
+        virtual         ~RadioHalHidl();
+
+                radio_class_t mClassId;
+                sp<IBroadcastRadio> mHalModule;
+};
+
+} // namespace android
+
+#endif // ANDROID_HARDWARE_RADIO_HAL_HIDL_H
diff --git a/services/soundtrigger/SoundTriggerHwService.cpp b/services/soundtrigger/SoundTriggerHwService.cpp
index 3ba7f62..54f9b95 100644
--- a/services/soundtrigger/SoundTriggerHwService.cpp
+++ b/services/soundtrigger/SoundTriggerHwService.cpp
@@ -73,8 +73,7 @@
     ALOGI("loaded default module %s, handle %d", descriptor.properties.description,
                                                  descriptor.handle);
 
-    sp<ISoundTriggerClient> client;
-    sp<Module> module = new Module(this, halInterface, descriptor, client);
+    sp<Module> module = new Module(this, halInterface, descriptor);
     mModules.add(descriptor.handle, module);
     mCallbackThread = new CallbackThread(this);
 }
@@ -126,11 +125,13 @@
     }
     sp<Module> module = mModules.valueAt(index);
 
-    module->setClient(client);
-    IInterface::asBinder(client)->linkToDeath(module);
-    moduleInterface = module;
+    sp<ModuleClient> moduleClient = module->addClient(client);
+    if (moduleClient == 0) {
+        return NO_INIT;
+    }
 
-    module->setCaptureState_l(mCaptureState);
+    moduleClient->setCaptureState_l(mCaptureState);
+    moduleInterface = moduleClient;
 
     return NO_ERROR;
 }
@@ -147,14 +148,6 @@
 }
 
 
-void SoundTriggerHwService::detachModule(const sp<Module>& module)
-{
-    ALOGV("detachModule");
-    AutoMutex lock(mServiceLock);
-    module->clearClient();
-}
-
-
 static const int kDumpLockRetries = 50;
 static const int kDumpLockSleep = 60000;
 
@@ -276,8 +269,10 @@
          return;
      }
 
-     sendCallbackEvent_l(new CallbackEvent(CallbackEvent::TYPE_RECOGNITION,
-                                                  eventMemory, strongModule));
+    sp<CallbackEvent> callbackEvent = new CallbackEvent(CallbackEvent::TYPE_RECOGNITION,
+                                                        eventMemory);
+    callbackEvent->setModule(strongModule);
+    sendCallbackEvent_l(callbackEvent);
 }
 
 // static
@@ -329,8 +324,10 @@
     if (strongModule == 0) {
         return;
     }
-    sendCallbackEvent_l(new CallbackEvent(CallbackEvent::TYPE_SOUNDMODEL,
-                                                 eventMemory, strongModule));
+    sp<CallbackEvent> callbackEvent = new CallbackEvent(CallbackEvent::TYPE_SOUNDMODEL,
+                                                        eventMemory);
+    callbackEvent->setModule(strongModule);
+    sendCallbackEvent_l(callbackEvent);
 }
 
 
@@ -366,8 +363,23 @@
     if (strongModule == 0) {
         return;
     }
-    sendCallbackEvent_l(new CallbackEvent(CallbackEvent::TYPE_SERVICE_STATE,
-                                                 eventMemory, strongModule));
+    sp<CallbackEvent> callbackEvent = new CallbackEvent(CallbackEvent::TYPE_SERVICE_STATE,
+                                                        eventMemory);
+    callbackEvent->setModule(strongModule);
+    sendCallbackEvent_l(callbackEvent);
+}
+
+void SoundTriggerHwService::sendServiceStateEvent_l(sound_trigger_service_state_t state,
+                                                    ModuleClient *moduleClient)
+{
+    sp<IMemory> eventMemory = prepareServiceStateEvent_l(state);
+    if (eventMemory == 0) {
+        return;
+    }
+    sp<CallbackEvent> callbackEvent = new CallbackEvent(CallbackEvent::TYPE_SERVICE_STATE,
+                                                        eventMemory);
+    callbackEvent->setModuleClient(moduleClient);
+    sendCallbackEvent_l(callbackEvent);
 }
 
 // call with mServiceLock held
@@ -380,14 +392,25 @@
 {
     ALOGV("onCallbackEvent");
     sp<Module> module;
+    sp<ModuleClient> moduleClient;
     {
         AutoMutex lock(mServiceLock);
+        //CallbackEvent is either for Module or ModuleClient
         module = event->mModule.promote();
         if (module == 0) {
-            return;
+            moduleClient = event->mModuleClient.promote();
+            if (moduleClient == 0) {
+                return;
+            }
         }
     }
-    module->onCallbackEvent(event);
+    if (module != 0) {
+        ALOGV("onCallbackEvent for module");
+        module->onCallbackEvent(event);
+    } else if (moduleClient != 0) {
+        ALOGV("onCallbackEvent for moduleClient");
+        moduleClient->onCallbackEvent(event);
+    }
     {
         AutoMutex lock(mServiceLock);
         // clear now to execute with mServiceLock locked
@@ -457,9 +480,8 @@
     mCallbackCond.signal();
 }
 
-SoundTriggerHwService::CallbackEvent::CallbackEvent(event_type type, sp<IMemory> memory,
-                                                    wp<Module> module)
-    : mType(type), mMemory(memory), mModule(module)
+SoundTriggerHwService::CallbackEvent::CallbackEvent(event_type type, sp<IMemory> memory)
+    : mType(type), mMemory(memory)
 {
 }
 
@@ -473,25 +495,59 @@
 
 SoundTriggerHwService::Module::Module(const sp<SoundTriggerHwService>& service,
                                       const sp<SoundTriggerHalInterface>& halInterface,
-                                      sound_trigger_module_descriptor descriptor,
-                                      const sp<ISoundTriggerClient>& client)
+                                      sound_trigger_module_descriptor descriptor)
  : mService(service), mHalInterface(halInterface), mDescriptor(descriptor),
-   mClient(client), mServiceState(SOUND_TRIGGER_STATE_NO_INIT)
+   mServiceState(SOUND_TRIGGER_STATE_NO_INIT)
 {
 }
 
 SoundTriggerHwService::Module::~Module() {
+    mModuleClients.clear();
 }
 
-void SoundTriggerHwService::Module::detach() {
-    ALOGV("detach()");
-    if (!captureHotwordAllowed()) {
+sp<SoundTriggerHwService::ModuleClient>
+SoundTriggerHwService::Module::addClient(const sp<ISoundTriggerClient>& client)
+{
+    AutoMutex lock(mLock);
+    sp<ModuleClient> moduleClient;
+
+    for (size_t i = 0; i < mModuleClients.size(); i++) {
+        if (mModuleClients[i]->client() == client) {
+            // Client already present, reuse client
+            return moduleClient;
+        }
+    }
+    moduleClient = new ModuleClient(this, client);
+
+    ALOGV("addClient() client %p", moduleClient.get());
+    mModuleClients.add(moduleClient);
+
+    return moduleClient;
+}
+
+void SoundTriggerHwService::Module::detach(const sp<ModuleClient>& moduleClient)
+{
+    ALOGV("Module::detach()");
+    AutoMutex lock(mLock);
+    ssize_t index = -1;
+
+    for (size_t i = 0; i < mModuleClients.size(); i++) {
+        if (mModuleClients[i] == moduleClient) {
+            index = i;
+            break;
+        }
+    }
+    if (index == -1) {
         return;
     }
-    {
-        AutoMutex lock(mLock);
-        for (size_t i = 0; i < mModels.size(); i++) {
-            sp<Model> model = mModels.valueAt(i);
+
+    ALOGV("remove client %p", moduleClient.get());
+    mModuleClients.removeAt(index);
+
+    for (size_t i = 0; i < mModels.size(); i++) {
+        sp<Model> model = mModels.valueAt(i);
+        if (moduleClient == model->mModuleClient) {
+            mModels.removeItemsAt(i);
             ALOGV("detach() unloading model %d", model->mHandle);
             if (mHalInterface != 0) {
                 if (model->mState == Model::STATE_ACTIVE) {
@@ -499,29 +555,20 @@
                 }
                 mHalInterface->unloadSoundModel(model->mHandle);
             }
+            AudioSystem::releaseSoundTriggerSession(model->mCaptureSession);
+            mHalInterface->unloadSoundModel(model->mHandle);
         }
-        mModels.clear();
     }
-    if (mClient != 0) {
-        IInterface::asBinder(mClient)->unlinkToDeath(this);
-    }
-    sp<SoundTriggerHwService> service = mService.promote();
-    if (service == 0) {
-        return;
-    }
-    service->detachModule(this);
 }
 
 status_t SoundTriggerHwService::Module::loadSoundModel(const sp<IMemory>& modelMemory,
-                                sound_model_handle_t *handle)
+                                                       sp<ModuleClient> moduleClient,
+                                                       sound_model_handle_t *handle)
 {
     ALOGV("loadSoundModel() handle");
     if (mHalInterface == 0) {
         return NO_INIT;
     }
-    if (!captureHotwordAllowed()) {
-        return PERMISSION_DENIED;
-    }
     if (modelMemory == 0 || modelMemory->pointer() == NULL) {
         ALOGE("loadSoundModel() modelMemory is 0 or has NULL pointer()");
         return BAD_VALUE;
@@ -569,7 +616,8 @@
         return status;
     }
 
-    sp<Model> model = new Model(*handle, session, ioHandle, device, sound_model->type);
+    sp<Model> model = new Model(*handle, session, ioHandle, device, sound_model->type,
+                                moduleClient);
     mModels.replaceValueFor(*handle, model);
 
     return status;
@@ -578,10 +626,6 @@
 status_t SoundTriggerHwService::Module::unloadSoundModel(sound_model_handle_t handle)
 {
     ALOGV("unloadSoundModel() model handle %d", handle);
-    if (!captureHotwordAllowed()) {
-        return PERMISSION_DENIED;
-    }
-
     AutoMutex lock(mLock);
     return unloadSoundModel_l(handle);
 }
@@ -612,10 +656,6 @@
     if (mHalInterface == 0) {
         return NO_INIT;
     }
-    if (!captureHotwordAllowed()) {
-        return PERMISSION_DENIED;
-    }
-
     if (dataMemory == 0 || dataMemory->pointer() == NULL) {
         ALOGE("startRecognition() dataMemory is 0 or has NULL pointer()");
         return BAD_VALUE;
@@ -668,10 +708,6 @@
     if (mHalInterface == 0) {
         return NO_INIT;
     }
-    if (!captureHotwordAllowed()) {
-        return PERMISSION_DENIED;
-    }
-
     AutoMutex lock(mLock);
     sp<Model> model = getModel(handle);
     if (model == 0) {
@@ -686,7 +722,6 @@
     return NO_ERROR;
 }
 
-
 void SoundTriggerHwService::Module::onCallbackEvent(const sp<CallbackEvent>& event)
 {
     ALOGV("onCallbackEvent type %d", event->mType);
@@ -696,8 +731,8 @@
     if (eventMemory == 0 || eventMemory->pointer() == NULL) {
         return;
     }
-    if (mClient == 0) {
-        ALOGI("%s mClient == 0", __func__);
+    if (mModuleClients.isEmpty()) {
+        ALOGI("%s no clients", __func__);
         return;
     }
 
@@ -720,7 +755,7 @@
 
             recognitionEvent->capture_session = model->mCaptureSession;
             model->mState = Model::STATE_IDLE;
-            client = mClient;
+            client = model->mModuleClient->client();
         }
         if (client != 0) {
             client->onRecognitionEvent(eventMemory);
@@ -737,20 +772,24 @@
                 ALOGW("%s model == 0", __func__);
                 return;
             }
-            client = mClient;
+            client = model->mModuleClient->client();
         }
         if (client != 0) {
             client->onSoundModelEvent(eventMemory);
         }
     } break;
     case CallbackEvent::TYPE_SERVICE_STATE: {
-        sp<ISoundTriggerClient> client;
+        Vector< sp<ISoundTriggerClient> > clients;
         {
             AutoMutex lock(mLock);
-            client = mClient;
+            for (size_t i = 0; i < mModuleClients.size(); i++) {
+                if (mModuleClients[i] != 0) {
+                    clients.add(mModuleClients[i]->client());
+                }
+            }
         }
-        if (client != 0) {
-            client->onServiceStateChange(eventMemory);
+        for (size_t i = 0; i < clients.size(); i++) {
+            clients[i]->onServiceStateChange(eventMemory);
         }
     } break;
     default:
@@ -769,12 +808,6 @@
     return model;
 }
 
-void SoundTriggerHwService::Module::binderDied(
-    const wp<IBinder> &who __unused) {
-    ALOGW("client binder died for module %d", mDescriptor.handle);
-    detach();
-}
-
 // Called with mServiceLock held
 void SoundTriggerHwService::Module::setCaptureState_l(bool active)
 {
@@ -858,8 +891,10 @@
     }
 
     for (size_t i = 0; i < events.size(); i++) {
-        service->sendCallbackEvent_l(new CallbackEvent(CallbackEvent::TYPE_RECOGNITION, events[i],
-                                                     this));
+        sp<CallbackEvent> callbackEvent = new CallbackEvent(CallbackEvent::TYPE_RECOGNITION,
+                                                            events[i]);
+        callbackEvent->setModule(this);
+        service->sendCallbackEvent_l(callbackEvent);
     }
 
 exit:
@@ -869,17 +904,170 @@
 
 SoundTriggerHwService::Model::Model(sound_model_handle_t handle, audio_session_t session,
                                     audio_io_handle_t ioHandle, audio_devices_t device,
-                                    sound_trigger_sound_model_type_t type) :
+                                    sound_trigger_sound_model_type_t type,
+                                    sp<ModuleClient>& moduleClient) :
     mHandle(handle), mState(STATE_IDLE), mCaptureSession(session),
-    mCaptureIOHandle(ioHandle), mCaptureDevice(device), mType(type)
+    mCaptureIOHandle(ioHandle), mCaptureDevice(device), mType(type),
+    mModuleClient(moduleClient)
 {
-
 }
 
-status_t SoundTriggerHwService::Module::dump(int fd __unused,
-                                             const Vector<String16>& args __unused) {
+#undef LOG_TAG
+#define LOG_TAG "SoundTriggerHwService::ModuleClient"
+
+SoundTriggerHwService::ModuleClient::ModuleClient(const sp<Module>& module,
+                                                  const sp<ISoundTriggerClient>& client)
+ : mModule(module), mClient(client)
+{
+}
+
+void SoundTriggerHwService::ModuleClient::onFirstRef()
+{
+    IInterface::asBinder(mClient)->linkToDeath(this);
+}
+
+SoundTriggerHwService::ModuleClient::~ModuleClient()
+{
+}
+
+status_t SoundTriggerHwService::ModuleClient::dump(int fd __unused,
+                                                   const Vector<String16>& args __unused) {
     String8 result;
     return NO_ERROR;
 }
 
+void SoundTriggerHwService::ModuleClient::detach() {
+    ALOGV("detach()");
+    if (!captureHotwordAllowed()) {
+        return;
+    }
+
+    {
+        AutoMutex lock(mLock);
+        if (mClient != 0) {
+            IInterface::asBinder(mClient)->unlinkToDeath(this);
+            mClient.clear();
+        }
+    }
+
+    sp<Module> module = mModule.promote();
+    if (module == 0) {
+        return;
+    }
+    module->detach(this);
+}
+
+status_t SoundTriggerHwService::ModuleClient::loadSoundModel(const sp<IMemory>& modelMemory,
+                                sound_model_handle_t *handle)
+{
+    ALOGV("loadSoundModel() handle");
+    if (!captureHotwordAllowed()) {
+        return PERMISSION_DENIED;
+    }
+
+    sp<Module> module = mModule.promote();
+    if (module == 0) {
+        return NO_INIT;
+    }
+    return module->loadSoundModel(modelMemory, this, handle);
+}
+
+status_t SoundTriggerHwService::ModuleClient::unloadSoundModel(sound_model_handle_t handle)
+{
+    ALOGV("unloadSoundModel() model handle %d", handle);
+    if (!captureHotwordAllowed()) {
+        return PERMISSION_DENIED;
+    }
+
+    sp<Module> module = mModule.promote();
+    if (module == 0) {
+        return NO_INIT;
+    }
+    return module->unloadSoundModel(handle);
+}
+
+status_t SoundTriggerHwService::ModuleClient::startRecognition(sound_model_handle_t handle,
+                                 const sp<IMemory>& dataMemory)
+{
+    ALOGV("startRecognition() model handle %d", handle);
+    if (!captureHotwordAllowed()) {
+        return PERMISSION_DENIED;
+    }
+
+    sp<Module> module = mModule.promote();
+    if (module == 0) {
+        return NO_INIT;
+    }
+    return module->startRecognition(handle, dataMemory);
+}
+
+status_t SoundTriggerHwService::ModuleClient::stopRecognition(sound_model_handle_t handle)
+{
+    ALOGV("stopRecognition() model handle %d", handle);
+    if (!captureHotwordAllowed()) {
+        return PERMISSION_DENIED;
+    }
+
+    sp<Module> module = mModule.promote();
+    if (module == 0) {
+        return NO_INIT;
+    }
+    return module->stopRecognition(handle);
+}
+
+void SoundTriggerHwService::ModuleClient::setCaptureState_l(bool active)
+{
+    ALOGV("ModuleClient::setCaptureState_l %d", active);
+    sp<SoundTriggerHwService> service;
+    sound_trigger_service_state_t state;
+
+    sp<Module> module = mModule.promote();
+    if (module == 0) {
+        return;
+    }
+    {
+        AutoMutex lock(mLock);
+        state = (active && !module->isConcurrentCaptureAllowed()) ?
+                                        SOUND_TRIGGER_STATE_DISABLED : SOUND_TRIGGER_STATE_ENABLED;
+
+        service = module->service().promote();
+        if (service == 0) {
+            return;
+        }
+    }
+    service->sendServiceStateEvent_l(state, this);
+}
+
+void SoundTriggerHwService::ModuleClient::onCallbackEvent(const sp<CallbackEvent>& event)
+{
+    ALOGV("ModuleClient onCallbackEvent type %d", event->mType);
+
+    sp<IMemory> eventMemory = event->mMemory;
+
+    if (eventMemory == 0 || eventMemory->pointer() == NULL) {
+        return;
+    }
+
+    switch (event->mType) {
+    case CallbackEvent::TYPE_SERVICE_STATE: {
+        sp<ISoundTriggerClient> client;
+        {
+            AutoMutex lock(mLock);
+            client = mClient;
+        }
+        if (client !=0 ) {
+            client->onServiceStateChange(eventMemory);
+        }
+    } break;
+    default:
+        LOG_ALWAYS_FATAL("onCallbackEvent unknown event type %d", event->mType);
+    }
+}
+
+void SoundTriggerHwService::ModuleClient::binderDied(
+    const wp<IBinder> &who __unused) {
+    ALOGW("client binder died for client %p", this);
+    detach();
+}
+
 }; // namespace android
diff --git a/services/soundtrigger/SoundTriggerHwService.h b/services/soundtrigger/SoundTriggerHwService.h
index 7f7d0cc..60ebb35 100644
--- a/services/soundtrigger/SoundTriggerHwService.h
+++ b/services/soundtrigger/SoundTriggerHwService.h
@@ -39,6 +39,7 @@
     friend class BinderService<SoundTriggerHwService>;
 public:
     class Module;
+    class ModuleClient;
 
     static char const* getServiceName() { return "media.sound_trigger_hw"; }
 
@@ -69,7 +70,8 @@
         };
 
         Model(sound_model_handle_t handle, audio_session_t session, audio_io_handle_t ioHandle,
-              audio_devices_t device, sound_trigger_sound_model_type_t type);
+              audio_devices_t device, sound_trigger_sound_model_type_t type,
+              sp<ModuleClient>& moduleClient);
         ~Model() {}
 
         sound_model_handle_t    mHandle;
@@ -79,6 +81,7 @@
         audio_devices_t         mCaptureDevice;
         sound_trigger_sound_model_type_t mType;
         struct sound_trigger_recognition_config mConfig;
+        sp<ModuleClient>        mModuleClient;
     };
 
     class CallbackEvent : public RefBase {
@@ -88,27 +91,76 @@
             TYPE_SOUNDMODEL,
             TYPE_SERVICE_STATE,
         } event_type;
-        CallbackEvent(event_type type, sp<IMemory> memory, wp<Module> module);
+        CallbackEvent(event_type type, sp<IMemory> memory);
 
         virtual             ~CallbackEvent();
 
+        void setModule(wp<Module> module) { mModule = module; }
+        void setModuleClient(wp<ModuleClient> moduleClient) { mModuleClient = moduleClient; }
+
         event_type mType;
         sp<IMemory> mMemory;
         wp<Module> mModule;
+        wp<ModuleClient> mModuleClient;
     };
 
-    class Module : public virtual RefBase,
-                   public BnSoundTrigger,
-                   public IBinder::DeathRecipient     {
+    class Module : public RefBase {
     public:
 
        Module(const sp<SoundTriggerHwService>& service,
               const sp<SoundTriggerHalInterface>& halInterface,
-              sound_trigger_module_descriptor descriptor,
-              const sp<ISoundTriggerClient>& client);
+              sound_trigger_module_descriptor descriptor);
 
        virtual ~Module();
 
+       virtual status_t loadSoundModel(const sp<IMemory>& modelMemory,
+                                       sp<ModuleClient> moduleClient,
+                                       sound_model_handle_t *handle);
+
+       virtual status_t unloadSoundModel(sound_model_handle_t handle);
+
+       virtual status_t startRecognition(sound_model_handle_t handle,
+                                         const sp<IMemory>& dataMemory);
+       virtual status_t stopRecognition(sound_model_handle_t handle);
+
+       sp<SoundTriggerHalInterface> halInterface() const { return mHalInterface; }
+       struct sound_trigger_module_descriptor descriptor() { return mDescriptor; }
+       wp<SoundTriggerHwService> service() const { return mService; }
+       bool isConcurrentCaptureAllowed() const { return mDescriptor.properties.concurrent_capture; }
+
+       sp<Model> getModel(sound_model_handle_t handle);
+
+       void setCaptureState_l(bool active);
+
+       sp<ModuleClient> addClient(const sp<ISoundTriggerClient>& client);
+
+       void detach(const sp<ModuleClient>& moduleClient);
+
+       void onCallbackEvent(const sp<CallbackEvent>& event);
+
+    private:
+
+        status_t unloadSoundModel_l(sound_model_handle_t handle);
+
+        Mutex                                  mLock;
+        wp<SoundTriggerHwService>              mService;
+        sp<SoundTriggerHalInterface>           mHalInterface;
+        struct sound_trigger_module_descriptor mDescriptor;
+        Vector< sp<ModuleClient> >             mModuleClients;
+        DefaultKeyedVector< sound_model_handle_t, sp<Model> >     mModels;
+        sound_trigger_service_state_t          mServiceState;
+    }; // class Module
+
+    class ModuleClient : public virtual RefBase,
+                         public BnSoundTrigger,
+                         public IBinder::DeathRecipient {
+    public:
+
+       ModuleClient(const sp<Module>& module,
+              const sp<ISoundTriggerClient>& client);
+
+       virtual ~ModuleClient();
+
        virtual void detach();
 
        virtual status_t loadSoundModel(const sp<IMemory>& modelMemory,
@@ -122,35 +174,23 @@
 
        virtual status_t dump(int fd, const Vector<String16>& args);
 
-
-       struct sound_trigger_module_descriptor descriptor() { return mDescriptor; }
-       void setClient(const sp<ISoundTriggerClient>& client) { mClient = client; }
-       void clearClient() { mClient.clear(); }
-       sp<ISoundTriggerClient> client() const { return mClient; }
-       wp<SoundTriggerHwService> service() const { return mService; }
-
-       void onCallbackEvent(const sp<CallbackEvent>& event);
-
-       sp<Model> getModel(sound_model_handle_t handle);
-
-       void setCaptureState_l(bool active);
+       virtual void onFirstRef();
 
        // IBinder::DeathRecipient implementation
        virtual void        binderDied(const wp<IBinder> &who);
 
+       void onCallbackEvent(const sp<CallbackEvent>& event);
+
+       void setCaptureState_l(bool active);
+
+       sp<ISoundTriggerClient> client() const { return mClient; }
+
     private:
 
-       status_t unloadSoundModel_l(sound_model_handle_t handle);
-
-
-        Mutex                                  mLock;
-        wp<SoundTriggerHwService>              mService;
-        sp<SoundTriggerHalInterface>           mHalInterface;
-        struct sound_trigger_module_descriptor mDescriptor;
-        sp<ISoundTriggerClient>                mClient;
-        DefaultKeyedVector< sound_model_handle_t, sp<Model> >     mModels;
-        sound_trigger_service_state_t          mServiceState;
-    }; // class Module
+        mutable Mutex               mLock;
+        wp<Module>                  mModule;
+        sp<ISoundTriggerClient>     mClient;
+    }; // class ModuleClient
 
     class CallbackThread : public Thread {
     public:
@@ -175,8 +215,6 @@
         Vector< sp<CallbackEvent> > mEventQueue;
     };
 
-           void detachModule(const sp<Module>& module);
-
     static void recognitionCallback(struct sound_trigger_recognition_event *event, void *cookie);
            sp<IMemory> prepareRecognitionEvent_l(struct sound_trigger_recognition_event *event);
            void sendRecognitionEvent(struct sound_trigger_recognition_event *event, Module *module);
@@ -187,6 +225,8 @@
 
            sp<IMemory> prepareServiceStateEvent_l(sound_trigger_service_state_t state);
            void sendServiceStateEvent_l(sound_trigger_service_state_t state, Module *module);
+           void sendServiceStateEvent_l(sound_trigger_service_state_t state,
+                                        ModuleClient *moduleClient);
 
            void sendCallbackEvent_l(const sp<CallbackEvent>& event);
            void onCallbackEvent(const sp<CallbackEvent>& event);