diff options
| author | 2020-03-11 23:06:42 +0000 | |
|---|---|---|
| committer | 2020-03-12 19:52:16 +0000 | |
| commit | 038a1987c9d3beffb43aa2a21b902edb42aa1e74 (patch) | |
| tree | 643e60d5d1227b0199b9f49ce2ab409bf0cfa607 | |
| parent | ee2571618ec960659e1326b540dcd41610f9a277 (diff) | |
"Revert^6 "[art] Enable compilation of secondary dexes by default i..."
This reverts commit c1ff0ff1e3f64a991119b3f86db3dc9e76f3a4e4.
Reason for revert: Blacklist another configuration.
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-app-images -t 597-app-images-same-classloader
Test: art/test/testrunner/testrunner.py -b --host --no-image -t 596-app-images -t 597-app-images-same-classloader
Test: art/test/testrunner/testrunner.py -b --target -t 596-app-images -t 597-app-images-same-classloader
Change-Id: Ibccc0030ae068f3ab6b50126a2d5c3b41806de12
21 files changed, 536 insertions, 187 deletions
diff --git a/test/130-hprof/run b/test/130-hprof/run new file mode 100644 index 0000000000..73a984e082 --- /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 b32f0bcc46..35d0209af8 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 @@ public class Main { // 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 0000000000..73a984e082 --- /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 498ea1d606..1bc2c1ef35 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 art { 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 6a5618ebc6..ff3be57faf 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 0000000000..2a3172c2cf --- /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 0000000000..dbdcd1cc3d --- /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 0000000000..8bc2f3f5c0 --- /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 0000000000..36eee8867c --- /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 88d95f4162..0000000000 --- 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 0000000000..ff3be57faf --- /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 0000000000..38f6e707ac --- /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 0000000000..c7406e217e --- /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 0000000000..496273fed9 --- /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 0000000000..96a902c96e --- /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 0000000000..36eee8867c --- /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 5fb5fe5ee0..0d6837e5ae 100644 --- a/test/660-clinit/src/Main.java +++ b/test/660-clinit/src/Main.java @@ -21,7 +21,7 @@ public class Main { 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 class Main { } } - 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 2babeefbe5..b57d10a905 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 f4e9d7124c..26e10e1151 100644 --- a/test/719-dm-verify-redefinition/run +++ b/test/719-dm-verify-redefinition/run @@ -23,4 +23,5 @@ exec ${RUN} \ --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 3701220e5a..2a8a7d4bd5 100755 --- a/test/etc/run-test-jar +++ b/test/etc/run-test-jar @@ -85,6 +85,9 @@ TEST_VDEX="n" 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 @@ while true; do 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 @@ while true; do # 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 @@ while true; do 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 @@ if [ "$PROFILE" = "y" ] || [ "$RANDOM_PROFILE" = "y" ]; then 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 @@ if [ "$PROFILE" = "y" ] || [ "$RANDOM_PROFILE" = "y" ]; then 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 @@ if [ "$PREBUILD" = "y" ]; then 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 @@ if [ "$PREBUILD" = "y" ]; then 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 @@ dalvikvm_cmdline="$INVOKE_WITH $GDB $ANDROID_ART_BIN_DIR/$DALVIKVM \ -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 @@ else $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 9dc5f26e80..3eecf7a1af 100644 --- a/test/knownfailures.json +++ b/test/knownfailures.json @@ -303,9 +303,24 @@ "variant": "optimizing & ndebuggable | regalloc_gc & ndebuggable | speed-profile & ndebuggable | jit & ndebuggable | jit-on-first-use & ndebuggable" }, { + "tests": ["596-app-images", "597-app-images-same-classloader"], + "description": "no image generated in configuration", + "variant": "no-image" + }, + { + "tests": ["596-app-images", "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": "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": "055-enum-performance", |