1 /* 2 * Copyright (C) 2017 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 import static art.Redefinition.doCommonClassRedefinition; 18 19 import java.lang.reflect.Method; 20 import java.util.ArrayList; 21 import java.util.Base64; 22 import java.util.LinkedList; 23 24 public class Main { 25 26 // TODO We should make this run on the RI. 27 /** 28 * This test cannot be run on the RI. 29 */ 30 private static final byte[] CLASS_BYTES = new byte[0]; 31 32 // TODO It might be a good idea to replace this hard-coded Object definition with a 33 // retransformation based test. 34 /** 35 * Base64 encoding of the following smali file. 36 * 37 * .class public Ljava/lang/Object; 38 * .source "Object.java" 39 * # instance fields 40 * .field private transient shadow$_klass_:Ljava/lang/Class; 41 * .annotation system Ldalvik/annotation/Signature; 42 * value = { 43 * "Ljava/lang/Class", 44 * "<*>;" 45 * } 46 * .end annotation 47 * .end field 48 * 49 * .field private transient shadow$_monitor_:I 50 * # direct methods 51 * .method public constructor <init>()V 52 * .registers 1 53 * .prologue 54 * invoke-static {p0}, Lart/test/TestWatcher;->NotifyConstructed(Ljava/lang/Object;)V 55 * return-void 56 * .end method 57 * 58 * .method static identityHashCode(Ljava/lang/Object;)I 59 * .registers 7 60 * .prologue 61 * iget v0, p0, Ljava/lang/Object;->shadow$_monitor_:I 62 * const/high16 v3, -0x40000000 # -2.0f 63 * const/high16 v2, -0x80000000 64 * const v1, 0xfffffff 65 * const/high16 v4, -0x40000000 # -2.0f 66 * and-int/2addr v4, v0 67 * const/high16 v5, -0x80000000 68 * if-ne v4, v5, :cond_15 69 * const v4, 0xfffffff 70 * and-int/2addr v4, v0 71 * return v4 72 * :cond_15 73 * invoke-static {p0}, Ljava/lang/Object;->identityHashCodeNative(Ljava/lang/Object;)I 74 * move-result v4 75 * return v4 76 * .end method 77 * 78 * .method private static native identityHashCodeNative(Ljava/lang/Object;)I 79 * .annotation build Ldalvik/annotation/optimization/FastNative; 80 * .end annotation 81 * .end method 82 * 83 * .method private native internalClone()Ljava/lang/Object; 84 * .annotation build Ldalvik/annotation/optimization/FastNative; 85 * .end annotation 86 * .end method 87 * 88 * 89 * # virtual methods 90 * .method protected clone()Ljava/lang/Object; 91 * .registers 4 92 * .annotation system Ldalvik/annotation/Throws; 93 * value = { 94 * Ljava/lang/CloneNotSupportedException; 95 * } 96 * .end annotation 97 * 98 * .prologue 99 * instance-of v0, p0, Ljava/lang/Cloneable; 100 * if-nez v0, :cond_2d 101 * new-instance v0, Ljava/lang/CloneNotSupportedException; 102 * new-instance v1, Ljava/lang/StringBuilder; 103 * invoke-direct {v1}, Ljava/lang/StringBuilder;-><init>()V 104 * const-string/jumbo v2, "Class " 105 * invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder; 106 * move-result-object v1 107 * invoke-virtual {p0}, Ljava/lang/Object;->getClass()Ljava/lang/Class; 108 * move-result-object v2 109 * invoke-virtual {v2}, Ljava/lang/Class;->getName()Ljava/lang/String; 110 * move-result-object v2 111 * invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder; 112 * move-result-object v1 113 * const-string/jumbo v2, " doesn\'t implement Cloneable" 114 * invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder; 115 * move-result-object v1 116 * invoke-virtual {v1}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String; 117 * move-result-object v1 118 * invoke-direct {v0, v1}, Ljava/lang/CloneNotSupportedException;-><init>(Ljava/lang/String;)V 119 * throw v0 120 * :cond_2d 121 * invoke-direct {p0}, Ljava/lang/Object;->internalClone()Ljava/lang/Object; 122 * move-result-object v0 123 * return-object v0 124 * .end method 125 * 126 * .method public equals(Ljava/lang/Object;)Z 127 * .registers 3 128 * .prologue 129 * if-ne p0, p1, :cond_4 130 * const/4 v0, 0x1 131 * :goto_3 132 * return v0 133 * :cond_4 134 * const/4 v0, 0x0 135 * goto :goto_3 136 * .end method 137 * 138 * .method protected finalize()V 139 * .registers 1 140 * .annotation system Ldalvik/annotation/Throws; 141 * value = { 142 * Ljava/lang/Throwable; 143 * } 144 * .end annotation 145 * .prologue 146 * return-void 147 * .end method 148 * 149 * .method public final getClass()Ljava/lang/Class; 150 * .registers 2 151 * .annotation system Ldalvik/annotation/Signature; 152 * value = { 153 * "()", 154 * "Ljava/lang/Class", 155 * "<*>;" 156 * } 157 * .end annotation 158 * .prologue 159 * iget-object v0, p0, Ljava/lang/Object;->shadow$_klass_:Ljava/lang/Class; 160 * return-object v0 161 * .end method 162 * 163 * .method public hashCode()I 164 * .registers 2 165 * .prologue 166 * invoke-static {p0}, Ljava/lang/Object;->identityHashCode(Ljava/lang/Object;)I 167 * move-result v0 168 * return v0 169 * .end method 170 * 171 * .method public final native notify()V 172 * .annotation build Ldalvik/annotation/optimization/FastNative; 173 * .end annotation 174 * .end method 175 * 176 * .method public final native notifyAll()V 177 * .annotation build Ldalvik/annotation/optimization/FastNative; 178 * .end annotation 179 * .end method 180 * 181 * .method public toString()Ljava/lang/String; 182 * .registers 3 183 * .prologue 184 * new-instance v0, Ljava/lang/StringBuilder; 185 * invoke-direct {v0}, Ljava/lang/StringBuilder;-><init>()V 186 * invoke-virtual {p0}, Ljava/lang/Object;->getClass()Ljava/lang/Class; 187 * move-result-object v1 188 * invoke-virtual {v1}, Ljava/lang/Class;->getName()Ljava/lang/String; 189 * move-result-object v1 190 * invoke-virtual {v0, v1}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder; 191 * move-result-object v0 192 * const-string/jumbo v1, "@" 193 * invoke-virtual {v0, v1}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder; 194 * move-result-object v0 195 * invoke-virtual {p0}, Ljava/lang/Object;->hashCode()I 196 * move-result v1 197 * invoke-static {v1}, Ljava/lang/Integer;->toHexString(I)Ljava/lang/String; 198 * move-result-object v1 199 * invoke-virtual {v0, v1}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder; 200 * move-result-object v0 201 * invoke-virtual {v0}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String; 202 * move-result-object v0 203 * return-object v0 204 * .end method 205 * 206 * .method public final native wait()V 207 * .annotation system Ldalvik/annotation/Throws; 208 * value = { 209 * Ljava/lang/InterruptedException; 210 * } 211 * .end annotation 212 * 213 * .annotation build Ldalvik/annotation/optimization/FastNative; 214 * .end annotation 215 * .end method 216 * 217 * .method public final wait(J)V 218 * .registers 4 219 * .annotation system Ldalvik/annotation/Throws; 220 * value = { 221 * Ljava/lang/InterruptedException; 222 * } 223 * .end annotation 224 * .prologue 225 * const/4 v0, 0x0 226 * invoke-virtual {p0, p1, p2, v0}, Ljava/lang/Object;->wait(JI)V 227 * return-void 228 * .end method 229 * 230 * .method public final native wait(JI)V 231 * .annotation system Ldalvik/annotation/Throws; 232 * value = { 233 * Ljava/lang/InterruptedException; 234 * } 235 * .end annotation 236 * 237 * .annotation build Ldalvik/annotation/optimization/FastNative; 238 * .end annotation 239 * .end method 240 */ 241 private static final byte[] DEX_BYTES = Base64.getDecoder().decode( 242 "ZGV4CjAzNQDUlMR9j03MYuOKekKs2p7zJzu2IfDb7RlMCgAAcAAAAHhWNBIAAAAAAAAAAIgJAAA6" + 243 "AAAAcAAAABEAAABYAQAADQAAAJwBAAACAAAAOAIAABYAAABIAgAAAQAAAPgCAAA0BwAAGAMAABgD" + 244 "AAA2AwAAOgMAAEADAABIAwAASwMAAFMDAABWAwAAWgMAAF0DAABgAwAAZAMAAGgDAACAAwAAnwMA" + 245 "ALsDAADoAwAA+gMAAA0EAAA1BAAATAQAAGEEAACDBAAAlwQAAKsEAADGBAAA3QQAAPAEAAD9BAAA" + 246 "AAUAAAQFAAAJBQAADQUAABAFAAAUBQAAHAUAACMFAAArBQAANQUAAD8FAABIBQAAUgUAAGQFAAB8" + 247 "BQAAiwUAAJUFAACnBQAAugUAAM0FAADVBQAA3QUAAOgFAADtBQAA/QUAAA8GAAAcBgAAJgYAAC0G" + 248 "AAAGAAAACAAAAAwAAAANAAAADgAAAA8AAAARAAAAEgAAABMAAAAUAAAAFQAAABYAAAAXAAAAGAAA" + 249 "ABkAAAAcAAAAIAAAAAYAAAAAAAAAAAAAAAcAAAAAAAAAPAYAAAkAAAAGAAAAAAAAAAkAAAALAAAA" + 250 "AAAAAAkAAAAMAAAAAAAAAAoAAAAMAAAARAYAAAsAAAANAAAAVAYAABwAAAAPAAAAAAAAAB0AAAAP" + 251 "AAAATAYAAB4AAAAPAAAANAYAAB8AAAAPAAAAPAYAAB8AAAAPAAAAVAYAACEAAAAQAAAAPAYAAAsA" + 252 "BgA0AAAACwAAADUAAAACAAoAGgAAAAYABAAnAAAABwALAAMAAAAJAAUANgAAAAsABwADAAAACwAD" + 253 "ACMAAAALAAwAJAAAAAsABwAlAAAACwACACYAAAALAAAAKAAAAAsAAQApAAAACwABACoAAAALAAMA" + 254 "KwAAAAsABwAxAAAACwAHADIAAAALAAQANwAAAAsABwA5AAAACwAIADkAAAALAAkAOQAAAA0ABwAD" + 255 "AAAADQAGACIAAAANAAQANwAAAAsAAAABAAAA/////wAAAAAbAAAA0AYAAD4JAAAAAAAAHCBkb2Vz" + 256 "bid0IGltcGxlbWVudCBDbG9uZWFibGUAAigpAAQ8Kj47AAY8aW5pdD4AAUAABkNsYXNzIAABSQAC" + 257 "SUwAAUoAAUwAAkxJAAJMTAAWTGFydC90ZXN0L1Rlc3RXYXRjaGVyOwAdTGRhbHZpay9hbm5vdGF0" + 258 "aW9uL1NpZ25hdHVyZTsAGkxkYWx2aWsvYW5ub3RhdGlvbi9UaHJvd3M7ACtMZGFsdmlrL2Fubm90" + 259 "YXRpb24vb3B0aW1pemF0aW9uL0Zhc3ROYXRpdmU7ABBMamF2YS9sYW5nL0NsYXNzABFMamF2YS9s" + 260 "YW5nL0NsYXNzOwAmTGphdmEvbGFuZy9DbG9uZU5vdFN1cHBvcnRlZEV4Y2VwdGlvbjsAFUxqYXZh" + 261 "L2xhbmcvQ2xvbmVhYmxlOwATTGphdmEvbGFuZy9JbnRlZ2VyOwAgTGphdmEvbGFuZy9JbnRlcnJ1" + 262 "cHRlZEV4Y2VwdGlvbjsAEkxqYXZhL2xhbmcvT2JqZWN0OwASTGphdmEvbGFuZy9TdHJpbmc7ABlM" + 263 "amF2YS9sYW5nL1N0cmluZ0J1aWxkZXI7ABVMamF2YS9sYW5nL1Rocm93YWJsZTsAEU5vdGlmeUNv" + 264 "bnN0cnVjdGVkAAtPYmplY3QuamF2YQABVgACVkoAA1ZKSQACVkwAAVoAAlpMAAZhcHBlbmQABWNs" + 265 "b25lAAZlcXVhbHMACGZpbmFsaXplAAhnZXRDbGFzcwAHZ2V0TmFtZQAIaGFzaENvZGUAEGlkZW50" + 266 "aXR5SGFzaENvZGUAFmlkZW50aXR5SGFzaENvZGVOYXRpdmUADWludGVybmFsQ2xvbmUACGxvY2tX" + 267 "b3JkABBsb2NrV29yZEhhc2hNYXNrABFsb2NrV29yZFN0YXRlSGFzaAARbG9ja1dvcmRTdGF0ZU1h" + 268 "c2sABm1pbGxpcwAGbm90aWZ5AAlub3RpZnlBbGwAA29iagAOc2hhZG93JF9rbGFzc18AEHNoYWRv" + 269 "dyRfbW9uaXRvcl8AC3RvSGV4U3RyaW5nAAh0b1N0cmluZwAFdmFsdWUABHdhaXQAAAIAAAABAAAA" + 270 "AQAAAAsAAAABAAAAAAAAAAEAAAABAAAAAQAAAAwAAgQBOBwBGAcCBAE4HAEYCgIDATgcAhcQFwIC" + 271 "BAE4HAEYDgAFAAIDATgcAxcBFxAXAgAAAAAAAAAAAAEAAABaBgAAAgAAAGIGAAB8BgAAAQAAAGIG" + 272 "AAABAAAAagYAAAEAAAB0BgAAAQAAAHwGAAABAAAAfwYAAAAAAAABAAAACgAAAAAAAAAAAAAAsAYA" + 273 "AAUAAACUBgAABwAAALgGAAAIAAAAyAYAAAsAAADABgAADAAAAMAGAAANAAAAwAYAAA4AAADABgAA" + 274 "EAAAAJwGAAARAAAAqAYAABIAAACcBgAAKAAHDgBwATQHDi0DAC0BLQMDMAEtAwIvATwDAS4BeFsA" + 275 "7AEABw5LARoPOsYArAEBNAcOAMUEAAcOAEEABw4AaAAHDgCRAgAHDgCmAwExBw5LAAAAAQABAAEA" + 276 "AAA4BwAABAAAAHEQAAAAAA4ABwABAAEAAAA9BwAAGgAAAFJgAQAVAwDAFQIAgBQB////DxUEAMC1" + 277 "BBUFAIAzVAcAFAT///8PtQQPBHEQCwAGAAoEDwQEAAEAAgAAAFkHAAAyAAAAIDAIADkAKwAiAAcA" + 278 "IgENAHAQEwABABsCBQAAAG4gFAAhAAwBbhAIAAMADAJuEAEAAgAMAm4gFAAhAAwBGwIAAAAAbiAU" + 279 "ACEADAFuEBUAAQAMAXAgAgAQACcAcBAMAAMADAARAAMAAgAAAAAAZQcAAAYAAAAzIQQAEhAPABIA" + 280 "KP4BAAEAAAAAAGwHAAABAAAADgAAAAIAAQAAAAAAcgcAAAMAAABUEAAAEQAAAAIAAQABAAAAdwcA" + 281 "AAUAAABxEAoAAQAKAA8AAAADAAEAAgAAAHwHAAApAAAAIgANAHAQEwAAAG4QCAACAAwBbhABAAEA" + 282 "DAFuIBQAEAAMABsBBAAAAG4gFAAQAAwAbhAJAAIACgFxEAMAAQAMAW4gFAAQAAwAbhAVAAAADAAR" + 283 "AAAABAADAAQAAACCBwAABQAAABIAbkASACEDDgAAAgQLAIIBAYIBBIGABIwPBgikDwGKAgABggIA" + 284 "BQToDwEB3BABBPgQARGMEQEBpBEEkQIAAZECAAEBwBEBkQIAARGkEgGRAgAAABAAAAAAAAAAAQAA" + 285 "AAAAAAABAAAAOgAAAHAAAAACAAAAEQAAAFgBAAADAAAADQAAAJwBAAAEAAAAAgAAADgCAAAFAAAA" + 286 "FgAAAEgCAAAGAAAAAQAAAPgCAAACIAAAOgAAABgDAAABEAAABQAAADQGAAAEIAAABgAAAFoGAAAD" + 287 "EAAACQAAAIwGAAAGIAAAAQAAANAGAAADIAAACQAAADgHAAABIAAACQAAAIwHAAAAIAAAAQAAAD4J" + 288 "AAAAEAAAAQAAAIgJAAA="); 289 290 private static final String LISTENER_LOCATION = 291 System.getenv("DEX_LOCATION") + "/980-redefine-object-ex.jar"; 292 293 private static Method doEnableReporting; 294 private static Method doDisableReporting; 295 DisableReporting()296 private static void DisableReporting() { 297 if (doDisableReporting == null) { 298 return; 299 } 300 try { 301 doDisableReporting.invoke(null); 302 } catch (Exception e) { 303 throw new Error("Unable to disable reporting!"); 304 } 305 } 306 EnableReporting()307 private static void EnableReporting() { 308 if (doEnableReporting == null) { 309 return; 310 } 311 try { 312 doEnableReporting.invoke(null); 313 } catch (Exception e) { 314 throw new Error("Unable to enable reporting!"); 315 } 316 } 317 main(String[] args)318 public static void main(String[] args) { 319 doTest(); 320 } 321 ensureTestWatcherInitialized()322 private static void ensureTestWatcherInitialized() { 323 try { 324 // Make sure the TestWatcher class can be found from the Object <init> function. 325 addToBootClassLoader(LISTENER_LOCATION); 326 // Load TestWatcher from the bootclassloader and make sure it is initialized. 327 Class<?> testwatcher_class = Class.forName("art.test.TestWatcher", true, null); 328 doEnableReporting = testwatcher_class.getDeclaredMethod("EnableReporting"); 329 doDisableReporting = testwatcher_class.getDeclaredMethod("DisableReporting"); 330 } catch (Exception e) { 331 throw new Error("Exception while making testwatcher", e); 332 } 333 } 334 335 // NB This function will cause 2 objects of type "Ljava/nio/HeapCharBuffer;" and 336 // "Ljava/nio/HeapCharBuffer;" to be allocated each time it is called. safePrintln(Object o)337 private static void safePrintln(Object o) { 338 DisableReporting(); 339 System.out.println("\t" + o); 340 EnableReporting(); 341 } 342 throwFrom(int depth)343 private static void throwFrom(int depth) throws Exception { 344 if (depth <= 0) { 345 throw new Exception("Throwing the exception"); 346 } else { 347 throwFrom(depth - 1); 348 } 349 } 350 doTest()351 public static void doTest() { 352 safePrintln("Initializing and loading the TestWatcher class that will (eventually) be " + 353 "notified of object allocations"); 354 // Make sure the TestWatcher class is initialized before we do anything else. 355 ensureTestWatcherInitialized(); 356 safePrintln("Allocating an j.l.Object before redefining Object class"); 357 // Make sure these aren't shown. 358 Object o = new Object(); 359 safePrintln("Allocating a Transform before redefining Object class"); 360 Transform t = new Transform(); 361 362 // Redefine the Object Class. 363 safePrintln("Redefining the Object class to add a hook into the <init> method"); 364 doCommonClassRedefinition(Object.class, CLASS_BYTES, DEX_BYTES); 365 366 safePrintln("Allocating an j.l.Object after redefining Object class"); 367 Object o2 = new Object(); 368 safePrintln("Allocating a Transform after redefining Object class"); 369 Transform t2 = new Transform(); 370 371 // This shouldn't cause the Object constructor to be run. 372 safePrintln("Allocating an int[] after redefining Object class"); 373 int[] abc = new int[12]; 374 375 // Try adding stuff to an array list. 376 safePrintln("Allocating an array list"); 377 ArrayList<Object> al = new ArrayList<>(); 378 safePrintln("Adding a bunch of stuff to the array list"); 379 al.add(new Object()); 380 al.add(new Object()); 381 al.add(o2); 382 al.add(o); 383 al.add(t); 384 al.add(t2); 385 al.add(new Transform()); 386 387 // Try adding stuff to a LinkedList 388 safePrintln("Allocating a linked list"); 389 LinkedList<Object> ll = new LinkedList<>(); 390 safePrintln("Adding a bunch of stuff to the linked list"); 391 ll.add(new Object()); 392 ll.add(new Object()); 393 ll.add(o2); 394 ll.add(o); 395 ll.add(t); 396 ll.add(t2); 397 ll.add(new Transform()); 398 399 // Try making an exception. 400 safePrintln("Throwing from down 4 stack frames"); 401 try { 402 throwFrom(4); 403 } catch (Exception e) { 404 safePrintln("Exception caught."); 405 } 406 407 safePrintln("Finishing test!"); 408 } 409 addToBootClassLoader(String s)410 private static native void addToBootClassLoader(String s); 411 } 412