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