155 lines
5.0 KiB
Java
155 lines
5.0 KiB
Java
/*
|
|
* 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);
|
|
}
|