Skip to content

Commit 6173416

Browse files
committed
[DEX] Simplify access flags and standardize program abstraction
1 parent d696426 commit 6173416

32 files changed

Lines changed: 634 additions & 225 deletions

src/main/java/com/reandroid/dex/common/AccessFlag.java

Lines changed: 150 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,17 @@
1616
package com.reandroid.dex.common;
1717

1818
import com.reandroid.dex.smali.SmaliReader;
19+
import com.reandroid.utils.StringsUtil;
1920
import com.reandroid.utils.collection.ArrayCollection;
2021
import com.reandroid.utils.collection.ArrayIterator;
22+
import com.reandroid.utils.collection.EmptyIterator;
2123

24+
import java.io.IOException;
2225
import java.lang.annotation.ElementType;
2326
import java.util.HashMap;
2427
import java.util.Iterator;
2528
import java.util.List;
29+
import java.util.NoSuchElementException;
2630
import java.util.function.Predicate;
2731

2832
public class AccessFlag extends Modifier {
@@ -44,66 +48,63 @@ public class AccessFlag extends Modifier {
4448
public static final AccessFlag SYNTHETIC;
4549
public static final AccessFlag ANNOTATION;
4650
public static final AccessFlag ENUM;
51+
4752
// for flags of dalvik.annotation.MethodParameters
4853
public static final AccessFlag MANDATED;
54+
4955
public static final AccessFlag CONSTRUCTOR;
5056
public static final AccessFlag DECLARED_SYNCHRONIZED;
5157

5258
private static final AccessFlag[] VALUES;
59+
private static final AccessFlag[] METHOD_VALUES;
60+
private static final int MASK;
5361

5462
private static final HashMap<String, AccessFlag> accessFlagsByName;
5563

5664
static {
5765

58-
PUBLIC = new AccessFlag(0x1, "public", true, true, true);
59-
PRIVATE = new AccessFlag(0x2, "private", true, true, true);
60-
PROTECTED = new AccessFlag(0x4, "protected", true, true, true);
61-
STATIC = new AccessFlag(0x8, "static", true, true, true);
62-
FINAL = new AccessFlag(0x10, "final", true, true, true);
63-
SYNCHRONIZED = new AccessFlag(0x20, "synchronized", false, true, false);
64-
VOLATILE = new AccessFlag(0x40, "volatile", false, false, true);
65-
BRIDGE = new AccessFlag(0x40, "bridge", false, true, false);
66-
TRANSIENT = new AccessFlag(0x80, "transient", false, false, true);
67-
VARARGS = new AccessFlag(0x80, "varargs", false, true, false);
68-
NATIVE = new AccessFlag(0x100, "native", false, true, false);
69-
INTERFACE = new AccessFlag(0x200, "interface", true, false, false);
70-
ABSTRACT = new AccessFlag(0x400, "abstract", true, true, false);
71-
STRICTFP = new AccessFlag(0x800, "strictfp", false, true, false);
72-
SYNTHETIC = new AccessFlag(0x1000, "synthetic", true, true, true);
73-
ANNOTATION = new AccessFlag(0x2000, "annotation", true, false, false);
74-
ENUM = new AccessFlag(0x4000, "enum", true, false, true);
75-
MANDATED = new AccessFlag(0x8000, "mandated", false, false, false);
76-
CONSTRUCTOR = new AccessFlag(0x10000, "constructor", false, true, false);
77-
DECLARED_SYNCHRONIZED = new AccessFlag(0x20000, "declared-synchronized", false, true, false);
78-
79-
VALUES = new AccessFlag[]{
80-
PUBLIC,
81-
PRIVATE,
82-
PROTECTED,
83-
STATIC,
84-
FINAL,
85-
SYNCHRONIZED,
86-
VOLATILE,
87-
BRIDGE,
88-
TRANSIENT,
89-
VARARGS,
90-
NATIVE,
91-
INTERFACE,
92-
ABSTRACT,
93-
STRICTFP,
94-
SYNTHETIC,
95-
ANNOTATION,
96-
ENUM,
97-
MANDATED,
98-
CONSTRUCTOR,
99-
DECLARED_SYNCHRONIZED
100-
};
101-
102-
accessFlagsByName = new HashMap<>();
103-
for (AccessFlag accessFlag : VALUES) {
104-
accessFlagsByName.put(accessFlag.getName(), accessFlag);
105-
}
66+
AccessFlag[] values = new AccessFlag[18];
67+
VALUES = values;
68+
69+
PUBLIC = values[0] = new AccessFlag(0x1, "public", true, true, true);
70+
PRIVATE = values[1] = new AccessFlag(0x1 << 1, "private", true, true, true);
71+
PROTECTED = values[2] = new AccessFlag(0x1 << 2, "protected", true, true, true);
72+
STATIC = values[3] = new AccessFlag(0x1 << 3, "static", true, true, true);
73+
FINAL = values[4] = new AccessFlag(0x1 << 4, "final", true, true, true);
74+
SYNCHRONIZED = values[5] = new AccessFlag(0x1 << 5, "synchronized", false, true, false);
75+
76+
VOLATILE = values[6] = new AccessFlag(0x1 << 6, "volatile", false, false, true);
77+
BRIDGE = new AccessFlag(0x1 << 6, "bridge", false, true, false);
78+
79+
TRANSIENT = values[7] = new AccessFlag(0x1 << 7, "transient", false, false, true);
80+
VARARGS = new AccessFlag(0x1 << 7, "varargs", false, true, false);
10681

82+
NATIVE = values[8] = new AccessFlag(0x1 << 8, "native", false, true, false);
83+
INTERFACE = values[9] = new AccessFlag(0x1 << 9, "interface", true, false, false);
84+
ABSTRACT = values[10] = new AccessFlag(0x1 << 10, "abstract", true, true, false);
85+
STRICTFP = values[11] = new AccessFlag(0x1 << 11, "strictfp", false, true, false);
86+
SYNTHETIC = values[12] = new AccessFlag(0x1 << 12, "synthetic", true, true, true);
87+
ANNOTATION = values[13] = new AccessFlag(0x1 << 13, "annotation", true, false, false);
88+
ENUM = values[14] = new AccessFlag(0x1 << 14, "enum", true, false, true);
89+
MANDATED = values[15] = new AccessFlag(0x1 << 15, "mandated", false, false, false);
90+
CONSTRUCTOR = values[16] = new AccessFlag(0x1 << 16, "constructor", false, true, false);
91+
DECLARED_SYNCHRONIZED = values[17] = new AccessFlag(0x1 << 17, "declared-synchronized", false, true, false);
92+
93+
MASK = (0x1 << values.length) - 1;
94+
95+
AccessFlag[] methodValues = values.clone();
96+
methodValues[6] = BRIDGE;
97+
methodValues[7] = VARARGS;
98+
METHOD_VALUES = methodValues;
99+
100+
HashMap<String, AccessFlag> map = new HashMap<>(20);
101+
accessFlagsByName = map;
102+
103+
for (AccessFlag accessFlag : values) {
104+
map.put(accessFlag.getName(), accessFlag);
105+
}
106+
map.put(BRIDGE.getName(), BRIDGE);
107+
map.put(VARARGS.getName(), VARARGS);
107108
}
108109

109110
private final boolean validForClass;
@@ -118,65 +119,94 @@ private AccessFlag(int value, String name, boolean validForClass, boolean validF
118119
this.validForField = validForField;
119120
}
120121

121-
@Override
122-
public boolean isSet(int accessFlags) {
123-
return (getValue() & accessFlags) != 0;
124-
}
125-
public boolean isSet(ElementType elementType, int accessFlags) {
126-
if (elementType == ElementType.TYPE) {
127-
return isSetForClass(accessFlags);
128-
}
129-
if (elementType == ElementType.FIELD) {
130-
return isSetForField(accessFlags);
131-
}
132-
if (elementType == ElementType.METHOD) {
133-
return isSetForMethod(accessFlags);
134-
}
135-
return false;
122+
public boolean isValidForClass() {
123+
return validForClass;
136124
}
137-
private boolean isSetForField(int value) {
138-
return validForField && (getValue() & value) != 0;
125+
public boolean isValidForField() {
126+
return validForField;
139127
}
140-
private boolean isSetForMethod(int value) {
141-
return validForMethod && (getValue() & value) != 0;
128+
public boolean isValidForMethod() {
129+
return validForMethod;
142130
}
143-
private boolean isSetForClass(int value) {
144-
return validForClass && (getValue() & value) != 0;
131+
132+
@Override
133+
public boolean isSet(int accessFlags) {
134+
return (getValue() & accessFlags) != 0;
145135
}
146136

147137
public static Iterator<AccessFlag> valuesOf(ElementType elementType, int value) {
148-
if (elementType == ElementType.TYPE) {
149-
return valuesOfClass(value);
138+
return valuesOf(elementType == ElementType.METHOD, value);
139+
}
140+
public static Iterator<AccessFlag> valuesOf(int value) {
141+
value = value & MASK;
142+
if (value == 0) {
143+
return EmptyIterator.of();
150144
}
151-
if (elementType == ElementType.FIELD) {
152-
return valuesOfField(value);
145+
return new FlagsIterator(VALUES, value);
146+
}
147+
public static Iterator<AccessFlag> valuesOf(boolean method, int value) {
148+
value = value & MASK;
149+
if (value == 0) {
150+
return EmptyIterator.of();
153151
}
154-
if (elementType == ElementType.METHOD) {
155-
return valuesOfMethod(value);
152+
AccessFlag[] values;
153+
if (method) {
154+
values = METHOD_VALUES;
155+
} else {
156+
values = VALUES;
156157
}
157-
return valuesOf(value);
158-
}
159-
public static Iterator<AccessFlag> valuesOfClass(int value) {
160-
return getValues(accessFlag -> accessFlag.isSetForClass(value));
161-
}
162-
public static Iterator<AccessFlag> valuesOfMethod(int value) {
163-
return getValues(accessFlag -> accessFlag.isSetForMethod(value));
164-
}
165-
public static Iterator<AccessFlag> valuesOfField(int value) {
166-
return getValues(accessFlag -> accessFlag.isSetForField(value));
167-
}
168-
public static Iterator<AccessFlag> valuesOf(int value) {
169-
return getValues(accessFlag -> accessFlag.isSet(value));
158+
return new FlagsIterator(values, value);
170159
}
171160
public static AccessFlag valueOf(String name) {
172161
return accessFlagsByName.get(name);
173162
}
174163
public static Iterator<AccessFlag> getValues() {
175-
return getValues(null);
164+
return new ArrayIterator<>(VALUES);
176165
}
177166
public static Iterator<AccessFlag> getValues(Predicate<AccessFlag> filter) {
178167
return new ArrayIterator<>(VALUES, filter);
179168
}
169+
public static String toString(int flags) {
170+
return toString(false, flags);
171+
}
172+
public static String toString(boolean method, int flags) {
173+
flags = flags & MASK;
174+
if (flags == 0) {
175+
return StringsUtil.EMPTY;
176+
}
177+
StringBuilder builder = new StringBuilder();
178+
try {
179+
append(method, flags, builder);
180+
} catch (IOException e) {
181+
builder.append(" # Unexpected AccessFlags.append: ");
182+
builder.append(e.getMessage());
183+
}
184+
return builder.toString();
185+
}
186+
public static void append(int flags, Appendable appendable) throws IOException {
187+
append(false, flags, appendable);
188+
}
189+
public static void append(boolean method, int flags, Appendable appendable) throws IOException {
190+
flags = flags & MASK;
191+
if (flags == 0) {
192+
return;
193+
}
194+
AccessFlag[] values;
195+
if (method) {
196+
values = METHOD_VALUES;
197+
} else {
198+
values = VALUES;
199+
}
200+
int i = 0;
201+
while (flags != 0) {
202+
if ((flags & 0x1) != 0) {
203+
appendable.append(values[i].getName());
204+
appendable.append(' ');
205+
}
206+
flags = flags >>> 1;
207+
i ++;
208+
}
209+
}
180210
public static AccessFlag[] parse(SmaliReader reader) {
181211
List<AccessFlag> accessFlags = null;
182212
AccessFlag flag;
@@ -220,4 +250,35 @@ public static int combineAccessFlags(Iterator<? extends Modifier> iterator) {
220250
}
221251
return result;
222252
}
253+
static class FlagsIterator implements Iterator<AccessFlag> {
254+
255+
private final AccessFlag[] values;
256+
private int flags;
257+
private int index;
258+
259+
public FlagsIterator(AccessFlag[] values, int flags) {
260+
this.values = values;
261+
this.flags = flags;
262+
}
263+
@Override
264+
public boolean hasNext() {
265+
return flags != 0;
266+
}
267+
@Override
268+
public AccessFlag next() {
269+
int flags = this.flags;
270+
if (flags == 0) {
271+
throw new NoSuchElementException();
272+
}
273+
int index = this.index;
274+
while ((flags & 0x1) == 0) {
275+
flags = flags >>> 1;
276+
index ++;
277+
}
278+
AccessFlag accessFlag = values[index];
279+
this.flags = flags >>> 1;
280+
this.index = index + 1;
281+
return accessFlag;
282+
}
283+
}
223284
}

src/main/java/com/reandroid/dex/common/HiddenApiFlag.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,9 @@ public static HiddenApiFlag domainOf(int value) {
151151
return null;
152152
}
153153

154+
public static int parseValues(SmaliReader reader) {
155+
return combineHiddenApiFlag(parse(reader));
156+
}
154157
public static HiddenApiFlag[] parse(SmaliReader reader) {
155158
Object container = null;
156159
HiddenApiFlag flag;

0 commit comments

Comments
 (0)