/* * 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.InputStreamReader; import java.io.IOException; import java.io.File; import java.io.FilenameFilter; /** * Induces optimization/verification of a set of DEX files. * * @deprecated this is an internal Dalvik class that is not appropriate for * general use. It will be removed from the public API in a future release. */ 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"); } } }