Fix onTrimMemory for HardwareRenderer

 Also fixes detachFunctor possibly drawing after return

 Bug: 15189843
 Bug: 15990672

Change-Id: I64c48cb674c461a8eeaba407b697e09f72c98ce3
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index f5514f8..422d88c 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -3962,10 +3962,6 @@
 
         ArrayList<ComponentCallbacks2> callbacks = collectComponentCallbacks(false, config);
 
-        // Cleanup hardware accelerated stuff
-        // TODO: Do we actually want to do this in response to all config changes?
-        WindowManagerGlobal.getInstance().trimLocalMemory();
-
         freeTextLayoutCachesIfNeeded(configDiff);
 
         if (callbacks != null) {
@@ -4100,9 +4096,6 @@
     final void handleTrimMemory(int level) {
         if (DEBUG_MEMORY_TRIM) Slog.v(TAG, "Trimming memory to level: " + level);
 
-        final WindowManagerGlobal windowManager = WindowManagerGlobal.getInstance();
-        windowManager.startTrimMemory(level);
-
         ArrayList<ComponentCallbacks2> callbacks = collectComponentCallbacks(true, null);
 
         final int N = callbacks.size();
@@ -4110,7 +4103,7 @@
             callbacks.get(i).onTrimMemory(level);
         }
 
-        windowManager.endTrimMemory();
+        WindowManagerGlobal.getInstance().trimMemory(level);
     }
 
     private void setupGraphicsSupport(LoadedApk info, File cacheDir) {
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java
index dcd9ba9..d7d3c72 100644
--- a/core/java/android/view/GLES20Canvas.java
+++ b/core/java/android/view/GLES20Canvas.java
@@ -203,31 +203,6 @@
     private static native int nCallDrawGLFunction(long renderer, long drawGLFunction);
 
     ///////////////////////////////////////////////////////////////////////////
-    // Memory
-    ///////////////////////////////////////////////////////////////////////////
-
-    /**
-     * Must match Caches::FlushMode values
-     *
-     * @see #flushCaches(int)
-     */
-    static final int FLUSH_CACHES_LAYERS = 0;
-
-    /**
-     * Must match Caches::FlushMode values
-     *
-     * @see #flushCaches(int)
-     */
-    static final int FLUSH_CACHES_MODERATE = 1;
-
-    /**
-     * Must match Caches::FlushMode values
-     *
-     * @see #flushCaches(int)
-     */
-    static final int FLUSH_CACHES_FULL = 2;
-
-    ///////////////////////////////////////////////////////////////////////////
     // Display list
     ///////////////////////////////////////////////////////////////////////////
 
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index e9bdcae..d69d01d 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -18,8 +18,6 @@
 
 import android.content.Context;
 import android.graphics.Bitmap;
-import android.graphics.Rect;
-import android.graphics.SurfaceTexture;
 import android.util.DisplayMetrics;
 import android.view.Surface.OutOfResourcesException;
 
@@ -200,10 +198,8 @@
 
     /**
      * Destroys the hardware rendering context.
-     *
-     * @param full If true, destroys all associated resources.
      */
-    abstract void destroy(boolean full);
+    abstract void destroy();
 
     /**
      * Initializes the hardware renderer for the specified surface.
@@ -435,28 +431,7 @@
      *              see {@link android.content.ComponentCallbacks}
      */
     static void trimMemory(int level) {
-        startTrimMemory(level);
-        endTrimMemory();
-    }
-
-    /**
-     * Starts the process of trimming memory. Usually this call will setup
-     * hardware rendering context and reclaim memory.Extra cleanup might
-     * be required by calling {@link #endTrimMemory()}.
-     *
-     * @param level Hint about the amount of memory that should be trimmed,
-     *              see {@link android.content.ComponentCallbacks}
-     */
-    static void startTrimMemory(int level) {
-        ThreadedRenderer.startTrimMemory(level);
-    }
-
-    /**
-     * Finishes the process of trimming memory. This method will usually
-     * cleanup special resources used by the memory trimming process.
-     */
-    static void endTrimMemory() {
-        ThreadedRenderer.endTrimMemory();
+        ThreadedRenderer.trimMemory(level);
     }
 
     /**
@@ -503,8 +478,15 @@
     abstract void fence();
 
     /**
+     * Prevents any further drawing until draw() is called. This is a signal
+     * that the contents of the RenderNode tree are no longer safe to play back.
+     * In practice this usually means that there are Functor pointers in the
+     * display list that are no longer valid.
+     */
+    abstract void stopDrawing();
+
+    /**
      * Called by {@link ViewRootImpl} when a new performTraverals is scheduled.
      */
-    public void notifyFramePending() {
-    }
+    abstract void notifyFramePending();
 }
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index 45714ff..fcc51ec 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -90,7 +90,7 @@
     }
 
     @Override
-    void destroy(boolean full) {
+    void destroy() {
         mInitialized = false;
         updateEnabledState(null);
         nDestroyCanvasAndSurface(mNativeProxy);
@@ -125,7 +125,7 @@
     @Override
     void destroyHardwareResources(View view) {
         destroyResources(view);
-        nFlushCaches(mNativeProxy, GLES20Canvas.FLUSH_CACHES_LAYERS);
+        nDestroyHardwareResources(mNativeProxy);
     }
 
     private static void destroyResources(View view) {
@@ -289,6 +289,11 @@
     }
 
     @Override
+    void stopDrawing() {
+        nStopDrawing(mNativeProxy);
+    }
+
+    @Override
     public void notifyFramePending() {
         nNotifyFramePending(mNativeProxy);
     }
@@ -303,12 +308,8 @@
         }
     }
 
-    static void startTrimMemory(int level) {
-        // TODO
-    }
-
-    static void endTrimMemory() {
-        // TODO
+    static void trimMemory(int level) {
+        nTrimMemory(level);
     }
 
     private static class AtlasInitializer {
@@ -403,9 +404,11 @@
     private static native void nCancelLayerUpdate(long nativeProxy, long layer);
     private static native void nDetachSurfaceTexture(long nativeProxy, long layer);
 
-    private static native void nFlushCaches(long nativeProxy, int flushMode);
+    private static native void nDestroyHardwareResources(long nativeProxy);
+    private static native void nTrimMemory(int level);
 
     private static native void nFence(long nativeProxy);
+    private static native void nStopDrawing(long nativeProxy);
     private static native void nNotifyFramePending(long nativeProxy);
 
     private static native void nDumpProfileInfo(long nativeProxy, FileDescriptor fd);
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 829e089..6cfc019 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -13598,7 +13598,9 @@
      * @hide
      */
     protected void destroyHardwareResources() {
-        resetDisplayList();
+        // Intentionally empty. RenderNode's lifecycle is now fully managed
+        // by the hardware renderer.
+        // However some subclasses (eg, WebView, TextureView) still need this signal
     }
 
     /**
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 4c9d3f9..3219330 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -632,21 +632,17 @@
     void destroyHardwareResources() {
         if (mAttachInfo.mHardwareRenderer != null) {
             mAttachInfo.mHardwareRenderer.destroyHardwareResources(mView);
-            mAttachInfo.mHardwareRenderer.destroy(false);
+            mAttachInfo.mHardwareRenderer.destroy();
         }
     }
 
-    void destroyHardwareLayers() {
-        // TODO Implement
-    }
-
     public void detachFunctor(long functor) {
         // TODO: Make the resize buffer some other way to not need this block
         mBlockResizeBuffer = true;
         if (mAttachInfo.mHardwareRenderer != null) {
             // Fence so that any pending invokeFunctor() messages will be processed
             // before we return from detachFunctor.
-            mAttachInfo.mHardwareRenderer.fence();
+            mAttachInfo.mHardwareRenderer.stopDrawing();
         }
     }
 
@@ -696,7 +692,7 @@
             if (!HardwareRenderer.sRendererDisabled || (HardwareRenderer.sSystemRendererDisabled
                     && forceHwAccelerated)) {
                 if (mAttachInfo.mHardwareRenderer != null) {
-                    mAttachInfo.mHardwareRenderer.destroy(true);
+                    mAttachInfo.mHardwareRenderer.destroy();
                 }
 
                 final boolean translucent = attrs.format != PixelFormat.OPAQUE;
@@ -1613,7 +1609,7 @@
                     // Our surface is gone
                     if (mAttachInfo.mHardwareRenderer != null &&
                             mAttachInfo.mHardwareRenderer.isEnabled()) {
-                        mAttachInfo.mHardwareRenderer.destroy(true);
+                        mAttachInfo.mHardwareRenderer.destroy();
                     }
                 } else if (surfaceGenerationId != mSurface.getGenerationId() &&
                         mSurfaceHolder == null && mAttachInfo.mHardwareRenderer != null) {
@@ -5436,7 +5432,7 @@
             if (mView != null) {
                 hardwareRenderer.destroyHardwareResources(mView);
             }
-            hardwareRenderer.destroy(true);
+            hardwareRenderer.destroy();
             hardwareRenderer.setRequested(false);
 
             attachInfo.mHardwareRenderer = null;
diff --git a/core/java/android/view/WindowManagerGlobal.java b/core/java/android/view/WindowManagerGlobal.java
index 0ebf2e1..74bc186 100644
--- a/core/java/android/view/WindowManagerGlobal.java
+++ b/core/java/android/view/WindowManagerGlobal.java
@@ -20,7 +20,6 @@
 import android.app.ActivityManager;
 import android.content.ComponentCallbacks2;
 import android.content.res.Configuration;
-import android.opengl.ManagedEGLContext;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.ServiceManager;
@@ -114,7 +113,6 @@
     private final ArrayList<WindowManager.LayoutParams> mParams =
             new ArrayList<WindowManager.LayoutParams>();
     private final ArraySet<View> mDyingViews = new ArraySet<View>();
-    private boolean mNeedsEglTerminate;
 
     private Runnable mSystemPropertyUpdater;
 
@@ -377,13 +375,22 @@
         return index;
     }
 
-    public void startTrimMemory(int level) {
+    public static boolean shouldDestroyEglContext(int trimLevel) {
+        // On low-end gfx devices we trim when memory is moderate;
+        // on high-end devices we do this when low.
+        if (trimLevel >= ComponentCallbacks2.TRIM_MEMORY_COMPLETE) {
+            return true;
+        }
+        if (trimLevel >= ComponentCallbacks2.TRIM_MEMORY_MODERATE
+                && !ActivityManager.isHighEndGfx()) {
+            return true;
+        }
+        return false;
+    }
+
+    public void trimMemory(int level) {
         if (HardwareRenderer.isAvailable()) {
-            // On low-end gfx devices we trim when memory is moderate;
-            // on high-end devices we do this when low.
-            if (level >= ComponentCallbacks2.TRIM_MEMORY_COMPLETE
-                    || (level >= ComponentCallbacks2.TRIM_MEMORY_MODERATE
-                            && !ActivityManager.isHighEndGfx())) {
+            if (shouldDestroyEglContext(level)) {
                 // Destroy all hardware surfaces and resources associated to
                 // known windows
                 synchronized (mLock) {
@@ -392,29 +399,10 @@
                     }
                 }
                 // Force a full memory flush
-                mNeedsEglTerminate = true;
-                HardwareRenderer.startTrimMemory(ComponentCallbacks2.TRIM_MEMORY_COMPLETE);
-                return;
+                level = ComponentCallbacks2.TRIM_MEMORY_COMPLETE;
             }
 
-            HardwareRenderer.startTrimMemory(level);
-        }
-    }
-
-    public void endTrimMemory() {
-        HardwareRenderer.endTrimMemory();
-
-        if (mNeedsEglTerminate) {
-            ManagedEGLContext.doTerminate();
-            mNeedsEglTerminate = false;
-        }
-    }
-
-    public void trimLocalMemory() {
-        synchronized (mLock) {
-            for (int i = mRoots.size() - 1; i >= 0; --i) {
-                mRoots.get(i).destroyHardwareLayers();
-            }
+            HardwareRenderer.trimMemory(level);
         }
     }
 
diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp
index e63c475..aab48b3 100644
--- a/core/jni/android_view_ThreadedRenderer.cpp
+++ b/core/jni/android_view_ThreadedRenderer.cpp
@@ -298,10 +298,15 @@
     proxy->detachSurfaceTexture(layer);
 }
 
-static void android_view_ThreadedRenderer_flushCaches(JNIEnv* env, jobject clazz,
-        jlong proxyPtr, jint flushMode) {
+static void android_view_ThreadedRenderer_destroyHardwareResources(JNIEnv* env, jobject clazz,
+        jlong proxyPtr) {
     RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
-    proxy->flushCaches(static_cast<Caches::FlushMode>(flushMode));
+    proxy->destroyHardwareResources();
+}
+
+static void android_view_ThreadedRenderer_trimMemory(JNIEnv* env, jobject clazz,
+        jint level) {
+    RenderProxy::trimMemory(level);
 }
 
 static void android_view_ThreadedRenderer_fence(JNIEnv* env, jobject clazz,
@@ -310,6 +315,12 @@
     proxy->fence();
 }
 
+static void android_view_ThreadedRenderer_stopDrawing(JNIEnv* env, jobject clazz,
+        jlong proxyPtr) {
+    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
+    proxy->stopDrawing();
+}
+
 static void android_view_ThreadedRenderer_notifyFramePending(JNIEnv* env, jobject clazz,
         jlong proxyPtr) {
     RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
@@ -365,8 +376,10 @@
     { "nPushLayerUpdate", "(JJ)V", (void*) android_view_ThreadedRenderer_pushLayerUpdate },
     { "nCancelLayerUpdate", "(JJ)V", (void*) android_view_ThreadedRenderer_cancelLayerUpdate },
     { "nDetachSurfaceTexture", "(JJ)V", (void*) android_view_ThreadedRenderer_detachSurfaceTexture },
-    { "nFlushCaches", "(JI)V", (void*) android_view_ThreadedRenderer_flushCaches },
+    { "nDestroyHardwareResources", "(J)V", (void*) android_view_ThreadedRenderer_destroyHardwareResources },
+    { "nTrimMemory", "(I)V", (void*) android_view_ThreadedRenderer_trimMemory },
     { "nFence", "(J)V", (void*) android_view_ThreadedRenderer_fence },
+    { "nStopDrawing", "(J)V", (void*) android_view_ThreadedRenderer_stopDrawing },
     { "nNotifyFramePending", "(J)V", (void*) android_view_ThreadedRenderer_notifyFramePending },
     { "nDumpProfileInfo", "(JLjava/io/FileDescriptor;)V", (void*) android_view_ThreadedRenderer_dumpProfileInfo },
 #endif