| /* |
| * 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); |
| } |