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