1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.ahat;
18 
19 import com.android.ahat.proguard.ProguardMap;
20 import java.io.IOException;
21 import java.io.StringReader;
22 import java.text.ParseException;
23 import org.junit.Test;
24 import static org.junit.Assert.assertEquals;
25 
26 public class ProguardMapTest {
27   private static final String TEST_MAP =
28       "# compiler: richard\n"
29     + "# compiler_version: 3.0-dev\n"
30     + "# min_api: 10000\n"
31     + "# compiler_hash: b7e25308967a577aa1f05a4b5a745c26\n"
32     + "class.that.is.Empty -> a:\n"
33     + "class.that.is.Empty$subclass -> b:\n"
34     + "class.with.only.Fields -> c:\n"
35     + "    int prim_type_field -> a\n"
36     + "    int[] prim_array_type_field -> b\n"
37     + "    class.that.is.Empty class_type_field -> c\n"
38     + "    class.that.is.Empty[] array_type_field -> d\n"
39     + "    int longObfuscatedNameField -> abc\n"
40     + "class.with.Methods -> d:\n"
41     + "    int some_field -> a\n"
42     + "    12:23:void <clinit>() -> <clinit>\n"
43     + "    42:43:void boringMethod() -> m\n"
44     + "    45:48:void methodWithPrimArgs(int,float) -> m\n"
45     + "    49:50:void methodWithPrimArrArgs(int[],float) -> m\n"
46     + "    52:55:void methodWithClearObjArg(class.not.in.Map) -> m\n"
47     + "    57:58:void methodWithClearObjArrArg(class.not.in.Map[]) -> m\n"
48     + "    59:61:void methodWithObfObjArg(class.with.only.Fields) -> m\n"
49     + "    64:66:class.with.only.Fields methodWithObfRes() -> n\n"
50     + "    80:80:void lineObfuscatedMethod():8:8 -> o\n"
51     + "    100:105:void lineObfuscatedMethod():50 -> o\n"
52     + "    90:94:void lineObfuscatedMethod2():9 -> p\n"
53     ;
54 
55   @Test
proguardMap()56   public void proguardMap() throws IOException, ParseException {
57     ProguardMap map = new ProguardMap();
58 
59     // An empty proguard map should not deobfuscate anything.
60     assertEquals("foo.bar.Sludge", map.getClassName("foo.bar.Sludge"));
61     assertEquals("fooBarSludge", map.getClassName("fooBarSludge"));
62     assertEquals("myfield", map.getFieldName("foo.bar.Sludge", "myfield"));
63     assertEquals("myfield", map.getFieldName("fooBarSludge", "myfield"));
64     ProguardMap.Frame frame = map.getFrame(
65         "foo.bar.Sludge", "mymethod", "(Lfoo/bar/Sludge;)V", "SourceFile.java", 123);
66     assertEquals("mymethod", frame.method);
67     assertEquals("(Lfoo/bar/Sludge;)V", frame.signature);
68     assertEquals("SourceFile.java", frame.filename);
69     assertEquals(123, frame.line);
70 
71     // Read in the proguard map.
72     map.readFromReader(new StringReader(TEST_MAP));
73 
74     // It should still not deobfuscate things that aren't in the map
75     assertEquals("foo.bar.Sludge", map.getClassName("foo.bar.Sludge"));
76     assertEquals("fooBarSludge", map.getClassName("fooBarSludge"));
77     assertEquals("myfield", map.getFieldName("foo.bar.Sludge", "myfield"));
78     assertEquals("myfield", map.getFieldName("fooBarSludge", "myfield"));
79     frame = map.getFrame("foo.bar.Sludge", "mymethod", "(Lfoo/bar/Sludge;)V",
80         "SourceFile.java", 123);
81     assertEquals("mymethod", frame.method);
82     assertEquals("(Lfoo/bar/Sludge;)V", frame.signature);
83     assertEquals("SourceFile.java", frame.filename);
84     assertEquals(123, frame.line);
85 
86     // Test deobfuscation of class names
87     assertEquals("class.that.is.Empty", map.getClassName("a"));
88     assertEquals("class.that.is.Empty$subclass", map.getClassName("b"));
89     assertEquals("class.with.only.Fields", map.getClassName("c"));
90     assertEquals("class.with.Methods", map.getClassName("d"));
91 
92     // Test deobfuscation of array classes.
93     assertEquals("class.with.Methods[]", map.getClassName("d[]"));
94     assertEquals("class.with.Methods[][]", map.getClassName("d[][]"));
95 
96     // Test deobfuscation of methods
97     assertEquals("prim_type_field", map.getFieldName("class.with.only.Fields", "a"));
98     assertEquals("prim_array_type_field", map.getFieldName("class.with.only.Fields", "b"));
99     assertEquals("class_type_field", map.getFieldName("class.with.only.Fields", "c"));
100     assertEquals("array_type_field", map.getFieldName("class.with.only.Fields", "d"));
101     assertEquals("longObfuscatedNameField", map.getFieldName("class.with.only.Fields", "abc"));
102     assertEquals("some_field", map.getFieldName("class.with.Methods", "a"));
103 
104     // Test deobfuscation of frames
105     frame = map.getFrame("class.with.Methods", "<clinit>", "()V", "SourceFile.java", 13);
106     assertEquals("<clinit>", frame.method);
107     assertEquals("()V", frame.signature);
108     assertEquals("Methods.java", frame.filename);
109     assertEquals(13, frame.line);
110 
111     frame = map.getFrame("class.with.Methods", "m", "()V", "SourceFile.java", 42);
112     assertEquals("boringMethod", frame.method);
113     assertEquals("()V", frame.signature);
114     assertEquals("Methods.java", frame.filename);
115     assertEquals(42, frame.line);
116 
117     frame = map.getFrame("class.with.Methods", "m", "(IF)V", "SourceFile.java", 45);
118     assertEquals("methodWithPrimArgs", frame.method);
119     assertEquals("(IF)V", frame.signature);
120     assertEquals("Methods.java", frame.filename);
121     assertEquals(45, frame.line);
122 
123     frame = map.getFrame("class.with.Methods", "m", "([IF)V", "SourceFile.java", 49);
124     assertEquals("methodWithPrimArrArgs", frame.method);
125     assertEquals("([IF)V", frame.signature);
126     assertEquals("Methods.java", frame.filename);
127     assertEquals(49, frame.line);
128 
129     frame = map.getFrame("class.with.Methods", "m", "(Lclass/not/in/Map;)V",
130         "SourceFile.java", 52);
131     assertEquals("methodWithClearObjArg", frame.method);
132     assertEquals("(Lclass/not/in/Map;)V", frame.signature);
133     assertEquals("Methods.java", frame.filename);
134     assertEquals(52, frame.line);
135 
136     frame = map.getFrame("class.with.Methods", "m", "([Lclass/not/in/Map;)V",
137         "SourceFile.java", 57);
138     assertEquals("methodWithClearObjArrArg", frame.method);
139     assertEquals("([Lclass/not/in/Map;)V", frame.signature);
140     assertEquals("Methods.java", frame.filename);
141     assertEquals(57, frame.line);
142 
143     frame = map.getFrame("class.with.Methods", "m", "(Lc;)V", "SourceFile.java", 59);
144     assertEquals("methodWithObfObjArg", frame.method);
145     assertEquals("(Lclass/with/only/Fields;)V", frame.signature);
146     assertEquals("Methods.java", frame.filename);
147     assertEquals(59, frame.line);
148 
149     frame = map.getFrame("class.with.Methods", "n", "()Lc;", "SourceFile.java", 64);
150     assertEquals("methodWithObfRes", frame.method);
151     assertEquals("()Lclass/with/only/Fields;", frame.signature);
152     assertEquals("Methods.java", frame.filename);
153     assertEquals(64, frame.line);
154 
155     frame = map.getFrame("class.with.Methods", "o", "()V", "SourceFile.java", 80);
156     assertEquals("lineObfuscatedMethod", frame.method);
157     assertEquals("()V", frame.signature);
158     assertEquals("Methods.java", frame.filename);
159     assertEquals(8, frame.line);
160 
161     frame = map.getFrame("class.with.Methods", "o", "()V", "SourceFile.java", 103);
162     assertEquals("lineObfuscatedMethod", frame.method);
163     assertEquals("()V", frame.signature);
164     assertEquals("Methods.java", frame.filename);
165     assertEquals(53, frame.line);
166 
167     frame = map.getFrame("class.with.Methods", "p", "()V", "SourceFile.java", 94);
168     assertEquals("lineObfuscatedMethod2", frame.method);
169     assertEquals("()V", frame.signature);
170     assertEquals("Methods.java", frame.filename);
171     assertEquals(13, frame.line);
172 
173     // Some methods may not have been obfuscated. We should still be able
174     // to compute the filename properly.
175     frame = map.getFrame("class.with.Methods", "unObfuscatedMethodName",
176         "()V", "SourceFile.java", 0);
177     assertEquals("Methods.java", frame.filename);
178   }
179 }
180