dx 生成 DEX文件流程分析

来源:互联网 发布:ai域名注册价格 编辑:程序博客网 时间:2024/05/16 18:29

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

 

 

0 0