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 java.lang.reflect.Method; 18 import java.util.ArrayList; 19 import java.util.Base64; 20 import java.util.LinkedList; 21 22 public class Main { 23 /** 24 * NB This test cannot be run on the RI. 25 * TODO We should make this run on the RI. 26 */ 27 28 private static final String LISTENER_LOCATION = 29 System.getenv("DEX_LOCATION") + "/980-redefine-object-ex.jar"; 30 31 private static Method doEnableReporting; 32 private static Method doDisableReporting; 33 DisableReporting()34 private static void DisableReporting() { 35 if (doDisableReporting == null) { 36 return; 37 } 38 try { 39 doDisableReporting.invoke(null); 40 } catch (Exception e) { 41 throw new Error("Unable to disable reporting!"); 42 } 43 } 44 EnableReporting()45 private static void EnableReporting() { 46 if (doEnableReporting == null) { 47 return; 48 } 49 try { 50 doEnableReporting.invoke(null); 51 } catch (Exception e) { 52 throw new Error("Unable to enable reporting!"); 53 } 54 } 55 main(String[] args)56 public static void main(String[] args) { 57 doTest(); 58 } 59 ensureTestWatcherInitialized()60 private static void ensureTestWatcherInitialized() { 61 try { 62 // Make sure the TestWatcher class can be found from the Object <init> function. 63 addToBootClassLoader(LISTENER_LOCATION); 64 // Load TestWatcher from the bootclassloader and make sure it is initialized. 65 Class<?> testwatcher_class = Class.forName("art.test.TestWatcher", true, null); 66 doEnableReporting = testwatcher_class.getDeclaredMethod("EnableReporting"); 67 doDisableReporting = testwatcher_class.getDeclaredMethod("DisableReporting"); 68 } catch (Exception e) { 69 throw new Error("Exception while making testwatcher", e); 70 } 71 } 72 73 // NB This function will cause 2 objects of type "Ljava/nio/HeapCharBuffer;" and 74 // "Ljava/nio/HeapCharBuffer;" to be allocated each time it is called. safePrintln(Object o)75 private static void safePrintln(Object o) { 76 DisableReporting(); 77 System.out.println("\t" + o); 78 EnableReporting(); 79 } 80 throwFrom(int depth)81 private static void throwFrom(int depth) throws Exception { 82 if (depth <= 0) { 83 throw new Exception("Throwing the exception"); 84 } else { 85 throwFrom(depth - 1); 86 } 87 } 88 doTest()89 public static void doTest() { 90 safePrintln("Initializing and loading the TestWatcher class that will (eventually) be " + 91 "notified of object allocations"); 92 // Make sure the TestWatcher class is initialized before we do anything else. 93 ensureTestWatcherInitialized(); 94 safePrintln("Allocating an j.l.Object before redefining Object class"); 95 // Make sure these aren't shown. 96 Object o = new Object(); 97 safePrintln("Allocating a Transform before redefining Object class"); 98 Transform t = new Transform(); 99 100 // Redefine the Object Class. 101 safePrintln("Redefining the Object class to add a hook into the <init> method"); 102 addMemoryTrackingCall(Object.class, Thread.currentThread()); 103 104 safePrintln("Allocating an j.l.Object after redefining Object class"); 105 Object o2 = new Object(); 106 safePrintln("Allocating a Transform after redefining Object class"); 107 Transform t2 = new Transform(); 108 109 // This shouldn't cause the Object constructor to be run. 110 safePrintln("Allocating an int[] after redefining Object class"); 111 int[] abc = new int[12]; 112 113 // Try adding stuff to an array list. 114 safePrintln("Allocating an array list"); 115 ArrayList<Object> al = new ArrayList<>(); 116 safePrintln("Adding a bunch of stuff to the array list"); 117 al.add(new Object()); 118 al.add(new Object()); 119 al.add(o2); 120 al.add(o); 121 al.add(t); 122 al.add(t2); 123 al.add(new Transform()); 124 125 // Try adding stuff to a LinkedList 126 safePrintln("Allocating a linked list"); 127 LinkedList<Object> ll = new LinkedList<>(); 128 safePrintln("Adding a bunch of stuff to the linked list"); 129 ll.add(new Object()); 130 ll.add(new Object()); 131 ll.add(o2); 132 ll.add(o); 133 ll.add(t); 134 ll.add(t2); 135 ll.add(new Transform()); 136 137 // Try making an exception. 138 safePrintln("Throwing from down 4 stack frames"); 139 try { 140 throwFrom(4); 141 } catch (Exception e) { 142 safePrintln("Exception caught."); 143 } 144 145 safePrintln("Finishing test!"); 146 } 147 148 // This is from 929-search/search.cc addToBootClassLoader(String s)149 private static native void addToBootClassLoader(String s); 150 // This is from 980-redefine-object/redef_object.cc 151 // It will add a call to Lart/test/TestWatcher;->NotifyConstructed()V in the Object <init>()V 152 // function. addMemoryTrackingCall(Class c, Thread thr)153 private static native void addMemoryTrackingCall(Class c, Thread thr); 154 } 155