Chromium Code Reviews| Index: android_webview/test/shell/src/org/chromium/android_webview/test/SeparateProcessWebViewService.java |
| diff --git a/android_webview/test/shell/src/org/chromium/android_webview/test/SeparateProcessWebViewService.java b/android_webview/test/shell/src/org/chromium/android_webview/test/SeparateProcessWebViewService.java |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..316be85f9261ed5c72fcb623929888c08f9601f2 |
| --- /dev/null |
| +++ b/android_webview/test/shell/src/org/chromium/android_webview/test/SeparateProcessWebViewService.java |
| @@ -0,0 +1,169 @@ |
| +// Copyright 2015 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.base.test.util.ScalableTimeout.scaleTimeout; |
| + |
| +import android.app.Service; |
| +import android.content.Intent; |
| +import android.os.Handler; |
| +import android.os.IBinder; |
| +import android.os.Message; |
| +import android.os.Messenger; |
| +import android.os.RemoteException; |
| +import android.util.AndroidRuntimeException; |
| + |
| +import org.chromium.android_webview.AwBrowserContext; |
| +import org.chromium.android_webview.AwContents; |
| +import org.chromium.android_webview.AwContentsClient; |
| +import org.chromium.android_webview.AwSettings; |
| +import org.chromium.android_webview.test.util.CommonResources; |
| +import org.chromium.android_webview.test.util.JSUtils; |
| +import org.chromium.base.Log; |
| +import org.chromium.base.test.util.InMemorySharedPreferences; |
| +import org.chromium.content.browser.test.util.CallbackHelper; |
| + |
| +import java.util.concurrent.TimeUnit; |
| + |
| +/** |
| + * This is a service for imitating a second browser process in the application. |
| + */ |
| +public class SeparateProcessWebViewService extends Service { |
| + private static final String TAG = SeparateProcessWebViewService.class.getSimpleName(); |
| + private static final String DATA_URL = "data:text/html,<div/>"; |
| + public static final int RECEIVER_MESSAGE_ID = 1; |
|
boliu
2016/08/02 20:15:59
these message ID names seem way too generic, maybe
gsennton
2016/09/06 15:26:08
Done.
|
| + public static final int RETURN_MESSAGE_ID = 42; |
|
boliu
2016/08/02 20:16:00
this one seems like "success" message, ie we got t
gsennton
2016/09/06 15:26:08
Done.
|
| + Messenger mTestMessenger; |
| + |
| + private AwTestContainerView mTestContainerView; |
| + private TestAwContentsClient mContentsClient; |
| + private AwContents mAwContents; |
| + |
| + // TODO "this handler should be static or leaks might occur" |
| + /** |
| + * Handler that receives a Messenger instance from the test so that we can communicate with the |
| + * test. |
| + */ |
| + class TestMessageReceiverHandler extends Handler { |
| + @Override |
| + public void handleMessage(Message msg) { |
| + // TODO this runs on the main thread, is this documented anywhere? Can we rely on this? |
| + switch (msg.what) { |
| + case RECEIVER_MESSAGE_ID: |
| + try { |
| + testShouldOverrideUrlLoadingCrash(msg); |
| + } catch (Exception e) { |
| + Log.e(TAG, "Caught exception in testShouldOverrideUrlLoadingCrash: " + e); |
|
boliu
2016/08/02 20:16:00
pass e as third parameter?
gsennton
2016/08/02 20:33:57
Will do
gsennton
2016/09/06 15:26:08
Done.
|
| + } |
| + break; |
| + default: |
| + super.handleMessage(msg); |
| + } |
| + } |
| + } |
| + |
| + private void testShouldOverrideUrlLoadingCrash(Message msg) throws Exception { |
| + mTestMessenger = msg.replyTo; |
| + final Message newMsg = Message.obtain(null, RETURN_MESSAGE_ID); |
| + final Thread.UncaughtExceptionHandler originalUncaughtExceptionHandler = |
| + Thread.currentThread().getUncaughtExceptionHandler(); |
| + Thread.currentThread().setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() { |
| + @Override |
| + public void uncaughtException(Thread t, Throwable e) { |
| + Log.e(TAG, "in uncaughtException with throwable " + e |
|
boliu
2016/08/02 20:16:00
this is not an error
gsennton
2016/08/02 20:33:57
Ooops, just used it as debug logging.
|
| + + " and throwable message: " + e.getMessage() + " on thread " + t); |
| + try { |
| + if (e instanceof MySpecialException) { |
| + mTestMessenger.send(newMsg); |
| + } // Else, wrong exception was thrown, don't message the main process! |
| + } catch (RemoteException re) { |
| + throw new AndroidRuntimeException(re); |
| + } |
| + // Call the original UEH to kill off this process |
| + originalUncaughtExceptionHandler.uncaughtException(t, e); |
| + } |
| + }); |
| + // Set up WebView and navigate on it to cause shouldOverrideUrlLoading to be called. |
| + SecondBrowserProcess.startBrowserProcess(this); |
| + createTestContainerView(); |
| + |
| + createAndClickOnLinkAsync( |
| + mAwContents, mContentsClient, mContentsClient.getOnPageFinishedHelper()); |
| + } |
| + |
| + private static class MySpecialException extends RuntimeException { |
| + MySpecialException() { |
| + super(); |
| + } |
| + } |
| + |
| + private void createTestContainerView() { |
| + mContentsClient = new TestAwContentsClient() { |
| + @Override |
| + public boolean shouldOverrideUrlLoading(AwWebResourceRequest request) { |
| + throw new MySpecialException(); |
| + } |
| + }; |
| + mTestContainerView = createDetachedAwTestContainerView(mContentsClient); |
| + mAwContents = mTestContainerView.getAwContents(); |
| + } |
| + |
| + // TODO This is copied from AwTestBase.. |
| + private AwTestContainerView createDetachedAwTestContainerView( |
| + final AwContentsClient awContentsClient) { |
| + AwBrowserContext browserContext = |
| + new AwBrowserContext(new InMemorySharedPreferences(), getApplicationContext()); |
| + AwTestContainerView testContainerView = new AwTestContainerView(this, false); |
| + AwSettings awSettings = |
| + new AwSettings(this, false /* isAccessFromFileURLsGrantedByDefault */, |
| + false /* supportsLegacyQuirks */, false /* allowEmptyDocumentPersistence */, |
| + true /* allowGeolocationOnInsecureOrigins */); |
| + testContainerView.initialize(new AwContents(browserContext, testContainerView, |
| + testContainerView.getContext(), testContainerView.getInternalAccessDelegate(), |
| + testContainerView.getNativeDrawGLFunctorFactory(), awContentsClient, awSettings)); |
| + return testContainerView; |
| + } |
| + |
| + Messenger mMessenger = new Messenger(new TestMessageReceiverHandler()); |
| + |
| + @Override |
| + public IBinder onBind(Intent intent) { |
| + return mMessenger.getBinder(); |
| + } |
| + |
| + // From AwTestBase |
| + /** |
| + * Loads data containing a link on the and creates another thread from where we click |
| + * wait for the data to be loaded, and then click on the link. |
| + * Assumes we are running on the UI thread! |
| + */ |
| + public static void createAndClickOnLinkAsync(final AwContents awContents, |
| + final TestAwContentsClient contentsClient, final CallbackHelper onPageFinishedHelper) |
| + throws Exception { |
| + final int currentCallCount = onPageFinishedHelper.getCallCount(); |
| + awContents.loadData( |
| + CommonResources.makeHtmlPageWithSimpleLinkTo(DATA_URL), "text/html", null); |
| + awContents.getSettings().setJavaScriptEnabled(true); |
| + // Since onPageFinished is called on the UI thread we would deadlock the UI thread by |
| + // waiting for onPageFinished here. Instead create a new thread and wait for the callback |
| + // (and then continue the rest of the test) from there. |
| + Thread t = new Thread(new Runnable() { |
| + @Override |
| + public void run() { |
| + try { |
| + onPageFinishedHelper.waitForCallback(currentCallCount, 1, |
| + scaleTimeout(15000), // TODO WAIT_TIMEOUT_MS |
| + TimeUnit.MILLISECONDS); |
| + |
| + JSUtils.clickOnLinkUsingJsFromNonUiThread(awContents, |
|
boliu
2016/08/02 20:16:00
you can just post back to UI asynchronously?
gsennton
2016/09/06 15:26:08
Yeah, this code isn't needed either when just navi
|
| + contentsClient.getOnEvaluateJavaScriptResultHelper(), "link"); |
| + } catch (Exception e) { |
| + Log.e(TAG, "Failed to click on link using JS: " + e); |
| + } |
| + } |
| + }); |
| + t.start(); |
| + } |
| +} |