xref: /aosp_15_r20/development/vndk/tools/header-checker/utils/utils.py (revision 90c8c64db3049935a07c6143d7fd006e26f8ecca)
1*90c8c64dSAndroid Build Coastguard Worker#!/usr/bin/env python3
2*90c8c64dSAndroid Build Coastguard Worker
3*90c8c64dSAndroid Build Coastguard Workerimport collections
4*90c8c64dSAndroid Build Coastguard Workerimport os
5*90c8c64dSAndroid Build Coastguard Workerimport re
6*90c8c64dSAndroid Build Coastguard Workerimport shutil
7*90c8c64dSAndroid Build Coastguard Workerimport subprocess
8*90c8c64dSAndroid Build Coastguard Workerimport sys
9*90c8c64dSAndroid Build Coastguard Workerimport tempfile
10*90c8c64dSAndroid Build Coastguard Workerimport collections
11*90c8c64dSAndroid Build Coastguard Worker
12*90c8c64dSAndroid Build Coastguard Worker
13*90c8c64dSAndroid Build Coastguard WorkerSCRIPT_DIR = os.path.abspath(os.path.dirname(__file__))
14*90c8c64dSAndroid Build Coastguard Worker
15*90c8c64dSAndroid Build Coastguard Workertry:
16*90c8c64dSAndroid Build Coastguard Worker    AOSP_DIR = os.environ['ANDROID_BUILD_TOP']
17*90c8c64dSAndroid Build Coastguard Workerexcept KeyError:
18*90c8c64dSAndroid Build Coastguard Worker    print('error: ANDROID_BUILD_TOP environment variable is not set.',
19*90c8c64dSAndroid Build Coastguard Worker          file=sys.stderr)
20*90c8c64dSAndroid Build Coastguard Worker    sys.exit(1)
21*90c8c64dSAndroid Build Coastguard Worker
22*90c8c64dSAndroid Build Coastguard WorkerBUILTIN_HEADERS_DIR = (
23*90c8c64dSAndroid Build Coastguard Worker    os.path.join(AOSP_DIR, 'bionic', 'libc', 'include'),
24*90c8c64dSAndroid Build Coastguard Worker    os.path.join(AOSP_DIR, 'external', 'libcxx', 'include'),
25*90c8c64dSAndroid Build Coastguard Worker    os.path.join(AOSP_DIR, 'prebuilts', 'clang-tools', 'linux-x86',
26*90c8c64dSAndroid Build Coastguard Worker                 'clang-headers'),
27*90c8c64dSAndroid Build Coastguard Worker)
28*90c8c64dSAndroid Build Coastguard Worker
29*90c8c64dSAndroid Build Coastguard WorkerSO_EXT = '.so'
30*90c8c64dSAndroid Build Coastguard WorkerSOURCE_ABI_DUMP_EXT_END = '.lsdump'
31*90c8c64dSAndroid Build Coastguard WorkerSOURCE_ABI_DUMP_EXT = SO_EXT + SOURCE_ABI_DUMP_EXT_END
32*90c8c64dSAndroid Build Coastguard WorkerKNOWN_ABI_DUMP_EXTS = {
33*90c8c64dSAndroid Build Coastguard Worker    SOURCE_ABI_DUMP_EXT,
34*90c8c64dSAndroid Build Coastguard Worker    SO_EXT + '.apex' + SOURCE_ABI_DUMP_EXT_END,
35*90c8c64dSAndroid Build Coastguard Worker    SO_EXT + '.llndk' + SOURCE_ABI_DUMP_EXT_END,
36*90c8c64dSAndroid Build Coastguard Worker}
37*90c8c64dSAndroid Build Coastguard Worker
38*90c8c64dSAndroid Build Coastguard WorkerDEFAULT_CPPFLAGS = ['-x', 'c++', '-std=c++11']
39*90c8c64dSAndroid Build Coastguard WorkerDEFAULT_CFLAGS = ['-std=gnu99']
40*90c8c64dSAndroid Build Coastguard WorkerDEFAULT_HEADER_FLAGS = ["-dump-function-declarations"]
41*90c8c64dSAndroid Build Coastguard WorkerDEFAULT_FORMAT = 'ProtobufTextFormat'
42*90c8c64dSAndroid Build Coastguard Worker
43*90c8c64dSAndroid Build Coastguard WorkerBuildTarget = collections.namedtuple(
44*90c8c64dSAndroid Build Coastguard Worker    'BuildTarget', ['product', 'release', 'variant'])
45*90c8c64dSAndroid Build Coastguard Worker
46*90c8c64dSAndroid Build Coastguard Worker
47*90c8c64dSAndroid Build Coastguard Workerclass Arch(object):
48*90c8c64dSAndroid Build Coastguard Worker    """A CPU architecture of a build target."""
49*90c8c64dSAndroid Build Coastguard Worker    def __init__(self, is_2nd, build_target):
50*90c8c64dSAndroid Build Coastguard Worker        extra = '_2ND' if is_2nd else ''
51*90c8c64dSAndroid Build Coastguard Worker        build_vars_to_fetch = ['TARGET_ARCH',
52*90c8c64dSAndroid Build Coastguard Worker                               'TARGET{}_ARCH'.format(extra),
53*90c8c64dSAndroid Build Coastguard Worker                               'TARGET{}_ARCH_VARIANT'.format(extra),
54*90c8c64dSAndroid Build Coastguard Worker                               'TARGET{}_CPU_VARIANT'.format(extra)]
55*90c8c64dSAndroid Build Coastguard Worker        build_vars = get_build_vars(build_vars_to_fetch, build_target)
56*90c8c64dSAndroid Build Coastguard Worker        self.primary_arch = build_vars[0]
57*90c8c64dSAndroid Build Coastguard Worker        assert self.primary_arch != ''
58*90c8c64dSAndroid Build Coastguard Worker        self.arch = build_vars[1]
59*90c8c64dSAndroid Build Coastguard Worker        self.arch_variant = build_vars[2]
60*90c8c64dSAndroid Build Coastguard Worker        self.cpu_variant = build_vars[3]
61*90c8c64dSAndroid Build Coastguard Worker
62*90c8c64dSAndroid Build Coastguard Worker    def get_arch_str(self):
63*90c8c64dSAndroid Build Coastguard Worker        """Return a string that represents the architecture and the primary
64*90c8c64dSAndroid Build Coastguard Worker        architecture.
65*90c8c64dSAndroid Build Coastguard Worker        """
66*90c8c64dSAndroid Build Coastguard Worker        if not self.arch or self.arch == self.primary_arch:
67*90c8c64dSAndroid Build Coastguard Worker            return self.primary_arch
68*90c8c64dSAndroid Build Coastguard Worker        return self.arch + '_' + self.primary_arch
69*90c8c64dSAndroid Build Coastguard Worker
70*90c8c64dSAndroid Build Coastguard Worker    def get_arch_cpu_str(self):
71*90c8c64dSAndroid Build Coastguard Worker        """Return a string that represents the architecture, the architecture
72*90c8c64dSAndroid Build Coastguard Worker        variant, and the CPU variant.
73*90c8c64dSAndroid Build Coastguard Worker
74*90c8c64dSAndroid Build Coastguard Worker        If TARGET_ARCH == TARGET_ARCH_VARIANT, soong makes targetArchVariant
75*90c8c64dSAndroid Build Coastguard Worker        empty. This is the case for aosp_x86_64.
76*90c8c64dSAndroid Build Coastguard Worker        """
77*90c8c64dSAndroid Build Coastguard Worker        if not self.arch_variant or self.arch_variant == self.arch:
78*90c8c64dSAndroid Build Coastguard Worker            arch_variant = ''
79*90c8c64dSAndroid Build Coastguard Worker        else:
80*90c8c64dSAndroid Build Coastguard Worker            arch_variant = '_' + self.arch_variant
81*90c8c64dSAndroid Build Coastguard Worker
82*90c8c64dSAndroid Build Coastguard Worker        if not self.cpu_variant or self.cpu_variant == 'generic':
83*90c8c64dSAndroid Build Coastguard Worker            cpu_variant = ''
84*90c8c64dSAndroid Build Coastguard Worker        else:
85*90c8c64dSAndroid Build Coastguard Worker            cpu_variant = '_' + self.cpu_variant
86*90c8c64dSAndroid Build Coastguard Worker
87*90c8c64dSAndroid Build Coastguard Worker        return self.arch + arch_variant + cpu_variant
88*90c8c64dSAndroid Build Coastguard Worker
89*90c8c64dSAndroid Build Coastguard Worker
90*90c8c64dSAndroid Build Coastguard Workerdef _strip_dump_name_ext(filename):
91*90c8c64dSAndroid Build Coastguard Worker    """Remove .so*.lsdump from a file name."""
92*90c8c64dSAndroid Build Coastguard Worker    for ext in KNOWN_ABI_DUMP_EXTS:
93*90c8c64dSAndroid Build Coastguard Worker        if filename.endswith(ext) and len(filename) > len(ext):
94*90c8c64dSAndroid Build Coastguard Worker            return filename[:-len(ext)]
95*90c8c64dSAndroid Build Coastguard Worker    raise ValueError(f'{filename} has an unknown file name extension.')
96*90c8c64dSAndroid Build Coastguard Worker
97*90c8c64dSAndroid Build Coastguard Worker
98*90c8c64dSAndroid Build Coastguard Workerdef _validate_dump_content(dump_path):
99*90c8c64dSAndroid Build Coastguard Worker    """Make sure that the dump contains relative source paths."""
100*90c8c64dSAndroid Build Coastguard Worker    with open(dump_path, 'r') as f:
101*90c8c64dSAndroid Build Coastguard Worker        for line_number, line in enumerate(f, 1):
102*90c8c64dSAndroid Build Coastguard Worker            start = 0
103*90c8c64dSAndroid Build Coastguard Worker            while True:
104*90c8c64dSAndroid Build Coastguard Worker                start = line.find(AOSP_DIR, start)
105*90c8c64dSAndroid Build Coastguard Worker                if start < 0:
106*90c8c64dSAndroid Build Coastguard Worker                    break
107*90c8c64dSAndroid Build Coastguard Worker                # The substring is not preceded by a common path character.
108*90c8c64dSAndroid Build Coastguard Worker                if start == 0 or not (line[start - 1].isalnum() or
109*90c8c64dSAndroid Build Coastguard Worker                                      line[start - 1] in '.-_/'):
110*90c8c64dSAndroid Build Coastguard Worker                    raise ValueError(f'{dump_path} contains absolute path to '
111*90c8c64dSAndroid Build Coastguard Worker                                     f'$ANDROID_BUILD_TOP at line '
112*90c8c64dSAndroid Build Coastguard Worker                                     f'{line_number}:\n{line}')
113*90c8c64dSAndroid Build Coastguard Worker                start += len(AOSP_DIR)
114*90c8c64dSAndroid Build Coastguard Worker
115*90c8c64dSAndroid Build Coastguard Worker
116*90c8c64dSAndroid Build Coastguard Workerdef copy_reference_dump(lib_path, reference_dump_dir):
117*90c8c64dSAndroid Build Coastguard Worker    _validate_dump_content(lib_path)
118*90c8c64dSAndroid Build Coastguard Worker    ref_dump_name = (_strip_dump_name_ext(os.path.basename(lib_path)) +
119*90c8c64dSAndroid Build Coastguard Worker                     SOURCE_ABI_DUMP_EXT)
120*90c8c64dSAndroid Build Coastguard Worker    ref_dump_path = os.path.join(reference_dump_dir, ref_dump_name)
121*90c8c64dSAndroid Build Coastguard Worker    os.makedirs(reference_dump_dir, exist_ok=True)
122*90c8c64dSAndroid Build Coastguard Worker    shutil.copyfile(lib_path, ref_dump_path)
123*90c8c64dSAndroid Build Coastguard Worker    print(f'Created abi dump at {ref_dump_path}')
124*90c8c64dSAndroid Build Coastguard Worker    return ref_dump_path
125*90c8c64dSAndroid Build Coastguard Worker
126*90c8c64dSAndroid Build Coastguard Worker
127*90c8c64dSAndroid Build Coastguard Workerdef run_header_abi_dumper(input_path, output_path, cflags=tuple(),
128*90c8c64dSAndroid Build Coastguard Worker                          export_include_dirs=tuple(), flags=tuple()):
129*90c8c64dSAndroid Build Coastguard Worker    """Run header-abi-dumper to dump ABI from `input_path` and the output is
130*90c8c64dSAndroid Build Coastguard Worker    written to `output_path`."""
131*90c8c64dSAndroid Build Coastguard Worker    input_ext = os.path.splitext(input_path)[1]
132*90c8c64dSAndroid Build Coastguard Worker    cmd = ['header-abi-dumper', '-o', output_path, input_path]
133*90c8c64dSAndroid Build Coastguard Worker    for dir in export_include_dirs:
134*90c8c64dSAndroid Build Coastguard Worker        cmd += ['-I', dir]
135*90c8c64dSAndroid Build Coastguard Worker    cmd += flags
136*90c8c64dSAndroid Build Coastguard Worker    if '-output-format' not in flags:
137*90c8c64dSAndroid Build Coastguard Worker        cmd += ['-output-format', DEFAULT_FORMAT]
138*90c8c64dSAndroid Build Coastguard Worker    if input_ext == ".h":
139*90c8c64dSAndroid Build Coastguard Worker        cmd += DEFAULT_HEADER_FLAGS
140*90c8c64dSAndroid Build Coastguard Worker    cmd += ['--']
141*90c8c64dSAndroid Build Coastguard Worker    cmd += cflags
142*90c8c64dSAndroid Build Coastguard Worker    if input_ext in ('.cpp', '.cc', '.h'):
143*90c8c64dSAndroid Build Coastguard Worker        cmd += DEFAULT_CPPFLAGS
144*90c8c64dSAndroid Build Coastguard Worker    else:
145*90c8c64dSAndroid Build Coastguard Worker        cmd += DEFAULT_CFLAGS
146*90c8c64dSAndroid Build Coastguard Worker
147*90c8c64dSAndroid Build Coastguard Worker    for dir in BUILTIN_HEADERS_DIR:
148*90c8c64dSAndroid Build Coastguard Worker        cmd += ['-isystem', dir]
149*90c8c64dSAndroid Build Coastguard Worker    # The export include dirs imply local include dirs.
150*90c8c64dSAndroid Build Coastguard Worker    for dir in export_include_dirs:
151*90c8c64dSAndroid Build Coastguard Worker        cmd += ['-I', dir]
152*90c8c64dSAndroid Build Coastguard Worker    subprocess.check_call(cmd, cwd=AOSP_DIR)
153*90c8c64dSAndroid Build Coastguard Worker    _validate_dump_content(output_path)
154*90c8c64dSAndroid Build Coastguard Worker
155*90c8c64dSAndroid Build Coastguard Worker
156*90c8c64dSAndroid Build Coastguard Workerdef run_header_abi_linker(inputs, output_path, version_script, api, arch_str,
157*90c8c64dSAndroid Build Coastguard Worker                          flags=tuple()):
158*90c8c64dSAndroid Build Coastguard Worker    """Link inputs, taking version_script into account"""
159*90c8c64dSAndroid Build Coastguard Worker    cmd = ['header-abi-linker', '-o', output_path, '-v', version_script,
160*90c8c64dSAndroid Build Coastguard Worker           '-api', api, '-arch', arch_str]
161*90c8c64dSAndroid Build Coastguard Worker    cmd += flags
162*90c8c64dSAndroid Build Coastguard Worker    if '-input-format' not in flags:
163*90c8c64dSAndroid Build Coastguard Worker        cmd += ['-input-format', DEFAULT_FORMAT]
164*90c8c64dSAndroid Build Coastguard Worker    if '-output-format' not in flags:
165*90c8c64dSAndroid Build Coastguard Worker        cmd += ['-output-format', DEFAULT_FORMAT]
166*90c8c64dSAndroid Build Coastguard Worker    cmd += inputs
167*90c8c64dSAndroid Build Coastguard Worker    subprocess.check_call(cmd, cwd=AOSP_DIR)
168*90c8c64dSAndroid Build Coastguard Worker    _validate_dump_content(output_path)
169*90c8c64dSAndroid Build Coastguard Worker
170*90c8c64dSAndroid Build Coastguard Worker
171*90c8c64dSAndroid Build Coastguard Workerdef make_targets(build_target, args):
172*90c8c64dSAndroid Build Coastguard Worker    make_cmd = ['build/soong/soong_ui.bash', '--make-mode', '-j',
173*90c8c64dSAndroid Build Coastguard Worker                'TARGET_PRODUCT=' + build_target.product,
174*90c8c64dSAndroid Build Coastguard Worker                'TARGET_BUILD_VARIANT=' + build_target.variant]
175*90c8c64dSAndroid Build Coastguard Worker    if build_target.release:
176*90c8c64dSAndroid Build Coastguard Worker        make_cmd.append('TARGET_RELEASE=' + build_target.release)
177*90c8c64dSAndroid Build Coastguard Worker    make_cmd += args
178*90c8c64dSAndroid Build Coastguard Worker    subprocess.check_call(make_cmd, cwd=AOSP_DIR)
179*90c8c64dSAndroid Build Coastguard Worker
180*90c8c64dSAndroid Build Coastguard Worker
181*90c8c64dSAndroid Build Coastguard Workerdef make_libraries(build_target, arches, libs, lsdump_filter):
182*90c8c64dSAndroid Build Coastguard Worker    """Build lsdump files for specific libs."""
183*90c8c64dSAndroid Build Coastguard Worker    lsdump_paths = read_lsdump_paths(build_target, arches, lsdump_filter,
184*90c8c64dSAndroid Build Coastguard Worker                                     build=True)
185*90c8c64dSAndroid Build Coastguard Worker    make_target_paths = []
186*90c8c64dSAndroid Build Coastguard Worker    for name in libs:
187*90c8c64dSAndroid Build Coastguard Worker        if not (name in lsdump_paths and lsdump_paths[name]):
188*90c8c64dSAndroid Build Coastguard Worker            raise KeyError('Cannot find lsdump for %s.' % name)
189*90c8c64dSAndroid Build Coastguard Worker        for tag_path_dict in lsdump_paths[name].values():
190*90c8c64dSAndroid Build Coastguard Worker            make_target_paths.extend(tag_path_dict.values())
191*90c8c64dSAndroid Build Coastguard Worker    make_targets(build_target, make_target_paths)
192*90c8c64dSAndroid Build Coastguard Worker
193*90c8c64dSAndroid Build Coastguard Worker
194*90c8c64dSAndroid Build Coastguard Workerdef get_lsdump_paths_file_path(build_target):
195*90c8c64dSAndroid Build Coastguard Worker    """Get the path to lsdump_paths.txt."""
196*90c8c64dSAndroid Build Coastguard Worker    product_out = get_build_vars(['PRODUCT_OUT'], build_target)[0]
197*90c8c64dSAndroid Build Coastguard Worker    return os.path.join(product_out, 'lsdump_paths.txt')
198*90c8c64dSAndroid Build Coastguard Worker
199*90c8c64dSAndroid Build Coastguard Worker
200*90c8c64dSAndroid Build Coastguard Workerdef _get_module_variant_sort_key(suffix):
201*90c8c64dSAndroid Build Coastguard Worker    for variant in suffix.split('_'):
202*90c8c64dSAndroid Build Coastguard Worker        match = re.match(r'apex(\d+)$', variant)
203*90c8c64dSAndroid Build Coastguard Worker        if match:
204*90c8c64dSAndroid Build Coastguard Worker            return (int(match.group(1)), suffix)
205*90c8c64dSAndroid Build Coastguard Worker    return (-1, suffix)
206*90c8c64dSAndroid Build Coastguard Worker
207*90c8c64dSAndroid Build Coastguard Worker
208*90c8c64dSAndroid Build Coastguard Workerdef _get_module_variant_dir_name(tag, arch_cpu_str):
209*90c8c64dSAndroid Build Coastguard Worker    """Return the module variant directory name.
210*90c8c64dSAndroid Build Coastguard Worker
211*90c8c64dSAndroid Build Coastguard Worker    For example, android_x86_shared, android_vendor.R_arm_armv7-a-neon_shared.
212*90c8c64dSAndroid Build Coastguard Worker    """
213*90c8c64dSAndroid Build Coastguard Worker    if tag in ('LLNDK', 'NDK', 'PLATFORM', 'APEX'):
214*90c8c64dSAndroid Build Coastguard Worker        return f'android_{arch_cpu_str}_shared'
215*90c8c64dSAndroid Build Coastguard Worker    if tag == 'VENDOR':
216*90c8c64dSAndroid Build Coastguard Worker        return f'android_vendor_{arch_cpu_str}_shared'
217*90c8c64dSAndroid Build Coastguard Worker    if tag == 'PRODUCT':
218*90c8c64dSAndroid Build Coastguard Worker        return f'android_product_{arch_cpu_str}_shared'
219*90c8c64dSAndroid Build Coastguard Worker    raise ValueError(tag + ' is not a known tag.')
220*90c8c64dSAndroid Build Coastguard Worker
221*90c8c64dSAndroid Build Coastguard Worker
222*90c8c64dSAndroid Build Coastguard Workerdef _read_lsdump_paths(lsdump_paths_file_path, arches, lsdump_filter):
223*90c8c64dSAndroid Build Coastguard Worker    """Read lsdump paths from lsdump_paths.txt for each libname and variant.
224*90c8c64dSAndroid Build Coastguard Worker
225*90c8c64dSAndroid Build Coastguard Worker    This function returns a dictionary, {lib_name: {arch_cpu: {tag: path}}}.
226*90c8c64dSAndroid Build Coastguard Worker    For example,
227*90c8c64dSAndroid Build Coastguard Worker    {
228*90c8c64dSAndroid Build Coastguard Worker      "libc": {
229*90c8c64dSAndroid Build Coastguard Worker        "x86_x86_64": {
230*90c8c64dSAndroid Build Coastguard Worker          "NDK": "path/to/libc.so.lsdump"
231*90c8c64dSAndroid Build Coastguard Worker        }
232*90c8c64dSAndroid Build Coastguard Worker      }
233*90c8c64dSAndroid Build Coastguard Worker    }
234*90c8c64dSAndroid Build Coastguard Worker    """
235*90c8c64dSAndroid Build Coastguard Worker    lsdump_paths = collections.defaultdict(
236*90c8c64dSAndroid Build Coastguard Worker        lambda: collections.defaultdict(dict))
237*90c8c64dSAndroid Build Coastguard Worker    suffixes = collections.defaultdict(
238*90c8c64dSAndroid Build Coastguard Worker        lambda: collections.defaultdict(dict))
239*90c8c64dSAndroid Build Coastguard Worker
240*90c8c64dSAndroid Build Coastguard Worker    with open(lsdump_paths_file_path, 'r') as lsdump_paths_file:
241*90c8c64dSAndroid Build Coastguard Worker        for line in lsdump_paths_file:
242*90c8c64dSAndroid Build Coastguard Worker            if not line.strip():
243*90c8c64dSAndroid Build Coastguard Worker                continue
244*90c8c64dSAndroid Build Coastguard Worker            tag, path = (x.strip() for x in line.split(':', 1))
245*90c8c64dSAndroid Build Coastguard Worker            dir_path, filename = os.path.split(path)
246*90c8c64dSAndroid Build Coastguard Worker            libname = _strip_dump_name_ext(filename)
247*90c8c64dSAndroid Build Coastguard Worker            if not lsdump_filter(tag, libname):
248*90c8c64dSAndroid Build Coastguard Worker                continue
249*90c8c64dSAndroid Build Coastguard Worker            # dir_path may contain soong config hash.
250*90c8c64dSAndroid Build Coastguard Worker            # For example, the following dir_paths are valid.
251*90c8c64dSAndroid Build Coastguard Worker            # android_x86_x86_64_shared/012abc/libc.so.lsdump
252*90c8c64dSAndroid Build Coastguard Worker            # android_x86_x86_64_shared/libc.so.lsdump
253*90c8c64dSAndroid Build Coastguard Worker            dirnames = []
254*90c8c64dSAndroid Build Coastguard Worker            dir_path, dirname = os.path.split(dir_path)
255*90c8c64dSAndroid Build Coastguard Worker            dirnames.append(dirname)
256*90c8c64dSAndroid Build Coastguard Worker            dirname = os.path.basename(dir_path)
257*90c8c64dSAndroid Build Coastguard Worker            dirnames.append(dirname)
258*90c8c64dSAndroid Build Coastguard Worker            for arch in arches:
259*90c8c64dSAndroid Build Coastguard Worker                arch_cpu = arch.get_arch_cpu_str()
260*90c8c64dSAndroid Build Coastguard Worker                prefix = _get_module_variant_dir_name(tag, arch_cpu)
261*90c8c64dSAndroid Build Coastguard Worker                variant = next((d for d in dirnames if d.startswith(prefix)),
262*90c8c64dSAndroid Build Coastguard Worker                               None)
263*90c8c64dSAndroid Build Coastguard Worker                if not variant:
264*90c8c64dSAndroid Build Coastguard Worker                    continue
265*90c8c64dSAndroid Build Coastguard Worker                new_suffix = variant[len(prefix):]
266*90c8c64dSAndroid Build Coastguard Worker                old_suffix = suffixes[libname][arch_cpu].get(tag)
267*90c8c64dSAndroid Build Coastguard Worker                if (not old_suffix or
268*90c8c64dSAndroid Build Coastguard Worker                        _get_module_variant_sort_key(new_suffix) >
269*90c8c64dSAndroid Build Coastguard Worker                        _get_module_variant_sort_key(old_suffix)):
270*90c8c64dSAndroid Build Coastguard Worker                    lsdump_paths[libname][arch_cpu][tag] = path
271*90c8c64dSAndroid Build Coastguard Worker                    suffixes[libname][arch_cpu][tag] = new_suffix
272*90c8c64dSAndroid Build Coastguard Worker    return lsdump_paths
273*90c8c64dSAndroid Build Coastguard Worker
274*90c8c64dSAndroid Build Coastguard Worker
275*90c8c64dSAndroid Build Coastguard Workerdef read_lsdump_paths(build_target, arches, lsdump_filter, build):
276*90c8c64dSAndroid Build Coastguard Worker    """Build lsdump_paths.txt and read the paths."""
277*90c8c64dSAndroid Build Coastguard Worker    lsdump_paths_file_path = get_lsdump_paths_file_path(build_target)
278*90c8c64dSAndroid Build Coastguard Worker    lsdump_paths_file_abspath = os.path.join(AOSP_DIR, lsdump_paths_file_path)
279*90c8c64dSAndroid Build Coastguard Worker    if build:
280*90c8c64dSAndroid Build Coastguard Worker        if os.path.lexists(lsdump_paths_file_abspath):
281*90c8c64dSAndroid Build Coastguard Worker            os.unlink(lsdump_paths_file_abspath)
282*90c8c64dSAndroid Build Coastguard Worker        make_targets(build_target, [lsdump_paths_file_path])
283*90c8c64dSAndroid Build Coastguard Worker    return _read_lsdump_paths(lsdump_paths_file_abspath, arches, lsdump_filter)
284*90c8c64dSAndroid Build Coastguard Worker
285*90c8c64dSAndroid Build Coastguard Worker
286*90c8c64dSAndroid Build Coastguard Workerdef find_lib_lsdumps(lsdump_paths, libs, arch):
287*90c8c64dSAndroid Build Coastguard Worker    """Find the lsdump corresponding to libs for the given architecture.
288*90c8c64dSAndroid Build Coastguard Worker
289*90c8c64dSAndroid Build Coastguard Worker    This function returns a list of (tag, absolute_path).
290*90c8c64dSAndroid Build Coastguard Worker    For example,
291*90c8c64dSAndroid Build Coastguard Worker    [
292*90c8c64dSAndroid Build Coastguard Worker      (
293*90c8c64dSAndroid Build Coastguard Worker        "NDK",
294*90c8c64dSAndroid Build Coastguard Worker        "/path/to/libc.so.lsdump"
295*90c8c64dSAndroid Build Coastguard Worker      )
296*90c8c64dSAndroid Build Coastguard Worker    ]
297*90c8c64dSAndroid Build Coastguard Worker    """
298*90c8c64dSAndroid Build Coastguard Worker    arch_cpu = arch.get_arch_cpu_str()
299*90c8c64dSAndroid Build Coastguard Worker    result = []
300*90c8c64dSAndroid Build Coastguard Worker    if libs:
301*90c8c64dSAndroid Build Coastguard Worker        for lib_name in libs:
302*90c8c64dSAndroid Build Coastguard Worker            if not (lib_name in lsdump_paths and
303*90c8c64dSAndroid Build Coastguard Worker                    arch_cpu in lsdump_paths[lib_name]):
304*90c8c64dSAndroid Build Coastguard Worker                raise KeyError('Cannot find lsdump for %s, %s.' %
305*90c8c64dSAndroid Build Coastguard Worker                               (lib_name, arch_cpu))
306*90c8c64dSAndroid Build Coastguard Worker            result.extend(lsdump_paths[lib_name][arch_cpu].items())
307*90c8c64dSAndroid Build Coastguard Worker    else:
308*90c8c64dSAndroid Build Coastguard Worker        for arch_tag_path_dict in lsdump_paths.values():
309*90c8c64dSAndroid Build Coastguard Worker            result.extend(arch_tag_path_dict[arch_cpu].items())
310*90c8c64dSAndroid Build Coastguard Worker    return [(tag, os.path.join(AOSP_DIR, path)) for tag, path in result]
311*90c8c64dSAndroid Build Coastguard Worker
312*90c8c64dSAndroid Build Coastguard Worker
313*90c8c64dSAndroid Build Coastguard Workerdef run_abi_diff(old_dump_path, new_dump_path, output_path, arch_str, lib_name,
314*90c8c64dSAndroid Build Coastguard Worker                 flags):
315*90c8c64dSAndroid Build Coastguard Worker    abi_diff_cmd = ['header-abi-diff', '-new', new_dump_path, '-old',
316*90c8c64dSAndroid Build Coastguard Worker                    old_dump_path, '-arch', arch_str, '-lib', lib_name,
317*90c8c64dSAndroid Build Coastguard Worker                    '-o', output_path]
318*90c8c64dSAndroid Build Coastguard Worker    abi_diff_cmd += flags
319*90c8c64dSAndroid Build Coastguard Worker    if '-input-format-old' not in flags:
320*90c8c64dSAndroid Build Coastguard Worker        abi_diff_cmd += ['-input-format-old', DEFAULT_FORMAT]
321*90c8c64dSAndroid Build Coastguard Worker    if '-input-format-new' not in flags:
322*90c8c64dSAndroid Build Coastguard Worker        abi_diff_cmd += ['-input-format-new', DEFAULT_FORMAT]
323*90c8c64dSAndroid Build Coastguard Worker    return subprocess.run(abi_diff_cmd).returncode
324*90c8c64dSAndroid Build Coastguard Worker
325*90c8c64dSAndroid Build Coastguard Worker
326*90c8c64dSAndroid Build Coastguard Workerdef run_and_read_abi_diff(old_dump_path, new_dump_path, arch_str, lib_name,
327*90c8c64dSAndroid Build Coastguard Worker                          flags=tuple()):
328*90c8c64dSAndroid Build Coastguard Worker    with tempfile.TemporaryDirectory() as tmp:
329*90c8c64dSAndroid Build Coastguard Worker        output_name = os.path.join(tmp, lib_name) + '.abidiff'
330*90c8c64dSAndroid Build Coastguard Worker        result = run_abi_diff(old_dump_path, new_dump_path, output_name,
331*90c8c64dSAndroid Build Coastguard Worker                              arch_str, lib_name, flags)
332*90c8c64dSAndroid Build Coastguard Worker        with open(output_name, 'r') as output_file:
333*90c8c64dSAndroid Build Coastguard Worker            return result, output_file.read()
334*90c8c64dSAndroid Build Coastguard Worker
335*90c8c64dSAndroid Build Coastguard Worker
336*90c8c64dSAndroid Build Coastguard Workerdef get_build_vars(names, build_target):
337*90c8c64dSAndroid Build Coastguard Worker    """ Get build system variable for the launched target."""
338*90c8c64dSAndroid Build Coastguard Worker    env = os.environ.copy()
339*90c8c64dSAndroid Build Coastguard Worker    env['TARGET_PRODUCT'] = build_target.product
340*90c8c64dSAndroid Build Coastguard Worker    env['TARGET_BUILD_VARIANT'] = build_target.variant
341*90c8c64dSAndroid Build Coastguard Worker    if build_target.release:
342*90c8c64dSAndroid Build Coastguard Worker        env['TARGET_RELEASE'] = build_target.release
343*90c8c64dSAndroid Build Coastguard Worker    cmd = [
344*90c8c64dSAndroid Build Coastguard Worker        os.path.join('build', 'soong', 'soong_ui.bash'),
345*90c8c64dSAndroid Build Coastguard Worker        '--dumpvars-mode', '-vars', ' '.join(names),
346*90c8c64dSAndroid Build Coastguard Worker    ]
347*90c8c64dSAndroid Build Coastguard Worker
348*90c8c64dSAndroid Build Coastguard Worker    proc = subprocess.Popen(cmd, stdout=subprocess.PIPE,
349*90c8c64dSAndroid Build Coastguard Worker                            stderr=subprocess.PIPE, cwd=AOSP_DIR, env=env)
350*90c8c64dSAndroid Build Coastguard Worker    out, err = proc.communicate()
351*90c8c64dSAndroid Build Coastguard Worker
352*90c8c64dSAndroid Build Coastguard Worker    if proc.returncode != 0:
353*90c8c64dSAndroid Build Coastguard Worker        print("error: %s" % err.decode('utf-8'), file=sys.stderr)
354*90c8c64dSAndroid Build Coastguard Worker        return None
355*90c8c64dSAndroid Build Coastguard Worker
356*90c8c64dSAndroid Build Coastguard Worker    build_vars = out.decode('utf-8').strip().splitlines()
357*90c8c64dSAndroid Build Coastguard Worker
358*90c8c64dSAndroid Build Coastguard Worker    build_vars_list = []
359*90c8c64dSAndroid Build Coastguard Worker    for build_var in build_vars:
360*90c8c64dSAndroid Build Coastguard Worker        value = build_var.partition('=')[2]
361*90c8c64dSAndroid Build Coastguard Worker        build_vars_list.append(value.replace('\'', ''))
362*90c8c64dSAndroid Build Coastguard Worker    return build_vars_list
363