Revert^4 "[art] Enable compilation of secondary dexes by default i..."
This reverts commit f5d83b3a550496f6ef120606de9920b3fb85baf1.
Reason for revert: Blacklist more tests expected to fail. Fix up
run script.
Bug: 149098478
Test: art/test/testrunner/testrunner.py -b --host
Test: art/test/testrunner/testrunner.py -b --host -t 596-app-images -t 660-clinit
Test: art/test/testrunner/testrunner.py -b --host -t 597-app-images-same-classloader
Test: art/test/testrunner/testrunner.py -b --host --debuggable
Test: art/test/testrunner/testrunner.py -b --host --all-jvmti -t 596 -t 597-app-images-same-classloader
Test: art/test/testrunner/testrunner.py -b --target -t 596 -t 597-app-images-same-classloader
Change-Id: If84e1cb941e64be9907cd7e9ce1ec30ce32f46c7
diff --git a/test/130-hprof/run b/test/130-hprof/run
new file mode 100644
index 0000000..73a984e
--- /dev/null
+++ b/test/130-hprof/run
@@ -0,0 +1,18 @@
+#!/bin/bash
+#
+# Copyright (C) 2020 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.
+
+# Currently app images aren't unloaded when dex files are unloaded.
+exec ${RUN} $@ --no-secondary-app-image
diff --git a/test/138-duplicate-classes-check/src-art/Main.java b/test/138-duplicate-classes-check/src-art/Main.java
index b32f0bc..35d0209 100644
--- a/test/138-duplicate-classes-check/src-art/Main.java
+++ b/test/138-duplicate-classes-check/src-art/Main.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-import dalvik.system.DexClassLoader;
+import dalvik.system.PathClassLoader;
import java.io.File;
import java.lang.reflect.Method;
@@ -32,9 +32,8 @@
// Now run the class from the -ex file.
String dexPath = System.getenv("DEX_LOCATION") + "/138-duplicate-classes-check-ex.jar";
- String optimizedDirectory = System.getenv("DEX_LOCATION");
String librarySearchPath = null;
- DexClassLoader loader = new DexClassLoader(dexPath, optimizedDirectory, librarySearchPath,
+ PathClassLoader loader = new PathClassLoader(dexPath, librarySearchPath,
getClass().getClassLoader());
try {
diff --git a/test/141-class-unload/run b/test/141-class-unload/run
new file mode 100644
index 0000000..73a984e
--- /dev/null
+++ b/test/141-class-unload/run
@@ -0,0 +1,18 @@
+#!/bin/bash
+#
+# Copyright (C) 2020 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.
+
+# Currently app images aren't unloaded when dex files are unloaded.
+exec ${RUN} $@ --no-secondary-app-image
diff --git a/test/596-app-images/app_images.cc b/test/596-app-images/app_images.cc
index 498ea1d..1bc2c1e 100644
--- a/test/596-app-images/app_images.cc
+++ b/test/596-app-images/app_images.cc
@@ -27,6 +27,8 @@
#include "gc/space/space-inl.h"
#include "image.h"
#include "mirror/class.h"
+#include "nativehelper/scoped_utf_chars.h"
+#include "oat_file.h"
#include "runtime.h"
#include "scoped_thread_state_change-inl.h"
@@ -34,13 +36,36 @@
namespace {
-extern "C" JNIEXPORT jboolean JNICALL Java_Main_checkAppImageLoaded(JNIEnv*, jclass) {
+// Returns whether the extensionless basename of `location` is equal to name.
+// E.g. check_name("/foo/bar/baz.odex", "baz") == true,
+// check_name("/foo/bar/baz.odex", "bar") == false
+static bool check_name(const std::string& location, const std::string& name) {
+ std::string loc_name = location;
+ size_t idx = loc_name.rfind('/');
+ if (idx != std::string::npos) {
+ loc_name = loc_name.substr(idx + 1);
+ }
+ idx = loc_name.rfind('.');
+ if (idx != std::string::npos) {
+ loc_name = loc_name.substr(0, idx);
+ }
+ return loc_name == name;
+}
+
+extern "C" JNIEXPORT jboolean JNICALL Java_Main_checkAppImageLoaded(JNIEnv* env,
+ jclass,
+ jstring jimage_name) {
+ ScopedUtfChars image_name(env, jimage_name);
ScopedObjectAccess soa(Thread::Current());
for (auto* space : Runtime::Current()->GetHeap()->GetContinuousSpaces()) {
if (space->IsImageSpace()) {
auto* image_space = space->AsImageSpace();
const auto& image_header = image_space->GetImageHeader();
- if (image_header.IsAppImage()) {
+ // Check that this is an app image associated with the dex file named
+ // `jname` by verifying the extensionless basename of the odex file
+ // location is equal to `jname`.
+ if (image_header.IsAppImage() &&
+ check_name(image_space->GetOatFile()->GetLocation(), image_name.c_str())) {
return JNI_TRUE;
}
}
diff --git a/test/596-app-images/expected.txt b/test/596-app-images/expected.txt
index 6a5618e..ff3be57 100644
--- a/test/596-app-images/expected.txt
+++ b/test/596-app-images/expected.txt
@@ -1 +1,2 @@
JNI_OnLoad called
+Secondary went
diff --git a/test/596-app-images/profile b/test/596-app-images/profile
new file mode 100644
index 0000000..2a3172c
--- /dev/null
+++ b/test/596-app-images/profile
@@ -0,0 +1,7 @@
+LMain$Inner;
+LMain$Nested;
+LStaticFields;
+LStaticFieldsInitSub;
+LStaticFieldsInit;
+LStaticInternString;
+LSecondary;
diff --git a/test/596-app-images/run b/test/596-app-images/run
new file mode 100644
index 0000000..dbdcd1c
--- /dev/null
+++ b/test/596-app-images/run
@@ -0,0 +1,18 @@
+#!/bin/bash
+#
+# Copyright (C) 2020 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.
+
+# We need a profile to tell dex2oat to include classes in the final app image
+exec ${RUN} --profile $@
diff --git a/test/596-app-images/src-art/Main.java b/test/596-app-images/src-art/Main.java
new file mode 100644
index 0000000..8bc2f3f
--- /dev/null
+++ b/test/596-app-images/src-art/Main.java
@@ -0,0 +1,193 @@
+/*
+ * Copyright 2020 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 dalvik.system.PathClassLoader;
+import java.lang.reflect.Field;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+
+class Main {
+ static final String DEX_FILE = System.getenv("DEX_LOCATION") + "/596-app-images.jar";
+ static final String SECONDARY_DEX_FILE =
+ System.getenv("DEX_LOCATION") + "/596-app-images-ex.jar";
+ static final String LIBRARY_SEARCH_PATH = System.getProperty("java.library.path");
+
+ static class Inner {
+ final public static int abc = 10;
+ }
+
+ static class Nested {
+
+ }
+
+ public static void main(String[] args) throws Exception {
+ System.loadLibrary(args[0]);
+
+ testAppImageLoaded();
+ testInitializedClasses();
+ testInternedStrings();
+ testReloadInternedString();
+ testClassesOutsideAppImage();
+ testLoadingSecondaryAppImage();
+ }
+
+ public static native boolean checkAppImageLoaded(String name);
+ public static native boolean checkAppImageContains(Class<?> klass);
+ public static native boolean checkInitialized(Class<?> klass);
+
+ public static void testAppImageLoaded() throws Exception {
+ assertTrue("App image is loaded", checkAppImageLoaded("596-app-images"));
+ assertTrue("App image contains Inner", checkAppImageContains(Inner.class));
+ }
+
+ public static void testInitializedClasses() throws Exception {
+ assertInitialized(Inner.class);
+ assertInitialized(Nested.class);
+ assertInitialized(StaticFields.class);
+ assertInitialized(StaticFieldsInitSub.class);
+ assertInitialized(StaticFieldsInit.class);
+ assertInitialized(StaticInternString.class);
+ }
+
+ private static void assertInitialized(Class<?> klass) {
+ assertTrue(klass.toString() + " is preinitialized", checkInitialized(klass));
+ }
+
+ public static void testInternedStrings() throws Exception {
+ StringBuffer sb = new StringBuffer();
+ sb.append("java.");
+ sb.append("abc.");
+ sb.append("Action");
+
+ String tmp = sb.toString();
+ String intern = tmp.intern();
+
+ assertNotSame("Dynamically constructed string is not interned", tmp, intern);
+ assertEquals("Static string on initialized class is matches runtime interned string", intern,
+ StaticInternString.intent);
+ assertEquals("Static string on initialized class is pre-interned", BootInternedString.boot,
+ BootInternedString.boot.intern());
+
+ // TODO: Does this next check really provide us anything?
+ Field f = StaticInternString.class.getDeclaredField("intent");
+ assertEquals("String literals are interned properly", intern, f.get(null));
+
+ assertEquals("String literals are interned properly across classes",
+ StaticInternString.getIntent(), StaticInternString2.getIntent());
+ }
+
+ public static void testReloadInternedString() throws Exception {
+ // reload the class StaticInternString, check whether static strings interned properly
+ PathClassLoader loader = new PathClassLoader(DEX_FILE, LIBRARY_SEARCH_PATH, null);
+ Class<?> staticInternString = loader.loadClass("StaticInternString");
+ assertTrue("Class in app image isn't loaded a second time after loading dex file again",
+ checkAppImageContains(staticInternString));
+
+ Method getIntent = staticInternString.getDeclaredMethod("getIntent");
+ assertEquals("Interned strings are still interned after multiple dex loads",
+ StaticInternString.getIntent(), getIntent.invoke(staticInternString));
+ }
+
+ public static void testClassesOutsideAppImage() {
+ assertFalse("App image doesn't contain non-optimized class",
+ checkAppImageContains(NonOptimizedClass.class));
+ assertFalse("App image didn't pre-initialize non-optimized class",
+ checkInitialized(NonOptimizedClass.class));
+ }
+
+ public static void testLoadingSecondaryAppImage() throws Exception {
+ final ClassLoader parent = Main.class.getClassLoader();
+
+ // Sanity check that the image isn't already loaded so we don't get bogus results below
+ assertFalse("Secondary app image isn't already loaded",
+ checkAppImageLoaded("596-app-images-ex"));
+
+ PathClassLoader pcl = new PathClassLoader(SECONDARY_DEX_FILE, parent);
+
+ assertTrue("Ensure app image is loaded if it should be",
+ checkAppImageLoaded("596-app-images-ex"));
+
+ Class<?> secondaryCls = pcl.loadClass("Secondary");
+ assertTrue("Ensure Secondary class is in the app image if the CLC is correct",
+ checkAppImageContains(secondaryCls));
+ assertTrue("Ensure Secondary class is preinitialized if the CLC is correct",
+ checkInitialized(secondaryCls));
+
+ secondaryCls.getDeclaredMethod("go").invoke(null);
+ }
+
+ private static void assertTrue(String message, boolean flag) {
+ if (flag) {
+ return;
+ }
+ throw new AssertionError(message);
+ }
+
+ private static void assertEquals(String message, Object a, Object b) {
+ StringBuilder sb = new StringBuilder(message != null ? message : "");
+ if (sb.length() > 0) {
+ sb.append(" ");
+ }
+ sb.append("expected:<").append(a).append("> but was:<").append(b).append(">");
+ assertTrue(sb.toString(), (a == null && b == null) || (a != null && a.equals(b)));
+ }
+
+ private static void assertFalse(String message, boolean flag) {
+ assertTrue(message, !flag);
+ }
+
+ private static void assertNotSame(String message, Object a, Object b) {
+ StringBuilder sb = new StringBuilder(message != null ? message : "");
+ if (sb.length() > 0) {
+ sb.append(" ");
+ }
+ sb.append("unexpected sameness, found:<").append(a).append("> and:<").append(b).append(">");
+ assertTrue(sb.toString(), a != b);
+ }
+}
+
+class StaticFields {
+ public static int abc;
+}
+
+class StaticFieldsInitSub extends StaticFieldsInit {
+ final public static int def = 10;
+}
+
+class StaticFieldsInit {
+ final public static int abc = 10;
+}
+
+class StaticInternString {
+ final public static String intent = "java.abc.Action";
+ static public String getIntent() {
+ return intent;
+ }
+}
+
+class BootInternedString {
+ final public static String boot = "double";
+}
+
+class StaticInternString2 {
+ final public static String intent = "java.abc.Action";
+
+ static String getIntent() {
+ return intent;
+ }
+}
+
+class NonOptimizedClass {}
diff --git a/test/596-app-images/src-ex/Secondary.java b/test/596-app-images/src-ex/Secondary.java
new file mode 100644
index 0000000..36eee88
--- /dev/null
+++ b/test/596-app-images/src-ex/Secondary.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2020 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 Secondary {
+ public static void go() {
+ System.out.println("Secondary went");
+ }
+}
diff --git a/test/596-app-images/src/Main.java b/test/596-app-images/src/Main.java
deleted file mode 100644
index 88d95f4..0000000
--- a/test/596-app-images/src/Main.java
+++ /dev/null
@@ -1,155 +0,0 @@
-/*
- * Copyright 2016 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.Field;
-import java.lang.reflect.Constructor;
-import java.lang.reflect.Method;
-
-class Main {
- static class Inner {
- final public static int abc = 10;
- }
-
- static class Nested {
-
- }
-
- public static void main(String[] args) {
- System.loadLibrary(args[0]);
- if (!checkAppImageLoaded()) {
- System.out.println("App image is not loaded!");
- } else if (!checkAppImageContains(Inner.class)) {
- System.out.println("App image does not contain Inner!");
- }
-
- if (!checkInitialized(Inner.class))
- System.out.println("Inner class is not initialized!");
-
- if (!checkInitialized(Nested.class))
- System.out.println("Nested class is not initialized!");
-
- if (!checkInitialized(StaticFields.class))
- System.out.println("StaticFields class is not initialized!");
-
- if (!checkInitialized(StaticFieldsInitSub.class))
- System.out.println("StaticFieldsInitSub class is not initialized!");
-
- if (!checkInitialized(StaticFieldsInit.class))
- System.out.println("StaticFieldsInit class is not initialized!");
-
- if (!checkInitialized(StaticInternString.class))
- System.out.println("StaticInternString class is not initialized!");
-
- StringBuffer sb = new StringBuffer();
- sb.append("java.");
- sb.append("abc.");
- sb.append("Action");
-
- String tmp = sb.toString();
- String intern = tmp.intern();
-
- assertNotEqual(tmp, intern, "Dynamically constructed String, not interned.");
- assertEqual(intern, StaticInternString.intent, "Static encoded literal String not interned.");
- assertEqual(BootInternedString.boot, BootInternedString.boot.intern(),
- "Static encoded literal String not moved back to runtime intern table.");
-
- try {
- Field f = StaticInternString.class.getDeclaredField("intent");
- assertEqual(intern, f.get(null), "String Literals are not interned properly.");
-
- } catch (Exception e) {
- System.out.println("Exception");
- }
-
- assertEqual(StaticInternString.getIntent(), StaticInternString2.getIntent(),
- "String Literals are not intenred properly, App image static strings duplicated.");
-
- // reload the class StaticInternString, check whether static strings interned properly
- final String DEX_FILE = System.getenv("DEX_LOCATION") + "/596-app-images.jar";
- final String LIBRARY_SEARCH_PATH = System.getProperty("java.library.path");
-
- try {
- Class<?> pathClassLoader = Class.forName("dalvik.system.PathClassLoader");
- if (pathClassLoader == null) {
- throw new AssertionError("Counldn't find path class loader class");
- }
- Constructor<?> ctor =
- pathClassLoader.getDeclaredConstructor(String.class, String.class, ClassLoader.class);
- ClassLoader loader = (ClassLoader) ctor.newInstance(
- DEX_FILE, LIBRARY_SEARCH_PATH, null);
-
- Class<?> staticInternString = loader.loadClass("StaticInternString");
-
- if (!checkAppImageContains(staticInternString)) {
- System.out.println("Not loaded again.");
- }
- Method getIntent = staticInternString.getDeclaredMethod("getIntent");
-
- assertEqual(StaticInternString.getIntent(), getIntent.invoke(staticInternString),
- "Dynamically loaded app image's literal strings not interned properly.");
- } catch (Exception e) {
- e.printStackTrace(System.out);
- }
-
- }
-
- public static native boolean checkAppImageLoaded();
- public static native boolean checkAppImageContains(Class<?> klass);
- public static native boolean checkInitialized(Class<?> klass);
-
- public static void assertEqual(Object a, Object b, String msg) {
- if (a != b)
- System.out.println(msg);
- }
-
- public static void assertNotEqual(Object a, Object b, String msg) {
- if (a == b)
- System.out.println(msg);
- }
-
-}
-
-class StaticFields{
- public static int abc;
-}
-
-class StaticFieldsInitSub extends StaticFieldsInit {
- final public static int def = 10;
-}
-
-class StaticFieldsInit{
- final public static int abc = 10;
-}
-
-class StaticInternString {
- final public static String intent = "java.abc.Action";
- static public String getIntent() {
- return intent;
- }
-}
-
-class BootInternedString {
- final public static String boot = "double";
-}
-
-class StaticInternString2 {
- final public static String intent = "java.abc.Action";
-
- static String getIntent() {
- return intent;
- }
-}
-
diff --git a/test/597-app-images-same-classloader/expected.txt b/test/597-app-images-same-classloader/expected.txt
new file mode 100644
index 0000000..ff3be57
--- /dev/null
+++ b/test/597-app-images-same-classloader/expected.txt
@@ -0,0 +1,2 @@
+JNI_OnLoad called
+Secondary went
diff --git a/test/597-app-images-same-classloader/info.txt b/test/597-app-images-same-classloader/info.txt
new file mode 100644
index 0000000..38f6e70
--- /dev/null
+++ b/test/597-app-images-same-classloader/info.txt
@@ -0,0 +1,2 @@
+Tests that loading an app image into an already existent classloader works if
+the classloader context is correct.
diff --git a/test/597-app-images-same-classloader/profile b/test/597-app-images-same-classloader/profile
new file mode 100644
index 0000000..c7406e2
--- /dev/null
+++ b/test/597-app-images-same-classloader/profile
@@ -0,0 +1,2 @@
+LMain;
+LSecondary;
diff --git a/test/597-app-images-same-classloader/run b/test/597-app-images-same-classloader/run
new file mode 100644
index 0000000..496273f
--- /dev/null
+++ b/test/597-app-images-same-classloader/run
@@ -0,0 +1,18 @@
+#!/bin/bash
+#
+# Copyright (C) 2020 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.
+
+# We need a profile to tell dex2oat to include classes in the final app image
+exec ${RUN} --profile --secondary-class-loader-context "PCL[$DEX_LOCATION/$TEST_NAME.jar]" $@
diff --git a/test/597-app-images-same-classloader/src-art/Main.java b/test/597-app-images-same-classloader/src-art/Main.java
new file mode 100644
index 0000000..96a902c
--- /dev/null
+++ b/test/597-app-images-same-classloader/src-art/Main.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2020 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 dalvik.system.PathClassLoader;
+
+class Main {
+ static final String TEST_NAME = "597-app-images-same-classloader";
+
+ static final String DEX_FILE = System.getenv("DEX_LOCATION") + "/" + TEST_NAME + ".jar";
+ static final String LIBRARY_SEARCH_PATH = System.getProperty("java.library.path");
+
+ static final String SECONDARY_NAME = TEST_NAME + "-ex";
+ static final String SECONDARY_DEX_FILE =
+ System.getenv("DEX_LOCATION") + "/" + SECONDARY_NAME + ".jar";
+
+ public static void main(String[] args) throws Exception {
+ System.loadLibrary(args[0]);
+
+ testLoadingSecondaryAppImageInLoadedClassLoader();
+ }
+
+ public static native boolean checkAppImageLoaded(String name);
+ public static native boolean checkAppImageContains(Class<?> klass);
+ public static native boolean checkInitialized(Class<?> klass);
+
+ public static void testLoadingSecondaryAppImageInLoadedClassLoader() throws Exception {
+ // Sanity check that the image isn't already loaded so we don't get bogus results below
+ assertFalse("Secondary app image isn't already loaded",
+ checkAppImageLoaded(SECONDARY_NAME));
+
+ PathClassLoader pcl = new PathClassLoader(DEX_FILE, LIBRARY_SEARCH_PATH, null);
+ pcl.addDexPath(SECONDARY_DEX_FILE);
+
+ assertTrue("Ensure app image is loaded if it should be",
+ checkAppImageLoaded(SECONDARY_NAME));
+
+ Class<?> secondaryCls = pcl.loadClass("Secondary");
+ assertTrue("Ensure Secondary class is in the app image",
+ checkAppImageContains(secondaryCls));
+ assertTrue("Ensure Secondary class is preinitialized", checkInitialized(secondaryCls));
+
+ secondaryCls.getDeclaredMethod("go").invoke(null);
+ }
+
+ private static void assertTrue(String message, boolean flag) {
+ if (flag) {
+ return;
+ }
+ throw new AssertionError(message);
+ }
+
+ private static void assertFalse(String message, boolean flag) {
+ assertTrue(message, !flag);
+ }
+}
diff --git a/test/597-app-images-same-classloader/src-ex/Secondary.java b/test/597-app-images-same-classloader/src-ex/Secondary.java
new file mode 100644
index 0000000..36eee88
--- /dev/null
+++ b/test/597-app-images-same-classloader/src-ex/Secondary.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2020 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 Secondary {
+ public static void go() {
+ System.out.println("Secondary went");
+ }
+}
diff --git a/test/660-clinit/src/Main.java b/test/660-clinit/src/Main.java
index 5fb5fe5..0d6837e 100644
--- a/test/660-clinit/src/Main.java
+++ b/test/660-clinit/src/Main.java
@@ -21,7 +21,7 @@
public static void main(String[] args) throws Exception {
System.loadLibrary(args[0]);
- if (!checkAppImageLoaded()) {
+ if (!checkAppImageLoaded("660-clinit")) {
System.out.println("AppImage not loaded.");
}
if (!checkAppImageContains(ClInit.class)) {
@@ -90,7 +90,7 @@
}
}
- public static native boolean checkAppImageLoaded();
+ public static native boolean checkAppImageLoaded(String name);
public static native boolean checkAppImageContains(Class<?> klass);
public static native boolean checkInitialized(Class<?> klass);
}
diff --git a/test/674-hiddenapi/run b/test/674-hiddenapi/run
index 2babeef..b57d10a 100755
--- a/test/674-hiddenapi/run
+++ b/test/674-hiddenapi/run
@@ -16,4 +16,7 @@
# Make verification soft fail so that we can re-verify boot classpath
# methods at runtime.
-exec ${RUN} $@ --verify-soft-fail
\ No newline at end of file
+#
+# N.B. Compilation of secondary dexes can prevent hidden API checks, e.g. if
+# a blacklisted field get is inlined.
+exec ${RUN} $@ --verify-soft-fail --no-secondary-compilation
diff --git a/test/719-dm-verify-redefinition/run b/test/719-dm-verify-redefinition/run
index f4e9d71..26e10e1 100644
--- a/test/719-dm-verify-redefinition/run
+++ b/test/719-dm-verify-redefinition/run
@@ -23,4 +23,5 @@
--dm \
--vdex-arg \
--class-loader-context=PCL[$DEX_LOCATION/719-dm-verify-redefinition-ex.jar] \
+ --no-secondary-compilation \
"${@}"
diff --git a/test/etc/run-test-jar b/test/etc/run-test-jar
index 3701220..2a8a7d4 100755
--- a/test/etc/run-test-jar
+++ b/test/etc/run-test-jar
@@ -85,6 +85,9 @@
TEST_DM="n"
TEST_IS_NDEBUG="n"
APP_IMAGE="y"
+SECONDARY_APP_IMAGE="y"
+SECONDARY_CLASS_LOADER_CONTEXT=""
+SECONDARY_COMPILATION="y"
JVMTI_STRESS="n"
JVMTI_STEP_STRESS="n"
JVMTI_FIELD_STRESS="n"
@@ -131,6 +134,8 @@
elif [ "x$1" = "x--jvmti" ]; then
USE_JVMTI="y"
IS_JVMTI_TEST="y"
+ # Secondary images block some tested behavior.
+ SECONDARY_APP_IMAGE="n"
shift
elif [ "x$1" = "x--add-libdir-argument" ]; then
ADD_LIBDIR_ARGUMENTS="y"
@@ -216,6 +221,7 @@
# APP_IMAGE doesn't really work with jvmti redefine stress
USE_JVMTI="y"
APP_IMAGE="n"
+ SECONDARY_APP_IMAGE="n"
JVMTI_STRESS="y"
JVMTI_REDEFINE_STRESS="y"
shift
@@ -237,6 +243,16 @@
elif [ "x$1" = "x--no-app-image" ]; then
APP_IMAGE="n"
shift
+ elif [ "x$1" = "x--no-secondary-app-image" ]; then
+ SECONDARY_APP_IMAGE="n"
+ shift
+ elif [ "x$1" = "x--secondary-class-loader-context" ]; then
+ shift
+ SECONDARY_CLASS_LOADER_CONTEXT="$1"
+ shift
+ elif [ "x$1" = "x--no-secondary-compilation" ]; then
+ SECONDARY_COMPILATION="n"
+ shift
elif [ "x$1" = "x--strip-dex" ]; then
STRIP_DEX="y"
shift
@@ -898,7 +914,7 @@
profman_cmdline="$ANDROID_ART_BIN_DIR/profman \
--apk=$DEX_LOCATION/$TEST_NAME.jar \
--dex-location=$DEX_LOCATION/$TEST_NAME.jar"
- if [ -f $DEX_LOCATION/$TEST_NAME-ex.jar ]; then
+ if [ -f "$TEST_NAME-ex.jar" ] && [ "$SECONDARY_COMPILATION" = "y" ] ; then
profman_cmdline="${profman_cmdline} \
--apk=$DEX_LOCATION/$TEST_NAME-ex.jar \
--dex-location=$DEX_LOCATION/$TEST_NAME-ex.jar"
@@ -914,16 +930,27 @@
fi
fi
-# Enable mini-debug-info for JIT (if JIT is used).
-FLAGS="$FLAGS -Xcompiler-option --generate-mini-debug-info"
+function write_dex2oat_cmdlines {
+ local name="$1"
-if [ "$PREBUILD" = "y" ]; then
- mkdir_locations="${mkdir_locations} ${DEX_LOCATION}/oat/$ISA"
+ local class_loader_context=""
+ local enable_app_image=false
if [ "$APP_IMAGE" = "y" ]; then
- # Pick a base that will force the app image to get relocated.
- app_image="--app-image-file=$DEX_LOCATION/oat/$ISA/$TEST_NAME.art --resolve-startup-const-strings=true"
+ enable_app_image=true
fi
+ # If the name ends in -ex then this is a secondary dex file
+ if [ "${name:${#name}-3}" = "-ex" ]; then
+ # Lazily realize the default value in case DEX_LOCATION/TEST_NAME change
+ [ -z "$SECONDARY_CLASS_LOADER_CONTEXT" ] && SECONDARY_CLASS_LOADER_CONTEXT="PCL[];PCL[$DEX_LOCATION/$TEST_NAME.jar]"
+ class_loader_context="'--class-loader-context=$SECONDARY_CLASS_LOADER_CONTEXT'"
+ $enable_app_image && [ "$SECONDARY_APP_IMAGE" = "y" ] || enable_app_image=false
+ fi
+
+ local app_image=""
+ $enable_app_image && app_image="--app-image-file=$DEX_LOCATION/oat/$ISA/$name.art --resolve-startup-const-strings=true"
+
+ local dex2oat_binary
dex2oat_binary=${DEX2OAT_DEBUG_BINARY}
if [[ "$TEST_IS_NDEBUG" = "y" ]]; then
dex2oat_binary=${DEX2OAT_NDEBUG_BINARY}
@@ -931,11 +958,12 @@
dex2oat_cmdline="$INVOKE_WITH $ANDROID_ART_BIN_DIR/$dex2oat_binary \
$COMPILE_FLAGS \
--boot-image=${BOOT_IMAGE} \
- --dex-file=$DEX_LOCATION/$TEST_NAME.jar \
- --oat-file=$DEX_LOCATION/oat/$ISA/$TEST_NAME.odex \
- ${app_image} \
+ --dex-file=$DEX_LOCATION/$name.jar \
+ --oat-file=$DEX_LOCATION/oat/$ISA/$name.odex \
+ "$app_image" \
--generate-mini-debug-info \
- --instruction-set=$ISA"
+ --instruction-set=$ISA \
+ $class_loader_context"
if [ "x$INSTRUCTION_SET_FEATURES" != "x" ] ; then
dex2oat_cmdline="${dex2oat_cmdline} --instruction-set-features=${INSTRUCTION_SET_FEATURES}"
fi
@@ -952,15 +980,48 @@
dex2oat_cmdline="timeout -k ${DEX2OAT_TIMEOUT}s -s SIGRTMIN+2 ${DEX2OAT_RT_TIMEOUT}s ${dex2oat_cmdline} --watchdog-timeout=${DEX2OAT_TIMEOUT}000"
fi
if [ "$PROFILE" = "y" ] || [ "$RANDOM_PROFILE" = "y" ]; then
- vdex_cmdline="${dex2oat_cmdline} ${VDEX_ARGS} --input-vdex=$DEX_LOCATION/oat/$ISA/$TEST_NAME.vdex --output-vdex=$DEX_LOCATION/oat/$ISA/$TEST_NAME.vdex"
+ vdex_cmdline="${dex2oat_cmdline} ${VDEX_ARGS} --input-vdex=$DEX_LOCATION/oat/$ISA/$name.vdex --output-vdex=$DEX_LOCATION/oat/$ISA/$name.vdex"
elif [ "$TEST_VDEX" = "y" ]; then
- vdex_cmdline="${dex2oat_cmdline} ${VDEX_ARGS} --input-vdex=$DEX_LOCATION/oat/$ISA/$TEST_NAME.vdex"
+ vdex_cmdline="${dex2oat_cmdline} ${VDEX_ARGS} --input-vdex=$DEX_LOCATION/oat/$ISA/$name.vdex"
elif [ "$TEST_DM" = "y" ]; then
dex2oat_cmdline="${dex2oat_cmdline} --output-vdex=$DEX_LOCATION/oat/$ISA/primary.vdex"
- dm_cmdline="zip -qj $DEX_LOCATION/oat/$ISA/$TEST_NAME.dm $DEX_LOCATION/oat/$ISA/primary.vdex"
- vdex_cmdline="${dex2oat_cmdline} ${VDEX_ARGS} --dump-timings --dm-file=$DEX_LOCATION/oat/$ISA/$TEST_NAME.dm"
- elif [ "$PROFILE" = "y" ] || [ "$RANDOM_PROFILE" = "y" ]; then
- vdex_cmdline="${dex2oat_cmdline} --input-vdex=$DEX_LOCATION/oat/$ISA/$TEST_NAME.vdex --output-vdex=$DEX_LOCATION/oat/$ISA/$TEST_NAME.vdex"
+ dm_cmdline="zip -qj $DEX_LOCATION/oat/$ISA/$name.dm $DEX_LOCATION/oat/$ISA/primary.vdex"
+ vdex_cmdline="${dex2oat_cmdline} ${VDEX_ARGS} --dump-timings --dm-file=$DEX_LOCATION/oat/$ISA/$name.dm"
+ fi
+}
+
+# Enable mini-debug-info for JIT (if JIT is used).
+FLAGS="$FLAGS -Xcompiler-option --generate-mini-debug-info"
+
+if [ "$PREBUILD" = "y" ]; then
+ mkdir_locations="${mkdir_locations} ${DEX_LOCATION}/oat/$ISA"
+
+ # "Primary".
+ write_dex2oat_cmdlines "$TEST_NAME"
+ dex2oat_cmdline=$(echo $dex2oat_cmdline)
+ dm_cmdline=$(echo $dm_cmdline)
+ vdex_cmdline=$(echo $vdex_cmdline)
+
+ # Enable mini-debug-info for JIT (if JIT is used).
+ FLAGS="$FLAGS -Xcompiler-option --generate-mini-debug-info"
+
+ if [ -f "$TEST_NAME-ex.jar" ] && [ "$SECONDARY_COMPILATION" = "y" ] ; then
+ # "Secondary" for test coverage.
+
+ # Store primary values.
+ base_dex2oat_cmdline="$dex2oat_cmdline"
+ base_dm_cmdline="$dm_cmdline"
+ base_vdex_cmdline="$vdex_cmdline"
+
+ write_dex2oat_cmdlines "$TEST_NAME-ex"
+ dex2oat_cmdline=$(echo $dex2oat_cmdline)
+ dm_cmdline=$(echo $dm_cmdline)
+ vdex_cmdline=$(echo $vdex_cmdline)
+
+ # Concatenate.
+ dex2oat_cmdline="$base_dex2oat_cmdline && $dex2oat_cmdline"
+ dm_cmdline="$base_dm_cmdline" # Only use primary dm.
+ vdex_cmdline="$base_vdex_cmdline && $vdex_cmdline"
fi
fi
@@ -1009,11 +1070,22 @@
-XX:DumpNativeStackOnSigQuit:false \
-cp $DEX_LOCATION/$TEST_NAME.jar$SECONDARY_DEX $MAIN $ARGS"
+sanitize_dex2oat_cmdline() {
+ local args=()
+ for arg in "$@"; do
+ if [ "$arg" = "--class-loader-context=&" ]; then
+ arg="--class-loader-context=\&"
+ fi
+ args+=("$arg")
+ done
+ echo -n "${args[@]}"
+}
+
# Remove whitespace.
-dex2oat_cmdline=$(echo $dex2oat_cmdline)
+dex2oat_cmdline=$(sanitize_dex2oat_cmdline $(echo $dex2oat_cmdline))
dalvikvm_cmdline=$(echo $dalvikvm_cmdline)
dm_cmdline=$(echo $dm_cmdline)
-vdex_cmdline=$(echo $vdex_cmdline)
+vdex_cmdline=$(sanitize_dex2oat_cmdline $(echo $vdex_cmdline))
profman_cmdline=$(echo $profman_cmdline)
# Use an empty ASAN_OPTIONS to enable defaults.
@@ -1274,9 +1346,9 @@
$linkroot_cmdline || { echo "create symlink android-root failed." >&2 ; exit 2; }
$linkroot_overlay_cmdline || { echo "overlay android-root failed." >&2 ; exit 2; }
$profman_cmdline || { echo "Profman failed." >&2 ; exit 2; }
- $dex2oat_cmdline || { echo "Dex2oat failed." >&2 ; exit 2; }
- $dm_cmdline || { echo "Dex2oat failed." >&2 ; exit 2; }
- $vdex_cmdline || { echo "Dex2oat failed." >&2 ; exit 2; }
+ eval "$dex2oat_cmdline" || { echo "Dex2oat failed." >&2 ; exit 2; }
+ eval "$dm_cmdline" || { echo "Dex2oat failed." >&2 ; exit 2; }
+ eval "$vdex_cmdline" || { echo "Dex2oat failed." >&2 ; exit 2; }
$strip_cmdline || { echo "Strip failed." >&2 ; exit 3; }
$sync_cmdline || { echo "Sync failed." >&2 ; exit 4; }
diff --git a/test/knownfailures.json b/test/knownfailures.json
index 9dc5f26..4501779 100644
--- a/test/knownfailures.json
+++ b/test/knownfailures.json
@@ -304,8 +304,23 @@
},
{
"tests": "596-app-images",
- "description": "Code being tested has been disabled",
- "bug": "b/70734839"
+ "description": "app images do not initialize classes when debuggable",
+ "variant": "debuggable"
+ },
+ {
+ "tests": "596-app-images",
+ "description": "not generated when using the access check configuration",
+ "variant": "interp-ac"
+ },
+ {
+ "tests": "597-app-images-same-classloader",
+ "description": "not generated when using the access check configuration",
+ "variant": "interp-ac"
+ },
+ {
+ "tests": ["596-app-images", "597-app-images-same-classloader"],
+ "description": "jvmti does not interact well with images",
+ "variant": "field-stress | jvmti-stress | redefine-stress | step-stress | trace-stress"
},
{
"tests": "055-enum-performance",