1#!/usr/bin/env python3 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 shutil 25import subprocess 26import sys 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_32 = ['arm', 'x86'] 46ARCHS_64 = ['arm64', 'riscv64', 'x86_64'] 47 48# Multilib options 49MULTILIB_32 = '32' 50MULTILIB_64 = '64' 51MULTILIB_BOTH = 'both' 52MULTILIB_FIRST = 'first' 53 54# Directory containing ART tests within an ART APEX (if the package includes 55# any). ART test executables are installed in `bin/art/<arch>`. Segregating 56# tests by architecture is useful on devices supporting more than one 57# architecture, as it permits testing all of them using a single ART APEX 58# package. 59ART_TEST_DIR = 'bin/art' 60 61 62# Test if a given variable is set to a string "true". 63def isEnvTrue(var): 64 return var in os.environ and os.environ[var] == 'true' 65 66 67def extract_apex(apex_path, deapexer_path, debugfs_path, fsckerofs_path, 68 tmpdir): 69 _, apex_name = os.path.split(apex_path) 70 extract_path = os.path.join(tmpdir, apex_name) 71 if os.path.exists(extract_path): 72 shutil.rmtree(extract_path) 73 subprocess.check_call([deapexer_path, '--debugfs', debugfs_path, 74 '--fsckerofs', fsckerofs_path, 75 'extract', apex_path, extract_path], 76 stdout=subprocess.DEVNULL) 77 return extract_path 78 79 80class FSObject: 81 def __init__(self, name, is_dir, is_exec, is_symlink, size): 82 self.name = name 83 self.is_dir = is_dir 84 self.is_exec = is_exec 85 self.is_symlink = is_symlink 86 self.size = size 87 88 def __str__(self): 89 return '%s(dir=%r,exec=%r,symlink=%r,size=%d)' \ 90 % (self.name, self.is_dir, self.is_exec, self.is_symlink, self.size) 91 92 def type_descr(self): 93 if self.is_dir: 94 return 'directory' 95 if self.is_symlink: 96 return 'symlink' 97 return 'file' 98 99 100class TargetApexProvider: 101 def __init__(self, apex): 102 self._folder_cache = {} 103 self._apex = apex 104 105 def get(self, path): 106 apex_dir, name = os.path.split(path) 107 if not apex_dir: 108 apex_dir = '.' 109 apex_map = self.read_dir(apex_dir) 110 return apex_map[name] if name in apex_map else None 111 112 def read_dir(self, apex_dir): 113 if apex_dir in self._folder_cache: 114 return self._folder_cache[apex_dir] 115 apex_map = {} 116 dirname = os.path.join(self._apex, apex_dir) 117 if os.path.exists(dirname): 118 for basename in os.listdir(dirname): 119 filepath = os.path.join(dirname, basename) 120 is_dir = os.path.isdir(filepath) 121 is_exec = os.access(filepath, os.X_OK) 122 is_symlink = os.path.islink(filepath) 123 if is_symlink: 124 # Report the length of the symlink's target's path as file size, like `ls`. 125 size = len(os.readlink(filepath)) 126 else: 127 size = os.path.getsize(filepath) 128 apex_map[basename] = FSObject(basename, is_dir, is_exec, is_symlink, size) 129 self._folder_cache[apex_dir] = apex_map 130 return apex_map 131 132 133# DO NOT USE DIRECTLY! This is an "abstract" base class. 134class Checker: 135 def __init__(self, provider): 136 self._provider = provider 137 self._errors = 0 138 self._expected_file_globs = set() 139 140 def fail(self, msg, *fail_args): 141 self._errors += 1 142 logging.error(msg, *fail_args) 143 144 def error_count(self): 145 return self._errors 146 147 def reset_errors(self): 148 self._errors = 0 149 150 def is_file(self, path): 151 fs_object = self._provider.get(path) 152 if fs_object is None: 153 return False, 'Could not find %s' 154 if fs_object.is_dir: 155 return False, '%s is a directory' 156 if fs_object.is_symlink: 157 return False, '%s is a symlink' 158 return True, '' 159 160 def is_dir(self, path): 161 fs_object = self._provider.get(path) 162 if fs_object is None: 163 return False, 'Could not find %s' 164 if not fs_object.is_dir: 165 return False, '%s is not a directory' 166 return True, '' 167 168 def check_file(self, path): 169 ok, msg = self.is_file(path) 170 if not ok: 171 self.fail(msg, path) 172 self._expected_file_globs.add(path) 173 return ok 174 175 def check_dir(self, path): 176 ok, msg = self.is_dir(path) 177 if not ok: 178 self.fail(msg, path) 179 self._expected_file_globs.add(path) 180 return ok 181 182 def check_optional_file(self, path): 183 if not self._provider.get(path): 184 return True 185 return self.check_file(path) 186 187 def check_executable(self, filename): 188 path = 'bin/%s' % filename 189 if not self.check_file(path): 190 return 191 if not self._provider.get(path).is_exec: 192 self.fail('%s is not executable', path) 193 194 def check_executable_symlink(self, filename): 195 path = 'bin/%s' % filename 196 fs_object = self._provider.get(path) 197 if fs_object is None: 198 self.fail('Could not find %s', path) 199 return 200 if fs_object.is_dir: 201 self.fail('%s is a directory', path) 202 return 203 if not fs_object.is_symlink: 204 self.fail('%s is not a symlink', path) 205 self._expected_file_globs.add(path) 206 207 def arch_dirs_for_path(self, path, multilib=None): 208 # Look for target-specific subdirectories for the given directory path. 209 # This is needed because the list of build targets is not propagated 210 # to this script. 211 # 212 # TODO(b/123602136): Pass build target information to this script and fix 213 # all places where this function in used (or similar workarounds). 214 dirs = [] 215 for archs_per_bitness in self.possible_archs_per_bitness(multilib): 216 found_dir = False 217 for arch in archs_per_bitness: 218 dir = '%s/%s' % (path, arch) 219 found, _ = self.is_dir(dir) 220 if found: 221 found_dir = True 222 dirs.append(dir) 223 # At least one arch directory per bitness must exist. 224 if not found_dir: 225 self.fail('Arch directories missing in %s - expected at least one of %s', 226 path, ', '.join(archs_per_bitness)) 227 return dirs 228 229 def check_art_test_executable(self, filename, multilib=None): 230 for dir in self.arch_dirs_for_path(ART_TEST_DIR, multilib): 231 test_path = '%s/%s' % (dir, filename) 232 self._expected_file_globs.add(test_path) 233 file_obj = self._provider.get(test_path) 234 if not file_obj: 235 self.fail('ART test binary missing: %s', test_path) 236 elif not file_obj.is_exec: 237 self.fail('%s is not executable', test_path) 238 239 def check_art_test_data(self, filename): 240 for dir in self.arch_dirs_for_path(ART_TEST_DIR): 241 if not self.check_file('%s/%s' % (dir, filename)): 242 return 243 244 def check_single_library(self, filename): 245 lib_path = 'lib/%s' % filename 246 lib64_path = 'lib64/%s' % filename 247 lib_is_file, _ = self.is_file(lib_path) 248 if lib_is_file: 249 self._expected_file_globs.add(lib_path) 250 lib64_is_file, _ = self.is_file(lib64_path) 251 if lib64_is_file: 252 self._expected_file_globs.add(lib64_path) 253 if not lib_is_file and not lib64_is_file: 254 self.fail('Library missing: %s', filename) 255 256 def check_java_library(self, basename): 257 return self.check_file('javalib/%s.jar' % basename) 258 259 def ignore_path(self, path_glob): 260 self._expected_file_globs.add(path_glob) 261 262 def check_optional_art_test_executable(self, filename): 263 for archs_per_bitness in self.possible_archs_per_bitness(): 264 for arch in archs_per_bitness: 265 self.ignore_path('%s/%s/%s' % (ART_TEST_DIR, arch, filename)) 266 267 def check_no_superfluous_files(self): 268 def recurse(dir_path): 269 paths = [] 270 for name, fsobj in sorted(self._provider.read_dir(dir_path).items(), key=lambda p: p[0]): 271 if name in ('.', '..'): 272 continue 273 path = os.path.join(dir_path, name) 274 paths.append(path) 275 if fsobj.is_dir: 276 recurse(path) 277 for path_glob in self._expected_file_globs: 278 paths = [path for path in paths if not fnmatch.fnmatch(path, path_glob)] 279 for unexpected_path in paths: 280 fs_object = self._provider.get(unexpected_path) 281 self.fail('Unexpected %s: %s', fs_object.type_descr(), unexpected_path) 282 recurse('') 283 284 # Just here for docs purposes, even if it isn't good Python style. 285 286 def check_symlinked_multilib_executable(self, filename): 287 """Check bin/filename32, and/or bin/filename64, with symlink bin/filename.""" 288 raise NotImplementedError 289 290 def check_symlinked_first_executable(self, filename): 291 """Check bin/filename32, and/or bin/filename64, with symlink bin/filename.""" 292 raise NotImplementedError 293 294 def check_native_library(self, basename): 295 """Check lib/basename.so, and/or lib64/basename.so.""" 296 raise NotImplementedError 297 298 def check_optional_native_library(self, basename_glob): 299 """Allow lib/basename.so and/or lib64/basename.so to exist.""" 300 raise NotImplementedError 301 302 def check_prefer64_library(self, basename): 303 """Check lib64/basename.so, or lib/basename.so on 32 bit only.""" 304 raise NotImplementedError 305 306 def possible_archs_per_bitness(self, multilib=None): 307 """Returns a list of lists of possible architectures per bitness.""" 308 raise NotImplementedError 309 310class Arch32Checker(Checker): 311 def __init__(self, provider): 312 super().__init__(provider) 313 self.lib_dirs = ['lib'] 314 315 def check_symlinked_multilib_executable(self, filename): 316 self.check_executable('%s32' % filename) 317 self.check_executable_symlink(filename) 318 319 def check_symlinked_first_executable(self, filename): 320 self.check_executable('%s32' % filename) 321 self.check_executable_symlink(filename) 322 323 def check_native_library(self, basename): 324 # TODO: Use $TARGET_ARCH (e.g. check whether it is "arm" or "arm64") to improve 325 # the precision of this test? 326 self.check_file('lib/%s.so' % basename) 327 328 def check_optional_native_library(self, basename_glob): 329 self.ignore_path('lib/%s.so' % basename_glob) 330 331 def check_prefer64_library(self, basename): 332 self.check_native_library(basename) 333 334 def possible_archs_per_bitness(self, multilib=None): 335 return [ARCHS_32] 336 337class Arch64Checker(Checker): 338 def __init__(self, provider): 339 super().__init__(provider) 340 self.lib_dirs = ['lib64'] 341 342 def check_symlinked_multilib_executable(self, filename): 343 self.check_executable('%s64' % filename) 344 self.check_executable_symlink(filename) 345 346 def check_symlinked_first_executable(self, filename): 347 self.check_executable('%s64' % filename) 348 self.check_executable_symlink(filename) 349 350 def check_native_library(self, basename): 351 # TODO: Use $TARGET_ARCH (e.g. check whether it is "arm" or "arm64") to improve 352 # the precision of this test? 353 self.check_file('lib64/%s.so' % basename) 354 355 def check_optional_native_library(self, basename_glob): 356 self.ignore_path('lib64/%s.so' % basename_glob) 357 358 def check_prefer64_library(self, basename): 359 self.check_native_library(basename) 360 361 def possible_archs_per_bitness(self, multilib=None): 362 return [ARCHS_64] 363 364 365class MultilibChecker(Checker): 366 def __init__(self, provider): 367 super().__init__(provider) 368 self.lib_dirs = ['lib', 'lib64'] 369 370 def check_symlinked_multilib_executable(self, filename): 371 self.check_executable('%s32' % filename) 372 self.check_executable('%s64' % filename) 373 self.check_executable_symlink(filename) 374 375 def check_symlinked_first_executable(self, filename): 376 self.check_executable('%s64' % filename) 377 self.check_executable_symlink(filename) 378 379 def check_native_library(self, basename): 380 # TODO: Use $TARGET_ARCH (e.g. check whether it is "arm" or "arm64") to improve 381 # the precision of this test? 382 self.check_file('lib/%s.so' % basename) 383 self.check_file('lib64/%s.so' % basename) 384 385 def check_optional_native_library(self, basename_glob): 386 self.ignore_path('lib/%s.so' % basename_glob) 387 self.ignore_path('lib64/%s.so' % basename_glob) 388 389 def check_prefer64_library(self, basename): 390 self.check_file('lib64/%s.so' % basename) 391 392 def possible_archs_per_bitness(self, multilib=None): 393 if multilib is None or multilib == MULTILIB_BOTH: 394 return [ARCHS_32, ARCHS_64] 395 if multilib == MULTILIB_FIRST or multilib == MULTILIB_64: 396 return [ARCHS_64] 397 elif multilib == MULTILIB_32: 398 return [ARCHS_32] 399 self.fail('Unrecognized multilib option "%s"', multilib) 400 401 402class ReleaseChecker: 403 def __init__(self, checker): 404 self._checker = checker 405 406 def __str__(self): 407 return 'Release Checker' 408 409 def run(self): 410 # Check the root directory. 411 self._checker.check_dir('bin') 412 self._checker.check_dir('etc') 413 self._checker.check_dir('javalib') 414 for lib_dir in self._checker.lib_dirs: 415 self._checker.check_dir(lib_dir) 416 self._checker.check_file('apex_manifest.pb') 417 418 # Check etc. 419 self._checker.check_file('etc/boot-image.prof') 420 self._checker.check_dir('etc/classpaths') 421 self._checker.check_file('etc/classpaths/bootclasspath.pb') 422 self._checker.check_file('etc/classpaths/systemserverclasspath.pb') 423 self._checker.check_dir('etc/compatconfig') 424 self._checker.check_file('etc/compatconfig/libcore-platform-compat-config.xml') 425 self._checker.check_file('etc/init.rc') 426 self._checker.check_file('etc/linker.config.pb') 427 self._checker.check_file('etc/sdkinfo.pb') 428 self._checker.check_file('etc/dirty-image-objects') 429 430 # Check flagging files that don't get added in builds on master-art. 431 # TODO(b/345713436): Make flags work on master-art. 432 self._checker.check_optional_file('etc/aconfig_flags.pb') 433 self._checker.check_optional_file('etc/flag.info') 434 self._checker.check_optional_file('etc/flag.map') 435 self._checker.check_optional_file('etc/flag.val') 436 self._checker.check_optional_file('etc/package.map') 437 438 # Check binaries for ART. 439 self._checker.check_executable('art_boot') 440 self._checker.check_executable('art_exec') 441 self._checker.check_executable('artd') 442 self._checker.check_executable('dexdump') 443 self._checker.check_executable('dexlist') 444 self._checker.check_executable('dexopt_chroot_setup') 445 self._checker.check_executable('dexoptanalyzer') 446 self._checker.check_executable('oatdump') 447 self._checker.check_executable('odrefresh') 448 self._checker.check_executable('profman') 449 self._checker.check_symlinked_multilib_executable('dalvikvm') 450 self._checker.check_symlinked_multilib_executable('dex2oat') 451 452 # Check exported libraries for ART. 453 self._checker.check_native_library('libdexfile') 454 self._checker.check_native_library('libnativebridge') 455 self._checker.check_native_library('libnativehelper') 456 self._checker.check_native_library('libnativeloader') 457 458 # Check internal libraries for ART. 459 self._checker.check_native_library('libadbconnection') 460 self._checker.check_native_library('libart') 461 self._checker.check_native_library('libart-disassembler') 462 self._checker.check_native_library('libartbase') 463 self._checker.check_native_library('libartpalette') 464 self._checker.check_native_library('libdt_fd_forward') 465 self._checker.check_native_library('libopenjdkjvm') 466 self._checker.check_native_library('libopenjdkjvmti') 467 self._checker.check_native_library('libperfetto_hprof') 468 self._checker.check_native_library('libprofile') 469 self._checker.check_native_library('libsigchain') 470 self._checker.check_prefer64_library('libartservice') 471 self._checker.check_prefer64_library('libarttools') 472 473 # Check internal Java libraries for ART. 474 self._checker.check_java_library('service-art') 475 self._checker.check_file('javalib/service-art.jar.prof') 476 477 # Check exported native libraries for Managed Core Library. 478 self._checker.check_native_library('libandroidio') 479 480 # Check Java libraries for Managed Core Library. 481 self._checker.check_java_library('apache-xml') 482 self._checker.check_java_library('bouncycastle') 483 self._checker.check_java_library('core-libart') 484 self._checker.check_java_library('core-oj') 485 self._checker.check_java_library('okhttp') 486 if isEnvTrue('EMMA_INSTRUMENT_FRAMEWORK'): 487 # In coverage builds jacoco is added to the list of ART apex jars. 488 self._checker.check_java_library('jacocoagent') 489 490 # Check internal native libraries for Managed Core Library. 491 self._checker.check_native_library('libjavacore') 492 self._checker.check_native_library('libopenjdk') 493 494 # Check internal native library dependencies. 495 # 496 # Any internal dependency not listed here will cause a failure in 497 # NoSuperfluousFilesChecker. Internal dependencies are generally just 498 # implementation details, but in the release package we want to track them 499 # because a) they add to the package size and the RAM usage (in particular 500 # if the library is also present in /system or another APEX and hence might 501 # get loaded twice through linker namespace separation), and b) we need to 502 # catch invalid dependencies on /system or other APEXes that should go 503 # through an exported library with stubs (b/128708192 tracks implementing a 504 # better approach for that). 505 self._checker.check_native_library('libbase') 506 self._checker.check_native_library('libc++') 507 self._checker.check_native_library('libdt_socket') 508 self._checker.check_native_library('libexpat') 509 self._checker.check_native_library('libjdwp') 510 self._checker.check_native_library('liblz4') 511 self._checker.check_native_library('liblzma') 512 self._checker.check_native_library('libnpt') 513 self._checker.check_native_library('libunwindstack') 514 515 # Allow extra dependencies that appear in ASAN builds. 516 self._checker.check_optional_native_library('libclang_rt.asan*') 517 self._checker.check_optional_native_library('libclang_rt.hwasan*') 518 self._checker.check_optional_native_library('libclang_rt.ubsan*') 519 520 521class DebugChecker: 522 def __init__(self, checker): 523 self._checker = checker 524 525 def __str__(self): 526 return 'Debug Checker' 527 528 def run(self): 529 # Check binaries for ART. 530 self._checker.check_executable('dexanalyze') 531 self._checker.check_symlinked_multilib_executable('imgdiag') 532 533 # Check debug binaries for ART. 534 self._checker.check_executable('dexoptanalyzerd') 535 self._checker.check_executable('oatdumpd') 536 self._checker.check_executable('profmand') 537 self._checker.check_symlinked_multilib_executable('dex2oatd') 538 self._checker.check_symlinked_multilib_executable('imgdiagd') 539 540 # Check exported libraries for ART. 541 self._checker.check_native_library('libdexfiled') 542 543 # Check internal libraries for ART. 544 self._checker.check_native_library('libadbconnectiond') 545 self._checker.check_native_library('libartbased') 546 self._checker.check_native_library('libartd') 547 self._checker.check_native_library('libartd-disassembler') 548 self._checker.check_native_library('libopenjdkjvmd') 549 self._checker.check_native_library('libopenjdkjvmtid') 550 self._checker.check_native_library('libperfetto_hprofd') 551 self._checker.check_native_library('libprofiled') 552 self._checker.check_prefer64_library('libartserviced') 553 554 # Check internal libraries for Managed Core Library. 555 self._checker.check_native_library('libopenjdkd') 556 557 # Check internal native library dependencies. 558 # 559 # Like in the release package, we check that we don't get other dependencies 560 # besides those listed here. In this case the concern is not bloat, but 561 # rather that we don't get behavioural differences between user (release) 562 # and userdebug/eng builds, which could happen if the debug package has 563 # duplicate library instances where releases don't. In other words, it's 564 # uncontroversial to add debug-only dependencies, as long as they don't make 565 # assumptions on having a single global state (ideally they should have 566 # double_loadable:true, cf. go/double_loadable). Also, like in the release 567 # package we need to look out for dependencies that should go through 568 # exported library stubs (until b/128708192 is fixed). 569 # 570 # (There are currently no debug-only native libraries.) 571 572 573class TestingChecker: 574 def __init__(self, checker): 575 self._checker = checker 576 577 def __str__(self): 578 return 'Testing Checker' 579 580 def run(self): 581 # Check test directories. 582 self._checker.check_dir(ART_TEST_DIR) 583 for arch_dir in self._checker.arch_dirs_for_path(ART_TEST_DIR): 584 self._checker.check_dir(arch_dir) 585 586 # Check ART test binaries. 587 self._checker.check_art_test_executable('art_cmdline_tests') 588 self._checker.check_art_test_executable('art_compiler_tests') 589 self._checker.check_art_test_executable('art_dex2oat_tests') 590 self._checker.check_art_test_executable('art_dexanalyze_tests') 591 self._checker.check_art_test_executable('art_dexdump_tests') 592 self._checker.check_art_test_executable('art_dexlist_tests') 593 self._checker.check_art_test_executable('art_dexoptanalyzer_tests') 594 self._checker.check_art_test_executable('art_disassembler_tests') 595 self._checker.check_art_test_executable('art_imgdiag_tests') 596 self._checker.check_art_test_executable('art_libartbase_tests') 597 self._checker.check_art_test_executable('art_libdexfile_support_tests') 598 self._checker.check_art_test_executable('art_libdexfile_tests') 599 self._checker.check_art_test_executable('art_libprofile_tests') 600 self._checker.check_art_test_executable('art_oatdump_tests') 601 self._checker.check_art_test_executable('art_odrefresh_tests', MULTILIB_FIRST) 602 self._checker.check_art_test_executable('art_profman_tests') 603 self._checker.check_art_test_executable('art_runtime_tests') 604 self._checker.check_art_test_executable('art_sigchain_tests') 605 606 # Check ART test tools. 607 self._checker.check_executable('signal_dumper') 608 609 # Check ART jar files which are needed for gtests. 610 self._checker.check_art_test_data('art-gtest-jars-AbstractMethod.jar') 611 self._checker.check_art_test_data('art-gtest-jars-ArrayClassWithUnresolvedComponent.dex') 612 self._checker.check_art_test_data('art-gtest-jars-MyClassNatives.jar') 613 self._checker.check_art_test_data('art-gtest-jars-Main.jar') 614 self._checker.check_art_test_data('art-gtest-jars-ProtoCompare.jar') 615 self._checker.check_art_test_data('art-gtest-jars-Transaction.jar') 616 self._checker.check_art_test_data('art-gtest-jars-VerifierDepsMulti.dex') 617 self._checker.check_art_test_data('art-gtest-jars-Nested.jar') 618 self._checker.check_art_test_data('art-gtest-jars-MyClass.jar') 619 self._checker.check_art_test_data('art-gtest-jars-ManyMethods.jar') 620 self._checker.check_art_test_data('art-gtest-jars-GetMethodSignature.jar') 621 self._checker.check_art_test_data('art-gtest-jars-Lookup.jar') 622 self._checker.check_art_test_data('art-gtest-jars-Instrumentation.jar') 623 self._checker.check_art_test_data('art-gtest-jars-MainUncompressedAligned.jar') 624 self._checker.check_art_test_data('art-gtest-jars-ForClassLoaderD.jar') 625 self._checker.check_art_test_data('art-gtest-jars-ForClassLoaderC.jar') 626 self._checker.check_art_test_data('art-gtest-jars-ErroneousA.jar') 627 self._checker.check_art_test_data('art-gtest-jars-HiddenApiSignatures.jar') 628 self._checker.check_art_test_data('art-gtest-jars-ForClassLoaderB.jar') 629 self._checker.check_art_test_data('art-gtest-jars-LinkageTest.dex') 630 self._checker.check_art_test_data('art-gtest-jars-MethodTypes.jar') 631 self._checker.check_art_test_data('art-gtest-jars-ErroneousInit.jar') 632 self._checker.check_art_test_data('art-gtest-jars-VerifierDeps.dex') 633 self._checker.check_art_test_data('art-gtest-jars-StringLiterals.jar') 634 self._checker.check_art_test_data('art-gtest-jars-XandY.jar') 635 self._checker.check_art_test_data('art-gtest-jars-ExceptionHandle.jar') 636 self._checker.check_art_test_data('art-gtest-jars-ImageLayoutB.jar') 637 self._checker.check_art_test_data('art-gtest-jars-Interfaces.jar') 638 self._checker.check_art_test_data('art-gtest-jars-IMTB.jar') 639 self._checker.check_art_test_data('art-gtest-jars-Extension2.jar') 640 self._checker.check_art_test_data('art-gtest-jars-Extension1.jar') 641 self._checker.check_art_test_data('art-gtest-jars-MainEmptyUncompressedAligned.jar') 642 self._checker.check_art_test_data('art-gtest-jars-ErroneousB.jar') 643 self._checker.check_art_test_data('art-gtest-jars-MultiDexModifiedSecondary.jar') 644 self._checker.check_art_test_data('art-gtest-jars-NonStaticLeafMethods.jar') 645 self._checker.check_art_test_data('art-gtest-jars-DefaultMethods.jar') 646 self._checker.check_art_test_data('art-gtest-jars-MultiDexUncompressedAligned.jar') 647 self._checker.check_art_test_data('art-gtest-jars-StaticsFromCode.jar') 648 self._checker.check_art_test_data('art-gtest-jars-ProfileTestMultiDex.jar') 649 self._checker.check_art_test_data('art-gtest-jars-VerifySoftFailDuringClinit.dex') 650 self._checker.check_art_test_data('art-gtest-jars-MainStripped.jar') 651 self._checker.check_art_test_data('art-gtest-jars-ForClassLoaderA.jar') 652 self._checker.check_art_test_data('art-gtest-jars-StaticLeafMethods.jar') 653 self._checker.check_art_test_data('art-gtest-jars-MultiDex.jar') 654 self._checker.check_art_test_data('art-gtest-jars-Packages.jar') 655 self._checker.check_art_test_data('art-gtest-jars-ProtoCompare2.jar') 656 self._checker.check_art_test_data('art-gtest-jars-Statics.jar') 657 self._checker.check_art_test_data('art-gtest-jars-AllFields.jar') 658 self._checker.check_art_test_data('art-gtest-jars-IMTA.jar') 659 self._checker.check_art_test_data('art-gtest-jars-ImageLayoutA.jar') 660 self._checker.check_art_test_data('art-gtest-jars-MainEmptyUncompressed.jar') 661 self._checker.check_art_test_data('art-gtest-jars-Dex2oatVdexTestDex.jar') 662 self._checker.check_art_test_data('art-gtest-jars-Dex2oatVdexPublicSdkDex.dex') 663 self._checker.check_art_test_data('art-gtest-jars-SuperWithAccessChecks.dex') 664 665 # Fuzzer cases 666 self._checker.check_art_test_data('dex_verification_fuzzer_corpus.zip') 667 self._checker.check_art_test_data('class_verification_fuzzer_corpus.zip') 668 669 670class NoSuperfluousFilesChecker: 671 def __init__(self, checker): 672 self._checker = checker 673 674 def __str__(self): 675 return 'No superfluous files checker' 676 677 def run(self): 678 self._checker.check_no_superfluous_files() 679 680 681class List: 682 def __init__(self, provider, print_size=False): 683 self._provider = provider 684 self._print_size = print_size 685 686 def print_list(self): 687 688 def print_list_rec(path): 689 apex_map = self._provider.read_dir(path) 690 if apex_map is None: 691 return 692 apex_map = dict(apex_map) 693 if '.' in apex_map: 694 del apex_map['.'] 695 if '..' in apex_map: 696 del apex_map['..'] 697 for (_, val) in sorted(apex_map.items()): 698 val_path = os.path.join(path, val.name) 699 if self._print_size: 700 if val.size < 0: 701 print('[ n/a ] %s' % val_path) 702 else: 703 print('[%11d] %s' % (val.size, val_path)) 704 else: 705 print(val_path) 706 if val.is_dir: 707 print_list_rec(val_path) 708 709 print_list_rec('') 710 711 712class Tree: 713 def __init__(self, provider, title, print_size=False): 714 print('%s' % title) 715 self._provider = provider 716 self._has_next_list = [] 717 self._print_size = print_size 718 719 @staticmethod 720 def get_vertical(has_next_list): 721 string = '' 722 for v in has_next_list: 723 string += '%s ' % ('│' if v else ' ') 724 return string 725 726 @staticmethod 727 def get_last_vertical(last): 728 return '└── ' if last else '├── ' 729 730 def print_tree(self): 731 732 def print_tree_rec(path): 733 apex_map = self._provider.read_dir(path) 734 if apex_map is None: 735 return 736 apex_map = dict(apex_map) 737 if '.' in apex_map: 738 del apex_map['.'] 739 if '..' in apex_map: 740 del apex_map['..'] 741 key_list = list(sorted(apex_map.keys())) 742 for i, key in enumerate(key_list): 743 prev = self.get_vertical(self._has_next_list) 744 last = self.get_last_vertical(i == len(key_list) - 1) 745 val = apex_map[key] 746 if self._print_size: 747 if val.size < 0: 748 print('%s%s[ n/a ] %s' % (prev, last, val.name)) 749 else: 750 print('%s%s[%11d] %s' % (prev, last, val.size, val.name)) 751 else: 752 print('%s%s%s' % (prev, last, val.name)) 753 if val.is_dir: 754 self._has_next_list.append(i < len(key_list) - 1) 755 val_path = os.path.join(path, val.name) 756 print_tree_rec(val_path) 757 self._has_next_list.pop() 758 759 print_tree_rec('') 760 761 762# Note: do not sys.exit early, for __del__ cleanup. 763def art_apex_test_main(test_args): 764 if test_args.list and test_args.tree: 765 logging.error('Both of --list and --tree set') 766 return 1 767 if test_args.size and not (test_args.list or test_args.tree): 768 logging.error('--size set but neither --list nor --tree set') 769 return 1 770 if not test_args.flattened and not test_args.tmpdir: 771 logging.error('Need a tmpdir.') 772 return 1 773 if not test_args.flattened: 774 if not test_args.deapexer: 775 logging.error('Need deapexer.') 776 return 1 777 if not test_args.debugfs: 778 logging.error('Need debugfs.') 779 return 1 780 if not test_args.fsckerofs: 781 logging.error('Need fsck.erofs.') 782 return 1 783 784 if test_args.flavor == FLAVOR_AUTO: 785 logging.warning('--flavor=auto, trying to autodetect. This may be incorrect!') 786 # The order of flavors in the list below matters, as the release tag (empty string) will 787 # match any package name. 788 for flavor in [ FLAVOR_DEBUG, FLAVOR_TESTING, FLAVOR_RELEASE ]: 789 flavor_tag = flavor 790 # Special handling for the release flavor, whose name is no longer part of the Release ART 791 # APEX file name (`com.android.art.capex` / `com.android.art`). 792 if flavor == FLAVOR_RELEASE: 793 flavor_tag = '' 794 flavor_pattern = '*.%s*' % flavor_tag 795 if fnmatch.fnmatch(test_args.apex, flavor_pattern): 796 test_args.flavor = flavor 797 logging.warning(' Detected %s flavor', flavor) 798 break 799 if test_args.flavor == FLAVOR_AUTO: 800 logging.error(' Could not detect APEX flavor, neither %s, %s nor %s for \'%s\'', 801 FLAVOR_RELEASE, FLAVOR_DEBUG, FLAVOR_TESTING, test_args.apex) 802 return 1 803 804 apex_dir = test_args.apex 805 if not test_args.flattened: 806 # Extract the apex. It would be nice to use the output from "deapexer list" 807 # to avoid this work, but it doesn't provide info about executable bits. 808 apex_dir = extract_apex(test_args.apex, test_args.deapexer, test_args.debugfs, 809 test_args.fsckerofs, test_args.tmpdir) 810 apex_provider = TargetApexProvider(apex_dir) 811 812 if test_args.tree: 813 Tree(apex_provider, test_args.apex, test_args.size).print_tree() 814 return 0 815 if test_args.list: 816 List(apex_provider, test_args.size).print_list() 817 return 0 818 819 checkers = [] 820 if test_args.bitness == BITNESS_AUTO: 821 logging.warning('--bitness=auto, trying to autodetect. This may be incorrect!') 822 has_32 = apex_provider.get('lib') is not None 823 has_64 = apex_provider.get('lib64') is not None 824 if has_32 and has_64: 825 logging.warning(' Detected multilib') 826 test_args.bitness = BITNESS_MULTILIB 827 elif has_32: 828 logging.warning(' Detected 32-only') 829 test_args.bitness = BITNESS_32 830 elif has_64: 831 logging.warning(' Detected 64-only') 832 test_args.bitness = BITNESS_64 833 else: 834 logging.error(' Could not detect bitness, neither lib nor lib64 contained.') 835 List(apex_provider).print_list() 836 return 1 837 838 if test_args.bitness == BITNESS_32: 839 base_checker = Arch32Checker(apex_provider) 840 elif test_args.bitness == BITNESS_64: 841 base_checker = Arch64Checker(apex_provider) 842 else: 843 assert test_args.bitness == BITNESS_MULTILIB 844 base_checker = MultilibChecker(apex_provider) 845 846 checkers.append(ReleaseChecker(base_checker)) 847 if test_args.flavor == FLAVOR_DEBUG or test_args.flavor == FLAVOR_TESTING: 848 checkers.append(DebugChecker(base_checker)) 849 if test_args.flavor == FLAVOR_TESTING: 850 checkers.append(TestingChecker(base_checker)) 851 852 # This checker must be last. 853 checkers.append(NoSuperfluousFilesChecker(base_checker)) 854 855 failed = False 856 for checker in checkers: 857 logging.info('%s...', checker) 858 checker.run() 859 if base_checker.error_count() > 0: 860 logging.error('%s FAILED', checker) 861 failed = True 862 else: 863 logging.info('%s SUCCEEDED', checker) 864 base_checker.reset_errors() 865 866 return 1 if failed else 0 867 868 869def art_apex_test_default(test_parser): 870 if 'ANDROID_PRODUCT_OUT' not in os.environ: 871 logging.error('No-argument use requires ANDROID_PRODUCT_OUT') 872 sys.exit(1) 873 product_out = os.environ['ANDROID_PRODUCT_OUT'] 874 if 'ANDROID_HOST_OUT' not in os.environ: 875 logging.error('No-argument use requires ANDROID_HOST_OUT') 876 sys.exit(1) 877 host_out = os.environ['ANDROID_HOST_OUT'] 878 879 test_args = test_parser.parse_args(['unused']) # For consistency. 880 test_args.debugfs = '%s/bin/debugfs' % host_out 881 test_args.fsckerofs = '%s/bin/fsck.erofs' % host_out 882 test_args.tmpdir = '.' 883 test_args.tree = False 884 test_args.list = False 885 test_args.bitness = BITNESS_AUTO 886 failed = False 887 888 if not os.path.exists(test_args.debugfs): 889 logging.error('Cannot find debugfs (default path %s). Please build it, e.g., m debugfs', 890 test_args.debugfs) 891 sys.exit(1) 892 893 # TODO: Add support for flattened APEX packages. 894 configs = [ 895 {'name': 'com.android.art.capex', 'flavor': FLAVOR_RELEASE}, 896 {'name': 'com.android.art.debug.capex', 'flavor': FLAVOR_DEBUG}, 897 # Note: The Testing ART APEX is not a Compressed APEX. 898 {'name': 'com.android.art.testing.apex', 'flavor': FLAVOR_TESTING}, 899 ] 900 901 for config in configs: 902 logging.info(config['name']) 903 test_args.apex = '%s/system/apex/%s' % (product_out, config['name']) 904 if not os.path.exists(test_args.apex): 905 failed = True 906 logging.error('Cannot find APEX %s. Please build it first.', test_args.apex) 907 continue 908 test_args.flavor = config['flavor'] 909 failed = art_apex_test_main(test_args) != 0 910 911 if failed: 912 sys.exit(1) 913 914 915if __name__ == '__main__': 916 parser = argparse.ArgumentParser(description='Check integrity of an ART APEX.') 917 918 parser.add_argument('apex', help='APEX file input') 919 920 parser.add_argument('--flattened', help='Check as flattened (target) APEX', action='store_true') 921 922 parser.add_argument('--flavor', help='Check as FLAVOR APEX', choices=FLAVORS_ALL, 923 default=FLAVOR_AUTO) 924 925 parser.add_argument('--list', help='List all files', action='store_true') 926 parser.add_argument('--tree', help='Print directory tree', action='store_true') 927 parser.add_argument('--size', help='Print file sizes', action='store_true') 928 929 parser.add_argument('--tmpdir', help='Directory for temp files') 930 parser.add_argument('--deapexer', help='Path to deapexer') 931 parser.add_argument('--debugfs', help='Path to debugfs') 932 parser.add_argument('--fsckerofs', help='Path to fsck.erofs') 933 934 parser.add_argument('--bitness', help='Bitness to check', choices=BITNESS_ALL, 935 default=BITNESS_AUTO) 936 937 if len(sys.argv) == 1: 938 art_apex_test_default(parser) 939 else: 940 args = parser.parse_args() 941 942 if args is None: 943 sys.exit(1) 944 945 exit_code = art_apex_test_main(args) 946 sys.exit(exit_code) 947