1282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/* 2282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Copyright (C) 2008 The Android Open Source Project 3282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * 4282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Licensed under the Apache License, Version 2.0 (the "License"); 5282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * you may not use this file except in compliance with the License. 6282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * You may obtain a copy of the License at 7282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * 8282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * http://www.apache.org/licenses/LICENSE-2.0 9282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * 10282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Unless required by applicable law or agreed to in writing, software 11282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * distributed under the License is distributed on an "AS IS" BASIS, 12282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * See the License for the specific language governing permissions and 14282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * limitations under the License. 15282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */ 16282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 17282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport java.io.BufferedWriter; 18282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport java.io.FileOutputStream; 19282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport java.io.IOException; 20282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport java.io.OutputStreamWriter; 21282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport java.io.Writer; 22282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport java.nio.charset.Charset; 23282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport java.util.Set; 24282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport java.util.TreeSet; 25282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 26282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/** 27282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Writes /frameworks/base/preloaded-classes. Also updates 28282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * {@link LoadedClass#preloaded} fields and writes over compiled log file. 29282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */ 30282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskipublic class WritePreloadedClassFile { 31282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 32282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski /** 33282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Preload any class that take longer to load than MIN_LOAD_TIME_MICROS us. 34282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */ 35282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski static final int MIN_LOAD_TIME_MICROS = 1250; 36282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 37282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski /** 38282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Preload any class that was loaded by at least MIN_PROCESSES processes. 39282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */ 40282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski static final int MIN_PROCESSES = 10; 41282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 42282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski public static void main(String[] args) throws IOException, 43282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski ClassNotFoundException { 44282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if (args.length != 1) { 45282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski System.err.println("Usage: WritePreloadedClassFile [compiled log]"); 46282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski System.exit(-1); 47282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 48282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski String rootFile = args[0]; 49282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski Root root = Root.fromFile(rootFile); 50282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 51282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski // No classes are preloaded to start. 52282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski for (LoadedClass loadedClass : root.loadedClasses.values()) { 53282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski loadedClass.preloaded = false; 54282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 55282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 56282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski // Open preloaded-classes file for output. 57282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski Writer out = new BufferedWriter(new OutputStreamWriter( 58282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski new FileOutputStream(Policy.PRELOADED_CLASS_FILE), 59282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski Charset.forName("US-ASCII"))); 60282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 61282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski out.write("# Classes which are preloaded by" 62282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski + " com.android.internal.os.ZygoteInit.\n"); 63282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski out.write("# Automatically generated by frameworks/base/tools/preload/" 64282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski + WritePreloadedClassFile.class.getSimpleName() + ".java.\n"); 65282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski out.write("# MIN_LOAD_TIME_MICROS=" + MIN_LOAD_TIME_MICROS + "\n"); 66282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski out.write("# MIN_PROCESSES=" + MIN_PROCESSES + "\n"); 67282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 68282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski /* 69282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * The set of classes to preload. We preload a class if: 70282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * 71282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * a) it's loaded in the bootclasspath (i.e., is a system class) 72282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * b) it takes > MIN_LOAD_TIME_MICROS us to load, and 73282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * c) it's loaded by more than one process, or it's loaded by an 74282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * application (i.e., not a long running service) 75282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */ 76282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski Set<LoadedClass> toPreload = new TreeSet<LoadedClass>(); 77282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 78282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski // Preload classes that were loaded by at least 2 processes. Hopefully, 79282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski // the memory associated with these classes will be shared. 80282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski for (LoadedClass loadedClass : root.loadedClasses.values()) { 81282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski Set<String> names = loadedClass.processNames(); 82282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if (!Policy.isPreloadable(loadedClass)) { 83282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski continue; 84282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 85282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 86282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if (names.size() >= MIN_PROCESSES || 87282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski (loadedClass.medianTimeMicros() > MIN_LOAD_TIME_MICROS && names.size() > 1)) { 88282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski toPreload.add(loadedClass); 89282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 90282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 91282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 92282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski int initialSize = toPreload.size(); 93282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski System.out.println(initialSize 94282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski + " classses were loaded by more than one app."); 95282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 96282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski // Preload eligable classes from applications (not long-running 97282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski // services). 98282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski for (Proc proc : root.processes.values()) { 99282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if (proc.fromZygote() && !Policy.isService(proc.name)) { 100282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski for (Operation operation : proc.operations) { 101282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski LoadedClass loadedClass = operation.loadedClass; 102282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if (shouldPreload(loadedClass)) { 103282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski toPreload.add(loadedClass); 104282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 105282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 106282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 107282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 108282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 109282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski System.out.println("Added " + (toPreload.size() - initialSize) 110282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski + " more to speed up applications."); 111282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 112282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski System.out.println(toPreload.size() 113282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski + " total classes will be preloaded."); 114282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 115282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski // Make classes that were implicitly loaded by the zygote explicit. 116282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski // This adds minimal overhead but avoid confusion about classes not 117282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski // appearing in the list. 118282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski addAllClassesFrom("zygote", root, toPreload); 119282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 120282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski for (LoadedClass loadedClass : toPreload) { 121282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski out.write(loadedClass.name + "\n"); 122282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 123282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 124282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski out.close(); 125282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 126282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski // Update data to reflect LoadedClass.preloaded changes. 127282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski for (LoadedClass loadedClass : toPreload) { 128282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski loadedClass.preloaded = true; 129282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 130282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski root.toFile(rootFile); 131282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 132282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 133282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski private static void addAllClassesFrom(String processName, Root root, 134282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski Set<LoadedClass> toPreload) { 135282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski for (Proc proc : root.processes.values()) { 136282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if (proc.name.equals(processName)) { 137282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski for (Operation operation : proc.operations) { 138282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski boolean preloadable 139282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski = Policy.isPreloadable(operation.loadedClass); 140282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if (preloadable) { 141282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski toPreload.add(operation.loadedClass); 142282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 143282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 144282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 145282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 146282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 147282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 148282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski /** 149282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Returns true if the class should be preloaded. 150282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */ 151282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski private static boolean shouldPreload(LoadedClass clazz) { 152282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski return Policy.isPreloadable(clazz) 153282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski && clazz.medianTimeMicros() > MIN_LOAD_TIME_MICROS; 154282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 155282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski} 156