blob: 05fc99a23199d1623b16525cd7c2b02f99fc0fba [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
Tyler Trephana1828f92023-10-06 02:39:13 +000021 ChangeModeForVehicleProperty.java, AccessForVehicleProperty.java, EnumForVehicleProperty.java under generated_lib/java.
Yu Shan63e24d72022-06-24 17:53:32 +000022
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')
Tyler Trephana1828f92023-10-06 02:39:13 +000043ENUM_JAVA_FILE_PATH = ('hardware/interfaces/automotive/vehicle/aidl/generated_lib/java/' +
44 'EnumForVehicleProperty.java')
Yu Shan41dd7f12023-06-07 13:25:43 -070045SCRIPT_PATH = 'hardware/interfaces/automotive/vehicle/tools/generate_annotation_enums.py'
Yu Shan63e24d72022-06-24 17:53:32 +000046
Yu Shan41dd7f12023-06-07 13:25:43 -070047TAB = ' '
48RE_ENUM_START = re.compile('\s*enum VehicleProperty \{')
49RE_ENUM_END = re.compile('\s*\}\;')
50RE_COMMENT_BEGIN = re.compile('\s*\/\*\*?')
51RE_COMMENT_END = re.compile('\s*\*\/')
52RE_CHANGE_MODE = re.compile('\s*\* @change_mode (\S+)\s*')
53RE_ACCESS = re.compile('\s*\* @access (\S+)\s*')
Yu Shan8ddd65d2023-06-28 17:02:29 -070054RE_DATA_ENUM = re.compile('\s*\* @data_enum (\S+)\s*')
55RE_UNIT = re.compile('\s*\* @unit (\S+)\s+')
Yu Shan41dd7f12023-06-07 13:25:43 -070056RE_VALUE = re.compile('\s*(\w+)\s*=(.*)')
Yu Shan63e24d72022-06-24 17:53:32 +000057
58LICENSE = """/*
Tyler Trephana1828f92023-10-06 02:39:13 +000059 * Copyright (C) 2023 The Android Open Source Project
Yu Shan63e24d72022-06-24 17:53:32 +000060 *
61 * Licensed under the Apache License, Version 2.0 (the "License");
62 * you may not use this file except in compliance with the License.
63 * You may obtain a copy of the License at
64 *
65 * http://www.apache.org/licenses/LICENSE-2.0
66 *
67 * Unless required by applicable law or agreed to in writing, software
68 * distributed under the License is distributed on an "AS IS" BASIS,
69 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
70 * See the License for the specific language governing permissions and
71 * limitations under the License.
72 */
73
74/**
75 * DO NOT EDIT MANUALLY!!!
76 *
77 * Generated by tools/generate_annotation_enums.py.
78 */
79
Aaqib Ismail2e8915d2023-01-30 13:04:05 -080080// clang-format off
81
Yu Shan63e24d72022-06-24 17:53:32 +000082"""
83
84CHANGE_MODE_CPP_HEADER = """#ifndef android_hardware_automotive_vehicle_aidl_generated_lib_ChangeModeForVehicleProperty_H_
85#define android_hardware_automotive_vehicle_aidl_generated_lib_ChangeModeForVehicleProperty_H_
86
87#include <aidl/android/hardware/automotive/vehicle/VehicleProperty.h>
88#include <aidl/android/hardware/automotive/vehicle/VehiclePropertyChangeMode.h>
89
90#include <unordered_map>
91
92namespace aidl {
93namespace android {
94namespace hardware {
95namespace automotive {
96namespace vehicle {
97
98std::unordered_map<VehicleProperty, VehiclePropertyChangeMode> ChangeModeForVehicleProperty = {
99"""
100
101CHANGE_MODE_CPP_FOOTER = """
102};
103
104} // namespace vehicle
105} // namespace automotive
106} // namespace hardware
107} // namespace android
108} // aidl
109
110#endif // android_hardware_automotive_vehicle_aidl_generated_lib_ChangeModeForVehicleProperty_H_
111"""
112
113ACCESS_CPP_HEADER = """#ifndef android_hardware_automotive_vehicle_aidl_generated_lib_AccessForVehicleProperty_H_
114#define android_hardware_automotive_vehicle_aidl_generated_lib_AccessForVehicleProperty_H_
115
116#include <aidl/android/hardware/automotive/vehicle/VehicleProperty.h>
117#include <aidl/android/hardware/automotive/vehicle/VehiclePropertyAccess.h>
118
119#include <unordered_map>
120
121namespace aidl {
122namespace android {
123namespace hardware {
124namespace automotive {
125namespace vehicle {
126
127std::unordered_map<VehicleProperty, VehiclePropertyAccess> AccessForVehicleProperty = {
128"""
129
130ACCESS_CPP_FOOTER = """
131};
132
133} // namespace vehicle
134} // namespace automotive
135} // namespace hardware
136} // namespace android
137} // aidl
138
139#endif // android_hardware_automotive_vehicle_aidl_generated_lib_AccessForVehicleProperty_H_
140"""
141
142CHANGE_MODE_JAVA_HEADER = """package android.hardware.automotive.vehicle;
143
144import java.util.Map;
145
146public final class ChangeModeForVehicleProperty {
147
148 public static final Map<Integer, Integer> values = Map.ofEntries(
149"""
150
151CHANGE_MODE_JAVA_FOOTER = """
152 );
153
154}
155"""
156
157ACCESS_JAVA_HEADER = """package android.hardware.automotive.vehicle;
158
159import java.util.Map;
160
161public final class AccessForVehicleProperty {
162
163 public static final Map<Integer, Integer> values = Map.ofEntries(
164"""
165
166ACCESS_JAVA_FOOTER = """
167 );
168
169}
170"""
171
Tyler Trephana1828f92023-10-06 02:39:13 +0000172ENUM_JAVA_HEADER = """package android.hardware.automotive.vehicle;
173
174import java.util.List;
175import java.util.Map;
176
177public final class EnumForVehicleProperty {
178
179 public static final Map<Integer, List<Class<?>>> values = Map.ofEntries(
180"""
181
182ENUM_JAVA_FOOTER = """
183 );
184
185}
186"""
187
Yu Shan63e24d72022-06-24 17:53:32 +0000188
Yu Shan8ddd65d2023-06-28 17:02:29 -0700189class PropertyConfig:
190 """Represents one VHAL property definition in VehicleProperty.aidl."""
Yu Shan63e24d72022-06-24 17:53:32 +0000191
Yu Shan8ddd65d2023-06-28 17:02:29 -0700192 def __init__(self):
193 self.name = None
194 self.description = None
195 self.change_mode = None
196 self.access_modes = []
197 self.enum_types = []
198 self.unit_type = None
Yu Shan63e24d72022-06-24 17:53:32 +0000199
Yu Shan8ddd65d2023-06-28 17:02:29 -0700200 def __repr__(self):
201 return self.__str__()
202
203 def __str__(self):
204 return ('PropertyConfig{{' +
205 'name: {}, description: {}, change_mode: {}, access_modes: {}, enum_types: {}' +
206 ', unit_type: {}}}').format(self.name, self.description, self.change_mode,
207 self.access_modes, self.enum_types, self.unit_type)
208
209
210class FileParser:
211
212 def __init__(self):
213 self.configs = None
214
215 def parseFile(self, input_file):
216 """Parses the input VehicleProperty.aidl file into a list of property configs."""
Yu Shan63e24d72022-06-24 17:53:32 +0000217 processing = False
218 in_comment = False
Yu Shan8ddd65d2023-06-28 17:02:29 -0700219 configs = []
220 config = None
221 with open(input_file, 'r') as f:
Yu Shan63e24d72022-06-24 17:53:32 +0000222 for line in f.readlines():
223 if RE_ENUM_START.match(line):
224 processing = True
Yu Shan63e24d72022-06-24 17:53:32 +0000225 elif RE_ENUM_END.match(line):
226 processing = False
227 if not processing:
228 continue
229 if RE_COMMENT_BEGIN.match(line):
230 in_comment = True
Yu Shan8ddd65d2023-06-28 17:02:29 -0700231 config = PropertyConfig()
232 description = ''
Yu Shan63e24d72022-06-24 17:53:32 +0000233 if RE_COMMENT_END.match(line):
234 in_comment = False
235 if in_comment:
Yu Shan8ddd65d2023-06-28 17:02:29 -0700236 if not config.description:
237 sline = line.strip()
238 # Skip the first line of comment
239 if sline.startswith('*'):
240 # Remove the '*'.
241 sline = sline[1:].strip()
242 # We reach an empty line of comment, the description part is ending.
243 if sline == '':
244 config.description = description
245 else:
246 if description != '':
247 description += ' '
248 description += sline
249 match = RE_CHANGE_MODE.match(line)
250 if match:
251 config.change_mode = match.group(1).replace('VehiclePropertyChangeMode.', '')
252 match = RE_ACCESS.match(line)
253 if match:
254 config.access_modes.append(match.group(1).replace('VehiclePropertyAccess.', ''))
255 match = RE_UNIT.match(line)
256 if match:
257 config.unit_type = match.group(1)
258 match = RE_DATA_ENUM.match(line)
259 if match:
260 config.enum_types.append(match.group(1))
Yu Shan63e24d72022-06-24 17:53:32 +0000261 else:
262 match = RE_VALUE.match(line)
263 if match:
264 prop_name = match.group(1)
Yu Shan41dd7f12023-06-07 13:25:43 -0700265 if prop_name == 'INVALID':
Yu Shan63e24d72022-06-24 17:53:32 +0000266 continue
Yu Shan8ddd65d2023-06-28 17:02:29 -0700267 if not config.change_mode:
Yu Shan41dd7f12023-06-07 13:25:43 -0700268 raise Exception(
Yu Shan8ddd65d2023-06-28 17:02:29 -0700269 'No change_mode annotation for property: ' + prop_name)
270 if not config.access_modes:
271 raise Exception(
272 'No access_mode annotation for property: ' + prop_name)
273 config.name = prop_name
274 configs.append(config)
275
276 self.configs = configs
277
278 def convert(self, output, header, footer, cpp, field):
279 """Converts the property config file to C++/Java output file."""
280 counter = 0
281 content = LICENSE + header
282 for config in self.configs:
283 if field == 'change_mode':
284 if cpp:
285 annotation = "VehiclePropertyChangeMode::" + config.change_mode
286 else:
287 annotation = "VehiclePropertyChangeMode." + config.change_mode
288 elif field == 'access_mode':
289 if cpp:
290 annotation = "VehiclePropertyAccess::" + config.access_modes[0]
291 else:
292 annotation = "VehiclePropertyAccess." + config.access_modes[0]
Tyler Trephana1828f92023-10-06 02:39:13 +0000293 elif field == 'enum_types':
294 if len(config.enum_types) < 1:
295 continue;
296 if not cpp:
297 annotation = "List.of(" + ', '.join([class_name + ".class" for class_name in config.enum_types]) + ")"
Yu Shan8ddd65d2023-06-28 17:02:29 -0700298 else:
299 raise Exception('Unknown field: ' + field)
300 if counter != 0:
301 content += '\n'
302 if cpp:
303 content += (TAB + TAB + '{VehicleProperty::' + config.name + ', ' +
304 annotation + '},')
305 else:
306 content += (TAB + TAB + 'Map.entry(VehicleProperty.' + config.name + ', ' +
307 annotation + '),')
308 counter += 1
Yu Shan63e24d72022-06-24 17:53:32 +0000309
Yu Shan41dd7f12023-06-07 13:25:43 -0700310 # Remove the additional ',' at the end for the Java file.
Yu Shan63e24d72022-06-24 17:53:32 +0000311 if not cpp:
312 content = content[:-1]
313
314 content += footer
315
316 with open(output, 'w') as f:
317 f.write(content)
318
Yu Shan8ddd65d2023-06-28 17:02:29 -0700319 def outputAsCsv(self, output):
320 content = 'name,description,change mode,access mode,enum type,unit type\n'
321 for config in self.configs:
322 enum_types = None
323 if not config.enum_types:
324 enum_types = '/'
325 else:
326 enum_types = '/'.join(config.enum_types)
327 unit_type = config.unit_type
328 if not unit_type:
329 unit_type = '/'
330 access_modes = ''
331 content += '"{}","{}","{}","{}","{}","{}"\n'.format(
332 config.name,
333 # Need to escape quote as double quote.
334 config.description.replace('"', '""'),
335 config.change_mode,
336 '/'.join(config.access_modes),
337 enum_types,
338 unit_type)
339
340 with open(output, 'w+') as f:
341 f.write(content)
342
Yu Shan63e24d72022-06-24 17:53:32 +0000343
Yu Shan41dd7f12023-06-07 13:25:43 -0700344def createTempFile():
345 f = tempfile.NamedTemporaryFile(delete=False);
346 f.close();
347 return f.name
348
349
Yu Shan63e24d72022-06-24 17:53:32 +0000350def main():
Yu Shan41dd7f12023-06-07 13:25:43 -0700351 parser = argparse.ArgumentParser(
352 description='Generate Java and C++ enums based on annotations in VehicleProperty.aidl')
353 parser.add_argument('--android_build_top', required=False, help='Path to ANDROID_BUILD_TOP')
Yu Shanb1fc8c92023-08-30 11:51:04 -0700354 parser.add_argument('--preupload_files', nargs='*', required=False, help='modified files')
Yu Shan41dd7f12023-06-07 13:25:43 -0700355 parser.add_argument('--check_only', required=False, action='store_true',
356 help='only check whether the generated files need update')
Yu Shan8ddd65d2023-06-28 17:02:29 -0700357 parser.add_argument('--output_csv', required=False,
358 help='Path to the parsing result in CSV style, useful for doc generation')
Yu Shan41dd7f12023-06-07 13:25:43 -0700359 args = parser.parse_args();
360 android_top = None
361 output_folder = None
362 if args.android_build_top:
363 android_top = args.android_build_top
364 vehiclePropertyUpdated = False
365 for preuload_file in args.preupload_files:
366 if preuload_file.endswith('VehicleProperty.aidl'):
367 vehiclePropertyUpdated = True
368 break
369 if not vehiclePropertyUpdated:
370 return
371 else:
372 android_top = os.environ['ANDROID_BUILD_TOP']
Yu Shan63e24d72022-06-24 17:53:32 +0000373 if not android_top:
Tyler Trephana1828f92023-10-06 02:39:13 +0000374 print('ANDROID_BUILD_TOP is not in environmental variable, please run source and lunch ' +
Yu Shan41dd7f12023-06-07 13:25:43 -0700375 'at the android root')
Yu Shan63e24d72022-06-24 17:53:32 +0000376
377 aidl_file = os.path.join(android_top, PROP_AIDL_FILE_PATH)
Yu Shan8ddd65d2023-06-28 17:02:29 -0700378 f = FileParser();
379 f.parseFile(aidl_file)
380
381 if args.output_csv:
382 f.outputAsCsv(args.output_csv)
383 return
Yu Shan63e24d72022-06-24 17:53:32 +0000384
Yu Shan41dd7f12023-06-07 13:25:43 -0700385 change_mode_cpp_file = os.path.join(android_top, CHANGE_MODE_CPP_FILE_PATH);
386 access_cpp_file = os.path.join(android_top, ACCESS_CPP_FILE_PATH);
387 change_mode_java_file = os.path.join(android_top, CHANGE_MODE_JAVA_FILE_PATH);
388 access_java_file = os.path.join(android_top, ACCESS_JAVA_FILE_PATH);
Tyler Trephana1828f92023-10-06 02:39:13 +0000389 enum_java_file = os.path.join(android_top, ENUM_JAVA_FILE_PATH);
Yu Shan41dd7f12023-06-07 13:25:43 -0700390 temp_files = []
391
392 if not args.check_only:
393 change_mode_cpp_output = change_mode_cpp_file
394 access_cpp_output = access_cpp_file
395 change_mode_java_output = change_mode_java_file
396 access_java_output = access_java_file
Tyler Trephana1828f92023-10-06 02:39:13 +0000397 enum_java_output = enum_java_file
Yu Shan41dd7f12023-06-07 13:25:43 -0700398 else:
399 change_mode_cpp_output = createTempFile()
400 temp_files.append(change_mode_cpp_output)
401 access_cpp_output = createTempFile()
402 temp_files.append(access_cpp_output)
403 change_mode_java_output = createTempFile()
404 temp_files.append(change_mode_java_output)
405 access_java_output = createTempFile()
406 temp_files.append(access_java_output)
Tyler Trephana1828f92023-10-06 02:39:13 +0000407 enum_java_output = createTempFile()
408 temp_files.append(enum_java_output)
Yu Shan41dd7f12023-06-07 13:25:43 -0700409
410 try:
Yu Shan8ddd65d2023-06-28 17:02:29 -0700411 f.convert(change_mode_cpp_output, CHANGE_MODE_CPP_HEADER, CHANGE_MODE_CPP_FOOTER,
412 True, 'change_mode')
413 f.convert(change_mode_java_output, CHANGE_MODE_JAVA_HEADER,
414 CHANGE_MODE_JAVA_FOOTER, False, 'change_mode')
415 f.convert(access_cpp_output, ACCESS_CPP_HEADER, ACCESS_CPP_FOOTER, True, 'access_mode')
416 f.convert(access_java_output, ACCESS_JAVA_HEADER, ACCESS_JAVA_FOOTER, False, 'access_mode')
Tyler Trephana1828f92023-10-06 02:39:13 +0000417 f.convert(enum_java_output, ENUM_JAVA_HEADER, ENUM_JAVA_FOOTER, False, 'enum_types')
Yu Shan41dd7f12023-06-07 13:25:43 -0700418
419 if not args.check_only:
420 return
421
422 if ((not filecmp.cmp(change_mode_cpp_output, change_mode_cpp_file)) or
423 (not filecmp.cmp(change_mode_java_output, change_mode_java_file)) or
424 (not filecmp.cmp(access_cpp_output, access_cpp_file)) or
Tyler Trephana1828f92023-10-06 02:39:13 +0000425 (not filecmp.cmp(access_java_output, access_java_file)) or
426 (not filecmp.cmp(enum_java_output, enum_java_file))):
Yu Shan41dd7f12023-06-07 13:25:43 -0700427 print('The generated enum files for VehicleProperty.aidl requires update, ')
428 print('Run \npython ' + android_top + '/' + SCRIPT_PATH)
429 sys.exit(1)
430 except Exception as e:
431 print('Error parsing VehicleProperty.aidl')
432 print(e)
433 sys.exit(1)
434 finally:
435 for file in temp_files:
436 os.remove(file)
Yu Shan63e24d72022-06-24 17:53:32 +0000437
438
Yu Shan41dd7f12023-06-07 13:25:43 -0700439if __name__ == '__main__':
Yu Shan63e24d72022-06-24 17:53:32 +0000440 main()