ClassNode.java 13.6 KB
Newer Older
S
Skylot 已提交
1 2 3 4
package jadx.core.dex.nodes;

import jadx.core.Consts;
import jadx.core.codegen.CodeWriter;
S
Skylot 已提交
5
import jadx.core.dex.attributes.AType;
S
Skylot 已提交
6
import jadx.core.dex.attributes.annotations.Annotation;
S
Skylot 已提交
7 8 9
import jadx.core.dex.attributes.nodes.JadxErrorAttr;
import jadx.core.dex.attributes.nodes.LineAttrNode;
import jadx.core.dex.attributes.nodes.SourceFileAttr;
S
Skylot 已提交
10 11 12 13 14 15
import jadx.core.dex.info.AccessInfo;
import jadx.core.dex.info.AccessInfo.AFType;
import jadx.core.dex.info.ClassInfo;
import jadx.core.dex.info.FieldInfo;
import jadx.core.dex.info.MethodInfo;
import jadx.core.dex.instructions.args.ArgType;
1
13.beta2 已提交
16
import jadx.core.dex.instructions.args.LiteralArg;
17
import jadx.core.dex.instructions.args.PrimitiveType;
S
Skylot 已提交
18
import jadx.core.dex.nodes.parser.AnnotationsParser;
19 20
import jadx.core.dex.nodes.parser.FieldInitAttr;
import jadx.core.dex.nodes.parser.FieldInitAttr.InitType;
S
Skylot 已提交
21
import jadx.core.dex.nodes.parser.SignatureParser;
S
Skylot 已提交
22 23
import jadx.core.dex.nodes.parser.StaticValuesParser;
import jadx.core.utils.exceptions.DecodeException;
S
Skylot 已提交
24
import jadx.core.utils.exceptions.JadxRuntimeException;
S
Skylot 已提交
25 26 27

import java.util.ArrayList;
import java.util.Collections;
S
Skylot 已提交
28
import java.util.HashMap;
29
import java.util.HashSet;
S
Skylot 已提交
30
import java.util.LinkedHashMap;
S
Skylot 已提交
31 32
import java.util.List;
import java.util.Map;
33
import java.util.Set;
S
Skylot 已提交
34

S
Skylot 已提交
35
import org.jetbrains.annotations.Nullable;
36
import org.jetbrains.annotations.TestOnly;
S
Skylot 已提交
37 38 39
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

B
Bjoern Kerler 已提交
40 41 42 43
import com.android.dex.ClassData;
import com.android.dex.ClassData.Field;
import com.android.dex.ClassData.Method;
import com.android.dex.ClassDef;
44
import com.android.dx.rop.code.AccessFlags;
S
Skylot 已提交
45

46
public class ClassNode extends LineAttrNode implements ILoadable {
S
Skylot 已提交
47
	private static final Logger LOG = LoggerFactory.getLogger(ClassNode.class);
S
Skylot 已提交
48 49 50

	private final DexNode dex;
	private final ClassInfo clsInfo;
S
Skylot 已提交
51
	private final AccessInfo accessFlags;
S
Skylot 已提交
52 53
	private ArgType superClass;
	private List<ArgType> interfaces;
54
	private Map<ArgType, List<ArgType>> genericMap;
S
Skylot 已提交
55

S
Skylot 已提交
56 57 58
	private final List<MethodNode> methods;
	private final List<FieldNode> fields;
	private Map<Object, FieldNode> constFields = Collections.emptyMap();
S
Skylot 已提交
59 60
	private List<ClassNode> innerClasses = Collections.emptyList();

61
	// store decompiled code
S
Skylot 已提交
62
	private CodeWriter code;
63 64
	// store parent for inner classes or 'this' otherwise
	private ClassNode parentClass;
S
Skylot 已提交
65

66 67 68
	private ProcessState state = ProcessState.NOT_LOADED;
	private final Set<ClassNode> dependencies = new HashSet<ClassNode>();

S
Skylot 已提交
69 70 71
	// cache maps
	private Map<MethodInfo, MethodNode> mthInfoMap = Collections.emptyMap();

S
Skylot 已提交
72 73 74 75
	public ClassNode(DexNode dex, ClassDef cls) throws DecodeException {
		this.dex = dex;
		this.clsInfo = ClassInfo.fromDex(dex, cls.getTypeIndex());
		try {
S
Skylot 已提交
76 77 78
			if (cls.getSupertypeIndex() == DexNode.NO_INDEX) {
				this.superClass = null;
			} else {
S
Skylot 已提交
79
				this.superClass = dex.getType(cls.getSupertypeIndex());
S
Skylot 已提交
80
			}
S
Skylot 已提交
81
			this.interfaces = new ArrayList<ArgType>(cls.getInterfaces().length);
S
Skylot 已提交
82
			for (short interfaceIdx : cls.getInterfaces()) {
S
Skylot 已提交
83
				this.interfaces.add(dex.getType(interfaceIdx));
S
Skylot 已提交
84
			}
S
Skylot 已提交
85
			if (cls.getClassDataOffset() != 0) {
S
Skylot 已提交
86
				ClassData clsData = dex.readClassData(cls);
S
Skylot 已提交
87 88
				int mthsCount = clsData.getDirectMethods().length + clsData.getVirtualMethods().length;
				int fieldsCount = clsData.getStaticFields().length + clsData.getInstanceFields().length;
S
Skylot 已提交
89

S
Skylot 已提交
90 91
				methods = new ArrayList<MethodNode>(mthsCount);
				fields = new ArrayList<FieldNode>(fieldsCount);
S
Skylot 已提交
92

S
Skylot 已提交
93
				for (Method mth : clsData.getDirectMethods()) {
94
					methods.add(new MethodNode(this, mth, false));
S
Skylot 已提交
95 96
				}
				for (Method mth : clsData.getVirtualMethods()) {
97
					methods.add(new MethodNode(this, mth, true));
S
Skylot 已提交
98
				}
S
Skylot 已提交
99

S
Skylot 已提交
100
				for (Field f : clsData.getStaticFields()) {
S
Skylot 已提交
101
					fields.add(new FieldNode(this, f));
S
Skylot 已提交
102
				}
S
Skylot 已提交
103
				loadStaticValues(cls, fields);
S
Skylot 已提交
104
				for (Field f : clsData.getInstanceFields()) {
S
Skylot 已提交
105
					fields.add(new FieldNode(this, f));
S
Skylot 已提交
106 107 108 109
				}
			} else {
				methods = Collections.emptyList();
				fields = Collections.emptyList();
S
Skylot 已提交
110 111 112 113
			}

			loadAnnotations(cls);

114 115
			parseClassSignature();
			setFieldsTypesFromSignature();
S
Skylot 已提交
116

117
			int sfIdx = cls.getSourceFileIndex();
118
			if (sfIdx != DexNode.NO_INDEX) {
119
				String fileName = dex.getString(sfIdx);
120
				addSourceFilenameAttr(fileName);
121 122
			}

S
Skylot 已提交
123
			// restore original access flags from dalvik annotation if present
124
			int accFlagsValue;
S
Skylot 已提交
125
			Annotation a = getAnnotation(Consts.DALVIK_INNER_CLASS);
S
Skylot 已提交
126
			if (a != null) {
127
				accFlagsValue = (Integer) a.getValues().get("accessFlags");
S
Skylot 已提交
128
			} else {
129
				accFlagsValue = cls.getAccessFlags();
S
Skylot 已提交
130
			}
S
Skylot 已提交
131 132
			this.accessFlags = new AccessInfo(accFlagsValue, AFType.CLASS);

S
Skylot 已提交
133
			buildCache();
S
Skylot 已提交
134
		} catch (Exception e) {
S
Skylot 已提交
135
			throw new DecodeException("Error decode class: " + clsInfo, e);
S
Skylot 已提交
136 137 138
		}
	}

139 140 141 142 143 144 145 146 147 148 149
	// empty synthetic class
	public ClassNode(DexNode dex, ClassInfo clsInfo) {
		this.dex = dex;
		this.clsInfo = clsInfo;
		this.interfaces = Collections.emptyList();
		this.methods = Collections.emptyList();
		this.fields = Collections.emptyList();
		this.accessFlags = new AccessInfo(AccessFlags.ACC_PUBLIC | AccessFlags.ACC_SYNTHETIC, AFType.CLASS);
		this.parentClass = this;
	}

S
Skylot 已提交
150 151 152 153
	private void loadAnnotations(ClassDef cls) {
		int offset = cls.getAnnotationsOffset();
		if (offset != 0) {
			try {
S
Skylot 已提交
154
				new AnnotationsParser(this).parse(offset);
155
			} catch (Exception e) {
S
Skylot 已提交
156
				LOG.error("Error parsing annotations in {}", this, e);
S
Skylot 已提交
157 158 159 160 161 162 163
			}
		}
	}

	private void loadStaticValues(ClassDef cls, List<FieldNode> staticFields) throws DecodeException {
		for (FieldNode f : staticFields) {
			if (f.getAccessFlags().isFinal()) {
164
				f.addAttr(FieldInitAttr.NULL_VALUE);
S
Skylot 已提交
165 166 167
			}
		}
		int offset = cls.getStaticValuesOffset();
168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183
		if (offset == 0) {
			return;
		}
		StaticValuesParser parser = new StaticValuesParser(dex, dex.openSection(offset));
		int count = parser.processFields(staticFields);
		if (count == 0) {
			return;
		}
		constFields = new LinkedHashMap<Object, FieldNode>(count);
		for (FieldNode f : staticFields) {
			AccessInfo accFlags = f.getAccessFlags();
			if (accFlags.isStatic() && accFlags.isFinal()) {
				FieldInitAttr fv = f.get(AType.FIELD_INIT);
				if (fv != null && fv.getValue() != null && fv.getValueType() == InitType.CONST) {
					if (accFlags.isPublic()) {
						dex.getConstFields().put(fv.getValue(), f);
S
Skylot 已提交
184
					}
185
					constFields.put(fv.getValue(), f);
S
Skylot 已提交
186 187 188 189 190
				}
			}
		}
	}

191
	private void parseClassSignature() {
S
Skylot 已提交
192 193
		SignatureParser sp = SignatureParser.fromNode(this);
		if (sp == null) {
194
			return;
S
Skylot 已提交
195
		}
S
Skylot 已提交
196 197 198 199
		try {
			// parse class generic map
			genericMap = sp.consumeGenericMap();
			// parse super class signature
S
Skylot 已提交
200
			superClass = sp.consumeType();
S
Skylot 已提交
201 202 203 204
			// parse interfaces signatures
			for (int i = 0; i < interfaces.size(); i++) {
				ArgType type = sp.consumeType();
				if (type != null) {
S
Skylot 已提交
205
					interfaces.set(i, type);
S
Skylot 已提交
206 207
				} else {
					break;
208 209
				}
			}
S
Skylot 已提交
210
		} catch (JadxRuntimeException e) {
S
Skylot 已提交
211
			LOG.error("Class signature parse error: {}", this, e);
212 213 214 215 216
		}
	}

	private void setFieldsTypesFromSignature() {
		for (FieldNode field : fields) {
S
Skylot 已提交
217 218 219 220 221 222 223 224
			SignatureParser sp = SignatureParser.fromNode(field);
			if (sp != null) {
				try {
					ArgType gType = sp.consumeType();
					if (gType != null) {
						field.setType(gType);
					}
				} catch (JadxRuntimeException e) {
S
Skylot 已提交
225
					LOG.error("Field signature parse error: {}", field, e);
S
Skylot 已提交
226 227
				}
			}
228 229 230
		}
	}

231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251
	private void addSourceFilenameAttr(String fileName) {
		if (fileName == null) {
			return;
		}
		if (fileName.endsWith(".java")) {
			fileName = fileName.substring(0, fileName.length() - 5);
		}
		if (fileName.isEmpty()
				|| fileName.equals("SourceFile")
				|| fileName.equals("\"")) {
			return;
		}
		if (clsInfo != null) {
			String name = clsInfo.getShortName();
			if (fileName.equals(name)) {
				return;
			}
			if (fileName.contains("$")
					&& fileName.endsWith("$" + name)) {
				return;
			}
S
Skylot 已提交
252 253 254 255
			ClassInfo parentClass = clsInfo.getTopParentClass();
			if (parentClass != null && fileName.equals(parentClass.getShortName())) {
				return;
			}
256 257 258 259 260
		}
		this.addAttr(new SourceFileAttr(fileName));
		LOG.debug("Class '{}' compiled from '{}'", this, fileName);
	}

S
Skylot 已提交
261
	@Override
S
Skylot 已提交
262
	public void load() {
S
Skylot 已提交
263
		for (MethodNode mth : getMethods()) {
S
Skylot 已提交
264 265
			try {
				mth.load();
266
			} catch (Exception e) {
267
				LOG.error("Method load error: {}", mth, e);
S
Skylot 已提交
268
				mth.addAttr(new JadxErrorAttr(e));
S
Skylot 已提交
269
			}
S
Skylot 已提交
270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285
		}
		for (ClassNode innerCls : getInnerClasses()) {
			innerCls.load();
		}
	}

	@Override
	public void unload() {
		for (MethodNode mth : getMethods()) {
			mth.unload();
		}
		for (ClassNode innerCls : getInnerClasses()) {
			innerCls.unload();
		}
	}

S
Skylot 已提交
286 287 288 289 290 291 292
	private void buildCache() {
		mthInfoMap = new HashMap<MethodInfo, MethodNode>(methods.size());
		for (MethodNode mth : methods) {
			mthInfoMap.put(mth.getMethodInfo(), mth);
		}
	}

S
Skylot 已提交
293 294
	@Nullable
	public ArgType getSuperClass() {
S
Skylot 已提交
295 296 297
		return superClass;
	}

S
Skylot 已提交
298
	public List<ArgType> getInterfaces() {
S
Skylot 已提交
299 300 301
		return interfaces;
	}

302 303 304 305
	public Map<ArgType, List<ArgType>> getGenericMap() {
		return genericMap;
	}

S
Skylot 已提交
306 307 308 309 310 311 312 313
	public List<MethodNode> getMethods() {
		return methods;
	}

	public List<FieldNode> getFields() {
		return fields;
	}

314 315 316 317 318
	public FieldNode getConstField(Object obj) {
		return getConstField(obj, true);
	}

	public FieldNode getConstField(Object obj, boolean searchGlobal) {
319 320 321
		ClassNode cn = this;
		FieldNode field;
		do {
322
			field = cn.constFields.get(obj);
323 324
		}
		while (field == null
325
				&& cn.clsInfo.getParentClass() != null
326
				&& (cn = dex.resolveClass(cn.clsInfo.getParentClass())) != null);
327

328 329 330
		if (field == null && searchGlobal) {
			field = dex.getConstFields().get(obj);
		}
S
Skylot 已提交
331
		if (obj instanceof Integer) {
332 333
			String str = dex.root().getResourcesNames().get(obj);
			if (str != null) {
S
Skylot 已提交
334 335 336 337 338 339 340
				ResRefField resField = new ResRefField(dex, str.replace('/', '.'));
				if (field == null) {
					return resField;
				}
				if (!field.getName().equals(resField.getName())) {
					field = resField;
				}
341 342
			}
		}
343 344 345
		return field;
	}

1
13.beta2 已提交
346
	public FieldNode getConstFieldByLiteralArg(LiteralArg arg) {
347 348 349 350
		PrimitiveType type = arg.getType().getPrimitiveType();
		if (type == null) {
			return null;
		}
1
13.beta2 已提交
351
		long literal = arg.getLiteral();
352 353 354 355
		switch (type) {
			case BOOLEAN:
				return getConstField(literal == 1, false);
			case CHAR:
356
				return getConstField((char) literal, Math.abs(literal) > 10);
357
			case BYTE:
358
				return getConstField((byte) literal, Math.abs(literal) > 10);
359
			case SHORT:
360
				return getConstField((short) literal, Math.abs(literal) > 100);
361
			case INT:
362
				return getConstField((int) literal, Math.abs(literal) > 100);
363
			case LONG:
364
				return getConstField(literal, Math.abs(literal) > 1000);
365
			case FLOAT:
366 367
				float f = Float.intBitsToFloat((int) literal);
				return getConstField(f, f != 0.0);
368
			case DOUBLE:
369 370
				double d = Double.longBitsToDouble(literal);
				return getConstField(d, d != 0);
1
13.beta2 已提交
371 372 373 374
		}
		return null;
	}

S
Skylot 已提交
375
	public FieldNode searchFieldById(int id) {
376 377 378 379
		return searchField(FieldInfo.fromDex(dex, id));
	}

	public FieldNode searchField(FieldInfo field) {
S
Skylot 已提交
380
		for (FieldNode f : fields) {
381
			if (f.getFieldInfo().equals(field)) {
S
Skylot 已提交
382
				return f;
S
Skylot 已提交
383
			}
S
Skylot 已提交
384 385 386 387
		}
		return null;
	}

388
	@TestOnly
S
Skylot 已提交
389
	public FieldNode searchFieldByName(String name) {
S
Skylot 已提交
390
		for (FieldNode f : fields) {
S
Skylot 已提交
391
			if (f.getName().equals(name)) {
S
Skylot 已提交
392
				return f;
S
Skylot 已提交
393
			}
S
Skylot 已提交
394 395 396 397
		}
		return null;
	}

S
Skylot 已提交
398
	public MethodNode searchMethod(MethodInfo mth) {
S
Skylot 已提交
399
		return mthInfoMap.get(mth);
S
Skylot 已提交
400 401 402
	}

	public MethodNode searchMethodByName(String shortId) {
S
Skylot 已提交
403
		for (MethodNode m : methods) {
S
Skylot 已提交
404
			if (m.getMethodInfo().getShortId().equals(shortId)) {
S
Skylot 已提交
405
				return m;
S
Skylot 已提交
406
			}
S
Skylot 已提交
407 408 409 410 411
		}
		return null;
	}

	public MethodNode searchMethodById(int id) {
S
Skylot 已提交
412
		return searchMethodByName(MethodInfo.fromDex(dex, id).getShortId());
S
Skylot 已提交
413 414
	}

415 416 417 418 419 420 421 422 423 424 425 426 427
	public ClassNode getParentClass() {
		if (parentClass == null) {
			if (clsInfo.isInner()) {
				ClassNode parent = dex().resolveClass(clsInfo.getParentClass());
				parent = parent == null ? this : parent;
				parentClass = parent;
			} else {
				parentClass = this;
			}
		}
		return parentClass;
	}

428 429 430 431 432
	public ClassNode getTopParentClass() {
		ClassNode parent = getParentClass();
		return parent == this ? this : parent.getParentClass();
	}

S
Skylot 已提交
433 434 435 436 437
	public List<ClassNode> getInnerClasses() {
		return innerClasses;
	}

	public void addInnerClass(ClassNode cls) {
S
Skylot 已提交
438
		if (innerClasses.isEmpty()) {
S
Skylot 已提交
439
			innerClasses = new ArrayList<ClassNode>(3);
S
Skylot 已提交
440
		}
S
Skylot 已提交
441 442 443
		innerClasses.add(cls);
	}

444
	public boolean isEnum() {
S
Skylot 已提交
445 446 447
		return getAccessFlags().isEnum()
				&& getSuperClass() != null
				&& getSuperClass().getObject().equals(ArgType.ENUM.getObject());
448 449
	}

S
Skylot 已提交
450
	public boolean isAnonymous() {
S
Skylot 已提交
451
		return clsInfo.isInner()
S
Skylot 已提交
452
				&& clsInfo.getAlias().getShortName().startsWith(Consts.ANONYMOUS_CLASS_PREFIX)
S
Skylot 已提交
453
				&& getDefaultConstructor() != null;
S
Skylot 已提交
454 455
	}

456 457 458 459 460 461
	@Nullable
	public MethodNode getClassInitMth() {
		return searchMethodByName("<clinit>()V");
	}

	@Nullable
S
Skylot 已提交
462 463
	public MethodNode getDefaultConstructor() {
		for (MethodNode mth : methods) {
464
			if (mth.isDefaultConstructor()) {
S
Skylot 已提交
465
				return mth;
S
Skylot 已提交
466 467
			}
		}
S
Skylot 已提交
468
		return null;
S
Skylot 已提交
469 470 471 472 473 474 475 476 477 478
	}

	public AccessInfo getAccessFlags() {
		return accessFlags;
	}

	public DexNode dex() {
		return dex;
	}

S
Skylot 已提交
479 480 481 482 483 484 485
	public String getRawName() {
		return clsInfo.getRawName();
	}

	/**
	 * Internal class info (don't use in code generation and external api).
	 */
S
Skylot 已提交
486 487 488 489
	public ClassInfo getClassInfo() {
		return clsInfo;
	}

S
Skylot 已提交
490 491 492 493 494 495 496
	/**
	 * Class info for external usage (code generation and external api).
	 */
	public ClassInfo getAlias() {
		return clsInfo.getAlias();
	}

S
Skylot 已提交
497
	public String getShortName() {
S
Skylot 已提交
498
		return clsInfo.getAlias().getShortName();
S
Skylot 已提交
499 500 501
	}

	public String getFullName() {
S
Skylot 已提交
502
		return clsInfo.getAlias().getFullName();
S
Skylot 已提交
503 504 505
	}

	public String getPackage() {
S
Skylot 已提交
506
		return clsInfo.getAlias().getPackage();
507 508
	}

S
Skylot 已提交
509 510 511 512 513 514 515 516
	public void setCode(CodeWriter code) {
		this.code = code;
	}

	public CodeWriter getCode() {
		return code;
	}

517 518 519 520 521 522 523 524 525 526 527 528
	public ProcessState getState() {
		return state;
	}

	public void setState(ProcessState state) {
		this.state = state;
	}

	public Set<ClassNode> getDependencies() {
		return dependencies;
	}

S
Skylot 已提交
529 530
	@Override
	public String toString() {
S
Skylot 已提交
531
		return clsInfo.getFullName();
S
Skylot 已提交
532 533
	}
}