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/MountService.java b/services/java/com/android/server/MountService.java
index 436eff0..91ada6b 100644
--- a/services/java/com/android/server/MountService.java
+++ b/services/java/com/android/server/MountService.java
@@ -374,7 +374,7 @@
done = true;
} else {
// Eliminate system process here?
- ams.killPids(pids, "unmount media");
+ ams.killPids(pids, "unmount media", true);
// Confirm if file references have been freed.
pids = getStorageUsers(path);
if (pids == null || pids.length == 0) {
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index e6dfb7f..2eafc1d 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -6184,7 +6184,7 @@
}
}
- public boolean killPids(int[] pids, String pReason) {
+ public boolean killPids(int[] pids, String pReason, boolean secure) {
if (Binder.getCallingUid() != Process.SYSTEM_UID) {
throw new SecurityException("killPids only available to the system");
}
@@ -6207,11 +6207,18 @@
}
}
- // If the worse oom_adj is somewhere in the hidden proc LRU range,
+ // If the worst oom_adj is somewhere in the hidden proc LRU range,
// then constrain it so we will kill all hidden procs.
if (worstType < EMPTY_APP_ADJ && worstType > HIDDEN_APP_MIN_ADJ) {
worstType = HIDDEN_APP_MIN_ADJ;
}
+
+ // If this is not a secure call, don't let it kill processes that
+ // are important.
+ if (!secure && worstType < SECONDARY_SERVER_ADJ) {
+ worstType = SECONDARY_SERVER_ADJ;
+ }
+
Slog.w(TAG, "Killing processes " + reason + " at adjustment " + worstType);
for (int i=0; i<pids.length; i++) {
ProcessRecord proc = mPidsSelfLocked.get(pids[i]);
diff --git a/services/java/com/android/server/wm/Session.java b/services/java/com/android/server/wm/Session.java
index b9db177..0f09356 100644
--- a/services/java/com/android/server/wm/Session.java
+++ b/services/java/com/android/server/wm/Session.java
@@ -161,6 +161,10 @@
return res;
}
+ public boolean outOfMemory(IWindow window) {
+ return mService.outOfMemoryWindow(this, window);
+ }
+
public void setTransparentRegion(IWindow window, Region region) {
mService.setTransparentRegionWindow(this, window, region);
}
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) {
diff --git a/services/java/com/android/server/wm/WindowState.java b/services/java/com/android/server/wm/WindowState.java
index d0eec89..f8ff5f8 100644
--- a/services/java/com/android/server/wm/WindowState.java
+++ b/services/java/com/android/server/wm/WindowState.java
@@ -594,7 +594,7 @@
+ " / " + this);
} catch (Surface.OutOfResourcesException e) {
Slog.w(WindowManagerService.TAG, "OutOfResourcesException creating surface");
- mService.reclaimSomeSurfaceMemoryLocked(this, "create");
+ mService.reclaimSomeSurfaceMemoryLocked(this, "create", true);
return null;
} catch (Exception e) {
Slog.e(WindowManagerService.TAG, "Exception creating surface", e);
@@ -628,7 +628,7 @@
}
} catch (RuntimeException e) {
Slog.w(WindowManagerService.TAG, "Error creating surface in " + w, e);
- mService.reclaimSomeSurfaceMemoryLocked(this, "create-init");
+ mService.reclaimSomeSurfaceMemoryLocked(this, "create-init", true);
}
mLastHidden = true;
} finally {