Trim OpenGLRenderer's memory usage whenever possible

Change-Id: I9225077184f374b1a43300add15cc1d5b6869d1c
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index c6a746b..86161da 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -3558,6 +3558,7 @@
     }
 
     final void handleTrimMemory(int level) {
+        WindowManagerImpl.getDefault().trimMemory(level);
     }
 
     private final void handleBindApplication(AppBindData data) {
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java
index 4987e2f..80244bb 100644
--- a/core/java/android/view/GLES20Canvas.java
+++ b/core/java/android/view/GLES20Canvas.java
@@ -286,6 +286,38 @@
 
     private static native boolean nCallDrawGLFunction(int renderer, int drawGLFunction);
 
+
+    ///////////////////////////////////////////////////////////////////////////
+    // Memory
+    ///////////////////////////////////////////////////////////////////////////
+
+    /**
+     * @see #flushCaches(int) 
+     */
+    public static final int FLUSH_CACHES_MODERATE = 0;
+
+    /**
+     * @see #flushCaches(int) 
+     */
+    public static final int FLUSH_CACHES_FULL = 1;
+
+    /**
+     * Flush caches to reclaim as much memory as possible. The amount of memory
+     * to reclaim is indicate by the level parameter.
+     * 
+     * The level can be one of {@link #FLUSH_CACHES_MODERATE} or
+     * {@link #FLUSH_CACHES_FULL}.
+     * 
+     * @param level Hint about the amount of memory to reclaim
+     * 
+     * @hide
+     */
+    public static void flushCaches(int level) {
+        nFlushCaches(level);
+    }
+
+    private static native void nFlushCaches(int level);
+
     ///////////////////////////////////////////////////////////////////////////
     // Display list
     ///////////////////////////////////////////////////////////////////////////
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index 011e44c..9a2564f 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -17,6 +17,7 @@
 
 package android.view;
 
+import android.content.ComponentCallbacks;
 import android.graphics.Paint;
 import android.graphics.Rect;
 import android.graphics.SurfaceTexture;
@@ -263,6 +264,18 @@
     }
 
     /**
+     * Invoke this method when the system is running out of memory. This
+     * method will attempt to recover as much memory as possible, based on
+     * the specified hint.
+     * 
+     * @param level Hint about the amount of memory that should be trimmed,
+     *              see {@link android.content.ComponentCallbacks}
+     */
+    static void trimMemory(int level) {
+        Gl20Renderer.flushCaches(level);
+    }
+
+    /**
      * Indicates whether hardware acceleration is currently enabled.
      * 
      * @return True if hardware acceleration is in use, false otherwise.
@@ -858,5 +871,16 @@
             }
             return null;
         }
+        
+        static void flushCaches(int level) {
+            switch (level) {
+                case ComponentCallbacks.TRIM_MEMORY_MODERATE:
+                    GLES20Canvas.flushCaches(GLES20Canvas.FLUSH_CACHES_MODERATE);
+                    break;
+                case ComponentCallbacks.TRIM_MEMORY_COMPLETE:
+                    GLES20Canvas.flushCaches(GLES20Canvas.FLUSH_CACHES_FULL);
+                    break;
+            }
+        }
     }
 }
diff --git a/core/java/android/view/WindowManagerImpl.java b/core/java/android/view/WindowManagerImpl.java
index 54e7c04..4e9531b 100644
--- a/core/java/android/view/WindowManagerImpl.java
+++ b/core/java/android/view/WindowManagerImpl.java
@@ -16,18 +16,16 @@
 
 package android.view;
 
-import java.util.HashMap;
-
 import android.content.res.CompatibilityInfo;
 import android.content.res.Configuration;
 import android.graphics.PixelFormat;
 import android.os.IBinder;
 import android.util.AndroidRuntimeException;
 import android.util.Log;
-import android.util.Slog;
-import android.view.WindowManager;
 import android.view.inputmethod.InputMethodManager;
 
+import java.util.HashMap;
+
 final class WindowLeaked extends AndroidRuntimeException {
     public WindowLeaked(String msg) {
         super(msg);
@@ -402,7 +400,16 @@
             }
         }
     }
-    
+
+    /**
+     * @param level See {@link android.content.ComponentCallbacks}
+     */
+    public void trimMemory(int level) {
+        if (HardwareRenderer.isAvailable()) {
+            HardwareRenderer.trimMemory(level);
+        }
+    }
+
     public void setStoppedState(IBinder token, boolean stopped) {
         synchronized (this) {
             if (mViews == null)
@@ -456,8 +463,7 @@
         return new Display(Display.DEFAULT_DISPLAY, null);
     }
 
-    private static void removeItem(Object[] dst, Object[] src, int index)
-    {
+    private static void removeItem(Object[] dst, Object[] src, int index) {
         if (dst.length > 0) {
             if (index > 0) {
                 System.arraycopy(src, 0, dst, 0, index);
@@ -468,8 +474,7 @@
         }
     }
 
-    private int findViewLocked(View view, boolean required)
-    {
+    private int findViewLocked(View view, boolean required) {
         synchronized (this) {
             final int count = mViews != null ? mViews.length : 0;
             for (int i=0; i<count; i++) {
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index 681f43f..d30e0ae 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -127,6 +127,13 @@
     }
 }
 
+static void android_view_GLES20Canvas_flushCaches(JNIEnv* env, jobject clazz,
+        Caches::FlushMode mode) {
+    if (Caches::hasInstance()) {
+        Caches::getInstance().flush(mode);
+    }
+}
+
 // ----------------------------------------------------------------------------
 // Constructors
 // ----------------------------------------------------------------------------
@@ -735,6 +742,7 @@
     { "nIsBackBufferPreserved", "()Z",         (void*) android_view_GLES20Canvas_isBackBufferPreserved },
     { "nPreserveBackBuffer",    "()Z",         (void*) android_view_GLES20Canvas_preserveBackBuffer },
     { "nDisableVsync",          "()V",         (void*) android_view_GLES20Canvas_disableVsync },
+    { "nFlushCaches",           "(I)V",        (void*) android_view_GLES20Canvas_flushCaches },
 
     { "nCreateRenderer",    "()I",             (void*) android_view_GLES20Canvas_createRenderer },
     { "nDestroyRenderer",   "(I)V",            (void*) android_view_GLES20Canvas_destroyRenderer },
diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp
index e232ddd..7114b6a 100644
--- a/libs/hwui/Caches.cpp
+++ b/libs/hwui/Caches.cpp
@@ -33,6 +33,16 @@
 namespace uirenderer {
 
 ///////////////////////////////////////////////////////////////////////////////
+// Macros
+///////////////////////////////////////////////////////////////////////////////
+
+#if DEBUG_CACHE_FLUSH
+    #define FLUSH_LOGD(...) LOGD(__VA_ARGS__)
+#else
+    #define FLUSH_LOGD(...)
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
 // Constructors/destructor
 ///////////////////////////////////////////////////////////////////////////////
 
@@ -150,6 +160,30 @@
     mLayerGarbage.push(layer);
 }
 
+void Caches::flush(FlushMode mode) {
+    FLUSH_LOGD("Flushing caches (mode %d)", mode);
+
+    clearGarbage();
+
+    switch (mode) {
+        case kFlushMode_Full:
+            textureCache.clear();
+            patchCache.clear();
+            dropShadowCache.clear();
+            gradientCache.clear();
+            // fall through
+        case kFlushMode_Moderate:
+            layerCache.clear();
+            pathCache.clear();
+            roundRectShapeCache.clear();
+            circleShapeCache.clear();
+            ovalShapeCache.clear();
+            rectShapeCache.clear();
+            arcShapeCache.clear();
+            break;
+    }
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 // VBO
 ///////////////////////////////////////////////////////////////////////////////
diff --git a/libs/hwui/Caches.h b/libs/hwui/Caches.h
index e64d8ac..76dff4b 100644
--- a/libs/hwui/Caches.h
+++ b/libs/hwui/Caches.h
@@ -100,6 +100,18 @@
     Vector<Layer*> mLayerGarbage;
 
 public:
+    enum FlushMode {
+        kFlushMode_Moderate = 0,
+        kFlushMode_Full
+    };
+
+    /**
+     * Flush the cache.
+     *
+     * @param mode Indicates how much of the cache should be flushed
+     */
+    void flush(FlushMode mode);
+
     /**
      * Indicates whether the renderer is in debug mode.
      * This debug mode provides limited information to app developers.
diff --git a/libs/hwui/Debug.h b/libs/hwui/Debug.h
index 2cdc8c3..5db73db 100644
--- a/libs/hwui/Debug.h
+++ b/libs/hwui/Debug.h
@@ -26,6 +26,9 @@
 // Turn on to enable memory usage summary on each frame
 #define DEBUG_MEMORY_USAGE 0
 
+// Turn on to enable debugging of cache flushes
+#define DEBUG_CACHE_FLUSH 1
+
 // Turn on to enable layers debugging when rendered as regions
 #define DEBUG_LAYERS_AS_REGIONS 0