Ensure surfaces stay alive until activity stop.

am: e12aece4ca

* commit 'e12aece4cad849efbbe6a806f132613a56699230':
  Ensure surfaces stay alive until activity stop.
This commit is contained in:
Robert Carr
2016-02-08 20:56:09 +00:00
committed by android-build-merger
7 changed files with 110 additions and 9 deletions

View File

@@ -166,6 +166,7 @@ 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);
void startAppFreezingScreen(IBinder token, int configChanges);
void stopAppFreezingScreen(IBinder token, boolean force);
void removeAppToken(IBinder token);

View File

@@ -1097,6 +1097,9 @@ final class ActivityStack {
mHandler.removeMessages(STOP_TIMEOUT_MSG, r);
r.stopped = true;
r.state = ActivityState.STOPPED;
mWindowManager.notifyAppStopped(r.appToken);
if (getVisibleBehindActivity() == r) {
mStackSupervisor.requestVisibleBehindLocked(r, false);
}

View File

@@ -127,6 +127,8 @@ class AppWindowToken extends WindowToken {
boolean mAlwaysFocusable;
boolean mAppStopped;
ArrayDeque<Rect> mFrozenBounds = new ArrayDeque<>();
AppWindowToken(WindowManagerService _service, IApplicationToken _token,
@@ -311,6 +313,47 @@ 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() {
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 (!win.mDestroying) {
continue;
}
if (!mAppStopped && !win.mClientRemoveRequested) {
return;
}
win.destroyOrSaveSurface();
if (win.mRemoveOnExit) {
win.mExiting = false;
service.removeWindowInnerLocked(win);
}
final DisplayContent displayContent = win.getDisplayContent();
if (displayContent != null && !displayList.contains(displayContent)) {
displayList.add(displayContent);
}
win.mDestroying = false;
}
for (int i = 0; i < displayList.size(); i++) {
final DisplayContent displayContent = displayList.get(i);
service.mLayersController.assignLayersLocked(displayContent.getWindowList());
displayContent.layoutNeeded = true;
}
}
// The application has stopped, so destroy any surfaces which were keeping alive
// in case they were still being used.
void notifyAppStopped() {
mAppStopped = true;
destroySurfaces();
}
/**
* Checks whether we should save surfaces for this app.
*

View File

@@ -2154,6 +2154,14 @@ public class WindowManagerService extends IWindowManager.Stub
if (win == null) {
return;
}
// We set this here instead of removeWindowLocked because we only want it to be
// true when the client has requested we remove the window. In other remove
// cases, we have to wait for activity stop to safely remove the window (as the
// client may still be using the surface). In this case though, the client has
// just dismissed a window (for example a Dialog) and activity stop isn't
// necessarily imminent, so we need to know not to wait for it after our
// hanimation (if applicable) finishes.
win.mClientRemoveRequested = true;
removeWindowLocked(win);
}
}
@@ -4187,6 +4195,24 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
@Override
public void notifyAppStopped(IBinder token) {
if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
"notifyAppStopped()")) {
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 set visibility of non-existing app token: " + token);
return;
}
wtoken.notifyAppStopped();
}
}
@Override
public void setAppVisibility(IBinder token, boolean visible) {
if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
@@ -4210,6 +4236,7 @@ public class WindowManagerService extends IWindowManager.Stub
mOpeningApps.remove(wtoken);
mClosingApps.remove(wtoken);
wtoken.mAppStopped = false;
wtoken.waitingToShow = false;
wtoken.hiddenRequested = !visible;

View File

@@ -385,6 +385,13 @@ final class WindowState implements WindowManagerPolicy.WindowState {
/** Is this window now (or just being) removed? */
boolean mRemoved;
/**
* Has the client requested we remove the window? In this case we know
* that we can dispose of it when we wish without further synchronization
* with the client
*/
boolean mClientRemoveRequested;
/**
* Temp for keeping track of windows that have been removed when
* rebuilding window list.

View File

@@ -471,16 +471,31 @@ class WindowStateAnimator {
if (WindowManagerService.localLOGV) Slog.v(
TAG, "Exit animation finished in " + this
+ ": remove=" + mWin.mRemoveOnExit);
if (hasSurface()) {
mService.mDestroySurface.add(mWin);
mWin.mDestroying = true;
hide("finishExit");
}
mWin.mExiting = false;
if (mWin.mRemoveOnExit) {
mService.mPendingRemove.add(mWin);
mWin.mRemoveOnExit = false;
mWin.mDestroying = true;
// If we have an app token, we ask it to destroy the surface for us,
// so that it can take care to ensure the activity has actually stopped
// and the surface is not still in use. Otherwise we add the service to
// mDestroySurface and allow it to be processed in our next transaction.
if (mWin.mAppToken != null) {
if (hasSurface()) {
hide("finishExit");
}
mWin.mAppToken.destroySurfaces();
} else {
if (hasSurface()) {
mService.mDestroySurface.add(mWin);
hide("finishExit");
}
mWin.mExiting = false;
if (mWin.mRemoveOnExit) {
mService.mPendingRemove.add(mWin);
mWin.mRemoveOnExit = false;
}
}
mWallpaperControllerLocked.hideWallpapers(mWin);
}

View File

@@ -347,6 +347,11 @@ public class IWindowManagerImpl implements IWindowManager {
}
@Override
public void notifyAppStopped(IBinder token) throws RemoteException {
// TODO Auto-generated method stub
}
@Override
public void setEventDispatching(boolean arg0) throws RemoteException {
// TODO Auto-generated method stub