1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3
4# Copyright (C) 2019 The Android Open Source Project
5#
6# Licensed under the Apache License, Version 2.0 (the "License");
7# you may not use this file except in compliance with the License.
8# You may obtain a copy of the License at
9#
10#      http://www.apache.org/licenses/LICENSE-2.0
11#
12# Unless required by applicable law or agreed to in writing, software
13# distributed under the License is distributed on an "AS IS" BASIS,
14# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15# See the License for the specific language governing permissions and
16# limitations under the License.
17#
18
19import argparse
20import fnmatch
21import logging
22import os
23import os.path
24import subprocess
25import sys
26import zipfile
27
28logging.basicConfig(format='%(message)s')
29
30# Flavors of ART APEX package.
31FLAVOR_RELEASE = 'release'
32FLAVOR_DEBUG = 'debug'
33FLAVOR_TESTING = 'testing'
34FLAVOR_AUTO = 'auto'
35FLAVORS_ALL = [FLAVOR_RELEASE, FLAVOR_DEBUG, FLAVOR_TESTING, FLAVOR_AUTO]
36
37# Bitness options for APEX package
38BITNESS_32 = '32'
39BITNESS_64 = '64'
40BITNESS_MULTILIB = 'multilib'
41BITNESS_AUTO = 'auto'
42BITNESS_ALL = [BITNESS_32, BITNESS_64, BITNESS_MULTILIB, BITNESS_AUTO]
43
44# Architectures supported by APEX packages.
45ARCHS = ["arm", "arm64", "x86", "x86_64"]
46
47# Directory containing ART tests within an ART APEX (if the package includes
48# any). ART test executables are installed in `bin/art/<arch>`. Segregating
49# tests by architecture is useful on devices supporting more than one
50# architecture, as it permits testing all of them using a single ART APEX
51# package.
52ART_TEST_DIR = 'bin/art'
53
54
55# Test if a given variable is set to a string "true".
56def isEnvTrue(var):
57  return var in os.environ and os.environ[var] == 'true'
58
59
60class FSObject:
61  def __init__(self, name, is_dir, is_exec, is_symlink, size):
62    self.name = name
63    self.is_dir = is_dir
64    self.is_exec = is_exec
65    self.is_symlink = is_symlink
66    self.size = size
67
68  def __str__(self):
69    return '%s(dir=%r,exec=%r,symlink=%r,size=%d)' \
70             % (self.name, self.is_dir, self.is_exec, self.is_symlink, self.size)
71
72
73class TargetApexProvider:
74  def __init__(self, apex, tmpdir, debugfs):
75    self._tmpdir = tmpdir
76    self._debugfs = debugfs
77    self._folder_cache = {}
78    self._payload = os.path.join(self._tmpdir, 'apex_payload.img')
79    # Extract payload to tmpdir.
80    apex_zip = zipfile.ZipFile(apex)
81    apex_zip.extract('apex_payload.img', tmpdir)
82
83  def __del__(self):
84    # Delete temps.
85    if os.path.exists(self._payload):
86      os.remove(self._payload)
87
88  def get(self, path):
89    apex_dir, name = os.path.split(path)
90    if not apex_dir:
91      apex_dir = '.'
92    apex_map = self.read_dir(apex_dir)
93    return apex_map[name] if name in apex_map else None
94
95  def read_dir(self, apex_dir):
96    if apex_dir in self._folder_cache:
97      return self._folder_cache[apex_dir]
98    # Cannot use check_output as it will annoy with stderr.
99    process = subprocess.Popen([self._debugfs, '-R', 'ls -l -p %s' % apex_dir, self._payload],
100                               stdout=subprocess.PIPE, stderr=subprocess.PIPE,
101                               universal_newlines=True)
102    stdout, _ = process.communicate()
103    res = str(stdout)
104    apex_map = {}
105    # Debugfs output looks like this:
106    #   debugfs 1.44.4 (18-Aug-2018)
107    #   /12/040755/0/2000/.//
108    #   /2/040755/1000/1000/..//
109    #   /13/100755/0/2000/dalvikvm32/28456/
110    #   /14/100755/0/2000/dexoptanalyzer/20396/
111    #   /15/100755/0/2000/linker/1152724/
112    #   /16/100755/0/2000/dex2oat/563508/
113    #   /17/100755/0/2000/linker64/1605424/
114    #   /18/100755/0/2000/profman/85304/
115    #   /19/100755/0/2000/dalvikvm64/28576/
116    #    |     |   |   |       |        |
117    #    |     |   |   #- gid  #- name  #- size
118    #    |     |   #- uid
119    #    |     #- type and permission bits
120    #    #- inode nr (?)
121    #
122    # Note: could break just on '/' to avoid names with newlines.
123    for line in res.split("\n"):
124      if not line:
125        continue
126      comps = line.split('/')
127      if len(comps) != 8:
128        logging.warning('Could not break and parse line \'%s\'', line)
129        continue
130      bits = comps[2]
131      name = comps[5]
132      size_str = comps[6]
133      # Use a negative value as an indicator of undefined/unknown size.
134      size = int(size_str) if size_str != '' else -1
135      if len(bits) != 6:
136        logging.warning('Dont understand bits \'%s\'', bits)
137        continue
138      is_dir = bits[1] == '4'
139
140      def is_exec_bit(ch):
141        return int(ch) & 1 == 1
142
143      is_exec = is_exec_bit(bits[3]) and is_exec_bit(bits[4]) and is_exec_bit(bits[5])
144      is_symlink = bits[1] == '2'
145      apex_map[name] = FSObject(name, is_dir, is_exec, is_symlink, size)
146    self._folder_cache[apex_dir] = apex_map
147    return apex_map
148
149
150class TargetFlattenedApexProvider:
151  def __init__(self, apex):
152    self._folder_cache = {}
153    self._apex = apex
154
155  def get(self, path):
156    apex_dir, name = os.path.split(path)
157    if not apex_dir:
158      apex_dir = '.'
159    apex_map = self.read_dir(apex_dir)
160    return apex_map[name] if name in apex_map else None
161
162  def read_dir(self, apex_dir):
163    if apex_dir in self._folder_cache:
164      return self._folder_cache[apex_dir]
165    apex_map = {}
166    dirname = os.path.join(self._apex, apex_dir)
167    if os.path.exists(dirname):
168      for basename in os.listdir(dirname):
169        filepath = os.path.join(dirname, basename)
170        is_dir = os.path.isdir(filepath)
171        is_exec = os.access(filepath, os.X_OK)
172        is_symlink = os.path.islink(filepath)
173        if is_symlink:
174          # Report the length of the symlink's target's path as file size, like `ls`.
175          size = len(os.readlink(filepath))
176        else:
177          size = os.path.getsize(filepath)
178        apex_map[basename] = FSObject(basename, is_dir, is_exec, is_symlink, size)
179    self._folder_cache[apex_dir] = apex_map
180    return apex_map
181
182
183class HostApexProvider:
184  def __init__(self, apex, tmpdir):
185    self._tmpdir = tmpdir
186    self._folder_cache = {}
187    self._payload = os.path.join(self._tmpdir, 'apex_payload.zip')
188    # Extract payload to tmpdir.
189    apex_zip = zipfile.ZipFile(apex)
190    apex_zip.extract('apex_payload.zip', tmpdir)
191
192  def __del__(self):
193    # Delete temps.
194    if os.path.exists(self._payload):
195      os.remove(self._payload)
196
197  def get(self, path):
198    apex_dir, name = os.path.split(path)
199    if not apex_dir:
200      apex_dir = ''
201    apex_map = self.read_dir(apex_dir)
202    return apex_map[name] if name in apex_map else None
203
204  def read_dir(self, apex_dir):
205    if apex_dir in self._folder_cache:
206      return self._folder_cache[apex_dir]
207    if not self._folder_cache:
208      self.parse_zip()
209    if apex_dir in self._folder_cache:
210      return self._folder_cache[apex_dir]
211    return {}
212
213  def parse_zip(self):
214    apex_zip = zipfile.ZipFile(self._payload)
215    infos = apex_zip.infolist()
216    for zipinfo in infos:
217      path = zipinfo.filename
218
219      # Assume no empty file is stored.
220      assert path
221
222      def get_octal(val, index):
223        return (val >> (index * 3)) & 0x7
224
225      def bits_is_exec(val):
226        # TODO: Enforce group/other, too?
227        return get_octal(val, 2) & 1 == 1
228
229      is_zipinfo = True
230      while path:
231        apex_dir, base = os.path.split(path)
232        # TODO: If directories are stored, base will be empty.
233
234        if apex_dir not in self._folder_cache:
235          self._folder_cache[apex_dir] = {}
236        dir_map = self._folder_cache[apex_dir]
237        if base not in dir_map:
238          if is_zipinfo:
239            bits = (zipinfo.external_attr >> 16) & 0xFFFF
240            is_dir = get_octal(bits, 4) == 4
241            is_symlink = get_octal(bits, 4) == 2
242            is_exec = bits_is_exec(bits)
243            size = zipinfo.file_size
244          else:
245            is_exec = False  # Seems we can't get this easily?
246            is_symlink = False
247            is_dir = True
248            # Use a negative value as an indicator of undefined/unknown size.
249            size = -1
250          dir_map[base] = FSObject(base, is_dir, is_exec, is_symlink, size)
251        is_zipinfo = False
252        path = apex_dir
253
254
255# DO NOT USE DIRECTLY! This is an "abstract" base class.
256class Checker:
257  def __init__(self, provider):
258    self._provider = provider
259    self._errors = 0
260    self._expected_file_globs = set()
261
262  def fail(self, msg, *fail_args):
263    self._errors += 1
264    logging.error(msg, *fail_args)
265
266  def error_count(self):
267    return self._errors
268
269  def reset_errors(self):
270    self._errors = 0
271
272  def is_file(self, path):
273    fs_object = self._provider.get(path)
274    if fs_object is None:
275      return False, 'Could not find %s'
276    if fs_object.is_dir:
277      return False, '%s is a directory'
278    return True, ''
279
280  def is_dir(self, path):
281    fs_object = self._provider.get(path)
282    if fs_object is None:
283      return False, 'Could not find %s'
284    if not fs_object.is_dir:
285      return False, '%s is not a directory'
286    return True, ''
287
288  def check_file(self, path):
289    ok, msg = self.is_file(path)
290    if not ok:
291      self.fail(msg, path)
292    self._expected_file_globs.add(path)
293    return ok
294
295  def check_executable(self, filename):
296    path = 'bin/%s' % filename
297    if not self.check_file(path):
298      return
299    if not self._provider.get(path).is_exec:
300      self.fail('%s is not executable', path)
301
302  def check_executable_symlink(self, filename):
303    path = 'bin/%s' % filename
304    fs_object = self._provider.get(path)
305    if fs_object is None:
306      self.fail('Could not find %s', path)
307      return
308    if fs_object.is_dir:
309      self.fail('%s is a directory', path)
310      return
311    if not fs_object.is_symlink:
312      self.fail('%s is not a symlink', path)
313    self._expected_file_globs.add(path)
314
315  def arch_dirs_for_path(self, path):
316    # Look for target-specific subdirectories for the given directory path.
317    # This is needed because the list of build targets is not propagated
318    # to this script.
319    #
320    # TODO(b/123602136): Pass build target information to this script and fix
321    # all places where this function in used (or similar workarounds).
322    dirs = []
323    for arch in ARCHS:
324      dir = '%s/%s' % (path, arch)
325      found, _ = self.is_dir(dir)
326      if found:
327        dirs.append(dir)
328    return dirs
329
330  def check_art_test_executable(self, filename):
331    dirs = self.arch_dirs_for_path(ART_TEST_DIR)
332    if not dirs:
333      self.fail('ART test binary missing: %s', filename)
334    for dir in dirs:
335      test_path = '%s/%s' % (dir, filename)
336      self._expected_file_globs.add(test_path)
337      if not self._provider.get(test_path).is_exec:
338        self.fail('%s is not executable', test_path)
339
340  def check_single_library(self, filename):
341    lib_path = 'lib/%s' % filename
342    lib64_path = 'lib64/%s' % filename
343    lib_is_file, _ = self.is_file(lib_path)
344    if lib_is_file:
345      self._expected_file_globs.add(lib_path)
346    lib64_is_file, _ = self.is_file(lib64_path)
347    if lib64_is_file:
348      self._expected_file_globs.add(lib64_path)
349    if not lib_is_file and not lib64_is_file:
350      self.fail('Library missing: %s', filename)
351
352  def check_dexpreopt(self, basename):
353    dirs = self.arch_dirs_for_path('javalib')
354    for dir in dirs:
355      for ext in ['art', 'oat', 'vdex']:
356        self.check_file('%s/%s.%s' % (dir, basename, ext))
357
358  def check_java_library(self, basename):
359    return self.check_file('javalib/%s.jar' % basename)
360
361  def ignore_path(self, path_glob):
362    self._expected_file_globs.add(path_glob)
363
364  def check_optional_art_test_executable(self, filename):
365    for arch in ARCHS:
366      self.ignore_path('%s/%s/%s' % (ART_TEST_DIR, arch, filename))
367
368  def check_no_superfluous_files(self, dir_path):
369    paths = []
370    for name in sorted(self._provider.read_dir(dir_path).keys()):
371      if name not in ('.', '..'):
372        paths.append(os.path.join(dir_path, name))
373    expected_paths = set()
374    dir_prefix = dir_path + '/'
375    for path_glob in self._expected_file_globs:
376      expected_paths |= set(fnmatch.filter(paths, path_glob))
377      # If there are globs in subdirectories of dir_path we want to match their
378      # path segments at this directory level.
379      if path_glob.startswith(dir_prefix):
380        subpath = path_glob[len(dir_prefix):]
381        subpath_first_segment, _, _ = subpath.partition('/')
382        expected_paths |= set(fnmatch.filter(paths, dir_prefix + subpath_first_segment))
383    for unexpected_path in set(paths) - expected_paths:
384      self.fail('Unexpected file \'%s\'', unexpected_path)
385
386  # Just here for docs purposes, even if it isn't good Python style.
387
388  def check_symlinked_multilib_executable(self, filename):
389    """Check bin/filename32, and/or bin/filename64, with symlink bin/filename."""
390    raise NotImplementedError
391
392  def check_symlinked_first_executable(self, filename):
393    """Check bin/filename32, and/or bin/filename64, with symlink bin/filename."""
394    raise NotImplementedError
395
396  def check_multilib_executable(self, filename):
397    """Check bin/filename for 32 bit, and/or bin/filename64."""
398    raise NotImplementedError
399
400  def check_first_executable(self, filename):
401    """Check bin/filename for 32 bit, and/or bin/filename64."""
402    raise NotImplementedError
403
404  def check_native_library(self, basename):
405    """Check lib/basename.so, and/or lib64/basename.so."""
406    raise NotImplementedError
407
408  def check_optional_native_library(self, basename_glob):
409    """Allow lib/basename.so and/or lib64/basename.so to exist."""
410    raise NotImplementedError
411
412  def check_prefer64_library(self, basename):
413    """Check lib64/basename.so, or lib/basename.so on 32 bit only."""
414    raise NotImplementedError
415
416
417class Arch32Checker(Checker):
418  def check_symlinked_multilib_executable(self, filename):
419    self.check_executable('%s32' % filename)
420    self.check_executable_symlink(filename)
421
422  def check_symlinked_first_executable(self, filename):
423    self.check_executable('%s32' % filename)
424    self.check_executable_symlink(filename)
425
426  def check_multilib_executable(self, filename):
427    self.check_executable('%s32' % filename)
428
429  def check_first_executable(self, filename):
430    self.check_executable('%s32' % filename)
431
432  def check_native_library(self, basename):
433    # TODO: Use $TARGET_ARCH (e.g. check whether it is "arm" or "arm64") to improve
434    # the precision of this test?
435    self.check_file('lib/%s.so' % basename)
436
437  def check_optional_native_library(self, basename_glob):
438    self.ignore_path('lib/%s.so' % basename_glob)
439
440  def check_prefer64_library(self, basename):
441    self.check_native_library(basename)
442
443
444class Arch64Checker(Checker):
445  def check_symlinked_multilib_executable(self, filename):
446    self.check_executable('%s64' % filename)
447    self.check_executable_symlink(filename)
448
449  def check_symlinked_first_executable(self, filename):
450    self.check_executable('%s64' % filename)
451    self.check_executable_symlink(filename)
452
453  def check_multilib_executable(self, filename):
454    self.check_executable('%s64' % filename)
455
456  def check_first_executable(self, filename):
457    self.check_executable('%s64' % filename)
458
459  def check_native_library(self, basename):
460    # TODO: Use $TARGET_ARCH (e.g. check whether it is "arm" or "arm64") to improve
461    # the precision of this test?
462    self.check_file('lib64/%s.so' % basename)
463
464  def check_optional_native_library(self, basename_glob):
465    self.ignore_path('lib64/%s.so' % basename_glob)
466
467  def check_prefer64_library(self, basename):
468    self.check_native_library(basename)
469
470
471class MultilibChecker(Checker):
472  def check_symlinked_multilib_executable(self, filename):
473    self.check_executable('%s32' % filename)
474    self.check_executable('%s64' % filename)
475    self.check_executable_symlink(filename)
476
477  def check_symlinked_first_executable(self, filename):
478    self.check_executable('%s64' % filename)
479    self.check_executable_symlink(filename)
480
481  def check_multilib_executable(self, filename):
482    self.check_executable('%s64' % filename)
483    self.check_executable('%s32' % filename)
484
485  def check_first_executable(self, filename):
486    self.check_executable('%s64' % filename)
487
488  def check_native_library(self, basename):
489    # TODO: Use $TARGET_ARCH (e.g. check whether it is "arm" or "arm64") to improve
490    # the precision of this test?
491    self.check_file('lib/%s.so' % basename)
492    self.check_file('lib64/%s.so' % basename)
493
494  def check_optional_native_library(self, basename_glob):
495    self.ignore_path('lib/%s.so' % basename_glob)
496    self.ignore_path('lib64/%s.so' % basename_glob)
497
498  def check_prefer64_library(self, basename):
499    self.check_file('lib64/%s.so' % basename)
500
501
502class ReleaseChecker:
503  def __init__(self, checker):
504    self._checker = checker
505
506  def __str__(self):
507    return 'Release Checker'
508
509  def run(self):
510    # Check the Protocol Buffers APEX manifest.
511    self._checker.check_file('apex_manifest.pb')
512
513    # Check binaries for ART.
514    self._checker.check_first_executable('dex2oat')
515    self._checker.check_executable('dexdump')
516    self._checker.check_executable('dexlist')
517    self._checker.check_executable('dexoptanalyzer')
518    self._checker.check_executable('profman')
519    self._checker.check_symlinked_multilib_executable('dalvikvm')
520
521    # Check exported libraries for ART.
522    self._checker.check_native_library('libdexfile_external')
523    self._checker.check_native_library('libnativebridge')
524    self._checker.check_native_library('libnativehelper')
525    self._checker.check_native_library('libnativeloader')
526
527    # Check internal libraries for ART.
528    self._checker.check_native_library('libadbconnection')
529    self._checker.check_native_library('libart')
530    self._checker.check_native_library('libart-compiler')
531    self._checker.check_native_library('libart-dexlayout')
532    self._checker.check_native_library('libart-disassembler')
533    self._checker.check_native_library('libartbase')
534    self._checker.check_native_library('libartpalette')
535    self._checker.check_native_library('libdexfile')
536    self._checker.check_native_library('libdexfile_support')
537    self._checker.check_native_library('libopenjdkjvm')
538    self._checker.check_native_library('libopenjdkjvmti')
539    self._checker.check_native_library('libprofile')
540    self._checker.check_native_library('libsigchain')
541
542    # Check java libraries for Managed Core Library.
543    self._checker.check_java_library('apache-xml')
544    self._checker.check_java_library('bouncycastle')
545    self._checker.check_java_library('core-icu4j')
546    self._checker.check_java_library('core-libart')
547    self._checker.check_java_library('core-oj')
548    self._checker.check_java_library('okhttp')
549    if isEnvTrue('EMMA_INSTRUMENT_FRAMEWORK'):
550      # In coverage builds jacoco is added to the list of ART apex jars.
551      self._checker.check_java_library('jacocoagent')
552
553    # Check internal native libraries for Managed Core Library.
554    self._checker.check_native_library('libjavacore')
555    self._checker.check_native_library('libopenjdk')
556
557    # Check internal native library dependencies.
558    #
559    # Any internal dependency not listed here will cause a failure in
560    # NoSuperfluousLibrariesChecker. Internal dependencies are generally just
561    # implementation details, but in the release package we want to track them
562    # because a) they add to the package size and the RAM usage (in particular
563    # if the library is also present in /system or another APEX and hence might
564    # get loaded twice through linker namespace separation), and b) we need to
565    # catch invalid dependencies on /system or other APEXes that should go
566    # through an exported library with stubs (b/128708192 tracks implementing a
567    # better approach for that).
568    self._checker.check_native_library('libbacktrace')
569    self._checker.check_native_library('libbase')
570    self._checker.check_native_library('libc++')
571    self._checker.check_native_library('libdt_fd_forward')
572    self._checker.check_native_library('libdt_socket')
573    self._checker.check_native_library('libjdwp')
574    self._checker.check_native_library('liblzma')
575    self._checker.check_native_library('libnpt')
576    self._checker.check_native_library('libunwindstack')
577    self._checker.check_native_library('libziparchive')
578    self._checker.check_optional_native_library('libvixl')  # Only on ARM/ARM64
579
580    # Allow extra dependencies that appear in ASAN builds.
581    self._checker.check_optional_native_library('libclang_rt.asan*')
582    self._checker.check_optional_native_library('libclang_rt.hwasan*')
583    self._checker.check_optional_native_library('libclang_rt.ubsan*')
584
585    # Check dexpreopt files for libcore bootclasspath jars.
586    self._checker.check_dexpreopt('boot')
587    self._checker.check_dexpreopt('boot-apache-xml')
588    self._checker.check_dexpreopt('boot-bouncycastle')
589    self._checker.check_dexpreopt('boot-core-icu4j')
590    self._checker.check_dexpreopt('boot-core-libart')
591    self._checker.check_dexpreopt('boot-okhttp')
592    if isEnvTrue('EMMA_INSTRUMENT_FRAMEWORK'):
593      # In coverage builds the ART boot image includes jacoco.
594      self._checker.check_dexpreopt('boot-jacocoagent')
595
596class ReleaseTargetChecker:
597  def __init__(self, checker):
598    self._checker = checker
599
600  def __str__(self):
601    return 'Release (Target) Checker'
602
603  def run(self):
604    # We don't check for the presence of the JSON APEX manifest (file
605    # `apex_manifest.json`, only present in target APEXes), as it is only
606    # included for compatibility reasons with Android Q and will likely be
607    # removed in Android R.
608
609    # Check binaries for ART.
610    self._checker.check_executable('oatdump')
611    self._checker.check_multilib_executable('dex2oat')
612
613    # Check internal libraries for ART.
614    self._checker.check_prefer64_library('libart-disassembler')
615    self._checker.check_native_library('libperfetto_hprof')
616
617    # Check exported native libraries for Managed Core Library.
618    self._checker.check_native_library('libandroidicu')
619    self._checker.check_native_library('libandroidio')
620
621    # Check internal native library dependencies.
622    self._checker.check_native_library('libcrypto')
623    self._checker.check_native_library('libexpat')
624    self._checker.check_native_library('libicui18n')
625    self._checker.check_native_library('libicuuc')
626    self._checker.check_native_library('libicu_jni')
627    self._checker.check_native_library('libpac')
628    self._checker.check_native_library('libz')
629
630    # TODO(b/139046641): Fix proper 2nd arch checks. For now, just ignore these
631    # directories.
632    self._checker.ignore_path('bin/arm')
633    self._checker.ignore_path('lib/arm')
634    self._checker.ignore_path('lib64/arm')
635
636
637class ReleaseHostChecker:
638  def __init__(self, checker):
639    self._checker = checker
640
641  def __str__(self):
642    return 'Release (Host) Checker'
643
644  def run(self):
645    # Check binaries for ART.
646    self._checker.check_executable('hprof-conv')
647    self._checker.check_symlinked_first_executable('dex2oatd')
648    self._checker.check_symlinked_first_executable('dex2oat')
649
650    # Check exported native libraries for Managed Core Library.
651    self._checker.check_native_library('libandroidicu-host')
652    self._checker.check_native_library('libandroidio')
653
654    # Check internal libraries for Managed Core Library.
655    self._checker.check_native_library('libexpat-host')
656    self._checker.check_native_library('libicui18n-host')
657    self._checker.check_native_library('libicuuc-host')
658    self._checker.check_native_library('libicu_jni')
659    self._checker.check_native_library('libz-host')
660
661
662class DebugChecker:
663  def __init__(self, checker):
664    self._checker = checker
665
666  def __str__(self):
667    return 'Debug Checker'
668
669  def run(self):
670    # Check binaries for ART.
671    self._checker.check_executable('dexdiag')
672    self._checker.check_executable('dexanalyze')
673    self._checker.check_executable('dexlayout')
674    self._checker.check_symlinked_multilib_executable('imgdiag')
675
676    # Check debug binaries for ART.
677    self._checker.check_executable('dexlayoutd')
678    self._checker.check_executable('dexoptanalyzerd')
679    self._checker.check_symlinked_multilib_executable('imgdiagd')
680    self._checker.check_executable('profmand')
681
682    # Check internal libraries for ART.
683    self._checker.check_native_library('libadbconnectiond')
684    self._checker.check_native_library('libart-disassembler')
685    self._checker.check_native_library('libartbased')
686    self._checker.check_native_library('libartd')
687    self._checker.check_native_library('libartd-compiler')
688    self._checker.check_native_library('libartd-dexlayout')
689    self._checker.check_native_library('libartd-disassembler')
690    self._checker.check_native_library('libdexfiled')
691    self._checker.check_native_library('libopenjdkjvmd')
692    self._checker.check_native_library('libopenjdkjvmtid')
693    self._checker.check_native_library('libprofiled')
694
695    # Check internal libraries for Managed Core Library.
696    self._checker.check_native_library('libopenjdkd')
697
698
699class DebugTargetChecker:
700  def __init__(self, checker):
701    self._checker = checker
702
703  def __str__(self):
704    return 'Debug (Target) Checker'
705
706  def run(self):
707    # Check ART debug binaries.
708    self._checker.check_multilib_executable('dex2oatd')
709    self._checker.check_multilib_executable('dex2oat')
710    self._checker.check_executable('oatdumpd')
711
712    # Check ART internal libraries.
713    self._checker.check_native_library('libdexfiled_external')
714    self._checker.check_native_library('libperfetto_hprofd')
715
716    # Check internal native library dependencies.
717    #
718    # Like in the release package, we check that we don't get other dependencies
719    # besides those listed here. In this case the concern is not bloat, but
720    # rather that we don't get behavioural differences between user (release)
721    # and userdebug/eng builds, which could happen if the debug package has
722    # duplicate library instances where releases don't. In other words, it's
723    # uncontroversial to add debug-only dependencies, as long as they don't make
724    # assumptions on having a single global state (ideally they should have
725    # double_loadable:true, cf. go/double_loadable). Also, like in the release
726    # package we need to look out for dependencies that should go through
727    # exported library stubs (until b/128708192 is fixed).
728    self._checker.check_optional_native_library('libvixld')  # Only on ARM/ARM64
729    self._checker.check_prefer64_library('libmeminfo')
730    self._checker.check_prefer64_library('libprocinfo')
731
732
733class TestingTargetChecker:
734  def __init__(self, checker):
735    self._checker = checker
736
737  def __str__(self):
738    return 'Testing (Target) Checker'
739
740  def run(self):
741    # Check cmdline tests.
742    self._checker.check_optional_art_test_executable('cmdline_parser_test')
743
744    # Check compiler tests.
745    self._checker.check_art_test_executable('atomic_dex_ref_map_test')
746    self._checker.check_art_test_executable('bounds_check_elimination_test')
747    self._checker.check_art_test_executable('codegen_test')
748    self._checker.check_art_test_executable('compiled_method_storage_test')
749    self._checker.check_art_test_executable('data_type_test')
750    self._checker.check_art_test_executable('dedupe_set_test')
751    self._checker.check_art_test_executable('dominator_test')
752    self._checker.check_art_test_executable('dwarf_test')
753    self._checker.check_art_test_executable('exception_test')
754    self._checker.check_art_test_executable('find_loops_test')
755    self._checker.check_art_test_executable('graph_checker_test')
756    self._checker.check_art_test_executable('graph_test')
757    self._checker.check_art_test_executable('gvn_test')
758    self._checker.check_art_test_executable('induction_var_analysis_test')
759    self._checker.check_art_test_executable('induction_var_range_test')
760    self._checker.check_art_test_executable('jni_cfi_test')
761    self._checker.check_art_test_executable('jni_compiler_test')
762    self._checker.check_art_test_executable('licm_test')
763    self._checker.check_art_test_executable('linker_patch_test')
764    self._checker.check_art_test_executable('live_interval_test')
765    self._checker.check_art_test_executable('load_store_analysis_test')
766    self._checker.check_art_test_executable('load_store_elimination_test')
767    self._checker.check_art_test_executable('loop_optimization_test')
768    self._checker.check_art_test_executable('nodes_test')
769    self._checker.check_art_test_executable('nodes_vector_test')
770    self._checker.check_art_test_executable('optimizing_cfi_test')
771    self._checker.check_art_test_executable('output_stream_test')
772    self._checker.check_art_test_executable('parallel_move_test')
773    self._checker.check_art_test_executable('pretty_printer_test')
774    self._checker.check_art_test_executable('reference_type_propagation_test')
775    self._checker.check_art_test_executable('scheduler_test')
776    self._checker.check_art_test_executable('select_generator_test')
777    self._checker.check_art_test_executable('side_effects_test')
778    self._checker.check_art_test_executable('src_map_elem_test')
779    self._checker.check_art_test_executable('ssa_liveness_analysis_test')
780    self._checker.check_art_test_executable('ssa_test')
781    self._checker.check_art_test_executable('stack_map_test')
782    self._checker.check_art_test_executable('superblock_cloner_test')
783    self._checker.check_art_test_executable('suspend_check_test')
784    self._checker.check_art_test_executable('swap_space_test')
785    # These tests depend on a specific code generator and are conditionally included.
786    self._checker.check_optional_art_test_executable('constant_folding_test')
787    self._checker.check_optional_art_test_executable('dead_code_elimination_test')
788    self._checker.check_optional_art_test_executable('linearize_test')
789    self._checker.check_optional_art_test_executable('live_ranges_test')
790    self._checker.check_optional_art_test_executable('liveness_test')
791    self._checker.check_optional_art_test_executable('managed_register_arm64_test')
792    self._checker.check_optional_art_test_executable('managed_register_arm_test')
793    self._checker.check_optional_art_test_executable('managed_register_x86_64_test')
794    self._checker.check_optional_art_test_executable('managed_register_x86_test')
795    self._checker.check_optional_art_test_executable('register_allocator_test')
796
797    # Check dex2oat tests.
798    self._checker.check_art_test_executable('compiler_driver_test')
799    self._checker.check_art_test_executable('dex2oat_image_test')
800    self._checker.check_art_test_executable('dex2oat_test')
801    self._checker.check_art_test_executable('dex_to_dex_decompiler_test')
802    self._checker.check_art_test_executable('elf_writer_test')
803    self._checker.check_art_test_executable('image_test')
804    self._checker.check_art_test_executable('image_write_read_test')
805    self._checker.check_art_test_executable('index_bss_mapping_encoder_test')
806    self._checker.check_art_test_executable('multi_oat_relative_patcher_test')
807    self._checker.check_art_test_executable('oat_writer_test')
808    self._checker.check_art_test_executable('verifier_deps_test')
809    # These tests depend on a specific code generator and are conditionally included.
810    self._checker.check_optional_art_test_executable('relative_patcher_arm64_test')
811    self._checker.check_optional_art_test_executable('relative_patcher_thumb2_test')
812    self._checker.check_optional_art_test_executable('relative_patcher_x86_64_test')
813    self._checker.check_optional_art_test_executable('relative_patcher_x86_test')
814
815    # Check dexanalyze tests.
816    self._checker.check_optional_art_test_executable('dexanalyze_test')
817
818    # Check dexdiag tests.
819    self._checker.check_optional_art_test_executable('dexdiag_test')
820
821    # Check dexdump tests.
822    self._checker.check_art_test_executable('dexdump_test')
823
824    # Check dexlayout tests.
825    self._checker.check_optional_art_test_executable('dexlayout_test')
826
827    # Check dexlist tests.
828    self._checker.check_art_test_executable('dexlist_test')
829
830    # Check dexoptanalyzer tests.
831    self._checker.check_art_test_executable('dexoptanalyzer_test')
832
833    # Check imgdiag tests.
834    self._checker.check_art_test_executable('imgdiag_test')
835
836    # Check libartbase tests.
837    self._checker.check_art_test_executable('arena_allocator_test')
838    self._checker.check_art_test_executable('bit_field_test')
839    self._checker.check_art_test_executable('bit_memory_region_test')
840    self._checker.check_art_test_executable('bit_string_test')
841    self._checker.check_art_test_executable('bit_struct_test')
842    self._checker.check_art_test_executable('bit_table_test')
843    self._checker.check_art_test_executable('bit_utils_test')
844    self._checker.check_art_test_executable('bit_vector_test')
845    self._checker.check_art_test_executable('fd_file_test')
846    self._checker.check_art_test_executable('file_utils_test')
847    self._checker.check_art_test_executable('hash_set_test')
848    self._checker.check_art_test_executable('hex_dump_test')
849    self._checker.check_art_test_executable('histogram_test')
850    self._checker.check_art_test_executable('indenter_test')
851    self._checker.check_art_test_executable('instruction_set_test')
852    self._checker.check_art_test_executable('intrusive_forward_list_test')
853    self._checker.check_art_test_executable('leb128_test')
854    self._checker.check_art_test_executable('logging_test')
855    self._checker.check_art_test_executable('mem_map_test')
856    self._checker.check_art_test_executable('membarrier_test')
857    self._checker.check_art_test_executable('memfd_test')
858    self._checker.check_art_test_executable('memory_region_test')
859    self._checker.check_art_test_executable('safe_copy_test')
860    self._checker.check_art_test_executable('scoped_flock_test')
861    self._checker.check_art_test_executable('time_utils_test')
862    self._checker.check_art_test_executable('transform_array_ref_test')
863    self._checker.check_art_test_executable('transform_iterator_test')
864    self._checker.check_art_test_executable('utils_test')
865    self._checker.check_art_test_executable('variant_map_test')
866    self._checker.check_art_test_executable('zip_archive_test')
867
868    # Check libartpalette tests.
869    self._checker.check_art_test_executable('palette_test')
870
871    # Check libdexfile tests.
872    self._checker.check_art_test_executable('art_dex_file_loader_test')
873    self._checker.check_art_test_executable('art_libdexfile_support_tests')
874    self._checker.check_art_test_executable('class_accessor_test')
875    self._checker.check_art_test_executable('code_item_accessors_test')
876    self._checker.check_art_test_executable('compact_dex_file_test')
877    self._checker.check_art_test_executable('compact_offset_table_test')
878    self._checker.check_art_test_executable('descriptors_names_test')
879    self._checker.check_art_test_executable('dex_file_loader_test')
880    self._checker.check_art_test_executable('dex_file_verifier_test')
881    self._checker.check_art_test_executable('dex_instruction_test')
882    self._checker.check_art_test_executable('primitive_test')
883    self._checker.check_art_test_executable('string_reference_test')
884    self._checker.check_art_test_executable('test_dex_file_builder_test')
885    self._checker.check_art_test_executable('type_lookup_table_test')
886    self._checker.check_art_test_executable('utf_test')
887
888    # Check libprofile tests.
889    self._checker.check_optional_art_test_executable('profile_boot_info_test')
890    self._checker.check_optional_art_test_executable('profile_compilation_info_test')
891
892    # Check oatdump tests.
893    self._checker.check_art_test_executable('oatdump_app_test')
894    self._checker.check_art_test_executable('oatdump_image_test')
895    self._checker.check_art_test_executable('oatdump_test')
896
897    # Check profman tests.
898    self._checker.check_art_test_executable('profile_assistant_test')
899
900    # Check runtime compiler tests.
901    self._checker.check_art_test_executable('module_exclusion_test')
902    self._checker.check_art_test_executable('reflection_test')
903
904    # Check runtime tests.
905    self._checker.check_art_test_executable('arch_test')
906    self._checker.check_art_test_executable('barrier_test')
907    self._checker.check_art_test_executable('card_table_test')
908    self._checker.check_art_test_executable('cha_test')
909    self._checker.check_art_test_executable('class_linker_test')
910    self._checker.check_art_test_executable('class_loader_context_test')
911    self._checker.check_art_test_executable('class_table_test')
912    self._checker.check_art_test_executable('compiler_filter_test')
913    self._checker.check_art_test_executable('dex_cache_test')
914    self._checker.check_art_test_executable('dlmalloc_space_random_test')
915    self._checker.check_art_test_executable('dlmalloc_space_static_test')
916    self._checker.check_art_test_executable('entrypoints_order_test')
917    self._checker.check_art_test_executable('exec_utils_test')
918    self._checker.check_art_test_executable('gtest_test')
919    self._checker.check_art_test_executable('handle_scope_test')
920    self._checker.check_art_test_executable('heap_test')
921    self._checker.check_art_test_executable('heap_verification_test')
922    self._checker.check_art_test_executable('hidden_api_test')
923    self._checker.check_art_test_executable('image_space_test')
924    self._checker.check_art_test_executable('immune_spaces_test')
925    self._checker.check_art_test_executable('imtable_test')
926    self._checker.check_art_test_executable('indirect_reference_table_test')
927    self._checker.check_art_test_executable('instruction_set_features_arm64_test')
928    self._checker.check_art_test_executable('instruction_set_features_arm_test')
929    self._checker.check_art_test_executable('instruction_set_features_test')
930    self._checker.check_art_test_executable('instruction_set_features_x86_64_test')
931    self._checker.check_art_test_executable('instruction_set_features_x86_test')
932    self._checker.check_art_test_executable('instrumentation_test')
933    self._checker.check_art_test_executable('intern_table_test')
934    self._checker.check_art_test_executable('java_vm_ext_test')
935    self._checker.check_art_test_executable('jit_memory_region_test')
936    self._checker.check_art_test_executable('jni_internal_test')
937    self._checker.check_art_test_executable('large_object_space_test')
938    self._checker.check_art_test_executable('math_entrypoints_test')
939    self._checker.check_art_test_executable('memcmp16_test')
940    self._checker.check_art_test_executable('method_handles_test')
941    self._checker.check_art_test_executable('method_type_test')
942    self._checker.check_art_test_executable('method_verifier_test')
943    self._checker.check_art_test_executable('mod_union_table_test')
944    self._checker.check_art_test_executable('monitor_pool_test')
945    self._checker.check_art_test_executable('monitor_test')
946    self._checker.check_art_test_executable('mutex_test')
947    self._checker.check_art_test_executable('oat_file_assistant_test')
948    self._checker.check_art_test_executable('oat_file_test')
949    self._checker.check_art_test_executable('object_test')
950    self._checker.check_art_test_executable('parsed_options_test')
951    self._checker.check_art_test_executable('prebuilt_tools_test')
952    self._checker.check_art_test_executable('profiling_info_test')
953    self._checker.check_art_test_executable('profile_saver_test')
954    self._checker.check_art_test_executable('proxy_test')
955    self._checker.check_art_test_executable('quick_trampoline_entrypoints_test')
956    self._checker.check_art_test_executable('reference_queue_test')
957    self._checker.check_art_test_executable('reference_table_test')
958    self._checker.check_art_test_executable('reg_type_test')
959    self._checker.check_art_test_executable('rosalloc_space_random_test')
960    self._checker.check_art_test_executable('rosalloc_space_static_test')
961    self._checker.check_art_test_executable('runtime_callbacks_test')
962    self._checker.check_art_test_executable('runtime_test')
963    self._checker.check_art_test_executable('safe_math_test')
964    self._checker.check_art_test_executable('space_bitmap_test')
965    self._checker.check_art_test_executable('space_create_test')
966    self._checker.check_art_test_executable('stub_test')
967    self._checker.check_art_test_executable('subtype_check_info_test')
968    self._checker.check_art_test_executable('subtype_check_test')
969    self._checker.check_art_test_executable('system_weak_test')
970    self._checker.check_art_test_executable('task_processor_test')
971    self._checker.check_art_test_executable('thread_pool_test')
972    self._checker.check_art_test_executable('timing_logger_test')
973    self._checker.check_art_test_executable('transaction_test')
974    self._checker.check_art_test_executable('two_runtimes_test')
975    self._checker.check_art_test_executable('unstarted_runtime_test')
976    self._checker.check_art_test_executable('var_handle_test')
977    self._checker.check_art_test_executable('vdex_file_test')
978
979    # Check sigchainlib tests.
980    self._checker.check_art_test_executable('sigchain_test')
981
982    # Check ART test (internal) libraries.
983    self._checker.check_native_library('libart-gtest')
984    self._checker.check_native_library('libartd-simulator-container')
985
986    # Check ART test tools.
987    self._checker.check_executable('signal_dumper')
988
989
990class NoSuperfluousBinariesChecker:
991  def __init__(self, checker):
992    self._checker = checker
993
994  def __str__(self):
995    return 'No superfluous binaries checker'
996
997  def run(self):
998    self._checker.check_no_superfluous_files('bin')
999
1000
1001class NoSuperfluousLibrariesChecker:
1002  def __init__(self, checker):
1003    self._checker = checker
1004
1005  def __str__(self):
1006    return 'No superfluous libraries checker'
1007
1008  def run(self):
1009    self._checker.check_no_superfluous_files('javalib')
1010    self._checker.check_no_superfluous_files('lib')
1011    self._checker.check_no_superfluous_files('lib64')
1012
1013
1014class NoSuperfluousArtTestsChecker:
1015  def __init__(self, checker):
1016    self._checker = checker
1017
1018  def __str__(self):
1019    return 'No superfluous ART tests checker'
1020
1021  def run(self):
1022    for arch in ARCHS:
1023      self._checker.check_no_superfluous_files('%s/%s' % (ART_TEST_DIR, arch))
1024
1025
1026class List:
1027  def __init__(self, provider, print_size=False):
1028    self._provider = provider
1029    self._print_size = print_size
1030
1031  def print_list(self):
1032
1033    def print_list_rec(path):
1034      apex_map = self._provider.read_dir(path)
1035      if apex_map is None:
1036        return
1037      apex_map = dict(apex_map)
1038      if '.' in apex_map:
1039        del apex_map['.']
1040      if '..' in apex_map:
1041        del apex_map['..']
1042      for (_, val) in sorted(apex_map.items()):
1043        val_path = os.path.join(path, val.name)
1044        if self._print_size:
1045          if val.size < 0:
1046            print('[    n/a    ]  %s' % val_path)
1047          else:
1048            print('[%11d]  %s' % (val.size, val_path))
1049        else:
1050          print(val_path)
1051        if val.is_dir:
1052          print_list_rec(val_path)
1053
1054    print_list_rec('')
1055
1056
1057class Tree:
1058  def __init__(self, provider, title, print_size=False):
1059    print('%s' % title)
1060    self._provider = provider
1061    self._has_next_list = []
1062    self._print_size = print_size
1063
1064  @staticmethod
1065  def get_vertical(has_next_list):
1066    string = ''
1067    for v in has_next_list:
1068      string += '%s   ' % ('│' if v else ' ')
1069    return string
1070
1071  @staticmethod
1072  def get_last_vertical(last):
1073    return '└── ' if last else '├── '
1074
1075  def print_tree(self):
1076
1077    def print_tree_rec(path):
1078      apex_map = self._provider.read_dir(path)
1079      if apex_map is None:
1080        return
1081      apex_map = dict(apex_map)
1082      if '.' in apex_map:
1083        del apex_map['.']
1084      if '..' in apex_map:
1085        del apex_map['..']
1086      key_list = list(sorted(apex_map.keys()))
1087      for i, key in enumerate(key_list):
1088        prev = self.get_vertical(self._has_next_list)
1089        last = self.get_last_vertical(i == len(key_list) - 1)
1090        val = apex_map[key]
1091        if self._print_size:
1092          if val.size < 0:
1093            print('%s%s[    n/a    ]  %s' % (prev, last, val.name))
1094          else:
1095            print('%s%s[%11d]  %s' % (prev, last, val.size, val.name))
1096        else:
1097          print('%s%s%s' % (prev, last, val.name))
1098        if val.is_dir:
1099          self._has_next_list.append(i < len(key_list) - 1)
1100          val_path = os.path.join(path, val.name)
1101          print_tree_rec(val_path)
1102          self._has_next_list.pop()
1103
1104    print_tree_rec('')
1105
1106
1107# Note: do not sys.exit early, for __del__ cleanup.
1108def art_apex_test_main(test_args):
1109  if test_args.host and test_args.flattened:
1110    logging.error("Both of --host and --flattened set")
1111    return 1
1112  if test_args.list and test_args.tree:
1113    logging.error("Both of --list and --tree set")
1114    return 1
1115  if test_args.size and not (test_args.list or test_args.tree):
1116    logging.error("--size set but neither --list nor --tree set")
1117    return 1
1118  if not test_args.flattened and not test_args.tmpdir:
1119    logging.error("Need a tmpdir.")
1120    return 1
1121  if not test_args.flattened and not test_args.host and not test_args.debugfs:
1122    logging.error("Need debugfs.")
1123    return 1
1124
1125  if test_args.host:
1126    # Host APEX.
1127    if test_args.flavor not in [FLAVOR_DEBUG, FLAVOR_AUTO]:
1128      logging.error("Using option --host with non-Debug APEX")
1129      return 1
1130    # Host APEX is always a debug flavor (for now).
1131    test_args.flavor = FLAVOR_DEBUG
1132  else:
1133    # Device APEX.
1134    if test_args.flavor == FLAVOR_AUTO:
1135      logging.warning('--flavor=auto, trying to autodetect. This may be incorrect!')
1136      for flavor in [ FLAVOR_RELEASE, FLAVOR_DEBUG, FLAVOR_TESTING ]:
1137        flavor_pattern = '*.%s*' % flavor
1138        if fnmatch.fnmatch(test_args.apex, flavor_pattern):
1139          test_args.flavor = flavor
1140          break
1141      if test_args.flavor == FLAVOR_AUTO:
1142        logging.error('  Could not detect APEX flavor, neither \'%s\', \'%s\' nor \'%s\' in \'%s\'',
1143                    FLAVOR_RELEASE, FLAVOR_DEBUG, FLAVOR_TESTING, test_args.apex)
1144        return 1
1145
1146  try:
1147    if test_args.host:
1148      apex_provider = HostApexProvider(test_args.apex, test_args.tmpdir)
1149    else:
1150      if test_args.flattened:
1151        apex_provider = TargetFlattenedApexProvider(test_args.apex)
1152      else:
1153        apex_provider = TargetApexProvider(test_args.apex, test_args.tmpdir, test_args.debugfs)
1154  except (zipfile.BadZipFile, zipfile.LargeZipFile) as e:
1155    logging.error('Failed to create provider: %s', e)
1156    return 1
1157
1158  if test_args.tree:
1159    Tree(apex_provider, test_args.apex, test_args.size).print_tree()
1160    return 0
1161  if test_args.list:
1162    List(apex_provider, test_args.size).print_list()
1163    return 0
1164
1165  checkers = []
1166  if test_args.bitness == BITNESS_AUTO:
1167    logging.warning('--bitness=auto, trying to autodetect. This may be incorrect!')
1168    has_32 = apex_provider.get('lib') is not None
1169    has_64 = apex_provider.get('lib64') is not None
1170    if has_32 and has_64:
1171      logging.warning('  Detected multilib')
1172      test_args.bitness = BITNESS_MULTILIB
1173    elif has_32:
1174      logging.warning('  Detected 32-only')
1175      test_args.bitness = BITNESS_32
1176    elif has_64:
1177      logging.warning('  Detected 64-only')
1178      test_args.bitness = BITNESS_64
1179    else:
1180      logging.error('  Could not detect bitness, neither lib nor lib64 contained.')
1181      List(apex_provider).print_list()
1182      return 1
1183
1184  if test_args.bitness == BITNESS_32:
1185    base_checker = Arch32Checker(apex_provider)
1186  elif test_args.bitness == BITNESS_64:
1187    base_checker = Arch64Checker(apex_provider)
1188  else:
1189    assert test_args.bitness == BITNESS_MULTILIB
1190    base_checker = MultilibChecker(apex_provider)
1191
1192  checkers.append(ReleaseChecker(base_checker))
1193  if test_args.host:
1194    checkers.append(ReleaseHostChecker(base_checker))
1195  else:
1196    checkers.append(ReleaseTargetChecker(base_checker))
1197  if test_args.flavor == FLAVOR_DEBUG or test_args.flavor == FLAVOR_TESTING:
1198    checkers.append(DebugChecker(base_checker))
1199    if not test_args.host:
1200      checkers.append(DebugTargetChecker(base_checker))
1201  if test_args.flavor == FLAVOR_TESTING:
1202    checkers.append(TestingTargetChecker(base_checker))
1203
1204  # These checkers must be last.
1205  checkers.append(NoSuperfluousBinariesChecker(base_checker))
1206  checkers.append(NoSuperfluousArtTestsChecker(base_checker))
1207  if not test_args.host:
1208    # We only care about superfluous libraries on target, where their absence
1209    # can be vital to ensure they get picked up from the right package.
1210    checkers.append(NoSuperfluousLibrariesChecker(base_checker))
1211
1212  failed = False
1213  for checker in checkers:
1214    logging.info('%s...', checker)
1215    checker.run()
1216    if base_checker.error_count() > 0:
1217      logging.error('%s FAILED', checker)
1218      failed = True
1219    else:
1220      logging.info('%s SUCCEEDED', checker)
1221    base_checker.reset_errors()
1222
1223  return 1 if failed else 0
1224
1225
1226def art_apex_test_default(test_parser):
1227  if 'ANDROID_PRODUCT_OUT' not in os.environ:
1228    logging.error('No-argument use requires ANDROID_PRODUCT_OUT')
1229    sys.exit(1)
1230  product_out = os.environ['ANDROID_PRODUCT_OUT']
1231  if 'ANDROID_HOST_OUT' not in os.environ:
1232    logging.error('No-argument use requires ANDROID_HOST_OUT')
1233    sys.exit(1)
1234  host_out = os.environ['ANDROID_HOST_OUT']
1235
1236  test_args = test_parser.parse_args(['dummy'])  # For consistency.
1237  test_args.debugfs = '%s/bin/debugfs' % host_out
1238  test_args.tmpdir = '.'
1239  test_args.tree = False
1240  test_args.list = False
1241  test_args.bitness = BITNESS_AUTO
1242  failed = False
1243
1244  if not os.path.exists(test_args.debugfs):
1245    logging.error("Cannot find debugfs (default path %s). Please build it, e.g., m debugfs",
1246                  test_args.debugfs)
1247    sys.exit(1)
1248
1249  # TODO: Add host support.
1250  # TODO: Add support for flattened APEX packages.
1251  configs = [
1252    {'name': 'com.android.art.release', 'flavor': FLAVOR_RELEASE, 'host': False},
1253    {'name': 'com.android.art.debug',   'flavor': FLAVOR_DEBUG,   'host': False},
1254    {'name': 'com.android.art.testing', 'flavor': FLAVOR_TESTING, 'host': False},
1255  ]
1256
1257  for config in configs:
1258    logging.info(config['name'])
1259    # TODO: Host will need different path.
1260    test_args.apex = '%s/system/apex/%s.apex' % (product_out, config['name'])
1261    if not os.path.exists(test_args.apex):
1262      failed = True
1263      logging.error("Cannot find APEX %s. Please build it first.", test_args.apex)
1264      continue
1265    test_args.flavor = config['flavor']
1266    test_args.host = config['host']
1267    failed = art_apex_test_main(test_args) != 0
1268
1269  if failed:
1270    sys.exit(1)
1271
1272
1273if __name__ == "__main__":
1274  parser = argparse.ArgumentParser(description='Check integrity of an ART APEX.')
1275
1276  parser.add_argument('apex', help='APEX file input')
1277
1278  parser.add_argument('--host', help='Check as host APEX', action='store_true')
1279
1280  parser.add_argument('--flattened', help='Check as flattened (target) APEX', action='store_true')
1281
1282  parser.add_argument('--flavor', help='Check as FLAVOR APEX', choices=FLAVORS_ALL,
1283                      default=FLAVOR_AUTO)
1284
1285  parser.add_argument('--list', help='List all files', action='store_true')
1286  parser.add_argument('--tree', help='Print directory tree', action='store_true')
1287  parser.add_argument('--size', help='Print file sizes', action='store_true')
1288
1289  parser.add_argument('--tmpdir', help='Directory for temp files')
1290  parser.add_argument('--debugfs', help='Path to debugfs')
1291
1292  parser.add_argument('--bitness', help='Bitness to check', choices=BITNESS_ALL,
1293                      default=BITNESS_AUTO)
1294
1295  if len(sys.argv) == 1:
1296    art_apex_test_default(parser)
1297  else:
1298    args = parser.parse_args()
1299
1300    if args is None:
1301      sys.exit(1)
1302
1303    exit_code = art_apex_test_main(args)
1304    sys.exit(exit_code)
1305