Fix issue #3485923: Gmail crash

Allow application to try to recover if a surface OOM error
happens on the client side.

Change-Id: I0308bd99647a35e4bcac448340b7fc6330a828f6
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index b5d84e8..eed41a0 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -2717,6 +2717,22 @@
                 | (displayed ? WindowManagerImpl.RELAYOUT_FIRST_TIME : 0);
     }
 
+    public boolean outOfMemoryWindow(Session session, IWindow client) {
+        long origId = Binder.clearCallingIdentity();
+
+        try {
+            synchronized(mWindowMap) {
+                WindowState win = windowForClientLocked(session, client, false);
+                if (win == null) {
+                    return false;
+                }
+                return reclaimSomeSurfaceMemoryLocked(win, "from-client", false);
+            }
+        } finally {
+            Binder.restoreCallingIdentity(origId);
+        }
+    }
+
     public void finishDrawingWindow(Session session, IWindow client) {
         final long origId = Binder.clearCallingIdentity();
         synchronized(mWindowMap) {
@@ -7443,7 +7459,7 @@
                                         + " pos=(" + w.mShownFrame.left
                                         + "," + w.mShownFrame.top + ")", e);
                                 if (!recoveringMemory) {
-                                    reclaimSomeSurfaceMemoryLocked(w, "position");
+                                    reclaimSomeSurfaceMemoryLocked(w, "position", true);
                                 }
                             }
                         }
@@ -7471,7 +7487,7 @@
                                 Slog.e(TAG, "Error resizing surface of " + w
                                         + " size=(" + width + "x" + height + ")", e);
                                 if (!recoveringMemory) {
-                                    reclaimSomeSurfaceMemoryLocked(w, "size");
+                                    reclaimSomeSurfaceMemoryLocked(w, "size", true);
                                 }
                             }
                         }
@@ -7618,7 +7634,7 @@
                             } catch (RuntimeException e) {
                                 Slog.w(TAG, "Error updating surface in " + w, e);
                                 if (!recoveringMemory) {
-                                    reclaimSomeSurfaceMemoryLocked(w, "update");
+                                    reclaimSomeSurfaceMemoryLocked(w, "update", true);
                                 }
                             }
                         }
@@ -8077,13 +8093,15 @@
             Slog.w(TAG, "Failure showing surface " + win.mSurface + " in " + win, e);
         }
 
-        reclaimSomeSurfaceMemoryLocked(win, "show");
+        reclaimSomeSurfaceMemoryLocked(win, "show", true);
 
         return false;
     }
 
-    void reclaimSomeSurfaceMemoryLocked(WindowState win, String operation) {
+    boolean reclaimSomeSurfaceMemoryLocked(WindowState win, String operation, boolean secure) {
         final Surface surface = win.mSurface;
+        boolean leakedSurface = false;
+        boolean killedApps = false;
 
         EventLog.writeEvent(EventLogTags.WM_NO_SURFACE_MEMORY, win.toString(),
                 win.mSession.mPid, operation);
@@ -8098,7 +8116,6 @@
             // window list to make sure we haven't left any dangling surfaces
             // around.
             int N = mWindows.size();
-            boolean leakedSurface = false;
             Slog.i(TAG, "Out of memory for surface!  Looking for leaks...");
             for (int i=0; i<N; i++) {
                 WindowState ws = mWindows.get(i);
@@ -8130,7 +8147,6 @@
                 }
             }
 
-            boolean killedApps = false;
             if (!leakedSurface) {
                 Slog.w(TAG, "No leaked surfaces; killing applicatons!");
                 SparseIntArray pidCandidates = new SparseIntArray();
@@ -8146,7 +8162,7 @@
                         pids[i] = pidCandidates.keyAt(i);
                     }
                     try {
-                        if (mActivityManager.killPids(pids, "Free memory")) {
+                        if (mActivityManager.killPids(pids, "Free memory", secure)) {
                             killedApps = true;
                         }
                     } catch (RemoteException e) {
@@ -8173,6 +8189,8 @@
         } finally {
             Binder.restoreCallingIdentity(callingIdentity);
         }
+
+        return leakedSurface || killedApps;
     }
 
     private boolean updateFocusedWindowLocked(int mode, boolean updateInputWindows) {