1 /* 2 * Copyright 2013, Google Inc. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are 7 * met: 8 * 9 * * Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * * Redistributions in binary form must reproduce the above 12 * copyright notice, this list of conditions and the following disclaimer 13 * in the documentation and/or other materials provided with the 14 * distribution. 15 * * Neither the name of Google Inc. nor the names of its 16 * contributors may be used to endorse or promote products derived from 17 * this software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 package org.jf.dexlib2.analysis; 33 34 import com.google.common.base.Supplier; 35 import com.google.common.base.Suppliers; 36 import com.google.common.cache.CacheBuilder; 37 import com.google.common.cache.CacheLoader; 38 import com.google.common.cache.LoadingCache; 39 import com.google.common.collect.ImmutableSet; 40 import com.google.common.collect.Lists; 41 import org.jf.dexlib2.Opcodes; 42 import org.jf.dexlib2.analysis.reflection.ReflectionClassDef; 43 import org.jf.dexlib2.iface.ClassDef; 44 import org.jf.dexlib2.immutable.ImmutableDexFile; 45 46 import javax.annotation.Nonnull; 47 import java.io.IOException; 48 import java.io.Serializable; 49 import java.util.Arrays; 50 import java.util.List; 51 52 public class ClassPath { 53 @Nonnull private final TypeProto unknownClass; 54 @Nonnull private List<ClassProvider> classProviders; 55 private final boolean checkPackagePrivateAccess; 56 public final int oatVersion; 57 58 public static final int NOT_ART = -1; 59 60 /** 61 * Creates a new ClassPath instance that can load classes from the given providers 62 * 63 * @param classProviders A varargs array of ClassProviders. When loading a class, these providers will be searched 64 * in order 65 */ ClassPath(ClassProvider... classProviders)66 public ClassPath(ClassProvider... classProviders) throws IOException { 67 this(Arrays.asList(classProviders), false, NOT_ART); 68 } 69 70 /** 71 * Creates a new ClassPath instance that can load classes from the given providers 72 * 73 * @param classProviders An iterable of ClassProviders. When loading a class, these providers will be searched in 74 * order 75 */ ClassPath(Iterable<ClassProvider> classProviders)76 public ClassPath(Iterable<ClassProvider> classProviders) throws IOException { 77 this(classProviders, false, NOT_ART); 78 } 79 80 /** 81 * Creates a new ClassPath instance that can load classes from the given providers 82 * 83 * @param classProviders An iterable of ClassProviders. When loading a class, these providers will be searched in 84 * order 85 * @param checkPackagePrivateAccess Whether checkPackagePrivateAccess is needed, enabled for ONLY early API 17 by 86 * default 87 * @param oatVersion The applicable oat version, or NOT_ART 88 */ ClassPath(@onnull Iterable<? extends ClassProvider> classProviders, boolean checkPackagePrivateAccess, int oatVersion)89 public ClassPath(@Nonnull Iterable<? extends ClassProvider> classProviders, boolean checkPackagePrivateAccess, 90 int oatVersion) { 91 // add fallbacks for certain special classes that must be present 92 unknownClass = new UnknownClassProto(this); 93 loadedClasses.put(unknownClass.getType(), unknownClass); 94 this.checkPackagePrivateAccess = checkPackagePrivateAccess; 95 this.oatVersion = oatVersion; 96 97 loadPrimitiveType("Z"); 98 loadPrimitiveType("B"); 99 loadPrimitiveType("S"); 100 loadPrimitiveType("C"); 101 loadPrimitiveType("I"); 102 loadPrimitiveType("J"); 103 loadPrimitiveType("F"); 104 loadPrimitiveType("D"); 105 loadPrimitiveType("L"); 106 107 this.classProviders = Lists.newArrayList(classProviders); 108 this.classProviders.add(getBasicClasses()); 109 } 110 loadPrimitiveType(String type)111 private void loadPrimitiveType(String type) { 112 loadedClasses.put(type, new PrimitiveProto(this, type)); 113 } 114 getBasicClasses()115 private static ClassProvider getBasicClasses() { 116 // fallbacks for some special classes that we assume are present 117 return new DexClassProvider(new ImmutableDexFile(Opcodes.getDefault(), ImmutableSet.of( 118 new ReflectionClassDef(Class.class), 119 new ReflectionClassDef(Cloneable.class), 120 new ReflectionClassDef(Object.class), 121 new ReflectionClassDef(Serializable.class), 122 new ReflectionClassDef(String.class), 123 new ReflectionClassDef(Throwable.class)))); 124 } 125 isArt()126 public boolean isArt() { 127 return oatVersion != NOT_ART; 128 } 129 130 @Nonnull getClass(@onnull CharSequence type)131 public TypeProto getClass(@Nonnull CharSequence type) { 132 return loadedClasses.getUnchecked(type.toString()); 133 } 134 135 private final CacheLoader<String, TypeProto> classLoader = new CacheLoader<String, TypeProto>() { 136 @Override public TypeProto load(String type) throws Exception { 137 if (type.charAt(0) == '[') { 138 return new ArrayProto(ClassPath.this, type); 139 } else { 140 return new ClassProto(ClassPath.this, type); 141 } 142 } 143 }; 144 145 @Nonnull private LoadingCache<String, TypeProto> loadedClasses = CacheBuilder.newBuilder().build(classLoader); 146 147 @Nonnull getClassDef(String type)148 public ClassDef getClassDef(String type) { 149 for (ClassProvider provider: classProviders) { 150 ClassDef classDef = provider.getClassDef(type); 151 if (classDef != null) { 152 return classDef; 153 } 154 } 155 throw new UnresolvedClassException("Could not resolve class %s", type); 156 } 157 158 @Nonnull getUnknownClass()159 public TypeProto getUnknownClass() { 160 return unknownClass; 161 } 162 shouldCheckPackagePrivateAccess()163 public boolean shouldCheckPackagePrivateAccess() { 164 return checkPackagePrivateAccess; 165 } 166 167 private final Supplier<OdexedFieldInstructionMapper> fieldInstructionMapperSupplier = Suppliers.memoize( 168 new Supplier<OdexedFieldInstructionMapper>() { 169 @Override public OdexedFieldInstructionMapper get() { 170 return new OdexedFieldInstructionMapper(isArt()); 171 } 172 }); 173 174 @Nonnull getFieldInstructionMapper()175 public OdexedFieldInstructionMapper getFieldInstructionMapper() { 176 return fieldInstructionMapperSupplier.get(); 177 } 178 } 179