blob: 26a0d78cd5bae51a2770ce3a60e6225b87d2d12f [file] [log] [blame]
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.android_webview.test;
import static org.chromium.android_webview.test.OnlyRunIn.ProcessMode.MULTI_PROCESS;
import android.util.Pair;
import androidx.test.filters.SmallTest;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.chromium.android_webview.AwContents;
import org.chromium.android_webview.AwRenderProcess;
import org.chromium.android_webview.renderer_priority.RendererPriority;
import org.chromium.base.task.PostTask;
import org.chromium.base.test.util.CallbackHelper;
import org.chromium.base.test.util.CommandLineFlags;
import org.chromium.base.test.util.Feature;
import org.chromium.content_public.browser.UiThreadTaskTraits;
import org.chromium.content_public.browser.test.util.TestThreadUtils;
import org.chromium.content_public.common.ContentUrlConstants;
import org.chromium.net.test.util.TestWebServer;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
/**
* Tests for AwContentsClient.onRenderProcessGone callback.
*/
@RunWith(AwJUnit4ClassRunner.class)
public class AwContentsClientOnRenderProcessGoneTest {
private static final String TAG = "AwRendererGone";
@Rule
public AwActivityTestRule mActivityTestRule = new AwActivityTestRule();
private TestWebServer mWebServer;
private TestAwContentsClient mContentsClient;
private AwTestContainerView mTestView;
private AwContents mAwContents;
@Before
public void setUp() throws Exception {
mWebServer = TestWebServer.start();
mContentsClient = new TestAwContentsClient();
mTestView = mActivityTestRule.createAwTestContainerViewOnMainSync(mContentsClient);
mAwContents = mTestView.getAwContents();
}
@After
public void tearDown() {
mWebServer.shutdown();
}
private String addPageToTestServer(String httpPath, String html) {
List<Pair<String, String>> headers = new ArrayList<Pair<String, String>>();
headers.add(Pair.create("Content-Type", "text/html"));
headers.add(Pair.create("Cache-Control", "no-store"));
return mWebServer.setResponse(httpPath, html, headers);
}
interface Terminator {
void terminate();
}
private AwRenderProcess createAndTerminateRenderProcess(
Terminator terminator, boolean expectCrash) throws Throwable {
TestAwContentsClient.RenderProcessGoneHelper helper =
mContentsClient.getRenderProcessGoneHelper();
helper.setResponse(true); // Don't automatically kill the browser process.
final AwRenderProcess renderProcess =
TestThreadUtils.runOnUiThreadBlocking(() -> mAwContents.getRenderProcess());
// Ensure that the renderer has started.
mActivityTestRule.loadUrlSync(mAwContents, mContentsClient.getOnPageFinishedHelper(),
ContentUrlConstants.ABOUT_BLANK_DISPLAY_URL);
// Terminate the renderer.
PostTask.runOrPostTask(UiThreadTaskTraits.DEFAULT, () -> terminator.terminate());
// Assert that onRenderProcessGone is called once.
int callCount = helper.getCallCount();
helper.waitForCallback(callCount, 1, CallbackHelper.WAIT_TIMEOUT_SECONDS * 5,
TimeUnit.SECONDS);
Assert.assertEquals(callCount + 1, helper.getCallCount());
Assert.assertEquals(helper.getAwRenderProcessGoneDetail().didCrash(), expectCrash);
Assert.assertEquals(
RendererPriority.HIGH, helper.getAwRenderProcessGoneDetail().rendererPriority());
return renderProcess;
}
@Test
@Feature({"AndroidWebView"})
@SmallTest
@OnlyRunIn(MULTI_PROCESS)
public void testOnRenderProcessCrash() throws Throwable {
createAndTerminateRenderProcess(() -> { mAwContents.loadUrl("chrome://crash"); }, true);
}
@Test
@Feature({"AndroidWebView"})
@SmallTest
@OnlyRunIn(MULTI_PROCESS)
public void testOnRenderProcessKill() throws Throwable {
createAndTerminateRenderProcess(() -> { mAwContents.loadUrl("chrome://kill"); }, false);
}
@Test
@Feature({"AndroidWebView"})
@SmallTest
@OnlyRunIn(MULTI_PROCESS)
public void testRenderProcessTermination() throws Throwable {
createAndTerminateRenderProcess(
() -> { mAwContents.getRenderProcess().terminate(); }, false);
}
@Test
@Feature({"AndroidWebView"})
@SmallTest
@OnlyRunIn(MULTI_PROCESS)
public void testRenderProcessDifferentAfterRestart() throws Throwable {
AwRenderProcess renderProcess1 = createAndTerminateRenderProcess(
() -> { mAwContents.getRenderProcess().terminate(); }, false);
AwRenderProcess renderProcess2 = createAndTerminateRenderProcess(
() -> { mAwContents.getRenderProcess().terminate(); }, false);
Assert.assertNotEquals(renderProcess1, renderProcess2);
}
@Test
@Feature({"AndroidWebView"})
@SmallTest
@OnlyRunIn(MULTI_PROCESS)
public void testRenderProcessCanNotTerminateBeforeStart() throws Throwable {
Assert.assertFalse(TestThreadUtils.runOnUiThreadBlocking(
() -> mAwContents.getRenderProcess().terminate()));
}
@Test
@Feature({"AndroidWebView"})
@SmallTest
@OnlyRunIn(MULTI_PROCESS)
public void testRenderProcessSameBeforeAndAfterStart() throws Throwable {
AwRenderProcess renderProcessBeforeStart =
TestThreadUtils.runOnUiThreadBlocking(() -> mAwContents.getRenderProcess());
// Ensure that the renderer has started.
mActivityTestRule.loadUrlSync(mAwContents, mContentsClient.getOnPageFinishedHelper(),
ContentUrlConstants.ABOUT_BLANK_DISPLAY_URL);
AwRenderProcess renderProcessAfterStart =
TestThreadUtils.runOnUiThreadBlocking(() -> mAwContents.getRenderProcess());
Assert.assertEquals(renderProcessBeforeStart, renderProcessAfterStart);
}
@Test
@Feature({"AndroidWebView"})
@SmallTest
@OnlyRunIn(MULTI_PROCESS)
// The RenderDocument feature has a "level" parameter. This enables the feature and sets the
// default level to "crashed-frame" to enable replacing the render frame host of crashed frames
// with a new render frame host (instead of resuing the old one). See
// https://go/force-field-trials-docs for the syntax of these flags.
@CommandLineFlags.Add({
"enable-features=RenderDocument<RenderDocument",
"force-fieldtrials=RenderDocument/Group1",
"force-fieldtrial-params=RenderDocument.Group1:level/crashed-frame",
})
public void
testNavigationAfterCrashAndJavaScript() throws Throwable {
// In https://crbug.com/1006814, a crashed frame, reinitialized by running JS fails to
// navigate.
mActivityTestRule.getAwSettingsOnUiThread(mAwContents).setJavaScriptEnabled(true);
// Crash the frame.
AwRenderProcess renderProcess1 = createAndTerminateRenderProcess(
() -> { mAwContents.getRenderProcess().terminate(); }, false);
// Run JS in the frame.
Assert.assertEquals("3",
mActivityTestRule.executeJavaScriptAndWaitForResult(
mAwContents, mContentsClient, "1+2"));
// Navigate to somewhere else. This should not crash the frame.
final String content = "some content";
final String httpPathOnServer = addPageToTestServer("/page.html", content);
mActivityTestRule.loadUrlSync(
mAwContents, mContentsClient.getOnPageFinishedHelper(), httpPathOnServer);
// Result is a string, so needs "".
Assert.assertEquals("\"" + content + "\"",
mActivityTestRule.executeJavaScriptAndWaitForResult(
mAwContents, mContentsClient, "document.body.textContent"));
}
}