• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env python3
2#
3# Copyright (C) 2017 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
19import glob
20import json
21import logging
22import os
23import sys
24
25import collect_licenses
26import utils
27
28
29class GenBuildFile(object):
30    """Generates Android.bp for VNDK snapshot.
31
32    VNDK snapshot directory structure under prebuilts/vndk/v{version}:
33        Android.bp
34        {SNAPSHOT_ARCH}/
35            Android.bp
36            arch-{TARGET_ARCH}-{TARGET_ARCH_VARIANT}/
37                shared/
38                    vndk-core/
39                        (VNDK-core libraries, e.g. libbinder.so)
40                    vndk-sp/
41                        (VNDK-SP libraries, e.g. libc++.so)
42            arch-{TARGET_2ND_ARCH}-{TARGET_2ND_ARCH_VARIANT}/
43                shared/
44                    vndk-core/
45                        (VNDK-core libraries, e.g. libbinder.so)
46                    vndk-sp/
47                        (VNDK-SP libraries, e.g. libc++.so)
48            binder32/
49                (This directory is newly introduced in v28 (Android P) to hold
50                prebuilts built for 32-bit binder interface.)
51                Android.bp
52                arch-{TARGET_ARCH}-{TARGE_ARCH_VARIANT}/
53                    ...
54            configs/
55                (various *.txt configuration files, e.g. ld.config.*.txt)
56        ... (other {SNAPSHOT_ARCH}/ directories)
57        common/
58            Android.bp
59            NOTICE_FILES/
60                (license files, e.g. libfoo.so.txt)
61    """
62    INDENT = '    '
63    ETC_MODULES = [
64        'llndk.libraries.txt',
65        'vndksp.libraries.txt',
66        'vndkcore.libraries.txt',
67        'vndkprivate.libraries.txt',
68        'vndkproduct.libraries.txt',
69    ]
70
71    """Some vendor prebuilts reference libprotobuf-cpp-lite.so and
72    libprotobuf-cpp-full.so and expect the 3.0.0-beta3 version.
73    The new version of protobuf will be installed as
74    /vendor/lib64/libprotobuf-cpp-lite-3.9.1.so.  The VNDK doesn't
75    help here because we compile old devices against the current
76    branch and not an old VNDK snapshot.  We need to continue to
77    provide a vendor libprotobuf-cpp-lite.so until all products in
78    the current branch get updated prebuilts or are obsoleted.
79
80    VENDOR_COMPAT is a dictionary that has VNDK versions as keys and
81    the list of (library name string, shared libs list) as values.
82    """
83    VENDOR_COMPAT = {
84        28: [
85            ('libprotobuf-cpp-lite',
86                ['libc++', 'libc', 'libdl', 'liblog', 'libm', 'libz']),
87            ('libprotobuf-cpp-full',
88                ['libc++', 'libc', 'libdl', 'liblog', 'libm', 'libz']),
89        ]
90    }
91
92    def __init__(self, install_dir, vndk_version):
93        """GenBuildFile constructor.
94
95        Args:
96          install_dir: string, absolute path to the prebuilts/vndk/v{version}
97            directory where the build files will be generated.
98          vndk_version: int, VNDK snapshot version (e.g. 30)
99        """
100        self._install_dir = install_dir
101        self._vndk_version = vndk_version
102        self._etc_paths = self._get_etc_paths()
103        self._snapshot_archs = utils.get_snapshot_archs(install_dir)
104        self._root_bpfile = os.path.join(install_dir, utils.ROOT_BP_PATH)
105        self._common_bpfile = os.path.join(install_dir, utils.COMMON_BP_PATH)
106        self._llndk = self._parse_lib_list(
107            os.path.basename(self._etc_paths['llndk.libraries.txt']))
108        self._vndk_core = self._parse_lib_list(
109            os.path.basename(self._etc_paths['vndkcore.libraries.txt']))
110        self._vndk_sp = self._parse_lib_list(
111            os.path.basename(self._etc_paths['vndksp.libraries.txt']))
112        self._vndk_private = self._parse_lib_list(
113            os.path.basename(self._etc_paths['vndkprivate.libraries.txt']))
114        self._vndk_product = self._parse_lib_list(
115            os.path.basename(self._etc_paths['vndkproduct.libraries.txt']))
116        self._modules_with_notice = self._get_modules_with_notice()
117
118    def _get_etc_paths(self):
119        """Returns a map of relative file paths for each ETC module."""
120
121        etc_paths = dict()
122        for etc_module in self.ETC_MODULES:
123            etc_pattern = '{}*'.format(os.path.splitext(etc_module)[0])
124            globbed = glob.glob(
125                os.path.join(self._install_dir, utils.CONFIG_DIR_PATH_PATTERN,
126                             etc_pattern))
127            if len(globbed) > 0:
128                rel_etc_path = globbed[0].replace(self._install_dir, '')[1:]
129                etc_paths[etc_module] = rel_etc_path
130        return etc_paths
131
132    def _parse_lib_list(self, txt_filename):
133        """Returns a map of VNDK library lists per VNDK snapshot arch.
134
135        Args:
136          txt_filename: string, name of snapshot config file
137
138        Returns:
139          dict, e.g. {'arm64': ['libfoo.so', 'libbar.so', ...], ...}
140        """
141        lib_map = dict()
142        for txt_path in utils.find(self._install_dir, [txt_filename]):
143            arch = utils.snapshot_arch_from_path(txt_path)
144            abs_path_of_txt = os.path.join(self._install_dir, txt_path)
145            with open(abs_path_of_txt, 'r') as f:
146                lib_map[arch] = f.read().strip().split('\n')
147            if lib_map[arch] == ['']:
148                lib_map[arch].clear()
149        return lib_map
150
151    def _get_modules_with_notice(self):
152        """Returns a list of modules that have associated notice files. """
153        notice_paths = glob.glob(
154            os.path.join(self._install_dir, utils.NOTICE_FILES_DIR_PATH,
155                         '*.txt'))
156        return sorted(os.path.splitext(os.path.basename(p))[0] for p in notice_paths)
157
158    def generate_root_android_bp(self):
159        """Autogenerates Android.bp."""
160
161        logging.info('Generating Android.bp for snapshot v{}'.format(
162            self._vndk_version))
163        prebuilt_buildrules = []
164        for prebuilt in self.ETC_MODULES:
165            prebuilt_buildrules.append(self._gen_etc_prebuilt(prebuilt))
166
167        if self._vndk_version in self.VENDOR_COMPAT:
168            prebuilt_buildrules.append('// Defining prebuilt libraries '
169                        'for the compatibility of old vendor modules')
170            for vendor_compat_lib_info in self.VENDOR_COMPAT[self._vndk_version]:
171                prebuilt_buildrules.append(
172                    self._gen_prebuilt_library_shared(vendor_compat_lib_info))
173
174        with open(self._root_bpfile, 'w') as bpfile:
175            bpfile.write(self._gen_autogen_msg('/'))
176            bpfile.write('\n')
177            bpfile.write(self._gen_license_package())
178            bpfile.write('\n')
179            bpfile.write(self._gen_license())
180            bpfile.write('\n')
181            bpfile.write('\n'.join(prebuilt_buildrules))
182            bpfile.write('\n')
183
184        logging.info('Successfully generated {}'.format(self._root_bpfile))
185
186    def generate_common_android_bp(self):
187        """Autogenerates common/Android.bp."""
188
189        logging.info('Generating common/Android.bp for snapshot v{}'.format(
190            self._vndk_version))
191        with open(self._common_bpfile, 'w') as bpfile:
192            bpfile.write(self._gen_autogen_msg('/'))
193            bpfile.write('\n')
194            bpfile.write(self._gen_license_package())
195            for module in self._modules_with_notice:
196                bpfile.write('\n')
197                bpfile.write(self._gen_notice_filegroup(module))
198
199    def generate_android_bp(self):
200        """Autogenerates Android.bp."""
201
202        def gen_for_variant(arch, is_binder32=False):
203            """Generates Android.bp file for specified VNDK snapshot variant.
204
205            A VNDK snapshot variant is defined by the TARGET_ARCH and binder
206            bitness. Example snapshot variants:
207                vndk_v{ver}_arm:            {arch: arm, binder: 64-bit}
208                vndk_v{ver}_arm_binder32:   {arch: arm, binder: 32-bit}
209
210            Args:
211              arch: string, VNDK snapshot arch (e.g. 'arm64')
212              is_binder32: bool, True if binder interface is 32-bit
213            """
214            binder32_suffix = '_{}'.format(
215                utils.BINDER32) if is_binder32 else ''
216            logging.info('Generating Android.bp for vndk_v{}_{}{}'.format(
217                self._vndk_version, arch, binder32_suffix))
218
219            src_root = os.path.join(self._install_dir, arch)
220            module_names_txt = os.path.join(
221                src_root, "configs", "module_names.txt")
222            module_names = dict()
223            try:
224                with open(module_names_txt, 'r') as f:
225                    # Remove empty lines from module_names_txt
226                    module_list = filter(None, f.read().split('\n'))
227                for module in module_list:
228                    lib, name = module.split(' ')
229                    module_names[lib] = name
230            except IOError:
231                # If module_names.txt doesn't exist, ignore it and parse
232                # module names out from .so filenames. (old snapshot)
233                pass
234
235            variant_subpath = arch
236            if is_binder32:
237                variant_subpath = os.path.join(arch, utils.BINDER32)
238            variant_path = os.path.join(self._install_dir, variant_subpath)
239            bpfile_path = os.path.join(variant_path, 'Android.bp')
240
241            vndk_core_buildrules = self._gen_vndk_shared_prebuilts(
242                self._vndk_core[arch],
243                arch,
244                is_llndk=False,
245                is_vndk_sp=False,
246                is_binder32=is_binder32,
247                module_names=module_names)
248            vndk_sp_buildrules = self._gen_vndk_shared_prebuilts(
249                self._vndk_sp[arch],
250                arch,
251                is_llndk=False,
252                is_vndk_sp=True,
253                is_binder32=is_binder32,
254                module_names=module_names)
255            include_llndk = self._vndk_version > 30
256            if include_llndk:
257                llndk_buildrules = self._gen_vndk_shared_prebuilts(
258                    self._llndk[arch],
259                    arch,
260                    is_llndk=True,
261                    is_vndk_sp=False,
262                    is_binder32=is_binder32,
263                    module_names=module_names)
264
265            with open(bpfile_path, 'w') as bpfile:
266                bpfile.write(self._gen_autogen_msg('/'))
267                bpfile.write('\n')
268                bpfile.write(self._gen_license_package())
269                bpfile.write('\n')
270                bpfile.write('\n'.join(vndk_core_buildrules))
271                bpfile.write('\n')
272                bpfile.write('\n'.join(vndk_sp_buildrules))
273                if include_llndk:
274                    bpfile.write('\n')
275                    bpfile.write('\n'.join(llndk_buildrules))
276
277            variant_include_path = os.path.join(variant_path, 'include')
278            include_path = os.path.join(self._install_dir, arch, 'include')
279            if os.path.isdir(include_path) and variant_include_path != include_path:
280                os.symlink(os.path.relpath(include_path, variant_path),
281                    variant_include_path)
282
283            logging.info('Successfully generated {}'.format(bpfile_path))
284
285        for arch in self._snapshot_archs:
286            if os.path.isdir(
287                    os.path.join(self._install_dir, arch, utils.BINDER32)):
288                gen_for_variant(arch, is_binder32=True)
289            gen_for_variant(arch)
290
291    def _gen_autogen_msg(self, comment_char):
292        return ('{0}{0} THIS FILE IS AUTOGENERATED BY '
293                'development/vndk/snapshot/gen_buildfiles.py\n'
294                '{0}{0} DO NOT EDIT\n'.format(comment_char))
295
296    def _gen_license_package(self):
297        """ Generates license package for VNDK snapshot libs """
298        return ('package {{\n'
299                '{ind}default_applicable_licenses: ["prebuilts_vndk_v{version}_license"],\n'
300                '}}\n'.format(
301                    ind=self.INDENT,
302                    version=self._vndk_version))
303
304    def _get_license_kinds(self):
305        """ Returns a set of license kinds """
306        license_collector = collect_licenses.LicenseCollector(self._install_dir)
307        license_collector.run()
308        return license_collector.license_kinds
309
310    def _gen_license(self):
311        """ Generates license module.
312
313        It uses license files for all VNDK snapshot libraries in common/NOTICE_FILES directory.
314        """
315        license_kinds = self._get_license_kinds()
316        license_kinds_string = ''
317        for license_kind in sorted(license_kinds):
318            license_kinds_string += '{ind}{ind}"{license_kind}",\n'.format(
319                                    ind=self.INDENT, license_kind=license_kind)
320        return ('license {{\n'
321                '{ind}name: "prebuilts_vndk_v{version}_license",\n'
322                '{ind}visibility: [":__subpackages__"],\n'
323                '{ind}license_kinds: [\n'
324                '{license_kinds}'
325                '{ind}],\n'
326                '{ind}license_text: ["{notice_files}"],\n'
327                '}}\n'.format(
328                    ind=self.INDENT,
329                    version=self._vndk_version,
330                    license_kinds=license_kinds_string,
331                    notice_files=os.path.join(utils.NOTICE_FILES_DIR_PATH, '*.txt')))
332
333    def _get_versioned_name(self,
334                            prebuilt,
335                            arch,
336                            is_etc=False,
337                            is_binder32=False,
338                            module_names=None):
339        """Returns the VNDK version-specific module name for a given prebuilt.
340
341        The VNDK version-specific module name is defined as follows:
342        For a VNDK shared lib: 'libfoo.so'
343            if binder is 32-bit:
344                'libfoo.vndk.{version}.{arch}.binder32.vendor'
345            else:
346                'libfoo.vndk.{version}.{arch}.vendor'
347        For an ETC module: 'foo.txt' -> 'foo.{version}.txt'
348
349        Args:
350          prebuilt: string, name of the prebuilt object
351          arch: string, VNDK snapshot arch (e.g. 'arm64')
352          is_etc: bool, True if the LOCAL_MODULE_CLASS of prebuilt is 'ETC'
353          is_binder32: bool, True if binder interface is 32-bit
354          module_names: dict, module names for given prebuilts
355        """
356        if is_etc:
357            name, ext = os.path.splitext(prebuilt)
358            versioned_name = '{}.{}{}'.format(name, self._vndk_version, ext)
359        else:
360            module_names = module_names or dict()
361            if prebuilt in module_names:
362                name = module_names[prebuilt]
363            else:
364                name = os.path.splitext(prebuilt)[0]
365            binder_suffix = '.{}'.format(utils.BINDER32) if is_binder32 else ''
366            versioned_name = '{}.vndk.{}.{}{}.vendor'.format(
367                name, self._vndk_version, arch, binder_suffix)
368
369        return versioned_name
370
371    def _gen_etc_prebuilt(self, prebuilt):
372        """Generates build rule for an ETC prebuilt.
373
374        Args:
375          prebuilt: string, name of ETC prebuilt object
376        """
377        etc_path = self._etc_paths[prebuilt]
378        etc_sub_path = etc_path[etc_path.index('/') + 1:]
379
380        prebuilt_etc = ('prebuilt_etc {{\n'
381                        '{ind}name: "{versioned_name}",\n'
382                        '{ind}target: {{\n'.format(
383                            ind=self.INDENT,
384                            versioned_name=self._get_versioned_name(
385                                prebuilt, None, is_etc=True)))
386        for arch in self._snapshot_archs:
387            prebuilt_etc += ('{ind}{ind}android_{arch}: {{\n'
388                             '{ind}{ind}{ind}src: "{arch}/{etc_sub_path}",\n'
389                             '{ind}{ind}}},\n'.format(
390                                 ind=self.INDENT,
391                                 arch=arch,
392                                 etc_sub_path=etc_sub_path))
393        prebuilt_etc += ('{ind}}},\n'
394                         '}}\n'.format(ind=self.INDENT))
395        return prebuilt_etc
396
397    def _gen_prebuilt_library_shared(self, prebuilt_lib_info):
398        """Generates cc_prebuilt_library_shared modules for the old vendor
399        compatibility.
400
401        Some vendor modules still require old version of libraries that is not
402        available from the current source tree. To provide the old copy of the
403        libraries, use the vndk snapshot.
404
405        Args:
406            prebuilt_lib_info: pair of (string, list of strings), name of the
407                        prebuilt library and the list of shared libs for it.
408        """
409        lib_name = prebuilt_lib_info[0]
410        shared_libs = prebuilt_lib_info[1]
411
412        shared_libs_prop = ''
413        if shared_libs:
414            shared_libs_prop = ('{ind}shared_libs: [\n'.format(ind=self.INDENT))
415            for lib in shared_libs:
416                shared_libs_prop += ('{ind}{ind}"{lib}",\n'.format(
417                                        ind=self.INDENT, lib=lib))
418            shared_libs_prop += ('{ind}],\n'.format(ind=self.INDENT))
419
420        cc_prebuilt_libraries = ('cc_prebuilt_library_shared {{\n'
421                                 '{ind}name: "{name}-vendorcompat",\n'
422                                 '{ind}stem: "{name}",\n'
423                                 '{ind}vendor: true,\n'
424                                 '{ind}// These are already stripped, and '
425                                 'restripping them just issues diagnostics.\n'
426                                 '{ind}strip: {{\n'
427                                 '{ind}{ind}none: true,\n'
428                                 '{ind}}},\n'
429                                 '{shared_libs}'
430                                 '{ind}target: {{\n'.format(
431                                    ind=self.INDENT,
432                                    name=lib_name,
433                                    shared_libs=shared_libs_prop))
434        src_paths = utils.find(self._install_dir, [lib_name+'.so'])
435        for src in src_paths:
436            dirs = src.split(os.path.sep)
437            if len(dirs) < 3 or not dirs[1].startswith('arch-{}-'.format(dirs[0])):
438                continue
439            cc_prebuilt_libraries += ('{ind}{ind}android_{arch}: {{\n'
440                                      '{ind}{ind}{ind}srcs: ["{src}"],\n'
441                                      '{ind}{ind}}},\n'.format(
442                                        ind=self.INDENT, arch=dirs[0], src=src))
443        cc_prebuilt_libraries += ('{ind}}},\n'
444                                  '}}\n'.format(ind=self.INDENT))
445        return cc_prebuilt_libraries
446
447    def _gen_notice_filegroup(self, module):
448        """Generates a notice filegroup build rule for a given module.
449
450        Args:
451          notice: string, module name
452        """
453        return ('filegroup {{\n'
454                '{ind}name: "{filegroup_name}",\n'
455                '{ind}srcs: ["{notice_dir}/{module}.txt"],\n'
456                '}}\n'.format(
457                    ind=self.INDENT,
458                    filegroup_name=self._get_notice_filegroup_name(module),
459                    module=module,
460                    notice_dir=utils.NOTICE_FILES_DIR_NAME))
461
462    def _get_notice_filegroup_name(self, module):
463        """ Gets a notice filegroup module name for a given module.
464
465        Args:
466          notice: string, module name.
467        """
468        return 'vndk-v{ver}-{module}-notice'.format(
469            ver=self._vndk_version, module=module)
470
471    def _gen_vndk_shared_prebuilts(self,
472                                   prebuilts,
473                                   arch,
474                                   is_llndk,
475                                   is_vndk_sp,
476                                   is_binder32,
477                                   module_names):
478        """Returns list of build rules for given prebuilts.
479
480        Args:
481          prebuilts: list of VNDK shared prebuilts
482          arch: string, VNDK snapshot arch (e.g. 'arm64')
483          is_llndk: bool, True if the prebuilts are LLNDK stubs
484          is_vndk_sp: bool, True if prebuilts are VNDK_SP libs
485          is_binder32: bool, True if binder interface is 32-bit
486          module_names: dict, module names for given prebuilts
487        """
488
489        module_prebuilts = dict()
490        for prebuilt in prebuilts:
491            if prebuilt in module_names:
492                name = module_names[prebuilt]
493            else:
494                name = os.path.splitext(prebuilt)[0]
495
496            if name not in module_prebuilts:
497                module_prebuilts[name] = list()
498            module_prebuilts[name].append(prebuilt)
499
500        build_rules = []
501        for name in module_prebuilts:
502            bp_module = self._gen_vndk_shared_prebuilt(
503                name,
504                arch,
505                srcs=module_prebuilts[name],
506                is_llndk=is_llndk,
507                is_vndk_sp=is_vndk_sp,
508                is_binder32=is_binder32)
509            if bp_module:
510                build_rules.append(bp_module)
511        return build_rules
512
513    def _gen_vndk_shared_prebuilt(self,
514                                  name,
515                                  arch,
516                                  srcs,
517                                  is_llndk,
518                                  is_vndk_sp,
519                                  is_binder32):
520        """Returns build rule for given prebuilt module, or an empty
521        string if the module is invalid (e.g. srcs doesn't exist).
522
523        Args:
524          name: string, name of prebuilt module
525          arch: string, VNDK snapshot arch (e.g. 'arm64')
526          srcs: list, prebuilt source file names of this module
527          is_llndk: bool, True if prebuilt is a LLNDK stub
528          is_vndk_sp: bool, True if prebuilt is a VNDK_SP lib
529          is_binder32: bool, True if binder interface is 32-bit
530        """
531
532        def is_prebuilts_in_list(prebuilts, vndk_list):
533            for prebuilt in prebuilts:
534                if prebuilt in vndk_list:
535                    return True
536            return False
537
538        def get_notice_file(prebuilts):
539            """Returns build rule for notice file (attribute 'notice').
540
541            Args:
542              prebuilts: list, names of prebuilt objects
543            """
544            notice = ''
545            for prebuilt in prebuilts:
546                if prebuilt in self._modules_with_notice:
547                    notice = '{ind}notice: ":{notice_filegroup}",\n'.format(
548                        ind=self.INDENT,
549                        notice_filegroup=self._get_notice_filegroup_name(prebuilt))
550                    break
551            return notice
552
553        def get_arch_props(name, arch, src_paths):
554            """Returns build rule for arch specific srcs.
555
556            e.g.,
557                arch: {
558                    arm: {
559                        export_include_dirs: ["..."],
560                        export_system_include_dirs: ["..."],
561                        export_flags: ["..."],
562                        relative_install_path: "...",
563                        srcs: ["..."]
564                    },
565                    arm64: {
566                        export_include_dirs: ["..."],
567                        export_system_include_dirs: ["..."],
568                        export_flags: ["..."],
569                        relative_install_path: "...",
570                        srcs: ["..."]
571                    },
572                }
573
574            Args:
575              name: string, name of prebuilt module
576              arch: string, VNDK snapshot arch (e.g. 'arm64')
577              src_paths: list of string paths, prebuilt source paths
578            """
579            arch_props = '{ind}arch: {{\n'.format(ind=self.INDENT)
580
581            def list_to_prop_value(l, name):
582                if len(l) == 0:
583                    return ''
584                dirs=',\n{ind}{ind}{ind}{ind}'.format(
585                    ind=self.INDENT).join(['"%s"' % d for d in l])
586                return ('{ind}{ind}{ind}{name}: [\n'
587                        '{ind}{ind}{ind}{ind}{dirs},\n'
588                        '{ind}{ind}{ind}],\n'.format(
589                            ind=self.INDENT,
590                            dirs=dirs,
591                            name=name))
592
593            def rename_generated_dirs(dirs):
594                # Reame out/soong/.intermedaites to generated-headers for better readability.
595                return [d.replace(utils.SOONG_INTERMEDIATES_DIR, utils.GENERATED_HEADERS_DIR, 1) for d in dirs]
596
597            for src in sorted(src_paths):
598                include_dirs = ''
599                system_include_dirs = ''
600                flags = ''
601                relative_install_path = ''
602                prop_path = os.path.join(src_root, src+'.json')
603                props = dict()
604                try:
605                    with open(prop_path, 'r') as f:
606                        props = json.loads(f.read())
607                    os.unlink(prop_path)
608                except:
609                    # TODO(b/70312118): Parse from soong build system
610                    if name == 'android.hidl.memory@1.0-impl':
611                        props['RelativeInstallPath'] = 'hw'
612                if 'ExportedDirs' in props:
613                    dirs = rename_generated_dirs(props['ExportedDirs'])
614                    l = ['include/%s' % d for d in dirs]
615                    include_dirs = list_to_prop_value(l, 'export_include_dirs')
616                if 'ExportedSystemDirs' in props:
617                    dirs = rename_generated_dirs(props['ExportedSystemDirs'])
618                    l = ['include/%s' % d for d in dirs]
619                    system_include_dirs = list_to_prop_value(l, 'export_system_include_dirs')
620                if 'ExportedFlags' in props:
621                    flags = list_to_prop_value(props['ExportedFlags'], 'export_flags')
622                if 'RelativeInstallPath' in props:
623                    relative_install_path = ('{ind}{ind}{ind}'
624                        'relative_install_path: "{path}",\n').format(
625                            ind=self.INDENT,
626                            path=props['RelativeInstallPath'])
627
628                arch_props += ('{ind}{ind}{arch}: {{\n'
629                               '{include_dirs}'
630                               '{system_include_dirs}'
631                               '{flags}'
632                               '{relative_install_path}'
633                               '{ind}{ind}{ind}srcs: ["{src}"],\n'
634                               '{ind}{ind}}},\n').format(
635                                  ind=self.INDENT,
636                                  arch=utils.prebuilt_arch_from_path(
637                                      os.path.join(arch, src)),
638                                  include_dirs=include_dirs,
639                                  system_include_dirs=system_include_dirs,
640                                  flags=flags,
641                                  relative_install_path=relative_install_path,
642                                  src=src)
643            arch_props += '{ind}}},\n'.format(ind=self.INDENT)
644            return arch_props
645
646        src_root = os.path.join(self._install_dir, arch)
647        if is_binder32:
648            src_root = os.path.join(src_root, utils.BINDER32)
649
650        src_paths = utils.find(src_root, srcs)
651        # filter out paths under 'binder32' subdirectory
652        src_paths = list(filter(lambda src: not src.startswith(utils.BINDER32),
653            src_paths))
654        # This module is invalid if no srcs are found.
655        if not src_paths:
656            logging.info('No srcs found for {}; skipping'.format(name))
657            return ""
658
659        product_available = ''
660        # if vndkproduct.libraries.txt is empty, make the VNDKs available to product by default.
661        if is_llndk or not self._vndk_product[arch] or is_prebuilts_in_list(srcs, self._vndk_product[arch]):
662            product_available = '{ind}product_available: true,\n'.format(
663                ind=self.INDENT)
664
665        vndk_props = ''
666        if not is_llndk:
667            vndk_sp = ''
668            if is_vndk_sp:
669                vndk_sp = '{ind}{ind}support_system_process: true,\n'.format(
670                    ind=self.INDENT)
671
672            vndk_private = ''
673            if is_prebuilts_in_list(srcs, self._vndk_private[arch]):
674                vndk_private = '{ind}{ind}private: true,\n'.format(
675                    ind=self.INDENT)
676
677            vndk_props = ('{ind}vndk: {{\n'
678                          '{ind}{ind}enabled: true,\n'
679                          '{vndk_sp}'
680                          '{vndk_private}'
681                          '{ind}}},\n'.format(
682                              ind=self.INDENT,
683                              product_available=product_available,
684                              vndk_sp=vndk_sp,
685                              vndk_private=vndk_private))
686
687        notice = get_notice_file(srcs)
688        arch_props = get_arch_props(name, arch, src_paths)
689
690        binder32bit = ''
691        if is_binder32:
692            binder32bit = '{ind}binder32bit: true,\n'.format(ind=self.INDENT)
693
694        return ('vndk_prebuilt_shared {{\n'
695                '{ind}name: "{name}",\n'
696                '{ind}version: "{ver}",\n'
697                '{ind}target_arch: "{target_arch}",\n'
698                '{binder32bit}'
699                '{ind}vendor_available: true,\n'
700                '{product_available}'
701                '{vndk_props}'
702                '{notice}'
703                '{arch_props}'
704                '}}\n'.format(
705                    ind=self.INDENT,
706                    name=name,
707                    ver=self._vndk_version,
708                    target_arch=arch,
709                    binder32bit=binder32bit,
710                    product_available=product_available,
711                    vndk_props=vndk_props,
712                    notice=notice,
713                    arch_props=arch_props))
714
715
716def get_args():
717    parser = argparse.ArgumentParser()
718    parser.add_argument(
719        'vndk_version',
720        type=utils.vndk_version_int,
721        help='VNDK snapshot version to install, e.g. "{}".'.format(
722            utils.MINIMUM_VNDK_VERSION))
723    parser.add_argument(
724        '-v',
725        '--verbose',
726        action='count',
727        default=0,
728        help='Increase output verbosity, e.g. "-v", "-vv".')
729    return parser.parse_args()
730
731
732def main():
733    """For local testing purposes.
734
735    Note: VNDK snapshot must be already installed under
736      prebuilts/vndk/v{version}.
737    """
738    ANDROID_BUILD_TOP = utils.get_android_build_top()
739    PREBUILTS_VNDK_DIR = utils.join_realpath(ANDROID_BUILD_TOP,
740                                             'prebuilts/vndk')
741
742    args = get_args()
743    vndk_version = args.vndk_version
744    install_dir = os.path.join(PREBUILTS_VNDK_DIR, 'v{}'.format(vndk_version))
745    if not os.path.isdir(install_dir):
746        raise ValueError(
747            'Please provide valid VNDK version. {} does not exist.'
748            .format(install_dir))
749    utils.set_logging_config(args.verbose)
750
751    buildfile_generator = GenBuildFile(install_dir, vndk_version)
752    buildfile_generator.generate_root_android_bp()
753    buildfile_generator.generate_common_android_bp()
754    buildfile_generator.generate_android_bp()
755
756    logging.info('Done.')
757
758
759if __name__ == '__main__':
760    main()
761