diff options
author | Assaf <asafyi@gmail.com> | 2018-06-20 13:05:57 +0300 |
---|---|---|
committer | Ben Gruver <bgruv@google.com> | 2018-07-10 16:16:45 -0700 |
commit | 5a6b891ef0fd909d5cbde705cfb323fa6c497c78 (patch) | |
tree | e5ed776fe53b327e2706c8c0d41dcc05bea52996 | |
parent | 71ea09fc8ef5a311015bf4b7d916521de639ef03 (diff) | |
download | smali-5a6b891ef0fd909d5cbde705cfb323fa6c497c78.tar.gz |
Extract new class, PathEntryLoader from ClassPathResolver.
Extract method ClassPathResolver::getDefaultBootClassPath()
-rw-r--r-- | dexlib2/src/main/java/org/jf/dexlib2/analysis/ClassPathResolver.java | 139 | ||||
-rw-r--r-- | dexlib2/src/main/java/org/jf/dexlib2/analysis/PathEntryLoader.java | 109 |
2 files changed, 145 insertions, 103 deletions
diff --git a/dexlib2/src/main/java/org/jf/dexlib2/analysis/ClassPathResolver.java b/dexlib2/src/main/java/org/jf/dexlib2/analysis/ClassPathResolver.java index b5fcf87c..3d5895bc 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/analysis/ClassPathResolver.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/analysis/ClassPathResolver.java @@ -34,11 +34,7 @@ package org.jf.dexlib2.analysis; import com.google.common.base.Joiner; import com.google.common.base.Splitter; import com.google.common.collect.Lists; -import com.google.common.collect.Sets; -import org.jf.dexlib2.DexFileFactory; import org.jf.dexlib2.DexFileFactory.UnsupportedFileTypeException; -import org.jf.dexlib2.Opcodes; -import org.jf.dexlib2.dexbacked.DexBackedDexFile; import org.jf.dexlib2.dexbacked.DexBackedOdexFile; import org.jf.dexlib2.dexbacked.OatFile; import org.jf.dexlib2.dexbacked.OatFile.OatDexFile; @@ -51,14 +47,11 @@ import javax.annotation.Nullable; import java.io.File; import java.io.IOException; import java.util.List; -import java.util.Set; public class ClassPathResolver { private final Iterable<String> classPathDirs; - private final Opcodes opcodes; - private final Set<File> loadedFiles = Sets.newHashSet(); - private final List<ClassProvider> classProviders = Lists.newArrayList(); + private final PathEntryLoader pathEntryLoader; /** * Constructs a new ClassPathResolver using a specified list of bootclasspath entries @@ -109,21 +102,21 @@ public class ClassPathResolver { @Nonnull List<String> extraClassPathEntries, @Nonnull DexFile dexFile, boolean unused) throws IOException { this.classPathDirs = bootClassPathDirs; - opcodes = dexFile.getOpcodes(); + this.pathEntryLoader = new PathEntryLoader(dexFile.getOpcodes()); if (bootClassPathEntries == null) { - bootClassPathEntries = getDefaultBootClassPath(dexFile, opcodes.api); + bootClassPathEntries = getDefaultBootClassPath(dexFile, dexFile.getOpcodes().api); } for (String entry : bootClassPathEntries) { try { loadLocalOrDeviceBootClassPathEntry(entry); - } catch (NoDexException ex) { + } catch (PathEntryLoader.NoDexException ex) { if (entry.endsWith(".jar")) { String odexEntry = entry.substring(0, entry.length() - 4) + ".odex"; try { loadLocalOrDeviceBootClassPathEntry(odexEntry); - } catch (NoDexException ex2) { + } catch (PathEntryLoader.NoDexException ex2) { throw new ResolveException("Neither %s nor %s contain a dex file", entry, odexEntry); } catch (NotFoundException ex2) { throw new ResolveException(ex); @@ -136,7 +129,7 @@ public class ClassPathResolver { String jarEntry = entry.substring(0, entry.length() - 5) + ".jar"; try { loadLocalOrDeviceBootClassPathEntry(jarEntry); - } catch (NoDexException ex2) { + } catch (PathEntryLoader.NoDexException ex2) { throw new ResolveException("Neither %s nor %s contain a dex file", entry, jarEntry); } catch (NotFoundException ex2) { throw new ResolveException(ex); @@ -152,7 +145,7 @@ public class ClassPathResolver { // bootClassPathDirs try { loadLocalClassPathEntry(entry); - } catch (NoDexException ex) { + } catch (PathEntryLoader.NoDexException ex) { throw new ResolveException(ex); } } @@ -160,23 +153,23 @@ public class ClassPathResolver { if (dexFile instanceof MultiDexContainer.MultiDexFile) { MultiDexContainer<? extends MultiDexFile> container = ((MultiDexFile)dexFile).getContainer(); for (String entry: container.getDexEntryNames()) { - classProviders.add(new DexClassProvider(container.getEntry(entry))); + pathEntryLoader.getClassProviders().add(new DexClassProvider(container.getEntry(entry))); } } else { - classProviders.add(new DexClassProvider(dexFile)); + pathEntryLoader.getClassProviders().add(new DexClassProvider(dexFile)); } } @Nonnull public List<ClassProvider> getResolvedClassProviders() { - return classProviders; + return pathEntryLoader.getResolvedClassProviders(); } - private boolean loadLocalClassPathEntry(@Nonnull String entry) throws NoDexException, IOException { + private boolean loadLocalClassPathEntry(@Nonnull String entry) throws PathEntryLoader.NoDexException, IOException { File entryFile = new File(entry); if (entryFile.exists() && entryFile.isFile()) { try { - loadEntry(entryFile, true); + pathEntryLoader.loadEntry(entryFile, true); return true; } catch (UnsupportedFileTypeException ex) { throw new ResolveException(ex, "Couldn't load classpath entry %s", entry); @@ -186,7 +179,7 @@ public class ClassPathResolver { } private void loadLocalOrDeviceBootClassPathEntry(@Nonnull String entry) - throws IOException, NoDexException, NotFoundException { + throws IOException, PathEntryLoader.NoDexException, NotFoundException { // first, see if the entry is a valid local path if (loadLocalClassPathEntry(entry)) { return; @@ -207,7 +200,7 @@ public class ClassPathResolver { String partialPath = pathJoiner.join(pathComponents.subList(i, pathComponents.size())); File entryFile = new File(directoryFile, partialPath); if (entryFile.exists() && entryFile.isFile()) { - loadEntry(entryFile, true); + pathEntryLoader.loadEntry(entryFile, true); return; } } @@ -216,86 +209,16 @@ public class ClassPathResolver { throw new NotFoundException("Could not find classpath entry %s", entry); } - private void loadEntry(@Nonnull File entryFile, boolean loadOatDependencies) - throws IOException, NoDexException { - if (loadedFiles.contains(entryFile)) { - return; - } - - MultiDexContainer<? extends DexBackedDexFile> container; - try { - container = DexFileFactory.loadDexContainer(entryFile, opcodes); - } catch (UnsupportedFileTypeException ex) { - throw new ResolveException(ex); - } - - List<String> entryNames = container.getDexEntryNames(); - - if (entryNames.size() == 0) { - throw new NoDexException("%s contains no dex file", entryFile); - } - - loadedFiles.add(entryFile); - - for (String entryName: entryNames) { - classProviders.add(new DexClassProvider(container.getEntry(entryName))); - } - - if (loadOatDependencies && container instanceof OatFile) { - List<String> oatDependencies = ((OatFile)container).getBootClassPath(); - if (!oatDependencies.isEmpty()) { - try { - loadOatDependencies(entryFile.getParentFile(), oatDependencies); - } catch (NotFoundException ex) { - throw new ResolveException(ex, "Error while loading oat file %s", entryFile); - } catch (NoDexException ex) { - throw new ResolveException(ex, "Error while loading dependencies for oat file %s", entryFile); - } - } - } - } - @Nonnull private static List<String> splitDevicePath(@Nonnull String path) { return Lists.newArrayList(Splitter.on('/').split(path)); } - private void loadOatDependencies(@Nonnull File directory, @Nonnull List<String> oatDependencies) - throws IOException, NoDexException, NotFoundException { - // We assume that all oat dependencies are located in the same directory as the oat file - for (String oatDependency: oatDependencies) { - String oatDependencyName = getFilenameForOatDependency(oatDependency); - File file = new File(directory, oatDependencyName); - if (!file.exists()) { - throw new NotFoundException("Cannot find dependency %s in %s", oatDependencyName, directory); - } - - loadEntry(file, false); - } - } - - @Nonnull - private String getFilenameForOatDependency(String oatDependency) { - int index = oatDependency.lastIndexOf('/'); - - String dependencyLeaf = oatDependency.substring(index+1); - if (dependencyLeaf.endsWith(".art")) { - return dependencyLeaf.substring(0, dependencyLeaf.length() - 4) + ".oat"; - } - return dependencyLeaf; - } - - private static class NotFoundException extends Exception { + static class NotFoundException extends Exception { public NotFoundException(String message, Object... formatArgs) { super(String.format(message, formatArgs)); } } - - private static class NoDexException extends Exception { - public NoDexException(String message, Object... formatArgs) { - super(String.format(message, formatArgs)); - } - } /** * An error that occurred while resolving the classpath @@ -320,17 +243,8 @@ public class ClassPathResolver { @Nonnull private static List<String> getDefaultBootClassPath(@Nonnull DexFile dexFile, int apiLevel) { if (dexFile instanceof OatFile.OatDexFile) { - List<String> bcp = ((OatDexFile)dexFile).getContainer().getBootClassPath(); - if (!bcp.isEmpty()) { - for (int i=0; i<bcp.size(); i++) { - String entry = bcp.get(i); - if (entry.endsWith(".art")) { - bcp.set(i, entry.substring(0, entry.length() - 4) + ".oat"); - } - } - return bcp; - } - return Lists.newArrayList("boot.oat"); + return bootClassPathForOat((OatDexFile) dexFile); + } if (dexFile instanceof DexBackedOdexFile) { @@ -462,4 +376,23 @@ public class ClassPathResolver { "/system/framework/org.apache.http.legacy.boot.jar"); } } + + private static List<String> bootClassPathForOat(@Nonnull OatDexFile dexFile) { + List<String> bcp = dexFile.getContainer().getBootClassPath(); + if(bcp.isEmpty()) { + return Lists.newArrayList("boot.oat"); + } else { + return replaceElementsSuffix(bcp, ".art", ".oat"); + } + } + + private static List<String> replaceElementsSuffix(List<String> bcp, String originalSuffix, String newSuffix) { + for (int i=0; i<bcp.size(); i++) { + String entry = bcp.get(i); + if (entry.endsWith(originalSuffix)) { + bcp.set(i, entry.substring(0, entry.length() - originalSuffix.length()) + newSuffix); + } + } + return bcp; + } } diff --git a/dexlib2/src/main/java/org/jf/dexlib2/analysis/PathEntryLoader.java b/dexlib2/src/main/java/org/jf/dexlib2/analysis/PathEntryLoader.java new file mode 100644 index 00000000..fd654de5 --- /dev/null +++ b/dexlib2/src/main/java/org/jf/dexlib2/analysis/PathEntryLoader.java @@ -0,0 +1,109 @@ +package org.jf.dexlib2.analysis; + +import com.google.common.collect.Lists; +import com.google.common.collect.Sets; +import org.jf.dexlib2.DexFileFactory; +import org.jf.dexlib2.Opcodes; +import org.jf.dexlib2.dexbacked.DexBackedDexFile; +import org.jf.dexlib2.dexbacked.OatFile; +import org.jf.dexlib2.iface.MultiDexContainer; + +import javax.annotation.Nonnull; +import java.io.File; +import java.io.IOException; +import java.util.List; +import java.util.Set; + +public class PathEntryLoader { + Opcodes opcodes; + + public Opcodes getOpcodes() { + return opcodes; + } + + final Set<File> loadedFiles = Sets.newHashSet(); + final List<ClassProvider> classProviders = Lists.newArrayList(); + + public List<ClassProvider> getClassProviders() { + return classProviders; + } + + public PathEntryLoader(Opcodes opcodes) { + this.opcodes = opcodes; + } + + @Nonnull + public List<ClassProvider> getResolvedClassProviders() { + return classProviders; + } + + public void loadEntry(@Nonnull File entryFile, boolean loadOatDependencies) + throws IOException, NoDexException { + if (loadedFiles.contains(entryFile)) { + return; + } + + MultiDexContainer<? extends DexBackedDexFile> container; + try { + container = DexFileFactory.loadDexContainer(entryFile, opcodes); + } catch (DexFileFactory.UnsupportedFileTypeException ex) { + throw new ClassPathResolver.ResolveException(ex); + } + + List<String> entryNames = container.getDexEntryNames(); + + if (entryNames.isEmpty()) { + throw new NoDexException("%s contains no dex file", entryFile); + } + + loadedFiles.add(entryFile); + + for (String entryName : entryNames) { + classProviders.add(new DexClassProvider(container.getEntry(entryName))); + } + + if (loadOatDependencies && container instanceof OatFile) { + List<String> oatDependencies = ((OatFile) container).getBootClassPath(); + if (!oatDependencies.isEmpty()) { + try { + loadOatDependencies(entryFile.getParentFile(), oatDependencies); + } catch (ClassPathResolver.NotFoundException ex) { + throw new ClassPathResolver.ResolveException(ex, "Error while loading oat file %s", entryFile); + } catch (NoDexException ex) { + throw new ClassPathResolver.ResolveException(ex, "Error while loading dependencies for oat file %s", entryFile); + } + } + } + } + + private void loadOatDependencies(@Nonnull File directory, @Nonnull List<String> oatDependencies) + throws IOException, NoDexException, ClassPathResolver.NotFoundException { + // We assume that all oat dependencies are located in the same directory as the oat file + for (String oatDependency : oatDependencies) { + String oatDependencyName = getFilenameForOatDependency(oatDependency); + File file = new File(directory, oatDependencyName); + if (!file.exists()) { + throw new ClassPathResolver.NotFoundException("Cannot find dependency %s in %s", oatDependencyName, directory); + } + + loadEntry(file, false); + } + } + + @Nonnull + private String getFilenameForOatDependency(String oatDependency) { + int index = oatDependency.lastIndexOf('/'); + + String dependencyLeaf = oatDependency.substring(index + 1); + if (dependencyLeaf.endsWith(".art")) { + return dependencyLeaf.substring(0, dependencyLeaf.length() - 4) + ".oat"; + } + return dependencyLeaf; + } + + static class NoDexException extends Exception { + public NoDexException(String message, Object... formatArgs) { + super(String.format(message, formatArgs)); + } + } +}
\ No newline at end of file |