/* * Copyright (C) 2017 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Base64; import java.util.LinkedList; public class Main { /** * NB This test cannot be run on the RI. * TODO We should make this run on the RI. */ private static final String LISTENER_LOCATION = System.getenv("DEX_LOCATION") + "/980-redefine-object-ex.jar"; private static Method doEnableReporting; private static Method doDisableReporting; private static void DisableReporting() { if (doDisableReporting == null) { return; } try { doDisableReporting.invoke(null); } catch (Exception e) { throw new Error("Unable to disable reporting!"); } } private static void EnableReporting() { if (doEnableReporting == null) { return; } try { doEnableReporting.invoke(null); } catch (Exception e) { throw new Error("Unable to enable reporting!"); } } public static void main(String[] args) { doTest(); } private static void ensureTestWatcherInitialized() { try { // Make sure the TestWatcher class can be found from the Object <init> function. addToBootClassLoader(LISTENER_LOCATION); // Load TestWatcher from the bootclassloader and make sure it is initialized. Class<?> testwatcher_class = Class.forName("art.test.TestWatcher", true, null); doEnableReporting = testwatcher_class.getDeclaredMethod("EnableReporting"); doDisableReporting = testwatcher_class.getDeclaredMethod("DisableReporting"); } catch (Exception e) { throw new Error("Exception while making testwatcher", e); } } // NB This function will cause 2 objects of type "Ljava/nio/HeapCharBuffer;" and // "Ljava/nio/HeapCharBuffer;" to be allocated each time it is called. private static void safePrintln(Object o) { DisableReporting(); System.out.println("\t" + o); EnableReporting(); } private static void throwFrom(int depth) throws Exception { if (depth <= 0) { throw new Exception("Throwing the exception"); } else { throwFrom(depth - 1); } } public static void doTest() { safePrintln("Initializing and loading the TestWatcher class that will (eventually) be " + "notified of object allocations"); // Make sure the TestWatcher class is initialized before we do anything else. ensureTestWatcherInitialized(); safePrintln("Allocating an j.l.Object before redefining Object class"); // Make sure these aren't shown. Object o = new Object(); safePrintln("Allocating a Transform before redefining Object class"); Transform t = new Transform(); // Redefine the Object Class. safePrintln("Redefining the Object class to add a hook into the <init> method"); addMemoryTrackingCall(Object.class, Thread.currentThread()); safePrintln("Allocating an j.l.Object after redefining Object class"); Object o2 = new Object(); safePrintln("Allocating a Transform after redefining Object class"); Transform t2 = new Transform(); // This shouldn't cause the Object constructor to be run. safePrintln("Allocating an int[] after redefining Object class"); int[] abc = new int[12]; // Try adding stuff to an array list. safePrintln("Allocating an array list"); ArrayList<Object> al = new ArrayList<>(); safePrintln("Adding a bunch of stuff to the array list"); al.add(new Object()); al.add(new Object()); al.add(o2); al.add(o); al.add(t); al.add(t2); al.add(new Transform()); // Try adding stuff to a LinkedList safePrintln("Allocating a linked list"); LinkedList<Object> ll = new LinkedList<>(); safePrintln("Adding a bunch of stuff to the linked list"); ll.add(new Object()); ll.add(new Object()); ll.add(o2); ll.add(o); ll.add(t); ll.add(t2); ll.add(new Transform()); // Try making an exception. safePrintln("Throwing from down 4 stack frames"); try { throwFrom(4); } catch (Exception e) { safePrintln("Exception caught."); } safePrintln("Finishing test!"); } // This is from 929-search/search.cc private static native void addToBootClassLoader(String s); // This is from 980-redefine-object/redef_object.cc // It will add a call to Lart/test/TestWatcher;->NotifyConstructed()V in the Object <init>()V // function. private static native void addMemoryTrackingCall(Class c, Thread thr); }