blob: 0952e30f191fff30bc4d40eaeaa5b9ada9365a14 [file] [log] [blame]
/*
* Copyright (C) 2007 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.
*/
package dalvik.system;
import java.io.BufferedReader;
import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStreamReader;
/**
* Induces optimization/verification of a set of DEX files.
*
* @hide
*/
public class TouchDex {
/**
* Forks a process, makes sure the DEX files are prepared, and returns
* when everything is finished.
* <p>
* The filenames must be the same as will be used when the files are
* actually opened, because the dalvik-cache filename is based upon
* this filename. (The absolute path to the JAR/ZIP/APK should work.)
*
* @param dexFiles a colon-separated list of DEX files.
* @return zero on success
*
* @cts What about error cases?
*/
public static int start(String dexFiles) {
return trampoline(dexFiles, System.getProperty("java.boot.class.path"));
}
/**
* This calls fork() and then, in the child, calls cont(dexFiles).
*
* @param dexFiles Colon-separated list of DEX files.
* @return zero on success
*/
native private static int trampoline(String dexFiles, String bcp);
/**
* The entry point for the child process. args[0] can be a colon-separated
* path list, or "-" to read from stdin.
* <p>
* Alternatively, if we're invoked directly from the command line we
* just start here (skipping the fork/exec stuff).
*
* @param args command line args
*/
public static void main(String[] args) {
if ("-".equals(args[0])) {
BufferedReader in = new BufferedReader(
new InputStreamReader(System.in), 256);
String line;
try {
while ((line = in.readLine()) != null) {
prepFiles(line);
}
} catch (IOException ex) {
throw new RuntimeException ("Error processing stdin");
}
} else {
prepFiles(args[0]);
}
System.out.println(" Prep complete");
}
private static String expandDirectories(String dexPath) {
String[] parts = dexPath.split(":");
StringBuilder outPath = new StringBuilder(dexPath.length());
// A filename filter accepting *.jar and *.apk
FilenameFilter filter = new FilenameFilter() {
public boolean accept(File dir, String name) {
return name.endsWith(".jar") || name.endsWith(".apk");
}
};
for (String part: parts) {
File f = new File(part);
if (f.isFile()) {
outPath.append(part);
outPath.append(':');
} else if (f.isDirectory()) {
String[] filenames = f.list(filter);
if (filenames == null) {
System.err.println("I/O error with directory: " + part);
continue;
}
for (String filename: filenames) {
outPath.append(part);
outPath.append(File.separatorChar);
outPath.append(filename);
outPath.append(':');
}
} else {
System.err.println("File not found: " + part);
}
}
return outPath.toString();
}
private static void prepFiles(String dexPath) {
System.out.println(" Prepping: " + dexPath);
TouchDexLoader loader
= new TouchDexLoader(expandDirectories(dexPath), null);
try {
/* By looking for a nonexistent class, we'll trick TouchDexLoader
* into trying to load something from every file on dexPath,
* optimizing all of them as a side-effect.
*
* The optimization happens implicitly in the VM the first time
* someone tries to load a class from an unoptimized dex file.
*/
loader.loadClass("com.google.NonexistentClassNeverFound");
throw new RuntimeException("nonexistent class loaded?!");
} catch (ClassNotFoundException cnfe) {
//System.out.println("got expected dnfe");
}
}
}