зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1465480 - Add ContentDelegate.onCrash() r=jchen,droeh
This will give applications the opportunity to recover from a content process crash. MozReview-Commit-ID: IAfVNy3ndS4
This commit is contained in:
Родитель
1383f7b956
Коммит
2a505d2d75
|
@ -900,6 +900,12 @@ public abstract class GeckoApp extends GeckoActivity
|
|||
|
||||
@Override
|
||||
public void onExternalResponse(final GeckoSession session, final GeckoSession.WebResponseInfo request) {
|
||||
// Won't happen, as we don't use the GeckoView download support in Fennec
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCrash(final GeckoSession session) {
|
||||
// Won't happen, as we don't use e10s in Fennec
|
||||
}
|
||||
|
||||
protected void setFullScreen(final boolean fullscreen) {
|
||||
|
|
|
@ -722,6 +722,12 @@ public class CustomTabsActivity extends AppCompatActivity
|
|||
|
||||
@Override
|
||||
public void onExternalResponse(final GeckoSession session, final GeckoSession.WebResponseInfo request) {
|
||||
// Won't happen, as we don't use the GeckoView download support in Fennec
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCrash(final GeckoSession session) {
|
||||
// Won't happen, as we don't use e10s in Fennec
|
||||
}
|
||||
|
||||
@Override // ActionModePresenter
|
||||
|
|
|
@ -369,6 +369,12 @@ public class WebAppActivity extends AppCompatActivity
|
|||
|
||||
@Override // GeckoSession.ContentDelegate
|
||||
public void onExternalResponse(final GeckoSession session, final GeckoSession.WebResponseInfo request) {
|
||||
// Won't happen, as we don't use the GeckoView download support in Fennec
|
||||
}
|
||||
|
||||
@Override // GeckoSession.ContentDelegate
|
||||
public void onCrash(final GeckoSession session) {
|
||||
// Won't happen, as we don't use e10s in Fennec
|
||||
}
|
||||
|
||||
@Override // GeckoSession.ContentDelegate
|
||||
|
|
|
@ -7,11 +7,14 @@ package org.mozilla.geckoview.test
|
|||
import org.mozilla.geckoview.GeckoResponse
|
||||
import org.mozilla.geckoview.GeckoSession
|
||||
import org.mozilla.geckoview.test.rule.GeckoSessionTestRule.AssertCalled
|
||||
import org.mozilla.geckoview.test.rule.GeckoSessionTestRule.IgnoreCrash
|
||||
import org.mozilla.geckoview.test.rule.GeckoSessionTestRule.ReuseSession
|
||||
import org.mozilla.geckoview.test.util.Callbacks
|
||||
|
||||
import android.support.test.filters.MediumTest
|
||||
import android.support.test.runner.AndroidJUnit4
|
||||
import org.hamcrest.Matchers.*
|
||||
import org.junit.Assume.assumeThat
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
|
@ -57,4 +60,53 @@ class ContentDelegateTest : BaseSessionTest() {
|
|||
})
|
||||
}
|
||||
|
||||
@IgnoreCrash
|
||||
@ReuseSession(false)
|
||||
@Test fun crashContent() {
|
||||
// This test doesn't make sense without multiprocess
|
||||
assumeThat(sessionRule.env.isMultiprocess, equalTo(true))
|
||||
|
||||
sessionRule.session.loadUri(CONTENT_CRASH_URL)
|
||||
|
||||
sessionRule.waitUntilCalled(object : Callbacks.ContentDelegate {
|
||||
@AssertCalled(count = 1)
|
||||
override fun onCrash(session: GeckoSession) {
|
||||
assertThat("Session should be closed after a crash", session.isOpen, equalTo(false))
|
||||
|
||||
// Recover immediately
|
||||
session.open()
|
||||
session.loadTestPath(HELLO_HTML_PATH)
|
||||
}
|
||||
});
|
||||
|
||||
sessionRule.waitForPageStop()
|
||||
|
||||
sessionRule.forCallbacksDuringWait(object: Callbacks.ProgressDelegate {
|
||||
@AssertCalled(count = 1)
|
||||
override fun onPageStop(session: GeckoSession, success: Boolean) {
|
||||
assertThat("Page should load successfully", success, equalTo(true))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@IgnoreCrash
|
||||
@ReuseSession(false)
|
||||
@Test fun crashContentMultipleSessions() {
|
||||
// This test doesn't make sense without multiprocess
|
||||
assumeThat(sessionRule.env.isMultiprocess, equalTo(true))
|
||||
|
||||
// We need to make sure all sessions in a given content process
|
||||
// receive onCrash(). If we add multiple content processes, this
|
||||
// test will need fixed to ensure the test sessions go into the
|
||||
// same one.
|
||||
sessionRule.createOpenSession()
|
||||
sessionRule.session.loadUri(CONTENT_CRASH_URL)
|
||||
|
||||
sessionRule.waitUntilCalled(object : Callbacks.ContentDelegate {
|
||||
@AssertCalled(count = 2)
|
||||
override fun onCrash(session: GeckoSession) {
|
||||
assertThat("Session should be closed after a crash", session.isOpen, equalTo(false))
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -85,6 +85,10 @@ public class TestRunnerActivity extends Activity {
|
|||
@Override
|
||||
public void onExternalResponse(GeckoSession session, GeckoSession.WebResponseInfo request) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCrash(GeckoSession session) {
|
||||
}
|
||||
};
|
||||
|
||||
private GeckoSession createSession() {
|
||||
|
|
|
@ -37,6 +37,9 @@ class Callbacks private constructor() {
|
|||
|
||||
override fun onExternalResponse(session: GeckoSession, response: GeckoSession.WebResponseInfo) {
|
||||
}
|
||||
|
||||
override fun onCrash(session: GeckoSession) {
|
||||
}
|
||||
}
|
||||
|
||||
interface NavigationDelegate : GeckoSession.NavigationDelegate {
|
||||
|
|
|
@ -104,13 +104,14 @@ public class GeckoSession extends LayerSession
|
|||
new GeckoSessionHandler<ContentDelegate>(
|
||||
"GeckoViewContent", this,
|
||||
new String[]{
|
||||
"GeckoView:ContentCrash",
|
||||
"GeckoView:ContextMenu",
|
||||
"GeckoView:DOMTitleChanged",
|
||||
"GeckoView:DOMWindowFocus",
|
||||
"GeckoView:DOMWindowClose",
|
||||
"GeckoView:ExternalResponse",
|
||||
"GeckoView:FullScreenEnter",
|
||||
"GeckoView:FullScreenExit"
|
||||
"GeckoView:FullScreenExit",
|
||||
}
|
||||
) {
|
||||
@Override
|
||||
|
@ -119,7 +120,10 @@ public class GeckoSession extends LayerSession
|
|||
final GeckoBundle message,
|
||||
final EventCallback callback) {
|
||||
|
||||
if ("GeckoView:ContextMenu".equals(event)) {
|
||||
if ("GeckoView:ContentCrash".equals(event)) {
|
||||
close();
|
||||
delegate.onCrash(GeckoSession.this);
|
||||
} else if ("GeckoView:ContextMenu".equals(event)) {
|
||||
final int type = getContentElementType(
|
||||
message.getString("elementType"));
|
||||
|
||||
|
@ -1891,6 +1895,17 @@ public class GeckoSession extends LayerSession
|
|||
* @param response the WebResponseInfo for the external response
|
||||
*/
|
||||
void onExternalResponse(GeckoSession session, WebResponseInfo response);
|
||||
|
||||
/**
|
||||
* The content process hosting this GeckoSession has crashed. The
|
||||
* GeckoSession is now closed and unusable. You may call
|
||||
* {@link #open(GeckoRuntime)} to recover the session, but no state
|
||||
* is preserved. Most applications will want to call
|
||||
* {@link #loadUri(Uri)} or {@link #restoreState(SessionState)} at this point.
|
||||
*
|
||||
* @param session The GeckoSession that crashed.
|
||||
*/
|
||||
void onCrash(GeckoSession session);
|
||||
}
|
||||
|
||||
public interface SelectionActionDelegate {
|
||||
|
|
|
@ -209,6 +209,13 @@ public class GeckoViewActivity extends Activity {
|
|||
@Override
|
||||
public void onExternalResponse(GeckoSession session, GeckoSession.WebResponseInfo request) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCrash(GeckoSession session) {
|
||||
Log.e(LOGTAG, "Crashed, reopening session");
|
||||
session.open(sGeckoRuntime);
|
||||
session.loadUri(DEFAULT_URL);
|
||||
}
|
||||
}
|
||||
|
||||
private class MyGeckoViewProgress implements GeckoSession.ProgressDelegate {
|
||||
|
|
|
@ -9,6 +9,10 @@ var EXPORTED_SYMBOLS = ["GeckoViewContent"];
|
|||
ChromeUtils.import("resource://gre/modules/GeckoViewModule.jsm");
|
||||
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetters(this, {
|
||||
Services: "resource://gre/modules/Services.jsm",
|
||||
});
|
||||
|
||||
class GeckoViewContent extends GeckoViewModule {
|
||||
onInit() {
|
||||
this.registerListener([
|
||||
|
@ -30,6 +34,8 @@ class GeckoViewContent extends GeckoViewModule {
|
|||
|
||||
this.messageManager.addMessageListener("GeckoView:DOMFullscreenExit", this);
|
||||
this.messageManager.addMessageListener("GeckoView:DOMFullscreenRequest", this);
|
||||
|
||||
Services.obs.addObserver(this, "oop-frameloader-crashed");
|
||||
}
|
||||
|
||||
onDisable() {
|
||||
|
@ -40,6 +46,8 @@ class GeckoViewContent extends GeckoViewModule {
|
|||
|
||||
this.messageManager.removeMessageListener("GeckoView:DOMFullscreenExit", this);
|
||||
this.messageManager.removeMessageListener("GeckoView:DOMFullscreenRequest", this);
|
||||
|
||||
Services.obs.removeObserver(this, "oop-frameloader-crashed");
|
||||
}
|
||||
|
||||
// Bundle event handler.
|
||||
|
@ -121,4 +129,23 @@ class GeckoViewContent extends GeckoViewModule {
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// nsIObserver event handler
|
||||
observe(aSubject, aTopic, aData) {
|
||||
debug `observe: ${aTopic}`;
|
||||
|
||||
switch (aTopic) {
|
||||
case "oop-frameloader-crashed": {
|
||||
const browser = aSubject.ownerElement;
|
||||
if (!browser || browser != this.browser) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.eventDispatcher.sendRequest({
|
||||
type: "GeckoView:ContentCrash"
|
||||
});
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -194,6 +194,7 @@ class GeckoViewProgress extends GeckoViewModule {
|
|||
.createInstance(Ci.nsIWebProgress);
|
||||
this.progressFilter.addProgressListener(this, flags);
|
||||
this.browser.addProgressListener(this.progressFilter, flags);
|
||||
Services.obs.addObserver(this, "oop-frameloader-crashed");
|
||||
}
|
||||
|
||||
onDisable() {
|
||||
|
@ -203,6 +204,8 @@ class GeckoViewProgress extends GeckoViewModule {
|
|||
this.progressFilter.removeProgressListener(this);
|
||||
this.browser.removeProgressListener(this.progressFilter);
|
||||
}
|
||||
|
||||
Services.obs.removeObserver(this, "oop-frameloader-crashed");
|
||||
}
|
||||
|
||||
onSettingsUpdate() {
|
||||
|
@ -225,6 +228,7 @@ class GeckoViewProgress extends GeckoViewModule {
|
|||
debug `onStateChange: uri=${uriSpec}`;
|
||||
|
||||
if (aStateFlags & Ci.nsIWebProgressListener.STATE_START) {
|
||||
this._inProgress = true;
|
||||
const message = {
|
||||
type: "GeckoView:PageStart",
|
||||
uri: uriSpec,
|
||||
|
@ -233,6 +237,7 @@ class GeckoViewProgress extends GeckoViewModule {
|
|||
this.eventDispatcher.sendRequest(message);
|
||||
} else if ((aStateFlags & Ci.nsIWebProgressListener.STATE_STOP) &&
|
||||
!aWebProgress.isLoadingDocument) {
|
||||
this._inProgress = false;
|
||||
let message = {
|
||||
type: "GeckoView:PageStop",
|
||||
success: !aStatus
|
||||
|
@ -276,4 +281,23 @@ class GeckoViewProgress extends GeckoViewModule {
|
|||
});
|
||||
}
|
||||
}
|
||||
|
||||
// nsIObserver event handler
|
||||
observe(aSubject, aTopic, aData) {
|
||||
debug `observe: topic=${aTopic}`;
|
||||
|
||||
switch (aTopic) {
|
||||
case "oop-frameloader-crashed": {
|
||||
const browser = aSubject.ownerElement;
|
||||
if (!browser || browser != this.browser || !this._inProgress) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.eventDispatcher.sendRequest({
|
||||
type: "GeckoView:PageStop",
|
||||
success: false
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче