Test case to check class loading using custom class loader

Change-Id: I45ce392b29b1c16de0c47acd1f04324206561ae8
diff --git a/tests/tests/os/assets/dex1.bytes b/tests/tests/os/assets/dex1.bytes
new file mode 100644
index 0000000..a9f914e
--- /dev/null
+++ b/tests/tests/os/assets/dex1.bytes
Binary files differ
diff --git a/tests/tests/os/src/android/os/cts/CustomClassLoaderTest.java b/tests/tests/os/src/android/os/cts/CustomClassLoaderTest.java
new file mode 100644
index 0000000..bd88073
--- /dev/null
+++ b/tests/tests/os/src/android/os/cts/CustomClassLoaderTest.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+
+package android.os.cts;
+
+import java.io.*;
+import java.lang.reflect.*;
+
+import android.test.AndroidTestCase;
+
+public class CustomClassLoaderTest extends AndroidTestCase {
+    File tf;
+
+    @Override
+    public void setUp() throws Exception {
+        /*
+         * dex1.bytes is a jar file with a classes.dex in it.
+         * The classes.dex has been javac'ed and dx'ed
+         * with the following java file:
+         *
+         * package android.os.cts;
+         *   public class TestClass {
+         *     public static final String MESSAGE = "expected_field";
+         *   }
+         *
+         */
+
+        super.setUp();
+        // Extract the packaged dex/jar file to a temporary file so we
+        // can use it with our classloader.
+        tf = File.createTempFile("CustomClassLoaderTest_TestClass", ".dex");
+        tf.deleteOnExit();
+        InputStream is = mContext.getAssets().open("dex1.bytes");
+        assertNotNull(is);
+        OutputStream fos = new FileOutputStream(tf);
+        byte[] buffer = new byte[8192];
+        int len = is.read(buffer);
+        while (len != -1) {
+            fos.write(buffer, 0, len);
+            len = is.read(buffer);
+        }
+        fos.flush();
+        fos.close();
+    }
+
+    /* Test a custom class loader based on the DexClassLoader.
+     */
+    public void testCustomDexClassLoader() throws Exception {
+        // Try to load the TestClass class by the CustomDexClassLoader.
+        try {
+            CustomDexClassLoader cl = new CustomDexClassLoader(
+                    tf.getAbsolutePath(),
+                    mContext.getCodeCacheDir().getAbsolutePath(),
+                    ClassLoader.getSystemClassLoader().getParent());
+            // Load the class and get the field 'MESSAGE' and
+            // check that it is from the dex1.bytes .jar file.
+            Field field = cl.loadClass("android.os.cts.TestClass").getField("MESSAGE");
+            assertTrue(((String)field.get(null)).equals("expected_field"));
+        } catch (Exception e) {
+            throw new RuntimeException("test exception", e);
+        }
+    }
+
+    /* Test a custom class loader based on the PathClassLoader.
+     */
+    public void testCustomPathClassLoader() throws Exception {
+        // Try to load the TestClass class by the CustomPathClassLoader.
+        try {
+            CustomPathClassLoader cl = new CustomPathClassLoader(
+                    tf.getAbsolutePath(),
+                    ClassLoader.getSystemClassLoader().getParent());
+            // Load the class and get the field 'MESSAGE' and
+            // check that it is from the dex1.bytes .jar file.
+            Field field = cl.loadClass("android.os.cts.TestClass").getField("MESSAGE");
+            assertTrue(((String)field.get(null)).equals("expected_field"));
+        } catch (Exception e) {
+            throw new RuntimeException("test exception", e);
+        }
+    }
+}
diff --git a/tests/tests/os/src/android/os/cts/CustomDexClassLoader.java b/tests/tests/os/src/android/os/cts/CustomDexClassLoader.java
new file mode 100644
index 0000000..c009bd8
--- /dev/null
+++ b/tests/tests/os/src/android/os/cts/CustomDexClassLoader.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+
+package android.os.cts;
+
+import dalvik.system.DexClassLoader;
+
+// Trivial subclass of DexClassLoader
+public class CustomDexClassLoader extends DexClassLoader {
+
+    public CustomDexClassLoader(String dexPath, String optimizedDirectory, ClassLoader parent) {
+        super(dexPath, optimizedDirectory, null, parent);
+    }
+}
diff --git a/tests/tests/os/src/android/os/cts/CustomPathClassLoader.java b/tests/tests/os/src/android/os/cts/CustomPathClassLoader.java
new file mode 100644
index 0000000..f7bdb51
--- /dev/null
+++ b/tests/tests/os/src/android/os/cts/CustomPathClassLoader.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+
+package android.os.cts;
+
+import dalvik.system.PathClassLoader;
+
+// Trivial subclass of PathClassLoader
+public class CustomPathClassLoader extends PathClassLoader {
+
+    public CustomPathClassLoader(String dexPath, ClassLoader parent) {
+        super(dexPath, parent);
+    }
+}
diff --git a/tests/tests/os/src/android/os/cts/TestClass.java b/tests/tests/os/src/android/os/cts/TestClass.java
new file mode 100644
index 0000000..f0959bc
--- /dev/null
+++ b/tests/tests/os/src/android/os/cts/TestClass.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+
+package android.os.cts;
+
+public class TestClass {
+
+    public static final String MESSAGE = "WRONG_FIELD";
+}