| # |
| # 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 |