1*795d594fSAndroid Build Coastguard Worker /* 2*795d594fSAndroid Build Coastguard Worker * Copyright (C) 2016 The Android Open Source Project 3*795d594fSAndroid Build Coastguard Worker * 4*795d594fSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License"); 5*795d594fSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License. 6*795d594fSAndroid Build Coastguard Worker * You may obtain a copy of the License at 7*795d594fSAndroid Build Coastguard Worker * 8*795d594fSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0 9*795d594fSAndroid Build Coastguard Worker * 10*795d594fSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software 11*795d594fSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS, 12*795d594fSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13*795d594fSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and 14*795d594fSAndroid Build Coastguard Worker * limitations under the License. 15*795d594fSAndroid Build Coastguard Worker */ 16*795d594fSAndroid Build Coastguard Worker 17*795d594fSAndroid Build Coastguard Worker package art; 18*795d594fSAndroid Build Coastguard Worker 19*795d594fSAndroid Build Coastguard Worker import java.lang.ref.*; 20*795d594fSAndroid Build Coastguard Worker import java.lang.reflect.*; 21*795d594fSAndroid Build Coastguard Worker import java.util.*; 22*795d594fSAndroid Build Coastguard Worker import java.util.concurrent.CountDownLatch; 23*795d594fSAndroid Build Coastguard Worker import java.util.function.Supplier; 24*795d594fSAndroid Build Coastguard Worker 25*795d594fSAndroid Build Coastguard Worker public class Test1979 { run()26*795d594fSAndroid Build Coastguard Worker public static void run() throws Exception { 27*795d594fSAndroid Build Coastguard Worker Redefinition.setTestConfiguration(Redefinition.Config.COMMON_REDEFINE); 28*795d594fSAndroid Build Coastguard Worker doTest(); 29*795d594fSAndroid Build Coastguard Worker } 30*795d594fSAndroid Build Coastguard Worker 31*795d594fSAndroid Build Coastguard Worker private static final boolean PRINT_NONDETERMINISTIC = false; 32*795d594fSAndroid Build Coastguard Worker 33*795d594fSAndroid Build Coastguard Worker public static WeakHashMap<Object, Long> id_nums = new WeakHashMap<>(); 34*795d594fSAndroid Build Coastguard Worker public static long next_id = 0; 35*795d594fSAndroid Build Coastguard Worker printGeneric(Object o)36*795d594fSAndroid Build Coastguard Worker public static String printGeneric(Object o) { 37*795d594fSAndroid Build Coastguard Worker Long id = id_nums.get(o); 38*795d594fSAndroid Build Coastguard Worker if (id == null) { 39*795d594fSAndroid Build Coastguard Worker id = Long.valueOf(next_id++); 40*795d594fSAndroid Build Coastguard Worker id_nums.put(o, id); 41*795d594fSAndroid Build Coastguard Worker } 42*795d594fSAndroid Build Coastguard Worker if (o == null) { 43*795d594fSAndroid Build Coastguard Worker return "(ID: " + id + ") <NULL>"; 44*795d594fSAndroid Build Coastguard Worker } 45*795d594fSAndroid Build Coastguard Worker Class oc = o.getClass(); 46*795d594fSAndroid Build Coastguard Worker if (oc.isArray() && oc.getComponentType() == Byte.TYPE) { 47*795d594fSAndroid Build Coastguard Worker return "(ID: " 48*795d594fSAndroid Build Coastguard Worker + id 49*795d594fSAndroid Build Coastguard Worker + ") " 50*795d594fSAndroid Build Coastguard Worker + Arrays.toString(Arrays.copyOf((byte[]) o, 10)).replace(']', ',') 51*795d594fSAndroid Build Coastguard Worker + " ...]"; 52*795d594fSAndroid Build Coastguard Worker } else { 53*795d594fSAndroid Build Coastguard Worker return "(ID: " + id + ") " + o.toString(); 54*795d594fSAndroid Build Coastguard Worker } 55*795d594fSAndroid Build Coastguard Worker } 56*795d594fSAndroid Build Coastguard Worker doRedefinition()57*795d594fSAndroid Build Coastguard Worker private static void doRedefinition() { 58*795d594fSAndroid Build Coastguard Worker Redefinition.doCommonStructuralClassRedefinition( 59*795d594fSAndroid Build Coastguard Worker Transform.class, REDEFINED_DEX_BYTES); 60*795d594fSAndroid Build Coastguard Worker } 61*795d594fSAndroid Build Coastguard Worker readReflective(String msg)62*795d594fSAndroid Build Coastguard Worker private static void readReflective(String msg) throws Exception { 63*795d594fSAndroid Build Coastguard Worker System.out.println(msg); 64*795d594fSAndroid Build Coastguard Worker for (Field f : Transform.class.getFields()) { 65*795d594fSAndroid Build Coastguard Worker System.out.println(f.toString() + " = " + printGeneric(f.get(null))); 66*795d594fSAndroid Build Coastguard Worker } 67*795d594fSAndroid Build Coastguard Worker } 68*795d594fSAndroid Build Coastguard Worker 69*795d594fSAndroid Build Coastguard Worker public static class Transform { 70*795d594fSAndroid Build Coastguard Worker static {} 71*795d594fSAndroid Build Coastguard Worker public static Object BAR = new Object() { 72*795d594fSAndroid Build Coastguard Worker public String toString() { 73*795d594fSAndroid Build Coastguard Worker return "value of <" + this.get() + ">"; 74*795d594fSAndroid Build Coastguard Worker } 75*795d594fSAndroid Build Coastguard Worker public Object get() { 76*795d594fSAndroid Build Coastguard Worker return "BAR FIELD"; 77*795d594fSAndroid Build Coastguard Worker } 78*795d594fSAndroid Build Coastguard Worker }; 79*795d594fSAndroid Build Coastguard Worker public static Object FOO = new Object() { 80*795d594fSAndroid Build Coastguard Worker public String toString() { 81*795d594fSAndroid Build Coastguard Worker return "value of <" + this.get() + ">"; 82*795d594fSAndroid Build Coastguard Worker } 83*795d594fSAndroid Build Coastguard Worker public Object get() { 84*795d594fSAndroid Build Coastguard Worker return "FOO FIELD"; 85*795d594fSAndroid Build Coastguard Worker } 86*795d594fSAndroid Build Coastguard Worker }; staticToString()87*795d594fSAndroid Build Coastguard Worker public static String staticToString() { 88*795d594fSAndroid Build Coastguard Worker return Transform.class.toString() + "[FOO: " + FOO + ", BAR: " + BAR + "]"; 89*795d594fSAndroid Build Coastguard Worker } 90*795d594fSAndroid Build Coastguard Worker } 91*795d594fSAndroid Build Coastguard Worker 92*795d594fSAndroid Build Coastguard Worker /* Base64 encoded class of: 93*795d594fSAndroid Build Coastguard Worker * public static class Transform { 94*795d594fSAndroid Build Coastguard Worker * static {} 95*795d594fSAndroid Build Coastguard Worker * // NB This is the order the fields will be laid out in memory. 96*795d594fSAndroid Build Coastguard Worker * public static Object BAR; 97*795d594fSAndroid Build Coastguard Worker * public static Object BAZ; 98*795d594fSAndroid Build Coastguard Worker * public static Object FOO; 99*795d594fSAndroid Build Coastguard Worker * public static String staticToString() { 100*795d594fSAndroid Build Coastguard Worker * return Transform.class.toString() + "[FOO: " + FOO + ", BAR: " + BAR + ", BAZ: " + BAZ + "]"; 101*795d594fSAndroid Build Coastguard Worker * } 102*795d594fSAndroid Build Coastguard Worker * } 103*795d594fSAndroid Build Coastguard Worker */ 104*795d594fSAndroid Build Coastguard Worker private static byte[] REDEFINED_DEX_BYTES = Base64.getDecoder().decode( 105*795d594fSAndroid Build Coastguard Worker "ZGV4CjAzNQDrznAlv8Fs6FNeDAHAxiU9uy8DUayd82ZkBQAAcAAAAHhWNBIAAAAAAAAAAKAEAAAd" + 106*795d594fSAndroid Build Coastguard Worker "AAAAcAAAAAkAAADkAAAABAAAAAgBAAADAAAAOAEAAAkAAABQAQAAAQAAAJgBAACsAwAAuAEAAHoC" + 107*795d594fSAndroid Build Coastguard Worker "AACDAgAAjAIAAJYCAACeAgAAowIAAKgCAACtAgAAsAIAALQCAADOAgAA3gIAAAIDAAAiAwAANQMA" + 108*795d594fSAndroid Build Coastguard Worker "AEkDAABdAwAAeAMAAIcDAACSAwAAlQMAAJ0DAACgAwAArQMAALUDAAC7AwAAywMAANUDAADcAwAA" + 109*795d594fSAndroid Build Coastguard Worker "CQAAAAoAAAALAAAADAAAAA0AAAAOAAAADwAAABAAAAATAAAABwAAAAYAAAAAAAAACAAAAAcAAABs" + 110*795d594fSAndroid Build Coastguard Worker "AgAACAAAAAcAAAB0AgAAEwAAAAgAAAAAAAAAAAAFAAQAAAAAAAUABQAAAAAABQAGAAAAAAADAAIA" + 111*795d594fSAndroid Build Coastguard Worker "AAAAAAMAAwAAAAAAAAAZAAAABAAAABoAAAAFAAMAAwAAAAcAAwADAAAABwABABcAAAAHAAIAFwAA" + 112*795d594fSAndroid Build Coastguard Worker "AAcAAAAaAAAAAAAAAAEAAAAFAAAAAAAAABEAAACQBAAAYwQAAAAAAAAFAAAAAgAAAGgCAAA2AAAA" + 113*795d594fSAndroid Build Coastguard Worker "HAAAAG4QAwAAAAwAYgECAGICAABiAwEAIgQHAHAQBQAEAG4gBwAEABoAFABuIAcABABuIAYAFAAa" + 114*795d594fSAndroid Build Coastguard Worker "AAAAbiAHAAQAbiAGACQAGgABAG4gBwAEAG4gBgA0ABoAFQBuIAcABABuEAgABAAMABEAAAAAAAAA" + 115*795d594fSAndroid Build Coastguard Worker "AABgAgAAAQAAAA4AAAABAAEAAQAAAGQCAAAEAAAAcBAEAAAADgAIAA4ABwAOAA4ADgABAAAABQAA" + 116*795d594fSAndroid Build Coastguard Worker "AAEAAAAGAAcsIEJBUjogAAcsIEJBWjogAAg8Y2xpbml0PgAGPGluaXQ+AANCQVIAA0JBWgADRk9P" + 117*795d594fSAndroid Build Coastguard Worker "AAFMAAJMTAAYTGFydC9UZXN0MTk3OSRUcmFuc2Zvcm07AA5MYXJ0L1Rlc3QxOTc5OwAiTGRhbHZp" + 118*795d594fSAndroid Build Coastguard Worker "ay9hbm5vdGF0aW9uL0VuY2xvc2luZ0NsYXNzOwAeTGRhbHZpay9hbm5vdGF0aW9uL0lubmVyQ2xh" + 119*795d594fSAndroid Build Coastguard Worker "c3M7ABFMamF2YS9sYW5nL0NsYXNzOwASTGphdmEvbGFuZy9PYmplY3Q7ABJMamF2YS9sYW5nL1N0" + 120*795d594fSAndroid Build Coastguard Worker "cmluZzsAGUxqYXZhL2xhbmcvU3RyaW5nQnVpbGRlcjsADVRlc3QxOTc5LmphdmEACVRyYW5zZm9y" + 121*795d594fSAndroid Build Coastguard Worker "bQABVgAGW0ZPTzogAAFdAAthY2Nlc3NGbGFncwAGYXBwZW5kAARuYW1lAA5zdGF0aWNUb1N0cmlu" + 122*795d594fSAndroid Build Coastguard Worker "ZwAIdG9TdHJpbmcABXZhbHVlAHZ+fkQ4eyJjb21waWxhdGlvbi1tb2RlIjoiZGVidWciLCJtaW4t" + 123*795d594fSAndroid Build Coastguard Worker "YXBpIjoxLCJzaGEtMSI6ImE4MzUyZjI1NDg4NTM2MmNjZDhkOTA5ZDM1MjljNjAwOTRkZDg5NmUi" + 124*795d594fSAndroid Build Coastguard Worker "LCJ2ZXJzaW9uIjoiMS42LjIwLWRldiJ9AAICARsYAQIDAhYECRgXEgMAAwAACQEJAQkAiIAEtAQB" + 125*795d594fSAndroid Build Coastguard Worker "gYAEyAQBCbgDAAAAAAAAAAIAAABUBAAAWgQAAIQEAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAEAAAAA" + 126*795d594fSAndroid Build Coastguard Worker "AAAAAQAAAB0AAABwAAAAAgAAAAkAAADkAAAAAwAAAAQAAAAIAQAABAAAAAMAAAA4AQAABQAAAAkA" + 127*795d594fSAndroid Build Coastguard Worker "AABQAQAABgAAAAEAAACYAQAAASAAAAMAAAC4AQAAAyAAAAMAAABgAgAAARAAAAIAAABsAgAAAiAA" + 128*795d594fSAndroid Build Coastguard Worker "AB0AAAB6AgAABCAAAAIAAABUBAAAACAAAAEAAABjBAAAAxAAAAIAAACABAAABiAAAAEAAACQBAAA" + 129*795d594fSAndroid Build Coastguard Worker "ABAAAAEAAACgBAAA"); 130*795d594fSAndroid Build Coastguard Worker 131*795d594fSAndroid Build Coastguard Worker public interface TRunnable { run()132*795d594fSAndroid Build Coastguard Worker public void run() throws Exception; 133*795d594fSAndroid Build Coastguard Worker } 134*795d594fSAndroid Build Coastguard Worker doTest()135*795d594fSAndroid Build Coastguard Worker public static void doTest() throws Exception { 136*795d594fSAndroid Build Coastguard Worker final CountDownLatch cdl = new CountDownLatch(1); 137*795d594fSAndroid Build Coastguard Worker final CountDownLatch continueLatch = new CountDownLatch(1); 138*795d594fSAndroid Build Coastguard Worker // Make sure the transformed class is already loaded before we start running (and possibly 139*795d594fSAndroid Build Coastguard Worker // compiling) the test thread. 140*795d594fSAndroid Build Coastguard Worker System.out.println("Hitting class " + Transform.staticToString()); 141*795d594fSAndroid Build Coastguard Worker Thread t = new Thread(() -> { 142*795d594fSAndroid Build Coastguard Worker try { 143*795d594fSAndroid Build Coastguard Worker // We don't want to read these in the same method here to ensure that no reference to 144*795d594fSAndroid Build Coastguard Worker // Transform is active on this thread at the time the redefinition occurs. To accomplish 145*795d594fSAndroid Build Coastguard Worker // this just run the code in a different method, which is good enough. 146*795d594fSAndroid Build Coastguard Worker ((TRunnable)() -> { 147*795d594fSAndroid Build Coastguard Worker System.out.println("Initial: " + Transform.staticToString()); 148*795d594fSAndroid Build Coastguard Worker readReflective("Reading with reflection."); 149*795d594fSAndroid Build Coastguard Worker System.out.println("Reading normally."); 150*795d594fSAndroid Build Coastguard Worker System.out.println("Read BAR field: " + printGeneric(Transform.BAR)); 151*795d594fSAndroid Build Coastguard Worker System.out.println("Read FOO field: " + printGeneric(Transform.FOO)); 152*795d594fSAndroid Build Coastguard Worker }).run(); 153*795d594fSAndroid Build Coastguard Worker cdl.countDown(); 154*795d594fSAndroid Build Coastguard Worker continueLatch.await(); 155*795d594fSAndroid Build Coastguard Worker // Now that redefinition has occurred without this frame having any references to the 156*795d594fSAndroid Build Coastguard Worker // Transform class we want to make sure we have the correct offsets. 157*795d594fSAndroid Build Coastguard Worker System.out.println("Redefined: " + Transform.staticToString()); 158*795d594fSAndroid Build Coastguard Worker readReflective("Reading with reflection after possible modification."); 159*795d594fSAndroid Build Coastguard Worker System.out.println("Reading normally after possible modification."); 160*795d594fSAndroid Build Coastguard Worker System.out.println("Read FOO field: " + printGeneric(Transform.FOO)); 161*795d594fSAndroid Build Coastguard Worker System.out.println("Read BAR field: " + printGeneric(Transform.BAR)); 162*795d594fSAndroid Build Coastguard Worker } catch (Exception e) { 163*795d594fSAndroid Build Coastguard Worker throw new Error(e); 164*795d594fSAndroid Build Coastguard Worker } 165*795d594fSAndroid Build Coastguard Worker }); 166*795d594fSAndroid Build Coastguard Worker t.start(); 167*795d594fSAndroid Build Coastguard Worker cdl.await(); 168*795d594fSAndroid Build Coastguard Worker doRedefinition(); 169*795d594fSAndroid Build Coastguard Worker continueLatch.countDown(); 170*795d594fSAndroid Build Coastguard Worker t.join(); 171*795d594fSAndroid Build Coastguard Worker } 172*795d594fSAndroid Build Coastguard Worker } 173