Fix potential NULL dereference in Visualizer effect am: 874f9e0b8e am: f060479b9a
am: bcc7230bb9

Change-Id: If5d6fefb276341472d827bac3f349561f7d1d990
diff --git a/CleanSpec.mk b/CleanSpec.mk
index e6d9ebf..d0890fe 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -47,6 +47,19 @@
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/lib/libmedia_native.so)
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/symbols/system/lib/libmedia_native.so)
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/lib/libmedia_native.so)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libaudioflinger_intermediates)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/lib/libaudioflinger.so)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libaudiopolicy_intermediates)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/lib/libaudiopolicy.so)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libaudiopolicy_intermediates)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/lib/libaudiopolicy.so)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libaudiopolicyservice_intermediates)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libaudiopolicymanager_intermediates)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/lib/libaudiopolicyservice.so)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/lib/libaudiopolicymanager.so)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libaudiopolicyservice_intermediates)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libaudiopolicymanager_intermediates)
+
 # ************************************************
 # NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
 # ************************************************
diff --git a/camera/Android.mk b/camera/Android.mk
index 5cedab0..da5ac59 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)
@@ -8,6 +22,7 @@
 	Camera.cpp \
 	CameraMetadata.cpp \
 	CameraParameters.cpp \
+	CaptureResult.cpp \
 	CameraParameters2.cpp \
 	ICamera.cpp \
 	ICameraClient.cpp \
@@ -22,6 +37,8 @@
 	camera2/CaptureRequest.cpp \
 	ProCamera.cpp \
 	CameraBase.cpp \
+	CameraUtils.cpp \
+	VendorTagDescriptor.cpp
 
 LOCAL_SHARED_LIBRARIES := \
 	libcutils \
@@ -35,6 +52,7 @@
 
 LOCAL_C_INCLUDES += \
 	system/media/camera/include \
+	system/media/private/camera/include \
 
 LOCAL_MODULE:= libcamera_client
 
diff --git a/camera/Camera.cpp b/camera/Camera.cpp
index 22199fa..85f44f0 100644
--- a/camera/Camera.cpp
+++ b/camera/Camera.cpp
@@ -77,6 +77,32 @@
     return CameraBaseT::connect(cameraId, clientPackageName, clientUid);
 }
 
+status_t Camera::connectLegacy(int cameraId, int halVersion,
+        const String16& clientPackageName,
+        int clientUid,
+        sp<Camera>& camera)
+{
+    ALOGV("%s: connect legacy camera device", __FUNCTION__);
+    sp<Camera> c = new Camera(cameraId);
+    sp<ICameraClient> cl = c;
+    status_t status = NO_ERROR;
+    const sp<ICameraService>& cs = CameraBaseT::getCameraService();
+
+    if (cs != 0) {
+        status = cs.get()->connectLegacy(cl, cameraId, halVersion, clientPackageName,
+                                        clientUid, /*out*/c->mCamera);
+    }
+    if (status == OK && c->mCamera != 0) {
+        c->mCamera->asBinder()->linkToDeath(c);
+        c->mStatus = NO_ERROR;
+        camera = c;
+    } else {
+        ALOGW("An error occurred while connecting to camera: %d", cameraId);
+        c.clear();
+    }
+    return status;
+}
+
 status_t Camera::reconnect()
 {
     ALOGV("reconnect");
diff --git a/camera/CameraBase.cpp b/camera/CameraBase.cpp
index 55376b0..04694cd 100644
--- a/camera/CameraBase.cpp
+++ b/camera/CameraBase.cpp
@@ -49,7 +49,7 @@
         DeathNotifier() {
         }
 
-        virtual void binderDied(const wp<IBinder>& who) {
+        virtual void binderDied(const wp<IBinder>& /*who*/) {
             ALOGV("binderDied");
             Mutex::Autolock _l(gLock);
             gCameraService.clear();
@@ -153,7 +153,7 @@
 }
 
 template <typename TCam, typename TCamTraits>
-void CameraBase<TCam, TCamTraits>::binderDied(const wp<IBinder>& who) {
+void CameraBase<TCam, TCamTraits>::binderDied(const wp<IBinder>& /*who*/) {
     ALOGW("mediaserver's remote binder Camera object died");
     notifyCallback(CAMERA_MSG_ERROR, CAMERA_ERROR_SERVER_DIED, /*ext2*/0);
 }
diff --git a/camera/CameraMetadata.cpp b/camera/CameraMetadata.cpp
index 7765914..043437f 100644
--- a/camera/CameraMetadata.cpp
+++ b/camera/CameraMetadata.cpp
@@ -25,6 +25,9 @@
 
 namespace android {
 
+#define ALIGN_TO(val, alignment) \
+    (((uintptr_t)(val) + ((alignment) - 1)) & ~((alignment) - 1))
+
 typedef Parcel::WritableBlob WritableBlob;
 typedef Parcel::ReadableBlob ReadableBlob;
 
@@ -270,7 +273,8 @@
     if ( (res = checkType(tag, TYPE_BYTE)) != OK) {
         return res;
     }
-    return updateImpl(tag, (const void*)string.string(), string.size());
+    // string.size() doesn't count the null termination character.
+    return updateImpl(tag, (const void*)string.string(), string.size() + 1);
 }
 
 status_t CameraMetadata::updateImpl(uint32_t tag, const void *data,
@@ -431,40 +435,70 @@
         *out = NULL;
     }
 
-    // arg0 = metadataSize (int32)
-    int32_t metadataSizeTmp = -1;
-    if ((err = data.readInt32(&metadataSizeTmp)) != OK) {
+    // See CameraMetadata::writeToParcel for parcel data layout diagram and explanation.
+    // arg0 = blobSize (int32)
+    int32_t blobSizeTmp = -1;
+    if ((err = data.readInt32(&blobSizeTmp)) != OK) {
         ALOGE("%s: Failed to read metadata size (error %d %s)",
               __FUNCTION__, err, strerror(-err));
         return err;
     }
-    const size_t metadataSize = static_cast<size_t>(metadataSizeTmp);
+    const size_t blobSize = static_cast<size_t>(blobSizeTmp);
+    const size_t alignment = get_camera_metadata_alignment();
 
-    if (metadataSize == 0) {
+    // Special case: zero blob size means zero sized (NULL) metadata.
+    if (blobSize == 0) {
         ALOGV("%s: Read 0-sized metadata", __FUNCTION__);
         return OK;
     }
 
-    // NOTE: this doesn't make sense to me. shouldnt the blob
+    if (blobSize <= alignment) {
+        ALOGE("%s: metadata blob is malformed, blobSize(%zu) should be larger than alignment(%zu)",
+                __FUNCTION__, blobSize, alignment);
+        return BAD_VALUE;
+    }
+
+    const size_t metadataSize = blobSize - alignment;
+
+    // NOTE: this doesn't make sense to me. shouldn't the blob
     // know how big it is? why do we have to specify the size
     // to Parcel::readBlob ?
-
     ReadableBlob blob;
     // arg1 = metadata (blob)
     do {
-        if ((err = data.readBlob(metadataSize, &blob)) != OK) {
-            ALOGE("%s: Failed to read metadata blob (sized %d). Possible "
+        if ((err = data.readBlob(blobSize, &blob)) != OK) {
+            ALOGE("%s: Failed to read metadata blob (sized %zu). Possible "
                   " serialization bug. Error %d %s",
-                  __FUNCTION__, metadataSize, err, strerror(-err));
+                  __FUNCTION__, blobSize, err, strerror(-err));
             break;
         }
-        const camera_metadata_t* tmp =
-                       reinterpret_cast<const camera_metadata_t*>(blob.data());
 
+        // arg2 = offset (blob)
+        // Must be after blob since we don't know offset until after writeBlob.
+        int32_t offsetTmp;
+        if ((err = data.readInt32(&offsetTmp)) != OK) {
+            ALOGE("%s: Failed to read metadata offsetTmp (error %d %s)",
+                  __FUNCTION__, err, strerror(-err));
+            break;
+        }
+        const size_t offset = static_cast<size_t>(offsetTmp);
+        if (offset >= alignment) {
+            ALOGE("%s: metadata offset(%zu) should be less than alignment(%zu)",
+                    __FUNCTION__, blobSize, alignment);
+            err = BAD_VALUE;
+            break;
+        }
+
+        const uintptr_t metadataStart = reinterpret_cast<uintptr_t>(blob.data()) + offset;
+        const camera_metadata_t* tmp =
+                       reinterpret_cast<const camera_metadata_t*>(metadataStart);
+        ALOGV("%s: alignment is: %zu, metadata start: %p, offset: %zu",
+                __FUNCTION__, alignment, tmp, offset);
         metadata = allocate_copy_camera_metadata_checked(tmp, metadataSize);
         if (metadata == NULL) {
             // We consider that allocation only fails if the validation
             // also failed, therefore the readFromParcel was a failure.
+            ALOGE("%s: metadata allocation and copy failed", __FUNCTION__);
             err = BAD_VALUE;
         }
     } while(0);
@@ -485,38 +519,80 @@
                                        const camera_metadata_t* metadata) {
     status_t res = OK;
 
-    // arg0 = metadataSize (int32)
+    /**
+     * Below is the camera metadata parcel layout:
+     *
+     * |--------------------------------------------|
+     * |             arg0: blobSize                 |
+     * |              (length = 4)                  |
+     * |--------------------------------------------|<--Skip the rest if blobSize == 0.
+     * |                                            |
+     * |                                            |
+     * |              arg1: blob                    |
+     * | (length = variable, see arg1 layout below) |
+     * |                                            |
+     * |                                            |
+     * |--------------------------------------------|
+     * |              arg2: offset                  |
+     * |              (length = 4)                  |
+     * |--------------------------------------------|
+     */
 
+    // arg0 = blobSize (int32)
     if (metadata == NULL) {
+        // Write zero blobSize for null metadata.
         return data.writeInt32(0);
     }
 
+    /**
+     * Always make the blob size sufficiently larger, as we need put alignment
+     * padding and metadata into the blob. Since we don't know the alignment
+     * offset before writeBlob. Then write the metadata to aligned offset.
+     */
     const size_t metadataSize = get_camera_metadata_compact_size(metadata);
-    res = data.writeInt32(static_cast<int32_t>(metadataSize));
+    const size_t alignment = get_camera_metadata_alignment();
+    const size_t blobSize = metadataSize + alignment;
+    res = data.writeInt32(static_cast<int32_t>(blobSize));
     if (res != OK) {
         return res;
     }
 
-    // arg1 = metadata (blob)
+    size_t offset = 0;
+    /**
+     * arg1 = metadata (blob).
+     *
+     * The blob size is the sum of front padding size, metadata size and back padding
+     * size, which is equal to metadataSize + alignment.
+     *
+     * The blob layout is:
+     * |------------------------------------|<----Start address of the blob (unaligned).
+     * |           front padding            |
+     * |          (size = offset)           |
+     * |------------------------------------|<----Aligned start address of metadata.
+     * |                                    |
+     * |                                    |
+     * |            metadata                |
+     * |       (size = metadataSize)        |
+     * |                                    |
+     * |                                    |
+     * |------------------------------------|
+     * |           back padding             |
+     * |     (size = alignment - offset)    |
+     * |------------------------------------|<----End address of blob.
+     *                                            (Blob start address + blob size).
+     */
     WritableBlob blob;
     do {
-        res = data.writeBlob(metadataSize, &blob);
+        res = data.writeBlob(blobSize, &blob);
         if (res != OK) {
             break;
         }
-        copy_camera_metadata(blob.data(), metadataSize, metadata);
-
-        IF_ALOGV() {
-            if (validate_camera_metadata_structure(
-                        (const camera_metadata_t*)blob.data(),
-                        &metadataSize) != OK) {
-                ALOGV("%s: Failed to validate metadata %p after writing blob",
-                       __FUNCTION__, blob.data());
-            } else {
-                ALOGV("%s: Metadata written to blob. Validation success",
-                        __FUNCTION__);
-            }
-        }
+        const uintptr_t metadataStart = ALIGN_TO(blob.data(), alignment);
+        offset = metadataStart - reinterpret_cast<uintptr_t>(blob.data());
+        ALOGV("%s: alignment is: %zu, metadata start: %p, offset: %zu",
+                __FUNCTION__, alignment,
+                reinterpret_cast<const void *>(metadataStart), offset);
+        copy_camera_metadata(reinterpret_cast<void*>(metadataStart), metadataSize, metadata);
 
         // Not too big of a problem since receiving side does hard validation
         // Don't check the size since the compact size could be larger
@@ -528,6 +604,9 @@
     } while(false);
     blob.release();
 
+    // arg2 = offset (int32)
+    res = data.writeInt32(static_cast<int32_t>(offset));
+
     return res;
 }
 
diff --git a/camera/CameraParameters.cpp b/camera/CameraParameters.cpp
index c51f265..25d632d 100644
--- a/camera/CameraParameters.cpp
+++ b/camera/CameraParameters.cpp
@@ -21,6 +21,7 @@
 #include <string.h>
 #include <stdlib.h>
 #include <camera/CameraParameters.h>
+#include <system/graphics.h>
 
 namespace android {
 // Parameter keys to communicate between camera application and driver.
@@ -456,7 +457,7 @@
 
 void CameraParameters::dump() const
 {
-    ALOGD("dump: mMap.size = %d", mMap.size());
+    ALOGD("dump: mMap.size = %zu", mMap.size());
     for (size_t i = 0; i < mMap.size(); i++) {
         String8 k, v;
         k = mMap.keyAt(i);
@@ -465,12 +466,12 @@
     }
 }
 
-status_t CameraParameters::dump(int fd, const Vector<String16>& args) const
+status_t CameraParameters::dump(int fd, const Vector<String16>& /*args*/) const
 {
     const size_t SIZE = 256;
     char buffer[SIZE];
     String8 result;
-    snprintf(buffer, 255, "CameraParameters::dump: mMap.size = %d\n", mMap.size());
+    snprintf(buffer, 255, "CameraParameters::dump: mMap.size = %zu\n", mMap.size());
     result.append(buffer);
     for (size_t i = 0; i < mMap.size(); i++) {
         String8 k, v;
@@ -483,4 +484,45 @@
     return NO_ERROR;
 }
 
+void CameraParameters::getSupportedPreviewFormats(Vector<int>& formats) const {
+    const char* supportedPreviewFormats =
+          get(CameraParameters::KEY_SUPPORTED_PREVIEW_FORMATS);
+
+    String8 fmtStr(supportedPreviewFormats);
+    char* prevFmts = fmtStr.lockBuffer(fmtStr.size());
+
+    char* savePtr;
+    char* fmt = strtok_r(prevFmts, ",", &savePtr);
+    while (fmt) {
+        int actual = previewFormatToEnum(fmt);
+        if (actual != -1) {
+            formats.add(actual);
+        }
+        fmt = strtok_r(NULL, ",", &savePtr);
+    }
+    fmtStr.unlockBuffer(fmtStr.size());
+}
+
+
+int CameraParameters::previewFormatToEnum(const char* format) {
+    return
+        !format ?
+            HAL_PIXEL_FORMAT_YCrCb_420_SP :
+        !strcmp(format, PIXEL_FORMAT_YUV422SP) ?
+            HAL_PIXEL_FORMAT_YCbCr_422_SP : // NV16
+        !strcmp(format, PIXEL_FORMAT_YUV420SP) ?
+            HAL_PIXEL_FORMAT_YCrCb_420_SP : // NV21
+        !strcmp(format, PIXEL_FORMAT_YUV422I) ?
+            HAL_PIXEL_FORMAT_YCbCr_422_I :  // YUY2
+        !strcmp(format, PIXEL_FORMAT_YUV420P) ?
+            HAL_PIXEL_FORMAT_YV12 :         // YV12
+        !strcmp(format, PIXEL_FORMAT_RGB565) ?
+            HAL_PIXEL_FORMAT_RGB_565 :      // RGB565
+        !strcmp(format, PIXEL_FORMAT_RGBA8888) ?
+            HAL_PIXEL_FORMAT_RGBA_8888 :    // RGB8888
+        !strcmp(format, PIXEL_FORMAT_BAYER_RGGB) ?
+            HAL_PIXEL_FORMAT_RAW_SENSOR :   // Raw sensor data
+        -1;
+}
+
 }; // namespace android
diff --git a/camera/CameraParameters2.cpp b/camera/CameraParameters2.cpp
index eac79e1..378afeb 100644
--- a/camera/CameraParameters2.cpp
+++ b/camera/CameraParameters2.cpp
@@ -362,6 +362,7 @@
 
 status_t CameraParameters2::dump(int fd, const Vector<String16>& args) const
 {
+    (void)args;
     const size_t SIZE = 256;
     char buffer[SIZE];
     String8 result;
diff --git a/camera/CameraUtils.cpp b/camera/CameraUtils.cpp
new file mode 100644
index 0000000..04244ac
--- /dev/null
+++ b/camera/CameraUtils.cpp
@@ -0,0 +1,125 @@
+/*
+ * 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 "CameraUtils"
+//#define LOG_NDEBUG 0
+
+#include <camera/CameraUtils.h>
+
+#include <system/window.h>
+#include <system/graphics.h>
+
+#include <utils/Log.h>
+
+namespace android {
+
+status_t CameraUtils::getRotationTransform(const CameraMetadata& staticInfo,
+                /*out*/int32_t* transform) {
+    ALOGV("%s", __FUNCTION__);
+
+    if (transform == NULL) {
+        ALOGW("%s: null transform", __FUNCTION__);
+        return BAD_VALUE;
+    }
+
+    *transform = 0;
+
+    camera_metadata_ro_entry_t entry = staticInfo.find(ANDROID_SENSOR_ORIENTATION);
+    if (entry.count == 0) {
+        ALOGE("%s: Can't find android.sensor.orientation in static metadata!", __FUNCTION__);
+        return INVALID_OPERATION;
+    }
+
+    camera_metadata_ro_entry_t entryFacing = staticInfo.find(ANDROID_LENS_FACING);
+    if (entry.count == 0) {
+        ALOGE("%s: Can't find android.lens.facing in static metadata!", __FUNCTION__);
+        return INVALID_OPERATION;
+    }
+
+    int32_t& flags = *transform;
+
+    bool mirror = (entryFacing.data.u8[0] == ANDROID_LENS_FACING_FRONT);
+    int orientation = entry.data.i32[0];
+    if (!mirror) {
+        switch (orientation) {
+            case 0:
+                flags = 0;
+                break;
+            case 90:
+                flags = NATIVE_WINDOW_TRANSFORM_ROT_90;
+                break;
+            case 180:
+                flags = NATIVE_WINDOW_TRANSFORM_ROT_180;
+                break;
+            case 270:
+                flags = NATIVE_WINDOW_TRANSFORM_ROT_270;
+                break;
+            default:
+                ALOGE("%s: Invalid HAL android.sensor.orientation value: %d",
+                      __FUNCTION__, orientation);
+                return INVALID_OPERATION;
+        }
+    } else {
+        // Front camera needs to be horizontally flipped for mirror-like behavior.
+        // Note: Flips are applied before rotates; using XOR here as some of these flags are
+        // composed in terms of other flip/rotation flags, and are not bitwise-ORable.
+        switch (orientation) {
+            case 0:
+                flags = NATIVE_WINDOW_TRANSFORM_FLIP_H;
+                break;
+            case 90:
+                flags = NATIVE_WINDOW_TRANSFORM_FLIP_H ^
+                        NATIVE_WINDOW_TRANSFORM_ROT_270;
+                break;
+            case 180:
+                flags = NATIVE_WINDOW_TRANSFORM_FLIP_H ^
+                        NATIVE_WINDOW_TRANSFORM_ROT_180;
+                break;
+            case 270:
+                flags = NATIVE_WINDOW_TRANSFORM_FLIP_H ^
+                        NATIVE_WINDOW_TRANSFORM_ROT_90;
+
+                break;
+            default:
+                ALOGE("%s: Invalid HAL android.sensor.orientation value: %d",
+                      __FUNCTION__, orientation);
+                return INVALID_OPERATION;
+        }
+
+    }
+
+    /**
+     * This magic flag makes surfaceflinger un-rotate the buffers
+     * to counter the extra global device UI rotation whenever the user
+     * physically rotates the device.
+     *
+     * By doing this, the camera buffer always ends up aligned
+     * with the physical camera for a "see through" effect.
+     *
+     * In essence, the buffer only gets rotated during preview use-cases.
+     * The user is still responsible to re-create streams of the proper
+     * aspect ratio, or the preview will end up looking non-uniformly
+     * stretched.
+     */
+    flags |= NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY;
+
+    ALOGV("%s: final transform = 0x%x", __FUNCTION__, flags);
+
+    return OK;
+}
+
+
+} /* namespace android */
diff --git a/camera/CaptureResult.cpp b/camera/CaptureResult.cpp
new file mode 100644
index 0000000..4e36160
--- /dev/null
+++ b/camera/CaptureResult.cpp
@@ -0,0 +1,129 @@
+/*
+ * 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 "Camera-CaptureResult"
+#include <utils/Log.h>
+
+#include <camera/CaptureResult.h>
+#include <binder/Parcel.h>
+
+namespace android {
+
+bool CaptureResultExtras::isValid() {
+    return requestId >= 0;
+}
+
+status_t CaptureResultExtras::readFromParcel(Parcel *parcel) {
+    if (parcel == NULL) {
+        ALOGE("%s: Null parcel", __FUNCTION__);
+        return BAD_VALUE;
+    }
+
+    parcel->readInt32(&requestId);
+    parcel->readInt32(&burstId);
+    parcel->readInt32(&afTriggerId);
+    parcel->readInt32(&precaptureTriggerId);
+    parcel->readInt64(&frameNumber);
+    parcel->readInt32(&partialResultCount);
+
+    return OK;
+}
+
+status_t CaptureResultExtras::writeToParcel(Parcel *parcel) const {
+    if (parcel == NULL) {
+        ALOGE("%s: Null parcel", __FUNCTION__);
+        return BAD_VALUE;
+    }
+
+    parcel->writeInt32(requestId);
+    parcel->writeInt32(burstId);
+    parcel->writeInt32(afTriggerId);
+    parcel->writeInt32(precaptureTriggerId);
+    parcel->writeInt64(frameNumber);
+    parcel->writeInt32(partialResultCount);
+
+    return OK;
+}
+
+CaptureResult::CaptureResult() :
+        mMetadata(), mResultExtras() {
+}
+
+CaptureResult::CaptureResult(const CaptureResult &otherResult) {
+    mResultExtras = otherResult.mResultExtras;
+    mMetadata = otherResult.mMetadata;
+}
+
+status_t CaptureResult::readFromParcel(Parcel *parcel) {
+
+    ALOGV("%s: parcel = %p", __FUNCTION__, parcel);
+
+    if (parcel == NULL) {
+        ALOGE("%s: parcel is null", __FUNCTION__);
+        return BAD_VALUE;
+    }
+
+    mMetadata.clear();
+
+    status_t res = OK;
+    res = mMetadata.readFromParcel(parcel);
+    if (res != OK) {
+        ALOGE("%s: Failed to read metadata from parcel.",
+              __FUNCTION__);
+        return res;
+    }
+    ALOGV("%s: Read metadata from parcel", __FUNCTION__);
+
+    res = mResultExtras.readFromParcel(parcel);
+    if (res != OK) {
+        ALOGE("%s: Failed to read result extras from parcel.",
+                __FUNCTION__);
+        return res;
+    }
+    ALOGV("%s: Read result extras from parcel", __FUNCTION__);
+
+    return OK;
+}
+
+status_t CaptureResult::writeToParcel(Parcel *parcel) const {
+
+    ALOGV("%s: parcel = %p", __FUNCTION__, parcel);
+
+    if (parcel == NULL) {
+        ALOGE("%s: parcel is null", __FUNCTION__);
+        return BAD_VALUE;
+    }
+
+    status_t res;
+
+    res = mMetadata.writeToParcel(parcel);
+    if (res != OK) {
+        ALOGE("%s: Failed to write metadata to parcel", __FUNCTION__);
+        return res;
+    }
+    ALOGV("%s: Wrote metadata to parcel", __FUNCTION__);
+
+    res = mResultExtras.writeToParcel(parcel);
+    if (res != OK) {
+        ALOGE("%s: Failed to write result extras to parcel", __FUNCTION__);
+        return res;
+    }
+    ALOGV("%s: Wrote result extras to parcel", __FUNCTION__);
+
+    return OK;
+}
+
+}
diff --git a/camera/ICameraService.cpp b/camera/ICameraService.cpp
index 5fc89fb..5485205 100644
--- a/camera/ICameraService.cpp
+++ b/camera/ICameraService.cpp
@@ -17,6 +17,8 @@
 
 #define LOG_TAG "BpCameraService"
 #include <utils/Log.h>
+#include <utils/Errors.h>
+#include <utils/String16.h>
 
 #include <stdint.h>
 #include <sys/types.h>
@@ -34,6 +36,7 @@
 #include <camera/camera2/ICameraDeviceUser.h>
 #include <camera/camera2/ICameraDeviceCallbacks.h>
 #include <camera/CameraMetadata.h>
+#include <camera/VendorTagDescriptor.h>
 
 namespace android {
 
@@ -143,6 +146,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,
@@ -165,6 +186,29 @@
         return status;
     }
 
+    // connect to camera service (android.hardware.Camera)
+    virtual status_t connectLegacy(const sp<ICameraClient>& cameraClient, int cameraId,
+                             int halVersion,
+                             const String16 &clientPackageName, int clientUid,
+                             /*out*/sp<ICamera>& device)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(ICameraService::getInterfaceDescriptor());
+        data.writeStrongBinder(cameraClient->asBinder());
+        data.writeInt32(cameraId);
+        data.writeInt32(halVersion);
+        data.writeString16(clientPackageName);
+        data.writeInt32(clientUid);
+        remote()->transact(BnCameraService::CONNECT_LEGACY, data, &reply);
+
+        if (readExceptionCode(reply)) return -EPROTO;
+        status_t status = reply.readInt32();
+        if (reply.readInt32() != 0) {
+            device = interface_cast<ICamera>(reply.readStrongBinder());
+        }
+        return status;
+    }
+
     // connect to camera service (pro client)
     virtual status_t connectPro(const sp<IProCameraCallbacks>& cameraCb, int cameraId,
                                 const String16 &clientPackageName, int clientUid,
@@ -233,6 +277,41 @@
         if (readExceptionCode(reply)) return -EPROTO;
         return reply.readInt32();
     }
+
+    virtual status_t getLegacyParameters(int cameraId, String16* parameters) {
+        if (parameters == NULL) {
+            ALOGE("%s: parameters must not be null", __FUNCTION__);
+            return BAD_VALUE;
+        }
+
+        Parcel data, reply;
+
+        data.writeInt32(cameraId);
+        remote()->transact(BnCameraService::GET_LEGACY_PARAMETERS, data, &reply);
+        if (readExceptionCode(reply)) return -EPROTO;
+
+        status_t res = data.readInt32();
+        int32_t length = data.readInt32(); // -1 means null
+        if (length > 0) {
+            *parameters = data.readString16();
+        } else {
+            *parameters = String16();
+        }
+
+        return res;
+    }
+
+    virtual status_t supportsCameraApi(int cameraId, int apiVersion) {
+        Parcel data, reply;
+
+        data.writeInt32(cameraId);
+        data.writeInt32(apiVersion);
+        remote()->transact(BnCameraService::SUPPORTS_CAMERA_API, data, &reply);
+        if (readExceptionCode(reply)) return -EPROTO;
+
+        status_t res = data.readInt32();
+        return res;
+    }
 };
 
 IMPLEMENT_META_INTERFACE(CameraService, "android.hardware.ICameraService");
@@ -275,6 +354,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 +379,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 +399,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 +419,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) {
@@ -351,6 +446,50 @@
             reply->writeInt32(removeListener(listener));
             return NO_ERROR;
         } break;
+        case GET_LEGACY_PARAMETERS: {
+            CHECK_INTERFACE(ICameraService, data, reply);
+            int cameraId = data.readInt32();
+            String16 parameters;
+
+            reply->writeNoException();
+            // return value
+            reply->writeInt32(getLegacyParameters(cameraId, &parameters));
+            // out parameters
+            reply->writeInt32(1); // parameters is always available
+            reply->writeString16(parameters);
+            return NO_ERROR;
+        } break;
+        case SUPPORTS_CAMERA_API: {
+            CHECK_INTERFACE(ICameraService, data, reply);
+            int cameraId = data.readInt32();
+            int apiVersion = data.readInt32();
+
+            reply->writeNoException();
+            // return value
+            reply->writeInt32(supportsCameraApi(cameraId, apiVersion));
+            return NO_ERROR;
+        } break;
+        case CONNECT_LEGACY: {
+            CHECK_INTERFACE(ICameraService, data, reply);
+            sp<ICameraClient> cameraClient =
+                    interface_cast<ICameraClient>(data.readStrongBinder());
+            int32_t cameraId = data.readInt32();
+            int32_t halVersion = data.readInt32();
+            const String16 clientName = data.readString16();
+            int32_t clientUid = data.readInt32();
+            sp<ICamera> camera;
+            status_t status = connectLegacy(cameraClient, cameraId, halVersion,
+                    clientName, clientUid, /*out*/camera);
+            reply->writeNoException();
+            reply->writeInt32(status);
+            if (camera != NULL) {
+                reply->writeInt32(1);
+                reply->writeStrongBinder(camera->asBinder());
+            } else {
+                reply->writeInt32(0);
+            }
+            return NO_ERROR;
+        } break;
         default:
             return BBinder::onTransact(code, data, reply, flags);
     }
diff --git a/camera/ProCamera.cpp b/camera/ProCamera.cpp
index ba5a48c..48f8e8e 100644
--- a/camera/ProCamera.cpp
+++ b/camera/ProCamera.cpp
@@ -249,11 +249,14 @@
     sp <IProCameraUser> c = mCamera;
     if (c == 0) return NO_INIT;
 
-    sp<BufferQueue> bq = new BufferQueue();
-    sp<CpuConsumer> cc = new CpuConsumer(bq, heapCount/*, synchronousMode*/);
+    sp<IGraphicBufferProducer> producer;
+    sp<IGraphicBufferConsumer> consumer;
+    BufferQueue::createBufferQueue(&producer, &consumer);
+    sp<CpuConsumer> cc = new CpuConsumer(consumer, heapCount
+            /*, synchronousMode*/);
     cc->setName(String8("ProCamera::mCpuConsumer"));
 
-    sp<Surface> stc = new Surface(bq);
+    sp<Surface> stc = new Surface(producer);
 
     status_t s = createStream(width, height, format,
                               stc->getIGraphicBufferProducer(),
diff --git a/camera/VendorTagDescriptor.cpp b/camera/VendorTagDescriptor.cpp
new file mode 100644
index 0000000..0dda6b6
--- /dev/null
+++ b/camera/VendorTagDescriptor.cpp
@@ -0,0 +1,460 @@
+/*
+ * 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 "VendorTagDescriptor"
+
+#include <binder/Parcel.h>
+#include <utils/Errors.h>
+#include <utils/Log.h>
+#include <utils/Mutex.h>
+#include <utils/Vector.h>
+#include <utils/SortedVector.h>
+#include <system/camera_metadata.h>
+#include <camera_metadata_hidden.h>
+
+#include "camera/VendorTagDescriptor.h"
+
+#include <stdio.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() {
+    size_t len = mReverseMapping.size();
+    for (size_t i = 0; i < len; ++i)  {
+        delete mReverseMapping[i];
+    }
+}
+
+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;
+
+    SortedVector<String8> sections;
+    KeyedVector<uint32_t, String8> tagToSectionMap;
+
+    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;
+        }
+
+        String8 sectionString(sectionName);
+
+        sections.add(sectionString);
+        tagToSectionMap.add(tag, sectionString);
+
+        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);
+    }
+
+    desc->mSections = sections;
+
+    for (size_t i = 0; i < static_cast<size_t>(tagCount); ++i) {
+        uint32_t tag = tagArray[i];
+        String8 sectionString = tagToSectionMap.valueFor(tag);
+
+        // Set up tag to section index map
+        ssize_t index = sections.indexOf(sectionString);
+        LOG_ALWAYS_FATAL_IF(index < 0, "index %zd must be non-negative", index);
+        desc->mTagToSectionMap.add(tag, static_cast<uint32_t>(index));
+
+        // Set up reverse mapping
+        ssize_t reverseIndex = -1;
+        if ((reverseIndex = desc->mReverseMapping.indexOfKey(sectionString)) < 0) {
+            KeyedVector<String8, uint32_t>* nameMapper = new KeyedVector<String8, uint32_t>();
+            reverseIndex = desc->mReverseMapping.add(sectionString, nameMapper);
+        }
+        desc->mReverseMapping[reverseIndex]->add(desc->mTagToNameMap.valueFor(tag), tag);
+    }
+
+    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, sectionIndex;
+    uint32_t maxSectionIndex = 0;
+    int32_t tagType;
+    Vector<uint32_t> allTags;
+    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;
+        }
+
+        if ((res = parcel->readInt32(reinterpret_cast<int32_t*>(&sectionIndex))) != OK) {
+            ALOGE("%s: could not read section index for tag %d.", __FUNCTION__, tag);
+            break;
+        }
+
+        maxSectionIndex = (maxSectionIndex >= sectionIndex) ? maxSectionIndex : sectionIndex;
+
+        allTags.add(tag);
+        desc->mTagToNameMap.add(tag, tagName);
+        desc->mTagToSectionMap.add(tag, sectionIndex);
+        desc->mTagToTypeMap.add(tag, tagType);
+    }
+
+    if (res != OK) {
+        return res;
+    }
+
+    size_t sectionCount;
+    if (tagCount > 0) {
+        if ((res = parcel->readInt32(reinterpret_cast<int32_t*>(&sectionCount))) != OK) {
+            ALOGE("%s: could not read section count for.", __FUNCTION__);
+            return res;
+        }
+        if (sectionCount < (maxSectionIndex + 1)) {
+            ALOGE("%s: Incorrect number of sections defined, received %zu, needs %d.",
+                    __FUNCTION__, sectionCount, (maxSectionIndex + 1));
+            return BAD_VALUE;
+        }
+        LOG_ALWAYS_FATAL_IF(desc->mSections.setCapacity(sectionCount) <= 0,
+                "Vector capacity must be positive");
+        for (size_t i = 0; i < sectionCount; ++i) {
+            String8 sectionName = parcel->readString8();
+            if (sectionName.isEmpty()) {
+                ALOGE("%s: parcel section name was NULL for section %zu.",
+                      __FUNCTION__, i);
+                return NOT_ENOUGH_DATA;
+            }
+            desc->mSections.add(sectionName);
+        }
+    }
+
+    LOG_ALWAYS_FATAL_IF(static_cast<size_t>(tagCount) != allTags.size(),
+                        "tagCount must be the same as allTags size");
+    // Set up reverse mapping
+    for (size_t i = 0; i < static_cast<size_t>(tagCount); ++i) {
+        uint32_t tag = allTags[i];
+        String8 sectionString = desc->mSections[desc->mTagToSectionMap.valueFor(tag)];
+
+        ssize_t reverseIndex = -1;
+        if ((reverseIndex = desc->mReverseMapping.indexOfKey(sectionString)) < 0) {
+            KeyedVector<String8, uint32_t>* nameMapper = new KeyedVector<String8, uint32_t>();
+            reverseIndex = desc->mReverseMapping.add(sectionString, nameMapper);
+        }
+        desc->mReverseMapping[reverseIndex]->add(desc->mTagToNameMap.valueFor(tag), tag);
+    }
+
+    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 mSections[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, sectionIndex;
+    int32_t tagType;
+    for (size_t i = 0; i < size; ++i) {
+        tag = mTagToNameMap.keyAt(i);
+        String8 tagName = mTagToNameMap[i];
+        sectionIndex = 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->writeInt32(sectionIndex)) != OK) break;
+    }
+
+    size_t numSections = mSections.size();
+    if (numSections > 0) {
+        if ((res = parcel->writeInt32(numSections)) != OK) return res;
+        for (size_t i = 0; i < numSections; ++i) {
+            if ((res = parcel->writeString8(mSections[i])) != OK) return res;
+        }
+    }
+
+    return res;
+}
+
+SortedVector<String8> VendorTagDescriptor::getAllSectionNames() const {
+    return mSections;
+}
+
+status_t VendorTagDescriptor::lookupTag(String8 name, String8 section, /*out*/uint32_t* tag) const {
+    ssize_t index = mReverseMapping.indexOfKey(section);
+    if (index < 0) {
+        ALOGE("%s: Section '%s' does not exist.", __FUNCTION__, section.string());
+        return BAD_VALUE;
+    }
+
+    ssize_t nameIndex = mReverseMapping[index]->indexOfKey(name);
+    if (nameIndex < 0) {
+        ALOGE("%s: Tag name '%s' does not exist.", __FUNCTION__, name.string());
+        return BAD_VALUE;
+    }
+
+    if (tag != NULL) {
+        *tag = mReverseMapping[index]->valueAt(nameIndex);
+    }
+    return OK;
+}
+
+void VendorTagDescriptor::dump(int fd, int verbosity, int indentation) const {
+
+    size_t size = mTagToNameMap.size();
+    if (size == 0) {
+        dprintf(fd, "%*sDumping configured vendor tag descriptors: None set\n",
+                indentation, "");
+        return;
+    }
+
+    dprintf(fd, "%*sDumping configured vendor tag descriptors: %zu entries\n",
+            indentation, "", size);
+    for (size_t i = 0; i < size; ++i) {
+        uint32_t tag =  mTagToNameMap.keyAt(i);
+
+        if (verbosity < 1) {
+            dprintf(fd, "%*s0x%x\n", indentation + 2, "", tag);
+            continue;
+        }
+        String8 name = mTagToNameMap.valueAt(i);
+        uint32_t sectionId = mTagToSectionMap.valueFor(tag);
+        String8 sectionName = mSections[sectionId];
+        int type = mTagToTypeMap.valueFor(tag);
+        const char* typeName = (type >= 0 && type < NUM_TYPES) ?
+                camera_metadata_type_names[type] : "UNKNOWN";
+        dprintf(fd, "%*s0x%x (%s) with type %d (%s) defined in section %s\n", indentation + 2,
+            "", tag, name.string(), type, typeName, sectionName.string());
+    }
+
+}
+
+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/camera2/ICameraDeviceCallbacks.cpp b/camera/camera2/ICameraDeviceCallbacks.cpp
index 613358a..4cc7b5d 100644
--- a/camera/camera2/ICameraDeviceCallbacks.cpp
+++ b/camera/camera2/ICameraDeviceCallbacks.cpp
@@ -28,6 +28,7 @@
 
 #include <camera/camera2/ICameraDeviceCallbacks.h>
 #include "camera/CameraMetadata.h"
+#include "camera/CaptureResult.h"
 
 namespace android {
 
@@ -46,12 +47,14 @@
     {
     }
 
-    void onDeviceError(CameraErrorCode errorCode)
+    void onDeviceError(CameraErrorCode errorCode, const CaptureResultExtras& resultExtras)
     {
         ALOGV("onDeviceError");
         Parcel data, reply;
         data.writeInterfaceToken(ICameraDeviceCallbacks::getInterfaceDescriptor());
         data.writeInt32(static_cast<int32_t>(errorCode));
+        data.writeInt32(1); // to mark presence of CaptureResultExtras object
+        resultExtras.writeToParcel(&data);
         remote()->transact(CAMERA_ERROR, data, &reply, IBinder::FLAG_ONEWAY);
         data.writeNoException();
     }
@@ -65,25 +68,28 @@
         data.writeNoException();
     }
 
-    void onCaptureStarted(int32_t requestId, int64_t timestamp)
+    void onCaptureStarted(const CaptureResultExtras& result, int64_t timestamp)
     {
         ALOGV("onCaptureStarted");
         Parcel data, reply;
         data.writeInterfaceToken(ICameraDeviceCallbacks::getInterfaceDescriptor());
-        data.writeInt32(requestId);
+        data.writeInt32(1); // to mark presence of CaptureResultExtras object
+        result.writeToParcel(&data);
         data.writeInt64(timestamp);
         remote()->transact(CAPTURE_STARTED, data, &reply, IBinder::FLAG_ONEWAY);
         data.writeNoException();
     }
 
 
-    void onResultReceived(int32_t requestId, const CameraMetadata& result) {
+    void onResultReceived(const CameraMetadata& metadata,
+            const CaptureResultExtras& resultExtras) {
         ALOGV("onResultReceived");
         Parcel data, reply;
         data.writeInterfaceToken(ICameraDeviceCallbacks::getInterfaceDescriptor());
-        data.writeInt32(requestId);
         data.writeInt32(1); // to mark presence of metadata object
-        result.writeToParcel(&data);
+        metadata.writeToParcel(&data);
+        data.writeInt32(1); // to mark presence of CaptureResult object
+        resultExtras.writeToParcel(&data);
         remote()->transact(RESULT_RECEIVED, data, &reply, IBinder::FLAG_ONEWAY);
         data.writeNoException();
     }
@@ -104,7 +110,13 @@
             CHECK_INTERFACE(ICameraDeviceCallbacks, data, reply);
             CameraErrorCode errorCode =
                     static_cast<CameraErrorCode>(data.readInt32());
-            onDeviceError(errorCode);
+            CaptureResultExtras resultExtras;
+            if (data.readInt32() != 0) {
+                resultExtras.readFromParcel(const_cast<Parcel*>(&data));
+            } else {
+                ALOGE("No CaptureResultExtras object is present!");
+            }
+            onDeviceError(errorCode, resultExtras);
             data.readExceptionCode();
             return NO_ERROR;
         } break;
@@ -118,23 +130,33 @@
         case CAPTURE_STARTED: {
             ALOGV("onCaptureStarted");
             CHECK_INTERFACE(ICameraDeviceCallbacks, data, reply);
-            int32_t requestId = data.readInt32();
+            CaptureResultExtras result;
+            if (data.readInt32() != 0) {
+                result.readFromParcel(const_cast<Parcel*>(&data));
+            } else {
+                ALOGE("No CaptureResultExtras object is present in result!");
+            }
             int64_t timestamp = data.readInt64();
-            onCaptureStarted(requestId, timestamp);
+            onCaptureStarted(result, timestamp);
             data.readExceptionCode();
             return NO_ERROR;
         } break;
         case RESULT_RECEIVED: {
             ALOGV("onResultReceived");
             CHECK_INTERFACE(ICameraDeviceCallbacks, data, reply);
-            int32_t requestId = data.readInt32();
-            CameraMetadata result;
+            CameraMetadata metadata;
             if (data.readInt32() != 0) {
-                result.readFromParcel(const_cast<Parcel*>(&data));
+                metadata.readFromParcel(const_cast<Parcel*>(&data));
             } else {
                 ALOGW("No metadata object is present in result");
             }
-            onResultReceived(requestId, result);
+            CaptureResultExtras resultExtras;
+            if (data.readInt32() != 0) {
+                resultExtras.readFromParcel(const_cast<Parcel*>(&data));
+            } else {
+                ALOGW("No capture result extras object is present in result");
+            }
+            onResultReceived(metadata, resultExtras);
             data.readExceptionCode();
             return NO_ERROR;
         } break;
diff --git a/camera/camera2/ICameraDeviceUser.cpp b/camera/camera2/ICameraDeviceUser.cpp
index 1e5822f..ff4a0c2 100644
--- a/camera/camera2/ICameraDeviceUser.cpp
+++ b/camera/camera2/ICameraDeviceUser.cpp
@@ -35,7 +35,10 @@
 enum {
     DISCONNECT = IBinder::FIRST_CALL_TRANSACTION,
     SUBMIT_REQUEST,
+    SUBMIT_REQUEST_LIST,
     CANCEL_REQUEST,
+    BEGIN_CONFIGURE,
+    END_CONFIGURE,
     DELETE_STREAM,
     CREATE_STREAM,
     CREATE_DEFAULT_REQUEST,
@@ -75,7 +78,8 @@
         reply.readExceptionCode();
     }
 
-    virtual int submitRequest(sp<CaptureRequest> request, bool streaming)
+    virtual status_t submitRequest(sp<CaptureRequest> request, bool repeating,
+                              int64_t *lastFrameNumber)
     {
         Parcel data, reply;
         data.writeInterfaceToken(ICameraDeviceUser::getInterfaceDescriptor());
@@ -89,15 +93,67 @@
         }
 
         // arg1 = streaming (bool)
-        data.writeInt32(streaming);
+        data.writeInt32(repeating);
 
         remote()->transact(SUBMIT_REQUEST, data, &reply);
 
         reply.readExceptionCode();
-        return reply.readInt32();
+        status_t res = reply.readInt32();
+
+        status_t resFrameNumber = BAD_VALUE;
+        if (reply.readInt32() != 0) {
+            if (lastFrameNumber != NULL) {
+                resFrameNumber = reply.readInt64(lastFrameNumber);
+            }
+        }
+
+	if ((res != NO_ERROR) || (resFrameNumber != NO_ERROR)) {
+            res = FAILED_TRANSACTION;
+        }
+        return res;
     }
 
-    virtual status_t cancelRequest(int requestId)
+    virtual status_t submitRequestList(List<sp<CaptureRequest> > requestList, bool repeating,
+                                  int64_t *lastFrameNumber)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(ICameraDeviceUser::getInterfaceDescriptor());
+
+        data.writeInt32(requestList.size());
+
+        for (List<sp<CaptureRequest> >::iterator it = requestList.begin();
+                it != requestList.end(); ++it) {
+            sp<CaptureRequest> request = *it;
+            if (request != 0) {
+                data.writeInt32(1);
+                if (request->writeToParcel(&data) != OK) {
+                    return BAD_VALUE;
+                }
+            } else {
+                data.writeInt32(0);
+            }
+        }
+
+        data.writeInt32(repeating);
+
+        remote()->transact(SUBMIT_REQUEST_LIST, data, &reply);
+
+        reply.readExceptionCode();
+        status_t res = reply.readInt32();
+
+        status_t resFrameNumber = BAD_VALUE;
+        if (reply.readInt32() != 0) {
+            if (lastFrameNumber != NULL) {
+                resFrameNumber = reply.readInt64(lastFrameNumber);
+            }
+        }
+        if ((res != NO_ERROR) || (resFrameNumber != NO_ERROR)) {
+            res = FAILED_TRANSACTION;
+        }
+        return res;
+    }
+
+    virtual status_t cancelRequest(int requestId, int64_t *lastFrameNumber)
     {
         Parcel data, reply;
         data.writeInterfaceToken(ICameraDeviceUser::getInterfaceDescriptor());
@@ -106,6 +162,37 @@
         remote()->transact(CANCEL_REQUEST, data, &reply);
 
         reply.readExceptionCode();
+        status_t res = reply.readInt32();
+
+        status_t resFrameNumber = BAD_VALUE;
+        if (reply.readInt32() != 0) {
+            if (lastFrameNumber != NULL) {
+                res = reply.readInt64(lastFrameNumber);
+            }
+        }
+        if ((res != NO_ERROR) || (resFrameNumber != NO_ERROR)) {
+            res = FAILED_TRANSACTION;
+        }
+        return res;
+    }
+
+    virtual status_t beginConfigure()
+    {
+        ALOGV("beginConfigure");
+        Parcel data, reply;
+        data.writeInterfaceToken(ICameraDeviceUser::getInterfaceDescriptor());
+        remote()->transact(BEGIN_CONFIGURE, data, &reply);
+        reply.readExceptionCode();
+        return reply.readInt32();
+    }
+
+    virtual status_t endConfigure()
+    {
+        ALOGV("endConfigure");
+        Parcel data, reply;
+        data.writeInterfaceToken(ICameraDeviceUser::getInterfaceDescriptor());
+        remote()->transact(END_CONFIGURE, data, &reply);
+        reply.readExceptionCode();
         return reply.readInt32();
     }
 
@@ -197,14 +284,25 @@
         return reply.readInt32();
     }
 
-    virtual status_t flush()
+    virtual status_t flush(int64_t *lastFrameNumber)
     {
         ALOGV("flush");
         Parcel data, reply;
         data.writeInterfaceToken(ICameraDeviceUser::getInterfaceDescriptor());
         remote()->transact(FLUSH, data, &reply);
         reply.readExceptionCode();
-        return reply.readInt32();
+        status_t res = reply.readInt32();
+
+        status_t resFrameNumber = BAD_VALUE;
+        if (reply.readInt32() != 0) {
+            if (lastFrameNumber != NULL) {
+                res = reply.readInt64(lastFrameNumber);
+            }
+        }
+        if ((res != NO_ERROR) || (resFrameNumber != NO_ERROR)) {
+            res = FAILED_TRANSACTION;
+        }
+        return res;
     }
 
 private:
@@ -239,11 +337,43 @@
             }
 
             // arg1 = streaming (bool)
-            bool streaming = data.readInt32();
+            bool repeating = data.readInt32();
 
             // return code: requestId (int32)
             reply->writeNoException();
-            reply->writeInt32(submitRequest(request, streaming));
+            int64_t lastFrameNumber = -1;
+            reply->writeInt32(submitRequest(request, repeating, &lastFrameNumber));
+            reply->writeInt32(1);
+            reply->writeInt64(lastFrameNumber);
+
+            return NO_ERROR;
+        } break;
+        case SUBMIT_REQUEST_LIST: {
+            CHECK_INTERFACE(ICameraDeviceUser, data, reply);
+
+            List<sp<CaptureRequest> > requestList;
+            int requestListSize = data.readInt32();
+            for (int i = 0; i < requestListSize; i++) {
+                if (data.readInt32() != 0) {
+                    sp<CaptureRequest> request = new CaptureRequest();
+                    if (request->readFromParcel(const_cast<Parcel*>(&data)) != OK) {
+                        return BAD_VALUE;
+                    }
+                    requestList.push_back(request);
+                } else {
+                    sp<CaptureRequest> request = 0;
+                    requestList.push_back(request);
+                    ALOGE("A request is missing. Sending in null request.");
+                }
+            }
+
+            bool repeating = data.readInt32();
+
+            reply->writeNoException();
+            int64_t lastFrameNumber = -1;
+            reply->writeInt32(submitRequestList(requestList, repeating, &lastFrameNumber));
+            reply->writeInt32(1);
+            reply->writeInt64(lastFrameNumber);
 
             return NO_ERROR;
         } break;
@@ -251,7 +381,10 @@
             CHECK_INTERFACE(ICameraDeviceUser, data, reply);
             int requestId = data.readInt32();
             reply->writeNoException();
-            reply->writeInt32(cancelRequest(requestId));
+            int64_t lastFrameNumber = -1;
+            reply->writeInt32(cancelRequest(requestId, &lastFrameNumber));
+            reply->writeInt32(1);
+            reply->writeInt64(lastFrameNumber);
             return NO_ERROR;
         } break;
         case DELETE_STREAM: {
@@ -339,9 +472,24 @@
         case FLUSH: {
             CHECK_INTERFACE(ICameraDeviceUser, data, reply);
             reply->writeNoException();
-            reply->writeInt32(flush());
+            int64_t lastFrameNumber = -1;
+            reply->writeInt32(flush(&lastFrameNumber));
+            reply->writeInt32(1);
+            reply->writeInt64(lastFrameNumber);
             return NO_ERROR;
         }
+        case BEGIN_CONFIGURE: {
+            CHECK_INTERFACE(ICameraDeviceUser, data, reply);
+            reply->writeNoException();
+            reply->writeInt32(beginConfigure());
+            return NO_ERROR;
+        } break;
+        case END_CONFIGURE: {
+            CHECK_INTERFACE(ICameraDeviceUser, data, reply);
+            reply->writeNoException();
+            reply->writeInt32(endConfigure());
+            return NO_ERROR;
+        } break;
         default:
             return BBinder::onTransact(code, data, reply, flags);
     }
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/FrameOutput.cpp b/cmds/screenrecord/FrameOutput.cpp
index 6c37501..03e0062 100644
--- a/cmds/screenrecord/FrameOutput.cpp
+++ b/cmds/screenrecord/FrameOutput.cpp
@@ -67,9 +67,11 @@
         return UNKNOWN_ERROR;
     }
 
-    mBufferQueue = new BufferQueue(/*new GraphicBufferAlloc()*/);
-    mGlConsumer = new GLConsumer(mBufferQueue, mExtTextureName,
-                GL_TEXTURE_EXTERNAL_OES);
+    sp<IGraphicBufferProducer> producer;
+    sp<IGraphicBufferConsumer> consumer;
+    BufferQueue::createBufferQueue(&producer, &consumer);
+    mGlConsumer = new GLConsumer(consumer, mExtTextureName,
+                GL_TEXTURE_EXTERNAL_OES, true, false);
     mGlConsumer->setName(String8("virtual display"));
     mGlConsumer->setDefaultBufferSize(width, height);
     mGlConsumer->setDefaultMaxBufferCount(5);
@@ -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 4ac3e8a..c49ec3b 100644
--- a/cmds/screenrecord/FrameOutput.h
+++ b/cmds/screenrecord/FrameOutput.h
@@ -34,9 +34,6 @@
         mExtTextureName(0),
         mPixelBuf(NULL)
         {}
-    virtual ~FrameOutput() {
-        delete[] mPixelBuf;
-    }
 
     // Create an "input surface", similar in purpose to a MediaCodec input
     // surface, that the virtual display can send buffers to.  Also configures
@@ -59,6 +56,11 @@
     FrameOutput(const FrameOutput&);
     FrameOutput& operator=(const FrameOutput&);
 
+    // Destruction via RefBase.
+    virtual ~FrameOutput() {
+        delete[] mPixelBuf;
+    }
+
     // (overrides GLConsumer::FrameAvailableListener method)
     virtual void onFrameAvailable();
 
@@ -75,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 96e25b8..7fef53d 100644
--- a/cmds/screenrecord/Overlay.cpp
+++ b/cmds/screenrecord/Overlay.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+#include <assert.h>
+#include <inttypes.h>
+#include <stdlib.h>
+
 #define LOG_TAG "ScreenRecord"
 //#define LOG_NDEBUG 0
 #include <utils/Log.h>
@@ -27,9 +31,6 @@
 #include <GLES2/gl2.h>
 #include <GLES2/gl2ext.h>
 
-#include <stdlib.h>
-#include <assert.h>
-
 #include "screenrecord.h"
 #include "Overlay.h"
 #include "TextRenderer.h"
@@ -47,7 +48,7 @@
         "ro.revision",
         "dalvik.vm.heapgrowthlimit",
         "dalvik.vm.heapsize",
-        "persist.sys.dalvik.vm.lib",
+        "persist.sys.dalvik.vm.lib.2",
         //"ro.product.cpu.abi",
         //"ro.bootloader",
         //"this-never-appears!",
@@ -84,7 +85,7 @@
     assert(mState == RUNNING);
 
     ALOGV("Overlay::start successful");
-    *pBufferProducer = mBufferQueue;
+    *pBufferProducer = mProducer;
     return NO_ERROR;
 }
 
@@ -169,9 +170,10 @@
         return UNKNOWN_ERROR;
     }
 
-    mBufferQueue = new BufferQueue(/*new GraphicBufferAlloc()*/);
-    mGlConsumer = new GLConsumer(mBufferQueue, mExtTextureName,
-                GL_TEXTURE_EXTERNAL_OES);
+    sp<IGraphicBufferConsumer> consumer;
+    BufferQueue::createBufferQueue(&mProducer, &consumer);
+    mGlConsumer = new GLConsumer(consumer, mExtTextureName,
+                GL_TEXTURE_EXTERNAL_OES, true, false);
     mGlConsumer->setName(String8("virtual display"));
     mGlConsumer->setDefaultBufferSize(width, height);
     mGlConsumer->setDefaultMaxBufferCount(5);
@@ -187,7 +189,7 @@
     ALOGV("Overlay::release_l");
     mOutputSurface.clear();
     mGlConsumer.clear();
-    mBufferQueue.clear();
+    mProducer.clear();
 
     mTexProgram.release();
     mExtTexProgram.release();
@@ -234,7 +236,7 @@
 
     char textBuf[64];
     getTimeString_l(monotonicNsec, textBuf, sizeof(textBuf));
-    String8 timeStr(String8::format("%s f=%lld (%zd)",
+    String8 timeStr(String8::format("%s f=%" PRId64 " (%zd)",
             textBuf, frameNumber, mTotalDroppedFrames));
     mTextRenderer.drawString(mTexProgram, Program::kIdentity, 0, 0, timeStr);
 
diff --git a/cmds/screenrecord/Overlay.h b/cmds/screenrecord/Overlay.h
index b8473b4..b1b5c29 100644
--- a/cmds/screenrecord/Overlay.h
+++ b/cmds/screenrecord/Overlay.h
@@ -47,7 +47,6 @@
         mLastFrameNumber(-1),
         mTotalDroppedFrames(0)
         {}
-    virtual ~Overlay() { assert(mState == UNINITIALIZED || mState == STOPPED); }
 
     // Creates a thread that performs the overlay.  Pass in the surface that
     // output will be sent to.
@@ -71,6 +70,9 @@
     Overlay(const Overlay&);
     Overlay& operator=(const Overlay&);
 
+    // Destruction via RefBase.
+    virtual ~Overlay() { assert(mState == UNINITIALIZED || mState == STOPPED); }
+
     // Draw the initial info screen.
     static void doDrawInfoPage(const EglWindow& window,
             const Program& texRender, TextRenderer& textRenderer);
@@ -120,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/screenrecord/TextRenderer.cpp b/cmds/screenrecord/TextRenderer.cpp
index 784055c..6a9176b 100644
--- a/cmds/screenrecord/TextRenderer.cpp
+++ b/cmds/screenrecord/TextRenderer.cpp
@@ -353,6 +353,6 @@
         }
     }
 
-    ALOGV("goodPos=%d for str='%s'", goodPos, str);
+    ALOGV("goodPos=%zu for str='%s'", goodPos, str);
     return const_cast<char*>(str + goodPos);
 }
diff --git a/cmds/screenrecord/screenrecord.cpp b/cmds/screenrecord/screenrecord.cpp
index 02ed53a..02df1d2 100644
--- a/cmds/screenrecord/screenrecord.cpp
+++ b/cmds/screenrecord/screenrecord.cpp
@@ -14,6 +14,19 @@
  * limitations under the License.
  */
 
+#include <assert.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <getopt.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/wait.h>
+#include <termios.h>
+#include <unistd.h>
+
 #define LOG_TAG "ScreenRecord"
 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
 //#define LOG_NDEBUG 0
@@ -36,18 +49,6 @@
 #include <media/stagefright/MediaMuxer.h>
 #include <media/ICrypto.h>
 
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <stdio.h>
-#include <ctype.h>
-#include <fcntl.h>
-#include <signal.h>
-#include <getopt.h>
-#include <sys/wait.h>
-#include <termios.h>
-#include <assert.h>
-
 #include "screenrecord.h"
 #include "Overlay.h"
 #include "FrameOutput.h"
@@ -354,7 +355,7 @@
         case NO_ERROR:
             // got a buffer
             if ((flags & MediaCodec::BUFFER_FLAG_CODECCONFIG) != 0) {
-                ALOGV("Got codec config buffer (%u bytes)", size);
+                ALOGV("Got codec config buffer (%zu bytes)", size);
                 if (muxer != NULL) {
                     // ignore this -- we passed the CSD into MediaMuxer when
                     // we got the format change notification
@@ -362,7 +363,7 @@
                 }
             }
             if (size != 0) {
-                ALOGV("Got data in buffer %d, size=%d, pts=%lld",
+                ALOGV("Got data in buffer %zu, size=%zu, pts=%" PRId64,
                         bufIndex, size, ptsUsec);
 
                 { // scope
@@ -473,7 +474,7 @@
 
     ALOGV("Encoder stopping (req=%d)", gStopRequested);
     if (gVerbose) {
-        printf("Encoder stopping; recorded %u frames in %lld seconds\n",
+        printf("Encoder stopping; recorded %u frames in %" PRId64 " seconds\n",
                 debugNumFrames, nanoseconds_to_seconds(
                         systemTime(CLOCK_MONOTONIC) - startWhenNsec));
     }
diff --git a/cmds/stagefright/SimplePlayer.cpp b/cmds/stagefright/SimplePlayer.cpp
index 5d2d721..1b2f792 100644
--- a/cmds/stagefright/SimplePlayer.cpp
+++ b/cmds/stagefright/SimplePlayer.cpp
@@ -23,6 +23,7 @@
 #include <gui/Surface.h>
 #include <media/AudioTrack.h>
 #include <media/ICrypto.h>
+#include <media/IMediaHTTPService.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
@@ -275,7 +276,8 @@
 
     mExtractor = new NuMediaExtractor;
 
-    status_t err = mExtractor->setDataSource(mPath.c_str());
+    status_t err = mExtractor->setDataSource(
+            NULL /* httpService */, mPath.c_str());
 
     if (err != OK) {
         mExtractor.clear();
diff --git a/cmds/stagefright/SineSource.cpp b/cmds/stagefright/SineSource.cpp
index 14b4306..587077a 100644
--- a/cmds/stagefright/SineSource.cpp
+++ b/cmds/stagefright/SineSource.cpp
@@ -24,7 +24,7 @@
     }
 }
 
-status_t SineSource::start(MetaData *params) {
+status_t SineSource::start(MetaData * /* params */) {
     CHECK(!mStarted);
 
     mGroup = new MediaBufferGroup;
@@ -58,7 +58,7 @@
 }
 
 status_t SineSource::read(
-        MediaBuffer **out, const ReadOptions *options) {
+        MediaBuffer **out, const ReadOptions * /* options */) {
     *out = NULL;
 
     MediaBuffer *buffer;
diff --git a/cmds/stagefright/audioloop.cpp b/cmds/stagefright/audioloop.cpp
index ed7d6cb..96073f1 100644
--- a/cmds/stagefright/audioloop.cpp
+++ b/cmds/stagefright/audioloop.cpp
@@ -1,4 +1,18 @@
-#include "SineSource.h"
+/*
+ * 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.
+ */
 
 #include <binder/ProcessState.h>
 #include <media/mediarecorder.h>
@@ -10,41 +24,79 @@
 #include <media/stagefright/MetaData.h>
 #include <media/stagefright/OMXClient.h>
 #include <media/stagefright/OMXCodec.h>
-
-#include <system/audio.h>
+#include "SineSource.h"
 
 using namespace android;
 
-int main() {
-    // We only have an AMR-WB encoder on sholes...
-    static bool outputWBAMR = false;
-    static const int32_t kSampleRate = outputWBAMR ? 16000 : 8000;
-    static const int32_t kNumChannels = 1;
+static void usage(const char* name)
+{
+    fprintf(stderr, "Usage: %s [-d duration] [-m] [-w] [<output-file>]\n", name);
+    fprintf(stderr, "Encodes either a sine wave or microphone input to AMR format\n");
+    fprintf(stderr, "    -d    duration in seconds, default 5 seconds\n");
+    fprintf(stderr, "    -m    use microphone for input, default sine source\n");
+    fprintf(stderr, "    -w    use AMR wideband (default narrowband)\n");
+    fprintf(stderr, "    <output-file> output file for AMR encoding,"
+            " if unspecified, decode to speaker.\n");
+}
+
+int main(int argc, char* argv[])
+{
+    static const int channels = 1; // not permitted to be stereo now
+    unsigned duration = 5;
+    bool useMic = false;
+    bool outputWBAMR = false;
+    bool playToSpeaker = true;
+    const char* fileOut = NULL;
+    int ch;
+    while ((ch = getopt(argc, argv, "d:mw")) != -1) {
+        switch (ch) {
+        case 'd':
+            duration = atoi(optarg);
+            break;
+        case 'm':
+            useMic = true;
+            break;
+        case 'w':
+            outputWBAMR = true;
+            break;
+        default:
+            usage(argv[0]);
+            return -1;
+        }
+    }
+    argc -= optind;
+    argv += optind;
+    if (argc == 1) {
+        fileOut = argv[0];
+    }
+    const int32_t kSampleRate = outputWBAMR ? 16000 : 8000;
+    const int32_t kBitRate = outputWBAMR ? 16000 : 8000;
 
     android::ProcessState::self()->startThreadPool();
-
     OMXClient client;
     CHECK_EQ(client.connect(), (status_t)OK);
+    sp<MediaSource> source;
 
-#if 0
-    sp<MediaSource> source = new SineSource(kSampleRate, kNumChannels);
-#else
-    sp<MediaSource> source = new AudioSource(
-            AUDIO_SOURCE_DEFAULT,
-            kSampleRate,
-            audio_channel_in_mask_from_count(kNumChannels));
-#endif
+    if (useMic) {
+        // talk into the appropriate microphone for the duration
+        source = new AudioSource(
+                AUDIO_SOURCE_MIC,
+                kSampleRate,
+                channels);
+    } else {
+        // use a sine source at 500 hz.
+        source = new SineSource(kSampleRate, channels);
+    }
 
     sp<MetaData> meta = new MetaData;
-
     meta->setCString(
             kKeyMIMEType,
             outputWBAMR ? MEDIA_MIMETYPE_AUDIO_AMR_WB
-                        : MEDIA_MIMETYPE_AUDIO_AMR_NB);
+                    : MEDIA_MIMETYPE_AUDIO_AMR_NB);
 
-    meta->setInt32(kKeyChannelCount, kNumChannels);
+    meta->setInt32(kKeyChannelCount, channels);
     meta->setInt32(kKeySampleRate, kSampleRate);
-
+    meta->setInt32(kKeyBitRate, kBitRate);
     int32_t maxInputSize;
     if (source->getFormat()->findInt32(kKeyMaxInputSize, &maxInputSize)) {
         meta->setInt32(kKeyMaxInputSize, maxInputSize);
@@ -55,47 +107,41 @@
             meta, true /* createEncoder */,
             source);
 
-#if 1
-    sp<AMRWriter> writer = new AMRWriter("/sdcard/out.amr");
-    writer->addSource(encoder);
-    writer->start();
-    sleep(10);
-    writer->stop();
-#else
-    sp<MediaSource> decoder = OMXCodec::Create(
-            client.interface(),
-            meta, false /* createEncoder */,
-            encoder);
+    if (fileOut != NULL) {
+        // target file specified, write encoded AMR output
+        sp<AMRWriter> writer = new AMRWriter(fileOut);
+        writer->addSource(encoder);
+        writer->start();
+        sleep(duration);
+        writer->stop();
+    } else {
+        // otherwise decode to speaker
+        sp<MediaSource> decoder = OMXCodec::Create(
+                client.interface(),
+                meta, false /* createEncoder */,
+                encoder);
 
-#if 0
-    AudioPlayer *player = new AudioPlayer(NULL);
-    player->setSource(decoder);
-
-    player->start();
-
-    sleep(10);
-
-    player->stop();
-
-    delete player;
-    player = NULL;
-#elif 0
-    CHECK_EQ(decoder->start(), (status_t)OK);
-
-    MediaBuffer *buffer;
-    while (decoder->read(&buffer) == OK) {
-        // do something with buffer
-
-        putchar('.');
-        fflush(stdout);
-
-        buffer->release();
-        buffer = NULL;
+        if (playToSpeaker) {
+            AudioPlayer *player = new AudioPlayer(NULL);
+            player->setSource(decoder);
+            player->start();
+            sleep(duration);
+            source->stop(); // must stop source otherwise delete player will hang
+            delete player; // there is no player->stop()...
+        } else {
+            CHECK_EQ(decoder->start(), (status_t)OK);
+            MediaBuffer* buffer;
+            while (decoder->read(&buffer) == OK) {
+                // do something with buffer (save it eventually?)
+                // need to stop after some count though...
+                putchar('.');
+                fflush(stdout);
+                buffer->release();
+                buffer = NULL;
+            }
+            CHECK_EQ(decoder->stop(), (status_t)OK);
+        }
     }
 
-    CHECK_EQ(decoder->stop(), (status_t)OK);
-#endif
-#endif
-
     return 0;
 }
diff --git a/cmds/stagefright/codec.cpp b/cmds/stagefright/codec.cpp
index fdfefdf..fd02bcc 100644
--- a/cmds/stagefright/codec.cpp
+++ b/cmds/stagefright/codec.cpp
@@ -16,6 +16,7 @@
 
 //#define LOG_NDEBUG 0
 #define LOG_TAG "codec"
+#include <inttypes.h>
 #include <utils/Log.h>
 
 #include "SimplePlayer.h"
@@ -23,6 +24,7 @@
 #include <binder/IServiceManager.h>
 #include <binder/ProcessState.h>
 #include <media/ICrypto.h>
+#include <media/IMediaHTTPService.h>
 #include <media/IMediaPlayerService.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
@@ -75,7 +77,7 @@
     static int64_t kTimeout = 500ll;
 
     sp<NuMediaExtractor> extractor = new NuMediaExtractor;
-    if (extractor->setDataSource(path) != OK) {
+    if (extractor->setDataSource(NULL /* httpService */, path) != OK) {
         fprintf(stderr, "unable to instantiate extractor.\n");
         return 1;
     }
@@ -291,13 +293,13 @@
         CHECK_EQ((status_t)OK, state->mCodec->release());
 
         if (state->mIsAudio) {
-            printf("track %d: %lld bytes received. %.2f KB/sec\n",
+            printf("track %zu: %" PRId64 " bytes received. %.2f KB/sec\n",
                    i,
                    state->mNumBytesDecoded,
                    state->mNumBytesDecoded * 1E6 / 1024 / elapsedTimeUs);
         } else {
-            printf("track %d: %lld frames decoded, %.2f fps. %lld bytes "
-                   "received. %.2f KB/sec\n",
+            printf("track %zu: %" PRId64 " frames decoded, %.2f fps. %" PRId64
+                    " bytes received. %.2f KB/sec\n",
                    i,
                    state->mNumBuffersDecoded,
                    state->mNumBuffersDecoded * 1E6 / elapsedTimeUs,
diff --git a/cmds/stagefright/muxer.cpp b/cmds/stagefright/muxer.cpp
index cca33e0..f4a33e8 100644
--- a/cmds/stagefright/muxer.cpp
+++ b/cmds/stagefright/muxer.cpp
@@ -16,9 +16,11 @@
 
 //#define LOG_NDEBUG 0
 #define LOG_TAG "muxer"
+#include <inttypes.h>
 #include <utils/Log.h>
 
 #include <binder/ProcessState.h>
+#include <media/IMediaHTTPService.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/ALooper.h>
@@ -58,7 +60,7 @@
         int trimEndTimeMs,
         int rotationDegrees) {
     sp<NuMediaExtractor> extractor = new NuMediaExtractor;
-    if (extractor->setDataSource(path) != OK) {
+    if (extractor->setDataSource(NULL /* httpService */, path) != OK) {
         fprintf(stderr, "unable to instantiate extractor. %s\n", path);
         return 1;
     }
@@ -198,7 +200,7 @@
     trackIndexMap.clear();
 
     int64_t elapsedTimeUs = ALooper::GetNowUs() - muxerStartTimeUs;
-    fprintf(stderr, "SUCCESS: muxer generate the video in %lld ms\n",
+    fprintf(stderr, "SUCCESS: muxer generate the video in %" PRId64 " ms\n",
             elapsedTimeUs / 1000);
 
     return 0;
diff --git a/cmds/stagefright/record.cpp b/cmds/stagefright/record.cpp
index b7a40c2..fdc352e 100644
--- a/cmds/stagefright/record.cpp
+++ b/cmds/stagefright/record.cpp
@@ -296,7 +296,7 @@
 }
 #else
 
-int main(int argc, char **argv) {
+int main(int /* argc */, char ** /* argv */) {
     android::ProcessState::self()->startThreadPool();
 
     OMXClient client;
diff --git a/cmds/stagefright/recordvideo.cpp b/cmds/stagefright/recordvideo.cpp
index c30c122..9f547c7 100644
--- a/cmds/stagefright/recordvideo.cpp
+++ b/cmds/stagefright/recordvideo.cpp
@@ -16,6 +16,7 @@
 
 #include "SineSource.h"
 
+#include <inttypes.h>
 #include <binder/ProcessState.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/AudioPlayer.h>
@@ -72,7 +73,7 @@
         return meta;
     }
 
-    virtual status_t start(MetaData *params) {
+    virtual status_t start(MetaData *params __unused) {
         mNumFramesOutput = 0;
         return OK;
     }
@@ -82,7 +83,7 @@
     }
 
     virtual status_t read(
-            MediaBuffer **buffer, const MediaSource::ReadOptions *options) {
+            MediaBuffer **buffer, const MediaSource::ReadOptions *options __unused) {
 
         if (mNumFramesOutput % 10 == 0) {
             fprintf(stderr, ".");
@@ -99,8 +100,12 @@
         // We don't care about the contents. we just test video encoder
         // Also, by skipping the content generation, we can return from
         // read() much faster.
-        //char x = (char)((double)rand() / RAND_MAX * 255);
-        //memset((*buffer)->data(), x, mSize);
+#if 0
+        // iterate through solid planes of color.
+        static unsigned char x = 0x60;
+        memset((*buffer)->data(), x, mSize);
+        x = x >= 0xa0 ? 0x60 : x + 1;
+#endif
         (*buffer)->set_range(0, mSize);
         (*buffer)->meta_data()->clear();
         (*buffer)->meta_data()->setInt64(
@@ -162,7 +167,7 @@
     int level = -1;        // Encoder specific default
     int profile = -1;      // Encoder specific default
     int codec = 0;
-    char *fileName = "/sdcard/output.mp4";
+    const char *fileName = "/sdcard/output.mp4";
     bool preferSoftwareCodec = false;
 
     android::ProcessState::self()->startThreadPool();
@@ -312,7 +317,7 @@
         fprintf(stderr, "record failed: %d\n", err);
         return 1;
     }
-    fprintf(stderr, "encoding %d frames in %lld us\n", nFrames, (end-start)/1000);
+    fprintf(stderr, "encoding %d frames in %" PRId64 " us\n", nFrames, (end-start)/1000);
     fprintf(stderr, "encoding speed is: %.2f fps\n", (nFrames * 1E9) / (end-start));
     return 0;
 }
diff --git a/cmds/stagefright/sf2.cpp b/cmds/stagefright/sf2.cpp
index c817443..0f729a3 100644
--- a/cmds/stagefright/sf2.cpp
+++ b/cmds/stagefright/sf2.cpp
@@ -16,10 +16,15 @@
 
 //#define LOG_NDEBUG 0
 #define LOG_TAG "sf2"
+#include <inttypes.h>
 #include <utils/Log.h>
 
+#include <signal.h>
+
 #include <binder/ProcessState.h>
 
+#include <media/IMediaHTTPService.h>
+
 #include <media/stagefright/foundation/hexdump.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
@@ -42,6 +47,18 @@
 
 using namespace android;
 
+volatile static bool ctrlc = false;
+
+static sighandler_t oldhandler = NULL;
+
+static void mysighandler(int signum) {
+    if (signum == SIGINT) {
+        ctrlc = true;
+        return;
+    }
+    oldhandler(signum);
+}
+
 struct Controller : public AHandler {
     Controller(const char *uri, bool decodeAudio,
                const sp<Surface> &surface, bool renderToSurface)
@@ -62,7 +79,30 @@
     virtual ~Controller() {
     }
 
+    virtual void printStatistics() {
+        int64_t delayUs = ALooper::GetNowUs() - mStartTimeUs;
+
+        if (mDecodeAudio) {
+            printf("%" PRId64 " bytes received. %.2f KB/sec\n",
+            mTotalBytesReceived,
+            mTotalBytesReceived * 1E6 / 1024 / delayUs);
+        } else {
+            printf("%d frames decoded, %.2f fps. %" PRId64 " bytes "
+                    "received. %.2f KB/sec\n",
+            mNumOutputBuffersReceived,
+            mNumOutputBuffersReceived * 1E6 / delayUs,
+            mTotalBytesReceived,
+            mTotalBytesReceived * 1E6 / 1024 / delayUs);
+        }
+    }
+
     virtual void onMessageReceived(const sp<AMessage> &msg) {
+        if (ctrlc) {
+            printf("\n");
+            printStatistics();
+            (new AMessage(kWhatStop, id()))->post();
+            ctrlc = false;
+        }
         switch (msg->what()) {
             case kWhatStart:
             {
@@ -75,7 +115,8 @@
 #endif
 
                 sp<DataSource> dataSource =
-                    DataSource::CreateFromURI(mURI.c_str());
+                    DataSource::CreateFromURI(
+                            NULL /* httpService */, mURI.c_str());
 
                 sp<MediaExtractor> extractor =
                     MediaExtractor::Create(dataSource);
@@ -98,7 +139,10 @@
                         break;
                     }
                 }
-                CHECK(mSource != NULL);
+                if (mSource == NULL) {
+                    printf("no %s track found\n", mDecodeAudio ? "audio" : "video");
+                    exit (1);
+                }
 
                 CHECK_EQ(mSource->start(), (status_t)OK);
 
@@ -167,42 +211,28 @@
                 int32_t what;
                 CHECK(msg->findInt32("what", &what));
 
-                if (what == ACodec::kWhatFillThisBuffer) {
+                if (what == CodecBase::kWhatFillThisBuffer) {
                     onFillThisBuffer(msg);
-                } else if (what == ACodec::kWhatDrainThisBuffer) {
+                } else if (what == CodecBase::kWhatDrainThisBuffer) {
                     if ((mNumOutputBuffersReceived++ % 16) == 0) {
                         printf(".");
                         fflush(stdout);
                     }
 
                     onDrainThisBuffer(msg);
-                } else if (what == ACodec::kWhatEOS
-                        || what == ACodec::kWhatError) {
-                    printf((what == ACodec::kWhatEOS) ? "$\n" : "E\n");
+                } else if (what == CodecBase::kWhatEOS
+                        || what == CodecBase::kWhatError) {
+                    printf((what == CodecBase::kWhatEOS) ? "$\n" : "E\n");
 
-                    int64_t delayUs = ALooper::GetNowUs() - mStartTimeUs;
-
-                    if (mDecodeAudio) {
-                        printf("%lld bytes received. %.2f KB/sec\n",
-                               mTotalBytesReceived,
-                               mTotalBytesReceived * 1E6 / 1024 / delayUs);
-                    } else {
-                        printf("%d frames decoded, %.2f fps. %lld bytes "
-                               "received. %.2f KB/sec\n",
-                               mNumOutputBuffersReceived,
-                               mNumOutputBuffersReceived * 1E6 / delayUs,
-                               mTotalBytesReceived,
-                               mTotalBytesReceived * 1E6 / 1024 / delayUs);
-                    }
-
+                    printStatistics();
                     (new AMessage(kWhatStop, id()))->post();
-                } else if (what == ACodec::kWhatFlushCompleted) {
+                } else if (what == CodecBase::kWhatFlushCompleted) {
                     mSeekState = SEEK_FLUSH_COMPLETED;
                     mCodec->signalResume();
 
                     (new AMessage(kWhatSeek, id()))->post(5000000ll);
-                } else if (what == ACodec::kWhatOutputFormatChanged) {
-                } else if (what == ACodec::kWhatShutdownCompleted) {
+                } else if (what == CodecBase::kWhatOutputFormatChanged) {
+                } else if (what == CodecBase::kWhatShutdownCompleted) {
                     mDecodeLooper->unregisterHandler(mCodec->id());
 
                     if (mDecodeLooper != looper()) {
@@ -210,12 +240,6 @@
                     }
 
                     looper()->stop();
-                } else if (what == ACodec::kWhatError) {
-                    ALOGE("something went wrong, codec reported an error.");
-
-                    printf("E\n");
-
-                    (new AMessage(kWhatStop, id()))->post();
                 }
                 break;
             }
@@ -638,6 +662,8 @@
 
     looper->registerHandler(controller);
 
+    signal(SIGINT, mysighandler);
+
     controller->startAsync();
 
     CHECK_EQ(looper->start(true /* runOnCallingThread */), (status_t)OK);
diff --git a/cmds/stagefright/stagefright.cpp b/cmds/stagefright/stagefright.cpp
index 030bf1b..81edcb4 100644
--- a/cmds/stagefright/stagefright.cpp
+++ b/cmds/stagefright/stagefright.cpp
@@ -14,20 +14,22 @@
  * limitations under the License.
  */
 
+#include <inttypes.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/time.h>
+
 //#define LOG_NDEBUG 0
 #define LOG_TAG "stagefright"
 #include <media/stagefright/foundation/ADebug.h>
 
-#include <sys/time.h>
-
-#include <stdlib.h>
-#include <string.h>
-
 #include "jpeg.h"
 #include "SineSource.h"
 
 #include <binder/IServiceManager.h>
 #include <binder/ProcessState.h>
+#include <media/IMediaHTTPService.h>
 #include <media/IMediaPlayerService.h>
 #include <media/stagefright/foundation/ALooper.h>
 #include "include/NuCachedSource2.h"
@@ -49,8 +51,6 @@
 
 #include <private/media/VideoFrame.h>
 
-#include <fcntl.h>
-
 #include <gui/GLConsumer.h>
 #include <gui/Surface.h>
 #include <gui/SurfaceComposerClient.h>
@@ -89,8 +89,8 @@
     int64_t minUs = decodeTimesUs->itemAt(0);
     int64_t maxUs = decodeTimesUs->itemAt(n - 1);
 
-    printf("min decode time %lld us (%.2f secs)\n", minUs, minUs / 1E6);
-    printf("max decode time %lld us (%.2f secs)\n", maxUs, maxUs / 1E6);
+    printf("min decode time %" PRId64 " us (%.2f secs)\n", minUs, minUs / 1E6);
+    printf("max decode time %" PRId64 " us (%.2f secs)\n", maxUs, maxUs / 1E6);
 
     size_t counts[100];
     for (size_t i = 0; i < 100; ++i) {
@@ -110,7 +110,7 @@
         int64_t slotUs = minUs + (i * (maxUs - minUs) / 100);
 
         double fps = 1E6 / slotUs;
-        printf("[%.2f fps]: %d\n", fps, counts[i]);
+        printf("[%.2f fps]: %zu\n", fps, counts[i]);
     }
 }
 
@@ -262,7 +262,7 @@
                     }
                 }
 
-                printf("buffer has timestamp %lld us (%.2f secs)\n",
+                printf("buffer has timestamp %" PRId64 " us (%.2f secs)\n",
                        timestampUs, timestampUs / 1E6);
 
                 buffer->release();
@@ -285,7 +285,7 @@
                 seekTimeUs = (rand() * (float)durationUs) / RAND_MAX;
                 options.setSeekTo(seekTimeUs);
 
-                printf("seeking to %lld us (%.2f secs)\n",
+                printf("seeking to %" PRId64 " us (%.2f secs)\n",
                        seekTimeUs, seekTimeUs / 1E6);
             }
         }
@@ -388,7 +388,7 @@
         // sizes may be different across decoders.
         printf("avg. %.2f KB/sec\n", totalBytes / 1024 * 1E6 / delay);
 
-        printf("decoded a total of %lld bytes\n", totalBytes);
+        printf("decoded a total of %" PRId64 " bytes\n", totalBytes);
     }
 }
 
@@ -574,7 +574,8 @@
             int64_t timeUs;
             CHECK(buffer->meta_data()->findInt64(kKeyTime, &timeUs));
 
-            printf("%lld\t%lld\t%lld\n", seekTimeUs, timeUs, seekTimeUs - timeUs);
+            printf("%" PRId64 "\t%" PRId64 "\t%" PRId64 "\n",
+                   seekTimeUs, timeUs, seekTimeUs - timeUs);
 
             buffer->release();
             buffer = NULL;
@@ -645,7 +646,7 @@
                 const CodecProfileLevel &profileLevel =
                      results[i].mProfileLevels[j];
 
-                printf("%s%ld/%ld", j > 0 ? ", " : "",
+                printf("%s%" PRIu32 "/%" PRIu32, j > 0 ? ", " : "",
                     profileLevel.mProfile, profileLevel.mLevel);
             }
 
@@ -938,9 +939,13 @@
         } else {
             CHECK(useSurfaceTexAlloc);
 
-            sp<BufferQueue> bq = new BufferQueue();
-            sp<GLConsumer> texture = new GLConsumer(bq, 0 /* tex */);
-            gSurface = new Surface(bq);
+            sp<IGraphicBufferProducer> producer;
+            sp<IGraphicBufferConsumer> consumer;
+            BufferQueue::createBufferQueue(&producer, &consumer);
+            sp<GLConsumer> texture = new GLConsumer(consumer, 0 /* tex */,
+                    GLConsumer::TEXTURE_EXTERNAL, true /* useFenceSync */,
+                    false /* isControlledByApp */);
+            gSurface = new Surface(producer);
         }
 
         CHECK_EQ((status_t)OK,
@@ -958,7 +963,8 @@
 
         const char *filename = argv[k];
 
-        sp<DataSource> dataSource = DataSource::CreateFromURI(filename);
+        sp<DataSource> dataSource =
+            DataSource::CreateFromURI(NULL /* httpService */, filename);
 
         if (strncasecmp(filename, "sine:", 5) && dataSource == NULL) {
             fprintf(stderr, "Unable to create data source.\n");
@@ -1071,7 +1077,7 @@
 
                 int64_t thumbTimeUs;
                 if (meta->findInt64(kKeyThumbnailTime, &thumbTimeUs)) {
-                    printf("thumbnailTime: %lld us (%.2f secs)\n",
+                    printf("thumbnailTime: %" PRId64 " us (%.2f secs)\n",
                            thumbTimeUs, thumbTimeUs / 1E6);
                 }
 
diff --git a/cmds/stagefright/stream.cpp b/cmds/stagefright/stream.cpp
index dba67a9..0566d14 100644
--- a/cmds/stagefright/stream.cpp
+++ b/cmds/stagefright/stream.cpp
@@ -21,6 +21,7 @@
 #include <binder/ProcessState.h>
 #include <cutils/properties.h> // for property_get
 
+#include <media/IMediaHTTPService.h>
 #include <media/IStreamSource.h>
 #include <media/mediaplayer.h>
 #include <media/stagefright/foundation/ADebug.h>
@@ -159,7 +160,9 @@
 MyConvertingStreamSource::MyConvertingStreamSource(const char *filename)
     : mCurrentBufferIndex(-1),
       mCurrentBufferOffset(0) {
-    sp<DataSource> dataSource = DataSource::CreateFromURI(filename);
+    sp<DataSource> dataSource =
+        DataSource::CreateFromURI(NULL /* httpService */, filename);
+
     CHECK(dataSource != NULL);
 
     sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource);
@@ -371,7 +374,7 @@
     }
 
     sp<IMediaPlayer> player =
-        service->create(client, 0);
+        service->create(client, AUDIO_SESSION_ALLOCATE);
 
     if (player != NULL && player->setDataSource(source) == NO_ERROR) {
         player->setVideoSurfaceTexture(surface->getIGraphicBufferProducer());
diff --git a/drm/common/DrmSupportInfo.cpp b/drm/common/DrmSupportInfo.cpp
index 5400bdd..584c6a6 100644
--- a/drm/common/DrmSupportInfo.cpp
+++ b/drm/common/DrmSupportInfo.cpp
@@ -47,7 +47,7 @@
         return false;
     }
 
-    for (unsigned int i = 0; i < mMimeTypeVector.size(); i++) {
+    for (size_t i = 0; i < mMimeTypeVector.size(); i++) {
         const String8 item = mMimeTypeVector.itemAt(i);
 
         if (!strcasecmp(item.string(), mimeType.string())) {
@@ -58,7 +58,7 @@
 }
 
 bool DrmSupportInfo::isSupportedFileSuffix(const String8& fileType) const {
-    for (unsigned int i = 0; i < mFileSuffixVector.size(); i++) {
+    for (size_t i = 0; i < mFileSuffixVector.size(); i++) {
         const String8 item = mFileSuffixVector.itemAt(i);
 
         if (!strcasecmp(item.string(), fileType.string())) {
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/drm/drmserver/DrmManager.cpp b/drm/drmserver/DrmManager.cpp
index dccd23d..d8aeb0c 100644
--- a/drm/drmserver/DrmManager.cpp
+++ b/drm/drmserver/DrmManager.cpp
@@ -101,7 +101,7 @@
 status_t DrmManager::loadPlugIns(const String8& plugInDirPath) {
     mPlugInManager.loadPlugIns(plugInDirPath);
     Vector<String8> plugInPathList = mPlugInManager.getPlugInIdList();
-    for (unsigned int i = 0; i < plugInPathList.size(); ++i) {
+    for (size_t i = 0; i < plugInPathList.size(); ++i) {
         String8 plugInPath = plugInPathList[i];
         DrmSupportInfo* info = mPlugInManager.getPlugIn(plugInPath).getSupportInfo(0);
         if (NULL != info) {
@@ -138,7 +138,7 @@
     Mutex::Autolock _l(mLock);
     if (!mSupportInfoToPlugInIdMap.isEmpty()) {
         Vector<String8> plugInIdList = mPlugInManager.getPlugInIdList();
-        for (unsigned int index = 0; index < plugInIdList.size(); index++) {
+        for (size_t index = 0; index < plugInIdList.size(); index++) {
             IDrmEngine& rDrmEngine = mPlugInManager.getPlugIn(plugInIdList.itemAt(index));
             rDrmEngine.initialize(uniqueId);
             rDrmEngine.setOnInfoListener(uniqueId, this);
@@ -149,7 +149,7 @@
 void DrmManager::removeClient(int uniqueId) {
     Mutex::Autolock _l(mLock);
     Vector<String8> plugInIdList = mPlugInManager.getPlugInIdList();
-    for (unsigned int index = 0; index < plugInIdList.size(); index++) {
+    for (size_t index = 0; index < plugInIdList.size(); index++) {
         IDrmEngine& rDrmEngine = mPlugInManager.getPlugIn(plugInIdList.itemAt(index));
         rDrmEngine.terminate(uniqueId);
     }
@@ -208,7 +208,7 @@
     bool result = false;
     Vector<String8> plugInPathList = mPlugInManager.getPlugInIdList();
 
-    for (unsigned int i = 0; i < plugInPathList.size(); ++i) {
+    for (size_t i = 0; i < plugInPathList.size(); ++i) {
         IDrmEngine& rDrmEngine = mPlugInManager.getPlugIn(plugInPathList[i]);
         result = rDrmEngine.canHandle(uniqueId, path);
 
@@ -318,7 +318,7 @@
 status_t DrmManager::removeAllRights(int uniqueId) {
     Vector<String8> plugInIdList = mPlugInManager.getPlugInIdList();
     status_t result = DRM_ERROR_UNKNOWN;
-    for (unsigned int index = 0; index < plugInIdList.size(); index++) {
+    for (size_t index = 0; index < plugInIdList.size(); index++) {
         IDrmEngine& rDrmEngine = mPlugInManager.getPlugIn(plugInIdList.itemAt(index));
         result = rDrmEngine.removeAllRights(uniqueId);
         if (DRM_NO_ERROR != result) {
@@ -412,7 +412,7 @@
     if (NULL != handle) {
         handle->decryptId = mDecryptSessionId + 1;
 
-        for (unsigned int index = 0; index < plugInIdList.size(); index++) {
+        for (size_t index = 0; index < plugInIdList.size(); index++) {
             String8 plugInId = plugInIdList.itemAt(index);
             IDrmEngine& rDrmEngine = mPlugInManager.getPlugIn(plugInId);
             result = rDrmEngine.openDecryptSession(uniqueId, handle, fd, offset, length, mime);
@@ -440,7 +440,7 @@
     if (NULL != handle) {
         handle->decryptId = mDecryptSessionId + 1;
 
-        for (unsigned int index = 0; index < plugInIdList.size(); index++) {
+        for (size_t index = 0; index < plugInIdList.size(); index++) {
             String8 plugInId = plugInIdList.itemAt(index);
             IDrmEngine& rDrmEngine = mPlugInManager.getPlugIn(plugInId);
             result = rDrmEngine.openDecryptSession(uniqueId, handle, uri, mime);
@@ -565,7 +565,7 @@
     String8 plugInId("");
 
     if (EMPTY_STRING != mimeType) {
-        for (unsigned int index = 0; index < mSupportInfoToPlugInIdMap.size(); index++) {
+        for (size_t index = 0; index < mSupportInfoToPlugInIdMap.size(); index++) {
             const DrmSupportInfo& drmSupportInfo = mSupportInfoToPlugInIdMap.keyAt(index);
 
             if (drmSupportInfo.isSupportedMimeType(mimeType)) {
@@ -581,7 +581,7 @@
     String8 plugInId("");
     const String8 fileSuffix = path.getPathExtension();
 
-    for (unsigned int index = 0; index < mSupportInfoToPlugInIdMap.size(); index++) {
+    for (size_t index = 0; index < mSupportInfoToPlugInIdMap.size(); index++) {
         const DrmSupportInfo& drmSupportInfo = mSupportInfoToPlugInIdMap.keyAt(index);
 
         if (drmSupportInfo.isSupportedFileSuffix(fileSuffix)) {
@@ -599,7 +599,7 @@
 
 void DrmManager::onInfo(const DrmInfoEvent& event) {
     Mutex::Autolock _l(mListenerLock);
-    for (unsigned int index = 0; index < mServiceListeners.size(); index++) {
+    for (size_t index = 0; index < mServiceListeners.size(); index++) {
         int uniqueId = mServiceListeners.keyAt(index);
 
         if (uniqueId == event.getUniqueId()) {
diff --git a/drm/drmserver/DrmManagerService.cpp b/drm/drmserver/DrmManagerService.cpp
index 2b71904..63341e0 100644
--- a/drm/drmserver/DrmManagerService.cpp
+++ b/drm/drmserver/DrmManagerService.cpp
@@ -34,7 +34,18 @@
 static Vector<uid_t> trustedUids;
 
 static bool isProtectedCallAllowed() {
-    return true;
+    // TODO
+    // Following implementation is just for reference.
+    // Each OEM manufacturer should implement/replace with their own solutions.
+    IPCThreadState* ipcState = IPCThreadState::self();
+    uid_t uid = ipcState->getCallingUid();
+
+    for (unsigned int i = 0; i < trustedUids.size(); ++i) {
+        if (trustedUids[i] == uid) {
+            return true;
+        }
+    }
+    return false;
 }
 
 void DrmManagerService::instantiate() {
diff --git a/drm/libdrmframework/include/PlugInManager.h b/drm/libdrmframework/include/PlugInManager.h
index 7bb143f..c1d019a 100644
--- a/drm/libdrmframework/include/PlugInManager.h
+++ b/drm/libdrmframework/include/PlugInManager.h
@@ -80,7 +80,7 @@
         Vector<String8> plugInFileList = getPlugInPathList(rsPlugInDirPath);
 
         if (!plugInFileList.isEmpty()) {
-            for (unsigned int i = 0; i < plugInFileList.size(); ++i) {
+            for (size_t i = 0; i < plugInFileList.size(); ++i) {
                 loadPlugIn(plugInFileList[i]);
             }
         }
@@ -91,7 +91,7 @@
      *
      */
     void unloadPlugIns() {
-        for (unsigned int i = 0; i < m_plugInIdList.size(); ++i) {
+        for (size_t i = 0; i < m_plugInIdList.size(); ++i) {
             unloadPlugIn(m_plugInIdList[i]);
         }
         m_plugInIdList.clear();
diff --git a/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/src/FwdLockEngine.cpp b/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/src/FwdLockEngine.cpp
index 234aef2..f400732 100644
--- a/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/src/FwdLockEngine.cpp
+++ b/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/src/FwdLockEngine.cpp
@@ -316,6 +316,7 @@
 
     if (-1 < fileDesc) {
         if (FwdLockFile_attach(fileDesc) < 0) {
+            close(fileDesc);
             return mimeString;
         }
         const char* pMimeType = FwdLockFile_GetContentType(fileDesc);
diff --git a/drm/mediadrm/plugins/clearkey/AesCtrDecryptor.cpp b/drm/mediadrm/plugins/clearkey/AesCtrDecryptor.cpp
new file mode 100644
index 0000000..01f8d65
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/AesCtrDecryptor.cpp
@@ -0,0 +1,67 @@
+/*
+ * 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 "ClearKeyCryptoPlugin"
+#include <utils/Log.h>
+
+#include <openssl/aes.h>
+
+#include "AesCtrDecryptor.h"
+
+namespace clearkeydrm {
+
+static const size_t kBlockBitCount = kBlockSize * 8;
+
+android::status_t AesCtrDecryptor::decrypt(const android::Vector<uint8_t>& key,
+        const Iv iv, const uint8_t* source,
+        uint8_t* destination,
+        const SubSample* subSamples,
+        size_t numSubSamples,
+        size_t* bytesDecryptedOut) {
+    uint32_t blockOffset = 0;
+    uint8_t previousEncryptedCounter[kBlockSize];
+    memset(previousEncryptedCounter, 0, kBlockSize);
+
+    size_t offset = 0;
+    AES_KEY opensslKey;
+    AES_set_encrypt_key(key.array(), kBlockBitCount, &opensslKey);
+    Iv opensslIv;
+    memcpy(opensslIv, iv, sizeof(opensslIv));
+
+    for (size_t i = 0; i < numSubSamples; ++i) {
+        const SubSample& subSample = subSamples[i];
+
+        if (subSample.mNumBytesOfClearData > 0) {
+            memcpy(destination + offset, source + offset,
+                    subSample.mNumBytesOfClearData);
+            offset += subSample.mNumBytesOfClearData;
+        }
+
+        if (subSample.mNumBytesOfEncryptedData > 0) {
+            AES_ctr128_encrypt(source + offset, destination + offset,
+                    subSample.mNumBytesOfEncryptedData, &opensslKey,
+                    opensslIv, previousEncryptedCounter,
+                    &blockOffset);
+            offset += subSample.mNumBytesOfEncryptedData;
+        }
+    }
+
+    *bytesDecryptedOut = offset;
+    return android::OK;
+}
+
+} // namespace clearkeydrm
diff --git a/drm/mediadrm/plugins/clearkey/AesCtrDecryptor.h b/drm/mediadrm/plugins/clearkey/AesCtrDecryptor.h
new file mode 100644
index 0000000..b416266
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/AesCtrDecryptor.h
@@ -0,0 +1,44 @@
+/*
+ * 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 CLEARKEY_AES_CTR_DECRYPTOR_H_
+#define CLEARKEY_AES_CTR_DECRYPTOR_H_
+
+#include <media/stagefright/foundation/ABase.h>
+#include <Utils.h>
+#include <utils/Errors.h>
+#include <utils/Vector.h>
+
+#include "ClearKeyTypes.h"
+
+namespace clearkeydrm {
+
+class AesCtrDecryptor {
+public:
+    AesCtrDecryptor() {}
+
+    android::status_t decrypt(const android::Vector<uint8_t>& key, const Iv iv,
+            const uint8_t* source, uint8_t* destination,
+            const SubSample* subSamples, size_t numSubSamples,
+            size_t* bytesDecryptedOut);
+
+private:
+    DISALLOW_EVIL_CONSTRUCTORS(AesCtrDecryptor);
+};
+
+} // namespace clearkeydrm
+
+#endif // CLEARKEY_AES_CTR_DECRYPTOR_H_
diff --git a/drm/mediadrm/plugins/clearkey/Android.mk b/drm/mediadrm/plugins/clearkey/Android.mk
new file mode 100644
index 0000000..22a85b4
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/Android.mk
@@ -0,0 +1,62 @@
+#
+# 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.
+#
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+    AesCtrDecryptor.cpp \
+    ClearKeyUUID.cpp \
+    CreatePluginFactories.cpp \
+    CryptoFactory.cpp \
+    CryptoPlugin.cpp \
+    DrmFactory.cpp \
+    DrmPlugin.cpp \
+    InitDataParser.cpp \
+    JsonWebKey.cpp \
+    Session.cpp \
+    SessionLibrary.cpp \
+    Utils.cpp \
+
+LOCAL_C_INCLUDES := \
+    bionic \
+    external/jsmn \
+    external/openssl/include \
+    frameworks/av/drm/mediadrm/plugins/clearkey \
+    frameworks/av/include \
+    frameworks/native/include \
+
+LOCAL_MODULE := libdrmclearkeyplugin
+
+LOCAL_PROPRIETARY_MODULE := true
+LOCAL_MODULE_RELATIVE_PATH := mediadrm
+
+LOCAL_SHARED_LIBRARIES := \
+    libcrypto \
+    liblog \
+    libstagefright_foundation \
+    libutils \
+
+LOCAL_STATIC_LIBRARIES := \
+    libjsmn \
+
+LOCAL_MODULE_TAGS := optional
+
+include $(BUILD_SHARED_LIBRARY)
+
+#########################################################################
+# Build unit tests
+
+include $(LOCAL_PATH)/tests/Android.mk
diff --git a/drm/mediadrm/plugins/clearkey/ClearKeyTypes.h b/drm/mediadrm/plugins/clearkey/ClearKeyTypes.h
new file mode 100644
index 0000000..a28959a
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/ClearKeyTypes.h
@@ -0,0 +1,38 @@
+/*
+ * 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 CLEARKEY_TYPES_H_
+#define CLEARKEY_TYPES_H_
+
+#include <media/hardware/CryptoAPI.h>
+#include <openssl/aes.h>
+#include <utils/KeyedVector.h>
+#include <utils/Vector.h>
+
+namespace clearkeydrm {
+
+const uint8_t kBlockSize = AES_BLOCK_SIZE;
+typedef uint8_t KeyId[kBlockSize];
+typedef uint8_t Iv[kBlockSize];
+
+typedef android::CryptoPlugin::SubSample SubSample;
+
+typedef android::KeyedVector<android::Vector<uint8_t>,
+        android::Vector<uint8_t> > KeyMap;
+
+} // namespace clearkeydrm
+
+#endif // CLEARKEY_TYPES_H_
diff --git a/drm/mediadrm/plugins/clearkey/ClearKeyUUID.cpp b/drm/mediadrm/plugins/clearkey/ClearKeyUUID.cpp
new file mode 100644
index 0000000..ed050f7
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/ClearKeyUUID.cpp
@@ -0,0 +1,32 @@
+/*
+ * 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.
+ */
+
+#include <string.h>
+
+#include "ClearKeyUUID.h"
+
+namespace clearkeydrm {
+
+bool isClearKeyUUID(const uint8_t uuid[16]) {
+    static const uint8_t kClearKeyUUID[16] = {
+        0x10,0x77,0xEF,0xEC,0xC0,0xB2,0x4D,0x02,
+        0xAC,0xE3,0x3C,0x1E,0x52,0xE2,0xFB,0x4B
+    };
+
+    return !memcmp(uuid, kClearKeyUUID, sizeof(kClearKeyUUID));
+}
+
+} // namespace clearkeydrm
diff --git a/libvideoeditor/vss/common/inc/NXPSW_CompilerSwitches.h b/drm/mediadrm/plugins/clearkey/ClearKeyUUID.h
old mode 100755
new mode 100644
similarity index 67%
rename from libvideoeditor/vss/common/inc/NXPSW_CompilerSwitches.h
rename to drm/mediadrm/plugins/clearkey/ClearKeyUUID.h
index 13cac6d..ac99418
--- a/libvideoeditor/vss/common/inc/NXPSW_CompilerSwitches.h
+++ b/drm/mediadrm/plugins/clearkey/ClearKeyUUID.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011 The Android Open Source Project
+ * 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.
@@ -14,13 +14,15 @@
  * limitations under the License.
  */
 
-#ifndef NXPSW_COMPILERSWITCHES_H
-#define NXPSW_COMPILERSWITCHES_H
+#ifndef CLEARKEY_UUID_H_
+#define CLEARKEY_UUID_H_
 
-/* ----- Main features ----- */
-#include "NXPSW_CompilerSwitches_MCS.h" /* Transcoder */
+#include <stdint.h>
 
-/* ----- Add-ons ----- */
+namespace clearkeydrm {
 
-#endif /* NXPSW_COMPILERSWITCHES_H */
+bool isClearKeyUUID(const uint8_t uuid[16]);
 
+} // namespace clearkeydrm
+
+#endif // CLEARKEY_UUID_H_
diff --git a/libvideoeditor/vss/common/inc/NXPSW_CompilerSwitches.h b/drm/mediadrm/plugins/clearkey/CreatePluginFactories.cpp
old mode 100755
new mode 100644
similarity index 61%
copy from libvideoeditor/vss/common/inc/NXPSW_CompilerSwitches.h
copy to drm/mediadrm/plugins/clearkey/CreatePluginFactories.cpp
index 13cac6d..ec1420e
--- a/libvideoeditor/vss/common/inc/NXPSW_CompilerSwitches.h
+++ b/drm/mediadrm/plugins/clearkey/CreatePluginFactories.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011 The Android Open Source Project
+ * 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.
@@ -14,13 +14,19 @@
  * limitations under the License.
  */
 
-#ifndef NXPSW_COMPILERSWITCHES_H
-#define NXPSW_COMPILERSWITCHES_H
+#include "CreatePluginFactories.h"
 
-/* ----- Main features ----- */
-#include "NXPSW_CompilerSwitches_MCS.h" /* Transcoder */
+#include "CryptoFactory.h"
+#include "DrmFactory.h"
 
-/* ----- Add-ons ----- */
+extern "C" {
 
-#endif /* NXPSW_COMPILERSWITCHES_H */
+android::DrmFactory* createDrmFactory() {
+    return new clearkeydrm::DrmFactory();
+}
 
+android::CryptoFactory* createCryptoFactory() {
+    return new clearkeydrm::CryptoFactory();
+}
+
+} // extern "C"
diff --git a/libvideoeditor/vss/common/inc/NXPSW_CompilerSwitches.h b/drm/mediadrm/plugins/clearkey/CreatePluginFactories.h
old mode 100755
new mode 100644
similarity index 60%
copy from libvideoeditor/vss/common/inc/NXPSW_CompilerSwitches.h
copy to drm/mediadrm/plugins/clearkey/CreatePluginFactories.h
index 13cac6d..d9acec1
--- a/libvideoeditor/vss/common/inc/NXPSW_CompilerSwitches.h
+++ b/drm/mediadrm/plugins/clearkey/CreatePluginFactories.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011 The Android Open Source Project
+ * 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.
@@ -14,13 +14,15 @@
  * limitations under the License.
  */
 
-#ifndef NXPSW_COMPILERSWITCHES_H
-#define NXPSW_COMPILERSWITCHES_H
+#ifndef CLEARKEY_CREATE_PLUGIN_FACTORIES_H_
+#define CLEARKEY_CREATE_PLUGIN_FACTORIES_H_
 
-/* ----- Main features ----- */
-#include "NXPSW_CompilerSwitches_MCS.h" /* Transcoder */
+#include <media/drm/DrmAPI.h>
+#include <media/hardware/CryptoAPI.h>
 
-/* ----- Add-ons ----- */
+extern "C" {
+    android::DrmFactory* createDrmFactory();
+    android::CryptoFactory* createCryptoFactory();
+}
 
-#endif /* NXPSW_COMPILERSWITCHES_H */
-
+#endif // CLEARKEY_CREATE_PLUGIN_FACTORIES_H_
diff --git a/drm/mediadrm/plugins/clearkey/CryptoFactory.cpp b/drm/mediadrm/plugins/clearkey/CryptoFactory.cpp
new file mode 100644
index 0000000..ee3189b
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/CryptoFactory.cpp
@@ -0,0 +1,52 @@
+/*
+ * 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 "ClearKeyCryptoPlugin"
+#include <utils/Log.h>
+
+#include <utils/Errors.h>
+#include <utils/StrongPointer.h>
+
+#include "CryptoFactory.h"
+
+#include "ClearKeyUUID.h"
+#include "CryptoPlugin.h"
+#include "Session.h"
+#include "SessionLibrary.h"
+
+namespace clearkeydrm {
+
+bool CryptoFactory::isCryptoSchemeSupported(const uint8_t uuid[16]) const {
+    return isClearKeyUUID(uuid);
+}
+
+android::status_t CryptoFactory::createPlugin(
+        const uint8_t uuid[16],
+        const void* data, size_t size,
+        android::CryptoPlugin** plugin) {
+    if (!isCryptoSchemeSupported(uuid)) {
+        *plugin = NULL;
+        return android::BAD_VALUE;
+    }
+
+    android::sp<Session> session = SessionLibrary::get()->findSession(
+            data, size);
+    *plugin = new CryptoPlugin(session);
+    return android::OK;
+}
+
+} // namespace clearkeydrm
diff --git a/drm/mediadrm/plugins/clearkey/CryptoFactory.h b/drm/mediadrm/plugins/clearkey/CryptoFactory.h
new file mode 100644
index 0000000..568bc4b
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/CryptoFactory.h
@@ -0,0 +1,44 @@
+/*
+ * 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 CLEARKEY_CRYPTO_FACTORY_H_
+#define CLEARKEY_CRYPTO_FACTORY_H_
+
+#include <media/hardware/CryptoAPI.h>
+#include <media/stagefright/foundation/ABase.h>
+#include <utils/Errors.h>
+
+namespace clearkeydrm {
+
+class CryptoFactory : public android::CryptoFactory {
+public:
+    CryptoFactory() {}
+    virtual ~CryptoFactory() {}
+
+    virtual bool isCryptoSchemeSupported(const uint8_t uuid[16]) const;
+
+    virtual android::status_t createPlugin(
+            const uint8_t uuid[16],
+            const void* data, size_t size,
+            android::CryptoPlugin** plugin);
+
+private:
+    DISALLOW_EVIL_CONSTRUCTORS(CryptoFactory);
+};
+
+} // namespace clearkeydrm
+
+#endif // CLEARKEY_CRYPTO_FACTORY_H_
diff --git a/drm/mediadrm/plugins/clearkey/CryptoPlugin.cpp b/drm/mediadrm/plugins/clearkey/CryptoPlugin.cpp
new file mode 100644
index 0000000..adad136
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/CryptoPlugin.cpp
@@ -0,0 +1,83 @@
+/*
+ * 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 "ClearKeyCryptoPlugin"
+#include <utils/Log.h>
+
+#include <media/stagefright/MediaErrors.h>
+#include <utils/Errors.h>
+
+#include "CryptoPlugin.h"
+
+namespace clearkeydrm {
+
+using android::Vector;
+using android::AString;
+using android::status_t;
+
+// Returns negative values for error code and positive values for the size of
+// decrypted data.  In theory, the output size can be larger than the input
+// size, but in practice this will never happen for AES-CTR.
+ssize_t CryptoPlugin::decrypt(bool secure, const KeyId keyId, const Iv iv,
+                              Mode mode, const void* srcPtr,
+                              const SubSample* subSamples, size_t numSubSamples,
+                              void* dstPtr, AString* errorDetailMsg) {
+    if (secure) {
+        errorDetailMsg->setTo("Secure decryption is not supported with "
+                              "ClearKey.");
+        return android::ERROR_DRM_CANNOT_HANDLE;
+    }
+
+    if (mode == kMode_Unencrypted) {
+        size_t offset = 0;
+        for (size_t i = 0; i < numSubSamples; ++i) {
+            const SubSample& subSample = subSamples[i];
+
+            if (subSample.mNumBytesOfEncryptedData != 0) {
+                errorDetailMsg->setTo(
+                        "Encrypted subsamples found in allegedly unencrypted "
+                        "data.");
+                return android::ERROR_DRM_DECRYPT;
+            }
+
+            if (subSample.mNumBytesOfClearData != 0) {
+                memcpy(reinterpret_cast<uint8_t*>(dstPtr) + offset,
+                       reinterpret_cast<const uint8_t*>(srcPtr) + offset,
+                       subSample.mNumBytesOfClearData);
+                offset += subSample.mNumBytesOfClearData;
+            }
+        }
+        return static_cast<ssize_t>(offset);
+    } else if (mode == kMode_AES_CTR) {
+        size_t bytesDecrypted;
+        status_t res = mSession->decrypt(keyId, iv, srcPtr, dstPtr, subSamples,
+                                         numSubSamples, &bytesDecrypted);
+        if (res == android::OK) {
+            return static_cast<ssize_t>(bytesDecrypted);
+        } else {
+            errorDetailMsg->setTo("Decryption Error");
+            return static_cast<ssize_t>(res);
+        }
+    } else {
+        errorDetailMsg->setTo(
+                "Selected encryption mode is not supported by the ClearKey DRM "
+                "Plugin.");
+        return android::ERROR_DRM_CANNOT_HANDLE;
+    }
+}
+
+}  // namespace clearkeydrm
diff --git a/drm/mediadrm/plugins/clearkey/CryptoPlugin.h b/drm/mediadrm/plugins/clearkey/CryptoPlugin.h
new file mode 100644
index 0000000..002d9e0
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/CryptoPlugin.h
@@ -0,0 +1,56 @@
+/*
+ * 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 CLEARKEY_CRYPTO_PLUGIN_H_
+#define CLEARKEY_CRYPTO_PLUGIN_H_
+
+#include <media/hardware/CryptoAPI.h>
+#include <media/stagefright/foundation/ABase.h>
+#include <media/stagefright/foundation/AString.h>
+#include <utils/Errors.h>
+#include <utils/StrongPointer.h>
+
+#include "ClearKeyTypes.h"
+#include "Session.h"
+#include "Utils.h"
+
+namespace clearkeydrm {
+
+class CryptoPlugin : public android::CryptoPlugin {
+public:
+    CryptoPlugin(const android::sp<Session>& session) : mSession(session) {}
+    virtual ~CryptoPlugin() {}
+
+    virtual bool requiresSecureDecoderComponent(const char* mime) const {
+        UNUSED(mime);
+        return false;
+    }
+
+    virtual ssize_t decrypt(
+            bool secure, const KeyId keyId, const Iv iv,
+            Mode mode, const void* srcPtr,
+            const SubSample* subSamples, size_t numSubSamples,
+            void* dstPtr, android::AString* errorDetailMsg);
+
+private:
+    DISALLOW_EVIL_CONSTRUCTORS(CryptoPlugin);
+
+    android::sp<Session> mSession;
+};
+
+} // namespace clearkeydrm
+
+#endif // CLEARKEY_CRYPTO_PLUGIN_H_
diff --git a/drm/mediadrm/plugins/clearkey/DrmFactory.cpp b/drm/mediadrm/plugins/clearkey/DrmFactory.cpp
new file mode 100644
index 0000000..40275cf
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/DrmFactory.cpp
@@ -0,0 +1,52 @@
+/*
+ * 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 "ClearKeyCryptoPlugin"
+#include <utils/Log.h>
+
+#include <utils/Errors.h>
+
+#include "DrmFactory.h"
+
+#include "DrmPlugin.h"
+#include "ClearKeyUUID.h"
+#include "SessionLibrary.h"
+
+namespace clearkeydrm {
+
+bool DrmFactory::isCryptoSchemeSupported(const uint8_t uuid[16]) {
+    return isClearKeyUUID(uuid);
+}
+
+bool DrmFactory::isContentTypeSupported(const android::String8 &initDataType) {
+    // This should match the types handed by InitDataParser.
+    return initDataType == "cenc" ||
+           initDataType == "webm";
+}
+
+android::status_t DrmFactory::createDrmPlugin(
+        const uint8_t uuid[16], android::DrmPlugin** plugin) {
+    if (!isCryptoSchemeSupported(uuid)) {
+        *plugin = NULL;
+        return android::BAD_VALUE;
+    }
+
+    *plugin = new DrmPlugin(SessionLibrary::get());
+    return android::OK;
+}
+
+} // namespace clearkeydrm
diff --git a/drm/mediadrm/plugins/clearkey/DrmFactory.h b/drm/mediadrm/plugins/clearkey/DrmFactory.h
new file mode 100644
index 0000000..164d3d0
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/DrmFactory.h
@@ -0,0 +1,46 @@
+/*
+ * 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 CLEARKEY_DRM_FACTORY_H_
+#define CLEARKEY_DRM_FACTORY_H_
+
+#include <media/drm/DrmAPI.h>
+#include <media/stagefright/foundation/ABase.h>
+#include <utils/Errors.h>
+
+#include "Utils.h"
+
+namespace clearkeydrm {
+
+class DrmFactory : public android::DrmFactory {
+public:
+    DrmFactory() {}
+    virtual ~DrmFactory() {}
+
+    virtual bool isCryptoSchemeSupported(const uint8_t uuid[16]);
+
+    virtual bool isContentTypeSupported(const android::String8 &initDataType);
+
+    virtual android::status_t createDrmPlugin(
+            const uint8_t uuid[16], android::DrmPlugin** plugin);
+
+private:
+    DISALLOW_EVIL_CONSTRUCTORS(DrmFactory);
+};
+
+} // namespace clearkeydrm
+
+#endif // CLEARKEY_DRM_FACTORY_H_
diff --git a/drm/mediadrm/plugins/clearkey/DrmPlugin.cpp b/drm/mediadrm/plugins/clearkey/DrmPlugin.cpp
new file mode 100644
index 0000000..96fca94
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/DrmPlugin.cpp
@@ -0,0 +1,91 @@
+/*
+ * 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 "ClearKeyCryptoPlugin"
+#include <utils/Log.h>
+
+#include <media/stagefright/MediaErrors.h>
+#include <utils/StrongPointer.h>
+
+#include "DrmPlugin.h"
+
+#include "Session.h"
+
+namespace clearkeydrm {
+
+using android::sp;
+
+status_t DrmPlugin::openSession(Vector<uint8_t>& sessionId) {
+    sp<Session> session = mSessionLibrary->createSession();
+    sessionId = session->sessionId();
+    return android::OK;
+}
+
+status_t DrmPlugin::closeSession(const Vector<uint8_t>& sessionId) {
+    sp<Session> session = mSessionLibrary->findSession(sessionId);
+    mSessionLibrary->destroySession(session);
+    return android::OK;
+}
+
+status_t DrmPlugin::getKeyRequest(
+        const Vector<uint8_t>& scope,
+        const Vector<uint8_t>& initData,
+        const String8& initDataType,
+        KeyType keyType,
+        const KeyedVector<String8, String8>& optionalParameters,
+        Vector<uint8_t>& request,
+        String8& defaultUrl) {
+    UNUSED(optionalParameters);
+    if (keyType != kKeyType_Streaming) {
+        return android::ERROR_DRM_CANNOT_HANDLE;
+    }
+
+    sp<Session> session = mSessionLibrary->findSession(scope);
+    defaultUrl.clear();
+    return session->getKeyRequest(initData, initDataType, &request);
+}
+
+status_t DrmPlugin::provideKeyResponse(
+        const Vector<uint8_t>& scope,
+        const Vector<uint8_t>& response,
+        Vector<uint8_t>& keySetId) {
+    sp<Session> session = mSessionLibrary->findSession(scope);
+    status_t res = session->provideKeyResponse(response);
+    if (res == android::OK) {
+        keySetId.clear();
+    }
+    return res;
+}
+
+status_t DrmPlugin::getPropertyString(
+        const String8& name, String8& value) const {
+    if (name == "vendor") {
+        value = "Google";
+    } else if (name == "version") {
+        value = "1.0";
+    } else if (name == "description") {
+        value = "ClearKey CDM";
+    } else if (name == "algorithms") {
+        value = "";
+    } else {
+        ALOGE("App requested unknown string property %s", name.string());
+        return android::ERROR_DRM_CANNOT_HANDLE;
+    }
+    return android::OK;
+}
+
+}  // namespace clearkeydrm
diff --git a/drm/mediadrm/plugins/clearkey/DrmPlugin.h b/drm/mediadrm/plugins/clearkey/DrmPlugin.h
new file mode 100644
index 0000000..27df9cd
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/DrmPlugin.h
@@ -0,0 +1,234 @@
+/*
+ * 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 CLEARKEY_DRM_PLUGIN_H_
+#define CLEARKEY_DRM_PLUGIN_H_
+
+#include <media/drm/DrmAPI.h>
+#include <media/stagefright/foundation/ABase.h>
+#include <media/stagefright/MediaErrors.h>
+#include <utils/Errors.h>
+#include <utils/KeyedVector.h>
+#include <utils/List.h>
+#include <utils/String8.h>
+#include <utils/Vector.h>
+
+#include "SessionLibrary.h"
+#include "Utils.h"
+
+namespace clearkeydrm {
+
+using android::KeyedVector;
+using android::List;
+using android::status_t;
+using android::String8;
+using android::Vector;
+
+class DrmPlugin : public android::DrmPlugin {
+public:
+    DrmPlugin(SessionLibrary* sessionLibrary)
+            : mSessionLibrary(sessionLibrary) {}
+    virtual ~DrmPlugin() {}
+
+    virtual status_t openSession(Vector<uint8_t>& sessionId);
+
+    virtual status_t closeSession(const Vector<uint8_t>& sessionId);
+
+    virtual status_t getKeyRequest(
+            const Vector<uint8_t>& scope,
+            const Vector<uint8_t>& initData,
+            const String8& initDataType,
+            KeyType keyType,
+            const KeyedVector<String8, String8>& optionalParameters,
+            Vector<uint8_t>& request,
+            String8& defaultUrl);
+
+    virtual status_t provideKeyResponse(
+            const Vector<uint8_t>& scope,
+            const Vector<uint8_t>& response,
+            Vector<uint8_t>& keySetId);
+
+    virtual status_t removeKeys(const Vector<uint8_t>& sessionId) {
+        UNUSED(sessionId);
+        return android::ERROR_DRM_CANNOT_HANDLE;
+    }
+
+    virtual status_t restoreKeys(
+            const Vector<uint8_t>& sessionId,
+            const Vector<uint8_t>& keySetId) {
+        UNUSED(sessionId);
+        UNUSED(keySetId);
+        return android::ERROR_DRM_CANNOT_HANDLE;
+    }
+
+    virtual status_t queryKeyStatus(
+            const Vector<uint8_t>& sessionId,
+            KeyedVector<String8, String8>& infoMap) const {
+        UNUSED(sessionId);
+        UNUSED(infoMap);
+        return android::ERROR_DRM_CANNOT_HANDLE;
+    }
+
+    virtual status_t getProvisionRequest(
+            const String8& cert_type,
+            const String8& cert_authority,
+            Vector<uint8_t>& request,
+            String8& defaultUrl) {
+        UNUSED(cert_type);
+        UNUSED(cert_authority);
+        UNUSED(request);
+        UNUSED(defaultUrl);
+        return android::ERROR_DRM_CANNOT_HANDLE;
+    }
+
+    virtual status_t provideProvisionResponse(
+            const Vector<uint8_t>& response,
+            Vector<uint8_t>& certificate,
+            Vector<uint8_t>& wrappedKey) {
+        UNUSED(response);
+        UNUSED(certificate);
+        UNUSED(wrappedKey);
+        return android::ERROR_DRM_CANNOT_HANDLE;
+    }
+
+    virtual status_t unprovisionDevice() {
+        return android::ERROR_DRM_CANNOT_HANDLE;
+    }
+
+    virtual status_t getSecureStops(List<Vector<uint8_t> >& secureStops) {
+        UNUSED(secureStops);
+        return android::ERROR_DRM_CANNOT_HANDLE;
+    }
+
+    virtual status_t releaseSecureStops(const Vector<uint8_t>& ssRelease) {
+        UNUSED(ssRelease);
+        return android::ERROR_DRM_CANNOT_HANDLE;
+    }
+
+    virtual status_t getPropertyString(
+            const String8& name, String8& value) const;
+
+    virtual status_t getPropertyByteArray(
+            const String8& name, Vector<uint8_t>& value) const {
+        UNUSED(name);
+        UNUSED(value);
+        return android::ERROR_DRM_CANNOT_HANDLE;
+    }
+
+    virtual status_t setPropertyString(
+            const String8& name, const String8& value) {
+        UNUSED(name);
+        UNUSED(value);
+        return android::ERROR_DRM_CANNOT_HANDLE;
+    }
+
+    virtual status_t setPropertyByteArray(
+            const String8& name, const Vector<uint8_t>& value) {
+        UNUSED(name);
+        UNUSED(value);
+        return android::ERROR_DRM_CANNOT_HANDLE;
+    }
+
+    virtual status_t setCipherAlgorithm(
+            const Vector<uint8_t>& sessionId, const String8& algorithm) {
+        UNUSED(sessionId);
+        UNUSED(algorithm);
+        return android::ERROR_DRM_CANNOT_HANDLE;
+    }
+
+    virtual status_t setMacAlgorithm(
+            const Vector<uint8_t>& sessionId, const String8& algorithm) {
+        UNUSED(sessionId);
+        UNUSED(algorithm);
+        return android::ERROR_DRM_CANNOT_HANDLE;
+    }
+
+    virtual status_t encrypt(
+            const Vector<uint8_t>& sessionId,
+            const Vector<uint8_t>& keyId,
+            const Vector<uint8_t>& input,
+            const Vector<uint8_t>& iv,
+            Vector<uint8_t>& output) {
+        UNUSED(sessionId);
+        UNUSED(keyId);
+        UNUSED(input);
+        UNUSED(iv);
+        UNUSED(output);
+        return android::ERROR_DRM_CANNOT_HANDLE;
+    }
+
+    virtual status_t decrypt(
+            const Vector<uint8_t>& sessionId,
+            const Vector<uint8_t>& keyId,
+            const Vector<uint8_t>& input,
+            const Vector<uint8_t>& iv,
+            Vector<uint8_t>& output) {
+        UNUSED(sessionId);
+        UNUSED(keyId);
+        UNUSED(input);
+        UNUSED(iv);
+        UNUSED(output);
+        return android::ERROR_DRM_CANNOT_HANDLE;
+    }
+
+    virtual status_t sign(
+            const Vector<uint8_t>& sessionId,
+            const Vector<uint8_t>& keyId,
+            const Vector<uint8_t>& message,
+            Vector<uint8_t>& signature) {
+        UNUSED(sessionId);
+        UNUSED(keyId);
+        UNUSED(message);
+        UNUSED(signature);
+        return android::ERROR_DRM_CANNOT_HANDLE;
+    }
+
+    virtual status_t verify(
+            const Vector<uint8_t>& sessionId,
+            const Vector<uint8_t>& keyId,
+            const Vector<uint8_t>& message,
+            const Vector<uint8_t>& signature, bool& match) {
+        UNUSED(sessionId);
+        UNUSED(keyId);
+        UNUSED(message);
+        UNUSED(signature);
+        UNUSED(match);
+        return android::ERROR_DRM_CANNOT_HANDLE;
+    }
+
+    virtual status_t signRSA(
+            const Vector<uint8_t>& sessionId,
+            const String8& algorithm,
+            const Vector<uint8_t>& message,
+            const Vector<uint8_t>& wrappedKey,
+            Vector<uint8_t>& signature) {
+        UNUSED(sessionId);
+        UNUSED(algorithm);
+        UNUSED(message);
+        UNUSED(wrappedKey);
+        UNUSED(signature);
+        return android::ERROR_DRM_CANNOT_HANDLE;
+    }
+
+private:
+    DISALLOW_EVIL_CONSTRUCTORS(DrmPlugin);
+
+    SessionLibrary* mSessionLibrary;
+};
+
+} // namespace clearkeydrm
+
+#endif // CLEARKEY_DRM_PLUGIN_H_
diff --git a/drm/mediadrm/plugins/clearkey/InitDataParser.cpp b/drm/mediadrm/plugins/clearkey/InitDataParser.cpp
new file mode 100644
index 0000000..c22d73a
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/InitDataParser.cpp
@@ -0,0 +1,147 @@
+/*
+ * 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 "ClearKeyCryptoPlugin"
+#include <utils/Log.h>
+
+#include <endian.h>
+#include <media/stagefright/foundation/AString.h>
+#include <media/stagefright/foundation/base64.h>
+#include <media/stagefright/MediaErrors.h>
+#include <string.h>
+
+#include "InitDataParser.h"
+
+#include "ClearKeyUUID.h"
+#include "Utils.h"
+
+namespace clearkeydrm {
+
+using android::AString;
+using android::String8;
+using android::Vector;
+
+namespace {
+    const size_t kKeyIdSize = 16;
+    const size_t kSystemIdSize = 16;
+}
+
+android::status_t InitDataParser::parse(const Vector<uint8_t>& initData,
+        const String8& initDataType,
+        Vector<uint8_t>* licenseRequest) {
+    // Build a list of the key IDs
+    Vector<const uint8_t*> keyIds;
+    if (initDataType == "cenc") {
+        android::status_t res = parsePssh(initData, &keyIds);
+        if (res != android::OK) {
+            return res;
+        }
+    } else if (initDataType == "webm") {
+        // WebM "init data" is just a single key ID
+        if (initData.size() != kKeyIdSize) {
+            return android::ERROR_DRM_CANNOT_HANDLE;
+        }
+        keyIds.push(initData.array());
+    } else {
+        return android::ERROR_DRM_CANNOT_HANDLE;
+    }
+
+    // Build the request
+    String8 requestJson = generateRequest(keyIds);
+    licenseRequest->clear();
+    licenseRequest->appendArray(
+            reinterpret_cast<const uint8_t*>(requestJson.string()),
+            requestJson.size());
+    return android::OK;
+}
+
+android::status_t InitDataParser::parsePssh(const Vector<uint8_t>& initData,
+        Vector<const uint8_t*>* keyIds) {
+    size_t readPosition = 0;
+
+    // Validate size field
+    uint32_t expectedSize = initData.size();
+    expectedSize = htonl(expectedSize);
+    if (memcmp(&initData[readPosition], &expectedSize,
+               sizeof(expectedSize)) != 0) {
+        return android::ERROR_DRM_CANNOT_HANDLE;
+    }
+    readPosition += sizeof(expectedSize);
+
+    // Validate PSSH box identifier
+    const char psshIdentifier[4] = {'p', 's', 's', 'h'};
+    if (memcmp(&initData[readPosition], psshIdentifier,
+               sizeof(psshIdentifier)) != 0) {
+        return android::ERROR_DRM_CANNOT_HANDLE;
+    }
+    readPosition += sizeof(psshIdentifier);
+
+    // Validate EME version number
+    const uint8_t psshVersion1[4] = {1, 0, 0, 0};
+    if (memcmp(&initData[readPosition], psshVersion1,
+               sizeof(psshVersion1)) != 0) {
+        return android::ERROR_DRM_CANNOT_HANDLE;
+    }
+    readPosition += sizeof(psshVersion1);
+
+    // Validate system ID
+    if (!isClearKeyUUID(&initData[readPosition])) {
+        return android::ERROR_DRM_CANNOT_HANDLE;
+    }
+    readPosition += kSystemIdSize;
+
+    // Read key ID count
+    uint32_t keyIdCount;
+    memcpy(&keyIdCount, &initData[readPosition], sizeof(keyIdCount));
+    keyIdCount = ntohl(keyIdCount);
+    readPosition += sizeof(keyIdCount);
+    if (readPosition + (keyIdCount * kKeyIdSize) !=
+            initData.size() - sizeof(uint32_t)) {
+        return android::ERROR_DRM_CANNOT_HANDLE;
+    }
+
+    // Calculate the key ID offsets
+    for (uint32_t i = 0; i < keyIdCount; ++i) {
+        size_t keyIdPosition = readPosition + (i * kKeyIdSize);
+        keyIds->push(&initData[keyIdPosition]);
+    }
+    return android::OK;
+}
+
+String8 InitDataParser::generateRequest(const Vector<const uint8_t*>& keyIds) {
+    const String8 kRequestPrefix("{\"kids\":[");
+    const String8 kRequestSuffix("],\"type\":\"temporary\"}");
+    const String8 kBase64Padding("=");
+
+    String8 request(kRequestPrefix);
+    AString encodedId;
+    for (size_t i = 0; i < keyIds.size(); ++i) {
+        encodedId.clear();
+        android::encodeBase64(keyIds[i], kKeyIdSize, &encodedId);
+        if (i != 0) {
+            request.append(",");
+        }
+        request.appendFormat("\"%s\"", encodedId.c_str());
+    }
+    request.append(kRequestSuffix);
+
+    // Android's Base64 encoder produces padding. EME forbids padding.
+    request.removeAll(kBase64Padding);
+    return request;
+}
+
+} // namespace clearkeydrm
diff --git a/drm/mediadrm/plugins/clearkey/InitDataParser.h b/drm/mediadrm/plugins/clearkey/InitDataParser.h
new file mode 100644
index 0000000..9505d2a
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/InitDataParser.h
@@ -0,0 +1,47 @@
+/*
+ * 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 CLEARKEY_INIT_DATA_PARSER_H_
+#define CLEARKEY_INIT_DATA_PARSER_H_
+
+#include <media/stagefright/foundation/ABase.h>
+#include <utils/Errors.h>
+#include <utils/String8.h>
+#include <utils/Vector.h>
+
+namespace clearkeydrm {
+
+class InitDataParser {
+public:
+    InitDataParser() {}
+
+    android::status_t parse(const android::Vector<uint8_t>& initData,
+            const android::String8& initDataType,
+            android::Vector<uint8_t>* licenseRequest);
+
+private:
+    DISALLOW_EVIL_CONSTRUCTORS(InitDataParser);
+
+    android::status_t parsePssh(const android::Vector<uint8_t>& initData,
+            android::Vector<const uint8_t*>* keyIds);
+
+    android::String8 generateRequest(
+            const android::Vector<const uint8_t*>& keyIds);
+};
+
+} // namespace clearkeydrm
+
+#endif // CLEARKEY_INIT_DATA_PARSER_H_
diff --git a/drm/mediadrm/plugins/clearkey/JsonWebKey.cpp b/drm/mediadrm/plugins/clearkey/JsonWebKey.cpp
new file mode 100644
index 0000000..53ffae4
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/JsonWebKey.cpp
@@ -0,0 +1,269 @@
+/*
+ * 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 "JsonWebKey"
+
+#include <media/stagefright/foundation/ABuffer.h>
+#include <media/stagefright/foundation/AString.h>
+#include <media/stagefright/foundation/base64.h>
+#include <utils/Log.h>
+
+#include "JsonWebKey.h"
+
+namespace {
+const android::String8 kKeysTag("keys");
+const android::String8 kKeyTypeTag("kty");
+const android::String8 kSymmetricKeyValue("oct");
+const android::String8 kKeyTag("k");
+const android::String8 kKeyIdTag("kid");
+const android::String8 kBase64Padding("=");
+}
+
+namespace clearkeydrm {
+
+using android::ABuffer;
+using android::AString;
+
+JsonWebKey::JsonWebKey() {
+}
+
+JsonWebKey::~JsonWebKey() {
+}
+
+/*
+ * Parses a JSON Web Key Set string, initializes a KeyMap with key id:key
+ * pairs from the JSON Web Key Set. Both key ids and keys are base64url
+ * encoded. The KeyMap contains base64url decoded key id:key pairs.
+ *
+ * @return Returns false for errors, true for success.
+ */
+bool JsonWebKey::extractKeysFromJsonWebKeySet(const String8& jsonWebKeySet,
+        KeyMap* keys) {
+
+    keys->clear();
+    if (!parseJsonWebKeySet(jsonWebKeySet, &mJsonObjects)) {
+        return false;
+    }
+
+    // mJsonObjects[0] contains the entire JSON Web Key Set, including
+    // all the base64 encoded keys. Each key is also stored separately as
+    // a JSON object in mJsonObjects[1..n] where n is the total
+    // number of keys in the set.
+    if (!isJsonWebKeySet(mJsonObjects[0])) {
+        return false;
+    }
+
+    String8 encodedKey, encodedKeyId;
+    Vector<uint8_t> decodedKey, decodedKeyId;
+
+    // mJsonObjects[1] contains the first JSON Web Key in the set
+    for (size_t i = 1; i < mJsonObjects.size(); ++i) {
+        encodedKeyId.clear();
+        encodedKey.clear();
+
+        if (!parseJsonObject(mJsonObjects[i], &mTokens))
+            return false;
+
+        if (findKey(mJsonObjects[i], &encodedKeyId, &encodedKey)) {
+            if (encodedKeyId.isEmpty() || encodedKey.isEmpty()) {
+                ALOGE("Must have both key id and key in the JsonWebKey set.");
+                continue;
+            }
+
+            if (!decodeBase64String(encodedKeyId, &decodedKeyId)) {
+                ALOGE("Failed to decode key id(%s)", encodedKeyId.string());
+                continue;
+            }
+
+            if (!decodeBase64String(encodedKey, &decodedKey)) {
+                ALOGE("Failed to decode key(%s)", encodedKey.string());
+                continue;
+            }
+
+            keys->add(decodedKeyId, decodedKey);
+        }
+    }
+    return true;
+}
+
+bool JsonWebKey::decodeBase64String(const String8& encodedText,
+        Vector<uint8_t>* decodedText) {
+
+    decodedText->clear();
+
+    // encodedText should not contain padding characters as per EME spec.
+    if (encodedText.find(kBase64Padding) != -1) {
+        return false;
+    }
+
+    // Since android::decodeBase64() requires padding characters,
+    // add them so length of encodedText is exactly a multiple of 4.
+    int remainder = encodedText.length() % 4;
+    String8 paddedText(encodedText);
+    if (remainder > 0) {
+        for (int i = 0; i < 4 - remainder; ++i) {
+            paddedText.append(kBase64Padding);
+        }
+    }
+
+    android::sp<ABuffer> buffer =
+            android::decodeBase64(AString(paddedText.string()));
+    if (buffer == NULL) {
+        ALOGE("Malformed base64 encoded content found.");
+        return false;
+    }
+
+    decodedText->appendArray(buffer->base(), buffer->size());
+    return true;
+}
+
+bool JsonWebKey::findKey(const String8& jsonObject, String8* keyId,
+        String8* encodedKey) {
+
+    String8 key, value;
+
+    // Only allow symmetric key, i.e. "kty":"oct" pair.
+    if (jsonObject.find(kKeyTypeTag) >= 0) {
+        findValue(kKeyTypeTag, &value);
+        if (0 != value.compare(kSymmetricKeyValue))
+            return false;
+    }
+
+    if (jsonObject.find(kKeyIdTag) >= 0) {
+        findValue(kKeyIdTag, keyId);
+    }
+
+    if (jsonObject.find(kKeyTag) >= 0) {
+        findValue(kKeyTag, encodedKey);
+    }
+    return true;
+}
+
+void JsonWebKey::findValue(const String8 &key, String8* value) {
+    value->clear();
+    const char* valueToken;
+    for (Vector<String8>::const_iterator nextToken = mTokens.begin();
+        nextToken != mTokens.end(); ++nextToken) {
+        if (0 == (*nextToken).compare(key)) {
+            if (nextToken + 1 == mTokens.end())
+                break;
+            valueToken = (*(nextToken + 1)).string();
+            value->setTo(valueToken);
+            nextToken++;
+            break;
+        }
+    }
+}
+
+bool JsonWebKey::isJsonWebKeySet(const String8& jsonObject) const {
+    if (jsonObject.find(kKeysTag) == -1) {
+        ALOGE("JSON Web Key does not contain keys.");
+        return false;
+    }
+    return true;
+}
+
+/*
+ * Parses a JSON objects string and initializes a vector of tokens.
+ *
+ * @return Returns false for errors, true for success.
+ */
+bool JsonWebKey::parseJsonObject(const String8& jsonObject,
+        Vector<String8>* tokens) {
+    jsmn_parser parser;
+
+    jsmn_init(&parser);
+    int numTokens = jsmn_parse(&parser,
+        jsonObject.string(), jsonObject.size(), NULL, 0);
+    if (numTokens < 0) {
+        ALOGE("Parser returns error code=%d", numTokens);
+        return false;
+    }
+
+    unsigned int jsmnTokensSize = numTokens * sizeof(jsmntok_t);
+    mJsmnTokens.clear();
+    mJsmnTokens.setCapacity(jsmnTokensSize);
+
+    jsmn_init(&parser);
+    int status = jsmn_parse(&parser, jsonObject.string(),
+        jsonObject.size(), mJsmnTokens.editArray(), numTokens);
+    if (status < 0) {
+        ALOGE("Parser returns error code=%d", status);
+        return false;
+    }
+
+    tokens->clear();
+    String8 token;
+    const char *pjs;
+    for (int j = 0; j < numTokens; ++j) {
+        pjs = jsonObject.string() + mJsmnTokens[j].start;
+        if (mJsmnTokens[j].type == JSMN_STRING ||
+                mJsmnTokens[j].type == JSMN_PRIMITIVE) {
+            token.setTo(pjs, mJsmnTokens[j].end - mJsmnTokens[j].start);
+            tokens->add(token);
+        }
+    }
+    return true;
+}
+
+/*
+ * Parses JSON Web Key Set string and initializes a vector of JSON objects.
+ *
+ * @return Returns false for errors, true for success.
+ */
+bool JsonWebKey::parseJsonWebKeySet(const String8& jsonWebKeySet,
+        Vector<String8>* jsonObjects) {
+    if (jsonWebKeySet.isEmpty()) {
+        ALOGE("Empty JSON Web Key");
+        return false;
+    }
+
+    // The jsmn parser only supports unicode encoding.
+    jsmn_parser parser;
+
+    // Computes number of tokens. A token marks the type, offset in
+    // the original string.
+    jsmn_init(&parser);
+    int numTokens = jsmn_parse(&parser,
+            jsonWebKeySet.string(), jsonWebKeySet.size(), NULL, 0);
+    if (numTokens < 0) {
+        ALOGE("Parser returns error code=%d", numTokens);
+        return false;
+    }
+
+    unsigned int jsmnTokensSize = numTokens * sizeof(jsmntok_t);
+    mJsmnTokens.setCapacity(jsmnTokensSize);
+
+    jsmn_init(&parser);
+    int status = jsmn_parse(&parser, jsonWebKeySet.string(),
+            jsonWebKeySet.size(), mJsmnTokens.editArray(), numTokens);
+    if (status < 0) {
+        ALOGE("Parser returns error code=%d", status);
+        return false;
+    }
+
+    String8 token;
+    const char *pjs;
+    for (int i = 0; i < numTokens; ++i) {
+        pjs = jsonWebKeySet.string() + mJsmnTokens[i].start;
+        if (mJsmnTokens[i].type == JSMN_OBJECT) {
+            token.setTo(pjs, mJsmnTokens[i].end - mJsmnTokens[i].start);
+            jsonObjects->add(token);
+        }
+    }
+    return true;
+}
+
+}  // clearkeydrm
diff --git a/drm/mediadrm/plugins/clearkey/JsonWebKey.h b/drm/mediadrm/plugins/clearkey/JsonWebKey.h
new file mode 100644
index 0000000..6ae50ee
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/JsonWebKey.h
@@ -0,0 +1,62 @@
+/*
+ * 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 CLEARKEY_JSON_WEB_KEY_H_
+#define CLEARKEY_JSON_WEB_KEY_H_
+
+#include <media/stagefright/foundation/ABase.h>
+#include <utils/KeyedVector.h>
+#include <utils/String8.h>
+#include <utils/StrongPointer.h>
+
+#include "jsmn.h"
+#include "Utils.h"
+#include "ClearKeyTypes.h"
+
+namespace clearkeydrm {
+
+using android::KeyedVector;
+using android::sp;
+using android::String8;
+using android::Vector;
+
+class JsonWebKey {
+ public:
+    JsonWebKey();
+    virtual ~JsonWebKey();
+
+    bool extractKeysFromJsonWebKeySet(const String8& jsonWebKeySet,
+            KeyMap* keys);
+
+ private:
+    Vector<jsmntok_t> mJsmnTokens;
+    Vector<String8> mJsonObjects;
+    Vector<String8> mTokens;
+
+    bool decodeBase64String(const String8& encodedText,
+            Vector<uint8_t>* decodedText);
+    bool findKey(const String8& jsonObject, String8* keyId,
+            String8* encodedKey);
+    void findValue(const String8 &key, String8* value);
+    bool isJsonWebKeySet(const String8& jsonObject) const;
+    bool parseJsonObject(const String8& jsonObject, Vector<String8>* tokens);
+    bool parseJsonWebKeySet(const String8& jsonWebKeySet, Vector<String8>* jsonObjects);
+
+    DISALLOW_EVIL_CONSTRUCTORS(JsonWebKey);
+};
+
+}  // namespace clearkeydrm
+
+#endif  // CLEARKEY_JSON_WEB_KEY_H_
diff --git a/drm/mediadrm/plugins/clearkey/Session.cpp b/drm/mediadrm/plugins/clearkey/Session.cpp
new file mode 100644
index 0000000..95016f5
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/Session.cpp
@@ -0,0 +1,85 @@
+/*
+ * 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 "ClearKeyCryptoPlugin"
+#include <utils/Log.h>
+
+#include <media/stagefright/MediaErrors.h>
+#include <utils/String8.h>
+
+#include "Session.h"
+
+#include "AesCtrDecryptor.h"
+#include "InitDataParser.h"
+#include "JsonWebKey.h"
+
+namespace clearkeydrm {
+
+using android::Mutex;
+using android::String8;
+using android::Vector;
+using android::status_t;
+
+status_t Session::getKeyRequest(
+        const Vector<uint8_t>& initData,
+        const String8& initDataType,
+        Vector<uint8_t>* keyRequest) const {
+    InitDataParser parser;
+    return parser.parse(initData, initDataType, keyRequest);
+}
+
+status_t Session::provideKeyResponse(const Vector<uint8_t>& response) {
+    String8 responseString(
+            reinterpret_cast<const char*>(response.array()), response.size());
+    KeyMap keys;
+
+    Mutex::Autolock lock(mMapLock);
+    JsonWebKey parser;
+    if (parser.extractKeysFromJsonWebKeySet(responseString, &keys)) {
+        for (size_t i = 0; i < keys.size(); ++i) {
+            const KeyMap::key_type& keyId = keys.keyAt(i);
+            const KeyMap::value_type& key = keys.valueAt(i);
+            mKeyMap.add(keyId, key);
+        }
+        return android::OK;
+    } else {
+        return android::ERROR_DRM_UNKNOWN;
+    }
+}
+
+status_t Session::decrypt(
+        const KeyId keyId, const Iv iv, const void* source,
+        void* destination, const SubSample* subSamples,
+        size_t numSubSamples, size_t* bytesDecryptedOut) {
+    Mutex::Autolock lock(mMapLock);
+
+    Vector<uint8_t> keyIdVector;
+    keyIdVector.appendArray(keyId, kBlockSize);
+    if (mKeyMap.indexOfKey(keyIdVector) < 0) {
+        return android::ERROR_DRM_NO_LICENSE;
+    }
+
+    const Vector<uint8_t>& key = mKeyMap.valueFor(keyIdVector);
+    AesCtrDecryptor decryptor;
+    return decryptor.decrypt(
+            key, iv,
+            reinterpret_cast<const uint8_t*>(source),
+            reinterpret_cast<uint8_t*>(destination), subSamples,
+            numSubSamples, bytesDecryptedOut);
+}
+
+} // namespace clearkeydrm
diff --git a/drm/mediadrm/plugins/clearkey/Session.h b/drm/mediadrm/plugins/clearkey/Session.h
new file mode 100644
index 0000000..cab0dc3
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/Session.h
@@ -0,0 +1,64 @@
+/*
+ * 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 CLEARKEY_SESSION_H_
+#define CLEARKEY_SESSION_H_
+
+#include <media/stagefright/foundation/ABase.h>
+#include <utils/Errors.h>
+#include <utils/Mutex.h>
+#include <utils/RefBase.h>
+#include <utils/String8.h>
+#include <utils/Vector.h>
+
+#include "ClearKeyTypes.h"
+#include "Utils.h"
+
+namespace clearkeydrm {
+
+class Session : public android::RefBase {
+public:
+    explicit Session(const android::Vector<uint8_t>& sessionId)
+            : mSessionId(sessionId) {}
+    virtual ~Session() {}
+
+    const android::Vector<uint8_t>& sessionId() const { return mSessionId; }
+
+    android::status_t getKeyRequest(
+            const android::Vector<uint8_t>& initData,
+            const android::String8& initDataType,
+            android::Vector<uint8_t>* keyRequest) const;
+
+    android::status_t provideKeyResponse(
+            const android::Vector<uint8_t>& response);
+
+    android::status_t decrypt(
+            const KeyId keyId, const Iv iv, const void* source,
+            void* destination, const SubSample* subSamples,
+            size_t numSubSamples, size_t* bytesDecryptedOut);
+
+private:
+    DISALLOW_EVIL_CONSTRUCTORS(Session);
+
+    const android::Vector<uint8_t> mSessionId;
+
+    android::Mutex mMapLock;
+    KeyMap mKeyMap;
+};
+
+} // namespace clearkeydrm
+
+#endif // CLEARKEY_SESSION_H_
diff --git a/drm/mediadrm/plugins/clearkey/SessionLibrary.cpp b/drm/mediadrm/plugins/clearkey/SessionLibrary.cpp
new file mode 100644
index 0000000..d047c53
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/SessionLibrary.cpp
@@ -0,0 +1,78 @@
+/*
+ * 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 "ClearKeyCryptoPlugin"
+#include <utils/Log.h>
+
+#include <utils/String8.h>
+
+#include "SessionLibrary.h"
+
+namespace clearkeydrm {
+
+using android::Mutex;
+using android::sp;
+using android::String8;
+using android::Vector;
+
+Mutex SessionLibrary::sSingletonLock;
+SessionLibrary* SessionLibrary::sSingleton = NULL;
+
+SessionLibrary* SessionLibrary::get() {
+    Mutex::Autolock lock(sSingletonLock);
+
+    if (sSingleton == NULL) {
+        ALOGD("Instantiating Session Library Singleton.");
+        sSingleton = new SessionLibrary();
+    }
+
+    return sSingleton;
+}
+
+const sp<Session>& SessionLibrary::createSession() {
+    Mutex::Autolock lock(mSessionsLock);
+
+    String8 sessionIdString = String8::format("%u", mNextSessionId);
+    mNextSessionId += 1;
+    Vector<uint8_t> sessionId;
+    sessionId.appendArray(
+            reinterpret_cast<const uint8_t*>(sessionIdString.string()),
+            sessionIdString.size());
+
+    mSessions.add(sessionId, new Session(sessionId));
+    return mSessions.valueFor(sessionId);
+}
+
+const sp<Session>& SessionLibrary::findSession(
+        const Vector<uint8_t>& sessionId) {
+    Mutex::Autolock lock(mSessionsLock);
+    return mSessions.valueFor(sessionId);
+}
+
+const sp<Session>& SessionLibrary::findSession(
+        const void* data, size_t size) {
+    Vector<uint8_t> sessionId;
+    sessionId.appendArray(reinterpret_cast<const uint8_t*>(data), size);
+    return findSession(sessionId);
+}
+
+void SessionLibrary::destroySession(const sp<Session>& session) {
+    Mutex::Autolock lock(mSessionsLock);\
+    mSessions.removeItem(session->sessionId());
+}
+
+} // namespace clearkeydrm
diff --git a/drm/mediadrm/plugins/clearkey/SessionLibrary.h b/drm/mediadrm/plugins/clearkey/SessionLibrary.h
new file mode 100644
index 0000000..56c8828
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/SessionLibrary.h
@@ -0,0 +1,59 @@
+/*
+ * 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 CLEARKEY_SESSION_LIBRARY_H_
+#define CLEARKEY_SESSION_LIBRARY_H_
+
+#include <utils/KeyedVector.h>
+#include <utils/Mutex.h>
+#include <utils/StrongPointer.h>
+#include <utils/Vector.h>
+
+#include "Session.h"
+#include "Utils.h"
+
+namespace clearkeydrm {
+
+class SessionLibrary {
+public:
+    static SessionLibrary* get();
+
+    const android::sp<Session>& createSession();
+
+    const android::sp<Session>& findSession(
+            const android::Vector<uint8_t>& sessionId);
+
+    const android::sp<Session>& findSession(const void* data, size_t size);
+
+    void destroySession(const android::sp<Session>& session);
+
+private:
+    DISALLOW_EVIL_CONSTRUCTORS(SessionLibrary);
+
+    SessionLibrary() : mNextSessionId(1) {}
+
+    static android::Mutex sSingletonLock;
+    static SessionLibrary* sSingleton;
+
+    android::Mutex mSessionsLock;
+    uint32_t mNextSessionId;
+    android::KeyedVector<android::Vector<uint8_t>, android::sp<Session> >
+            mSessions;
+};
+
+} // namespace clearkeydrm
+
+#endif // CLEARKEY_SESSION_LIBRARY_H_
diff --git a/drm/mediadrm/plugins/clearkey/Utils.cpp b/drm/mediadrm/plugins/clearkey/Utils.cpp
new file mode 100644
index 0000000..93c643b
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/Utils.cpp
@@ -0,0 +1,30 @@
+/*
+ * 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.
+ */
+
+#include "Utils.h"
+
+namespace android {
+
+bool operator<(const Vector<uint8_t> &lhs, const Vector<uint8_t> &rhs) {
+    if (lhs.size() < rhs.size()) {
+        return true;
+    } else if (lhs.size() > rhs.size()) {
+        return false;
+    }
+    return memcmp((void *)lhs.array(), (void *)rhs.array(), rhs.size()) < 0;
+}
+
+} // namespace android
diff --git a/drm/mediadrm/plugins/clearkey/Utils.h b/drm/mediadrm/plugins/clearkey/Utils.h
new file mode 100644
index 0000000..2543124
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/Utils.h
@@ -0,0 +1,32 @@
+/*
+ * 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 CLEARKEY_UTILS_H_
+#define CLEARKEY_UTILS_H_
+
+#include <utils/Vector.h>
+
+// Add a comparison operator for this Vector specialization so that it can be
+// used as a key in a KeyedVector.
+namespace android {
+
+bool operator<(const Vector<uint8_t> &lhs, const Vector<uint8_t> &rhs);
+
+} // namespace android
+
+#define UNUSED(x) (void)(x);
+
+#endif // CLEARKEY_UTILS_H_
diff --git a/drm/mediadrm/plugins/clearkey/tests/AesCtrDecryptorUnittest.cpp b/drm/mediadrm/plugins/clearkey/tests/AesCtrDecryptorUnittest.cpp
new file mode 100644
index 0000000..039e402
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/tests/AesCtrDecryptorUnittest.cpp
@@ -0,0 +1,421 @@
+/*
+ * 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.
+ */
+
+#include <gtest/gtest.h>
+#include <string.h>
+
+#include <utils/String8.h>
+#include <utils/Vector.h>
+
+#include "AesCtrDecryptor.h"
+
+namespace clearkeydrm {
+
+using namespace android;
+
+class AesCtrDecryptorTest : public ::testing::Test {
+  protected:
+    typedef uint8_t Key[kBlockSize];
+
+    status_t attemptDecrypt(const Key& key, const Iv& iv, const uint8_t* source,
+                            uint8_t* destination, const SubSample* subSamples,
+                            size_t numSubSamples, size_t* bytesDecryptedOut) {
+        Vector<uint8_t> keyVector;
+        keyVector.appendArray(key, kBlockSize);
+
+        AesCtrDecryptor decryptor;
+        return decryptor.decrypt(keyVector, iv, source, destination, subSamples,
+                                 numSubSamples, bytesDecryptedOut);
+    }
+
+    template <size_t totalSize>
+    void attemptDecryptExpectingSuccess(const Key& key, const Iv& iv,
+                                        const uint8_t* encrypted,
+                                        const uint8_t* decrypted,
+                                        const SubSample* subSamples,
+                                        size_t numSubSamples) {
+        uint8_t outputBuffer[totalSize] = {};
+        size_t bytesDecrypted = 0;
+        ASSERT_EQ(android::OK, attemptDecrypt(key, iv, encrypted, outputBuffer,
+                                              subSamples, numSubSamples,
+                                              &bytesDecrypted));
+        EXPECT_EQ(totalSize, bytesDecrypted);
+        EXPECT_EQ(0, memcmp(outputBuffer, decrypted, totalSize));
+    }
+};
+
+TEST_F(AesCtrDecryptorTest, DecryptsContiguousEncryptedBlock) {
+    const size_t kTotalSize = 64;
+    const size_t kNumSubsamples = 1;
+
+    // Test vectors from NIST-800-38A
+    Key key = {
+        0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
+        0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c
+    };
+
+    Iv iv = {
+        0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
+        0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
+    };
+
+    uint8_t encrypted[kTotalSize] = {
+        0x87, 0x4d, 0x61, 0x91, 0xb6, 0x20, 0xe3, 0x26,
+        0x1b, 0xef, 0x68, 0x64, 0x99, 0x0d, 0xb6, 0xce,
+        0x98, 0x06, 0xf6, 0x6b, 0x79, 0x70, 0xfd, 0xff,
+        0x86, 0x17, 0x18, 0x7b, 0xb9, 0xff, 0xfd, 0xff,
+        0x5a, 0xe4, 0xdf, 0x3e, 0xdb, 0xd5, 0xd3, 0x5e,
+        0x5b, 0x4f, 0x09, 0x02, 0x0d, 0xb0, 0x3e, 0xab,
+        0x1e, 0x03, 0x1d, 0xda, 0x2f, 0xbe, 0x03, 0xd1,
+        0x79, 0x21, 0x70, 0xa0, 0xf3, 0x00, 0x9c, 0xee
+    };
+
+    uint8_t decrypted[kTotalSize] = {
+        0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,
+        0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
+        0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c,
+        0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
+        0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11,
+        0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef,
+        0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17,
+        0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10
+    };
+
+    SubSample subSamples[kNumSubsamples] = {
+        {0, 64}
+    };
+
+    attemptDecryptExpectingSuccess<kTotalSize>(key, iv, encrypted, decrypted,
+                                               subSamples, kNumSubsamples);
+}
+
+TEST_F(AesCtrDecryptorTest, DecryptsAlignedBifurcatedEncryptedBlock) {
+    const size_t kTotalSize = 64;
+    const size_t kNumSubsamples = 2;
+
+    // Test vectors from NIST-800-38A
+    Key key = {
+        0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
+        0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c
+    };
+
+    Iv iv = {
+        0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
+        0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
+    };
+
+    uint8_t encrypted[kTotalSize] = {
+        0x87, 0x4d, 0x61, 0x91, 0xb6, 0x20, 0xe3, 0x26,
+        0x1b, 0xef, 0x68, 0x64, 0x99, 0x0d, 0xb6, 0xce,
+        0x98, 0x06, 0xf6, 0x6b, 0x79, 0x70, 0xfd, 0xff,
+        0x86, 0x17, 0x18, 0x7b, 0xb9, 0xff, 0xfd, 0xff,
+        0x5a, 0xe4, 0xdf, 0x3e, 0xdb, 0xd5, 0xd3, 0x5e,
+        0x5b, 0x4f, 0x09, 0x02, 0x0d, 0xb0, 0x3e, 0xab,
+        0x1e, 0x03, 0x1d, 0xda, 0x2f, 0xbe, 0x03, 0xd1,
+        0x79, 0x21, 0x70, 0xa0, 0xf3, 0x00, 0x9c, 0xee
+    };
+
+    uint8_t decrypted[kTotalSize] = {
+        0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,
+        0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
+        0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c,
+        0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
+        0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11,
+        0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef,
+        0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17,
+        0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10
+    };
+
+    SubSample subSamples[kNumSubsamples] = {
+        {0, 32},
+        {0, 32}
+    };
+
+    attemptDecryptExpectingSuccess<kTotalSize>(key, iv, encrypted, decrypted,
+                                               subSamples, kNumSubsamples);
+}
+
+TEST_F(AesCtrDecryptorTest, DecryptsUnalignedBifurcatedEncryptedBlock) {
+    const size_t kTotalSize = 64;
+    const size_t kNumSubsamples = 2;
+
+    // Test vectors from NIST-800-38A
+    Key key = {
+        0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
+        0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c
+    };
+
+    Iv iv = {
+        0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
+        0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
+    };
+
+    uint8_t encrypted[kTotalSize] = {
+        0x87, 0x4d, 0x61, 0x91, 0xb6, 0x20, 0xe3, 0x26,
+        0x1b, 0xef, 0x68, 0x64, 0x99, 0x0d, 0xb6, 0xce,
+        0x98, 0x06, 0xf6, 0x6b, 0x79, 0x70, 0xfd, 0xff,
+        0x86, 0x17, 0x18, 0x7b, 0xb9, 0xff, 0xfd, 0xff,
+        0x5a, 0xe4, 0xdf, 0x3e, 0xdb, 0xd5, 0xd3, 0x5e,
+        0x5b, 0x4f, 0x09, 0x02, 0x0d, 0xb0, 0x3e, 0xab,
+        0x1e, 0x03, 0x1d, 0xda, 0x2f, 0xbe, 0x03, 0xd1,
+        0x79, 0x21, 0x70, 0xa0, 0xf3, 0x00, 0x9c, 0xee
+    };
+
+    uint8_t decrypted[kTotalSize] = {
+        0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,
+        0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
+        0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c,
+        0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
+        0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11,
+        0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef,
+        0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17,
+        0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10
+    };
+
+    SubSample subSamples[kNumSubsamples] = {
+        {0, 29},
+        {0, 35}
+    };
+
+    attemptDecryptExpectingSuccess<kTotalSize>(key, iv, encrypted, decrypted,
+                                               subSamples, kNumSubsamples);
+}
+
+TEST_F(AesCtrDecryptorTest, DecryptsOneMixedSubSample) {
+    const size_t kTotalSize = 72;
+    const size_t kNumSubsamples = 1;
+
+    // Based on test vectors from NIST-800-38A
+    Key key = {
+        0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
+        0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c
+    };
+
+    Iv iv = {
+        0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
+        0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
+    };
+
+    uint8_t encrypted[kTotalSize] = {
+        // 8 clear bytes
+        0xf0, 0x13, 0xca, 0xc7, 0x00, 0x64, 0x0b, 0xbb,
+        // 64 encrypted bytes
+        0x87, 0x4d, 0x61, 0x91, 0xb6, 0x20, 0xe3, 0x26,
+        0x1b, 0xef, 0x68, 0x64, 0x99, 0x0d, 0xb6, 0xce,
+        0x98, 0x06, 0xf6, 0x6b, 0x79, 0x70, 0xfd, 0xff,
+        0x86, 0x17, 0x18, 0x7b, 0xb9, 0xff, 0xfd, 0xff,
+        0x5a, 0xe4, 0xdf, 0x3e, 0xdb, 0xd5, 0xd3, 0x5e,
+        0x5b, 0x4f, 0x09, 0x02, 0x0d, 0xb0, 0x3e, 0xab,
+        0x1e, 0x03, 0x1d, 0xda, 0x2f, 0xbe, 0x03, 0xd1,
+        0x79, 0x21, 0x70, 0xa0, 0xf3, 0x00, 0x9c, 0xee
+    };
+
+    uint8_t decrypted[kTotalSize] = {
+        0xf0, 0x13, 0xca, 0xc7, 0x00, 0x64, 0x0b, 0xbb,
+        0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,
+        0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
+        0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c,
+        0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
+        0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11,
+        0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef,
+        0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17,
+        0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10
+    };
+
+    SubSample subSamples[kNumSubsamples] = {
+        {8, 64}
+    };
+
+    attemptDecryptExpectingSuccess<kTotalSize>(key, iv, encrypted, decrypted,
+                                               subSamples, kNumSubsamples);
+}
+
+TEST_F(AesCtrDecryptorTest, DecryptsAlignedMixedSubSamples) {
+    const size_t kTotalSize = 80;
+    const size_t kNumSubsamples = 2;
+
+    // Based on test vectors from NIST-800-38A
+    Key key = {
+        0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
+        0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c
+    };
+
+    Iv iv = {
+        0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
+        0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
+    };
+
+    uint8_t encrypted[kTotalSize] = {
+        // 8 clear bytes
+        0xf0, 0x13, 0xca, 0xc7, 0x00, 0x64, 0x0b, 0xbb,
+        // 32 encrypted bytes
+        0x87, 0x4d, 0x61, 0x91, 0xb6, 0x20, 0xe3, 0x26,
+        0x1b, 0xef, 0x68, 0x64, 0x99, 0x0d, 0xb6, 0xce,
+        0x98, 0x06, 0xf6, 0x6b, 0x79, 0x70, 0xfd, 0xff,
+        0x86, 0x17, 0x18, 0x7b, 0xb9, 0xff, 0xfd, 0xff,
+        // 8 clear bytes
+        0x94, 0xba, 0x88, 0x2e, 0x0e, 0x12, 0x11, 0x55,
+        // 32 encrypted bytes
+        0x5a, 0xe4, 0xdf, 0x3e, 0xdb, 0xd5, 0xd3, 0x5e,
+        0x5b, 0x4f, 0x09, 0x02, 0x0d, 0xb0, 0x3e, 0xab,
+        0x1e, 0x03, 0x1d, 0xda, 0x2f, 0xbe, 0x03, 0xd1,
+        0x79, 0x21, 0x70, 0xa0, 0xf3, 0x00, 0x9c, 0xee
+    };
+
+    uint8_t decrypted[kTotalSize] = {
+        0xf0, 0x13, 0xca, 0xc7, 0x00, 0x64, 0x0b, 0xbb,
+        0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,
+        0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
+        0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c,
+        0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
+        0x94, 0xba, 0x88, 0x2e, 0x0e, 0x12, 0x11, 0x55,
+        0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11,
+        0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef,
+        0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17,
+        0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10
+    };
+
+    SubSample subSamples[kNumSubsamples] = {
+        {8, 32},
+        {8, 32}
+    };
+
+    attemptDecryptExpectingSuccess<kTotalSize>(key, iv, encrypted, decrypted,
+                                               subSamples, kNumSubsamples);
+}
+
+TEST_F(AesCtrDecryptorTest, DecryptsUnalignedMixedSubSamples) {
+    const size_t kTotalSize = 80;
+    const size_t kNumSubsamples = 2;
+
+    // Based on test vectors from NIST-800-38A
+    Key key = {
+        0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
+        0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c
+    };
+
+    Iv iv = {
+        0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
+        0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
+    };
+
+    uint8_t encrypted[kTotalSize] = {
+        // 8 clear bytes
+        0xf0, 0x13, 0xca, 0xc7, 0x00, 0x64, 0x0b, 0xbb,
+        // 30 encrypted bytes
+        0x87, 0x4d, 0x61, 0x91, 0xb6, 0x20, 0xe3, 0x26,
+        0x1b, 0xef, 0x68, 0x64, 0x99, 0x0d, 0xb6, 0xce,
+        0x98, 0x06, 0xf6, 0x6b, 0x79, 0x70, 0xfd, 0xff,
+        0x86, 0x17, 0x18, 0x7b, 0xb9, 0xff,
+        // 8 clear bytes
+        0x94, 0xba, 0x88, 0x2e, 0x0e, 0x12, 0x11, 0x55,
+        // 34 encrypted bytes
+        0xfd, 0xff, 0x5a, 0xe4, 0xdf, 0x3e, 0xdb, 0xd5,
+        0xd3, 0x5e, 0x5b, 0x4f, 0x09, 0x02, 0x0d, 0xb0,
+        0x3e, 0xab, 0x1e, 0x03, 0x1d, 0xda, 0x2f, 0xbe,
+        0x03, 0xd1, 0x79, 0x21, 0x70, 0xa0, 0xf3, 0x00,
+        0x9c, 0xee
+    };
+
+    uint8_t decrypted[kTotalSize] = {
+        0xf0, 0x13, 0xca, 0xc7, 0x00, 0x64, 0x0b, 0xbb,
+        0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,
+        0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
+        0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c,
+        0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x94, 0xba,
+        0x88, 0x2e, 0x0e, 0x12, 0x11, 0x55, 0x8e, 0x51,
+        0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11,
+        0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef,
+        0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17,
+        0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10
+    };
+
+    SubSample subSamples[kNumSubsamples] = {
+        {8, 30},
+        {8, 34}
+    };
+
+    attemptDecryptExpectingSuccess<kTotalSize>(key, iv, encrypted, decrypted,
+                                               subSamples, kNumSubsamples);
+}
+
+TEST_F(AesCtrDecryptorTest, DecryptsComplexMixedSubSamples) {
+    const size_t kTotalSize = 72;
+    const size_t kNumSubsamples = 6;
+
+    // Based on test vectors from NIST-800-38A
+    Key key = {
+        0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
+        0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c
+    };
+
+    Iv iv = {
+        0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
+        0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
+    };
+
+    uint8_t encrypted[kTotalSize] = {
+        // 4 clear bytes
+        0xf0, 0x13, 0xca, 0xc7,
+        // 1 encrypted bytes
+        0x87,
+        // 9 encrypted bytes
+        0x4d, 0x61, 0x91, 0xb6, 0x20, 0xe3, 0x26, 0x1b,
+        0xef,
+        // 11 clear bytes
+        0x81, 0x4f, 0x24, 0x87, 0x0e, 0xde, 0xba, 0xad,
+        0x11, 0x9b, 0x46,
+        // 20 encrypted bytes
+        0x68, 0x64, 0x99, 0x0d, 0xb6, 0xce,
+        0x98, 0x06, 0xf6, 0x6b, 0x79, 0x70, 0xfd, 0xff,
+        0x86, 0x17, 0x18, 0x7b, 0xb9, 0xff,
+        // 8 clear bytes
+        0x94, 0xba, 0x88, 0x2e, 0x0e, 0x12, 0x11, 0x55,
+        // 3 clear bytes
+        0x10, 0xf5, 0x22,
+        // 14 encrypted bytes
+        0xfd, 0xff, 0x5a, 0xe4, 0xdf, 0x3e, 0xdb, 0xd5,
+        0xd3, 0x5e, 0x5b, 0x4f, 0x09, 0x02,
+        // 2 clear bytes
+        0x02, 0x01
+    };
+
+    uint8_t decrypted[kTotalSize] = {
+        0xf0, 0x13, 0xca, 0xc7, 0x6b, 0xc1, 0xbe, 0xe2,
+        0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x81, 0x4f,
+        0x24, 0x87, 0x0e, 0xde, 0xba, 0xad, 0x11, 0x9b,
+        0x46, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, 0xae,
+        0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, 0x9e,
+        0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x94, 0xba, 0x88,
+        0x2e, 0x0e, 0x12, 0x11, 0x55, 0x10, 0xf5, 0x22,
+        0x8e, 0x51, 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c,
+        0xe4, 0x11, 0xe5, 0xfb, 0xc1, 0x19, 0x02, 0x01
+    };
+
+    SubSample subSamples[kNumSubsamples] = {
+        {4, 1},
+        {0, 9},
+        {11, 20},
+        {8, 0},
+        {3, 14},
+        {2, 0}
+    };
+
+    attemptDecryptExpectingSuccess<kTotalSize>(key, iv, encrypted, decrypted,
+                                               subSamples, kNumSubsamples);
+}
+
+}  // namespace clearkeydrm
diff --git a/drm/mediadrm/plugins/clearkey/tests/Android.mk b/drm/mediadrm/plugins/clearkey/tests/Android.mk
new file mode 100644
index 0000000..ac5bb21
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/tests/Android.mk
@@ -0,0 +1,52 @@
+#
+# 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.
+#
+# ----------------------------------------------------------------
+# Builds ClearKey Drm Tests
+#
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := ClearKeyDrmUnitTest
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := \
+    AesCtrDecryptorUnittest.cpp \
+    InitDataParserUnittest.cpp \
+    JsonWebKeyUnittest.cpp \
+
+LOCAL_C_INCLUDES := \
+    bionic \
+    external/gtest/include \
+    external/jsmn \
+    external/openssl/include \
+    external/stlport/stlport \
+    frameworks/av/drm/mediadrm/plugins/clearkey \
+    frameworks/av/include \
+    frameworks/native/include \
+
+LOCAL_STATIC_LIBRARIES := \
+    libgtest \
+    libgtest_main \
+
+LOCAL_SHARED_LIBRARIES := \
+    libcrypto \
+    libdrmclearkeyplugin \
+    liblog \
+    libstagefright_foundation \
+    libstlport \
+    libutils \
+
+include $(BUILD_NATIVE_TEST)
diff --git a/drm/mediadrm/plugins/clearkey/tests/InitDataParserUnittest.cpp b/drm/mediadrm/plugins/clearkey/tests/InitDataParserUnittest.cpp
new file mode 100644
index 0000000..4ba65ed
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/tests/InitDataParserUnittest.cpp
@@ -0,0 +1,235 @@
+/*
+ * 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.
+ */
+
+#include <gtest/gtest.h>
+#include <string.h>
+
+#include <media/stagefright/foundation/AString.h>
+#include <media/stagefright/foundation/base64.h>
+#include <utils/String8.h>
+#include <utils/Vector.h>
+
+#include "InitDataParser.h"
+
+namespace clearkeydrm {
+
+using namespace android;
+
+namespace {
+    const size_t kKeyIdSize = 16;
+    const String8 kCencType("cenc");
+    const String8 kWebMType("webm");
+    const String8 kBase64Padding("=");
+}
+
+class InitDataParserTest : public ::testing::Test {
+  protected:
+    status_t attemptParse(const Vector<uint8_t>& initData,
+                          const String8& initDataType,
+                          Vector<uint8_t>* licenseRequest) {
+        InitDataParser parser;
+        return parser.parse(initData, initDataType, licenseRequest);
+    }
+
+    void attemptParseExpectingSuccess(const Vector<uint8_t>& initData,
+                                      const String8& initDataType,
+                                      const Vector<String8>& expectedKeys) {
+        const String8 kRequestPrefix("{\"kids\":[");
+        const String8 kRequestSuffix("],\"type\":\"temporary\"}");
+        Vector<uint8_t> request;
+        ASSERT_EQ(android::OK, attemptParse(initData, initDataType, &request));
+
+        String8 requestString(reinterpret_cast<const char*>(request.array()),
+                              request.size());
+        EXPECT_EQ(0, requestString.find(kRequestPrefix));
+        EXPECT_EQ(requestString.size() - kRequestSuffix.size(),
+                  requestString.find(kRequestSuffix));
+        for (size_t i = 0; i < expectedKeys.size(); ++i) {
+            AString encodedIdAString;
+            android::encodeBase64(expectedKeys[i], kKeyIdSize,
+                                  &encodedIdAString);
+            String8 encodedId(encodedIdAString.c_str());
+            encodedId.removeAll(kBase64Padding);
+            EXPECT_TRUE(requestString.contains(encodedId));
+        }
+    }
+
+    void attemptParseExpectingFailure(const Vector<uint8_t>& initData,
+                                      const String8& initDataType) {
+        Vector<uint8_t> request;
+        ASSERT_NE(android::OK, attemptParse(initData, initDataType, &request));
+        EXPECT_EQ(0, request.size());
+    }
+};
+
+TEST_F(InitDataParserTest, ParsesSingleKeyPssh) {
+    uint8_t pssh[52] = {
+        0, 0, 0, 52,                                    // Total Size
+        'p', 's', 's', 'h',                             // PSSH
+        1, 0, 0, 0,                                     // Version
+        0x10, 0x77, 0xef, 0xec, 0xc0, 0xb2, 0x4d, 0x02, // System ID
+        0xac, 0xe3, 0x3c, 0x1e, 0x52, 0xe2, 0xfb, 0x4b,
+        0, 0, 0, 1,                                     // Key Count
+        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, // Key ID #1
+        0x38, 0x39, 0x30, 0x41, 0x42, 0x43, 0x44, 0x45, //   "01234567890ABCDE"
+        0, 0, 0, 0                                      // Data Size (always 0)
+    };
+    Vector<uint8_t> initData;
+    initData.appendArray(pssh, 52);
+
+    Vector<String8> expectedKeys;
+    expectedKeys.push(String8("01234567890ABCDE"));
+
+    attemptParseExpectingSuccess(initData, kCencType, expectedKeys);
+}
+
+TEST_F(InitDataParserTest, ParsesMultipleKeyPssh) {
+    uint8_t pssh[84] = {
+        0, 0, 0, 84,                                    // Total Size
+        'p', 's', 's', 'h',                             // PSSH
+        1, 0, 0, 0,                                     // Version
+        0x10, 0x77, 0xef, 0xec, 0xc0, 0xb2, 0x4d, 0x02, // System ID
+        0xac, 0xe3, 0x3c, 0x1e, 0x52, 0xe2, 0xfb, 0x4b,
+        0, 0, 0, 3,                                     // Key Count
+        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, // Key ID #1
+        0x38, 0x39, 0x30, 0x41, 0x42, 0x43, 0x44, 0x45, //   "01234567890ABCDE"
+        0x43, 0x6c, 0x65, 0x61, 0x72, 0x4b, 0x65, 0x79, // Key ID #2
+        0x43, 0x6c, 0x65, 0x61, 0x72, 0x4b, 0x65, 0x79, //   "ClearKeyClearKey"
+        0x20, 0x47, 0x4f, 0x4f, 0x47, 0x4c, 0x45, 0x20, // Key ID #3
+        0x20, 0x47, 0x4f, 0x4f, 0x47, 0x4c, 0x45, 0x20, //   " GOOGLE  GOOGLE "
+        0, 0, 0, 0                                      // Data Size (always 0)
+    };
+    Vector<uint8_t> initData;
+    initData.appendArray(pssh, 84);
+
+    Vector<String8> expectedKeys;
+    expectedKeys.push(String8("01234567890ABCDE"));
+    expectedKeys.push(String8("ClearKeyClearKey"));
+    expectedKeys.push(String8(" GOOGLE  GOOGLE "));
+
+    attemptParseExpectingSuccess(initData, kCencType, expectedKeys);
+}
+
+TEST_F(InitDataParserTest, ParsesWebM) {
+    uint8_t initDataRaw[16] = {
+        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, // Key ID
+        0x38, 0x39, 0x30, 0x41, 0x42, 0x43, 0x44, 0x45, //   "01234567890ABCDE"
+    };
+    Vector<uint8_t> initData;
+    initData.appendArray(initDataRaw, 16);
+
+    Vector<String8> expectedKeys;
+    expectedKeys.push(String8("01234567890ABCDE"));
+
+    attemptParseExpectingSuccess(initData, kWebMType, expectedKeys);
+}
+
+TEST_F(InitDataParserTest, FailsForPsshTooSmall) {
+    uint8_t pssh[16] = {
+        0, 0, 0, 52,
+        'p', 's', 's', 'h',
+        1, 0, 0, 0,
+        0x10, 0x77, 0xef, 0xec
+    };
+    Vector<uint8_t> initData;
+    initData.appendArray(pssh, 16);
+
+    attemptParseExpectingFailure(initData, kCencType);
+}
+
+TEST_F(InitDataParserTest, FailsForWebMTooSmall) {
+    uint8_t initDataRaw[8] = {
+        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37
+    };
+    Vector<uint8_t> initData;
+    initData.appendArray(initDataRaw, 8);
+
+    attemptParseExpectingFailure(initData, kWebMType);
+}
+
+TEST_F(InitDataParserTest, FailsForPsshBadSystemId) {
+    uint8_t pssh[52] = {
+        0, 0, 0, 52,                                    // Total Size
+        'p', 's', 's', 'h',                             // PSSH
+        1, 0, 0, 0,                                     // Version
+        0xac, 0xe3, 0x3c, 0x1e, 0x52, 0xe2, 0xfb, 0x4b, // System ID
+        0x10, 0x77, 0xef, 0xec, 0xc0, 0xb2, 0x4d, 0x02,
+        0, 0, 0, 1,                                     // Key Count
+        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, // Key ID #1
+        0x38, 0x39, 0x30, 0x41, 0x42, 0x43, 0x44, 0x45, //   "01234567890ABCDE"
+        0, 0, 0, 0                                      // Data Size (always 0)
+    };
+    Vector<uint8_t> initData;
+    initData.appendArray(pssh, 52);
+
+    attemptParseExpectingFailure(initData, kCencType);
+}
+
+TEST_F(InitDataParserTest, FailsForPsshBadSize) {
+    uint8_t pssh[52] = {
+        0, 0, 70, 200,                                  // Total Size
+        'p', 's', 's', 'h',                             // PSSH
+        1, 0, 0, 0,                                     // Version
+        0x10, 0x77, 0xef, 0xec, 0xc0, 0xb2, 0x4d, 0x02, // System ID
+        0xac, 0xe3, 0x3c, 0x1e, 0x52, 0xe2, 0xfb, 0x4b,
+        0, 0, 0, 1,                                     // Key Count
+        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, // Key ID #1
+        0x38, 0x39, 0x30, 0x41, 0x42, 0x43, 0x44, 0x45, //   "01234567890ABCDE"
+        0, 0, 0, 0                                      // Data Size (always 0)
+    };
+    Vector<uint8_t> initData;
+    initData.appendArray(pssh, 52);
+
+    attemptParseExpectingFailure(initData, kCencType);
+}
+
+TEST_F(InitDataParserTest, FailsForPsshWrongVersion) {
+    uint8_t pssh[52] = {
+        0, 0, 0, 52,                                    // Total Size
+        'p', 's', 's', 'h',                             // PSSH
+        0, 0, 0, 0,                                     // Version
+        0x10, 0x77, 0xef, 0xec, 0xc0, 0xb2, 0x4d, 0x02, // System ID
+        0xac, 0xe3, 0x3c, 0x1e, 0x52, 0xe2, 0xfb, 0x4b,
+        0, 0, 0, 1,                                     // Key Count
+        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, // Key ID #1
+        0x38, 0x39, 0x30, 0x41, 0x42, 0x43, 0x44, 0x45, //   "01234567890ABCDE"
+        0, 0, 0, 0                                      // Data Size (always 0)
+    };
+    Vector<uint8_t> initData;
+    initData.appendArray(pssh, 52);
+
+    attemptParseExpectingFailure(initData, kCencType);
+}
+
+TEST_F(InitDataParserTest, FailsForPsshBadKeyCount) {
+    uint8_t pssh[52] = {
+        0, 0, 0, 52,                                    // Total Size
+        'p', 's', 's', 'h',                             // PSSH
+        1, 0, 0, 0,                                     // Version
+        0x10, 0x77, 0xef, 0xec, 0xc0, 0xb2, 0x4d, 0x02, // System ID
+        0xac, 0xe3, 0x3c, 0x1e, 0x52, 0xe2, 0xfb, 0x4b,
+        0, 0, 0, 7,                                     // Key Count
+        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, // Key ID #1
+        0x38, 0x39, 0x30, 0x41, 0x42, 0x43, 0x44, 0x45, //   "01234567890ABCDE"
+        0, 0, 0, 0                                      // Data Size (always 0)
+    };
+    Vector<uint8_t> initData;
+    initData.appendArray(pssh, 52);
+
+    attemptParseExpectingFailure(initData, kCencType);
+}
+
+}  // namespace clearkeydrm
diff --git a/drm/mediadrm/plugins/clearkey/tests/JsonWebKeyUnittest.cpp b/drm/mediadrm/plugins/clearkey/tests/JsonWebKeyUnittest.cpp
new file mode 100644
index 0000000..c3b0d84
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/tests/JsonWebKeyUnittest.cpp
@@ -0,0 +1,321 @@
+/*
+ * 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.
+ */
+#include <utils/Log.h>
+
+#include "JsonWebKey.h"
+
+#include "gtest/gtest.h"
+#include "Utils.h"
+
+namespace clearkeydrm {
+using android::String8;
+using android::Vector;
+
+class JsonWebKeyTest : public ::testing::Test {
+ protected:
+    JsonWebKey* jwk;
+
+    JsonWebKeyTest() {
+        jwk = new JsonWebKey;
+    }
+
+    virtual ~JsonWebKeyTest() {
+        if (jwk)
+            delete jwk;
+    }
+};
+
+void stringFromVector(const Vector<uint8_t>& input,
+        String8* converted) {
+    converted->clear();
+    if (input.isEmpty()) {
+        return;
+    }
+
+    for (size_t i = 0; i < input.size(); ++i) {
+        converted->appendFormat("%c", input.itemAt(i));
+    }
+}
+
+void verifyKeys(const KeyMap& keys, const String8* clearKeys) {
+    if (keys.isEmpty()) {
+        return;
+    }
+
+    String8 keyString;
+    for (size_t i = 0; i < keys.size(); ++i) {
+        stringFromVector(keys.valueAt(i), &keyString);
+        EXPECT_EQ(keyString, clearKeys[i]);
+    }
+}
+
+TEST_F(JsonWebKeyTest, NoSymmetricKey) {
+    const String8 js(
+            "{"
+                "[{"
+                    "\"kty\":\"rsa\","
+                    "\"alg\":\"A128KW1\","
+                    "\"kid\":\"Y2xlYXJrZXlrZXlpZDAx\","
+                    "\"k\":\"1-GawgguFyGrWKav7AX4VKUg\""
+                "}]"
+          "}");
+
+    KeyMap keys;
+    EXPECT_FALSE(jwk->extractKeysFromJsonWebKeySet(js, &keys));
+    EXPECT_TRUE(keys.isEmpty());
+}
+
+TEST_F(JsonWebKeyTest, NoKeysTag) {
+    const String8 js(
+            "{"
+                "[{"
+                    "\"kty\":\"oct\","
+                    "\"alg\":\"A128KW1\","
+                    "\"kid\":\"Y2xlYXJrZXlrZXlpZDAx\","
+                    "\"k\":\"1-GawgguFyGrWKav7AX4VKUg\""
+                "},"
+                "{"
+                    "\"kty\":\"oct\","
+                    "\"alg\":\"A128KW2\","
+                    "\"k\":\"R29vZCBkYXkh\","
+                    "\"kid\":\"Y2xlYXJrZXlrZXlpZDAy\""
+                "}]"
+            "}");
+
+    KeyMap keys;
+    EXPECT_FALSE(jwk->extractKeysFromJsonWebKeySet(js, &keys));
+    EXPECT_TRUE(keys.isEmpty());
+}
+
+TEST_F(JsonWebKeyTest, NoKeyId) {
+    const String8 js(
+            "{"
+                "\"keys\":"
+                    "[{"
+                        "\"kty\":\"oct\""
+                        "\"alg\":\"A128KW1\""
+                        "\"k\":\"SGVsbG8gRnJpZW5kISE=\""
+                    "}"
+                    "{"
+                        "\"kty\":\"oct\""
+                        "\"alg\":\"A128KW2\""
+                        "\"k\":\"R29vZCBkYXkh\""
+                        "\"kid\":\"Y2xlYXJrZXlrZXlpZDAy\""
+                    "}]"
+            "}");
+
+    KeyMap keys;
+    EXPECT_TRUE(jwk->extractKeysFromJsonWebKeySet(js, &keys));
+    EXPECT_TRUE(keys.size() == 1);
+
+    const String8 clearKeys("Good day!");
+    verifyKeys(keys, &clearKeys);
+}
+
+TEST_F(JsonWebKeyTest, NoKey) {
+    const String8 js(
+            "{"
+                "\"keys\":"
+                    "[{"
+                        "\"kty\":\"oct\""
+                        "\"alg\":\"A128KW1\""
+                        "\"kid\":\"`\""
+                    "}"
+                    "{"
+                        "\"kty\":\"oct\""
+                        "\"alg\":\"A128KW2\""
+                        "\"k\":\"R29vZCBkYXkh\""
+                        "\"kid\":\"Y2xlYXJrZXlrZXlpZDAy\""
+                    "}]"
+            "}");
+
+    KeyMap keys;
+    EXPECT_TRUE(jwk->extractKeysFromJsonWebKeySet(js, &keys));
+    EXPECT_TRUE(keys.size() == 1);
+
+    const String8 clearKeys("Good day!");
+    verifyKeys(keys, &clearKeys);
+}
+
+TEST_F(JsonWebKeyTest, MalformedKey) {
+    const String8 js(
+            "{"
+                "\"keys\":"
+                    "[{"
+                        "\"kty\":\"oct\""
+                        "\"alg\":\"A128KW1\""
+                        "\"k\":\"GawgguFyGrWKav7AX4V???\""
+                        "\"kid\":\"67ef0gd8pvfd0=\""
+                    "}"
+                    "{"
+                        "\"kty\":\"oct\""
+                        "\"alg\":\"A128KW1\""
+                        "\"k\":\"GawgguFyGrWKav7AX4V???\""
+                        "\"kid\":"
+                    "}"
+                    "{"
+                        "\"kty\":\"oct\""
+                        "\"alg\":\"A128KW1\""
+                        ":\"GawgguFyGrWKav7AX4V???\""
+                        "\"kid\":\"67ef0gd8pvfd0=\""
+                    "}"
+                    "{"
+                        "\"kty\":\"oct\""
+                        "\"alg\":\"A128KW3\""
+                        "\"kid\":\"Y2xlYXJrZXlrZXlpZDAz\""
+                        "\"k\":\"R29vZCBkYXkh\""
+                    "}]"
+            "}");
+
+    KeyMap keys;
+    EXPECT_TRUE(jwk->extractKeysFromJsonWebKeySet(js, &keys));
+    EXPECT_TRUE(keys.size() == 1);
+
+    const String8 clearKeys("Good day!");
+    verifyKeys(keys, &clearKeys);
+}
+
+TEST_F(JsonWebKeyTest, EmptyJsonWebKey) {
+    const String8 js;
+    KeyMap keys;
+    EXPECT_FALSE(jwk->extractKeysFromJsonWebKeySet(js, &keys));
+    EXPECT_TRUE(keys.isEmpty());
+}
+
+TEST_F(JsonWebKeyTest, MalformedJsonWebKey) {
+    // Missing begin array '['
+    const String8 js(
+            "{"
+                "\"keys\":"
+                    "{"
+                        "\"kty\":\"oct\""
+                        "\"alg\":\"A128KW1\""
+                        "\"k\":\"GawgguFyGrWKav7AX4VKUg\""
+                        "\"kid\":\"67ef0gd8pvfd0=\""
+                    "}"
+            "]"
+            "}");
+
+    KeyMap keys;
+    EXPECT_FALSE(jwk->extractKeysFromJsonWebKeySet(js, &keys));
+    EXPECT_TRUE(keys.isEmpty());
+}
+
+TEST_F(JsonWebKeyTest, SameKeyId) {
+    const String8 js(
+            "{"
+                "\"keys\":"
+                    "[{"
+                        "\"kty\":\"oct\""
+                        "\"alg\":\"A128KW1\""
+                        "\"kid\":\"Y2xlYXJrZXlrZXlpZDAx\""
+                        "\"k\":\"SGVsbG8gRnJpZW5kISE\""
+                    "}"
+                    "{"
+                        "\"kty\":\"oct\""
+                        "\"alg\":\"A128KW1\""
+                        "\"k\":\"SGVsbG8gRnJpZW5kIQ\""
+                        "\"kid\":\"Y2xlYXJrZXlrZXlpZDAx\""
+                    "}"
+                    "{"
+                        "\"kty\":\"oct\""
+                        "\"alg\":\"A128KW3\""
+                        "\"kid\":\"Y2xlYXJrZXlrZXlpZDAz\""
+                        "\"k\":\"R29vZCBkYXkh\""
+                    "}]"
+            "}");
+
+    KeyMap keys;
+    jwk->extractKeysFromJsonWebKeySet(js, &keys);
+    EXPECT_TRUE(keys.size() == 2);
+
+    const String8 clearKeys[] =
+            { String8("Hello Friend!"), String8("Good day!") };
+    verifyKeys(keys, clearKeys);
+}
+
+TEST_F(JsonWebKeyTest, ExtractWellFormedKeys) {
+    const String8 js(
+            "{"
+                "\"keys\":"
+                    "[{"
+                        "\"kty\":\"oct\""
+                        "\"alg\":\"A128KW1\""
+                    "}"
+                    "{"
+                        "\"kty\":\"oct\""
+                        "\"alg\":\"A128KW2\""
+                        "\"k\":\"SGVsbG8gRnJpZW5kIQ\""
+                        "\"kid\":\"Y2xlYXJrZXlrZXlpZDAy\""
+                    "}"
+                    "{"
+                        "\"kty\":\"oct\""
+                        "\"alg\":\"A128KW3\""
+                        "\"kid\":\"Y2xlYXJrZXlrZXlpZDAz\""
+                        "\"k\":\"R29vZCBkYXkh\""
+                    "}]"
+            "}");
+
+    KeyMap keys;
+    jwk->extractKeysFromJsonWebKeySet(js, &keys);
+    EXPECT_TRUE(keys.size() == 2);
+
+    const String8 clearKeys[] =
+            { String8("Hello Friend!"), String8("Good day!") };
+    verifyKeys(keys, clearKeys);
+}
+
+TEST_F(JsonWebKeyTest, ExtractKeys) {
+    const String8 js(
+            "{"
+                "\"keys\":"
+                    "[{"
+                        "\"kid\":\"Y2xlYXJrZXlrZXlpZDAx\""
+                        "\"k\":\"SGVsbG8gRnJpZW5kISE\""
+                        "\"kty\":\"oct\""
+                        "\"alg\":\"A128KW1\""
+                    "}"
+                    "{"
+                        "\"kty\":\"oct\""
+                        "\"alg\":\"A128KW2\""
+                        "\"k\":\"SGVsbG8gRnJpZW5kIQ\""
+                        "\"kid\":\"Y2xlYXJrZXlrZXlpZDAy\""
+                    "}"
+                    "{"
+                        "\"kty\":\"rsa\""
+                        "\"alg\":\"A128KW-rsa\""
+                        "\"k\":\"R29vZCBkYXkh\""
+                        "\"kid\":\"rsa-67ef0gd8pvfd0=\""
+                    "}"
+                    "{"
+                        "\"alg\":\"A128KW3\""
+                        "\"kid\":\"Y2xlYXJrZXlrZXlpZDAz\""
+                        "\"k\":\"R29vZCBkYXkh\""
+                        "\"kty\":\"oct\""
+                    "}]"
+            "}");
+
+    KeyMap keys;
+    jwk->extractKeysFromJsonWebKeySet(js, &keys);
+    EXPECT_TRUE(keys.size() == 3);
+
+    const String8 clearKeys[] =
+            { String8("Hello Friend!!"), String8("Hello Friend!"),
+              String8("Good day!") };
+    verifyKeys(keys, clearKeys);
+}
+
+}  // namespace clearkeydrm
diff --git a/drm/mediadrm/plugins/mock/Android.mk b/drm/mediadrm/plugins/mock/Android.mk
index ada23a2..26c245b 100644
--- a/drm/mediadrm/plugins/mock/Android.mk
+++ b/drm/mediadrm/plugins/mock/Android.mk
@@ -21,7 +21,8 @@
 
 LOCAL_MODULE := libmockdrmcryptoplugin
 
-LOCAL_MODULE_PATH := $(TARGET_OUT_VENDOR_SHARED_LIBRARIES)/mediadrm
+LOCAL_PROPRIETARY_MODULE := true
+LOCAL_MODULE_RELATIVE_PATH := mediadrm
 
 LOCAL_SHARED_LIBRARIES := \
     libutils liblog
diff --git a/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.cpp b/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.cpp
index df0bca3..2ea554b 100644
--- a/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.cpp
+++ b/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.cpp
@@ -299,6 +299,12 @@
         return OK;
     }
 
+    status_t MockDrmPlugin::unprovisionDevice()
+    {
+        ALOGD("MockDrmPlugin::unprovisionDevice()");
+        return OK;
+    }
+
     status_t MockDrmPlugin::getSecureStops(List<Vector<uint8_t> > &secureStops)
     {
         Mutex::Autolock lock(mLock);
@@ -726,7 +732,7 @@
     {
         String8 result;
         for (size_t i = 0; i < numSubSamples; i++) {
-            result.appendFormat("[%d] {clear:%d, encrypted:%d} ", i,
+            result.appendFormat("[%zu] {clear:%zu, encrypted:%zu} ", i,
                                 subSamples[i].mNumBytesOfClearData,
                                 subSamples[i].mNumBytesOfEncryptedData);
         }
diff --git a/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.h b/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.h
index 97d7052..4b63299 100644
--- a/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.h
+++ b/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.h
@@ -85,6 +85,8 @@
                                           Vector<uint8_t> &certificate,
                                           Vector<uint8_t> &wrappedKey);
 
+        status_t unprovisionDevice();
+
         status_t getSecureStops(List<Vector<uint8_t> > &secureStops);
         status_t releaseSecureStops(Vector<uint8_t> const &ssRelease);
 
diff --git a/include/camera/Camera.h b/include/camera/Camera.h
index 79682b8..2b60842 100644
--- a/include/camera/Camera.h
+++ b/include/camera/Camera.h
@@ -74,6 +74,10 @@
                                 const String16& clientPackageName,
                                 int clientUid);
 
+    static  status_t  connectLegacy(int cameraId, int halVersion,
+                                     const String16& clientPackageName,
+                                     int clientUid, sp<Camera>& camera);
+
             virtual     ~Camera();
 
             status_t    reconnect();
diff --git a/include/camera/CameraParameters.h b/include/camera/CameraParameters.h
index d521543..c6074fc 100644
--- a/include/camera/CameraParameters.h
+++ b/include/camera/CameraParameters.h
@@ -102,6 +102,12 @@
     void dump() const;
     status_t dump(int fd, const Vector<String16>& args) const;
 
+    /**
+     * Returns a Vector containing the supported preview formats
+     * as enums given in graphics.h.
+     */
+    void getSupportedPreviewFormats(Vector<int>& formats) const;
+
     // Parameter keys to communicate between camera application and driver.
     // The access (read/write, read only, or write only) is viewed from the
     // perspective of applications, not driver.
@@ -674,6 +680,13 @@
     // High-dynamic range mode
     static const char LIGHTFX_HDR[];
 
+    /**
+     * Returns the the supported preview formats as an enum given in graphics.h
+     * corrsponding to the format given in the input string or -1 if no such
+     * conversion exists.
+     */
+    static int previewFormatToEnum(const char* format);
+
 private:
     DefaultKeyedVector<String8,String8>    mMap;
 };
diff --git a/include/camera/CameraUtils.h b/include/camera/CameraUtils.h
new file mode 100644
index 0000000..c06f05d
--- /dev/null
+++ b/include/camera/CameraUtils.h
@@ -0,0 +1,49 @@
+/*
+ * 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 ANDROID_CAMERA_CLIENT_CAMERAUTILS_H
+#define ANDROID_CAMERA_CLIENT_CAMERAUTILS_H
+
+#include <camera/CameraMetadata.h>
+#include <utils/Errors.h>
+
+#include <stdint.h>
+
+namespace android {
+
+/**
+ * CameraUtils contains utility methods that are shared between the native
+ * camera client, and the camera service.
+ */
+class CameraUtils {
+    public:
+        /**
+         * Calculate the ANativeWindow transform from the static camera
+         * metadata.  This is based on the sensor orientation and lens facing
+         * attributes of the camera device.
+         *
+         * Returns OK on success, or a negative error code.
+         */
+        static status_t getRotationTransform(const CameraMetadata& staticInfo,
+                /*out*/int32_t* transform);
+    private:
+        CameraUtils();
+};
+
+} /* namespace android */
+
+#endif /* ANDROID_CAMERA_CLIENT_CAMERAUTILS_H */
+
diff --git a/include/camera/CaptureResult.h b/include/camera/CaptureResult.h
new file mode 100644
index 0000000..0be7d6f
--- /dev/null
+++ b/include/camera/CaptureResult.h
@@ -0,0 +1,96 @@
+/*
+ * 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 ANDROID_HARDWARE_CAPTURERESULT_H
+#define ANDROID_HARDWARE_CAPTURERESULT_H
+
+#include <utils/RefBase.h>
+#include <camera/CameraMetadata.h>
+
+namespace android {
+
+/**
+ * CaptureResultExtras is a structure to encapsulate various indices for a capture result.
+ * These indices are framework-internal and not sent to the HAL.
+ */
+struct CaptureResultExtras {
+    /**
+     * An integer to index the request sequence that this result belongs to.
+     */
+    int32_t requestId;
+
+    /**
+     * An integer to index this result inside a request sequence, starting from 0.
+     */
+    int32_t burstId;
+
+    /**
+     * TODO: Add documentation for this field.
+     */
+    int32_t afTriggerId;
+
+    /**
+     * TODO: Add documentation for this field.
+     */
+    int32_t precaptureTriggerId;
+
+    /**
+     * A 64bit integer to index the frame number associated with this result.
+     */
+    int64_t frameNumber;
+
+    /**
+     * The partial result count (index) for this capture result.
+     */
+    int32_t partialResultCount;
+
+    /**
+     * Constructor initializes object as invalid by setting requestId to be -1.
+     */
+    CaptureResultExtras()
+        : requestId(-1),
+          burstId(0),
+          afTriggerId(0),
+          precaptureTriggerId(0),
+          frameNumber(0),
+          partialResultCount(0) {
+    }
+
+    /**
+     * This function returns true if it's a valid CaptureResultExtras object.
+     * Otherwise, returns false. It is valid only when requestId is non-negative.
+     */
+    bool isValid();
+
+    status_t                readFromParcel(Parcel* parcel);
+    status_t                writeToParcel(Parcel* parcel) const;
+};
+
+struct CaptureResult : public virtual LightRefBase<CaptureResult> {
+    CameraMetadata          mMetadata;
+    CaptureResultExtras     mResultExtras;
+
+    CaptureResult();
+
+    CaptureResult(const CaptureResult& otherResult);
+
+    status_t                readFromParcel(Parcel* parcel);
+    status_t                writeToParcel(Parcel* parcel) const;
+};
+
+}
+
+#endif /* ANDROID_HARDWARE_CAPTURERESULT_H */
diff --git a/include/camera/ICameraService.h b/include/camera/ICameraService.h
index f342122..f7f06bb 100644
--- a/include/camera/ICameraService.h
+++ b/include/camera/ICameraService.h
@@ -31,6 +31,8 @@
 class ICameraDeviceUser;
 class ICameraDeviceCallbacks;
 class CameraMetadata;
+class VendorTagDescriptor;
+class String16;
 
 class ICameraService : public IInterface
 {
@@ -47,21 +49,40 @@
         ADD_LISTENER,
         REMOVE_LISTENER,
         GET_CAMERA_CHARACTERISTICS,
+        GET_CAMERA_VENDOR_TAG_DESCRIPTOR,
+        GET_LEGACY_PARAMETERS,
+        SUPPORTS_CAMERA_API,
+        CONNECT_LEGACY,
     };
 
     enum {
         USE_CALLING_UID = -1
     };
 
+    enum {
+        API_VERSION_1 = 1,
+        API_VERSION_2 = 2,
+    };
+
+    enum {
+        CAMERA_HAL_API_VERSION_UNSPECIFIED = -1
+      };
+
 public:
     DECLARE_META_INTERFACE(CameraService);
 
     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
@@ -97,6 +118,30 @@
             int clientUid,
             /*out*/
             sp<ICameraDeviceUser>& device) = 0;
+
+    virtual status_t getLegacyParameters(
+            int cameraId,
+            /*out*/
+            String16* parameters) = 0;
+
+    /**
+     * Returns OK if device supports camera2 api,
+     * returns -EOPNOTSUPP if it doesn't.
+     */
+    virtual status_t supportsCameraApi(
+            int cameraId, int apiVersion) = 0;
+
+    /**
+     * Connect the device as a legacy device for a given HAL version.
+     * For halVersion, use CAMERA_API_DEVICE_VERSION_* for a particular
+     * version, or CAMERA_HAL_API_VERSION_UNSPECIFIED for a service-selected version.
+     */
+    virtual status_t connectLegacy(const sp<ICameraClient>& cameraClient,
+            int cameraId, int halVersion,
+            const String16& clientPackageName,
+            int clientUid,
+            /*out*/
+            sp<ICamera>& device) = 0;
 };
 
 // ----------------------------------------------------------------------------
diff --git a/include/camera/VendorTagDescriptor.h b/include/camera/VendorTagDescriptor.h
new file mode 100644
index 0000000..1758acf
--- /dev/null
+++ b/include/camera/VendorTagDescriptor.h
@@ -0,0 +1,145 @@
+/*
+ * 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/Vector.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;
+
+        /**
+         * Convenience method to get a vector containing all vendor tag
+         * sections, or an empty vector if none are defined.
+         */
+        SortedVector<String8> getAllSectionNames() const;
+
+        /**
+         * Lookup the tag id for a given tag name and section.
+         *
+         * Returns OK on success, or a negative error code.
+         */
+        status_t lookupTag(String8 name, String8 section, /*out*/uint32_t* tag) const;
+
+        /**
+         * Dump the currently configured vendor tags to a file descriptor.
+         */
+        void dump(int fd, int verbosity, int indentation) 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<String8, KeyedVector<String8, uint32_t>*> mReverseMapping;
+        KeyedVector<uint32_t, String8> mTagToNameMap;
+        KeyedVector<uint32_t, uint32_t> mTagToSectionMap; // Value is offset in mSections
+        KeyedVector<uint32_t, int32_t> mTagToTypeMap;
+        SortedVector<String8> mSections;
+        // 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/camera/camera2/ICameraDeviceCallbacks.h b/include/camera/camera2/ICameraDeviceCallbacks.h
index 8dac4f2..670480b 100644
--- a/include/camera/camera2/ICameraDeviceCallbacks.h
+++ b/include/camera/camera2/ICameraDeviceCallbacks.h
@@ -24,9 +24,12 @@
 #include <utils/Timers.h>
 #include <system/camera.h>
 
+#include <camera/CaptureResult.h>
+
 namespace android {
 class CameraMetadata;
 
+
 class ICameraDeviceCallbacks : public IInterface
 {
     /**
@@ -39,24 +42,29 @@
      * Error codes for CAMERA_MSG_ERROR
      */
     enum CameraErrorCode {
+        ERROR_CAMERA_INVALID_ERROR = -1, // To indicate all invalid error codes
         ERROR_CAMERA_DISCONNECTED = 0,
         ERROR_CAMERA_DEVICE = 1,
-        ERROR_CAMERA_SERVICE = 2
+        ERROR_CAMERA_SERVICE = 2,
+        ERROR_CAMERA_REQUEST = 3,
+        ERROR_CAMERA_RESULT = 4,
+        ERROR_CAMERA_BUFFER = 5,
     };
 
     // One way
-    virtual void            onDeviceError(CameraErrorCode errorCode) = 0;
+    virtual void            onDeviceError(CameraErrorCode errorCode,
+                                          const CaptureResultExtras& resultExtras) = 0;
 
     // One way
     virtual void            onDeviceIdle() = 0;
 
     // One way
-    virtual void            onCaptureStarted(int32_t requestId,
+    virtual void            onCaptureStarted(const CaptureResultExtras& resultExtras,
                                              int64_t timestamp) = 0;
 
     // One way
-    virtual void            onResultReceived(int32_t requestId,
-                                             const CameraMetadata& result) = 0;
+    virtual void            onResultReceived(const CameraMetadata& metadata,
+                                             const CaptureResultExtras& resultExtras) = 0;
 };
 
 // ----------------------------------------------------------------------------
diff --git a/include/camera/camera2/ICameraDeviceUser.h b/include/camera/camera2/ICameraDeviceUser.h
index f71f302..35488bb 100644
--- a/include/camera/camera2/ICameraDeviceUser.h
+++ b/include/camera/camera2/ICameraDeviceUser.h
@@ -19,6 +19,7 @@
 
 #include <binder/IInterface.h>
 #include <binder/Parcel.h>
+#include <utils/List.h>
 
 struct camera_metadata;
 
@@ -30,6 +31,10 @@
 class CaptureRequest;
 class CameraMetadata;
 
+enum {
+    NO_IN_FLIGHT_REPEATING_FRAMES = -1,
+};
+
 class ICameraDeviceUser : public IInterface
 {
     /**
@@ -44,9 +49,55 @@
      * Request Handling
      **/
 
+    /**
+     * For streaming requests, output lastFrameNumber is the last frame number
+     * of the previous repeating request.
+     * For non-streaming requests, output lastFrameNumber is the expected last
+     * frame number of the current request.
+     */
     virtual int             submitRequest(sp<CaptureRequest> request,
-                                          bool streaming = false) = 0;
-    virtual status_t        cancelRequest(int requestId) = 0;
+                                          bool streaming = false,
+                                          /*out*/
+                                          int64_t* lastFrameNumber = NULL) = 0;
+
+    /**
+     * For streaming requests, output lastFrameNumber is the last frame number
+     * of the previous repeating request.
+     * For non-streaming requests, output lastFrameNumber is the expected last
+     * frame number of the current request.
+     */
+    virtual int             submitRequestList(List<sp<CaptureRequest> > requestList,
+                                              bool streaming = false,
+                                              /*out*/
+                                              int64_t* lastFrameNumber = NULL) = 0;
+
+    /**
+     * Output lastFrameNumber is the last frame number of the previous repeating request.
+     */
+    virtual status_t        cancelRequest(int requestId,
+                                          /*out*/
+                                          int64_t* lastFrameNumber = NULL) = 0;
+
+    /**
+     * Begin the device configuration.
+     *
+     * <p>
+     * beginConfigure must be called before any call to deleteStream, createStream,
+     * or endConfigure.  It is not valid to call this when the device is not idle.
+     * <p>
+     */
+    virtual status_t        beginConfigure() = 0;
+
+    /**
+     * End the device configuration.
+     *
+     * <p>
+     * endConfigure must be called after stream configuration is complete (i.e. after
+     * a call to beginConfigure and subsequent createStream/deleteStream calls).  This
+     * must be called before any requests can be submitted.
+     * <p>
+     */
+    virtual status_t        endConfigure() = 0;
 
     virtual status_t        deleteStream(int streamId) = 0;
     virtual status_t        createStream(
@@ -64,8 +115,12 @@
     // Wait until all the submitted requests have finished processing
     virtual status_t        waitUntilIdle() =  0;
 
-    // Flush all pending and in-progress work as quickly as possible.
-    virtual status_t        flush() = 0;
+    /**
+     * Flush all pending and in-progress work as quickly as possible.
+     * Output lastFrameNumber is the last frame number of the previous repeating request.
+     */
+    virtual status_t        flush(/*out*/
+                                  int64_t* lastFrameNumber = NULL) = 0;
 };
 
 // ----------------------------------------------------------------------------
diff --git a/include/media/AudioBufferProvider.h b/include/media/AudioBufferProvider.h
index ef392f0..7be449c 100644
--- a/include/media/AudioBufferProvider.h
+++ b/include/media/AudioBufferProvider.h
@@ -61,6 +61,17 @@
     //  buffer->frameCount  0
     virtual status_t getNextBuffer(Buffer* buffer, int64_t pts = kInvalidPTS) = 0;
 
+    // Release (a portion of) the buffer previously obtained by getNextBuffer().
+    // It is permissible to call releaseBuffer() multiple times per getNextBuffer().
+    // On entry:
+    //  buffer->frameCount  number of frames to release, must be <= number of frames
+    //                      obtained but not yet released
+    //  buffer->raw         unused
+    // On return:
+    //  buffer->frameCount  0; implementation MUST set to zero
+    //  buffer->raw         undefined; implementation is PERMITTED to set to any value,
+    //                      so if caller needs to continue using this buffer it must
+    //                      keep track of the pointer itself
     virtual void releaseBuffer(Buffer* buffer) = 0;
 };
 
diff --git a/include/media/AudioEffect.h b/include/media/AudioEffect.h
index eef1b41..583695d 100644
--- a/include/media/AudioEffect.h
+++ b/include/media/AudioEffect.h
@@ -36,7 +36,7 @@
 
 // ----------------------------------------------------------------------------
 
-class effect_param_cblk_t;
+struct effect_param_cblk_t;
 
 // ----------------------------------------------------------------------------
 
@@ -218,8 +218,9 @@
      *      higher priorities, 0 being the normal priority.
      * cbf:         optional callback function (see effect_callback_t)
      * user:        pointer to context for use by the callback receiver.
-     * sessionID:   audio session this effect is associated to. If 0, the effect will be global to
-     *      the output mix. If not 0, the effect will be applied to all players
+     * sessionID:   audio session this effect is associated to.
+     *      If equal to AUDIO_SESSION_OUTPUT_MIX, the effect will be global to
+     *      the output mix.  Otherwise, the effect will be applied to all players
      *      (AudioTrack or MediaPLayer) within the same audio session.
      * io:  HAL audio output or input stream to which this effect must be attached. Leave at 0 for
      *      automatic output selection by AudioFlinger.
@@ -230,8 +231,8 @@
                   int32_t priority = 0,
                   effect_callback_t cbf = NULL,
                   void* user = NULL,
-                  int sessionId = 0,
-                  audio_io_handle_t io = 0
+                  int sessionId = AUDIO_SESSION_OUTPUT_MIX,
+                  audio_io_handle_t io = AUDIO_IO_HANDLE_NONE
                   );
 
     /* Constructor.
@@ -242,8 +243,8 @@
                     int32_t priority = 0,
                     effect_callback_t cbf = NULL,
                     void* user = NULL,
-                    int sessionId = 0,
-                    audio_io_handle_t io = 0
+                    int sessionId = AUDIO_SESSION_OUTPUT_MIX,
+                    audio_io_handle_t io = AUDIO_IO_HANDLE_NONE
                     );
 
     /* Terminates the AudioEffect and unregisters it from AudioFlinger.
@@ -264,8 +265,8 @@
                             int32_t priority = 0,
                             effect_callback_t cbf = NULL,
                             void* user = NULL,
-                            int sessionId = 0,
-                            audio_io_handle_t io = 0
+                            int sessionId = AUDIO_SESSION_OUTPUT_MIX,
+                            audio_io_handle_t io = AUDIO_IO_HANDLE_NONE
                             );
 
     /* Result of constructing the AudioEffect. This must be checked
@@ -453,6 +454,7 @@
     sp<EffectClient>        mIEffectClient;     // IEffectClient implementation
     sp<IMemory>             mCblkMemory;        // shared memory for deferred parameter setting
     effect_param_cblk_t*    mCblk;              // control block for deferred parameter setting
+    pid_t                   mClientPid;
 };
 
 
diff --git a/include/media/AudioPolicyHelper.h b/include/media/AudioPolicyHelper.h
new file mode 100644
index 0000000..f4afd45
--- /dev/null
+++ b/include/media/AudioPolicyHelper.h
@@ -0,0 +1,64 @@
+/*
+ * 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 AUDIO_POLICY_HELPER_H_
+#define AUDIO_POLICY_HELPER_H_
+
+#include <system/audio.h>
+
+audio_stream_type_t audio_attributes_to_stream_type(const audio_attributes_t *attr)
+{
+    // flags to stream type mapping
+    if ((attr->flags & AUDIO_FLAG_AUDIBILITY_ENFORCED) == AUDIO_FLAG_AUDIBILITY_ENFORCED) {
+        return AUDIO_STREAM_ENFORCED_AUDIBLE;
+    }
+    if ((attr->flags & AUDIO_FLAG_SCO) == AUDIO_FLAG_SCO) {
+        return AUDIO_STREAM_BLUETOOTH_SCO;
+    }
+
+    // usage to stream type mapping
+    switch (attr->usage) {
+    case AUDIO_USAGE_MEDIA:
+    case AUDIO_USAGE_GAME:
+    case AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY:
+    case AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE:
+        return AUDIO_STREAM_MUSIC;
+    case AUDIO_USAGE_ASSISTANCE_SONIFICATION:
+        return AUDIO_STREAM_SYSTEM;
+    case AUDIO_USAGE_VOICE_COMMUNICATION:
+        return AUDIO_STREAM_VOICE_CALL;
+
+    case AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING:
+        return AUDIO_STREAM_DTMF;
+
+    case AUDIO_USAGE_ALARM:
+        return AUDIO_STREAM_ALARM;
+    case AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE:
+        return AUDIO_STREAM_RING;
+
+    case AUDIO_USAGE_NOTIFICATION:
+    case AUDIO_USAGE_NOTIFICATION_COMMUNICATION_REQUEST:
+    case AUDIO_USAGE_NOTIFICATION_COMMUNICATION_INSTANT:
+    case AUDIO_USAGE_NOTIFICATION_COMMUNICATION_DELAYED:
+    case AUDIO_USAGE_NOTIFICATION_EVENT:
+        return AUDIO_STREAM_NOTIFICATION;
+
+    case AUDIO_USAGE_UNKNOWN:
+    default:
+        return AUDIO_STREAM_MUSIC;
+    }
+}
+
+#endif //AUDIO_POLICY_HELPER_H_
diff --git a/include/media/AudioRecord.h b/include/media/AudioRecord.h
index 052064d..4edc1bf 100644
--- a/include/media/AudioRecord.h
+++ b/include/media/AudioRecord.h
@@ -26,7 +26,7 @@
 
 // ----------------------------------------------------------------------------
 
-class audio_track_cblk_t;
+struct audio_track_cblk_t;
 class AudioRecordClientProxy;
 
 // ----------------------------------------------------------------------------
@@ -39,8 +39,12 @@
      * Keep in sync with frameworks/base/media/java/android/media/AudioRecord.java NATIVE_EVENT_*.
      */
     enum event_type {
-        EVENT_MORE_DATA = 0,        // Request to read more data from PCM buffer.
-        EVENT_OVERRUN = 1,          // PCM buffer overrun occurred.
+        EVENT_MORE_DATA = 0,        // Request to read available data from buffer.
+                                    // If this event is delivered but the callback handler
+                                    // does not want to read the available data, the handler must
+                                    // explicitly
+                                    // ignore the event by setting frameCount to zero.
+        EVENT_OVERRUN = 1,          // Buffer overrun occurred.
         EVENT_MARKER = 2,           // Record head is at the specified marker position
                                     // (See setMarkerPosition()).
         EVENT_NEW_POS = 3,          // Record head is at a new position
@@ -60,9 +64,10 @@
         size_t      frameCount;     // number of sample frames corresponding to size;
                                     // on input it is the number of frames available,
                                     // on output is the number of frames actually drained
-                                    // (currently ignored, but will make the primary field in future)
+                                    // (currently ignored but will make the primary field in future)
 
         size_t      size;           // input/output in bytes == frameCount * frameSize
+                                    // on output is the number of bytes actually drained
                                     // FIXME this is redundant with respect to frameCount,
                                     // and TRANSFER_OBTAIN mode is broken for 8-bit data
                                     // since we don't define the frame format
@@ -76,7 +81,7 @@
 
     /* As a convenience, if a callback is supplied, a handler thread
      * is automatically created with the appropriate priority. This thread
-     * invokes the callback when a new buffer becomes ready or various conditions occur.
+     * invokes the callback when a new buffer becomes available or various conditions occur.
      * Parameters:
      *
      * event:   type of event notified (see enum AudioRecord::event_type).
@@ -99,6 +104,8 @@
      *  - NO_ERROR: successful operation
      *  - NO_INIT: audio server or audio hardware not initialized
      *  - BAD_VALUE: unsupported configuration
+     * frameCount is guaranteed to be non-zero if status is NO_ERROR,
+     * and is undefined otherwise.
      */
 
      static status_t getMinFrameCount(size_t* frameCount,
@@ -109,7 +116,7 @@
     /* How data is transferred from AudioRecord
      */
     enum transfer_type {
-        TRANSFER_DEFAULT,   // not specified explicitly; determine from other parameters
+        TRANSFER_DEFAULT,   // not specified explicitly; determine from the other parameters
         TRANSFER_CALLBACK,  // callback EVENT_MORE_DATA
         TRANSFER_OBTAIN,    // FIXME deprecated: call obtainBuffer() and releaseBuffer()
         TRANSFER_SYNC,      // synchronous read()
@@ -137,7 +144,7 @@
      *                     be larger if the requested size is not compatible with current audio HAL
      *                     latency.  Zero means to use a default value.
      * cbf:                Callback function. If not null, this function is called periodically
-     *                     to consume new PCM data and inform of marker, position updates, etc.
+     *                     to consume new data and inform of marker, position updates, etc.
      * user:               Context for use by the callback receiver.
      * notificationFrames: The callback function is called each time notificationFrames PCM
      *                     frames are ready in record track output buffer.
@@ -151,11 +158,11 @@
                                     uint32_t sampleRate,
                                     audio_format_t format,
                                     audio_channel_mask_t channelMask,
-                                    int frameCount      = 0,
+                                    size_t frameCount = 0,
                                     callback_t cbf = NULL,
                                     void* user = NULL,
-                                    int notificationFrames = 0,
-                                    int sessionId = 0,
+                                    uint32_t notificationFrames = 0,
+                                    int sessionId = AUDIO_SESSION_ALLOCATE,
                                     transfer_type transferType = TRANSFER_DEFAULT,
                                     audio_input_flags_t flags = AUDIO_INPUT_FLAG_NONE);
 
@@ -171,9 +178,10 @@
      * Returned status (from utils/Errors.h) can be:
      *  - NO_ERROR: successful intialization
      *  - INVALID_OPERATION: AudioRecord is already initialized or record device is already in use
-     *  - BAD_VALUE: invalid parameter (channels, format, sampleRate...)
+     *  - BAD_VALUE: invalid parameter (channelMask, format, sampleRate...)
      *  - NO_INIT: audio server or audio hardware not initialized
      *  - PERMISSION_DENIED: recording is not allowed for the requesting process
+     * If status is not equal to NO_ERROR, don't call any other APIs on this AudioRecord.
      *
      * Parameters not listed in the AudioRecord constructors above:
      *
@@ -183,16 +191,16 @@
                             uint32_t sampleRate,
                             audio_format_t format,
                             audio_channel_mask_t channelMask,
-                            int frameCount      = 0,
+                            size_t frameCount = 0,
                             callback_t cbf = NULL,
                             void* user = NULL,
-                            int notificationFrames = 0,
+                            uint32_t notificationFrames = 0,
                             bool threadCanCallJava = false,
-                            int sessionId = 0,
+                            int sessionId = AUDIO_SESSION_ALLOCATE,
                             transfer_type transferType = TRANSFER_DEFAULT,
                             audio_input_flags_t flags = AUDIO_INPUT_FLAG_NONE);
 
-    /* Result of constructing the AudioRecord. This must be checked
+    /* Result of constructing the AudioRecord. This must be checked for successful initialization
      * before using any AudioRecord API (except for set()), because using
      * an uninitialized AudioRecord produces undefined results.
      * See set() method above for possible return codes.
@@ -221,7 +229,7 @@
             status_t    start(AudioSystem::sync_event_t event = AudioSystem::SYNC_EVENT_NONE,
                               int triggerSession = 0);
 
-    /* Stop a track. If set, the callback will cease being called.  Note that obtainBuffer() still
+    /* Stop a track.  The callback will cease being called.  Note that obtainBuffer() still
      * works and will drain buffers until the pool is exhausted, and then will return WOULD_BLOCK.
      */
             void        stop();
@@ -232,11 +240,16 @@
      */
             uint32_t    getSampleRate() const   { return mSampleRate; }
 
+    /* Return the notification frame count.
+     * This is approximately how often the callback is invoked, for transfer type TRANSFER_CALLBACK.
+     */
+            size_t      notificationFrames() const  { return mNotificationFramesAct; }
+
     /* Sets marker position. When record reaches the number of frames specified,
      * a callback with event type EVENT_MARKER is called. Calling setMarkerPosition
      * with marker == 0 cancels marker notification callback.
      * To set a marker at a position which would compute as 0,
-     * a workaround is to the set the marker at a nearby position such as ~0 or 1.
+     * a workaround is to set the marker at a nearby position such as ~0 or 1.
      * If the AudioRecord has been opened with no callback function associated,
      * the operation will fail.
      *
@@ -378,8 +391,10 @@
      * returning the current value by this function call.  Such loss typically occurs when the
      * user space process is blocked longer than the capacity of audio driver buffers.
      * Units: the number of input audio frames.
+     * FIXME The side-effect of resetting the counter may be incompatible with multi-client.
+     * Consider making it more like AudioTrack::getUnderrunFrames which doesn't have side effects.
      */
-            unsigned int  getInputFramesLost() const;
+            uint32_t    getInputFramesLost() const;
 
 private:
     /* copying audio record objects is not allowed */
@@ -412,6 +427,7 @@
         bool                mPaused;    // whether thread is requested to pause at next loop entry
         bool                mPausedInt; // whether thread internally requests pause
         nsecs_t             mPausedNs;  // if mPausedInt then associated timeout, otherwise ignored
+        bool                mIgnoreNextPausedInt;   // whether to ignore next mPausedInt request
     };
 
             // body of AudioRecordThread::threadLoop()
@@ -422,9 +438,10 @@
             //      NS_INACTIVE inactive so don't run again until re-started
             //      NS_NEVER    never again
             static const nsecs_t NS_WHENEVER = -1, NS_INACTIVE = -2, NS_NEVER = -3;
-            nsecs_t processAudioBuffer(const sp<AudioRecordThread>& thread);
+            nsecs_t processAudioBuffer();
 
             // caller must hold lock on mLock for all _l methods
+
             status_t openRecord_l(size_t epoch);
 
             // FIXME enum is faster than strcmp() for parameter 'from'
@@ -444,14 +461,16 @@
     // for notification APIs
     uint32_t                mNotificationFramesReq; // requested number of frames between each
                                                     // notification callback
+                                                    // as specified in constructor or set()
     uint32_t                mNotificationFramesAct; // actual number of frames between each
                                                     // notification callback
-    bool                    mRefreshRemaining;  // processAudioBuffer() should refresh next 2
+    bool                    mRefreshRemaining;      // processAudioBuffer() should refresh
+                                                    // mRemainingFrames and mRetryOnPartialBuffer
 
     // These are private to processAudioBuffer(), and are not protected by a lock
     uint32_t                mRemainingFrames;       // number of frames to request in obtainBuffer()
     bool                    mRetryOnPartialBuffer;  // sleep and retry after partial obtainBuffer()
-    int                     mObservedSequence;      // last observed value of mSequence
+    uint32_t                mObservedSequence;      // last observed value of mSequence
 
     uint32_t                mMarkerPosition;    // in wrapping (overflow) frame units
     bool                    mMarkerReached;
@@ -460,9 +479,13 @@
 
     status_t                mStatus;
 
+    size_t                  mFrameCount;            // corresponds to current IAudioRecord, value is
+                                                    // reported back by AudioFlinger to the client
+    size_t                  mReqFrameCount;         // frame count to request the first or next time
+                                                    // a new IAudioRecord is needed, non-decreasing
+
     // constant after constructor or set()
     uint32_t                mSampleRate;
-    size_t                  mFrameCount;
     audio_format_t          mFormat;
     uint32_t                mChannelCount;
     size_t                  mFrameSize;         // app-level frame size == AudioFlinger frame size
@@ -473,12 +496,13 @@
     int                     mSessionId;
     transfer_type           mTransfer;
 
-    audio_io_handle_t       mInput;             // returned by AudioSystem::getInput()
-
-    // may be changed if IAudioRecord object is re-created
+    // Next 5 fields may be changed if IAudioRecord is re-created, but always != 0
+    // provided the initial set() was successful
     sp<IAudioRecord>        mAudioRecord;
     sp<IMemory>             mCblkMemory;
     audio_track_cblk_t*     mCblk;              // re-load after mLock.unlock()
+    sp<IMemory>             mBufferMemory;
+    audio_io_handle_t       mInput;             // returned by AudioSystem::getInput()
 
     int                     mPreviousPriority;  // before start()
     SchedPolicy             mPreviousSchedulingGroup;
diff --git a/include/media/AudioResamplerPublic.h b/include/media/AudioResamplerPublic.h
new file mode 100644
index 0000000..97847a0
--- /dev/null
+++ b/include/media/AudioResamplerPublic.h
@@ -0,0 +1,29 @@
+/*
+ * 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 ANDROID_AUDIO_RESAMPLER_PUBLIC_H
+#define ANDROID_AUDIO_RESAMPLER_PUBLIC_H
+
+// AUDIO_RESAMPLER_DOWN_RATIO_MAX is the maximum ratio between the original
+// audio sample rate and the target rate when downsampling,
+// as permitted in the audio framework, e.g. AudioTrack and AudioFlinger.
+// In practice, it is not recommended to downsample more than 6:1
+// for best audio quality, even though the audio framework permits a larger
+// downsampling ratio.
+// TODO: replace with an API
+#define AUDIO_RESAMPLER_DOWN_RATIO_MAX 256
+
+#endif // ANDROID_AUDIO_RESAMPLER_PUBLIC_H
diff --git a/include/media/AudioSystem.h b/include/media/AudioSystem.h
index 225ef76..f8c0198 100644
--- a/include/media/AudioSystem.h
+++ b/include/media/AudioSystem.h
@@ -19,6 +19,7 @@
 
 #include <hardware/audio_effect.h>
 #include <media/IAudioFlingerClient.h>
+#include <media/IAudioPolicyServiceClient.h>
 #include <system/audio.h>
 #include <system/audio_policy.h>
 #include <utils/Errors.h>
@@ -67,20 +68,24 @@
 
     // returns true in *state if tracks are active on the specified stream or have been active
     // in the past inPastMs milliseconds
-    static status_t isStreamActive(audio_stream_type_t stream, bool *state, uint32_t inPastMs = 0);
+    static status_t isStreamActive(audio_stream_type_t stream, bool *state, uint32_t inPastMs);
     // returns true in *state if tracks are active for what qualifies as remote playback
     // on the specified stream or have been active in the past inPastMs milliseconds. Remote
     // playback isn't mutually exclusive with local playback.
     static status_t isStreamActiveRemotely(audio_stream_type_t stream, bool *state,
-            uint32_t inPastMs = 0);
+            uint32_t inPastMs);
     // returns true in *state if a recorder is currently recording with the specified source
     static status_t isSourceActive(audio_source_t source, bool *state);
 
     // set/get audio hardware parameters. The function accepts a list of parameters
     // key value pairs in the form: key1=value1;key2=value2;...
     // Some keys are reserved for standard parameters (See AudioParameter class).
+    // The versions with audio_io_handle_t are intended for internal media framework use only.
     static status_t setParameters(audio_io_handle_t ioHandle, const String8& keyValuePairs);
     static String8  getParameters(audio_io_handle_t ioHandle, const String8& keys);
+    // The versions without audio_io_handle_t are intended for JNI.
+    static status_t setParameters(const String8& keyValuePairs);
+    static String8  getParameters(const String8& keys);
 
     static void setErrorCallback(audio_error_callback cb);
 
@@ -90,36 +95,37 @@
     static float linearToLog(int volume);
     static int logToLinear(float volume);
 
+    // Returned samplingRate and frameCount output values are guaranteed
+    // to be non-zero if status == NO_ERROR
     static status_t getOutputSamplingRate(uint32_t* samplingRate,
-            audio_stream_type_t stream = AUDIO_STREAM_DEFAULT);
+            audio_stream_type_t stream);
+    static status_t getOutputSamplingRateForAttr(uint32_t* samplingRate,
+                const audio_attributes_t *attr);
     static status_t getOutputFrameCount(size_t* frameCount,
-            audio_stream_type_t stream = AUDIO_STREAM_DEFAULT);
+            audio_stream_type_t stream);
     static status_t getOutputLatency(uint32_t* latency,
-            audio_stream_type_t stream = AUDIO_STREAM_DEFAULT);
+            audio_stream_type_t stream);
     static status_t getSamplingRate(audio_io_handle_t output,
-                                          audio_stream_type_t streamType,
                                           uint32_t* samplingRate);
     // returns the number of frames per audio HAL write buffer. Corresponds to
-    // audio_stream->get_buffer_size()/audio_stream_frame_size()
+    // audio_stream->get_buffer_size()/audio_stream_out_frame_size()
     static status_t getFrameCount(audio_io_handle_t output,
-                                  audio_stream_type_t stream,
                                   size_t* frameCount);
     // returns the audio output stream latency in ms. Corresponds to
     // audio_stream_out->get_latency()
     static status_t getLatency(audio_io_handle_t output,
-                               audio_stream_type_t stream,
                                uint32_t* latency);
 
     static bool routedToA2dpOutput(audio_stream_type_t streamType);
 
+    // return status NO_ERROR implies *buffSize > 0
     static status_t getInputBufferSize(uint32_t sampleRate, audio_format_t format,
         audio_channel_mask_t channelMask, size_t* buffSize);
 
     static status_t setVoiceVolume(float volume);
 
     // return the number of audio frames written by AudioFlinger to audio HAL and
-    // audio dsp to DAC since the output on which the specified stream is playing
-    // has exited standby.
+    // audio dsp to DAC since the specified output I/O handle has exited standby.
     // returned status (from utils/Errors.h) can be:
     // - NO_ERROR: successful operation, halFrames and dspFrames point to valid data
     // - INVALID_OPERATION: Not supported on current hardware platform
@@ -127,16 +133,26 @@
     // NOTE: this feature is not supported on all hardware platforms and it is
     // necessary to check returned status before using the returned values.
     static status_t getRenderPosition(audio_io_handle_t output,
-                                      size_t *halFrames,
-                                      size_t *dspFrames,
-                                      audio_stream_type_t stream = AUDIO_STREAM_DEFAULT);
+                                      uint32_t *halFrames,
+                                      uint32_t *dspFrames);
 
     // return the number of input frames lost by HAL implementation, or 0 if the handle is invalid
-    static size_t getInputFramesLost(audio_io_handle_t ioHandle);
+    static uint32_t getInputFramesLost(audio_io_handle_t ioHandle);
 
-    static int newAudioSessionId();
-    static void acquireAudioSessionId(int audioSession);
-    static void releaseAudioSessionId(int audioSession);
+    // Allocate a new unique ID for use as an audio session ID or I/O handle.
+    // If unable to contact AudioFlinger, returns AUDIO_UNIQUE_ID_ALLOCATE instead.
+    // FIXME If AudioFlinger were to ever exhaust the unique ID namespace,
+    //       this method could fail by returning either AUDIO_UNIQUE_ID_ALLOCATE
+    //       or an unspecified existing unique ID.
+    static audio_unique_id_t newAudioUniqueId();
+
+    static void acquireAudioSessionId(int audioSession, pid_t pid);
+    static void releaseAudioSessionId(int audioSession, pid_t pid);
+
+    // Get the HW synchronization source used for an audio session.
+    // Return a valid source or AUDIO_HW_SYNC_INVALID if an error occurs
+    // or no HW sync source is used.
+    static audio_hw_sync_t getAudioHwSyncForSession(audio_session_t sessionId);
 
     // types of io configuration change events received with ioConfigChanged()
     enum io_config_event {
@@ -155,7 +171,8 @@
     class OutputDescriptor {
     public:
         OutputDescriptor()
-        : samplingRate(0), format(AUDIO_FORMAT_DEFAULT), channelMask(0), frameCount(0), latency(0)  {}
+        : samplingRate(0), format(AUDIO_FORMAT_DEFAULT), channelMask(0), frameCount(0), latency(0)
+            {}
 
         uint32_t samplingRate;
         audio_format_t format;
@@ -193,27 +210,44 @@
     static status_t setPhoneState(audio_mode_t state);
     static status_t setForceUse(audio_policy_force_use_t usage, audio_policy_forced_cfg_t config);
     static audio_policy_forced_cfg_t getForceUse(audio_policy_force_use_t usage);
+
+    // Client must successfully hand off the handle reference to AudioFlinger via createTrack(),
+    // or release it with releaseOutput().
     static audio_io_handle_t getOutput(audio_stream_type_t stream,
                                         uint32_t samplingRate = 0,
                                         audio_format_t format = AUDIO_FORMAT_DEFAULT,
                                         audio_channel_mask_t channelMask = AUDIO_CHANNEL_OUT_STEREO,
                                         audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE,
                                         const audio_offload_info_t *offloadInfo = NULL);
+    static audio_io_handle_t getOutputForAttr(const audio_attributes_t *attr,
+                                        uint32_t samplingRate = 0,
+                                        audio_format_t format = AUDIO_FORMAT_DEFAULT,
+                                        audio_channel_mask_t channelMask = AUDIO_CHANNEL_OUT_STEREO,
+                                        audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE,
+                                        const audio_offload_info_t *offloadInfo = NULL);
     static status_t startOutput(audio_io_handle_t output,
                                 audio_stream_type_t stream,
-                                int session = 0);
+                                int session);
     static status_t stopOutput(audio_io_handle_t output,
                                audio_stream_type_t stream,
-                               int session = 0);
+                               int session);
     static void releaseOutput(audio_io_handle_t output);
+
+    // Client must successfully hand off the handle reference to AudioFlinger via openRecord(),
+    // or release it with releaseInput().
     static audio_io_handle_t getInput(audio_source_t inputSource,
-                                    uint32_t samplingRate = 0,
-                                    audio_format_t format = AUDIO_FORMAT_DEFAULT,
-                                    audio_channel_mask_t channelMask = AUDIO_CHANNEL_IN_MONO,
-                                    int sessionId = 0);
-    static status_t startInput(audio_io_handle_t input);
-    static status_t stopInput(audio_io_handle_t input);
-    static void releaseInput(audio_io_handle_t input);
+                                    uint32_t samplingRate,
+                                    audio_format_t format,
+                                    audio_channel_mask_t channelMask,
+                                    int sessionId,
+                                    audio_input_flags_t);
+
+    static status_t startInput(audio_io_handle_t input,
+                               audio_session_t session);
+    static status_t stopInput(audio_io_handle_t input,
+                              audio_session_t session);
+    static void releaseInput(audio_io_handle_t input,
+                             audio_session_t session);
     static status_t initStreamVolume(audio_stream_type_t stream,
                                       int indexMin,
                                       int indexMax);
@@ -255,8 +289,56 @@
     // check presence of audio flinger service.
     // returns NO_ERROR if binding to service succeeds, DEAD_OBJECT otherwise
     static status_t checkAudioFlinger();
+
+    /* List available audio ports and their attributes */
+    static status_t listAudioPorts(audio_port_role_t role,
+                                   audio_port_type_t type,
+                                   unsigned int *num_ports,
+                                   struct audio_port *ports,
+                                   unsigned int *generation);
+
+    /* Get attributes for a given audio port */
+    static status_t getAudioPort(struct audio_port *port);
+
+    /* Create an audio patch between several source and sink ports */
+    static status_t createAudioPatch(const struct audio_patch *patch,
+                                       audio_patch_handle_t *handle);
+
+    /* Release an audio patch */
+    static status_t releaseAudioPatch(audio_patch_handle_t handle);
+
+    /* List existing audio patches */
+    static status_t listAudioPatches(unsigned int *num_patches,
+                                      struct audio_patch *patches,
+                                      unsigned int *generation);
+    /* Set audio port configuration */
+    static status_t setAudioPortConfig(const struct audio_port_config *config);
+
+
+    static status_t acquireSoundTriggerSession(audio_session_t *session,
+                                           audio_io_handle_t *ioHandle,
+                                           audio_devices_t *device);
+    static status_t releaseSoundTriggerSession(audio_session_t session);
+
+    static audio_mode_t getPhoneState();
+
     // ----------------------------------------------------------------------------
 
+    class AudioPortCallback : public RefBase
+    {
+    public:
+
+                AudioPortCallback() {}
+        virtual ~AudioPortCallback() {}
+
+        virtual void onAudioPortListUpdate() = 0;
+        virtual void onAudioPatchListUpdate() = 0;
+        virtual void onServiceDied() = 0;
+
+    };
+
+    static void setAudioPortCallback(sp<AudioPortCallback> callBack);
+
 private:
 
     class AudioFlingerClient: public IBinder::DeathRecipient, public BnAudioFlingerClient
@@ -275,7 +357,8 @@
         virtual void ioConfigChanged(int event, audio_io_handle_t ioHandle, const void *param2);
     };
 
-    class AudioPolicyServiceClient: public IBinder::DeathRecipient
+    class AudioPolicyServiceClient: public IBinder::DeathRecipient,
+                                    public BnAudioPolicyServiceClient
     {
     public:
         AudioPolicyServiceClient() {
@@ -283,6 +366,10 @@
 
         // DeathRecipient
         virtual void binderDied(const wp<IBinder>& who);
+
+        // IAudioPolicyServiceClient
+        virtual void onAudioPortListUpdate();
+        virtual void onAudioPatchListUpdate();
     };
 
     static sp<AudioFlingerClient> gAudioFlingerClient;
@@ -302,11 +389,11 @@
 
     static sp<IAudioPolicyService> gAudioPolicyService;
 
-    // mapping between stream types and outputs
-    static DefaultKeyedVector<audio_stream_type_t, audio_io_handle_t> gStreamOutputMap;
     // list of output descriptors containing cached parameters
     // (sampling rate, framecount, channel count...)
     static DefaultKeyedVector<audio_io_handle_t, OutputDescriptor *> gOutputs;
+
+    static sp<AudioPortCallback> gAudioPortCallback;
 };
 
 };  // namespace android
diff --git a/include/media/AudioTimestamp.h b/include/media/AudioTimestamp.h
index c29c7e5..99e9c3e 100644
--- a/include/media/AudioTimestamp.h
+++ b/include/media/AudioTimestamp.h
@@ -19,6 +19,8 @@
 
 #include <time.h>
 
+namespace android {
+
 class AudioTimestamp {
 public:
     AudioTimestamp() : mPosition(0) {
@@ -30,4 +32,6 @@
     struct timespec mTime;     // corresponding CLOCK_MONOTONIC when frame is expected to present
 };
 
+}   // namespace
+
 #endif  // ANDROID_AUDIO_TIMESTAMP_H
diff --git a/include/media/AudioTrack.h b/include/media/AudioTrack.h
index 4736369..b5256f0 100644
--- a/include/media/AudioTrack.h
+++ b/include/media/AudioTrack.h
@@ -27,7 +27,7 @@
 
 // ----------------------------------------------------------------------------
 
-class audio_track_cblk_t;
+struct audio_track_cblk_t;
 class AudioTrackClientProxy;
 class StaticAudioTrackClientProxy;
 
@@ -36,11 +36,6 @@
 class AudioTrack : public RefBase
 {
 public:
-    enum channel_index {
-        MONO   = 0,
-        LEFT   = 0,
-        RIGHT  = 1
-    };
 
     /* Events used by AudioTrack callback function (callback_t).
      * Keep in sync with frameworks/base/media/java/android/media/AudioTrack.java NATIVE_EVENT_*.
@@ -82,6 +77,7 @@
                                   // (currently ignored, but will make the primary field in future)
 
         size_t      size;         // input/output in bytes == frameCount * frameSize
+                                  // on input it is unused
                                   // on output is the number of bytes actually filled
                                   // FIXME this is redundant with respect to frameCount,
                                   // and TRANSFER_OBTAIN mode is broken for 8-bit data
@@ -91,7 +87,7 @@
             void*       raw;
             short*      i16;      // signed 16-bit
             int8_t*     i8;       // unsigned 8-bit, offset by 0x80
-        };
+        };                        // input: unused, output: pointer to buffer
     };
 
     /* As a convenience, if a callback is supplied, a handler thread
@@ -123,6 +119,8 @@
      *  - NO_ERROR: successful operation
      *  - NO_INIT: audio server or audio hardware not initialized
      *  - BAD_VALUE: unsupported configuration
+     * frameCount is guaranteed to be non-zero if status is NO_ERROR,
+     * and is undefined otherwise.
      */
 
     static status_t getMinFrameCount(size_t* frameCount,
@@ -156,9 +154,10 @@
      * streamType:         Select the type of audio stream this track is attached to
      *                     (e.g. AUDIO_STREAM_MUSIC).
      * sampleRate:         Data source sampling rate in Hz.
-     * format:             Audio format (e.g AUDIO_FORMAT_PCM_16_BIT for signed
-     *                     16 bits per sample).
-     * channelMask:        Channel mask.
+     * format:             Audio format.  For mixed tracks, any PCM format supported by server is OK
+     *                     or AUDIO_FORMAT_PCM_8_BIT which is handled on client side.  For direct
+     *                     and offloaded tracks, the possible format(s) depends on the output sink.
+     * channelMask:        Channel mask, such that audio_is_output_channel(channelMask) is true.
      * frameCount:         Minimum size of track PCM buffer in frames. This defines the
      *                     application's contribution to the
      *                     latency of the track. The actual size selected by the AudioTrack could be
@@ -180,15 +179,17 @@
                                     uint32_t sampleRate,
                                     audio_format_t format,
                                     audio_channel_mask_t,
-                                    int frameCount       = 0,
+                                    size_t frameCount    = 0,
                                     audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE,
                                     callback_t cbf       = NULL,
                                     void* user           = NULL,
-                                    int notificationFrames = 0,
-                                    int sessionId        = 0,
+                                    uint32_t notificationFrames = 0,
+                                    int sessionId        = AUDIO_SESSION_ALLOCATE,
                                     transfer_type transferType = TRANSFER_DEFAULT,
                                     const audio_offload_info_t *offloadInfo = NULL,
-                                    int uid = -1);
+                                    int uid = -1,
+                                    pid_t pid = -1,
+                                    const audio_attributes_t* pAttributes = NULL);
 
     /* Creates an audio track and registers it with AudioFlinger.
      * With this constructor, the track is configured for static buffer mode.
@@ -209,11 +210,13 @@
                                     audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE,
                                     callback_t cbf      = NULL,
                                     void* user          = NULL,
-                                    int notificationFrames = 0,
-                                    int sessionId       = 0,
+                                    uint32_t notificationFrames = 0,
+                                    int sessionId       = AUDIO_SESSION_ALLOCATE,
                                     transfer_type transferType = TRANSFER_DEFAULT,
                                     const audio_offload_info_t *offloadInfo = NULL,
-                                    int uid = -1);
+                                    int uid = -1,
+                                    pid_t pid = -1,
+                                    const audio_attributes_t* pAttributes = NULL);
 
     /* Terminates the AudioTrack and unregisters it from AudioFlinger.
      * Also destroys all resources associated with the AudioTrack.
@@ -241,17 +244,19 @@
                             uint32_t sampleRate,
                             audio_format_t format,
                             audio_channel_mask_t channelMask,
-                            int frameCount      = 0,
+                            size_t frameCount   = 0,
                             audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE,
                             callback_t cbf      = NULL,
                             void* user          = NULL,
-                            int notificationFrames = 0,
+                            uint32_t notificationFrames = 0,
                             const sp<IMemory>& sharedBuffer = 0,
                             bool threadCanCallJava = false,
-                            int sessionId       = 0,
+                            int sessionId       = AUDIO_SESSION_ALLOCATE,
                             transfer_type transferType = TRANSFER_DEFAULT,
                             const audio_offload_info_t *offloadInfo = NULL,
-                            int uid = -1);
+                            int uid = -1,
+                            pid_t pid = -1,
+                            const audio_attributes_t* pAttributes = NULL);
 
     /* Result of constructing the AudioTrack. This must be checked for successful initialization
      * before using any AudioTrack API (except for set()), because using
@@ -279,7 +284,7 @@
             size_t      frameSize() const   { return mFrameSize; }
 
             uint32_t    channelCount() const { return mChannelCount; }
-            uint32_t    frameCount() const  { return mFrameCount; }
+            size_t      frameCount() const  { return mFrameCount; }
 
     /* Return the static buffer specified in constructor or set(), or 0 for streaming mode */
             sp<IMemory> sharedBuffer() const { return mSharedBuffer; }
@@ -336,7 +341,7 @@
      */
             status_t    setSampleRate(uint32_t sampleRate);
 
-    /* Return current source sample rate in Hz, or 0 if unknown */
+    /* Return current source sample rate in Hz */
             uint32_t    getSampleRate() const;
 
     /* Enables looping and sets the start and end points of looping.
@@ -361,7 +366,7 @@
     /* Sets marker position. When playback reaches the number of frames specified, a callback with
      * event type EVENT_MARKER is called. Calling setMarkerPosition with marker == 0 cancels marker
      * notification callback.  To set a marker at a position which would compute as 0,
-     * a workaround is to the set the marker at a nearby position such as ~0 or 1.
+     * a workaround is to set the marker at a nearby position such as ~0 or 1.
      * If the AudioTrack has been opened with no callback function associated, the operation will
      * fail.
      *
@@ -425,7 +430,7 @@
      *  - NO_ERROR: successful operation
      *  - BAD_VALUE:  position is NULL
      */
-            status_t    getPosition(uint32_t *position) const;
+            status_t    getPosition(uint32_t *position);
 
     /* For static buffer mode only, this returns the current playback position in frames
      * relative to start of buffer.  It is analogous to the position units used by
@@ -450,9 +455,10 @@
      *  none.
      *
      * Returned value:
-     *  handle on audio hardware output
+     *  handle on audio hardware output, or AUDIO_IO_HANDLE_NONE if the
+     *  track needed to be re-created but that failed
      */
-            audio_io_handle_t    getOutput();
+            audio_io_handle_t    getOutput() const;
 
     /* Returns the unique session ID associated with this track.
      *
@@ -528,15 +534,6 @@
                                      struct timespec *elapsed = NULL, size_t *nonContig = NULL);
 public:
 
-//EL_FIXME to be reconciled with new obtainBuffer() return codes and control block proxy
-//            enum {
-//            NO_MORE_BUFFERS = 0x80000001,   // same name in AudioFlinger.h, ok to be different value
-//            TEAR_DOWN       = 0x80000002,
-//            STOPPED = 1,
-//            STREAM_END_WAIT,
-//            STREAM_END
-//        };
-
     /* Release a filled buffer of "audioBuffer->frameCount" frames for AudioFlinger to process. */
     // FIXME make private when obtainBuffer() for TRANSFER_OBTAIN is removed
             void        releaseBuffer(Buffer* audioBuffer);
@@ -551,8 +548,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.
@@ -566,7 +566,7 @@
             uint32_t    getUnderrunFrames() const;
 
     /* Get the flags */
-            audio_output_flags_t getFlags() const { return mFlags; }
+            audio_output_flags_t getFlags() const { AutoMutex _l(mLock); return mFlags; }
 
     /* Set parameters - only possible when using direct output */
             status_t    setParameters(const String8& keyValuePairs);
@@ -580,7 +580,15 @@
      * Caution: calling this method too often may be inefficient;
      * if you need a high resolution mapping between frame position and presentation time,
      * consider implementing that at application level, based on the low resolution timestamps.
-     * Returns NO_ERROR if timestamp is valid.
+     * Returns NO_ERROR    if timestamp is valid.
+     *         WOULD_BLOCK if called in STOPPED or FLUSHED state, or if called immediately after
+     *                     start/ACTIVE, when the number of frames consumed is less than the
+     *                     overall hardware latency to physical output. In WOULD_BLOCK cases,
+     *                     one might poll again, or use getPosition(), or use 0 position and
+     *                     current time for the timestamp.
+     *         INVALID_OPERATION  if called on a FastTrack, wrong state, or some other error.
+     *
+     * The timestamp parameter is undefined on return, if status is not NO_ERROR.
      */
             status_t    getTimestamp(AudioTimestamp& timestamp);
 
@@ -589,6 +597,11 @@
                         AudioTrack(const AudioTrack& other);
             AudioTrack& operator = (const AudioTrack& other);
 
+            void        setAttributesFromStreamType(audio_stream_type_t streamType);
+            void        setStreamTypeFromAttributes(audio_attributes_t& aa);
+    /* paa is guaranteed non-NULL */
+            bool        isValidAttributes(const audio_attributes_t *paa);
+
     /* a small internal class to handle the callback */
     class AudioTrackThread : public Thread
     {
@@ -626,53 +639,63 @@
             //      NS_INACTIVE inactive so don't run again until re-started
             //      NS_NEVER    never again
             static const nsecs_t NS_WHENEVER = -1, NS_INACTIVE = -2, NS_NEVER = -3;
-            nsecs_t processAudioBuffer(const sp<AudioTrackThread>& thread);
-            status_t processStreamEnd(int32_t waitCount);
+            nsecs_t processAudioBuffer();
 
+            bool     isOffloaded() const;
+            bool     isDirect() const;
+            bool     isOffloadedOrDirect() const;
 
             // caller must hold lock on mLock for all _l methods
 
-            status_t createTrack_l(audio_stream_type_t streamType,
-                                 uint32_t sampleRate,
-                                 audio_format_t format,
-                                 size_t frameCount,
-                                 audio_output_flags_t flags,
-                                 const sp<IMemory>& sharedBuffer,
-                                 audio_io_handle_t output,
-                                 size_t epoch);
+            status_t createTrack_l();
 
             // can only be called when mState != STATE_ACTIVE
             void flush_l();
 
             void setLoop_l(uint32_t loopStart, uint32_t loopEnd, int loopCount);
-            audio_io_handle_t getOutput_l();
 
             // FIXME enum is faster than strcmp() for parameter 'from'
             status_t restoreTrack_l(const char *from);
 
-            bool     isOffloaded() const
+            bool     isOffloaded_l() const
                 { return (mFlags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) != 0; }
 
-    // Next 3 fields may be changed if IAudioTrack is re-created, but always != 0
+            bool     isOffloadedOrDirect_l() const
+                { return (mFlags & (AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD|
+                                                AUDIO_OUTPUT_FLAG_DIRECT)) != 0; }
+
+            bool     isDirect_l() const
+                { return (mFlags & AUDIO_OUTPUT_FLAG_DIRECT) != 0; }
+
+            // increment mPosition by the delta of mServer, and return new value of mPosition
+            uint32_t updateAndGetPosition_l();
+
+    // Next 4 fields may be changed if IAudioTrack is re-created, but always != 0
     sp<IAudioTrack>         mAudioTrack;
     sp<IMemory>             mCblkMemory;
     audio_track_cblk_t*     mCblk;                  // re-load after mLock.unlock()
+    audio_io_handle_t       mOutput;                // returned by AudioSystem::getOutput()
 
     sp<AudioTrackThread>    mAudioTrackThread;
+
     float                   mVolume[2];
     float                   mSendLevel;
     mutable uint32_t        mSampleRate;            // mutable because getSampleRate() can update it.
-    size_t                  mFrameCount;            // corresponds to current IAudioTrack
-    size_t                  mReqFrameCount;         // frame count to request the next time a new
-                                                    // IAudioTrack is needed
-
+    size_t                  mFrameCount;            // corresponds to current IAudioTrack, value is
+                                                    // reported back by AudioFlinger to the client
+    size_t                  mReqFrameCount;         // frame count to request the first or next time
+                                                    // a new IAudioTrack is needed, non-decreasing
 
     // constant after constructor or set()
     audio_format_t          mFormat;                // as requested by client, not forced to 16-bit
     audio_stream_type_t     mStreamType;
     uint32_t                mChannelCount;
     audio_channel_mask_t    mChannelMask;
+    sp<IMemory>             mSharedBuffer;
     transfer_type           mTransfer;
+    audio_offload_info_t    mOffloadInfoCopy;
+    const audio_offload_info_t* mOffloadInfo;
+    audio_attributes_t      mAttributes;
 
     // mFrameSize is equal to mFrameSizeAF for non-PCM or 16-bit PCM data.  For 8-bit PCM data, it's
     // twice as large as mFrameSize because data is expanded to 16-bit before it's stored in buffer.
@@ -705,21 +728,39 @@
     uint32_t                mNotificationFramesAct; // actual number of frames between each
                                                     // notification callback,
                                                     // at initial source sample rate
-    bool                    mRefreshRemaining;      // processAudioBuffer() should refresh next 2
+    bool                    mRefreshRemaining;      // processAudioBuffer() should refresh
+                                                    // mRemainingFrames and mRetryOnPartialBuffer
 
     // These are private to processAudioBuffer(), and are not protected by a lock
     uint32_t                mRemainingFrames;       // number of frames to request in obtainBuffer()
     bool                    mRetryOnPartialBuffer;  // sleep and retry after partial obtainBuffer()
     uint32_t                mObservedSequence;      // last observed value of mSequence
 
-    sp<IMemory>             mSharedBuffer;
     uint32_t                mLoopPeriod;            // in frames, zero means looping is disabled
+
     uint32_t                mMarkerPosition;        // in wrapping (overflow) frame units
     bool                    mMarkerReached;
     uint32_t                mNewPosition;           // in frames
     uint32_t                mUpdatePeriod;          // in frames, zero means no EVENT_NEW_POS
+    uint32_t                mServer;                // in frames, last known mProxy->getPosition()
+                                                    // which is count of frames consumed by server,
+                                                    // reset by new IAudioTrack,
+                                                    // whether it is reset by stop() is TBD
+    uint32_t                mPosition;              // in frames, like mServer except continues
+                                                    // monotonically after new IAudioTrack,
+                                                    // and could be easily widened to uint64_t
+    uint32_t                mReleased;              // in frames, count of frames released to server
+                                                    // but not necessarily consumed by server,
+                                                    // reset by stop() but continues monotonically
+                                                    // after new IAudioTrack to restore mPosition,
+                                                    // and could be easily widened to uint64_t
+    int64_t                 mStartUs;               // the start time after flush or stop.
+                                                    // only used for offloaded and direct tracks.
 
     audio_output_flags_t    mFlags;
+        // const after set(), except for bits AUDIO_OUTPUT_FLAG_FAST and AUDIO_OUTPUT_FLAG_OFFLOAD.
+        // mLock must be held to read or write those bits reliably.
+
     int                     mSessionId;
     int                     mAuxEffectId;
 
@@ -739,7 +780,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:
@@ -754,8 +794,8 @@
 
     sp<DeathNotifier>       mDeathNotifier;
     uint32_t                mSequence;              // incremented for each new IAudioTrack attempt
-    audio_io_handle_t       mOutput;                // cached output io handle
     int                     mClientUid;
+    pid_t                   mClientPid;
 };
 
 class TimedAudioTrack : public AudioTrack
diff --git a/include/media/CharacterEncodingDetector.h b/include/media/CharacterEncodingDetector.h
new file mode 100644
index 0000000..deaa377
--- /dev/null
+++ b/include/media/CharacterEncodingDetector.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _CHARACTER_ENCODING_DETECTOR_H
+#define _CHARACTER_ENCODING_DETECTOR_H
+
+#include <media/mediascanner.h>
+
+#include "StringArray.h"
+
+#include "unicode/ucnv.h"
+#include "unicode/ucsdet.h"
+#include "unicode/ustring.h"
+
+namespace android {
+
+class CharacterEncodingDetector {
+
+    public:
+    CharacterEncodingDetector();
+        ~CharacterEncodingDetector();
+
+        void addTag(const char *name, const char *value);
+        size_t size();
+
+        void detectAndConvert();
+        status_t getTag(int index, const char **name, const char**value);
+
+    private:
+        const UCharsetMatch *getPreferred(
+                const char *input, size_t len,
+                const UCharsetMatch** ucma, size_t matches,
+                bool *goodmatch, int *highestmatch);
+
+        bool isFrequent(const uint16_t *values, uint32_t c);
+
+        // cached name and value strings, for native encoding support.
+        // TODO: replace these with byte blob arrays that don't require the data to be
+        // singlenullbyte-terminated
+        StringArray     mNames;
+        StringArray     mValues;
+
+        UConverter*     mUtf8Conv;
+};
+
+
+
+};  // namespace android
+
+#endif
diff --git a/include/media/IAudioFlinger.h b/include/media/IAudioFlinger.h
index 899d79f..31a14f0 100644
--- a/include/media/IAudioFlinger.h
+++ b/include/media/IAudioFlinger.h
@@ -50,6 +50,7 @@
         TRACK_TIMED   = 1,  // client requests a TimedAudioTrack
         TRACK_FAST    = 2,  // client requests a fast AudioTrack or AudioRecord
         TRACK_OFFLOAD = 4,  // client requests offload to hw codec
+        TRACK_DIRECT = 8,   // client requests a direct output
     };
     typedef uint32_t track_flags_t;
 
@@ -64,37 +65,39 @@
                                 uint32_t sampleRate,
                                 audio_format_t format,
                                 audio_channel_mask_t channelMask,
-                                size_t frameCount,
+                                size_t *pFrameCount,
                                 track_flags_t *flags,
                                 const sp<IMemory>& sharedBuffer,
+                                // On successful return, AudioFlinger takes over the handle
+                                // reference and will release it when the track is destroyed.
+                                // However on failure, the client is responsible for release.
                                 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;
 
     virtual sp<IAudioRecord> openRecord(
+                                // On successful return, AudioFlinger takes over the handle
+                                // reference and will release it when the track is destroyed.
+                                // However on failure, the client is responsible for release.
                                 audio_io_handle_t input,
                                 uint32_t sampleRate,
                                 audio_format_t format,
                                 audio_channel_mask_t channelMask,
-                                size_t frameCount,
+                                size_t *pFrameCount,
                                 track_flags_t *flags,
                                 pid_t tid,  // -1 means unused, otherwise must be valid non-0
                                 int *sessionId,
+                                size_t *notificationFrames,
+                                sp<IMemory>& cblk,
+                                sp<IMemory>& buffers,   // return value 0 means it follows cblk
                                 status_t *status) = 0;
 
     /* query the audio hardware state. This state never changes,
      * and therefore can be cached.
      */
     virtual     uint32_t    sampleRate(audio_io_handle_t output) const = 0;
-#if 0
-    virtual     int         channelCount(audio_io_handle_t output) const = 0;
-#endif
     virtual     audio_format_t format(audio_io_handle_t output) const = 0;
     virtual     size_t      frameCount(audio_io_handle_t output) const = 0;
 
@@ -142,40 +145,41 @@
     virtual size_t getInputBufferSize(uint32_t sampleRate, audio_format_t format,
             audio_channel_mask_t channelMask) const = 0;
 
-    virtual audio_io_handle_t openOutput(audio_module_handle_t module,
-                                         audio_devices_t *pDevices,
-                                         uint32_t *pSamplingRate,
-                                         audio_format_t *pFormat,
-                                         audio_channel_mask_t *pChannelMask,
-                                         uint32_t *pLatencyMs,
-                                         audio_output_flags_t flags,
-                                         const audio_offload_info_t *offloadInfo = NULL) = 0;
+    virtual status_t openOutput(audio_module_handle_t module,
+                                audio_io_handle_t *output,
+                                audio_config_t *config,
+                                audio_devices_t *devices,
+                                const String8& address,
+                                uint32_t *latencyMs,
+                                audio_output_flags_t flags) = 0;
     virtual audio_io_handle_t openDuplicateOutput(audio_io_handle_t output1,
                                     audio_io_handle_t output2) = 0;
     virtual status_t closeOutput(audio_io_handle_t output) = 0;
     virtual status_t suspendOutput(audio_io_handle_t output) = 0;
     virtual status_t restoreOutput(audio_io_handle_t output) = 0;
 
-    virtual audio_io_handle_t openInput(audio_module_handle_t module,
-                                        audio_devices_t *pDevices,
-                                        uint32_t *pSamplingRate,
-                                        audio_format_t *pFormat,
-                                        audio_channel_mask_t *pChannelMask) = 0;
+    virtual status_t openInput(audio_module_handle_t module,
+                               audio_io_handle_t *input,
+                               audio_config_t *config,
+                               audio_devices_t *device,
+                               const String8& address,
+                               audio_source_t source,
+                               audio_input_flags_t flags) = 0;
     virtual status_t closeInput(audio_io_handle_t input) = 0;
 
-    virtual status_t setStreamOutput(audio_stream_type_t stream, audio_io_handle_t output) = 0;
+    virtual status_t invalidateStream(audio_stream_type_t stream) = 0;
 
     virtual status_t setVoiceVolume(float volume) = 0;
 
-    virtual status_t getRenderPosition(size_t *halFrames, size_t *dspFrames,
+    virtual status_t getRenderPosition(uint32_t *halFrames, uint32_t *dspFrames,
                                     audio_io_handle_t output) const = 0;
 
-    virtual size_t getInputFramesLost(audio_io_handle_t ioHandle) const = 0;
+    virtual uint32_t getInputFramesLost(audio_io_handle_t ioHandle) const = 0;
 
-    virtual int newAudioSessionId() = 0;
+    virtual audio_unique_id_t newAudioUniqueId() = 0;
 
-    virtual void acquireAudioSessionId(int audioSession) = 0;
-    virtual void releaseAudioSessionId(int audioSession) = 0;
+    virtual void acquireAudioSessionId(int audioSession, pid_t pid) = 0;
+    virtual void releaseAudioSessionId(int audioSession, pid_t pid) = 0;
 
     virtual status_t queryNumberEffects(uint32_t *numEffects) const = 0;
 
@@ -188,6 +192,7 @@
                                     effect_descriptor_t *pDesc,
                                     const sp<IEffectClient>& client,
                                     int32_t priority,
+                                    // AudioFlinger doesn't take over handle reference from client
                                     audio_io_handle_t output,
                                     int sessionId,
                                     status_t *status,
@@ -209,6 +214,29 @@
     // and should be called at most once.  For a definition of what "low RAM" means, see
     // android.app.ActivityManager.isLowRamDevice().
     virtual status_t setLowRamDevice(bool isLowRamDevice) = 0;
+
+    /* List available audio ports and their attributes */
+    virtual status_t listAudioPorts(unsigned int *num_ports,
+                                    struct audio_port *ports) = 0;
+
+    /* Get attributes for a given audio port */
+    virtual status_t getAudioPort(struct audio_port *port) = 0;
+
+    /* Create an audio patch between several source and sink ports */
+    virtual status_t createAudioPatch(const struct audio_patch *patch,
+                                       audio_patch_handle_t *handle) = 0;
+
+    /* Release an audio patch */
+    virtual status_t releaseAudioPatch(audio_patch_handle_t handle) = 0;
+
+    /* List existing audio patches */
+    virtual status_t listAudioPatches(unsigned int *num_patches,
+                                      struct audio_patch *patches) = 0;
+    /* Set audio port configuration */
+    virtual status_t setAudioPortConfig(const struct audio_port_config *config) = 0;
+
+    /* Get the HW synchronization source used for an audio session */
+    virtual audio_hw_sync_t getAudioHwSyncForSession(audio_session_t sessionId) = 0;
 };
 
 
diff --git a/include/media/IAudioPolicyService.h b/include/media/IAudioPolicyService.h
index 09b9ea6..16fe9cf 100644
--- a/include/media/IAudioPolicyService.h
+++ b/include/media/IAudioPolicyService.h
@@ -25,6 +25,7 @@
 #include <utils/Errors.h>
 #include <binder/IInterface.h>
 #include <media/AudioSystem.h>
+#include <media/IAudioPolicyServiceClient.h>
 
 #include <system/audio_policy.h>
 
@@ -55,6 +56,12 @@
                                         audio_channel_mask_t channelMask = 0,
                                         audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE,
                                         const audio_offload_info_t *offloadInfo = NULL) = 0;
+    virtual audio_io_handle_t getOutputForAttr(const audio_attributes_t *attr,
+                                            uint32_t samplingRate = 0,
+                                            audio_format_t format = AUDIO_FORMAT_DEFAULT,
+                                            audio_channel_mask_t channelMask = 0,
+                                            audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE,
+                                            const audio_offload_info_t *offloadInfo = NULL) = 0;
     virtual status_t startOutput(audio_io_handle_t output,
                                  audio_stream_type_t stream,
                                  int session = 0) = 0;
@@ -63,13 +70,17 @@
                                 int session = 0) = 0;
     virtual void releaseOutput(audio_io_handle_t output) = 0;
     virtual audio_io_handle_t getInput(audio_source_t inputSource,
-                                    uint32_t samplingRate = 0,
-                                    audio_format_t format = AUDIO_FORMAT_DEFAULT,
-                                    audio_channel_mask_t channelMask = 0,
-                                    int audioSession = 0) = 0;
-    virtual status_t startInput(audio_io_handle_t input) = 0;
-    virtual status_t stopInput(audio_io_handle_t input) = 0;
-    virtual void releaseInput(audio_io_handle_t input) = 0;
+                                    uint32_t samplingRate,
+                                    audio_format_t format,
+                                    audio_channel_mask_t channelMask,
+                                    int audioSession,
+                                    audio_input_flags_t flags) = 0;
+    virtual status_t startInput(audio_io_handle_t input,
+                                audio_session_t session) = 0;
+    virtual status_t stopInput(audio_io_handle_t input,
+                               audio_session_t session) = 0;
+    virtual void releaseInput(audio_io_handle_t input,
+                              audio_session_t session) = 0;
     virtual status_t initStreamVolume(audio_stream_type_t stream,
                                       int indexMin,
                                       int indexMax) = 0;
@@ -99,6 +110,40 @@
    // Check if offload is possible for given format, stream type, sample rate,
     // bit rate, duration, video and streaming or offload property is enabled
     virtual bool isOffloadSupported(const audio_offload_info_t& info) = 0;
+
+    /* List available audio ports and their attributes */
+    virtual status_t listAudioPorts(audio_port_role_t role,
+                                    audio_port_type_t type,
+                                    unsigned int *num_ports,
+                                    struct audio_port *ports,
+                                    unsigned int *generation) = 0;
+
+    /* Get attributes for a given audio port */
+    virtual status_t getAudioPort(struct audio_port *port) = 0;
+
+    /* Create an audio patch between several source and sink ports */
+    virtual status_t createAudioPatch(const struct audio_patch *patch,
+                                       audio_patch_handle_t *handle) = 0;
+
+    /* Release an audio patch */
+    virtual status_t releaseAudioPatch(audio_patch_handle_t handle) = 0;
+
+    /* List existing audio patches */
+    virtual status_t listAudioPatches(unsigned int *num_patches,
+                                      struct audio_patch *patches,
+                                      unsigned int *generation) = 0;
+    /* Set audio port configuration */
+    virtual status_t setAudioPortConfig(const struct audio_port_config *config) = 0;
+
+    virtual void registerClient(const sp<IAudioPolicyServiceClient>& client) = 0;
+
+    virtual status_t acquireSoundTriggerSession(audio_session_t *session,
+                                           audio_io_handle_t *ioHandle,
+                                           audio_devices_t *device) = 0;
+
+    virtual status_t releaseSoundTriggerSession(audio_session_t session) = 0;
+
+    virtual audio_mode_t getPhoneState() = 0;
 };
 
 
diff --git a/include/media/IAudioPolicyServiceClient.h b/include/media/IAudioPolicyServiceClient.h
new file mode 100644
index 0000000..59df046
--- /dev/null
+++ b/include/media/IAudioPolicyServiceClient.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_IAUDIOPOLICYSERVICECLIENT_H
+#define ANDROID_IAUDIOPOLICYSERVICECLIENT_H
+
+
+#include <utils/RefBase.h>
+#include <binder/IInterface.h>
+#include <system/audio.h>
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+class IAudioPolicyServiceClient : public IInterface
+{
+public:
+    DECLARE_META_INTERFACE(AudioPolicyServiceClient);
+
+    // Notifies a change of audio port configuration.
+    virtual void onAudioPortListUpdate() = 0;
+    // Notifies a change of audio patch configuration.
+    virtual void onAudioPatchListUpdate() = 0;
+};
+
+
+// ----------------------------------------------------------------------------
+
+class BnAudioPolicyServiceClient : public BnInterface<IAudioPolicyServiceClient>
+{
+public:
+    virtual status_t    onTransact( uint32_t code,
+                                    const Parcel& data,
+                                    Parcel* reply,
+                                    uint32_t flags = 0);
+};
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_IAUDIOPOLICYSERVICECLIENT_H
diff --git a/include/media/IAudioRecord.h b/include/media/IAudioRecord.h
index eccc2ca..2003985 100644
--- a/include/media/IAudioRecord.h
+++ b/include/media/IAudioRecord.h
@@ -34,9 +34,6 @@
 public:
     DECLARE_META_INTERFACE(AudioRecord);
 
-    /* get this tracks control block */
-    virtual sp<IMemory> getCblk() const = 0;
-
     /* After it's created the track is not active. Call start() to
      * make it active.
      */
diff --git a/include/media/IAudioTrack.h b/include/media/IAudioTrack.h
index 5c8a484..619ac78 100644
--- a/include/media/IAudioTrack.h
+++ b/include/media/IAudioTrack.h
@@ -88,7 +88,7 @@
     /* Send parameters to the audio hardware */
     virtual status_t    setParameters(const String8& keyValuePairs) = 0;
 
-    /* Return NO_ERROR if timestamp is valid */
+    /* Return NO_ERROR if timestamp is valid.  timestamp is undefined otherwise. */
     virtual status_t    getTimestamp(AudioTimestamp& timestamp) = 0;
 
     /* Signal the playback thread for a change in control block */
diff --git a/include/media/IDrm.h b/include/media/IDrm.h
index 32ae28e..68de87a 100644
--- a/include/media/IDrm.h
+++ b/include/media/IDrm.h
@@ -70,6 +70,8 @@
                                               Vector<uint8_t> &certificate,
                                               Vector<uint8_t> &wrappedKey) = 0;
 
+    virtual status_t unprovisionDevice() = 0;
+
     virtual status_t getSecureStops(List<Vector<uint8_t> > &secureStops) = 0;
 
     virtual status_t releaseSecureStops(Vector<uint8_t> const &ssRelease) = 0;
diff --git a/include/media/IMediaCodecList.h b/include/media/IMediaCodecList.h
new file mode 100644
index 0000000..e93ea8b
--- /dev/null
+++ b/include/media/IMediaCodecList.h
@@ -0,0 +1,55 @@
+/*
+ * 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 ANDROID_IMEDIACODECLIST_H
+#define ANDROID_IMEDIACODECLIST_H
+
+#include <utils/Errors.h>  // for status_t
+#include <binder/IInterface.h>
+#include <binder/Parcel.h>
+
+namespace android {
+
+struct MediaCodecInfo;
+
+class IMediaCodecList: public IInterface
+{
+public:
+    DECLARE_META_INTERFACE(MediaCodecList);
+
+    virtual size_t countCodecs() const = 0;
+    virtual sp<MediaCodecInfo> getCodecInfo(size_t index) const = 0;
+
+    virtual ssize_t findCodecByType(
+            const char *type, bool encoder, size_t startIndex = 0) const = 0;
+
+    virtual ssize_t findCodecByName(const char *name) const = 0;
+};
+
+// ----------------------------------------------------------------------------
+
+class BnMediaCodecList: public BnInterface<IMediaCodecList>
+{
+public:
+    virtual status_t    onTransact( uint32_t code,
+                                    const Parcel& data,
+                                    Parcel* reply,
+                                    uint32_t flags = 0);
+};
+
+}; // namespace android
+
+#endif // ANDROID_IMEDIACODECLIST_H
diff --git a/include/media/IMediaHTTPConnection.h b/include/media/IMediaHTTPConnection.h
new file mode 100644
index 0000000..2a63eb7
--- /dev/null
+++ b/include/media/IMediaHTTPConnection.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef I_MEDIA_HTTP_CONNECTION_H_
+
+#define I_MEDIA_HTTP_CONNECTION_H_
+
+#include <binder/IInterface.h>
+#include <media/stagefright/foundation/ABase.h>
+#include <utils/KeyedVector.h>
+
+namespace android {
+
+struct IMediaHTTPConnection;
+
+/** MUST stay in sync with IMediaHTTPConnection.aidl */
+
+struct IMediaHTTPConnection : public IInterface {
+    DECLARE_META_INTERFACE(MediaHTTPConnection);
+
+    virtual bool connect(
+            const char *uri, const KeyedVector<String8, String8> *headers) = 0;
+
+    virtual void disconnect() = 0;
+    virtual ssize_t readAt(off64_t offset, void *data, size_t size) = 0;
+    virtual off64_t getSize() = 0;
+    virtual status_t getMIMEType(String8 *mimeType) = 0;
+    virtual status_t getUri(String8 *uri) = 0;
+
+private:
+    DISALLOW_EVIL_CONSTRUCTORS(IMediaHTTPConnection);
+};
+
+}  // namespace android
+
+#endif  // I_MEDIA_HTTP_CONNECTION_H_
diff --git a/include/media/IMediaHTTPService.h b/include/media/IMediaHTTPService.h
new file mode 100644
index 0000000..f66d6c8
--- /dev/null
+++ b/include/media/IMediaHTTPService.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef I_MEDIA_HTTP_SERVICE_H_
+
+#define I_MEDIA_HTTP_SERVICE_H_
+
+#include <binder/IInterface.h>
+#include <media/stagefright/foundation/ABase.h>
+
+namespace android {
+
+struct IMediaHTTPConnection;
+
+/** MUST stay in sync with IMediaHTTPService.aidl */
+
+struct IMediaHTTPService : public IInterface {
+    DECLARE_META_INTERFACE(MediaHTTPService);
+
+    virtual sp<IMediaHTTPConnection> makeHTTPConnection() = 0;
+
+private:
+    DISALLOW_EVIL_CONSTRUCTORS(IMediaHTTPService);
+};
+
+}  // namespace android
+
+#endif  // I_MEDIA_HTTP_SERVICE_H_
diff --git a/include/media/IMediaMetadataRetriever.h b/include/media/IMediaMetadataRetriever.h
index 6dbb2d7..2529800 100644
--- a/include/media/IMediaMetadataRetriever.h
+++ b/include/media/IMediaMetadataRetriever.h
@@ -26,6 +26,8 @@
 
 namespace android {
 
+struct IMediaHTTPService;
+
 class IMediaMetadataRetriever: public IInterface
 {
 public:
@@ -33,6 +35,7 @@
     virtual void            disconnect() = 0;
 
     virtual status_t        setDataSource(
+            const sp<IMediaHTTPService> &httpService,
             const char *srcUrl,
             const KeyedVector<String8, String8> *headers = NULL) = 0;
 
diff --git a/include/media/IMediaPlayer.h b/include/media/IMediaPlayer.h
index 0cbd269..db62cd5 100644
--- a/include/media/IMediaPlayer.h
+++ b/include/media/IMediaPlayer.h
@@ -33,6 +33,7 @@
 class Surface;
 class IStreamSource;
 class IGraphicBufferProducer;
+struct IMediaHTTPService;
 
 class IMediaPlayer: public IInterface
 {
@@ -41,8 +42,11 @@
 
     virtual void            disconnect() = 0;
 
-    virtual status_t        setDataSource(const char *url,
-                                    const KeyedVector<String8, String8>* headers) = 0;
+    virtual status_t        setDataSource(
+            const sp<IMediaHTTPService> &httpService,
+            const char *url,
+            const KeyedVector<String8, String8>* headers) = 0;
+
     virtual status_t        setDataSource(int fd, int64_t offset, int64_t length) = 0;
     virtual status_t        setDataSource(const sp<IStreamSource>& source) = 0;
     virtual status_t        setVideoSurfaceTexture(
diff --git a/include/media/IMediaPlayerService.h b/include/media/IMediaPlayerService.h
index 2998b37..d7e584a 100644
--- a/include/media/IMediaPlayerService.h
+++ b/include/media/IMediaPlayerService.h
@@ -34,6 +34,8 @@
 struct ICrypto;
 struct IDrm;
 struct IHDCP;
+struct IMediaCodecList;
+struct IMediaHTTPService;
 class IMediaRecorder;
 class IOMX;
 class IRemoteDisplay;
@@ -49,9 +51,14 @@
     virtual sp<IMediaMetadataRetriever> createMetadataRetriever() = 0;
     virtual sp<IMediaPlayer> create(const sp<IMediaPlayerClient>& client, int audioSessionId = 0) = 0;
 
-    virtual status_t         decode(const char* url, uint32_t *pSampleRate, int* pNumChannels,
-                                    audio_format_t* pFormat,
-                                    const sp<IMemoryHeap>& heap, size_t *pSize) = 0;
+    virtual status_t         decode(
+            const sp<IMediaHTTPService> &httpService,
+            const char* url,
+            uint32_t *pSampleRate,
+            int* pNumChannels,
+            audio_format_t* pFormat,
+            const sp<IMemoryHeap>& heap, size_t *pSize) = 0;
+
     virtual status_t         decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate,
                                     int* pNumChannels, audio_format_t* pFormat,
                                     const sp<IMemoryHeap>& heap, size_t *pSize) = 0;
@@ -59,6 +66,7 @@
     virtual sp<ICrypto>         makeCrypto() = 0;
     virtual sp<IDrm>            makeDrm() = 0;
     virtual sp<IHDCP>           makeHDCP(bool createEncryptionModule) = 0;
+    virtual sp<IMediaCodecList> getCodecList() const = 0;
 
     // Connects to a remote display.
     // 'iface' specifies the address of the local interface on which to listen for
@@ -93,9 +101,6 @@
 
     virtual void addBatteryData(uint32_t params) = 0;
     virtual status_t pullBatteryData(Parcel* reply) = 0;
-
-    virtual status_t updateProxyConfig(
-            const char *host, int32_t port, const char *exclusionList) = 0;
 };
 
 // ----------------------------------------------------------------------------
diff --git a/include/media/IOMX.h b/include/media/IOMX.h
index 86a44a9..6e4a4ac 100644
--- a/include/media/IOMX.h
+++ b/include/media/IOMX.h
@@ -38,8 +38,8 @@
 public:
     DECLARE_META_INTERFACE(OMX);
 
-    typedef void *buffer_id;
-    typedef void *node_id;
+    typedef uint32_t buffer_id;
+    typedef uint32_t node_id;
 
     // Given a node_id and the calling process' pid, returns true iff
     // the implementation of the OMX interface lives in the same
@@ -87,6 +87,10 @@
             node_id node, OMX_U32 portIndex, OMX_BOOL enable,
             OMX_U32 maxFrameWidth, OMX_U32 maxFrameHeight) = 0;
 
+   virtual status_t configureVideoTunnelMode(
+            node_id node, OMX_U32 portIndex, OMX_BOOL tunneled,
+            OMX_U32 audioHwSync, native_handle_t **sidebandHandle) = 0;
+
     virtual status_t enableGraphicBuffers(
             node_id node, OMX_U32 port_index, OMX_BOOL enable) = 0;
 
@@ -143,6 +147,8 @@
         INTERNAL_OPTION_SUSPEND,  // data is a bool
         INTERNAL_OPTION_REPEAT_PREVIOUS_FRAME_DELAY,  // data is an int64_t
         INTERNAL_OPTION_MAX_TIMESTAMP_GAP, // data is int64_t
+        INTERNAL_OPTION_START_TIME, // data is an int64_t
+        INTERNAL_OPTION_TIME_LAPSE, // data is an int64_t[2]
     };
     virtual status_t setInternalOption(
             node_id node,
@@ -182,8 +188,6 @@
             OMX_U32 range_length;
             OMX_U32 flags;
             OMX_TICKS timestamp;
-            OMX_PTR platform_private;
-            OMX_PTR data_ptr;
         } extended_buffer_data;
 
     } u;
diff --git a/include/media/MediaCodecInfo.h b/include/media/MediaCodecInfo.h
new file mode 100644
index 0000000..cd56adb
--- /dev/null
+++ b/include/media/MediaCodecInfo.h
@@ -0,0 +1,123 @@
+/*
+ * Copyright 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 MEDIA_CODEC_INFO_H_
+
+#define MEDIA_CODEC_INFO_H_
+
+#include <binder/Parcel.h>
+#include <media/stagefright/foundation/ABase.h>
+#include <media/stagefright/foundation/AString.h>
+
+#include <sys/types.h>
+#include <utils/Errors.h>
+#include <utils/KeyedVector.h>
+#include <utils/RefBase.h>
+#include <utils/Vector.h>
+#include <utils/StrongPointer.h>
+
+namespace android {
+
+struct AMessage;
+struct Parcel;
+struct CodecCapabilities;
+
+struct MediaCodecInfo : public RefBase {
+    struct ProfileLevel {
+        uint32_t mProfile;
+        uint32_t mLevel;
+    };
+
+    struct Capabilities : public RefBase {
+        void getSupportedProfileLevels(Vector<ProfileLevel> *profileLevels) const;
+        void getSupportedColorFormats(Vector<uint32_t> *colorFormats) const;
+        uint32_t getFlags() const;
+        const sp<AMessage> getDetails() const;
+
+    private:
+        Vector<ProfileLevel> mProfileLevels;
+        Vector<uint32_t> mColorFormats;
+        uint32_t mFlags;
+        sp<AMessage> mDetails;
+
+        Capabilities();
+
+        // read object from parcel even if object creation fails
+        static sp<Capabilities> FromParcel(const Parcel &parcel);
+        status_t writeToParcel(Parcel *parcel) const;
+
+        DISALLOW_EVIL_CONSTRUCTORS(Capabilities);
+
+        friend class MediaCodecInfo;
+    };
+
+    bool isEncoder() const;
+    bool hasQuirk(const char *name) const;
+    void getSupportedMimes(Vector<AString> *mimes) const;
+    const sp<Capabilities> getCapabilitiesFor(const char *mime) const;
+    const char *getCodecName() const;
+
+    /**
+     * Serialization over Binder
+     */
+    static sp<MediaCodecInfo> FromParcel(const Parcel &parcel);
+    status_t writeToParcel(Parcel *parcel) const;
+
+private:
+    // variable set only in constructor - these are accessed by MediaCodecList
+    // to avoid duplication of same variables
+    AString mName;
+    bool mIsEncoder;
+    bool mHasSoleMime; // was initialized with mime
+
+    Vector<AString> mQuirks;
+    KeyedVector<AString, sp<Capabilities> > mCaps;
+
+    sp<Capabilities> mCurrentCaps; // currently initalized capabilities
+
+    ssize_t getCapabilityIndex(const char *mime) const;
+
+    /* Methods used by MediaCodecList to construct the info
+     * object from XML.
+     *
+     * After info object is created:
+     * - additional quirks can be added
+     * - additional mimes can be added
+     *   - OMX codec capabilities can be set for the current mime-type
+     *   - a capability detail can be set for the current mime-type
+     *   - a feature can be set for the current mime-type
+     *   - info object can be completed when parsing of a mime-type is done
+     */
+    MediaCodecInfo(AString name, bool encoder, const char *mime);
+    void addQuirk(const char *name);
+    status_t addMime(const char *mime);
+    status_t initializeCapabilities(const CodecCapabilities &caps);
+    void addDetail(const AString &key, const AString &value);
+    void addFeature(const AString &key, int32_t value);
+    void addFeature(const AString &key, const char *value);
+    void removeMime(const char *mime);
+    void complete();
+
+    DISALLOW_EVIL_CONSTRUCTORS(MediaCodecInfo);
+
+    friend class MediaCodecList;
+};
+
+}  // namespace android
+
+#endif  // MEDIA_CODEC_INFO_H_
+
+
diff --git a/include/media/MediaMetadataRetrieverInterface.h b/include/media/MediaMetadataRetrieverInterface.h
index ecc3b65..38dbb20 100644
--- a/include/media/MediaMetadataRetrieverInterface.h
+++ b/include/media/MediaMetadataRetrieverInterface.h
@@ -20,10 +20,13 @@
 
 #include <utils/RefBase.h>
 #include <media/mediametadataretriever.h>
+#include <media/mediascanner.h>
 #include <private/media/VideoFrame.h>
 
 namespace android {
 
+struct IMediaHTTPService;
+
 // Abstract base class
 class MediaMetadataRetrieverBase : public RefBase
 {
@@ -32,6 +35,7 @@
     virtual             ~MediaMetadataRetrieverBase() {}
 
     virtual status_t    setDataSource(
+            const sp<IMediaHTTPService> &httpService,
             const char *url,
             const KeyedVector<String8, String8> *headers = NULL) = 0;
 
diff --git a/include/media/MediaPlayerInterface.h b/include/media/MediaPlayerInterface.h
index 26d8729..cf18a45 100644
--- a/include/media/MediaPlayerInterface.h
+++ b/include/media/MediaPlayerInterface.h
@@ -27,6 +27,7 @@
 
 #include <media/mediaplayer.h>
 #include <media/AudioSystem.h>
+#include <media/AudioTimestamp.h>
 #include <media/Metadata.h>
 
 // Fwd decl to make sure everyone agrees that the scope of struct sockaddr_in is
@@ -97,6 +98,7 @@
         virtual uint32_t    latency() const = 0;
         virtual float       msecsPerFrame() const = 0;
         virtual status_t    getPosition(uint32_t *position) const = 0;
+        virtual status_t    getTimestamp(AudioTimestamp &ts) const = 0;
         virtual status_t    getFramesWritten(uint32_t *frameswritten) const = 0;
         virtual int         getSessionId() const = 0;
         virtual audio_stream_type_t getAudioStreamType() const = 0;
@@ -137,6 +139,7 @@
     }
 
     virtual status_t    setDataSource(
+            const sp<IMediaHTTPService> &httpService,
             const char *url,
             const KeyedVector<String8, String8> *headers = NULL) = 0;
 
@@ -213,11 +216,6 @@
         return INVALID_OPERATION;
     }
 
-    virtual status_t updateProxyConfig(
-            const char *host, int32_t port, const char *exclusionList) {
-        return INVALID_OPERATION;
-    }
-
 private:
     friend class MediaPlayerService;
 
diff --git a/include/media/MediaProfiles.h b/include/media/MediaProfiles.h
index 9fc962c..f061d22 100644
--- a/include/media/MediaProfiles.h
+++ b/include/media/MediaProfiles.h
@@ -33,7 +33,8 @@
     CAMCORDER_QUALITY_720P = 5,
     CAMCORDER_QUALITY_1080P = 6,
     CAMCORDER_QUALITY_QVGA = 7,
-    CAMCORDER_QUALITY_LIST_END = 7,
+    CAMCORDER_QUALITY_2160P = 8,
+    CAMCORDER_QUALITY_LIST_END = 8,
 
     CAMCORDER_QUALITY_TIME_LAPSE_LIST_START = 1000,
     CAMCORDER_QUALITY_TIME_LAPSE_LOW  = 1000,
@@ -44,7 +45,17 @@
     CAMCORDER_QUALITY_TIME_LAPSE_720P = 1005,
     CAMCORDER_QUALITY_TIME_LAPSE_1080P = 1006,
     CAMCORDER_QUALITY_TIME_LAPSE_QVGA = 1007,
-    CAMCORDER_QUALITY_TIME_LAPSE_LIST_END = 1007,
+    CAMCORDER_QUALITY_TIME_LAPSE_2160P = 1008,
+    CAMCORDER_QUALITY_TIME_LAPSE_LIST_END = 1008,
+
+    CAMCORDER_QUALITY_HIGH_SPEED_LIST_START = 2000,
+    CAMCORDER_QUALITY_HIGH_SPEED_LOW  = 2000,
+    CAMCORDER_QUALITY_HIGH_SPEED_HIGH = 2001,
+    CAMCORDER_QUALITY_HIGH_SPEED_480P = 2002,
+    CAMCORDER_QUALITY_HIGH_SPEED_720P = 2003,
+    CAMCORDER_QUALITY_HIGH_SPEED_1080P = 2004,
+    CAMCORDER_QUALITY_HIGH_SPEED_2160P = 2005,
+    CAMCORDER_QUALITY_HIGH_SPEED_LIST_END = 2005,
 };
 
 /**
diff --git a/include/media/SoundPool.h b/include/media/SoundPool.h
index 1b21a36..f57313c 100644
--- a/include/media/SoundPool.h
+++ b/include/media/SoundPool.h
@@ -167,7 +167,7 @@
     friend class SoundPoolThread;
     friend class SoundChannel;
 public:
-    SoundPool(int maxChannels, audio_stream_type_t streamType, int srcQuality);
+    SoundPool(int maxChannels, const audio_attributes_t* pAttributes);
     ~SoundPool();
     int load(const char* url, int priority);
     int load(int fd, int64_t offset, int64_t length, int priority);
@@ -183,8 +183,7 @@
     void setPriority(int channelID, int priority);
     void setLoop(int channelID, int loop);
     void setRate(int channelID, float rate);
-    audio_stream_type_t streamType() const { return mStreamType; }
-    int srcQuality() const { return mSrcQuality; }
+    const audio_attributes_t* attributes() { return &mAttributes; }
 
     // called from SoundPoolThread
     void sampleLoaded(int sampleID);
@@ -225,8 +224,7 @@
     List<SoundChannel*>     mStop;
     DefaultKeyedVector< int, sp<Sample> >   mSamples;
     int                     mMaxChannels;
-    audio_stream_type_t     mStreamType;
-    int                     mSrcQuality;
+    audio_attributes_t      mAttributes;
     int                     mAllocated;
     int                     mNextSampleID;
     int                     mNextChannelID;
diff --git a/media/libmedia/StringArray.h b/include/media/StringArray.h
similarity index 100%
rename from media/libmedia/StringArray.h
rename to include/media/StringArray.h
diff --git a/include/media/mediametadataretriever.h b/include/media/mediametadataretriever.h
index 1acfac3..84b9846 100644
--- a/include/media/mediametadataretriever.h
+++ b/include/media/mediametadataretriever.h
@@ -25,6 +25,7 @@
 
 namespace android {
 
+struct IMediaHTTPService;
 class IMediaPlayerService;
 class IMediaMetadataRetriever;
 
@@ -68,6 +69,7 @@
     void disconnect();
 
     status_t setDataSource(
+            const sp<IMediaHTTPService> &httpService,
             const char *dataSourceUrl,
             const KeyedVector<String8, String8> *headers = NULL);
 
diff --git a/include/media/mediaplayer.h b/include/media/mediaplayer.h
index 4c05fc3..9cc208e 100644
--- a/include/media/mediaplayer.h
+++ b/include/media/mediaplayer.h
@@ -160,6 +160,9 @@
     // Playback rate expressed in permille (1000 is normal speed), saved as int32_t, with negative
     // values used for rewinding or reverse playback.
     KEY_PARAMETER_PLAYBACK_RATE_PERMILLE = 1300,                // set only
+
+    // Set a Parcel containing the value of a parcelled Java AudioAttribute instance
+    KEY_PARAMETER_AUDIO_ATTRIBUTES = 1400                       // set only
 };
 
 // Keep INVOKE_ID_* in sync with MediaPlayer.java.
@@ -170,6 +173,7 @@
     INVOKE_ID_SELECT_TRACK = 4,
     INVOKE_ID_UNSELECT_TRACK = 5,
     INVOKE_ID_SET_VIDEO_SCALING_MODE = 6,
+    INVOKE_ID_GET_SELECTED_TRACK = 7
 };
 
 // Keep MEDIA_TRACK_TYPE_* in sync with MediaPlayer.java.
@@ -189,6 +193,8 @@
     virtual void notify(int msg, int ext1, int ext2, const Parcel *obj) = 0;
 };
 
+struct IMediaHTTPService;
+
 class MediaPlayer : public BnMediaPlayerClient,
                     public virtual IMediaDeathNotifier
 {
@@ -199,6 +205,7 @@
             void            disconnect();
 
             status_t        setDataSource(
+                    const sp<IMediaHTTPService> &httpService,
                     const char *url,
                     const KeyedVector<String8, String8> *headers);
 
@@ -220,13 +227,19 @@
             status_t        getDuration(int *msec);
             status_t        reset();
             status_t        setAudioStreamType(audio_stream_type_t type);
+            status_t        getAudioStreamType(audio_stream_type_t *type);
             status_t        setLooping(int loop);
             bool            isLooping();
             status_t        setVolume(float leftVolume, float rightVolume);
             void            notify(int msg, int ext1, int ext2, const Parcel *obj = NULL);
-    static  status_t        decode(const char* url, uint32_t *pSampleRate, int* pNumChannels,
-                                   audio_format_t* pFormat,
-                                   const sp<IMemoryHeap>& heap, size_t *pSize);
+    static  status_t        decode(
+            const sp<IMediaHTTPService> &httpService,
+            const char* url,
+            uint32_t *pSampleRate,
+            int* pNumChannels,
+            audio_format_t* pFormat,
+            const sp<IMemoryHeap>& heap,
+            size_t *pSize);
     static  status_t        decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate,
                                    int* pNumChannels, audio_format_t* pFormat,
                                    const sp<IMemoryHeap>& heap, size_t *pSize);
@@ -242,9 +255,6 @@
             status_t        setRetransmitEndpoint(const char* addrString, uint16_t port);
             status_t        setNextMediaPlayer(const sp<MediaPlayer>& player);
 
-            status_t updateProxyConfig(
-                    const char *host, int32_t port, const char *exclusionList);
-
 private:
             void            clear_l();
             status_t        seekTo_l(int msec);
@@ -253,6 +263,7 @@
             status_t        attachNewPlayer(const sp<IMediaPlayer>& player);
             status_t        reset_l();
             status_t        doSetRetransmitEndpoint(const sp<IMediaPlayer>& player);
+            status_t        checkStateForKeySet_l(int key);
 
     sp<IMediaPlayer>            mPlayer;
     thread_id_t                 mLockThreadId;
@@ -267,6 +278,7 @@
     bool                        mPrepareSync;
     status_t                    mPrepareStatus;
     audio_stream_type_t         mStreamType;
+    Parcel*                     mAudioAttributesParcel;
     bool                        mLoop;
     float                       mLeftVolume;
     float                       mRightVolume;
diff --git a/include/media/mediarecorder.h b/include/media/mediarecorder.h
index 88a42a0..b0a62a7 100644
--- a/include/media/mediarecorder.h
+++ b/include/media/mediarecorder.h
@@ -39,7 +39,7 @@
 enum video_source {
     VIDEO_SOURCE_DEFAULT = 0,
     VIDEO_SOURCE_CAMERA = 1,
-    VIDEO_SOURCE_GRALLOC_BUFFER = 2,
+    VIDEO_SOURCE_SURFACE = 2,
 
     VIDEO_SOURCE_LIST_END  // must be last - used to validate audio source type
 };
@@ -61,12 +61,18 @@
     OUTPUT_FORMAT_AAC_ADIF = 5,
     OUTPUT_FORMAT_AAC_ADTS = 6,
 
+    OUTPUT_FORMAT_AUDIO_ONLY_END = 7, // Used in validating the output format.  Should be the
+                                      //  at the end of the audio only output formats.
+
     /* Stream over a socket, limited to a single stream */
     OUTPUT_FORMAT_RTP_AVP = 7,
 
     /* H.264/AAC data encapsulated in MPEG2/TS */
     OUTPUT_FORMAT_MPEG2TS = 8,
 
+    /* VP8/VORBIS data in a WEBM container */
+    OUTPUT_FORMAT_WEBM = 9,
+
     OUTPUT_FORMAT_LIST_END // must be last - used to validate format type
 };
 
@@ -77,6 +83,7 @@
     AUDIO_ENCODER_AAC = 3,
     AUDIO_ENCODER_HE_AAC = 4,
     AUDIO_ENCODER_AAC_ELD = 5,
+    AUDIO_ENCODER_VORBIS = 6,
 
     AUDIO_ENCODER_LIST_END // must be the last - used to validate the audio encoder type
 };
@@ -86,6 +93,7 @@
     VIDEO_ENCODER_H263 = 1,
     VIDEO_ENCODER_H264 = 2,
     VIDEO_ENCODER_MPEG_4_SP = 3,
+    VIDEO_ENCODER_VP8 = 4,
 
     VIDEO_ENCODER_LIST_END // must be the last - used to validate the video encoder type
 };
diff --git a/include/media/mediascanner.h b/include/media/mediascanner.h
index a73403b..d555279 100644
--- a/include/media/mediascanner.h
+++ b/include/media/mediascanner.h
@@ -21,6 +21,7 @@
 #include <utils/threads.h>
 #include <utils/List.h>
 #include <utils/Errors.h>
+#include <utils/String8.h>
 #include <pthread.h>
 
 struct dirent;
@@ -29,6 +30,7 @@
 
 class MediaScannerClient;
 class StringArray;
+class CharacterEncodingDetector;
 
 enum MediaScanResult {
     // This file or directory was scanned successfully.
@@ -41,6 +43,31 @@
     MEDIA_SCAN_RESULT_ERROR,
 };
 
+struct MediaAlbumArt {
+public:
+    static MediaAlbumArt *fromData(int32_t size, const void* data);
+
+    static void init(MediaAlbumArt* instance, int32_t size, const void* data);
+
+    MediaAlbumArt *clone();
+
+    const char *data() {
+        return &mData[0];
+    }
+
+    int32_t size() {
+        return mSize;
+    }
+
+private:
+    int32_t mSize;
+    char mData[];
+
+    // You can't construct instances of this class directly because this is a
+    // variable-sized object passed through the binder.
+    MediaAlbumArt();
+} __packed;
+
 struct MediaScanner {
     MediaScanner();
     virtual ~MediaScanner();
@@ -53,8 +80,7 @@
 
     void setLocale(const char *locale);
 
-    // extracts album art as a block of data
-    virtual char *extractAlbumArt(int fd) = 0;
+    virtual MediaAlbumArt *extractAlbumArt(int fd) = 0;
 
 protected:
     const char *locale() const;
@@ -94,15 +120,8 @@
     virtual status_t setMimeType(const char* mimeType) = 0;
 
 protected:
-    void convertValues(uint32_t encoding);
-
-protected:
-    // cached name and value strings, for native encoding support.
-    StringArray*    mNames;
-    StringArray*    mValues;
-
-    // default encoding based on MediaScanner::mLocale string
-    uint32_t        mLocaleEncoding;
+    // default encoding from MediaScanner::mLocale
+    String8 mLocale;
 };
 
 }; // namespace android
diff --git a/include/media/nbaio/AudioBufferProviderSource.h b/include/media/nbaio/AudioBufferProviderSource.h
index 2c4aaff..b16e20a 100644
--- a/include/media/nbaio/AudioBufferProviderSource.h
+++ b/include/media/nbaio/AudioBufferProviderSource.h
@@ -27,7 +27,7 @@
 class AudioBufferProviderSource : public NBAIO_Source {
 
 public:
-    AudioBufferProviderSource(AudioBufferProvider *provider, NBAIO_Format format);
+    AudioBufferProviderSource(AudioBufferProvider *provider, const NBAIO_Format& format);
     virtual ~AudioBufferProviderSource();
 
     // NBAIO_Port interface
diff --git a/include/media/nbaio/AudioStreamInSource.h b/include/media/nbaio/AudioStreamInSource.h
index 07d8c89..5169f1e 100644
--- a/include/media/nbaio/AudioStreamInSource.h
+++ b/include/media/nbaio/AudioStreamInSource.h
@@ -43,9 +43,9 @@
 
     // This is an over-estimate, and could dupe the caller into making a blocking read()
     // FIXME Use an audio HAL API to query the buffer filling status when it's available.
-    virtual ssize_t availableToRead() { return mStreamBufferSizeBytes >> mBitShift; }
+    virtual ssize_t availableToRead() { return mStreamBufferSizeBytes / mFrameSize; }
 
-    virtual ssize_t read(void *buffer, size_t count);
+    virtual ssize_t read(void *buffer, size_t count, int64_t readPTS);
 
     // NBAIO_Sink end
 
diff --git a/include/media/nbaio/AudioStreamOutSink.h b/include/media/nbaio/AudioStreamOutSink.h
index 7948d40..9949b88 100644
--- a/include/media/nbaio/AudioStreamOutSink.h
+++ b/include/media/nbaio/AudioStreamOutSink.h
@@ -43,7 +43,7 @@
 
     // This is an over-estimate, and could dupe the caller into making a blocking write()
     // FIXME Use an audio HAL API to query the buffer emptying status when it's available.
-    virtual ssize_t availableToWrite() const { return mStreamBufferSizeBytes >> mBitShift; }
+    virtual ssize_t availableToWrite() const { return mStreamBufferSizeBytes / mFrameSize; }
 
     virtual ssize_t write(const void *buffer, size_t count);
 
diff --git a/include/media/nbaio/MonoPipe.h b/include/media/nbaio/MonoPipe.h
index d3802fe..b09b35f 100644
--- a/include/media/nbaio/MonoPipe.h
+++ b/include/media/nbaio/MonoPipe.h
@@ -41,7 +41,7 @@
     // Note: whatever shares this object with another thread needs to do so in an SMP-safe way (like
     // creating it the object before creating the other thread, or storing the object with a
     // release_store). Otherwise the other thread could see a partially-constructed object.
-    MonoPipe(size_t reqFrames, NBAIO_Format format, bool writeCanBlock = false);
+    MonoPipe(size_t reqFrames, const NBAIO_Format& format, bool writeCanBlock = false);
     virtual ~MonoPipe();
 
     // NBAIO_Port interface
diff --git a/include/media/nbaio/NBAIO.h b/include/media/nbaio/NBAIO.h
index 1da0c73..d422576 100644
--- a/include/media/nbaio/NBAIO.h
+++ b/include/media/nbaio/NBAIO.h
@@ -29,6 +29,7 @@
 #include <utils/Errors.h>
 #include <utils/RefBase.h>
 #include <media/AudioTimestamp.h>
+#include <system/audio.h>
 
 namespace android {
 
@@ -52,31 +53,41 @@
 // the combinations that are actually needed within AudioFlinger.  If the list of combinations grows
 // too large, then this decision should be re-visited.
 // Sample rate and channel count are explicit, PCM interleaved 16-bit is assumed.
-typedef unsigned NBAIO_Format;
-enum {
-    Format_Invalid
+struct NBAIO_Format {
+// FIXME make this a class, and change Format_... global methods to class methods
+//private:
+    unsigned    mSampleRate;
+    unsigned    mChannelCount;
+    audio_format_t  mFormat;
+    size_t      mFrameSize;
 };
 
-// Return the frame size of an NBAIO_Format in bytes
-size_t Format_frameSize(NBAIO_Format format);
+extern const NBAIO_Format Format_Invalid;
 
-// Return the frame size of an NBAIO_Format as a bit shift
-size_t Format_frameBitShift(NBAIO_Format format);
+// Return the frame size of an NBAIO_Format in bytes
+size_t Format_frameSize(const NBAIO_Format& format);
 
 // Convert a sample rate in Hz and channel count to an NBAIO_Format
-NBAIO_Format Format_from_SR_C(unsigned sampleRate, unsigned channelCount);
+// FIXME rename
+NBAIO_Format Format_from_SR_C(unsigned sampleRate, unsigned channelCount, audio_format_t format);
 
 // Return the sample rate in Hz of an NBAIO_Format
-unsigned Format_sampleRate(NBAIO_Format format);
+unsigned Format_sampleRate(const NBAIO_Format& format);
 
 // Return the channel count of an NBAIO_Format
-unsigned Format_channelCount(NBAIO_Format format);
+unsigned Format_channelCount(const NBAIO_Format& format);
 
 // Callbacks used by NBAIO_Sink::writeVia() and NBAIO_Source::readVia() below.
 typedef ssize_t (*writeVia_t)(void *user, void *buffer, size_t count);
 typedef ssize_t (*readVia_t)(void *user, const void *buffer,
                              size_t count, int64_t readPTS);
 
+// Check whether an NBAIO_Format is valid
+bool Format_isValid(const NBAIO_Format& format);
+
+// Compare two NBAIO_Format values
+bool Format_isEqual(const NBAIO_Format& format1, const NBAIO_Format& format2);
+
 // Abstract class (interface) representing a data port.
 class NBAIO_Port : public RefBase {
 
@@ -115,15 +126,15 @@
     virtual NBAIO_Format format() const { return mNegotiated ? mFormat : Format_Invalid; }
 
 protected:
-    NBAIO_Port(NBAIO_Format format) : mNegotiated(false), mFormat(format),
-                                      mBitShift(Format_frameBitShift(format)) { }
+    NBAIO_Port(const NBAIO_Format& format) : mNegotiated(false), mFormat(format),
+                                             mFrameSize(Format_frameSize(format)) { }
     virtual ~NBAIO_Port() { }
 
     // Implementations are free to ignore these if they don't need them
 
     bool            mNegotiated;    // mNegotiated implies (mFormat != Format_Invalid)
     NBAIO_Format    mFormat;        // (mFormat != Format_Invalid) does not imply mNegotiated
-    size_t          mBitShift;      // assign in parallel with any assignment to mFormat
+    size_t          mFrameSize;     // assign in parallel with any assignment to mFormat
 };
 
 // Abstract class (interface) representing a non-blocking data sink, for use by a data provider.
@@ -216,11 +227,11 @@
 
     // Returns NO_ERROR if a timestamp is available.  The timestamp includes the total number
     // of frames presented to an external observer, together with the value of CLOCK_MONOTONIC
-    // as of this presentation count.
+    // as of this presentation count.  The timestamp parameter is undefined if error is returned.
     virtual status_t getTimestamp(AudioTimestamp& timestamp) { return INVALID_OPERATION; }
 
 protected:
-    NBAIO_Sink(NBAIO_Format format = Format_Invalid) : NBAIO_Port(format), mFramesWritten(0) { }
+    NBAIO_Sink(const NBAIO_Format& format = Format_Invalid) : NBAIO_Port(format), mFramesWritten(0) { }
     virtual ~NBAIO_Sink() { }
 
     // Implementations are free to ignore these if they don't need them
@@ -311,7 +322,7 @@
     virtual void    onTimestamp(const AudioTimestamp& timestamp) { }
 
 protected:
-    NBAIO_Source(NBAIO_Format format = Format_Invalid) : NBAIO_Port(format), mFramesRead(0) { }
+    NBAIO_Source(const NBAIO_Format& format = Format_Invalid) : NBAIO_Port(format), mFramesRead(0) { }
     virtual ~NBAIO_Source() { }
 
     // Implementations are free to ignore these if they don't need them
diff --git a/include/media/nbaio/NBLog.h b/include/media/nbaio/NBLog.h
index 6d59ea7..bcbbc04 100644
--- a/include/media/nbaio/NBLog.h
+++ b/include/media/nbaio/NBLog.h
@@ -25,6 +25,8 @@
 
 namespace android {
 
+class String8;
+
 class NBLog {
 
 public:
@@ -187,6 +189,10 @@
     const Shared* const mShared; // raw pointer to shared memory
     const sp<IMemory> mIMemory; // ref-counted version
     int32_t     mFront;         // index of oldest acknowledged Entry
+    int     mFd;                // file descriptor
+    int     mIndent;            // indentation level
+
+    void    dumpLine(const String8& timestamp, String8& body);
 
     static const size_t kSquashTimestamp = 5; // squash this many or more adjacent timestamps
 };
diff --git a/include/media/nbaio/Pipe.h b/include/media/nbaio/Pipe.h
index 79a4eee..eba37bc 100644
--- a/include/media/nbaio/Pipe.h
+++ b/include/media/nbaio/Pipe.h
@@ -30,7 +30,11 @@
 
 public:
     // maxFrames will be rounded up to a power of 2, and all slots are available. Must be >= 2.
-    Pipe(size_t maxFrames, NBAIO_Format format);
+    // buffer is an optional parameter specifying the virtual address of the pipe buffer,
+    // which must be of size roundup(maxFrames) * Format_frameSize(format) bytes.
+    Pipe(size_t maxFrames, const NBAIO_Format& format, void *buffer = NULL);
+
+    // If a buffer was specified in the constructor, it is not automatically freed by destructor.
     virtual ~Pipe();
 
     // NBAIO_Port interface
@@ -57,6 +61,7 @@
     void * const    mBuffer;
     volatile int32_t mRear;         // written by android_atomic_release_store
     volatile int32_t mReaders;      // number of PipeReader clients currently attached to this Pipe
+    const bool      mFreeBufferInDestructor;
 };
 
 }   // namespace android
diff --git a/include/media/nbaio/SourceAudioBufferProvider.h b/include/media/nbaio/SourceAudioBufferProvider.h
index cdfb6fe..daf6bc3 100644
--- a/include/media/nbaio/SourceAudioBufferProvider.h
+++ b/include/media/nbaio/SourceAudioBufferProvider.h
@@ -41,7 +41,7 @@
 
 private:
     const sp<NBAIO_Source> mSource;     // the wrapped source
-    /*const*/ size_t    mFrameBitShift; // log2(frame size in bytes)
+    /*const*/ size_t    mFrameSize; // frame size in bytes
     void*               mAllocated; // pointer to base of allocated memory
     size_t              mSize;      // size of mAllocated in frames
     size_t              mOffset;    // frame offset within mAllocated of valid data
diff --git a/include/media/stagefright/ACodec.h b/include/media/stagefright/ACodec.h
index 9b534e7..a0e5d84 100644
--- a/include/media/stagefright/ACodec.h
+++ b/include/media/stagefright/ACodec.h
@@ -22,6 +22,7 @@
 #include <android/native_window.h>
 #include <media/IOMX.h>
 #include <media/stagefright/foundation/AHierarchicalStateMachine.h>
+#include <media/stagefright/CodecBase.h>
 #include <media/stagefright/SkipCutBuffer.h>
 #include <OMX_Audio.h>
 
@@ -31,45 +32,34 @@
 
 struct ABuffer;
 struct MemoryDealer;
+struct DescribeColorFormatParams;
 
-struct ACodec : public AHierarchicalStateMachine {
-    enum {
-        kWhatFillThisBuffer      = 'fill',
-        kWhatDrainThisBuffer     = 'drai',
-        kWhatEOS                 = 'eos ',
-        kWhatShutdownCompleted   = 'scom',
-        kWhatFlushCompleted      = 'fcom',
-        kWhatOutputFormatChanged = 'outC',
-        kWhatError               = 'erro',
-        kWhatComponentAllocated  = 'cAll',
-        kWhatComponentConfigured = 'cCon',
-        kWhatInputSurfaceCreated = 'isfc',
-        kWhatSignaledInputEOS    = 'seos',
-        kWhatBuffersAllocated    = 'allc',
-        kWhatOMXDied             = 'OMXd',
-    };
-
+struct ACodec : public AHierarchicalStateMachine, public CodecBase {
     ACodec();
 
-    void setNotificationMessage(const sp<AMessage> &msg);
+    virtual void setNotificationMessage(const sp<AMessage> &msg);
+
     void initiateSetup(const sp<AMessage> &msg);
-    void signalFlush();
-    void signalResume();
-    void initiateShutdown(bool keepComponentAllocated = false);
 
-    void signalSetParameters(const sp<AMessage> &msg);
-    void signalEndOfInputStream();
+    virtual void initiateAllocateComponent(const sp<AMessage> &msg);
+    virtual void initiateConfigureComponent(const sp<AMessage> &msg);
+    virtual void initiateCreateInputSurface();
+    virtual void initiateStart();
+    virtual void initiateShutdown(bool keepComponentAllocated = false);
 
-    void initiateAllocateComponent(const sp<AMessage> &msg);
-    void initiateConfigureComponent(const sp<AMessage> &msg);
-    void initiateCreateInputSurface();
-    void initiateStart();
+    virtual void signalFlush();
+    virtual void signalResume();
 
-    void signalRequestIDRFrame();
+    virtual void signalSetParameters(const sp<AMessage> &msg);
+    virtual void signalEndOfInputStream();
+    virtual void signalRequestIDRFrame();
 
-    bool isConfiguredForAdaptivePlayback() { return mIsConfiguredForAdaptivePlayback; }
+    // AHierarchicalStateMachine implements the message handling
+    virtual void onMessageReceived(const sp<AMessage> &msg) {
+        handleMessage(msg);
+    }
 
-    struct PortDescription : public RefBase {
+    struct PortDescription : public CodecBase::PortDescription {
         size_t countBuffers();
         IOMX::buffer_id bufferIDAt(size_t index) const;
         sp<ABuffer> bufferAt(size_t index) const;
@@ -86,6 +76,16 @@
         DISALLOW_EVIL_CONSTRUCTORS(PortDescription);
     };
 
+    static bool isFlexibleColorFormat(
+            const sp<IOMX> &omx, IOMX::node_id node,
+            uint32_t colorFormat, OMX_U32 *flexibleEquivalent);
+
+    // Returns 0 if configuration is not supported.  NOTE: this is treated by
+    // some OMX components as auto level, and by others as invalid level.
+    static int /* OMX_VIDEO_AVCLEVELTYPE */ getAVCLevelFor(
+            int width, int height, int rate, int bitrate,
+            OMX_VIDEO_AVCPROFILETYPE profile = OMX_VIDEO_AVCProfileBaseline);
+
 protected:
     virtual ~ACodec();
 
@@ -119,6 +119,8 @@
         kWhatRequestIDRFrame         = 'ridr',
         kWhatSetParameters           = 'setP',
         kWhatSubmitOutputMetaDataBufferIfEOS = 'subm',
+        kWhatOMXDied                 = 'OMXd',
+        kWhatReleaseCodecInstance    = 'relC',
     };
 
     enum {
@@ -178,6 +180,8 @@
     sp<MemoryDealer> mDealer[2];
 
     sp<ANativeWindow> mNativeWindow;
+    sp<AMessage> mInputFormat;
+    sp<AMessage> mOutputFormat;
 
     Vector<BufferInfo> mBuffers[2];
     bool mPortEOS[2];
@@ -190,7 +194,7 @@
     bool mUseMetadataOnEncoderOutput;
     bool mFatalError;
     bool mShutdownInProgress;
-    bool mIsConfiguredForAdaptivePlayback;
+    bool mExplicitShutdown;
 
     // If "mKeepComponentAllocated" we only transition back to Loaded state
     // and do not release the component instance.
@@ -198,16 +202,25 @@
 
     int32_t mEncoderDelay;
     int32_t mEncoderPadding;
+    int32_t mRotationDegrees;
 
     bool mChannelMaskPresent;
     int32_t mChannelMask;
     unsigned mDequeueCounter;
     bool mStoreMetaDataInOutputBuffers;
     int32_t mMetaDataBuffersToSubmit;
+    size_t mNumUndequeuedBuffers;
 
     int64_t mRepeatFrameDelayUs;
     int64_t mMaxPtsGapUs;
 
+    int64_t mTimePerFrameUs;
+    int64_t mTimePerCaptureUs;
+
+    bool mCreateInputBuffersSuspended;
+
+    bool mTunneled;
+
     status_t setCyclicIntraMacroblockRefresh(const sp<AMessage> &msg, int32_t mode);
     status_t allocateBuffersOnPort(OMX_U32 portIndex);
     status_t freeBuffersOnPort(OMX_U32 portIndex);
@@ -231,6 +244,9 @@
     status_t setComponentRole(bool isEncoder, const char *mime);
     status_t configureCodec(const char *mime, const sp<AMessage> &msg);
 
+    status_t configureTunneledVideoPlayback(int32_t audioHwSync,
+            const sp<ANativeWindow> &nativeWindow);
+
     status_t setVideoPortFormatType(
             OMX_U32 portIndex,
             OMX_VIDEO_CODINGTYPE compressionFormat,
@@ -239,7 +255,7 @@
     status_t setSupportedOutputFormat();
 
     status_t setupVideoDecoder(
-            const char *mime, int32_t width, int32_t height);
+            const char *mime, const sp<AMessage> &msg);
 
     status_t setupVideoEncoder(
             const char *mime, const sp<AMessage> &msg);
@@ -249,10 +265,20 @@
             int32_t width, int32_t height,
             OMX_VIDEO_CODINGTYPE compressionFormat);
 
+    typedef struct drcParams {
+        int32_t drcCut;
+        int32_t drcBoost;
+        int32_t heavyCompression;
+        int32_t targetRefLevel;
+        int32_t encodedTargetLevel;
+    } drcParams_t;
+
     status_t setupAACCodec(
             bool encoder,
             int32_t numChannels, int32_t sampleRate, int32_t bitRate,
-            int32_t aacProfile, bool isADTS);
+            int32_t aacProfile, bool isADTS, int32_t sbrMode,
+            int32_t maxOutputChannelCount, const drcParams_t& drc,
+            int32_t pcmLimiterEnable);
 
     status_t setupAC3Codec(bool encoder, int32_t numChannels, int32_t sampleRate);
 
@@ -273,6 +299,7 @@
     status_t setupMPEG4EncoderParameters(const sp<AMessage> &msg);
     status_t setupH263EncoderParameters(const sp<AMessage> &msg);
     status_t setupAVCEncoderParameters(const sp<AMessage> &msg);
+    status_t setupHEVCEncoderParameters(const sp<AMessage> &msg);
     status_t setupVPXEncoderParameters(const sp<AMessage> &msg);
 
     status_t verifySupportForProfileAndLevel(int32_t profile, int32_t level);
@@ -301,11 +328,17 @@
     void processDeferredMessages();
 
     void sendFormatChange(const sp<AMessage> &reply);
+    status_t getPortFormat(OMX_U32 portIndex, sp<AMessage> &notify);
 
     void signalError(
             OMX_ERRORTYPE error = OMX_ErrorUndefined,
             status_t internalError = UNKNOWN_ERROR);
 
+    static bool describeDefaultColorFormat(DescribeColorFormatParams &describeParams);
+    static bool describeColorFormat(
+        const sp<IOMX> &omx, IOMX::node_id node,
+        DescribeColorFormatParams &describeParams);
+
     status_t requestIDRFrame();
     status_t setParameters(const sp<AMessage> &params);
 
diff --git a/include/media/stagefright/CameraSource.h b/include/media/stagefright/CameraSource.h
index 32f468b..cc46801 100644
--- a/include/media/stagefright/CameraSource.h
+++ b/include/media/stagefright/CameraSource.h
@@ -172,7 +172,7 @@
                  const sp<IGraphicBufferProducer>& surface,
                  bool storeMetaDataInVideoBuffers);
 
-    virtual void startCameraRecording();
+    virtual status_t startCameraRecording();
     virtual void releaseRecordingFrame(const sp<IMemory>& frame);
 
     // Returns true if need to skip the current frame.
@@ -185,6 +185,8 @@
     virtual void dataCallbackTimestamp(int64_t timestampUs, int32_t msgType,
             const sp<IMemory> &data);
 
+    void releaseCamera();
+
 private:
     friend class CameraSourceListener;
 
@@ -236,7 +238,6 @@
     static void adjustOutgoingANWBuffer(IMemory* data);
 
     void stopCameraRecording();
-    void releaseCamera();
     status_t reset();
 
     CameraSource(const CameraSource &);
diff --git a/include/media/stagefright/ClockEstimator.h b/include/media/stagefright/ClockEstimator.h
new file mode 100644
index 0000000..2fd6e75
--- /dev/null
+++ b/include/media/stagefright/ClockEstimator.h
@@ -0,0 +1,110 @@
+/*
+**
+** Copyright 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 CLOCK_ESTIMATOR_H_
+
+#define CLOCK_ESTIMATOR_H_
+
+
+#include <utils/RefBase.h>
+#include <utils/Vector.h>
+
+namespace android {
+// ---------------------------------------------------------------------------
+
+struct ClockEstimator : RefBase {
+    virtual double estimate(double x, double y) = 0;
+    virtual void reset() = 0;
+};
+
+struct WindowedLinearFitEstimator : ClockEstimator {
+    struct LinearFit {
+        /**
+         * Fit y = a * x + b, where each input has a weight
+         */
+        double mX;  // sum(w_i * x_i)
+        double mXX; // sum(w_i * x_i^2)
+        double mY;  // sum(w_i * y_i)
+        double mYY; // sum(w_i * y_i^2)
+        double mXY; // sum(w_i * x_i * y_i)
+        double mW;  // sum(w_i)
+
+        LinearFit();
+        void reset();
+        void combine(const LinearFit &lf);
+        void add(double x, double y, double w);
+        void scale(double w);
+        double interpolate(double x);
+        double size() const;
+
+        DISALLOW_EVIL_CONSTRUCTORS(LinearFit);
+    };
+
+    /**
+     * Estimator for f(x) = y' where input y' is noisy, but
+     * theoretically linear:
+     *
+     *      y' =~ y = a * x + b
+     *
+     * It uses linear fit regression over a tapering rolling window
+     * to get an estimate for y (from the current and past inputs
+     * (x, y')).
+     *
+     *     ____________
+     *    /|          |\
+     *   / |          | \
+     *  /  |          |  \   <--- new data (x, y')
+     * /   |   main   |   \
+     * <--><----------><-->
+     * tail            head
+     *
+     * weight is 1 under the main window, tapers exponentially by
+     * the factors given in the head and the tail.
+     *
+     * Assuming that x and y' are monotonic, that x is somewhat
+     * evenly sampled, and that a =~ 1, the estimated y is also
+     * going to be monotonic.
+     */
+    WindowedLinearFitEstimator(
+            size_t headLength = 5, double headFactor = 0.5,
+            size_t mainLength = 0, double tailFactor = 0.99);
+
+    virtual void reset();
+
+    // add a new sample (x -> y') and return an estimated value for the true y
+    virtual double estimate(double x, double y);
+
+private:
+    Vector<double> mXHistory; // circular buffer
+    Vector<double> mYHistory; // circular buffer
+    LinearFit mHead;
+    LinearFit mMain;
+    LinearFit mTail;
+    double mHeadFactorInv;
+    double mTailFactor;
+    double mFirstWeight;
+    size_t mHistoryLength;
+    size_t mHeadLength;
+    size_t mNumSamples;
+    size_t mSampleIx;
+
+    DISALLOW_EVIL_CONSTRUCTORS(WindowedLinearFitEstimator);
+};
+
+}; // namespace android
+
+#endif
diff --git a/include/media/stagefright/CodecBase.h b/include/media/stagefright/CodecBase.h
new file mode 100644
index 0000000..1bf27a6
--- /dev/null
+++ b/include/media/stagefright/CodecBase.h
@@ -0,0 +1,88 @@
+/*
+ * 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 CODEC_BASE_H_
+
+#define CODEC_BASE_H_
+
+#include <stdint.h>
+#include <media/IOMX.h>
+
+#include <media/stagefright/foundation/AHandler.h>
+
+namespace android {
+
+struct ABuffer;
+
+struct CodecBase : public AHandler {
+    enum {
+        kWhatFillThisBuffer      = 'fill',
+        kWhatDrainThisBuffer     = 'drai',
+        kWhatEOS                 = 'eos ',
+        kWhatShutdownCompleted   = 'scom',
+        kWhatFlushCompleted      = 'fcom',
+        kWhatOutputFormatChanged = 'outC',
+        kWhatError               = 'erro',
+        kWhatComponentAllocated  = 'cAll',
+        kWhatComponentConfigured = 'cCon',
+        kWhatInputSurfaceCreated = 'isfc',
+        kWhatSignaledInputEOS    = 'seos',
+        kWhatBuffersAllocated    = 'allc',
+    };
+
+    virtual void setNotificationMessage(const sp<AMessage> &msg) = 0;
+
+    virtual void initiateAllocateComponent(const sp<AMessage> &msg) = 0;
+    virtual void initiateConfigureComponent(const sp<AMessage> &msg) = 0;
+    virtual void initiateCreateInputSurface() = 0;
+    virtual void initiateStart() = 0;
+    virtual void initiateShutdown(bool keepComponentAllocated = false) = 0;
+
+    // require an explicit message handler
+    virtual void onMessageReceived(const sp<AMessage> &msg) = 0;
+
+    virtual void signalFlush() = 0;
+    virtual void signalResume() = 0;
+
+    virtual void signalRequestIDRFrame() = 0;
+    virtual void signalSetParameters(const sp<AMessage> &msg) = 0;
+    virtual void signalEndOfInputStream() = 0;
+
+    struct PortDescription : public RefBase {
+        virtual size_t countBuffers() = 0;
+        virtual IOMX::buffer_id bufferIDAt(size_t index) const = 0;
+        virtual sp<ABuffer> bufferAt(size_t index) const = 0;
+
+    protected:
+        PortDescription();
+        virtual ~PortDescription();
+
+    private:
+        DISALLOW_EVIL_CONSTRUCTORS(PortDescription);
+    };
+
+protected:
+    CodecBase();
+    virtual ~CodecBase();
+
+private:
+    DISALLOW_EVIL_CONSTRUCTORS(CodecBase);
+};
+
+}  // namespace android
+
+#endif  // CODEC_BASE_H_
+
diff --git a/include/media/stagefright/DataSource.h b/include/media/stagefright/DataSource.h
index 6c64a2c..766a81d 100644
--- a/include/media/stagefright/DataSource.h
+++ b/include/media/stagefright/DataSource.h
@@ -31,7 +31,10 @@
 namespace android {
 
 struct AMessage;
+struct AString;
+struct IMediaHTTPService;
 class String8;
+struct HTTPBase;
 
 class DataSource : public RefBase {
 public:
@@ -43,8 +46,13 @@
     };
 
     static sp<DataSource> CreateFromURI(
+            const sp<IMediaHTTPService> &httpService,
             const char *uri,
-            const KeyedVector<String8, String8> *headers = NULL);
+            const KeyedVector<String8, String8> *headers = NULL,
+            String8 *contentType = NULL,
+            HTTPBase *httpSource = NULL);
+
+    static sp<DataSource> CreateMediaHTTP(const sp<IMediaHTTPService> &httpService);
 
     DataSource() {}
 
diff --git a/include/media/stagefright/DataURISource.h b/include/media/stagefright/DataURISource.h
new file mode 100644
index 0000000..693562e
--- /dev/null
+++ b/include/media/stagefright/DataURISource.h
@@ -0,0 +1,49 @@
+/*
+ * 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 DATA_URI_SOURCE_H_
+
+#define DATA_URI_SOURCE_H_
+
+#include <media/stagefright/DataSource.h>
+#include <media/stagefright/foundation/ABase.h>
+
+namespace android {
+
+struct ABuffer;
+
+struct DataURISource : public DataSource {
+    static sp<DataURISource> Create(const char *uri);
+
+    virtual status_t initCheck() const;
+    virtual ssize_t readAt(off64_t offset, void *data, size_t size);
+    virtual status_t getSize(off64_t *size);
+
+protected:
+    virtual ~DataURISource();
+
+private:
+    sp<ABuffer> mBuffer;
+
+    DataURISource(const sp<ABuffer> &buffer);
+
+    DISALLOW_EVIL_CONSTRUCTORS(DataURISource);
+};
+
+}  // namespace android
+
+#endif  // DATA_URI_SOURCE_H_
+
diff --git a/include/media/stagefright/FileSource.h b/include/media/stagefright/FileSource.h
index d994cb3..a981d1c 100644
--- a/include/media/stagefright/FileSource.h
+++ b/include/media/stagefright/FileSource.h
@@ -30,6 +30,7 @@
 class FileSource : public DataSource {
 public:
     FileSource(const char *filename);
+    // FileSource takes ownership and will close the fd
     FileSource(int fd, int64_t offset, int64_t length);
 
     virtual status_t initCheck() const;
@@ -55,7 +56,7 @@
     sp<DecryptHandle> mDecryptHandle;
     DrmManagerClient *mDrmManagerClient;
     int64_t mDrmBufOffset;
-    int64_t mDrmBufSize;
+    size_t mDrmBufSize;
     unsigned char *mDrmBuf;
 
     ssize_t readAtDRM(off64_t offset, void *data, size_t size);
diff --git a/include/media/stagefright/MPEG4Writer.h b/include/media/stagefright/MPEG4Writer.h
index 3ef6b9a..26ce5f9 100644
--- a/include/media/stagefright/MPEG4Writer.h
+++ b/include/media/stagefright/MPEG4Writer.h
@@ -63,8 +63,8 @@
     int32_t getTimeScale() const { return mTimeScale; }
 
     status_t setGeoData(int latitudex10000, int longitudex10000);
-    void setStartTimeOffsetMs(int ms) { mStartTimeOffsetMs = ms; }
-    int32_t getStartTimeOffsetMs() const { return mStartTimeOffsetMs; }
+    virtual void setStartTimeOffsetMs(int ms) { mStartTimeOffsetMs = ms; }
+    virtual int32_t getStartTimeOffsetMs() const { return mStartTimeOffsetMs; }
 
 protected:
     virtual ~MPEG4Writer();
diff --git a/include/media/stagefright/MediaBuffer.h b/include/media/stagefright/MediaBuffer.h
index 3d79596..c8a50e8 100644
--- a/include/media/stagefright/MediaBuffer.h
+++ b/include/media/stagefright/MediaBuffer.h
@@ -18,6 +18,8 @@
 
 #define MEDIA_BUFFER_H_
 
+#include <media/stagefright/foundation/MediaBufferBase.h>
+
 #include <pthread.h>
 
 #include <utils/Errors.h>
@@ -43,7 +45,7 @@
     MediaBufferObserver &operator=(const MediaBufferObserver &);
 };
 
-class MediaBuffer {
+class MediaBuffer : public MediaBufferBase {
 public:
     // The underlying data remains the responsibility of the caller!
     MediaBuffer(void *data, size_t size);
@@ -56,10 +58,10 @@
 
     // Decrements the reference count and returns the buffer to its
     // associated MediaBufferGroup if the reference count drops to 0.
-    void release();
+    virtual void release();
 
     // Increments the reference count.
-    void add_ref();
+    virtual void add_ref();
 
     void *data() const;
     size_t size() const;
diff --git a/include/media/stagefright/MediaBufferGroup.h b/include/media/stagefright/MediaBufferGroup.h
index 0488292..a006f7f 100644
--- a/include/media/stagefright/MediaBufferGroup.h
+++ b/include/media/stagefright/MediaBufferGroup.h
@@ -34,9 +34,12 @@
 
     void add_buffer(MediaBuffer *buffer);
 
-    // Blocks until a buffer is available and returns it to the caller,
-    // the returned buffer will have a reference count of 1.
-    status_t acquire_buffer(MediaBuffer **buffer);
+    // If nonBlocking is false, it blocks until a buffer is available and
+    // passes it to the caller in *buffer, while returning OK.
+    // The returned buffer will have a reference count of 1.
+    // If nonBlocking is true and a buffer is not immediately available,
+    // buffer is set to NULL and it returns WOULD_BLOCK.
+    status_t acquire_buffer(MediaBuffer **buffer, bool nonBlocking = false);
 
 protected:
     virtual void signalBufferReturned(MediaBuffer *buffer);
diff --git a/include/media/stagefright/MediaCodec.h b/include/media/stagefright/MediaCodec.h
index 76aa503..54a4e8b 100644
--- a/include/media/stagefright/MediaCodec.h
+++ b/include/media/stagefright/MediaCodec.h
@@ -26,10 +26,11 @@
 namespace android {
 
 struct ABuffer;
-struct ACodec;
 struct AMessage;
 struct AString;
+struct CodecBase;
 struct ICrypto;
+struct IBatteryStats;
 struct SoftwareRenderer;
 struct Surface;
 
@@ -44,11 +45,20 @@
         BUFFER_FLAG_EOS         = 4,
     };
 
+    enum {
+        CB_INPUT_AVAILABLE = 1,
+        CB_OUTPUT_AVAILABLE = 2,
+        CB_ERROR = 3,
+        CB_OUTPUT_FORMAT_CHANGED = 4,
+    };
+
+    struct BatteryNotifier;
+
     static sp<MediaCodec> CreateByType(
-            const sp<ALooper> &looper, const char *mime, bool encoder);
+            const sp<ALooper> &looper, const char *mime, bool encoder, status_t *err = NULL);
 
     static sp<MediaCodec> CreateByComponentName(
-            const sp<ALooper> &looper, const char *name);
+            const sp<ALooper> &looper, const char *name, status_t *err = NULL);
 
     status_t configure(
             const sp<AMessage> &format,
@@ -56,6 +66,8 @@
             const sp<ICrypto> &crypto,
             uint32_t flags);
 
+    status_t setCallback(const sp<AMessage> &callback);
+
     status_t createInputSurface(sp<IGraphicBufferProducer>* bufferProducer);
 
     status_t start();
@@ -64,6 +76,10 @@
     // unconfigured.
     status_t stop();
 
+    // Resets the codec to the INITIALIZED state.  Can be called after an error
+    // has occured to make the codec usable.
+    status_t reset();
+
     // Client MUST call release before releasing final reference to this
     // object.
     status_t release();
@@ -100,16 +116,22 @@
             uint32_t *flags,
             int64_t timeoutUs = 0ll);
 
+    status_t renderOutputBufferAndRelease(size_t index, int64_t timestampNs);
     status_t renderOutputBufferAndRelease(size_t index);
     status_t releaseOutputBuffer(size_t index);
 
     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;
 
+    status_t getOutputBuffer(size_t index, sp<ABuffer> *buffer);
+    status_t getOutputFormat(size_t index, sp<AMessage> *format);
+    status_t getInputBuffer(size_t index, sp<ABuffer> *buffer);
+
     status_t requestIDRFrame();
 
     // Notification will be posted once there "is something to do", i.e.
@@ -135,6 +157,7 @@
         STARTING,
         STARTED,
         FLUSHING,
+        FLUSHED,
         STOPPING,
         RELEASING,
     };
@@ -159,6 +182,7 @@
         kWhatGetBuffers                     = 'getB',
         kWhatFlush                          = 'flus',
         kWhatGetOutputFormat                = 'getO',
+        kWhatGetInputFormat                 = 'getI',
         kWhatDequeueInputTimedOut           = 'dITO',
         kWhatDequeueOutputTimedOut          = 'dOTO',
         kWhatCodecNotify                    = 'codc',
@@ -166,6 +190,7 @@
         kWhatRequestActivityNotification    = 'racN',
         kWhatGetName                        = 'getN',
         kWhatSetParameters                  = 'setP',
+        kWhatSetCallback                    = 'setC',
     };
 
     enum {
@@ -179,26 +204,46 @@
         kFlagSawMediaServerDie          = 128,
         kFlagIsEncoder                  = 256,
         kFlagGatherCodecSpecificData    = 512,
+        kFlagIsAsync                    = 1024,
+        kFlagIsComponentAllocated       = 2048,
     };
 
     struct BufferInfo {
-        void *mBufferID;
+        uint32_t mBufferID;
         sp<ABuffer> mData;
         sp<ABuffer> mEncryptedData;
         sp<AMessage> mNotify;
+        sp<AMessage> mFormat;
         bool mOwnedByClient;
     };
 
     State mState;
     sp<ALooper> mLooper;
     sp<ALooper> mCodecLooper;
-    sp<ACodec> mCodec;
+    sp<CodecBase> mCodec;
     AString mComponentName;
     uint32_t mReplyID;
     uint32_t mFlags;
+    status_t mStickyError;
     sp<Surface> mNativeWindow;
     SoftwareRenderer *mSoftRenderer;
     sp<AMessage> mOutputFormat;
+    sp<AMessage> mInputFormat;
+    sp<AMessage> mCallback;
+
+    bool mBatteryStatNotified;
+    bool mIsVideo;
+
+    // initial create parameters
+    AString mInitName;
+    bool mInitNameIsType;
+    bool mInitIsEncoder;
+
+    // Used only to synchronize asynchronous getBufferAndFormat
+    // across all the other (synchronous) buffer state change
+    // operations, such as de/queueIn/OutputBuffer, start and
+    // stop/flush/reset/release.
+    Mutex mBufferLock;
 
     List<size_t> mAvailPortBuffers[2];
     Vector<BufferInfo> mPortBuffers[2];
@@ -222,7 +267,9 @@
     static status_t PostAndAwaitResponse(
             const sp<AMessage> &msg, sp<AMessage> *response);
 
-    status_t init(const char *name, bool nameIsType, bool encoder);
+    static void PostReplyWithError(int32_t replyID, int32_t err);
+
+    status_t init(const AString &name, bool nameIsType, bool encoder);
 
     void setState(State newState);
     void returnBuffersToCodec();
@@ -232,6 +279,10 @@
     status_t onReleaseOutputBuffer(const sp<AMessage> &msg);
     ssize_t dequeuePortBuffer(int32_t portIndex);
 
+    status_t getBufferAndFormat(
+            size_t portIndex, size_t index,
+            sp<ABuffer> *buffer, sp<AMessage> *format);
+
     bool handleDequeueInputBuffer(uint32_t replyID, bool newRequest = false);
     bool handleDequeueOutputBuffer(uint32_t replyID, bool newRequest = false);
     void cancelPendingDequeueOperations();
@@ -244,9 +295,28 @@
 
     void postActivityNotificationIfPossible();
 
+    void onInputBufferAvailable();
+    void onOutputBufferAvailable();
+    void onError(status_t err, int32_t actionCode, const char *detail = NULL);
+    void onOutputFormatChanged();
+
     status_t onSetParameters(const sp<AMessage> &params);
 
     status_t amendOutputFormatWithCodecSpecificData(const sp<ABuffer> &buffer);
+    void updateBatteryStat();
+    bool isExecuting() const;
+
+    /* called to get the last codec error when the sticky flag is set.
+     * if no such codec error is found, returns UNKNOWN_ERROR.
+     */
+    inline status_t getStickyError() const {
+        return mStickyError != 0 ? mStickyError : UNKNOWN_ERROR;
+    }
+
+    inline void setStickyError(status_t err) {
+        mFlags |= kFlagStickyError;
+        mStickyError = err;
+    }
 
     DISALLOW_EVIL_CONSTRUCTORS(MediaCodec);
 };