Don't destroy the same texture twice
Bug #7221449

SurfaceTexture already deletes the GL texture when detachFromContext
is invoked. The newly introduced refcount would casue the Layer
object to be destroyed later and attempt to delete the GL texture
again. By the time the second cleanup occurs, the texture name
might have been reused by somebody else, resulting in erroneous
behaviors.

Change-Id: I257c589fea64b34c00f46fbfaa7732e6854a5e41
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java
index c703aaf..b64a06e 100644
--- a/core/java/android/view/GLES20Canvas.java
+++ b/core/java/android/view/GLES20Canvas.java
@@ -166,6 +166,7 @@
     static native void nSetLayerColorFilter(int layerId, int nativeColorFilter);
     static native void nUpdateTextureLayer(int layerId, int width, int height, boolean opaque,
             SurfaceTexture surface);
+    static native void nClearLayerTexture(int layerId);
     static native void nSetTextureLayerTransform(int layerId, int matrix);
     static native void nDestroyLayer(int layerId);
     static native void nDestroyLayerDeferred(int layerId);
diff --git a/core/java/android/view/GLES20Layer.java b/core/java/android/view/GLES20Layer.java
index a462ed6..812fb97 100644
--- a/core/java/android/view/GLES20Layer.java
+++ b/core/java/android/view/GLES20Layer.java
@@ -66,6 +66,11 @@
         mLayer = 0;
     }
 
+    @Override
+    void clearStorage() {
+        if (mLayer != 0) GLES20Canvas.nClearLayerTexture(mLayer);
+    }
+
     static class Finalizer {
         private int mLayerId;
 
diff --git a/core/java/android/view/GLES20TextureLayer.java b/core/java/android/view/GLES20TextureLayer.java
index 797c734..e863e49 100644
--- a/core/java/android/view/GLES20TextureLayer.java
+++ b/core/java/android/view/GLES20TextureLayer.java
@@ -39,7 +39,7 @@
             mFinalizer = new Finalizer(mLayer);
         } else {
             mFinalizer = null;
-        }        
+        }
     }
 
     @Override
diff --git a/core/java/android/view/HardwareLayer.java b/core/java/android/view/HardwareLayer.java
index d6868ca..d3bc35a 100644
--- a/core/java/android/view/HardwareLayer.java
+++ b/core/java/android/view/HardwareLayer.java
@@ -204,4 +204,9 @@
      * @param dirtyRect The dirty region of the layer that needs to be redrawn
      */
     abstract void redrawLater(DisplayList displayList, Rect dirtyRect);
+
+    /**
+     * Indicates that this layer has lost its underlying storage.
+     */
+    abstract void clearStorage();
 }
diff --git a/core/java/android/view/TextureView.java b/core/java/android/view/TextureView.java
index 7e335f0..876b7d84 100644
--- a/core/java/android/view/TextureView.java
+++ b/core/java/android/view/TextureView.java
@@ -224,6 +224,7 @@
     private void destroySurface() {
         if (mLayer != null) {
             mSurface.detachFromGLContext();
+            mLayer.clearStorage();
 
             boolean shouldRelease = true;
             if (mListener != null) {
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index a3834ac..1b71b43 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -822,6 +822,11 @@
     layer->updateDeferred(renderer, displayList, left, top, right, bottom);
 }
 
+static void android_view_GLES20Canvas_clearLayerTexture(JNIEnv* env, jobject clazz,
+        Layer* layer) {
+    layer->clearTexture();
+}
+
 static void android_view_GLES20Canvas_setTextureLayerTransform(JNIEnv* env, jobject clazz,
         Layer* layer, SkMatrix* matrix) {
 
@@ -1016,6 +1021,7 @@
     { "nUpdateTextureLayer",     "(IIIZLandroid/graphics/SurfaceTexture;)V",
             (void*) android_view_GLES20Canvas_updateTextureLayer },
     { "nUpdateRenderLayer",      "(IIIIIII)V", (void*) android_view_GLES20Canvas_updateRenderLayer },
+    { "nClearLayerTexture",      "(I)V",       (void*) android_view_GLES20Canvas_clearLayerTexture },
     { "nDestroyLayer",           "(I)V",       (void*) android_view_GLES20Canvas_destroyLayer },
     { "nDestroyLayerDeferred",   "(I)V",       (void*) android_view_GLES20Canvas_destroyLayerDeferred },
     { "nDrawLayer",              "(IIFFI)V",   (void*) android_view_GLES20Canvas_drawLayer },
diff --git a/libs/hwui/Layer.h b/libs/hwui/Layer.h
index d2cd440..9b6205d 100644
--- a/libs/hwui/Layer.h
+++ b/libs/hwui/Layer.h
@@ -134,10 +134,6 @@
         return fbo;
     }
 
-    inline GLuint* getTexturePointer() {
-        return &texture.id;
-    }
-
     inline GLuint getTexture() {
         return texture.id;
     }
@@ -181,15 +177,31 @@
     ANDROID_API void setColorFilter(SkiaColorFilter* filter);
 
     inline void bindTexture() {
-        glBindTexture(renderTarget, texture.id);
+        if (texture.id) {
+            glBindTexture(renderTarget, texture.id);
+        }
     }
 
     inline void generateTexture() {
-        glGenTextures(1, &texture.id);
+        if (!texture.id) {
+            glGenTextures(1, &texture.id);
+        }
     }
 
     inline void deleteTexture() {
-        if (texture.id) glDeleteTextures(1, &texture.id);
+        if (texture.id) {
+            glDeleteTextures(1, &texture.id);
+            texture.id = 0;
+        }
+    }
+
+    /**
+     * When the caller frees the texture itself, the caller
+     * must call this method to tell this layer that it lost
+     * the texture.
+     */
+    void clearTexture() {
+        texture.id = 0;
     }
 
     inline void deleteFbo() {