Implement data push from scripts.  Fixes the problem where apps would have to poll to monitor a scripts state.
Fix bug in StoreState where state could be overridden by the default unless the script used more than one state.

Change only impacts renderscript and renderscript apps.
diff --git a/graphics/java/android/renderscript/RenderScript.java b/graphics/java/android/renderscript/RenderScript.java
index 6b0b696..1f2ea38 100644
--- a/graphics/java/android/renderscript/RenderScript.java
+++ b/graphics/java/android/renderscript/RenderScript.java
@@ -75,6 +75,9 @@
     native void nContextAddDefineF(String name, float value);
     native void nContextPause();
     native void nContextResume();
+    native int nContextGetMessage(int[] data, boolean wait);
+    native void nContextInitToClient();
+    native void nContextDeinitToClient();
 
     native void nAssignName(int obj, byte[] name);
     native void nObjDestroy(int id);
@@ -190,6 +193,7 @@
     private int     mContext;
     @SuppressWarnings({"FieldCanBeLocal"})
     private Surface mSurface;
+    private MessageThread mMessageThread;
 
 
     Element mElement_USER_U8;
@@ -214,6 +218,52 @@
     ///////////////////////////////////////////////////////////////////////////////////
     //
 
+    public static class RSMessage implements Runnable {
+        protected int[] mData;
+        protected int mID;
+        public void run() {
+        }
+    }
+    public RSMessage mMessageCallback = null;
+
+    private static class MessageThread extends Thread {
+        RenderScript mRS;
+        boolean mRun = true;
+
+        MessageThread(RenderScript rs) {
+            super("RSMessageThread");
+            mRS = rs;
+
+        }
+
+        public void run() {
+            // This function is a temporary solution.  The final solution will
+            // used typed allocations where the message id is the type indicator.
+            int[] rbuf = new int[16];
+            mRS.nContextInitToClient();
+            while(mRun) {
+                int msg = mRS.nContextGetMessage(rbuf, true);
+                if (msg == 0) {
+                    // Should only happen during teardown.
+                    // But we want to avoid starving other threads during
+                    // teardown by yielding until the next line in the destructor
+                    // can execute to set mRun = false
+                    try {
+                        sleep(1, 0);
+                    } catch(InterruptedException e) {
+                    }
+                }
+                if(mRS.mMessageCallback != null) {
+                    mRS.mMessageCallback.mData = rbuf;
+                    mRS.mMessageCallback.mID = msg;
+                    mRS.mMessageCallback.run();
+                }
+                //Log.d("rs", "MessageThread msg " + msg + " v1 " + rbuf[0] + " v2 " + rbuf[1] + " v3 " +rbuf[2]);
+            }
+            Log.d("rs", "MessageThread exiting.");
+        }
+    }
+
     public RenderScript(Surface sur, boolean useDepth, boolean forceSW) {
         mSurface = sur;
         mDev = nDeviceCreate();
@@ -222,9 +272,14 @@
         }
         mContext = nContextCreate(mDev, mSurface, 0, useDepth);
         Element.initPredefined(this);
+        mMessageThread = new MessageThread(this);
+        mMessageThread.start();
     }
 
     public void destroy() {
+        nContextDeinitToClient();
+        mMessageThread.mRun = false;
+
         nContextDestroy(mContext);
         mContext = 0;
 
diff --git a/graphics/jni/android_renderscript_RenderScript.cpp b/graphics/jni/android_renderscript_RenderScript.cpp
index 9054b65..fa3baa2 100644
--- a/graphics/jni/android_renderscript_RenderScript.cpp
+++ b/graphics/jni/android_renderscript_RenderScript.cpp
@@ -194,6 +194,37 @@
     rsContextResume(con);
 }
 
+static jint
+nContextGetMessage(JNIEnv *_env, jobject _this, jintArray data, jboolean wait)
+{
+    RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+    jint len = _env->GetArrayLength(data);
+    LOG_API("nContextGetMessage, con(%p), len(%i)", con, len);
+    jint *ptr = _env->GetIntArrayElements(data, NULL);
+    size_t receiveLen;
+    int id = rsContextGetMessage(con, ptr, &receiveLen, len * 4, wait);
+    if (!id && receiveLen) {
+        LOGE("message receive buffer too small.  %i", receiveLen);
+    }
+    _env->ReleaseIntArrayElements(data, ptr, 0);
+    return id;
+}
+
+static void nContextInitToClient(JNIEnv *_env, jobject _this)
+{
+    RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+    LOG_API("nContextInitToClient, con(%p)", con);
+    rsContextInitToClient(con);
+}
+
+static void nContextDeinitToClient(JNIEnv *_env, jobject _this)
+{
+    RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+    LOG_API("nContextDeinitToClient, con(%p)", con);
+    rsContextDeinitToClient(con);
+}
+
+
 static void
 nElementBegin(JNIEnv *_env, jobject _this)
 {
@@ -1303,6 +1334,9 @@
 {"nAssignName",                    "(I[B)V",                               (void*)nAssignName },
 {"nObjDestroy",                    "(I)V",                                 (void*)nObjDestroy },
 {"nObjDestroyOOB",                 "(I)V",                                 (void*)nObjDestroyOOB },
+{"nContextGetMessage",             "([IZ)I",                               (void*)nContextGetMessage },
+{"nContextInitToClient",           "()V",                                  (void*)nContextInitToClient },
+{"nContextDeinitToClient",         "()V",                                  (void*)nContextDeinitToClient },
 
 {"nFileOpen",                      "([B)I",                                (void*)nFileOpen },
 
diff --git a/libs/rs/RenderScript.h b/libs/rs/RenderScript.h
index 87a2f4a..9b04393 100644
--- a/libs/rs/RenderScript.h
+++ b/libs/rs/RenderScript.h
@@ -59,6 +59,10 @@
 void rsContextDestroy(RsContext);
 void rsObjDestroyOOB(RsContext, void *);
 
+uint32_t rsContextGetMessage(RsContext, void *data, size_t *receiveLen, size_t bufferLen, bool wait);
+void rsContextInitToClient(RsContext);
+void rsContextDeinitToClient(RsContext);
+
 #define RS_MAX_TEXTURE 2
 
 enum RsDataType {
diff --git a/libs/rs/rsContext.cpp b/libs/rs/rsContext.cpp
index 169d5d4..a1e9e45 100644
--- a/libs/rs/rsContext.cpp
+++ b/libs/rs/rsContext.cpp
@@ -142,6 +142,7 @@
     if (this->props.mLogTimes) {
         timerSet(RS_TIMER_SCRIPT);
     }
+    mStateFragmentStore.mLast.clear();
     bool ret = runScript(mRootScript.get(), 0);
     return ret;
 }
@@ -529,6 +530,64 @@
     }
 }
 
+uint32_t Context::getMessageToClient(void *data, size_t *receiveLen, size_t bufferLen, bool wait)
+{
+    //LOGE("getMessageToClient %i %i", bufferLen, wait);
+    if (!wait) {
+        if (mIO.mToClient.isEmpty()) {
+            // No message to get and not going to wait for one.
+            receiveLen = 0;
+            return 0;
+        }
+    }
+
+    //LOGE("getMessageToClient 2 con=%p", this);
+    uint32_t bytesData = 0;
+    uint32_t commandID = 0;
+    const void *d = mIO.mToClient.get(&commandID, &bytesData);
+    //LOGE("getMessageToClient 3    %i  %i", commandID, bytesData);
+
+    *receiveLen = bytesData;
+    if (bufferLen >= bytesData) {
+        memcpy(data, d, bytesData);
+        mIO.mToClient.next();
+        return commandID;
+    }
+    return 0;
+}
+
+bool Context::sendMessageToClient(void *data, uint32_t cmdID, size_t len, bool waitForSpace)
+{
+    //LOGE("sendMessageToClient %i %i %i", cmdID, len, waitForSpace);
+    if (cmdID == 0) {
+        LOGE("Attempting to send invalid command 0 to client.");
+        return false;
+    }
+    if (!waitForSpace) {
+        if (mIO.mToClient.getFreeSpace() < len) {
+            // Not enough room, and not waiting.
+            return false;
+        }
+    }
+    //LOGE("sendMessageToClient 2");
+    void *p = mIO.mToClient.reserve(len);
+    memcpy(p, data, len);
+    mIO.mToClient.commit(cmdID, len);
+    //LOGE("sendMessageToClient 3");
+    return true;
+}
+
+void Context::initToClient()
+{
+    while(!mRunning) {
+        usleep(100);
+    }
+}
+
+void Context::deinitToClient()
+{
+    mIO.mToClient.shutdown();
+}
 
 
 ///////////////////////////////////////////////////////////////////////////////////////////
@@ -636,3 +695,21 @@
     rsc->objDestroyAdd(static_cast<ObjectBase *>(obj));
 }
 
+uint32_t rsContextGetMessage(RsContext vrsc, void *data, size_t *receiveLen, size_t bufferLen, bool wait)
+{
+    Context * rsc = static_cast<Context *>(vrsc);
+    return rsc->getMessageToClient(data, receiveLen, bufferLen, wait);
+}
+
+void rsContextInitToClient(RsContext vrsc)
+{
+    Context * rsc = static_cast<Context *>(vrsc);
+    rsc->initToClient();
+}
+
+void rsContextDeinitToClient(RsContext vrsc)
+{
+    Context * rsc = static_cast<Context *>(vrsc);
+    rsc->deinitToClient();
+}
+
diff --git a/libs/rs/rsContext.h b/libs/rs/rsContext.h
index cef421d..b56e7d7 100644
--- a/libs/rs/rsContext.h
+++ b/libs/rs/rsContext.h
@@ -97,6 +97,12 @@
     void appendNameDefines(String8 *str) const;
     void appendVarDefines(String8 *str) const;
 
+    uint32_t getMessageToClient(void *data, size_t *receiveLen, size_t bufferLen, bool wait);
+    bool sendMessageToClient(void *data, uint32_t cmdID, size_t len, bool waitForSpace);
+
+    void initToClient();
+    void deinitToClient();
+
     ProgramFragment * getDefaultProgramFragment() const {
         return mStateFragment.mDefault.get();
     }
diff --git a/libs/rs/rsLocklessFifo.cpp b/libs/rs/rsLocklessFifo.cpp
index b0540a6..085a81e 100644
--- a/libs/rs/rsLocklessFifo.cpp
+++ b/libs/rs/rsLocklessFifo.cpp
@@ -99,6 +99,9 @@
 
 void LocklessCommandFifo::commit(uint32_t command, uint32_t sizeInBytes)
 {
+    if (mInShutdown) {
+        return;
+    }
     //dumpState("commit 1");
     reinterpret_cast<uint16_t *>(mPut)[0] = command;
     reinterpret_cast<uint16_t *>(mPut)[1] = sizeInBytes;
@@ -109,6 +112,9 @@
 
 void LocklessCommandFifo::commitSync(uint32_t command, uint32_t sizeInBytes)
 {
+    if (mInShutdown) {
+        return;
+    }
     commit(command, sizeInBytes);
     flush();
 }
diff --git a/libs/rs/rsScriptC_Lib.cpp b/libs/rs/rsScriptC_Lib.cpp
index 17d14f5..9a96290 100644
--- a/libs/rs/rsScriptC_Lib.cpp
+++ b/libs/rs/rsScriptC_Lib.cpp
@@ -1002,6 +1002,12 @@
     return rs888to565(ir, ig, ib);
 }
 
+static uint32_t SC_toClient(void *data, int cmdID, int len, int waitForSpace)
+{
+    GET_TLS();
+    return rsc->sendMessageToClient(data, cmdID, len, waitForSpace != 0);
+}
+
 //////////////////////////////////////////////////////////////////////////////
 // Class implementation
 //////////////////////////////////////////////////////////////////////////////
@@ -1270,6 +1276,8 @@
     { "getHeight", (void *)&SC_getHeight,
         "int", "()" },
 
+    { "sendToClient", (void *)&SC_toClient,
+        "int", "(void *data, int cmdID, int len, int waitForSpace)" },
 
 
     { "debugF", (void *)&SC_debugF,
diff --git a/libs/rs/rsThreadIO.cpp b/libs/rs/rsThreadIO.cpp
index 4d3d73a..527b3d7 100644
--- a/libs/rs/rsThreadIO.cpp
+++ b/libs/rs/rsThreadIO.cpp
@@ -24,6 +24,7 @@
 ThreadIO::ThreadIO()
 {
     mToCore.init(16 * 1024);
+    mToClient.init(1024);
 }
 
 ThreadIO::~ThreadIO()
diff --git a/libs/rs/rsThreadIO.h b/libs/rs/rsThreadIO.h
index 1f6a0c2..95270f5 100644
--- a/libs/rs/rsThreadIO.h
+++ b/libs/rs/rsThreadIO.h
@@ -39,7 +39,7 @@
 
 
     LocklessCommandFifo mToCore;
-    //LocklessCommandFifo mToClient;
+    LocklessCommandFifo mToClient;
 
     intptr_t mToCoreRet;