• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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