Merge "audio policy: renamed AudioPolicyManagerBase to AudioPolicyManager"
diff --git a/camera/Android.mk b/camera/Android.mk
index e633450..369d0c5 100644
--- a/camera/Android.mk
+++ b/camera/Android.mk
@@ -1,3 +1,17 @@
+# Copyright 2010 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
 CAMERA_CLIENT_LOCAL_PATH:= $(call my-dir)
 include $(call all-subdir-makefiles)
 include $(CLEAR_VARS)
@@ -21,6 +35,7 @@
 	camera2/CaptureRequest.cpp \
 	ProCamera.cpp \
 	CameraBase.cpp \
+	VendorTagDescriptor.cpp
 
 LOCAL_SHARED_LIBRARIES := \
 	libcutils \
@@ -34,6 +49,7 @@
 
 LOCAL_C_INCLUDES += \
 	system/media/camera/include \
+	system/media/private/camera/include
 
 LOCAL_MODULE:= libcamera_client
 
diff --git a/camera/ICameraService.cpp b/camera/ICameraService.cpp
index 5fc89fb..b86651f 100644
--- a/camera/ICameraService.cpp
+++ b/camera/ICameraService.cpp
@@ -17,6 +17,7 @@
 
 #define LOG_TAG "BpCameraService"
 #include <utils/Log.h>
+#include <utils/Errors.h>
 
 #include <stdint.h>
 #include <sys/types.h>
@@ -34,6 +35,7 @@
 #include <camera/camera2/ICameraDeviceUser.h>
 #include <camera/camera2/ICameraDeviceCallbacks.h>
 #include <camera/CameraMetadata.h>
+#include <camera/VendorTagDescriptor.h>
 
 namespace android {
 
@@ -143,6 +145,24 @@
         return result;
     }
 
+    // Get enumeration and description of vendor tags for camera
+    virtual status_t getCameraVendorTagDescriptor(/*out*/sp<VendorTagDescriptor>& desc) {
+        Parcel data, reply;
+        data.writeInterfaceToken(ICameraService::getInterfaceDescriptor());
+        remote()->transact(BnCameraService::GET_CAMERA_VENDOR_TAG_DESCRIPTOR, data, &reply);
+
+        if (readExceptionCode(reply)) return -EPROTO;
+        status_t result = reply.readInt32();
+
+        if (reply.readInt32() != 0) {
+            sp<VendorTagDescriptor> d;
+            if (VendorTagDescriptor::createFromParcel(&reply, /*out*/d) == OK) {
+                desc = d;
+            }
+        }
+        return result;
+    }
+
     // connect to camera service (android.hardware.Camera)
     virtual status_t connect(const sp<ICameraClient>& cameraClient, int cameraId,
                              const String16 &clientPackageName, int clientUid,
@@ -275,6 +295,22 @@
             info.writeToParcel(reply);
             return NO_ERROR;
         } break;
+        case GET_CAMERA_VENDOR_TAG_DESCRIPTOR: {
+            CHECK_INTERFACE(ICameraService, data, reply);
+            sp<VendorTagDescriptor> d;
+            status_t result = getCameraVendorTagDescriptor(d);
+            reply->writeNoException();
+            reply->writeInt32(result);
+
+            // out-variables are after exception and return value
+            if (d == NULL) {
+                reply->writeInt32(0);
+            } else {
+                reply->writeInt32(1); // means the parcelable is included
+                d->writeToParcel(reply);
+            }
+            return NO_ERROR;
+        } break;
         case CONNECT: {
             CHECK_INTERFACE(ICameraService, data, reply);
             sp<ICameraClient> cameraClient =
@@ -284,7 +320,7 @@
             int32_t clientUid = data.readInt32();
             sp<ICamera> camera;
             status_t status = connect(cameraClient, cameraId,
-                    clientName, clientUid, /*out*/ camera);
+                    clientName, clientUid, /*out*/camera);
             reply->writeNoException();
             reply->writeInt32(status);
             if (camera != NULL) {
@@ -304,7 +340,7 @@
             int32_t clientUid = data.readInt32();
             sp<IProCameraUser> camera;
             status_t status = connectPro(cameraClient, cameraId,
-                    clientName, clientUid, /*out*/ camera);
+                    clientName, clientUid, /*out*/camera);
             reply->writeNoException();
             reply->writeInt32(status);
             if (camera != NULL) {
@@ -324,7 +360,7 @@
             int32_t clientUid = data.readInt32();
             sp<ICameraDeviceUser> camera;
             status_t status = connectDevice(cameraClient, cameraId,
-                    clientName, clientUid, /*out*/ camera);
+                    clientName, clientUid, /*out*/camera);
             reply->writeNoException();
             reply->writeInt32(status);
             if (camera != NULL) {
diff --git a/camera/VendorTagDescriptor.cpp b/camera/VendorTagDescriptor.cpp
new file mode 100644
index 0000000..a0a6a51
--- /dev/null
+++ b/camera/VendorTagDescriptor.cpp
@@ -0,0 +1,319 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "VenderTagDescriptor"
+
+#include <binder/Parcel.h>
+#include <utils/Errors.h>
+#include <utils/Log.h>
+#include <utils/Mutex.h>
+#include <utils/Vector.h>
+#include <system/camera_metadata.h>
+#include <camera_metadata_hidden.h>
+
+#include "camera/VendorTagDescriptor.h"
+
+#include <string.h>
+
+namespace android {
+
+extern "C" {
+
+static int vendor_tag_descriptor_get_tag_count(const vendor_tag_ops_t* v);
+static void vendor_tag_descriptor_get_all_tags(const vendor_tag_ops_t* v, uint32_t* tagArray);
+static const char* vendor_tag_descriptor_get_section_name(const vendor_tag_ops_t* v, uint32_t tag);
+static const char* vendor_tag_descriptor_get_tag_name(const vendor_tag_ops_t* v, uint32_t tag);
+static int vendor_tag_descriptor_get_tag_type(const vendor_tag_ops_t* v, uint32_t tag);
+
+} /* extern "C" */
+
+
+static Mutex sLock;
+static sp<VendorTagDescriptor> sGlobalVendorTagDescriptor;
+
+VendorTagDescriptor::VendorTagDescriptor() {}
+VendorTagDescriptor::~VendorTagDescriptor() {}
+
+status_t VendorTagDescriptor::createDescriptorFromOps(const vendor_tag_ops_t* vOps,
+            /*out*/
+            sp<VendorTagDescriptor>& descriptor) {
+    if (vOps == NULL) {
+        ALOGE("%s: vendor_tag_ops argument was NULL.", __FUNCTION__);
+        return BAD_VALUE;
+    }
+
+    int tagCount = vOps->get_tag_count(vOps);
+    if (tagCount < 0 || tagCount > INT32_MAX) {
+        ALOGE("%s: tag count %d from vendor ops is invalid.", __FUNCTION__, tagCount);
+        return BAD_VALUE;
+    }
+
+    Vector<uint32_t> tagArray;
+    LOG_ALWAYS_FATAL_IF(tagArray.resize(tagCount) != tagCount,
+            "%s: too many (%u) vendor tags defined.", __FUNCTION__, tagCount);
+
+    vOps->get_all_tags(vOps, /*out*/tagArray.editArray());
+
+    sp<VendorTagDescriptor> desc = new VendorTagDescriptor();
+    desc->mTagCount = tagCount;
+
+    for (size_t i = 0; i < static_cast<size_t>(tagCount); ++i) {
+        uint32_t tag = tagArray[i];
+        if (tag < CAMERA_METADATA_VENDOR_TAG_BOUNDARY) {
+            ALOGE("%s: vendor tag %d not in vendor tag section.", __FUNCTION__, tag);
+            return BAD_VALUE;
+        }
+        const char *tagName = vOps->get_tag_name(vOps, tag);
+        if (tagName == NULL) {
+            ALOGE("%s: no tag name defined for vendor tag %d.", __FUNCTION__, tag);
+            return BAD_VALUE;
+        }
+        desc->mTagToNameMap.add(tag, String8(tagName));
+        const char *sectionName = vOps->get_section_name(vOps, tag);
+        if (sectionName == NULL) {
+            ALOGE("%s: no section name defined for vendor tag %d.", __FUNCTION__, tag);
+            return BAD_VALUE;
+        }
+        desc->mTagToSectionMap.add(tag, String8(sectionName));
+        int tagType = vOps->get_tag_type(vOps, tag);
+        if (tagType < 0 || tagType >= NUM_TYPES) {
+            ALOGE("%s: tag type %d from vendor ops does not exist.", __FUNCTION__, tagType);
+            return BAD_VALUE;
+        }
+        desc->mTagToTypeMap.add(tag, tagType);
+    }
+    descriptor = desc;
+    return OK;
+}
+
+status_t VendorTagDescriptor::createFromParcel(const Parcel* parcel,
+            /*out*/
+            sp<VendorTagDescriptor>& descriptor) {
+    status_t res = OK;
+    if (parcel == NULL) {
+        ALOGE("%s: parcel argument was NULL.", __FUNCTION__);
+        return BAD_VALUE;
+    }
+
+    int32_t tagCount = 0;
+    if ((res = parcel->readInt32(&tagCount)) != OK) {
+        ALOGE("%s: could not read tag count from parcel", __FUNCTION__);
+        return res;
+    }
+
+    if (tagCount < 0 || tagCount > INT32_MAX) {
+        ALOGE("%s: tag count %d from vendor ops is invalid.", __FUNCTION__, tagCount);
+        return BAD_VALUE;
+    }
+
+    sp<VendorTagDescriptor> desc = new VendorTagDescriptor();
+    desc->mTagCount = tagCount;
+
+    uint32_t tag;
+    int32_t tagType;
+    for (int32_t i = 0; i < tagCount; ++i) {
+        if ((res = parcel->readInt32(reinterpret_cast<int32_t*>(&tag))) != OK) {
+            ALOGE("%s: could not read tag id from parcel for index %d", __FUNCTION__, i);
+            break;
+        }
+        if (tag < CAMERA_METADATA_VENDOR_TAG_BOUNDARY) {
+            ALOGE("%s: vendor tag %d not in vendor tag section.", __FUNCTION__, tag);
+            res = BAD_VALUE;
+            break;
+        }
+        if ((res = parcel->readInt32(&tagType)) != OK) {
+            ALOGE("%s: could not read tag type from parcel for tag %d", __FUNCTION__, tag);
+            break;
+        }
+        if (tagType < 0 || tagType >= NUM_TYPES) {
+            ALOGE("%s: tag type %d from vendor ops does not exist.", __FUNCTION__, tagType);
+            res = BAD_VALUE;
+            break;
+        }
+        String8 tagName = parcel->readString8();
+        if (tagName.isEmpty()) {
+            ALOGE("%s: parcel tag name was NULL for tag %d.", __FUNCTION__, tag);
+            res = NOT_ENOUGH_DATA;
+            break;
+        }
+        String8 sectionName = parcel->readString8();
+        if (sectionName.isEmpty()) {
+            ALOGE("%s: parcel section name was NULL for tag %d.", __FUNCTION__, tag);
+            res = NOT_ENOUGH_DATA;
+            break;
+        }
+
+        desc->mTagToNameMap.add(tag, tagName);
+        desc->mTagToSectionMap.add(tag, sectionName);
+        desc->mTagToTypeMap.add(tag, tagType);
+    }
+
+    if (res != OK) {
+        return res;
+    }
+
+    descriptor = desc;
+    return res;
+}
+
+int VendorTagDescriptor::getTagCount() const {
+    size_t size = mTagToNameMap.size();
+    if (size == 0) {
+        return VENDOR_TAG_COUNT_ERR;
+    }
+    return size;
+}
+
+void VendorTagDescriptor::getTagArray(uint32_t* tagArray) const {
+    size_t size = mTagToNameMap.size();
+    for (size_t i = 0; i < size; ++i) {
+        tagArray[i] = mTagToNameMap.keyAt(i);
+    }
+}
+
+const char* VendorTagDescriptor::getSectionName(uint32_t tag) const {
+    ssize_t index = mTagToSectionMap.indexOfKey(tag);
+    if (index < 0) {
+        return VENDOR_SECTION_NAME_ERR;
+    }
+    return mTagToSectionMap.valueAt(index).string();
+}
+
+const char* VendorTagDescriptor::getTagName(uint32_t tag) const {
+    ssize_t index = mTagToNameMap.indexOfKey(tag);
+    if (index < 0) {
+        return VENDOR_TAG_NAME_ERR;
+    }
+    return mTagToNameMap.valueAt(index).string();
+}
+
+int VendorTagDescriptor::getTagType(uint32_t tag) const {
+    ssize_t index = mTagToNameMap.indexOfKey(tag);
+    if (index < 0) {
+        return VENDOR_TAG_TYPE_ERR;
+    }
+    return mTagToTypeMap.valueFor(tag);
+}
+
+status_t VendorTagDescriptor::writeToParcel(Parcel* parcel) const {
+    status_t res = OK;
+    if (parcel == NULL) {
+        ALOGE("%s: parcel argument was NULL.", __FUNCTION__);
+        return BAD_VALUE;
+    }
+
+    if ((res = parcel->writeInt32(mTagCount)) != OK) {
+        return res;
+    }
+
+    size_t size = mTagToNameMap.size();
+    uint32_t tag;
+    int32_t tagType;
+    for (size_t i = 0; i < size; ++i) {
+        tag = mTagToNameMap.keyAt(i);
+        String8 tagName = mTagToNameMap[i];
+        String8 sectionName = mTagToSectionMap.valueFor(tag);
+        tagType = mTagToTypeMap.valueFor(tag);
+        if ((res = parcel->writeInt32(tag)) != OK) break;
+        if ((res = parcel->writeInt32(tagType)) != OK) break;
+        if ((res = parcel->writeString8(tagName)) != OK) break;
+        if ((res = parcel->writeString8(sectionName)) != OK) break;
+    }
+
+    return res;
+}
+
+status_t VendorTagDescriptor::setAsGlobalVendorTagDescriptor(const sp<VendorTagDescriptor>& desc) {
+    status_t res = OK;
+    Mutex::Autolock al(sLock);
+    sGlobalVendorTagDescriptor = desc;
+
+    vendor_tag_ops_t* opsPtr = NULL;
+    if (desc != NULL) {
+        opsPtr = &(desc->mVendorOps);
+        opsPtr->get_tag_count = vendor_tag_descriptor_get_tag_count;
+        opsPtr->get_all_tags = vendor_tag_descriptor_get_all_tags;
+        opsPtr->get_section_name = vendor_tag_descriptor_get_section_name;
+        opsPtr->get_tag_name = vendor_tag_descriptor_get_tag_name;
+        opsPtr->get_tag_type = vendor_tag_descriptor_get_tag_type;
+    }
+    if((res = set_camera_metadata_vendor_ops(opsPtr)) != OK) {
+        ALOGE("%s: Could not set vendor tag descriptor, received error %s (%d)."
+                , __FUNCTION__, strerror(-res), res);
+    }
+    return res;
+}
+
+void VendorTagDescriptor::clearGlobalVendorTagDescriptor() {
+    Mutex::Autolock al(sLock);
+    set_camera_metadata_vendor_ops(NULL);
+    sGlobalVendorTagDescriptor.clear();
+}
+
+sp<VendorTagDescriptor> VendorTagDescriptor::getGlobalVendorTagDescriptor() {
+    Mutex::Autolock al(sLock);
+    return sGlobalVendorTagDescriptor;
+}
+
+extern "C" {
+
+int vendor_tag_descriptor_get_tag_count(const vendor_tag_ops_t* v) {
+    Mutex::Autolock al(sLock);
+    if (sGlobalVendorTagDescriptor == NULL) {
+        ALOGE("%s: Vendor tag descriptor not initialized.", __FUNCTION__);
+        return VENDOR_TAG_COUNT_ERR;
+    }
+    return sGlobalVendorTagDescriptor->getTagCount();
+}
+
+void vendor_tag_descriptor_get_all_tags(const vendor_tag_ops_t* v, uint32_t* tagArray) {
+    Mutex::Autolock al(sLock);
+    if (sGlobalVendorTagDescriptor == NULL) {
+        ALOGE("%s: Vendor tag descriptor not initialized.", __FUNCTION__);
+        return;
+    }
+    sGlobalVendorTagDescriptor->getTagArray(tagArray);
+}
+
+const char* vendor_tag_descriptor_get_section_name(const vendor_tag_ops_t* v, uint32_t tag) {
+    Mutex::Autolock al(sLock);
+    if (sGlobalVendorTagDescriptor == NULL) {
+        ALOGE("%s: Vendor tag descriptor not initialized.", __FUNCTION__);
+        return VENDOR_SECTION_NAME_ERR;
+    }
+    return sGlobalVendorTagDescriptor->getSectionName(tag);
+}
+
+const char* vendor_tag_descriptor_get_tag_name(const vendor_tag_ops_t* v, uint32_t tag) {
+    Mutex::Autolock al(sLock);
+    if (sGlobalVendorTagDescriptor == NULL) {
+        ALOGE("%s: Vendor tag descriptor not initialized.", __FUNCTION__);
+        return VENDOR_TAG_NAME_ERR;
+    }
+    return sGlobalVendorTagDescriptor->getTagName(tag);
+}
+
+int vendor_tag_descriptor_get_tag_type(const vendor_tag_ops_t* v, uint32_t tag) {
+    Mutex::Autolock al(sLock);
+    if (sGlobalVendorTagDescriptor == NULL) {
+        ALOGE("%s: Vendor tag descriptor not initialized.", __FUNCTION__);
+        return VENDOR_TAG_TYPE_ERR;
+    }
+    return sGlobalVendorTagDescriptor->getTagType(tag);
+}
+
+} /* extern "C" */
+} /* namespace android */
diff --git a/camera/tests/Android.mk b/camera/tests/Android.mk
index ec13911..61385e5 100644
--- a/camera/tests/Android.mk
+++ b/camera/tests/Android.mk
@@ -1,9 +1,24 @@
+# Copyright 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.
+
 LOCAL_PATH:= $(call my-dir)
 include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES:= \
 	main.cpp \
 	ProCameraTests.cpp \
+	VendorTagDescriptorTests.cpp
 
 LOCAL_SHARED_LIBRARIES := \
 	libutils \
@@ -26,6 +41,8 @@
 	external/gtest/include \
 	external/stlport/stlport \
 	system/media/camera/include \
+	system/media/private/camera/include \
+	system/media/camera/tests \
 	frameworks/av/services/camera/libcameraservice \
 	frameworks/av/include/camera \
 	frameworks/native/include \
diff --git a/camera/tests/VendorTagDescriptorTests.cpp b/camera/tests/VendorTagDescriptorTests.cpp
new file mode 100644
index 0000000..6624e79
--- /dev/null
+++ b/camera/tests/VendorTagDescriptorTests.cpp
@@ -0,0 +1,204 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_NDEBUG 0
+#define LOG_TAG "VendorTagDescriptorTests"
+
+#include <binder/Parcel.h>
+#include <camera/VendorTagDescriptor.h>
+#include <camera_metadata_tests_fake_vendor.h>
+#include <camera_metadata_hidden.h>
+#include <system/camera_vendor_tags.h>
+#include <utils/Errors.h>
+#include <utils/Log.h>
+#include <utils/RefBase.h>
+
+#include <gtest/gtest.h>
+#include <stdint.h>
+
+using namespace android;
+
+enum {
+    BAD_TAG_ARRAY = 0xDEADBEEFu,
+    BAD_TAG = 0x8DEADBADu,
+};
+
+#define ARRAY_SIZE(a)      (sizeof(a) / sizeof((a)[0]))
+
+static bool ContainsTag(uint32_t* tagArray, size_t size, uint32_t tag) {
+    for (size_t i = 0; i < size; ++i) {
+        if (tag == tagArray[i]) return true;
+    }
+    return false;
+}
+
+#define EXPECT_CONTAINS_TAG(t, a) \
+    EXPECT_TRUE(ContainsTag(a, ARRAY_SIZE(a), t))
+
+#define ASSERT_NOT_NULL(x) \
+    ASSERT_TRUE((x) != NULL)
+
+extern "C" {
+
+static int default_get_tag_count(const vendor_tag_ops_t* vOps) {
+    return VENDOR_TAG_COUNT_ERR;
+}
+
+static void default_get_all_tags(const vendor_tag_ops_t* vOps, uint32_t* tagArray) {
+    //Noop
+}
+
+static const char* default_get_section_name(const vendor_tag_ops_t* vOps, uint32_t tag) {
+    return VENDOR_SECTION_NAME_ERR;
+}
+
+static const char* default_get_tag_name(const vendor_tag_ops_t* vOps, uint32_t tag) {
+    return VENDOR_TAG_NAME_ERR;
+}
+
+static int default_get_tag_type(const vendor_tag_ops_t* vOps, uint32_t tag) {
+    return VENDOR_TAG_TYPE_ERR;
+}
+
+} /*extern "C"*/
+
+// Set default vendor operations for a vendor_tag_ops struct
+static void FillWithDefaults(vendor_tag_ops_t* vOps) {
+    ASSERT_NOT_NULL(vOps);
+    vOps->get_tag_count = default_get_tag_count;
+    vOps->get_all_tags = default_get_all_tags;
+    vOps->get_section_name = default_get_section_name;
+    vOps->get_tag_name = default_get_tag_name;
+    vOps->get_tag_type = default_get_tag_type;
+}
+
+/**
+ * Test if values from VendorTagDescriptor methods match corresponding values
+ * from vendor_tag_ops functions.
+ */
+TEST(VendorTagDescriptorTest, ConsistentWithVendorTags) {
+    sp<VendorTagDescriptor> vDesc;
+    const vendor_tag_ops_t *vOps = &fakevendor_ops;
+    EXPECT_EQ(OK, VendorTagDescriptor::createDescriptorFromOps(vOps, /*out*/vDesc));
+
+    ASSERT_NOT_NULL(vDesc);
+
+    // Ensure reasonable tag count
+    int tagCount = vDesc->getTagCount();
+    EXPECT_EQ(tagCount, vOps->get_tag_count(vOps));
+
+    uint32_t descTagArray[tagCount];
+    uint32_t opsTagArray[tagCount];
+
+    // Get all tag ids
+    vDesc->getTagArray(descTagArray);
+    vOps->get_all_tags(vOps, opsTagArray);
+
+    ASSERT_NOT_NULL(descTagArray);
+    ASSERT_NOT_NULL(opsTagArray);
+
+    uint32_t tag;
+    for (int i = 0; i < tagCount; ++i) {
+        // For each tag id, check whether type, section name, tag name match
+        tag = descTagArray[i];
+        EXPECT_CONTAINS_TAG(tag, opsTagArray);
+        EXPECT_EQ(vDesc->getTagType(tag), vOps->get_tag_type(vOps, tag));
+        EXPECT_STREQ(vDesc->getSectionName(tag), vOps->get_section_name(vOps, tag));
+        EXPECT_STREQ(vDesc->getTagName(tag), vOps->get_tag_name(vOps, tag));
+    }
+}
+
+/**
+ * Test if values from VendorTagDescriptor methods stay consistent after being
+ * parcelled/unparcelled.
+ */
+TEST(VendorTagDescriptorTest, ConsistentAcrossParcel) {
+    sp<VendorTagDescriptor> vDescOriginal, vDescParceled;
+    const vendor_tag_ops_t *vOps = &fakevendor_ops;
+    EXPECT_EQ(OK, VendorTagDescriptor::createDescriptorFromOps(vOps, /*out*/vDescOriginal));
+
+    ASSERT_TRUE(vDescOriginal != NULL);
+
+    Parcel p;
+
+    // Check whether parcel read/write succeed
+    EXPECT_EQ(OK, vDescOriginal->writeToParcel(&p));
+    p.setDataPosition(0);
+    ASSERT_EQ(OK, VendorTagDescriptor::createFromParcel(&p, vDescParceled));
+
+    // Ensure consistent tag count
+    int tagCount = vDescOriginal->getTagCount();
+    ASSERT_EQ(tagCount, vDescParceled->getTagCount());
+
+    uint32_t descTagArray[tagCount];
+    uint32_t desc2TagArray[tagCount];
+
+    // Get all tag ids
+    vDescOriginal->getTagArray(descTagArray);
+    vDescParceled->getTagArray(desc2TagArray);
+
+    ASSERT_NOT_NULL(descTagArray);
+    ASSERT_NOT_NULL(desc2TagArray);
+
+    uint32_t tag;
+    for (int i = 0; i < tagCount; ++i) {
+        // For each tag id, check consistency between the two vendor tag
+        // descriptors for each type, section name, tag name
+        tag = descTagArray[i];
+        EXPECT_CONTAINS_TAG(tag, desc2TagArray);
+        EXPECT_EQ(vDescOriginal->getTagType(tag), vDescParceled->getTagType(tag));
+        EXPECT_STREQ(vDescOriginal->getSectionName(tag), vDescParceled->getSectionName(tag));
+        EXPECT_STREQ(vDescOriginal->getTagName(tag), vDescParceled->getTagName(tag));
+    }
+}
+
+/**
+ * Test defaults and error conditions.
+ */
+TEST(VendorTagDescriptorTest, ErrorConditions) {
+    sp<VendorTagDescriptor> vDesc;
+    vendor_tag_ops_t vOps;
+    FillWithDefaults(&vOps);
+
+    // Ensure create fails when using null vOps
+    EXPECT_EQ(BAD_VALUE, VendorTagDescriptor::createDescriptorFromOps(/*vOps*/NULL, vDesc));
+
+    // Ensure create works when there are no vtags defined in a well-formed vOps
+    ASSERT_EQ(OK, VendorTagDescriptor::createDescriptorFromOps(&vOps, vDesc));
+
+    // Ensure defaults are returned when no vtags are defined, or tag is unknown
+    EXPECT_EQ(VENDOR_TAG_COUNT_ERR, vDesc->getTagCount());
+    uint32_t* tagArray = reinterpret_cast<uint32_t*>(BAD_TAG_ARRAY);
+    uint32_t* testArray = tagArray;
+    vDesc->getTagArray(tagArray);
+    EXPECT_EQ(testArray, tagArray);
+    EXPECT_EQ(VENDOR_SECTION_NAME_ERR, vDesc->getSectionName(BAD_TAG));
+    EXPECT_EQ(VENDOR_TAG_NAME_ERR, vDesc->getTagName(BAD_TAG));
+    EXPECT_EQ(VENDOR_TAG_TYPE_ERR, vDesc->getTagType(BAD_TAG));
+
+    // Make sure global can be set/cleared
+    const vendor_tag_ops_t *fakeOps = &fakevendor_ops;
+    sp<VendorTagDescriptor> prevGlobal = VendorTagDescriptor::getGlobalVendorTagDescriptor();
+    VendorTagDescriptor::clearGlobalVendorTagDescriptor();
+
+    EXPECT_TRUE(VendorTagDescriptor::getGlobalVendorTagDescriptor() == NULL);
+    EXPECT_EQ(OK, VendorTagDescriptor::setAsGlobalVendorTagDescriptor(vDesc));
+    EXPECT_TRUE(VendorTagDescriptor::getGlobalVendorTagDescriptor() != NULL);
+    EXPECT_EQ(VENDOR_SECTION_NAME_ERR, vDesc->getSectionName(BAD_TAG));
+    EXPECT_EQ(OK, VendorTagDescriptor::setAsGlobalVendorTagDescriptor(prevGlobal));
+    EXPECT_EQ(prevGlobal, VendorTagDescriptor::getGlobalVendorTagDescriptor());
+}
+
diff --git a/cmds/screenrecord/Android.mk b/cmds/screenrecord/Android.mk
index 6747e60..6ee2884 100644
--- a/cmds/screenrecord/Android.mk
+++ b/cmds/screenrecord/Android.mk
@@ -41,4 +41,6 @@
 
 LOCAL_MODULE:= screenrecord
 
+LOCAL_32_BIT_ONLY := true
+
 include $(BUILD_EXECUTABLE)
diff --git a/cmds/screenrecord/FrameOutput.cpp b/cmds/screenrecord/FrameOutput.cpp
index b5cf2f9..06b1f70 100644
--- a/cmds/screenrecord/FrameOutput.cpp
+++ b/cmds/screenrecord/FrameOutput.cpp
@@ -67,8 +67,10 @@
         return UNKNOWN_ERROR;
     }
 
-    mBufferQueue = new BufferQueue(/*new GraphicBufferAlloc()*/);
-    mGlConsumer = new GLConsumer(mBufferQueue, mExtTextureName,
+    sp<IGraphicBufferProducer> producer;
+    sp<IGraphicBufferConsumer> consumer;
+    BufferQueue::createBufferQueue(&producer, &consumer);
+    mGlConsumer = new GLConsumer(consumer, mExtTextureName,
                 GL_TEXTURE_EXTERNAL_OES);
     mGlConsumer->setName(String8("virtual display"));
     mGlConsumer->setDefaultBufferSize(width, height);
@@ -79,7 +81,7 @@
 
     mPixelBuf = new uint8_t[width * height * kGlBytesPerPixel];
 
-    *pBufferProducer = mBufferQueue;
+    *pBufferProducer = producer;
 
     ALOGD("FrameOutput::createInputSurface OK");
     return NO_ERROR;
diff --git a/cmds/screenrecord/FrameOutput.h b/cmds/screenrecord/FrameOutput.h
index bb66e05..c1148d0 100644
--- a/cmds/screenrecord/FrameOutput.h
+++ b/cmds/screenrecord/FrameOutput.h
@@ -77,10 +77,6 @@
     // Set by the FrameAvailableListener callback.
     bool mFrameAvailable;
 
-    // Our queue.  The producer side is passed to the virtual display, the
-    // consumer side feeds into our GLConsumer.
-    sp<BufferQueue> mBufferQueue;
-
     // This receives frames from the virtual display and makes them available
     // as an external texture.
     sp<GLConsumer> mGlConsumer;
diff --git a/cmds/screenrecord/Overlay.cpp b/cmds/screenrecord/Overlay.cpp
index 2e98874..94f560d 100644
--- a/cmds/screenrecord/Overlay.cpp
+++ b/cmds/screenrecord/Overlay.cpp
@@ -84,7 +84,7 @@
     assert(mState == RUNNING);
 
     ALOGV("Overlay::start successful");
-    *pBufferProducer = mBufferQueue;
+    *pBufferProducer = mProducer;
     return NO_ERROR;
 }
 
@@ -169,8 +169,9 @@
         return UNKNOWN_ERROR;
     }
 
-    mBufferQueue = new BufferQueue(/*new GraphicBufferAlloc()*/);
-    mGlConsumer = new GLConsumer(mBufferQueue, mExtTextureName,
+    sp<IGraphicBufferConsumer> consumer;
+    BufferQueue::createBufferQueue(&mProducer, &consumer);
+    mGlConsumer = new GLConsumer(consumer, mExtTextureName,
                 GL_TEXTURE_EXTERNAL_OES);
     mGlConsumer->setName(String8("virtual display"));
     mGlConsumer->setDefaultBufferSize(width, height);
@@ -187,7 +188,7 @@
     ALOGV("Overlay::release_l");
     mOutputSurface.clear();
     mGlConsumer.clear();
-    mBufferQueue.clear();
+    mProducer.clear();
 
     mTexProgram.release();
     mExtTexProgram.release();
diff --git a/cmds/screenrecord/Overlay.h b/cmds/screenrecord/Overlay.h
index 48e48e0..b1b5c29 100644
--- a/cmds/screenrecord/Overlay.h
+++ b/cmds/screenrecord/Overlay.h
@@ -122,9 +122,9 @@
     // surface.
     sp<IGraphicBufferProducer> mOutputSurface;
 
-    // Our queue.  The producer side is passed to the virtual display, the
-    // consumer side feeds into our GLConsumer.
-    sp<BufferQueue> mBufferQueue;
+    // Producer side of queue, passed into the virtual display.
+    // The consumer end feeds into our GLConsumer.
+    sp<IGraphicBufferProducer> mProducer;
 
     // This receives frames from the virtual display and makes them available
     // as an external texture.
diff --git a/cmds/stagefright/Android.mk b/cmds/stagefright/Android.mk
index 561ce02..e2e389b 100644
--- a/cmds/stagefright/Android.mk
+++ b/cmds/stagefright/Android.mk
@@ -23,6 +23,8 @@
 
 LOCAL_MODULE:= stagefright
 
+LOCAL_32_BIT_ONLY := true
+
 include $(BUILD_EXECUTABLE)
 
 ################################################################################
@@ -46,6 +48,8 @@
 
 LOCAL_MODULE:= record
 
+LOCAL_32_BIT_ONLY := true
+
 include $(BUILD_EXECUTABLE)
 
 ################################################################################
@@ -69,6 +73,8 @@
 
 LOCAL_MODULE:= recordvideo
 
+LOCAL_32_BIT_ONLY := true
+
 include $(BUILD_EXECUTABLE)
 
 
@@ -93,6 +99,8 @@
 
 LOCAL_MODULE:= audioloop
 
+LOCAL_32_BIT_ONLY := true
+
 include $(BUILD_EXECUTABLE)
 
 ################################################################################
@@ -116,6 +124,8 @@
 
 LOCAL_MODULE:= stream
 
+LOCAL_32_BIT_ONLY := true
+
 include $(BUILD_EXECUTABLE)
 
 ################################################################################
@@ -139,6 +149,8 @@
 
 LOCAL_MODULE:= sf2
 
+LOCAL_32_BIT_ONLY := true
+
 include $(BUILD_EXECUTABLE)
 
 ################################################################################
@@ -163,6 +175,8 @@
 
 LOCAL_MODULE:= codec
 
+LOCAL_32_BIT_ONLY := true
+
 include $(BUILD_EXECUTABLE)
 
 ################################################################################
@@ -186,4 +200,6 @@
 
 LOCAL_MODULE:= muxer
 
+LOCAL_32_BIT_ONLY := true
+
 include $(BUILD_EXECUTABLE)
diff --git a/drm/drmserver/Android.mk b/drm/drmserver/Android.mk
index dc973da..aa0ab9b 100644
--- a/drm/drmserver/Android.mk
+++ b/drm/drmserver/Android.mk
@@ -39,4 +39,6 @@
 
 LOCAL_MODULE_TAGS := optional
 
+LOCAL_32_BIT_ONLY := true
+
 include $(BUILD_EXECUTABLE)
diff --git a/include/camera/ICameraService.h b/include/camera/ICameraService.h
index f342122..6e48f22 100644
--- a/include/camera/ICameraService.h
+++ b/include/camera/ICameraService.h
@@ -31,6 +31,7 @@
 class ICameraDeviceUser;
 class ICameraDeviceCallbacks;
 class CameraMetadata;
+class VendorTagDescriptor;
 
 class ICameraService : public IInterface
 {
@@ -47,6 +48,7 @@
         ADD_LISTENER,
         REMOVE_LISTENER,
         GET_CAMERA_CHARACTERISTICS,
+        GET_CAMERA_VENDOR_TAG_DESCRIPTOR,
     };
 
     enum {
@@ -58,10 +60,16 @@
 
     virtual int32_t  getNumberOfCameras() = 0;
     virtual status_t getCameraInfo(int cameraId,
-                                          struct CameraInfo* cameraInfo) = 0;
+            /*out*/
+            struct CameraInfo* cameraInfo) = 0;
 
     virtual status_t getCameraCharacteristics(int cameraId,
-                                              CameraMetadata* cameraInfo) = 0;
+            /*out*/
+            CameraMetadata* cameraInfo) = 0;
+
+    virtual status_t getCameraVendorTagDescriptor(
+            /*out*/
+            sp<VendorTagDescriptor>& desc) = 0;
 
     // Returns 'OK' if operation succeeded
     // - Errors: ALREADY_EXISTS if the listener was already added
diff --git a/include/camera/VendorTagDescriptor.h b/include/camera/VendorTagDescriptor.h
new file mode 100644
index 0000000..ea21d31
--- /dev/null
+++ b/include/camera/VendorTagDescriptor.h
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef VENDOR_TAG_DESCRIPTOR_H
+
+#include <utils/KeyedVector.h>
+#include <utils/String8.h>
+#include <utils/RefBase.h>
+#include <system/camera_vendor_tags.h>
+
+#include <stdint.h>
+
+namespace android {
+
+class Parcel;
+
+/**
+ * VendorTagDescriptor objects are parcelable containers for the vendor tag
+ * definitions provided, and are typically used to pass the vendor tag
+ * information enumerated by the HAL to clients of the camera service.
+ */
+class VendorTagDescriptor
+        : public LightRefBase<VendorTagDescriptor> {
+    public:
+        virtual ~VendorTagDescriptor();
+
+        /**
+         * The following 'get*' methods implement the corresponding
+         * functions defined in
+         * system/media/camera/include/system/camera_vendor_tags.h
+         */
+
+        // Returns the number of vendor tags defined.
+        int getTagCount() const;
+
+        // Returns an array containing the id's of vendor tags defined.
+        void getTagArray(uint32_t* tagArray) const;
+
+        // Returns the section name string for a given vendor tag id.
+        const char* getSectionName(uint32_t tag) const;
+
+        // Returns the tag name string for a given vendor tag id.
+        const char* getTagName(uint32_t tag) const;
+
+        // Returns the tag type for a given vendor tag id.
+        int getTagType(uint32_t tag) const;
+
+        /**
+         * Write the VendorTagDescriptor object into the given parcel.
+         *
+         * Returns OK on success, or a negative error code.
+         */
+        status_t writeToParcel(
+                /*out*/
+                Parcel* parcel) const;
+
+        // Static methods:
+
+        /**
+         * Create a VendorTagDescriptor object from the given parcel.
+         *
+         * Returns OK on success, or a negative error code.
+         */
+        static status_t createFromParcel(const Parcel* parcel,
+                /*out*/
+                sp<VendorTagDescriptor>& descriptor);
+
+        /**
+         * Create a VendorTagDescriptor object from the given vendor_tag_ops_t
+         * struct.
+         *
+         * Returns OK on success, or a negative error code.
+         */
+        static status_t createDescriptorFromOps(const vendor_tag_ops_t* vOps,
+                /*out*/
+                sp<VendorTagDescriptor>& descriptor);
+
+        /**
+         * Sets the global vendor tag descriptor to use for this process.
+         * Camera metadata operations that access vendor tags will use the
+         * vendor tag definitions set this way.
+         *
+         * Returns OK on success, or a negative error code.
+         */
+        static status_t setAsGlobalVendorTagDescriptor(const sp<VendorTagDescriptor>& desc);
+
+        /**
+         * Clears the global vendor tag descriptor used by this process.
+         */
+        static void clearGlobalVendorTagDescriptor();
+
+        /**
+         * Returns the global vendor tag descriptor used by this process.
+         * This will contain NULL if no vendor tags are defined.
+         */
+        static sp<VendorTagDescriptor> getGlobalVendorTagDescriptor();
+    protected:
+        VendorTagDescriptor();
+        KeyedVector<uint32_t, String8> mTagToNameMap;
+        KeyedVector<uint32_t, String8> mTagToSectionMap;
+        KeyedVector<uint32_t, int32_t> mTagToTypeMap;
+        // must be int32_t to be compatible with Parcel::writeInt32
+        int32_t mTagCount;
+    private:
+        vendor_tag_ops mVendorOps;
+};
+
+} /* namespace android */
+
+#define VENDOR_TAG_DESCRIPTOR_H
+#endif /* VENDOR_TAG_DESCRIPTOR_H */
diff --git a/include/media/AudioTrack.h b/include/media/AudioTrack.h
index 7d23d02..647748b 100644
--- a/include/media/AudioTrack.h
+++ b/include/media/AudioTrack.h
@@ -556,8 +556,11 @@
      *      WOULD_BLOCK         when obtainBuffer() returns same, or
      *                          AudioTrack was stopped during the write
      *      or any other error code returned by IAudioTrack::start() or restoreTrack_l().
+     * Default behavior is to only return until all data has been transferred. Set 'blocking' to
+     * false for the method to return immediately without waiting to try multiple times to write
+     * the full content of the buffer.
      */
-            ssize_t     write(const void* buffer, size_t size);
+            ssize_t     write(const void* buffer, size_t size, bool blocking = true);
 
     /*
      * Dumps the state of an audio track.
@@ -745,7 +748,6 @@
     sp<AudioTrackClientProxy>       mProxy;         // primary owner of the memory
 
     bool                    mInUnderrun;            // whether track is currently in underrun state
-    String8                 mName;                  // server's name for this IAudioTrack
     uint32_t                mPausedPosition;
 
 private:
diff --git a/include/media/IAudioFlinger.h b/include/media/IAudioFlinger.h
index 7c5f33a..9101f06 100644
--- a/include/media/IAudioFlinger.h
+++ b/include/media/IAudioFlinger.h
@@ -73,10 +73,6 @@
                                 audio_io_handle_t output,
                                 pid_t tid,  // -1 means unused, otherwise must be valid non-0
                                 int *sessionId,
-                                // input: ignored
-                                // output: server's description of IAudioTrack for display in logs.
-                                // Don't attempt to parse, as the format could change.
-                                String8& name,
                                 int clientUid,
                                 status_t *status) = 0;
 
diff --git a/include/media/stagefright/ACodec.h b/include/media/stagefright/ACodec.h
index 36f2a67..863a7d5 100644
--- a/include/media/stagefright/ACodec.h
+++ b/include/media/stagefright/ACodec.h
@@ -67,8 +67,6 @@
 
     void signalRequestIDRFrame();
 
-    bool isConfiguredForAdaptivePlayback() { return mIsConfiguredForAdaptivePlayback; }
-
     struct PortDescription : public RefBase {
         size_t countBuffers();
         IOMX::buffer_id bufferIDAt(size_t index) const;
@@ -178,6 +176,8 @@
     sp<MemoryDealer> mDealer[2];
 
     sp<ANativeWindow> mNativeWindow;
+    sp<AMessage> mInputFormat;
+    sp<AMessage> mOutputFormat;
 
     Vector<BufferInfo> mBuffers[2];
     bool mPortEOS[2];
@@ -189,7 +189,6 @@
     bool mIsEncoder;
     bool mUseMetadataOnEncoderOutput;
     bool mShutdownInProgress;
-    bool mIsConfiguredForAdaptivePlayback;
 
     // If "mKeepComponentAllocated" we only transition back to Loaded state
     // and do not release the component instance.
@@ -203,6 +202,7 @@
     unsigned mDequeueCounter;
     bool mStoreMetaDataInOutputBuffers;
     int32_t mMetaDataBuffersToSubmit;
+    size_t mNumUndequeuedBuffers;
 
     int64_t mRepeatFrameDelayUs;
     int64_t mMaxPtsGapUs;
@@ -305,6 +305,7 @@
     void processDeferredMessages();
 
     void sendFormatChange(const sp<AMessage> &reply);
+    status_t getPortFormat(OMX_U32 portIndex, sp<AMessage> &notify);
 
     void signalError(
             OMX_ERRORTYPE error = OMX_ErrorUndefined,
diff --git a/include/media/stagefright/MediaCodec.h b/include/media/stagefright/MediaCodec.h
index 76aa503..276543b 100644
--- a/include/media/stagefright/MediaCodec.h
+++ b/include/media/stagefright/MediaCodec.h
@@ -106,6 +106,7 @@
     status_t signalEndOfInputStream();
 
     status_t getOutputFormat(sp<AMessage> *format) const;
+    status_t getInputFormat(sp<AMessage> *format) const;
 
     status_t getInputBuffers(Vector<sp<ABuffer> > *buffers) const;
     status_t getOutputBuffers(Vector<sp<ABuffer> > *buffers) const;
@@ -159,6 +160,7 @@
         kWhatGetBuffers                     = 'getB',
         kWhatFlush                          = 'flus',
         kWhatGetOutputFormat                = 'getO',
+        kWhatGetInputFormat                 = 'getI',
         kWhatDequeueInputTimedOut           = 'dITO',
         kWhatDequeueOutputTimedOut          = 'dOTO',
         kWhatCodecNotify                    = 'codc',
@@ -199,6 +201,7 @@
     sp<Surface> mNativeWindow;
     SoftwareRenderer *mSoftRenderer;
     sp<AMessage> mOutputFormat;
+    sp<AMessage> mInputFormat;
 
     List<size_t> mAvailPortBuffers[2];
     Vector<BufferInfo> mPortBuffers[2];
diff --git a/include/media/stagefright/SurfaceMediaSource.h b/include/media/stagefright/SurfaceMediaSource.h
index db5f947..59e83c2 100644
--- a/include/media/stagefright/SurfaceMediaSource.h
+++ b/include/media/stagefright/SurfaceMediaSource.h
@@ -139,6 +139,10 @@
     // frames is separate than the one calling stop.
     virtual void onBuffersReleased();
 
+    // SurfaceMediaSource can't handle sideband streams, so this is not expected
+    // to ever be called. Does nothing.
+    virtual void onSidebandStreamChanged();
+
     static bool isExternalFormat(uint32_t format);
 
 private:
diff --git a/libvideoeditor/lvpp/Android.mk b/libvideoeditor/lvpp/Android.mk
index 860d351..77a21ac 100755
--- a/libvideoeditor/lvpp/Android.mk
+++ b/libvideoeditor/lvpp/Android.mk
@@ -99,6 +99,8 @@
     -DUSE_STAGEFRIGHT_READERS \
     -DUSE_STAGEFRIGHT_3GPP_READER
 
+LOCAL_32_BIT_ONLY := true
+
 include $(BUILD_SHARED_LIBRARY)
 
 #include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/libvideoeditor/lvpp/NativeWindowRenderer.cpp b/libvideoeditor/lvpp/NativeWindowRenderer.cpp
index 8b362ef..be0f747 100755
--- a/libvideoeditor/lvpp/NativeWindowRenderer.cpp
+++ b/libvideoeditor/lvpp/NativeWindowRenderer.cpp
@@ -568,9 +568,11 @@
 RenderInput::RenderInput(NativeWindowRenderer* renderer, GLuint textureId)
     : mRenderer(renderer)
     , mTextureId(textureId) {
-    sp<BufferQueue> bq = new BufferQueue();
-    mST = new GLConsumer(bq, mTextureId);
-    mSTC = new Surface(bq);
+    sp<IGraphicBufferProducer> producer;
+    sp<IGraphicBufferConsumer> consumer;
+    BufferQueue::createBufferQueue(&producer, &consumer);
+    mST = new GLConsumer(consumer, mTextureId);
+    mSTC = new Surface(producer);
     native_window_connect(mSTC.get(), NATIVE_WINDOW_API_MEDIA);
 }
 
diff --git a/libvideoeditor/vss/src/Android.mk b/libvideoeditor/vss/src/Android.mk
index 0caa15b..8856c41 100755
--- a/libvideoeditor/vss/src/Android.mk
+++ b/libvideoeditor/vss/src/Android.mk
@@ -96,4 +96,6 @@
     -DM4xVSS_RESERVED_MOOV_DISK_SPACEno \
     -DDECODE_GIF_ON_SAVING
 
+LOCAL_32_BIT_ONLY := true
+
 include $(BUILD_SHARED_LIBRARY)
diff --git a/libvideoeditor/vss/stagefrightshells/src/Android.mk b/libvideoeditor/vss/stagefrightshells/src/Android.mk
index 9188942..a060c0d 100755
--- a/libvideoeditor/vss/stagefrightshells/src/Android.mk
+++ b/libvideoeditor/vss/stagefrightshells/src/Android.mk
@@ -64,4 +64,6 @@
 
 LOCAL_MODULE_TAGS := optional
 
+LOCAL_32_BIT_ONLY := true
+
 include $(BUILD_STATIC_LIBRARY)
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index ae47201..20c1cdb 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -1024,7 +1024,6 @@
                                                       output,
                                                       tid,
                                                       &mSessionId,
-                                                      mName,
                                                       mClientUid,
                                                       &status);
 
@@ -1281,8 +1280,7 @@
     if (mState == STATE_ACTIVE) {
         audio_track_cblk_t* cblk = mCblk;
         if (android_atomic_and(~CBLK_DISABLED, &cblk->mFlags) & CBLK_DISABLED) {
-            ALOGW("releaseBuffer() track %p name=%s disabled due to previous underrun, restarting",
-                    this, mName.string());
+            ALOGW("releaseBuffer() track %p disabled due to previous underrun, restarting", this);
             // FIXME ignoring status
             mAudioTrack->start();
         }
@@ -1291,7 +1289,7 @@
 
 // -------------------------------------------------------------------------
 
-ssize_t AudioTrack::write(const void* buffer, size_t userSize)
+ssize_t AudioTrack::write(const void* buffer, size_t userSize, bool blocking)
 {
     if (mTransfer != TRANSFER_SYNC || mIsTimed) {
         return INVALID_OPERATION;
@@ -1310,7 +1308,8 @@
     while (userSize >= mFrameSize) {
         audioBuffer.frameCount = userSize / mFrameSize;
 
-        status_t err = obtainBuffer(&audioBuffer, &ClientProxy::kForever);
+        status_t err = obtainBuffer(&audioBuffer,
+                blocking ? &ClientProxy::kForever : &ClientProxy::kNonBlocking);
         if (err < 0) {
             if (written > 0) {
                 break;
diff --git a/media/libmedia/IAudioFlinger.cpp b/media/libmedia/IAudioFlinger.cpp
index a9a9f1a..762681e 100644
--- a/media/libmedia/IAudioFlinger.cpp
+++ b/media/libmedia/IAudioFlinger.cpp
@@ -95,7 +95,6 @@
                                 audio_io_handle_t output,
                                 pid_t tid,
                                 int *sessionId,
-                                String8& name,
                                 int clientUid,
                                 status_t *status)
     {
@@ -140,7 +139,6 @@
             if (sessionId != NULL) {
                 *sessionId = lSessionId;
             }
-            name = reply.readString8();
             lStatus = reply.readInt32();
             track = interface_cast<IAudioTrack>(reply.readStrongBinder());
             if (lStatus == NO_ERROR) {
@@ -808,7 +806,6 @@
             pid_t tid = (pid_t) data.readInt32();
             int sessionId = data.readInt32();
             int clientUid = data.readInt32();
-            String8 name;
             status_t status;
             sp<IAudioTrack> track;
             if ((haveSharedBuffer && (buffer == 0)) ||
@@ -819,13 +816,12 @@
                 track = createTrack(
                         (audio_stream_type_t) streamType, sampleRate, format,
                         channelMask, &frameCount, &flags, buffer, output, tid,
-                        &sessionId, name, clientUid, &status);
+                        &sessionId, clientUid, &status);
                 LOG_ALWAYS_FATAL_IF((track != 0) != (status == NO_ERROR));
             }
             reply->writeInt32(frameCount);
             reply->writeInt32(flags);
             reply->writeInt32(sessionId);
-            reply->writeString8(name);
             reply->writeInt32(status);
             reply->writeStrongBinder(track->asBinder());
             return NO_ERROR;
diff --git a/media/libmediaplayerservice/Android.mk b/media/libmediaplayerservice/Android.mk
index 4189a5e..caf2dfc 100644
--- a/media/libmediaplayerservice/Android.mk
+++ b/media/libmediaplayerservice/Android.mk
@@ -53,6 +53,8 @@
 
 LOCAL_MODULE:= libmediaplayerservice
 
+LOCAL_32_BIT_ONLY := true
+
 include $(BUILD_SHARED_LIBRARY)
 
 include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
index a750ad0..d8d939a 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
@@ -31,13 +31,10 @@
 
 #include "ATSParser.h"
 
-#include "SoftwareRenderer.h"
-
 #include <media/stagefright/foundation/hexdump.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
-#include <media/stagefright/ACodec.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaErrors.h>
 #include <media/stagefright/MetaData.h>
@@ -146,7 +143,6 @@
     : mUIDValid(false),
       mSourceFlags(0),
       mVideoIsAVC(false),
-      mNeedsSwRenderer(false),
       mAudioEOS(false),
       mVideoEOS(false),
       mScanSourcesPending(false),
@@ -442,7 +438,6 @@
             ALOGV("kWhatStart");
 
             mVideoIsAVC = false;
-            mNeedsSwRenderer = false;
             mAudioEOS = false;
             mVideoEOS = false;
             mSkipRenderingAudioUntilMediaTimeUs = -1;
@@ -533,24 +528,21 @@
         {
             bool audio = msg->what() == kWhatAudioNotify;
 
-            sp<AMessage> codecRequest;
-            CHECK(msg->findMessage("codec-request", &codecRequest));
-
             int32_t what;
-            CHECK(codecRequest->findInt32("what", &what));
+            CHECK(msg->findInt32("what", &what));
 
-            if (what == ACodec::kWhatFillThisBuffer) {
+            if (what == Decoder::kWhatFillThisBuffer) {
                 status_t err = feedDecoderInputData(
-                        audio, codecRequest);
+                        audio, msg);
 
                 if (err == -EWOULDBLOCK) {
                     if (mSource->feedMoreTSData() == OK) {
                         msg->post(10000ll);
                     }
                 }
-            } else if (what == ACodec::kWhatEOS) {
+            } else if (what == Decoder::kWhatEOS) {
                 int32_t err;
-                CHECK(codecRequest->findInt32("err", &err));
+                CHECK(msg->findInt32("err", &err));
 
                 if (err == ERROR_END_OF_STREAM) {
                     ALOGV("got %s decoder EOS", audio ? "audio" : "video");
@@ -561,7 +553,7 @@
                 }
 
                 mRenderer->queueEOS(audio, err);
-            } else if (what == ACodec::kWhatFlushCompleted) {
+            } else if (what == Decoder::kWhatFlushCompleted) {
                 bool needShutdown;
 
                 if (audio) {
@@ -590,14 +582,17 @@
                 }
 
                 finishFlushIfPossible();
-            } else if (what == ACodec::kWhatOutputFormatChanged) {
+            } else if (what == Decoder::kWhatOutputFormatChanged) {
+                sp<AMessage> format;
+                CHECK(msg->findMessage("format", &format));
+
                 if (audio) {
                     int32_t numChannels;
-                    CHECK(codecRequest->findInt32(
+                    CHECK(format->findInt32(
                                 "channel-count", &numChannels));
 
                     int32_t sampleRate;
-                    CHECK(codecRequest->findInt32("sample-rate", &sampleRate));
+                    CHECK(format->findInt32("sample-rate", &sampleRate));
 
                     ALOGV("Audio output format changed to %d Hz, %d channels",
                          sampleRate, numChannels);
@@ -621,7 +616,7 @@
                     }
 
                     int32_t channelMask;
-                    if (!codecRequest->findInt32("channel-mask", &channelMask)) {
+                    if (!format->findInt32("channel-mask", &channelMask)) {
                         channelMask = CHANNEL_MASK_USE_CHANNEL_ORDER;
                     }
 
@@ -642,11 +637,11 @@
                     // video
 
                     int32_t width, height;
-                    CHECK(codecRequest->findInt32("width", &width));
-                    CHECK(codecRequest->findInt32("height", &height));
+                    CHECK(format->findInt32("width", &width));
+                    CHECK(format->findInt32("height", &height));
 
                     int32_t cropLeft, cropTop, cropRight, cropBottom;
-                    CHECK(codecRequest->findRect(
+                    CHECK(format->findRect(
                                 "crop",
                                 &cropLeft, &cropTop, &cropRight, &cropBottom));
 
@@ -679,22 +674,8 @@
 
                     notifyListener(
                             MEDIA_SET_VIDEO_SIZE, displayWidth, displayHeight);
-
-                    if (mNeedsSwRenderer && mNativeWindow != NULL) {
-                        int32_t colorFormat;
-                        CHECK(codecRequest->findInt32("color-format", &colorFormat));
-
-                        sp<MetaData> meta = new MetaData;
-                        meta->setInt32(kKeyWidth, width);
-                        meta->setInt32(kKeyHeight, height);
-                        meta->setRect(kKeyCropRect, cropLeft, cropTop, cropRight, cropBottom);
-                        meta->setInt32(kKeyColorFormat, colorFormat);
-
-                        mRenderer->setSoftRenderer(
-                                new SoftwareRenderer(mNativeWindow->getNativeWindow(), meta));
-                    }
                 }
-            } else if (what == ACodec::kWhatShutdownCompleted) {
+            } else if (what == Decoder::kWhatShutdownCompleted) {
                 ALOGV("%s shutdown completed", audio ? "audio" : "video");
                 if (audio) {
                     mAudioDecoder.clear();
@@ -709,22 +690,15 @@
                 }
 
                 finishFlushIfPossible();
-            } else if (what == ACodec::kWhatError) {
+            } else if (what == Decoder::kWhatError) {
                 ALOGE("Received error from %s decoder, aborting playback.",
                      audio ? "audio" : "video");
 
                 mRenderer->queueEOS(audio, UNKNOWN_ERROR);
-            } else if (what == ACodec::kWhatDrainThisBuffer) {
-                renderBuffer(audio, codecRequest);
-            } else if (what == ACodec::kWhatComponentAllocated) {
-                if (!audio) {
-                    AString name;
-                    CHECK(codecRequest->findString("componentName", &name));
-                    mNeedsSwRenderer = name.startsWith("OMX.google.");
-                }
-            } else if (what != ACodec::kWhatComponentConfigured
-                    && what != ACodec::kWhatBuffersAllocated) {
-                ALOGV("Unhandled codec notification %d '%c%c%c%c'.",
+            } else if (what == Decoder::kWhatDrainThisBuffer) {
+                renderBuffer(audio, msg);
+            } else {
+                ALOGV("Unhandled decoder notification %d '%c%c%c%c'.",
                       what,
                       what >> 24,
                       (what >> 16) & 0xff,
@@ -925,8 +899,7 @@
 
     *decoder = audio ? new Decoder(notify) :
                        new Decoder(notify, mNativeWindow);
-    looper()->registerHandler(*decoder);
-
+    (*decoder)->init();
     (*decoder)->configure(format);
 
     return OK;
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.h b/media/libmediaplayerservice/nuplayer/NuPlayer.h
index 9dfe4a0..f1d3d55 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.h
@@ -24,7 +24,6 @@
 
 namespace android {
 
-struct ACodec;
 struct MetaData;
 struct NuPlayerDriver;
 
@@ -118,7 +117,6 @@
     sp<MediaPlayerBase::AudioSink> mAudioSink;
     sp<Decoder> mVideoDecoder;
     bool mVideoIsAVC;
-    bool mNeedsSwRenderer;
     sp<Decoder> mAudioDecoder;
     sp<Renderer> mRenderer;
 
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
index 2423fd5..469c9ca 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
@@ -17,14 +17,17 @@
 //#define LOG_NDEBUG 0
 #define LOG_TAG "NuPlayerDecoder"
 #include <utils/Log.h>
+#include <inttypes.h>
 
 #include "NuPlayerDecoder.h"
 
+#include <media/ICrypto.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
-#include <media/stagefright/ACodec.h>
+#include <media/stagefright/MediaCodec.h>
 #include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/MediaErrors.h>
 
 namespace android {
 
@@ -32,70 +35,404 @@
         const sp<AMessage> &notify,
         const sp<NativeWindowWrapper> &nativeWindow)
     : mNotify(notify),
-      mNativeWindow(nativeWindow) {
+      mNativeWindow(nativeWindow),
+      mBufferGeneration(0),
+      mComponentName("decoder") {
+    // Every decoder has its own looper because MediaCodec operations
+    // are blocking, but NuPlayer needs asynchronous operations.
+    mDecoderLooper = new ALooper;
+    mDecoderLooper->setName("NuPlayerDecoder");
+    mDecoderLooper->start(false, false, ANDROID_PRIORITY_AUDIO);
+
+    mCodecLooper = new ALooper;
+    mCodecLooper->setName("NuPlayerDecoder-MC");
+    mCodecLooper->start(false, false, ANDROID_PRIORITY_AUDIO);
 }
 
 NuPlayer::Decoder::~Decoder() {
 }
 
-void NuPlayer::Decoder::configure(const sp<AMessage> &format) {
+void NuPlayer::Decoder::onConfigure(const sp<AMessage> &format) {
     CHECK(mCodec == NULL);
 
+    ++mBufferGeneration;
+
     AString mime;
     CHECK(format->findString("mime", &mime));
 
-    sp<AMessage> notifyMsg =
-        new AMessage(kWhatCodecNotify, id());
-
-    mCSDIndex = 0;
-    for (size_t i = 0;; ++i) {
-        sp<ABuffer> csd;
-        if (!format->findBuffer(StringPrintf("csd-%d", i).c_str(), &csd)) {
-            break;
-        }
-
-        mCSD.push(csd);
+    sp<Surface> surface = NULL;
+    if (mNativeWindow != NULL) {
+        surface = mNativeWindow->getSurfaceTextureClient();
     }
 
+    mComponentName = mime;
+    mComponentName.append(" decoder");
+    ALOGV("[%s] onConfigure (surface=%p)", mComponentName.c_str(), surface.get());
+
+    mCodec = MediaCodec::CreateByType(mCodecLooper, mime.c_str(), false /* encoder */);
+    if (mCodec == NULL) {
+        ALOGE("Failed to create %s decoder", mime.c_str());
+        handleError(UNKNOWN_ERROR);
+        return;
+    }
+
+    mCodec->getName(&mComponentName);
+
     if (mNativeWindow != NULL) {
-        format->setObject("native-window", mNativeWindow);
+        // disconnect from surface as MediaCodec will reconnect
+        CHECK_EQ((int)NO_ERROR,
+                native_window_api_disconnect(
+                        surface.get(),
+                        NATIVE_WINDOW_API_MEDIA));
+    }
+    status_t err = mCodec->configure(
+            format, surface, NULL /* crypto */, 0 /* flags */);
+    if (err != OK) {
+        ALOGE("Failed to configure %s decoder (err=%d)", mComponentName.c_str(), err);
+        handleError(err);
+        return;
+    }
+    // the following should work in configured state
+    CHECK_EQ((status_t)OK, mCodec->getOutputFormat(&mOutputFormat));
+    CHECK_EQ((status_t)OK, mCodec->getInputFormat(&mInputFormat));
+
+    err = mCodec->start();
+    if (err != OK) {
+        ALOGE("Failed to start %s decoder (err=%d)", mComponentName.c_str(), err);
+        handleError(err);
+        return;
     }
 
-    // Current video decoders do not return from OMX_FillThisBuffer
-    // quickly, violating the OpenMAX specs, until that is remedied
-    // we need to invest in an extra looper to free the main event
-    // queue.
-    bool needDedicatedLooper = !strncasecmp(mime.c_str(), "video/", 6);
+    // the following should work after start
+    CHECK_EQ((status_t)OK, mCodec->getInputBuffers(&mInputBuffers));
+    CHECK_EQ((status_t)OK, mCodec->getOutputBuffers(&mOutputBuffers));
+    ALOGV("[%s] got %zu input and %zu output buffers",
+            mComponentName.c_str(),
+            mInputBuffers.size(),
+            mOutputBuffers.size());
 
-    mFormat = format;
-    mCodec = new ACodec;
+    requestCodecNotification();
+}
 
-    if (needDedicatedLooper && mCodecLooper == NULL) {
-        mCodecLooper = new ALooper;
-        mCodecLooper->setName("NuPlayerDecoder");
-        mCodecLooper->start(false, false, ANDROID_PRIORITY_AUDIO);
+void NuPlayer::Decoder::requestCodecNotification() {
+    if (mCodec != NULL) {
+        sp<AMessage> reply = new AMessage(kWhatCodecNotify, id());
+        reply->setInt32("generation", mBufferGeneration);
+        mCodec->requestActivityNotification(reply);
+    }
+}
+
+bool NuPlayer::Decoder::isStaleReply(const sp<AMessage> &msg) {
+    int32_t generation;
+    CHECK(msg->findInt32("generation", &generation));
+    return generation != mBufferGeneration;
+}
+
+void NuPlayer::Decoder::init() {
+    mDecoderLooper->registerHandler(this);
+}
+
+void NuPlayer::Decoder::configure(const sp<AMessage> &format) {
+    sp<AMessage> msg = new AMessage(kWhatConfigure, id());
+    msg->setMessage("format", format);
+    msg->post();
+}
+
+void NuPlayer::Decoder::handleError(int32_t err)
+{
+    sp<AMessage> notify = mNotify->dup();
+    notify->setInt32("what", kWhatError);
+    notify->setInt32("err", err);
+    notify->post();
+}
+
+bool NuPlayer::Decoder::handleAnInputBuffer() {
+    size_t bufferIx = -1;
+    status_t res = mCodec->dequeueInputBuffer(&bufferIx);
+    ALOGV("[%s] dequeued input: %d",
+            mComponentName.c_str(), res == OK ? (int)bufferIx : res);
+    if (res != OK) {
+        if (res != -EAGAIN) {
+            handleError(res);
+        }
+        return false;
     }
 
-    (needDedicatedLooper ? mCodecLooper : looper())->registerHandler(mCodec);
+    CHECK_LT(bufferIx, mInputBuffers.size());
 
-    mCodec->setNotificationMessage(notifyMsg);
-    mCodec->initiateSetup(format);
+    sp<AMessage> reply = new AMessage(kWhatInputBufferFilled, id());
+    reply->setSize("buffer-ix", bufferIx);
+    reply->setInt32("generation", mBufferGeneration);
+
+    sp<AMessage> notify = mNotify->dup();
+    notify->setInt32("what", kWhatFillThisBuffer);
+    notify->setBuffer("buffer", mInputBuffers[bufferIx]);
+    notify->setMessage("reply", reply);
+    notify->post();
+    return true;
+}
+
+void android::NuPlayer::Decoder::onInputBufferFilled(const sp<AMessage> &msg) {
+    size_t bufferIx;
+    CHECK(msg->findSize("buffer-ix", &bufferIx));
+    CHECK_LT(bufferIx, mInputBuffers.size());
+    sp<ABuffer> codecBuffer = mInputBuffers[bufferIx];
+
+    sp<ABuffer> buffer;
+    bool hasBuffer = msg->findBuffer("buffer", &buffer);
+    if (buffer == NULL /* includes !hasBuffer */) {
+        int32_t streamErr = ERROR_END_OF_STREAM;
+        CHECK(msg->findInt32("err", &streamErr) || !hasBuffer);
+
+        if (streamErr == OK) {
+            /* buffers are returned to hold on to */
+            return;
+        }
+
+        // attempt to queue EOS
+        status_t err = mCodec->queueInputBuffer(
+                bufferIx,
+                0,
+                0,
+                0,
+                MediaCodec::BUFFER_FLAG_EOS);
+        if (streamErr == ERROR_END_OF_STREAM && err != OK) {
+            streamErr = err;
+            // err will not be ERROR_END_OF_STREAM
+        }
+
+        if (streamErr != ERROR_END_OF_STREAM) {
+            handleError(streamErr);
+        }
+    } else {
+        int64_t timeUs = 0;
+        uint32_t flags = 0;
+        CHECK(buffer->meta()->findInt64("timeUs", &timeUs));
+
+        int32_t eos;
+        // we do not expect CODECCONFIG or SYNCFRAME for decoder
+        if (buffer->meta()->findInt32("eos", &eos) && eos) {
+            flags |= MediaCodec::BUFFER_FLAG_EOS;
+        }
+
+        // copy into codec buffer
+        if (buffer != codecBuffer) {
+            CHECK_LE(buffer->size(), codecBuffer->capacity());
+            codecBuffer->setRange(0, buffer->size());
+            memcpy(codecBuffer->data(), buffer->data(), buffer->size());
+        }
+
+        status_t err = mCodec->queueInputBuffer(
+                        bufferIx,
+                        codecBuffer->offset(),
+                        codecBuffer->size(),
+                        timeUs,
+                        flags);
+        if (err != OK) {
+            ALOGE("Failed to queue input buffer for %s (err=%d)",
+                    mComponentName.c_str(), err);
+            handleError(err);
+        }
+    }
+}
+
+bool NuPlayer::Decoder::handleAnOutputBuffer() {
+    size_t bufferIx = -1;
+    size_t offset;
+    size_t size;
+    int64_t timeUs;
+    uint32_t flags;
+    status_t res = mCodec->dequeueOutputBuffer(
+            &bufferIx, &offset, &size, &timeUs, &flags);
+
+    if (res != OK) {
+        ALOGV("[%s] dequeued output: %d", mComponentName.c_str(), res);
+    } else {
+        ALOGV("[%s] dequeued output: %d (time=%lld flags=%" PRIu32 ")",
+                mComponentName.c_str(), (int)bufferIx, timeUs, flags);
+    }
+
+    if (res == INFO_OUTPUT_BUFFERS_CHANGED) {
+        res = mCodec->getOutputBuffers(&mOutputBuffers);
+        if (res != OK) {
+            ALOGE("Failed to get output buffers for %s after INFO event (err=%d)",
+                    mComponentName.c_str(), res);
+            handleError(res);
+            return false;
+        }
+        // NuPlayer ignores this
+        return true;
+    } else if (res == INFO_FORMAT_CHANGED) {
+        sp<AMessage> format = new AMessage();
+        res = mCodec->getOutputFormat(&format);
+        if (res != OK) {
+            ALOGE("Failed to get output format for %s after INFO event (err=%d)",
+                    mComponentName.c_str(), res);
+            handleError(res);
+            return false;
+        }
+
+        sp<AMessage> notify = mNotify->dup();
+        notify->setInt32("what", kWhatOutputFormatChanged);
+        notify->setMessage("format", format);
+        notify->post();
+        return true;
+    } else if (res == INFO_DISCONTINUITY) {
+        // nothing to do
+        return true;
+    } else if (res != OK) {
+        if (res != -EAGAIN) {
+            handleError(res);
+        }
+        return false;
+    }
+
+    CHECK_LT(bufferIx, mOutputBuffers.size());
+    sp<ABuffer> buffer = mOutputBuffers[bufferIx];
+    buffer->setRange(offset, size);
+    buffer->meta()->clear();
+    buffer->meta()->setInt64("timeUs", timeUs);
+    if (flags & MediaCodec::BUFFER_FLAG_EOS) {
+        buffer->meta()->setInt32("eos", true);
+    }
+    // we do not expect CODECCONFIG or SYNCFRAME for decoder
+
+    sp<AMessage> reply = new AMessage(kWhatRenderBuffer, id());
+    reply->setSize("buffer-ix", bufferIx);
+    reply->setInt32("generation", mBufferGeneration);
+
+    sp<AMessage> notify = mNotify->dup();
+    notify->setInt32("what", kWhatDrainThisBuffer);
+    notify->setBuffer("buffer", buffer);
+    notify->setMessage("reply", reply);
+    notify->post();
+
+    // FIXME: This should be handled after rendering is complete,
+    // but Renderer needs it now
+    if (flags & MediaCodec::BUFFER_FLAG_EOS) {
+        ALOGV("queueing eos [%s]", mComponentName.c_str());
+        sp<AMessage> notify = mNotify->dup();
+        notify->setInt32("what", kWhatEOS);
+        notify->setInt32("err", ERROR_END_OF_STREAM);
+        notify->post();
+    }
+    return true;
+}
+
+void NuPlayer::Decoder::onRenderBuffer(const sp<AMessage> &msg) {
+    status_t err;
+    int32_t render;
+    size_t bufferIx;
+    CHECK(msg->findSize("buffer-ix", &bufferIx));
+    if (msg->findInt32("render", &render) && render) {
+        err = mCodec->renderOutputBufferAndRelease(bufferIx);
+    } else {
+        err = mCodec->releaseOutputBuffer(bufferIx);
+    }
+    if (err != OK) {
+        ALOGE("failed to release output buffer for %s (err=%d)",
+                mComponentName.c_str(), err);
+        handleError(err);
+    }
+}
+
+void NuPlayer::Decoder::onFlush() {
+    status_t err = OK;
+    if (mCodec != NULL) {
+        err = mCodec->flush();
+        ++mBufferGeneration;
+    }
+
+    if (err != OK) {
+        ALOGE("failed to flush %s (err=%d)", mComponentName.c_str(), err);
+        handleError(err);
+        return;
+    }
+
+    sp<AMessage> notify = mNotify->dup();
+    notify->setInt32("what", kWhatFlushCompleted);
+    notify->post();
+}
+
+void NuPlayer::Decoder::onShutdown() {
+    status_t err = OK;
+    if (mCodec != NULL) {
+        err = mCodec->release();
+        mCodec = NULL;
+        ++mBufferGeneration;
+
+        if (mNativeWindow != NULL) {
+            // reconnect to surface as MediaCodec disconnected from it
+            CHECK_EQ((int)NO_ERROR,
+                    native_window_api_connect(
+                            mNativeWindow->getNativeWindow().get(),
+                            NATIVE_WINDOW_API_MEDIA));
+        }
+        mComponentName = "decoder";
+    }
+
+    if (err != OK) {
+        ALOGE("failed to release %s (err=%d)", mComponentName.c_str(), err);
+        handleError(err);
+        return;
+    }
+
+    sp<AMessage> notify = mNotify->dup();
+    notify->setInt32("what", kWhatShutdownCompleted);
+    notify->post();
 }
 
 void NuPlayer::Decoder::onMessageReceived(const sp<AMessage> &msg) {
+    ALOGV("[%s] onMessage: %s", mComponentName.c_str(), msg->debugString().c_str());
+
     switch (msg->what()) {
+        case kWhatConfigure:
+        {
+            sp<AMessage> format;
+            CHECK(msg->findMessage("format", &format));
+            onConfigure(format);
+            break;
+        }
+
         case kWhatCodecNotify:
         {
-            int32_t what;
-            CHECK(msg->findInt32("what", &what));
+            if (!isStaleReply(msg)) {
+                while (handleAnInputBuffer()) {
+                }
 
-            if (what == ACodec::kWhatFillThisBuffer) {
-                onFillThisBuffer(msg);
-            } else {
-                sp<AMessage> notify = mNotify->dup();
-                notify->setMessage("codec-request", msg);
-                notify->post();
+                while (handleAnOutputBuffer()) {
+                }
             }
+
+            requestCodecNotification();
+            break;
+        }
+
+        case kWhatInputBufferFilled:
+        {
+            if (!isStaleReply(msg)) {
+                onInputBufferFilled(msg);
+            }
+            break;
+        }
+
+        case kWhatRenderBuffer:
+        {
+            if (!isStaleReply(msg)) {
+                onRenderBuffer(msg);
+            }
+            break;
+        }
+
+        case kWhatFlush:
+        {
+            onFlush();
+            break;
+        }
+
+        case kWhatShutdown:
+        {
+            onShutdown();
             break;
         }
 
@@ -105,47 +442,16 @@
     }
 }
 
-void NuPlayer::Decoder::onFillThisBuffer(const sp<AMessage> &msg) {
-    sp<AMessage> reply;
-    CHECK(msg->findMessage("reply", &reply));
-
-#if 0
-    sp<ABuffer> outBuffer;
-    CHECK(msg->findBuffer("buffer", &outBuffer));
-#else
-    sp<ABuffer> outBuffer;
-#endif
-
-    if (mCSDIndex < mCSD.size()) {
-        outBuffer = mCSD.editItemAt(mCSDIndex++);
-        outBuffer->meta()->setInt64("timeUs", 0);
-
-        reply->setBuffer("buffer", outBuffer);
-        reply->post();
-        return;
-    }
-
-    sp<AMessage> notify = mNotify->dup();
-    notify->setMessage("codec-request", msg);
-    notify->post();
-}
-
 void NuPlayer::Decoder::signalFlush() {
-    if (mCodec != NULL) {
-        mCodec->signalFlush();
-    }
+    (new AMessage(kWhatFlush, id()))->post();
 }
 
 void NuPlayer::Decoder::signalResume() {
-    if (mCodec != NULL) {
-        mCodec->signalResume();
-    }
+    // nothing to do
 }
 
 void NuPlayer::Decoder::initiateShutdown() {
-    if (mCodec != NULL) {
-        mCodec->initiateShutdown();
-    }
+    (new AMessage(kWhatShutdown, id()))->post();
 }
 
 bool NuPlayer::Decoder::supportsSeamlessAudioFormatChange(const sp<AMessage> &targetFormat) const {
@@ -163,14 +469,16 @@
         const char * keys[] = { "channel-count", "sample-rate", "is-adts" };
         for (unsigned int i = 0; i < sizeof(keys) / sizeof(keys[0]); i++) {
             int32_t oldVal, newVal;
-            if (!mFormat->findInt32(keys[i], &oldVal) || !targetFormat->findInt32(keys[i], &newVal)
-                    || oldVal != newVal) {
+            if (!mOutputFormat->findInt32(keys[i], &oldVal) ||
+                    !targetFormat->findInt32(keys[i], &newVal) ||
+                    oldVal != newVal) {
                 return false;
             }
         }
 
         sp<ABuffer> oldBuf, newBuf;
-        if (mFormat->findBuffer("csd-0", &oldBuf) && targetFormat->findBuffer("csd-0", &newBuf)) {
+        if (mOutputFormat->findBuffer("csd-0", &oldBuf) &&
+                targetFormat->findBuffer("csd-0", &newBuf)) {
             if (oldBuf->size() != newBuf->size()) {
                 return false;
             }
@@ -181,7 +489,7 @@
 }
 
 bool NuPlayer::Decoder::supportsSeamlessFormatChange(const sp<AMessage> &targetFormat) const {
-    if (mFormat == NULL) {
+    if (mOutputFormat == NULL) {
         return false;
     }
 
@@ -190,7 +498,7 @@
     }
 
     AString oldMime, newMime;
-    if (!mFormat->findString("mime", &oldMime)
+    if (!mOutputFormat->findString("mime", &oldMime)
             || !targetFormat->findString("mime", &newMime)
             || !(oldMime == newMime)) {
         return false;
@@ -201,7 +509,10 @@
     if (audio) {
         seamless = supportsSeamlessAudioFormatChange(targetFormat);
     } else {
-        seamless = mCodec != NULL && mCodec->isConfiguredForAdaptivePlayback();
+        int32_t isAdaptive;
+        seamless = (mCodec != NULL &&
+                mInputFormat->findInt32("adaptive-playback", &isAdaptive) &&
+                isAdaptive);
     }
 
     ALOGV("%s seamless support for %s", seamless ? "yes" : "no", oldMime.c_str());
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h
index 78ea74a..94243fc 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h
@@ -25,12 +25,14 @@
 namespace android {
 
 struct ABuffer;
+struct MediaCodec;
 
 struct NuPlayer::Decoder : public AHandler {
     Decoder(const sp<AMessage> &notify,
             const sp<NativeWindowWrapper> &nativeWindow = NULL);
 
     void configure(const sp<AMessage> &format);
+    void init();
 
     void signalFlush();
     void signalResume();
@@ -38,7 +40,18 @@
 
     bool supportsSeamlessFormatChange(const sp<AMessage> &to) const;
 
+    enum {
+        kWhatFillThisBuffer      = 'flTB',
+        kWhatDrainThisBuffer     = 'drTB',
+        kWhatOutputFormatChanged = 'fmtC',
+        kWhatFlushCompleted      = 'flsC',
+        kWhatShutdownCompleted   = 'shDC',
+        kWhatEOS                 = 'eos ',
+        kWhatError               = 'err ',
+    };
+
 protected:
+
     virtual ~Decoder();
 
     virtual void onMessageReceived(const sp<AMessage> &msg);
@@ -46,21 +59,40 @@
 private:
     enum {
         kWhatCodecNotify        = 'cdcN',
+        kWhatConfigure          = 'conf',
+        kWhatInputBufferFilled  = 'inpF',
+        kWhatRenderBuffer       = 'rndr',
+        kWhatFlush              = 'flus',
+        kWhatShutdown           = 'shuD',
     };
 
     sp<AMessage> mNotify;
     sp<NativeWindowWrapper> mNativeWindow;
 
-    sp<AMessage> mFormat;
-    sp<ACodec> mCodec;
+    sp<AMessage> mInputFormat;
+    sp<AMessage> mOutputFormat;
+    sp<MediaCodec> mCodec;
     sp<ALooper> mCodecLooper;
+    sp<ALooper> mDecoderLooper;
 
-    Vector<sp<ABuffer> > mCSD;
-    size_t mCSDIndex;
+    Vector<sp<ABuffer> > mInputBuffers;
+    Vector<sp<ABuffer> > mOutputBuffers;
 
-    sp<AMessage> makeFormat(const sp<MetaData> &meta);
+    void handleError(int32_t err);
+    bool handleAnInputBuffer();
+    bool handleAnOutputBuffer();
 
-    void onFillThisBuffer(const sp<AMessage> &msg);
+    void requestCodecNotification();
+    bool isStaleReply(const sp<AMessage> &msg);
+
+    void onConfigure(const sp<AMessage> &format);
+    void onFlush();
+    void onInputBufferFilled(const sp<AMessage> &msg);
+    void onRenderBuffer(const sp<AMessage> &msg);
+    void onShutdown();
+
+    int32_t mBufferGeneration;
+    AString mComponentName;
 
     bool supportsSeamlessAudioFormatChange(const sp<AMessage> &targetFormat) const;
 
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
index bf5271e..a070c1a 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
@@ -20,8 +20,6 @@
 
 #include "NuPlayerRenderer.h"
 
-#include "SoftwareRenderer.h"
-
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
@@ -36,7 +34,6 @@
         const sp<AMessage> &notify,
         uint32_t flags)
     : mAudioSink(sink),
-      mSoftRenderer(NULL),
       mNotify(notify),
       mFlags(flags),
       mNumFramesWritten(0),
@@ -60,12 +57,6 @@
 }
 
 NuPlayer::Renderer::~Renderer() {
-    delete mSoftRenderer;
-}
-
-void NuPlayer::Renderer::setSoftRenderer(SoftwareRenderer *softRenderer) {
-    delete mSoftRenderer;
-    mSoftRenderer = softRenderer;
 }
 
 void NuPlayer::Renderer::queueBuffer(
@@ -425,9 +416,6 @@
         ALOGV("rendering video at media time %.2f secs",
                 (mFlags & FLAG_REAL_TIME ? realTimeUs :
                 (realTimeUs + mAnchorTimeMediaUs - mAnchorTimeRealUs)) / 1E6);
-        if (mSoftRenderer != NULL) {
-            mSoftRenderer->render(entry->mBuffer->data(), entry->mBuffer->size(), NULL);
-        }
     }
 
     entry->mNotifyConsumed->setInt32("render", !tooLate);
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
index 9124e03..94a05ea 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
@@ -23,7 +23,6 @@
 namespace android {
 
 struct ABuffer;
-class SoftwareRenderer;
 
 struct NuPlayer::Renderer : public AHandler {
     enum Flags {
@@ -57,8 +56,6 @@
         kWhatMediaRenderingStart = 'mdrd',
     };
 
-    void setSoftRenderer(SoftwareRenderer *softRenderer);
-
 protected:
     virtual ~Renderer();
 
@@ -86,7 +83,6 @@
     static const int64_t kMinPositionUpdateDelayUs;
 
     sp<MediaPlayerBase::AudioSink> mAudioSink;
-    SoftwareRenderer *mSoftRenderer;
     sp<AMessage> mNotify;
     uint32_t mFlags;
     List<QueueEntry> mAudioQueue;
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index 9c48587..e9e96d1 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -365,7 +365,6 @@
       mIsEncoder(false),
       mUseMetadataOnEncoderOutput(false),
       mShutdownInProgress(false),
-      mIsConfiguredForAdaptivePlayback(false),
       mEncoderDelay(0),
       mEncoderPadding(0),
       mChannelMaskPresent(false),
@@ -643,18 +642,33 @@
         return err;
     }
 
-    // XXX: Is this the right logic to use?  It's not clear to me what the OMX
-    // buffer counts refer to - how do they account for the renderer holding on
-    // to buffers?
-    if (def.nBufferCountActual < def.nBufferCountMin + *minUndequeuedBuffers) {
-        OMX_U32 newBufferCount = def.nBufferCountMin + *minUndequeuedBuffers;
+    // FIXME: assume that surface is controlled by app (native window
+    // returns the number for the case when surface is not controlled by app)
+    (*minUndequeuedBuffers)++;
+
+
+    // Use conservative allocation while also trying to reduce starvation
+    //
+    // 1. allocate at least nBufferCountMin + minUndequeuedBuffers - that is the
+    //    minimum needed for the consumer to be able to work
+    // 2. try to allocate two (2) additional buffers to reduce starvation from
+    //    the consumer
+    for (OMX_U32 extraBuffers = 2; /* condition inside loop */; extraBuffers--) {
+        OMX_U32 newBufferCount =
+            def.nBufferCountMin + *minUndequeuedBuffers + extraBuffers;
         def.nBufferCountActual = newBufferCount;
         err = mOMX->setParameter(
                 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
 
-        if (err != OK) {
-            ALOGE("[%s] setting nBufferCountActual to %lu failed: %d",
-                    mComponentName.c_str(), newBufferCount, err);
+        if (err == OK) {
+            *minUndequeuedBuffers += extraBuffers;
+            break;
+        }
+
+        ALOGW("[%s] setting nBufferCountActual to %lu failed: %d",
+                mComponentName.c_str(), newBufferCount, err);
+        /* exit condition */
+        if (extraBuffers == 0) {
             return err;
         }
     }
@@ -679,6 +693,7 @@
             &bufferCount, &bufferSize, &minUndequeuedBuffers);
     if (err != 0)
         return err;
+    mNumUndequeuedBuffers = minUndequeuedBuffers;
 
     ALOGV("[%s] Allocating %lu buffers from a native window of size %lu on "
          "output port",
@@ -744,6 +759,7 @@
             &bufferCount, &bufferSize, &minUndequeuedBuffers);
     if (err != 0)
         return err;
+    mNumUndequeuedBuffers = minUndequeuedBuffers;
 
     ALOGV("[%s] Allocating %lu meta buffers on output port",
          mComponentName.c_str(), bufferCount);
@@ -1041,6 +1057,9 @@
         encoder = false;
     }
 
+    sp<AMessage> inputFormat = new AMessage();
+    sp<AMessage> outputFormat = new AMessage();
+
     mIsEncoder = encoder;
 
     status_t err = setComponentRole(encoder /* isEncoder */, mime);
@@ -1142,7 +1161,9 @@
     int32_t haveNativeWindow = msg->findObject("native-window", &obj) &&
             obj != NULL;
     mStoreMetaDataInOutputBuffers = false;
-    mIsConfiguredForAdaptivePlayback = false;
+    if (video && !encoder) {
+        inputFormat->setInt32("adaptive-playback", false);
+    }
     if (!encoder && video && haveNativeWindow) {
         err = mOMX->storeMetaDataInBuffers(mNode, kPortIndexOutput, OMX_TRUE);
         if (err != OK) {
@@ -1187,14 +1208,19 @@
                 ALOGW_IF(err != OK,
                         "[%s] prepareForAdaptivePlayback failed w/ err %d",
                         mComponentName.c_str(), err);
-                mIsConfiguredForAdaptivePlayback = (err == OK);
+
+                if (err == OK) {
+                    inputFormat->setInt32("max-width", maxWidth);
+                    inputFormat->setInt32("max-height", maxHeight);
+                    inputFormat->setInt32("adaptive-playback", true);
+                }
             }
             // allow failure
             err = OK;
         } else {
             ALOGV("[%s] storeMetaDataInBuffers succeeded", mComponentName.c_str());
             mStoreMetaDataInOutputBuffers = true;
-            mIsConfiguredForAdaptivePlayback = true;
+            inputFormat->setInt32("adaptive-playback", true);
         }
 
         int32_t push;
@@ -1334,6 +1360,11 @@
         err = setMinBufferSize(kPortIndexInput, 8192);  // XXX
     }
 
+    CHECK_EQ(getPortFormat(kPortIndexInput, inputFormat), (status_t)OK);
+    CHECK_EQ(getPortFormat(kPortIndexOutput, outputFormat), (status_t)OK);
+    mInputFormat = inputFormat;
+    mOutputFormat = outputFormat;
+
     return err;
 }
 
@@ -2498,19 +2529,7 @@
         return;
     }
 
-    int minUndequeuedBufs = 0;
-    status_t err = mNativeWindow->query(
-            mNativeWindow.get(), NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS,
-            &minUndequeuedBufs);
-
-    if (err != OK) {
-        ALOGE("[%s] NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS query failed: %s (%d)",
-                mComponentName.c_str(), strerror(-err), -err);
-
-        minUndequeuedBufs = 0;
-    }
-
-    while (countBuffersOwnedByNativeWindow() > (size_t)minUndequeuedBufs
+    while (countBuffersOwnedByNativeWindow() > mNumUndequeuedBuffers
             && dequeueBufferFromNativeWindow() != NULL) {
         // these buffers will be submitted as regular buffers; account for this
         if (mStoreMetaDataInOutputBuffers && mMetaDataBuffersToSubmit > 0) {
@@ -2556,79 +2575,78 @@
     }
 }
 
-void ACodec::sendFormatChange(const sp<AMessage> &reply) {
-    sp<AMessage> notify = mNotify->dup();
-    notify->setInt32("what", kWhatOutputFormatChanged);
-
+status_t ACodec::getPortFormat(OMX_U32 portIndex, sp<AMessage> &notify) {
+    // TODO: catch errors an return them instead of using CHECK
     OMX_PARAM_PORTDEFINITIONTYPE def;
     InitOMXParams(&def);
-    def.nPortIndex = kPortIndexOutput;
+    def.nPortIndex = portIndex;
 
     CHECK_EQ(mOMX->getParameter(
                 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def)),
              (status_t)OK);
 
-    CHECK_EQ((int)def.eDir, (int)OMX_DirOutput);
+    CHECK_EQ((int)def.eDir,
+            (int)(portIndex == kPortIndexOutput ? OMX_DirOutput : OMX_DirInput));
 
     switch (def.eDomain) {
         case OMX_PortDomainVideo:
         {
             OMX_VIDEO_PORTDEFINITIONTYPE *videoDef = &def.format.video;
+            switch ((int)videoDef->eCompressionFormat) {
+                case OMX_VIDEO_CodingUnused:
+                {
+                    CHECK(mIsEncoder ^ (portIndex == kPortIndexOutput));
+                    notify->setString("mime", MEDIA_MIMETYPE_VIDEO_RAW);
 
-            AString mime;
-            if (!mIsEncoder) {
-                notify->setString("mime", MEDIA_MIMETYPE_VIDEO_RAW);
-            } else if (GetMimeTypeForVideoCoding(
+                    notify->setInt32("stride", videoDef->nStride);
+                    notify->setInt32("slice-height", videoDef->nSliceHeight);
+                    notify->setInt32("color-format", videoDef->eColorFormat);
+
+                    OMX_CONFIG_RECTTYPE rect;
+                    InitOMXParams(&rect);
+                    rect.nPortIndex = kPortIndexOutput;
+
+                    if (mOMX->getConfig(
+                                mNode, OMX_IndexConfigCommonOutputCrop,
+                                &rect, sizeof(rect)) != OK) {
+                        rect.nLeft = 0;
+                        rect.nTop = 0;
+                        rect.nWidth = videoDef->nFrameWidth;
+                        rect.nHeight = videoDef->nFrameHeight;
+                    }
+
+                    CHECK_GE(rect.nLeft, 0);
+                    CHECK_GE(rect.nTop, 0);
+                    CHECK_GE(rect.nWidth, 0u);
+                    CHECK_GE(rect.nHeight, 0u);
+                    CHECK_LE(rect.nLeft + rect.nWidth - 1, videoDef->nFrameWidth);
+                    CHECK_LE(rect.nTop + rect.nHeight - 1, videoDef->nFrameHeight);
+
+                    notify->setRect(
+                            "crop",
+                            rect.nLeft,
+                            rect.nTop,
+                            rect.nLeft + rect.nWidth - 1,
+                            rect.nTop + rect.nHeight - 1);
+
+                    break;
+                }
+                default:
+                {
+                    CHECK(mIsEncoder ^ (portIndex == kPortIndexInput));
+                    AString mime;
+                    if (GetMimeTypeForVideoCoding(
                         videoDef->eCompressionFormat, &mime) != OK) {
-                notify->setString("mime", "application/octet-stream");
-            } else {
-                notify->setString("mime", mime.c_str());
+                        notify->setString("mime", "application/octet-stream");
+                    } else {
+                        notify->setString("mime", mime.c_str());
+                    }
+                    break;
+                }
             }
 
             notify->setInt32("width", videoDef->nFrameWidth);
             notify->setInt32("height", videoDef->nFrameHeight);
-
-            if (!mIsEncoder) {
-                notify->setInt32("stride", videoDef->nStride);
-                notify->setInt32("slice-height", videoDef->nSliceHeight);
-                notify->setInt32("color-format", videoDef->eColorFormat);
-
-                OMX_CONFIG_RECTTYPE rect;
-                InitOMXParams(&rect);
-                rect.nPortIndex = kPortIndexOutput;
-
-                if (mOMX->getConfig(
-                            mNode, OMX_IndexConfigCommonOutputCrop,
-                            &rect, sizeof(rect)) != OK) {
-                    rect.nLeft = 0;
-                    rect.nTop = 0;
-                    rect.nWidth = videoDef->nFrameWidth;
-                    rect.nHeight = videoDef->nFrameHeight;
-                }
-
-                CHECK_GE(rect.nLeft, 0);
-                CHECK_GE(rect.nTop, 0);
-                CHECK_GE(rect.nWidth, 0u);
-                CHECK_GE(rect.nHeight, 0u);
-                CHECK_LE(rect.nLeft + rect.nWidth - 1, videoDef->nFrameWidth);
-                CHECK_LE(rect.nTop + rect.nHeight - 1, videoDef->nFrameHeight);
-
-                notify->setRect(
-                        "crop",
-                        rect.nLeft,
-                        rect.nTop,
-                        rect.nLeft + rect.nWidth - 1,
-                        rect.nTop + rect.nHeight - 1);
-
-                if (mNativeWindow != NULL) {
-                    reply->setRect(
-                            "crop",
-                            rect.nLeft,
-                            rect.nTop,
-                            rect.nLeft + rect.nWidth,
-                            rect.nTop + rect.nHeight);
-                }
-            }
             break;
         }
 
@@ -2641,7 +2659,7 @@
                 {
                     OMX_AUDIO_PARAM_PCMMODETYPE params;
                     InitOMXParams(&params);
-                    params.nPortIndex = kPortIndexOutput;
+                    params.nPortIndex = portIndex;
 
                     CHECK_EQ(mOMX->getParameter(
                                 mNode, OMX_IndexParamAudioPcm,
@@ -2661,20 +2679,6 @@
                     notify->setString("mime", MEDIA_MIMETYPE_AUDIO_RAW);
                     notify->setInt32("channel-count", params.nChannels);
                     notify->setInt32("sample-rate", params.nSamplingRate);
-                    if (mEncoderDelay + mEncoderPadding) {
-                        size_t frameSize = params.nChannels * sizeof(int16_t);
-                        if (mSkipCutBuffer != NULL) {
-                            size_t prevbufsize = mSkipCutBuffer->size();
-                            if (prevbufsize != 0) {
-                                ALOGW("Replacing SkipCutBuffer holding %d "
-                                      "bytes",
-                                      prevbufsize);
-                            }
-                        }
-                        mSkipCutBuffer = new SkipCutBuffer(
-                                mEncoderDelay * frameSize,
-                                mEncoderPadding * frameSize);
-                    }
 
                     if (mChannelMaskPresent) {
                         notify->setInt32("channel-mask", mChannelMask);
@@ -2686,7 +2690,7 @@
                 {
                     OMX_AUDIO_PARAM_AACPROFILETYPE params;
                     InitOMXParams(&params);
-                    params.nPortIndex = kPortIndexOutput;
+                    params.nPortIndex = portIndex;
 
                     CHECK_EQ(mOMX->getParameter(
                                 mNode, OMX_IndexParamAudioAac,
@@ -2703,7 +2707,7 @@
                 {
                     OMX_AUDIO_PARAM_AMRTYPE params;
                     InitOMXParams(&params);
-                    params.nPortIndex = kPortIndexOutput;
+                    params.nPortIndex = portIndex;
 
                     CHECK_EQ(mOMX->getParameter(
                                 mNode, OMX_IndexParamAudioAmr,
@@ -2729,7 +2733,7 @@
                 {
                     OMX_AUDIO_PARAM_FLACTYPE params;
                     InitOMXParams(&params);
-                    params.nPortIndex = kPortIndexOutput;
+                    params.nPortIndex = portIndex;
 
                     CHECK_EQ(mOMX->getParameter(
                                 mNode, OMX_IndexParamAudioFlac,
@@ -2742,11 +2746,45 @@
                     break;
                 }
 
+                case OMX_AUDIO_CodingMP3:
+                {
+                    OMX_AUDIO_PARAM_MP3TYPE params;
+                    InitOMXParams(&params);
+                    params.nPortIndex = portIndex;
+
+                    CHECK_EQ(mOMX->getParameter(
+                                mNode, OMX_IndexParamAudioMp3,
+                                &params, sizeof(params)),
+                             (status_t)OK);
+
+                    notify->setString("mime", MEDIA_MIMETYPE_AUDIO_MPEG);
+                    notify->setInt32("channel-count", params.nChannels);
+                    notify->setInt32("sample-rate", params.nSampleRate);
+                    break;
+                }
+
+                case OMX_AUDIO_CodingVORBIS:
+                {
+                    OMX_AUDIO_PARAM_VORBISTYPE params;
+                    InitOMXParams(&params);
+                    params.nPortIndex = portIndex;
+
+                    CHECK_EQ(mOMX->getParameter(
+                                mNode, OMX_IndexParamAudioVorbis,
+                                &params, sizeof(params)),
+                             (status_t)OK);
+
+                    notify->setString("mime", MEDIA_MIMETYPE_AUDIO_VORBIS);
+                    notify->setInt32("channel-count", params.nChannels);
+                    notify->setInt32("sample-rate", params.nSampleRate);
+                    break;
+                }
+
                 case OMX_AUDIO_CodingAndroidAC3:
                 {
                     OMX_AUDIO_PARAM_ANDROID_AC3TYPE params;
                     InitOMXParams(&params);
-                    params.nPortIndex = kPortIndexOutput;
+                    params.nPortIndex = portIndex;
 
                     CHECK_EQ((status_t)OK, mOMX->getParameter(
                             mNode,
@@ -2761,6 +2799,7 @@
                 }
 
                 default:
+                    ALOGE("UNKNOWN AUDIO CODING: %d\n", audioDef->eEncoding);
                     TRESPASS();
             }
             break;
@@ -2770,6 +2809,43 @@
             TRESPASS();
     }
 
+    return OK;
+}
+
+void ACodec::sendFormatChange(const sp<AMessage> &reply) {
+    sp<AMessage> notify = mNotify->dup();
+    notify->setInt32("what", kWhatOutputFormatChanged);
+
+    CHECK_EQ(getPortFormat(kPortIndexOutput, notify), (status_t)OK);
+
+    AString mime;
+    CHECK(notify->findString("mime", &mime));
+
+    int32_t left, top, right, bottom;
+    if (mime == MEDIA_MIMETYPE_VIDEO_RAW &&
+        mNativeWindow != NULL &&
+        notify->findRect("crop", &left, &top, &right, &bottom)) {
+        // notify renderer of the crop change
+        // NOTE: native window uses extended right-bottom coordinate
+        reply->setRect("crop", left, top, right + 1, bottom + 1);
+    } else if (mime == MEDIA_MIMETYPE_AUDIO_RAW &&
+               (mEncoderDelay || mEncoderPadding)) {
+        int32_t channelCount;
+        CHECK(notify->findInt32("channel-count", &channelCount));
+        size_t frameSize = channelCount * sizeof(int16_t);
+        if (mSkipCutBuffer != NULL) {
+            size_t prevbufsize = mSkipCutBuffer->size();
+            if (prevbufsize != 0) {
+                ALOGW("Replacing SkipCutBuffer holding %d "
+                      "bytes",
+                      prevbufsize);
+            }
+        }
+        mSkipCutBuffer = new SkipCutBuffer(
+                mEncoderDelay * frameSize,
+                mEncoderPadding * frameSize);
+    }
+
     notify->post();
 
     mSentFormat = true;
@@ -3799,7 +3875,8 @@
     mCodec->mDequeueCounter = 0;
     mCodec->mMetaDataBuffersToSubmit = 0;
     mCodec->mRepeatFrameDelayUs = -1ll;
-    mCodec->mIsConfiguredForAdaptivePlayback = false;
+    mCodec->mInputFormat.clear();
+    mCodec->mOutputFormat.clear();
 
     if (mCodec->mShutdownInProgress) {
         bool keepComponentAllocated = mCodec->mKeepComponentAllocated;
@@ -3913,6 +3990,8 @@
     {
         sp<AMessage> notify = mCodec->mNotify->dup();
         notify->setInt32("what", ACodec::kWhatComponentConfigured);
+        notify->setMessage("input-format", mCodec->mInputFormat);
+        notify->setMessage("output-format", mCodec->mOutputFormat);
         notify->post();
     }
 
diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk
index 714b5e0..a9b0c73 100644
--- a/media/libstagefright/Android.mk
+++ b/media/libstagefright/Android.mk
@@ -118,6 +118,8 @@
 
 LOCAL_MODULE_TAGS := optional
 
+LOCAL_32_BIT_ONLY := true
+
 include $(BUILD_SHARED_LIBRARY)
 
 include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index fe21296..e0419ca 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -352,6 +352,20 @@
     return OK;
 }
 
+status_t MediaCodec::getInputFormat(sp<AMessage> *format) const {
+    sp<AMessage> msg = new AMessage(kWhatGetInputFormat, id());
+
+    sp<AMessage> response;
+    status_t err;
+    if ((err = PostAndAwaitResponse(msg, &response)) != OK) {
+        return err;
+    }
+
+    CHECK(response->findMessage("format", format));
+
+    return OK;
+}
+
 status_t MediaCodec::getName(AString *name) const {
     sp<AMessage> msg = new AMessage(kWhatGetName, id());
 
@@ -642,6 +656,9 @@
                     // reset input surface flag
                     mHaveInputSurface = false;
 
+                    CHECK(msg->findMessage("input-format", &mInputFormat));
+                    CHECK(msg->findMessage("output-format", &mOutputFormat));
+
                     (new AMessage)->postReply(mReplyID);
                     break;
                 }
@@ -1330,14 +1347,19 @@
             break;
         }
 
+        case kWhatGetInputFormat:
         case kWhatGetOutputFormat:
         {
+            sp<AMessage> format =
+                (msg->what() == kWhatGetOutputFormat ? mOutputFormat : mInputFormat);
+
             uint32_t replyID;
             CHECK(msg->senderAwaitsResponse(&replyID));
 
-            if ((mState != STARTED && mState != FLUSHING)
+            if ((mState != CONFIGURED && mState != STARTING &&
+                 mState != STARTED && mState != FLUSHING)
                     || (mFlags & kFlagStickyError)
-                    || mOutputFormat == NULL) {
+                    || format == NULL) {
                 sp<AMessage> response = new AMessage;
                 response->setInt32("err", INVALID_OPERATION);
 
@@ -1346,7 +1368,7 @@
             }
 
             sp<AMessage> response = new AMessage;
-            response->setMessage("format", mOutputFormat);
+            response->setMessage("format", format);
             response->postReply(replyID);
             break;
         }
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index 4d3b5bd..545ca9d 100644
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -94,6 +94,7 @@
 
 #define CODEC_LOGI(x, ...) ALOGI("[%s] "x, mComponentName, ##__VA_ARGS__)
 #define CODEC_LOGV(x, ...) ALOGV("[%s] "x, mComponentName, ##__VA_ARGS__)
+#define CODEC_LOGW(x, ...) ALOGW("[%s] "x, mComponentName, ##__VA_ARGS__)
 #define CODEC_LOGE(x, ...) ALOGE("[%s] "x, mComponentName, ##__VA_ARGS__)
 
 struct OMXCodecObserver : public BnOMXObserver {
@@ -1803,21 +1804,40 @@
                 strerror(-err), -err);
         return err;
     }
+    // FIXME: assume that surface is controlled by app (native window
+    // returns the number for the case when surface is not controlled by app)
+    minUndequeuedBufs++;
 
-    // XXX: Is this the right logic to use?  It's not clear to me what the OMX
-    // buffer counts refer to - how do they account for the renderer holding on
-    // to buffers?
-    if (def.nBufferCountActual < def.nBufferCountMin + minUndequeuedBufs) {
-        OMX_U32 newBufferCount = def.nBufferCountMin + minUndequeuedBufs;
+    // Use conservative allocation while also trying to reduce starvation
+    //
+    // 1. allocate at least nBufferCountMin + minUndequeuedBuffers - that is the
+    //    minimum needed for the consumer to be able to work
+    // 2. try to allocate two (2) additional buffers to reduce starvation from
+    //    the consumer
+    CODEC_LOGI("OMX-buffers: min=%u actual=%u undeq=%d",
+            def.nBufferCountMin, def.nBufferCountActual, minUndequeuedBufs);
+
+    for (OMX_U32 extraBuffers = 2; /* condition inside loop */; extraBuffers--) {
+        OMX_U32 newBufferCount =
+            def.nBufferCountMin + minUndequeuedBufs + extraBuffers;
         def.nBufferCountActual = newBufferCount;
         err = mOMX->setParameter(
                 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
-        if (err != OK) {
-            CODEC_LOGE("setting nBufferCountActual to %lu failed: %d",
-                    newBufferCount, err);
+
+        if (err == OK) {
+            minUndequeuedBufs += extraBuffers;
+            break;
+        }
+
+        CODEC_LOGW("setting nBufferCountActual to %lu failed: %d",
+                newBufferCount, err);
+        /* exit condition */
+        if (extraBuffers == 0) {
             return err;
         }
     }
+    CODEC_LOGI("OMX-buffers: min=%u actual=%u undeq=%d",
+            def.nBufferCountMin, def.nBufferCountActual, minUndequeuedBufs);
 
     err = native_window_set_buffer_count(
             mNativeWindow.get(), def.nBufferCountActual);
diff --git a/media/libstagefright/SurfaceMediaSource.cpp b/media/libstagefright/SurfaceMediaSource.cpp
index 10c00f4..e7cc46d 100644
--- a/media/libstagefright/SurfaceMediaSource.cpp
+++ b/media/libstagefright/SurfaceMediaSource.cpp
@@ -477,4 +477,8 @@
     }
 }
 
+void SurfaceMediaSource::onSidebandStreamChanged() {
+    ALOG_ASSERT(false, "SurfaceMediaSource can't consume sideband streams");
+}
+
 } // end of namespace android
diff --git a/media/libstagefright/codecs/aacenc/Android.mk b/media/libstagefright/codecs/aacenc/Android.mk
index 58ec3ba..04dc487 100644
--- a/media/libstagefright/codecs/aacenc/Android.mk
+++ b/media/libstagefright/codecs/aacenc/Android.mk
@@ -117,6 +117,7 @@
 
   LOCAL_MODULE := libstagefright_soft_aacenc
   LOCAL_MODULE_TAGS := optional
+  LOCAL_32_BIT_ONLY := true
 
   include $(BUILD_SHARED_LIBRARY)
 
diff --git a/media/libstagefright/codecs/avc/enc/Android.mk b/media/libstagefright/codecs/avc/enc/Android.mk
index 537ba42..c2e7b81 100644
--- a/media/libstagefright/codecs/avc/enc/Android.mk
+++ b/media/libstagefright/codecs/avc/enc/Android.mk
@@ -20,6 +20,7 @@
 
 
 LOCAL_MODULE := libstagefright_avcenc
+LOCAL_32_BIT_ONLY := true
 
 LOCAL_C_INCLUDES := \
     $(LOCAL_PATH)/src \
@@ -70,6 +71,7 @@
 
 LOCAL_MODULE := libstagefright_soft_h264enc
 LOCAL_MODULE_TAGS := optional
+LOCAL_32_BIT_ONLY := true
 
 LOCAL_CFLAGS += -Werror
 
diff --git a/media/libstagefright/codecs/mp3dec/SoftMP3.cpp b/media/libstagefright/codecs/mp3dec/SoftMP3.cpp
index a09ab7c..5396022 100644
--- a/media/libstagefright/codecs/mp3dec/SoftMP3.cpp
+++ b/media/libstagefright/codecs/mp3dec/SoftMP3.cpp
@@ -146,6 +146,23 @@
             return OMX_ErrorNone;
         }
 
+        case OMX_IndexParamAudioMp3:
+        {
+            OMX_AUDIO_PARAM_MP3TYPE *mp3Params =
+                (OMX_AUDIO_PARAM_MP3TYPE *)params;
+
+            if (mp3Params->nPortIndex > 1) {
+                return OMX_ErrorUndefined;
+            }
+
+            mp3Params->nChannels = mNumChannels;
+            mp3Params->nBitRate = 0 /* unknown */;
+            mp3Params->nSampleRate = mSamplingRate;
+            // other fields are encoder-only
+
+            return OMX_ErrorNone;
+        }
+
         default:
             return SimpleSoftOMXComponent::internalGetParameter(index, params);
     }
diff --git a/media/libstagefright/httplive/LiveSession.cpp b/media/libstagefright/httplive/LiveSession.cpp
index ceb3c8f..19db6eb 100644
--- a/media/libstagefright/httplive/LiveSession.cpp
+++ b/media/libstagefright/httplive/LiveSession.cpp
@@ -71,7 +71,7 @@
 
     mStreams[kAudioIndex] = StreamItem("audio");
     mStreams[kVideoIndex] = StreamItem("video");
-    mStreams[kSubtitleIndex] = StreamItem("subtitle");
+    mStreams[kSubtitleIndex] = StreamItem("subtitles");
 
     for (size_t i = 0; i < kMaxStreams; ++i) {
         mPacketSources.add(indexToType(i), new AnotherPacketSource(NULL /* meta */));
@@ -488,7 +488,7 @@
     mPlaylist = fetchPlaylist(url.c_str(), NULL /* curPlaylistHash */, &dummy);
 
     if (mPlaylist == NULL) {
-        ALOGE("unable to fetch master playlist '%s'.", url.c_str());
+        ALOGE("unable to fetch master playlist <URL suppressed>.");
 
         postPrepared(ERROR_IO);
         return;
diff --git a/media/libstagefright/httplive/M3UParser.cpp b/media/libstagefright/httplive/M3UParser.cpp
index 87918c8..dacdd40 100644
--- a/media/libstagefright/httplive/M3UParser.cpp
+++ b/media/libstagefright/httplive/M3UParser.cpp
@@ -798,8 +798,7 @@
                 if (MakeURL(baseURI.c_str(), val.c_str(), &absURI)) {
                     val = absURI;
                 } else {
-                    ALOGE("failed to make absolute url for '%s'.",
-                         val.c_str());
+                    ALOGE("failed to make absolute url for <URL suppressed>.");
                 }
             }
 
diff --git a/media/libstagefright/omx/GraphicBufferSource.cpp b/media/libstagefright/omx/GraphicBufferSource.cpp
index b81b116..5bea7a6 100644
--- a/media/libstagefright/omx/GraphicBufferSource.cpp
+++ b/media/libstagefright/omx/GraphicBufferSource.cpp
@@ -777,6 +777,11 @@
     }
 }
 
+// BufferQueue::ConsumerListener callback
+void GraphicBufferSource::onSidebandStreamChanged() {
+    ALOG_ASSERT(false, "GraphicBufferSource can't consume sideband streams");
+}
+
 status_t GraphicBufferSource::setRepeatPreviousFrameDelayUs(
         int64_t repeatAfterUs) {
     Mutex::Autolock autoLock(mMutex);
diff --git a/media/libstagefright/omx/GraphicBufferSource.h b/media/libstagefright/omx/GraphicBufferSource.h
index fba42b7..757edc8 100644
--- a/media/libstagefright/omx/GraphicBufferSource.h
+++ b/media/libstagefright/omx/GraphicBufferSource.h
@@ -143,6 +143,11 @@
     // set of mBufferSlot entries.
     virtual void onBuffersReleased();
 
+    // 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).
+    virtual void onSidebandStreamChanged();
+
 private:
     // Keep track of codec input buffers.  They may either be available
     // (mGraphicBuffer == NULL) or in use by the codec.
diff --git a/media/libstagefright/rtsp/ARTSPConnection.cpp b/media/libstagefright/rtsp/ARTSPConnection.cpp
index 4054da6..cc3b63c 100644
--- a/media/libstagefright/rtsp/ARTSPConnection.cpp
+++ b/media/libstagefright/rtsp/ARTSPConnection.cpp
@@ -239,7 +239,7 @@
         // right here, since we currently have no way of asking the user
         // for this information.
 
-        ALOGE("Malformed rtsp url %s", url.c_str());
+        ALOGE("Malformed rtsp url <URL suppressed>");
 
         reply->setInt32("result", ERROR_MALFORMED);
         reply->post();
diff --git a/media/libstagefright/rtsp/MyHandler.h b/media/libstagefright/rtsp/MyHandler.h
index 45470a3..f3dfc59 100644
--- a/media/libstagefright/rtsp/MyHandler.h
+++ b/media/libstagefright/rtsp/MyHandler.h
@@ -159,7 +159,7 @@
             mSessionURL.append(StringPrintf("%u", port));
             mSessionURL.append(path);
 
-            ALOGI("rewritten session url: '%s'", mSessionURL.c_str());
+            ALOGV("rewritten session url: '%s'", mSessionURL.c_str());
         }
 
         mSessionHost = host;
@@ -488,21 +488,32 @@
                     sp<ARTSPResponse> response =
                         static_cast<ARTSPResponse *>(obj.get());
 
-                    if (response->mStatusCode == 302) {
+                    if (response->mStatusCode == 301 || response->mStatusCode == 302) {
                         ssize_t i = response->mHeaders.indexOfKey("location");
                         CHECK_GE(i, 0);
 
-                        mSessionURL = response->mHeaders.valueAt(i);
+                        mOriginalSessionURL = response->mHeaders.valueAt(i);
+                        mSessionURL = mOriginalSessionURL;
 
-                        AString request;
-                        request = "DESCRIBE ";
-                        request.append(mSessionURL);
-                        request.append(" RTSP/1.0\r\n");
-                        request.append("Accept: application/sdp\r\n");
-                        request.append("\r\n");
+                        // Strip any authentication info from the session url, we don't
+                        // want to transmit user/pass in cleartext.
+                        AString host, path, user, pass;
+                        unsigned port;
+                        if (ARTSPConnection::ParseURL(
+                                    mSessionURL.c_str(), &host, &port, &path, &user, &pass)
+                                && user.size() > 0) {
+                            mSessionURL.clear();
+                            mSessionURL.append("rtsp://");
+                            mSessionURL.append(host);
+                            mSessionURL.append(":");
+                            mSessionURL.append(StringPrintf("%u", port));
+                            mSessionURL.append(path);
 
-                        sp<AMessage> reply = new AMessage('desc', id());
-                        mConn->sendRequest(request.c_str(), reply);
+                            ALOGI("rewritten session url: '%s'", mSessionURL.c_str());
+                        }
+
+                        sp<AMessage> reply = new AMessage('conn', id());
+                        mConn->connect(mOriginalSessionURL.c_str(), reply);
                         break;
                     }
 
diff --git a/media/libstagefright/rtsp/SDPLoader.cpp b/media/libstagefright/rtsp/SDPLoader.cpp
index ce1e89d..13e8da3 100644
--- a/media/libstagefright/rtsp/SDPLoader.cpp
+++ b/media/libstagefright/rtsp/SDPLoader.cpp
@@ -90,7 +90,7 @@
     msg->findPointer("headers", (void **)&headers);
 
     if (!(mFlags & kFlagIncognito)) {
-        ALOGI("onLoad '%s'", url.c_str());
+        ALOGV("onLoad '%s'", url.c_str());
     } else {
         ALOGI("onLoad <URL suppressed>");
     }
diff --git a/media/mediaserver/Android.mk b/media/mediaserver/Android.mk
index 9335a84..d3e546a 100644
--- a/media/mediaserver/Android.mk
+++ b/media/mediaserver/Android.mk
@@ -38,5 +38,6 @@
     frameworks/av/services/camera/libcameraservice
 
 LOCAL_MODULE:= mediaserver
+LOCAL_32_BIT_ONLY := true
 
 include $(BUILD_EXECUTABLE)
diff --git a/media/mtp/MtpProperty.cpp b/media/mtp/MtpProperty.cpp
index 375ed9a..3838ce8 100644
--- a/media/mtp/MtpProperty.cpp
+++ b/media/mtp/MtpProperty.cpp
@@ -190,9 +190,9 @@
             if (deviceProp)
                 writeValue(packet, mCurrentValue);
     }
-    packet.putUInt32(mGroupCode);
     if (!deviceProp)
-        packet.putUInt8(mFormFlag);
+        packet.putUInt32(mGroupCode);
+    packet.putUInt8(mFormFlag);
     if (mFormFlag == kFormRange) {
             writeValue(packet, mMinimumValue);
             writeValue(packet, mMaximumValue);
diff --git a/media/mtp/MtpServer.cpp b/media/mtp/MtpServer.cpp
index df87db4..dadfb54 100644
--- a/media/mtp/MtpServer.cpp
+++ b/media/mtp/MtpServer.cpp
@@ -93,6 +93,7 @@
     MTP_EVENT_OBJECT_REMOVED,
     MTP_EVENT_STORE_ADDED,
     MTP_EVENT_STORE_REMOVED,
+    MTP_EVENT_DEVICE_PROP_CHANGED,
 };
 
 MtpServer::MtpServer(int fd, MtpDatabase* database, bool ptp,
@@ -261,6 +262,11 @@
     sendEvent(MTP_EVENT_STORE_REMOVED, id);
 }
 
+void MtpServer::sendDevicePropertyChanged(MtpDeviceProperty property) {
+    ALOGV("sendDevicePropertyChanged %d\n", property);
+    sendEvent(MTP_EVENT_DEVICE_PROP_CHANGED, property);
+}
+
 void MtpServer::sendEvent(MtpEventCode code, uint32_t param1) {
     if (mSessionOpen) {
         mEvent.setEventCode(code);
diff --git a/media/mtp/MtpServer.h b/media/mtp/MtpServer.h
index dfa8258..b3a11e0 100644
--- a/media/mtp/MtpServer.h
+++ b/media/mtp/MtpServer.h
@@ -104,6 +104,7 @@
 
     void                sendObjectAdded(MtpObjectHandle handle);
     void                sendObjectRemoved(MtpObjectHandle handle);
+    void                sendDevicePropertyChanged(MtpDeviceProperty property);
 
 private:
     void                sendStoreAdded(MtpStorageID id);
diff --git a/services/audioflinger/Android.mk b/services/audioflinger/Android.mk
index f1ab072..de7e3c3 100644
--- a/services/audioflinger/Android.mk
+++ b/services/audioflinger/Android.mk
@@ -63,6 +63,7 @@
     libserviceutility
 
 LOCAL_MODULE:= libaudioflinger
+LOCAL_32_BIT_ONLY := true
 
 LOCAL_SRC_FILES += FastMixer.cpp FastMixerState.cpp AudioWatchdog.cpp
 
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 92ee30e..50179c5 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -509,7 +509,6 @@
         audio_io_handle_t output,
         pid_t tid,
         int *sessionId,
-        String8& name,
         int clientUid,
         status_t *status)
 {
@@ -559,7 +558,6 @@
     {
         Mutex::Autolock _l(mLock);
         PlaybackThread *thread = checkPlaybackThread_l(output);
-        PlaybackThread *effectThread = NULL;
         if (thread == NULL) {
             ALOGE("no playback thread found for output handle %d", output);
             lStatus = BAD_VALUE;
@@ -567,24 +565,23 @@
         }
 
         pid_t pid = IPCThreadState::self()->getCallingPid();
-
         client = registerPid_l(pid);
 
-        ALOGV("createTrack() sessionId: %d", (sessionId == NULL) ? -2 : *sessionId);
+        PlaybackThread *effectThread = NULL;
         if (sessionId != NULL && *sessionId != AUDIO_SESSION_ALLOCATE) {
+            lSessionId = *sessionId;
             // check if an effect chain with the same session ID is present on another
             // output thread and move it here.
             for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
                 sp<PlaybackThread> t = mPlaybackThreads.valueAt(i);
                 if (mPlaybackThreads.keyAt(i) != output) {
-                    uint32_t sessions = t->hasAudioSession(*sessionId);
+                    uint32_t sessions = t->hasAudioSession(lSessionId);
                     if (sessions & PlaybackThread::EFFECT_SESSION) {
                         effectThread = t.get();
                         break;
                     }
                 }
             }
-            lSessionId = *sessionId;
         } else {
             // if no audio session id is provided, create one here
             lSessionId = nextUniqueId();
@@ -625,18 +622,17 @@
 
     }
 
-    if (lStatus == NO_ERROR) {
-        // s for server's pid, n for normal mixer name, f for fast index
-        name = String8::format("s:%d;n:%d;f:%d", getpid_cached, track->name() - AudioMixer::TRACK0,
-                track->fastIndex());
-        trackHandle = new TrackHandle(track);
-    } else {
-        // remove local strong reference to Client before deleting the Track so that the Client
-        // destructor is called by the TrackBase destructor with mLock held
+    if (lStatus != NO_ERROR) {
+        // remove local strong reference to Client before deleting the Track so that the
+        // Client destructor is called by the TrackBase destructor with mLock held
         client.clear();
         track.clear();
+        goto Exit;
     }
 
+    // return handle to client
+    trackHandle = new TrackHandle(track);
+
 Exit:
     *status = lStatus;
     return trackHandle;
@@ -1324,8 +1320,6 @@
     sp<RecordHandle> recordHandle;
     sp<Client> client;
     status_t lStatus;
-    RecordThread *thread;
-    size_t inFrameCount;
     int lSessionId;
 
     // check calling permissions
@@ -1342,9 +1336,9 @@
         goto Exit;
     }
 
-    // FIXME when we support more formats, add audio_is_valid_format(format)
-    //       and any explicit restrictions if audio_is_linear_pcm(format)
-    if (format != AUDIO_FORMAT_PCM_16_BIT) {
+    // we don't yet support anything other than 16-bit PCM
+    if (!(audio_is_valid_format(format) &&
+            audio_is_linear_pcm(format) && format == AUDIO_FORMAT_PCM_16_BIT)) {
         ALOGE("openRecord() invalid format %#x", format);
         lStatus = BAD_VALUE;
         goto Exit;
@@ -1357,10 +1351,9 @@
         goto Exit;
     }
 
-    // add client to list
-    { // scope for mLock
+    {
         Mutex::Autolock _l(mLock);
-        thread = checkRecordThread_l(input);
+        RecordThread *thread = checkRecordThread_l(input);
         if (thread == NULL) {
             ALOGE("openRecord() checkRecordThread_l failed");
             lStatus = BAD_VALUE;
@@ -1377,17 +1370,17 @@
         pid_t pid = IPCThreadState::self()->getCallingPid();
         client = registerPid_l(pid);
 
-        // If no audio session id is provided, create one here
         if (sessionId != NULL && *sessionId != AUDIO_SESSION_ALLOCATE) {
             lSessionId = *sessionId;
         } else {
+            // if no audio session id is provided, create one here
             lSessionId = nextUniqueId();
             if (sessionId != NULL) {
                 *sessionId = lSessionId;
             }
         }
-        // create new record track.
-        // The record track uses one track in mHardwareMixerThread by convention.
+        ALOGV("openRecord() lSessionId: %d", lSessionId);
+
         // TODO: the uid should be passed in as a parameter to openRecord
         recordTrack = thread->createRecordTrack_l(client, sampleRate, format, channelMask,
                                                   frameCount, lSessionId,
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index c2b516b..2367d7d 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -108,7 +108,6 @@
                                 audio_io_handle_t output,
                                 pid_t tid,
                                 int *sessionId,
-                                String8& name,
                                 int clientUid,
                                 status_t *status /*non-NULL*/);
 
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 82c516c..12d453e 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -1145,7 +1145,7 @@
 AudioFlinger::PlaybackThread::~PlaybackThread()
 {
     mAudioFlinger->unregisterWriter(mNBLogWriter);
-    delete[] mSinkBuffer;
+    free(mSinkBuffer);
     free(mMixerBuffer);
     free(mEffectBuffer);
 }
@@ -1340,7 +1340,9 @@
     }
     *pFrameCount = frameCount;
 
-    if (mType == DIRECT) {
+    switch (mType) {
+
+    case DIRECT:
         if ((format & AUDIO_FORMAT_MAIN_MASK) == AUDIO_FORMAT_PCM) {
             if (sampleRate != mSampleRate || format != mFormat || channelMask != mChannelMask) {
                 ALOGE("createTrack_l() Bad parameter: sampleRate %u format %#x, channelMask 0x%08x "
@@ -1350,7 +1352,9 @@
                 goto Exit;
             }
         }
-    } else if (mType == OFFLOAD) {
+        break;
+
+    case OFFLOAD:
         if (sampleRate != mSampleRate || format != mFormat || channelMask != mChannelMask) {
             ALOGE("createTrack_l() Bad parameter: sampleRate %d format %#x, channelMask 0x%08x \""
                     "for output %p with format %#x",
@@ -1358,7 +1362,9 @@
             lStatus = BAD_VALUE;
             goto Exit;
         }
-    } else {
+        break;
+
+    default:
         if ((format & AUDIO_FORMAT_MAIN_MASK) != AUDIO_FORMAT_PCM) {
                 ALOGE("createTrack_l() Bad parameter: format %#x \""
                         "for output %p with format %#x",
@@ -1372,11 +1378,13 @@
             lStatus = BAD_VALUE;
             goto Exit;
         }
+        break;
+
     }
 
     lStatus = initCheck();
     if (lStatus != NO_ERROR) {
-        ALOGE("Audio driver not initialized.");
+        ALOGE("createTrack_l() audio driver not initialized");
         goto Exit;
     }
 
@@ -1416,7 +1424,6 @@
             // track must be cleared from the caller as the caller has the AF lock
             goto Exit;
         }
-
         mTracks.add(track);
 
         sp<EffectChain> chain = getEffectChain_l(sessionId);
@@ -1782,11 +1789,14 @@
     ALOGI("HAL output buffer size %u frames, normal sink buffer size %u frames", mFrameCount,
             mNormalFrameCount);
 
-    delete[] mSinkBuffer;
-    size_t normalBufferSize = mNormalFrameCount * mFrameSize;
-    // For historical reasons mSinkBuffer is int16_t[], but mFrameSize can be odd (such as 1)
-    mSinkBuffer = new int16_t[(normalBufferSize + 1) >> 1];
-    memset(mSinkBuffer, 0, normalBufferSize);
+    // mSinkBuffer is the sink buffer.  Size is always multiple-of-16 frames.
+    // Originally this was int16_t[] array, need to remove legacy implications.
+    free(mSinkBuffer);
+    mSinkBuffer = NULL;
+    // For sink buffer size, we use the frame size from the downstream sink to avoid problems
+    // with non PCM formats for compressed music, e.g. AAC, and Offload threads.
+    const size_t sinkBufferSize = mNormalFrameCount * mFrameSize;
+    (void)posix_memalign(&mSinkBuffer, 32, sinkBufferSize);
 
     // We resize the mMixerBuffer according to the requirements of the sink buffer which
     // drives the output.
@@ -1984,12 +1994,12 @@
     mLastWriteTime = systemTime();
     mInWrite = true;
     ssize_t bytesWritten;
+    const size_t offset = mCurrentWriteLength - mBytesRemaining;
 
     // If an NBAIO sink is present, use it to write the normal mixer's submix
     if (mNormalSink != 0) {
-#define mBitShift 2 // FIXME
-        size_t count = mBytesRemaining >> mBitShift;
-        size_t offset = (mCurrentWriteLength - mBytesRemaining) >> 1;
+        const size_t count = mBytesRemaining / mFrameSize;
+
         ATRACE_BEGIN("write");
         // update the setpoint when AudioFlinger::mScreenState changes
         uint32_t screenState = AudioFlinger::mScreenState;
@@ -2001,10 +2011,10 @@
                         (pipe->maxFrames() * 7) / 8 : mNormalFrameCount * 2);
             }
         }
-        ssize_t framesWritten = mNormalSink->write(mSinkBuffer + offset, count);
+        ssize_t framesWritten = mNormalSink->write((char *)mSinkBuffer + offset, count);
         ATRACE_END();
         if (framesWritten > 0) {
-            bytesWritten = framesWritten << mBitShift;
+            bytesWritten = framesWritten * mFrameSize;
         } else {
             bytesWritten = framesWritten;
         }
@@ -2019,7 +2029,7 @@
     // otherwise use the HAL / AudioStreamOut directly
     } else {
         // Direct output and offload threads
-        size_t offset = (mCurrentWriteLength - mBytesRemaining);
+
         if (mUseAsyncWrite) {
             ALOGW_IF(mWriteAckSequence & 1, "threadLoop_write(): out of sequence write request");
             mWriteAckSequence += 2;
@@ -2111,8 +2121,8 @@
 status_t AudioFlinger::PlaybackThread::addEffectChain_l(const sp<EffectChain>& chain)
 {
     int session = chain->sessionId();
-    int16_t *buffer = mEffectBufferEnabled
-            ? reinterpret_cast<int16_t*>(mEffectBuffer) : mSinkBuffer;
+    int16_t* buffer = reinterpret_cast<int16_t*>(mEffectBufferEnabled
+            ? mEffectBuffer : mSinkBuffer);
     bool ownsBuffer = false;
 
     ALOGV("addEffectChain_l() %p on thread %p for session %d", chain.get(), this, session);
@@ -2152,8 +2162,8 @@
     }
 
     chain->setInBuffer(buffer, ownsBuffer);
-    chain->setOutBuffer(mEffectBufferEnabled
-            ? reinterpret_cast<int16_t*>(mEffectBuffer) : mSinkBuffer);
+    chain->setOutBuffer(reinterpret_cast<int16_t*>(mEffectBufferEnabled
+            ? mEffectBuffer : mSinkBuffer));
     // Effect chain for session AUDIO_SESSION_OUTPUT_STAGE is inserted at end of effect
     // chains list in order to be processed last as it contains output stage effects
     // Effect chain for session AUDIO_SESSION_OUTPUT_MIX is inserted before
@@ -2203,7 +2213,7 @@
             for (size_t i = 0; i < mTracks.size(); ++i) {
                 sp<Track> track = mTracks[i];
                 if (session == track->sessionId()) {
-                    track->setMainBuffer(mSinkBuffer);
+                    track->setMainBuffer(reinterpret_cast<int16_t*>(mSinkBuffer));
                     chain->decTrackCnt();
                 }
             }
@@ -4471,7 +4481,15 @@
 ssize_t AudioFlinger::DuplicatingThread::threadLoop_write()
 {
     for (size_t i = 0; i < outputTracks.size(); i++) {
-        outputTracks[i]->write(mSinkBuffer, writeFrames);
+        // We convert the duplicating thread format to AUDIO_FORMAT_PCM_16_BIT
+        // for delivery downstream as needed. This in-place conversion is safe as
+        // AUDIO_FORMAT_PCM_16_BIT is smaller than any other supported format
+        // (AUDIO_FORMAT_PCM_8_BIT is not allowed here).
+        if (mFormat != AUDIO_FORMAT_PCM_16_BIT) {
+            memcpy_by_audio_format(mSinkBuffer, AUDIO_FORMAT_PCM_16_BIT,
+                    mSinkBuffer, mFormat, writeFrames * mChannelCount);
+        }
+        outputTracks[i]->write(reinterpret_cast<int16_t*>(mSinkBuffer), writeFrames);
     }
     mStandby = false;
     return (ssize_t)mSinkBufferSize;
@@ -4500,10 +4518,16 @@
     Mutex::Autolock _l(mLock);
     // FIXME explain this formula
     size_t frameCount = (3 * mNormalFrameCount * mSampleRate) / thread->sampleRate();
+    // OutputTrack is forced to AUDIO_FORMAT_PCM_16_BIT regardless of mFormat
+    // due to current usage case and restrictions on the AudioBufferProvider.
+    // Actual buffer conversion is done in threadLoop_write().
+    //
+    // TODO: This may change in the future, depending on multichannel
+    // (and non int16_t*) support on AF::PlaybackThread::OutputTrack
     OutputTrack *outputTrack = new OutputTrack(thread,
                                             this,
                                             mSampleRate,
-                                            mFormat,
+                                            AUDIO_FORMAT_PCM_16_BIT,
                                             mChannelMask,
                                             frameCount,
                                             IPCThreadState::self()->getCallingUid());
@@ -5036,6 +5060,7 @@
     mInput->stream->common.standby(&mInput->stream->common);
 }
 
+// RecordThread::createRecordTrack_l() must be called with AudioFlinger::mLock held
 sp<AudioFlinger::RecordThread::RecordTrack> AudioFlinger::RecordThread::createRecordTrack_l(
         const sp<AudioFlinger::Client>& client,
         uint32_t sampleRate,
@@ -5052,12 +5077,6 @@
     sp<RecordTrack> track;
     status_t lStatus;
 
-    lStatus = initCheck();
-    if (lStatus != NO_ERROR) {
-        ALOGE("createRecordTrack_l() audio driver not initialized");
-        goto Exit;
-    }
-
     // client expresses a preference for FAST, but we get the final say
     if (*flags & IAudioFlinger::TRACK_FAST) {
       if (
@@ -5110,7 +5129,11 @@
     }
     *pFrameCount = frameCount;
 
-    // FIXME use flags and tid similar to createTrack_l()
+    lStatus = initCheck();
+    if (lStatus != NO_ERROR) {
+        ALOGE("createRecordTrack_l() audio driver not initialized");
+        goto Exit;
+    }
 
     { // scope for mLock
         Mutex::Autolock _l(mLock);
@@ -5139,6 +5162,7 @@
             sendPrioConfigEvent_l(callingPid, tid, kPriorityAudioApp);
         }
     }
+
     lStatus = NO_ERROR;
 
 Exit:
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index 3af4874..59d5c66 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -450,8 +450,11 @@
     virtual     String8     getParameters(const String8& keys);
     virtual     void        audioConfigChanged_l(int event, int param = 0);
                 status_t    getRenderPosition(uint32_t *halFrames, uint32_t *dspFrames);
-                // TODO: rename mixBuffer() to sinkBuffer() or try to remove external use.
-                int16_t     *mixBuffer() const { return mSinkBuffer; };
+                // FIXME rename mixBuffer() to sinkBuffer() and remove int16_t* dependency.
+                // Consider also removing and passing an explicit mMainBuffer initialization
+                // parameter to AF::PlaybackThread::Track::Track().
+                int16_t     *mixBuffer() const {
+                    return reinterpret_cast<int16_t *>(mSinkBuffer); };
 
     virtual     void detachAuxEffect_l(int effectId);
                 status_t attachAuxEffect(const sp<AudioFlinger::PlaybackThread::Track> track,
@@ -482,7 +485,7 @@
     // updated by readOutputParameters_l()
     size_t                          mNormalFrameCount;  // normal mixer and effects
 
-    int16_t*                        mSinkBuffer;         // frame size aligned sink buffer
+    void*                           mSinkBuffer;         // frame size aligned sink buffer
 
     // TODO:
     // Rearrange the buffer info into a struct/class with
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index 92ed46a..f19cd88 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -350,39 +350,39 @@
     mResumeToStopping(false),
     mFlushHwPending(false)
 {
-    if (mCblk != NULL) {
-        if (sharedBuffer == 0) {
-            mAudioTrackServerProxy = new AudioTrackServerProxy(mCblk, mBuffer, frameCount,
-                    mFrameSize);
-        } else {
-            mAudioTrackServerProxy = new StaticAudioTrackServerProxy(mCblk, mBuffer, frameCount,
-                    mFrameSize);
-        }
-        mServerProxy = mAudioTrackServerProxy;
-        // to avoid leaking a track name, do not allocate one unless there is an mCblk
-        mName = thread->getTrackName_l(channelMask, sessionId);
-        if (mName < 0) {
-            ALOGE("no more track names available");
-            return;
-        }
-        // only allocate a fast track index if we were able to allocate a normal track name
-        if (flags & IAudioFlinger::TRACK_FAST) {
-            mAudioTrackServerProxy->framesReadyIsCalledByMultipleThreads();
-            ALOG_ASSERT(thread->mFastTrackAvailMask != 0);
-            int i = __builtin_ctz(thread->mFastTrackAvailMask);
-            ALOG_ASSERT(0 < i && i < (int)FastMixerState::kMaxFastTracks);
-            // FIXME This is too eager.  We allocate a fast track index before the
-            //       fast track becomes active.  Since fast tracks are a scarce resource,
-            //       this means we are potentially denying other more important fast tracks from
-            //       being created.  It would be better to allocate the index dynamically.
-            mFastIndex = i;
-            // Read the initial underruns because this field is never cleared by the fast mixer
-            mObservedUnderruns = thread->getFastTrackUnderruns(i);
-            thread->mFastTrackAvailMask &= ~(1 << i);
-        }
+    if (mCblk == NULL) {
+        return;
     }
-    ALOGV("Track constructor name %d, calling pid %d", mName,
-            IPCThreadState::self()->getCallingPid());
+
+    if (sharedBuffer == 0) {
+        mAudioTrackServerProxy = new AudioTrackServerProxy(mCblk, mBuffer, frameCount,
+                mFrameSize);
+    } else {
+        mAudioTrackServerProxy = new StaticAudioTrackServerProxy(mCblk, mBuffer, frameCount,
+                mFrameSize);
+    }
+    mServerProxy = mAudioTrackServerProxy;
+
+    mName = thread->getTrackName_l(channelMask, sessionId);
+    if (mName < 0) {
+        ALOGE("no more track names available");
+        return;
+    }
+    // only allocate a fast track index if we were able to allocate a normal track name
+    if (flags & IAudioFlinger::TRACK_FAST) {
+        mAudioTrackServerProxy->framesReadyIsCalledByMultipleThreads();
+        ALOG_ASSERT(thread->mFastTrackAvailMask != 0);
+        int i = __builtin_ctz(thread->mFastTrackAvailMask);
+        ALOG_ASSERT(0 < i && i < (int)FastMixerState::kMaxFastTracks);
+        // FIXME This is too eager.  We allocate a fast track index before the
+        //       fast track becomes active.  Since fast tracks are a scarce resource,
+        //       this means we are potentially denying other more important fast tracks from
+        //       being created.  It would be better to allocate the index dynamically.
+        mFastIndex = i;
+        // Read the initial underruns because this field is never cleared by the fast mixer
+        mObservedUnderruns = thread->getFastTrackUnderruns(i);
+        thread->mFastTrackAvailMask &= ~(1 << i);
+    }
 }
 
 AudioFlinger::PlaybackThread::Track::~Track()
@@ -1773,7 +1773,7 @@
 
 // ----------------------------------------------------------------------------
 
-// RecordTrack constructor must be called with AudioFlinger::mLock held
+// RecordTrack constructor must be called with AudioFlinger::mLock and ThreadBase::mLock held
 AudioFlinger::RecordThread::RecordTrack::RecordTrack(
             RecordThread *thread,
             const sp<Client>& client,
@@ -1789,11 +1789,12 @@
         // See real initialization of mRsmpInFront at RecordThread::start()
         mRsmpInUnrel(0), mRsmpInFront(0), mFramesToDrop(0), mResamplerBufferProvider(NULL)
 {
-    ALOGV("RecordTrack constructor");
-    if (mCblk != NULL) {
-        mServerProxy = new AudioRecordServerProxy(mCblk, mBuffer, frameCount, mFrameSize);
+    if (mCblk == NULL) {
+        return;
     }
 
+    mServerProxy = new AudioRecordServerProxy(mCblk, mBuffer, frameCount, mFrameSize);
+
     uint32_t channelCount = popcount(channelMask);
     // FIXME I don't understand either of the channel count checks
     if (thread->mSampleRate != sampleRate && thread->mChannelCount <= FCC_2 &&
diff --git a/services/camera/libcameraservice/Android.mk b/services/camera/libcameraservice/Android.mk
index 51ba698..4e2272d 100644
--- a/services/camera/libcameraservice/Android.mk
+++ b/services/camera/libcameraservice/Android.mk
@@ -1,3 +1,17 @@
+# Copyright 2010 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
 LOCAL_PATH:= $(call my-dir)
 
 #
@@ -53,11 +67,13 @@
 
 LOCAL_C_INCLUDES += \
     system/media/camera/include \
+    system/media/private/camera/include \
     external/jpeg
 
 
 LOCAL_CFLAGS += -Wall -Wextra
 
 LOCAL_MODULE:= libcameraservice
+LOCAL_32_BIT_ONLY := true
 
 include $(BUILD_SHARED_LIBRARY)
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index 79fbf76..b83c315 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -1,24 +1,24 @@
 /*
-**
-** Copyright (C) 2008, 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.
-*/
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 
 #define LOG_TAG "CameraService"
 //#define LOG_NDEBUG 0
 
 #include <stdio.h>
+#include <string.h>
 #include <sys/types.h>
 #include <pthread.h>
 
@@ -37,6 +37,8 @@
 #include <utils/Errors.h>
 #include <utils/Log.h>
 #include <utils/String16.h>
+#include <utils/Trace.h>
+#include <system/camera_vendor_tags.h>
 
 #include "CameraService.h"
 #include "api1/CameraClient.h"
@@ -131,6 +133,12 @@
             mModule->set_callbacks(this);
         }
 
+        VendorTagDescriptor::clearGlobalVendorTagDescriptor();
+
+        if (mModule->common.module_api_version >= CAMERA_MODULE_API_VERSION_2_2) {
+            setUpVendorTags();
+        }
+
         CameraDeviceFactory::registerService(this);
     }
 }
@@ -142,6 +150,7 @@
         }
     }
 
+    VendorTagDescriptor::clearGlobalVendorTagDescriptor();
     gCameraService = NULL;
 }
 
@@ -270,6 +279,22 @@
     return ret;
 }
 
+status_t CameraService::getCameraVendorTagDescriptor(/*out*/sp<VendorTagDescriptor>& desc) {
+    if (!mModule) {
+        ALOGE("%s: camera hardware module doesn't exist", __FUNCTION__);
+        return -ENODEV;
+    }
+
+    if (mModule->common.module_api_version < CAMERA_MODULE_API_VERSION_2_2) {
+        // TODO: Remove this check once HAL1 shim is in place.
+        ALOGW("%s: Only HAL module version V2.2 or higher supports vendor tags", __FUNCTION__);
+        return -EOPNOTSUPP;
+    }
+
+    desc = VendorTagDescriptor::getGlobalVendorTagDescriptor();
+    return OK;
+}
+
 int CameraService::getDeviceVersion(int cameraId, int* facing) {
     struct camera_info info;
     if (mModule->get_camera_info(cameraId, &info) != OK) {
@@ -307,6 +332,44 @@
     return false;
 }
 
+bool CameraService::setUpVendorTags() {
+    vendor_tag_ops_t vOps = vendor_tag_ops_t();
+
+    // Check if vendor operations have been implemented
+    if (mModule->get_vendor_tag_ops == NULL) {
+        ALOGI("%s: No vendor tags defined for this device.", __FUNCTION__);
+        return false;
+    }
+
+    ATRACE_BEGIN("camera3->get_metadata_vendor_tag_ops");
+    mModule->get_vendor_tag_ops(&vOps);
+    ATRACE_END();
+
+    // Ensure all vendor operations are present
+    if (vOps.get_tag_count == NULL || vOps.get_all_tags == NULL ||
+            vOps.get_section_name == NULL || vOps.get_tag_name == NULL ||
+            vOps.get_tag_type == NULL) {
+        ALOGE("%s: Vendor tag operations not fully defined. Ignoring definitions."
+               , __FUNCTION__);
+        return false;
+    }
+
+    // Read all vendor tag definitions into a descriptor
+    sp<VendorTagDescriptor> desc;
+    status_t res;
+    if ((res = VendorTagDescriptor::createDescriptorFromOps(&vOps, /*out*/desc))
+            != OK) {
+        ALOGE("%s: Could not generate descriptor from vendor tag operations,"
+              "received error %s (%d). Camera clients will not be able to use"
+              "vendor tags", __FUNCTION__, strerror(res), res);
+        return false;
+    }
+
+    // Set the global descriptor to use with camera metadata
+    VendorTagDescriptor::setAsGlobalVendorTagDescriptor(desc);
+    return true;
+}
+
 status_t CameraService::validateConnect(int cameraId,
                                     /*inout*/
                                     int& clientUid) const {
@@ -656,6 +719,11 @@
                                 const sp<ICameraServiceListener>& listener) {
     ALOGV("%s: Add listener %p", __FUNCTION__, listener.get());
 
+    if (listener == 0) {
+        ALOGE("%s: Listener must not be null", __FUNCTION__);
+        return BAD_VALUE;
+    }
+
     Mutex::Autolock lock(mServiceLock);
 
     Vector<sp<ICameraServiceListener> >::iterator it, end;
@@ -684,6 +752,11 @@
                                 const sp<ICameraServiceListener>& listener) {
     ALOGV("%s: Remove listener %p", __FUNCTION__, listener.get());
 
+    if (listener == 0) {
+        ALOGE("%s: Listener must not be null", __FUNCTION__);
+        return BAD_VALUE;
+    }
+
     Mutex::Autolock lock(mServiceLock);
 
     Vector<sp<ICameraServiceListener> >::iterator it;
diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h
index ad6a582..8853e48 100644
--- a/services/camera/libcameraservice/CameraService.h
+++ b/services/camera/libcameraservice/CameraService.h
@@ -1,19 +1,18 @@
 /*
-**
-** Copyright (C) 2008, 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.
-*/
+ * Copyright (C) 2008 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_SERVERS_CAMERA_CAMERASERVICE_H
 #define ANDROID_SERVERS_CAMERA_CAMERASERVICE_H
@@ -31,6 +30,7 @@
 #include <camera/IProCameraCallbacks.h>
 #include <camera/camera2/ICameraDeviceUser.h>
 #include <camera/camera2/ICameraDeviceCallbacks.h>
+#include <camera/VendorTagDescriptor.h>
 
 #include <camera/ICameraServiceListener.h>
 
@@ -73,6 +73,7 @@
                                       struct CameraInfo* cameraInfo);
     virtual status_t    getCameraCharacteristics(int cameraId,
                                                  CameraMetadata* cameraInfo);
+    virtual status_t    getCameraVendorTagDescriptor(/*out*/ sp<VendorTagDescriptor>& desc);
 
     virtual status_t connect(const sp<ICameraClient>& cameraClient, int cameraId,
             const String16& clientPackageName, int clientUid,
@@ -387,6 +388,8 @@
     // Helpers
 
     bool                isValidCameraId(int cameraId);
+
+    bool                setUpVendorTags();
 };
 
 } // namespace android
diff --git a/services/camera/libcameraservice/device2/Camera2Device.cpp b/services/camera/libcameraservice/device2/Camera2Device.cpp
index dc97c47..f60ca98 100644
--- a/services/camera/libcameraservice/device2/Camera2Device.cpp
+++ b/services/camera/libcameraservice/device2/Camera2Device.cpp
@@ -112,20 +112,6 @@
         return res;
     }
 
-    res = device->ops->get_metadata_vendor_tag_ops(device, &mVendorTagOps);
-    if (res != OK ) {
-        ALOGE("%s: Camera %d: Unable to retrieve tag ops from device: %s (%d)",
-                __FUNCTION__, mId, strerror(-res), res);
-        device->common.close(&device->common);
-        return res;
-    }
-    res = set_camera_metadata_vendor_tag_ops(mVendorTagOps);
-    if (res != OK) {
-        ALOGE("%s: Camera %d: Unable to set tag ops: %s (%d)",
-            __FUNCTION__, mId, strerror(-res), res);
-        device->common.close(&device->common);
-        return res;
-    }
     res = device->ops->set_notify_callback(device, notificationCallback,
             NULL);
     if (res != OK) {
diff --git a/services/camera/libcameraservice/device2/Camera2Device.h b/services/camera/libcameraservice/device2/Camera2Device.h
index 1f53c56..5b91f88 100644
--- a/services/camera/libcameraservice/device2/Camera2Device.h
+++ b/services/camera/libcameraservice/device2/Camera2Device.h
@@ -78,7 +78,6 @@
     camera2_device_t *mHal2Device;
 
     CameraMetadata mDeviceInfo;
-    vendor_tag_query_ops_t *mVendorTagOps;
 
     /**
      * Queue class for both sending requests to a camera2 device, and for
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index da3e121..08e03ce 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -146,24 +146,6 @@
         return BAD_VALUE;
     }
 
-    /** Get vendor metadata tags */
-
-    mVendorTagOps.get_camera_vendor_section_name = NULL;
-
-    ATRACE_BEGIN("camera3->get_metadata_vendor_tag_ops");
-    device->ops->get_metadata_vendor_tag_ops(device, &mVendorTagOps);
-    ATRACE_END();
-
-    if (mVendorTagOps.get_camera_vendor_section_name != NULL) {
-        res = set_camera_metadata_vendor_tag_ops(&mVendorTagOps);
-        if (res != OK) {
-            SET_ERR_L("Unable to set tag ops: %s (%d)",
-                    strerror(-res), res);
-            device->common.close(&device->common);
-            return res;
-        }
-    }
-
     /** Start up status tracker thread */
     mStatusTracker = new StatusTracker(this);
     res = mStatusTracker->run(String8::format("C3Dev-%d-Status", mId).string());
diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h
index 468f641..9007a9b 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.h
+++ b/services/camera/libcameraservice/device3/Camera3Device.h
@@ -157,7 +157,6 @@
     camera3_device_t          *mHal3Device;
 
     CameraMetadata             mDeviceInfo;
-    vendor_tag_query_ops_t     mVendorTagOps;
 
     enum Status {
         STATUS_ERROR,
diff --git a/services/medialog/Android.mk b/services/medialog/Android.mk
index 08006c8..95f2fef 100644
--- a/services/medialog/Android.mk
+++ b/services/medialog/Android.mk
@@ -8,4 +8,6 @@
 
 LOCAL_MODULE:= libmedialogservice
 
+LOCAL_32_BIT_ONLY := true
+
 include $(BUILD_SHARED_LIBRARY)