1ae38a1e705253b53abf1beff7dc3467d52c58f32Jesse Wilson/* 2ae38a1e705253b53abf1beff7dc3467d52c58f32Jesse Wilson * Copyright (C) 2011 The Android Open Source Project 3ae38a1e705253b53abf1beff7dc3467d52c58f32Jesse Wilson * 4ae38a1e705253b53abf1beff7dc3467d52c58f32Jesse Wilson * Licensed under the Apache License, Version 2.0 (the "License"); 5ae38a1e705253b53abf1beff7dc3467d52c58f32Jesse Wilson * you may not use this file except in compliance with the License. 6ae38a1e705253b53abf1beff7dc3467d52c58f32Jesse Wilson * You may obtain a copy of the License at 7ae38a1e705253b53abf1beff7dc3467d52c58f32Jesse Wilson * 8ae38a1e705253b53abf1beff7dc3467d52c58f32Jesse Wilson * http://www.apache.org/licenses/LICENSE-2.0 9ae38a1e705253b53abf1beff7dc3467d52c58f32Jesse Wilson * 10ae38a1e705253b53abf1beff7dc3467d52c58f32Jesse Wilson * Unless required by applicable law or agreed to in writing, software 11ae38a1e705253b53abf1beff7dc3467d52c58f32Jesse Wilson * distributed under the License is distributed on an "AS IS" BASIS, 12ae38a1e705253b53abf1beff7dc3467d52c58f32Jesse Wilson * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13ae38a1e705253b53abf1beff7dc3467d52c58f32Jesse Wilson * See the License for the specific language governing permissions and 14ae38a1e705253b53abf1beff7dc3467d52c58f32Jesse Wilson * limitations under the License. 15ae38a1e705253b53abf1beff7dc3467d52c58f32Jesse Wilson */ 16ae38a1e705253b53abf1beff7dc3467d52c58f32Jesse Wilson 17ae38a1e705253b53abf1beff7dc3467d52c58f32Jesse Wilsonpackage com.android.dx.command.grep; 18ae38a1e705253b53abf1beff7dc3467d52c58f32Jesse Wilson 19fe107fb6e3f308ac5174ebdc5a794ee880c741d9Jesse Wilsonimport com.android.dex.ClassData; 20fe107fb6e3f308ac5174ebdc5a794ee880c741d9Jesse Wilsonimport com.android.dex.ClassDef; 21fe107fb6e3f308ac5174ebdc5a794ee880c741d9Jesse Wilsonimport com.android.dex.Dex; 22fe107fb6e3f308ac5174ebdc5a794ee880c741d9Jesse Wilsonimport com.android.dex.EncodedValueReader; 23fe107fb6e3f308ac5174ebdc5a794ee880c741d9Jesse Wilsonimport com.android.dex.MethodId; 24ae38a1e705253b53abf1beff7dc3467d52c58f32Jesse Wilsonimport com.android.dx.io.CodeReader; 25ae38a1e705253b53abf1beff7dc3467d52c58f32Jesse Wilsonimport com.android.dx.io.instructions.DecodedInstruction; 266bf7f30e6968d9917eb4d0ca2280df96a8096134Jesse Wilsonimport java.io.PrintWriter; 27ae38a1e705253b53abf1beff7dc3467d52c58f32Jesse Wilsonimport java.util.HashSet; 28ae38a1e705253b53abf1beff7dc3467d52c58f32Jesse Wilsonimport java.util.Set; 29ae38a1e705253b53abf1beff7dc3467d52c58f32Jesse Wilsonimport java.util.regex.Pattern; 30ae38a1e705253b53abf1beff7dc3467d52c58f32Jesse Wilson 31ae38a1e705253b53abf1beff7dc3467d52c58f32Jesse Wilsonpublic final class Grep { 32fe107fb6e3f308ac5174ebdc5a794ee880c741d9Jesse Wilson private final Dex dex; 33ae38a1e705253b53abf1beff7dc3467d52c58f32Jesse Wilson private final CodeReader codeReader = new CodeReader(); 34ae38a1e705253b53abf1beff7dc3467d52c58f32Jesse Wilson private final Set<Integer> stringIds; 35ae38a1e705253b53abf1beff7dc3467d52c58f32Jesse Wilson 366bf7f30e6968d9917eb4d0ca2280df96a8096134Jesse Wilson private final PrintWriter out; 37ae38a1e705253b53abf1beff7dc3467d52c58f32Jesse Wilson private int count = 0; 38ae38a1e705253b53abf1beff7dc3467d52c58f32Jesse Wilson 39ae38a1e705253b53abf1beff7dc3467d52c58f32Jesse Wilson private ClassDef currentClass; 40ae38a1e705253b53abf1beff7dc3467d52c58f32Jesse Wilson private ClassData.Method currentMethod; 41ae38a1e705253b53abf1beff7dc3467d52c58f32Jesse Wilson 42fe107fb6e3f308ac5174ebdc5a794ee880c741d9Jesse Wilson public Grep(final Dex dex, Pattern pattern, final PrintWriter out) { 43ae38a1e705253b53abf1beff7dc3467d52c58f32Jesse Wilson this.dex = dex; 44ae38a1e705253b53abf1beff7dc3467d52c58f32Jesse Wilson this.out = out; 45ae38a1e705253b53abf1beff7dc3467d52c58f32Jesse Wilson 46ae38a1e705253b53abf1beff7dc3467d52c58f32Jesse Wilson stringIds = getStringIds(dex, pattern); 47ae38a1e705253b53abf1beff7dc3467d52c58f32Jesse Wilson 48ae38a1e705253b53abf1beff7dc3467d52c58f32Jesse Wilson codeReader.setStringVisitor(new CodeReader.Visitor() { 499dbd802c8c96c3a66873bc600bc7d1374a1d08e5Orion Hodson @Override 50ae38a1e705253b53abf1beff7dc3467d52c58f32Jesse Wilson public void visit(DecodedInstruction[] all, DecodedInstruction one) { 51ae38a1e705253b53abf1beff7dc3467d52c58f32Jesse Wilson encounterString(one.getIndex()); 52ae38a1e705253b53abf1beff7dc3467d52c58f32Jesse Wilson } 53ae38a1e705253b53abf1beff7dc3467d52c58f32Jesse Wilson }); 54ae38a1e705253b53abf1beff7dc3467d52c58f32Jesse Wilson } 55ae38a1e705253b53abf1beff7dc3467d52c58f32Jesse Wilson 567e85b634fbafa4a3b927c80665dea6fac337d886Jesse Wilson private void readArray(EncodedValueReader reader) { 577e85b634fbafa4a3b927c80665dea6fac337d886Jesse Wilson for (int i = 0, size = reader.readArray(); i < size; i++) { 587e85b634fbafa4a3b927c80665dea6fac337d886Jesse Wilson switch (reader.peek()) { 597e85b634fbafa4a3b927c80665dea6fac337d886Jesse Wilson case EncodedValueReader.ENCODED_STRING: 607e85b634fbafa4a3b927c80665dea6fac337d886Jesse Wilson encounterString(reader.readString()); 617e85b634fbafa4a3b927c80665dea6fac337d886Jesse Wilson break; 627e85b634fbafa4a3b927c80665dea6fac337d886Jesse Wilson case EncodedValueReader.ENCODED_ARRAY: 637e85b634fbafa4a3b927c80665dea6fac337d886Jesse Wilson readArray(reader); 647e85b634fbafa4a3b927c80665dea6fac337d886Jesse Wilson break; 65ae38a1e705253b53abf1beff7dc3467d52c58f32Jesse Wilson } 667e85b634fbafa4a3b927c80665dea6fac337d886Jesse Wilson } 67ae38a1e705253b53abf1beff7dc3467d52c58f32Jesse Wilson } 68ae38a1e705253b53abf1beff7dc3467d52c58f32Jesse Wilson 69ae38a1e705253b53abf1beff7dc3467d52c58f32Jesse Wilson private void encounterString(int index) { 70ae38a1e705253b53abf1beff7dc3467d52c58f32Jesse Wilson if (stringIds.contains(index)) { 71ae38a1e705253b53abf1beff7dc3467d52c58f32Jesse Wilson out.println(location() + " " + dex.strings().get(index)); 72ae38a1e705253b53abf1beff7dc3467d52c58f32Jesse Wilson count++; 73ae38a1e705253b53abf1beff7dc3467d52c58f32Jesse Wilson } 74ae38a1e705253b53abf1beff7dc3467d52c58f32Jesse Wilson } 75ae38a1e705253b53abf1beff7dc3467d52c58f32Jesse Wilson 76ae38a1e705253b53abf1beff7dc3467d52c58f32Jesse Wilson private String location() { 77ae38a1e705253b53abf1beff7dc3467d52c58f32Jesse Wilson String className = dex.typeNames().get(currentClass.getTypeIndex()); 78ae38a1e705253b53abf1beff7dc3467d52c58f32Jesse Wilson if (currentMethod != null) { 79ae38a1e705253b53abf1beff7dc3467d52c58f32Jesse Wilson MethodId methodId = dex.methodIds().get(currentMethod.getMethodIndex()); 80ae38a1e705253b53abf1beff7dc3467d52c58f32Jesse Wilson return className + "." + dex.strings().get(methodId.getNameIndex()); 81ae38a1e705253b53abf1beff7dc3467d52c58f32Jesse Wilson } else { 82ae38a1e705253b53abf1beff7dc3467d52c58f32Jesse Wilson return className; 83ae38a1e705253b53abf1beff7dc3467d52c58f32Jesse Wilson } 84ae38a1e705253b53abf1beff7dc3467d52c58f32Jesse Wilson } 85ae38a1e705253b53abf1beff7dc3467d52c58f32Jesse Wilson 86ae38a1e705253b53abf1beff7dc3467d52c58f32Jesse Wilson /** 87ae38a1e705253b53abf1beff7dc3467d52c58f32Jesse Wilson * Prints usages to out. Returns the number of matches found. 88ae38a1e705253b53abf1beff7dc3467d52c58f32Jesse Wilson */ 89ae38a1e705253b53abf1beff7dc3467d52c58f32Jesse Wilson public int grep() { 90ae38a1e705253b53abf1beff7dc3467d52c58f32Jesse Wilson for (ClassDef classDef : dex.classDefs()) { 91ae38a1e705253b53abf1beff7dc3467d52c58f32Jesse Wilson currentClass = classDef; 92ae38a1e705253b53abf1beff7dc3467d52c58f32Jesse Wilson currentMethod = null; 93ae38a1e705253b53abf1beff7dc3467d52c58f32Jesse Wilson 94ae38a1e705253b53abf1beff7dc3467d52c58f32Jesse Wilson if (classDef.getClassDataOffset() == 0) { 95ae38a1e705253b53abf1beff7dc3467d52c58f32Jesse Wilson continue; 96ae38a1e705253b53abf1beff7dc3467d52c58f32Jesse Wilson } 97ae38a1e705253b53abf1beff7dc3467d52c58f32Jesse Wilson 98ae38a1e705253b53abf1beff7dc3467d52c58f32Jesse Wilson ClassData classData = dex.readClassData(classDef); 99ae38a1e705253b53abf1beff7dc3467d52c58f32Jesse Wilson 100ae38a1e705253b53abf1beff7dc3467d52c58f32Jesse Wilson // find the strings in encoded constants 101ae38a1e705253b53abf1beff7dc3467d52c58f32Jesse Wilson int staticValuesOffset = classDef.getStaticValuesOffset(); 102ae38a1e705253b53abf1beff7dc3467d52c58f32Jesse Wilson if (staticValuesOffset != 0) { 1037e85b634fbafa4a3b927c80665dea6fac337d886Jesse Wilson readArray(new EncodedValueReader(dex.open(staticValuesOffset))); 104ae38a1e705253b53abf1beff7dc3467d52c58f32Jesse Wilson } 105ae38a1e705253b53abf1beff7dc3467d52c58f32Jesse Wilson 106ae38a1e705253b53abf1beff7dc3467d52c58f32Jesse Wilson // find the strings in method bodies 107ae38a1e705253b53abf1beff7dc3467d52c58f32Jesse Wilson for (ClassData.Method method : classData.allMethods()) { 108ae38a1e705253b53abf1beff7dc3467d52c58f32Jesse Wilson currentMethod = method; 109ae38a1e705253b53abf1beff7dc3467d52c58f32Jesse Wilson if (method.getCodeOffset() != 0) { 110ae38a1e705253b53abf1beff7dc3467d52c58f32Jesse Wilson codeReader.visitAll(dex.readCode(method).getInstructions()); 111ae38a1e705253b53abf1beff7dc3467d52c58f32Jesse Wilson } 112ae38a1e705253b53abf1beff7dc3467d52c58f32Jesse Wilson } 113ae38a1e705253b53abf1beff7dc3467d52c58f32Jesse Wilson } 114ae38a1e705253b53abf1beff7dc3467d52c58f32Jesse Wilson 115ae38a1e705253b53abf1beff7dc3467d52c58f32Jesse Wilson currentClass = null; 116ae38a1e705253b53abf1beff7dc3467d52c58f32Jesse Wilson currentMethod = null; 117ae38a1e705253b53abf1beff7dc3467d52c58f32Jesse Wilson return count; 118ae38a1e705253b53abf1beff7dc3467d52c58f32Jesse Wilson } 119ae38a1e705253b53abf1beff7dc3467d52c58f32Jesse Wilson 120fe107fb6e3f308ac5174ebdc5a794ee880c741d9Jesse Wilson private Set<Integer> getStringIds(Dex dex, Pattern pattern) { 121ae38a1e705253b53abf1beff7dc3467d52c58f32Jesse Wilson Set<Integer> stringIds = new HashSet<Integer>(); 122ae38a1e705253b53abf1beff7dc3467d52c58f32Jesse Wilson int stringIndex = 0; 123ae38a1e705253b53abf1beff7dc3467d52c58f32Jesse Wilson for (String s : dex.strings()) { 124ae38a1e705253b53abf1beff7dc3467d52c58f32Jesse Wilson if (pattern.matcher(s).find()) { 125ae38a1e705253b53abf1beff7dc3467d52c58f32Jesse Wilson stringIds.add(stringIndex); 126ae38a1e705253b53abf1beff7dc3467d52c58f32Jesse Wilson } 127ae38a1e705253b53abf1beff7dc3467d52c58f32Jesse Wilson stringIndex++; 128ae38a1e705253b53abf1beff7dc3467d52c58f32Jesse Wilson } 129ae38a1e705253b53abf1beff7dc3467d52c58f32Jesse Wilson return stringIds; 130ae38a1e705253b53abf1beff7dc3467d52c58f32Jesse Wilson } 131ae38a1e705253b53abf1beff7dc3467d52c58f32Jesse Wilson} 132