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_FORMAT = 28 "# compiler: richard\n" 29 + "# compiler_version: %s-dev\n" 30 + "# min_api: 10000\n" 31 + "# compiler_hash: b7e25308967a577aa1f05a4b5a745c26\n" 32 + " # indented comment\n" 33 + "class.that.is.Empty -> a:\n" 34 + "class.that.is.Empty$subclass -> b:\n" 35 + "class.with.only.Fields -> c:\n" 36 + " # indented inner comment\n" 37 + " int prim_type_field -> a\n" 38 + " int[] prim_array_type_field -> b\n" 39 + " class.that.is.Empty class_type_field -> c\n" 40 + " class.that.is.Empty[] array_type_field -> d\n" 41 + " int longObfuscatedNameField -> abc\n" 42 + "class.with.Methods -> d:\n" 43 + " int some_field -> a\n" 44 + " 12:23:void <clinit>() -> <clinit>\n" 45 + " 42:43:void boringMethod() -> m\n" 46 + " # indented further inner comment\n" 47 + " 45:48:void methodWithPrimArgs(int,float) -> m\n" 48 + " 49:50:void methodWithPrimArrArgs(int[],float) -> m\n" 49 + " 52:55:void methodWithClearObjArg(class.not.in.Map) -> m\n" 50 + " 57:58:void methodWithClearObjArrArg(class.not.in.Map[]) -> m\n" 51 + " 59:61:void methodWithObfObjArg(class.with.only.Fields) -> m\n" 52 + " 64:66:class.with.only.Fields methodWithObfRes() -> n\n" 53 + " 80:80:void lineObfuscatedMethod():8:8 -> o\n" 54 + " 100:105:void lineObfuscatedMethod():50 -> o\n" 55 + " 90:94:void lineObfuscatedMethod2():9 -> p\n" 56 ; 57 58 @Test oldProguardMap()59 public void oldProguardMap() throws IOException, ParseException { 60 runOldProguardMap(String.format(TEST_MAP_FORMAT, "3.0.1")); 61 runOldProguardMap(String.format(TEST_MAP_FORMAT, "3.1")); 62 } 63 runOldProguardMap(String testMap)64 public void runOldProguardMap(String testMap) throws IOException, ParseException { 65 ProguardMap map = new ProguardMap(); 66 67 // An empty proguard map should not deobfuscate anything. 68 assertEquals("foo.bar.Sludge", map.getClassName("foo.bar.Sludge")); 69 assertEquals("fooBarSludge", map.getClassName("fooBarSludge")); 70 assertEquals("myfield", map.getFieldName("foo.bar.Sludge", "myfield")); 71 assertEquals("myfield", map.getFieldName("fooBarSludge", "myfield")); 72 ProguardMap.Frame frame = map.getFrame( 73 "foo.bar.Sludge", "mymethod", "(Lfoo/bar/Sludge;)V", "SourceFile.java", 123); 74 assertEquals("mymethod", frame.method); 75 assertEquals("(Lfoo/bar/Sludge;)V", frame.signature); 76 assertEquals("SourceFile.java", frame.filename); 77 assertEquals(123, frame.line); 78 79 // Read in the proguard map. 80 map.readFromReader(new StringReader(testMap)); 81 82 // It should still not deobfuscate things that aren't in the map 83 assertEquals("foo.bar.Sludge", map.getClassName("foo.bar.Sludge")); 84 assertEquals("fooBarSludge", map.getClassName("fooBarSludge")); 85 assertEquals("myfield", map.getFieldName("foo.bar.Sludge", "myfield")); 86 assertEquals("myfield", map.getFieldName("fooBarSludge", "myfield")); 87 frame = map.getFrame("foo.bar.Sludge", "mymethod", "(Lfoo/bar/Sludge;)V", 88 "SourceFile.java", 123); 89 assertEquals("mymethod", frame.method); 90 assertEquals("(Lfoo/bar/Sludge;)V", frame.signature); 91 assertEquals("SourceFile.java", frame.filename); 92 assertEquals(123, frame.line); 93 94 // Test deobfuscation of class names 95 assertEquals("class.that.is.Empty", map.getClassName("a")); 96 assertEquals("class.that.is.Empty$subclass", map.getClassName("b")); 97 assertEquals("class.with.only.Fields", map.getClassName("c")); 98 assertEquals("class.with.Methods", map.getClassName("d")); 99 100 // Test deobfuscation of array classes. 101 assertEquals("class.with.Methods[]", map.getClassName("d[]")); 102 assertEquals("class.with.Methods[][]", map.getClassName("d[][]")); 103 104 // Test deobfuscation of methods 105 assertEquals("prim_type_field", map.getFieldName("class.with.only.Fields", "a")); 106 assertEquals("prim_array_type_field", map.getFieldName("class.with.only.Fields", "b")); 107 assertEquals("class_type_field", map.getFieldName("class.with.only.Fields", "c")); 108 assertEquals("array_type_field", map.getFieldName("class.with.only.Fields", "d")); 109 assertEquals("longObfuscatedNameField", map.getFieldName("class.with.only.Fields", "abc")); 110 assertEquals("some_field", map.getFieldName("class.with.Methods", "a")); 111 112 // Test deobfuscation of frames 113 frame = map.getFrame("class.with.Methods", "<clinit>", "()V", "SourceFile.java", 13); 114 assertEquals("<clinit>", frame.method); 115 assertEquals("()V", frame.signature); 116 assertEquals("Methods.java", frame.filename); 117 assertEquals(13, frame.line); 118 119 frame = map.getFrame("class.with.Methods", "m", "()V", "SourceFile.java", 42); 120 assertEquals("boringMethod", frame.method); 121 assertEquals("()V", frame.signature); 122 assertEquals("Methods.java", frame.filename); 123 assertEquals(42, frame.line); 124 125 frame = map.getFrame("class.with.Methods", "m", "(IF)V", "SourceFile.java", 45); 126 assertEquals("methodWithPrimArgs", frame.method); 127 assertEquals("(IF)V", frame.signature); 128 assertEquals("Methods.java", frame.filename); 129 assertEquals(45, frame.line); 130 131 frame = map.getFrame("class.with.Methods", "m", "([IF)V", "SourceFile.java", 49); 132 assertEquals("methodWithPrimArrArgs", frame.method); 133 assertEquals("([IF)V", frame.signature); 134 assertEquals("Methods.java", frame.filename); 135 assertEquals(49, frame.line); 136 137 frame = map.getFrame("class.with.Methods", "m", "(Lclass/not/in/Map;)V", 138 "SourceFile.java", 52); 139 assertEquals("methodWithClearObjArg", frame.method); 140 assertEquals("(Lclass/not/in/Map;)V", frame.signature); 141 assertEquals("Methods.java", frame.filename); 142 assertEquals(52, frame.line); 143 144 frame = map.getFrame("class.with.Methods", "m", "([Lclass/not/in/Map;)V", 145 "SourceFile.java", 57); 146 assertEquals("methodWithClearObjArrArg", frame.method); 147 assertEquals("([Lclass/not/in/Map;)V", frame.signature); 148 assertEquals("Methods.java", frame.filename); 149 assertEquals(57, frame.line); 150 151 frame = map.getFrame("class.with.Methods", "m", "(Lc;)V", "SourceFile.java", 59); 152 assertEquals("methodWithObfObjArg", frame.method); 153 assertEquals("(Lclass/with/only/Fields;)V", frame.signature); 154 assertEquals("Methods.java", frame.filename); 155 assertEquals(59, frame.line); 156 157 frame = map.getFrame("class.with.Methods", "n", "()Lc;", "SourceFile.java", 64); 158 assertEquals("methodWithObfRes", frame.method); 159 assertEquals("()Lclass/with/only/Fields;", frame.signature); 160 assertEquals("Methods.java", frame.filename); 161 assertEquals(64, frame.line); 162 163 frame = map.getFrame("class.with.Methods", "o", "()V", "SourceFile.java", 80); 164 assertEquals("lineObfuscatedMethod", frame.method); 165 assertEquals("()V", frame.signature); 166 assertEquals("Methods.java", frame.filename); 167 assertEquals(8, frame.line); 168 169 frame = map.getFrame("class.with.Methods", "o", "()V", "SourceFile.java", 103); 170 assertEquals("lineObfuscatedMethod", frame.method); 171 assertEquals("()V", frame.signature); 172 assertEquals("Methods.java", frame.filename); 173 assertEquals(53, frame.line); 174 175 frame = map.getFrame("class.with.Methods", "p", "()V", "SourceFile.java", 94); 176 assertEquals("lineObfuscatedMethod2", frame.method); 177 assertEquals("()V", frame.signature); 178 assertEquals("Methods.java", frame.filename); 179 assertEquals(13, frame.line); 180 181 // Some methods may not have been obfuscated. We should still be able 182 // to compute the filename properly. 183 frame = map.getFrame("class.with.Methods", "unObfuscatedMethodName", 184 "()V", "SourceFile.java", 0); 185 assertEquals("Methods.java", frame.filename); 186 } 187 188 @Test proguardMap()189 public void proguardMap() throws IOException, ParseException { 190 runNewProguardMap(String.format(TEST_MAP_FORMAT, "3.1.4")); 191 runNewProguardMap(String.format(TEST_MAP_FORMAT, "3.2")); 192 } 193 runNewProguardMap(String testMap)194 public void runNewProguardMap(String testMap) throws IOException, ParseException { 195 ProguardMap map = new ProguardMap(); 196 197 // An empty proguard map should not deobfuscate anything. 198 assertEquals("foo.bar.Sludge", map.getClassName("foo.bar.Sludge")); 199 assertEquals("fooBarSludge", map.getClassName("fooBarSludge")); 200 assertEquals("myfield", map.getFieldName("foo.bar.Sludge", "myfield")); 201 assertEquals("myfield", map.getFieldName("fooBarSludge", "myfield")); 202 ProguardMap.Frame frame = map.getFrame( 203 "foo.bar.Sludge", "mymethod", "(Lfoo/bar/Sludge;)V", "SourceFile.java", 123); 204 assertEquals("mymethod", frame.method); 205 assertEquals("(Lfoo/bar/Sludge;)V", frame.signature); 206 assertEquals("SourceFile.java", frame.filename); 207 assertEquals(123, frame.line); 208 209 // Read in the proguard map. 210 map.readFromReader(new StringReader(testMap)); 211 212 // It should still not deobfuscate things that aren't in the map 213 assertEquals("foo.bar.Sludge", map.getClassName("foo.bar.Sludge")); 214 assertEquals("fooBarSludge", map.getClassName("fooBarSludge")); 215 assertEquals("myfield", map.getFieldName("foo.bar.Sludge", "myfield")); 216 assertEquals("myfield", map.getFieldName("fooBarSludge", "myfield")); 217 frame = map.getFrame("foo.bar.Sludge", "mymethod", "(Lfoo/bar/Sludge;)V", 218 "SourceFile.java", 123); 219 assertEquals("mymethod", frame.method); 220 assertEquals("(Lfoo/bar/Sludge;)V", frame.signature); 221 assertEquals("SourceFile.java", frame.filename); 222 assertEquals(123, frame.line); 223 224 // Test deobfuscation of class names 225 assertEquals("class.that.is.Empty", map.getClassName("a")); 226 assertEquals("class.that.is.Empty$subclass", map.getClassName("b")); 227 assertEquals("class.with.only.Fields", map.getClassName("c")); 228 assertEquals("class.with.Methods", map.getClassName("d")); 229 230 // Test deobfuscation of array classes. 231 assertEquals("class.with.Methods[]", map.getClassName("d[]")); 232 assertEquals("class.with.Methods[][]", map.getClassName("d[][]")); 233 234 // Test deobfuscation of fields 235 assertEquals("prim_type_field", map.getFieldName("class.with.only.Fields", "a")); 236 assertEquals("prim_array_type_field", map.getFieldName("class.with.only.Fields", "b")); 237 assertEquals("class_type_field", map.getFieldName("class.with.only.Fields", "c")); 238 assertEquals("array_type_field", map.getFieldName("class.with.only.Fields", "d")); 239 assertEquals("longObfuscatedNameField", map.getFieldName("class.with.only.Fields", "abc")); 240 assertEquals("some_field", map.getFieldName("class.with.Methods", "a")); 241 242 // Test deobfuscation of frames 243 frame = map.getFrame("class.with.Methods", "<clinit>", "()V", "SourceFile.java", 13); 244 assertEquals("<clinit>", frame.method); 245 assertEquals("()V", frame.signature); 246 assertEquals("Methods.java", frame.filename); 247 assertEquals(13, frame.line); 248 249 frame = map.getFrame("class.with.Methods", "m", "()V", "SourceFile.java", 42); 250 assertEquals("boringMethod", frame.method); 251 assertEquals("()V", frame.signature); 252 assertEquals("Methods.java", frame.filename); 253 assertEquals(42, frame.line); 254 255 frame = map.getFrame("class.with.Methods", "m", "(IF)V", "SourceFile.java", 45); 256 assertEquals("methodWithPrimArgs", frame.method); 257 assertEquals("(IF)V", frame.signature); 258 assertEquals("Methods.java", frame.filename); 259 assertEquals(45, frame.line); 260 261 frame = map.getFrame("class.with.Methods", "m", "([IF)V", "SourceFile.java", 49); 262 assertEquals("methodWithPrimArrArgs", frame.method); 263 assertEquals("([IF)V", frame.signature); 264 assertEquals("Methods.java", frame.filename); 265 assertEquals(49, frame.line); 266 267 frame = map.getFrame("class.with.Methods", "m", "(Lclass/not/in/Map;)V", 268 "SourceFile.java", 52); 269 assertEquals("methodWithClearObjArg", frame.method); 270 assertEquals("(Lclass/not/in/Map;)V", frame.signature); 271 assertEquals("Methods.java", frame.filename); 272 assertEquals(52, frame.line); 273 274 frame = map.getFrame("class.with.Methods", "m", "([Lclass/not/in/Map;)V", 275 "SourceFile.java", 57); 276 assertEquals("methodWithClearObjArrArg", frame.method); 277 assertEquals("([Lclass/not/in/Map;)V", frame.signature); 278 assertEquals("Methods.java", frame.filename); 279 assertEquals(57, frame.line); 280 281 frame = map.getFrame("class.with.Methods", "m", "(Lc;)V", "SourceFile.java", 59); 282 assertEquals("methodWithObfObjArg", frame.method); 283 assertEquals("(Lclass/with/only/Fields;)V", frame.signature); 284 assertEquals("Methods.java", frame.filename); 285 assertEquals(59, frame.line); 286 287 frame = map.getFrame("class.with.Methods", "n", "()Lc;", "SourceFile.java", 64); 288 assertEquals("methodWithObfRes", frame.method); 289 assertEquals("()Lclass/with/only/Fields;", frame.signature); 290 assertEquals("Methods.java", frame.filename); 291 assertEquals(64, frame.line); 292 293 frame = map.getFrame("class.with.Methods", "o", "()V", "SourceFile.java", 80); 294 assertEquals("lineObfuscatedMethod", frame.method); 295 assertEquals("()V", frame.signature); 296 assertEquals("Methods.java", frame.filename); 297 assertEquals(8, frame.line); 298 299 frame = map.getFrame("class.with.Methods", "o", "()V", "SourceFile.java", 103); 300 assertEquals("lineObfuscatedMethod", frame.method); 301 assertEquals("()V", frame.signature); 302 assertEquals("Methods.java", frame.filename); 303 assertEquals(50, frame.line); 304 305 frame = map.getFrame("class.with.Methods", "p", "()V", "SourceFile.java", 94); 306 assertEquals("lineObfuscatedMethod2", frame.method); 307 assertEquals("()V", frame.signature); 308 assertEquals("Methods.java", frame.filename); 309 assertEquals(9, frame.line); 310 311 // Some methods may not have been obfuscated. We should still be able 312 // to compute the filename properly. 313 frame = map.getFrame("class.with.Methods", "unObfuscatedMethodName", 314 "()V", "SourceFile.java", 0); 315 assertEquals("Methods.java", frame.filename); 316 } 317 } 318