| 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.os.Handler; | |
| 8 import android.os.Looper; | |
| 9 import android.test.suitebuilder.annotation.SmallTest; | 7 import android.test.suitebuilder.annotation.SmallTest; |
| 10 | 8 |
| 11 import org.chromium.base.test.util.DisabledTest; | |
| 12 import org.chromium.base.test.util.Feature; | 9 import org.chromium.base.test.util.Feature; |
| 13 import org.chromium.content.browser.test.util.TestCallbackHelperContainer; | 10 import org.chromium.content.browser.test.util.TestCallbackHelperContainer; |
| 14 import org.chromium.content_shell_apk.ContentShellActivity; | 11 import org.chromium.content_shell_apk.ContentShellActivity; |
| 15 | 12 |
| 16 import java.lang.annotation.Annotation; | 13 import java.lang.annotation.Annotation; |
| 17 import java.lang.annotation.ElementType; | 14 import java.lang.annotation.ElementType; |
| 18 import java.lang.annotation.Retention; | 15 import java.lang.annotation.Retention; |
| 19 import java.lang.annotation.RetentionPolicy; | 16 import java.lang.annotation.RetentionPolicy; |
| 20 import java.lang.annotation.Target; | 17 import java.lang.annotation.Target; |
| 21 import java.lang.ref.WeakReference; | 18 import java.lang.ref.WeakReference; |
| (...skipping 433 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 455 assertEquals("true", executeJavaScriptAndGetStringResult( | 452 assertEquals("true", executeJavaScriptAndGetStringResult( |
| 456 "(function() { " + | 453 "(function() { " + |
| 457 "delete globalInner; gc(); return (typeof globalInner ==
'undefined'); " + | 454 "delete globalInner; gc(); return (typeof globalInner ==
'undefined'); " + |
| 458 "})()")); | 455 "})()")); |
| 459 // Force GC on the Java side again. The bridge had to release the inner
object, so it must | 456 // Force GC on the Java side again. The bridge had to release the inner
object, so it must |
| 460 // be collected this time. | 457 // be collected this time. |
| 461 Runtime.getRuntime().gc(); | 458 Runtime.getRuntime().gc(); |
| 462 assertEquals(null, object.weakRefForInner.get()); | 459 assertEquals(null, object.weakRefForInner.get()); |
| 463 } | 460 } |
| 464 | 461 |
| 465 /* | 462 @SmallTest |
| 466 * The current Java bridge implementation doesn't reuse JS wrappers when ret
urning | 463 @Feature({"AndroidWebView", "Android-JavaBridge"}) |
| 467 * the same object from a method. That looks wrong. For example, in the case
of DOM, | |
| 468 * wrappers are reused, which allows JS code to attach custom properties to
interface | |
| 469 * objects and use them regardless of the way the reference has been obtaine
d: | |
| 470 * via copying a JS reference or by calling the method one more time (assumi
ng that | |
| 471 * the method is supposed to return a reference to the same object each time
). | |
| 472 * TODO(mnaganov): Fix this in the new implementation. | |
| 473 * | |
| 474 * @SmallTest | |
| 475 * @Feature({"AndroidWebView", "Android-JavaBridge"}) | |
| 476 */ | |
| 477 @DisabledTest | |
| 478 public void testSameReturnedObjectUsesSameWrapper() throws Throwable { | 464 public void testSameReturnedObjectUsesSameWrapper() throws Throwable { |
| 479 class InnerObject { | 465 class InnerObject { |
| 480 } | 466 } |
| 481 final InnerObject innerObject = new InnerObject(); | 467 final InnerObject innerObject = new InnerObject(); |
| 482 final Object injectedTestObject = new Object() { | 468 final Object injectedTestObject = new Object() { |
| 483 public InnerObject getInnerObject() { | 469 public InnerObject getInnerObject() { |
| 484 return innerObject; | 470 return innerObject; |
| 485 } | 471 } |
| 486 }; | 472 }; |
| 487 injectObjectAndReload(injectedTestObject, "injectedTestObject"); | 473 injectObjectAndReload(injectedTestObject, "injectedTestObject"); |
| (...skipping 358 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 846 String.format(jsObjectKeysTestTemplate, nonInspectableOb
jectName))); | 832 String.format(jsObjectKeysTestTemplate, nonInspectableOb
jectName))); |
| 847 assertEquals("", executeJavaScriptAndGetStringResult( | 833 assertEquals("", executeJavaScriptAndGetStringResult( |
| 848 String.format(jsForInTestTemplate, nonInspectableObjectN
ame))); | 834 String.format(jsForInTestTemplate, nonInspectableObjectN
ame))); |
| 849 } | 835 } |
| 850 | 836 |
| 851 @SmallTest | 837 @SmallTest |
| 852 @Feature({"AndroidWebView", "Android-JavaBridge"}) | 838 @Feature({"AndroidWebView", "Android-JavaBridge"}) |
| 853 public void testAccessToObjectGetClassIsBlocked() throws Throwable { | 839 public void testAccessToObjectGetClassIsBlocked() throws Throwable { |
| 854 injectObjectAndReload(new Object(), "testObject"); | 840 injectObjectAndReload(new Object(), "testObject"); |
| 855 assertEquals("function", executeJavaScriptAndGetStringResult("typeof tes
tObject.getClass")); | 841 assertEquals("function", executeJavaScriptAndGetStringResult("typeof tes
tObject.getClass")); |
| 856 boolean securityExceptionThrown = false; | 842 assertRaisesException("testObject.getClass()"); |
| 857 try { | |
| 858 final String result = executeJavaScriptAndWaitForExceptionSynchronou
sly( | |
| 859 "typeof testObject.getClass()"); | |
| 860 fail("A call to java.lang.Object.getClass has been allowed, result:
'" + result + "'"); | |
| 861 } catch (SecurityException exception) { | |
| 862 securityExceptionThrown = true; | |
| 863 } | |
| 864 assertTrue(securityExceptionThrown); | |
| 865 } | |
| 866 | |
| 867 // Unlike executeJavaScriptAndGetStringResult, this method is sitting on the
UI thread | |
| 868 // until a non-null result is obtained or a Java exception has been thrown.
This method is | |
| 869 // capable of catching Java RuntimeExceptions happening on the UI thread asy
nchronously. | |
| 870 private String executeJavaScriptAndWaitForExceptionSynchronously(final Strin
g script) | |
| 871 throws Throwable { | |
| 872 class ExitLoopException extends RuntimeException { | |
| 873 } | |
| 874 mTestController.setStringValue(null); | |
| 875 runTestOnUiThread(new Runnable() { | |
| 876 @Override | |
| 877 public void run() { | |
| 878 getContentViewCore().loadUrl(new LoadUrlParams("javascript:(func
tion() { " + | |
| 879 "testController.setStringValue(" + script + ") }
)()")); | |
| 880 do { | |
| 881 final Boolean[] deactivateExitLoopTask = new Boolean[1]; | |
| 882 deactivateExitLoopTask[0] = false; | |
| 883 // We can't use Loop.quit(), as this is the main looper, so
we throw | |
| 884 // an exception to bail out from the loop. | |
| 885 new Handler(Looper.myLooper()).post(new Runnable() { | |
| 886 @Override | |
| 887 public void run() { | |
| 888 if (!deactivateExitLoopTask[0]) { | |
| 889 throw new ExitLoopException(); | |
| 890 } | |
| 891 } | |
| 892 }); | |
| 893 try { | |
| 894 Looper.loop(); | |
| 895 } catch (ExitLoopException e) { | |
| 896 // Intentionally empty. | |
| 897 } catch (RuntimeException e) { | |
| 898 // Prevent the task that throws the ExitLoopException fr
om exploding | |
| 899 // on the main loop outside of this function. | |
| 900 deactivateExitLoopTask[0] = true; | |
| 901 throw e; | |
| 902 } | |
| 903 } while (mTestController.getStringValue() == null || | |
| 904 // When an exception in an injected method happens, the
function returns | |
| 905 // null. We ignore this and wait until the exception on
the browser side | |
| 906 // will be thrown. | |
| 907 mTestController.getStringValue().equals("null")); | |
| 908 } | |
| 909 }); | |
| 910 return mTestController.getStringValue(); | |
| 911 } | 843 } |
| 912 } | 844 } |
| OLD | NEW |