xref: /aosp_15_r20/external/cronet/build/android/gyp/lint.py (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1*6777b538SAndroid Build Coastguard Worker#!/usr/bin/env python3
2*6777b538SAndroid Build Coastguard Worker#
3*6777b538SAndroid Build Coastguard Worker# Copyright 2013 The Chromium Authors
4*6777b538SAndroid Build Coastguard Worker# Use of this source code is governed by a BSD-style license that can be
5*6777b538SAndroid Build Coastguard Worker# found in the LICENSE file.
6*6777b538SAndroid Build Coastguard Worker"""Runs Android's lint tool."""
7*6777b538SAndroid Build Coastguard Worker
8*6777b538SAndroid Build Coastguard Workerimport argparse
9*6777b538SAndroid Build Coastguard Workerimport logging
10*6777b538SAndroid Build Coastguard Workerimport os
11*6777b538SAndroid Build Coastguard Workerimport shutil
12*6777b538SAndroid Build Coastguard Workerimport sys
13*6777b538SAndroid Build Coastguard Workerimport time
14*6777b538SAndroid Build Coastguard Workerfrom xml.dom import minidom
15*6777b538SAndroid Build Coastguard Workerfrom xml.etree import ElementTree
16*6777b538SAndroid Build Coastguard Worker
17*6777b538SAndroid Build Coastguard Workerfrom util import build_utils
18*6777b538SAndroid Build Coastguard Workerfrom util import manifest_utils
19*6777b538SAndroid Build Coastguard Workerfrom util import server_utils
20*6777b538SAndroid Build Coastguard Workerimport action_helpers  # build_utils adds //build to sys.path.
21*6777b538SAndroid Build Coastguard Worker
22*6777b538SAndroid Build Coastguard Worker_LINT_MD_URL = 'https://chromium.googlesource.com/chromium/src/+/main/build/android/docs/lint.md'  # pylint: disable=line-too-long
23*6777b538SAndroid Build Coastguard Worker
24*6777b538SAndroid Build Coastguard Worker# These checks are not useful for chromium.
25*6777b538SAndroid Build Coastguard Worker_DISABLED_ALWAYS = [
26*6777b538SAndroid Build Coastguard Worker    "AppCompatResource",  # Lint does not correctly detect our appcompat lib.
27*6777b538SAndroid Build Coastguard Worker    "Assert",  # R8 --force-enable-assertions is used to enable java asserts.
28*6777b538SAndroid Build Coastguard Worker    "InflateParams",  # Null is ok when inflating views for dialogs.
29*6777b538SAndroid Build Coastguard Worker    "InlinedApi",  # Constants are copied so they are always available.
30*6777b538SAndroid Build Coastguard Worker    "LintBaseline",  # Don't warn about using baseline.xml files.
31*6777b538SAndroid Build Coastguard Worker    "LintBaselineFixed",  # We dont care if baseline.xml has unused entries.
32*6777b538SAndroid Build Coastguard Worker    "MissingInflatedId",  # False positives https://crbug.com/1394222
33*6777b538SAndroid Build Coastguard Worker    "MissingApplicationIcon",  # False positive for non-production targets.
34*6777b538SAndroid Build Coastguard Worker    "NetworkSecurityConfig",  # Breaks on library certificates b/269783280.
35*6777b538SAndroid Build Coastguard Worker    "ObsoleteLintCustomCheck",  # We have no control over custom lint checks.
36*6777b538SAndroid Build Coastguard Worker    "StringFormatCount",  # Has false-positives.
37*6777b538SAndroid Build Coastguard Worker    "SwitchIntDef",  # Many C++ enums are not used at all in java.
38*6777b538SAndroid Build Coastguard Worker    "Typos",  # Strings are committed in English first and later translated.
39*6777b538SAndroid Build Coastguard Worker    "VisibleForTests",  # Does not recognize "ForTesting" methods.
40*6777b538SAndroid Build Coastguard Worker    "UniqueConstants",  # Chromium enums allow aliases.
41*6777b538SAndroid Build Coastguard Worker    "UnusedAttribute",  # Chromium apks have various minSdkVersion values.
42*6777b538SAndroid Build Coastguard Worker]
43*6777b538SAndroid Build Coastguard Worker
44*6777b538SAndroid Build Coastguard Worker# These checks are not useful for test targets and adds an unnecessary burden
45*6777b538SAndroid Build Coastguard Worker# to suppress them.
46*6777b538SAndroid Build Coastguard Worker_DISABLED_FOR_TESTS = [
47*6777b538SAndroid Build Coastguard Worker    # We should not require test strings.xml files to explicitly add
48*6777b538SAndroid Build Coastguard Worker    # translatable=false since they are not translated and not used in
49*6777b538SAndroid Build Coastguard Worker    # production.
50*6777b538SAndroid Build Coastguard Worker    "MissingTranslation",
51*6777b538SAndroid Build Coastguard Worker    # Test strings.xml files often have simple names and are not translatable,
52*6777b538SAndroid Build Coastguard Worker    # so it may conflict with a production string and cause this error.
53*6777b538SAndroid Build Coastguard Worker    "Untranslatable",
54*6777b538SAndroid Build Coastguard Worker    # Test targets often use the same strings target and resources target as the
55*6777b538SAndroid Build Coastguard Worker    # production targets but may not use all of them.
56*6777b538SAndroid Build Coastguard Worker    "UnusedResources",
57*6777b538SAndroid Build Coastguard Worker    # TODO(wnwen): Turn this back on since to crash it would require running on
58*6777b538SAndroid Build Coastguard Worker    #     a device with all the various minSdkVersions.
59*6777b538SAndroid Build Coastguard Worker    # Real NewApi violations crash the app, so the only ones that lint catches
60*6777b538SAndroid Build Coastguard Worker    # but tests still succeed are false positives.
61*6777b538SAndroid Build Coastguard Worker    "NewApi",
62*6777b538SAndroid Build Coastguard Worker    # Tests should be allowed to access these methods/classes.
63*6777b538SAndroid Build Coastguard Worker    "VisibleForTests",
64*6777b538SAndroid Build Coastguard Worker]
65*6777b538SAndroid Build Coastguard Worker
66*6777b538SAndroid Build Coastguard Worker_RES_ZIP_DIR = 'RESZIPS'
67*6777b538SAndroid Build Coastguard Worker_SRCJAR_DIR = 'SRCJARS'
68*6777b538SAndroid Build Coastguard Worker_AAR_DIR = 'AARS'
69*6777b538SAndroid Build Coastguard Worker
70*6777b538SAndroid Build Coastguard Worker
71*6777b538SAndroid Build Coastguard Workerdef _SrcRelative(path):
72*6777b538SAndroid Build Coastguard Worker  """Returns relative path to top-level src dir."""
73*6777b538SAndroid Build Coastguard Worker  return os.path.relpath(path, build_utils.DIR_SOURCE_ROOT)
74*6777b538SAndroid Build Coastguard Worker
75*6777b538SAndroid Build Coastguard Worker
76*6777b538SAndroid Build Coastguard Workerdef _GenerateProjectFile(android_manifest,
77*6777b538SAndroid Build Coastguard Worker                         android_sdk_root,
78*6777b538SAndroid Build Coastguard Worker                         cache_dir,
79*6777b538SAndroid Build Coastguard Worker                         partials_dir,
80*6777b538SAndroid Build Coastguard Worker                         sources=None,
81*6777b538SAndroid Build Coastguard Worker                         classpath=None,
82*6777b538SAndroid Build Coastguard Worker                         srcjar_sources=None,
83*6777b538SAndroid Build Coastguard Worker                         resource_sources=None,
84*6777b538SAndroid Build Coastguard Worker                         custom_lint_jars=None,
85*6777b538SAndroid Build Coastguard Worker                         custom_annotation_zips=None,
86*6777b538SAndroid Build Coastguard Worker                         android_sdk_version=None,
87*6777b538SAndroid Build Coastguard Worker                         baseline_path=None):
88*6777b538SAndroid Build Coastguard Worker  project = ElementTree.Element('project')
89*6777b538SAndroid Build Coastguard Worker  root = ElementTree.SubElement(project, 'root')
90*6777b538SAndroid Build Coastguard Worker  # Run lint from output directory: crbug.com/1115594
91*6777b538SAndroid Build Coastguard Worker  root.set('dir', os.getcwd())
92*6777b538SAndroid Build Coastguard Worker  sdk = ElementTree.SubElement(project, 'sdk')
93*6777b538SAndroid Build Coastguard Worker  # Lint requires that the sdk path be an absolute path.
94*6777b538SAndroid Build Coastguard Worker  sdk.set('dir', os.path.abspath(android_sdk_root))
95*6777b538SAndroid Build Coastguard Worker  if baseline_path is not None:
96*6777b538SAndroid Build Coastguard Worker    baseline = ElementTree.SubElement(project, 'baseline')
97*6777b538SAndroid Build Coastguard Worker    baseline.set('file', baseline_path)
98*6777b538SAndroid Build Coastguard Worker  cache = ElementTree.SubElement(project, 'cache')
99*6777b538SAndroid Build Coastguard Worker  cache.set('dir', cache_dir)
100*6777b538SAndroid Build Coastguard Worker  main_module = ElementTree.SubElement(project, 'module')
101*6777b538SAndroid Build Coastguard Worker  main_module.set('name', 'main')
102*6777b538SAndroid Build Coastguard Worker  main_module.set('android', 'true')
103*6777b538SAndroid Build Coastguard Worker  main_module.set('library', 'false')
104*6777b538SAndroid Build Coastguard Worker  # Required to make lint-resources.xml be written to a per-target path.
105*6777b538SAndroid Build Coastguard Worker  # https://crbug.com/1515070 and b/324598620
106*6777b538SAndroid Build Coastguard Worker  main_module.set('partial-results-dir', partials_dir)
107*6777b538SAndroid Build Coastguard Worker  if android_sdk_version:
108*6777b538SAndroid Build Coastguard Worker    main_module.set('compile_sdk_version', android_sdk_version)
109*6777b538SAndroid Build Coastguard Worker  manifest = ElementTree.SubElement(main_module, 'manifest')
110*6777b538SAndroid Build Coastguard Worker  manifest.set('file', android_manifest)
111*6777b538SAndroid Build Coastguard Worker  if srcjar_sources:
112*6777b538SAndroid Build Coastguard Worker    for srcjar_file in srcjar_sources:
113*6777b538SAndroid Build Coastguard Worker      src = ElementTree.SubElement(main_module, 'src')
114*6777b538SAndroid Build Coastguard Worker      src.set('file', srcjar_file)
115*6777b538SAndroid Build Coastguard Worker      # Cannot add generated="true" since then lint does not scan them, and
116*6777b538SAndroid Build Coastguard Worker      # we get "UnusedResources" lint errors when resources are used only by
117*6777b538SAndroid Build Coastguard Worker      # generated files.
118*6777b538SAndroid Build Coastguard Worker  if sources:
119*6777b538SAndroid Build Coastguard Worker    for source in sources:
120*6777b538SAndroid Build Coastguard Worker      src = ElementTree.SubElement(main_module, 'src')
121*6777b538SAndroid Build Coastguard Worker      src.set('file', source)
122*6777b538SAndroid Build Coastguard Worker      # Cannot set test="true" since we sometimes put Test.java files beside
123*6777b538SAndroid Build Coastguard Worker      # non-test files, which lint does not allow:
124*6777b538SAndroid Build Coastguard Worker      # "Test sources cannot be in the same source root as production files"
125*6777b538SAndroid Build Coastguard Worker  if classpath:
126*6777b538SAndroid Build Coastguard Worker    for file_path in classpath:
127*6777b538SAndroid Build Coastguard Worker      classpath_element = ElementTree.SubElement(main_module, 'classpath')
128*6777b538SAndroid Build Coastguard Worker      classpath_element.set('file', file_path)
129*6777b538SAndroid Build Coastguard Worker  if resource_sources:
130*6777b538SAndroid Build Coastguard Worker    for resource_file in resource_sources:
131*6777b538SAndroid Build Coastguard Worker      resource = ElementTree.SubElement(main_module, 'resource')
132*6777b538SAndroid Build Coastguard Worker      resource.set('file', resource_file)
133*6777b538SAndroid Build Coastguard Worker  if custom_lint_jars:
134*6777b538SAndroid Build Coastguard Worker    for lint_jar in custom_lint_jars:
135*6777b538SAndroid Build Coastguard Worker      lint = ElementTree.SubElement(main_module, 'lint-checks')
136*6777b538SAndroid Build Coastguard Worker      lint.set('file', lint_jar)
137*6777b538SAndroid Build Coastguard Worker  if custom_annotation_zips:
138*6777b538SAndroid Build Coastguard Worker    for annotation_zip in custom_annotation_zips:
139*6777b538SAndroid Build Coastguard Worker      annotation = ElementTree.SubElement(main_module, 'annotations')
140*6777b538SAndroid Build Coastguard Worker      annotation.set('file', annotation_zip)
141*6777b538SAndroid Build Coastguard Worker  return project
142*6777b538SAndroid Build Coastguard Worker
143*6777b538SAndroid Build Coastguard Worker
144*6777b538SAndroid Build Coastguard Workerdef _RetrieveBackportedMethods(backported_methods_path):
145*6777b538SAndroid Build Coastguard Worker  with open(backported_methods_path) as f:
146*6777b538SAndroid Build Coastguard Worker    methods = f.read().splitlines()
147*6777b538SAndroid Build Coastguard Worker  # Methods look like:
148*6777b538SAndroid Build Coastguard Worker  #   java/util/Set#of(Ljava/lang/Object;)Ljava/util/Set;
149*6777b538SAndroid Build Coastguard Worker  # But error message looks like:
150*6777b538SAndroid Build Coastguard Worker  #   Call requires API level R (current min is 21): java.util.Set#of [NewApi]
151*6777b538SAndroid Build Coastguard Worker  methods = (m.replace('/', '\\.') for m in methods)
152*6777b538SAndroid Build Coastguard Worker  methods = (m[:m.index('(')] for m in methods)
153*6777b538SAndroid Build Coastguard Worker  return sorted(set(methods))
154*6777b538SAndroid Build Coastguard Worker
155*6777b538SAndroid Build Coastguard Worker
156*6777b538SAndroid Build Coastguard Workerdef _GenerateConfigXmlTree(orig_config_path, backported_methods):
157*6777b538SAndroid Build Coastguard Worker  if orig_config_path:
158*6777b538SAndroid Build Coastguard Worker    root_node = ElementTree.parse(orig_config_path).getroot()
159*6777b538SAndroid Build Coastguard Worker  else:
160*6777b538SAndroid Build Coastguard Worker    root_node = ElementTree.fromstring('<lint/>')
161*6777b538SAndroid Build Coastguard Worker
162*6777b538SAndroid Build Coastguard Worker  issue_node = ElementTree.SubElement(root_node, 'issue')
163*6777b538SAndroid Build Coastguard Worker  issue_node.attrib['id'] = 'NewApi'
164*6777b538SAndroid Build Coastguard Worker  ignore_node = ElementTree.SubElement(issue_node, 'ignore')
165*6777b538SAndroid Build Coastguard Worker  ignore_node.attrib['regexp'] = '|'.join(backported_methods)
166*6777b538SAndroid Build Coastguard Worker  return root_node
167*6777b538SAndroid Build Coastguard Worker
168*6777b538SAndroid Build Coastguard Worker
169*6777b538SAndroid Build Coastguard Workerdef _GenerateAndroidManifest(original_manifest_path, extra_manifest_paths,
170*6777b538SAndroid Build Coastguard Worker                             min_sdk_version, android_sdk_version):
171*6777b538SAndroid Build Coastguard Worker  # Set minSdkVersion in the manifest to the correct value.
172*6777b538SAndroid Build Coastguard Worker  doc, manifest, app_node = manifest_utils.ParseManifest(original_manifest_path)
173*6777b538SAndroid Build Coastguard Worker
174*6777b538SAndroid Build Coastguard Worker  # TODO(crbug.com/1126301): Should this be done using manifest merging?
175*6777b538SAndroid Build Coastguard Worker  # Add anything in the application node of the extra manifests to the main
176*6777b538SAndroid Build Coastguard Worker  # manifest to prevent unused resource errors.
177*6777b538SAndroid Build Coastguard Worker  for path in extra_manifest_paths:
178*6777b538SAndroid Build Coastguard Worker    _, _, extra_app_node = manifest_utils.ParseManifest(path)
179*6777b538SAndroid Build Coastguard Worker    for node in extra_app_node:
180*6777b538SAndroid Build Coastguard Worker      app_node.append(node)
181*6777b538SAndroid Build Coastguard Worker
182*6777b538SAndroid Build Coastguard Worker  uses_sdk = manifest.find('./uses-sdk')
183*6777b538SAndroid Build Coastguard Worker  if uses_sdk is None:
184*6777b538SAndroid Build Coastguard Worker    uses_sdk = ElementTree.Element('uses-sdk')
185*6777b538SAndroid Build Coastguard Worker    manifest.insert(0, uses_sdk)
186*6777b538SAndroid Build Coastguard Worker  uses_sdk.set('{%s}minSdkVersion' % manifest_utils.ANDROID_NAMESPACE,
187*6777b538SAndroid Build Coastguard Worker               min_sdk_version)
188*6777b538SAndroid Build Coastguard Worker  uses_sdk.set('{%s}targetSdkVersion' % manifest_utils.ANDROID_NAMESPACE,
189*6777b538SAndroid Build Coastguard Worker               android_sdk_version)
190*6777b538SAndroid Build Coastguard Worker  return doc
191*6777b538SAndroid Build Coastguard Worker
192*6777b538SAndroid Build Coastguard Worker
193*6777b538SAndroid Build Coastguard Workerdef _WriteXmlFile(root, path):
194*6777b538SAndroid Build Coastguard Worker  logging.info('Writing xml file %s', path)
195*6777b538SAndroid Build Coastguard Worker  build_utils.MakeDirectory(os.path.dirname(path))
196*6777b538SAndroid Build Coastguard Worker  with action_helpers.atomic_output(path) as f:
197*6777b538SAndroid Build Coastguard Worker    # Although we can write it just with ElementTree.tostring, using minidom
198*6777b538SAndroid Build Coastguard Worker    # makes it a lot easier to read as a human (also on code search).
199*6777b538SAndroid Build Coastguard Worker    f.write(
200*6777b538SAndroid Build Coastguard Worker        minidom.parseString(ElementTree.tostring(
201*6777b538SAndroid Build Coastguard Worker            root, encoding='utf-8')).toprettyxml(indent='  ').encode('utf-8'))
202*6777b538SAndroid Build Coastguard Worker
203*6777b538SAndroid Build Coastguard Worker
204*6777b538SAndroid Build Coastguard Workerdef _RunLint(custom_lint_jar_path,
205*6777b538SAndroid Build Coastguard Worker             lint_jar_path,
206*6777b538SAndroid Build Coastguard Worker             backported_methods_path,
207*6777b538SAndroid Build Coastguard Worker             config_path,
208*6777b538SAndroid Build Coastguard Worker             manifest_path,
209*6777b538SAndroid Build Coastguard Worker             extra_manifest_paths,
210*6777b538SAndroid Build Coastguard Worker             sources,
211*6777b538SAndroid Build Coastguard Worker             classpath,
212*6777b538SAndroid Build Coastguard Worker             cache_dir,
213*6777b538SAndroid Build Coastguard Worker             android_sdk_version,
214*6777b538SAndroid Build Coastguard Worker             aars,
215*6777b538SAndroid Build Coastguard Worker             srcjars,
216*6777b538SAndroid Build Coastguard Worker             min_sdk_version,
217*6777b538SAndroid Build Coastguard Worker             resource_sources,
218*6777b538SAndroid Build Coastguard Worker             resource_zips,
219*6777b538SAndroid Build Coastguard Worker             android_sdk_root,
220*6777b538SAndroid Build Coastguard Worker             lint_gen_dir,
221*6777b538SAndroid Build Coastguard Worker             baseline,
222*6777b538SAndroid Build Coastguard Worker             testonly_target=False,
223*6777b538SAndroid Build Coastguard Worker             warnings_as_errors=False):
224*6777b538SAndroid Build Coastguard Worker  logging.info('Lint starting')
225*6777b538SAndroid Build Coastguard Worker  if not cache_dir:
226*6777b538SAndroid Build Coastguard Worker    # Use per-target cache directory when --cache-dir is not used.
227*6777b538SAndroid Build Coastguard Worker    cache_dir = os.path.join(lint_gen_dir, 'cache')
228*6777b538SAndroid Build Coastguard Worker    # Lint complains if the directory does not exist.
229*6777b538SAndroid Build Coastguard Worker    # When --create-cache is used, ninja will create this directory because the
230*6777b538SAndroid Build Coastguard Worker    # stamp file is created within it.
231*6777b538SAndroid Build Coastguard Worker    os.makedirs(cache_dir, exist_ok=True)
232*6777b538SAndroid Build Coastguard Worker
233*6777b538SAndroid Build Coastguard Worker  if baseline and not os.path.exists(baseline):
234*6777b538SAndroid Build Coastguard Worker    # Generating new baselines is only done locally, and requires more memory to
235*6777b538SAndroid Build Coastguard Worker    # avoid OOMs.
236*6777b538SAndroid Build Coastguard Worker    creating_baseline = True
237*6777b538SAndroid Build Coastguard Worker    lint_xmx = '4G'
238*6777b538SAndroid Build Coastguard Worker  else:
239*6777b538SAndroid Build Coastguard Worker    creating_baseline = False
240*6777b538SAndroid Build Coastguard Worker    lint_xmx = '2G'
241*6777b538SAndroid Build Coastguard Worker
242*6777b538SAndroid Build Coastguard Worker  # Lint requires this directory to exist and be cleared.
243*6777b538SAndroid Build Coastguard Worker  # See b/324598620
244*6777b538SAndroid Build Coastguard Worker  partials_dir = os.path.join(lint_gen_dir, 'partials')
245*6777b538SAndroid Build Coastguard Worker  shutil.rmtree(partials_dir, ignore_errors=True)
246*6777b538SAndroid Build Coastguard Worker  os.makedirs(partials_dir)
247*6777b538SAndroid Build Coastguard Worker
248*6777b538SAndroid Build Coastguard Worker  # All paths in lint are based off of relative paths from root with root as the
249*6777b538SAndroid Build Coastguard Worker  # prefix. Path variable substitution is based off of prefix matching so custom
250*6777b538SAndroid Build Coastguard Worker  # path variables need to match exactly in order to show up in baseline files.
251*6777b538SAndroid Build Coastguard Worker  # e.g. lint_path=path/to/output/dir/../../file/in/src
252*6777b538SAndroid Build Coastguard Worker  root_path = os.getcwd()  # This is usually the output directory.
253*6777b538SAndroid Build Coastguard Worker  pathvar_src = os.path.join(
254*6777b538SAndroid Build Coastguard Worker      root_path, os.path.relpath(build_utils.DIR_SOURCE_ROOT, start=root_path))
255*6777b538SAndroid Build Coastguard Worker
256*6777b538SAndroid Build Coastguard Worker  cmd = build_utils.JavaCmd(xmx=lint_xmx) + [
257*6777b538SAndroid Build Coastguard Worker      '-cp',
258*6777b538SAndroid Build Coastguard Worker      '{}:{}'.format(lint_jar_path, custom_lint_jar_path),
259*6777b538SAndroid Build Coastguard Worker      'org.chromium.build.CustomLint',
260*6777b538SAndroid Build Coastguard Worker      '--sdk-home',
261*6777b538SAndroid Build Coastguard Worker      android_sdk_root,
262*6777b538SAndroid Build Coastguard Worker      '--jdk-home',
263*6777b538SAndroid Build Coastguard Worker      build_utils.JAVA_HOME,
264*6777b538SAndroid Build Coastguard Worker      '--path-variables',
265*6777b538SAndroid Build Coastguard Worker      f'SRC={pathvar_src}',
266*6777b538SAndroid Build Coastguard Worker      '--offline',
267*6777b538SAndroid Build Coastguard Worker      '--quiet',  # Silences lint's "." progress updates.
268*6777b538SAndroid Build Coastguard Worker      '--stacktrace',  # Prints full stacktraces for internal lint errors.
269*6777b538SAndroid Build Coastguard Worker      '--disable',
270*6777b538SAndroid Build Coastguard Worker      ','.join(_DISABLED_ALWAYS),
271*6777b538SAndroid Build Coastguard Worker  ]
272*6777b538SAndroid Build Coastguard Worker
273*6777b538SAndroid Build Coastguard Worker  if testonly_target:
274*6777b538SAndroid Build Coastguard Worker    cmd.extend(['--disable', ','.join(_DISABLED_FOR_TESTS)])
275*6777b538SAndroid Build Coastguard Worker
276*6777b538SAndroid Build Coastguard Worker  if not manifest_path:
277*6777b538SAndroid Build Coastguard Worker    manifest_path = os.path.join(build_utils.DIR_SOURCE_ROOT, 'build',
278*6777b538SAndroid Build Coastguard Worker                                 'android', 'AndroidManifest.xml')
279*6777b538SAndroid Build Coastguard Worker
280*6777b538SAndroid Build Coastguard Worker  logging.info('Generating config.xml')
281*6777b538SAndroid Build Coastguard Worker  backported_methods = _RetrieveBackportedMethods(backported_methods_path)
282*6777b538SAndroid Build Coastguard Worker  config_xml_node = _GenerateConfigXmlTree(config_path, backported_methods)
283*6777b538SAndroid Build Coastguard Worker  generated_config_path = os.path.join(lint_gen_dir, 'config.xml')
284*6777b538SAndroid Build Coastguard Worker  _WriteXmlFile(config_xml_node, generated_config_path)
285*6777b538SAndroid Build Coastguard Worker  cmd.extend(['--config', generated_config_path])
286*6777b538SAndroid Build Coastguard Worker
287*6777b538SAndroid Build Coastguard Worker  logging.info('Generating Android manifest file')
288*6777b538SAndroid Build Coastguard Worker  android_manifest_tree = _GenerateAndroidManifest(manifest_path,
289*6777b538SAndroid Build Coastguard Worker                                                   extra_manifest_paths,
290*6777b538SAndroid Build Coastguard Worker                                                   min_sdk_version,
291*6777b538SAndroid Build Coastguard Worker                                                   android_sdk_version)
292*6777b538SAndroid Build Coastguard Worker  # Just use a hardcoded name, since we may have different target names (and
293*6777b538SAndroid Build Coastguard Worker  # thus different manifest_paths) using the same lint baseline. Eg.
294*6777b538SAndroid Build Coastguard Worker  # trichrome_chrome_bundle and trichrome_chrome_32_64_bundle.
295*6777b538SAndroid Build Coastguard Worker  lint_android_manifest_path = os.path.join(lint_gen_dir, 'AndroidManifest.xml')
296*6777b538SAndroid Build Coastguard Worker  _WriteXmlFile(android_manifest_tree.getroot(), lint_android_manifest_path)
297*6777b538SAndroid Build Coastguard Worker
298*6777b538SAndroid Build Coastguard Worker  resource_root_dir = os.path.join(lint_gen_dir, _RES_ZIP_DIR)
299*6777b538SAndroid Build Coastguard Worker  # These are zip files with generated resources (e. g. strings from GRD).
300*6777b538SAndroid Build Coastguard Worker  logging.info('Extracting resource zips')
301*6777b538SAndroid Build Coastguard Worker  for resource_zip in resource_zips:
302*6777b538SAndroid Build Coastguard Worker    # Use a consistent root and name rather than a temporary file so that
303*6777b538SAndroid Build Coastguard Worker    # suppressions can be local to the lint target and the resource target.
304*6777b538SAndroid Build Coastguard Worker    resource_dir = os.path.join(resource_root_dir, resource_zip)
305*6777b538SAndroid Build Coastguard Worker    shutil.rmtree(resource_dir, True)
306*6777b538SAndroid Build Coastguard Worker    os.makedirs(resource_dir)
307*6777b538SAndroid Build Coastguard Worker    resource_sources.extend(
308*6777b538SAndroid Build Coastguard Worker        build_utils.ExtractAll(resource_zip, path=resource_dir))
309*6777b538SAndroid Build Coastguard Worker
310*6777b538SAndroid Build Coastguard Worker  logging.info('Extracting aars')
311*6777b538SAndroid Build Coastguard Worker  aar_root_dir = os.path.join(lint_gen_dir, _AAR_DIR)
312*6777b538SAndroid Build Coastguard Worker  custom_lint_jars = []
313*6777b538SAndroid Build Coastguard Worker  custom_annotation_zips = []
314*6777b538SAndroid Build Coastguard Worker  if aars:
315*6777b538SAndroid Build Coastguard Worker    for aar in aars:
316*6777b538SAndroid Build Coastguard Worker      # Use relative source for aar files since they are not generated.
317*6777b538SAndroid Build Coastguard Worker      aar_dir = os.path.join(aar_root_dir,
318*6777b538SAndroid Build Coastguard Worker                             os.path.splitext(_SrcRelative(aar))[0])
319*6777b538SAndroid Build Coastguard Worker      shutil.rmtree(aar_dir, True)
320*6777b538SAndroid Build Coastguard Worker      os.makedirs(aar_dir)
321*6777b538SAndroid Build Coastguard Worker      aar_files = build_utils.ExtractAll(aar, path=aar_dir)
322*6777b538SAndroid Build Coastguard Worker      for f in aar_files:
323*6777b538SAndroid Build Coastguard Worker        if f.endswith('lint.jar'):
324*6777b538SAndroid Build Coastguard Worker          custom_lint_jars.append(f)
325*6777b538SAndroid Build Coastguard Worker        elif f.endswith('annotations.zip'):
326*6777b538SAndroid Build Coastguard Worker          custom_annotation_zips.append(f)
327*6777b538SAndroid Build Coastguard Worker
328*6777b538SAndroid Build Coastguard Worker  logging.info('Extracting srcjars')
329*6777b538SAndroid Build Coastguard Worker  srcjar_root_dir = os.path.join(lint_gen_dir, _SRCJAR_DIR)
330*6777b538SAndroid Build Coastguard Worker  srcjar_sources = []
331*6777b538SAndroid Build Coastguard Worker  if srcjars:
332*6777b538SAndroid Build Coastguard Worker    for srcjar in srcjars:
333*6777b538SAndroid Build Coastguard Worker      # Use path without extensions since otherwise the file name includes
334*6777b538SAndroid Build Coastguard Worker      # .srcjar and lint treats it as a srcjar.
335*6777b538SAndroid Build Coastguard Worker      srcjar_dir = os.path.join(srcjar_root_dir, os.path.splitext(srcjar)[0])
336*6777b538SAndroid Build Coastguard Worker      shutil.rmtree(srcjar_dir, True)
337*6777b538SAndroid Build Coastguard Worker      os.makedirs(srcjar_dir)
338*6777b538SAndroid Build Coastguard Worker      # Sadly lint's srcjar support is broken since it only considers the first
339*6777b538SAndroid Build Coastguard Worker      # srcjar. Until we roll a lint version with that fixed, we need to extract
340*6777b538SAndroid Build Coastguard Worker      # it ourselves.
341*6777b538SAndroid Build Coastguard Worker      srcjar_sources.extend(build_utils.ExtractAll(srcjar, path=srcjar_dir))
342*6777b538SAndroid Build Coastguard Worker
343*6777b538SAndroid Build Coastguard Worker  logging.info('Generating project file')
344*6777b538SAndroid Build Coastguard Worker  project_file_root = _GenerateProjectFile(
345*6777b538SAndroid Build Coastguard Worker      lint_android_manifest_path, android_sdk_root, cache_dir, partials_dir,
346*6777b538SAndroid Build Coastguard Worker      sources, classpath, srcjar_sources, resource_sources, custom_lint_jars,
347*6777b538SAndroid Build Coastguard Worker      custom_annotation_zips, android_sdk_version, baseline)
348*6777b538SAndroid Build Coastguard Worker
349*6777b538SAndroid Build Coastguard Worker  project_xml_path = os.path.join(lint_gen_dir, 'project.xml')
350*6777b538SAndroid Build Coastguard Worker  _WriteXmlFile(project_file_root, project_xml_path)
351*6777b538SAndroid Build Coastguard Worker  cmd += ['--project', project_xml_path]
352*6777b538SAndroid Build Coastguard Worker
353*6777b538SAndroid Build Coastguard Worker  # This filter is necessary for JDK11.
354*6777b538SAndroid Build Coastguard Worker  stderr_filter = build_utils.FilterReflectiveAccessJavaWarnings
355*6777b538SAndroid Build Coastguard Worker  stdout_filter = lambda x: build_utils.FilterLines(x, 'No issues found')
356*6777b538SAndroid Build Coastguard Worker
357*6777b538SAndroid Build Coastguard Worker  start = time.time()
358*6777b538SAndroid Build Coastguard Worker  logging.debug('Lint command %s', ' '.join(cmd))
359*6777b538SAndroid Build Coastguard Worker  failed = False
360*6777b538SAndroid Build Coastguard Worker
361*6777b538SAndroid Build Coastguard Worker  if creating_baseline and not warnings_as_errors:
362*6777b538SAndroid Build Coastguard Worker    # Allow error code 6 when creating a baseline: ERRNO_CREATED_BASELINE
363*6777b538SAndroid Build Coastguard Worker    fail_func = lambda returncode, _: returncode not in (0, 6)
364*6777b538SAndroid Build Coastguard Worker  else:
365*6777b538SAndroid Build Coastguard Worker    fail_func = lambda returncode, _: returncode != 0
366*6777b538SAndroid Build Coastguard Worker
367*6777b538SAndroid Build Coastguard Worker  try:
368*6777b538SAndroid Build Coastguard Worker    build_utils.CheckOutput(cmd,
369*6777b538SAndroid Build Coastguard Worker                            print_stdout=True,
370*6777b538SAndroid Build Coastguard Worker                            stdout_filter=stdout_filter,
371*6777b538SAndroid Build Coastguard Worker                            stderr_filter=stderr_filter,
372*6777b538SAndroid Build Coastguard Worker                            fail_on_output=warnings_as_errors,
373*6777b538SAndroid Build Coastguard Worker                            fail_func=fail_func)
374*6777b538SAndroid Build Coastguard Worker  except build_utils.CalledProcessError as e:
375*6777b538SAndroid Build Coastguard Worker    failed = True
376*6777b538SAndroid Build Coastguard Worker    # Do not output the python stacktrace because it is lengthy and is not
377*6777b538SAndroid Build Coastguard Worker    # relevant to the actual lint error.
378*6777b538SAndroid Build Coastguard Worker    sys.stderr.write(e.output)
379*6777b538SAndroid Build Coastguard Worker  finally:
380*6777b538SAndroid Build Coastguard Worker    # When not treating warnings as errors, display the extra footer.
381*6777b538SAndroid Build Coastguard Worker    is_debug = os.environ.get('LINT_DEBUG', '0') != '0'
382*6777b538SAndroid Build Coastguard Worker
383*6777b538SAndroid Build Coastguard Worker    end = time.time() - start
384*6777b538SAndroid Build Coastguard Worker    logging.info('Lint command took %ss', end)
385*6777b538SAndroid Build Coastguard Worker    if not is_debug:
386*6777b538SAndroid Build Coastguard Worker      shutil.rmtree(aar_root_dir, ignore_errors=True)
387*6777b538SAndroid Build Coastguard Worker      shutil.rmtree(resource_root_dir, ignore_errors=True)
388*6777b538SAndroid Build Coastguard Worker      shutil.rmtree(srcjar_root_dir, ignore_errors=True)
389*6777b538SAndroid Build Coastguard Worker      os.unlink(project_xml_path)
390*6777b538SAndroid Build Coastguard Worker      shutil.rmtree(partials_dir, ignore_errors=True)
391*6777b538SAndroid Build Coastguard Worker
392*6777b538SAndroid Build Coastguard Worker    if failed:
393*6777b538SAndroid Build Coastguard Worker      print('- For more help with lint in Chrome:', _LINT_MD_URL)
394*6777b538SAndroid Build Coastguard Worker      if is_debug:
395*6777b538SAndroid Build Coastguard Worker        print('- DEBUG MODE: Here is the project.xml: {}'.format(
396*6777b538SAndroid Build Coastguard Worker            _SrcRelative(project_xml_path)))
397*6777b538SAndroid Build Coastguard Worker      else:
398*6777b538SAndroid Build Coastguard Worker        print('- Run with LINT_DEBUG=1 to enable lint configuration debugging')
399*6777b538SAndroid Build Coastguard Worker      sys.exit(1)
400*6777b538SAndroid Build Coastguard Worker
401*6777b538SAndroid Build Coastguard Worker  logging.info('Lint completed')
402*6777b538SAndroid Build Coastguard Worker
403*6777b538SAndroid Build Coastguard Worker
404*6777b538SAndroid Build Coastguard Workerdef _ParseArgs(argv):
405*6777b538SAndroid Build Coastguard Worker  parser = argparse.ArgumentParser()
406*6777b538SAndroid Build Coastguard Worker  action_helpers.add_depfile_arg(parser)
407*6777b538SAndroid Build Coastguard Worker  parser.add_argument('--target-name', help='Fully qualified GN target name.')
408*6777b538SAndroid Build Coastguard Worker  parser.add_argument('--skip-build-server',
409*6777b538SAndroid Build Coastguard Worker                      action='store_true',
410*6777b538SAndroid Build Coastguard Worker                      help='Avoid using the build server.')
411*6777b538SAndroid Build Coastguard Worker  parser.add_argument('--use-build-server',
412*6777b538SAndroid Build Coastguard Worker                      action='store_true',
413*6777b538SAndroid Build Coastguard Worker                      help='Always use the build server.')
414*6777b538SAndroid Build Coastguard Worker  parser.add_argument('--lint-jar-path',
415*6777b538SAndroid Build Coastguard Worker                      required=True,
416*6777b538SAndroid Build Coastguard Worker                      help='Path to the lint jar.')
417*6777b538SAndroid Build Coastguard Worker  parser.add_argument('--custom-lint-jar-path',
418*6777b538SAndroid Build Coastguard Worker                      required=True,
419*6777b538SAndroid Build Coastguard Worker                      help='Path to our custom lint jar.')
420*6777b538SAndroid Build Coastguard Worker  parser.add_argument('--backported-methods',
421*6777b538SAndroid Build Coastguard Worker                      help='Path to backported methods file created by R8.')
422*6777b538SAndroid Build Coastguard Worker  parser.add_argument('--cache-dir',
423*6777b538SAndroid Build Coastguard Worker                      help='Path to the directory in which the android cache '
424*6777b538SAndroid Build Coastguard Worker                      'directory tree should be stored.')
425*6777b538SAndroid Build Coastguard Worker  parser.add_argument('--config-path', help='Path to lint suppressions file.')
426*6777b538SAndroid Build Coastguard Worker  parser.add_argument('--lint-gen-dir',
427*6777b538SAndroid Build Coastguard Worker                      required=True,
428*6777b538SAndroid Build Coastguard Worker                      help='Path to store generated xml files.')
429*6777b538SAndroid Build Coastguard Worker  parser.add_argument('--stamp', help='Path to stamp upon success.')
430*6777b538SAndroid Build Coastguard Worker  parser.add_argument('--android-sdk-version',
431*6777b538SAndroid Build Coastguard Worker                      help='Version (API level) of the Android SDK used for '
432*6777b538SAndroid Build Coastguard Worker                      'building.')
433*6777b538SAndroid Build Coastguard Worker  parser.add_argument('--min-sdk-version',
434*6777b538SAndroid Build Coastguard Worker                      required=True,
435*6777b538SAndroid Build Coastguard Worker                      help='Minimal SDK version to lint against.')
436*6777b538SAndroid Build Coastguard Worker  parser.add_argument('--android-sdk-root',
437*6777b538SAndroid Build Coastguard Worker                      required=True,
438*6777b538SAndroid Build Coastguard Worker                      help='Lint needs an explicit path to the android sdk.')
439*6777b538SAndroid Build Coastguard Worker  parser.add_argument('--testonly',
440*6777b538SAndroid Build Coastguard Worker                      action='store_true',
441*6777b538SAndroid Build Coastguard Worker                      help='If set, some checks like UnusedResources will be '
442*6777b538SAndroid Build Coastguard Worker                      'disabled since they are not helpful for test '
443*6777b538SAndroid Build Coastguard Worker                      'targets.')
444*6777b538SAndroid Build Coastguard Worker  parser.add_argument('--create-cache',
445*6777b538SAndroid Build Coastguard Worker                      action='store_true',
446*6777b538SAndroid Build Coastguard Worker                      help='Whether this invocation is just warming the cache.')
447*6777b538SAndroid Build Coastguard Worker  parser.add_argument('--warnings-as-errors',
448*6777b538SAndroid Build Coastguard Worker                      action='store_true',
449*6777b538SAndroid Build Coastguard Worker                      help='Treat all warnings as errors.')
450*6777b538SAndroid Build Coastguard Worker  parser.add_argument('--sources',
451*6777b538SAndroid Build Coastguard Worker                      help='A list of files containing java and kotlin source '
452*6777b538SAndroid Build Coastguard Worker                      'files.')
453*6777b538SAndroid Build Coastguard Worker  parser.add_argument('--aars', help='GN list of included aars.')
454*6777b538SAndroid Build Coastguard Worker  parser.add_argument('--srcjars', help='GN list of included srcjars.')
455*6777b538SAndroid Build Coastguard Worker  parser.add_argument('--manifest-path',
456*6777b538SAndroid Build Coastguard Worker                      help='Path to original AndroidManifest.xml')
457*6777b538SAndroid Build Coastguard Worker  parser.add_argument('--extra-manifest-paths',
458*6777b538SAndroid Build Coastguard Worker                      action='append',
459*6777b538SAndroid Build Coastguard Worker                      help='GYP-list of manifest paths to merge into the '
460*6777b538SAndroid Build Coastguard Worker                      'original AndroidManifest.xml')
461*6777b538SAndroid Build Coastguard Worker  parser.add_argument('--resource-sources',
462*6777b538SAndroid Build Coastguard Worker                      default=[],
463*6777b538SAndroid Build Coastguard Worker                      action='append',
464*6777b538SAndroid Build Coastguard Worker                      help='GYP-list of resource sources files, similar to '
465*6777b538SAndroid Build Coastguard Worker                      'java sources files, but for resource files.')
466*6777b538SAndroid Build Coastguard Worker  parser.add_argument('--resource-zips',
467*6777b538SAndroid Build Coastguard Worker                      default=[],
468*6777b538SAndroid Build Coastguard Worker                      action='append',
469*6777b538SAndroid Build Coastguard Worker                      help='GYP-list of resource zips, zip files of generated '
470*6777b538SAndroid Build Coastguard Worker                      'resource files.')
471*6777b538SAndroid Build Coastguard Worker  parser.add_argument('--classpath',
472*6777b538SAndroid Build Coastguard Worker                      help='List of jars to add to the classpath.')
473*6777b538SAndroid Build Coastguard Worker  parser.add_argument('--baseline',
474*6777b538SAndroid Build Coastguard Worker                      help='Baseline file to ignore existing errors and fail '
475*6777b538SAndroid Build Coastguard Worker                      'on new errors.')
476*6777b538SAndroid Build Coastguard Worker
477*6777b538SAndroid Build Coastguard Worker  args = parser.parse_args(build_utils.ExpandFileArgs(argv))
478*6777b538SAndroid Build Coastguard Worker  args.sources = action_helpers.parse_gn_list(args.sources)
479*6777b538SAndroid Build Coastguard Worker  args.aars = action_helpers.parse_gn_list(args.aars)
480*6777b538SAndroid Build Coastguard Worker  args.srcjars = action_helpers.parse_gn_list(args.srcjars)
481*6777b538SAndroid Build Coastguard Worker  args.resource_sources = action_helpers.parse_gn_list(args.resource_sources)
482*6777b538SAndroid Build Coastguard Worker  args.extra_manifest_paths = action_helpers.parse_gn_list(
483*6777b538SAndroid Build Coastguard Worker      args.extra_manifest_paths)
484*6777b538SAndroid Build Coastguard Worker  args.resource_zips = action_helpers.parse_gn_list(args.resource_zips)
485*6777b538SAndroid Build Coastguard Worker  args.classpath = action_helpers.parse_gn_list(args.classpath)
486*6777b538SAndroid Build Coastguard Worker
487*6777b538SAndroid Build Coastguard Worker  if args.baseline:
488*6777b538SAndroid Build Coastguard Worker    assert os.path.basename(args.baseline) == 'lint-baseline.xml', (
489*6777b538SAndroid Build Coastguard Worker        'The baseline file needs to be named "lint-baseline.xml" in order for '
490*6777b538SAndroid Build Coastguard Worker        'the autoroller to find and update it whenever lint is rolled to a new '
491*6777b538SAndroid Build Coastguard Worker        'version.')
492*6777b538SAndroid Build Coastguard Worker
493*6777b538SAndroid Build Coastguard Worker  return args
494*6777b538SAndroid Build Coastguard Worker
495*6777b538SAndroid Build Coastguard Worker
496*6777b538SAndroid Build Coastguard Workerdef main():
497*6777b538SAndroid Build Coastguard Worker  build_utils.InitLogging('LINT_DEBUG')
498*6777b538SAndroid Build Coastguard Worker  args = _ParseArgs(sys.argv[1:])
499*6777b538SAndroid Build Coastguard Worker
500*6777b538SAndroid Build Coastguard Worker  # TODO(wnwen): Consider removing lint cache now that there are only two lint
501*6777b538SAndroid Build Coastguard Worker  #              invocations.
502*6777b538SAndroid Build Coastguard Worker  # Avoid parallelizing cache creation since lint runs without the cache defeat
503*6777b538SAndroid Build Coastguard Worker  # the purpose of creating the cache in the first place.
504*6777b538SAndroid Build Coastguard Worker  if (not args.create_cache and not args.skip_build_server
505*6777b538SAndroid Build Coastguard Worker      and server_utils.MaybeRunCommand(name=args.target_name,
506*6777b538SAndroid Build Coastguard Worker                                       argv=sys.argv,
507*6777b538SAndroid Build Coastguard Worker                                       stamp_file=args.stamp,
508*6777b538SAndroid Build Coastguard Worker                                       force=args.use_build_server)):
509*6777b538SAndroid Build Coastguard Worker    return
510*6777b538SAndroid Build Coastguard Worker
511*6777b538SAndroid Build Coastguard Worker  sources = []
512*6777b538SAndroid Build Coastguard Worker  for sources_file in args.sources:
513*6777b538SAndroid Build Coastguard Worker    sources.extend(build_utils.ReadSourcesList(sources_file))
514*6777b538SAndroid Build Coastguard Worker  resource_sources = []
515*6777b538SAndroid Build Coastguard Worker  for resource_sources_file in args.resource_sources:
516*6777b538SAndroid Build Coastguard Worker    resource_sources.extend(build_utils.ReadSourcesList(resource_sources_file))
517*6777b538SAndroid Build Coastguard Worker
518*6777b538SAndroid Build Coastguard Worker  possible_depfile_deps = (args.srcjars + args.resource_zips + sources +
519*6777b538SAndroid Build Coastguard Worker                           resource_sources + [
520*6777b538SAndroid Build Coastguard Worker                               args.baseline,
521*6777b538SAndroid Build Coastguard Worker                               args.manifest_path,
522*6777b538SAndroid Build Coastguard Worker                           ])
523*6777b538SAndroid Build Coastguard Worker  depfile_deps = [p for p in possible_depfile_deps if p]
524*6777b538SAndroid Build Coastguard Worker
525*6777b538SAndroid Build Coastguard Worker  _RunLint(args.custom_lint_jar_path,
526*6777b538SAndroid Build Coastguard Worker           args.lint_jar_path,
527*6777b538SAndroid Build Coastguard Worker           args.backported_methods,
528*6777b538SAndroid Build Coastguard Worker           args.config_path,
529*6777b538SAndroid Build Coastguard Worker           args.manifest_path,
530*6777b538SAndroid Build Coastguard Worker           args.extra_manifest_paths,
531*6777b538SAndroid Build Coastguard Worker           sources,
532*6777b538SAndroid Build Coastguard Worker           args.classpath,
533*6777b538SAndroid Build Coastguard Worker           args.cache_dir,
534*6777b538SAndroid Build Coastguard Worker           args.android_sdk_version,
535*6777b538SAndroid Build Coastguard Worker           args.aars,
536*6777b538SAndroid Build Coastguard Worker           args.srcjars,
537*6777b538SAndroid Build Coastguard Worker           args.min_sdk_version,
538*6777b538SAndroid Build Coastguard Worker           resource_sources,
539*6777b538SAndroid Build Coastguard Worker           args.resource_zips,
540*6777b538SAndroid Build Coastguard Worker           args.android_sdk_root,
541*6777b538SAndroid Build Coastguard Worker           args.lint_gen_dir,
542*6777b538SAndroid Build Coastguard Worker           args.baseline,
543*6777b538SAndroid Build Coastguard Worker           testonly_target=args.testonly,
544*6777b538SAndroid Build Coastguard Worker           warnings_as_errors=args.warnings_as_errors)
545*6777b538SAndroid Build Coastguard Worker  logging.info('Creating stamp file')
546*6777b538SAndroid Build Coastguard Worker  build_utils.Touch(args.stamp)
547*6777b538SAndroid Build Coastguard Worker
548*6777b538SAndroid Build Coastguard Worker  if args.depfile:
549*6777b538SAndroid Build Coastguard Worker    action_helpers.write_depfile(args.depfile, args.stamp, depfile_deps)
550*6777b538SAndroid Build Coastguard Worker
551*6777b538SAndroid Build Coastguard Worker
552*6777b538SAndroid Build Coastguard Workerif __name__ == '__main__':
553*6777b538SAndroid Build Coastguard Worker  sys.exit(main())
554