1 /* 2 * Copyright (C) 2011 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.dx.command.grep; 18 19 import com.android.dex.ClassData; 20 import com.android.dex.ClassDef; 21 import com.android.dex.Dex; 22 import com.android.dex.EncodedValueReader; 23 import com.android.dex.MethodId; 24 import com.android.dx.io.CodeReader; 25 import com.android.dx.io.instructions.DecodedInstruction; 26 import java.io.PrintWriter; 27 import java.util.HashSet; 28 import java.util.Set; 29 import java.util.regex.Pattern; 30 31 public final class Grep { 32 private final Dex dex; 33 private final CodeReader codeReader = new CodeReader(); 34 private final Set<Integer> stringIds; 35 36 private final PrintWriter out; 37 private int count = 0; 38 39 private ClassDef currentClass; 40 private ClassData.Method currentMethod; 41 Grep(final Dex dex, Pattern pattern, final PrintWriter out)42 public Grep(final Dex dex, Pattern pattern, final PrintWriter out) { 43 this.dex = dex; 44 this.out = out; 45 46 stringIds = getStringIds(dex, pattern); 47 48 codeReader.setStringVisitor(new CodeReader.Visitor() { 49 @Override 50 public void visit(DecodedInstruction[] all, DecodedInstruction one) { 51 encounterString(one.getIndex()); 52 } 53 }); 54 } 55 readArray(EncodedValueReader reader)56 private void readArray(EncodedValueReader reader) { 57 for (int i = 0, size = reader.readArray(); i < size; i++) { 58 switch (reader.peek()) { 59 case EncodedValueReader.ENCODED_STRING: 60 encounterString(reader.readString()); 61 break; 62 case EncodedValueReader.ENCODED_ARRAY: 63 readArray(reader); 64 break; 65 } 66 } 67 } 68 encounterString(int index)69 private void encounterString(int index) { 70 if (stringIds.contains(index)) { 71 out.println(location() + " " + dex.strings().get(index)); 72 count++; 73 } 74 } 75 location()76 private String location() { 77 String className = dex.typeNames().get(currentClass.getTypeIndex()); 78 if (currentMethod != null) { 79 MethodId methodId = dex.methodIds().get(currentMethod.getMethodIndex()); 80 return className + "." + dex.strings().get(methodId.getNameIndex()); 81 } else { 82 return className; 83 } 84 } 85 86 /** 87 * Prints usages to out. Returns the number of matches found. 88 */ grep()89 public int grep() { 90 for (ClassDef classDef : dex.classDefs()) { 91 currentClass = classDef; 92 currentMethod = null; 93 94 if (classDef.getClassDataOffset() == 0) { 95 continue; 96 } 97 98 ClassData classData = dex.readClassData(classDef); 99 100 // find the strings in encoded constants 101 int staticValuesOffset = classDef.getStaticValuesOffset(); 102 if (staticValuesOffset != 0) { 103 readArray(new EncodedValueReader(dex.open(staticValuesOffset))); 104 } 105 106 // find the strings in method bodies 107 for (ClassData.Method method : classData.allMethods()) { 108 currentMethod = method; 109 if (method.getCodeOffset() != 0) { 110 codeReader.visitAll(dex.readCode(method).getInstructions()); 111 } 112 } 113 } 114 115 currentClass = null; 116 currentMethod = null; 117 return count; 118 } 119 getStringIds(Dex dex, Pattern pattern)120 private Set<Integer> getStringIds(Dex dex, Pattern pattern) { 121 Set<Integer> stringIds = new HashSet<Integer>(); 122 int stringIndex = 0; 123 for (String s : dex.strings()) { 124 if (pattern.matcher(s).find()) { 125 stringIds.add(stringIndex); 126 } 127 stringIndex++; 128 } 129 return stringIds; 130 } 131 } 132