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