Enable asynchronous destruction of BaseObjs.

Change-Id: Iaddf8041a3c870a986ec8999e6ccc3aede38fc4c
diff --git a/rs/java/android/renderscript/RenderScript.java b/rs/java/android/renderscript/RenderScript.java
index d2c7456..b0ef156 100644
--- a/rs/java/android/renderscript/RenderScript.java
+++ b/rs/java/android/renderscript/RenderScript.java
@@ -18,6 +18,7 @@
 
 import java.io.File;
 import java.lang.reflect.Method;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
 
 import android.content.Context;
 import android.content.res.AssetManager;
@@ -147,6 +148,7 @@
     }
 
     ContextType mContextType;
+    ReentrantReadWriteLock mRWLock;
 
     // Methods below are wrapped to protect the non-threadsafe
     // lockless fifo.
@@ -174,7 +176,18 @@
     native void rsnContextDestroy(long con);
     synchronized void nContextDestroy() {
         validate();
-        rsnContextDestroy(mContext);
+
+        // take teardown lock
+        // teardown lock can only be taken when no objects are being destroyed
+        ReentrantReadWriteLock.WriteLock wlock = mRWLock.writeLock();
+        wlock.lock();
+
+        long curCon = mContext;
+        // context is considered dead as of this point
+        mContext = 0;
+
+        wlock.unlock();
+        rsnContextDestroy(curCon);
     }
     native void rsnContextSetSurface(long con, int w, int h, Surface sur);
     synchronized void nContextSetSurface(int w, int h, Surface sur) {
@@ -259,8 +272,10 @@
         validate();
         return rsnGetName(mContext, obj);
     }
+
+    // nObjDestroy is explicitly _not_ synchronous to prevent crashes in finalizers
     native void rsnObjDestroy(long con, long id);
-    synchronized void nObjDestroy(long id) {
+    void nObjDestroy(long id) {
         // There is a race condition here.  The calling code may be run
         // by the gc while teardown is occuring.  This protects againts
         // deleting dead objects.
@@ -1092,6 +1107,7 @@
         if (ctx != null) {
             mApplicationContext = ctx.getApplicationContext();
         }
+        mRWLock = new ReentrantReadWriteLock();
     }
 
     /**
@@ -1186,6 +1202,8 @@
      */
     public void destroy() {
         validate();
+        nContextFinish();
+
         nContextDeinitToClient(mContext);
         mMessageThread.mRun = false;
         try {
@@ -1194,7 +1212,6 @@
         }
 
         nContextDestroy();
-        mContext = 0;
 
         nDeviceDestroy(mDev);
         mDev = 0;