• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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