Fix ThreadedRenderer.setEnabled()

 Bug: 13914116
 Fixes lifecycle issues around setEnabled where ThreadedRenderer
 was reporting as being enabled before it had a Surface. This is
 incorrect.

 Also fix some EGL lifecycle issues

Change-Id: I12ebb279707f9b533a570b61d68735d858b560bf
diff --git a/core/java/android/view/GLRenderer.java b/core/java/android/view/GLRenderer.java
index ad33b6f..bcdfda6 100644
--- a/core/java/android/view/GLRenderer.java
+++ b/core/java/android/view/GLRenderer.java
@@ -838,6 +838,11 @@
         }
     }
 
+    @Override
+    void pauseSurface(Surface surface) {
+        // No-op
+    }
+
     boolean initializeEgl() {
         synchronized (sEglLock) {
             if (sEgl == null && sEglConfig == null) {
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index 92d85d1..7d46cab 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -234,6 +234,13 @@
     abstract void updateSurface(Surface surface) throws OutOfResourcesException;
 
     /**
+     * Stops any rendering into the surface. Use this if it is unclear whether
+     * or not the surface used by the HardwareRenderer will be changing. It
+     * Suspends any rendering into the surface, but will not do any destruction
+     */
+    abstract void pauseSurface(Surface surface);
+
+    /**
      * Destroys all hardware rendering resources associated with the specified
      * view hierarchy.
      *
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index a747ab6..2e0f509 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -54,28 +54,46 @@
 
     private int mWidth, mHeight;
     private long mNativeProxy;
+    private boolean mInitialized = false;
 
     ThreadedRenderer(boolean translucent) {
         mNativeProxy = nCreateProxy(translucent);
-        setEnabled(mNativeProxy != 0);
     }
 
     @Override
     void destroy(boolean full) {
+        mInitialized = false;
+        updateEnabledState(null);
         nDestroyCanvas(mNativeProxy);
     }
 
+    private void updateEnabledState(Surface surface) {
+        if (surface == null || !surface.isValid()) {
+            setEnabled(false);
+        } else {
+            setEnabled(mInitialized);
+        }
+    }
+
     @Override
     boolean initialize(Surface surface) throws OutOfResourcesException {
+        mInitialized = true;
+        updateEnabledState(surface);
         return nInitialize(mNativeProxy, surface);
     }
 
     @Override
     void updateSurface(Surface surface) throws OutOfResourcesException {
+        updateEnabledState(surface);
         nUpdateSurface(mNativeProxy, surface);
     }
 
     @Override
+    void pauseSurface(Surface surface) {
+        nPauseSurface(mNativeProxy, surface);
+    }
+
+    @Override
     void destroyHardwareResources(View view) {
         destroyResources(view);
         // TODO: GLES20Canvas.flushCaches(GLES20Canvas.FLUSH_CACHES_LAYERS);
@@ -267,6 +285,7 @@
 
     private static native boolean nInitialize(long nativeProxy, Surface window);
     private static native void nUpdateSurface(long nativeProxy, Surface window);
+    private static native void nPauseSurface(long nativeProxy, Surface window);
     private static native void nSetup(long nativeProxy, int width, int height);
     private static native void nSetDisplayListData(long nativeProxy, long displayList,
             long newData);
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 94f0683..2d503bf 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -1421,6 +1421,12 @@
                             host.getMeasuredHeight() + ", params=" + params);
                 }
 
+                if (mAttachInfo.mHardwareRenderer != null) {
+                    // relayoutWindow may decide to destroy mSurface. As that decision
+                    // happens in WindowManager service, we need to be defensive here
+                    // and stop using the surface in case it gets destroyed.
+                    mAttachInfo.mHardwareRenderer.pauseSurface(mSurface);
+                }
                 final int surfaceGenerationId = mSurface.getGenerationId();
                 relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);
                 if (!mDrawDuringWindowsAnimating &&
diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp
index 32890cf..20a61bf 100644
--- a/core/jni/android_view_ThreadedRenderer.cpp
+++ b/core/jni/android_view_ThreadedRenderer.cpp
@@ -84,7 +84,7 @@
         jlong proxyPtr, jobject jsurface) {
     RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
     sp<ANativeWindow> window = android_view_Surface_getNativeWindow(env, jsurface);
-    return proxy->initialize(window.get());
+    return proxy->initialize(window);
 }
 
 static void android_view_ThreadedRenderer_updateSurface(JNIEnv* env, jobject clazz,
@@ -94,7 +94,17 @@
     if (jsurface) {
         window = android_view_Surface_getNativeWindow(env, jsurface);
     }
-    proxy->updateSurface(window.get());
+    proxy->updateSurface(window);
+}
+
+static void android_view_ThreadedRenderer_pauseSurface(JNIEnv* env, jobject clazz,
+        jlong proxyPtr, jobject jsurface) {
+    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
+    sp<ANativeWindow> window;
+    if (jsurface) {
+        window = android_view_Surface_getNativeWindow(env, jsurface);
+    }
+    proxy->pauseSurface(window);
 }
 
 static void android_view_ThreadedRenderer_setup(JNIEnv* env, jobject clazz,
@@ -203,6 +213,7 @@
     { "nDeleteProxy", "(J)V", (void*) android_view_ThreadedRenderer_deleteProxy },
     { "nInitialize", "(JLandroid/view/Surface;)Z", (void*) android_view_ThreadedRenderer_initialize },
     { "nUpdateSurface", "(JLandroid/view/Surface;)V", (void*) android_view_ThreadedRenderer_updateSurface },
+    { "nPauseSurface", "(JLandroid/view/Surface;)V", (void*) android_view_ThreadedRenderer_pauseSurface },
     { "nSetup", "(JII)V", (void*) android_view_ThreadedRenderer_setup },
     { "nSetDisplayListData", "(JJJ)V", (void*) android_view_ThreadedRenderer_setDisplayListData },
     { "nDrawDisplayList", "(JJIIII)V", (void*) android_view_ThreadedRenderer_drawDisplayList },
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index c231f6f..af35344 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -347,6 +347,7 @@
 
     if (mEglSurface != EGL_NO_SURFACE) {
         mDirtyRegionsEnabled = mGlobalContext->enableDirtyRegions(mEglSurface);
+        mGlobalContext->makeCurrent(mEglSurface);
         mHaveNewSurface = true;
     }
 }
@@ -356,14 +357,15 @@
     mHaveNewSurface = false;
 }
 
-void CanvasContext::makeCurrent() {
+void CanvasContext::requireSurface() {
+    LOG_ALWAYS_FATAL_IF(mEglSurface == EGL_NO_SURFACE,
+            "requireSurface() called but no surface set!");
     mGlobalContext->makeCurrent(mEglSurface);
 }
 
 bool CanvasContext::initialize(EGLNativeWindowType window) {
     if (mCanvas) return false;
     setSurface(window);
-    makeCurrent();
     mCanvas = new OpenGLRenderer();
     mCanvas->initProperties();
     return true;
@@ -371,7 +373,11 @@
 
 void CanvasContext::updateSurface(EGLNativeWindowType window) {
     setSurface(window);
-    makeCurrent();
+}
+
+void CanvasContext::pauseSurface(EGLNativeWindowType window) {
+    // TODO: For now we just need a fence, in the future suspend any animations
+    // and such to prevent from trying to render into this surface
 }
 
 void CanvasContext::setup(int width, int height) {
@@ -460,7 +466,7 @@
 
     if (!mCanvas) return;
 
-    makeCurrent();
+    requireSurface();
     Rect dirty;
     mCanvas->invokeFunctors(dirty);
 }
@@ -491,12 +497,12 @@
 }
 
 Layer* CanvasContext::createRenderLayer(int width, int height) {
-    requireGlContext();
+    requireSurface();
     return LayerRenderer::createRenderLayer(width, height);
 }
 
 Layer* CanvasContext::createTextureLayer() {
-    requireGlContext();
+    requireSurface();
     return LayerRenderer::createTextureLayer();
 }
 
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index 6f1c37f..9f64944 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -63,6 +63,7 @@
 
     bool initialize(EGLNativeWindowType window);
     void updateSurface(EGLNativeWindowType window);
+    void pauseSurface(EGLNativeWindowType window);
     void setup(int width, int height);
     void setDisplayListData(RenderNode* displayList, DisplayListData* newData);
     void processLayerUpdates(const Vector<DeferredLayerUpdater*>* layerUpdaters);
@@ -83,7 +84,7 @@
 private:
     void setSurface(EGLNativeWindowType window);
     void swapBuffers();
-    void makeCurrent();
+    void requireSurface();
 
     friend class InvokeFunctorsTask;
     void invokeFunctors();
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index e817e61..a7c955e 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -92,10 +92,10 @@
     return (void*) args->context->initialize(args->window);
 }
 
-bool RenderProxy::initialize(EGLNativeWindowType window) {
+bool RenderProxy::initialize(const sp<ANativeWindow>& window) {
     SETUP_TASK(initialize);
     args->context = mContext;
-    args->window = window;
+    args->window = window.get();
     return (bool) postAndWait(task);
 }
 
@@ -104,11 +104,23 @@
     return NULL;
 }
 
-void RenderProxy::updateSurface(EGLNativeWindowType window) {
+void RenderProxy::updateSurface(const sp<ANativeWindow>& window) {
     SETUP_TASK(updateSurface);
     args->context = mContext;
-    args->window = window;
-    post(task);
+    args->window = window.get();
+    postAndWait(task);
+}
+
+CREATE_BRIDGE2(pauseSurface, CanvasContext* context, EGLNativeWindowType window) {
+    args->context->pauseSurface(args->window);
+    return NULL;
+}
+
+void RenderProxy::pauseSurface(const sp<ANativeWindow>& window) {
+    SETUP_TASK(pauseSurface);
+    args->context = mContext;
+    args->window = window.get();
+    postAndWait(task);
 }
 
 CREATE_BRIDGE3(setup, CanvasContext* context, int width, int height) {
diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h
index c50da79..489bf20c1 100644
--- a/libs/hwui/renderthread/RenderProxy.h
+++ b/libs/hwui/renderthread/RenderProxy.h
@@ -59,8 +59,9 @@
     ANDROID_API RenderProxy(bool translucent);
     ANDROID_API virtual ~RenderProxy();
 
-    ANDROID_API bool initialize(EGLNativeWindowType window);
-    ANDROID_API void updateSurface(EGLNativeWindowType window);
+    ANDROID_API bool initialize(const sp<ANativeWindow>& window);
+    ANDROID_API void updateSurface(const sp<ANativeWindow>& window);
+    ANDROID_API void pauseSurface(const sp<ANativeWindow>& window);
     ANDROID_API void setup(int width, int height);
     ANDROID_API void setDisplayListData(RenderNode* renderNode, DisplayListData* newData);
     ANDROID_API void drawDisplayList(RenderNode* displayList,