Home | History | Annotate | Download | only in preload
      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 = 1250;
     36 
     37     /**
     38      * Preload any class that was loaded by at least MIN_PROCESSES processes.
     39      */
     40     static final int MIN_PROCESSES = 10;
     41 
     42     public static void main(String[] args) throws IOException,
     43             ClassNotFoundException {
     44         if (args.length != 1) {
     45             System.err.println("Usage: WritePreloadedClassFile [compiled log]");
     46             System.exit(-1);
     47         }
     48         String rootFile = args[0];
     49         Root root = Root.fromFile(rootFile);
     50 
     51         // No classes are preloaded to start.
     52         for (LoadedClass loadedClass : root.loadedClasses.values()) {
     53             loadedClass.preloaded = false;
     54         }
     55 
     56         // Open preloaded-classes file for output.
     57         Writer out = new BufferedWriter(new OutputStreamWriter(
     58                 new FileOutputStream(Policy.PRELOADED_CLASS_FILE),
     59                 Charset.forName("US-ASCII")));
     60 
     61         out.write("# Classes which are preloaded by"
     62                 + " com.android.internal.os.ZygoteInit.\n");
     63         out.write("# Automatically generated by frameworks/base/tools/preload/"
     64             + WritePreloadedClassFile.class.getSimpleName() + ".java.\n");
     65         out.write("# MIN_LOAD_TIME_MICROS=" + MIN_LOAD_TIME_MICROS + "\n");
     66         out.write("# MIN_PROCESSES=" + MIN_PROCESSES + "\n");
     67 
     68         /*
     69          * The set of classes to preload. We preload a class if:
     70          *
     71          *  a) it's loaded in the bootclasspath (i.e., is a system class)
     72          *  b) it takes > MIN_LOAD_TIME_MICROS us to load, and
     73          *  c) it's loaded by more than one process, or it's loaded by an
     74          *     application (i.e., not a long running service)
     75          */
     76         Set<LoadedClass> toPreload = new TreeSet<LoadedClass>();
     77 
     78         // Preload classes that were loaded by at least 2 processes. Hopefully,
     79         // the memory associated with these classes will be shared.
     80         for (LoadedClass loadedClass : root.loadedClasses.values()) {
     81             Set<String> names = loadedClass.processNames();
     82             if (!Policy.isPreloadable(loadedClass)) {
     83                 continue;
     84             }
     85 
     86             if (names.size() >= MIN_PROCESSES ||
     87                     (loadedClass.medianTimeMicros() > MIN_LOAD_TIME_MICROS && names.size() > 1)) {
     88                 toPreload.add(loadedClass);
     89             }
     90         }
     91 
     92         int initialSize = toPreload.size();
     93         System.out.println(initialSize
     94                 + " classses were loaded by more than one app.");
     95 
     96         // Preload eligable classes from applications (not long-running
     97         // services).
     98         for (Proc proc : root.processes.values()) {
     99             if (proc.fromZygote() && !Policy.isService(proc.name)) {
    100                 for (Operation operation : proc.operations) {
    101                     LoadedClass loadedClass = operation.loadedClass;
    102                     if (shouldPreload(loadedClass)) {
    103                         toPreload.add(loadedClass);
    104                     }
    105                 }
    106             }
    107         }
    108 
    109         System.out.println("Added " + (toPreload.size() - initialSize)
    110                 + " more to speed up applications.");
    111 
    112         System.out.println(toPreload.size()
    113                 + " total classes will be preloaded.");
    114 
    115         // Make classes that were implicitly loaded by the zygote explicit.
    116         // This adds minimal overhead but avoid confusion about classes not
    117         // appearing in the list.
    118         addAllClassesFrom("zygote", root, toPreload);
    119 
    120         for (LoadedClass loadedClass : toPreload) {
    121             out.write(loadedClass.name + "\n");
    122         }
    123 
    124         out.close();
    125 
    126         // Update data to reflect LoadedClass.preloaded changes.
    127         for (LoadedClass loadedClass : toPreload) {
    128             loadedClass.preloaded = true;
    129         }
    130         root.toFile(rootFile);
    131     }
    132 
    133     private static void addAllClassesFrom(String processName, Root root,
    134             Set<LoadedClass> toPreload) {
    135         for (Proc proc : root.processes.values()) {
    136             if (proc.name.equals(processName)) {
    137                 for (Operation operation : proc.operations) {
    138                     boolean preloadable
    139                             = Policy.isPreloadable(operation.loadedClass);
    140                     if (preloadable) {
    141                         toPreload.add(operation.loadedClass);
    142                     }
    143                 }
    144             }
    145         }
    146     }
    147 
    148     /**
    149      * Returns true if the class should be preloaded.
    150      */
    151     private static boolean shouldPreload(LoadedClass clazz) {
    152         return Policy.isPreloadable(clazz)
    153                 && clazz.medianTimeMicros() > MIN_LOAD_TIME_MICROS;
    154     }
    155 }
    156