| OLD | NEW |
| 1 // Copyright 2012 The Chromium Authors. All rights reserved. | 1 // Copyright 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 package org.chromium.content.browser; | 5 package org.chromium.content.browser; |
| 6 | 6 |
| 7 import android.support.test.InstrumentationRegistry; |
| 7 import android.support.test.filters.SmallTest; | 8 import android.support.test.filters.SmallTest; |
| 8 | 9 |
| 10 import org.junit.Assert; |
| 11 import org.junit.Before; |
| 12 import org.junit.Rule; |
| 13 import org.junit.Test; |
| 14 import org.junit.runner.RunWith; |
| 15 |
| 9 import org.chromium.base.annotations.SuppressFBWarnings; | 16 import org.chromium.base.annotations.SuppressFBWarnings; |
| 10 import org.chromium.base.test.util.CommandLineFlags; | 17 import org.chromium.base.test.util.CommandLineFlags; |
| 11 import org.chromium.base.test.util.DisabledTest; | 18 import org.chromium.base.test.util.DisabledTest; |
| 12 import org.chromium.base.test.util.Feature; | 19 import org.chromium.base.test.util.Feature; |
| 13 import org.chromium.base.test.util.RetryOnFailure; | 20 import org.chromium.base.test.util.RetryOnFailure; |
| 14 import org.chromium.content.browser.JavaBridgeTestCommon.Controller; | 21 import org.chromium.content.browser.JavaBridgeTestCommon.Controller; |
| 22 import org.chromium.content.browser.test.ContentJUnit4ClassRunner; |
| 15 import org.chromium.content_public.browser.JavaScriptCallback; | 23 import org.chromium.content_public.browser.JavaScriptCallback; |
| 16 import org.chromium.content_public.browser.LoadUrlParams; | 24 import org.chromium.content_public.browser.LoadUrlParams; |
| 17 import org.chromium.content_public.browser.NavigationController; | 25 import org.chromium.content_public.browser.NavigationController; |
| 18 import org.chromium.content_public.browser.WebContents; | 26 import org.chromium.content_public.browser.WebContents; |
| 19 | 27 |
| 20 import java.lang.ref.WeakReference; | 28 import java.lang.ref.WeakReference; |
| 21 import java.util.concurrent.CountDownLatch; | 29 import java.util.concurrent.CountDownLatch; |
| 22 import java.util.concurrent.TimeUnit; | 30 import java.util.concurrent.TimeUnit; |
| 23 import java.util.concurrent.TimeoutException; | 31 import java.util.concurrent.TimeoutException; |
| 24 | 32 |
| 25 /** | 33 /** |
| 26 * Part of the test suite for the WebView's Java Bridge. | 34 * Part of the test suite for the WebView's Java Bridge. |
| 27 * | 35 * |
| 28 * Ensures that injected objects are exposed to child frames as well as the | 36 * Ensures that injected objects are exposed to child frames as well as the |
| 29 * main frame. | 37 * main frame. |
| 30 */ | 38 */ |
| 39 @RunWith(ContentJUnit4ClassRunner.class) |
| 31 @SuppressFBWarnings("UMAC_UNCALLABLE_METHOD_OF_ANONYMOUS_CLASS") | 40 @SuppressFBWarnings("UMAC_UNCALLABLE_METHOD_OF_ANONYMOUS_CLASS") |
| 32 public class JavaBridgeChildFrameTest extends JavaBridgeTestBase { | 41 public class JavaBridgeChildFrameTest { |
| 42 @Rule |
| 43 public JavaBridgeActivityTestRule mActivityTestRule = |
| 44 new JavaBridgeActivityTestRule().shouldSetUp(true); |
| 45 |
| 33 @SuppressFBWarnings("CHROMIUM_SYNCHRONIZED_METHOD") | 46 @SuppressFBWarnings("CHROMIUM_SYNCHRONIZED_METHOD") |
| 34 private static class TestController extends Controller { | 47 private static class TestController extends Controller { |
| 35 private String mStringValue; | 48 private String mStringValue; |
| 36 | 49 |
| 37 @SuppressWarnings("unused") // Called via reflection | 50 @SuppressWarnings("unused") // Called via reflection |
| 38 public synchronized void setStringValue(String x) { | 51 public synchronized void setStringValue(String x) { |
| 39 mStringValue = x; | 52 mStringValue = x; |
| 40 notifyResultIsReady(); | 53 notifyResultIsReady(); |
| 41 } | 54 } |
| 42 | 55 |
| 43 public synchronized String waitForStringValue() { | 56 public synchronized String waitForStringValue() { |
| 44 waitForResult(); | 57 waitForResult(); |
| 45 return mStringValue; | 58 return mStringValue; |
| 46 } | 59 } |
| 47 } | 60 } |
| 48 | 61 |
| 49 TestController mTestController; | 62 TestController mTestController; |
| 50 | 63 |
| 51 @Override | 64 @Before |
| 52 protected void setUp() throws Exception { | 65 public void setUp() throws Exception { |
| 53 super.setUp(); | |
| 54 mTestController = new TestController(); | 66 mTestController = new TestController(); |
| 55 injectObjectAndReload(mTestController, "testController"); | 67 mActivityTestRule.injectObjectAndReload(mTestController, "testController
"); |
| 56 } | 68 } |
| 57 | 69 |
| 70 @Test |
| 58 @SmallTest | 71 @SmallTest |
| 59 @Feature({"AndroidWebView", "Android-JavaBridge"}) | 72 @Feature({"AndroidWebView", "Android-JavaBridge"}) |
| 60 public void testInjectedObjectPresentInChildFrame() throws Throwable { | 73 public void testInjectedObjectPresentInChildFrame() throws Throwable { |
| 61 loadDataSync(getWebContents().getNavigationController(), | 74 loadDataSync(mActivityTestRule.getWebContents().getNavigationController(
), |
| 62 "<html><body><iframe></iframe></body></html>", "text/html", fals
e); | 75 "<html><body><iframe></iframe></body></html>", "text/html", fals
e); |
| 63 // We are not executing this code as a part of page loading routine to a
void races | 76 // We are not executing this code as a part of page loading routine to a
void races |
| 64 // with internal Blink events that notify Java Bridge about window objec
t updates. | 77 // with internal Blink events that notify Java Bridge about window objec
t updates. |
| 65 assertEquals("\"object\"", executeJavaScriptAndGetResult( | 78 Assert.assertEquals("\"object\"", |
| 66 getWebContents(), "typeof window.frames[0].testControlle
r")); | 79 executeJavaScriptAndGetResult(mActivityTestRule.getWebContents()
, |
| 67 executeJavaScriptAndGetResult( | 80 "typeof window.frames[0].testController")); |
| 68 getWebContents(), "window.frames[0].testController.setStringValu
e('PASS')"); | 81 executeJavaScriptAndGetResult(mActivityTestRule.getWebContents(), |
| 69 assertEquals("PASS", mTestController.waitForStringValue()); | 82 "window.frames[0].testController.setStringValue('PASS')"); |
| 83 Assert.assertEquals("PASS", mTestController.waitForStringValue()); |
| 70 } | 84 } |
| 71 | 85 |
| 72 // Verify that loading an iframe doesn't ruin JS wrapper of the main page. | 86 // Verify that loading an iframe doesn't ruin JS wrapper of the main page. |
| 73 // This is a regression test for the problem described in b/15572824. | 87 // This is a regression test for the problem described in b/15572824. |
| 88 @Test |
| 74 @SmallTest | 89 @SmallTest |
| 75 @Feature({"AndroidWebView", "Android-JavaBridge"}) | 90 @Feature({"AndroidWebView", "Android-JavaBridge"}) |
| 76 public void testMainPageWrapperIsNotBrokenByChildFrame() throws Throwable { | 91 public void testMainPageWrapperIsNotBrokenByChildFrame() throws Throwable { |
| 77 loadDataSync(getWebContents().getNavigationController(), | 92 loadDataSync(mActivityTestRule.getWebContents().getNavigationController(
), |
| 78 "<html><body><iframe></iframe></body></html>", "text/html", fals
e); | 93 "<html><body><iframe></iframe></body></html>", "text/html", fals
e); |
| 79 // In case there is anything wrong with the JS wrapper, an attempt | 94 // In case there is anything wrong with the JS wrapper, an attempt |
| 80 // to look up its properties will result in an exception being thrown. | 95 // to look up its properties will result in an exception being thrown. |
| 81 String script = "(function(){ try {" | 96 String script = "(function(){ try {" |
| 82 + " return typeof testController.setStringValue;" | 97 + " return typeof testController.setStringValue;" |
| 83 + "} catch (e) {" | 98 + "} catch (e) {" |
| 84 + " return e.toString();" | 99 + " return e.toString();" |
| 85 + "} })()"; | 100 + "} })()"; |
| 86 assertEquals("\"function\"", | 101 Assert.assertEquals("\"function\"", |
| 87 executeJavaScriptAndGetResult(getWebContents(), script)); | 102 executeJavaScriptAndGetResult(mActivityTestRule.getWebContents()
, script)); |
| 88 // Make sure calling a method also works. | 103 // Make sure calling a method also works. |
| 89 executeJavaScriptAndGetResult(getWebContents(), | 104 executeJavaScriptAndGetResult( |
| 90 "testController.setStringValue('PASS');"); | 105 mActivityTestRule.getWebContents(), "testController.setStringVal
ue('PASS');"); |
| 91 assertEquals("PASS", mTestController.waitForStringValue()); | 106 Assert.assertEquals("PASS", mTestController.waitForStringValue()); |
| 92 } | 107 } |
| 93 | 108 |
| 94 // Verify that parent page and child frame each has own JS wrapper object. | 109 // Verify that parent page and child frame each has own JS wrapper object. |
| 95 // Failing to do so exposes parent's context to the child. | 110 // Failing to do so exposes parent's context to the child. |
| 111 @Test |
| 96 @SmallTest | 112 @SmallTest |
| 97 @Feature({"AndroidWebView", "Android-JavaBridge"}) | 113 @Feature({"AndroidWebView", "Android-JavaBridge"}) |
| 98 public void testWrapperIsNotSharedWithChildFrame() throws Throwable { | 114 public void testWrapperIsNotSharedWithChildFrame() throws Throwable { |
| 99 // Test by setting a custom property on the parent page's injected | 115 // Test by setting a custom property on the parent page's injected |
| 100 // object and then checking that child frame doesn't see the property. | 116 // object and then checking that child frame doesn't see the property. |
| 101 loadDataSync(getWebContents().getNavigationController(), | 117 loadDataSync(mActivityTestRule.getWebContents().getNavigationController(
), |
| 102 "<html><head>" | 118 "<html><head>" |
| 103 + "<script>" | 119 + "<script>" |
| 104 + " window.wProperty = 42;" | 120 + " window.wProperty = 42;" |
| 105 + " testController.tcProperty = 42;" | 121 + " testController.tcProperty = 42;" |
| 106 + " function queryProperties(w) {" | 122 + " function queryProperties(w) {" |
| 107 + " return w.wProperty + ' / ' + w.testController.tcP
roperty;" | 123 + " return w.wProperty + ' / ' + w.testController.tcP
roperty;" |
| 108 + " }" | 124 + " }" |
| 109 + "</script>" | 125 + "</script>" |
| 110 + "</head><body><iframe></iframe></body></html>", "text/
html", false); | 126 + "</head><body><iframe></iframe></body></html>", |
| 111 assertEquals("\"42 / 42\"", | 127 "text/html", false); |
| 112 executeJavaScriptAndGetResult(getWebContents(), "queryProperties
(window)")); | 128 Assert.assertEquals("\"42 / 42\"", |
| 113 assertEquals("\"undefined / undefined\"", | 129 executeJavaScriptAndGetResult( |
| 114 executeJavaScriptAndGetResult(getWebContents(), | 130 mActivityTestRule.getWebContents(), "queryProperties(win
dow)")); |
| 115 "queryProperties(window.frames[0])")); | 131 Assert.assertEquals("\"undefined / undefined\"", |
| 132 executeJavaScriptAndGetResult( |
| 133 mActivityTestRule.getWebContents(), "queryProperties(win
dow.frames[0])")); |
| 116 } | 134 } |
| 117 | 135 |
| 118 // Regression test for crbug.com/484927 -- make sure that existence of trans
ient | 136 // Regression test for crbug.com/484927 -- make sure that existence of trans
ient |
| 119 // objects held by multiple RenderFrames doesn't cause an infinite loop when
one | 137 // objects held by multiple RenderFrames doesn't cause an infinite loop when
one |
| 120 // of them gets removed. | 138 // of them gets removed. |
| 139 @Test |
| 121 @SmallTest | 140 @SmallTest |
| 122 @Feature({"AndroidWebView", "Android-JavaBridge"}) | 141 @Feature({"AndroidWebView", "Android-JavaBridge"}) |
| 123 @DisabledTest(message = "https://crbug.com/677182") | 142 @DisabledTest(message = "https://crbug.com/677182") |
| 124 public void testRemovingTransientObjectHolders() throws Throwable { | 143 public void testRemovingTransientObjectHolders() throws Throwable { |
| 125 class Test { | 144 class Test { |
| 126 private Object mInner = new Object(); | 145 private Object mInner = new Object(); |
| 127 // Expecting the inner object to be retrieved twice. | 146 // Expecting the inner object to be retrieved twice. |
| 128 private CountDownLatch mLatch = new CountDownLatch(2); | 147 private CountDownLatch mLatch = new CountDownLatch(2); |
| 129 @JavascriptInterface | 148 @JavascriptInterface |
| 130 public Object getInner() { | 149 public Object getInner() { |
| 131 mLatch.countDown(); | 150 mLatch.countDown(); |
| 132 return mInner; | 151 return mInner; |
| 133 } | 152 } |
| 134 public void waitForInjection() throws Throwable { | 153 public void waitForInjection() throws Throwable { |
| 135 if (!mLatch.await(5, TimeUnit.SECONDS)) { | 154 if (!mLatch.await(5, TimeUnit.SECONDS)) { |
| 136 throw new TimeoutException(); | 155 throw new TimeoutException(); |
| 137 } | 156 } |
| 138 } | 157 } |
| 139 } | 158 } |
| 140 final Test testObject = new Test(); | 159 final Test testObject = new Test(); |
| 141 | 160 |
| 142 // Due to crbug.com/486262, Java objects are sometimes not injected | 161 // Due to crbug.com/486262, Java objects are sometimes not injected |
| 143 // into newly added frames. To work around this, we load the page first,
so | 162 // into newly added frames. To work around this, we load the page first,
so |
| 144 // all the frames got created, then inject the object. | 163 // all the frames got created, then inject the object. |
| 145 // Thus, the script code fails on the first execution (as no Java object
is | 164 // Thus, the script code fails on the first execution (as no Java object
is |
| 146 // injected yet), but then works just fine after reload. | 165 // injected yet), but then works just fine after reload. |
| 147 loadDataSync(getWebContents().getNavigationController(), | 166 loadDataSync(mActivityTestRule.getWebContents().getNavigationController(
), |
| 148 "<html>" | 167 "<html>" |
| 149 + "<head><script>window.inner_ref = test.getInner()</script></he
ad>" | 168 + "<head><script>window.inner_ref = test.getInner()</scr
ipt></head>" |
| 150 + "<body>" | 169 + "<body>" |
| 151 + " <iframe id='frame' " | 170 + " <iframe id='frame' " |
| 152 + " srcdoc='<script>window.inner_ref = test.getInner()</sc
ript>'>" | 171 + " srcdoc='<script>window.inner_ref = test.getInn
er()</script>'>" |
| 153 + " </iframe>" | 172 + " </iframe>" |
| 154 + "</body></html>", "text/html", false); | 173 + "</body></html>", |
| 155 injectObjectAndReload(testObject, "test"); | 174 "text/html", false); |
| 175 mActivityTestRule.injectObjectAndReload(testObject, "test"); |
| 156 testObject.waitForInjection(); | 176 testObject.waitForInjection(); |
| 157 // Just in case, check that the object wrappers are in place. | 177 // Just in case, check that the object wrappers are in place. |
| 158 assertEquals("\"object\"", | 178 Assert.assertEquals("\"object\"", |
| 159 executeJavaScriptAndGetResult(getWebContents(), "typeof inner_re
f")); | 179 executeJavaScriptAndGetResult( |
| 160 assertEquals("\"object\"", | 180 mActivityTestRule.getWebContents(), "typeof inner_ref"))
; |
| 161 executeJavaScriptAndGetResult(getWebContents(), | 181 Assert.assertEquals("\"object\"", |
| 162 "typeof window.frames[0].inner_ref")); | 182 executeJavaScriptAndGetResult( |
| 183 mActivityTestRule.getWebContents(), "typeof window.frame
s[0].inner_ref")); |
| 163 // Remove the iframe, this will trigger a removal of RenderFrame, which
was causing | 184 // Remove the iframe, this will trigger a removal of RenderFrame, which
was causing |
| 164 // the bug condition, as the transient object still has a holder -- the
main window. | 185 // the bug condition, as the transient object still has a holder -- the
main window. |
| 165 assertEquals("\"object\"", | 186 Assert.assertEquals("\"object\"", |
| 166 executeJavaScriptAndGetResult(getWebContents(), | 187 executeJavaScriptAndGetResult(mActivityTestRule.getWebContents()
, |
| 167 "(function(){ " | 188 "(function(){ " |
| 168 + "var f = document.getElementById('frame');" | 189 + "var f = document.getElementById('frame');" |
| 169 + "f.parentNode.removeChild(f); return typeof f; })()"))
; | 190 + "f.parentNode.removeChild(f); return typeof f;
})()")); |
| 170 // Just in case, check that the remaining wrapper is still accessible. | 191 // Just in case, check that the remaining wrapper is still accessible. |
| 171 assertEquals("\"object\"", | 192 Assert.assertEquals("\"object\"", |
| 172 executeJavaScriptAndGetResult(getWebContents(), | 193 executeJavaScriptAndGetResult( |
| 173 "typeof inner_ref")); | 194 mActivityTestRule.getWebContents(), "typeof inner_ref"))
; |
| 174 } | 195 } |
| 175 | 196 |
| 176 // Regression test for crbug.com/486245 -- assign ownership of a transient o
bject | 197 // Regression test for crbug.com/486245 -- assign ownership of a transient o
bject |
| 177 // to one frame with a code running in the second frame. Deletion of the sec
ond | 198 // to one frame with a code running in the second frame. Deletion of the sec
ond |
| 178 // frame should not affect the injected object. | 199 // frame should not affect the injected object. |
| 200 @Test |
| 179 @SmallTest | 201 @SmallTest |
| 180 @Feature({"AndroidWebView", "Android-JavaBridge"}) | 202 @Feature({"AndroidWebView", "Android-JavaBridge"}) |
| 181 @CommandLineFlags.Add("js-flags=--expose-gc") | 203 @CommandLineFlags.Add("js-flags=--expose-gc") |
| 182 @RetryOnFailure | 204 @RetryOnFailure |
| 183 @DisabledTest(message = "https://crbug.com/646843") | 205 @DisabledTest(message = "https://crbug.com/646843") |
| 184 public void testHolderFrame() throws Throwable { | 206 public void testHolderFrame() throws Throwable { |
| 185 class Test { | 207 class Test { |
| 186 WeakReference<Object> mWeakRefForInner; | 208 WeakReference<Object> mWeakRefForInner; |
| 187 private CountDownLatch mLatch = new CountDownLatch(1); | 209 private CountDownLatch mLatch = new CountDownLatch(1); |
| 188 @JavascriptInterface | 210 @JavascriptInterface |
| 189 public Object getInner() { | 211 public Object getInner() { |
| 190 mLatch.countDown(); | 212 mLatch.countDown(); |
| 191 Object inner = new Object(); | 213 Object inner = new Object(); |
| 192 mWeakRefForInner = new WeakReference<Object>(inner); | 214 mWeakRefForInner = new WeakReference<Object>(inner); |
| 193 return inner; | 215 return inner; |
| 194 } | 216 } |
| 195 public void waitForInjection() throws Throwable { | 217 public void waitForInjection() throws Throwable { |
| 196 if (!mLatch.await(5, TimeUnit.SECONDS)) { | 218 if (!mLatch.await(5, TimeUnit.SECONDS)) { |
| 197 throw new TimeoutException(); | 219 throw new TimeoutException(); |
| 198 } | 220 } |
| 199 } | 221 } |
| 200 } | 222 } |
| 201 final Test testObject = new Test(); | 223 final Test testObject = new Test(); |
| 202 | 224 |
| 203 assertEquals("\"function\"", executeJavaScriptAndGetResult(getWebContent
s(), "typeof gc")); | 225 Assert.assertEquals("\"function\"", |
| 226 executeJavaScriptAndGetResult(mActivityTestRule.getWebContents()
, "typeof gc")); |
| 204 // The page executes in the second frame code which creates a wrapper fo
r a transient | 227 // The page executes in the second frame code which creates a wrapper fo
r a transient |
| 205 // injected object, but makes the first frame the owner of the object. | 228 // injected object, but makes the first frame the owner of the object. |
| 206 loadDataSync(getWebContents().getNavigationController(), | 229 loadDataSync(mActivityTestRule.getWebContents().getNavigationController(
), |
| 207 "<html>" | 230 "<html>" |
| 208 + "<head></head>" | 231 + "<head></head>" |
| 209 + "<body>" | 232 + "<body>" |
| 210 + " <iframe id='frame1' " | 233 + " <iframe id='frame1' " |
| 211 + " srcdoc='<body>I am the Inner object owner!</body>'>" | 234 + " srcdoc='<body>I am the Inner object owner!</bo
dy>'>" |
| 212 + " </iframe>" | 235 + " </iframe>" |
| 213 + " <iframe id='frame2' " | 236 + " <iframe id='frame2' " |
| 214 + " srcdoc='<script>" | 237 + " srcdoc='<script>" |
| 215 + " window.parent.frames[0].inner_ref = test.getInner(
)" | 238 + " window.parent.frames[0].inner_ref = test.g
etInner()" |
| 216 + " </script>'>" | 239 + " </script>'>" |
| 217 + " </iframe>" | 240 + " </iframe>" |
| 218 + "</body></html>", "text/html", false); | 241 + "</body></html>", |
| 219 injectObjectAndReload(testObject, "test"); | 242 "text/html", false); |
| 243 mActivityTestRule.injectObjectAndReload(testObject, "test"); |
| 220 testObject.waitForInjection(); | 244 testObject.waitForInjection(); |
| 221 // Check that the object wrappers are in place. | 245 // Check that the object wrappers are in place. |
| 222 assertTrue(testObject.mWeakRefForInner.get() != null); | 246 Assert.assertTrue(testObject.mWeakRefForInner.get() != null); |
| 223 assertEquals("\"object\"", | 247 Assert.assertEquals("\"object\"", |
| 224 executeJavaScriptAndGetResult(getWebContents(), | 248 executeJavaScriptAndGetResult( |
| 225 "typeof window.frames[0].inner_ref")); | 249 mActivityTestRule.getWebContents(), "typeof window.frame
s[0].inner_ref")); |
| 226 // Remove the second frame. This must not toggle the deletion of the inn
er | 250 // Remove the second frame. This must not toggle the deletion of the inn
er |
| 227 // object. | 251 // object. |
| 228 assertEquals("\"object\"", | 252 Assert.assertEquals("\"object\"", |
| 229 executeJavaScriptAndGetResult(getWebContents(), | 253 executeJavaScriptAndGetResult(mActivityTestRule.getWebContents()
, |
| 230 "(function(){ " | 254 "(function(){ " |
| 231 + "var f = document.getElementById('frame2');" | 255 + "var f = document.getElementById('frame2');" |
| 232 + "f.parentNode.removeChild(f); return typeof f; })()"))
; | 256 + "f.parentNode.removeChild(f); return typeof f;
})()")); |
| 233 // Perform two major GCs at the end to flush out all wrappers | 257 // Perform two major GCs at the end to flush out all wrappers |
| 234 // and other Blink (Oilpan) objects. | 258 // and other Blink (Oilpan) objects. |
| 235 executeJavaScriptAndGetResult(getWebContents(), "for (var i = 0; i < 2;
++i) gc();"); | 259 executeJavaScriptAndGetResult( |
| 260 mActivityTestRule.getWebContents(), "for (var i = 0; i < 2; ++i)
gc();"); |
| 236 // Check that returned Java object is being held by the Java bridge, thu
s it's not | 261 // Check that returned Java object is being held by the Java bridge, thu
s it's not |
| 237 // collected. Note that despite that what JavaDoc says about invoking "
gc()", both Dalvik | 262 // collected. Note that despite that what JavaDoc says about invoking "
gc()", both Dalvik |
| 238 // and ART actually run the collector. | 263 // and ART actually run the collector. |
| 239 Runtime.getRuntime().gc(); | 264 Runtime.getRuntime().gc(); |
| 240 assertNotNull(testObject.mWeakRefForInner.get()); | 265 Assert.assertNotNull(testObject.mWeakRefForInner.get()); |
| 241 // Now, remove the first frame and GC. As it was the only holder of the | 266 // Now, remove the first frame and GC. As it was the only holder of the |
| 242 // inner object's wrapper, the wrapper must be collected. Then, the deat
h | 267 // inner object's wrapper, the wrapper must be collected. Then, the deat
h |
| 243 // of the wrapper must cause removal of the inner object. | 268 // of the wrapper must cause removal of the inner object. |
| 244 assertEquals("\"object\"", | 269 Assert.assertEquals("\"object\"", |
| 245 executeJavaScriptAndGetResult(getWebContents(), | 270 executeJavaScriptAndGetResult(mActivityTestRule.getWebContents()
, |
| 246 "(function(){ " | 271 "(function(){ " |
| 247 + "var f = document.getElementById('frame1');" | 272 + "var f = document.getElementById('frame1');" |
| 248 + "f.parentNode.removeChild(f); return typeof f; })()"))
; | 273 + "f.parentNode.removeChild(f); return typeof f;
})()")); |
| 249 executeJavaScriptAndGetResult(getWebContents(), "for (var i = 0; i < 2;
++i) gc();"); | 274 executeJavaScriptAndGetResult( |
| 275 mActivityTestRule.getWebContents(), "for (var i = 0; i < 2; ++i)
gc();"); |
| 250 Runtime.getRuntime().gc(); | 276 Runtime.getRuntime().gc(); |
| 251 assertNull(testObject.mWeakRefForInner.get()); | 277 Assert.assertNull(testObject.mWeakRefForInner.get()); |
| 252 } | 278 } |
| 253 | 279 |
| 254 private String executeJavaScriptAndGetResult(final WebContents webContents, | 280 private String executeJavaScriptAndGetResult(final WebContents webContents, |
| 255 final String script) throws Throwable { | 281 final String script) throws Throwable { |
| 256 final String[] result = new String[1]; | 282 final String[] result = new String[1]; |
| 257 class ResultCallback extends Controller implements JavaScriptCallback { | 283 class ResultCallback extends Controller implements JavaScriptCallback { |
| 258 @Override | 284 @Override |
| 259 public void handleJavaScriptResult(String jsonResult) { | 285 public void handleJavaScriptResult(String jsonResult) { |
| 260 result[0] = jsonResult; | 286 result[0] = jsonResult; |
| 261 notifyResultIsReady(); | 287 notifyResultIsReady(); |
| 262 } | 288 } |
| 263 } | 289 } |
| 264 final ResultCallback resultCallback = new ResultCallback(); | 290 final ResultCallback resultCallback = new ResultCallback(); |
| 265 runTestOnUiThread(new Runnable() { | 291 InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable(
) { |
| 266 @Override | 292 @Override |
| 267 public void run() { | 293 public void run() { |
| 268 webContents.evaluateJavaScriptForTests(script, resultCallback); | 294 webContents.evaluateJavaScriptForTests(script, resultCallback); |
| 269 } | 295 } |
| 270 }); | 296 }); |
| 271 resultCallback.waitForResult(); | 297 resultCallback.waitForResult(); |
| 272 return result[0]; | 298 return result[0]; |
| 273 } | 299 } |
| 274 | 300 |
| 275 /** | 301 /** |
| 276 * Loads data on the UI thread and blocks until onPageFinished is called. | 302 * Loads data on the UI thread and blocks until onPageFinished is called. |
| 277 */ | 303 */ |
| 278 private void loadDataSync(final NavigationController navigationController, f
inal String data, | 304 private void loadDataSync(final NavigationController navigationController, f
inal String data, |
| 279 final String mimeType, final boolean isBase64Encoded) throws Throwab
le { | 305 final String mimeType, final boolean isBase64Encoded) throws Throwab
le { |
| 280 loadUrl(navigationController, getTestCallBackHelperContainer(), | 306 mActivityTestRule.loadUrl(navigationController, |
| 307 mActivityTestRule.getTestCallBackHelperContainer(), |
| 281 LoadUrlParams.createLoadDataParams(data, mimeType, isBase64Encod
ed)); | 308 LoadUrlParams.createLoadDataParams(data, mimeType, isBase64Encod
ed)); |
| 282 } | 309 } |
| 283 } | 310 } |
| OLD | NEW |