Merge "Disable CameraServiceTest in a normal build." into kraken
diff --git a/camera/tests/CameraServiceTest/CameraServiceTest.cpp b/camera/tests/CameraServiceTest/CameraServiceTest.cpp
index cb69534..3c8d553 100644
--- a/camera/tests/CameraServiceTest/CameraServiceTest.cpp
+++ b/camera/tests/CameraServiceTest/CameraServiceTest.cpp
@@ -226,7 +226,7 @@
 }
 
 void MCameraClient::notifyCallback(int32_t msgType, int32_t ext1, int32_t ext2) {
-    INFO(__func__);
+    INFO("%s", __func__);
     Mutex::Autolock _l(mLock);
     ssize_t i = mNotifyCount.indexOfKey(msgType);
     if (i < 0) {
@@ -238,7 +238,7 @@
 }
 
 void MCameraClient::dataCallback(int32_t msgType, const sp<IMemory>& data) {
-    INFO(__func__);
+    INFO("%s", __func__);
     int dataSize = data->size();
     INFO("data type = %d, size = %d", msgType, dataSize);
     Mutex::Autolock _l(mLock);
@@ -314,7 +314,7 @@
 };
 
 status_t MSurface::registerBuffers(const BufferHeap& buffers) {
-    INFO(__func__);
+    INFO("%s", __func__);
     Mutex::Autolock _l(mLock);
     ++registerBuffersCount;
     mCond.signal();
@@ -322,26 +322,26 @@
 }
 
 void MSurface::postBuffer(ssize_t offset) {
-    // INFO(__func__);
+    // INFO("%s", __func__);
     Mutex::Autolock _l(mLock);
     ++postBufferCount;
     mCond.signal();
 }
 
 void MSurface::unregisterBuffers() {
-    INFO(__func__);
+    INFO("%s", __func__);
     Mutex::Autolock _l(mLock);
     ++unregisterBuffersCount;
     mCond.signal();
 }
 
 sp<GraphicBuffer> MSurface::requestBuffer(int bufferIdx, int usage) {
-    INFO(__func__);
+    INFO("%s", __func__);
     return NULL;
 }
 
 status_t MSurface::setBufferCount(int bufferCount) {
-    INFO(__func__);
+    INFO("%s", __func__);
     return NULL;
 }
 
@@ -386,17 +386,17 @@
 }
 
 void putTempObject(sp<IBinder> obj) {
-    INFO(__func__);
+    INFO("%s", __func__);
     getHolder()->put(obj);
 }
 
 sp<IBinder> getTempObject() {
-    INFO(__func__);
+    INFO("%s", __func__);
     return getHolder()->get();
 }
 
 void clearTempObject() {
-    INFO(__func__);
+    INFO("%s", __func__);
     getHolder()->clear();
 }
 
@@ -422,7 +422,7 @@
 // Various Connect Tests
 //
 void testConnect(int cameraId) {
-    INFO(__func__);
+    INFO("%s", __func__);
     sp<ICameraService> cs = getCameraService();
     sp<MCameraClient> cc = new MCameraClient();
     sp<ICamera> c = cs->connect(cc, cameraId);
@@ -431,7 +431,7 @@
 }
 
 void testAllowConnectOnceOnly(int cameraId) {
-    INFO(__func__);
+    INFO("%s", __func__);
     sp<ICameraService> cs = getCameraService();
     // Connect the first client.
     sp<MCameraClient> cc = new MCameraClient();
@@ -446,14 +446,14 @@
 }
 
 void testReconnectFailed() {
-    INFO(__func__);
+    INFO("%s", __func__);
     sp<ICamera> c = interface_cast<ICamera>(getTempObject());
     sp<MCameraClient> cc = new MCameraClient();
     ASSERT(c->connect(cc) != NO_ERROR);
 }
 
 void testReconnectSuccess() {
-    INFO(__func__);
+    INFO("%s", __func__);
     sp<ICamera> c = interface_cast<ICamera>(getTempObject());
     sp<MCameraClient> cc = new MCameraClient();
     ASSERT(c->connect(cc) == NO_ERROR);
@@ -461,20 +461,20 @@
 }
 
 void testLockFailed() {
-    INFO(__func__);
+    INFO("%s", __func__);
     sp<ICamera> c = interface_cast<ICamera>(getTempObject());
     ASSERT(c->lock() != NO_ERROR);
 }
 
 void testLockUnlockSuccess() {
-    INFO(__func__);
+    INFO("%s", __func__);
     sp<ICamera> c = interface_cast<ICamera>(getTempObject());
     ASSERT(c->lock() == NO_ERROR);
     ASSERT(c->unlock() == NO_ERROR);
 }
 
 void testLockSuccess() {
-    INFO(__func__);
+    INFO("%s", __func__);
     sp<ICamera> c = interface_cast<ICamera>(getTempObject());
     ASSERT(c->lock() == NO_ERROR);
     c->disconnect();
@@ -525,7 +525,7 @@
 }
 
 void testReconnect(int cameraId) {
-    INFO(__func__);
+    INFO("%s", __func__);
     sp<ICameraService> cs = getCameraService();
     sp<MCameraClient> cc = new MCameraClient();
     sp<ICamera> c = cs->connect(cc, cameraId);
@@ -559,7 +559,7 @@
 }
 
 void testReconnectFromAnotherProcess(int cameraId) {
-    INFO(__func__);
+    INFO("%s", __func__);
 
     sp<ICameraService> cs = getCameraService();
     sp<MCameraClient> cc = new MCameraClient();
@@ -729,7 +729,7 @@
 public:
     void run() {
         String8 param_str = c->getParameters();
-        INFO(param_str);
+        INFO("%s", static_cast<const char*>(param_str));
     }
 };
 
diff --git a/include/private/surfaceflinger/SharedBufferStack.h b/include/private/surfaceflinger/SharedBufferStack.h
index c23832d..c3ac317 100644
--- a/include/private/surfaceflinger/SharedBufferStack.h
+++ b/include/private/surfaceflinger/SharedBufferStack.h
@@ -55,12 +55,6 @@
  * 
  */
 
-// When changing these values, the COMPILE_TIME_ASSERT at the end of this
-// file need to be updated.
-const unsigned int NUM_LAYERS_MAX  = 31;
-const unsigned int NUM_BUFFER_MAX  = 16;
-const unsigned int NUM_DISPLAY_MAX = 4;
-
 // ----------------------------------------------------------------------------
 
 class Region;
@@ -82,6 +76,13 @@
     friend class SharedBufferServer;
 
 public:
+    // When changing these values, the COMPILE_TIME_ASSERT at the end of this
+    // file need to be updated.
+    static const unsigned int NUM_LAYERS_MAX  = 31;
+    static const unsigned int NUM_BUFFER_MAX  = 16;
+    static const unsigned int NUM_BUFFER_MIN  = 2;
+    static const unsigned int NUM_DISPLAY_MAX = 4;
+
     struct Statistics { // 4 longs
         typedef int32_t usecs_t;
         usecs_t  totalTime;
@@ -147,7 +148,7 @@
     // FIXME: this should be replaced by a lock-less primitive
     Mutex lock;
     Condition cv;
-    SharedBufferStack surfaces[ NUM_LAYERS_MAX ];
+    SharedBufferStack surfaces[ SharedBufferStack::NUM_LAYERS_MAX ];
 };
 
 // ============================================================================
@@ -155,7 +156,7 @@
 class SharedBufferBase
 {
 public:
-    SharedBufferBase(SharedClient* sharedClient, int surface, int num,
+    SharedBufferBase(SharedClient* sharedClient, int surface,
             int32_t identity);
     ~SharedBufferBase();
     uint32_t getIdentity();
@@ -166,9 +167,7 @@
 protected:
     SharedClient* const mSharedClient;
     SharedBufferStack* const mSharedStack;
-    int mNumBuffers;
     const int mIdentity;
-    int32_t computeTail() const;
 
     friend struct Update;
     friend struct QueueUpdate;
@@ -217,8 +216,16 @@
     bool needNewBuffer(int buffer) const;
     status_t setDirtyRegion(int buffer, const Region& reg);
     status_t setCrop(int buffer, const Rect& reg);
-    status_t setBufferCount(int bufferCount);
     
+
+    class SetBufferCountCallback {
+        friend class SharedBufferClient;
+        virtual status_t operator()(int bufferCount) const = 0;
+    protected:
+        virtual ~SetBufferCountCallback() { }
+    };
+    status_t setBufferCount(int bufferCount, const SetBufferCountCallback& ipc);
+
 private:
     friend struct Condition;
     friend struct DequeueCondition;
@@ -249,11 +256,16 @@
         inline const char* name() const { return "LockCondition"; }
     };
 
+    int32_t computeTail() const;
+
+    mutable RWLock mLock;
+    int mNumBuffers;
+
     int32_t tail;
     int32_t undoDequeueTail;
     int32_t queued_head;
     // statistics...
-    nsecs_t mDequeueTime[NUM_BUFFER_MAX];
+    nsecs_t mDequeueTime[SharedBufferStack::NUM_BUFFER_MAX];
 };
 
 // ----------------------------------------------------------------------------
@@ -287,7 +299,8 @@
         size_t mCapacity;
         uint32_t mList;
     public:
-        BufferList(size_t c = NUM_BUFFER_MAX) : mCapacity(c), mList(0) { }
+        BufferList(size_t c = SharedBufferStack::NUM_BUFFER_MAX)
+            : mCapacity(c), mList(0) { }
         status_t add(int value);
         status_t remove(int value);
 
@@ -295,7 +308,8 @@
             friend class BufferList;
             uint32_t mask, curr;
             const_iterator(uint32_t mask) :
-                mask(mask), curr(31 - __builtin_clz(mask)) { }
+                mask(mask), curr(__builtin_clz(mask)) {
+            }
         public:
             inline bool operator == (const const_iterator& rhs) const {
                 return mask == rhs.mask;
@@ -304,9 +318,9 @@
                 return mask != rhs.mask;
             }
             inline int operator *() const { return curr; }
-            inline const const_iterator& operator ++(int) {
-                mask &= ~curr;
-                curr = 31 - __builtin_clz(mask);
+            inline const const_iterator& operator ++() {
+                mask &= ~(1<<(31-curr));
+                curr = __builtin_clz(mask);
                 return *this;
             }
         };
@@ -323,6 +337,9 @@
         }
     };
 
+    // this protects mNumBuffers and mBufferList
+    mutable RWLock mLock;
+    int mNumBuffers;
     BufferList mBufferList;
 
     struct UnlockUpdate : public UpdateBase {
@@ -372,7 +389,7 @@
     uint8_t         connected;
     uint8_t         reserved[3];
     uint32_t        pad[7];
-    display_cblk_t  displays[NUM_DISPLAY_MAX];
+    display_cblk_t  displays[SharedBufferStack::NUM_DISPLAY_MAX];
 };
 
 // ---------------------------------------------------------------------------
diff --git a/include/surfaceflinger/Surface.h b/include/surfaceflinger/Surface.h
index 973780f..e4d60af 100644
--- a/include/surfaceflinger/Surface.h
+++ b/include/surfaceflinger/Surface.h
@@ -212,6 +212,7 @@
     int  dispatch_connect(va_list args);
     int  dispatch_disconnect(va_list args);
     int  dispatch_crop(va_list args);
+    int  dispatch_set_buffer_count(va_list args);
     
     void setUsage(uint32_t reqUsage);
     int  connect(int api);
diff --git a/include/ui/egl/android_natives.h b/include/ui/egl/android_natives.h
index 49bfa2b..b44901f 100644
--- a/include/ui/egl/android_natives.h
+++ b/include/ui/egl/android_natives.h
@@ -81,6 +81,7 @@
     NATIVE_WINDOW_CONNECT,
     NATIVE_WINDOW_DISCONNECT,
     NATIVE_WINDOW_SET_CROP,
+    NATIVE_WINDOW_SET_BUFFER_COUNT,
 };
 
 /* parameter for NATIVE_WINDOW_[DIS]CONNECT */
@@ -190,6 +191,7 @@
      *     NATIVE_WINDOW_CONNECT
      *     NATIVE_WINDOW_DISCONNECT
      *     NATIVE_WINDOW_SET_CROP
+     *     NATIVE_WINDOW_SET_BUFFER_COUNT
      *  
      */
     
@@ -201,8 +203,9 @@
 
 
 /*
- *  native_window_set_usage() sets the intended usage flags for the next
- *  buffers acquired with (*lockBuffer)() and on.
+ *  native_window_set_usage(..., usage)
+ *  Sets the intended usage flags for the next buffers
+ *  acquired with (*lockBuffer)() and on.
  *  By default (if this function is never called), a usage of
  *      GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE
  *  is assumed.
@@ -217,8 +220,8 @@
 }
 
 /*
- * native_window_connect(..., NATIVE_WINDOW_API_EGL) must be called
- * by EGL when the window is made current.
+ * native_window_connect(..., NATIVE_WINDOW_API_EGL)
+ * Must be called by EGL when the window is made current.
  * Returns -EINVAL if for some reason the window cannot be connected, which
  * can happen if it's connected to some other API.
  */
@@ -229,8 +232,8 @@
 }
 
 /*
- * native_window_disconnect(..., NATIVE_WINDOW_API_EGL) must be called
- * by EGL when the window is made not current.
+ * native_window_disconnect(..., NATIVE_WINDOW_API_EGL)
+ * Must be called by EGL when the window is made not current.
  * An error is returned if for instance the window wasn't connected in the
  * first place.
  */
@@ -241,8 +244,8 @@
 }
 
 /*
- * native_window_set_crop(..., crop) sets which region of the next queued
- * buffers needs to be considered.
+ * native_window_set_crop(..., crop)
+ * Sets which region of the next queued buffers needs to be considered.
  * A buffer's crop region is scaled to match the surface's size.
  *
  * The specified crop region applies to all buffers queued after it is called.
@@ -259,6 +262,17 @@
     return window->perform(window, NATIVE_WINDOW_SET_CROP, crop);
 }
 
+/*
+ * native_window_set_buffer_count(..., count)
+ * Sets the number of buffers associated with this native window.
+ */
+static inline int native_window_set_buffer_count(
+        android_native_window_t* window,
+        size_t bufferCount)
+{
+    return window->perform(window, NATIVE_WINDOW_SET_BUFFER_COUNT, bufferCount);
+}
+
 // ---------------------------------------------------------------------------
 
 /* FIXME: this is legacy for pixmaps */
diff --git a/include/utils/threads.h b/include/utils/threads.h
index 5ac0c5e..1bcfaed 100644
--- a/include/utils/threads.h
+++ b/include/utils/threads.h
@@ -295,6 +295,96 @@
 
 /*****************************************************************************/
 
+#if defined(HAVE_PTHREADS)
+
+/*
+ * Simple mutex class.  The implementation is system-dependent.
+ *
+ * The mutex must be unlocked by the thread that locked it.  They are not
+ * recursive, i.e. the same thread can't lock it multiple times.
+ */
+class RWLock {
+public:
+    enum {
+        PRIVATE = 0,
+        SHARED = 1
+    };
+
+                RWLock();
+                RWLock(const char* name);
+                RWLock(int type, const char* name = NULL);
+                ~RWLock();
+
+    status_t    readLock();
+    status_t    tryReadLock();
+    status_t    writeLock();
+    status_t    tryWriteLock();
+    void        unlock();
+
+    class AutoRLock {
+    public:
+        inline AutoRLock(RWLock& rwlock) : mLock(rwlock)  { mLock.readLock(); }
+        inline ~AutoRLock() { mLock.unlock(); }
+    private:
+        RWLock& mLock;
+    };
+
+    class AutoWLock {
+    public:
+        inline AutoWLock(RWLock& rwlock) : mLock(rwlock)  { mLock.writeLock(); }
+        inline ~AutoWLock() { mLock.unlock(); }
+    private:
+        RWLock& mLock;
+    };
+
+private:
+    // A RWLock cannot be copied
+                RWLock(const RWLock&);
+   RWLock&      operator = (const RWLock&);
+
+   pthread_rwlock_t mRWLock;
+};
+
+inline RWLock::RWLock() {
+    pthread_rwlock_init(&mRWLock, NULL);
+}
+inline RWLock::RWLock(const char* name) {
+    pthread_rwlock_init(&mRWLock, NULL);
+}
+inline RWLock::RWLock(int type, const char* name) {
+    if (type == SHARED) {
+        pthread_rwlockattr_t attr;
+        pthread_rwlockattr_init(&attr);
+        pthread_rwlockattr_setpshared(&attr, PTHREAD_PROCESS_SHARED);
+        pthread_rwlock_init(&mRWLock, &attr);
+        pthread_rwlockattr_destroy(&attr);
+    } else {
+        pthread_rwlock_init(&mRWLock, NULL);
+    }
+}
+inline RWLock::~RWLock() {
+    pthread_rwlock_destroy(&mRWLock);
+}
+inline status_t RWLock::readLock() {
+    return -pthread_rwlock_rdlock(&mRWLock);
+}
+inline status_t RWLock::tryReadLock() {
+    return -pthread_rwlock_tryrdlock(&mRWLock);
+}
+inline status_t RWLock::writeLock() {
+    return -pthread_rwlock_wrlock(&mRWLock);
+}
+inline status_t RWLock::tryWriteLock() {
+    return -pthread_rwlock_trywrlock(&mRWLock);
+}
+inline void RWLock::unlock() {
+    pthread_rwlock_unlock(&mRWLock);
+}
+
+#endif // HAVE_PTHREADS
+
+/*****************************************************************************/
+
 /*
  * Condition variable class.  The implementation is system-dependent.
  *
diff --git a/libs/audioflinger/AudioFlinger.cpp b/libs/audioflinger/AudioFlinger.cpp
index 06443ef..3b38d83 100644
--- a/libs/audioflinger/AudioFlinger.cpp
+++ b/libs/audioflinger/AudioFlinger.cpp
@@ -783,7 +783,7 @@
 AudioFlinger::ThreadBase::ThreadBase(const sp<AudioFlinger>& audioFlinger, int id)
     :   Thread(false),
         mAudioFlinger(audioFlinger), mSampleRate(0), mFrameCount(0), mChannelCount(0),
-        mFormat(0), mFrameSize(1), mStandby(false), mId(id), mExiting(false)
+        mFrameSize(1), mFormat(0), mStandby(false), mId(id), mExiting(false)
 {
 }
 
@@ -816,7 +816,7 @@
 
 int AudioFlinger::ThreadBase::channelCount() const
 {
-    return mChannelCount;
+    return (int)mChannelCount;
 }
 
 int AudioFlinger::ThreadBase::format() const
@@ -873,11 +873,12 @@
         LOGV("processConfigEvents() remaining events %d", mConfigEvents.size());
         ConfigEvent *configEvent = mConfigEvents[0];
         mConfigEvents.removeAt(0);
-        // release mLock because audioConfigChanged() will lock AudioFlinger mLock
-        // before calling Audioflinger::audioConfigChanged_l() thus creating
-        // potential cross deadlock between AudioFlinger::mLock and mLock
+        // release mLock before locking AudioFlinger mLock: lock order is always
+        // AudioFlinger then ThreadBase to avoid cross deadlock
         mLock.unlock();
-        audioConfigChanged(configEvent->mEvent, configEvent->mParam);
+        mAudioFlinger->mLock.lock();
+        audioConfigChanged_l(configEvent->mEvent, configEvent->mParam);
+        mAudioFlinger->mLock.unlock();
         delete configEvent;
         mLock.lock();
     }
@@ -953,8 +954,6 @@
         mStreamTypes[stream].volume = mAudioFlinger->streamVolumeInternal(stream);
         mStreamTypes[stream].mute = mAudioFlinger->streamMute(stream);
     }
-    // notify client processes that a new input has been opened
-    sendConfigEvent(AudioSystem::OUTPUT_OPENED);
 }
 
 AudioFlinger::PlaybackThread::~PlaybackThread()
@@ -1064,7 +1063,7 @@
     status_t lStatus;
 
     if (mType == DIRECT) {
-        if (sampleRate != mSampleRate || format != mFormat || channelCount != mChannelCount) {
+        if (sampleRate != mSampleRate || format != mFormat || channelCount != (int)mChannelCount) {
             LOGE("createTrack_l() Bad parameter:  sampleRate %d format %d, channelCount %d for output %p",
                  sampleRate, format, channelCount, mOutput);
             lStatus = BAD_VALUE;
@@ -1234,16 +1233,17 @@
     return mOutput->getParameters(keys);
 }
 
-void AudioFlinger::PlaybackThread::audioConfigChanged(int event, int param) {
+// destroyTrack_l() must be called with AudioFlinger::mLock held
+void AudioFlinger::PlaybackThread::audioConfigChanged_l(int event, int param) {
     AudioSystem::OutputDescriptor desc;
     void *param2 = 0;
 
-    LOGV("PlaybackThread::audioConfigChanged, thread %p, event %d, param %d", this, event, param);
+    LOGV("PlaybackThread::audioConfigChanged_l, thread %p, event %d, param %d", this, event, param);
 
     switch (event) {
     case AudioSystem::OUTPUT_OPENED:
     case AudioSystem::OUTPUT_CONFIG_CHANGED:
-        desc.channels = mChannelCount;
+        desc.channels = mChannels;
         desc.samplingRate = mSampleRate;
         desc.format = mFormat;
         desc.frameCount = mFrameCount;
@@ -1257,17 +1257,16 @@
     default:
         break;
     }
-    Mutex::Autolock _l(mAudioFlinger->mLock);
     mAudioFlinger->audioConfigChanged_l(event, mId, param2);
 }
 
 void AudioFlinger::PlaybackThread::readOutputParameters()
 {
     mSampleRate = mOutput->sampleRate();
-    mChannelCount = AudioSystem::popCount(mOutput->channels());
-
+    mChannels = mOutput->channels();
+    mChannelCount = (uint16_t)AudioSystem::popCount(mChannels);
     mFormat = mOutput->format();
-    mFrameSize = mOutput->frameSize();
+    mFrameSize = (uint16_t)mOutput->frameSize();
     mFrameCount = mOutput->bufferSize() / mFrameSize;
 
     // FIXME - Current mixer implementation only supports stereo output: Always
@@ -1614,66 +1613,22 @@
     return mixerStatus;
 }
 
-void AudioFlinger::MixerThread::getTracks(
-        SortedVector < sp<Track> >& tracks,
-        SortedVector < wp<Track> >& activeTracks,
-        int streamType)
+void AudioFlinger::MixerThread::invalidateTracks(int streamType)
 {
-    LOGV ("MixerThread::getTracks() mixer %p, mTracks.size %d, mActiveTracks.size %d", this,  mTracks.size(), mActiveTracks.size());
+    LOGV ("MixerThread::invalidateTracks() mixer %p, streamType %d, mTracks.size %d", this,  streamType, mTracks.size());
     Mutex::Autolock _l(mLock);
     size_t size = mTracks.size();
     for (size_t i = 0; i < size; i++) {
         sp<Track> t = mTracks[i];
         if (t->type() == streamType) {
-            tracks.add(t);
-            int j = mActiveTracks.indexOf(t);
-            if (j >= 0) {
-                t = mActiveTracks[j].promote();
-                if (t != NULL) {
-                    activeTracks.add(t);
+            t->mCblk->lock.lock();
+            t->mCblk->flags |= CBLK_INVALID_ON;
+            t->mCblk->cv.signal();
+            t->mCblk->lock.unlock();
                 }
             }
         }
-    }
 
-    size = activeTracks.size();
-    for (size_t i = 0; i < size; i++) {
-        mActiveTracks.remove(activeTracks[i]);
-    }
-
-    size = tracks.size();
-    for (size_t i = 0; i < size; i++) {
-        sp<Track> t = tracks[i];
-        mTracks.remove(t);
-        deleteTrackName_l(t->name());
-    }
-}
-
-void AudioFlinger::MixerThread::putTracks(
-        SortedVector < sp<Track> >& tracks,
-        SortedVector < wp<Track> >& activeTracks)
-{
-    LOGV ("MixerThread::putTracks() mixer %p, tracks.size %d, activeTracks.size %d", this,  tracks.size(), activeTracks.size());
-    Mutex::Autolock _l(mLock);
-    size_t size = tracks.size();
-    for (size_t i = 0; i < size ; i++) {
-        sp<Track> t = tracks[i];
-        int name = getTrackName_l();
-
-        if (name < 0) return;
-
-        t->mName = name;
-        t->mThread = this;
-        mTracks.add(t);
-
-        int j = activeTracks.indexOf(t);
-        if (j >= 0) {
-            mActiveTracks.add(t);
-            // force buffer refilling and no ramp volume when the track is mixed for the first time
-            t->mFillingUpStatus = Track::FS_FILLING;
-        }
-    }
-}
 
 // getTrackName_l() must be called with ThreadBase::mLock held
 int AudioFlinger::MixerThread::getTrackName_l()
@@ -2342,13 +2297,13 @@
                 // clear all buffers
                 mCblk->frameCount = frameCount;
                 mCblk->sampleRate = sampleRate;
-                mCblk->channels = (uint8_t)channelCount;
+                mCblk->channelCount = (uint8_t)channelCount;
                 if (sharedBuffer == 0) {
                     mBuffer = (char*)mCblk + sizeof(audio_track_cblk_t);
                     memset(mBuffer, 0, frameCount*channelCount*sizeof(int16_t));
                     // Force underrun condition to avoid false underrun callback until first data is
                     // written to buffer
-                    mCblk->flowControlFlag = 1;
+                    mCblk->flags = CBLK_UNDERRUN_ON;
                 } else {
                     mBuffer = sharedBuffer->pointer();
                 }
@@ -2366,12 +2321,12 @@
            // clear all buffers
            mCblk->frameCount = frameCount;
            mCblk->sampleRate = sampleRate;
-           mCblk->channels = (uint8_t)channelCount;
+           mCblk->channelCount = (uint8_t)channelCount;
            mBuffer = (char*)mCblk + sizeof(audio_track_cblk_t);
            memset(mBuffer, 0, frameCount*channelCount*sizeof(int16_t));
            // Force underrun condition to avoid false underrun callback until first data is
            // written to buffer
-           mCblk->flowControlFlag = 1;
+           mCblk->flags = CBLK_UNDERRUN_ON;
            mBufferEnd = (uint8_t *)mBuffer + bufferSize;
        }
    }
@@ -2433,7 +2388,7 @@
 }
 
 int AudioFlinger::ThreadBase::TrackBase::channelCount() const {
-    return (int)mCblk->channels;
+    return (int)mCblk->channelCount;
 }
 
 void* AudioFlinger::ThreadBase::TrackBase::getBuffer(uint32_t offset, uint32_t frames) const {
@@ -2445,9 +2400,9 @@
     if (bufferStart < mBuffer || bufferStart > bufferEnd || bufferEnd > mBufferEnd ||
         ((unsigned long)bufferStart & (unsigned long)(cblk->frameSize - 1))) {
         LOGE("TrackBase::getBuffer buffer out of range:\n    start: %p, end %p , mBuffer %p mBufferEnd %p\n    \
-                server %d, serverBase %d, user %d, userBase %d, channels %d",
+                server %d, serverBase %d, user %d, userBase %d, channelCount %d",
                 bufferStart, bufferEnd, mBuffer, mBufferEnd,
-                cblk->server, cblk->serverBase, cblk->user, cblk->userBase, cblk->channels);
+                cblk->server, cblk->serverBase, cblk->user, cblk->userBase, cblk->channelCount);
         return 0;
     }
 
@@ -2532,7 +2487,7 @@
             (mClient == NULL) ? getpid() : mClient->pid(),
             mStreamType,
             mFormat,
-            mCblk->channels,
+            mCblk->channelCount,
             mFrameCount,
             mState,
             mMute,
@@ -2589,9 +2544,9 @@
     if (mFillingUpStatus != FS_FILLING) return true;
 
     if (mCblk->framesReady() >= mCblk->frameCount ||
-        mCblk->forceReady) {
+            (mCblk->flags & CBLK_FORCEREADY_MSK)) {
         mFillingUpStatus = FS_FILLED;
-        mCblk->forceReady = 0;
+        mCblk->flags &= ~CBLK_FORCEREADY_MSK;
         return true;
     }
     return false;
@@ -2706,8 +2661,8 @@
         TrackBase::reset();
         // Force underrun condition to avoid false underrun callback until first data is
         // written to buffer
-        mCblk->flowControlFlag = 1;
-        mCblk->forceReady = 0;
+        mCblk->flags |= CBLK_UNDERRUN_ON;
+        mCblk->flags &= ~CBLK_FORCEREADY_MSK;
         mFillingUpStatus = FS_FILLING;
         mResetDone = true;
     }
@@ -2818,7 +2773,7 @@
         TrackBase::reset();
         // Force overerrun condition to avoid false overrun callback until first data is
         // read from buffer
-        mCblk->flowControlFlag = 1;
+        mCblk->flags |= CBLK_UNDERRUN_ON;
     }
 }
 
@@ -2827,7 +2782,7 @@
     snprintf(buffer, size, "   %05d %03u %03u %04u %01d %05u  %08x %08x\n",
             (mClient == NULL) ? getpid() : mClient->pid(),
             mFormat,
-            mCblk->channels,
+            mCblk->channelCount,
             mFrameCount,
             mState,
             mCblk->sampleRate,
@@ -2851,13 +2806,13 @@
 
     PlaybackThread *playbackThread = (PlaybackThread *)thread.unsafe_get();
     if (mCblk != NULL) {
-        mCblk->out = 1;
+        mCblk->flags |= CBLK_DIRECTION_OUT;
         mCblk->buffers = (char*)mCblk + sizeof(audio_track_cblk_t);
         mCblk->volume[0] = mCblk->volume[1] = 0x1000;
         mOutBuffer.frameCount = 0;
         playbackThread->mTracks.add(this);
-        LOGV("OutputTrack constructor mCblk %p, mBuffer %p, mCblk->buffers %p, mCblk->frameCount %d, mCblk->sampleRate %d, mCblk->channels %d mBufferEnd %p",
-                mCblk, mBuffer, mCblk->buffers, mCblk->frameCount, mCblk->sampleRate, mCblk->channels, mBufferEnd);
+        LOGV("OutputTrack constructor mCblk %p, mBuffer %p, mCblk->buffers %p, mCblk->frameCount %d, mCblk->sampleRate %d, mCblk->channelCount %d mBufferEnd %p",
+                mCblk, mBuffer, mCblk->buffers, mCblk->frameCount, mCblk->sampleRate, mCblk->channelCount, mBufferEnd);
     } else {
         LOGW("Error creating output track on thread %p", playbackThread);
     }
@@ -2892,7 +2847,7 @@
 {
     Buffer *pInBuffer;
     Buffer inBuffer;
-    uint32_t channels = mCblk->channels;
+    uint32_t channelCount = mCblk->channelCount;
     bool outputBufferFull = false;
     inBuffer.frameCount = frames;
     inBuffer.i16 = data;
@@ -2908,10 +2863,10 @@
                 if (mBufferQueue.size() < kMaxOverFlowBuffers) {
                     uint32_t startFrames = (mCblk->frameCount - frames);
                     pInBuffer = new Buffer;
-                    pInBuffer->mBuffer = new int16_t[startFrames * channels];
+                    pInBuffer->mBuffer = new int16_t[startFrames * channelCount];
                     pInBuffer->frameCount = startFrames;
                     pInBuffer->i16 = pInBuffer->mBuffer;
-                    memset(pInBuffer->raw, 0, startFrames * channels * sizeof(int16_t));
+                    memset(pInBuffer->raw, 0, startFrames * channelCount * sizeof(int16_t));
                     mBufferQueue.add(pInBuffer);
                 } else {
                     LOGW ("OutputTrack::write() %p no more buffers in queue", this);
@@ -2949,12 +2904,12 @@
         }
 
         uint32_t outFrames = pInBuffer->frameCount > mOutBuffer.frameCount ? mOutBuffer.frameCount : pInBuffer->frameCount;
-        memcpy(mOutBuffer.raw, pInBuffer->raw, outFrames * channels * sizeof(int16_t));
+        memcpy(mOutBuffer.raw, pInBuffer->raw, outFrames * channelCount * sizeof(int16_t));
         mCblk->stepUser(outFrames);
         pInBuffer->frameCount -= outFrames;
-        pInBuffer->i16 += outFrames * channels;
+        pInBuffer->i16 += outFrames * channelCount;
         mOutBuffer.frameCount -= outFrames;
-        mOutBuffer.i16 += outFrames * channels;
+        mOutBuffer.i16 += outFrames * channelCount;
 
         if (pInBuffer->frameCount == 0) {
             if (mBufferQueue.size()) {
@@ -2974,10 +2929,10 @@
         if (thread != 0 && !thread->standby()) {
             if (mBufferQueue.size() < kMaxOverFlowBuffers) {
                 pInBuffer = new Buffer;
-                pInBuffer->mBuffer = new int16_t[inBuffer.frameCount * channels];
+                pInBuffer->mBuffer = new int16_t[inBuffer.frameCount * channelCount];
                 pInBuffer->frameCount = inBuffer.frameCount;
                 pInBuffer->i16 = pInBuffer->mBuffer;
-                memcpy(pInBuffer->raw, inBuffer.raw, inBuffer.frameCount * channels * sizeof(int16_t));
+                memcpy(pInBuffer->raw, inBuffer.raw, inBuffer.frameCount * channelCount * sizeof(int16_t));
                 mBufferQueue.add(pInBuffer);
                 LOGV("OutputTrack::write() %p thread %p adding overflow buffer %d", this, mThread.unsafe_get(), mBufferQueue.size());
             } else {
@@ -2993,10 +2948,10 @@
         if (mCblk->user < mCblk->frameCount) {
             frames = mCblk->frameCount - mCblk->user;
             pInBuffer = new Buffer;
-            pInBuffer->mBuffer = new int16_t[frames * channels];
+            pInBuffer->mBuffer = new int16_t[frames * channelCount];
             pInBuffer->frameCount = frames;
             pInBuffer->i16 = pInBuffer->mBuffer;
-            memset(pInBuffer->raw, 0, frames * channels * sizeof(int16_t));
+            memset(pInBuffer->raw, 0, frames * channelCount * sizeof(int16_t));
             mBufferQueue.add(pInBuffer);
         } else if (mActive) {
             stop();
@@ -3274,7 +3229,6 @@
     mReqChannelCount = AudioSystem::popCount(channels);
     mReqSampleRate = sampleRate;
     readInputParameters();
-    sendConfigEvent(AudioSystem::INPUT_OPENED);
 }
 
 
@@ -3371,7 +3325,7 @@
                                 framesIn = framesOut;
                             mRsmpInIndex += framesIn;
                             framesOut -= framesIn;
-                            if (mChannelCount == mReqChannelCount ||
+                            if ((int)mChannelCount == mReqChannelCount ||
                                 mFormat != AudioSystem::PCM_16_BIT) {
                                 memcpy(dst, src, framesIn * mFrameSize);
                             } else {
@@ -3392,7 +3346,7 @@
                         }
                         if (framesOut && mFrameCount == mRsmpInIndex) {
                             if (framesOut == mFrameCount &&
-                                (mChannelCount == mReqChannelCount || mFormat != AudioSystem::PCM_16_BIT)) {
+                                ((int)mChannelCount == mReqChannelCount || mFormat != AudioSystem::PCM_16_BIT)) {
                                 mBytesRead = mInput->read(buffer.raw, mInputBytes);
                                 framesOut = 0;
                             } else {
@@ -3689,14 +3643,14 @@
     return mInput->getParameters(keys);
 }
 
-void AudioFlinger::RecordThread::audioConfigChanged(int event, int param) {
+void AudioFlinger::RecordThread::audioConfigChanged_l(int event, int param) {
     AudioSystem::OutputDescriptor desc;
     void *param2 = 0;
 
     switch (event) {
     case AudioSystem::INPUT_OPENED:
     case AudioSystem::INPUT_CONFIG_CHANGED:
-        desc.channels = mChannelCount;
+        desc.channels = mChannels;
         desc.samplingRate = mSampleRate;
         desc.format = mFormat;
         desc.frameCount = mFrameCount;
@@ -3708,7 +3662,6 @@
     default:
         break;
     }
-    Mutex::Autolock _l(mAudioFlinger->mLock);
     mAudioFlinger->audioConfigChanged_l(event, mId, param2);
 }
 
@@ -3720,9 +3673,10 @@
     mResampler = 0;
 
     mSampleRate = mInput->sampleRate();
-    mChannelCount = AudioSystem::popCount(mInput->channels());
+    mChannels = mInput->channels();
+    mChannelCount = (uint16_t)AudioSystem::popCount(mChannels);
     mFormat = mInput->format();
-    mFrameSize = mInput->frameSize();
+    mFrameSize = (uint16_t)mInput->frameSize();
     mInputBytes = mInput->bufferSize();
     mFrameCount = mInputBytes / mFrameSize;
     mRsmpInBuffer = new int16_t[mFrameCount * mChannelCount];
@@ -3827,6 +3781,8 @@
         if (pChannels) *pChannels = channels;
         if (pLatencyMs) *pLatencyMs = thread->latency();
 
+        // notify client processes of the new output creation
+        thread->audioConfigChanged_l(AudioSystem::OUTPUT_OPENED);
         return mNextThreadId;
     }
 
@@ -3848,6 +3804,8 @@
     DuplicatingThread *thread = new DuplicatingThread(this, thread1, ++mNextThreadId);
     thread->addOutputTrack(thread2);
     mPlaybackThreads.add(mNextThreadId, thread);
+    // notify client processes of the new output creation
+    thread->audioConfigChanged_l(AudioSystem::OUTPUT_OPENED);
     return mNextThreadId;
 }
 
@@ -3977,6 +3935,8 @@
 
         input->standby();
 
+        // notify client processes of the new input creation
+        thread->audioConfigChanged_l(AudioSystem::INPUT_OPENED);
         return mNextThreadId;
     }
 
@@ -4017,22 +3977,16 @@
     }
 
     LOGV("setStreamOutput() stream %d to output %d", stream, output);
+    audioConfigChanged_l(AudioSystem::STREAM_CONFIG_CHANGED, output, &stream);
 
     for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
         PlaybackThread *thread = mPlaybackThreads.valueAt(i).get();
         if (thread != dstThread &&
             thread->type() != PlaybackThread::DIRECT) {
             MixerThread *srcThread = (MixerThread *)thread;
-            SortedVector < sp<MixerThread::Track> > tracks;
-            SortedVector < wp<MixerThread::Track> > activeTracks;
-            srcThread->getTracks(tracks, activeTracks, stream);
-            if (tracks.size()) {
-                dstThread->putTracks(tracks, activeTracks);
+            srcThread->invalidateTracks(stream);
             }
         }
-    }
-
-    dstThread->sendConfigEvent(AudioSystem::STREAM_CONFIG_CHANGED, stream);
 
     return NO_ERROR;
 }
diff --git a/libs/audioflinger/AudioFlinger.h b/libs/audioflinger/AudioFlinger.h
index 13aac8b..f35f38b 100644
--- a/libs/audioflinger/AudioFlinger.h
+++ b/libs/audioflinger/AudioFlinger.h
@@ -342,7 +342,7 @@
         virtual     bool        checkForNewParameters_l() = 0;
         virtual     status_t    setParameters(const String8& keyValuePairs);
         virtual     String8     getParameters(const String8& keys) = 0;
-        virtual     void        audioConfigChanged(int event, int param = 0) = 0;
+        virtual     void        audioConfigChanged_l(int event, int param = 0) = 0;
                     void        sendConfigEvent(int event, int param = 0);
                     void        sendConfigEvent_l(int event, int param = 0);
                     void        processConfigEvents();
@@ -366,9 +366,10 @@
                     sp<AudioFlinger>        mAudioFlinger;
                     uint32_t                mSampleRate;
                     size_t                  mFrameCount;
-                    int                     mChannelCount;
+                    uint32_t                mChannels;
+                    uint16_t                mChannelCount;
+                    uint16_t                mFrameSize;
                     int                     mFormat;
-                    uint32_t                mFrameSize;
                     Condition               mParamCond;
                     Vector<String8>         mNewParameters;
                     status_t                mParamStatus;
@@ -546,7 +547,7 @@
                     void        restore() { if (mSuspended) mSuspended--; }
                     bool        isSuspended() { return (mSuspended != 0); }
         virtual     String8     getParameters(const String8& keys);
-        virtual     void        audioConfigChanged(int event, int param = 0);
+        virtual     void        audioConfigChanged_l(int event, int param = 0);
         virtual     status_t    getRenderPosition(uint32_t *halFrames, uint32_t *dspFrames);
 
         struct  stream_type_t {
@@ -612,11 +613,7 @@
         // Thread virtuals
         virtual     bool        threadLoop();
 
-                    void        getTracks(SortedVector < sp<Track> >& tracks,
-                                      SortedVector < wp<Track> >& activeTracks,
-                                      int streamType);
-                    void        putTracks(SortedVector < sp<Track> >& tracks,
-                                      SortedVector < wp<Track> >& activeTracks);
+                    void        invalidateTracks(int streamType);
         virtual     bool        checkForNewParameters_l();
         virtual     status_t    dumpInternals(int fd, const Vector<String16>& args);
 
@@ -763,7 +760,7 @@
         virtual void        releaseBuffer(AudioBufferProvider::Buffer* buffer);
         virtual bool        checkForNewParameters_l();
         virtual String8     getParameters(const String8& keys);
-        virtual void        audioConfigChanged(int event, int param = 0);
+        virtual void        audioConfigChanged_l(int event, int param = 0);
                 void        readInputParameters();
         virtual unsigned int  getInputFramesLost();
 
diff --git a/libs/audioflinger/AudioPolicyManagerBase.cpp b/libs/audioflinger/AudioPolicyManagerBase.cpp
index c8b3f48..381a958 100644
--- a/libs/audioflinger/AudioPolicyManagerBase.cpp
+++ b/libs/audioflinger/AudioPolicyManagerBase.cpp
@@ -1249,6 +1249,17 @@
     LOGV("setDeviceConnectionState() closing A2DP and duplicated output!");
 
     if (mDuplicatedOutput != 0) {
+        AudioOutputDescriptor *dupOutputDesc = mOutputs.valueFor(mDuplicatedOutput);
+        AudioOutputDescriptor *hwOutputDesc = mOutputs.valueFor(mHardwareOutput);
+        // As all active tracks on duplicated output will be deleted,
+        // and as they were also referenced on hardware output, the reference
+        // count for their stream type must be adjusted accordingly on
+        // hardware output.
+        for (int i = 0; i < (int)AudioSystem::NUM_STREAM_TYPES; i++) {
+            int refCount = dupOutputDesc->mRefCount[i];
+            hwOutputDesc->changeRefCount((AudioSystem::stream_type)i,-refCount);
+        }
+
         mpClientInterface->closeOutput(mDuplicatedOutput);
         delete mOutputs.valueFor(mDuplicatedOutput);
         mOutputs.removeItem(mDuplicatedOutput);
@@ -1288,11 +1299,6 @@
         for (int i = 0; i < (int)AudioSystem::NUM_STREAM_TYPES; i++) {
             if (getStrategy((AudioSystem::stream_type)i) == strategy) {
                 mpClientInterface->setStreamOutput((AudioSystem::stream_type)i, mHardwareOutput);
-                int refCount = a2dpOutputDesc->mRefCount[i];
-                // in the case of duplicated output, the ref count is first incremented
-                // and then decremented on hardware output tus keeping its value
-                hwOutputDesc->changeRefCount((AudioSystem::stream_type)i, refCount);
-                a2dpOutputDesc->changeRefCount((AudioSystem::stream_type)i,-refCount);
             }
         }
         // do not change newDevice if it was already set before this call by a previous call to
@@ -1318,11 +1324,6 @@
         for (int i = 0; i < (int)AudioSystem::NUM_STREAM_TYPES; i++) {
             if (getStrategy((AudioSystem::stream_type)i) == strategy) {
                 mpClientInterface->setStreamOutput((AudioSystem::stream_type)i, a2dpOutput);
-                int refCount = hwOutputDesc->mRefCount[i];
-                // in the case of duplicated output, the ref count is first incremented
-                // and then decremented on hardware output tus keeping its value
-                a2dpOutputDesc->changeRefCount((AudioSystem::stream_type)i, refCount);
-                hwOutputDesc->changeRefCount((AudioSystem::stream_type)i,-refCount);
             }
         }
     }
diff --git a/libs/surfaceflinger/Barrier.h b/libs/surfaceflinger/Barrier.h
index e2bcf6a..6f8507e 100644
--- a/libs/surfaceflinger/Barrier.h
+++ b/libs/surfaceflinger/Barrier.h
@@ -29,10 +29,6 @@
     inline Barrier() : state(CLOSED) { }
     inline ~Barrier() { }
     void open() {
-        // gcc memory barrier, this makes sure all memory writes
-        // have been issued by gcc. On an SMP system we'd need a real
-        // h/w barrier.
-        asm volatile ("":::"memory");
         Mutex::Autolock _l(lock);
         state = OPENED;
         cv.broadcast();
diff --git a/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp b/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp
index af89e9a..51de1da 100644
--- a/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp
+++ b/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp
@@ -73,7 +73,7 @@
 DisplayHardware::DisplayHardware(
         const sp<SurfaceFlinger>& flinger,
         uint32_t dpy)
-    : DisplayHardwareBase(flinger, dpy)
+    : DisplayHardwareBase(flinger, dpy), mFlags(0)
 {
     init(dpy);
 }
diff --git a/libs/surfaceflinger/Layer.cpp b/libs/surfaceflinger/Layer.cpp
index 1fe997d..621b7e3 100644
--- a/libs/surfaceflinger/Layer.cpp
+++ b/libs/surfaceflinger/Layer.cpp
@@ -60,7 +60,7 @@
     // no OpenGL operation is possible here, since we might not be
     // in the OpenGL thread.
     lcblk = new SharedBufferServer(
-            client->ctrlblk, i, mBufferManager.getBufferCount(),
+            client->ctrlblk, i, mBufferManager.getDefaultBufferCount(),
             getIdentity());
 
    mBufferManager.setActiveBufferIndex( lcblk->getFrontBuffer() );
@@ -68,7 +68,10 @@
 
 Layer::~Layer()
 {
-    destroy();
+    // FIXME: must be called from the main UI thread
+    EGLDisplay dpy(mFlinger->graphicPlane(0).getEGLDisplay());
+    mBufferManager.destroy(dpy);
+
     // the actual buffers will be destroyed here
     delete lcblk;
 }
@@ -81,17 +84,6 @@
     lcblk->setStatus(NO_INIT);
 }
 
-void Layer::destroy()
-{
-    EGLDisplay dpy(mFlinger->graphicPlane(0).getEGLDisplay());
-    mBufferManager.destroy(dpy);
-
-    mSurface.clear();
-
-    Mutex::Autolock _l(mLock);
-    mWidth = mHeight = 0;
-}
-
 sp<LayerBaseClient::Surface> Layer::createSurface() const
 {
     return mSurface;
@@ -99,9 +91,17 @@
 
 status_t Layer::ditch()
 {
+    // NOTE: Called from the main UI thread
+
     // the layer is not on screen anymore. free as much resources as possible
     mFreezeLock.clear();
-    destroy();
+
+    EGLDisplay dpy(mFlinger->graphicPlane(0).getEGLDisplay());
+    mBufferManager.destroy(dpy);
+    mSurface.clear();
+
+    Mutex::Autolock _l(mLock);
+    mWidth = mHeight = 0;
     return NO_ERROR;
 }
 
@@ -211,7 +211,7 @@
 
 status_t Layer::setBufferCount(int bufferCount)
 {
-    // this ensures our client doesn't go away while we're accessing
+    // Ensures our client doesn't go away while we're accessing
     // the shared area.
     sp<Client> ourClient(client.promote());
     if (ourClient == 0) {
@@ -219,15 +219,10 @@
         return DEAD_OBJECT;
     }
 
-    status_t err;
-
-    // FIXME: resize() below is NOT thread-safe, we need to synchronize
-    // the users of lcblk in our process (ie: retire), and we assume the
-    // client is not mucking with the SharedStack, which is only enforced
-    // by construction, therefore we need to protect ourselves against
-    // buggy and malicious client (as always)
-
-    err = lcblk->resize(bufferCount);
+    // NOTE: lcblk->resize() is protected by an internal lock
+    status_t err = lcblk->resize(bufferCount);
+    if (err == NO_ERROR)
+        mBufferManager.resize(bufferCount);
 
     return err;
 }
@@ -248,7 +243,7 @@
      * This is called from the client's Surface::dequeue(). This can happen
      * at any time, especially while we're in the middle of using the
      * buffer 'index' as our front buffer.
-     * 
+     *
      * Make sure the buffer we're resizing is not the front buffer and has been
      * dequeued. Once this condition is asserted, we are guaranteed that this
      * buffer cannot become the front buffer under our feet, since we're called
@@ -544,12 +539,20 @@
 // ---------------------------------------------------------------------------
 
 Layer::BufferManager::BufferManager(TextureManager& tm)
-    : mTextureManager(tm), mActiveBuffer(0), mFailover(false)
+    : mNumBuffers(NUM_BUFFERS), mTextureManager(tm),
+      mActiveBuffer(0), mFailover(false)
 {
 }
 
-size_t Layer::BufferManager::getBufferCount() const {
-    return NUM_BUFFERS;
+Layer::BufferManager::~BufferManager()
+{
+}
+
+status_t Layer::BufferManager::resize(size_t size)
+{
+    Mutex::Autolock _l(mLock);
+    mNumBuffers = size;
+    return NO_ERROR;
 }
 
 // only for debugging
@@ -568,51 +571,55 @@
 }
 
 Texture Layer::BufferManager::getActiveTexture() const {
-    return mFailover ? mFailoverTexture : mBufferData[mActiveBuffer].texture;
+    Texture res;
+    if (mFailover) {
+        res = mFailoverTexture;
+    } else {
+        static_cast<Image&>(res) = mBufferData[mActiveBuffer].texture;
+    }
+    return res;
 }
 
 sp<GraphicBuffer> Layer::BufferManager::getActiveBuffer() const {
+    const size_t activeBuffer = mActiveBuffer;
+    BufferData const * const buffers = mBufferData;
     Mutex::Autolock _l(mLock);
-    return mBufferData[mActiveBuffer].buffer;
+    return buffers[activeBuffer].buffer;
 }
 
 sp<GraphicBuffer> Layer::BufferManager::detachBuffer(size_t index)
 {
+    BufferData* const buffers = mBufferData;
     sp<GraphicBuffer> buffer;
     Mutex::Autolock _l(mLock);
-    buffer = mBufferData[index].buffer;
-    mBufferData[index].buffer = 0;
+    buffer = buffers[index].buffer;
+    buffers[index].buffer = 0;
     return buffer;
 }
 
 status_t Layer::BufferManager::attachBuffer(size_t index,
         const sp<GraphicBuffer>& buffer)
 {
+    BufferData* const buffers = mBufferData;
     Mutex::Autolock _l(mLock);
-    mBufferData[index].buffer = buffer;
-    mBufferData[index].texture.dirty = true;
-    return NO_ERROR;
-}
-
-status_t Layer::BufferManager::destroyTexture(Texture* tex, EGLDisplay dpy)
-{
-    if (tex->name != -1U) {
-        glDeleteTextures(1, &tex->name);
-        tex->name = -1U;
-    }
-    if (tex->image != EGL_NO_IMAGE_KHR) {
-        eglDestroyImageKHR(dpy, tex->image);
-        tex->image = EGL_NO_IMAGE_KHR;
-    }
+    buffers[index].buffer = buffer;
+    buffers[index].texture.dirty = true;
     return NO_ERROR;
 }
 
 status_t Layer::BufferManager::destroy(EGLDisplay dpy)
 {
-    Mutex::Autolock _l(mLock);
-    for (size_t i=0 ; i<NUM_BUFFERS ; i++) {
-        destroyTexture(&mBufferData[i].texture, dpy);
-        mBufferData[i].buffer = 0;
+    BufferData* const buffers = mBufferData;
+    size_t num;
+    { // scope for the lock
+        Mutex::Autolock _l(mLock);
+        num = mNumBuffers;
+        for (size_t i=0 ; i<num ; i++) {
+            buffers[i].buffer = 0;
+        }
+    }
+    for (size_t i=0 ; i<num ; i++) {
+        destroyTexture(&buffers[i].texture, dpy);
     }
     destroyTexture(&mFailoverTexture, dpy);
     return NO_ERROR;
@@ -622,7 +629,7 @@
         const sp<GraphicBuffer>& buffer)
 {
     size_t index = mActiveBuffer;
-    Texture& texture(mBufferData[index].texture);
+    Image& texture(mBufferData[index].texture);
     status_t err = mTextureManager.initEglImage(&texture, dpy, buffer);
     // if EGLImage fails, we switch to regular texture mode, and we
     // free all resources associated with using EGLImages.
@@ -631,7 +638,8 @@
         destroyTexture(&mFailoverTexture, dpy);
     } else {
         mFailover = true;
-        for (size_t i=0 ; i<NUM_BUFFERS ; i++) {
+        const size_t num = mNumBuffers;
+        for (size_t i=0 ; i<num ; i++) {
             destroyTexture(&mBufferData[i].texture, dpy);
         }
     }
@@ -644,6 +652,19 @@
     return mTextureManager.loadTexture(&mFailoverTexture, dirty, t);
 }
 
+status_t Layer::BufferManager::destroyTexture(Image* tex, EGLDisplay dpy)
+{
+    if (tex->name != -1U) {
+        glDeleteTextures(1, &tex->name);
+        tex->name = -1U;
+    }
+    if (tex->image != EGL_NO_IMAGE_KHR) {
+        eglDestroyImageKHR(dpy, tex->image);
+        tex->image = EGL_NO_IMAGE_KHR;
+    }
+    return NO_ERROR;
+}
+
 // ---------------------------------------------------------------------------
 
 Layer::SurfaceLayer::SurfaceLayer(const sp<SurfaceFlinger>& flinger,
@@ -661,6 +682,11 @@
     sp<GraphicBuffer> buffer;
     sp<Layer> owner(getOwner());
     if (owner != 0) {
+        /*
+         * requestBuffer() cannot be called from the main thread
+         * as it could cause a dead-lock, since it may have to wait
+         * on conditions updated my the main thread.
+         */
         buffer = owner->requestBuffer(index, usage);
     }
     return buffer;
@@ -671,6 +697,11 @@
     status_t err = DEAD_OBJECT;
     sp<Layer> owner(getOwner());
     if (owner != 0) {
+        /*
+         * setBufferCount() cannot be called from the main thread
+         * as it could cause a dead-lock, since it may have to wait
+         * on conditions updated my the main thread.
+         */
         err = owner->setBufferCount(bufferCount);
     }
     return err;
diff --git a/libs/surfaceflinger/Layer.h b/libs/surfaceflinger/Layer.h
index 80fbd6a..247748b 100644
--- a/libs/surfaceflinger/Layer.h
+++ b/libs/surfaceflinger/Layer.h
@@ -90,7 +90,6 @@
 
     sp<GraphicBuffer> requestBuffer(int index, int usage);
     status_t setBufferCount(int bufferCount);
-    void destroy();
 
     class SurfaceLayer : public LayerBaseClient::Surface {
     public:
@@ -120,25 +119,32 @@
                 static const size_t NUM_BUFFERS = 2;
                 struct BufferData {
                     sp<GraphicBuffer>   buffer;
-                    Texture             texture;
+                    Image               texture;
                 };
+                // this lock protect mBufferData[].buffer but since there
+                // is very little contention, we have only one like for
+                // the whole array, we also use it to protect mNumBuffers.
                 mutable Mutex mLock;
-                BufferData          mBufferData[NUM_BUFFERS];
+                BufferData          mBufferData[SharedBufferStack::NUM_BUFFER_MAX];
+                size_t              mNumBuffers;
                 Texture             mFailoverTexture;
                 TextureManager&     mTextureManager;
                 ssize_t             mActiveBuffer;
                 bool                mFailover;
-                static status_t destroyTexture(Texture* tex, EGLDisplay dpy);
+                static status_t destroyTexture(Image* tex, EGLDisplay dpy);
 
             public:
+                static size_t getDefaultBufferCount() { return NUM_BUFFERS; }
                 BufferManager(TextureManager& tm);
-
-                size_t getBufferCount() const;
+                ~BufferManager();
 
                 // detach/attach buffer from/to given index
                 sp<GraphicBuffer> detachBuffer(size_t index);
                 status_t attachBuffer(size_t index, const sp<GraphicBuffer>& buffer);
 
+                // resize the number of active buffers
+                status_t resize(size_t size);
+
                 // ----------------------------------------------
                 // must be called from GL thread
 
@@ -170,6 +176,8 @@
             TextureManager mTextureManager;
             BufferManager mBufferManager;
 
+            // this lock protects mWidth and mHeight which are accessed from
+            // the main thread and requestBuffer's binder transaction thread.
             mutable Mutex mLock;
             uint32_t    mWidth;
             uint32_t    mHeight;
diff --git a/libs/surfaceflinger/LayerBlur.cpp b/libs/surfaceflinger/LayerBlur.cpp
index 2d77876..09c90e8 100644
--- a/libs/surfaceflinger/LayerBlur.cpp
+++ b/libs/surfaceflinger/LayerBlur.cpp
@@ -95,7 +95,9 @@
                     mCacheDirty = false;
                 } else {
                     if (!mAutoRefreshPending) {
-                        mFlinger->signalDelayedEvent(ms2ns(500));
+                        mFlinger->postMessageAsync(
+                                new MessageBase(MessageQueue::INVALIDATE),
+                                ms2ns(500));
                         mAutoRefreshPending = true;
                     }
                 }
diff --git a/libs/surfaceflinger/MessageQueue.cpp b/libs/surfaceflinger/MessageQueue.cpp
index b43d801..d668e88 100644
--- a/libs/surfaceflinger/MessageQueue.cpp
+++ b/libs/surfaceflinger/MessageQueue.cpp
@@ -60,9 +60,9 @@
 {
 }
 
-MessageList::value_type MessageQueue::waitMessage(nsecs_t timeout)
+sp<MessageBase> MessageQueue::waitMessage(nsecs_t timeout)
 {
-    MessageList::value_type result;
+    sp<MessageBase> result;
 
     bool again;
     do {
@@ -132,6 +132,7 @@
         if (again) {
             // the message has been processed. release our reference to it
             // without holding the lock.
+            result->notify();
             result = 0;
         }
         
@@ -141,7 +142,7 @@
 }
 
 status_t MessageQueue::postMessage(
-        const MessageList::value_type& message, nsecs_t relTime, uint32_t flags)
+        const sp<MessageBase>& message, nsecs_t relTime, uint32_t flags)
 {
     return queueMessage(message, relTime, flags);
 }
@@ -154,7 +155,7 @@
 }
 
 status_t MessageQueue::queueMessage(
-        const MessageList::value_type& message, nsecs_t relTime, uint32_t flags)
+        const sp<MessageBase>& message, nsecs_t relTime, uint32_t flags)
 {
     Mutex::Autolock _l(mLock);
     message->when = systemTime() + relTime;
@@ -167,13 +168,13 @@
     return NO_ERROR;
 }
 
-void MessageQueue::dump(const MessageList::value_type& message)
+void MessageQueue::dump(const sp<MessageBase>& message)
 {
     Mutex::Autolock _l(mLock);
     dumpLocked(message);
 }
 
-void MessageQueue::dumpLocked(const MessageList::value_type& message)
+void MessageQueue::dumpLocked(const sp<MessageBase>& message)
 {
     LIST::const_iterator cur(mMessages.begin());
     LIST::const_iterator end(mMessages.end());
diff --git a/libs/surfaceflinger/MessageQueue.h b/libs/surfaceflinger/MessageQueue.h
index dc8138d..890f809 100644
--- a/libs/surfaceflinger/MessageQueue.h
+++ b/libs/surfaceflinger/MessageQueue.h
@@ -25,6 +25,7 @@
 #include <utils/Timers.h>
 #include <utils/List.h>
 
+#include "Barrier.h"
 
 namespace android {
 
@@ -37,7 +38,6 @@
     List< sp<MessageBase> > mList;
     typedef List< sp<MessageBase> > LIST;
 public:
-    typedef sp<MessageBase> value_type;
     inline LIST::iterator begin()                { return mList.begin(); }
     inline LIST::const_iterator begin() const    { return mList.begin(); }
     inline LIST::iterator end()                  { return mList.end(); }
@@ -63,11 +63,19 @@
     
     // return true if message has a handler
     virtual bool handler() { return false; }
+
+    // waits for the handler to be processed
+    void wait() const { barrier.wait(); }
     
+    // releases all waiters. this is done automatically if
+    // handler returns true
+    void notify() const { barrier.open(); }
+
 protected:
     virtual ~MessageBase() { }
 
 private:
+    mutable Barrier barrier;
     friend class LightRefBase<MessageBase>;
 };
 
@@ -82,42 +90,33 @@
     typedef List< sp<MessageBase> > LIST;
 public:
 
-    // this is a work-around the multichar constant warning. A macro would
-    // work too, but would pollute the namespace.
-    template <int a, int b, int c, int d>
-    struct WHAT {
-        static const uint32_t Value = 
-            (uint32_t(a&0xff)<<24)|(uint32_t(b&0xff)<<16)|
-            (uint32_t(c&0xff)<<8)|uint32_t(d&0xff);
-    };
-    
     MessageQueue();
     ~MessageQueue();
 
     // pre-defined messages
     enum {
-        INVALIDATE = WHAT<'_','p','d','t'>::Value
+        INVALIDATE = '_upd'
     };
 
-    MessageList::value_type waitMessage(nsecs_t timeout = -1);
+    sp<MessageBase> waitMessage(nsecs_t timeout = -1);
     
-    status_t postMessage(const MessageList::value_type& message, 
+    status_t postMessage(const sp<MessageBase>& message,
             nsecs_t reltime=0, uint32_t flags = 0);
-        
+
     status_t invalidate();
     
-    void dump(const MessageList::value_type& message);
+    void dump(const sp<MessageBase>& message);
 
 private:
-    status_t queueMessage(const MessageList::value_type& message,
+    status_t queueMessage(const sp<MessageBase>& message,
             nsecs_t reltime, uint32_t flags);
-    void dumpLocked(const MessageList::value_type& message);
+    void dumpLocked(const sp<MessageBase>& message);
     
     Mutex           mLock;
     Condition       mCondition;
     MessageList     mMessages;
     bool            mInvalidate;
-    MessageList::value_type mInvalidateMessage;
+    sp<MessageBase> mInvalidateMessage;
 };
 
 // ---------------------------------------------------------------------------
diff --git a/libs/surfaceflinger/SurfaceFlinger.cpp b/libs/surfaceflinger/SurfaceFlinger.cpp
index 62d829b..5a6893f 100644
--- a/libs/surfaceflinger/SurfaceFlinger.cpp
+++ b/libs/surfaceflinger/SurfaceFlinger.cpp
@@ -426,7 +426,7 @@
             timeout = waitTime>0 ? waitTime : 0;
         }
 
-        MessageList::value_type msg = mEventQueue.waitMessage(timeout);
+        sp<MessageBase> msg = mEventQueue.waitMessage(timeout);
 
         // see if we timed out
         if (isFrozen()) {
@@ -461,9 +461,20 @@
     const_cast<SurfaceFlinger*>(this)->signalEvent();
 }
 
-void SurfaceFlinger::signalDelayedEvent(nsecs_t delay)
+status_t SurfaceFlinger::postMessageAsync(const sp<MessageBase>& msg,
+        nsecs_t reltime, uint32_t flags)
 {
-    mEventQueue.postMessage( new MessageBase(MessageQueue::INVALIDATE), delay);
+    return mEventQueue.postMessage(msg, reltime, flags);
+}
+
+status_t SurfaceFlinger::postMessageSync(const sp<MessageBase>& msg,
+        nsecs_t reltime, uint32_t flags)
+{
+    status_t res = mEventQueue.postMessage(msg, reltime, flags);
+    if (res == NO_ERROR) {
+        msg->wait();
+    }
+    return res;
 }
 
 // ----------------------------------------------------------------------------
@@ -1135,15 +1146,11 @@
     return android_atomic_and(~flags, &mTransactionFlags) & flags;
 }
 
-uint32_t SurfaceFlinger::setTransactionFlags(uint32_t flags, nsecs_t delay)
+uint32_t SurfaceFlinger::setTransactionFlags(uint32_t flags)
 {
     uint32_t old = android_atomic_or(flags, &mTransactionFlags);
     if ((old & flags)==0) { // wake the server up
-        if (delay > 0) {
-            signalDelayedEvent(delay);
-        } else {
-            signalEvent();
-        }
+        signalEvent();
     }
     return old;
 }
@@ -1245,7 +1252,7 @@
 
     //LOGD("createSurface for pid %d (%d x %d)", pid, w, h);
     int32_t id = client->generateId(pid);
-    if (uint32_t(id) >= NUM_LAYERS_MAX) {
+    if (uint32_t(id) >= SharedBufferStack::NUM_LAYERS_MAX) {
         LOGE("createSurface() failed, generateId = %d", id);
         return surfaceHandle;
     }
@@ -1399,7 +1406,7 @@
         }
     };
 
-    mEventQueue.postMessage( new MessageDestroySurface(this, layer) );
+    postMessageAsync( new MessageDestroySurface(this, layer) );
     return NO_ERROR;
 }
 
@@ -1672,7 +1679,7 @@
 int32_t Client::generateId(int pid)
 {
     const uint32_t i = clz( ~mBitmap );
-    if (i >= NUM_LAYERS_MAX) {
+    if (i >= SharedBufferStack::NUM_LAYERS_MAX) {
         return NO_MEMORY;
     }
     mPid = pid;
@@ -1699,7 +1706,8 @@
 }
 
 bool Client::isValid(int32_t i) const {
-    return (uint32_t(i)<NUM_LAYERS_MAX) && (mBitmap & (1<<(31-i)));
+    return (uint32_t(i)<SharedBufferStack::NUM_LAYERS_MAX) &&
+            (mBitmap & (1<<(31-i)));
 }
 
 sp<LayerBaseClient> Client::getLayerUser(int32_t i) const {
diff --git a/libs/surfaceflinger/SurfaceFlinger.h b/libs/surfaceflinger/SurfaceFlinger.h
index 9c8de51..2558324 100644
--- a/libs/surfaceflinger/SurfaceFlinger.h
+++ b/libs/surfaceflinger/SurfaceFlinger.h
@@ -255,8 +255,6 @@
 public:     // hack to work around gcc 4.0.3 bug
             void        signalEvent();
 private:
-            void        signalDelayedEvent(nsecs_t delay);
-
             void        handleConsoleEvents();
             void        handleTransaction(uint32_t transactionFlags);
             void        handleTransactionLocked(
@@ -286,7 +284,7 @@
             void        free_resources_l();
 
             uint32_t    getTransactionFlags(uint32_t flags);
-            uint32_t    setTransactionFlags(uint32_t flags, nsecs_t delay = 0);
+            uint32_t    setTransactionFlags(uint32_t flags);
             void        commitTransaction();
 
 
@@ -310,7 +308,12 @@
            
 
     mutable     MessageQueue    mEventQueue;
-    
+
+    status_t postMessageAsync(const sp<MessageBase>& msg,
+            nsecs_t reltime=0, uint32_t flags = 0);
+
+    status_t postMessageSync(const sp<MessageBase>& msg,
+            nsecs_t reltime=0, uint32_t flags = 0);
                 
                 
                 // access must be protected by mStateLock
diff --git a/libs/surfaceflinger/TextureManager.cpp b/libs/surfaceflinger/TextureManager.cpp
index e5d5302..ee2159b 100644
--- a/libs/surfaceflinger/TextureManager.cpp
+++ b/libs/surfaceflinger/TextureManager.cpp
@@ -68,7 +68,7 @@
     return false;
 }
 
-status_t TextureManager::initEglImage(Texture* texture,
+status_t TextureManager::initEglImage(Image* texture,
         EGLDisplay dpy, const sp<GraphicBuffer>& buffer)
 {
     status_t err = NO_ERROR;
@@ -108,7 +108,6 @@
             err = INVALID_OPERATION;
         } else {
             // Everything went okay!
-            texture->NPOTAdjust = false;
             texture->dirty  = false;
             texture->width  = clientBuf->width;
             texture->height = clientBuf->height;
diff --git a/libs/surfaceflinger/TextureManager.h b/libs/surfaceflinger/TextureManager.h
index 90cb62b..d0acfe9 100644
--- a/libs/surfaceflinger/TextureManager.h
+++ b/libs/surfaceflinger/TextureManager.h
@@ -36,21 +36,24 @@
 
 // ---------------------------------------------------------------------------
 
-struct Texture {
-    Texture() : name(-1U), width(0), height(0),
-        image(EGL_NO_IMAGE_KHR), transform(0),
-        NPOTAdjust(false), dirty(true) { }
+struct Image {
+    Image() : name(-1U), image(EGL_NO_IMAGE_KHR), width(0), height(0),
+        transform(0), dirty(true) { }
     GLuint        name;
+    EGLImageKHR   image;
     GLuint        width;
     GLuint        height;
+    uint32_t      transform;
+    bool          dirty;
+};
+
+struct Texture : public Image {
+    Texture() : Image(), NPOTAdjust(false)  { }
     GLuint        potWidth;
     GLuint        potHeight;
     GLfloat       wScale;
     GLfloat       hScale;
-    EGLImageKHR   image;
-    uint32_t      transform;
     bool          NPOTAdjust;
-    bool          dirty;
 };
 
 // ---------------------------------------------------------------------------
@@ -68,7 +71,7 @@
             const Region& dirty, const GGLSurface& t);
 
     // make active buffer an EGLImage if needed
-    status_t initEglImage(Texture* texture,
+    status_t initEglImage(Image* texture,
             EGLDisplay dpy, const sp<GraphicBuffer>& buffer);
 };
 
diff --git a/libs/surfaceflinger_client/SharedBufferStack.cpp b/libs/surfaceflinger_client/SharedBufferStack.cpp
index 4a98026..e2e1591 100644
--- a/libs/surfaceflinger_client/SharedBufferStack.cpp
+++ b/libs/surfaceflinger_client/SharedBufferStack.cpp
@@ -44,7 +44,7 @@
 
 // these functions are used by the clients
 status_t SharedClient::validate(size_t i) const {
-    if (uint32_t(i) >= uint32_t(NUM_LAYERS_MAX))
+    if (uint32_t(i) >= uint32_t(SharedBufferStack::NUM_LAYERS_MAX))
         return BAD_INDEX;
     return surfaces[i].status;
 }
@@ -144,10 +144,10 @@
 // ----------------------------------------------------------------------------
 
 SharedBufferBase::SharedBufferBase(SharedClient* sharedClient,
-        int surface, int num, int32_t identity)
+        int surface, int32_t identity)
     : mSharedClient(sharedClient), 
       mSharedStack(sharedClient->surfaces + surface),
-      mNumBuffers(num), mIdentity(identity)
+      mIdentity(identity)
 {
 }
 
@@ -179,22 +179,16 @@
     char buffer[SIZE];
     String8 result;
     SharedBufferStack& stack( *mSharedStack );
-    int tail = computeTail();
     snprintf(buffer, SIZE, 
-            "%s[ head=%2d, available=%2d, queued=%2d, tail=%2d ] "
-            "reallocMask=%08x, inUse=%2d, identity=%d, status=%d\n",
-            prefix, stack.head, stack.available, stack.queued, tail,
+            "%s[ head=%2d, available=%2d, queued=%2d ] "
+            "reallocMask=%08x, inUse=%2d, identity=%d, status=%d",
+            prefix, stack.head, stack.available, stack.queued,
             stack.reallocMask, stack.inUse, stack.identity, stack.status);
     result.append(buffer);
+    result.append("\n");
     return result;
 }
 
-int32_t SharedBufferBase::computeTail() const
-{
-    SharedBufferStack& stack( *mSharedStack );
-    return (mNumBuffers + stack.head - stack.available + 1) % mNumBuffers;
-}
-
 status_t SharedBufferBase::waitForCondition(const ConditionBase& condition)
 {
     const SharedBufferStack& stack( *mSharedStack );
@@ -258,7 +252,7 @@
 }
 bool SharedBufferServer::ReallocateCondition::operator()() const {
     int32_t head = stack.head;
-    if (uint32_t(head) >= NUM_BUFFER_MAX) {
+    if (uint32_t(head) >= SharedBufferStack::NUM_BUFFER_MAX) {
         // if stack.head is messed up, we cannot allow the server to
         // crash (since stack.head is mapped on the client side)
         stack.status = BAD_VALUE;
@@ -306,7 +300,7 @@
 }
 ssize_t SharedBufferServer::RetireUpdate::operator()() {
     int32_t head = stack.head;
-    if (uint32_t(head) >= NUM_BUFFER_MAX)
+    if (uint32_t(head) >= SharedBufferStack::NUM_BUFFER_MAX)
         return BAD_VALUE;
 
     // Preventively lock the current buffer before updating queued.
@@ -323,6 +317,7 @@
     
     // lock the buffer before advancing head, which automatically unlocks
     // the buffer we preventively locked upon entering this function
+
     head = (head + 1) % numBuffers;
     android_atomic_write(stack.index[head], &stack.inUse);
 
@@ -348,14 +343,20 @@
 
 SharedBufferClient::SharedBufferClient(SharedClient* sharedClient,
         int surface, int num, int32_t identity)
-    : SharedBufferBase(sharedClient, surface, num, identity),
-      tail(0), undoDequeueTail(0)
+    : SharedBufferBase(sharedClient, surface, identity),
+      mNumBuffers(num), tail(0), undoDequeueTail(0)
 {
     SharedBufferStack& stack( *mSharedStack );
     tail = computeTail();
     queued_head = stack.head;
 }
 
+int32_t SharedBufferClient::computeTail() const
+{
+    SharedBufferStack& stack( *mSharedStack );
+    return (mNumBuffers + stack.head - stack.available + 1) % mNumBuffers;
+}
+
 ssize_t SharedBufferClient::dequeue()
 {
     SharedBufferStack& stack( *mSharedStack );
@@ -364,7 +365,9 @@
         LOGW("dequeue: tail=%d, head=%d, avail=%d, queued=%d",
                 tail, stack.head, stack.available, stack.queued);
     }
-        
+
+    RWLock::AutoRLock _rd(mLock);
+
     const nsecs_t dequeueTime = systemTime(SYSTEM_TIME_THREAD);
 
     //LOGD("[%d] about to dequeue a buffer",
@@ -394,6 +397,8 @@
 
 status_t SharedBufferClient::undoDequeue(int buf)
 {
+    RWLock::AutoRLock _rd(mLock);
+
     // TODO: we can only undo the previous dequeue, we should
     // enforce that in the api
     UndoDequeueUpdate update(this);
@@ -406,6 +411,8 @@
 
 status_t SharedBufferClient::lock(int buf)
 {
+    RWLock::AutoRLock _rd(mLock);
+
     SharedBufferStack& stack( *mSharedStack );
     LockCondition condition(this, buf);
     status_t err = waitForCondition(condition);
@@ -414,9 +421,11 @@
 
 status_t SharedBufferClient::queue(int buf)
 {
+    RWLock::AutoRLock _rd(mLock);
+
     SharedBufferStack& stack( *mSharedStack );
 
-    queued_head = ((queued_head+1 >= mNumBuffers) ? 0 : queued_head+1);
+    queued_head = (queued_head + 1) % mNumBuffers;
     stack.index[queued_head] = buf;
 
     QueueUpdate update(this);
@@ -447,19 +456,32 @@
     return stack.setDirtyRegion(buf, reg);
 }
 
-status_t SharedBufferClient::setBufferCount(int bufferCount)
+status_t SharedBufferClient::setBufferCount(
+        int bufferCount, const SetBufferCountCallback& ipc)
 {
-    if (uint32_t(bufferCount) >= NUM_BUFFER_MAX)
+    SharedBufferStack& stack( *mSharedStack );
+    if (uint32_t(bufferCount) >= SharedBufferStack::NUM_BUFFER_MAX)
         return BAD_VALUE;
-    mNumBuffers = bufferCount;
-    return NO_ERROR;
+
+    if (uint32_t(bufferCount) < SharedBufferStack::NUM_BUFFER_MIN)
+        return BAD_VALUE;
+
+    RWLock::AutoWLock _wr(mLock);
+
+    status_t err = ipc(bufferCount);
+    if (err == NO_ERROR) {
+        mNumBuffers = bufferCount;
+        queued_head = (stack.head + stack.queued) % mNumBuffers;
+    }
+    return err;
 }
 
 // ----------------------------------------------------------------------------
 
 SharedBufferServer::SharedBufferServer(SharedClient* sharedClient,
         int surface, int num, int32_t identity)
-    : SharedBufferBase(sharedClient, surface, num, identity)
+    : SharedBufferBase(sharedClient, surface, identity),
+      mNumBuffers(num)
 {
     mSharedStack->init(identity);
     mSharedStack->head = num-1;
@@ -475,10 +497,12 @@
 
 ssize_t SharedBufferServer::retireAndLock()
 {
+    RWLock::AutoRLock _l(mLock);
+
     RetireUpdate update(this, mNumBuffers);
     ssize_t buf = updateCondition( update );
     if (buf >= 0) {
-        if (uint32_t(buf) >= NUM_BUFFER_MAX)
+        if (uint32_t(buf) >= SharedBufferStack::NUM_BUFFER_MAX)
             return BAD_VALUE;
         SharedBufferStack& stack( *mSharedStack );
         buf = stack.index[buf];
@@ -505,6 +529,8 @@
 
 status_t SharedBufferServer::reallocate()
 {
+    RWLock::AutoRLock _l(mLock);
+
     SharedBufferStack& stack( *mSharedStack );
     uint32_t mask = (1<<mNumBuffers)-1;
     android_atomic_or(mask, &stack.reallocMask); 
@@ -519,6 +545,13 @@
 
 status_t SharedBufferServer::assertReallocate(int buf)
 {
+    /*
+     * NOTE: it's safe to hold mLock for read while waiting for
+     * the ReallocateCondition because that condition is not updated
+     * by the thread that holds mLock for write.
+     */
+    RWLock::AutoRLock _l(mLock);
+
     // TODO: need to validate "buf"
     ReallocateCondition condition(this, buf);
     status_t err = waitForCondition(condition);
@@ -531,9 +564,7 @@
     return stack.getDirtyRegion(buf);
 }
 
-
 /*
- *
  * NOTE: this is not thread-safe on the server-side, meaning
  * 'head' cannot move during this operation. The client-side
  * can safely operate an usual.
@@ -541,9 +572,11 @@
  */
 status_t SharedBufferServer::resize(int newNumBuffers)
 {
-    if (uint32_t(newNumBuffers) >= NUM_BUFFER_MAX)
+    if (uint32_t(newNumBuffers) >= SharedBufferStack::NUM_BUFFER_MAX)
         return BAD_VALUE;
 
+    RWLock::AutoWLock _l(mLock);
+
     // for now we're not supporting shrinking
     const int numBuffers = mNumBuffers;
     if (newNumBuffers < numBuffers)
@@ -554,12 +587,13 @@
 
     // read the head, make sure it's valid
     int32_t head = stack.head;
-    if (uint32_t(head) >= NUM_BUFFER_MAX)
+    if (uint32_t(head) >= SharedBufferStack::NUM_BUFFER_MAX)
         return BAD_VALUE;
 
     int base = numBuffers;
     int32_t avail = stack.available;
     int tail = head - avail + 1;
+
     if (tail >= 0) {
         int8_t* const index = const_cast<int8_t*>(stack.index);
         const int nb = numBuffers - head;
@@ -573,8 +607,9 @@
     // fill the new free space with unused buffers
     BufferList::const_iterator curr(mBufferList.free_begin());
     for (int i=0 ; i<extra ; i++) {
-        stack.index[base+i] = *curr++;
-        mBufferList.add(stack.index[base+i]);
+        stack.index[base+i] = *curr;
+        mBufferList.add(*curr);
+        ++curr;
     }
 
     mNumBuffers = newNumBuffers;
diff --git a/libs/surfaceflinger_client/Surface.cpp b/libs/surfaceflinger_client/Surface.cpp
index afbeafb..5f42af0 100644
--- a/libs/surfaceflinger_client/Surface.cpp
+++ b/libs/surfaceflinger_client/Surface.cpp
@@ -584,6 +584,9 @@
     case NATIVE_WINDOW_SET_CROP:
         res = dispatch_crop( args );
         break;
+    case NATIVE_WINDOW_SET_BUFFER_COUNT:
+        res = dispatch_set_buffer_count( args );
+        break;
     default:
         res = NAME_NOT_FOUND;
         break;
@@ -607,6 +610,10 @@
     android_native_rect_t const* rect = va_arg(args, android_native_rect_t*);
     return crop( reinterpret_cast<Rect const*>(rect) );
 }
+int Surface::dispatch_set_buffer_count(va_list args) {
+    size_t bufferCount = va_arg(args, size_t);
+    return setBufferCount(bufferCount);
+}
 
 
 void Surface::setUsage(uint32_t reqUsage)
@@ -678,19 +685,18 @@
     sp<ISurface> s(mSurface);
     if (s == 0) return NO_INIT;
 
-    // FIXME: this needs to be synchronized dequeue/queue
+    class SetBufferCountIPC : public SharedBufferClient::SetBufferCountCallback {
+        sp<ISurface> surface;
+        virtual status_t operator()(int bufferCount) const {
+            return surface->setBufferCount(bufferCount);
+        }
+    public:
+        SetBufferCountIPC(const sp<ISurface>& surface) : surface(surface) { }
+    } ipc(s);
 
-    status_t err = s->setBufferCount(bufferCount);
+    status_t err = mSharedBufferClient->setBufferCount(bufferCount, ipc);
     LOGE_IF(err, "ISurface::setBufferCount(%d) returned %s",
             bufferCount, strerror(-err));
-    if (err == NO_ERROR) {
-        err = mSharedBufferClient->getStatus();
-        LOGE_IF(err,  "Surface (identity=%d) state = %d", mIdentity, err);
-        if (!err) {
-            // update our local copy of the buffer count
-            mSharedBufferClient->setBufferCount(bufferCount);
-        }
-    }
     return err;
 }
 
@@ -857,7 +863,7 @@
                 currentBuffer->setIndex(index);
             }
         } else {
-            err = err<0 ? err : NO_MEMORY;
+            err = err<0 ? err : status_t(NO_MEMORY);
         }
     }
     return err; 
diff --git a/libs/surfaceflinger_client/SurfaceComposerClient.cpp b/libs/surfaceflinger_client/SurfaceComposerClient.cpp
index 3117495..9ac73d2 100644
--- a/libs/surfaceflinger_client/SurfaceComposerClient.cpp
+++ b/libs/surfaceflinger_client/SurfaceComposerClient.cpp
@@ -58,7 +58,7 @@
 // Must not be holding SurfaceComposerClient::mLock when acquiring gLock here.
 static Mutex                                                gLock;
 static sp<ISurfaceComposer>                                 gSurfaceManager;
-static DefaultKeyedVector< sp<IBinder>, sp<SurfaceComposerClient> > gActiveConnections;
+static DefaultKeyedVector< sp<IBinder>, wp<SurfaceComposerClient> > gActiveConnections;
 static SortedVector<sp<SurfaceComposerClient> >             gOpenTransactions;
 static sp<IMemoryHeap>                                      gServerCblkMemory;
 static volatile surface_flinger_cblk_t*                     gServerCblk;
@@ -195,7 +195,7 @@
 
     { // scope for lock
         Mutex::Autolock _l(gLock);
-        client = gActiveConnections.valueFor(conn);
+        client = gActiveConnections.valueFor(conn).promote();
     }
 
     if (client == 0) {
@@ -250,7 +250,7 @@
 status_t SurfaceComposerClient::getDisplayInfo(
         DisplayID dpy, DisplayInfo* info)
 {
-    if (uint32_t(dpy)>=NUM_DISPLAY_MAX)
+    if (uint32_t(dpy)>=SharedBufferStack::NUM_DISPLAY_MAX)
         return BAD_VALUE;
 
     volatile surface_flinger_cblk_t const * cblk = get_cblk();
@@ -268,7 +268,7 @@
 
 ssize_t SurfaceComposerClient::getDisplayWidth(DisplayID dpy)
 {
-    if (uint32_t(dpy)>=NUM_DISPLAY_MAX)
+    if (uint32_t(dpy)>=SharedBufferStack::NUM_DISPLAY_MAX)
         return BAD_VALUE;
     volatile surface_flinger_cblk_t const * cblk = get_cblk();
     volatile display_cblk_t const * dcblk = cblk->displays + dpy;
@@ -277,7 +277,7 @@
 
 ssize_t SurfaceComposerClient::getDisplayHeight(DisplayID dpy)
 {
-    if (uint32_t(dpy)>=NUM_DISPLAY_MAX)
+    if (uint32_t(dpy)>=SharedBufferStack::NUM_DISPLAY_MAX)
         return BAD_VALUE;
     volatile surface_flinger_cblk_t const * cblk = get_cblk();
     volatile display_cblk_t const * dcblk = cblk->displays + dpy;
@@ -286,7 +286,7 @@
 
 ssize_t SurfaceComposerClient::getDisplayOrientation(DisplayID dpy)
 {
-    if (uint32_t(dpy)>=NUM_DISPLAY_MAX)
+    if (uint32_t(dpy)>=SharedBufferStack::NUM_DISPLAY_MAX)
         return BAD_VALUE;
     volatile surface_flinger_cblk_t const * cblk = get_cblk();
     volatile display_cblk_t const * dcblk = cblk->displays + dpy;
@@ -345,7 +345,7 @@
         sp<ISurface> surface = mClient->createSurface(&data, pid, name,
                 display, w, h, format, flags);
         if (surface != 0) {
-            if (uint32_t(data.token) < NUM_LAYERS_MAX) {
+            if (uint32_t(data.token) < SharedBufferStack::NUM_LAYERS_MAX) {
                 result = new SurfaceControl(this, surface, data, w, h, format, flags);
             }
         }
@@ -383,8 +383,8 @@
     const size_t N = gActiveConnections.size();
     VERBOSE("openGlobalTransaction (%ld clients)", N);
     for (size_t i=0; i<N; i++) {
-        sp<SurfaceComposerClient> client(gActiveConnections.valueAt(i));
-        if (gOpenTransactions.indexOf(client) < 0) {
+        sp<SurfaceComposerClient> client(gActiveConnections.valueAt(i).promote());
+        if (client != 0 && gOpenTransactions.indexOf(client) < 0) {
             if (client->openTransaction() == NO_ERROR) {
                 if (gOpenTransactions.add(client) < 0) {
                     // Ooops!
diff --git a/libs/surfaceflinger_client/tests/SharedBufferStack/SharedBufferStackTest.cpp b/libs/surfaceflinger_client/tests/SharedBufferStack/SharedBufferStackTest.cpp
index 6732580..f409f48 100644
--- a/libs/surfaceflinger_client/tests/SharedBufferStack/SharedBufferStackTest.cpp
+++ b/libs/surfaceflinger_client/tests/SharedBufferStack/SharedBufferStackTest.cpp
@@ -24,6 +24,51 @@
 
 using namespace android;
 
+void log(const char* prefix, int *b, size_t num);
+void test0(SharedBufferServer& s, SharedBufferClient& c, size_t num, int* list);
+
+// ----------------------------------------------------------------------------
+
+int main(int argc, char** argv)
+{
+    SharedClient client;
+    SharedBufferServer s(&client, 0, 4, 0);
+    SharedBufferClient c(&client, 0, 4, 0);
+
+    printf("basic test 0\n");
+    int list0[4] = {0, 1, 2, 3};
+    test0(s, c, 4, list0);
+
+    printf("basic test 1\n");
+    int list1[4] = {2, 1, 0, 3};
+    test0(s, c, 4, list1);
+
+    int b = c.dequeue();
+    c.lock(b);
+    c.queue(b);
+    s.retireAndLock();
+
+    printf("basic test 2\n");
+    int list2[4] = {1, 2, 3, 0};
+    test0(s, c, 4, list2);
+
+
+    printf("resize test\n");
+    class SetBufferCountIPC : public SharedBufferClient::SetBufferCountCallback {
+        SharedBufferServer& s;
+        virtual status_t operator()(int bufferCount) const {
+            return s.resize(bufferCount);
+        }
+    public:
+        SetBufferCountIPC(SharedBufferServer& s) : s(s) { }
+    } resize(s);
+
+    c.setBufferCount(6, resize);
+    int list3[6] = {3, 2, 1, 4, 5, 0};
+    test0(s, c, 6, list3);
+
+    return 0;
+}
 
 void log(const char* prefix, int *b, size_t num)
 {
@@ -34,18 +79,20 @@
     printf("\n");
 }
 
-int main(int argc, char** argv)
+// ----------------------------------------------------------------------------
+
+void test0(
+        SharedBufferServer& s,
+        SharedBufferClient& c,
+        size_t num,
+        int* list)
 {
     status_t err;
-    const size_t num = 4;
-    SharedClient client;
-    SharedBufferServer s(&client, 0, num, 0);
-    SharedBufferClient c(&client, 0, num, 0);
     int b[num], u[num], r[num];
 
     for (size_t i=0 ; i<num ; i++) {
         b[i] = c.dequeue();
-        assert(b[i]==i);
+        assert(b[i]==list[i]);
     }
     log("DQ", b, num);
 
@@ -64,7 +111,7 @@
 
     for (size_t i=0 ; i<num-1 ; i++) {
         r[i] = s.retireAndLock();
-        assert(r[i]==i);
+        assert(r[i]==list[i]);
         err = s.unlock(r[i]);
         assert(err == 0);
     }
@@ -79,7 +126,7 @@
     log(" Q", b+num-1, 1);
 
     r[num-1] = s.retireAndLock();
-    assert(r[num-1]==num-1);
+    assert(r[num-1]==list[num-1]);
     err = s.unlock(r[num-1]);
     assert(err == 0);
     log("RT", r+num-1, 1);
@@ -89,7 +136,7 @@
 
     for (size_t i=0 ; i<num ; i++) {
         b[i] = c.dequeue();
-        assert(b[i]==i);
+        assert(b[i]==list[i]);
     }
     log("DQ", b, num);
 
@@ -102,7 +149,7 @@
     for (size_t i=0 ; i<num-1 ; i++) {
         u[i] = b[num-2-i];
     }
-    u[num-1] = num-1;
+    u[num-1] = b[num-1];
 
     for (size_t i=0 ; i<num-1 ; i++) {
         err = c.queue(u[i]);
@@ -127,7 +174,7 @@
     log(" Q", b+num-1, 1);
 
     r[num-1] = s.retireAndLock();
-    assert(r[num-1]==num-1);
+    assert(r[num-1]==list[num-1]);
     err = s.unlock(r[num-1]);
     assert(err == 0);
     log("RT", r+num-1, 1);
@@ -170,7 +217,7 @@
     log(" Q", u+num-1, 1);
 
     r[num-1] = s.retireAndLock();
-    assert(r[num-1]==num-1);
+    assert(r[num-1]==u[num-1]);
     err = s.unlock(r[num-1]);
     assert(err == 0);
     log("RT", r+num-1, 1);
@@ -224,10 +271,9 @@
     log(" Q", u+num-1, 1);
 
     r[num-1] = s.retireAndLock();
-    assert(r[num-1]==num-1);
+    assert(r[num-1]==u[num-1]);
     err = s.unlock(r[num-1]);
     assert(err == 0);
     log("RT", r+num-1, 1);
-
-    return 0;
+    printf("\n");
 }
diff --git a/opengl/libagl/egl.cpp b/opengl/libagl/egl.cpp
index b6e0aae..7cb01d0 100644
--- a/opengl/libagl/egl.cpp
+++ b/opengl/libagl/egl.cpp
@@ -1525,8 +1525,13 @@
     }
 
     if (ggl_unlikely(attrib_list==0)) {
-        *num_config = 0;
-        return EGL_TRUE;
+        /*
+         * A NULL attrib_list should be treated as though it was an empty
+         * one (terminated with EGL_NONE) as defined in
+         * section 3.4.1 "Querying Configurations" in the EGL specification.
+         */
+        static const EGLint dummy = EGL_NONE;
+        attrib_list = &dummy;
     }
 
     int numAttributes = 0;
diff --git a/opengl/libs/EGL/egl.cpp b/opengl/libs/EGL/egl.cpp
index e6cf792..ba09d08 100644
--- a/opengl/libs/EGL/egl.cpp
+++ b/opengl/libs/EGL/egl.cpp
@@ -843,10 +843,12 @@
     EGLint patch_index = -1;
     GLint attr;
     size_t size = 0;
-    while ((attr=attrib_list[size]) != EGL_NONE) {
-        if (attr == EGL_CONFIG_ID)
-            patch_index = size;
-        size += 2;
+    if (attrib_list) {
+        while ((attr=attrib_list[size]) != EGL_NONE) {
+            if (attr == EGL_CONFIG_ID)
+                patch_index = size;
+            size += 2;
+        }
     }
     if (patch_index >= 0) {
         size += 2; // we need copy the sentinel as well