xref: /aosp_15_r20/art/test/1979-threaded-structural-transformation/src/art/Test1979.java (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
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