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