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