com.tencent.tinker.commons.dexpatcher.util.AbstractIndexMap Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of tinker-commons Show documentation
Show all versions of tinker-commons Show documentation
Tinker is a hot-fix solution library for Android, it supports dex, library and resources update without reinstalling apk.
/*
* Copyright (C) 2007 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.tencent.tinker.commons.dexpatcher.util;
import com.tencent.tinker.android.dex.Annotation;
import com.tencent.tinker.android.dex.AnnotationSet;
import com.tencent.tinker.android.dex.AnnotationSetRefList;
import com.tencent.tinker.android.dex.AnnotationsDirectory;
import com.tencent.tinker.android.dex.ClassData;
import com.tencent.tinker.android.dex.ClassDef;
import com.tencent.tinker.android.dex.Code;
import com.tencent.tinker.android.dex.DebugInfoItem;
import com.tencent.tinker.android.dex.DexException;
import com.tencent.tinker.android.dex.EncodedValue;
import com.tencent.tinker.android.dex.EncodedValueCodec;
import com.tencent.tinker.android.dex.EncodedValueReader;
import com.tencent.tinker.android.dex.FieldId;
import com.tencent.tinker.android.dex.Leb128;
import com.tencent.tinker.android.dex.MethodId;
import com.tencent.tinker.android.dex.ProtoId;
import com.tencent.tinker.android.dex.TypeList;
import com.tencent.tinker.android.dex.util.ByteInput;
import com.tencent.tinker.android.dex.util.ByteOutput;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
/**
* Created by tangyinsheng on 2016/6/29.
*
* *** This file is renamed from IndexMap in dx project. ***
*/
public abstract class AbstractIndexMap {
public abstract int adjustStringIndex(int stringIndex);
public abstract int adjustTypeIdIndex(int typeIdIndex);
public abstract int adjustProtoIdIndex(int protoIndex);
public abstract int adjustFieldIdIndex(int fieldIndex);
public abstract int adjustMethodIdIndex(int methodIndex);
public abstract int adjustTypeListOffset(int typeListOffset);
public abstract int adjustAnnotationOffset(int annotationOffset);
public abstract int adjustAnnotationSetOffset(int annotationSetOffset);
public abstract int adjustAnnotationSetRefListOffset(int annotationSetRefListOffset);
public abstract int adjustAnnotationsDirectoryOffset(int annotationsDirectoryOffset);
public abstract int adjustStaticValuesOffset(int staticValuesOffset);
public abstract int adjustClassDataOffset(int classDataOffset);
public abstract int adjustDebugInfoItemOffset(int debugInfoItemOffset);
public abstract int adjustCodeOffset(int codeOffset);
public TypeList adjust(TypeList typeList) {
if (typeList == TypeList.EMPTY) {
return typeList;
}
short[] types = new short[typeList.types.length];
for (int i = 0; i < types.length; ++i) {
types[i] = (short) adjustTypeIdIndex(typeList.types[i]);
}
return new TypeList(typeList.off, types);
}
public MethodId adjust(MethodId methodId) {
int adjustedDeclaringClassIndex = adjustTypeIdIndex(methodId.declaringClassIndex);
int adjustedProtoIndex = adjustProtoIdIndex(methodId.protoIndex);
int adjustedNameIndex = adjustStringIndex(methodId.nameIndex);
return new MethodId(
methodId.off, adjustedDeclaringClassIndex, adjustedProtoIndex, adjustedNameIndex
);
}
public FieldId adjust(FieldId fieldId) {
int adjustedDeclaringClassIndex = adjustTypeIdIndex(fieldId.declaringClassIndex);
int adjustedTypeIndex = adjustTypeIdIndex(fieldId.typeIndex);
int adjustedNameIndex = adjustStringIndex(fieldId.nameIndex);
return new FieldId(
fieldId.off, adjustedDeclaringClassIndex, adjustedTypeIndex, adjustedNameIndex
);
}
public ProtoId adjust(ProtoId protoId) {
int adjustedShortyIndex = adjustStringIndex(protoId.shortyIndex);
int adjustedReturnTypeIndex = adjustTypeIdIndex(protoId.returnTypeIndex);
int adjustedParametersOffset = adjustTypeListOffset(protoId.parametersOffset);
return new ProtoId(
protoId.off, adjustedShortyIndex, adjustedReturnTypeIndex, adjustedParametersOffset
);
}
public ClassDef adjust(ClassDef classDef) {
int adjustedTypeIndex = adjustTypeIdIndex(classDef.typeIndex);
int adjustedSupertypeIndex = adjustTypeIdIndex(classDef.supertypeIndex);
int adjustedInterfacesOffset = adjustTypeListOffset(classDef.interfacesOffset);
int adjustedSourceFileIndex = adjustStringIndex(classDef.sourceFileIndex);
int adjustedAnnotationsOffset = adjustAnnotationsDirectoryOffset(classDef.annotationsOffset);
int adjustedClassDataOffset = adjustClassDataOffset(classDef.classDataOffset);
int adjustedStaticValuesOffset = adjustStaticValuesOffset(classDef.staticValuesOffset);
return new ClassDef(
classDef.off, adjustedTypeIndex, classDef.accessFlags, adjustedSupertypeIndex,
adjustedInterfacesOffset, adjustedSourceFileIndex, adjustedAnnotationsOffset,
adjustedClassDataOffset, adjustedStaticValuesOffset
);
}
public ClassData adjust(ClassData classData) {
ClassData.Field[] adjustedStaticFields = adjustFields(classData.staticFields);
ClassData.Field[] adjustedInstanceFields = adjustFields(classData.instanceFields);
ClassData.Method[] adjustedDirectMethods = adjustMethods(classData.directMethods);
ClassData.Method[] adjustedVirtualMethods = adjustMethods(classData.virtualMethods);
return new ClassData(
classData.off, adjustedStaticFields, adjustedInstanceFields,
adjustedDirectMethods, adjustedVirtualMethods
);
}
public Code adjust(Code code) {
int adjustedDebugInfoOffset = adjustDebugInfoItemOffset(code.debugInfoOffset);
short[] adjustedInstructions = adjustInstructions(code.instructions);
Code.CatchHandler[] adjustedCatchHandlers = adjustCatchHandlers(code.catchHandlers);
return new Code(
code.off, code.registersSize, code.insSize, code.outsSize,
adjustedDebugInfoOffset, adjustedInstructions, code.tries, adjustedCatchHandlers
);
}
private short[] adjustInstructions(short[] instructions) {
if (instructions == null || instructions.length == 0) {
return instructions;
}
InstructionTransformer insTrans = new InstructionTransformer(this);
return insTrans.transform(instructions);
}
private Code.CatchHandler[] adjustCatchHandlers(Code.CatchHandler[] catchHandlers) {
if (catchHandlers == null || catchHandlers.length == 0) {
return catchHandlers;
}
Code.CatchHandler[] adjustedCatchHandlers = new Code.CatchHandler[catchHandlers.length];
for (int i = 0; i < catchHandlers.length; ++i) {
Code.CatchHandler catchHandler = catchHandlers[i];
int typeIndexesCount = catchHandler.typeIndexes.length;
int[] adjustedTypeIndexes = new int[typeIndexesCount];
for (int j = 0; j < typeIndexesCount; ++j) {
adjustedTypeIndexes[j] = adjustTypeIdIndex(catchHandler.typeIndexes[j]);
}
adjustedCatchHandlers[i] = new Code.CatchHandler(
adjustedTypeIndexes, catchHandler.addresses,
catchHandler.catchAllAddress, catchHandler.offset
);
}
return adjustedCatchHandlers;
}
private ClassData.Field[] adjustFields(ClassData.Field[] fields) {
ClassData.Field[] adjustedFields = new ClassData.Field[fields.length];
for (int i = 0; i < fields.length; ++i) {
ClassData.Field field = fields[i];
int adjustedFieldIndex = adjustFieldIdIndex(field.fieldIndex);
adjustedFields[i] = new ClassData.Field(adjustedFieldIndex, field.accessFlags);
}
return adjustedFields;
}
private ClassData.Method[] adjustMethods(ClassData.Method[] methods) {
ClassData.Method[] adjustedMethods = new ClassData.Method[methods.length];
for (int i = 0; i < methods.length; ++i) {
ClassData.Method method = methods[i];
int adjustedMethodIndex = adjustMethodIdIndex(method.methodIndex);
int adjustedCodeOffset = adjustCodeOffset(method.codeOffset);
adjustedMethods[i] = new ClassData.Method(
adjustedMethodIndex, method.accessFlags, adjustedCodeOffset
);
}
return adjustedMethods;
}
public DebugInfoItem adjust(DebugInfoItem debugInfoItem) {
int[] parameterNames = adjustParameterNames(debugInfoItem.parameterNames);
byte[] infoSTM = adjustDebugInfoItemSTM(debugInfoItem.infoSTM);
return new DebugInfoItem(
debugInfoItem.off, debugInfoItem.lineStart, parameterNames, infoSTM
);
}
private int[] adjustParameterNames(int[] parameterNames) {
int size = parameterNames.length;
int[] adjustedParameterNames = new int[size];
for (int i = 0; i < size; ++i) {
adjustedParameterNames[i] = adjustStringIndex(parameterNames[i]);
}
return adjustedParameterNames;
}
private byte[] adjustDebugInfoItemSTM(byte[] infoSTM) {
ByteArrayInputStream bais = new ByteArrayInputStream(infoSTM);
final ByteArrayInputStream baisRef = bais;
ByteInput inAdapter = new ByteInput() {
@Override
public byte readByte() {
return (byte) (baisRef.read() & 0xFF);
}
};
ByteArrayOutputStream baos = new ByteArrayOutputStream(infoSTM.length + 512);
final ByteArrayOutputStream baosRef = baos;
ByteOutput outAdapter = new ByteOutput() {
@Override
public void writeByte(int i) {
baosRef.write(i);
}
};
outside_whileloop:
while (true) {
int opcode = bais.read() & 0xFF;
baos.write(opcode);
switch (opcode) {
case DebugInfoItem.DBG_END_SEQUENCE: {
break outside_whileloop;
}
case DebugInfoItem.DBG_ADVANCE_PC: {
int addrDiff = Leb128.readUnsignedLeb128(inAdapter);
Leb128.writeUnsignedLeb128(outAdapter, addrDiff);
break;
}
case DebugInfoItem.DBG_ADVANCE_LINE: {
int lineDiff = Leb128.readSignedLeb128(inAdapter);
Leb128.writeSignedLeb128(outAdapter, lineDiff);
break;
}
case DebugInfoItem.DBG_START_LOCAL:
case DebugInfoItem.DBG_START_LOCAL_EXTENDED: {
int registerNum = Leb128.readUnsignedLeb128(inAdapter);
Leb128.writeUnsignedLeb128(outAdapter, registerNum);
int nameIndex = adjustStringIndex(Leb128.readUnsignedLeb128p1(inAdapter));
Leb128.writeUnsignedLeb128p1(outAdapter, nameIndex);
int typeIndex = adjustTypeIdIndex(Leb128.readUnsignedLeb128p1(inAdapter));
Leb128.writeUnsignedLeb128p1(outAdapter, typeIndex);
if (opcode == DebugInfoItem.DBG_START_LOCAL_EXTENDED) {
int sigIndex = adjustStringIndex(Leb128.readUnsignedLeb128p1(inAdapter));
Leb128.writeUnsignedLeb128p1(outAdapter, sigIndex);
}
break;
}
case DebugInfoItem.DBG_END_LOCAL:
case DebugInfoItem.DBG_RESTART_LOCAL: {
int registerNum = Leb128.readUnsignedLeb128(inAdapter);
Leb128.writeUnsignedLeb128(outAdapter, registerNum);
break;
}
case DebugInfoItem.DBG_SET_FILE: {
int nameIndex = adjustStringIndex(Leb128.readUnsignedLeb128p1(inAdapter));
Leb128.writeUnsignedLeb128p1(outAdapter, nameIndex);
break;
}
case DebugInfoItem.DBG_SET_PROLOGUE_END:
case DebugInfoItem.DBG_SET_EPILOGUE_BEGIN:
default: {
break;
}
}
}
return baos.toByteArray();
}
public EncodedValue adjust(EncodedValue encodedArray) {
final ByteArrayOutputStream baos = new ByteArrayOutputStream(encodedArray.data.length);
new EncodedValueTransformer(
new ByteOutput() {
@Override
public void writeByte(int i) {
baos.write(i);
}
}
).transformArray(
new EncodedValueReader(encodedArray, EncodedValueReader.ENCODED_ARRAY)
);
return new EncodedValue(encodedArray.off, baos.toByteArray());
}
public Annotation adjust(Annotation annotation) {
final ByteArrayOutputStream baos = new ByteArrayOutputStream(annotation.encodedAnnotation.data.length);
new EncodedValueTransformer(
new ByteOutput() {
@Override
public void writeByte(int i) {
baos.write(i);
}
}
).transformAnnotation(annotation.getReader());
return new Annotation(
annotation.off,
annotation.visibility,
new EncodedValue(annotation.encodedAnnotation.off, baos.toByteArray())
);
}
public AnnotationSet adjust(AnnotationSet annotationSet) {
int size = annotationSet.annotationOffsets.length;
int[] adjustedAnnotationOffsets = new int[size];
for (int i = 0; i < size; ++i) {
adjustedAnnotationOffsets[i]
= adjustAnnotationOffset(annotationSet.annotationOffsets[i]);
}
return new AnnotationSet(annotationSet.off, adjustedAnnotationOffsets);
}
public AnnotationSetRefList adjust(AnnotationSetRefList annotationSetRefList) {
int size = annotationSetRefList.annotationSetRefItems.length;
int[] adjustedAnnotationSetRefItems = new int[size];
for (int i = 0; i < size; ++i) {
adjustedAnnotationSetRefItems[i]
= adjustAnnotationSetOffset(annotationSetRefList.annotationSetRefItems[i]);
}
return new AnnotationSetRefList(annotationSetRefList.off, adjustedAnnotationSetRefItems);
}
public AnnotationsDirectory adjust(AnnotationsDirectory annotationsDirectory) {
int adjustedClassAnnotationsOffset
= adjustAnnotationSetOffset(annotationsDirectory.classAnnotationsOffset);
int[][] adjustedFieldAnnotations
= new int[annotationsDirectory.fieldAnnotations.length][2];
for (int i = 0; i < adjustedFieldAnnotations.length; ++i) {
adjustedFieldAnnotations[i][0]
= adjustFieldIdIndex(annotationsDirectory.fieldAnnotations[i][0]);
adjustedFieldAnnotations[i][1]
= adjustAnnotationSetOffset(annotationsDirectory.fieldAnnotations[i][1]);
}
int[][] adjustedMethodAnnotations
= new int[annotationsDirectory.methodAnnotations.length][2];
for (int i = 0; i < adjustedMethodAnnotations.length; ++i) {
adjustedMethodAnnotations[i][0]
= adjustMethodIdIndex(annotationsDirectory.methodAnnotations[i][0]);
adjustedMethodAnnotations[i][1]
= adjustAnnotationSetOffset(annotationsDirectory.methodAnnotations[i][1]);
}
int[][] adjustedParameterAnnotations
= new int[annotationsDirectory.parameterAnnotations.length][2];
for (int i = 0; i < adjustedParameterAnnotations.length; ++i) {
adjustedParameterAnnotations[i][0]
= adjustMethodIdIndex(annotationsDirectory.parameterAnnotations[i][0]);
adjustedParameterAnnotations[i][1]
= adjustAnnotationSetRefListOffset(
annotationsDirectory.parameterAnnotations[i][1]
);
}
return new AnnotationsDirectory(
annotationsDirectory.off, adjustedClassAnnotationsOffset,
adjustedFieldAnnotations, adjustedMethodAnnotations, adjustedParameterAnnotations
);
}
/**
* Adjust an encoded value or array.
*/
private final class EncodedValueTransformer {
private final ByteOutput out;
EncodedValueTransformer(ByteOutput out) {
this.out = out;
}
public void transform(EncodedValueReader reader) {
switch (reader.peek()) {
case EncodedValueReader.ENCODED_BYTE:
EncodedValueCodec.writeSignedIntegralValue(out, EncodedValueReader.ENCODED_BYTE, reader.readByte());
break;
case EncodedValueReader.ENCODED_SHORT:
EncodedValueCodec.writeSignedIntegralValue(out, EncodedValueReader.ENCODED_SHORT, reader.readShort());
break;
case EncodedValueReader.ENCODED_INT:
EncodedValueCodec.writeSignedIntegralValue(out, EncodedValueReader.ENCODED_INT, reader.readInt());
break;
case EncodedValueReader.ENCODED_LONG:
EncodedValueCodec.writeSignedIntegralValue(out, EncodedValueReader.ENCODED_LONG, reader.readLong());
break;
case EncodedValueReader.ENCODED_CHAR:
EncodedValueCodec.writeUnsignedIntegralValue(out, EncodedValueReader.ENCODED_CHAR, reader.readChar());
break;
case EncodedValueReader.ENCODED_FLOAT:
// Shift value left 32 so that right-zero-extension works.
long longBits = ((long) Float.floatToIntBits(reader.readFloat())) << 32;
EncodedValueCodec.writeRightZeroExtendedValue(out, EncodedValueReader.ENCODED_FLOAT, longBits);
break;
case EncodedValueReader.ENCODED_DOUBLE:
EncodedValueCodec.writeRightZeroExtendedValue(
out, EncodedValueReader.ENCODED_DOUBLE, Double.doubleToLongBits(reader.readDouble()));
break;
case EncodedValueReader.ENCODED_STRING:
EncodedValueCodec.writeUnsignedIntegralValue(
out, EncodedValueReader.ENCODED_STRING, adjustStringIndex(reader.readString()));
break;
case EncodedValueReader.ENCODED_TYPE:
EncodedValueCodec.writeUnsignedIntegralValue(
out, EncodedValueReader.ENCODED_TYPE, adjustTypeIdIndex(reader.readType()));
break;
case EncodedValueReader.ENCODED_FIELD:
EncodedValueCodec.writeUnsignedIntegralValue(
out, EncodedValueReader.ENCODED_FIELD, adjustFieldIdIndex(reader.readField()));
break;
case EncodedValueReader.ENCODED_ENUM:
EncodedValueCodec.writeUnsignedIntegralValue(
out, EncodedValueReader.ENCODED_ENUM, adjustFieldIdIndex(reader.readEnum()));
break;
case EncodedValueReader.ENCODED_METHOD:
EncodedValueCodec.writeUnsignedIntegralValue(
out, EncodedValueReader.ENCODED_METHOD, adjustMethodIdIndex(reader.readMethod()));
break;
case EncodedValueReader.ENCODED_ARRAY:
writeTypeAndArg(EncodedValueReader.ENCODED_ARRAY, 0);
transformArray(reader);
break;
case EncodedValueReader.ENCODED_ANNOTATION:
writeTypeAndArg(EncodedValueReader.ENCODED_ANNOTATION, 0);
transformAnnotation(reader);
break;
case EncodedValueReader.ENCODED_NULL:
reader.readNull();
writeTypeAndArg(EncodedValueReader.ENCODED_NULL, 0);
break;
case EncodedValueReader.ENCODED_BOOLEAN:
boolean value = reader.readBoolean();
writeTypeAndArg(EncodedValueReader.ENCODED_BOOLEAN, value ? 1 : 0);
break;
default:
throw new DexException("Unexpected type: " + Integer.toHexString(reader.peek()));
}
}
private void transformAnnotation(EncodedValueReader reader) {
int fieldCount = reader.readAnnotation();
Leb128.writeUnsignedLeb128(out, adjustTypeIdIndex(reader.getAnnotationType()));
Leb128.writeUnsignedLeb128(out, fieldCount);
for (int i = 0; i < fieldCount; i++) {
Leb128.writeUnsignedLeb128(out, adjustStringIndex(reader.readAnnotationName()));
transform(reader);
}
}
private void transformArray(EncodedValueReader reader) {
int size = reader.readArray();
Leb128.writeUnsignedLeb128(out, size);
for (int i = 0; i < size; i++) {
transform(reader);
}
}
private void writeTypeAndArg(int type, int arg) {
out.writeByte((arg << 5) | type);
}
}
}