| # |
| # 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 |
| from xml.etree import ElementTree |
| |
| |
| class FuzzerType(object): |
| """Types of fuzzers.""" |
| FUNC_FUZZER = 0 |
| IFACE_FUZZER = 1 |
| |
| |
| class ConfigGen(object): |
| """Config generator for test/vts-testcase/fuzz. |
| |
| Attributes: |
| _android_build_top: string, equal to environment variable ANDROID_BUILD_TOP. |
| _project_path: string, path to test/vts-testcase/fuzz. |
| _template_dir: string, path to directory containing templates. |
| _utils: test/vts-testcase/hal/script/build/config_gen_utils module. |
| _vts_spec_parser: tools that generates and parses vts spec with hidl-gen. |
| """ |
| |
| def __init__(self): |
| """ConfigGen constructor. """ |
| 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._template_dir = os.path.join(self._project_path, 'script', |
| 'config', 'template') |
| 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() |
| |
| def _GetPlansFromConfig(self, xml_file_path): |
| """Gets plan names from a module config. |
| |
| Args: |
| xml_file_path: string, path to the XML file. |
| |
| Returns: |
| list of strings, the plans that the module belongs to. |
| """ |
| root = ElementTree.parse(xml_file_path).getroot() |
| plans = [e.attrib["value"] for e in root.iterfind("option") if |
| e.get("name", "") == "config-descriptor:metadata" and |
| e.get("key", "") == "plan" and |
| "value" in e.attrib] |
| return plans |
| |
| def UpdateFuzzerConfigs(self): |
| """Updates build rules for fuzzers. |
| |
| Updates fuzzer configs for each pair of (hal_name, hal_version). |
| """ |
| config_dir = os.path.join(self._project_path, 'config') |
| old_config = dict() |
| |
| for base_dir, dirs, files, in os.walk(config_dir): |
| for file_name in files: |
| file_path = os.path.join(base_dir, file_name) |
| if file_name == 'AndroidTest.xml': |
| old_config[file_path] = self._GetPlansFromConfig(file_path) |
| if file_name in ('AndroidTest.xml', 'Android.bp'): |
| os.remove(file_path) |
| |
| self.UpdateFuzzerConfigsForType(FuzzerType.IFACE_FUZZER, old_config) |
| |
| def UpdateFuzzerConfigsForType(self, fuzzer_type, old_config): |
| """Updates build rules for fuzzers. |
| |
| Updates fuzzer configs for given fuzzer type. |
| |
| Args: |
| fuzzer_type: FuzzerType, type of fuzzer. |
| old_config: dict. The key is the path to the old XML. The value is |
| the list of the plans the module belongs to. |
| """ |
| bp_template_path = os.path.join(self._template_dir, 'template.bp') |
| xml_template_path = os.path.join(self._template_dir, 'template.xml') |
| with open(bp_template_path) as template_file: |
| bp_template = str(template_file.read()) |
| with open(xml_template_path) as template_file: |
| xml_template = str(template_file.read()) |
| |
| hal_list = self._vts_spec_parser.HalNamesAndVersions() |
| for hal_name, hal_version in hal_list: |
| if not self._IsTestable(hal_name, hal_version): |
| continue |
| fuzzer_type_subdir = self._FuzzerTypeUnderscore(fuzzer_type) |
| config_dir = os.path.join( |
| self._project_path, 'config', self._utils.HalNameDir(hal_name), |
| self._utils.HalVerDir(hal_version), fuzzer_type_subdir) |
| bp_file_path = os.path.join(config_dir, 'Android.bp') |
| xml_file_path = os.path.join(config_dir, 'AndroidTest.xml') |
| |
| plan = 'vts-staging-fuzz' |
| if xml_file_path in old_config: |
| old_plans = old_config[xml_file_path] |
| if old_plans: |
| plan = old_plans[0] |
| else: |
| print('WARNING: No plan name in %s' % xml_file_path) |
| if len(old_plans) > 1: |
| print('WARNING: More than one plan name in %s' % |
| xml_file_path) |
| |
| bp_string = self._FillOutTemplate( |
| hal_name, hal_version, fuzzer_type, plan, bp_template) |
| |
| xml_string = self._FillOutTemplate( |
| hal_name, hal_version, fuzzer_type, plan, xml_template) |
| |
| self._utils.WriteBuildRule(bp_file_path, bp_string) |
| self._utils.WriteBuildRule(xml_file_path, xml_string) |
| |
| def _FuzzerTestName(self, hal_name, hal_version, fuzzer_type): |
| """Returns vts hal fuzzer test module name. |
| |
| Args: |
| hal_name: string, name of the hal, e.g. 'vibrator'. |
| hal_version: string, version of the hal, e.g '7.4' |
| fuzzer_type: FuzzerType, type of fuzzer. |
| |
| Returns: |
| string, test module name, e.g. VtsHalVibratorV7_4FuncFuzzer |
| """ |
| test_name = 'VtsHal' |
| test_name += ''.join(map(lambda x: x.title(), hal_name.split('.'))) |
| test_name += self._utils.HalVerDir(hal_version) |
| test_name += self._FuzzerTypeCamel(fuzzer_type) |
| return test_name |
| |
| def _FuzzerTypeUnderscore(self, fuzzer_type): |
| """Returns vts hal fuzzer type string in underscore case. |
| |
| Args: |
| fuzzer_type: FuzzerType, type of fuzzer. |
| |
| Returns: |
| string, fuzzer type, e.g. "iface_fuzzer" |
| """ |
| if fuzzer_type == FuzzerType.FUNC_FUZZER: |
| test_type = 'func_fuzzer' |
| else: |
| test_type = 'iface_fuzzer' |
| return test_type |
| |
| def _FuzzerTypeCamel(self, fuzzer_type): |
| """Returns vts hal fuzzer type string in camel case. |
| |
| Args: |
| fuzzer_type: FuzzerType, type of fuzzer. |
| |
| Returns: |
| string, fuzzer type, e.g. "IfaceFuzzer" |
| """ |
| if fuzzer_type == FuzzerType.FUNC_FUZZER: |
| test_type = 'FuncFuzzer' |
| else: |
| test_type = 'IfaceFuzzer' |
| return test_type |
| |
| def _FillOutTemplate(self, hal_name, hal_version, fuzzer_type, plan, |
| 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' |
| fuzzer_type: FuzzerType, type of fuzzer. |
| plan: string, name of the plan, e.g. 'vts-staging-fuzz' |
| template: string, build rule template to fill out. |
| |
| Returns: |
| string, complete build rule in string form. |
| """ |
| config = template |
| config = config.replace('{TEST_NAME}', self._FuzzerTestName( |
| hal_name, hal_version, fuzzer_type)) |
| config = config.replace('{HAL_NAME}', hal_name) |
| config = config.replace('{HAL_VERSION}', hal_version) |
| config = config.replace('{TEST_TYPE_CAMEL}', |
| self._FuzzerTypeCamel(fuzzer_type)) |
| config = config.replace('{TEST_TYPE_UNDERSCORE}', |
| self._FuzzerTypeUnderscore(fuzzer_type)) |
| config = config.replace('{PLAN}', plan) |
| return config |
| |
| def _IsTestable(self, hal_name, hal_version): |
| """Returns true iff hal can be tested.""" |
| if 'tests' in hal_name: |
| return False |
| return True |