Commit 293b5ca2 authored by Michael Thiessen's avatar Michael Thiessen Committed by Commit Bot

Fix crash in TabModelSelectorTabObserver#tabRemoved

Ran into this crash when changing the timing of Activity finishing in
tests.

TabModelSelectorTabObserver#tabRemoved posts a task, and then uses the
Tab after it's possibly been destroyed.

Changes to CriticalPersistedState were also necessary to avoid the
observer leak that would happen in this case.

Change-Id: I152a2d08cee86af51517f5708e57f8dc7fad4f9c
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2535559
Commit-Queue: Michael Thiessen <mthiesse@chromium.org>
Reviewed-by: default avatarTed Choc <tedchoc@chromium.org>
Cr-Commit-Position: refs/heads/master@{#827176}
parent b6d1d101
......@@ -186,6 +186,8 @@ public class TabImpl implements Tab, TabObscuringHandler.Observer {
private final UserDataHost mUserDataHost = new UserDataHost();
private boolean mIsDestroyed;
/**
* Creates an instance of a {@link TabImpl}.
*
......@@ -574,6 +576,11 @@ public class TabImpl implements Tab, TabObscuringHandler.Observer {
return mNativeTabAndroid != 0;
}
@Override
public boolean isDestroyed() {
return mIsDestroyed;
}
@Override
public final void show(@TabSelectionType int type) {
try {
......@@ -651,6 +658,10 @@ public class TabImpl implements Tab, TabObscuringHandler.Observer {
@Override
public void destroy() {
// Set at the start since destroying the WebContents can lead to calling back into
// this class.
mIsDestroyed = true;
// Update the title before destroying the tab. http://b/5783092
updateTitle();
......
......@@ -16,6 +16,11 @@ public interface TabLifecycle {
*/
boolean isInitialized();
/**
* @return Whether this Tab has been destroyed.
*/
boolean isDestroyed();
/**
* Prepares the tab to be shown. This method is supposed to be called before the tab is
* displayed. It restores the ContentView if it is not available after the cold start and
......
......@@ -410,7 +410,9 @@ public class CriticalPersistedTabData extends PersistedTabData {
}
@Override
public void destroy() {}
public void destroy() {
mObservers.clear();
}
/**
* @return title of the {@link Tab}
......
......@@ -75,6 +75,8 @@ public class TabModelSelectorTabObserver
// Post the removal of the observer so that other tab events are notified
// before removing the tab observer (e.g. detach tab from activity).
PostTask.postTask(UiThreadTaskTraits.DEFAULT, () -> {
// If the tab as been destroyed we cannot access PersistedTabData.
if (tab.isDestroyed()) return;
tab.removeObserver(TabModelSelectorTabObserver.this);
CriticalPersistedTabData.from(tab).removeObserver(
TabModelSelectorTabObserver.this);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment