Merge "Suppress unused paramter warnings in omx hal 1.0"
diff --git a/cmds/stagefright/Android.mk b/cmds/stagefright/Android.mk
index a98a207..ad70470 100644
--- a/cmds/stagefright/Android.mk
+++ b/cmds/stagefright/Android.mk
@@ -10,8 +10,9 @@
 LOCAL_SHARED_LIBRARIES := \
         libstagefright libmedia libutils libbinder libstagefright_foundation \
         libjpeg libgui libcutils liblog \
+        libhidlmemory \
         android.hardware.media.omx@1.0 \
-        android.hardware.media.omx@1.0-utils
+        android.hardware.media.omx@1.0-utils \
 
 LOCAL_C_INCLUDES:= \
         frameworks/av/media/libstagefright \
diff --git a/drm/libmediadrm/Android.mk b/drm/libmediadrm/Android.mk
index 8e3cc40..7176582 100644
--- a/drm/libmediadrm/Android.mk
+++ b/drm/libmediadrm/Android.mk
@@ -6,12 +6,24 @@
 
 include $(CLEAR_VARS)
 
-LOCAL_SRC_FILES:= \
+LOCAL_AIDL_INCLUDES := \
+    frameworks/base/media/java
+
+LOCAL_SRC_FILES := \
+    ../../../base/media/java/android/media/ICas.aidl \
+    ../../../base/media/java/android/media/ICasListener.aidl \
+    ../../../base/media/java/android/media/IDescrambler.aidl \
+    ../../../base/media/java/android/media/IMediaCasService.aidl \
+
+LOCAL_SRC_FILES += \
+    CasImpl.cpp \
+    DescramblerImpl.cpp \
     DrmSessionManager.cpp \
     ICrypto.cpp \
     IDrm.cpp \
     IDrmClient.cpp \
     IMediaDrmService.cpp \
+    MediaCasDefs.cpp \
     SharedLibrary.cpp
 ifneq ($(DISABLE_TREBLE_DRM), true)
 LOCAL_SRC_FILES += \
diff --git a/drm/libmediadrm/CasImpl.cpp b/drm/libmediadrm/CasImpl.cpp
new file mode 100644
index 0000000..de15244
--- /dev/null
+++ b/drm/libmediadrm/CasImpl.cpp
@@ -0,0 +1,201 @@
+
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+//#define LOG_NDEBUG 0
+#define LOG_TAG "CasImpl"
+
+#include <android/media/ICasListener.h>
+#include <media/cas/CasAPI.h>
+#include <media/CasImpl.h>
+#include <media/SharedLibrary.h>
+#include <utils/Log.h>
+
+namespace android {
+
+static Status getBinderStatus(status_t err) {
+    if (err == OK) {
+        return Status::ok();
+    }
+    if (err == BAD_VALUE) {
+        return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT);
+    }
+    if (err == INVALID_OPERATION) {
+        return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE);
+    }
+    return Status::fromServiceSpecificError(err);
+}
+
+static String8 sessionIdToString(const CasSessionId &sessionId) {
+    String8 result;
+    for (size_t i = 0; i < sessionId.size(); i++) {
+        result.appendFormat("%02x ", sessionId[i]);
+    }
+    if (result.isEmpty()) {
+        result.append("(null)");
+    }
+    return result;
+}
+
+CasImpl::CasImpl(const sp<ICasListener> &listener)
+    : mPlugin(NULL), mListener(listener) {
+    ALOGV("CTOR: mPlugin=%p", mPlugin);
+}
+
+CasImpl::~CasImpl() {
+    ALOGV("DTOR: mPlugin=%p", mPlugin);
+    release();
+}
+
+//static
+void CasImpl::OnEvent(
+        void *appData,
+        int32_t event,
+        int32_t arg,
+        uint8_t *data,
+        size_t size) {
+    if (appData == NULL) {
+        ALOGE("Invalid appData!");
+        return;
+    }
+    CasImpl *casImpl = static_cast<CasImpl *>(appData);
+    casImpl->onEvent(event, arg, data, size);
+}
+
+void CasImpl::init(const sp<SharedLibrary>& library, CasPlugin *plugin) {
+    mLibrary = library;
+    mPlugin = plugin;
+}
+
+void CasImpl::onEvent(
+        int32_t event, int32_t arg, uint8_t *data, size_t size) {
+    if (mListener == NULL) {
+        return;
+    }
+
+    std::unique_ptr<CasData> eventData;
+    if (data != NULL && size > 0) {
+        eventData.reset(new CasData(data, data + size));
+    }
+
+    mListener->onEvent(event, arg, eventData);
+}
+
+Status CasImpl::setPrivateData(const CasData& pvtData) {
+    ALOGV("setPrivateData");
+    return getBinderStatus(mPlugin->setPrivateData(pvtData));
+}
+
+Status CasImpl::openSession(int32_t program_number, CasSessionId* sessionId) {
+    ALOGV("openSession: program_number=%d", program_number);
+
+    status_t err = mPlugin->openSession(program_number, sessionId);
+
+    ALOGV("openSession: session opened for program_number=%d, sessionId=%s",
+            program_number, sessionIdToString(*sessionId).string());
+
+    return getBinderStatus(err);
+}
+
+Status CasImpl::openSessionForStream(
+        int32_t program_number,
+        int32_t elementary_PID,
+        CasSessionId* sessionId) {
+    ALOGV("openSession: program_number=%d, elementary_PID=%d",
+            program_number, elementary_PID);
+
+    status_t err = mPlugin->openSession(
+            program_number, elementary_PID, sessionId);
+
+    ALOGV("openSession: session opened for "
+            "program_number=%d, elementary_PID=%d, sessionId=%s",
+            program_number, elementary_PID,
+            sessionIdToString(*sessionId).string());
+
+    return getBinderStatus(err);
+}
+
+Status CasImpl::setSessionPrivateData(
+        const CasSessionId &sessionId, const CasData& pvtData) {
+    ALOGV("setSessionPrivateData: sessionId=%s",
+            sessionIdToString(sessionId).string());
+
+    return getBinderStatus(mPlugin->setSessionPrivateData(sessionId, pvtData));
+}
+
+Status CasImpl::closeSession(const CasSessionId &sessionId) {
+    ALOGV("closeSession: sessionId=%s",
+            sessionIdToString(sessionId).string());
+
+    return getBinderStatus(mPlugin->closeSession(sessionId));
+}
+
+Status CasImpl::processEcm(const CasSessionId &sessionId, const ParcelableCasData& ecm) {
+    ALOGV("processEcm: sessionId=%s",
+            sessionIdToString(sessionId).string());
+
+    return getBinderStatus(mPlugin->processEcm(sessionId, ecm));
+}
+
+Status CasImpl::processEmm(const ParcelableCasData& emm) {
+    ALOGV("processEmm");
+
+    return getBinderStatus(mPlugin->processEmm(emm));
+}
+
+Status CasImpl::sendEvent(
+        int32_t event, int32_t arg, const ::std::unique_ptr<CasData> &eventData) {
+    ALOGV("sendEvent");
+
+    status_t err;
+    if (eventData == nullptr) {
+        err = mPlugin->sendEvent(event, arg, CasData());
+    } else {
+        err = mPlugin->sendEvent(event, arg, *eventData);
+    }
+    return getBinderStatus(err);
+}
+
+Status CasImpl::provision(const String16& provisionString) {
+    ALOGV("provision: provisionString=%s", String8(provisionString).string());
+
+    return getBinderStatus(mPlugin->provision(String8(provisionString)));
+}
+
+Status CasImpl::refreshEntitlements(
+        int32_t refreshType, const ::std::unique_ptr<CasData> &refreshData) {
+    ALOGV("refreshEntitlements");
+
+    status_t err;
+    if (refreshData == nullptr) {
+        err = mPlugin->refreshEntitlements(refreshType, CasData());
+    } else {
+        err = mPlugin->refreshEntitlements(refreshType, *refreshData);
+    }
+    return getBinderStatus(err);
+}
+
+Status CasImpl::release() {
+    ALOGV("release: mPlugin=%p", mPlugin);
+
+    if (mPlugin != NULL) {
+        delete mPlugin;
+        mPlugin = NULL;
+    }
+    return Status::ok();
+}
+
+} // namespace android
+
diff --git a/drm/libmediadrm/DescramblerImpl.cpp b/drm/libmediadrm/DescramblerImpl.cpp
new file mode 100644
index 0000000..94e09e2
--- /dev/null
+++ b/drm/libmediadrm/DescramblerImpl.cpp
@@ -0,0 +1,107 @@
+
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+//#define LOG_NDEBUG 0
+#define LOG_TAG "DescramblerImpl"
+
+#include <media/cas/DescramblerAPI.h>
+#include <media/DescramblerImpl.h>
+#include <media/SharedLibrary.h>
+#include <utils/Log.h>
+#include <binder/IMemory.h>
+
+namespace android {
+
+static Status getBinderStatus(status_t err) {
+    if (err == OK) {
+        return Status::ok();
+    }
+    if (err == BAD_VALUE) {
+        return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT);
+    }
+    if (err == INVALID_OPERATION) {
+        return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE);
+    }
+    return Status::fromServiceSpecificError(err);
+}
+
+static String8 sessionIdToString(const CasSessionId &sessionId) {
+    String8 result;
+    for (size_t i = 0; i < sessionId.size(); i++) {
+        result.appendFormat("%02x ", sessionId[i]);
+    }
+    if (result.isEmpty()) {
+        result.append("(null)");
+    }
+    return result;
+}
+
+DescramblerImpl::DescramblerImpl(
+        const sp<SharedLibrary>& library, DescramblerPlugin *plugin) :
+        mLibrary(library), mPlugin(plugin) {
+    ALOGV("CTOR: mPlugin=%p", mPlugin);
+}
+
+DescramblerImpl::~DescramblerImpl() {
+    ALOGV("DTOR: mPlugin=%p", mPlugin);
+    release();
+}
+
+Status DescramblerImpl::setMediaCasSession(const CasSessionId& sessionId) {
+    ALOGV("setMediaCasSession: sessionId=%s",
+            sessionIdToString(sessionId).string());
+
+    return getBinderStatus(mPlugin->setMediaCasSession(sessionId));
+}
+
+Status DescramblerImpl::requiresSecureDecoderComponent(
+        const String16& mime, bool *result) {
+    *result = mPlugin->requiresSecureDecoderComponent(String8(mime));
+
+    return getBinderStatus(OK);
+}
+
+Status DescramblerImpl::descramble(
+        const DescrambleInfo& info, int32_t *result) {
+    ALOGV("descramble");
+
+    *result = mPlugin->descramble(
+            info.dstType != DescrambleInfo::kDestinationTypeVmPointer,
+            info.scramblingControl,
+            info.numSubSamples,
+            info.subSamples,
+            info.srcMem->pointer(),
+            info.srcOffset,
+            info.dstType == DescrambleInfo::kDestinationTypeVmPointer ?
+                    info.srcMem->pointer() : info.dstPtr,
+            info.dstOffset,
+            NULL);
+
+    return getBinderStatus(*result >= 0 ? OK : *result);
+}
+
+Status DescramblerImpl::release() {
+    ALOGV("release: mPlugin=%p", mPlugin);
+
+    if (mPlugin != NULL) {
+        delete mPlugin;
+        mPlugin = NULL;
+    }
+    return Status::ok();
+}
+
+} // namespace android
+
diff --git a/drm/libmediadrm/MediaCasDefs.cpp b/drm/libmediadrm/MediaCasDefs.cpp
new file mode 100644
index 0000000..9c2ba38
--- /dev/null
+++ b/drm/libmediadrm/MediaCasDefs.cpp
@@ -0,0 +1,184 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+//#define LOG_NDEBUG 0
+#define LOG_TAG "MediaCas"
+
+#include <media/MediaCasDefs.h>
+#include <utils/Log.h>
+#include <binder/IMemory.h>
+
+namespace android {
+namespace media {
+
+///////////////////////////////////////////////////////////////////////////////
+namespace MediaCas {
+
+status_t ParcelableCasData::readFromParcel(const Parcel* parcel) {
+    return parcel->readByteVector(this);
+}
+
+status_t ParcelableCasData::writeToParcel(Parcel* parcel) const  {
+    return parcel->writeByteVector(*this);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+status_t ParcelableCasPluginDescriptor::readFromParcel(const Parcel* /*parcel*/) {
+    ALOGE("CAPluginDescriptor::readFromParcel() shouldn't be called");
+    return INVALID_OPERATION;
+}
+
+status_t ParcelableCasPluginDescriptor::writeToParcel(Parcel* parcel) const {
+    status_t err = parcel->writeInt32(mCASystemId);
+    if (err != NO_ERROR) {
+        return err;
+    }
+    return parcel->writeString16(mName);
+}
+
+} // namespace MediaCas
+///////////////////////////////////////////////////////////////////////////////
+
+namespace MediaDescrambler {
+
+DescrambleInfo::DescrambleInfo() {}
+
+DescrambleInfo::~DescrambleInfo() {}
+
+status_t DescrambleInfo::readFromParcel(const Parcel* parcel) {
+    status_t err = parcel->readInt32((int32_t*)&dstType);
+    if (err != OK) {
+        return err;
+    }
+    if (dstType != kDestinationTypeNativeHandle
+            && dstType != kDestinationTypeVmPointer) {
+        return BAD_VALUE;
+    }
+
+    err = parcel->readInt32((int32_t*)&scramblingControl);
+    if (err != OK) {
+        return err;
+    }
+
+    err = parcel->readUint32((uint32_t*)&numSubSamples);
+    if (err != OK) {
+        return err;
+    }
+    if (numSubSamples > 0xffff) {
+        return BAD_VALUE;
+    }
+
+    subSamples = new DescramblerPlugin::SubSample[numSubSamples];
+    if (subSamples == NULL) {
+        return NO_MEMORY;
+    }
+
+    for (size_t i = 0; i < numSubSamples; i++) {
+        err = parcel->readUint32(&subSamples[i].mNumBytesOfClearData);
+        if (err != OK) {
+            return err;
+        }
+        err = parcel->readUint32(&subSamples[i].mNumBytesOfEncryptedData);
+        if (err != OK) {
+            return err;
+        }
+    }
+
+    srcMem = interface_cast<IMemory>(parcel->readStrongBinder());
+    if (srcMem == NULL) {
+        return BAD_VALUE;
+    }
+
+    err = parcel->readInt32(&srcOffset);
+    if (err != OK) {
+        return err;
+    }
+
+    native_handle_t *nativeHandle = NULL;
+    if (dstType == kDestinationTypeNativeHandle) {
+        nativeHandle = parcel->readNativeHandle();
+        dstPtr = static_cast<void *>(nativeHandle);
+    } else {
+        dstPtr = NULL;
+    }
+
+    err = parcel->readInt32(&dstOffset);
+    if (err != OK) {
+        return err;
+    }
+
+    return OK;
+}
+
+status_t DescrambleInfo::writeToParcel(Parcel* parcel) const {
+    if (dstType != kDestinationTypeNativeHandle
+            && dstType != kDestinationTypeVmPointer) {
+        return BAD_VALUE;
+    }
+
+    status_t err = parcel->writeInt32((int32_t)dstType);
+    if (err != OK) {
+        return err;
+    }
+
+    err = parcel->writeInt32(scramblingControl);
+    if (err != OK) {
+        return err;
+    }
+
+    err = parcel->writeUint32(numSubSamples);
+    if (err != OK) {
+        return err;
+    }
+
+    for (size_t i = 0; i < numSubSamples; i++) {
+        err = parcel->writeUint32(subSamples[i].mNumBytesOfClearData);
+        if (err != OK) {
+            return err;
+        }
+        err = parcel->writeUint32(subSamples[i].mNumBytesOfEncryptedData);
+        if (err != OK) {
+            return err;
+        }
+    }
+
+    err = parcel->writeStrongBinder(IInterface::asBinder(srcMem));
+    if (err != OK) {
+        return err;
+    }
+
+    err = parcel->writeInt32(srcOffset);
+    if (err != OK) {
+        return err;
+    }
+
+    if (dstType == kDestinationTypeNativeHandle) {
+        parcel->writeNativeHandle(static_cast<native_handle_t *>(dstPtr));
+    }
+
+    err = parcel->writeInt32(dstOffset);
+    if (err != OK) {
+        return err;
+    }
+
+    return OK;
+}
+
+} // namespace MediaDescrambler
+
+} // namespace media
+} // namespace android
+
diff --git a/drm/libmediadrm/SharedLibrary.cpp b/drm/libmediadrm/SharedLibrary.cpp
index 74b3a71..bebafa8 100644
--- a/drm/libmediadrm/SharedLibrary.cpp
+++ b/drm/libmediadrm/SharedLibrary.cpp
@@ -43,6 +43,9 @@
         if (!mLibHandle) {
             return NULL;
         }
+        // Clear last error before we load the symbol again,
+        // in case the caller didn't retrieve it.
+        (void)dlerror();
         return dlsym(mLibHandle, symbol);
     }
 
diff --git a/include/media/CasImpl.h b/include/media/CasImpl.h
new file mode 100644
index 0000000..80c901e
--- /dev/null
+++ b/include/media/CasImpl.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef CAS_IMPL_H_
+#define CAS_IMPL_H_
+
+#include <media/stagefright/foundation/ABase.h>
+#include <android/media/BnCas.h>
+
+namespace android {
+namespace media {
+class ICasListener;
+}
+using namespace media;
+using namespace MediaCas;
+using binder::Status;
+class CasPlugin;
+class SharedLibrary;
+
+class CasImpl : public BnCas {
+public:
+    CasImpl(const sp<ICasListener> &listener);
+    virtual ~CasImpl();
+
+    static void OnEvent(
+            void *appData,
+            int32_t event,
+            int32_t arg,
+            uint8_t *data,
+            size_t size);
+
+    void init(const sp<SharedLibrary>& library, CasPlugin *plugin);
+    void onEvent(
+            int32_t event,
+            int32_t arg,
+            uint8_t *data,
+            size_t size);
+
+    // ICas inherits
+
+    virtual Status setPrivateData(
+            const CasData& pvtData) override;
+
+    virtual Status openSession(
+            int32_t program_number, CasSessionId* _aidl_return) override;
+
+    virtual Status openSessionForStream(
+            int32_t program_number,
+            int32_t elementary_PID,
+            CasSessionId* _aidl_return) override;
+
+    virtual Status closeSession(const CasSessionId& sessionId) override;
+
+    virtual Status setSessionPrivateData(
+            const CasSessionId& sessionId,
+            const CasData& pvtData) override;
+
+    virtual Status processEcm(
+            const CasSessionId& sessionId, const ParcelableCasData& ecm) override;
+
+    virtual Status processEmm(const ParcelableCasData& emm) override;
+
+    virtual Status sendEvent(
+            int32_t event, int32_t arg, const ::std::unique_ptr<CasData> &eventData) override;
+
+    virtual Status provision(const String16& provisionString) override;
+
+    virtual Status refreshEntitlements(
+            int32_t refreshType, const ::std::unique_ptr<CasData> &refreshData) override;
+
+    virtual Status release() override;
+
+private:
+    sp<SharedLibrary> mLibrary;
+    CasPlugin *mPlugin;
+    sp<ICasListener> mListener;
+
+    DISALLOW_EVIL_CONSTRUCTORS(CasImpl);
+};
+
+} // namespace android
+
+#endif // CAS_IMPL_H_
diff --git a/include/media/DescramblerImpl.h b/include/media/DescramblerImpl.h
new file mode 100644
index 0000000..c1c79b3
--- /dev/null
+++ b/include/media/DescramblerImpl.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef DESCRAMBLER_IMPL_H_
+#define DESCRAMBLER_IMPL_H_
+
+#include <media/stagefright/foundation/ABase.h>
+#include <android/media/BnDescrambler.h>
+
+namespace android {
+using namespace media;
+using namespace MediaDescrambler;
+using binder::Status;
+class DescramblerPlugin;
+class SharedLibrary;
+
+class DescramblerImpl : public BnDescrambler {
+public:
+    DescramblerImpl(const sp<SharedLibrary>& library, DescramblerPlugin *plugin);
+    virtual ~DescramblerImpl();
+
+    virtual Status setMediaCasSession(
+            const CasSessionId& sessionId) override;
+
+    virtual Status requiresSecureDecoderComponent(
+            const String16& mime, bool *result) override;
+
+    virtual Status descramble(
+            const DescrambleInfo& descrambleInfo, int32_t *result) override;
+
+    virtual Status release() override;
+
+private:
+    sp<SharedLibrary> mLibrary;
+    DescramblerPlugin *mPlugin;
+
+    DISALLOW_EVIL_CONSTRUCTORS(DescramblerImpl);
+};
+
+} // namespace android
+
+#endif // DESCRAMBLER_IMPL_H_
diff --git a/include/media/IMediaExtractor.h b/include/media/IMediaExtractor.h
index 06db359..cf1b9fb 100644
--- a/include/media/IMediaExtractor.h
+++ b/include/media/IMediaExtractor.h
@@ -24,6 +24,10 @@
 namespace android {
 
 class MetaData;
+namespace media {
+class ICas;
+};
+using namespace media;
 
 class IMediaExtractor : public IInterface {
 public:
@@ -57,6 +61,9 @@
 
     // for DRM
     virtual char* getDrmTrackInfo(size_t trackID, int *len)  = 0;
+
+    virtual status_t setMediaCas(const sp<ICas> &cas) = 0;
+
     virtual void setUID(uid_t uid)  = 0;
 
     virtual const char * name() = 0;
diff --git a/include/media/MediaCasDefs.h b/include/media/MediaCasDefs.h
new file mode 100644
index 0000000..8c5a967
--- /dev/null
+++ b/include/media/MediaCasDefs.h
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MEDIA_CAS_DEFS_H_
+#define MEDIA_CAS_DEFS_H_
+
+#include <binder/Parcel.h>
+#include <media/cas/CasAPI.h>
+#include <media/cas/DescramblerAPI.h>
+#include <media/stagefright/foundation/ABase.h>
+
+namespace android {
+class IMemory;
+namespace media {
+
+namespace MediaCas {
+class ParcelableCasData : public CasData,
+                          public Parcelable {
+public:
+    ParcelableCasData() {}
+    ParcelableCasData(const uint8_t *data, size_t size) :
+        CasData(data, data + size) {}
+    virtual ~ParcelableCasData() {}
+    status_t readFromParcel(const Parcel* parcel) override;
+    status_t writeToParcel(Parcel* parcel) const override;
+
+private:
+    DISALLOW_EVIL_CONSTRUCTORS(ParcelableCasData);
+};
+
+class ParcelableCasPluginDescriptor : public Parcelable {
+public:
+    ParcelableCasPluginDescriptor(int32_t CA_system_id, const char *name)
+        : mCASystemId(CA_system_id), mName(name) {}
+
+    ParcelableCasPluginDescriptor() : mCASystemId(0) {}
+
+    ParcelableCasPluginDescriptor(ParcelableCasPluginDescriptor&& desc) = default;
+
+    virtual ~ParcelableCasPluginDescriptor() {}
+
+    status_t readFromParcel(const Parcel* parcel) override;
+    status_t writeToParcel(Parcel* parcel) const override;
+
+private:
+    int32_t mCASystemId;
+    String16 mName;
+    DISALLOW_EVIL_CONSTRUCTORS(ParcelableCasPluginDescriptor);
+};
+}
+
+namespace MediaDescrambler {
+class DescrambleInfo : public Parcelable {
+public:
+    enum DestinationType {
+        kDestinationTypeVmPointer,    // non-secure
+        kDestinationTypeNativeHandle  // secure
+    };
+
+    DestinationType dstType;
+    DescramblerPlugin::ScramblingControl scramblingControl;
+    size_t numSubSamples;
+    DescramblerPlugin::SubSample *subSamples;
+    sp<IMemory> srcMem;
+    int32_t srcOffset;
+    void *dstPtr;
+    int32_t dstOffset;
+
+    DescrambleInfo();
+    virtual ~DescrambleInfo();
+    status_t readFromParcel(const Parcel* parcel) override;
+    status_t writeToParcel(Parcel* parcel) const override;
+
+private:
+
+    DISALLOW_EVIL_CONSTRUCTORS(DescrambleInfo);
+};
+}
+
+} // namespace media
+} // namespace android
+
+
+#endif // MEDIA_CAS_DEFS_H_
diff --git a/include/media/MediaDefs.h b/include/media/MediaDefs.h
index 0682413..7f17013 100644
--- a/include/media/MediaDefs.h
+++ b/include/media/MediaDefs.h
@@ -31,6 +31,7 @@
 extern const char *MEDIA_MIMETYPE_VIDEO_MPEG2;
 extern const char *MEDIA_MIMETYPE_VIDEO_RAW;
 extern const char *MEDIA_MIMETYPE_VIDEO_DOLBY_VISION;
+extern const char *MEDIA_MIMETYPE_VIDEO_SCRAMBLED;
 
 extern const char *MEDIA_MIMETYPE_AUDIO_AMR_NB;
 extern const char *MEDIA_MIMETYPE_AUDIO_AMR_WB;
@@ -50,6 +51,7 @@
 extern const char *MEDIA_MIMETYPE_AUDIO_MSGSM;
 extern const char *MEDIA_MIMETYPE_AUDIO_AC3;
 extern const char *MEDIA_MIMETYPE_AUDIO_EAC3;
+extern const char *MEDIA_MIMETYPE_AUDIO_SCRAMBLED;
 
 extern const char *MEDIA_MIMETYPE_CONTAINER_MPEG4;
 extern const char *MEDIA_MIMETYPE_CONTAINER_WAV;
diff --git a/include/media/stagefright/MediaCodec.h b/include/media/stagefright/MediaCodec.h
index 20b26e2..fd3ff26 100644
--- a/include/media/stagefright/MediaCodec.h
+++ b/include/media/stagefright/MediaCodec.h
@@ -47,6 +47,10 @@
 struct PersistentSurface;
 class SoftwareRenderer;
 class Surface;
+namespace media {
+class IDescrambler;
+};
+using namespace media;
 
 struct MediaCodec : public AHandler {
     enum ConfigureFlags {
@@ -91,6 +95,13 @@
             const sp<ICrypto> &crypto,
             uint32_t flags);
 
+    status_t configure(
+            const sp<AMessage> &format,
+            const sp<Surface> &nativeWindow,
+            const sp<ICrypto> &crypto,
+            const sp<IDescrambler> &descrambler,
+            uint32_t flags);
+
     status_t releaseCrypto();
 
     status_t setCallback(const sp<AMessage> &callback);
@@ -345,6 +356,8 @@
 
     sp<ICrypto> mCrypto;
 
+    sp<IDescrambler> mDescrambler;
+
     List<sp<ABuffer> > mCSD;
 
     sp<AMessage> mActivityNotify;
diff --git a/include/media/stagefright/MediaExtractor.h b/include/media/stagefright/MediaExtractor.h
index 9ce6cc5..073391f 100644
--- a/include/media/stagefright/MediaExtractor.h
+++ b/include/media/stagefright/MediaExtractor.h
@@ -23,7 +23,10 @@
 #include <media/MediaAnalyticsItem.h>
 
 namespace android {
-
+namespace media {
+class ICas;
+};
+using namespace media;
 class DataSource;
 struct MediaSource;
 class MetaData;
@@ -67,6 +70,9 @@
     }
     virtual void setUID(uid_t /*uid*/) {
     }
+    virtual status_t setMediaCas(const sp<ICas> &cas) override {
+        return INVALID_OPERATION;
+    }
 
     virtual const char * name() { return "<unspecified>"; }
 
diff --git a/include/media/stagefright/NuMediaExtractor.h b/include/media/stagefright/NuMediaExtractor.h
index ad0d37b..3e3cc17 100644
--- a/include/media/stagefright/NuMediaExtractor.h
+++ b/include/media/stagefright/NuMediaExtractor.h
@@ -28,6 +28,10 @@
 #include <utils/Vector.h>
 
 namespace android {
+namespace media {
+class ICas;
+}
+using namespace media;
 
 struct ABuffer;
 struct AMessage;
@@ -60,6 +64,8 @@
 
     status_t setDataSource(const sp<DataSource> &datasource);
 
+    status_t setMediaCas(const sp<ICas> &cas);
+
     size_t countTracks() const;
     status_t getTrackFormat(size_t index, sp<AMessage> *format, uint32_t flags = 0) const;
 
@@ -109,6 +115,7 @@
     sp<DataSource> mDataSource;
 
     sp<IMediaExtractor> mImpl;
+    sp<ICas> mCas;
 
     Vector<TrackInfo> mSelectedTracks;
     int64_t mTotalBitrate;  // in bits/sec
diff --git a/media/libaudiohal/DeviceHalHidl.cpp b/media/libaudiohal/DeviceHalHidl.cpp
index dcedfd3..71fbd98 100644
--- a/media/libaudiohal/DeviceHalHidl.cpp
+++ b/media/libaudiohal/DeviceHalHidl.cpp
@@ -21,6 +21,7 @@
 
 #include <android/hardware/audio/2.0/IPrimaryDevice.h>
 #include <cutils/native_handle.h>
+#include <hwbinder/IPCThreadState.h>
 #include <utils/Log.h>
 
 #include "DeviceHalHidl.h"
@@ -101,6 +102,10 @@
 }
 
 DeviceHalHidl::~DeviceHalHidl() {
+    if (mDevice != 0) {
+        mDevice.clear();
+        hardware::IPCThreadState::self()->flushCommands();
+    }
 }
 
 status_t DeviceHalHidl::getSupportedDevices(uint32_t*) {
diff --git a/media/libaudiohal/EffectHalHidl.cpp b/media/libaudiohal/EffectHalHidl.cpp
index d17f8bd..db115ef 100644
--- a/media/libaudiohal/EffectHalHidl.cpp
+++ b/media/libaudiohal/EffectHalHidl.cpp
@@ -17,6 +17,7 @@
 #define LOG_TAG "EffectHalHidl"
 //#define LOG_NDEBUG 0
 
+#include <hwbinder/IPCThreadState.h>
 #include <media/EffectsFactoryApi.h>
 #include <utils/Log.h>
 
@@ -44,7 +45,11 @@
 }
 
 EffectHalHidl::~EffectHalHidl() {
-    close();
+    if (mEffect != 0) {
+        close();
+        mEffect.clear();
+        hardware::IPCThreadState::self()->flushCommands();
+    }
 }
 
 // static
diff --git a/media/libaudiohal/StreamHalHidl.cpp b/media/libaudiohal/StreamHalHidl.cpp
index b66ba2b..2a7a67f 100644
--- a/media/libaudiohal/StreamHalHidl.cpp
+++ b/media/libaudiohal/StreamHalHidl.cpp
@@ -18,6 +18,7 @@
 //#define LOG_NDEBUG 0
 
 #include <android/hardware/audio/2.0/IStreamOutCallback.h>
+#include <hwbinder/IPCThreadState.h>
 #include <mediautils/SchedulingPolicyService.h>
 #include <utils/Log.h>
 
@@ -263,8 +264,10 @@
             processReturn("clearCallback", mStream->clearCallback());
         }
         processReturn("close", mStream->close());
+        mStream.clear();
     }
     mCallback.clear();
+    hardware::IPCThreadState::self()->flushCommands();
     if (mEfGroup) {
         EventFlag::deleteEventFlag(&mEfGroup);
     }
@@ -538,6 +541,8 @@
 StreamInHalHidl::~StreamInHalHidl() {
     if (mStream != 0) {
         processReturn("close", mStream->close());
+        mStream.clear();
+        hardware::IPCThreadState::self()->flushCommands();
     }
     if (mEfGroup) {
         EventFlag::deleteEventFlag(&mEfGroup);
diff --git a/media/libmedia/Android.mk b/media/libmedia/Android.mk
index 6c6c369..eac532b 100644
--- a/media/libmedia/Android.mk
+++ b/media/libmedia/Android.mk
@@ -60,10 +60,10 @@
         libui liblog libcutils libutils libbinder libsonivox libicuuc libicui18n libexpat \
         libcamera_client libstagefright_foundation \
         libgui libdl libaudioutils libaudioclient \
-        libmedia_helper \
+        libmedia_helper libmediadrm \
         libhidlbase \
 
-LOCAL_EXPORT_SHARED_LIBRARY_HEADERS := libbinder libsonivox
+LOCAL_EXPORT_SHARED_LIBRARY_HEADERS := libbinder libsonivox libmediadrm
 
 # for memory heap analysis
 LOCAL_STATIC_LIBRARIES := libc_malloc_debug_backtrace libc_logging
diff --git a/media/libmedia/IMediaExtractor.cpp b/media/libmedia/IMediaExtractor.cpp
index bfc43a6..f08fabb 100644
--- a/media/libmedia/IMediaExtractor.cpp
+++ b/media/libmedia/IMediaExtractor.cpp
@@ -21,6 +21,7 @@
 #include <stdint.h>
 #include <sys/types.h>
 
+#include <android/media/ICas.h>
 #include <binder/IPCThreadState.h>
 #include <binder/Parcel.h>
 #include <media/IMediaExtractor.h>
@@ -35,6 +36,7 @@
     GETMETADATA,
     FLAGS,
     GETDRMTRACKINFO,
+    SETMEDIACAS,
     SETUID,
     NAME,
     GETMETRICS
@@ -114,6 +116,21 @@
         ALOGV("getDrmTrackInfo NOT IMPLEMENTED");
         return NULL;
     }
+
+    virtual status_t setMediaCas(const sp<ICas> & cas) {
+        ALOGV("setMediaCas");
+
+        Parcel data, reply;
+        data.writeInterfaceToken(BpMediaExtractor::getInterfaceDescriptor());
+        data.writeStrongBinder(IInterface::asBinder(cas));
+
+        status_t err = remote()->transact(SETMEDIACAS, data, &reply);
+        if (err != NO_ERROR) {
+            return err;
+        }
+        return reply.readInt32();
+    }
+
     virtual void setUID(uid_t uid __unused) {
         ALOGV("setUID NOT IMPLEMENTED");
     }
@@ -185,6 +202,21 @@
             status_t ret = getMetrics(reply);
             return ret;
         }
+        case SETMEDIACAS: {
+            ALOGV("setMediaCas");
+            CHECK_INTERFACE(IMediaExtractor, data, reply);
+
+            sp<IBinder> casBinder;
+            status_t err = data.readNullableStrongBinder(&casBinder);
+            if (err != NO_ERROR) {
+                ALOGE("Error reading cas from parcel");
+                return err;
+            }
+            sp<ICas> cas = interface_cast<ICas>(casBinder);
+
+            reply->writeInt32(setMediaCas(cas));
+            return OK;
+        }
         default:
             return BBinder::onTransact(code, data, reply, flags);
     }
diff --git a/media/libmedia/MediaDefs.cpp b/media/libmedia/MediaDefs.cpp
index 2ae71f7..544a6ae 100644
--- a/media/libmedia/MediaDefs.cpp
+++ b/media/libmedia/MediaDefs.cpp
@@ -29,6 +29,7 @@
 const char *MEDIA_MIMETYPE_VIDEO_MPEG2 = "video/mpeg2";
 const char *MEDIA_MIMETYPE_VIDEO_RAW = "video/raw";
 const char *MEDIA_MIMETYPE_VIDEO_DOLBY_VISION = "video/dolby-vision";
+const char *MEDIA_MIMETYPE_VIDEO_SCRAMBLED = "video/scrambled";
 
 const char *MEDIA_MIMETYPE_AUDIO_AMR_NB = "audio/3gpp";
 const char *MEDIA_MIMETYPE_AUDIO_AMR_WB = "audio/amr-wb";
@@ -48,6 +49,7 @@
 const char *MEDIA_MIMETYPE_AUDIO_MSGSM = "audio/gsm";
 const char *MEDIA_MIMETYPE_AUDIO_AC3 = "audio/ac3";
 const char *MEDIA_MIMETYPE_AUDIO_EAC3 = "audio/eac3";
+const char *MEDIA_MIMETYPE_AUDIO_SCRAMBLED = "audio/scrambled";
 
 const char *MEDIA_MIMETYPE_CONTAINER_MPEG4 = "video/mp4";
 const char *MEDIA_MIMETYPE_CONTAINER_WAV = "audio/x-wav";
diff --git a/media/libmediaplayerservice/Android.mk b/media/libmediaplayerservice/Android.mk
index e6d9b71..035cd8a 100644
--- a/media/libmediaplayerservice/Android.mk
+++ b/media/libmediaplayerservice/Android.mk
@@ -36,6 +36,7 @@
     libstagefright_omx          \
     libstagefright_wfd          \
     libutils                    \
+    libnativewindow             \
     libhidlbase                 \
     android.hardware.media.omx@1.0 \
 
diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk
index d044754..140ceb1 100644
--- a/media/libstagefright/Android.mk
+++ b/media/libstagefright/Android.mk
@@ -93,6 +93,8 @@
         libui \
         libutils \
         libvorbisidec \
+        libmediadrm \
+        libnativewindow \
 
 LOCAL_STATIC_LIBRARIES := \
         libstagefright_color_conversion \
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index 03010ab..6674e2c 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -23,6 +23,7 @@
 #include "include/SharedMemoryBuffer.h"
 #include "include/SoftwareRenderer.h"
 
+#include <android/media/IDescrambler.h>
 #include <binder/IMemory.h>
 #include <binder/IPCThreadState.h>
 #include <binder/IServiceManager.h>
@@ -680,8 +681,17 @@
 
 status_t MediaCodec::configure(
         const sp<AMessage> &format,
+        const sp<Surface> &nativeWindow,
+        const sp<ICrypto> &crypto,
+        uint32_t flags) {
+    return configure(format, nativeWindow, crypto, NULL, flags);
+}
+
+status_t MediaCodec::configure(
+        const sp<AMessage> &format,
         const sp<Surface> &surface,
         const sp<ICrypto> &crypto,
+        const sp<IDescrambler> &descrambler,
         uint32_t flags) {
     sp<AMessage> msg = new AMessage(kWhatConfigure, this);
 
@@ -710,8 +720,12 @@
     msg->setInt32("flags", flags);
     msg->setObject("surface", surface);
 
-    if (crypto != NULL) {
-        msg->setPointer("crypto", crypto.get());
+    if (crypto != NULL || descrambler != NULL) {
+        if (crypto != NULL) {
+            msg->setPointer("crypto", crypto.get());
+        } else {
+            msg->setPointer("descrambler", descrambler.get());
+        }
         if (mAnalyticsItem != NULL) {
             // XXX: save indication that it's crypto in some way...
             mAnalyticsItem->setInt32("crypto", 1);
@@ -1992,6 +2006,13 @@
             ALOGV("kWhatConfigure: New mCrypto: %p (%d)",
                     mCrypto.get(), (mCrypto != NULL ? mCrypto->getStrongCount() : 0));
 
+            void *descrambler;
+            if (!msg->findPointer("descrambler", &descrambler)) {
+                descrambler = NULL;
+            }
+
+            mDescrambler = static_cast<IDescrambler *>(descrambler);
+
             uint32_t flags;
             CHECK(msg->findInt32("flags", (int32_t *)&flags));
 
@@ -2592,6 +2613,7 @@
                     mCrypto.get(), (mCrypto != NULL ? mCrypto->getStrongCount() : 0));
         }
         mCrypto.clear();
+        mDescrambler.clear();
         handleSetSurface(NULL);
 
         mInputFormat.clear();
diff --git a/media/libstagefright/NuMediaExtractor.cpp b/media/libstagefright/NuMediaExtractor.cpp
index 1c1acb0..ea3ed28 100644
--- a/media/libstagefright/NuMediaExtractor.cpp
+++ b/media/libstagefright/NuMediaExtractor.cpp
@@ -35,6 +35,7 @@
 #include <media/stagefright/MediaSource.h>
 #include <media/stagefright/MetaData.h>
 #include <media/stagefright/Utils.h>
+#include <android/media/ICas.h>
 
 namespace android {
 
@@ -82,6 +83,10 @@
         return ERROR_UNSUPPORTED;
     }
 
+    if (mCas != NULL) {
+        mImpl->setMediaCas(mCas);
+    }
+
     status_t err = updateDurationAndBitrate();
     if (err == OK) {
         mDataSource = dataSource;
@@ -114,6 +119,10 @@
         return ERROR_UNSUPPORTED;
     }
 
+    if (mCas != NULL) {
+        mImpl->setMediaCas(mCas);
+    }
+
     err = updateDurationAndBitrate();
     if (err == OK) {
         mDataSource = fileSource;
@@ -140,6 +149,10 @@
         return ERROR_UNSUPPORTED;
     }
 
+    if (mCas != NULL) {
+        mImpl->setMediaCas(mCas);
+    }
+
     err = updateDurationAndBitrate();
     if (err == OK) {
         mDataSource = source;
@@ -148,6 +161,27 @@
     return err;
 }
 
+status_t NuMediaExtractor::setMediaCas(const sp<ICas> &cas) {
+    ALOGV("setMediaCas: cas=%p", cas.get());
+
+    Mutex::Autolock autoLock(mLock);
+
+    if (cas == NULL) {
+        return BAD_VALUE;
+    }
+
+    if (mImpl != NULL) {
+        mImpl->setMediaCas(cas);
+        status_t err = updateDurationAndBitrate();
+        if (err != OK) {
+            return err;
+        }
+    }
+
+    mCas = cas;
+    return OK;
+}
+
 status_t NuMediaExtractor::updateDurationAndBitrate() {
     if (mImpl->countTracks() > kMaxTrackCount) {
         return ERROR_UNSUPPORTED;
diff --git a/media/libstagefright/matroska/MatroskaExtractor.cpp b/media/libstagefright/matroska/MatroskaExtractor.cpp
index a974671..81179d1 100644
--- a/media/libstagefright/matroska/MatroskaExtractor.cpp
+++ b/media/libstagefright/matroska/MatroskaExtractor.cpp
@@ -1288,8 +1288,51 @@
                     continue;
                 }
 
-                meta->setInt32(kKeyWidth, vtrack->GetWidth());
-                meta->setInt32(kKeyHeight, vtrack->GetHeight());
+                const long long width = vtrack->GetWidth();
+                const long long height = vtrack->GetHeight();
+                if (width <= 0 || width > INT32_MAX) {
+                    ALOGW("track width exceeds int32_t, %lld", width);
+                    continue;
+                }
+                if (height <= 0 || height > INT32_MAX) {
+                    ALOGW("track height exceeds int32_t, %lld", height);
+                    continue;
+                }
+                meta->setInt32(kKeyWidth, (int32_t)width);
+                meta->setInt32(kKeyHeight, (int32_t)height);
+
+                // setting display width/height is optional
+                const long long displayUnit = vtrack->GetDisplayUnit();
+                const long long displayWidth = vtrack->GetDisplayWidth();
+                const long long displayHeight = vtrack->GetDisplayHeight();
+                if (displayWidth > 0 && displayWidth <= INT32_MAX
+                        && displayHeight > 0 && displayHeight <= INT32_MAX) {
+                    switch (displayUnit) {
+                    case 0: // pixels
+                        meta->setInt32(kKeyDisplayWidth, (int32_t)displayWidth);
+                        meta->setInt32(kKeyDisplayHeight, (int32_t)displayHeight);
+                        break;
+                    case 1: // centimeters
+                    case 2: // inches
+                    case 3: // aspect ratio
+                    {
+                        // Physical layout size is treated the same as aspect ratio.
+                        // Note: displayWidth and displayHeight are never zero as they are
+                        // checked in the if above.
+                        const long long computedWidth =
+                                std::max(width, height * displayWidth / displayHeight);
+                        const long long computedHeight =
+                                std::max(height, width * displayHeight / displayWidth);
+                        if (computedWidth <= INT32_MAX && computedHeight <= INT32_MAX) {
+                            meta->setInt32(kKeyDisplayWidth, (int32_t)computedWidth);
+                            meta->setInt32(kKeyDisplayHeight, (int32_t)computedHeight);
+                        }
+                        break;
+                    }
+                    default: // unknown display units, perhaps future version of spec.
+                        break;
+                    }
+                }
 
                 getColorInformation(vtrack, meta);
 
diff --git a/media/libstagefright/omx/hal/1.0/impl/Android.mk b/media/libstagefright/omx/hal/1.0/impl/Android.mk
index 49e0ca7..09424b5 100644
--- a/media/libstagefright/omx/hal/1.0/impl/Android.mk
+++ b/media/libstagefright/omx/hal/1.0/impl/Android.mk
@@ -2,7 +2,6 @@
 
 include $(CLEAR_VARS)
 LOCAL_MODULE := android.hardware.media.omx@1.0-impl
-LOCAL_MODULE_RELATIVE_PATH := hw
 LOCAL_SRC_FILES := \
     WGraphicBufferSource.cpp \
     WOmx.cpp \
@@ -12,7 +11,6 @@
     WOmxObserver.cpp \
     WOmxProducerListener.cpp \
     Omx.cpp \
-    OmxNode.cpp \
 
 LOCAL_SHARED_LIBRARIES := \
     libmedia \
@@ -28,6 +26,7 @@
     libcutils \
     libbinder \
     liblog \
+    libbase \
     android.hardware.media.omx@1.0 \
     android.hardware.graphics.common@1.0 \
     android.hardware.media@1.0 \
@@ -38,12 +37,10 @@
     -Werror
 
 LOCAL_C_INCLUDES += \
-        $(TOP) \
-        $(TOP)/frameworks/av/include/media \
-        $(TOP)/frameworks/av/media/libstagefright/include \
-        $(TOP)/frameworks/av/media/libstagefright/omx \
-        $(TOP)/frameworks/native/include/media/hardware \
-        $(TOP)/frameworks/native/include/media/openmax \
+        $(TOP)/frameworks/av/include \
+        $(TOP)/frameworks/av/media/libstagefright \
         $(TOP)/frameworks/native/include \
+        $(TOP)/frameworks/native/include/media/openmax \
+        $(TOP)/frameworks/native/include/media/hardware \
 
 include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libstagefright/omx/hal/1.0/impl/Conversion.h b/media/libstagefright/omx/hal/1.0/impl/Conversion.h
index d164faa..d5cf029 100644
--- a/media/libstagefright/omx/hal/1.0/impl/Conversion.h
+++ b/media/libstagefright/omx/hal/1.0/impl/Conversion.h
@@ -17,29 +17,26 @@
 #ifndef ANDROID_HARDWARE_MEDIA_OMX_V1_0__CONVERSION_H
 #define ANDROID_HARDWARE_MEDIA_OMX_V1_0__CONVERSION_H
 
+#include <vector>
+#include <list>
+
+#include <unistd.h>
+
 #include <hidl/MQDescriptor.h>
 #include <hidl/Status.h>
 #include <hidlmemory/mapping.h>
-#include <android/hidl/memory/1.0/IMemory.h>
-
-#include <unistd.h>
-#include <vector>
-#include <list>
 
 #include <binder/Binder.h>
 #include <binder/Status.h>
 #include <ui/FenceTime.h>
-
-#include <OMXFenceParcelable.h>
+#include <media/OMXFenceParcelable.h>
 #include <cutils/native_handle.h>
 #include <gui/IGraphicBufferProducer.h>
 
-#include <IOMX.h>
+#include <media/OMXBuffer.h>
 #include <VideoAPI.h>
-#include <OMXBuffer.h>
-#include <android/IOMXBufferSource.h>
-#include <android/IGraphicBufferSource.h>
 
+#include <android/hidl/memory/1.0/IMemory.h>
 #include <android/hardware/media/omx/1.0/types.h>
 #include <android/hardware/media/omx/1.0/IOmx.h>
 #include <android/hardware/media/omx/1.0/IOmxNode.h>
@@ -49,6 +46,9 @@
 #include <android/hardware/media/omx/1.0/IOmxProducerListener.h>
 #include <android/hardware/media/omx/1.0/IGraphicBufferSource.h>
 
+#include <android/IGraphicBufferSource.h>
+#include <android/IOMXBufferSource.h>
+
 namespace android {
 namespace hardware {
 namespace media {
@@ -177,25 +177,6 @@
  */
 
 /**
- * \brief Convert `binder::Status` to `Return<void>`.
- *
- * \param[in] l The source `binder::Status`.
- * \return The corresponding `Return<void>`.
- */
-// convert: ::android::binder::Status -> Return<void>
-inline Return<void> toHardwareStatus(
-        ::android::binder::Status const& l) {
-    if (l.exceptionCode() == ::android::binder::Status::EX_SERVICE_SPECIFIC) {
-        return ::android::hardware::Status::fromServiceSpecificError(
-                l.serviceSpecificErrorCode(),
-                l.exceptionMessage());
-    }
-    return ::android::hardware::Status::fromExceptionCode(
-            l.exceptionCode(),
-            l.exceptionMessage());
-}
-
-/**
  * \brief Convert `Return<void>` to `binder::Status`.
  *
  * \param[in] t The source `Return<void>`.
diff --git a/media/libstagefright/omx/hal/1.0/impl/GraphicBufferSource.cpp b/media/libstagefright/omx/hal/1.0/impl/GraphicBufferSource.cpp
new file mode 100644
index 0000000..2f457ac
--- /dev/null
+++ b/media/libstagefright/omx/hal/1.0/impl/GraphicBufferSource.cpp
@@ -0,0 +1,1203 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <inttypes.h>
+
+#define LOG_TAG "GraphicBufferSource"
+//#define LOG_NDEBUG 0
+#include <utils/Log.h>
+
+#define STRINGIFY_ENUMS // for asString in HardwareAPI.h/VideoAPI.h
+
+#include "GraphicBufferSource.h"
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/foundation/ColorUtils.h>
+
+#include <media/hardware/MetadataBufferType.h>
+#include <ui/GraphicBuffer.h>
+#include <gui/BufferItem.h>
+#include <HardwareAPI.h>
+#include "omx/OMXUtils.h"
+#include <OMX_Component.h>
+#include <OMX_IndexExt.h>
+#include "OMXBuffer.h"
+
+#include <inttypes.h>
+#include "FrameDropper.h"
+
+namespace android {
+
+static const OMX_U32 kPortIndexInput = 0;
+
+class GraphicBufferSource::OmxBufferSource : public BnOMXBufferSource {
+public:
+    GraphicBufferSource* mSource;
+
+    OmxBufferSource(GraphicBufferSource* source): mSource(source) {
+    }
+
+    Status onOmxExecuting() override {
+        return mSource->onOmxExecuting();
+    }
+
+    Status onOmxIdle() override {
+        return mSource->onOmxIdle();
+    }
+
+    Status onOmxLoaded() override {
+        return mSource->onOmxLoaded();
+    }
+
+    Status onInputBufferAdded(int bufferId) override {
+        return mSource->onInputBufferAdded(bufferId);
+    }
+
+    Status onInputBufferEmptied(
+            int bufferId, const OMXFenceParcelable& fenceParcel) override {
+        return mSource->onInputBufferEmptied(bufferId, fenceParcel);
+    }
+};
+
+GraphicBufferSource::GraphicBufferSource() :
+    mInitCheck(UNKNOWN_ERROR),
+    mExecuting(false),
+    mSuspended(false),
+    mStopTimeUs(-1),
+    mLastDataSpace(HAL_DATASPACE_UNKNOWN),
+    mNumFramesAvailable(0),
+    mNumBufferAcquired(0),
+    mEndOfStream(false),
+    mEndOfStreamSent(false),
+    mLastActionTimeUs(-1ll),
+    mPrevOriginalTimeUs(-1ll),
+    mSkipFramesBeforeNs(-1ll),
+    mRepeatAfterUs(-1ll),
+    mRepeatLastFrameGeneration(0),
+    mRepeatLastFrameTimestamp(-1ll),
+    mRepeatLastFrameCount(0),
+    mLatestBufferId(-1),
+    mLatestBufferFrameNum(0),
+    mLatestBufferFence(Fence::NO_FENCE),
+    mRepeatBufferDeferred(false),
+    mTimePerCaptureUs(-1ll),
+    mTimePerFrameUs(-1ll),
+    mPrevCaptureUs(-1ll),
+    mPrevFrameUs(-1ll),
+    mInputBufferTimeOffsetUs(0ll),
+    mOmxBufferSource(new OmxBufferSource(this)) {
+    ALOGV("GraphicBufferSource");
+
+    String8 name("GraphicBufferSource");
+
+    BufferQueue::createBufferQueue(&mProducer, &mConsumer);
+    mConsumer->setConsumerName(name);
+
+    // Note that we can't create an sp<...>(this) in a ctor that will not keep a
+    // reference once the ctor ends, as that would cause the refcount of 'this'
+    // dropping to 0 at the end of the ctor.  Since all we need is a wp<...>
+    // that's what we create.
+    wp<BufferQueue::ConsumerListener> listener =
+            static_cast<BufferQueue::ConsumerListener*>(this);
+    sp<IConsumerListener> proxy =
+            new BufferQueue::ProxyConsumerListener(listener);
+
+    mInitCheck = mConsumer->consumerConnect(proxy, false);
+    if (mInitCheck != NO_ERROR) {
+        ALOGE("Error connecting to BufferQueue: %s (%d)",
+                strerror(-mInitCheck), mInitCheck);
+        return;
+    }
+
+    memset(&mColorAspects, 0, sizeof(mColorAspects));
+
+    CHECK(mInitCheck == NO_ERROR);
+}
+
+GraphicBufferSource::~GraphicBufferSource() {
+    ALOGV("~GraphicBufferSource");
+    if (mLatestBufferId >= 0) {
+        releaseBuffer(mLatestBufferId, mLatestBufferFrameNum, mLatestBufferFence);
+    }
+    if (mNumBufferAcquired != 0) {
+        ALOGW("potential buffer leak (acquired %d)", mNumBufferAcquired);
+    }
+    if (mConsumer != NULL) {
+        status_t err = mConsumer->consumerDisconnect();
+        if (err != NO_ERROR) {
+            ALOGW("consumerDisconnect failed: %d", err);
+        }
+    }
+}
+
+Status GraphicBufferSource::onOmxExecuting() {
+    Mutex::Autolock autoLock(mMutex);
+    ALOGV("--> executing; avail=%zu, codec vec size=%zd",
+            mNumFramesAvailable, mCodecBuffers.size());
+    CHECK(!mExecuting);
+    mExecuting = true;
+    mLastDataSpace = HAL_DATASPACE_UNKNOWN;
+    ALOGV("clearing last dataSpace");
+
+    // Start by loading up as many buffers as possible.  We want to do this,
+    // rather than just submit the first buffer, to avoid a degenerate case:
+    // if all BQ buffers arrive before we start executing, and we only submit
+    // one here, the other BQ buffers will just sit until we get notified
+    // that the codec buffer has been released.  We'd then acquire and
+    // submit a single additional buffer, repeatedly, never using more than
+    // one codec buffer simultaneously.  (We could instead try to submit
+    // all BQ buffers whenever any codec buffer is freed, but if we get the
+    // initial conditions right that will never be useful.)
+    while (mNumFramesAvailable) {
+        if (!fillCodecBuffer_l()) {
+            ALOGV("stop load with frames available (codecAvail=%d)",
+                    isCodecBufferAvailable_l());
+            break;
+        }
+    }
+
+    ALOGV("done loading initial frames, avail=%zu", mNumFramesAvailable);
+
+    // If EOS has already been signaled, and there are no more frames to
+    // submit, try to send EOS now as well.
+    if (mStopTimeUs == -1 && mEndOfStream && mNumFramesAvailable == 0) {
+        submitEndOfInputStream_l();
+    }
+
+    if (mRepeatAfterUs > 0ll && mLooper == NULL) {
+        mReflector = new AHandlerReflector<GraphicBufferSource>(this);
+
+        mLooper = new ALooper;
+        mLooper->registerHandler(mReflector);
+        mLooper->start();
+
+        if (mLatestBufferId >= 0) {
+            sp<AMessage> msg =
+                new AMessage(kWhatRepeatLastFrame, mReflector);
+
+            msg->setInt32("generation", ++mRepeatLastFrameGeneration);
+            msg->post(mRepeatAfterUs);
+        }
+    }
+
+    return Status::ok();
+}
+
+Status GraphicBufferSource::onOmxIdle() {
+    ALOGV("omxIdle");
+
+    Mutex::Autolock autoLock(mMutex);
+
+    if (mExecuting) {
+        // We are only interested in the transition from executing->idle,
+        // not loaded->idle.
+        mExecuting = false;
+    }
+    return Status::ok();
+}
+
+Status GraphicBufferSource::onOmxLoaded(){
+    Mutex::Autolock autoLock(mMutex);
+    if (!mExecuting) {
+        // This can happen if something failed very early.
+        ALOGW("Dropped back down to Loaded without Executing");
+    }
+
+    if (mLooper != NULL) {
+        mLooper->unregisterHandler(mReflector->id());
+        mReflector.clear();
+
+        mLooper->stop();
+        mLooper.clear();
+    }
+
+    ALOGV("--> loaded; avail=%zu eos=%d eosSent=%d acquired=%d",
+            mNumFramesAvailable, mEndOfStream, mEndOfStreamSent, mNumBufferAcquired);
+
+    // Codec is no longer executing.  Releasing all buffers to bq.
+    for (int i = (int)mCodecBuffers.size() - 1; i >= 0; --i) {
+        if (mCodecBuffers[i].mGraphicBuffer != NULL) {
+            int id = mCodecBuffers[i].mSlot;
+            if (id != mLatestBufferId) {
+                ALOGV("releasing buffer for codec: slot=%d, useCount=%d, latest=%d",
+                        id, mBufferUseCount[id], mLatestBufferId);
+                sp<Fence> fence = new Fence(-1);
+                releaseBuffer(id, mCodecBuffers[i].mFrameNumber, fence);
+                mBufferUseCount[id] = 0;
+            }
+        }
+    }
+    // Also release the latest buffer
+    if (mLatestBufferId >= 0) {
+        releaseBuffer(mLatestBufferId, mLatestBufferFrameNum, mLatestBufferFence);
+        mBufferUseCount[mLatestBufferId] = 0;
+        mLatestBufferId = -1;
+    }
+
+    mCodecBuffers.clear();
+    mOMXNode.clear();
+    mExecuting = false;
+
+    return Status::ok();
+}
+
+Status GraphicBufferSource::onInputBufferAdded(int32_t bufferID) {
+    Mutex::Autolock autoLock(mMutex);
+
+    if (mExecuting) {
+        // This should never happen -- buffers can only be allocated when
+        // transitioning from "loaded" to "idle".
+        ALOGE("addCodecBuffer: buffer added while executing");
+        return Status::fromServiceSpecificError(INVALID_OPERATION);
+    }
+
+    ALOGV("addCodecBuffer: bufferID=%u", bufferID);
+
+    CodecBuffer codecBuffer;
+    codecBuffer.mBufferID = bufferID;
+    mCodecBuffers.add(codecBuffer);
+    return Status::ok();
+}
+
+Status GraphicBufferSource::onInputBufferEmptied(
+        int32_t bufferID, const OMXFenceParcelable &fenceParcel) {
+    int fenceFd = fenceParcel.get();
+
+    Mutex::Autolock autoLock(mMutex);
+    if (!mExecuting) {
+        if (fenceFd >= 0) {
+            ::close(fenceFd);
+        }
+        return Status::fromServiceSpecificError(INVALID_OPERATION);
+    }
+
+    int cbi = findMatchingCodecBuffer_l(bufferID);
+    if (cbi < 0) {
+        // This should never happen.
+        ALOGE("codecBufferEmptied: buffer not recognized (bufferID=%u)", bufferID);
+        if (fenceFd >= 0) {
+            ::close(fenceFd);
+        }
+        return Status::fromServiceSpecificError(BAD_VALUE);
+    }
+
+    ALOGV("codecBufferEmptied: bufferID=%u, cbi=%d", bufferID, cbi);
+    CodecBuffer& codecBuffer(mCodecBuffers.editItemAt(cbi));
+
+    // header->nFilledLen may not be the original value, so we can't compare
+    // that to zero to see of this was the EOS buffer.  Instead we just
+    // see if the GraphicBuffer reference was null, which should only ever
+    // happen for EOS.
+    if (codecBuffer.mGraphicBuffer == NULL) {
+        if (!(mEndOfStream && mEndOfStreamSent)) {
+            // This can happen when broken code sends us the same buffer
+            // twice in a row.
+            ALOGE("ERROR: codecBufferEmptied on non-EOS null buffer "
+                    "(buffer emptied twice?)");
+        }
+        // No GraphicBuffer to deal with, no additional input or output is
+        // expected, so just return.
+        if (fenceFd >= 0) {
+            ::close(fenceFd);
+        }
+        return Status::fromServiceSpecificError(BAD_VALUE);
+    }
+
+    // Find matching entry in our cached copy of the BufferQueue slots.
+    // If we find a match, release that slot.  If we don't, the BufferQueue
+    // has dropped that GraphicBuffer, and there's nothing for us to release.
+    int id = codecBuffer.mSlot;
+    sp<Fence> fence = new Fence(fenceFd);
+    if (mBufferSlot[id] != NULL &&
+        mBufferSlot[id]->handle == codecBuffer.mGraphicBuffer->handle) {
+        mBufferUseCount[id]--;
+
+        if (mBufferUseCount[id] < 0) {
+            ALOGW("mBufferUseCount for bq slot %d < 0 (=%d)", id, mBufferUseCount[id]);
+            mBufferUseCount[id] = 0;
+        }
+        if (id != mLatestBufferId && mBufferUseCount[id] == 0) {
+            releaseBuffer(id, codecBuffer.mFrameNumber, fence);
+        }
+        ALOGV("codecBufferEmptied: slot=%d, cbi=%d, useCount=%d, acquired=%d, handle=%p",
+                id, cbi, mBufferUseCount[id], mNumBufferAcquired, mBufferSlot[id]->handle);
+    } else {
+        ALOGV("codecBufferEmptied: no match for emptied buffer, "
+                "slot=%d, cbi=%d, useCount=%d, acquired=%d",
+                id, cbi, mBufferUseCount[id], mNumBufferAcquired);
+        // we will not reuse codec buffer, so there is no need to wait for fence
+    }
+
+    // Mark the codec buffer as available by clearing the GraphicBuffer ref.
+    codecBuffer.mGraphicBuffer = NULL;
+
+    if (mNumFramesAvailable) {
+        // Fill this codec buffer.
+        CHECK(!mEndOfStreamSent);
+        ALOGV("buffer freed, %zu frames avail (eos=%d)",
+                mNumFramesAvailable, mEndOfStream);
+        fillCodecBuffer_l();
+    } else if (mEndOfStream && mStopTimeUs == -1) {
+        // No frames available, but EOS is pending and no stop time, so use this buffer to
+        // send that.
+        ALOGV("buffer freed, EOS pending");
+        submitEndOfInputStream_l();
+    } else if (mRepeatBufferDeferred) {
+        bool success = repeatLatestBuffer_l();
+        if (success) {
+            ALOGV("deferred repeatLatestBuffer_l SUCCESS");
+        } else {
+            ALOGV("deferred repeatLatestBuffer_l FAILURE");
+        }
+        mRepeatBufferDeferred = false;
+    }
+
+    return Status::ok();
+}
+
+void GraphicBufferSource::onDataSpaceChanged_l(
+        android_dataspace dataSpace, android_pixel_format pixelFormat) {
+    ALOGD("got buffer with new dataSpace #%x", dataSpace);
+    mLastDataSpace = dataSpace;
+
+    if (ColorUtils::convertDataSpaceToV0(dataSpace)) {
+        omx_message msg;
+        msg.type = omx_message::EVENT;
+        msg.fenceFd = -1;
+        msg.u.event_data.event = OMX_EventDataSpaceChanged;
+        msg.u.event_data.data1 = mLastDataSpace;
+        msg.u.event_data.data2 = ColorUtils::packToU32(mColorAspects);
+        msg.u.event_data.data3 = pixelFormat;
+
+        mOMXNode->dispatchMessage(msg);
+    }
+}
+
+bool GraphicBufferSource::fillCodecBuffer_l() {
+    CHECK(mExecuting && mNumFramesAvailable > 0);
+
+    if (mSuspended && mActionQueue.empty()) {
+        return false;
+    }
+
+    int cbi = findAvailableCodecBuffer_l();
+    if (cbi < 0) {
+        // No buffers available, bail.
+        ALOGV("fillCodecBuffer_l: no codec buffers, avail now %zu",
+                mNumFramesAvailable);
+        return false;
+    }
+
+    ALOGV("fillCodecBuffer_l: acquiring buffer, avail=%zu",
+            mNumFramesAvailable);
+    BufferItem item;
+    status_t err = acquireBuffer(&item);
+    if (err != OK) {
+        ALOGE("fillCodecBuffer_l: acquireBuffer returned err=%d", err);
+        return false;
+    }
+
+    int64_t itemTimeUs = item.mTimestamp / 1000;
+
+    mNumFramesAvailable--;
+
+    // Process ActionItem in the Queue if there is any. If a buffer's timestamp
+    // is smaller than the first action's timestamp, no action need to be performed.
+    // If buffer's timestamp is larger or equal than the last action's timestamp,
+    // only the last action needs to be performed as all the acitions before the
+    // the action are overridden by the last action. For the other cases, traverse
+    // the Queue to find the newest action that with timestamp smaller or equal to
+    // the buffer's timestamp. For example, an action queue like
+    // [pause, 1s], [resume 2us], [pause 3us], [resume 4us], [pause 5us].... Upon
+    // receiving a buffer with timestamp 3.5us, only the action [pause, 3us] needs
+    // to be handled and [pause, 1us], [resume 2us] will be discarded.
+    bool dropped = false;
+    bool done = false;
+    if (!mActionQueue.empty()) {
+        // First scan to check if bufferTimestamp is smaller than first action's timestamp.
+        ActionItem nextAction = *(mActionQueue.begin());
+        if (itemTimeUs < nextAction.mActionTimeUs) {
+            ALOGV("No action. buffer timestamp %lld us < action timestamp: %lld us",
+                (long long)itemTimeUs, (long long)nextAction.mActionTimeUs);
+            // All the actions are ahead. No action need to perform now.
+            // Release the buffer if is in suspended state, or process the buffer
+            // if not in suspended state.
+            dropped = mSuspended;
+            done = true;
+        }
+
+        if (!done) {
+            List<ActionItem>::iterator it = mActionQueue.begin();
+            while(it != mActionQueue.end()) {
+                nextAction = *it;
+                mActionQueue.erase(it);
+                if (nextAction.mActionTimeUs > itemTimeUs) {
+                    break;
+                }
+                ++it;
+            }
+
+            CHECK(itemTimeUs >= nextAction.mActionTimeUs);
+            switch (nextAction.mAction) {
+                case ActionItem::PAUSE:
+                {
+                    mSuspended = true;
+                    dropped = true;
+                    ALOGV("RUNNING/PAUSE -> PAUSE at buffer %lld us  PAUSE Time: %lld us",
+                            (long long)itemTimeUs, (long long)nextAction.mActionTimeUs);
+                    break;
+                }
+                case ActionItem::RESUME:
+                {
+                    mSuspended = false;
+                    ALOGV("PAUSE/RUNNING -> RUNNING at buffer %lld us  RESUME Time: %lld us",
+                            (long long)itemTimeUs, (long long)nextAction.mActionTimeUs);
+                    break;
+                }
+                case ActionItem::STOP:
+                {
+                    ALOGV("RUNNING/PAUSE -> STOP at buffer %lld us  STOP Time: %lld us",
+                            (long long)itemTimeUs, (long long)nextAction.mActionTimeUs);
+                    dropped = true;
+                    // Clear the whole ActionQueue as recording is done
+                    mActionQueue.clear();
+                    submitEndOfInputStream_l();
+                    break;
+                }
+                default:
+                    ALOGE("Unknown action type");
+                    return false;
+            }
+        }
+    }
+
+    if (dropped) {
+        releaseBuffer(item.mSlot, item.mFrameNumber, item.mFence);
+        return true;
+    }
+
+    if (item.mDataSpace != mLastDataSpace) {
+        onDataSpaceChanged_l(
+                item.mDataSpace, (android_pixel_format)mBufferSlot[item.mSlot]->getPixelFormat());
+    }
+
+    err = UNKNOWN_ERROR;
+
+    // only submit sample if start time is unspecified, or sample
+    // is queued after the specified start time
+    if (mSkipFramesBeforeNs < 0ll || item.mTimestamp >= mSkipFramesBeforeNs) {
+        // if start time is set, offset time stamp by start time
+        if (mSkipFramesBeforeNs > 0) {
+            item.mTimestamp -= mSkipFramesBeforeNs;
+        }
+
+        int64_t timeUs = item.mTimestamp / 1000;
+        if (mFrameDropper != NULL && mFrameDropper->shouldDrop(timeUs)) {
+            ALOGV("skipping frame (%lld) to meet max framerate", static_cast<long long>(timeUs));
+            // set err to OK so that the skipped frame can still be saved as the lastest frame
+            err = OK;
+            dropped = true;
+        } else {
+            err = submitBuffer_l(item, cbi);
+        }
+    }
+
+    if (err != OK) {
+        ALOGV("submitBuffer_l failed, releasing bq slot %d", item.mSlot);
+        releaseBuffer(item.mSlot, item.mFrameNumber, item.mFence);
+    } else {
+        // Don't set the last buffer id if we're not repeating,
+        // we'll be holding on to the last buffer for nothing.
+        if (mRepeatAfterUs > 0ll) {
+            setLatestBuffer_l(item);
+        }
+        if (!dropped) {
+            ++mBufferUseCount[item.mSlot];
+        }
+        ALOGV("buffer submitted: slot=%d, cbi=%d, useCount=%d, acquired=%d",
+                item.mSlot, cbi, mBufferUseCount[item.mSlot], mNumBufferAcquired);
+    }
+
+    return true;
+}
+
+bool GraphicBufferSource::repeatLatestBuffer_l() {
+    CHECK(mExecuting && mNumFramesAvailable == 0);
+
+    if (mLatestBufferId < 0 || mSuspended) {
+        return false;
+    }
+    if (mBufferSlot[mLatestBufferId] == NULL) {
+        // This can happen if the remote side disconnects, causing
+        // onBuffersReleased() to NULL out our copy of the slots.  The
+        // buffer is gone, so we have nothing to show.
+        //
+        // To be on the safe side we try to release the buffer.
+        ALOGD("repeatLatestBuffer_l: slot was NULL");
+        mConsumer->releaseBuffer(
+                mLatestBufferId,
+                mLatestBufferFrameNum,
+                EGL_NO_DISPLAY,
+                EGL_NO_SYNC_KHR,
+                mLatestBufferFence);
+        mLatestBufferId = -1;
+        mLatestBufferFrameNum = 0;
+        mLatestBufferFence = Fence::NO_FENCE;
+        return false;
+    }
+
+    int cbi = findAvailableCodecBuffer_l();
+    if (cbi < 0) {
+        // No buffers available, bail.
+        ALOGV("repeatLatestBuffer_l: no codec buffers.");
+        return false;
+    }
+
+    BufferItem item;
+    item.mSlot = mLatestBufferId;
+    item.mFrameNumber = mLatestBufferFrameNum;
+    item.mTimestamp = mRepeatLastFrameTimestamp;
+    item.mFence = mLatestBufferFence;
+
+    status_t err = submitBuffer_l(item, cbi);
+
+    if (err != OK) {
+        return false;
+    }
+
+    ++mBufferUseCount[item.mSlot];
+
+    /* repeat last frame up to kRepeatLastFrameCount times.
+     * in case of static scene, a single repeat might not get rid of encoder
+     * ghosting completely, refresh a couple more times to get better quality
+     */
+    if (--mRepeatLastFrameCount > 0) {
+        mRepeatLastFrameTimestamp = item.mTimestamp + mRepeatAfterUs * 1000;
+
+        if (mReflector != NULL) {
+            sp<AMessage> msg = new AMessage(kWhatRepeatLastFrame, mReflector);
+            msg->setInt32("generation", ++mRepeatLastFrameGeneration);
+            msg->post(mRepeatAfterUs);
+        }
+    }
+
+    return true;
+}
+
+void GraphicBufferSource::setLatestBuffer_l(const BufferItem &item) {
+    if (mLatestBufferId >= 0 && mBufferUseCount[mLatestBufferId] == 0) {
+        releaseBuffer(mLatestBufferId, mLatestBufferFrameNum, mLatestBufferFence);
+        // mLatestBufferFence will be set to new fence just below
+    }
+
+    mLatestBufferId = item.mSlot;
+    mLatestBufferFrameNum = item.mFrameNumber;
+    mRepeatLastFrameTimestamp = item.mTimestamp + mRepeatAfterUs * 1000;
+
+    ALOGV("setLatestBuffer_l: slot=%d, useCount=%d",
+            item.mSlot, mBufferUseCount[item.mSlot]);
+
+    mRepeatBufferDeferred = false;
+    mRepeatLastFrameCount = kRepeatLastFrameCount;
+    mLatestBufferFence = item.mFence;
+
+    if (mReflector != NULL) {
+        sp<AMessage> msg = new AMessage(kWhatRepeatLastFrame, mReflector);
+        msg->setInt32("generation", ++mRepeatLastFrameGeneration);
+        msg->post(mRepeatAfterUs);
+    }
+}
+
+bool GraphicBufferSource::getTimestamp(
+        const BufferItem &item, int64_t *codecTimeUs) {
+    int64_t timeUs = item.mTimestamp / 1000;
+    timeUs += mInputBufferTimeOffsetUs;
+
+    if (mTimePerCaptureUs > 0ll
+            && (mTimePerCaptureUs > 2 * mTimePerFrameUs
+            || mTimePerFrameUs > 2 * mTimePerCaptureUs)) {
+        // Time lapse or slow motion mode
+        if (mPrevCaptureUs < 0ll) {
+            // first capture
+            mPrevCaptureUs = timeUs;
+            // adjust the first sample timestamp.
+            mPrevFrameUs = (timeUs * mTimePerFrameUs) / mTimePerCaptureUs;
+        } else {
+            // snap to nearest capture point
+            int64_t nFrames = (timeUs + mTimePerCaptureUs / 2 - mPrevCaptureUs)
+                    / mTimePerCaptureUs;
+            if (nFrames <= 0) {
+                // skip this frame as it's too close to previous capture
+                ALOGV("skipping frame, timeUs %lld", static_cast<long long>(timeUs));
+                return false;
+            }
+            mPrevCaptureUs = mPrevCaptureUs + nFrames * mTimePerCaptureUs;
+            mPrevFrameUs += mTimePerFrameUs * nFrames;
+        }
+
+        ALOGV("timeUs %lld, captureUs %lld, frameUs %lld",
+                static_cast<long long>(timeUs),
+                static_cast<long long>(mPrevCaptureUs),
+                static_cast<long long>(mPrevFrameUs));
+
+        *codecTimeUs = mPrevFrameUs;
+        return true;
+    } else {
+        int64_t originalTimeUs = timeUs;
+        if (originalTimeUs <= mPrevOriginalTimeUs) {
+                // Drop the frame if it's going backward in time. Bad timestamp
+                // could disrupt encoder's rate control completely.
+            ALOGW("Dropping frame that's going backward in time");
+            return false;
+        }
+
+        mPrevOriginalTimeUs = originalTimeUs;
+    }
+
+    *codecTimeUs = timeUs;
+    return true;
+}
+
+status_t GraphicBufferSource::submitBuffer_l(const BufferItem &item, int cbi) {
+    ALOGV("submitBuffer_l: slot=%d, cbi=%d", item.mSlot, cbi);
+
+    int64_t codecTimeUs;
+    if (!getTimestamp(item, &codecTimeUs)) {
+        return UNKNOWN_ERROR;
+    }
+
+    CodecBuffer& codecBuffer(mCodecBuffers.editItemAt(cbi));
+    codecBuffer.mGraphicBuffer = mBufferSlot[item.mSlot];
+    codecBuffer.mSlot = item.mSlot;
+    codecBuffer.mFrameNumber = item.mFrameNumber;
+
+    IOMX::buffer_id bufferID = codecBuffer.mBufferID;
+    const sp<GraphicBuffer> &buffer = codecBuffer.mGraphicBuffer;
+    int fenceID = item.mFence->isValid() ? item.mFence->dup() : -1;
+
+    status_t err = mOMXNode->emptyBuffer(
+            bufferID, buffer, OMX_BUFFERFLAG_ENDOFFRAME, codecTimeUs, fenceID);
+
+    if (err != OK) {
+        ALOGW("WARNING: emptyGraphicBuffer failed: 0x%x", err);
+        codecBuffer.mGraphicBuffer = NULL;
+        return err;
+    }
+
+    ALOGV("emptyGraphicBuffer succeeded, bufferID=%u buf=%p bufhandle=%p",
+            bufferID, buffer->getNativeBuffer(), buffer->handle);
+    return OK;
+}
+
+void GraphicBufferSource::submitEndOfInputStream_l() {
+    CHECK(mEndOfStream);
+    if (mEndOfStreamSent) {
+        ALOGV("EOS already sent");
+        return;
+    }
+
+    int cbi = findAvailableCodecBuffer_l();
+    if (cbi < 0) {
+        ALOGV("submitEndOfInputStream_l: no codec buffers available");
+        return;
+    }
+
+    // We reject any additional incoming graphic buffers, so there's no need
+    // to stick a placeholder into codecBuffer.mGraphicBuffer to mark it as
+    // in-use.
+    CodecBuffer& codecBuffer(mCodecBuffers.editItemAt(cbi));
+    IOMX::buffer_id bufferID = codecBuffer.mBufferID;
+
+    status_t err = mOMXNode->emptyBuffer(
+            bufferID, (sp<GraphicBuffer>)NULL,
+            OMX_BUFFERFLAG_ENDOFFRAME | OMX_BUFFERFLAG_EOS,
+            0 /* timestamp */, -1 /* fenceFd */);
+    if (err != OK) {
+        ALOGW("emptyDirectBuffer EOS failed: 0x%x", err);
+    } else {
+        ALOGV("submitEndOfInputStream_l: buffer submitted, bufferID=%u cbi=%d",
+                bufferID, cbi);
+        mEndOfStreamSent = true;
+    }
+}
+
+int GraphicBufferSource::findAvailableCodecBuffer_l() {
+    CHECK(mCodecBuffers.size() > 0);
+
+    for (int i = (int)mCodecBuffers.size() - 1; i>= 0; --i) {
+        if (mCodecBuffers[i].mGraphicBuffer == NULL) {
+            return i;
+        }
+    }
+    return -1;
+}
+
+int GraphicBufferSource::findMatchingCodecBuffer_l(IOMX::buffer_id bufferID) {
+    for (int i = (int)mCodecBuffers.size() - 1; i>= 0; --i) {
+        if (mCodecBuffers[i].mBufferID == bufferID) {
+            return i;
+        }
+    }
+    return -1;
+}
+
+status_t GraphicBufferSource::acquireBuffer(BufferItem *bi) {
+    status_t err = mConsumer->acquireBuffer(bi, 0);
+    if (err == BufferQueue::NO_BUFFER_AVAILABLE) {
+        // shouldn't happen
+        ALOGW("acquireBuffer: frame was not available");
+        return err;
+    } else if (err != OK) {
+        ALOGW("acquireBuffer: failed with err=%d", err);
+        return err;
+    }
+    // If this is the first time we're seeing this buffer, add it to our
+    // slot table.
+    if (bi->mGraphicBuffer != NULL) {
+        ALOGV("acquireBuffer: setting mBufferSlot %d", bi->mSlot);
+        mBufferSlot[bi->mSlot] = bi->mGraphicBuffer;
+        mBufferUseCount[bi->mSlot] = 0;
+    }
+    mNumBufferAcquired++;
+    return OK;
+}
+
+/*
+ * Releases an acquired buffer back to the consumer.
+ *
+ * id: buffer slot to release
+ * frameNum: frame number of the frame being released
+ * fence: fence of the frame being released
+ */
+void GraphicBufferSource::releaseBuffer(
+        int id, uint64_t frameNum, const sp<Fence> &fence) {
+    ALOGV("releaseBuffer: slot=%d", id);
+    mConsumer->releaseBuffer(
+            id, frameNum, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, fence);
+    mNumBufferAcquired--;
+}
+
+// BufferQueue::ConsumerListener callback
+void GraphicBufferSource::onFrameAvailable(const BufferItem& /*item*/) {
+    Mutex::Autolock autoLock(mMutex);
+
+    ALOGV("onFrameAvailable exec=%d avail=%zu",
+            mExecuting, mNumFramesAvailable);
+
+    if (mOMXNode == NULL || mEndOfStreamSent || (mSuspended && mActionQueue.empty())) {
+        if (mEndOfStreamSent) {
+            // This should only be possible if a new buffer was queued after
+            // EOS was signaled, i.e. the app is misbehaving.
+
+            ALOGW("onFrameAvailable: EOS is sent, ignoring frame");
+        } else {
+            ALOGV("onFrameAvailable: suspended, ignoring frame");
+        }
+
+        BufferItem item;
+        status_t err = acquireBuffer(&item);
+        if (err == OK) {
+            releaseBuffer(item.mSlot, item.mFrameNumber, item.mFence);
+        } else {
+            ALOGE("onFrameAvailable: acquireBuffer returned err=%d", err);
+        }
+        return;
+    }
+
+    mNumFramesAvailable++;
+
+    mRepeatBufferDeferred = false;
+    ++mRepeatLastFrameGeneration;
+
+    if (mExecuting) {
+        fillCodecBuffer_l();
+    }
+}
+
+// BufferQueue::ConsumerListener callback
+void GraphicBufferSource::onBuffersReleased() {
+    Mutex::Autolock lock(mMutex);
+
+    uint64_t slotMask;
+    if (mConsumer->getReleasedBuffers(&slotMask) != NO_ERROR) {
+        ALOGW("onBuffersReleased: unable to get released buffer set");
+        slotMask = 0xffffffffffffffffULL;
+    }
+
+    ALOGV("onBuffersReleased: 0x%016" PRIx64, slotMask);
+
+    for (int i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) {
+        if ((slotMask & 0x01) != 0) {
+            // Last buffer (if set) is always acquired even if its use count
+            // is 0, because we could have skipped that frame but kept it for
+            // repeating. Otherwise a buffer is only acquired if use count>0.
+            if (mBufferSlot[i] != NULL &&
+                    (mBufferUseCount[i] > 0 || mLatestBufferId == i)) {
+                ALOGV("releasing acquired buffer: slot=%d, useCount=%d, latest=%d",
+                        i, mBufferUseCount[i], mLatestBufferId);
+                mNumBufferAcquired--;
+            }
+            if (mLatestBufferId == i) {
+                mLatestBufferId = -1;
+            }
+            mBufferSlot[i] = NULL;
+            mBufferUseCount[i] = 0;
+        }
+        slotMask >>= 1;
+    }
+}
+
+// BufferQueue::ConsumerListener callback
+void GraphicBufferSource::onSidebandStreamChanged() {
+    ALOG_ASSERT(false, "GraphicBufferSource can't consume sideband streams");
+}
+
+Status GraphicBufferSource::configure(
+        const sp<IOMXNode>& omxNode, int32_t dataSpace) {
+    if (omxNode == NULL) {
+        return Status::fromServiceSpecificError(BAD_VALUE);
+    }
+
+    // Do setInputSurface() first, the node will try to enable metadata
+    // mode on input, and does necessary error checking. If this fails,
+    // we can't use this input surface on the node.
+    status_t err = omxNode->setInputSurface(mOmxBufferSource);
+    if (err != NO_ERROR) {
+        ALOGE("Unable to set input surface: %d", err);
+        return Status::fromServiceSpecificError(err);
+    }
+
+    // use consumer usage bits queried from encoder, but always add
+    // HW_VIDEO_ENCODER for backward compatibility.
+    uint32_t consumerUsage;
+    if (omxNode->getParameter(
+            (OMX_INDEXTYPE)OMX_IndexParamConsumerUsageBits,
+            &consumerUsage, sizeof(consumerUsage)) != OK) {
+        consumerUsage = 0;
+    }
+
+    OMX_PARAM_PORTDEFINITIONTYPE def;
+    InitOMXParams(&def);
+    def.nPortIndex = kPortIndexInput;
+
+    err = omxNode->getParameter(
+            OMX_IndexParamPortDefinition, &def, sizeof(def));
+    if (err != NO_ERROR) {
+        ALOGE("Failed to get port definition: %d", err);
+        return Status::fromServiceSpecificError(UNKNOWN_ERROR);
+    }
+
+    // Call setMaxAcquiredBufferCount without lock.
+    // setMaxAcquiredBufferCount could call back to onBuffersReleased
+    // if the buffer count change results in releasing of existing buffers,
+    // which would lead to deadlock.
+    err = mConsumer->setMaxAcquiredBufferCount(def.nBufferCountActual);
+    if (err != NO_ERROR) {
+        ALOGE("Unable to set BQ max acquired buffer count to %u: %d",
+                def.nBufferCountActual, err);
+        return Status::fromServiceSpecificError(err);
+    }
+
+    {
+        Mutex::Autolock autoLock(mMutex);
+        mOMXNode = omxNode;
+
+        err = mConsumer->setDefaultBufferSize(
+                def.format.video.nFrameWidth,
+                def.format.video.nFrameHeight);
+        if (err != NO_ERROR) {
+            ALOGE("Unable to set BQ default buffer size to %ux%u: %d",
+                    def.format.video.nFrameWidth,
+                    def.format.video.nFrameHeight,
+                    err);
+            return Status::fromServiceSpecificError(err);
+        }
+
+        consumerUsage |= GRALLOC_USAGE_HW_VIDEO_ENCODER;
+        mConsumer->setConsumerUsageBits(consumerUsage);
+
+        // Sets the default buffer data space
+        ALOGD("setting dataspace: %#x, acquired=%d", dataSpace, mNumBufferAcquired);
+        mConsumer->setDefaultBufferDataSpace((android_dataspace)dataSpace);
+        mLastDataSpace = (android_dataspace)dataSpace;
+
+        mExecuting = false;
+        mSuspended = false;
+        mEndOfStream = false;
+        mEndOfStreamSent = false;
+        mPrevOriginalTimeUs = -1ll;
+        mSkipFramesBeforeNs = -1ll;
+        mRepeatAfterUs = -1ll;
+        mRepeatLastFrameGeneration = 0;
+        mRepeatLastFrameTimestamp = -1ll;
+        mRepeatLastFrameCount = 0;
+        mLatestBufferId = -1;
+        mLatestBufferFrameNum = 0;
+        mLatestBufferFence = Fence::NO_FENCE;
+        mRepeatBufferDeferred = false;
+        mTimePerCaptureUs = -1ll;
+        mTimePerFrameUs = -1ll;
+        mPrevCaptureUs = -1ll;
+        mPrevFrameUs = -1ll;
+        mInputBufferTimeOffsetUs = 0;
+        mStopTimeUs = -1;
+        mActionQueue.clear();
+    }
+
+    return Status::ok();
+}
+
+Status GraphicBufferSource::setSuspend(bool suspend, int64_t suspendStartTimeUs) {
+    ALOGV("setSuspend=%d at time %lld us", suspend, (long long)suspendStartTimeUs);
+
+    Mutex::Autolock autoLock(mMutex);
+
+    if (mStopTimeUs != -1) {
+        ALOGE("setSuspend failed as STOP action is pending");
+        return Status::fromServiceSpecificError(INVALID_OPERATION);
+    }
+
+    // Push the action to the queue.
+    if (suspendStartTimeUs != -1) {
+        // suspendStartTimeUs must be smaller or equal to current systemTime.
+        int64_t currentSystemTimeUs = systemTime() / 1000;
+        if (suspendStartTimeUs > currentSystemTimeUs) {
+            ALOGE("setSuspend failed. %lld is larger than current system time %lld us",
+                    (long long)suspendStartTimeUs, (long long)currentSystemTimeUs);
+            return Status::fromServiceSpecificError(INVALID_OPERATION);
+        }
+        if (mLastActionTimeUs != -1 && suspendStartTimeUs < mLastActionTimeUs) {
+            ALOGE("setSuspend failed. %lld is smaller than last action time %lld us",
+                    (long long)suspendStartTimeUs, (long long)mLastActionTimeUs);
+            return Status::fromServiceSpecificError(INVALID_OPERATION);
+        }
+        mLastActionTimeUs = suspendStartTimeUs;
+        ActionItem action;
+        action.mAction = suspend ? ActionItem::PAUSE : ActionItem::RESUME;
+        action.mActionTimeUs = suspendStartTimeUs;
+        ALOGV("Push %s action into actionQueue", suspend ? "PAUSE" : "RESUME");
+        mActionQueue.push_back(action);
+    } else {
+        if (suspend) {
+            mSuspended = true;
+
+            while (mNumFramesAvailable > 0) {
+                BufferItem item;
+                status_t err = acquireBuffer(&item);
+
+                if (err != OK) {
+                    ALOGE("setSuspend: acquireBuffer returned err=%d", err);
+                    break;
+                }
+
+                --mNumFramesAvailable;
+
+                releaseBuffer(item.mSlot, item.mFrameNumber, item.mFence);
+            }
+            return Status::ok();
+        } else {
+
+            mSuspended = false;
+
+            if (mExecuting && mNumFramesAvailable == 0 && mRepeatBufferDeferred) {
+                if (repeatLatestBuffer_l()) {
+                    ALOGV("suspend/deferred repeatLatestBuffer_l SUCCESS");
+
+                    mRepeatBufferDeferred = false;
+                } else {
+                    ALOGV("suspend/deferred repeatLatestBuffer_l FAILURE");
+                }
+            }
+        }
+    }
+    return Status::ok();
+}
+
+Status GraphicBufferSource::setRepeatPreviousFrameDelayUs(int64_t repeatAfterUs) {
+    ALOGV("setRepeatPreviousFrameDelayUs: delayUs=%lld", (long long)repeatAfterUs);
+
+    Mutex::Autolock autoLock(mMutex);
+
+    if (mExecuting || repeatAfterUs <= 0ll) {
+        return Status::fromServiceSpecificError(INVALID_OPERATION);
+    }
+
+    mRepeatAfterUs = repeatAfterUs;
+    return Status::ok();
+}
+
+Status GraphicBufferSource::setTimeOffsetUs(int64_t timeOffsetUs) {
+    Mutex::Autolock autoLock(mMutex);
+
+    // timeOffsetUs must be negative for adjustment.
+    if (timeOffsetUs >= 0ll) {
+        return Status::fromServiceSpecificError(INVALID_OPERATION);
+    }
+
+    mInputBufferTimeOffsetUs = timeOffsetUs;
+    return Status::ok();
+}
+
+Status GraphicBufferSource::setMaxFps(float maxFps) {
+    ALOGV("setMaxFps: maxFps=%lld", (long long)maxFps);
+
+    Mutex::Autolock autoLock(mMutex);
+
+    if (mExecuting) {
+        return Status::fromServiceSpecificError(INVALID_OPERATION);
+    }
+
+    mFrameDropper = new FrameDropper();
+    status_t err = mFrameDropper->setMaxFrameRate(maxFps);
+    if (err != OK) {
+        mFrameDropper.clear();
+        return Status::fromServiceSpecificError(err);
+    }
+
+    return Status::ok();
+}
+
+Status GraphicBufferSource::setStartTimeUs(int64_t skipFramesBeforeUs) {
+    ALOGV("setStartTimeUs: skipFramesBeforeUs=%lld", (long long)skipFramesBeforeUs);
+
+    Mutex::Autolock autoLock(mMutex);
+
+    mSkipFramesBeforeNs =
+            (skipFramesBeforeUs > 0) ? (skipFramesBeforeUs * 1000) : -1ll;
+
+    return Status::ok();
+}
+
+Status GraphicBufferSource::setStopTimeUs(int64_t stopTimeUs) {
+    ALOGV("setStopTimeUs: %lld us", (long long)stopTimeUs);
+    Mutex::Autolock autoLock(mMutex);
+
+    if (mStopTimeUs != -1) {
+        // Ignore if stop time has already been set
+        return Status::ok();
+    }
+
+    // stopTimeUs must be smaller or equal to current systemTime.
+    int64_t currentSystemTimeUs = systemTime() / 1000;
+    if (stopTimeUs > currentSystemTimeUs) {
+        ALOGE("setStopTimeUs failed. %lld is larger than current system time %lld us",
+            (long long)stopTimeUs, (long long)currentSystemTimeUs);
+        return Status::fromServiceSpecificError(INVALID_OPERATION);
+    }
+    if (mLastActionTimeUs != -1 && stopTimeUs < mLastActionTimeUs) {
+        ALOGE("setSuspend failed. %lld is smaller than last action time %lld us",
+            (long long)stopTimeUs, (long long)mLastActionTimeUs);
+        return Status::fromServiceSpecificError(INVALID_OPERATION);
+    }
+    mLastActionTimeUs = stopTimeUs;
+    ActionItem action;
+    action.mAction = ActionItem::STOP;
+    action.mActionTimeUs = stopTimeUs;
+    mActionQueue.push_back(action);
+    mStopTimeUs = stopTimeUs;
+    return Status::ok();
+}
+
+Status GraphicBufferSource::setTimeLapseConfig(int64_t timePerFrameUs, int64_t timePerCaptureUs) {
+    ALOGV("setTimeLapseConfig: timePerFrameUs=%lld, timePerCaptureUs=%lld",
+            (long long)timePerFrameUs, (long long)timePerCaptureUs);
+
+    Mutex::Autolock autoLock(mMutex);
+
+    if (mExecuting || timePerFrameUs <= 0ll || timePerCaptureUs <= 0ll) {
+        return Status::fromServiceSpecificError(INVALID_OPERATION);
+    }
+
+    mTimePerFrameUs = timePerFrameUs;
+    mTimePerCaptureUs = timePerCaptureUs;
+
+    return Status::ok();
+}
+
+Status GraphicBufferSource::setColorAspects(int32_t aspectsPacked) {
+    Mutex::Autolock autoLock(mMutex);
+    mColorAspects = ColorUtils::unpackToColorAspects(aspectsPacked);
+    ALOGD("requesting color aspects (R:%d(%s), P:%d(%s), M:%d(%s), T:%d(%s))",
+            mColorAspects.mRange, asString(mColorAspects.mRange),
+            mColorAspects.mPrimaries, asString(mColorAspects.mPrimaries),
+            mColorAspects.mMatrixCoeffs, asString(mColorAspects.mMatrixCoeffs),
+            mColorAspects.mTransfer, asString(mColorAspects.mTransfer));
+
+    return Status::ok();
+}
+
+Status GraphicBufferSource::signalEndOfInputStream() {
+    Mutex::Autolock autoLock(mMutex);
+    ALOGV("signalEndOfInputStream: exec=%d avail=%zu eos=%d",
+            mExecuting, mNumFramesAvailable, mEndOfStream);
+
+    if (mEndOfStream) {
+        ALOGE("EOS was already signaled");
+        return Status::fromStatusT(INVALID_OPERATION);
+    }
+
+    // Set the end-of-stream flag.  If no frames are pending from the
+    // BufferQueue, and a codec buffer is available, and we're executing,
+    // and there is no stop timestamp, we initiate the EOS from here.
+    // Otherwise, we'll let codecBufferEmptied() (or omxExecuting) do it.
+    //
+    // Note: if there are no pending frames and all codec buffers are
+    // available, we *must* submit the EOS from here or we'll just
+    // stall since no future events are expected.
+    mEndOfStream = true;
+
+    if (mStopTimeUs == -1 && mExecuting && mNumFramesAvailable == 0) {
+        submitEndOfInputStream_l();
+    }
+
+    return Status::ok();
+}
+
+void GraphicBufferSource::onMessageReceived(const sp<AMessage> &msg) {
+    switch (msg->what()) {
+        case kWhatRepeatLastFrame:
+        {
+            Mutex::Autolock autoLock(mMutex);
+
+            int32_t generation;
+            CHECK(msg->findInt32("generation", &generation));
+
+            if (generation != mRepeatLastFrameGeneration) {
+                // stale
+                break;
+            }
+
+            if (!mExecuting || mNumFramesAvailable > 0) {
+                break;
+            }
+
+            bool success = repeatLatestBuffer_l();
+
+            if (success) {
+                ALOGV("repeatLatestBuffer_l SUCCESS");
+            } else {
+                ALOGV("repeatLatestBuffer_l FAILURE");
+                mRepeatBufferDeferred = true;
+            }
+            break;
+        }
+
+        default:
+            TRESPASS();
+    }
+}
+
+}  // namespace android
diff --git a/media/libstagefright/omx/hal/1.0/impl/GraphicBufferSource.h b/media/libstagefright/omx/hal/1.0/impl/GraphicBufferSource.h
new file mode 100644
index 0000000..475548e
--- /dev/null
+++ b/media/libstagefright/omx/hal/1.0/impl/GraphicBufferSource.h
@@ -0,0 +1,343 @@
+/*
+ * Copyright (C) 2013 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 GRAPHIC_BUFFER_SOURCE_H_
+
+#define GRAPHIC_BUFFER_SOURCE_H_
+
+#include <gui/IGraphicBufferProducer.h>
+#include <gui/BufferQueue.h>
+#include <utils/RefBase.h>
+
+#include <VideoAPI.h>
+#include <media/IOMX.h>
+#include <media/OMXFenceParcelable.h>
+#include <media/stagefright/foundation/ABase.h>
+#include <media/stagefright/foundation/AHandlerReflector.h>
+#include <media/stagefright/foundation/ALooper.h>
+
+#include <android/BnGraphicBufferSource.h>
+#include <android/BnOMXBufferSource.h>
+
+namespace android {
+
+using ::android::binder::Status;
+
+struct FrameDropper;
+
+/*
+ * This class is used to feed OMX codecs from a Surface via BufferQueue.
+ *
+ * Instances of the class don't run on a dedicated thread.  Instead,
+ * various events trigger data movement:
+ *
+ *  - Availability of a new frame of data from the BufferQueue (notified
+ *    via the onFrameAvailable callback).
+ *  - The return of a codec buffer (via OnEmptyBufferDone).
+ *  - Application signaling end-of-stream.
+ *  - Transition to or from "executing" state.
+ *
+ * Frames of data (and, perhaps, the end-of-stream indication) can arrive
+ * before the codec is in the "executing" state, so we need to queue
+ * things up until we're ready to go.
+ */
+class GraphicBufferSource : public BnGraphicBufferSource,
+                            public BufferQueue::ConsumerListener {
+public:
+    GraphicBufferSource();
+
+    virtual ~GraphicBufferSource();
+
+    // We can't throw an exception if the constructor fails, so we just set
+    // this and require that the caller test the value.
+    status_t initCheck() const {
+        return mInitCheck;
+    }
+
+    // Returns the handle to the producer side of the BufferQueue.  Buffers
+    // queued on this will be received by GraphicBufferSource.
+    sp<IGraphicBufferProducer> getIGraphicBufferProducer() const {
+        return mProducer;
+    }
+
+    // This is called when OMX transitions to OMX_StateExecuting, which means
+    // we can start handing it buffers.  If we already have buffers of data
+    // sitting in the BufferQueue, this will send them to the codec.
+    Status onOmxExecuting();
+
+    // This is called when OMX transitions to OMX_StateIdle, indicating that
+    // the codec is meant to return all buffers back to the client for them
+    // to be freed. Do NOT submit any more buffers to the component.
+    Status onOmxIdle();
+
+    // This is called when OMX transitions to OMX_StateLoaded, indicating that
+    // we are shutting down.
+    Status onOmxLoaded();
+
+    // A "codec buffer", i.e. a buffer that can be used to pass data into
+    // the encoder, has been allocated.  (This call does not call back into
+    // OMXNodeInstance.)
+    Status onInputBufferAdded(int32_t bufferID);
+
+    // Called from OnEmptyBufferDone.  If we have a BQ buffer available,
+    // fill it with a new frame of data; otherwise, just mark it as available.
+    Status onInputBufferEmptied(
+            int32_t bufferID, const OMXFenceParcelable& fenceParcel);
+
+    // Configure the buffer source to be used with an OMX node with the default
+    // data space.
+    Status configure(const sp<IOMXNode>& omxNode, int32_t dataSpace) override;
+
+    // This is called after the last input frame has been submitted or buffer
+    // timestamp is greater or equal than stopTimeUs. We need to submit an empty
+    // buffer with the EOS flag set.  If we don't have a codec buffer ready,
+    // we just set the mEndOfStream flag.
+    Status signalEndOfInputStream() override;
+
+    // If suspend is true, all incoming buffers (including those currently
+    // in the BufferQueue) with timestamp larger than timeUs will be discarded
+    // until the suspension is lifted. If suspend is false, all incoming buffers
+    // including those currently in the BufferQueue) with timestamp larger than
+    // timeUs will be processed. timeUs uses SYSTEM_TIME_MONOTONIC time base.
+    Status setSuspend(bool suspend, int64_t timeUs) override;
+
+    // Specifies the interval after which we requeue the buffer previously
+    // queued to the encoder. This is useful in the case of surface flinger
+    // providing the input surface if the resulting encoded stream is to
+    // be displayed "live". If we were not to push through the extra frame
+    // the decoder on the remote end would be unable to decode the latest frame.
+    // This API must be called before transitioning the encoder to "executing"
+    // state and once this behaviour is specified it cannot be reset.
+    Status setRepeatPreviousFrameDelayUs(int64_t repeatAfterUs) override;
+
+    // Sets the input buffer timestamp offset.
+    // When set, the sample's timestamp will be adjusted with the timeOffsetUs.
+    Status setTimeOffsetUs(int64_t timeOffsetUs) override;
+
+    // When set, the max frame rate fed to the encoder will be capped at maxFps.
+    Status setMaxFps(float maxFps) override;
+
+    // Sets the time lapse (or slow motion) parameters.
+    // When set, the sample's timestamp will be modified to playback framerate,
+    // and capture timestamp will be modified to capture rate.
+    Status setTimeLapseConfig(int64_t timePerFrameUs, int64_t timePerCaptureUs) override;
+
+    // Sets the start time us (in system time), samples before which should
+    // be dropped and not submitted to encoder
+    Status setStartTimeUs(int64_t startTimeUs) override;
+
+    // Sets the stop time us (in system time), samples after which should be dropped
+    // and not submitted to encoder. timeUs uses SYSTEM_TIME_MONOTONIC time base.
+    Status setStopTimeUs(int64_t stopTimeUs) override;
+
+    // Sets the desired color aspects, e.g. to be used when producer does not specify a dataspace.
+    Status setColorAspects(int32_t aspectsPacked) override;
+
+protected:
+    // BufferQueue::ConsumerListener interface, called when a new frame of
+    // data is available.  If we're executing and a codec buffer is
+    // available, we acquire the buffer, copy the GraphicBuffer reference
+    // into the codec buffer, and call Empty[This]Buffer.  If we're not yet
+    // executing or there's no codec buffer available, we just increment
+    // mNumFramesAvailable and return.
+    void onFrameAvailable(const BufferItem& item) override;
+
+    // BufferQueue::ConsumerListener interface, called when the client has
+    // released one or more GraphicBuffers.  We clear out the appropriate
+    // set of mBufferSlot entries.
+    void onBuffersReleased() override;
+
+    // BufferQueue::ConsumerListener interface, called when the client has
+    // changed the sideband stream. GraphicBufferSource doesn't handle sideband
+    // streams so this is a no-op (and should never be called).
+    void onSidebandStreamChanged() override;
+
+private:
+
+    // Keep track of codec input buffers.  They may either be available
+    // (mGraphicBuffer == NULL) or in use by the codec.
+    struct CodecBuffer {
+        IOMX::buffer_id mBufferID;
+
+        // buffer producer's frame-number for buffer
+        uint64_t mFrameNumber;
+
+        // buffer producer's buffer slot for buffer
+        int mSlot;
+
+        sp<GraphicBuffer> mGraphicBuffer;
+    };
+
+    // Returns the index of an available codec buffer.  If none are
+    // available, returns -1.  Mutex must be held by caller.
+    int findAvailableCodecBuffer_l();
+
+    // Returns true if a codec buffer is available.
+    bool isCodecBufferAvailable_l() {
+        return findAvailableCodecBuffer_l() >= 0;
+    }
+
+    // Finds the mCodecBuffers entry that matches.  Returns -1 if not found.
+    int findMatchingCodecBuffer_l(IOMX::buffer_id bufferID);
+
+    // Fills a codec buffer with a frame from the BufferQueue.  This must
+    // only be called when we know that a frame of data is ready (i.e. we're
+    // in the onFrameAvailable callback, or if we're in codecBufferEmptied
+    // and mNumFramesAvailable is nonzero).  Returns without doing anything if
+    // we don't have a codec buffer available.
+    //
+    // Returns true if we successfully filled a codec buffer with a BQ buffer.
+    bool fillCodecBuffer_l();
+
+    // Marks the mCodecBuffers entry as in-use, copies the GraphicBuffer
+    // reference into the codec buffer, and submits the data to the codec.
+    status_t submitBuffer_l(const BufferItem &item, int cbi);
+
+    // Submits an empty buffer, with the EOS flag set.   Returns without
+    // doing anything if we don't have a codec buffer available.
+    void submitEndOfInputStream_l();
+
+    // Acquire buffer from the consumer
+    status_t acquireBuffer(BufferItem *bi);
+
+    // Release buffer to the consumer
+    void releaseBuffer(int id, uint64_t frameNum, const sp<Fence> &fence);
+
+    void setLatestBuffer_l(const BufferItem &item);
+    bool repeatLatestBuffer_l();
+    bool getTimestamp(const BufferItem &item, int64_t *codecTimeUs);
+
+    // called when the data space of the input buffer changes
+    void onDataSpaceChanged_l(android_dataspace dataSpace, android_pixel_format pixelFormat);
+
+    // Lock, covers all member variables.
+    mutable Mutex mMutex;
+
+    // Used to report constructor failure.
+    status_t mInitCheck;
+
+    // Pointer back to the IOMXNode that created us.  We send buffers here.
+    sp<IOMXNode> mOMXNode;
+
+    // Set by omxExecuting() / omxIdling().
+    bool mExecuting;
+
+    bool mSuspended;
+
+    // The time to stop sending buffers.
+    int64_t mStopTimeUs;
+
+    // Last dataspace seen
+    android_dataspace mLastDataSpace;
+
+    // Our BufferQueue interfaces. mProducer is passed to the producer through
+    // getIGraphicBufferProducer, and mConsumer is used internally to retrieve
+    // the buffers queued by the producer.
+    sp<IGraphicBufferProducer> mProducer;
+    sp<IGraphicBufferConsumer> mConsumer;
+
+    // Number of frames pending in BufferQueue that haven't yet been
+    // forwarded to the codec.
+    size_t mNumFramesAvailable;
+
+    // Number of frames acquired from consumer (debug only)
+    int32_t mNumBufferAcquired;
+
+    // Set to true if we want to send end-of-stream after we run out of
+    // frames in BufferQueue.
+    bool mEndOfStream;
+    bool mEndOfStreamSent;
+
+    // Cache of GraphicBuffers from the buffer queue.  When the codec
+    // is done processing a GraphicBuffer, we can use this to map back
+    // to a slot number.
+    sp<GraphicBuffer> mBufferSlot[BufferQueue::NUM_BUFFER_SLOTS];
+    int32_t mBufferUseCount[BufferQueue::NUM_BUFFER_SLOTS];
+
+    // Tracks codec buffers.
+    Vector<CodecBuffer> mCodecBuffers;
+
+    struct ActionItem {
+        typedef enum {
+            PAUSE,
+            RESUME,
+            STOP
+        } ActionType;
+        ActionType mAction;
+        int64_t mActionTimeUs;
+    };
+
+    // Maintain last action timestamp to ensure all the action timestamps are
+    // monotonically increasing.
+    int64_t mLastActionTimeUs;
+
+    // An action queue that queue up all the actions sent to GraphicBufferSource.
+    // STOP action should only show up at the end of the list as all the actions
+    // after a STOP action will be discarded. mActionQueue is protected by mMutex.
+    List<ActionItem> mActionQueue;
+
+    ////
+    friend struct AHandlerReflector<GraphicBufferSource>;
+
+    enum {
+        kWhatRepeatLastFrame,
+    };
+    enum {
+        kRepeatLastFrameCount = 10,
+    };
+
+    int64_t mPrevOriginalTimeUs;
+    int64_t mSkipFramesBeforeNs;
+
+    sp<FrameDropper> mFrameDropper;
+
+    sp<ALooper> mLooper;
+    sp<AHandlerReflector<GraphicBufferSource> > mReflector;
+
+    int64_t mRepeatAfterUs;
+    int32_t mRepeatLastFrameGeneration;
+    int64_t mRepeatLastFrameTimestamp;
+    int32_t mRepeatLastFrameCount;
+
+    int mLatestBufferId;
+    uint64_t mLatestBufferFrameNum;
+    sp<Fence> mLatestBufferFence;
+
+    // The previous buffer should've been repeated but
+    // no codec buffer was available at the time.
+    bool mRepeatBufferDeferred;
+
+    // Time lapse / slow motion configuration
+    int64_t mTimePerCaptureUs;
+    int64_t mTimePerFrameUs;
+    int64_t mPrevCaptureUs;
+    int64_t mPrevFrameUs;
+
+    int64_t mInputBufferTimeOffsetUs;
+
+    ColorAspects mColorAspects;
+
+    class OmxBufferSource;
+    sp<OmxBufferSource> mOmxBufferSource;
+
+    void onMessageReceived(const sp<AMessage> &msg);
+
+    DISALLOW_EVIL_CONSTRUCTORS(GraphicBufferSource);
+};
+
+}  // namespace android
+
+#endif  // GRAPHIC_BUFFER_SOURCE_H_
diff --git a/media/libstagefright/omx/hal/1.0/impl/Omx.cpp b/media/libstagefright/omx/hal/1.0/impl/Omx.cpp
index eddcc77..a9f29e9 100644
--- a/media/libstagefright/omx/hal/1.0/impl/Omx.cpp
+++ b/media/libstagefright/omx/hal/1.0/impl/Omx.cpp
@@ -14,17 +14,17 @@
  * limitations under the License.
  */
 
+#include <ios>
 #include <list>
 
-#include "Omx.h"
-#include <IOMX.h>
-#include <OMXMaster.h>
-#include <OMXNodeInstance.h>
-#include <GraphicBufferSource.h>
+#include <android-base/logging.h>
 #include <gui/IGraphicBufferProducer.h>
-
+#include <OMX_Core.h>
 #include <OMX_AsString.h>
-#include <OMXUtils.h>
+
+#include "../../../OMXUtils.h"
+#include "../../../OMXMaster.h"
+#include "../../../GraphicBufferSource.h"
 
 #include "WOmxNode.h"
 #include "WOmxObserver.h"
@@ -32,6 +32,8 @@
 #include "WGraphicBufferSource.h"
 #include "Conversion.h"
 
+#include "Omx.h"
+
 namespace android {
 namespace hardware {
 namespace media {
@@ -102,9 +104,10 @@
             instance.get(), &handle);
 
     if (err != OMX_ErrorNone) {
-        ALOGE("FAILED to allocate omx component '%s' err=%s(%#x)",
-                name.c_str(), asString(err), err);
-
+        LOG(ERROR) << "Failed to allocate omx component "
+                "'" << name.c_str() << "' "
+                " err=" << asString(err) <<
+                "(0x" << std::hex << unsigned(err) << ")";
         _hidl_cb(toStatus(StatusFromOMXError(err)), nullptr);
         return Void();
     }
@@ -125,8 +128,9 @@
     sp<GraphicBufferSource> graphicBufferSource = new GraphicBufferSource();
     status_t err = graphicBufferSource->initCheck();
     if (err != OK) {
-        ALOGE("Failed to create persistent input surface: %s (%d)",
-                strerror(-err), err);
+        LOG(ERROR) << "Failed to create persistent input surface: "
+                << strerror(-err) << " "
+                "(" << int(err) << ")";
         _hidl_cb(toStatus(err), nullptr, nullptr);
         return Void();
     }
@@ -147,7 +151,7 @@
         ssize_t index = mLiveNodes.indexOfKey(who);
 
         if (index < 0) {
-            ALOGE("b/27597103, nonexistent observer on serviceDied");
+            LOG(ERROR) << "b/27597103, nonexistent observer on serviceDied";
             android_errorWriteLog(0x534e4554, "27597103");
             return;
         }
diff --git a/media/libstagefright/omx/hal/1.0/impl/Omx.h b/media/libstagefright/omx/hal/1.0/impl/Omx.h
index 7633820..3e9ea73 100644
--- a/media/libstagefright/omx/hal/1.0/impl/Omx.h
+++ b/media/libstagefright/omx/hal/1.0/impl/Omx.h
@@ -17,13 +17,12 @@
 #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>
 
-#include <utils/threads.h>
-#include <utils/KeyedVector.h>
-#include <OmxNodeOwner.h>
+#include "../../../../include/OMXNodeInstance.h"
+
+#include <android/hardware/media/omx/1.0/IOmx.h>
 
 namespace android {
 
diff --git a/media/libstagefright/omx/hal/1.0/impl/OmxNode.cpp b/media/libstagefright/omx/hal/1.0/impl/OmxNode.cpp
deleted file mode 100644
index f62269f..0000000
--- a/media/libstagefright/omx/hal/1.0/impl/OmxNode.cpp
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * 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.
- */
-
-#include <IOMX.h>
-#include <OMXNodeInstance.h>
-#include "OmxNode.h"
-#include "WOmxNode.h"
-#include "WOmxObserver.h"
-#include "Conversion.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, int32_t param) {
-    // 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 {};
-}
-
-OmxNode::OmxNode(OmxNodeOwner* owner, sp<IOmxObserver> const& observer, char const* name) {
-    mLNode = new OMXNodeInstance(owner, new LWOmxObserver(observer), name);
-}
-
-}  // namespace implementation
-}  // namespace V1_0
-}  // namespace omx
-}  // namespace media
-}  // namespace hardware
-}  // namespace android
diff --git a/media/libstagefright/omx/hal/1.0/impl/OmxNode.h b/media/libstagefright/omx/hal/1.0/impl/OmxNode.h
deleted file mode 100644
index fc19306..0000000
--- a/media/libstagefright/omx/hal/1.0/impl/OmxNode.h
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * 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_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 <android/hardware/media/omx/1.0/IOmxObserver.h>
-#include <hidl/MQDescriptor.h>
-#include <hidl/Status.h>
-
-#include <OMXNodeInstance.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::IOmxObserver;
-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::hidl::base::V1_0::IBase;
-using ::android::hardware::hidl_array;
-using ::android::hardware::hidl_memory;
-using ::android::hardware::hidl_string;
-using ::android::hardware::hidl_vec;
-using ::android::hardware::Return;
-using ::android::hardware::Void;
-using ::android::sp;
-
-using ::android::OMXNodeInstance;
-using ::android::OmxNodeOwner;
-
-/**
- * Wrapper classes for conversion
- * ==============================
- *
- * Naming convention:
- * - LW = Legacy Wrapper --- It wraps a Treble object inside a legacy object.
- * - TW = Treble Wrapper --- It wraps a legacy object inside a Treble object.
- */
-
-struct OmxNode : public IOmxNode {
-    Return<Status> freeNode() override;
-    Return<Status> sendCommand(uint32_t cmd, int32_t param) 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;
-
-    OmxNode(OmxNodeOwner* owner, sp<IOmxObserver> const& observer, char const* name);
-protected:
-    sp<OMXNodeInstance> mLNode;
-};
-
-}  // 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/impl/WGraphicBufferSource.cpp b/media/libstagefright/omx/hal/1.0/impl/WGraphicBufferSource.cpp
index af9cf03..884e87b 100644
--- a/media/libstagefright/omx/hal/1.0/impl/WGraphicBufferSource.cpp
+++ b/media/libstagefright/omx/hal/1.0/impl/WGraphicBufferSource.cpp
@@ -14,11 +14,12 @@
  * limitations under the License.
  */
 
-#include "WGraphicBufferSource.h"
-#include "Conversion.h"
-#include "WOmxNode.h"
 #include <stagefright/foundation/ColorUtils.h>
 
+#include "WGraphicBufferSource.h"
+#include "WOmxNode.h"
+#include "Conversion.h"
+
 namespace android {
 namespace hardware {
 namespace media {
@@ -124,7 +125,8 @@
 }
 
 Return<void> TWGraphicBufferSource::setStopTimeUs(int64_t stopTimeUs) {
-    return toHardwareStatus(mBase->setStopTimeUs(stopTimeUs));
+    mBase->setStopTimeUs(stopTimeUs);
+    return Void();
 }
 
 Return<void> TWGraphicBufferSource::setColorAspects(
diff --git a/media/libstagefright/omx/hal/1.0/impl/WGraphicBufferSource.h b/media/libstagefright/omx/hal/1.0/impl/WGraphicBufferSource.h
index dd6168e..bd60c46 100644
--- a/media/libstagefright/omx/hal/1.0/impl/WGraphicBufferSource.h
+++ b/media/libstagefright/omx/hal/1.0/impl/WGraphicBufferSource.h
@@ -17,16 +17,17 @@
 #ifndef ANDROID_HARDWARE_MEDIA_OMX_V1_0_WGRAPHICBUFFERSOURCE_H
 #define ANDROID_HARDWARE_MEDIA_OMX_V1_0_WGRAPHICBUFFERSOURCE_H
 
-#include <android/hardware/media/omx/1.0/IGraphicBufferSource.h>
 #include <hidl/MQDescriptor.h>
 #include <hidl/Status.h>
 
-#include <frameworks/native/include/binder/Binder.h>
-#include <IOMX.h>
-#include <android/BnGraphicBufferSource.h>
-#include <android/hardware/media/omx/1.0/IOmxNode.h>
+#include <media/IOMX.h>
+#include <binder/Binder.h>
 
 #include <android/hardware/graphics/common/1.0/types.h>
+#include <android/hardware/media/omx/1.0/IOmxNode.h>
+#include <android/hardware/media/omx/1.0/IGraphicBufferSource.h>
+
+#include <android/BnGraphicBufferSource.h>
 
 namespace android {
 namespace hardware {
diff --git a/media/libstagefright/omx/hal/1.0/impl/WOmx.h b/media/libstagefright/omx/hal/1.0/impl/WOmx.h
index ab11c6a..3cb002e 100644
--- a/media/libstagefright/omx/hal/1.0/impl/WOmx.h
+++ b/media/libstagefright/omx/hal/1.0/impl/WOmx.h
@@ -17,11 +17,12 @@
 #ifndef ANDROID_HARDWARE_MEDIA_OMX_V1_0_WOMX_H
 #define ANDROID_HARDWARE_MEDIA_OMX_V1_0_WOMX_H
 
-#include <android/hardware/media/omx/1.0/IOmx.h>
 #include <hidl/MQDescriptor.h>
 #include <hidl/Status.h>
 
-#include <IOMX.h>
+#include "../../../../include/OMXNodeInstance.h"
+
+#include <android/hardware/media/omx/1.0/IOmx.h>
 
 namespace android {
 namespace hardware {
diff --git a/media/libstagefright/omx/hal/1.0/impl/WOmxBufferProducer.cpp b/media/libstagefright/omx/hal/1.0/impl/WOmxBufferProducer.cpp
index 3bd6c6e..b6b9a3b 100644
--- a/media/libstagefright/omx/hal/1.0/impl/WOmxBufferProducer.cpp
+++ b/media/libstagefright/omx/hal/1.0/impl/WOmxBufferProducer.cpp
@@ -14,8 +14,13 @@
  * limitations under the License.
  */
 
+#define LOG_TAG "WOmxBufferProducer-impl"
+
+#include <android-base/logging.h>
+
 #include "WOmxBufferProducer.h"
 #include "WOmxProducerListener.h"
+#include "Conversion.h"
 
 namespace android {
 namespace hardware {
@@ -62,23 +67,29 @@
             width, height,
             static_cast<::android::PixelFormat>(format), usage,
             getFrameTimestamps ? &outTimestamps : nullptr);
-
     hidl_handle tFence;
-    native_handle_t* nh;
-    if (!wrapAs(&tFence, &nh, *fence)) {
-        return ::android::hardware::Status::fromExceptionCode(
-                ::android::hardware::Status::EX_BAD_PARCELABLE,
-                String8("TWOmxBufferProducer::dequeueBuffer(): "
-                "Cannot wrap Fence in hidl_handle"));
-    }
     FrameEventHistoryDelta tOutTimestamps;
+
+    native_handle_t* nh = nullptr;
+    if ((fence == nullptr) || !wrapAs(&tFence, &nh, *fence)) {
+        LOG(ERROR) << "TWOmxBufferProducer::dequeueBuffer - "
+                "Invalid output fence";
+        _hidl_cb(toStatus(status),
+                 static_cast<int32_t>(slot),
+                 tFence,
+                 tOutTimestamps);
+        return Void();
+    }
     std::vector<std::vector<native_handle_t*> > nhAA;
     if (getFrameTimestamps && !wrapAs(&tOutTimestamps, &nhAA, outTimestamps)) {
+        LOG(ERROR) << "TWOmxBufferProducer::dequeueBuffer - "
+                "Invalid output timestamps";
+        _hidl_cb(toStatus(status),
+                 static_cast<int32_t>(slot),
+                 tFence,
+                 tOutTimestamps);
         native_handle_delete(nh);
-        return ::android::hardware::Status::fromExceptionCode(
-                ::android::hardware::Status::EX_BAD_PARCELABLE,
-                String8("TWOmxBufferProducer::dequeueBuffer(): "
-                "Cannot wrap Fence in hidl_handle"));
+        return Void();
     }
 
     _hidl_cb(toStatus(status),
@@ -89,9 +100,7 @@
     if (getFrameTimestamps) {
         for (auto& nhA : nhAA) {
             for (auto& handle : nhA) {
-                if (handle != nullptr) {
-                    native_handle_delete(handle);
-                }
+                native_handle_delete(handle);
             }
         }
     }
@@ -107,16 +116,22 @@
     sp<GraphicBuffer> outBuffer;
     sp<Fence> outFence;
     status_t status = mBase->detachNextBuffer(&outBuffer, &outFence);
-
     AnwBuffer tBuffer;
-    wrapAs(&tBuffer, *outBuffer);
     hidl_handle tFence;
-    native_handle_t* nh;
-    if (!wrapAs(&tFence, &nh, *outFence)) {
-        return ::android::hardware::Status::fromExceptionCode(
-                ::android::hardware::Status::EX_BAD_PARCELABLE,
-                String8("TWOmxBufferProducer::detachNextBuffer(): "
-                "Cannot wrap Fence in hidl_handle"));
+
+    if (outBuffer == nullptr) {
+        LOG(ERROR) << "TWOmxBufferProducer::detachNextBuffer - "
+                "Invalid output buffer";
+        _hidl_cb(toStatus(status), tBuffer, tFence);
+        return Void();
+    }
+    wrapAs(&tBuffer, *outBuffer);
+    native_handle_t* nh = nullptr;
+    if ((outFence != nullptr) && !wrapAs(&tFence, &nh, *outFence)) {
+        LOG(ERROR) << "TWOmxBufferProducer::detachNextBuffer - "
+                "Invalid output fence";
+        _hidl_cb(toStatus(status), tBuffer, tFence);
+        return Void();
     }
 
     _hidl_cb(toStatus(status), tBuffer, tFence);
@@ -130,10 +145,10 @@
     int outSlot;
     sp<GraphicBuffer> lBuffer = new GraphicBuffer();
     if (!convertTo(lBuffer.get(), buffer)) {
-        return ::android::hardware::Status::fromExceptionCode(
-                ::android::hardware::Status::EX_BAD_PARCELABLE,
-                String8("TWOmxBufferProducer::attachBuffer(): "
-                "Cannot convert AnwBuffer to GraphicBuffer"));
+        LOG(ERROR) << "TWOmxBufferProducer::attachBuffer - "
+                "Invalid input native window buffer";
+        _hidl_cb(toStatus(BAD_VALUE), -1);
+        return Void();
     }
     status_t status = mBase->attachBuffer(&outSlot, lBuffer);
 
@@ -144,38 +159,34 @@
 Return<void> TWOmxBufferProducer::queueBuffer(
         int32_t slot, const QueueBufferInput& input,
         queueBuffer_cb _hidl_cb) {
+    QueueBufferOutput tOutput;
     IGraphicBufferProducer::QueueBufferInput lInput(
             0, false, HAL_DATASPACE_UNKNOWN,
             ::android::Rect(0, 0, 1, 1),
             NATIVE_WINDOW_SCALING_MODE_FREEZE,
             0, ::android::Fence::NO_FENCE);
     if (!convertTo(&lInput, input)) {
-        return ::android::hardware::Status::fromExceptionCode(
-                ::android::hardware::Status::EX_BAD_PARCELABLE,
-                String8("TWOmxBufferProducer::queueBuffer(): "
-                "Cannot convert IOmxBufferProducer::QueueBufferInput "
-                "to IGraphicBufferProducer::QueueBufferInput"));
+        LOG(ERROR) << "TWOmxBufferProducer::queueBuffer - "
+                "Invalid input";
+        _hidl_cb(toStatus(BAD_VALUE), tOutput);
+        return Void();
     }
     IGraphicBufferProducer::QueueBufferOutput lOutput;
     status_t status = mBase->queueBuffer(
             static_cast<int>(slot), lInput, &lOutput);
 
-    QueueBufferOutput tOutput;
     std::vector<std::vector<native_handle_t*> > nhAA;
     if (!wrapAs(&tOutput, &nhAA, lOutput)) {
-        return ::android::hardware::Status::fromExceptionCode(
-                ::android::hardware::Status::EX_BAD_PARCELABLE,
-                String8("TWOmxBufferProducer::queueBuffer(): "
-                "Cannot wrap IGraphicBufferProducer::QueueBufferOutput "
-                "in IOmxBufferProducer::QueueBufferOutput"));
+        LOG(ERROR) << "TWOmxBufferProducer::queueBuffer - "
+                "Invalid output";
+        _hidl_cb(toStatus(BAD_VALUE), tOutput);
+        return Void();
     }
 
     _hidl_cb(toStatus(status), tOutput);
     for (auto& nhA : nhAA) {
         for (auto& nh : nhA) {
-            if (nh != nullptr) {
-                native_handle_delete(nh);
-            }
+            native_handle_delete(nh);
         }
     }
     return Void();
@@ -185,10 +196,9 @@
         int32_t slot, const hidl_handle& fence) {
     sp<Fence> lFence = new Fence();
     if (!convertTo(lFence.get(), fence)) {
-        return ::android::hardware::Status::fromExceptionCode(
-                ::android::hardware::Status::EX_BAD_PARCELABLE,
-                String8("TWOmxBufferProducer::cancelBuffer(): "
-                "Cannot convert hidl_handle to Fence"));
+        LOG(ERROR) << "TWOmxBufferProducer::cancelBuffer - "
+                "Invalid input fence";
+        return toStatus(BAD_VALUE);
     }
     return toStatus(mBase->cancelBuffer(static_cast<int>(slot), lFence));
 }
@@ -214,19 +224,16 @@
     QueueBufferOutput tOutput;
     std::vector<std::vector<native_handle_t*> > nhAA;
     if (!wrapAs(&tOutput, &nhAA, lOutput)) {
-        return ::android::hardware::Status::fromExceptionCode(
-                ::android::hardware::Status::EX_BAD_PARCELABLE,
-                String8("TWOmxBufferProducer::connect(): "
-                "Cannot wrap IGraphicBufferProducer::QueueBufferOutput "
-                "in IOmxBufferProducer::QueueBufferOutput"));
+        LOG(ERROR) << "TWOmxBufferProducer::connect - "
+                "Invalid output";
+        _hidl_cb(toStatus(status), tOutput);
+        return Void();
     }
 
     _hidl_cb(toStatus(status), tOutput);
     for (auto& nhA : nhAA) {
         for (auto& nh : nhA) {
-            if (nh != nullptr) {
-                native_handle_delete(nh);
-            }
+            native_handle_delete(nh);
         }
     }
     return Void();
@@ -287,14 +294,19 @@
             &lOutBuffer, &lOutFence, lOutTransformMatrix);
 
     AnwBuffer tOutBuffer;
-    wrapAs(&tOutBuffer, *lOutBuffer);
+    if (lOutBuffer != nullptr) {
+        wrapAs(&tOutBuffer, *lOutBuffer);
+    }
     hidl_handle tOutFence;
-    native_handle_t* nh;
-    if (!wrapAs(&tOutFence, &nh, *lOutFence)) {
-        return ::android::hardware::Status::fromExceptionCode(
-                ::android::hardware::Status::EX_BAD_PARCELABLE,
-                String8("TWOmxBufferProducer::getLastQueuedBuffer(): "
-                "Cannot wrap Fence in hidl_handle"));
+    native_handle_t* nh = nullptr;
+    if ((lOutFence == nullptr) || !wrapAs(&tOutFence, &nh, *lOutFence)) {
+        LOG(ERROR) << "TWOmxBufferProducer::getLastQueuedBuffer - "
+                "Invalid output fence";
+        _hidl_cb(toStatus(status),
+                tOutBuffer,
+                tOutFence,
+                hidl_array<float, 16>());
+        return Void();
     }
     hidl_array<float, 16> tOutTransformMatrix(lOutTransformMatrix);
 
@@ -311,19 +323,16 @@
     FrameEventHistoryDelta tDelta;
     std::vector<std::vector<native_handle_t*> > nhAA;
     if (!wrapAs(&tDelta, &nhAA, lDelta)) {
-        return ::android::hardware::Status::fromExceptionCode(
-                ::android::hardware::Status::EX_BAD_PARCELABLE,
-                String8("TWOmxBufferProducer::getFrameTimestamps(): "
-                "Cannot wrap ::android::FrameEventHistoryDelta "
-                "in FrameEventHistoryDelta"));
+        LOG(ERROR) << "TWOmxBufferProducer::getFrameTimestamps - "
+                "Invalid output frame timestamps";
+        _hidl_cb(tDelta);
+        return Void();
     }
 
     _hidl_cb(tDelta);
     for (auto& nhA : nhAA) {
         for (auto& nh : nhA) {
-            if (nh != nullptr) {
-                native_handle_delete(nh);
-            }
+            native_handle_delete(nh);
         }
     }
     return Void();
@@ -383,9 +392,13 @@
                 fnStatus = toStatusT(status);
                 *slot = tSlot;
                 if (!convertTo(fence->get(), tFence)) {
+                    LOG(ERROR) << "LWOmxBufferProducer::dequeueBuffer - "
+                            "Invalid output fence";
                     fnStatus = fnStatus == NO_ERROR ? BAD_VALUE : fnStatus;
                 }
                 if (outTimestamps && !convertTo(outTimestamps, tTs)) {
+                    LOG(ERROR) << "LWOmxBufferProducer::dequeueBuffer - "
+                            "Invalid output timestamps";
                     fnStatus = fnStatus == NO_ERROR ? BAD_VALUE : fnStatus;
                 }
             }));
@@ -408,9 +421,13 @@
                     hidl_handle const& tFence) {
                 fnStatus = toStatusT(status);
                 if (!convertTo(outFence->get(), tFence)) {
+                    LOG(ERROR) << "LWOmxBufferProducer::detachNextBuffer - "
+                            "Invalid output fence";
                     fnStatus = fnStatus == NO_ERROR ? BAD_VALUE : fnStatus;
                 }
                 if (!convertTo(outBuffer->get(), tBuffer)) {
+                    LOG(ERROR) << "LWOmxBufferProducer::detachNextBuffer - "
+                            "Invalid output buffer";
                     fnStatus = fnStatus == NO_ERROR ? BAD_VALUE : fnStatus;
                 }
             }));
@@ -437,6 +454,8 @@
     IOmxBufferProducer::QueueBufferInput tInput;
     native_handle_t* nh;
     if (!wrapAs(&tInput, &nh, input)) {
+        LOG(ERROR) << "LWOmxBufferProducer::queueBuffer - "
+                "Invalid input";
         return BAD_VALUE;
     }
     status_t fnStatus;
@@ -446,6 +465,8 @@
                     IOmxBufferProducer::QueueBufferOutput const& tOutput) {
                 fnStatus = toStatusT(status);
                 if (!convertTo(output, tOutput)) {
+                    LOG(ERROR) << "LWOmxBufferProducer::queueBuffer - "
+                            "Invalid output";
                     fnStatus = fnStatus == NO_ERROR ? BAD_VALUE : fnStatus;
                 }
             }));
@@ -455,8 +476,10 @@
 
 status_t LWOmxBufferProducer::cancelBuffer(int slot, const sp<Fence>& fence) {
     hidl_handle tFence;
-    native_handle_t* nh;
-    if (!wrapAs(&tFence, &nh, *fence)) {
+    native_handle_t* nh = nullptr;
+    if ((fence == nullptr) || !wrapAs(&tFence, &nh, *fence)) {
+        LOG(ERROR) << "LWOmxBufferProducer::cancelBuffer - "
+                "Invalid input fence";
         return BAD_VALUE;
     }
 
@@ -490,6 +513,8 @@
                     IOmxBufferProducer::QueueBufferOutput const& tOutput) {
                 fnStatus = toStatusT(status);
                 if (!convertTo(output, tOutput)) {
+                    LOG(ERROR) << "LWOmxBufferProducer::connect - "
+                            "Invalid output";
                     fnStatus = fnStatus == NO_ERROR ? BAD_VALUE : fnStatus;
                 }
             }));
@@ -554,10 +579,14 @@
                 fnStatus = toStatusT(status);
                 *outBuffer = new GraphicBuffer();
                 if (!convertTo(outBuffer->get(), buffer)) {
+                    LOG(ERROR) << "LWOmxBufferProducer::getLastQueuedBuffer - "
+                            "Invalid output buffer";
                     fnStatus = fnStatus == NO_ERROR ? BAD_VALUE : fnStatus;
                 }
                 *outFence = new Fence();
                 if (!convertTo(outFence->get(), fence)) {
+                    LOG(ERROR) << "LWOmxBufferProducer::getLastQueuedBuffer - "
+                            "Invalid output fence";
                     fnStatus = fnStatus == NO_ERROR ? BAD_VALUE : fnStatus;
                 }
                 std::copy(transformMatrix.data(),
diff --git a/media/libstagefright/omx/hal/1.0/impl/WOmxBufferProducer.h b/media/libstagefright/omx/hal/1.0/impl/WOmxBufferProducer.h
index 65b093c..8520160 100644
--- a/media/libstagefright/omx/hal/1.0/impl/WOmxBufferProducer.h
+++ b/media/libstagefright/omx/hal/1.0/impl/WOmxBufferProducer.h
@@ -17,13 +17,14 @@
 #ifndef ANDROID_HARDWARE_MEDIA_OMX_V1_0_WOMXBUFFERPRODUCER_H
 #define ANDROID_HARDWARE_MEDIA_OMX_V1_0_WOMXBUFFERPRODUCER_H
 
-#include <android/hardware/media/omx/1.0/IOmxBufferProducer.h>
-#include <binder/Binder.h>
 #include <hidl/MQDescriptor.h>
 #include <hidl/Status.h>
+
+#include <binder/Binder.h>
 #include <gui/IGraphicBufferProducer.h>
 #include <gui/IProducerListener.h>
-#include "Conversion.h"
+
+#include <android/hardware/media/omx/1.0/IOmxBufferProducer.h>
 
 namespace android {
 namespace hardware {
diff --git a/media/libstagefright/omx/hal/1.0/impl/WOmxBufferSource.cpp b/media/libstagefright/omx/hal/1.0/impl/WOmxBufferSource.cpp
index 97bcee0..803283a 100644
--- a/media/libstagefright/omx/hal/1.0/impl/WOmxBufferSource.cpp
+++ b/media/libstagefright/omx/hal/1.0/impl/WOmxBufferSource.cpp
@@ -14,10 +14,10 @@
  * limitations under the License.
  */
 
+#include <utils/String8.h>
+
 #include "WOmxBufferSource.h"
 #include "Conversion.h"
-#include <utils/String8.h>
-#include <cutils/native_handle.h>
 
 namespace android {
 namespace hardware {
@@ -95,8 +95,7 @@
         uint32_t buffer, hidl_handle const& fence) {
     OMXFenceParcelable fenceParcelable;
     if (!convertTo(&fenceParcelable, fence)) {
-      return ::android::hardware::Status::fromExceptionCode(
-              ::android::hardware::Status::EX_BAD_PARCELABLE);
+        return Void();
     }
     mBase->onInputBufferEmptied(int32_t(buffer), fenceParcelable);
     return Void();
diff --git a/media/libstagefright/omx/hal/1.0/impl/WOmxBufferSource.h b/media/libstagefright/omx/hal/1.0/impl/WOmxBufferSource.h
index 83bf46f..9b27796 100644
--- a/media/libstagefright/omx/hal/1.0/impl/WOmxBufferSource.h
+++ b/media/libstagefright/omx/hal/1.0/impl/WOmxBufferSource.h
@@ -17,13 +17,14 @@
 #ifndef ANDROID_HARDWARE_MEDIA_OMX_V1_0_WOMXBUFFERSOURCE_H
 #define ANDROID_HARDWARE_MEDIA_OMX_V1_0_WOMXBUFFERSOURCE_H
 
-#include <android/hardware/media/omx/1.0/IOmxBufferSource.h>
 #include <hidl/MQDescriptor.h>
 #include <hidl/Status.h>
 
-#include <frameworks/native/include/binder/Binder.h>
+#include <binder/Binder.h>
+#include <media/OMXFenceParcelable.h>
+
+#include <android/hardware/media/omx/1.0/IOmxBufferSource.h>
 #include <android/BnOMXBufferSource.h>
-#include <OMXFenceParcelable.h>
 
 namespace android {
 namespace hardware {
diff --git a/media/libstagefright/omx/hal/1.0/impl/WOmxNode.cpp b/media/libstagefright/omx/hal/1.0/impl/WOmxNode.cpp
index 26617aa..dc5c8e1 100644
--- a/media/libstagefright/omx/hal/1.0/impl/WOmxNode.cpp
+++ b/media/libstagefright/omx/hal/1.0/impl/WOmxNode.cpp
@@ -14,14 +14,12 @@
  * limitations under the License.
  */
 
-#include <IOMX.h>
-#include <OMXNodeInstance.h>
+#include <algorithm>
+
 #include "WOmxNode.h"
 #include "WOmxBufferSource.h"
 #include "Conversion.h"
 
-#include <algorithm>
-
 namespace android {
 namespace hardware {
 namespace media {
diff --git a/media/libstagefright/omx/hal/1.0/impl/WOmxNode.h b/media/libstagefright/omx/hal/1.0/impl/WOmxNode.h
index 12c2f04..75816ba 100644
--- a/media/libstagefright/omx/hal/1.0/impl/WOmxNode.h
+++ b/media/libstagefright/omx/hal/1.0/impl/WOmxNode.h
@@ -17,13 +17,16 @@
 #ifndef ANDROID_HARDWARE_MEDIA_OMX_V1_0_WOMXNODE_H
 #define ANDROID_HARDWARE_MEDIA_OMX_V1_0_WOMXNODE_H
 
-#include <android/hardware/media/omx/1.0/IOmxNode.h>
-#include <android/hardware/media/omx/1.0/IOmxObserver.h>
 #include <hidl/MQDescriptor.h>
 #include <hidl/Status.h>
 
 #include <utils/Errors.h>
 
+#include "../../../../include/OMXNodeInstance.h"
+
+#include <android/hardware/media/omx/1.0/IOmxNode.h>
+#include <android/hardware/media/omx/1.0/IOmxObserver.h>
+
 namespace android {
 namespace hardware {
 namespace media {
diff --git a/media/libstagefright/omx/hal/1.0/impl/WOmxObserver.cpp b/media/libstagefright/omx/hal/1.0/impl/WOmxObserver.cpp
index 433a8b8..354db29 100644
--- a/media/libstagefright/omx/hal/1.0/impl/WOmxObserver.cpp
+++ b/media/libstagefright/omx/hal/1.0/impl/WOmxObserver.cpp
@@ -15,13 +15,14 @@
  */
 
 #define LOG_TAG "WOmxObserver-impl"
-#include "WOmxObserver.h"
 
 #include <vector>
 
+#include <android-base/logging.h>
 #include <cutils/native_handle.h>
-#include <frameworks/native/include/binder/Binder.h>
+#include <binder/Binder.h>
 
+#include "WOmxObserver.h"
 #include "Conversion.h"
 
 namespace android {
@@ -46,7 +47,7 @@
     }
     auto transResult = mBase->onMessages(tMessages);
     if (!transResult.isOk()) {
-        ALOGE("LWOmxObserver::onMessages transaction failed");
+        LOG(ERROR) << "LWOmxObserver::onMessages - Transaction failed";
     }
     for (auto& handle : handles) {
         native_handle_close(handle);
diff --git a/media/libstagefright/omx/hal/1.0/impl/WOmxObserver.h b/media/libstagefright/omx/hal/1.0/impl/WOmxObserver.h
index cfe4281..7075513 100644
--- a/media/libstagefright/omx/hal/1.0/impl/WOmxObserver.h
+++ b/media/libstagefright/omx/hal/1.0/impl/WOmxObserver.h
@@ -17,12 +17,14 @@
 #ifndef ANDROID_HARDWARE_MEDIA_OMX_V1_0_WOMXOBSERVER_H
 #define ANDROID_HARDWARE_MEDIA_OMX_V1_0_WOMXOBSERVER_H
 
-#include <android/hardware/media/omx/1.0/IOmxObserver.h>
+#include <list>
+
 #include <hidl/MQDescriptor.h>
 #include <hidl/Status.h>
 
-#include <IOMX.h>
-#include <list>
+#include <media/IOMX.h>
+
+#include <android/hardware/media/omx/1.0/IOmxObserver.h>
 
 namespace android {
 namespace hardware {
diff --git a/media/libstagefright/omx/hal/1.0/impl/WOmxProducerListener.h b/media/libstagefright/omx/hal/1.0/impl/WOmxProducerListener.h
index 86656ca..e60032e 100644
--- a/media/libstagefright/omx/hal/1.0/impl/WOmxProducerListener.h
+++ b/media/libstagefright/omx/hal/1.0/impl/WOmxProducerListener.h
@@ -17,13 +17,14 @@
 #ifndef ANDROID_HARDWARE_MEDIA_OMX_V1_0_WOMXPRODUCERLISTENER_H
 #define ANDROID_HARDWARE_MEDIA_OMX_V1_0_WOMXPRODUCERLISTENER_H
 
-#include <android/hardware/media/omx/1.0/IOmxProducerListener.h>
 #include <hidl/MQDescriptor.h>
 #include <hidl/Status.h>
 
 #include <binder/IBinder.h>
 #include <gui/IProducerListener.h>
 
+#include <android/hardware/media/omx/1.0/IOmxProducerListener.h>
+
 namespace android {
 namespace hardware {
 namespace media {
diff --git a/media/libstagefright/omx/hal/1.0/utils/Android.mk b/media/libstagefright/omx/hal/1.0/utils/Android.mk
index 6930c87..c44ce25 100644
--- a/media/libstagefright/omx/hal/1.0/utils/Android.mk
+++ b/media/libstagefright/omx/hal/1.0/utils/Android.mk
@@ -25,18 +25,17 @@
     libcutils \
     libbinder \
     liblog \
+    libbase \
     android.hardware.media.omx@1.0 \
     android.hardware.graphics.common@1.0 \
     android.hardware.media@1.0 \
     android.hidl.base@1.0 \
 
 LOCAL_C_INCLUDES += \
-        $(TOP) \
-        $(TOP)/frameworks/av/include/media \
-        $(TOP)/frameworks/av/media/libstagefright/include \
-        $(TOP)/frameworks/av/media/libstagefright/omx \
-        $(TOP)/frameworks/native/include/media/hardware \
-        $(TOP)/frameworks/native/include/media/openmax \
+        $(TOP)/frameworks/av/include \
+        $(TOP)/frameworks/av/media/libstagefright \
         $(TOP)/frameworks/native/include \
+        $(TOP)/frameworks/native/include/media/openmax \
+        $(TOP)/frameworks/native/include/media/hardware \
 
 include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libstagefright/omx/hal/1.0/utils/Conversion.h b/media/libstagefright/omx/hal/1.0/utils/Conversion.h
index 5050687..375c7f9 100644
--- a/media/libstagefright/omx/hal/1.0/utils/Conversion.h
+++ b/media/libstagefright/omx/hal/1.0/utils/Conversion.h
@@ -17,29 +17,26 @@
 #ifndef ANDROID_HARDWARE_MEDIA_OMX_V1_0__CONVERSION_H
 #define ANDROID_HARDWARE_MEDIA_OMX_V1_0__CONVERSION_H
 
+#include <vector>
+#include <list>
+
+#include <unistd.h>
+
 #include <hidl/MQDescriptor.h>
 #include <hidl/Status.h>
 #include <hidlmemory/mapping.h>
-#include <android/hidl/memory/1.0/IMemory.h>
-
-#include <unistd.h>
-#include <vector>
-#include <list>
 
 #include <binder/Binder.h>
 #include <binder/Status.h>
 #include <ui/FenceTime.h>
-
-#include <OMXFenceParcelable.h>
+#include <media/OMXFenceParcelable.h>
 #include <cutils/native_handle.h>
 #include <gui/IGraphicBufferProducer.h>
 
-#include <IOMX.h>
+#include <media/OMXBuffer.h>
 #include <VideoAPI.h>
-#include <OMXBuffer.h>
-#include <android/IOMXBufferSource.h>
-#include <android/IGraphicBufferSource.h>
 
+#include <android/hidl/memory/1.0/IMemory.h>
 #include <android/hardware/media/omx/1.0/types.h>
 #include <android/hardware/media/omx/1.0/IOmx.h>
 #include <android/hardware/media/omx/1.0/IOmxNode.h>
@@ -49,6 +46,9 @@
 #include <android/hardware/media/omx/1.0/IOmxProducerListener.h>
 #include <android/hardware/media/omx/1.0/IGraphicBufferSource.h>
 
+#include <android/IGraphicBufferSource.h>
+#include <android/IOMXBufferSource.h>
+
 namespace android {
 namespace hardware {
 namespace media {
@@ -177,25 +177,6 @@
  */
 
 /**
- * \brief Convert `binder::Status` to `Return<void>`.
- *
- * \param[in] l The source `binder::Status`.
- * \return The corresponding `Return<void>`.
- */
-// convert: ::android::binder::Status -> Return<void>
-inline Return<void> toHardwareStatus(
-        ::android::binder::Status const& l) {
-    if (l.exceptionCode() == ::android::binder::Status::EX_SERVICE_SPECIFIC) {
-        return ::android::hardware::Status::fromServiceSpecificError(
-                l.serviceSpecificErrorCode(),
-                l.exceptionMessage());
-    }
-    return ::android::hardware::Status::fromExceptionCode(
-            l.exceptionCode(),
-            l.exceptionMessage());
-}
-
-/**
  * \brief Convert `Return<void>` to `binder::Status`.
  *
  * \param[in] t The source `Return<void>`.
diff --git a/media/libstagefright/omx/hal/1.0/utils/WGraphicBufferSource.cpp b/media/libstagefright/omx/hal/1.0/utils/WGraphicBufferSource.cpp
index afe8bc5..0ba6060 100644
--- a/media/libstagefright/omx/hal/1.0/utils/WGraphicBufferSource.cpp
+++ b/media/libstagefright/omx/hal/1.0/utils/WGraphicBufferSource.cpp
@@ -14,11 +14,12 @@
  * limitations under the License.
  */
 
-#include "WGraphicBufferSource.h"
-#include "Conversion.h"
-#include "WOmxNode.h"
 #include <stagefright/foundation/ColorUtils.h>
 
+#include "WGraphicBufferSource.h"
+#include "WOmxNode.h"
+#include "Conversion.h"
+
 namespace android {
 namespace hardware {
 namespace media {
@@ -95,7 +96,8 @@
     return Void();
 }
 
-Return<void> TWGraphicBufferSource::setSuspend(bool suspend, int64_t timeUs) {
+Return<void> TWGraphicBufferSource::setSuspend(
+        bool suspend, int64_t timeUs) {
     mBase->setSuspend(suspend, timeUs);
     return Void();
 }
@@ -123,7 +125,8 @@
 }
 
 Return<void> TWGraphicBufferSource::setStopTimeUs(int64_t stopTimeUs) {
-    return toHardwareStatus(mBase->setStopTimeUs(stopTimeUs));
+    mBase->setStopTimeUs(stopTimeUs);
+    return Void();
 }
 
 Return<void> TWGraphicBufferSource::setColorAspects(
diff --git a/media/libstagefright/omx/hal/1.0/utils/WGraphicBufferSource.h b/media/libstagefright/omx/hal/1.0/utils/WGraphicBufferSource.h
index 1b09cbd..1090d52 100644
--- a/media/libstagefright/omx/hal/1.0/utils/WGraphicBufferSource.h
+++ b/media/libstagefright/omx/hal/1.0/utils/WGraphicBufferSource.h
@@ -17,16 +17,17 @@
 #ifndef ANDROID_HARDWARE_MEDIA_OMX_V1_0_WGRAPHICBUFFERSOURCE_H
 #define ANDROID_HARDWARE_MEDIA_OMX_V1_0_WGRAPHICBUFFERSOURCE_H
 
-#include <android/hardware/media/omx/1.0/IGraphicBufferSource.h>
 #include <hidl/MQDescriptor.h>
 #include <hidl/Status.h>
 
-#include <frameworks/native/include/binder/Binder.h>
-#include <IOMX.h>
-#include <android/BnGraphicBufferSource.h>
-#include <android/hardware/media/omx/1.0/IOmxNode.h>
+#include <media/IOMX.h>
+#include <binder/Binder.h>
 
 #include <android/hardware/graphics/common/1.0/types.h>
+#include <android/hardware/media/omx/1.0/IOmxNode.h>
+#include <android/hardware/media/omx/1.0/IGraphicBufferSource.h>
+
+#include <android/BnGraphicBufferSource.h>
 
 namespace android {
 namespace hardware {
diff --git a/media/libstagefright/omx/hal/1.0/utils/WOmx.h b/media/libstagefright/omx/hal/1.0/utils/WOmx.h
index 73adc55..7860f46 100644
--- a/media/libstagefright/omx/hal/1.0/utils/WOmx.h
+++ b/media/libstagefright/omx/hal/1.0/utils/WOmx.h
@@ -17,11 +17,12 @@
 #ifndef ANDROID_HARDWARE_MEDIA_OMX_V1_0_WOMX_H
 #define ANDROID_HARDWARE_MEDIA_OMX_V1_0_WOMX_H
 
-#include <android/hardware/media/omx/1.0/IOmx.h>
 #include <hidl/MQDescriptor.h>
 #include <hidl/Status.h>
 
-#include <IOMX.h>
+#include "../../../../include/OMXNodeInstance.h"
+
+#include <android/hardware/media/omx/1.0/IOmx.h>
 
 namespace android {
 namespace hardware {
diff --git a/media/libstagefright/omx/hal/1.0/utils/WOmxBufferProducer.cpp b/media/libstagefright/omx/hal/1.0/utils/WOmxBufferProducer.cpp
index cfb0cce..e9a93b9 100644
--- a/media/libstagefright/omx/hal/1.0/utils/WOmxBufferProducer.cpp
+++ b/media/libstagefright/omx/hal/1.0/utils/WOmxBufferProducer.cpp
@@ -14,8 +14,13 @@
  * limitations under the License.
  */
 
+#define LOG_TAG "WOmxBufferProducer-utils"
+
+#include <android-base/logging.h>
+
 #include "WOmxBufferProducer.h"
 #include "WOmxProducerListener.h"
+#include "Conversion.h"
 
 namespace android {
 namespace hardware {
@@ -62,23 +67,29 @@
             width, height,
             static_cast<::android::PixelFormat>(format), usage,
             getFrameTimestamps ? &outTimestamps : nullptr);
-
     hidl_handle tFence;
-    native_handle_t* nh;
-    if (!wrapAs(&tFence, &nh, *fence)) {
-        return ::android::hardware::Status::fromExceptionCode(
-                ::android::hardware::Status::EX_BAD_PARCELABLE,
-                String8("TWOmxBufferProducer::dequeueBuffer(): "
-                "Cannot wrap Fence in hidl_handle"));
-    }
     FrameEventHistoryDelta tOutTimestamps;
+
+    native_handle_t* nh = nullptr;
+    if ((fence == nullptr) || !wrapAs(&tFence, &nh, *fence)) {
+        LOG(ERROR) << "TWOmxBufferProducer::dequeueBuffer - "
+                "Invalid output fence";
+        _hidl_cb(toStatus(status),
+                 static_cast<int32_t>(slot),
+                 tFence,
+                 tOutTimestamps);
+        return Void();
+    }
     std::vector<std::vector<native_handle_t*> > nhAA;
     if (getFrameTimestamps && !wrapAs(&tOutTimestamps, &nhAA, outTimestamps)) {
+        LOG(ERROR) << "TWOmxBufferProducer::dequeueBuffer - "
+                "Invalid output timestamps";
+        _hidl_cb(toStatus(status),
+                 static_cast<int32_t>(slot),
+                 tFence,
+                 tOutTimestamps);
         native_handle_delete(nh);
-        return ::android::hardware::Status::fromExceptionCode(
-                ::android::hardware::Status::EX_BAD_PARCELABLE,
-                String8("TWOmxBufferProducer::dequeueBuffer(): "
-                "Cannot wrap Fence in hidl_handle"));
+        return Void();
     }
 
     _hidl_cb(toStatus(status),
@@ -89,9 +100,7 @@
     if (getFrameTimestamps) {
         for (auto& nhA : nhAA) {
             for (auto& handle : nhA) {
-                if (handle != nullptr) {
-                    native_handle_delete(handle);
-                }
+                native_handle_delete(handle);
             }
         }
     }
@@ -107,16 +116,22 @@
     sp<GraphicBuffer> outBuffer;
     sp<Fence> outFence;
     status_t status = mBase->detachNextBuffer(&outBuffer, &outFence);
-
     AnwBuffer tBuffer;
-    wrapAs(&tBuffer, *outBuffer);
     hidl_handle tFence;
-    native_handle_t* nh;
-    if (!wrapAs(&tFence, &nh, *outFence)) {
-        return ::android::hardware::Status::fromExceptionCode(
-                ::android::hardware::Status::EX_BAD_PARCELABLE,
-                String8("TWOmxBufferProducer::detachNextBuffer(): "
-                "Cannot wrap Fence in hidl_handle"));
+
+    if (outBuffer == nullptr) {
+        LOG(ERROR) << "TWOmxBufferProducer::detachNextBuffer - "
+                "Invalid output buffer";
+        _hidl_cb(toStatus(status), tBuffer, tFence);
+        return Void();
+    }
+    wrapAs(&tBuffer, *outBuffer);
+    native_handle_t* nh = nullptr;
+    if ((outFence != nullptr) && !wrapAs(&tFence, &nh, *outFence)) {
+        LOG(ERROR) << "TWOmxBufferProducer::detachNextBuffer - "
+                "Invalid output fence";
+        _hidl_cb(toStatus(status), tBuffer, tFence);
+        return Void();
     }
 
     _hidl_cb(toStatus(status), tBuffer, tFence);
@@ -130,10 +145,10 @@
     int outSlot;
     sp<GraphicBuffer> lBuffer = new GraphicBuffer();
     if (!convertTo(lBuffer.get(), buffer)) {
-        return ::android::hardware::Status::fromExceptionCode(
-                ::android::hardware::Status::EX_BAD_PARCELABLE,
-                String8("TWOmxBufferProducer::attachBuffer(): "
-                "Cannot convert AnwBuffer to GraphicBuffer"));
+        LOG(ERROR) << "TWOmxBufferProducer::attachBuffer - "
+                "Invalid input native window buffer";
+        _hidl_cb(toStatus(BAD_VALUE), -1);
+        return Void();
     }
     status_t status = mBase->attachBuffer(&outSlot, lBuffer);
 
@@ -144,38 +159,34 @@
 Return<void> TWOmxBufferProducer::queueBuffer(
         int32_t slot, const QueueBufferInput& input,
         queueBuffer_cb _hidl_cb) {
+    QueueBufferOutput tOutput;
     IGraphicBufferProducer::QueueBufferInput lInput(
             0, false, HAL_DATASPACE_UNKNOWN,
             ::android::Rect(0, 0, 1, 1),
             NATIVE_WINDOW_SCALING_MODE_FREEZE,
             0, ::android::Fence::NO_FENCE);
     if (!convertTo(&lInput, input)) {
-        return ::android::hardware::Status::fromExceptionCode(
-                ::android::hardware::Status::EX_BAD_PARCELABLE,
-                String8("TWOmxBufferProducer::queueBuffer(): "
-                "Cannot convert IOmxBufferProducer::QueueBufferInput "
-                "to IGraphicBufferProducer::QueueBufferInput"));
+        LOG(ERROR) << "TWOmxBufferProducer::queueBuffer - "
+                "Invalid input";
+        _hidl_cb(toStatus(BAD_VALUE), tOutput);
+        return Void();
     }
     IGraphicBufferProducer::QueueBufferOutput lOutput;
     status_t status = mBase->queueBuffer(
             static_cast<int>(slot), lInput, &lOutput);
 
-    QueueBufferOutput tOutput;
     std::vector<std::vector<native_handle_t*> > nhAA;
     if (!wrapAs(&tOutput, &nhAA, lOutput)) {
-        return ::android::hardware::Status::fromExceptionCode(
-                ::android::hardware::Status::EX_BAD_PARCELABLE,
-                String8("TWOmxBufferProducer::queueBuffer(): "
-                "Cannot wrap IGraphicBufferProducer::QueueBufferOutput "
-                "in IOmxBufferProducer::QueueBufferOutput"));
+        LOG(ERROR) << "TWOmxBufferProducer::queueBuffer - "
+                "Invalid output";
+        _hidl_cb(toStatus(BAD_VALUE), tOutput);
+        return Void();
     }
 
     _hidl_cb(toStatus(status), tOutput);
     for (auto& nhA : nhAA) {
         for (auto& nh : nhA) {
-            if (nh != nullptr) {
-                native_handle_delete(nh);
-            }
+            native_handle_delete(nh);
         }
     }
     return Void();
@@ -185,10 +196,9 @@
         int32_t slot, const hidl_handle& fence) {
     sp<Fence> lFence = new Fence();
     if (!convertTo(lFence.get(), fence)) {
-        return ::android::hardware::Status::fromExceptionCode(
-                ::android::hardware::Status::EX_BAD_PARCELABLE,
-                String8("TWOmxBufferProducer::cancelBuffer(): "
-                "Cannot convert hidl_handle to Fence"));
+        LOG(ERROR) << "TWOmxBufferProducer::cancelBuffer - "
+                "Invalid input fence";
+        return toStatus(BAD_VALUE);
     }
     return toStatus(mBase->cancelBuffer(static_cast<int>(slot), lFence));
 }
@@ -214,19 +224,16 @@
     QueueBufferOutput tOutput;
     std::vector<std::vector<native_handle_t*> > nhAA;
     if (!wrapAs(&tOutput, &nhAA, lOutput)) {
-        return ::android::hardware::Status::fromExceptionCode(
-                ::android::hardware::Status::EX_BAD_PARCELABLE,
-                String8("TWOmxBufferProducer::connect(): "
-                "Cannot wrap IGraphicBufferProducer::QueueBufferOutput "
-                "in IOmxBufferProducer::QueueBufferOutput"));
+        LOG(ERROR) << "TWOmxBufferProducer::connect - "
+                "Invalid output";
+        _hidl_cb(toStatus(status), tOutput);
+        return Void();
     }
 
     _hidl_cb(toStatus(status), tOutput);
     for (auto& nhA : nhAA) {
         for (auto& nh : nhA) {
-            if (nh != nullptr) {
-                native_handle_delete(nh);
-            }
+            native_handle_delete(nh);
         }
     }
     return Void();
@@ -287,14 +294,19 @@
             &lOutBuffer, &lOutFence, lOutTransformMatrix);
 
     AnwBuffer tOutBuffer;
-    wrapAs(&tOutBuffer, *lOutBuffer);
+    if (lOutBuffer != nullptr) {
+        wrapAs(&tOutBuffer, *lOutBuffer);
+    }
     hidl_handle tOutFence;
-    native_handle_t* nh;
-    if (!wrapAs(&tOutFence, &nh, *lOutFence)) {
-        return ::android::hardware::Status::fromExceptionCode(
-                ::android::hardware::Status::EX_BAD_PARCELABLE,
-                String8("TWOmxBufferProducer::getLastQueuedBuffer(): "
-                "Cannot wrap Fence in hidl_handle"));
+    native_handle_t* nh = nullptr;
+    if ((lOutFence == nullptr) || !wrapAs(&tOutFence, &nh, *lOutFence)) {
+        LOG(ERROR) << "TWOmxBufferProducer::getLastQueuedBuffer - "
+                "Invalid output fence";
+        _hidl_cb(toStatus(status),
+                tOutBuffer,
+                tOutFence,
+                hidl_array<float, 16>());
+        return Void();
     }
     hidl_array<float, 16> tOutTransformMatrix(lOutTransformMatrix);
 
@@ -311,19 +323,16 @@
     FrameEventHistoryDelta tDelta;
     std::vector<std::vector<native_handle_t*> > nhAA;
     if (!wrapAs(&tDelta, &nhAA, lDelta)) {
-        return ::android::hardware::Status::fromExceptionCode(
-                ::android::hardware::Status::EX_BAD_PARCELABLE,
-                String8("TWOmxBufferProducer::getFrameTimestamps(): "
-                "Cannot wrap ::android::FrameEventHistoryDelta "
-                "in FrameEventHistoryDelta"));
+        LOG(ERROR) << "TWOmxBufferProducer::getFrameTimestamps - "
+                "Invalid output frame timestamps";
+        _hidl_cb(tDelta);
+        return Void();
     }
 
     _hidl_cb(tDelta);
     for (auto& nhA : nhAA) {
         for (auto& nh : nhA) {
-            if (nh != nullptr) {
-                native_handle_delete(nh);
-            }
+            native_handle_delete(nh);
         }
     }
     return Void();
@@ -383,9 +392,13 @@
                 fnStatus = toStatusT(status);
                 *slot = tSlot;
                 if (!convertTo(fence->get(), tFence)) {
+                    LOG(ERROR) << "LWOmxBufferProducer::dequeueBuffer - "
+                            "Invalid output fence";
                     fnStatus = fnStatus == NO_ERROR ? BAD_VALUE : fnStatus;
                 }
                 if (outTimestamps && !convertTo(outTimestamps, tTs)) {
+                    LOG(ERROR) << "LWOmxBufferProducer::dequeueBuffer - "
+                            "Invalid output timestamps";
                     fnStatus = fnStatus == NO_ERROR ? BAD_VALUE : fnStatus;
                 }
             }));
@@ -408,9 +421,13 @@
                     hidl_handle const& tFence) {
                 fnStatus = toStatusT(status);
                 if (!convertTo(outFence->get(), tFence)) {
+                    LOG(ERROR) << "LWOmxBufferProducer::detachNextBuffer - "
+                            "Invalid output fence";
                     fnStatus = fnStatus == NO_ERROR ? BAD_VALUE : fnStatus;
                 }
                 if (!convertTo(outBuffer->get(), tBuffer)) {
+                    LOG(ERROR) << "LWOmxBufferProducer::detachNextBuffer - "
+                            "Invalid output buffer";
                     fnStatus = fnStatus == NO_ERROR ? BAD_VALUE : fnStatus;
                 }
             }));
@@ -437,6 +454,8 @@
     IOmxBufferProducer::QueueBufferInput tInput;
     native_handle_t* nh;
     if (!wrapAs(&tInput, &nh, input)) {
+        LOG(ERROR) << "LWOmxBufferProducer::queueBuffer - "
+                "Invalid input";
         return BAD_VALUE;
     }
     status_t fnStatus;
@@ -446,6 +465,8 @@
                     IOmxBufferProducer::QueueBufferOutput const& tOutput) {
                 fnStatus = toStatusT(status);
                 if (!convertTo(output, tOutput)) {
+                    LOG(ERROR) << "LWOmxBufferProducer::queueBuffer - "
+                            "Invalid output";
                     fnStatus = fnStatus == NO_ERROR ? BAD_VALUE : fnStatus;
                 }
             }));
@@ -455,8 +476,10 @@
 
 status_t LWOmxBufferProducer::cancelBuffer(int slot, const sp<Fence>& fence) {
     hidl_handle tFence;
-    native_handle_t* nh;
-    if (!wrapAs(&tFence, &nh, *fence)) {
+    native_handle_t* nh = nullptr;
+    if ((fence == nullptr) || !wrapAs(&tFence, &nh, *fence)) {
+        LOG(ERROR) << "LWOmxBufferProducer::cancelBuffer - "
+                "Invalid input fence";
         return BAD_VALUE;
     }
 
@@ -490,6 +513,8 @@
                     IOmxBufferProducer::QueueBufferOutput const& tOutput) {
                 fnStatus = toStatusT(status);
                 if (!convertTo(output, tOutput)) {
+                    LOG(ERROR) << "LWOmxBufferProducer::connect - "
+                            "Invalid output";
                     fnStatus = fnStatus == NO_ERROR ? BAD_VALUE : fnStatus;
                 }
             }));
@@ -554,10 +579,14 @@
                 fnStatus = toStatusT(status);
                 *outBuffer = new GraphicBuffer();
                 if (!convertTo(outBuffer->get(), buffer)) {
+                    LOG(ERROR) << "LWOmxBufferProducer::getLastQueuedBuffer - "
+                            "Invalid output buffer";
                     fnStatus = fnStatus == NO_ERROR ? BAD_VALUE : fnStatus;
                 }
                 *outFence = new Fence();
                 if (!convertTo(outFence->get(), fence)) {
+                    LOG(ERROR) << "LWOmxBufferProducer::getLastQueuedBuffer - "
+                            "Invalid output fence";
                     fnStatus = fnStatus == NO_ERROR ? BAD_VALUE : fnStatus;
                 }
                 std::copy(transformMatrix.data(),
diff --git a/media/libstagefright/omx/hal/1.0/utils/WOmxBufferProducer.h b/media/libstagefright/omx/hal/1.0/utils/WOmxBufferProducer.h
index a5d2961..54b9078 100644
--- a/media/libstagefright/omx/hal/1.0/utils/WOmxBufferProducer.h
+++ b/media/libstagefright/omx/hal/1.0/utils/WOmxBufferProducer.h
@@ -17,13 +17,14 @@
 #ifndef ANDROID_HARDWARE_MEDIA_OMX_V1_0_WOMXBUFFERPRODUCER_H
 #define ANDROID_HARDWARE_MEDIA_OMX_V1_0_WOMXBUFFERPRODUCER_H
 
-#include <android/hardware/media/omx/1.0/IOmxBufferProducer.h>
-#include <binder/Binder.h>
 #include <hidl/MQDescriptor.h>
 #include <hidl/Status.h>
+
+#include <binder/Binder.h>
 #include <gui/IGraphicBufferProducer.h>
 #include <gui/IProducerListener.h>
-#include "Conversion.h"
+
+#include <android/hardware/media/omx/1.0/IOmxBufferProducer.h>
 
 namespace android {
 namespace hardware {
diff --git a/media/libstagefright/omx/hal/1.0/utils/WOmxBufferSource.cpp b/media/libstagefright/omx/hal/1.0/utils/WOmxBufferSource.cpp
index f3f5b9d..fe565e6 100644
--- a/media/libstagefright/omx/hal/1.0/utils/WOmxBufferSource.cpp
+++ b/media/libstagefright/omx/hal/1.0/utils/WOmxBufferSource.cpp
@@ -14,10 +14,10 @@
  * limitations under the License.
  */
 
+#include <utils/String8.h>
+
 #include "WOmxBufferSource.h"
 #include "Conversion.h"
-#include <utils/String8.h>
-#include <cutils/native_handle.h>
 
 namespace android {
 namespace hardware {
@@ -95,8 +95,7 @@
         uint32_t buffer, hidl_handle const& fence) {
     OMXFenceParcelable fenceParcelable;
     if (!convertTo(&fenceParcelable, fence)) {
-      return ::android::hardware::Status::fromExceptionCode(
-              ::android::hardware::Status::EX_BAD_PARCELABLE);
+        return Void();
     }
     mBase->onInputBufferEmptied(int32_t(buffer), fenceParcelable);
     return Void();
diff --git a/media/libstagefright/omx/hal/1.0/utils/WOmxBufferSource.h b/media/libstagefright/omx/hal/1.0/utils/WOmxBufferSource.h
index 1214300..086f648 100644
--- a/media/libstagefright/omx/hal/1.0/utils/WOmxBufferSource.h
+++ b/media/libstagefright/omx/hal/1.0/utils/WOmxBufferSource.h
@@ -17,13 +17,14 @@
 #ifndef ANDROID_HARDWARE_MEDIA_OMX_V1_0_WOMXBUFFERSOURCE_H
 #define ANDROID_HARDWARE_MEDIA_OMX_V1_0_WOMXBUFFERSOURCE_H
 
-#include <android/hardware/media/omx/1.0/IOmxBufferSource.h>
 #include <hidl/MQDescriptor.h>
 #include <hidl/Status.h>
 
-#include <frameworks/native/include/binder/Binder.h>
+#include <binder/Binder.h>
+#include <media/OMXFenceParcelable.h>
+
+#include <android/hardware/media/omx/1.0/IOmxBufferSource.h>
 #include <android/BnOMXBufferSource.h>
-#include <OMXFenceParcelable.h>
 
 namespace android {
 namespace hardware {
diff --git a/media/libstagefright/omx/hal/1.0/utils/WOmxNode.cpp b/media/libstagefright/omx/hal/1.0/utils/WOmxNode.cpp
index 3bb7a99..df191c7 100644
--- a/media/libstagefright/omx/hal/1.0/utils/WOmxNode.cpp
+++ b/media/libstagefright/omx/hal/1.0/utils/WOmxNode.cpp
@@ -14,14 +14,12 @@
  * limitations under the License.
  */
 
-#include <IOMX.h>
-#include <OMXNodeInstance.h>
+#include <algorithm>
+
 #include "WOmxNode.h"
 #include "WOmxBufferSource.h"
 #include "Conversion.h"
 
-#include <algorithm>
-
 namespace android {
 namespace hardware {
 namespace media {
diff --git a/media/libstagefright/omx/hal/1.0/utils/WOmxNode.h b/media/libstagefright/omx/hal/1.0/utils/WOmxNode.h
index 9c4bb4a..46dfb49 100644
--- a/media/libstagefright/omx/hal/1.0/utils/WOmxNode.h
+++ b/media/libstagefright/omx/hal/1.0/utils/WOmxNode.h
@@ -17,13 +17,16 @@
 #ifndef ANDROID_HARDWARE_MEDIA_OMX_V1_0_WOMXNODE_H
 #define ANDROID_HARDWARE_MEDIA_OMX_V1_0_WOMXNODE_H
 
-#include <android/hardware/media/omx/1.0/IOmxNode.h>
-#include <android/hardware/media/omx/1.0/IOmxObserver.h>
 #include <hidl/MQDescriptor.h>
 #include <hidl/Status.h>
 
 #include <utils/Errors.h>
 
+#include "../../../../include/OMXNodeInstance.h"
+
+#include <android/hardware/media/omx/1.0/IOmxNode.h>
+#include <android/hardware/media/omx/1.0/IOmxObserver.h>
+
 namespace android {
 namespace hardware {
 namespace media {
diff --git a/media/libstagefright/omx/hal/1.0/utils/WOmxObserver.cpp b/media/libstagefright/omx/hal/1.0/utils/WOmxObserver.cpp
index bab6a09..05ec37e 100644
--- a/media/libstagefright/omx/hal/1.0/utils/WOmxObserver.cpp
+++ b/media/libstagefright/omx/hal/1.0/utils/WOmxObserver.cpp
@@ -15,13 +15,14 @@
  */
 
 #define LOG_TAG "WOmxObserver-utils"
-#include "WOmxObserver.h"
 
 #include <vector>
 
+#include <android-base/logging.h>
 #include <cutils/native_handle.h>
-#include <frameworks/native/include/binder/Binder.h>
+#include <binder/Binder.h>
 
+#include "WOmxObserver.h"
 #include "Conversion.h"
 
 namespace android {
@@ -46,7 +47,7 @@
     }
     auto transResult = mBase->onMessages(tMessages);
     if (!transResult.isOk()) {
-        ALOGE("LWOmxObserver::onMessages transaction failed");
+        LOG(ERROR) << "LWOmxObserver::onMessages - Transaction failed";
     }
     for (auto& handle : handles) {
         native_handle_close(handle);
diff --git a/media/libstagefright/omx/hal/1.0/utils/WOmxObserver.h b/media/libstagefright/omx/hal/1.0/utils/WOmxObserver.h
index b9eb412..d442218 100644
--- a/media/libstagefright/omx/hal/1.0/utils/WOmxObserver.h
+++ b/media/libstagefright/omx/hal/1.0/utils/WOmxObserver.h
@@ -17,12 +17,14 @@
 #ifndef ANDROID_HARDWARE_MEDIA_OMX_V1_0_WOMXOBSERVER_H
 #define ANDROID_HARDWARE_MEDIA_OMX_V1_0_WOMXOBSERVER_H
 
-#include <android/hardware/media/omx/1.0/IOmxObserver.h>
+#include <list>
+
 #include <hidl/MQDescriptor.h>
 #include <hidl/Status.h>
 
-#include <IOMX.h>
-#include <list>
+#include <media/IOMX.h>
+
+#include <android/hardware/media/omx/1.0/IOmxObserver.h>
 
 namespace android {
 namespace hardware {
diff --git a/media/libstagefright/omx/hal/1.0/utils/WOmxProducerListener.h b/media/libstagefright/omx/hal/1.0/utils/WOmxProducerListener.h
index 2be077b..7d20887 100644
--- a/media/libstagefright/omx/hal/1.0/utils/WOmxProducerListener.h
+++ b/media/libstagefright/omx/hal/1.0/utils/WOmxProducerListener.h
@@ -17,13 +17,14 @@
 #ifndef ANDROID_HARDWARE_MEDIA_OMX_V1_0_WOMXPRODUCERLISTENER_H
 #define ANDROID_HARDWARE_MEDIA_OMX_V1_0_WOMXPRODUCERLISTENER_H
 
-#include <android/hardware/media/omx/1.0/IOmxProducerListener.h>
 #include <hidl/MQDescriptor.h>
 #include <hidl/Status.h>
 
 #include <binder/IBinder.h>
 #include <gui/IProducerListener.h>
 
+#include <android/hardware/media/omx/1.0/IOmxProducerListener.h>
+
 namespace android {
 namespace hardware {
 namespace media {
diff --git a/media/libstagefright/omx/tests/Android.mk b/media/libstagefright/omx/tests/Android.mk
index 08deaab..6d0f189 100644
--- a/media/libstagefright/omx/tests/Android.mk
+++ b/media/libstagefright/omx/tests/Android.mk
@@ -14,6 +14,7 @@
         libcutils \
         libhidlbase \
         libhidlmemory \
+        android.hidl.allocator@1.0 \
         android.hidl.memory@1.0 \
         android.hardware.media.omx@1.0 \
         android.hardware.media.omx@1.0-utils
diff --git a/media/libstagefright/omx/tests/OMXHarness.h b/media/libstagefright/omx/tests/OMXHarness.h
index 94a37da..4fc0f79 100644
--- a/media/libstagefright/omx/tests/OMXHarness.h
+++ b/media/libstagefright/omx/tests/OMXHarness.h
@@ -79,7 +79,7 @@
     virtual ~Harness();
 
 private:
-    typedef hidl::memory::V1_0::IAllocator IAllocator;
+    typedef hidl::allocator::V1_0::IAllocator IAllocator;
 
     friend struct NodeReaper;
     struct CodecObserver;
diff --git a/media/mtp/MtpFfsHandle.cpp b/media/mtp/MtpFfsHandle.cpp
index 58d2bb8..35dd10f 100644
--- a/media/mtp/MtpFfsHandle.cpp
+++ b/media/mtp/MtpFfsHandle.cpp
@@ -205,13 +205,13 @@
 const struct usb_ss_ep_comp_descriptor ss_sink_comp = {
     .bLength = sizeof(ss_sink_comp),
     .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
-    .bMaxBurst = 2,
+    .bMaxBurst = 6,
 };
 
 const struct usb_ss_ep_comp_descriptor ss_source_comp = {
     .bLength = sizeof(ss_source_comp),
     .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
-    .bMaxBurst = 2,
+    .bMaxBurst = 6,
 };
 
 const struct usb_ss_ep_comp_descriptor ss_intr_comp = {
diff --git a/services/mediacodec/Android.mk b/services/mediacodec/Android.mk
index a87c71c..a428c75 100644
--- a/services/mediacodec/Android.mk
+++ b/services/mediacodec/Android.mk
@@ -34,9 +34,12 @@
     libcutils \
     libhwbinder \
     libhidltransport \
-    android.hardware.media.omx@1.0
+    android.hardware.media.omx@1.0 \
+    android.hardware.media.omx@1.0-impl \
+    android.hidl.memory@1.0
 LOCAL_C_INCLUDES := \
     $(TOP)/frameworks/av/media/libstagefright \
+    $(TOP)/frameworks/av/media/libstagefright/include \
     $(TOP)/frameworks/native/include/media/openmax
 LOCAL_MODULE := mediacodec
 LOCAL_32_BIT_ONLY := true
diff --git a/services/mediacodec/main_codecservice.cpp b/services/mediacodec/main_codecservice.cpp
index 983bbba..688c651 100644
--- a/services/mediacodec/main_codecservice.cpp
+++ b/services/mediacodec/main_codecservice.cpp
@@ -33,6 +33,7 @@
 
 #include <android/hardware/media/omx/1.0/IOmx.h>
 #include <hidl/HidlTransportSupport.h>
+#include <omx/hal/1.0/impl/Omx.h>
 
 using namespace android;
 
@@ -54,10 +55,10 @@
     if ((trebleOmx == 1) || ((trebleOmx == -1) &&
             property_get_bool("persist.hal.binderization", 0))) {
         using namespace ::android::hardware::media::omx::V1_0;
-        sp<IOmx> omx = IOmx::getService(true);
+        sp<IOmx> omx = new implementation::Omx();
         if (omx == nullptr) {
             LOG(ERROR) << "Cannot create a Treble IOmx service.";
-        } else if (omx->registerAsService("default") != OK) {
+        } else if (omx->registerAsService() != OK) {
             LOG(ERROR) << "Cannot register a Treble IOmx service.";
         } else {
             LOG(INFO) << "Treble IOmx service created.";
diff --git a/services/mediadrm/Android.mk b/services/mediadrm/Android.mk
index e72236d..87fddd4 100644
--- a/services/mediadrm/Android.mk
+++ b/services/mediadrm/Android.mk
@@ -17,6 +17,7 @@
 include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES:= \
+    MediaCasService.cpp \
     MediaDrmService.cpp \
     main_mediadrmserver.cpp
 
diff --git a/services/mediadrm/FactoryLoader.h b/services/mediadrm/FactoryLoader.h
new file mode 100644
index 0000000..1e03e9b
--- /dev/null
+++ b/services/mediadrm/FactoryLoader.h
@@ -0,0 +1,220 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MEDIA_CAS_LOADER_H_
+#define MEDIA_CAS_LOADER_H_
+
+#include <dirent.h>
+#include <dlfcn.h>
+#include <media/SharedLibrary.h>
+#include <utils/KeyedVector.h>
+#include <utils/Mutex.h>
+
+namespace android {
+using namespace std;
+using namespace media;
+using namespace MediaCas;
+
+template <class T>
+class FactoryLoader {
+public:
+    FactoryLoader(const char *name) :
+        mFactory(NULL), mCreateFactoryFuncName(name) {}
+
+    virtual ~FactoryLoader() { closeFactory(); }
+
+    bool findFactoryForScheme(
+            int32_t CA_system_id,
+            sp<SharedLibrary> *library = NULL,
+            T** factory = NULL);
+
+    bool enumeratePlugins(vector<ParcelableCasPluginDescriptor>* results);
+
+private:
+    typedef T*(*CreateFactoryFunc)();
+
+    Mutex mMapLock;
+    T* mFactory;
+    const char *mCreateFactoryFuncName;
+    sp<SharedLibrary> mLibrary;
+    KeyedVector<int32_t, String8> mCASystemIdToLibraryPathMap;
+    KeyedVector<String8, wp<SharedLibrary> > mLibraryPathToOpenLibraryMap;
+
+    bool loadFactoryForSchemeFromPath(
+            const String8 &path,
+            int32_t CA_system_id,
+            sp<SharedLibrary> *library,
+            T** factory);
+
+    bool queryPluginsFromPath(
+            const String8 &path,
+            vector<ParcelableCasPluginDescriptor>* results);
+
+    bool openFactory(const String8 &path);
+    void closeFactory();
+};
+
+template <class T>
+bool FactoryLoader<T>::findFactoryForScheme(
+        int32_t CA_system_id, sp<SharedLibrary> *library, T** factory) {
+    if (library != NULL) {
+        library->clear();
+    }
+    if (factory != NULL) {
+        *factory = NULL;
+    }
+
+    Mutex::Autolock autoLock(mMapLock);
+
+    // first check cache
+    ssize_t index = mCASystemIdToLibraryPathMap.indexOfKey(CA_system_id);
+    if (index >= 0) {
+        return loadFactoryForSchemeFromPath(
+                mCASystemIdToLibraryPathMap[index],
+                CA_system_id, library, factory);
+    }
+
+    // no luck, have to search
+    String8 dirPath("/vendor/lib/mediacas");
+    DIR* pDir = opendir(dirPath.string());
+
+    if (pDir == NULL) {
+        ALOGE("Failed to open plugin directory %s", dirPath.string());
+        return false;
+    }
+
+    struct dirent* pEntry;
+    while ((pEntry = readdir(pDir))) {
+        String8 pluginPath = dirPath + "/" + pEntry->d_name;
+        if (pluginPath.getPathExtension() == ".so") {
+            if (loadFactoryForSchemeFromPath(
+                    pluginPath, CA_system_id, library, factory)) {
+                mCASystemIdToLibraryPathMap.add(CA_system_id, pluginPath);
+                closedir(pDir);
+
+                return true;
+            }
+        }
+    }
+
+    closedir(pDir);
+
+    ALOGE("Failed to find plugin");
+    return false;
+}
+
+template <class T>
+bool FactoryLoader<T>::enumeratePlugins(
+        vector<ParcelableCasPluginDescriptor>* results) {
+    ALOGI("enumeratePlugins");
+
+    results->clear();
+
+    String8 dirPath("/vendor/lib/mediacas");
+    DIR* pDir = opendir(dirPath.string());
+
+    if (pDir == NULL) {
+        ALOGE("Failed to open plugin directory %s", dirPath.string());
+        return false;
+    }
+
+    Mutex::Autolock autoLock(mMapLock);
+
+    struct dirent* pEntry;
+    while ((pEntry = readdir(pDir))) {
+        String8 pluginPath = dirPath + "/" + pEntry->d_name;
+        if (pluginPath.getPathExtension() == ".so") {
+            queryPluginsFromPath(pluginPath, results);
+        }
+    }
+    return true;
+}
+
+template <class T>
+bool FactoryLoader<T>::loadFactoryForSchemeFromPath(
+        const String8 &path, int32_t CA_system_id,
+        sp<SharedLibrary> *library, T** factory) {
+    closeFactory();
+
+    if (!openFactory(path) || !mFactory->isSystemIdSupported(CA_system_id)) {
+        closeFactory();
+        return false;
+    }
+
+    if (library != NULL) {
+        *library = mLibrary;
+    }
+    if (factory != NULL) {
+        *factory = mFactory;
+    }
+    return true;
+}
+
+template <class T>
+bool FactoryLoader<T>::queryPluginsFromPath(
+        const String8 &path, vector<ParcelableCasPluginDescriptor>* results) {
+    closeFactory();
+
+    vector<CasPluginDescriptor> descriptors;
+    if (!openFactory(path) || mFactory->queryPlugins(&descriptors) != OK) {
+        closeFactory();
+        return false;
+    }
+
+    for (auto it = descriptors.begin(); it != descriptors.end(); it++) {
+        results->push_back(ParcelableCasPluginDescriptor(
+                it->CA_system_id, it->name));
+    }
+    return true;
+}
+
+template <class T>
+bool FactoryLoader<T>::openFactory(const String8 &path) {
+    // get strong pointer to open shared library
+    ssize_t index = mLibraryPathToOpenLibraryMap.indexOfKey(path);
+    if (index >= 0) {
+        mLibrary = mLibraryPathToOpenLibraryMap[index].promote();
+    } else {
+        index = mLibraryPathToOpenLibraryMap.add(path, NULL);
+    }
+
+    if (!mLibrary.get()) {
+        mLibrary = new SharedLibrary(path);
+        if (!*mLibrary) {
+            return false;
+        }
+
+        mLibraryPathToOpenLibraryMap.replaceValueAt(index, mLibrary);
+    }
+
+    CreateFactoryFunc createFactory =
+        (CreateFactoryFunc)mLibrary->lookup(mCreateFactoryFuncName);
+    if (createFactory == NULL || (mFactory = createFactory()) == NULL) {
+        return false;
+    }
+    return true;
+}
+
+template <class T>
+void FactoryLoader<T>::closeFactory() {
+    delete mFactory;
+    mFactory = NULL;
+    mLibrary.clear();
+}
+
+} // namespace android
+
+#endif // MEDIA_CAS_LOADER_H_
diff --git a/services/mediadrm/MediaCasService.cpp b/services/mediadrm/MediaCasService.cpp
new file mode 100644
index 0000000..c111283
--- /dev/null
+++ b/services/mediadrm/MediaCasService.cpp
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "MediaCasService"
+
+#include <binder/IServiceManager.h>
+#include <media/cas/CasAPI.h>
+#include <media/cas/DescramblerAPI.h>
+#include <media/CasImpl.h>
+#include <media/DescramblerImpl.h>
+#include <utils/Log.h>
+#include <utils/List.h>
+#include "MediaCasService.h"
+#include <android/media/ICasListener.h>
+
+namespace android {
+
+//static
+void MediaCasService::instantiate() {
+    defaultServiceManager()->addService(
+            String16("media.cas"), new MediaCasService());
+}
+
+MediaCasService::MediaCasService() :
+    mCasLoader(new FactoryLoader<CasFactory>("createCasFactory")),
+    mDescramblerLoader(new FactoryLoader<DescramblerFactory>(
+            "createDescramblerFactory")) {
+}
+
+MediaCasService::~MediaCasService() {
+    delete mCasLoader;
+    delete mDescramblerLoader;
+}
+
+Status MediaCasService::enumeratePlugins(
+        vector<ParcelableCasPluginDescriptor>* results) {
+    ALOGV("enumeratePlugins");
+
+    mCasLoader->enumeratePlugins(results);
+
+    return Status::ok();
+}
+
+Status MediaCasService::isSystemIdSupported(
+        int32_t CA_system_id, bool* result) {
+    ALOGV("isSystemIdSupported: CA_system_id=%d", CA_system_id);
+
+    *result = mCasLoader->findFactoryForScheme(CA_system_id);
+
+    return Status::ok();
+}
+
+Status MediaCasService::createPlugin(
+        int32_t CA_system_id,
+        const sp<ICasListener> &listener,
+        sp<ICas>* result) {
+    ALOGV("createPlugin: CA_system_id=%d", CA_system_id);
+
+    result->clear();
+
+    CasFactory *factory;
+    sp<SharedLibrary> library;
+    if (mCasLoader->findFactoryForScheme(CA_system_id, &library, &factory)) {
+        CasPlugin *plugin = NULL;
+        sp<CasImpl> casImpl = new CasImpl(listener);
+        if (factory->createPlugin(CA_system_id, (uint64_t)casImpl.get(),
+                &CasImpl::OnEvent, &plugin) == OK && plugin != NULL) {
+            casImpl->init(library, plugin);
+            *result = casImpl;
+        }
+    }
+
+    return Status::ok();
+}
+
+Status MediaCasService::isDescramblerSupported(
+        int32_t CA_system_id, bool* result) {
+    ALOGV("isDescramblerSupported: CA_system_id=%d", CA_system_id);
+
+    *result = mDescramblerLoader->findFactoryForScheme(CA_system_id);
+
+    return Status::ok();
+}
+
+Status MediaCasService::createDescrambler(
+        int32_t CA_system_id, sp<IDescrambler>* result) {
+    ALOGV("createDescrambler: CA_system_id=%d", CA_system_id);
+
+    result->clear();
+
+    DescramblerFactory *factory;
+    sp<SharedLibrary> library;
+    if (mDescramblerLoader->findFactoryForScheme(
+            CA_system_id, &library, &factory)) {
+        DescramblerPlugin *plugin = NULL;
+        if (factory->createPlugin(CA_system_id, &plugin) == OK
+                && plugin != NULL) {
+            *result = new DescramblerImpl(library, plugin);
+        }
+    }
+
+    return Status::ok();
+}
+
+} // namespace android
diff --git a/services/mediadrm/MediaCasService.h b/services/mediadrm/MediaCasService.h
new file mode 100644
index 0000000..cb828f2
--- /dev/null
+++ b/services/mediadrm/MediaCasService.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MEDIA_CAS_SERVICE_H_
+#define MEDIA_CAS_SERVICE_H_
+
+#include <android/media/BnMediaCasService.h>
+
+#include "FactoryLoader.h"
+
+namespace android {
+using binder::Status;
+struct CasFactory;
+struct DescramblerFactory;
+
+class MediaCasService : public BnMediaCasService {
+public:
+    static void instantiate();
+
+    virtual Status enumeratePlugins(
+            vector<ParcelableCasPluginDescriptor>* results) override;
+
+    virtual Status isSystemIdSupported(
+            int32_t CA_system_id, bool* result) override;
+
+    virtual Status createPlugin(
+            int32_t CA_system_id,
+            const sp<ICasListener> &listener,
+            sp<ICas>* result) override;
+
+    virtual Status isDescramblerSupported(
+            int32_t CA_system_id, bool* result) override;
+
+    virtual Status createDescrambler(
+            int32_t CA_system_id, sp<IDescrambler>* result) override;
+
+private:
+    FactoryLoader<CasFactory> *mCasLoader;
+    FactoryLoader<DescramblerFactory> *mDescramblerLoader;
+
+    MediaCasService();
+    virtual ~MediaCasService();
+};
+
+} // namespace android
+
+#endif // MEDIA_CAS_SERVICE_H_
diff --git a/services/mediadrm/main_mediadrmserver.cpp b/services/mediadrm/main_mediadrmserver.cpp
index b767b8c..b685ae0 100644
--- a/services/mediadrm/main_mediadrmserver.cpp
+++ b/services/mediadrm/main_mediadrmserver.cpp
@@ -27,6 +27,7 @@
 #include <cutils/properties.h>
 #include <utils/Log.h>
 #include "MediaDrmService.h"
+#include "MediaCasService.h"
 
 using namespace android;
 
@@ -38,6 +39,7 @@
     sp<IServiceManager> sm = defaultServiceManager();
     ALOGI("ServiceManager: %p", sm.get());
     MediaDrmService::instantiate();
+    MediaCasService::instantiate();
     ProcessState::self()->startThreadPool();
     IPCThreadState::self()->joinThreadPool();
 }
diff --git a/services/radio/RadioHalHidl.cpp b/services/radio/RadioHalHidl.cpp
index 3dcf2f3..bfc5500 100644
--- a/services/radio/RadioHalHidl.cpp
+++ b/services/radio/RadioHalHidl.cpp
@@ -116,7 +116,7 @@
 sp<IBroadcastRadio> RadioHalHidl::getService()
 {
     if (mHalModule == 0) {
-        sp<IBroadcastRadioFactory> factory = IBroadcastRadioFactory::getService("broadcastradio");
+        sp<IBroadcastRadioFactory> factory = IBroadcastRadioFactory::getService();
         if (factory != 0) {
             factory->connectModule(static_cast<Class>(mClassId),
                                [&](Result retval, const ::android::sp<IBroadcastRadio>& result) {