Home | History | Annotate | Download | only in src
      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 
    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 
    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 
    318   public static void main(String[] args) {
    319     doTest();
    320   }
    321 
    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.
    337   private static void safePrintln(Object o) {
    338     DisableReporting();
    339     System.out.println("\t" + o);
    340     EnableReporting();
    341   }
    342 
    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 
    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 
    410   private static native void addToBootClassLoader(String s);
    411 }
    412