Merge "even more logging"
diff --git a/core/jni/android/graphics/Canvas.cpp b/core/jni/android/graphics/Canvas.cpp
index 2dceab9..9d9196e 100644
--- a/core/jni/android/graphics/Canvas.cpp
+++ b/core/jni/android/graphics/Canvas.cpp
@@ -764,13 +764,6 @@
         env->ReleaseStringChars(text, textArray);
     }
 
-    static void logGlyphs(sp<TextLayoutCacheValue> value) {
-        LOGD("drawTextWithGlyphs -- got glyphs - count=%d", value->getGlyphsCount());
-        for (size_t i = 0; i < value->getGlyphsCount(); i++) {
-            LOGD("                          glyphs[%d]=%d", i, value->getGlyphs()[i]);
-        }
-    }
-
     static void drawTextWithGlyphs(SkCanvas* canvas, const jchar* textArray,
             int start, int end,
             jfloat x, jfloat y, int flags, SkPaint* paint) {
@@ -779,7 +772,7 @@
         sp<TextLayoutCacheValue> value = gTextLayoutCache.getValue(
                 paint, textArray, start, count, count, flags);
         if (value == NULL) {
-            LOGE("drawTextWithGlyphs -- cannot get Cache value");
+            LOGE("Cannot get TextLayoutCache value");
             return ;
         }
 #if DEBUG_GLYPHS
@@ -796,7 +789,7 @@
         sp<TextLayoutCacheValue> value = gTextLayoutCache.getValue(
                 paint, textArray, start, count, contextCount, flags);
         if (value == NULL) {
-            LOGE("drawTextWithGlyphs -- cannot get Cache value");
+            LOGE("Cannot get TextLayoutCache value");
             return ;
         }
 #if DEBUG_GLYPHS
diff --git a/core/jni/android/graphics/TextLayout.h b/core/jni/android/graphics/TextLayout.h
index 9bb1b92..d197d04 100644
--- a/core/jni/android/graphics/TextLayout.h
+++ b/core/jni/android/graphics/TextLayout.h
@@ -64,6 +64,14 @@
     kDirection_Mask = 0x1
 };
 
+static void logGlyphs(sp<TextLayoutCacheValue> value) {
+    if (value == NULL) return;
+    LOGD("Got glyphs - count=%d", value->getGlyphsCount());
+    for (size_t i = 0; i < value->getGlyphsCount(); i++) {
+        LOGD("      glyphs[%d]=%d", i, value->getGlyphs()[i]);
+    }
+}
+
 class TextLayout {
 public:
 
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index d43a27f..e539cd2 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -419,6 +419,20 @@
 
 static void renderText(OpenGLRenderer* renderer, const jchar* text, int count,
         jfloat x, jfloat y, int flags, SkPaint* paint) {
+#if 0 // TODO: replace "0" by "RTL_USE_HARFBUZZ" when renderer->drawGlyphs() is implemented
+    sp<TextLayoutCacheValue> value = gTextLayoutCache.getValue(
+            paint, text, 0, count, count, flags);
+    if (value == NULL) {
+        LOGE("Cannot get TextLayoutCache value");
+        return ;
+    }
+#if DEBUG_GLYPHS
+    logGlyphs(value);
+#endif
+    const jchar* glyphArray = value->getGlyphs();
+    int glyphCount = value->getGlyphsCount();
+    renderer->drawGlyphs((const char*) glyphArray, 0, glyphCount << 1, x, y, paint);
+#else
     const jchar *workText;
     jchar* buffer = NULL;
     int32_t workBytes;
@@ -426,11 +440,26 @@
         renderer->drawText((const char*) workText, workBytes, count, x, y, paint);
         free(buffer);
     }
+#endif
 }
 
 static void renderTextRun(OpenGLRenderer* renderer, const jchar* text,
         jint start, jint count, jint contextCount, jfloat x, jfloat y,
         int flags, SkPaint* paint) {
+#if 0 // TODO: replace "0" by "RTL_USE_HARFBUZZ" when renderer->drawGlyphs() is implemented
+    sp<TextLayoutCacheValue> value = gTextLayoutCache.getValue(
+            paint, text, start, count, contextCount, flags);
+    if (value == NULL) {
+        LOGE("Cannot get TextLayoutCache value");
+        return ;
+    }
+#if DEBUG_GLYPHS
+    logGlyphs(value);
+#endif
+    const jchar* glyphArray = value->getGlyphs();
+    int glyphCount = value->getGlyphsCount();
+    renderer->drawGlyphs((const char*) glyphArray, 0, glyphCount << 1, x, y, paint);
+#else
     uint8_t rtl = flags & 0x1;
     if (rtl) {
         SkAutoSTMalloc<80, jchar> buffer(contextCount);
@@ -443,6 +472,7 @@
     } else {
         renderer->drawText((const char*) (text + start), count << 1, count, x, y, paint);
     }
+#endif
 }
 
 static void android_view_GLES20Canvas_drawTextArray(JNIEnv* env, jobject clazz,
diff --git a/graphics/java/android/renderscript/Mesh.java b/graphics/java/android/renderscript/Mesh.java
index 2774809..7b3b73f 100644
--- a/graphics/java/android/renderscript/Mesh.java
+++ b/graphics/java/android/renderscript/Mesh.java
@@ -320,53 +320,55 @@
             return tb.create();
         }
 
-        static synchronized Mesh internalCreate(RenderScript rs, Builder b) {
-
-            int id = rs.nMeshCreate(b.mVertexTypeCount, b.mIndexTypes.size());
-            Mesh newMesh = new Mesh(id, rs);
-            newMesh.mIndexBuffers = new Allocation[b.mIndexTypes.size()];
-            newMesh.mPrimitives = new Primitive[b.mIndexTypes.size()];
-            newMesh.mVertexBuffers = new Allocation[b.mVertexTypeCount];
-
-            for(int ct = 0; ct < b.mIndexTypes.size(); ct ++) {
-                Allocation alloc = null;
-                Entry entry = (Entry)b.mIndexTypes.elementAt(ct);
-                if (entry.t != null) {
-                    alloc = Allocation.createTyped(rs, entry.t, b.mUsage);
-                }
-                else if(entry.e != null) {
-                    alloc = Allocation.createSized(rs, entry.e, entry.size, b.mUsage);
-                }
-                int allocID = (alloc == null) ? 0 : alloc.getID();
-                rs.nMeshBindIndex(id, allocID, entry.prim.mID, ct);
-                newMesh.mIndexBuffers[ct] = alloc;
-                newMesh.mPrimitives[ct] = entry.prim;
-            }
-
-            for(int ct = 0; ct < b.mVertexTypeCount; ct ++) {
-                Allocation alloc = null;
-                Entry entry = b.mVertexTypes[ct];
-                if (entry.t != null) {
-                    alloc = Allocation.createTyped(rs, entry.t, b.mUsage);
-                } else if(entry.e != null) {
-                    alloc = Allocation.createSized(rs, entry.e, entry.size, b.mUsage);
-                }
-                rs.nMeshBindVertex(id, alloc.getID(), ct);
-                newMesh.mVertexBuffers[ct] = alloc;
-            }
-            rs.nMeshInitVertexAttribs(id);
-
-            return newMesh;
-        }
-
         /**
         * Create a Mesh object from the current state of the builder
         *
         **/
         public Mesh create() {
             mRS.validate();
-            Mesh sm = internalCreate(mRS, this);
-            return sm;
+            int[] vtx = new int[mVertexTypeCount];
+            int[] idx = new int[mIndexTypes.size()];
+            int[] prim = new int[mIndexTypes.size()];
+
+            Allocation[] vertexBuffers = new Allocation[mVertexTypeCount];
+            Allocation[] indexBuffers = new Allocation[mIndexTypes.size()];
+            Primitive[] primitives = new Primitive[mIndexTypes.size()];
+
+            for(int ct = 0; ct < mVertexTypeCount; ct ++) {
+                Allocation alloc = null;
+                Entry entry = mVertexTypes[ct];
+                if (entry.t != null) {
+                    alloc = Allocation.createTyped(mRS, entry.t, mUsage);
+                } else if(entry.e != null) {
+                    alloc = Allocation.createSized(mRS, entry.e, entry.size, mUsage);
+                }
+                vertexBuffers[ct] = alloc;
+                vtx[ct] = alloc.getID();
+            }
+
+            for(int ct = 0; ct < mIndexTypes.size(); ct ++) {
+                Allocation alloc = null;
+                Entry entry = (Entry)mIndexTypes.elementAt(ct);
+                if (entry.t != null) {
+                    alloc = Allocation.createTyped(mRS, entry.t, mUsage);
+                } else if(entry.e != null) {
+                    alloc = Allocation.createSized(mRS, entry.e, entry.size, mUsage);
+                }
+                int allocID = (alloc == null) ? 0 : alloc.getID();
+                indexBuffers[ct] = alloc;
+                primitives[ct] = entry.prim;
+
+                idx[ct] = allocID;
+                prim[ct] = entry.prim.mID;
+            }
+
+            int id = mRS.nMeshCreate(vtx, idx, prim);
+            Mesh newMesh = new Mesh(id, mRS);
+            newMesh.mVertexBuffers = vertexBuffers;
+            newMesh.mIndexBuffers = indexBuffers;
+            newMesh.mPrimitives = primitives;
+
+            return newMesh;
         }
     }
 
@@ -463,40 +465,44 @@
             return this;
         }
 
-        static synchronized Mesh internalCreate(RenderScript rs, AllocationBuilder b) {
-
-            int id = rs.nMeshCreate(b.mVertexTypeCount, b.mIndexTypes.size());
-            Mesh newMesh = new Mesh(id, rs);
-            newMesh.mIndexBuffers = new Allocation[b.mIndexTypes.size()];
-            newMesh.mPrimitives = new Primitive[b.mIndexTypes.size()];
-            newMesh.mVertexBuffers = new Allocation[b.mVertexTypeCount];
-
-            for(int ct = 0; ct < b.mIndexTypes.size(); ct ++) {
-                Entry entry = (Entry)b.mIndexTypes.elementAt(ct);
-                int allocID = (entry.a == null) ? 0 : entry.a.getID();
-                rs.nMeshBindIndex(id, allocID, entry.prim.mID, ct);
-                newMesh.mIndexBuffers[ct] = entry.a;
-                newMesh.mPrimitives[ct] = entry.prim;
-            }
-
-            for(int ct = 0; ct < b.mVertexTypeCount; ct ++) {
-                Entry entry = b.mVertexTypes[ct];
-                rs.nMeshBindVertex(id, entry.a.getID(), ct);
-                newMesh.mVertexBuffers[ct] = entry.a;
-            }
-            rs.nMeshInitVertexAttribs(id);
-
-            return newMesh;
-        }
-
         /**
         * Create a Mesh object from the current state of the builder
         *
         **/
         public Mesh create() {
             mRS.validate();
-            Mesh sm = internalCreate(mRS, this);
-            return sm;
+
+            int[] vtx = new int[mVertexTypeCount];
+            int[] idx = new int[mIndexTypes.size()];
+            int[] prim = new int[mIndexTypes.size()];
+
+            Allocation[] indexBuffers = new Allocation[mIndexTypes.size()];
+            Primitive[] primitives = new Primitive[mIndexTypes.size()];
+            Allocation[] vertexBuffers = new Allocation[mVertexTypeCount];
+
+            for(int ct = 0; ct < mVertexTypeCount; ct ++) {
+                Entry entry = mVertexTypes[ct];
+                vertexBuffers[ct] = entry.a;
+                vtx[ct] = entry.a.getID();
+            }
+
+            for(int ct = 0; ct < mIndexTypes.size(); ct ++) {
+                Entry entry = (Entry)mIndexTypes.elementAt(ct);
+                int allocID = (entry.a == null) ? 0 : entry.a.getID();
+                indexBuffers[ct] = entry.a;
+                primitives[ct] = entry.prim;
+
+                idx[ct] = allocID;
+                prim[ct] = entry.prim.mID;
+            }
+
+            int id = mRS.nMeshCreate(vtx, idx, prim);
+            Mesh newMesh = new Mesh(id, mRS);
+            newMesh.mVertexBuffers = vertexBuffers;
+            newMesh.mIndexBuffers = indexBuffers;
+            newMesh.mPrimitives = primitives;
+
+            return newMesh;
         }
     }
 
diff --git a/graphics/java/android/renderscript/RenderScript.java b/graphics/java/android/renderscript/RenderScript.java
index feb74b8..41a29e6 100644
--- a/graphics/java/android/renderscript/RenderScript.java
+++ b/graphics/java/android/renderscript/RenderScript.java
@@ -527,25 +527,10 @@
         return rsnProgramVertexCreate(mContext, shader, params);
     }
 
-    native int  rsnMeshCreate(int con, int vtxCount, int indexCount);
-    synchronized int nMeshCreate(int vtxCount, int indexCount) {
+    native int  rsnMeshCreate(int con, int[] vtx, int[] idx, int[] prim);
+    synchronized int nMeshCreate(int[] vtx, int[] idx, int[] prim) {
         validate();
-        return rsnMeshCreate(mContext, vtxCount, indexCount);
-    }
-    native void rsnMeshBindVertex(int con, int id, int alloc, int slot);
-    synchronized void nMeshBindVertex(int id, int alloc, int slot) {
-        validate();
-        rsnMeshBindVertex(mContext, id, alloc, slot);
-    }
-    native void rsnMeshBindIndex(int con, int id, int alloc, int prim, int slot);
-    synchronized void nMeshBindIndex(int id, int alloc, int prim, int slot) {
-        validate();
-        rsnMeshBindIndex(mContext, id, alloc, prim, slot);
-    }
-    native void rsnMeshInitVertexAttribs(int con, int id);
-    synchronized void nMeshInitVertexAttribs(int id) {
-        validate();
-        rsnMeshInitVertexAttribs(mContext, id);
+        return rsnMeshCreate(mContext, vtx, idx, prim);
     }
     native int  rsnMeshGetVertexBufferCount(int con, int id);
     synchronized int nMeshGetVertexBufferCount(int id) {
diff --git a/graphics/jni/android_renderscript_RenderScript.cpp b/graphics/jni/android_renderscript_RenderScript.cpp
index 2eaedaa..26a6287 100644
--- a/graphics/jni/android_renderscript_RenderScript.cpp
+++ b/graphics/jni/android_renderscript_RenderScript.cpp
@@ -1075,35 +1075,28 @@
 // ---------------------------------------------------------------------------
 
 static jint
-nMeshCreate(JNIEnv *_env, jobject _this, RsContext con, jint vtxCount, jint idxCount)
+nMeshCreate(JNIEnv *_env, jobject _this, RsContext con, jintArray _vtx, jintArray _idx, jintArray _prim)
 {
-    LOG_API("nMeshCreate, con(%p), vtxCount(%i), idxCount(%i)", con, vtxCount, idxCount);
-    int id = (int)rsMeshCreate(con, vtxCount, idxCount);
+    LOG_API("nMeshCreate, con(%p)", con);
+
+    jint vtxLen = _env->GetArrayLength(_vtx);
+    jint *vtxPtr = _env->GetIntArrayElements(_vtx, NULL);
+    jint idxLen = _env->GetArrayLength(_idx);
+    jint *idxPtr = _env->GetIntArrayElements(_idx, NULL);
+    jint primLen = _env->GetArrayLength(_prim);
+    jint *primPtr = _env->GetIntArrayElements(_prim, NULL);
+
+    int id = (int)rsMeshCreate(con,
+                               (RsAllocation *)vtxPtr, vtxLen,
+                               (RsAllocation *)idxPtr, idxLen,
+                               (uint32_t *)primPtr, primLen);
+
+    _env->ReleaseIntArrayElements(_vtx, vtxPtr, 0);
+    _env->ReleaseIntArrayElements(_idx, idxPtr, 0);
+    _env->ReleaseIntArrayElements(_prim, primPtr, 0);
     return id;
 }
 
-static void
-nMeshBindVertex(JNIEnv *_env, jobject _this, RsContext con, jint mesh, jint alloc, jint slot)
-{
-    LOG_API("nMeshBindVertex, con(%p), Mesh(%p), Alloc(%p), slot(%i)", con, (RsMesh)mesh, (RsAllocation)alloc, slot);
-    rsMeshBindVertex(con, (RsMesh)mesh, (RsAllocation)alloc, slot);
-}
-
-static void
-nMeshBindIndex(JNIEnv *_env, jobject _this, RsContext con, jint mesh, jint alloc, jint primID, jint slot)
-{
-    LOG_API("nMeshBindIndex, con(%p), Mesh(%p), Alloc(%p)", con, (RsMesh)mesh, (RsAllocation)alloc);
-    rsMeshBindIndex(con, (RsMesh)mesh, (RsAllocation)alloc, primID, slot);
-}
-
-static void
-nMeshInitVertexAttribs(JNIEnv *_env, jobject _this, RsContext con, jint mesh)
-{
-    LOG_API("nMeshInitVertexAttribs, con(%p), Mesh(%p)", con, (RsMesh)mesh);
-    rsMeshInitVertexAttribs(con, (RsMesh)mesh);
-}
-
-
 static jint
 nMeshGetVertexBufferCount(JNIEnv *_env, jobject _this, RsContext con, jint mesh)
 {
@@ -1267,10 +1260,7 @@
 
 {"rsnSamplerCreate",                 "(IIIIIIF)I",                            (void*)nSamplerCreate },
 
-{"rsnMeshCreate",                    "(III)I",                                (void*)nMeshCreate },
-{"rsnMeshBindVertex",                "(IIII)V",                               (void*)nMeshBindVertex },
-{"rsnMeshBindIndex",                 "(IIIII)V",                              (void*)nMeshBindIndex },
-{"rsnMeshInitVertexAttribs",         "(II)V",                                 (void*)nMeshInitVertexAttribs },
+{"rsnMeshCreate",                    "(I[I[I[I)I",                            (void*)nMeshCreate },
 
 {"rsnMeshGetVertexBufferCount",      "(II)I",                                 (void*)nMeshGetVertexBufferCount },
 {"rsnMeshGetIndexCount",             "(II)I",                                 (void*)nMeshGetIndexCount },
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 5a86fe3..3232f6f 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -2059,6 +2059,11 @@
     drawTextDecorations(text, bytesCount, length, oldX, oldY, paint);
 }
 
+void OpenGLRenderer::drawGlyphs(const char* glyphs, int index, int count, float x, float y,
+        SkPaint* paint) {
+    // TODO
+}
+
 void OpenGLRenderer::drawPath(SkPath* path, SkPaint* paint) {
     if (mSnapshot->isIgnored()) return;
 
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index ffacbfc..70abe88 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -123,6 +123,8 @@
     virtual void drawPoints(float* points, int count, SkPaint* paint);
     virtual void drawText(const char* text, int bytesCount, int count, float x, float y,
             SkPaint* paint);
+    virtual void drawGlyphs(const char* glyphs, int index, int count, float x, float y,
+            SkPaint* paint);
 
     virtual void resetShader();
     virtual void setupShader(SkiaShader* shader);
diff --git a/libs/rs/rs.spec b/libs/rs/rs.spec
index 00e3a0a..1da00a5 100644
--- a/libs/rs/rs.spec
+++ b/libs/rs/rs.spec
@@ -403,25 +403,8 @@
 	}
 
 MeshCreate {
+	param RsAllocation *vtx
+	param RsAllocation *idx
+	param uint32_t *primType
 	ret RsMesh
-	param uint32_t vtxCount
-	param uint32_t idxCount
 	}
-
-MeshBindIndex {
-	param RsMesh mesh
-	param RsAllocation idx
-	param uint32_t primType
-	param uint32_t slot
-	}
-
-MeshBindVertex {
-	param RsMesh mesh
-	param RsAllocation vtx
-	param uint32_t slot
-	}
-
-MeshInitVertexAttribs {
-	param RsMesh mesh
-	}
-
diff --git a/libs/rs/rsMesh.cpp b/libs/rs/rsMesh.cpp
index 35184c1..3d0342d 100644
--- a/libs/rs/rsMesh.cpp
+++ b/libs/rs/rsMesh.cpp
@@ -263,30 +263,25 @@
 namespace android {
 namespace renderscript {
 
-RsMesh rsi_MeshCreate(Context *rsc, uint32_t vtxCount, uint32_t idxCount) {
+RsMesh rsi_MeshCreate(Context *rsc,
+                      RsAllocation *vtx, uint32_t vtxCount,
+                      RsAllocation *idx, uint32_t idxCount,
+                      uint32_t *primType, uint32_t primTypeCount) {
+    rsAssert(idxCount == primTypeCount);
     Mesh *sm = new Mesh(rsc, vtxCount, idxCount);
     sm->incUserRef();
 
-    return sm;
-}
+    for (uint32_t i = 0; i < vtxCount; i ++) {
+        sm->setVertexBuffer((Allocation*)vtx[i], i);
+    }
 
-void rsi_MeshBindVertex(Context *rsc, RsMesh mv, RsAllocation va, uint32_t slot) {
-    Mesh *sm = static_cast<Mesh *>(mv);
-    rsAssert(slot < sm->mHal.state.vertexBuffersCount);
+    for (uint32_t i = 0; i < idxCount; i ++) {
+        sm->setPrimitive((Allocation*)idx[i], (RsPrimitive)primType[i], i);
+    }
 
-    sm->setVertexBuffer((Allocation *)va, slot);
-}
-
-void rsi_MeshBindIndex(Context *rsc, RsMesh mv, RsAllocation va, uint32_t primType, uint32_t slot) {
-    Mesh *sm = static_cast<Mesh *>(mv);
-    rsAssert(slot < sm->mHal.state.primitivesCount);
-
-    sm->setPrimitive((Allocation *)va, (RsPrimitive)primType, slot);
-}
-
-void rsi_MeshInitVertexAttribs(Context *rsc, RsMesh mv) {
-    Mesh *sm = static_cast<Mesh *>(mv);
     sm->init();
+
+    return sm;
 }
 
 }}
diff --git a/libs/rs/rsMesh.h b/libs/rs/rsMesh.h
index 1e279f4..ed1e93d 100644
--- a/libs/rs/rsMesh.h
+++ b/libs/rs/rsMesh.h
@@ -39,13 +39,6 @@
         RsPrimitive mPrimitive;
     };
 
-    // compatibility to not break the build
-    ObjectBaseRef<Allocation> *mVertexBuffers;
-    uint32_t mVertexBufferCount;
-    Primitive_t ** mPrimitives;
-    uint32_t mPrimitivesCount;
-    // end compatibility
-
     virtual void serialize(OStream *stream) const;
     virtual RsA3DClassID getClassId() const { return RS_A3D_CLASS_ID_MESH; }
     static Mesh *createFromStream(Context *rsc, IStream *stream);
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 10beee9..a6ba1a0 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -1257,6 +1257,7 @@
             LOGV("createTrack_l() setting main buffer %p", chain->inBuffer());
             track->setMainBuffer(chain->inBuffer());
             chain->setStrategy(AudioSystem::getStrategyForStream((audio_stream_type_t)track->type()));
+            chain->incTrackCnt();
         }
     }
     lStatus = NO_ERROR;
@@ -1340,7 +1341,7 @@
             sp<EffectChain> chain = getEffectChain_l(track->sessionId());
             if (chain != 0) {
                 LOGV("addTrack_l() starting track on chain %p for session %d", chain.get(), track->sessionId());
-                chain->startTrack();
+                chain->incActiveTrackCnt();
             }
         }
 
@@ -1358,8 +1359,17 @@
 {
     track->mState = TrackBase::TERMINATED;
     if (mActiveTracks.indexOf(track) < 0) {
-        mTracks.remove(track);
-        deleteTrackName_l(track->name());
+        removeTrack_l(track);
+    }
+}
+
+void AudioFlinger::PlaybackThread::removeTrack_l(const sp<Track>& track)
+{
+    mTracks.remove(track);
+    deleteTrackName_l(track->name());
+    sp<EffectChain> chain = getEffectChain_l(track->sessionId());
+    if (chain != 0) {
+        chain->decTrackCnt();
     }
 }
 
@@ -1865,12 +1875,11 @@
                 chain = getEffectChain_l(track->sessionId());
                 if (chain != 0) {
                     LOGV("stopping track on chain %p for session Id: %d", chain.get(), track->sessionId());
-                    chain->stopTrack();
+                    chain->decActiveTrackCnt();
                 }
             }
             if (track->isTerminated()) {
-                mTracks.remove(track);
-                deleteTrackName_l(track->mName);
+                removeTrack_l(track);
             }
         }
     }
@@ -1956,7 +1965,7 @@
         if (param.getInt(String8(AudioParameter::keyRouting), value) == NO_ERROR) {
             // when changing the audio output device, call addBatteryData to notify
             // the change
-            if (mDevice != value) {
+            if ((int)mDevice != value) {
                 uint32_t params = 0;
                 // check whether speaker is on
                 if (value & AUDIO_DEVICE_OUT_SPEAKER) {
@@ -2348,11 +2357,10 @@
                 if (!effectChains.isEmpty()) {
                     LOGV("stopping track on chain %p for session Id: %d", effectChains[0].get(),
                             trackToRemove->sessionId());
-                    effectChains[0]->stopTrack();
+                    effectChains[0]->decActiveTrackCnt();
                 }
                 if (trackToRemove->isTerminated()) {
-                    mTracks.remove(trackToRemove);
-                    deleteTrackName_l(trackToRemove->mName);
+                    removeTrack_l(trackToRemove);
                 }
             }
 
@@ -5150,6 +5158,7 @@
             if (session == track->sessionId()) {
                 LOGV("addEffectChain_l() track->setMainBuffer track %p buffer %p", track.get(), buffer);
                 track->setMainBuffer(buffer);
+                chain->incTrackCnt();
             }
         }
 
@@ -5159,7 +5168,7 @@
             if (track == 0) continue;
             if (session == track->sessionId()) {
                 LOGV("addEffectChain_l() activating track %p on session %d", track.get(), session);
-                chain->startTrack();
+                chain->incActiveTrackCnt();
             }
         }
     }
@@ -5195,11 +5204,23 @@
     for (size_t i = 0; i < mEffectChains.size(); i++) {
         if (chain == mEffectChains[i]) {
             mEffectChains.removeAt(i);
+            // detach all active tracks from the chain
+            for (size_t i = 0 ; i < mActiveTracks.size() ; ++i) {
+                sp<Track> track = mActiveTracks[i].promote();
+                if (track == 0) continue;
+                if (session == track->sessionId()) {
+                    LOGV("removeEffectChain_l(): stopping track on chain %p for session Id: %d",
+                            chain.get(), session);
+                    chain->decActiveTrackCnt();
+                }
+            }
+
             // detach all tracks with same session ID from this chain
             for (size_t i = 0; i < mTracks.size(); ++i) {
                 sp<Track> track = mTracks[i];
                 if (session == track->sessionId()) {
                     track->setMainBuffer(mMixBuffer);
+                    chain->decTrackCnt();
                 }
             }
             break;
@@ -5481,7 +5502,7 @@
         // If an insert effect is idle and input buffer is different from output buffer,
         // accumulate input onto output
         sp<EffectChain> chain = mChain.promote();
-        if (chain != 0 && chain->activeTracks() != 0) {
+        if (chain != 0 && chain->activeTrackCnt() != 0) {
             size_t frameCnt = mConfig.inputCfg.buffer.frameCount * 2;  //always stereo here
             int16_t *in = mConfig.inputCfg.buffer.s16;
             int16_t *out = mConfig.outputCfg.buffer.s16;
@@ -6157,9 +6178,9 @@
 
 AudioFlinger::EffectChain::EffectChain(const wp<ThreadBase>& wThread,
                                         int sessionId)
-    : mThread(wThread), mSessionId(sessionId), mActiveTrackCnt(0), mOwnInBuffer(false),
-            mVolumeCtrlIdx(-1), mLeftVolume(UINT_MAX), mRightVolume(UINT_MAX),
-            mNewLeftVolume(UINT_MAX), mNewRightVolume(UINT_MAX)
+    : mThread(wThread), mSessionId(sessionId), mActiveTrackCnt(0), mTrackCnt(0),
+      mOwnInBuffer(false), mVolumeCtrlIdx(-1), mLeftVolume(UINT_MAX), mRightVolume(UINT_MAX),
+      mNewLeftVolume(UINT_MAX), mNewRightVolume(UINT_MAX)
 {
     mStrategy = AudioSystem::getStrategyForStream(AUDIO_STREAM_MUSIC);
 }
@@ -6216,8 +6237,15 @@
             (mSessionId == AUDIO_SESSION_OUTPUT_STAGE);
     bool tracksOnSession = false;
     if (!isGlobalSession) {
-        tracksOnSession =
-                playbackThread->hasAudioSession(mSessionId) & PlaybackThread::TRACK_SESSION;
+        tracksOnSession = (trackCnt() != 0);
+    }
+
+    // if no track is active, input buffer must be cleared here as the mixer process
+    // will not do it
+    if (tracksOnSession &&
+            activeTrackCnt() == 0) {
+        size_t numSamples = playbackThread->frameCount() * playbackThread->channelCount();
+        memset(mInBuffer, 0, numSamples * sizeof(int16_t));
     }
 
     size_t size = mEffects.size();
@@ -6230,13 +6258,6 @@
     for (size_t i = 0; i < size; i++) {
         mEffects[i]->updateState();
     }
-    // if no track is active, input buffer must be cleared here as the mixer process
-    // will not do it
-    if (tracksOnSession &&
-        activeTracks() == 0) {
-        size_t numSamples = playbackThread->frameCount() * playbackThread->channelCount();
-        memset(mInBuffer, 0, numSamples * sizeof(int16_t));
-    }
 }
 
 // addEffect_l() must be called with PlaybackThread::mLock held
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 43be6fe..39314ad 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -684,6 +684,7 @@
 
         status_t    addTrack_l(const sp<Track>& track);
         void        destroyTrack_l(const sp<Track>& track);
+        void        removeTrack_l(const sp<Track>& track);
 
         void        readOutputParameters();
 
@@ -1134,9 +1135,13 @@
             return mOutBuffer;
         }
 
-        void startTrack() {mActiveTrackCnt++;}
-        void stopTrack() {mActiveTrackCnt--;}
-        int activeTracks() { return mActiveTrackCnt;}
+        void incTrackCnt() { android_atomic_inc(&mTrackCnt); }
+        void decTrackCnt() { android_atomic_dec(&mTrackCnt); }
+        int32_t trackCnt() { return mTrackCnt;}
+
+        void incActiveTrackCnt() { android_atomic_inc(&mActiveTrackCnt); }
+        void decActiveTrackCnt() { android_atomic_dec(&mActiveTrackCnt); }
+        int32_t activeTrackCnt() { return mActiveTrackCnt;}
 
         uint32_t strategy() { return mStrategy; }
         void setStrategy(uint32_t strategy)
@@ -1155,7 +1160,8 @@
         int mSessionId;             // audio session ID
         int16_t *mInBuffer;         // chain input buffer
         int16_t *mOutBuffer;        // chain output buffer
-        int mActiveTrackCnt;        // number of active tracks connected
+        volatile int32_t mActiveTrackCnt;  // number of active tracks connected
+        volatile int32_t mTrackCnt;        // number of tracks connected
         bool mOwnInBuffer;          // true if the chain owns its input buffer
         int mVolumeCtrlIdx;         // index of insert effect having control over volume
         uint32_t mLeftVolume;       // previous volume on left channel