Index: content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeChildFrameTest.java |
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeChildFrameTest.java b/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeChildFrameTest.java |
index 2d494d039238f74982eb408bbde6f7c50572b195..40ea4ae47b86dd5ebec55d06437a0613dc1e4b32 100644 |
--- a/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeChildFrameTest.java |
+++ b/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeChildFrameTest.java |
@@ -13,6 +13,10 @@ import org.chromium.content_public.browser.LoadUrlParams; |
import org.chromium.content_public.browser.NavigationController; |
import org.chromium.content_public.browser.WebContents; |
+import java.util.concurrent.CountDownLatch; |
+import java.util.concurrent.TimeUnit; |
+import java.util.concurrent.TimeoutException; |
+ |
/** |
* Part of the test suite for the WebView's Java Bridge. |
* |
@@ -105,6 +109,63 @@ public class JavaBridgeChildFrameTest extends JavaBridgeTestBase { |
"queryProperties(window.frames[0])")); |
} |
+ // Regression test for crbug.com/484927 -- make sure that existence of transient |
+ // objects held by multiple RenderFrames doesn't cause an infinite loop when one |
+ // of them gets removed. |
+ @SmallTest |
+ @Feature({"AndroidWebView", "Android-JavaBridge"}) |
+ public void testRemovingTransientObjectHolders() throws Throwable { |
+ class Test { |
+ private Object mInner = new Object(); |
+ // Expecting the inner object to be retrieved twice. |
+ private CountDownLatch mLatch = new CountDownLatch(2); |
+ @JavascriptInterface |
+ public Object getInner() { |
+ mLatch.countDown(); |
+ return mInner; |
+ } |
+ public void waitForInjection() throws Throwable { |
+ if (!mLatch.await(5, TimeUnit.SECONDS)) { |
+ throw new TimeoutException(); |
+ } |
+ } |
+ } |
+ final Test testObject = new Test(); |
+ |
+ // Due to crbug.com/486262, Java objects are sometimes not injected |
+ // into newly added frames. To work around this, we load the page first, so |
+ // all the frames got created, then inject the object. |
+ // Thus, the script code fails on the first execution (as no Java object is |
+ // injected yet), but then works just fine after reload. |
+ loadDataSync(getWebContents().getNavigationController(), |
+ "<html>" |
+ + "<head><script>window.inner_ref = test.getInner()</script></head>" |
+ + "<body>" |
+ + " <iframe id='frame' " |
+ + " srcdoc='<script>window.inner_ref = test.getInner()</script>'>" |
+ + " </iframe>" |
+ + "</body></html>", "text/html", false); |
+ injectObjectAndReload(testObject, "test"); |
+ testObject.waitForInjection(); |
+ // Just in case, check that the object wrappers are in place. |
+ assertEquals("\"object\"", |
+ executeJavaScriptAndGetResult(getWebContents(), "typeof inner_ref")); |
+ assertEquals("\"object\"", |
+ executeJavaScriptAndGetResult(getWebContents(), |
+ "typeof window.frames[0].inner_ref")); |
+ // Remove the iframe, this will trigger a removal of RenderFrame, which was causing |
+ // the bug condition, as the transient object still has a holder -- the main window. |
+ assertEquals("{}", |
+ executeJavaScriptAndGetResult(getWebContents(), |
+ "(function(){ " |
+ + "var f = document.getElementById('frame');" |
+ + "f.parentNode.removeChild(f); return f; })()")); |
+ // Just in case, check that the remaining wrapper is still accessible. |
+ assertEquals("\"object\"", |
+ executeJavaScriptAndGetResult(getWebContents(), |
+ "typeof inner_ref")); |
+ } |
+ |
private String executeJavaScriptAndGetResult(final WebContents webContents, |
final String script) throws Throwable { |
final String[] result = new String[1]; |