1 /* 2 * Copyright (C) 2019 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.reflect.Executable; 20 import java.lang.reflect.Field; 21 import java.util.Base64; 22 23 public class Test1984 { notifyFieldModify( Executable method, long location, Class<?> f_klass, Object target, Field f, Object value)24 public static void notifyFieldModify( 25 Executable method, long location, Class<?> f_klass, Object target, Field f, Object value) { 26 System.out.println("method: " + method + "\tMODIFY: " + f + "\tSet to: " + value); 27 } 28 notifyFieldAccess( Executable method, long location, Class<?> f_klass, Object target, Field f)29 public static void notifyFieldAccess( 30 Executable method, long location, Class<?> f_klass, Object target, Field f) { 31 System.out.println("method: " + method + "\tACCESS: " + f); 32 } 33 34 public static class Transform { 35 public static int count_down = 2; 36 public static boolean boom = false; 37 public static boolean tock = false; 38 tick()39 public static void tick() { 40 boolean tocked = tock; 41 tock = !tock; 42 if (tocked) { 43 count_down--; 44 } 45 if (count_down == 0) { 46 boom = true; 47 } 48 } 49 } 50 51 /* Base64 encoded dex file for. 52 * // NB The addition of aaa_INITIAL means the fields all have different offsets 53 * public static class Transform { 54 * public static int aaa_INITIAL = 0; 55 * public static int count_down = 2; 56 * public static boolean boom = false; 57 * public static boolean tock = false; 58 * public static void tick() { 59 * boolean tocked = tock; 60 * tock = !tock; 61 * if (tocked) { 62 * count_down--; 63 * } 64 * if (count_down == 0) { 65 * boom = true; 66 * } 67 * } 68 * } 69 */ 70 public static final byte[] REDEFINED_DEX_BYTES = 71 Base64.getDecoder() 72 .decode( 73 "ZGV4CjAzNQDejZufbnVbJEn1/OfB3XmJPtVbudlWkvnsAwAAcAAAAHhWNBIAAAAAAAAAADQDAAAU" 74 + "AAAAcAAAAAgAAADAAAAAAQAAAOAAAAAEAAAA7AAAAAQAAAAMAQAAAQAAACwBAACgAgAATAEAAPAB" 75 + "AAD6AQAAAgIAAAUCAAAfAgAALwIAAFMCAABzAgAAhwIAAJYCAAChAgAApAIAAKcCAAC0AgAAwQIA" 76 + "AMcCAADTAgAA2QIAAN8CAADlAgAAAgAAAAMAAAAEAAAABQAAAAYAAAAHAAAACgAAAAsAAAAKAAAA" 77 + "BgAAAAAAAAABAAAADAAAAAEABwAOAAAAAQAAAA8AAAABAAcAEgAAAAEAAAAAAAAAAQAAAAEAAAAB" 78 + "AAAAEQAAAAUAAAABAAAAAQAAAAEAAAAFAAAAAAAAAAgAAADgAQAAFgMAAAAAAAACAAAABwMAAA0D" 79 + "AAACAAAAAAAAAOwCAAALAAAAEgFnAQAAEiBnAAIAagEBAGoBAwAOAAAAAQABAAEAAAD0AgAABAAA" 80 + "AHAQAwAAAA4AAwAAAAAAAAD5AgAAGwAAABIRYwIDAGMAAwA5ABQAARBqAAMAOAIIAGAAAgDYAAD/" 81 + "ZwACAGAAAgA5AAQAagEBAA4AEgAo7gAATAEAAAAAAAAAAAAAAAAAAAg8Y2xpbml0PgAGPGluaXQ+" 82 + "AAFJABhMYXJ0L1Rlc3QxOTg0JFRyYW5zZm9ybTsADkxhcnQvVGVzdDE5ODQ7ACJMZGFsdmlrL2Fu" 83 + "bm90YXRpb24vRW5jbG9zaW5nQ2xhc3M7AB5MZGFsdmlrL2Fubm90YXRpb24vSW5uZXJDbGFzczsA" 84 + "EkxqYXZhL2xhbmcvT2JqZWN0OwANVGVzdDE5ODQuamF2YQAJVHJhbnNmb3JtAAFWAAFaAAthYWFf" 85 + "SU5JVElBTAALYWNjZXNzRmxhZ3MABGJvb20ACmNvdW50X2Rvd24ABG5hbWUABHRpY2sABHRvY2sA" 86 + "BXZhbHVlAAgABx0tPC0ABwAHDgANAAcdLXgtaksuAnkdAAIDARMYAgIEAg0ECRAXCQQAAwAACQEJ" 87 + "AQkBCQCIgATYAgGBgASAAwEJmAMAAA8AAAAAAAAAAQAAAAAAAAABAAAAFAAAAHAAAAACAAAACAAA" 88 + "AMAAAAADAAAAAQAAAOAAAAAEAAAABAAAAOwAAAAFAAAABAAAAAwBAAAGAAAAAQAAACwBAAADEAAA" 89 + "AQAAAEwBAAABIAAAAwAAAFgBAAAGIAAAAQAAAOABAAACIAAAFAAAAPABAAADIAAAAwAAAOwCAAAE" 90 + "IAAAAgAAAAcDAAAAIAAAAQAAABYDAAAAEAAAAQAAADQDAAA="); 91 run()92 public static void run() throws Exception { 93 System.out.println("Dumping fields at start"); 94 for (Field f : Transform.class.getDeclaredFields()) { 95 System.out.println(f.toString() + "=" + f.get(null)); 96 } 97 Trace.disableTracing(Thread.currentThread()); 98 Trace.enableFieldTracing( 99 Test1984.class, 100 Test1984.class.getDeclaredMethod( 101 "notifyFieldAccess", 102 Executable.class, 103 Long.TYPE, 104 Class.class, 105 Object.class, 106 Field.class), 107 Test1984.class.getDeclaredMethod( 108 "notifyFieldModify", 109 Executable.class, 110 Long.TYPE, 111 Class.class, 112 Object.class, 113 Field.class, 114 Object.class), 115 Thread.currentThread()); 116 for (Field f : Transform.class.getDeclaredFields()) { 117 Trace.watchFieldAccess(f); 118 Trace.watchFieldModification(f); 119 } 120 // count_down = 2 121 Transform.tick(); // count_down = 2 122 Transform.tick(); // count_down = 1 123 System.out.println("REDEFINING TRANSFORM CLASS"); 124 Redefinition.doCommonStructuralClassRedefinition(Transform.class, REDEFINED_DEX_BYTES); 125 Transform.tick(); // count_down = 1 126 Transform.tick(); // count_down = 0 127 System.out.println("Dumping fields at end"); 128 for (Field f : Transform.class.getDeclaredFields()) { 129 System.out.println(f.toString() + "=" + f.get(null)); 130 } 131 // Turn off tracing so we don't have to deal with print internals. 132 Trace.disableTracing(Thread.currentThread()); 133 } 134 } 135