Skip to content

Commit 5a59568

Browse files
committed
[tinker] Fix: ClassDef order validation failure caused by DexPatchGenerator.
1 parent bcd19fb commit 5a59568

File tree

3 files changed

+109
-8
lines changed

3 files changed

+109
-8
lines changed

third-party/aosp-dexutils/src/main/java/com/tencent/tinker/android/dex/Dex.java

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,27 @@ public final class Dex {
5252
static final short[] EMPTY_SHORT_ARRAY = new short[0];
5353
private static final int CHECKSUM_OFFSET = 8;
5454
private static final int SIGNATURE_OFFSET = CHECKSUM_OFFSET + SizeOf.CHECKSUM;
55+
56+
public static final int ACC_PUBLIC = 0x1;
57+
public static final int ACC_PRIVATE = 0x2;
58+
public static final int ACC_PROTECTED = 0x4;
59+
public static final int ACC_STATIC = 0x8;
60+
public static final int ACC_FINAL = 0x10;
61+
public static final int ACC_SYNCHRONIZED = 0x20;
62+
public static final int ACC_VOLATILE = 0x40;
63+
public static final int ACC_BRIDGE = 0x40;
64+
public static final int ACC_TRANSIENT = 0x80;
65+
public static final int ACC_VARARGS = 0x80;
66+
public static final int ACC_NATIVE = 0x100;
67+
public static final int ACC_INTERFACE = 0x200;
68+
public static final int ACC_ABSTRACT = 0x400;
69+
public static final int ACC_STRICT = 0x800;
70+
public static final int ACC_SYNTHETIC = 0x1000;
71+
public static final int ACC_ANNOTATION = 0x2000;
72+
public static final int ACC_ENUM = 0x4000;
73+
public static final int ACC_CONSTRUCTOR = 0x10000;
74+
public static final int ACC_DECLARED_SYNCHRONIZED = 0x20000;
75+
5576
private final TableOfContents tableOfContents = new TableOfContents();
5677
private final StringTable strings = new StringTable();
5778
private final TypeIndexToDescriptorIndexTable typeIds = new TypeIndexToDescriptorIndexTable();
@@ -595,15 +616,11 @@ public short[] interfaceTypeIndicesFromClassDefIndex(int classDefIndex) {
595616
}
596617

597618
public short[] interfaceTypeIndicesFromClassDef(ClassDef classDef) {
598-
int position = classDef.off;
599-
position += SizeOf.UINT; // type
600-
position += SizeOf.UINT; // accessFlags
601-
position += SizeOf.UINT; // superType
602-
int interfacesOffset = data.getInt(position);
619+
int interfacesOffset = classDef.interfacesOffset;
603620
if (interfacesOffset == 0) {
604621
return EMPTY_SHORT_ARRAY;
605622
}
606-
position = interfacesOffset;
623+
int position = interfacesOffset;
607624
int size = data.getInt(position);
608625
if (size <= 0) {
609626
throw new AssertionError("Unexpected interfaces list size: " + size);

tinker-commons/src/main/java/com/tencent/tinker/commons/dexpatcher/algorithms/patch/ClassDefSectionPatchAlgorithm.java

Lines changed: 77 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,16 +20,26 @@
2020
import com.tencent.tinker.android.dex.Dex;
2121
import com.tencent.tinker.android.dex.TableOfContents;
2222
import com.tencent.tinker.android.dex.io.DexDataBuffer;
23+
import com.tencent.tinker.android.utils.SparseIntArray;
2324
import com.tencent.tinker.commons.dexpatcher.struct.DexPatchFile;
2425
import com.tencent.tinker.commons.dexpatcher.util.AbstractIndexMap;
2526
import com.tencent.tinker.commons.dexpatcher.util.SparseIndexMap;
2627

28+
import java.util.ArrayDeque;
29+
import java.util.ArrayList;
30+
import java.util.HashMap;
31+
import java.util.List;
32+
import java.util.Map;
33+
import java.util.Queue;
34+
2735
/**
2836
* Created by tangyinsheng on 2016/7/4.
2937
*/
3038
public class ClassDefSectionPatchAlgorithm extends DexSectionPatchAlgorithm<ClassDef> {
39+
private Dex patchedDex = null;
3140
private TableOfContents.Section patchedClassDefTocSec = null;
3241
private Dex.Section patchedClassDefSec = null;
42+
private List<ClassDef> patchedClassDefs = null;
3343

3444
public ClassDefSectionPatchAlgorithm(
3545
DexPatchFile patchFile,
@@ -40,8 +50,10 @@ public ClassDefSectionPatchAlgorithm(
4050
super(patchFile, oldDex, oldToPatchedIndexMap);
4151

4252
if (patchedDex != null) {
53+
this.patchedDex = patchedDex;
4354
this.patchedClassDefTocSec = patchedDex.getTableOfContents().classDefs;
4455
this.patchedClassDefSec = patchedDex.openSection(this.patchedClassDefTocSec);
56+
this.patchedClassDefs = new ArrayList<>(512);
4557
}
4658
}
4759

@@ -69,6 +81,70 @@ protected ClassDef adjustItem(AbstractIndexMap indexMap, ClassDef item) {
6981
@Override
7082
protected int writePatchedItem(ClassDef patchedItem) {
7183
++this.patchedClassDefTocSec.size;
72-
return this.patchedClassDefSec.writeClassDef(patchedItem);
84+
this.patchedClassDefs.add(patchedItem);
85+
// Since no other sections concern about offset of ClassDef item, we can simply return 0 here.
86+
return 0;
87+
}
88+
89+
@Override
90+
protected void onPatchAlgorithmEnd() {
91+
this.patchedClassDefs = topologicalSort(this.patchedClassDefs);
92+
for (ClassDef patchedItem : this.patchedClassDefs) {
93+
this.patchedClassDefSec.writeClassDef(patchedItem);
94+
}
95+
}
96+
97+
private List<ClassDef> topologicalSort(List<ClassDef> elements) {
98+
final Map<Integer, ClassDef> typeIdToClassDefMap = new HashMap<>(elements.size() + 8);
99+
final Map<Integer, List<Integer>> typeGraph = new HashMap<>(elements.size() + 8);
100+
final SparseIntArray inDegrees = new SparseIntArray(elements.size() + 8);
101+
for (ClassDef elem : elements) {
102+
typeIdToClassDefMap.put(elem.typeIndex, elem);
103+
typeGraph.put(elem.typeIndex, new ArrayList<>(8));
104+
inDegrees.put(elem.typeIndex, 0);
105+
}
106+
107+
for (ClassDef elem : elements) {
108+
if (typeIdToClassDefMap.containsKey(elem.supertypeIndex)) {
109+
typeGraph.get(elem.supertypeIndex).add(elem.typeIndex);
110+
inDegrees.put(elem.typeIndex, inDegrees.get(elem.typeIndex) + 1);
111+
}
112+
for (int implTypeId : patchedDex.interfaceTypeIndicesFromClassDef(elem)) {
113+
if (typeIdToClassDefMap.containsKey(implTypeId)) {
114+
typeGraph.get(implTypeId).add(elem.typeIndex);
115+
inDegrees.put(elem.typeIndex, inDegrees.get(elem.typeIndex) + 1);
116+
}
117+
}
118+
}
119+
120+
final Queue<Integer> typeIdWithZeroInDegrees = new ArrayDeque<>(64);
121+
for (int i = 0; i < inDegrees.size(); ++i) {
122+
final int typeId = inDegrees.keyAt(i);
123+
final int inDegree = inDegrees.valueAt(i);
124+
if (inDegree == 0) {
125+
typeIdWithZeroInDegrees.offer(typeId);
126+
}
127+
}
128+
129+
final List<ClassDef> result = new ArrayList<>();
130+
while (!typeIdWithZeroInDegrees.isEmpty()) {
131+
final int currentTypeId = typeIdWithZeroInDegrees.poll();
132+
result.add(typeIdToClassDefMap.get(currentTypeId));
133+
134+
for (int nextTypeId : typeGraph.get(currentTypeId)) {
135+
final int newInDegree = inDegrees.get(nextTypeId) - 1;
136+
inDegrees.put(nextTypeId, newInDegree);
137+
if (newInDegree == 0) {
138+
typeIdWithZeroInDegrees.offer(nextTypeId);
139+
}
140+
}
141+
}
142+
143+
// Check if type graph contains loop.
144+
if (result.size() != elements.size()) {
145+
throw new IllegalStateException("Illegal dex format, there's at least one loop in class inheritance graph.");
146+
}
147+
148+
return result;
73149
}
74150
}

tinker-commons/src/main/java/com/tencent/tinker/commons/dexpatcher/algorithms/patch/DexSectionPatchAlgorithm.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,10 +94,16 @@ protected void markDeletedIndexOrOffset(SparseIndexMap sparseIndexMap, int delet
9494
* Output patched item. This method should be overrided by subclass
9595
* so that patched item can be written to right place.
9696
* <p/>
97-
* Returns the offset where {@code patchedItem} is written. (<b>Must be valid.</b>)
97+
* Returns the offset where {@code patchedItem} is written.
98+
* (<b>Must be valid if the patched section is depended by other sections.</b>)
9899
*/
99100
protected abstract int writePatchedItem(T patchedItem);
100101

102+
/**
103+
* Called when patch algorithm finish generating patched section.
104+
*/
105+
protected void onPatchAlgorithmEnd() {}
106+
101107
private int[] readDeltaIndiciesOrOffsets(int count) {
102108
int[] result = new int[count];
103109
int lastVal = 0;
@@ -234,5 +240,7 @@ private void doFullPatch(
234240
)
235241
);
236242
}
243+
244+
onPatchAlgorithmEnd();
237245
}
238246
}

0 commit comments

Comments
 (0)