diff options
author | 2016-07-22 17:07:44 +0000 | |
---|---|---|
committer | 2016-07-22 17:07:45 +0000 | |
commit | e86da3bc62e2ec650d69477ab7655aa7255be473 (patch) | |
tree | 974041d62b5b1009f2ac92ad266edafa68802596 | |
parent | 1dcda854141d2660ec151e45c9336512f87c0832 (diff) | |
parent | 45e6d2dc8b8b7bd4e588368179d8d4b05fc6810c (diff) |
Merge "Clean up surfaces when app is resumed without being stopped." into nyc-mr1-dev
5 files changed, 77 insertions, 22 deletions
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl index 9bc0bb4b38f7..06012198333c 100644 --- a/core/java/android/view/IWindowManager.aidl +++ b/core/java/android/view/IWindowManager.aidl @@ -173,7 +173,8 @@ interface IWindowManager in CompatibilityInfo compatInfo, CharSequence nonLocalizedLabel, int labelRes, int icon, int logo, int windowFlags, IBinder transferFrom, boolean createIfNeeded); void setAppVisibility(IBinder token, boolean visible); - void notifyAppStopped(IBinder token, boolean stopped); + void notifyAppResumed(IBinder token, boolean wasStopped); + void notifyAppStopped(IBinder token); void startAppFreezingScreen(IBinder token, int configChanges); void stopAppFreezingScreen(IBinder token, boolean force); void removeAppToken(IBinder token); diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java index eb02dc34e1a2..752dbd95c4c2 100644 --- a/services/core/java/com/android/server/am/ActivityStack.java +++ b/services/core/java/com/android/server/am/ActivityStack.java @@ -1249,7 +1249,7 @@ final class ActivityStack { r.stopped = true; r.state = ActivityState.STOPPED; - mWindowManager.notifyAppStopped(r.appToken, true); + mWindowManager.notifyAppStopped(r.appToken); if (getVisibleBehindActivity() == r) { mStackSupervisor.requestVisibleBehindLocked(r, false); @@ -2490,7 +2490,7 @@ final class ActivityStack { // Well the app will no longer be stopped. // Clear app token stopped state in window manager if needed. - mWindowManager.notifyAppStopped(next.appToken, false); + mWindowManager.notifyAppResumed(next.appToken, next.stopped); EventLog.writeEvent(EventLogTags.AM_RESUME_ACTIVITY, next.userId, System.identityHashCode(next), next.task.taskId, next.shortComponentName); diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java index 66e9fd8659d5..eac72b01c8f9 100644 --- a/services/core/java/com/android/server/wm/AppWindowToken.java +++ b/services/core/java/com/android/server/wm/AppWindowToken.java @@ -337,21 +337,41 @@ class AppWindowToken extends WindowToken { } } - // Here we destroy surfaces which have been marked as eligible by the animator, taking care - // to ensure the client has finished with them. If the client could still be using them - // we will skip destruction and try again when the client has stopped. void destroySurfaces() { + destroySurfaces(false /*cleanupOnResume*/); + } + + /** + * Destroy surfaces which have been marked as eligible by the animator, taking care to ensure + * the client has finished with them. + * + * @param cleanupOnResume whether this is done when app is resumed without fully stopped. If + * set to true, destroy only surfaces of removed windows, and clear relevant flags of the + * others so that they are ready to be reused. If set to false (common case), destroy all + * surfaces that's eligible, if the app is already stopped. + */ + + private void destroySurfaces(boolean cleanupOnResume) { final ArrayList<WindowState> allWindows = (ArrayList<WindowState>) allAppWindows.clone(); final DisplayContentList displayList = new DisplayContentList(); for (int i = allWindows.size() - 1; i >= 0; i--) { final WindowState win = allWindows.get(i); - if (!(mAppStopped || win.mWindowRemovalAllowed)) { + if (!(mAppStopped || win.mWindowRemovalAllowed || cleanupOnResume)) { continue; } win.mWinAnimator.destroyPreservedSurfaceLocked(); + if (cleanupOnResume) { + // If the window has an unfinished exit animation, consider that animation + // done and mark the window destroying so that it goes through the cleanup. + if (win.mAnimatingExit) { + win.mDestroying = true; + win.mAnimatingExit = false; + } + } + if (!win.mDestroying) { continue; } @@ -361,7 +381,9 @@ class AppWindowToken extends WindowToken { + " win.mWindowRemovalAllowed=" + win.mWindowRemovalAllowed + " win.mRemoveOnExit=" + win.mRemoveOnExit); - win.destroyOrSaveSurface(); + if (!cleanupOnResume || win.mRemoveOnExit) { + win.destroyOrSaveSurface(); + } if (win.mRemoveOnExit) { service.removeWindowInnerLocked(win); } @@ -379,21 +401,30 @@ class AppWindowToken extends WindowToken { } /** - * If the application has stopped it is okay to destroy any surfaces which were keeping alive - * in case they were still being used. + * Notify that the app is now resumed, and it was not stopped before, perform a clean + * up of the surfaces */ - void notifyAppStopped(boolean stopped) { - if (DEBUG_ADD_REMOVE) Slog.v(TAG, "notifyAppStopped: stopped=" + stopped + " " + this); - mAppStopped = stopped; - - if (stopped) { - destroySurfaces(); - // Remove any starting window that was added for this app if they are still around. - mTask.mService.scheduleRemoveStartingWindowLocked(this); + void notifyAppResumed(boolean wasStopped) { + if (DEBUG_ADD_REMOVE) Slog.v(TAG, "notifyAppResumed: wasStopped=" + wasStopped + " " + this); + mAppStopped = false; + if (!wasStopped) { + destroySurfaces(true /*cleanupOnResume*/); } } /** + * Notify that the app has stopped, and it is okay to destroy any surfaces which were + * keeping alive in case they were still being used. + */ + void notifyAppStopped() { + if (DEBUG_ADD_REMOVE) Slog.v(TAG, "notifyAppStopped: " + this); + mAppStopped = true; + destroySurfaces(); + // Remove any starting window that was added for this app if they are still around. + mTask.mService.scheduleRemoveStartingWindowLocked(this); + } + + /** * Checks whether we should save surfaces for this app. * * @return true if the surfaces should be saved, false otherwise. diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index d8a45387c5bf..8c5481d1a4d8 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -4476,7 +4476,25 @@ public class WindowManagerService extends IWindowManager.Stub } @Override - public void notifyAppStopped(IBinder token, boolean stopped) { + public void notifyAppResumed(IBinder token, boolean wasStopped) { + if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS, + "notifyAppResumed()")) { + throw new SecurityException("Requires MANAGE_APP_TOKENS permission"); + } + + synchronized(mWindowMap) { + final AppWindowToken wtoken; + wtoken = findAppWindowToken(token); + if (wtoken == null) { + Slog.w(TAG_WM, "Attempted to notify resumed of non-existing app token: " + token); + return; + } + wtoken.notifyAppResumed(wasStopped); + } + } + + @Override + public void notifyAppStopped(IBinder token) { if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS, "notifyAppStopped()")) { throw new SecurityException("Requires MANAGE_APP_TOKENS permission"); @@ -4486,10 +4504,10 @@ public class WindowManagerService extends IWindowManager.Stub final AppWindowToken wtoken; wtoken = findAppWindowToken(token); if (wtoken == null) { - Slog.w(TAG_WM, "Attempted to set visibility of non-existing app token: " + token); + Slog.w(TAG_WM, "Attempted to notify stopped of non-existing app token: " + token); return; } - wtoken.notifyAppStopped(stopped); + wtoken.notifyAppStopped(); } } diff --git a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java index 49ab9f911833..5a9860d5c80a 100644 --- a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java +++ b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java @@ -351,7 +351,12 @@ public class IWindowManagerImpl implements IWindowManager { } @Override - public void notifyAppStopped(IBinder token, boolean stopped) throws RemoteException { + public void notifyAppResumed(IBinder token, boolean wasStopped) throws RemoteException { + // TODO Auto-generated method stub + } + + @Override + public void notifyAppStopped(IBinder token) throws RemoteException { // TODO Auto-generated method stub } |