1 /* 2 * Copyright (C) 2013 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 import java.lang.reflect.Constructor; 18 import java.lang.reflect.InvocationHandler; 19 import java.lang.reflect.InvocationTargetException; 20 import java.lang.reflect.Method; 21 import java.lang.reflect.Field; 22 import java.lang.reflect.Proxy; 23 import java.util.regex.Pattern; 24 25 import dalvik.annotation.optimization.CriticalNative; 26 import dalvik.annotation.optimization.FastNative; 27 28 public class Main { main(String[] args)29 public static void main(String[] args) { 30 System.loadLibrary(args[0]); 31 32 if (!isSlowDebug()) { 33 throw new RuntimeException("Slow-debug flags unexpectedly off."); 34 } 35 36 testFieldSubclass(); 37 testFindClassOnAttachedNativeThread(); 38 testFindFieldOnAttachedNativeThread(); 39 testReflectFieldGetFromAttachedNativeThreadNative(); 40 testCallStaticVoidMethodOnSubClass(); 41 testGetMirandaMethod(); 42 testZeroLengthByteBuffers(); 43 testByteMethod(); 44 testShortMethod(); 45 testBooleanMethod(); 46 testCharMethod(); 47 testIsAssignableFromOnPrimitiveTypes(); 48 testShallowGetCallingClassLoader(); 49 testShallowGetStackClass2(); 50 testCallNonvirtual(); 51 testNewStringObject(); 52 testRemoveLocalObject(); 53 testProxyGetMethodID(); 54 testJniCriticalSectionAndGc(); 55 testCallDefaultMethods(); 56 String lambda = "λ"; 57 testInvokeLambdaMethod(() -> { System.out.println("hi-lambda: " + lambda); }); 58 String def = "δ"; 59 testInvokeLambdaDefaultMethod(() -> { System.out.println("hi-default " + def + lambda); }); 60 61 registerNativesJniTest(); 62 testFastNativeMethods(); 63 testCriticalNativeMethods(); 64 65 testClinitMethodLookup(); 66 67 testDoubleLoad(args[0]); 68 testUTFRegion("\0\0\0"); 69 70 testBadFastCriticalNatives(); 71 } 72 73 static class ABC { public static int XYZ = 12; } 74 static class DEF extends ABC {} testFieldSubclass()75 public static void testFieldSubclass() { 76 try { 77 System.out.println("ABC.XYZ = " + ABC.XYZ + ", GetStaticIntField(DEF.class, 'XYZ') = " + 78 getFieldSubclass(ABC.class.getDeclaredField("XYZ"), DEF.class)); 79 } catch (Exception e) { 80 throw new RuntimeException("Failed to test get static field on a subclass", e); 81 } 82 } 83 testUTFRegion(String null_str)84 public static native void testUTFRegion(String null_str); 85 getFieldSubclass(Field f, Class sub)86 public static native int getFieldSubclass(Field f, Class sub); 87 registerNativesJniTest()88 private static native boolean registerNativesJniTest(); 89 testCallDefaultMethods()90 private static native void testCallDefaultMethods(); 91 testFindClassOnAttachedNativeThread()92 private static native void testFindClassOnAttachedNativeThread(); 93 94 private static boolean testFindFieldOnAttachedNativeThreadField; 95 testReflectFieldGetFromAttachedNativeThreadNative()96 private static native void testReflectFieldGetFromAttachedNativeThreadNative(); 97 98 public static boolean testReflectFieldGetFromAttachedNativeThreadField; 99 testFindFieldOnAttachedNativeThread()100 private static void testFindFieldOnAttachedNativeThread() { 101 testFindFieldOnAttachedNativeThreadNative(); 102 if (!testFindFieldOnAttachedNativeThreadField) { 103 throw new AssertionError(); 104 } 105 } 106 testFindFieldOnAttachedNativeThreadNative()107 private static native void testFindFieldOnAttachedNativeThreadNative(); 108 testCallStaticVoidMethodOnSubClass()109 private static void testCallStaticVoidMethodOnSubClass() { 110 testCallStaticVoidMethodOnSubClassNative(); 111 if (!testCallStaticVoidMethodOnSubClass_SuperClass.executed) { 112 throw new AssertionError(); 113 } 114 } 115 testCallStaticVoidMethodOnSubClassNative()116 private static native void testCallStaticVoidMethodOnSubClassNative(); 117 118 private static class testCallStaticVoidMethodOnSubClass_SuperClass { 119 private static boolean executed = false; execute()120 private static void execute() { 121 executed = true; 122 } 123 } 124 125 private static class testCallStaticVoidMethodOnSubClass_SubClass 126 extends testCallStaticVoidMethodOnSubClass_SuperClass { 127 } 128 testGetMirandaMethodNative()129 private static native Method testGetMirandaMethodNative(); 130 testGetMirandaMethod()131 private static void testGetMirandaMethod() { 132 Method m = testGetMirandaMethodNative(); 133 if (m.getDeclaringClass() != testGetMirandaMethod_MirandaInterface.class) { 134 throw new AssertionError(); 135 } 136 } 137 testZeroLengthByteBuffers()138 private static native void testZeroLengthByteBuffers(); 139 140 private static abstract class testGetMirandaMethod_MirandaAbstract implements testGetMirandaMethod_MirandaInterface { inAbstract()141 public boolean inAbstract() { 142 return true; 143 } 144 } 145 146 private static interface testGetMirandaMethod_MirandaInterface { inInterface()147 public boolean inInterface(); 148 } 149 150 // Test sign-extension for values < 32b 151 byteMethod(byte b1, byte b2, byte b3, byte b4, byte b5, byte b6, byte b7, byte b8, byte b9, byte b10)152 static native byte byteMethod(byte b1, byte b2, byte b3, byte b4, byte b5, byte b6, byte b7, 153 byte b8, byte b9, byte b10); 154 testByteMethod()155 private static void testByteMethod() { 156 byte returns[] = { 0, 1, 2, 127, -1, -2, -128 }; 157 for (int i = 0; i < returns.length; i++) { 158 byte result = byteMethod((byte)i, (byte)2, (byte)(-3), (byte)4, (byte)(-5), (byte)6, 159 (byte)(-7), (byte)8, (byte)(-9), (byte)10); 160 if (returns[i] != result) { 161 System.out.println("Run " + i + " with " + returns[i] + " vs " + result); 162 throw new AssertionError(); 163 } 164 } 165 } 166 removeLocalObject(Object o)167 private static native void removeLocalObject(Object o); 168 testRemoveLocalObject()169 private static void testRemoveLocalObject() { 170 removeLocalObject(new Object()); 171 } 172 shortMethod(short s1, short s2, short s3, short s4, short s5, short s6, short s7, short s8, short s9, short s10)173 private static native short shortMethod(short s1, short s2, short s3, short s4, short s5, short s6, short s7, 174 short s8, short s9, short s10); 175 testShortMethod()176 private static void testShortMethod() { 177 short returns[] = { 0, 1, 2, 127, 32767, -1, -2, -128, -32768 }; 178 for (int i = 0; i < returns.length; i++) { 179 short result = shortMethod((short)i, (short)2, (short)(-3), (short)4, (short)(-5), (short)6, 180 (short)(-7), (short)8, (short)(-9), (short)10); 181 if (returns[i] != result) { 182 System.out.println("Run " + i + " with " + returns[i] + " vs " + result); 183 throw new AssertionError(); 184 } 185 } 186 } 187 188 // Test zero-extension for values < 32b 189 booleanMethod(boolean b1, boolean b2, boolean b3, boolean b4, boolean b5, boolean b6, boolean b7, boolean b8, boolean b9, boolean b10)190 private static native boolean booleanMethod(boolean b1, boolean b2, boolean b3, boolean b4, boolean b5, boolean b6, boolean b7, 191 boolean b8, boolean b9, boolean b10); 192 testBooleanMethod()193 private static void testBooleanMethod() { 194 if (booleanMethod(false, true, false, true, false, true, false, true, false, true)) { 195 throw new AssertionError(); 196 } 197 198 if (!booleanMethod(true, true, false, true, false, true, false, true, false, true)) { 199 throw new AssertionError(); 200 } 201 } 202 charMethod(char c1, char c2, char c3, char c4, char c5, char c6, char c7, char c8, char c9, char c10)203 private static native char charMethod(char c1, char c2, char c3, char c4, char c5, char c6, char c7, 204 char c8, char c9, char c10); 205 testCharMethod()206 private static void testCharMethod() { 207 char returns[] = { (char)0, (char)1, (char)2, (char)127, (char)255, (char)256, (char)15000, 208 (char)34000 }; 209 for (int i = 0; i < returns.length; i++) { 210 char result = charMethod((char)i, 'a', 'b', 'c', '0', '1', '2', (char)1234, (char)2345, 211 (char)3456); 212 if (returns[i] != result) { 213 System.out.println("Run " + i + " with " + (int)returns[i] + " vs " + (int)result); 214 throw new AssertionError(); 215 } 216 } 217 } 218 219 // http://b/16531674 testIsAssignableFromOnPrimitiveTypes()220 private static void testIsAssignableFromOnPrimitiveTypes() { 221 if (!nativeIsAssignableFrom(int.class, Integer.TYPE)) { 222 System.out.println("IsAssignableFrom(int.class, Integer.TYPE) returned false, expected true"); 223 throw new AssertionError(); 224 } 225 226 if (!nativeIsAssignableFrom(Integer.TYPE, int.class)) { 227 System.out.println("IsAssignableFrom(Integer.TYPE, int.class) returned false, expected true"); 228 throw new AssertionError(); 229 } 230 } 231 nativeIsAssignableFrom(Class<?> from, Class<?> to)232 private static native boolean nativeIsAssignableFrom(Class<?> from, Class<?> to); 233 testShallowGetCallingClassLoader()234 private static void testShallowGetCallingClassLoader() { 235 nativeTestShallowGetCallingClassLoader(); 236 } 237 nativeTestShallowGetCallingClassLoader()238 private native static void nativeTestShallowGetCallingClassLoader(); 239 testShallowGetStackClass2()240 private static void testShallowGetStackClass2() { 241 nativeTestShallowGetStackClass2(); 242 } 243 nativeTestShallowGetStackClass2()244 private static native void nativeTestShallowGetStackClass2(); 245 testCallNonvirtual()246 private static native void testCallNonvirtual(); 247 testNewStringObject()248 private static native void testNewStringObject(); 249 250 private interface SimpleInterface { a()251 void a(); 252 } 253 254 private static class MinimalInvocationHandler implements InvocationHandler { invoke(Object proxy, Method method, Object[] args)255 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 256 return null; 257 } 258 } 259 testProxyGetMethodID()260 private static void testProxyGetMethodID() { 261 InvocationHandler handler = new MinimalInvocationHandler(); 262 SimpleInterface proxy = 263 (SimpleInterface) Proxy.newProxyInstance(SimpleInterface.class.getClassLoader(), 264 new Class<?>[] {SimpleInterface.class}, handler); 265 if (testGetMethodID(SimpleInterface.class) == 0) { 266 throw new AssertionError(); 267 } 268 if (testGetMethodID(proxy.getClass()) == 0) { 269 throw new AssertionError(); 270 } 271 } 272 testGetMethodID(Class<?> c)273 private static native long testGetMethodID(Class<?> c); 274 275 // Exercise GC and JNI critical sections in parallel. testJniCriticalSectionAndGc()276 private static void testJniCriticalSectionAndGc() { 277 Thread runGcThread = new Thread(new Runnable() { 278 @Override 279 public void run() { 280 for (int i = 0; i < 10; ++i) { 281 Runtime.getRuntime().gc(); 282 } 283 } 284 }); 285 Thread jniCriticalThread = new Thread(new Runnable() { 286 @Override 287 public void run() { 288 final int arraySize = 32; 289 byte[] array0 = new byte[arraySize]; 290 byte[] array1 = new byte[arraySize]; 291 enterJniCriticalSection(arraySize, array0, array1); 292 } 293 }); 294 jniCriticalThread.start(); 295 runGcThread.start(); 296 try { 297 jniCriticalThread.join(); 298 runGcThread.join(); 299 } catch (InterruptedException ignored) {} 300 } 301 enterJniCriticalSection(int arraySize, byte[] array0, byte[] array)302 private static native void enterJniCriticalSection(int arraySize, byte[] array0, byte[] array); 303 testInvokeLambdaMethod(LambdaInterface iface)304 private static native void testInvokeLambdaMethod(LambdaInterface iface); 305 testInvokeLambdaDefaultMethod(LambdaInterface iface)306 private static native void testInvokeLambdaDefaultMethod(LambdaInterface iface); 307 308 // Test invoking @FastNative methods works correctly. 309 310 // Return sum of a+b+c. 311 @FastNative intFastNativeMethod(int a, int b, int c)312 static native int intFastNativeMethod(int a, int b, int c); 313 testFastNativeMethods()314 private static void testFastNativeMethods() { 315 int returns[] = { 0, 3, 6, 9, 12 }; 316 for (int i = 0; i < returns.length; i++) { 317 int result = intFastNativeMethod(i, i, i); 318 if (returns[i] != result) { 319 System.out.println("FastNative Int Run " + i + " with " + returns[i] + " vs " + result); 320 throw new AssertionError(); 321 } 322 } 323 } 324 325 // Smoke test for @CriticalNative 326 // TODO: Way more thorough tests since it involved quite a bit of changes. 327 328 // Return sum of a+b+c. 329 @CriticalNative intCriticalNativeMethod(int a, int b, int c)330 static native int intCriticalNativeMethod(int a, int b, int c); 331 testCriticalNativeMethods()332 private static void testCriticalNativeMethods() { 333 int returns[] = { 3, 6, 9, 12, 15 }; 334 for (int i = 0; i < returns.length; i++) { 335 int result = intCriticalNativeMethod(i, i+1, i+2); 336 if (returns[i] != result) { 337 System.out.println("CriticalNative Int Run " + i + " with " + returns[i] + " vs " + result); 338 throw new AssertionError(); 339 } 340 } 341 } 342 isSlowDebug()343 private static native boolean isSlowDebug(); 344 testClinitMethodLookup()345 private static void testClinitMethodLookup() { 346 // Expect this to print <NSME Exception> 347 try { 348 System.out.println("Clinit Lookup: ClassWithoutClinit: " + methodString(lookupClinit(ClassWithoutClinit.class))); 349 } catch (NoSuchMethodError e) { 350 System.out.println("Clinit Lookup: ClassWithoutClinit: <NSME Exception>"); 351 } 352 // Expect this to print <clinit> 353 try { 354 System.out.println("Clinit Lookup: ClassWithClinit: " + methodString(lookupClinit(ClassWithClinit.class))); 355 } catch (NoSuchMethodError e) { 356 System.out.println("Clinit Lookup: ClassWithClinit: <NSME Exception>"); 357 } 358 } 359 methodString(java.lang.reflect.Executable method)360 private static String methodString(java.lang.reflect.Executable method) { 361 if (method == null) { 362 return "<<null>>"; 363 } else { 364 return method.toString() + "(Class: " + method.getClass().toString() + ")"; 365 } 366 } lookupClinit(Class kls)367 private static native java.lang.reflect.Executable lookupClinit(Class kls); 368 369 private static class ClassWithoutClinit { 370 } 371 private static class ClassWithClinit { 372 static {} 373 } 374 testDoubleLoad(String library)375 private static void testDoubleLoad(String library) { 376 // Test that nothing observably happens on loading "library" again. 377 System.loadLibrary(library); 378 379 // Now load code in a separate classloader and try to let it load. 380 ClassLoader loader = createClassLoader(); 381 try { 382 Class<?> aClass = loader.loadClass("A"); 383 Method runMethod = aClass.getDeclaredMethod("run", String.class); 384 runMethod.invoke(null, library); 385 } catch (InvocationTargetException ite) { 386 if (ite.getCause() instanceof UnsatisfiedLinkError) { 387 if (!(loader instanceof java.net.URLClassLoader)) { 388 String msg = ite.getCause().getMessage(); 389 String pattern = "^Shared library .*libarttest.* already opened by ClassLoader.*" + 390 "004-JniTest.jar.*; can't open in ClassLoader.*004-JniTest-ex.jar.*"; 391 if (!Pattern.matches(pattern, msg)) { 392 throw new RuntimeException("Could not find pattern in message", ite.getCause()); 393 } 394 } 395 System.out.println("Got UnsatisfiedLinkError for duplicate loadLibrary"); 396 } else { 397 throw new RuntimeException(ite); 398 } 399 } catch (Throwable t) { 400 // Anything else just let die. 401 throw new RuntimeException(t); 402 } 403 } 404 createClassLoader()405 private static ClassLoader createClassLoader() { 406 String location = System.getenv("DEX_LOCATION"); 407 try { 408 Class<?> class_loader_class = Class.forName("dalvik.system.PathClassLoader"); 409 Constructor<?> ctor = class_loader_class.getConstructor(String.class, ClassLoader.class); 410 411 return (ClassLoader)ctor.newInstance(location + "/004-JniTest-ex.jar", 412 Main.class.getClassLoader()); 413 } catch (ClassNotFoundException e) { 414 // Running on RI. Use URLClassLoader. 415 try { 416 return new java.net.URLClassLoader( 417 new java.net.URL[] { new java.net.URL("file://" + location + "/classes-ex/") }); 418 } catch (Throwable t) { 419 throw new RuntimeException(t); 420 } 421 } catch (Throwable t) { 422 throw new RuntimeException(t); 423 } 424 } 425 testBadFastCriticalNatives()426 private static void testBadFastCriticalNatives() { 427 testBadFastCriticalNative("BadFastNative"); 428 testBadFastCriticalNative("BadCriticalNative"); 429 testBadFastCriticalNative("BadCriticalNative2"); 430 testBadFastCriticalNative("BadCriticalNative3"); 431 } 432 testBadFastCriticalNative(String className)433 private static void testBadFastCriticalNative(String className) { 434 try { 435 Class.forName(className); 436 throw new Error("Expected verification error"); 437 } catch (VerifyError e) { 438 // Expected. 439 } catch (Throwable e) { 440 throw new Error("Expected verification error"); 441 } 442 } 443 } 444 445 @FunctionalInterface 446 interface LambdaInterface { sayHi()447 public void sayHi(); sayHiTwice()448 public default void sayHiTwice() { 449 sayHi(); 450 sayHi(); 451 } 452 } 453 454 class JniCallNonvirtualTest { 455 public boolean nonstaticMethodSuperCalled = false; 456 public boolean nonstaticMethodSubCalled = false; 457 testCallNonvirtual()458 private static native void testCallNonvirtual(); 459 JniCallNonvirtualTest()460 public JniCallNonvirtualTest() { 461 System.out.println("Super.<init>"); 462 } 463 staticMethod()464 public static void staticMethod() { 465 System.out.println("Super.staticMethod"); 466 } 467 nonstaticMethod()468 public void nonstaticMethod() { 469 System.out.println("Super.nonstaticMethod"); 470 nonstaticMethodSuperCalled = true; 471 } 472 } 473 474 class JniCallNonvirtualTestSubclass extends JniCallNonvirtualTest { 475 JniCallNonvirtualTestSubclass()476 public JniCallNonvirtualTestSubclass() { 477 System.out.println("Subclass.<init>"); 478 } 479 staticMethod()480 public static void staticMethod() { 481 System.out.println("Subclass.staticMethod"); 482 } 483 nonstaticMethod()484 public void nonstaticMethod() { 485 System.out.println("Subclass.nonstaticMethod"); 486 nonstaticMethodSubCalled = true; 487 } 488 } 489 490 class BadFastNative { 491 @FastNative test()492 public static native synchronized void test(); 493 } 494 495 class BadCriticalNative { 496 @CriticalNative test()497 public static native synchronized void test(); 498 } 499 500 class BadCriticalNative2 { 501 @CriticalNative test()502 public native void test(); 503 } 504 505 class BadCriticalNative3 { 506 @CriticalNative test(Object o)507 public static native void test(Object o); 508 } 509