Fix clear() operation for rsScriptC.

- This removes a memory leak where some elements were not getting tracked
  properly (and then triggering an assert when a context is destroyed).
- Convert ScriptCState to use a tracked object reference for mScript.
- Add a missing clear to FontState.
- Clean up synchronization in RSTest so that our graphics context outlives
  any subtest context.

Change-Id: I0d5768c4d2f8810dd1ae2f68b1edd7e150f382fd
diff --git a/libs/rs/java/tests/src/com/android/rs/test/RSTestCore.java b/libs/rs/java/tests/src/com/android/rs/test/RSTestCore.java
index dbc9133..835dea2 100644
--- a/libs/rs/java/tests/src/com/android/rs/test/RSTestCore.java
+++ b/libs/rs/java/tests/src/com/android/rs/test/RSTestCore.java
@@ -21,6 +21,8 @@
 import android.util.Log;
 import java.util.ArrayList;
 import java.util.ListIterator;
+import java.util.Timer;
+import java.util.TimerTask;
 
 
 public class RSTestCore {
@@ -42,12 +44,18 @@
     private ArrayList<UnitTest> unitTests;
     private ListIterator<UnitTest> test_iter;
     private UnitTest activeTest;
+    private boolean stopTesting;
+
+    /* Periodic timer for ensuring future tests get scheduled */
+    private Timer mTimer;
+    public static final int RS_TIMER_PERIOD = 100;
 
     public void init(RenderScriptGL rs, Resources res, int width, int height) {
         mRS = rs;
         mRes = res;
         mWidth = width;
         mHeight = height;
+        stopTesting = false;
 
         mScript = new ScriptC_rslist(mRS, mRes, R.raw.rslist, true);
 
@@ -88,9 +96,17 @@
 
         test_iter = unitTests.listIterator();
         refreshTestResults(); /* Kick off the first test */
+
+        TimerTask pTask = new TimerTask() {
+            public void run() {
+                refreshTestResults();
+            }
+        };
+
+        mTimer = new Timer();
+        mTimer.schedule(pTask, RS_TIMER_PERIOD, RS_TIMER_PERIOD);
     }
 
-    static int count = 0;
     public void checkAndRunNextTest() {
         if (activeTest != null) {
             if (!activeTest.isAlive()) {
@@ -104,7 +120,7 @@
             }
         }
 
-        if (activeTest == null) {
+        if (!stopTesting && activeTest == null) {
             if (test_iter.hasNext()) {
                 activeTest = test_iter.next();
                 activeTest.start();
@@ -112,8 +128,14 @@
                  * should start running. The message handler in UnitTest.java
                  * ensures this. */
             }
+            else {
+                if (mTimer != null) {
+                    mTimer.cancel();
+                    mTimer.purge();
+                    mTimer = null;
+                }
+            }
         }
-        count++;
     }
 
     public void refreshTestResults() {
@@ -127,6 +149,29 @@
         }
     }
 
+    public void cleanup() {
+        stopTesting = true;
+        UnitTest t = activeTest;
+
+        /* Stop periodic refresh of testing */
+        if (mTimer != null) {
+            mTimer.cancel();
+            mTimer.purge();
+            mTimer = null;
+        }
+
+        /* Wait to exit until we finish the current test */
+        if (t != null) {
+            try {
+                t.join();
+            }
+            catch (InterruptedException e) {
+            }
+            t = null;
+        }
+
+    }
+
     public void newTouchPosition(float x, float y, float pressure, int id) {
     }
 
diff --git a/libs/rs/java/tests/src/com/android/rs/test/RSTestView.java b/libs/rs/java/tests/src/com/android/rs/test/RSTestView.java
index ce99c6d..b811d48 100644
--- a/libs/rs/java/tests/src/com/android/rs/test/RSTestView.java
+++ b/libs/rs/java/tests/src/com/android/rs/test/RSTestView.java
@@ -62,6 +62,7 @@
     @Override
     protected void onDetachedFromWindow() {
         if(mRS != null) {
+            mRender.cleanup();
             mRS = null;
             destroyRenderScript();
         }
diff --git a/libs/rs/java/tests/src/com/android/rs/test/UT_fp_mad.java b/libs/rs/java/tests/src/com/android/rs/test/UT_fp_mad.java
index 8391fb3..9d57e90 100644
--- a/libs/rs/java/tests/src/com/android/rs/test/UT_fp_mad.java
+++ b/libs/rs/java/tests/src/com/android/rs/test/UT_fp_mad.java
@@ -33,6 +33,7 @@
         pRS.mMessageCallback = mRsMessage;
         s.invoke_fp_mad_test(0, 0);
         pRS.finish();
+        waitForMessage();
         pRS.destroy();
     }
 }
diff --git a/libs/rs/java/tests/src/com/android/rs/test/UT_primitives.java b/libs/rs/java/tests/src/com/android/rs/test/UT_primitives.java
index bef6ec5..fb355dd 100644
--- a/libs/rs/java/tests/src/com/android/rs/test/UT_primitives.java
+++ b/libs/rs/java/tests/src/com/android/rs/test/UT_primitives.java
@@ -33,6 +33,7 @@
         pRS.mMessageCallback = mRsMessage;
         s.invoke_primitives_test(0, 0);
         pRS.finish();
+        waitForMessage();
         pRS.destroy();
     }
 }
diff --git a/libs/rs/java/tests/src/com/android/rs/test/UnitTest.java b/libs/rs/java/tests/src/com/android/rs/test/UnitTest.java
index 5eb0d67..c9d88a6 100644
--- a/libs/rs/java/tests/src/com/android/rs/test/UnitTest.java
+++ b/libs/rs/java/tests/src/com/android/rs/test/UnitTest.java
@@ -23,6 +23,7 @@
     public int result;
     private ScriptField_ListAllocs_s.Item mItem;
     private RSTestCore mRSTC;
+    private boolean msgHandled;
 
     /* These constants must match those in shared.rsh */
     public static final int RS_MSG_TEST_PASSED = 100;
@@ -35,6 +36,7 @@
         super();
         mRSTC = rstc;
         name = n;
+        msgHandled = false;
         result = initResult;
         testID = numTests++;
     }
@@ -67,6 +69,7 @@
 
             if (mItem != null) {
                 mItem.result = result;
+                msgHandled = true;
                 try {
                     mRSTC.refreshTestResults();
                 }
@@ -79,6 +82,12 @@
         }
     };
 
+    public void waitForMessage() {
+        while (!msgHandled) {
+            yield();
+        }
+    }
+
     public void setItem(ScriptField_ListAllocs_s.Item item) {
         mItem = item;
     }
diff --git a/libs/rs/rsContext.cpp b/libs/rs/rsContext.cpp
index b4d5014..cfd6479 100644
--- a/libs/rs/rsContext.cpp
+++ b/libs/rs/rsContext.cpp
@@ -294,6 +294,7 @@
          LOGE("pthread_setspecific %i", status);
      }
 
+     rsc->mScriptC.init(rsc);
      if (rsc->mIsGraphicsContext) {
          rsc->mStateRaster.init(rsc);
          rsc->setRaster(NULL);
diff --git a/libs/rs/rsFont.cpp b/libs/rs/rsFont.cpp
index 4f8d8df..12dedac 100644
--- a/libs/rs/rsFont.cpp
+++ b/libs/rs/rsFont.cpp
@@ -743,6 +743,8 @@
 {
     mInitialized = false;
 
+    mFontShaderFConstant.clear();
+
     mIndexBuffer.clear();
     mVertexArray.clear();
 
diff --git a/libs/rs/rsObjectBase.cpp b/libs/rs/rsObjectBase.cpp
index 48f1fee..713d61e 100644
--- a/libs/rs/rsObjectBase.cpp
+++ b/libs/rs/rsObjectBase.cpp
@@ -61,6 +61,7 @@
     if (mRSC) {
         remove();
     }
+    rsAssert(rsc);
     mRSC = rsc;
     if (rsc) {
         add();
diff --git a/libs/rs/rsScriptC.cpp b/libs/rs/rsScriptC.cpp
index e9621b9..c6418be 100644
--- a/libs/rs/rsScriptC.cpp
+++ b/libs/rs/rsScriptC.cpp
@@ -349,25 +349,29 @@
 
 ScriptCState::ScriptCState()
 {
-    mScript = NULL;
-    clear();
+    mScript.clear();
 }
 
 ScriptCState::~ScriptCState()
 {
-    delete mScript;
-    mScript = NULL;
+    mScript.clear();
 }
 
-void ScriptCState::clear()
+void ScriptCState::init(Context *rsc)
 {
+    clear(rsc);
+}
+
+void ScriptCState::clear(Context *rsc)
+{
+    rsAssert(rsc);
     for (uint32_t ct=0; ct < MAX_SCRIPT_BANKS; ct++) {
         mConstantBufferTypes[ct].clear();
         mSlotWritable[ct] = false;
     }
 
-    delete mScript;
-    mScript = new ScriptC(NULL);
+    mScript.clear();
+    mScript.set(new ScriptC(rsc));
 }
 
 static BCCvoid* symbolLookup(BCCvoid* pContext, const BCCchar* name)
@@ -503,7 +507,7 @@
 void rsi_ScriptCBegin(Context * rsc)
 {
     ScriptCState *ss = &rsc->mScriptC;
-    ss->clear();
+    ss->clear(rsc);
 }
 
 void rsi_ScriptCSetText(Context *rsc, const char *text, uint32_t len)
@@ -522,10 +526,10 @@
 {
     ScriptCState *ss = &rsc->mScriptC;
 
-    ScriptC *s = ss->mScript;
-    ss->mScript = NULL;
+    ObjectBaseRef<ScriptC> s = ss->mScript.get();
+    ss->mScript.clear();
 
-    ss->runCompiler(rsc, s);
+    ss->runCompiler(rsc, s.get());
     s->incUserRef();
     s->setContext(rsc);
     for (int ct=0; ct < MAX_SCRIPT_BANKS; ct++) {
@@ -533,8 +537,8 @@
         s->mSlotWritable[ct] = ss->mSlotWritable[ct];
     }
 
-    ss->clear();
-    return s;
+    ss->clear(rsc);
+    return s.get();
 }
 
 }
diff --git a/libs/rs/rsScriptC.h b/libs/rs/rsScriptC.h
index 9d09b0b..7ec80aa 100644
--- a/libs/rs/rsScriptC.h
+++ b/libs/rs/rsScriptC.h
@@ -79,14 +79,16 @@
     ScriptCState();
     ~ScriptCState();
 
-    ScriptC *mScript;
+    ObjectBaseRef<ScriptC> mScript;
 
     ObjectBaseRef<const Type> mConstantBufferTypes[MAX_SCRIPT_BANKS];
     //String8 mSlotNames[MAX_SCRIPT_BANKS];
     bool mSlotWritable[MAX_SCRIPT_BANKS];
     //String8 mInvokableNames[MAX_SCRIPT_BANKS];
 
-    void clear();
+    void init(Context *rsc);
+
+    void clear(Context *rsc);
     void runCompiler(Context *rsc, ScriptC *s);
 
     struct SymbolTable_t {