本文环境
java version "1.7.0_75"
dx version 1.11
baksmali 2.1.0

知识预备

系统注解

系统注解用来表示java反射相关的信息,是由编译器生成的。
存在于 .dex 文件annotation部分,只在运行时系统可见。
源码在 /libcore/dalvik/src/main/java/dalvik/annotation/ 目录下.

AnnotationDefault

注解类的默认注解类,如果指定了默认值,此注解类就会出现。

EnclosingClass

出现在内部类中,指定该 内部类/匿名内部类 所在的最近的外部类,此注解类必须和InnerClass注解类一同出现,不能和EnclosingMethod一同出现。

EnclosingMethod

出现在内部类中,指定该内部类所在的最近的外部函数,此注解类必须和InnerClass注解类一同出现,不能和EnclosingClass一同出现。

InnerClass

出现在内部类中,提供内部类的名字(不包括包名,匿名内部类值为null)和访问权限(同类的访问权限)。
该注解类需和EnclosingMethod或EnclosingClass之一一同出现。

MemberClasses

出现在具有内部类的类中,提供直接内部类(不包含嵌套)的类名列表。

Signature

出现由更复杂的类型定义的类、字段或者方法中,dex文件不定义signature的格式,此注解类只是指定源语言能够实现其语义的相应的signature。
因此,signature并不能被解析或这验证,只能被高一级的API或者工具(如调试器)接管。
signature以字符串数组的形式存在,使用的时候拼接。只有编译工具才能将一个完整的signature分成几个字符串。

Throws

以数组形式指定某个方法抛出的异常类型。

内部类

java 在编译的时候会为每个类生成一个class文件,内部类的格式为 [外部类]$[内部类].class.

java 代码

1
2
3
4
5
6
7
8
9
10
class HeyInnerclass
{
class Inner1{
class Inner1_1{}
}
class Inner2{}
private void func(){
class InnerFun{}
}
}

smali 代码

以下仅为部分相关代码。

HeyInnerclass

1
2
3
4
5
6
7
8
9
10
11
12
13
# annotations //注解类MemberClasses
.annotation system Ldalvik/annotation/MemberClasses;
value = {
LHeyInnerclass$Inner2;,
LHeyInnerclass$Inner1;
}
.end annotation
.method private func()V
.registers 1
.prologue
.line 18
return-void
.end method

HeyInnerclass 中有 HeyInnerclass$Inner2 和 HeyInnerclass$Inner1 两个类!
func 方法中并没有任何实现还是占用了一个寄存器,这个寄存器表示自身(this)的引用。

Inner1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# annotations //注解类 EnclosingClass
.annotation system Ldalvik/annotation/EnclosingClass;
value = LHeyInnerclass;
.end annotation
//注解类 InnerClass
.annotation system Ldalvik/annotation/InnerClass;
accessFlags = 0x0
name = "Inner1"
.end annotation
//注解类 MemberClasses
.annotation system Ldalvik/annotation/MemberClasses;
value = {
LHeyInnerclass$Inner1$Inner1_1;
}
.end annotation
# instance fields //声明字段this$0
.field final synthetic this$0:LHeyInnerclass;
# direct methods
.method constructor <init>(LHeyInnerclass;)V
.registers 2
.prologue
.line 3 //初始化字段 this$0
iput-object p1, p0, LHeyInnerclass$Inner1;->this$0:LHeyInnerclass;
invoke-direct {p0}, Ljava/lang/Object;-><init>()V
.line 5
return-void
.end method

Inner1 中有一个内部类 HeyInnerclass$Inner1$Inner1_1,所在的外部类是 HeyInnerclass,名字是 Inner1,访问权限 0x0.
this$0 是 HeyInnerclass 类型的,是内部类的保留的对所在的外部类的引用,this表示父类的引用,0表示引用的层数。
synthetic表示这是合成的,由编译器生成的,不是写出来的。

Inner2 与 Inner1 除了没有字节的内部类外其余基本一致,代码就不贴了。

Inner1_1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# annotations #注解类
.annotation system Ldalvik/annotation/EnclosingClass;
value = LHeyInnerclass$Inner1;
.end annotation
.annotation system Ldalvik/annotation/InnerClass; #注解类
accessFlags = 0x0
name = "Inner1_1"
.end annotation
# instance fields
.field final synthetic this$1:LHeyInnerclass$Inner1;
# direct methods
.method constructor <init>(LHeyInnerclass$Inner1;)V
.registers 2
.prologue
.line 5
iput-object p1, p0, LHeyInnerclass$Inner1$Inner1_1;->this$1:LHeyInnerclass$Inner1;
invoke-direct {p0}, Ljava/lang/Object;-><init>()V
return-void
.end method

Inner1_1 名字是 Inner1_1,访问权限为0x0,所在的外部类是HeyInnerclass$Inner1,
对外部类的的引用是 this$1,类型是 HeyInnerclass$Inner1,1表示引用层数深了一层。

InnerFun

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# annotations #注解类
.annotation system Ldalvik/annotation/EnclosingMethod;
value = LHeyInnerclass;->func()V
.end annotation
.annotation system Ldalvik/annotation/InnerClass; #注解类
accessFlags = 0x0
name = "InnerFun"
.end annotation
# instance fields #引用字段
.field final synthetic this$0:LHeyInnerclass;
# direct methods
.method constructor <init>(LHeyInnerclass;)V
.registers 2
.prologue
.line 17
iput-object p1, p0, LHeyInnerclass$1InnerFun;->this$0:LHeyInnerclass;
invoke-direct {p0}, Ljava/lang/Object;-><init>()V
return-void
.end method

InnerFun的名字是InnerFun,访问权限是0x0,所在的方法是 LHeyInnerclass;->func()V .
对外部类的引用是 this$0,类型是 HeyInnerclass,引用层数为0.