diff options
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. } |