diff options
author | jeffhao <jeffhao@google.com> | 2011-09-29 17:41:15 -0700 |
---|---|---|
committer | jeffhao <jeffhao@google.com> | 2011-09-29 17:41:15 -0700 |
commit | 5d1ac920fdaef5d4ec8f66bb734488cd9660b024 (patch) | |
tree | dd372f306ab70f4c86759869b1f74eca62ff6f2b /test/068-classloader | |
parent | c31664f3d82e6cd68275a529a8a73f067a52e8be (diff) | |
download | art-5d1ac920fdaef5d4ec8f66bb734488cd9660b024.zip art-5d1ac920fdaef5d4ec8f66bb734488cd9660b024.tar.gz art-5d1ac920fdaef5d4ec8f66bb734488cd9660b024.tar.bz2 |
Adding old unit tests to test suite.
These tests are copied straight over. They'll still run, but they're
using the old system.
Change-Id: If494519e52ddf858a9febfc55bdae830468cb3c8
Diffstat (limited to 'test/068-classloader')
29 files changed, 1166 insertions, 0 deletions
diff --git a/test/068-classloader/expected.txt b/test/068-classloader/expected.txt new file mode 100644 index 0000000..bf131ee --- /dev/null +++ b/test/068-classloader/expected.txt @@ -0,0 +1,13 @@ +base: class DoubledImplement +base2: class DoubledImplement2 +Got expected access exception #1 +Got expected CNFE/IAE #2 +Got expected CNFE/IAE #3 +Got expected LinkageError on DE +Got DEO result DoubledExtendOkay 1 +Got LinkageError on GD +Got LinkageError on TA +Ctor: doubled implement, type 1 +DoubledImplement one +Got LinkageError on DI (early) +Got LinkageError on IDI (early) diff --git a/test/068-classloader/info.txt b/test/068-classloader/info.txt new file mode 100644 index 0000000..421e52a --- /dev/null +++ b/test/068-classloader/info.txt @@ -0,0 +1,8 @@ +Class loaders allow code to "redefine" a given class, e.g. it's possible to +have multiple classes called "com.android.Blah" loaded simultaneously. The +classes are distinct and must be treated as such. This test exercises +some situations in which a VM that only checks the UTF-8 signatures could +mix things up. + +This also tests a couple of situations in which an IllegalAccessException +is expected. diff --git a/test/068-classloader/src-ex/AbstractGet.java b/test/068-classloader/src-ex/AbstractGet.java new file mode 100644 index 0000000..db13b32 --- /dev/null +++ b/test/068-classloader/src-ex/AbstractGet.java @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2009 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. + */ + +/** + * Verify that we don't reject this with a LinkageError. + */ +public class AbstractGet extends AbstractBase { + public DoubledExtendOkay getExtended() { + return new DoubledExtendOkay(); + } +} + +/** + * Abstract class, does not declare getAbstract. This cause the VM to + * generate a "miranda" method. + */ +abstract class AbstractBase extends BaseOkay { + public abstract DoubledExtendOkay getExtended(); +} diff --git a/test/068-classloader/src-ex/DoubledExtend.java b/test/068-classloader/src-ex/DoubledExtend.java new file mode 100644 index 0000000..6ad2708 --- /dev/null +++ b/test/068-classloader/src-ex/DoubledExtend.java @@ -0,0 +1,20 @@ +// Copyright 2008 The Android Open Source Project + +/** + * Doubled sub-class, form #2. + */ +public class DoubledExtend extends Base { + public DoubledExtend() { + //System.out.println("Ctor: doubled extend, type 2"); + } + + @Override + public DoubledExtend getExtended() { + //System.out.println("getExtended 2"); + return new DoubledExtend(); + } + + public String getStr() { + return "DoubledExtend 2"; + } +} diff --git a/test/068-classloader/src-ex/DoubledExtendOkay.java b/test/068-classloader/src-ex/DoubledExtendOkay.java new file mode 100644 index 0000000..9674875 --- /dev/null +++ b/test/068-classloader/src-ex/DoubledExtendOkay.java @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2009 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. + */ + +/** + * "Okay" doubled sub-class, form #2. + */ +public class DoubledExtendOkay extends BaseOkay { + public DoubledExtendOkay() { + //System.out.println("Ctor: doubled extend okay, type 2"); + } + + /* + @Override + public DoubledExtendOkay getExtended() { + //System.out.println("getExtended 2"); + return new DoubledExtendOkay(); + } + */ + + public String getStr() { + return "DoubledExtendOkay 2"; + } +} diff --git a/test/068-classloader/src-ex/DoubledImplement.java b/test/068-classloader/src-ex/DoubledImplement.java new file mode 100644 index 0000000..5c44fc3 --- /dev/null +++ b/test/068-classloader/src-ex/DoubledImplement.java @@ -0,0 +1,18 @@ +// Copyright 2008 The Android Open Source Project + +/** + * Doubled sub-class, form #2. + */ +public class DoubledImplement implements ICommon { + public DoubledImplement() { + System.out.println("Ctor: doubled implement, type 2"); + } + + public DoubledImplement getDoubledInstance() { + return new DoubledImplement(); + } + + public void two() { + System.out.println("DoubledImplement two"); + } +} diff --git a/test/068-classloader/src-ex/DoubledImplement2.java b/test/068-classloader/src-ex/DoubledImplement2.java new file mode 100644 index 0000000..24ecb65 --- /dev/null +++ b/test/068-classloader/src-ex/DoubledImplement2.java @@ -0,0 +1,32 @@ +/* + * 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. + */ + +/** + * Another doubled sub-class, form #2. + */ +public class DoubledImplement2 implements ICommon2 { + public DoubledImplement2() { + System.out.println("Ctor: doubled implement, type 2"); + } + + public DoubledImplement2 getDoubledInstance2() { + return new DoubledImplement2(); + } + + public void two() { + System.out.println("DoubledImplement2 two"); + } +} diff --git a/test/068-classloader/src-ex/GetDoubled.java b/test/068-classloader/src-ex/GetDoubled.java new file mode 100644 index 0000000..28ada1e --- /dev/null +++ b/test/068-classloader/src-ex/GetDoubled.java @@ -0,0 +1,26 @@ +/* + * 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. + */ + +/* + * The interface we implement was declared in a different class loader, + * which means the DoubledExtend we return is not the one it was declared + * to return. + */ +public class GetDoubled implements IGetDoubled { + public DoubledExtendOkay getDoubled() { + return new DoubledExtendOkay(); + } +} diff --git a/test/068-classloader/src-ex/IfaceImpl.java b/test/068-classloader/src-ex/IfaceImpl.java new file mode 100644 index 0000000..7e9c27d --- /dev/null +++ b/test/068-classloader/src-ex/IfaceImpl.java @@ -0,0 +1,21 @@ +/* + * 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. + */ + +public class IfaceImpl implements IfaceSub { + public DoubledImplement2 getDoubledInstance2() { + return new DoubledImplement2(); + } +} diff --git a/test/068-classloader/src-ex/IfaceSub.java b/test/068-classloader/src-ex/IfaceSub.java new file mode 100644 index 0000000..7e512e7 --- /dev/null +++ b/test/068-classloader/src-ex/IfaceSub.java @@ -0,0 +1,19 @@ +/* + * 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. + */ + +public interface IfaceSub extends IfaceSuper { + public DoubledImplement2 getDoubledInstance2(); +} diff --git a/test/068-classloader/src-ex/Inaccessible1.java b/test/068-classloader/src-ex/Inaccessible1.java new file mode 100644 index 0000000..415a8a1 --- /dev/null +++ b/test/068-classloader/src-ex/Inaccessible1.java @@ -0,0 +1,11 @@ +// Copyright 2008 The Android Open Source Project + +/** + * Non-public class, inaccessible from Main. Note the constructor is + * public. + */ +class Inaccessible1 extends SimpleBase { + public Inaccessible1() { + System.out.println("--- inaccessible1"); + } +} diff --git a/test/068-classloader/src-ex/Inaccessible2.java b/test/068-classloader/src-ex/Inaccessible2.java new file mode 100644 index 0000000..dc20c21 --- /dev/null +++ b/test/068-classloader/src-ex/Inaccessible2.java @@ -0,0 +1,10 @@ +// Copyright 2008 The Android Open Source Project + +/** + * Public class that can't access its base. + */ +public class Inaccessible2 extends InaccessibleBase { + public Inaccessible2() { + System.out.println("--- inaccessible2"); + } +} diff --git a/test/068-classloader/src-ex/Inaccessible3.java b/test/068-classloader/src-ex/Inaccessible3.java new file mode 100644 index 0000000..771d0f7 --- /dev/null +++ b/test/068-classloader/src-ex/Inaccessible3.java @@ -0,0 +1,10 @@ +// Copyright 2008 The Android Open Source Project + +/** + * Public class that can't access its interface. + */ +public class Inaccessible3 implements InaccessibleInterface { + public Inaccessible3() { + System.out.println("--- inaccessible3"); + } +} diff --git a/test/068-classloader/src/Base.java b/test/068-classloader/src/Base.java new file mode 100644 index 0000000..b297a8a --- /dev/null +++ b/test/068-classloader/src/Base.java @@ -0,0 +1,16 @@ +// Copyright 2008 The Android Open Source Project + +/** + * Common base class. + */ +public class Base { + public Base() {} + + public DoubledExtend getExtended() { + return new DoubledExtend(); + } + + public static String doStuff(DoubledExtend dt) { + return dt.getStr(); + } +} diff --git a/test/068-classloader/src/BaseOkay.java b/test/068-classloader/src/BaseOkay.java new file mode 100644 index 0000000..48b7796 --- /dev/null +++ b/test/068-classloader/src/BaseOkay.java @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2009 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. + */ + +/** + * Common base class. + */ +public class BaseOkay implements IDoubledExtendOkay { + public BaseOkay() {} + + public DoubledExtendOkay getExtended() { + return new DoubledExtendOkay(); + } + + public static String doStuff(DoubledExtendOkay dt) { + return dt.getStr(); + } +} + +/** + * Interface that declares the not-overridden method. This exists to ensure + * that the existence of an interface doesn't trip the check. + */ +interface IDoubledExtendOkay { + public DoubledExtendOkay getExtended(); +} diff --git a/test/068-classloader/src/DoubledExtend.java b/test/068-classloader/src/DoubledExtend.java new file mode 100644 index 0000000..5f8ebc2 --- /dev/null +++ b/test/068-classloader/src/DoubledExtend.java @@ -0,0 +1,20 @@ +// Copyright 2008 The Android Open Source Project + +/** + * Doubled sub-class, form #1. + */ +public class DoubledExtend extends Base { + public DoubledExtend() { + //System.out.println("Ctor: doubled extend, type 1"); + } + + @Override + public DoubledExtend getExtended() { + System.out.println("getExtended 1"); + return new DoubledExtend(); + } + + public String getStr() { + return "DoubledExtend 1"; + } +} diff --git a/test/068-classloader/src/DoubledExtendOkay.java b/test/068-classloader/src/DoubledExtendOkay.java new file mode 100644 index 0000000..e226e5f --- /dev/null +++ b/test/068-classloader/src/DoubledExtendOkay.java @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2009 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. + */ + +/** + * "Okay" doubled sub-class, form #1. + */ +public class DoubledExtendOkay extends BaseOkay { + public DoubledExtendOkay() { + //System.out.println("Ctor: doubled extend okay, type 1"); + } + + /* + @Override + public DoubledExtendOkay getExtended() { + System.out.println("getExtended 1"); + return new DoubledExtendOkay(); + } + */ + + public String getStr() { + return "DoubledExtendOkay 1"; + } +} diff --git a/test/068-classloader/src/DoubledImplement.java b/test/068-classloader/src/DoubledImplement.java new file mode 100644 index 0000000..64ec5e2 --- /dev/null +++ b/test/068-classloader/src/DoubledImplement.java @@ -0,0 +1,18 @@ +// Copyright 2008 The Android Open Source Project + +/** + * Doubled sub-class, form #1. + */ +class DoubledImplement implements ICommon { + public DoubledImplement() { + System.out.println("Ctor: doubled implement, type 1"); + } + + public DoubledImplement getDoubledInstance() { + return new DoubledImplement(); + } + + public void one() { + System.out.println("DoubledImplement one"); + } +} diff --git a/test/068-classloader/src/DoubledImplement2.java b/test/068-classloader/src/DoubledImplement2.java new file mode 100644 index 0000000..12c036c --- /dev/null +++ b/test/068-classloader/src/DoubledImplement2.java @@ -0,0 +1,32 @@ +/* + * 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. + */ + +/** + * Another doubled sub-class, form #1. + */ +public class DoubledImplement2 implements ICommon2 { + public DoubledImplement2() { + System.out.println("Ctor: doubled implement, type 1"); + } + + public DoubledImplement2 getDoubledInstance2() { + return new DoubledImplement2(); + } + + public void one() { + System.out.println("DoubledImplement2 one"); + } +} diff --git a/test/068-classloader/src/FancyLoader.java b/test/068-classloader/src/FancyLoader.java new file mode 100644 index 0000000..173b08f --- /dev/null +++ b/test/068-classloader/src/FancyLoader.java @@ -0,0 +1,228 @@ +/* + * 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.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.RandomAccessFile; +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; +import java.lang.reflect.InvocationTargetException; + +/** + * A class loader with atypical behavior: we try to load a private + * class implementation before asking the system or boot loader. This + * is used to create multiple classes with identical names in a single VM. + * + * If DexFile is available, we use that; if not, we assume we're not in + * Dalvik and instantiate the class with defineClass(). + * + * The location of the DEX files and class data is dependent upon the + * test framework. + */ +public class FancyLoader extends ClassLoader { + /* this is where the "alternate" .class files live */ + static final String CLASS_PATH = "classes-ex/"; + + /* this is the "alternate" DEX/Jar file */ + static final String DEX_FILE = "test-ex.jar"; + + /* on Dalvik, this is a DexFile; otherwise, it's null */ + private Class mDexClass; + + private Object mDexFile; + + /** + * Construct FancyLoader, grabbing a reference to the DexFile class + * if we're running under Dalvik. + */ + public FancyLoader(ClassLoader parent) { + super(parent); + + try { + mDexClass = parent.loadClass("dalvik/system/DexFile"); + } catch (ClassNotFoundException cnfe) { + // ignore -- not running Dalvik + } + } + + /** + * Finds the class with the specified binary name. + * + * We search for a file in CLASS_PATH or pull an entry from DEX_FILE. + * If we don't find a match, we throw an exception. + */ + protected Class<?> findClass(String name) throws ClassNotFoundException + { + if (mDexClass != null) { + return findClassDalvik(name); + } else { + return findClassNonDalvik(name); + } + } + + /** + * Finds the class with the specified binary name, from a DEX file. + */ + private Class<?> findClassDalvik(String name) + throws ClassNotFoundException { + + if (mDexFile == null) { + synchronized (FancyLoader.class) { + Constructor ctor; + /* + * Construct a DexFile object through reflection. + */ + try { + ctor = mDexClass.getConstructor(new Class[] {String.class}); + } catch (NoSuchMethodException nsme) { + throw new ClassNotFoundException("getConstructor failed", + nsme); + } + + try { + mDexFile = ctor.newInstance(DEX_FILE); + } catch (InstantiationException ie) { + throw new ClassNotFoundException("newInstance failed", ie); + } catch (IllegalAccessException iae) { + throw new ClassNotFoundException("newInstance failed", iae); + } catch (InvocationTargetException ite) { + throw new ClassNotFoundException("newInstance failed", ite); + } + } + } + + /* + * Call DexFile.loadClass(String, ClassLoader). + */ + Method meth; + + try { + meth = mDexClass.getMethod("loadClass", + new Class[] { String.class, ClassLoader.class }); + } catch (NoSuchMethodException nsme) { + throw new ClassNotFoundException("getMethod failed", nsme); + } + + try { + meth.invoke(mDexFile, name, this); + } catch (IllegalAccessException iae) { + throw new ClassNotFoundException("loadClass failed", iae); + } catch (InvocationTargetException ite) { + throw new ClassNotFoundException("loadClass failed", + ite.getCause()); + } + + return null; + } + + /** + * Finds the class with the specified binary name, from .class files. + */ + private Class<?> findClassNonDalvik(String name) + throws ClassNotFoundException { + + String pathName = CLASS_PATH + name + ".class"; + //System.out.println("--- Fancy: looking for " + pathName); + + File path = new File(pathName); + RandomAccessFile raf; + + try { + raf = new RandomAccessFile(path, "r"); + } catch (FileNotFoundException fnfe) { + throw new ClassNotFoundException("Not found: " + pathName); + } + + /* read the entire file in */ + byte[] fileData; + try { + fileData = new byte[(int) raf.length()]; + raf.readFully(fileData); + } catch (IOException ioe) { + throw new ClassNotFoundException("Read error: " + pathName); + } finally { + try { + raf.close(); + } catch (IOException ioe) { + // drop + } + } + + /* create the class */ + //System.out.println("--- Fancy: defining " + name); + try { + return defineClass(name, fileData, 0, fileData.length); + } catch (Throwable th) { + throw new ClassNotFoundException("defineClass failed", th); + } + } + + /** + * Load a class. + * + * Normally a class loader wouldn't override this, but we want our + * version of the class to take precedence over an already-loaded + * version. + * + * We still want the system classes (e.g. java.lang.Object) from the + * bootstrap class loader. + */ + protected Class<?> loadClass(String name, boolean resolve) + throws ClassNotFoundException + { + Class res; + + /* + * 1. Invoke findLoadedClass(String) to check if the class has + * already been loaded. + * + * This doesn't change. + */ + res = findLoadedClass(name); + if (res != null) { + System.out.println("FancyLoader.loadClass: " + + name + " already loaded"); + if (resolve) + resolveClass(res); + return res; + } + + /* + * 3. Invoke the findClass(String) method to find the class. + */ + try { + res = findClass(name); + if (resolve) + resolveClass(res); + } + catch (ClassNotFoundException e) { + // we couldn't find it, so eat the exception and keep going + } + + /* + * 2. Invoke the loadClass method on the parent class loader. If + * the parent loader is null the class loader built-in to the + * virtual machine is used, instead. + * + * (Since we're not in java.lang, we can't actually invoke the + * parent's loadClass() method, but we passed our parent to the + * super-class which can take care of it for us.) + */ + res = super.loadClass(name, resolve); // returns class or throws + return res; + } +} diff --git a/test/068-classloader/src/ICommon.java b/test/068-classloader/src/ICommon.java new file mode 100644 index 0000000..35a98cc --- /dev/null +++ b/test/068-classloader/src/ICommon.java @@ -0,0 +1,8 @@ +// Copyright 2008 The Android Open Source Project + +/** + * Common interface. + */ +public interface ICommon { + public DoubledImplement getDoubledInstance(); +} diff --git a/test/068-classloader/src/ICommon2.java b/test/068-classloader/src/ICommon2.java new file mode 100644 index 0000000..6d81afc --- /dev/null +++ b/test/068-classloader/src/ICommon2.java @@ -0,0 +1,22 @@ +/* + * 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. + */ + +/** + * Common interface. + */ +public interface ICommon2 { + public DoubledImplement2 getDoubledInstance2(); +} diff --git a/test/068-classloader/src/IGetDoubled.java b/test/068-classloader/src/IGetDoubled.java new file mode 100644 index 0000000..08cd1ce --- /dev/null +++ b/test/068-classloader/src/IGetDoubled.java @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2009 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. + */ + +/** + * Interface, loaded from one loader, used from another. + */ +public interface IGetDoubled { + public DoubledExtendOkay getDoubled(); +} diff --git a/test/068-classloader/src/IfaceSuper.java b/test/068-classloader/src/IfaceSuper.java new file mode 100644 index 0000000..36d278c --- /dev/null +++ b/test/068-classloader/src/IfaceSuper.java @@ -0,0 +1,19 @@ +/* + * 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. + */ + +public interface IfaceSuper { + public DoubledImplement2 getDoubledInstance2(); +} diff --git a/test/068-classloader/src/InaccessibleBase.java b/test/068-classloader/src/InaccessibleBase.java new file mode 100644 index 0000000..83af665 --- /dev/null +++ b/test/068-classloader/src/InaccessibleBase.java @@ -0,0 +1,7 @@ +// Copyright 2008 The Android Open Source Project + +/** + * Non-public base class, inaccessible from alternate class loader. + */ +class InaccessibleBase { +} diff --git a/test/068-classloader/src/InaccessibleInterface.java b/test/068-classloader/src/InaccessibleInterface.java new file mode 100644 index 0000000..7f52b80 --- /dev/null +++ b/test/068-classloader/src/InaccessibleInterface.java @@ -0,0 +1,7 @@ +// Copyright 2008 The Android Open Source Project + +/** + * Non-public interface class, inaccessible from alternate class loader. + */ +interface InaccessibleInterface { +} diff --git a/test/068-classloader/src/Main.java b/test/068-classloader/src/Main.java new file mode 100644 index 0000000..1bc7b04 --- /dev/null +++ b/test/068-classloader/src/Main.java @@ -0,0 +1,425 @@ +/* + * 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. + */ + +/** + * Class loader test. + */ +public class Main { + /** + * Main entry point. + */ + public static void main(String[] args) { + 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); + } + + /** + * 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.err.println("loadClass failed"); + cnfe.printStackTrace(); + return; + } + + /* instantiate */ + Object obj; + try { + obj = altClass.newInstance(); + System.err.println("ERROR: Inaccessible1 was accessible"); + } catch (InstantiationException ie) { + System.err.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.err.println("ERROR: Inaccessible2 was accessible"); + } catch (ClassNotFoundException cnfe) { + Throwable cause = cnfe.getCause(); + if (cause instanceof IllegalAccessError) { + System.out.println("Got expected CNFE/IAE #2"); + } else { + System.err.println("Got unexpected CNFE/IAE #2"); + cnfe.printStackTrace(); + } + } + } + + /** + * See if we can load a class with an inaccessible interface. + */ + static void testAccess3(ClassLoader loader) { + Class altClass; + + try { + altClass = loader.loadClass("Inaccessible3"); + System.err.println("ERROR: Inaccessible3 was accessible"); + } catch (ClassNotFoundException cnfe) { + Throwable cause = cnfe.getCause(); + if (cause instanceof IllegalAccessError) { + System.out.println("Got expected CNFE/IAE #3"); + } else { + System.err.println("Got unexpected CNFE/IAE #3"); + cnfe.printStackTrace(); + } + } + } + + /** + * 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.err.println("loadClass failed: " + cnfe); + return; + } + + /* instantiate */ + try { + obj = doubledExtendClass.newInstance(); + } catch (InstantiationException ie) { + System.err.println("newInstance failed: " + ie); + return; + } catch (IllegalAccessException iae) { + System.err.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.err.println("ERROR: did not get LinkageError on DE"); + System.err.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.err.println("loadClass failed: " + cnfe); + return; + } + + /* instantiate */ + try { + obj = doubledExtendOkayClass.newInstance(); + } catch (InstantiationException ie) { + System.err.println("newInstance failed: " + ie); + return; + } catch (IllegalAccessException iae) { + System.err.println("newInstance failed: " + iae); + return; + } catch (LinkageError le) { + System.err.println("Got unexpected LinkageError on DEO"); + le.printStackTrace(); + 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.err.println("Got unexpected LinkageError on DEO"); + le.printStackTrace(); + 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.err.println("loadClass failed: " + cnfe); + return; + } + + /* instantiate */ + try { + obj = getDoubledClass.newInstance(); + } catch (InstantiationException ie) { + System.err.println("newInstance failed: " + ie); + return; + } catch (IllegalAccessException iae) { + System.err.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.err.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.err.println("loadClass ta failed: " + cnfe); + return; + } + + /* instantiate */ + try { + obj = abstractGetClass.newInstance(); + } catch (InstantiationException ie) { + System.err.println("newInstance failed: " + ie); + return; + } catch (IllegalAccessException iae) { + System.err.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.err.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.err.println("loadClass failed: " + cnfe); + return; + } + + /* instantiate */ + try { + obj = doubledImplementClass.newInstance(); + } catch (InstantiationException ie) { + System.err.println("newInstance failed: " + ie); + return; + } catch (IllegalAccessException iae) { + System.err.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.err.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.err.println("loadClass failed: " + cnfe); + return; + } + + /* instantiate */ + try { + obj = ifaceImplClass.newInstance(); + } catch (InstantiationException ie) { + System.err.println("newInstance failed: " + ie); + return; + } catch (IllegalAccessException iae) { + System.err.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(); + } +} diff --git a/test/068-classloader/src/SimpleBase.java b/test/068-classloader/src/SimpleBase.java new file mode 100644 index 0000000..fd56db9 --- /dev/null +++ b/test/068-classloader/src/SimpleBase.java @@ -0,0 +1,8 @@ +// Copyright 2008 The Android Open Source Project + +/** + * Simple, public base class. + */ +public class SimpleBase { + public SimpleBase() {} +} diff --git a/test/068-classloader/src/Useless.java b/test/068-classloader/src/Useless.java new file mode 100644 index 0000000..f51d9a8 --- /dev/null +++ b/test/068-classloader/src/Useless.java @@ -0,0 +1,4 @@ + +public class Useless implements ICommon { + public DoubledImplement getDoubledInstance() { return null; } +} |