xref: /aosp_15_r20/art/test/596-app-images/src-art/Main.java (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
1*795d594fSAndroid Build Coastguard Worker /*
2*795d594fSAndroid Build Coastguard Worker  * Copyright 2020 The Android Open Source Project
3*795d594fSAndroid Build Coastguard Worker  *
4*795d594fSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*795d594fSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*795d594fSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*795d594fSAndroid Build Coastguard Worker  *
8*795d594fSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*795d594fSAndroid Build Coastguard Worker  *
10*795d594fSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*795d594fSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*795d594fSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*795d594fSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*795d594fSAndroid Build Coastguard Worker  * limitations under the License.
15*795d594fSAndroid Build Coastguard Worker  */
16*795d594fSAndroid Build Coastguard Worker 
17*795d594fSAndroid Build Coastguard Worker import dalvik.system.PathClassLoader;
18*795d594fSAndroid Build Coastguard Worker import java.lang.reflect.Field;
19*795d594fSAndroid Build Coastguard Worker import java.lang.reflect.Constructor;
20*795d594fSAndroid Build Coastguard Worker import java.lang.reflect.Method;
21*795d594fSAndroid Build Coastguard Worker 
22*795d594fSAndroid Build Coastguard Worker class Main {
23*795d594fSAndroid Build Coastguard Worker   static final String DEX_FILE = System.getenv("DEX_LOCATION") + "/596-app-images.jar";
24*795d594fSAndroid Build Coastguard Worker   static final String SECONDARY_DEX_FILE =
25*795d594fSAndroid Build Coastguard Worker     System.getenv("DEX_LOCATION") + "/596-app-images-ex.jar";
26*795d594fSAndroid Build Coastguard Worker   static final String LIBRARY_SEARCH_PATH = System.getProperty("java.library.path");
27*795d594fSAndroid Build Coastguard Worker 
28*795d594fSAndroid Build Coastguard Worker   static class Inner {
29*795d594fSAndroid Build Coastguard Worker     final public static int abc = 10;
30*795d594fSAndroid Build Coastguard Worker   }
31*795d594fSAndroid Build Coastguard Worker 
32*795d594fSAndroid Build Coastguard Worker   static class Nested {
33*795d594fSAndroid Build Coastguard Worker 
34*795d594fSAndroid Build Coastguard Worker   }
35*795d594fSAndroid Build Coastguard Worker 
main(String[] args)36*795d594fSAndroid Build Coastguard Worker   public static void main(String[] args) throws Exception {
37*795d594fSAndroid Build Coastguard Worker     System.loadLibrary(args[0]);
38*795d594fSAndroid Build Coastguard Worker 
39*795d594fSAndroid Build Coastguard Worker     testAppImageLoaded();
40*795d594fSAndroid Build Coastguard Worker     testInitializedClasses();
41*795d594fSAndroid Build Coastguard Worker     testInternedStrings();
42*795d594fSAndroid Build Coastguard Worker     testReloadInternedString();
43*795d594fSAndroid Build Coastguard Worker     testClassesOutsideAppImage();
44*795d594fSAndroid Build Coastguard Worker     testLoadingSecondaryAppImage();
45*795d594fSAndroid Build Coastguard Worker   }
46*795d594fSAndroid Build Coastguard Worker 
checkAppImageLoaded(String name)47*795d594fSAndroid Build Coastguard Worker   public static native boolean checkAppImageLoaded(String name);
checkAppImageContains(Class<?> klass)48*795d594fSAndroid Build Coastguard Worker   public static native boolean checkAppImageContains(Class<?> klass);
checkInitialized(Class<?> klass)49*795d594fSAndroid Build Coastguard Worker   public static native boolean checkInitialized(Class<?> klass);
50*795d594fSAndroid Build Coastguard Worker 
testAppImageLoaded()51*795d594fSAndroid Build Coastguard Worker   public static void testAppImageLoaded() throws Exception {
52*795d594fSAndroid Build Coastguard Worker     assertTrue("App image is loaded", checkAppImageLoaded("596-app-images"));
53*795d594fSAndroid Build Coastguard Worker     assertTrue("App image contains Inner", checkAppImageContains(Inner.class));
54*795d594fSAndroid Build Coastguard Worker   }
55*795d594fSAndroid Build Coastguard Worker 
testInitializedClasses()56*795d594fSAndroid Build Coastguard Worker   public static void testInitializedClasses() throws Exception {
57*795d594fSAndroid Build Coastguard Worker     assertInitialized(Inner.class);
58*795d594fSAndroid Build Coastguard Worker     assertInitialized(Nested.class);
59*795d594fSAndroid Build Coastguard Worker     assertInitialized(StaticFields.class);
60*795d594fSAndroid Build Coastguard Worker     assertInitialized(StaticFieldsInitSub.class);
61*795d594fSAndroid Build Coastguard Worker     assertInitialized(StaticFieldsInit.class);
62*795d594fSAndroid Build Coastguard Worker     assertInitialized(StaticInternString.class);
63*795d594fSAndroid Build Coastguard Worker   }
64*795d594fSAndroid Build Coastguard Worker 
assertInitialized(Class<?> klass)65*795d594fSAndroid Build Coastguard Worker   private static void assertInitialized(Class<?> klass) {
66*795d594fSAndroid Build Coastguard Worker     assertTrue(klass.toString() + " is preinitialized", checkInitialized(klass));
67*795d594fSAndroid Build Coastguard Worker   }
68*795d594fSAndroid Build Coastguard Worker 
testInternedStrings()69*795d594fSAndroid Build Coastguard Worker   public static void testInternedStrings() throws Exception {
70*795d594fSAndroid Build Coastguard Worker     StringBuffer sb = new StringBuffer();
71*795d594fSAndroid Build Coastguard Worker     sb.append("java.");
72*795d594fSAndroid Build Coastguard Worker     sb.append("abc.");
73*795d594fSAndroid Build Coastguard Worker     sb.append("Action");
74*795d594fSAndroid Build Coastguard Worker 
75*795d594fSAndroid Build Coastguard Worker     String tmp = sb.toString();
76*795d594fSAndroid Build Coastguard Worker     String intern = tmp.intern();
77*795d594fSAndroid Build Coastguard Worker 
78*795d594fSAndroid Build Coastguard Worker     assertNotSame("Dynamically constructed string is not interned", tmp, intern);
79*795d594fSAndroid Build Coastguard Worker     assertEquals("Static string on initialized class is matches runtime interned string", intern,
80*795d594fSAndroid Build Coastguard Worker         StaticInternString.intent);
81*795d594fSAndroid Build Coastguard Worker     assertEquals("Static string on initialized class is pre-interned", BootInternedString.boot,
82*795d594fSAndroid Build Coastguard Worker         BootInternedString.boot.intern());
83*795d594fSAndroid Build Coastguard Worker 
84*795d594fSAndroid Build Coastguard Worker     // TODO: Does this next check really provide us anything?
85*795d594fSAndroid Build Coastguard Worker     Field f = StaticInternString.class.getDeclaredField("intent");
86*795d594fSAndroid Build Coastguard Worker     assertEquals("String literals are interned properly", intern, f.get(null));
87*795d594fSAndroid Build Coastguard Worker 
88*795d594fSAndroid Build Coastguard Worker     assertEquals("String literals are interned properly across classes",
89*795d594fSAndroid Build Coastguard Worker         StaticInternString.getIntent(), StaticInternString2.getIntent());
90*795d594fSAndroid Build Coastguard Worker   }
91*795d594fSAndroid Build Coastguard Worker 
testReloadInternedString()92*795d594fSAndroid Build Coastguard Worker   public static void testReloadInternedString() throws Exception {
93*795d594fSAndroid Build Coastguard Worker     // reload the class StaticInternString, check whether static strings interned properly
94*795d594fSAndroid Build Coastguard Worker     PathClassLoader loader = new PathClassLoader(DEX_FILE, LIBRARY_SEARCH_PATH, null);
95*795d594fSAndroid Build Coastguard Worker     Class<?> staticInternString = loader.loadClass("StaticInternString");
96*795d594fSAndroid Build Coastguard Worker     assertTrue("Class in app image isn't loaded a second time after loading dex file again",
97*795d594fSAndroid Build Coastguard Worker         checkAppImageContains(staticInternString));
98*795d594fSAndroid Build Coastguard Worker 
99*795d594fSAndroid Build Coastguard Worker     Method getIntent = staticInternString.getDeclaredMethod("getIntent");
100*795d594fSAndroid Build Coastguard Worker     assertEquals("Interned strings are still interned after multiple dex loads",
101*795d594fSAndroid Build Coastguard Worker         StaticInternString.getIntent(), getIntent.invoke(staticInternString));
102*795d594fSAndroid Build Coastguard Worker   }
103*795d594fSAndroid Build Coastguard Worker 
testClassesOutsideAppImage()104*795d594fSAndroid Build Coastguard Worker   public static void testClassesOutsideAppImage() {
105*795d594fSAndroid Build Coastguard Worker     assertFalse("App image doesn't contain non-optimized class",
106*795d594fSAndroid Build Coastguard Worker         checkAppImageContains(NonOptimizedClass.class));
107*795d594fSAndroid Build Coastguard Worker     assertFalse("App image didn't pre-initialize non-optimized class",
108*795d594fSAndroid Build Coastguard Worker         checkInitialized(NonOptimizedClass.class));
109*795d594fSAndroid Build Coastguard Worker   }
110*795d594fSAndroid Build Coastguard Worker 
testLoadingSecondaryAppImage()111*795d594fSAndroid Build Coastguard Worker   public static void testLoadingSecondaryAppImage() throws Exception {
112*795d594fSAndroid Build Coastguard Worker     final ClassLoader parent = Main.class.getClassLoader();
113*795d594fSAndroid Build Coastguard Worker 
114*795d594fSAndroid Build Coastguard Worker     // Initial check that the image isn't already loaded so we don't get bogus results below
115*795d594fSAndroid Build Coastguard Worker     assertFalse("Secondary app image isn't already loaded",
116*795d594fSAndroid Build Coastguard Worker         checkAppImageLoaded("596-app-images-ex"));
117*795d594fSAndroid Build Coastguard Worker 
118*795d594fSAndroid Build Coastguard Worker     PathClassLoader pcl = new PathClassLoader(SECONDARY_DEX_FILE, parent);
119*795d594fSAndroid Build Coastguard Worker 
120*795d594fSAndroid Build Coastguard Worker     assertTrue("Ensure app image is loaded if it should be",
121*795d594fSAndroid Build Coastguard Worker         checkAppImageLoaded("596-app-images-ex"));
122*795d594fSAndroid Build Coastguard Worker 
123*795d594fSAndroid Build Coastguard Worker     Class<?> secondaryCls = pcl.loadClass("Secondary");
124*795d594fSAndroid Build Coastguard Worker     assertTrue("Ensure Secondary class is in the app image if the CLC is correct",
125*795d594fSAndroid Build Coastguard Worker         checkAppImageContains(secondaryCls));
126*795d594fSAndroid Build Coastguard Worker     assertTrue("Ensure Secondary class is preinitialized if the CLC is correct",
127*795d594fSAndroid Build Coastguard Worker         checkInitialized(secondaryCls));
128*795d594fSAndroid Build Coastguard Worker 
129*795d594fSAndroid Build Coastguard Worker     secondaryCls.getDeclaredMethod("go").invoke(null);
130*795d594fSAndroid Build Coastguard Worker   }
131*795d594fSAndroid Build Coastguard Worker 
assertTrue(String message, boolean flag)132*795d594fSAndroid Build Coastguard Worker   private static void assertTrue(String message, boolean flag) {
133*795d594fSAndroid Build Coastguard Worker     if (flag) {
134*795d594fSAndroid Build Coastguard Worker       return;
135*795d594fSAndroid Build Coastguard Worker     }
136*795d594fSAndroid Build Coastguard Worker     throw new AssertionError(message);
137*795d594fSAndroid Build Coastguard Worker   }
138*795d594fSAndroid Build Coastguard Worker 
assertEquals(String message, Object a, Object b)139*795d594fSAndroid Build Coastguard Worker   private static void assertEquals(String message, Object a, Object b) {
140*795d594fSAndroid Build Coastguard Worker     StringBuilder sb = new StringBuilder(message != null ? message  : "");
141*795d594fSAndroid Build Coastguard Worker     if (sb.length() > 0) {
142*795d594fSAndroid Build Coastguard Worker       sb.append(" ");
143*795d594fSAndroid Build Coastguard Worker     }
144*795d594fSAndroid Build Coastguard Worker     sb.append("expected:<").append(a).append("> but was:<").append(b).append(">");
145*795d594fSAndroid Build Coastguard Worker     assertTrue(sb.toString(), (a == null && b == null) || (a != null && a.equals(b)));
146*795d594fSAndroid Build Coastguard Worker   }
147*795d594fSAndroid Build Coastguard Worker 
assertFalse(String message, boolean flag)148*795d594fSAndroid Build Coastguard Worker   private static void assertFalse(String message, boolean flag) {
149*795d594fSAndroid Build Coastguard Worker     assertTrue(message, !flag);
150*795d594fSAndroid Build Coastguard Worker   }
151*795d594fSAndroid Build Coastguard Worker 
assertNotSame(String message, Object a, Object b)152*795d594fSAndroid Build Coastguard Worker   private static void assertNotSame(String message, Object a, Object b) {
153*795d594fSAndroid Build Coastguard Worker     StringBuilder sb = new StringBuilder(message != null ? message  : "");
154*795d594fSAndroid Build Coastguard Worker     if (sb.length() > 0) {
155*795d594fSAndroid Build Coastguard Worker       sb.append(" ");
156*795d594fSAndroid Build Coastguard Worker     }
157*795d594fSAndroid Build Coastguard Worker     sb.append("unexpected sameness, found:<").append(a).append("> and:<").append(b).append(">");
158*795d594fSAndroid Build Coastguard Worker     assertTrue(sb.toString(), a != b);
159*795d594fSAndroid Build Coastguard Worker   }
160*795d594fSAndroid Build Coastguard Worker }
161*795d594fSAndroid Build Coastguard Worker 
162*795d594fSAndroid Build Coastguard Worker class StaticFields {
163*795d594fSAndroid Build Coastguard Worker   public static int abc;
164*795d594fSAndroid Build Coastguard Worker }
165*795d594fSAndroid Build Coastguard Worker 
166*795d594fSAndroid Build Coastguard Worker class StaticFieldsInitSub extends StaticFieldsInit {
167*795d594fSAndroid Build Coastguard Worker   final public static int def = 10;
168*795d594fSAndroid Build Coastguard Worker }
169*795d594fSAndroid Build Coastguard Worker 
170*795d594fSAndroid Build Coastguard Worker class StaticFieldsInit {
171*795d594fSAndroid Build Coastguard Worker   final public static int abc = 10;
172*795d594fSAndroid Build Coastguard Worker }
173*795d594fSAndroid Build Coastguard Worker 
174*795d594fSAndroid Build Coastguard Worker class StaticInternString {
175*795d594fSAndroid Build Coastguard Worker   final public static String intent = "java.abc.Action";
getIntent()176*795d594fSAndroid Build Coastguard Worker   static public String getIntent() {
177*795d594fSAndroid Build Coastguard Worker     return intent;
178*795d594fSAndroid Build Coastguard Worker   }
179*795d594fSAndroid Build Coastguard Worker }
180*795d594fSAndroid Build Coastguard Worker 
181*795d594fSAndroid Build Coastguard Worker class BootInternedString {
182*795d594fSAndroid Build Coastguard Worker   final public static String boot = "double";
183*795d594fSAndroid Build Coastguard Worker }
184*795d594fSAndroid Build Coastguard Worker 
185*795d594fSAndroid Build Coastguard Worker class StaticInternString2 {
186*795d594fSAndroid Build Coastguard Worker   final public static String intent = "java.abc.Action";
187*795d594fSAndroid Build Coastguard Worker 
getIntent()188*795d594fSAndroid Build Coastguard Worker   static String getIntent() {
189*795d594fSAndroid Build Coastguard Worker     return intent;
190*795d594fSAndroid Build Coastguard Worker   }
191*795d594fSAndroid Build Coastguard Worker }
192*795d594fSAndroid Build Coastguard Worker 
193*795d594fSAndroid Build Coastguard Worker class NonOptimizedClass {}
194