Unlike previous releases where the set of classes-to-be-preloaded was generated on a first-generation device (G1 and MyTouch 3G), this round I used a second-generation device, a Nexus One. As a consequence, class loading is faster (win) and fewer classes hit the 1250ms threshold. Instead of sharing classes based on load time alone, classes are now shared based on the number of applications loading them. Change-Id: I18f7aa3e7e6258818871b3968b515c06314371b3 http://b/2546002
156 lines
5.6 KiB
Java
156 lines
5.6 KiB
Java
/*
|
|
* Copyright (C) 2008 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
import java.io.BufferedWriter;
|
|
import java.io.FileOutputStream;
|
|
import java.io.IOException;
|
|
import java.io.OutputStreamWriter;
|
|
import java.io.Writer;
|
|
import java.nio.charset.Charset;
|
|
import java.util.Set;
|
|
import java.util.TreeSet;
|
|
|
|
/**
|
|
* Writes /frameworks/base/preloaded-classes. Also updates
|
|
* {@link LoadedClass#preloaded} fields and writes over compiled log file.
|
|
*/
|
|
public class WritePreloadedClassFile {
|
|
|
|
/**
|
|
* Preload any class that take longer to load than MIN_LOAD_TIME_MICROS us.
|
|
*/
|
|
static final int MIN_LOAD_TIME_MICROS = 1250;
|
|
|
|
/**
|
|
* Preload any class that was loaded by at least MIN_PROCESSES processes.
|
|
*/
|
|
static final int MIN_PROCESSES = 10;
|
|
|
|
public static void main(String[] args) throws IOException,
|
|
ClassNotFoundException {
|
|
if (args.length != 1) {
|
|
System.err.println("Usage: WritePreloadedClassFile [compiled log]");
|
|
System.exit(-1);
|
|
}
|
|
String rootFile = args[0];
|
|
Root root = Root.fromFile(rootFile);
|
|
|
|
// No classes are preloaded to start.
|
|
for (LoadedClass loadedClass : root.loadedClasses.values()) {
|
|
loadedClass.preloaded = false;
|
|
}
|
|
|
|
// Open preloaded-classes file for output.
|
|
Writer out = new BufferedWriter(new OutputStreamWriter(
|
|
new FileOutputStream(Policy.PRELOADED_CLASS_FILE),
|
|
Charset.forName("US-ASCII")));
|
|
|
|
out.write("# Classes which are preloaded by"
|
|
+ " com.android.internal.os.ZygoteInit.\n");
|
|
out.write("# Automatically generated by frameworks/base/tools/preload/"
|
|
+ WritePreloadedClassFile.class.getSimpleName() + ".java.\n");
|
|
out.write("# MIN_LOAD_TIME_MICROS=" + MIN_LOAD_TIME_MICROS + "\n");
|
|
out.write("# MIN_PROCESSES=" + MIN_PROCESSES + "\n");
|
|
|
|
/*
|
|
* The set of classes to preload. We preload a class if:
|
|
*
|
|
* a) it's loaded in the bootclasspath (i.e., is a system class)
|
|
* b) it takes > MIN_LOAD_TIME_MICROS us to load, and
|
|
* c) it's loaded by more than one process, or it's loaded by an
|
|
* application (i.e., not a long running service)
|
|
*/
|
|
Set<LoadedClass> toPreload = new TreeSet<LoadedClass>();
|
|
|
|
// Preload classes that were loaded by at least 2 processes. Hopefully,
|
|
// the memory associated with these classes will be shared.
|
|
for (LoadedClass loadedClass : root.loadedClasses.values()) {
|
|
Set<String> names = loadedClass.processNames();
|
|
if (!Policy.isPreloadable(loadedClass)) {
|
|
continue;
|
|
}
|
|
|
|
if (names.size() >= MIN_PROCESSES ||
|
|
(loadedClass.medianTimeMicros() > MIN_LOAD_TIME_MICROS && names.size() > 1)) {
|
|
toPreload.add(loadedClass);
|
|
}
|
|
}
|
|
|
|
int initialSize = toPreload.size();
|
|
System.out.println(initialSize
|
|
+ " classses were loaded by more than one app.");
|
|
|
|
// Preload eligable classes from applications (not long-running
|
|
// services).
|
|
for (Proc proc : root.processes.values()) {
|
|
if (proc.fromZygote() && !Policy.isService(proc.name)) {
|
|
for (Operation operation : proc.operations) {
|
|
LoadedClass loadedClass = operation.loadedClass;
|
|
if (shouldPreload(loadedClass)) {
|
|
toPreload.add(loadedClass);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
System.out.println("Added " + (toPreload.size() - initialSize)
|
|
+ " more to speed up applications.");
|
|
|
|
System.out.println(toPreload.size()
|
|
+ " total classes will be preloaded.");
|
|
|
|
// Make classes that were implicitly loaded by the zygote explicit.
|
|
// This adds minimal overhead but avoid confusion about classes not
|
|
// appearing in the list.
|
|
addAllClassesFrom("zygote", root, toPreload);
|
|
|
|
for (LoadedClass loadedClass : toPreload) {
|
|
out.write(loadedClass.name + "\n");
|
|
}
|
|
|
|
out.close();
|
|
|
|
// Update data to reflect LoadedClass.preloaded changes.
|
|
for (LoadedClass loadedClass : toPreload) {
|
|
loadedClass.preloaded = true;
|
|
}
|
|
root.toFile(rootFile);
|
|
}
|
|
|
|
private static void addAllClassesFrom(String processName, Root root,
|
|
Set<LoadedClass> toPreload) {
|
|
for (Proc proc : root.processes.values()) {
|
|
if (proc.name.equals(processName)) {
|
|
for (Operation operation : proc.operations) {
|
|
boolean preloadable
|
|
= Policy.isPreloadable(operation.loadedClass);
|
|
if (preloadable) {
|
|
toPreload.add(operation.loadedClass);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns true if the class should be preloaded.
|
|
*/
|
|
private static boolean shouldPreload(LoadedClass clazz) {
|
|
return Policy.isPreloadable(clazz)
|
|
&& clazz.medianTimeMicros() > MIN_LOAD_TIME_MICROS;
|
|
}
|
|
}
|