Files
build_soong/scripts/check_boot_jars/check_boot_jars.py
Paul Duffin cd4f673ceb Switch boot jars package check to use dexdump xml output
The xml output from dexdump is more stable than the text output so this
change switches to use that.

Bug: 171479578
Test: m check-boot-jars - for failing and passing cases
Change-Id: Ie347b1b685951524d5ae09db280248c61b4228ee
2020-11-16 17:46:16 +00:00

102 lines
2.8 KiB
Python
Executable File

#!/usr/bin/env python
"""
Check boot jars.
Usage: check_boot_jars.py <dexdump_path> <package_allow_list_file> <jar1> <jar2> ...
"""
import logging
import os.path
import re
import subprocess
import sys
import xml.etree.ElementTree
# The compiled allow list RE.
allow_list_re = None
def LoadAllowList(filename):
""" Load and compile allow list regular expressions from filename.
"""
lines = []
with open(filename, 'r') as f:
for line in f:
line = line.strip()
if not line or line.startswith('#'):
continue
lines.append(line)
combined_re = r'^(%s)$' % '|'.join(lines)
global allow_list_re
try:
allow_list_re = re.compile(combined_re)
except re.error:
logging.exception(
'Cannot compile package allow list regular expression: %r',
combined_re)
allow_list_re = None
return False
return True
def CheckDexJar(dexdump_path, allow_list_path, jar):
"""Check a dex jar file.
"""
# Use dexdump to generate the XML representation of the dex jar file.
p = subprocess.Popen(args='%s -l xml %s' % (dexdump_path, jar),
stdout=subprocess.PIPE, shell=True)
stdout, _ = p.communicate()
if p.returncode != 0:
return False
packages = 0
try:
# TODO(b/172063475) - improve performance
root = xml.etree.ElementTree.fromstring(stdout)
except xml.etree.ElementTree.ParseError as e:
print >> sys.stderr, 'Error processing jar %s - %s' % (jar, e)
print >> sys.stderr, stdout
return False
for package_elt in root.iterfind('package'):
packages += 1
package_name = package_elt.get('name')
if not package_name or not allow_list_re.match(package_name):
# Report the name of a class in the package as it is easier to navigate to
# the source of a concrete class than to a package which is often required
# to investigate this failure.
class_name = package_elt[0].get('name')
if package_name != "":
class_name = package_name + "." + class_name
print >> sys.stderr, ('Error: %s contains class file %s, whose package name "%s" is empty or'
' not in the allow list %s of packages allowed on the bootclasspath.'
% (jar, class_name, package_name, allow_list_path))
return False
if packages == 0:
print >> sys.stderr, ('Error: %s does not contain any packages.' % jar)
return False
return True
def main(argv):
if len(argv) < 3:
print __doc__
return 1
dexdump_path = argv[0]
allow_list_path = argv[1]
if not LoadAllowList(allow_list_path):
return 1
passed = True
for jar in argv[2:]:
if not CheckDexJar(dexdump_path, allow_list_path, jar):
passed = False
if not passed:
return 1
return 0
if __name__ == '__main__':
sys.exit(main(sys.argv[1:]))