dx 生成 DEX文件流程分析
命令
dx -JXms16M -JXmx2048M --dex --output=. /classes.dex ./classes.jar
dalvik/dx/etc/dx
37 jarfile=dx.jar
38 libdir="$progdir"
39
40 if [ ! -r "$libdir/$jarfile" ];then
41 #set dx.jar location for the SDK case
42 libdir="$libdir/lib"
43 fi
88
89 exec java $javaOpts-jar "$jarpath" "$@"
调用过程
dx/com/android/dx/command/Main.java
88 public static voidmain(String[] args) {
89 boolean gotCmd = false;
90 boolean showUsage = false;
91
92 try {
93 for (int i = 0; i < args.length; i++) {
94 String arg = args[i];
95 if (arg.equals("--")|| !arg.startsWith("--")) {
96 gotCmd = false;
97 showUsage = true;
98 break;
99 }
100
101 gotCmd = true;
102 if(arg.equals("--dex")) {
103 com.android.dx.command.dexer.Main.main(without(args, i));
104 break;
105 } else if(arg.equals("--dump")) {
106 com.android.dx.command.dump.Main.main(without(args, i));
107 break;
com/android/dx/command/dexer/Main.java
195 public static voidmain(String[] argArray) throws IOException {
196 Arguments arguments = new Arguments();
197 arguments.parse(argArray);
198
199 int result = run(arguments);
200 if (result != 0) {
201 System.exit(result);
202 }
203 }
210 public static intrun(Arguments arguments) throws IOException {
211 // Reset the error count to start fresh.
212 errors = 0;
213 // empty the list, so that toolsthat load dx and keep it around
214 // for multiple runs don't reuse older buffers.
215 libraryDexBuffers.clear();
216
217 args = arguments;
218 args.makeOptionsObjects();
219
220 OutputStream humanOutRaw = null;
221 if (args.humanOutName != null) {
222 humanOutRaw = openOutput(args.humanOutName);
223 humanOutWriter = new OutputStreamWriter(humanOutRaw);
224 }
225
226 try {
227 if (args.multiDex) {
228 return runMultiDex();
229 } else {
230 return runMonoDex();
231 }
232 } finally {
233 closeOutput(humanOutRaw);
234 }
235 }
249 private static int runMonoDex()throws IOException {
250
251 File incrementalOutFile = null;
252 if (args.incremental) {
253 if (args.outName == null) {
254 System.err.println(
255 "error: noincremental output name specified");
256 return -1;
257 }
258 incrementalOutFile = new File(args.outName);
259 if (incrementalOutFile.exists()) {
260 minimumFileAge =incrementalOutFile.lastModified();
261 }
262 }
263
264 if (!processAllFiles()) {
265 return 1;
266 }
267
268 if (args.incremental && !anyFilesProcessed) {
269 return 0; // this was a no-op incremental build
270 }
271
272 // this array is null if no classes were defined
273 byte[] outArray = null;
274
275 if (!outputDex.isEmpty()) {
276 outArray = writeDex();
277
278 if (outArray == null) {
279 return 2;
280 }
281 }
282
283 if (args.incremental) {
284 outArray = mergeIncremental(outArray, incrementalOutFile);
285 }
286
287 outArray = mergeLibraryDexBuffers(outArray);
288
289 if (args.jarOutput) {
290 // Effectively free up the (often massive) DexFile memory.
291 outputDex = null;
292
293 if (outArray != null) {
294 outputResources.put(DexFormat.DEX_IN_JAR_NAME, outArray);
295 }
296 if (!createJar(args.outName)) {
297 return 3;
298 }
299 } else if (outArray != null && args.outName != null) {
300 OutputStream out =openOutput(args.outName);
301 out.write(outArray);
302 closeOutput(out);
303 }
304
305 return 0;
306 }
748 private static byte[]writeDex() {
749 byte[] outArray = null;
750
751 try {
752 try {
753 if (args.methodToDump != null){
754 /*
755 * Simply dump therequested method. Note: The call
756 * to toDex() is requiredjust to get the underlying
757 * structures ready.
758 */
759 outputDex.toDex(null,false);
760 dumpMethod(outputDex,args.methodToDump, humanOutWriter);
761 } else {
762 /*
763 * This is the usual case:Create an output .dex file,
764 * and write it, dump it,etc.
765 */
766 outArray =outputDex.toDex(humanOutWriter, args.verboseDump);
767 }
768
769 if (args.statistics) {
770 DxConsole.out.println(outputDex.getStatistics().toHuman());
771 }
772 } finally {
773 if (humanOutWriter != null) {
774 humanOutWriter.flush();
775 }
776 }
777 } catch (Exception ex) {
778 if (args.debug) {
779 DxConsole.err.println("\ntrouble writing output:");
780 ex.printStackTrace(DxConsole.err);
781 } else {
782 DxConsole.err.println("\ntrouble writing output: " +
783 ex.getMessage());
784 }
785 return null;
786 }
787
788 return outArray;
789 }
dx/src//com/android/dx/dex/file/DexFile.java
211 public byte[]toDex(Writer humanOut, boolean verbose)
212 throws IOException {
213 boolean annotate = (humanOut != null);
214 ByteArrayAnnotatedOutput result = toDex0(annotate, verbose);
215
216 if (annotate) {
217 result.writeAnnotationsTo(humanOut);
218 }
219
220 return result.getArray();
221 }
492 private ByteArrayAnnotatedOutputtoDex0(boolean annotate,
493 boolean verbose) {
494 /*
495 * The following is ordered so that the prepare() calls which
496 * add items happen before the calls to the sections that get
497 * added to.
498 */
499
500 classDefs.prepare();
501 classData.prepare();
502 wordData.prepare();
503 byteData.prepare();
504 methodIds.prepare();
505 fieldIds.prepare();
506 protoIds.prepare();
507 typeLists.prepare();
508 typeIds.prepare();
509 stringIds.prepare();
510 stringData.prepare();
511 header.prepare();
512
513 // Place the sections within the file.
514
515 int count = sections.length;
516 int offset = 0;
517
518 for (int i = 0; i < count; i++) {
519 Section one = sections[i];
520 int placedAt =one.setFileOffset(offset);
521 if (placedAt < offset) {
522 throw newRuntimeException("bogus placement for section " + i);
523 }
524
525 try {
526 if (one == map) {
527 /*
528 * Inform the map of allthe sections, and add it
529 * to the file. This canonly be done after all
530 * the other items havebeen sorted and placed.
531 */
532 MapItem.addMap(sections,map);
533 map.prepare();
534 }
535
536 if (one instanceofMixedItemSection) {
537 /*
538 * Place the items of aMixedItemSection that just
539 * got placed.
540 */
541 ((MixedItemSection)one).placeItems();
542 }
543
544 offset = placedAt +one.writeSize();
545 } catch (RuntimeException ex) {
546 throw ExceptionWithContext.withContext(ex,
547 "...while writingsection " + i);
548 }
549 }
550
551 // Write out all thesections.
552
553 fileSize = offset;
554 byte[] barr = new byte[fileSize];
555 ByteArrayAnnotatedOutput out = newByteArrayAnnotatedOutput(barr);
556
557 if (annotate) {
558 out.enableAnnotations(dumpWidth,verbose);
559 }
560
561 for (int i = 0; i < count; i++) {
562 try {
563 Section one = sections[i];
564 int zeroCount =one.getFileOffset() - out.getCursor();
565 if (zeroCount < 0) {
566 throw newExceptionWithContext("excess write of " +
567 (-zeroCount));
568 }
569 out.writeZeroes(one.getFileOffset() - out.getCursor());
570 one.writeTo(out);
571 } catch (RuntimeException ex) {
572 ExceptionWithContext ec;
573 if (ex instanceofExceptionWithContext) {
574 ec =(ExceptionWithContext) ex;
575 } else {
576 ec = newExceptionWithContext(ex);
577 }
578 ec.addContext("...whilewriting section " + i);
579 throw ec;
580 }
581 }
582
583 if (out.getCursor() != fileSize) {
584 throw newRuntimeException("foreshortened write");
585 }
586
./com/android/dx/dex/file/Section.java
145 public final voidwriteTo(AnnotatedOutput out) {
146 throwIfNotPrepared();
147 align(out);
148
149 int cursor = out.getCursor();
150
151 if (fileOffset < 0) {
152 fileOffset = cursor;
153 } else if (fileOffset != cursor) {
154 throw newRuntimeException("alignment mismatch: for " + this +
155 ",at " + cursor +
156 ",but expected " + fileOffset);
157 }
158
159 if (out.annotates()) {
160 if (name != null) {
161 out.annotate(0, "\n"+ name + ":");
162 } else if (cursor != 0) {
163 out.annotate(0,"\n");
164 }
165 }
166
167 writeTo0(out);
168 }
./com/android/dx/dex/file/UniformItemSection.java
81 protected final void writeTo0(AnnotatedOutput out) {
82 DexFile file = getFile();
83 int alignment = getAlignment();
84
85 for (Item one : items()) {
86 one.writeTo(file, out);
87 out.alignTo(alignment);
88 }
89 }
com/android/dx/dex/file/HeaderItem.java
56 public voidwriteTo(DexFile file, AnnotatedOutput out) {
57 int mapOff = file.getMap().getFileOffset();
58 Section firstDataSection = file.getFirstDataSection();
59 Section lastDataSection = file.getLastDataSection();
60 int dataOff = firstDataSection.getFileOffset();
61 int dataSize =lastDataSection.getFileOffset() +
62 lastDataSection.writeSize() - dataOff;
63
64 String magic = file.getDexOptions().getMagic();
65
66 if (out.annotates()) {
67 out.annotate(8, "magic: " + new CstString(magic).toQuoted());
68 out.annotate(4, "checksum");
69 out.annotate(20, "signature");
70 out.annotate(4, "file_size: " +
71 Hex.u4(file.getFileSize()));
72 out.annotate(4, "header_size: " + Hex.u4(SizeOf.HEADER_ITEM));
73 out.annotate(4, "endian_tag: " + Hex.u4(DexFormat.ENDIAN_TAG));
74 out.annotate(4, "link_size: 0");
75 out.annotate(4, "link_off: 0");
76 out.annotate(4, "map_off: " + Hex.u4(mapOff));
77 }
78
79 // Write the magic number.
80 for (int i = 0; i < 8; i++) {
81 out.writeByte(magic.charAt(i));
82 }
83
84 // Leave space for the checksum and signature.
85 out.writeZeroes(24);
86
87 out.writeInt(file.getFileSize());
88 out.writeInt(SizeOf.HEADER_ITEM);
89 out.writeInt(DexFormat.ENDIAN_TAG);
90
91 /*
92 * Write zeroes for the link sizeand data, as the output
93 * isn't a staticly linked file.
94 */
95 out.writeZeroes(8);
96
97 out.writeInt(mapOff);
98
99 // Write out each section's respectiveheader part.
100 file.getStringIds().writeHeaderPart(out);
101 file.getTypeIds().writeHeaderPart(out);
102 file.getProtoIds().writeHeaderPart(out);
103 file.getFieldIds().writeHeaderPart(out);
104 file.getMethodIds().writeHeaderPart(out);
105 file.getClassDefs().writeHeaderPart(out);
106
107 if (out.annotates()) {
108 out.annotate(4,"data_size: " +Hex.u4(dataSize));
109 out.annotate(4,"data_off: " +Hex.u4(dataOff));
110 }
111
112 out.writeInt(dataSize);
113 out.writeInt(dataOff);
114 }
115 }
类处理过程
Dx/src/com/android/dx/command/dexer/Main.java
processAllFiles –》 processOne –》 processFileBytes –》 run@ParallelProcessor–》 processFileBytes
606 private static booleanprocessFileBytes(String name, long lastModified, byte[] bytes) {
607 boolean isClass = name.endsWith(".class");
608 boolean isClassesDex = name.equals(DexFormat.DEX_IN_JAR_NAME);
609 boolean keepResources = (outputResources != null);
610
611 if (!isClass && !isClassesDex && !keepResources) {
612 if (args.verbose) {
613 DxConsole.out.println("ignored resource " + name);
614 }
615 return false;
616 }
617
618 if (args.verbose) {
619 DxConsole.out.println("processing " + name + "...");
620 }
621
622 String fixedName = fixPath(name);
623
624 if (isClass) {
625
626 if (keepResources && args.keepClassesInJar) {
627 synchronized (outputResources){
628 outputResources.put(fixedName, bytes);
629 }
630 }
631 if (lastModified < minimumFileAge) {
632 return true;
633 }
634 return processClass(fixedName,bytes);
635 } else if (isClassesDex) {
636 synchronized (libraryDexBuffers) {
637 libraryDexBuffers.add(bytes);
638 }
639 return true;
640 } else {
641 synchronized (outputResources) {
642 outputResources.put(fixedName,bytes);
643 }
644 return true;
645 }
646 }
656 private static booleanprocessClass(String name, byte[] bytes) {
657 if (! args.coreLibrary) {
658 checkClassName(name);
659 }
660
661 DirectClassFile cf =
662 new DirectClassFile(bytes, name, args.cfOptions.strictNameCheck);
663
664 cf.setAttributeFactory(StdAttributeFactory.THE_ONE);
665 cf.getMagic();
666
667 int numMethodIds = outputDex.getMethodIds().items().size();
668 int numFieldIds = outputDex.getFieldIds().items().size();
669 int numTypeIds = outputDex.getTypeIds().items().size();
670 int constantPoolSize = cf.getConstantPool().size();
671
672 if (args.multiDex &&((numMethodIds + constantPoolSize > args.maxNumberOfIdxPerDex) ||
673 (numFieldIds + constantPoolSize > args.maxNumberOfIdxPerDex) ||
674 (numTypeIds + constantPoolSize
675 /* annotation added by dxare not counted in numTypeIds */
676 +AnnotationUtils.DALVIK_ANNOTATION_NUMBER
677 >args.maxNumberOfIdxPerDex))) {
678 createDexFile();
679 }
680
681 try {
682 ClassDefItem clazz =
683 CfTranslator.translate(cf,bytes, args.cfOptions, args.dexOptions, outputDex);
684 synchronized (outputDex) {
685 outputDex.add(clazz);
686 }
687 return true;
688
689 } catch (ParseException ex) {
690 DxConsole.err.println("\ntrouble processing:");
691 if (args.debug) {
692 ex.printStackTrace(DxConsole.err);
693 } else {
694 ex.printContext(DxConsole.err);
695 }
696 }
697 errors++;
698 return false;
699 }
700