Do not remove window if IWindow#resized is failed

Even DeadObjectException is thrown, it is not equivalent to the
window is died (transaction failed by small size data will be
DeadObjectException). Sometimes it may be caused by the binder
buffer of process is temporarily full. If the window is removed
directly but the process is still alive, the application client
and window manager are out of sync. Especially if the window is
important system window, e.g. status bar, notification shade,
navigation bar, which might need to reboot to recover. Ideally,
if the process is really dead, there should be a binderDied
callback that also removes the window.

The original purpose of the removal is to avoid display frozen
(e.g. rotation) always timeout which is caused by resetting
WindowState#mOrientationChanging in each layout traversal. Now
the window states are still updated as "resized" has reported,
so it won't block unfreeze display.

Bug: 151814107
Bug: 147448299
Test: atest WindowStateTests#testReportResizedWithRemoteException
Test: Hard code to throw RemoteException for a specified window
      and rotate the display.

Change-Id: Id295456cc99ab9af30aa5fad2eedada6afb862a2
This commit is contained in:
Riddle Hsu
2020-03-31 21:41:18 +08:00
parent 07217a0dac
commit 839b5f55f9
4 changed files with 58 additions and 31 deletions

View File

@@ -25,6 +25,12 @@
"group": "WM_DEBUG_REMOTE_ANIMATIONS",
"at": "com\/android\/server\/wm\/RemoteAnimationController.java"
},
"-2101985723": {
"message": "Failed looking up window session=%s callers=%s",
"level": "WARN",
"group": "WM_ERROR",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
"-2072089308": {
"message": "Attempted to add window with token that is a sub-window: %s. Aborting.",
"level": "WARN",
@@ -301,12 +307,6 @@
"group": "WM_DEBUG_ADD_REMOVE",
"at": "com\/android\/server\/wm\/ActivityRecord.java"
},
"-1455600136": {
"message": "Attempted to add Dream window with unknown token %s. Aborting.",
"level": "WARN",
"group": "WM_ERROR",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
"-1443029505": {
"message": "SAFE MODE ENABLED (menu=%d s=%d dpad=%d trackball=%d)",
"level": "INFO",
@@ -385,12 +385,6 @@
"group": "WM_DEBUG_RESIZE",
"at": "com\/android\/server\/wm\/WindowState.java"
},
"-1263554915": {
"message": "Attempted to add Dream window with bad token %s. Aborting.",
"level": "WARN",
"group": "WM_ERROR",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
"-1263316010": {
"message": "Computed rotation=%s (%d) for display id=%d based on lastOrientation=%s (%d) and oldRotation=%s (%d)",
"level": "VERBOSE",
@@ -673,12 +667,6 @@
"group": "WM_DEBUG_SCREEN_ON",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
"-747671114": {
"message": "Failed looking up window callers=%s",
"level": "WARN",
"group": "WM_ERROR",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
"-714291355": {
"message": "Losing delayed focus: %s",
"level": "INFO",

View File

@@ -5321,7 +5321,8 @@ public class WindowManagerService extends IWindowManager.Stub
throw new IllegalArgumentException(
"Requested window " + client + " does not exist");
}
ProtoLog.w(WM_ERROR, "Failed looking up window callers=%s", Debug.getCallers(3));
ProtoLog.w(WM_ERROR, "Failed looking up window session=%s callers=%s", session,
Debug.getCallers(3));
return null;
}
if (session != null && win.mSession != session) {
@@ -5329,7 +5330,8 @@ public class WindowManagerService extends IWindowManager.Stub
throw new IllegalArgumentException("Requested window " + client + " is in session "
+ win.mSession + ", not " + session);
}
ProtoLog.w(WM_ERROR, "Failed looking up window callers=%s", Debug.getCallers(3));
ProtoLog.w(WM_ERROR, "Failed looking up window session=%s callers=%s", session,
Debug.getCallers(3));
return null;
}

View File

@@ -3440,13 +3440,23 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
getMergedConfiguration(mLastReportedConfiguration);
mLastConfigReportedToClient = true;
final boolean reportOrientation = mReportOrientationChanged;
// Always reset these states first, so if {@link IWindow#resized} fails, this
// window won't be added to {@link WindowManagerService#mResizingWindows} and set
// {@link #mOrientationChanging} to true again by {@link #updateResizingWindowIfNeeded}
// that may cause WINDOW_FREEZE_TIMEOUT because resizing the client keeps failing.
mReportOrientationChanged = false;
mDragResizingChangeReported = true;
mWinAnimator.mSurfaceResized = false;
mWindowFrames.resetInsetsChanged();
final Rect frame = mWindowFrames.mCompatFrame;
final Rect contentInsets = mWindowFrames.mLastContentInsets;
final Rect visibleInsets = mWindowFrames.mLastVisibleInsets;
final Rect stableInsets = mWindowFrames.mLastStableInsets;
final MergedConfiguration mergedConfiguration = mLastReportedConfiguration;
final boolean reportDraw = mWinAnimator.mDrawState == DRAW_PENDING;
final boolean forceRelayout = mReportOrientationChanged || isDragResizeChanged();
final boolean forceRelayout = reportOrientation || isDragResizeChanged();
final int displayId = getDisplayId();
final DisplayCutout displayCutout = getWmDisplayCutout().getDisplayCutout();
@@ -3455,25 +3465,17 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
mergedConfiguration, getBackdropFrame(frame), forceRelayout,
getDisplayContent().getDisplayPolicy().areSystemBarsForcedShownLw(this),
displayId, new DisplayCutout.ParcelableWrapper(displayCutout));
mDragResizingChangeReported = true;
if (mWmService.mAccessibilityController != null) {
mWmService.mAccessibilityController.onSomeWindowResizedOrMovedLocked(displayId);
}
updateLocationInParentDisplayIfNeeded();
mWindowFrames.resetInsetsChanged();
mWinAnimator.mSurfaceResized = false;
mReportOrientationChanged = false;
} catch (RemoteException e) {
// Cancel orientation change of this window to avoid blocking unfreeze display.
setOrientationChanging(false);
mLastFreezeDuration = (int)(SystemClock.elapsedRealtime()
- mWmService.mDisplayFreezeTime);
// We are assuming the hosting process is dead or in a zombie state.
Slog.w(TAG, "Failed to report 'resized' to the client of " + this
+ ", removing this window.");
mWmService.mPendingRemove.add(this);
mWmService.mWindowPlacerLocked.requestTraversal();
Slog.w(TAG, "Failed to report 'resized' to " + this + " due to " + e);
}
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}

View File

@@ -40,6 +40,7 @@ import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doThrow;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.never;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.reset;
@@ -47,6 +48,8 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
import static com.google.common.truth.Truth.assertThat;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.not;
import static org.junit.Assert.assertEquals;
@@ -55,6 +58,7 @@ import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString;
@@ -65,6 +69,7 @@ import android.graphics.Insets;
import android.graphics.Matrix;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.os.RemoteException;
import android.platform.test.annotations.Presubmit;
import android.util.Size;
import android.view.DisplayCutout;
@@ -569,6 +574,36 @@ public class WindowStateTests extends WindowTestsBase {
assertEquals(Arrays.asList(keyguardHostWindow, startingWindow), outWaitingForDrawn);
}
@Test
public void testReportResizedWithRemoteException() {
final WindowState win = mChildAppWindowAbove;
makeWindowVisible(win, win.getParentWindow());
win.mLayoutSeq = win.getDisplayContent().mLayoutSeq;
win.updateResizingWindowIfNeeded();
assertThat(mWm.mResizingWindows).contains(win);
assertTrue(win.getOrientationChanging());
mWm.mResizingWindows.remove(win);
spyOn(win.mClient);
try {
doThrow(new RemoteException("test")).when(win.mClient).resized(any() /* frame */,
any() /* contentInsets */, any() /* visibleInsets */, any() /* stableInsets */,
anyBoolean() /* reportDraw */, any() /* mergedConfig */,
any() /* backDropFrame */, anyBoolean() /* forceLayout */,
anyBoolean() /* alwaysConsumeSystemBars */, anyInt() /* displayId */,
any() /* displayCutout */);
} catch (RemoteException ignored) {
}
win.reportResized();
win.updateResizingWindowIfNeeded();
// Even "resized" throws remote exception, it is still considered as reported. So the window
// shouldn't be resized again (which may block unfreeze in real case).
assertThat(mWm.mResizingWindows).doesNotContain(win);
assertFalse(win.getOrientationChanging());
}
@Test
public void testGetTransformationMatrix() {
final int PARENT_WINDOW_OFFSET = 1;