1*d57664e9SAndroid Build Coastguard Worker /* 2*d57664e9SAndroid Build Coastguard Worker * Copyright (C) 2008 The Android Open Source Project 3*d57664e9SAndroid Build Coastguard Worker * 4*d57664e9SAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License"); 5*d57664e9SAndroid Build Coastguard Worker * you may not use this file except in compliance with the License. 6*d57664e9SAndroid Build Coastguard Worker * You may obtain a copy of the License at 7*d57664e9SAndroid Build Coastguard Worker * 8*d57664e9SAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0 9*d57664e9SAndroid Build Coastguard Worker * 10*d57664e9SAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software 11*d57664e9SAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS, 12*d57664e9SAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13*d57664e9SAndroid Build Coastguard Worker * See the License for the specific language governing permissions and 14*d57664e9SAndroid Build Coastguard Worker * limitations under the License. 15*d57664e9SAndroid Build Coastguard Worker */ 16*d57664e9SAndroid Build Coastguard Worker 17*d57664e9SAndroid Build Coastguard Worker import java.io.BufferedWriter; 18*d57664e9SAndroid Build Coastguard Worker import java.io.FileOutputStream; 19*d57664e9SAndroid Build Coastguard Worker import java.io.IOException; 20*d57664e9SAndroid Build Coastguard Worker import java.io.OutputStreamWriter; 21*d57664e9SAndroid Build Coastguard Worker import java.io.Writer; 22*d57664e9SAndroid Build Coastguard Worker import java.nio.charset.Charset; 23*d57664e9SAndroid Build Coastguard Worker import java.util.Set; 24*d57664e9SAndroid Build Coastguard Worker import java.util.TreeSet; 25*d57664e9SAndroid Build Coastguard Worker 26*d57664e9SAndroid Build Coastguard Worker /** 27*d57664e9SAndroid Build Coastguard Worker * Writes /frameworks/base/preloaded-classes. Also updates 28*d57664e9SAndroid Build Coastguard Worker * {@link LoadedClass#preloaded} fields and writes over compiled log file. 29*d57664e9SAndroid Build Coastguard Worker */ 30*d57664e9SAndroid Build Coastguard Worker public class WritePreloadedClassFile { 31*d57664e9SAndroid Build Coastguard Worker 32*d57664e9SAndroid Build Coastguard Worker /** 33*d57664e9SAndroid Build Coastguard Worker * Preload any class that take longer to load than MIN_LOAD_TIME_MICROS us. 34*d57664e9SAndroid Build Coastguard Worker */ 35*d57664e9SAndroid Build Coastguard Worker static final int MIN_LOAD_TIME_MICROS = 1250; 36*d57664e9SAndroid Build Coastguard Worker 37*d57664e9SAndroid Build Coastguard Worker /** 38*d57664e9SAndroid Build Coastguard Worker * Preload any class that was loaded by at least MIN_PROCESSES processes. 39*d57664e9SAndroid Build Coastguard Worker */ 40*d57664e9SAndroid Build Coastguard Worker static final int MIN_PROCESSES = 10; 41*d57664e9SAndroid Build Coastguard Worker main(String[] args)42*d57664e9SAndroid Build Coastguard Worker public static void main(String[] args) throws IOException, 43*d57664e9SAndroid Build Coastguard Worker ClassNotFoundException { 44*d57664e9SAndroid Build Coastguard Worker if (args.length != 1) { 45*d57664e9SAndroid Build Coastguard Worker System.err.println("Usage: WritePreloadedClassFile [compiled log]"); 46*d57664e9SAndroid Build Coastguard Worker System.exit(-1); 47*d57664e9SAndroid Build Coastguard Worker } 48*d57664e9SAndroid Build Coastguard Worker String rootFile = args[0]; 49*d57664e9SAndroid Build Coastguard Worker Root root = Root.fromFile(rootFile); 50*d57664e9SAndroid Build Coastguard Worker 51*d57664e9SAndroid Build Coastguard Worker // No classes are preloaded to start. 52*d57664e9SAndroid Build Coastguard Worker for (LoadedClass loadedClass : root.loadedClasses.values()) { 53*d57664e9SAndroid Build Coastguard Worker loadedClass.preloaded = false; 54*d57664e9SAndroid Build Coastguard Worker } 55*d57664e9SAndroid Build Coastguard Worker 56*d57664e9SAndroid Build Coastguard Worker // Open preloaded-classes file for output. 57*d57664e9SAndroid Build Coastguard Worker Writer out = new BufferedWriter(new OutputStreamWriter( 58*d57664e9SAndroid Build Coastguard Worker new FileOutputStream(Policy.PRELOADED_CLASS_FILE), 59*d57664e9SAndroid Build Coastguard Worker Charset.forName("US-ASCII"))); 60*d57664e9SAndroid Build Coastguard Worker 61*d57664e9SAndroid Build Coastguard Worker out.write("# Classes which are preloaded by" 62*d57664e9SAndroid Build Coastguard Worker + " com.android.internal.os.ZygoteInit.\n"); 63*d57664e9SAndroid Build Coastguard Worker out.write("# Automatically generated by frameworks/base/tools/preload/" 64*d57664e9SAndroid Build Coastguard Worker + WritePreloadedClassFile.class.getSimpleName() + ".java.\n"); 65*d57664e9SAndroid Build Coastguard Worker out.write("# MIN_LOAD_TIME_MICROS=" + MIN_LOAD_TIME_MICROS + "\n"); 66*d57664e9SAndroid Build Coastguard Worker out.write("# MIN_PROCESSES=" + MIN_PROCESSES + "\n"); 67*d57664e9SAndroid Build Coastguard Worker 68*d57664e9SAndroid Build Coastguard Worker /* 69*d57664e9SAndroid Build Coastguard Worker * The set of classes to preload. We preload a class if: 70*d57664e9SAndroid Build Coastguard Worker * 71*d57664e9SAndroid Build Coastguard Worker * a) it's loaded in the bootclasspath (i.e., is a system class) 72*d57664e9SAndroid Build Coastguard Worker * b) it takes > MIN_LOAD_TIME_MICROS us to load, and 73*d57664e9SAndroid Build Coastguard Worker * c) it's loaded by more than one process, or it's loaded by an 74*d57664e9SAndroid Build Coastguard Worker * application (i.e., not a long running service) 75*d57664e9SAndroid Build Coastguard Worker */ 76*d57664e9SAndroid Build Coastguard Worker Set<LoadedClass> toPreload = new TreeSet<LoadedClass>(); 77*d57664e9SAndroid Build Coastguard Worker 78*d57664e9SAndroid Build Coastguard Worker // Preload classes that were loaded by at least 2 processes. Hopefully, 79*d57664e9SAndroid Build Coastguard Worker // the memory associated with these classes will be shared. 80*d57664e9SAndroid Build Coastguard Worker for (LoadedClass loadedClass : root.loadedClasses.values()) { 81*d57664e9SAndroid Build Coastguard Worker Set<String> names = loadedClass.processNames(); 82*d57664e9SAndroid Build Coastguard Worker if (!Policy.isPreloadable(loadedClass)) { 83*d57664e9SAndroid Build Coastguard Worker continue; 84*d57664e9SAndroid Build Coastguard Worker } 85*d57664e9SAndroid Build Coastguard Worker 86*d57664e9SAndroid Build Coastguard Worker if (names.size() >= MIN_PROCESSES || 87*d57664e9SAndroid Build Coastguard Worker (loadedClass.medianTimeMicros() > MIN_LOAD_TIME_MICROS && names.size() > 1)) { 88*d57664e9SAndroid Build Coastguard Worker toPreload.add(loadedClass); 89*d57664e9SAndroid Build Coastguard Worker } 90*d57664e9SAndroid Build Coastguard Worker } 91*d57664e9SAndroid Build Coastguard Worker 92*d57664e9SAndroid Build Coastguard Worker int initialSize = toPreload.size(); 93*d57664e9SAndroid Build Coastguard Worker System.out.println(initialSize 94*d57664e9SAndroid Build Coastguard Worker + " classses were loaded by more than one app."); 95*d57664e9SAndroid Build Coastguard Worker 96*d57664e9SAndroid Build Coastguard Worker // Preload eligable classes from applications (not long-running 97*d57664e9SAndroid Build Coastguard Worker // services). 98*d57664e9SAndroid Build Coastguard Worker for (Proc proc : root.processes.values()) { 99*d57664e9SAndroid Build Coastguard Worker if (proc.fromZygote() && !Policy.isService(proc.name)) { 100*d57664e9SAndroid Build Coastguard Worker for (Operation operation : proc.operations) { 101*d57664e9SAndroid Build Coastguard Worker LoadedClass loadedClass = operation.loadedClass; 102*d57664e9SAndroid Build Coastguard Worker if (shouldPreload(loadedClass)) { 103*d57664e9SAndroid Build Coastguard Worker toPreload.add(loadedClass); 104*d57664e9SAndroid Build Coastguard Worker } 105*d57664e9SAndroid Build Coastguard Worker } 106*d57664e9SAndroid Build Coastguard Worker } 107*d57664e9SAndroid Build Coastguard Worker } 108*d57664e9SAndroid Build Coastguard Worker 109*d57664e9SAndroid Build Coastguard Worker System.out.println("Added " + (toPreload.size() - initialSize) 110*d57664e9SAndroid Build Coastguard Worker + " more to speed up applications."); 111*d57664e9SAndroid Build Coastguard Worker 112*d57664e9SAndroid Build Coastguard Worker System.out.println(toPreload.size() 113*d57664e9SAndroid Build Coastguard Worker + " total classes will be preloaded."); 114*d57664e9SAndroid Build Coastguard Worker 115*d57664e9SAndroid Build Coastguard Worker // Make classes that were implicitly loaded by the zygote explicit. 116*d57664e9SAndroid Build Coastguard Worker // This adds minimal overhead but avoid confusion about classes not 117*d57664e9SAndroid Build Coastguard Worker // appearing in the list. 118*d57664e9SAndroid Build Coastguard Worker addAllClassesFrom("zygote", root, toPreload); 119*d57664e9SAndroid Build Coastguard Worker 120*d57664e9SAndroid Build Coastguard Worker for (LoadedClass loadedClass : toPreload) { 121*d57664e9SAndroid Build Coastguard Worker out.write(loadedClass.name + "\n"); 122*d57664e9SAndroid Build Coastguard Worker } 123*d57664e9SAndroid Build Coastguard Worker 124*d57664e9SAndroid Build Coastguard Worker out.close(); 125*d57664e9SAndroid Build Coastguard Worker 126*d57664e9SAndroid Build Coastguard Worker // Update data to reflect LoadedClass.preloaded changes. 127*d57664e9SAndroid Build Coastguard Worker for (LoadedClass loadedClass : toPreload) { 128*d57664e9SAndroid Build Coastguard Worker loadedClass.preloaded = true; 129*d57664e9SAndroid Build Coastguard Worker } 130*d57664e9SAndroid Build Coastguard Worker root.toFile(rootFile); 131*d57664e9SAndroid Build Coastguard Worker } 132*d57664e9SAndroid Build Coastguard Worker addAllClassesFrom(String processName, Root root, Set<LoadedClass> toPreload)133*d57664e9SAndroid Build Coastguard Worker private static void addAllClassesFrom(String processName, Root root, 134*d57664e9SAndroid Build Coastguard Worker Set<LoadedClass> toPreload) { 135*d57664e9SAndroid Build Coastguard Worker for (Proc proc : root.processes.values()) { 136*d57664e9SAndroid Build Coastguard Worker if (proc.name.equals(processName)) { 137*d57664e9SAndroid Build Coastguard Worker for (Operation operation : proc.operations) { 138*d57664e9SAndroid Build Coastguard Worker boolean preloadable 139*d57664e9SAndroid Build Coastguard Worker = Policy.isPreloadable(operation.loadedClass); 140*d57664e9SAndroid Build Coastguard Worker if (preloadable) { 141*d57664e9SAndroid Build Coastguard Worker toPreload.add(operation.loadedClass); 142*d57664e9SAndroid Build Coastguard Worker } 143*d57664e9SAndroid Build Coastguard Worker } 144*d57664e9SAndroid Build Coastguard Worker } 145*d57664e9SAndroid Build Coastguard Worker } 146*d57664e9SAndroid Build Coastguard Worker } 147*d57664e9SAndroid Build Coastguard Worker 148*d57664e9SAndroid Build Coastguard Worker /** 149*d57664e9SAndroid Build Coastguard Worker * Returns true if the class should be preloaded. 150*d57664e9SAndroid Build Coastguard Worker */ shouldPreload(LoadedClass clazz)151*d57664e9SAndroid Build Coastguard Worker private static boolean shouldPreload(LoadedClass clazz) { 152*d57664e9SAndroid Build Coastguard Worker return Policy.isPreloadable(clazz) 153*d57664e9SAndroid Build Coastguard Worker && clazz.medianTimeMicros() > MIN_LOAD_TIME_MICROS; 154*d57664e9SAndroid Build Coastguard Worker } 155*d57664e9SAndroid Build Coastguard Worker } 156