1 /*
2  * Copyright (C) 2017 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 package art;
18 
19 import java.lang.reflect.Constructor;
20 import java.lang.reflect.Method;
21 import java.nio.ByteBuffer;
22 import java.util.Arrays;
23 import java.util.Base64;
24 
25 public class Test1901 {
26   // Class & Dex file containing the following class.
27   // Using this representation to prevent any changes to the compiler or the file formats from
28   // changing the output of this test.
29   //
30   // package art;
31   // public class Target {
32   //   public void doNothing() {
33   //     return;
34   //   }
35   //
36   //   public static void staticNothing() {
37   //     return;
38   //   }
39   //
40   //   public void sayHi() {
41   //     System.out.println("hello");
42   //   }
43   // }
44   public static byte[] CLASS_BYTES = Base64.getDecoder().decode(
45     "yv66vgAAADQAHgoABgAQCQARABIIABMKABQAFQcAFgcAFwEABjxpbml0PgEAAygpVgEABENvZGUB" +
46     "AA9MaW5lTnVtYmVyVGFibGUBAAlkb05vdGhpbmcBAA1zdGF0aWNOb3RoaW5nAQAFc2F5SGkBAApT" +
47     "b3VyY2VGaWxlAQALVGFyZ2V0LmphdmEMAAcACAcAGAwAGQAaAQAFaGVsbG8HABsMABwAHQEACmFy" +
48     "dC9UYXJnZXQBABBqYXZhL2xhbmcvT2JqZWN0AQAQamF2YS9sYW5nL1N5c3RlbQEAA291dAEAFUxq" +
49     "YXZhL2lvL1ByaW50U3RyZWFtOwEAE2phdmEvaW8vUHJpbnRTdHJlYW0BAAdwcmludGxuAQAVKExq" +
50     "YXZhL2xhbmcvU3RyaW5nOylWACEABQAGAAAAAAAEAAEABwAIAAEACQAAAB0AAQABAAAABSq3AAGx" +
51     "AAAAAQAKAAAABgABAAAAAgABAAsACAABAAkAAAAZAAAAAQAAAAGxAAAAAQAKAAAABgABAAAABAAJ" +
52     "AAwACAABAAkAAAAZAAAAAAAAAAGxAAAAAQAKAAAABgABAAAACAABAA0ACAABAAkAAAAlAAIAAQAA" +
53     "AAmyAAISA7YABLEAAAABAAoAAAAKAAIAAAAMAAgADQABAA4AAAACAA8=");
54   public static byte[] DEX_BYTES = Base64.getDecoder().decode(
55     "ZGV4CjAzNQAbYkxNjiZ8a+fNWF4smR2+uXbrq88/FNoYAwAAcAAAAHhWNBIAAAAAAAAAAHgCAAAP" +
56     "AAAAcAAAAAYAAACsAAAAAgAAAMQAAAABAAAA3AAAAAYAAADkAAAAAQAAABQBAADkAQAANAEAAJoB" +
57     "AACiAQAAsAEAAMcBAADbAQAA7wEAAAMCAAAQAgAAEwIAABcCAAAiAgAAKQIAAC4CAAA3AgAAPgIA" +
58     "AAEAAAACAAAAAwAAAAQAAAAFAAAABwAAAAcAAAAFAAAAAAAAAAgAAAAFAAAAlAEAAAQAAQALAAAA" +
59     "AAAAAAAAAAAAAAAACQAAAAAAAAANAAAAAAAAAA4AAAABAAEADAAAAAIAAAAAAAAAAAAAAAEAAAAC" +
60     "AAAAAAAAAAYAAAAAAAAAYgIAAAAAAAABAAEAAQAAAE0CAAAEAAAAcBAFAAAADgAAAAAAAAAAAFIC" +
61     "AAABAAAADgAAAAEAAQAAAAAAVwIAAAEAAAAOAAAAAwABAAIAAABcAgAACAAAAGIAAAAaAQoAbiAE" +
62     "ABAADgABAAAAAwAGPGluaXQ+AAxMYXJ0L1RhcmdldDsAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwAS" +
63     "TGphdmEvbGFuZy9PYmplY3Q7ABJMamF2YS9sYW5nL1N0cmluZzsAEkxqYXZhL2xhbmcvU3lzdGVt" +
64     "OwALVGFyZ2V0LmphdmEAAVYAAlZMAAlkb05vdGhpbmcABWhlbGxvAANvdXQAB3ByaW50bG4ABXNh" +
65     "eUhpAA1zdGF0aWNOb3RoaW5nAAIABw4ACAAHDgAEAAcOAAwABw54AAAAAgIAgYAEtAIDCcwCAQHg" +
66     "AgEB9AINAAAAAAAAAAEAAAAAAAAAAQAAAA8AAABwAAAAAgAAAAYAAACsAAAAAwAAAAIAAADEAAAA" +
67     "BAAAAAEAAADcAAAABQAAAAYAAADkAAAABgAAAAEAAAAUAQAAASAAAAQAAAA0AQAAARAAAAEAAACU" +
68     "AQAAAiAAAA8AAACaAQAAAyAAAAQAAABNAgAAACAAAAEAAABiAgAAABAAAAEAAAB4AgAA");
69 
70   public static byte[][] DO_NOTHING_BYTECODES = new byte[][] {
71     // Dex Bytecodes for doNothing
72     // 0e00           |0000: return-void
73     new byte[] { 14, 0 },
74     // Java bytecodes
75     // 0: return
76     new byte[] { -79 },
77   };
78 
79   public static byte[][] STATIC_NOTHING_BYTECODES = new byte[][] {
80     // Dex Bytecodes for staticNothing
81     // 0e00           |0000: return-void
82     new byte[] { 14, 0 },
83     // Java bytecodes
84     // 0: return
85     new byte[] { -79 },
86   };
87 
88   public static byte[][] SAY_HI_NOTHING_BYTECODES = new byte[][] {
89     // Dex Bytecodes for sayHi
90     // 6200 0000      |0000: sget-object v0, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0000
91     // 1a01 0a00      |0002: const-string v1, "hello" // string@000a
92     // 6e20 0400 1000 |0004: invoke-virtual {v0, v1}, Ljava/io/PrintStream;.println:(Ljava/lang/String;)V // method@0004
93     // 0e00           |0007: return-void
94     new byte[] { 98, 0, 0, 0, 26, 1, 10, 0, 110, 32, 4, 0, 16, 0, 14, 0 },
95     // Java bytecodes
96     // 0: getstatic     #2  // Field java/lang/System.out:Ljava/io/PrintStream;
97     // 3: ldc           #3  // String hello
98     // 5: invokevirtual #4  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
99     // 8: return
100     new byte[] { -78, 0, 2, 18, 3, -74, 0, 4, -79 },
101   };
102 
getClassLoader()103   public static ClassLoader getClassLoader() throws Exception {
104     try {
105       Class<?> class_loader_class = Class.forName("dalvik.system.InMemoryDexClassLoader");
106       Constructor<?> ctor = class_loader_class.getConstructor(ByteBuffer.class, ClassLoader.class);
107       // We are on art since we got the InMemoryDexClassLoader.
108       return (ClassLoader)ctor.newInstance(
109           ByteBuffer.wrap(DEX_BYTES), Test1901.class.getClassLoader());
110     } catch (ClassNotFoundException e) {
111       // Running on RI.
112       return new ClassLoader(Test1901.class.getClassLoader()) {
113         protected Class<?> findClass(String name) throws ClassNotFoundException {
114           if (name.equals("art.Target")) {
115             return defineClass(name, CLASS_BYTES, 0, CLASS_BYTES.length);
116           } else {
117             return super.findClass(name);
118           }
119         }
120       };
121     }
122   }
123 
CheckMethodBytes(Method m, byte[][] possible_bytecodes)124   public static void CheckMethodBytes(Method m, byte[][] possible_bytecodes) {
125     byte[] real_codes = getBytecodes(m);
126     for (byte[] pos : possible_bytecodes) {
127       if (Arrays.equals(pos, real_codes)) {
128         return;
129       }
130     }
131     System.out.println("Unexpected bytecodes for " + m);
132     System.out.println("Received: " + Arrays.toString(real_codes));
133     System.out.println("Expected one of:");
134     for (byte[] pos : possible_bytecodes) {
135       System.out.println("\t" + Arrays.toString(pos));
136     }
137   }
138 
run()139   public static void run() throws Exception {
140     Class<?> target = getClassLoader().loadClass("art.Target");
141     CheckMethodBytes(target.getDeclaredMethod("doNothing"), DO_NOTHING_BYTECODES);
142     CheckMethodBytes(target.getDeclaredMethod("staticNothing"), STATIC_NOTHING_BYTECODES);
143     CheckMethodBytes(target.getDeclaredMethod("sayHi"), SAY_HI_NOTHING_BYTECODES);
144   }
145 
getBytecodes(Method m)146   public static native byte[] getBytecodes(Method m);
147 }
148