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.util.*; 22 23 public class Test1982 { run()24 public static void run() throws Exception { 25 Redefinition.setTestConfiguration(Redefinition.Config.COMMON_REDEFINE); 26 doTest(); 27 } 28 29 private static final boolean PRINT_NONDETERMINISTIC = false; 30 31 public static WeakHashMap<Object, Long> id_nums = new WeakHashMap<>(); 32 public static long next_id = 0; 33 printGeneric(Object o)34 public static String printGeneric(Object o) { 35 Long id = id_nums.get(o); 36 if (id == null) { 37 id = Long.valueOf(next_id++); 38 id_nums.put(o, id); 39 } 40 if (o == null) { 41 return "(ID: " + id + ") <NULL>"; 42 } 43 Class oc = o.getClass(); 44 if (oc.isArray() && oc.getComponentType() == Byte.TYPE) { 45 return "(ID: " 46 + id 47 + ") " 48 + Arrays.toString(Arrays.copyOf((byte[]) o, 10)).replace(']', ',') 49 + " ...]"; 50 } else { 51 return "(ID: " + id + ") " + o.toString(); 52 } 53 } 54 doRedefinition()55 private static void doRedefinition() { 56 Redefinition.doCommonStructuralClassRedefinition(Transform.class, REDEFINED_DEX_BYTES); 57 } 58 readReflective(String msg, Field[] fields, Object recv)59 private static void readReflective(String msg, Field[] fields, Object recv) throws Exception { 60 System.out.println(msg); 61 for (Field f : fields) { 62 System.out.println( 63 f.toString() + " on " + printGeneric(recv) + " = " + printGeneric(f.get(recv))); 64 } 65 } 66 67 public static class SuperTransform { 68 public int id; 69 SuperTransform(int id)70 public SuperTransform(int id) { 71 this.id = id; 72 } 73 toString()74 public String toString() { 75 return "SuperTransform { id: " + id + ", class: " + getClass() + " }"; 76 } 77 } 78 79 public static class Transform extends SuperTransform { 80 static { 81 } 82 83 public static Object BAR = 84 new Object() { 85 public String toString() { 86 return "value of <" + this.get() + ">"; 87 } 88 89 public Object get() { 90 return "BAR FIELD"; 91 } 92 }; 93 public static Object FOO = 94 new Object() { 95 public String toString() { 96 return "value of <" + this.get() + ">"; 97 } 98 99 public Object get() { 100 return "FOO FIELD"; 101 } 102 }; 103 // This class has no virtual fields or methods. This means we can structurally redefine it 104 // without having to change the size of any instances. Transform(int id)105 public Transform(int id) { 106 super(id); 107 } 108 staticToString()109 public static String staticToString() { 110 return Transform.class.toString() + "[FOO: " + FOO + ", BAR: " + BAR + "]"; 111 } 112 } 113 114 public static class SubTransform extends Transform { SubTransform(int id)115 public SubTransform(int id) { 116 super(id); 117 } 118 myToString()119 public String myToString() { 120 return "SubTransform (subclass of: " + staticToString() + ") { id: " + id + " }"; 121 } 122 } 123 124 /* Base64 encoded class of: 125 * public static class Transform extends SuperTransform { 126 * static {} 127 * public Transform(int id) { super(id + 1000); } 128 * // NB This is the order the fields will be laid out in memory. 129 * public static Object BAR; 130 * public static Object BAZ; 131 * public static Object FOO; 132 * public static String staticToString() { 133 * return Transform.class.toString() + "[FOO: " + FOO + ", BAR: " + BAR + ", BAZ: " + BAZ + "]"; 134 * } 135 * } 136 */ 137 private static byte[] REDEFINED_DEX_BYTES = 138 Base64.getDecoder() 139 .decode( 140 "ZGV4CjAzNQAV5GctNSI+SEKJDaJIQLEac9ClAxZUSZq4BQAAcAAAAHhWNBIAAAAAAAAAAPQEAAAg" 141 + "AAAAcAAAAAsAAADwAAAABQAAABwBAAADAAAAWAEAAAkAAABwAQAAAQAAALgBAADgAwAA2AEAAKoC" 142 + "AACzAgAAvAIAAMYCAADOAgAA0wIAANgCAADdAgAA4AIAAOMCAADnAgAABgMAACADAAAwAwAAVAMA" 143 + "AHQDAACHAwAAmwMAAK8DAADKAwAA2QMAAOQDAADnAwAA6wMAAPMDAAD2AwAAAwQAAAsEAAARBAAA" 144 + "IQQAACsEAAAyBAAABwAAAAoAAAALAAAADAAAAA0AAAAOAAAADwAAABAAAAARAAAAEgAAABUAAAAI" 145 + "AAAACAAAAAAAAAAJAAAACQAAAJQCAAAJAAAACQAAAJwCAAAVAAAACgAAAAAAAAAWAAAACgAAAKQC" 146 + "AAACAAcABAAAAAIABwAFAAAAAgAHAAYAAAABAAQAAwAAAAIAAwACAAAAAgAEAAMAAAACAAAAHAAA" 147 + "AAYAAAAdAAAACQADAAMAAAAJAAEAGgAAAAkAAgAaAAAACQAAAB0AAAACAAAAAQAAAAEAAAAAAAAA" 148 + "EwAAAOQEAAC5BAAAAAAAAAUAAAACAAAAjQIAADYAAAAcAAIAbhAEAAAADABiAQIAYgIAAGIDAQAi" 149 + "BAkAcBAFAAQAbiAHAAQAGgAXAG4gBwAEAG4gBgAUABoAAABuIAcABABuIAYAJAAaAAEAbiAHAAQA" 150 + "biAGADQAGgAYAG4gBwAEAG4QCAAEAAwAEQAAAAAAAAAAAIQCAAABAAAADgAAAAIAAgACAAAAiAIA" 151 + "AAYAAADQEegDcCAAABAADgAKAA4ACwEADgARAA4AAAAAAQAAAAcAAAABAAAACAAAAAEAAAAAAAcs" 152 + "IEJBUjogAAcsIEJBWjogAAg8Y2xpbml0PgAGPGluaXQ+AANCQVIAA0JBWgADRk9PAAFJAAFMAAJM" 153 + "TAAdTGFydC9UZXN0MTk4MiRTdXBlclRyYW5zZm9ybTsAGExhcnQvVGVzdDE5ODIkVHJhbnNmb3Jt" 154 + "OwAOTGFydC9UZXN0MTk4MjsAIkxkYWx2aWsvYW5ub3RhdGlvbi9FbmNsb3NpbmdDbGFzczsAHkxk" 155 + "YWx2aWsvYW5ub3RhdGlvbi9Jbm5lckNsYXNzOwARTGphdmEvbGFuZy9DbGFzczsAEkxqYXZhL2xh" 156 + "bmcvT2JqZWN0OwASTGphdmEvbGFuZy9TdHJpbmc7ABlMamF2YS9sYW5nL1N0cmluZ0J1aWxkZXI7" 157 + "AA1UZXN0MTk4Mi5qYXZhAAlUcmFuc2Zvcm0AAVYAAlZJAAZbRk9POiAAAV0AC2FjY2Vzc0ZsYWdz" 158 + "AAZhcHBlbmQABG5hbWUADnN0YXRpY1RvU3RyaW5nAAh0b1N0cmluZwAFdmFsdWUAdn5+RDh7ImNv" 159 + "bXBpbGF0aW9uLW1vZGUiOiJkZWJ1ZyIsIm1pbi1hcGkiOjEsInNoYS0xIjoiYTgzNTJmMjU0ODg1" 160 + "MzYyY2NkOGQ5MDlkMzUyOWM2MDA5NGRkODk2ZSIsInZlcnNpb24iOiIxLjYuMjAtZGV2In0AAgQB" 161 + "HhgDAgUCGQQJGxcUAwADAAAJAQkBCQGIgATUBAGBgAToBAEJ2AMAAAAAAAIAAACqBAAAsAQAANgE" 162 + "AAAAAAAAAAAAAAAAAAAQAAAAAAAAAAEAAAAAAAAAAQAAACAAAABwAAAAAgAAAAsAAADwAAAAAwAA" 163 + "AAUAAAAcAQAABAAAAAMAAABYAQAABQAAAAkAAABwAQAABgAAAAEAAAC4AQAAASAAAAMAAADYAQAA" 164 + "AyAAAAMAAACEAgAAARAAAAMAAACUAgAAAiAAACAAAACqAgAABCAAAAIAAACqBAAAACAAAAEAAAC5" 165 + "BAAAAxAAAAIAAADUBAAABiAAAAEAAADkBAAAABAAAAEAAAD0BAAA"); 166 doTest()167 public static void doTest() throws Exception { 168 Transform t1 = new Transform(1); 169 SuperTransform t2 = new SubTransform(2); 170 readReflective("Reading with reflection.", Transform.class.getDeclaredFields(), null); 171 readReflective( 172 "Reading with reflection on subtransform instance.", SubTransform.class.getFields(), t2); 173 System.out.println("Reading normally."); 174 System.out.println("Read BAR field: " + printGeneric(Transform.BAR)); 175 System.out.println("Read FOO field: " + printGeneric(Transform.FOO)); 176 System.out.println("t1 is " + printGeneric(t1)); 177 System.out.println("t2 is " + printGeneric(t2)); 178 doRedefinition(); 179 System.out.println("Redefined: " + Transform.staticToString()); 180 readReflective( 181 "Reading with reflection after redefinition.", Transform.class.getDeclaredFields(), null); 182 readReflective( 183 "Reading with reflection after redefinition on subtransform instance.", 184 SubTransform.class.getFields(), 185 t2); 186 System.out.println("Reading normally after possible modification."); 187 System.out.println("Read FOO field: " + printGeneric(Transform.FOO)); 188 System.out.println("Read BAR field: " + printGeneric(Transform.BAR)); 189 System.out.println("t1 is " + printGeneric(t1)); 190 System.out.println("t2 is " + printGeneric(t2)); 191 SubTransform t3 = new SubTransform(3); 192 System.out.println("new SubTransform is " + printGeneric(t3)); 193 System.out.println("myToString of " + printGeneric(t3) + " is " + t3.myToString()); 194 // We verified in test 1980 that getDeclaredConstructor will throw if the class is obsolete. 195 // This therefore is a reasonable test that the t1 object's declaring class was updated. 196 System.out.println( 197 "Creating new transform from t1 class = " 198 + printGeneric(t1.getClass().getDeclaredConstructor(Integer.TYPE).newInstance(4))); 199 } 200 } 201