7 def SplitSections(buffer):
8 """Spin through the input buffer looking for section header lines.
9 When found, the name of the section is extracted. The entire contents
10 of that section is added to a result hashmap with the section name
15 # capturing section_name
16 headerPattern = re.compile(r'^\s+\|([a-z _]+)\:$', re.MULTILINE)
24 # Look for a section header
25 result = headerPattern.search(buffer, start)
27 # If there are no more, add a section from the last header to EOF
30 sections[sectionName] = buffer[anchor]
33 # Add the lines from the last header, to this one to the sections
34 # map indexed by the section name
36 sections[sectionName] = buffer[anchor:result.start()]
38 sectionName = result.group(1)
44 def FindMethods(section):
45 """Spin through the 'method code index' section and extract all
46 method signatures. When found, they are added to a result list."""
49 # |[abcd] com/example/app/Class.method:(args)return
50 # capturing the method signature
51 methodPattern = re.compile(r'^\s+\|\[\w{4}\] (.*)$', re.MULTILINE)
57 # Look for a method name
58 result = methodPattern.search(section, start)
63 # Add the captured signature to the method list
64 methods.append(result.group(1))
67 def CallsMethod(codes, method):
68 """Spin through all the input method signatures. For each one, return
69 whether or not there is method invokation line in the codes section that
70 lists the method as the target."""
75 # Find the next reference to the method signature
76 match = codes.find(method, start)
81 # Find the beginning of the line the method reference is on
82 startOfLine = codes.rfind("\n", 0, match) + 1
84 # If the word 'invoke' comes between the beginning of the line
85 # and the method reference, then it is a call to that method rather
86 # than the beginning of the code section for that method.
87 if codes.find("invoke", startOfLine, match) is not -1:
90 start = match + len(method)
97 if len(sys.argv) is not 2 or not sys.argv[1].endswith(".jar"):
98 print "Usage:", sys.argv[0], "<filename.jar>"
101 command = 'dx --dex --dump-width=1000 --dump-to=-"" "%s"' % sys.argv[1]
103 pipe = os.popen(command)
105 # Read the whole dump file into memory
107 sections = SplitSections(data)
112 methods = FindMethods(sections['method code index'])
113 codes = sections['codes']
116 print "Dead Methods:"
119 for method in methods:
120 if not CallsMethod(codes, method):
127 if __name__ == '__main__':