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
19fe107fb6e3f308ac5174ebdc5a794ee880c741d9Jesse Wilsonimport com.android.dex.Dex;
20c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarcheimport com.android.dex.DexException;
21fe107fb6e3f308ac5174ebdc5a794ee880c741d9Jesse Wilsonimport com.android.dex.DexFormat;
22fe107fb6e3f308ac5174ebdc5a794ee880c741d9Jesse Wilsonimport com.android.dex.util.FileUtils;
23f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.Version;
24d0900d13fb7bb1706aff5205af7e2d6517335beejeffhaoimport com.android.dx.cf.code.SimException;
25f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.cf.direct.ClassPathOpener;
26c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarcheimport com.android.dx.cf.direct.ClassPathOpener.FileNameFilter;
27c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarcheimport com.android.dx.cf.direct.DirectClassFile;
28c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarcheimport com.android.dx.cf.direct.StdAttributeFactory;
29dc86cd9edc8b80953c8b698a83cdaebf6825d798Jesse Wilsonimport com.android.dx.cf.iface.ParseException;
30f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.command.DxConsole;
31f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.command.UsageException;
323dfda9ad1964510e4a7948a240b30cd710e86341Dan Bornsteinimport com.android.dx.dex.DexOptions;
33f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.dex.cf.CfOptions;
34f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.dex.cf.CfTranslator;
35f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.dex.cf.CodeStatistics;
36f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.dex.code.PositionList;
37f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.dex.file.ClassDefItem;
38f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.dex.file.DexFile;
39f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.dex.file.EncodedMethod;
4009d308b04b7c4fd3ed83a8f8f4c07be67a25478cJesse Wilsonimport com.android.dx.merge.CollisionPolicy;
41dc86cd9edc8b80953c8b698a83cdaebf6825d798Jesse Wilsonimport com.android.dx.merge.DexMerger;
42f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.rop.annotation.Annotation;
43f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.rop.annotation.Annotations;
44f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.rop.annotation.AnnotationsList;
45f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.rop.cst.CstNat;
46333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilsonimport com.android.dx.rop.cst.CstString;
47c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche
48c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarcheimport java.io.BufferedReader;
49f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.io.ByteArrayInputStream;
50dc86cd9edc8b80953c8b698a83cdaebf6825d798Jesse Wilsonimport java.io.ByteArrayOutputStream;
51f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.io.File;
52f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.io.FileOutputStream;
53c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarcheimport java.io.FileReader;
54f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.io.IOException;
55f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.io.OutputStream;
56f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.io.OutputStreamWriter;
57f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.io.PrintWriter;
58f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.util.ArrayList;
59dc86cd9edc8b80953c8b698a83cdaebf6825d798Jesse Wilsonimport java.util.Arrays;
609747950064e4711c15baf0986102320a2512097aXavier Ducrohetimport java.util.Collection;
61c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarcheimport java.util.HashMap;
62c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarcheimport java.util.HashSet;
6309d308b04b7c4fd3ed83a8f8f4c07be67a25478cJesse Wilsonimport java.util.List;
64f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.util.Map;
65c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarcheimport java.util.Set;
66f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.util.TreeMap;
67cecacd3a4b5ab7a45340f3843522a42a0a4cf287Benoit Lamarcheimport java.util.concurrent.Callable;
68cecacd3a4b5ab7a45340f3843522a42a0a4cf287Benoit Lamarcheimport java.util.concurrent.ExecutionException;
69590f78fc4b6e3268149c5eacb7c8b7dd33497f44jeffhaoimport java.util.concurrent.ExecutorService;
70590f78fc4b6e3268149c5eacb7c8b7dd33497f44jeffhaoimport java.util.concurrent.Executors;
71cecacd3a4b5ab7a45340f3843522a42a0a4cf287Benoit Lamarcheimport java.util.concurrent.Future;
72cecacd3a4b5ab7a45340f3843522a42a0a4cf287Benoit Lamarcheimport java.util.concurrent.ThreadFactory;
73590f78fc4b6e3268149c5eacb7c8b7dd33497f44jeffhaoimport java.util.concurrent.TimeUnit;
74cecacd3a4b5ab7a45340f3843522a42a0a4cf287Benoit Lamarcheimport java.util.concurrent.atomic.AtomicInteger;
75f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.util.jar.Attributes;
76f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.util.jar.JarEntry;
77f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.util.jar.JarOutputStream;
78f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.util.jar.Manifest;
79f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
80f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/**
81f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Main class for the class file translator.
82f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
83f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectpublic class Main {
84466d7d94b8b173a323fc5616837940219a216f9dYohann Roussel
85f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
86c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche     * File extension of a {@code .dex} file.
87c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche     */
88c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche    private static final String DEX_EXTENSION = ".dex";
89c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche
90c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche    /**
91c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche     * File name prefix of a {@code .dex} file automatically loaded in an
92c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche     * archive.
93c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche     */
94c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche    private static final String DEX_PREFIX = "classes";
95c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche
96c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche    /**
9785dc40d2a0cb19792bf3ee6f6c57fed08eb91ea4Dan Bornstein     * {@code non-null;} the lengthy message that tries to discourage
9885dc40d2a0cb19792bf3ee6f6c57fed08eb91ea4Dan Bornstein     * people from defining core classes in applications
9985dc40d2a0cb19792bf3ee6f6c57fed08eb91ea4Dan Bornstein     */
10085dc40d2a0cb19792bf3ee6f6c57fed08eb91ea4Dan Bornstein    private static final String IN_RE_CORE_CLASSES =
10185dc40d2a0cb19792bf3ee6f6c57fed08eb91ea4Dan Bornstein        "Ill-advised or mistaken usage of a core class (java.* or javax.*)\n" +
10285dc40d2a0cb19792bf3ee6f6c57fed08eb91ea4Dan Bornstein        "when not building a core library.\n\n" +
10385dc40d2a0cb19792bf3ee6f6c57fed08eb91ea4Dan Bornstein        "This is often due to inadvertently including a core library file\n" +
10485dc40d2a0cb19792bf3ee6f6c57fed08eb91ea4Dan Bornstein        "in your application's project, when using an IDE (such as\n" +
10585dc40d2a0cb19792bf3ee6f6c57fed08eb91ea4Dan Bornstein        "Eclipse). If you are sure you're not intentionally defining a\n" +
10685dc40d2a0cb19792bf3ee6f6c57fed08eb91ea4Dan Bornstein        "core class, then this is the most likely explanation of what's\n" +
10785dc40d2a0cb19792bf3ee6f6c57fed08eb91ea4Dan Bornstein        "going on.\n\n" +
10885dc40d2a0cb19792bf3ee6f6c57fed08eb91ea4Dan Bornstein        "However, you might actually be trying to define a class in a core\n" +
10985dc40d2a0cb19792bf3ee6f6c57fed08eb91ea4Dan Bornstein        "namespace, the source of which you may have taken, for example,\n" +
11085dc40d2a0cb19792bf3ee6f6c57fed08eb91ea4Dan Bornstein        "from a non-Android virtual machine project. This will most\n" +
11185dc40d2a0cb19792bf3ee6f6c57fed08eb91ea4Dan Bornstein        "assuredly not work. At a minimum, it jeopardizes the\n" +
11285dc40d2a0cb19792bf3ee6f6c57fed08eb91ea4Dan Bornstein        "compatibility of your app with future versions of the platform.\n" +
11385dc40d2a0cb19792bf3ee6f6c57fed08eb91ea4Dan Bornstein        "It is also often of questionable legality.\n\n" +
11485dc40d2a0cb19792bf3ee6f6c57fed08eb91ea4Dan Bornstein        "If you really intend to build a core library -- which is only\n" +
11585dc40d2a0cb19792bf3ee6f6c57fed08eb91ea4Dan Bornstein        "appropriate as part of creating a full virtual machine\n" +
11685dc40d2a0cb19792bf3ee6f6c57fed08eb91ea4Dan Bornstein        "distribution, as opposed to compiling an application -- then use\n" +
11785dc40d2a0cb19792bf3ee6f6c57fed08eb91ea4Dan Bornstein        "the \"--core-library\" option to suppress this error message.\n\n" +
11885dc40d2a0cb19792bf3ee6f6c57fed08eb91ea4Dan Bornstein        "If you go ahead and use \"--core-library\" but are in fact\n" +
11985dc40d2a0cb19792bf3ee6f6c57fed08eb91ea4Dan Bornstein        "building an application, then be forewarned that your application\n" +
12085dc40d2a0cb19792bf3ee6f6c57fed08eb91ea4Dan Bornstein        "will still fail to build or run, at some point. Please be\n" +
12185dc40d2a0cb19792bf3ee6f6c57fed08eb91ea4Dan Bornstein        "prepared for angry customers who find, for example, that your\n" +
12285dc40d2a0cb19792bf3ee6f6c57fed08eb91ea4Dan Bornstein        "application ceases to function once they upgrade their operating\n" +
12385dc40d2a0cb19792bf3ee6f6c57fed08eb91ea4Dan Bornstein        "system. You will be to blame for this problem.\n\n" +
12485dc40d2a0cb19792bf3ee6f6c57fed08eb91ea4Dan Bornstein        "If you are legitimately using some code that happens to be in a\n" +
12585dc40d2a0cb19792bf3ee6f6c57fed08eb91ea4Dan Bornstein        "core package, then the easiest safe alternative you have is to\n" +
12685dc40d2a0cb19792bf3ee6f6c57fed08eb91ea4Dan Bornstein        "repackage that code. That is, move the classes in question into\n" +
12785dc40d2a0cb19792bf3ee6f6c57fed08eb91ea4Dan Bornstein        "your own package namespace. This means that they will never be in\n" +
12885dc40d2a0cb19792bf3ee6f6c57fed08eb91ea4Dan Bornstein        "conflict with core system classes. JarJar is a tool that may help\n" +
12985dc40d2a0cb19792bf3ee6f6c57fed08eb91ea4Dan Bornstein        "you in this endeavor. If you find that you cannot do this, then\n" +
13085dc40d2a0cb19792bf3ee6f6c57fed08eb91ea4Dan Bornstein        "that is an indication that the path you are on will ultimately\n" +
13185dc40d2a0cb19792bf3ee6f6c57fed08eb91ea4Dan Bornstein        "lead to pain, suffering, grief, and lamentation.\n";
13285dc40d2a0cb19792bf3ee6f6c57fed08eb91ea4Dan Bornstein
13385dc40d2a0cb19792bf3ee6f6c57fed08eb91ea4Dan Bornstein    /**
13499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * {@code non-null;} name of the standard manifest file in {@code .jar}
135f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * files
136f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
137f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private static final String MANIFEST_NAME = "META-INF/MANIFEST.MF";
138f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
139f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
14099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * {@code non-null;} attribute name for the (quasi-standard?)
14199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * {@code Created-By} attribute
142f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
143f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private static final Attributes.Name CREATED_BY =
144f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        new Attributes.Name("Created-By");
145f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
146f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
14799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * {@code non-null;} list of {@code javax} subpackages that are considered
148f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * to be "core". <b>Note:</b>: This list must be sorted, since it
149f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * is binary-searched.
150f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
151f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private static final String[] JAVAX_CORE = {
152f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        "accessibility", "crypto", "imageio", "management", "naming", "net",
1539028bfd131e42a58255699d1471c914d58893c61jeffhao        "print", "rmi", "security", "sip", "sound", "sql", "swing",
1549028bfd131e42a58255699d1471c914d58893c61jeffhao        "transaction", "xml"
155f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    };
156f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
157466d7d94b8b173a323fc5616837940219a216f9dYohann Roussel    /* Array.newInstance may be added by RopperMachine,
158466d7d94b8b173a323fc5616837940219a216f9dYohann Roussel     * ArrayIndexOutOfBoundsException.<init> may be added by EscapeAnalysis */
159466d7d94b8b173a323fc5616837940219a216f9dYohann Roussel    private static final int MAX_METHOD_ADDED_DURING_DEX_CREATION = 2;
160466d7d94b8b173a323fc5616837940219a216f9dYohann Roussel
161466d7d94b8b173a323fc5616837940219a216f9dYohann Roussel    /* <primitive types box class>.TYPE */
162466d7d94b8b173a323fc5616837940219a216f9dYohann Roussel    private static final int MAX_FIELD_ADDED_DURING_DEX_CREATION = 9;
163466d7d94b8b173a323fc5616837940219a216f9dYohann Roussel
164f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /** number of errors during processing */
165cecacd3a4b5ab7a45340f3843522a42a0a4cf287Benoit Lamarche    private static AtomicInteger errors = new AtomicInteger(0);
166f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
16799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    /** {@code non-null;} parsed command-line arguments */
168f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private static Arguments args;
169f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
17099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    /** {@code non-null;} output file in-progress */
171f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private static DexFile outputDex;
172f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
173f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
17499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * {@code null-ok;} map of resources to include in the output, or
17599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * {@code null} if resources are being ignored
176f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
177f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private static TreeMap<String, byte[]> outputResources;
178f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
17909d308b04b7c4fd3ed83a8f8f4c07be67a25478cJesse Wilson    /** Library .dex files to merge into the output .dex. */
18009d308b04b7c4fd3ed83a8f8f4c07be67a25478cJesse Wilson    private static final List<byte[]> libraryDexBuffers = new ArrayList<byte[]>();
18109d308b04b7c4fd3ed83a8f8f4c07be67a25478cJesse Wilson
182590f78fc4b6e3268149c5eacb7c8b7dd33497f44jeffhao    /** thread pool object used for multi-threaded file processing */
183590f78fc4b6e3268149c5eacb7c8b7dd33497f44jeffhao    private static ExecutorService threadPool;
184590f78fc4b6e3268149c5eacb7c8b7dd33497f44jeffhao
185cecacd3a4b5ab7a45340f3843522a42a0a4cf287Benoit Lamarche    /** used to handle Errors for multi-threaded file processing */
186cecacd3a4b5ab7a45340f3843522a42a0a4cf287Benoit Lamarche    private static List<Future<Void>> parallelProcessorFutures;
187cecacd3a4b5ab7a45340f3843522a42a0a4cf287Benoit Lamarche
188590f78fc4b6e3268149c5eacb7c8b7dd33497f44jeffhao    /** true if any files are successfully processed */
189cecacd3a4b5ab7a45340f3843522a42a0a4cf287Benoit Lamarche    private static volatile boolean anyFilesProcessed;
190590f78fc4b6e3268149c5eacb7c8b7dd33497f44jeffhao
191dc86cd9edc8b80953c8b698a83cdaebf6825d798Jesse Wilson    /** class files older than this must be defined in the target dex file. */
192dc86cd9edc8b80953c8b698a83cdaebf6825d798Jesse Wilson    private static long minimumFileAge = 0;
193dc86cd9edc8b80953c8b698a83cdaebf6825d798Jesse Wilson
194c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche    private static Set<String> classesInMainDex = null;
195c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche
196c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche    private static List<byte[]> dexOutputArrays = new ArrayList<byte[]>();
197c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche
198c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche    private static OutputStreamWriter humanOutWriter = null;
199c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche
200f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
201f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * This class is uninstantiable.
202f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
203f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private Main() {
204f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        // This space intentionally left blank.
205f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
206f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
207f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
208f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Run and exit if something unexpected happened.
209f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @param argArray the command line arguments
210f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
211dc86cd9edc8b80953c8b698a83cdaebf6825d798Jesse Wilson    public static void main(String[] argArray) throws IOException {
212f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        Arguments arguments = new Arguments();
213f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        arguments.parse(argArray);
214f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
215f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int result = run(arguments);
216f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (result != 0) {
217f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            System.exit(result);
218f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
219f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
220f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
221f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
222f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Run and return a result code.
223f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @param arguments the data + parameters for the conversion
224f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @return 0 if success > 0 otherwise.
225f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
226dc86cd9edc8b80953c8b698a83cdaebf6825d798Jesse Wilson    public static int run(Arguments arguments) throws IOException {
2270b44e47c51b5c735283cc99b0c08cac82dba8a00delphinemartin        // Reset the error count to start fresh.
228cecacd3a4b5ab7a45340f3843522a42a0a4cf287Benoit Lamarche        errors.set(0);
2297aa5ce7e990dc3766eba97cd0932b62e4de21503Xavier Ducrohet        // empty the list, so that  tools that load dx and keep it around
2307aa5ce7e990dc3766eba97cd0932b62e4de21503Xavier Ducrohet        // for multiple runs don't reuse older buffers.
2317aa5ce7e990dc3766eba97cd0932b62e4de21503Xavier Ducrohet        libraryDexBuffers.clear();
232f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
233f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        args = arguments;
23409dc1b7301e8b03fc6772b022d21afe9cb077d89Dan Bornstein        args.makeOptionsObjects();
235f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
236c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche        OutputStream humanOutRaw = null;
237c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche        if (args.humanOutName != null) {
238c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche            humanOutRaw = openOutput(args.humanOutName);
239c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche            humanOutWriter = new OutputStreamWriter(humanOutRaw);
240c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche        }
241c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche
242c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche        try {
243c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche            if (args.multiDex) {
244c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche                return runMultiDex();
245c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche            } else {
246c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche                return runMonoDex();
247c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche            }
248c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche        } finally {
249c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche            closeOutput(humanOutRaw);
250c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche        }
251c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche    }
252c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche
253d352de04f03b848e0246119344ea13e7233018f0Yohann Roussel    /**
254d352de04f03b848e0246119344ea13e7233018f0Yohann Roussel     * {@code non-null;} Error message for too many method/field/type ids.
255d352de04f03b848e0246119344ea13e7233018f0Yohann Roussel     */
256d352de04f03b848e0246119344ea13e7233018f0Yohann Roussel    public static String getTooManyIdsErrorMessage() {
257d352de04f03b848e0246119344ea13e7233018f0Yohann Roussel        if (args.multiDex) {
258d352de04f03b848e0246119344ea13e7233018f0Yohann Roussel            return "The list of classes given in " + Arguments.MAIN_DEX_LIST_OPTION +
259d352de04f03b848e0246119344ea13e7233018f0Yohann Roussel                   " is too big and does not fit in the main dex.";
260d352de04f03b848e0246119344ea13e7233018f0Yohann Roussel        } else {
261d352de04f03b848e0246119344ea13e7233018f0Yohann Roussel            return "You may try using " + Arguments.MULTI_DEX_OPTION + " option.";
262d352de04f03b848e0246119344ea13e7233018f0Yohann Roussel        }
263d352de04f03b848e0246119344ea13e7233018f0Yohann Roussel    }
264d352de04f03b848e0246119344ea13e7233018f0Yohann Roussel
265c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche    private static int runMonoDex() throws IOException {
266c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche
267dc520adfdcf0f0e9190cdb90605c42a7cc8fa98fDan Bornstein        File incrementalOutFile = null;
268dc520adfdcf0f0e9190cdb90605c42a7cc8fa98fDan Bornstein        if (args.incremental) {
269dc520adfdcf0f0e9190cdb90605c42a7cc8fa98fDan Bornstein            if (args.outName == null) {
270dc520adfdcf0f0e9190cdb90605c42a7cc8fa98fDan Bornstein                System.err.println(
271dc520adfdcf0f0e9190cdb90605c42a7cc8fa98fDan Bornstein                        "error: no incremental output name specified");
272dc520adfdcf0f0e9190cdb90605c42a7cc8fa98fDan Bornstein                return -1;
273dc520adfdcf0f0e9190cdb90605c42a7cc8fa98fDan Bornstein            }
274dc520adfdcf0f0e9190cdb90605c42a7cc8fa98fDan Bornstein            incrementalOutFile = new File(args.outName);
275dc520adfdcf0f0e9190cdb90605c42a7cc8fa98fDan Bornstein            if (incrementalOutFile.exists()) {
276dc520adfdcf0f0e9190cdb90605c42a7cc8fa98fDan Bornstein                minimumFileAge = incrementalOutFile.lastModified();
277dc520adfdcf0f0e9190cdb90605c42a7cc8fa98fDan Bornstein            }
278dc86cd9edc8b80953c8b698a83cdaebf6825d798Jesse Wilson        }
279dc86cd9edc8b80953c8b698a83cdaebf6825d798Jesse Wilson
280f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (!processAllFiles()) {
281f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return 1;
282f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
283f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
284dc86cd9edc8b80953c8b698a83cdaebf6825d798Jesse Wilson        if (args.incremental && !anyFilesProcessed) {
285dc86cd9edc8b80953c8b698a83cdaebf6825d798Jesse Wilson            return 0; // this was a no-op incremental build
286dc86cd9edc8b80953c8b698a83cdaebf6825d798Jesse Wilson        }
287dc86cd9edc8b80953c8b698a83cdaebf6825d798Jesse Wilson
288d2b3f499be6f5b1d4076b1244be3d1501d178315Jesse Wilson        // this array is null if no classes were defined
289d2b3f499be6f5b1d4076b1244be3d1501d178315Jesse Wilson        byte[] outArray = null;
290d2b3f499be6f5b1d4076b1244be3d1501d178315Jesse Wilson
2910820aa265488e7104ad43dc0584c01f0bfb01c7aJean-Marie Henaff        if (!outputDex.isEmpty() || (args.humanOutName != null)) {
292d2b3f499be6f5b1d4076b1244be3d1501d178315Jesse Wilson            outArray = writeDex();
293f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
294d2b3f499be6f5b1d4076b1244be3d1501d178315Jesse Wilson            if (outArray == null) {
295d2b3f499be6f5b1d4076b1244be3d1501d178315Jesse Wilson                return 2;
296d2b3f499be6f5b1d4076b1244be3d1501d178315Jesse Wilson            }
297f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
298f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
299d2b3f499be6f5b1d4076b1244be3d1501d178315Jesse Wilson        if (args.incremental) {
30009d308b04b7c4fd3ed83a8f8f4c07be67a25478cJesse Wilson            outArray = mergeIncremental(outArray, incrementalOutFile);
301dc86cd9edc8b80953c8b698a83cdaebf6825d798Jesse Wilson        }
302dc86cd9edc8b80953c8b698a83cdaebf6825d798Jesse Wilson
30309d308b04b7c4fd3ed83a8f8f4c07be67a25478cJesse Wilson        outArray = mergeLibraryDexBuffers(outArray);
30409d308b04b7c4fd3ed83a8f8f4c07be67a25478cJesse Wilson
305f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (args.jarOutput) {
306f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            // Effectively free up the (often massive) DexFile memory.
307f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            outputDex = null;
308f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
309c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche            if (outArray != null) {
310c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche                outputResources.put(DexFormat.DEX_IN_JAR_NAME, outArray);
311c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche            }
312c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche            if (!createJar(args.outName)) {
313f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                return 3;
314f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
315d2b3f499be6f5b1d4076b1244be3d1501d178315Jesse Wilson        } else if (outArray != null && args.outName != null) {
316dc86cd9edc8b80953c8b698a83cdaebf6825d798Jesse Wilson            OutputStream out = openOutput(args.outName);
317dc86cd9edc8b80953c8b698a83cdaebf6825d798Jesse Wilson            out.write(outArray);
318dc86cd9edc8b80953c8b698a83cdaebf6825d798Jesse Wilson            closeOutput(out);
319f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
320f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
321f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return 0;
322f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
323f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
324c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche    private static int runMultiDex() throws IOException {
325c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche
326c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche        assert !args.incremental;
327c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche        assert args.numThreads == 1;
328c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche
329c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche        if (args.mainDexListFile != null) {
3309747950064e4711c15baf0986102320a2512097aXavier Ducrohet            classesInMainDex = new HashSet<String>();
3319747950064e4711c15baf0986102320a2512097aXavier Ducrohet            readPathsFromFile(args.mainDexListFile, classesInMainDex);
332c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche        }
333c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche
334c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche        if (!processAllFiles()) {
335c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche            return 1;
336c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche        }
337c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche
338c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche        if (!libraryDexBuffers.isEmpty()) {
339c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche            throw new DexException("Library dex files are not supported in multi-dex mode");
340c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche        }
341c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche
342c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche        if (outputDex != null) {
343c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche            // this array is null if no classes were defined
344c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche            dexOutputArrays.add(writeDex());
345c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche
346c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche            // Effectively free up the (often massive) DexFile memory.
347c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche            outputDex = null;
348c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche        }
349c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche
350c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche        if (args.jarOutput) {
351c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche
352c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche            for (int i = 0; i < dexOutputArrays.size(); i++) {
353c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche                outputResources.put(getDexFileName(i),
354c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche                        dexOutputArrays.get(i));
355c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche            }
356c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche
357c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche            if (!createJar(args.outName)) {
358c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche                return 3;
359c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche            }
360c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche        } else if (args.outName != null) {
361c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche            File outDir = new File(args.outName);
362c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche            assert outDir.isDirectory();
363c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche            for (int i = 0; i < dexOutputArrays.size(); i++) {
364c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche                OutputStream out = new FileOutputStream(new File(outDir, getDexFileName(i)));
365c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche                try {
366c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche                    out.write(dexOutputArrays.get(i));
367c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche                } finally {
368c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche                    closeOutput(out);
369c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche                }
370c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche            }
371c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche
372c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche        }
373c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche
374c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche        return 0;
375c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche    }
376c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche
377c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche    private static String getDexFileName(int i) {
378c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche        if (i == 0) {
379c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche            return DexFormat.DEX_IN_JAR_NAME;
380c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche        } else {
381c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche            return DEX_PREFIX + (i + 1) + DEX_EXTENSION;
382c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche        }
383c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche    }
384c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche
3859747950064e4711c15baf0986102320a2512097aXavier Ducrohet    private static void readPathsFromFile(String fileName, Collection<String> paths) throws IOException {
386c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche        BufferedReader bfr = null;
387c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche        try {
3888a5d5ccc26c97d555024c36f54140f07a4b40b8cJohn Fazekas            FileReader fr = new FileReader(fileName);
389c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche            bfr = new BufferedReader(fr);
390c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche
391c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche            String line;
392c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche
393c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche            while (null != (line = bfr.readLine())) {
3948a5d5ccc26c97d555024c36f54140f07a4b40b8cJohn Fazekas                paths.add(fixPath(line));
395c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche            }
396c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche
397c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche        } finally {
398c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche            if (bfr != null) {
399c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche                bfr.close();
400c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche            }
401c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche        }
402c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche    }
403c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche
404f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
405dc86cd9edc8b80953c8b698a83cdaebf6825d798Jesse Wilson     * Merges the dex files {@code update} and {@code base}, preferring
406d2b3f499be6f5b1d4076b1244be3d1501d178315Jesse Wilson     * {@code update}'s definition for types defined in both dex files.
407d2b3f499be6f5b1d4076b1244be3d1501d178315Jesse Wilson     *
40809d308b04b7c4fd3ed83a8f8f4c07be67a25478cJesse Wilson     * @param base a file to find the previous dex file. May be a .dex file, a
40909d308b04b7c4fd3ed83a8f8f4c07be67a25478cJesse Wilson     *     jar file possibly containing a .dex file, or null.
410d2b3f499be6f5b1d4076b1244be3d1501d178315Jesse Wilson     * @return the bytes of the merged dex file, or null if both the update
411d2b3f499be6f5b1d4076b1244be3d1501d178315Jesse Wilson     *     and the base dex do not exist.
412dc86cd9edc8b80953c8b698a83cdaebf6825d798Jesse Wilson     */
41309d308b04b7c4fd3ed83a8f8f4c07be67a25478cJesse Wilson    private static byte[] mergeIncremental(byte[] update, File base) throws IOException {
414fe107fb6e3f308ac5174ebdc5a794ee880c741d9Jesse Wilson        Dex dexA = null;
415fe107fb6e3f308ac5174ebdc5a794ee880c741d9Jesse Wilson        Dex dexB = null;
416dc86cd9edc8b80953c8b698a83cdaebf6825d798Jesse Wilson
417d2b3f499be6f5b1d4076b1244be3d1501d178315Jesse Wilson        if (update != null) {
418fe107fb6e3f308ac5174ebdc5a794ee880c741d9Jesse Wilson            dexA = new Dex(update);
419d2b3f499be6f5b1d4076b1244be3d1501d178315Jesse Wilson        }
420d2b3f499be6f5b1d4076b1244be3d1501d178315Jesse Wilson
421d2b3f499be6f5b1d4076b1244be3d1501d178315Jesse Wilson        if (base.exists()) {
422fe107fb6e3f308ac5174ebdc5a794ee880c741d9Jesse Wilson            dexB = new Dex(base);
423d2b3f499be6f5b1d4076b1244be3d1501d178315Jesse Wilson        }
424d2b3f499be6f5b1d4076b1244be3d1501d178315Jesse Wilson
425fe107fb6e3f308ac5174ebdc5a794ee880c741d9Jesse Wilson        Dex result;
426d2b3f499be6f5b1d4076b1244be3d1501d178315Jesse Wilson        if (dexA == null && dexB == null) {
427d2b3f499be6f5b1d4076b1244be3d1501d178315Jesse Wilson            return null;
428d2b3f499be6f5b1d4076b1244be3d1501d178315Jesse Wilson        } else if (dexA == null) {
429d2b3f499be6f5b1d4076b1244be3d1501d178315Jesse Wilson            result = dexB;
430d2b3f499be6f5b1d4076b1244be3d1501d178315Jesse Wilson        } else if (dexB == null) {
431d2b3f499be6f5b1d4076b1244be3d1501d178315Jesse Wilson            result = dexA;
432dc86cd9edc8b80953c8b698a83cdaebf6825d798Jesse Wilson        } else {
43309d308b04b7c4fd3ed83a8f8f4c07be67a25478cJesse Wilson            result = new DexMerger(dexA, dexB, CollisionPolicy.KEEP_FIRST).merge();
434dc86cd9edc8b80953c8b698a83cdaebf6825d798Jesse Wilson        }
435dc86cd9edc8b80953c8b698a83cdaebf6825d798Jesse Wilson
436dc86cd9edc8b80953c8b698a83cdaebf6825d798Jesse Wilson        ByteArrayOutputStream bytesOut = new ByteArrayOutputStream();
437d2b3f499be6f5b1d4076b1244be3d1501d178315Jesse Wilson        result.writeTo(bytesOut);
438dc86cd9edc8b80953c8b698a83cdaebf6825d798Jesse Wilson        return bytesOut.toByteArray();
439dc86cd9edc8b80953c8b698a83cdaebf6825d798Jesse Wilson    }
440dc86cd9edc8b80953c8b698a83cdaebf6825d798Jesse Wilson
441dc86cd9edc8b80953c8b698a83cdaebf6825d798Jesse Wilson    /**
44209d308b04b7c4fd3ed83a8f8f4c07be67a25478cJesse Wilson     * Merges the dex files in library jars. If multiple dex files define the
44309d308b04b7c4fd3ed83a8f8f4c07be67a25478cJesse Wilson     * same type, this fails with an exception.
44409d308b04b7c4fd3ed83a8f8f4c07be67a25478cJesse Wilson     */
44509d308b04b7c4fd3ed83a8f8f4c07be67a25478cJesse Wilson    private static byte[] mergeLibraryDexBuffers(byte[] outArray) throws IOException {
446fe107fb6e3f308ac5174ebdc5a794ee880c741d9Jesse Wilson        for (byte[] libraryDex : libraryDexBuffers) {
44709d308b04b7c4fd3ed83a8f8f4c07be67a25478cJesse Wilson            if (outArray == null) {
448fe107fb6e3f308ac5174ebdc5a794ee880c741d9Jesse Wilson                outArray = libraryDex;
44909d308b04b7c4fd3ed83a8f8f4c07be67a25478cJesse Wilson                continue;
45009d308b04b7c4fd3ed83a8f8f4c07be67a25478cJesse Wilson            }
45109d308b04b7c4fd3ed83a8f8f4c07be67a25478cJesse Wilson
452fe107fb6e3f308ac5174ebdc5a794ee880c741d9Jesse Wilson            Dex a = new Dex(outArray);
453fe107fb6e3f308ac5174ebdc5a794ee880c741d9Jesse Wilson            Dex b = new Dex(libraryDex);
454fe107fb6e3f308ac5174ebdc5a794ee880c741d9Jesse Wilson            Dex ab = new DexMerger(a, b, CollisionPolicy.FAIL).merge();
45509d308b04b7c4fd3ed83a8f8f4c07be67a25478cJesse Wilson            outArray = ab.getBytes();
45609d308b04b7c4fd3ed83a8f8f4c07be67a25478cJesse Wilson        }
4577aa5ce7e990dc3766eba97cd0932b62e4de21503Xavier Ducrohet
45809d308b04b7c4fd3ed83a8f8f4c07be67a25478cJesse Wilson        return outArray;
45909d308b04b7c4fd3ed83a8f8f4c07be67a25478cJesse Wilson    }
46009d308b04b7c4fd3ed83a8f8f4c07be67a25478cJesse Wilson
46109d308b04b7c4fd3ed83a8f8f4c07be67a25478cJesse Wilson    /**
462f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Constructs the output {@link DexFile}, fill it in with all the
463f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * specified classes, and populate the resources map if required.
464f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
465f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @return whether processing was successful
466f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
467f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private static boolean processAllFiles() {
468c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche        createDexFile();
469f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
470f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (args.jarOutput) {
471f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            outputResources = new TreeMap<String, byte[]>();
472f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
473f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
474590f78fc4b6e3268149c5eacb7c8b7dd33497f44jeffhao        anyFilesProcessed = false;
475f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        String[] fileNames = args.fileNames;
476f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
477590f78fc4b6e3268149c5eacb7c8b7dd33497f44jeffhao        if (args.numThreads > 1) {
478590f78fc4b6e3268149c5eacb7c8b7dd33497f44jeffhao            threadPool = Executors.newFixedThreadPool(args.numThreads);
479cecacd3a4b5ab7a45340f3843522a42a0a4cf287Benoit Lamarche            parallelProcessorFutures = new ArrayList<Future<Void>>();
480590f78fc4b6e3268149c5eacb7c8b7dd33497f44jeffhao        }
481590f78fc4b6e3268149c5eacb7c8b7dd33497f44jeffhao
482f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        try {
483c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche            if (args.mainDexListFile != null) {
484c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche                // with --main-dex-list
485c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche                FileNameFilter mainPassFilter = args.strictNameCheck ? new MainDexListFilter() :
486c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche                    new BestEffortMainDexListFilter();
487c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche
488c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche                // forced in main dex
489c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche                for (int i = 0; i < fileNames.length; i++) {
490cecacd3a4b5ab7a45340f3843522a42a0a4cf287Benoit Lamarche                    processOne(fileNames[i], mainPassFilter);
491c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche                }
492c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche
493c00fafdb91760a4cdfbe9e5323b5165ab4c01b76Benoit Lamarche                if (dexOutputArrays.size() > 0) {
494c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche                    throw new DexException("Too many classes in " + Arguments.MAIN_DEX_LIST_OPTION
495c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche                            + ", main dex capacity exceeded");
496c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche                }
497c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche
498c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche                if (args.minimalMainDex) {
499c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche                    // start second pass directly in a secondary dex file.
500c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche                    createDexFile();
501c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche                }
502c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche
503c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche                // remaining files
504c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche                for (int i = 0; i < fileNames.length; i++) {
505cecacd3a4b5ab7a45340f3843522a42a0a4cf287Benoit Lamarche                    processOne(fileNames[i], new NotFilter(mainPassFilter));
506c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche                }
507c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche            } else {
508c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche                // without --main-dex-list
509c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche                for (int i = 0; i < fileNames.length; i++) {
510cecacd3a4b5ab7a45340f3843522a42a0a4cf287Benoit Lamarche                    processOne(fileNames[i], ClassPathOpener.acceptAll);
511590f78fc4b6e3268149c5eacb7c8b7dd33497f44jeffhao                }
512f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
513f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        } catch (StopProcessing ex) {
514f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            /*
5150b44e47c51b5c735283cc99b0c08cac82dba8a00delphinemartin             * Ignore it and just let the error reporting do
516f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * their things.
517f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             */
518f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
519f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
520590f78fc4b6e3268149c5eacb7c8b7dd33497f44jeffhao        if (args.numThreads > 1) {
521590f78fc4b6e3268149c5eacb7c8b7dd33497f44jeffhao            try {
522590f78fc4b6e3268149c5eacb7c8b7dd33497f44jeffhao                threadPool.shutdown();
523cecacd3a4b5ab7a45340f3843522a42a0a4cf287Benoit Lamarche                if (!threadPool.awaitTermination(600L, TimeUnit.SECONDS)) {
524cecacd3a4b5ab7a45340f3843522a42a0a4cf287Benoit Lamarche                    throw new RuntimeException("Timed out waiting for threads.");
525cecacd3a4b5ab7a45340f3843522a42a0a4cf287Benoit Lamarche                }
526590f78fc4b6e3268149c5eacb7c8b7dd33497f44jeffhao            } catch (InterruptedException ex) {
527cecacd3a4b5ab7a45340f3843522a42a0a4cf287Benoit Lamarche                threadPool.shutdownNow();
528cecacd3a4b5ab7a45340f3843522a42a0a4cf287Benoit Lamarche                throw new RuntimeException("A thread has been interrupted.");
529cecacd3a4b5ab7a45340f3843522a42a0a4cf287Benoit Lamarche            }
530cecacd3a4b5ab7a45340f3843522a42a0a4cf287Benoit Lamarche
531cecacd3a4b5ab7a45340f3843522a42a0a4cf287Benoit Lamarche            try {
532cecacd3a4b5ab7a45340f3843522a42a0a4cf287Benoit Lamarche              for (Future<?> future : parallelProcessorFutures) {
533cecacd3a4b5ab7a45340f3843522a42a0a4cf287Benoit Lamarche                future.get();
534cecacd3a4b5ab7a45340f3843522a42a0a4cf287Benoit Lamarche              }
535cecacd3a4b5ab7a45340f3843522a42a0a4cf287Benoit Lamarche            } catch (ExecutionException e) {
536cecacd3a4b5ab7a45340f3843522a42a0a4cf287Benoit Lamarche                Throwable cause = e.getCause();
537cecacd3a4b5ab7a45340f3843522a42a0a4cf287Benoit Lamarche                // All Exceptions should have been handled in the ParallelProcessor, only Errors
538cecacd3a4b5ab7a45340f3843522a42a0a4cf287Benoit Lamarche                // should remain
539cecacd3a4b5ab7a45340f3843522a42a0a4cf287Benoit Lamarche                if (cause instanceof Error) {
540cecacd3a4b5ab7a45340f3843522a42a0a4cf287Benoit Lamarche                    throw (Error) e.getCause();
541cecacd3a4b5ab7a45340f3843522a42a0a4cf287Benoit Lamarche                } else {
542cecacd3a4b5ab7a45340f3843522a42a0a4cf287Benoit Lamarche                    throw new AssertionError(e.getCause());
543cecacd3a4b5ab7a45340f3843522a42a0a4cf287Benoit Lamarche                }
544cecacd3a4b5ab7a45340f3843522a42a0a4cf287Benoit Lamarche            } catch (InterruptedException e) {
545cecacd3a4b5ab7a45340f3843522a42a0a4cf287Benoit Lamarche              // If we're here, it means all threads have completed cleanly, so there should not be
546cecacd3a4b5ab7a45340f3843522a42a0a4cf287Benoit Lamarche              // any InterruptedException
547cecacd3a4b5ab7a45340f3843522a42a0a4cf287Benoit Lamarche              throw new AssertionError(e);
548590f78fc4b6e3268149c5eacb7c8b7dd33497f44jeffhao            }
549590f78fc4b6e3268149c5eacb7c8b7dd33497f44jeffhao        }
550590f78fc4b6e3268149c5eacb7c8b7dd33497f44jeffhao
551cecacd3a4b5ab7a45340f3843522a42a0a4cf287Benoit Lamarche        int errorNum = errors.get();
552cecacd3a4b5ab7a45340f3843522a42a0a4cf287Benoit Lamarche        if (errorNum != 0) {
553cecacd3a4b5ab7a45340f3843522a42a0a4cf287Benoit Lamarche            DxConsole.err.println(errorNum + " error" +
554cecacd3a4b5ab7a45340f3843522a42a0a4cf287Benoit Lamarche                    ((errorNum == 1) ? "" : "s") + "; aborting");
555f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return false;
556f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
557f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
558dc86cd9edc8b80953c8b698a83cdaebf6825d798Jesse Wilson        if (args.incremental && !anyFilesProcessed) {
559dc86cd9edc8b80953c8b698a83cdaebf6825d798Jesse Wilson            return true;
560dc86cd9edc8b80953c8b698a83cdaebf6825d798Jesse Wilson        }
561dc86cd9edc8b80953c8b698a83cdaebf6825d798Jesse Wilson
562590f78fc4b6e3268149c5eacb7c8b7dd33497f44jeffhao        if (!(anyFilesProcessed || args.emptyOk)) {
563f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            DxConsole.err.println("no classfiles specified");
564f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return false;
565f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
566f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
567f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (args.optimize && args.statistics) {
568f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            CodeStatistics.dumpStatistics(DxConsole.out);
569f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
570f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
571f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return true;
572f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
573f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
574c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche    private static void createDexFile() {
575c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche        if (outputDex != null) {
576c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche            dexOutputArrays.add(writeDex());
577c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche        }
578c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche
579c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche        outputDex = new DexFile(args.dexOptions);
580c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche
581c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche        if (args.dumpWidth != 0) {
582c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche            outputDex.setDumpWidth(args.dumpWidth);
583c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche        }
584c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche    }
585c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche
586f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
587f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Processes one pathname element.
588f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
58955423dcd081e30c4fc27b997f127db7b00f1b981Dan Bornstein     * @param pathname {@code non-null;} the pathname to process. May
59055423dcd081e30c4fc27b997f127db7b00f1b981Dan Bornstein     * be the path of a class file, a jar file, or a directory
59155423dcd081e30c4fc27b997f127db7b00f1b981Dan Bornstein     * containing class files.
592c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche     * @param filter {@code non-null;} A filter for excluding files.
593f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
594cecacd3a4b5ab7a45340f3843522a42a0a4cf287Benoit Lamarche    private static void processOne(String pathname, FileNameFilter filter) {
595f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        ClassPathOpener opener;
596f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
597c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche        opener = new ClassPathOpener(pathname, false, filter,
598f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                new ClassPathOpener.Consumer() {
599cecacd3a4b5ab7a45340f3843522a42a0a4cf287Benoit Lamarche
600cecacd3a4b5ab7a45340f3843522a42a0a4cf287Benoit Lamarche            @Override
601dc86cd9edc8b80953c8b698a83cdaebf6825d798Jesse Wilson            public boolean processFileBytes(String name, long lastModified, byte[] bytes) {
602cecacd3a4b5ab7a45340f3843522a42a0a4cf287Benoit Lamarche                return Main.processFileBytes(name, lastModified, bytes);
603f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
604cecacd3a4b5ab7a45340f3843522a42a0a4cf287Benoit Lamarche
605cecacd3a4b5ab7a45340f3843522a42a0a4cf287Benoit Lamarche            @Override
606f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            public void onException(Exception ex) {
607f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                if (ex instanceof StopProcessing) {
608f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    throw (StopProcessing) ex;
609d0900d13fb7bb1706aff5205af7e2d6517335beejeffhao                } else if (ex instanceof SimException) {
610d0900d13fb7bb1706aff5205af7e2d6517335beejeffhao                    DxConsole.err.println("\nEXCEPTION FROM SIMULATION:");
611d0900d13fb7bb1706aff5205af7e2d6517335beejeffhao                    DxConsole.err.println(ex.getMessage() + "\n");
612d0900d13fb7bb1706aff5205af7e2d6517335beejeffhao                    DxConsole.err.println(((SimException) ex).getContext());
613d0900d13fb7bb1706aff5205af7e2d6517335beejeffhao                } else {
614d0900d13fb7bb1706aff5205af7e2d6517335beejeffhao                    DxConsole.err.println("\nUNEXPECTED TOP-LEVEL EXCEPTION:");
615d0900d13fb7bb1706aff5205af7e2d6517335beejeffhao                    ex.printStackTrace(DxConsole.err);
616f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
617cecacd3a4b5ab7a45340f3843522a42a0a4cf287Benoit Lamarche                errors.incrementAndGet();
618f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
619cecacd3a4b5ab7a45340f3843522a42a0a4cf287Benoit Lamarche
620cecacd3a4b5ab7a45340f3843522a42a0a4cf287Benoit Lamarche            @Override
621f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            public void onProcessArchiveStart(File file) {
622f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                if (args.verbose) {
62355423dcd081e30c4fc27b997f127db7b00f1b981Dan Bornstein                    DxConsole.out.println("processing archive " + file +
62455423dcd081e30c4fc27b997f127db7b00f1b981Dan Bornstein                            "...");
625f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
626f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
627f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        });
628f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
629cecacd3a4b5ab7a45340f3843522a42a0a4cf287Benoit Lamarche        if (args.numThreads > 1) {
630cecacd3a4b5ab7a45340f3843522a42a0a4cf287Benoit Lamarche            parallelProcessorFutures.add(threadPool.submit(new ParallelProcessor(opener)));
631cecacd3a4b5ab7a45340f3843522a42a0a4cf287Benoit Lamarche        } else {
632cecacd3a4b5ab7a45340f3843522a42a0a4cf287Benoit Lamarche            if (opener.process()) {
633cecacd3a4b5ab7a45340f3843522a42a0a4cf287Benoit Lamarche                anyFilesProcessed = true;
634cecacd3a4b5ab7a45340f3843522a42a0a4cf287Benoit Lamarche            }
635cecacd3a4b5ab7a45340f3843522a42a0a4cf287Benoit Lamarche        }
636f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
637f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
638f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
639f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Processes one file, which may be either a class or a resource.
640f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
64199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @param name {@code non-null;} name of the file
64299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @param bytes {@code non-null;} contents of the file
643f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @return whether processing was successful
644f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
645dc86cd9edc8b80953c8b698a83cdaebf6825d798Jesse Wilson    private static boolean processFileBytes(String name, long lastModified, byte[] bytes) {
646f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        boolean isClass = name.endsWith(".class");
64709d308b04b7c4fd3ed83a8f8f4c07be67a25478cJesse Wilson        boolean isClassesDex = name.equals(DexFormat.DEX_IN_JAR_NAME);
648f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        boolean keepResources = (outputResources != null);
649f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
65009d308b04b7c4fd3ed83a8f8f4c07be67a25478cJesse Wilson        if (!isClass && !isClassesDex && !keepResources) {
651f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (args.verbose) {
652f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                DxConsole.out.println("ignored resource " + name);
653f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
654f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return false;
655f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
656f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
657f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (args.verbose) {
658f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            DxConsole.out.println("processing " + name + "...");
659f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
660f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
661f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        String fixedName = fixPath(name);
662f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
663f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (isClass) {
664c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche
665f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (keepResources && args.keepClassesInJar) {
666590f78fc4b6e3268149c5eacb7c8b7dd33497f44jeffhao                synchronized (outputResources) {
667590f78fc4b6e3268149c5eacb7c8b7dd33497f44jeffhao                    outputResources.put(fixedName, bytes);
668590f78fc4b6e3268149c5eacb7c8b7dd33497f44jeffhao                }
669f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
670dc86cd9edc8b80953c8b698a83cdaebf6825d798Jesse Wilson            if (lastModified < minimumFileAge) {
671dc86cd9edc8b80953c8b698a83cdaebf6825d798Jesse Wilson                return true;
672dc86cd9edc8b80953c8b698a83cdaebf6825d798Jesse Wilson            }
673f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return processClass(fixedName, bytes);
67409d308b04b7c4fd3ed83a8f8f4c07be67a25478cJesse Wilson        } else if (isClassesDex) {
67509d308b04b7c4fd3ed83a8f8f4c07be67a25478cJesse Wilson            synchronized (libraryDexBuffers) {
67609d308b04b7c4fd3ed83a8f8f4c07be67a25478cJesse Wilson                libraryDexBuffers.add(bytes);
67709d308b04b7c4fd3ed83a8f8f4c07be67a25478cJesse Wilson            }
67809d308b04b7c4fd3ed83a8f8f4c07be67a25478cJesse Wilson            return true;
679f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        } else {
680590f78fc4b6e3268149c5eacb7c8b7dd33497f44jeffhao            synchronized (outputResources) {
681590f78fc4b6e3268149c5eacb7c8b7dd33497f44jeffhao                outputResources.put(fixedName, bytes);
682590f78fc4b6e3268149c5eacb7c8b7dd33497f44jeffhao            }
683f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return true;
684f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
685f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
686f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
687f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
688f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Processes one classfile.
689f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
69099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @param name {@code non-null;} name of the file, clipped such that it
691f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * <i>should</i> correspond to the name of the class it contains
69299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @param bytes {@code non-null;} contents of the file
693f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @return whether processing was successful
694f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
695f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private static boolean processClass(String name, byte[] bytes) {
696f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (! args.coreLibrary) {
697f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            checkClassName(name);
698f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
699de75089fb7216d19e9c22cce4dc62a49513477d3Carl Shapiro
700c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche        DirectClassFile cf =
701c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche            new DirectClassFile(bytes, name, args.cfOptions.strictNameCheck);
702c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche
703c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche        cf.setAttributeFactory(StdAttributeFactory.THE_ONE);
704c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche        cf.getMagic();
705c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche
706c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche        int numMethodIds = outputDex.getMethodIds().items().size();
707c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche        int numFieldIds = outputDex.getFieldIds().items().size();
708c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche        int constantPoolSize = cf.getConstantPool().size();
709c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche
710466d7d94b8b173a323fc5616837940219a216f9dYohann Roussel        int maxMethodIdsInDex = numMethodIds + constantPoolSize + cf.getMethods().size() +
711466d7d94b8b173a323fc5616837940219a216f9dYohann Roussel                MAX_METHOD_ADDED_DURING_DEX_CREATION;
712466d7d94b8b173a323fc5616837940219a216f9dYohann Roussel        int maxFieldIdsInDex = numFieldIds + constantPoolSize + cf.getFields().size() +
713466d7d94b8b173a323fc5616837940219a216f9dYohann Roussel                MAX_FIELD_ADDED_DURING_DEX_CREATION;
714466d7d94b8b173a323fc5616837940219a216f9dYohann Roussel
715084b7f109aa96a86a267074f5464732b8062bd5aYohann Roussel        if (args.multiDex
716084b7f109aa96a86a267074f5464732b8062bd5aYohann Roussel            // Never switch to the next dex if current dex is already empty
717084b7f109aa96a86a267074f5464732b8062bd5aYohann Roussel            && (outputDex.getClassDefs().items().size() > 0)
718084b7f109aa96a86a267074f5464732b8062bd5aYohann Roussel            && ((maxMethodIdsInDex > args.maxNumberOfIdxPerDex) ||
719466d7d94b8b173a323fc5616837940219a216f9dYohann Roussel                (maxFieldIdsInDex > args.maxNumberOfIdxPerDex))) {
720466d7d94b8b173a323fc5616837940219a216f9dYohann Roussel            DexFile completeDex = outputDex;
721466d7d94b8b173a323fc5616837940219a216f9dYohann Roussel            createDexFile();
722466d7d94b8b173a323fc5616837940219a216f9dYohann Roussel            assert  (completeDex.getMethodIds().items().size() <= numMethodIds +
723466d7d94b8b173a323fc5616837940219a216f9dYohann Roussel                    MAX_METHOD_ADDED_DURING_DEX_CREATION) &&
724466d7d94b8b173a323fc5616837940219a216f9dYohann Roussel                    (completeDex.getFieldIds().items().size() <= numFieldIds +
725466d7d94b8b173a323fc5616837940219a216f9dYohann Roussel                    MAX_FIELD_ADDED_DURING_DEX_CREATION);
726c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche        }
727c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche
728f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        try {
729f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            ClassDefItem clazz =
730c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche                CfTranslator.translate(cf, bytes, args.cfOptions, args.dexOptions, outputDex);
731590f78fc4b6e3268149c5eacb7c8b7dd33497f44jeffhao            synchronized (outputDex) {
732590f78fc4b6e3268149c5eacb7c8b7dd33497f44jeffhao                outputDex.add(clazz);
733590f78fc4b6e3268149c5eacb7c8b7dd33497f44jeffhao            }
734f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return true;
735c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche
736f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        } catch (ParseException ex) {
737f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            DxConsole.err.println("\ntrouble processing:");
738f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (args.debug) {
739f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                ex.printStackTrace(DxConsole.err);
740f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            } else {
741f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                ex.printContext(DxConsole.err);
742f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
743f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
744cecacd3a4b5ab7a45340f3843522a42a0a4cf287Benoit Lamarche        errors.incrementAndGet();
745f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return false;
746f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
747f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
748f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
749f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Check the class name to make sure it's not a "core library"
750f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * class. If there is a problem, this updates the error count and
751f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * throws an exception to stop processing.
752de75089fb7216d19e9c22cce4dc62a49513477d3Carl Shapiro     *
75355423dcd081e30c4fc27b997f127db7b00f1b981Dan Bornstein     * @param name {@code non-null;} the fully-qualified internal-form
75455423dcd081e30c4fc27b997f127db7b00f1b981Dan Bornstein     * class name
755f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
756f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private static void checkClassName(String name) {
757f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        boolean bogus = false;
758de75089fb7216d19e9c22cce4dc62a49513477d3Carl Shapiro
759f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (name.startsWith("java/")) {
760f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            bogus = true;
761f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        } else if (name.startsWith("javax/")) {
762f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            int slashAt = name.indexOf('/', 6);
763f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (slashAt == -1) {
764f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                // Top-level javax classes are verboten.
765f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                bogus = true;
766f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            } else {
767f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                String pkg = name.substring(6, slashAt);
768f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                bogus = (Arrays.binarySearch(JAVAX_CORE, pkg) >= 0);
769f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
770f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
771f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
772f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (! bogus) {
773f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return;
774f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
775f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
776f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /*
777f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * The user is probably trying to include an entire desktop
778f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * core library in a misguided attempt to get their application
779f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * working. Try to help them understand what's happening.
780f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
781f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
78285dc40d2a0cb19792bf3ee6f6c57fed08eb91ea4Dan Bornstein        DxConsole.err.println("\ntrouble processing \"" + name + "\":\n\n" +
78385dc40d2a0cb19792bf3ee6f6c57fed08eb91ea4Dan Bornstein                IN_RE_CORE_CLASSES);
784cecacd3a4b5ab7a45340f3843522a42a0a4cf287Benoit Lamarche        errors.incrementAndGet();
785f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        throw new StopProcessing();
786f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
787f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
788f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
789dc86cd9edc8b80953c8b698a83cdaebf6825d798Jesse Wilson     * Converts {@link #outputDex} into a {@code byte[]} and do whatever
790dc86cd9edc8b80953c8b698a83cdaebf6825d798Jesse Wilson     * human-oriented dumping is required.
791f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
79299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @return {@code null-ok;} the converted {@code byte[]} or {@code null}
793f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * if there was a problem
794f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
795f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private static byte[] writeDex() {
796f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        byte[] outArray = null;
797f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
798f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        try {
799f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            try {
800f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                if (args.methodToDump != null) {
801f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    /*
802f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                     * Simply dump the requested method. Note: The call
803f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                     * to toDex() is required just to get the underlying
804f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                     * structures ready.
805f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                     */
806f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    outputDex.toDex(null, false);
807c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche                    dumpMethod(outputDex, args.methodToDump, humanOutWriter);
808f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                } else {
809f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    /*
810f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                     * This is the usual case: Create an output .dex file,
811f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                     * and write it, dump it, etc.
812f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                     */
813c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche                    outArray = outputDex.toDex(humanOutWriter, args.verboseDump);
814f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
815f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
816f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                if (args.statistics) {
817f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    DxConsole.out.println(outputDex.getStatistics().toHuman());
818f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
819f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            } finally {
820c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche                if (humanOutWriter != null) {
821c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche                    humanOutWriter.flush();
822f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
823f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
824f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        } catch (Exception ex) {
825f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (args.debug) {
826f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                DxConsole.err.println("\ntrouble writing output:");
827f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                ex.printStackTrace(DxConsole.err);
828f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            } else {
829f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                DxConsole.err.println("\ntrouble writing output: " +
830f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                                   ex.getMessage());
831f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
832f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return null;
833f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
834f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
835f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return outArray;
836f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
837f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
838f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
839c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche     * Creates a jar file from the resources (including dex file arrays).
840f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
84199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @param fileName {@code non-null;} name of the file
842f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @return whether the creation was successful
843f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
844c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche    private static boolean createJar(String fileName) {
845f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /*
846f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * Make or modify the manifest (as appropriate), put the dex
847f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * array into the resources map, and then process the entire
848f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * resources map in a uniform manner.
849f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
850f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
851f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        try {
852f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            Manifest manifest = makeManifest();
853f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            OutputStream out = openOutput(fileName);
854f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            JarOutputStream jarOut = new JarOutputStream(out, manifest);
855f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
856f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            try {
857f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                for (Map.Entry<String, byte[]> e :
858f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                         outputResources.entrySet()) {
859f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    String name = e.getKey();
860f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    byte[] contents = e.getValue();
861f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    JarEntry entry = new JarEntry(name);
862c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche                    int length = contents.length;
863f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
864f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    if (args.verbose) {
865c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche                        DxConsole.out.println("writing " + name + "; size " + length + "...");
866f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    }
867f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
868c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche                    entry.setSize(length);
869f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    jarOut.putNextEntry(entry);
870f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    jarOut.write(contents);
871f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    jarOut.closeEntry();
872f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
873f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            } finally {
874f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                jarOut.finish();
875f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                jarOut.flush();
876f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                closeOutput(out);
877f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
878f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        } catch (Exception ex) {
879f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (args.debug) {
880f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                DxConsole.err.println("\ntrouble writing output:");
881f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                ex.printStackTrace(DxConsole.err);
882f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            } else {
883f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                DxConsole.err.println("\ntrouble writing output: " +
884f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                                   ex.getMessage());
885f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
886f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return false;
887f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
888f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
889f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return true;
890f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
891f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
892f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
893f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Creates and returns the manifest to use for the output. This may
894f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * modify {@link #outputResources} (removing the pre-existing manifest).
895f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
89699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @return {@code non-null;} the manifest
897f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
898f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private static Manifest makeManifest() throws IOException {
899f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        byte[] manifestBytes = outputResources.get(MANIFEST_NAME);
900f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        Manifest manifest;
901f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        Attributes attribs;
902f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
903f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (manifestBytes == null) {
904f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            // We need to construct an entirely new manifest.
905f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            manifest = new Manifest();
906f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            attribs = manifest.getMainAttributes();
907f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            attribs.put(Attributes.Name.MANIFEST_VERSION, "1.0");
908f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        } else {
909f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            manifest = new Manifest(new ByteArrayInputStream(manifestBytes));
910f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            attribs = manifest.getMainAttributes();
911f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            outputResources.remove(MANIFEST_NAME);
912f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
913f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
914f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        String createdBy = attribs.getValue(CREATED_BY);
915f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (createdBy == null) {
916f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            createdBy = "";
917f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        } else {
918f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            createdBy += " + ";
919f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
920f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        createdBy += "dx " + Version.VERSION;
921f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
922f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        attribs.put(CREATED_BY, createdBy);
923dc86cd9edc8b80953c8b698a83cdaebf6825d798Jesse Wilson        attribs.putValue("Dex-Location", DexFormat.DEX_IN_JAR_NAME);
924f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
925f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return manifest;
926f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
927f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
928f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
929f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Opens and returns the named file for writing, treating "-" specially.
930f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
93199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @param name {@code non-null;} the file name
93299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @return {@code non-null;} the opened file
933f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
934f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private static OutputStream openOutput(String name) throws IOException {
935f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (name.equals("-") ||
936f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                name.startsWith("-.")) {
937f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return System.out;
938f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
939f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
940f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return new FileOutputStream(name);
941f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
942f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
943f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
944f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Flushes and closes the given output stream, except if it happens to be
945f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * {@link System#out} in which case this method does the flush but not
946f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * the close. This method will also silently do nothing if given a
94799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * {@code null} argument.
948f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
94999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @param stream {@code null-ok;} what to close
950f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
951f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private static void closeOutput(OutputStream stream) throws IOException {
952f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (stream == null) {
953f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return;
954f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
955f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
956f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        stream.flush();
957f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
958f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (stream != System.out) {
959f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            stream.close();
960f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
961f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
962f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
963f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
964f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Returns the "fixed" version of a given file path, suitable for
96599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * use as a path within a {@code .jar} file and for checking
966f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * against a classfile-internal "this class" name. This looks for
96799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * the last instance of the substring {@code "/./"} within
968f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * the path, and if it finds it, it takes the portion after to be
969f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * the fixed path. If that isn't found but the path starts with
97099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * {@code "./"}, then that prefix is removed and the rest is
971f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * return. If neither of these is the case, this method returns
972f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * its argument.
973f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
97499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @param path {@code non-null;} the path to "fix"
97599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @return {@code non-null;} the fixed version (which might be the same as
97699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * the given {@code path})
977f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
978f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private static String fixPath(String path) {
979f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /*
980f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * If the path separator is \ (like on windows), we convert the
981f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * path to a standard '/' separated path.
982f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
983f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (File.separatorChar == '\\') {
984f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            path = path.replace('\\', '/');
985f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
986f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
987f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int index = path.lastIndexOf("/./");
988f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
989f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (index != -1) {
990f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return path.substring(index + 3);
991f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
992f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
993f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (path.startsWith("./")) {
994f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return path.substring(2);
995f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
996f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
997f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return path;
998f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
999f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1000f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
1001f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Dumps any method with the given name in the given file.
1002f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
100399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @param dex {@code non-null;} the dex file
100455423dcd081e30c4fc27b997f127db7b00f1b981Dan Bornstein     * @param fqName {@code non-null;} the fully-qualified name of the
100555423dcd081e30c4fc27b997f127db7b00f1b981Dan Bornstein     * method(s)
100699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @param out {@code non-null;} where to dump to
1007f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
1008f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private static void dumpMethod(DexFile dex, String fqName,
1009f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            OutputStreamWriter out) {
1010f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        boolean wildcard = fqName.endsWith("*");
1011f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int lastDot = fqName.lastIndexOf('.');
1012f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1013f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if ((lastDot <= 0) || (lastDot == (fqName.length() - 1))) {
1014f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            DxConsole.err.println("bogus fully-qualified method name: " +
1015f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                               fqName);
1016f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return;
1017f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
1018f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1019f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        String className = fqName.substring(0, lastDot).replace('.', '/');
1020f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        String methodName = fqName.substring(lastDot + 1);
1021f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        ClassDefItem clazz = dex.getClassOrNull(className);
1022f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1023f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (clazz == null) {
1024f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            DxConsole.err.println("no such class: " + className);
1025f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return;
1026f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
1027f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1028f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (wildcard) {
1029f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            methodName = methodName.substring(0, methodName.length() - 1);
1030f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
1031f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1032f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        ArrayList<EncodedMethod> allMeths = clazz.getMethods();
1033f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        TreeMap<CstNat, EncodedMethod> meths =
1034f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            new TreeMap<CstNat, EncodedMethod>();
1035f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1036f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /*
1037f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * Figure out which methods to include in the output, and get them
1038f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * all sorted, so that the printout code is robust with respect to
1039f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * changes in the underlying order.
1040f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
1041f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        for (EncodedMethod meth : allMeths) {
1042f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            String methName = meth.getName().getString();
1043f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if ((wildcard && methName.startsWith(methodName)) ||
1044f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                (!wildcard && methName.equals(methodName))) {
1045f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                meths.put(meth.getRef().getNat(), meth);
1046f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
1047f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
1048f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1049f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (meths.size() == 0) {
1050f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            DxConsole.err.println("no such method: " + fqName);
1051f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return;
1052f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
1053f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1054f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        PrintWriter pw = new PrintWriter(out);
1055f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1056f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        for (EncodedMethod meth : meths.values()) {
1057f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            // TODO: Better stuff goes here, perhaps.
1058f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            meth.debugPrint(pw, args.verboseDump);
1059f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1060f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            /*
1061de75089fb7216d19e9c22cce4dc62a49513477d3Carl Shapiro             * The (default) source file is an attribute of the class, but
1062f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * it's useful to see it in method dumps.
1063f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             */
1064333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson            CstString sourceFile = clazz.getSourceFile();
1065f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (sourceFile != null) {
1066f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                pw.println("  source file: " + sourceFile.toQuoted());
1067f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
1068f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1069f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            Annotations methodAnnotations =
1070f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                clazz.getMethodAnnotations(meth.getRef());
1071f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            AnnotationsList parameterAnnotations =
1072f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                clazz.getParameterAnnotations(meth.getRef());
1073f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1074f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (methodAnnotations != null) {
1075f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                pw.println("  method annotations:");
1076f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                for (Annotation a : methodAnnotations.getAnnotations()) {
1077f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    pw.println("    " + a);
1078f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
1079f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
1080f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1081f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (parameterAnnotations != null) {
1082f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                pw.println("  parameter annotations:");
1083f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                int sz = parameterAnnotations.size();
1084f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                for (int i = 0; i < sz; i++) {
1085f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    pw.println("    parameter " + i);
1086f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    Annotations annotations = parameterAnnotations.get(i);
1087f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    for (Annotation a : annotations.getAnnotations()) {
1088f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        pw.println("      " + a);
1089f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    }
1090f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
1091f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
1092f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
1093f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1094f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        pw.flush();
1095f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
1096f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1097c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche    private static class NotFilter implements FileNameFilter {
1098c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche        private final FileNameFilter filter;
1099c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche
1100c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche        private NotFilter(FileNameFilter filter) {
1101c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche            this.filter = filter;
1102c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche        }
1103c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche
1104c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche        @Override
1105c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche        public boolean accept(String path) {
1106c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche            return !filter.accept(path);
1107c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche        }
1108c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche    }
1109c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche
1110c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche    /**
1111c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche     * A quick and accurate filter for when file path can be trusted.
1112c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche     */
1113c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche    private static class MainDexListFilter implements FileNameFilter {
1114c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche
1115c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche        @Override
1116c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche        public boolean accept(String fullPath) {
1117c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche            if (fullPath.endsWith(".class")) {
1118c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche                String path = fixPath(fullPath);
1119c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche                return classesInMainDex.contains(path);
1120c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche            } else {
1121c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche                return true;
1122c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche            }
1123c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche        }
1124c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche    }
1125c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche
1126c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche    /**
1127c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche     * A best effort conservative filter for when file path can <b>not</b> be trusted.
1128c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche     */
1129c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche    private static class BestEffortMainDexListFilter implements FileNameFilter {
1130c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche
1131c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche       Map<String, List<String>> map = new HashMap<String, List<String>>();
1132c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche
1133c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche       public BestEffortMainDexListFilter() {
1134c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche           for (String pathOfClass : classesInMainDex) {
1135c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche               String normalized = fixPath(pathOfClass);
1136c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche               String simple = getSimpleName(normalized);
1137c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche               List<String> fullPath = map.get(simple);
1138c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche               if (fullPath == null) {
1139c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche                   fullPath = new ArrayList<String>(1);
1140c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche                   map.put(simple, fullPath);
1141c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche               }
1142c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche               fullPath.add(normalized);
1143c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche           }
1144c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche        }
1145c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche
1146c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche        @Override
1147c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche        public boolean accept(String path) {
1148c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche            if (path.endsWith(".class")) {
1149c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche                String normalized = fixPath(path);
1150c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche                String simple = getSimpleName(normalized);
1151c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche                List<String> fullPaths = map.get(simple);
1152c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche                if (fullPaths != null) {
1153c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche                    for (String fullPath : fullPaths) {
1154c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche                        if (normalized.endsWith(fullPath)) {
1155c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche                            return true;
1156c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche                        }
1157c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche                    }
1158c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche                }
1159ad27e19691c6723a801b127f8802f5cdf4f44359Yohann Roussel                return false;
1160ad27e19691c6723a801b127f8802f5cdf4f44359Yohann Roussel            } else {
1161ad27e19691c6723a801b127f8802f5cdf4f44359Yohann Roussel                return true;
1162c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche            }
1163c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche        }
1164c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche
1165c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche        private static String getSimpleName(String path) {
1166c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche            int index = path.lastIndexOf('/');
1167c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche            if (index >= 0) {
1168c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche                return path.substring(index + 1);
1169c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche            } else {
1170c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche                return path;
1171c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche            }
1172c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche        }
1173c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche    }
1174c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche
1175f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
1176f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Exception class used to halt processing prematurely.
1177f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
1178f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private static class StopProcessing extends RuntimeException {
1179f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        // This space intentionally left blank.
1180f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
1181de75089fb7216d19e9c22cce4dc62a49513477d3Carl Shapiro
1182f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
1183f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Command-line argument parser and access.
1184f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
1185f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public static class Arguments {
1186c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche
1187c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche        private static final String MINIMAL_MAIN_DEX_OPTION = "--minimal-main-dex";
1188c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche
1189c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche        private static final String MAIN_DEX_LIST_OPTION = "--main-dex-list";
1190c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche
1191c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche        private static final String MULTI_DEX_OPTION = "--multi-dex";
1192c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche
1193c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche        private static final String NUM_THREADS_OPTION = "--num-threads";
1194c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche
1195c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche        private static final String INCREMENTAL_OPTION = "--incremental";
1196c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche
11978a5d5ccc26c97d555024c36f54140f07a4b40b8cJohn Fazekas        private static final String INPUT_LIST_OPTION = "--input-list";
11988a5d5ccc26c97d555024c36f54140f07a4b40b8cJohn Fazekas
1199f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /** whether to run in debug mode */
1200f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        public boolean debug = false;
1201f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1202f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /** whether to emit high-level verbose human-oriented output */
1203f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        public boolean verbose = false;
1204f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1205f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /** whether to emit verbose human-oriented output in the dump file */
1206f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        public boolean verboseDump = false;
1207f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1208f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /** whether we are constructing a core library */
1209f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        public boolean coreLibrary = false;
1210f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
121199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        /** {@code null-ok;} particular method to dump */
1212f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        public String methodToDump = null;
1213f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1214f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /** max width for columnar output */
1215f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        public int dumpWidth = 0;
1216f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
121799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        /** {@code null-ok;} output file name for binary file */
1218f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        public String outName = null;
1219f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
122099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        /** {@code null-ok;} output file name for human-oriented dump */
1221f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        public String humanOutName = null;
1222f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1223f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /** whether strict file-name-vs-class-name checking should be done */
1224f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        public boolean strictNameCheck = true;
1225f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1226f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /**
122799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project         * whether it is okay for there to be no {@code .class} files
1228f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * to process
1229f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
1230f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        public boolean emptyOk = false;
1231f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1232f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /**
123399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project         * whether the binary output is to be a {@code .jar} file
123499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project         * instead of a plain {@code .dex}
1235f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
1236f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        public boolean jarOutput = false;
1237f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1238f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /**
123999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project         * when writing a {@code .jar} file, whether to still
124099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project         * keep the {@code .class} files
1241f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
1242f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        public boolean keepClassesInJar = false;
1243f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1244f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /** how much source position info to preserve */
1245f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        public int positionInfo = PositionList.LINES;
1246f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1247f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /** whether to keep local variable information */
1248f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        public boolean localInfo = true;
1249f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1250dc86cd9edc8b80953c8b698a83cdaebf6825d798Jesse Wilson        /** whether to merge with the output dex file if it exists. */
1251dc86cd9edc8b80953c8b698a83cdaebf6825d798Jesse Wilson        public boolean incremental = false;
1252dc86cd9edc8b80953c8b698a83cdaebf6825d798Jesse Wilson
1253f870f2dce9300c8dec620613371f08e5c234245bjeffhao        /** whether to force generation of const-string/jumbo for all indexes,
1254f870f2dce9300c8dec620613371f08e5c234245bjeffhao         *  to allow merges between dex files with many strings. */
1255f870f2dce9300c8dec620613371f08e5c234245bjeffhao        public boolean forceJumbo = false;
1256f870f2dce9300c8dec620613371f08e5c234245bjeffhao
12573dfda9ad1964510e4a7948a240b30cd710e86341Dan Bornstein        /** {@code non-null} after {@link #parse}; file name arguments */
1258f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        public String[] fileNames;
1259f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1260f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /** whether to do SSA/register optimization */
1261f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        public boolean optimize = true;
1262f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1263f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /** Filename containg list of methods to optimize */
1264f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        public String optimizeListFile = null;
1265f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1266f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /** Filename containing list of methods to NOT optimize */
1267f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        public String dontOptimizeListFile = null;
1268f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1269f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /** Whether to print statistics to stdout at end of compile cycle */
1270f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        public boolean statistics;
1271f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
12723dfda9ad1964510e4a7948a240b30cd710e86341Dan Bornstein        /** Options for class file transformation */
1273f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        public CfOptions cfOptions;
1274f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
12753dfda9ad1964510e4a7948a240b30cd710e86341Dan Bornstein        /** Options for dex file output */
12763dfda9ad1964510e4a7948a240b30cd710e86341Dan Bornstein        public DexOptions dexOptions;
12773dfda9ad1964510e4a7948a240b30cd710e86341Dan Bornstein
1278590f78fc4b6e3268149c5eacb7c8b7dd33497f44jeffhao        /** number of threads to run with */
1279590f78fc4b6e3268149c5eacb7c8b7dd33497f44jeffhao        public int numThreads = 1;
1280590f78fc4b6e3268149c5eacb7c8b7dd33497f44jeffhao
1281c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche        /** generation of multiple dex is allowed */
1282c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche        public boolean multiDex = false;
1283c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche
1284c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche        /** Optional file containing a list of class files containing classes to be forced in main
1285c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche         * dex */
1286c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche        public String mainDexListFile = null;
1287c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche
1288c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche        /** Produce the smallest possible main dex. Ignored unless multiDex is true and
1289c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche         * mainDexListFile is specified and non empty. */
1290c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche        public boolean minimalMainDex = false;
1291c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche
12928a5d5ccc26c97d555024c36f54140f07a4b40b8cJohn Fazekas        /** Optional list containing inputs read in from a file. */
12939747950064e4711c15baf0986102320a2512097aXavier Ducrohet        private List<String> inputList = null;
12948a5d5ccc26c97d555024c36f54140f07a4b40b8cJohn Fazekas
1295c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche        private int maxNumberOfIdxPerDex = DexFormat.MAX_MEMBER_IDX + 1;
1296c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche
12971e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll        private static class ArgumentsParser {
12981e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll
12991e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll            /** The arguments to process. */
13001e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll            private final String[] arguments;
13011e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll            /** The index of the next argument to process. */
13021e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll            private int index;
13031e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll            /** The current argument being processed after a {@link #getNext()} call. */
13041e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll            private String current;
13051e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll            /** The last value of an argument processed by {@link #isArg(String)}. */
13061e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll            private String lastValue;
13071e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll
13081e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll            public ArgumentsParser(String[] arguments) {
13091e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                this.arguments = arguments;
13101e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                index = 0;
13111e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll            }
13121e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll
13131e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll            public String getCurrent() {
13141e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                return current;
13151e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll            }
13161e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll
13171e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll            public String getLastValue() {
13181e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                return lastValue;
13191e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll            }
13201e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll
13211e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll            /**
13221e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll             * Moves on to the next argument.
13231e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll             * Returns false when we ran out of arguments that start with --.
13241e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll             */
13251e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll            public boolean getNext() {
13261e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                if (index >= arguments.length) {
13271e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                    return false;
13281e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                }
13291e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                current = arguments[index];
13301e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                if (current.equals("--") || !current.startsWith("--")) {
13311e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                    return false;
13321e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                }
13331e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                index++;
13341e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                return true;
13351e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll            }
13361e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll
13371e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll            /**
13381e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll             * Similar to {@link #getNext()}, this moves on the to next argument.
13391e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll             * It does not check however whether the argument starts with --
13401e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll             * and thus can be used to retrieve values.
13411e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll             */
13421e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll            private boolean getNextValue() {
13431e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                if (index >= arguments.length) {
13441e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                    return false;
13451e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                }
13461e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                current = arguments[index];
13471e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                index++;
13481e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                return true;
13491e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll            }
13501e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll
13511e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll            /**
13521e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll             * Returns all the arguments that have not been processed yet.
13531e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll             */
13541e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll            public String[] getRemaining() {
13551e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                int n = arguments.length - index;
13561e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                String[] remaining = new String[n];
13571e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                if (n > 0) {
13581e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                    System.arraycopy(arguments, index, remaining, 0, n);
13591e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                }
13601e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                return remaining;
13611e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll            }
13621e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll
13631e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll            /**
13641e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll             * Checks the current argument against the given prefix.
13651e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll             * If prefix is in the form '--name=', an extra value is expected.
13661e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll             * The argument can then be in the form '--name=value' or as a 2-argument
13671e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll             * form '--name value'.
13681e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll             */
13691e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll            public boolean isArg(String prefix) {
13701e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                int n = prefix.length();
13711e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                if (n > 0 && prefix.charAt(n-1) == '=') {
13721e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                    // Argument accepts a value. Capture it.
13731e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                    if (current.startsWith(prefix)) {
13741e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                        // Argument is in the form --name=value, split the value out
13751e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                        lastValue = current.substring(n);
13761e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                        return true;
13771e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                    } else {
13781e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                        // Check whether we have "--name value" as 2 arguments
13791e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                        prefix = prefix.substring(0, n-1);
13801e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                        if (current.equals(prefix)) {
13811e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                            if (getNextValue()) {
13821e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                                lastValue = current;
13831e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                                return true;
13841e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                            } else {
13851e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                                System.err.println("Missing value after parameter " + prefix);
13861e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                                throw new UsageException();
13871e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                            }
13881e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                        }
13891e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                        return false;
13901e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                    }
13911e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                } else {
13921e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                    // Argument does not accept a value.
13931e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                    return current.equals(prefix);
13941e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                }
13951e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll            }
13961e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll        }
13971e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll
1398f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /**
1399f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * Parses the given command-line arguments.
1400f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         *
140199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project         * @param args {@code non-null;} the arguments
1402f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
1403f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        public void parse(String[] args) {
14041e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll            ArgumentsParser parser = new ArgumentsParser(args);
1405f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1406c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche            boolean outputIsDirectory = false;
1407c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche            boolean outputIsDirectDex = false;
1408c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche
14091e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll            while(parser.getNext()) {
14101e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                if (parser.isArg("--debug")) {
1411f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    debug = true;
14121e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                } else if (parser.isArg("--verbose")) {
1413f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    verbose = true;
14141e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                } else if (parser.isArg("--verbose-dump")) {
1415f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    verboseDump = true;
14161e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                } else if (parser.isArg("--no-files")) {
1417f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    emptyOk = true;
14181e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                } else if (parser.isArg("--no-optimize")) {
1419f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    optimize = false;
14201e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                } else if (parser.isArg("--no-strict")) {
1421f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    strictNameCheck = false;
14221e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                } else if (parser.isArg("--core-library")) {
1423f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    coreLibrary = true;
14241e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                } else if (parser.isArg("--statistics")) {
1425f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    statistics = true;
14261e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                } else if (parser.isArg("--optimize-list=")) {
1427f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    if (dontOptimizeListFile != null) {
1428f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        System.err.println("--optimize-list and "
1429f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                                + "--no-optimize-list are incompatible.");
1430f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        throw new UsageException();
1431f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    }
1432f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    optimize = true;
14331e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                    optimizeListFile = parser.getLastValue();
14341e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                } else if (parser.isArg("--no-optimize-list=")) {
1435f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    if (dontOptimizeListFile != null) {
1436f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        System.err.println("--optimize-list and "
1437f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                                + "--no-optimize-list are incompatible.");
1438f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        throw new UsageException();
1439f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    }
1440f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    optimize = true;
14411e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                    dontOptimizeListFile = parser.getLastValue();
14421e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                } else if (parser.isArg("--keep-classes")) {
1443f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    keepClassesInJar = true;
14441e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                } else if (parser.isArg("--output=")) {
14451e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                    outName = parser.getLastValue();
1446c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche                    if (new File(outName).isDirectory()) {
1447c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche                        jarOutput = false;
1448c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche                        outputIsDirectory = true;
1449c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche                    } else if (FileUtils.hasArchiveSuffix(outName)) {
1450f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        jarOutput = true;
1451f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    } else if (outName.endsWith(".dex") ||
1452f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                               outName.equals("-")) {
1453f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        jarOutput = false;
1454c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche                        outputIsDirectDex = true;
1455f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    } else {
1456f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        System.err.println("unknown output extension: " +
1457f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                                           outName);
1458f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        throw new UsageException();
1459f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    }
14601e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                } else if (parser.isArg("--dump-to=")) {
14611e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                    humanOutName = parser.getLastValue();
14621e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                } else if (parser.isArg("--dump-width=")) {
14631e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                    dumpWidth = Integer.parseInt(parser.getLastValue());
14641e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                } else if (parser.isArg("--dump-method=")) {
14651e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                    methodToDump = parser.getLastValue();
1466f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    jarOutput = false;
14671e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                } else if (parser.isArg("--positions=")) {
14681e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                    String pstr = parser.getLastValue().intern();
1469f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    if (pstr == "none") {
1470f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        positionInfo = PositionList.NONE;
1471f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    } else if (pstr == "important") {
1472f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        positionInfo = PositionList.IMPORTANT;
1473f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    } else if (pstr == "lines") {
1474f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        positionInfo = PositionList.LINES;
1475f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    } else {
1476f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        System.err.println("unknown positions option: " +
1477f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                                           pstr);
1478f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        throw new UsageException();
1479f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    }
14801e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                } else if (parser.isArg("--no-locals")) {
1481f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    localInfo = false;
1482c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche                } else if (parser.isArg(NUM_THREADS_OPTION + "=")) {
148372b7c6179a6ab44b60735f9c4411faa5fce9649dRaphael                    numThreads = Integer.parseInt(parser.getLastValue());
1484c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche                } else if (parser.isArg(INCREMENTAL_OPTION)) {
1485dc86cd9edc8b80953c8b698a83cdaebf6825d798Jesse Wilson                    incremental = true;
1486f870f2dce9300c8dec620613371f08e5c234245bjeffhao                } else if (parser.isArg("--force-jumbo")) {
1487f870f2dce9300c8dec620613371f08e5c234245bjeffhao                    forceJumbo = true;
1488c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche                } else if (parser.isArg(MULTI_DEX_OPTION)) {
1489c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche                    multiDex = true;
1490c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche                } else if (parser.isArg(MAIN_DEX_LIST_OPTION + "=")) {
1491c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche                    mainDexListFile = parser.getLastValue();
1492c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche                } else if (parser.isArg(MINIMAL_MAIN_DEX_OPTION)) {
1493c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche                    minimalMainDex = true;
1494c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche                } else if (parser.isArg("--set-max-idx-number=")) { // undocumented test option
1495c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche                    maxNumberOfIdxPerDex = Integer.parseInt(parser.getLastValue());
14968a5d5ccc26c97d555024c36f54140f07a4b40b8cJohn Fazekas                } else if(parser.isArg(INPUT_LIST_OPTION + "=")) {
14978a5d5ccc26c97d555024c36f54140f07a4b40b8cJohn Fazekas                    File inputListFile = new File(parser.getLastValue());
14988a5d5ccc26c97d555024c36f54140f07a4b40b8cJohn Fazekas                    try{
14999747950064e4711c15baf0986102320a2512097aXavier Ducrohet                        inputList = new ArrayList<String>();
15009747950064e4711c15baf0986102320a2512097aXavier Ducrohet                        readPathsFromFile(inputListFile.getAbsolutePath(), inputList);
15018a5d5ccc26c97d555024c36f54140f07a4b40b8cJohn Fazekas                    } catch(IOException e) {
15028a5d5ccc26c97d555024c36f54140f07a4b40b8cJohn Fazekas                        System.err.println(
15038a5d5ccc26c97d555024c36f54140f07a4b40b8cJohn Fazekas                            "Unable to read input list file: " + inputListFile.getName());
15048a5d5ccc26c97d555024c36f54140f07a4b40b8cJohn Fazekas                        // problem reading the file so we should halt execution
15058a5d5ccc26c97d555024c36f54140f07a4b40b8cJohn Fazekas                        throw new UsageException();
15068a5d5ccc26c97d555024c36f54140f07a4b40b8cJohn Fazekas                    }
15078a5d5ccc26c97d555024c36f54140f07a4b40b8cJohn Fazekas                } else {
15081e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                    System.err.println("unknown option: " + parser.getCurrent());
1509f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    throw new UsageException();
1510f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
1511f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
1512f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
15131e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll            fileNames = parser.getRemaining();
15148a5d5ccc26c97d555024c36f54140f07a4b40b8cJohn Fazekas            if(inputList != null && !inputList.isEmpty()) {
15158a5d5ccc26c97d555024c36f54140f07a4b40b8cJohn Fazekas                // append the file names to the end of the input list
15168a5d5ccc26c97d555024c36f54140f07a4b40b8cJohn Fazekas                inputList.addAll(Arrays.asList(fileNames));
15178a5d5ccc26c97d555024c36f54140f07a4b40b8cJohn Fazekas                fileNames = inputList.toArray(new String[inputList.size()]);
15188a5d5ccc26c97d555024c36f54140f07a4b40b8cJohn Fazekas            }
15198a5d5ccc26c97d555024c36f54140f07a4b40b8cJohn Fazekas
15201e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll            if (fileNames.length == 0) {
1521f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                if (!emptyOk) {
1522f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    System.err.println("no input files specified");
1523f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    throw new UsageException();
1524f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
1525f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            } else if (emptyOk) {
1526f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                System.out.println("ignoring input files");
1527f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
1528f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1529f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if ((humanOutName == null) && (methodToDump != null)) {
1530f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                humanOutName = "-";
1531f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
1532f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1533c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche            if (mainDexListFile != null && !multiDex) {
1534c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche                System.err.println(MAIN_DEX_LIST_OPTION + " is only supported in combination with "
1535c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche                    + MULTI_DEX_OPTION);
1536c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche                throw new UsageException();
1537c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche            }
1538c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche
1539c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche            if (minimalMainDex && (mainDexListFile == null || !multiDex)) {
1540c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche                System.err.println(MINIMAL_MAIN_DEX_OPTION + " is only supported in combination with "
1541c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche                    + MULTI_DEX_OPTION + " and " + MAIN_DEX_LIST_OPTION);
1542c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche                throw new UsageException();
1543c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche            }
1544c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche
1545c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche            if (multiDex && numThreads != 1) {
1546cf069ca52f2af9f70fcbeac99443f00401d43b4aBenoit Lamarche                System.out.println(NUM_THREADS_OPTION + " is ignored when used with "
1547c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche                    + MULTI_DEX_OPTION);
1548cf069ca52f2af9f70fcbeac99443f00401d43b4aBenoit Lamarche                numThreads = 1;
1549c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche            }
1550c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche
1551c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche            if (multiDex && incremental) {
1552c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche                System.err.println(INCREMENTAL_OPTION + " is not supported with "
1553c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche                    + MULTI_DEX_OPTION);
1554c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche                throw new UsageException();
1555c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche            }
1556c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche
1557c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche            if (multiDex && outputIsDirectDex) {
1558c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche                System.err.println("Unsupported output \"" + outName +"\". " + MULTI_DEX_OPTION +
1559c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche                        " supports only archive or directory output");
1560c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche                throw new UsageException();
1561c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche            }
1562c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche
1563c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche            if (outputIsDirectory && !multiDex) {
1564c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche                outName = new File(outName, DexFormat.DEX_IN_JAR_NAME).getPath();
1565c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche            }
1566c7daf656da3a4854296b6a8bb702e3ee418450e5Benoit Lamarche
156709dc1b7301e8b03fc6772b022d21afe9cb077d89Dan Bornstein            makeOptionsObjects();
1568f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
1569f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1570f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /**
157109dc1b7301e8b03fc6772b022d21afe9cb077d89Dan Bornstein         * Copies relevent arguments over into CfOptions and
157209dc1b7301e8b03fc6772b022d21afe9cb077d89Dan Bornstein         * DexOptions instances.
1573f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
157409dc1b7301e8b03fc6772b022d21afe9cb077d89Dan Bornstein        private void makeOptionsObjects() {
1575f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            cfOptions = new CfOptions();
1576f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            cfOptions.positionInfo = positionInfo;
1577f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            cfOptions.localInfo = localInfo;
1578f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            cfOptions.strictNameCheck = strictNameCheck;
1579f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            cfOptions.optimize = optimize;
1580f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            cfOptions.optimizeListFile = optimizeListFile;
1581f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            cfOptions.dontOptimizeListFile = dontOptimizeListFile;
1582f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            cfOptions.statistics = statistics;
1583f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            cfOptions.warn = DxConsole.err;
15843dfda9ad1964510e4a7948a240b30cd710e86341Dan Bornstein
15853dfda9ad1964510e4a7948a240b30cd710e86341Dan Bornstein            dexOptions = new DexOptions();
1586f870f2dce9300c8dec620613371f08e5c234245bjeffhao            dexOptions.forceJumbo = forceJumbo;
15873dfda9ad1964510e4a7948a240b30cd710e86341Dan Bornstein        }
1588f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
1589590f78fc4b6e3268149c5eacb7c8b7dd33497f44jeffhao
1590cecacd3a4b5ab7a45340f3843522a42a0a4cf287Benoit Lamarche    /** Callable helper class to process files in multiple threads */
1591cecacd3a4b5ab7a45340f3843522a42a0a4cf287Benoit Lamarche    private static class ParallelProcessor implements Callable<Void> {
1592590f78fc4b6e3268149c5eacb7c8b7dd33497f44jeffhao
1593cecacd3a4b5ab7a45340f3843522a42a0a4cf287Benoit Lamarche        ClassPathOpener classPathOpener;
1594590f78fc4b6e3268149c5eacb7c8b7dd33497f44jeffhao
1595cecacd3a4b5ab7a45340f3843522a42a0a4cf287Benoit Lamarche        private ParallelProcessor(ClassPathOpener classPathOpener) {
1596cecacd3a4b5ab7a45340f3843522a42a0a4cf287Benoit Lamarche            this.classPathOpener = classPathOpener;
1597590f78fc4b6e3268149c5eacb7c8b7dd33497f44jeffhao        }
1598590f78fc4b6e3268149c5eacb7c8b7dd33497f44jeffhao
1599cecacd3a4b5ab7a45340f3843522a42a0a4cf287Benoit Lamarche        @Override
1600cecacd3a4b5ab7a45340f3843522a42a0a4cf287Benoit Lamarche        public Void call() throws Exception {
1601cecacd3a4b5ab7a45340f3843522a42a0a4cf287Benoit Lamarche            if (classPathOpener.process()) {
1602590f78fc4b6e3268149c5eacb7c8b7dd33497f44jeffhao                anyFilesProcessed = true;
1603590f78fc4b6e3268149c5eacb7c8b7dd33497f44jeffhao            }
1604cecacd3a4b5ab7a45340f3843522a42a0a4cf287Benoit Lamarche            return null;
1605590f78fc4b6e3268149c5eacb7c8b7dd33497f44jeffhao        }
1606590f78fc4b6e3268149c5eacb7c8b7dd33497f44jeffhao    }
1607f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
1608