TouchDex.java revision 72e93344b4d1ffc71e9c832ec23de0657e5b04a5
1/*
2 * Copyright (C) 2007 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
17package dalvik.system;
18
19import java.io.BufferedReader;
20import java.io.InputStreamReader;
21import java.io.IOException;
22import java.io.File;
23import java.io.FilenameFilter;
24
25/**
26 * Induces optimization/verification of a set of DEX files.
27 *
28 * @deprecated this is an internal Dalvik class that is not appropriate for
29 *      general use. It will be removed from the public API in a future release.
30 */
31public class TouchDex {
32
33    /**
34     * Forks a process, makes sure the DEX files are prepared, and returns
35     * when everything is finished.
36     * <p>
37     * The filenames must be the same as will be used when the files are
38     * actually opened, because the dalvik-cache filename is based upon
39     * this filename.  (The absolute path to the JAR/ZIP/APK should work.)
40     *
41     * @param dexFiles a colon-separated list of DEX files.
42     * @return zero on success
43     *
44     * @cts What about error cases?
45     */
46    public static int start(String dexFiles) {
47        return trampoline(dexFiles, System.getProperty("java.boot.class.path"));
48    }
49
50    /**
51     * This calls fork() and then, in the child, calls cont(dexFiles).
52     *
53     * @param dexFiles Colon-separated list of DEX files.
54     * @return zero on success
55     */
56    native private static int trampoline(String dexFiles, String bcp);
57
58    /**
59     * The entry point for the child process. args[0] can be a colon-separated
60     * path list, or "-" to read from stdin.
61     * <p>
62     * Alternatively, if we're invoked directly from the command line we
63     * just start here (skipping the fork/exec stuff).
64     *
65     * @param args command line args
66     */
67    public static void main(String[] args) {
68
69        if ("-".equals(args[0])) {
70            BufferedReader in = new BufferedReader(
71                    new InputStreamReader(System.in), 256);
72
73            String line;
74            try {
75                while ((line = in.readLine()) != null) {
76                    prepFiles(line);
77                }
78            } catch (IOException ex) {
79                throw new RuntimeException ("Error processing stdin");
80            }
81        } else {
82            prepFiles(args[0]);
83        }
84
85        System.out.println(" Prep complete");
86    }
87
88
89    private static String expandDirectories(String dexPath) {
90        String[] parts = dexPath.split(":");
91        StringBuilder outPath = new StringBuilder(dexPath.length());
92
93        // A filename filter accepting *.jar and *.apk
94        FilenameFilter filter = new FilenameFilter() {
95            public boolean accept(File dir, String name) {
96                return name.endsWith(".jar") || name.endsWith(".apk");
97            }
98        };
99
100        for (String part: parts) {
101            File f = new File(part);
102
103            if (f.isFile()) {
104                outPath.append(part);
105                outPath.append(':');
106            } else if (f.isDirectory()) {
107                String[] filenames = f.list(filter);
108
109                if (filenames == null) {
110                    System.err.println("I/O error with directory: " + part);
111                    continue;
112                }
113
114                for (String filename: filenames) {
115                    outPath.append(part);
116                    outPath.append(File.separatorChar);
117                    outPath.append(filename);
118                    outPath.append(':');
119                }
120            } else {
121                System.err.println("File not found: " + part);
122            }
123        }
124
125
126        return outPath.toString();
127    }
128
129    private static void prepFiles(String dexPath) {
130
131        System.out.println(" Prepping: " + dexPath);
132
133        TouchDexLoader loader
134                = new TouchDexLoader(expandDirectories(dexPath), null);
135
136        try {
137            /* By looking for a nonexistent class, we'll trick TouchDexLoader
138             * into trying to load something from every file on dexPath,
139             * optimizing all of them as a side-effect.
140             *
141             * The optimization happens implicitly in the VM the first time
142             * someone tries to load a class from an unoptimized dex file.
143             */
144            loader.loadClass("com.google.NonexistentClassNeverFound");
145            throw new RuntimeException("nonexistent class loaded?!");
146        } catch (ClassNotFoundException cnfe) {
147            //System.out.println("got expected dnfe");
148        }
149    }
150}
151
152