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 |