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