blob: fddc55b5f4cc6c777e0f3ad83f0218f29d0155f0 [file] [log] [blame]
Keith Mok57baaaf2023-06-13 22:33:10 +00001#!/usr/bin/python3
Yu Shan63e24d72022-06-24 17:53:32 +00002
3# Copyright (C) 2022 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"""A script to generate Java files and CPP header files based on annotations in VehicleProperty.aidl
18
19 Need ANDROID_BUILD_TOP environmental variable to be set. This script will update
20 ChangeModeForVehicleProperty.h and AccessForVehicleProperty.h under generated_lib/cpp and
21 ChangeModeForVehicleProperty.java and AccessForVehicleProperty.java under generated_lib/java.
22
23 Usage:
24 $ python generate_annotation_enums.py
25"""
Yu Shan41dd7f12023-06-07 13:25:43 -070026import argparse
27import filecmp
Yu Shan63e24d72022-06-24 17:53:32 +000028import os
29import re
30import sys
Yu Shan41dd7f12023-06-07 13:25:43 -070031import tempfile
Yu Shan63e24d72022-06-24 17:53:32 +000032
Yu Shan41dd7f12023-06-07 13:25:43 -070033PROP_AIDL_FILE_PATH = ('hardware/interfaces/automotive/vehicle/aidl_property/android/hardware/' +
34 'automotive/vehicle/VehicleProperty.aidl')
35CHANGE_MODE_CPP_FILE_PATH = ('hardware/interfaces/automotive/vehicle/aidl/generated_lib/cpp/' +
36 'ChangeModeForVehicleProperty.h')
37ACCESS_CPP_FILE_PATH = ('hardware/interfaces/automotive/vehicle/aidl/generated_lib/cpp/' +
38 'AccessForVehicleProperty.h')
39CHANGE_MODE_JAVA_FILE_PATH = ('hardware/interfaces/automotive/vehicle/aidl/generated_lib/java/' +
40 'ChangeModeForVehicleProperty.java')
41ACCESS_JAVA_FILE_PATH = ('hardware/interfaces/automotive/vehicle/aidl/generated_lib/java/' +
42 'AccessForVehicleProperty.java')
43SCRIPT_PATH = 'hardware/interfaces/automotive/vehicle/tools/generate_annotation_enums.py'
Yu Shan63e24d72022-06-24 17:53:32 +000044
Yu Shan41dd7f12023-06-07 13:25:43 -070045TAB = ' '
46RE_ENUM_START = re.compile('\s*enum VehicleProperty \{')
47RE_ENUM_END = re.compile('\s*\}\;')
48RE_COMMENT_BEGIN = re.compile('\s*\/\*\*?')
49RE_COMMENT_END = re.compile('\s*\*\/')
50RE_CHANGE_MODE = re.compile('\s*\* @change_mode (\S+)\s*')
51RE_ACCESS = re.compile('\s*\* @access (\S+)\s*')
Yu Shan8ddd65d2023-06-28 17:02:29 -070052RE_DATA_ENUM = re.compile('\s*\* @data_enum (\S+)\s*')
53RE_UNIT = re.compile('\s*\* @unit (\S+)\s+')
Yu Shan41dd7f12023-06-07 13:25:43 -070054RE_VALUE = re.compile('\s*(\w+)\s*=(.*)')
Yu Shan63e24d72022-06-24 17:53:32 +000055
56LICENSE = """/*
57 * Copyright (C) 2022 The Android Open Source Project
58 *
59 * Licensed under the Apache License, Version 2.0 (the "License");
60 * you may not use this file except in compliance with the License.
61 * You may obtain a copy of the License at
62 *
63 * http://www.apache.org/licenses/LICENSE-2.0
64 *
65 * Unless required by applicable law or agreed to in writing, software
66 * distributed under the License is distributed on an "AS IS" BASIS,
67 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
68 * See the License for the specific language governing permissions and
69 * limitations under the License.
70 */
71
72/**
73 * DO NOT EDIT MANUALLY!!!
74 *
75 * Generated by tools/generate_annotation_enums.py.
76 */
77
Aaqib Ismail2e8915d2023-01-30 13:04:05 -080078// clang-format off
79
Yu Shan63e24d72022-06-24 17:53:32 +000080"""
81
82CHANGE_MODE_CPP_HEADER = """#ifndef android_hardware_automotive_vehicle_aidl_generated_lib_ChangeModeForVehicleProperty_H_
83#define android_hardware_automotive_vehicle_aidl_generated_lib_ChangeModeForVehicleProperty_H_
84
85#include <aidl/android/hardware/automotive/vehicle/VehicleProperty.h>
86#include <aidl/android/hardware/automotive/vehicle/VehiclePropertyChangeMode.h>
87
88#include <unordered_map>
89
90namespace aidl {
91namespace android {
92namespace hardware {
93namespace automotive {
94namespace vehicle {
95
96std::unordered_map<VehicleProperty, VehiclePropertyChangeMode> ChangeModeForVehicleProperty = {
97"""
98
99CHANGE_MODE_CPP_FOOTER = """
100};
101
102} // namespace vehicle
103} // namespace automotive
104} // namespace hardware
105} // namespace android
106} // aidl
107
108#endif // android_hardware_automotive_vehicle_aidl_generated_lib_ChangeModeForVehicleProperty_H_
109"""
110
111ACCESS_CPP_HEADER = """#ifndef android_hardware_automotive_vehicle_aidl_generated_lib_AccessForVehicleProperty_H_
112#define android_hardware_automotive_vehicle_aidl_generated_lib_AccessForVehicleProperty_H_
113
114#include <aidl/android/hardware/automotive/vehicle/VehicleProperty.h>
115#include <aidl/android/hardware/automotive/vehicle/VehiclePropertyAccess.h>
116
117#include <unordered_map>
118
119namespace aidl {
120namespace android {
121namespace hardware {
122namespace automotive {
123namespace vehicle {
124
125std::unordered_map<VehicleProperty, VehiclePropertyAccess> AccessForVehicleProperty = {
126"""
127
128ACCESS_CPP_FOOTER = """
129};
130
131} // namespace vehicle
132} // namespace automotive
133} // namespace hardware
134} // namespace android
135} // aidl
136
137#endif // android_hardware_automotive_vehicle_aidl_generated_lib_AccessForVehicleProperty_H_
138"""
139
140CHANGE_MODE_JAVA_HEADER = """package android.hardware.automotive.vehicle;
141
142import java.util.Map;
143
144public final class ChangeModeForVehicleProperty {
145
146 public static final Map<Integer, Integer> values = Map.ofEntries(
147"""
148
149CHANGE_MODE_JAVA_FOOTER = """
150 );
151
152}
153"""
154
155ACCESS_JAVA_HEADER = """package android.hardware.automotive.vehicle;
156
157import java.util.Map;
158
159public final class AccessForVehicleProperty {
160
161 public static final Map<Integer, Integer> values = Map.ofEntries(
162"""
163
164ACCESS_JAVA_FOOTER = """
165 );
166
167}
168"""
169
170
Yu Shan8ddd65d2023-06-28 17:02:29 -0700171class PropertyConfig:
172 """Represents one VHAL property definition in VehicleProperty.aidl."""
Yu Shan63e24d72022-06-24 17:53:32 +0000173
Yu Shan8ddd65d2023-06-28 17:02:29 -0700174 def __init__(self):
175 self.name = None
176 self.description = None
177 self.change_mode = None
178 self.access_modes = []
179 self.enum_types = []
180 self.unit_type = None
Yu Shan63e24d72022-06-24 17:53:32 +0000181
Yu Shan8ddd65d2023-06-28 17:02:29 -0700182 def __repr__(self):
183 return self.__str__()
184
185 def __str__(self):
186 return ('PropertyConfig{{' +
187 'name: {}, description: {}, change_mode: {}, access_modes: {}, enum_types: {}' +
188 ', unit_type: {}}}').format(self.name, self.description, self.change_mode,
189 self.access_modes, self.enum_types, self.unit_type)
190
191
192class FileParser:
193
194 def __init__(self):
195 self.configs = None
196
197 def parseFile(self, input_file):
198 """Parses the input VehicleProperty.aidl file into a list of property configs."""
Yu Shan63e24d72022-06-24 17:53:32 +0000199 processing = False
200 in_comment = False
Yu Shan8ddd65d2023-06-28 17:02:29 -0700201 configs = []
202 config = None
203 with open(input_file, 'r') as f:
Yu Shan63e24d72022-06-24 17:53:32 +0000204 for line in f.readlines():
205 if RE_ENUM_START.match(line):
206 processing = True
Yu Shan63e24d72022-06-24 17:53:32 +0000207 elif RE_ENUM_END.match(line):
208 processing = False
209 if not processing:
210 continue
211 if RE_COMMENT_BEGIN.match(line):
212 in_comment = True
Yu Shan8ddd65d2023-06-28 17:02:29 -0700213 config = PropertyConfig()
214 description = ''
Yu Shan63e24d72022-06-24 17:53:32 +0000215 if RE_COMMENT_END.match(line):
216 in_comment = False
217 if in_comment:
Yu Shan8ddd65d2023-06-28 17:02:29 -0700218 if not config.description:
219 sline = line.strip()
220 # Skip the first line of comment
221 if sline.startswith('*'):
222 # Remove the '*'.
223 sline = sline[1:].strip()
224 # We reach an empty line of comment, the description part is ending.
225 if sline == '':
226 config.description = description
227 else:
228 if description != '':
229 description += ' '
230 description += sline
231 match = RE_CHANGE_MODE.match(line)
232 if match:
233 config.change_mode = match.group(1).replace('VehiclePropertyChangeMode.', '')
234 match = RE_ACCESS.match(line)
235 if match:
236 config.access_modes.append(match.group(1).replace('VehiclePropertyAccess.', ''))
237 match = RE_UNIT.match(line)
238 if match:
239 config.unit_type = match.group(1)
240 match = RE_DATA_ENUM.match(line)
241 if match:
242 config.enum_types.append(match.group(1))
Yu Shan63e24d72022-06-24 17:53:32 +0000243 else:
244 match = RE_VALUE.match(line)
245 if match:
246 prop_name = match.group(1)
Yu Shan41dd7f12023-06-07 13:25:43 -0700247 if prop_name == 'INVALID':
Yu Shan63e24d72022-06-24 17:53:32 +0000248 continue
Yu Shan8ddd65d2023-06-28 17:02:29 -0700249 if not config.change_mode:
Yu Shan41dd7f12023-06-07 13:25:43 -0700250 raise Exception(
Yu Shan8ddd65d2023-06-28 17:02:29 -0700251 'No change_mode annotation for property: ' + prop_name)
252 if not config.access_modes:
253 raise Exception(
254 'No access_mode annotation for property: ' + prop_name)
255 config.name = prop_name
256 configs.append(config)
257
258 self.configs = configs
259
260 def convert(self, output, header, footer, cpp, field):
261 """Converts the property config file to C++/Java output file."""
262 counter = 0
263 content = LICENSE + header
264 for config in self.configs:
265 if field == 'change_mode':
266 if cpp:
267 annotation = "VehiclePropertyChangeMode::" + config.change_mode
268 else:
269 annotation = "VehiclePropertyChangeMode." + config.change_mode
270 elif field == 'access_mode':
271 if cpp:
272 annotation = "VehiclePropertyAccess::" + config.access_modes[0]
273 else:
274 annotation = "VehiclePropertyAccess." + config.access_modes[0]
275 else:
276 raise Exception('Unknown field: ' + field)
277 if counter != 0:
278 content += '\n'
279 if cpp:
280 content += (TAB + TAB + '{VehicleProperty::' + config.name + ', ' +
281 annotation + '},')
282 else:
283 content += (TAB + TAB + 'Map.entry(VehicleProperty.' + config.name + ', ' +
284 annotation + '),')
285 counter += 1
Yu Shan63e24d72022-06-24 17:53:32 +0000286
Yu Shan41dd7f12023-06-07 13:25:43 -0700287 # Remove the additional ',' at the end for the Java file.
Yu Shan63e24d72022-06-24 17:53:32 +0000288 if not cpp:
289 content = content[:-1]
290
291 content += footer
292
293 with open(output, 'w') as f:
294 f.write(content)
295
Yu Shan8ddd65d2023-06-28 17:02:29 -0700296 def outputAsCsv(self, output):
297 content = 'name,description,change mode,access mode,enum type,unit type\n'
298 for config in self.configs:
299 enum_types = None
300 if not config.enum_types:
301 enum_types = '/'
302 else:
303 enum_types = '/'.join(config.enum_types)
304 unit_type = config.unit_type
305 if not unit_type:
306 unit_type = '/'
307 access_modes = ''
308 content += '"{}","{}","{}","{}","{}","{}"\n'.format(
309 config.name,
310 # Need to escape quote as double quote.
311 config.description.replace('"', '""'),
312 config.change_mode,
313 '/'.join(config.access_modes),
314 enum_types,
315 unit_type)
316
317 with open(output, 'w+') as f:
318 f.write(content)
319
Yu Shan63e24d72022-06-24 17:53:32 +0000320
Yu Shan41dd7f12023-06-07 13:25:43 -0700321def createTempFile():
322 f = tempfile.NamedTemporaryFile(delete=False);
323 f.close();
324 return f.name
325
326
Yu Shan63e24d72022-06-24 17:53:32 +0000327def main():
Yu Shan41dd7f12023-06-07 13:25:43 -0700328 parser = argparse.ArgumentParser(
329 description='Generate Java and C++ enums based on annotations in VehicleProperty.aidl')
330 parser.add_argument('--android_build_top', required=False, help='Path to ANDROID_BUILD_TOP')
Yu Shanb1fc8c92023-08-30 11:51:04 -0700331 parser.add_argument('--preupload_files', nargs='*', required=False, help='modified files')
Yu Shan41dd7f12023-06-07 13:25:43 -0700332 parser.add_argument('--check_only', required=False, action='store_true',
333 help='only check whether the generated files need update')
Yu Shan8ddd65d2023-06-28 17:02:29 -0700334 parser.add_argument('--output_csv', required=False,
335 help='Path to the parsing result in CSV style, useful for doc generation')
Yu Shan41dd7f12023-06-07 13:25:43 -0700336 args = parser.parse_args();
337 android_top = None
338 output_folder = None
339 if args.android_build_top:
340 android_top = args.android_build_top
341 vehiclePropertyUpdated = False
342 for preuload_file in args.preupload_files:
343 if preuload_file.endswith('VehicleProperty.aidl'):
344 vehiclePropertyUpdated = True
345 break
346 if not vehiclePropertyUpdated:
347 return
348 else:
349 android_top = os.environ['ANDROID_BUILD_TOP']
Yu Shan63e24d72022-06-24 17:53:32 +0000350 if not android_top:
Yu Shan41dd7f12023-06-07 13:25:43 -0700351 print('ANDROID_BUILD_TOP is not in envorinmental variable, please run source and lunch ' +
352 'at the android root')
Yu Shan63e24d72022-06-24 17:53:32 +0000353
354 aidl_file = os.path.join(android_top, PROP_AIDL_FILE_PATH)
Yu Shan8ddd65d2023-06-28 17:02:29 -0700355 f = FileParser();
356 f.parseFile(aidl_file)
357
358 if args.output_csv:
359 f.outputAsCsv(args.output_csv)
360 return
Yu Shan63e24d72022-06-24 17:53:32 +0000361
Yu Shan41dd7f12023-06-07 13:25:43 -0700362 change_mode_cpp_file = os.path.join(android_top, CHANGE_MODE_CPP_FILE_PATH);
363 access_cpp_file = os.path.join(android_top, ACCESS_CPP_FILE_PATH);
364 change_mode_java_file = os.path.join(android_top, CHANGE_MODE_JAVA_FILE_PATH);
365 access_java_file = os.path.join(android_top, ACCESS_JAVA_FILE_PATH);
366 temp_files = []
367
368 if not args.check_only:
369 change_mode_cpp_output = change_mode_cpp_file
370 access_cpp_output = access_cpp_file
371 change_mode_java_output = change_mode_java_file
372 access_java_output = access_java_file
373 else:
374 change_mode_cpp_output = createTempFile()
375 temp_files.append(change_mode_cpp_output)
376 access_cpp_output = createTempFile()
377 temp_files.append(access_cpp_output)
378 change_mode_java_output = createTempFile()
379 temp_files.append(change_mode_java_output)
380 access_java_output = createTempFile()
381 temp_files.append(access_java_output)
382
383 try:
Yu Shan8ddd65d2023-06-28 17:02:29 -0700384 f.convert(change_mode_cpp_output, CHANGE_MODE_CPP_HEADER, CHANGE_MODE_CPP_FOOTER,
385 True, 'change_mode')
386 f.convert(change_mode_java_output, CHANGE_MODE_JAVA_HEADER,
387 CHANGE_MODE_JAVA_FOOTER, False, 'change_mode')
388 f.convert(access_cpp_output, ACCESS_CPP_HEADER, ACCESS_CPP_FOOTER, True, 'access_mode')
389 f.convert(access_java_output, ACCESS_JAVA_HEADER, ACCESS_JAVA_FOOTER, False, 'access_mode')
Yu Shan41dd7f12023-06-07 13:25:43 -0700390
391 if not args.check_only:
392 return
393
394 if ((not filecmp.cmp(change_mode_cpp_output, change_mode_cpp_file)) or
395 (not filecmp.cmp(change_mode_java_output, change_mode_java_file)) or
396 (not filecmp.cmp(access_cpp_output, access_cpp_file)) or
397 (not filecmp.cmp(access_java_output, access_java_file))):
398 print('The generated enum files for VehicleProperty.aidl requires update, ')
399 print('Run \npython ' + android_top + '/' + SCRIPT_PATH)
400 sys.exit(1)
401 except Exception as e:
402 print('Error parsing VehicleProperty.aidl')
403 print(e)
404 sys.exit(1)
405 finally:
406 for file in temp_files:
407 os.remove(file)
Yu Shan63e24d72022-06-24 17:53:32 +0000408
409
Yu Shan41dd7f12023-06-07 13:25:43 -0700410if __name__ == '__main__':
Yu Shan63e24d72022-06-24 17:53:32 +0000411 main()