Merge "To reduce the bytes need to be buffered before start playing the streaming video. We might revert this change if too many spinnings were introduced. For bug 4448008."
diff --git a/drm/libdrmframework/plugins/common/util/include/SessionMap.h b/drm/libdrmframework/plugins/common/util/include/SessionMap.h
index 3dff58c..e563894 100644
--- a/drm/libdrmframework/plugins/common/util/include/SessionMap.h
+++ b/drm/libdrmframework/plugins/common/util/include/SessionMap.h
@@ -13,141 +13,175 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
 #ifndef __SESSIONMAP_H__
 #define __SESSIONMAP_H__
 
 #include <utils/KeyedVector.h>
+#include <utils/threads.h>
 
 namespace android {
 
 /**
- * A wrapper template class for handling DRM Engine sessions.
+ * A thread safe wrapper template class for session handlings for Drm Engines. It wraps a
+ * pointer type over KeyedVector. It keeps pointer as data in the vector and free up memory
+ * allocated pointer can be of any type of structure/class meant for keeping session data.
+ * so session object here means pointer to the session data.
  */
-template <typename NODE>
+template <typename TValue>
 class SessionMap {
 
 public:
-    KeyedVector<int, NODE> map;
-
     SessionMap() {}
 
     virtual ~SessionMap() {
+        Mutex::Autolock lock(mLock);
         destroyMap();
     }
 
-/**
- * Adds a new value in the session map table. It expects memory to be allocated already
- * for the session object
- *
- * @param key - key or Session ID
- * @param value - session object to add
- *
- * @return boolean result of adding value. returns false if key is already exist.
- */
-bool addValue(int key, NODE value) {
-    bool result = false;
-
-    if (!isCreated(key)) {
-        map.add(key, value);
-        result = true;
+    /**
+     * Adds a new value in the session map table. It expects memory to be allocated already
+     * for the session object
+     *
+     * @param key - key or Session ID
+     * @param value - session object to add
+     *
+     * @return boolean result of adding value. returns false if key is already exist.
+     */
+    bool addValue(int key, TValue value) {
+        Mutex::Autolock lock(mLock);
+        if (!isCreatedInternal(key)) {
+            map.add(key, value);
+            return true;
+        }
+        return false;
     }
 
-    return result;
-}
-
-
-/**
- * returns the session object by the key
- *
- * @param key - key or Session ID
- *
- * @return session object as per the key
- */
-NODE getValue(int key) {
-    NODE value = NULL;
-
-    if (isCreated(key)) {
-        value = (NODE) map.valueFor(key);
+    /**
+     * returns the session object by the key
+     *
+     * @param key - key or Session ID
+     *
+     * @return session object as per the key
+     */
+    TValue getValue(int key) {
+        Mutex::Autolock lock(mLock);
+        return getValueInternal(key);
     }
 
-    return value;
-}
-
-/**
- * returns the number of objects in the session map table
- *
- * @return count of number of session objects.
- */
-int getSize() {
-    return map.size();
-}
-
-/**
- * returns the session object by the index in the session map table
- *
- * @param index - index of the value required
- *
- * @return session object as per the index
- */
-NODE getValueAt(unsigned int index) {
-    NODE value = NULL;
-
-    if (map.size() > index) {
-      value = map.valueAt(index);
+    /**
+     * returns the number of objects in the session map table
+     *
+     * @return count of number of session objects.
+     */
+    int getSize() {
+        Mutex::Autolock lock(mLock);
+        return map.size();
     }
 
-    return value;
-}
+    /**
+     * returns the session object by the index in the session map table
+     *
+     * @param index - index of the value required
+     *
+     * @return session object as per the index
+     */
+    TValue getValueAt(unsigned int index) {
+        TValue value = NULL;
+        Mutex::Autolock lock(mLock);
 
-/**
- * deletes the object from session map. It also frees up memory for the session object.
- *
- * @param key - key of the value to be deleted
- *
- */
-void removeValue(int key) {
-    deleteValue(getValue(key));
-    map.removeItem(key);
-}
-
-/**
- * decides if session is already created.
- *
- * @param key - key of the value for the session
- *
- * @return boolean result of whether session is created
- */
-bool isCreated(int key) {
-    return (0 <= map.indexOfKey(key));
-}
-
-/**
- * empty the entire session table. It releases all the memory for session objects.
- */
-void destroyMap() {
-    int size = map.size();
-    int i = 0;
-
-    for (i = 0; i < size; i++) {
-        deleteValue(map.valueAt(i));
+        if (map.size() > index) {
+            value = map.valueAt(index);
+        }
+        return value;
     }
 
-    map.clear();
-}
+    /**
+     * deletes the object from session map. It also frees up memory for the session object.
+     *
+     * @param key - key of the value to be deleted
+     *
+     */
+    void removeValue(int key) {
+        Mutex::Autolock lock(mLock);
+        deleteValue(getValueInternal(key));
+        map.removeItem(key);
+    }
 
-/**
- * free up the memory for the session object.
- * Make sure if any reference to the session object anywhere, otherwise it will be a
- * dangle pointer after this call.
- *
- * @param value - session object to free
- *
- */
-void deleteValue(NODE value) {
-    delete value;
-}
+    /**
+     * decides if session is already created.
+     *
+     * @param key - key of the value for the session
+     *
+     * @return boolean result of whether session is created
+     */
+    bool isCreated(int key) {
+        Mutex::Autolock lock(mLock);
+        return isCreatedInternal(key);
+    }
 
+    SessionMap<TValue> & operator=(const SessionMap<TValue> & objectCopy) {
+        Mutex::Autolock lock(mLock);
+
+        destroyMap();
+        map = objectCopy.map;
+        return *this;
+    }
+
+private:
+    KeyedVector<int, TValue> map;
+    Mutex mLock;
+
+   /**
+    * free up the memory for the session object.
+    * Make sure if any reference to the session object anywhere, otherwise it will be a
+    * dangle pointer after this call.
+    *
+    * @param value - session object to free
+    *
+    */
+    void deleteValue(TValue value) {
+        delete value;
+    }
+
+   /**
+    * free up the memory for the entire map.
+    * free up any resources in the sessions before calling this funtion.
+    *
+    */
+    void destroyMap() {
+        int size = map.size();
+
+        for (int i = 0; i < size; i++) {
+            deleteValue(map.valueAt(i));
+        }
+        map.clear();
+    }
+
+   /**
+    * decides if session is already created.
+    *
+    * @param key - key of the value for the session
+    *
+    * @return boolean result of whether session is created
+    */
+    bool isCreatedInternal(int key) {
+        return(0 <= map.indexOfKey(key));
+    }
+
+   /**
+    * returns the session object by the key
+    *
+    * @param key - key or Session ID
+    *
+    * @return session object as per the key
+    */
+    TValue getValueInternal(int key) {
+        TValue value = NULL;
+        if (isCreatedInternal(key)) {
+            value = (TValue) map.valueFor(key);
+        }
+        return value;
+    }
 };
 
 };
diff --git a/drm/libdrmframework/plugins/common/util/src/MimeTypeUtil.cpp b/drm/libdrmframework/plugins/common/util/src/MimeTypeUtil.cpp
index 4ee903e..57ef799 100644
--- a/drm/libdrmframework/plugins/common/util/src/MimeTypeUtil.cpp
+++ b/drm/libdrmframework/plugins/common/util/src/MimeTypeUtil.cpp
@@ -22,6 +22,13 @@
 #undef LOG_TAG
 #define LOG_TAG "MimeTypeUtil"
 
+#ifdef DRM_OMA_FL_ENGINE_DEBUG
+#define LOG_NDEBUG 0
+#define LOG_DEBUG(...) LOGD(__VA_ARGS__)
+#else
+#define LOG_DEBUG(...)
+#endif
+
 enum {
     MIMETYPE_AUDIO       = 0,
     MIMETYPE_APPLICATION = 1,
@@ -59,6 +66,7 @@
 static const char mime_group_application[] = "application/";
 static const char mime_group_image[]       = "image/";
 static const char mime_group_video[]       = "video/";
+static const char mime_type_unsupported[]  = "unsupported/drm.mimetype";
 
 static struct MimeGroup mimeGroup[] = {
     {MIMETYPE_AUDIO,       mime_group_audio,        sizeof(mime_group_audio)-1},
@@ -107,48 +115,52 @@
  * replacement mimetype otherwise the original mimetype
  * is returned.
  *
+ * If the mimetype is of unsupported group i.e. application/*
+ * then "unsupported/drm.mimetype" will be returned.
+ *
  * @param mimeType - mimetype in lower case to convert.
  *
- * @return mimetype or null.
+ * @return mimetype or "unsupported/drm.mimetype".
  */
 String8 MimeTypeUtil::convertMimeType(String8& mimeType) {
     String8 result = mimeType;
-    const char* pTmp;
     const char* pMimeType;
     struct MimeGroup* pGroup;
     struct MimeTypeList* pMimeItem;
     int len;
-
     pMimeType = mimeType.string();
     if (NULL != pMimeType) {
-        /* Check which group the mimetype is */
-        pGroup = mimeGroup;
-
-        while (MIMETYPE_LAST != pGroup->type) {
-            if (0 == strncmp(pMimeType, pGroup->pGroup, pGroup->size)) {
-                break;
-            }
-            pGroup++;
-        }
-
-        /* Go through the mimetype list. Only check items of the correct group */
-        if (MIMETYPE_LAST != pGroup->type) {
-            pMimeItem = mimeTypeList;
-            len = strlen (pMimeType+pGroup->size);
-
-            while (MIMETYPE_LAST != pMimeItem->type) {
-                if ((len == pMimeItem->size) &&
-                    (0 == strcmp(pMimeType+pGroup->size, pMimeItem->pMimeExt))) {
-                    result = String8(pMimeItem->pMimeType);
+        if ((0 == strncmp(pMimeType, mime_group_audio, (sizeof mime_group_audio) - 1)) ||
+            (0 == strncmp(pMimeType, mime_group_video, (sizeof mime_group_video) - 1))) {
+            /* Check which group the mimetype is */
+            pGroup = mimeGroup;
+            while (MIMETYPE_LAST != pGroup->type) {
+                if (0 == strncmp(pMimeType, pGroup->pGroup, pGroup->size)) {
                     break;
                 }
-                pMimeItem++;
+                pGroup++;
             }
-        }
-        LOGI("convertMimeType got mimetype %s, converted into mimetype %s",
-             pMimeType, result.string());
-    }
 
+            /* Go through the mimetype list. Only check items of the correct group */
+            if (MIMETYPE_LAST != pGroup->type) {
+                pMimeItem = mimeTypeList;
+                len = strlen (pMimeType+pGroup->size);
+                while (MIMETYPE_LAST != pMimeItem->type) {
+                    if ((pGroup->type == pMimeItem->type) &&
+                        (len == pMimeItem->size) &&
+                        (0 == strcmp(pMimeType+pGroup->size, pMimeItem->pMimeExt))) {
+                        result = String8(pMimeItem->pMimeType);
+                        break;
+                    }
+                    pMimeItem++;
+                }
+            }
+        } else {
+            result = String8(mime_type_unsupported);
+        }
+        LOG_DEBUG("convertMimeType got mimetype %s, converted into mimetype %s",
+                pMimeType, result.string());
+    }
     return result;
 }
 };
diff --git a/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/Android.mk b/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/Android.mk
index 9805a40..e359dbd 100644
--- a/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/Android.mk
+++ b/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/Android.mk
@@ -17,6 +17,9 @@
 
 include $(CLEAR_VARS)
 
+# The flag below turns on local debug printouts
+#LOCAL_CFLAGS += -DDRM_OMA_FL_ENGINE_DEBUG
+
 base := frameworks/base
 
 # Determine whether the DRM framework uses 64-bit data types for file offsets and do the same.
diff --git a/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/src/FwdLockEngine.cpp b/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/src/FwdLockEngine.cpp
index 31c3c14..e184545 100644
--- a/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/src/FwdLockEngine.cpp
+++ b/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/src/FwdLockEngine.cpp
@@ -41,6 +41,13 @@
 #undef LOG_TAG
 #define LOG_TAG "FwdLockEngine"
 
+#ifdef DRM_OMA_FL_ENGINE_DEBUG
+#define LOG_NDEBUG 0
+#define LOG_VERBOSE(...) LOGV(__VA_ARGS__)
+#else
+#define LOG_VERBOSE(...)
+#endif
+
 using namespace android;
 // This extern "C" is mandatory to be managed by TPlugInManager
 extern "C" IDrmEngine* create() {
@@ -53,14 +60,25 @@
 }
 
 FwdLockEngine::FwdLockEngine() {
-    LOGV("FwdLockEngine Construction");
+    LOG_VERBOSE("FwdLockEngine Construction");
 }
 
 FwdLockEngine::~FwdLockEngine() {
-    LOGV("FwdLockEngine Destruction");
+    LOG_VERBOSE("FwdLockEngine Destruction");
 
-    convertSessionMap.destroyMap();
-    decodeSessionMap.destroyMap();
+    int size = decodeSessionMap.getSize();
+
+    for (int i = 0; i < size; i++) {
+        DecodeSession *session = (DecodeSession*) decodeSessionMap.getValueAt(i);
+        FwdLockFile_detach(session->fileDesc);
+        ::close(session->fileDesc);
+    }
+
+    size = convertSessionMap.getSize();
+    for (int i = 0; i < size; i++) {
+        ConvertSession *convSession = (ConvertSession*) convertSessionMap.getValueAt(i);
+        FwdLockConv_CloseSession(convSession->uniqueId, &(convSession->output));
+    }
 }
 
 int FwdLockEngine::getConvertedStatus(FwdLockConv_Status_t status) {
@@ -74,12 +92,12 @@
         case FwdLockConv_Status_InvalidArgument:
         case FwdLockConv_Status_UnsupportedFileFormat:
         case FwdLockConv_Status_UnsupportedContentTransferEncoding:
-            LOGD("FwdLockEngine getConvertedStatus: file conversion Error %d. " \
+            LOGE("FwdLockEngine getConvertedStatus: file conversion Error %d. "
                   "Returning STATUS_INPUTDATA_ERROR", status);
             retStatus = DrmConvertedStatus::STATUS_INPUTDATA_ERROR;
             break;
         default:
-            LOGD("FwdLockEngine getConvertedStatus: file conversion Error %d. " \
+            LOGE("FwdLockEngine getConvertedStatus: file conversion Error %d. "
                   "Returning STATUS_ERROR", status);
             retStatus = DrmConvertedStatus::STATUS_ERROR;
             break;
@@ -91,7 +109,7 @@
 DrmConstraints* FwdLockEngine::onGetConstraints(int uniqueId, const String8* path, int action) {
     DrmConstraints* drmConstraints = NULL;
 
-    LOGV("FwdLockEngine::onGetConstraints");
+    LOG_VERBOSE("FwdLockEngine::onGetConstraints");
 
     if (NULL != path &&
         (RightsStatus::RIGHTS_VALID == onCheckRightsStatus(uniqueId, *path, action))) {
@@ -105,7 +123,7 @@
 DrmMetadata* FwdLockEngine::onGetMetadata(int uniqueId, const String8* path) {
     DrmMetadata* drmMetadata = NULL;
 
-    LOGV("FwdLockEngine::onGetMetadata");
+    LOG_VERBOSE("FwdLockEngine::onGetMetadata");
 
     if (NULL != path) {
         // Returns empty metadata to show no error condition.
@@ -116,13 +134,12 @@
 }
 
 android::status_t FwdLockEngine::onInitialize(int uniqueId) {
-    LOGV("FwdLockEngine::onInitialize");
-
+    LOG_VERBOSE("FwdLockEngine::onInitialize");
 
     if (FwdLockGlue_InitializeKeyEncryption()) {
-        LOGV("FwdLockEngine::onInitialize -- FwdLockGlue_InitializeKeyEncryption succeeded");
+        LOG_VERBOSE("FwdLockEngine::onInitialize -- FwdLockGlue_InitializeKeyEncryption succeeded");
     } else {
-        LOGD("FwdLockEngine::onInitialize -- FwdLockGlue_InitializeKeyEncryption failed:"
+        LOGE("FwdLockEngine::onInitialize -- FwdLockGlue_InitializeKeyEncryption failed:"
              "errno = %d", errno);
     }
 
@@ -132,13 +149,13 @@
 android::status_t
 FwdLockEngine::onSetOnInfoListener(int uniqueId, const IDrmEngine::OnInfoListener* infoListener) {
     // Not used
-    LOGV("FwdLockEngine::onSetOnInfoListener");
+    LOG_VERBOSE("FwdLockEngine::onSetOnInfoListener");
 
     return DRM_NO_ERROR;
 }
 
 android::status_t FwdLockEngine::onTerminate(int uniqueId) {
-    LOGV("FwdLockEngine::onTerminate");
+    LOG_VERBOSE("FwdLockEngine::onTerminate");
 
     return DRM_NO_ERROR;
 }
@@ -146,7 +163,7 @@
 DrmSupportInfo* FwdLockEngine::onGetSupportInfo(int uniqueId) {
     DrmSupportInfo* pSupportInfo = new DrmSupportInfo();
 
-    LOGV("FwdLockEngine::onGetSupportInfo");
+    LOG_VERBOSE("FwdLockEngine::onGetSupportInfo");
 
     // fill all Forward Lock mimetypes and extensions
     if (NULL != pSupportInfo) {
@@ -182,7 +199,7 @@
 
     drmInfoStatus = new DrmInfoStatus((int)DrmInfoStatus::STATUS_OK, 0, NULL, String8(""));
 
-    LOGV("FwdLockEngine::onProcessDrmInfo");
+    LOG_VERBOSE("FwdLockEngine::onProcessDrmInfo");
 
     return drmInfoStatus;
 }
@@ -193,7 +210,7 @@
             const String8& rightsPath,
             const String8& contentPath) {
     // No rights to save. Return
-    LOGV("FwdLockEngine::onSaveRights");
+    LOG_VERBOSE("FwdLockEngine::onSaveRights");
     return DRM_ERROR_UNKNOWN;
 }
 
@@ -201,7 +218,7 @@
     DrmInfo* drmInfo = NULL;
 
     // Nothing to be done for Forward Lock file
-    LOGV("FwdLockEngine::onAcquireDrmInfo");
+    LOG_VERBOSE("FwdLockEngine::onAcquireDrmInfo");
 
     return drmInfo;
 }
@@ -211,7 +228,7 @@
                                        int action) {
     int result = RightsStatus::RIGHTS_INVALID;
 
-    LOGV("FwdLockEngine::onCheckRightsStatus");
+    LOG_VERBOSE("FwdLockEngine::onCheckRightsStatus");
 
     // Only Transfer action is not allowed for forward Lock files.
     if (onCanHandle(uniqueId, path)) {
@@ -241,7 +258,7 @@
                                         int action,
                                         bool reserve) {
     // No rights consumption
-    LOGV("FwdLockEngine::onConsumeRights");
+    LOG_VERBOSE("FwdLockEngine::onConsumeRights");
     return DRM_NO_ERROR;
 }
 
@@ -249,14 +266,14 @@
                                      const String8& path,
                                      int action,
                                      const ActionDescription& description) {
-    LOGV("FwdLockEngine::onValidateAction");
+    LOG_VERBOSE("FwdLockEngine::onValidateAction");
 
     // For the forwardlock engine checkRights and ValidateAction are the same.
     return (onCheckRightsStatus(uniqueId, path, action) == RightsStatus::RIGHTS_VALID);
 }
 
 String8 FwdLockEngine::onGetOriginalMimeType(int uniqueId, const String8& path) {
-    LOGV("FwdLockEngine::onGetOriginalMimeType");
+    LOG_VERBOSE("FwdLockEngine::onGetOriginalMimeType");
     String8 mimeString = String8("");
     int fileDesc = FwdLockFile_open(path.string());
 
@@ -280,7 +297,7 @@
                                       const String8& mimeType) {
     String8 mimeStr = String8(mimeType);
 
-    LOGV("FwdLockEngine::onGetDrmObjectType");
+    LOG_VERBOSE("FwdLockEngine::onGetDrmObjectType");
 
     mimeStr.toLower();
 
@@ -301,13 +318,13 @@
 
 status_t FwdLockEngine::onRemoveRights(int uniqueId, const String8& path) {
     // No Rights to remove
-    LOGV("FwdLockEngine::onRemoveRights");
+    LOG_VERBOSE("FwdLockEngine::onRemoveRights");
     return DRM_NO_ERROR;
 }
 
 status_t FwdLockEngine::onRemoveAllRights(int uniqueId) {
     // No rights to remove
-    LOGV("FwdLockEngine::onRemoveAllRights");
+    LOG_VERBOSE("FwdLockEngine::onRemoveAllRights");
     return DRM_NO_ERROR;
 }
 
@@ -319,14 +336,14 @@
                                             int playbackStatus, int position) {
 #endif
     // Not used
-    LOGV("FwdLockEngine::onSetPlaybackStatus");
+    LOG_VERBOSE("FwdLockEngine::onSetPlaybackStatus");
     return DRM_NO_ERROR;
 }
 
 status_t FwdLockEngine::onOpenConvertSession(int uniqueId,
                                          int convertId) {
     status_t result = DRM_ERROR_UNKNOWN;
-    LOGV("FwdLockEngine::onOpenConvertSession");
+    LOG_VERBOSE("FwdLockEngine::onOpenConvertSession");
     if (!convertSessionMap.isCreated(convertId)) {
         ConvertSession *newSession = new ConvertSession();
         if (FwdLockConv_Status_OK ==
@@ -334,7 +351,7 @@
             convertSessionMap.addValue(convertId, newSession);
             result = DRM_NO_ERROR;
         } else {
-            LOGD("FwdLockEngine::onOpenConvertSession -- FwdLockConv_OpenSession failed.");
+            LOGE("FwdLockEngine::onOpenConvertSession -- FwdLockConv_OpenSession failed.");
             delete newSession;
         }
     }
@@ -383,7 +400,7 @@
     DrmBuffer *convResult = new DrmBuffer(NULL, 0);
     int offset = -1;
 
-    LOGV("FwdLockEngine::onCloseConvertSession");
+    LOG_VERBOSE("FwdLockEngine::onCloseConvertSession");
 
     if (convertSessionMap.isCreated(convertId)) {
         ConvertSession *convSession = convertSessionMap.getValue(convertId);
@@ -424,14 +441,14 @@
     status_t result = DRM_ERROR_CANNOT_HANDLE;
     int fileDesc = -1;
 
-    LOGV("FwdLockEngine::onOpenDecryptSession");
+    LOG_VERBOSE("FwdLockEngine::onOpenDecryptSession");
 
     if ((-1 < fd) &&
         (NULL != decryptHandle) &&
         (!decodeSessionMap.isCreated(decryptHandle->decryptId))) {
         fileDesc = dup(fd);
     } else {
-        LOGD("FwdLockEngine::onOpenDecryptSession parameter error");
+        LOGE("FwdLockEngine::onOpenDecryptSession parameter error");
         return result;
     }
 
@@ -453,7 +470,7 @@
             decryptHandle->decryptInfo = NULL;
             result = DRM_NO_ERROR;
         } else {
-            LOGD("FwdLockEngine::onOpenDecryptSession Integrity Check failed for the fd");
+            LOG_VERBOSE("FwdLockEngine::onOpenDecryptSession Integrity Check failed for the fd");
             FwdLockFile_detach(fileDesc);
             delete decodeSession;
         }
@@ -463,7 +480,7 @@
         ::close(fileDesc);
     }
 
-    LOGV("FwdLockEngine::onOpenDecryptSession Exit. result = %d", result);
+    LOG_VERBOSE("FwdLockEngine::onOpenDecryptSession Exit. result = %d", result);
 
     return result;
 }
@@ -500,7 +517,7 @@
 status_t FwdLockEngine::onCloseDecryptSession(int uniqueId,
                                               DecryptHandle* decryptHandle) {
     status_t result = DRM_ERROR_UNKNOWN;
-    LOGV("FwdLockEngine::onCloseDecryptSession");
+    LOG_VERBOSE("FwdLockEngine::onCloseDecryptSession");
 
     if (NULL != decryptHandle && decodeSessionMap.isCreated(decryptHandle->decryptId)) {
         DecodeSession* session = decodeSessionMap.getValue(decryptHandle->decryptId);
@@ -525,7 +542,7 @@
         decryptHandle = NULL;
     }
 
-    LOGV("FwdLockEngine::onCloseDecryptSession Exit");
+    LOG_VERBOSE("FwdLockEngine::onCloseDecryptSession Exit");
     return result;
 }
 
@@ -533,13 +550,13 @@
                                                 DecryptHandle* decryptHandle,
                                                 int decryptUnitId,
                                                 const DrmBuffer* headerInfo) {
-    LOGV("FwdLockEngine::onInitializeDecryptUnit");
+    LOGE("FwdLockEngine::onInitializeDecryptUnit is not supported for this DRM scheme");
     return DRM_ERROR_UNKNOWN;
 }
 
 status_t FwdLockEngine::onDecrypt(int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId,
             const DrmBuffer* encBuffer, DrmBuffer** decBuffer, DrmBuffer* IV) {
-    LOGV("FwdLockEngine::onDecrypt");
+    LOGE("FwdLockEngine::onDecrypt is not supported for this DRM scheme");
     return DRM_ERROR_UNKNOWN;
 }
 
@@ -548,14 +565,14 @@
                                   int decryptUnitId,
                                   const DrmBuffer* encBuffer,
                                   DrmBuffer** decBuffer) {
-    LOGV("FwdLockEngine::onDecrypt");
+    LOGE("FwdLockEngine::onDecrypt is not supported for this DRM scheme");
     return DRM_ERROR_UNKNOWN;
 }
 
 status_t FwdLockEngine::onFinalizeDecryptUnit(int uniqueId,
                                               DecryptHandle* decryptHandle,
                                               int decryptUnitId) {
-    LOGV("FwdLockEngine::onFinalizeDecryptUnit");
+    LOGE("FwdLockEngine::onFinalizeDecryptUnit is not supported for this DRM scheme");
     return DRM_ERROR_UNKNOWN;
 }
 
@@ -633,11 +650,11 @@
         if (((off_t)-1) != decoderSession->offset) {
             bytesRead = onRead(uniqueId, decryptHandle, buffer, numBytes);
             if (bytesRead < 0) {
-                LOGD("FwdLockEngine::onPread error reading");
+                LOGE("FwdLockEngine::onPread error reading");
             }
         }
     } else {
-        LOGD("FwdLockEngine::onPread decryptId not found");
+        LOGE("FwdLockEngine::onPread decryptId not found");
     }
 
     return bytesRead;
diff --git a/drm/libdrmframework/plugins/forward-lock/internal-format/converter/FwdLockConv.c b/drm/libdrmframework/plugins/forward-lock/internal-format/converter/FwdLockConv.c
index 14ea9e9..299116d 100644
--- a/drm/libdrmframework/plugins/forward-lock/internal-format/converter/FwdLockConv.c
+++ b/drm/libdrmframework/plugins/forward-lock/internal-format/converter/FwdLockConv.c
@@ -275,17 +275,18 @@
 }
 
 /**
- * Checks whether a given character is valid in a boundary. Note that the boundary may contain
- * leading and internal spaces.
+ * Checks whether a given character is valid in a boundary. Allows some non-standard characters that
+ * are invalid according to RFC 2046 but nevertheless used by one vendor's DRM packager. Note that
+ * the boundary may contain leading and internal spaces.
  *
  * @param[in] ch The character to check.
  *
  * @return A Boolean value indicating whether the given character is valid in a boundary.
  */
 static int FwdLockConv_IsBoundaryChar(int ch) {
-    return isalnum(ch) || ch == '\'' ||
-            ch == '(' || ch == ')' || ch == '+' || ch == '_' || ch == ',' || ch == '-' ||
-            ch == '.' || ch == '/' || ch == ':' || ch == '=' || ch == '?' || ch == ' ';
+    return isalnum(ch) || ch == '\'' || ch == '(' || ch == ')' || ch == '+' || ch == '_' ||
+            ch == ',' || ch == '-' || ch == '.' || ch == '/' || ch == ':' || ch == '=' ||
+            ch == '?' || ch == ' ' || ch == '%' || ch == '[' || ch == '&' || ch == '*' || ch == '^';
 }
 
 /**
@@ -1085,6 +1086,13 @@
         status = FwdLockConv_MatchBinaryEncodedData(pSession, ch, pOutput);
         break;
     case FwdLockConv_ParserState_WantsBase64EncodedData:
+        if (ch == '\n' && pSession->scannerState != FwdLockConv_ScannerState_WantsLF) {
+            // Repair base64-encoded data that doesn't have carriage returns in its line breaks.
+            status = FwdLockConv_MatchBase64EncodedData(pSession, '\r', pOutput);
+            if (status != FwdLockConv_Status_OK) {
+                break;
+            }
+        }
         status = FwdLockConv_MatchBase64EncodedData(pSession, ch, pOutput);
         break;
     case FwdLockConv_ParserState_Done:
@@ -1199,7 +1207,7 @@
             status = FwdLockConv_Status_SyntaxError;
         } else {
             // Finalize the data signature.
-            size_t signatureSize;
+            unsigned int signatureSize = SHA1_HASH_SIZE;
             HMAC_Final(&pSession->signingContext, pOutput->fromCloseSession.signatures,
                        &signatureSize);
             if (signatureSize != SHA1_HASH_SIZE) {
@@ -1214,9 +1222,9 @@
                 HMAC_Update(&pSession->signingContext, pSession->pEncryptedSessionKey,
                             pSession->encryptedSessionKeyLength);
                 HMAC_Update(&pSession->signingContext, pOutput->fromCloseSession.signatures,
-                            signatureSize);
-                HMAC_Final(&pSession->signingContext, &pOutput->fromCloseSession.
-                           signatures[signatureSize], &signatureSize);
+                            SHA1_HASH_SIZE);
+                HMAC_Final(&pSession->signingContext,
+                           &pOutput->fromCloseSession.signatures[SHA1_HASH_SIZE], &signatureSize);
                 if (signatureSize != SHA1_HASH_SIZE) {
                     status = FwdLockConv_Status_ProgramError;
                 } else {
diff --git a/drm/libdrmframework/plugins/forward-lock/internal-format/decoder/FwdLockFile.c b/drm/libdrmframework/plugins/forward-lock/internal-format/decoder/FwdLockFile.c
index 98284e7..dacf00e 100644
--- a/drm/libdrmframework/plugins/forward-lock/internal-format/decoder/FwdLockFile.c
+++ b/drm/libdrmframework/plugins/forward-lock/internal-format/decoder/FwdLockFile.c
@@ -114,7 +114,7 @@
 }
 
 /**
- * Finds the file session associated to the given file descriptor.
+ * Finds the file session associated with the given file descriptor.
  *
  * @param[in] fileDesc A file descriptor.
  *
@@ -389,7 +389,7 @@
                 result = FALSE;
             } else {
                 ssize_t numBytesRead;
-                size_t signatureSize = SHA1_HASH_SIZE;
+                unsigned int signatureSize = SHA1_HASH_SIZE;
                 while ((numBytesRead =
                         read(pSession->fileDesc, pData->buffer, SIG_CALC_BUFFER_SIZE)) > 0) {
                     HMAC_Update(&pSession->signingContext, pData->buffer, (size_t)numBytesRead);
@@ -399,7 +399,7 @@
                 } else {
                     HMAC_Final(&pSession->signingContext, pData->signature, &signatureSize);
                     assert(signatureSize == SHA1_HASH_SIZE);
-                    result = memcmp(pData->signature, pSession->dataSignature, signatureSize) == 0;
+                    result = memcmp(pData->signature, pSession->dataSignature, SHA1_HASH_SIZE) == 0;
                 }
                 HMAC_Init_ex(&pSession->signingContext, NULL, KEY_SIZE, NULL, NULL);
                 (void)lseek64(pSession->fileDesc, pSession->dataOffset + pSession->filePos,
@@ -419,16 +419,16 @@
     } else {
         FwdLockFile_Session_t *pSession = sessionPtrs[sessionId];
         unsigned char signature[SHA1_HASH_SIZE];
-        size_t signatureSize = SHA1_HASH_SIZE;
+        unsigned int signatureSize = SHA1_HASH_SIZE;
         HMAC_Update(&pSession->signingContext, pSession->topHeader, TOP_HEADER_SIZE);
         HMAC_Update(&pSession->signingContext, (unsigned char *)pSession->pContentType,
                     pSession->contentTypeLength);
         HMAC_Update(&pSession->signingContext, pSession->pEncryptedSessionKey,
                     pSession->encryptedSessionKeyLength);
-        HMAC_Update(&pSession->signingContext, pSession->dataSignature, signatureSize);
+        HMAC_Update(&pSession->signingContext, pSession->dataSignature, SHA1_HASH_SIZE);
         HMAC_Final(&pSession->signingContext, signature, &signatureSize);
         assert(signatureSize == SHA1_HASH_SIZE);
-        result = memcmp(signature, pSession->headerSignature, signatureSize) == 0;
+        result = memcmp(signature, pSession->headerSignature, SHA1_HASH_SIZE) == 0;
         HMAC_Init_ex(&pSession->signingContext, NULL, KEY_SIZE, NULL, NULL);
     }
     return result;
diff --git a/include/media/AudioSystem.h b/include/media/AudioSystem.h
index f20e234..eb22e32 100644
--- a/include/media/AudioSystem.h
+++ b/include/media/AudioSystem.h
@@ -108,6 +108,8 @@
     static unsigned int  getInputFramesLost(audio_io_handle_t ioHandle);
 
     static int newAudioSessionId();
+    static void acquireAudioSessionId(int audioSession);
+    static void releaseAudioSessionId(int audioSession);
 
     // types of io configuration change events received with ioConfigChanged()
     enum io_config_event {
diff --git a/include/media/IAudioFlinger.h b/include/media/IAudioFlinger.h
index 4037c46..9e3cb7f 100644
--- a/include/media/IAudioFlinger.h
+++ b/include/media/IAudioFlinger.h
@@ -139,6 +139,9 @@
 
     virtual int newAudioSessionId() = 0;
 
+    virtual void acquireAudioSessionId(int audioSession) = 0;
+    virtual void releaseAudioSessionId(int audioSession) = 0;
+
     virtual status_t queryNumberEffects(uint32_t *numEffects) = 0;
 
     virtual status_t queryEffect(uint32_t index, effect_descriptor_t *pDescriptor) = 0;
diff --git a/include/media/stagefright/MediaBuffer.h b/include/media/stagefright/MediaBuffer.h
index c1c4f94..3d79596 100644
--- a/include/media/stagefright/MediaBuffer.h
+++ b/include/media/stagefright/MediaBuffer.h
@@ -25,6 +25,7 @@
 
 namespace android {
 
+struct ABuffer;
 class GraphicBuffer;
 class MediaBuffer;
 class MediaBufferObserver;
@@ -51,6 +52,8 @@
 
     MediaBuffer(const sp<GraphicBuffer>& graphicBuffer);
 
+    MediaBuffer(const sp<ABuffer> &buffer);
+
     // Decrements the reference count and returns the buffer to its
     // associated MediaBufferGroup if the reference count drops to 0.
     void release();
@@ -100,6 +103,7 @@
     void *mData;
     size_t mSize, mRangeOffset, mRangeLength;
     sp<GraphicBuffer> mGraphicBuffer;
+    sp<ABuffer> mBuffer;
 
     bool mOwnsData;
 
diff --git a/include/media/stagefright/SurfaceMediaSource.h b/include/media/stagefright/SurfaceMediaSource.h
index fab258c..1affb8a 100644
--- a/include/media/stagefright/SurfaceMediaSource.h
+++ b/include/media/stagefright/SurfaceMediaSource.h
@@ -133,7 +133,8 @@
     //
     // This method will fail if the connect was previously called on the
     // SurfaceMediaSource and no corresponding disconnect call was made.
-    virtual status_t connect(int api);
+    virtual status_t connect(int api,
+            uint32_t* outWidth, uint32_t* outHeight, uint32_t* outTransform);
 
     // disconnect attempts to disconnect a client API from the SurfaceMediaSource.
     // Calling this method will cause any subsequent calls to other
diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp
index 16554c2..e5062ab 100644
--- a/media/libmedia/AudioRecord.cpp
+++ b/media/libmedia/AudioRecord.cpp
@@ -114,6 +114,7 @@
         }
         mAudioRecord.clear();
         IPCThreadState::self()->flushCommands();
+        AudioSystem::releaseAudioSessionId(mSessionId);
     }
 }
 
@@ -233,6 +234,7 @@
     mInputSource = (uint8_t)inputSource;
     mFlags = flags;
     mInput = input;
+    AudioSystem::acquireAudioSessionId(mSessionId);
 
     return NO_ERROR;
 }
@@ -465,6 +467,7 @@
                                                        ((uint16_t)flags) << 16,
                                                        &mSessionId,
                                                        &status);
+
     if (record == 0) {
         LOGE("AudioFlinger could not create record track, status: %d", status);
         return status;
diff --git a/media/libmedia/AudioSystem.cpp b/media/libmedia/AudioSystem.cpp
index 5009957..b26ed71 100644
--- a/media/libmedia/AudioSystem.cpp
+++ b/media/libmedia/AudioSystem.cpp
@@ -356,6 +356,20 @@
     return af->newAudioSessionId();
 }
 
+void AudioSystem::acquireAudioSessionId(int audioSession) {
+    const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
+    if (af != 0) {
+        af->acquireAudioSessionId(audioSession);
+    }
+}
+
+void AudioSystem::releaseAudioSessionId(int audioSession) {
+    const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
+    if (af != 0) {
+        af->releaseAudioSessionId(audioSession);
+    }
+}
+
 // ---------------------------------------------------------------------------
 
 void AudioSystem::AudioFlingerClient::binderDied(const wp<IBinder>& who) {
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index 31eb97a..3949c39 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -134,6 +134,7 @@
         }
         mAudioTrack.clear();
         IPCThreadState::self()->flushCommands();
+        AudioSystem::releaseAudioSessionId(mSessionId);
     }
 }
 
@@ -259,6 +260,7 @@
     mNewPosition = 0;
     mUpdatePeriod = 0;
     mFlags = flags;
+    AudioSystem::acquireAudioSessionId(mSessionId);
 
     return NO_ERROR;
 }
diff --git a/media/libmedia/IAudioFlinger.cpp b/media/libmedia/IAudioFlinger.cpp
index 4a12962..d58834b 100644
--- a/media/libmedia/IAudioFlinger.cpp
+++ b/media/libmedia/IAudioFlinger.cpp
@@ -1,4 +1,4 @@
-/* //device/extlibs/pv/android/IAudioflinger.cpp
+/*
 **
 ** Copyright 2007, The Android Open Source Project
 **
@@ -63,6 +63,8 @@
     GET_RENDER_POSITION,
     GET_INPUT_FRAMES_LOST,
     NEW_AUDIO_SESSION_ID,
+    ACQUIRE_AUDIO_SESSION_ID,
+    RELEASE_AUDIO_SESSION_ID,
     QUERY_NUM_EFFECTS,
     QUERY_EFFECT,
     GET_EFFECT_DESCRIPTOR,
@@ -526,6 +528,22 @@
         return id;
     }
 
+    virtual void acquireAudioSessionId(int audioSession)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+        data.writeInt32(audioSession);
+        remote()->transact(ACQUIRE_AUDIO_SESSION_ID, data, &reply);
+    }
+
+    virtual void releaseAudioSessionId(int audioSession)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+        data.writeInt32(audioSession);
+        remote()->transact(RELEASE_AUDIO_SESSION_ID, data, &reply);
+    }
+
     virtual status_t queryNumberEffects(uint32_t *numEffects)
     {
         Parcel data, reply;
@@ -919,6 +937,18 @@
             reply->writeInt32(newAudioSessionId());
             return NO_ERROR;
         } break;
+        case ACQUIRE_AUDIO_SESSION_ID: {
+            CHECK_INTERFACE(IAudioFlinger, data, reply);
+            int audioSession = data.readInt32();
+            acquireAudioSessionId(audioSession);
+            return NO_ERROR;
+        } break;
+        case RELEASE_AUDIO_SESSION_ID: {
+            CHECK_INTERFACE(IAudioFlinger, data, reply);
+            int audioSession = data.readInt32();
+            releaseAudioSessionId(audioSession);
+            return NO_ERROR;
+        } break;
         case QUERY_NUM_EFFECTS: {
             CHECK_INTERFACE(IAudioFlinger, data, reply);
             uint32_t numEffects;
diff --git a/media/libmedia/mediaplayer.cpp b/media/libmedia/mediaplayer.cpp
index 3dd9249..67a66a2 100644
--- a/media/libmedia/mediaplayer.cpp
+++ b/media/libmedia/mediaplayer.cpp
@@ -61,12 +61,14 @@
     mVideoWidth = mVideoHeight = 0;
     mLockThreadId = 0;
     mAudioSessionId = AudioSystem::newAudioSessionId();
+    AudioSystem::acquireAudioSessionId(mAudioSessionId);
     mSendLevel = 0;
 }
 
 MediaPlayer::~MediaPlayer()
 {
     LOGV("destructor");
+    AudioSystem::releaseAudioSessionId(mAudioSessionId);
     disconnect();
     IPCThreadState::self()->flushCommands();
 }
@@ -618,7 +620,11 @@
     if (sessionId < 0) {
         return BAD_VALUE;
     }
-    mAudioSessionId = sessionId;
+    if (sessionId != mAudioSessionId) {
+      AudioSystem::releaseAudioSessionId(mAudioSessionId);
+      AudioSystem::acquireAudioSessionId(sessionId);
+      mAudioSessionId = sessionId;
+    }
     return NO_ERROR;
 }
 
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index 1e7c969..8630ec1 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -255,8 +255,8 @@
             this, pid, connId, client, audioSessionId,
             IPCThreadState::self()->getCallingUid());
 
-    LOGV("Create new client(%d) from pid %d, url=%s, connId=%d, audioSessionId=%d",
-            connId, pid, url, connId, audioSessionId);
+    LOGV("Create new client(%d) from pid %d, uid %d, url=%s, connId=%d, audioSessionId=%d",
+            connId, pid, IPCThreadState::self()->getCallingUid(), url, connId, audioSessionId);
     if (NO_ERROR != c->setDataSource(url, headers))
     {
         c.clear();
@@ -277,8 +277,9 @@
             this, pid, connId, client, audioSessionId,
             IPCThreadState::self()->getCallingUid());
 
-    LOGV("Create new client(%d) from pid %d, fd=%d, offset=%lld, length=%lld, audioSessionId=%d",
-            connId, pid, fd, offset, length, audioSessionId);
+    LOGV("Create new client(%d) from pid %d, uid %d, fd=%d, offset=%lld, "
+         "length=%lld, audioSessionId=%d", connId, pid,
+         IPCThreadState::self()->getCallingUid(), fd, offset, length, audioSessionId);
     if (NO_ERROR != c->setDataSource(fd, offset, length)) {
         c.clear();
     } else {
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index 8382036..0ea880b 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -1157,6 +1157,8 @@
     mSurface.clear();
     if (surfaceTexture != NULL) {
         setNativeWindow_l(new SurfaceTextureClient(surfaceTexture));
+    } else {
+        setNativeWindow_l(NULL);
     }
 }
 
@@ -1769,7 +1771,8 @@
         }
     }
 
-    if (mVideoRendererIsPreview || mVideoRenderer == NULL) {
+    if ((mNativeWindow != NULL)
+            && (mVideoRendererIsPreview || mVideoRenderer == NULL)) {
         mVideoRendererIsPreview = false;
 
         initRenderer_l();
diff --git a/media/libstagefright/CameraSource.cpp b/media/libstagefright/CameraSource.cpp
index ea8eaa4..ac3565f 100755
--- a/media/libstagefright/CameraSource.cpp
+++ b/media/libstagefright/CameraSource.cpp
@@ -665,7 +665,7 @@
     LOGV("releaseRecordingFrame");
     if (mCameraRecordingProxy != NULL) {
         mCameraRecordingProxy->releaseRecordingFrame(frame);
-    } else {
+    } else if (mCamera != NULL) {
         int64_t token = IPCThreadState::self()->clearCallingIdentity();
         mCamera->releaseRecordingFrame(frame);
         IPCThreadState::self()->restoreCallingIdentity(token);
diff --git a/media/libstagefright/HTTPBase.cpp b/media/libstagefright/HTTPBase.cpp
index f9d8501..3c5a8a5 100644
--- a/media/libstagefright/HTTPBase.cpp
+++ b/media/libstagefright/HTTPBase.cpp
@@ -39,7 +39,8 @@
       mPrevBandwidthMeasureTimeUs(0),
       mPrevEstimatedBandWidthKbps(0),
       mBandWidthCollectFreqMs(5000),
-      mUIDValid(false) {
+      mUIDValid(false),
+      mUID(0) {
 }
 
 // static
@@ -135,9 +136,19 @@
 }
 
 // static
-void HTTPBase::RegisterSocketUser(int s, uid_t uid) {
-    static const uint32_t kTag = 0xdeadbeef;
-    set_qtaguid(s, kTag, uid);
+void HTTPBase::RegisterSocketUserTag(int sockfd, uid_t uid, uint32_t kTag) {
+    int res = qtaguid_tagSocket(sockfd, kTag, uid);
+    if (res != 0) {
+        LOGE("Failed tagging socket %d for uid %d (My UID=%d)", sockfd, uid, geteuid());
+    }
+}
+
+// static
+void HTTPBase::UnRegisterSocketUserTag(int sockfd) {
+    int res = qtaguid_untagSocket(sockfd);
+    if (res != 0) {
+        LOGE("Failed untagging socket %d (My UID=%d)", sockfd, geteuid());
+    }
 }
 
 }  // namespace android
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index 8c9ff87..5f58090 100755
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -1172,6 +1172,9 @@
 void MPEG4Writer::Track::addOneSttsTableEntry(
         size_t sampleCount, int32_t duration) {
 
+    if (duration == 0) {
+        LOGW("%d 0-duration samples found: %d", sampleCount);
+    }
     SttsTableEntry sttsEntry(sampleCount, duration);
     mSttsTableEntries.push_back(sttsEntry);
     ++mNumSttsTableEntries;
@@ -2001,17 +2004,18 @@
             mTrackDurationUs = timestampUs;
         }
 
+        // We need to use the time scale based ticks, rather than the
+        // timestamp itself to determine whether we have to use a new
+        // stts entry, since we may have rounding errors.
+        // The calculation is intended to reduce the accumulated
+        // rounding errors.
+        currDurationTicks =
+            ((timestampUs * mTimeScale + 500000LL) / 1000000LL -
+                (lastTimestampUs * mTimeScale + 500000LL) / 1000000LL);
+
         mSampleSizes.push_back(sampleSize);
         ++mNumSamples;
         if (mNumSamples > 2) {
-            // We need to use the time scale based ticks, rather than the
-            // timestamp itself to determine whether we have to use a new
-            // stts entry, since we may have rounding errors.
-            // The calculation is intended to reduce the accumulated
-            // rounding errors.
-            currDurationTicks =
-                     ((timestampUs * mTimeScale + 500000LL) / 1000000LL -
-                     (lastTimestampUs * mTimeScale + 500000LL) / 1000000LL);
 
             // Force the first sample to have its own stts entry so that
             // we can adjust its value later to maintain the A/V sync.
diff --git a/media/libstagefright/MediaBuffer.cpp b/media/libstagefright/MediaBuffer.cpp
index a8fadf2..0b14f1e 100644
--- a/media/libstagefright/MediaBuffer.cpp
+++ b/media/libstagefright/MediaBuffer.cpp
@@ -21,6 +21,7 @@
 #include <pthread.h>
 #include <stdlib.h>
 
+#include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/MediaBuffer.h>
 #include <media/stagefright/MediaDebug.h>
 #include <media/stagefright/MetaData.h>
@@ -70,6 +71,20 @@
       mOriginal(NULL) {
 }
 
+MediaBuffer::MediaBuffer(const sp<ABuffer> &buffer)
+    : mObserver(NULL),
+      mNextBuffer(NULL),
+      mRefCount(0),
+      mData(buffer->data()),
+      mSize(buffer->size()),
+      mRangeOffset(0),
+      mRangeLength(mSize),
+      mBuffer(buffer),
+      mOwnsData(false),
+      mMetaData(new MetaData),
+      mOriginal(NULL) {
+}
+
 void MediaBuffer::release() {
     if (mObserver == NULL) {
         CHECK_EQ(mRefCount, 0);
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index a4f3922..644c413 100755
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -442,9 +442,17 @@
     sp<OMXCodecObserver> observer = new OMXCodecObserver;
     IOMX::node_id node = 0;
 
-    const char *componentName;
     for (size_t i = 0; i < matchingCodecs.size(); ++i) {
-        componentName = matchingCodecs[i].string();
+        const char *componentNameBase = matchingCodecs[i].string();
+        const char *componentName = componentNameBase;
+
+        AString tmp;
+        if (flags & kUseSecureInputBuffers) {
+            tmp = componentNameBase;
+            tmp.append(".secure");
+
+            componentName = tmp.c_str();
+        }
 
         if (createEncoder) {
             sp<MediaSource> softwareCodec =
@@ -459,7 +467,7 @@
 
         LOGV("Attempting to allocate OMX node '%s'", componentName);
 
-        uint32_t quirks = getComponentQuirks(componentName, createEncoder);
+        uint32_t quirks = getComponentQuirks(componentNameBase, createEncoder);
 
         if (!createEncoder
                 && (quirks & kOutputBuffersAreUnreadable)
diff --git a/media/libstagefright/SurfaceMediaSource.cpp b/media/libstagefright/SurfaceMediaSource.cpp
index 3d8c56a..ddfd9ff 100644
--- a/media/libstagefright/SurfaceMediaSource.cpp
+++ b/media/libstagefright/SurfaceMediaSource.cpp
@@ -371,7 +371,8 @@
     return err;
 }
 
-status_t SurfaceMediaSource::connect(int api) {
+status_t SurfaceMediaSource::connect(int api,
+        uint32_t* outWidth, uint32_t* outHeight, uint32_t* outTransform) {
     LOGV("SurfaceMediaSource::connect");
     Mutex::Autolock lock(mMutex);
     status_t err = NO_ERROR;
@@ -384,6 +385,9 @@
                 err = -EINVAL;
             } else {
                 mConnectedApi = api;
+                *outWidth = mDefaultWidth;
+                *outHeight = mDefaultHeight;
+                *outTransform = 0;
             }
             break;
         default:
diff --git a/media/libstagefright/chromium_http/ChromiumHTTPDataSource.cpp b/media/libstagefright/chromium_http/ChromiumHTTPDataSource.cpp
index 07a9eb8..180460b 100644
--- a/media/libstagefright/chromium_http/ChromiumHTTPDataSource.cpp
+++ b/media/libstagefright/chromium_http/ChromiumHTTPDataSource.cpp
@@ -47,6 +47,8 @@
     delete mDelegate;
     mDelegate = NULL;
 
+    clearDRMState_l();
+
     if (mDrmManagerClient != NULL) {
         delete mDrmManagerClient;
         mDrmManagerClient = NULL;
@@ -59,6 +61,12 @@
         off64_t offset) {
     Mutex::Autolock autoLock(mLock);
 
+    uid_t uid;
+    if (getUID(&uid)) {
+        mDelegate->setUID(uid);
+    }
+    LOG_PRI(ANDROID_LOG_VERBOSE, LOG_TAG, "connect on behalf of uid %d", uid);
+
     return connect_l(uri, headers, offset);
 }
 
@@ -116,8 +124,6 @@
     // mURI.clear();
 
     mIOResult = err;
-
-    clearDRMState_l();
 }
 
 void ChromiumHTTPDataSource::disconnect() {
@@ -251,8 +257,6 @@
     // mURI.clear();
 
     mCondition.broadcast();
-
-    clearDRMState_l();
 }
 
 sp<DecryptHandle> ChromiumHTTPDataSource::DrmInitialization() {
diff --git a/media/libstagefright/chromium_http/support.cpp b/media/libstagefright/chromium_http/support.cpp
index 26c3eda..de936c4 100644
--- a/media/libstagefright/chromium_http/support.cpp
+++ b/media/libstagefright/chromium_http/support.cpp
@@ -23,6 +23,7 @@
 #include "support.h"
 
 #include "android/net/android_network_library_impl.h"
+#include "base/logging.h"
 #include "base/threading/thread.h"
 #include "net/base/cert_verifier.h"
 #include "net/base/cookie_monster.h"
@@ -34,8 +35,10 @@
 
 #include "include/ChromiumHTTPDataSource.h"
 
+#include <cutils/log.h>
 #include <cutils/properties.h>
 #include <media/stagefright/MediaErrors.h>
+#include <string>
 
 namespace android {
 
@@ -44,6 +47,34 @@
 static scoped_refptr<net::URLRequestContext> gReqContext;
 static scoped_ptr<net::NetworkChangeNotifier> gNetworkChangeNotifier;
 
+bool logMessageHandler(
+        int severity,
+        const char* file,
+        int line,
+        size_t message_start,
+        const std::string& str) {
+    int androidSeverity = ANDROID_LOG_VERBOSE;
+    switch(severity) {
+    case logging::LOG_FATAL:
+        androidSeverity = ANDROID_LOG_FATAL;
+        break;
+    case logging::LOG_ERROR_REPORT:
+    case logging::LOG_ERROR:
+        androidSeverity = ANDROID_LOG_ERROR;
+        break;
+    case logging::LOG_WARNING:
+        androidSeverity = ANDROID_LOG_WARN;
+        break;
+    default:
+        androidSeverity = ANDROID_LOG_VERBOSE;
+        break;
+    }
+    android_printLog(androidSeverity, "chromium-libstagefright",
+                    "%s:%d: %s", file, line, str.c_str());
+    return false;
+}
+
+
 static void InitializeNetworkThreadIfNecessary() {
     Mutex::Autolock autoLock(gNetworkThreadLock);
     if (gNetworkThread == NULL) {
@@ -58,6 +89,7 @@
 
         net::AndroidNetworkLibrary::RegisterSharedInstance(
                 new SfNetworkLibrary);
+        logging::SetLogMessageHandler(logMessageHandler);
     }
 }
 
@@ -181,6 +213,14 @@
     mOwner = owner;
 }
 
+void SfDelegate::setUID(uid_t uid) {
+    gReqContext->setUID(uid);
+}
+
+bool SfDelegate::getUID(uid_t *uid) const {
+    return gReqContext->getUID(uid);
+}
+
 void SfDelegate::OnReceivedRedirect(
             net::URLRequest *request, const GURL &new_url, bool *defer_redirect) {
     MY_LOGV("OnReceivedRedirect");
diff --git a/media/libstagefright/chromium_http/support.h b/media/libstagefright/chromium_http/support.h
index 8fe8db1..d2c5bc0 100644
--- a/media/libstagefright/chromium_http/support.h
+++ b/media/libstagefright/chromium_http/support.h
@@ -91,6 +91,11 @@
 
     void setOwner(ChromiumHTTPDataSource *mOwner);
 
+    // Gets the UID of the calling process
+    bool getUID(uid_t *uid) const;
+
+    void setUID(uid_t uid);
+
     virtual void OnReceivedRedirect(
             net::URLRequest *request, const GURL &new_url, bool *defer_redirect);
 
diff --git a/media/libstagefright/include/HTTPBase.h b/media/libstagefright/include/HTTPBase.h
index 0e9af69..b8e10f7 100644
--- a/media/libstagefright/include/HTTPBase.h
+++ b/media/libstagefright/include/HTTPBase.h
@@ -53,7 +53,8 @@
 
     static sp<HTTPBase> Create(uint32_t flags = 0);
 
-    static void RegisterSocketUser(int s, uid_t uid);
+    static void RegisterSocketUserTag(int sockfd, uid_t uid, uint32_t kTag);
+    static void UnRegisterSocketUserTag(int sockfd);
 
 protected:
     void addBandwidthMeasurement(size_t numBytes, int64_t delayUs);
diff --git a/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp b/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp
index 59de17e..2e66a2c 100644
--- a/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp
+++ b/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp
@@ -105,12 +105,10 @@
             int64_t timeUs;
             CHECK(buffer->meta()->findInt64("timeUs", &timeUs));
 
-            MediaBuffer *mediaBuffer = new MediaBuffer(buffer->size());
+            MediaBuffer *mediaBuffer = new MediaBuffer(buffer);
+
             mediaBuffer->meta_data()->setInt64(kKeyTime, timeUs);
 
-            // hexdump(buffer->data(), buffer->size());
-
-            memcpy(mediaBuffer->data(), buffer->data(), buffer->size());
             *out = mediaBuffer;
             return OK;
         }
diff --git a/media/libstagefright/rtsp/APacketSource.cpp b/media/libstagefright/rtsp/APacketSource.cpp
index a02591f..4ecb92f 100644
--- a/media/libstagefright/rtsp/APacketSource.cpp
+++ b/media/libstagefright/rtsp/APacketSource.cpp
@@ -628,14 +628,12 @@
 
         updateNormalPlayTime_l(buffer);
 
-        MediaBuffer *mediaBuffer = new MediaBuffer(buffer->size());
-
         int64_t timeUs;
         CHECK(buffer->meta()->findInt64("timeUs", &timeUs));
 
+        MediaBuffer *mediaBuffer = new MediaBuffer(buffer);
         mediaBuffer->meta_data()->setInt64(kKeyTime, timeUs);
 
-        memcpy(mediaBuffer->data(), buffer->data(), buffer->size());
         *out = mediaBuffer;
 
         mBuffers.erase(mBuffers.begin());
diff --git a/media/libstagefright/rtsp/ARTSPConnection.cpp b/media/libstagefright/rtsp/ARTSPConnection.cpp
index b398c9d..bd0e491 100644
--- a/media/libstagefright/rtsp/ARTSPConnection.cpp
+++ b/media/libstagefright/rtsp/ARTSPConnection.cpp
@@ -56,6 +56,9 @@
 ARTSPConnection::~ARTSPConnection() {
     if (mSocket >= 0) {
         LOGE("Connection is still open, closing the socket.");
+        if (mUIDValid) {
+            HTTPBase::UnRegisterSocketUserTag(mSocket);
+        }
         close(mSocket);
         mSocket = -1;
     }
@@ -202,6 +205,9 @@
     ++mConnectionID;
 
     if (mState != DISCONNECTED) {
+        if (mUIDValid) {
+            HTTPBase::UnRegisterSocketUserTag(mSocket);
+        }
         close(mSocket);
         mSocket = -1;
 
@@ -251,7 +257,8 @@
     mSocket = socket(AF_INET, SOCK_STREAM, 0);
 
     if (mUIDValid) {
-        HTTPBase::RegisterSocketUser(mSocket, mUID);
+        HTTPBase::RegisterSocketUserTag(mSocket, mUID,
+                                        (uint32_t)*(uint32_t*) "RTSP");
     }
 
     MakeSocketBlocking(mSocket, false);
@@ -279,6 +286,9 @@
         reply->setInt32("result", -errno);
         mState = DISCONNECTED;
 
+        if (mUIDValid) {
+            HTTPBase::UnRegisterSocketUserTag(mSocket);
+        }
         close(mSocket);
         mSocket = -1;
     } else {
@@ -294,6 +304,9 @@
 
 void ARTSPConnection::onDisconnect(const sp<AMessage> &msg) {
     if (mState == CONNECTED || mState == CONNECTING) {
+        if (mUIDValid) {
+            HTTPBase::UnRegisterSocketUserTag(mSocket);
+        }
         close(mSocket);
         mSocket = -1;
 
@@ -358,6 +371,9 @@
         reply->setInt32("result", -err);
 
         mState = DISCONNECTED;
+        if (mUIDValid) {
+            HTTPBase::UnRegisterSocketUserTag(mSocket);
+        }
         close(mSocket);
         mSocket = -1;
     } else {
diff --git a/media/libstagefright/rtsp/MyHandler.h b/media/libstagefright/rtsp/MyHandler.h
index 71d68f6..8128813 100644
--- a/media/libstagefright/rtsp/MyHandler.h
+++ b/media/libstagefright/rtsp/MyHandler.h
@@ -545,6 +545,12 @@
                 if (result != OK) {
                     if (track) {
                         if (!track->mUsingInterleavedTCP) {
+                            // Clear the tag
+                            if (mUIDValid) {
+                                HTTPBase::UnRegisterSocketUserTag(track->mRTPSocket);
+                                HTTPBase::UnRegisterSocketUserTag(track->mRTCPSocket);
+                            }
+
                             close(track->mRTPSocket);
                             close(track->mRTCPSocket);
                         }
@@ -618,6 +624,12 @@
                     if (!info->mUsingInterleavedTCP) {
                         mRTPConn->removeStream(info->mRTPSocket, info->mRTCPSocket);
 
+                        // Clear the tag
+                        if (mUIDValid) {
+                            HTTPBase::UnRegisterSocketUserTag(info->mRTPSocket);
+                            HTTPBase::UnRegisterSocketUserTag(info->mRTCPSocket);
+                        }
+
                         close(info->mRTPSocket);
                         close(info->mRTCPSocket);
                     }
@@ -1181,8 +1193,10 @@
                     &info->mRTPSocket, &info->mRTCPSocket, &rtpPort);
 
             if (mUIDValid) {
-                HTTPBase::RegisterSocketUser(info->mRTPSocket, mUID);
-                HTTPBase::RegisterSocketUser(info->mRTCPSocket, mUID);
+                HTTPBase::RegisterSocketUserTag(info->mRTPSocket, mUID,
+                                                (uint32_t)*(uint32_t*) "RTP_");
+                HTTPBase::RegisterSocketUserTag(info->mRTCPSocket, mUID,
+                                                (uint32_t)*(uint32_t*) "RTP_");
             }
 
             request.append("Transport: RTP/AVP/UDP;unicast;client_port=");
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 2355d5c..d6bfda6 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -264,6 +264,14 @@
             }
         }
     }
+
+    result.append("Global session refs:\n");
+    result.append(" session pid cnt\n");
+    for (size_t i = 0; i < mAudioSessionRefs.size(); i++) {
+        AudioSessionRef *r = mAudioSessionRefs[i];
+        snprintf(buffer, SIZE, " %7d %3d %3d\n", r->sessionid, r->pid, r->cnt);
+        result.append(buffer);
+    }
     write(fd, result.string(), result.size());
     return NO_ERROR;
 }
@@ -892,6 +900,25 @@
         LOGV("removeNotificationClient() %p, pid %d", client.get(), pid);
         mNotificationClients.removeItem(pid);
     }
+
+    LOGV("%d died, releasing its sessions", pid);
+    int num = mAudioSessionRefs.size();
+    bool removed = false;
+    for (int i = 0; i< num; i++) {
+        AudioSessionRef *ref = mAudioSessionRefs.itemAt(i);
+        LOGV(" pid %d @ %d", ref->pid, i);
+        if (ref->pid == pid) {
+            LOGV(" removing entry for pid %d session %d", pid, ref->sessionid);
+            mAudioSessionRefs.removeAt(i);
+            delete ref;
+            removed = true;
+            i--;
+            num--;
+        }
+    }
+    if (removed) {
+        purgeStaleEffects_l();
+    }
 }
 
 // audioConfigChanged_l() must be called with AudioFlinger::mLock held
@@ -1392,12 +1419,13 @@
 // Thread virtuals
 status_t AudioFlinger::PlaybackThread::readyToRun()
 {
-    if (mSampleRate == 0) {
+    status_t status = initCheck();
+    if (status == NO_ERROR) {
+        LOGI("AudioFlinger's thread %p ready to run", this);
+    } else {
         LOGE("No working audio driver found.");
-        return NO_INIT;
     }
-    LOGI("AudioFlinger's thread %p ready to run", this);
-    return NO_ERROR;
+    return status;
 }
 
 void AudioFlinger::PlaybackThread::onFirstRef()
@@ -1491,10 +1519,10 @@
 
 uint32_t AudioFlinger::PlaybackThread::latency() const
 {
-    if (mOutput) {
+    Mutex::Autolock _l(mLock);
+    if (initCheck() == NO_ERROR) {
         return mOutput->stream->get_latency(mOutput->stream);
-    }
-    else {
+    } else {
         return 0;
     }
 }
@@ -1595,16 +1623,21 @@
 
 String8 AudioFlinger::PlaybackThread::getParameters(const String8& keys)
 {
-    String8 out_s8;
+    String8 out_s8 = String8("");
     char *s;
 
+    Mutex::Autolock _l(mLock);
+    if (initCheck() != NO_ERROR) {
+        return out_s8;
+    }
+
     s = mOutput->stream->common.get_parameters(&mOutput->stream->common, keys.string());
     out_s8 = String8(s);
     free(s);
     return out_s8;
 }
 
-// destroyTrack_l() must be called with AudioFlinger::mLock held
+// audioConfigChanged_l() must be called with AudioFlinger::mLock held
 void AudioFlinger::PlaybackThread::audioConfigChanged_l(int event, int param) {
     AudioSystem::OutputDescriptor desc;
     void *param2 = 0;
@@ -1663,6 +1696,7 @@
     if (halFrames == 0 || dspFrames == 0) {
         return BAD_VALUE;
     }
+    Mutex::Autolock _l(mLock);
     if (initCheck() != NO_ERROR) {
         return INVALID_OPERATION;
     }
@@ -1709,6 +1743,29 @@
 }
 
 
+AudioFlinger::AudioStreamOut* AudioFlinger::PlaybackThread::getOutput()
+{
+    Mutex::Autolock _l(mLock);
+    return mOutput;
+}
+
+AudioFlinger::AudioStreamOut* AudioFlinger::PlaybackThread::clearOutput()
+{
+    Mutex::Autolock _l(mLock);
+    AudioStreamOut *output = mOutput;
+    mOutput = NULL;
+    return output;
+}
+
+// this method must always be called either with ThreadBase mLock held or inside the thread loop
+audio_stream_t* AudioFlinger::PlaybackThread::stream()
+{
+    if (mOutput == NULL) {
+        return NULL;
+    }
+    return &mOutput->stream->common;
+}
+
 // ----------------------------------------------------------------------------
 
 AudioFlinger::MixerThread::MixerThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int id, uint32_t device)
@@ -4083,6 +4140,13 @@
     run(mName, PRIORITY_URGENT_AUDIO);
 }
 
+status_t AudioFlinger::RecordThread::readyToRun()
+{
+    status_t status = initCheck();
+    LOGW_IF(status != NO_ERROR,"RecordThread %p could not initialize", this);
+    return status;
+}
+
 bool AudioFlinger::RecordThread::threadLoop()
 {
     AudioBufferProvider::Buffer buffer;
@@ -4573,7 +4637,12 @@
 String8 AudioFlinger::RecordThread::getParameters(const String8& keys)
 {
     char *s;
-    String8 out_s8;
+    String8 out_s8 = String8();
+
+    Mutex::Autolock _l(mLock);
+    if (initCheck() != NO_ERROR) {
+        return out_s8;
+    }
 
     s = mInput->stream->common.get_parameters(&mInput->stream->common, keys.string());
     out_s8 = String8(s);
@@ -4645,6 +4714,11 @@
 
 unsigned int AudioFlinger::RecordThread::getInputFramesLost()
 {
+    Mutex::Autolock _l(mLock);
+    if (initCheck() != NO_ERROR) {
+        return 0;
+    }
+
     return mInput->stream->get_input_frames_lost(mInput->stream);
 }
 
@@ -4669,6 +4743,30 @@
     return mTrack;
 }
 
+AudioFlinger::AudioStreamIn* AudioFlinger::RecordThread::getInput()
+{
+    Mutex::Autolock _l(mLock);
+    return mInput;
+}
+
+AudioFlinger::AudioStreamIn* AudioFlinger::RecordThread::clearInput()
+{
+    Mutex::Autolock _l(mLock);
+    AudioStreamIn *input = mInput;
+    mInput = NULL;
+    return input;
+}
+
+// this method must always be called either with ThreadBase mLock held or inside the thread loop
+audio_stream_t* AudioFlinger::RecordThread::stream()
+{
+    if (mInput == NULL) {
+        return NULL;
+    }
+    return &mInput->stream->common;
+}
+
+
 // ----------------------------------------------------------------------------
 
 int AudioFlinger::openOutput(uint32_t *pDevices,
@@ -4792,7 +4890,8 @@
     thread->exit();
 
     if (thread->type() != ThreadBase::DUPLICATING) {
-        AudioStreamOut *out = thread->getOutput();
+        AudioStreamOut *out = thread->clearOutput();
+        // from now on thread->mOutput is NULL
         out->hwDev->close_output_stream(out->hwDev, out->stream);
         delete out;
     }
@@ -4932,7 +5031,8 @@
     }
     thread->exit();
 
-    AudioStreamIn *in = thread->getInput();
+    AudioStreamIn *in = thread->clearInput();
+    // from now on thread->mInput is NULL
     in->hwDev->close_input_stream(in->hwDev, in->stream);
     delete in;
 
@@ -4969,6 +5069,109 @@
     return nextUniqueId();
 }
 
+void AudioFlinger::acquireAudioSessionId(int audioSession)
+{
+    Mutex::Autolock _l(mLock);
+    int caller = IPCThreadState::self()->getCallingPid();
+    LOGV("acquiring %d from %d", audioSession, caller);
+    int num = mAudioSessionRefs.size();
+    for (int i = 0; i< num; i++) {
+        AudioSessionRef *ref = mAudioSessionRefs.editItemAt(i);
+        if (ref->sessionid == audioSession && ref->pid == caller) {
+            ref->cnt++;
+            LOGV(" incremented refcount to %d", ref->cnt);
+            return;
+        }
+    }
+    AudioSessionRef *ref = new AudioSessionRef();
+    ref->sessionid = audioSession;
+    ref->pid = caller;
+    ref->cnt = 1;
+    mAudioSessionRefs.push(ref);
+    LOGV(" added new entry for %d", ref->sessionid);
+}
+
+void AudioFlinger::releaseAudioSessionId(int audioSession)
+{
+    Mutex::Autolock _l(mLock);
+    int caller = IPCThreadState::self()->getCallingPid();
+    LOGV("releasing %d from %d", audioSession, caller);
+    int num = mAudioSessionRefs.size();
+    for (int i = 0; i< num; i++) {
+        AudioSessionRef *ref = mAudioSessionRefs.itemAt(i);
+        if (ref->sessionid == audioSession && ref->pid == caller) {
+            ref->cnt--;
+            LOGV(" decremented refcount to %d", ref->cnt);
+            if (ref->cnt == 0) {
+                mAudioSessionRefs.removeAt(i);
+                delete ref;
+                purgeStaleEffects_l();
+            }
+            return;
+        }
+    }
+    LOGW("session id %d not found for pid %d", audioSession, caller);
+}
+
+void AudioFlinger::purgeStaleEffects_l() {
+
+    LOGV("purging stale effects");
+
+    Vector< sp<EffectChain> > chains;
+
+    for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
+        sp<PlaybackThread> t = mPlaybackThreads.valueAt(i);
+        for (size_t j = 0; j < t->mEffectChains.size(); j++) {
+            sp<EffectChain> ec = t->mEffectChains[j];
+            chains.push(ec);
+        }
+    }
+    for (size_t i = 0; i < mRecordThreads.size(); i++) {
+        sp<RecordThread> t = mRecordThreads.valueAt(i);
+        for (size_t j = 0; j < t->mEffectChains.size(); j++) {
+            sp<EffectChain> ec = t->mEffectChains[j];
+            chains.push(ec);
+        }
+    }
+
+    for (size_t i = 0; i < chains.size(); i++) {
+        sp<EffectChain> ec = chains[i];
+        int sessionid = ec->sessionId();
+        sp<ThreadBase> t = ec->mThread.promote();
+        if (t == 0) {
+            continue;
+        }
+        size_t numsessionrefs = mAudioSessionRefs.size();
+        bool found = false;
+        for (size_t k = 0; k < numsessionrefs; k++) {
+            AudioSessionRef *ref = mAudioSessionRefs.itemAt(k);
+            if (ref->sessionid == sessionid) {
+                LOGV(" session %d still exists for %d with %d refs",
+                     sessionid, ref->pid, ref->cnt);
+                found = true;
+                break;
+            }
+        }
+        if (!found) {
+            // remove all effects from the chain
+            while (ec->mEffects.size()) {
+                sp<EffectModule> effect = ec->mEffects[0];
+                effect->unPin();
+                Mutex::Autolock _l (t->mLock);
+                t->removeEffect_l(effect);
+                for (size_t j = 0; j < effect->mHandles.size(); j++) {
+                    sp<EffectHandle> handle = effect->mHandles[j].promote();
+                    if (handle != 0) {
+                        handle->mEffect.clear();
+                    }
+                }
+                AudioSystem::unregisterEffect(effect->id());
+            }
+        }
+    }
+    return;
+}
+
 // checkPlaybackThread_l() must be called with AudioFlinger::mLock held
 AudioFlinger::PlaybackThread *AudioFlinger::checkPlaybackThread_l(int output) const
 {
@@ -5010,7 +5213,8 @@
 {
     for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
         PlaybackThread *thread = mPlaybackThreads.valueAt(i).get();
-        if (thread->getOutput()->hwDev == mPrimaryHardwareDev) {
+        AudioStreamOut *output = thread->getOutput();
+        if (output != NULL && output->hwDev == mPrimaryHardwareDev) {
             return thread;
         }
     }
@@ -5125,6 +5329,7 @@
             }
             uint32_t numEffects = 0;
             effect_descriptor_t d;
+            d.flags = 0; // prevent compiler warning
             bool found = false;
 
             lStatus = EffectQueryNumberEffects(&numEffects);
@@ -5228,7 +5433,7 @@
             mClients.add(pid, client);
         }
 
-        // create effect on selected output trhead
+        // create effect on selected output thread
         handle = thread->createEffect_l(client, effectClient, priority, sessionId,
                 &desc, enabled, &lStatus);
         if (handle != 0 && id != NULL) {
@@ -5270,7 +5475,7 @@
     return NO_ERROR;
 }
 
-// moveEffectChain_l mustbe called with both srcThread and dstThread mLocks held
+// moveEffectChain_l must be called with both srcThread and dstThread mLocks held
 status_t AudioFlinger::moveEffectChain_l(int sessionId,
                                    AudioFlinger::PlaybackThread *srcThread,
                                    AudioFlinger::PlaybackThread *dstThread,
@@ -5296,7 +5501,7 @@
     // correct buffer sizes and audio parameters and effect engines reconfigured accordingly
     int dstOutput = dstThread->id();
     sp<EffectChain> dstChain;
-    uint32_t strategy;
+    uint32_t strategy = 0; // prevent compiler warning
     sp<EffectModule> effect = chain->getEffectFromId_l(0);
     while (effect != 0) {
         srcThread->removeEffect_l(effect);
@@ -5558,14 +5763,17 @@
 }
 
 void AudioFlinger::ThreadBase::disconnectEffect(const sp<EffectModule>& effect,
-                                                    const wp<EffectHandle>& handle) {
+                                                    const wp<EffectHandle>& handle,
+                                                    bool unpiniflast) {
 
     Mutex::Autolock _l(mLock);
     LOGV("disconnectEffect() %p effect %p", this, effect.get());
     // delete the effect module if removing last handle on it
     if (effect->removeHandle(handle) == 0) {
-        removeEffect_l(effect);
-        AudioSystem::unregisterEffect(effect->id());
+        if (!effect->isPinned() || unpiniflast) {
+            removeEffect_l(effect);
+            AudioSystem::unregisterEffect(effect->id());
+        }
     }
 }
 
@@ -5773,6 +5981,9 @@
         goto Error;
     }
 
+    if (mSessionId > AUDIO_SESSION_OUTPUT_MIX) {
+        mPinned = true;
+    }
     LOGV("Constructor success name %s, Interface %p", mDescriptor.name, mEffectInterface);
     return;
 Error:
@@ -5789,7 +6000,10 @@
                 (mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_POST_PROC) {
             sp<ThreadBase> thread = mThread.promote();
             if (thread != 0) {
-                thread->stream()->remove_audio_effect(thread->stream(), mEffectInterface);
+                audio_stream_t *stream = thread->stream();
+                if (stream != NULL) {
+                    stream->remove_audio_effect(stream, mEffectInterface);
+                }
             }
         }
         // release effect engine
@@ -5861,7 +6075,7 @@
     // Prevent calls to process() and other functions on effect interface from now on.
     // The effect engine will be released by the destructor when the last strong reference on
     // this object is released which can happen after next process is called.
-    if (size == 0) {
+    if (size == 0 && !mPinned) {
         mState = DESTROYED;
     }
 
@@ -5878,9 +6092,7 @@
     return handle;
 }
 
-
-
-void AudioFlinger::EffectModule::disconnect(const wp<EffectHandle>& handle)
+void AudioFlinger::EffectModule::disconnect(const wp<EffectHandle>& handle, bool unpiniflast)
 {
     LOGV("disconnect() %p handle %p ", this, handle.unsafe_get());
     // keep a strong reference on this EffectModule to avoid calling the
@@ -5889,7 +6101,7 @@
     {
         sp<ThreadBase> thread = mThread.promote();
         if (thread != 0) {
-            thread->disconnectEffect(keep, handle);
+            thread->disconnectEffect(keep, handle, unpiniflast);
         }
     }
 }
@@ -6104,7 +6316,10 @@
              (mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_POST_PROC)) {
         sp<ThreadBase> thread = mThread.promote();
         if (thread != 0) {
-            thread->stream()->add_audio_effect(thread->stream(), mEffectInterface);
+            audio_stream_t *stream = thread->stream();
+            if (stream != NULL) {
+                stream->add_audio_effect(stream, mEffectInterface);
+            }
         }
     }
     return status;
@@ -6137,7 +6352,10 @@
              (mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_POST_PROC)) {
         sp<ThreadBase> thread = mThread.promote();
         if (thread != 0) {
-            thread->stream()->remove_audio_effect(thread->stream(), mEffectInterface);
+            audio_stream_t *stream = thread->stream();
+            if (stream != NULL) {
+                stream->remove_audio_effect(stream, mEffectInterface);
+            }
         }
     }
     return status;
@@ -6450,11 +6668,14 @@
                                         const sp<IEffectClient>& effectClient,
                                         int32_t priority)
     : BnEffect(),
-    mEffect(effect), mEffectClient(effectClient), mClient(client),
+    mEffect(effect), mEffectClient(effectClient), mClient(client), mCblk(NULL),
     mPriority(priority), mHasControl(false), mEnabled(false)
 {
     LOGV("constructor %p", this);
 
+    if (client == 0) {
+        return;
+    }
     int bufOffset = ((sizeof(effect_param_cblk_t) - 1) / sizeof(int) + 1) * sizeof(int);
     mCblkMemory = client->heap()->allocate(EFFECT_PARAM_BUFFER_SIZE + bufOffset);
     if (mCblkMemory != 0) {
@@ -6473,7 +6694,7 @@
 AudioFlinger::EffectHandle::~EffectHandle()
 {
     LOGV("Destructor %p", this);
-    disconnect();
+    disconnect(false);
     LOGV("Destructor DONE %p", this);
 }
 
@@ -6522,12 +6743,16 @@
 
 void AudioFlinger::EffectHandle::disconnect()
 {
-    LOGV("disconnect %p", this);
+    disconnect(true);
+}
+
+void AudioFlinger::EffectHandle::disconnect(bool unpiniflast)
+{
+    LOGV("disconnect(%s)", unpiniflast ? "true" : "false");
     if (mEffect == 0) {
         return;
     }
-
-    mEffect->disconnect(this);
+    mEffect->disconnect(this, unpiniflast);
 
     sp<ThreadBase> thread = mEffect->thread().promote();
     if (thread != 0) {
@@ -6536,11 +6761,11 @@
 
     // release sp on module => module destructor can be called now
     mEffect.clear();
-    if (mCblk) {
-        mCblk->~effect_param_cblk_t();   // destroy our shared-structure.
-    }
-    mCblkMemory.clear();            // and free the shared memory
     if (mClient != 0) {
+        if (mCblk) {
+            mCblk->~effect_param_cblk_t();   // destroy our shared-structure.
+        }
+        mCblkMemory.clear();            // and free the shared memory
         Mutex::Autolock _l(mClient->audioFlinger()->mLock);
         mClient.clear();
     }
@@ -6560,6 +6785,7 @@
         return INVALID_OPERATION;
     }
     if (mEffect == 0) return DEAD_OBJECT;
+    if (mClient == 0) return INVALID_OPERATION;
 
     // handle commands that are not forwarded transparently to effect engine
     if (cmdCode == EFFECT_CMD_SET_PARAM_COMMIT) {
@@ -6666,15 +6892,15 @@
 
 void AudioFlinger::EffectHandle::dump(char* buffer, size_t size)
 {
-    bool locked = tryLock(mCblk->lock);
+    bool locked = mCblk ? tryLock(mCblk->lock) : false;
 
     snprintf(buffer, size, "\t\t\t%05d %05d    %01u    %01u      %05u  %05u\n",
             (mClient == NULL) ? getpid() : mClient->pid(),
             mPriority,
             mHasControl,
             !locked,
-            mCblk->clientIndex,
-            mCblk->serverIndex
+            mCblk ? mCblk->clientIndex : 0,
+            mCblk ? mCblk->serverIndex : 0
             );
 
     if (locked) {
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 791341a..3a0aac9 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -149,6 +149,10 @@
 
     virtual int newAudioSessionId();
 
+    virtual void acquireAudioSessionId(int audioSession);
+
+    virtual void releaseAudioSessionId(int audioSession);
+
     virtual status_t queryNumberEffects(uint32_t *numEffects);
 
     virtual status_t queryEffect(uint32_t index, effect_descriptor_t *descriptor);
@@ -215,6 +219,7 @@
     status_t                initCheck() const;
     virtual     void        onFirstRef();
     audio_hw_device_t*      findSuitableHwDev_l(uint32_t devices);
+    void                    purgeStaleEffects_l();
 
     // Internal dump utilites.
     status_t dumpPermissionDenial(int fd, const Vector<String16>& args);
@@ -436,7 +441,8 @@
                                         int *enabled,
                                         status_t *status);
                     void disconnectEffect(const sp< EffectModule>& effect,
-                                          const wp<EffectHandle>& handle);
+                                          const wp<EffectHandle>& handle,
+                                          bool unpiniflast);
 
                     // return values for hasAudioSession (bit field)
                     enum effect_state {
@@ -519,6 +525,7 @@
                     // updated mSuspendedSessions when an effect chain is removed
                     void updateSuspendedSessionsOnRemoveEffectChain_l(const sp<EffectChain>& chain);
 
+        friend class AudioFlinger;
         friend class Track;
         friend class TrackBase;
         friend class PlaybackThread;
@@ -607,7 +614,6 @@
 
         protected:
             friend class ThreadBase;
-            friend class AudioFlinger;
             friend class TrackHandle;
             friend class PlaybackThread;
             friend class MixerThread;
@@ -724,8 +730,9 @@
                                     int sessionId,
                                     status_t *status);
 
-                    AudioStreamOut* getOutput() { return mOutput; }
-                    virtual audio_stream_t* stream() { return &mOutput->stream->common; }
+                    AudioStreamOut* getOutput();
+                    AudioStreamOut* clearOutput();
+                    virtual audio_stream_t* stream();
 
                     void        suspend() { mSuspended++; }
                     void        restore() { if (mSuspended) mSuspended--; }
@@ -967,7 +974,7 @@
                 ~RecordThread();
 
         virtual bool        threadLoop();
-        virtual status_t    readyToRun() { return NO_ERROR; }
+        virtual status_t    readyToRun();
         virtual void        onFirstRef();
 
         virtual status_t    initCheck() const { return (mInput == 0) ? NO_INIT : NO_ERROR; }
@@ -984,8 +991,9 @@
                 status_t    start(RecordTrack* recordTrack);
                 void        stop(RecordTrack* recordTrack);
                 status_t    dump(int fd, const Vector<String16>& args);
-                AudioStreamIn* getInput() { return mInput; }
-                virtual audio_stream_t* stream() { return &mInput->stream->common; }
+                AudioStreamIn* getInput();
+                AudioStreamIn* clearInput();
+                virtual audio_stream_t* stream();
 
         virtual status_t    getNextBuffer(AudioBufferProvider::Buffer* buffer);
         virtual void        releaseBuffer(AudioBufferProvider::Buffer* buffer);
@@ -1098,7 +1106,7 @@
         wp<ThreadBase>& thread() { return mThread; }
 
         status_t addHandle(sp<EffectHandle>& handle);
-        void disconnect(const wp<EffectHandle>& handle);
+        void disconnect(const wp<EffectHandle>& handle, bool unpiniflast);
         size_t removeHandle (const wp<EffectHandle>& handle);
 
         effect_descriptor_t& desc() { return mDescriptor; }
@@ -1113,9 +1121,15 @@
 
         sp<EffectHandle> controlHandle();
 
+        bool             isPinned() { return mPinned; }
+        void             unPin() { mPinned = false; }
+
         status_t         dump(int fd, const Vector<String16>& args);
 
     protected:
+        friend class EffectHandle;
+        friend class AudioFlinger;
+        bool                mPinned;
 
         // Maximum time allocated to effect engines to complete the turn off sequence
         static const uint32_t MAX_DISABLE_TIME_MS = 10000;
@@ -1167,6 +1181,7 @@
                                  uint32_t *replySize,
                                  void *pReplyData);
         virtual void disconnect();
+        virtual void disconnect(bool unpiniflast);
         virtual sp<IMemory> getCblk() const;
         virtual status_t onTransact(uint32_t code, const Parcel& data,
                 Parcel* reply, uint32_t flags);
@@ -1194,7 +1209,8 @@
         void dump(char* buffer, size_t size);
 
     protected:
-
+        friend class AudioFlinger;
+        friend class EffectModule;
         EffectHandle(const EffectHandle&);
         EffectHandle& operator =(const EffectHandle&);
 
@@ -1286,7 +1302,7 @@
         status_t dump(int fd, const Vector<String16>& args);
 
     protected:
-
+        friend class AudioFlinger;
         EffectChain(const EffectChain&);
         EffectChain& operator =(const EffectChain&);
 
@@ -1342,6 +1358,12 @@
             hwDev(dev), stream(in) {}
     };
 
+    struct AudioSessionRef {
+        int sessionid;
+        pid_t pid;
+        int cnt;
+    };
+
     friend class RecordThread;
     friend class PlaybackThread;
 
@@ -1367,6 +1389,7 @@
                 uint32_t                            mMode;
                 bool                                mBtNrec;
 
+                Vector<AudioSessionRef*> mAudioSessionRefs;
 };