summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/app/ActivityManagerNative.java6
-rw-r--r--core/java/android/app/IActivityManager.java2
-rw-r--r--core/java/android/view/HardwareRenderer.java16
-rw-r--r--core/java/android/view/IWindowSession.aidl5
-rw-r--r--core/java/android/view/ViewRoot.java66
-rw-r--r--services/java/com/android/server/MountService.java2
-rw-r--r--services/java/com/android/server/am/ActivityManagerService.java11
-rw-r--r--services/java/com/android/server/wm/Session.java4
-rw-r--r--services/java/com/android/server/wm/WindowManagerService.java34
-rw-r--r--services/java/com/android/server/wm/WindowState.java4
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java4
11 files changed, 122 insertions, 32 deletions
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index d3d379294789..64266354edcc 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -1020,7 +1020,8 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM
data.enforceInterface(IActivityManager.descriptor);
int[] pids = data.createIntArray();
String reason = data.readString();
- boolean res = killPids(pids, reason);
+ boolean secure = data.readInt() != 0;
+ boolean res = killPids(pids, reason, secure);
reply.writeNoException();
reply.writeInt(res ? 1 : 0);
return true;
@@ -2636,12 +2637,13 @@ class ActivityManagerProxy implements IActivityManager
mRemote.transact(NOTE_WAKEUP_ALARM_TRANSACTION, data, null, 0);
data.recycle();
}
- public boolean killPids(int[] pids, String reason) throws RemoteException {
+ public boolean killPids(int[] pids, String reason, boolean secure) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
data.writeIntArray(pids);
data.writeString(reason);
+ data.writeInt(secure ? 1 : 0);
mRemote.transact(KILL_PIDS_TRANSACTION, data, reply, 0);
boolean res = reply.readInt() != 0;
data.recycle();
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index f42e8fb73e86..61e6fc8466c2 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -250,7 +250,7 @@ public interface IActivityManager extends IInterface {
public void noteWakeupAlarm(IIntentSender sender) throws RemoteException;
- public boolean killPids(int[] pids, String reason) throws RemoteException;
+ public boolean killPids(int[] pids, String reason, boolean secure) throws RemoteException;
// Special low-level communication with activity manager.
public void startRunning(String pkg, String cls, String action,
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index d46dacc2e55d..b53aa21b955b 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -108,14 +108,14 @@ public abstract class HardwareRenderer {
*
* @return True if the initialization was successful, false otherwise.
*/
- abstract boolean initialize(SurfaceHolder holder);
+ abstract boolean initialize(SurfaceHolder holder) throws Surface.OutOfResourcesException;
/**
* Updates the hardware renderer for the specified surface.
*
* @param holder The holder for the surface to hardware accelerate.
*/
- abstract void updateSurface(SurfaceHolder holder);
+ abstract void updateSurface(SurfaceHolder holder) throws Surface.OutOfResourcesException;
/**
* Setup the hardware renderer for drawing. This is called for every
@@ -189,7 +189,7 @@ public abstract class HardwareRenderer {
* @param holder
*/
void initializeIfNeeded(int width, int height, View.AttachInfo attachInfo,
- SurfaceHolder holder) {
+ SurfaceHolder holder) throws Surface.OutOfResourcesException {
if (isRequested()) {
// We lost the gl context, so recreate it.
if (!isEnabled()) {
@@ -366,7 +366,7 @@ public abstract class HardwareRenderer {
}
@Override
- boolean initialize(SurfaceHolder holder) {
+ boolean initialize(SurfaceHolder holder) throws Surface.OutOfResourcesException {
if (isRequested() && !isEnabled()) {
initializeEgl();
mGl = createEglSurface(holder);
@@ -395,7 +395,7 @@ public abstract class HardwareRenderer {
}
@Override
- void updateSurface(SurfaceHolder holder) {
+ void updateSurface(SurfaceHolder holder) throws Surface.OutOfResourcesException {
if (isRequested() && isEnabled()) {
createEglSurface(holder);
}
@@ -446,7 +446,7 @@ public abstract class HardwareRenderer {
sEglContext = createContext(sEgl, sEglDisplay, sEglConfig);
}
- GL createEglSurface(SurfaceHolder holder) {
+ GL createEglSurface(SurfaceHolder holder) throws Surface.OutOfResourcesException {
// Check preconditions.
if (sEgl == null) {
throw new RuntimeException("egl not initialized");
@@ -494,7 +494,7 @@ public abstract class HardwareRenderer {
* the context is current and bound to a surface.
*/
if (!sEgl.eglMakeCurrent(sEglDisplay, mEglSurface, mEglSurface, sEglContext)) {
- throw new RuntimeException("eglMakeCurrent failed "
+ throw new Surface.OutOfResourcesException("eglMakeCurrent failed "
+ getEGLErrorString(sEgl.eglGetError()));
}
@@ -516,7 +516,7 @@ public abstract class HardwareRenderer {
@Override
void initializeIfNeeded(int width, int height, View.AttachInfo attachInfo,
- SurfaceHolder holder) {
+ SurfaceHolder holder) throws Surface.OutOfResourcesException {
if (isRequested()) {
checkEglErrors();
super.initializeIfNeeded(width, height, attachInfo, holder);
diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl
index 1218e81d7708..990af083d859 100644
--- a/core/java/android/view/IWindowSession.aidl
+++ b/core/java/android/view/IWindowSession.aidl
@@ -84,6 +84,11 @@ interface IWindowSession {
out Surface outSurface);
/**
+ * Called by a client to report that it ran out of graphics memory.
+ */
+ boolean outOfMemory(IWindow window);
+
+ /**
* Give the window manager a hint of the part of the window that is
* completely transparent, allowing it to work with the surface flinger
* to optimize compositing of this part of the window.
diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java
index 965c959f2db4..546823047b24 100644
--- a/core/java/android/view/ViewRoot.java
+++ b/core/java/android/view/ViewRoot.java
@@ -1066,7 +1066,20 @@ public final class ViewRoot extends Handler implements ViewParent,
mPreviousTransparentRegion.setEmpty();
if (mAttachInfo.mHardwareRenderer != null) {
- hwInitialized = mAttachInfo.mHardwareRenderer.initialize(mHolder);
+ try {
+ hwInitialized = mAttachInfo.mHardwareRenderer.initialize(mHolder);
+ } catch (Surface.OutOfResourcesException e) {
+ Log.e(TAG, "OutOfResourcesException initializing HW surface", e);
+ try {
+ if (!sWindowSession.outOfMemory(mWindow)) {
+ Slog.w(TAG, "No processes killed for memory; killing self");
+ Process.killProcess(Process.myPid());
+ }
+ } catch (RemoteException ex) {
+ }
+ mLayoutRequested = true; // ask wm for a new surface next time.
+ return;
+ }
}
}
} else if (!mSurface.isValid()) {
@@ -1081,7 +1094,20 @@ public final class ViewRoot extends Handler implements ViewParent,
} else if (surfaceGenerationId != mSurface.getGenerationId() &&
mSurfaceHolder == null && mAttachInfo.mHardwareRenderer != null) {
fullRedrawNeeded = true;
- mAttachInfo.mHardwareRenderer.updateSurface(mHolder);
+ try {
+ mAttachInfo.mHardwareRenderer.updateSurface(mHolder);
+ } catch (Surface.OutOfResourcesException e) {
+ Log.e(TAG, "OutOfResourcesException updating HW surface", e);
+ try {
+ if (!sWindowSession.outOfMemory(mWindow)) {
+ Slog.w(TAG, "No processes killed for memory; killing self");
+ Process.killProcess(Process.myPid());
+ }
+ } catch (RemoteException ex) {
+ }
+ mLayoutRequested = true; // ask wm for a new surface next time.
+ return;
+ }
}
} catch (RemoteException e) {
}
@@ -1569,14 +1595,24 @@ public final class ViewRoot extends Handler implements ViewParent,
canvas.setDensity(mDensity);
} catch (Surface.OutOfResourcesException e) {
Log.e(TAG, "OutOfResourcesException locking surface", e);
- // TODO: we should ask the window manager to do something!
- // for now we just do nothing
+ try {
+ if (!sWindowSession.outOfMemory(mWindow)) {
+ Slog.w(TAG, "No processes killed for memory; killing self");
+ Process.killProcess(Process.myPid());
+ }
+ } catch (RemoteException ex) {
+ }
mLayoutRequested = true; // ask wm for a new surface next time.
return;
} catch (IllegalArgumentException e) {
Log.e(TAG, "IllegalArgumentException locking surface", e);
- // TODO: we should ask the window manager to do something!
- // for now we just do nothing
+ try {
+ if (!sWindowSession.outOfMemory(mWindow)) {
+ Slog.w(TAG, "No processes killed for memory; killing self");
+ Process.killProcess(Process.myPid());
+ }
+ } catch (RemoteException ex) {
+ }
mLayoutRequested = true; // ask wm for a new surface next time.
return;
}
@@ -2033,8 +2069,22 @@ public final class ViewRoot extends Handler implements ViewParent,
if (mAttachInfo.mHardwareRenderer != null &&
mSurface != null && mSurface.isValid()) {
mFullRedrawNeeded = true;
- mAttachInfo.mHardwareRenderer.initializeIfNeeded(mWidth, mHeight,
- mAttachInfo, mHolder);
+ try {
+ mAttachInfo.mHardwareRenderer.initializeIfNeeded(mWidth, mHeight,
+ mAttachInfo, mHolder);
+ } catch (Surface.OutOfResourcesException e) {
+ Log.e(TAG, "OutOfResourcesException locking surface", e);
+ try {
+ if (!sWindowSession.outOfMemory(mWindow)) {
+ Slog.w(TAG, "No processes killed for memory; killing self");
+ Process.killProcess(Process.myPid());
+ }
+ } catch (RemoteException ex) {
+ }
+ // Retry in a bit.
+ sendMessageDelayed(obtainMessage(msg.what, msg.arg1, msg.arg2), 500);
+ return;
+ }
}
}
diff --git a/services/java/com/android/server/MountService.java b/services/java/com/android/server/MountService.java
index 436eff0befbe..91ada6bf52b1 100644
--- a/services/java/com/android/server/MountService.java
+++ b/services/java/com/android/server/MountService.java
@@ -374,7 +374,7 @@ class MountService extends IMountService.Stub implements INativeDaemonConnectorC
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 40417b18daa9..0fab964b5fd8 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -6189,7 +6189,7 @@ public final class ActivityManagerService extends ActivityManagerNative
}
}
- 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");
}
@@ -6212,11 +6212,18 @@ public final class ActivityManagerService extends ActivityManagerNative
}
}
- // 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 b9db17702a81..0f09356f95e5 100644
--- a/services/java/com/android/server/wm/Session.java
+++ b/services/java/com/android/server/wm/Session.java
@@ -161,6 +161,10 @@ final class Session extends IWindowSession.Stub
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 b5d84e87f382..eed41a0c0e9a 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -2717,6 +2717,22 @@ public class WindowManagerService extends IWindowManager.Stub
| (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 @@ public class WindowManagerService extends IWindowManager.Stub
+ " pos=(" + w.mShownFrame.left
+ "," + w.mShownFrame.top + ")", e);
if (!recoveringMemory) {
- reclaimSomeSurfaceMemoryLocked(w, "position");
+ reclaimSomeSurfaceMemoryLocked(w, "position", true);
}
}
}
@@ -7471,7 +7487,7 @@ public class WindowManagerService extends IWindowManager.Stub
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 @@ public class WindowManagerService extends IWindowManager.Stub
} 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 @@ public class WindowManagerService extends IWindowManager.Stub
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 @@ public class WindowManagerService extends IWindowManager.Stub
// 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 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
- boolean killedApps = false;
if (!leakedSurface) {
Slog.w(TAG, "No leaked surfaces; killing applicatons!");
SparseIntArray pidCandidates = new SparseIntArray();
@@ -8146,7 +8162,7 @@ public class WindowManagerService extends IWindowManager.Stub
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 @@ public class WindowManagerService extends IWindowManager.Stub
} 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 d0eec898c3af..f8ff5f8133b6 100644
--- a/services/java/com/android/server/wm/WindowState.java
+++ b/services/java/com/android/server/wm/WindowState.java
@@ -594,7 +594,7 @@ final class WindowState implements WindowManagerPolicy.WindowState {
+ " / " + 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 @@ final class WindowState implements WindowManagerPolicy.WindowState {
}
} 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 {
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java
index 8422d4890b0a..ab8c4ec75152 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java
@@ -85,6 +85,10 @@ public final class BridgeWindowSession implements IWindowSession {
return 0;
}
+ public boolean outOfMemory(IWindow window) throws RemoteException {
+ return false;
+ }
+
public void getDisplayFrame(IWindow window, Rect outDisplayFrame) {
// pass for now.
}