1 /* 2 * Copyright (C) 2016 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.ref.*; 20 import java.lang.reflect.*; 21 import java.lang.invoke.*; 22 import java.util.*; 23 24 public class Test1976 { 25 26 // The fact that the target is having methods added makes it annoying to test since we cannot 27 // initially call them. To work around this in a simple-ish way just use (non-structural) 28 // redefinition to change the implementation of the caller of Transform1976 after redefining the 29 // target. 30 public static final class RunTransformMethods implements Runnable { run()31 public void run() { 32 System.out.println("Saying everything!"); 33 Transform1976.sayEverything(); 34 System.out.println("Saying hi!"); 35 Transform1976.sayHi(); 36 } 37 } 38 39 /* Base64 encoded dex bytes of: 40 * public static final class RunTransformMethods implements Runnable { 41 * public void run() { 42 * System.out.println("Saying everything!"); 43 * Transform1976.sayEverything(); 44 * System.out.println("Saying hi!"); 45 * Transform1976.sayHi(); 46 * System.out.println("Saying bye!"); 47 * Transform1976.sayBye(); 48 * } 49 * } 50 */ 51 public static final byte[] RUN_DEX_BYTES = 52 Base64.getDecoder() 53 .decode( 54 "ZGV4CjAzNQCv3eV8jFcpSsqMGl1ZXRk2iraZO41D0TIgBQAAcAAAAHhWNBIAAAAAAAAAAFwEAAAc" 55 + "AAAAcAAAAAsAAADgAAAAAgAAAAwBAAABAAAAJAEAAAcAAAAsAQAAAQAAAGQBAACcAwAAhAEAAAYC" 56 + "AAAOAgAAMgIAAEICAABXAgAAewIAAJsCAACyAgAAxgIAANwCAADwAgAABAMAABkDAAAmAwAAOgMA" 57 + "AEYDAABVAwAAWAMAAFwDAABpAwAAbwMAAHQDAAB9AwAAggMAAIoDAACZAwAAoAMAAKcDAAABAAAA" 58 + "AgAAAAMAAAAEAAAABQAAAAYAAAAHAAAACAAAAAkAAAAKAAAAEAAAABAAAAAKAAAAAAAAABEAAAAK" 59 + "AAAAAAIAAAkABQAUAAAAAAAAAAAAAAAAAAAAFgAAAAIAAAAXAAAAAgAAABgAAAACAAAAGQAAAAUA" 60 + "AQAVAAAABgAAAAAAAAAAAAAAEQAAAAYAAAD4AQAADwAAAEwEAAAuBAAAAAAAAAEAAQABAAAA6gEA" 61 + "AAQAAABwEAYAAAAOAAMAAQACAAAA7gEAAB8AAABiAAAAGgENAG4gBQAQAHEAAwAAAGIAAAAaAQ4A" 62 + "biAFABAAcQAEAAAAYgAAABoBDABuIAUAEABxAAIAAAAOAAYADgAIAA54PHg8eDwAAQAAAAcAAAAB" 63 + "AAAACAAGPGluaXQ+ACJMYXJ0L1Rlc3QxOTc2JFJ1blRyYW5zZm9ybU1ldGhvZHM7AA5MYXJ0L1Rl" 64 + "c3QxOTc2OwATTGFydC9UcmFuc2Zvcm0xOTc2OwAiTGRhbHZpay9hbm5vdGF0aW9uL0VuY2xvc2lu" 65 + "Z0NsYXNzOwAeTGRhbHZpay9hbm5vdGF0aW9uL0lubmVyQ2xhc3M7ABVMamF2YS9pby9QcmludFN0" 66 + "cmVhbTsAEkxqYXZhL2xhbmcvT2JqZWN0OwAUTGphdmEvbGFuZy9SdW5uYWJsZTsAEkxqYXZhL2xh" 67 + "bmcvU3RyaW5nOwASTGphdmEvbGFuZy9TeXN0ZW07ABNSdW5UcmFuc2Zvcm1NZXRob2RzAAtTYXlp" 68 + "bmcgYnllIQASU2F5aW5nIGV2ZXJ5dGhpbmchAApTYXlpbmcgaGkhAA1UZXN0MTk3Ni5qYXZhAAFW" 69 + "AAJWTAALYWNjZXNzRmxhZ3MABG5hbWUAA291dAAHcHJpbnRsbgADcnVuAAZzYXlCeWUADXNheUV2" 70 + "ZXJ5dGhpbmcABXNheUhpAAV2YWx1ZQB2fn5EOHsiY29tcGlsYXRpb24tbW9kZSI6ImRlYnVnIiwi" 71 + "bWluLWFwaSI6MSwic2hhLTEiOiJhODM1MmYyNTQ4ODUzNjJjY2Q4ZDkwOWQzNTI5YzYwMDk0ZGQ4" 72 + "OTZlIiwidmVyc2lvbiI6IjEuNi4yMC1kZXYifQACAwEaGAECBAISBBkTFwsAAAEBAIGABIQDAQGc" 73 + "AwAAAAACAAAAHwQAACUEAABABAAAAAAAAAAAAAAAAAAAEAAAAAAAAAABAAAAAAAAAAEAAAAcAAAA" 74 + "cAAAAAIAAAALAAAA4AAAAAMAAAACAAAADAEAAAQAAAABAAAAJAEAAAUAAAAHAAAALAEAAAYAAAAB" 75 + "AAAAZAEAAAEgAAACAAAAhAEAAAMgAAACAAAA6gEAAAEQAAACAAAA+AEAAAIgAAAcAAAABgIAAAQg" 76 + "AAACAAAAHwQAAAAgAAABAAAALgQAAAMQAAACAAAAPAQAAAYgAAABAAAATAQAAAAQAAABAAAAXAQA" 77 + "AA=="); 78 run()79 public static void run() throws Exception { 80 Redefinition.setTestConfiguration(Redefinition.Config.COMMON_REDEFINE); 81 doTest(); 82 } 83 84 private static final boolean PRINT_ID_NUM = false; 85 printRun(long id, Method m)86 public static void printRun(long id, Method m) { 87 if (PRINT_ID_NUM) { 88 System.out.println("Running method " + id + " " + m + " using JNI."); 89 } else { 90 System.out.println("Running method " + m + " using JNI."); 91 } 92 } 93 94 public static final class MethodHandleWrapper { 95 private MethodHandle mh; 96 private Method m; MethodHandleWrapper(MethodHandle mh, Method m)97 public MethodHandleWrapper(MethodHandle mh, Method m) { 98 this.m = m; 99 this.mh = mh; 100 } getHandle()101 public MethodHandle getHandle() { 102 return mh; 103 } getMethod()104 public Method getMethod() { 105 return m; 106 } invoke()107 public Object invoke() throws Throwable { 108 return mh.invoke(); 109 } toString()110 public String toString() { 111 return mh.toString(); 112 } 113 } 114 getMethodHandles(Method[] methods)115 public static MethodHandleWrapper[] getMethodHandles(Method[] methods) throws Exception { 116 final MethodHandles.Lookup l = MethodHandles.lookup(); 117 ArrayList<MethodHandleWrapper> res = new ArrayList<>(); 118 for (Method m : methods) { 119 if (!Modifier.isStatic(m.getModifiers())) { 120 continue; 121 } 122 res.add(new MethodHandleWrapper(l.unreflect(m), m)); 123 } 124 return res.toArray(new MethodHandleWrapper[0]); 125 } 126 runMethodHandles(MethodHandleWrapper[] handles)127 public static void runMethodHandles(MethodHandleWrapper[] handles) throws Exception { 128 for (MethodHandleWrapper h : handles) { 129 try { 130 System.out.println("Invoking " + h + " (" + h.getMethod() + ")"); 131 h.invoke(); 132 } catch (Throwable t) { 133 if (t instanceof Exception) { 134 throw (Exception)t; 135 } else if (t instanceof Error) { 136 throw (Error)t; 137 } else { 138 throw new RuntimeException("Unexpected throwable thrown!", t); 139 } 140 } 141 } 142 } 143 doTest()144 public static void doTest() throws Exception { 145 Runnable r = new RunTransformMethods(); 146 System.out.println("Running directly"); 147 r.run(); 148 System.out.println("Running reflective"); 149 Method[] methods = Transform1976.class.getDeclaredMethods(); 150 for (Method m : methods) { 151 if (Modifier.isStatic(m.getModifiers())) { 152 System.out.println("Reflectively invoking " + m); 153 m.invoke(null); 154 } else { 155 System.out.println("Not invoking non-static method " + m); 156 } 157 } 158 System.out.println("Running jni"); 159 long[] mids = getMethodIds(methods); 160 callNativeMethods(Transform1976.class, mids); 161 MethodHandleWrapper[] handles = getMethodHandles(methods); 162 System.out.println("Running method handles"); 163 runMethodHandles(handles); 164 Redefinition.doCommonStructuralClassRedefinition( 165 Transform1976.class, Transform1976.REDEFINED_DEX_BYTES); 166 // Change RunTransformMethods to also call the 'runBye' method. No RI support so no classfile 167 // bytes required. 168 Redefinition.doCommonClassRedefinition(RunTransformMethods.class, new byte[] {}, RUN_DEX_BYTES); 169 System.out.println("Running directly after redef"); 170 r.run(); 171 System.out.println("Running reflective after redef using old j.l.r.Method"); 172 for (Method m : methods) { 173 if (Modifier.isStatic(m.getModifiers())) { 174 System.out.println("Reflectively invoking " + m + " on old j.l.r.Method"); 175 m.invoke(null); 176 } else { 177 System.out.println("Not invoking non-static method " + m); 178 } 179 } 180 System.out.println("Running reflective after redef using new j.l.r.Method"); 181 for (Method m : Transform1976.class.getDeclaredMethods()) { 182 if (Modifier.isStatic(m.getModifiers())) { 183 System.out.println("Reflectively invoking " + m + " on new j.l.r.Method"); 184 m.invoke(null); 185 } else { 186 System.out.println("Not invoking non-static method " + m); 187 } 188 } 189 System.out.println("Running jni with old ids"); 190 callNativeMethods(Transform1976.class, mids); 191 System.out.println("Running jni with new ids"); 192 callNativeMethods(Transform1976.class, getMethodIds(Transform1976.class.getDeclaredMethods())); 193 194 System.out.println("Running method handles using old handles"); 195 runMethodHandles(handles); 196 System.out.println("Running method handles using new handles"); 197 runMethodHandles(getMethodHandles(Transform1976.class.getDeclaredMethods())); 198 } 199 getMethodIds(Method[] m)200 public static native long[] getMethodIds(Method[] m); 201 callNativeMethods(Class<?> k, long[] smethods)202 public static native void callNativeMethods(Class<?> k, long[] smethods); 203 } 204