Main.java revision dc520adfdcf0f0e9190cdb90605c42a7cc8fa98f
1f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
2f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Copyright (C) 2007 The Android Open Source Project
3f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
4f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
5f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * you may not use this file except in compliance with the License.
6f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * You may obtain a copy of the License at
7f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
8f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
9f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
10f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
11f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
12f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * See the License for the specific language governing permissions and
14f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * limitations under the License.
15f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
16f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
17f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectpackage com.android.dx.command.dexer;
18f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
19f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.Version;
20d0900d13fb7bb1706aff5205af7e2d6517335beejeffhaoimport com.android.dx.cf.code.SimException;
21f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.cf.direct.ClassPathOpener;
22dc86cd9edc8b80953c8b698a83cdaebf6825d798Jesse Wilsonimport com.android.dx.cf.iface.ParseException;
23f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.command.DxConsole;
24f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.command.UsageException;
25dc86cd9edc8b80953c8b698a83cdaebf6825d798Jesse Wilsonimport com.android.dx.dex.DexFormat;
26f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.dex.cf.CfOptions;
27f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.dex.cf.CfTranslator;
28f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.dex.cf.CodeStatistics;
29f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.dex.code.PositionList;
30f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.dex.file.ClassDefItem;
31f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.dex.file.DexFile;
32f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.dex.file.EncodedMethod;
33dc86cd9edc8b80953c8b698a83cdaebf6825d798Jesse Wilsonimport com.android.dx.io.DexBuffer;
34dc86cd9edc8b80953c8b698a83cdaebf6825d798Jesse Wilsonimport com.android.dx.merge.DexMerger;
35f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.rop.annotation.Annotation;
36f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.rop.annotation.Annotations;
37f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.rop.annotation.AnnotationsList;
38f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.rop.cst.CstNat;
39f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.rop.cst.CstUtf8;
40dc86cd9edc8b80953c8b698a83cdaebf6825d798Jesse Wilsonimport com.android.dx.util.FileUtils;
41f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.io.ByteArrayInputStream;
42dc86cd9edc8b80953c8b698a83cdaebf6825d798Jesse Wilsonimport java.io.ByteArrayOutputStream;
43f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.io.File;
44dc86cd9edc8b80953c8b698a83cdaebf6825d798Jesse Wilsonimport java.io.FileInputStream;
45f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.io.FileOutputStream;
46f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.io.IOException;
47dc86cd9edc8b80953c8b698a83cdaebf6825d798Jesse Wilsonimport java.io.InputStream;
48f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.io.OutputStream;
49f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.io.OutputStreamWriter;
50f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.io.PrintWriter;
51f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.util.ArrayList;
52dc86cd9edc8b80953c8b698a83cdaebf6825d798Jesse Wilsonimport java.util.Arrays;
53f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.util.Map;
54f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.util.TreeMap;
55590f78fc4b6e3268149c5eacb7c8b7dd33497f44jeffhaoimport java.util.concurrent.ExecutorService;
56590f78fc4b6e3268149c5eacb7c8b7dd33497f44jeffhaoimport java.util.concurrent.Executors;
57590f78fc4b6e3268149c5eacb7c8b7dd33497f44jeffhaoimport java.util.concurrent.TimeUnit;
58f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.util.jar.Attributes;
59f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.util.jar.JarEntry;
60f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.util.jar.JarOutputStream;
61f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.util.jar.Manifest;
62dc86cd9edc8b80953c8b698a83cdaebf6825d798Jesse Wilsonimport java.util.zip.ZipFile;
63f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
64f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/**
65f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Main class for the class file translator.
66f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
67f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectpublic class Main {
68f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
6985dc40d2a0cb19792bf3ee6f6c57fed08eb91ea4Dan Bornstein     * {@code non-null;} the lengthy message that tries to discourage
7085dc40d2a0cb19792bf3ee6f6c57fed08eb91ea4Dan Bornstein     * people from defining core classes in applications
7185dc40d2a0cb19792bf3ee6f6c57fed08eb91ea4Dan Bornstein     */
7285dc40d2a0cb19792bf3ee6f6c57fed08eb91ea4Dan Bornstein    private static final String IN_RE_CORE_CLASSES =
7385dc40d2a0cb19792bf3ee6f6c57fed08eb91ea4Dan Bornstein        "Ill-advised or mistaken usage of a core class (java.* or javax.*)\n" +
7485dc40d2a0cb19792bf3ee6f6c57fed08eb91ea4Dan Bornstein        "when not building a core library.\n\n" +
7585dc40d2a0cb19792bf3ee6f6c57fed08eb91ea4Dan Bornstein        "This is often due to inadvertently including a core library file\n" +
7685dc40d2a0cb19792bf3ee6f6c57fed08eb91ea4Dan Bornstein        "in your application's project, when using an IDE (such as\n" +
7785dc40d2a0cb19792bf3ee6f6c57fed08eb91ea4Dan Bornstein        "Eclipse). If you are sure you're not intentionally defining a\n" +
7885dc40d2a0cb19792bf3ee6f6c57fed08eb91ea4Dan Bornstein        "core class, then this is the most likely explanation of what's\n" +
7985dc40d2a0cb19792bf3ee6f6c57fed08eb91ea4Dan Bornstein        "going on.\n\n" +
8085dc40d2a0cb19792bf3ee6f6c57fed08eb91ea4Dan Bornstein        "However, you might actually be trying to define a class in a core\n" +
8185dc40d2a0cb19792bf3ee6f6c57fed08eb91ea4Dan Bornstein        "namespace, the source of which you may have taken, for example,\n" +
8285dc40d2a0cb19792bf3ee6f6c57fed08eb91ea4Dan Bornstein        "from a non-Android virtual machine project. This will most\n" +
8385dc40d2a0cb19792bf3ee6f6c57fed08eb91ea4Dan Bornstein        "assuredly not work. At a minimum, it jeopardizes the\n" +
8485dc40d2a0cb19792bf3ee6f6c57fed08eb91ea4Dan Bornstein        "compatibility of your app with future versions of the platform.\n" +
8585dc40d2a0cb19792bf3ee6f6c57fed08eb91ea4Dan Bornstein        "It is also often of questionable legality.\n\n" +
8685dc40d2a0cb19792bf3ee6f6c57fed08eb91ea4Dan Bornstein        "If you really intend to build a core library -- which is only\n" +
8785dc40d2a0cb19792bf3ee6f6c57fed08eb91ea4Dan Bornstein        "appropriate as part of creating a full virtual machine\n" +
8885dc40d2a0cb19792bf3ee6f6c57fed08eb91ea4Dan Bornstein        "distribution, as opposed to compiling an application -- then use\n" +
8985dc40d2a0cb19792bf3ee6f6c57fed08eb91ea4Dan Bornstein        "the \"--core-library\" option to suppress this error message.\n\n" +
9085dc40d2a0cb19792bf3ee6f6c57fed08eb91ea4Dan Bornstein        "If you go ahead and use \"--core-library\" but are in fact\n" +
9185dc40d2a0cb19792bf3ee6f6c57fed08eb91ea4Dan Bornstein        "building an application, then be forewarned that your application\n" +
9285dc40d2a0cb19792bf3ee6f6c57fed08eb91ea4Dan Bornstein        "will still fail to build or run, at some point. Please be\n" +
9385dc40d2a0cb19792bf3ee6f6c57fed08eb91ea4Dan Bornstein        "prepared for angry customers who find, for example, that your\n" +
9485dc40d2a0cb19792bf3ee6f6c57fed08eb91ea4Dan Bornstein        "application ceases to function once they upgrade their operating\n" +
9585dc40d2a0cb19792bf3ee6f6c57fed08eb91ea4Dan Bornstein        "system. You will be to blame for this problem.\n\n" +
9685dc40d2a0cb19792bf3ee6f6c57fed08eb91ea4Dan Bornstein        "If you are legitimately using some code that happens to be in a\n" +
9785dc40d2a0cb19792bf3ee6f6c57fed08eb91ea4Dan Bornstein        "core package, then the easiest safe alternative you have is to\n" +
9885dc40d2a0cb19792bf3ee6f6c57fed08eb91ea4Dan Bornstein        "repackage that code. That is, move the classes in question into\n" +
9985dc40d2a0cb19792bf3ee6f6c57fed08eb91ea4Dan Bornstein        "your own package namespace. This means that they will never be in\n" +
10085dc40d2a0cb19792bf3ee6f6c57fed08eb91ea4Dan Bornstein        "conflict with core system classes. JarJar is a tool that may help\n" +
10185dc40d2a0cb19792bf3ee6f6c57fed08eb91ea4Dan Bornstein        "you in this endeavor. If you find that you cannot do this, then\n" +
10285dc40d2a0cb19792bf3ee6f6c57fed08eb91ea4Dan Bornstein        "that is an indication that the path you are on will ultimately\n" +
10385dc40d2a0cb19792bf3ee6f6c57fed08eb91ea4Dan Bornstein        "lead to pain, suffering, grief, and lamentation.\n";
10485dc40d2a0cb19792bf3ee6f6c57fed08eb91ea4Dan Bornstein
10585dc40d2a0cb19792bf3ee6f6c57fed08eb91ea4Dan Bornstein    /**
10699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * {@code non-null;} name of the standard manifest file in {@code .jar}
107f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * files
108f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
109f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private static final String MANIFEST_NAME = "META-INF/MANIFEST.MF";
110f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
111f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
11299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * {@code non-null;} attribute name for the (quasi-standard?)
11399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * {@code Created-By} attribute
114f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
115f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private static final Attributes.Name CREATED_BY =
116f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        new Attributes.Name("Created-By");
117f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
118f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
11999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * {@code non-null;} list of {@code javax} subpackages that are considered
120f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * to be "core". <b>Note:</b>: This list must be sorted, since it
121f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * is binary-searched.
122f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
123f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private static final String[] JAVAX_CORE = {
124f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        "accessibility", "crypto", "imageio", "management", "naming", "net",
1259028bfd131e42a58255699d1471c914d58893c61jeffhao        "print", "rmi", "security", "sip", "sound", "sql", "swing",
1269028bfd131e42a58255699d1471c914d58893c61jeffhao        "transaction", "xml"
127f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    };
128f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
129f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /** number of warnings during processing */
130f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private static int warnings = 0;
131f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
132f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /** number of errors during processing */
133f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private static int errors = 0;
134f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
13599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    /** {@code non-null;} parsed command-line arguments */
136f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private static Arguments args;
137f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
13899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    /** {@code non-null;} output file in-progress */
139f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private static DexFile outputDex;
140f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
141f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
14299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * {@code null-ok;} map of resources to include in the output, or
14399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * {@code null} if resources are being ignored
144f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
145f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private static TreeMap<String, byte[]> outputResources;
146f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
147590f78fc4b6e3268149c5eacb7c8b7dd33497f44jeffhao    /** thread pool object used for multi-threaded file processing */
148590f78fc4b6e3268149c5eacb7c8b7dd33497f44jeffhao    private static ExecutorService threadPool;
149590f78fc4b6e3268149c5eacb7c8b7dd33497f44jeffhao
150590f78fc4b6e3268149c5eacb7c8b7dd33497f44jeffhao    /** true if any files are successfully processed */
151590f78fc4b6e3268149c5eacb7c8b7dd33497f44jeffhao    private static boolean anyFilesProcessed;
152590f78fc4b6e3268149c5eacb7c8b7dd33497f44jeffhao
153dc86cd9edc8b80953c8b698a83cdaebf6825d798Jesse Wilson    /** class files older than this must be defined in the target dex file. */
154dc86cd9edc8b80953c8b698a83cdaebf6825d798Jesse Wilson    private static long minimumFileAge = 0;
155dc86cd9edc8b80953c8b698a83cdaebf6825d798Jesse Wilson
156f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
157f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * This class is uninstantiable.
158f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
159f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private Main() {
160f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        // This space intentionally left blank.
161f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
162f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
163f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
164f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Run and exit if something unexpected happened.
165f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @param argArray the command line arguments
166f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
167dc86cd9edc8b80953c8b698a83cdaebf6825d798Jesse Wilson    public static void main(String[] argArray) throws IOException {
168f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        Arguments arguments = new Arguments();
169f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        arguments.parse(argArray);
170f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
171f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int result = run(arguments);
172f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (result != 0) {
173f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            System.exit(result);
174f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
175f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
176f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
177f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
178f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Run and return a result code.
179f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @param arguments the data + parameters for the conversion
180f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @return 0 if success > 0 otherwise.
181f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
182dc86cd9edc8b80953c8b698a83cdaebf6825d798Jesse Wilson    public static int run(Arguments arguments) throws IOException {
183f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        // Reset the error/warning count to start fresh.
184f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        warnings = 0;
185f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        errors = 0;
186f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
187f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        args = arguments;
188f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        args.makeCfOptions();
189f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
190dc520adfdcf0f0e9190cdb90605c42a7cc8fa98fDan Bornstein        File incrementalOutFile = null;
191dc520adfdcf0f0e9190cdb90605c42a7cc8fa98fDan Bornstein        if (args.incremental) {
192dc520adfdcf0f0e9190cdb90605c42a7cc8fa98fDan Bornstein            if (args.outName == null) {
193dc520adfdcf0f0e9190cdb90605c42a7cc8fa98fDan Bornstein                System.err.println(
194dc520adfdcf0f0e9190cdb90605c42a7cc8fa98fDan Bornstein                        "error: no incremental output name specified");
195dc520adfdcf0f0e9190cdb90605c42a7cc8fa98fDan Bornstein                return -1;
196dc520adfdcf0f0e9190cdb90605c42a7cc8fa98fDan Bornstein            }
197dc520adfdcf0f0e9190cdb90605c42a7cc8fa98fDan Bornstein            incrementalOutFile = new File(args.outName);
198dc520adfdcf0f0e9190cdb90605c42a7cc8fa98fDan Bornstein            if (incrementalOutFile.exists()) {
199dc520adfdcf0f0e9190cdb90605c42a7cc8fa98fDan Bornstein                minimumFileAge = incrementalOutFile.lastModified();
200dc520adfdcf0f0e9190cdb90605c42a7cc8fa98fDan Bornstein            }
201dc86cd9edc8b80953c8b698a83cdaebf6825d798Jesse Wilson        }
202dc86cd9edc8b80953c8b698a83cdaebf6825d798Jesse Wilson
203f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (!processAllFiles()) {
204f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return 1;
205f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
206f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
207dc86cd9edc8b80953c8b698a83cdaebf6825d798Jesse Wilson        if (args.incremental && !anyFilesProcessed) {
208dc86cd9edc8b80953c8b698a83cdaebf6825d798Jesse Wilson            return 0; // this was a no-op incremental build
209dc86cd9edc8b80953c8b698a83cdaebf6825d798Jesse Wilson        }
210dc86cd9edc8b80953c8b698a83cdaebf6825d798Jesse Wilson
211f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        byte[] outArray = writeDex();
212f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
213f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (outArray == null) {
214f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return 2;
215f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
216f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
217dc520adfdcf0f0e9190cdb90605c42a7cc8fa98fDan Bornstein        if (args.incremental && incrementalOutFile.exists()) {
218dc520adfdcf0f0e9190cdb90605c42a7cc8fa98fDan Bornstein            outArray = merge(outArray, incrementalOutFile);
219dc86cd9edc8b80953c8b698a83cdaebf6825d798Jesse Wilson        }
220dc86cd9edc8b80953c8b698a83cdaebf6825d798Jesse Wilson
221f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (args.jarOutput) {
222f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            // Effectively free up the (often massive) DexFile memory.
223f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            outputDex = null;
224f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
225f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (!createJar(args.outName, outArray)) {
226f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                return 3;
227f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
228dc86cd9edc8b80953c8b698a83cdaebf6825d798Jesse Wilson        } else if (args.outName != null) {
229dc86cd9edc8b80953c8b698a83cdaebf6825d798Jesse Wilson            OutputStream out = openOutput(args.outName);
230dc86cd9edc8b80953c8b698a83cdaebf6825d798Jesse Wilson            out.write(outArray);
231dc86cd9edc8b80953c8b698a83cdaebf6825d798Jesse Wilson            closeOutput(out);
232f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
233f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
234f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return 0;
235f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
236f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
237f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
238dc86cd9edc8b80953c8b698a83cdaebf6825d798Jesse Wilson     * Merges the dex files {@code update} and {@code base}, preferring
239dc86cd9edc8b80953c8b698a83cdaebf6825d798Jesse Wilson     * {@code update}'s definition for types defined in both dex files. Returns
240dc86cd9edc8b80953c8b698a83cdaebf6825d798Jesse Wilson     * the bytes of the merged dex file.
241dc86cd9edc8b80953c8b698a83cdaebf6825d798Jesse Wilson     */
242dc86cd9edc8b80953c8b698a83cdaebf6825d798Jesse Wilson    private static byte[] merge(byte[] update, File base) throws IOException {
243dc86cd9edc8b80953c8b698a83cdaebf6825d798Jesse Wilson        DexBuffer dexA = new DexBuffer();
244dc86cd9edc8b80953c8b698a83cdaebf6825d798Jesse Wilson        dexA.loadFrom(new ByteArrayInputStream(update));
245dc86cd9edc8b80953c8b698a83cdaebf6825d798Jesse Wilson
246dc86cd9edc8b80953c8b698a83cdaebf6825d798Jesse Wilson        DexBuffer dexB = new DexBuffer();
247dc86cd9edc8b80953c8b698a83cdaebf6825d798Jesse Wilson        if (args.jarOutput) {
248dc86cd9edc8b80953c8b698a83cdaebf6825d798Jesse Wilson            ZipFile zipFile = new ZipFile(base);
249dc86cd9edc8b80953c8b698a83cdaebf6825d798Jesse Wilson            dexB.loadFrom(zipFile.getInputStream(zipFile.getEntry(DexFormat.DEX_IN_JAR_NAME)));
250dc86cd9edc8b80953c8b698a83cdaebf6825d798Jesse Wilson            zipFile.close();
251dc86cd9edc8b80953c8b698a83cdaebf6825d798Jesse Wilson        } else {
252dc86cd9edc8b80953c8b698a83cdaebf6825d798Jesse Wilson            InputStream in = new FileInputStream(base);
253dc86cd9edc8b80953c8b698a83cdaebf6825d798Jesse Wilson            dexB.loadFrom(in);
254dc86cd9edc8b80953c8b698a83cdaebf6825d798Jesse Wilson            in.close();
255dc86cd9edc8b80953c8b698a83cdaebf6825d798Jesse Wilson        }
256dc86cd9edc8b80953c8b698a83cdaebf6825d798Jesse Wilson
257dc86cd9edc8b80953c8b698a83cdaebf6825d798Jesse Wilson        DexBuffer merged = new DexMerger(dexA, dexB).merge();
258dc86cd9edc8b80953c8b698a83cdaebf6825d798Jesse Wilson        ByteArrayOutputStream bytesOut = new ByteArrayOutputStream();
259dc86cd9edc8b80953c8b698a83cdaebf6825d798Jesse Wilson        merged.writeTo(bytesOut);
260dc86cd9edc8b80953c8b698a83cdaebf6825d798Jesse Wilson        return bytesOut.toByteArray();
261dc86cd9edc8b80953c8b698a83cdaebf6825d798Jesse Wilson    }
262dc86cd9edc8b80953c8b698a83cdaebf6825d798Jesse Wilson
263dc86cd9edc8b80953c8b698a83cdaebf6825d798Jesse Wilson    /**
264f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Constructs the output {@link DexFile}, fill it in with all the
265f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * specified classes, and populate the resources map if required.
266f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
267f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @return whether processing was successful
268f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
269f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private static boolean processAllFiles() {
270f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        outputDex = new DexFile();
271f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
272f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (args.jarOutput) {
273f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            outputResources = new TreeMap<String, byte[]>();
274f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
275f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
276f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (args.dumpWidth != 0) {
277f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            outputDex.setDumpWidth(args.dumpWidth);
278f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
279f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
280590f78fc4b6e3268149c5eacb7c8b7dd33497f44jeffhao        anyFilesProcessed = false;
281f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        String[] fileNames = args.fileNames;
282f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
283590f78fc4b6e3268149c5eacb7c8b7dd33497f44jeffhao        if (args.numThreads > 1) {
284590f78fc4b6e3268149c5eacb7c8b7dd33497f44jeffhao            threadPool = Executors.newFixedThreadPool(args.numThreads);
285590f78fc4b6e3268149c5eacb7c8b7dd33497f44jeffhao        }
286590f78fc4b6e3268149c5eacb7c8b7dd33497f44jeffhao
287f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        try {
288f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            for (int i = 0; i < fileNames.length; i++) {
289590f78fc4b6e3268149c5eacb7c8b7dd33497f44jeffhao                if (processOne(fileNames[i])) {
290590f78fc4b6e3268149c5eacb7c8b7dd33497f44jeffhao                    anyFilesProcessed = true;
291590f78fc4b6e3268149c5eacb7c8b7dd33497f44jeffhao                }
292f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
293f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        } catch (StopProcessing ex) {
294f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            /*
295f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * Ignore it and just let the warning/error reporting do
296f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * their things.
297f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             */
298f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
299f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
300590f78fc4b6e3268149c5eacb7c8b7dd33497f44jeffhao        if (args.numThreads > 1) {
301590f78fc4b6e3268149c5eacb7c8b7dd33497f44jeffhao            try {
302590f78fc4b6e3268149c5eacb7c8b7dd33497f44jeffhao                threadPool.shutdown();
303590f78fc4b6e3268149c5eacb7c8b7dd33497f44jeffhao                threadPool.awaitTermination(600L, TimeUnit.SECONDS);
304590f78fc4b6e3268149c5eacb7c8b7dd33497f44jeffhao            } catch (InterruptedException ex) {
305590f78fc4b6e3268149c5eacb7c8b7dd33497f44jeffhao                throw new RuntimeException("Timed out waiting for threads.");
306590f78fc4b6e3268149c5eacb7c8b7dd33497f44jeffhao            }
307590f78fc4b6e3268149c5eacb7c8b7dd33497f44jeffhao        }
308590f78fc4b6e3268149c5eacb7c8b7dd33497f44jeffhao
309f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (warnings != 0) {
310f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            DxConsole.err.println(warnings + " warning" +
311f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                               ((warnings == 1) ? "" : "s"));
312f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
313f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
314f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (errors != 0) {
315f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            DxConsole.err.println(errors + " error" +
316f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    ((errors == 1) ? "" : "s") + "; aborting");
317f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return false;
318f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
319f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
320dc86cd9edc8b80953c8b698a83cdaebf6825d798Jesse Wilson        if (args.incremental && !anyFilesProcessed) {
321dc86cd9edc8b80953c8b698a83cdaebf6825d798Jesse Wilson            return true;
322dc86cd9edc8b80953c8b698a83cdaebf6825d798Jesse Wilson        }
323dc86cd9edc8b80953c8b698a83cdaebf6825d798Jesse Wilson
324590f78fc4b6e3268149c5eacb7c8b7dd33497f44jeffhao        if (!(anyFilesProcessed || args.emptyOk)) {
325f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            DxConsole.err.println("no classfiles specified");
326f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return false;
327f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
328f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
329f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (args.optimize && args.statistics) {
330f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            CodeStatistics.dumpStatistics(DxConsole.out);
331f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
332f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
333f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return true;
334f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
335f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
336f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
337f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Processes one pathname element.
338f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
33955423dcd081e30c4fc27b997f127db7b00f1b981Dan Bornstein     * @param pathname {@code non-null;} the pathname to process. May
34055423dcd081e30c4fc27b997f127db7b00f1b981Dan Bornstein     * be the path of a class file, a jar file, or a directory
34155423dcd081e30c4fc27b997f127db7b00f1b981Dan Bornstein     * containing class files.
342f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @return whether any processing actually happened
343f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
344f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private static boolean processOne(String pathname) {
345f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        ClassPathOpener opener;
346f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
347f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        opener = new ClassPathOpener(pathname, false,
348f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                new ClassPathOpener.Consumer() {
349dc86cd9edc8b80953c8b698a83cdaebf6825d798Jesse Wilson            public boolean processFileBytes(String name, long lastModified, byte[] bytes) {
350590f78fc4b6e3268149c5eacb7c8b7dd33497f44jeffhao                if (args.numThreads > 1) {
351dc86cd9edc8b80953c8b698a83cdaebf6825d798Jesse Wilson                    threadPool.execute(new ParallelProcessor(name, lastModified, bytes));
352590f78fc4b6e3268149c5eacb7c8b7dd33497f44jeffhao                    return false;
353590f78fc4b6e3268149c5eacb7c8b7dd33497f44jeffhao                } else {
354dc86cd9edc8b80953c8b698a83cdaebf6825d798Jesse Wilson                    return Main.processFileBytes(name, lastModified, bytes);
355590f78fc4b6e3268149c5eacb7c8b7dd33497f44jeffhao                }
356f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
357f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            public void onException(Exception ex) {
358f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                if (ex instanceof StopProcessing) {
359f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    throw (StopProcessing) ex;
360d0900d13fb7bb1706aff5205af7e2d6517335beejeffhao                } else if (ex instanceof SimException) {
361d0900d13fb7bb1706aff5205af7e2d6517335beejeffhao                    DxConsole.err.println("\nEXCEPTION FROM SIMULATION:");
362d0900d13fb7bb1706aff5205af7e2d6517335beejeffhao                    DxConsole.err.println(ex.getMessage() + "\n");
363d0900d13fb7bb1706aff5205af7e2d6517335beejeffhao                    DxConsole.err.println(((SimException) ex).getContext());
364d0900d13fb7bb1706aff5205af7e2d6517335beejeffhao                } else {
365d0900d13fb7bb1706aff5205af7e2d6517335beejeffhao                    DxConsole.err.println("\nUNEXPECTED TOP-LEVEL EXCEPTION:");
366d0900d13fb7bb1706aff5205af7e2d6517335beejeffhao                    ex.printStackTrace(DxConsole.err);
367f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
368f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                errors++;
369f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
370f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            public void onProcessArchiveStart(File file) {
371f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                if (args.verbose) {
37255423dcd081e30c4fc27b997f127db7b00f1b981Dan Bornstein                    DxConsole.out.println("processing archive " + file +
37355423dcd081e30c4fc27b997f127db7b00f1b981Dan Bornstein                            "...");
374f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
375f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
376f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        });
377f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
378de75089fb7216d19e9c22cce4dc62a49513477d3Carl Shapiro        return opener.process();
379f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
380f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
381f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
382f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Processes one file, which may be either a class or a resource.
383f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
38499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @param name {@code non-null;} name of the file
38599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @param bytes {@code non-null;} contents of the file
386f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @return whether processing was successful
387f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
388dc86cd9edc8b80953c8b698a83cdaebf6825d798Jesse Wilson    private static boolean processFileBytes(String name, long lastModified, byte[] bytes) {
389f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        boolean isClass = name.endsWith(".class");
390f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        boolean keepResources = (outputResources != null);
391f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
392f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (!isClass && !keepResources) {
393f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (args.verbose) {
394f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                DxConsole.out.println("ignored resource " + name);
395f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
396f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return false;
397f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
398f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
399f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (args.verbose) {
400f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            DxConsole.out.println("processing " + name + "...");
401f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
402f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
403f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        String fixedName = fixPath(name);
404f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
405f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (isClass) {
406f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (keepResources && args.keepClassesInJar) {
407590f78fc4b6e3268149c5eacb7c8b7dd33497f44jeffhao                synchronized (outputResources) {
408590f78fc4b6e3268149c5eacb7c8b7dd33497f44jeffhao                    outputResources.put(fixedName, bytes);
409590f78fc4b6e3268149c5eacb7c8b7dd33497f44jeffhao                }
410f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
411dc86cd9edc8b80953c8b698a83cdaebf6825d798Jesse Wilson            if (lastModified < minimumFileAge) {
412dc86cd9edc8b80953c8b698a83cdaebf6825d798Jesse Wilson                return true;
413dc86cd9edc8b80953c8b698a83cdaebf6825d798Jesse Wilson            }
414f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return processClass(fixedName, bytes);
415f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        } else {
416590f78fc4b6e3268149c5eacb7c8b7dd33497f44jeffhao            synchronized (outputResources) {
417590f78fc4b6e3268149c5eacb7c8b7dd33497f44jeffhao                outputResources.put(fixedName, bytes);
418590f78fc4b6e3268149c5eacb7c8b7dd33497f44jeffhao            }
419f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return true;
420f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
421f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
422f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
423f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
424f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Processes one classfile.
425f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
42699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @param name {@code non-null;} name of the file, clipped such that it
427f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * <i>should</i> correspond to the name of the class it contains
42899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @param bytes {@code non-null;} contents of the file
429f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @return whether processing was successful
430f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
431f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private static boolean processClass(String name, byte[] bytes) {
432f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (! args.coreLibrary) {
433f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            checkClassName(name);
434f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
435de75089fb7216d19e9c22cce4dc62a49513477d3Carl Shapiro
436f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        try {
437f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            ClassDefItem clazz =
438f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                CfTranslator.translate(name, bytes, args.cfOptions);
439590f78fc4b6e3268149c5eacb7c8b7dd33497f44jeffhao            synchronized (outputDex) {
440590f78fc4b6e3268149c5eacb7c8b7dd33497f44jeffhao                outputDex.add(clazz);
441590f78fc4b6e3268149c5eacb7c8b7dd33497f44jeffhao            }
442f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return true;
443f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        } catch (ParseException ex) {
444f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            DxConsole.err.println("\ntrouble processing:");
445f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (args.debug) {
446f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                ex.printStackTrace(DxConsole.err);
447f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            } else {
448f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                ex.printContext(DxConsole.err);
449f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
450f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
451f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
452f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        warnings++;
453f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return false;
454f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
455f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
456f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
457f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Check the class name to make sure it's not a "core library"
458f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * class. If there is a problem, this updates the error count and
459f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * throws an exception to stop processing.
460de75089fb7216d19e9c22cce4dc62a49513477d3Carl Shapiro     *
46155423dcd081e30c4fc27b997f127db7b00f1b981Dan Bornstein     * @param name {@code non-null;} the fully-qualified internal-form
46255423dcd081e30c4fc27b997f127db7b00f1b981Dan Bornstein     * class name
463f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
464f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private static void checkClassName(String name) {
465f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        boolean bogus = false;
466de75089fb7216d19e9c22cce4dc62a49513477d3Carl Shapiro
467f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (name.startsWith("java/")) {
468f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            bogus = true;
469f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        } else if (name.startsWith("javax/")) {
470f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            int slashAt = name.indexOf('/', 6);
471f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (slashAt == -1) {
472f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                // Top-level javax classes are verboten.
473f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                bogus = true;
474f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            } else {
475f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                String pkg = name.substring(6, slashAt);
476f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                bogus = (Arrays.binarySearch(JAVAX_CORE, pkg) >= 0);
477f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
478f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
479f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
480f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (! bogus) {
481f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return;
482f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
483f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
484f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /*
485f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * The user is probably trying to include an entire desktop
486f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * core library in a misguided attempt to get their application
487f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * working. Try to help them understand what's happening.
488f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
489f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
49085dc40d2a0cb19792bf3ee6f6c57fed08eb91ea4Dan Bornstein        DxConsole.err.println("\ntrouble processing \"" + name + "\":\n\n" +
49185dc40d2a0cb19792bf3ee6f6c57fed08eb91ea4Dan Bornstein                IN_RE_CORE_CLASSES);
492f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        errors++;
493f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        throw new StopProcessing();
494f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
495f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
496f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
497dc86cd9edc8b80953c8b698a83cdaebf6825d798Jesse Wilson     * Converts {@link #outputDex} into a {@code byte[]} and do whatever
498dc86cd9edc8b80953c8b698a83cdaebf6825d798Jesse Wilson     * human-oriented dumping is required.
499f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
50099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @return {@code null-ok;} the converted {@code byte[]} or {@code null}
501f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * if there was a problem
502f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
503f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private static byte[] writeDex() {
504f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        byte[] outArray = null;
505f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
506f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        try {
507f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            OutputStream humanOutRaw = null;
508f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            OutputStreamWriter humanOut = null;
509f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            try {
510f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                if (args.humanOutName != null) {
511f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    humanOutRaw = openOutput(args.humanOutName);
512f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    humanOut = new OutputStreamWriter(humanOutRaw);
513f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
514f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
515f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                if (args.methodToDump != null) {
516f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    /*
517f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                     * Simply dump the requested method. Note: The call
518f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                     * to toDex() is required just to get the underlying
519f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                     * structures ready.
520f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                     */
521f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    outputDex.toDex(null, false);
522f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    dumpMethod(outputDex, args.methodToDump, humanOut);
523f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                } else {
524f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    /*
525f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                     * This is the usual case: Create an output .dex file,
526f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                     * and write it, dump it, etc.
527f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                     */
528f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    outArray = outputDex.toDex(humanOut, args.verboseDump);
529f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
530f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
531f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                if (args.statistics) {
532f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    DxConsole.out.println(outputDex.getStatistics().toHuman());
533f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
534f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            } finally {
535f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                if (humanOut != null) {
536f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    humanOut.flush();
537f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
538f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                closeOutput(humanOutRaw);
539f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
540f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        } catch (Exception ex) {
541f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (args.debug) {
542f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                DxConsole.err.println("\ntrouble writing output:");
543f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                ex.printStackTrace(DxConsole.err);
544f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            } else {
545f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                DxConsole.err.println("\ntrouble writing output: " +
546f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                                   ex.getMessage());
547f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
548f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return null;
549f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
550f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
551f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return outArray;
552f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
553f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
554f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
555f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Creates a jar file from the resources and given dex file array.
556f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
55799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @param fileName {@code non-null;} name of the file
55855423dcd081e30c4fc27b997f127db7b00f1b981Dan Bornstein     * @param dexArray {@code non-null;} array containing the dex file
55955423dcd081e30c4fc27b997f127db7b00f1b981Dan Bornstein     * to include
560f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @return whether the creation was successful
561f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
562f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private static boolean createJar(String fileName, byte[] dexArray) {
563f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /*
564f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * Make or modify the manifest (as appropriate), put the dex
565f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * array into the resources map, and then process the entire
566f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * resources map in a uniform manner.
567f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
568f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
569f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        try {
570f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            Manifest manifest = makeManifest();
571f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            OutputStream out = openOutput(fileName);
572f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            JarOutputStream jarOut = new JarOutputStream(out, manifest);
573f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
574dc86cd9edc8b80953c8b698a83cdaebf6825d798Jesse Wilson            outputResources.put(DexFormat.DEX_IN_JAR_NAME, dexArray);
575f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
576f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            try {
577f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                for (Map.Entry<String, byte[]> e :
578f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                         outputResources.entrySet()) {
579f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    String name = e.getKey();
580f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    byte[] contents = e.getValue();
581f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    JarEntry entry = new JarEntry(name);
582f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
583f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    if (args.verbose) {
584f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        DxConsole.out.println("writing " + name + "; size " +
585f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                                           contents.length + "...");
586f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    }
587f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
588f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    entry.setSize(contents.length);
589f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    jarOut.putNextEntry(entry);
590f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    jarOut.write(contents);
591f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    jarOut.closeEntry();
592f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
593f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            } finally {
594f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                jarOut.finish();
595f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                jarOut.flush();
596f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                closeOutput(out);
597f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
598f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        } catch (Exception ex) {
599f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (args.debug) {
600f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                DxConsole.err.println("\ntrouble writing output:");
601f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                ex.printStackTrace(DxConsole.err);
602f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            } else {
603f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                DxConsole.err.println("\ntrouble writing output: " +
604f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                                   ex.getMessage());
605f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
606f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return false;
607f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
608f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
609f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return true;
610f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
611f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
612f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
613f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Creates and returns the manifest to use for the output. This may
614f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * modify {@link #outputResources} (removing the pre-existing manifest).
615f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
61699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @return {@code non-null;} the manifest
617f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
618f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private static Manifest makeManifest() throws IOException {
619f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        byte[] manifestBytes = outputResources.get(MANIFEST_NAME);
620f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        Manifest manifest;
621f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        Attributes attribs;
622f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
623f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (manifestBytes == null) {
624f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            // We need to construct an entirely new manifest.
625f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            manifest = new Manifest();
626f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            attribs = manifest.getMainAttributes();
627f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            attribs.put(Attributes.Name.MANIFEST_VERSION, "1.0");
628f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        } else {
629f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            manifest = new Manifest(new ByteArrayInputStream(manifestBytes));
630f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            attribs = manifest.getMainAttributes();
631f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            outputResources.remove(MANIFEST_NAME);
632f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
633f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
634f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        String createdBy = attribs.getValue(CREATED_BY);
635f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (createdBy == null) {
636f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            createdBy = "";
637f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        } else {
638f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            createdBy += " + ";
639f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
640f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        createdBy += "dx " + Version.VERSION;
641f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
642f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        attribs.put(CREATED_BY, createdBy);
643dc86cd9edc8b80953c8b698a83cdaebf6825d798Jesse Wilson        attribs.putValue("Dex-Location", DexFormat.DEX_IN_JAR_NAME);
644f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
645f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return manifest;
646f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
647f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
648f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
649f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Opens and returns the named file for writing, treating "-" specially.
650f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
65199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @param name {@code non-null;} the file name
65299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @return {@code non-null;} the opened file
653f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
654f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private static OutputStream openOutput(String name) throws IOException {
655f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (name.equals("-") ||
656f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                name.startsWith("-.")) {
657f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return System.out;
658f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
659f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
660f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return new FileOutputStream(name);
661f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
662f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
663f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
664f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Flushes and closes the given output stream, except if it happens to be
665f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * {@link System#out} in which case this method does the flush but not
666f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * the close. This method will also silently do nothing if given a
66799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * {@code null} argument.
668f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
66999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @param stream {@code null-ok;} what to close
670f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
671f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private static void closeOutput(OutputStream stream) throws IOException {
672f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (stream == null) {
673f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return;
674f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
675f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
676f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        stream.flush();
677f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
678f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (stream != System.out) {
679f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            stream.close();
680f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
681f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
682f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
683f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
684f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Returns the "fixed" version of a given file path, suitable for
68599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * use as a path within a {@code .jar} file and for checking
686f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * against a classfile-internal "this class" name. This looks for
68799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * the last instance of the substring {@code "/./"} within
688f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * the path, and if it finds it, it takes the portion after to be
689f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * the fixed path. If that isn't found but the path starts with
69099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * {@code "./"}, then that prefix is removed and the rest is
691f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * return. If neither of these is the case, this method returns
692f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * its argument.
693f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
69499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @param path {@code non-null;} the path to "fix"
69599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @return {@code non-null;} the fixed version (which might be the same as
69699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * the given {@code path})
697f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
698f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private static String fixPath(String path) {
699f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /*
700f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * If the path separator is \ (like on windows), we convert the
701f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * path to a standard '/' separated path.
702f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
703f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (File.separatorChar == '\\') {
704f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            path = path.replace('\\', '/');
705f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
706f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
707f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int index = path.lastIndexOf("/./");
708f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
709f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (index != -1) {
710f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return path.substring(index + 3);
711f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
712f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
713f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (path.startsWith("./")) {
714f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return path.substring(2);
715f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
716f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
717f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return path;
718f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
719f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
720f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
721f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Dumps any method with the given name in the given file.
722f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
72399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @param dex {@code non-null;} the dex file
72455423dcd081e30c4fc27b997f127db7b00f1b981Dan Bornstein     * @param fqName {@code non-null;} the fully-qualified name of the
72555423dcd081e30c4fc27b997f127db7b00f1b981Dan Bornstein     * method(s)
72699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @param out {@code non-null;} where to dump to
727f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
728f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private static void dumpMethod(DexFile dex, String fqName,
729f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            OutputStreamWriter out) {
730f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        boolean wildcard = fqName.endsWith("*");
731f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int lastDot = fqName.lastIndexOf('.');
732f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
733f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if ((lastDot <= 0) || (lastDot == (fqName.length() - 1))) {
734f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            DxConsole.err.println("bogus fully-qualified method name: " +
735f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                               fqName);
736f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return;
737f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
738f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
739f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        String className = fqName.substring(0, lastDot).replace('.', '/');
740f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        String methodName = fqName.substring(lastDot + 1);
741f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        ClassDefItem clazz = dex.getClassOrNull(className);
742f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
743f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (clazz == null) {
744f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            DxConsole.err.println("no such class: " + className);
745f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return;
746f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
747f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
748f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (wildcard) {
749f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            methodName = methodName.substring(0, methodName.length() - 1);
750f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
751f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
752f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        ArrayList<EncodedMethod> allMeths = clazz.getMethods();
753f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        TreeMap<CstNat, EncodedMethod> meths =
754f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            new TreeMap<CstNat, EncodedMethod>();
755f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
756f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /*
757f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * Figure out which methods to include in the output, and get them
758f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * all sorted, so that the printout code is robust with respect to
759f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * changes in the underlying order.
760f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
761f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        for (EncodedMethod meth : allMeths) {
762f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            String methName = meth.getName().getString();
763f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if ((wildcard && methName.startsWith(methodName)) ||
764f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                (!wildcard && methName.equals(methodName))) {
765f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                meths.put(meth.getRef().getNat(), meth);
766f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
767f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
768f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
769f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (meths.size() == 0) {
770f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            DxConsole.err.println("no such method: " + fqName);
771f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return;
772f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
773f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
774f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        PrintWriter pw = new PrintWriter(out);
775f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
776f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        for (EncodedMethod meth : meths.values()) {
777f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            // TODO: Better stuff goes here, perhaps.
778f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            meth.debugPrint(pw, args.verboseDump);
779f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
780f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            /*
781de75089fb7216d19e9c22cce4dc62a49513477d3Carl Shapiro             * The (default) source file is an attribute of the class, but
782f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * it's useful to see it in method dumps.
783f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             */
784f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            CstUtf8 sourceFile = clazz.getSourceFile();
785f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (sourceFile != null) {
786f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                pw.println("  source file: " + sourceFile.toQuoted());
787f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
788f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
789f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            Annotations methodAnnotations =
790f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                clazz.getMethodAnnotations(meth.getRef());
791f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            AnnotationsList parameterAnnotations =
792f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                clazz.getParameterAnnotations(meth.getRef());
793f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
794f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (methodAnnotations != null) {
795f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                pw.println("  method annotations:");
796f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                for (Annotation a : methodAnnotations.getAnnotations()) {
797f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    pw.println("    " + a);
798f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
799f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
800f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
801f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (parameterAnnotations != null) {
802f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                pw.println("  parameter annotations:");
803f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                int sz = parameterAnnotations.size();
804f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                for (int i = 0; i < sz; i++) {
805f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    pw.println("    parameter " + i);
806f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    Annotations annotations = parameterAnnotations.get(i);
807f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    for (Annotation a : annotations.getAnnotations()) {
808f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        pw.println("      " + a);
809f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    }
810f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
811f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
812f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
813f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
814f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        pw.flush();
815f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
816f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
817f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
818f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Exception class used to halt processing prematurely.
819f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
820f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private static class StopProcessing extends RuntimeException {
821f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        // This space intentionally left blank.
822f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
823de75089fb7216d19e9c22cce4dc62a49513477d3Carl Shapiro
824f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
825f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Command-line argument parser and access.
826f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
827f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public static class Arguments {
828f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /** whether to run in debug mode */
829f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        public boolean debug = false;
830f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
831f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /** whether to emit high-level verbose human-oriented output */
832f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        public boolean verbose = false;
833f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
834f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /** whether to emit verbose human-oriented output in the dump file */
835f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        public boolean verboseDump = false;
836f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
837f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /** whether we are constructing a core library */
838f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        public boolean coreLibrary = false;
839f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
84099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        /** {@code null-ok;} particular method to dump */
841f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        public String methodToDump = null;
842f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
843f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /** max width for columnar output */
844f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        public int dumpWidth = 0;
845f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
84699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        /** {@code null-ok;} output file name for binary file */
847f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        public String outName = null;
848f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
84999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        /** {@code null-ok;} output file name for human-oriented dump */
850f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        public String humanOutName = null;
851f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
852f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /** whether strict file-name-vs-class-name checking should be done */
853f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        public boolean strictNameCheck = true;
854f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
855f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /**
85699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project         * whether it is okay for there to be no {@code .class} files
857f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * to process
858f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
859f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        public boolean emptyOk = false;
860f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
861f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /**
86299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project         * whether the binary output is to be a {@code .jar} file
86399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project         * instead of a plain {@code .dex}
864f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
865f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        public boolean jarOutput = false;
866f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
867f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /**
86899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project         * when writing a {@code .jar} file, whether to still
86999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project         * keep the {@code .class} files
870f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
871f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        public boolean keepClassesInJar = false;
872f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
873f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /** how much source position info to preserve */
874f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        public int positionInfo = PositionList.LINES;
875f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
876f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /** whether to keep local variable information */
877f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        public boolean localInfo = true;
878f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
879dc86cd9edc8b80953c8b698a83cdaebf6825d798Jesse Wilson        /** whether to merge with the output dex file if it exists. */
880dc86cd9edc8b80953c8b698a83cdaebf6825d798Jesse Wilson        public boolean incremental = false;
881dc86cd9edc8b80953c8b698a83cdaebf6825d798Jesse Wilson
88299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        /** {@code non-null after {@link #parse};} file name arguments */
883f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        public String[] fileNames;
884f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
885f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /** whether to do SSA/register optimization */
886f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        public boolean optimize = true;
887f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
888f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /** Filename containg list of methods to optimize */
889f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        public String optimizeListFile = null;
890f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
891f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /** Filename containing list of methods to NOT optimize */
892f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        public String dontOptimizeListFile = null;
893f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
894f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /** Whether to print statistics to stdout at end of compile cycle */
895f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        public boolean statistics;
896f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
897f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /** Options for dex.cf.* */
898f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        public CfOptions cfOptions;
899f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
900590f78fc4b6e3268149c5eacb7c8b7dd33497f44jeffhao        /** number of threads to run with */
901590f78fc4b6e3268149c5eacb7c8b7dd33497f44jeffhao        public int numThreads = 1;
902590f78fc4b6e3268149c5eacb7c8b7dd33497f44jeffhao
903f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /**
904f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * Parses the given command-line arguments.
905f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         *
90699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project         * @param args {@code non-null;} the arguments
907f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
908f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        public void parse(String[] args) {
909f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            int at = 0;
910f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
911f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            for (/*at*/; at < args.length; at++) {
912f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                String arg = args[at];
913f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                if (arg.equals("--") || !arg.startsWith("--")) {
914f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    break;
915f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                } else if (arg.equals("--debug")) {
916f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    debug = true;
917f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                } else if (arg.equals("--verbose")) {
918f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    verbose = true;
919f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                } else if (arg.equals("--verbose-dump")) {
920f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    verboseDump = true;
921f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                } else if (arg.equals("--no-files")) {
922f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    emptyOk = true;
923f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                } else if (arg.equals("--no-optimize")) {
924f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    optimize = false;
925f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                } else if (arg.equals("--no-strict")) {
926f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    strictNameCheck = false;
927f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                } else if (arg.equals("--core-library")) {
928f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    coreLibrary = true;
929f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                } else if (arg.equals("--statistics")) {
930f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    statistics = true;
931f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                } else if (arg.startsWith("--optimize-list=")) {
932f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    if (dontOptimizeListFile != null) {
933f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        System.err.println("--optimize-list and "
934f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                                + "--no-optimize-list are incompatible.");
935f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        throw new UsageException();
936f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    }
937f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    optimize = true;
938f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    optimizeListFile = arg.substring(arg.indexOf('=') + 1);
939f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                } else if (arg.startsWith("--no-optimize-list=")) {
940f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    if (dontOptimizeListFile != null) {
941f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        System.err.println("--optimize-list and "
942f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                                + "--no-optimize-list are incompatible.");
943f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        throw new UsageException();
944f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    }
945f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    optimize = true;
946f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    dontOptimizeListFile = arg.substring(arg.indexOf('=') + 1);
947f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                } else if (arg.equals("--keep-classes")) {
948f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    keepClassesInJar = true;
949f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                } else if (arg.startsWith("--output=")) {
950f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    outName = arg.substring(arg.indexOf('=') + 1);
951dc86cd9edc8b80953c8b698a83cdaebf6825d798Jesse Wilson                    if (FileUtils.hasArchiveSuffix(outName)) {
952f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        jarOutput = true;
953f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    } else if (outName.endsWith(".dex") ||
954f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                               outName.equals("-")) {
955f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        jarOutput = false;
956f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    } else {
957f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        System.err.println("unknown output extension: " +
958f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                                           outName);
959f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        throw new UsageException();
960f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    }
961f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                } else if (arg.startsWith("--dump-to=")) {
962f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    humanOutName = arg.substring(arg.indexOf('=') + 1);
963f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                } else if (arg.startsWith("--dump-width=")) {
964f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    arg = arg.substring(arg.indexOf('=') + 1);
965f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    dumpWidth = Integer.parseInt(arg);
966f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                } else if (arg.startsWith("--dump-method=")) {
967f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    methodToDump = arg.substring(arg.indexOf('=') + 1);
968f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    jarOutput = false;
969f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                } else if (arg.startsWith("--positions=")) {
970f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    String pstr = arg.substring(arg.indexOf('=') + 1).intern();
971f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    if (pstr == "none") {
972f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        positionInfo = PositionList.NONE;
973f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    } else if (pstr == "important") {
974f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        positionInfo = PositionList.IMPORTANT;
975f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    } else if (pstr == "lines") {
976f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        positionInfo = PositionList.LINES;
977f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    } else {
978f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        System.err.println("unknown positions option: " +
979f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                                           pstr);
980f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        throw new UsageException();
981f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    }
982f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                } else if (arg.equals("--no-locals")) {
983f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    localInfo = false;
984590f78fc4b6e3268149c5eacb7c8b7dd33497f44jeffhao                } else if (arg.startsWith("--num-threads=")) {
985590f78fc4b6e3268149c5eacb7c8b7dd33497f44jeffhao                    arg = arg.substring(arg.indexOf('=') + 1);
986590f78fc4b6e3268149c5eacb7c8b7dd33497f44jeffhao                    numThreads = Integer.parseInt(arg);
987dc86cd9edc8b80953c8b698a83cdaebf6825d798Jesse Wilson                } else if (arg.equals("--incremental")) {
988dc86cd9edc8b80953c8b698a83cdaebf6825d798Jesse Wilson                    incremental = true;
989f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                } else {
990f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    System.err.println("unknown option: " + arg);
991f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    throw new UsageException();
992f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
993f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
994f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
995f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            int fileCount = args.length - at;
996f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
997f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (fileCount == 0) {
998f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                if (!emptyOk) {
999f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    System.err.println("no input files specified");
1000f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    throw new UsageException();
1001f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
1002f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            } else if (emptyOk) {
1003f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                System.out.println("ignoring input files");
100455423dcd081e30c4fc27b997f127db7b00f1b981Dan Bornstein                at = 0;
100555423dcd081e30c4fc27b997f127db7b00f1b981Dan Bornstein                fileCount = 0;
1006f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
1007f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
100855423dcd081e30c4fc27b997f127db7b00f1b981Dan Bornstein            fileNames = new String[fileCount];
100955423dcd081e30c4fc27b997f127db7b00f1b981Dan Bornstein            System.arraycopy(args, at, fileNames, 0, fileCount);
101055423dcd081e30c4fc27b997f127db7b00f1b981Dan Bornstein
1011f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if ((humanOutName == null) && (methodToDump != null)) {
1012f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                humanOutName = "-";
1013f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
1014f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1015f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            makeCfOptions();
1016f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
1017f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1018f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /**
1019f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * Copies relevent arguments over into a CfOptions instance.
1020f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
1021f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        private void makeCfOptions() {
1022f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            cfOptions = new CfOptions();
1023f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1024f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            cfOptions.positionInfo = positionInfo;
1025f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            cfOptions.localInfo = localInfo;
1026f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            cfOptions.strictNameCheck = strictNameCheck;
1027f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            cfOptions.optimize = optimize;
1028f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            cfOptions.optimizeListFile = optimizeListFile;
1029f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            cfOptions.dontOptimizeListFile = dontOptimizeListFile;
1030f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            cfOptions.statistics = statistics;
1031f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            cfOptions.warn = DxConsole.err;
1032f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
1033f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
1034590f78fc4b6e3268149c5eacb7c8b7dd33497f44jeffhao
1035590f78fc4b6e3268149c5eacb7c8b7dd33497f44jeffhao    /** Runnable helper class to process files in multiple threads */
1036590f78fc4b6e3268149c5eacb7c8b7dd33497f44jeffhao    private static class ParallelProcessor implements Runnable {
1037590f78fc4b6e3268149c5eacb7c8b7dd33497f44jeffhao
1038590f78fc4b6e3268149c5eacb7c8b7dd33497f44jeffhao        String path;
1039dc86cd9edc8b80953c8b698a83cdaebf6825d798Jesse Wilson        long lastModified;
1040590f78fc4b6e3268149c5eacb7c8b7dd33497f44jeffhao        byte[] bytes;
1041590f78fc4b6e3268149c5eacb7c8b7dd33497f44jeffhao
1042590f78fc4b6e3268149c5eacb7c8b7dd33497f44jeffhao        /**
1043590f78fc4b6e3268149c5eacb7c8b7dd33497f44jeffhao         * Constructs an instance.
1044590f78fc4b6e3268149c5eacb7c8b7dd33497f44jeffhao         *
1045590f78fc4b6e3268149c5eacb7c8b7dd33497f44jeffhao         * @param path {@code non-null;} filename of element. May not be a valid
1046590f78fc4b6e3268149c5eacb7c8b7dd33497f44jeffhao         * filesystem path.
1047590f78fc4b6e3268149c5eacb7c8b7dd33497f44jeffhao         * @param bytes {@code non-null;} file data
1048590f78fc4b6e3268149c5eacb7c8b7dd33497f44jeffhao         */
1049dc86cd9edc8b80953c8b698a83cdaebf6825d798Jesse Wilson        private ParallelProcessor(String path, long lastModified, byte bytes[]) {
1050590f78fc4b6e3268149c5eacb7c8b7dd33497f44jeffhao            this.path = path;
1051dc86cd9edc8b80953c8b698a83cdaebf6825d798Jesse Wilson            this.lastModified = lastModified;
1052590f78fc4b6e3268149c5eacb7c8b7dd33497f44jeffhao            this.bytes = bytes;
1053590f78fc4b6e3268149c5eacb7c8b7dd33497f44jeffhao        }
1054590f78fc4b6e3268149c5eacb7c8b7dd33497f44jeffhao
1055590f78fc4b6e3268149c5eacb7c8b7dd33497f44jeffhao        /**
1056590f78fc4b6e3268149c5eacb7c8b7dd33497f44jeffhao         * Task run by each thread in the thread pool. Runs processFileBytes
1057590f78fc4b6e3268149c5eacb7c8b7dd33497f44jeffhao         * with the given path and bytes.
1058590f78fc4b6e3268149c5eacb7c8b7dd33497f44jeffhao         */
1059590f78fc4b6e3268149c5eacb7c8b7dd33497f44jeffhao        public void run() {
1060dc86cd9edc8b80953c8b698a83cdaebf6825d798Jesse Wilson            if (Main.processFileBytes(path, lastModified, bytes)) {
1061590f78fc4b6e3268149c5eacb7c8b7dd33497f44jeffhao                anyFilesProcessed = true;
1062590f78fc4b6e3268149c5eacb7c8b7dd33497f44jeffhao            }
1063590f78fc4b6e3268149c5eacb7c8b7dd33497f44jeffhao        }
1064590f78fc4b6e3268149c5eacb7c8b7dd33497f44jeffhao    }
1065f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
1066