xref: /aosp_15_r20/external/leakcanary2/shark-graph/src/test/java/shark/HprofDeobfuscatorTest.kt (revision d9e8da70d8c9df9a41d7848ae506fb3115cae6e6)

<lambda>null1 package shark
2 
3 import org.assertj.core.api.Assertions.assertThat
4 import org.junit.Before
5 import org.junit.Rule
6 import org.junit.Test
7 import org.junit.rules.TemporaryFolder
8 import shark.ValueHolder.IntHolder
9 import java.io.File
10 
11 class HprofDeobfuscatorTest {
12 
13   @get:Rule
14   var testFolder = TemporaryFolder()
15   private lateinit var hprofFile: File
16 
17   @Before
18   fun setUp() {
19     hprofFile = testFolder.newFile("temp.hprof")
20   }
21 
22   @Test
23   fun deobfuscateHprofClassName() {
24     val proguardMapping = ProguardMapping().create {
25       clazz("Foo" to "a")
26     }
27 
28     hprofFile.dump {
29       "a" clazz {}
30     }
31 
32     val deobfuscator = HprofDeobfuscator()
33     val deobfuscatedFile = deobfuscator.deobfuscate(proguardMapping, hprofFile)
34 
35     deobfuscatedFile.readHprof { graph ->
36       val fooClass = graph.findClassByName("Foo")
37       assertThat(fooClass).isNotNull
38     }
39   }
40 
41   @Test
42   fun deobfuscateHprofStaticFieldName() {
43     val proguardMapping = ProguardMapping().create {
44       clazz("Foo" to "a") {
45         field { "staticField" to "b" }
46       }
47     }
48 
49     hprofFile.dump {
50       "a" clazz {
51         staticField["b"] = IntHolder(42)
52       }
53     }
54 
55     val deobfuscator = HprofDeobfuscator()
56     val deobfuscatedFile = deobfuscator.deobfuscate(proguardMapping, hprofFile)
57 
58     deobfuscatedFile.readHprof { graph ->
59       val fooClass = graph.findClassByName("Foo")!!
60 
61       assertThat(
62         fooClass.readStaticFields()
63           .map { it.name }
64           .toList()
65       ).contains("staticField")
66     }
67   }
68 
69   @Test
70   fun deobfuscateHprofMemberFieldName() {
71     val proguardMapping = ProguardMapping().create {
72       clazz("Foo" to "a") {
73         field { "instanceField" to "b" }
74       }
75     }
76 
77     hprofFile.dump {
78       val classId = clazz(
79         className = "a",
80         fields = listOf("b" to IntHolder::class)
81       )
82       instance(classId, listOf(IntHolder(0)))
83     }
84 
85     val deobfuscator = HprofDeobfuscator()
86     val deobfuscatedFile = deobfuscator.deobfuscate(proguardMapping, hprofFile)
87 
88     deobfuscatedFile.readHprof { graph ->
89       val instance = graph.instances.find { heapInstance ->
90         heapInstance.instanceClassName == "Foo"
91       }!!
92 
93       assertThat(
94         instance.readFields()
95           .map { it.name }
96           .toList()
97       ).contains("instanceField")
98     }
99   }
100 
101   @Test
102   fun deobfuscateHprofClassNameUsedAsFieldName() {
103     val proguardMapping = ProguardMapping().create {
104       clazz("Foo" to "a") {
105         field { "instanceField" to "a" }
106       }
107     }
108 
109     hprofFile.dump {
110       val classNameRecord = stringRecord("a")
111 
112       val classId = clazz(
113         classNameRecord = classNameRecord,
114         fields = listOf(classNameRecord.id to IntHolder::class)
115       )
116       instance(classId, listOf(IntHolder(0)))
117     }
118 
119     val deobfuscator = HprofDeobfuscator()
120     val deobfuscatedFile = deobfuscator.deobfuscate(proguardMapping, hprofFile)
121 
122     deobfuscatedFile.readHprof { graph ->
123       val instance = graph.instances.find { heapInstance ->
124         heapInstance.instanceClassName == "Foo"
125       }!!
126 
127       assertThat(
128         instance.readFields()
129           .map { it.name }
130           .toList()
131       ).contains("instanceField")
132     }
133   }
134 
135   @Test
136   fun deobfuscateHprofClassNameUsedAsStaticFieldName() {
137     val proguardMapping = ProguardMapping().create {
138       clazz("Foo" to "a") {
139         field { "staticField" to "a" }
140       }
141     }
142 
143     hprofFile.dump {
144       val classNameRecord = stringRecord("a")
145 
146       clazz(
147         classNameRecord = classNameRecord,
148         staticFields = listOf(classNameRecord.id to IntHolder(42))
149       )
150     }
151 
152     val deobfuscator = HprofDeobfuscator()
153     val deobfuscatedFile = deobfuscator.deobfuscate(proguardMapping, hprofFile)
154 
155     deobfuscatedFile.readHprof { graph ->
156       val fooClass = graph.findClassByName("Foo")!!
157 
158       assertThat(
159         fooClass.readStaticFields()
160           .map { it.name }
161           .toList()
162       ).contains("staticField")
163     }
164   }
165 
166   @Test
167   fun deobfuscateHprofTwoFieldsWithSameName() {
168     val proguardMapping = ProguardMapping().create {
169       clazz("Foo" to "a") {
170         field { "instanceField1" to "c" }
171       }
172       clazz("Bar" to "b") {
173         field { "instanceField2" to "c" }
174       }
175     }
176 
177     hprofFile.dump {
178       val fooClassNameRecord = stringRecord("a")
179       val barClassNameRecord = stringRecord("b")
180       val fieldNameRecord = stringRecord("c")
181 
182       val fooClassId = clazz(
183         classNameRecord = fooClassNameRecord,
184         fields = listOf(fieldNameRecord.id to IntHolder::class)
185       )
186       instance(fooClassId, listOf(IntHolder(0)))
187 
188       val barClassId = clazz(
189         classNameRecord = barClassNameRecord,
190         fields = listOf(fieldNameRecord.id to IntHolder::class)
191       )
192       instance(barClassId, listOf(IntHolder(0)))
193     }
194 
195     val deobfuscator = HprofDeobfuscator()
196     val deobfuscatedFile = deobfuscator.deobfuscate(proguardMapping, hprofFile)
197 
198     deobfuscatedFile.readHprof { graph ->
199       val fooInstance = graph.instances.find { heapInstance ->
200         heapInstance.instanceClassName == "Foo"
201       }!!
202 
203       assertThat(
204         fooInstance.readFields()
205           .map { it.name }
206           .toList()
207       ).contains("instanceField1")
208 
209       val barInstance = graph.instances.find { heapInstance ->
210         heapInstance.instanceClassName == "Bar"
211       }!!
212 
213       assertThat(
214         barInstance.readFields()
215           .map { it.name }
216           .toList()
217       ).contains("instanceField2")
218     }
219   }
220 
221   private fun File.readHprof(block: (HeapGraph) -> Unit) {
222     Hprof.open(this)
223       .use { hprof ->
224         block(HprofHeapGraph.indexHprof(hprof))
225       }
226   }
227 }