blob: d3ba1c1931cac64886e935dd4061a192dd3feabc [file] [log] [blame]
Andreas Gampe2c846cd2019-01-29 22:06:46 +00001#!/usr/bin/env python3
2
3# Copyright (C) 2019 The Android Open Source Project
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16#
17
18import argparse
Martin Stjernholm84a32cd2019-03-29 16:39:46 +000019import fnmatch
Andreas Gampe2c846cd2019-01-29 22:06:46 +000020import logging
21import os
Martin Stjernholm84a32cd2019-03-29 16:39:46 +000022import os.path
Andreas Gampe2c846cd2019-01-29 22:06:46 +000023import subprocess
24import sys
25import zipfile
26
27logging.basicConfig(format='%(message)s')
28
Luca Stefani4e91ee92019-03-06 15:08:16 +010029
Andreas Gampe2c846cd2019-01-29 22:06:46 +000030class FSObject:
31 def __init__(self, name, is_dir, is_exec, is_symlink):
32 self.name = name
33 self.is_dir = is_dir
34 self.is_exec = is_exec
35 self.is_symlink = is_symlink
Luca Stefani4e91ee92019-03-06 15:08:16 +010036
Andreas Gampe2c846cd2019-01-29 22:06:46 +000037 def __str__(self):
38 return '%s(dir=%r,exec=%r,symlink=%r)' % (self.name, self.is_dir, self.is_exec, self.is_symlink)
39
Luca Stefani4e91ee92019-03-06 15:08:16 +010040
Andreas Gampe2c846cd2019-01-29 22:06:46 +000041class TargetApexProvider:
42 def __init__(self, apex, tmpdir, debugfs):
43 self._tmpdir = tmpdir
44 self._debugfs = debugfs
45 self._folder_cache = {}
46 self._payload = os.path.join(self._tmpdir, 'apex_payload.img')
47 # Extract payload to tmpdir.
Luca Stefani4e91ee92019-03-06 15:08:16 +010048 apex_zip = zipfile.ZipFile(apex)
49 apex_zip.extract('apex_payload.img', tmpdir)
Andreas Gampe2c846cd2019-01-29 22:06:46 +000050
51 def __del__(self):
52 # Delete temps.
53 if os.path.exists(self._payload):
54 os.remove(self._payload)
55
56 def get(self, path):
Luca Stefani4e91ee92019-03-06 15:08:16 +010057 apex_dir, name = os.path.split(path)
58 if not apex_dir:
59 apex_dir = '.'
60 apex_map = self.read_dir(apex_dir)
61 return apex_map[name] if name in apex_map else None
Andreas Gampe2c846cd2019-01-29 22:06:46 +000062
Luca Stefani4e91ee92019-03-06 15:08:16 +010063 def read_dir(self, apex_dir):
64 if apex_dir in self._folder_cache:
65 return self._folder_cache[apex_dir]
Andreas Gampe2c846cd2019-01-29 22:06:46 +000066 # Cannot use check_output as it will annoy with stderr.
Luca Stefani4e91ee92019-03-06 15:08:16 +010067 process = subprocess.Popen([self._debugfs, '-R', 'ls -l -p %s' % apex_dir, self._payload],
Andreas Gampe2c846cd2019-01-29 22:06:46 +000068 stdout=subprocess.PIPE, stderr=subprocess.PIPE,
69 universal_newlines=True)
Luca Stefani4e91ee92019-03-06 15:08:16 +010070 stdout, _ = process.communicate()
Andreas Gampe2c846cd2019-01-29 22:06:46 +000071 res = str(stdout)
Luca Stefani4e91ee92019-03-06 15:08:16 +010072 apex_map = {}
Andreas Gampe2c846cd2019-01-29 22:06:46 +000073 # Debugfs output looks like this:
74 # debugfs 1.44.4 (18-Aug-2018)
75 # /12/040755/0/2000/.//
76 # /2/040755/1000/1000/..//
77 # /13/100755/0/2000/dalvikvm32/28456/
78 # /14/100755/0/2000/dexoptanalyzer/20396/
79 # /15/100755/0/2000/linker/1152724/
80 # /16/100755/0/2000/dex2oat/563508/
81 # /17/100755/0/2000/linker64/1605424/
82 # /18/100755/0/2000/profman/85304/
83 # /19/100755/0/2000/dalvikvm64/28576/
84 # | | | | | |
85 # | | | #- gid #- name #- size
86 # | | #- uid
87 # | #- type and permission bits
88 # #- inode nr (?)
89 #
90 # Note: could break just on '/' to avoid names with newlines.
91 for line in res.split("\n"):
92 if not line:
93 continue
94 comps = line.split('/')
95 if len(comps) != 8:
Luca Stefani4e91ee92019-03-06 15:08:16 +010096 logging.warning('Could not break and parse line \'%s\'', line)
Andreas Gampe2c846cd2019-01-29 22:06:46 +000097 continue
98 bits = comps[2]
99 name = comps[5]
100 if len(bits) != 6:
Luca Stefani4e91ee92019-03-06 15:08:16 +0100101 logging.warning('Dont understand bits \'%s\'', bits)
Andreas Gampe2c846cd2019-01-29 22:06:46 +0000102 continue
Luca Stefani4e91ee92019-03-06 15:08:16 +0100103 is_dir = bits[1] == '4'
104
Andreas Gampe2c846cd2019-01-29 22:06:46 +0000105 def is_exec_bit(ch):
Luca Stefani4e91ee92019-03-06 15:08:16 +0100106 return int(ch) & 1 == 1
107
Andreas Gampe2c846cd2019-01-29 22:06:46 +0000108 is_exec = is_exec_bit(bits[3]) and is_exec_bit(bits[4]) and is_exec_bit(bits[5])
Luca Stefani4e91ee92019-03-06 15:08:16 +0100109 is_symlink = bits[1] == '2'
110 apex_map[name] = FSObject(name, is_dir, is_exec, is_symlink)
111 self._folder_cache[apex_dir] = apex_map
112 return apex_map
113
Andreas Gampe2c846cd2019-01-29 22:06:46 +0000114
Andreas Gampe09123952019-01-30 13:17:02 -0800115class HostApexProvider:
116 def __init__(self, apex, tmpdir):
117 self._tmpdir = tmpdir
Luca Stefani4e91ee92019-03-06 15:08:16 +0100118 self.folder_cache = {}
Andreas Gampe09123952019-01-30 13:17:02 -0800119 self._payload = os.path.join(self._tmpdir, 'apex_payload.zip')
120 # Extract payload to tmpdir.
Luca Stefani4e91ee92019-03-06 15:08:16 +0100121 apex_zip = zipfile.ZipFile(apex)
122 apex_zip.extract('apex_payload.zip', tmpdir)
Andreas Gampe09123952019-01-30 13:17:02 -0800123
124 def __del__(self):
125 # Delete temps.
126 if os.path.exists(self._payload):
127 os.remove(self._payload)
128
129 def get(self, path):
Luca Stefani4e91ee92019-03-06 15:08:16 +0100130 apex_dir, name = os.path.split(path)
131 if not apex_dir:
132 apex_dir = ''
133 apex_map = self.read_dir(apex_dir)
134 return apex_map[name] if name in apex_map else None
Andreas Gampe09123952019-01-30 13:17:02 -0800135
Luca Stefani4e91ee92019-03-06 15:08:16 +0100136 def read_dir(self, apex_dir):
137 if apex_dir in self.folder_cache:
138 return self.folder_cache[apex_dir]
139 if not self.folder_cache:
Andreas Gampe09123952019-01-30 13:17:02 -0800140 self.parse_zip()
Luca Stefani4e91ee92019-03-06 15:08:16 +0100141 if apex_dir in self.folder_cache:
142 return self.folder_cache[apex_dir]
Andreas Gampe09123952019-01-30 13:17:02 -0800143 return {}
144
145 def parse_zip(self):
Luca Stefani4e91ee92019-03-06 15:08:16 +0100146 apex_zip = zipfile.ZipFile(self._payload)
147 infos = apex_zip.infolist()
Andreas Gampe09123952019-01-30 13:17:02 -0800148 for zipinfo in infos:
149 path = zipinfo.filename
150
151 # Assume no empty file is stored.
152 assert path
153
154 def get_octal(val, index):
Luca Stefani4e91ee92019-03-06 15:08:16 +0100155 return (val >> (index * 3)) & 0x7
156
Andreas Gampe09123952019-01-30 13:17:02 -0800157 def bits_is_exec(val):
158 # TODO: Enforce group/other, too?
159 return get_octal(val, 2) & 1 == 1
160
161 is_zipinfo = True
162 while path:
Luca Stefani4e91ee92019-03-06 15:08:16 +0100163 apex_dir, base = os.path.split(path)
Andreas Gampe09123952019-01-30 13:17:02 -0800164 # TODO: If directories are stored, base will be empty.
165
Luca Stefani4e91ee92019-03-06 15:08:16 +0100166 if apex_dir not in self.folder_cache:
167 self.folder_cache[apex_dir] = {}
168 dir_map = self.folder_cache[apex_dir]
169 if base not in dir_map:
Andreas Gampe09123952019-01-30 13:17:02 -0800170 if is_zipinfo:
171 bits = (zipinfo.external_attr >> 16) & 0xFFFF
172 is_dir = get_octal(bits, 4) == 4
173 is_symlink = get_octal(bits, 4) == 2
174 is_exec = bits_is_exec(bits)
175 else:
176 is_exec = False # Seems we can't get this easily?
177 is_symlink = False
178 is_dir = True
179 dir_map[base] = FSObject(base, is_dir, is_exec, is_symlink)
180 is_zipinfo = False
Luca Stefani4e91ee92019-03-06 15:08:16 +0100181 path = apex_dir
182
Andreas Gampe09123952019-01-30 13:17:02 -0800183
Andreas Gampeeb555b82019-01-30 14:47:49 -0800184# DO NOT USE DIRECTLY! This is an "abstract" base class.
Andreas Gampe2c846cd2019-01-29 22:06:46 +0000185class Checker:
186 def __init__(self, provider):
187 self._provider = provider
188 self._errors = 0
Martin Stjernholm84a32cd2019-03-29 16:39:46 +0000189 self._expected_file_globs = set()
Andreas Gampe2c846cd2019-01-29 22:06:46 +0000190
Luca Stefani4e91ee92019-03-06 15:08:16 +0100191 def fail(self, msg, *fail_args):
Andreas Gampe2c846cd2019-01-29 22:06:46 +0000192 self._errors += 1
Martin Stjernholm2babede2019-03-18 21:04:49 +0000193 logging.error(msg, *fail_args)
Andreas Gampe2c846cd2019-01-29 22:06:46 +0000194
195 def error_count(self):
196 return self._errors
Luca Stefani4e91ee92019-03-06 15:08:16 +0100197
Andreas Gampe9dc4b052019-01-30 13:47:25 -0800198 def reset_errors(self):
199 self._errors = 0
Andreas Gampe2c846cd2019-01-29 22:06:46 +0000200
Martin Stjernholm2babede2019-03-18 21:04:49 +0000201 def is_file(self, path):
202 fs_object = self._provider.get(path)
Andreas Gampe2c846cd2019-01-29 22:06:46 +0000203 if fs_object is None:
Luca Stefani4e91ee92019-03-06 15:08:16 +0100204 return False, 'Could not find %s'
Andreas Gampe2c846cd2019-01-29 22:06:46 +0000205 if fs_object.is_dir:
Luca Stefani4e91ee92019-03-06 15:08:16 +0100206 return False, '%s is a directory'
207 return True, ''
Andreas Gampea0242cf2019-01-29 13:01:23 -0800208
Martin Stjernholm2babede2019-03-18 21:04:49 +0000209 def check_file(self, path):
210 ok, msg = self.is_file(path)
211 if not ok:
212 self.fail(msg, path)
Martin Stjernholm84a32cd2019-03-29 16:39:46 +0000213 self._expected_file_globs.add(path)
Martin Stjernholm2babede2019-03-18 21:04:49 +0000214 return ok
Luca Stefani4e91ee92019-03-06 15:08:16 +0100215
Martin Stjernholmc17ace22019-03-18 21:47:31 +0000216 def check_executable(self, filename):
Martin Stjernholm2babede2019-03-18 21:04:49 +0000217 path = 'bin/%s' % filename
Andreas Gampe2c846cd2019-01-29 22:06:46 +0000218 if not self.check_file(path):
Luca Stefani4e91ee92019-03-06 15:08:16 +0100219 return
Andreas Gampe2c846cd2019-01-29 22:06:46 +0000220 if not self._provider.get(path).is_exec:
221 self.fail('%s is not executable', path)
Andreas Gampe2c846cd2019-01-29 22:06:46 +0000222
Martin Stjernholmc17ace22019-03-18 21:47:31 +0000223 def check_executable_symlink(self, filename):
Martin Stjernholm2babede2019-03-18 21:04:49 +0000224 path = 'bin/%s' % filename
Andreas Gampe2c846cd2019-01-29 22:06:46 +0000225 fs_object = self._provider.get(path)
226 if fs_object is None:
227 self.fail('Could not find %s', path)
Luca Stefani4e91ee92019-03-06 15:08:16 +0100228 return
Andreas Gampe2c846cd2019-01-29 22:06:46 +0000229 if fs_object.is_dir:
230 self.fail('%s is a directory', path)
Luca Stefani4e91ee92019-03-06 15:08:16 +0100231 return
Andreas Gampe2c846cd2019-01-29 22:06:46 +0000232 if not fs_object.is_symlink:
233 self.fail('%s is not a symlink', path)
Martin Stjernholm84a32cd2019-03-29 16:39:46 +0000234 self._expected_file_globs.add(path)
Andreas Gampe2c846cd2019-01-29 22:06:46 +0000235
Martin Stjernholm2babede2019-03-18 21:04:49 +0000236 def check_single_library(self, filename):
237 lib_path = 'lib/%s' % filename
238 lib64_path = 'lib64/%s' % filename
239 lib_is_file, _ = self.is_file(lib_path)
240 if lib_is_file:
Martin Stjernholm84a32cd2019-03-29 16:39:46 +0000241 self._expected_file_globs.add(lib_path)
Martin Stjernholm2babede2019-03-18 21:04:49 +0000242 lib64_is_file, _ = self.is_file(lib64_path)
243 if lib64_is_file:
Martin Stjernholm84a32cd2019-03-29 16:39:46 +0000244 self._expected_file_globs.add(lib64_path)
Martin Stjernholm2babede2019-03-18 21:04:49 +0000245 if not lib_is_file and not lib64_is_file:
246 self.fail('Library missing: %s', filename)
Andreas Gampea0242cf2019-01-29 13:01:23 -0800247
Martin Stjernholmc17ace22019-03-18 21:47:31 +0000248 def check_java_library(self, basename):
249 return self.check_file('javalib/%s.jar' % basename)
Andreas Gampe09123952019-01-30 13:17:02 -0800250
Martin Stjernholm84a32cd2019-03-29 16:39:46 +0000251 def ignore_path(self, path_glob):
252 self._expected_file_globs.add(path_glob)
Martin Stjernholm2babede2019-03-18 21:04:49 +0000253
254 def check_no_superfluous_files(self, dir_path):
Martin Stjernholm84a32cd2019-03-29 16:39:46 +0000255 paths = []
Martin Stjernholm2babede2019-03-18 21:04:49 +0000256 for name in sorted(self._provider.read_dir(dir_path).keys()):
Martin Stjernholm84a32cd2019-03-29 16:39:46 +0000257 if name not in ('.', '..'):
258 paths.append(os.path.join(dir_path, name))
259 expected_paths = set()
260 dir_prefix = dir_path + '/'
261 for path_glob in self._expected_file_globs:
262 expected_paths |= set(fnmatch.filter(paths, path_glob))
263 # If there are globs in subdirectories of dir_path we want to match their
264 # path segments at this directory level.
265 if path_glob.startswith(dir_prefix):
266 subpath = path_glob[len(dir_prefix):]
267 subpath_first_segment, _, _ = subpath.partition('/')
268 expected_paths |= set(fnmatch.filter(paths, dir_prefix + subpath_first_segment))
269 for unexpected_path in set(paths) - expected_paths:
270 self.fail('Unexpected file \'%s\'', unexpected_path)
Andreas Gampe2c846cd2019-01-29 22:06:46 +0000271
Andreas Gampeeb555b82019-01-30 14:47:49 -0800272 # Just here for docs purposes, even if it isn't good Python style.
273
Martin Stjernholmc17ace22019-03-18 21:47:31 +0000274 def check_symlinked_multilib_executable(self, filename):
275 """Check bin/filename32, and/or bin/filename64, with symlink bin/filename."""
Andreas Gampeeb555b82019-01-30 14:47:49 -0800276 raise NotImplementedError
277
Martin Stjernholmc17ace22019-03-18 21:47:31 +0000278 def check_symlinked_prefer32_executable(self, filename):
279 """Check bin/filename32, or bin/filename64 on 64 bit only, with symlink bin/filename."""
Andreas Gampeeb555b82019-01-30 14:47:49 -0800280 raise NotImplementedError
281
Martin Stjernholmc17ace22019-03-18 21:47:31 +0000282 def check_multilib_executable(self, filename):
283 """Check bin/filename for 32 bit, and/or bin/filename64."""
Andreas Gampeeb555b82019-01-30 14:47:49 -0800284 raise NotImplementedError
285
Martin Stjernholmc17ace22019-03-18 21:47:31 +0000286 def check_native_library(self, basename):
287 """Check lib/basename.so, and/or lib64/basename.so."""
Martin Stjernholm2babede2019-03-18 21:04:49 +0000288 raise NotImplementedError
289
Martin Stjernholm84a32cd2019-03-29 16:39:46 +0000290 def check_optional_native_library(self, basename_glob):
Martin Stjernholmc17ace22019-03-18 21:47:31 +0000291 """Allow lib/basename.so and/or lib64/basename.so to exist."""
Martin Stjernholmb81fe232019-03-25 17:38:04 +0000292 raise NotImplementedError
293
Martin Stjernholmc17ace22019-03-18 21:47:31 +0000294 def check_prefer64_library(self, basename):
295 """Check lib64/basename.so, or lib/basename.so on 32 bit only."""
Andreas Gampeeb555b82019-01-30 14:47:49 -0800296 raise NotImplementedError
297
298
299class Arch32Checker(Checker):
Martin Stjernholmc17ace22019-03-18 21:47:31 +0000300 def check_symlinked_multilib_executable(self, filename):
301 self.check_executable('%s32' % filename)
302 self.check_executable_symlink(filename)
Andreas Gampeeb555b82019-01-30 14:47:49 -0800303
Martin Stjernholmc17ace22019-03-18 21:47:31 +0000304 def check_symlinked_prefer32_executable(self, filename):
305 self.check_executable('%s32' % filename)
306 self.check_executable_symlink(filename)
Martin Stjernholm2babede2019-03-18 21:04:49 +0000307
Martin Stjernholmc17ace22019-03-18 21:47:31 +0000308 def check_multilib_executable(self, filename):
309 self.check_executable(filename)
Martin Stjernholm2babede2019-03-18 21:04:49 +0000310
Martin Stjernholmc17ace22019-03-18 21:47:31 +0000311 def check_native_library(self, basename):
Andreas Gampeeb555b82019-01-30 14:47:49 -0800312 # TODO: Use $TARGET_ARCH (e.g. check whether it is "arm" or "arm64") to improve
313 # the precision of this test?
Martin Stjernholmc17ace22019-03-18 21:47:31 +0000314 self.check_file('lib/%s.so' % basename)
Andreas Gampeeb555b82019-01-30 14:47:49 -0800315
Martin Stjernholm84a32cd2019-03-29 16:39:46 +0000316 def check_optional_native_library(self, basename_glob):
317 self.ignore_path('lib/%s.so' % basename_glob)
Martin Stjernholmb81fe232019-03-25 17:38:04 +0000318
Martin Stjernholmc17ace22019-03-18 21:47:31 +0000319 def check_prefer64_library(self, basename):
320 self.check_native_library(basename)
Andreas Gampeeb555b82019-01-30 14:47:49 -0800321
322
323class Arch64Checker(Checker):
Martin Stjernholmc17ace22019-03-18 21:47:31 +0000324 def check_symlinked_multilib_executable(self, filename):
325 self.check_executable('%s64' % filename)
326 self.check_executable_symlink(filename)
Andreas Gampeeb555b82019-01-30 14:47:49 -0800327
Martin Stjernholmc17ace22019-03-18 21:47:31 +0000328 def check_symlinked_prefer32_executable(self, filename):
329 self.check_executable('%s64' % filename)
330 self.check_executable_symlink(filename)
Martin Stjernholm2babede2019-03-18 21:04:49 +0000331
Martin Stjernholmc17ace22019-03-18 21:47:31 +0000332 def check_multilib_executable(self, filename):
333 self.check_executable('%s64' % filename)
Martin Stjernholm2babede2019-03-18 21:04:49 +0000334
Martin Stjernholmc17ace22019-03-18 21:47:31 +0000335 def check_native_library(self, basename):
Andreas Gampeeb555b82019-01-30 14:47:49 -0800336 # TODO: Use $TARGET_ARCH (e.g. check whether it is "arm" or "arm64") to improve
337 # the precision of this test?
Martin Stjernholmc17ace22019-03-18 21:47:31 +0000338 self.check_file('lib64/%s.so' % basename)
Andreas Gampeeb555b82019-01-30 14:47:49 -0800339
Martin Stjernholm84a32cd2019-03-29 16:39:46 +0000340 def check_optional_native_library(self, basename_glob):
341 self.ignore_path('lib64/%s.so' % basename_glob)
Martin Stjernholmb81fe232019-03-25 17:38:04 +0000342
Martin Stjernholmc17ace22019-03-18 21:47:31 +0000343 def check_prefer64_library(self, basename):
344 self.check_native_library(basename)
Andreas Gampeeb555b82019-01-30 14:47:49 -0800345
346
347class MultilibChecker(Checker):
Martin Stjernholmc17ace22019-03-18 21:47:31 +0000348 def check_symlinked_multilib_executable(self, filename):
349 self.check_executable('%s32' % filename)
350 self.check_executable('%s64' % filename)
351 self.check_executable_symlink(filename)
Andreas Gampeeb555b82019-01-30 14:47:49 -0800352
Martin Stjernholmc17ace22019-03-18 21:47:31 +0000353 def check_symlinked_prefer32_executable(self, filename):
354 self.check_executable('%s32' % filename)
355 self.check_executable_symlink(filename)
Martin Stjernholm2babede2019-03-18 21:04:49 +0000356
Martin Stjernholmc17ace22019-03-18 21:47:31 +0000357 def check_multilib_executable(self, filename):
358 self.check_executable('%s64' % filename)
359 self.check_executable(filename)
Martin Stjernholm2babede2019-03-18 21:04:49 +0000360
Martin Stjernholmc17ace22019-03-18 21:47:31 +0000361 def check_native_library(self, basename):
Andreas Gampeeb555b82019-01-30 14:47:49 -0800362 # TODO: Use $TARGET_ARCH (e.g. check whether it is "arm" or "arm64") to improve
363 # the precision of this test?
Martin Stjernholmc17ace22019-03-18 21:47:31 +0000364 self.check_file('lib/%s.so' % basename)
365 self.check_file('lib64/%s.so' % basename)
Andreas Gampeeb555b82019-01-30 14:47:49 -0800366
Martin Stjernholm84a32cd2019-03-29 16:39:46 +0000367 def check_optional_native_library(self, basename_glob):
368 self.ignore_path('lib/%s.so' % basename_glob)
369 self.ignore_path('lib64/%s.so' % basename_glob)
Martin Stjernholmb81fe232019-03-25 17:38:04 +0000370
Martin Stjernholmc17ace22019-03-18 21:47:31 +0000371 def check_prefer64_library(self, basename):
372 self.check_file('lib64/%s.so' % basename)
Andreas Gampeeb555b82019-01-30 14:47:49 -0800373
374
Andreas Gampe9dc4b052019-01-30 13:47:25 -0800375class ReleaseChecker:
376 def __init__(self, checker):
377 self._checker = checker
Luca Stefani4e91ee92019-03-06 15:08:16 +0100378
Andreas Gampe2c846cd2019-01-29 22:06:46 +0000379 def __str__(self):
380 return 'Release Checker'
381
382 def run(self):
Martin Stjernholm023c2182019-03-28 15:52:32 +0000383 # Check the APEX manifest.
Andreas Gampe9dc4b052019-01-30 13:47:25 -0800384 self._checker.check_file('apex_manifest.json')
Andreas Gampe2c846cd2019-01-29 22:06:46 +0000385
Martin Stjernholm77f17662019-04-03 17:08:21 +0100386 # Check binaries for ART.
Martin Stjernholmc17ace22019-03-18 21:47:31 +0000387 self._checker.check_executable('dex2oat')
Martin Stjernholm77f17662019-04-03 17:08:21 +0100388 self._checker.check_executable('dexdump')
389 self._checker.check_executable('dexlist')
Martin Stjernholmc17ace22019-03-18 21:47:31 +0000390 self._checker.check_executable('dexoptanalyzer')
391 self._checker.check_executable('profman')
Martin Stjernholm023c2182019-03-28 15:52:32 +0000392 self._checker.check_symlinked_multilib_executable('dalvikvm')
Andreas Gampe2c846cd2019-01-29 22:06:46 +0000393
Martin Stjernholm023c2182019-03-28 15:52:32 +0000394 # Check exported libraries for ART.
Martin Stjernholmc17ace22019-03-18 21:47:31 +0000395 self._checker.check_native_library('libdexfile_external')
396 self._checker.check_native_library('libnativebridge')
397 self._checker.check_native_library('libnativehelper')
398 self._checker.check_native_library('libnativeloader')
Martin Stjernholm023c2182019-03-28 15:52:32 +0000399
400 # Check internal libraries for ART.
401 self._checker.check_native_library('libadbconnection')
402 self._checker.check_native_library('libart')
403 self._checker.check_native_library('libart-compiler')
404 self._checker.check_native_library('libart-dexlayout')
405 self._checker.check_native_library('libartbase')
406 self._checker.check_native_library('libartpalette')
407 self._checker.check_native_library('libdexfile')
408 self._checker.check_native_library('libdexfile_support')
Martin Stjernholmc17ace22019-03-18 21:47:31 +0000409 self._checker.check_native_library('libopenjdkjvm')
410 self._checker.check_native_library('libopenjdkjvmti')
411 self._checker.check_native_library('libprofile')
Martin Stjernholm023c2182019-03-28 15:52:32 +0000412 self._checker.check_native_library('libsigchain')
413
414 # Check java libraries for Managed Core Library.
415 self._checker.check_java_library('apache-xml')
416 self._checker.check_java_library('bouncycastle')
417 self._checker.check_java_library('core-libart')
418 self._checker.check_java_library('core-oj')
419 self._checker.check_java_library('okhttp')
420
421 # Check internal native libraries for Managed Core Library.
Martin Stjernholmc17ace22019-03-18 21:47:31 +0000422 self._checker.check_native_library('libjavacore')
423 self._checker.check_native_library('libopenjdk')
Andreas Gampe2c846cd2019-01-29 22:06:46 +0000424
Martin Stjernholm2babede2019-03-18 21:04:49 +0000425 # Check internal native library dependencies.
Andreas Gampe2c846cd2019-01-29 22:06:46 +0000426 #
Martin Stjernholm2babede2019-03-18 21:04:49 +0000427 # Any internal dependency not listed here will cause a failure in
428 # NoSuperfluousLibrariesChecker. Internal dependencies are generally just
429 # implementation details, but in the release package we want to track them
430 # because a) they add to the package size and the RAM usage (in particular
431 # if the library is also present in /system or another APEX and hence might
432 # get loaded twice through linker namespace separation), and b) we need to
433 # catch invalid dependencies on /system or other APEXes that should go
434 # through an exported library with stubs (b/128708192 tracks implementing a
435 # better approach for that).
Martin Stjernholmc17ace22019-03-18 21:47:31 +0000436 self._checker.check_native_library('libbacktrace')
437 self._checker.check_native_library('libbase')
438 self._checker.check_native_library('libc++')
Martin Stjernholm023c2182019-03-28 15:52:32 +0000439 self._checker.check_native_library('libdt_fd_forward')
440 self._checker.check_native_library('libdt_socket')
441 self._checker.check_native_library('libjdwp')
Martin Stjernholmc17ace22019-03-18 21:47:31 +0000442 self._checker.check_native_library('liblzma')
Martin Stjernholm023c2182019-03-28 15:52:32 +0000443 self._checker.check_native_library('libnpt')
Martin Stjernholmc17ace22019-03-18 21:47:31 +0000444 self._checker.check_native_library('libunwindstack')
Martin Stjernholm023c2182019-03-28 15:52:32 +0000445 self._checker.check_native_library('libziparchive')
Martin Stjernholmc17ace22019-03-18 21:47:31 +0000446 self._checker.check_optional_native_library('libvixl') # Only on ARM/ARM64
Martin Stjernholm2babede2019-03-18 21:04:49 +0000447
Martin Stjernholm84a32cd2019-03-29 16:39:46 +0000448 # Allow extra dependencies that appear in ASAN builds.
449 self._checker.check_optional_native_library('libclang_rt.asan*')
450 self._checker.check_optional_native_library('libclang_rt.hwasan*')
451 self._checker.check_optional_native_library('libclang_rt.ubsan*')
452
Luca Stefani4e91ee92019-03-06 15:08:16 +0100453
Andreas Gampe9dc4b052019-01-30 13:47:25 -0800454class ReleaseTargetChecker:
455 def __init__(self, checker):
456 self._checker = checker
Luca Stefani4e91ee92019-03-06 15:08:16 +0100457
Andreas Gampe09123952019-01-30 13:17:02 -0800458 def __str__(self):
459 return 'Release (Target) Checker'
460
461 def run(self):
Martin Stjernholm2babede2019-03-18 21:04:49 +0000462 # Check the APEX package scripts.
Martin Stjernholmc17ace22019-03-18 21:47:31 +0000463 self._checker.check_executable('art_postinstall_hook')
464 self._checker.check_executable('art_preinstall_hook')
465 self._checker.check_executable('art_preinstall_hook_boot')
466 self._checker.check_executable('art_preinstall_hook_system_server')
467 self._checker.check_executable('art_prepostinstall_utils')
Martin Stjernholm2babede2019-03-18 21:04:49 +0000468
Martin Stjernholm023c2182019-03-28 15:52:32 +0000469 # Check binaries for ART.
Martin Stjernholm023c2182019-03-28 15:52:32 +0000470 self._checker.check_executable('oatdump')
471
472 # Check internal libraries for ART.
473 self._checker.check_prefer64_library('libart-disassembler')
474
475 # Check binaries for Bionic.
Martin Stjernholmc17ace22019-03-18 21:47:31 +0000476 self._checker.check_multilib_executable('linker')
477 self._checker.check_multilib_executable('linker_asan')
Martin Stjernholm2babede2019-03-18 21:04:49 +0000478
Martin Stjernholm023c2182019-03-28 15:52:32 +0000479 # Check libraries for Bionic.
Martin Stjernholmc17ace22019-03-18 21:47:31 +0000480 self._checker.check_native_library('bionic/libc')
481 self._checker.check_native_library('bionic/libdl')
482 self._checker.check_native_library('bionic/libm')
Jiyong Park408f7d02019-04-02 23:04:42 +0900483 # ... and its internal dependencies
484 self._checker.check_native_library('libc_malloc_hooks')
485 self._checker.check_native_library('libc_malloc_debug')
Martin Stjernholm2babede2019-03-18 21:04:49 +0000486
Martin Stjernholm023c2182019-03-28 15:52:32 +0000487 # Check exported native libraries for Managed Core Library.
Martin Stjernholmc17ace22019-03-18 21:47:31 +0000488 self._checker.check_native_library('libandroidicu')
489 self._checker.check_native_library('libandroidio')
Martin Stjernholm023c2182019-03-28 15:52:32 +0000490
491 # Check internal native library dependencies.
492 self._checker.check_native_library('libcrypto')
Martin Stjernholmc17ace22019-03-18 21:47:31 +0000493 self._checker.check_native_library('libexpat')
494 self._checker.check_native_library('libicui18n')
495 self._checker.check_native_library('libicuuc')
496 self._checker.check_native_library('libpac')
Martin Stjernholm023c2182019-03-28 15:52:32 +0000497 self._checker.check_native_library('libz')
Martin Stjernholm2babede2019-03-18 21:04:49 +0000498
Martin Stjernholm4160c122019-04-23 17:05:39 +0100499 # Guest architecture proxy libraries currently end up in these
500 # subdirectories in x86 builds with native bridge.
501 # TODO(b/131155689): These are unused - fix the build rules to avoid
502 # creating them.
Martin Stjernholmc17ace22019-03-18 21:47:31 +0000503 self._checker.ignore_path('lib/arm')
504 self._checker.ignore_path('lib/arm64')
Martin Stjernholm2babede2019-03-18 21:04:49 +0000505
Luca Stefani4e91ee92019-03-06 15:08:16 +0100506
Andreas Gampe9dc4b052019-01-30 13:47:25 -0800507class ReleaseHostChecker:
508 def __init__(self, checker):
Luca Stefani4e91ee92019-03-06 15:08:16 +0100509 self._checker = checker
510
Andreas Gampe09123952019-01-30 13:17:02 -0800511 def __str__(self):
512 return 'Release (Host) Checker'
513
514 def run(self):
Martin Stjernholm84a32cd2019-03-29 16:39:46 +0000515 # Check binaries for ART.
516 self._checker.check_executable('hprof-conv')
517 self._checker.check_symlinked_multilib_executable('dex2oatd')
518
Martin Stjernholm023c2182019-03-28 15:52:32 +0000519 # Check exported native libraries for Managed Core Library.
Martin Stjernholmc17ace22019-03-18 21:47:31 +0000520 self._checker.check_native_library('libandroidicu-host')
521 self._checker.check_native_library('libandroidio')
Martin Stjernholm023c2182019-03-28 15:52:32 +0000522
523 # Check internal libraries for Managed Core Library.
Martin Stjernholmc17ace22019-03-18 21:47:31 +0000524 self._checker.check_native_library('libexpat-host')
525 self._checker.check_native_library('libicui18n-host')
526 self._checker.check_native_library('libicuuc-host')
527 self._checker.check_native_library('libz-host')
Andreas Gampe09123952019-01-30 13:17:02 -0800528
Luca Stefani4e91ee92019-03-06 15:08:16 +0100529
Andreas Gampe9dc4b052019-01-30 13:47:25 -0800530class DebugChecker:
531 def __init__(self, checker):
532 self._checker = checker
Luca Stefani4e91ee92019-03-06 15:08:16 +0100533
Andreas Gampe2c846cd2019-01-29 22:06:46 +0000534 def __str__(self):
535 return 'Debug Checker'
536
537 def run(self):
Martin Stjernholm023c2182019-03-28 15:52:32 +0000538 # Check binaries for ART.
Martin Stjernholmc17ace22019-03-18 21:47:31 +0000539 self._checker.check_executable('dexdiag')
Andreas Gampe2c846cd2019-01-29 22:06:46 +0000540
Martin Stjernholm023c2182019-03-28 15:52:32 +0000541 # Check debug binaries for ART.
Martin Stjernholmc17ace22019-03-18 21:47:31 +0000542 self._checker.check_executable('dexoptanalyzerd')
543 self._checker.check_executable('profmand')
Martin Stjernholm023c2182019-03-28 15:52:32 +0000544 self._checker.check_symlinked_prefer32_executable('dex2oatd')
Andreas Gampe2c846cd2019-01-29 22:06:46 +0000545
Martin Stjernholm023c2182019-03-28 15:52:32 +0000546 # Check internal libraries for ART.
547 self._checker.check_native_library('libadbconnectiond')
Martin Stjernholmc17ace22019-03-18 21:47:31 +0000548 self._checker.check_native_library('libartbased')
Martin Stjernholm023c2182019-03-28 15:52:32 +0000549 self._checker.check_native_library('libartd')
Martin Stjernholmc17ace22019-03-18 21:47:31 +0000550 self._checker.check_native_library('libartd-compiler')
551 self._checker.check_native_library('libartd-dexlayout')
Martin Stjernholmc17ace22019-03-18 21:47:31 +0000552 self._checker.check_native_library('libdexfiled')
553 self._checker.check_native_library('libopenjdkjvmd')
554 self._checker.check_native_library('libopenjdkjvmtid')
555 self._checker.check_native_library('libprofiled')
Martin Stjernholm023c2182019-03-28 15:52:32 +0000556
557 # Check internal libraries for Managed Core Library.
Martin Stjernholmc17ace22019-03-18 21:47:31 +0000558 self._checker.check_native_library('libopenjdkd')
Andreas Gampe2c846cd2019-01-29 22:06:46 +0000559
Luca Stefani4e91ee92019-03-06 15:08:16 +0100560
Andreas Gampe9dc4b052019-01-30 13:47:25 -0800561class DebugTargetChecker:
562 def __init__(self, checker):
563 self._checker = checker
Luca Stefani4e91ee92019-03-06 15:08:16 +0100564
Andreas Gampea0242cf2019-01-29 13:01:23 -0800565 def __str__(self):
566 return 'Debug (Target) Checker'
567
568 def run(self):
Martin Stjernholm023c2182019-03-28 15:52:32 +0000569 # Check ART debug binaries.
Martin Stjernholmc17ace22019-03-18 21:47:31 +0000570 self._checker.check_executable('oatdumpd')
Martin Stjernholm023c2182019-03-28 15:52:32 +0000571
572 # Check ART internal libraries.
Martin Stjernholm356864a2019-04-30 16:22:17 +0100573 self._checker.check_native_library('libdexfiled_external')
Martin Stjernholmc17ace22019-03-18 21:47:31 +0000574 self._checker.check_prefer64_library('libartd-disassembler')
Andreas Gampea0242cf2019-01-29 13:01:23 -0800575
Martin Stjernholm2babede2019-03-18 21:04:49 +0000576 # Check internal native library dependencies.
577 #
578 # Like in the release package, we check that we don't get other dependencies
579 # besides those listed here. In this case the concern is not bloat, but
580 # rather that we don't get behavioural differences between user (release)
581 # and userdebug/eng builds, which could happen if the debug package has
582 # duplicate library instances where releases don't. In other words, it's
583 # uncontroversial to add debug-only dependencies, as long as they don't make
584 # assumptions on having a single global state (ideally they should have
585 # double_loadable:true, cf. go/double_loadable). Also, like in the release
586 # package we need to look out for dependencies that should go through
587 # exported library stubs (until b/128708192 is fixed).
Martin Stjernholmc17ace22019-03-18 21:47:31 +0000588 self._checker.check_optional_native_library('libvixld') # Only on ARM/ARM64
Martin Stjernholm77f17662019-04-03 17:08:21 +0100589 self._checker.check_prefer64_library('libmeminfo')
590 self._checker.check_prefer64_library('libprocinfo')
Martin Stjernholm2babede2019-03-18 21:04:49 +0000591
592
593class NoSuperfluousBinariesChecker:
594 def __init__(self, checker):
595 self._checker = checker
596
597 def __str__(self):
598 return 'No superfluous binaries checker'
599
600 def run(self):
601 self._checker.check_no_superfluous_files('bin')
602
603
604class NoSuperfluousLibrariesChecker:
605 def __init__(self, checker):
606 self._checker = checker
607
608 def __str__(self):
609 return 'No superfluous libraries checker'
610
611 def run(self):
612 self._checker.check_no_superfluous_files('javalib')
613 self._checker.check_no_superfluous_files('lib')
614 self._checker.check_no_superfluous_files('lib/bionic')
615 self._checker.check_no_superfluous_files('lib64')
616 self._checker.check_no_superfluous_files('lib64/bionic')
617
Andreas Gampeb1d55672019-01-29 22:17:02 +0000618
Luca Stefani4e91ee92019-03-06 15:08:16 +0100619class List:
620 def __init__(self, provider):
621 self._provider = provider
622 self._path = ''
623
624 def print_list(self):
625 apex_map = self._provider.read_dir(self._path)
626 if apex_map is None:
627 return
628 apex_map = dict(apex_map)
629 if '.' in apex_map:
630 del apex_map['.']
631 if '..' in apex_map:
632 del apex_map['..']
633 for (_, val) in sorted(apex_map.items()):
634 self._path = os.path.join(self._path, val.name)
635 print(self._path)
636 if val.is_dir:
637 self.print_list()
638
639
640class Tree:
641 def __init__(self, provider, title):
642 print('%s' % title)
643 self._provider = provider
644 self._path = ''
645 self._has_next_list = []
646
647 @staticmethod
648 def get_vertical(has_next_list):
649 string = ''
650 for v in has_next_list:
651 string += '%s ' % ('│' if v else ' ')
652 return string
653
654 @staticmethod
655 def get_last_vertical(last):
656 return '└── ' if last else '├── '
657
658 def print_tree(self):
659 apex_map = self._provider.read_dir(self._path)
660 if apex_map is None:
661 return
662 apex_map = dict(apex_map)
663 if '.' in apex_map:
664 del apex_map['.']
665 if '..' in apex_map:
666 del apex_map['..']
667 key_list = list(sorted(apex_map.keys()))
Andreas Gampe7dd0f0f2019-03-14 16:55:25 -0700668 for i, key in enumerate(key_list):
Luca Stefani4e91ee92019-03-06 15:08:16 +0100669 prev = self.get_vertical(self._has_next_list)
670 last = self.get_last_vertical(i == len(key_list) - 1)
Andreas Gampe7dd0f0f2019-03-14 16:55:25 -0700671 val = apex_map[key]
Luca Stefani4e91ee92019-03-06 15:08:16 +0100672 print('%s%s%s' % (prev, last, val.name))
673 if val.is_dir:
674 self._has_next_list.append(i < len(key_list) - 1)
Andreas Gampe7dd0f0f2019-03-14 16:55:25 -0700675 saved_dir = self._path
Luca Stefani4e91ee92019-03-06 15:08:16 +0100676 self._path = os.path.join(self._path, val.name)
677 self.print_tree()
Andreas Gampe7dd0f0f2019-03-14 16:55:25 -0700678 self._path = saved_dir
Luca Stefani4e91ee92019-03-06 15:08:16 +0100679 self._has_next_list.pop()
680
Andreas Gampeb1d55672019-01-29 22:17:02 +0000681
Andreas Gampe2c846cd2019-01-29 22:06:46 +0000682# Note: do not sys.exit early, for __del__ cleanup.
Luca Stefani4e91ee92019-03-06 15:08:16 +0100683def art_apex_test_main(test_args):
684 if test_args.tree and test_args.debug:
Andreas Gampe09123952019-01-30 13:17:02 -0800685 logging.error("Both of --tree and --debug set")
Andreas Gampeb1d55672019-01-29 22:17:02 +0000686 return 1
Luca Stefani4e91ee92019-03-06 15:08:16 +0100687 if test_args.list and test_args.debug:
Andreas Gampe09123952019-01-30 13:17:02 -0800688 logging.error("Both of --list and --debug set")
Andreas Gampeb1d55672019-01-29 22:17:02 +0000689 return 1
Luca Stefani4e91ee92019-03-06 15:08:16 +0100690 if test_args.list and test_args.tree:
Andreas Gampeb1d55672019-01-29 22:17:02 +0000691 logging.error("Both of --list and --tree set")
Andreas Gampe2c846cd2019-01-29 22:06:46 +0000692 return 1
Luca Stefani4e91ee92019-03-06 15:08:16 +0100693 if not test_args.tmpdir:
Andreas Gampe2c846cd2019-01-29 22:06:46 +0000694 logging.error("Need a tmpdir.")
695 return 1
Luca Stefani4e91ee92019-03-06 15:08:16 +0100696 if not test_args.host and not test_args.debugfs:
Andreas Gampe2c846cd2019-01-29 22:06:46 +0000697 logging.error("Need debugfs.")
698 return 1
Luca Stefani4e91ee92019-03-06 15:08:16 +0100699 if test_args.bitness not in ['32', '64', 'multilib', 'auto']:
Andreas Gampeeb555b82019-01-30 14:47:49 -0800700 logging.error('--bitness needs to be one of 32|64|multilib|auto')
Andreas Gampe2c846cd2019-01-29 22:06:46 +0000701
702 try:
Luca Stefani4e91ee92019-03-06 15:08:16 +0100703 if test_args.host:
704 apex_provider = HostApexProvider(test_args.apex, test_args.tmpdir)
Andreas Gampe09123952019-01-30 13:17:02 -0800705 else:
Luca Stefani4e91ee92019-03-06 15:08:16 +0100706 apex_provider = TargetApexProvider(test_args.apex, test_args.tmpdir, test_args.debugfs)
707 except (zipfile.BadZipFile, zipfile.LargeZipFile) as e:
Andreas Gampea0242cf2019-01-29 13:01:23 -0800708 logging.error('Failed to create provider: %s', e)
Andreas Gampe2c846cd2019-01-29 22:06:46 +0000709 return 1
710
Luca Stefani4e91ee92019-03-06 15:08:16 +0100711 if test_args.tree:
712 Tree(apex_provider, test_args.apex).print_tree()
Andreas Gampeb1d55672019-01-29 22:17:02 +0000713 return 0
Luca Stefani4e91ee92019-03-06 15:08:16 +0100714 if test_args.list:
715 List(apex_provider).print_list()
Andreas Gampeb1d55672019-01-29 22:17:02 +0000716 return 0
717
Andreas Gampe2c846cd2019-01-29 22:06:46 +0000718 checkers = []
Luca Stefani4e91ee92019-03-06 15:08:16 +0100719 if test_args.bitness == 'auto':
720 logging.warning('--bitness=auto, trying to autodetect. This may be incorrect!')
Andreas Gampeeb555b82019-01-30 14:47:49 -0800721 has_32 = apex_provider.get('lib') is not None
722 has_64 = apex_provider.get('lib64') is not None
723 if has_32 and has_64:
Luca Stefani4e91ee92019-03-06 15:08:16 +0100724 logging.warning(' Detected multilib')
725 test_args.bitness = 'multilib'
Andreas Gampeeb555b82019-01-30 14:47:49 -0800726 elif has_32:
Luca Stefani4e91ee92019-03-06 15:08:16 +0100727 logging.warning(' Detected 32-only')
728 test_args.bitness = '32'
Andreas Gampeeb555b82019-01-30 14:47:49 -0800729 elif has_64:
Luca Stefani4e91ee92019-03-06 15:08:16 +0100730 logging.warning(' Detected 64-only')
731 test_args.bitness = '64'
Andreas Gampeeb555b82019-01-30 14:47:49 -0800732 else:
733 logging.error(' Could not detect bitness, neither lib nor lib64 contained.')
Luca Stefani4e91ee92019-03-06 15:08:16 +0100734 print('%s' % apex_provider.folder_cache)
Andreas Gampeeb555b82019-01-30 14:47:49 -0800735 return 1
736
Luca Stefani4e91ee92019-03-06 15:08:16 +0100737 if test_args.bitness == '32':
Andreas Gampeeb555b82019-01-30 14:47:49 -0800738 base_checker = Arch32Checker(apex_provider)
Luca Stefani4e91ee92019-03-06 15:08:16 +0100739 elif test_args.bitness == '64':
Andreas Gampeeb555b82019-01-30 14:47:49 -0800740 base_checker = Arch64Checker(apex_provider)
741 else:
Luca Stefani4e91ee92019-03-06 15:08:16 +0100742 assert test_args.bitness == 'multilib'
Andreas Gampeeb555b82019-01-30 14:47:49 -0800743 base_checker = MultilibChecker(apex_provider)
Andreas Gampe2c846cd2019-01-29 22:06:46 +0000744
Andreas Gampe9dc4b052019-01-30 13:47:25 -0800745 checkers.append(ReleaseChecker(base_checker))
Luca Stefani4e91ee92019-03-06 15:08:16 +0100746 if test_args.host:
Andreas Gampe9dc4b052019-01-30 13:47:25 -0800747 checkers.append(ReleaseHostChecker(base_checker))
Andreas Gampe09123952019-01-30 13:17:02 -0800748 else:
Andreas Gampe9dc4b052019-01-30 13:47:25 -0800749 checkers.append(ReleaseTargetChecker(base_checker))
Luca Stefani4e91ee92019-03-06 15:08:16 +0100750 if test_args.debug:
Andreas Gampe9dc4b052019-01-30 13:47:25 -0800751 checkers.append(DebugChecker(base_checker))
Luca Stefani4e91ee92019-03-06 15:08:16 +0100752 if test_args.debug and not test_args.host:
Andreas Gampe9dc4b052019-01-30 13:47:25 -0800753 checkers.append(DebugTargetChecker(base_checker))
Andreas Gampe2c846cd2019-01-29 22:06:46 +0000754
Martin Stjernholm2babede2019-03-18 21:04:49 +0000755 # These checkers must be last.
756 checkers.append(NoSuperfluousBinariesChecker(base_checker))
757 if not test_args.host:
758 # We only care about superfluous libraries on target, where their absence
759 # can be vital to ensure they get picked up from the right package.
760 checkers.append(NoSuperfluousLibrariesChecker(base_checker))
761
Andreas Gampe2c846cd2019-01-29 22:06:46 +0000762 failed = False
763 for checker in checkers:
764 logging.info('%s...', checker)
765 checker.run()
Andreas Gampe9dc4b052019-01-30 13:47:25 -0800766 if base_checker.error_count() > 0:
Andreas Gampe2c846cd2019-01-29 22:06:46 +0000767 logging.error('%s FAILED', checker)
768 failed = True
769 else:
770 logging.info('%s SUCCEEDED', checker)
Andreas Gampe9dc4b052019-01-30 13:47:25 -0800771 base_checker.reset_errors()
Andreas Gampe2c846cd2019-01-29 22:06:46 +0000772
773 return 1 if failed else 0
774
Luca Stefani4e91ee92019-03-06 15:08:16 +0100775
776def art_apex_test_default(test_parser):
777 if 'ANDROID_PRODUCT_OUT' not in os.environ:
Andreas Gampe2c846cd2019-01-29 22:06:46 +0000778 logging.error('No-argument use requires ANDROID_PRODUCT_OUT')
779 sys.exit(1)
780 product_out = os.environ['ANDROID_PRODUCT_OUT']
Luca Stefani4e91ee92019-03-06 15:08:16 +0100781 if 'ANDROID_HOST_OUT' not in os.environ:
Andreas Gampe2c846cd2019-01-29 22:06:46 +0000782 logging.error('No-argument use requires ANDROID_HOST_OUT')
783 sys.exit(1)
784 host_out = os.environ['ANDROID_HOST_OUT']
785
Luca Stefani4e91ee92019-03-06 15:08:16 +0100786 test_args = test_parser.parse_args(['dummy']) # For consistency.
787 test_args.debugfs = '%s/bin/debugfs' % host_out
788 test_args.tmpdir = '.'
789 test_args.tree = False
790 test_args.list = False
791 test_args.bitness = 'auto'
Andreas Gampe2c846cd2019-01-29 22:06:46 +0000792 failed = False
793
Luca Stefani4e91ee92019-03-06 15:08:16 +0100794 if not os.path.exists(test_args.debugfs):
Andreas Gampe2c846cd2019-01-29 22:06:46 +0000795 logging.error("Cannot find debugfs (default path %s). Please build it, e.g., m debugfs",
Luca Stefani4e91ee92019-03-06 15:08:16 +0100796 test_args.debugfs)
Andreas Gampe2c846cd2019-01-29 22:06:46 +0000797 sys.exit(1)
798
799 # TODO: Add host support
Luca Stefani4e91ee92019-03-06 15:08:16 +0100800 configs = [
Andreas Gampe09123952019-01-30 13:17:02 -0800801 {'name': 'com.android.runtime.release', 'debug': False, 'host': False},
802 {'name': 'com.android.runtime.debug', 'debug': True, 'host': False},
Andreas Gampe2c846cd2019-01-29 22:06:46 +0000803 ]
804
805 for config in configs:
806 logging.info(config['name'])
807 # TODO: Host will need different path.
Luca Stefani4e91ee92019-03-06 15:08:16 +0100808 test_args.apex = '%s/system/apex/%s.apex' % (product_out, config['name'])
809 if not os.path.exists(test_args.apex):
Andreas Gampe2c846cd2019-01-29 22:06:46 +0000810 failed = True
Luca Stefani4e91ee92019-03-06 15:08:16 +0100811 logging.error("Cannot find APEX %s. Please build it first.", test_args.apex)
Andreas Gampe2c846cd2019-01-29 22:06:46 +0000812 continue
Luca Stefani4e91ee92019-03-06 15:08:16 +0100813 test_args.debug = config['debug']
814 test_args.host = config['host']
815 failed = art_apex_test_main(test_args) != 0
Andreas Gampe2c846cd2019-01-29 22:06:46 +0000816
817 if failed:
818 sys.exit(1)
819
Luca Stefani4e91ee92019-03-06 15:08:16 +0100820
Andreas Gampe2c846cd2019-01-29 22:06:46 +0000821if __name__ == "__main__":
822 parser = argparse.ArgumentParser(description='Check integrity of a Runtime APEX.')
823
824 parser.add_argument('apex', help='apex file input')
825
826 parser.add_argument('--host', help='Check as host apex', action='store_true')
Andreas Gampe09123952019-01-30 13:17:02 -0800827
Andreas Gampe2c846cd2019-01-29 22:06:46 +0000828 parser.add_argument('--debug', help='Check as debug apex', action='store_true')
829
Andreas Gampeb1d55672019-01-29 22:17:02 +0000830 parser.add_argument('--list', help='List all files', action='store_true')
831 parser.add_argument('--tree', help='Print directory tree', action='store_true')
832
Andreas Gampe2c846cd2019-01-29 22:06:46 +0000833 parser.add_argument('--tmpdir', help='Directory for temp files')
834 parser.add_argument('--debugfs', help='Path to debugfs')
835
Andreas Gampeeb555b82019-01-30 14:47:49 -0800836 parser.add_argument('--bitness', help='Bitness to check, 32|64|multilib|auto', default='auto')
837
Andreas Gampe2c846cd2019-01-29 22:06:46 +0000838 if len(sys.argv) == 1:
Luca Stefani4e91ee92019-03-06 15:08:16 +0100839 art_apex_test_default(parser)
Andreas Gampe2c846cd2019-01-29 22:06:46 +0000840 else:
841 args = parser.parse_args()
842
843 if args is None:
844 sys.exit(1)
845
Luca Stefani4e91ee92019-03-06 15:08:16 +0100846 exit_code = art_apex_test_main(args)
Andreas Gampe2c846cd2019-01-29 22:06:46 +0000847 sys.exit(exit_code)