diff options
-rw-r--r-- | tools/dexdeps/src/com/android/dexdeps/ClassRef.java | 70 | ||||
-rw-r--r-- | tools/dexdeps/src/com/android/dexdeps/DexData.java | 89 | ||||
-rw-r--r-- | tools/dexdeps/src/com/android/dexdeps/Output.java | 161 |
3 files changed, 218 insertions, 102 deletions
diff --git a/tools/dexdeps/src/com/android/dexdeps/ClassRef.java b/tools/dexdeps/src/com/android/dexdeps/ClassRef.java new file mode 100644 index 000000000..8065a0aab --- /dev/null +++ b/tools/dexdeps/src/com/android/dexdeps/ClassRef.java @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.dexdeps; + +import java.util.ArrayList; + +public class ClassRef { + private String mClassName; + private ArrayList<FieldRef> mFieldRefs; + private ArrayList<MethodRef> mMethodRefs; + + /** + * Initializes a new class reference. + */ + public ClassRef(String className) { + mClassName = className; + mFieldRefs = new ArrayList<FieldRef>(); + mMethodRefs = new ArrayList<MethodRef>(); + } + + /** + * Adds the field to the field list. + */ + public void addField(FieldRef fref) { + mFieldRefs.add(fref); + } + + /** + * Returns the field list as an array. + */ + public FieldRef[] getFieldArray() { + return mFieldRefs.toArray(new FieldRef[mFieldRefs.size()]); + } + + /** + * Adds the method to the method list. + */ + public void addMethod(MethodRef mref) { + mMethodRefs.add(mref); + } + + /** + * Returns the method list as an array. + */ + public MethodRef[] getMethodArray() { + return mMethodRefs.toArray(new MethodRef[mMethodRefs.size()]); + } + + /** + * Gets the class name. + */ + public String getName() { + return mClassName; + } +} + diff --git a/tools/dexdeps/src/com/android/dexdeps/DexData.java b/tools/dexdeps/src/com/android/dexdeps/DexData.java index fa79d60b6..0a7fa2d4e 100644 --- a/tools/dexdeps/src/com/android/dexdeps/DexData.java +++ b/tools/dexdeps/src/com/android/dexdeps/DexData.java @@ -341,66 +341,75 @@ public class DexData { } /** - * Returns an array with all of the field references that don't - * correspond to classes in the DEX file. + * Returns an array with all of the class references that don't + * correspond to classes in the DEX file. Each class reference has + * a list of the referenced fields and methods associated with + * that class. */ - public FieldRef[] getExternalFieldReferences() { - // get a count + public ClassRef[] getExternalReferences() { + // create a sparse array of ClassRef that parallels mTypeIds + ClassRef[] sparseRefs = new ClassRef[mTypeIds.length]; + + // create entries for all externally-referenced classes int count = 0; - for (int i = 0; i < mFieldIds.length; i++) { - if (!mTypeIds[mFieldIds[i].classIdx].internal) + for (int i = 0; i < mTypeIds.length; i++) { + if (!mTypeIds[i].internal) { + sparseRefs[i] = + new ClassRef(mStrings[mTypeIds[i].descriptorIdx]); count++; + } } - //System.out.println("count is " + count + " of " + mFieldIds.length); + // add fields and methods to the appropriate class entry + addExternalFieldReferences(sparseRefs); + addExternalMethodReferences(sparseRefs); - FieldRef[] fieldRefs = new FieldRef[count]; - count = 0; - for (int i = 0; i < mFieldIds.length; i++) { - if (!mTypeIds[mFieldIds[i].classIdx].internal) { - FieldIdItem fieldId = mFieldIds[i]; - fieldRefs[count++] = - new FieldRef(classNameFromTypeIndex(fieldId.classIdx), - classNameFromTypeIndex(fieldId.typeIdx), - mStrings[fieldId.nameIdx]); - } + // crunch out the sparseness + ClassRef[] classRefs = new ClassRef[count]; + int idx = 0; + for (int i = 0; i < mTypeIds.length; i++) { + if (sparseRefs[i] != null) + classRefs[idx++] = sparseRefs[i]; } - assert count == fieldRefs.length; + assert idx == count; - return fieldRefs; + return classRefs; } /** - * Returns an array with all of the method references that don't - * correspond to classes in the DEX file. + * Runs through the list of field references, inserting external + * references into the appropriate ClassRef. */ - public MethodRef[] getExternalMethodReferences() { - // get a count - int count = 0; - for (int i = 0; i < mMethodIds.length; i++) { - if (!mTypeIds[mMethodIds[i].classIdx].internal) - count++; + private void addExternalFieldReferences(ClassRef[] sparseRefs) { + for (int i = 0; i < mFieldIds.length; i++) { + if (!mTypeIds[mFieldIds[i].classIdx].internal) { + FieldIdItem fieldId = mFieldIds[i]; + FieldRef newFieldRef = new FieldRef( + classNameFromTypeIndex(fieldId.classIdx), + classNameFromTypeIndex(fieldId.typeIdx), + mStrings[fieldId.nameIdx]); + sparseRefs[mFieldIds[i].classIdx].addField(newFieldRef); + } } + } - //System.out.println("count is " + count + " of " + mMethodIds.length); - - MethodRef[] methodRefs = new MethodRef[count]; - count = 0; + /** + * Runs through the list of method references, inserting external + * references into the appropriate ClassRef. + */ + private void addExternalMethodReferences(ClassRef[] sparseRefs) { for (int i = 0; i < mMethodIds.length; i++) { if (!mTypeIds[mMethodIds[i].classIdx].internal) { MethodIdItem methodId = mMethodIds[i]; - methodRefs[count++] = - new MethodRef(classNameFromTypeIndex(methodId.classIdx), - argArrayFromProtoIndex(methodId.protoIdx), - returnTypeFromProtoIndex(methodId.protoIdx), - mStrings[methodId.nameIdx]); + MethodRef newMethodRef = new MethodRef( + classNameFromTypeIndex(methodId.classIdx), + argArrayFromProtoIndex(methodId.protoIdx), + returnTypeFromProtoIndex(methodId.protoIdx), + mStrings[methodId.nameIdx]); + sparseRefs[mMethodIds[i].classIdx].addMethod(newMethodRef); } } - - assert count == methodRefs.length; - - return methodRefs; } diff --git a/tools/dexdeps/src/com/android/dexdeps/Output.java b/tools/dexdeps/src/com/android/dexdeps/Output.java index 0039b3302..7114951dc 100644 --- a/tools/dexdeps/src/com/android/dexdeps/Output.java +++ b/tools/dexdeps/src/com/android/dexdeps/Output.java @@ -20,6 +20,12 @@ package com.android.dexdeps; * Generate fancy output. */ public class Output { + private static final String IN0 = ""; + private static final String IN1 = " "; + private static final String IN2 = " "; + private static final String IN3 = " "; + private static final String IN4 = " "; + public static void generate(DexData dexData, String format) { if (format.equals("brief")) { printBrief(dexData); @@ -35,36 +41,56 @@ public class Output { * Prints the data in a simple human-readable format. */ static void printBrief(DexData dexData) { - FieldRef[] externFieldRefs = dexData.getExternalFieldReferences(); - MethodRef[] externMethodRefs = dexData.getExternalMethodReferences(); + ClassRef[] externClassRefs = dexData.getExternalReferences(); - printFieldRefs(externFieldRefs); - printMethodRefs(externMethodRefs); + printClassRefs(externClassRefs); + printFieldRefs(externClassRefs); + printMethodRefs(externClassRefs); + } + + /** + * Prints the list of classes in a simple human-readable format. + */ + static void printClassRefs(ClassRef[] classes) { + System.out.println("Classes:"); + for (int i = 0; i < classes.length; i++) { + ClassRef ref = classes[i]; + + System.out.println(descriptorToDot(ref.getName())); + } } /** * Prints the list of fields in a simple human-readable format. */ - static void printFieldRefs(FieldRef[] fields) { + static void printFieldRefs(ClassRef[] classes) { System.out.println("Fields:"); - for (int i = 0; i < fields.length; i++) { - FieldRef ref = fields[i]; + for (int i = 0; i < classes.length; i++) { + FieldRef[] fields = classes[i].getFieldArray(); + + for (int j = 0; j < fields.length; j++) { + FieldRef ref = fields[j]; - System.out.println(descriptorToDot(ref.getDeclClassName()) + "." + - ref.getName() + " : " + ref.getTypeName()); + System.out.println(descriptorToDot(ref.getDeclClassName()) + + "." + ref.getName() + " : " + ref.getTypeName()); + } } } /** * Prints the list of methods in a simple human-readable format. */ - static void printMethodRefs(MethodRef[] methods) { + static void printMethodRefs(ClassRef[] classes) { System.out.println("Methods:"); - for (int i = 0; i < methods.length; i++) { - MethodRef ref = methods[i]; + for (int i = 0; i < classes.length; i++) { + MethodRef[] methods = classes[i].getMethodArray(); - System.out.println(descriptorToDot(ref.getDeclClassName()) + - "." + ref.getName() + " : " + ref.getDescriptor()); + for (int j = 0; j < methods.length; j++) { + MethodRef ref = methods[j]; + + System.out.println(descriptorToDot(ref.getDeclClassName()) + + "." + ref.getName() + " : " + ref.getDescriptor()); + } } } @@ -75,79 +101,90 @@ public class Output { * We shouldn't need to XML-escape the field/method info. */ static void printXml(DexData dexData) { - final String IN0 = ""; - final String IN1 = " "; - final String IN2 = " "; - final String IN3 = " "; - FieldRef[] externFieldRefs = dexData.getExternalFieldReferences(); - MethodRef[] externMethodRefs = dexData.getExternalMethodReferences(); - String prevClass = null; + ClassRef[] externClassRefs = dexData.getExternalReferences(); System.out.println(IN0 + "<external>"); - /* print fields */ - for (int i = 0; i < externFieldRefs.length; i++) { - FieldRef fref = externFieldRefs[i]; - String declClassName = fref.getDeclClassName(); - - if (prevClass != null && !prevClass.equals(declClassName)) { - System.out.println(IN1 + "</class>"); - } - if (!declClassName.equals(prevClass)) { - String className = classNameOnly(declClassName); - String packageName = packageNameOnly(declClassName); - System.out.println(IN1 + "<class package=\"" + packageName + - "\" name=\"" + className + "\">"); - prevClass = declClassName; + /* + * Iterate through externClassRefs. For each class, dump all of + * the matching fields and methods. + */ + String prevPackage = null; + for (int i = 0; i < externClassRefs.length; i++) { + ClassRef cref = externClassRefs[i]; + String declClassName = cref.getName(); + String className = classNameOnly(declClassName); + String packageName = packageNameOnly(declClassName); + + /* + * If we're in a different package, emit the appropriate tags. + */ + if (!packageName.equals(prevPackage)) { + if (prevPackage != null) { + System.out.println(IN1 + "</package>"); + } + + System.out.println(IN1 + + "<package name=\"" + packageName + "\">"); + + prevPackage = packageName; } - System.out.println(IN2 + "<field name=\"" + fref.getName() + + System.out.println(IN2 + "<class name=\"" + className + "\">"); + printXmlFields(cref); + printXmlMethods(cref); + System.out.println(IN2 + "</class>"); + } + + if (prevPackage != null) + System.out.println(IN1 + "</package>"); + System.out.println(IN0 + "</external>"); + } + + /** + * Prints the externally-visible fields in XML format. + */ + private static void printXmlFields(ClassRef cref) { + FieldRef[] fields = cref.getFieldArray(); + for (int i = 0; i < fields.length; i++) { + FieldRef fref = fields[i]; + + System.out.println(IN3 + "<field name=\"" + fref.getName() + "\" type=\"" + descriptorToDot(fref.getTypeName()) + "\"/>"); } + } - /* print methods */ - for (int i = 0; i < externMethodRefs.length; i++) { - MethodRef mref = externMethodRefs[i]; + /** + * Prints the externally-visible methods in XML format. + */ + private static void printXmlMethods(ClassRef cref) { + MethodRef[] methods = cref.getMethodArray(); + for (int i = 0; i < methods.length; i++) { + MethodRef mref = methods[i]; String declClassName = mref.getDeclClassName(); boolean constructor; - if (prevClass != null && !prevClass.equals(declClassName)) { - System.out.println(IN1 + "</class>"); - } - if (!declClassName.equals(prevClass)) { - String className = classNameOnly(declClassName); - String packageName = packageNameOnly(declClassName); - System.out.println(IN1 + "<class package=\"" + packageName + - "\" name=\"" + className + "\">"); - prevClass = declClassName; - } - constructor = mref.getName().equals("<init>"); if (constructor) { - /* use class name instead of method name */ - System.out.println(IN2 + "<constructor name=\"" + - classNameOnly(declClassName) + "\" return=\"" + - descriptorToDot(mref.getReturnTypeName()) + "\">"); + // use class name instead of method name + System.out.println(IN3 + "<constructor name=\"" + + classNameOnly(declClassName) + "\">"); } else { - System.out.println(IN2 + "<method name=\"" + mref.getName() + + System.out.println(IN3 + "<method name=\"" + mref.getName() + "\" return=\"" + descriptorToDot(mref.getReturnTypeName()) + "\">"); } String[] args = mref.getArgumentTypeNames(); for (int j = 0; j < args.length; j++) { - System.out.println(IN3 + "<parameter type=\"" + + System.out.println(IN4 + "<parameter type=\"" + descriptorToDot(args[j]) + "\"/>"); } if (constructor) { - System.out.println(IN2 + "</constructor>"); + System.out.println(IN3 + "</constructor>"); } else { - System.out.println(IN2 + "</method>"); + System.out.println(IN3 + "</method>"); } } - - if (prevClass != null) - System.out.println(IN1 + "</class>"); - System.out.println(IN0 + "</external>"); } |