/*
* Copyright ( C ) 2008 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.Constructor;
import java.lang.reflect.Method;
/**
* Class loader test .
*/
public class Main {
/**
* Main entry point .
*/
public static void main(String[] args) throws Exception {
FancyLoader loader;
loader = new FancyLoader(ClassLoader.getSystemClassLoader());
//System.out.println("SYSTEM: " + ClassLoader.getSystemClassLoader());
//System.out.println("ALTERN: " + loader);
/*
* This statement has no effect on this program , but it can
* change the point where a LinkageException is thrown in
* testImplement ( ) . When this is present the " reference
* implementation " throws an exception from Class . newInstance ( ) ,
* when it ' s absent the exception is deferred until the first time
* we call a method that isn ' t actually implemented .
*
* This isn ' t the class that fails - - it ' s a class with the same
* name in the " fancy " class loader - - but the VM thinks it has a
* reference to one of these ; presumably the difference is that
* without this the VM finds itself holding a reference to an
* instance of an uninitialized class .
*/
System.out.println("base: " + DoubledImplement.class );
System.out.println("base2: " + DoubledImplement2.class );
/*
* Run tests .
*/
testAccess1(loader);
testAccess2(loader);
testAccess3(loader);
testExtend(loader);
testExtendOkay(loader);
testInterface(loader);
testAbstract(loader);
testImplement(loader);
testIfaceImplement(loader);
testSeparation();
testClassForName();
testNullClassLoader();
}
static void testNullClassLoader() {
try {
/* this is the "alternate" DEX/Jar file */
String DEX_FILE = System.getenv("DEX_LOCATION" ) + "/068-classloader-ex.jar" ;
/* on Dalvik, this is a DexFile; otherwise, it's null */
Class <?> mDexClass = Class .forName("dalvik.system.DexFile" );
Constructor<?> ctor = mDexClass.getConstructor(String.class );
Object mDexFile = ctor.newInstance(DEX_FILE);
Method meth = mDexClass.getMethod("loadClass" , String.class , ClassLoader.class );
Object klass = meth.invoke(mDexFile, "Mutator" , null );
if (klass == null ) {
throw new AssertionError("loadClass with nullclass loader failed" );
}
} catch (Exception e) {
System.out.println(e);
}
System.out.println("Loaded class into null class loader" );
}
static void testSeparation() {
FancyLoader loader1 = new FancyLoader(ClassLoader.getSystemClassLoader());
FancyLoader loader2 = new FancyLoader(ClassLoader.getSystemClassLoader());
try {
Class <?> target1 = loader1.loadClass("MutationTarget" );
Class <?> target2 = loader2.loadClass("MutationTarget" );
if (target1 == target2) {
throw new RuntimeException("target1 should not be equal to target2" );
}
Class <?> mutator1 = loader1.loadClass("Mutator" );
Class <?> mutator2 = loader2.loadClass("Mutator" );
if (mutator1 == mutator2) {
throw new RuntimeException("mutator1 should not be equal to mutator2" );
}
runMutator(mutator1, 1 );
int value = getMutationTargetValue(target1);
if (value != 1 ) {
throw new RuntimeException("target 1 has unexpected value " + value);
}
value = getMutationTargetValue(target2);
if (value != 0 ) {
throw new RuntimeException("target 2 has unexpected value " + value);
}
runMutator(mutator2, 2 );
value = getMutationTargetValue(target1);
if (value != 1 ) {
throw new RuntimeException("target 1 has unexpected value " + value);
}
value = getMutationTargetValue(target2);
if (value != 2 ) {
throw new RuntimeException("target 2 has unexpected value " + value);
}
} catch (Exception ex) {
ex.printStackTrace(System.out);
}
}
private static void runMutator(Class <?> c, int v) throws Exception {
java.lang.reflect.Method m = c.getDeclaredMethod("mutate" , int .class );
m.invoke(null , v);
}
private static int getMutationTargetValue(Class <?> c) throws Exception {
java.lang.reflect.Field f = c.getDeclaredField("value" );
return f.getInt(null );
}
/**
* See if we can load a class that isn ' t public to us . We should be
* able to load it but not instantiate it .
*/
static void testAccess1(ClassLoader loader) {
Class <?> altClass;
try {
altClass = loader.loadClass("Inaccessible1" );
} catch (ClassNotFoundException cnfe) {
System.out.println("loadClass failed" );
cnfe.printStackTrace(System.out);
return ;
}
/* instantiate */
Object obj;
try {
obj = altClass.newInstance();
System.out.println("ERROR: Inaccessible1 was accessible" );
} catch (InstantiationException ie) {
System.out.println("newInstance failed: " + ie);
return ;
} catch (IllegalAccessException iae) {
System.out.println("Got expected access exception #1" );
//System.out.println("+++ " + iae);
return ;
}
}
/**
* See if we can load a class whose base class is not accessible to it
* ( though the base * is * accessible to us ) .
*/
static void testAccess2(ClassLoader loader) {
Class <?> altClass;
try {
altClass = loader.loadClass("Inaccessible2" );
System.out.println("ERROR: Inaccessible2 was accessible: " + altClass);
} catch (ClassNotFoundException cnfe) {
Throwable cause = cnfe.getCause();
if (cause instanceof IllegalAccessError) {
System.out.println("Got expected CNFE/IAE #2" );
} else {
System.out.println("Got unexpected CNFE/IAE #2" );
cnfe.printStackTrace(System.out);
}
}
}
/**
* See if we can load a class with an inaccessible interface .
*/
static void testAccess3(ClassLoader loader) {
Class <?> altClass;
try {
altClass = loader.loadClass("Inaccessible3" );
System.out.println("ERROR: Inaccessible3 was accessible: " + altClass);
} catch (ClassNotFoundException cnfe) {
Throwable cause = cnfe.getCause();
if (cause instanceof IllegalAccessError) {
System.out.println("Got expected CNFE/IAE #3" );
} else {
System.out.println("Got unexpected CNFE/IAE #3" );
cnfe.printStackTrace(System.out);
}
}
}
/**
* Test a doubled class that extends the base class .
*/
static void testExtend(ClassLoader loader) {
Class <?> doubledExtendClass;
Object obj;
/* get the "alternate" version of DoubledExtend */
try {
doubledExtendClass = loader.loadClass("DoubledExtend" );
//System.out.println("+++ DoubledExtend is " + doubledExtendClass
// + " in " + doubledExtendClass.getClassLoader());
} catch (ClassNotFoundException cnfe) {
System.out.println("loadClass failed: " + cnfe);
return ;
}
/* instantiate */
try {
obj = doubledExtendClass.newInstance();
} catch (InstantiationException ie) {
System.out.println("newInstance failed: " + ie);
return ;
} catch (IllegalAccessException iae) {
System.out.println("newInstance failed: " + iae);
return ;
} catch (LinkageError le) {
System.out.println("Got expected LinkageError on DE" );
return ;
}
/* use the base class reference to get a CL-specific instance */
Base baseRef = (Base) obj;
DoubledExtend de = baseRef.getExtended();
/* try to call through it */
try {
String result;
result = Base.doStuff(de);
System.out.println("ERROR: did not get LinkageError on DE" );
System.out.println("(result=" + result + ")" );
} catch (LinkageError le) {
System.out.println("Got expected LinkageError on DE" );
return ;
}
}
/**
* Test a doubled class that extends the base class , but is okay since
* it doesn ' t override the base class method .
*/
static void testExtendOkay(ClassLoader loader) {
Class <?> doubledExtendOkayClass;
Object obj;
/* get the "alternate" version of DoubledExtendOkay */
try {
doubledExtendOkayClass = loader.loadClass("DoubledExtendOkay" );
} catch (ClassNotFoundException cnfe) {
System.out.println("loadClass failed: " + cnfe);
return ;
}
/* instantiate */
try {
obj = doubledExtendOkayClass.newInstance();
} catch (InstantiationException ie) {
System.out.println("newInstance failed: " + ie);
return ;
} catch (IllegalAccessException iae) {
System.out.println("newInstance failed: " + iae);
return ;
} catch (LinkageError le) {
System.out.println("Got unexpected LinkageError on DEO" );
le.printStackTrace(System.out);
return ;
}
/* use the base class reference to get a CL-specific instance */
BaseOkay baseRef = (BaseOkay) obj;
DoubledExtendOkay de = baseRef.getExtended();
/* try to call through it */
try {
String result;
result = BaseOkay.doStuff(de);
System.out.println("Got DEO result " + result);
} catch (LinkageError le) {
System.out.println("Got unexpected LinkageError on DEO" );
le.printStackTrace(System.out);
return ;
}
}
/**
* Try to access a doubled class through a class that implements
* an interface declared in a different class .
*/
static void testInterface(ClassLoader loader) {
Class <?> getDoubledClass;
Object obj;
/* get GetDoubled from the "alternate" class loader */
try {
getDoubledClass = loader.loadClass("GetDoubled" );
} catch (ClassNotFoundException cnfe) {
System.out.println("loadClass failed: " + cnfe);
return ;
}
/* instantiate */
try {
obj = getDoubledClass.newInstance();
} catch (InstantiationException ie) {
System.out.println("newInstance failed: " + ie);
return ;
} catch (IllegalAccessException iae) {
System.out.println("newInstance failed: " + iae);
return ;
} catch (LinkageError le) {
// Dalvik bails here
System.out.println("Got LinkageError on GD" );
return ;
}
/*
* Cast the object to the interface , and try to use it .
*/
IGetDoubled iface = (IGetDoubled) obj;
try {
/* "de" will be the wrong variety of DoubledExtendOkay */
DoubledExtendOkay de = iface.getDoubled();
// reference impl bails here
String str = de.getStr();
} catch (LinkageError le) {
System.out.println("Got LinkageError on GD" );
return ;
}
System.out.println("Should have failed by now on GetDoubled" );
}
/**
* Throw an abstract class into the middle and see what happens .
*/
static void testAbstract(ClassLoader loader) {
Class <?> abstractGetClass;
Object obj;
/* get AbstractGet from the "alternate" loader */
try {
abstractGetClass = loader.loadClass("AbstractGet" );
} catch (ClassNotFoundException cnfe) {
System.out.println("loadClass ta failed: " + cnfe);
return ;
}
/* instantiate */
try {
obj = abstractGetClass.newInstance();
} catch (InstantiationException ie) {
System.out.println("newInstance failed: " + ie);
return ;
} catch (IllegalAccessException iae) {
System.out.println("newInstance failed: " + iae);
return ;
} catch (LinkageError le) {
System.out.println("Got LinkageError on TA" );
return ;
}
/* use the base class reference to get a CL-specific instance */
BaseOkay baseRef = (BaseOkay) obj;
DoubledExtendOkay de = baseRef.getExtended();
/* try to call through it */
try {
String result;
result = BaseOkay.doStuff(de);
} catch (LinkageError le) {
System.out.println("Got LinkageError on TA" );
return ;
}
System.out.println("Should have failed by now in testAbstract" );
}
/**
* Test a doubled class that implements a common interface .
*/
static void testImplement(ClassLoader loader) {
Class <?> doubledImplementClass;
Object obj;
useImplement(new DoubledImplement(), true );
/* get the "alternate" version of DoubledImplement */
try {
doubledImplementClass = loader.loadClass("DoubledImplement" );
} catch (ClassNotFoundException cnfe) {
System.out.println("loadClass failed: " + cnfe);
return ;
}
/* instantiate */
try {
obj = doubledImplementClass.newInstance();
} catch (InstantiationException ie) {
System.out.println("newInstance failed: " + ie);
return ;
} catch (IllegalAccessException iae) {
System.out.println("newInstance failed: " + iae);
return ;
} catch (LinkageError le) {
System.out.println("Got LinkageError on DI (early)" );
return ;
}
/* if we lived this long, try to do something with it */
ICommon icommon = (ICommon) obj;
useImplement(icommon.getDoubledInstance(), false );
}
/**
* Do something with a DoubledImplement instance .
*/
static void useImplement(DoubledImplement di, boolean isOne) {
//System.out.println("useObject: " + di.toString() + " -- "
// + di.getClass().getClassLoader());
try {
di.one();
if (!isOne) {
System.out.println("ERROR: did not get LinkageError on DI" );
}
} catch (LinkageError le) {
if (!isOne) {
System.out.println("Got LinkageError on DI (late)" );
} else {
throw le;
}
}
}
/**
* Test a class that implements an interface with a super - interface
* that refers to a doubled class .
*/
static void testIfaceImplement(ClassLoader loader) {
Class <?> ifaceImplClass;
Object obj;
/*
* Create an instance of IfaceImpl . We also pull in
* DoubledImplement2 from the other class loader ; without this
* we don ' t fail in some implementations .
*/
try {
ifaceImplClass = loader.loadClass("IfaceImpl" );
ifaceImplClass = loader.loadClass("DoubledImplement2" );
} catch (ClassNotFoundException cnfe) {
System.out.println("loadClass failed: " + cnfe);
return ;
}
/* instantiate */
try {
obj = ifaceImplClass.newInstance();
} catch (InstantiationException ie) {
System.out.println("newInstance failed: " + ie);
return ;
} catch (IllegalAccessException iae) {
System.out.println("newInstance failed: " + iae);
return ;
} catch (LinkageError le) {
System.out.println("Got LinkageError on IDI (early)" );
//System.out.println(le);
return ;
}
/*
* Without the pre - load of FancyLoader - > DoubledImplement2 , some
* implementations will happily execute through this part . " obj "
* comes from FancyLoader , but the di2 returned from ifaceSuper
* comes from the application class loader .
*/
IfaceSuper ifaceSuper = (IfaceSuper) obj;
DoubledImplement2 di2 = ifaceSuper.getDoubledInstance2();
di2.one();
}
static void testClassForName() throws Exception {
System.out.println(Class .forName("Main" ).toString());
try {
System.out.println(Class .forName("Main" , false , null ).toString());
} catch (ClassNotFoundException expected) {
System.out.println("Got expected ClassNotFoundException" );
}
}
}
Messung V0.5 in Prozent C=91 H=94 G=92
¤ Dauer der Verarbeitung: 0.2 Sekunden
(vorverarbeitet am 2026-06-29)
¤
*© Formatika GbR, Deutschland