Code drop from //branches/cupcake/...@124589
diff --git a/libs/audioflinger/A2dpAudioInterface.cpp b/libs/audioflinger/A2dpAudioInterface.cpp
new file mode 100644
index 0000000..d54795c
--- /dev/null
+++ b/libs/audioflinger/A2dpAudioInterface.cpp
@@ -0,0 +1,186 @@
+/*
+ * Copyright (C) 2008 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 <math.h>
+
+#define LOG_NDEBUG 0
+#define LOG_TAG "A2dpAudioInterface"
+#include <utils/Log.h>
+#include <utils/String8.h>
+
+#include "A2dpAudioInterface.h"
+#include "audio/liba2dp.h"
+
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+A2dpAudioInterface::A2dpAudioInterface() :
+    mOutput(0)
+{
+}
+
+A2dpAudioInterface::~A2dpAudioInterface()
+{
+    delete mOutput;
+}
+
+status_t A2dpAudioInterface::initCheck()
+{
+    return 0;
+}
+
+AudioStreamOut* A2dpAudioInterface::openOutputStream(
+        int format, int channelCount, uint32_t sampleRate, status_t *status)
+{
+    LOGD("A2dpAudioInterface::openOutputStream %d, %d, %d\n", format, channelCount, sampleRate);
+    Mutex::Autolock lock(mLock);
+    status_t err = 0;
+
+    // only one output stream allowed
+    if (mOutput) {
+        if (status)
+            *status = -1;
+        return NULL;
+    }
+
+    // create new output stream
+    A2dpAudioStreamOut* out = new A2dpAudioStreamOut();
+    if ((err = out->set(format, channelCount, sampleRate)) == NO_ERROR) {
+        mOutput = out;
+    } else {
+        delete out;
+    }
+    
+    if (status)
+        *status = err;
+    return mOutput;
+}
+
+AudioStreamIn* A2dpAudioInterface::openInputStream(
+        int format, int channelCount, uint32_t sampleRate, status_t *status)
+{
+    if (status)
+        *status = -1;
+    return NULL;
+}
+
+status_t A2dpAudioInterface::standby()
+{
+    return 0;
+}
+
+status_t A2dpAudioInterface::setMicMute(bool state)
+{
+    return 0;
+}
+
+status_t A2dpAudioInterface::getMicMute(bool* state)
+{
+    return 0;
+}
+
+status_t A2dpAudioInterface::setParameter(const char *key, const char *value)
+{
+    LOGD("setParameter %s,%s\n", key, value);
+    return 0;
+}
+
+status_t A2dpAudioInterface::setVoiceVolume(float v)
+{
+    return 0;
+}
+
+status_t A2dpAudioInterface::setMasterVolume(float v)
+{
+    return 0;
+}
+
+status_t A2dpAudioInterface::doRouting()
+{
+    return 0;
+}
+
+status_t A2dpAudioInterface::dump(int fd, const Vector<String16>& args)
+{
+    return 0;
+}
+
+// ----------------------------------------------------------------------------
+
+A2dpAudioInterface::A2dpAudioStreamOut::A2dpAudioStreamOut() :
+    mFd(-1), mStartCount(0), mRetryCount(0), mData(NULL),
+    mInitialized(false), mBufferRemaining(0)
+{
+}
+
+status_t A2dpAudioInterface::A2dpAudioStreamOut::set(
+        int format, int channels, uint32_t rate)
+{
+    LOGD("A2dpAudioStreamOut::set %d, %d, %d\n", format, channels, rate);
+
+    // fix up defaults
+    if (format == 0) format = AudioSystem::PCM_16_BIT;
+    if (channels == 0) channels = channelCount();
+    if (rate == 0) rate = sampleRate();
+
+    // check values
+    if ((format != AudioSystem::PCM_16_BIT) ||
+            (channels != channelCount()) ||
+            (rate != sampleRate()))
+        return BAD_VALUE;
+
+    return NO_ERROR;
+}
+
+A2dpAudioInterface::A2dpAudioStreamOut::~A2dpAudioStreamOut()
+{
+    if (mData)
+        a2dp_cleanup(mData);
+}
+
+ssize_t A2dpAudioInterface::A2dpAudioStreamOut::write(const void* buffer, size_t bytes)
+{    
+    if (!mInitialized) {
+        int ret = a2dp_init("00:00:00:00:00:00", 44100, 2, &mData);
+        if (ret)
+            return ret;
+        mInitialized = true;
+    }
+    
+    size_t remaining = bytes;
+    while (remaining > 0) {
+        int written = a2dp_write(mData, buffer, remaining);        
+        remaining -= written;
+        buffer = ((char *)buffer) + written;
+    }
+    
+    return bytes;
+}
+
+status_t A2dpAudioInterface::A2dpAudioStreamOut::standby()
+{
+    return 0;
+}
+
+status_t A2dpAudioInterface::A2dpAudioStreamOut::dump(int fd, const Vector<String16>& args)
+{
+    return NO_ERROR;
+}
+
+
+}; // namespace android
diff --git a/libs/audioflinger/A2dpAudioInterface.h b/libs/audioflinger/A2dpAudioInterface.h
new file mode 100644
index 0000000..03bf933
--- /dev/null
+++ b/libs/audioflinger/A2dpAudioInterface.h
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2008 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 A2DP_AUDIO_HARDWARE_H
+#define A2DP_AUDIO_HARDWARE_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/threads.h>
+
+#include <hardware/AudioHardwareBase.h>
+
+
+namespace android {
+
+class A2dpAudioInterface : public AudioHardwareBase
+{
+    class A2dpAudioStreamOut;
+
+public:
+                        A2dpAudioInterface();
+    virtual             ~A2dpAudioInterface();
+    virtual status_t    initCheck();
+    virtual status_t    standby();
+
+    virtual status_t    setVoiceVolume(float volume);
+    virtual status_t    setMasterVolume(float volume);
+
+    // mic mute
+    virtual status_t    setMicMute(bool state);
+    virtual status_t    getMicMute(bool* state);
+
+    // Temporary interface, do not use
+    // TODO: Replace with a more generic key:value get/set mechanism
+    virtual status_t    setParameter(const char *key, const char *value);
+
+    // create I/O streams
+    virtual AudioStreamOut* openOutputStream(
+                                int format=0,
+                                int channelCount=0,
+                                uint32_t sampleRate=0,
+                                status_t *status=0);
+
+    virtual AudioStreamIn* openInputStream(
+                                int format,
+                                int channelCount,
+                                uint32_t sampleRate,
+                                status_t *status);
+
+protected:
+    virtual status_t    doRouting();
+    virtual status_t    dump(int fd, const Vector<String16>& args);
+
+private:
+    class A2dpAudioStreamOut : public AudioStreamOut {
+    public:
+                            A2dpAudioStreamOut();
+        virtual             ~A2dpAudioStreamOut();
+                status_t    set(int format,
+                                int channelCount,
+                                uint32_t sampleRate);
+        virtual uint32_t    sampleRate() const { return 44100; }
+        // must be 32-bit aligned - driver only seems to like 4800
+        virtual size_t      bufferSize() const { return 5120; }
+        virtual int         channelCount() const { return 2; }
+        virtual int         format() const { return AudioSystem::PCM_16_BIT; }
+        virtual uint32_t    latency() const { return 0; }
+        virtual status_t    setVolume(float volume) { return INVALID_OPERATION; }
+        virtual ssize_t     write(const void* buffer, size_t bytes);
+                status_t    standby();
+        virtual status_t    dump(int fd, const Vector<String16>& args);
+
+    private:
+                int         mFd;
+                int         mStartCount;
+                int         mRetryCount;
+                void*       mData;
+                bool        mInitialized;
+
+#define kBufferSize 50000
+                char                    mBuffer[kBufferSize];
+                int                     mBufferRemaining;
+    };
+
+    Mutex                   mLock;
+    A2dpAudioStreamOut*     mOutput;
+};
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // A2DP_AUDIO_HARDWARE_H
diff --git a/libs/audioflinger/Android.mk b/libs/audioflinger/Android.mk
index a9cb3037..d16e3e14 100644
--- a/libs/audioflinger/Android.mk
+++ b/libs/audioflinger/Android.mk
@@ -45,9 +45,12 @@
 
 LOCAL_MODULE:= libaudioflinger
 
-ifeq ($(TARGET_ARCH),arm)  # not simulator
-  LOCAL_CFLAGS += -DWITH_BLUETOOTH
+ifeq ($(BOARD_HAVE_BLUETOOTH),true)
+  LOCAL_SRC_FILES += A2dpAudioInterface.cpp
+  LOCAL_SHARED_LIBRARIES += liba2dp
+  LOCAL_CFLAGS += -DWITH_BLUETOOTH -DWITH_A2DP
   LOCAL_C_INCLUDES += $(call include-path-for, bluez-libs)
+  LOCAL_C_INCLUDES += $(call include-path-for, bluez-utils)
 endif
 
 include $(BUILD_SHARED_LIBRARY)
diff --git a/libs/audioflinger/AudioDumpInterface.cpp b/libs/audioflinger/AudioDumpInterface.cpp
index 5ff2f18..8eee9cc 100644
--- a/libs/audioflinger/AudioDumpInterface.cpp
+++ b/libs/audioflinger/AudioDumpInterface.cpp
@@ -2,16 +2,16 @@
 **
 ** Copyright 2008, 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 
+** 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 
+**     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 
+** 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.
 */
 
@@ -28,6 +28,8 @@
 
 namespace android {
 
+bool gFirst = true;       // true if first write after a standby
+
 // ----------------------------------------------------------------------------
 
 AudioDumpInterface::AudioDumpInterface(AudioHardwareInterface* hw)
@@ -40,17 +42,25 @@
 }
 
 
+AudioDumpInterface::~AudioDumpInterface()
+{
+    if(mFinalInterface) delete mFinalInterface;
+    if(mStreamOut) delete mStreamOut;
+}
+
+
 status_t AudioDumpInterface::standby()
 {
     if(mStreamOut)  mStreamOut->Close();
+    gFirst = true;
     return mFinalInterface->standby();
 }
 
 
 AudioStreamOut* AudioDumpInterface::openOutputStream(
-        int format, int channelCount, uint32_t sampleRate)
+        int format, int channelCount, uint32_t sampleRate, status_t *status)
 {
-    AudioStreamOut* outFinal = mFinalInterface->openOutputStream(format, channelCount, sampleRate);
+    AudioStreamOut* outFinal = mFinalInterface->openOutputStream(format, channelCount, sampleRate, status);
 
     if(outFinal) {
         mStreamOut =  new AudioStreamOutDump(outFinal);
@@ -69,13 +79,26 @@
     mOutFile = 0;
 }
 
+
+AudioStreamOutDump::~AudioStreamOutDump()
+{
+    Close();
+    delete mFinalStream;
+}
+
 ssize_t AudioStreamOutDump::write(const void* buffer, size_t bytes)
 {
     ssize_t ret;
-    
+
     ret = mFinalStream->write(buffer, bytes);
-    if(!mOutFile) {
-        mOutFile = fopen(FLINGER_DUMP_NAME, "ab");
+    if(!mOutFile && gFirst) {
+        gFirst = false;
+        // check if dump file exist
+        mOutFile = fopen(FLINGER_DUMP_NAME, "r");
+        if(mOutFile) {
+            fclose(mOutFile);
+            mOutFile = fopen(FLINGER_DUMP_NAME, "ab");
+        }
     }
     if (mOutFile) {
         fwrite(buffer, bytes, 1, mOutFile);
diff --git a/libs/audioflinger/AudioDumpInterface.h b/libs/audioflinger/AudioDumpInterface.h
index 732b97d..a65e56a 100644
--- a/libs/audioflinger/AudioDumpInterface.h
+++ b/libs/audioflinger/AudioDumpInterface.h
@@ -2,16 +2,16 @@
 **
 ** Copyright 2008, 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 
+** 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 
+**     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 
+** 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.
 */
 
@@ -21,33 +21,35 @@
 #include <stdint.h>
 #include <sys/types.h>
 
-#include <hardware/AudioHardwareInterface.h>
+#include <hardware/AudioHardwareBase.h>
 
 namespace android {
 
-#define FLINGER_DUMP_NAME "/tmp/FlingerOut.pcm" // name of file used for dump
+#define FLINGER_DUMP_NAME "/data/FlingerOut.pcm" // name of file used for dump
 
 class AudioStreamOutDump : public AudioStreamOut {
 public:
                         AudioStreamOutDump( AudioStreamOut* FinalStream);
+                        ~AudioStreamOutDump();
                         virtual ssize_t     write(const void* buffer, size_t bytes);
-                        
+
     virtual uint32_t    sampleRate() const { return mFinalStream->sampleRate(); }
     virtual size_t      bufferSize() const { return mFinalStream->bufferSize(); }
     virtual int         channelCount() const { return mFinalStream->channelCount(); }
     virtual int         format() const { return mFinalStream->format(); }
+    virtual uint32_t    latency() const { return mFinalStream->latency(); }
     virtual status_t    setVolume(float volume)
                             { return mFinalStream->setVolume(volume); }
     virtual status_t    dump(int fd, const Vector<String16>& args) { return mFinalStream->dump(fd, args); }
     void                Close(void);
 
 private:
-    AudioStreamOut  *mFinalStream;
-    FILE            *mOutFile;     // output file
+    AudioStreamOut      *mFinalStream;
+    FILE                *mOutFile;     // output file
 };
 
 
-class AudioDumpInterface : public  AudioHardwareInterface
+class AudioDumpInterface : public AudioHardwareBase
 {
 
 public:
@@ -56,10 +58,10 @@
     virtual AudioStreamOut* openOutputStream(
                                 int format=0,
                                 int channelCount=0,
-                                uint32_t sampleRate=0);
+                                uint32_t sampleRate=0,
+                                status_t *status=0);
+    virtual             ~AudioDumpInterface();
 
-    virtual             ~AudioDumpInterface()
-                            {delete mFinalInterface;}
     virtual status_t    initCheck()
                             {return mFinalInterface->initCheck();}
     virtual status_t    setVoiceVolume(float volume)
@@ -67,13 +69,6 @@
     virtual status_t    setMasterVolume(float volume)
                             {return mFinalInterface->setMasterVolume(volume);}
 
-    virtual status_t    setRouting(int mode, uint32_t routes)
-                            {return mFinalInterface->setRouting(mode, routes);}
-    virtual status_t    getRouting(int mode, uint32_t* routes)
-                            {return mFinalInterface->getRouting(mode, routes);}
-    virtual status_t    getMode(int* mode)
-                            {return mFinalInterface->getMode(mode);}
-    
     // mic mute
     virtual status_t    setMicMute(bool state)
                             {return mFinalInterface->setMicMute(state);}
@@ -83,17 +78,17 @@
     virtual status_t    setParameter(const char* key, const char* value)
                             {return mFinalInterface->setParameter(key, value);}
 
-    virtual AudioStreamIn* openInputStream( int format, int channelCount, uint32_t sampleRate)
-                            {return mFinalInterface->openInputStream( format, channelCount, sampleRate);}
+    virtual AudioStreamIn* openInputStream( int format, int channelCount, uint32_t sampleRate, status_t *status)
+                            {return mFinalInterface->openInputStream( format, channelCount, sampleRate, status);}
 
     virtual status_t    dump(int fd, const Vector<String16>& args) { return mFinalInterface->dumpState(fd, args); }
 
 protected:
-    virtual status_t    doRouting() {return 0;}
-    
+    virtual status_t    doRouting() {return mFinalInterface->setRouting(mMode, mRoutes[mMode]);}
+
     AudioHardwareInterface  *mFinalInterface;
     AudioStreamOutDump      *mStreamOut;
-    
+
 };
 
 }; // namespace android
diff --git a/libs/audioflinger/AudioFlinger.cpp b/libs/audioflinger/AudioFlinger.cpp
index fb21629..53b18ad 100644
--- a/libs/audioflinger/AudioFlinger.cpp
+++ b/libs/audioflinger/AudioFlinger.cpp
@@ -31,6 +31,8 @@
 #include <utils/String16.h>
 #include <utils/threads.h>
 
+#include <cutils/properties.h>
+
 #include <media/AudioTrack.h>
 #include <media/AudioRecord.h>
 
@@ -41,9 +43,13 @@
 #include "AudioMixer.h"
 #include "AudioFlinger.h"
 
+#ifdef WITH_A2DP
+#include "A2dpAudioInterface.h"
+#endif
+
 namespace android {
 
-static const nsecs_t kStandbyTimeInNsecs = seconds(3);
+//static const nsecs_t kStandbyTimeInNsecs = seconds(3);
 static const unsigned long kBufferRecoveryInUsecs = 2000;
 static const unsigned long kMaxBufferRecoveryInUsecs = 20000;
 static const float MAX_GAIN = 4096.0f;
@@ -93,8 +99,9 @@
 
 AudioFlinger::AudioFlinger()
     : BnAudioFlinger(), Thread(false),
-        mMasterVolume(0), mMasterMute(true),
-        mAudioMixer(0), mAudioHardware(0), mOutput(0), mAudioRecordThread(0),
+        mMasterVolume(0), mMasterMute(true), mHardwareAudioMixer(0), mA2dpAudioMixer(0),
+        mAudioMixer(0), mAudioHardware(0), mA2dpAudioInterface(0),
+        mHardwareOutput(0), mA2dpOutput(0), mOutput(0), mAudioRecordThread(0),
         mSampleRate(0), mFrameCount(0), mChannelCount(0), mFormat(0),
         mMixBuffer(0), mLastWriteTime(0), mNumWrites(0), mNumDelayedWrites(0),
         mStandby(false), mInWrite(false)
@@ -105,17 +112,14 @@
     if (mAudioHardware->initCheck() == NO_ERROR) {
         // open 16-bit output stream for s/w mixer
         mHardwareStatus = AUDIO_HW_OUTPUT_OPEN;
-        mOutput = mAudioHardware->openOutputStream(AudioSystem::PCM_16_BIT);
+        status_t status;
+        mHardwareOutput = mAudioHardware->openOutputStream(AudioSystem::PCM_16_BIT, 0, 0, &status);
         mHardwareStatus = AUDIO_HW_IDLE;
-        if (mOutput) {
-            mSampleRate = mOutput->sampleRate();
-            mChannelCount = mOutput->channelCount();
-            mFormat = mOutput->format();
-            mMixBufferSize = mOutput->bufferSize();
-            mFrameCount = mMixBufferSize / mChannelCount / sizeof(int16_t);
-            mMixBuffer = new int16_t[mFrameCount * mChannelCount];
-            memset(mMixBuffer, 0, mMixBufferSize);
-            mAudioMixer = new AudioMixer(mFrameCount, mSampleRate);
+        if (mHardwareOutput) {
+            mSampleRate = mHardwareOutput->sampleRate();
+            mHardwareAudioMixer = new AudioMixer(getOutputFrameCount(mHardwareOutput), mSampleRate);
+            setOutput(mHardwareOutput);
+
             // FIXME - this should come from settings
             setMasterVolume(1.0f);
             setRouting(AudioSystem::MODE_NORMAL, AudioSystem::ROUTE_SPEAKER, AudioSystem::ROUTE_ALL);
@@ -124,20 +128,87 @@
             setMode(AudioSystem::MODE_NORMAL);
             mMasterMute = false;
         } else {
-            LOGE("Failed to initialize output stream");
+            LOGE("Failed to initialize output stream, status: %d", status);
         }
-    } else {
+        
+#ifdef WITH_A2DP
+        // Create A2DP interface
+        mA2dpAudioInterface = new A2dpAudioInterface();
+        mA2dpOutput = mA2dpAudioInterface->openOutputStream(AudioSystem::PCM_16_BIT, 0, 0, &status);       
+        mA2dpAudioMixer = new AudioMixer(getOutputFrameCount(mA2dpOutput), mA2dpOutput->sampleRate());
+
+        // create a buffer big enough for both hardware and A2DP audio output.
+        size_t hwFrameCount = getOutputFrameCount(mHardwareOutput);
+        size_t a2dpFrameCount = getOutputFrameCount(mA2dpOutput);
+        size_t frameCount = (hwFrameCount > a2dpFrameCount ? hwFrameCount : a2dpFrameCount);
+#else
+        size_t frameCount = getOutputFrameCount(mHardwareOutput);
+#endif
+        // FIXME - Current mixer implementation only supports stereo output: Always
+        // Allocate a stereo buffer even if HW output is mono.
+        mMixBuffer = new int16_t[frameCount * 2];
+        memset(mMixBuffer, 0, frameCount * 2 * sizeof(int16_t));
+        
+        // Start record thread
+        mAudioRecordThread = new AudioRecordThread(mAudioHardware);
+        if (mAudioRecordThread != 0) {
+            mAudioRecordThread->run("AudioRecordThread", PRIORITY_URGENT_AUDIO);            
+        }
+     } else {
         LOGE("Couldn't even initialize the stubbed audio hardware!");
     }
+
+    char value[PROPERTY_VALUE_MAX];
+    // FIXME: What property should this be???
+    property_get("ro.audio.silent", value, "0");
+    if (atoi(value)) {
+        LOGD("Silence is golden");
+        mMasterMute = true;
+    }
 }
 
 AudioFlinger::~AudioFlinger()
 {
+    if (mAudioRecordThread != 0) {
+        mAudioRecordThread->exit();
+        mAudioRecordThread.clear();        
+    }
     delete mOutput;
+    delete mA2dpOutput;
     delete mAudioHardware;
+    delete mA2dpAudioInterface;
     delete [] mMixBuffer;
-    delete mAudioMixer;
-    mAudioRecordThread.clear();
+    delete mHardwareAudioMixer;
+    delete mA2dpAudioMixer;
+}
+ 
+void AudioFlinger::setOutput(AudioStreamOut* output)
+{
+    // lock on mOutputLock to prevent threadLoop() from starving us
+    Mutex::Autolock _l2(mOutputLock);
+    
+    // to synchronize with threadLoop()
+    Mutex::Autolock _l(mLock);
+
+    if (mOutput != output) {
+        mSampleRate = output->sampleRate();
+        mChannelCount = output->channelCount();
+    
+        // FIXME - Current mixer implementation only supports stereo output
+        if (mChannelCount == 1) {
+            LOGE("Invalid audio hardware channel count");
+        }
+        mFormat = output->format();
+        mFrameCount = getOutputFrameCount(output);
+                
+        mAudioMixer = (output == mA2dpOutput ? mA2dpAudioMixer : mHardwareAudioMixer);
+        mOutput = output;
+    }
+}
+
+size_t AudioFlinger::getOutputFrameCount(AudioStreamOut* output) 
+{
+    return output->bufferSize() / output->channelCount() / sizeof(int16_t);
 }
 
 status_t AudioFlinger::dumpClients(int fd, const Vector<String16>& args)
@@ -201,8 +272,8 @@
     const size_t SIZE = 256;
     char buffer[SIZE];
     String8 result;
-    
-    snprintf(buffer, SIZE, "AudioMixer tracks: %08x\n", audioMixer().trackNames());
+
+    snprintf(buffer, SIZE, "AudioMixer tracks: %08x\n", audioMixer()->trackNames());
     result.append(buffer);
     snprintf(buffer, SIZE, "last write occurred (msecs): %llu\n", ns2ms(systemTime() - mLastWriteTime));
     result.append(buffer);
@@ -254,17 +325,26 @@
 // Thread virtuals
 bool AudioFlinger::threadLoop()
 {
-    nsecs_t maxPeriod = seconds(mFrameCount) / mSampleRate * 2;
     unsigned long sleepTime = kBufferRecoveryInUsecs;
-    const size_t mixBufferSize = mFrameCount*mChannelCount*sizeof(int16_t);
     int16_t* curBuf = mMixBuffer;
     Vector< sp<Track> > tracksToRemove;
-    size_t enabledTracks;
+    size_t enabledTracks = 0;
     nsecs_t standbyTime = systemTime();
+    AudioMixer* mixer = 0;
+    size_t frameCount = 0;
+    int channelCount = 0;
+    uint32_t sampleRate = 0;
+    AudioStreamOut* output = 0;
 
     do {
         enabledTracks = 0;
-        { // scope for the lock
+        { // scope for the mLock
+        
+            // locking briefly on the secondary mOutputLock is necessary to avoid
+            // having this thread starve the thread that called setOutput()
+            mOutputLock.lock();
+            mOutputLock.unlock();
+
             Mutex::Autolock _l(mLock);
             const SortedVector< wp<Track> >& activeTracks = mActiveTracks;
 
@@ -286,6 +366,15 @@
                 continue;
             }
 
+            // get active mixer and output parameter while the lock is held and keep them
+            // consistent till the next loop.
+            
+            mixer = audioMixer();
+            frameCount = mFrameCount;
+            channelCount = mChannelCount;
+            sampleRate = mSampleRate;
+            output = mOutput;
+            
             // find out which tracks need to be processed
             size_t count = activeTracks.size();
             for (size_t i=0 ; i<count ; i++) {
@@ -294,13 +383,11 @@
 
                 Track* const track = t.get();
                 audio_track_cblk_t* cblk = track->cblk();
-                uint32_t u = cblk->user;
-                uint32_t s = cblk->server;
 
                 // The first time a track is added we wait
                 // for all its buffers to be filled before processing it
-                audioMixer().setActiveTrack(track->name());
-                if ((u > s) && (track->isReady(u, s) || track->isStopped()) &&
+                mixer->setActiveTrack(track->name());
+                if (cblk->framesReady() && (track->isReady() || track->isStopped()) &&
                         !track->isPaused())
                 {
                     //LOGD("u=%08x, s=%08x [OK]", u, s);
@@ -325,9 +412,8 @@
                     }
 
                     // XXX: these things DON'T need to be done each time
-                    AudioMixer& mixer(audioMixer());
-                    mixer.setBufferProvider(track);
-                    mixer.enable(AudioMixer::MIXING);
+                    mixer->setBufferProvider(track);
+                    mixer->enable(AudioMixer::MIXING);
 
                     int param;
                     if ( track->mFillingUpStatus == Track::FS_FILLED) {
@@ -342,15 +428,15 @@
                     } else {
                         param = AudioMixer::RAMP_VOLUME;
                     }
-                    mixer.setParameter(param, AudioMixer::VOLUME0, left);
-                    mixer.setParameter(param, AudioMixer::VOLUME1, right);
-                    mixer.setParameter(
+                    mixer->setParameter(param, AudioMixer::VOLUME0, left);
+                    mixer->setParameter(param, AudioMixer::VOLUME1, right);
+                    mixer->setParameter(
                         AudioMixer::TRACK,
                         AudioMixer::FORMAT, track->format());
-                    mixer.setParameter(
+                    mixer->setParameter(
                         AudioMixer::TRACK,
                         AudioMixer::CHANNEL_COUNT, track->channelCount());
-                    mixer.setParameter(
+                    mixer->setParameter(
                         AudioMixer::RESAMPLE,
                         AudioMixer::SAMPLE_RATE,
                         int(cblk->sampleRate));
@@ -361,8 +447,7 @@
                 } else {
                     //LOGD("u=%08x, s=%08x [NOT READY]", u, s);
                     if (track->isStopped()) {
-                        track->mFillingUpStatus = Track::FS_FILLING;
-                        track->mFlags = 0;    
+                        track->reset();
                     }
                     if (track->isTerminated() || track->isStopped() || track->isPaused()) {
                         // We have consumed all the buffers of this track.
@@ -378,7 +463,7 @@
                         }
                     }
                     // LOGV("disable(%d)", track->name());
-                    audioMixer().disable(AudioMixer::MIXING);
+                    mixer->disable(AudioMixer::MIXING);
                 }
             }
 
@@ -390,26 +475,27 @@
                     mActiveTracks.remove(track);
                     if (track->isTerminated()) {
                         mTracks.remove(track);
-                        audioMixer().deleteTrackName(track->mName);
+                        mixer->deleteTrackName(track->mName);
                     }
                 }
-            }
-        }
-
+            }  
+       }
         if (LIKELY(enabledTracks)) {
             // mix buffers...
-            audioMixer().process(curBuf);
+            mixer->process(curBuf);
 
             // output audio to hardware
             mLastWriteTime = systemTime();
             mInWrite = true;
-            mOutput->write(curBuf, mixBufferSize);
+            size_t mixBufferSize = frameCount*channelCount*sizeof(int16_t);
+            output->write(curBuf, mixBufferSize);
             mNumWrites++;
             mInWrite = false;
             mStandby = false;
             nsecs_t temp = systemTime();
             standbyTime = temp + kStandbyTimeInNsecs;
             nsecs_t delta = temp - mLastWriteTime;
+            nsecs_t maxPeriod = seconds(frameCount) / sampleRate * 2;
             if (delta > maxPeriod) {
                 LOGW("write blocked for %llu msecs", ns2ms(delta));
                 mNumDelayedWrites++;
@@ -458,43 +544,60 @@
         uint32_t sampleRate,
         int format,
         int channelCount,
-        int bufferCount,
-        uint32_t flags)
+        int frameCount,
+        uint32_t flags,
+        const sp<IMemory>& sharedBuffer,
+        status_t *status)
 {
-    if (streamType >= AudioTrack::NUM_STREAM_TYPES) {
-        LOGE("invalid stream type");
-        return NULL;
-    }
-
-    if (sampleRate > MAX_SAMPLE_RATE) {
-        LOGE("Sample rate out of range: %d", sampleRate);
-        return NULL;
-    }
-
     sp<Track> track;
     sp<TrackHandle> trackHandle;
-    Mutex::Autolock _l(mLock);
-
-    if (mSampleRate == 0) {
-        LOGE("Audio driver not initialized.");
-        return trackHandle;
-    }
-
     sp<Client> client;
-    wp<Client> wclient = mClients.valueFor(pid);
+    wp<Client> wclient;
+    status_t lStatus;
 
-    if (wclient != NULL) {
-        client = wclient.promote();
-    } else {
-        client = new Client(this, pid);
-        mClients.add(pid, client);
+    if (streamType >= AudioTrack::NUM_STREAM_TYPES) {
+        LOGE("invalid stream type");
+        lStatus = BAD_VALUE;
+        goto Exit;
     }
 
-    // FIXME: Buffer size should be based on sample rate for consistent latency
-    track = new Track(this, client, streamType, sampleRate, format,
-            channelCount, bufferCount, channelCount == 1 ? mMixBufferSize>>1 : mMixBufferSize);
-    mTracks.add(track);
-    trackHandle = new TrackHandle(track);
+    // Resampler implementation limits input sampling rate to 2 x output sampling rate.
+    if (sampleRate > MAX_SAMPLE_RATE || sampleRate > mSampleRate*2) {
+        LOGE("Sample rate out of range: %d", sampleRate);
+        lStatus = BAD_VALUE;
+        goto Exit;
+    }
+
+    {
+        Mutex::Autolock _l(mLock);
+
+        if (mSampleRate == 0) {
+            LOGE("Audio driver not initialized.");
+            lStatus = NO_INIT;
+            goto Exit;
+        }
+
+        wclient = mClients.valueFor(pid);
+
+        if (wclient != NULL) {
+            client = wclient.promote();
+        } else {
+            client = new Client(this, pid);
+            mClients.add(pid, client);
+        }
+
+        track = new Track(this, client, streamType, sampleRate, format,
+                channelCount, frameCount, sharedBuffer);
+        mTracks.add(track);
+        trackHandle = new TrackHandle(track);
+
+        lStatus = NO_ERROR;
+    }
+
+Exit:
+    if(status) {
+        *status = lStatus;
+    }
     return trackHandle;
 }
 
@@ -518,6 +621,16 @@
     return mFrameCount;
 }
 
+uint32_t AudioFlinger::latency() const
+{
+    if (mOutput) {
+        return mOutput->latency();
+    }
+    else {
+        return 0;
+    }
+}
+
 status_t AudioFlinger::setMasterVolume(float value)
 {
     // check calling permissions
@@ -549,6 +662,21 @@
         return BAD_VALUE;
     }
 
+#ifdef WITH_A2DP
+    LOGD("setRouting %d %d %d\n", mode, routes, mask);
+    if (mode == AudioSystem::MODE_NORMAL && 
+            (mask & AudioSystem::ROUTE_BLUETOOTH_A2DP)) {
+        if (routes & AudioSystem::ROUTE_BLUETOOTH_A2DP) {
+            LOGD("set output to A2DP\n");
+            setOutput(mA2dpOutput);
+        } else {
+            LOGD("set output to hardware audio\n");
+            setOutput(mHardwareOutput);
+        }
+        LOGD("setOutput done\n");
+    }
+#endif
+
     AutoMutex lock(mHardwareLock);
     mHardwareStatus = AUDIO_HW_GET_ROUTING;
     uint32_t r;
@@ -656,7 +784,7 @@
     if (uint32_t(stream) >= AudioTrack::NUM_STREAM_TYPES) {
         return BAD_VALUE;
     }
-    
+
     mStreamTypes[stream].volume = value;
     status_t ret = NO_ERROR;
     if (stream == AudioTrack::VOICE_CALL) {
@@ -750,6 +878,7 @@
         // buffers before playing. This is to ensure the client will
         // effectively get the latency it requested.
         track->mFillingUpStatus = Track::FS_FILLING;
+        track->mResetDone = false;
         mActiveTracks.add(track);
         return NO_ERROR;
     }
@@ -771,7 +900,7 @@
     if (t!=NULL) {
         t->reset();
     }
-    audioMixer().deleteTrackName(name);
+    audioMixer()->deleteTrackName(name);
     mActiveTracks.remove(track);
     mWaitWorkCV.broadcast();
 }
@@ -789,7 +918,7 @@
     if (mActiveTracks.indexOf(track) < 0) {
         LOGV("remove track (%d) and delete from mixer", track->name());
         mTracks.remove(track);
-        audioMixer().deleteTrackName(keep->name());
+        audioMixer()->deleteTrackName(keep->name());
     }
 }
 
@@ -823,38 +952,53 @@
             uint32_t sampleRate,
             int format,
             int channelCount,
-            int bufferCount,
-            int bufferSize)
+            int frameCount,
+            const sp<IMemory>& sharedBuffer)
     :   RefBase(),
         mAudioFlinger(audioFlinger),
         mClient(client),
         mStreamType(streamType),
-        mFormat(format),
-        mChannelCount(channelCount),
-        mBufferCount(bufferCount),
-        mFlags(0),
-        mBufferSize(bufferSize),
+        mFrameCount(0),
         mState(IDLE),
-        mClientTid(-1)
+        mClientTid(-1),
+        mFormat(format),
+        mFlags(0)
 {
-    mName = audioFlinger->audioMixer().getTrackName();
+    mName = audioFlinger->audioMixer()->getTrackName();
     if (mName < 0) {
         LOGE("no more track names availlable");
         return;
     }
 
+    LOGV_IF(sharedBuffer != 0, "sharedBuffer: %p, size: %d", sharedBuffer->pointer(), sharedBuffer->size());
+
+
     // LOGD("Creating track with %d buffers @ %d bytes", bufferCount, bufferSize);
-    size_t size = sizeof(audio_track_cblk_t) + bufferCount * bufferSize;
+   size_t size = sizeof(audio_track_cblk_t);
+   size_t bufferSize = frameCount*channelCount*sizeof(int16_t);
+   if (sharedBuffer == 0) {
+       size += bufferSize;
+   }
+
     mCblkMemory = client->heap()->allocate(size);
     if (mCblkMemory != 0) {
         mCblk = static_cast<audio_track_cblk_t *>(mCblkMemory->pointer());
         if (mCblk) { // construct the shared structure in-place.
             new(mCblk) audio_track_cblk_t();
             // clear all buffers
-            mCblk->size = bufferSize;
+            mCblk->frameCount = frameCount;
             mCblk->sampleRate = sampleRate;
-            mBuffers = (char*)mCblk + sizeof(audio_track_cblk_t);
-            memset(mBuffers, 0, bufferCount * bufferSize);
+            mCblk->channels = 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;
+            } else {
+                mBuffer = sharedBuffer->pointer();
+            }
+            mBufferEnd = (uint8_t *)mBuffer + bufferSize;
         }
     } else {
         LOGE("not enough memory for AudioTrack size=%u", size);
@@ -873,15 +1017,16 @@
 void AudioFlinger::TrackBase::releaseBuffer(AudioBufferProvider::Buffer* buffer)
 {
     buffer->raw = 0;
-    buffer->frameCount = 0;
+    mFrameCount = buffer->frameCount;
     step();
+    buffer->frameCount = 0;
 }
 
 bool AudioFlinger::TrackBase::step() {
     bool result;
     audio_track_cblk_t* cblk = this->cblk();
-    
-    result = cblk->stepServer(bufferCount()); 
+
+    result = cblk->stepServer(mFrameCount);
     if (!result) {
         LOGV("stepServer failed acquiring cblk mutex");
         mFlags |= STEPSERVER_FAILED;
@@ -894,7 +1039,10 @@
 
     cblk->user = 0;
     cblk->server = 0;
-    mFlags = 0;    
+    cblk->userBase = 0;
+    cblk->serverBase = 0;
+    mFlags = 0;
+    LOGV("TrackBase::reset");
 }
 
 sp<IMemory> AudioFlinger::TrackBase::getCblk() const
@@ -906,6 +1054,27 @@
     return mCblk->sampleRate;
 }
 
+int AudioFlinger::TrackBase::channelCount() const {
+    return mCblk->channels;
+}
+
+void* AudioFlinger::TrackBase::getBuffer(uint32_t offset, uint32_t frames) const {
+    audio_track_cblk_t* cblk = this->cblk();
+    int16_t *bufferStart = (int16_t *)mBuffer + (offset-cblk->serverBase)*cblk->channels;
+    int16_t *bufferEnd = bufferStart + frames * cblk->channels;
+
+    // Check validity of returned pointer in case the track control block would have been corrupted.
+    if (bufferStart < mBuffer || bufferStart > bufferEnd || bufferEnd > mBufferEnd) {
+        LOGW("TrackBase::getBuffer buffer out of range:\n    start: %p, end %p , mBuffer %p mBufferEnd %p\n    \
+                server %d, serverBase %d, user %d, userBase %d",
+                bufferStart, bufferEnd, mBuffer, mBufferEnd,
+                cblk->server, cblk->serverBase, cblk->user, cblk->userBase);
+        return 0;
+    }
+
+    return bufferStart;
+}
+
 // ----------------------------------------------------------------------------
 
 AudioFlinger::Track::Track(
@@ -915,13 +1084,14 @@
             uint32_t sampleRate,
             int format,
             int channelCount,
-            int bufferCount,
-            int bufferSize)
-    :   TrackBase(audioFlinger, client, streamType, sampleRate, format, channelCount, bufferCount, bufferSize)
+            int frameCount,
+            const sp<IMemory>& sharedBuffer)
+    :   TrackBase(audioFlinger, client, streamType, sampleRate, format, channelCount, frameCount, sharedBuffer)
 {
     mVolume[0] = 1.0f;
     mVolume[1] = 1.0f;
     mMute = false;
+    mSharedBuffer = sharedBuffer;
 }
 
 AudioFlinger::Track::~Track()
@@ -943,8 +1113,8 @@
             mClient->pid(),
             mStreamType,
             mFormat,
-            mChannelCount,
-            mBufferCount,
+            mCblk->channels,
+            mFrameCount,
             mState,
             mMute,
             mFillingUpStatus,
@@ -958,36 +1128,50 @@
 status_t AudioFlinger::Track::getNextBuffer(AudioBufferProvider::Buffer* buffer)
 {
      audio_track_cblk_t* cblk = this->cblk();
-     uint32_t u = cblk->user;
-     uint32_t s = cblk->server;
-     
-     // Check if last stepServer failed, try to step now 
+     uint32_t framesReady;
+     uint32_t framesReq = buffer->frameCount;
+
+     // Check if last stepServer failed, try to step now
      if (mFlags & TrackBase::STEPSERVER_FAILED) {
          if (!step())  goto getNextBuffer_exit;
          LOGV("stepServer recovered");
          mFlags &= ~TrackBase::STEPSERVER_FAILED;
      }
 
-     if (LIKELY(u > s)) {
-         int index = s & audio_track_cblk_t::BUFFER_MASK;
-         buffer->raw = getBuffer(index);
-         buffer->frameCount = mAudioFlinger->frameCount();
-         return NO_ERROR;
+     framesReady = cblk->framesReady();
+
+     if (LIKELY(framesReady)) {
+        uint32_t s = cblk->server;
+        uint32_t bufferEnd = cblk->serverBase + cblk->frameCount;
+
+        bufferEnd = (cblk->loopEnd < bufferEnd) ? cblk->loopEnd : bufferEnd;
+        if (framesReq > framesReady) {
+            framesReq = framesReady;
+        }
+        if (s + framesReq > bufferEnd) {
+            framesReq = bufferEnd - s;
+        }
+
+         buffer->raw = getBuffer(s, framesReq);
+         if (buffer->raw == 0) goto getNextBuffer_exit;
+
+         buffer->frameCount = framesReq;
+        return NO_ERROR;
      }
+
 getNextBuffer_exit:
      buffer->raw = 0;
      buffer->frameCount = 0;
      return NOT_ENOUGH_DATA;
 }
 
-bool AudioFlinger::Track::isReady(uint32_t u, int32_t s) const {
+bool AudioFlinger::Track::isReady() const {
     if (mFillingUpStatus != FS_FILLING) return true;
-    const uint32_t u_seq = u & audio_track_cblk_t::SEQUENCE_MASK;
-    const uint32_t u_buf = u & audio_track_cblk_t::BUFFER_MASK;
-    const uint32_t s_seq = s & audio_track_cblk_t::SEQUENCE_MASK;
-    const uint32_t s_buf = s & audio_track_cblk_t::BUFFER_MASK;
-    if (u_seq > s_seq && u_buf == s_buf) {
+
+    if (mCblk->framesReady() >= mCblk->frameCount ||
+        mCblk->forceReady) {
         mFillingUpStatus = FS_FILLED;
+        mCblk->forceReady = 0;
         return true;
     }
     return false;
@@ -1006,7 +1190,7 @@
     Mutex::Autolock _l(mAudioFlinger->mLock);
     if (mState > STOPPED) {
         mState = STOPPED;
-        // If the track is not active (PAUSED and buffers full), flush buffers  
+        // If the track is not active (PAUSED and buffers full), flush buffers
         if (mAudioFlinger->mActiveTracks.indexOf(this) < 0) {
             reset();
         }
@@ -1038,15 +1222,24 @@
     // NOTE: reset() will reset cblk->user and cblk->server with
     // the risk that at the same time, the AudioMixer is trying to read
     // data. In this case, getNextBuffer() would return a NULL pointer
-    // as audio buffer => the AudioMixer code MUST always test that pointer 
-    // returned by getNextBuffer() is not NULL! 
+    // as audio buffer => the AudioMixer code MUST always test that pointer
+    // returned by getNextBuffer() is not NULL!
     reset();
 }
 
 void AudioFlinger::Track::reset()
 {
-    TrackBase::reset();
-    mFillingUpStatus = FS_FILLING;
+    // Do not reset twice to avoid discarding data written just after a flush and before
+    // the audioflinger thread detects the track is stopped.
+    if (!mResetDone) {
+        TrackBase::reset();
+        // Force underrun condition to avoid false underrun callback until first data is
+        // written to buffer
+        mCblk->flowControlFlag = 1;
+        mCblk->forceReady = 0;
+        mFillingUpStatus = FS_FILLING;        
+        mResetDone = true;
+    }
 }
 
 void AudioFlinger::Track::mute(bool muted)
@@ -1112,26 +1305,15 @@
 
 // ----------------------------------------------------------------------------
 
-sp<AudioFlinger::AudioRecordThread> AudioFlinger::audioRecordThread()
-{
-    Mutex::Autolock _l(mLock);
-    return mAudioRecordThread;
-}
-
-void AudioFlinger::endRecord()
-{
-    Mutex::Autolock _l(mLock);
-    mAudioRecordThread.clear();
-}
-
 sp<IAudioRecord> AudioFlinger::openRecord(
         pid_t pid,
         int streamType,
         uint32_t sampleRate,
         int format,
         int channelCount,
-        int bufferCount,
-        uint32_t flags)
+        int frameCount,
+        uint32_t flags,
+        status_t *status)
 {
     sp<AudioRecordThread> thread;
     sp<RecordTrack> recordTrack;
@@ -1139,46 +1321,46 @@
     sp<Client> client;
     wp<Client> wclient;
     AudioStreamIn* input = 0;
+    int inFrameCount;
+    size_t inputBufferSize;
+    status_t lStatus;
 
     // check calling permissions
     if (!recordingAllowed()) {
+        lStatus = PERMISSION_DENIED;
         goto Exit;
     }
 
     if (uint32_t(streamType) >= AudioRecord::NUM_STREAM_TYPES) {
         LOGE("invalid stream type");
+        lStatus = BAD_VALUE;
         goto Exit;
     }
 
     if (sampleRate > MAX_SAMPLE_RATE) {
         LOGE("Sample rate out of range");
+        lStatus = BAD_VALUE;
         goto Exit;
     }
 
     if (mSampleRate == 0) {
         LOGE("Audio driver not initialized");
+        lStatus = NO_INIT;
         goto Exit;
     }
 
-    // Create audio thread - take mutex to prevent race condition
-    {
-        Mutex::Autolock _l(mLock);
-        if (mAudioRecordThread != 0) {
-            LOGE("Record channel already open");
-            goto Exit;
-        }
-        thread = new AudioRecordThread(this);
-        mAudioRecordThread = thread;
+    if (mAudioRecordThread == 0) {
+        LOGE("Audio record thread not started");
+        lStatus = NO_INIT;
+        goto Exit;
     }
-    // It's safe to release the mutex here since the client doesn't get a
-    // handle until we return from this call
 
-    // open driver, initialize h/w
-    input = mAudioHardware->openInputStream(
-            AudioSystem::PCM_16_BIT, channelCount, sampleRate);
-    if (!input) {
-        LOGE("Error opening input stream");
-        mAudioRecordThread.clear();
+
+    // Check that audio input stream accepts requested audio parameters 
+    inputBufferSize = mAudioHardware->getInputBufferSize(sampleRate, format, channelCount);
+    if (inputBufferSize == 0) {
+        lStatus = BAD_VALUE;
+        LOGE("Bad audio input parameters: sampling rate %u, format %d, channels %d",  sampleRate, format, channelCount);
         goto Exit;
     }
 
@@ -1194,37 +1376,38 @@
         }
     }
 
+    // frameCount must be a multiple of input buffer size
+    inFrameCount = inputBufferSize/channelCount/sizeof(short);
+    frameCount = ((frameCount - 1)/inFrameCount + 1) * inFrameCount;
+
     // create new record track and pass to record thread
     recordTrack = new RecordTrack(this, client, streamType, sampleRate,
-            format, channelCount, bufferCount, input->bufferSize());
-
-    // spin up record thread
-    thread->open(recordTrack, input);
-    thread->run("AudioRecordThread", PRIORITY_URGENT_AUDIO);
+            format, channelCount, frameCount);
 
     // return to handle to client
     recordHandle = new RecordHandle(recordTrack);
+    lStatus = NO_ERROR;
 
 Exit:
+    if (status) {
+        *status = lStatus;
+    }
     return recordHandle;
 }
 
-status_t AudioFlinger::startRecord() {
-    sp<AudioRecordThread> t = audioRecordThread();
-    if (t == 0) return NO_INIT;
-    return t->start();
+status_t AudioFlinger::startRecord(RecordTrack* recordTrack) {
+    if (mAudioRecordThread != 0) {
+        return mAudioRecordThread->start(recordTrack);        
+    }
+    return NO_INIT;
 }
 
-void AudioFlinger::stopRecord() {
-    sp<AudioRecordThread> t = audioRecordThread();
-    if (t != 0) t->stop();
+void AudioFlinger::stopRecord(RecordTrack* recordTrack) {
+    if (mAudioRecordThread != 0) {
+        mAudioRecordThread->stop(recordTrack);
+    }
 }
 
-void AudioFlinger::exitRecord()
-{
-    sp<AudioRecordThread> t = audioRecordThread();
-    if (t != 0) t->exit();
-}
 
 // ----------------------------------------------------------------------------
 
@@ -1235,55 +1418,69 @@
             uint32_t sampleRate,
             int format,
             int channelCount,
-            int bufferCount,
-            int bufferSize)
+            int frameCount)
     :   TrackBase(audioFlinger, client, streamType, sampleRate, format,
-            channelCount, bufferCount, bufferSize),
+            channelCount, frameCount, 0),
             mOverflow(false)
 {
 }
 
 AudioFlinger::RecordTrack::~RecordTrack()
 {
-    mAudioFlinger->audioMixer().deleteTrackName(mName);
-    mAudioFlinger->exitRecord();
+    mAudioFlinger->audioMixer()->deleteTrackName(mName);
 }
 
 status_t AudioFlinger::RecordTrack::getNextBuffer(AudioBufferProvider::Buffer* buffer)
 {
-     audio_track_cblk_t* cblk = this->cblk();
-     const uint32_t u_seq = cblk->user & audio_track_cblk_t::SEQUENCE_MASK;
-     const uint32_t u_buf = cblk->user & audio_track_cblk_t::BUFFER_MASK;
-     const uint32_t s_seq = cblk->server & audio_track_cblk_t::SEQUENCE_MASK;
-     const uint32_t s_buf = cblk->server & audio_track_cblk_t::BUFFER_MASK;
-     
-     // Check if last stepServer failed, try to step now 
-     if (mFlags & TrackBase::STEPSERVER_FAILED) {
-         if (!step())  goto getNextBuffer_exit;
-         LOGV("stepServer recovered");
-         mFlags &= ~TrackBase::STEPSERVER_FAILED;
-     }
+    audio_track_cblk_t* cblk = this->cblk();
+    uint32_t framesAvail;
+    uint32_t framesReq = buffer->frameCount;
 
-     if (LIKELY(s_seq == u_seq || s_buf != u_buf)) {
-         buffer->raw = getBuffer(s_buf);
-         buffer->frameCount = mAudioFlinger->frameCount();
-         return NO_ERROR;
-     }
+     // Check if last stepServer failed, try to step now
+    if (mFlags & TrackBase::STEPSERVER_FAILED) {
+        if (!step()) goto getNextBuffer_exit;
+        LOGV("stepServer recovered");
+        mFlags &= ~TrackBase::STEPSERVER_FAILED;
+    }
 
-getNextBuffer_exit:     
-     buffer->raw = 0;
-     buffer->frameCount = 0;
-     return NOT_ENOUGH_DATA;
+    framesAvail = cblk->framesAvailable_l();
+
+    if (LIKELY(framesAvail)) {
+        uint32_t s = cblk->server;
+        uint32_t bufferEnd = cblk->serverBase + cblk->frameCount;
+
+        if (framesReq > framesAvail) {
+            framesReq = framesAvail;
+        }
+        if (s + framesReq > bufferEnd) {
+            framesReq = bufferEnd - s;
+        }
+
+        buffer->raw = getBuffer(s, framesReq);
+        if (buffer->raw == 0) goto getNextBuffer_exit;
+
+        buffer->frameCount = framesReq;
+        return NO_ERROR;
+    }
+
+getNextBuffer_exit:
+    buffer->raw = 0;
+    buffer->frameCount = 0;
+    return NOT_ENOUGH_DATA;
 }
 
 status_t AudioFlinger::RecordTrack::start()
 {
-    return mAudioFlinger->startRecord();
+    return mAudioFlinger->startRecord(this);
 }
 
 void AudioFlinger::RecordTrack::stop()
 {
-    mAudioFlinger->stopRecord();
+    mAudioFlinger->stopRecord(this);
+    TrackBase::reset();
+    // Force overerrun condition to avoid false overrun callback until first data is
+    // read from buffer
+    mCblk->flowControlFlag = 1;
 }
 
 // ----------------------------------------------------------------------------
@@ -1294,7 +1491,9 @@
 {
 }
 
-AudioFlinger::RecordHandle::~RecordHandle() {}
+AudioFlinger::RecordHandle::~RecordHandle() {
+    stop();
+}
 
 status_t AudioFlinger::RecordHandle::start() {
     LOGV("RecordHandle::start()");
@@ -1318,10 +1517,8 @@
 
 // ----------------------------------------------------------------------------
 
-AudioFlinger::AudioRecordThread::AudioRecordThread(const sp<AudioFlinger>& audioFlinger) :
-    mAudioFlinger(audioFlinger),
-    mRecordTrack(0),
-    mInput(0),
+AudioFlinger::AudioRecordThread::AudioRecordThread(AudioHardwareInterface* audioHardware) :
+    mAudioHardware(audioHardware),
     mActive(false)
 {
 }
@@ -1333,108 +1530,123 @@
 bool AudioFlinger::AudioRecordThread::threadLoop()
 {
     LOGV("AudioRecordThread: start record loop");
+    AudioBufferProvider::Buffer buffer;
+    int inBufferSize = 0;
+    int inFrameCount = 0;
+    AudioStreamIn* input = 0;
 
+    mActive = 0;
+    
     // start recording
     while (!exitPending()) {
         if (!mActive) {
             mLock.lock();
             if (!mActive && !exitPending()) {
                 LOGV("AudioRecordThread: loop stopping");
+                if (input) {
+                    delete input;
+                    input = 0;
+                }
+                mRecordTrack.clear();
+
                 mWaitWorkCV.wait(mLock);
+               
                 LOGV("AudioRecordThread: loop starting");
+                if (mRecordTrack != 0) {
+                    input = mAudioHardware->openInputStream(mRecordTrack->format(), 
+                                            mRecordTrack->channelCount(), 
+                                            mRecordTrack->sampleRate(), 
+                                            &mStartStatus);
+                    if (input != 0) {
+                        inBufferSize = input->bufferSize();
+                        inFrameCount = inBufferSize/input->frameSize();                        
+                    }
+                } else {
+                    mStartStatus = NO_INIT;
+                }
+                if (mStartStatus !=NO_ERROR) {
+                    LOGW("record start failed, status %d", mStartStatus);
+                    mActive = false;
+                    mRecordTrack.clear();                    
+                }
+                mWaitWorkCV.signal();
             }
             mLock.unlock();
-        } else {
-            // promote strong ref so track isn't deleted while we access it
-            sp<RecordTrack> t = mRecordTrack.promote();
+        } else if (mRecordTrack != 0){
 
-            // if we lose the weak reference, client is gone.
-            if (t == 0) {
-                LOGV("AudioRecordThread: client deleted track");
-                break;
-            }
-
-            if (LIKELY(t->getNextBuffer(&mBuffer) == NO_ERROR)) {
-                if (mInput->read(mBuffer.raw, t->mBufferSize) < 0) {
+            buffer.frameCount = inFrameCount;
+            if (LIKELY(mRecordTrack->getNextBuffer(&buffer) == NO_ERROR)) {
+                LOGV("AudioRecordThread read: %d frames", buffer.frameCount);
+                if (input->read(buffer.raw, inBufferSize) < 0) {
                     LOGE("Error reading audio input");
                     sleep(1);
                 }
-                t->releaseBuffer(&mBuffer);
+                mRecordTrack->releaseBuffer(&buffer);
+                mRecordTrack->overflow();
             }
 
             // client isn't retrieving buffers fast enough
             else {
-                if (!t->setOverflow())
+                if (!mRecordTrack->setOverflow())
                     LOGW("AudioRecordThread: buffer overflow");
+                // Release the processor for a while before asking for a new buffer.
+                // This will give the application more chance to read from the buffer and
+                // clear the overflow.
+                usleep(5000);
             }
         }
-    };
+    }
 
-    // close hardware
-    close();
 
-    // delete this object - no more data references after this call
-    mAudioFlinger->endRecord();
+    if (input) {
+        delete input;
+    }
+    mRecordTrack.clear();
+    
     return false;
 }
 
-status_t AudioFlinger::AudioRecordThread::open(const sp<RecordTrack>& recordTrack, AudioStreamIn *input) {
-    LOGV("AudioRecordThread::open");
-    // check for record channel already open
-    AutoMutex lock(&mLock);
-    if (mRecordTrack != NULL) {
-        LOGE("Record channel already open");
-        return ALREADY_EXISTS;
-    }
-    mRecordTrack = recordTrack;
-    mInput = input;
-    return NO_ERROR;
-}
-
-status_t AudioFlinger::AudioRecordThread::start()
+status_t AudioFlinger::AudioRecordThread::start(RecordTrack* recordTrack)
 {
     LOGV("AudioRecordThread::start");
     AutoMutex lock(&mLock);
-    if (mActive) return -EBUSY;
+    mActive = true;
+    // If starting the active track, just reset mActive in case a stop
+    // was pending and exit
+    if (recordTrack == mRecordTrack.get()) return NO_ERROR;
 
-    sp<RecordTrack> t = mRecordTrack.promote();
-    if (t == 0) return UNKNOWN_ERROR;
+    if (mRecordTrack != 0) return -EBUSY;
+
+    mRecordTrack = recordTrack;
 
     // signal thread to start
     LOGV("Signal record thread");
-    mActive = true;
     mWaitWorkCV.signal();
-    return NO_ERROR;
+    mWaitWorkCV.wait(mLock);
+    LOGV("Record started, status %d", mStartStatus);
+    return mStartStatus;
 }
 
-void AudioFlinger::AudioRecordThread::stop() {
+void AudioFlinger::AudioRecordThread::stop(RecordTrack* recordTrack) {
     LOGV("AudioRecordThread::stop");
     AutoMutex lock(&mLock);
-    if (mActive) {
+    if (mActive && (recordTrack == mRecordTrack.get())) {
         mActive = false;
-        mWaitWorkCV.signal();
     }
 }
 
 void AudioFlinger::AudioRecordThread::exit()
 {
     LOGV("AudioRecordThread::exit");
-    AutoMutex lock(&mLock);
-    requestExit();
-    mWaitWorkCV.signal();
+    {
+        AutoMutex lock(&mLock);
+        requestExit();
+        mWaitWorkCV.signal();
+    }
+    requestExitAndWait();
 }
 
 
-status_t AudioFlinger::AudioRecordThread::close()
-{
-    LOGV("AudioRecordThread::close");
-    AutoMutex lock(&mLock);
-    if (!mInput) return NO_INIT;
-    delete mInput;
-    mInput = 0;
-    return NO_ERROR;
-}
-
 status_t AudioFlinger::onTransact(
         uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
 {
diff --git a/libs/audioflinger/AudioFlinger.h b/libs/audioflinger/AudioFlinger.h
index 8c02617..d9f7b49 100644
--- a/libs/audioflinger/AudioFlinger.h
+++ b/libs/audioflinger/AudioFlinger.h
@@ -43,13 +43,17 @@
 class AudioMixer;
 class AudioBuffer;
 
+
 // ----------------------------------------------------------------------------
 
 #define LIKELY( exp )       (__builtin_expect( (exp) != 0, true  ))
 #define UNLIKELY( exp )     (__builtin_expect( (exp) != 0, false ))
 
+
 // ----------------------------------------------------------------------------
 
+static const nsecs_t kStandbyTimeInNsecs = seconds(3);
+
 class AudioFlinger : public BnAudioFlinger, protected Thread
 {
 public:
@@ -69,13 +73,16 @@
                                 uint32_t sampleRate,
                                 int format,
                                 int channelCount,
-                                int bufferCount,
-                                uint32_t flags);
+                                int frameCount,
+                                uint32_t flags,
+                                const sp<IMemory>& sharedBuffer,
+                                status_t *status);
 
     virtual     uint32_t    sampleRate() const;
     virtual     int         channelCount() const;
     virtual     int         format() const;
     virtual     size_t      frameCount() const;
+    virtual     size_t      latency() const;
 
     virtual     status_t    setMasterVolume(float value);
     virtual     status_t    setMasterMute(bool muted);
@@ -128,8 +135,9 @@
                                 uint32_t sampleRate,
                                 int format,
                                 int channelCount,
-                                int bufferCount,
-                                uint32_t flags);
+                                int frameCount,
+                                uint32_t flags,
+                                status_t *status);
 
     virtual     status_t    onTransact(
                                 uint32_t code,
@@ -141,12 +149,15 @@
                             AudioFlinger();
     virtual                 ~AudioFlinger();
     
+    void                    setOutput(AudioStreamOut* output);
+    size_t                  getOutputFrameCount(AudioStreamOut* output);
+
     // Internal dump utilites.
     status_t dumpPermissionDenial(int fd, const Vector<String16>& args);
     status_t dumpClients(int fd, const Vector<String16>& args);
     status_t dumpTracks(int fd, const Vector<String16>& args);
     status_t dumpInternals(int fd, const Vector<String16>& args);
-    
+
     // --- Client ---
     class Client : public RefBase {
     public:
@@ -183,17 +194,17 @@
         };
 
         enum track_flags {
-            STEPSERVER_FAILED = 0x01   //  StepServer could not acquire cblk->lock mutex 
+            STEPSERVER_FAILED = 0x01   //  StepServer could not acquire cblk->lock mutex
         };
-        
+
                             TrackBase(  const sp<AudioFlinger>& audioFlinger,
                                     const sp<Client>& client,
                                     int streamType,
                                     uint32_t sampleRate,
                                     int format,
                                     int channelCount,
-                                    int bufferCount,
-                                    int bufferSize);
+                                    int frameCount,
+                                    const sp<IMemory>& sharedBuffer);
                             ~TrackBase();
 
         virtual status_t    start() = 0;
@@ -203,6 +214,7 @@
     protected:
         friend class AudioFlinger;
         friend class RecordHandle;
+        friend class AudioRecordThread;
 
                             TrackBase(const TrackBase&);
                             TrackBase& operator = (const TrackBase&);
@@ -222,19 +234,11 @@
             return mFormat;
         }
 
-        int channelCount() const {
-            return mChannelCount;
-        }
-
-        int bufferCount() const {
-            return mBufferCount;
-        }
+        int channelCount() const ;
 
         int sampleRate() const;
 
-        void* getBuffer(int n) const {
-            return (char*)mBuffers + n * mBufferSize;
-        }
+        void* getBuffer(uint32_t offset, uint32_t frames) const;
 
         int name() const {
             return mName;
@@ -256,16 +260,15 @@
         sp<IMemory>         mCblkMemory;
         audio_track_cblk_t* mCblk;
         int                 mStreamType;
-        uint8_t             mFormat;
-        uint8_t             mChannelCount;
-        uint8_t             mBufferCount;
-        uint8_t             mFlags;
-        void*               mBuffers;
-        size_t              mBufferSize;
+        void*               mBuffer;
+        void*               mBufferEnd;
+        uint32_t            mFrameCount;
         int                 mName;
         // we don't really need a lock for these
         int                 mState;
         int                 mClientTid;
+        uint8_t             mFormat;
+        uint8_t             mFlags;
     };
 
     // playback track
@@ -277,8 +280,8 @@
                                     uint32_t sampleRate,
                                     int format,
                                     int channelCount,
-                                    int bufferCount,
-                                    int bufferSize);
+                                    int frameCount,
+                                    const sp<IMemory>& sharedBuffer);
                             ~Track();
 
                 void        dump(char* buffer, size_t size);
@@ -312,7 +315,7 @@
             return mState == PAUSED;
         }
 
-        bool isReady(uint32_t u, int32_t s) const;
+        bool isReady() const;
 
         void setPaused() { mState = PAUSED; }
         void reset();
@@ -324,6 +327,8 @@
         enum {FS_FILLING, FS_FILLED, FS_ACTIVE};
         mutable uint8_t     mFillingUpStatus;
         int8_t              mRetryCount;
+        sp<IMemory>         mSharedBuffer;
+        bool                mResetDone;
     };  // end of Track
 
     friend class AudioBuffer;
@@ -366,8 +371,8 @@
                 void        remove_track_l(wp<Track> track, int name);
                 void        destroyTrack(const sp<Track>& track);
 
-                AudioMixer& audioMixer() {
-                    return *mAudioMixer;
+                AudioMixer* audioMixer() {
+                    return mAudioMixer;
                 }
 
     // record track
@@ -379,8 +384,7 @@
                                     uint32_t sampleRate,
                                     int format,
                                     int channelCount,
-                                    int bufferCount,
-                                    int bufferSize);
+                                    int frameCount);
                             ~RecordTrack();
 
         virtual status_t    start();
@@ -419,43 +423,34 @@
     class AudioRecordThread : public Thread
     {
     public:
-        AudioRecordThread(const sp<AudioFlinger>& audioFlinger);
+        AudioRecordThread(AudioHardwareInterface* audioHardware);
         virtual             ~AudioRecordThread();
         virtual bool        threadLoop();
         virtual status_t    readyToRun() { return NO_ERROR; }
         virtual void        onFirstRef() {}
 
-                status_t    open(const sp<RecordTrack>& recordTrack, AudioStreamIn *input);
-                status_t    start();
-                void        stop();
-                status_t    close();
+                status_t    start(RecordTrack* recordTrack);
+                void        stop(RecordTrack* recordTrack);
                 void        exit();
-                
-                bool        isOpen() { return bool(mRecordTrack != NULL); }
 
     private:
                 AudioRecordThread();
-                sp<AudioFlinger>                    mAudioFlinger;
-                wp<RecordTrack>                     mRecordTrack;
-                AudioStreamIn*                      mInput;
+                AudioHardwareInterface              *mAudioHardware;
+                sp<RecordTrack>                     mRecordTrack;
                 Mutex                               mLock;
                 Condition                           mWaitWorkCV;
-                AudioBufferProvider::Buffer         mBuffer;
                 volatile bool                       mActive;
+                status_t                            mStartStatus;
     };
 
     friend class AudioRecordThread;
 
-                sp<AudioRecordThread> audioRecordThread();
-                void        endRecord();
-                status_t    startRecord();
-                void        stopRecord();
-                void        exitRecord();
-                
-                AudioHardwareInterface* audioHardware() { return mAudioHardware; }
+                status_t    startRecord(RecordTrack* recordTrack);
+                void        stopRecord(RecordTrack* recordTrack);
 
     mutable     Mutex                                       mHardwareLock;
     mutable     Mutex                                       mLock;
+    mutable     Mutex                                       mOutputLock;
     mutable     Condition                                   mWaitWorkCV;
                 DefaultKeyedVector< pid_t, wp<Client> >     mClients;
                 SortedVector< wp<Track> >                   mActiveTracks;
@@ -465,15 +460,19 @@
                 bool                                mMasterMute;
                 stream_type_t                       mStreamTypes[AudioTrack::NUM_STREAM_TYPES];
 
+                AudioMixer*                         mHardwareAudioMixer;
+                AudioMixer*                         mA2dpAudioMixer;
                 AudioMixer*                         mAudioMixer;
                 AudioHardwareInterface*             mAudioHardware;
+                AudioHardwareInterface*             mA2dpAudioInterface;
+                AudioStreamOut*                     mHardwareOutput;
+                AudioStreamOut*                     mA2dpOutput;
                 AudioStreamOut*                     mOutput;
                 sp<AudioRecordThread>               mAudioRecordThread;
                 uint32_t                            mSampleRate;
                 size_t                              mFrameCount;
                 int                                 mChannelCount;
                 int                                 mFormat;
-                int                                 mMixBufferSize;
                 int16_t*                            mMixBuffer;
     mutable     int                                 mHardwareStatus;
                 nsecs_t                             mLastWriteTime;
diff --git a/libs/audioflinger/AudioHardwareGeneric.cpp b/libs/audioflinger/AudioHardwareGeneric.cpp
index b1e5b7f..e6a163b 100644
--- a/libs/audioflinger/AudioHardwareGeneric.cpp
+++ b/libs/audioflinger/AudioHardwareGeneric.cpp
@@ -2,16 +2,16 @@
 **
 ** Copyright 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 
+** 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 
+**     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 
+** 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.
 */
 
@@ -68,16 +68,25 @@
 }
 
 AudioStreamOut* AudioHardwareGeneric::openOutputStream(
-        int format, int channelCount, uint32_t sampleRate)
+        int format, int channelCount, uint32_t sampleRate, status_t *status)
 {
     AutoMutex lock(mLock);
 
     // only one output stream allowed
-    if (mOutput) return 0;
+    if (mOutput) {
+        if (status) {
+            *status = INVALID_OPERATION;
+        }
+        return 0;
+    }
 
     // create new output stream
     AudioStreamOutGeneric* out = new AudioStreamOutGeneric();
-    if (out->set(this, mFd, format, channelCount, sampleRate) == NO_ERROR) {
+    status_t lStatus = out->set(this, mFd, format, channelCount, sampleRate);
+    if (status) {
+        *status = lStatus;
+    }
+    if (lStatus == NO_ERROR) {
         mOutput = out;
     } else {
         delete out;
@@ -90,16 +99,25 @@
 }
 
 AudioStreamIn* AudioHardwareGeneric::openInputStream(
-        int format, int channelCount, uint32_t sampleRate)
+        int format, int channelCount, uint32_t sampleRate, status_t *status)
 {
     AutoMutex lock(mLock);
 
     // only one input stream allowed
-    if (mInput) return 0;
+    if (mInput) {
+        if (status) {
+            *status = INVALID_OPERATION;
+        }
+        return 0;
+    }
 
     // create new output stream
     AudioStreamInGeneric* in = new AudioStreamInGeneric();
-    if (in->set(this, mFd, format, channelCount, sampleRate) == NO_ERROR) {
+    status_t lStatus = in->set(this, mFd, format, channelCount, sampleRate);
+    if (status) {
+        *status = lStatus;
+    }
+    if (lStatus == NO_ERROR) {
         mInput = in;
     } else {
         delete in;
diff --git a/libs/audioflinger/AudioHardwareGeneric.h b/libs/audioflinger/AudioHardwareGeneric.h
index 10cc45d..a2342cd 100644
--- a/libs/audioflinger/AudioHardwareGeneric.h
+++ b/libs/audioflinger/AudioHardwareGeneric.h
@@ -2,16 +2,16 @@
 **
 ** Copyright 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 
+** 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 
+**     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 
+** 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.
 */
 
@@ -23,7 +23,7 @@
 
 #include <utils/threads.h>
 
-#include <hardware/AudioHardwareInterface.h>
+#include <hardware/AudioHardwareBase.h>
 
 namespace android {
 
@@ -47,6 +47,7 @@
     virtual size_t      bufferSize() const { return 4096; }
     virtual int         channelCount() const { return 2; }
     virtual int         format() const { return AudioSystem::PCM_16_BIT; }
+    virtual uint32_t    latency() const { return 0; }
     virtual status_t    setVolume(float volume) { return INVALID_OPERATION; }
     virtual ssize_t     write(const void* buffer, size_t bytes);
     virtual status_t    dump(int fd, const Vector<String16>& args);
@@ -76,6 +77,7 @@
     virtual status_t    setGain(float gain) { return INVALID_OPERATION; }
     virtual ssize_t     read(void* buffer, ssize_t bytes);
     virtual status_t    dump(int fd, const Vector<String16>& args);
+    virtual status_t    standby() { return NO_ERROR; }
 
 private:
     AudioHardwareGeneric *mAudioHardware;
@@ -84,7 +86,7 @@
 };
 
 
-class AudioHardwareGeneric : public  AudioHardwareInterface
+class AudioHardwareGeneric : public AudioHardwareBase
 {
 public:
                         AudioHardwareGeneric();
@@ -105,12 +107,14 @@
     virtual AudioStreamOut* openOutputStream(
             int format=0,
             int channelCount=0,
-            uint32_t sampleRate=0);
+            uint32_t sampleRate=0,
+            status_t *status=0);
 
     virtual AudioStreamIn* openInputStream(
             int format,
             int channelCount,
-            uint32_t sampleRate);
+            uint32_t sampleRate,
+            status_t *status);
 
             void            closeOutputStream(AudioStreamOutGeneric* out);
             void            closeInputStream(AudioStreamInGeneric* in);
@@ -120,7 +124,7 @@
 
 private:
     status_t                dumpInternals(int fd, const Vector<String16>& args);
-    
+
     Mutex                   mLock;
     AudioStreamOutGeneric   *mOutput;
     AudioStreamInGeneric    *mInput;
diff --git a/libs/audioflinger/AudioHardwareInterface.cpp b/libs/audioflinger/AudioHardwareInterface.cpp
index 7387b3d..ac76a19 100644
--- a/libs/audioflinger/AudioHardwareInterface.cpp
+++ b/libs/audioflinger/AudioHardwareInterface.cpp
@@ -26,7 +26,7 @@
 #include "AudioHardwareStub.h"
 #include "AudioHardwareGeneric.h"
 
-// #define DUMP_FLINGER_OUT        // if defined allows recording samples in a file
+//#define DUMP_FLINGER_OUT        // if defined allows recording samples in a file
 #ifdef DUMP_FLINGER_OUT
 #include "AudioDumpInterface.h"
 #endif
@@ -54,6 +54,7 @@
     "SPEAKER ",
     "BLUETOOTH ",
     "HEADSET "
+    "BLUETOOTH_A2DP "
 };
 static const char* routeNone = "NONE";
 
@@ -115,24 +116,10 @@
     // This code adds a record of buffers in a file to write calls made by AudioFlinger.
     // It replaces the current AudioHardwareInterface object by an intermediate one which
     // will record buffers in a file (after sending them to hardware) for testing purpose.
-    // This feature is enabled by defining symbol DUMP_FLINGER_OUT and setting environement
-    // "audioflinger.dump = 1". The output file is "tmp/FlingerOut.pcm". Pause are not recorded
-    // in the file.
+    // This feature is enabled by defining symbol DUMP_FLINGER_OUT.
+    // The output file is FLINGER_DUMP_NAME. Pause are not recorded in the file.
     
-    // read dump mode
-    property_get("audioflinger.dump", value, "0");
-    switch(value[0]) {
-    case '1':
-        LOGV("Dump mode");
-        hw = new AudioDumpInterface(hw);    // replace interface
-        return hw;
-        break;
-    case '0':
-    default:
-        LOGV("No Dump mode");
-        return hw;
-        break;
-    }
+    hw = new AudioDumpInterface(hw);    // replace interface
 #endif
     return hw;
 }
@@ -143,7 +130,7 @@
 
 AudioStreamIn::~AudioStreamIn() {}
 
-AudioHardwareInterface::AudioHardwareInterface()
+AudioHardwareBase::AudioHardwareBase()
 {
     // force a routing update on initialization
     memset(&mRoutes, 0, sizeof(mRoutes));
@@ -151,7 +138,7 @@
 }
 
 // generics for audio routing - the real work is done in doRouting
-status_t AudioHardwareInterface::setRouting(int mode, uint32_t routes)
+status_t AudioHardwareBase::setRouting(int mode, uint32_t routes)
 {
 #if LOG_ROUTING_CALLS
     LOGD("setRouting: mode=%s, routes=[%s]", displayMode(mode), displayRoutes(routes));
@@ -173,7 +160,7 @@
     return doRouting();
 }
 
-status_t AudioHardwareInterface::getRouting(int mode, uint32_t* routes)
+status_t AudioHardwareBase::getRouting(int mode, uint32_t* routes)
 {
     if (mode == AudioSystem::MODE_CURRENT)
         mode = mMode;
@@ -187,7 +174,7 @@
     return NO_ERROR;
 }
 
-status_t AudioHardwareInterface::setMode(int mode)
+status_t AudioHardwareBase::setMode(int mode)
 {
 #if LOG_ROUTING_CALLS
     LOGD("setMode(%s)", displayMode(mode));
@@ -204,25 +191,45 @@
     return doRouting();
 }
 
-status_t AudioHardwareInterface::getMode(int* mode)
+status_t AudioHardwareBase::getMode(int* mode)
 {
     // Implement: set audio routing
     *mode = mMode;
     return NO_ERROR;
 }
 
-status_t AudioHardwareInterface::setParameter(const char* key, const char* value)
+status_t AudioHardwareBase::setParameter(const char* key, const char* value)
 {
     // default implementation is to ignore
     return NO_ERROR;
 }
 
-status_t AudioHardwareInterface::dumpState(int fd, const Vector<String16>& args)
+
+// default implementation
+size_t AudioHardwareBase::getInputBufferSize(uint32_t sampleRate, int format, int channelCount)
+{
+    if (sampleRate != 8000) {
+        LOGW("getInputBufferSize bad sampling rate: %d", sampleRate);
+        return 0;
+    }
+    if (format != AudioSystem::PCM_16_BIT) {
+        LOGW("getInputBufferSize bad format: %d", format);
+        return 0;
+    }
+    if (channelCount != 1) {
+        LOGW("getInputBufferSize bad channel count: %d", channelCount);
+        return 0;
+    }
+
+    return 320;
+}
+
+status_t AudioHardwareBase::dumpState(int fd, const Vector<String16>& args)
 {
     const size_t SIZE = 256;
     char buffer[SIZE];
     String8 result;
-    snprintf(buffer, SIZE, "AudioHardwareInterface::dumpState\n");
+    snprintf(buffer, SIZE, "AudioHardwareBase::dumpState\n");
     result.append(buffer);
     snprintf(buffer, SIZE, "\tmMode: %d\n", mMode);
     result.append(buffer);
diff --git a/libs/audioflinger/AudioHardwareStub.cpp b/libs/audioflinger/AudioHardwareStub.cpp
index 0046db8..d309902 100644
--- a/libs/audioflinger/AudioHardwareStub.cpp
+++ b/libs/audioflinger/AudioHardwareStub.cpp
@@ -2,16 +2,16 @@
 **
 ** Copyright 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 
+** 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 
+**     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 
+** 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.
 */
 
@@ -47,20 +47,28 @@
 }
 
 AudioStreamOut* AudioHardwareStub::openOutputStream(
-        int format, int channelCount, uint32_t sampleRate)
+        int format, int channelCount, uint32_t sampleRate, status_t *status)
 {
     AudioStreamOutStub* out = new AudioStreamOutStub();
-    if (out->set(format, channelCount, sampleRate) == NO_ERROR)
+    status_t lStatus = out->set(format, channelCount, sampleRate);
+    if (status) {
+        *status = lStatus;
+    }
+    if (lStatus == NO_ERROR)
         return out;
     delete out;
     return 0;
 }
 
 AudioStreamIn* AudioHardwareStub::openInputStream(
-        int format, int channelCount, uint32_t sampleRate)
+        int format, int channelCount, uint32_t sampleRate, status_t *status)
 {
     AudioStreamInStub* in = new AudioStreamInStub();
-    if (in->set(format, channelCount, sampleRate) == NO_ERROR)
+    status_t lStatus = in->set(format, channelCount, sampleRate);
+    if (status) {
+        *status = lStatus;
+    }
+    if (lStatus == NO_ERROR)
         return in;
     delete in;
     return 0;
@@ -102,7 +110,7 @@
     if (format == 0) format = AudioSystem::PCM_16_BIT;
     if (channels == 0) channels = channelCount();
     if (rate == 0) rate = sampleRate();
-    
+
     if ((format == AudioSystem::PCM_16_BIT) &&
             (channels == channelCount()) &&
             (rate == sampleRate()))
@@ -129,7 +137,7 @@
     snprintf(buffer, SIZE, "\tformat: %d\n", format());
     result.append(buffer);
     ::write(fd, result.string(), result.size());
-    return NO_ERROR; 
+    return NO_ERROR;
 }
 
 // ----------------------------------------------------------------------------
diff --git a/libs/audioflinger/AudioHardwareStub.h b/libs/audioflinger/AudioHardwareStub.h
index 1a61552..5316d60 100644
--- a/libs/audioflinger/AudioHardwareStub.h
+++ b/libs/audioflinger/AudioHardwareStub.h
@@ -2,16 +2,16 @@
 **
 ** Copyright 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 
+** 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 
+**     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 
+** 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.
 */
 
@@ -21,7 +21,7 @@
 #include <stdint.h>
 #include <sys/types.h>
 
-#include <hardware/AudioHardwareInterface.h>
+#include <hardware/AudioHardwareBase.h>
 
 namespace android {
 
@@ -34,6 +34,7 @@
     virtual size_t      bufferSize() const { return 4096; }
     virtual int         channelCount() const { return 2; }
     virtual int         format() const { return AudioSystem::PCM_16_BIT; }
+    virtual uint32_t    latency() const { return 0; }
     virtual status_t    setVolume(float volume) { return NO_ERROR; }
     virtual ssize_t     write(const void* buffer, size_t bytes);
     virtual status_t    dump(int fd, const Vector<String16>& args);
@@ -49,9 +50,10 @@
     virtual status_t    setGain(float gain) { return NO_ERROR; }
     virtual ssize_t     read(void* buffer, ssize_t bytes);
     virtual status_t    dump(int fd, const Vector<String16>& args);
+    virtual status_t    standby() { return NO_ERROR; }
 };
 
-class AudioHardwareStub : public  AudioHardwareInterface
+class AudioHardwareStub : public  AudioHardwareBase
 {
 public:
                         AudioHardwareStub();
@@ -72,12 +74,14 @@
     virtual AudioStreamOut* openOutputStream(
                                 int format=0,
                                 int channelCount=0,
-                                uint32_t sampleRate=0);
+                                uint32_t sampleRate=0,
+                                status_t *status=0);
 
     virtual AudioStreamIn* openInputStream(
                                 int format,
                                 int channelCount,
-                                uint32_t sampleRate);
+                                uint32_t sampleRate,
+                                status_t *status);
 
 protected:
     virtual status_t    doRouting() { return NO_ERROR; }
diff --git a/libs/audioflinger/AudioMixer.cpp b/libs/audioflinger/AudioMixer.cpp
index 9f1b17f..b03467f 100644
--- a/libs/audioflinger/AudioMixer.cpp
+++ b/libs/audioflinger/AudioMixer.cpp
@@ -2,16 +2,16 @@
 **
 ** Copyright 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 
+** 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 
+**     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 
+** 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.
 */
 
@@ -247,8 +247,8 @@
 void AudioMixer::track_t::adjustVolumeRamp()
 {
     for (int i=0 ; i<2 ; i++) {
-        if (((volumeInc[i]>0) && ((prevVolume[i]>>16) >= volume[i])) ||
-            ((volumeInc[i]<0) && ((prevVolume[i]>>16) <= volume[i]))) {
+        if (((volumeInc[i]>0) && (((prevVolume[i]+volumeInc[i])>>16) >= volume[i])) ||
+            ((volumeInc[i]<0) && (((prevVolume[i]+volumeInc[i])>>16) <= volume[i]))) {
             volumeInc[i] = 0;
             prevVolume[i] = volume[i]<<16;
         }
@@ -307,7 +307,7 @@
         n |= NEEDS_CHANNEL_1 + t.channelCount - 1;
         n |= NEEDS_FORMAT_16;
         n |= t.doesResample() ? NEEDS_RESAMPLE_ENABLED : NEEDS_RESAMPLE_DISABLED;
-        
+       
         if (t.volumeInc[0]|t.volumeInc[1]) {
             volumeRamp = 1;
         } else if (!t.doesResample() && t.volumeRL == 0) {
@@ -370,7 +370,7 @@
 
    state->hook(state, output);
 
-   // Now that the volume ramp has been done, set optimal state and 
+   // Now that the volume ramp has been done, set optimal state and
    // track hooks for subsequent mixer process
    if (countActiveTracks) {
        int allMuted = 1;
@@ -397,7 +397,7 @@
    }
 }
 
-static inline 
+static inline
 int32_t mulAdd(int16_t in, int16_t v, int32_t a)
 {
 #if defined(__arm__) && !defined(__thumb__)
@@ -412,7 +412,7 @@
 #endif
 }
 
-static inline 
+static inline
 int32_t mul(int16_t in, int16_t v)
 {
 #if defined(__arm__) && !defined(__thumb__)
@@ -427,7 +427,7 @@
 #endif
 }
 
-static inline 
+static inline
 int32_t mulAddRL(int left, uint32_t inRL, uint32_t vRL, int32_t a)
 {
 #if defined(__arm__) && !defined(__thumb__)
@@ -453,7 +453,7 @@
 #endif
 }
 
-static inline 
+static inline
 int32_t mulRL(int left, uint32_t inRL, uint32_t vRL)
 {
 #if defined(__arm__) && !defined(__thumb__)
@@ -513,7 +513,7 @@
     //LOGD("[0] %p: inc=%f, v0=%f, v1=%d, final=%f, count=%d",
     //        t, vlInc/65536.0f, vl/65536.0f, t->volume[0],
     //       (vl + vlInc*frameCount)/65536.0f, frameCount);
-    
+   
     // ramp volume
     do {
         *out++ += (vl >> 16) * (*temp++ >> 12);
@@ -548,7 +548,7 @@
             vl += vlInc;
             vr += vrInc;
         } while (--frameCount);
-        
+       
         t->prevVolume[0] = vl;
         t->prevVolume[1] = vr;
         t->adjustVolumeRamp();
@@ -590,7 +590,7 @@
             vl += vlInc;
             vr += vrInc;
         } while (--frameCount);
-        
+       
         t->prevVolume[0] = vl;
         t->prevVolume[1] = vr;
         t->adjustVolumeRamp();
@@ -609,7 +609,7 @@
     t->in = in;
 }
 
-inline 
+inline
 void AudioMixer::ditherAndClamp(int32_t* out, int32_t const *sums, size_t c)
 {
     for (size_t i=0 ; i<c ; i++) {
@@ -633,8 +633,12 @@
         const int i = 31 - __builtin_clz(en);
         en &= ~(1<<i);
         track_t& t = state->tracks[i];
-        t.bufferProvider->getNextBuffer(&t.buffer);
-        if (t.buffer.raw) {
+        size_t outFrames = state->frameCount;
+        while (outFrames) {
+            t.buffer.frameCount = outFrames;
+            t.bufferProvider->getNextBuffer(&t.buffer);
+            if (!t.buffer.raw) break;
+            outFrames -= t.buffer.frameCount;
             t.bufferProvider->releaseBuffer(&t.buffer);
         }
     }
@@ -652,12 +656,14 @@
         const int i = 31 - __builtin_clz(en);
         en &= ~(1<<i);
         track_t& t = state->tracks[i];
+        t.buffer.frameCount = state->frameCount;
         t.bufferProvider->getNextBuffer(&t.buffer);
+        t.frameCount = t.buffer.frameCount;
         t.in = t.buffer.raw;
         // t.in == NULL can happen if the track was flushed just after having
         // been enabled for mixing.
         if (t.in == NULL)
-            enabledTracks &= ~(1<<i); 
+            enabledTracks &= ~(1<<i);
     }
 
     // this assumes output 16 bits stereo, no resampling
@@ -671,12 +677,31 @@
             const int i = 31 - __builtin_clz(en);
             en &= ~(1<<i);
             track_t& t = state->tracks[i];
-            (t.hook)(&t, outTemp, BLOCKSIZE, state->resampleTemp);
+            size_t outFrames = BLOCKSIZE;
+           
+            while (outFrames) {
+                size_t inFrames = (t.frameCount > outFrames)?outFrames:t.frameCount;
+                if (inFrames) {
+                    (t.hook)(&t, outTemp + (BLOCKSIZE-outFrames)*MAX_NUM_CHANNELS, inFrames, state->resampleTemp);
+                    t.frameCount -= inFrames;
+                    outFrames -= inFrames;
+                }
+                if (t.frameCount == 0 && outFrames) {
+                    t.bufferProvider->releaseBuffer(&t.buffer);
+                    t.buffer.frameCount = numFrames - (BLOCKSIZE - outFrames);
+                    t.bufferProvider->getNextBuffer(&t.buffer);
+                    t.in = t.buffer.raw;
+                    if (t.in == NULL) {
+                        enabledTracks &= ~(1<<i);
+                        break;
+                    }
+                    t.frameCount = t.buffer.frameCount;
+                 }
+            }
         }
 
         ditherAndClamp(out, outTemp, BLOCKSIZE);
         out += BLOCKSIZE;
-
         numFrames -= BLOCKSIZE;
     } while (numFrames);
 
@@ -713,12 +738,19 @@
         if ((t.needs & NEEDS_RESAMPLE__MASK) == NEEDS_RESAMPLE_ENABLED) {
             (t.hook)(&t, outTemp, numFrames, state->resampleTemp);
         } else {
-            t.bufferProvider->getNextBuffer(&t.buffer);
-            t.in = t.buffer.raw;
-            // t.in == NULL can happen if the track was flushed just after having
-            // been enabled for mixing.
-            if (t.in) {
-                (t.hook)(&t, outTemp, numFrames, state->resampleTemp);
+
+            size_t outFrames = numFrames;
+           
+            while (outFrames) {
+                t.buffer.frameCount = outFrames;
+                t.bufferProvider->getNextBuffer(&t.buffer);
+                t.in = t.buffer.raw;
+                // t.in == NULL can happen if the track was flushed just after having
+                // been enabled for mixing.
+                if (t.in == NULL) break;
+
+                (t.hook)(&t, outTemp + (numFrames-outFrames)*MAX_NUM_CHANNELS, t.buffer.frameCount, state->resampleTemp);
+                outFrames -= t.buffer.frameCount;
                 t.bufferProvider->releaseBuffer(&t.buffer);
             }
         }
@@ -734,45 +766,51 @@
     const track_t& t = state->tracks[i];
 
     AudioBufferProvider::Buffer& b(t.buffer);
-    t.bufferProvider->getNextBuffer(&b);
-    int16_t const *in = t.buffer.i16;
-
-    // in == NULL can happen if the track was flushed just after having
-    // been enabled for mixing.
-    if (in == NULL) {
-        memset(output, 0, state->frameCount*MAX_NUM_CHANNELS*sizeof(int16_t));
-        return;
-    }
-    
+   
     int32_t* out = static_cast<int32_t*>(output);
     size_t numFrames = state->frameCount;
+  
     const int16_t vl = t.volume[0];
     const int16_t vr = t.volume[1];
     const uint32_t vrl = t.volumeRL;
-    if (UNLIKELY(uint32_t(vl) > UNITY_GAIN || uint32_t(vr) > UNITY_GAIN)) {
-        // volume is boosted, so we might need to clamp even though
-        // we process only one track.
-        do {
-            uint32_t rl = *reinterpret_cast<uint32_t const *>(in);
-            in += 2;
-            int32_t l = mulRL(1, rl, vrl) >> 12;
-            int32_t r = mulRL(0, rl, vrl) >> 12;
-            // clamping...
-            l = clamp16(l);
-            r = clamp16(r);
-            *out++ = (r<<16) | (l & 0xFFFF);
-        } while (--numFrames);
-    } else {
-        do {
-            uint32_t rl = *reinterpret_cast<uint32_t const *>(in);
-            in += 2;
-            int32_t l = mulRL(1, rl, vrl) >> 12;
-            int32_t r = mulRL(0, rl, vrl) >> 12;
-            *out++ = (r<<16) | (l & 0xFFFF);
-        } while (--numFrames);
-    }
+    while (numFrames) {
+        b.frameCount = numFrames;
+        t.bufferProvider->getNextBuffer(&b);
+        int16_t const *in = b.i16;
 
-    t.bufferProvider->releaseBuffer(&b);
+        // in == NULL can happen if the track was flushed just after having
+        // been enabled for mixing.
+        if (in == NULL) {
+            memset(out, 0, numFrames*MAX_NUM_CHANNELS*sizeof(int16_t));
+            return;
+        }
+        size_t outFrames = b.frameCount;
+       
+        if (UNLIKELY(uint32_t(vl) > UNITY_GAIN || uint32_t(vr) > UNITY_GAIN)) {
+            // volume is boosted, so we might need to clamp even though
+            // we process only one track.
+            do {
+                uint32_t rl = *reinterpret_cast<uint32_t const *>(in);
+                in += 2;
+                int32_t l = mulRL(1, rl, vrl) >> 12;
+                int32_t r = mulRL(0, rl, vrl) >> 12;
+                // clamping...
+                l = clamp16(l);
+                r = clamp16(r);
+                *out++ = (r<<16) | (l & 0xFFFF);
+            } while (--outFrames);
+        } else {
+            do {
+                uint32_t rl = *reinterpret_cast<uint32_t const *>(in);
+                in += 2;
+                int32_t l = mulRL(1, rl, vrl) >> 12;
+                int32_t r = mulRL(0, rl, vrl) >> 12;
+                *out++ = (r<<16) | (l & 0xFFFF);
+            } while (--outFrames);
+        }
+        numFrames -= b.frameCount;
+        t.bufferProvider->releaseBuffer(&b);
+    }
 }
 
 // 2 tracks is also a common case
@@ -784,71 +822,89 @@
     i = 31 - __builtin_clz(en);
     const track_t& t0 = state->tracks[i];
     AudioBufferProvider::Buffer& b0(t0.buffer);
-    t0.bufferProvider->getNextBuffer(&b0);
 
     en &= ~(1<<i);
     i = 31 - __builtin_clz(en);
     const track_t& t1 = state->tracks[i];
     AudioBufferProvider::Buffer& b1(t1.buffer);
-    t1.bufferProvider->getNextBuffer(&b1);
-
+   
     int16_t const *in0;
     const int16_t vl0 = t0.volume[0];
     const int16_t vr0 = t0.volume[1];
+    size_t frameCount0 = 0;
+  
     int16_t const *in1;
     const int16_t vl1 = t1.volume[0];
     const int16_t vr1 = t1.volume[1];
-    size_t numFrames = state->frameCount;
+    size_t frameCount1 = 0;
+   
     int32_t* out = static_cast<int32_t*>(output);
+    size_t numFrames = state->frameCount;
+    int16_t const *buff = NULL;
 
-    // t0/1.buffer.i16 == NULL can happen if the track was flushed just after having
-    // been enabled for mixing.
-    if (t0.buffer.i16 != NULL) {
-        in0 = t0.buffer.i16;
-        if (t1.buffer.i16 != NULL) {
-            in1 = t1.buffer.i16;
-        } else {
-            in1 = new int16_t[MAX_NUM_CHANNELS * state->frameCount];
-            memset((void *)in1, 0, state->frameCount*MAX_NUM_CHANNELS*sizeof(int16_t));
+  
+    while (numFrames) {
+   
+        if (frameCount0 == 0) {
+            b0.frameCount = numFrames;
+            t0.bufferProvider->getNextBuffer(&b0);
+            if (b0.i16 == NULL) {
+                if (buff == NULL) {
+                    buff = new int16_t[MAX_NUM_CHANNELS * state->frameCount];
+                }
+                in0 = buff;
+                b0.frameCount = numFrames;
+            } else {
+                in0 = b0.i16;
+            }
+            frameCount0 = b0.frameCount;
         }
-    } else {
-        in0 = new int16_t[MAX_NUM_CHANNELS * state->frameCount];
-        memset((void *)in0, 0, state->frameCount*MAX_NUM_CHANNELS*sizeof(int16_t));
-        if (t1.buffer.i16 != NULL) {
-            in1 = t1.buffer.i16;
-        } else {
-            in1 = in0;
+        if (frameCount1 == 0) {
+            b1.frameCount = numFrames;
+            t1.bufferProvider->getNextBuffer(&b1);
+            if (b1.i16 == NULL) {
+                if (buff == NULL) {
+                    buff = new int16_t[MAX_NUM_CHANNELS * state->frameCount];
+                }
+                in1 = buff;
+                b1.frameCount = numFrames;
+               } else {
+                in1 = b1.i16;
+            }
+            frameCount1 = b1.frameCount;
         }
-    }
-    
-    do {
-        int32_t l0 = *in0++;
-        int32_t r0 = *in0++;
-        l0 = mul(l0, vl0);
-        r0 = mul(r0, vr0);
-        int32_t l = *in1++;
-        int32_t r = *in1++;
-        l = mulAdd(l, vl1, l0) >> 12;
-        r = mulAdd(r, vr1, r0) >> 12;
-        // clamping...
-        l = clamp16(l);
-        r = clamp16(r);
-        *out++ = (r<<16) | (l & 0xFFFF);
-    } while (--numFrames);
+       
+        size_t outFrames = frameCount0 < frameCount1?frameCount0:frameCount1;
 
-    
-    if (t0.buffer.i16 != NULL) {
-        t0.bufferProvider->releaseBuffer(&b0);
-        if (t1.buffer.i16 != NULL) {
-            t1.bufferProvider->releaseBuffer(&b1);
-        } else {
-            delete [] in1;
+        numFrames -= outFrames;
+        frameCount0 -= outFrames;
+        frameCount1 -= outFrames;
+       
+        do {
+            int32_t l0 = *in0++;
+            int32_t r0 = *in0++;
+            l0 = mul(l0, vl0);
+            r0 = mul(r0, vr0);
+            int32_t l = *in1++;
+            int32_t r = *in1++;
+            l = mulAdd(l, vl1, l0) >> 12;
+            r = mulAdd(r, vr1, r0) >> 12;
+            // clamping...
+            l = clamp16(l);
+            r = clamp16(r);
+            *out++ = (r<<16) | (l & 0xFFFF);
+        } while (--outFrames);
+       
+        if (frameCount0 == 0) {
+            t0.bufferProvider->releaseBuffer(&b0);
         }
-    } else {
-        delete [] in0;
-        if (t1.buffer.i16 != NULL) {
+        if (frameCount1 == 0) {
             t1.bufferProvider->releaseBuffer(&b1);
         }
+    }   
+       
+    if (buff != NULL) {
+        delete [] buff;       
     }
 }
 
diff --git a/libs/audioflinger/AudioMixer.h b/libs/audioflinger/AudioMixer.h
index 9ca109f..72ca28a 100644
--- a/libs/audioflinger/AudioMixer.h
+++ b/libs/audioflinger/AudioMixer.h
@@ -2,16 +2,16 @@
 **
 ** Copyright 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 
+** 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 
+**     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 
+** 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.
 */
 
@@ -130,7 +130,7 @@
 
         int32_t     volumeInc[2];
 
-        uint16_t    reserved;
+        uint16_t    frameCount;
 
         uint8_t     channelCount : 4;
         uint8_t     enabled      : 1;
diff --git a/libs/audioflinger/AudioResampler.cpp b/libs/audioflinger/AudioResampler.cpp
index c93ead3..5dabacb 100644
--- a/libs/audioflinger/AudioResampler.cpp
+++ b/libs/audioflinger/AudioResampler.cpp
@@ -14,17 +14,23 @@
  * limitations under the License.
  */
 
+#define LOG_TAG "AudioResampler"
+//#define LOG_NDEBUG 0
+
 #include <stdint.h>
 #include <stdlib.h>
 #include <sys/types.h>
 #include <cutils/log.h>
 #include <cutils/properties.h>
-
 #include "AudioResampler.h"
 #include "AudioResamplerSinc.h"
 #include "AudioResamplerCubic.h"
 
 namespace android {
+
+#ifdef __ARM_ARCH_5E__  // optimized asm option
+    #define ASM_ARM_RESAMP1 // enable asm optimisation for ResamplerOrder1
+#endif // __ARM_ARCH_5E__
 // ----------------------------------------------------------------------------
 
 class AudioResamplerOrder1 : public AudioResampler {
@@ -46,6 +52,15 @@
             AudioBufferProvider* provider);
     void resampleStereo16(int32_t* out, size_t outFrameCount,
             AudioBufferProvider* provider);
+#ifdef ASM_ARM_RESAMP1  // asm optimisation for ResamplerOrder1
+    void AsmMono16Loop(int16_t *in, int32_t* maxOutPt, int32_t maxInIdx,
+            size_t &outputIndex, int32_t* out, size_t &inputIndex, int32_t vl, int32_t vr,
+            uint32_t &phaseFraction, uint32_t phaseIncrement);
+    void AsmStereo16Loop(int16_t *in, int32_t* maxOutPt, int32_t maxInIdx,
+            size_t &outputIndex, int32_t* out, size_t &inputIndex, int32_t vl, int32_t vr,
+            uint32_t &phaseFraction, uint32_t phaseIncrement);
+#endif  // ASM_ARM_RESAMP1
+
     static inline int32_t Interp(int32_t x0, int32_t x1, uint32_t f) {
         return x0 + (((x1 - x0) * (int32_t)(f >> kPreInterpShift)) >> kNumInterpBits);
     }
@@ -73,20 +88,23 @@
 
     if (quality == DEFAULT)
         quality = LOW_QUALITY;
-    
+
     switch (quality) {
     default:
     case LOW_QUALITY:
+        LOGV("Create linear Resampler");
         resampler = new AudioResamplerOrder1(bitDepth, inChannelCount, sampleRate);
         break;
     case MED_QUALITY:
+        LOGV("Create cubic Resampler");
         resampler = new AudioResamplerCubic(bitDepth, inChannelCount, sampleRate);
         break;
     case HIGH_QUALITY:
+        LOGV("Create sinc Resampler");
         resampler = new AudioResamplerSinc(bitDepth, inChannelCount, sampleRate);
         break;
     }
-    
+
     // initialize resampler
     resampler->init();
     return resampler;
@@ -103,10 +121,10 @@
                 inChannelCount);
         // LOG_ASSERT(0);
     }
-    
+
     // initialize common members
     mVolume[0] = mVolume[1] = 0;
-    mBuffer.raw = NULL;
+    mBuffer.frameCount = 0;
 
     // save format for quick lookup
     if (inChannelCount == 1) {
@@ -160,19 +178,31 @@
     uint32_t phaseIncrement = mPhaseIncrement;
     size_t outputIndex = 0;
     size_t outputSampleCount = outFrameCount * 2;
+    size_t inFrameCount = (outFrameCount*mInSampleRate)/mSampleRate;
 
     // LOGE("starting resample %d frames, inputIndex=%d, phaseFraction=%d, phaseIncrement=%d\n",
-    //		outFrameCount, inputIndex, phaseFraction, phaseIncrement);
+    //      outFrameCount, inputIndex, phaseFraction, phaseIncrement);
 
     while (outputIndex < outputSampleCount) {
 
         // buffer is empty, fetch a new one
-        if (mBuffer.raw == NULL) {
+        while (mBuffer.frameCount == 0) {
+            mBuffer.frameCount = inFrameCount;
             provider->getNextBuffer(&mBuffer);
-            if (mBuffer.raw == NULL)
-                break;
+            if (mBuffer.raw == NULL) {
+                goto resampleStereo16_exit;
+            }
+
             // LOGE("New buffer fetched: %d frames\n", mBuffer.frameCount);
+            if (mBuffer.frameCount > inputIndex) break;
+
+            inputIndex -= mBuffer.frameCount;
+            mX0L = mBuffer.i16[mBuffer.frameCount*2-2];
+            mX0R = mBuffer.i16[mBuffer.frameCount*2-1];
+            provider->releaseBuffer(&mBuffer);
+             // mBuffer.frameCount == 0 now so we reload a new buffer
         }
+
         int16_t *in = mBuffer.i16;
 
         // handle boundary case
@@ -187,34 +217,47 @@
 
         // process input samples
         // LOGE("general case\n");
-        while (outputIndex < outputSampleCount) {
+
+#ifdef ASM_ARM_RESAMP1  // asm optimisation for ResamplerOrder1
+        if (inputIndex + 2 < mBuffer.frameCount) {
+            int32_t* maxOutPt;
+            int32_t maxInIdx;
+
+            maxOutPt = out + (outputSampleCount - 2);   // 2 because 2 frames per loop
+            maxInIdx = mBuffer.frameCount - 2;
+            AsmStereo16Loop(in, maxOutPt, maxInIdx, outputIndex, out, inputIndex, vl, vr,
+                    phaseFraction, phaseIncrement);
+        }
+#endif  // ASM_ARM_RESAMP1
+
+        while (outputIndex < outputSampleCount && inputIndex < mBuffer.frameCount) {
             out[outputIndex++] += vl * Interp(in[inputIndex*2-2],
                     in[inputIndex*2], phaseFraction);
             out[outputIndex++] += vr * Interp(in[inputIndex*2-1],
                     in[inputIndex*2+1], phaseFraction);
             Advance(&inputIndex, &phaseFraction, phaseIncrement);
-            if (inputIndex >= mBuffer.frameCount)
-                break;
         }
+
         // LOGE("loop done - outputIndex=%d, inputIndex=%d\n", outputIndex, inputIndex);
 
         // if done with buffer, save samples
         if (inputIndex >= mBuffer.frameCount) {
             inputIndex -= mBuffer.frameCount;
 
-            // LOGE("buffer done, new input index", inputIndex);
+            // LOGE("buffer done, new input index %d", inputIndex);
 
             mX0L = mBuffer.i16[mBuffer.frameCount*2-2];
             mX0R = mBuffer.i16[mBuffer.frameCount*2-1];
             provider->releaseBuffer(&mBuffer);
 
-            // verify that the releaseBuffer NULLS the buffer pointer 
-            // LOG_ASSERT(mBuffer.raw == NULL);
+            // verify that the releaseBuffer resets the buffer frameCount
+            // LOG_ASSERT(mBuffer.frameCount == 0);
         }
     }
 
     // LOGE("output buffer full - outputIndex=%d, inputIndex=%d\n", outputIndex, inputIndex);
 
+resampleStereo16_exit:
     // save state
     mInputIndex = inputIndex;
     mPhaseFraction = phaseFraction;
@@ -231,18 +274,27 @@
     uint32_t phaseIncrement = mPhaseIncrement;
     size_t outputIndex = 0;
     size_t outputSampleCount = outFrameCount * 2;
+    size_t inFrameCount = (outFrameCount*mInSampleRate)/mSampleRate;
 
     // LOGE("starting resample %d frames, inputIndex=%d, phaseFraction=%d, phaseIncrement=%d\n",
     //      outFrameCount, inputIndex, phaseFraction, phaseIncrement);
-
     while (outputIndex < outputSampleCount) {
-
         // buffer is empty, fetch a new one
-        if (mBuffer.raw == NULL) {
+        while (mBuffer.frameCount == 0) {
+            mBuffer.frameCount = inFrameCount;
             provider->getNextBuffer(&mBuffer);
-            if (mBuffer.raw == NULL)
-                break;
+            if (mBuffer.raw == NULL) {
+                mInputIndex = inputIndex;
+                mPhaseFraction = phaseFraction;
+                goto resampleMono16_exit;
+            }
             // LOGE("New buffer fetched: %d frames\n", mBuffer.frameCount);
+            if (mBuffer.frameCount >  inputIndex) break;
+
+            inputIndex -= mBuffer.frameCount;
+            mX0L = mBuffer.i16[mBuffer.frameCount-1];
+            provider->releaseBuffer(&mBuffer);
+            // mBuffer.frameCount == 0 now so we reload a new buffer
         }
         int16_t *in = mBuffer.i16;
 
@@ -259,38 +311,284 @@
 
         // process input samples
         // LOGE("general case\n");
-        while (outputIndex < outputSampleCount) {
+
+#ifdef ASM_ARM_RESAMP1  // asm optimisation for ResamplerOrder1
+        if (inputIndex + 2 < mBuffer.frameCount) {
+            int32_t* maxOutPt;
+            int32_t maxInIdx;
+
+            maxOutPt = out + (outputSampleCount - 2);
+            maxInIdx = (int32_t)mBuffer.frameCount - 2;
+                AsmMono16Loop(in, maxOutPt, maxInIdx, outputIndex, out, inputIndex, vl, vr,
+                        phaseFraction, phaseIncrement);
+        }
+#endif  // ASM_ARM_RESAMP1
+
+        while (outputIndex < outputSampleCount && inputIndex < mBuffer.frameCount) {
             int32_t sample = Interp(in[inputIndex-1], in[inputIndex],
                     phaseFraction);
             out[outputIndex++] += vl * sample;
             out[outputIndex++] += vr * sample;
             Advance(&inputIndex, &phaseFraction, phaseIncrement);
-            if (inputIndex >= mBuffer.frameCount)
-                break;
         }
+
+
         // LOGE("loop done - outputIndex=%d, inputIndex=%d\n", outputIndex, inputIndex);
 
         // if done with buffer, save samples
         if (inputIndex >= mBuffer.frameCount) {
             inputIndex -= mBuffer.frameCount;
 
-            // LOGE("buffer done, new input index", inputIndex);
+            // LOGE("buffer done, new input index %d", inputIndex);
 
             mX0L = mBuffer.i16[mBuffer.frameCount-1];
             provider->releaseBuffer(&mBuffer);
 
-            // verify that the releaseBuffer NULLS the buffer pointer 
-            // LOG_ASSERT(mBuffer.raw == NULL);
+            // verify that the releaseBuffer resets the buffer frameCount
+            // LOG_ASSERT(mBuffer.frameCount == 0);
         }
     }
 
     // LOGE("output buffer full - outputIndex=%d, inputIndex=%d\n", outputIndex, inputIndex);
 
+resampleMono16_exit:
     // save state
     mInputIndex = inputIndex;
     mPhaseFraction = phaseFraction;
 }
 
+#ifdef ASM_ARM_RESAMP1  // asm optimisation for ResamplerOrder1
+
+/*******************************************************************
+*
+*   AsmMono16Loop
+*   asm optimized monotonic loop version; one loop is 2 frames
+*   Input:
+*       in : pointer on input samples
+*       maxOutPt : pointer on first not filled
+*       maxInIdx : index on first not used
+*       outputIndex : pointer on current output index
+*       out : pointer on output buffer
+*       inputIndex : pointer on current input index
+*       vl, vr : left and right gain
+*       phaseFraction : pointer on current phase fraction
+*       phaseIncrement
+*   Ouput:
+*       outputIndex :
+*       out : updated buffer
+*       inputIndex : index of next to use
+*       phaseFraction : phase fraction for next interpolation
+*
+*******************************************************************/
+void AudioResamplerOrder1::AsmMono16Loop(int16_t *in, int32_t* maxOutPt, int32_t maxInIdx,
+            size_t &outputIndex, int32_t* out, size_t &inputIndex, int32_t vl, int32_t vr,
+            uint32_t &phaseFraction, uint32_t phaseIncrement)
+{
+#define MO_PARAM5   "36"        // offset of parameter 5 (outputIndex)
+
+    asm(
+        "stmfd  sp!, {r4, r5, r6, r7, r8, r9, r10, r11, lr}\n"
+        // get parameters
+        "   ldr r6, [sp, #" MO_PARAM5 " + 20]\n"    // &phaseFraction
+        "   ldr r6, [r6]\n"                         // phaseFraction
+        "   ldr r7, [sp, #" MO_PARAM5 " + 8]\n"     // &inputIndex
+        "   ldr r7, [r7]\n"                         // inputIndex
+        "   ldr r8, [sp, #" MO_PARAM5 " + 4]\n"     // out
+        "   ldr r0, [sp, #" MO_PARAM5 " + 0]\n"     // &outputIndex
+        "   ldr r0, [r0]\n"                         // outputIndex
+        "   add r8, r0, asl #2\n"                   // curOut
+        "   ldr r9, [sp, #" MO_PARAM5 " + 24]\n"    // phaseIncrement
+        "   ldr r10, [sp, #" MO_PARAM5 " + 12]\n"   // vl
+        "   ldr r11, [sp, #" MO_PARAM5 " + 16]\n"   // vr
+
+        // r0 pin, x0, Samp
+
+        // r1 in
+        // r2 maxOutPt
+        // r3 maxInIdx
+
+        // r4 x1, i1, i3, Out1
+        // r5 out0
+
+        // r6 frac
+        // r7 inputIndex
+        // r8 curOut
+
+        // r9 inc
+        // r10 vl
+        // r11 vr
+
+        // r12
+        // r13 sp
+        // r14
+
+        // the following loop works on 2 frames
+
+        ".Y4L01:\n"
+        "   cmp r8, r2\n"                   // curOut - maxCurOut
+        "   bcs .Y4L02\n"
+
+#define MO_ONE_FRAME \
+    "   add r0, r1, r7, asl #1\n"       /* in + inputIndex */\
+    "   ldrsh r4, [r0]\n"               /* in[inputIndex] */\
+    "   ldr r5, [r8]\n"                 /* out[outputIndex] */\
+    "   ldrsh r0, [r0, #-2]\n"          /* in[inputIndex-1] */\
+    "   bic r6, r6, #0xC0000000\n"      /* phaseFraction & ... */\
+    "   sub r4, r4, r0\n"               /* in[inputIndex] - in[inputIndex-1] */\
+    "   mov r4, r4, lsl #2\n"           /* <<2 */\
+    "   smulwt r4, r4, r6\n"            /* (x1-x0)*.. */\
+    "   add r6, r6, r9\n"               /* phaseFraction + phaseIncrement */\
+    "   add r0, r0, r4\n"               /* x0 - (..) */\
+    "   mla r5, r0, r10, r5\n"          /* vl*interp + out[] */\
+    "   ldr r4, [r8, #4]\n"             /* out[outputIndex+1] */\
+    "   str r5, [r8], #4\n"             /* out[outputIndex++] = ... */\
+    "   mla r4, r0, r11, r4\n"          /* vr*interp + out[] */\
+    "   add r7, r7, r6, lsr #30\n"      /* inputIndex + phaseFraction>>30 */\
+    "   str r4, [r8], #4\n"             /* out[outputIndex++] = ... */
+
+        MO_ONE_FRAME    // frame 1
+        MO_ONE_FRAME    // frame 2
+
+        "   cmp r7, r3\n"                   // inputIndex - maxInIdx
+        "   bcc .Y4L01\n"
+        ".Y4L02:\n"
+
+        "   bic r6, r6, #0xC0000000\n"             // phaseFraction & ...
+        // save modified values
+        "   ldr r0, [sp, #" MO_PARAM5 " + 20]\n"    // &phaseFraction
+        "   str r6, [r0]\n"                         // phaseFraction
+        "   ldr r0, [sp, #" MO_PARAM5 " + 8]\n"     // &inputIndex
+        "   str r7, [r0]\n"                         // inputIndex
+        "   ldr r0, [sp, #" MO_PARAM5 " + 4]\n"     // out
+        "   sub r8, r0\n"                           // curOut - out
+        "   asr r8, #2\n"                           // new outputIndex
+        "   ldr r0, [sp, #" MO_PARAM5 " + 0]\n"     // &outputIndex
+        "   str r8, [r0]\n"                         // save outputIndex
+
+        "   ldmfd   sp!, {r4, r5, r6, r7, r8, r9, r10, r11, pc}\n"
+    );
+}
+
+/*******************************************************************
+*
+*   AsmStereo16Loop
+*   asm optimized stereo loop version; one loop is 2 frames
+*   Input:
+*       in : pointer on input samples
+*       maxOutPt : pointer on first not filled
+*       maxInIdx : index on first not used
+*       outputIndex : pointer on current output index
+*       out : pointer on output buffer
+*       inputIndex : pointer on current input index
+*       vl, vr : left and right gain
+*       phaseFraction : pointer on current phase fraction
+*       phaseIncrement
+*   Ouput:
+*       outputIndex :
+*       out : updated buffer
+*       inputIndex : index of next to use
+*       phaseFraction : phase fraction for next interpolation
+*
+*******************************************************************/
+void AudioResamplerOrder1::AsmStereo16Loop(int16_t *in, int32_t* maxOutPt, int32_t maxInIdx,
+            size_t &outputIndex, int32_t* out, size_t &inputIndex, int32_t vl, int32_t vr,
+            uint32_t &phaseFraction, uint32_t phaseIncrement)
+{
+#define ST_PARAM5    "40"     // offset of parameter 5 (outputIndex)
+    asm(
+        "stmfd  sp!, {r4, r5, r6, r7, r8, r9, r10, r11, r12, lr}\n"
+        // get parameters
+        "   ldr r6, [sp, #" ST_PARAM5 " + 20]\n"    // &phaseFraction
+        "   ldr r6, [r6]\n"                         // phaseFraction
+        "   ldr r7, [sp, #" ST_PARAM5 " + 8]\n"     // &inputIndex
+        "   ldr r7, [r7]\n"                         // inputIndex
+        "   ldr r8, [sp, #" ST_PARAM5 " + 4]\n"     // out
+        "   ldr r0, [sp, #" ST_PARAM5 " + 0]\n"     // &outputIndex
+        "   ldr r0, [r0]\n"                         // outputIndex
+        "   add r8, r0, asl #2\n"                   // curOut
+        "   ldr r9, [sp, #" ST_PARAM5 " + 24]\n"    // phaseIncrement
+        "   ldr r10, [sp, #" ST_PARAM5 " + 12]\n"   // vl
+        "   ldr r11, [sp, #" ST_PARAM5 " + 16]\n"   // vr
+
+        // r0 pin, x0, Samp
+
+        // r1 in
+        // r2 maxOutPt
+        // r3 maxInIdx
+
+        // r4 x1, i1, i3, out1
+        // r5 out0
+
+        // r6 frac
+        // r7 inputIndex
+        // r8 curOut
+
+        // r9 inc
+        // r10 vl
+        // r11 vr
+
+        // r12 temporary
+        // r13 sp
+        // r14
+
+        ".Y5L01:\n"
+        "   cmp r8, r2\n"                   // curOut - maxCurOut
+        "   bcs .Y5L02\n"
+
+#define ST_ONE_FRAME \
+    "   bic r6, r6, #0xC0000000\n"      /* phaseFraction & ... */\
+\
+    "   add r0, r1, r7, asl #2\n"       /* in + 2*inputIndex */\
+\
+    "   ldrsh r4, [r0]\n"               /* in[2*inputIndex] */\
+    "   ldr r5, [r8]\n"                 /* out[outputIndex] */\
+    "   ldrsh r12, [r0, #-4]\n"         /* in[2*inputIndex-2] */\
+    "   sub r4, r4, r12\n"              /* in[2*InputIndex] - in[2*InputIndex-2] */\
+    "   mov r4, r4, lsl #2\n"           /* <<2 */\
+    "   smulwt r4, r4, r6\n"            /* (x1-x0)*.. */\
+    "   add r12, r12, r4\n"             /* x0 - (..) */\
+    "   mla r5, r12, r10, r5\n"         /* vl*interp + out[] */\
+    "   ldr r4, [r8, #4]\n"             /* out[outputIndex+1] */\
+    "   str r5, [r8], #4\n"             /* out[outputIndex++] = ... */\
+\
+    "   ldrsh r12, [r0, #+2]\n"         /* in[2*inputIndex+1] */\
+    "   ldrsh r0, [r0, #-2]\n"          /* in[2*inputIndex-1] */\
+    "   sub r12, r12, r0\n"             /* in[2*InputIndex] - in[2*InputIndex-2] */\
+    "   mov r12, r12, lsl #2\n"         /* <<2 */\
+    "   smulwt r12, r12, r6\n"          /* (x1-x0)*.. */\
+    "   add r12, r0, r12\n"             /* x0 - (..) */\
+    "   mla r4, r12, r11, r4\n"         /* vr*interp + out[] */\
+    "   str r4, [r8], #4\n"             /* out[outputIndex++] = ... */\
+\
+    "   add r6, r6, r9\n"               /* phaseFraction + phaseIncrement */\
+    "   add r7, r7, r6, lsr #30\n"      /* inputIndex + phaseFraction>>30 */
+
+    ST_ONE_FRAME    // frame 1
+    ST_ONE_FRAME    // frame 1
+
+        "   cmp r7, r3\n"                       // inputIndex - maxInIdx
+        "   bcc .Y5L01\n"
+        ".Y5L02:\n"
+
+        "   bic r6, r6, #0xC0000000\n"              // phaseFraction & ...
+        // save modified values
+        "   ldr r0, [sp, #" ST_PARAM5 " + 20]\n"    // &phaseFraction
+        "   str r6, [r0]\n"                         // phaseFraction
+        "   ldr r0, [sp, #" ST_PARAM5 " + 8]\n"     // &inputIndex
+        "   str r7, [r0]\n"                         // inputIndex
+        "   ldr r0, [sp, #" ST_PARAM5 " + 4]\n"     // out
+        "   sub r8, r0\n"                           // curOut - out
+        "   asr r8, #2\n"                           // new outputIndex
+        "   ldr r0, [sp, #" ST_PARAM5 " + 0]\n"     // &outputIndex
+        "   str r8, [r0]\n"                         // save outputIndex
+
+        "   ldmfd   sp!, {r4, r5, r6, r7, r8, r9, r10, r11, r12, pc}\n"
+    );
+}
+
+#endif  // ASM_ARM_RESAMP1
+
+
 // ----------------------------------------------------------------------------
 }
 ; // namespace android
diff --git a/libs/audioflinger/AudioResamplerCubic.cpp b/libs/audioflinger/AudioResamplerCubic.cpp
index 4f437bf..1d247bd 100644
--- a/libs/audioflinger/AudioResamplerCubic.cpp
+++ b/libs/audioflinger/AudioResamplerCubic.cpp
@@ -60,9 +60,11 @@
     uint32_t phaseIncrement = mPhaseIncrement;
     size_t outputIndex = 0;
     size_t outputSampleCount = outFrameCount * 2;
-    
+    size_t inFrameCount = (outFrameCount*mInSampleRate)/mSampleRate;
+
     // fetch first buffer
-    if (mBuffer.raw == NULL) {
+    if (mBuffer.frameCount == 0) {
+        mBuffer.frameCount = inFrameCount;
         provider->getNextBuffer(&mBuffer);
         if (mBuffer.raw == NULL)
             return;
@@ -79,7 +81,7 @@
         out[outputIndex++] += vl * interp(&left, x);
         out[outputIndex++] += vr * interp(&right, x);
         // out[outputIndex++] += vr * in[inputIndex*2];
-        
+
         // increment phase
         phaseFraction += phaseIncrement;
         uint32_t indexIncrement = (phaseFraction >> kNumPhaseBits);
@@ -92,6 +94,7 @@
             if (inputIndex == mBuffer.frameCount) {
                 inputIndex = 0;
                 provider->releaseBuffer(&mBuffer);
+                mBuffer.frameCount = inFrameCount;
                 provider->getNextBuffer(&mBuffer);
                 if (mBuffer.raw == NULL)
                     goto save_state;  // ugly, but efficient
@@ -122,9 +125,11 @@
     uint32_t phaseIncrement = mPhaseIncrement;
     size_t outputIndex = 0;
     size_t outputSampleCount = outFrameCount * 2;
-    
+    size_t inFrameCount = (outFrameCount*mInSampleRate)/mSampleRate;
+
     // fetch first buffer
-    if (mBuffer.raw == NULL) {
+    if (mBuffer.frameCount == 0) {
+        mBuffer.frameCount = inFrameCount;
         provider->getNextBuffer(&mBuffer);
         if (mBuffer.raw == NULL)
             return;
@@ -141,7 +146,7 @@
         sample = interp(&left, x);
         out[outputIndex++] += vl * sample;
         out[outputIndex++] += vr * sample;
-        
+
         // increment phase
         phaseFraction += phaseIncrement;
         uint32_t indexIncrement = (phaseFraction >> kNumPhaseBits);
@@ -154,6 +159,7 @@
             if (inputIndex == mBuffer.frameCount) {
                 inputIndex = 0;
                 provider->releaseBuffer(&mBuffer);
+                mBuffer.frameCount = inFrameCount;
                 provider->getNextBuffer(&mBuffer);
                 if (mBuffer.raw == NULL)
                     goto save_state;  // ugly, but efficient
diff --git a/libs/audioflinger/AudioResamplerSinc.cpp b/libs/audioflinger/AudioResamplerSinc.cpp
index e710d16..9e5e254 100644
--- a/libs/audioflinger/AudioResamplerSinc.cpp
+++ b/libs/audioflinger/AudioResamplerSinc.cpp
@@ -25,18 +25,18 @@
  * These coeficients are computed with the "fir" utility found in
  * tools/resampler_tools
  * TODO: A good optimization would be to transpose this matrix, to take
- * better advantage of the data-cache. 
+ * better advantage of the data-cache.
  */
 const int32_t AudioResamplerSinc::mFirCoefsUp[] = {
-		0x7fffffff, 0x7f15d078, 0x7c5e0da6, 0x77ecd867, 0x71e2e251, 0x6a6c304a, 0x61be7269, 0x58170412, 0x4db8ab05, 0x42e92ea6, 0x37eee214, 0x2d0e3bb1, 0x22879366, 0x18951e95, 0x0f693d0d, 0x072d2621, 
-	    0x00000000, 0xf9f66655, 0xf51a5fd7, 0xf16bbd84, 0xeee0d9ac, 0xed67a922, 0xece70de6, 0xed405897, 0xee50e505, 0xeff3be30, 0xf203370f, 0xf45a6741, 0xf6d67d53, 0xf957db66, 0xfbc2f647, 0xfe00f2b9, 
-	    0x00000000, 0x01b37218, 0x0313a0c6, 0x041d930d, 0x04d28057, 0x053731b0, 0x05534dff, 0x05309bfd, 0x04da440d, 0x045c1aee, 0x03c1fcdd, 0x03173ef5, 0x02663ae8, 0x01b7f736, 0x0113ec79, 0x007fe6a9, 
-	    0x00000000, 0xff96b229, 0xff44f99f, 0xff0a86be, 0xfee5f803, 0xfed518fd, 0xfed521fd, 0xfee2f4fd, 0xfefb54f8, 0xff1b159b, 0xff3f4203, 0xff6539e0, 0xff8ac502, 0xffae1ddd, 0xffcdf3f9, 0xffe96798, 
-	    0x00000000, 0x00119de6, 0x001e6b7e, 0x0026cb7a, 0x002b4830, 0x002c83d6, 0x002b2a82, 0x0027e67a, 0x002356f9, 0x001e098e, 0x001875e4, 0x0012fbbe, 0x000de2d1, 0x00095c10, 0x00058414, 0x00026636, 
-	    0x00000000, 0xfffe44a9, 0xfffd206d, 0xfffc7b7f, 0xfffc3c8f, 0xfffc4ac2, 0xfffc8f2b, 0xfffcf5c4, 0xfffd6df3, 0xfffdeab2, 0xfffe6275, 0xfffececf, 0xffff2c07, 0xffff788c, 0xffffb471, 0xffffe0f2, 
-	    0x00000000, 0x000013e6, 0x00001f03, 0x00002396, 0x00002399, 0x000020b6, 0x00001c3c, 0x00001722, 0x00001216, 0x00000d81, 0x0000099c, 0x0000067c, 0x00000419, 0x0000025f, 0x00000131, 0x00000070, 
-	    0x00000000, 0xffffffc7, 0xffffffb3, 0xffffffb3, 0xffffffbe, 0xffffffcd, 0xffffffdb, 0xffffffe7, 0xfffffff0, 0xfffffff7, 0xfffffffb, 0xfffffffe, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 
-	    0x00000000 // this one is needed for lerping the last coefficient
+        0x7fffffff, 0x7f15d078, 0x7c5e0da6, 0x77ecd867, 0x71e2e251, 0x6a6c304a, 0x61be7269, 0x58170412, 0x4db8ab05, 0x42e92ea6, 0x37eee214, 0x2d0e3bb1, 0x22879366, 0x18951e95, 0x0f693d0d, 0x072d2621,
+        0x00000000, 0xf9f66655, 0xf51a5fd7, 0xf16bbd84, 0xeee0d9ac, 0xed67a922, 0xece70de6, 0xed405897, 0xee50e505, 0xeff3be30, 0xf203370f, 0xf45a6741, 0xf6d67d53, 0xf957db66, 0xfbc2f647, 0xfe00f2b9,
+        0x00000000, 0x01b37218, 0x0313a0c6, 0x041d930d, 0x04d28057, 0x053731b0, 0x05534dff, 0x05309bfd, 0x04da440d, 0x045c1aee, 0x03c1fcdd, 0x03173ef5, 0x02663ae8, 0x01b7f736, 0x0113ec79, 0x007fe6a9,
+        0x00000000, 0xff96b229, 0xff44f99f, 0xff0a86be, 0xfee5f803, 0xfed518fd, 0xfed521fd, 0xfee2f4fd, 0xfefb54f8, 0xff1b159b, 0xff3f4203, 0xff6539e0, 0xff8ac502, 0xffae1ddd, 0xffcdf3f9, 0xffe96798,
+        0x00000000, 0x00119de6, 0x001e6b7e, 0x0026cb7a, 0x002b4830, 0x002c83d6, 0x002b2a82, 0x0027e67a, 0x002356f9, 0x001e098e, 0x001875e4, 0x0012fbbe, 0x000de2d1, 0x00095c10, 0x00058414, 0x00026636,
+        0x00000000, 0xfffe44a9, 0xfffd206d, 0xfffc7b7f, 0xfffc3c8f, 0xfffc4ac2, 0xfffc8f2b, 0xfffcf5c4, 0xfffd6df3, 0xfffdeab2, 0xfffe6275, 0xfffececf, 0xffff2c07, 0xffff788c, 0xffffb471, 0xffffe0f2,
+        0x00000000, 0x000013e6, 0x00001f03, 0x00002396, 0x00002399, 0x000020b6, 0x00001c3c, 0x00001722, 0x00001216, 0x00000d81, 0x0000099c, 0x0000067c, 0x00000419, 0x0000025f, 0x00000131, 0x00000070,
+        0x00000000, 0xffffffc7, 0xffffffb3, 0xffffffb3, 0xffffffbe, 0xffffffcd, 0xffffffdb, 0xffffffe7, 0xfffffff0, 0xfffffff7, 0xfffffffb, 0xfffffffe, 0xffffffff, 0x00000000, 0x00000000, 0x00000000,
+        0x00000000 // this one is needed for lerping the last coefficient
 };
 
 /*
@@ -46,20 +46,20 @@
  * these coefficient from the above by "Stretching" them in time).
  */
 const int32_t AudioResamplerSinc::mFirCoefsDown[] = {
-		0x7fffffff, 0x7f55e46d, 0x7d5b4c60, 0x7a1b4b98, 0x75a7fb14, 0x7019f0bd, 0x698f875a, 0x622bfd59, 0x5a167256, 0x5178cc54, 0x487e8e6c, 0x3f53aae8, 0x36235ad4, 0x2d17047b, 0x245539ab, 0x1c00d540, 
-	    0x14383e57, 0x0d14d5ca, 0x06aa910b, 0x0107c38b, 0xfc351654, 0xf835abae, 0xf5076b45, 0xf2a37202, 0xf0fe9faa, 0xf00a3bbd, 0xefb4aa81, 0xefea2b05, 0xf0959716, 0xf1a11e83, 0xf2f6f7a0, 0xf481fff4, 
-	    0xf62e48ce, 0xf7e98ca5, 0xf9a38b4c, 0xfb4e4bfa, 0xfcde456f, 0xfe4a6d30, 0xff8c2fdf, 0x009f5555, 0x0181d393, 0x0233940f, 0x02b62f06, 0x030ca07d, 0x033afa62, 0x03461725, 0x03334f83, 0x030835fa, 
-	    0x02ca59cc, 0x027f12d1, 0x022b570d, 0x01d39a49, 0x017bb78f, 0x0126e414, 0x00d7aaaf, 0x008feec7, 0x0050f584, 0x001b73e3, 0xffefa063, 0xffcd46ed, 0xffb3ddcd, 0xffa29aaa, 0xff988691, 0xff949066, 
-	    0xff959d24, 0xff9a959e, 0xffa27195, 0xffac4011, 0xffb72d2b, 0xffc28569, 0xffcdb706, 0xffd85171, 0xffe20364, 0xffea97e9, 0xfff1f2b2, 0xfff80c06, 0xfffcec92, 0x0000a955, 0x00035fd8, 0x000532cf, 
-	    0x00064735, 0x0006c1f9, 0x0006c62d, 0x000673ba, 0x0005e68f, 0x00053630, 0x000475a3, 0x0003b397, 0x0002fac1, 0x00025257, 0x0001be9e, 0x0001417a, 0x0000dafd, 0x000089eb, 0x00004c28, 0x00001f1d, 
-	    0x00000000, 0xffffec10, 0xffffe0be, 0xffffdbc5, 0xffffdb39, 0xffffdd8b, 0xffffe182, 0xffffe638, 0xffffeb0a, 0xffffef8f, 0xfffff38b, 0xfffff6e3, 0xfffff993, 0xfffffba6, 0xfffffd30, 0xfffffe4a, 
-	    0xffffff09, 0xffffff85, 0xffffffd1, 0xfffffffb, 0x0000000f, 0x00000016, 0x00000015, 0x00000012, 0x0000000d, 0x00000009, 0x00000006, 0x00000003, 0x00000002, 0x00000001, 0x00000000, 0x00000000, 
-	    0x00000000 // this one is needed for lerping the last coefficient
+        0x7fffffff, 0x7f55e46d, 0x7d5b4c60, 0x7a1b4b98, 0x75a7fb14, 0x7019f0bd, 0x698f875a, 0x622bfd59, 0x5a167256, 0x5178cc54, 0x487e8e6c, 0x3f53aae8, 0x36235ad4, 0x2d17047b, 0x245539ab, 0x1c00d540,
+        0x14383e57, 0x0d14d5ca, 0x06aa910b, 0x0107c38b, 0xfc351654, 0xf835abae, 0xf5076b45, 0xf2a37202, 0xf0fe9faa, 0xf00a3bbd, 0xefb4aa81, 0xefea2b05, 0xf0959716, 0xf1a11e83, 0xf2f6f7a0, 0xf481fff4,
+        0xf62e48ce, 0xf7e98ca5, 0xf9a38b4c, 0xfb4e4bfa, 0xfcde456f, 0xfe4a6d30, 0xff8c2fdf, 0x009f5555, 0x0181d393, 0x0233940f, 0x02b62f06, 0x030ca07d, 0x033afa62, 0x03461725, 0x03334f83, 0x030835fa,
+        0x02ca59cc, 0x027f12d1, 0x022b570d, 0x01d39a49, 0x017bb78f, 0x0126e414, 0x00d7aaaf, 0x008feec7, 0x0050f584, 0x001b73e3, 0xffefa063, 0xffcd46ed, 0xffb3ddcd, 0xffa29aaa, 0xff988691, 0xff949066,
+        0xff959d24, 0xff9a959e, 0xffa27195, 0xffac4011, 0xffb72d2b, 0xffc28569, 0xffcdb706, 0xffd85171, 0xffe20364, 0xffea97e9, 0xfff1f2b2, 0xfff80c06, 0xfffcec92, 0x0000a955, 0x00035fd8, 0x000532cf,
+        0x00064735, 0x0006c1f9, 0x0006c62d, 0x000673ba, 0x0005e68f, 0x00053630, 0x000475a3, 0x0003b397, 0x0002fac1, 0x00025257, 0x0001be9e, 0x0001417a, 0x0000dafd, 0x000089eb, 0x00004c28, 0x00001f1d,
+        0x00000000, 0xffffec10, 0xffffe0be, 0xffffdbc5, 0xffffdb39, 0xffffdd8b, 0xffffe182, 0xffffe638, 0xffffeb0a, 0xffffef8f, 0xfffff38b, 0xfffff6e3, 0xfffff993, 0xfffffba6, 0xfffffd30, 0xfffffe4a,
+        0xffffff09, 0xffffff85, 0xffffffd1, 0xfffffffb, 0x0000000f, 0x00000016, 0x00000015, 0x00000012, 0x0000000d, 0x00000009, 0x00000006, 0x00000003, 0x00000002, 0x00000001, 0x00000000, 0x00000000,
+        0x00000000 // this one is needed for lerping the last coefficient
 };
 
 // ----------------------------------------------------------------------------
 
-static inline 
+static inline
 int32_t mulRL(int left, int32_t in, uint32_t vRL)
 {
 #if defined(__arm__) && !defined(__thumb__)
@@ -85,7 +85,7 @@
 #endif
 }
 
-static inline 
+static inline
 int32_t mulAdd(int16_t in, int32_t v, int32_t a)
 {
 #if defined(__arm__) && !defined(__thumb__)
@@ -95,12 +95,14 @@
          : [in]"%r"(in), [v]"r"(v), [a]"r"(a)
          : );
     return out;
-#else    
-    return a + ((in * int32_t(v))>>16);
+#else
+    return a + in * (v>>16);
+    // improved precision
+    // return a + in * (v>>16) + ((in * (v & 0xffff)) >> 16);
 #endif
 }
 
-static inline 
+static inline
 int32_t mulAddRL(int left, uint32_t inRL, int32_t v, int32_t a)
 {
 #if defined(__arm__) && !defined(__thumb__)
@@ -119,9 +121,11 @@
     return out;
 #else
     if (left) {
-        return a + ((int16_t(inRL&0xFFFF) * int32_t(v))>>16);
+        return a + (int16_t(inRL&0xFFFF) * (v>>16));
+        //improved precision
+        // return a + (int16_t(inRL&0xFFFF) * (v>>16)) + ((int16_t(inRL&0xFFFF) * (v & 0xffff)) >> 16);
     } else {
-        return a + ((int16_t(inRL>>16) * int32_t(v))>>16);
+        return a + (int16_t(inRL>>16) * (v>>16));
     }
 #endif
 }
@@ -129,37 +133,37 @@
 // ----------------------------------------------------------------------------
 
 AudioResamplerSinc::AudioResamplerSinc(int bitDepth,
-		int inChannelCount, int32_t sampleRate)
-	: AudioResampler(bitDepth, inChannelCount, sampleRate),
-	mState(0)
+        int inChannelCount, int32_t sampleRate)
+    : AudioResampler(bitDepth, inChannelCount, sampleRate),
+    mState(0)
 {
-	/* 
-	 * Layout of the state buffer for 32 tap:
-	 * 
-	 * "present" sample            beginning of 2nd buffer
-	 *                 v                v
-	 *  0              01               2              23              3
-	 *  0              F0               0              F0              F
-	 * [pppppppppppppppInnnnnnnnnnnnnnnnpppppppppppppppInnnnnnnnnnnnnnnn]
-	 *                 ^               ^ head
-	 * 
-	 * p = past samples, convoluted with the (p)ositive side of sinc()
-	 * n = future samples, convoluted with the (n)egative side of sinc()
-	 * r = extra space for implementing the ring buffer
-	 * 
-	 */
+    /*
+     * Layout of the state buffer for 32 tap:
+     *
+     * "present" sample            beginning of 2nd buffer
+     *                 v                v
+     *  0              01               2              23              3
+     *  0              F0               0              F0              F
+     * [pppppppppppppppInnnnnnnnnnnnnnnnpppppppppppppppInnnnnnnnnnnnnnnn]
+     *                 ^               ^ head
+     *
+     * p = past samples, convoluted with the (p)ositive side of sinc()
+     * n = future samples, convoluted with the (n)egative side of sinc()
+     * r = extra space for implementing the ring buffer
+     *
+     */
 
-	const size_t numCoefs = 2*halfNumCoefs;
-	const size_t stateSize = numCoefs * inChannelCount * 2;
-	mState = new int16_t[stateSize];
-	memset(mState, 0, sizeof(int16_t)*stateSize);
-	mImpulse = mState + (halfNumCoefs-1)*inChannelCount;
-	mRingFull = mImpulse + (numCoefs+1)*inChannelCount;
+    const size_t numCoefs = 2*halfNumCoefs;
+    const size_t stateSize = numCoefs * inChannelCount * 2;
+    mState = new int16_t[stateSize];
+    memset(mState, 0, sizeof(int16_t)*stateSize);
+    mImpulse = mState + (halfNumCoefs-1)*inChannelCount;
+    mRingFull = mImpulse + (numCoefs+1)*inChannelCount;
 }
 
 AudioResamplerSinc::~AudioResamplerSinc()
 {
-	delete [] mState;
+    delete [] mState;
 }
 
 void AudioResamplerSinc::init() {
@@ -168,9 +172,9 @@
 void AudioResamplerSinc::resample(int32_t* out, size_t outFrameCount,
             AudioBufferProvider* provider)
 {
-	mFirCoefs = (mInSampleRate <= mSampleRate) ? mFirCoefsUp : mFirCoefsDown;
+    mFirCoefs = (mInSampleRate <= mSampleRate) ? mFirCoefsUp : mFirCoefsDown;
 
-	// select the appropriate resampler
+    // select the appropriate resampler
     switch (mChannelCount) {
     case 1:
         resample<1>(out, outFrameCount, provider);
@@ -193,43 +197,68 @@
     uint32_t phaseIncrement = mPhaseIncrement;
     size_t outputIndex = 0;
     size_t outputSampleCount = outFrameCount * 2;
+    size_t inFrameCount = (outFrameCount*mInSampleRate)/mSampleRate;
 
     AudioBufferProvider::Buffer& buffer(mBuffer);
     while (outputIndex < outputSampleCount) {
         // buffer is empty, fetch a new one
-        if (buffer.raw == NULL) {
+        while (buffer.frameCount == 0) {
+            buffer.frameCount = inFrameCount;
             provider->getNextBuffer(&buffer);
-            if (buffer.raw == NULL)
-                break;
-    		const uint32_t phaseIndex = phaseFraction >> kNumPhaseBits;
-        	if (phaseIndex) {
-        		read<CHANNELS>(impulse, phaseFraction, buffer.i16, inputIndex);
+            if (buffer.raw == NULL) {
+                goto resample_exit;
             }
+            const uint32_t phaseIndex = phaseFraction >> kNumPhaseBits;
+            if (phaseIndex == 1) {
+                // read one frame
+                read<CHANNELS>(impulse, phaseFraction, buffer.i16, inputIndex);
+            } else if (phaseIndex == 2) {
+                // read 2 frames
+                read<CHANNELS>(impulse, phaseFraction, buffer.i16, inputIndex);
+                inputIndex++;
+                if (inputIndex >= mBuffer.frameCount) {
+                    inputIndex -= mBuffer.frameCount;
+                    provider->releaseBuffer(&buffer);
+                } else {
+                    read<CHANNELS>(impulse, phaseFraction, buffer.i16, inputIndex);
+                }
+           }
         }
         int16_t *in = buffer.i16;
-    	const size_t frameCount = buffer.frameCount;
+        const size_t frameCount = buffer.frameCount;
 
-    	// Always read-in the first samples from the input buffer
-    	int16_t* head = impulse + halfNumCoefs*CHANNELS;
-		head[0] = in[inputIndex*CHANNELS + 0];
-		if (CHANNELS == 2)
-			head[1] = in[inputIndex*CHANNELS + 1];
+        // Always read-in the first samples from the input buffer
+        int16_t* head = impulse + halfNumCoefs*CHANNELS;
+        head[0] = in[inputIndex*CHANNELS + 0];
+        if (CHANNELS == 2)
+            head[1] = in[inputIndex*CHANNELS + 1];
 
         // handle boundary case
-    	int32_t l, r;
+        int32_t l, r;
         while (outputIndex < outputSampleCount) {
-        	filterCoefficient<CHANNELS>(l, r, phaseFraction, impulse);
-    		out[outputIndex++] = mulRL(1, l, vRL);
-    		out[outputIndex++] = mulRL(0, r, vRL);
+            filterCoefficient<CHANNELS>(l, r, phaseFraction, impulse);
+            out[outputIndex++] += 2 * mulRL(1, l, vRL);
+            out[outputIndex++] += 2 * mulRL(0, r, vRL);
 
-        	phaseFraction += phaseIncrement;
-    		const uint32_t phaseIndex = phaseFraction >> kNumPhaseBits;
-        	if (phaseIndex) {
-        		inputIndex += phaseIndex;
-        		if (inputIndex >= frameCount)
-        			break;
-        		read<CHANNELS>(impulse, phaseFraction, in, inputIndex);
-        	}
+            phaseFraction += phaseIncrement;
+            const uint32_t phaseIndex = phaseFraction >> kNumPhaseBits;
+            if (phaseIndex == 1) {
+                inputIndex++;
+                if (inputIndex >= frameCount)
+                    break;  // need a new buffer
+                read<CHANNELS>(impulse, phaseFraction, in, inputIndex);
+            } else if(phaseIndex == 2) {    // maximum value
+                inputIndex++;
+                if (inputIndex >= frameCount)
+                    break;  // 0 frame available, 2 frames needed
+                // read first frame
+                read<CHANNELS>(impulse, phaseFraction, in, inputIndex);
+                inputIndex++;
+                if (inputIndex >= frameCount)
+                    break;  // 0 frame available, 1 frame needed
+                // read second frame
+                read<CHANNELS>(impulse, phaseFraction, in, inputIndex);
+            }
         }
 
         // if done with buffer, save samples
@@ -239,80 +268,89 @@
         }
     }
 
+resample_exit:
     mImpulse = impulse;
     mInputIndex = inputIndex;
     mPhaseFraction = phaseFraction;
 }
 
 template<int CHANNELS>
+/***
+* read()
+*
+* This function reads only one frame from input buffer and writes it in
+* state buffer
+*
+**/
 void AudioResamplerSinc::read(
-		int16_t*& impulse, uint32_t& phaseFraction,
-		int16_t const* in, size_t inputIndex)
+        int16_t*& impulse, uint32_t& phaseFraction,
+        int16_t const* in, size_t inputIndex)
 {
-	// read new samples into the ring buffer
-	while (phaseFraction >> kNumPhaseBits) {
-		const uint32_t phaseIndex = phaseFraction >> kNumPhaseBits;
-		impulse += CHANNELS;
-		phaseFraction -= 1LU<<kNumPhaseBits;
-		if (impulse >= mRingFull) {
-			const size_t stateSize = (halfNumCoefs*2)*CHANNELS;
-			memcpy(mState, mState+stateSize, sizeof(int16_t)*stateSize);
-			impulse -= stateSize;
-		}
-		int16_t* head = impulse + halfNumCoefs*CHANNELS;
-		head[0] = in[inputIndex*CHANNELS + 0];
-		if (CHANNELS == 2)
-			head[1] = in[inputIndex*CHANNELS + 1];
-	}
+    const uint32_t phaseIndex = phaseFraction >> kNumPhaseBits;
+    impulse += CHANNELS;
+    phaseFraction -= 1LU<<kNumPhaseBits;
+    if (impulse >= mRingFull) {
+        const size_t stateSize = (halfNumCoefs*2)*CHANNELS;
+        memcpy(mState, mState+stateSize, sizeof(int16_t)*stateSize);
+        impulse -= stateSize;
+    }
+    int16_t* head = impulse + halfNumCoefs*CHANNELS;
+    head[0] = in[inputIndex*CHANNELS + 0];
+    if (CHANNELS == 2)
+        head[1] = in[inputIndex*CHANNELS + 1];
 }
 
 template<int CHANNELS>
 void AudioResamplerSinc::filterCoefficient(
-		int32_t& l, int32_t& r, uint32_t phase, int16_t const *samples)
-{	
-	// compute the index of the coefficient on the positive side and
-	// negative side
-	uint32_t indexP = (phase & cMask) >> cShift;
-	uint16_t lerpP  = (phase & pMask) >> pShift;
-	uint32_t indexN = (-phase & cMask) >> cShift;
-	uint16_t lerpN  = (-phase & pMask) >> pShift;
-	
-	l = 0;
-	r = 0;
-	int32_t const* coefs = mFirCoefs;
-	int16_t const *sP = samples;
-	int16_t const *sN = samples+CHANNELS;
-	for (unsigned int i=0 ; i<halfNumCoefs/4 ; i++) {
-		interpolate<CHANNELS>(l, r, coefs+indexP, lerpP, sP);
-		interpolate<CHANNELS>(l, r, coefs+indexN, lerpN, sN);
-		sP -= CHANNELS; sN += CHANNELS; coefs += 1<<coefsBits;
+        int32_t& l, int32_t& r, uint32_t phase, int16_t const *samples)
+{
+    // compute the index of the coefficient on the positive side and
+    // negative side
+    uint32_t indexP = (phase & cMask) >> cShift;
+    uint16_t lerpP  = (phase & pMask) >> pShift;
+    uint32_t indexN = (-phase & cMask) >> cShift;
+    uint16_t lerpN  = (-phase & pMask) >> pShift;
+    if ((indexP == 0) && (lerpP == 0)) {
+        indexN = cMask >> cShift;
+        lerpN = pMask >> pShift;
+    }
+
+    l = 0;
+    r = 0;
+    int32_t const* coefs = mFirCoefs;
+    int16_t const *sP = samples;
+    int16_t const *sN = samples+CHANNELS;
+    for (unsigned int i=0 ; i<halfNumCoefs/4 ; i++) {
         interpolate<CHANNELS>(l, r, coefs+indexP, lerpP, sP);
         interpolate<CHANNELS>(l, r, coefs+indexN, lerpN, sN);
-		sP -= CHANNELS; sN += CHANNELS; coefs += 1<<coefsBits;
+        sP -= CHANNELS; sN += CHANNELS; coefs += 1<<coefsBits;
         interpolate<CHANNELS>(l, r, coefs+indexP, lerpP, sP);
         interpolate<CHANNELS>(l, r, coefs+indexN, lerpN, sN);
-		sP -= CHANNELS; sN += CHANNELS; coefs += 1<<coefsBits;
+        sP -= CHANNELS; sN += CHANNELS; coefs += 1<<coefsBits;
         interpolate<CHANNELS>(l, r, coefs+indexP, lerpP, sP);
         interpolate<CHANNELS>(l, r, coefs+indexN, lerpN, sN);
-		sP -= CHANNELS; sN += CHANNELS; coefs += 1<<coefsBits;
-	}
+        sP -= CHANNELS; sN += CHANNELS; coefs += 1<<coefsBits;
+        interpolate<CHANNELS>(l, r, coefs+indexP, lerpP, sP);
+        interpolate<CHANNELS>(l, r, coefs+indexN, lerpN, sN);
+        sP -= CHANNELS; sN += CHANNELS; coefs += 1<<coefsBits;
+    }
 }
 
 template<int CHANNELS>
 void AudioResamplerSinc::interpolate(
         int32_t& l, int32_t& r,
-		int32_t const* coefs, int16_t lerp, int16_t const* samples)
+        int32_t const* coefs, int16_t lerp, int16_t const* samples)
 {
-	int32_t c0 = coefs[0];
-	int32_t c1 = coefs[1];
-	int32_t sinc = mulAdd(lerp, (c1-c0)<<1, c0);
-	if (CHANNELS == 2) {
-		uint32_t rl = *reinterpret_cast<uint32_t const*>(samples);
-		l = mulAddRL(1, rl, sinc, l);
-		r = mulAddRL(0, rl, sinc, r);
-	} else {
-		r = l = mulAdd(samples[0], sinc, l);
-	}
+    int32_t c0 = coefs[0];
+    int32_t c1 = coefs[1];
+    int32_t sinc = mulAdd(lerp, (c1-c0)<<1, c0);
+    if (CHANNELS == 2) {
+        uint32_t rl = *reinterpret_cast<uint32_t const*>(samples);
+        l = mulAddRL(1, rl, sinc, l);
+        r = mulAddRL(0, rl, sinc, r);
+    } else {
+        r = l = mulAdd(samples[0], sinc, l);
+    }
 }
 
 // ----------------------------------------------------------------------------
diff --git a/libs/audioflinger/AudioResamplerSinc.h b/libs/audioflinger/AudioResamplerSinc.h
index 89b9577..e6cb90b 100644
--- a/libs/audioflinger/AudioResamplerSinc.h
+++ b/libs/audioflinger/AudioResamplerSinc.h
@@ -24,19 +24,20 @@
 #include "AudioResampler.h"
 
 namespace android {
+
 // ----------------------------------------------------------------------------
 
 class AudioResamplerSinc : public AudioResampler {
 public:
-	AudioResamplerSinc(int bitDepth, int inChannelCount, int32_t sampleRate);
+    AudioResamplerSinc(int bitDepth, int inChannelCount, int32_t sampleRate);
 
-	~AudioResamplerSinc();
-	
+    ~AudioResamplerSinc();
+
     virtual void resample(int32_t* out, size_t outFrameCount,
             AudioBufferProvider* provider);
 private:
     void init();
-    
+
     template<int CHANNELS>
     void resample(int32_t* out, size_t outFrameCount,
             AudioBufferProvider* provider);
@@ -52,12 +53,12 @@
 
     template<int CHANNELS>
     inline void read(int16_t*& impulse, uint32_t& phaseFraction,
-    		int16_t const* in, size_t inputIndex);
+            int16_t const* in, size_t inputIndex);
 
     int16_t *mState;
     int16_t *mImpulse;
     int16_t *mRingFull;
-    
+
     int32_t const * mFirCoefs;
     static const int32_t mFirCoefsDown[];
     static const int32_t mFirCoefsUp[];
@@ -67,15 +68,15 @@
     static const int32_t RESAMPLE_FIR_LERP_INT_BITS  = 4;
 
     // we have 16 coefs samples per zero-crossing
-    static const int coefsBits = RESAMPLE_FIR_LERP_INT_BITS;
-    static const int cShift = kNumPhaseBits - coefsBits;
-    static const uint32_t cMask  = ((1<<coefsBits)-1) << cShift;
+    static const int coefsBits = RESAMPLE_FIR_LERP_INT_BITS;        // 4
+    static const int cShift = kNumPhaseBits - coefsBits;            // 26
+    static const uint32_t cMask  = ((1<<coefsBits)-1) << cShift;    // 0xf<<26 = 3c00 0000
 
     // and we use 15 bits to interpolate between these samples
     // this cannot change because the mul below rely on it.
     static const int pLerpBits = 15;
-    static const int pShift = kNumPhaseBits - coefsBits - pLerpBits;
-    static const uint32_t pMask  = ((1<<pLerpBits)-1) << pShift;
+    static const int pShift = kNumPhaseBits - coefsBits - pLerpBits;    // 11
+    static const uint32_t pMask  = ((1<<pLerpBits)-1) << pShift;    // 0x7fff << 11
 
     // number of zero-crossing on each side
     static const unsigned int halfNumCoefs = RESAMPLE_FIR_NUM_COEF;
diff --git a/libs/surfaceflinger/Android.mk b/libs/surfaceflinger/Android.mk
index 7741456..d14cebf 100644
--- a/libs/surfaceflinger/Android.mk
+++ b/libs/surfaceflinger/Android.mk
@@ -31,6 +31,7 @@
 endif
 
 LOCAL_SHARED_LIBRARIES := \
+	libhardware \
 	libutils \
 	libcutils \
 	libui \
diff --git a/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp b/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp
index 5dd9446..cd72179 100644
--- a/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp
+++ b/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp
@@ -19,6 +19,7 @@
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
+#include <math.h>
 
 #include <GLES/egl.h>
 
@@ -27,7 +28,9 @@
 #include <ui/EGLDisplaySurface.h>
 
 #include "DisplayHardware/DisplayHardware.h"
-#include "ui/BlitHardware.h"
+
+#include <hardware/copybit.h>
+#include <hardware/overlay.h>
 
 using namespace android;
 
@@ -91,19 +94,13 @@
     fini();
 }
 
-float DisplayHardware::getDpiX() const           { return mDpiX; }
-float DisplayHardware::getDpiY() const           { return mDpiY; }
-float DisplayHardware::getRefreshRate() const    { return mRefreshRate; }
-
-int DisplayHardware::getWidth() const {
-    return mWidth;
-}
-int DisplayHardware::getHeight() const {
-    return mHeight;
-}
-PixelFormat DisplayHardware::getFormat() const {
-    return mFormat;
-}
+float DisplayHardware::getDpiX() const          { return mDpiX; }
+float DisplayHardware::getDpiY() const          { return mDpiY; }
+float DisplayHardware::getDensity() const       { return mDensity; }
+float DisplayHardware::getRefreshRate() const   { return mRefreshRate; }
+int DisplayHardware::getWidth() const           { return mWidth; }
+int DisplayHardware::getHeight() const          { return mHeight; }
+PixelFormat DisplayHardware::getFormat() const  { return mFormat; }
 
 void DisplayHardware::init(uint32_t dpy)
 {
@@ -195,6 +192,12 @@
         mDpiY = 25.4f * float(value)/EGL_DISPLAY_SCALING;
     }
     mRefreshRate = 60.f;    // TODO: get the real refresh rate 
+    
+    // compute a "density" automatically as a scale factor from 160 dpi
+    // TODO: this value should be calculated a compile time based on the
+    // board.
+    mDensity = floorf((mDpiX>mDpiY ? mDpiX : mDpiY)*0.1f + 0.5f) * (10.0f/160.0f);
+    LOGI("density = %f", mDensity);
 
     /*
      * Create our OpenGL ES context
@@ -237,8 +240,18 @@
     mSurface = surface;
     mContext = context;
     mFormat  = GGL_PIXEL_FORMAT_RGB_565;
+    
+    hw_module_t const* module;
 
-    mBlitEngine = copybit_init();
+    mBlitEngine = NULL;
+    if (hw_get_module(COPYBIT_HARDWARE_MODULE_ID, &module) == 0) {
+        copybit_open(module, &mBlitEngine);
+    }
+
+    mOverlayEngine = NULL;
+    if (hw_get_module(OVERLAY_HARDWARE_MODULE_ID, &module) == 0) {
+        overlay_open(module, &mOverlayEngine);
+    }
 }
 
 /*
@@ -252,7 +265,8 @@
 {
     eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
     eglTerminate(mDisplay);
-    copybit_term(mBlitEngine);
+    copybit_close(mBlitEngine);
+    overlay_close(mOverlayEngine);
 }
 
 void DisplayHardware::releaseScreen() const
diff --git a/libs/surfaceflinger/DisplayHardware/DisplayHardware.h b/libs/surfaceflinger/DisplayHardware/DisplayHardware.h
index 299e236..de4a2cc 100644
--- a/libs/surfaceflinger/DisplayHardware/DisplayHardware.h
+++ b/libs/surfaceflinger/DisplayHardware/DisplayHardware.h
@@ -26,6 +26,8 @@
 
 #include "DisplayHardware/DisplayHardwareBase.h"
 
+struct overlay_device_t;
+struct copybit_device_t;
 struct copybit_image_t;
 struct copybit_t;
 
@@ -64,6 +66,7 @@
     float       getDpiX() const;
     float       getDpiY() const;
     float       getRefreshRate() const;
+    float       getDensity() const;
     int         getWidth() const;
     int         getHeight() const;
     PixelFormat getFormat() const;
@@ -74,7 +77,8 @@
     void getDisplaySurface(copybit_image_t* img) const;
     void getDisplaySurface(GGLSurface* fb) const;
     EGLDisplay getEGLDisplay() const { return mDisplay; }
-    copybit_t* getBlitEngine() const { return mBlitEngine; }
+    copybit_device_t* getBlitEngine() const { return mBlitEngine; }
+    overlay_device_t* getOverlayEngine() const { return mOverlayEngine; }
     
     Rect bounds() const {
         return Rect(mWidth, mHeight);
@@ -91,13 +95,15 @@
     float           mDpiX;
     float           mDpiY;
     float           mRefreshRate;
+    float           mDensity;
     int             mWidth;
     int             mHeight;
     PixelFormat     mFormat;
     uint32_t        mFlags;
     mutable Region  mDirty;
     sp<EGLDisplaySurface> mDisplaySurface;
-    copybit_t*      mBlitEngine;
+    copybit_device_t*     mBlitEngine;
+    overlay_device_t*     mOverlayEngine;
 };
 
 }; // namespace android
diff --git a/libs/surfaceflinger/DisplayHardware/DisplayHardwareBase.cpp b/libs/surfaceflinger/DisplayHardware/DisplayHardwareBase.cpp
index 90f6287..f75e5c2 100644
--- a/libs/surfaceflinger/DisplayHardware/DisplayHardwareBase.cpp
+++ b/libs/surfaceflinger/DisplayHardware/DisplayHardwareBase.cpp
@@ -49,8 +49,10 @@
 // ----------------------------------------------------------------------------
 namespace android {
 
-static char const * const kSleepFileName = "/sys/android_power/wait_for_fb_sleep";
-static char const * const kWakeFileName = "/sys/android_power/wait_for_fb_wake";
+static char const * kSleepFileName = "/sys/power/wait_for_fb_sleep";
+static char const * kWakeFileName = "/sys/power/wait_for_fb_wake";
+static char const * const kOldSleepFileName = "/sys/android_power/wait_for_fb_sleep";
+static char const * const kOldWakeFileName = "/sys/android_power/wait_for_fb_wake";
 
 // This dir exists if the framebuffer console is present, either built into
 // the kernel or loaded as a module.
@@ -123,16 +125,22 @@
 status_t DisplayHardwareBase::DisplayEventThread::readyToRun()
 {
     if (access(kSleepFileName, R_OK) || access(kWakeFileName, R_OK)) {
-        LOGE("Couldn't open %s or %s", kSleepFileName, kWakeFileName);
-        return NO_INIT;
+        if (access(kOldSleepFileName, R_OK) || access(kOldWakeFileName, R_OK)) {
+            LOGE("Couldn't open %s or %s", kSleepFileName, kWakeFileName);
+            return NO_INIT;
+        }
+        kSleepFileName = kOldSleepFileName;
+        kWakeFileName = kOldWakeFileName;
     }
     return NO_ERROR;
 }
 
 status_t DisplayHardwareBase::DisplayEventThread::initCheck() const
 {
-    return (access(kSleepFileName, R_OK) == 0 &&
-            access(kWakeFileName, R_OK) == 0 &&
+    return (((access(kSleepFileName, R_OK) == 0 &&
+            access(kWakeFileName, R_OK) == 0) ||
+            (access(kOldSleepFileName, R_OK) == 0 &&
+            access(kOldWakeFileName, R_OK) == 0)) &&
             access(kFbconSysDir, F_OK) != 0) ? NO_ERROR : NO_INIT;
 }
 
diff --git a/libs/surfaceflinger/GPUHardware/GPUHardware.cpp b/libs/surfaceflinger/GPUHardware/GPUHardware.cpp
index b24a0f2..eb75f99 100644
--- a/libs/surfaceflinger/GPUHardware/GPUHardware.cpp
+++ b/libs/surfaceflinger/GPUHardware/GPUHardware.cpp
@@ -30,6 +30,7 @@
 #include <cutils/log.h>
 #include <cutils/properties.h>
 
+#include <utils/IBinder.h>
 #include <utils/MemoryDealer.h>
 #include <utils/MemoryBase.h>
 #include <utils/MemoryHeapPmem.h>
@@ -48,36 +49,113 @@
 
 #include "GPUHardware/GPUHardware.h"
 
+
 /* 
- * This file manages the GPU if there is one. The intent is that this code
- * needs to be different for every devce. Currently there is no abstraction,
- * but in the long term, this code needs to be refactored so that API and
- * implementation are separated.
+ * Manage the GPU. This implementation is very specific to the G1.
+ * There are no abstraction here. 
  * 
- * In this particular implementation, the GPU, its memory and register are
- * managed here. Clients (such as OpenGL ES) request the GPU when then need
- * it and are given a revokable heap containing the registers on memory. 
+ * All this code will soon go-away and be replaced by a new architecture
+ * for managing graphics accelerators.
+ * 
+ * In the meantime, it is conceptually possible to instantiate a
+ * GPUHardwareInterface for another GPU (see GPUFactory at the bottom
+ * of this file); practically... doubtful.
  * 
  */
 
 namespace android {
+
 // ---------------------------------------------------------------------------
 
+class GPUClientHeap;
+class GPUAreaHeap;
+
+class GPUHardware : public GPUHardwareInterface, public IBinder::DeathRecipient
+{
+public:
+    static const int GPU_RESERVED_SIZE;
+    static const int GPUR_SIZE;
+
+            GPUHardware();
+    virtual ~GPUHardware();
+    
+    virtual void revoke(int pid);
+    virtual sp<MemoryDealer> request(int pid);
+    virtual status_t request(int pid, 
+            const sp<IGPUCallback>& callback,
+            ISurfaceComposer::gpu_info_t* gpu);
+
+    virtual status_t friendlyRevoke();
+    virtual void unconditionalRevoke();
+    
+    virtual pid_t getOwner() const { return mOwner; }
+
+    // used for debugging only...
+    virtual sp<SimpleBestFitAllocator> getAllocator() const;
+
+private:
+    
+    
+    enum {
+        NO_OWNER = -1,
+    };
+        
+    struct GPUArea {
+        sp<GPUAreaHeap>     heap;
+        sp<MemoryHeapPmem>  clientHeap;
+        sp<IMemory> map();
+    };
+    
+    struct Client {
+        pid_t       pid;
+        GPUArea     smi;
+        GPUArea     ebi;
+        GPUArea     reg;
+        void createClientHeaps();
+        void revokeAllHeaps();
+    };
+    
+    Client& getClientLocked(pid_t pid);
+    status_t requestLocked(int pid);
+    void releaseLocked();
+    void takeBackGPULocked();
+    void registerCallbackLocked(const sp<IGPUCallback>& callback,
+            Client& client);
+
+    virtual void binderDied(const wp<IBinder>& who);
+
+    mutable Mutex           mLock;
+    sp<GPUAreaHeap>         mSMIHeap;
+    sp<GPUAreaHeap>         mEBIHeap;
+    sp<GPUAreaHeap>         mREGHeap;
+
+    KeyedVector<pid_t, Client> mClients;
+    DefaultKeyedVector< wp<IBinder>, pid_t > mRegisteredClients;
+    
+    pid_t                   mOwner;
+
+    sp<MemoryDealer>        mCurrentAllocator;
+    sp<IGPUCallback>        mCallback;
+    
+    sp<SimpleBestFitAllocator>  mAllocator;
+
+    Condition               mCondition;
+};
+
 // size reserved for GPU surfaces
 // 1200 KB fits exactly:
 //  - two 320*480 16-bits double-buffered surfaces
 //  - one 320*480 32-bits double-buffered surface
-//  - one 320*240 16-bits double-bufferd, 4x anti-aliased surface
-static const int GPU_RESERVED_SIZE  = 1200 * 1024;
-
-static const int GPUR_SIZE          = 1 * 1024 * 1024;
+//  - one 320*240 16-bits double-buffered, 4x anti-aliased surface
+const int GPUHardware::GPU_RESERVED_SIZE  = 1200 * 1024;
+const int GPUHardware::GPUR_SIZE          = 1 * 1024 * 1024;
 
 // ---------------------------------------------------------------------------
 
 /* 
  * GPUHandle is a special IMemory given to the client. It represents their
  * handle to the GPU. Once they give it up, they loose GPU access, or if
- * they explicitely revoke their acces through the binder code 1000.
+ * they explicitly revoke their access through the binder code 1000.
  * In both cases, this triggers a callback to revoke()
  * first, and then actually powers down the chip.
  * 
@@ -92,42 +170,99 @@
  * 
  */
 
-class GPUHandle : public BnMemory
+class GPUClientHeap : public MemoryHeapPmem
 {
 public:
-            GPUHandle(const sp<GPUHardware>& gpu, const sp<IMemoryHeap>& heap)
-                : mGPU(gpu), mClientHeap(heap) {
-            }
-    virtual ~GPUHandle();
-    virtual sp<IMemoryHeap> getMemory(ssize_t* offset, size_t* size) const;
-    virtual status_t onTransact(
-            uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags);
-    void setOwner(int owner) { mOwner = owner; }
-private:
-    void revokeNotification();
+    GPUClientHeap(const wp<GPUHardware>& gpu, 
+            const sp<MemoryHeapBase>& heap)
+        :  MemoryHeapPmem(heap), mGPU(gpu) { }
+protected:
     wp<GPUHardware> mGPU;
-    sp<IMemoryHeap> mClientHeap;
-    int mOwner;
 };
 
-GPUHandle::~GPUHandle() { 
+class GPUAreaHeap : public MemoryHeapBase
+{
+public:
+    GPUAreaHeap(const wp<GPUHardware>& gpu,
+            const char* const vram, size_t size=0, size_t reserved=0)
+    : MemoryHeapBase(vram, size), mGPU(gpu) { 
+        if (base() != MAP_FAILED) {
+            if (reserved == 0)
+                reserved = virtualSize();
+            mAllocator = new SimpleBestFitAllocator(reserved);
+        }
+    }
+    virtual sp<MemoryHeapPmem> createClientHeap() {
+        sp<MemoryHeapBase> parentHeap(this);
+        return new GPUClientHeap(mGPU, parentHeap);
+    }
+    virtual const sp<SimpleBestFitAllocator>& getAllocator() const {
+        return mAllocator; 
+    }
+private:
+    sp<SimpleBestFitAllocator>  mAllocator;
+protected:
+    wp<GPUHardware> mGPU;
+};
+
+class GPURegisterHeap : public GPUAreaHeap
+{
+public:
+    GPURegisterHeap(const sp<GPUHardware>& gpu)
+        : GPUAreaHeap(gpu, "/dev/hw3d", GPUHardware::GPUR_SIZE) { }
+    virtual sp<MemoryHeapPmem> createClientHeap() {
+        sp<MemoryHeapBase> parentHeap(this);
+        return new MemoryHeapRegs(mGPU, parentHeap);
+    }
+private:
+    class MemoryHeapRegs : public GPUClientHeap  {
+    public:
+        MemoryHeapRegs(const wp<GPUHardware>& gpu, 
+             const sp<MemoryHeapBase>& heap)
+            : GPUClientHeap(gpu, heap) { }
+        sp<MemoryHeapPmem::MemoryPmem> createMemory(size_t offset, size_t size);
+        virtual void revoke();
+    private:
+        class GPUHandle : public MemoryHeapPmem::MemoryPmem {
+        public:
+            GPUHandle(const sp<GPUHardware>& gpu,
+                    const sp<MemoryHeapPmem>& heap)
+                : MemoryHeapPmem::MemoryPmem(heap), 
+                  mGPU(gpu), mOwner(gpu->getOwner()) { }
+            virtual ~GPUHandle();
+            virtual sp<IMemoryHeap> getMemory(
+                    ssize_t* offset, size_t* size) const;
+            virtual void revoke() { };
+            virtual status_t onTransact(
+                    uint32_t code, const Parcel& data, 
+                    Parcel* reply, uint32_t flags);
+        private:
+            void revokeNotification();
+            wp<GPUHardware> mGPU;
+            pid_t mOwner;
+        };
+    };
+};
+
+GPURegisterHeap::MemoryHeapRegs::GPUHandle::~GPUHandle() { 
     //LOGD("GPUHandle %p released, revoking GPU", this);
     revokeNotification(); 
 }
-
-void GPUHandle::revokeNotification()  {
+void GPURegisterHeap::MemoryHeapRegs::GPUHandle::revokeNotification()  {
     sp<GPUHardware> hw(mGPU.promote());
     if (hw != 0) {
         hw->revoke(mOwner);
     }
 }
-sp<IMemoryHeap> GPUHandle::getMemory(ssize_t* offset, size_t* size) const
+sp<IMemoryHeap> GPURegisterHeap::MemoryHeapRegs::GPUHandle::getMemory(
+        ssize_t* offset, size_t* size) const
 {
+    sp<MemoryHeapPmem> heap = getHeap();
     if (offset) *offset = 0;
-    if (size)   *size = mClientHeap !=0 ? mClientHeap->virtualSize() : 0;
-    return mClientHeap;
+    if (size)   *size = heap !=0 ? heap->virtualSize() : 0;
+    return heap;
 }
-status_t GPUHandle::onTransact(
+status_t GPURegisterHeap::MemoryHeapRegs::GPUHandle::onTransact(
         uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
 {
     status_t err = BnMemory::onTransact(code, data, reply, flags);
@@ -150,22 +285,14 @@
 
 // ---------------------------------------------------------------------------
 
-class MemoryHeapRegs : public MemoryHeapPmem 
-{
-public:
-            MemoryHeapRegs(const wp<GPUHardware>& gpu, const sp<MemoryHeapBase>& heap);
-    virtual ~MemoryHeapRegs();
-    sp<IMemory> mapMemory(size_t offset, size_t size);
-    virtual void revoke();
-private:
-    wp<GPUHardware> mGPU;
-};
 
-MemoryHeapRegs::MemoryHeapRegs(const wp<GPUHardware>& gpu, const sp<MemoryHeapBase>& heap)
-    :  MemoryHeapPmem(heap), mGPU(gpu)
+sp<MemoryHeapPmem::MemoryPmem> GPURegisterHeap::MemoryHeapRegs::createMemory(
+        size_t offset, size_t size)
 {
+    sp<GPUHandle> memory;
+    sp<GPUHardware> gpu = mGPU.promote();
+    if (heapID()>0 && gpu!=0) {
 #if HAVE_ANDROID_OS
-    if (heapID()>0) {
         /* this is where the GPU is powered on and the registers are mapped
          * in the client */
         //LOGD("ioctl(HW3D_GRANT_GPU)");
@@ -174,27 +301,16 @@
             // it can happen if the master heap has been closed already
             // in which case the GPU already is revoked (app crash for
             // instance).
-            //LOGW("HW3D_GRANT_GPU failed (%s), mFD=%d, base=%p",
-            //        strerror(errno), heapID(), base());
+            LOGW("HW3D_GRANT_GPU failed (%s), mFD=%d, base=%p",
+                    strerror(errno), heapID(), base());
         }
-    }
-#endif
-}
-
-MemoryHeapRegs::~MemoryHeapRegs() 
-{
-}
-
-sp<IMemory> MemoryHeapRegs::mapMemory(size_t offset, size_t size)
-{
-    sp<GPUHandle> memory;
-    sp<GPUHardware> gpu = mGPU.promote();
-    if (heapID()>0 && gpu!=0) 
         memory = new GPUHandle(gpu, this);
+#endif
+    }
     return memory;
 }
 
-void MemoryHeapRegs::revoke() 
+void GPURegisterHeap::MemoryHeapRegs::revoke() 
 {
     MemoryHeapPmem::revoke();
 #if HAVE_ANDROID_OS
@@ -207,25 +323,6 @@
 #endif
 }
 
-// ---------------------------------------------------------------------------
-
-class GPURegisterHeap : public PMemHeapInterface
-{
-public:
-    GPURegisterHeap(const sp<GPUHardware>& gpu)
-        : PMemHeapInterface("/dev/hw3d", GPUR_SIZE), mGPU(gpu)
-    {
-    }
-    virtual ~GPURegisterHeap() {
-    }
-    virtual sp<MemoryHeapPmem> createClientHeap() {
-        sp<MemoryHeapBase> parentHeap(this);
-        return new MemoryHeapRegs(mGPU, parentHeap);
-    }
-private:
-    wp<GPUHardware> mGPU;
-};
-
 /*****************************************************************************/
 
 GPUHardware::GPUHardware()
@@ -237,85 +334,87 @@
 {
 }
 
-sp<MemoryDealer> GPUHardware::request(int pid)
+status_t GPUHardware::requestLocked(int pid)
 {
-    sp<MemoryDealer> dealer;
-
-    LOGD("pid %d requesting gpu surface (current owner = %d)", pid, mOwner);
-
     const int self_pid = getpid();
     if (pid == self_pid) {
         // can't use GPU from surfaceflinger's process
-        return dealer;
-    }
-
-    Mutex::Autolock _l(mLock);
-    
-    if (mOwner != pid) {
-        // someone already has the gpu.
-        takeBackGPULocked();
-
-        // releaseLocked() should be a no-op most of the time
-        releaseLocked();
-
-        requestLocked(); 
-    }
-
-    dealer = mAllocator;
-    mOwner = pid;
-    if (dealer == 0) {
-        mOwner = SURFACE_FAILED;
-    }
-    
-    LOGD_IF(dealer!=0, "gpu surface granted to pid %d", mOwner);
-    return dealer;
-}
-
-status_t GPUHardware::request(const sp<IGPUCallback>& callback,
-        ISurfaceComposer::gpu_info_t* gpu)
-{
-    sp<IMemory> gpuHandle;
-    IPCThreadState* ipc = IPCThreadState::self();
-    const int pid = ipc->getCallingPid();
-    const int self_pid = getpid();
-
-    LOGD("pid %d requesting gpu core (owner = %d)", pid, mOwner);
-
-    if (pid == self_pid) {
-        // can't use GPU from surfaceflinger's process
         return PERMISSION_DENIED;
     }
 
-    Mutex::Autolock _l(mLock);
     if (mOwner != pid) {
-        // someone already has the gpu.
-        takeBackGPULocked();
-
-        // releaseLocked() should be a no-op most of the time
-        releaseLocked();
-
-        requestLocked(); 
+        if (mREGHeap != 0) {
+            if (mOwner != NO_OWNER) {
+                // someone already has the gpu.
+                takeBackGPULocked();
+                releaseLocked();
+            }
+        } else {
+            // first time, initialize the stuff.
+            if (mSMIHeap == 0)
+                mSMIHeap = new GPUAreaHeap(this, "/dev/pmem_gpu0");
+            if (mEBIHeap == 0)
+                mEBIHeap = new GPUAreaHeap(this, 
+                        "/dev/pmem_gpu1", 0, GPU_RESERVED_SIZE);
+            mREGHeap = new GPURegisterHeap(this);
+            mAllocator = mEBIHeap->getAllocator();
+            if (mAllocator == NULL) {
+                // something went terribly wrong.
+                mSMIHeap.clear();
+                mEBIHeap.clear();
+                mREGHeap.clear();
+                return INVALID_OPERATION;
+            }
+        }
+        Client& client = getClientLocked(pid);
+        mCurrentAllocator = new MemoryDealer(client.ebi.clientHeap, mAllocator);
+        mOwner = pid;
     }
+    return NO_ERROR;
+}
 
-    if (mHeapR.isValid()) {
+sp<MemoryDealer> GPUHardware::request(int pid)
+{
+    sp<MemoryDealer> dealer;
+    Mutex::Autolock _l(mLock);
+    Client* client;
+    LOGD("pid %d requesting gpu surface (current owner = %d)", pid, mOwner);
+    if (requestLocked(pid) == NO_ERROR) {
+        dealer = mCurrentAllocator;
+        LOGD_IF(dealer!=0, "gpu surface granted to pid %d", mOwner);
+    }
+    return dealer;
+}
+
+status_t GPUHardware::request(int pid, const sp<IGPUCallback>& callback,
+        ISurfaceComposer::gpu_info_t* gpu)
+{
+    if (callback == 0)
+        return BAD_VALUE;
+
+    sp<IMemory> gpuHandle;
+    LOGD("pid %d requesting gpu core (owner = %d)", pid, mOwner);
+    Mutex::Autolock _l(mLock);
+    status_t err = requestLocked(pid);
+    if (err == NO_ERROR) {
+        // it's guaranteed to be there, be construction
+        Client& client = mClients.editValueFor(pid);
+        registerCallbackLocked(callback, client);
         gpu->count = 2;
-        gpu->regions[0].region = mHeap0.map(true);
-        gpu->regions[0].reserved = mHeap0.reserved;
-        gpu->regions[1].region = mHeap1.map(true);
-        gpu->regions[1].reserved = mHeap1.reserved;
-        gpu->regs = mHeapR.map();
+        gpu->regions[0].region = client.smi.map();
+        gpu->regions[1].region = client.ebi.map();
+        gpu->regs              = client.reg.map();
+        gpu->regions[0].reserved = 0;
+        gpu->regions[1].reserved = GPU_RESERVED_SIZE;
         if (gpu->regs != 0) {
-            static_cast< GPUHandle* >(gpu->regs.get())->setOwner(pid);
+            //LOGD("gpu core granted to pid %d, handle base=%p",
+            //        mOwner, gpu->regs->pointer());
         }
         mCallback = callback;
-        mOwner = pid;
-        //LOGD("gpu core granted to pid %d, handle base=%p",
-        //        mOwner, gpu->regs->pointer());
     } else {
         LOGW("couldn't grant gpu core to pid %d", pid);
     }
-
-    return NO_ERROR;
+    return err;
 }
 
 void GPUHardware::revoke(int pid)
@@ -330,16 +429,16 @@
         // mOwner could be <0 if the same process acquired the GPU
         // several times without releasing it first.
         mCondition.signal();
-        releaseLocked(true);
+        releaseLocked();
     }
 }
 
 status_t GPUHardware::friendlyRevoke()
 {
     Mutex::Autolock _l(mLock);
-    takeBackGPULocked();
     //LOGD("friendlyRevoke owner=%d", mOwner);
-    releaseLocked(true);
+    takeBackGPULocked();
+    releaseLocked();
     return NO_ERROR;
 }
 
@@ -353,90 +452,37 @@
     }
 }
 
-void GPUHardware::requestLocked()
+void GPUHardware::releaseLocked()
 {
-    if (mAllocator == 0) {
-        GPUPart* part = 0;
-        sp<PMemHeap> surfaceHeap;
-        if (mHeap1.promote() == false) {
-            //LOGD("requestLocked: (1) creating new heap");
-            mHeap1.set(new PMemHeap("/dev/pmem_gpu1", 0, GPU_RESERVED_SIZE));
+    //LOGD("revoking gpu from pid %d", mOwner);
+    if (mOwner != NO_OWNER) {
+        // this may fail because the client might have died, and have
+        // been removed from the list.
+        ssize_t index = mClients.indexOfKey(mOwner);
+        if (index >= 0) {
+            Client& client(mClients.editValueAt(index));
+            client.revokeAllHeaps();
         }
-        if (mHeap1.isValid()) {
-            //LOGD("requestLocked: (1) heap is valid");
-            // NOTE: if GPU1 is available we use it for our surfaces
-            // this could be device specific, so we should do something more
-            // generic
-            surfaceHeap = static_cast< PMemHeap* >( mHeap1.getHeap().get() );
-            part = &mHeap1;
-            if (mHeap0.promote() == false) {
-                //LOGD("requestLocked: (0) creating new heap");
-                mHeap0.set(new PMemHeap("/dev/pmem_gpu0"));
-            }
-        } else {
-            //LOGD("requestLocked: (1) heap is not valid");
-            // No GPU1, use GPU0 only
-            if (mHeap0.promote() == false) {
-                //LOGD("requestLocked: (0) creating new heap");
-                mHeap0.set(new PMemHeap("/dev/pmem_gpu0", 0, GPU_RESERVED_SIZE));
-            }
-            if (mHeap0.isValid()) {
-                //LOGD("requestLocked: (0) heap is valid");
-                surfaceHeap = static_cast< PMemHeap* >( mHeap0.getHeap().get() );
-                part = &mHeap0;
-            }
-        }
-        
-        if (mHeap0.isValid() || mHeap1.isValid()) {
-            if (mHeapR.promote() == false) {
-                //LOGD("requestLocked: (R) creating new register heap");
-                mHeapR.set(new GPURegisterHeap(this));
-            }
-        } else {
-            // we got nothing...
-            mHeap0.clear();
-            mHeap1.clear();
-        }
-
-        if (mHeapR.isValid() == false) {
-            //LOGD("requestLocked: (R) register heap not valid!!!");
-            // damn, couldn't get the gpu registers!
-            mHeap0.clear();
-            mHeap1.clear();
-            surfaceHeap.clear();
-            part = NULL;
-        }
-
-        if (surfaceHeap != 0 && part && part->getClientHeap()!=0) {
-            part->reserved = GPU_RESERVED_SIZE;
-            part->surface = true;
-            mAllocatorDebug = static_cast<SimpleBestFitAllocator*>(
-                    surfaceHeap->getAllocator().get());
-            mAllocator = new MemoryDealer(
-                    part->getClientHeap(),
-                    surfaceHeap->getAllocator());
-        }
+        mOwner = NO_OWNER;
+        mCurrentAllocator.clear();
+        mCallback.clear();
     }
 }
 
-void GPUHardware::releaseLocked(bool dispose)
+GPUHardware::Client& GPUHardware::getClientLocked(pid_t pid)
 {
-    /* 
-     * if dispose is set, we will force the destruction of the heap,
-     * so it is given back to other systems, such as camera.
-     * Otherwise, we'll keep a weak pointer to it, this way we might be able
-     * to reuse it later if it's still around. 
-     */
-    //LOGD("revoking gpu from pid %d", mOwner);
-    mOwner = NO_OWNER;
-    mAllocator.clear();
-    mCallback.clear();
-
-    /* if we're asked for a full revoke, dispose only of the heap
-     * we're not using for surface (as we might need it while drawing) */
-    mHeap0.release(mHeap0.surface ? false : dispose);
-    mHeap1.release(mHeap1.surface ? false : dispose);
-    mHeapR.release(false);
+    ssize_t index = mClients.indexOfKey(pid);
+    if (index < 0) {
+        Client client;
+        client.pid = pid;
+        client.smi.heap = mSMIHeap;
+        client.ebi.heap = mEBIHeap;
+        client.reg.heap = mREGHeap;
+        index = mClients.add(pid, client);
+    }
+    Client& client(mClients.editValueAt(index));
+    client.createClientHeaps();
+    return client;
 }
 
 // ----------------------------------------------------------------------------
@@ -444,8 +490,7 @@
 
 sp<SimpleBestFitAllocator> GPUHardware::getAllocator() const {
     Mutex::Autolock _l(mLock);
-    sp<SimpleBestFitAllocator> allocator = mAllocatorDebug.promote();
-    return allocator;
+    return mAllocator;
 }
 
 void GPUHardware::unconditionalRevoke()
@@ -456,102 +501,81 @@
 
 // ---------------------------------------------------------------------------
 
-
-GPUHardware::GPUPart::GPUPart()
-    : surface(false), reserved(0)
-{
-}
-
-GPUHardware::GPUPart::~GPUPart() {
-}
-    
-const sp<PMemHeapInterface>& GPUHardware::GPUPart::getHeap() const {
-    return mHeap;
-}
-
-const sp<MemoryHeapPmem>& GPUHardware::GPUPart::getClientHeap() const {
-    return mClientHeap;
-}
-
-bool GPUHardware::GPUPart::isValid() const {
-    return ((mHeap!=0) && (mHeap->base() != MAP_FAILED));
-}
-
-void GPUHardware::GPUPart::clear() 
-{
-    mHeap.clear();
-    mHeapWeak.clear();
-    mClientHeap.clear();
-    surface = false;
-}
-
-void GPUHardware::GPUPart::set(const sp<PMemHeapInterface>& heap) 
-{
-    mHeapWeak.clear();
-    if (heap!=0 && heap->base() == MAP_FAILED) {
-        mHeap.clear();
-        mClientHeap.clear();
-    } else { 
-        mHeap = heap;
-        mClientHeap = mHeap->createClientHeap();
-    }
-}
-
-bool GPUHardware::GPUPart::promote() 
-{
-    //LOGD("mHeapWeak=%p, mHeap=%p", mHeapWeak.unsafe_get(), mHeap.get());
-    if (mHeap == 0) {
-        mHeap = mHeapWeak.promote();
-    }
-    if (mHeap != 0) {
-        if (mClientHeap != 0) {
-            mClientHeap->revoke();
-        }
-        mClientHeap = mHeap->createClientHeap();
-    }  else {
-        surface = false;
-    }
-    return mHeap != 0;
-}
-
-sp<IMemory> GPUHardware::GPUPart::map(bool clear) 
-{
+sp<IMemory> GPUHardware::GPUArea::map() {
     sp<IMemory> memory;
-    if (mClientHeap != NULL) {
-        memory = mClientHeap->mapMemory(0, mHeap->virtualSize());
-        if (clear && memory!=0) {
-            //StopWatch sw("memset");
-            memset(memory->pointer(), 0, memory->size());
-        }
+    if (clientHeap != 0 && heap != 0) {
+        memory = clientHeap->mapMemory(0, heap->virtualSize());
     }
     return memory;
 }
 
-void GPUHardware::GPUPart::release(bool dispose)
+void GPUHardware::Client::createClientHeaps() 
 {
-    if (mClientHeap != 0) {
-        mClientHeap->revoke();
-        mClientHeap.clear();
+    if (smi.clientHeap == 0)
+        smi.clientHeap = smi.heap->createClientHeap();
+    if (ebi.clientHeap == 0)
+        ebi.clientHeap = ebi.heap->createClientHeap();
+    if (reg.clientHeap == 0)
+        reg.clientHeap = reg.heap->createClientHeap();
+}
+
+void GPUHardware::Client::revokeAllHeaps() 
+{
+    if (smi.clientHeap != 0)
+        smi.clientHeap->revoke();
+    if (ebi.clientHeap != 0)
+        ebi.clientHeap->revoke();
+    if (reg.clientHeap != 0)
+        reg.clientHeap->revoke();
+}
+
+void GPUHardware::registerCallbackLocked(const sp<IGPUCallback>& callback,
+        Client& client)
+{
+    sp<IBinder> binder = callback->asBinder();
+    if (mRegisteredClients.add(binder, client.pid) >= 0) {
+        binder->linkToDeath(this);
     }
-    if (dispose) {
-        if (mHeapWeak!=0 && mHeap==0) {
-            mHeap = mHeapWeak.promote();
-        }
-        if (mHeap != 0) {
-            mHeap->dispose();
-            mHeapWeak.clear();
-            mHeap.clear();
-        } else {
-            surface = false;
-        }
-    } else {
-        if (mHeap != 0) {
-            mHeapWeak = mHeap;
-            mHeap.clear();
+}
+
+void GPUHardware::binderDied(const wp<IBinder>& who)
+{
+    Mutex::Autolock _l(mLock);
+    pid_t pid = mRegisteredClients.valueFor(who);
+    if (pid != 0) {
+        ssize_t index = mClients.indexOfKey(pid);
+        if (index >= 0) {
+            //LOGD("*** removing client at %d", index);
+            Client& client(mClients.editValueAt(index));
+            client.revokeAllHeaps(); // not really needed in theory
+            mClients.removeItemsAt(index);
+            if (mClients.size() == 0) {
+                //LOGD("*** was last client closing everything");
+                mCallback.clear();
+                mAllocator.clear();
+                mCurrentAllocator.clear();
+                mSMIHeap.clear();
+                mREGHeap.clear();
+                
+                // NOTE: we cannot clear the EBI heap because surfaceflinger
+                // itself may be using it, since this is where surfaces
+                // are allocated. if we're in the middle of compositing 
+                // a surface (even if its process just died), we cannot
+                // rip the heap under our feet.
+                
+                mOwner = NO_OWNER;
+            }
         }
     }
 }
 
 // ---------------------------------------------------------------------------
+
+sp<GPUHardwareInterface> GPUFactory::getGPU()
+{
+    return new GPUHardware();
+}
+
+// ---------------------------------------------------------------------------
 }; // namespace android
 
diff --git a/libs/surfaceflinger/GPUHardware/GPUHardware.h b/libs/surfaceflinger/GPUHardware/GPUHardware.h
index 9a78b99..3354528 100644
--- a/libs/surfaceflinger/GPUHardware/GPUHardware.h
+++ b/libs/surfaceflinger/GPUHardware/GPUHardware.h
@@ -22,92 +22,39 @@
 
 #include <utils/RefBase.h>
 #include <utils/threads.h>
+#include <utils/KeyedVector.h>
+
+#include <ui/ISurfaceComposer.h>
 
 namespace android {
 
 // ---------------------------------------------------------------------------
 
-class GPUHardwareInterface : public RefBase
+class IGPUCallback;
+
+class GPUHardwareInterface : public virtual RefBase
 {
 public:
     virtual void                revoke(int pid) = 0;
     virtual sp<MemoryDealer>    request(int pid) = 0;
-    virtual status_t            request(const sp<IGPUCallback>& callback,
+    virtual status_t            request(int pid, const sp<IGPUCallback>& callback,
             ISurfaceComposer::gpu_info_t* gpu) = 0;
 
     virtual status_t            friendlyRevoke() = 0;
-    virtual void                unconditionalRevoke() = 0;
     
     // used for debugging only...
     virtual sp<SimpleBestFitAllocator> getAllocator() const  = 0;
     virtual pid_t getOwner() const = 0;
+    virtual void unconditionalRevoke() = 0;
 };
 
 // ---------------------------------------------------------------------------
 
-class IMemory;
-class MemoryHeapPmem;
-class PMemHeap;
-
-class GPUHardware : public GPUHardwareInterface
-{
+class GPUFactory
+{    
 public:
-            GPUHardware();
-    virtual ~GPUHardware();
-    
-    virtual void                revoke(int pid);
-    virtual sp<MemoryDealer>    request(int pid);
-    virtual status_t            request(const sp<IGPUCallback>& callback,
-            ISurfaceComposer::gpu_info_t* gpu);
-
-    virtual status_t            friendlyRevoke();
-    virtual void                unconditionalRevoke();
-    
-    // used for debugging only...
-    virtual sp<SimpleBestFitAllocator> getAllocator() const;
-    virtual pid_t getOwner() const { return mOwner; }
-    
-private:
-    enum {
-        NO_OWNER        = -1,
-        SURFACE_FAILED  = -2
-    };
-    
-    void requestLocked();
-    void releaseLocked(bool dispose = false);
-    void takeBackGPULocked();
-    
-    class GPUPart
-    {
-    public:
-        bool surface;
-        size_t reserved;
-        GPUPart();
-        ~GPUPart();
-        const sp<PMemHeapInterface>& getHeap() const;
-        const sp<MemoryHeapPmem>& getClientHeap() const;
-        bool isValid() const;
-        void clear();
-        void set(const sp<PMemHeapInterface>& heap);
-        bool promote();
-        sp<IMemory> map(bool clear = false);
-        void release(bool dispose);
-    private:
-        sp<PMemHeapInterface>   mHeap;
-        wp<PMemHeapInterface>   mHeapWeak;
-        sp<MemoryHeapPmem>      mClientHeap;
-    };
-    
-    mutable Mutex   mLock;
-    GPUPart         mHeap0; // SMI
-    GPUPart         mHeap1; // EBI1
-    GPUPart         mHeapR;
-    sp<MemoryDealer> mAllocator;
-    pid_t            mOwner;
-    sp<IGPUCallback> mCallback;
-    wp<SimpleBestFitAllocator> mAllocatorDebug;
-    
-    Condition       mCondition;
+    // the gpu factory
+    static sp<GPUHardwareInterface> getGPU();
 };
 
 // ---------------------------------------------------------------------------
diff --git a/libs/surfaceflinger/Layer.cpp b/libs/surfaceflinger/Layer.cpp
index 4f6bae1..8ba0851 100644
--- a/libs/surfaceflinger/Layer.cpp
+++ b/libs/surfaceflinger/Layer.cpp
@@ -92,26 +92,29 @@
     status_t err = getPixelFormatInfo(format, &info);
     if (err) return err;
 
-    // TODO: if eHardware is explicitely requested, we should fail
+    // TODO: if eHardware is explicitly requested, we should fail
     // on systems where we can't allocate memory that can be used with
     // DMA engines for instance.
+    
+    // FIXME: we always ask for hardware for now (this should come from copybit)
+    flags |= ISurfaceComposer::eHardware;
 
-    int memory_type = NATIVE_MEMORY_TYPE_PMEM;
+    const uint32_t memory_flags = flags & 
+            (ISurfaceComposer::eGPU | 
+             ISurfaceComposer::eHardware | 
+             ISurfaceComposer::eSecure);
     
     // pixel-alignment. the final alignment may be bigger because
     // we always force a 4-byte aligned bpr.
     uint32_t alignment = 1;
 
-    const uint32_t mask = ISurfaceComposer::eGPU | ISurfaceComposer::eSecure;
-    if ((flags & mask) == ISurfaceComposer::eGPU) {
-        // don't grant GPU memory if GPU is disabled
-        char value[PROPERTY_VALUE_MAX];
-        property_get("debug.egl.hw", value, "1");
-        if (atoi(value) != 0) {
-            flags |= ISurfaceComposer::eHardware;
-            memory_type = NATIVE_MEMORY_TYPE_GPU;
-            // TODO: this value should come from the h/w
-            alignment = 8; 
+    if (flags & ISurfaceComposer::eGPU) {
+        // FIXME: this value should come from the h/w
+        alignment = 8; 
+        // FIXME: this is msm7201A specific, as its GPU only supports
+        // BGRA_8888.
+        if (format == PIXEL_FORMAT_RGBA_8888) {
+            format = PIXEL_FORMAT_BGRA_8888;
         }
     }
 
@@ -119,7 +122,7 @@
     mNeedsBlending = (info.h_alpha - info.l_alpha) > 0;
     sp<MemoryDealer> allocators[2];
     for (int i=0 ; i<2 ; i++) {
-        allocators[i] = client->createAllocator(memory_type);
+        allocators[i] = client->createAllocator(memory_flags);
         if (allocators[i] == 0)
             return NO_MEMORY;
         mBuffers[i].init(allocators[i]);
@@ -133,7 +136,7 @@
     mSurface = new Surface(clientIndex(),
             allocators[0]->getMemoryHeap(),
             allocators[1]->getMemoryHeap(),
-            memory_type, mIdentity);
+            mIdentity);
 
     return NO_ERROR;
 }
@@ -180,7 +183,7 @@
         front.getBitmapSurface(&src);
         copybit_rect_t srect = { 0, 0, t.width, t.height };
 
-        copybit_t* copybit = mFlinger->getBlitEngine();
+        copybit_device_t* copybit = mFlinger->getBlitEngine();
         copybit->set_parameter(copybit, COPYBIT_TRANSFORM, getOrientation());
         copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, s.alpha);
         copybit->set_parameter(copybit, COPYBIT_DITHER,
diff --git a/libs/surfaceflinger/LayerBase.cpp b/libs/surfaceflinger/LayerBase.cpp
index 17c9f42..af353e2 100644
--- a/libs/surfaceflinger/LayerBase.cpp
+++ b/libs/surfaceflinger/LayerBase.cpp
@@ -30,7 +30,7 @@
 #include "DisplayHardware/DisplayHardware.h"
 
 
-// We don't honor the premultipliad alpha flags, which means that
+// We don't honor the premultiplied alpha flags, which means that
 // premultiplied surface may be composed using a non-premultiplied
 // equation. We do this because it may be a lot faster on some hardware
 // The correct value is HONOR_PREMULTIPLIED_ALPHA = 1
@@ -256,7 +256,7 @@
 
     // see if we can/should use 2D h/w with the new configuration
     mCanUseCopyBit = false;
-    copybit_t* copybit = mFlinger->getBlitEngine();
+    copybit_device_t* copybit = mFlinger->getBlitEngine();
     if (copybit) { 
         const int step = copybit->get(copybit, COPYBIT_ROTATION_STEP_DEG);
         const int scaleBits = copybit->get(copybit, COPYBIT_SCALING_FRAC_BITS);
@@ -413,7 +413,7 @@
         // premultiplied alpha.
         
         // If the texture doesn't have an alpha channel we can
-        // use REPLACE and switch to non premultiplied-alpha
+        // use REPLACE and switch to non premultiplied alpha
         // blending (SRCA/ONE_MINUS_SRCA).
         
         GLenum env, src;
@@ -431,11 +431,11 @@
         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);
         if (needsBlending()) {
             GLenum src = mPremultipliedAlpha ? GL_ONE : GL_SRC_ALPHA;
             glEnable(GL_BLEND);
             glBlendFunc(src, GL_ONE_MINUS_SRC_ALPHA);
-            glColor4x(0x10000, 0x10000, 0x10000, 0x10000);
         } else {
             glDisable(GL_BLEND);
         }
@@ -463,7 +463,7 @@
             glMatrixMode(GL_TEXTURE);
             glLoadIdentity();
             if (!(mFlags & DisplayHardware::NPOT_EXTENSION)) {
-                // find the smalest power-of-two that will accomodate our surface
+                // find the smallest power-of-two that will accommodate our surface
                 GLuint tw = 1 << (31 - clz(t.width));
                 GLuint th = 1 << (31 - clz(t.height));
                 if (tw < t.width)  tw <<= 1;
@@ -556,7 +556,7 @@
     GLuint texture_w = tw;
     GLuint texture_h = th;
     if (!(flags & DisplayHardware::NPOT_EXTENSION)) {
-        // find the smalest power-of-two that will accomodate our surface
+        // find the smallest power-of-two that will accommodate our surface
         texture_w = 1 << (31 - clz(t.width));
         texture_h = 1 << (31 - clz(t.height));
         if (texture_w < t.width)  texture_w <<= 1;
@@ -582,6 +582,8 @@
             glTexImage2D(GL_DIRECT_TEXTURE_2D_QUALCOMM, 0,
                     GL_RGBA, tw, th, 0,
                     GL_RGBA, GL_UNSIGNED_BYTE, t.data);
+        } else if (t.format == GGL_PIXEL_FORMAT_BGRA_8888) {
+            // TODO: add GL_BGRA extension
         } else {
             // oops, we don't handle this format, try the regular path
             goto regular;
@@ -592,7 +594,7 @@
 regular:
         Rect bounds(dirty.bounds());
         GLvoid* data = 0;
-        if (texture_w!=textureWidth || texture_w!=textureHeight) {
+        if (texture_w!=textureWidth || texture_h!=textureHeight) {
             // texture size changed, we need to create a new one
 
             if (!textureWidth || !textureHeight) {
@@ -606,31 +608,36 @@
                     bounds.set(Rect(tw, th));
                 }
             }
-
+            
             if (t.format == GGL_PIXEL_FORMAT_RGB_565) {
                 glTexImage2D(GL_TEXTURE_2D, 0,
-                        GL_RGB, tw, th, 0,
+                        GL_RGB, texture_w, texture_h, 0,
                         GL_RGB, GL_UNSIGNED_SHORT_5_6_5, data);
             } else if (t.format == GGL_PIXEL_FORMAT_RGBA_4444) {
                 glTexImage2D(GL_TEXTURE_2D, 0,
-                        GL_RGBA, tw, th, 0,
+                        GL_RGBA, texture_w, texture_h, 0,
                         GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, data);
             } else if (t.format == GGL_PIXEL_FORMAT_RGBA_8888) {
                 glTexImage2D(GL_TEXTURE_2D, 0,
-                        GL_RGBA, tw, th, 0,
+                        GL_RGBA, texture_w, texture_h, 0,
                         GL_RGBA, GL_UNSIGNED_BYTE, data);
             } else if ( t.format == GGL_PIXEL_FORMAT_YCbCr_422_SP ||
                         t.format == GGL_PIXEL_FORMAT_YCbCr_420_SP) {
                 // just show the Y plane of YUV buffers
                 data = t.data;
                 glTexImage2D(GL_TEXTURE_2D, 0,
-                        GL_LUMINANCE, tw, th, 0,
+                        GL_LUMINANCE, texture_w, texture_h, 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, textureName, t.format);
+                textureName = -1;
             }
-            textureWidth = tw;
-            textureHeight = th;
+            textureWidth = texture_w;
+            textureHeight = texture_h;
         }
-        if (!data) {
+        if (!data && textureName>=0) {
             if (t.format == GGL_PIXEL_FORMAT_RGB_565) {
                 glTexSubImage2D(GL_TEXTURE_2D, 0,
                         0, bounds.top, t.width, bounds.height(),
diff --git a/libs/surfaceflinger/LayerBase.h b/libs/surfaceflinger/LayerBase.h
index 10c1bc1..b3f3771 100644
--- a/libs/surfaceflinger/LayerBase.h
+++ b/libs/surfaceflinger/LayerBase.h
@@ -23,6 +23,8 @@
 #include <private/ui/LayerState.h>
 
 #include <ui/Region.h>
+#include <ui/Overlay.h>
+
 #include <pixelflinger/pixelflinger.h>
 
 #include "Transform.h"
@@ -223,16 +225,14 @@
         Surface(SurfaceID id, int identity) { 
             mParams.token = id;
             mParams.identity = identity;
-            mParams.type = 0;
         }
         Surface(SurfaceID id, 
                 const sp<IMemoryHeap>& heap0,
                 const sp<IMemoryHeap>& heap1,
-                int memory_type, int identity)
+                int identity)
         {
             mParams.token = id;
             mParams.identity = identity;
-            mParams.type = memory_type;
             mParams.heap[0] = heap0;
             mParams.heap[1] = heap1;
         }
@@ -240,8 +240,8 @@
             // TODO: We now have a point here were we can clean-up the
             // client's mess.
             // This is also where surface id should be recycled.
-            //LOGD("Surface %d, heaps={%p, %p}, type=%d destroyed",
-            //        mId, mHeap[0].get(), mHeap[1].get(), mMemoryType);
+            //LOGD("Surface %d, heaps={%p, %p} destroyed",
+            //        mId, mHeap[0].get(), mHeap[1].get());
         }
 
         virtual void getSurfaceData(
@@ -254,6 +254,10 @@
                 { return INVALID_OPERATION; }
         virtual void postBuffer(ssize_t offset) { }
         virtual void unregisterBuffers() { };
+        virtual sp<Overlay> createOverlay(
+                uint32_t w, uint32_t h, int32_t format) {
+            return NULL;
+        };
 
     private:
         ISurfaceFlingerClient::surface_data_t mParams;
diff --git a/libs/surfaceflinger/LayerBlur.cpp b/libs/surfaceflinger/LayerBlur.cpp
index 192ceda..e3ae7fb 100644
--- a/libs/surfaceflinger/LayerBlur.cpp
+++ b/libs/surfaceflinger/LayerBlur.cpp
@@ -145,11 +145,13 @@
             mRefreshCache = false;
             mAutoRefreshPending = false;
             
-            uint16_t* const pixels = (uint16_t*)malloc(w*h*2);
+            // allocate enough memory for 4-bytes (2 pixels) aligned data
+            const int32_t s = (w + 1) & ~1;
+            uint16_t* const pixels = (uint16_t*)malloc(s*h*2);
 
-            // this reads the frame-buffer, so a h/w GL would have to
+            // This reads the frame-buffer, so a h/w GL would have to
             // finish() its rendering first. we don't want to do that
-            // too often.
+            // too often. Read data is 4-bytes aligned.
             glReadPixels(X, Y, w, h, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, pixels);
             
             // blur that texture.
@@ -157,7 +159,7 @@
             bl.version = sizeof(GGLSurface);
             bl.width = w;
             bl.height = h;
-            bl.stride = w;
+            bl.stride = s;
             bl.format = GGL_PIXEL_FORMAT_RGB_565;
             bl.data = (GGLubyte*)pixels;            
             blurFilter(&bl, 8, 2);
diff --git a/libs/surfaceflinger/LayerBuffer.cpp b/libs/surfaceflinger/LayerBuffer.cpp
index d871fc3..3861e681 100644
--- a/libs/surfaceflinger/LayerBuffer.cpp
+++ b/libs/surfaceflinger/LayerBuffer.cpp
@@ -104,7 +104,7 @@
          * the requested scale factor, in which case we perform the scaling
          * in several passes. */
 
-        copybit_t* copybit = mFlinger->getBlitEngine();
+        copybit_device_t* copybit = mFlinger->getBlitEngine();
         const float min = copybit->get(copybit, COPYBIT_MINIFICATION_LIMIT);
         const float mag = copybit->get(copybit, COPYBIT_MAGNIFICATION_LIMIT);
 
@@ -123,7 +123,7 @@
             if (UNLIKELY(mTemporaryDealer == 0)) {
                 // allocate a memory-dealer for this the first time
                 mTemporaryDealer = mFlinger->getSurfaceHeapManager()
-                        ->createHeap(NATIVE_MEMORY_TYPE_PMEM);
+                        ->createHeap(ISurfaceComposer::eHardware);
                 mTempBitmap.init(mTemporaryDealer);
             }
 
@@ -230,7 +230,18 @@
 status_t LayerBuffer::registerBuffers(int w, int h, int hstride, int vstride,
             PixelFormat format, const sp<IMemoryHeap>& memoryHeap)
 {
-    status_t err = (memoryHeap!=0 && memoryHeap->heapID() >= 0) ? NO_ERROR : NO_INIT;
+    if (memoryHeap == NULL) {
+        // this is allowed, but in this case, it is illegal to receive
+        // postBuffer(). The surface just erases the framebuffer with
+        // fully transparent pixels.
+        mHeap.clear();
+        mWidth = w;
+        mHeight = h;
+        mNeedsBlending = false;
+        return NO_ERROR;
+    }
+    
+    status_t err = (memoryHeap->heapID() >= 0) ? NO_ERROR : NO_INIT;
     if (err != NO_ERROR)
         return err;
 
@@ -281,6 +292,32 @@
     invalidateLocked();
 }
 
+sp<Overlay> LayerBuffer::createOverlay(uint32_t w, uint32_t h, int32_t format)
+{
+    sp<Overlay> result;
+    Mutex::Autolock _l(mLock);
+    if (mHeap != 0 || mBuffer != 0) {
+        // we're a push surface. error.
+        return result;
+    }
+    
+    overlay_device_t* overlay_dev = mFlinger->getOverlayEngine();
+    if (overlay_dev == NULL) {
+        // overlays not supported
+        return result;
+    }
+
+    overlay_t* overlay = overlay_dev->createOverlay(overlay_dev, w, h, format);
+    if (overlay == NULL) {
+        // couldn't create the overlay (no memory? no more overlays?)
+        return result;
+    }
+    
+    /* TODO: implement the real stuff here */
+    
+    return result;
+}
+
 sp<LayerBuffer::Buffer> LayerBuffer::getBuffer() const
 {
     Mutex::Autolock _l(mLock);
@@ -330,6 +367,15 @@
         owner->unregisterBuffers();
 }
 
+sp<Overlay> LayerBuffer::SurfaceBuffer::createOverlay(
+        uint32_t w, uint32_t h, int32_t format) {
+    sp<Overlay> result;
+    LayerBuffer* owner(getOwner());
+    if (owner)
+        result = owner->createOverlay(w, h, format);
+    return result;
+}
+
 void LayerBuffer::SurfaceBuffer::disown()
 {
     Mutex::Autolock _l(mLock);
diff --git a/libs/surfaceflinger/LayerBuffer.h b/libs/surfaceflinger/LayerBuffer.h
index ef473dd..3e616f27 100644
--- a/libs/surfaceflinger/LayerBuffer.h
+++ b/libs/surfaceflinger/LayerBuffer.h
@@ -33,6 +33,7 @@
 
 class MemoryDealer;
 class Region;
+class Overlay;
 
 class LayerBuffer : public LayerBaseClient
 {
@@ -56,6 +57,7 @@
             PixelFormat format, const sp<IMemoryHeap>& heap);
     void postBuffer(ssize_t offset);
     void unregisterBuffers();
+    sp<Overlay> createOverlay(uint32_t w, uint32_t h, int32_t format);
     void invalidate();
     void invalidateLocked();
 
@@ -107,7 +109,9 @@
                 PixelFormat format, const sp<IMemoryHeap>& heap);
         virtual void postBuffer(ssize_t offset);
         virtual void unregisterBuffers();
-        void disown();
+        virtual sp<Overlay> createOverlay(
+                uint32_t w, uint32_t h, int32_t format);
+       void disown();
     private:
         LayerBuffer* getOwner() const {
             Mutex::Autolock _l(mLock);
diff --git a/libs/surfaceflinger/LayerDim.cpp b/libs/surfaceflinger/LayerDim.cpp
index fc23d53..0c347cc 100644
--- a/libs/surfaceflinger/LayerDim.cpp
+++ b/libs/surfaceflinger/LayerDim.cpp
@@ -48,7 +48,7 @@
 {
     // must only be called once.
     mDimmerDealer = flinger->getSurfaceHeapManager()
-            ->createHeap(NATIVE_MEMORY_TYPE_PMEM);
+            ->createHeap(ISurfaceComposer::eHardware);
     if (mDimmerDealer != 0) {
         mDimmerBitmap.init(mDimmerDealer);
         mDimmerBitmap.setBits(w, h, 1, PIXEL_FORMAT_RGB_565);
@@ -81,7 +81,7 @@
             mDimmerBitmap.getBitmapSurface(&src);
             const copybit_rect_t& srect(drect);
 
-            copybit_t* copybit = mFlinger->getBlitEngine();
+            copybit_device_t* copybit = mFlinger->getBlitEngine();
             copybit->set_parameter(copybit, COPYBIT_TRANSFORM, 0);
             copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, s.alpha);
             copybit->set_parameter(copybit, COPYBIT_DITHER, COPYBIT_ENABLE);
diff --git a/libs/surfaceflinger/SurfaceFlinger.cpp b/libs/surfaceflinger/SurfaceFlinger.cpp
index 45496b2..e8de21a3 100644
--- a/libs/surfaceflinger/SurfaceFlinger.cpp
+++ b/libs/surfaceflinger/SurfaceFlinger.cpp
@@ -38,7 +38,6 @@
 #include <utils/String16.h>
 #include <utils/StopWatch.h>
 
-#include <ui/BlitHardware.h>
 #include <ui/PixelFormat.h>
 #include <ui/DisplayInfo.h>
 #include <ui/EGLDisplaySurface.h>
@@ -202,23 +201,6 @@
 {
     LOGI("SurfaceFlinger is starting");
 
-    // create the shared control-block
-    mServerHeap = new MemoryDealer(4096, MemoryDealer::READ_ONLY);
-    LOGE_IF(mServerHeap==0, "can't create shared memory dealer");
-
-    mServerCblkMemory = mServerHeap->allocate(4096);
-    LOGE_IF(mServerCblkMemory==0, "can't create shared control block");
-
-    mServerCblk = static_cast<surface_flinger_cblk_t *>(mServerCblkMemory->pointer());
-    LOGE_IF(mServerCblk==0, "can't get to shared control block's address");
-    new(mServerCblk) surface_flinger_cblk_t;
-
-    // create the surface Heap manager, which manages the heaps
-    // (be it in RAM or VRAM) where surfaces are allocated
-    // We give 8 MB per client.
-    mSurfaceHeapManager = new SurfaceHeapManager(8 << 20);
-    mGPU = new GPUHardware();
-
     // debugging stuff...
     char value[PROPERTY_VALUE_MAX];
     property_get("debug.sf.showupdates", value, "0");
@@ -244,11 +226,16 @@
     glDeleteTextures(1, &mWormholeTexName);
 }
 
-copybit_t* SurfaceFlinger::getBlitEngine() const
+copybit_device_t* SurfaceFlinger::getBlitEngine() const
 {
     return graphicPlane(0).displayHardware().getBlitEngine();
 }
 
+overlay_device_t* SurfaceFlinger::getOverlayEngine() const
+{
+    return graphicPlane(0).displayHardware().getOverlayEngine();
+}
+
 sp<IMemory> SurfaceFlinger::getCblk() const
 {
     return mServerCblkMemory;
@@ -257,7 +244,9 @@
 status_t SurfaceFlinger::requestGPU(const sp<IGPUCallback>& callback,
         gpu_info_t* gpu)
 {
-    status_t err = mGPU->request(callback, gpu);
+    IPCThreadState* ipc = IPCThreadState::self();
+    const int pid = ipc->getCallingPid();
+    status_t err = mGPU->request(pid, callback, gpu);
     return err;
 }
 
@@ -360,7 +349,26 @@
     LOGI(   "SurfaceFlinger's main thread ready to run. "
             "Initializing graphics H/W...");
 
-    //
+    // create the shared control-block
+    mServerHeap = new MemoryDealer(4096, MemoryDealer::READ_ONLY);
+    LOGE_IF(mServerHeap==0, "can't create shared memory dealer");
+
+    mServerCblkMemory = mServerHeap->allocate(4096);
+    LOGE_IF(mServerCblkMemory==0, "can't create shared control block");
+
+    mServerCblk = static_cast<surface_flinger_cblk_t *>(mServerCblkMemory->pointer());
+    LOGE_IF(mServerCblk==0, "can't get to shared control block's address");
+    new(mServerCblk) surface_flinger_cblk_t;
+
+    // get a reference to the GPU if we have one
+    mGPU = GPUFactory::getGPU();
+
+    // create the surface Heap manager, which manages the heaps
+    // (be it in RAM or VRAM) where surfaces are allocated
+    // We give 8 MB per client.
+    mSurfaceHeapManager = new SurfaceHeapManager(this, 8 << 20);
+
+    
     GLES_localSurfaceManager = static_cast<ISurfaceComposer*>(this);
 
     // we only support one display currently
@@ -395,7 +403,7 @@
     dcblk->xdpi         = hw.getDpiX();
     dcblk->ydpi         = hw.getDpiY();
     dcblk->fps          = hw.getRefreshRate();
-    dcblk->density      = 1.0f; // XXX: do someting more real here...
+    dcblk->density      = hw.getDensity();
     asm volatile ("":::"memory");
 
     // Initialize OpenGL|ES
@@ -407,6 +415,7 @@
     glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
     glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
     glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
+    glPixelStorei(GL_PACK_ALIGNMENT, 4); 
     glEnableClientState(GL_VERTEX_ARRAY);
     glEnable(GL_SCISSOR_TEST);
     glShadeModel(GL_FLAT);
@@ -1679,7 +1688,7 @@
 Client::Client(ClientID clientID, const sp<SurfaceFlinger>& flinger)
     : ctrlblk(0), cid(clientID), mPid(0), mBitmap(0), mFlinger(flinger)
 {
-    mSharedHeapAllocator = getSurfaceHeapManager()->createHeap(NATIVE_MEMORY_TYPE_HEAP);
+    mSharedHeapAllocator = getSurfaceHeapManager()->createHeap();
     const int pgsize = getpagesize();
     const int cblksize=((sizeof(per_client_cblk_t)+(pgsize-1))&~(pgsize-1));
     mCblkHeap = new MemoryDealer(cblksize);
@@ -1703,10 +1712,6 @@
     return mFlinger->getSurfaceHeapManager();
 }
 
-const sp<GPUHardwareInterface>& Client::getGPU() const {
-    return mFlinger->getGPU();
-}
-
 int32_t Client::generateId(int pid)
 {
     const uint32_t i = clz( ~mBitmap );
@@ -1734,25 +1739,11 @@
     }
 }
 
-sp<MemoryDealer> Client::createAllocator(int memory_type)
+sp<MemoryDealer> Client::createAllocator(uint32_t flags)
 {
     sp<MemoryDealer> allocator;
-    if (memory_type == NATIVE_MEMORY_TYPE_GPU) {
-        allocator = getGPU()->request(getClientPid());
-        if (allocator == 0)
-            memory_type = NATIVE_MEMORY_TYPE_PMEM;
-    }
-    if (memory_type == NATIVE_MEMORY_TYPE_PMEM) {
-        allocator = mPMemAllocator;
-        if (allocator == 0) {
-            allocator = getSurfaceHeapManager()->createHeap(
-                    NATIVE_MEMORY_TYPE_PMEM);
-            mPMemAllocator = allocator;
-        }
-    }
-    if (allocator == 0)
-        allocator = mSharedHeapAllocator;
-
+    allocator = getSurfaceHeapManager()->createHeap(
+            flags, getClientPid(), mSharedHeapAllocator);
     return allocator;
 }
 
diff --git a/libs/surfaceflinger/SurfaceFlinger.h b/libs/surfaceflinger/SurfaceFlinger.h
index 1581474..92021d0 100644
--- a/libs/surfaceflinger/SurfaceFlinger.h
+++ b/libs/surfaceflinger/SurfaceFlinger.h
@@ -41,7 +41,8 @@
 #include "BootAnimation.h"
 #include "Barrier.h"
 
-struct copybit_t;
+struct copybit_device_t;
+struct overlay_device_t;
 
 namespace android {
 
@@ -74,7 +75,7 @@
             int32_t                 generateId(int pid);
             void                    free(int32_t id);
             status_t                bindLayer(LayerBaseClient* layer, int32_t id);
-            sp<MemoryDealer>        createAllocator(int memory_type);
+            sp<MemoryDealer>        createAllocator(uint32_t memory_type);
 
     inline  bool                    isValid(int32_t i) const;
     inline  const uint8_t*          inUseArray() const;
@@ -92,7 +93,6 @@
     
 private:
     int                     getClientPid() const { return mPid; }
-    const sp<GPUHardwareInterface>&  getGPU() const;
         
     int                         mPid;
     uint32_t                    mBitmap;
@@ -179,7 +179,8 @@
                 return mGPU; 
             }
 
-            copybit_t* getBlitEngine() const;
+            copybit_device_t* getBlitEngine() const;
+            overlay_device_t* getOverlayEngine() const;
             
 private:
     friend class BClient;
diff --git a/libs/surfaceflinger/VRamHeap.cpp b/libs/surfaceflinger/VRamHeap.cpp
index 3852d51..77bc576 100644
--- a/libs/surfaceflinger/VRamHeap.cpp
+++ b/libs/surfaceflinger/VRamHeap.cpp
@@ -37,6 +37,8 @@
 
 #include <GLES/eglnatives.h>
 
+#include "GPUHardware/GPUHardware.h"
+#include "SurfaceFlinger.h"
 #include "VRamHeap.h"
 
 #if HAVE_ANDROID_OS
@@ -59,8 +61,9 @@
 
 // ---------------------------------------------------------------------------
 
-SurfaceHeapManager::SurfaceHeapManager(size_t clientHeapSize)
-    : mClientHeapSize(clientHeapSize)
+SurfaceHeapManager::SurfaceHeapManager(const sp<SurfaceFlinger>& flinger, 
+        size_t clientHeapSize)
+    : mFlinger(flinger), mClientHeapSize(clientHeapSize)
 {
     SurfaceHeapManager::global_pmem_heap = 1;
 }
@@ -81,25 +84,53 @@
     }
 }
 
-sp<MemoryDealer> SurfaceHeapManager::createHeap(int type)
+sp<MemoryDealer> SurfaceHeapManager::createHeap(
+        uint32_t flags,
+        pid_t client_pid,
+        const sp<MemoryDealer>& defaultAllocator)
 {
-    if (!global_pmem_heap && type==NATIVE_MEMORY_TYPE_PMEM)
-        type = NATIVE_MEMORY_TYPE_HEAP;
-
-    const sp<PMemHeap>& heap(mPMemHeap);
     sp<MemoryDealer> dealer; 
-    switch (type) {
-    case NATIVE_MEMORY_TYPE_HEAP:
-        dealer = new MemoryDealer(mClientHeapSize, 0, "SFNativeHeap");
-        break;
 
-    case NATIVE_MEMORY_TYPE_PMEM:
-        if (heap != 0) {
-            dealer = new MemoryDealer( 
-                    heap->createClientHeap(),
-                    heap->getAllocator());
+    if (flags & ISurfaceComposer::eGPU) {
+        // don't grant GPU memory if GPU is disabled
+        char value[PROPERTY_VALUE_MAX];
+        property_get("debug.egl.hw", value, "1");
+        if (atoi(value) == 0) {
+            flags &= ~ISurfaceComposer::eGPU;
         }
-        break;
+    }
+
+    if (flags & ISurfaceComposer::eGPU) {
+        // FIXME: this is msm7201A specific, where gpu surfaces may not be secure
+        if (!(flags & ISurfaceComposer::eSecure)) {
+            // if GPU doesn't work, we try eHardware
+            flags |= ISurfaceComposer::eHardware;
+            // asked for GPU memory, try that first
+            dealer = mFlinger->getGPU()->request(client_pid);
+        }
+    }
+
+    if (dealer == NULL) {
+        if (defaultAllocator != NULL)
+            // if a default allocator is given, use that
+            dealer = defaultAllocator;
+    }
+    
+    if (dealer == NULL) {
+        // always try h/w accelerated memory first
+        if (global_pmem_heap) {
+            const sp<PMemHeap>& heap(mPMemHeap);
+            if (dealer == NULL && heap != NULL) {
+                dealer = new MemoryDealer( 
+                        heap->createClientHeap(),
+                        heap->getAllocator());
+            }
+        }
+    }
+
+    if (dealer == NULL) {
+        // return the ashmem allocator (software rendering)
+        dealer = new MemoryDealer(mClientHeapSize, 0, "SFNativeHeap");
     }
     return dealer;
 }
@@ -122,22 +153,8 @@
 
 // ---------------------------------------------------------------------------
 
-PMemHeapInterface::PMemHeapInterface(int fd, size_t size)
-    : MemoryHeapBase(fd, size) {
-}
-PMemHeapInterface::PMemHeapInterface(const char* device, size_t size)
-    : MemoryHeapBase(device, size) {
-}
-PMemHeapInterface::PMemHeapInterface(size_t size, uint32_t flags, char const * name)
-    : MemoryHeapBase(size, flags, name) {
-}
-PMemHeapInterface::~PMemHeapInterface() {
-}
-
-// ---------------------------------------------------------------------------
-
 PMemHeap::PMemHeap(const char* const device, size_t size, size_t reserved)
-    : PMemHeapInterface(device, size)
+    : MemoryHeapBase(device, size)
 {
     //LOGD("%s, %p, mFD=%d", __PRETTY_FUNCTION__, this, heapID());
     if (base() != MAP_FAILED) {
diff --git a/libs/surfaceflinger/VRamHeap.h b/libs/surfaceflinger/VRamHeap.h
index 03e0336..9140167 100644
--- a/libs/surfaceflinger/VRamHeap.h
+++ b/libs/surfaceflinger/VRamHeap.h
@@ -27,16 +27,19 @@
 
 class PMemHeap;
 class MemoryHeapPmem;
+class SurfaceFlinger; 
 
 // ---------------------------------------------------------------------------
 
 class SurfaceHeapManager  : public RefBase
 {
 public:
-    SurfaceHeapManager(size_t clientHeapSize);
+    SurfaceHeapManager(const sp<SurfaceFlinger>& flinger, size_t clientHeapSize);
     virtual ~SurfaceHeapManager();
     virtual void onFirstRef();
-    sp<MemoryDealer> createHeap(int type);
+    /* use ISurfaceComposer flags eGPU|eHArdware|eSecure */
+    sp<MemoryDealer> createHeap(uint32_t flags=0, pid_t client_pid = 0,
+            const sp<MemoryDealer>& defaultAllocator = 0);
     
     // used for debugging only...
     sp<SimpleBestFitAllocator> getAllocator(int type) const;
@@ -44,6 +47,7 @@
 private:
     sp<PMemHeap> getHeap(int type) const;
 
+    sp<SurfaceFlinger> mFlinger;
     mutable Mutex   mLock;
     size_t          mClientHeapSize;
     sp<PMemHeap>    mPMemHeap;
@@ -52,19 +56,7 @@
 
 // ---------------------------------------------------------------------------
 
-class PMemHeapInterface : public MemoryHeapBase
-{
-public:
-    PMemHeapInterface(int fd, size_t size);
-    PMemHeapInterface(const char* device, size_t size = 0);
-    PMemHeapInterface(size_t size, uint32_t flags = 0, char const * name = NULL);
-    virtual ~PMemHeapInterface();
-    virtual sp<MemoryHeapPmem> createClientHeap() = 0;
-};
-
-// ---------------------------------------------------------------------------
-
-class PMemHeap : public PMemHeapInterface
+class PMemHeap : public MemoryHeapBase
 {
 public:
                 PMemHeap(const char* const vram,
diff --git a/libs/ui/Android.mk b/libs/ui/Android.mk
index 71579c5..7b51300 100644
--- a/libs/ui/Android.mk
+++ b/libs/ui/Android.mk
@@ -2,7 +2,6 @@
 include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES:= \
-	BlitHardware.cpp \
 	Camera.cpp \
 	CameraParameters.cpp \
 	EGLDisplaySurface.cpp \
@@ -14,10 +13,12 @@
 	ICamera.cpp \
 	ICameraClient.cpp \
 	ICameraService.cpp \
+	IOverlay.cpp \
 	ISurfaceComposer.cpp \
 	ISurface.cpp \
 	ISurfaceFlingerClient.cpp \
 	LayerState.cpp \
+	Overlay.cpp \
 	PixelFormat.cpp \
 	Point.cpp \
 	Rect.cpp \
diff --git a/libs/ui/BlitHardware.cpp b/libs/ui/BlitHardware.cpp
deleted file mode 100644
index 90838b4..0000000
--- a/libs/ui/BlitHardware.cpp
+++ /dev/null
@@ -1,446 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "SurfaceFlinger"
-
-#include <stdint.h>
-#include <string.h>
-#include <unistd.h>
-#include <fcntl.h>
-
-#include <sys/ioctl.h>
-#include <sys/types.h>
-#include <sys/mman.h>
-
-#include <cutils/log.h>
-
-#include <utils/Errors.h>
-
-#if HAVE_ANDROID_OS
-#include <linux/fb.h>
-#include <linux/msm_mdp.h>
-#endif
-
-#include <ui/BlitHardware.h>
-
-/******************************************************************************/
-
-namespace android {
-class CopybitMSM7K : public copybit_t {
-public:
-    CopybitMSM7K();
-    ~CopybitMSM7K();
-    
-    status_t getStatus() const {
-        if (mFD<0) return mFD;
-        return NO_ERROR;
-    }
-
-    status_t setParameter(int name, int value);
-
-    status_t get(int name);
-
-    status_t blit( 
-            const copybit_image_t& dst,
-            const copybit_image_t& src,
-            copybit_region_t const* region);
-
-    status_t stretch( 
-            const copybit_image_t& dst,
-            const copybit_image_t& src, 
-            const copybit_rect_t& dst_rect,
-            const copybit_rect_t& src_rect,
-            copybit_region_t const* region);
-
-#if HAVE_ANDROID_OS
-private:
-    static int copybit_set_parameter(copybit_t* handle, int name, int value);
-    static int copybit_blit( copybit_t* handle, 
-            copybit_image_t const* dst, copybit_image_t const* src,
-            copybit_region_t const* region);
-    static int copybit_stretch(copybit_t* handle, 
-            copybit_image_t const* dst,  copybit_image_t const* src, 
-            copybit_rect_t const* dst_rect, copybit_rect_t const* src_rect,
-            copybit_region_t const* region);
-    static int copybit_get(copybit_t* handle, int name);
-
-    int getFormat(int format);
-    void setImage(mdp_img* img, const copybit_image_t& rhs);
-    void setRects(mdp_blit_req* req, const copybit_rect_t& dst,
-            const copybit_rect_t& src, const copybit_rect_t& scissor);
-    void setInfos(mdp_blit_req* req);
-    static void intersect(copybit_rect_t* out, 
-            const copybit_rect_t& lhs, const copybit_rect_t& rhs);
-    status_t msm_copybit(void const* list);
-#endif
-    int mFD;
-    uint8_t mAlpha;
-    uint8_t mFlags;
-};
-}; // namespace android
-
-using namespace android;
-
-/******************************************************************************/
-
-struct copybit_t* copybit_init()
-{
-    CopybitMSM7K* engine = new CopybitMSM7K();
-    if (engine->getStatus() != NO_ERROR) {
-        delete engine;
-        engine = 0;
-    }
-    return (struct copybit_t*)engine;
-        
-}
-
-int copybit_term(copybit_t* handle)
-{
-    delete static_cast<CopybitMSM7K*>(handle);
-    return NO_ERROR;
-}
-
-namespace android {
-/******************************************************************************/
-
-static inline
-int min(int a, int b) {
-    return (a<b) ? a : b;
-}
-
-static inline
-int max(int a, int b) {
-    return (a>b) ? a : b;
-}
-
-static inline
-void MULDIV(uint32_t& a, uint32_t& b, int mul, int div)
-{
-    if (mul != div) {
-        a = (mul * a) / div;
-        b = (mul * b) / div;
-    }
-}
-
-//-----------------------------------------------------------------------------
-
-#if HAVE_ANDROID_OS
-
-int CopybitMSM7K::copybit_set_parameter(copybit_t* handle, int name, int value)
-{
-    return static_cast<CopybitMSM7K*>(handle)->setParameter(name, value);
-}
-
-int CopybitMSM7K::copybit_get(copybit_t* handle, int name)
-{
-    return static_cast<CopybitMSM7K*>(handle)->get(name);
-}
-
-int CopybitMSM7K::copybit_blit(
-        copybit_t* handle, 
-        copybit_image_t const* dst, 
-        copybit_image_t const* src,
-        struct copybit_region_t const* region)
-{
-    return static_cast<CopybitMSM7K*>(handle)->blit(*dst, *src, region);
-}
-
-int CopybitMSM7K::copybit_stretch(
-        copybit_t* handle, 
-        copybit_image_t const* dst, 
-        copybit_image_t const* src, 
-        copybit_rect_t const* dst_rect,
-        copybit_rect_t const* src_rect,
-        struct copybit_region_t const* region)
-{
-    return static_cast<CopybitMSM7K*>(handle)->stretch(
-            *dst, *src, *dst_rect, *src_rect, region);
-}
-
-//-----------------------------------------------------------------------------
-
-CopybitMSM7K::CopybitMSM7K()
-    : mFD(-1), mAlpha(MDP_ALPHA_NOP), mFlags(0)
-{
-    int fd = open("/dev/graphics/fb0", O_RDWR, 0);
-    if (fd > 0) {
-        struct fb_fix_screeninfo finfo;
-        if (ioctl(fd, FBIOGET_FSCREENINFO, &finfo) == 0) {
-            if (!strcmp(finfo.id, "msmfb")) {
-                mFD = fd;
-                copybit_t::set_parameter = copybit_set_parameter;
-                copybit_t::get = copybit_get;
-                copybit_t::blit = copybit_blit;
-                copybit_t::stretch = copybit_stretch;
-            }
-        }
-    }
-    if (fd<0 || mFD<0) {
-        if (fd>0) { close(fd); }
-        mFD = -errno;
-    }
-}
-
-CopybitMSM7K::~CopybitMSM7K()
-{
-    if (mFD > 0){
-        close(mFD);
-    }
-}
-
-status_t CopybitMSM7K::setParameter(int name, int value)
-{
-    switch(name) {
-    case COPYBIT_ROTATION_DEG:
-        switch (value) {
-        case 0:
-            mFlags &= ~0x7;
-            break;
-        case 90:
-            mFlags &= ~0x7;
-            mFlags |= MDP_ROT_90;
-            break;
-        case 180:
-            mFlags &= ~0x7;
-            mFlags |= MDP_ROT_180;
-            break;
-        case 270:
-            mFlags &= ~0x7;
-            mFlags |= MDP_ROT_270;
-            break;
-        default:
-            return BAD_VALUE;
-        }
-        break;
-    case COPYBIT_PLANE_ALPHA:
-        if (value < 0)      value = 0;
-        if (value >= 256)   value = 255;
-        mAlpha = value;
-        break;
-    case COPYBIT_DITHER:
-        if (value == COPYBIT_ENABLE) {
-            mFlags |= MDP_DITHER;
-        } else if (value == COPYBIT_DISABLE) {
-            mFlags &= ~MDP_DITHER;
-        }
-        break;
-    case COPYBIT_TRANSFORM:
-        mFlags &= ~0x7;
-        mFlags |= value & 0x7;
-        break;
-    default:
-        return BAD_VALUE;
-    }
-    return NO_ERROR;
-}
-
-status_t CopybitMSM7K::get(int name)
-{
-    switch(name) {
-    case COPYBIT_MINIFICATION_LIMIT:
-        return 4;
-    case COPYBIT_MAGNIFICATION_LIMIT:
-        return 4;
-    case COPYBIT_SCALING_FRAC_BITS:
-        return 32;
-    case COPYBIT_ROTATION_STEP_DEG:
-        return 90;
-    }
-    return BAD_VALUE;
-}
-
-status_t CopybitMSM7K::blit( 
-        const copybit_image_t& dst,
-        const copybit_image_t& src,
-        copybit_region_t const* region)
-{
-    
-    copybit_rect_t dr = { 0, 0, dst.w, dst.h };
-    copybit_rect_t sr = { 0, 0, src.w, src.h };
-    return CopybitMSM7K::stretch(dst, src, dr, sr, region);
-}
-
-status_t CopybitMSM7K::stretch( 
-        const copybit_image_t& dst,
-        const copybit_image_t& src, 
-        const copybit_rect_t& dst_rect,
-        const copybit_rect_t& src_rect,
-        copybit_region_t const* region)
-{
-    struct {
-        uint32_t count;
-        struct mdp_blit_req req[12];
-    } list;
-    
-    if (mAlpha<255) {
-        switch (src.format) {
-            // we dont' support plane alpha with RGBA formats
-            case COPYBIT_RGBA_8888:
-            case COPYBIT_RGBA_5551:
-            case COPYBIT_RGBA_4444:
-                return INVALID_OPERATION;
-        }
-    }
-        
-    const uint32_t maxCount = sizeof(list.req)/sizeof(list.req[0]);
-    const copybit_rect_t bounds = { 0, 0, dst.w, dst.h };
-    copybit_rect_t clip;
-    list.count = 0;
-    int err = 0;
-    while (!err && region->next(region, &clip)) {
-        intersect(&clip, bounds, clip);
-        setInfos(&list.req[list.count]);
-        setImage(&list.req[list.count].dst, dst);
-        setImage(&list.req[list.count].src, src);
-        setRects(&list.req[list.count], dst_rect, src_rect, clip);
-        if (++list.count == maxCount) {
-            err = msm_copybit(&list);
-            list.count = 0;
-        }
-    }
-    if (!err && list.count) {
-        err = msm_copybit(&list);
-    }
-    return err;
-}
-
-status_t CopybitMSM7K::msm_copybit(void const* list)
-{
-    int err = ioctl(mFD, MSMFB_BLIT, static_cast<mdp_blit_req_list const*>(list));
-    LOGE_IF(err<0, "copyBits failed (%s)", strerror(errno));
-    if (err == 0)
-        return NO_ERROR;
-    return -errno;
-}
-
-int CopybitMSM7K::getFormat(int format)
-{
-    switch (format) {
-    case COPYBIT_RGBA_8888:     return MDP_RGBA_8888;
-    case COPYBIT_RGB_565:       return MDP_RGB_565;
-    case COPYBIT_YCbCr_422_SP:  return MDP_Y_CBCR_H2V1;
-    case COPYBIT_YCbCr_420_SP:  return MDP_Y_CBCR_H2V2;
-    }
-    return -1;
-}
-
-void CopybitMSM7K::setInfos(mdp_blit_req* req)
-{
-    req->alpha = mAlpha;
-    req->transp_mask = MDP_TRANSP_NOP;
-    req->flags = mFlags;
-}
-
-void CopybitMSM7K::setImage(mdp_img* img, const copybit_image_t& rhs)
-{
-    img->width      = rhs.w;
-    img->height     = rhs.h;
-    img->format     = getFormat(rhs.format);
-    img->offset     = rhs.offset;
-    img->memory_id  = rhs.fd;
-}
-    
-void CopybitMSM7K::setRects(mdp_blit_req* e, 
-        const copybit_rect_t& dst, const copybit_rect_t& src,
-        const copybit_rect_t& scissor)
-{
-    copybit_rect_t clip;
-    intersect(&clip, scissor, dst);
-
-    e->dst_rect.x  = clip.l;
-    e->dst_rect.y  = clip.t;
-    e->dst_rect.w  = clip.r - clip.l;
-    e->dst_rect.h  = clip.b - clip.t;
-
-    uint32_t W, H;
-    if (mFlags & COPYBIT_TRANSFORM_ROT_90) {
-        e->src_rect.x  = (clip.t - dst.t) + src.t;
-        e->src_rect.y  = (dst.r - clip.r) + src.l;
-        e->src_rect.w  = (clip.b - clip.t);
-        e->src_rect.h  = (clip.r - clip.l);
-        W = dst.b - dst.t;
-        H = dst.r - dst.l;
-    } else {
-        e->src_rect.x  = (clip.l - dst.l) + src.l;
-        e->src_rect.y  = (clip.t - dst.t) + src.t;
-        e->src_rect.w  = (clip.r - clip.l);
-        e->src_rect.h  = (clip.b - clip.t);
-        W = dst.r - dst.l;
-        H = dst.b - dst.t;
-    }
-    MULDIV(e->src_rect.x, e->src_rect.w, src.r - src.l, W);
-    MULDIV(e->src_rect.y, e->src_rect.h, src.b - src.t, H);
-    if (mFlags & COPYBIT_TRANSFORM_FLIP_V) {
-        e->src_rect.y = e->src.height - (e->src_rect.y + e->src_rect.h);
-    }
-    if (mFlags & COPYBIT_TRANSFORM_FLIP_H) {
-        e->src_rect.x = e->src.width  - (e->src_rect.x + e->src_rect.w);
-    }
-}
-
-void CopybitMSM7K::intersect(copybit_rect_t* out, 
-        const copybit_rect_t& lhs, const copybit_rect_t& rhs)
-{
-    out->l = max(lhs.l, rhs.l);
-    out->t = max(lhs.t, rhs.t);
-    out->r = min(lhs.r, rhs.r);
-    out->b = min(lhs.b, rhs.b);
-}
-
-/******************************************************************************/
-#else // HAVE_ANDROID_OS
-
-CopybitMSM7K::CopybitMSM7K()
-    : mFD(-1)
-{
-}
-
-CopybitMSM7K::~CopybitMSM7K()
-{
-}
-
-status_t CopybitMSM7K::setParameter(int name, int value)
-{
-    return NO_INIT;
-}
-
-status_t CopybitMSM7K::get(int name)
-{
-    return BAD_VALUE;
-}
-
-status_t CopybitMSM7K::blit( 
-        const copybit_image_t& dst,
-        const copybit_image_t& src,
-        copybit_region_t const* region)
-{
-    return NO_INIT;
-}
-
-status_t CopybitMSM7K::stretch( 
-        const copybit_image_t& dst,
-        const copybit_image_t& src, 
-        const copybit_rect_t& dst_rect,
-        const copybit_rect_t& src_rect,
-        copybit_region_t const* region)
-{
-    return NO_INIT;
-}
-
-#endif // HAVE_ANDROID_OS
-
-/******************************************************************************/
-}; // namespace android
diff --git a/libs/ui/Camera.cpp b/libs/ui/Camera.cpp
index 1528e6e..9527009 100644
--- a/libs/ui/Camera.cpp
+++ b/libs/ui/Camera.cpp
@@ -1,28 +1,28 @@
 /*
 **
-** Copyright 2008, The Android Open Source Project
+** Copyright (C) 2008, The Android Open Source Project
+** Copyright (C) 2008 HTC Inc.
 **
-** 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 
+** 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 
+**     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 
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
 ** limitations under the License.
 */
 
+//#define LOG_NDEBUG 0
 #define LOG_TAG "Camera"
 #include <utils/Log.h>
-
 #include <utils/IServiceManager.h>
 #include <utils/threads.h>
 #include <utils/IMemory.h>
 #include <ui/Surface.h>
-
 #include <ui/Camera.h>
 #include <ui/ICameraService.h>
 
@@ -60,20 +60,36 @@
 // ---------------------------------------------------------------------------
 
 Camera::Camera()
-      : mStatus(UNKNOWN_ERROR),
-        mShutterCallback(0),
-        mShutterCallbackCookie(0),
-        mRawCallback(0),
-        mRawCallbackCookie(0),
-        mJpegCallback(0),
-        mJpegCallbackCookie(0),
-        mFrameCallback(0),
-        mFrameCallbackCookie(0),
-        mErrorCallback(0),
-        mErrorCallbackCookie(0),
-        mAutoFocusCallback(0),
-        mAutoFocusCallbackCookie(0)
 {
+    init();
+}
+
+Camera::Camera(const sp<ICamera>& camera)
+{
+    init();
+    // connect this client to existing camera remote
+    if (camera->connect(this) == NO_ERROR) {
+        mStatus = NO_ERROR;
+        mCamera = camera;
+        camera->asBinder()->linkToDeath(this);
+    }
+}
+
+void Camera::init()
+{
+    mStatus = UNKNOWN_ERROR;
+    mShutterCallback = 0;
+    mShutterCallbackCookie = 0;
+    mRawCallback = 0;
+    mRawCallbackCookie = 0;
+    mJpegCallback = 0;
+    mJpegCallbackCookie = 0;
+    mFrameCallback = 0;
+    mFrameCallbackCookie = 0;
+    mErrorCallback = 0;
+    mErrorCallbackCookie = 0;
+    mAutoFocusCallback = 0;
+    mAutoFocusCallbackCookie = 0;
 }
 
 Camera::~Camera()
@@ -83,6 +99,7 @@
 
 sp<Camera> Camera::connect()
 {
+    LOGV("connect");
     sp<Camera> c = new Camera();
     const sp<ICameraService>& cs = getCameraService();
     if (cs != 0) {
@@ -97,6 +114,7 @@
 
 void Camera::disconnect()
 {
+    LOGV("disconnect");
     if (mCamera != 0) {
         mErrorCallback = 0;
         mCamera->disconnect();
@@ -104,9 +122,24 @@
     }
 }
 
+status_t Camera::reconnect()
+{
+    LOGV("reconnect");
+    if (mCamera != 0) {
+        return mCamera->connect(this);
+    }
+    return NO_INIT;
+}
+
+sp<ICamera> Camera::remote()
+{
+    return mCamera;
+}
+
 // pass the buffered ISurface to the camera service
 status_t Camera::setPreviewDisplay(const sp<Surface>& surface)
 {
+    LOGV("setPreviewDisplay");
     if (surface == 0) {
         LOGE("app passed NULL surface");
         return NO_INIT;
@@ -114,81 +147,105 @@
     return mCamera->setPreviewDisplay(surface->getISurface());
 }
 
+status_t Camera::setPreviewDisplay(const sp<ISurface>& surface)
+{
+    LOGV("setPreviewDisplay");
+    if (surface == 0) {
+        LOGE("app passed NULL surface");
+        return NO_INIT;
+    }
+    return mCamera->setPreviewDisplay(surface);
+}
+
+
 // start preview mode, must call setPreviewDisplay first
 status_t Camera::startPreview()
 {
+    LOGV("startPreview");
     return mCamera->startPreview();
 }
 
 // stop preview mode
 void Camera::stopPreview()
 {
+    LOGV("stopPreview");
     mCamera->stopPreview();
 }
 
 status_t Camera::autoFocus()
 {
+    LOGV("autoFocus");
     return mCamera->autoFocus();
 }
 
 // take a picture
 status_t Camera::takePicture()
 {
+    LOGV("takePicture");
     return mCamera->takePicture();
 }
 
 // set preview/capture parameters - key/value pairs
 status_t Camera::setParameters(const String8& params)
 {
+    LOGV("setParameters");
     return mCamera->setParameters(params);
 }
 
 // get preview/capture parameters - key/value pairs
 String8 Camera::getParameters() const
 {
+    LOGV("getParameters");
     String8 params = mCamera->getParameters();
     return params;
 }
 
 void Camera::setAutoFocusCallback(autofocus_callback cb, void *cookie)
 {
+    LOGV("setAutoFocusCallback");
     mAutoFocusCallback = cb;
     mAutoFocusCallbackCookie = cookie;
 }
 
 void Camera::setShutterCallback(shutter_callback cb, void *cookie)
 {
+    LOGV("setShutterCallback");
     mShutterCallback = cb;
     mShutterCallbackCookie = cookie;
 }
 
 void Camera::setRawCallback(frame_callback cb, void *cookie)
 {
+    LOGV("setRawCallback");
     mRawCallback = cb;
     mRawCallbackCookie = cookie;
 }
 
 void Camera::setJpegCallback(frame_callback cb, void *cookie)
 {
+    LOGV("setJpegCallback");
     mJpegCallback = cb;
     mJpegCallbackCookie = cookie;
 }
 
-void Camera::setFrameCallback(frame_callback cb, void *cookie)
+void Camera::setFrameCallback(frame_callback cb, void *cookie, int frame_callback_flag)
 {
+    LOGV("setFrameCallback");
     mFrameCallback = cb;
     mFrameCallbackCookie = cookie;
-    mCamera->setHasFrameCallback(cb != NULL);
+    mCamera->setFrameCallbackFlag(frame_callback_flag);
 }
 
 void Camera::setErrorCallback(error_callback cb, void *cookie)
 {
+    LOGV("setErrorCallback");
     mErrorCallback = cb;
     mErrorCallbackCookie = cookie;
 }
 
 void Camera::autoFocusCallback(bool focused)
 {
+    LOGV("autoFocusCallback");
     if (mAutoFocusCallback) {
         mAutoFocusCallback(focused, mAutoFocusCallbackCookie);
     }
@@ -196,6 +253,7 @@
 
 void Camera::shutterCallback()
 {
+    LOGV("shutterCallback");
     if (mShutterCallback) {
         mShutterCallback(mShutterCallbackCookie);
     }
@@ -203,6 +261,7 @@
 
 void Camera::rawCallback(const sp<IMemory>& picture)
 {
+    LOGV("rawCallback");
     if (mRawCallback) {
         mRawCallback(picture, mRawCallbackCookie);
     }
@@ -211,6 +270,7 @@
 // callback from camera service when image is ready
 void Camera::jpegCallback(const sp<IMemory>& picture)
 {
+    LOGV("jpegCallback");
     if (mJpegCallback) {
         mJpegCallback(picture, mJpegCallbackCookie);
     }
@@ -219,6 +279,7 @@
 // callback from camera service when video frame is ready
 void Camera::frameCallback(const sp<IMemory>& frame)
 {
+    LOGV("frameCallback");
     if (mFrameCallback) {
         mFrameCallback(frame, mFrameCallbackCookie);
     }
@@ -227,19 +288,21 @@
 // callback from camera service when an error occurs in preview or takePicture
 void Camera::errorCallback(status_t error)
 {
+    LOGV("errorCallback");
     if (mErrorCallback) {
         mErrorCallback(error, mErrorCallbackCookie);
     }
 }
 
-void Camera::binderDied(const wp<IBinder>& who) {    
+void Camera::binderDied(const wp<IBinder>& who) {
     LOGW("ICamera died");
     if (mErrorCallback) {
         mErrorCallback(DEAD_OBJECT, mErrorCallbackCookie);
     }
 }
 
-void Camera::DeathNotifier::binderDied(const wp<IBinder>& who) {    
+void Camera::DeathNotifier::binderDied(const wp<IBinder>& who) {
+    LOGV("binderDied");
     Mutex::Autolock _l(Camera::mLock);
     Camera::mCameraService.clear();
     LOGW("Camera server died!");
diff --git a/libs/ui/EGLDisplaySurface.cpp b/libs/ui/EGLDisplaySurface.cpp
index ea245f5..44258a8 100644
--- a/libs/ui/EGLDisplaySurface.cpp
+++ b/libs/ui/EGLDisplaySurface.cpp
@@ -28,11 +28,15 @@
 
 #include <cutils/log.h>
 #include <cutils/atomic.h>
+#include <cutils/properties.h>
+
+#include <hardware/copybit.h>
 
 #include <ui/SurfaceComposerClient.h>
 #include <ui/DisplayInfo.h>
 #include <ui/Rect.h>
 #include <ui/Region.h>
+#include <ui/EGLDisplaySurface.h>
 
 #if HAVE_ANDROID_OS
 #include <linux/msm_mdp.h>
@@ -42,7 +46,6 @@
 
 #include <pixelflinger/format.h>
 
-#include <ui/EGLDisplaySurface.h>
 
 // ----------------------------------------------------------------------------
 
@@ -78,7 +81,12 @@
     mBlitEngine = 0;
     egl_native_window_t::fd = mapFrameBuffer();
     if (egl_native_window_t::fd >= 0) {
-        mBlitEngine = copybit_init();
+        
+        hw_module_t const* module;
+        if (hw_get_module(COPYBIT_HARDWARE_MODULE_ID, &module) == 0) {
+            copybit_open(module, &mBlitEngine);
+        }
+        
         const float in2mm = 25.4f;
         float refreshRate = 1000000000000000LLU / (
                 float( mInfo.upper_margin + mInfo.lower_margin + mInfo.yres )
@@ -108,7 +116,7 @@
 EGLDisplaySurface::~EGLDisplaySurface()
 {
     magic = 0;
-    copybit_term(mBlitEngine);
+    copybit_close(mBlitEngine);
     mBlitEngine = 0;
     close(egl_native_window_t::fd);
     munmap(mFb[0].data, mSize);
@@ -147,9 +155,6 @@
 
 uint32_t EGLDisplaySurface::swapBuffers()
 {
-    if (!(mFlags & PAGE_FLIP))
-        return 0;
-
 #define SHOW_FPS 0
 #if SHOW_FPS
     nsecs_t now = systemTime();
@@ -171,6 +176,11 @@
         }
     }
 #endif
+    /* If we can't do the page_flip, just copy the back buffer to the front */
+    if (!(mFlags & PAGE_FLIP)) {
+        memcpy(mFb[0].data, mFb[1].data, mInfo.xres*mInfo.yres*2);
+        return 0;
+    }
 
     // do the actual flip
     mIndex = 1 - mIndex;
@@ -192,7 +202,7 @@
      * with msm7k.
      */
     if (egl_native_window_t::memory_type == NATIVE_MEMORY_TYPE_GPU && oem[0] && mBlitEngine) {
-        copybit_t *copybit = mBlitEngine;
+        copybit_device_t *copybit = mBlitEngine;
         copybit_rect_t sdrect = { 0, 0,
                 egl_native_window_t::width, egl_native_window_t::height };
         copybit_image_t dst = {
@@ -273,6 +283,12 @@
     } else
 #endif
     {
+        /* no extra copy needed since we copied back to front instead of
+         * flipping */
+        if (!(mFlags & PAGE_FLIP)) {
+            return;
+        }
+
         Region::iterator iterator(copyback);
         if (iterator) {
             Rect r;
@@ -373,12 +389,11 @@
         // bleagh, bad info from the driver
         refreshRate = 60*1000;  // 60 Hz
     }
-
     if (int(info.width) <= 0 || int(info.height) <= 0) {
         // the driver doesn't return that information
         // default to 160 dpi
-        info.width  = 51;
-        info.height = 38;
+        info.width  = ((info.xres * 25.4f)/160.0f + 0.5f);
+        info.height = ((info.yres * 25.4f)/160.0f + 0.5f);
     }
 
     float xdpi = (info.xres * 25.4f) / info.width;
diff --git a/libs/ui/EGLNativeWindowSurface.cpp b/libs/ui/EGLNativeWindowSurface.cpp
index 0b6afc0..d55fb70 100644
--- a/libs/ui/EGLNativeWindowSurface.cpp
+++ b/libs/ui/EGLNativeWindowSurface.cpp
@@ -163,7 +163,12 @@
         egl_native_window_t::format = info.format;
         egl_native_window_t::base   = intptr_t(info.base);
         egl_native_window_t::offset = intptr_t(info.bits) - intptr_t(info.base);
-        egl_native_window_t::memory_type = mSurface->getMemoryType();
+        // FIXME: egl_native_window_t::memory_type used to be set from
+        // mSurface, but we wanted to break this dependency. We set it to
+        // GPU because the software rendered doesn't care, but the h/w
+        // accelerator needs it. Eventually, this value should go away
+        // completely, since memory will be managed by OpenGL.
+        egl_native_window_t::memory_type = NATIVE_MEMORY_TYPE_GPU; 
         egl_native_window_t::fd = 0;
     }
 }
diff --git a/libs/ui/EventHub.cpp b/libs/ui/EventHub.cpp
index f0c77ba..abe7407 100644
--- a/libs/ui/EventHub.cpp
+++ b/libs/ui/EventHub.cpp
@@ -315,9 +315,8 @@
         }
 
         //printf("poll %d, returned %d\n", mFDCount, pollres);
-        if(mFDs[0].revents & POLLIN) {
-            read_notify(mFDs[0].fd);
-        }
+
+        // mFDs[0] is used for inotify, so process regular events starting at mFDs[1]
         for(i = 1; i < mFDCount; i++) {
             if(mFDs[i].revents) {
                 LOGV("revents for %d = 0x%08x", i, mFDs[i].revents);
@@ -357,6 +356,12 @@
                 }
             }
         }
+        
+        // read_notify() will modify mFDs and mFDCount, so this must be done after
+        // processing all other events.
+        if(mFDs[0].revents & POLLIN) {
+            read_notify(mFDs[0].fd);
+        }
     }
 }
 
@@ -607,7 +612,7 @@
         sprintf(propName, "hw.keyboards.%u.devname", publicID);
         property_set(propName, devname);
 
-        LOGI("New keyboard: publicID=%d device->id=%d devname='%s propName='%s' keylayout='%s'\n",
+        LOGI("New keyboard: publicID=%d device->id=%d devname='%s' propName='%s' keylayout='%s'\n",
                 publicID, device->id, devname, propName, keylayoutFilename);
     }
 
diff --git a/libs/ui/ICamera.cpp b/libs/ui/ICamera.cpp
index 420bb49..6a2dc6b 100644
--- a/libs/ui/ICamera.cpp
+++ b/libs/ui/ICamera.cpp
@@ -2,41 +2,40 @@
 **
 ** Copyright 2008, 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 
+** 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 
+**     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 
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
 ** limitations under the License.
 */
 
+//#define LOG_NDEBUG 0
+#define LOG_TAG "ICamera"
+#include <utils/Log.h>
 #include <stdint.h>
 #include <sys/types.h>
-
 #include <utils/Parcel.h>
-
 #include <ui/ICamera.h>
 
-#define LOG_TAG "@@@@@@@@@@@ CAMERA @@@@@@@@@@@"
-#include <utils/Log.h>
-
 namespace android {
 
 enum {
     DISCONNECT = IBinder::FIRST_CALL_TRANSACTION,
     SET_PREVIEW_DISPLAY,
-    SET_HAS_FRAME_CALLBACK,
+    SET_FRAME_CALLBACK_FLAG,
     START_PREVIEW,
     STOP_PREVIEW,
     AUTO_FOCUS,
     TAKE_PICTURE,
     SET_PARAMETERS,
-    GET_PARAMETERS
+    GET_PARAMETERS,
+    CONNECT
 };
 
 class BpCamera: public BpInterface<ICamera>
@@ -50,6 +49,7 @@
     // disconnect from camera service
     void disconnect()
     {
+        LOGV("disconnect");
         Parcel data, reply;
         data.writeInterfaceToken(ICamera::getInterfaceDescriptor());
         remote()->transact(DISCONNECT, data, &reply);
@@ -58,25 +58,29 @@
     // pass the buffered ISurface to the camera service
     status_t setPreviewDisplay(const sp<ISurface>& surface)
     {
+        LOGV("setPreviewDisplay");
         Parcel data, reply;
         data.writeInterfaceToken(ICamera::getInterfaceDescriptor());
         data.writeStrongBinder(surface->asBinder());
         remote()->transact(SET_PREVIEW_DISPLAY, data, &reply);
         return reply.readInt32();
     }
-    
-    // tell the service whether to callback with each preview frame
-    void setHasFrameCallback(bool installed)
+
+    // set the frame callback flag to affect how the received frames from
+    // preview are handled.
+    void setFrameCallbackFlag(int frame_callback_flag)
     {
+        LOGV("setFrameCallbackFlag(%d)", frame_callback_flag);
         Parcel data, reply;
         data.writeInterfaceToken(ICamera::getInterfaceDescriptor());
-        data.writeInt32((int32_t)installed);
-        remote()->transact(SET_HAS_FRAME_CALLBACK, data, &reply);
+        data.writeInt32(frame_callback_flag);
+        remote()->transact(SET_FRAME_CALLBACK_FLAG, data, &reply);
     }
 
     // start preview mode, must call setPreviewDisplay first
     status_t startPreview()
     {
+        LOGV("startPreview");
         Parcel data, reply;
         data.writeInterfaceToken(ICamera::getInterfaceDescriptor());
         remote()->transact(START_PREVIEW, data, &reply);
@@ -86,6 +90,7 @@
     // stop preview mode
     void stopPreview()
     {
+        LOGV("stopPreview");
         Parcel data, reply;
         data.writeInterfaceToken(ICamera::getInterfaceDescriptor());
         remote()->transact(STOP_PREVIEW, data, &reply);
@@ -94,6 +99,7 @@
     // auto focus
     status_t autoFocus()
     {
+        LOGV("autoFocus");
         Parcel data, reply;
         data.writeInterfaceToken(ICamera::getInterfaceDescriptor());
         remote()->transact(AUTO_FOCUS, data, &reply);
@@ -104,6 +110,7 @@
     // take a picture - returns an IMemory (ref-counted mmap)
     status_t takePicture()
     {
+        LOGV("takePicture");
         Parcel data, reply;
         data.writeInterfaceToken(ICamera::getInterfaceDescriptor());
         remote()->transact(TAKE_PICTURE, data, &reply);
@@ -114,6 +121,7 @@
     // set preview/capture parameters - key/value pairs
     status_t setParameters(const String8& params)
     {
+        LOGV("setParameters");
         Parcel data, reply;
         data.writeInterfaceToken(ICamera::getInterfaceDescriptor());
         data.writeString8(params);
@@ -124,11 +132,20 @@
     // get preview/capture parameters - key/value pairs
     String8 getParameters() const
     {
+        LOGV("getParameters");
         Parcel data, reply;
         data.writeInterfaceToken(ICamera::getInterfaceDescriptor());
         remote()->transact(GET_PARAMETERS, data, &reply);
         return reply.readString8();
     }
+    virtual status_t connect(const sp<ICameraClient>& cameraClient)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(ICamera::getInterfaceDescriptor());
+        data.writeStrongBinder(cameraClient->asBinder());
+        remote()->transact(CONNECT, data, &reply);
+        return reply.readInt32();
+    }
 };
 
 IMPLEMENT_META_INTERFACE(Camera, "android.hardware.ICamera");
@@ -146,53 +163,68 @@
 {
     switch(code) {
         case DISCONNECT: {
+            LOGV("DISCONNECT");
             CHECK_INTERFACE(ICamera, data, reply);
             disconnect();
             return NO_ERROR;
         } break;
         case SET_PREVIEW_DISPLAY: {
+            LOGV("SET_PREVIEW_DISPLAY");
             CHECK_INTERFACE(ICamera, data, reply);
             sp<ISurface> surface = interface_cast<ISurface>(data.readStrongBinder());
             reply->writeInt32(setPreviewDisplay(surface));
             return NO_ERROR;
         } break;
-        case SET_HAS_FRAME_CALLBACK: {
+        case SET_FRAME_CALLBACK_FLAG: {
+            LOGV("SET_FRAME_CALLBACK_TYPE");
             CHECK_INTERFACE(ICamera, data, reply);
-            bool installed = (bool)data.readInt32();
-            setHasFrameCallback(installed);
+            int frame_callback_flag = data.readInt32();
+            setFrameCallbackFlag(frame_callback_flag);
             return NO_ERROR;
         } break;
         case START_PREVIEW: {
+            LOGV("START_PREVIEW");
             CHECK_INTERFACE(ICamera, data, reply);
             reply->writeInt32(startPreview());
             return NO_ERROR;
         } break;
         case STOP_PREVIEW: {
+            LOGV("STOP_PREVIEW");
             CHECK_INTERFACE(ICamera, data, reply);
             stopPreview();
             return NO_ERROR;
         } break;
         case AUTO_FOCUS: {
+            LOGV("AUTO_FOCUS");
             CHECK_INTERFACE(ICamera, data, reply);
             reply->writeInt32(autoFocus());
             return NO_ERROR;
         } break;
         case TAKE_PICTURE: {
+            LOGV("TAKE_PICTURE");
             CHECK_INTERFACE(ICamera, data, reply);
             reply->writeInt32(takePicture());
             return NO_ERROR;
         } break;
         case SET_PARAMETERS: {
+            LOGV("SET_PARAMETERS");
             CHECK_INTERFACE(ICamera, data, reply);
-             String8 params(data.readString8());
-             reply->writeInt32(setParameters(params));
+            String8 params(data.readString8());
+            reply->writeInt32(setParameters(params));
             return NO_ERROR;
          } break;
         case GET_PARAMETERS: {
+            LOGV("GET_PARAMETERS");
             CHECK_INTERFACE(ICamera, data, reply);
              reply->writeString8(getParameters());
             return NO_ERROR;
          } break;
+        case CONNECT: {
+            CHECK_INTERFACE(ICamera, data, reply);
+            sp<ICameraClient> cameraClient = interface_cast<ICameraClient>(data.readStrongBinder());
+            reply->writeInt32(connect(cameraClient));
+            return NO_ERROR;
+        } break;
         default:
             return BBinder::onTransact(code, data, reply, flags);
     }
diff --git a/libs/ui/ICameraClient.cpp b/libs/ui/ICameraClient.cpp
index 3737034..c5d6d52 100644
--- a/libs/ui/ICameraClient.cpp
+++ b/libs/ui/ICameraClient.cpp
@@ -15,9 +15,11 @@
 ** limitations under the License.
 */
 
+//#define LOG_NDEBUG 0
+#define LOG_TAG "ICameraClient"
+#include <utils/Log.h>
 #include <stdint.h>
 #include <sys/types.h>
-
 #include <ui/ICameraClient.h>
 
 namespace android {
@@ -42,6 +44,7 @@
     // callback to let the app know the shutter has closed, ideal for playing the shutter sound
     void shutterCallback()
     {
+        LOGV("shutterCallback");
         Parcel data, reply;
         data.writeInterfaceToken(ICameraClient::getInterfaceDescriptor());
         remote()->transact(SHUTTER_CALLBACK, data, &reply, IBinder::FLAG_ONEWAY);
@@ -50,6 +53,7 @@
     // callback from camera service to app with picture data
     void rawCallback(const sp<IMemory>& picture)
     {
+        LOGV("rawCallback");
         Parcel data, reply;
         data.writeInterfaceToken(ICameraClient::getInterfaceDescriptor());
         data.writeStrongBinder(picture->asBinder());
@@ -59,6 +63,7 @@
     // callback from camera service to app with picture data
     void jpegCallback(const sp<IMemory>& picture)
     {
+        LOGV("jpegCallback");
         Parcel data, reply;
         data.writeInterfaceToken(ICameraClient::getInterfaceDescriptor());
         data.writeStrongBinder(picture->asBinder());
@@ -68,6 +73,7 @@
     // callback from camera service to app with video frame data
     void frameCallback(const sp<IMemory>& frame)
     {
+        LOGV("frameCallback");
         Parcel data, reply;
         data.writeInterfaceToken(ICameraClient::getInterfaceDescriptor());
         data.writeStrongBinder(frame->asBinder());
@@ -77,6 +83,7 @@
     // callback from camera service to app to report error
     void errorCallback(status_t error)
     {
+        LOGV("errorCallback");
         Parcel data, reply;
         data.writeInterfaceToken(ICameraClient::getInterfaceDescriptor());
         data.writeInt32(error);
@@ -86,6 +93,7 @@
     // callback from camera service to app to report autofocus completion
     void autoFocusCallback(bool focused)
     {
+        LOGV("autoFocusCallback");
         Parcel data, reply;
         data.writeInterfaceToken(ICameraClient::getInterfaceDescriptor());
         data.writeInt32(focused);
@@ -108,35 +116,41 @@
 {
     switch(code) {
         case SHUTTER_CALLBACK: {
+            LOGV("SHUTTER_CALLBACK");
             CHECK_INTERFACE(ICameraClient, data, reply);
             shutterCallback();
             return NO_ERROR;
         } break;
         case RAW_CALLBACK: {
+            LOGV("RAW_CALLBACK");
             CHECK_INTERFACE(ICameraClient, data, reply);
             sp<IMemory> picture = interface_cast<IMemory>(data.readStrongBinder());
             rawCallback(picture);
             return NO_ERROR;
         } break;
         case JPEG_CALLBACK: {
+            LOGV("JPEG_CALLBACK");
             CHECK_INTERFACE(ICameraClient, data, reply);
             sp<IMemory> picture = interface_cast<IMemory>(data.readStrongBinder());
             jpegCallback(picture);
             return NO_ERROR;
         } break;
         case FRAME_CALLBACK: {
+            LOGV("FRAME_CALLBACK");
             CHECK_INTERFACE(ICameraClient, data, reply);
             sp<IMemory> frame = interface_cast<IMemory>(data.readStrongBinder());
             frameCallback(frame);
             return NO_ERROR;
         } break;
         case ERROR_CALLBACK: {
+            LOGV("ERROR_CALLBACK");
             CHECK_INTERFACE(ICameraClient, data, reply);
             status_t error = data.readInt32();
             errorCallback(error);
             return NO_ERROR;
         } break;
         case AUTOFOCUS_CALLBACK: {
+            LOGV("AUTOFOCUS_CALLBACK");
             CHECK_INTERFACE(ICameraClient, data, reply);
             bool focused = (bool)data.readInt32();
             autoFocusCallback(focused);
diff --git a/libs/ui/IOverlay.cpp b/libs/ui/IOverlay.cpp
new file mode 100644
index 0000000..59d1ea0
--- /dev/null
+++ b/libs/ui/IOverlay.cpp
@@ -0,0 +1,87 @@
+/*
+ * 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.
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Parcel.h>
+#include <utils/IInterface.h>
+
+#include <ui/IOverlay.h>
+
+namespace android {
+
+enum {
+    DESTROY = IBinder::FIRST_CALL_TRANSACTION, // one-way transaction
+    SWAP_BUFFERS,
+};
+
+class BpOverlay : public BpInterface<IOverlay>
+{
+public:
+    BpOverlay(const sp<IBinder>& impl)
+        : BpInterface<IOverlay>(impl)
+    {
+    }
+
+    virtual void destroy()
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IOverlay::getInterfaceDescriptor());
+        remote()->transact(DESTROY, data, &reply, IBinder::FLAG_ONEWAY);
+    }
+
+    virtual ssize_t swapBuffers()
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IOverlay::getInterfaceDescriptor());
+        remote()->transact(SWAP_BUFFERS, data, &reply);
+        return reply.readInt32();
+    }
+};
+
+IMPLEMENT_META_INTERFACE(Overlay, "android.ui.IOverlay");
+
+// ----------------------------------------------------------------------
+
+#define CHECK_INTERFACE(interface, data, reply) \
+        do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
+            LOGW("Call incorrectly routed to " #interface); \
+            return PERMISSION_DENIED; \
+        } } while (0)
+
+status_t BnOverlay::onTransact(
+    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+    switch(code) {
+        case DESTROY: {
+            CHECK_INTERFACE(IOverlay, data, reply);
+            destroy();
+            return NO_ERROR;
+        } break;
+        case SWAP_BUFFERS: {
+            CHECK_INTERFACE(IOverlay, data, reply);
+            ssize_t offset = swapBuffers();
+            reply->writeInt32(offset);
+            return NO_ERROR;
+        } break;
+        default:
+            return BBinder::onTransact(code, data, reply, flags);
+    }
+}
+
+}; // namespace android
diff --git a/libs/ui/ISurface.cpp b/libs/ui/ISurface.cpp
index 817f4d9..c1c9596 100644
--- a/libs/ui/ISurface.cpp
+++ b/libs/ui/ISurface.cpp
@@ -22,6 +22,7 @@
 #include <utils/IMemory.h>
 
 #include <ui/ISurface.h>
+#include <ui/Overlay.h>
 
 
 namespace android {
@@ -30,6 +31,7 @@
     REGISTER_BUFFERS = IBinder::FIRST_CALL_TRANSACTION,
     UNREGISTER_BUFFERS,
     POST_BUFFER, // one-way transaction
+    CREATE_OVERLAY,
 };
 
 class BpSurface : public BpInterface<ISurface>
@@ -70,6 +72,18 @@
         data.writeInterfaceToken(ISurface::getInterfaceDescriptor());
         remote()->transact(UNREGISTER_BUFFERS, data, &reply);
     }
+
+    virtual sp<Overlay> createOverlay(
+             uint32_t w, uint32_t h, int32_t format)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(ISurface::getInterfaceDescriptor());
+        data.writeInt32(w);
+        data.writeInt32(h);
+        data.writeInt32(format);
+        remote()->transact(CREATE_OVERLAY, data, &reply);
+        return Overlay::readFromParcel(reply);
+    }
 };
 
 IMPLEMENT_META_INTERFACE(Surface, "android.ui.ISurface");
@@ -109,6 +123,14 @@
             postBuffer(offset);
             return NO_ERROR;
         } break;
+        case CREATE_OVERLAY: {
+            CHECK_INTERFACE(ISurface, data, reply);
+            int w = data.readInt32();
+            int h = data.readInt32();
+            int f = data.readInt32();
+            sp<Overlay> o = createOverlay(w, h, w);
+            return Overlay::writeToParcel(reply, o);
+        } break;
         default:
             return BBinder::onTransact(code, data, reply, flags);
     }
diff --git a/libs/ui/ISurfaceFlingerClient.cpp b/libs/ui/ISurfaceFlingerClient.cpp
index 9444af7..dd6a798 100644
--- a/libs/ui/ISurfaceFlingerClient.cpp
+++ b/libs/ui/ISurfaceFlingerClient.cpp
@@ -82,7 +82,7 @@
         data.writeInt32(format);
         data.writeInt32(flags);
         remote()->transact(CREATE_SURFACE, data, &reply);
-        params->readFromParcel(data);
+        params->readFromParcel(reply);
         return interface_cast<ISurface>(reply.readStrongBinder());
     }
                                     
@@ -191,7 +191,6 @@
 {
     token = parcel.readInt32();
     identity  = parcel.readInt32();
-    type = parcel.readInt32();
     heap[0] = interface_cast<IMemoryHeap>(parcel.readStrongBinder());
     heap[1] = interface_cast<IMemoryHeap>(parcel.readStrongBinder());
     return NO_ERROR;
@@ -201,7 +200,6 @@
 {
     parcel->writeInt32(token);
     parcel->writeInt32(identity);
-    parcel->writeInt32(type);
     parcel->writeStrongBinder(heap[0]!=0 ? heap[0]->asBinder() : NULL);
     parcel->writeStrongBinder(heap[1]!=0 ? heap[1]->asBinder() : NULL);
     return NO_ERROR;
diff --git a/libs/ui/Overlay.cpp b/libs/ui/Overlay.cpp
new file mode 100644
index 0000000..2267c3e
--- /dev/null
+++ b/libs/ui/Overlay.cpp
@@ -0,0 +1,145 @@
+/*
+ * 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.
+ */
+
+#include <utils/IMemory.h>
+#include <utils/Parcel.h>
+
+#include <ui/IOverlay.h>
+#include <ui/Overlay.h>
+
+namespace android {
+
+Overlay::Overlay(overlay_handle_t* handle, 
+        const sp<IOverlay>& o, const sp<IMemoryHeap>& heap, 
+        uint32_t w, uint32_t h, int32_t f, uint32_t ws, uint32_t hs)
+    : mOverlay(o), mHeap(heap), mCurrentBufferOffset(0), mOverlayHandle(handle),
+      mWidth(w), mHeight(h), mFormat(f), mWidthStride(ws), mHeightStride(hs)
+{
+}
+
+Overlay::Overlay(overlay_t* overlay, 
+        const sp<IOverlay>& o, const sp<IMemoryHeap>& heap)
+    : mOverlay(o), mHeap(heap) 
+{
+    mCurrentBufferOffset = 0; 
+    mOverlayHandle = overlay->getHandleRef(overlay);
+    mWidth = overlay->w;
+    mHeight = overlay->h;
+    mFormat = overlay->format; 
+    mWidthStride = overlay->w_stride;
+    mHeightStride = overlay->h_stride;
+}
+
+
+Overlay::~Overlay() {
+}
+
+void Overlay::destroy() {  
+    mOverlay->destroy();
+}
+
+status_t Overlay::swapBuffers() {
+    ssize_t result = mOverlay->swapBuffers();
+    if (result < 0)
+        return status_t(result);
+    mCurrentBufferOffset = result;
+    return NO_ERROR;
+}
+
+overlay_handle_t const* Overlay::getHandleRef() const {
+    return mOverlayHandle;
+}
+
+size_t Overlay::getBufferOffset() const {
+    return mCurrentBufferOffset;
+}
+
+sp<IMemoryHeap> Overlay::getHeap() const {
+    return mHeap;
+}
+
+uint32_t Overlay::getWidth() const {
+    return mWidth;
+}
+
+uint32_t Overlay::getHeight() const {
+    return mHeight;
+}
+
+int32_t Overlay::getFormat() const {
+    return mFormat;
+}
+
+int32_t Overlay::getWidthStride() const {
+    return mWidthStride;
+}
+
+int32_t Overlay::getHeightStride() const {
+    return mHeightStride;
+}
+
+sp<Overlay> Overlay::readFromParcel(const Parcel& data) {
+    sp<Overlay> result;
+    sp<IOverlay> overlay = IOverlay::asInterface(data.readStrongBinder());
+    if (overlay != NULL) {
+        sp<IMemoryHeap> heap = IMemoryHeap::asInterface(data.readStrongBinder());
+        uint32_t w = data.readInt32();
+        uint32_t h = data.readInt32();
+        uint32_t f = data.readInt32();
+        uint32_t ws = data.readInt32();
+        uint32_t hs = data.readInt32();
+        /* FIXME: handles should be promoted to "real" API and be handled by 
+         * the framework */
+        int numfd = data.readInt32();
+        int numint = data.readInt32();
+        overlay_handle_t* handle = (overlay_handle_t*)malloc(
+                sizeof(overlay_handle_t) + numint*sizeof(int));
+        for (int i=0 ; i<numfd ; i++)
+            handle->fds[i] = data.readFileDescriptor();
+        for (int i=0 ; i<numint ; i++)
+            handle->data[i] = data.readInt32();
+        result = new Overlay(handle, overlay, heap, w, h, f, ws, hs);
+    }
+    return result;
+}
+
+status_t Overlay::writeToParcel(Parcel* reply, const sp<Overlay>& o) {
+    if (o != NULL) {
+        reply->writeStrongBinder(o->mOverlay->asBinder());
+        reply->writeStrongBinder(o->mHeap->asBinder());
+        reply->writeInt32(o->mWidth);
+        reply->writeInt32(o->mHeight);
+        reply->writeInt32(o->mFormat);
+        reply->writeInt32(o->mWidthStride);
+        reply->writeInt32(o->mHeightStride);
+        /* FIXME: handles should be promoted to "real" API and be handled by 
+         * the framework */
+        reply->writeInt32(o->mOverlayHandle->numFds);
+        reply->writeInt32(o->mOverlayHandle->numInts);
+        for (int i=0 ; i<o->mOverlayHandle->numFds ; i++)
+            reply->writeFileDescriptor(o->mOverlayHandle->fds[i]);
+        for (int i=0 ; i<o->mOverlayHandle->numInts ; i++)
+            reply->writeInt32(o->mOverlayHandle->data[i]);
+    } else {
+        reply->writeStrongBinder(NULL);
+    }
+    return NO_ERROR;
+}
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
+
diff --git a/libs/ui/Surface.cpp b/libs/ui/Surface.cpp
index 0a9aaad..4ea9ae2 100644
--- a/libs/ui/Surface.cpp
+++ b/libs/ui/Surface.cpp
@@ -47,7 +47,7 @@
         const ISurfaceFlingerClient::surface_data_t& data,
         uint32_t w, uint32_t h, PixelFormat format, uint32_t flags,
         bool owner)
-    : mClient(client), mSurface(surface), mMemoryType(data.type),
+    : mClient(client), mSurface(surface),
       mToken(data.token), mIdentity(data.identity),
       mFormat(format), mFlags(flags), mOwner(owner)
 {
@@ -67,7 +67,6 @@
     mSurface = rhs->mSurface;
     mHeap[0] = rhs->mHeap[0];
     mHeap[1] = rhs->mHeap[1];
-    mMemoryType = rhs->mMemoryType;
     mFormat  = rhs->mFormat;
     mFlags   = rhs->mFlags;
     mSurfaceHeapBase[0] = rhs->mSurfaceHeapBase[0];
@@ -186,7 +185,6 @@
     sp<ISurface> surface    = interface_cast<ISurface>(parcel->readStrongBinder());
     data.heap[0]            = interface_cast<IMemoryHeap>(parcel->readStrongBinder());
     data.heap[1]            = interface_cast<IMemoryHeap>(parcel->readStrongBinder());
-    data.type               = parcel->readInt32();
     data.token              = parcel->readInt32();
     data.identity           = parcel->readInt32();
     PixelFormat format      = parcel->readInt32();
@@ -207,7 +205,6 @@
     sp<SurfaceComposerClient> client;
     sp<ISurface> sur;
     sp<IMemoryHeap> heap[2];
-    int type = 0;
     if (surface->isValid()) {
         token = surface->mToken;
         identity = surface->mIdentity;
@@ -215,7 +212,6 @@
         sur = surface->mSurface;
         heap[0] = surface->mHeap[0];
         heap[1] = surface->mHeap[1];
-        type = surface->mMemoryType;
         format = surface->mFormat;
         flags = surface->mFlags;
     }
@@ -223,7 +219,6 @@
     parcel->writeStrongBinder(sur!=0     ? sur->asBinder()      : NULL);
     parcel->writeStrongBinder(heap[0]!=0 ? heap[0]->asBinder()  : NULL);
     parcel->writeStrongBinder(heap[1]!=0 ? heap[1]->asBinder()  : NULL);
-    parcel->writeInt32(type);
     parcel->writeInt32(token);
     parcel->writeInt32(identity);
     parcel->writeInt32(format);
diff --git a/libs/ui/Time.cpp b/libs/ui/Time.cpp
index c98667f..b5539135 100644
--- a/libs/ui/Time.cpp
+++ b/libs/ui/Time.cpp
@@ -85,10 +85,10 @@
 }
 
 String8 
-Time::format(const char *format) const
+Time::format(const char *format, const struct strftime_locale *locale) const
 {
     char buf[257];
-    int n = strftime(buf, 257, format, &(this->t));
+    int n = strftime_tz(buf, 257, format, &(this->t), locale);
     if (n > 0) {
         return String8(buf);
     } else {
diff --git a/libs/utils/Android.mk b/libs/utils/Android.mk
index 4a68dc1..cdb8ca2 100644
--- a/libs/utils/Android.mk
+++ b/libs/utils/Android.mk
@@ -139,6 +139,14 @@
 	liblog \
 	libcutils
 
+ifneq ($(TARGET_SIMULATOR),true)
+ifeq ($(TARGET_OS)-$(TARGET_ARCH),linux-x86)
+# This is needed on x86 to bring in dl_iterate_phdr for CallStack.cpp
+LOCAL_SHARED_LIBRARIES += \
+	libdl
+endif # linux-x86
+endif # sim
+
 LOCAL_MODULE:= libutils
 
 #LOCAL_CFLAGS+=
diff --git a/libs/utils/CallStack.cpp b/libs/utils/CallStack.cpp
index 4968666..26fb22a 100644
--- a/libs/utils/CallStack.cpp
+++ b/libs/utils/CallStack.cpp
@@ -79,35 +79,35 @@
 /*****************************************************************************/
 
 static 
-const char *lookup_symbol(const void* addr, uint32_t *offset, char* name, size_t bufSize)
+const char *lookup_symbol(const void* addr, void **offset, char* name, size_t bufSize)
 {
 #if HAVE_DLADDR
-	Dl_info info;
-	if (dladdr(addr, &info)) {
-		*offset = (uint32_t)info.dli_saddr;
-		return info.dli_sname;
-	}
+    Dl_info info;
+    if (dladdr(addr, &info)) {
+        *offset = info.dli_saddr;
+        return info.dli_sname;
+    }
 #endif
-	return NULL;
+    return NULL;
 }
 
 static 
 int32_t linux_gcc_demangler(const char *mangled_name, char *unmangled_name, size_t buffersize)
 {
-	size_t out_len = 0;
+    size_t out_len = 0;
 #if HAVE_CXXABI
-	int status = 0;
-	char *demangled = abi::__cxa_demangle(mangled_name, 0, &out_len, &status);
-	if (status == 0) {
-		// OK
-		if (out_len < buffersize) memcpy(unmangled_name, demangled, out_len);
-		else out_len = 0;
-		free(demangled);
-	} else {
-		out_len = 0;
-	}
+    int status = 0;
+    char *demangled = abi::__cxa_demangle(mangled_name, 0, &out_len, &status);
+    if (status == 0) {
+        // OK
+        if (out_len < buffersize) memcpy(unmangled_name, demangled, out_len);
+        else out_len = 0;
+        free(demangled);
+    } else {
+        out_len = 0;
+    }
 #endif
-	return out_len;
+    return out_len;
 }
 
 /*****************************************************************************/
@@ -115,12 +115,12 @@
 class MapInfo {
     struct mapinfo {
         struct mapinfo *next;
-        unsigned start;
-        unsigned end;
+        uint64_t start;
+        uint64_t end;
         char name[];
     };
 
-    const char *map_to_name(unsigned pc, const char* def) {
+    const char *map_to_name(uint64_t pc, const char* def) {
         mapinfo* mi = getMapInfoList();
         while(mi) {
             if ((pc >= mi->start) && (pc < mi->end))
@@ -139,8 +139,8 @@
         if (line[20] != 'x') return 0;
         mi = (mapinfo*)malloc(sizeof(mapinfo) + (len - 47));
         if (mi == 0) return 0;
-        mi->start = strtoul(line, 0, 16);
-        mi->end = strtoul(line + 9, 0, 16);
+        mi->start = strtoull(line, 0, 16);
+        mi->end = strtoull(line + 9, 0, 16);
         mi->next = 0;
         strcpy(mi->name, line + 49);
         return mi;
@@ -184,7 +184,7 @@
     }
     
     static const char *mapAddressToName(const void* pc, const char* def) {
-        return sMapInfo.map_to_name((unsigned)pc, def);
+        return sMapInfo.map_to_name((uint64_t)pc, def);
     }
 
 };
@@ -278,7 +278,7 @@
     char tmp[256];
     char tmp1[32];
     char tmp2[32];
-    uint32_t offs;
+    void *offs;
 
     const void* ip = mStack[level];
     if (!ip) return res;
@@ -291,14 +291,14 @@
     if (name) {
         if (linux_gcc_demangler(name, tmp, 256) != 0)
             name = tmp;
-        snprintf(tmp1, 32, "0x%08x: <", (size_t)ip);
-        snprintf(tmp2, 32, ">+0x%08x", offs);
+        snprintf(tmp1, 32, "0x%p: <", ip);
+        snprintf(tmp2, 32, ">+0x%p", offs);
         res.append(tmp1);
         res.append(name);
         res.append(tmp2);
     } else { 
         name = MapInfo::mapAddressToName(ip, "<unknown>");
-        snprintf(tmp, 256, "pc %08x  %s", (size_t)ip, name);
+        snprintf(tmp, 256, "pc %p  %s", ip, name);
         res.append(tmp);
     }
     res.append("\n");
diff --git a/libs/utils/IPCThreadState.cpp b/libs/utils/IPCThreadState.cpp
index ca49d9a..04ae142 100644
--- a/libs/utils/IPCThreadState.cpp
+++ b/libs/utils/IPCThreadState.cpp
@@ -391,6 +391,29 @@
     status_t result;
     do {
         int32_t cmd;
+        
+        // When we've cleared the incoming command queue, process any pending derefs
+        if (mIn.dataPosition() >= mIn.dataSize()) {
+            size_t numPending = mPendingWeakDerefs.size();
+            if (numPending > 0) {
+                for (size_t i = 0; i < numPending; i++) {
+                    RefBase::weakref_type* refs = mPendingWeakDerefs[i];
+                    refs->decWeak(mProcess.get());
+                }
+                mPendingWeakDerefs.clear();
+            }
+
+            numPending = mPendingStrongDerefs.size();
+            if (numPending > 0) {
+                for (size_t i = 0; i < numPending; i++) {
+                    BBinder* obj = mPendingStrongDerefs[i];
+                    obj->decStrong(mProcess.get());
+                }
+                mPendingStrongDerefs.clear();
+            }
+        }
+
+        // now get the next command to be processed, waiting if necessary
         result = talkWithDriver();
         if (result >= NO_ERROR) {
             size_t IN = mIn.dataAvail();
@@ -832,7 +855,7 @@
             LOG_REMOTEREFS("BR_RELEASE from driver on %p", obj);
             obj->printRefs();
         }
-        obj->decStrong(mProcess.get());
+        mPendingStrongDerefs.push(obj);
         break;
         
     case BR_INCREFS:
@@ -853,7 +876,7 @@
         //LOG_ASSERT(refs->refBase() == obj,
         //           "BR_DECREFS: object %p does not match cookie %p (expected %p)",
         //           refs, obj, refs->refBase());
-        refs->decWeak(mProcess.get());
+        mPendingWeakDerefs.push(refs);
         break;
         
     case BR_ATTEMPT_ACQUIRE:
diff --git a/libs/utils/LogSocket.cpp b/libs/utils/LogSocket.cpp
index e64f794..55c1b99 100644
--- a/libs/utils/LogSocket.cpp
+++ b/libs/utils/LogSocket.cpp
@@ -16,7 +16,7 @@
 
 
 #ifndef HAVE_WINSOCK
-#define SOCKETLOG
+//#define SOCKETLOG
 #endif
 
 #ifdef SOCKETLOG
diff --git a/libs/utils/MemoryDealer.cpp b/libs/utils/MemoryDealer.cpp
index e6d1d18..cf8201b 100644
--- a/libs/utils/MemoryDealer.cpp
+++ b/libs/utils/MemoryDealer.cpp
@@ -387,21 +387,23 @@
     start = (start + pagesize-1) & ~(pagesize-1);
     end &= ~(pagesize-1);    
 
-    void* const start_ptr = (void*)(intptr_t(getHeap()->base()) + start);
-    size_t size = end-start;
+    if (start < end) {
+        void* const start_ptr = (void*)(intptr_t(getHeap()->base()) + start);
+        size_t size = end-start;
 
 #ifndef NDEBUG
-    memset(start_ptr, 0xdf, size);
+        memset(start_ptr, 0xdf, size);
 #endif
-  
-// MADV_REMOVE is not defined on Dapper based Goobuntu 
+
+        // MADV_REMOVE is not defined on Dapper based Goobuntu 
 #ifdef MADV_REMOVE 
-    if (size) {
-        int err = madvise(start_ptr, size, MADV_REMOVE);
-        LOGW_IF(err, "madvise(%p, %u, MADV_REMOVE) returned %s",
-                start_ptr, size, err<0 ? strerror(errno) : "Ok");
-    }
+        if (size) {
+            int err = madvise(start_ptr, size, MADV_REMOVE);
+            LOGW_IF(err, "madvise(%p, %u, MADV_REMOVE) returned %s",
+                    start_ptr, size, err<0 ? strerror(errno) : "Ok");
+        }
 #endif
+    }
 }
 
 }; // namespace android
diff --git a/libs/utils/MemoryHeapPmem.cpp b/libs/utils/MemoryHeapPmem.cpp
index 1e5a1cc..eba2b30 100644
--- a/libs/utils/MemoryHeapPmem.cpp
+++ b/libs/utils/MemoryHeapPmem.cpp
@@ -38,9 +38,20 @@
 
 // ---------------------------------------------------------------------------
 
-class MemoryHeapPmem;
+MemoryHeapPmem::MemoryPmem::MemoryPmem(const sp<MemoryHeapPmem>& heap)
+    : BnMemory(), mClientHeap(heap)
+{
+}
 
-class SubRegionMemory : public BnMemory {
+MemoryHeapPmem::MemoryPmem::~MemoryPmem() {
+    if (mClientHeap != NULL) {
+        mClientHeap->remove(this);
+    }
+}
+
+// ---------------------------------------------------------------------------
+
+class SubRegionMemory : public MemoryHeapPmem::MemoryPmem {
 public:
     SubRegionMemory(const sp<MemoryHeapPmem>& heap, ssize_t offset, size_t size);
     virtual ~SubRegionMemory();
@@ -50,15 +61,14 @@
     void revoke();
     size_t              mSize;
     ssize_t             mOffset;
-    sp<MemoryHeapPmem>  mClientHeap;
 };
 
 SubRegionMemory::SubRegionMemory(const sp<MemoryHeapPmem>& heap,
         ssize_t offset, size_t size)
-    : mSize(size), mOffset(offset), mClientHeap(heap)
+    : MemoryHeapPmem::MemoryPmem(heap), mSize(size), mOffset(offset)
 {
 #ifndef NDEBUG
-    void* const start_ptr = (void*)(intptr_t(mClientHeap->base()) + offset);
+    void* const start_ptr = (void*)(intptr_t(getHeap()->base()) + offset);
     memset(start_ptr, 0xda, size);
 #endif
 
@@ -80,7 +90,7 @@
 {
     if (offset) *offset = mOffset;
     if (size)   *size = mSize;
-    return mClientHeap;
+    return getHeap();
 }
 
 SubRegionMemory::~SubRegionMemory()
@@ -98,8 +108,9 @@
     // promote() it.
     
 #if HAVE_ANDROID_OS
-    if (mClientHeap != NULL) {
-        int our_fd = mClientHeap->heapID();
+    if (mSize != NULL) {
+        const sp<MemoryHeapPmem>& heap(getHeap());
+        int our_fd = heap->heapID();
         struct pmem_region sub;
         sub.offset = mOffset;
         sub.len = mSize;
@@ -107,7 +118,7 @@
         LOGE_IF(err<0, "PMEM_UNMAP failed (%s), "
                 "mFD=%d, sub.offset=%lu, sub.size=%lu",
                 strerror(errno), our_fd, sub.offset, sub.len);
-        mClientHeap.clear();
+        mSize = 0;
     }
 #endif
 }
@@ -157,10 +168,7 @@
 
 sp<IMemory> MemoryHeapPmem::mapMemory(size_t offset, size_t size)
 {
-    sp<SubRegionMemory> memory;
-    if (heapID() > 0) 
-        memory = new SubRegionMemory(this, offset, size);
-
+    sp<MemoryPmem> memory = createMemory(offset, size);
     if (memory != 0) {
         Mutex::Autolock _l(mLock);
         mAllocations.add(memory);
@@ -168,6 +176,15 @@
     return memory;
 }
 
+sp<MemoryHeapPmem::MemoryPmem> MemoryHeapPmem::createMemory(
+        size_t offset, size_t size)
+{
+    sp<SubRegionMemory> memory;
+    if (heapID() > 0) 
+        memory = new SubRegionMemory(this, offset, size);
+    return memory;
+}
+
 status_t MemoryHeapPmem::slap()
 {
 #if HAVE_ANDROID_OS
@@ -206,21 +223,26 @@
 
 void MemoryHeapPmem::revoke()
 {
-    Vector< wp<SubRegionMemory> > allocations;
+    SortedVector< wp<MemoryPmem> > allocations;
 
     { // scope for lock
         Mutex::Autolock _l(mLock);
         allocations = mAllocations;
-        mAllocations.clear();
     }
     
     ssize_t count = allocations.size();
     for (ssize_t i=0 ; i<count ; i++) {
-        sp<SubRegionMemory> memory(allocations[i].promote());
+        sp<MemoryPmem> memory(allocations[i].promote());
         if (memory != 0)
             memory->revoke();
     }
 }
 
+void MemoryHeapPmem::remove(const wp<MemoryPmem>& memory)
+{
+    Mutex::Autolock _l(mLock);
+    mAllocations.remove(memory);
+}
+
 // ---------------------------------------------------------------------------
 }; // namespace android
diff --git a/libs/utils/ResourceTypes.cpp b/libs/utils/ResourceTypes.cpp
index a5fe9fb..5a09fb4 100644
--- a/libs/utils/ResourceTypes.cpp
+++ b/libs/utils/ResourceTypes.cpp
@@ -164,7 +164,11 @@
 
 size_t Res_png_9patch::serializedSize()
 {
-    return sizeof(Res_png_9patch)
+    // The size of this struct is 32 bytes on the 32-bit target system
+    // 4 * int8_t
+    // 4 * int32_t
+    // 3 * pointer
+    return 32
             + numXDivs * sizeof(int32_t)
             + numYDivs * sizeof(int32_t)
             + numColors * sizeof(uint32_t);
@@ -180,8 +184,10 @@
 void Res_png_9patch::serialize(void * outData)
 {
     char* data = (char*) outData;
-    memmove(data, this, sizeof(Res_png_9patch));
-    data +=  sizeof(Res_png_9patch);
+    memmove(data, &wasDeserialized, 4);     // copy  wasDeserialized, numXDivs, numYDivs, numColors
+    memmove(data + 12, &paddingLeft, 16);   // copy paddingXXXX
+    data += 32;
+
     memmove(data, this->xDivs, numXDivs * sizeof(int32_t));
     data +=  numXDivs * sizeof(int32_t);
     memmove(data, this->yDivs, numYDivs * sizeof(int32_t));
@@ -189,27 +195,32 @@
     memmove(data, this->colors, numColors * sizeof(uint32_t));
 }
 
-Res_png_9patch* Res_png_9patch::deserialize(const void* inData)
-{
-    deserialize(inData, (Res_png_9patch*) inData);
-    return (Res_png_9patch*) inData;
-}
-
-void Res_png_9patch::deserialize(const void* inData, Res_png_9patch* outData) {
-    Res_png_9patch* patch = (Res_png_9patch*) inData;
+static void deserializeInternal(const void* inData, Res_png_9patch* outData) {
+    char* patch = (char*) inData;
     if (inData != outData) {
-        memcpy(outData, inData, patch->serializedSize());
+        memmove(&outData->wasDeserialized, patch, 4);     // copy  wasDeserialized, numXDivs, numYDivs, numColors
+        memmove(&outData->paddingLeft, patch + 12, 4);     // copy  wasDeserialized, numXDivs, numYDivs, numColors
     }
     outData->wasDeserialized = true;
     char* data = (char*)outData;
     data +=  sizeof(Res_png_9patch);
     outData->xDivs = (int32_t*) data;
-    data +=  patch->numXDivs * sizeof(int32_t);
+    data +=  outData->numXDivs * sizeof(int32_t);
     outData->yDivs = (int32_t*) data;
-    data +=  patch->numYDivs * sizeof(int32_t);
+    data +=  outData->numYDivs * sizeof(int32_t);
     outData->colors = (uint32_t*) data;
 }
 
+Res_png_9patch* Res_png_9patch::deserialize(const void* inData)
+{
+    if (sizeof(void*) != sizeof(int32_t)) {
+        LOGE("Cannot deserialize on non 32-bit system\n");
+        return NULL;
+    }
+    deserializeInternal(inData, (Res_png_9patch*) inData);
+    return (Res_png_9patch*) inData;
+}
+
 // --------------------------------------------------------------------
 // --------------------------------------------------------------------
 // --------------------------------------------------------------------
@@ -3863,7 +3874,7 @@
                 }
                 for (size_t configIndex=0; configIndex<NTC; configIndex++) {
                     const ResTable_type* type = typeConfigs->configs[configIndex];
-                    if ((((int)type)&0x3) != 0) {
+                    if ((((uint64_t)type)&0x3) != 0) {
                         printf("      NON-INTEGER ResTable_type ADDRESS: %p\n", type);
                         continue;
                     }
diff --git a/libs/utils/futex_synchro.c b/libs/utils/futex_synchro.c
index c13760d..ba19520 100644
--- a/libs/utils/futex_synchro.c
+++ b/libs/utils/futex_synchro.c
@@ -25,8 +25,8 @@
 #include <private/utils/futex_synchro.h>
 
 
-// This futex glue code is need on desktop linux, but is part of klibc on ARM
-#if !defined(__arm__)
+// This futex glue code is need on desktop linux, but is already part of bionic.
+#if !defined(HAVE_FUTEX_WRAPPERS)
 
 #include <sys/syscall.h>
 typedef unsigned int u32;
@@ -76,7 +76,7 @@
 int __atomic_swap(int _new, volatile int *ptr);
 int __atomic_dec(volatile int *ptr);
 
-#endif // !defined(__arm__)
+#endif // !defined(HAVE_FUTEX_WRAPPERS)
 
 
 // lock states