// In ProGuardTask @TaskAction publicvoidproguard()throws ParseException, IOException { ... // Run ProGuard with the collected configuration. new ProGuard(getConfiguration()).execute(); }
讀取完Configuration後是呼叫execute():
// In ProGuard publicvoidexecute()throws IOException { ... readInput(); ... }
直接看到readInput():
// In ProGuard privatevoidreadInput()throws IOException { ... // Fill the program class pool and the library class pool. new InputReader(configuration).execute(programClassPool, libraryClassPool); }
根據內容確定這就是我們在Part1提到的,讀取完ParGuard設定後,接著讀取要處理的程式碼,並分成Program class pool和Library class pool。
接著看到execute():
// In InputReader publicvoidexecute(ClassPool programClassPool, ClassPool libraryClassPool)throws IOException { WarningPrinter warningPrinter = new WarningPrinter(System.err, configuration.warn); WarningPrinter notePrinter = new WarningPrinter(System.out, configuration.note);
DuplicateClassPrinter duplicateClassPrinter = new DuplicateClassPrinter(notePrinter);
// Read the library class files, if any and if they should get priority. if (FAVOR_LIBRARY_CLASSES && configuration.libraryJars != null) { // Prepare a data entry reader to filter all classes, // which are then decoded to classes by a class reader, // which are then put in the class pool by a class pool filler. readInput("Reading library ", configuration.libraryJars, new ClassFilter( new ClassReader(true, configuration.skipNonPublicLibraryClasses, configuration.skipNonPublicLibraryClassMembers, warningPrinter, new ClassPresenceFilter(libraryClassPool, duplicateClassPrinter, new ClassPoolFiller(libraryClassPool))))); }
// Read the program class files. // Prepare a data entry reader to filter all classes, // which are then decoded to classes by a class reader, // which are then put in the class pool by a class pool filler. readInput("Reading program ", configuration.programJars, new ClassFilter( new ClassReader(false, configuration.skipNonPublicLibraryClasses, configuration.skipNonPublicLibraryClassMembers, warningPrinter, new ClassPresenceFilter(programClassPool, duplicateClassPrinter, new ClassPresenceFilter(libraryClassPool, duplicateClassPrinter, new ClassPoolFiller(programClassPool))))));
... // Read the library class files, if any. if (!FAVOR_LIBRARY_CLASSES && configuration.libraryJars != null) { // Prepare a data entry reader to filter all classes, // which are then decoded to classes by a class reader, // which are then put in the class pool by a class pool filler. readInput("Reading library ", configuration.libraryJars, new ClassFilter( new ClassReader(true, configuration.skipNonPublicLibraryClasses, configuration.skipNonPublicLibraryClassMembers, warningPrinter, new ClassPresenceFilter(programClassPool, duplicateClassPrinter, new ClassPresenceFilter(libraryClassPool, duplicateClassPrinter, new ClassPoolFiller(libraryClassPool)))))); } ... }
執行到這邊,透過-injars、-outjars和-libraryjars指定的Jar檔內的Class檔,都已經被讀取並分類至Library class pool和Program class pool。
// In InputReader DuplicateClassPrinter duplicateClassPrinter = new DuplicateClassPrinter(notePrinter);
readInput("Reading library ", configuration.libraryJars, new ClassFilter( new ClassReader( true, configuration.skipNonPublicLibraryClasses, configuration.skipNonPublicLibraryClassMembers, warningPrinter, new ClassPresenceFilter(libraryClassPool, duplicateClassPrinter, new ClassPoolFiller(libraryClassPool)))));
// In InputReader publicvoidreadInput(String messagePrefix, ClassPath classPath, int fromIndex, int toIndex, DataEntryReader reader)throws IOException { for (int index = fromIndex; index < toIndex; index++) { ClassPathEntry entry = classPath.get(index); if (!entry.isOutput()) { readInput(messagePrefix, entry, reader); } } }
這邊會依序從ClassPath取出檔案路徑,傳入另一個readInput():
// In InputReader privatevoidreadInput(String messagePrefix, ClassPathEntry classPathEntry, DataEntryReader dataEntryReader)throws IOException { ... // Create a reader that can unwrap jars, wars, ears, jmods and zips. DataEntryReader reader = DataEntryReaderFactory.createDataEntryReader(messagePrefix, classPathEntry, dataEntryReader); // Create the data entry pump. DirectoryPump directoryPump = new DirectoryPump(classPathEntry.getFile()); // Pump the data entries into the reader. directoryPump.pumpDataEntries(reader); ... }
// In DataEntryReaderFactory privatestatic DataEntryReader wrapInJarReader(DataEntryReader reader, boolean stripClassesPrefix, boolean stripJmodHeader, boolean isJar, List jarFilter, String jarExtension){ ... // Unzip any jars, if necessary. DataEntryReader jarReader = new JarReader(reader, stripJmodHeader);
if (isJar) { // Always unzip. return jarReader; } else { ... // Only unzip the right type of jars. returnnew FilteredDataEntryReader( new DataEntryNameFilter(new ExtensionMatcher(jarExtension)), jarReader, reader); } }
privatevoidreadFiles(File file, DataEntryReader dataEntryReader)throws IOException { // Pass the file data entry to the reader. dataEntryReader.read(new FileDataEntry(directory, file)); ... }
這邊用到的首先是JarReader的read():
// in JarReader publicvoidread(DataEntry dataEntry)throws IOException { ... ZipInputStream zipInputStream = new ZipInputStream(dataEntry.getInputStream()); try { // Get all entries from the input jar. while (true) { // Can we get another entry? ZipEntry zipEntry = zipInputStream.getNextEntry(); if (zipEntry == null) { break; }
// Delegate the actual reading to the data entry reader. dataEntryReader.read(new ZipDataEntry(dataEntry, zipEntry, zipInputStream)); } } ... }
// In ClassReader publicvoidread(DataEntry dataEntry)throws IOException { try { // Get the input stream. InputStream inputStream = dataEntry.getInputStream(); // Wrap it into a data input stream. DataInputStream dataInputStream = new DataInputStream(inputStream); // Create a Clazz representation. Clazz clazz; if (isLibrary) { clazz = new LibraryClass(); clazz.accept(new LibraryClassReader(dataInputStream, ...)); } else { clazz = new ProgramClass(); clazz.accept(new ProgramClassReader(dataInputStream)); }
// Apply the visitor, if we have a real class. String className = clazz.getName(); if (className != null) { ... clazz.accept(classVisitor); }
// In LibraryClassReader publicvoidvisitLibraryClass(LibraryClass libraryClass) { ... // Store their actual names. libraryClass.thisClassName = getClassName(u2thisClass); libraryClass.superClassName = (u2superClass == 0) ? null : getClassName(u2superClass);
... libraryClass.interfaceNames = new String[u2interfacesCount]; for (int index = 0; index < u2interfacesCount; index++) { // Store the actual interface name. int u2interface = dataInput.readUnsignedShort(); libraryClass.interfaceNames[index] = getClassName(u2interface); }
... // Copy the visible fields (if any) into a fields array of the right size. ... else { libraryClass.fields = new LibraryField[visibleFieldsCount]; System.arraycopy(reusableFields, 0, libraryClass.fields, 0, visibleFieldsCount); } ... // Copy the visible methods (if any) into a methods array of the right size. ... else { libraryClass.methods = new LibraryMethod[visibleMethodsCount]; System.arraycopy(reusableMethods, 0, libraryClass.methods, 0, visibleMethodsCount); } }