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

3
import java.io.StringWriter;
4 5 6
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
7
import java.util.LinkedHashSet;
8 9
import java.util.List;
import java.util.Map;
10
import java.util.Set;
11

12 13 14 15
import org.jetbrains.annotations.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

16 17 18 19 20 21
import com.android.dex.ClassData;
import com.android.dex.ClassData.Field;
import com.android.dex.ClassData.Method;
import com.android.dex.ClassDef;
import com.android.dex.Dex;

22
import jadx.api.ICodeCache;
S
Skylot 已提交
23
import jadx.api.ICodeInfo;
S
Skylot 已提交
24
import jadx.core.Consts;
S
Skylot 已提交
25
import jadx.core.ProcessClass;
26
import jadx.core.dex.attributes.AFlag;
S
Skylot 已提交
27
import jadx.core.dex.attributes.annotations.Annotation;
S
Skylot 已提交
28 29
import jadx.core.dex.attributes.nodes.LineAttrNode;
import jadx.core.dex.attributes.nodes.SourceFileAttr;
S
Skylot 已提交
30 31 32 33 34 35
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 已提交
36
import jadx.core.dex.instructions.args.LiteralArg;
S
Skylot 已提交
37
import jadx.core.dex.nodes.parser.AnnotationsParser;
38
import jadx.core.dex.nodes.parser.FieldInitAttr;
S
Skylot 已提交
39
import jadx.core.dex.nodes.parser.SignatureParser;
S
Skylot 已提交
40
import jadx.core.dex.nodes.parser.StaticValuesParser;
41
import jadx.core.utils.SmaliUtils;
S
Skylot 已提交
42
import jadx.core.utils.exceptions.DecodeException;
S
Skylot 已提交
43
import jadx.core.utils.exceptions.JadxRuntimeException;
S
Skylot 已提交
44

S
Skylot 已提交
45
import static jadx.core.dex.nodes.ProcessState.LOADED;
46
import static jadx.core.dex.nodes.ProcessState.NOT_LOADED;
47

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

	private final DexNode dex;
52
	private final int clsDefOffset;
S
Skylot 已提交
53
	private final ClassInfo clsInfo;
54
	private AccessInfo accessFlags;
S
Skylot 已提交
55 56
	private ArgType superClass;
	private List<ArgType> interfaces;
57
	private List<GenericTypeParameter> generics = Collections.emptyList();
S
Skylot 已提交
58

S
Skylot 已提交
59 60
	private final List<MethodNode> methods;
	private final List<FieldNode> fields;
61
	private List<ClassNode> innerClasses = Collections.emptyList();
S
Skylot 已提交
62

63 64
	private List<ClassNode> inlinedClasses = Collections.emptyList();

65 66
	// store smali
	private String smali;
67 68
	// store parent for inner classes or 'this' otherwise
	private ClassNode parentClass;
S
Skylot 已提交
69

S
Skylot 已提交
70
	private volatile ProcessState state = ProcessState.NOT_LOADED;
S
Skylot 已提交
71
	private List<ClassNode> dependencies = Collections.emptyList();
72

S
Skylot 已提交
73 74 75
	// cache maps
	private Map<MethodInfo, MethodNode> mthInfoMap = Collections.emptyMap();

76
	public ClassNode(DexNode dex, ClassDef cls) {
S
Skylot 已提交
77
		this.dex = dex;
78
		this.clsDefOffset = cls.getOffset();
S
Skylot 已提交
79 80
		this.clsInfo = ClassInfo.fromDex(dex, cls.getTypeIndex());
		try {
S
Skylot 已提交
81 82
			if (cls.getSupertypeIndex() == DexNode.NO_INDEX) {
				this.superClass = null;
83 84 85 86
				// only java.lang.Object don't have super class
				if (!clsInfo.getType().getObject().equals(Consts.CLASS_OBJECT)) {
					throw new JadxRuntimeException("No super class in " + clsInfo.getType());
				}
S
Skylot 已提交
87
			} else {
S
Skylot 已提交
88
				this.superClass = dex.getType(cls.getSupertypeIndex());
S
Skylot 已提交
89
			}
S
Skylot 已提交
90
			this.interfaces = new ArrayList<>(cls.getInterfaces().length);
S
Skylot 已提交
91
			for (short interfaceIdx : cls.getInterfaces()) {
D
Donlon 已提交
92
				this.interfaces.add(dex.getType(interfaceIdx));
S
Skylot 已提交
93
			}
S
Skylot 已提交
94
			if (cls.getClassDataOffset() != 0) {
S
Skylot 已提交
95
				ClassData clsData = dex.readClassData(cls);
S
Skylot 已提交
96 97
				int mthsCount = clsData.getDirectMethods().length + clsData.getVirtualMethods().length;
				int fieldsCount = clsData.getStaticFields().length + clsData.getInstanceFields().length;
S
Skylot 已提交
98

S
Skylot 已提交
99 100
				methods = new ArrayList<>(mthsCount);
				fields = new ArrayList<>(fieldsCount);
S
Skylot 已提交
101

S
Skylot 已提交
102
				for (Method mth : clsData.getDirectMethods()) {
103
					methods.add(new MethodNode(this, mth, false));
S
Skylot 已提交
104 105
				}
				for (Method mth : clsData.getVirtualMethods()) {
106
					methods.add(new MethodNode(this, mth, true));
S
Skylot 已提交
107
				}
S
Skylot 已提交
108

S
Skylot 已提交
109
				for (Field f : clsData.getStaticFields()) {
S
Skylot 已提交
110
					fields.add(new FieldNode(this, f));
S
Skylot 已提交
111
				}
S
Skylot 已提交
112
				loadStaticValues(cls, fields);
S
Skylot 已提交
113
				for (Field f : clsData.getInstanceFields()) {
S
Skylot 已提交
114
					fields.add(new FieldNode(this, f));
S
Skylot 已提交
115 116 117 118
				}
			} else {
				methods = Collections.emptyList();
				fields = Collections.emptyList();
S
Skylot 已提交
119 120 121
			}

			loadAnnotations(cls);
122
			initAccessFlags(cls);
123 124
			parseClassSignature();
			setFieldsTypesFromSignature();
125
			methods.forEach(MethodNode::initMethodTypes);
S
Skylot 已提交
126

127
			int sfIdx = cls.getSourceFileIndex();
128
			if (sfIdx != DexNode.NO_INDEX) {
129
				String fileName = dex.getString(sfIdx);
130
				addSourceFilenameAttr(fileName);
131 132
			}

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

139 140 141 142 143 144 145 146 147 148 149 150 151 152
	/**
	 * Restore original access flags from Dalvik annotation if present
	 */
	private void initAccessFlags(ClassDef cls) {
		int accFlagsValue;
		Annotation a = getAnnotation(Consts.DALVIK_INNER_CLASS);
		if (a != null) {
			accFlagsValue = (Integer) a.getValues().get("accessFlags");
		} else {
			accFlagsValue = cls.getAccessFlags();
		}
		this.accessFlags = new AccessInfo(accFlagsValue, AFType.CLASS);
	}

153
	// empty synthetic class
154
	public ClassNode(DexNode dex, String name, int accessFlags) {
155
		this.dex = dex;
156
		this.clsDefOffset = 0;
157 158 159 160 161
		this.clsInfo = ClassInfo.fromName(dex.root(), name);
		this.interfaces = new ArrayList<>();
		this.methods = new ArrayList<>();
		this.fields = new ArrayList<>();
		this.accessFlags = new AccessInfo(accessFlags, AFType.CLASS);
162
		this.parentClass = this;
163 164

		dex.addClassNode(this);
165 166
	}

S
Skylot 已提交
167 168 169 170
	private void loadAnnotations(ClassDef cls) {
		int offset = cls.getAnnotationsOffset();
		if (offset != 0) {
			try {
S
Skylot 已提交
171
				new AnnotationsParser(this).parse(offset);
172
			} catch (Exception e) {
S
Skylot 已提交
173
				LOG.error("Error parsing annotations in {}", this, e);
S
Skylot 已提交
174 175 176 177 178 179 180
			}
		}
	}

	private void loadStaticValues(ClassDef cls, List<FieldNode> staticFields) throws DecodeException {
		for (FieldNode f : staticFields) {
			if (f.getAccessFlags().isFinal()) {
181
				// incorrect initialization will be removed if assign found in constructor
182
				f.addAttr(FieldInitAttr.NULL_VALUE);
S
Skylot 已提交
183 184 185
			}
		}
		int offset = cls.getStaticValuesOffset();
186 187 188
		if (offset == 0) {
			return;
		}
189 190 191 192 193 194
		Dex.Section section = dex.openSection(offset);
		StaticValuesParser parser = new StaticValuesParser(dex, section);
		parser.processFields(staticFields);

		// process const fields
		root().getConstValues().processConstFields(this, staticFields);
S
Skylot 已提交
195 196
	}

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

	private void setFieldsTypesFromSignature() {
		for (FieldNode field : fields) {
223 224 225
			try {
				SignatureParser sp = SignatureParser.fromNode(field);
				if (sp != null) {
S
Skylot 已提交
226 227 228 229
					ArgType gType = sp.consumeType();
					if (gType != null) {
						field.setType(gType);
					}
S
Skylot 已提交
230
				}
231 232
			} catch (Exception e) {
				LOG.error("Field signature parse error: {}.{}", this.getFullName(), field.getName(), e);
S
Skylot 已提交
233
			}
234 235 236
		}
	}

237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254
	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("$")
255
					&& fileName.endsWith('$' + name)) {
256 257
				return;
			}
S
Skylot 已提交
258 259
			ClassInfo parentCls = clsInfo.getTopParentClass();
			if (parentCls != null && fileName.equals(parentCls.getShortName())) {
S
Skylot 已提交
260 261
				return;
			}
262 263 264 265
		}
		this.addAttr(new SourceFileAttr(fileName));
	}

266 267 268 269 270 271 272
	public void ensureProcessed() {
		ClassNode topClass = getTopParentClass();
		ProcessState topState = topClass.getState();
		if (!topState.isProcessed()) {
			throw new JadxRuntimeException("Expected class to be processed at this point,"
					+ " class: " + topClass + ", state: " + topState);
		}
S
Skylot 已提交
273 274
	}

275 276 277 278 279 280 281 282 283 284 285 286 287
	public ICodeInfo decompile() {
		return decompile(true);
	}

	public ICodeInfo getCode() {
		return decompile(true);
	}

	public ICodeInfo reloadCode() {
		return decompile(false);
	}

	private synchronized ICodeInfo decompile(boolean searchInCache) {
288 289 290
		ICodeCache codeCache = root().getCodeCache();
		ClassNode topParentClass = getTopParentClass();
		String clsRawName = topParentClass.getRawName();
291 292
		if (searchInCache) {
			ICodeInfo code = codeCache.get(clsRawName);
293
			if (code != null && code != ICodeInfo.EMPTY) {
294 295
				return code;
			}
S
Skylot 已提交
296
		}
297 298
		ICodeInfo codeInfo = ProcessClass.generateCode(topParentClass);
		codeCache.add(clsRawName, codeInfo);
S
Skylot 已提交
299 300 301
		return codeInfo;
	}

S
Skylot 已提交
302
	@Override
S
Skylot 已提交
303
	public void load() {
S
Skylot 已提交
304
		for (MethodNode mth : getMethods()) {
S
Skylot 已提交
305 306
			try {
				mth.load();
307
			} catch (Exception e) {
308
				mth.addError("Method load error", e);
S
Skylot 已提交
309
			}
S
Skylot 已提交
310 311 312 313
		}
		for (ClassNode innerCls : getInnerClasses()) {
			innerCls.load();
		}
S
Skylot 已提交
314
		setState(LOADED);
S
Skylot 已提交
315 316 317 318
	}

	@Override
	public void unload() {
319 320 321 322
		methods.forEach(MethodNode::unload);
		innerClasses.forEach(ClassNode::unload);
		fields.forEach(FieldNode::unloadAttributes);
		unloadAttributes();
323
		setState(NOT_LOADED);
S
Skylot 已提交
324 325
	}

S
Skylot 已提交
326
	private void buildCache() {
S
Skylot 已提交
327
		mthInfoMap = new HashMap<>(methods.size());
S
Skylot 已提交
328 329 330 331 332
		for (MethodNode mth : methods) {
			mthInfoMap.put(mth.getMethodInfo(), mth);
		}
	}

S
Skylot 已提交
333 334
	@Nullable
	public ArgType getSuperClass() {
S
Skylot 已提交
335 336 337
		return superClass;
	}

S
Skylot 已提交
338
	public List<ArgType> getInterfaces() {
S
Skylot 已提交
339 340 341
		return interfaces;
	}

342
	public List<GenericTypeParameter> getGenericTypeParameters() {
343
		return generics;
344 345
	}

S
Skylot 已提交
346 347 348 349 350 351 352 353
	public List<MethodNode> getMethods() {
		return methods;
	}

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

354 355 356 357
	public FieldNode getConstField(Object obj) {
		return getConstField(obj, true);
	}

358
	@Nullable
359
	public FieldNode getConstField(Object obj, boolean searchGlobal) {
360
		return root().getConstValues().getConstField(this, obj, searchGlobal);
361 362
	}

363
	@Nullable
1
13.beta2 已提交
364
	public FieldNode getConstFieldByLiteralArg(LiteralArg arg) {
365
		return root().getConstValues().getConstFieldByLiteralArg(this, arg);
1
13.beta2 已提交
366 367
	}

S
Skylot 已提交
368
	public FieldNode searchFieldById(int id) {
369 370 371 372
		return searchField(FieldInfo.fromDex(dex, id));
	}

	public FieldNode searchField(FieldInfo field) {
S
Skylot 已提交
373
		for (FieldNode f : fields) {
374
			if (f.getFieldInfo().equals(field)) {
S
Skylot 已提交
375
				return f;
S
Skylot 已提交
376
			}
S
Skylot 已提交
377 378 379 380
		}
		return null;
	}

381 382 383 384 385 386 387 388 389
	public FieldNode searchFieldByNameAndType(FieldInfo field) {
		for (FieldNode f : fields) {
			if (f.getFieldInfo().equalsNameAndType(field)) {
				return f;
			}
		}
		return null;
	}

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

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

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

412 413
	/**
	 * Return first method by original short name
414 415
	 * Note: methods are not unique by name (class can have several methods with same name but different
	 * signature)
416 417 418 419 420 421 422 423 424 425 426
	 */
	@Nullable
	public MethodNode searchMethodByShortName(String name) {
		for (MethodNode m : methods) {
			if (m.getMethodInfo().getName().equals(name)) {
				return m;
			}
		}
		return null;
	}

S
Skylot 已提交
427
	public MethodNode searchMethodById(int id) {
428
		return searchMethodByShortId(MethodInfo.fromDex(dex, id).getShortId());
S
Skylot 已提交
429 430
	}

431 432 433 434
	public ClassNode getParentClass() {
		if (parentClass == null) {
			if (clsInfo.isInner()) {
				ClassNode parent = dex().resolveClass(clsInfo.getParentClass());
435
				parentClass = parent == null ? this : parent;
436 437 438 439 440 441 442
			} else {
				parentClass = this;
			}
		}
		return parentClass;
	}

443 444
	public ClassNode getTopParentClass() {
		ClassNode parent = getParentClass();
445
		return parent == this ? this : parent.getTopParentClass();
446 447
	}

448 449 450 451 452 453 454 455 456 457 458
	public boolean hasNotGeneratedParent() {
		if (contains(AFlag.DONT_GENERATE)) {
			return true;
		}
		ClassNode parent = getParentClass();
		if (parent == this) {
			return false;
		}
		return parent.hasNotGeneratedParent();
	}

S
Skylot 已提交
459 460 461 462
	public List<ClassNode> getInnerClasses() {
		return innerClasses;
	}

463
	/**
464
	 * Get all inner and inlined classes recursively
465
	 *
466
	 * @param resultClassesSet all identified inner and inlined classes are added to this set
467
	 */
468 469 470 471 472 473 474 475 476 477
	public void getInnerAndInlinedClassesRecursive(Set<ClassNode> resultClassesSet) {
		for (ClassNode innerCls : innerClasses) {
			if (resultClassesSet.add(innerCls)) {
				innerCls.getInnerAndInlinedClassesRecursive(resultClassesSet);
			}
		}
		for (ClassNode inlinedCls : inlinedClasses) {
			if (resultClassesSet.add(inlinedCls)) {
				inlinedCls.getInnerAndInlinedClassesRecursive(resultClassesSet);
			}
478 479 480
		}
	}

S
Skylot 已提交
481
	public void addInnerClass(ClassNode cls) {
482 483 484
		if (innerClasses.isEmpty()) {
			innerClasses = new ArrayList<>(5);
		}
S
Skylot 已提交
485
		innerClasses.add(cls);
486
		cls.parentClass = this;
S
Skylot 已提交
487 488
	}

489 490 491 492 493 494 495
	public void addInlinedClass(ClassNode cls) {
		if (inlinedClasses.isEmpty()) {
			inlinedClasses = new ArrayList<>(5);
		}
		inlinedClasses.add(cls);
	}

496
	public boolean isEnum() {
S
Skylot 已提交
497 498 499
		return getAccessFlags().isEnum()
				&& getSuperClass() != null
				&& getSuperClass().getObject().equals(ArgType.ENUM.getObject());
500 501
	}

S
Skylot 已提交
502
	public boolean isAnonymous() {
503
		return contains(AFlag.ANONYMOUS_CLASS);
504 505
	}

506 507
	@Nullable
	public MethodNode getClassInitMth() {
508
		return searchMethodByShortId("<clinit>()V");
509 510 511
	}

	@Nullable
S
Skylot 已提交
512 513
	public MethodNode getDefaultConstructor() {
		for (MethodNode mth : methods) {
514
			if (mth.isDefaultConstructor()) {
S
Skylot 已提交
515
				return mth;
S
Skylot 已提交
516 517
			}
		}
S
Skylot 已提交
518
		return null;
S
Skylot 已提交
519 520
	}

521
	@Override
S
Skylot 已提交
522 523 524 525
	public AccessInfo getAccessFlags() {
		return accessFlags;
	}

526 527 528 529 530
	@Override
	public void setAccessFlags(AccessInfo accessFlags) {
		this.accessFlags = accessFlags;
	}

531
	@Override
S
Skylot 已提交
532 533 534 535
	public DexNode dex() {
		return dex;
	}

536 537 538 539 540
	@Override
	public RootNode root() {
		return dex.root();
	}

541 542 543 544 545
	@Override
	public String typeName() {
		return "class";
	}

S
Skylot 已提交
546 547 548 549 550 551 552
	public String getRawName() {
		return clsInfo.getRawName();
	}

	/**
	 * Internal class info (don't use in code generation and external api).
	 */
S
Skylot 已提交
553 554 555 556 557
	public ClassInfo getClassInfo() {
		return clsInfo;
	}

	public String getShortName() {
558
		return clsInfo.getAliasShortName();
S
Skylot 已提交
559 560 561
	}

	public String getFullName() {
562
		return clsInfo.getAliasFullName();
S
Skylot 已提交
563 564 565
	}

	public String getPackage() {
566
		return clsInfo.getAliasPkg();
567 568
	}

569
	public String getSmali() {
570
		if (smali == null) {
571 572 573
			StringWriter stringWriter = new StringWriter(4096);
			getSmali(this, stringWriter);
			stringWriter.append(System.lineSeparator());
574 575 576
			Set<ClassNode> allInlinedClasses = new LinkedHashSet<>();
			getInnerAndInlinedClassesRecursive(allInlinedClasses);
			for (ClassNode innerClass : allInlinedClasses) {
577 578 579 580
				getSmali(innerClass, stringWriter);
				stringWriter.append(System.lineSeparator());
			}
			smali = stringWriter.toString();
581
		}
582 583 584
		return smali;
	}

585 586 587 588 589 590
	protected static boolean getSmali(ClassNode classNode, StringWriter stringWriter) {
		stringWriter.append(String.format("###### Class %s (%s)", classNode.getFullName(), classNode.getRawName()));
		stringWriter.append(System.lineSeparator());
		return SmaliUtils.getSmaliCode(classNode.dex, classNode.clsDefOffset, stringWriter);
	}

591 592 593 594 595 596 597 598
	public ProcessState getState() {
		return state;
	}

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

S
Skylot 已提交
599
	public List<ClassNode> getDependencies() {
600 601 602
		return dependencies;
	}

S
Skylot 已提交
603 604 605 606
	public void setDependencies(List<ClassNode> dependencies) {
		this.dependencies = dependencies;
	}

607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623
	@Override
	public int hashCode() {
		return clsInfo.hashCode();
	}

	@Override
	public boolean equals(Object o) {
		if (this == o) {
			return true;
		}
		if (o instanceof ClassNode) {
			ClassNode other = (ClassNode) o;
			return clsInfo.equals(other.clsInfo);
		}
		return false;
	}

S
Skylot 已提交
624 625
	@Override
	public String toString() {
S
Skylot 已提交
626
		return clsInfo.getFullName();
S
Skylot 已提交
627
	}
628

S
Skylot 已提交
629
}