Bug 1574917 - Prevent GeckoSessions from being GC'd in tests r=agi

... and document that the onNewSession/WebExtensionController.onNewTab
delegates are responsible for maintaining the lifetime of the returned
GeckoSession references.

Currently, the consequence of not keeping the reference is that the
browser window can be closed at an unpredictable moment, as seen in the
linked bug report.

This patch has been verified using the STR at
https://bugzilla.mozilla.org/show_bug.cgi?id=1574917#c13

Differential Revision: https://phabricator.services.mozilla.com/D46074

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Rob Wu 2019-09-16 22:16:20 +00:00
Родитель 2d3752662c
Коммит 703f89d157
4 изменённых файлов: 10 добавлений и 0 удалений

Просмотреть файл

@ -28,6 +28,7 @@ import android.support.annotation.Nullable;
import android.view.Surface; import android.view.Surface;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet;
public class TestRunnerActivity extends Activity { public class TestRunnerActivity extends Activity {
private static final String LOGTAG = "TestRunnerActivity"; private static final String LOGTAG = "TestRunnerActivity";
@ -41,6 +42,7 @@ public class TestRunnerActivity extends Activity {
private boolean mKillProcessOnDestroy; private boolean mKillProcessOnDestroy;
private HashMap<GeckoSession, GeckoDisplay> mDisplays = new HashMap<>(); private HashMap<GeckoSession, GeckoDisplay> mDisplays = new HashMap<>();
private HashSet<GeckoSession> mOwnedSessions = new HashSet<>();
private GeckoSession.PermissionDelegate mPermissionDelegate = new GeckoSession.PermissionDelegate() { private GeckoSession.PermissionDelegate mPermissionDelegate = new GeckoSession.PermissionDelegate() {
@Override @Override
@ -149,6 +151,7 @@ public class TestRunnerActivity extends Activity {
session.setNavigationDelegate(mNavigationDelegate); session.setNavigationDelegate(mNavigationDelegate);
session.setContentDelegate(mContentDelegate); session.setContentDelegate(mContentDelegate);
session.setPermissionDelegate(mPermissionDelegate); session.setPermissionDelegate(mPermissionDelegate);
mOwnedSessions.add(session);
return session; return session;
} }
@ -172,6 +175,7 @@ public class TestRunnerActivity extends Activity {
session.releaseDisplay(display); session.releaseDisplay(display);
} }
mOwnedSessions.remove(session);
session.close(); session.close();
} }

Просмотреть файл

@ -3464,6 +3464,8 @@ public class GeckoSession implements Parcelable {
* @return A {@link GeckoResult} which holds the returned GeckoSession. May be null, in * @return A {@link GeckoResult} which holds the returned GeckoSession. May be null, in
* which case the request for a new window by web content will fail. e.g., * which case the request for a new window by web content will fail. e.g.,
* <code>window.open()</code> will return null. * <code>window.open()</code> will return null.
* The implementation of onNewSession is responsible for maintaining a reference
* to the returned object, to prevent it from being garbage collected.
*/ */
@UiThread @UiThread
default @Nullable GeckoResult<GeckoSession> onNewSession(@NonNull GeckoSession session, default @Nullable GeckoResult<GeckoSession> onNewSession(@NonNull GeckoSession session,

Просмотреть файл

@ -22,6 +22,8 @@ public class WebExtensionController {
* do not call {@link GeckoSession#loadUri} on it. * do not call {@link GeckoSession#loadUri} on it.
* @return A {@link GeckoResult} which holds the returned GeckoSession. May be null, in * @return A {@link GeckoResult} which holds the returned GeckoSession. May be null, in
* which case the request for a new tab by the extension will fail. * which case the request for a new tab by the extension will fail.
* The implementation of onNewTab is responsible for maintaining a reference
* to the returned object, to prevent it from being garbage collected.
*/ */
@UiThread @UiThread
@Nullable @Nullable

Просмотреть файл

@ -1050,6 +1050,8 @@ public class GeckoViewActivity extends AppCompatActivity {
public GeckoResult<GeckoSession> onNewSession(final GeckoSession session, final String uri) { public GeckoResult<GeckoSession> onNewSession(final GeckoSession session, final String uri) {
final TabSession newSession = createSession(); final TabSession newSession = createSession();
mToolbarView.updateTabCount(); mToolbarView.updateTabCount();
// A reference to newSession is stored by mTabSessionManager,
// which prevents the session from being garbage-collected.
return GeckoResult.fromValue(newSession); return GeckoResult.fromValue(newSession);
} }