1 /* 2 * Copyright (C) 2020 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 Test2031 { 24 public static class MyClass { starting()25 public void starting() { 26 System.out.println("Starting up!"); 27 } toString()28 public String toString() { 29 return "This is my object!"; 30 } 31 } 32 $noinline$doSimulateZygoteFork()33 public static void $noinline$doSimulateZygoteFork() { 34 simulateZygoteFork(); 35 } 36 $noinline$run(String testdir)37 public static void $noinline$run(String testdir) throws Exception { 38 $noinline$doSimulateZygoteFork(); 39 final MyClass myObject = new MyClass(); 40 $noinline$startTest(testdir, myObject); 41 System.out.println(myObject); 42 } 43 $noinline$startTest(String testdir, final MyClass myObject)44 public static void $noinline$startTest(String testdir, final MyClass myObject) throws Exception { 45 Thread thr = new Thread(() -> { 46 try { 47 waitForNativeSleep(); 48 setupJvmti(testdir); 49 Redefinition.setTestConfiguration(Redefinition.Config.COMMON_REDEFINE); 50 Thread tester = new Thread(() -> { 51 try { 52 myObject.starting(); 53 doTest(); 54 } catch (Exception e) { 55 throw new Error("Failure!", e); 56 } 57 }); 58 tester.start(); 59 tester.join(); 60 wakeupNativeSleep(); 61 } catch (Exception e) { 62 throw new Error("Failure!", e); 63 } 64 }); 65 thr.start(); 66 nativeSleep(); 67 thr.join(); 68 } 69 simulateZygoteFork()70 public static native void simulateZygoteFork(); setupJvmti(String testdir)71 public static native void setupJvmti(String testdir); waitForNativeSleep()72 public static native void waitForNativeSleep(); wakeupNativeSleep()73 public static native void wakeupNativeSleep(); nativeSleep()74 public static native void nativeSleep(); 75 doRedefinition()76 private static void doRedefinition() { 77 Redefinition.doCommonStructuralClassRedefinition(Transform.class, REDEFINED_DEX_BYTES); 78 } 79 80 public static class SuperTransform { 81 public int id; 82 SuperTransform(int id)83 public SuperTransform(int id) { 84 this.id = id; 85 } 86 toString()87 public String toString() { 88 return "SuperTransform { id: " + id + ", class: " + getClass() + " }"; 89 } 90 } 91 92 public static class Transform extends SuperTransform { 93 static { 94 } 95 96 public static Object BAR = 97 new Object() { 98 public String toString() { 99 return "value of <" + this.get() + ">"; 100 } 101 102 public Object get() { 103 return "BAR FIELD"; 104 } 105 }; 106 public static Object FOO = 107 new Object() { 108 public String toString() { 109 return "value of <" + this.get() + ">"; 110 } 111 112 public Object get() { 113 return "FOO FIELD"; 114 } 115 }; 116 // This class has no virtual fields or methods. This means we can structurally redefine it 117 // without having to change the size of any instances. Transform(int id)118 public Transform(int id) { 119 super(id); 120 } 121 staticToString()122 public static String staticToString() { 123 return Transform.class.toString() + "[FOO: " + FOO + ", BAR: " + BAR + "]"; 124 } 125 } 126 127 public static class SubTransform extends Transform { SubTransform(int id)128 public SubTransform(int id) { 129 super(id); 130 } 131 myToString()132 public String myToString() { 133 return "SubTransform (subclass of: " + staticToString() + ") { id: " + id + " }"; 134 } 135 } 136 137 /* Base64 encoded class of: 138 * public static class Transform extends SuperTransform { 139 * static {} 140 * public Transform(int id) { super(id + 1000); } 141 * // NB This is the order the fields will be laid out in memory. 142 * public static Object BAR; 143 * public static Object BAZ; 144 * public static Object FOO; 145 * public static String staticToString() { 146 * return Transform.class.toString() + "[FOO: " + FOO + ", BAR: " + BAR + ", BAZ: " + BAZ + "]"; 147 * } 148 * } 149 */ 150 private static byte[] REDEFINED_DEX_BYTES = 151 Base64.getDecoder() 152 .decode( 153 "ZGV4CjAzNQC78lC18jI6omumTaKUcf/8pvcR4/Hx2u3QBQAAcAAAAHhWNBIAAAAAAAAAAAwFAAAg" + 154 "AAAAcAAAAAsAAADwAAAABQAAABwBAAADAAAAWAEAAAkAAABwAQAAAQAAALgBAAD4AwAA2AEAAKoC" + 155 "AACzAgAAvAIAAMYCAADOAgAA0wIAANgCAADdAgAA4AIAAOMCAADnAgAABgMAACADAAAwAwAAVAMA" + 156 "AHQDAACHAwAAmwMAAK8DAADKAwAA2QMAAOQDAADnAwAA6wMAAPMDAAD2AwAAAwQAAAsEAAARBAAA" + 157 "IQQAACsEAAAyBAAABwAAAAoAAAALAAAADAAAAA0AAAAOAAAADwAAABAAAAARAAAAEgAAABUAAAAI" + 158 "AAAACAAAAAAAAAAJAAAACQAAAJQCAAAJAAAACQAAAJwCAAAVAAAACgAAAAAAAAAWAAAACgAAAKQC" + 159 "AAACAAcABAAAAAIABwAFAAAAAgAHAAYAAAABAAQAAwAAAAIAAwACAAAAAgAEAAMAAAACAAAAHAAA" + 160 "AAYAAAAdAAAACQADAAMAAAAJAAEAGgAAAAkAAgAaAAAACQAAAB0AAAACAAAAAQAAAAEAAAAAAAAA" + 161 "EwAAAPwEAADQBAAAAAAAAAUAAAACAAAAjQIAADYAAAAcAAIAbhAEAAAADABiAQIAYgIAAGIDAQAi" + 162 "BAkAcBAFAAQAbiAHAAQAGgAXAG4gBwAEAG4gBgAUABoAAABuIAcABABuIAYAJAAaAAEAbiAHAAQA" + 163 "biAGADQAGgAYAG4gBwAEAG4QCAAEAAwAEQAAAAAAAAAAAIQCAAABAAAADgAAAAIAAgACAAAAiAIA" + 164 "AAYAAADQEegDcCAAABAADgAPAA4AEAEADgAWAA4AAAAAAQAAAAcAAAABAAAACAAAAAEAAAAAAAcs" + 165 "IEJBUjogAAcsIEJBWjogAAg8Y2xpbml0PgAGPGluaXQ+AANCQVIAA0JBWgADRk9PAAFJAAFMAAJM" + 166 "TAAdTGFydC9UZXN0MjAzMSRTdXBlclRyYW5zZm9ybTsAGExhcnQvVGVzdDIwMzEkVHJhbnNmb3Jt" + 167 "OwAOTGFydC9UZXN0MjAzMTsAIkxkYWx2aWsvYW5ub3RhdGlvbi9FbmNsb3NpbmdDbGFzczsAHkxk" + 168 "YWx2aWsvYW5ub3RhdGlvbi9Jbm5lckNsYXNzOwARTGphdmEvbGFuZy9DbGFzczsAEkxqYXZhL2xh" + 169 "bmcvT2JqZWN0OwASTGphdmEvbGFuZy9TdHJpbmc7ABlMamF2YS9sYW5nL1N0cmluZ0J1aWxkZXI7" + 170 "AA1UZXN0MjAzMS5qYXZhAAlUcmFuc2Zvcm0AAVYAAlZJAAZbRk9POiAAAV0AC2FjY2Vzc0ZsYWdz" + 171 "AAZhcHBlbmQABG5hbWUADnN0YXRpY1RvU3RyaW5nAAh0b1N0cmluZwAFdmFsdWUAjAF+fkQ4eyJj" + 172 "b21waWxhdGlvbi1tb2RlIjoiZGVidWciLCJoYXMtY2hlY2tzdW1zIjpmYWxzZSwibWluLWFwaSI6" + 173 "MSwic2hhLTEiOiJkMWQ1MWMxY2IzZTg1YWEzMGUwMGE2ODIyY2NhODNiYmUxZGZlOTQ1IiwidmVy" + 174 "c2lvbiI6IjIuMC4xMy1kZXYifQACBAEeGAMCBQIZBAkbFxQDAAMAAAkBCQEJAYiABNQEAYGABOgE" + 175 "AQnYAwAAAAAAAAIAAADBBAAAxwQAAPAEAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAEAAAAAAAAAAQAA" + 176 "ACAAAABwAAAAAgAAAAsAAADwAAAAAwAAAAUAAAAcAQAABAAAAAMAAABYAQAABQAAAAkAAABwAQAA" + 177 "BgAAAAEAAAC4AQAAASAAAAMAAADYAQAAAyAAAAMAAACEAgAAARAAAAMAAACUAgAAAiAAACAAAACq" + 178 "AgAABCAAAAIAAADBBAAAACAAAAEAAADQBAAAAxAAAAIAAADsBAAABiAAAAEAAAD8BAAAABAAAAEA" + 179 "AAAMBQAA"); 180 doTest()181 public static void doTest() throws Exception { 182 Transform t1 = new Transform(1); 183 SuperTransform t2 = new SubTransform(2); 184 doRedefinition(); 185 } 186 } 187