am 5c9d9949: am 6ee412d5: Also dump system process threads halfway through the watchdog interval

Merge commit '5c9d99496dab7a5cfe7cd37df749075ec9b4421b' into kraken

* commit '5c9d99496dab7a5cfe7cd37df749075ec9b4421b':
  Also dump system process threads halfway through the watchdog interval
diff --git a/camera/libcameraservice/Android.mk b/camera/libcameraservice/Android.mk
index df5c166..a0d6ee1 100644
--- a/camera/libcameraservice/Android.mk
+++ b/camera/libcameraservice/Android.mk
@@ -1,18 +1,21 @@
 LOCAL_PATH:= $(call my-dir)
 
-#
-# Set USE_CAMERA_STUB for non-emulator and non-simulator builds, if you want
-# the camera service to use the fake camera.  For emulator or simulator builds,
-# we always use the fake camera.
+# Set USE_CAMERA_STUB if you don't want to use the hardware camera.
 
-ifeq ($(USE_CAMERA_STUB),)
-USE_CAMERA_STUB:=false
+# force these builds to use camera stub only
 ifneq ($(filter sooner generic sim,$(TARGET_DEVICE)),)
-USE_CAMERA_STUB:=true
-endif #libcamerastub
+  USE_CAMERA_STUB:=true
 endif
 
 ifeq ($(USE_CAMERA_STUB),true)
+  INCLUDE_CAMERA_STUB:=true
+  INCLUDE_CAMERA_HARDWARE:=false
+else
+  INCLUDE_CAMERA_STUB:=true  # set this to true temporarily for testing
+  INCLUDE_CAMERA_HARDWARE:=true
+endif
+
+ifeq ($(INCLUDE_CAMERA_STUB),true)
 #
 # libcamerastub
 #
@@ -32,7 +35,7 @@
 LOCAL_SHARED_LIBRARIES:= libui
 
 include $(BUILD_STATIC_LIBRARY)
-endif # USE_CAMERA_STUB
+endif # INCLUDE_CAMERA_STUB
 
 #
 # libcameraservice
@@ -54,18 +57,18 @@
 
 LOCAL_MODULE:= libcameraservice
 
-LOCAL_CFLAGS += -DLOG_TAG=\"CameraService\"
-
 ifeq ($(TARGET_SIMULATOR),true)
 LOCAL_CFLAGS += -DSINGLE_PROCESS
 endif
 
-ifeq ($(USE_CAMERA_STUB), true)
+ifeq ($(INCLUDE_CAMERA_STUB), true)
 LOCAL_STATIC_LIBRARIES += libcamerastub
-LOCAL_CFLAGS += -include CameraHardwareStub.h
-else
+LOCAL_CFLAGS += -DINCLUDE_CAMERA_STUB
+endif
+
+ifeq ($(INCLUDE_CAMERA_HARDWARE),true)
+LOCAL_CFLAGS += -DINCLUDE_CAMERA_HARDWARE
 LOCAL_SHARED_LIBRARIES += libcamera 
 endif
 
 include $(BUILD_SHARED_LIBRARY)
-
diff --git a/camera/libcameraservice/CameraHardwareStub.cpp b/camera/libcameraservice/CameraHardwareStub.cpp
index 8b66389..fda48e8 100644
--- a/camera/libcameraservice/CameraHardwareStub.cpp
+++ b/camera/libcameraservice/CameraHardwareStub.cpp
@@ -47,14 +47,14 @@
 {
     CameraParameters p;
 
-    p.set("preview-size-values","320x240");
+    p.set(CameraParameters::KEY_SUPPORTED_PREVIEW_SIZES, "320x240");
     p.setPreviewSize(320, 240);
     p.setPreviewFrameRate(15);
-    p.setPreviewFormat("yuv422sp");
+    p.setPreviewFormat(CameraParameters::PIXEL_FORMAT_YUV420SP);
 
-    p.set("picture-size-values", "320x240");
+    p.set(CameraParameters::KEY_SUPPORTED_PICTURE_SIZES, "320x240");
     p.setPictureSize(320, 240);
-    p.setPictureFormat("jpeg");
+    p.setPictureFormat(CameraParameters::PIXEL_FORMAT_JPEG);
 
     if (setParameters(p) != NO_ERROR) {
         LOGE("Failed to set default parameters?!");
@@ -66,14 +66,14 @@
     // Create raw heap.
     int picture_width, picture_height;
     mParameters.getPictureSize(&picture_width, &picture_height);
-    mRawHeap = new MemoryHeapBase(picture_width * 2 * picture_height);
+    mRawHeap = new MemoryHeapBase(picture_width * picture_height * 3 / 2);
 
     int preview_width, preview_height;
     mParameters.getPreviewSize(&preview_width, &preview_height);
     LOGD("initHeapLocked: preview size=%dx%d", preview_width, preview_height);
 
-    // Note that we enforce yuv422 in setParameters().
-    int how_big = preview_width * preview_height * 2;
+    // Note that we enforce yuv420sp in setParameters().
+    int how_big = preview_width * preview_height * 3 / 2;
 
     // If we are being reinitialized to the same size as before, no
     // work needs to be done.
@@ -99,7 +99,6 @@
 {
     delete mFakeCamera;
     mFakeCamera = 0; // paranoia
-    singleton.clear();
 }
 
 sp<IMemoryHeap> CameraHardwareStub::getPreviewHeap() const
@@ -175,7 +174,7 @@
 
         // Fill the current frame with the fake camera.
         uint8_t *frame = ((uint8_t *)base) + offset;
-        fakeCamera->getNextFrameAsYuv422(frame);
+        fakeCamera->getNextFrameAsYuv420(frame);
 
         //LOGV("previewThread: generated frame to buffer %d", mCurrentPreviewFrame);
 
@@ -288,9 +287,9 @@
         // In the meantime just make another fake camera picture.
         int w, h;
         mParameters.getPictureSize(&w, &h);
-        sp<MemoryBase> mem = new MemoryBase(mRawHeap, 0, w * 2 * h);
+        sp<MemoryBase> mem = new MemoryBase(mRawHeap, 0, w * h * 3 / 2);
         FakeCamera cam(w, h);
-        cam.getNextFrameAsYuv422((uint8_t *)mRawHeap->base());
+        cam.getNextFrameAsYuv420((uint8_t *)mRawHeap->base());
         mDataCb(CAMERA_MSG_RAW_IMAGE, mem, mCallbackCookie);
     }
 
@@ -307,7 +306,7 @@
 {
     stopPreview();
     if (createThread(beginPictureThread, this) == false)
-        return -1;
+        return UNKNOWN_ERROR;
     return NO_ERROR;
 }
 
@@ -339,12 +338,14 @@
     Mutex::Autolock lock(mLock);
     // XXX verify params
 
-    if (strcmp(params.getPreviewFormat(), "yuv422sp") != 0) {
-        LOGE("Only yuv422sp preview is supported");
+    if (strcmp(params.getPreviewFormat(),
+        CameraParameters::PIXEL_FORMAT_YUV420SP) != 0) {
+        LOGE("Only yuv420sp preview is supported");
         return -1;
     }
 
-    if (strcmp(params.getPictureFormat(), "jpeg") != 0) {
+    if (strcmp(params.getPictureFormat(),
+        CameraParameters::PIXEL_FORMAT_JPEG) != 0) {
         LOGE("Only jpeg still pictures are supported");
         return -1;
     }
@@ -379,22 +380,12 @@
 {
 }
 
-wp<CameraHardwareInterface> CameraHardwareStub::singleton;
-
 sp<CameraHardwareInterface> CameraHardwareStub::createInstance()
 {
-    if (singleton != 0) {
-        sp<CameraHardwareInterface> hardware = singleton.promote();
-        if (hardware != 0) {
-            return hardware;
-        }
-    }
-    sp<CameraHardwareInterface> hardware(new CameraHardwareStub());
-    singleton = hardware;
-    return hardware;
+    return new CameraHardwareStub();
 }
 
-extern "C" sp<CameraHardwareInterface> openCameraHardware()
+extern "C" sp<CameraHardwareInterface> openCameraHardwareStub()
 {
     return CameraHardwareStub::createInstance();
 }
diff --git a/camera/libcameraservice/CameraHardwareStub.h b/camera/libcameraservice/CameraHardwareStub.h
index 957813a..d194f3c 100644
--- a/camera/libcameraservice/CameraHardwareStub.h
+++ b/camera/libcameraservice/CameraHardwareStub.h
@@ -67,8 +67,6 @@
                         CameraHardwareStub();
     virtual             ~CameraHardwareStub();
 
-    static wp<CameraHardwareInterface> singleton;
-
     static const int kBufferCount = 4;
 
     class PreviewThread : public Thread {
@@ -130,6 +128,8 @@
     int                 mCurrentPreviewFrame;
 };
 
+extern "C" sp<CameraHardwareInterface> openCameraHardwareStub();
+
 }; // namespace android
 
 #endif
diff --git a/camera/libcameraservice/CameraService.cpp b/camera/libcameraservice/CameraService.cpp
index 00bd54e..4f684b7 100644
--- a/camera/libcameraservice/CameraService.cpp
+++ b/camera/libcameraservice/CameraService.cpp
@@ -17,383 +17,448 @@
 */
 
 #define LOG_TAG "CameraService"
-#include <utils/Log.h>
 
-#include <binder/IServiceManager.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <pthread.h>
+
 #include <binder/IPCThreadState.h>
-#include <utils/String16.h>
-#include <utils/Errors.h>
+#include <binder/IServiceManager.h>
 #include <binder/MemoryBase.h>
 #include <binder/MemoryHeapBase.h>
-#include <camera/ICameraService.h>
+#include <cutils/atomic.h>
+#include <hardware/hardware.h>
+#include <media/AudioSystem.h>
+#include <media/mediaplayer.h>
 #include <surfaceflinger/ISurface.h>
 #include <ui/Overlay.h>
+#include <utils/Errors.h>
+#include <utils/Log.h>
+#include <utils/String16.h>
 
-#include <hardware/hardware.h>
-
-#include <media/mediaplayer.h>
-#include <media/AudioSystem.h>
 #include "CameraService.h"
-
-#include <cutils/atomic.h>
+#ifdef INCLUDE_CAMERA_STUB
+#include "CameraHardwareStub.h"
+#endif
 
 namespace android {
 
-extern "C" {
-#include <stdio.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <pthread.h>
-#include <signal.h>
+/* This determines the number of cameras available */
+#if defined(INCLUDE_CAMERA_HARDWARE) && defined(INCLUDE_CAMERA_STUB)
+  #define NUM_CAMERAS 2
+#elif defined(INCLUDE_CAMERA_HARDWARE) || defined(INCLUDE_CAMERA_STUB)
+  #define NUM_CAMERAS 1
+#else
+  #error "Should have at least one camera"
+#endif
+
+/* Make sure we have enough array space allocated */
+#if NUM_CAMERAS > MAX_CAMERAS
+  #error "Need to increase MAX_CAMERAS"
+#endif
+
+/* This defines the "open" function for each camera */
+extern "C" typedef sp<CameraHardwareInterface> (*OpenCameraHardwareFunction)();
+static OpenCameraHardwareFunction sOpenCameraTable[] = {
+#ifdef INCLUDE_CAMERA_HARDWARE
+    &openCameraHardware,
+#endif
+#ifdef INCLUDE_CAMERA_STUB
+    &openCameraHardwareStub,
+#endif
+};
+
+// ----------------------------------------------------------------------------
+// Logging support -- this is for debugging only
+// Use "adb shell dumpsys media.camera -v 1" to change it.
+static volatile int32_t gLogLevel = 0;
+
+#define LOG1(...) LOGD_IF(gLogLevel >= 1, __VA_ARGS__);
+#define LOG2(...) LOGD_IF(gLogLevel >= 2, __VA_ARGS__);
+
+static void setLogLevel(int level) {
+    android_atomic_write(level, &gLogLevel);
 }
 
-// When you enable this, as well as DEBUG_REFS=1 and
-// DEBUG_REFS_ENABLED_BY_DEFAULT=0 in libutils/RefBase.cpp, this will track all
-// references to the CameraService::Client in order to catch the case where the
-// client is being destroyed while a callback from the CameraHardwareInterface
-// is outstanding.  This is a serious bug because if we make another call into
-// CameraHardwreInterface that itself triggers a callback, we will deadlock.
-
-#define DEBUG_CLIENT_REFERENCES 0
-
-#define PICTURE_TIMEOUT seconds(5)
-
-#define DEBUG_DUMP_PREVIEW_FRAME_TO_FILE 0 /* n-th frame to write */
-#define DEBUG_DUMP_JPEG_SNAPSHOT_TO_FILE 0
-#define DEBUG_DUMP_YUV_SNAPSHOT_TO_FILE 0
-#define DEBUG_DUMP_POSTVIEW_SNAPSHOT_TO_FILE 0
-
-#if DEBUG_DUMP_PREVIEW_FRAME_TO_FILE
-static int debug_frame_cnt;
-#endif
+// ----------------------------------------------------------------------------
 
 static int getCallingPid() {
     return IPCThreadState::self()->getCallingPid();
 }
 
-// ----------------------------------------------------------------------------
-
-void CameraService::instantiate() {
-    defaultServiceManager()->addService(
-            String16("media.camera"), new CameraService());
+static int getCallingUid() {
+    return IPCThreadState::self()->getCallingUid();
 }
 
 // ----------------------------------------------------------------------------
 
-CameraService::CameraService() :
-    BnCameraService()
-{
-    LOGI("CameraService started: pid=%d", getpid());
-    mUsers = 0;
-}
+// This is ugly and only safe if we never re-create the CameraService, but
+// should be ok for now.
+static CameraService *gCameraService;
 
-CameraService::~CameraService()
+CameraService::CameraService()
+:mSoundRef(0)
 {
-    if (mClient != 0) {
-        LOGE("mClient was still connected in destructor!");
+    LOGI("CameraService started (pid=%d)", getpid());
+
+    for (int i = 0; i < NUM_CAMERAS; i++) {
+        setCameraFree(i);
     }
+
+    gCameraService = this;
 }
 
-sp<ICamera> CameraService::connect(const sp<ICameraClient>& cameraClient)
-{
-    int callingPid = getCallingPid();
-    LOGV("CameraService::connect E (pid %d, client %p)", callingPid,
-            cameraClient->asBinder().get());
-
-    Mutex::Autolock lock(mServiceLock);
-    sp<Client> client;
-    if (mClient != 0) {
-        sp<Client> currentClient = mClient.promote();
-        if (currentClient != 0) {
-            sp<ICameraClient> currentCameraClient(currentClient->getCameraClient());
-            if (cameraClient->asBinder() == currentCameraClient->asBinder()) {
-                // This is the same client reconnecting...
-                LOGV("CameraService::connect X (pid %d, same client %p) is reconnecting...",
-                    callingPid, cameraClient->asBinder().get());
-                return currentClient;
-            } else {
-                // It's another client... reject it
-                LOGV("CameraService::connect X (pid %d, new client %p) rejected. "
-                    "(old pid %d, old client %p)",
-                    callingPid, cameraClient->asBinder().get(),
-                    currentClient->mClientPid, currentCameraClient->asBinder().get());
-                if (kill(currentClient->mClientPid, 0) == -1 && errno == ESRCH) {
-                    LOGV("The old client is dead!");
-                }
-                return client;
-            }
-        } else {
-            // can't promote, the previous client has died...
-            LOGV("New client (pid %d) connecting, old reference was dangling...",
-                    callingPid);
-            mClient.clear();
+CameraService::~CameraService() {
+    for (int i = 0; i < NUM_CAMERAS; i++) {
+        if (mBusy[i]) {
+            LOGE("camera %d is still in use in destructor!", i);
         }
     }
 
-    if (mUsers > 0) {
-        LOGV("Still have client, rejected");
-        return client;
+    gCameraService = NULL;
+}
+
+int32_t CameraService::getNumberOfCameras() {
+    return NUM_CAMERAS;
+}
+
+sp<ICamera> CameraService::connect(
+        const sp<ICameraClient>& cameraClient, int cameraId) {
+    int callingPid = getCallingPid();
+    LOG1("CameraService::connect E (pid %d, id %d)", callingPid, cameraId);
+
+    sp<Client> client;
+    if (cameraId < 0 || cameraId >= NUM_CAMERAS) {
+        LOGE("CameraService::connect X (pid %d) rejected (invalid cameraId %d).",
+            callingPid, cameraId);
+        return NULL;
     }
 
-    // create a new Client object
-    client = new Client(this, cameraClient, callingPid);
-    mClient = client;
-#if DEBUG_CLIENT_REFERENCES
-    // Enable tracking for this object, and track increments and decrements of
-    // the refcount.
-    client->trackMe(true, true);
-#endif
-    LOGV("CameraService::connect X");
+    Mutex::Autolock lock(mServiceLock);
+    if (mClient[cameraId] != 0) {
+        client = mClient[cameraId].promote();
+        if (client != 0) {
+            if (cameraClient->asBinder() == client->getCameraClient()->asBinder()) {
+                LOG1("CameraService::connect X (pid %d) (the same client)",
+                    callingPid);
+                return client;
+            } else {
+                LOGW("CameraService::connect X (pid %d) rejected (existing client).",
+                    callingPid);
+                return NULL;
+            }
+        }
+        mClient[cameraId].clear();
+    }
+
+    if (mBusy[cameraId]) {
+        LOGW("CameraService::connect X (pid %d) rejected"
+             " (camera %d is still busy).", callingPid, cameraId);
+        return NULL;
+    }
+
+    client = new Client(this, cameraClient, cameraId, callingPid);
+    mClient[cameraId] = client;
+    LOG1("CameraService::connect X");
     return client;
 }
 
-void CameraService::removeClient(const sp<ICameraClient>& cameraClient)
-{
+void CameraService::removeClient(const sp<ICameraClient>& cameraClient) {
     int callingPid = getCallingPid();
+    LOG1("CameraService::removeClient E (pid %d)", callingPid);
 
-    // Declare this outside the lock to make absolutely sure the
-    // destructor won't be called with the lock held.
-    sp<Client> client;
+    for (int i = 0; i < NUM_CAMERAS; i++) {
+        // Declare this before the lock to make absolutely sure the
+        // destructor won't be called with the lock held.
+        sp<Client> client;
 
-    Mutex::Autolock lock(mServiceLock);
+        Mutex::Autolock lock(mServiceLock);
 
-    if (mClient == 0) {
-        // This happens when we have already disconnected.
-        LOGV("removeClient (pid %d): already disconnected", callingPid);
-        return;
+        // This happens when we have already disconnected (or this is
+        // just another unused camera).
+        if (mClient[i] == 0) continue;
+
+        // Promote mClient. It can fail if we are called from this path:
+        // Client::~Client() -> disconnect() -> removeClient().
+        client = mClient[i].promote();
+
+        if (client == 0) {
+            mClient[i].clear();
+            continue;
+        }
+
+        if (cameraClient->asBinder() == client->getCameraClient()->asBinder()) {
+            // Found our camera, clear and leave.
+            LOG1("removeClient: clear camera %d", i);
+            mClient[i].clear();
+            break;
+        }
     }
 
-    // Promote mClient. It can fail if we are called from this path:
-    // Client::~Client() -> disconnect() -> removeClient().
-    client = mClient.promote();
-    if (client == 0) {
-        LOGV("removeClient (pid %d): no more strong reference", callingPid);
-        mClient.clear();
-        return;
+    LOG1("CameraService::removeClient X (pid %d)", callingPid);
+}
+
+sp<CameraService::Client> CameraService::getClientById(int cameraId) {
+    if (cameraId < 0 || cameraId >= NUM_CAMERAS) return NULL;
+    return mClient[cameraId].promote();
+}
+
+void CameraService::instantiate() {
+    defaultServiceManager()->addService(String16("media.camera"),
+        new CameraService());
+}
+
+status_t CameraService::onTransact(
+    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) {
+    // Permission checks
+    switch (code) {
+        case BnCameraService::CONNECT:
+            const int pid = getCallingPid();
+            const int self_pid = getpid();
+            if (pid != self_pid) {
+                // we're called from a different process, do the real check
+                if (!checkCallingPermission(
+                        String16("android.permission.CAMERA"))) {
+                    const int uid = getCallingUid();
+                    LOGE("Permission Denial: "
+                         "can't use the camera pid=%d, uid=%d", pid, uid);
+                    return PERMISSION_DENIED;
+                }
+            }
+            break;
     }
 
-    if (cameraClient->asBinder() != client->getCameraClient()->asBinder()) {
-        // ugh! that's not our client!!
-        LOGW("removeClient (pid %d): mClient doesn't match!", callingPid);
-    } else {
-        // okay, good, forget about mClient
-        mClient.clear();
-    }
-
-    LOGV("removeClient (pid %d) done", callingPid);
+    return BnCameraService::onTransact(code, data, reply, flags);
 }
 
-// The reason we need this count is a new CameraService::connect() request may
-// come in while the previous Client's destructor has not been run or is still
-// running. If the last strong reference of the previous Client is gone but
-// destructor has not been run, we should not allow the new Client to be created
-// because we need to wait for the previous Client to tear down the hardware
-// first.
-void CameraService::incUsers() {
-    android_atomic_inc(&mUsers);
+// The reason we need this busy bit is a new CameraService::connect() request
+// may come in while the previous Client's destructor has not been run or is
+// still running. If the last strong reference of the previous Client is gone
+// but the destructor has not been finished, we should not allow the new Client
+// to be created because we need to wait for the previous Client to tear down
+// the hardware first.
+void CameraService::setCameraBusy(int cameraId) {
+    android_atomic_write(1, &mBusy[cameraId]);
 }
 
-void CameraService::decUsers() {
-    android_atomic_dec(&mUsers);
+void CameraService::setCameraFree(int cameraId) {
+    android_atomic_write(0, &mBusy[cameraId]);
 }
 
-static sp<MediaPlayer> newMediaPlayer(const char *file)
-{
-    sp<MediaPlayer> mp = new MediaPlayer();
-    if (mp->setDataSource(file, NULL /* headers */) == NO_ERROR) {
+// We share the media players for shutter and recording sound for all clients.
+// A reference count is kept to determine when we will actually release the
+// media players.
+
+static MediaPlayer* newMediaPlayer(const char *file) {
+    MediaPlayer* mp = new MediaPlayer();
+    if (mp->setDataSource(file, NULL) == NO_ERROR) {
         mp->setAudioStreamType(AudioSystem::ENFORCED_AUDIBLE);
         mp->prepare();
     } else {
-        mp.clear();
-        LOGE("Failed to load CameraService sounds.");
+        LOGE("Failed to load CameraService sounds: %s", file);
+        return NULL;
     }
     return mp;
 }
 
+void CameraService::loadSound() {
+    Mutex::Autolock lock(mSoundLock);
+    LOG1("CameraService::loadSound ref=%d", mSoundRef);
+    if (mSoundRef++) return;
+
+    mSoundPlayer[SOUND_SHUTTER] = newMediaPlayer("/system/media/audio/ui/camera_click.ogg");
+    mSoundPlayer[SOUND_RECORDING] = newMediaPlayer("/system/media/audio/ui/VideoRecord.ogg");
+}
+
+void CameraService::releaseSound() {
+    Mutex::Autolock lock(mSoundLock);
+    LOG1("CameraService::releaseSound ref=%d", mSoundRef);
+    if (--mSoundRef) return;
+
+    for (int i = 0; i < NUM_SOUNDS; i++) {
+        if (mSoundPlayer[i] != 0) {
+            mSoundPlayer[i]->disconnect();
+            mSoundPlayer[i].clear();
+        }
+    }
+}
+
+void CameraService::playSound(sound_kind kind) {
+    LOG1("playSound(%d)", kind);
+    Mutex::Autolock lock(mSoundLock);
+    sp<MediaPlayer> player = mSoundPlayer[kind];
+    if (player != 0) {
+        // do not play the sound if stream volume is 0
+        // (typically because ringer mode is silent).
+        int index;
+        AudioSystem::getStreamVolumeIndex(AudioSystem::ENFORCED_AUDIBLE, &index);
+        if (index != 0) {
+            player->seekTo(0);
+            player->start();
+        }
+    }
+}
+
+// ----------------------------------------------------------------------------
+
 CameraService::Client::Client(const sp<CameraService>& cameraService,
-        const sp<ICameraClient>& cameraClient, pid_t clientPid)
-{
+        const sp<ICameraClient>& cameraClient, int cameraId, int clientPid) {
     int callingPid = getCallingPid();
-    LOGV("Client::Client E (pid %d)", callingPid);
+    LOG1("Client::Client E (pid %d)", callingPid);
+
     mCameraService = cameraService;
     mCameraClient = cameraClient;
+    mCameraId = cameraId;
     mClientPid = clientPid;
-    mHardware = openCameraHardware();
+
+    mHardware = sOpenCameraTable[cameraId]();
     mUseOverlay = mHardware->useOverlay();
+    mMsgEnabled = 0;
 
     mHardware->setCallbacks(notifyCallback,
                             dataCallback,
                             dataCallbackTimestamp,
-                            mCameraService.get());
+                            (void *)cameraId);
 
     // Enable zoom, error, and focus messages by default
-    mHardware->enableMsgType(CAMERA_MSG_ERROR |
-                             CAMERA_MSG_ZOOM |
-                             CAMERA_MSG_FOCUS);
-
-    mMediaPlayerClick = newMediaPlayer("/system/media/audio/ui/camera_click.ogg");
-    mMediaPlayerBeep = newMediaPlayer("/system/media/audio/ui/VideoRecord.ogg");
+    enableMsgType(CAMERA_MSG_ERROR |
+                  CAMERA_MSG_ZOOM |
+                  CAMERA_MSG_FOCUS);
     mOverlayW = 0;
     mOverlayH = 0;
 
     // Callback is disabled by default
     mPreviewCallbackFlag = FRAME_CALLBACK_FLAG_NOOP;
     mOrientation = 0;
-    cameraService->incUsers();
-    LOGV("Client::Client X (pid %d)", callingPid);
+    cameraService->setCameraBusy(cameraId);
+    cameraService->loadSound();
+    LOG1("Client::Client X (pid %d)", callingPid);
 }
 
-status_t CameraService::Client::checkPid()
-{
-    int callingPid = getCallingPid();
-    if (mClientPid == callingPid) return NO_ERROR;
-    LOGW("Attempt to use locked camera (client %p) from different process "
-        " (old pid %d, new pid %d)",
-        getCameraClient()->asBinder().get(), mClientPid, callingPid);
-    return -EBUSY;
-}
-
-status_t CameraService::Client::lock()
-{
-    int callingPid = getCallingPid();
-    LOGV("lock from pid %d (mClientPid %d)", callingPid, mClientPid);
-    Mutex::Autolock _l(mLock);
-    // lock camera to this client if the the camera is unlocked
-    if (mClientPid == 0) {
-        mClientPid = callingPid;
-        return NO_ERROR;
-    }
-    // returns NO_ERROR if the client already owns the camera, -EBUSY otherwise
-    return checkPid();
-}
-
-status_t CameraService::Client::unlock()
-{
-    int callingPid = getCallingPid();
-    LOGV("unlock from pid %d (mClientPid %d)", callingPid, mClientPid);
-    Mutex::Autolock _l(mLock);
-    // allow anyone to use camera
-    status_t result = checkPid();
-    if (result == NO_ERROR) {
-        mClientPid = 0;
-        LOGV("clear mCameraClient (pid %d)", callingPid);
-        // we need to remove the reference so that when app goes
-        // away, the reference count goes to 0.
-        mCameraClient.clear();
-    }
-    return result;
-}
-
-status_t CameraService::Client::connect(const sp<ICameraClient>& client)
-{
-    int callingPid = getCallingPid();
-
-    // connect a new process to the camera
-    LOGV("Client::connect E (pid %d, client %p)", callingPid, client->asBinder().get());
-
-    // I hate this hack, but things get really ugly when the media recorder
-    // service is handing back the camera to the app. The ICameraClient
-    // destructor will be called during the same IPC, making it look like
-    // the remote client is trying to disconnect. This hack temporarily
-    // sets the mClientPid to an invalid pid to prevent the hardware from
-    // being torn down.
-    {
-
-        // hold a reference to the old client or we will deadlock if the client is
-        // in the same process and we hold the lock when we remove the reference
-        sp<ICameraClient> oldClient;
-        {
-            Mutex::Autolock _l(mLock);
-            if (mClientPid != 0 && checkPid() != NO_ERROR) {
-                LOGW("Tried to connect to locked camera (old pid %d, new pid %d)",
-                        mClientPid, callingPid);
-                return -EBUSY;
-            }
-            oldClient = mCameraClient;
-
-            // did the client actually change?
-            if ((mCameraClient != NULL) && (client->asBinder() == mCameraClient->asBinder())) {
-                LOGV("Connect to the same client");
-                return NO_ERROR;
-            }
-
-            mCameraClient = client;
-            mClientPid = -1;
-            mPreviewCallbackFlag = FRAME_CALLBACK_FLAG_NOOP;
-            LOGV("Connect to the new client (pid %d, client %p)",
-                callingPid, mCameraClient->asBinder().get());
-        }
-
-    }
-    // the old client destructor is called when oldClient goes out of scope
-    // now we set the new PID to lock the interface again
-    mClientPid = callingPid;
-
-    return NO_ERROR;
-}
-
-#if HAVE_ANDROID_OS
-static void *unregister_surface(void *arg)
-{
+static void *unregister_surface(void *arg) {
     ISurface *surface = (ISurface *)arg;
     surface->unregisterBuffers();
     IPCThreadState::self()->flushCommands();
     return NULL;
 }
-#endif
 
-CameraService::Client::~Client()
-{
+// tear down the client
+CameraService::Client::~Client() {
     int callingPid = getCallingPid();
+    LOG1("Client::~Client E (pid %d, this %p)", callingPid, this);
 
-    // tear down client
-    LOGV("Client::~Client E (pid %d, client %p)",
-            callingPid, getCameraClient()->asBinder().get());
     if (mSurface != 0 && !mUseOverlay) {
-#if HAVE_ANDROID_OS
         pthread_t thr;
         // We unregister the buffers in a different thread because binder does
         // not let us make sychronous transactions in a binder destructor (that
         // is, upon our reaching a refcount of zero.)
-        pthread_create(&thr, NULL,
+        pthread_create(&thr,
+                       NULL,  // attr
                        unregister_surface,
                        mSurface.get());
         pthread_join(thr, NULL);
-#else
-        mSurface->unregisterBuffers();
-#endif
     }
 
-    if (mMediaPlayerBeep.get() != NULL) {
-        mMediaPlayerBeep->disconnect();
-        mMediaPlayerBeep.clear();
-    }
-    if (mMediaPlayerClick.get() != NULL) {
-        mMediaPlayerClick->disconnect();
-        mMediaPlayerClick.clear();
-    }
-
-    // make sure we tear down the hardware
+    // set mClientPid to let disconnet() tear down the hardware
     mClientPid = callingPid;
     disconnect();
-    LOGV("Client::~Client X (pid %d)", mClientPid);
+    mCameraService->releaseSound();
+    LOG1("Client::~Client X (pid %d, this %p)", callingPid, this);
 }
 
-void CameraService::Client::disconnect()
-{
+// ----------------------------------------------------------------------------
+
+status_t CameraService::Client::checkPid() const {
     int callingPid = getCallingPid();
+    if (callingPid == mClientPid) return NO_ERROR;
+    if (callingPid == getpid()) {
+        LOGW("FIXME: use camera from mediaserver without permission.");
+        return NO_ERROR;
+    }
+    LOGW("attempt to use a locked camera from a different process"
+         " (old pid %d, new pid %d)", mClientPid, callingPid);
+    return EBUSY;
+}
 
-    LOGV("Client::disconnect() E (pid %d client %p)",
-            callingPid, getCameraClient()->asBinder().get());
+status_t CameraService::Client::checkPidAndHardware() const {
+    status_t result = checkPid();
+    if (result != NO_ERROR) return result;
+    if (mHardware == 0) {
+        LOGE("attempt to use a camera after disconnect() (pid %d)", getCallingPid());
+        return INVALID_OPERATION;
+    }
+    return NO_ERROR;
+}
 
+status_t CameraService::Client::lock() {
+    int callingPid = getCallingPid();
+    LOG1("lock (pid %d)", callingPid);
     Mutex::Autolock lock(mLock);
-    if (mClientPid <= 0) {
-        LOGV("camera is unlocked (mClientPid = %d), don't tear down hardware", mClientPid);
+
+    // lock camera to this client if the the camera is unlocked
+    if (mClientPid == 0) {
+        mClientPid = callingPid;
+        return NO_ERROR;
+    }
+
+    // returns NO_ERROR if the client already owns the camera, EBUSY otherwise
+    return checkPid();
+}
+
+status_t CameraService::Client::unlock() {
+    int callingPid = getCallingPid();
+    LOG1("unlock (pid %d)", callingPid);
+    Mutex::Autolock lock(mLock);
+
+    // allow anyone to use camera (after they lock the camera)
+    status_t result = checkPid();
+    if (result == NO_ERROR) {
+        mClientPid = 0;
+        LOG1("clear mCameraClient (pid %d)", callingPid);
+        // we need to remove the reference to ICameraClient so that when the app
+        // goes away, the reference count goes to 0.
+        mCameraClient.clear();
+    }
+    return result;
+}
+
+// connect a new client to the camera
+status_t CameraService::Client::connect(const sp<ICameraClient>& client) {
+    int callingPid = getCallingPid();
+    LOG1("connect E (pid %d)", callingPid);
+    Mutex::Autolock lock(mLock);
+
+    if (mClientPid != 0 && checkPid() != NO_ERROR) {
+        LOGW("Tried to connect to a locked camera (old pid %d, new pid %d)",
+                mClientPid, callingPid);
+        return EBUSY;
+    }
+
+    if (mCameraClient != 0 && (client->asBinder() == mCameraClient->asBinder())) {
+        LOG1("Connect to the same client");
+        return NO_ERROR;
+    }
+
+    mPreviewCallbackFlag = FRAME_CALLBACK_FLAG_NOOP;
+    mClientPid = callingPid;
+    mCameraClient = client;
+
+    LOG1("connect X (pid %d)", callingPid);
+    return NO_ERROR;
+}
+
+void CameraService::Client::disconnect() {
+    int callingPid = getCallingPid();
+    LOG1("disconnect E (pid %d)", callingPid);
+    Mutex::Autolock lock(mLock);
+
+    if (checkPid() != NO_ERROR) {
+        LOGW("different client - don't disconnect");
         return;
     }
-    if (checkPid() != NO_ERROR) {
-        LOGV("Different client - don't disconnect");
+
+    if (mClientPid <= 0) {
+        LOG1("camera is unlocked (mClientPid = %d), don't tear down hardware", mClientPid);
         return;
     }
 
@@ -401,826 +466,366 @@
     // from the user directly, or called by the destructor.
     if (mHardware == 0) return;
 
-    LOGV("hardware teardown");
+    LOG1("hardware teardown");
     // Before destroying mHardware, we must make sure it's in the
     // idle state.
+    // Turn off all messages.
+    disableMsgType(CAMERA_MSG_ALL_MSGS);
     mHardware->stopPreview();
-    // Cancel all picture callbacks.
-    mHardware->disableMsgType(CAMERA_MSG_SHUTTER |
-                              CAMERA_MSG_POSTVIEW_FRAME |
-                              CAMERA_MSG_RAW_IMAGE |
-                              CAMERA_MSG_COMPRESSED_IMAGE);
     mHardware->cancelPicture();
-    // Turn off remaining messages.
-    mHardware->disableMsgType(CAMERA_MSG_ALL_MSGS);
     // Release the hardware resources.
     mHardware->release();
     // Release the held overlay resources.
-    if (mUseOverlay)
-    {
+    if (mUseOverlay) {
         mOverlayRef = 0;
     }
     mHardware.clear();
 
     mCameraService->removeClient(mCameraClient);
-    mCameraService->decUsers();
+    mCameraService->setCameraFree(mCameraId);
 
-    LOGV("Client::disconnect() X (pid %d)", callingPid);
+    LOG1("disconnect X (pid %d)", callingPid);
 }
 
-// pass the buffered ISurface to the camera service
-status_t CameraService::Client::setPreviewDisplay(const sp<ISurface>& surface)
-{
-    LOGV("setPreviewDisplay(%p) (pid %d)",
-         ((surface == NULL) ? NULL : surface.get()), getCallingPid());
+// ----------------------------------------------------------------------------
+
+// set the ISurface that the preview will use
+status_t CameraService::Client::setPreviewDisplay(const sp<ISurface>& surface) {
+    LOG1("setPreviewDisplay(%p) (pid %d)", surface.get(), getCallingPid());
     Mutex::Autolock lock(mLock);
-    status_t result = checkPid();
+    status_t result = checkPidAndHardware();
     if (result != NO_ERROR) return result;
 
-    Mutex::Autolock surfaceLock(mSurfaceLock);
     result = NO_ERROR;
+
+    // return if no change in surface.
     // asBinder() is safe on NULL (returns NULL)
-    if (surface->asBinder() != mSurface->asBinder()) {
-        if (mSurface != 0) {
-            LOGV("clearing old preview surface %p", mSurface.get());
-            if ( !mUseOverlay)
-            {
-                mSurface->unregisterBuffers();
-            }
-            else
-            {
-                // Force the destruction of any previous overlay
-                sp<Overlay> dummy;
-                mHardware->setOverlay( dummy );
-            }
-        }
-        mSurface = surface;
-        mOverlayRef = 0;
-        // If preview has been already started, set overlay or register preview
-        // buffers now.
-        if (mHardware->previewEnabled()) {
-            if (mUseOverlay) {
-                result = setOverlay();
-            } else if (mSurface != 0) {
-                result = registerPreviewBuffers();
-            }
+    if (surface->asBinder() == mSurface->asBinder()) {
+        return result;
+    }
+
+    if (mSurface != 0) {
+        LOG1("clearing old preview surface %p", mSurface.get());
+        if (mUseOverlay) {
+            // Force the destruction of any previous overlay
+            sp<Overlay> dummy;
+            mHardware->setOverlay(dummy);
+        } else {
+            mSurface->unregisterBuffers();
         }
     }
+    mSurface = surface;
+    mOverlayRef = 0;
+    // If preview has been already started, set overlay or register preview
+    // buffers now.
+    if (mHardware->previewEnabled()) {
+        if (mUseOverlay) {
+            result = setOverlay();
+        } else if (mSurface != 0) {
+            result = registerPreviewBuffers();
+        }
+    }
+
     return result;
 }
 
-// set the preview callback flag to affect how the received frames from
-// preview are handled.
-void CameraService::Client::setPreviewCallbackFlag(int callback_flag)
-{
-    LOGV("setPreviewCallbackFlag (pid %d)", getCallingPid());
-    Mutex::Autolock lock(mLock);
-    if (checkPid() != NO_ERROR) return;
-    mPreviewCallbackFlag = callback_flag;
-
-    if(mUseOverlay) {
-        if(mPreviewCallbackFlag & FRAME_CALLBACK_FLAG_ENABLE_MASK)
-            mHardware->enableMsgType(CAMERA_MSG_PREVIEW_FRAME);
-        else
-            mHardware->disableMsgType(CAMERA_MSG_PREVIEW_FRAME);
-    }
-}
-
-// start preview mode
-status_t CameraService::Client::startCameraMode(camera_mode mode)
-{
-    int callingPid = getCallingPid();
-
-    LOGV("startCameraMode(%d) (pid %d)", mode, callingPid);
-
-    /* we cannot call into mHardware with mLock held because
-     * mHardware has callbacks onto us which acquire this lock
-     */
-
-    Mutex::Autolock lock(mLock);
-    status_t result = checkPid();
-    if (result != NO_ERROR) return result;
-
-    if (mHardware == 0) {
-        LOGE("mHardware is NULL, returning.");
-        return INVALID_OPERATION;
-    }
-
-    switch(mode) {
-    case CAMERA_RECORDING_MODE:
-        if (mSurface == 0) {
-            LOGE("setPreviewDisplay must be called before startRecordingMode.");
-            return INVALID_OPERATION;
-        }
-        return startRecordingMode();
-
-    default: // CAMERA_PREVIEW_MODE
-        if (mSurface == 0) {
-            LOGV("mSurface is not set yet.");
-        }
-        return startPreviewMode();
-    }
-}
-
-status_t CameraService::Client::startRecordingMode()
-{
-    LOGV("startRecordingMode (pid %d)", getCallingPid());
-
-    status_t ret = UNKNOWN_ERROR;
-
-    // if preview has not been started, start preview first
-    if (!mHardware->previewEnabled()) {
-        ret = startPreviewMode();
-        if (ret != NO_ERROR) {
-            return ret;
-        }
-    }
-
-    // if recording has been enabled, nothing needs to be done
-    if (mHardware->recordingEnabled()) {
-        return NO_ERROR;
-    }
-
-    // start recording mode
-    ret = mHardware->startRecording();
-    if (ret != NO_ERROR) {
-        LOGE("mHardware->startRecording() failed with status %d", ret);
-    }
-    return ret;
-}
-
-status_t CameraService::Client::setOverlay()
-{
-    LOGV("setOverlay");
+status_t CameraService::Client::registerPreviewBuffers() {
     int w, h;
     CameraParameters params(mHardware->getParameters());
     params.getPreviewSize(&w, &h);
 
-    if ( w != mOverlayW || h != mOverlayH )
-    {
-        // Force the destruction of any previous overlay
-        sp<Overlay> dummy;
-        mHardware->setOverlay( dummy );
-        mOverlayRef = 0;
-    }
-
-    status_t ret = NO_ERROR;
-    if (mSurface != 0) {
-        if (mOverlayRef.get() == NULL) {
-
-            // FIXME:
-            // Surfaceflinger may hold onto the previous overlay reference for some
-            // time after we try to destroy it. retry a few times. In the future, we
-            // should make the destroy call block, or possibly specify that we can
-            // wait in the createOverlay call if the previous overlay is in the 
-            // process of being destroyed.
-            for (int retry = 0; retry < 50; ++retry) {
-                mOverlayRef = mSurface->createOverlay(w, h, OVERLAY_FORMAT_DEFAULT,
-                                                      mOrientation);
-                if (mOverlayRef != NULL) break;
-                LOGW("Overlay create failed - retrying");
-                usleep(20000);
-            }
-            if ( mOverlayRef.get() == NULL )
-            {
-                LOGE("Overlay Creation Failed!");
-                return -EINVAL;
-            }
-            ret = mHardware->setOverlay(new Overlay(mOverlayRef));
-        }
-    } else {
-        ret = mHardware->setOverlay(NULL);
-    }
-    if (ret != NO_ERROR) {
-        LOGE("mHardware->setOverlay() failed with status %d\n", ret);
-    }
-
-    mOverlayW = w;
-    mOverlayH = h;
-
-    return ret;
-}
-
-status_t CameraService::Client::registerPreviewBuffers()
-{
-    int w, h;
-    CameraParameters params(mHardware->getParameters());
-    params.getPreviewSize(&w, &h);
-
-    // don't use a hardcoded format here
+    // FIXME: don't use a hardcoded format here.
     ISurface::BufferHeap buffers(w, h, w, h,
                                  HAL_PIXEL_FORMAT_YCrCb_420_SP,
                                  mOrientation,
                                  0,
                                  mHardware->getPreviewHeap());
 
-    status_t ret = mSurface->registerBuffers(buffers);
-    if (ret != NO_ERROR) {
-        LOGE("registerBuffers failed with status %d", ret);
+    status_t result = mSurface->registerBuffers(buffers);
+    if (result != NO_ERROR) {
+        LOGE("registerBuffers failed with status %d", result);
     }
-    return ret;
+    return result;
 }
 
-status_t CameraService::Client::startPreviewMode()
-{
-    LOGV("startPreviewMode (pid %d)", getCallingPid());
+status_t CameraService::Client::setOverlay() {
+    int w, h;
+    CameraParameters params(mHardware->getParameters());
+    params.getPreviewSize(&w, &h);
+
+    if (w != mOverlayW || h != mOverlayH) {
+        // Force the destruction of any previous overlay
+        sp<Overlay> dummy;
+        mHardware->setOverlay(dummy);
+        mOverlayRef = 0;
+    }
+
+    status_t result = NO_ERROR;
+    if (mSurface == 0) {
+        result = mHardware->setOverlay(NULL);
+    } else {
+        if (mOverlayRef == 0) {
+            // FIXME:
+            // Surfaceflinger may hold onto the previous overlay reference for some
+            // time after we try to destroy it. retry a few times. In the future, we
+            // should make the destroy call block, or possibly specify that we can
+            // wait in the createOverlay call if the previous overlay is in the
+            // process of being destroyed.
+            for (int retry = 0; retry < 50; ++retry) {
+                mOverlayRef = mSurface->createOverlay(w, h, OVERLAY_FORMAT_DEFAULT,
+                                                      mOrientation);
+                if (mOverlayRef != 0) break;
+                LOGW("Overlay create failed - retrying");
+                usleep(20000);
+            }
+            if (mOverlayRef == 0) {
+                LOGE("Overlay Creation Failed!");
+                return -EINVAL;
+            }
+            result = mHardware->setOverlay(new Overlay(mOverlayRef));
+        }
+    }
+    if (result != NO_ERROR) {
+        LOGE("mHardware->setOverlay() failed with status %d\n", result);
+        return result;
+    }
+
+    mOverlayW = w;
+    mOverlayH = h;
+
+    return result;
+}
+
+// set the preview callback flag to affect how the received frames from
+// preview are handled.
+void CameraService::Client::setPreviewCallbackFlag(int callback_flag) {
+    LOG1("setPreviewCallbackFlag(%d) (pid %d)", callback_flag, getCallingPid());
+    Mutex::Autolock lock(mLock);
+    if (checkPidAndHardware() != NO_ERROR) return;
+
+    mPreviewCallbackFlag = callback_flag;
+
+    // If we don't use overlay, we always need the preview frame for display.
+    // If we do use overlay, we only need the preview frame if the user
+    // wants the data.
+    if (mUseOverlay) {
+        if(mPreviewCallbackFlag & FRAME_CALLBACK_FLAG_ENABLE_MASK) {
+            enableMsgType(CAMERA_MSG_PREVIEW_FRAME);
+        } else {
+            disableMsgType(CAMERA_MSG_PREVIEW_FRAME);
+        }
+    }
+}
+
+// start preview mode
+status_t CameraService::Client::startPreview() {
+    LOG1("startPreview (pid %d)", getCallingPid());
+    return startCameraMode(CAMERA_PREVIEW_MODE);
+}
+
+// start recording mode
+status_t CameraService::Client::startRecording() {
+    LOG1("startRecording (pid %d)", getCallingPid());
+    return startCameraMode(CAMERA_RECORDING_MODE);
+}
+
+// start preview or recording
+status_t CameraService::Client::startCameraMode(camera_mode mode) {
+    LOG1("startCameraMode(%d)", mode);
+    Mutex::Autolock lock(mLock);
+    status_t result = checkPidAndHardware();
+    if (result != NO_ERROR) return result;
+
+    switch(mode) {
+        case CAMERA_PREVIEW_MODE:
+            if (mSurface == 0) {
+                LOG1("mSurface is not set yet.");
+                // still able to start preview in this case.
+            }
+            return startPreviewMode();
+        case CAMERA_RECORDING_MODE:
+            if (mSurface == 0) {
+                LOGE("mSurface must be set before startRecordingMode.");
+                return INVALID_OPERATION;
+            }
+            return startRecordingMode();
+        default:
+            return UNKNOWN_ERROR;
+    }
+}
+
+status_t CameraService::Client::startPreviewMode() {
+    LOG1("startPreviewMode");
+    status_t result = NO_ERROR;
 
     // if preview has been enabled, nothing needs to be done
     if (mHardware->previewEnabled()) {
         return NO_ERROR;
     }
 
-    // start preview mode
-#if DEBUG_DUMP_PREVIEW_FRAME_TO_FILE
-    debug_frame_cnt = 0;
-#endif
-    status_t ret = NO_ERROR;
-
     if (mUseOverlay) {
         // If preview display has been set, set overlay now.
         if (mSurface != 0) {
-            ret = setOverlay();
+            result = setOverlay();
         }
-        if (ret != NO_ERROR) return ret;
-        ret = mHardware->startPreview();
+        if (result != NO_ERROR) return result;
+        result = mHardware->startPreview();
     } else {
-        mHardware->enableMsgType(CAMERA_MSG_PREVIEW_FRAME);
-        ret = mHardware->startPreview();
-        if (ret != NO_ERROR) return ret;
+        enableMsgType(CAMERA_MSG_PREVIEW_FRAME);
+        result = mHardware->startPreview();
+        if (result != NO_ERROR) return result;
         // If preview display has been set, register preview buffers now.
         if (mSurface != 0) {
-           // Unregister here because the surface registered with raw heap.
+           // Unregister here because the surface may be previously registered
+           // with the raw (snapshot) heap.
            mSurface->unregisterBuffers();
-           ret = registerPreviewBuffers();
+           result = registerPreviewBuffers();
         }
     }
-    return ret;
+    return result;
 }
 
-status_t CameraService::Client::startPreview()
-{
-    LOGV("startPreview (pid %d)", getCallingPid());
+status_t CameraService::Client::startRecordingMode() {
+    LOG1("startRecordingMode");
+    status_t result = NO_ERROR;
 
-    return startCameraMode(CAMERA_PREVIEW_MODE);
-}
+    // if recording has been enabled, nothing needs to be done
+    if (mHardware->recordingEnabled()) {
+        return NO_ERROR;
+    }
 
-status_t CameraService::Client::startRecording()
-{
-    LOGV("startRecording (pid %d)", getCallingPid());
-
-    if (mMediaPlayerBeep.get() != NULL) {
-        // do not play record jingle if stream volume is 0
-        // (typically because ringer mode is silent).
-        int index;
-        AudioSystem::getStreamVolumeIndex(AudioSystem::ENFORCED_AUDIBLE, &index);
-        if (index != 0) {
-            mMediaPlayerBeep->seekTo(0);
-            mMediaPlayerBeep->start();
+    // if preview has not been started, start preview first
+    if (!mHardware->previewEnabled()) {
+        result = startPreviewMode();
+        if (result != NO_ERROR) {
+            return result;
         }
     }
 
-    mHardware->enableMsgType(CAMERA_MSG_VIDEO_FRAME);
-
-    return startCameraMode(CAMERA_RECORDING_MODE);
+    // start recording mode
+    enableMsgType(CAMERA_MSG_VIDEO_FRAME);
+    mCameraService->playSound(SOUND_RECORDING);
+    result = mHardware->startRecording();
+    if (result != NO_ERROR) {
+        LOGE("mHardware->startRecording() failed with status %d", result);
+    }
+    return result;
 }
 
 // stop preview mode
-void CameraService::Client::stopPreview()
-{
-    LOGV("stopPreview (pid %d)", getCallingPid());
+void CameraService::Client::stopPreview() {
+    LOG1("stopPreview (pid %d)", getCallingPid());
+    Mutex::Autolock lock(mLock);
+    if (checkPidAndHardware() != NO_ERROR) return;
 
-    // hold main lock during state transition
-    {
-        Mutex::Autolock lock(mLock);
-        if (checkPid() != NO_ERROR) return;
+    disableMsgType(CAMERA_MSG_PREVIEW_FRAME);
+    mHardware->stopPreview();
 
-        if (mHardware == 0) {
-            LOGE("mHardware is NULL, returning.");
-            return;
-        }
-
-        mHardware->stopPreview();
-        mHardware->disableMsgType(CAMERA_MSG_PREVIEW_FRAME);
-        LOGV("stopPreview(), hardware stopped OK");
-
-        if (mSurface != 0 && !mUseOverlay) {
-            mSurface->unregisterBuffers();
-        }
+    if (mSurface != 0 && !mUseOverlay) {
+        mSurface->unregisterBuffers();
     }
 
-    // hold preview buffer lock
-    {
-        Mutex::Autolock lock(mPreviewLock);
-        mPreviewBuffer.clear();
-    }
+    mPreviewBuffer.clear();
 }
 
 // stop recording mode
-void CameraService::Client::stopRecording()
-{
-    LOGV("stopRecording (pid %d)", getCallingPid());
+void CameraService::Client::stopRecording() {
+    LOG1("stopRecording (pid %d)", getCallingPid());
+    Mutex::Autolock lock(mLock);
+    if (checkPidAndHardware() != NO_ERROR) return;
 
-    // hold main lock during state transition
-    {
-        Mutex::Autolock lock(mLock);
-        if (checkPid() != NO_ERROR) return;
+    mCameraService->playSound(SOUND_RECORDING);
+    disableMsgType(CAMERA_MSG_VIDEO_FRAME);
+    mHardware->stopRecording();
 
-        if (mHardware == 0) {
-            LOGE("mHardware is NULL, returning.");
-            return;
-        }
-
-        if (mMediaPlayerBeep.get() != NULL) {
-            mMediaPlayerBeep->seekTo(0);
-            mMediaPlayerBeep->start();
-        }
-
-        mHardware->stopRecording();
-        mHardware->disableMsgType(CAMERA_MSG_VIDEO_FRAME);
-        LOGV("stopRecording(), hardware stopped OK");
-    }
-
-    // hold preview buffer lock
-    {
-        Mutex::Autolock lock(mPreviewLock);
-        mPreviewBuffer.clear();
-    }
+    mPreviewBuffer.clear();
 }
 
 // release a recording frame
-void CameraService::Client::releaseRecordingFrame(const sp<IMemory>& mem)
-{
+void CameraService::Client::releaseRecordingFrame(const sp<IMemory>& mem) {
     Mutex::Autolock lock(mLock);
-    if (checkPid() != NO_ERROR) return;
-
-    if (mHardware == 0) {
-        LOGE("mHardware is NULL, returning.");
-        return;
-    }
-
+    if (checkPidAndHardware() != NO_ERROR) return;
     mHardware->releaseRecordingFrame(mem);
 }
 
-bool CameraService::Client::previewEnabled()
-{
+bool CameraService::Client::previewEnabled() {
+    LOG1("previewEnabled (pid %d)", getCallingPid());
+
     Mutex::Autolock lock(mLock);
-    if (mHardware == 0) return false;
+    if (checkPidAndHardware() != NO_ERROR) return false;
     return mHardware->previewEnabled();
 }
 
-bool CameraService::Client::recordingEnabled()
-{
+bool CameraService::Client::recordingEnabled() {
+    LOG1("recordingEnabled (pid %d)", getCallingPid());
+
     Mutex::Autolock lock(mLock);
-    if (mHardware == 0) return false;
+    if (checkPidAndHardware() != NO_ERROR) return false;
     return mHardware->recordingEnabled();
 }
 
-// Safely retrieves a strong pointer to the client during a hardware callback.
-sp<CameraService::Client> CameraService::Client::getClientFromCookie(void* user)
-{
-    sp<Client> client = 0;
-    CameraService *service = static_cast<CameraService*>(user);
-    if (service != NULL) {
-        Mutex::Autolock ourLock(service->mServiceLock);
-        if (service->mClient != 0) {
-            client = service->mClient.promote();
-            if (client == 0) {
-                LOGE("getClientFromCookie: client appears to have died");
-                service->mClient.clear();
-            }
-        } else {
-            LOGE("getClientFromCookie: got callback but client was NULL");
-        }
-    }
-    return client;
-}
-
-
-#if DEBUG_DUMP_JPEG_SNAPSHOT_TO_FILE || \
-    DEBUG_DUMP_YUV_SNAPSHOT_TO_FILE || \
-    DEBUG_DUMP_PREVIEW_FRAME_TO_FILE
-static void dump_to_file(const char *fname,
-                         uint8_t *buf, uint32_t size)
-{
-    int nw, cnt = 0;
-    uint32_t written = 0;
-
-    LOGV("opening file [%s]\n", fname);
-    int fd = open(fname, O_RDWR | O_CREAT);
-    if (fd < 0) {
-        LOGE("failed to create file [%s]: %s", fname, strerror(errno));
-        return;
-    }
-
-    LOGV("writing %d bytes to file [%s]\n", size, fname);
-    while (written < size) {
-        nw = ::write(fd,
-                     buf + written,
-                     size - written);
-        if (nw < 0) {
-            LOGE("failed to write to file [%s]: %s",
-                 fname, strerror(errno));
-            break;
-        }
-        written += nw;
-        cnt++;
-    }
-    LOGV("done writing %d bytes to file [%s] in %d passes\n",
-         size, fname, cnt);
-    ::close(fd);
-}
-#endif
-
-status_t CameraService::Client::autoFocus()
-{
-    LOGV("autoFocus (pid %d)", getCallingPid());
+status_t CameraService::Client::autoFocus() {
+    LOG1("autoFocus (pid %d)", getCallingPid());
 
     Mutex::Autolock lock(mLock);
-    status_t result = checkPid();
+    status_t result = checkPidAndHardware();
     if (result != NO_ERROR) return result;
 
-    if (mHardware == 0) {
-        LOGE("mHardware is NULL, returning.");
-        return INVALID_OPERATION;
-    }
-
     return mHardware->autoFocus();
 }
 
-status_t CameraService::Client::cancelAutoFocus()
-{
-    LOGV("cancelAutoFocus (pid %d)", getCallingPid());
+status_t CameraService::Client::cancelAutoFocus() {
+    LOG1("cancelAutoFocus (pid %d)", getCallingPid());
 
     Mutex::Autolock lock(mLock);
-    status_t result = checkPid();
+    status_t result = checkPidAndHardware();
     if (result != NO_ERROR) return result;
 
-    if (mHardware == 0) {
-        LOGE("mHardware is NULL, returning.");
-        return INVALID_OPERATION;
-    }
-
     return mHardware->cancelAutoFocus();
 }
 
 // take a picture - image is returned in callback
-status_t CameraService::Client::takePicture()
-{
-    LOGV("takePicture (pid %d)", getCallingPid());
+status_t CameraService::Client::takePicture() {
+    LOG1("takePicture (pid %d)", getCallingPid());
 
     Mutex::Autolock lock(mLock);
-    status_t result = checkPid();
+    status_t result = checkPidAndHardware();
     if (result != NO_ERROR) return result;
 
-    if (mHardware == 0) {
-        LOGE("mHardware is NULL, returning.");
-        return INVALID_OPERATION;
-    }
-
-    mHardware->enableMsgType(CAMERA_MSG_SHUTTER |
-                             CAMERA_MSG_POSTVIEW_FRAME |
-                             CAMERA_MSG_RAW_IMAGE |
-                             CAMERA_MSG_COMPRESSED_IMAGE);
+    enableMsgType(CAMERA_MSG_SHUTTER |
+                  CAMERA_MSG_POSTVIEW_FRAME |
+                  CAMERA_MSG_RAW_IMAGE |
+                  CAMERA_MSG_COMPRESSED_IMAGE);
 
     return mHardware->takePicture();
 }
 
-// snapshot taken
-void CameraService::Client::handleShutter(
-    image_rect_type *size // The width and height of yuv picture for
-                          // registerBuffer. If this is NULL, use the picture
-                          // size from parameters.
-)
-{
-    // Play shutter sound.
-    if (mMediaPlayerClick.get() != NULL) {
-        // do not play shutter sound if stream volume is 0
-        // (typically because ringer mode is silent).
-        int index;
-        AudioSystem::getStreamVolumeIndex(AudioSystem::ENFORCED_AUDIBLE, &index);
-        if (index != 0) {
-            mMediaPlayerClick->seekTo(0);
-            mMediaPlayerClick->start();
-        }
-    }
-
-    // Screen goes black after the buffer is unregistered.
-    if (mSurface != 0 && !mUseOverlay) {
-        mSurface->unregisterBuffers();
-    }
-
-    sp<ICameraClient> c = mCameraClient;
-    if (c != NULL) {
-        c->notifyCallback(CAMERA_MSG_SHUTTER, 0, 0);
-    }
-    mHardware->disableMsgType(CAMERA_MSG_SHUTTER);
-
-    // It takes some time before yuvPicture callback to be called.
-    // Register the buffer for raw image here to reduce latency.
-    if (mSurface != 0 && !mUseOverlay) {
-        int w, h;
-        CameraParameters params(mHardware->getParameters());
-        if (size == NULL) {
-            params.getPictureSize(&w, &h);
-        } else {
-            w = size->width;
-            h = size->height;
-            w &= ~1;
-            h &= ~1;
-            LOGV("Snapshot image width=%d, height=%d", w, h);
-        }
-        // FIXME: don't use hardcoded format constants here
-        ISurface::BufferHeap buffers(w, h, w, h,
-            HAL_PIXEL_FORMAT_YCrCb_420_SP, mOrientation, 0,
-            mHardware->getRawHeap());
-
-        mSurface->registerBuffers(buffers);
-    }
-}
-
-// preview callback - frame buffer update
-void CameraService::Client::handlePreviewData(const sp<IMemory>& mem)
-{
-    ssize_t offset;
-    size_t size;
-    sp<IMemoryHeap> heap = mem->getMemory(&offset, &size);
-
-#if DEBUG_HEAP_LEAKS && 0 // debugging
-    if (gWeakHeap == NULL) {
-        if (gWeakHeap != heap) {
-            LOGV("SETTING PREVIEW HEAP");
-            heap->trackMe(true, true);
-            gWeakHeap = heap;
-        }
-    }
-#endif
-#if DEBUG_DUMP_PREVIEW_FRAME_TO_FILE
-    {
-        if (debug_frame_cnt++ == DEBUG_DUMP_PREVIEW_FRAME_TO_FILE) {
-            dump_to_file("/data/preview.yuv",
-                         (uint8_t *)heap->base() + offset, size);
-        }
-    }
-#endif
-
-    if (!mUseOverlay)
-    {
-        Mutex::Autolock surfaceLock(mSurfaceLock);
-        if (mSurface != NULL) {
-            mSurface->postBuffer(offset);
-        }
-    }
-
-    // local copy of the callback flags
-    int flags = mPreviewCallbackFlag;
-
-    // is callback enabled?
-    if (!(flags & FRAME_CALLBACK_FLAG_ENABLE_MASK)) {
-        // If the enable bit is off, the copy-out and one-shot bits are ignored
-        LOGV("frame callback is diabled");
-        return;
-    }
-
-    // hold a strong pointer to the client
-    sp<ICameraClient> c = mCameraClient;
-
-    // clear callback flags if no client or one-shot mode
-    if ((c == NULL) || (mPreviewCallbackFlag & FRAME_CALLBACK_FLAG_ONE_SHOT_MASK)) {
-        LOGV("Disable preview callback");
-        mPreviewCallbackFlag &= ~(FRAME_CALLBACK_FLAG_ONE_SHOT_MASK |
-                                FRAME_CALLBACK_FLAG_COPY_OUT_MASK |
-                                FRAME_CALLBACK_FLAG_ENABLE_MASK);
-        // TODO: Shouldn't we use this API for non-overlay hardware as well?
-        if (mUseOverlay)
-            mHardware->disableMsgType(CAMERA_MSG_PREVIEW_FRAME);
-    }
-
-    // Is the received frame copied out or not?
-    if (flags & FRAME_CALLBACK_FLAG_COPY_OUT_MASK) {
-        LOGV("frame is copied");
-        copyFrameAndPostCopiedFrame(c, heap, offset, size);
-    } else {
-        LOGV("frame is forwarded");
-        c->dataCallback(CAMERA_MSG_PREVIEW_FRAME, mem);
-    }
-}
-
-// picture callback - postview image ready
-void CameraService::Client::handlePostview(const sp<IMemory>& mem)
-{
-#if DEBUG_DUMP_POSTVIEW_SNAPSHOT_TO_FILE // for testing pursposes only
-    {
-        ssize_t offset;
-        size_t size;
-        sp<IMemoryHeap> heap = mem->getMemory(&offset, &size);
-        dump_to_file("/data/postview.yuv",
-                     (uint8_t *)heap->base() + offset, size);
-    }
-#endif
-
-    sp<ICameraClient> c = mCameraClient;
-    if (c != NULL) {
-        c->dataCallback(CAMERA_MSG_POSTVIEW_FRAME, mem);
-    }
-    mHardware->disableMsgType(CAMERA_MSG_POSTVIEW_FRAME);
-}
-
-// picture callback - raw image ready
-void CameraService::Client::handleRawPicture(const sp<IMemory>& mem)
-{
-    ssize_t offset;
-    size_t size;
-    sp<IMemoryHeap> heap = mem->getMemory(&offset, &size);
-#if DEBUG_HEAP_LEAKS && 0 // debugging
-    gWeakHeap = heap; // debugging
-#endif
-
-    //LOGV("handleRawPicture(%d, %d)", offset, size);
-#if DEBUG_DUMP_YUV_SNAPSHOT_TO_FILE // for testing pursposes only
-    dump_to_file("/data/photo.yuv",
-                 (uint8_t *)heap->base() + offset, size);
-#endif
-
-    // Put the YUV version of the snapshot in the preview display.
-    if (mSurface != 0 && !mUseOverlay) {
-        mSurface->postBuffer(offset);
-    }
-
-    sp<ICameraClient> c = mCameraClient;
-    if (c != NULL) {
-        c->dataCallback(CAMERA_MSG_RAW_IMAGE, mem);
-    }
-    mHardware->disableMsgType(CAMERA_MSG_RAW_IMAGE);
-}
-
-// picture callback - compressed picture ready
-void CameraService::Client::handleCompressedPicture(const sp<IMemory>& mem)
-{
-#if DEBUG_DUMP_JPEG_SNAPSHOT_TO_FILE // for testing pursposes only
-    {
-        ssize_t offset;
-        size_t size;
-        sp<IMemoryHeap> heap = mem->getMemory(&offset, &size);
-        dump_to_file("/data/photo.jpg",
-                     (uint8_t *)heap->base() + offset, size);
-    }
-#endif
-
-    sp<ICameraClient> c = mCameraClient;
-    if (c != NULL) {
-        c->dataCallback(CAMERA_MSG_COMPRESSED_IMAGE, mem);
-    }
-    mHardware->disableMsgType(CAMERA_MSG_COMPRESSED_IMAGE);
-}
-
-void CameraService::Client::notifyCallback(int32_t msgType, int32_t ext1, int32_t ext2, void* user)
-{
-    LOGV("notifyCallback(%d)", msgType);
-
-    sp<Client> client = getClientFromCookie(user);
-    if (client == 0) {
-        return;
-    }
-
-    switch (msgType) {
-        case CAMERA_MSG_SHUTTER:
-            // ext1 is the dimension of the yuv picture.
-            client->handleShutter((image_rect_type *)ext1);
-            break;
-        default:
-            sp<ICameraClient> c = client->mCameraClient;
-            if (c != NULL) {
-                c->notifyCallback(msgType, ext1, ext2);
-            }
-            break;
-    }
-
-#if DEBUG_CLIENT_REFERENCES
-    if (client->getStrongCount() == 1) {
-        LOGE("++++++++++++++++ (NOTIFY CALLBACK) THIS WILL CAUSE A LOCKUP!");
-        client->printRefs();
-    }
-#endif
-}
-
-void CameraService::Client::dataCallback(int32_t msgType, const sp<IMemory>& dataPtr, void* user)
-{
-    LOGV("dataCallback(%d)", msgType);
-
-    sp<Client> client = getClientFromCookie(user);
-    if (client == 0) {
-        return;
-    }
-
-    sp<ICameraClient> c = client->mCameraClient;
-    if (dataPtr == NULL) {
-        LOGE("Null data returned in data callback");
-        if (c != NULL) {
-            c->notifyCallback(CAMERA_MSG_ERROR, UNKNOWN_ERROR, 0);
-            c->dataCallback(msgType, NULL);
-        }
-        return;
-    }
-
-    switch (msgType) {
-        case CAMERA_MSG_PREVIEW_FRAME:
-            client->handlePreviewData(dataPtr);
-            break;
-        case CAMERA_MSG_POSTVIEW_FRAME:
-            client->handlePostview(dataPtr);
-            break;
-        case CAMERA_MSG_RAW_IMAGE:
-            client->handleRawPicture(dataPtr);
-            break;
-        case CAMERA_MSG_COMPRESSED_IMAGE:
-            client->handleCompressedPicture(dataPtr);
-            break;
-        default:
-            if (c != NULL) {
-                c->dataCallback(msgType, dataPtr);
-            }
-            break;
-    }
-
-#if DEBUG_CLIENT_REFERENCES
-    if (client->getStrongCount() == 1) {
-        LOGE("++++++++++++++++ (DATA CALLBACK) THIS WILL CAUSE A LOCKUP!");
-        client->printRefs();
-    }
-#endif
-}
-
-void CameraService::Client::dataCallbackTimestamp(nsecs_t timestamp, int32_t msgType,
-                                                  const sp<IMemory>& dataPtr, void* user)
-{
-    LOGV("dataCallbackTimestamp(%d)", msgType);
-
-    sp<Client> client = getClientFromCookie(user);
-    if (client == 0) {
-        return;
-    }
-    sp<ICameraClient> c = client->mCameraClient;
-
-    if (dataPtr == NULL) {
-        LOGE("Null data returned in data with timestamp callback");
-        if (c != NULL) {
-            c->notifyCallback(CAMERA_MSG_ERROR, UNKNOWN_ERROR, 0);
-            c->dataCallbackTimestamp(0, msgType, NULL);
-        }
-        return;
-    }
-
-    if (c != NULL) {
-        c->dataCallbackTimestamp(timestamp, msgType, dataPtr);
-    }
-
-#if DEBUG_CLIENT_REFERENCES
-    if (client->getStrongCount() == 1) {
-        LOGE("++++++++++++++++ (DATA CALLBACK TIMESTAMP) THIS WILL CAUSE A LOCKUP!");
-        client->printRefs();
-    }
-#endif
-}
-
 // set preview/capture parameters - key/value pairs
-status_t CameraService::Client::setParameters(const String8& params)
-{
-    LOGV("setParameters(%s)", params.string());
+status_t CameraService::Client::setParameters(const String8& params) {
+    LOG1("setParameters (pid %d) (%s)", getCallingPid(), params.string());
 
     Mutex::Autolock lock(mLock);
-    status_t result = checkPid();
+    status_t result = checkPidAndHardware();
     if (result != NO_ERROR) return result;
 
-    if (mHardware == 0) {
-        LOGE("mHardware is NULL, returning.");
-        return INVALID_OPERATION;
-    }
-
     CameraParameters p(params);
-
     return mHardware->setParameters(p);
 }
 
 // get preview/capture parameters - key/value pairs
-String8 CameraService::Client::getParameters() const
-{
+String8 CameraService::Client::getParameters() const {
     Mutex::Autolock lock(mLock);
-
-    if (mHardware == 0) {
-        LOGE("mHardware is NULL, returning.");
-        return String8();
-    }
+    if (checkPidAndHardware() != NO_ERROR) return String8();
 
     String8 params(mHardware->getParameters().flatten());
-    LOGV("getParameters(%s)", params.string());
+    LOG1("getParameters (pid %d) (%s)", getCallingPid(), params.string());
     return params;
 }
 
-status_t CameraService::Client::sendCommand(int32_t cmd, int32_t arg1, int32_t arg2)
-{
-    LOGV("sendCommand (pid %d)", getCallingPid());
+status_t CameraService::Client::sendCommand(int32_t cmd, int32_t arg1, int32_t arg2) {
+    LOG1("sendCommand (pid %d)", getCallingPid());
     Mutex::Autolock lock(mLock);
-    status_t result = checkPid();
+    status_t result = checkPidAndHardware();
     if (result != NO_ERROR) return result;
 
     if (cmd == CAMERA_CMD_SET_DISPLAY_ORIENTATION) {
@@ -1247,50 +852,365 @@
         return OK;
     }
 
-    if (mHardware == 0) {
-        LOGE("mHardware is NULL, returning.");
-        return INVALID_OPERATION;
-    }
-
     return mHardware->sendCommand(cmd, arg1, arg2);
 }
 
-void CameraService::Client::copyFrameAndPostCopiedFrame(const sp<ICameraClient>& client,
-        const sp<IMemoryHeap>& heap, size_t offset, size_t size)
-{
-    LOGV("copyFrameAndPostCopiedFrame");
+// ----------------------------------------------------------------------------
+
+void CameraService::Client::enableMsgType(int32_t msgType) {
+    android_atomic_or(msgType, &mMsgEnabled);
+    mHardware->enableMsgType(msgType);
+}
+
+void CameraService::Client::disableMsgType(int32_t msgType) {
+    android_atomic_and(~msgType, &mMsgEnabled);
+    mHardware->disableMsgType(msgType);
+}
+
+#define CHECK_MESSAGE_INTERVAL 10 // 10ms
+bool CameraService::Client::lockIfMessageWanted(int32_t msgType) {
+    int sleepCount = 0;
+    while (mMsgEnabled & msgType) {
+        if (mLock.tryLock() == NO_ERROR) {
+            if (sleepCount > 0) {
+                LOG1("lockIfMessageWanted(%d): waited for %d ms",
+                    msgType, sleepCount * CHECK_MESSAGE_INTERVAL);
+            }
+            return true;
+        }
+        if (sleepCount++ == 0) {
+            LOG1("lockIfMessageWanted(%d): enter sleep", msgType);
+        }
+        usleep(CHECK_MESSAGE_INTERVAL * 1000);
+    }
+    LOGW("lockIfMessageWanted(%d): dropped unwanted message", msgType);
+    return false;
+}
+
+// ----------------------------------------------------------------------------
+
+// Converts from a raw pointer to the client to a strong pointer during a
+// hardware callback. This requires the callbacks only happen when the client
+// is still alive.
+sp<CameraService::Client> CameraService::Client::getClientFromCookie(void* user) {
+    sp<Client> client = gCameraService->getClientById((int) user);
+
+    // This could happen if the Client is in the process of shutting down (the
+    // last strong reference is gone, but the destructor hasn't finished
+    // stopping the hardware).
+    if (client == 0) return NULL;
+
+    // The checks below are not necessary and are for debugging only.
+    if (client->mCameraService.get() != gCameraService) {
+        LOGE("mismatch service!");
+        return NULL;
+    }
+
+    if (client->mHardware == 0) {
+        LOGE("mHardware == 0: callback after disconnect()?");
+        return NULL;
+    }
+
+    return client;
+}
+
+// Callback messages can be dispatched to internal handlers or pass to our
+// client's callback functions, depending on the message type.
+//
+// notifyCallback:
+//      CAMERA_MSG_SHUTTER              handleShutter
+//      (others)                        c->notifyCallback
+// dataCallback:
+//      CAMERA_MSG_PREVIEW_FRAME        handlePreviewData
+//      CAMERA_MSG_POSTVIEW_FRAME       handlePostview
+//      CAMERA_MSG_RAW_IMAGE            handleRawPicture
+//      CAMERA_MSG_COMPRESSED_IMAGE     handleCompressedPicture
+//      (others)                        c->dataCallback
+// dataCallbackTimestamp
+//      (others)                        c->dataCallbackTimestamp
+//
+// NOTE: the *Callback functions grab mLock of the client before passing
+// control to handle* functions. So the handle* functions must release the
+// lock before calling the ICameraClient's callbacks, so those callbacks can
+// invoke methods in the Client class again (For example, the preview frame
+// callback may want to releaseRecordingFrame). The handle* functions must
+// release the lock after all accesses to member variables, so it must be
+// handled very carefully.
+
+void CameraService::Client::notifyCallback(int32_t msgType, int32_t ext1,
+        int32_t ext2, void* user) {
+    LOG2("notifyCallback(%d)", msgType);
+
+    sp<Client> client = getClientFromCookie(user);
+    if (client == 0) return;
+    if (!client->lockIfMessageWanted(msgType)) return;
+
+    switch (msgType) {
+        case CAMERA_MSG_SHUTTER:
+            // ext1 is the dimension of the yuv picture.
+            client->handleShutter((image_rect_type *)ext1);
+            break;
+        default:
+            client->handleGenericNotify(msgType, ext1, ext2);
+            break;
+    }
+}
+
+void CameraService::Client::dataCallback(int32_t msgType,
+        const sp<IMemory>& dataPtr, void* user) {
+    LOG2("dataCallback(%d)", msgType);
+
+    sp<Client> client = getClientFromCookie(user);
+    if (client == 0) return;
+    if (!client->lockIfMessageWanted(msgType)) return;
+
+    if (dataPtr == 0) {
+        LOGE("Null data returned in data callback");
+        client->handleGenericNotify(CAMERA_MSG_ERROR, UNKNOWN_ERROR, 0);
+        return;
+    }
+
+    switch (msgType) {
+        case CAMERA_MSG_PREVIEW_FRAME:
+            client->handlePreviewData(dataPtr);
+            break;
+        case CAMERA_MSG_POSTVIEW_FRAME:
+            client->handlePostview(dataPtr);
+            break;
+        case CAMERA_MSG_RAW_IMAGE:
+            client->handleRawPicture(dataPtr);
+            break;
+        case CAMERA_MSG_COMPRESSED_IMAGE:
+            client->handleCompressedPicture(dataPtr);
+            break;
+        default:
+            client->handleGenericData(msgType, dataPtr);
+            break;
+    }
+}
+
+void CameraService::Client::dataCallbackTimestamp(nsecs_t timestamp,
+        int32_t msgType, const sp<IMemory>& dataPtr, void* user) {
+    LOG2("dataCallbackTimestamp(%d)", msgType);
+
+    sp<Client> client = getClientFromCookie(user);
+    if (client == 0) return;
+    if (!client->lockIfMessageWanted(msgType)) return;
+
+    if (dataPtr == 0) {
+        LOGE("Null data returned in data with timestamp callback");
+        client->handleGenericNotify(CAMERA_MSG_ERROR, UNKNOWN_ERROR, 0);
+        return;
+    }
+
+    client->handleGenericDataTimestamp(timestamp, msgType, dataPtr);
+}
+
+// snapshot taken callback
+// "size" is the width and height of yuv picture for registerBuffer.
+// If it is NULL, use the picture size from parameters.
+void CameraService::Client::handleShutter(image_rect_type *size) {
+    mCameraService->playSound(SOUND_SHUTTER);
+
+    // Screen goes black after the buffer is unregistered.
+    if (mSurface != 0 && !mUseOverlay) {
+        mSurface->unregisterBuffers();
+    }
+
+    sp<ICameraClient> c = mCameraClient;
+    if (c != 0) {
+        mLock.unlock();
+        c->notifyCallback(CAMERA_MSG_SHUTTER, 0, 0);
+        if (!lockIfMessageWanted(CAMERA_MSG_SHUTTER)) return;
+    }
+    disableMsgType(CAMERA_MSG_SHUTTER);
+
+    // It takes some time before yuvPicture callback to be called.
+    // Register the buffer for raw image here to reduce latency.
+    if (mSurface != 0 && !mUseOverlay) {
+        int w, h;
+        CameraParameters params(mHardware->getParameters());
+        if (size == NULL) {
+            params.getPictureSize(&w, &h);
+        } else {
+            w = size->width;
+            h = size->height;
+            w &= ~1;
+            h &= ~1;
+            LOG1("Snapshot image width=%d, height=%d", w, h);
+        }
+        // FIXME: don't use hardcoded format constants here
+        ISurface::BufferHeap buffers(w, h, w, h,
+            HAL_PIXEL_FORMAT_YCrCb_420_SP, mOrientation, 0,
+            mHardware->getRawHeap());
+
+        mSurface->registerBuffers(buffers);
+    }
+
+    mLock.unlock();
+}
+
+// preview callback - frame buffer update
+void CameraService::Client::handlePreviewData(const sp<IMemory>& mem) {
+    ssize_t offset;
+    size_t size;
+    sp<IMemoryHeap> heap = mem->getMemory(&offset, &size);
+
+    if (!mUseOverlay) {
+        if (mSurface != 0) {
+            mSurface->postBuffer(offset);
+        }
+    }
+
+    // local copy of the callback flags
+    int flags = mPreviewCallbackFlag;
+
+    // is callback enabled?
+    if (!(flags & FRAME_CALLBACK_FLAG_ENABLE_MASK)) {
+        // If the enable bit is off, the copy-out and one-shot bits are ignored
+        LOG2("frame callback is disabled");
+        mLock.unlock();
+        return;
+    }
+
+    // hold a strong pointer to the client
+    sp<ICameraClient> c = mCameraClient;
+
+    // clear callback flags if no client or one-shot mode
+    if (c == 0 || (mPreviewCallbackFlag & FRAME_CALLBACK_FLAG_ONE_SHOT_MASK)) {
+        LOG2("Disable preview callback");
+        mPreviewCallbackFlag &= ~(FRAME_CALLBACK_FLAG_ONE_SHOT_MASK |
+                                  FRAME_CALLBACK_FLAG_COPY_OUT_MASK |
+                                  FRAME_CALLBACK_FLAG_ENABLE_MASK);
+        if (mUseOverlay) {
+            disableMsgType(CAMERA_MSG_PREVIEW_FRAME);
+        }
+    }
+
+    if (c != 0) {
+        // Is the received frame copied out or not?
+        if (flags & FRAME_CALLBACK_FLAG_COPY_OUT_MASK) {
+            LOG2("frame is copied");
+            copyFrameAndPostCopiedFrame(c, heap, offset, size);
+        } else {
+            LOG2("frame is forwarded");
+            mLock.unlock();
+            c->dataCallback(CAMERA_MSG_PREVIEW_FRAME, mem);
+        }
+    } else {
+        mLock.unlock();
+    }
+}
+
+// picture callback - postview image ready
+void CameraService::Client::handlePostview(const sp<IMemory>& mem) {
+    disableMsgType(CAMERA_MSG_POSTVIEW_FRAME);
+
+    sp<ICameraClient> c = mCameraClient;
+    mLock.unlock();
+    if (c != 0) {
+        c->dataCallback(CAMERA_MSG_POSTVIEW_FRAME, mem);
+    }
+}
+
+// picture callback - raw image ready
+void CameraService::Client::handleRawPicture(const sp<IMemory>& mem) {
+    disableMsgType(CAMERA_MSG_RAW_IMAGE);
+
+    ssize_t offset;
+    size_t size;
+    sp<IMemoryHeap> heap = mem->getMemory(&offset, &size);
+
+    // Put the YUV version of the snapshot in the preview display.
+    if (mSurface != 0 && !mUseOverlay) {
+        mSurface->postBuffer(offset);
+    }
+
+    sp<ICameraClient> c = mCameraClient;
+    mLock.unlock();
+    if (c != 0) {
+        c->dataCallback(CAMERA_MSG_RAW_IMAGE, mem);
+    }
+}
+
+// picture callback - compressed picture ready
+void CameraService::Client::handleCompressedPicture(const sp<IMemory>& mem) {
+    disableMsgType(CAMERA_MSG_COMPRESSED_IMAGE);
+
+    sp<ICameraClient> c = mCameraClient;
+    mLock.unlock();
+    if (c != 0) {
+        c->dataCallback(CAMERA_MSG_COMPRESSED_IMAGE, mem);
+    }
+}
+
+
+void CameraService::Client::handleGenericNotify(int32_t msgType,
+    int32_t ext1, int32_t ext2) {
+    sp<ICameraClient> c = mCameraClient;
+    mLock.unlock();
+    if (c != 0) {
+        c->notifyCallback(msgType, ext1, ext2);
+    }
+}
+
+void CameraService::Client::handleGenericData(int32_t msgType,
+    const sp<IMemory>& dataPtr) {
+    sp<ICameraClient> c = mCameraClient;
+    mLock.unlock();
+    if (c != 0) {
+        c->dataCallback(msgType, dataPtr);
+    }
+}
+
+void CameraService::Client::handleGenericDataTimestamp(nsecs_t timestamp,
+    int32_t msgType, const sp<IMemory>& dataPtr) {
+    sp<ICameraClient> c = mCameraClient;
+    mLock.unlock();
+    if (c != 0) {
+        c->dataCallbackTimestamp(timestamp, msgType, dataPtr);
+    }
+}
+
+void CameraService::Client::copyFrameAndPostCopiedFrame(
+        const sp<ICameraClient>& client, const sp<IMemoryHeap>& heap,
+        size_t offset, size_t size) {
+    LOG2("copyFrameAndPostCopiedFrame");
     // It is necessary to copy out of pmem before sending this to
     // the callback. For efficiency, reuse the same MemoryHeapBase
     // provided it's big enough. Don't allocate the memory or
     // perform the copy if there's no callback.
-
     // hold the preview lock while we grab a reference to the preview buffer
     sp<MemoryHeapBase> previewBuffer;
-    {
-        Mutex::Autolock lock(mPreviewLock);
-        if (mPreviewBuffer == 0) {
-            mPreviewBuffer = new MemoryHeapBase(size, 0, NULL);
-        } else if (size > mPreviewBuffer->virtualSize()) {
-            mPreviewBuffer.clear();
-            mPreviewBuffer = new MemoryHeapBase(size, 0, NULL);
-        }
-        if (mPreviewBuffer == 0) {
-            LOGE("failed to allocate space for preview buffer");
-            return;
-        }
-        previewBuffer = mPreviewBuffer;
+
+    if (mPreviewBuffer == 0) {
+        mPreviewBuffer = new MemoryHeapBase(size, 0, NULL);
+    } else if (size > mPreviewBuffer->virtualSize()) {
+        mPreviewBuffer.clear();
+        mPreviewBuffer = new MemoryHeapBase(size, 0, NULL);
     }
-    memcpy(previewBuffer->base(),
-           (uint8_t *)heap->base() + offset, size);
+    if (mPreviewBuffer == 0) {
+        LOGE("failed to allocate space for preview buffer");
+        mLock.unlock();
+        return;
+    }
+    previewBuffer = mPreviewBuffer;
+
+    memcpy(previewBuffer->base(), (uint8_t *)heap->base() + offset, size);
 
     sp<MemoryBase> frame = new MemoryBase(previewBuffer, 0, size);
     if (frame == 0) {
         LOGE("failed to allocate space for frame callback");
+        mLock.unlock();
         return;
     }
+
+    mLock.unlock();
     client->dataCallback(CAMERA_MSG_PREVIEW_FRAME, frame);
 }
 
+// ----------------------------------------------------------------------------
+
 static const int kDumpLockRetries = 50;
 static const int kDumpLockSleep = 60000;
 
@@ -1307,8 +1227,7 @@
     return locked;
 }
 
-status_t CameraService::dump(int fd, const Vector<String16>& args)
-{
+status_t CameraService::dump(int fd, const Vector<String16>& args) {
     static const char* kDeadlockedString = "CameraService may be deadlocked\n";
 
     const size_t SIZE = 256;
@@ -1318,7 +1237,7 @@
         snprintf(buffer, SIZE, "Permission Denial: "
                 "can't dump CameraService from pid=%d, uid=%d\n",
                 getCallingPid(),
-                IPCThreadState::self()->getCallingUid());
+                getCallingUid());
         result.append(buffer);
         write(fd, result.string(), result.size());
     } else {
@@ -1329,89 +1248,39 @@
             write(fd, result.string(), result.size());
         }
 
-        if (mClient != 0) {
-            sp<Client> currentClient = mClient.promote();
-            sprintf(buffer, "Client (%p) PID: %d\n",
-                    currentClient->getCameraClient()->asBinder().get(),
-                    currentClient->mClientPid);
+        bool hasClient = false;
+        for (int i = 0; i < NUM_CAMERAS; i++) {
+            sp<Client> client = mClient[i].promote();
+            if (client == 0) continue;
+            hasClient = true;
+            sprintf(buffer, "Client[%d] (%p) PID: %d\n",
+                    i,
+                    client->getCameraClient()->asBinder().get(),
+                    client->mClientPid);
             result.append(buffer);
             write(fd, result.string(), result.size());
-            currentClient->mHardware->dump(fd, args);
-        } else {
+            client->mHardware->dump(fd, args);
+        }
+        if (!hasClient) {
             result.append("No camera client yet.\n");
             write(fd, result.string(), result.size());
         }
 
         if (locked) mServiceLock.unlock();
+
+        // change logging level
+        int n = args.size();
+        for (int i = 0; i + 1 < n; i++) {
+            if (args[i] == String16("-v")) {
+                String8 levelStr(args[i+1]);
+                int level = atoi(levelStr.string());
+                sprintf(buffer, "Set Log Level to %d", level);
+                result.append(buffer);
+                setLogLevel(level);
+            }
+        }
     }
     return NO_ERROR;
 }
 
-
-status_t CameraService::onTransact(
-    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
-{
-    // permission checks...
-    switch (code) {
-        case BnCameraService::CONNECT:
-            IPCThreadState* ipc = IPCThreadState::self();
-            const int pid = ipc->getCallingPid();
-            const int self_pid = getpid();
-            if (pid != self_pid) {
-                // we're called from a different process, do the real check
-                if (!checkCallingPermission(
-                        String16("android.permission.CAMERA")))
-                {
-                    const int uid = ipc->getCallingUid();
-                    LOGE("Permission Denial: "
-                            "can't use the camera pid=%d, uid=%d", pid, uid);
-                    return PERMISSION_DENIED;
-                }
-            }
-            break;
-    }
-
-    status_t err = BnCameraService::onTransact(code, data, reply, flags);
-
-#if DEBUG_HEAP_LEAKS
-    LOGV("+++ onTransact err %d code %d", err, code);
-
-    if (err == UNKNOWN_TRANSACTION || err == PERMISSION_DENIED) {
-        // the 'service' command interrogates this binder for its name, and then supplies it
-        // even for the debugging commands.  that means we need to check for it here, using
-        // ISurfaceComposer (since we delegated the INTERFACE_TRANSACTION handling to
-        // BnSurfaceComposer before falling through to this code).
-
-        LOGV("+++ onTransact code %d", code);
-
-        CHECK_INTERFACE(ICameraService, data, reply);
-
-        switch(code) {
-        case 1000:
-        {
-            if (gWeakHeap != 0) {
-                sp<IMemoryHeap> h = gWeakHeap.promote();
-                IMemoryHeap *p = gWeakHeap.unsafe_get();
-                LOGV("CHECKING WEAK REFERENCE %p (%p)", h.get(), p);
-                if (h != 0)
-                    h->printRefs();
-                bool attempt_to_delete = data.readInt32() == 1;
-                if (attempt_to_delete) {
-                    // NOT SAFE!
-                    LOGV("DELETING WEAK REFERENCE %p (%p)", h.get(), p);
-                    if (p) delete p;
-                }
-                return NO_ERROR;
-            }
-        }
-        break;
-        default:
-            break;
-        }
-    }
-#endif // DEBUG_HEAP_LEAKS
-
-    return err;
-}
-
 }; // namespace android
diff --git a/camera/libcameraservice/CameraService.h b/camera/libcameraservice/CameraService.h
index bc49b1d..86986ca 100644
--- a/camera/libcameraservice/CameraService.h
+++ b/camera/libcameraservice/CameraService.h
@@ -21,207 +21,171 @@
 
 #include <camera/ICameraService.h>
 #include <camera/CameraHardwareInterface.h>
-#include <camera/Camera.h>
+
+/* This needs to be increased if we can have more cameras */
+#define MAX_CAMERAS 2
 
 namespace android {
 
 class MemoryHeapBase;
 class MediaPlayer;
 
-// ----------------------------------------------------------------------------
-
-#define LIKELY( exp )       (__builtin_expect( (exp) != 0, true  ))
-#define UNLIKELY( exp )     (__builtin_expect( (exp) != 0, false ))
-
-// When enabled, this feature allows you to send an event to the CameraService
-// so that you can cause all references to the heap object gWeakHeap, defined
-// below, to be printed. You will also need to set DEBUG_REFS=1 and
-// DEBUG_REFS_ENABLED_BY_DEFAULT=0 in libutils/RefBase.cpp. You just have to
-// set gWeakHeap to the appropriate heap you want to track.
-
-#define DEBUG_HEAP_LEAKS 0
-
-// ----------------------------------------------------------------------------
-
-class CameraService : public BnCameraService
+class CameraService: public BnCameraService
 {
     class Client;
-
 public:
-    static void instantiate();
+    static void         instantiate();
 
-    // ICameraService interface
-    virtual sp<ICamera>     connect(const sp<ICameraClient>& cameraClient);
+                        CameraService();
+    virtual             ~CameraService();
 
-    virtual status_t        dump(int fd, const Vector<String16>& args);
+    virtual int32_t     getNumberOfCameras();
+    virtual sp<ICamera> connect(const sp<ICameraClient>& cameraClient, int cameraId);
+    virtual void        removeClient(const sp<ICameraClient>& cameraClient);
+    virtual sp<Client>  getClientById(int cameraId);
 
-            void            removeClient(const sp<ICameraClient>& cameraClient);
+    virtual status_t    dump(int fd, const Vector<String16>& args);
+    virtual status_t    onTransact(uint32_t code, const Parcel& data,
+                                   Parcel* reply, uint32_t flags);
 
-    virtual status_t onTransact(
-        uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags);
+    enum sound_kind {
+        SOUND_SHUTTER = 0,
+        SOUND_RECORDING = 1,
+        NUM_SOUNDS
+    };
+
+    void                loadSound();
+    void                playSound(sound_kind kind);
+    void                releaseSound();
 
 private:
+    Mutex               mServiceLock;
+    wp<Client>          mClient[MAX_CAMERAS];  // protected by mServiceLock
 
-// ----------------------------------------------------------------------------
+    // atomics to record whether the hardware is allocated to some client.
+    volatile int32_t    mBusy[MAX_CAMERAS];
+    void                setCameraBusy(int cameraId);
+    void                setCameraFree(int cameraId);
 
-    class Client : public BnCamera {
+    // sounds
+    Mutex               mSoundLock;
+    sp<MediaPlayer>     mSoundPlayer[NUM_SOUNDS];
+    int                 mSoundRef;  // reference count (release all MediaPlayer when 0)
 
+    class Client : public BnCamera
+    {
     public:
+        // ICamera interface (see ICamera for details)
         virtual void            disconnect();
-
-        // connect new client with existing camera remote
         virtual status_t        connect(const sp<ICameraClient>& client);
-
-        // prevent other processes from using this ICamera interface
         virtual status_t        lock();
-
-        // allow other processes to use this ICamera interface
         virtual status_t        unlock();
-
-        // pass the buffered ISurface to the camera service
         virtual status_t        setPreviewDisplay(const sp<ISurface>& surface);
-
-        // set the preview callback flag to affect how the received frames from
-        // preview are handled.
-        virtual void            setPreviewCallbackFlag(int callback_flag);
-
-        // start preview mode, must call setPreviewDisplay first
+        virtual void            setPreviewCallbackFlag(int flag);
         virtual status_t        startPreview();
-
-        // stop preview mode
         virtual void            stopPreview();
-
-        // get preview state
         virtual bool            previewEnabled();
-
-        // start recording mode
         virtual status_t        startRecording();
-
-        // stop recording mode
         virtual void            stopRecording();
-
-        // get recording state
         virtual bool            recordingEnabled();
-
-        // release a recording frame
         virtual void            releaseRecordingFrame(const sp<IMemory>& mem);
-
-        // auto focus
         virtual status_t        autoFocus();
-
-        // cancel auto focus
         virtual status_t        cancelAutoFocus();
-
-        // take a picture - returns an IMemory (ref-counted mmap)
         virtual status_t        takePicture();
-
-        // set preview/capture parameters - key/value pairs
         virtual status_t        setParameters(const String8& params);
-
-        // get preview/capture parameters - key/value pairs
         virtual String8         getParameters() const;
-
-        // send command to camera driver
         virtual status_t        sendCommand(int32_t cmd, int32_t arg1, int32_t arg2);
-
-        // our client...
-        const sp<ICameraClient>&    getCameraClient() const { return mCameraClient; }
-
     private:
         friend class CameraService;
                                 Client(const sp<CameraService>& cameraService,
-                                        const sp<ICameraClient>& cameraClient,
-                                        pid_t clientPid);
-                                Client();
-        virtual                 ~Client();
+                                       const sp<ICameraClient>& cameraClient,
+                                       int cameraId,
+                                       int clientPid);
+                                ~Client();
 
-                    status_t    checkPid();
+        // return our camera client
+        const sp<ICameraClient>&    getCameraClient() { return mCameraClient; }
 
-        static      void        notifyCallback(int32_t msgType, int32_t ext1, int32_t ext2, void* user);
-        static      void        dataCallback(int32_t msgType, const sp<IMemory>& dataPtr, void* user);
-        static      void        dataCallbackTimestamp(nsecs_t timestamp, int32_t msgType,
-                                                      const sp<IMemory>& dataPtr, void* user);
+        // check whether the calling process matches mClientPid.
+        status_t                checkPid() const;
+        status_t                checkPidAndHardware() const;  // also check mHardware != 0
 
-        static      sp<Client>  getClientFromCookie(void* user);
-
-                    void        handlePreviewData(const sp<IMemory>&);
-                    void        handleShutter(image_rect_type *image);
-                    void        handlePostview(const sp<IMemory>&);
-                    void        handleRawPicture(const sp<IMemory>&);
-                    void        handleCompressedPicture(const sp<IMemory>&);
-
-                    void        copyFrameAndPostCopiedFrame(const sp<ICameraClient>& client,
-                                    const sp<IMemoryHeap>& heap, size_t offset, size_t size);
+        // these are internal functions used to set up preview buffers
+        status_t                registerPreviewBuffers();
+        status_t                setOverlay();
 
         // camera operation mode
         enum camera_mode {
             CAMERA_PREVIEW_MODE   = 0,  // frame automatically released
             CAMERA_RECORDING_MODE = 1,  // frame has to be explicitly released by releaseRecordingFrame()
         };
+        // these are internal functions used for preview/recording
         status_t                startCameraMode(camera_mode mode);
         status_t                startPreviewMode();
         status_t                startRecordingMode();
-        status_t                setOverlay();
-        status_t                registerPreviewBuffers();
+
+        // these are static callback functions
+        static void             notifyCallback(int32_t msgType, int32_t ext1, int32_t ext2, void* user);
+        static void             dataCallback(int32_t msgType, const sp<IMemory>& dataPtr, void* user);
+        static void             dataCallbackTimestamp(nsecs_t timestamp, int32_t msgType, const sp<IMemory>& dataPtr, void* user);
+        // convert client from cookie
+        static sp<Client>       getClientFromCookie(void* user);
+        // handlers for messages
+        void                    handleShutter(image_rect_type *size);
+        void                    handlePreviewData(const sp<IMemory>& mem);
+        void                    handlePostview(const sp<IMemory>& mem);
+        void                    handleRawPicture(const sp<IMemory>& mem);
+        void                    handleCompressedPicture(const sp<IMemory>& mem);
+        void                    handleGenericNotify(int32_t msgType, int32_t ext1, int32_t ext2);
+        void                    handleGenericData(int32_t msgType, const sp<IMemory>& dataPtr);
+        void                    handleGenericDataTimestamp(nsecs_t timestamp, int32_t msgType, const sp<IMemory>& dataPtr);
+
+        void                    copyFrameAndPostCopiedFrame(
+                                    const sp<ICameraClient>& client,
+                                    const sp<IMemoryHeap>& heap,
+                                    size_t offset, size_t size);
+
+        // these are initialized in the constructor.
+        sp<CameraService>               mCameraService;  // immutable after constructor
+        sp<ICameraClient>               mCameraClient;
+        int                             mCameraId;       // immutable after constructor
+        pid_t                           mClientPid;
+        sp<CameraHardwareInterface>     mHardware;       // cleared after disconnect()
+        bool                            mUseOverlay;     // immutable after constructor
+        sp<OverlayRef>                  mOverlayRef;
+        int                             mOverlayW;
+        int                             mOverlayH;
+        int                             mPreviewCallbackFlag;
+        int                             mOrientation;
 
         // Ensures atomicity among the public methods
-        mutable     Mutex                       mLock;
+        mutable Mutex                   mLock;
+        sp<ISurface>                    mSurface;
 
-        // mSurfaceLock synchronizes access to mSurface between
-        // setPreviewSurface() and postPreviewFrame().  Note that among
-        // the public methods, all accesses to mSurface are
-        // syncrhonized by mLock.  However, postPreviewFrame() is called
-        // by the CameraHardwareInterface callback, and needs to
-        // access mSurface.  It cannot hold mLock, however, because
-        // stopPreview() may be holding that lock while attempting
-        // to stop preview, and stopPreview itself will block waiting
-        // for a callback from CameraHardwareInterface.  If this
-        // happens, it will cause a deadlock.
-        mutable     Mutex                       mSurfaceLock;
-        mutable     Condition                   mReady;
-                    sp<CameraService>           mCameraService;
-                    sp<ISurface>                mSurface;
-                    int                         mPreviewCallbackFlag;
-                    int                         mOrientation;
+        // If the user want us to return a copy of the preview frame (instead
+        // of the original one), we allocate mPreviewBuffer and reuse it if possible.
+        sp<MemoryHeapBase>              mPreviewBuffer;
 
-                    sp<MediaPlayer>             mMediaPlayerClick;
-                    sp<MediaPlayer>             mMediaPlayerBeep;
+        // We need to avoid the deadlock when the incoming command thread and
+        // the CameraHardwareInterface callback thread both want to grab mLock.
+        // An extra flag is used to tell the callback thread that it should stop
+        // trying to deliver the callback messages if the client is not
+        // interested in it anymore. For example, if the client is calling
+        // stopPreview(), the preview frame messages do not need to be delivered
+        // anymore.
 
-                    // these are immutable once the object is created,
-                    // they don't need to be protected by a lock
-                    sp<ICameraClient>           mCameraClient;
-                    sp<CameraHardwareInterface> mHardware;
-                    pid_t                       mClientPid;
-                    bool                        mUseOverlay;
+        // This function takes the same parameter as the enableMsgType() and
+        // disableMsgType() functions in CameraHardwareInterface.
+        void                    enableMsgType(int32_t msgType);
+        void                    disableMsgType(int32_t msgType);
+        volatile int32_t        mMsgEnabled;
 
-                    sp<OverlayRef>              mOverlayRef;
-                    int                         mOverlayW;
-                    int                         mOverlayH;
-
-        mutable     Mutex                       mPreviewLock;
-                    sp<MemoryHeapBase>          mPreviewBuffer;
+        // This function keeps trying to grab mLock, or give up if the message
+        // is found to be disabled. It returns true if mLock is grabbed.
+        bool                    lockIfMessageWanted(int32_t msgType);
     };
-
-// ----------------------------------------------------------------------------
-
-                            CameraService();
-    virtual                 ~CameraService();
-
-    // We use a count for number of clients (shoule only be 0 or 1).
-    volatile    int32_t                     mUsers;
-    virtual     void                        incUsers();
-    virtual     void                        decUsers();
-
-    mutable     Mutex                       mServiceLock;
-                wp<Client>                  mClient;
-
-#if DEBUG_HEAP_LEAKS
-                wp<IMemoryHeap>             gWeakHeap;
-#endif
 };
 
-// ----------------------------------------------------------------------------
-
-}; // namespace android
+} // namespace android
 
 #endif
diff --git a/camera/libcameraservice/FakeCamera.cpp b/camera/libcameraservice/FakeCamera.cpp
index 6749899..f3a6a67 100644
--- a/camera/libcameraservice/FakeCamera.cpp
+++ b/camera/libcameraservice/FakeCamera.cpp
@@ -198,10 +198,11 @@
 static const int  DELTA  = kYb*(1 << SHIFT2);
 static const int  GAMMA  = kYr*(1 << SHIFT2);
 
-int32_t ccrgb16toyuv_wo_colorkey(uint8_t *rgb16,uint8_t *yuv422,uint32_t *param,uint8_t *table[])
+int32_t ccrgb16toyuv_wo_colorkey(uint8_t *rgb16, uint8_t *yuv420,
+        uint32_t *param, uint8_t *table[])
 {
     uint16_t *inputRGB = (uint16_t*)rgb16;
-    uint8_t *outYUV =  yuv422;
+    uint8_t *outYUV = yuv420;
     int32_t width_dst = param[0];
     int32_t height_dst = param[1];
     int32_t pitch_dst = param[2];
@@ -260,12 +261,14 @@
 
             tempY[0] = y0;
             tempY[1] = y1;
-            tempU[0] = u;
-            tempV[0] = v;
-
             tempY += 2;
-            tempU += 2;
-            tempV += 2;
+
+            if ((j&1) == 0) {
+                tempU[0] = u;
+                tempV[0] = v;
+                tempU += 2;
+                tempV += 2;
+            }
         }
 
         inputRGB += pitch_src;
@@ -277,7 +280,7 @@
 #define min(a,b) ((a)<(b)?(a):(b))
 #define max(a,b) ((a)>(b)?(a):(b))
 
-static void convert_rgb16_to_yuv422(uint8_t *rgb, uint8_t *yuv, int width, int height)
+static void convert_rgb16_to_yuv420(uint8_t *rgb, uint8_t *yuv, int width, int height)
 {
     if (!tables_initialized) {
         initYtab();
@@ -326,7 +329,7 @@
     mCheckY = 0;
 
     // This will cause it to be reallocated on the next call
-    // to getNextFrameAsYuv422().
+    // to getNextFrameAsYuv420().
     delete[] mTmpRgb16Buffer;
     mTmpRgb16Buffer = 0;
 }
@@ -347,13 +350,13 @@
     mCounter++;
 }
 
-void FakeCamera::getNextFrameAsYuv422(uint8_t *buffer)
+void FakeCamera::getNextFrameAsYuv420(uint8_t *buffer)
 {
     if (mTmpRgb16Buffer == 0)
         mTmpRgb16Buffer = new uint16_t[mWidth * mHeight];
 
     getNextFrameAsRgb565(mTmpRgb16Buffer);
-    convert_rgb16_to_yuv422((uint8_t*)mTmpRgb16Buffer, buffer, mWidth, mHeight);
+    convert_rgb16_to_yuv420((uint8_t*)mTmpRgb16Buffer, buffer, mWidth, mHeight);
 }
 
 void FakeCamera::drawSquare(uint16_t *dst, int x, int y, int size, int color, int shadow)
diff --git a/camera/libcameraservice/FakeCamera.h b/camera/libcameraservice/FakeCamera.h
index f7f8803..724de20 100644
--- a/camera/libcameraservice/FakeCamera.h
+++ b/camera/libcameraservice/FakeCamera.h
@@ -40,7 +40,7 @@
     ~FakeCamera();
 
     void setSize(int width, int height);
-    void getNextFrameAsYuv422(uint8_t *buffer);
+    void getNextFrameAsYuv420(uint8_t *buffer);
     // Write to the fd a string representing the current state.
     void dump(int fd) const;
 
diff --git a/camera/tests/CameraServiceTest/Android.mk b/camera/tests/CameraServiceTest/Android.mk
index 9bb190a..cf4e42f 100644
--- a/camera/tests/CameraServiceTest/Android.mk
+++ b/camera/tests/CameraServiceTest/Android.mk
@@ -21,4 +21,6 @@
                 libcamera_client \
                 libsurfaceflinger_client
 
-include $(BUILD_EXECUTABLE)
+# Disable it because the ISurface interface may change, and before we have a
+# chance to fix this test, we don't want to break normal builds.
+#include $(BUILD_EXECUTABLE)
diff --git a/camera/tests/CameraServiceTest/CameraServiceTest.cpp b/camera/tests/CameraServiceTest/CameraServiceTest.cpp
index 9fc795b..3c8d553 100644
--- a/camera/tests/CameraServiceTest/CameraServiceTest.cpp
+++ b/camera/tests/CameraServiceTest/CameraServiceTest.cpp
@@ -38,7 +38,7 @@
     INFO("assertion failed at file %s, line %d, function %s:",
             file, line, func);
     INFO("%s", expr);
-    exit(1);
+    abort();
 }
 
 void assert_eq_fail(const char *file, int line, const char *func,
@@ -46,7 +46,7 @@
     INFO("assertion failed at file %s, line %d, function %s:",
             file, line, func);
     INFO("(expected) %s != (actual) %d", expr, actual);
-    exit(1);
+    abort();
 }
 
 #define ASSERT(e) \
@@ -155,7 +155,7 @@
     virtual void notifyCallback(int32_t msgType, int32_t ext1, int32_t ext2);
     virtual void dataCallback(int32_t msgType, const sp<IMemory>& data);
     virtual void dataCallbackTimestamp(nsecs_t timestamp,
-            int32_t msgType, const sp<IMemory>& data) {}
+            int32_t msgType, const sp<IMemory>& data);
 
     // new functions
     void clearStat();
@@ -176,6 +176,7 @@
     DefaultKeyedVector<int32_t, int> mDataCount;
     DefaultKeyedVector<int32_t, int> mDataSize;
     bool test(OP op, int v1, int v2);
+    void assertTest(OP op, int v1, int v2);
 
     ICamera *mReleaser;
 };
@@ -199,26 +200,33 @@
     return false;
 }
 
+void MCameraClient::assertTest(OP op, int v1, int v2) {
+    if (!test(op, v1, v2)) {
+        LOGE("assertTest failed: op=%d, v1=%d, v2=%d", op, v1, v2);
+        ASSERT(0);
+    }
+}
+
 void MCameraClient::assertNotify(int32_t msgType, OP op, int count) {
     Mutex::Autolock _l(mLock);
     int v = mNotifyCount.valueFor(msgType);
-    ASSERT(test(op, v, count));
+    assertTest(op, v, count);
 }
 
 void MCameraClient::assertData(int32_t msgType, OP op, int count) {
     Mutex::Autolock _l(mLock);
     int v = mDataCount.valueFor(msgType);
-    ASSERT(test(op, v, count));
+    assertTest(op, v, count);
 }
 
 void MCameraClient::assertDataSize(int32_t msgType, OP op, int dataSize) {
     Mutex::Autolock _l(mLock);
     int v = mDataSize.valueFor(msgType);
-    ASSERT(test(op, v, dataSize));
+    assertTest(op, v, dataSize);
 }
 
 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) {
@@ -230,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);
@@ -250,6 +258,11 @@
     }
 }
 
+void MCameraClient::dataCallbackTimestamp(nsecs_t timestamp, int32_t msgType,
+        const sp<IMemory>& data) {
+    dataCallback(msgType, data);
+}
+
 void MCameraClient::waitNotify(int32_t msgType, OP op, int count) {
     INFO("waitNotify: %d, %d, %d", msgType, op, count);
     Mutex::Autolock _l(mLock);
@@ -285,6 +298,7 @@
     virtual sp<OverlayRef> createOverlay(
             uint32_t w, uint32_t h, int32_t format, int32_t orientation);
     virtual sp<GraphicBuffer> requestBuffer(int bufferIdx, int usage);
+    virtual status_t setBufferCount(int bufferCount);
 
     // new functions
     void clearStat();
@@ -300,7 +314,7 @@
 };
 
 status_t MSurface::registerBuffers(const BufferHeap& buffers) {
-    INFO(__func__);
+    INFO("%s", __func__);
     Mutex::Autolock _l(mLock);
     ++registerBuffersCount;
     mCond.signal();
@@ -308,21 +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("%s", __func__);
     return NULL;
 }
 
@@ -348,10 +367,9 @@
 
 sp<OverlayRef> MSurface::createOverlay(uint32_t w, uint32_t h, int32_t format,
         int32_t orientation) {
-    // We don't expect this to be called in current hardware.
+    // Not implemented.
     ASSERT(0);
-    sp<OverlayRef> dummy;
-    return dummy;
+    return NULL;
 }
 
 //
@@ -368,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();
 }
 
@@ -395,64 +413,71 @@
     return cs;
 }
 
+int getNumberOfCameras() {
+    sp<ICameraService> cs = getCameraService();
+    return cs->getNumberOfCameras();
+}
+
 //
 // Various Connect Tests
 //
-void testConnect() {
-    INFO(__func__);
+void testConnect(int cameraId) {
+    INFO("%s", __func__);
     sp<ICameraService> cs = getCameraService();
     sp<MCameraClient> cc = new MCameraClient();
-    sp<ICamera> c = cs->connect(cc);
+    sp<ICamera> c = cs->connect(cc, cameraId);
     ASSERT(c != 0);
     c->disconnect();
 }
 
-void testAllowConnectOnceOnly() {
-    INFO(__func__);
+void testAllowConnectOnceOnly(int cameraId) {
+    INFO("%s", __func__);
     sp<ICameraService> cs = getCameraService();
     // Connect the first client.
     sp<MCameraClient> cc = new MCameraClient();
-    sp<ICamera> c = cs->connect(cc);
+    sp<ICamera> c = cs->connect(cc, cameraId);
     ASSERT(c != 0);
     // Same client -- ok.
-    ASSERT(cs->connect(cc) != 0);
+    ASSERT(cs->connect(cc, cameraId) != 0);
     // Different client -- not ok.
     sp<MCameraClient> cc2 = new MCameraClient();
-    ASSERT(cs->connect(cc2) == 0);
+    ASSERT(cs->connect(cc2, cameraId) == 0);
     c->disconnect();
 }
 
 void testReconnectFailed() {
-    INFO(__func__);
+    INFO("%s", __func__);
     sp<ICamera> c = interface_cast<ICamera>(getTempObject());
-    sp<MCameraClient> cc2 = new MCameraClient();
-    ASSERT(c->connect(cc2) != NO_ERROR);
+    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);
+    c->disconnect();
 }
 
 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();
 }
 
 //
@@ -499,11 +524,11 @@
     }
 }
 
-void testReconnect() {
-    INFO(__func__);
+void testReconnect(int cameraId) {
+    INFO("%s", __func__);
     sp<ICameraService> cs = getCameraService();
     sp<MCameraClient> cc = new MCameraClient();
-    sp<ICamera> c = cs->connect(cc);
+    sp<ICamera> c = cs->connect(cc, cameraId);
     ASSERT(c != 0);
     // Reconnect to the same client -- ok.
     ASSERT(c->connect(cc) == NO_ERROR);
@@ -514,10 +539,10 @@
     cc->assertNotify(CAMERA_MSG_ERROR, MCameraClient::EQ, 0);
 }
 
-void testLockUnlock() {
+void testLockUnlock(int cameraId) {
     sp<ICameraService> cs = getCameraService();
     sp<MCameraClient> cc = new MCameraClient();
-    sp<ICamera> c = cs->connect(cc);
+    sp<ICamera> c = cs->connect(cc, cameraId);
     ASSERT(c != 0);
     // We can lock as many times as we want.
     ASSERT(c->lock() == NO_ERROR);
@@ -530,16 +555,15 @@
     runInAnotherProcess("testLockUnlockSuccess");
     // Unlock then lock from a different process -- ok.
     runInAnotherProcess("testLockSuccess");
-    c->disconnect();
     clearTempObject();
 }
 
-void testReconnectFromAnotherProcess() {
-    INFO(__func__);
+void testReconnectFromAnotherProcess(int cameraId) {
+    INFO("%s", __func__);
 
     sp<ICameraService> cs = getCameraService();
     sp<MCameraClient> cc = new MCameraClient();
-    sp<ICamera> c = cs->connect(cc);
+    sp<ICamera> c = cs->connect(cc, cameraId);
     ASSERT(c != 0);
     // Reconnect from a different process -- not ok.
     putTempObject(c->asBinder());
@@ -547,7 +571,6 @@
     // Unlock then reconnect from a different process -- ok.
     ASSERT(c->unlock() == NO_ERROR);
     runInAnotherProcess("testReconnectSuccess");
-    c->disconnect();
     clearTempObject();
 }
 
@@ -560,10 +583,11 @@
 }
 
 // Run a test case
-#define RUN(class_name) do { \
+#define RUN(class_name, cameraId) do { \
     { \
         INFO(#class_name); \
         class_name instance; \
+        instance.init(cameraId); \
         instance.run(); \
     } \
     flushCommands(); \
@@ -571,19 +595,21 @@
 
 // Base test case after the the camera is connected.
 class AfterConnect {
+public:
+    void init(int cameraId) {
+        cs = getCameraService();
+        cc = new MCameraClient();
+        c = cs->connect(cc, cameraId);
+        ASSERT(c != 0);
+    }
+
 protected:
     sp<ICameraService> cs;
     sp<MCameraClient> cc;
     sp<ICamera> c;
 
-    AfterConnect() {
-        cs = getCameraService();
-        cc = new MCameraClient();
-        c = cs->connect(cc);
-        ASSERT(c != 0);
-    }
-
     ~AfterConnect() {
+        c->disconnect();
         c.clear();
         cc.clear();
         cs.clear();
@@ -612,19 +638,16 @@
         surface->waitUntil(1, 10, 0); // needs 1 registerBuffers and 10 postBuffer
         surface->clearStat();
 
-        c->disconnect();
-        // TODO: CameraService crashes for this. Fix it.
-#if 0
         sp<MSurface> another_surface = new MSurface();
         c->setPreviewDisplay(another_surface);  // just to make sure unregisterBuffers
                                                 // is called.
         surface->waitUntil(0, 0, 1);  // needs unregisterBuffers
-#endif
+
         cc->assertNotify(CAMERA_MSG_ERROR, MCameraClient::EQ, 0);
     }
 };
 
-class TestStartPreviewWithoutDisplay : AfterConnect {
+class TestStartPreviewWithoutDisplay : public AfterConnect {
 public:
     void run() {
         ASSERT(c->startPreview() == NO_ERROR);
@@ -636,15 +659,17 @@
 
 // Base test case after the the camera is connected and the preview is started.
 class AfterStartPreview : public AfterConnect {
-protected:
-    sp<MSurface> surface;
-
-    AfterStartPreview() {
+public:
+    void init(int cameraId) {
+        AfterConnect::init(cameraId);
         surface = new MSurface();
         ASSERT(c->setPreviewDisplay(surface) == NO_ERROR);
         ASSERT(c->startPreview() == NO_ERROR);
     }
 
+protected:
+    sp<MSurface> surface;
+
     ~AfterStartPreview() {
         surface.clear();
     }
@@ -680,9 +705,6 @@
         cc->waitData(CAMERA_MSG_RAW_IMAGE, MCameraClient::EQ, 1);
         cc->waitData(CAMERA_MSG_COMPRESSED_IMAGE, MCameraClient::EQ, 1);
         c->stopPreview();
-#if 1  // TODO: It crashes if we don't have this. Fix it.
-        usleep(100000);
-#endif
         c->disconnect();
         cc->assertNotify(CAMERA_MSG_ERROR, MCameraClient::EQ, 0);
     }
@@ -697,7 +719,6 @@
             cc->waitNotify(CAMERA_MSG_SHUTTER, MCameraClient::EQ, 1);
             cc->waitData(CAMERA_MSG_RAW_IMAGE, MCameraClient::EQ, 1);
             cc->waitData(CAMERA_MSG_COMPRESSED_IMAGE, MCameraClient::EQ, 1);
-            usleep(100000);  // 100ms
         }
         c->disconnect();
         cc->assertNotify(CAMERA_MSG_ERROR, MCameraClient::EQ, 0);
@@ -708,36 +729,71 @@
 public:
     void run() {
         String8 param_str = c->getParameters();
-        INFO(param_str);
+        INFO("%s", static_cast<const char*>(param_str));
     }
 };
 
+static bool getNextSize(const char **ptrS, int *w, int *h) {
+    const char *s = *ptrS;
+
+    // skip over ','
+    if (*s == ',') s++;
+
+    // remember start position in p
+    const char *p = s;
+    while (*s != '\0' && *s != 'x') {
+        s++;
+    }
+    if (*s == '\0') return false;
+
+    // get the width
+    *w = atoi(p);
+
+    // skip over 'x'
+    ASSERT(*s == 'x');
+    p = s + 1;
+    while (*s != '\0' && *s != ',') {
+        s++;
+    }
+
+    // get the height
+    *h = atoi(p);
+    *ptrS = s;
+    return true;
+}
+
 class TestPictureSize : public AfterStartPreview {
 public:
     void checkOnePicture(int w, int h) {
-        const float rate = 0.5;  // byte per pixel limit
+        const float rate = 0.9;  // byte per pixel limit
         int pixels = w * h;
 
         CameraParameters param(c->getParameters());
         param.setPictureSize(w, h);
+        // disable thumbnail to get more accurate size.
+        param.set(CameraParameters::KEY_JPEG_THUMBNAIL_WIDTH, 0);
+        param.set(CameraParameters::KEY_JPEG_THUMBNAIL_HEIGHT, 0);
         c->setParameters(param.flatten());
 
         cc->clearStat();
         ASSERT(c->takePicture() == NO_ERROR);
         cc->waitData(CAMERA_MSG_RAW_IMAGE, MCameraClient::EQ, 1);
-        cc->assertDataSize(CAMERA_MSG_RAW_IMAGE, MCameraClient::EQ, pixels*3/2);
+        //cc->assertDataSize(CAMERA_MSG_RAW_IMAGE, MCameraClient::EQ, pixels*3/2);
         cc->waitData(CAMERA_MSG_COMPRESSED_IMAGE, MCameraClient::EQ, 1);
         cc->assertDataSize(CAMERA_MSG_COMPRESSED_IMAGE, MCameraClient::LT,
                 int(pixels * rate));
         cc->assertDataSize(CAMERA_MSG_COMPRESSED_IMAGE, MCameraClient::GT, 0);
         cc->assertNotify(CAMERA_MSG_ERROR, MCameraClient::EQ, 0);
-        usleep(100000);  // 100ms
     }
 
     void run() {
-        checkOnePicture(2048, 1536);
-        checkOnePicture(1600, 1200);
-        checkOnePicture(1024, 768);
+        CameraParameters param(c->getParameters());
+        int w, h;
+        const char *s = param.get(CameraParameters::KEY_SUPPORTED_PICTURE_SIZES);
+        while (getNextSize(&s, &w, &h)) {
+            LOGD("checking picture size %dx%d", w, h);
+            checkOnePicture(w, h);
+        }
     }
 };
 
@@ -749,6 +805,8 @@
 
         // Try all flag combinations.
         for (int v = 0; v < 8; v++) {
+            LOGD("TestPreviewCallbackFlag: flag=%d", v);
+            usleep(100000); // sleep a while to clear the in-flight callbacks.
             cc->clearStat();
             c->setPreviewCallbackFlag(v);
             ASSERT(c->previewEnabled() == false);
@@ -781,6 +839,7 @@
         ASSERT(c->recordingEnabled() == true);
         sleep(2);
         c->stopRecording();
+        usleep(100000); // sleep a while to clear the in-flight callbacks.
         cc->setReleaser(NULL);
         cc->assertData(CAMERA_MSG_VIDEO_FRAME, MCameraClient::GE, 10);
     }
@@ -806,9 +865,13 @@
     }
 
     void run() {
-        checkOnePicture(480, 320);
-        checkOnePicture(352, 288);
-        checkOnePicture(176, 144);
+        CameraParameters param(c->getParameters());
+        int w, h;
+        const char *s = param.get(CameraParameters::KEY_SUPPORTED_PREVIEW_SIZES);
+        while (getNextSize(&s, &w, &h)) {
+            LOGD("checking preview size %dx%d", w, h);
+            checkOnePicture(w, h);
+        }
     }
 };
 
@@ -827,23 +890,30 @@
     INFO("CameraServiceTest start");
     gExecutable = argv[0];
     runHolderService();
+    int n = getNumberOfCameras();
+    INFO("%d Cameras available", n);
 
-    testConnect();                              flushCommands();
-    testAllowConnectOnceOnly();                 flushCommands();
-    testReconnect();                            flushCommands();
-    testLockUnlock();                           flushCommands();
-    testReconnectFromAnotherProcess();          flushCommands();
+    for (int id = 0; id < n; id++) {
+        INFO("Testing camera %d", id);
+        testConnect(id);                              flushCommands();
+        testAllowConnectOnceOnly(id);                 flushCommands();
+        testReconnect(id);                            flushCommands();
+        testLockUnlock(id);                           flushCommands();
+        testReconnectFromAnotherProcess(id);          flushCommands();
 
-    RUN(TestSetPreviewDisplay);
-    RUN(TestStartPreview);
-    RUN(TestStartPreviewWithoutDisplay);
-    RUN(TestAutoFocus);
-    RUN(TestStopPreview);
-    RUN(TestTakePicture);
-    RUN(TestTakeMultiplePictures);
-    RUN(TestGetParameters);
-    RUN(TestPictureSize);
-    RUN(TestPreviewCallbackFlag);
-    RUN(TestRecording);
-    RUN(TestPreviewSize);
+        RUN(TestSetPreviewDisplay, id);
+        RUN(TestStartPreview, id);
+        RUN(TestStartPreviewWithoutDisplay, id);
+        RUN(TestAutoFocus, id);
+        RUN(TestStopPreview, id);
+        RUN(TestTakePicture, id);
+        RUN(TestTakeMultiplePictures, id);
+        RUN(TestGetParameters, id);
+        RUN(TestPictureSize, id);
+        RUN(TestPreviewCallbackFlag, id);
+        RUN(TestRecording, id);
+        RUN(TestPreviewSize, id);
+    }
+
+    INFO("CameraServiceTest finished");
 }
diff --git a/include/private/surfaceflinger/SharedBufferStack.h b/include/private/surfaceflinger/SharedBufferStack.h
index 9b5a1e0..b859e78 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  = 4;
-const unsigned int NUM_DISPLAY_MAX = 4;
-
 // ----------------------------------------------------------------------------
 
 class Region;
@@ -69,7 +63,11 @@
 
 // ----------------------------------------------------------------------------
 
-// should be 128 bytes (32 longs)
+// 4 * (11 + 7 + (1 + 2*NUM_RECT_MAX) * NUM_BUFFER_MAX) * NUM_LAYERS_MAX
+// 4 * (11 + 7 + (1 + 2*7)*16) * 31
+// 1032 * 31
+// = ~27 KiB (31992)
+
 class SharedBufferStack
 {
     friend class SharedClient;
@@ -78,21 +76,38 @@
     friend class SharedBufferServer;
 
 public:
-    struct FlatRegion { // 12 bytes
-        static const unsigned int NUM_RECT_MAX = 1;
-        uint32_t    count;
-        uint16_t    rects[4*NUM_RECT_MAX];
-    };
-    
+    // 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;
         usecs_t  reserved[3];
     };
+
+    struct SmallRect {
+        uint16_t l, t, r, b;
+    };
+
+    struct FlatRegion { // 52 bytes = 4 * (1 + 2*N)
+        static const unsigned int NUM_RECT_MAX = 6;
+        uint32_t    count;
+        SmallRect   rects[NUM_RECT_MAX];
+    };
+    
+    struct BufferData {
+        FlatRegion dirtyRegion;
+        SmallRect  crop;
+    };
     
     SharedBufferStack();
     void init(int32_t identity);
     status_t setDirtyRegion(int buffer, const Region& reg);
+    status_t setCrop(int buffer, const Rect& reg);
     Region getDirtyRegion(int buffer) const;
 
     // these attributes are part of the conditions/updates
@@ -104,16 +119,18 @@
 
     // not part of the conditions
     volatile int32_t reallocMask;
+    volatile int8_t index[NUM_BUFFER_MAX];
 
     int32_t     identity;       // surface's identity (const)
-    int32_t     reserved32[9];
+    int32_t     reserved32[2];
     Statistics  stats;
-    FlatRegion  dirtyRegion[NUM_BUFFER_MAX];    // 12*4=48 bytes
+    int32_t     reserved;
+    BufferData  buffers[NUM_BUFFER_MAX];     // 960 bytes
 };
 
 // ----------------------------------------------------------------------------
 
-// 4 KB max
+// 32 KB max
 class SharedClient
 {
 public:
@@ -131,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 ];
 };
 
 // ============================================================================
@@ -139,10 +156,9 @@
 class SharedBufferBase
 {
 public:
-    SharedBufferBase(SharedClient* sharedClient, int surface, int num,
+    SharedBufferBase(SharedClient* sharedClient, int surface,
             int32_t identity);
     ~SharedBufferBase();
-    uint32_t getIdentity();
     status_t getStatus() const;
     size_t getFrontBuffer() const;
     String8 dump(char const* prefix) const;
@@ -150,7 +166,6 @@
 protected:
     SharedClient* const mSharedClient;
     SharedBufferStack* const mSharedStack;
-    const int mNumBuffers;
     const int mIdentity;
 
     friend struct Update;
@@ -160,61 +175,22 @@
         SharedBufferStack& stack;
         inline ConditionBase(SharedBufferBase* sbc) 
             : stack(*sbc->mSharedStack) { }
+        virtual ~ConditionBase() { };
+        virtual bool operator()() const = 0;
+        virtual const char* name() const = 0;
     };
+    status_t waitForCondition(const ConditionBase& condition);
 
     struct UpdateBase {
         SharedBufferStack& stack;
         inline UpdateBase(SharedBufferBase* sbb) 
             : stack(*sbb->mSharedStack) { }
     };
-
-    template <typename T>
-    status_t waitForCondition(T condition);
-
     template <typename T>
     status_t updateCondition(T update);
 };
 
 template <typename T>
-status_t SharedBufferBase::waitForCondition(T condition) 
-{
-    const SharedBufferStack& stack( *mSharedStack );
-    SharedClient& client( *mSharedClient );
-    const nsecs_t TIMEOUT = s2ns(1);
-    Mutex::Autolock _l(client.lock);
-    while ((condition()==false) &&
-            (stack.identity == mIdentity) &&
-            (stack.status == NO_ERROR))
-    {
-        status_t err = client.cv.waitRelative(client.lock, TIMEOUT);
-        
-        // handle errors and timeouts
-        if (CC_UNLIKELY(err != NO_ERROR)) {
-            if (err == TIMED_OUT) {
-                if (condition()) {
-                    LOGE("waitForCondition(%s) timed out (identity=%d), "
-                        "but condition is true! We recovered but it "
-                        "shouldn't happen." , T::name(),
-                        stack.identity);
-                    break;
-                } else {
-                    LOGW("waitForCondition(%s) timed out "
-                        "(identity=%d, status=%d). "
-                        "CPU may be pegged. trying again.", T::name(),
-                        stack.identity, stack.status);
-                }
-            } else {
-                LOGE("waitForCondition(%s) error (%s) ",
-                        T::name(), strerror(-err));
-                return err;
-            }
-        }
-    }
-    return (stack.identity != mIdentity) ? status_t(BAD_INDEX) : stack.status;
-}
-
-
-template <typename T>
 status_t SharedBufferBase::updateCondition(T update) {
     SharedClient& client( *mSharedClient );
     Mutex::Autolock _l(client.lock);
@@ -238,13 +214,21 @@
     status_t queue(int buf);
     bool needNewBuffer(int buffer) const;
     status_t setDirtyRegion(int buffer, const Region& reg);
+    status_t setCrop(int buffer, const Rect& reg);
     
+
+    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;
     friend struct LockCondition;
-    
-    int32_t computeTail() const;
 
     struct QueueUpdate : public UpdateBase {
         inline QueueUpdate(SharedBufferBase* sbb);
@@ -260,20 +244,27 @@
 
     struct DequeueCondition : public ConditionBase {
         inline DequeueCondition(SharedBufferClient* sbc);
-        inline bool operator()();
-        static inline const char* name() { return "DequeueCondition"; }
+        inline bool operator()() const;
+        inline const char* name() const { return "DequeueCondition"; }
     };
 
     struct LockCondition : public ConditionBase {
         int buf;
         inline LockCondition(SharedBufferClient* sbc, int buf);
-        inline bool operator()();
-        static inline const char* name() { return "LockCondition"; }
+        inline bool operator()() const;
+        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,16 +278,71 @@
     ssize_t retireAndLock();
     status_t unlock(int buffer);
     void setStatus(status_t status);
-    status_t reallocate();
+    status_t reallocateAll();
+    status_t reallocateAllExcept(int buffer);
     status_t assertReallocate(int buffer);
     int32_t getQueuedCount() const;
-    
     Region getDirtyRegion(int buffer) const;
 
+    status_t resize(int newNumBuffers);
+
     SharedBufferStack::Statistics getStats() const;
     
 
 private:
+    /*
+     * BufferList is basically a fixed-capacity sorted-vector of
+     * unsigned 5-bits ints using a 32-bits int as storage.
+     * it has efficient iterators to find items in the list and not in the list.
+     */
+    class BufferList {
+        size_t mCapacity;
+        uint32_t mList;
+    public:
+        BufferList(size_t c = SharedBufferStack::NUM_BUFFER_MAX)
+            : mCapacity(c), mList(0) { }
+        status_t add(int value);
+        status_t remove(int value);
+        uint32_t getMask() const { return mList; }
+
+        class const_iterator {
+            friend class BufferList;
+            uint32_t mask, curr;
+            const_iterator(uint32_t mask) :
+                mask(mask), curr(__builtin_clz(mask)) {
+            }
+        public:
+            inline bool operator == (const const_iterator& rhs) const {
+                return mask == rhs.mask;
+            }
+            inline bool operator != (const const_iterator& rhs) const {
+                return mask != rhs.mask;
+            }
+            inline int operator *() const { return curr; }
+            inline const const_iterator& operator ++() {
+                mask &= ~(1<<(31-curr));
+                curr = __builtin_clz(mask);
+                return *this;
+            }
+        };
+
+        inline const_iterator begin() const {
+            return const_iterator(mList);
+        }
+        inline const_iterator end() const   {
+            return const_iterator(0);
+        }
+        inline const_iterator free_begin() const {
+            uint32_t mask = (1 << (32-mCapacity)) - 1;
+            return const_iterator( ~(mList | mask) );
+        }
+    };
+
+    // this protects mNumBuffers and mBufferList
+    mutable RWLock mLock;
+    int mNumBuffers;
+    BufferList mBufferList;
+
     struct UnlockUpdate : public UpdateBase {
         const int lockedBuffer;
         inline UnlockUpdate(SharedBufferBase* sbb, int lockedBuffer);
@@ -318,8 +364,8 @@
     struct ReallocateCondition : public ConditionBase {
         int buf;
         inline ReallocateCondition(SharedBufferBase* sbb, int buf);
-        inline bool operator()();
-        static inline const char* name() { return "ReallocateCondition"; }
+        inline bool operator()() const;
+        inline const char* name() const { return "ReallocateCondition"; }
     };
 };
 
@@ -344,13 +390,12 @@
     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];
 };
 
 // ---------------------------------------------------------------------------
 
-COMPILE_TIME_ASSERT(sizeof(SharedClient) <= 4096)
-COMPILE_TIME_ASSERT(sizeof(SharedBufferStack) == 128)
+COMPILE_TIME_ASSERT(sizeof(SharedClient) <= 32768)
 COMPILE_TIME_ASSERT(sizeof(surface_flinger_cblk_t) <= 4096)
 
 // ---------------------------------------------------------------------------
diff --git a/include/surfaceflinger/ISurface.h b/include/surfaceflinger/ISurface.h
index 472f759..18e7950 100644
--- a/include/surfaceflinger/ISurface.h
+++ b/include/surfaceflinger/ISurface.h
@@ -47,12 +47,15 @@
         POST_BUFFER, // one-way transaction
         CREATE_OVERLAY,
         REQUEST_BUFFER,
+        SET_BUFFER_COUNT,
     };
 
 public: 
     DECLARE_META_INTERFACE(Surface);
 
-    virtual sp<GraphicBuffer> requestBuffer(int bufferIdx, int usage) = 0; 
+    virtual sp<GraphicBuffer> requestBuffer(int bufferIdx,
+            uint32_t w, uint32_t h, uint32_t format, uint32_t usage) = 0;
+    virtual status_t setBufferCount(int bufferCount) = 0;
     
     class BufferHeap {
     public:
diff --git a/include/surfaceflinger/ISurfaceFlingerClient.h b/include/surfaceflinger/ISurfaceFlingerClient.h
index d257645..c96432f 100644
--- a/include/surfaceflinger/ISurfaceFlingerClient.h
+++ b/include/surfaceflinger/ISurfaceFlingerClient.h
@@ -59,6 +59,9 @@
     
     virtual sp<IMemoryHeap> getControlBlock() const = 0;
 
+    /*
+     * Requires ACCESS_SURFACE_FLINGER permission
+     */
     virtual sp<ISurface> createSurface( surface_data_t* data,
                                         int pid, 
                                         const String8& name,
@@ -68,8 +71,14 @@
                                         PixelFormat format,
                                         uint32_t flags) = 0;
                                     
+    /*
+     * Requires ACCESS_SURFACE_FLINGER permission
+     */
     virtual status_t    destroySurface(SurfaceID sid) = 0;
 
+    /*
+     * Requires ACCESS_SURFACE_FLINGER permission
+     */
     virtual status_t    setState(int32_t count, const layer_state_t* states) = 0;
 };
 
diff --git a/include/surfaceflinger/Surface.h b/include/surfaceflinger/Surface.h
index 0279d84..33269cb 100644
--- a/include/surfaceflinger/Surface.h
+++ b/include/surfaceflinger/Surface.h
@@ -30,10 +30,13 @@
 #include <surfaceflinger/ISurface.h>
 #include <surfaceflinger/ISurfaceFlingerClient.h>
 
+#define ANDROID_VIEW_SURFACE_JNI_ID    "mNativeSurface"
+
 namespace android {
 
 // ---------------------------------------------------------------------------
 
+class GraphicBuffer;
 class GraphicBufferMapper;
 class IOMX;
 class Rect;
@@ -41,6 +44,7 @@
 class SurfaceComposerClient;
 class SharedClient;
 class SharedBufferClient;
+class SurfaceClient;
 
 // ---------------------------------------------------------------------------
 
@@ -163,38 +167,36 @@
     // setSwapRectangle() is intended to be used by GL ES clients
     void        setSwapRectangle(const Rect& r);
 
+
 private:
-    // can't be copied
-    Surface& operator = (Surface& rhs);
-    Surface(const Surface& rhs);
-
-    Surface(const sp<SurfaceControl>& control);
-    void init();
-     ~Surface();
-  
-    friend class SurfaceComposerClient;
-    friend class SurfaceControl;
-
-    
+    /*
+     * Android frameworks friends
+     * (eventually this should go away and be replaced by proper APIs)
+     */
     // camera and camcorder need access to the ISurface binder interface for preview
     friend class Camera;
     friend class MediaRecorder;
-    // mediaplayer needs access to ISurface for display
+    // MediaPlayer needs access to ISurface for display
     friend class MediaPlayer;
     friend class IOMX;
     // this is just to be able to write some unit tests
     friend class Test;
 
-    sp<SurfaceComposerClient> getClient() const;
-    sp<ISurface> getISurface() const;
+private:
+    friend class SurfaceComposerClient;
+    friend class SurfaceControl;
 
-    status_t getBufferLocked(int index, int usage);
-   
-           status_t validate() const;
+    // can't be copied
+    Surface& operator = (Surface& rhs);
+    Surface(const Surface& rhs);
 
-    inline const GraphicBufferMapper& getBufferMapper() const { return mBufferMapper; }
-    inline GraphicBufferMapper& getBufferMapper() { return mBufferMapper; }
-    
+    Surface(const sp<SurfaceControl>& control);
+    ~Surface();
+
+
+    /*
+     *  android_native_window_t hooks
+     */
     static int setSwapInterval(android_native_window_t* window, int interval);
     static int dequeueBuffer(android_native_window_t* window, android_native_buffer_t** buffer);
     static int lockBuffer(android_native_window_t* window, android_native_buffer_t* buffer);
@@ -208,21 +210,61 @@
     int query(int what, int* value);
     int perform(int operation, va_list args);
 
-    status_t dequeueBuffer(sp<GraphicBuffer>* buffer);
-
     void dispatch_setUsage(va_list args);
     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);
+    int  dispatch_set_buffers_geometry(va_list args);
     
     void setUsage(uint32_t reqUsage);
     int  connect(int api);
     int  disconnect(int api);
+    int  crop(Rect const* rect);
+    int  setBufferCount(int bufferCount);
+    int  setBuffersGeometry(int w, int h, int format);
 
-    uint32_t getUsage() const;
-    int      getConnectedApi() const;
+    /*
+     *  private stuff...
+     */
+    void init();
+    status_t validate() const;
+    status_t initCheck() const;
+    sp<ISurface> getISurface() const;
+
+    inline const GraphicBufferMapper& getBufferMapper() const { return mBufferMapper; }
+    inline GraphicBufferMapper& getBufferMapper() { return mBufferMapper; }
+
+    status_t getBufferLocked(int index,
+            uint32_t w, uint32_t h, uint32_t format, uint32_t usage);
+    int getBufferIndex(const sp<GraphicBuffer>& buffer) const;
+
+    int getConnectedApi() const;
     
+    bool needNewBuffer(int bufIdx,
+            uint32_t *pWidth, uint32_t *pHeight,
+            uint32_t *pFormat, uint32_t *pUsage) const;
+
+    class BufferInfo {
+        uint32_t mWidth;
+        uint32_t mHeight;
+        uint32_t mFormat;
+        uint32_t mUsage;
+        mutable uint32_t mDirty;
+        enum {
+            GEOMETRY = 0x01
+        };
+    public:
+        BufferInfo();
+        void set(uint32_t w, uint32_t h, uint32_t format);
+        void set(uint32_t usage);
+        void get(uint32_t *pWidth, uint32_t *pHeight,
+                uint32_t *pFormat, uint32_t *pUsage) const;
+        bool validateBuffer(const sp<GraphicBuffer>& buffer) const;
+    };
+
     // constants
-    sp<SurfaceComposerClient>   mClient;
+    sp<SurfaceClient>           mClient;
     sp<ISurface>                mSurface;
     SurfaceID                   mToken;
     uint32_t                    mIdentity;
@@ -230,22 +272,26 @@
     uint32_t                    mFlags;
     GraphicBufferMapper&        mBufferMapper;
     SharedBufferClient*         mSharedBufferClient;
+    status_t                    mInitCheck;
 
     // protected by mSurfaceLock
     Rect                        mSwapRectangle;
-    uint32_t                    mUsage;
     int                         mConnected;
+    Rect                        mNextBufferCrop;
+    BufferInfo                  mBufferInfo;
     
     // protected by mSurfaceLock. These are also used from lock/unlock
     // but in that case, they must be called form the same thread.
-    sp<GraphicBuffer>           mBuffers[2];
     mutable Region              mDirtyRegion;
 
     // must be used from the lock/unlock thread
     sp<GraphicBuffer>           mLockedBuffer;
     sp<GraphicBuffer>           mPostedBuffer;
     mutable Region              mOldDirtyRegion;
-    bool                        mNeedFullUpdate;
+    bool                        mReserved;
+
+    // only used from dequeueBuffer()
+    Vector< sp<GraphicBuffer> > mBuffers;
 
     // query() must be called from dequeueBuffer() thread
     uint32_t                    mWidth;
diff --git a/include/surfaceflinger/SurfaceComposerClient.h b/include/surfaceflinger/SurfaceComposerClient.h
index 9d0f0cb..102aebc 100644
--- a/include/surfaceflinger/SurfaceComposerClient.h
+++ b/include/surfaceflinger/SurfaceComposerClient.h
@@ -40,7 +40,9 @@
 class ISurfaceComposer;
 class DisplayInfo;
 
-class SurfaceComposerClient : virtual public RefBase
+// ---------------------------------------------------------------------------
+
+class SurfaceComposerClient : public RefBase
 {
 public:    
                 SurfaceComposerClient();
@@ -52,10 +54,6 @@
     // Return the connection of this client
     sp<IBinder> connection() const;
     
-    // Retrieve a client for an existing connection.
-    static sp<SurfaceComposerClient>
-                clientForConnection(const sp<IBinder>& conn);
-
     // Forcibly remove connection before all references have gone away.
     void        dispose();
 
@@ -123,13 +121,6 @@
     status_t linkToComposerDeath(const sp<IBinder::DeathRecipient>& recipient,
             void* cookie = NULL, uint32_t flags = 0);
 
-private:
-    friend class Surface;
-    friend class SurfaceControl;
-    
-    SurfaceComposerClient(const sp<ISurfaceComposer>& sm, 
-            const sp<IBinder>& conn);
-
     status_t    hide(SurfaceID id);
     status_t    show(SurfaceID id, int32_t layer = -1);
     status_t    freeze(SurfaceID id);
@@ -142,32 +133,45 @@
     status_t    setMatrix(SurfaceID id, float dsdx, float dtdx, float dsdy, float dtdy);
     status_t    setPosition(SurfaceID id, int32_t x, int32_t y);
     status_t    setSize(SurfaceID id, uint32_t w, uint32_t h);
-    
-    void        signalServer();
-
     status_t    destroySurface(SurfaceID sid);
 
-    void        _init(const sp<ISurfaceComposer>& sm,
-                    const sp<ISurfaceFlingerClient>& conn);
-
-    inline layer_state_t*   _get_state_l(SurfaceID id);
-    layer_state_t*          _lockLayerState(SurfaceID id);
-    inline void             _unlockLayerState();
+private:
+    virtual void onFirstRef();
+    inline layer_state_t*   get_state_l(SurfaceID id);
+    layer_state_t*          lockLayerState(SurfaceID id);
+    inline void             unlockLayerState();
 
     mutable     Mutex                               mLock;
-                layer_state_t*                      mPrebuiltLayerState;
                 SortedVector<layer_state_t>         mStates;
                 int32_t                             mTransactionOpen;
+                layer_state_t*                      mPrebuiltLayerState;
 
                 // these don't need to be protected because they never change
                 // after assignment
                 status_t                    mStatus;
-                SharedClient*               mControl;
-                sp<IMemoryHeap>             mControlMemory;
                 sp<ISurfaceFlingerClient>   mClient;
-                sp<ISurfaceComposer>        mSignalServer;
 };
 
+// ---------------------------------------------------------------------------
+
+class SurfaceClient : public RefBase
+{
+    // all these attributes are constants
+    status_t                    mStatus;
+    SharedClient*               mControl;
+    sp<IMemoryHeap>             mControlMemory;
+    sp<IBinder>                 mConnection;
+    sp<ISurfaceComposer>        mSignalServer;
+    void init(const sp<IBinder>& conn);
+public:
+    explicit SurfaceClient(const sp<IBinder>& conn);
+    explicit SurfaceClient(const sp<SurfaceComposerClient>& client);
+    status_t initCheck() const;
+    SharedClient* getSharedClient() const;
+    void signalServer() const;
+};
+
+// ---------------------------------------------------------------------------
 }; // namespace android
 
 #endif // ANDROID_SF_SURFACE_COMPOSER_CLIENT_H
diff --git a/include/ui/GraphicBufferAllocator.h b/include/ui/GraphicBufferAllocator.h
index 741d763..54b8236 100644
--- a/include/ui/GraphicBufferAllocator.h
+++ b/include/ui/GraphicBufferAllocator.h
@@ -73,9 +73,9 @@
     struct alloc_rec_t {
         uint32_t w;
         uint32_t h;
+        uint32_t s;
         PixelFormat format;
         uint32_t usage;
-        void* vaddr;
         size_t size;
     };
     
diff --git a/include/ui/android_native_buffer.h b/include/ui/android_native_buffer.h
index 9c92af8..402843e 100644
--- a/include/ui/android_native_buffer.h
+++ b/include/ui/android_native_buffer.h
@@ -33,6 +33,15 @@
         common.version = sizeof(android_native_buffer_t);
         memset(common.reserved, 0, sizeof(common.reserved));
     }
+
+    // Implement the methods that sp<android_native_buffer_t> expects so that it
+    // can be used to automatically refcount android_native_buffer_t's.
+    void incStrong(const void* id) const {
+        common.incRef(const_cast<android_native_base_t*>(&common));
+    }
+    void decStrong(const void* id) const {
+        common.decRef(const_cast<android_native_base_t*>(&common));
+    }
 #endif
 
     struct android_native_base_t common;
diff --git a/include/ui/egl/android_natives.h b/include/ui/egl/android_natives.h
index 773fd93..171f3df 100644
--- a/include/ui/egl/android_natives.h
+++ b/include/ui/egl/android_natives.h
@@ -41,6 +41,14 @@
 
 struct android_native_buffer_t;
 
+typedef struct android_native_rect_t
+{
+    int32_t left;
+    int32_t top;
+    int32_t right;
+    int32_t bottom;
+} android_native_rect_t;
+
 // ---------------------------------------------------------------------------
 
 typedef struct android_native_base_t
@@ -63,15 +71,18 @@
 /* attributes queriable with query() */
 enum {
     NATIVE_WINDOW_WIDTH     = 0,
-    NATIVE_WINDOW_HEIGHT    = 1,
-    NATIVE_WINDOW_FORMAT    = 2,
+    NATIVE_WINDOW_HEIGHT,
+    NATIVE_WINDOW_FORMAT,
 };
 
 /* valid operations for the (*perform)() hook */
 enum {
     NATIVE_WINDOW_SET_USAGE  = 0,
-    NATIVE_WINDOW_CONNECT    = 1,
-    NATIVE_WINDOW_DISCONNECT = 2
+    NATIVE_WINDOW_CONNECT,
+    NATIVE_WINDOW_DISCONNECT,
+    NATIVE_WINDOW_SET_CROP,
+    NATIVE_WINDOW_SET_BUFFER_COUNT,
+    NATIVE_WINDOW_SET_BUFFERS_GEOMETRY,
 };
 
 /* parameter for NATIVE_WINDOW_[DIS]CONNECT */
@@ -89,6 +100,15 @@
         common.version = sizeof(android_native_window_t);
         memset(common.reserved, 0, sizeof(common.reserved));
     }
+
+    // Implement the methods that sp<android_native_window_t> expects so that it
+    // can be used to automatically refcount android_native_window_t's.
+    void incStrong(const void* id) const {
+        common.incRef(const_cast<android_native_base_t*>(&common));
+    }
+    void decStrong(const void* id) const {
+        common.decRef(const_cast<android_native_base_t*>(&common));
+    }
 #endif
     
     struct android_native_base_t common;
@@ -125,7 +145,7 @@
      * 
      * Returns 0 on success or -errno on error.
      */
-    int     (*dequeueBuffer)(struct android_native_window_t* window, 
+    int     (*dequeueBuffer)(struct android_native_window_t* window,
                 struct android_native_buffer_t** buffer);
 
     /*
@@ -171,6 +191,9 @@
      *     NATIVE_WINDOW_SET_USAGE
      *     NATIVE_WINDOW_CONNECT
      *     NATIVE_WINDOW_DISCONNECT
+     *     NATIVE_WINDOW_SET_CROP
+     *     NATIVE_WINDOW_SET_BUFFER_COUNT
+     *     NATIVE_WINDOW_SET_BUFFERS_GEOMETRY
      *  
      */
     
@@ -182,8 +205,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.
@@ -198,8 +222,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.
  */
@@ -210,8 +234,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.
  */
@@ -221,6 +245,54 @@
     return window->perform(window, NATIVE_WINDOW_DISCONNECT, api);
 }
 
+/*
+ * 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.
+ *
+ * if 'crop' is NULL, subsequently queued buffers won't be cropped.
+ *
+ * An error is returned if for instance the crop region is invalid,
+ * out of the buffer's bound or if the window is invalid.
+ */
+static inline int native_window_set_crop(
+        android_native_window_t* window,
+        android_native_rect_t const * crop)
+{
+    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);
+}
+
+/*
+ * native_window_set_buffers_geometry(..., int w, int h, int format)
+ * All buffers dequeued after this call will have the geometry specified.
+ * In particular, all buffers will have a fixed-size, independent form the
+ * native-window size. They will be appropriately scaled to the window-size
+ * upon composition.
+ *
+ * If all parameters are 0, the normal behavior is restored. That is,
+ * dequeued buffers following this call will be sized to the window's size.
+ *
+ */
+static inline int native_window_set_buffers_geometry(
+        android_native_window_t* window,
+        int w, int h, int format)
+{
+    return window->perform(window, NATIVE_WINDOW_SET_BUFFERS_GEOMETRY,
+            w, h, format);
+}
 
 // ---------------------------------------------------------------------------
 
@@ -263,6 +335,15 @@
 template <typename NATIVE_TYPE, typename TYPE, typename REF>
 class EGLNativeBase : public NATIVE_TYPE, public REF
 {
+public:
+    // Disambiguate between the incStrong in REF and NATIVE_TYPE
+    void incStrong(const void* id) const {
+        REF::incStrong(id);
+    }
+    void decStrong(const void* id) const {
+        REF::decStrong(id);
+    }
+
 protected:
     typedef EGLNativeBase<NATIVE_TYPE, TYPE, REF> BASE;
     EGLNativeBase() : NATIVE_TYPE(), REF() {
diff --git a/include/utils/ResourceTypes.h b/include/utils/ResourceTypes.h
index b701ce7..c7d9ff1 100644
--- a/include/utils/ResourceTypes.h
+++ b/include/utils/ResourceTypes.h
@@ -933,6 +933,7 @@
         SCREENSIZE_SMALL = 0x01,
         SCREENSIZE_NORMAL = 0x02,
         SCREENSIZE_LARGE = 0x03,
+        SCREENSIZE_XLARGE = 0x04,
         
         // screenLayout bits for wide/long screen variation.
         MASK_SCREENLONG = 0x30,
@@ -1208,7 +1209,28 @@
             if (screenLayout || o.screenLayout) {
                 if (((screenLayout^o.screenLayout) & MASK_SCREENSIZE) != 0
                         && (requested->screenLayout & MASK_SCREENSIZE)) {
-                    return (screenLayout & MASK_SCREENSIZE);
+                    // A little backwards compatibility here: undefined is
+                    // considered equivalent to normal.  But only if the
+                    // requested size is at least normal; otherwise, small
+                    // is better than the default.
+                    int mySL = (screenLayout & MASK_SCREENSIZE);
+                    int oSL = (o.screenLayout & MASK_SCREENSIZE);
+                    int fixedMySL = mySL;
+                    int fixedOSL = oSL;
+                    if ((requested->screenLayout & MASK_SCREENSIZE) >= SCREENSIZE_NORMAL) {
+                        if (fixedMySL == 0) fixedMySL = SCREENSIZE_NORMAL;
+                        if (fixedOSL == 0) fixedOSL = SCREENSIZE_NORMAL;
+                    }
+                    // For screen size, the best match is the one that is
+                    // closest to the requested screen size, but not over
+                    // (the not over part is dealt with in match() below).
+                    if (fixedMySL == fixedOSL) {
+                        // If the two are the same, but 'this' is actually
+                        // undefined, then the other is really a better match.
+                        if (mySL == 0) return false;
+                        return true;
+                    }
+                    return fixedMySL >= fixedOSL;
                 }
                 if (((screenLayout^o.screenLayout) & MASK_SCREENLONG) != 0
                         && (requested->screenLayout & MASK_SCREENLONG)) {
@@ -1370,8 +1392,11 @@
         if (screenConfig != 0) {
             const int screenSize = screenLayout&MASK_SCREENSIZE;
             const int setScreenSize = settings.screenLayout&MASK_SCREENSIZE;
-            if (setScreenSize != 0 && screenSize != 0
-                    && screenSize != setScreenSize) {
+            // Any screen sizes for larger screens than the setting do not
+            // match.
+            if ((setScreenSize != 0 && screenSize != 0
+                    && screenSize > setScreenSize) ||
+                    (setScreenSize == 0 && screenSize != 0)) {
                 return false;
             }
             
diff --git a/include/utils/ZipFileCRO.h b/include/utils/ZipFileCRO.h
index 30e0036..e38bf66 100644
--- a/include/utils/ZipFileCRO.h
+++ b/include/utils/ZipFileCRO.h
@@ -47,8 +47,8 @@
         const char* fileName);
 
 extern bool ZipFileCRO_getEntryInfo(ZipFileCRO zip, ZipEntryCRO entry,
-        int* pMethod, long* pUncompLen,
-        long* pCompLen, off_t* pOffset, long* pModWhen, long* pCrc32);
+        int* pMethod, size_t* pUncompLen,
+        size_t* pCompLen, off_t* pOffset, long* pModWhen, long* pCrc32);
 
 extern bool ZipFileCRO_uncompressEntry(ZipFileCRO zip, ZipEntryCRO entry, int fd);
 
diff --git a/include/utils/ZipFileRO.h b/include/utils/ZipFileRO.h
index 51c4f2f..97d31f4 100644
--- a/include/utils/ZipFileRO.h
+++ b/include/utils/ZipFileRO.h
@@ -58,14 +58,19 @@
 class ZipFileRO {
 public:
     ZipFileRO()
-        : mFd(-1), mFileMap(NULL), mHashTableSize(-1), mHashTable(NULL)
+        : mFd(-1), mFileName(NULL), mFileLength(-1),
+          mDirectoryMap(NULL),
+          mNumEntries(-1), mDirectoryOffset(-1),
+          mHashTableSize(-1), mHashTable(NULL)
         {}
     ~ZipFileRO() {
         free(mHashTable);
-        if (mFileMap)
-            mFileMap->release();
+        if (mDirectoryMap)
+            mDirectoryMap->release();
         if (mFd >= 0)
             close(mFd);
+        if (mFileName)
+            free(mFileName);
     }
 
     /*
@@ -118,8 +123,8 @@
      * Returns "false" if "entry" is bogus or if the data in the Zip file
      * appears to be bad.
      */
-    bool getEntryInfo(ZipEntryRO entry, int* pMethod, long* pUncompLen,
-        long* pCompLen, off_t* pOffset, long* pModWhen, long* pCrc32) const;
+    bool getEntryInfo(ZipEntryRO entry, int* pMethod, size_t* pUncompLen,
+        size_t* pCompLen, off_t* pOffset, long* pModWhen, long* pCrc32) const;
 
     /*
      * Create a new FileMap object that maps a subset of the archive.  For
@@ -155,13 +160,13 @@
      * Utility function: uncompress deflated data, buffer to buffer.
      */
     static bool inflateBuffer(void* outBuf, const void* inBuf,
-        long uncompLen, long compLen);
+        size_t uncompLen, size_t compLen);
 
     /*
      * Utility function: uncompress deflated data, buffer to fd.
      */
     static bool inflateBuffer(int fd, const void* inBuf,
-        long uncompLen, long compLen);
+        size_t uncompLen, size_t compLen);
 
     /*
      * Some basic functions for raw data manipulation.  "LE" means
@@ -179,6 +184,9 @@
     ZipFileRO(const ZipFileRO& src);
     ZipFileRO& operator=(const ZipFileRO& src);
 
+    /* locate and parse the central directory */
+    bool mapCentralDirectory(void);
+
     /* parse the archive, prepping internal structures */
     bool parseZipArchive(void);
 
@@ -203,12 +211,21 @@
     /* open Zip archive */
     int         mFd;
 
+    /* zip file name */
+    char*       mFileName;
+
+    /* length of file */
+    size_t      mFileLength;
+
     /* mapped file */
-    FileMap*    mFileMap;
+    FileMap*    mDirectoryMap;
 
     /* number of entries in the Zip archive */
     int         mNumEntries;
 
+    /* CD directory offset in the Zip archive */
+    off_t       mDirectoryOffset;
+
     /*
      * We know how many entries are in the Zip archive, so we have a
      * fixed-size hash table.  We probe for an empty slot.
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/AudioDumpInterface.cpp b/libs/audioflinger/AudioDumpInterface.cpp
index a018b4c..6c11114 100644
--- a/libs/audioflinger/AudioDumpInterface.cpp
+++ b/libs/audioflinger/AudioDumpInterface.cpp
@@ -32,7 +32,7 @@
 // ----------------------------------------------------------------------------
 
 AudioDumpInterface::AudioDumpInterface(AudioHardwareInterface* hw)
-    : mFirstHwOutput(true), mPolicyCommands(String8("")), mFileName(String8(""))
+    : mPolicyCommands(String8("")), mFileName(String8(""))
 {
     if(hw == 0) {
         LOGE("Dump construct hw = 0");
@@ -47,6 +47,11 @@
     for (size_t i = 0; i < mOutputs.size(); i++) {
         closeOutputStream((AudioStreamOut *)mOutputs[i]);
     }
+
+    for (size_t i = 0; i < mInputs.size(); i++) {
+        closeInputStream((AudioStreamIn *)mInputs[i]);
+    }
+
     if(mFinalInterface) delete mFinalInterface;
 }
 
@@ -60,31 +65,32 @@
     uint32_t lRate = 44100;
 
 
-    if (AudioSystem::isA2dpDevice((AudioSystem::audio_devices)devices) || mFirstHwOutput) {
-        outFinal = mFinalInterface->openOutputStream(devices, format, channels, sampleRate, status);
-        if (outFinal != 0) {
-            lFormat = outFinal->format();
-            lChannels = outFinal->channels();
-            lRate = outFinal->sampleRate();
-            if (!AudioSystem::isA2dpDevice((AudioSystem::audio_devices)devices)) {
-                mFirstHwOutput = false;
+    outFinal = mFinalInterface->openOutputStream(devices, format, channels, sampleRate, status);
+    if (outFinal != 0) {
+        lFormat = outFinal->format();
+        lChannels = outFinal->channels();
+        lRate = outFinal->sampleRate();
+    } else {
+        if (format != 0) {
+            if (*format != 0) {
+                lFormat = *format;
+            } else {
+                *format = lFormat;
             }
         }
-    } else {
-        if (format != 0 && *format != 0) {
-            lFormat = *format;
-        } else {
-            lFormat = AudioSystem::PCM_16_BIT;
+        if (channels != 0) {
+            if (*channels != 0) {
+                lChannels = *channels;
+            } else {
+                *channels = lChannels;
+            }
         }
-        if (channels != 0 && *channels != 0) {
-            lChannels = *channels;
-        } else {
-            lChannels = AudioSystem::CHANNEL_OUT_STEREO;
-        }
-        if (sampleRate != 0 && *sampleRate != 0) {
-            lRate = *sampleRate;
-        } else {
-            lRate = 44100;
+        if (sampleRate != 0) {
+            if (*sampleRate != 0) {
+                lRate = *sampleRate;
+            } else {
+                *sampleRate = lRate;
+            }
         }
         if (status) *status = NO_ERROR;
     }
@@ -111,7 +117,6 @@
     dumpOut->standby();
     if (dumpOut->finalStream() != NULL) {
         mFinalInterface->closeOutputStream(dumpOut->finalStream());
-        mFirstHwOutput = true;
     }
 
     mOutputs.remove(dumpOut);
@@ -126,18 +131,33 @@
     uint32_t lChannels = AudioSystem::CHANNEL_IN_MONO;
     uint32_t lRate = 8000;
 
-
-    if (mInputs.size() == 0) {
-        inFinal = mFinalInterface->openInputStream(devices, format, channels, sampleRate, status, acoustics);
-        if (inFinal == 0) return 0;
-
+    inFinal = mFinalInterface->openInputStream(devices, format, channels, sampleRate, status, acoustics);
+    if (inFinal != 0) {
         lFormat = inFinal->format();
         lChannels = inFinal->channels();
         lRate = inFinal->sampleRate();
     } else {
-        if (format != 0 && *format != 0) lFormat = *format;
-        if (channels != 0 && *channels != 0) lChannels = *channels;
-        if (sampleRate != 0 && *sampleRate != 0) lRate = *sampleRate;
+        if (format != 0) {
+            if (*format != 0) {
+                lFormat = *format;
+            } else {
+                *format = lFormat;
+            }
+        }
+        if (channels != 0) {
+            if (*channels != 0) {
+                lChannels = *channels;
+            } else {
+                *channels = lChannels;
+            }
+        }
+        if (sampleRate != 0) {
+            if (*sampleRate != 0) {
+                lRate = *sampleRate;
+            } else {
+                *sampleRate = lRate;
+            }
+        }
         if (status) *status = NO_ERROR;
     }
     LOGV("openInputStream(), inFinal %p", inFinal);
@@ -223,6 +243,15 @@
     return keyValuePairs;
 }
 
+status_t AudioDumpInterface::setMode(int mode)
+{
+    return mFinalInterface->setMode(mode);
+}
+
+size_t AudioDumpInterface::getInputBufferSize(uint32_t sampleRate, int format, int channelCount)
+{
+    return mFinalInterface->getInputBufferSize(sampleRate, format, channelCount);
+}
 
 // ----------------------------------------------------------------------------
 
@@ -235,7 +264,7 @@
                                         uint32_t sampleRate)
     : mInterface(interface), mId(id),
       mSampleRate(sampleRate), mFormat(format), mChannels(channels), mLatency(0), mDevice(devices),
-      mBufferSize(1024), mFinalStream(finalStream), mOutFile(0), mFileCount(0)
+      mBufferSize(1024), mFinalStream(finalStream), mFile(0), mFileCount(0)
 {
     LOGV("AudioStreamOutDump Constructor %p, mInterface %p, mFinalStream %p", this, mInterface, mFinalStream);
 }
@@ -254,26 +283,26 @@
     if (mFinalStream) {
         ret = mFinalStream->write(buffer, bytes);
     } else {
-        usleep((bytes * 1000000) / frameSize() / sampleRate());
+        usleep((((bytes * 1000) / frameSize()) / sampleRate()) * 1000);
         ret = bytes;
     }
-    if(!mOutFile) {
+    if(!mFile) {
         if (mInterface->fileName() != "") {
             char name[255];
-            sprintf(name, "%s_%d_%d.pcm", mInterface->fileName().string(), mId, ++mFileCount);
-            mOutFile = fopen(name, "wb");
-            LOGV("Opening dump file %s, fh %p", name, mOutFile);
+            sprintf(name, "%s_out_%d_%d.pcm", mInterface->fileName().string(), mId, ++mFileCount);
+            mFile = fopen(name, "wb");
+            LOGV("Opening dump file %s, fh %p", name, mFile);
         }
     }
-    if (mOutFile) {
-        fwrite(buffer, bytes, 1, mOutFile);
+    if (mFile) {
+        fwrite(buffer, bytes, 1, mFile);
     }
     return ret;
 }
 
 status_t AudioStreamOutDump::standby()
 {
-    LOGV("AudioStreamOutDump standby(), mOutFile %p, mFinalStream %p", mOutFile, mFinalStream);
+    LOGV("AudioStreamOutDump standby(), mFile %p, mFinalStream %p", mFile, mFinalStream);
 
     Close();
     if (mFinalStream != 0 ) return mFinalStream->standby();
@@ -330,7 +359,7 @@
     }
 
     if (param.getInt(String8("format"), valueInt) == NO_ERROR) {
-        if (mOutFile == 0) {
+        if (mFile == 0) {
             mFormat = valueInt;
         } else {
             status = INVALID_OPERATION;
@@ -345,7 +374,7 @@
     }
     if (param.getInt(String8("sampling_rate"), valueInt) == NO_ERROR) {
         if (valueInt > 0 && valueInt <= 48000) {
-            if (mOutFile == 0) {
+            if (mFile == 0) {
                 mSampleRate = valueInt;
             } else {
                 status = INVALID_OPERATION;
@@ -373,9 +402,9 @@
 
 void AudioStreamOutDump::Close()
 {
-    if(mOutFile) {
-        fclose(mOutFile);
-        mOutFile = 0;
+    if(mFile) {
+        fclose(mFile);
+        mFile = 0;
     }
 }
 
@@ -396,7 +425,7 @@
                                         uint32_t sampleRate)
     : mInterface(interface), mId(id),
       mSampleRate(sampleRate), mFormat(format), mChannels(channels), mDevice(devices),
-      mBufferSize(1024), mFinalStream(finalStream), mInFile(0)
+      mBufferSize(1024), mFinalStream(finalStream), mFile(0), mFileCount(0)
 {
     LOGV("AudioStreamInDump Constructor %p, mInterface %p, mFinalStream %p", this, mInterface, mFinalStream);
 }
@@ -409,55 +438,68 @@
 
 ssize_t AudioStreamInDump::read(void* buffer, ssize_t bytes)
 {
+    ssize_t ret;
+
     if (mFinalStream) {
-        return mFinalStream->read(buffer, bytes);
-    }
-
-    usleep((bytes * 1000000) / frameSize() / sampleRate());
-
-    if(!mInFile) {
-        char name[255];
-        strcpy(name, "/sdcard/music/sine440");
-        if (channels() == AudioSystem::CHANNEL_IN_MONO) {
-            strcat(name, "_mo");
-        } else {
-            strcat(name, "_st");
+        ret = mFinalStream->read(buffer, bytes);
+        if(!mFile) {
+            if (mInterface->fileName() != "") {
+                char name[255];
+                sprintf(name, "%s_in_%d_%d.pcm", mInterface->fileName().string(), mId, ++mFileCount);
+                mFile = fopen(name, "wb");
+                LOGV("Opening input dump file %s, fh %p", name, mFile);
+            }
         }
-        if (format() == AudioSystem::PCM_16_BIT) {
-            strcat(name, "_16b");
-        } else {
-            strcat(name, "_8b");
+        if (mFile) {
+            fwrite(buffer, bytes, 1, mFile);
         }
-        if (sampleRate() < 16000) {
-            strcat(name, "_8k");
-        } else if (sampleRate() < 32000) {
-            strcat(name, "_22k");
-        } else if (sampleRate() < 48000) {
-            strcat(name, "_44k");
-        } else {
-            strcat(name, "_48k");
+    } else {
+        usleep((((bytes * 1000) / frameSize()) / sampleRate()) * 1000);
+        ret = bytes;
+        if(!mFile) {
+            char name[255];
+            strcpy(name, "/sdcard/music/sine440");
+            if (channels() == AudioSystem::CHANNEL_IN_MONO) {
+                strcat(name, "_mo");
+            } else {
+                strcat(name, "_st");
+            }
+            if (format() == AudioSystem::PCM_16_BIT) {
+                strcat(name, "_16b");
+            } else {
+                strcat(name, "_8b");
+            }
+            if (sampleRate() < 16000) {
+                strcat(name, "_8k");
+            } else if (sampleRate() < 32000) {
+                strcat(name, "_22k");
+            } else if (sampleRate() < 48000) {
+                strcat(name, "_44k");
+            } else {
+                strcat(name, "_48k");
+            }
+            strcat(name, ".wav");
+            mFile = fopen(name, "rb");
+            LOGV("Opening input read file %s, fh %p", name, mFile);
+            if (mFile) {
+                fseek(mFile, AUDIO_DUMP_WAVE_HDR_SIZE, SEEK_SET);
+            }
         }
-        strcat(name, ".wav");
-        mInFile = fopen(name, "rb");
-        LOGV("Opening dump file %s, fh %p", name, mInFile);
-        if (mInFile) {
-            fseek(mInFile, AUDIO_DUMP_WAVE_HDR_SIZE, SEEK_SET);
-        }
-
-    }
-    if (mInFile) {
-        ssize_t bytesRead = fread(buffer, bytes, 1, mInFile);
-        if (bytesRead != bytes) {
-            fseek(mInFile, AUDIO_DUMP_WAVE_HDR_SIZE, SEEK_SET);
-            fread((uint8_t *)buffer+bytesRead, bytes-bytesRead, 1, mInFile);
+        if (mFile) {
+            ssize_t bytesRead = fread(buffer, bytes, 1, mFile);
+            if (bytesRead >=0 && bytesRead < bytes) {
+                fseek(mFile, AUDIO_DUMP_WAVE_HDR_SIZE, SEEK_SET);
+                fread((uint8_t *)buffer+bytesRead, bytes-bytesRead, 1, mFile);
+            }
         }
     }
-    return bytes;
+
+    return ret;
 }
 
 status_t AudioStreamInDump::standby()
 {
-    LOGV("AudioStreamInDump standby(), mInFile %p, mFinalStream %p", mInFile, mFinalStream);
+    LOGV("AudioStreamInDump standby(), mFile %p, mFinalStream %p", mFile, mFinalStream);
 
     Close();
     if (mFinalStream != 0 ) return mFinalStream->standby();
@@ -523,9 +565,9 @@
 
 void AudioStreamInDump::Close()
 {
-    if(mInFile) {
-        fclose(mInFile);
-        mInFile = 0;
+    if(mFile) {
+        fclose(mFile);
+        mFile = 0;
     }
 }
 }; // namespace android
diff --git a/libs/audioflinger/AudioDumpInterface.h b/libs/audioflinger/AudioDumpInterface.h
index 4c62b3e..814ce5f 100644
--- a/libs/audioflinger/AudioDumpInterface.h
+++ b/libs/audioflinger/AudioDumpInterface.h
@@ -69,7 +69,7 @@
     uint32_t mDevice;                   // current device this output is routed to
     size_t  mBufferSize;
     AudioStreamOut      *mFinalStream;
-    FILE                *mOutFile;      // output file
+    FILE                *mFile;      // output file
     int                 mFileCount;
 };
 
@@ -109,7 +109,8 @@
     uint32_t mDevice;                   // current device this output is routed to
     size_t  mBufferSize;
     AudioStreamIn      *mFinalStream;
-    FILE                *mInFile;      // output file
+    FILE                *mFile;      // output file
+    int                 mFileCount;
 };
 
 class AudioDumpInterface : public AudioHardwareBase
@@ -134,6 +135,8 @@
     virtual status_t    setMasterVolume(float volume)
                             {return mFinalInterface->setMasterVolume(volume);}
 
+    virtual status_t    setMode(int mode);
+
     // mic mute
     virtual status_t    setMicMute(bool state)
                             {return mFinalInterface->setMicMute(state);}
@@ -143,6 +146,8 @@
     virtual status_t    setParameters(const String8& keyValuePairs);
     virtual String8     getParameters(const String8& keys);
 
+    virtual size_t      getInputBufferSize(uint32_t sampleRate, int format, int channelCount);
+
     virtual AudioStreamIn* openInputStream(uint32_t devices, int *format, uint32_t *channels,
             uint32_t *sampleRate, status_t *status, AudioSystem::audio_in_acoustics acoustics);
     virtual    void        closeInputStream(AudioStreamIn* in);
@@ -153,8 +158,7 @@
 protected:
 
     AudioHardwareInterface          *mFinalInterface;
-    SortedVector<AudioStreamOutDump *>    mOutputs;
-    bool                            mFirstHwOutput;
+    SortedVector<AudioStreamOutDump *>   mOutputs;
     SortedVector<AudioStreamInDump *>    mInputs;
     Mutex                           mLock;
     String8                         mPolicyCommands;
diff --git a/libs/audioflinger/AudioFlinger.cpp b/libs/audioflinger/AudioFlinger.cpp
index 2414e8d..3b38d83 100644
--- a/libs/audioflinger/AudioFlinger.cpp
+++ b/libs/audioflinger/AudioFlinger.cpp
@@ -142,6 +142,7 @@
     }
 #ifdef LVMX
     LifeVibes::init();
+    mLifeVibesClientPid = -1;
 #endif
 }
 
@@ -596,8 +597,10 @@
     int musicEnabled = -1;
     if (NO_ERROR == param.get(key, value)) {
         if (value == LifevibesEnable) {
+            mLifeVibesClientPid = IPCThreadState::self()->getCallingPid();
             musicEnabled = 1;
         } else if (value == LifevibesDisable) {
+            mLifeVibesClientPid = -1;
             musicEnabled = 0;
         }
     }
@@ -609,7 +612,7 @@
         mHardwareStatus = AUDIO_SET_PARAMETER;
         result = mAudioHardware->setParameters(keyValuePairs);
 #ifdef LVMX
-        if ((NO_ERROR == result) && (musicEnabled != -1)) {
+        if (musicEnabled != -1) {
             LifeVibes::enableMusic((bool) musicEnabled);
         }
 #endif
@@ -713,51 +716,57 @@
 void AudioFlinger::registerClient(const sp<IAudioFlingerClient>& client)
 {
 
-    LOGV("registerClient() %p, tid %d, calling tid %d", client.get(), gettid(), IPCThreadState::self()->getCallingPid());
     Mutex::Autolock _l(mLock);
 
-    sp<IBinder> binder = client->asBinder();
-    if (mNotificationClients.indexOf(binder) < 0) {
-        LOGV("Adding notification client %p", binder.get());
-        binder->linkToDeath(this);
-        mNotificationClients.add(binder);
-    }
+    int pid = IPCThreadState::self()->getCallingPid();
+    if (mNotificationClients.indexOfKey(pid) < 0) {
+        sp<NotificationClient> notificationClient = new NotificationClient(this,
+                                                                            client,
+                                                                            pid);
+        LOGV("registerClient() client %p, pid %d", notificationClient.get(), pid);
 
-    // the config change is always sent from playback or record threads to avoid deadlock
-    // with AudioSystem::gLock
-    for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
-        mPlaybackThreads.valueAt(i)->sendConfigEvent(AudioSystem::OUTPUT_OPENED);
-    }
+        mNotificationClients.add(pid, notificationClient);
 
-    for (size_t i = 0; i < mRecordThreads.size(); i++) {
-        mRecordThreads.valueAt(i)->sendConfigEvent(AudioSystem::INPUT_OPENED);
-    }
-}
+        sp<IBinder> binder = client->asBinder();
+        binder->linkToDeath(notificationClient);
 
-void AudioFlinger::binderDied(const wp<IBinder>& who) {
+        // the config change is always sent from playback or record threads to avoid deadlock
+        // with AudioSystem::gLock
+        for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
+            mPlaybackThreads.valueAt(i)->sendConfigEvent(AudioSystem::OUTPUT_OPENED);
+        }
 
-    LOGV("binderDied() %p, tid %d, calling tid %d", who.unsafe_get(), gettid(), IPCThreadState::self()->getCallingPid());
-    Mutex::Autolock _l(mLock);
-
-    IBinder *binder = who.unsafe_get();
-
-    if (binder != NULL) {
-        int index = mNotificationClients.indexOf(binder);
-        if (index >= 0) {
-            LOGV("Removing notification client %p", binder);
-            mNotificationClients.removeAt(index);
+        for (size_t i = 0; i < mRecordThreads.size(); i++) {
+            mRecordThreads.valueAt(i)->sendConfigEvent(AudioSystem::INPUT_OPENED);
         }
     }
 }
 
+void AudioFlinger::removeNotificationClient(pid_t pid)
+{
+    Mutex::Autolock _l(mLock);
+
+    int index = mNotificationClients.indexOfKey(pid);
+    if (index >= 0) {
+        sp <NotificationClient> client = mNotificationClients.valueFor(pid);
+        LOGV("removeNotificationClient() %p, pid %d", client.get(), pid);
+#ifdef LVMX
+        if (pid == mLifeVibesClientPid) {
+            LOGV("Disabling lifevibes");
+            LifeVibes::enableMusic(false);
+            mLifeVibesClientPid = -1;
+        }
+#endif
+        mNotificationClients.removeItem(pid);
+    }
+}
+
 // audioConfigChanged_l() must be called with AudioFlinger::mLock held
-void AudioFlinger::audioConfigChanged_l(int event, int ioHandle, void *param2) {
+void AudioFlinger::audioConfigChanged_l(int event, int ioHandle, void *param2)
+{
     size_t size = mNotificationClients.size();
     for (size_t i = 0; i < size; i++) {
-        sp<IBinder> binder = mNotificationClients.itemAt(i);
-        LOGV("audioConfigChanged_l() Notifying change to client %p", binder.get());
-        sp<IAudioFlingerClient> client = interface_cast<IAudioFlingerClient> (binder);
-        client->ioConfigChanged(event, ioHandle, param2);
+        mNotificationClients.valueAt(i)->client()->ioConfigChanged(event, ioHandle, param2);
     }
 }
 
@@ -768,12 +777,13 @@
     mClients.removeItem(pid);
 }
 
+
 // ----------------------------------------------------------------------------
 
 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)
 {
 }
 
@@ -806,7 +816,7 @@
 
 int AudioFlinger::ThreadBase::channelCount() const
 {
-    return mChannelCount;
+    return (int)mChannelCount;
 }
 
 int AudioFlinger::ThreadBase::format() const
@@ -863,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();
     }
@@ -943,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()
@@ -1054,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;
@@ -1224,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;
@@ -1247,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
@@ -1604,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()
@@ -2332,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();
                 }
@@ -2356,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;
        }
    }
@@ -2423,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 {
@@ -2435,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;
     }
 
@@ -2522,7 +2487,7 @@
             (mClient == NULL) ? getpid() : mClient->pid(),
             mStreamType,
             mFormat,
-            mCblk->channels,
+            mCblk->channelCount,
             mFrameCount,
             mState,
             mMute,
@@ -2579,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;
@@ -2696,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;
     }
@@ -2808,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;
     }
 }
 
@@ -2817,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,
@@ -2841,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);
     }
@@ -2882,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;
@@ -2898,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);
@@ -2939,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()) {
@@ -2964,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 {
@@ -2983,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();
@@ -3086,6 +3051,28 @@
 
 // ----------------------------------------------------------------------------
 
+AudioFlinger::NotificationClient::NotificationClient(const sp<AudioFlinger>& audioFlinger,
+                                                     const sp<IAudioFlingerClient>& client,
+                                                     pid_t pid)
+    : mAudioFlinger(audioFlinger), mPid(pid), mClient(client)
+{
+}
+
+AudioFlinger::NotificationClient::~NotificationClient()
+{
+    mClient.clear();
+}
+
+void AudioFlinger::NotificationClient::binderDied(const wp<IBinder>& who)
+{
+    sp<NotificationClient> keep(this);
+    {
+        mAudioFlinger->removeNotificationClient(mPid);
+    }
+}
+
+// ----------------------------------------------------------------------------
+
 AudioFlinger::TrackHandle::TrackHandle(const sp<AudioFlinger::PlaybackThread::Track>& track)
     : BnAudioTrack(),
       mTrack(track)
@@ -3242,7 +3229,6 @@
     mReqChannelCount = AudioSystem::popCount(channels);
     mReqSampleRate = sampleRate;
     readInputParameters();
-    sendConfigEvent(AudioSystem::INPUT_OPENED);
 }
 
 
@@ -3339,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 {
@@ -3360,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 {
@@ -3657,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;
@@ -3676,7 +3662,6 @@
     default:
         break;
     }
-    Mutex::Autolock _l(mAudioFlinger->mLock);
     mAudioFlinger->audioConfigChanged_l(event, mId, param2);
 }
 
@@ -3688,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];
@@ -3795,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;
     }
 
@@ -3816,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;
 }
 
@@ -3945,6 +3935,8 @@
 
         input->standby();
 
+        // notify client processes of the new input creation
+        thread->audioConfigChanged_l(AudioSystem::INPUT_OPENED);
         return mNextThreadId;
     }
 
@@ -3985,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 739ec33..f35f38b 100644
--- a/libs/audioflinger/AudioFlinger.h
+++ b/libs/audioflinger/AudioFlinger.h
@@ -57,7 +57,7 @@
 
 static const nsecs_t kStandbyTimeInNsecs = seconds(3);
 
-class AudioFlinger : public BnAudioFlinger, public IBinder::DeathRecipient
+class AudioFlinger : public BnAudioFlinger
 {
 public:
     static void instantiate();
@@ -139,9 +139,6 @@
 
     virtual status_t getRenderPosition(uint32_t *halFrames, uint32_t *dspFrames, int output);
 
-    // IBinder::DeathRecipient
-    virtual     void        binderDied(const wp<IBinder>& who);
-
     enum hardware_call_state {
         AUDIO_HW_IDLE = 0,
         AUDIO_HW_INIT,
@@ -205,6 +202,27 @@
         pid_t               mPid;
     };
 
+    // --- Notification Client ---
+    class NotificationClient : public IBinder::DeathRecipient {
+    public:
+                            NotificationClient(const sp<AudioFlinger>& audioFlinger,
+                                                const sp<IAudioFlingerClient>& client,
+                                                pid_t pid);
+        virtual             ~NotificationClient();
+
+                sp<IAudioFlingerClient>    client() { return mClient; }
+
+                // IBinder::DeathRecipient
+                virtual     void        binderDied(const wp<IBinder>& who);
+
+    private:
+                            NotificationClient(const NotificationClient&);
+                            NotificationClient& operator = (const NotificationClient&);
+
+        sp<AudioFlinger>        mAudioFlinger;
+        pid_t                   mPid;
+        sp<IAudioFlingerClient> mClient;
+    };
 
     class TrackHandle;
     class RecordHandle;
@@ -324,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();
@@ -348,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;
@@ -528,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 {
@@ -594,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);
 
@@ -685,6 +700,7 @@
 
 
                 void        removeClient_l(pid_t pid);
+                void        removeNotificationClient(pid_t pid);
 
 
     // record thread
@@ -744,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();
 
@@ -796,8 +812,11 @@
 
                 DefaultKeyedVector< int, sp<RecordThread> >    mRecordThreads;
 
-                SortedVector< sp<IBinder> >         mNotificationClients;
+                DefaultKeyedVector< pid_t, sp<NotificationClient> >    mNotificationClients;
                 int                                 mNextThreadId;
+#ifdef LVMX
+                int mLifeVibesClientPid;
+#endif
 };
 
 // ----------------------------------------------------------------------------
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/Android.mk b/libs/surfaceflinger/Android.mk
index 86eb78d..b8a0630 100644
--- a/libs/surfaceflinger/Android.mk
+++ b/libs/surfaceflinger/Android.mk
@@ -13,6 +13,7 @@
     LayerDim.cpp \
     MessageQueue.cpp \
     SurfaceFlinger.cpp \
+    TextureManager.cpp \
     Tokenizer.cpp \
     Transform.cpp
 
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 ea68352..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);
 }
@@ -125,7 +125,6 @@
     EGLint numConfigs=0;
     EGLSurface surface;
     EGLContext context;
-    mFlags = CACHED_BUFFERS;
 
     // TODO: all the extensions below should be queried through
     // eglGetProcAddress().
@@ -253,22 +252,10 @@
     LOGI("GL_MAX_TEXTURE_SIZE = %d", mMaxTextureSize);
     LOGI("GL_MAX_VIEWPORT_DIMS = %d", mMaxViewportDims);
 
-#if 0
-    // for drivers that don't have proper support for flushing cached buffers
-    // on gralloc unlock, uncomment this block and test for the specific
-    // renderer substring
-    if (strstr(gl_renderer, "<some vendor string>")) {
-        LOGD("Assuming uncached graphics buffers.");
-        mFlags &= ~CACHED_BUFFERS;
-    }
-#endif
 
     if (strstr(gl_extensions, "GL_ARB_texture_non_power_of_two")) {
         mFlags |= NPOT_EXTENSION;
     }
-    if (strstr(gl_extensions, "GL_OES_draw_texture")) {
-        mFlags |= DRAW_TEXTURE_EXTENSION;
-    }
 #ifdef EGL_ANDROID_image_native_buffer
     if (strstr( gl_extensions, "GL_OES_EGL_image") &&
         (strstr(egl_extensions, "EGL_KHR_image_base") || 
diff --git a/libs/surfaceflinger/DisplayHardware/DisplayHardware.h b/libs/surfaceflinger/DisplayHardware/DisplayHardware.h
index df046af..ebd7c42 100644
--- a/libs/surfaceflinger/DisplayHardware/DisplayHardware.h
+++ b/libs/surfaceflinger/DisplayHardware/DisplayHardware.h
@@ -46,12 +46,10 @@
         DIRECT_TEXTURE          = 0x00000002,
         COPY_BITS_EXTENSION     = 0x00000008,
         NPOT_EXTENSION          = 0x00000100,
-        DRAW_TEXTURE_EXTENSION  = 0x00000200,
         BUFFER_PRESERVED        = 0x00010000,
         PARTIAL_UPDATES         = 0x00020000,   // video driver feature
         SLOW_CONFIG             = 0x00040000,   // software
         SWAP_RECTANGLE          = 0x00080000,
-        CACHED_BUFFERS          = 0x00100000
     };
 
     DisplayHardware(
diff --git a/libs/surfaceflinger/Layer.cpp b/libs/surfaceflinger/Layer.cpp
index ce7e9aa..3fbb4d3 100644
--- a/libs/surfaceflinger/Layer.cpp
+++ b/libs/surfaceflinger/Layer.cpp
@@ -47,47 +47,42 @@
 
 // ---------------------------------------------------------------------------
 
-const uint32_t Layer::typeInfo = LayerBaseClient::typeInfo | 4;
-const char* const Layer::typeID = "Layer";
-
-// ---------------------------------------------------------------------------
-
 Layer::Layer(SurfaceFlinger* flinger, DisplayID display, 
-        const sp<Client>& c, int32_t i)
-    :   LayerBaseClient(flinger, display, c, i),
+        const sp<Client>& client, int32_t i)
+    :   LayerBaseClient(flinger, display, client, i),
+        lcblk(NULL),
         mSecure(false),
-        mNoEGLImageForSwBuffers(false),
         mNeedsBlending(true),
-        mNeedsDithering(false)
+        mNeedsDithering(false),
+        mTextureManager(mFlags),
+        mBufferManager(mTextureManager),
+        mWidth(0), mHeight(0), mFixedSize(false)
 {
     // no OpenGL operation is possible here, since we might not be
     // in the OpenGL thread.
-    mFrontBufferIndex = lcblk->getFrontBuffer();
+    lcblk = new SharedBufferServer(
+            client->ctrlblk, i, mBufferManager.getDefaultBufferCount(),
+            getIdentity());
+
+   mBufferManager.setActiveBufferIndex( lcblk->getFrontBuffer() );
 }
 
 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;
 }
 
-void Layer::destroy()
+// called with SurfaceFlinger::mStateLock as soon as the layer is entered
+// in the purgatory list
+void Layer::onRemoved()
 {
-    for (size_t i=0 ; i<NUM_BUFFERS ; i++) {
-        if (mTextures[i].name != -1U) {
-            glDeleteTextures(1, &mTextures[i].name);
-            mTextures[i].name = -1U;
-        }
-        if (mTextures[i].image != EGL_NO_IMAGE_KHR) {
-            EGLDisplay dpy(mFlinger->graphicPlane(0).getEGLDisplay());
-            eglDestroyImageKHR(dpy, mTextures[i].image);
-            mTextures[i].image = EGL_NO_IMAGE_KHR;
-        }
-        Mutex::Autolock _l(mLock);
-        mBuffers[i].clear();
-        mWidth = mHeight = 0;
-    }
-    mSurface.clear();
+    // wake up the condition
+    lcblk->setStatus(NO_INIT);
 }
 
 sp<LayerBaseClient::Surface> Layer::createSurface() const
@@ -97,9 +92,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;
 }
 
@@ -131,24 +134,19 @@
     mHeight = h;
     mSecure = (flags & ISurfaceComposer::eSecure) ? true : false;
     mNeedsBlending = (info.h_alpha - info.l_alpha) > 0;
-    mNoEGLImageForSwBuffers = !(hwFlags & DisplayHardware::CACHED_BUFFERS);
 
     // we use the red index
     int displayRedSize = displayInfo.getSize(PixelFormatInfo::INDEX_RED);
     int layerRedsize = info.getSize(PixelFormatInfo::INDEX_RED);
     mNeedsDithering = layerRedsize > displayRedSize;
 
-    for (size_t i=0 ; i<NUM_BUFFERS ; i++) {
-        mBuffers[i] = new GraphicBuffer();
-    }
     mSurface = new SurfaceLayer(mFlinger, clientIndex(), this);
     return NO_ERROR;
 }
 
 void Layer::reloadTexture(const Region& dirty)
 {
-    Mutex::Autolock _l(mLock);
-    sp<GraphicBuffer> buffer(getFrontBufferLocked());
+    sp<GraphicBuffer> buffer(mBufferManager.getActiveBuffer());
     if (buffer == NULL) {
         // this situation can happen if we ran out of memory for instance.
         // not much we can do. continue to use whatever texture was bound
@@ -156,118 +154,24 @@
         return;
     }
 
-    const int index = mFrontBufferIndex;
-
-    // create the new texture name if needed
-    if (UNLIKELY(mTextures[index].name == -1U)) {
-        mTextures[index].name = createTexture();
-        mTextures[index].width = 0;
-        mTextures[index].height = 0;
-    }
-
 #ifdef EGL_ANDROID_image_native_buffer
     if (mFlags & DisplayHardware::DIRECT_TEXTURE) {
-        if (buffer->usage & GraphicBuffer::USAGE_HW_TEXTURE) {
-            if (mTextures[index].dirty) {
-                if (initializeEglImage(buffer, &mTextures[index]) != NO_ERROR) {
-                    // not sure what we can do here...
-                    mFlags &= ~DisplayHardware::DIRECT_TEXTURE;
-                    goto slowpath;
-                }
-            }
-        } else {
-            if (mHybridBuffer==0 || (mHybridBuffer->width != buffer->width ||
-                    mHybridBuffer->height != buffer->height)) {
-                mHybridBuffer.clear();
-                mHybridBuffer = new GraphicBuffer(
-                        buffer->width, buffer->height, buffer->format,
-                        GraphicBuffer::USAGE_SW_WRITE_OFTEN |
-                        GraphicBuffer::USAGE_HW_TEXTURE);
-                if (initializeEglImage(
-                        mHybridBuffer, &mTextures[0]) != NO_ERROR) {
-                    // not sure what we can do here...
-                    mFlags &= ~DisplayHardware::DIRECT_TEXTURE;
-                    mHybridBuffer.clear();
-                    goto slowpath;
-                }
-            }
-
-            GGLSurface t;
-            status_t res = buffer->lock(&t, GRALLOC_USAGE_SW_READ_OFTEN);
-            LOGE_IF(res, "error %d (%s) locking buffer %p",
-                    res, strerror(res), buffer.get());
-            if (res == NO_ERROR) {
-                Texture* const texture(&mTextures[0]);
-
-                glBindTexture(GL_TEXTURE_2D, texture->name);
-
-                sp<GraphicBuffer> buf(mHybridBuffer);
-                void* vaddr;
-                res = buf->lock(GraphicBuffer::USAGE_SW_WRITE_OFTEN, &vaddr);
-                if (res == NO_ERROR) {
-                    int bpp = 0;
-                    switch (t.format) {
-                    case HAL_PIXEL_FORMAT_RGB_565:
-                    case HAL_PIXEL_FORMAT_RGBA_4444:
-                        bpp = 2;
-                        break;
-                    case HAL_PIXEL_FORMAT_RGBA_8888:
-                    case HAL_PIXEL_FORMAT_RGBX_8888:
-                        bpp = 4;
-                        break;
-                    default:
-                        if (isSupportedYuvFormat(t.format)) {
-                            // just show the Y plane of YUV buffers
-                            bpp = 1;
-                            break;
-                        }
-                        // oops, we don't handle this format!
-                        LOGE("layer %p, texture=%d, using format %d, which is not "
-                                "supported by the GL", this, texture->name, t.format);
-                    }
-                    if (bpp) {
-                        const Rect bounds(dirty.getBounds());
-                        size_t src_stride = t.stride;
-                        size_t dst_stride = buf->stride;
-                        if (src_stride == dst_stride &&
-                            bounds.width() == t.width &&
-                            bounds.height() == t.height)
-                        {
-                            memcpy(vaddr, t.data, t.height * t.stride * bpp);
-                        } else {
-                            GLubyte const * src = t.data +
-                                (bounds.left + bounds.top * src_stride) * bpp;
-                            GLubyte * dst = (GLubyte *)vaddr +
-                                (bounds.left + bounds.top * dst_stride) * bpp;
-                            const size_t length = bounds.width() * bpp;
-                            size_t h = bounds.height();
-                            src_stride *= bpp;
-                            dst_stride *= bpp;
-                            while (h--) {
-                                memcpy(dst, src, length);
-                                dst += dst_stride;
-                                src += src_stride;
-                            }
-                        }
-                    }
-                    buf->unlock();
-                }
-                buffer->unlock();
-            }
+        EGLDisplay dpy(mFlinger->graphicPlane(0).getEGLDisplay());
+        if (mBufferManager.initEglImage(dpy, buffer) != NO_ERROR) {
+            // not sure what we can do here...
+            mFlags &= ~DisplayHardware::DIRECT_TEXTURE;
+            goto slowpath;
         }
     } else
 #endif
     {
 slowpath:
-        for (size_t i=0 ; i<NUM_BUFFERS ; i++) {
-            mTextures[i].image = EGL_NO_IMAGE_KHR;
-        }
         GGLSurface t;
         status_t res = buffer->lock(&t, GRALLOC_USAGE_SW_READ_OFTEN);
         LOGE_IF(res, "error %d (%s) locking buffer %p",
                 res, strerror(res), buffer.get());
         if (res == NO_ERROR) {
-            loadTexture(&mTextures[0], dirty, t);
+            mBufferManager.loadTexture(dirty, t);
             buffer->unlock();
         }
     }
@@ -275,11 +179,8 @@
 
 void Layer::onDraw(const Region& clip) const
 {
-    int index = mFrontBufferIndex;
-    if (mTextures[index].image == EGL_NO_IMAGE_KHR)
-        index = 0;
-    GLuint textureName = mTextures[index].name;
-    if (UNLIKELY(textureName == -1LU)) {
+    Texture tex(mBufferManager.getActiveTexture());
+    if (tex.name == -1LU) {
         // the texture has not been created yet, this Layer has
         // in fact never been drawn into. This happens frequently with
         // SurfaceView because the WindowManager can't know when the client
@@ -305,13 +206,53 @@
         }
         return;
     }
-    drawWithOpenGL(clip, mTextures[index]);
+    drawWithOpenGL(clip, tex);
 }
 
-sp<GraphicBuffer> Layer::requestBuffer(int index, int usage)
+bool Layer::needsFiltering() const
+{
+    if (!(mFlags & DisplayHardware::SLOW_CONFIG)) {
+        // NOTE: there is a race here, because mFixedSize is updated in a
+        // binder transaction. however, it doesn't really matter since it is
+        // evaluated each time we draw. To be perfectly correct, this flag
+        // would have to be associated with a buffer.
+        if (mFixedSize)
+            return true;
+    }
+    return LayerBase::needsFiltering();
+}
+
+
+status_t Layer::setBufferCount(int bufferCount)
+{
+    // Ensures our client doesn't go away while we're accessing
+    // the shared area.
+    sp<Client> ourClient(client.promote());
+    if (ourClient == 0) {
+        // oops, the client is already gone
+        return DEAD_OBJECT;
+    }
+
+    // NOTE: lcblk->resize() is protected by an internal lock
+    status_t err = lcblk->resize(bufferCount);
+    if (err == NO_ERROR)
+        mBufferManager.resize(bufferCount);
+
+    return err;
+}
+
+sp<GraphicBuffer> Layer::requestBuffer(int index,
+        uint32_t reqWidth, uint32_t reqHeight, uint32_t reqFormat,
+        uint32_t usage)
 {
     sp<GraphicBuffer> buffer;
 
+    if ((reqWidth | reqHeight | reqFormat) < 0)
+        return buffer;
+
+    if ((!reqWidth && reqHeight) || (reqWidth && !reqHeight))
+        return buffer;
+
     // this ensures our client doesn't go away while we're accessing
     // the shared area.
     sp<Client> ourClient(client.promote());
@@ -324,7 +265,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
@@ -337,31 +278,33 @@
         return buffer;
     }
 
-    uint32_t w, h;
+    uint32_t w, h, f;
     { // scope for the lock
         Mutex::Autolock _l(mLock);
-        w = mWidth;
-        h = mHeight;
-        buffer = mBuffers[index];
-        
-        // destroy() could have been called before we get here, we log it
-        // because it's uncommon, and the code below should handle it
-        LOGW_IF(buffer==0, 
-                "mBuffers[%d] is null (mWidth=%d, mHeight=%d)",
-                index, w, h);
-        
-        mBuffers[index].clear();
+        const bool fixedSizeChanged = mFixedSize != (reqWidth && reqHeight);
+        const bool formatChanged    = mReqFormat != reqFormat;
+        mReqWidth  = reqWidth;
+        mReqHeight = reqHeight;
+        mReqFormat = reqFormat;
+        mFixedSize = reqWidth && reqHeight;
+        w = reqWidth  ? reqWidth  : mWidth;
+        h = reqHeight ? reqHeight : mHeight;
+        f = reqFormat ? reqFormat : mFormat;
+        buffer = mBufferManager.detachBuffer(index);
+        if (fixedSizeChanged || formatChanged) {
+            lcblk->reallocateAllExcept(index);
+        }
     }
 
     const uint32_t effectiveUsage = getEffectiveUsage(usage);
     if (buffer!=0 && buffer->getStrongCount() == 1) {
-        err = buffer->reallocate(w, h, mFormat, effectiveUsage);
+        err = buffer->reallocate(w, h, f, effectiveUsage);
     } else {
         // here we have to reallocate a new buffer because we could have a
         // client in our process with a reference to it (eg: status bar),
         // and we can't release the handle under its feet.
         buffer.clear();
-        buffer = new GraphicBuffer(w, h, mFormat, effectiveUsage);
+        buffer = new GraphicBuffer(w, h, f, effectiveUsage);
         err = buffer->initCheck();
     }
 
@@ -377,15 +320,7 @@
 
     if (err == NO_ERROR && buffer->handle != 0) {
         Mutex::Autolock _l(mLock);
-        if (mWidth && mHeight) {
-            // and we have new buffer
-            mBuffers[index] = buffer;
-            // texture is now dirty...
-            mTextures[index].dirty = true;
-        } else {
-            // oops we got killed while we were allocating the buffer
-            buffer.clear();
-        }
+        mBufferManager.attachBuffer(index, buffer);
     }
     return buffer;
 }
@@ -411,15 +346,8 @@
     } else {
         // it's allowed to modify the usage flags here, but generally
         // the requested flags should be honored.
-        if (mNoEGLImageForSwBuffers) {
-            if (usage & GraphicBuffer::USAGE_HW_MASK) {
-                // request EGLImage for h/w buffers only
-                usage |= GraphicBuffer::USAGE_HW_TEXTURE;
-            }
-        } else {
-            // request EGLImage for all buffers
-            usage |= GraphicBuffer::USAGE_HW_TEXTURE;
-        }
+        // request EGLImage for all buffers
+        usage |= GraphicBuffer::USAGE_HW_TEXTURE;
     }
     return usage;
 }
@@ -429,42 +357,46 @@
     const Layer::State& front(drawingState());
     const Layer::State& temp(currentState());
 
-    if ((front.requested_w != temp.requested_w) || 
-        (front.requested_h != temp.requested_h)) {
+    const bool sizeChanged = (front.requested_w != temp.requested_w) ||
+            (front.requested_h != temp.requested_h);
+
+    if (sizeChanged) {
         // the size changed, we need to ask our client to request a new buffer
         LOGD_IF(DEBUG_RESIZE,
-                    "resize (layer=%p), requested (%dx%d), "
-                    "drawing (%d,%d), (%dx%d), (%dx%d)",
-                    this, 
-                    int(temp.requested_w), int(temp.requested_h),
-                    int(front.requested_w), int(front.requested_h),
-                    int(mBuffers[0]->getWidth()), int(mBuffers[0]->getHeight()),
-                    int(mBuffers[1]->getWidth()), int(mBuffers[1]->getHeight()));
+                "resize (layer=%p), requested (%dx%d), drawing (%d,%d)",
+                this,
+                int(temp.requested_w), int(temp.requested_h),
+                int(front.requested_w), int(front.requested_h));
 
-        // we're being resized and there is a freeze display request,
-        // acquire a freeze lock, so that the screen stays put
-        // until we've redrawn at the new size; this is to avoid
-        // glitches upon orientation changes.
-        if (mFlinger->hasFreezeRequest()) {
-            // if the surface is hidden, don't try to acquire the
-            // freeze lock, since hidden surfaces may never redraw
-            if (!(front.flags & ISurfaceComposer::eLayerHidden)) {
-                mFreezeLock = mFlinger->getFreezeLock();
+        if (!isFixedSize()) {
+            // we're being resized and there is a freeze display request,
+            // acquire a freeze lock, so that the screen stays put
+            // until we've redrawn at the new size; this is to avoid
+            // glitches upon orientation changes.
+            if (mFlinger->hasFreezeRequest()) {
+                // if the surface is hidden, don't try to acquire the
+                // freeze lock, since hidden surfaces may never redraw
+                if (!(front.flags & ISurfaceComposer::eLayerHidden)) {
+                    mFreezeLock = mFlinger->getFreezeLock();
+                }
             }
+
+            // this will make sure LayerBase::doTransaction doesn't update
+            // the drawing state's size
+            Layer::State& editDraw(mDrawingState);
+            editDraw.requested_w = temp.requested_w;
+            editDraw.requested_h = temp.requested_h;
+
+            // record the new size, form this point on, when the client request
+            // a buffer, it'll get the new size.
+            setBufferSize(temp.requested_w, temp.requested_h);
+
+            // all buffers need reallocation
+            lcblk->reallocateAll();
+        } else {
+            // record the new size
+            setBufferSize(temp.requested_w, temp.requested_h);
         }
-
-        // this will make sure LayerBase::doTransaction doesn't update
-        // the drawing state's size
-        Layer::State& editDraw(mDrawingState);
-        editDraw.requested_w = temp.requested_w;
-        editDraw.requested_h = temp.requested_h;
-
-        // record the new size, form this point on, when the client request a
-        // buffer, it'll get the new size.
-        setDrawingSize(temp.requested_w, temp.requested_h);
-
-        // all buffers need reallocation
-        lcblk->reallocate();
     }
 
     if (temp.sequence != front.sequence) {
@@ -478,12 +410,17 @@
     return LayerBase::doTransaction(flags);
 }
 
-void Layer::setDrawingSize(uint32_t w, uint32_t h) {
+void Layer::setBufferSize(uint32_t w, uint32_t h) {
     Mutex::Autolock _l(mLock);
     mWidth = w;
     mHeight = h;
 }
 
+bool Layer::isFixedSize() const {
+    Mutex::Autolock _l(mLock);
+    return mFixedSize;
+}
+
 // ----------------------------------------------------------------------------
 // pageflip handling...
 // ----------------------------------------------------------------------------
@@ -491,22 +428,25 @@
 void Layer::lockPageFlip(bool& recomputeVisibleRegions)
 {
     ssize_t buf = lcblk->retireAndLock();
-    if (buf < NO_ERROR) {
-        //LOGW("nothing to retire (%s)", strerror(-buf));
-        // NOTE: here the buffer is locked because we will used 
+    if (buf == NOT_ENOUGH_DATA) {
+        // NOTE: This is not an error, it simply means there is nothing to
+        // retire. The buffer is locked because we will use it
         // for composition later in the loop
         return;
     }
 
-    // ouch, this really should never happen
-    if (uint32_t(buf)>=NUM_BUFFERS) {
+    if (buf < NO_ERROR) {
         LOGE("retireAndLock() buffer index (%d) out of range", buf);
         mPostedDirtyRegion.clear();
         return;
     }
 
     // we retired a buffer, which becomes the new front buffer
-    mFrontBufferIndex = buf;
+    if (mBufferManager.setActiveBufferIndex(buf) < NO_ERROR) {
+        LOGE("retireAndLock() buffer index (%d) out of range", buf);
+        mPostedDirtyRegion.clear();
+        return;
+    }
 
     // get the dirty region
     sp<GraphicBuffer> newFrontBuffer(getBuffer(buf));
@@ -559,9 +499,15 @@
         mFlinger->signalEvent();
     }
 
-    if (!mPostedDirtyRegion.isEmpty()) {
-        reloadTexture( mPostedDirtyRegion );
-    }
+    /* a buffer was posted, so we need to call reloadTexture(), which
+     * will update our internal data structures (eg: EGLImageKHR or
+     * texture names). we need to do this even if mPostedDirtyRegion is
+     * empty -- it's orthogonal to the fact that a new buffer was posted,
+     * for instance, a degenerate case could be that the user did an empty
+     * update but repainted the buffer with appropriate content (after a
+     * resize for instance).
+     */
+    reloadTexture( mPostedDirtyRegion );
 }
 
 void Layer::unlockPageFlip(
@@ -585,17 +531,177 @@
     }
     if (visibleRegionScreen.isEmpty()) {
         // an invisible layer should not hold a freeze-lock
-        // (because it may never be updated and thereore never release it)
+        // (because it may never be updated and therefore never release it)
         mFreezeLock.clear();
     }
 }
 
 void Layer::finishPageFlip()
 {
-    status_t err = lcblk->unlock( mFrontBufferIndex );
-    LOGE_IF(err!=NO_ERROR, 
-            "layer %p, buffer=%d wasn't locked!",
-            this, mFrontBufferIndex);
+    int buf = mBufferManager.getActiveBufferIndex();
+    status_t err = lcblk->unlock( buf );
+    LOGE_IF(err!=NO_ERROR, "layer %p, buffer=%d wasn't locked!", this, buf);
+}
+
+
+void Layer::dump(String8& result, char* buffer, size_t SIZE) const
+{
+    LayerBaseClient::dump(result, buffer, SIZE);
+
+    SharedBufferStack::Statistics stats = lcblk->getStats();
+    result.append( lcblk->dump("      ") );
+    sp<const GraphicBuffer> buf0(getBuffer(0));
+    sp<const GraphicBuffer> buf1(getBuffer(1));
+    uint32_t w0=0, h0=0, s0=0;
+    uint32_t w1=0, h1=0, s1=0;
+    if (buf0 != 0) {
+        w0 = buf0->getWidth();
+        h0 = buf0->getHeight();
+        s0 = buf0->getStride();
+    }
+    if (buf1 != 0) {
+        w1 = buf1->getWidth();
+        h1 = buf1->getHeight();
+        s1 = buf1->getStride();
+    }
+    snprintf(buffer, SIZE,
+            "      "
+            "format=%2d, [%3ux%3u:%3u] [%3ux%3u:%3u],"
+            " freezeLock=%p, dq-q-time=%u us\n",
+            pixelFormat(),
+            w0, h0, s0, w1, h1, s1,
+            getFreezeLock().get(), stats.totalTime);
+
+    result.append(buffer);
+}
+
+// ---------------------------------------------------------------------------
+
+Layer::BufferManager::BufferManager(TextureManager& tm)
+    : mNumBuffers(NUM_BUFFERS), mTextureManager(tm),
+      mActiveBuffer(0), mFailover(false)
+{
+}
+
+Layer::BufferManager::~BufferManager()
+{
+}
+
+status_t Layer::BufferManager::resize(size_t size)
+{
+    Mutex::Autolock _l(mLock);
+    mNumBuffers = size;
+    return NO_ERROR;
+}
+
+// only for debugging
+sp<GraphicBuffer> Layer::BufferManager::getBuffer(size_t index) const {
+    return mBufferData[index].buffer;
+}
+
+status_t Layer::BufferManager::setActiveBufferIndex(size_t index) {
+    // TODO: need to validate 'index'
+    mActiveBuffer = index;
+    return NO_ERROR;
+}
+
+size_t Layer::BufferManager::getActiveBufferIndex() const {
+    return mActiveBuffer;
+}
+
+Texture Layer::BufferManager::getActiveTexture() const {
+    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 buffers[activeBuffer].buffer;
+}
+
+sp<GraphicBuffer> Layer::BufferManager::detachBuffer(size_t index)
+{
+    BufferData* const buffers = mBufferData;
+    sp<GraphicBuffer> buffer;
+    Mutex::Autolock _l(mLock);
+    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);
+    buffers[index].buffer = buffer;
+    buffers[index].texture.dirty = true;
+    return NO_ERROR;
+}
+
+status_t Layer::BufferManager::destroy(EGLDisplay dpy)
+{
+    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;
+}
+
+status_t Layer::BufferManager::initEglImage(EGLDisplay dpy,
+        const sp<GraphicBuffer>& buffer)
+{
+    size_t index = mActiveBuffer;
+    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.
+    if (err == NO_ERROR) {
+        mFailover = false;
+        destroyTexture(&mFailoverTexture, dpy);
+    } else {
+        mFailover = true;
+        const size_t num = mNumBuffers;
+        for (size_t i=0 ; i<num ; i++) {
+            destroyTexture(&mBufferData[i].texture, dpy);
+        }
+    }
+    return err;
+}
+
+status_t Layer::BufferManager::loadTexture(
+        const Region& dirty, const GGLSurface& t)
+{
+    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;
 }
 
 // ---------------------------------------------------------------------------
@@ -610,20 +716,37 @@
 {
 }
 
-sp<GraphicBuffer> Layer::SurfaceLayer::requestBuffer(int index, int usage)
+sp<GraphicBuffer> Layer::SurfaceLayer::requestBuffer(int index,
+        uint32_t w, uint32_t h, uint32_t format, uint32_t usage)
 {
     sp<GraphicBuffer> buffer;
     sp<Layer> owner(getOwner());
     if (owner != 0) {
-        LOGE_IF(uint32_t(index)>=NUM_BUFFERS,
-                "getBuffer() index (%d) out of range", index);
-        if (uint32_t(index) < NUM_BUFFERS) {
-            buffer = owner->requestBuffer(index, usage);
-        }
+        /*
+         * 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, w, h, format, usage);
     }
     return buffer;
 }
 
+status_t Layer::SurfaceLayer::setBufferCount(int bufferCount)
+{
+    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 743afb4..59603a5 100644
--- a/libs/surfaceflinger/Layer.h
+++ b/libs/surfaceflinger/Layer.h
@@ -31,6 +31,7 @@
 
 #include "LayerBase.h"
 #include "Transform.h"
+#include "TextureManager.h"
 
 namespace android {
 
@@ -41,16 +42,13 @@
 
 // ---------------------------------------------------------------------------
 
-const size_t NUM_BUFFERS = 2;
-
 class Layer : public LayerBaseClient
 {
-public:    
-    static const uint32_t typeInfo;
-    static const char* const typeID;
-    virtual char const* getTypeID() const { return typeID; }
-    virtual uint32_t getTypeInfo() const { return typeInfo; }
-    
+public:
+    // lcblk is (almost) only accessed from the main SF thread, in the places
+    // where it's not, a reference to Client must be held
+    SharedBufferServer*     lcblk;
+
                  Layer(SurfaceFlinger* flinger, DisplayID display,
                          const sp<Client>& client, int32_t i);
 
@@ -59,7 +57,8 @@
     status_t setBuffers(uint32_t w, uint32_t h, 
             PixelFormat format, uint32_t flags=0);
 
-    void setDrawingSize(uint32_t w, uint32_t h);
+    void setBufferSize(uint32_t w, uint32_t h);
+    bool isFixedSize() const;
 
     virtual void onDraw(const Region& clip) const;
     virtual uint32_t doTransaction(uint32_t transactionFlags);
@@ -68,30 +67,32 @@
     virtual void finishPageFlip();
     virtual bool needsBlending() const      { return mNeedsBlending; }
     virtual bool needsDithering() const     { return mNeedsDithering; }
+    virtual bool needsFiltering() const;
     virtual bool isSecure() const           { return mSecure; }
     virtual sp<Surface> createSurface() const;
     virtual status_t ditch();
+    virtual void onRemoved();
     
     // only for debugging
-    inline sp<GraphicBuffer> getBuffer(int i) { return mBuffers[i]; }
+    inline sp<GraphicBuffer> getBuffer(int i) const { return mBufferManager.getBuffer(i); }
     // only for debugging
     inline const sp<FreezeLock>&  getFreezeLock() const { return mFreezeLock; }
     // only for debugging
     inline PixelFormat pixelFormat() const { return mFormat; }
-    // only for debugging
-    inline int getFrontBufferIndex() const { return mFrontBufferIndex; }
+
+    virtual const char* getTypeId() const { return "Layer"; }
+
+protected:
+    virtual void dump(String8& result, char* scratch, size_t size) const;
 
 private:
-    inline sp<GraphicBuffer> getFrontBufferLocked() {
-        return mBuffers[mFrontBufferIndex];
-    }
- 
     void reloadTexture(const Region& dirty);
 
     uint32_t getEffectiveUsage(uint32_t usage) const;
 
-    sp<GraphicBuffer> requestBuffer(int index, int usage);
-    void destroy();
+    sp<GraphicBuffer> requestBuffer(int bufferIdx,
+            uint32_t w, uint32_t h, uint32_t format, uint32_t usage);
+    status_t setBufferCount(int bufferCount);
 
     class SurfaceLayer : public LayerBaseClient::Surface {
     public:
@@ -99,7 +100,9 @@
                 SurfaceID id, const sp<Layer>& owner);
         ~SurfaceLayer();
     private:
-        virtual sp<GraphicBuffer> requestBuffer(int index, int usage);
+        virtual sp<GraphicBuffer> requestBuffer(int bufferIdx,
+                uint32_t w, uint32_t h, uint32_t format, uint32_t usage);
+        virtual status_t setBufferCount(int bufferCount);
         sp<Layer> getOwner() const {
             return static_cast<Layer*>(Surface::getOwner().get());
         }
@@ -109,22 +112,83 @@
     sp<Surface>             mSurface;
 
             bool            mSecure;
-            bool            mNoEGLImageForSwBuffers;
             int32_t         mFrontBufferIndex;
             bool            mNeedsBlending;
             bool            mNeedsDithering;
             Region          mPostedDirtyRegion;
             sp<FreezeLock>  mFreezeLock;
             PixelFormat     mFormat;
-            
-            // protected by mLock
-            sp<GraphicBuffer> mBuffers[NUM_BUFFERS];
-            Texture         mTextures[NUM_BUFFERS];
-            sp<GraphicBuffer> mHybridBuffer;
-            uint32_t        mWidth;
-            uint32_t        mHeight;
-            
-   mutable Mutex mLock;
+
+            class BufferManager {
+                static const size_t NUM_BUFFERS = 2;
+                struct BufferData {
+                    sp<GraphicBuffer>   buffer;
+                    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[SharedBufferStack::NUM_BUFFER_MAX];
+                size_t              mNumBuffers;
+                Texture             mFailoverTexture;
+                TextureManager&     mTextureManager;
+                ssize_t             mActiveBuffer;
+                bool                mFailover;
+                static status_t destroyTexture(Image* tex, EGLDisplay dpy);
+
+            public:
+                static size_t getDefaultBufferCount() { return NUM_BUFFERS; }
+                BufferManager(TextureManager& tm);
+                ~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
+
+                // set/get active buffer index
+                status_t setActiveBufferIndex(size_t index);
+                size_t getActiveBufferIndex() const;
+
+                // return the active buffer
+                sp<GraphicBuffer> getActiveBuffer() const;
+
+                // return the active texture (or fail-over)
+                Texture getActiveTexture() const;
+
+                // frees resources associated with all buffers
+                status_t destroy(EGLDisplay dpy);
+
+                // load bitmap data into the active buffer
+                status_t loadTexture(const Region& dirty, const GGLSurface& t);
+
+                // make active buffer an EGLImage if needed
+                status_t initEglImage(EGLDisplay dpy,
+                        const sp<GraphicBuffer>& buffer);
+
+                // ----------------------------------------------
+                // only for debugging
+                sp<GraphicBuffer> getBuffer(size_t index) const;
+            };
+
+            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;
+            uint32_t    mReqWidth;
+            uint32_t    mReqHeight;
+            uint32_t    mReqFormat;
+            bool        mFixedSize;
 };
 
 // ---------------------------------------------------------------------------
diff --git a/libs/surfaceflinger/LayerBase.cpp b/libs/surfaceflinger/LayerBase.cpp
index a8b735e..76733a9 100644
--- a/libs/surfaceflinger/LayerBase.cpp
+++ b/libs/surfaceflinger/LayerBase.cpp
@@ -32,29 +32,21 @@
 #include "LayerBase.h"
 #include "SurfaceFlinger.h"
 #include "DisplayHardware/DisplayHardware.h"
+#include "TextureManager.h"
 
 
 namespace android {
 
 // ---------------------------------------------------------------------------
 
-const uint32_t LayerBase::typeInfo = 1;
-const char* const LayerBase::typeID = "LayerBase";
-
-const uint32_t LayerBaseClient::typeInfo = LayerBase::typeInfo | 2;
-const char* const LayerBaseClient::typeID = "LayerBaseClient";
-
-// ---------------------------------------------------------------------------
-
 LayerBase::LayerBase(SurfaceFlinger* flinger, DisplayID display)
     : dpy(display), contentDirty(false),
       mFlinger(flinger),
-      mTransformed(false),
-      mUseLinearFiltering(false),
+      mNeedsFiltering(false),
       mOrientation(0),
       mLeft(0), mTop(0),
       mTransactionFlags(0),
-      mPremultipliedAlpha(true), mDebug(false),
+      mPremultipliedAlpha(true), mName("unnamed"), mDebug(false),
       mInvalidate(0)
 {
     const DisplayHardware& hw(flinger->graphicPlane(0).displayHardware());
@@ -221,13 +213,12 @@
         flags |= eVisibleRegion;
         this->contentDirty = true;
 
-        const bool linearFiltering = mUseLinearFiltering;
-        mUseLinearFiltering = false;
+        mNeedsFiltering = false;
         if (!(mFlags & DisplayHardware::SLOW_CONFIG)) {
             // we may use linear filtering, if the matrix scales us
             const uint8_t type = temp.transform.getType();
             if (!temp.transform.preserveRects() || (type >= Transform::SCALE)) {
-                mUseLinearFiltering = true;
+                mNeedsFiltering = true;
             }
         }
     }
@@ -267,7 +258,6 @@
     // cache a few things...
     mOrientation = tr.getOrientation();
     mTransformedBounds = tr.makeBounds(w, h);
-    mTransformed = transformed;
     mLeft = tr.tx();
     mTop  = tr.ty();
 }
@@ -348,25 +338,13 @@
     */
 }
 
-GLuint LayerBase::createTexture() const
-{
-    GLuint textureName = -1;
-    glGenTextures(1, &textureName);
-    glBindTexture(GL_TEXTURE_2D, textureName);
-    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
-    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
-    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
-    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
-    return textureName;
-}
-
-void LayerBase::clearWithOpenGL(const Region& clip, GLclampx red,
-                                GLclampx green, GLclampx blue,
-                                GLclampx alpha) const
+void LayerBase::clearWithOpenGL(const Region& clip, GLclampf red,
+                                GLclampf green, GLclampf blue,
+                                GLclampf alpha) const
 {
     const DisplayHardware& hw(graphicPlane(0).displayHardware());
     const uint32_t fbHeight = hw.getHeight();
-    glColor4x(red,green,blue,alpha);
+    glColor4f(red,green,blue,alpha);
     glDisable(GL_TEXTURE_2D);
     glDisable(GL_BLEND);
     glDisable(GL_DITHER);
@@ -374,7 +352,7 @@
     Region::const_iterator it = clip.begin();
     Region::const_iterator const end = clip.end();
     glEnable(GL_SCISSOR_TEST);
-    glVertexPointer(2, GL_FIXED, 0, mVertices);
+    glVertexPointer(2, GL_FLOAT, 0, mVertices);
     while (it != end) {
         const Rect& r = *it++;
         const GLint sy = fbHeight - (r.top + r.height());
@@ -418,14 +396,14 @@
             env = GL_REPLACE;
             src = GL_SRC_ALPHA;
         }
-        const GGLfixed alpha = (s.alpha << 16)/255;
-        glColor4x(alpha, alpha, alpha, alpha);
+        const GLfloat alpha = s.alpha * (1.0f/255.0f);
+        glColor4f(alpha, alpha, alpha, alpha);
         glEnable(GL_BLEND);
         glBlendFunc(src, GL_ONE_MINUS_SRC_ALPHA);
         glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, env);
     } else {
         glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
-        glColor4x(0x10000, 0x10000, 0x10000, 0x10000);
+        glColor4f(1, 1, 1, 1);
         if (needsBlending()) {
             GLenum src = mPremultipliedAlpha ? GL_ONE : GL_SRC_ALPHA;
             glEnable(GL_BLEND);
@@ -437,13 +415,11 @@
 
     Region::const_iterator it = clip.begin();
     Region::const_iterator const end = clip.end();
-
-    //StopWatch watch("GL transformed");
-    const GLfixed texCoords[4][2] = {
-            { 0,        0 },
-            { 0,        0x10000 },
-            { 0x10000,  0x10000 },
-            { 0x10000,  0 }
+    const GLfloat texCoords[4][2] = {
+            { 0,  0 },
+            { 0,  1 },
+            { 1,  1 },
+            { 1,  0 }
     };
 
     glMatrixMode(GL_TEXTURE);
@@ -470,8 +446,8 @@
     }
 
     glEnableClientState(GL_TEXTURE_COORD_ARRAY);
-    glVertexPointer(2, GL_FIXED, 0, mVertices);
-    glTexCoordPointer(2, GL_FIXED, 0, texCoords);
+    glVertexPointer(2, GL_FLOAT, 0, mVertices);
+    glTexCoordPointer(2, GL_FLOAT, 0, texCoords);
 
     while (it != end) {
         const Rect& r = *it++;
@@ -487,7 +463,7 @@
     glBindTexture(GL_TEXTURE_2D, textureName);
     // TODO: reload the texture if needed
     // this is currently done in loadTexture() below
-    if (mUseLinearFiltering) {
+    if (needsFiltering()) {
         glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
         glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
     } else {
@@ -502,200 +478,32 @@
     }
 }
 
-bool LayerBase::isSupportedYuvFormat(int format) const
+void LayerBase::dump(String8& result, char* buffer, size_t SIZE) const
 {
-    switch (format) {
-        case HAL_PIXEL_FORMAT_YCbCr_422_SP:
-        case HAL_PIXEL_FORMAT_YCbCr_420_SP:
-        case HAL_PIXEL_FORMAT_YCbCr_422_P:
-        case HAL_PIXEL_FORMAT_YCbCr_420_P:
-        case HAL_PIXEL_FORMAT_YCbCr_422_I:
-        case HAL_PIXEL_FORMAT_YCbCr_420_I:
-        case HAL_PIXEL_FORMAT_YCrCb_420_SP:
-            return true;
-    }
-    return false;
+    const Layer::State& s(drawingState());
+    snprintf(buffer, SIZE,
+            "+ %s %p\n"
+            "      "
+            "z=%9d, pos=(%4d,%4d), size=(%4d,%4d), "
+            "needsBlending=%1d, needsDithering=%1d, invalidate=%1d, "
+            "alpha=0x%02x, flags=0x%08x, tr=[%.2f, %.2f][%.2f, %.2f]\n",
+            getTypeId(), this, s.z, tx(), ty(), s.w, s.h,
+            needsBlending(), needsDithering(), contentDirty,
+            s.alpha, s.flags,
+            s.transform[0][0], s.transform[0][1],
+            s.transform[1][0], s.transform[1][1]);
+    result.append(buffer);
 }
 
-void LayerBase::loadTexture(Texture* texture, 
-        const Region& dirty, const GGLSurface& t) const
-{
-    if (texture->name == -1U) {
-        // uh?
-        return;
-    }
-
-    glBindTexture(GL_TEXTURE_2D, texture->name);
-
-    /*
-     * In OpenGL ES we can't specify a stride with glTexImage2D (however,
-     * GL_UNPACK_ALIGNMENT is a limited form of stride).
-     * So if the stride here isn't representable with GL_UNPACK_ALIGNMENT, we
-     * need to do something reasonable (here creating a bigger texture).
-     * 
-     * extra pixels = (((stride - width) * pixelsize) / GL_UNPACK_ALIGNMENT);
-     * 
-     * This situation doesn't happen often, but some h/w have a limitation
-     * for their framebuffer (eg: must be multiple of 8 pixels), and
-     * we need to take that into account when using these buffers as
-     * textures.
-     *
-     * This should never be a problem with POT textures
-     */
-    
-    int unpack = __builtin_ctz(t.stride * bytesPerPixel(t.format));
-    unpack = 1 << ((unpack > 3) ? 3 : unpack);
-    glPixelStorei(GL_UNPACK_ALIGNMENT, unpack);
-    
-    /*
-     * round to POT if needed 
-     */
-    if (!(mFlags & DisplayHardware::NPOT_EXTENSION)) {
-        texture->NPOTAdjust = true;
-    }
-    
-    if (texture->NPOTAdjust) {
-        // find the smallest power-of-two that will accommodate our surface
-        texture->potWidth  = 1 << (31 - clz(t.width));
-        texture->potHeight = 1 << (31 - clz(t.height));
-        if (texture->potWidth  < t.width)  texture->potWidth  <<= 1;
-        if (texture->potHeight < t.height) texture->potHeight <<= 1;
-        texture->wScale = float(t.width)  / texture->potWidth;
-        texture->hScale = float(t.height) / texture->potHeight;
-    } else {
-        texture->potWidth  = t.width;
-        texture->potHeight = t.height;
-    }
-
-    Rect bounds(dirty.bounds());
-    GLvoid* data = 0;
-    if (texture->width != t.width || texture->height != t.height) {
-        texture->width  = t.width;
-        texture->height = t.height;
-
-        // texture size changed, we need to create a new one
-        bounds.set(Rect(t.width, t.height));
-        if (t.width  == texture->potWidth &&
-            t.height == texture->potHeight) {
-            // we can do it one pass
-            data = t.data;
-        }
-
-        if (t.format == HAL_PIXEL_FORMAT_RGB_565) {
-            glTexImage2D(GL_TEXTURE_2D, 0,
-                    GL_RGB, texture->potWidth, texture->potHeight, 0,
-                    GL_RGB, GL_UNSIGNED_SHORT_5_6_5, data);
-        } else if (t.format == HAL_PIXEL_FORMAT_RGBA_4444) {
-            glTexImage2D(GL_TEXTURE_2D, 0,
-                    GL_RGBA, texture->potWidth, texture->potHeight, 0,
-                    GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, data);
-        } else if (t.format == HAL_PIXEL_FORMAT_RGBA_8888 ||
-                   t.format == HAL_PIXEL_FORMAT_RGBX_8888) {
-            glTexImage2D(GL_TEXTURE_2D, 0,
-                    GL_RGBA, texture->potWidth, texture->potHeight, 0,
-                    GL_RGBA, GL_UNSIGNED_BYTE, data);
-        } else if (isSupportedYuvFormat(t.format)) {
-            // just show the Y plane of YUV buffers
-            glTexImage2D(GL_TEXTURE_2D, 0,
-                    GL_LUMINANCE, texture->potWidth, texture->potHeight, 0,
-                    GL_LUMINANCE, GL_UNSIGNED_BYTE, data);
-        } else {
-            // oops, we don't handle this format!
-            LOGE("layer %p, texture=%d, using format %d, which is not "
-                 "supported by the GL", this, texture->name, t.format);
-        }
-    }
-    if (!data) {
-        if (t.format == HAL_PIXEL_FORMAT_RGB_565) {
-            glTexSubImage2D(GL_TEXTURE_2D, 0,
-                    0, bounds.top, t.width, bounds.height(),
-                    GL_RGB, GL_UNSIGNED_SHORT_5_6_5,
-                    t.data + bounds.top*t.stride*2);
-        } else if (t.format == HAL_PIXEL_FORMAT_RGBA_4444) {
-            glTexSubImage2D(GL_TEXTURE_2D, 0,
-                    0, bounds.top, t.width, bounds.height(),
-                    GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4,
-                    t.data + bounds.top*t.stride*2);
-        } else if (t.format == HAL_PIXEL_FORMAT_RGBA_8888 ||
-                   t.format == HAL_PIXEL_FORMAT_RGBX_8888) {
-            glTexSubImage2D(GL_TEXTURE_2D, 0,
-                    0, bounds.top, t.width, bounds.height(),
-                    GL_RGBA, GL_UNSIGNED_BYTE,
-                    t.data + bounds.top*t.stride*4);
-        } else if (isSupportedYuvFormat(t.format)) {
-            // just show the Y plane of YUV buffers
-            glTexSubImage2D(GL_TEXTURE_2D, 0,
-                    0, bounds.top, t.width, bounds.height(),
-                    GL_LUMINANCE, GL_UNSIGNED_BYTE,
-                    t.data + bounds.top*t.stride);
-        }
-    }
-}
-
-status_t LayerBase::initializeEglImage(
-        const sp<GraphicBuffer>& buffer, Texture* texture)
-{
-    status_t err = NO_ERROR;
-
-    // we need to recreate the texture
-    EGLDisplay dpy(mFlinger->graphicPlane(0).getEGLDisplay());
-
-    // free the previous image
-    if (texture->image != EGL_NO_IMAGE_KHR) {
-        eglDestroyImageKHR(dpy, texture->image);
-        texture->image = EGL_NO_IMAGE_KHR;
-    }
-
-    // construct an EGL_NATIVE_BUFFER_ANDROID
-    android_native_buffer_t* clientBuf = buffer->getNativeBuffer();
-
-    // create the new EGLImageKHR
-    const EGLint attrs[] = {
-            EGL_IMAGE_PRESERVED_KHR,    EGL_TRUE,
-            EGL_NONE,                   EGL_NONE
-    };
-    texture->image = eglCreateImageKHR(
-            dpy, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID,
-            (EGLClientBuffer)clientBuf, attrs);
-
-    if (texture->image != EGL_NO_IMAGE_KHR) {
-        glBindTexture(GL_TEXTURE_2D, texture->name);
-        glEGLImageTargetTexture2DOES(GL_TEXTURE_2D,
-                (GLeglImageOES)texture->image);
-        GLint error = glGetError();
-        if (UNLIKELY(error != GL_NO_ERROR)) {
-            LOGE("layer=%p, glEGLImageTargetTexture2DOES(%p) "
-                 "failed err=0x%04x",
-                 this, texture->image, error);
-            err = INVALID_OPERATION;
-        } else {
-            // Everything went okay!
-            texture->NPOTAdjust = false;
-            texture->dirty  = false;
-            texture->width  = clientBuf->width;
-            texture->height = clientBuf->height;
-        }
-    } else {
-        LOGE("layer=%p, eglCreateImageKHR() failed. err=0x%4x",
-                this, eglGetError());
-        err = INVALID_OPERATION;
-    }
-    return err;
-}
-
-
 // ---------------------------------------------------------------------------
 
-int32_t LayerBaseClient::sIdentity = 0;
+int32_t LayerBaseClient::sIdentity = 1;
 
 LayerBaseClient::LayerBaseClient(SurfaceFlinger* flinger, DisplayID display,
         const sp<Client>& client, int32_t i)
-    : LayerBase(flinger, display), lcblk(NULL), client(client), mIndex(i),
+    : LayerBase(flinger, display), client(client), mIndex(i),
       mIdentity(uint32_t(android_atomic_inc(&sIdentity)))
 {
-    lcblk = new SharedBufferServer(
-            client->ctrlblk, i, NUM_BUFFERS,
-            mIdentity);
 }
 
 void LayerBaseClient::onFirstRef()
@@ -712,16 +520,15 @@
     if (client != 0) {
         client->free(mIndex);
     }
-    delete lcblk;
 }
 
-int32_t LayerBaseClient::serverIndex() const 
+ssize_t LayerBaseClient::serverIndex() const
 {
     sp<Client> client(this->client.promote());
     if (client != 0) {
         return (client->cid<<16)|mIndex;
     }
-    return 0xFFFF0000 | mIndex;
+    return ssize_t(0xFFFF0000 | mIndex);
 }
 
 sp<LayerBaseClient::Surface> LayerBaseClient::getSurface()
@@ -742,12 +549,19 @@
             const_cast<LayerBaseClient *>(this));
 }
 
-// called with SurfaceFlinger::mStateLock as soon as the layer is entered
-// in the purgatory list
-void LayerBaseClient::onRemoved()
+void LayerBaseClient::dump(String8& result, char* buffer, size_t SIZE) const
 {
-    // wake up the condition
-    lcblk->setStatus(NO_INIT);
+    LayerBase::dump(result, buffer, SIZE);
+
+    sp<Client> client(this->client.promote());
+    snprintf(buffer, SIZE,
+            "      name=%s\n"
+            "      id=0x%08x, client=0x%08x, identity=%u\n",
+            getName().string(),
+            clientIndex(), client.get() ? client->cid : 0,
+            getIdentity());
+
+    result.append(buffer);
 }
 
 // ---------------------------------------------------------------------------
@@ -799,11 +613,17 @@
     return BnSurface::onTransact(code, data, reply, flags);
 }
 
-sp<GraphicBuffer> LayerBaseClient::Surface::requestBuffer(int index, int usage) 
+sp<GraphicBuffer> LayerBaseClient::Surface::requestBuffer(int bufferIdx,
+        uint32_t w, uint32_t h, uint32_t format, uint32_t usage)
 {
     return NULL; 
 }
 
+status_t LayerBaseClient::Surface::setBufferCount(int bufferCount)
+{
+    return INVALID_OPERATION;
+}
+
 status_t LayerBaseClient::Surface::registerBuffers(
         const ISurface::BufferHeap& buffers) 
 { 
diff --git a/libs/surfaceflinger/LayerBase.h b/libs/surfaceflinger/LayerBase.h
index 62ec839..a78424e 100644
--- a/libs/surfaceflinger/LayerBase.h
+++ b/libs/surfaceflinger/LayerBase.h
@@ -46,40 +46,15 @@
 class GraphicBuffer;
 class GraphicPlane;
 class SurfaceFlinger;
+class Texture;
 
 // ---------------------------------------------------------------------------
 
 class LayerBase : public RefBase
 {
-    // poor man's dynamic_cast below
-    template<typename T>
-    struct getTypeInfoOfAnyType {
-        static uint32_t get() { return T::typeInfo; }
-    };
-
-    template<typename T>
-    struct getTypeInfoOfAnyType<T*> {
-        static uint32_t get() { return getTypeInfoOfAnyType<T>::get(); }
-    };
-
 public:
-    static const uint32_t typeInfo;
-    static const char* const typeID;
-    virtual char const* getTypeID() const { return typeID; }
-    virtual uint32_t getTypeInfo() const { return typeInfo; }
-    
-    template<typename T>
-    static T dynamicCast(LayerBase* base) {
-        uint32_t mostDerivedInfo = base->getTypeInfo();
-        uint32_t castToInfo = getTypeInfoOfAnyType<T>::get();
-        if ((mostDerivedInfo & castToInfo) == castToInfo)
-            return static_cast<T>(base);
-        return 0;
-    }
+            LayerBase(SurfaceFlinger* flinger, DisplayID display);
 
-    
-    LayerBase(SurfaceFlinger* flinger, DisplayID display);
-    
     DisplayID           dpy;
     mutable bool        contentDirty;
             Region      visibleRegionScreen;
@@ -125,6 +100,9 @@
 
             void invalidate();
 
+    virtual const char* getTypeId() const { return "LayerBase"; }
+    virtual ssize_t serverIndex() const { return -1; }
+
     /**
      * draw - performs some global clipping optimizations
      * and calls onDraw().
@@ -199,9 +177,9 @@
     virtual bool needsDithering() const { return false; }
 
     /**
-     * transformed -- true is this surface needs a to be transformed
+     * needsLinearFiltering - true if this surface needs filtering
      */
-    virtual bool transformed() const    { return mTransformed; }
+    virtual bool needsFiltering() const { return mNeedsFiltering; }
 
     /**
      * isSecure - true if this surface is secure, that is if it prevents
@@ -217,7 +195,10 @@
      *  current list */
     virtual void onRemoved() { };
     
-    
+    /** always call base class first */
+    virtual void dump(String8& result, char* scratch, size_t size) const;
+
+
     enum { // flags for doTransaction()
         eVisibleRegion      = 0x00000002,
     };
@@ -241,44 +222,18 @@
     const GraphicPlane& graphicPlane(int dpy) const;
           GraphicPlane& graphicPlane(int dpy);
 
-          GLuint createTexture() const;
-    
-          struct Texture {
-              Texture() : name(-1U), width(0), height(0),
-                  image(EGL_NO_IMAGE_KHR), transform(0), 
-                  NPOTAdjust(false), dirty(true) { }
-              GLuint        name;
-              GLuint        width;
-              GLuint        height;
-              GLuint        potWidth;
-              GLuint        potHeight;
-              GLfloat       wScale;
-              GLfloat       hScale;
-              EGLImageKHR   image;
-              uint32_t      transform;
-              bool          NPOTAdjust;
-              bool          dirty;
-          };
-
-          void clearWithOpenGL(const Region& clip, GLclampx r, GLclampx g,
-                               GLclampx b, GLclampx alpha) const;
+          void clearWithOpenGL(const Region& clip, GLclampf r, GLclampf g,
+                               GLclampf b, GLclampf alpha) const;
           void clearWithOpenGL(const Region& clip) const;
           void drawWithOpenGL(const Region& clip, const Texture& texture) const;
-          void loadTexture(Texture* texture, 
-                  const Region& dirty, const GGLSurface& t) const;
-          status_t initializeEglImage(
-                  const sp<GraphicBuffer>& buffer, Texture* texture);
-
-          bool isSupportedYuvFormat(int format) const;
           
                 sp<SurfaceFlinger> mFlinger;
                 uint32_t        mFlags;
 
                 // cached during validateVisibility()
-                bool            mTransformed;
-                bool            mUseLinearFiltering;
+                bool            mNeedsFiltering;
                 int32_t         mOrientation;
-                GLfixed         mVertices[4][2];
+                GLfloat         mVertices[4][2];
                 Rect            mTransformedBounds;
                 int             mLeft;
                 int             mTop;
@@ -313,14 +268,6 @@
 {
 public:
     class Surface;
-   static const uint32_t typeInfo;
-    static const char* const typeID;
-    virtual char const* getTypeID() const { return typeID; }
-    virtual uint32_t getTypeInfo() const { return typeInfo; }
-
-    // lcblk is (almost) only accessed from the main SF thread, in the places
-    // where it's not, a reference to Client must be held
-    SharedBufferServer*     lcblk;
 
     LayerBaseClient(SurfaceFlinger* flinger, DisplayID display, 
             const sp<Client>& client, int32_t i);
@@ -331,14 +278,11 @@
 
     inline  uint32_t    getIdentity() const { return mIdentity; }
     inline  int32_t     clientIndex() const { return mIndex; }
-            int32_t     serverIndex() const;
-
    
             sp<Surface> getSurface();
     virtual sp<Surface> createSurface() const;
-    
-    virtual void onRemoved();
-
+    virtual ssize_t     serverIndex() const;
+    virtual const char* getTypeId() const { return "LayerBaseClient"; }
 
     class Surface : public BnSurface 
     {
@@ -356,7 +300,10 @@
         sp<LayerBaseClient> getOwner() const;
 
     private:
-        virtual sp<GraphicBuffer> requestBuffer(int index, int usage);
+        virtual sp<GraphicBuffer> requestBuffer(int bufferIdx,
+                uint32_t w, uint32_t h, uint32_t format, uint32_t usage);
+        virtual status_t setBufferCount(int bufferCount);
+
         virtual status_t registerBuffers(const ISurface::BufferHeap& buffers); 
         virtual void postBuffer(ssize_t offset);
         virtual void unregisterBuffers();
@@ -373,8 +320,11 @@
 
     friend class Surface;
 
+protected:
+    virtual void dump(String8& result, char* scratch, size_t size) const;
+
 private:
-                int32_t         mIndex;
+    int32_t         mIndex;
     mutable     Mutex           mLock;
     mutable     wp<Surface>     mClientSurface;
     // only read
diff --git a/libs/surfaceflinger/LayerBlur.cpp b/libs/surfaceflinger/LayerBlur.cpp
index 5fd7904..09c90e8 100644
--- a/libs/surfaceflinger/LayerBlur.cpp
+++ b/libs/surfaceflinger/LayerBlur.cpp
@@ -33,11 +33,6 @@
 namespace android {
 // ---------------------------------------------------------------------------
 
-const uint32_t LayerBlur::typeInfo = LayerBaseClient::typeInfo | 8;
-const char* const LayerBlur::typeID = "LayerBlur";
-
-// ---------------------------------------------------------------------------
-
 LayerBlur::LayerBlur(SurfaceFlinger* flinger, DisplayID display,
         const sp<Client>& client, int32_t i)
     : LayerBaseClient(flinger, display, client, i), mCacheDirty(true),
@@ -100,7 +95,9 @@
                     mCacheDirty = false;
                 } else {
                     if (!mAutoRefreshPending) {
-                        mFlinger->signalDelayedEvent(ms2ns(500));
+                        mFlinger->postMessageAsync(
+                                new MessageBase(MessageQueue::INVALIDATE),
+                                ms2ns(500));
                         mAutoRefreshPending = true;
                     }
                 }
@@ -206,8 +203,8 @@
 
         const State& s = drawingState();
         if (UNLIKELY(s.alpha < 0xFF)) {
-            const GGLfixed alpha = (s.alpha << 16)/255;
-            glColor4x(0, 0, 0, alpha);
+            const GLfloat alpha = s.alpha * (1.0f/255.0f);
+            glColor4f(0, 0, 0, alpha);
             glEnable(GL_BLEND);
             glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
             glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
@@ -225,38 +222,20 @@
         glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
         glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
 
-        if (UNLIKELY(transformed()
-                || !(mFlags & DisplayHardware::DRAW_TEXTURE_EXTENSION) )) {
-            // This is a very rare scenario.
-            glMatrixMode(GL_TEXTURE);
-            glLoadIdentity();
-            glScalef(mWidthScale, mHeightScale, 1);
-            glTranslatef(-x, mYOffset - y, 0);
-            glEnableClientState(GL_TEXTURE_COORD_ARRAY);
-            glVertexPointer(2, GL_FIXED, 0, mVertices);
-            glTexCoordPointer(2, GL_FIXED, 0, mVertices);
-            while (it != end) {
-                const Rect& r = *it++;
-                const GLint sy = fbHeight - (r.top + r.height());
-                glScissor(r.left, sy, r.width(), r.height());
-                glDrawArrays(GL_TRIANGLE_FAN, 0, 4); 
-            }       
-            glDisableClientState(GL_TEXTURE_COORD_ARRAY);
-        } else {
-            // NOTE: this is marginally faster with the software gl, because
-            // glReadPixels() reads the fb bottom-to-top, however we'll
-            // skip all the jaccobian computations.
-            Rect r;
-            GLint crop[4] = { 0, 0, w, h };
-            glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop);
-            y = fbHeight - (y + h);
-            while (it != end) {
-                const Rect& r = *it++;
-                const GLint sy = fbHeight - (r.top + r.height());
-                glScissor(r.left, sy, r.width(), r.height());
-                glDrawTexiOES(x, y, 0, w, h);
-            }
+        glMatrixMode(GL_TEXTURE);
+        glLoadIdentity();
+        glScalef(mWidthScale, mHeightScale, 1);
+        glTranslatef(-x, mYOffset - y, 0);
+        glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+        glVertexPointer(2, GL_FLOAT, 0, mVertices);
+        glTexCoordPointer(2, GL_FLOAT, 0, mVertices);
+        while (it != end) {
+            const Rect& r = *it++;
+            const GLint sy = fbHeight - (r.top + r.height());
+            glScissor(r.left, sy, r.width(), r.height());
+            glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
         }
+        glDisableClientState(GL_TEXTURE_COORD_ARRAY);
     }
 }
 
diff --git a/libs/surfaceflinger/LayerBlur.h b/libs/surfaceflinger/LayerBlur.h
index 5b63dec..380f587 100644
--- a/libs/surfaceflinger/LayerBlur.h
+++ b/libs/surfaceflinger/LayerBlur.h
@@ -31,11 +31,6 @@
 class LayerBlur : public LayerBaseClient
 {
 public:    
-    static const uint32_t typeInfo;
-    static const char* const typeID;
-    virtual char const* getTypeID() const { return typeID; }
-    virtual uint32_t getTypeInfo() const { return typeInfo; }
-    
                 LayerBlur(SurfaceFlinger* flinger, DisplayID display,
                         const sp<Client>& client, int32_t i);
         virtual ~LayerBlur();
@@ -43,6 +38,7 @@
     virtual void onDraw(const Region& clip) const;
     virtual bool needsBlending() const  { return true; }
     virtual bool isSecure() const       { return false; }
+    virtual const char* getTypeId() const { return "LayerBlur"; }
 
     virtual uint32_t doTransaction(uint32_t flags);
     virtual void setVisibleRegion(const Region& visibleRegion);
diff --git a/libs/surfaceflinger/LayerBuffer.cpp b/libs/surfaceflinger/LayerBuffer.cpp
index 5c21593..8a582da 100644
--- a/libs/surfaceflinger/LayerBuffer.cpp
+++ b/libs/surfaceflinger/LayerBuffer.cpp
@@ -39,8 +39,6 @@
 
 // ---------------------------------------------------------------------------
 
-const uint32_t LayerBuffer::typeInfo = LayerBaseClient::typeInfo | 0x20;
-const char* const LayerBuffer::typeID = "LayerBuffer";
 gralloc_module_t const* LayerBuffer::sGrallocModule = 0;
 
 // ---------------------------------------------------------------------------
@@ -120,7 +118,7 @@
         source->onTransaction(flags);
     uint32_t res = LayerBase::doTransaction(flags);
     // we always want filtering for these surfaces
-    mUseLinearFiltering = !(mFlags & DisplayHardware::SLOW_CONFIG);
+    mNeedsFiltering = !(mFlags & DisplayHardware::SLOW_CONFIG);
     return res;
 }
 
@@ -145,14 +143,6 @@
     }
 }
 
-bool LayerBuffer::transformed() const
-{
-    sp<Source> source(getSource());
-    if (LIKELY(source != 0))
-        return source->transformed();
-    return false;
-}
-
 void LayerBuffer::serverDestroy()
 {
     sp<Source> source(clearSource());
@@ -321,16 +311,13 @@
 }
 void LayerBuffer::Source::unregisterBuffers() {
 }
-bool LayerBuffer::Source::transformed() const {
-    return mLayer.mTransformed; 
-}
 
 // ---------------------------------------------------------------------------
 
 LayerBuffer::BufferSource::BufferSource(LayerBuffer& layer,
         const ISurface::BufferHeap& buffers)
     : Source(layer), mStatus(NO_ERROR), mBufferSize(0),
-      mUseEGLImageDirectly(true)
+      mTextureManager(layer.mFlags)
 {
     if (buffers.heap == NULL) {
         // this is allowed, but in this case, it is illegal to receive
@@ -444,11 +431,6 @@
     mBuffer = buffer;
 }
 
-bool LayerBuffer::BufferSource::transformed() const
-{
-    return mBufferHeap.transform ? true : Source::transformed(); 
-}
-
 void LayerBuffer::BufferSource::onDraw(const Region& clip) const 
 {
     sp<Buffer> ourBuffer(getBuffer());
@@ -462,35 +444,10 @@
     NativeBuffer src(ourBuffer->getBuffer());
     const Rect transformedBounds(mLayer.getTransformedBounds());
 
-    if (UNLIKELY(mTexture.name == -1LU)) {
-        mTexture.name = mLayer.createTexture();
-    }
-
 #if defined(EGL_ANDROID_image_native_buffer)
     if (mLayer.mFlags & DisplayHardware::DIRECT_TEXTURE) {
         err = INVALID_OPERATION;
         if (ourBuffer->supportsCopybit()) {
-
-            // there are constraints on buffers used by the GPU and these may not
-            // be honored here. We need to change the API so the buffers
-            // are allocated with gralloc. For now disable this code-path
-#if 0
-            // First, try to use the buffer as an EGLImage directly
-            if (mUseEGLImageDirectly) {
-                // NOTE: Assume the buffer is allocated with the proper USAGE flags
-
-                sp<GraphicBuffer> buffer = new  GraphicBuffer(
-                        src.img.w, src.img.h, src.img.format,
-                        GraphicBuffer::USAGE_HW_TEXTURE,
-                        src.img.w, src.img.handle, false);
-
-                err = mLayer.initializeEglImage(buffer, &mTexture);
-                if (err != NO_ERROR) {
-                    mUseEGLImageDirectly = false;
-                }
-            }
-#endif
-
             copybit_device_t* copybit = mLayer.mBlitEngine;
             if (copybit && err != NO_ERROR) {
                 // create our EGLImageKHR the first time
@@ -527,7 +484,7 @@
         t.format = src.img.format;
         t.data = (GGLubyte*)src.img.base;
         const Region dirty(Rect(t.width, t.height));
-        mLayer.loadTexture(&mTexture, dirty, t);
+        mTextureManager.loadTexture(&mTexture, dirty, t);
     }
 
     mTexture.transform = mBufferHeap.transform;
@@ -569,7 +526,7 @@
     // figure out if we need linear filtering
     if (buffers.w * h == buffers.h * w) {
         // same pixel area, don't use filtering
-        mLayer.mUseLinearFiltering = false;
+        mLayer.mNeedsFiltering = false;
     }
 
     // Allocate a temporary buffer and create the corresponding EGLImageKHR
@@ -593,7 +550,8 @@
         dst.crop.r = w;
         dst.crop.b = h;
 
-        err = mLayer.initializeEglImage(buffer, &mTexture);
+        EGLDisplay dpy(mLayer.mFlinger->graphicPlane(0).getEGLDisplay());
+        err = mTextureManager.initEglImage(&mTexture, dpy, buffer);
     }
 
     return err;
@@ -609,7 +567,6 @@
     glDeleteTextures(1, &mTexture.name);
     Texture defaultTexture;
     mTexture = defaultTexture;
-    mTexture.name = mLayer.createTexture();
 }
 
 // ---------------------------------------------------------------------------
@@ -665,9 +622,9 @@
 void LayerBuffer::OverlaySource::onDraw(const Region& clip) const
 {
     // this would be where the color-key would be set, should we need it.
-    GLclampx red = 0;
-    GLclampx green = 0;
-    GLclampx blue = 0;
+    GLclampf red = 0;
+    GLclampf green = 0;
+    GLclampf blue = 0;
     mLayer.clearWithOpenGL(clip, red, green, blue, 0);
 }
 
diff --git a/libs/surfaceflinger/LayerBuffer.h b/libs/surfaceflinger/LayerBuffer.h
index b176623..d38dde2 100644
--- a/libs/surfaceflinger/LayerBuffer.h
+++ b/libs/surfaceflinger/LayerBuffer.h
@@ -21,6 +21,7 @@
 #include <sys/types.h>
 
 #include "LayerBase.h"
+#include "TextureManager.h"
 
 struct copybit_device_t;
 
@@ -45,31 +46,25 @@
         virtual void onVisibilityResolved(const Transform& planeTransform);
         virtual void postBuffer(ssize_t offset);
         virtual void unregisterBuffers();
-        virtual bool transformed() const;
         virtual void destroy() { }
     protected:
         LayerBuffer& mLayer;
     };
 
 public:
-    static const uint32_t typeInfo;
-    static const char* const typeID;
-    virtual char const* getTypeID() const { return typeID; }
-    virtual uint32_t getTypeInfo() const { return typeInfo; }
-
             LayerBuffer(SurfaceFlinger* flinger, DisplayID display,
                     const sp<Client>& client, int32_t i);
         virtual ~LayerBuffer();
 
     virtual void onFirstRef();
     virtual bool needsBlending() const;
+    virtual const char* getTypeId() const { return "LayerBuffer"; }
 
     virtual sp<LayerBaseClient::Surface> createSurface() const;
     virtual status_t ditch();
     virtual void onDraw(const Region& clip) const;
     virtual uint32_t doTransaction(uint32_t flags);
     virtual void unlockPageFlip(const Transform& planeTransform, Region& outDirtyRegion);
-    virtual bool transformed() const;
 
     status_t registerBuffers(const ISurface::BufferHeap& buffers);
     void postBuffer(ssize_t offset);
@@ -133,7 +128,6 @@
         virtual void onDraw(const Region& clip) const;
         virtual void postBuffer(ssize_t offset);
         virtual void unregisterBuffers();
-        virtual bool transformed() const;
         virtual void destroy() { }
     private:
         status_t initTempBuffer() const;
@@ -143,9 +137,9 @@
         status_t                        mStatus;
         ISurface::BufferHeap            mBufferHeap;
         size_t                          mBufferSize;
-        mutable LayerBase::Texture      mTexture;
+        mutable Texture                 mTexture;
         mutable NativeBuffer            mTempBuffer;
-        mutable bool                    mUseEGLImageDirectly;
+        mutable TextureManager          mTextureManager;
     };
     
     class OverlaySource : public Source {
diff --git a/libs/surfaceflinger/LayerDim.cpp b/libs/surfaceflinger/LayerDim.cpp
index fd61e30..568fedb 100644
--- a/libs/surfaceflinger/LayerDim.cpp
+++ b/libs/surfaceflinger/LayerDim.cpp
@@ -30,9 +30,6 @@
 namespace android {
 // ---------------------------------------------------------------------------
 
-const uint32_t LayerDim::typeInfo = LayerBaseClient::typeInfo | 0x10;
-const char* const LayerDim::typeID = "LayerDim";
-
 bool LayerDim::sUseTexture;
 GLuint LayerDim::sTexId;
 EGLImageKHR LayerDim::sImage;
diff --git a/libs/surfaceflinger/LayerDim.h b/libs/surfaceflinger/LayerDim.h
index d4672a1..19a9990 100644
--- a/libs/surfaceflinger/LayerDim.h
+++ b/libs/surfaceflinger/LayerDim.h
@@ -37,11 +37,6 @@
     static int32_t sWidth;
     static int32_t sHeight;
 public:    
-    static const uint32_t typeInfo;
-    static const char* const typeID;
-    virtual char const* getTypeID() const { return typeID; }
-    virtual uint32_t getTypeInfo() const { return typeInfo; }
-    
                 LayerDim(SurfaceFlinger* flinger, DisplayID display,
                         const sp<Client>& client, int32_t i);
         virtual ~LayerDim();
@@ -49,6 +44,7 @@
     virtual void onDraw(const Region& clip) const;
     virtual bool needsBlending() const  { return true; }
     virtual bool isSecure() const       { return false; }
+    virtual const char* getTypeId() const { return "LayerDim"; }
 
     static void initDimmer(SurfaceFlinger* flinger, uint32_t w, uint32_t h);
 };
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 0722fda..5a6893f 100644
--- a/libs/surfaceflinger/SurfaceFlinger.cpp
+++ b/libs/surfaceflinger/SurfaceFlinger.cpp
@@ -206,8 +206,8 @@
     property_get("debug.sf.showbackground", value, "0");
     mDebugBackground = atoi(value);
 
-    LOGI_IF(mDebugRegion,           "showupdates enabled");
-    LOGI_IF(mDebugBackground,       "showbackground enabled");
+    LOGI_IF(mDebugRegion,       "showupdates enabled");
+    LOGI_IF(mDebugBackground,   "showbackground enabled");
 }
 
 SurfaceFlinger::~SurfaceFlinger()
@@ -357,7 +357,6 @@
     dcblk->ydpi         = hw.getDpiY();
     dcblk->fps          = hw.getRefreshRate();
     dcblk->density      = hw.getDensity();
-    asm volatile ("":::"memory");
 
     // Initialize OpenGL|ES
     glActiveTexture(GL_TEXTURE0);
@@ -427,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()) {
@@ -462,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;
 }
 
 // ----------------------------------------------------------------------------
@@ -1079,15 +1089,15 @@
 
 status_t SurfaceFlinger::addLayer_l(const sp<LayerBase>& layer)
 {
-    if (layer == 0)
-        return BAD_VALUE;
     ssize_t i = mCurrentState.layersSortedByZ.add(
                 layer, &LayerBase::compareCurrentStateZ);
-    sp<LayerBaseClient> lbc = LayerBase::dynamicCast< LayerBaseClient* >(layer.get());
-    if (lbc != 0) {
-        mLayerMap.add(lbc->serverIndex(), lbc);
-    }
-    return NO_ERROR;
+    return (i < 0) ? status_t(i) : status_t(NO_ERROR);
+}
+
+status_t SurfaceFlinger::addClientLayer_l(const sp<LayerBaseClient>& lbc)
+{
+    ssize_t serverIndex = lbc->serverIndex();
+    return mLayerMap.add(serverIndex, lbc);
 }
 
 status_t SurfaceFlinger::removeLayer_l(const sp<LayerBase>& layerBase)
@@ -1095,10 +1105,9 @@
     ssize_t index = mCurrentState.layersSortedByZ.remove(layerBase);
     if (index >= 0) {
         mLayersRemoved = true;
-        sp<LayerBaseClient> layer =
-            LayerBase::dynamicCast< LayerBaseClient* >(layerBase.get());
-        if (layer != 0) {
-            mLayerMap.removeItem(layer->serverIndex());
+        ssize_t serverIndex = layerBase->serverIndex();
+        if (serverIndex >= 0) {
+            mLayerMap.removeItem(serverIndex);
         }
         return NO_ERROR;
     }
@@ -1137,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;
 }
@@ -1247,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;
     }
@@ -1298,7 +1303,7 @@
         format = PIXEL_FORMAT_RGBA_8888;
         break;
     case PIXEL_FORMAT_OPAQUE:
-        format = PIXEL_FORMAT_RGB_565;
+        format = PIXEL_FORMAT_RGBX_8888;
         break;
     }
 
@@ -1307,6 +1312,7 @@
     if (LIKELY(err == NO_ERROR)) {
         layer->initStates(w, h, flags);
         addLayer_l(layer);
+        addClientLayer_l(layer);
     } else {
         LOGE("createNormalSurfaceLocked() failed (%s)", strerror(-err));
         layer.clear();
@@ -1321,6 +1327,7 @@
     sp<LayerBlur> layer = new LayerBlur(this, display, client, id);
     layer->initStates(w, h, flags);
     addLayer_l(layer);
+    addClientLayer_l(layer);
     return layer;
 }
 
@@ -1331,6 +1338,7 @@
     sp<LayerDim> layer = new LayerDim(this, display, client, id);
     layer->initStates(w, h, flags);
     addLayer_l(layer);
+    addClientLayer_l(layer);
     return layer;
 }
 
@@ -1341,6 +1349,7 @@
     sp<LayerBuffer> layer = new LayerBuffer(this, display, client, id);
     layer->initStates(w, h, flags);
     addLayer_l(layer);
+    addClientLayer_l(layer);
     return layer;
 }
 
@@ -1397,7 +1406,7 @@
         }
     };
 
-    mEventQueue.postMessage( new MessageDestroySurface(this, layer) );
+    postMessageAsync( new MessageDestroySurface(this, layer) );
     return NO_ERROR;
 }
 
@@ -1512,83 +1521,17 @@
             result.append(buffer);
         }
 
-        size_t s = mClientsMap.size();
-        char name[64];
-        for (size_t i=0 ; i<s ; i++) {
-            sp<Client> client = mClientsMap.valueAt(i);
-            sprintf(name, "  Client (id=0x%08x)", client->cid);
-            client->dump(name);
-        }
         const LayerVector& currentLayers = mCurrentState.layersSortedByZ;
         const size_t count = currentLayers.size();
         for (size_t i=0 ; i<count ; i++) {
-            /*** LayerBase ***/
-            const sp<LayerBase>& layer = currentLayers[i];
-            const Layer::State& s = layer->drawingState();
-            snprintf(buffer, SIZE,
-                    "+ %s %p\n"
-                    "      "
-                    "z=%9d, pos=(%4d,%4d), size=(%4d,%4d), "
-                    "needsBlending=%1d, needsDithering=%1d, invalidate=%1d, "
-                    "alpha=0x%02x, flags=0x%08x, tr=[%.2f, %.2f][%.2f, %.2f]\n",
-                    layer->getTypeID(), layer.get(),
-                    s.z, layer->tx(), layer->ty(), s.w, s.h,
-                    layer->needsBlending(), layer->needsDithering(),
-                    layer->contentDirty,
-                    s.alpha, s.flags,
-                    s.transform[0][0], s.transform[0][1],
-                    s.transform[1][0], s.transform[1][1]);
-            result.append(buffer);
-            buffer[0] = 0;
-            /*** LayerBaseClient ***/
-            sp<LayerBaseClient> lbc =
-                LayerBase::dynamicCast< LayerBaseClient* >(layer.get());
-            if (lbc != 0) {
-                sp<Client> client(lbc->client.promote());
-                snprintf(buffer, SIZE,
-                        "      name=%s\n", lbc->getName().string());
-                result.append(buffer);
-                snprintf(buffer, SIZE,
-                        "      id=0x%08x, client=0x%08x, identity=%u\n",
-                        lbc->clientIndex(), client.get() ? client->cid : 0,
-                        lbc->getIdentity());
-
-                result.append(buffer);
-                buffer[0] = 0;
-            }
-            /*** Layer ***/
-            sp<Layer> l = LayerBase::dynamicCast< Layer* >(layer.get());
-            if (l != 0) {
-                SharedBufferStack::Statistics stats = l->lcblk->getStats();
-                result.append( l->lcblk->dump("      ") );
-                sp<const GraphicBuffer> buf0(l->getBuffer(0));
-                sp<const GraphicBuffer> buf1(l->getBuffer(1));
-                uint32_t w0=0, h0=0, s0=0;
-                uint32_t w1=0, h1=0, s1=0;
-                if (buf0 != 0) {
-                    w0 = buf0->getWidth();
-                    h0 = buf0->getHeight();
-                    s0 = buf0->getStride();
-                }
-                if (buf1 != 0) {
-                    w1 = buf1->getWidth();
-                    h1 = buf1->getHeight();
-                    s1 = buf1->getStride();
-                }
-                snprintf(buffer, SIZE,
-                        "      "
-                        "format=%2d, [%3ux%3u:%3u] [%3ux%3u:%3u],"
-                        " freezeLock=%p, dq-q-time=%u us\n",
-                        l->pixelFormat(),
-                        w0, h0, s0, w1, h1, s1,
-                        l->getFreezeLock().get(), stats.totalTime);
-                result.append(buffer);
-                buffer[0] = 0;
-            }
+            const sp<LayerBase>& layer(currentLayers[i]);
+            layer->dump(result, buffer, SIZE);
+            const Layer::State& s(layer->drawingState());
             s.transparentRegion.dump(result, "transparentRegion");
             layer->transparentRegionScreen.dump(result, "transparentRegionScreen");
             layer->visibleRegionScreen.dump(result, "visibleRegionScreen");
         }
+
         mWormholeRegion.dump(result, "WormholeRegion");
         const DisplayHardware& hw(graphicPlane(0).displayHardware());
         snprintf(buffer, SIZE,
@@ -1601,16 +1544,19 @@
                 "  last transaction time     : %f us\n",
                 mLastSwapBufferTime/1000.0, mLastTransactionTime/1000.0);
         result.append(buffer);
+
         if (inSwapBuffersDuration || !locked) {
             snprintf(buffer, SIZE, "  eglSwapBuffers time: %f us\n",
                     inSwapBuffersDuration/1000.0);
             result.append(buffer);
         }
+
         if (inTransactionDuration || !locked) {
             snprintf(buffer, SIZE, "  transaction time: %f us\n",
                     inTransactionDuration/1000.0);
             result.append(buffer);
         }
+
         snprintf(buffer, SIZE, "  client count: %d\n", mClientsMap.size());
         result.append(buffer);
         const GraphicBufferAllocator& alloc(GraphicBufferAllocator::get());
@@ -1733,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;
@@ -1760,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 {
@@ -1773,10 +1720,6 @@
     return lbc;
 }
 
-void Client::dump(const char* what)
-{
-}
-
 // ---------------------------------------------------------------------------
 #if 0
 #pragma mark -
diff --git a/libs/surfaceflinger/SurfaceFlinger.h b/libs/surfaceflinger/SurfaceFlinger.h
index d75dc15..2558324 100644
--- a/libs/surfaceflinger/SurfaceFlinger.h
+++ b/libs/surfaceflinger/SurfaceFlinger.h
@@ -73,7 +73,6 @@
 
     inline  bool                    isValid(int32_t i) const;
     sp<LayerBaseClient>             getLayerUser(int32_t i) const;
-    void                            dump(const char* what);
     
     const Vector< wp<LayerBaseClient> >& getLayers() const { 
         return mLayers; 
@@ -256,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(
@@ -281,12 +278,13 @@
             void        destroyConnection(ClientID cid);
             sp<LayerBaseClient> getLayerUser_l(SurfaceID index) const;
             status_t    addLayer_l(const sp<LayerBase>& layer);
+            status_t    addClientLayer_l(const sp<LayerBaseClient>& lbc);
             status_t    removeLayer_l(const sp<LayerBase>& layer);
             status_t    purgatorizeLayer_l(const sp<LayerBase>& layer);
             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
new file mode 100644
index 0000000..ee2159b
--- /dev/null
+++ b/libs/surfaceflinger/TextureManager.cpp
@@ -0,0 +1,241 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Errors.h>
+#include <utils/Log.h>
+
+#include <ui/GraphicBuffer.h>
+
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+
+#include <hardware/hardware.h>
+
+#include "clz.h"
+#include "DisplayHardware/DisplayHardware.h"
+#include "TextureManager.h"
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+TextureManager::TextureManager(uint32_t flags)
+    : mFlags(flags)
+{
+}
+
+GLuint TextureManager::createTexture()
+{
+    GLuint textureName = -1;
+    glGenTextures(1, &textureName);
+    glBindTexture(GL_TEXTURE_2D, textureName);
+    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+    return textureName;
+}
+
+bool TextureManager::isSupportedYuvFormat(int format)
+{
+    switch (format) {
+        case HAL_PIXEL_FORMAT_YCbCr_422_SP:
+        case HAL_PIXEL_FORMAT_YCbCr_420_SP:
+        case HAL_PIXEL_FORMAT_YCbCr_422_P:
+        case HAL_PIXEL_FORMAT_YCbCr_420_P:
+        case HAL_PIXEL_FORMAT_YCbCr_422_I:
+        case HAL_PIXEL_FORMAT_YCbCr_420_I:
+        case HAL_PIXEL_FORMAT_YCrCb_420_SP:
+            return true;
+    }
+    return false;
+}
+
+status_t TextureManager::initEglImage(Image* texture,
+        EGLDisplay dpy, const sp<GraphicBuffer>& buffer)
+{
+    status_t err = NO_ERROR;
+    if (!texture->dirty) return err;
+
+    // free the previous image
+    if (texture->image != EGL_NO_IMAGE_KHR) {
+        eglDestroyImageKHR(dpy, texture->image);
+        texture->image = EGL_NO_IMAGE_KHR;
+    }
+
+    // construct an EGL_NATIVE_BUFFER_ANDROID
+    android_native_buffer_t* clientBuf = buffer->getNativeBuffer();
+
+    // create the new EGLImageKHR
+    const EGLint attrs[] = {
+            EGL_IMAGE_PRESERVED_KHR,    EGL_TRUE,
+            EGL_NONE,                   EGL_NONE
+    };
+    texture->image = eglCreateImageKHR(
+            dpy, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID,
+            (EGLClientBuffer)clientBuf, attrs);
+
+    if (texture->image != EGL_NO_IMAGE_KHR) {
+        if (texture->name == -1UL) {
+            texture->name = createTexture();
+            texture->width = 0;
+            texture->height = 0;
+        }
+        glBindTexture(GL_TEXTURE_2D, texture->name);
+        glEGLImageTargetTexture2DOES(GL_TEXTURE_2D,
+                (GLeglImageOES)texture->image);
+        GLint error = glGetError();
+        if (error != GL_NO_ERROR) {
+            LOGE("glEGLImageTargetTexture2DOES(%p) failed err=0x%04x",
+                    texture->image, error);
+            err = INVALID_OPERATION;
+        } else {
+            // Everything went okay!
+            texture->dirty  = false;
+            texture->width  = clientBuf->width;
+            texture->height = clientBuf->height;
+        }
+    } else {
+        LOGE("eglCreateImageKHR() failed. err=0x%4x", eglGetError());
+        err = INVALID_OPERATION;
+    }
+    return err;
+}
+
+status_t TextureManager::loadTexture(Texture* texture,
+        const Region& dirty, const GGLSurface& t)
+{
+    if (texture->name == -1UL) {
+        texture->name = createTexture();
+        texture->width = 0;
+        texture->height = 0;
+    }
+
+    glBindTexture(GL_TEXTURE_2D, texture->name);
+
+    /*
+     * In OpenGL ES we can't specify a stride with glTexImage2D (however,
+     * GL_UNPACK_ALIGNMENT is a limited form of stride).
+     * So if the stride here isn't representable with GL_UNPACK_ALIGNMENT, we
+     * need to do something reasonable (here creating a bigger texture).
+     *
+     * extra pixels = (((stride - width) * pixelsize) / GL_UNPACK_ALIGNMENT);
+     *
+     * This situation doesn't happen often, but some h/w have a limitation
+     * for their framebuffer (eg: must be multiple of 8 pixels), and
+     * we need to take that into account when using these buffers as
+     * textures.
+     *
+     * This should never be a problem with POT textures
+     */
+
+    int unpack = __builtin_ctz(t.stride * bytesPerPixel(t.format));
+    unpack = 1 << ((unpack > 3) ? 3 : unpack);
+    glPixelStorei(GL_UNPACK_ALIGNMENT, unpack);
+
+    /*
+     * round to POT if needed
+     */
+    if (!(mFlags & DisplayHardware::NPOT_EXTENSION)) {
+        texture->NPOTAdjust = true;
+    }
+
+    if (texture->NPOTAdjust) {
+        // find the smallest power-of-two that will accommodate our surface
+        texture->potWidth  = 1 << (31 - clz(t.width));
+        texture->potHeight = 1 << (31 - clz(t.height));
+        if (texture->potWidth  < t.width)  texture->potWidth  <<= 1;
+        if (texture->potHeight < t.height) texture->potHeight <<= 1;
+        texture->wScale = float(t.width)  / texture->potWidth;
+        texture->hScale = float(t.height) / texture->potHeight;
+    } else {
+        texture->potWidth  = t.width;
+        texture->potHeight = t.height;
+    }
+
+    Rect bounds(dirty.bounds());
+    GLvoid* data = 0;
+    if (texture->width != t.width || texture->height != t.height) {
+        texture->width  = t.width;
+        texture->height = t.height;
+
+        // texture size changed, we need to create a new one
+        bounds.set(Rect(t.width, t.height));
+        if (t.width  == texture->potWidth &&
+            t.height == texture->potHeight) {
+            // we can do it one pass
+            data = t.data;
+        }
+
+        if (t.format == HAL_PIXEL_FORMAT_RGB_565) {
+            glTexImage2D(GL_TEXTURE_2D, 0,
+                    GL_RGB, texture->potWidth, texture->potHeight, 0,
+                    GL_RGB, GL_UNSIGNED_SHORT_5_6_5, data);
+        } else if (t.format == HAL_PIXEL_FORMAT_RGBA_4444) {
+            glTexImage2D(GL_TEXTURE_2D, 0,
+                    GL_RGBA, texture->potWidth, texture->potHeight, 0,
+                    GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, data);
+        } else if (t.format == HAL_PIXEL_FORMAT_RGBA_8888 ||
+                   t.format == HAL_PIXEL_FORMAT_RGBX_8888) {
+            glTexImage2D(GL_TEXTURE_2D, 0,
+                    GL_RGBA, texture->potWidth, texture->potHeight, 0,
+                    GL_RGBA, GL_UNSIGNED_BYTE, data);
+        } else if (isSupportedYuvFormat(t.format)) {
+            // just show the Y plane of YUV buffers
+            glTexImage2D(GL_TEXTURE_2D, 0,
+                    GL_LUMINANCE, texture->potWidth, texture->potHeight, 0,
+                    GL_LUMINANCE, GL_UNSIGNED_BYTE, data);
+        } else {
+            // oops, we don't handle this format!
+            LOGE("texture=%d, using format %d, which is not "
+                 "supported by the GL", texture->name, t.format);
+        }
+    }
+    if (!data) {
+        if (t.format == HAL_PIXEL_FORMAT_RGB_565) {
+            glTexSubImage2D(GL_TEXTURE_2D, 0,
+                    0, bounds.top, t.width, bounds.height(),
+                    GL_RGB, GL_UNSIGNED_SHORT_5_6_5,
+                    t.data + bounds.top*t.stride*2);
+        } else if (t.format == HAL_PIXEL_FORMAT_RGBA_4444) {
+            glTexSubImage2D(GL_TEXTURE_2D, 0,
+                    0, bounds.top, t.width, bounds.height(),
+                    GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4,
+                    t.data + bounds.top*t.stride*2);
+        } else if (t.format == HAL_PIXEL_FORMAT_RGBA_8888 ||
+                   t.format == HAL_PIXEL_FORMAT_RGBX_8888) {
+            glTexSubImage2D(GL_TEXTURE_2D, 0,
+                    0, bounds.top, t.width, bounds.height(),
+                    GL_RGBA, GL_UNSIGNED_BYTE,
+                    t.data + bounds.top*t.stride*4);
+        } else if (isSupportedYuvFormat(t.format)) {
+            // just show the Y plane of YUV buffers
+            glTexSubImage2D(GL_TEXTURE_2D, 0,
+                    0, bounds.top, t.width, bounds.height(),
+                    GL_LUMINANCE, GL_UNSIGNED_BYTE,
+                    t.data + bounds.top*t.stride);
+        }
+    }
+    return NO_ERROR;
+}
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
diff --git a/libs/surfaceflinger/TextureManager.h b/libs/surfaceflinger/TextureManager.h
new file mode 100644
index 0000000..d0acfe9
--- /dev/null
+++ b/libs/surfaceflinger/TextureManager.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_TEXTURE_MANAGER_H
+#define ANDROID_TEXTURE_MANAGER_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#include <GLES/gl.h>
+
+#include <ui/Region.h>
+
+#include <pixelflinger/pixelflinger.h>
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+class GraphicBuffer;
+
+// ---------------------------------------------------------------------------
+
+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;
+    bool          NPOTAdjust;
+};
+
+// ---------------------------------------------------------------------------
+
+class TextureManager {
+    uint32_t mFlags;
+    GLuint createTexture();
+    static bool isSupportedYuvFormat(int format);
+public:
+
+    TextureManager(uint32_t flags);
+
+    // load bitmap data into the active buffer
+    status_t loadTexture(Texture* texture,
+            const Region& dirty, const GGLSurface& t);
+
+    // make active buffer an EGLImage if needed
+    status_t initEglImage(Image* texture,
+            EGLDisplay dpy, const sp<GraphicBuffer>& buffer);
+};
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_TEXTURE_MANAGER_H
diff --git a/libs/surfaceflinger/Transform.cpp b/libs/surfaceflinger/Transform.cpp
index 175f989..5e27cc9 100644
--- a/libs/surfaceflinger/Transform.cpp
+++ b/libs/surfaceflinger/Transform.cpp
@@ -229,14 +229,13 @@
     return r;
 }
 
-void Transform::transform(fixed1616* point, int x, int y) const
+void Transform::transform(float* point, int x, int y) const
 {
-    const float toFixed = 65536.0f;
     const mat33& M(mMatrix);
     vec2 v(x, y);
     v = transform(v);
-    point[0] = v[0] * toFixed;
-    point[1] = v[1] * toFixed;
+    point[0] = v[0];
+    point[1] = v[1];
 }
 
 Rect Transform::makeBounds(int w, int h) const
diff --git a/libs/surfaceflinger/Transform.h b/libs/surfaceflinger/Transform.h
index 2e5b893..20fa11a 100644
--- a/libs/surfaceflinger/Transform.h
+++ b/libs/surfaceflinger/Transform.h
@@ -37,8 +37,6 @@
            explicit Transform(uint32_t orientation);
                     ~Transform();
 
-            typedef int32_t fixed1616;
-
             // FIXME: must match OVERLAY_TRANSFORM_*, pull from hardware.h
             enum orientation_flags {
                 ROT_0   = 0x00000000,
@@ -76,7 +74,7 @@
 
             // transform data
             Rect    makeBounds(int w, int h) const;
-            void    transform(fixed1616* point, int x, int y) const;
+            void    transform(float* point, int x, int y) const;
             Region  transform(const Region& reg) const;
             Transform operator * (const Transform& rhs) const;
 
diff --git a/libs/surfaceflinger_client/ISurface.cpp b/libs/surfaceflinger_client/ISurface.cpp
index bb86199..7049d9e 100644
--- a/libs/surfaceflinger_client/ISurface.cpp
+++ b/libs/surfaceflinger_client/ISurface.cpp
@@ -71,11 +71,15 @@
     {
     }
 
-    virtual sp<GraphicBuffer> requestBuffer(int bufferIdx, int usage)
+    virtual sp<GraphicBuffer> requestBuffer(int bufferIdx,
+            uint32_t w, uint32_t h, uint32_t format, uint32_t usage)
     {
         Parcel data, reply;
         data.writeInterfaceToken(ISurface::getInterfaceDescriptor());
         data.writeInt32(bufferIdx);
+        data.writeInt32(w);
+        data.writeInt32(h);
+        data.writeInt32(format);
         data.writeInt32(usage);
         remote()->transact(REQUEST_BUFFER, data, &reply);
         sp<GraphicBuffer> buffer = new GraphicBuffer();
@@ -83,6 +87,16 @@
         return buffer;
     }
 
+    virtual status_t setBufferCount(int bufferCount)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(ISurface::getInterfaceDescriptor());
+        data.writeInt32(bufferCount);
+        remote()->transact(SET_BUFFER_COUNT, data, &reply);
+        status_t err = reply.readInt32();
+        return err;
+    }
+
     virtual status_t registerBuffers(const BufferHeap& buffers)
     {
         Parcel data, reply;
@@ -140,12 +154,22 @@
         case REQUEST_BUFFER: {
             CHECK_INTERFACE(ISurface, data, reply);
             int bufferIdx = data.readInt32();
-            int usage = data.readInt32();
-            sp<GraphicBuffer> buffer(requestBuffer(bufferIdx, usage));
+            uint32_t w = data.readInt32();
+            uint32_t h = data.readInt32();
+            uint32_t format = data.readInt32();
+            uint32_t usage = data.readInt32();
+            sp<GraphicBuffer> buffer(requestBuffer(bufferIdx, w, h, format, usage));
             if (buffer == NULL)
                 return BAD_VALUE;
             return reply->write(*buffer);
         }
+        case SET_BUFFER_COUNT: {
+            CHECK_INTERFACE(ISurface, data, reply);
+            int bufferCount = data.readInt32();
+            status_t err = setBufferCount(bufferCount);
+            reply->writeInt32(err);
+            return NO_ERROR;
+        }
         case REGISTER_BUFFERS: {
             CHECK_INTERFACE(ISurface, data, reply);
             BufferHeap buffer;
diff --git a/libs/surfaceflinger_client/SharedBufferStack.cpp b/libs/surfaceflinger_client/SharedBufferStack.cpp
index a17e8ac..2577dc0 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;
 }
@@ -67,19 +67,47 @@
     identity = i;
 }
 
+status_t SharedBufferStack::setCrop(int buffer, const Rect& crop)
+{
+    if (uint32_t(buffer) >= NUM_BUFFER_MAX)
+        return BAD_INDEX;
+
+    buffers[buffer].crop.l = uint16_t(crop.left);
+    buffers[buffer].crop.t = uint16_t(crop.top);
+    buffers[buffer].crop.r = uint16_t(crop.right);
+    buffers[buffer].crop.b = uint16_t(crop.bottom);
+    return NO_ERROR;
+}
+
 status_t SharedBufferStack::setDirtyRegion(int buffer, const Region& dirty)
 {
     if (uint32_t(buffer) >= NUM_BUFFER_MAX)
         return BAD_INDEX;
 
-    // in the current implementation we only send a single rectangle
-    const Rect bounds(dirty.getBounds());
-    FlatRegion& reg(dirtyRegion[buffer]);
-    reg.count = 1;
-    reg.rects[0] = uint16_t(bounds.left);
-    reg.rects[1] = uint16_t(bounds.top);
-    reg.rects[2] = uint16_t(bounds.right);
-    reg.rects[3] = uint16_t(bounds.bottom);
+    FlatRegion& reg(buffers[buffer].dirtyRegion);
+    if (dirty.isEmpty()) {
+        reg.count = 0;
+        return NO_ERROR;
+    }
+
+    size_t count;
+    Rect const* r = dirty.getArray(&count);
+    if (count > FlatRegion::NUM_RECT_MAX) {
+        const Rect bounds(dirty.getBounds());
+        reg.count = 1;
+        reg.rects[0].l = uint16_t(bounds.left);
+        reg.rects[0].t = uint16_t(bounds.top);
+        reg.rects[0].r = uint16_t(bounds.right);
+        reg.rects[0].b = uint16_t(bounds.bottom);
+    } else {
+        reg.count = count;
+        for (size_t i=0 ; i<count ; i++) {
+            reg.rects[i].l = uint16_t(r[i].left);
+            reg.rects[i].t = uint16_t(r[i].top);
+            reg.rects[i].r = uint16_t(r[i].right);
+            reg.rects[i].b = uint16_t(r[i].bottom);
+        }
+    }
     return NO_ERROR;
 }
 
@@ -89,18 +117,37 @@
     if (uint32_t(buffer) >= NUM_BUFFER_MAX)
         return res;
 
-    const FlatRegion& reg(dirtyRegion[buffer]);
-    res.set(Rect(reg.rects[0], reg.rects[1], reg.rects[2], reg.rects[3]));
+    const FlatRegion& reg(buffers[buffer].dirtyRegion);
+    if (reg.count > FlatRegion::NUM_RECT_MAX)
+        return res;
+
+    if (reg.count == 1) {
+        const Rect r(
+                reg.rects[0].l,
+                reg.rects[0].t,
+                reg.rects[0].r,
+                reg.rects[0].b);
+        res.set(r);
+    } else {
+        for (size_t i=0 ; i<reg.count ; i++) {
+            const Rect r(
+                    reg.rects[i].l,
+                    reg.rects[i].t,
+                    reg.rects[i].r,
+                    reg.rects[i].b);
+            res.orSelf(r);
+        }
+    }
     return res;
 }
 
 // ----------------------------------------------------------------------------
 
 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)
 {
 }
 
@@ -108,12 +155,6 @@
 {
 }
 
-uint32_t SharedBufferBase::getIdentity()
-{
-    SharedBufferStack& stack( *mSharedStack );
-    return stack.identity;
-}
-
 status_t SharedBufferBase::getStatus() const
 {
     SharedBufferStack& stack( *mSharedStack );
@@ -132,16 +173,52 @@
     char buffer[SIZE];
     String8 result;
     SharedBufferStack& stack( *mSharedStack );
-    int tail = (mNumBuffers + stack.head - stack.available + 1) % mNumBuffers;
     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;
 }
 
+status_t SharedBufferBase::waitForCondition(const ConditionBase& condition)
+{
+    const SharedBufferStack& stack( *mSharedStack );
+    SharedClient& client( *mSharedClient );
+    const nsecs_t TIMEOUT = s2ns(1);
+    const int identity = mIdentity;
+
+    Mutex::Autolock _l(client.lock);
+    while ((condition()==false) &&
+            (stack.identity == identity) &&
+            (stack.status == NO_ERROR))
+    {
+        status_t err = client.cv.waitRelative(client.lock, TIMEOUT);
+        // handle errors and timeouts
+        if (CC_UNLIKELY(err != NO_ERROR)) {
+            if (err == TIMED_OUT) {
+                if (condition()) {
+                    LOGE("waitForCondition(%s) timed out (identity=%d), "
+                        "but condition is true! We recovered but it "
+                        "shouldn't happen." , condition.name(), stack.identity);
+                    break;
+                } else {
+                    LOGW("waitForCondition(%s) timed out "
+                        "(identity=%d, status=%d). "
+                        "CPU may be pegged. trying again.", condition.name(),
+                        stack.identity, stack.status);
+                }
+            } else {
+                LOGE("waitForCondition(%s) error (%s) ",
+                        condition.name(), strerror(-err));
+                return err;
+            }
+        }
+    }
+    return (stack.identity != mIdentity) ? status_t(BAD_INDEX) : stack.status;
+}
 // ============================================================================
 // conditions and updates
 // ============================================================================
@@ -149,24 +226,34 @@
 SharedBufferClient::DequeueCondition::DequeueCondition(
         SharedBufferClient* sbc) : ConditionBase(sbc)  { 
 }
-bool SharedBufferClient::DequeueCondition::operator()() {
+bool SharedBufferClient::DequeueCondition::operator()() const {
     return stack.available > 0;
 }
 
 SharedBufferClient::LockCondition::LockCondition(
         SharedBufferClient* sbc, int buf) : ConditionBase(sbc), buf(buf) { 
 }
-bool SharedBufferClient::LockCondition::operator()() {
-    return (buf != stack.head || 
+bool SharedBufferClient::LockCondition::operator()() const {
+    // NOTE: if stack.head is messed up, we could crash the client
+    // or cause some drawing artifacts. This is okay, as long as it is
+    // limited to the client.
+    return (buf != stack.index[stack.head] ||
             (stack.queued > 0 && stack.inUse != buf));
 }
 
 SharedBufferServer::ReallocateCondition::ReallocateCondition(
         SharedBufferBase* sbb, int buf) : ConditionBase(sbb), buf(buf) { 
 }
-bool SharedBufferServer::ReallocateCondition::operator()() {
+bool SharedBufferServer::ReallocateCondition::operator()() const {
+    int32_t head = stack.head;
+    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;
+        return false;
+    }
     // TODO: we should also check that buf has been dequeued
-    return (buf != stack.head);
+    return (buf != stack.index[head]);
 }
 
 // ----------------------------------------------------------------------------
@@ -206,11 +293,12 @@
     : UpdateBase(sbb), numBuffers(numBuffers) {
 }
 ssize_t SharedBufferServer::RetireUpdate::operator()() {
-    // head is only written in this function, which is single-thread.
     int32_t head = stack.head;
+    if (uint32_t(head) >= SharedBufferStack::NUM_BUFFER_MAX)
+        return BAD_VALUE;
 
     // Preventively lock the current buffer before updating queued.
-    android_atomic_write(head, &stack.inUse);
+    android_atomic_write(stack.index[head], &stack.inUse);
 
     // Decrement the number of queued buffers 
     int32_t queued;
@@ -221,16 +309,15 @@
         }
     } while (android_atomic_cmpxchg(queued, queued-1, &stack.queued));
     
-    // update the head pointer
-    head = ((head+1 >= numBuffers) ? 0 : head+1);
-
     // lock the buffer before advancing head, which automatically unlocks
     // the buffer we preventively locked upon entering this function
-    android_atomic_write(head, &stack.inUse);
 
-    // advance head
+    head = (head + 1) % numBuffers;
+    android_atomic_write(stack.index[head], &stack.inUse);
+
+    // head is only modified here, so we don't need to use cmpxchg
     android_atomic_write(head, &stack.head);
-    
+
     // now that head has moved, we can increment the number of available buffers
     android_atomic_inc(&stack.available);
     return head;
@@ -250,41 +337,31 @@
 
 SharedBufferClient::SharedBufferClient(SharedClient* sharedClient,
         int surface, int num, int32_t identity)
-    : SharedBufferBase(sharedClient, surface, num, identity), tail(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 );
-    // we need to make sure we read available and head coherently,
-    // w.r.t RetireUpdate.
-    int32_t newTail;
-    int32_t avail;
-    int32_t head;
-    do {
-        avail = stack.available;
-        head = stack.head;
-    } while (stack.available != avail);
-    newTail = head - avail + 1;
-    if (newTail < 0) {
-        newTail += mNumBuffers;
-    } else if (newTail >= mNumBuffers) {
-        newTail -= mNumBuffers;
-    }
-    return newTail;
+    return (mNumBuffers + stack.head - stack.available + 1) % mNumBuffers;
 }
 
 ssize_t SharedBufferClient::dequeue()
 {
     SharedBufferStack& stack( *mSharedStack );
 
-    if (stack.head == tail && stack.available == 2) {
+    if (stack.head == tail && stack.available == mNumBuffers) {
         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",
@@ -301,9 +378,10 @@
         LOGW("dequeue probably called from multiple threads!");
     }
 
-    int dequeued = tail;
+    undoDequeueTail = tail;
+    int dequeued = stack.index[tail];
     tail = ((tail+1 >= mNumBuffers) ? 0 : tail+1);
-    LOGD_IF(DEBUG_ATOMICS, "dequeued=%d, tail=%d, %s",
+    LOGD_IF(DEBUG_ATOMICS, "dequeued=%d, tail++=%d, %s",
             dequeued, tail, dump("").string());
 
     mDequeueTime[dequeued] = dequeueTime; 
@@ -313,16 +391,23 @@
 
 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);
     status_t err = updateCondition( update );
     if (err == NO_ERROR) {
-        tail = computeTail();
+        tail = undoDequeueTail;
     }
     return err;
 }
 
 status_t SharedBufferClient::lock(int buf)
 {
+    RWLock::AutoRLock _rd(mLock);
+
+    SharedBufferStack& stack( *mSharedStack );
     LockCondition condition(this, buf);
     status_t err = waitForCondition(condition);
     return err;
@@ -330,53 +415,100 @@
 
 status_t SharedBufferClient::queue(int buf)
 {
+    RWLock::AutoRLock _rd(mLock);
+
+    SharedBufferStack& stack( *mSharedStack );
+
+    queued_head = (queued_head + 1) % mNumBuffers;
+    stack.index[queued_head] = buf;
+
     QueueUpdate update(this);
     status_t err = updateCondition( update );
     LOGD_IF(DEBUG_ATOMICS, "queued=%d, %s", buf, dump("").string());
-    SharedBufferStack& stack( *mSharedStack );
+
     const nsecs_t now = systemTime(SYSTEM_TIME_THREAD);
     stack.stats.totalTime = ns2us(now - mDequeueTime[buf]);
     return err;
 }
 
-bool SharedBufferClient::needNewBuffer(int buffer) const
+bool SharedBufferClient::needNewBuffer(int buf) const
 {
     SharedBufferStack& stack( *mSharedStack );
-    const uint32_t mask = 1<<buffer;
+    const uint32_t mask = 1<<(31-buf);
     return (android_atomic_and(~mask, &stack.reallocMask) & mask) != 0;
 }
 
-status_t SharedBufferClient::setDirtyRegion(int buffer, const Region& reg)
+status_t SharedBufferClient::setCrop(int buf, const Rect& crop)
 {
     SharedBufferStack& stack( *mSharedStack );
-    return stack.setDirtyRegion(buffer, reg);
+    return stack.setCrop(buf, crop);
+}
+
+status_t SharedBufferClient::setDirtyRegion(int buf, const Region& reg)
+{
+    SharedBufferStack& stack( *mSharedStack );
+    return stack.setDirtyRegion(buf, reg);
+}
+
+status_t SharedBufferClient::setBufferCount(
+        int bufferCount, const SetBufferCountCallback& ipc)
+{
+    SharedBufferStack& stack( *mSharedStack );
+    if (uint32_t(bufferCount) >= SharedBufferStack::NUM_BUFFER_MAX)
+        return BAD_VALUE;
+
+    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;
     mSharedStack->available = num;
     mSharedStack->queued = 0;
     mSharedStack->reallocMask = 0;
-    memset(mSharedStack->dirtyRegion, 0, sizeof(mSharedStack->dirtyRegion));
+    memset(mSharedStack->buffers, 0, sizeof(mSharedStack->buffers));
+    for (int i=0 ; i<num ; i++) {
+        mBufferList.add(i);
+        mSharedStack->index[i] = i;
+    }
 }
 
 ssize_t SharedBufferServer::retireAndLock()
 {
+    RWLock::AutoRLock _l(mLock);
+
     RetireUpdate update(this, mNumBuffers);
     ssize_t buf = updateCondition( update );
-    LOGD_IF(DEBUG_ATOMICS && buf>=0, "retire=%d, %s", int(buf), dump("").string());
+    if (buf >= 0) {
+        if (uint32_t(buf) >= SharedBufferStack::NUM_BUFFER_MAX)
+            return BAD_VALUE;
+        SharedBufferStack& stack( *mSharedStack );
+        buf = stack.index[buf];
+        LOGD_IF(DEBUG_ATOMICS && buf>=0, "retire=%d, %s",
+                int(buf), dump("").string());
+    }
     return buf;
 }
 
-status_t SharedBufferServer::unlock(int buffer)
+status_t SharedBufferServer::unlock(int buf)
 {
-    UnlockUpdate update(this, buffer);
+    UnlockUpdate update(this, buf);
     status_t err = updateCondition( update );
     return err;
 }
@@ -389,11 +521,25 @@
     }
 }
 
-status_t SharedBufferServer::reallocate()
+status_t SharedBufferServer::reallocateAll()
 {
+    RWLock::AutoRLock _l(mLock);
+
     SharedBufferStack& stack( *mSharedStack );
-    uint32_t mask = (1<<mNumBuffers)-1;
-    android_atomic_or(mask, &stack.reallocMask); 
+    uint32_t mask = mBufferList.getMask();
+    android_atomic_or(mask, &stack.reallocMask);
+    return NO_ERROR;
+}
+
+status_t SharedBufferServer::reallocateAllExcept(int buffer)
+{
+    RWLock::AutoRLock _l(mLock);
+
+    SharedBufferStack& stack( *mSharedStack );
+    BufferList temp(mBufferList);
+    temp.remove(buffer);
+    uint32_t mask = temp.getMask();
+    android_atomic_or(mask, &stack.reallocMask);
     return NO_ERROR;
 }
 
@@ -403,17 +549,77 @@
     return stack.queued;
 }
 
-status_t SharedBufferServer::assertReallocate(int buffer)
+status_t SharedBufferServer::assertReallocate(int buf)
 {
-    ReallocateCondition condition(this, buffer);
+    /*
+     * 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);
     return err;
 }
 
-Region SharedBufferServer::getDirtyRegion(int buffer) const
+Region SharedBufferServer::getDirtyRegion(int buf) const
 {
     SharedBufferStack& stack( *mSharedStack );
-    return stack.getDirtyRegion(buffer);
+    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.
+ *
+ */
+status_t SharedBufferServer::resize(int newNumBuffers)
+{
+    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)
+        return BAD_VALUE;
+
+    SharedBufferStack& stack( *mSharedStack );
+    const int extra = newNumBuffers - numBuffers;
+
+    // read the head, make sure it's valid
+    int32_t head = stack.head;
+    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;
+        memmove(&index[head + extra], &index[head], nb);
+        base = head;
+        // move head 'extra' ahead, this doesn't impact stack.index[head];
+        stack.head = head + extra;
+    }
+    stack.available += extra;
+
+    // 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(*curr);
+        ++curr;
+    }
+
+    mNumBuffers = newNumBuffers;
+    return NO_ERROR;
 }
 
 SharedBufferStack::Statistics SharedBufferServer::getStats() const
@@ -422,6 +628,29 @@
     return stack.stats;
 }
 
+// ---------------------------------------------------------------------------
+status_t SharedBufferServer::BufferList::add(int value)
+{
+    if (uint32_t(value) >= mCapacity)
+        return BAD_VALUE;
+    uint32_t mask = 1<<(31-value);
+    if (mList & mask)
+        return ALREADY_EXISTS;
+    mList |= mask;
+    return NO_ERROR;
+}
+
+status_t SharedBufferServer::BufferList::remove(int value)
+{
+    if (uint32_t(value) >= mCapacity)
+        return BAD_VALUE;
+    uint32_t mask = 1<<(31-value);
+    if (!(mList & mask))
+        return NAME_NOT_FOUND;
+    mList &= ~mask;
+    return NO_ERROR;
+}
+
 
 // ---------------------------------------------------------------------------
 }; // namespace android
diff --git a/libs/surfaceflinger_client/Surface.cpp b/libs/surfaceflinger_client/Surface.cpp
index 5dd75c3..35a4e8b 100644
--- a/libs/surfaceflinger_client/Surface.cpp
+++ b/libs/surfaceflinger_client/Surface.cpp
@@ -17,8 +17,6 @@
 #define LOG_TAG "Surface"
 
 #include <stdint.h>
-#include <unistd.h>
-#include <fcntl.h>
 #include <errno.h>
 #include <sys/types.h>
 #include <sys/stat.h>
@@ -28,8 +26,6 @@
 #include <utils/CallStack.h>
 #include <utils/Log.h>
 
-#include <pixelflinger/pixelflinger.h>
-
 #include <binder/IPCThreadState.h>
 #include <binder/IMemory.h>
 
@@ -55,6 +51,8 @@
         const sp<GraphicBuffer>& src, 
         const Region& reg)
 {
+    // src and dst with, height and format must be identical. no verification
+    // is done here.
     status_t err;
     uint8_t const * src_bits = NULL;
     err = src->lock(GRALLOC_USAGE_SW_READ_OFTEN, reg.bounds(), (void**)&src_bits);
@@ -67,7 +65,6 @@
     Region::const_iterator head(reg.begin());
     Region::const_iterator tail(reg.end());
     if (head != tail && src_bits && dst_bits) {
-        // NOTE: dst and src must be the same format
         const size_t bpp = bytesPerPixel(src->format);
         const size_t dbpr = dst->stride * bpp;
         const size_t sbpr = src->stride * bpp;
@@ -154,75 +151,75 @@
 }
 
 status_t SurfaceControl::setLayer(int32_t layer) {
-    const sp<SurfaceComposerClient>& client(mClient);
     status_t err = validate();
     if (err < 0) return err;
+    const sp<SurfaceComposerClient>& client(mClient);
     return client->setLayer(mToken, layer);
 }
 status_t SurfaceControl::setPosition(int32_t x, int32_t y) {
-    const sp<SurfaceComposerClient>& client(mClient);
     status_t err = validate();
     if (err < 0) return err;
+    const sp<SurfaceComposerClient>& client(mClient);
     return client->setPosition(mToken, x, y);
 }
 status_t SurfaceControl::setSize(uint32_t w, uint32_t h) {
-    const sp<SurfaceComposerClient>& client(mClient);
     status_t err = validate();
     if (err < 0) return err;
+    const sp<SurfaceComposerClient>& client(mClient);
     return client->setSize(mToken, w, h);
 }
 status_t SurfaceControl::hide() {
-    const sp<SurfaceComposerClient>& client(mClient);
     status_t err = validate();
     if (err < 0) return err;
+    const sp<SurfaceComposerClient>& client(mClient);
     return client->hide(mToken);
 }
 status_t SurfaceControl::show(int32_t layer) {
-    const sp<SurfaceComposerClient>& client(mClient);
     status_t err = validate();
     if (err < 0) return err;
+    const sp<SurfaceComposerClient>& client(mClient);
     return client->show(mToken, layer);
 }
 status_t SurfaceControl::freeze() {
-    const sp<SurfaceComposerClient>& client(mClient);
     status_t err = validate();
     if (err < 0) return err;
+    const sp<SurfaceComposerClient>& client(mClient);
     return client->freeze(mToken);
 }
 status_t SurfaceControl::unfreeze() {
-    const sp<SurfaceComposerClient>& client(mClient);
     status_t err = validate();
     if (err < 0) return err;
+    const sp<SurfaceComposerClient>& client(mClient);
     return client->unfreeze(mToken);
 }
 status_t SurfaceControl::setFlags(uint32_t flags, uint32_t mask) {
-    const sp<SurfaceComposerClient>& client(mClient);
     status_t err = validate();
     if (err < 0) return err;
+    const sp<SurfaceComposerClient>& client(mClient);
     return client->setFlags(mToken, flags, mask);
 }
 status_t SurfaceControl::setTransparentRegionHint(const Region& transparent) {
-    const sp<SurfaceComposerClient>& client(mClient);
     status_t err = validate();
     if (err < 0) return err;
+    const sp<SurfaceComposerClient>& client(mClient);
     return client->setTransparentRegionHint(mToken, transparent);
 }
 status_t SurfaceControl::setAlpha(float alpha) {
-    const sp<SurfaceComposerClient>& client(mClient);
     status_t err = validate();
     if (err < 0) return err;
+    const sp<SurfaceComposerClient>& client(mClient);
     return client->setAlpha(mToken, alpha);
 }
 status_t SurfaceControl::setMatrix(float dsdx, float dtdx, float dsdy, float dtdy) {
-    const sp<SurfaceComposerClient>& client(mClient);
     status_t err = validate();
     if (err < 0) return err;
+    const sp<SurfaceComposerClient>& client(mClient);
     return client->setMatrix(mToken, dsdx, dtdx, dsdy, dtdy);
 }
 status_t SurfaceControl::setFreezeTint(uint32_t tint) {
-    const sp<SurfaceComposerClient>& client(mClient);
     status_t err = validate();
     if (err < 0) return err;
+    const sp<SurfaceComposerClient>& client(mClient);
     return client->setFreezeTint(mToken, tint);
 }
 
@@ -233,23 +230,6 @@
                 mToken, mIdentity, mClient.get());
         return NO_INIT;
     }
-    SharedClient const* cblk = mClient->mControl;
-    if (cblk == 0) {
-        LOGE("cblk is null (surface id=%d, identity=%u)", mToken, mIdentity);
-        return NO_INIT;
-    }
-    status_t err = cblk->validate(mToken);
-    if (err != NO_ERROR) {
-        LOGE("surface (id=%d, identity=%u) is invalid, err=%d (%s)",
-                mToken, mIdentity, err, strerror(-err));
-        return err;
-    }
-    uint32_t identity = cblk->getIdentity(mToken);
-    if (mIdentity != identity) {
-        LOGE("using an invalid surface id=%d, identity=%u should be %d",
-                mToken, mIdentity, identity);
-        return NO_INIT;
-    }
     return NO_ERROR;
 }
 
@@ -298,23 +278,24 @@
 //  Surface
 // ============================================================================
 
+
 Surface::Surface(const sp<SurfaceControl>& surface)
-    : mClient(surface->mClient), mSurface(surface->mSurface),
+    : mSurface(surface->mSurface),
       mToken(surface->mToken), mIdentity(surface->mIdentity),
       mFormat(surface->mFormat), mFlags(surface->mFlags),
       mBufferMapper(GraphicBufferMapper::get()), mSharedBufferClient(NULL),
+      mInitCheck(NO_INIT),
       mWidth(surface->mWidth), mHeight(surface->mHeight)
 {
-    mSharedBufferClient = new SharedBufferClient(
-            mClient->mControl, mToken, 2, mIdentity);
-
+    mClient = new SurfaceClient(surface->mClient);
     init();
 }
 
 Surface::Surface(const Parcel& parcel)
-    :  mBufferMapper(GraphicBufferMapper::get()), mSharedBufferClient(NULL)
+    :  mBufferMapper(GraphicBufferMapper::get()),
+       mSharedBufferClient(NULL), mInitCheck(NO_INIT)
 {
-    sp<IBinder> clientBinder = parcel.readStrongBinder();
+    sp<IBinder> conn = parcel.readStrongBinder();
     mSurface    = interface_cast<ISurface>(parcel.readStrongBinder());
     mToken      = parcel.readInt32();
     mIdentity   = parcel.readInt32();
@@ -322,15 +303,7 @@
     mHeight     = parcel.readInt32();
     mFormat     = parcel.readInt32();
     mFlags      = parcel.readInt32();
-
-    // FIXME: what does that mean if clientBinder is NULL here?
-    if (clientBinder != NULL) {
-        mClient = SurfaceComposerClient::clientForConnection(clientBinder);
-
-        mSharedBufferClient = new SharedBufferClient(
-                mClient->mControl, mToken, 2, mIdentity);
-    }
-
+    mClient = new SurfaceClient(conn);
     init();
 }
 
@@ -342,7 +315,7 @@
     android_native_window_t::queueBuffer      = queueBuffer;
     android_native_window_t::query            = query;
     android_native_window_t::perform          = perform;
-    mSwapRectangle.makeInvalid();
+
     DisplayInfo dinfo;
     SurfaceComposerClient::getDisplayInfo(0, &dinfo);
     const_cast<float&>(android_native_window_t::xdpi) = dinfo.xdpi;
@@ -351,17 +324,27 @@
     const_cast<int&>(android_native_window_t::minSwapInterval) = 1;
     const_cast<int&>(android_native_window_t::maxSwapInterval) = 1;
     const_cast<uint32_t&>(android_native_window_t::flags) = 0;
-    // be default we request a hardware surface
-    mUsage = GRALLOC_USAGE_HW_RENDER;
+
     mConnected = 0;
-    mNeedFullUpdate = false;
+    mSwapRectangle.makeInvalid();
+    // two buffers by default
+    mBuffers.setCapacity(2);
+    mBuffers.insertAt(0, 2);
+
+    if (mClient != 0 && mClient->initCheck() == NO_ERROR) {
+        mSharedBufferClient = new SharedBufferClient(
+                mClient->getSharedClient(), mToken, 2, mIdentity);
+    }
+
+    mInitCheck = initCheck();
 }
 
 Surface::~Surface()
 {
     // this is a client-side operation, the surface is destroyed, unmap
     // its buffers in this process.
-    for (int i=0 ; i<2 ; i++) {
+    size_t size = mBuffers.size();
+    for (size_t i=0 ; i<size ; i++) {
         if (mBuffers[i] != 0 && mBuffers[i]->handle != 0) {
             getBufferMapper().unregisterBuffer(mBuffers[i]->handle);
         }
@@ -369,62 +352,80 @@
 
     // clear all references and trigger an IPC now, to make sure things
     // happen without delay, since these resources are quite heavy.
+    mBuffers.clear();
     mClient.clear();
     mSurface.clear();
     delete mSharedBufferClient;
     IPCThreadState::self()->flushCommands();
 }
 
-sp<SurfaceComposerClient> Surface::getClient() const {
-    return mClient;
-}
-
-sp<ISurface> Surface::getISurface() const {
-    return mSurface;
-}
-
-bool Surface::isValid() {
-    return mToken>=0 && mClient!=0;
-}
-
-status_t Surface::validate() const
+status_t Surface::initCheck() const
 {
-    sp<SurfaceComposerClient> client(getClient());
-    if (mToken<0 || mClient==0) {
-        LOGE("invalid token (%d, identity=%u) or client (%p)", 
-                mToken, mIdentity, client.get());
+    if (mToken<0 || mClient==0 || mClient->initCheck() != NO_ERROR) {
         return NO_INIT;
     }
-    SharedClient const* cblk = mClient->mControl;
+    SharedClient const* cblk = mClient->getSharedClient();
     if (cblk == 0) {
         LOGE("cblk is null (surface id=%d, identity=%u)", mToken, mIdentity);
         return NO_INIT;
     }
+    return NO_ERROR;
+}
+
+bool Surface::isValid() {
+    return mInitCheck == NO_ERROR;
+}
+
+status_t Surface::validate() const
+{
+    // check that we initialized ourself properly
+    if (mInitCheck != NO_ERROR) {
+        LOGE("invalid token (%d, identity=%u) or client (%p)",
+                mToken, mIdentity, mClient.get());
+        return mInitCheck;
+    }
+
+    // verify the identity of this surface
+    SharedClient const* cblk = mClient->getSharedClient();
+
+    uint32_t identity = cblk->getIdentity(mToken);
+
+    // this is a bit of a (temporary) special case, identity==0 means that
+    // no operation are allowed from the client (eg: dequeue/queue), this
+    // is used with PUSH_BUFFER surfaces for instance
+    if (identity == 0) {
+        LOGE("[Surface] invalid operation (identity=%u)", mIdentity);
+        return INVALID_OPERATION;
+    }
+
+    if (mIdentity != identity) {
+        LOGE("[Surface] using an invalid surface id=%d, "
+                "identity=%u should be %d",
+                mToken, mIdentity, identity);
+        return NO_INIT;
+    }
+
+    // check the surface didn't become invalid
     status_t err = cblk->validate(mToken);
     if (err != NO_ERROR) {
         LOGE("surface (id=%d, identity=%u) is invalid, err=%d (%s)",
                 mToken, mIdentity, err, strerror(-err));
         return err;
     }
-    uint32_t identity = cblk->getIdentity(mToken);
-    if (mIdentity != identity) {
-        LOGE("using an invalid surface id=%d, identity=%u should be %d",
-                mToken, mIdentity, identity);
-        return NO_INIT;
-    }
+
     return NO_ERROR;
 }
 
-
-bool Surface::isSameSurface(
-        const sp<Surface>& lhs, const sp<Surface>& rhs) 
-{
+bool Surface::isSameSurface(const sp<Surface>& lhs, const sp<Surface>& rhs) {
     if (lhs == 0 || rhs == 0)
         return false;
-
     return lhs->mSurface->asBinder() == rhs->mSurface->asBinder();
 }
 
+sp<ISurface> Surface::getISurface() const {
+    return mSurface;
+}
+
 // ----------------------------------------------------------------------------
 
 int Surface::setSwapInterval(android_native_window_t* window, int interval) {
@@ -467,21 +468,24 @@
 
 // ----------------------------------------------------------------------------
 
-status_t Surface::dequeueBuffer(sp<GraphicBuffer>* buffer) {
-    android_native_buffer_t* out;
-    status_t err = dequeueBuffer(&out);
-    if (err == NO_ERROR) {
-        *buffer = GraphicBuffer::getSelf(out);
+bool Surface::needNewBuffer(int bufIdx,
+        uint32_t *pWidth, uint32_t *pHeight,
+        uint32_t *pFormat, uint32_t *pUsage) const
+{
+    Mutex::Autolock _l(mSurfaceLock);
+
+    // Always call needNewBuffer(), since it clears the needed buffers flags
+    bool needNewBuffer = mSharedBufferClient->needNewBuffer(bufIdx);
+    bool validBuffer = mBufferInfo.validateBuffer(mBuffers[bufIdx]);
+    bool newNeewBuffer = needNewBuffer || !validBuffer;
+    if (newNeewBuffer) {
+        mBufferInfo.get(pWidth, pHeight, pFormat, pUsage);
     }
-    return err;
+    return newNeewBuffer;
 }
 
-// ----------------------------------------------------------------------------
-
-
 int Surface::dequeueBuffer(android_native_buffer_t** buffer)
 {
-    sp<SurfaceComposerClient> client(getClient());
     status_t err = validate();
     if (err != NO_ERROR)
         return err;
@@ -492,24 +496,28 @@
         return bufIdx;
     }
 
-    // below we make sure we AT LEAST have the usage flags we want
-    const uint32_t usage(getUsage());
-    const sp<GraphicBuffer>& backBuffer(mBuffers[bufIdx]);
-    if (backBuffer == 0 || 
-        ((uint32_t(backBuffer->usage) & usage) != usage) ||
-        mSharedBufferClient->needNewBuffer(bufIdx)) 
-    {
-        err = getBufferLocked(bufIdx, usage);
-        LOGE_IF(err, "getBufferLocked(%ld, %08x) failed (%s)",
-                bufIdx, usage, strerror(-err));
+    // grow the buffer array if needed
+    const size_t size = mBuffers.size();
+    const size_t needed = bufIdx+1;
+    if (size < needed) {
+        mBuffers.insertAt(size, needed-size);
+    }
+
+    uint32_t w, h, format, usage;
+    if (needNewBuffer(bufIdx, &w, &h, &format, &usage)) {
+        err = getBufferLocked(bufIdx, w, h, format, usage);
+        LOGE_IF(err, "getBufferLocked(%ld, %u, %u, %u, %08x) failed (%s)",
+                bufIdx, w, h, format, usage, strerror(-err));
         if (err == NO_ERROR) {
             // reset the width/height with the what we get from the buffer
+            const sp<GraphicBuffer>& backBuffer(mBuffers[bufIdx]);
             mWidth  = uint32_t(backBuffer->width);
             mHeight = uint32_t(backBuffer->height);
         }
     }
 
     // if we still don't have a buffer here, we probably ran out of memory
+    const sp<GraphicBuffer>& backBuffer(mBuffers[bufIdx]);
     if (!err && backBuffer==0) {
         err = NO_MEMORY;
     }
@@ -526,12 +534,11 @@
 
 int Surface::lockBuffer(android_native_buffer_t* buffer)
 {
-    sp<SurfaceComposerClient> client(getClient());
     status_t err = validate();
     if (err != NO_ERROR)
         return err;
 
-    int32_t bufIdx = GraphicBuffer::getSelf(buffer)->getIndex();
+    int32_t bufIdx = getBufferIndex(GraphicBuffer::getSelf(buffer));
     err = mSharedBufferClient->lock(bufIdx);
     LOGE_IF(err, "error locking buffer %d (%s)", bufIdx, strerror(-err));
     return err;
@@ -539,7 +546,6 @@
 
 int Surface::queueBuffer(android_native_buffer_t* buffer)
 {   
-    sp<SurfaceComposerClient> client(getClient());
     status_t err = validate();
     if (err != NO_ERROR)
         return err;
@@ -548,14 +554,15 @@
         mDirtyRegion.set(mSwapRectangle);
     }
     
-    int32_t bufIdx = GraphicBuffer::getSelf(buffer)->getIndex();
+    int32_t bufIdx = getBufferIndex(GraphicBuffer::getSelf(buffer));
+    mSharedBufferClient->setCrop(bufIdx, mNextBufferCrop);
     mSharedBufferClient->setDirtyRegion(bufIdx, mDirtyRegion);
     err = mSharedBufferClient->queue(bufIdx);
     LOGE_IF(err, "error queuing buffer %d (%s)", bufIdx, strerror(-err));
 
     if (err == NO_ERROR) {
         // FIXME: can we avoid this IPC if we know there is one pending?
-        client->signalServer();
+        mClient->signalServer();
     }
     return err;
 }
@@ -578,6 +585,10 @@
 
 int Surface::perform(int operation, va_list args)
 {
+    status_t err = validate();
+    if (err != NO_ERROR)
+        return err;
+
     int res = NO_ERROR;
     switch (operation) {
     case NATIVE_WINDOW_SET_USAGE:
@@ -589,6 +600,15 @@
     case NATIVE_WINDOW_DISCONNECT:
         res = dispatch_disconnect( args );
         break;
+    case NATIVE_WINDOW_SET_CROP:
+        res = dispatch_crop( args );
+        break;
+    case NATIVE_WINDOW_SET_BUFFER_COUNT:
+        res = dispatch_set_buffer_count( args );
+        break;
+    case NATIVE_WINDOW_SET_BUFFERS_GEOMETRY:
+        res = dispatch_set_buffers_geometry( args );
+        break;
     default:
         res = NAME_NOT_FOUND;
         break;
@@ -608,12 +628,25 @@
     int api = va_arg(args, int);
     return disconnect( api );
 }
-
+int Surface::dispatch_crop(va_list args) {
+    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);
+}
+int Surface::dispatch_set_buffers_geometry(va_list args) {
+    int w = va_arg(args, int);
+    int h = va_arg(args, int);
+    int f = va_arg(args, int);
+    return setBuffersGeometry(w, h, f);
+}
 
 void Surface::setUsage(uint32_t reqUsage)
 {
     Mutex::Autolock _l(mSurfaceLock);
-    mUsage = reqUsage;
+    mBufferInfo.set(reqUsage);
 }
 
 int Surface::connect(int api)
@@ -654,19 +687,55 @@
     return err;
 }
 
-uint32_t Surface::getUsage() const
+int Surface::crop(Rect const* rect)
 {
     Mutex::Autolock _l(mSurfaceLock);
-    return mUsage;
+    // TODO: validate rect size
+    mNextBufferCrop = *rect;
+    return NO_ERROR;
 }
 
+int Surface::setBufferCount(int bufferCount)
+{
+    sp<ISurface> s(mSurface);
+    if (s == 0) return NO_INIT;
+
+    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 = mSharedBufferClient->setBufferCount(bufferCount, ipc);
+    LOGE_IF(err, "ISurface::setBufferCount(%d) returned %s",
+            bufferCount, strerror(-err));
+    return err;
+}
+
+int Surface::setBuffersGeometry(int w, int h, int format)
+{
+    if (w<0 || h<0 || format<0)
+        return BAD_VALUE;
+
+    if ((w && !h) || (!w && h))
+        return BAD_VALUE;
+
+    Mutex::Autolock _l(mSurfaceLock);
+    mBufferInfo.set(w, h, format);
+    return NO_ERROR;
+}
+
+// ----------------------------------------------------------------------------
+
 int Surface::getConnectedApi() const
 {
     Mutex::Autolock _l(mSurfaceLock);
     return mConnected;
 }
 
-
 // ----------------------------------------------------------------------------
 
 status_t Surface::lock(SurfaceInfo* info, bool blocking) {
@@ -703,45 +772,47 @@
     // we're intending to do software rendering from this point
     setUsage(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN);
 
-    sp<GraphicBuffer> backBuffer;
-    status_t err = dequeueBuffer(&backBuffer);
+    android_native_buffer_t* out;
+    status_t err = dequeueBuffer(&out);
     LOGE_IF(err, "dequeueBuffer failed (%s)", strerror(-err));
     if (err == NO_ERROR) {
+        sp<GraphicBuffer> backBuffer(GraphicBuffer::getSelf(out));
         err = lockBuffer(backBuffer.get());
         LOGE_IF(err, "lockBuffer (idx=%d) failed (%s)",
-                backBuffer->getIndex(), strerror(-err));
+                getBufferIndex(backBuffer), strerror(-err));
         if (err == NO_ERROR) {
-            // we handle copy-back here...
-
             const Rect bounds(backBuffer->width, backBuffer->height);
-            Region scratch(bounds);
+            const Region boundsRegion(bounds);
+            Region scratch(boundsRegion);
             Region& newDirtyRegion(dirtyIn ? *dirtyIn : scratch);
+            newDirtyRegion &= boundsRegion;
 
-            if (mNeedFullUpdate) {
-                // reset newDirtyRegion to bounds when a buffer is reallocated
-                // it would be better if this information was associated with
-                // the buffer and made available to outside of Surface.
-                // This will do for now though.
-                mNeedFullUpdate = false;
-                newDirtyRegion.set(bounds);
-            } else {
-                newDirtyRegion.andSelf(bounds);
-            }
-
+            // figure out if we can copy the frontbuffer back
             const sp<GraphicBuffer>& frontBuffer(mPostedBuffer);
-            if (frontBuffer !=0 &&
-                backBuffer->width  == frontBuffer->width && 
-                backBuffer->height == frontBuffer->height &&
-                !(mFlags & ISurfaceComposer::eDestroyBackbuffer)) 
-            {
+            const bool canCopyBack = (frontBuffer != 0 &&
+                    backBuffer->width  == frontBuffer->width &&
+                    backBuffer->height == frontBuffer->height &&
+                    backBuffer->format == frontBuffer->format &&
+                    !(mFlags & ISurfaceComposer::eDestroyBackbuffer));
+
+            // the dirty region we report to surfaceflinger is the one
+            // given by the user (as opposed to the one *we* return to the
+            // user).
+            mDirtyRegion = newDirtyRegion;
+
+            if (canCopyBack) {
+                // copy the area that is invalid and not repainted this round
                 const Region copyback(mOldDirtyRegion.subtract(newDirtyRegion));
-                if (!copyback.isEmpty() && frontBuffer!=0) {
-                    // copy front to back
+                if (!copyback.isEmpty())
                     copyBlt(backBuffer, frontBuffer, copyback);
-                }
+            } else {
+                // if we can't copy-back anything, modify the user's dirty
+                // region to make sure they redraw the whole buffer
+                newDirtyRegion = boundsRegion;
             }
 
-            mDirtyRegion = newDirtyRegion;
+            // keep track of the are of the buffer that is "clean"
+            // (ie: that will be redrawn)
             mOldDirtyRegion = newDirtyRegion;
 
             void* vaddr;
@@ -777,7 +848,7 @@
     
     err = queueBuffer(mLockedBuffer.get());
     LOGE_IF(err, "queueBuffer (idx=%d) failed (%s)",
-            mLockedBuffer->getIndex(), strerror(-err));
+            getBufferIndex(mLockedBuffer), strerror(-err));
 
     mPostedBuffer = mLockedBuffer;
     mLockedBuffer = 0;
@@ -789,7 +860,13 @@
     mSwapRectangle = r;
 }
 
-status_t Surface::getBufferLocked(int index, int usage)
+int Surface::getBufferIndex(const sp<GraphicBuffer>& buffer) const
+{
+    return buffer->getIndex();
+}
+
+status_t Surface::getBufferLocked(int index,
+        uint32_t w, uint32_t h, uint32_t format, uint32_t usage)
 {
     sp<ISurface> s(mSurface);
     if (s == 0) return NO_INIT;
@@ -797,20 +874,21 @@
     status_t err = NO_MEMORY;
 
     // free the current buffer
-    sp<GraphicBuffer>& currentBuffer(mBuffers[index]);
+    sp<GraphicBuffer>& currentBuffer(mBuffers.editItemAt(index));
     if (currentBuffer != 0) {
         getBufferMapper().unregisterBuffer(currentBuffer->handle);
         currentBuffer.clear();
     }
 
-    sp<GraphicBuffer> buffer = s->requestBuffer(index, usage);
+    sp<GraphicBuffer> buffer = s->requestBuffer(index, w, h, format, usage);
     LOGE_IF(buffer==0,
             "ISurface::getBuffer(%d, %08x) returned NULL",
             index, usage);
     if (buffer != 0) { // this should never happen by construction
         LOGE_IF(buffer->handle == NULL, 
-                "Surface (identity=%d) requestBuffer(%d, %08x) returned"
-                "a buffer with a null handle", mIdentity, index, usage);
+                "Surface (identity=%d) requestBuffer(%d, %u, %u, %u, %08x) "
+                "returned a buffer with a null handle",
+                mIdentity, index, w, h, format, usage);
         err = mSharedBufferClient->getStatus();
         LOGE_IF(err,  "Surface (identity=%d) state = %d", mIdentity, err);
         if (!err && buffer->handle != NULL) {
@@ -820,14 +898,52 @@
             if (err == NO_ERROR) {
                 currentBuffer = buffer;
                 currentBuffer->setIndex(index);
-                mNeedFullUpdate = true;
             }
         } else {
-            err = err<0 ? err : NO_MEMORY;
+            err = err<0 ? err : status_t(NO_MEMORY);
         }
     }
     return err; 
 }
 
+// ----------------------------------------------------------------------------
+Surface::BufferInfo::BufferInfo()
+    : mWidth(0), mHeight(0), mFormat(0),
+      mUsage(GRALLOC_USAGE_HW_RENDER), mDirty(0)
+{
+}
+
+void Surface::BufferInfo::set(uint32_t w, uint32_t h, uint32_t format) {
+    if ((mWidth != w) || (mHeight != h) || (mFormat != format)) {
+        mWidth = w;
+        mHeight = h;
+        mFormat = format;
+        mDirty |= GEOMETRY;
+    }
+}
+
+void Surface::BufferInfo::set(uint32_t usage) {
+    mUsage = usage;
+}
+
+void Surface::BufferInfo::get(uint32_t *pWidth, uint32_t *pHeight,
+        uint32_t *pFormat, uint32_t *pUsage) const {
+    *pWidth  = mWidth;
+    *pHeight = mHeight;
+    *pFormat = mFormat;
+    *pUsage  = mUsage;
+}
+
+bool Surface::BufferInfo::validateBuffer(const sp<GraphicBuffer>& buffer) const {
+    // make sure we AT LEAST have the usage flags we want
+    if (mDirty || buffer==0 ||
+            ((buffer->usage & mUsage) != mUsage)) {
+        mDirty = 0;
+        return false;
+    }
+    return true;
+}
+
+// ----------------------------------------------------------------------------
 }; // namespace android
 
diff --git a/libs/surfaceflinger_client/SurfaceComposerClient.cpp b/libs/surfaceflinger_client/SurfaceComposerClient.cpp
index 85167da..8d39c85 100644
--- a/libs/surfaceflinger_client/SurfaceComposerClient.cpp
+++ b/libs/surfaceflinger_client/SurfaceComposerClient.cpp
@@ -17,25 +17,18 @@
 #define LOG_TAG "SurfaceComposerClient"
 
 #include <stdint.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <errno.h>
 #include <sys/types.h>
-#include <sys/stat.h>
 
-#include <cutils/memory.h>
-
-#include <utils/Atomic.h>
 #include <utils/Errors.h>
 #include <utils/threads.h>
-#include <utils/KeyedVector.h>
+#include <utils/SortedVector.h>
 #include <utils/Log.h>
+#include <utils/Singleton.h>
 
 #include <binder/IServiceManager.h>
 #include <binder/IMemory.h>
 
 #include <ui/DisplayInfo.h>
-#include <ui/Rect.h>
 
 #include <surfaceflinger/ISurfaceComposer.h>
 #include <surfaceflinger/ISurfaceFlingerClient.h>
@@ -45,69 +38,110 @@
 #include <private/surfaceflinger/LayerState.h>
 #include <private/surfaceflinger/SharedBufferStack.h>
 
-#define VERBOSE(...)	((void)0)
-//#define VERBOSE			LOGD
-
-#define LIKELY( exp )       (__builtin_expect( (exp) != 0, true  ))
-#define UNLIKELY( exp )     (__builtin_expect( (exp) != 0, false ))
 
 namespace android {
-
 // ---------------------------------------------------------------------------
 
-// Must not be holding SurfaceComposerClient::mLock when acquiring gLock here.
-static Mutex                                                gLock;
-static sp<ISurfaceComposer>                                 gSurfaceManager;
-static DefaultKeyedVector< sp<IBinder>, wp<SurfaceComposerClient> > gActiveConnections;
-static SortedVector<sp<SurfaceComposerClient> >             gOpenTransactions;
-static sp<IMemoryHeap>                                      gServerCblkMemory;
-static volatile surface_flinger_cblk_t*                     gServerCblk;
-
-static sp<ISurfaceComposer> getComposerService()
+class Composer : public Singleton<Composer>
 {
-    sp<ISurfaceComposer> sc;
-    Mutex::Autolock _l(gLock);
-    if (gSurfaceManager != 0) {
-        sc = gSurfaceManager;
-    } else {
-        // release the lock while we're waiting...
-        gLock.unlock();
+    // these are constants
+    sp<ISurfaceComposer> mComposerService;
+    sp<IMemoryHeap> mServerCblkMemory;
+    surface_flinger_cblk_t volatile* mServerCblk;
 
-        sp<IBinder> binder;
-        sp<IServiceManager> sm = defaultServiceManager();
-        do {
-            binder = sm->getService(String16("SurfaceFlinger"));
-            if (binder == 0) {
-                LOGW("SurfaceFlinger not published, waiting...");
-                usleep(500000); // 0.5 s
+    Mutex mLock;
+    SortedVector< wp<SurfaceComposerClient> > mActiveConnections;
+    SortedVector<sp<SurfaceComposerClient> > mOpenTransactions;
+
+    Composer() : Singleton<Composer>() {
+        const String16 name("SurfaceFlinger");
+        while (getService(name, &mComposerService) != NO_ERROR) {
+            usleep(250000);
+        }
+        mServerCblkMemory = mComposerService->getCblk();
+        mServerCblk = static_cast<surface_flinger_cblk_t volatile *>(
+                mServerCblkMemory->getBase());
+    }
+
+    void addClientImpl(const sp<SurfaceComposerClient>& client) {
+        Mutex::Autolock _l(mLock);
+        mActiveConnections.add(client);
+    }
+
+    void removeClientImpl(const sp<SurfaceComposerClient>& client) {
+        Mutex::Autolock _l(mLock);
+        mActiveConnections.remove(client);
+    }
+
+    void openGlobalTransactionImpl()
+    {
+        Mutex::Autolock _l(mLock);
+        if (mOpenTransactions.size()) {
+            LOGE("openGlobalTransaction() called more than once. skipping.");
+            return;
+        }
+        const size_t N = mActiveConnections.size();
+        for (size_t i=0; i<N; i++) {
+            sp<SurfaceComposerClient> client(mActiveConnections[i].promote());
+            if (client != 0 && mOpenTransactions.indexOf(client) < 0) {
+                if (client->openTransaction() == NO_ERROR) {
+                    mOpenTransactions.add(client);
+                } else {
+                    LOGE("openTransaction on client %p failed", client.get());
+                    // let it go, it'll fail later when the user
+                    // tries to do something with the transaction
+                }
             }
-        } while(binder == 0);
-
-        // grab the lock again for updating gSurfaceManager
-        gLock.lock();
-        if (gSurfaceManager == 0) {
-            sc = interface_cast<ISurfaceComposer>(binder);
-            gSurfaceManager = sc;
-        } else {
-            sc = gSurfaceManager;
         }
     }
-    return sc;
+
+    void closeGlobalTransactionImpl()
+    {
+        mLock.lock();
+            SortedVector< sp<SurfaceComposerClient> > clients(mOpenTransactions);
+            mOpenTransactions.clear();
+        mLock.unlock();
+
+        sp<ISurfaceComposer> sm(mComposerService);
+        sm->openGlobalTransaction();
+            const size_t N = clients.size();
+            for (size_t i=0; i<N; i++) {
+                clients[i]->closeTransaction();
+            }
+        sm->closeGlobalTransaction();
+    }
+
+    friend class Singleton<Composer>;
+
+public:
+    static sp<ISurfaceComposer> getComposerService() {
+        return Composer::getInstance().mComposerService;
+    }
+    static surface_flinger_cblk_t const volatile * getControlBlock() {
+        return Composer::getInstance().mServerCblk;
+    }
+    static void addClient(const sp<SurfaceComposerClient>& client) {
+        Composer::getInstance().addClientImpl(client);
+    }
+    static void removeClient(const sp<SurfaceComposerClient>& client) {
+        Composer::getInstance().removeClientImpl(client);
+    }
+    static void openGlobalTransaction() {
+        Composer::getInstance().openGlobalTransactionImpl();
+    }
+    static void closeGlobalTransaction() {
+        Composer::getInstance().closeGlobalTransactionImpl();
+    }
+};
+
+ANDROID_SINGLETON_STATIC_INSTANCE(Composer);
+
+static inline sp<ISurfaceComposer> getComposerService() {
+    return Composer::getComposerService();
 }
 
-static volatile surface_flinger_cblk_t const * get_cblk()
-{
-    if (gServerCblk == 0) {
-        sp<ISurfaceComposer> sm(getComposerService());
-        Mutex::Autolock _l(gLock);
-        if (gServerCblk == 0) {
-            gServerCblkMemory = sm->getCblk();
-            LOGE_IF(gServerCblkMemory==0, "Can't get server control block");
-            gServerCblk = (surface_flinger_cblk_t *)gServerCblkMemory->getBase();
-            LOGE_IF(gServerCblk==0, "Can't get server control block address");
-        }
-    }
-    return gServerCblk;
+static inline surface_flinger_cblk_t const volatile * get_cblk() {
+    return Composer::getControlBlock();
 }
 
 // ---------------------------------------------------------------------------
@@ -120,61 +154,27 @@
 }
 
 SurfaceComposerClient::SurfaceComposerClient()
+    : mTransactionOpen(0), mPrebuiltLayerState(0), mStatus(NO_INIT)
+{
+}
+
+void SurfaceComposerClient::onFirstRef()
 {
     sp<ISurfaceComposer> sm(getComposerService());
-    if (sm == 0) {
-        _init(0, 0);
-        return;
+    if (sm != 0) {
+        sp<ISurfaceFlingerClient> conn = sm->createConnection();
+        if (conn != 0) {
+            mClient = conn;
+            Composer::addClient(this);
+            mPrebuiltLayerState = new layer_state_t;
+            mStatus = NO_ERROR;
+        }
     }
-
-    _init(sm, sm->createConnection());
-
-    if (mClient != 0) {
-        Mutex::Autolock _l(gLock);
-        VERBOSE("Adding client %p to map", this);
-        gActiveConnections.add(mClient->asBinder(), this);
-    }
-}
-
-SurfaceComposerClient::SurfaceComposerClient(
-        const sp<ISurfaceComposer>& sm, const sp<IBinder>& conn)
-{
-    _init(sm, interface_cast<ISurfaceFlingerClient>(conn));
-}
-
-
-status_t SurfaceComposerClient::linkToComposerDeath(
-        const sp<IBinder::DeathRecipient>& recipient,
-        void* cookie, uint32_t flags)
-{
-    sp<ISurfaceComposer> sm(getComposerService());
-    return sm->asBinder()->linkToDeath(recipient, cookie, flags);    
-}
-
-void SurfaceComposerClient::_init(
-        const sp<ISurfaceComposer>& sm, const sp<ISurfaceFlingerClient>& conn)
-{
-    VERBOSE("Creating client %p, conn %p", this, conn.get());
-
-    mPrebuiltLayerState = 0;
-    mTransactionOpen = 0;
-    mStatus = NO_ERROR;
-    mControl = 0;
-
-    mClient = conn;
-    if (mClient == 0) {
-        mStatus = NO_INIT;
-        return;
-    }
-
-    mControlMemory = mClient->getControlBlock();
-    mSignalServer = sm;
-    mControl = static_cast<SharedClient *>(mControlMemory->getBase());
 }
 
 SurfaceComposerClient::~SurfaceComposerClient()
 {
-    VERBOSE("Destroying client %p, conn %p", this, mClient.get());
+    delete mPrebuiltLayerState;
     dispose();
 }
 
@@ -188,69 +188,31 @@
     return (mClient != 0) ? mClient->asBinder() : 0;
 }
 
-sp<SurfaceComposerClient>
-SurfaceComposerClient::clientForConnection(const sp<IBinder>& conn)
+status_t SurfaceComposerClient::linkToComposerDeath(
+        const sp<IBinder::DeathRecipient>& recipient,
+        void* cookie, uint32_t flags)
 {
-    sp<SurfaceComposerClient> client;
-
-    { // scope for lock
-        Mutex::Autolock _l(gLock);
-        client = gActiveConnections.valueFor(conn).promote();
-    }
-
-    if (client == 0) {
-        // Need to make a new client.
-        sp<ISurfaceComposer> sm(getComposerService());
-        client = new SurfaceComposerClient(sm, conn);
-        if (client != 0 && client->initCheck() == NO_ERROR) {
-            Mutex::Autolock _l(gLock);
-            gActiveConnections.add(conn, client);
-            //LOGD("we have %d connections", gActiveConnections.size());
-        } else {
-            client.clear();
-        }
-    }
-
-    return client;
+    sp<ISurfaceComposer> sm(getComposerService());
+    return sm->asBinder()->linkToDeath(recipient, cookie, flags);
 }
 
 void SurfaceComposerClient::dispose()
 {
     // this can be called more than once.
-
-    sp<IMemoryHeap>             controlMemory;
-    sp<ISurfaceFlingerClient>   client;
-
-    {
-        Mutex::Autolock _lg(gLock);
-        Mutex::Autolock _lm(mLock);
-
-        mSignalServer = 0;
-
-        if (mClient != 0) {
-            client = mClient;
-            mClient.clear();
-
-            ssize_t i = gActiveConnections.indexOfKey(client->asBinder());
-            if (i >= 0 && gActiveConnections.valueAt(i) == this) {
-                VERBOSE("Removing client %p from map at %d", this, int(i));
-                gActiveConnections.removeItemsAt(i);
-            }
-        }
-
-        delete mPrebuiltLayerState;
-        mPrebuiltLayerState = 0;
-        controlMemory = mControlMemory;
-        mControlMemory.clear();
-        mControl = 0;
-        mStatus = NO_INIT;
+    sp<ISurfaceFlingerClient> client;
+    Mutex::Autolock _lm(mLock);
+    if (mClient != 0) {
+        Composer::removeClient(this);
+        client = mClient; // hold ref while lock is held
+        mClient.clear();
     }
+    mStatus = NO_INIT;
 }
 
 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 +230,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 +239,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 +248,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;
@@ -305,12 +267,6 @@
     return n;
 }
 
-
-void SurfaceComposerClient::signalServer()
-{
-    mSignalServer->signal();
-}
-
 sp<SurfaceControl> SurfaceComposerClient::createSurface(
         int pid,
         DisplayID display,
@@ -327,7 +283,6 @@
 
     return SurfaceComposerClient::createSurface(pid, name, display,
             w, h, format, flags);
-
 }
 
 sp<SurfaceControl> SurfaceComposerClient::createSurface(
@@ -345,7 +300,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);
             }
         }
@@ -373,56 +328,14 @@
 
 void SurfaceComposerClient::openGlobalTransaction()
 {
-    Mutex::Autolock _l(gLock);
-
-    if (gOpenTransactions.size()) {
-        LOGE("openGlobalTransaction() called more than once. skipping.");
-        return;
-    }
-
-    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).promote());
-        if (client != 0 && gOpenTransactions.indexOf(client) < 0) {
-            if (client->openTransaction() == NO_ERROR) {
-                if (gOpenTransactions.add(client) < 0) {
-                    // Ooops!
-                    LOGE(   "Unable to add a SurfaceComposerClient "
-                            "to the global transaction set (out of memory?)");
-                    client->closeTransaction();
-                    // let it go, it'll fail later when the user
-                    // tries to do something with the transaction
-                }
-            } else {
-                LOGE("openTransaction on client %p failed", client.get());
-                // let it go, it'll fail later when the user
-                // tries to do something with the transaction
-            }
-        }
-    }
+    Composer::openGlobalTransaction();
 }
 
 void SurfaceComposerClient::closeGlobalTransaction()
 {
-    gLock.lock();
-        SortedVector< sp<SurfaceComposerClient> > clients(gOpenTransactions);
-        gOpenTransactions.clear();
-    gLock.unlock();
-
-    const size_t N = clients.size();
-    VERBOSE("closeGlobalTransaction (%ld clients)", N);
-
-    sp<ISurfaceComposer> sm(getComposerService());
-    sm->openGlobalTransaction();
-    for (size_t i=0; i<N; i++) {
-        clients[i]->closeTransaction();
-    }
-    sm->closeGlobalTransaction();
-
+    Composer::closeGlobalTransaction();
 }
 
-
 status_t SurfaceComposerClient::freezeDisplay(DisplayID dpy, uint32_t flags)
 {
     sp<ISurfaceComposer> sm(getComposerService());
@@ -447,26 +360,16 @@
     if (mStatus != NO_ERROR)
         return mStatus;
     Mutex::Autolock _l(mLock);
-    VERBOSE(   "openTransaction (client %p, mTransactionOpen=%d)",
-            this, mTransactionOpen);
     mTransactionOpen++;
-    if (mPrebuiltLayerState == 0) {
-        mPrebuiltLayerState = new layer_state_t;
-    }
     return NO_ERROR;
 }
 
-
 status_t SurfaceComposerClient::closeTransaction()
 {
     if (mStatus != NO_ERROR)
         return mStatus;
 
     Mutex::Autolock _l(mLock);
-
-    VERBOSE(   "closeTransaction (client %p, mTransactionOpen=%d)",
-            this, mTransactionOpen);
-
     if (mTransactionOpen <= 0) {
         LOGE(   "closeTransaction (client %p, mTransactionOpen=%d) "
                 "called more times than openTransaction()",
@@ -488,7 +391,7 @@
     return NO_ERROR;
 }
 
-layer_state_t* SurfaceComposerClient::_get_state_l(SurfaceID index)
+layer_state_t* SurfaceComposerClient::get_state_l(SurfaceID index)
 {
     // API usage error, do nothing.
     if (mTransactionOpen<=0) {
@@ -498,7 +401,7 @@
     }
 
     // use mPrebuiltLayerState just to find out if we already have it
-    layer_state_t& dummy = *mPrebuiltLayerState;
+    layer_state_t& dummy(*mPrebuiltLayerState);
     dummy.surface = index;
     ssize_t i = mStates.indexOf(dummy);
     if (i < 0) {
@@ -508,49 +411,49 @@
     return mStates.editArray() + i;
 }
 
-layer_state_t* SurfaceComposerClient::_lockLayerState(SurfaceID id)
+layer_state_t* SurfaceComposerClient::lockLayerState(SurfaceID id)
 {
     layer_state_t* s;
     mLock.lock();
-    s = _get_state_l(id);
+    s = get_state_l(id);
     if (!s) mLock.unlock();
     return s;
 }
 
-void SurfaceComposerClient::_unlockLayerState()
+void SurfaceComposerClient::unlockLayerState()
 {
     mLock.unlock();
 }
 
 status_t SurfaceComposerClient::setPosition(SurfaceID id, int32_t x, int32_t y)
 {
-    layer_state_t* s = _lockLayerState(id);
+    layer_state_t* s = lockLayerState(id);
     if (!s) return BAD_INDEX;
     s->what |= ISurfaceComposer::ePositionChanged;
     s->x = x;
     s->y = y;
-    _unlockLayerState();
+    unlockLayerState();
     return NO_ERROR;
 }
 
 status_t SurfaceComposerClient::setSize(SurfaceID id, uint32_t w, uint32_t h)
 {
-    layer_state_t* s = _lockLayerState(id);
+    layer_state_t* s = lockLayerState(id);
     if (!s) return BAD_INDEX;
     s->what |= ISurfaceComposer::eSizeChanged;
     s->w = w;
     s->h = h;
-    _unlockLayerState();
+    unlockLayerState();
     return NO_ERROR;
 }
 
 status_t SurfaceComposerClient::setLayer(SurfaceID id, int32_t z)
 {
-    layer_state_t* s = _lockLayerState(id);
+    layer_state_t* s = lockLayerState(id);
     if (!s) return BAD_INDEX;
     s->what |= ISurfaceComposer::eLayerChanged;
     s->z = z;
-    _unlockLayerState();
+    unlockLayerState();
     return NO_ERROR;
 }
 
@@ -579,34 +482,34 @@
 status_t SurfaceComposerClient::setFlags(SurfaceID id,
         uint32_t flags, uint32_t mask)
 {
-    layer_state_t* s = _lockLayerState(id);
+    layer_state_t* s = lockLayerState(id);
     if (!s) return BAD_INDEX;
     s->what |= ISurfaceComposer::eVisibilityChanged;
     s->flags &= ~mask;
     s->flags |= (flags & mask);
     s->mask |= mask;
-    _unlockLayerState();
+    unlockLayerState();
     return NO_ERROR;
 }
 
 status_t SurfaceComposerClient::setTransparentRegionHint(
         SurfaceID id, const Region& transparentRegion)
 {
-    layer_state_t* s = _lockLayerState(id);
+    layer_state_t* s = lockLayerState(id);
     if (!s) return BAD_INDEX;
     s->what |= ISurfaceComposer::eTransparentRegionChanged;
     s->transparentRegion = transparentRegion;
-    _unlockLayerState();
+    unlockLayerState();
     return NO_ERROR;
 }
 
 status_t SurfaceComposerClient::setAlpha(SurfaceID id, float alpha)
 {
-    layer_state_t* s = _lockLayerState(id);
+    layer_state_t* s = lockLayerState(id);
     if (!s) return BAD_INDEX;
     s->what |= ISurfaceComposer::eAlphaChanged;
     s->alpha = alpha;
-    _unlockLayerState();
+    unlockLayerState();
     return NO_ERROR;
 }
 
@@ -615,7 +518,7 @@
         float dsdx, float dtdx,
         float dsdy, float dtdy )
 {
-    layer_state_t* s = _lockLayerState(id);
+    layer_state_t* s = lockLayerState(id);
     if (!s) return BAD_INDEX;
     s->what |= ISurfaceComposer::eMatrixChanged;
     layer_state_t::matrix22_t matrix;
@@ -624,19 +527,56 @@
     matrix.dsdy = dsdy;
     matrix.dtdy = dtdy;
     s->matrix = matrix;
-    _unlockLayerState();
+    unlockLayerState();
     return NO_ERROR;
 }
 
 status_t SurfaceComposerClient::setFreezeTint(SurfaceID id, uint32_t tint)
 {
-    layer_state_t* s = _lockLayerState(id);
+    layer_state_t* s = lockLayerState(id);
     if (!s) return BAD_INDEX;
     s->what |= ISurfaceComposer::eFreezeTintChanged;
     s->tint = tint;
-    _unlockLayerState();
+    unlockLayerState();
     return NO_ERROR;
 }
 
+// ----------------------------------------------------------------------------
+
+SurfaceClient::SurfaceClient(const sp<SurfaceComposerClient>& client)
+    : mStatus(NO_INIT), mControl(0)
+{
+    if (client != 0) {
+        sp<IBinder> conn = client->connection();
+        init(conn);
+    }
+}
+SurfaceClient::SurfaceClient(const sp<IBinder>& conn)
+    : mStatus(NO_INIT), mControl(0)
+{
+    init(conn);
+}
+void SurfaceClient::init(const sp<IBinder>& conn)
+{
+    mSignalServer = getComposerService();
+    sp<ISurfaceFlingerClient> sf(interface_cast<ISurfaceFlingerClient>(conn));
+    if (sf != 0) {
+        mConnection = conn;
+        mControlMemory = sf->getControlBlock();
+        mControl = static_cast<SharedClient *>(mControlMemory->getBase());
+        mStatus = NO_ERROR;
+    }
+}
+status_t SurfaceClient::initCheck() const {
+    return mStatus;
+}
+SharedClient* SurfaceClient::getSharedClient() const {
+    return mControl;
+}
+void SurfaceClient::signalServer() const {
+    mSignalServer->signal();
+}
+
+// ----------------------------------------------------------------------------
 }; // namespace android
 
diff --git a/libs/surfaceflinger_client/tests/Android.mk b/libs/surfaceflinger_client/tests/Android.mk
new file mode 100644
index 0000000..5053e7d
--- /dev/null
+++ b/libs/surfaceflinger_client/tests/Android.mk
@@ -0,0 +1 @@
+include $(call all-subdir-makefiles)
diff --git a/libs/surfaceflinger_client/tests/SharedBufferStack/Android.mk b/libs/surfaceflinger_client/tests/SharedBufferStack/Android.mk
new file mode 100644
index 0000000..d3dfe04
--- /dev/null
+++ b/libs/surfaceflinger_client/tests/SharedBufferStack/Android.mk
@@ -0,0 +1,17 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+	SharedBufferStackTest.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+	libcutils \
+	libutils \
+    libui \
+    libsurfaceflinger_client
+
+LOCAL_MODULE:= test-sharedbufferstack
+
+LOCAL_MODULE_TAGS := tests
+
+include $(BUILD_EXECUTABLE)
diff --git a/libs/surfaceflinger_client/tests/SharedBufferStack/SharedBufferStackTest.cpp b/libs/surfaceflinger_client/tests/SharedBufferStack/SharedBufferStackTest.cpp
new file mode 100644
index 0000000..f409f48
--- /dev/null
+++ b/libs/surfaceflinger_client/tests/SharedBufferStack/SharedBufferStackTest.cpp
@@ -0,0 +1,279 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#undef NDEBUG
+
+#include <assert.h>
+#include <cutils/memory.h>
+#include <cutils/log.h>
+#include <utils/Errors.h>
+#include <private/surfaceflinger/SharedBufferStack.h>
+
+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)
+{
+    printf("%s: ", prefix);
+    for (size_t i=0 ; i<num ; i++) {
+        printf("%d ", b[i]);
+    }
+    printf("\n");
+}
+
+// ----------------------------------------------------------------------------
+
+void test0(
+        SharedBufferServer& s,
+        SharedBufferClient& c,
+        size_t num,
+        int* list)
+{
+    status_t err;
+    int b[num], u[num], r[num];
+
+    for (size_t i=0 ; i<num ; i++) {
+        b[i] = c.dequeue();
+        assert(b[i]==list[i]);
+    }
+    log("DQ", b, num);
+
+    for (size_t i=0 ; i<num-1 ; i++) {
+        err = c.lock(b[i]);
+        assert(err==0);
+    }
+    log("LK", b, num-1);
+
+    for (size_t i=0 ; i<num-1 ; i++) {
+        err = c.queue(b[i]);
+        assert(err==0);
+    }
+    log(" Q", b, num-1);
+
+
+    for (size_t i=0 ; i<num-1 ; i++) {
+        r[i] = s.retireAndLock();
+        assert(r[i]==list[i]);
+        err = s.unlock(r[i]);
+        assert(err == 0);
+    }
+    log("RT", r, num-1);
+
+    err = c.lock(b[num-1]);
+    assert(err == 0);
+    log("LK", b+num-1, 1);
+
+    err = c.queue(b[num-1]);
+    assert(err == 0);
+    log(" Q", b+num-1, 1);
+
+    r[num-1] = s.retireAndLock();
+    assert(r[num-1]==list[num-1]);
+    err = s.unlock(r[num-1]);
+    assert(err == 0);
+    log("RT", r+num-1, 1);
+
+    // ------------------------------------
+    printf("\n");
+
+    for (size_t i=0 ; i<num ; i++) {
+        b[i] = c.dequeue();
+        assert(b[i]==list[i]);
+    }
+    log("DQ", b, num);
+
+    for (size_t i=0 ; i<num-1 ; i++) {
+        err = c.lock(b[i]);
+        assert(err==0);
+    }
+    log("LK", b, num-1);
+
+    for (size_t i=0 ; i<num-1 ; i++) {
+        u[i] = b[num-2-i];
+    }
+    u[num-1] = b[num-1];
+
+    for (size_t i=0 ; i<num-1 ; i++) {
+        err = c.queue(u[i]);
+        assert(err==0);
+    }
+    log(" Q", u, num-1);
+
+    for (size_t i=0 ; i<num-1 ; i++) {
+        r[i] = s.retireAndLock();
+        assert(r[i]==u[i]);
+        err = s.unlock(r[i]);
+        assert(err == 0);
+    }
+    log("RT", r, num-1);
+
+    err = c.lock(b[num-1]);
+    assert(err == 0);
+    log("LK", b+num-1, 1);
+
+    err = c.queue(b[num-1]);
+    assert(err == 0);
+    log(" Q", b+num-1, 1);
+
+    r[num-1] = s.retireAndLock();
+    assert(r[num-1]==list[num-1]);
+    err = s.unlock(r[num-1]);
+    assert(err == 0);
+    log("RT", r+num-1, 1);
+
+    // ------------------------------------
+    printf("\n");
+
+    for (size_t i=0 ; i<num ; i++) {
+        b[i] = c.dequeue();
+        assert(b[i]==u[i]);
+    }
+    log("DQ", b, num);
+
+    for (size_t i=0 ; i<num-1 ; i++) {
+        err = c.lock(b[i]);
+        assert(err==0);
+    }
+    log("LK", b, num-1);
+
+    for (size_t i=0 ; i<num-1 ; i++) {
+        err = c.queue(b[i]);
+        assert(err==0);
+    }
+    log(" Q", b, num-1);
+
+    for (size_t i=0 ; i<num-1 ; i++) {
+        r[i] = s.retireAndLock();
+        assert(r[i]==u[i]);
+        err = s.unlock(r[i]);
+        assert(err == 0);
+    }
+    log("RT", r, num-1);
+
+    err = c.lock(u[num-1]);
+    assert(err == 0);
+    log("LK", u+num-1, 1);
+
+    err = c.queue(u[num-1]);
+    assert(err == 0);
+    log(" Q", u+num-1, 1);
+
+    r[num-1] = s.retireAndLock();
+    assert(r[num-1]==u[num-1]);
+    err = s.unlock(r[num-1]);
+    assert(err == 0);
+    log("RT", r+num-1, 1);
+
+    // ------------------------------------
+    printf("\n");
+
+    b[0] = c.dequeue();
+    assert(b[0]==u[0]);
+    log("DQ", b, 1);
+
+    c.undoDequeue(b[0]);
+    assert(err == 0);
+    log("UDQ", b, 1);
+
+    // ------------------------------------
+    printf("\n");
+
+    for (size_t i=0 ; i<num ; i++) {
+        b[i] = c.dequeue();
+        assert(b[i]==u[i]);
+    }
+    log("DQ", b, num);
+
+    for (size_t i=0 ; i<num-1 ; i++) {
+        err = c.lock(b[i]);
+        assert(err==0);
+    }
+    log("LK", b, num-1);
+
+    for (size_t i=0 ; i<num-1 ; i++) {
+        err = c.queue(b[i]);
+        assert(err==0);
+    }
+    log(" Q", b, num-1);
+
+    for (size_t i=0 ; i<num-1 ; i++) {
+        r[i] = s.retireAndLock();
+        assert(r[i]==u[i]);
+        err = s.unlock(r[i]);
+        assert(err == 0);
+    }
+    log("RT", r, num-1);
+
+    err = c.lock(u[num-1]);
+    assert(err == 0);
+    log("LK", u+num-1, 1);
+
+    err = c.queue(u[num-1]);
+    assert(err == 0);
+    log(" Q", u+num-1, 1);
+
+    r[num-1] = s.retireAndLock();
+    assert(r[num-1]==u[num-1]);
+    err = s.unlock(r[num-1]);
+    assert(err == 0);
+    log("RT", r+num-1, 1);
+    printf("\n");
+}
diff --git a/libs/ui/GraphicBufferAllocator.cpp b/libs/ui/GraphicBufferAllocator.cpp
index 6ae7e74..d51664d 100644
--- a/libs/ui/GraphicBufferAllocator.cpp
+++ b/libs/ui/GraphicBufferAllocator.cpp
@@ -15,6 +15,8 @@
 ** limitations under the License.
 */
 
+#define LOG_TAG "GraphicBufferAllocator"
+
 #include <cutils/log.h>
 
 #include <utils/Singleton.h>
@@ -61,9 +63,9 @@
     const size_t c = list.size();
     for (size_t i=0 ; i<c ; i++) {
         const alloc_rec_t& rec(list.valueAt(i));
-        snprintf(buffer, SIZE, "%10p: %7.2f KiB | %4u x %4u | %2d | 0x%08x\n",
+        snprintf(buffer, SIZE, "%10p: %7.2f KiB | %4u (%4u) x %4u | %2d | 0x%08x\n",
             list.keyAt(i), rec.size/1024.0f, 
-            rec.w, rec.h, rec.format, rec.usage);
+            rec.w, rec.s, rec.h, rec.format, rec.usage);
         result.append(buffer);
         total += rec.size;
     }
@@ -71,16 +73,13 @@
     result.append(buffer);
 }
 
-static inline uint32_t clamp(uint32_t c) {
-    return c>0 ? c : 1;
-}
-
 status_t GraphicBufferAllocator::alloc(uint32_t w, uint32_t h, PixelFormat format,
         int usage, buffer_handle_t* handle, int32_t* stride)
 {
-    // make sure to not allocate a 0 x 0 buffer
-    w = clamp(w);
-    h = clamp(h);
+    // make sure to not allocate a N x 0 or 0 x N buffer, since this is
+    // allowed from an API stand-point allocate a 1x1 buffer instead.
+    if (!w || !h)
+        w = h = 1;
 
     // we have a h/w allocator and h/w buffer is requested
     status_t err; 
@@ -100,9 +99,9 @@
         alloc_rec_t rec;
         rec.w = w;
         rec.h = h;
+        rec.s = *stride;
         rec.format = format;
         rec.usage = usage;
-        rec.vaddr = 0;
         rec.size = h * stride[0] * bytesPerPixel(format);
         list.add(*handle, rec);
     } else {
diff --git a/libs/utils/AssetManager.cpp b/libs/utils/AssetManager.cpp
index 5a05e6a..60a0d82 100644
--- a/libs/utils/AssetManager.cpp
+++ b/libs/utils/AssetManager.cpp
@@ -824,7 +824,7 @@
 
     // TODO: look for previously-created shared memory slice?
     int method;
-    long uncompressedLen;
+    size_t uncompressedLen;
 
     //printf("USING Zip '%s'\n", pEntry->getFileName());
 
diff --git a/libs/utils/ResourceTypes.cpp b/libs/utils/ResourceTypes.cpp
index 7e0f881..a1401ad 100644
--- a/libs/utils/ResourceTypes.cpp
+++ b/libs/utils/ResourceTypes.cpp
@@ -4178,6 +4178,9 @@
                             case ResTable_config::SCREENSIZE_LARGE:
                                 printf(" (large)");
                                 break;
+                            case ResTable_config::SCREENSIZE_XLARGE:
+                                printf(" (xlarge)");
+                                break;
                         }
                         printf(" lng=%d",
                                 type->config.screenLayout&ResTable_config::MASK_SCREENLONG);
diff --git a/libs/utils/ZipFileCRO.cpp b/libs/utils/ZipFileCRO.cpp
index 45f6c8b..16b219c 100644
--- a/libs/utils/ZipFileCRO.cpp
+++ b/libs/utils/ZipFileCRO.cpp
@@ -39,8 +39,8 @@
 }
 
 bool ZipFileCRO_getEntryInfo(ZipFileCRO zipToken, ZipEntryRO entryToken,
-        int* pMethod, long* pUncompLen,
-        long* pCompLen, off_t* pOffset, long* pModWhen, long* pCrc32) {
+        int* pMethod, size_t* pUncompLen,
+        size_t* pCompLen, off_t* pOffset, long* pModWhen, long* pCrc32) {
     ZipFileRO* zip = (ZipFileRO*)zipToken;
     ZipEntryRO entry = (ZipEntryRO)entryToken;
     return zip->getEntryInfo(entry, pMethod, pUncompLen, pCompLen, pOffset,
diff --git a/libs/utils/ZipFileRO.cpp b/libs/utils/ZipFileRO.cpp
index 6c701dd..28dc512 100644
--- a/libs/utils/ZipFileRO.cpp
+++ b/libs/utils/ZipFileRO.cpp
@@ -29,6 +29,22 @@
 #include <fcntl.h>
 #include <errno.h>
 #include <assert.h>
+#include <unistd.h>
+
+/*
+ * TEMP_FAILURE_RETRY is defined by some, but not all, versions of
+ * <unistd.h>. (Alas, it is not as standard as we'd hoped!) So, if it's
+ * not already defined, then define it here.
+ */
+#ifndef TEMP_FAILURE_RETRY
+/* Used to retry syscalls that can return EINTR. */
+#define TEMP_FAILURE_RETRY(exp) ({         \
+    typeof (exp) _rc;                      \
+    do {                                   \
+        _rc = (exp);                       \
+    } while (_rc == -1 && errno == EINTR); \
+    _rc; })
+#endif
 
 using namespace android;
 
@@ -38,6 +54,7 @@
 #define kEOCDSignature      0x06054b50
 #define kEOCDLen            22
 #define kEOCDNumEntries     8               // offset to #of entries in file
+#define kEOCDSize           12              // size of the central directory
 #define kEOCDFileOffset     16              // offset to central directory
 
 #define kMaxCommentLen      65535           // longest possible in ushort
@@ -90,9 +107,8 @@
 status_t ZipFileRO::open(const char* zipFileName)
 {
     int fd = -1;
-    off_t length;
 
-    assert(mFileMap == NULL);
+    assert(mDirectoryMap == NULL);
 
     /*
      * Open and map the specified file.
@@ -103,172 +119,240 @@
         return NAME_NOT_FOUND;
     }
 
-    length = lseek(fd, 0, SEEK_END);
-    if (length < 0) {
+    mFileLength = lseek(fd, 0, SEEK_END);
+    if (mFileLength < kEOCDLen) {
         close(fd);
         return UNKNOWN_ERROR;
     }
 
-    mFileMap = new FileMap();
-    if (mFileMap == NULL) {
-        close(fd);
-        return NO_MEMORY;
+    if (mFileName != NULL) {
+        free(mFileName);
     }
-    if (!mFileMap->create(zipFileName, fd, 0, length, true)) {
-        LOGW("Unable to map '%s': %s\n", zipFileName, strerror(errno));
-        close(fd);
-        return UNKNOWN_ERROR;
-    }
+    mFileName = strdup(zipFileName);
 
     mFd = fd;
 
     /*
-     * Got it mapped, verify it and create data structures for fast access.
+     * Find the Central Directory and store its size and number of entries.
+     */
+    if (!mapCentralDirectory()) {
+        goto bail;
+    }
+
+    /*
+     * Verify Central Directory and create data structures for fast access.
      */
     if (!parseZipArchive()) {
-        mFileMap->release();
-        mFileMap = NULL;
-        return UNKNOWN_ERROR;
+        goto bail;
     }
 
     return OK;
+
+bail:
+    free(mFileName);
+    mFileName = NULL;
+    close(fd);
+    return UNKNOWN_ERROR;
 }
 
 /*
  * Parse the Zip archive, verifying its contents and initializing internal
  * data structures.
  */
+bool ZipFileRO::mapCentralDirectory(void)
+{
+    size_t readAmount = kMaxEOCDSearch;
+    if (readAmount > (size_t) mFileLength)
+        readAmount = mFileLength;
+
+    unsigned char* scanBuf = (unsigned char*) malloc(readAmount);
+    if (scanBuf == NULL) {
+        LOGW("couldn't allocate scanBuf: %s", strerror(errno));
+        free(scanBuf);
+        return false;
+    }
+
+    /*
+     * Make sure this is a Zip archive.
+     */
+    if (lseek(mFd, 0, SEEK_SET) != 0) {
+        LOGW("seek to start failed: %s", strerror(errno));
+        free(scanBuf);
+        return false;
+    }
+
+    ssize_t actual = TEMP_FAILURE_RETRY(read(mFd, scanBuf, sizeof(int32_t)));
+    if (actual != (ssize_t) sizeof(int32_t)) {
+        LOGI("couldn't read first signature from zip archive: %s", strerror(errno));
+        free(scanBuf);
+        return false;
+    }
+
+    {
+        unsigned int header = get4LE(scanBuf);
+        if (header == kEOCDSignature) {
+            LOGI("Found Zip archive, but it looks empty\n");
+            free(scanBuf);
+            return false;
+        } else if (header != kLFHSignature) {
+            LOGV("Not a Zip archive (found 0x%08x)\n", val);
+            free(scanBuf);
+            return false;
+        }
+    }
+
+    /*
+     * Perform the traditional EOCD snipe hunt.
+     *
+     * We're searching for the End of Central Directory magic number,
+     * which appears at the start of the EOCD block.  It's followed by
+     * 18 bytes of EOCD stuff and up to 64KB of archive comment.  We
+     * need to read the last part of the file into a buffer, dig through
+     * it to find the magic number, parse some values out, and use those
+     * to determine the extent of the CD.
+     *
+     * We start by pulling in the last part of the file.
+     */
+    off_t searchStart = mFileLength - readAmount;
+
+    if (lseek(mFd, searchStart, SEEK_SET) != searchStart) {
+        LOGW("seek %ld failed: %s\n",  (long) searchStart, strerror(errno));
+        free(scanBuf);
+        return false;
+    }
+    actual = TEMP_FAILURE_RETRY(read(mFd, scanBuf, readAmount));
+    if (actual != (ssize_t) readAmount) {
+        LOGW("Zip: read %zd failed: %s\n", readAmount, strerror(errno));
+        free(scanBuf);
+        return false;
+    }
+
+    /*
+     * Scan backward for the EOCD magic.  In an archive without a trailing
+     * comment, we'll find it on the first try.  (We may want to consider
+     * doing an initial minimal read; if we don't find it, retry with a
+     * second read as above.)
+     */
+    int i;
+    for (i = readAmount - kEOCDLen; i >= 0; i--) {
+        if (scanBuf[i] == 0x50 && get4LE(&scanBuf[i]) == kEOCDSignature) {
+            LOGV("+++ Found EOCD at buf+%d\n", i);
+            break;
+        }
+    }
+    if (i < 0) {
+        LOGD("Zip: EOCD not found, %s is not zip\n", mFileName);
+        free(scanBuf);
+        return false;
+    }
+
+    off_t eocdOffset = searchStart + i;
+    const unsigned char* eocdPtr = scanBuf + i;
+
+    assert(eocdOffset < mFileLength);
+
+    /*
+     * Grab the CD offset and size, and the number of entries in the
+     * archive.  Verify that they look reasonable.
+     */
+    unsigned int numEntries = get2LE(eocdPtr + kEOCDNumEntries);
+    unsigned int dirSize = get4LE(eocdPtr + kEOCDSize);
+    unsigned int dirOffset = get4LE(eocdPtr + kEOCDFileOffset);
+
+    if ((long long) dirOffset + (long long) dirSize > (long long) eocdOffset) {
+        LOGW("bad offsets (dir %ld, size %u, eocd %ld)\n",
+            (long) dirOffset, dirSize, (long) eocdOffset);
+        free(scanBuf);
+        return false;
+    }
+    if (numEntries == 0) {
+        LOGW("empty archive?\n");
+        free(scanBuf);
+        return false;
+    }
+
+    LOGV("+++ numEntries=%d dirSize=%d dirOffset=%d\n",
+        numEntries, dirSize, dirOffset);
+
+    mDirectoryMap = new FileMap();
+    if (mDirectoryMap == NULL) {
+        LOGW("Unable to create directory map: %s", strerror(errno));
+        free(scanBuf);
+        return false;
+    }
+
+    if (!mDirectoryMap->create(mFileName, mFd, dirOffset, dirSize, true)) {
+        LOGW("Unable to map '%s' (%zd to %zd): %s\n", mFileName,
+                dirOffset, dirOffset + dirSize, strerror(errno));
+        free(scanBuf);
+        return false;
+    }
+
+    mNumEntries = numEntries;
+    mDirectoryOffset = dirOffset;
+
+    return true;
+}
+
 bool ZipFileRO::parseZipArchive(void)
 {
-#define CHECK_OFFSET(_off) {                                                \
-        if ((unsigned int) (_off) >= maxOffset) {                           \
-            LOGE("ERROR: bad offset %u (max %d): %s\n",                     \
-                (unsigned int) (_off), maxOffset, #_off);                   \
-            goto bail;                                                      \
-        }                                                                   \
-    }
-    const unsigned char* basePtr = (const unsigned char*)mFileMap->getDataPtr();
-    const unsigned char* ptr;
-    size_t length = mFileMap->getDataLength();
     bool result = false;
-    unsigned int i, numEntries, cdOffset;
-    unsigned int val;
-
-    /*
-     * The first 4 bytes of the file will either be the local header
-     * signature for the first file (kLFHSignature) or, if the archive doesn't
-     * have any files in it, the end-of-central-directory signature
-     * (kEOCDSignature).
-     */
-    val = get4LE(basePtr);
-    if (val == kEOCDSignature) {
-        LOGI("Found Zip archive, but it looks empty\n");
-        goto bail;
-    } else if (val != kLFHSignature) {
-        LOGV("Not a Zip archive (found 0x%08x)\n", val);
-        goto bail;
-    }
-
-    /*
-     * Find the EOCD.  We'll find it immediately unless they have a file
-     * comment.
-     */
-    ptr = basePtr + length - kEOCDLen;
-
-    while (ptr >= basePtr) {
-        if (*ptr == (kEOCDSignature & 0xff) && get4LE(ptr) == kEOCDSignature)
-            break;
-        ptr--;
-    }
-    if (ptr < basePtr) {
-        LOGI("Could not find end-of-central-directory in Zip\n");
-        goto bail;
-    }
-
-    /*
-     * There are two interesting items in the EOCD block: the number of
-     * entries in the file, and the file offset of the start of the
-     * central directory.
-     *
-     * (There's actually a count of the #of entries in this file, and for
-     * all files which comprise a spanned archive, but for our purposes
-     * we're only interested in the current file.  Besides, we expect the
-     * two to be equivalent for our stuff.)
-     */
-    numEntries = get2LE(ptr + kEOCDNumEntries);
-    cdOffset = get4LE(ptr + kEOCDFileOffset);
-
-    /* valid offsets are [0,EOCD] */
-    unsigned int maxOffset;
-    maxOffset = (ptr - basePtr) +1;
-
-    LOGV("+++ numEntries=%d cdOffset=%d\n", numEntries, cdOffset);
-    if (numEntries == 0 || cdOffset >= length) {
-        LOGW("Invalid entries=%d offset=%d (len=%zd)\n",
-            numEntries, cdOffset, length);
-        goto bail;
-    }
+    const unsigned char* cdPtr = (const unsigned char*) mDirectoryMap->getDataPtr();
+    size_t cdLength = mDirectoryMap->getDataLength();
+    int numEntries = mNumEntries;
 
     /*
      * Create hash table.  We have a minimum 75% load factor, possibly as
      * low as 50% after we round off to a power of 2.
      */
-    mNumEntries = numEntries;
-    mHashTableSize = roundUpPower2(1 + ((numEntries * 4) / 3));
-    mHashTable = (HashEntry*) calloc(1, sizeof(HashEntry) * mHashTableSize);
+    mHashTableSize = roundUpPower2(1 + (numEntries * 4) / 3);
+    mHashTable = (HashEntry*) calloc(mHashTableSize, sizeof(HashEntry));
 
     /*
      * Walk through the central directory, adding entries to the hash
      * table.
      */
-    ptr = basePtr + cdOffset;
-    for (i = 0; i < numEntries; i++) {
-        unsigned int fileNameLen, extraLen, commentLen, localHdrOffset;
-        const unsigned char* localHdr;
-        unsigned int hash;
-
+    const unsigned char* ptr = cdPtr;
+    for (int i = 0; i < numEntries; i++) {
         if (get4LE(ptr) != kCDESignature) {
             LOGW("Missed a central dir sig (at %d)\n", i);
             goto bail;
         }
-        if (ptr + kCDELen > basePtr + length) {
+        if (ptr + kCDELen > cdPtr + cdLength) {
             LOGW("Ran off the end (at %d)\n", i);
             goto bail;
         }
 
-        localHdrOffset = get4LE(ptr + kCDELocalOffset);
-        CHECK_OFFSET(localHdrOffset);
+        long localHdrOffset = (long) get4LE(ptr + kCDELocalOffset);
+        if (localHdrOffset >= mDirectoryOffset) {
+            LOGW("bad LFH offset %ld at entry %d\n", localHdrOffset, i);
+            goto bail;
+        }
+
+        unsigned int fileNameLen, extraLen, commentLen, hash;
+
         fileNameLen = get2LE(ptr + kCDENameLen);
         extraLen = get2LE(ptr + kCDEExtraLen);
         commentLen = get2LE(ptr + kCDECommentLen);
 
-        //LOGV("+++ %d: localHdr=%d fnl=%d el=%d cl=%d\n",
-        //    i, localHdrOffset, fileNameLen, extraLen, commentLen);
-        //LOGV(" '%.*s'\n", fileNameLen, ptr + kCDELen);
-
         /* add the CDE filename to the hash table */
         hash = computeHash((const char*)ptr + kCDELen, fileNameLen);
         addToHash((const char*)ptr + kCDELen, fileNameLen, hash);
 
-        localHdr = basePtr + localHdrOffset;
-        if (get4LE(localHdr) != kLFHSignature) {
-            LOGW("Bad offset to local header: %d (at %d)\n",
-                localHdrOffset, i);
+        ptr += kCDELen + fileNameLen + extraLen + commentLen;
+        if ((size_t)(ptr - cdPtr) > cdLength) {
+            LOGW("bad CD advance (%d vs %zd) at entry %d\n",
+                (int) (ptr - cdPtr), cdLength, i);
             goto bail;
         }
-
-        ptr += kCDELen + fileNameLen + extraLen + commentLen;
-        CHECK_OFFSET(ptr - basePtr);
     }
-
+    LOGV("+++ zip good scan %d entries\n", numEntries);
     result = true;
 
 bail:
     return result;
-#undef CHECK_OFFSET
 }
 
-
 /*
  * Simple string hash function for non-null-terminated strings.
  */
@@ -315,7 +399,7 @@
             memcmp(mHashTable[ent].name, fileName, nameLen) == 0)
         {
             /* match */
-            return (ZipEntryRO) (ent + kZipEntryAdj);
+            return (ZipEntryRO)(long)(ent + kZipEntryAdj);
         }
 
         ent = (ent + 1) & (mHashTableSize-1);
@@ -354,20 +438,24 @@
  * Returns "false" if the offsets to the fields or the contents of the fields
  * appear to be bogus.
  */
-bool ZipFileRO::getEntryInfo(ZipEntryRO entry, int* pMethod, long* pUncompLen,
-    long* pCompLen, off_t* pOffset, long* pModWhen, long* pCrc32) const
+bool ZipFileRO::getEntryInfo(ZipEntryRO entry, int* pMethod, size_t* pUncompLen,
+    size_t* pCompLen, off_t* pOffset, long* pModWhen, long* pCrc32) const
 {
-    int ent = entryToIndex(entry);
+    bool ret = false;
+
+    const int ent = entryToIndex(entry);
     if (ent < 0)
         return false;
 
+    HashEntry hashEntry = mHashTable[ent];
+
     /*
      * Recover the start of the central directory entry from the filename
-     * pointer.
+     * pointer.  The filename is the first entry past the fixed-size data,
+     * so we can just subtract back from that.
      */
-    const unsigned char* basePtr = (const unsigned char*)mFileMap->getDataPtr();
-    const unsigned char* ptr = (const unsigned char*) mHashTable[ent].name;
-    size_t zipLength = mFileMap->getDataLength();
+    const unsigned char* ptr = (const unsigned char*) hashEntry.name;
+    off_t cdOffset = mDirectoryOffset;
 
     ptr -= kCDELen;
 
@@ -380,48 +468,78 @@
     if (pCrc32 != NULL)
         *pCrc32 = get4LE(ptr + kCDECRC);
 
+    size_t compLen = get4LE(ptr + kCDECompLen);
+    if (pCompLen != NULL)
+        *pCompLen = compLen;
+    size_t uncompLen = get4LE(ptr + kCDEUncompLen);
+    if (pUncompLen != NULL)
+        *pUncompLen = uncompLen;
+
     /*
-     * We need to make sure that the lengths are not so large that somebody
-     * trying to map the compressed or uncompressed data runs off the end
-     * of the mapped region.
+     * If requested, determine the offset of the start of the data.  All we
+     * have is the offset to the Local File Header, which is variable size,
+     * so we have to read the contents of the struct to figure out where
+     * the actual data starts.
+     *
+     * We also need to make sure that the lengths are not so large that
+     * somebody trying to map the compressed or uncompressed data runs
+     * off the end of the mapped region.
+     *
+     * Note we don't verify compLen/uncompLen if they don't request the
+     * dataOffset, because dataOffset is expensive to determine.  However,
+     * if they don't have the file offset, they're not likely to be doing
+     * anything with the contents.
      */
-    unsigned long localHdrOffset = get4LE(ptr + kCDELocalOffset);
-    if (localHdrOffset + kLFHLen >= zipLength) {
-        LOGE("ERROR: bad local hdr offset in zip\n");
-        return false;
-    }
-    const unsigned char* localHdr = basePtr + localHdrOffset;
-    off_t dataOffset = localHdrOffset + kLFHLen
-        + get2LE(localHdr + kLFHNameLen) + get2LE(localHdr + kLFHExtraLen);
-    if ((unsigned long) dataOffset >= zipLength) {
-        LOGE("ERROR: bad data offset in zip\n");
-        return false;
-    }
-
-    if (pCompLen != NULL) {
-        *pCompLen = get4LE(ptr + kCDECompLen);
-        if (*pCompLen < 0 || (size_t)(dataOffset + *pCompLen) >= zipLength) {
-            LOGE("ERROR: bad compressed length in zip\n");
-            return false;
-        }
-    }
-    if (pUncompLen != NULL) {
-        *pUncompLen = get4LE(ptr + kCDEUncompLen);
-        if (*pUncompLen < 0) {
-            LOGE("ERROR: negative uncompressed length in zip\n");
-            return false;
-        }
-        if (method == kCompressStored &&
-            (size_t)(dataOffset + *pUncompLen) >= zipLength)
-        {
-            LOGE("ERROR: bad uncompressed length in zip\n");
-            return false;
-        }
-    }
-
     if (pOffset != NULL) {
+        long localHdrOffset = get4LE(ptr + kCDELocalOffset);
+        if (localHdrOffset + kLFHLen >= cdOffset) {
+            LOGE("ERROR: bad local hdr offset in zip\n");
+            return false;
+        }
+
+        unsigned char lfhBuf[kLFHLen];
+        if (lseek(mFd, localHdrOffset, SEEK_SET) != localHdrOffset) {
+            LOGW("failed seeking to lfh at offset %ld\n", localHdrOffset);
+            return false;
+        }
+        ssize_t actual =
+            TEMP_FAILURE_RETRY(read(mFd, lfhBuf, sizeof(lfhBuf)));
+        if (actual != sizeof(lfhBuf)) {
+            LOGW("failed reading lfh from offset %ld\n", localHdrOffset);
+            return false;
+        }
+
+        if (get4LE(lfhBuf) != kLFHSignature) {
+            LOGW("didn't find signature at start of lfh, offset=%ld\n",
+                localHdrOffset);
+            return false;
+        }
+
+        off_t dataOffset = localHdrOffset + kLFHLen
+            + get2LE(lfhBuf + kLFHNameLen) + get2LE(lfhBuf + kLFHExtraLen);
+        if (dataOffset >= cdOffset) {
+            LOGW("bad data offset %ld in zip\n", (long) dataOffset);
+            return false;
+        }
+
+        /* check lengths */
+        if ((off_t)(dataOffset + compLen) > cdOffset) {
+            LOGW("bad compressed length in zip (%ld + %zd > %ld)\n",
+                (long) dataOffset, compLen, (long) cdOffset);
+            return false;
+        }
+
+        if (method == kCompressStored &&
+            (off_t)(dataOffset + uncompLen) > cdOffset)
+        {
+            LOGE("ERROR: bad uncompressed length in zip (%ld + %zd > %ld)\n",
+                (long) dataOffset, uncompLen, (long) cdOffset);
+            return false;
+        }
+
         *pOffset = dataOffset;
     }
+
     return true;
 }
 
@@ -457,14 +575,14 @@
      */
 
     FileMap* newMap;
-    long compLen;
+    size_t compLen;
     off_t offset;
 
     if (!getEntryInfo(entry, NULL, NULL, &compLen, &offset, NULL, NULL))
         return NULL;
 
     newMap = new FileMap();
-    if (!newMap->create(mFileMap->getFileName(), mFd, offset, compLen, true)) {
+    if (!newMap->create(mFileName, mFd, offset, compLen, true)) {
         newMap->release();
         return NULL;
     }
@@ -480,19 +598,26 @@
  */
 bool ZipFileRO::uncompressEntry(ZipEntryRO entry, void* buffer) const
 {
-    const int kSequentialMin = 32768;
+    const size_t kSequentialMin = 32768;
     bool result = false;
     int ent = entryToIndex(entry);
     if (ent < 0)
         return -1;
 
-    const unsigned char* basePtr = (const unsigned char*)mFileMap->getDataPtr();
     int method;
-    long uncompLen, compLen;
+    size_t uncompLen, compLen;
     off_t offset;
+    const unsigned char* ptr;
 
     getEntryInfo(entry, &method, &uncompLen, &compLen, &offset, NULL, NULL);
 
+    FileMap* file = createEntryFileMap(entry);
+    if (file == NULL) {
+        goto bail;
+    }
+
+    ptr = (const unsigned char*) file->getDataPtr();
+
     /*
      * Experiment with madvise hint.  When we want to uncompress a file,
      * we pull some stuff out of the central dir entry and then hit a
@@ -507,17 +632,17 @@
      * pair of system calls are negated by a reduction in page faults.
      */
     if (compLen > kSequentialMin)
-        mFileMap->advise(FileMap::SEQUENTIAL);
+        file->advise(FileMap::SEQUENTIAL);
 
     if (method == kCompressStored) {
-        memcpy(buffer, basePtr + offset, uncompLen);
+        memcpy(buffer, ptr, uncompLen);
     } else {
-        if (!inflateBuffer(buffer, basePtr + offset, uncompLen, compLen))
+        if (!inflateBuffer(buffer, ptr, uncompLen, compLen))
             goto bail;
     }
 
     if (compLen > kSequentialMin)
-        mFileMap->advise(FileMap::NORMAL);
+        file->advise(FileMap::NORMAL);
 
     result = true;
 
@@ -537,29 +662,34 @@
     if (ent < 0)
         return -1;
 
-    const unsigned char* basePtr = (const unsigned char*)mFileMap->getDataPtr();
     int method;
-    long uncompLen, compLen;
+    size_t uncompLen, compLen;
     off_t offset;
+    const unsigned char* ptr;
 
     getEntryInfo(entry, &method, &uncompLen, &compLen, &offset, NULL, NULL);
 
-    if (method == kCompressStored) {
-        ssize_t actual;
+    const FileMap* file = createEntryFileMap(entry);
+    if (file == NULL) {
+        goto bail;
+    }
 
-        actual = write(fd, basePtr + offset, uncompLen);
+    ptr = (const unsigned char*) file->getDataPtr();
+
+    if (method == kCompressStored) {
+        ssize_t actual = write(fd, ptr, uncompLen);
         if (actual < 0) {
             LOGE("Write failed: %s\n", strerror(errno));
             goto bail;
-        } else if (actual != uncompLen) {
-            LOGE("Partial write during uncompress (%d of %ld)\n",
-                (int)actual, uncompLen);
+        } else if ((size_t) actual != uncompLen) {
+            LOGE("Partial write during uncompress (%zd of %zd)\n",
+                actual, uncompLen);
             goto bail;
         } else {
             LOGI("+++ successful write\n");
         }
     } else {
-        if (!inflateBuffer(fd, basePtr+offset, uncompLen, compLen))
+        if (!inflateBuffer(fd, ptr, uncompLen, compLen))
             goto bail;
     }
 
@@ -573,7 +703,7 @@
  * Uncompress "deflate" data from one buffer to another.
  */
 /*static*/ bool ZipFileRO::inflateBuffer(void* outBuf, const void* inBuf,
-    long uncompLen, long compLen)
+    size_t uncompLen, size_t compLen)
 {
     bool result = false;
     z_stream zstream;
@@ -582,7 +712,7 @@
     /*
      * Initialize the zlib stream struct.
      */
-	memset(&zstream, 0, sizeof(zstream));
+    memset(&zstream, 0, sizeof(zstream));
     zstream.zalloc = Z_NULL;
     zstream.zfree = Z_NULL;
     zstream.opaque = Z_NULL;
@@ -592,10 +722,10 @@
     zstream.avail_out = uncompLen;
     zstream.data_type = Z_UNKNOWN;
 
-	/*
-	 * Use the undocumented "negative window bits" feature to tell zlib
-	 * that there's no zlib header waiting for it.
-	 */
+    /*
+     * Use the undocumented "negative window bits" feature to tell zlib
+     * that there's no zlib header waiting for it.
+     */
     zerr = inflateInit2(&zstream, -MAX_WBITS);
     if (zerr != Z_OK) {
         if (zerr == Z_VERSION_ERROR) {
@@ -619,8 +749,8 @@
     }
 
     /* paranoia */
-    if ((long) zstream.total_out != uncompLen) {
-        LOGW("Size mismatch on inflated file (%ld vs %ld)\n",
+    if (zstream.total_out != uncompLen) {
+        LOGW("Size mismatch on inflated file (%ld vs %zd)\n",
             zstream.total_out, uncompLen);
         goto z_bail;
     }
@@ -638,10 +768,10 @@
  * Uncompress "deflate" data from one buffer to an open file descriptor.
  */
 /*static*/ bool ZipFileRO::inflateBuffer(int fd, const void* inBuf,
-    long uncompLen, long compLen)
+    size_t uncompLen, size_t compLen)
 {
     bool result = false;
-    const int kWriteBufSize = 32768;
+    const size_t kWriteBufSize = 32768;
     unsigned char writeBuf[kWriteBufSize];
     z_stream zstream;
     int zerr;
@@ -649,7 +779,7 @@
     /*
      * Initialize the zlib stream struct.
      */
-	memset(&zstream, 0, sizeof(zstream));
+    memset(&zstream, 0, sizeof(zstream));
     zstream.zalloc = Z_NULL;
     zstream.zfree = Z_NULL;
     zstream.opaque = Z_NULL;
@@ -659,10 +789,10 @@
     zstream.avail_out = sizeof(writeBuf);
     zstream.data_type = Z_UNKNOWN;
 
-	/*
-	 * Use the undocumented "negative window bits" feature to tell zlib
-	 * that there's no zlib header waiting for it.
-	 */
+    /*
+     * Use the undocumented "negative window bits" feature to tell zlib
+     * that there's no zlib header waiting for it.
+     */
     zerr = inflateInit2(&zstream, -MAX_WBITS);
     if (zerr != Z_OK) {
         if (zerr == Z_VERSION_ERROR) {
@@ -708,8 +838,8 @@
     assert(zerr == Z_STREAM_END);       /* other errors should've been caught */
 
     /* paranoia */
-    if ((long) zstream.total_out != uncompLen) {
-        LOGW("Size mismatch on inflated file (%ld vs %ld)\n",
+    if (zstream.total_out != uncompLen) {
+        LOGW("Size mismatch on inflated file (%ld vs %zd)\n",
             zstream.total_out, uncompLen);
         goto z_bail;
     }
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 89b3e1f..ba09d08 100644
--- a/opengl/libs/EGL/egl.cpp
+++ b/opengl/libs/EGL/egl.cpp
@@ -239,7 +239,7 @@
 
 // ----------------------------------------------------------------------------
 
-egl_connection_t gEGLImpl[IMPL_NUM_IMPLEMENTATIONS];
+static egl_connection_t gEGLImpl[IMPL_NUM_IMPLEMENTATIONS];
 static egl_display_t gDisplay[NUM_DISPLAYS];
 static pthread_mutex_t gThreadLocalStorageKeyMutex = PTHREAD_MUTEX_INITIALIZER;
 static pthread_key_t gEGLThreadLocalStorageKey = -1;
@@ -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
diff --git a/opengl/libs/egl_impl.h b/opengl/libs/egl_impl.h
index 1fba209..c8f529a 100644
--- a/opengl/libs/egl_impl.h
+++ b/opengl/libs/egl_impl.h
@@ -31,6 +31,7 @@
 
 struct egl_connection_t
 {
+    inline egl_connection_t() : dso(0) { }
     void *              dso;
     gl_hooks_t *        hooks[2];
     EGLint              major;
diff --git a/vpn/java/android/net/vpn/VpnManager.java b/vpn/java/android/net/vpn/VpnManager.java
index ce522c8..ce40b5d 100644
--- a/vpn/java/android/net/vpn/VpnManager.java
+++ b/vpn/java/android/net/vpn/VpnManager.java
@@ -85,7 +85,8 @@
 
     // TODO(oam): Test VPN when EFS is enabled (will do later)...
     public static String getProfilePath() {
-        return Environment.getDataDirectory().getPath() + PROFILES_PATH;
+        // This call will return the correct path if Encrypted FS is enabled or not.
+        return Environment.getSecureDataDirectory().getPath() + PROFILES_PATH;
     }
 
     /**