Merge "Fix a bug in sp<> and wp<> which could cause memory corruptions" into gingerbread
diff --git a/libs/audioflinger/AudioFlinger.cpp b/libs/audioflinger/AudioFlinger.cpp
index 1860793..48c04a6 100644
--- a/libs/audioflinger/AudioFlinger.cpp
+++ b/libs/audioflinger/AudioFlinger.cpp
@@ -51,7 +51,7 @@
 #include "lifevibes.h"
 #endif
 
-#include <media/EffectFactoryApi.h>
+#include <media/EffectsFactoryApi.h>
 
 // ----------------------------------------------------------------------------
 // the sim build doesn't have gettid
@@ -126,7 +126,8 @@
 
 AudioFlinger::AudioFlinger()
     : BnAudioFlinger(),
-        mAudioHardware(0), mMasterVolume(1.0f), mMasterMute(false), mNextUniqueId(1)
+        mAudioHardware(0), mMasterVolume(1.0f), mMasterMute(false), mNextUniqueId(1),
+        mTotalEffectsCpuLoad(0), mTotalEffectsMemory(0)
 {
     mHardwareStatus = AUDIO_HW_IDLE;
 
@@ -135,8 +136,8 @@
     mHardwareStatus = AUDIO_HW_INIT;
     if (mAudioHardware->initCheck() == NO_ERROR) {
         // open 16-bit output stream for s/w mixer
-
-        setMode(AudioSystem::MODE_NORMAL);
+        mMode = AudioSystem::MODE_NORMAL;
+        setMode(mMode);
 
         setMasterVolume(1.0f);
         setMasterMute(false);
@@ -431,6 +432,8 @@
 
 status_t AudioFlinger::setMode(int mode)
 {
+    status_t ret;
+
     // check calling permissions
     if (!settingsAllowed()) {
         return PERMISSION_DENIED;
@@ -440,15 +443,23 @@
         return BAD_VALUE;
     }
 
-    AutoMutex lock(mHardwareLock);
-    mHardwareStatus = AUDIO_HW_SET_MODE;
-    status_t ret = mAudioHardware->setMode(mode);
-#ifdef LVMX
-    if (NO_ERROR == ret) {
-        LifeVibes::setMode(mode);
+    { // scope for the lock
+        AutoMutex lock(mHardwareLock);
+        mHardwareStatus = AUDIO_HW_SET_MODE;
+        ret = mAudioHardware->setMode(mode);
+        mHardwareStatus = AUDIO_HW_IDLE;
     }
+
+    if (NO_ERROR == ret) {
+        Mutex::Autolock _l(mLock);
+        mMode = mode;
+        for (uint32_t i = 0; i < mPlaybackThreads.size(); i++)
+           mPlaybackThreads.valueAt(i)->setMode(mode);
+#ifdef LVMX
+        LifeVibes::setMode(mode);
 #endif
-    mHardwareStatus = AUDIO_HW_IDLE;
+    }
+
     return ret;
 }
 
@@ -1385,6 +1396,15 @@
     return chain;
 }
 
+void AudioFlinger::PlaybackThread::setMode(uint32_t mode)
+{
+    Mutex::Autolock _l(mLock);
+    size_t size = mEffectChains.size();
+    for (size_t i = 0; i < size; i++) {
+        mEffectChains[i]->setMode(mode);
+    }
+}
+
 // ----------------------------------------------------------------------------
 
 AudioFlinger::MixerThread::MixerThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int id, uint32_t device)
@@ -1803,9 +1823,9 @@
             t->mCblk->flags |= CBLK_INVALID_ON;
             t->mCblk->cv.signal();
             t->mCblk->lock.unlock();
-                }
-            }
         }
+    }
+}
 
 
 // getTrackName_l() must be called with ThreadBase::mLock held
@@ -4466,10 +4486,10 @@
     return EffectQueryNumberEffects(numEffects);
 }
 
-status_t AudioFlinger::queryNextEffect(effect_descriptor_t *descriptor)
+status_t AudioFlinger::queryEffect(uint32_t index, effect_descriptor_t *descriptor)
 {
     Mutex::Autolock _l(mLock);
-    return EffectQueryNext(descriptor);
+    return EffectQueryEffect(index, descriptor);
 }
 
 status_t AudioFlinger::getEffectDescriptor(effect_uuid_t *pUuid, effect_descriptor_t *descriptor)
@@ -4529,10 +4549,10 @@
                 LOGW("createEffect() error %d from EffectQueryNumberEffects", lStatus);
                 goto Exit;
             }
-            for (; numEffects > 0; numEffects--) {
-                lStatus = EffectQueryNext(&desc);
+            for (uint32_t i = 0; i < numEffects; i++) {
+                lStatus = EffectQueryEffect(i, &desc);
                 if (lStatus < 0) {
-                    LOGW("createEffect() error %d from EffectQueryNext", lStatus);
+                    LOGW("createEffect() error %d from EffectQueryEffect", lStatus);
                     continue;
                 }
                 if (memcmp(&desc.type, &pDesc->type, sizeof(effect_uuid_t)) == 0) {
@@ -4567,6 +4587,13 @@
             goto Exit;
         }
 
+        // Session -1 is reserved for output stage effects that can only be created
+        // by audio policy manager (running in same process)
+        if (sessionId == -1 && getpid() != IPCThreadState::self()->getCallingPid()) {
+            lStatus = INVALID_OPERATION;
+            goto Exit;
+        }
+
         // return effect descriptor
         memcpy(pDesc, &desc, sizeof(effect_descriptor_t));
 
@@ -4574,7 +4601,7 @@
         // output threads.
         // TODO: allow attachment of effect to inputs
         if (output == 0) {
-            if (sessionId == 0) {
+            if (sessionId <= 0) {
                 // default to first output
                 // TODO: define criteria to choose output when not specified. Or
                 // receive output from audio policy manager
@@ -4621,6 +4648,33 @@
     return handle;
 }
 
+status_t AudioFlinger::registerEffectResource_l(effect_descriptor_t *desc) {
+    if (mTotalEffectsCpuLoad + desc->cpuLoad > MAX_EFFECTS_CPU_LOAD) {
+        LOGW("registerEffectResource() CPU Load limit exceeded for Fx %s, CPU %f MIPS",
+                desc->name, (float)desc->cpuLoad/10);
+        return INVALID_OPERATION;
+    }
+    if (mTotalEffectsMemory + desc->memoryUsage > MAX_EFFECTS_MEMORY) {
+        LOGW("registerEffectResource() memory limit exceeded for Fx %s, Memory %d KB",
+                desc->name, desc->memoryUsage);
+        return INVALID_OPERATION;
+    }
+    mTotalEffectsCpuLoad += desc->cpuLoad;
+    mTotalEffectsMemory += desc->memoryUsage;
+    LOGV("registerEffectResource_l() effect %s, CPU %d, memory %d",
+            desc->name, desc->cpuLoad, desc->memoryUsage);
+    LOGV("  total CPU %d, total memory %d", mTotalEffectsCpuLoad, mTotalEffectsMemory);
+    return NO_ERROR;
+}
+
+void AudioFlinger::unregisterEffectResource_l(effect_descriptor_t *desc) {
+    mTotalEffectsCpuLoad -= desc->cpuLoad;
+    mTotalEffectsMemory -= desc->memoryUsage;
+    LOGV("unregisterEffectResource_l() effect %s, CPU %d, memory %d",
+            desc->name, desc->cpuLoad, desc->memoryUsage);
+    LOGV("  total CPU %d, total memory %d", mTotalEffectsCpuLoad, mTotalEffectsMemory);
+}
+
 // PlaybackThread::createEffect_l() must be called with AudioFlinger::mLock held
 sp<AudioFlinger::EffectHandle> AudioFlinger::PlaybackThread::createEffect_l(
         const sp<AudioFlinger::Client>& client,
@@ -4638,6 +4692,7 @@
     sp<Track> track;
     sp<EffectChain> chain;
     bool effectCreated = false;
+    bool effectRegistered = false;
 
     if (mOutput == 0) {
         LOGW("createEffect_l() Audio driver not initialized.");
@@ -4680,20 +4735,26 @@
         LOGV("createEffect_l() got effect %p on chain %p", effect == 0 ? 0 : effect.get(), chain.get());
 
         if (effect == 0) {
+            // Check CPU and memory usage
+            lStatus = mAudioFlinger->registerEffectResource_l(desc);
+            if (lStatus != NO_ERROR) {
+                goto Exit;
+            }
+            effectRegistered = true;
             // create a new effect module if none present in the chain
-            effectCreated = true;
             effect = new EffectModule(this, chain, desc, mAudioFlinger->nextUniqueId(), sessionId);
             lStatus = effect->status();
             if (lStatus != NO_ERROR) {
                 goto Exit;
             }
-            //TODO: handle CPU load and memory usage here
             lStatus = chain->addEffect(effect);
             if (lStatus != NO_ERROR) {
                 goto Exit;
             }
+            effectCreated = true;
 
             effect->setDevice(mDevice);
+            effect->setMode(mAudioFlinger->getMode());
         }
         // create effect handle and connect it to effect module
         handle = new EffectHandle(effect, client, effectClient, priority);
@@ -4705,11 +4766,14 @@
 
 Exit:
     if (lStatus != NO_ERROR && lStatus != ALREADY_EXISTS) {
-        if (chain != 0 && effectCreated) {
+        if (effectCreated) {
             if (chain->removeEffect(effect) == 0) {
                 removeEffectChain_l(chain);
             }
         }
+        if (effectRegistered) {
+            mAudioFlinger->unregisterEffectResource_l(desc);
+        }
         handle.clear();
     }
 
@@ -4719,21 +4783,37 @@
     return handle;
 }
 
+void AudioFlinger::PlaybackThread::disconnectEffect(const sp< EffectModule>& effect,
+                                                    const wp<EffectHandle>& handle) {
+    effect_descriptor_t desc = effect->desc();
+    Mutex::Autolock _l(mLock);
+    // delete the effect module if removing last handle on it
+    if (effect->removeHandle(handle) == 0) {
+        if ((desc.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) {
+            detachAuxEffect_l(effect->id());
+        }
+        sp<EffectChain> chain = effect->chain().promote();
+        if (chain != 0) {
+            // remove effect chain if remove last effect
+            if (chain->removeEffect(effect) == 0) {
+                removeEffectChain_l(chain);
+            }
+        }
+        mLock.unlock();
+        mAudioFlinger->mLock.lock();
+        mAudioFlinger->unregisterEffectResource_l(&desc);
+        mAudioFlinger->mLock.unlock();
+    }
+}
+
 status_t AudioFlinger::PlaybackThread::addEffectChain_l(const sp<EffectChain>& chain)
 {
     int session = chain->sessionId();
     int16_t *buffer = mMixBuffer;
+    bool ownsBuffer = false;
 
     LOGV("addEffectChain_l() %p on thread %p for session %d", chain.get(), this, session);
-    if (session == 0) {
-        chain->setInBuffer(buffer, false);
-        chain->setOutBuffer(buffer);
-        // Effect chain for session 0 is inserted at end of effect chains list
-        // to be processed last as it contains output mix effects to apply after
-        // all track specific effects
-        mEffectChains.add(chain);
-    } else {
-        bool ownsBuffer = false;
+    if (session > 0) {
         // Only one effect chain can be present in direct output thread and it uses
         // the mix buffer as input
         if (mType != DIRECT) {
@@ -4743,32 +4823,42 @@
             LOGV("addEffectChain_l() creating new input buffer %p session %d", buffer, session);
             ownsBuffer = true;
         }
-        chain->setInBuffer(buffer, ownsBuffer);
-        chain->setOutBuffer(mMixBuffer);
-        // Effect chain for session other than 0 is inserted at beginning of effect
-        // chains list to be processed before output mix effects. Relative order between
-        // sessions other than 0 is not important
-        mEffectChains.insertAt(chain, 0);
-    }
 
-    // Attach all tracks with same session ID to this chain.
-    for (size_t i = 0; i < mTracks.size(); ++i) {
-        sp<Track> track = mTracks[i];
-        if (session == track->sessionId()) {
-            LOGV("addEffectChain_l() track->setMainBuffer track %p buffer %p", track.get(), buffer);
-            track->setMainBuffer(buffer);
+        // Attach all tracks with same session ID to this chain.
+        for (size_t i = 0; i < mTracks.size(); ++i) {
+            sp<Track> track = mTracks[i];
+            if (session == track->sessionId()) {
+                LOGV("addEffectChain_l() track->setMainBuffer track %p buffer %p", track.get(), buffer);
+                track->setMainBuffer(buffer);
+            }
+        }
+
+        // indicate all active tracks in the chain
+        for (size_t i = 0 ; i < mActiveTracks.size() ; ++i) {
+            sp<Track> track = mActiveTracks[i].promote();
+            if (track == 0) continue;
+            if (session == track->sessionId()) {
+                LOGV("addEffectChain_l() activating track %p on session %d", track.get(), session);
+                chain->startTrack();
+            }
         }
     }
 
-    // indicate all active tracks in the chain
-    for (size_t i = 0 ; i < mActiveTracks.size() ; ++i) {
-        sp<Track> track = mActiveTracks[i].promote();
-        if (track == 0) continue;
-        if (session == track->sessionId()) {
-            LOGV("addEffectChain_l() activating track %p on session %d", track.get(), session);
-            chain->startTrack();
-        }
+    chain->setInBuffer(buffer, ownsBuffer);
+    chain->setOutBuffer(mMixBuffer);
+    // Effect chain for session -1 is inserted at end of effect chains list
+    // in order to be processed last as it contains output stage effects
+    // Effect chain for session 0 is inserted before session -1 to be processed
+    // after track specific effects and before output stage
+    // Effect chain for session other than 0 is inserted at beginning of effect
+    // chains list to be processed before output mix effects. Relative order between
+    // sessions other than 0 is not important
+    size_t size = mEffectChains.size();
+    size_t i = 0;
+    for (i = 0; i < size; i++) {
+        if (mEffectChains[i]->sessionId() < session) break;
     }
+    mEffectChains.insertAt(chain, i);
 
     return NO_ERROR;
 }
@@ -4884,7 +4974,8 @@
     memcpy(&mDescriptor, desc, sizeof(effect_descriptor_t));
 
     // create effect engine from effect factory
-    mStatus = EffectCreate(&desc->uuid, &mEffectInterface);
+    mStatus = EffectCreate(&desc->uuid, sessionId, p->id(), &mEffectInterface);
+
     if (mStatus != NO_ERROR) {
         return;
     }
@@ -4969,22 +5060,11 @@
     // keep a strong reference on this EffectModule to avoid calling the
     // destructor before we exit
     sp<EffectModule> keep(this);
-    sp<ThreadBase> thread = mThread.promote();
-    if (thread != 0) {
-        Mutex::Autolock _l(thread->mLock);
-        // delete the effect module if removing last handle on it
-        if (removeHandle(handle) == 0) {
+    {
+        sp<ThreadBase> thread = mThread.promote();
+        if (thread != 0) {
             PlaybackThread *playbackThread = (PlaybackThread *)thread.get();
-            if ((mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) {
-                playbackThread->detachAuxEffect_l(mId);
-            }
-            sp<EffectChain> chain = mChain.promote();
-            if (chain != 0) {
-                // remove effect chain if remove last effect
-                if (chain->removeEffect(keep) == 0) {
-                    playbackThread->removeEffectChain_l(chain);
-                }
-            }
+            playbackThread->disconnectEffect(keep, handle);
         }
     }
 }
@@ -5007,88 +5087,25 @@
 
         // TODO: handle effects with buffer provider
         if (mState != ACTIVE) {
-            uint32_t count = mConfig.inputCfg.buffer.frameCount;
-            int32_t amp = 32767L << 16;
-            int32_t step = amp / count;
-            int16_t *pIn = mConfig.inputCfg.buffer.s16;
-            int16_t *pOut = mConfig.outputCfg.buffer.s16;
-            int inChannels;
-            int outChannels;
-
-            if (mConfig.inputCfg.channels == CHANNEL_MONO) {
-                inChannels = 1;
-            } else {
-                inChannels = 2;
-            }
-            if (mConfig.outputCfg.channels == CHANNEL_MONO) {
-                outChannels = 1;
-            } else {
-                outChannels = 2;
-            }
-
             switch (mState) {
             case RESET:
                 reset();
+                mState = STARTING;
                 // clear auxiliary effect input buffer for next accumulation
                 if ((mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) {
                     memset(mConfig.inputCfg.buffer.raw, 0, mConfig.inputCfg.buffer.frameCount*sizeof(int32_t));
                 }
-                step = -step;
-                mState = STARTING;
-                break;
+                return;
             case STARTING:
                 start();
-                amp = 0;
-                pOut = mConfig.inputCfg.buffer.s16;
-                outChannels = inChannels;
                 mState = ACTIVE;
                 break;
             case STOPPING:
-                step = -step;
-                pOut = mConfig.inputCfg.buffer.s16;
-                outChannels = inChannels;
                 mState = STOPPED;
                 break;
             case STOPPED:
                 stop();
-                amp = 0;
                 mState = IDLE;
-                break;
-            }
-
-            // ramp volume down or up before activating or deactivating the effect
-            if (inChannels == 1) {
-                if (outChannels == 1) {
-                    while (count--) {
-                        *pOut++ = (int16_t)(((int32_t)*pIn++ * (amp >> 16)) >> 15);
-                        amp += step;
-                    }
-                } else {
-                    while (count--) {
-                        int32_t smp = (int16_t)(((int32_t)*pIn++ * (amp >> 16)) >> 15);
-                        *pOut++ = smp;
-                        *pOut++ = smp;
-                        amp += step;
-                    }
-                }
-            } else {
-                if (outChannels == 1) {
-                    while (count--) {
-                        int32_t smp = (((int32_t)*pIn * (amp >> 16)) >> 16) +
-                                      (((int32_t)*(pIn + 1) * (amp >> 16)) >> 16);
-                        pIn += 2;
-                        *pOut++ = (int16_t)smp;
-                        amp += step;
-                    }
-                } else {
-                    while (count--) {
-                        *pOut++ = (int16_t)((int32_t)*pIn++ * (amp >> 16)) >> 15;
-                        *pOut++ = (int16_t)((int32_t)*pIn++ * (amp >> 16)) >> 15;
-                         amp += step;
-                    }
-                }
-            }
-            if (mState == STARTING || mState == IDLE) {
                 return;
             }
         }
@@ -5148,8 +5165,8 @@
         mConfig.inputCfg.channels = channels;
     }
     mConfig.outputCfg.channels = channels;
-    mConfig.inputCfg.format = PCM_FORMAT_S15;
-    mConfig.outputCfg.format = PCM_FORMAT_S15;
+    mConfig.inputCfg.format = SAMPLE_FORMAT_PCM_S15;
+    mConfig.outputCfg.format = SAMPLE_FORMAT_PCM_S15;
     mConfig.inputCfg.samplingRate = thread->sampleRate();
     mConfig.outputCfg.samplingRate = mConfig.inputCfg.samplingRate;
     mConfig.inputCfg.bufferProvider.cookie = NULL;
@@ -5160,7 +5177,7 @@
     mConfig.outputCfg.bufferProvider.releaseBuffer = NULL;
     mConfig.inputCfg.accessMode = EFFECT_BUFFER_ACCESS_READ;
     // Insert effect:
-    // - in session 0, always overwrites output buffer: input buffer == output buffer
+    // - in session 0 or -1, always overwrites output buffer: input buffer == output buffer
     // - in other sessions:
     //      last effect in the chain accumulates in output buffer: input buffer != output buffer
     //      other effect: overwrites output buffer: input buffer == output buffer
@@ -5331,7 +5348,12 @@
 status_t AudioFlinger::EffectModule::setDevice(uint32_t device)
 {
     status_t status = NO_ERROR;
-    if ((mDescriptor.flags & EFFECT_FLAG_DEVICE_MASK) == EFFECT_FLAG_DEVICE_MASK) {
+    if ((mDescriptor.flags & EFFECT_FLAG_DEVICE_MASK) == EFFECT_FLAG_DEVICE_IND) {
+        // convert device bit field from AudioSystem to EffectApi format.
+        device = deviceAudioSystemToEffectApi(device);
+        if (device == 0) {
+            return BAD_VALUE;
+        }
         status_t cmdStatus;
         int size = sizeof(status_t);
         status = (*mEffectInterface)->command(mEffectInterface, EFFECT_CMD_SET_DEVICE, sizeof(uint32_t), &device, &size, &cmdStatus);
@@ -5342,6 +5364,70 @@
     return status;
 }
 
+status_t AudioFlinger::EffectModule::setMode(uint32_t mode)
+{
+    status_t status = NO_ERROR;
+    if ((mDescriptor.flags & EFFECT_FLAG_AUDIO_MODE_MASK) == EFFECT_FLAG_AUDIO_MODE_IND) {
+        // convert audio mode from AudioSystem to EffectApi format.
+        int effectMode = modeAudioSystemToEffectApi(mode);
+        if (effectMode < 0) {
+            return BAD_VALUE;
+        }
+        status_t cmdStatus;
+        int size = sizeof(status_t);
+        status = (*mEffectInterface)->command(mEffectInterface, EFFECT_CMD_SET_AUDIO_MODE, sizeof(int), &effectMode, &size, &cmdStatus);
+        if (status == NO_ERROR) {
+            status = cmdStatus;
+        }
+    }
+    return status;
+}
+
+// update this table when AudioSystem::audio_devices or audio_device_e (in EffectApi.h) are modified
+const uint32_t AudioFlinger::EffectModule::sDeviceConvTable[] = {
+    DEVICE_EARPIECE, // AudioSystem::DEVICE_OUT_EARPIECE
+    DEVICE_SPEAKER, // AudioSystem::DEVICE_OUT_SPEAKER
+    DEVICE_WIRED_HEADSET, // case AudioSystem::DEVICE_OUT_WIRED_HEADSET
+    DEVICE_WIRED_HEADPHONE, // AudioSystem::DEVICE_OUT_WIRED_HEADPHONE
+    DEVICE_BLUETOOTH_SCO, // AudioSystem::DEVICE_OUT_BLUETOOTH_SCO
+    DEVICE_BLUETOOTH_SCO_HEADSET, // AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_HEADSET
+    DEVICE_BLUETOOTH_SCO_CARKIT, //  AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_CARKIT
+    DEVICE_BLUETOOTH_A2DP, //  AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP
+    DEVICE_BLUETOOTH_A2DP_HEADPHONES, // AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES
+    DEVICE_BLUETOOTH_A2DP_SPEAKER, // AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER
+    DEVICE_AUX_DIGITAL // AudioSystem::DEVICE_OUT_AUX_DIGITAL
+};
+
+uint32_t AudioFlinger::EffectModule::deviceAudioSystemToEffectApi(uint32_t device)
+{
+    uint32_t deviceOut = 0;
+    while (device) {
+        const uint32_t i = 31 - __builtin_clz(device);
+        device &= ~(1 << i);
+        if (i >= sizeof(sDeviceConvTable)/sizeof(uint32_t)) {
+            LOGE("device convertion error for AudioSystem device 0x%08x", device);
+            return 0;
+        }
+        deviceOut |= (uint32_t)sDeviceConvTable[i];
+    }
+    return deviceOut;
+}
+
+// update this table when AudioSystem::audio_mode or audio_mode_e (in EffectApi.h) are modified
+const uint32_t AudioFlinger::EffectModule::sModeConvTable[] = {
+    AUDIO_MODE_NORMAL,   // AudioSystem::MODE_NORMAL
+    AUDIO_MODE_RINGTONE, // AudioSystem::MODE_RINGTONE
+    AUDIO_MODE_IN_CALL   // AudioSystem::MODE_IN_CALL
+};
+
+int AudioFlinger::EffectModule::modeAudioSystemToEffectApi(uint32_t mode)
+{
+    int modeOut = -1;
+    if (mode < sizeof(sModeConvTable) / sizeof(uint32_t)) {
+        modeOut = (int)sModeConvTable[mode];
+    }
+    return modeOut;
+}
 
 status_t AudioFlinger::EffectModule::dump(int fd, const Vector<String16>& args)
 {
@@ -5525,7 +5611,16 @@
             int rsize = sizeof(int);
             int *p = (int *)(mBuffer + mCblk->serverIndex);
             int size = *p++;
+            if (((uint8_t *)p + size) > mBuffer + mCblk->clientIndex) {
+                LOGW("command(): invalid parameter block size");
+                break;
+            }
             effect_param_t *param = (effect_param_t *)p;
+            if (param->psize == 0 || param->vsize == 0) {
+                LOGW("command(): null parameter or value size");
+                mCblk->serverIndex += size;
+                continue;
+            }
             int psize = sizeof(effect_param_t) + ((param->psize - 1) / sizeof(int) + 1) * sizeof(int) + param->vsize;
             status_t ret = mEffect->command(EFFECT_CMD_SET_PARAM, psize, p, &rsize, &reply);
             if (ret == NO_ERROR) {
@@ -5659,7 +5754,7 @@
     }
     // if no track is active, input buffer must be cleared here as the mixer process
     // will not do it
-    if (mSessionId != 0 && activeTracks() == 0) {
+    if (mSessionId > 0 && activeTracks() == 0) {
         sp<ThreadBase> thread = mThread.promote();
         if (thread != 0) {
             size_t numSamples = thread->frameCount() * thread->channelCount();
@@ -5697,15 +5792,16 @@
     } else {
         // Insert effects are inserted at the end of mEffects vector as they are processed
         //  after track and auxiliary effects.
-        // Insert effect order:
-        //  if EFFECT_FLAG_INSERT_FIRST or EFFECT_FLAG_INSERT_EXCLUSIVE insert as first insert effect
+        // Insert effect order as a function of indicated preference:
+        //  if EFFECT_FLAG_INSERT_EXCLUSIVE, insert in first position or reject if
+        //  another effect is present
+        //  else if EFFECT_FLAG_INSERT_FIRST, insert in first position or after the
+        //  last effect claiming first position
+        //  else if EFFECT_FLAG_INSERT_LAST, insert in last position or before the
+        //  first effect claiming last position
         //  else if EFFECT_FLAG_INSERT_ANY insert after first or before last
-        //  else insert as last insert effect
-        // Reject insertion if:
-        //  - EFFECT_FLAG_INSERT_EXCLUSIVE and another effect is present
-        //  - an effect with EFFECT_FLAG_INSERT_EXCLUSIVE is present
-        //  - EFFECT_FLAG_INSERT_FIRST or EFFECT_FLAG_INSERT_LAST and an effect with same
-        //  preference is present
+        // Reject insertion if an effect with EFFECT_FLAG_INSERT_EXCLUSIVE is
+        // already present
 
         int size = (int)mEffects.size();
         int idx_insert = size;
@@ -5719,35 +5815,40 @@
             if (iMode == EFFECT_FLAG_TYPE_INSERT) {
                 // check invalid effect chaining combinations
                 if (insertPref == EFFECT_FLAG_INSERT_EXCLUSIVE ||
-                    iPref == EFFECT_FLAG_INSERT_EXCLUSIVE ||
-                    (insertPref != EFFECT_FLAG_INSERT_ANY
-                                && insertPref == iPref)) {
+                    iPref == EFFECT_FLAG_INSERT_EXCLUSIVE) {
+                    LOGW("addEffect() could not insert effect %s: exclusive conflict with %s", desc.name, d.name);
                     return INVALID_OPERATION;
                 }
-                // remember position of first insert effect
+                // remember position of first insert effect and by default
+                // select this as insert position for new effect
                 if (idx_insert == size) {
                     idx_insert = i;
                 }
-                // remember position of insert effect claiming
-                // first place
+                // remember position of last insert effect claiming
+                // first position
                 if (iPref == EFFECT_FLAG_INSERT_FIRST) {
                     idx_insert_first = i;
                 }
-                // remember position of insert effect claiming
-                // last place
-                if (iPref == EFFECT_FLAG_INSERT_LAST) {
+                // remember position of first insert effect claiming
+                // last position
+                if (iPref == EFFECT_FLAG_INSERT_LAST &&
+                    idx_insert_last == -1) {
                     idx_insert_last = i;
                 }
             }
         }
 
-        // modify idx_insert from first place if needed
-        if (idx_insert_first != -1) {
-            idx_insert = idx_insert_first + 1;
-        } else if (idx_insert_last != -1) {
-            idx_insert = idx_insert_last;
-        } else if (insertPref == EFFECT_FLAG_INSERT_LAST) {
-            idx_insert = size;
+        // modify idx_insert from first position if needed
+        if (insertPref == EFFECT_FLAG_INSERT_LAST) {
+            if (idx_insert_last != -1) {
+                idx_insert = idx_insert_last;
+            } else {
+                idx_insert = size;
+            }
+        } else {
+            if (idx_insert_first != -1) {
+                idx_insert = idx_insert_first + 1;
+            }
         }
 
         // always read samples from chain input buffer
@@ -5764,14 +5865,14 @@
         } else {
             effect->setOutBuffer(mInBuffer);
         }
-        status_t status = mEffects.insertAt(effect, idx_insert);
+        mEffects.insertAt(effect, idx_insert);
         // Always give volume control to last effect in chain with volume control capability
         if (((desc.flags & EFFECT_FLAG_VOLUME_MASK) & EFFECT_FLAG_VOLUME_CTRL) &&
                 mVolumeCtrlIdx < idx_insert) {
             mVolumeCtrlIdx = idx_insert;
         }
 
-        LOGV("addEffect() effect %p, added in chain %p at rank %d status %d", effect.get(), this, idx_insert, status);
+        LOGV("addEffect() effect %p, added in chain %p at rank %d", effect.get(), this, idx_insert);
     }
     effect->configure();
     return NO_ERROR;
@@ -5823,6 +5924,14 @@
     }
 }
 
+void AudioFlinger::EffectChain::setMode(uint32_t mode)
+{
+    size_t size = mEffects.size();
+    for (size_t i = 0; i < size; i++) {
+        mEffects[i]->setMode(mode);
+    }
+}
+
 bool AudioFlinger::EffectChain::setVolume(uint32_t *left, uint32_t *right)
 {
     uint32_t newLeft = *left;
diff --git a/libs/audioflinger/AudioFlinger.h b/libs/audioflinger/AudioFlinger.h
index e543334..42dca4c 100644
--- a/libs/audioflinger/AudioFlinger.h
+++ b/libs/audioflinger/AudioFlinger.h
@@ -149,7 +149,7 @@
 
     virtual status_t queryNumberEffects(uint32_t *numEffects);
 
-    virtual status_t queryNextEffect(effect_descriptor_t *descriptor);
+    virtual status_t queryEffect(uint32_t index, effect_descriptor_t *descriptor);
 
     virtual status_t getEffectDescriptor(effect_uuid_t *pUuid, effect_descriptor_t *descriptor);
 
@@ -163,6 +163,9 @@
                         int *id,
                         int *enabled);
 
+            status_t registerEffectResource_l(effect_descriptor_t *desc);
+            void     unregisterEffectResource_l(effect_descriptor_t *desc);
+
     enum hardware_call_state {
         AUDIO_HW_IDLE = 0,
         AUDIO_HW_INIT,
@@ -200,6 +203,8 @@
                                 Parcel* reply,
                                 uint32_t flags);
 
+                uint32_t    getMode() { return mMode; }
+
 private:
                             AudioFlinger();
     virtual                 ~AudioFlinger();
@@ -601,6 +606,8 @@
                                         effect_descriptor_t *desc,
                                         int *enabled,
                                         status_t *status);
+                    void disconnectEffect(const sp< EffectModule>& effect,
+                                          const wp<EffectHandle>& handle);
 
                     bool hasAudioSession(int sessionId);
                     sp<EffectChain> getEffectChain(int sessionId);
@@ -614,6 +621,7 @@
                     void detachAuxEffect_l(int effectId);
                     status_t attachAuxEffect(const sp<AudioFlinger::PlaybackThread::Track> track, int EffectId);
                     status_t attachAuxEffect_l(const sp<AudioFlinger::PlaybackThread::Track> track, int EffectId);
+                    void setMode(uint32_t mode);
 
         struct  stream_type_t {
             stream_type_t()
@@ -930,9 +938,11 @@
         size_t removeHandle (const wp<EffectHandle>& handle);
 
         effect_descriptor_t& desc() { return mDescriptor; }
+        wp<EffectChain>&     chain() { return mChain; }
 
         status_t         setDevice(uint32_t device);
         status_t         setVolume(uint32_t *left, uint32_t *right, bool controller);
+        status_t         setMode(uint32_t mode);
 
         status_t         dump(int fd, const Vector<String16>& args);
 
@@ -944,6 +954,14 @@
         status_t start();
         status_t stop();
 
+        // update this table when AudioSystem::audio_devices or audio_device_e (in EffectApi.h) are modified
+        static const uint32_t sDeviceConvTable[];
+        static uint32_t deviceAudioSystemToEffectApi(uint32_t device);
+
+        // update this table when AudioSystem::audio_mode or audio_mode_e (in EffectApi.h) are modified
+        static const uint32_t sModeConvTable[];
+        static int modeAudioSystemToEffectApi(uint32_t mode);
+
         Mutex               mLock;      // mutex for process, commands and handles list protection
         wp<ThreadBase>      mThread;    // parent thread
         wp<EffectChain>     mChain;     // parent effect chain
@@ -1042,6 +1060,8 @@
         sp<EffectModule> getVolumeController();
         bool setVolume(uint32_t *left, uint32_t *right);
         void setDevice(uint32_t device);
+        void setMode(uint32_t mode);
+
 
         void setInBuffer(int16_t *buffer, bool ownsBuffer = false) {
             mInBuffer = buffer;
@@ -1104,6 +1124,14 @@
 #ifdef LVMX
                 int mLifeVibesClientPid;
 #endif
+                uint32_t mMode;
+
+                // Maximum CPU load allocated to audio effects in 0.1 MIPS (ARMv5TE, 0 WS memory) units
+                static const uint32_t MAX_EFFECTS_CPU_LOAD = 1000;
+                // Maximum memory allocated to audio effects in KB
+                static const uint32_t MAX_EFFECTS_MEMORY = 512;
+                uint32_t mTotalEffectsCpuLoad; // current CPU load used by effects
+                uint32_t mTotalEffectsMemory;  // current memory used by effects
 };
 
 // ----------------------------------------------------------------------------
diff --git a/libs/surfaceflinger/Android.mk b/libs/surfaceflinger/Android.mk
index b0229c0..0879a66 100644
--- a/libs/surfaceflinger/Android.mk
+++ b/libs/surfaceflinger/Android.mk
@@ -6,7 +6,6 @@
     DisplayHardware/DisplayHardware.cpp \
     DisplayHardware/DisplayHardwareBase.cpp \
     BlurFilter.cpp.arm \
-    GLExtensions.cpp \
     Layer.cpp \
     LayerBase.cpp \
     LayerBuffer.cpp \
diff --git a/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp b/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp
index 2eac0a8..51de1da 100644
--- a/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp
+++ b/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp
@@ -40,8 +40,6 @@
 #include <hardware/overlay.h>
 #include <hardware/gralloc.h>
 
-#include "GLExtensions.h"
-
 using namespace android;
 
 
@@ -75,8 +73,7 @@
 DisplayHardware::DisplayHardware(
         const sp<SurfaceFlinger>& flinger,
         uint32_t dpy)
-    : DisplayHardwareBase(flinger, dpy),
-      mFlags(0)
+    : DisplayHardwareBase(flinger, dpy), mFlags(0)
 {
     init(dpy);
 }
@@ -100,9 +97,6 @@
 {
     mNativeWindow = new FramebufferNativeWindow();
     framebuffer_device_t const * fbDev = mNativeWindow->getDevice();
-    mDpiX = mNativeWindow->xdpi;
-    mDpiY = mNativeWindow->ydpi;
-    mRefreshRate = fbDev->fps;
 
     mOverlayEngine = NULL;
     hw_module_t const* module;
@@ -110,11 +104,6 @@
         overlay_control_open(module, &mOverlayEngine);
     }
 
-    EGLint w, h, dummy;
-    EGLint numConfigs=0;
-    EGLSurface surface;
-    EGLContext context;
-
     // initialize EGL
     EGLint attribs[] = {
             EGL_SURFACE_TYPE,   EGL_WINDOW_BIT,
@@ -132,6 +121,11 @@
         }
     }
 
+    EGLint w, h, dummy;
+    EGLint numConfigs=0;
+    EGLSurface surface;
+    EGLContext context;
+
     // TODO: all the extensions below should be queried through
     // eglGetProcAddress().
 
@@ -150,6 +144,22 @@
     eglGetConfigAttrib(display, config, EGL_BLUE_SIZE,  &b);
     eglGetConfigAttrib(display, config, EGL_ALPHA_SIZE, &a);
 
+    /*
+     * Gather EGL extensions
+     */
+
+    const char* const egl_extensions = eglQueryString(
+            display, EGL_EXTENSIONS);
+    
+    LOGI("EGL informations:");
+    LOGI("# of configs : %d", numConfigs);
+    LOGI("vendor    : %s", eglQueryString(display, EGL_VENDOR));
+    LOGI("version   : %s", eglQueryString(display, EGL_VERSION));
+    LOGI("extensions: %s", egl_extensions);
+    LOGI("Client API: %s", eglQueryString(display, EGL_CLIENT_APIS)?:"Not Supported");
+    LOGI("EGLSurface: %d-%d-%d-%d, config=%p", r, g, b, a, config);
+    
+
     if (mNativeWindow->isUpdateOnDemand()) {
         mFlags |= PARTIAL_UPDATES;
     }
@@ -164,8 +174,6 @@
      */
 
     surface = eglCreateWindowSurface(display, config, mNativeWindow.get(), NULL);
-    eglQuerySurface(display, surface, EGL_WIDTH,  &mWidth);
-    eglQuerySurface(display, surface, EGL_HEIGHT, &mHeight);
 
     if (mFlags & PARTIAL_UPDATES) {
         // if we have partial updates, we definitely don't need to
@@ -179,6 +187,31 @@
             mFlags |= BUFFER_PRESERVED;
         }
     }
+
+    eglQuerySurface(display, surface, EGL_WIDTH,  &mWidth);
+    eglQuerySurface(display, surface, EGL_HEIGHT, &mHeight);
+
+#ifdef EGL_ANDROID_swap_rectangle    
+    if (strstr(egl_extensions, "EGL_ANDROID_swap_rectangle")) {
+        if (eglSetSwapRectangleANDROID(display, surface,
+                0, 0, mWidth, mHeight) == EGL_TRUE) {
+            // This could fail if this extension is not supported by this
+            // specific surface (of config)
+            mFlags |= SWAP_RECTANGLE;
+        }
+    }
+    // when we have the choice between PARTIAL_UPDATES and SWAP_RECTANGLE
+    // choose PARTIAL_UPDATES, which should be more efficient
+    if (mFlags & PARTIAL_UPDATES)
+        mFlags &= ~SWAP_RECTANGLE;
+#endif
+    
+
+    LOGI("flags     : %08x", mFlags);
+    
+    mDpiX = mNativeWindow->xdpi;
+    mDpiY = mNativeWindow->ydpi;
+    mRefreshRate = fbDev->fps; 
     
     /* Read density from build-specific ro.sf.lcd_density property
      * except if it is overridden by qemu.sf.lcd_density.
@@ -201,67 +234,49 @@
     
     context = eglCreateContext(display, config, NULL, NULL);
     
+    /*
+     * Gather OpenGL ES extensions
+     */
+
+    eglMakeCurrent(display, surface, surface, context);
+    const char* const  gl_extensions = (const char*)glGetString(GL_EXTENSIONS);
+    const char* const  gl_renderer = (const char*)glGetString(GL_RENDERER);
+    LOGI("OpenGL informations:");
+    LOGI("vendor    : %s", glGetString(GL_VENDOR));
+    LOGI("renderer  : %s", gl_renderer);
+    LOGI("version   : %s", glGetString(GL_VERSION));
+    LOGI("extensions: %s", gl_extensions);
+
+    glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTextureSize);
+    glGetIntegerv(GL_MAX_VIEWPORT_DIMS, &mMaxViewportDims);
+    LOGI("GL_MAX_TEXTURE_SIZE = %d", mMaxTextureSize);
+    LOGI("GL_MAX_VIEWPORT_DIMS = %d", mMaxViewportDims);
+
+
+    if (strstr(gl_extensions, "GL_ARB_texture_non_power_of_two")) {
+        mFlags |= NPOT_EXTENSION;
+    }
+#ifdef EGL_ANDROID_image_native_buffer
+    if (strstr( gl_extensions, "GL_OES_EGL_image") &&
+        (strstr(egl_extensions, "EGL_KHR_image_base") || 
+                strstr(egl_extensions, "EGL_KHR_image")) &&
+        strstr(egl_extensions, "EGL_ANDROID_image_native_buffer")) {
+        mFlags |= DIRECT_TEXTURE;
+    }
+#else
+#warning "EGL_ANDROID_image_native_buffer not supported"
+#endif
+
+
+    // Unbind the context from this thread
+    eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+
     mDisplay = display;
     mConfig  = config;
     mSurface = surface;
     mContext = context;
     mFormat  = fbDev->format;
     mPageFlipCount = 0;
-
-    /*
-     * Gather OpenGL ES extensions
-     */
-
-    eglMakeCurrent(display, surface, surface, context);
-
-    GLExtensions& extensions(GLExtensions::getInstance());
-    extensions.initWithGLStrings(
-            glGetString(GL_VENDOR),
-            glGetString(GL_RENDERER),
-            glGetString(GL_VERSION),
-            glGetString(GL_EXTENSIONS),
-            eglQueryString(display, EGL_VENDOR),
-            eglQueryString(display, EGL_VERSION),
-            eglQueryString(display, EGL_EXTENSIONS));
-
-    glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTextureSize);
-    glGetIntegerv(GL_MAX_VIEWPORT_DIMS, &mMaxViewportDims);
-
-
-#ifdef EGL_ANDROID_swap_rectangle
-    if (extensions.hasExtension("EGL_ANDROID_swap_rectangle")) {
-        if (eglSetSwapRectangleANDROID(display, surface,
-                0, 0, mWidth, mHeight) == EGL_TRUE) {
-            // This could fail if this extension is not supported by this
-            // specific surface (of config)
-            mFlags |= SWAP_RECTANGLE;
-        }
-    }
-    // when we have the choice between PARTIAL_UPDATES and SWAP_RECTANGLE
-    // choose PARTIAL_UPDATES, which should be more efficient
-    if (mFlags & PARTIAL_UPDATES)
-        mFlags &= ~SWAP_RECTANGLE;
-#endif
-
-    LOGI("EGL informations:");
-    LOGI("# of configs : %d", numConfigs);
-    LOGI("vendor    : %s", extensions.getEglVendor());
-    LOGI("version   : %s", extensions.getEglVersion());
-    LOGI("extensions: %s", extensions.getEglExtension());
-    LOGI("Client API: %s", eglQueryString(display, EGL_CLIENT_APIS)?:"Not Supported");
-    LOGI("EGLSurface: %d-%d-%d-%d, config=%p", r, g, b, a, config);
-
-    LOGI("OpenGL informations:");
-    LOGI("vendor    : %s", extensions.getVendor());
-    LOGI("renderer  : %s", extensions.getRenderer());
-    LOGI("version   : %s", extensions.getVersion());
-    LOGI("extensions: %s", extensions.getExtension());
-    LOGI("GL_MAX_TEXTURE_SIZE = %d", mMaxTextureSize);
-    LOGI("GL_MAX_VIEWPORT_DIMS = %d", mMaxViewportDims);
-    LOGI("flags = %08x", mFlags);
-
-    // Unbind the context from this thread
-    eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
 }
 
 /*
diff --git a/libs/surfaceflinger/DisplayHardware/DisplayHardware.h b/libs/surfaceflinger/DisplayHardware/DisplayHardware.h
index 66bf521..ebd7c42 100644
--- a/libs/surfaceflinger/DisplayHardware/DisplayHardware.h
+++ b/libs/surfaceflinger/DisplayHardware/DisplayHardware.h
@@ -29,8 +29,6 @@
 
 #include <pixelflinger/pixelflinger.h>
 
-#include "GLExtensions.h"
-
 #include "DisplayHardware/DisplayHardwareBase.h"
 
 struct overlay_control_device_t;
@@ -45,11 +43,13 @@
 {
 public:
     enum {
-        COPY_BITS_EXTENSION         = 0x00000008,
-        BUFFER_PRESERVED            = 0x00010000,
-        PARTIAL_UPDATES             = 0x00020000,   // video driver feature
-        SLOW_CONFIG                 = 0x00040000,   // software
-        SWAP_RECTANGLE              = 0x00080000,
+        DIRECT_TEXTURE          = 0x00000002,
+        COPY_BITS_EXTENSION     = 0x00000008,
+        NPOT_EXTENSION          = 0x00000100,
+        BUFFER_PRESERVED        = 0x00010000,
+        PARTIAL_UPDATES         = 0x00020000,   // video driver feature
+        SLOW_CONFIG             = 0x00040000,   // software
+        SWAP_RECTANGLE          = 0x00080000,
     };
 
     DisplayHardware(
diff --git a/libs/surfaceflinger/GLExtensions.cpp b/libs/surfaceflinger/GLExtensions.cpp
deleted file mode 100644
index 7f4f9fc..0000000
--- a/libs/surfaceflinger/GLExtensions.cpp
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <stdint.h>
-
-#include "GLExtensions.h"
-
-namespace android {
-// ---------------------------------------------------------------------------
-
-ANDROID_SINGLETON_STATIC_INSTANCE( GLExtensions )
-
-GLExtensions::GLExtensions()
-    : mHaveTextureExternal(false),
-      mHaveNpot(false),
-      mHaveDirectTexture(false)
-{
-}
-
-void GLExtensions::initWithGLStrings(
-        GLubyte const* vendor,
-        GLubyte const* renderer,
-        GLubyte const* version,
-        GLubyte const* extensions,
-        char const* egl_vendor,
-        char const* egl_version,
-        char const* egl_extensions)
-{
-    mVendor     = (char const*)vendor;
-    mRenderer   = (char const*)renderer;
-    mVersion    = (char const*)version;
-    mExtensions = (char const*)extensions;
-    mEglVendor     = egl_vendor;
-    mEglVersion    = egl_version;
-    mEglExtensions = egl_extensions;
-
-    char const* curr = (char const*)extensions;
-    char const* head = curr;
-    do {
-        head = strchr(curr, ' ');
-        String8 s(curr, head ? head-curr : strlen(curr));
-        if (s.length()) {
-            mExtensionList.add(s);
-        }
-        curr = head+1;
-    } while (head);
-
-    curr = egl_extensions;
-    head = curr;
-    do {
-        head = strchr(curr, ' ');
-        String8 s(curr, head ? head-curr : strlen(curr));
-        if (s.length()) {
-            mExtensionList.add(s);
-        }
-        curr = head+1;
-    } while (head);
-
-#ifdef EGL_ANDROID_image_native_buffer
-    if (hasExtension("GL_OES_EGL_image") &&
-        (hasExtension("EGL_KHR_image_base") || hasExtension("EGL_KHR_image")) &&
-        hasExtension("EGL_ANDROID_image_native_buffer"))
-    {
-        mHaveDirectTexture = true;
-    }
-#else
-#warning "EGL_ANDROID_image_native_buffer not supported"
-#endif
-
-    if (hasExtension("GL_ARB_texture_non_power_of_two")) {
-        mHaveNpot = true;
-    }
-
-    if (hasExtension("GL_OES_texture_external")) {
-        mHaveTextureExternal = true;
-    } else if (strstr(mRenderer.string(), "Adreno")) {
-        // hack for Adreno 200
-        mHaveTextureExternal = true;
-    }
-}
-
-bool GLExtensions::hasExtension(char const* extension) const
-{
-    const String8 s(extension);
-    return mExtensionList.indexOf(s) >= 0;
-}
-
-char const* GLExtensions::getVendor() const {
-    return mVendor.string();
-}
-
-char const* GLExtensions::getRenderer() const {
-    return mRenderer.string();
-}
-
-char const* GLExtensions::getVersion() const {
-    return mVersion.string();
-}
-
-char const* GLExtensions::getExtension() const {
-    return mExtensions.string();
-}
-
-char const* GLExtensions::getEglVendor() const {
-    return mEglVendor.string();
-}
-
-char const* GLExtensions::getEglVersion() const {
-    return mEglVersion.string();
-}
-
-char const* GLExtensions::getEglExtension() const {
-    return mEglExtensions.string();
-}
-
-
-// ---------------------------------------------------------------------------
-}; // namespace android
diff --git a/libs/surfaceflinger/GLExtensions.h b/libs/surfaceflinger/GLExtensions.h
deleted file mode 100644
index bbb284e..0000000
--- a/libs/surfaceflinger/GLExtensions.h
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_SF_GLEXTENSION_H
-#define ANDROID_SF_GLEXTENSION_H
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <utils/String8.h>
-#include <utils/SortedVector.h>
-#include <utils/Singleton.h>
-
-#include <EGL/egl.h>
-#include <EGL/eglext.h>
-#include <GLES/gl.h>
-#include <GLES/glext.h>
-
-namespace android {
-// ---------------------------------------------------------------------------
-
-class GLExtensions : public Singleton<GLExtensions>
-{
-    friend class Singleton<GLExtensions>;
-
-    bool mHaveTextureExternal   : 1;
-    bool mHaveNpot              : 1;
-    bool mHaveDirectTexture     : 1;
-
-    String8 mVendor;
-    String8 mRenderer;
-    String8 mVersion;
-    String8 mExtensions;
-    String8 mEglVendor;
-    String8 mEglVersion;
-    String8 mEglExtensions;
-    SortedVector<String8> mExtensionList;
-
-    GLExtensions(const GLExtensions&);
-    GLExtensions& operator = (const GLExtensions&);
-
-protected:
-    GLExtensions();
-
-public:
-    inline bool haveTextureExternal() const {
-        return mHaveTextureExternal;
-    }
-    inline bool haveNpot() const {
-        return mHaveNpot;
-    }
-    inline bool haveDirectTexture() const {
-        return mHaveDirectTexture;
-    }
-
-    void initWithGLStrings(
-            GLubyte const* vendor,
-            GLubyte const* renderer,
-            GLubyte const* version,
-            GLubyte const* extensions,
-            char const* egl_vendor,
-            char const* egl_version,
-            char const* egl_extensions);
-
-    char const* getVendor() const;
-    char const* getRenderer() const;
-    char const* getVersion() const;
-    char const* getExtension() const;
-
-    char const* getEglVendor() const;
-    char const* getEglVersion() const;
-    char const* getEglExtension() const;
-
-    bool hasExtension(char const* extension) const;
-};
-
-
-// ---------------------------------------------------------------------------
-}; // namespace android
-
-#endif // ANDROID_SF_GLEXTENSION_H
diff --git a/libs/surfaceflinger/Layer.cpp b/libs/surfaceflinger/Layer.cpp
index 758da4e..e606f71 100644
--- a/libs/surfaceflinger/Layer.cpp
+++ b/libs/surfaceflinger/Layer.cpp
@@ -31,7 +31,6 @@
 #include <surfaceflinger/Surface.h>
 
 #include "clz.h"
-#include "GLExtensions.h"
 #include "Layer.h"
 #include "SurfaceFlinger.h"
 #include "DisplayHardware/DisplayHardware.h"
@@ -51,11 +50,10 @@
 Layer::Layer(SurfaceFlinger* flinger,
         DisplayID display, const sp<Client>& client)
     :   LayerBaseClient(flinger, display, client),
-        mGLExtensions(GLExtensions::getInstance()),
         mNeedsBlending(true),
         mNeedsDithering(false),
         mSecure(false),
-        mTextureManager(),
+        mTextureManager(mFlags),
         mBufferManager(mTextureManager),
         mWidth(0), mHeight(0), mFixedSize(false)
 {
@@ -187,13 +185,17 @@
         return;
     }
 
-    if (mGLExtensions.haveDirectTexture()) {
+#ifdef EGL_ANDROID_image_native_buffer
+    if (mFlags & DisplayHardware::DIRECT_TEXTURE) {
         EGLDisplay dpy(mFlinger->graphicPlane(0).getEGLDisplay());
         if (mBufferManager.initEglImage(dpy, buffer) != NO_ERROR) {
             // not sure what we can do here...
+            mFlags &= ~DisplayHardware::DIRECT_TEXTURE;
             goto slowpath;
         }
-    } else {
+    } else
+#endif
+    {
 slowpath:
         GGLSurface t;
         status_t res = buffer->lock(&t, GRALLOC_USAGE_SW_READ_OFTEN);
@@ -784,24 +786,19 @@
     status_t err = NO_INIT;
     ssize_t index = mActiveBuffer;
     if (index >= 0) {
-        if (!mFailover) {
-            Image& texture(mBufferData[index].texture);
-            err = mTextureManager.initEglImage(&texture, dpy, buffer);
-            // if EGLImage fails, we switch to regular texture mode, and we
-            // free all resources associated with using EGLImages.
-            if (err == NO_ERROR) {
-                mFailover = false;
-                destroyTexture(&mFailoverTexture, dpy);
-            } else {
-                mFailover = true;
-                const size_t num = mNumBuffers;
-                for (size_t i=0 ; i<num ; i++) {
-                    destroyTexture(&mBufferData[i].texture, dpy);
-                }
-            }
+        Image& texture(mBufferData[index].texture);
+        err = mTextureManager.initEglImage(&texture, dpy, buffer);
+        // if EGLImage fails, we switch to regular texture mode, and we
+        // free all resources associated with using EGLImages.
+        if (err == NO_ERROR) {
+            mFailover = false;
+            destroyTexture(&mFailoverTexture, dpy);
         } else {
-            // we failed once, don't try again
-            err = BAD_VALUE;
+            mFailover = true;
+            const size_t num = mNumBuffers;
+            for (size_t i=0 ; i<num ; i++) {
+                destroyTexture(&mBufferData[i].texture, dpy);
+            }
         }
     }
     return err;
diff --git a/libs/surfaceflinger/Layer.h b/libs/surfaceflinger/Layer.h
index e1d283b..dcb27a0 100644
--- a/libs/surfaceflinger/Layer.h
+++ b/libs/surfaceflinger/Layer.h
@@ -37,10 +37,9 @@
 
 // ---------------------------------------------------------------------------
 
-class FreezeLock;
 class Client;
-class GLExtensions;
 class UserClient;
+class FreezeLock;
 
 // ---------------------------------------------------------------------------
 
@@ -207,7 +206,6 @@
     // constants
     sp<Surface> mSurface;
     PixelFormat mFormat;
-    const GLExtensions& mGLExtensions;
     bool mNeedsBlending;
     bool mNeedsDithering;
 
diff --git a/libs/surfaceflinger/LayerBlur.cpp b/libs/surfaceflinger/LayerBlur.cpp
index 64a43c7..c1c440b 100644
--- a/libs/surfaceflinger/LayerBlur.cpp
+++ b/libs/surfaceflinger/LayerBlur.cpp
@@ -147,9 +147,7 @@
     Region::const_iterator const end = clip.end();
     if (it != end) {
 #if defined(GL_OES_texture_external)
-        if (GLExtensions::getInstance().haveTextureExternal()) {
-            glDisable(GL_TEXTURE_EXTERNAL_OES);
-        }
+        glDisable(GL_TEXTURE_EXTERNAL_OES);
 #endif
         glEnable(GL_TEXTURE_2D);
         glBindTexture(GL_TEXTURE_2D, mTextureName);
@@ -183,7 +181,7 @@
             bl.data = (GGLubyte*)pixels;            
             blurFilter(&bl, 8, 2);
 
-            if (GLExtensions::getInstance().haveNpot()) {
+            if (mFlags & (DisplayHardware::NPOT_EXTENSION)) {
                 glTexImage2D(GL_TEXTURE_2D, 0, mReadFormat, w, h, 0,
                         mReadFormat, mReadType, pixels);
                 mWidthScale  = 1.0f / w;
diff --git a/libs/surfaceflinger/LayerBuffer.cpp b/libs/surfaceflinger/LayerBuffer.cpp
index 5f83636..732a4ec 100644
--- a/libs/surfaceflinger/LayerBuffer.cpp
+++ b/libs/surfaceflinger/LayerBuffer.cpp
@@ -315,7 +315,8 @@
 
 LayerBuffer::BufferSource::BufferSource(LayerBuffer& layer,
         const ISurface::BufferHeap& buffers)
-    : Source(layer), mStatus(NO_ERROR), mBufferSize(0)
+    : Source(layer), mStatus(NO_ERROR), mBufferSize(0),
+      mTextureManager(layer.mFlags)
 {
     if (buffers.heap == NULL) {
         // this is allowed, but in this case, it is illegal to receive
@@ -373,11 +374,11 @@
 
     if (mTexture.name != -1U) {
         // GL textures can only be destroyed from the GL thread
-        getFlinger()->mEventQueue.postMessage(
-                new MessageDestroyTexture(getFlinger(), mTexture.name) );
+        mLayer.mFlinger->mEventQueue.postMessage(
+                new MessageDestroyTexture(mLayer.mFlinger.get(), mTexture.name) );
     }
     if (mTexture.image != EGL_NO_IMAGE_KHR) {
-        EGLDisplay dpy(getFlinger()->graphicPlane(0).getEGLDisplay());
+        EGLDisplay dpy(mLayer.mFlinger->graphicPlane(0).getEGLDisplay());
         eglDestroyImageKHR(dpy, mTexture.image);
     }
 }
@@ -443,7 +444,7 @@
     const Rect transformedBounds(mLayer.getTransformedBounds());
 
 #if defined(EGL_ANDROID_image_native_buffer)
-    if (GLExtensions::getInstance().haveDirectTexture()) {
+    if (mLayer.mFlags & DisplayHardware::DIRECT_TEXTURE) {
         err = INVALID_OPERATION;
         if (ourBuffer->supportsCopybit()) {
             copybit_device_t* copybit = mLayer.mBlitEngine;
@@ -548,7 +549,7 @@
         dst.crop.r = w;
         dst.crop.b = h;
 
-        EGLDisplay dpy(getFlinger()->graphicPlane(0).getEGLDisplay());
+        EGLDisplay dpy(mLayer.mFlinger->graphicPlane(0).getEGLDisplay());
         err = mTextureManager.initEglImage(&mTexture, dpy, buffer);
     }
 
@@ -558,7 +559,7 @@
 void LayerBuffer::BufferSource::clearTempBufferImage() const
 {
     // delete the image
-    EGLDisplay dpy(getFlinger()->graphicPlane(0).getEGLDisplay());
+    EGLDisplay dpy(mLayer.mFlinger->graphicPlane(0).getEGLDisplay());
     eglDestroyImageKHR(dpy, mTexture.image);
 
     // and the associated texture (recreate a name)
@@ -575,7 +576,7 @@
     : Source(layer), mVisibilityChanged(false),
     mOverlay(0), mOverlayHandle(0), mOverlayDevice(0), mOrientation(orientation)
 {
-    overlay_control_device_t* overlay_dev = getFlinger()->getOverlayEngine();
+    overlay_control_device_t* overlay_dev = mLayer.mFlinger->getOverlayEngine();
     if (overlay_dev == NULL) {
         // overlays not supported
         return;
@@ -606,7 +607,7 @@
 
     *overlayRef = new OverlayRef(mOverlayHandle, channel,
             mWidth, mHeight, mFormat, mWidthStride, mHeightStride);
-    getFlinger()->signalEvent();
+    mLayer.mFlinger->signalEvent();
 }
 
 LayerBuffer::OverlaySource::~OverlaySource()
diff --git a/libs/surfaceflinger/LayerBuffer.h b/libs/surfaceflinger/LayerBuffer.h
index 1c0bf83..413b8a4 100644
--- a/libs/surfaceflinger/LayerBuffer.h
+++ b/libs/surfaceflinger/LayerBuffer.h
@@ -47,7 +47,6 @@
         virtual void postBuffer(ssize_t offset);
         virtual void unregisterBuffers();
         virtual void destroy() { }
-        SurfaceFlinger* getFlinger() const { return mLayer.mFlinger.get(); }
     protected:
         LayerBuffer& mLayer;
     };
diff --git a/libs/surfaceflinger/LayerDim.cpp b/libs/surfaceflinger/LayerDim.cpp
index c13b4b3..906a583 100644
--- a/libs/surfaceflinger/LayerDim.cpp
+++ b/libs/surfaceflinger/LayerDim.cpp
@@ -112,17 +112,15 @@
     Region::const_iterator const end = clip.end();
     if (s.alpha>0 && (it != end)) {
         const DisplayHardware& hw(graphicPlane(0).displayHardware());
-        const GLfloat alpha = s.alpha/255.0f;
+        const GGLfixed alpha = (s.alpha << 16)/255;
         const uint32_t fbHeight = hw.getHeight();
         glDisable(GL_DITHER);
         glEnable(GL_BLEND);
         glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
-        glColor4f(0, 0, 0, alpha);
-
+        glColor4x(0, 0, 0, alpha);
+        
 #if defined(GL_OES_texture_external)
-        if (GLExtensions::getInstance().haveTextureExternal()) {
-            glDisable(GL_TEXTURE_EXTERNAL_OES);
-        }
+        glDisable(GL_TEXTURE_EXTERNAL_OES);
 #endif
 #if defined(DIM_WITH_TEXTURE) && defined(EGL_ANDROID_image_native_buffer)
         if (sUseTexture) {
diff --git a/libs/surfaceflinger/SurfaceFlinger.cpp b/libs/surfaceflinger/SurfaceFlinger.cpp
index 23efd16..96a5411 100644
--- a/libs/surfaceflinger/SurfaceFlinger.cpp
+++ b/libs/surfaceflinger/SurfaceFlinger.cpp
@@ -44,7 +44,6 @@
 #include <GLES/gl.h>
 
 #include "clz.h"
-#include "GLExtensions.h"
 #include "Layer.h"
 #include "LayerBlur.h"
 #include "LayerBuffer.h"
@@ -994,9 +993,7 @@
         glTexCoordPointer(2, GL_SHORT, 0, tcoords);
         glEnableClientState(GL_TEXTURE_COORD_ARRAY);
 #if defined(GL_OES_texture_external)
-        if (GLExtensions::getInstance().haveTextureExternal()) {
-            glDisable(GL_TEXTURE_EXTERNAL_OES);
-        }
+        glDisable(GL_TEXTURE_EXTERNAL_OES);
 #endif
         glEnable(GL_TEXTURE_2D);
         glBindTexture(GL_TEXTURE_2D, mWormholeTexName);
diff --git a/libs/surfaceflinger/TextureManager.cpp b/libs/surfaceflinger/TextureManager.cpp
index e4dd42f..d9bdc6a 100644
--- a/libs/surfaceflinger/TextureManager.cpp
+++ b/libs/surfaceflinger/TextureManager.cpp
@@ -30,15 +30,14 @@
 
 #include "clz.h"
 #include "DisplayHardware/DisplayHardware.h"
-#include "GLExtensions.h"
 #include "TextureManager.h"
 
 namespace android {
 
 // ---------------------------------------------------------------------------
 
-TextureManager::TextureManager()
-    : mGLExtensions(GLExtensions::getInstance())
+TextureManager::TextureManager(uint32_t flags)
+    : mFlags(flags)
 {
 }
 
@@ -86,11 +85,9 @@
 
     GLenum target = GL_TEXTURE_2D;
 #if defined(GL_OES_texture_external)
-    if (GLExtensions::getInstance().haveTextureExternal()) {
-        if (format && isSupportedYuvFormat(format)) {
-            target = GL_TEXTURE_EXTERNAL_OES;
-            pImage->target = Texture::TEXTURE_EXTERNAL;
-        }
+    if (format && isSupportedYuvFormat(format)) {
+        target = GL_TEXTURE_EXTERNAL_OES;
+        pImage->target = Texture::TEXTURE_EXTERNAL;
     }
 #endif
 
@@ -211,7 +208,7 @@
     /*
      * round to POT if needed
      */
-    if (!mGLExtensions.haveNpot()) {
+    if (!(mFlags & DisplayHardware::NPOT_EXTENSION)) {
         texture->NPOTAdjust = true;
     }
 
@@ -297,19 +294,14 @@
 void TextureManager::activateTexture(const Texture& texture, bool filter)
 {
     const GLenum target = getTextureTarget(&texture);
-    if (target == Texture::TEXTURE_2D) {
-        glBindTexture(GL_TEXTURE_2D, texture.name);
-        glEnable(GL_TEXTURE_2D);
+
+    glBindTexture(target, texture.name);
+    glEnable(target);
+
 #if defined(GL_OES_texture_external)
-        if (GLExtensions::getInstance().haveTextureExternal()) {
-            glDisable(GL_TEXTURE_EXTERNAL_OES);
-        }
-#endif
-    }
-#if defined(GL_OES_texture_external)
-    else {
-        glBindTexture(GL_TEXTURE_EXTERNAL_OES, texture.name);
-        glEnable(GL_TEXTURE_EXTERNAL_OES);
+    if (texture.target == Texture::TEXTURE_2D) {
+        glDisable(GL_TEXTURE_EXTERNAL_OES);
+    } else {
         glDisable(GL_TEXTURE_2D);
     }
 #endif
@@ -327,9 +319,7 @@
 {
     glDisable(GL_TEXTURE_2D);
 #if defined(GL_OES_texture_external)
-    if (GLExtensions::getInstance().haveTextureExternal()) {
-        glDisable(GL_TEXTURE_EXTERNAL_OES);
-    }
+    glDisable(GL_TEXTURE_EXTERNAL_OES);
 #endif
 }
 
diff --git a/libs/surfaceflinger/TextureManager.h b/libs/surfaceflinger/TextureManager.h
index c7c14e7..1f7fe3f 100644
--- a/libs/surfaceflinger/TextureManager.h
+++ b/libs/surfaceflinger/TextureManager.h
@@ -32,7 +32,6 @@
 
 // ---------------------------------------------------------------------------
 
-class GLExtensions;
 class GraphicBuffer;
 
 // ---------------------------------------------------------------------------
@@ -62,7 +61,7 @@
 // ---------------------------------------------------------------------------
 
 class TextureManager {
-    const GLExtensions& mGLExtensions;
+    uint32_t mFlags;
     static status_t initTexture(Image* texture, int32_t format);
     static status_t initTexture(Texture* texture);
     static bool isSupportedYuvFormat(int format);
@@ -70,7 +69,7 @@
     static GLenum getTextureTarget(const Image* pImage);
 public:
 
-    TextureManager();
+    TextureManager(uint32_t flags);
 
     // load bitmap data into the active buffer
     status_t loadTexture(Texture* texture,