Merge "More native input dispatch work." into gingerbread
diff --git a/include/ui/InputTransport.h b/include/ui/InputTransport.h
index 2dfe2a8..11714d5 100644
--- a/include/ui/InputTransport.h
+++ b/include/ui/InputTransport.h
@@ -33,6 +33,7 @@
 #include <semaphore.h>
 #include <ui/Input.h>
 #include <utils/Errors.h>
+#include <utils/PollLoop.h>
 #include <utils/Timers.h>
 #include <utils/RefBase.h>
 #include <utils/String8.h>
@@ -345,11 +346,15 @@
     
     android::status_t consume(android::InputEvent** event);
     
+    void setPollLoop(const android::sp<android::PollLoop>& pollLoop) { mPollLoop = pollLoop; }
+    const android::sp<android::PollLoop> getPollLoop() const { return mPollLoop; }
+    
     virtual void doDefaultKey(android::KeyEvent* keyEvent) = 0;
     
 private:
     android::InputConsumer mConsumer;
     android::PreallocatedInputEventFactory mInputEventFactory;
+    android::sp<android::PollLoop> mPollLoop;
 };
 
 #endif // _UI_INPUT_TRANSPORT_H
diff --git a/include/utils/PollLoop.h b/include/utils/PollLoop.h
index a95fb17..b3651ca 100644
--- a/include/utils/PollLoop.h
+++ b/include/utils/PollLoop.h
@@ -22,12 +22,22 @@
 
 #include <sys/poll.h>
 
+#include <android/looper.h>
+
+struct ALooper : public android::RefBase {
+protected:
+    virtual ~ALooper() { }
+
+public:
+    ALooper() { }
+};
+
 namespace android {
 
 /**
  * A basic file descriptor polling loop based on poll() with callbacks.
  */
-class PollLoop : public RefBase {
+class PollLoop : public ALooper {
 protected:
     virtual ~PollLoop();
 
@@ -83,6 +93,11 @@
     void setCallback(int fd, int events, Callback callback, void* data = NULL);
 
     /**
+     * Like setCallback(), but for the NDK callback function.
+     */
+    void setLooperCallback(int fd, int events, ALooper_callbackFunc* callback, void* data);
+    
+    /**
      * Removes the callback for a file descriptor, if one exists.
      *
      * When this method returns, it is safe to close the file descriptor since the poll loop
@@ -100,9 +115,22 @@
      */
     bool removeCallback(int fd);
 
+    /**
+     * Set the given PollLoop to be associated with the
+     * calling thread.  There must be a 1:1 relationship between
+     * PollLoop and thread.
+     */
+    static void setForThread(const sp<PollLoop>& pollLoop);
+    
+    /**
+     * Return the PollLoop associated with the calling thread.
+     */
+    static sp<PollLoop> getForThread();
+    
 private:
     struct RequestedCallback {
         Callback callback;
+        ALooper_callbackFunc* looperCallback;
         void* data;
     };
 
@@ -110,6 +138,7 @@
         int fd;
         int events;
         Callback callback;
+        ALooper_callbackFunc* looperCallback;
         void* data;
     };
 
@@ -130,8 +159,11 @@
     void openWakePipe();
     void closeWakePipe();
 
+    void setCallbackCommon(int fd, int events, Callback callback,
+            ALooper_callbackFunc* looperCallback, void* data);
     ssize_t getRequestIndexLocked(int fd);
     void wakeAndLock();
+    static void threadDestructor(void *st);
 };
 
 } // namespace android
diff --git a/libs/audioflinger/AudioFlinger.cpp b/libs/audioflinger/AudioFlinger.cpp
index 48c04a6..e6f46ce 100644
--- a/libs/audioflinger/AudioFlinger.cpp
+++ b/libs/audioflinger/AudioFlinger.cpp
@@ -17,7 +17,8 @@
 
 
 #define LOG_TAG "AudioFlinger"
-//#define LOG_NDEBUG 0
+//
+#define LOG_NDEBUG 0
 
 #include <math.h>
 #include <signal.h>
@@ -52,6 +53,7 @@
 #endif
 
 #include <media/EffectsFactoryApi.h>
+#include <media/EffectVisualizerApi.h>
 
 // ----------------------------------------------------------------------------
 // the sim build doesn't have gettid
@@ -4498,6 +4500,11 @@
     return EffectGetDescriptor(pUuid, descriptor);
 }
 
+
+// this UUID must match the one defined in media/libeffects/EffectVisualizer.cpp
+static const effect_uuid_t VISUALIZATION_UUID_ =
+    {0xd069d9e0, 0x8329, 0x11df, 0x9168, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}};
+
 sp<IEffect> AudioFlinger::createEffect(pid_t pid,
         effect_descriptor_t *pDesc,
         const sp<IEffectClient>& effectClient,
@@ -4525,6 +4532,15 @@
     {
         Mutex::Autolock _l(mLock);
 
+        // check recording permission for visualizer
+        if (memcmp(&pDesc->type, SL_IID_VISUALIZATION, sizeof(effect_uuid_t)) == 0 ||
+            memcmp(&pDesc->uuid, &VISUALIZATION_UUID_, sizeof(effect_uuid_t)) == 0) {
+            if (!recordingAllowed()) {
+                lStatus = PERMISSION_DENIED;
+                goto Exit;
+            }
+        }
+
         if (!EffectIsNullUuid(&pDesc->uuid)) {
             // if uuid is specified, request effect descriptor
             lStatus = EffectGetDescriptor(&pDesc->uuid, &desc);
@@ -5089,7 +5105,7 @@
         if (mState != ACTIVE) {
             switch (mState) {
             case RESET:
-                reset();
+                reset_l();
                 mState = STARTING;
                 // clear auxiliary effect input buffer for next accumulation
                 if ((mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) {
@@ -5097,14 +5113,14 @@
                 }
                 return;
             case STARTING:
-                start();
+                start_l();
                 mState = ACTIVE;
                 break;
             case STOPPING:
                 mState = STOPPED;
                 break;
             case STOPPED:
-                stop();
+                stop_l();
                 mState = IDLE;
                 return;
             }
@@ -5132,7 +5148,7 @@
     }
 }
 
-void AudioFlinger::EffectModule::reset()
+void AudioFlinger::EffectModule::reset_l()
 {
     if (mEffectInterface == NULL) {
         return;
@@ -5205,6 +5221,7 @@
 
 status_t AudioFlinger::EffectModule::init()
 {
+    Mutex::Autolock _l(mLock);
     if (mEffectInterface == NULL) {
         return NO_INIT;
     }
@@ -5217,7 +5234,7 @@
     return status;
 }
 
-status_t AudioFlinger::EffectModule::start()
+status_t AudioFlinger::EffectModule::start_l()
 {
     if (mEffectInterface == NULL) {
         return NO_INIT;
@@ -5231,7 +5248,7 @@
     return status;
 }
 
-status_t AudioFlinger::EffectModule::stop()
+status_t AudioFlinger::EffectModule::stop_l()
 {
     if (mEffectInterface == NULL) {
         return NO_INIT;
@@ -5247,7 +5264,8 @@
 
 status_t AudioFlinger::EffectModule::command(int cmdCode, int cmdSize, void *pCmdData, int *replySize, void *pReplyData)
 {
-    LOGV("command(), cmdCode: %d, mEffectInterface: %p", cmdCode, mEffectInterface);
+    Mutex::Autolock _l(mLock);
+//    LOGV("command(), cmdCode: %d, mEffectInterface: %p", cmdCode, mEffectInterface);
 
     if (mEffectInterface == NULL) {
         return NO_INIT;
@@ -5255,7 +5273,6 @@
     status_t status = (*mEffectInterface)->command(mEffectInterface, cmdCode, cmdSize, pCmdData, replySize, pReplyData);
     if (cmdCode != EFFECT_CMD_GET_PARAM && status == NO_ERROR) {
         int size = (replySize == NULL) ? 0 : *replySize;
-        Mutex::Autolock _l(mLock);
         for (size_t i = 1; i < mHandles.size(); i++) {
             sp<EffectHandle> h = mHandles[i].promote();
             if (h != 0) {
@@ -5322,6 +5339,7 @@
 
 status_t AudioFlinger::EffectModule::setVolume(uint32_t *left, uint32_t *right, bool controller)
 {
+    Mutex::Autolock _l(mLock);
     status_t status = NO_ERROR;
 
     // Send volume indication if EFFECT_FLAG_VOLUME_IND is set and read back altered volume
@@ -5347,6 +5365,7 @@
 
 status_t AudioFlinger::EffectModule::setDevice(uint32_t device)
 {
+    Mutex::Autolock _l(mLock);
     status_t status = NO_ERROR;
     if ((mDescriptor.flags & EFFECT_FLAG_DEVICE_MASK) == EFFECT_FLAG_DEVICE_IND) {
         // convert device bit field from AudioSystem to EffectApi format.
@@ -5366,6 +5385,7 @@
 
 status_t AudioFlinger::EffectModule::setMode(uint32_t mode)
 {
+    Mutex::Autolock _l(mLock);
     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.
@@ -5586,7 +5606,7 @@
 
 status_t AudioFlinger::EffectHandle::command(int cmdCode, int cmdSize, void *pCmdData, int *replySize, void *pReplyData)
 {
-    LOGV("command(), cmdCode: %d, mHasControl: %d, mEffect: %p", cmdCode, mHasControl, (mEffect == 0) ? 0 : mEffect.get());
+//    LOGV("command(), cmdCode: %d, mHasControl: %d, mEffect: %p", cmdCode, mHasControl, (mEffect == 0) ? 0 : mEffect.get());
 
     // only get parameter command is permitted for applications not controlling the effect
     if (!mHasControl && cmdCode != EFFECT_CMD_GET_PARAM) {
diff --git a/libs/audioflinger/AudioFlinger.h b/libs/audioflinger/AudioFlinger.h
index 42dca4c..ec3d7f1 100644
--- a/libs/audioflinger/AudioFlinger.h
+++ b/libs/audioflinger/AudioFlinger.h
@@ -916,7 +916,7 @@
         void process();
         status_t command(int cmdCode, int cmdSize, void *pCmdData, int *replySize, void *pReplyData);
 
-        void reset();
+        void reset_l();
         status_t configure();
         status_t init();
         uint32_t state() {
@@ -951,8 +951,8 @@
         EffectModule(const EffectModule&);
         EffectModule& operator = (const EffectModule&);
 
-        status_t start();
-        status_t stop();
+        status_t start_l();
+        status_t stop_l();
 
         // update this table when AudioSystem::audio_devices or audio_device_e (in EffectApi.h) are modified
         static const uint32_t sDeviceConvTable[];
diff --git a/libs/utils/PollLoop.cpp b/libs/utils/PollLoop.cpp
index 20a4d13..58fe141 100644
--- a/libs/utils/PollLoop.cpp
+++ b/libs/utils/PollLoop.cpp
@@ -21,6 +21,10 @@
 
 namespace android {
 
+static pthread_mutex_t gTLSMutex = PTHREAD_MUTEX_INITIALIZER;
+static bool gHaveTLS = false;
+static pthread_key_t gTLS = 0;
+
 PollLoop::PollLoop() :
         mPolling(false), mWaiters(0) {
     openWakePipe();
@@ -30,6 +34,41 @@
     closeWakePipe();
 }
 
+void PollLoop::threadDestructor(void *st) {
+    PollLoop* const self = static_cast<PollLoop*>(st);
+    if (self != NULL) {
+        self->decStrong((void*)threadDestructor);
+    }
+}
+
+void PollLoop::setForThread(const sp<PollLoop>& pollLoop) {
+    sp<PollLoop> old = getForThread();
+    
+    if (pollLoop != NULL) {
+        pollLoop->incStrong((void*)threadDestructor);
+    }
+    
+    pthread_setspecific(gTLS, pollLoop.get());
+    
+    if (old != NULL) {
+        old->decStrong((void*)threadDestructor);
+    }
+}
+    
+sp<PollLoop> PollLoop::getForThread() {
+    if (!gHaveTLS) {
+        pthread_mutex_lock(&gTLSMutex);
+        if (pthread_key_create(&gTLS, threadDestructor) != 0) {
+            pthread_mutex_unlock(&gTLSMutex);
+            return NULL;
+        }
+        gHaveTLS = true;
+        pthread_mutex_unlock(&gTLSMutex);
+    }
+    
+    return (PollLoop*)pthread_getspecific(gTLS);
+}
+
 void PollLoop::openWakePipe() {
     int wakeFds[2];
     int result = pipe(wakeFds);
@@ -54,6 +93,7 @@
 
     RequestedCallback requestedCallback;
     requestedCallback.callback = NULL;
+    requestedCallback.looperCallback = NULL;
     requestedCallback.data = NULL;
     mRequestedCallbacks.insertAt(requestedCallback, 0);
 }
@@ -123,12 +163,14 @@
         if (revents) {
             const RequestedCallback& requestedCallback = mRequestedCallbacks.itemAt(i);
             Callback callback = requestedCallback.callback;
+            ALooper_callbackFunc* looperCallback = requestedCallback.looperCallback;
 
-            if (callback) {
+            if (callback || looperCallback) {
                 PendingCallback pendingCallback;
                 pendingCallback.fd = requestedFd.fd;
                 pendingCallback.events = requestedFd.revents;
                 pendingCallback.callback = callback;
+                pendingCallback.looperCallback = looperCallback;
                 pendingCallback.data = requestedCallback.data;
                 mPendingCallbacks.push(pendingCallback);
             } else {
@@ -172,8 +214,14 @@
             LOGD("%p ~ pollOnce - invoking callback for fd %d", this, pendingCallback.fd);
 #endif
 
-            bool keep = pendingCallback.callback(pendingCallback.fd, pendingCallback.events,
-                    pendingCallback.data);
+            bool keep = true;
+            if (pendingCallback.callback != NULL) {
+                keep = pendingCallback.callback(pendingCallback.fd, pendingCallback.events,
+                        pendingCallback.data);
+            } else {
+                keep = pendingCallback.looperCallback(pendingCallback.fd, pendingCallback.events,
+                        pendingCallback.data) != 0;
+            }
             if (! keep) {
                 removeCallback(pendingCallback.fd);
             }
@@ -200,11 +248,22 @@
 }
 
 void PollLoop::setCallback(int fd, int events, Callback callback, void* data) {
+    setCallbackCommon(fd, events, callback, NULL, data);
+}
+
+void PollLoop::setLooperCallback(int fd, int events, ALooper_callbackFunc* callback,
+        void* data) {
+    setCallbackCommon(fd, events, NULL, callback, data);
+}
+
+void PollLoop::setCallbackCommon(int fd, int events, Callback callback,
+        ALooper_callbackFunc* looperCallback, void* data) {
+
 #if DEBUG_CALLBACKS
     LOGD("%p ~ setCallback - fd=%d, events=%d", this, fd, events);
 #endif
 
-    if (! events || ! callback) {
+    if (! events || (! callback && ! looperCallback)) {
         LOGE("Invalid attempt to set a callback with no selected poll events or no callback.");
         removeCallback(fd);
         return;
@@ -218,6 +277,7 @@
 
     RequestedCallback requestedCallback;
     requestedCallback.callback = callback;
+    requestedCallback.looperCallback = looperCallback;
     requestedCallback.data = data;
 
     ssize_t index = getRequestIndexLocked(fd);