• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#
2# Copyright (C) 2017 The Android Open Source Project
3#
4# Licensed under the Apache License, Version 2.0 (the 'License');
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8#      http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an 'AS IS' BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15#
16
17import os
18import sys
19
20from importlib import import_module
21
22
23class FuncFuzzerBuildRuleGen(object):
24    """Build rule generator for test/vts-testcase/fuzz/func_fuzzer.
25
26    Attributes:
27        _android_build_top: string, equal to environment variable ANDROID_BUILD_TOP.
28        _project_path: string, path to test/vts-testcase/fuzz.
29        _func_fuzzer_dir: string, path to test/vts-testcase/fuzz/func_fuzzer.
30        _func_fuzzer_build_template: string, path to fuzzer build template file.
31        _utils: test/vts-testcase/hal/script/build/build_rule_gen_utils module.
32        _vts_spec_parser: tools that generates and parses vts spec with hidl-gen.
33        _warning_header: string, warning header for every generated file.
34    """
35
36    def __init__(self, warning_header):
37        """BuildRuleGen constructor.
38
39        Args:
40            warning_header: string, warning header for every generated file.
41        """
42        self._android_build_top = os.environ.get('ANDROID_BUILD_TOP')
43        if not self._android_build_top:
44            print 'Run "lunch" command first.'
45            sys.exit(1)
46        self._project_path = os.path.join(self._android_build_top, 'test',
47                                          'vts-testcase', 'fuzz')
48        self._func_fuzzer_dir = os.path.join(self._project_path, 'func_fuzzer')
49        self._func_fuzzer_build_template = os.path.join(
50            self._project_path, 'script', 'build', 'template',
51            'func_fuzzer_build_template.bp')
52        self._func_fuzzer_build_defaults = os.path.join(
53            self._project_path, 'script', 'build', 'template',
54            'func_fuzzer_build_defaults.bp')
55
56        sys.path.append(
57            os.path.join(self._android_build_top, 'test', 'vts-testcase', 'hal',
58                         'script', 'build'))
59        vts_spec_parser = import_module('vts_spec_parser')
60        self._utils = import_module('build_rule_gen_utils')
61        self._vts_spec_parser = vts_spec_parser.VtsSpecParser()
62        self._warning_header = warning_header
63
64    def UpdateBuildRule(self):
65        """Updates build rules under test/vts-testcase/fuzz/func_fuzzer."""
66        self._utils.RemoveFilesInDirIf(
67            self._func_fuzzer_dir,
68            lambda x: self._IsAutoGenerated(x))
69        hal_list = self._vts_spec_parser.HalNamesAndVersions()
70        self.UpdateTopLevelBuildRule()
71        self.UpdateSecondLevelBuildRule(hal_list)
72        self.UpdateHalDirBuildRule(hal_list)
73
74    def UpdateTopLevelBuildRule(self):
75        """Updates test/vts-testcase/fuzz/func_fuzzer/Android.bp"""
76        build_rule = self._warning_header
77        with open(self._func_fuzzer_build_defaults) as build_file:
78            build_rule += str(build_file.read())
79
80        self._utils.WriteBuildRule(
81            os.path.join(self._func_fuzzer_dir, 'Android.bp'), build_rule)
82
83    def UpdateSecondLevelBuildRule(self, hal_list):
84        """Updates test/vts-testcase/fuzz/func_fuzzer/<hal_name>/Android.bp"""
85        top_level_dirs = dict()
86        for target in hal_list:
87            hal_dir = os.path.join(
88                self._utils.HalNameDir(target[0]),
89                self._utils.HalVerDir(target[1]))
90            top_dir = hal_dir.split('/', 1)[0]
91            top_level_dirs.setdefault(
92                top_dir, []).append(os.path.relpath(hal_dir, top_dir))
93
94        for k, v in top_level_dirs.items():
95            file_path = os.path.join(self._func_fuzzer_dir, k, 'Android.bp')
96            self._utils.WriteBuildRule(
97                file_path,
98                self._utils.OnlySubdirsBpRule(self._warning_header, sorted(v)))
99
100    def UpdateHalDirBuildRule(self, hal_list):
101        """Updates build rules for function fuzzers.
102
103        Updates func_fuzzer build rules for each pair of
104        (hal_name, hal_version) in hal_list.
105
106        Args:
107            hal_list: list of tuple of strings. For example,
108                [('vibrator', '1.3'), ('sensors', '1.7')]
109        """
110        for target in hal_list:
111            hal_name = target[0]
112            hal_version = target[1]
113
114            file_path = os.path.join(
115                self._func_fuzzer_dir, self._utils.HalNameDir(hal_name),
116                self._utils.HalVerDir(hal_version), 'Android.bp')
117
118            self._utils.WriteBuildRule(
119                file_path, self._FuncFuzzerBuildRuleFromTemplate(
120                    hal_name, hal_version, self._func_fuzzer_build_template))
121
122    def _FuncFuzzerBuildRuleFromTemplate(self, hal_name, hal_version,
123                                         template_path):
124        """Returns build rules in string form by filling out a template.
125
126        Reads template from given path and fills it out.
127
128        Args:
129            template_path: string, path to build rule template file.
130            hal_name: string, name of the hal, e.g. 'vibrator'.
131            hal_version: string, version of the hal, e.g '7.4'
132
133        Returns:
134            string, complete build rules in string form
135        """
136        with open(template_path) as template_file:
137            build_template = str(template_file.read())
138
139        vts_spec_names = self._vts_spec_parser.VtsSpecNames(hal_name,
140                                                            hal_version)
141
142        result = self._warning_header
143        for vts_spec in vts_spec_names:
144            hal_iface_name = vts_spec.replace('.vts', '')
145            if not self._IsFuzzable(hal_iface_name):
146                continue
147            result += self._FillOutBuildRuleTemplate(
148                hal_name, hal_version, hal_iface_name, build_template)
149
150        return result
151
152    def _FillOutBuildRuleTemplate(self, hal_name, hal_version, hal_iface_name,
153                                  template):
154        """Returns build rules in string form by filling out given template.
155
156        Args:
157            hal_name: string, name of the hal, e.g. 'vibrator'.
158            hal_version: string, version of the hal, e.g '7.4'
159            hal_iface_name: string, name of a hal interface, e.g 'Vibrator'
160            template: string, build rule template to fill out.
161
162        Returns:
163            string, complete build rule in string form.
164        """
165        build_rule = template
166        build_rule = build_rule.replace('{HAL_NAME}', hal_name)
167        build_rule = build_rule.replace('{HAL_NAME_DIR}',
168                                        self._utils.HalNameDir(hal_name))
169        build_rule = build_rule.replace('{HAL_VERSION}', hal_version)
170        build_rule = build_rule.replace('{HAL_IFACE_NAME}', hal_iface_name)
171        return build_rule
172
173    def _IsAutoGenerated(self, abs_file_path):
174        """Checks if file was auto-generated.
175
176        Args:
177            abs_file_path: string, absolute file path.
178
179        Returns:
180            True iff file was auto-generated by FuncFuzzerBuildRuleGen.
181        """
182        with open(abs_file_path) as myfile:
183            header = ''.join([next(myfile) for x in xrange(2)])
184        return header == self._warning_header
185
186    @staticmethod
187    def _IsFuzzable(component_name):
188        """Checks if component is fuzzable.
189
190        Args:
191            component_name: string, name of component, e.g. 'types, 'Vibrator'
192
193        Returns:
194            True iff can generate a func_fuzzer for component_name.
195        """
196        if component_name == 'types':
197            return False
198        elif component_name.endswith('Callback'):
199            return False
200        else:
201            return True
202