• 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.writer.builder;
33 
34 import com.google.common.base.Function;
35 import com.google.common.collect.*;
36 import org.jf.dexlib2.Opcodes;
37 import org.jf.dexlib2.ValueType;
38 import org.jf.dexlib2.iface.Annotation;
39 import org.jf.dexlib2.iface.AnnotationElement;
40 import org.jf.dexlib2.iface.MethodImplementation;
41 import org.jf.dexlib2.iface.MethodParameter;
42 import org.jf.dexlib2.iface.reference.*;
43 import org.jf.dexlib2.iface.value.*;
44 import org.jf.dexlib2.util.FieldUtil;
45 import org.jf.dexlib2.writer.DexWriter;
46 import org.jf.dexlib2.writer.builder.BuilderEncodedValues.*;
47 import org.jf.dexlib2.writer.util.StaticInitializerUtil;
48 import org.jf.util.ExceptionWithContext;
49 
50 import javax.annotation.Nonnull;
51 import javax.annotation.Nullable;
52 import java.io.IOException;
53 import java.util.Iterator;
54 import java.util.List;
55 import java.util.Set;
56 
57 public class DexBuilder extends DexWriter<BuilderStringReference, BuilderStringReference, BuilderTypeReference,
58         BuilderTypeReference, BuilderMethodProtoReference, BuilderFieldReference, BuilderMethodReference,
59         BuilderClassDef, BuilderCallSiteReference, BuilderMethodHandleReference, BuilderAnnotation, BuilderAnnotationSet, BuilderTypeList,
60         BuilderField, BuilderMethod, BuilderArrayEncodedValue, BuilderEncodedValue, BuilderAnnotationElement,
61         BuilderStringPool, BuilderTypePool, BuilderProtoPool, BuilderFieldPool, BuilderMethodPool, BuilderClassPool,
62         BuilderCallSitePool, BuilderMethodHandlePool, BuilderTypeListPool, BuilderAnnotationPool,
63         BuilderAnnotationSetPool, BuilderEncodedArrayPool> {
64 
DexBuilder(@onnull Opcodes opcodes)65     public DexBuilder(@Nonnull Opcodes opcodes) {
66         super(opcodes);
67     }
68 
getSectionProvider()69     @Nonnull @Override protected SectionProvider getSectionProvider() {
70         return new DexBuilderSectionProvider();
71     }
72 
internField(@onnull String definingClass, @Nonnull String name, @Nonnull String type, int accessFlags, @Nullable EncodedValue initialValue, @Nonnull Set<? extends Annotation> annotations)73     @Nonnull public BuilderField internField(@Nonnull String definingClass,
74                                              @Nonnull String name,
75                                              @Nonnull String type,
76                                              int accessFlags,
77                                              @Nullable EncodedValue initialValue,
78                                              @Nonnull Set<? extends Annotation> annotations) {
79         return new BuilderField(fieldSection.internField(definingClass, name, type),
80                 accessFlags,
81                 internNullableEncodedValue(initialValue),
82                 annotationSetSection.internAnnotationSet(annotations));
83     }
84 
internMethod(@onnull String definingClass, @Nonnull String name, @Nullable List<? extends MethodParameter> parameters, @Nonnull String returnType, int accessFlags, @Nonnull Set<? extends Annotation> annotations, @Nullable MethodImplementation methodImplementation)85     @Nonnull public BuilderMethod internMethod(@Nonnull String definingClass,
86                                                @Nonnull String name,
87                                                @Nullable List<? extends MethodParameter> parameters,
88                                                @Nonnull String returnType,
89                                                int accessFlags,
90                                                @Nonnull Set<? extends Annotation> annotations,
91                                                @Nullable MethodImplementation methodImplementation) {
92         if (parameters == null) {
93             parameters = ImmutableList.of();
94         }
95         return new BuilderMethod(methodSection.internMethod(definingClass, name, parameters, returnType),
96                 internMethodParameters(parameters),
97                 accessFlags,
98                 annotationSetSection.internAnnotationSet(annotations),
99                 methodImplementation);
100     }
101 
internClassDef(@onnull String type, int accessFlags, @Nullable String superclass, @Nullable List<String> interfaces, @Nullable String sourceFile, @Nonnull Set<? extends Annotation> annotations, @Nullable Iterable<? extends BuilderField> fields, @Nullable Iterable<? extends BuilderMethod> methods)102     @Nonnull public BuilderClassDef internClassDef(@Nonnull String type,
103                                                    int accessFlags,
104                                                    @Nullable String superclass,
105                                                    @Nullable List<String> interfaces,
106                                                    @Nullable String sourceFile,
107                                                    @Nonnull Set<? extends Annotation> annotations,
108                                                    @Nullable Iterable<? extends BuilderField> fields,
109                                                    @Nullable Iterable<? extends BuilderMethod> methods) {
110         if (interfaces == null) {
111             interfaces = ImmutableList.of();
112         } else {
113             Set<String> interfaces_copy = Sets.newHashSet(interfaces);
114             Iterator<String> interfaceIterator = interfaces.iterator();
115             while (interfaceIterator.hasNext()) {
116                 String iface = interfaceIterator.next();
117                 if (!interfaces_copy.contains(iface)) {
118                     interfaceIterator.remove();
119                 } else {
120                     interfaces_copy.remove(iface);
121                 }
122             }
123         }
124 
125         ImmutableSortedSet<BuilderField> staticFields = null;
126         ImmutableSortedSet<BuilderField> instanceFields = null;
127         BuilderArrayEncodedValue internedStaticInitializers = null;
128         if (fields != null) {
129             staticFields = ImmutableSortedSet.copyOf(Iterables.filter(fields, FieldUtil.FIELD_IS_STATIC));
130             instanceFields = ImmutableSortedSet.copyOf(Iterables.filter(fields, FieldUtil.FIELD_IS_INSTANCE));
131             ArrayEncodedValue staticInitializers = StaticInitializerUtil.getStaticInitializers(staticFields);
132             if (staticInitializers != null) {
133                 internedStaticInitializers = encodedArraySection.internArrayEncodedValue(staticInitializers);
134             }
135         }
136 
137         return classSection.internClass(new BuilderClassDef(typeSection.internType(type),
138                 accessFlags,
139                 typeSection.internNullableType(superclass),
140                 typeListSection.internTypeList(interfaces),
141                 stringSection.internNullableString(sourceFile),
142                 annotationSetSection.internAnnotationSet(annotations),
143                 staticFields,
144                 instanceFields,
145                 methods,
146                 internedStaticInitializers));
147     }
148 
internCallSite(@onnull CallSiteReference callSiteReference)149     public BuilderCallSiteReference internCallSite(@Nonnull CallSiteReference callSiteReference) {
150         return callSiteSection.internCallSite(callSiteReference);
151     }
152 
internMethodHandle(@onnull MethodHandleReference methodHandleReference)153     public BuilderMethodHandleReference internMethodHandle(@Nonnull MethodHandleReference methodHandleReference) {
154         return methodHandleSection.internMethodHandle(methodHandleReference);
155     }
156 
internStringReference(@onnull String string)157     @Nonnull public BuilderStringReference internStringReference(@Nonnull String string) {
158         return stringSection.internString(string);
159     }
160 
internNullableStringReference(@ullable String string)161     @Nullable public BuilderStringReference internNullableStringReference(@Nullable String string) {
162         if (string != null) {
163             return internStringReference(string);
164         }
165         return null;
166     }
167 
internTypeReference(@onnull String type)168     @Nonnull public BuilderTypeReference internTypeReference(@Nonnull String type) {
169         return typeSection.internType(type);
170     }
171 
internNullableTypeReference(@ullable String type)172     @Nullable public BuilderTypeReference internNullableTypeReference(@Nullable String type) {
173         if (type != null) {
174             return internTypeReference(type);
175         }
176         return null;
177     }
178 
internFieldReference(@onnull FieldReference field)179     @Nonnull public BuilderFieldReference internFieldReference(@Nonnull FieldReference field) {
180         return fieldSection.internField(field);
181     }
182 
internMethodReference(@onnull MethodReference method)183     @Nonnull public BuilderMethodReference internMethodReference(@Nonnull MethodReference method) {
184         return methodSection.internMethod(method);
185     }
186 
internMethodProtoReference(@onnull MethodProtoReference methodProto)187     @Nonnull public BuilderMethodProtoReference internMethodProtoReference(@Nonnull MethodProtoReference methodProto) {
188         return protoSection.internMethodProto(methodProto);
189     }
190 
internReference(@onnull Reference reference)191     @Nonnull public BuilderReference internReference(@Nonnull Reference reference) {
192         if (reference instanceof StringReference) {
193             return internStringReference(((StringReference)reference).getString());
194         }
195         if (reference instanceof TypeReference) {
196             return internTypeReference(((TypeReference)reference).getType());
197         }
198         if (reference instanceof MethodReference) {
199             return internMethodReference((MethodReference)reference);
200         }
201         if (reference instanceof FieldReference) {
202             return internFieldReference((FieldReference)reference);
203         }
204         if (reference instanceof MethodProtoReference) {
205             return internMethodProtoReference((MethodProtoReference) reference);
206         }
207         if (reference instanceof CallSiteReference) {
208             return internCallSite((CallSiteReference) reference);
209         }
210         if (reference instanceof MethodHandleReference) {
211             return internMethodHandle((MethodHandleReference) reference);
212         }
213         throw new IllegalArgumentException("Could not determine type of reference");
214     }
215 
internMethodParameters( @ullable List<? extends MethodParameter> methodParameters)216     @Nonnull private List<BuilderMethodParameter> internMethodParameters(
217             @Nullable List<? extends MethodParameter> methodParameters) {
218         if (methodParameters == null) {
219             return ImmutableList.of();
220         }
221         return ImmutableList.copyOf(Iterators.transform(methodParameters.iterator(),
222                 new Function<MethodParameter, BuilderMethodParameter>() {
223                     @Nullable @Override public BuilderMethodParameter apply(MethodParameter input) {
224                         return internMethodParameter(input);
225                     }
226                 }));
227     }
228 
229     @Nonnull private BuilderMethodParameter internMethodParameter(@Nonnull MethodParameter methodParameter) {
230         return new BuilderMethodParameter(
231                 typeSection.internType(methodParameter.getType()),
232                 stringSection.internNullableString(methodParameter.getName()),
233                 annotationSetSection.internAnnotationSet(methodParameter.getAnnotations()));
234     }
235 
236     @Override protected void writeEncodedValue(@Nonnull InternalEncodedValueWriter writer,
237                                                @Nonnull BuilderEncodedValue encodedValue) throws IOException {
238         switch (encodedValue.getValueType()) {
239             case ValueType.ANNOTATION:
240                 BuilderAnnotationEncodedValue annotationEncodedValue = (BuilderAnnotationEncodedValue)encodedValue;
241                 writer.writeAnnotation(annotationEncodedValue.typeReference, annotationEncodedValue.elements);
242                 break;
243             case ValueType.ARRAY:
244                 BuilderArrayEncodedValue arrayEncodedValue = (BuilderArrayEncodedValue)encodedValue;
245                 writer.writeArray(arrayEncodedValue.elements);
246                 break;
247             case ValueType.BOOLEAN:
248                 writer.writeBoolean(((BooleanEncodedValue)encodedValue).getValue());
249                 break;
250             case ValueType.BYTE:
251                 writer.writeByte(((ByteEncodedValue)encodedValue).getValue());
252                 break;
253             case ValueType.CHAR:
254                 writer.writeChar(((CharEncodedValue)encodedValue).getValue());
255                 break;
256             case ValueType.DOUBLE:
257                 writer.writeDouble(((DoubleEncodedValue)encodedValue).getValue());
258                 break;
259             case ValueType.ENUM:
260                 writer.writeEnum(((BuilderEnumEncodedValue)encodedValue).getValue());
261                 break;
262             case ValueType.FIELD:
263                 writer.writeField(((BuilderFieldEncodedValue)encodedValue).fieldReference);
264                 break;
265             case ValueType.FLOAT:
266                 writer.writeFloat(((FloatEncodedValue)encodedValue).getValue());
267                 break;
268             case ValueType.INT:
269                 writer.writeInt(((IntEncodedValue)encodedValue).getValue());
270                 break;
271             case ValueType.LONG:
272                 writer.writeLong(((LongEncodedValue)encodedValue).getValue());
273                 break;
274             case ValueType.METHOD:
275                 writer.writeMethod(((BuilderMethodEncodedValue)encodedValue).methodReference);
276                 break;
277             case ValueType.NULL:
278                 writer.writeNull();
279                 break;
280             case ValueType.SHORT:
281                 writer.writeShort(((ShortEncodedValue)encodedValue).getValue());
282                 break;
283             case ValueType.STRING:
284                 writer.writeString(((BuilderStringEncodedValue)encodedValue).stringReference);
285                 break;
286             case ValueType.TYPE:
287                 writer.writeType(((BuilderTypeEncodedValue)encodedValue).typeReference);
288                 break;
289             case ValueType.METHOD_TYPE:
290                 writer.writeMethodType(((BuilderMethodTypeEncodedValue) encodedValue).methodProtoReference);
291                 break;
292             case ValueType.METHOD_HANDLE:
293                 writer.writeMethodHandle(((BuilderMethodHandleEncodedValue) encodedValue).methodHandleReference);
294                 break;
295             default:
296                 throw new ExceptionWithContext("Unrecognized value type: %d", encodedValue.getValueType());
297         }
298     }
299 
300     @Nonnull Set<? extends BuilderAnnotationElement> internAnnotationElements(
301             @Nonnull Set<? extends AnnotationElement> elements) {
302         return ImmutableSet.copyOf(
303                 Iterators.transform(elements.iterator(),
304                         new Function<AnnotationElement, BuilderAnnotationElement>() {
305                             @Nullable @Override
306                             public BuilderAnnotationElement apply(AnnotationElement input) {
307                                 return internAnnotationElement(input);
308                             }
309                         }));
310     }
311 
312     @Nonnull private BuilderAnnotationElement internAnnotationElement(@Nonnull AnnotationElement annotationElement) {
313         return new BuilderAnnotationElement(stringSection.internString(annotationElement.getName()),
314                 internEncodedValue(annotationElement.getValue()));
315     }
316 
317     @Nullable BuilderEncodedValue internNullableEncodedValue(@Nullable EncodedValue encodedValue) {
318         if (encodedValue == null) {
319             return null;
320         }
321         return internEncodedValue(encodedValue);
322     }
323 
324     @Nonnull BuilderEncodedValue internEncodedValue(@Nonnull EncodedValue encodedValue) {
325         switch (encodedValue.getValueType()) {
326             case ValueType.ANNOTATION:
327                 return internAnnotationEncodedValue((AnnotationEncodedValue)encodedValue);
328             case ValueType.ARRAY:
329                 return internArrayEncodedValue((ArrayEncodedValue)encodedValue);
330             case ValueType.BOOLEAN:
331                 boolean value = ((BooleanEncodedValue)encodedValue).getValue();
332                 return value?BuilderBooleanEncodedValue.TRUE_VALUE:BuilderBooleanEncodedValue.FALSE_VALUE;
333             case ValueType.BYTE:
334                 return new BuilderByteEncodedValue(((ByteEncodedValue)encodedValue).getValue());
335             case ValueType.CHAR:
336                 return new BuilderCharEncodedValue(((CharEncodedValue)encodedValue).getValue());
337             case ValueType.DOUBLE:
338                 return new BuilderDoubleEncodedValue(((DoubleEncodedValue)encodedValue).getValue());
339             case ValueType.ENUM:
340                 return internEnumEncodedValue((EnumEncodedValue)encodedValue);
341             case ValueType.FIELD:
342                 return internFieldEncodedValue((FieldEncodedValue)encodedValue);
343             case ValueType.FLOAT:
344                 return new BuilderFloatEncodedValue(((FloatEncodedValue)encodedValue).getValue());
345             case ValueType.INT:
346                 return new BuilderIntEncodedValue(((IntEncodedValue)encodedValue).getValue());
347             case ValueType.LONG:
348                 return new BuilderLongEncodedValue(((LongEncodedValue)encodedValue).getValue());
349             case ValueType.METHOD:
350                 return internMethodEncodedValue((MethodEncodedValue)encodedValue);
351             case ValueType.NULL:
352                 return BuilderNullEncodedValue.INSTANCE;
353             case ValueType.SHORT:
354                 return new BuilderShortEncodedValue(((ShortEncodedValue)encodedValue).getValue());
355             case ValueType.STRING:
356                 return internStringEncodedValue((StringEncodedValue)encodedValue);
357             case ValueType.TYPE:
358                 return internTypeEncodedValue((TypeEncodedValue)encodedValue);
359             case ValueType.METHOD_TYPE:
360                 return internMethodTypeEncodedValue((MethodTypeEncodedValue) encodedValue);
361             case ValueType.METHOD_HANDLE:
362                 return internMethodHandleEncodedValue((MethodHandleEncodedValue) encodedValue);
363             default:
364                 throw new ExceptionWithContext("Unexpected encoded value type: %d", encodedValue.getValueType());
365         }
366     }
367 
368     @Nonnull private BuilderAnnotationEncodedValue internAnnotationEncodedValue(@Nonnull AnnotationEncodedValue value) {
369         return new BuilderAnnotationEncodedValue(
370                 typeSection.internType(value.getType()),
371                 internAnnotationElements(value.getElements()));
372     }
373 
374     @Nonnull private BuilderArrayEncodedValue internArrayEncodedValue(@Nonnull ArrayEncodedValue value) {
375         return new BuilderArrayEncodedValue(
376                 ImmutableList.copyOf(
377                         Iterators.transform(value.getValue().iterator(),
378                                 new Function<EncodedValue, BuilderEncodedValue>() {
379                                     @Nullable @Override public BuilderEncodedValue apply(EncodedValue input) {
380                                         return internEncodedValue(input);
381                                     }
382                                 })));
383     }
384 
385     @Nonnull private BuilderEnumEncodedValue internEnumEncodedValue(@Nonnull EnumEncodedValue value) {
386         return new BuilderEnumEncodedValue(fieldSection.internField(value.getValue()));
387     }
388 
389     @Nonnull private BuilderFieldEncodedValue internFieldEncodedValue(@Nonnull FieldEncodedValue value) {
390         return new BuilderFieldEncodedValue(fieldSection.internField(value.getValue()));
391     }
392 
393     @Nonnull private BuilderMethodEncodedValue internMethodEncodedValue(@Nonnull MethodEncodedValue value) {
394         return new BuilderMethodEncodedValue(methodSection.internMethod(value.getValue()));
395     }
396 
397     @Nonnull private BuilderStringEncodedValue internStringEncodedValue(@Nonnull StringEncodedValue string) {
398         return new BuilderStringEncodedValue(stringSection.internString(string.getValue()));
399     }
400 
401     @Nonnull private BuilderTypeEncodedValue internTypeEncodedValue(@Nonnull TypeEncodedValue type) {
402         return new BuilderTypeEncodedValue(typeSection.internType(type.getValue()));
403     }
404 
405     @Nonnull private BuilderMethodTypeEncodedValue internMethodTypeEncodedValue(
406             @Nonnull MethodTypeEncodedValue methodType) {
407         return new BuilderMethodTypeEncodedValue(protoSection.internMethodProto(methodType.getValue()));
408     }
409 
410     @Nonnull private BuilderMethodHandleEncodedValue internMethodHandleEncodedValue(
411             @Nonnull MethodHandleEncodedValue methodHandle) {
412         return new BuilderMethodHandleEncodedValue(methodHandleSection.internMethodHandle(methodHandle.getValue()));
413     }
414 
415     protected class DexBuilderSectionProvider extends SectionProvider {
416         @Nonnull @Override public BuilderStringPool getStringSection() {
417             return new BuilderStringPool();
418         }
419 
420         @Nonnull @Override public BuilderTypePool getTypeSection() {
421             return new BuilderTypePool(DexBuilder.this);
422         }
423 
424         @Nonnull @Override public BuilderProtoPool getProtoSection() {
425             return new BuilderProtoPool(DexBuilder.this);
426         }
427 
428         @Nonnull @Override public BuilderFieldPool getFieldSection() {
429             return new BuilderFieldPool(DexBuilder.this);
430         }
431 
432         @Nonnull @Override public BuilderMethodPool getMethodSection() {
433             return new BuilderMethodPool(DexBuilder.this);
434         }
435 
436         @Nonnull @Override public BuilderClassPool getClassSection() {
437             return new BuilderClassPool(DexBuilder.this);
438         }
439 
440         @Nonnull @Override public BuilderCallSitePool getCallSiteSection() {
441             return new BuilderCallSitePool(DexBuilder.this);
442         }
443 
444         @Nonnull @Override public BuilderMethodHandlePool getMethodHandleSection() {
445             return new BuilderMethodHandlePool(DexBuilder.this);
446         }
447 
448         @Nonnull @Override public BuilderTypeListPool getTypeListSection() {
449             return new BuilderTypeListPool(DexBuilder.this);
450         }
451 
452         @Nonnull @Override public BuilderAnnotationPool getAnnotationSection() {
453             return new BuilderAnnotationPool(DexBuilder.this);
454         }
455 
456         @Nonnull @Override public BuilderAnnotationSetPool getAnnotationSetSection() {
457             return new BuilderAnnotationSetPool(DexBuilder.this);
458         }
459 
460         @Nonnull @Override public BuilderEncodedArrayPool getEncodedArraySection() {
461             return new BuilderEncodedArrayPool(DexBuilder.this);
462         }
463     }
464 }
465