private int getDataSectionOffset() { return HeaderItem.ITEM_SIZE + stringSection.getItemCount() * StringIdItem.ITEM_SIZE + typeSection.getItemCount() * TypeIdItem.ITEM_SIZE + protoSection.getItemCount() * ProtoIdItem.ITEM_SIZE + fieldSection.getItemCount() * FieldIdItem.ITEM_SIZE + methodSection.getItemCount() * MethodIdItem.ITEM_SIZE + classSection.getItemCount() * ClassDefItem.ITEM_SIZE + callSiteSection.getItemCount() * CallSiteIdItem.ITEM_SIZE + methodHandleSection.getItemCount() * MethodHandleItem.ITEM_SIZE; }
/** * Checks whether any of the size-sensitive constant pools have more than the supplied maximum number of entries. * * @param maxPoolSize the maximum number of entries allowed in any of the size-sensitive constant pools * @return true if any of the size-sensitive constant pools have overflowed the supplied size limit */ public boolean hasOverflowed(int maxPoolSize) { for (IndexSection section: overflowableSections) { if (section.getItemCount() > maxPoolSize) return true; } return false; }
private void writeAnnotations(@Nonnull DexDataWriter writer) throws IOException { InternalEncodedValueWriter encodedValueWriter = new InternalEncodedValueWriter(writer); annotationSectionOffset = writer.getPosition(); for (Map.Entry<? extends AnnotationKey, Integer> entry: annotationSection.getItems()) { entry.setValue(writer.getPosition()); AnnotationKey key = entry.getKey(); writer.writeUbyte(annotationSection.getVisibility(key)); writer.writeUleb128(typeSection.getItemIndex(annotationSection.getType(key))); Collection<? extends AnnotationElement> elements = Ordering.from(BaseAnnotationElement.BY_NAME) .immutableSortedCopy(annotationSection.getElements(key)); writer.writeUleb128(elements.size()); for (AnnotationElement element: elements) { writer.writeUleb128(stringSection.getItemIndex(annotationSection.getElementName(element))); writeEncodedValue(encodedValueWriter, annotationSection.getElementValue(element)); } } }
private void writeMethods(@Nonnull DexDataWriter writer) throws IOException { methodSectionOffset = writer.getPosition(); int index = 0; List<Map.Entry<? extends MethodRefKey, Integer>> methodEntries = Lists.newArrayList(methodSection.getItems()); Collections.sort(methodEntries, DexWriter.<MethodRefKey>comparableKeyComparator()); for (Map.Entry<? extends MethodRefKey, Integer> entry: methodEntries) { entry.setValue(index++); MethodRefKey key = entry.getKey(); writer.writeUshort(typeSection.getItemIndex(methodSection.getDefiningClass(key))); writer.writeUshort(protoSection.getItemIndex(methodSection.getPrototype(key))); writer.writeInt(stringSection.getItemIndex(methodSection.getName(key))); } }
private void writeFields(@Nonnull DexDataWriter writer) throws IOException { fieldSectionOffset = writer.getPosition(); int index = 0; List<Map.Entry<? extends FieldRefKey, Integer>> fieldEntries = Lists.newArrayList(fieldSection.getItems()); Collections.sort(fieldEntries, DexWriter.<FieldRefKey>comparableKeyComparator()); for (Map.Entry<? extends FieldRefKey, Integer> entry: fieldEntries) { entry.setValue(index++); FieldRefKey key = entry.getKey(); writer.writeUshort(typeSection.getItemIndex(fieldSection.getDefiningClass(key))); writer.writeUshort(typeSection.getItemIndex(fieldSection.getFieldType(key))); writer.writeInt(stringSection.getItemIndex(fieldSection.getName(key))); } }
private void writeProtos(@Nonnull DexDataWriter writer) throws IOException { protoSectionOffset = writer.getPosition(); int index = 0; List<Map.Entry<? extends ProtoRefKey, Integer>> protoEntries = Lists.newArrayList(protoSection.getItems()); Collections.sort(protoEntries, DexWriter.<ProtoRefKey>comparableKeyComparator()); for (Map.Entry<? extends ProtoRefKey, Integer> entry: protoEntries) { entry.setValue(index++); ProtoRefKey key = entry.getKey(); writer.writeInt(stringSection.getItemIndex(protoSection.getShorty(key))); writer.writeInt(typeSection.getItemIndex(protoSection.getReturnType(key))); writer.writeInt(typeListSection.getNullableItemOffset(protoSection.getParameters(key))); } }
private void writeHeader(@Nonnull DexDataWriter writer, int dataOffset, int fileSize) throws IOException { // Write the appropriate header. writer.write(HeaderItem.getMagicForApi(opcodes.api)); // checksum placeholder writer.writeInt(0); // signature placeholder writer.write(new byte[20]); writer.writeInt(fileSize); writer.writeInt(HeaderItem.ITEM_SIZE); writer.writeInt(HeaderItem.LITTLE_ENDIAN_TAG); // link writer.writeInt(0); writer.writeInt(0); // map writer.writeInt(mapSectionOffset); // index sections writeSectionInfo(writer, stringSection.getItems().size(), stringIndexSectionOffset); writeSectionInfo(writer, typeSection.getItems().size(), typeSectionOffset); writeSectionInfo(writer, protoSection.getItems().size(), protoSectionOffset); writeSectionInfo(writer, fieldSection.getItems().size(), fieldSectionOffset); writeSectionInfo(writer, methodSection.getItems().size(), methodSectionOffset); writeSectionInfo(writer, classSection.getItems().size(), classIndexSectionOffset); // data section writer.writeInt(fileSize - dataOffset); writer.writeInt(dataOffset); }
protected DexWriter(Opcodes opcodes) { this.opcodes = opcodes; SectionProvider sectionProvider = getSectionProvider(); this.stringSection = sectionProvider.getStringSection(); this.typeSection = sectionProvider.getTypeSection(); this.protoSection = sectionProvider.getProtoSection(); this.fieldSection = sectionProvider.getFieldSection(); this.methodSection = sectionProvider.getMethodSection(); this.classSection = sectionProvider.getClassSection(); this.callSiteSection = sectionProvider.getCallSiteSection(); this.methodHandleSection = sectionProvider.getMethodHandleSection(); this.typeListSection = sectionProvider.getTypeListSection(); this.annotationSection = sectionProvider.getAnnotationSection(); this.annotationSetSection = sectionProvider.getAnnotationSetSection(); this.encodedArraySection = sectionProvider.getEncodedArraySection(); overflowableSections = new IndexSection<?>[] { //stringSection, // supports jumbo indexes typeSection, protoSection, fieldSection, methodSection, //classSection, // redundant check: cannot be larger than typeSection callSiteSection, methodHandleSection, }; }
private void writeTypeLists(@Nonnull DexDataWriter writer) throws IOException { writer.align(); typeListSectionOffset = writer.getPosition(); for (Map.Entry<? extends TypeListKey, Integer> entry: typeListSection.getItems()) { writer.align(); entry.setValue(writer.getPosition()); Collection<? extends TypeKey> types = typeListSection.getTypes(entry.getKey()); writer.writeInt(types.size()); for (TypeKey typeKey: types) { writer.writeUshort(typeSection.getItemIndex(typeKey)); } } }
private void writeAnnotationSets(@Nonnull DexDataWriter writer) throws IOException { writer.align(); annotationSetSectionOffset = writer.getPosition(); if (shouldCreateEmptyAnnotationSet()) { writer.writeInt(0); } for (Map.Entry<? extends AnnotationSetKey, Integer> entry: annotationSetSection.getItems()) { Collection<? extends AnnotationKey> annotations = Ordering.from(BaseAnnotation.BY_TYPE) .immutableSortedCopy(annotationSetSection.getAnnotations(entry.getKey())); writer.align(); entry.setValue(writer.getPosition()); writer.writeInt(annotations.size()); for (AnnotationKey annotationKey: annotations) { writer.writeInt(annotationSection.getItemOffset(annotationKey)); } } }
private void writeEncodedArrays(@Nonnull DexDataWriter writer) throws IOException { InternalEncodedValueWriter encodedValueWriter = new InternalEncodedValueWriter(writer); encodedArraySectionOffset = writer.getPosition(); for (Map.Entry<? extends EncodedArrayKey, Integer> entry: encodedArraySection.getItems()) { entry.setValue(writer.getPosition()); List<? extends EncodedValue> encodedArray = encodedArraySection.getEncodedValueList(entry.getKey()); writer.writeUleb128(encodedArray.size()); for (EncodedValue value: encodedArray) { writeEncodedValue(encodedValueWriter, value); } } }
private void writeTypes(@Nonnull DexDataWriter writer) throws IOException { typeSectionOffset = writer.getPosition(); int index = 0; List<Map.Entry<? extends TypeKey, Integer>> typeEntries = Lists.newArrayList(typeSection.getItems()); Collections.sort(typeEntries, toStringKeyComparator); for (Map.Entry<? extends TypeKey, Integer> entry : typeEntries) { entry.setValue(index++); writer.writeInt(stringSection.getItemIndex(typeSection.getString(entry.getKey()))); } }
private void writeCallSites(DexDataWriter writer) throws IOException { callSiteSectionOffset = writer.getPosition(); List<Map.Entry<? extends CallSiteKey, Integer>> callSiteEntries = Lists.newArrayList(callSiteSection.getItems()); Collections.sort(callSiteEntries, callSiteComparator); int index = 0; for (Map.Entry<? extends CallSiteKey, Integer> callSite: callSiteEntries) { callSite.setValue(index++); writer.writeInt(encodedArraySection.getItemOffset(callSiteSection.getEncodedCallSite(callSite.getKey()))); } }
private void writeEncodedMethods(@Nonnull DexDataWriter writer, @Nonnull Collection<? extends MethodKey> methods) throws IOException { int prevIndex = 0; for (MethodKey key: methods) { int index = methodSection.getMethodIndex(key); writer.writeUleb128(index-prevIndex); writer.writeUleb128(classSection.getMethodAccessFlags(key)); writer.writeUleb128(classSection.getCodeItemOffset(key)); prevIndex = index; } }
private void writeClasses(@Nonnull DexDataWriter indexWriter, @Nonnull DexDataWriter offsetWriter) throws IOException { classIndexSectionOffset = indexWriter.getPosition(); classDataSectionOffset = offsetWriter.getPosition(); List<Map.Entry<? extends ClassKey, Integer>> classEntries = Lists.newArrayList(classSection.getItems()); Collections.sort(classEntries, DexWriter.<ClassKey>comparableKeyComparator()); int index = 0; for (Map.Entry<? extends ClassKey, Integer> key: classEntries) { index = writeClass(indexWriter, offsetWriter, index, key); } }
private void writeEncodedFields(@Nonnull DexDataWriter writer, @Nonnull Collection<? extends FieldKey> fields) throws IOException { int prevIndex = 0; for (FieldKey key: fields) { int index = fieldSection.getFieldIndex(key); writer.writeUleb128(index - prevIndex); writer.writeUleb128(classSection.getFieldAccessFlags(key)); prevIndex = index; } }
private void writeMapItem(@Nonnull DexDataWriter writer, int type, int size, int offset) throws IOException { if (size > 0) { writer.writeUshort(type); writer.writeUshort(0); writer.writeInt(size); writer.writeInt(offset); } }
@Override public int compare(Entry<? extends CallSiteKey, Integer> o1, Entry<? extends CallSiteKey, Integer> o2) { int offset1 = encodedArraySection.getItemOffset(callSiteSection.getEncodedCallSite(o1.getKey())); int offset2 = encodedArraySection.getItemOffset(callSiteSection.getEncodedCallSite(o2.getKey())); return Ints.compare(offset1, offset2); } };
/** * Checks whether any of the size-sensitive constant pools have overflowed and have more than 64Ki entries. * * Note that even if this returns true, it may still be possible to successfully write the dex file, if the * overflowed items are not referenced anywhere that uses a 16-bit index. * * @return true if any of the size-sensitive constant pools have overflowed */ public boolean hasOverflowed() { return hasOverflowed(MAX_POOL_SIZE); }