普通文本  |  202行  |  7.85 KB

#
# Copyright (C) 2017 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the 'License');
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an 'AS IS' BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

import os
import sys

from importlib import import_module


class FuncFuzzerBuildRuleGen(object):
    """Build rule generator for test/vts-testcase/fuzz/func_fuzzer.

    Attributes:
        _android_build_top: string, equal to environment variable ANDROID_BUILD_TOP.
        _project_path: string, path to test/vts-testcase/fuzz.
        _func_fuzzer_dir: string, path to test/vts-testcase/fuzz/func_fuzzer.
        _func_fuzzer_build_template: string, path to fuzzer build template file.
        _utils: test/vts-testcase/hal/script/build/build_rule_gen_utils module.
        _vts_spec_parser: tools that generates and parses vts spec with hidl-gen.
        _warning_header: string, warning header for every generated file.
    """

    def __init__(self, warning_header):
        """BuildRuleGen constructor.

        Args:
            warning_header: string, warning header for every generated file.
        """
        self._android_build_top = os.environ.get('ANDROID_BUILD_TOP')
        if not self._android_build_top:
            print 'Run "lunch" command first.'
            sys.exit(1)
        self._project_path = os.path.join(self._android_build_top, 'test',
                                          'vts-testcase', 'fuzz')
        self._func_fuzzer_dir = os.path.join(self._project_path, 'func_fuzzer')
        self._func_fuzzer_build_template = os.path.join(
            self._project_path, 'script', 'build', 'template',
            'func_fuzzer_build_template.bp')
        self._func_fuzzer_build_defaults = os.path.join(
            self._project_path, 'script', 'build', 'template',
            'func_fuzzer_build_defaults.bp')

        sys.path.append(
            os.path.join(self._android_build_top, 'test', 'vts-testcase', 'hal',
                         'script', 'build'))
        vts_spec_parser = import_module('vts_spec_parser')
        self._utils = import_module('build_rule_gen_utils')
        self._vts_spec_parser = vts_spec_parser.VtsSpecParser()
        self._warning_header = warning_header

    def UpdateBuildRule(self):
        """Updates build rules under test/vts-testcase/fuzz/func_fuzzer."""
        self._utils.RemoveFilesInDirIf(
            self._func_fuzzer_dir,
            lambda x: self._IsAutoGenerated(x))
        hal_list = self._vts_spec_parser.HalNamesAndVersions()
        self.UpdateTopLevelBuildRule()
        self.UpdateSecondLevelBuildRule(hal_list)
        self.UpdateHalDirBuildRule(hal_list)

    def UpdateTopLevelBuildRule(self):
        """Updates test/vts-testcase/fuzz/func_fuzzer/Android.bp"""
        build_rule = self._warning_header
        with open(self._func_fuzzer_build_defaults) as build_file:
            build_rule += str(build_file.read())

        self._utils.WriteBuildRule(
            os.path.join(self._func_fuzzer_dir, 'Android.bp'), build_rule)

    def UpdateSecondLevelBuildRule(self, hal_list):
        """Updates test/vts-testcase/fuzz/func_fuzzer/<hal_name>/Android.bp"""
        top_level_dirs = dict()
        for target in hal_list:
            hal_dir = os.path.join(
                self._utils.HalNameDir(target[0]),
                self._utils.HalVerDir(target[1]))
            top_dir = hal_dir.split('/', 1)[0]
            top_level_dirs.setdefault(
                top_dir, []).append(os.path.relpath(hal_dir, top_dir))

        for k, v in top_level_dirs.items():
            file_path = os.path.join(self._func_fuzzer_dir, k, 'Android.bp')
            self._utils.WriteBuildRule(
                file_path,
                self._utils.OnlySubdirsBpRule(self._warning_header, sorted(v)))

    def UpdateHalDirBuildRule(self, hal_list):
        """Updates build rules for function fuzzers.

        Updates func_fuzzer build rules for each pair of
        (hal_name, hal_version) in hal_list.

        Args:
            hal_list: list of tuple of strings. For example,
                [('vibrator', '1.3'), ('sensors', '1.7')]
        """
        for target in hal_list:
            hal_name = target[0]
            hal_version = target[1]

            file_path = os.path.join(
                self._func_fuzzer_dir, self._utils.HalNameDir(hal_name),
                self._utils.HalVerDir(hal_version), 'Android.bp')

            self._utils.WriteBuildRule(
                file_path, self._FuncFuzzerBuildRuleFromTemplate(
                    hal_name, hal_version, self._func_fuzzer_build_template))

    def _FuncFuzzerBuildRuleFromTemplate(self, hal_name, hal_version,
                                         template_path):
        """Returns build rules in string form by filling out a template.

        Reads template from given path and fills it out.

        Args:
            template_path: string, path to build rule template file.
            hal_name: string, name of the hal, e.g. 'vibrator'.
            hal_version: string, version of the hal, e.g '7.4'

        Returns:
            string, complete build rules in string form
        """
        with open(template_path) as template_file:
            build_template = str(template_file.read())

        vts_spec_names = self._vts_spec_parser.VtsSpecNames(hal_name,
                                                            hal_version)

        result = self._warning_header
        for vts_spec in vts_spec_names:
            hal_iface_name = vts_spec.replace('.vts', '')
            if not self._IsFuzzable(hal_iface_name):
                continue
            result += self._FillOutBuildRuleTemplate(
                hal_name, hal_version, hal_iface_name, build_template)

        return result

    def _FillOutBuildRuleTemplate(self, hal_name, hal_version, hal_iface_name,
                                  template):
        """Returns build rules in string form by filling out given template.

        Args:
            hal_name: string, name of the hal, e.g. 'vibrator'.
            hal_version: string, version of the hal, e.g '7.4'
            hal_iface_name: string, name of a hal interface, e.g 'Vibrator'
            template: string, build rule template to fill out.

        Returns:
            string, complete build rule in string form.
        """
        build_rule = template
        build_rule = build_rule.replace('{HAL_NAME}', hal_name)
        build_rule = build_rule.replace('{HAL_NAME_DIR}',
                                        self._utils.HalNameDir(hal_name))
        build_rule = build_rule.replace('{HAL_VERSION}', hal_version)
        build_rule = build_rule.replace('{HAL_IFACE_NAME}', hal_iface_name)
        return build_rule

    def _IsAutoGenerated(self, abs_file_path):
        """Checks if file was auto-generated.

        Args:
            abs_file_path: string, absolute file path.

        Returns:
            True iff file was auto-generated by FuncFuzzerBuildRuleGen.
        """
        with open(abs_file_path) as myfile:
            header = ''.join([next(myfile) for x in xrange(2)])
        return header == self._warning_header

    @staticmethod
    def _IsFuzzable(component_name):
        """Checks if component is fuzzable.

        Args:
            component_name: string, name of component, e.g. 'types, 'Vibrator'

        Returns:
            True iff can generate a func_fuzzer for component_name.
        """
        if component_name == 'types':
            return False
        elif component_name.endswith('Callback'):
            return False
        else:
            return True