1#!/usr/bin/python3 2 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/version/cpp and 21 ChangeModeForVehicleProperty.java, AccessForVehicleProperty.java, EnumForVehicleProperty.java 22 UnitsForVehicleProperty.java under generated_lib/version/java. 23 24 Usage: 25 $ python generate_annotation_enums.py 26""" 27import argparse 28import filecmp 29import os 30import re 31import sys 32import tempfile 33 34# Keep this updated with the latest in-development property version. 35PROPERTY_VERSION = '4' 36 37PROP_AIDL_FILE_PATH = ('hardware/interfaces/automotive/vehicle/aidl_property/android/hardware/' + 38 'automotive/vehicle/VehicleProperty.aidl') 39GENERATED_LIB = ('hardware/interfaces/automotive/vehicle/aidl/generated_lib/' + PROPERTY_VERSION + 40 '/') 41CHANGE_MODE_CPP_FILE_PATH = GENERATED_LIB + '/cpp/ChangeModeForVehicleProperty.h' 42ACCESS_CPP_FILE_PATH = GENERATED_LIB + '/cpp/AccessForVehicleProperty.h' 43CHANGE_MODE_JAVA_FILE_PATH = GENERATED_LIB + '/java/ChangeModeForVehicleProperty.java' 44ACCESS_JAVA_FILE_PATH = GENERATED_LIB + '/java/AccessForVehicleProperty.java' 45ENUM_CPP_FILE_PATH = GENERATED_LIB + '/cpp/EnumForVehicleProperty.h' 46ENUM_JAVA_FILE_PATH = GENERATED_LIB + '/java/EnumForVehicleProperty.java' 47UNITS_JAVA_FILE_PATH = GENERATED_LIB + '/java/UnitsForVehicleProperty.java' 48VERSION_CPP_FILE_PATH = GENERATED_LIB + '/cpp/VersionForVehicleProperty.h' 49ANNOTATIONS_CPP_FILE_PATH = GENERATED_LIB + '/cpp/AnnotationsForVehicleProperty.h' 50ANNOTATIONS_JAVA_FILE_PATH = GENERATED_LIB + '/java/AnnotationsForVehicleProperty.java' 51SCRIPT_PATH = 'hardware/interfaces/automotive/vehicle/tools/generate_annotation_enums.py' 52 53TAB = ' ' 54RE_ENUM_START = re.compile(r'\s*enum VehicleProperty \{') 55RE_ENUM_END = re.compile(r'\s*\}\;') 56RE_COMMENT_BEGIN = re.compile(r'\s*\/\*\*?') 57RE_COMMENT_END = re.compile(r'\s*\*\/') 58RE_CHANGE_MODE = re.compile(r'\s*\* @change_mode (\S+)\s*') 59RE_VERSION = re.compile(r'\s*\* @version (\S+)\s*') 60RE_ACCESS = re.compile(r'\s*\* @access (\S+)\s*') 61RE_DATA_ENUM = re.compile(r'\s*\* @data_enum (\S+)\s*') 62RE_UNIT = re.compile(r'\s*\* @unit (\S+)\s+') 63RE_VALUE = re.compile(r'\s*(\w+)\s*=(.*)') 64RE_ANNOTATION = re.compile(r'\s*\* @(\S+)\s*') 65 66SUPPORTED_ANNOTATIONS = ['change_mode', 'access', 'unit', 'data_enum', 'data_enum_bit_flags', 67 'version', 'require_min_max_supported_value', 'require_supported_values_list', 68 'legacy_supported_values_in_config'] 69 70# Non static data_enum properties that do not require supported values list. 71# These properties are either deprecated or for internal use only. 72ENUM_PROPERTIES_WITHOUT_SUPPORTED_VALUES = [ 73 # deprecated 74 'TURN_SIGNAL_STATE', 75 # The supported values are exposed through HVAC_FAN_DIRECTION_AVAILABLE 76 'HVAC_FAN_DIRECTION', 77 # Internal use only 78 'HW_ROTARY_INPUT', 79 # Internal use only 80 'HW_CUSTOM_INPUT', 81 # Internal use only 82 'SHUTDOWN_REQUEST', 83 # Internal use only 84 'CAMERA_SERVICE_CURRENT_STATE' 85] 86 87LICENSE = """/* 88 * Copyright (C) 2025 The Android Open Source Project 89 * 90 * Licensed under the Apache License, Version 2.0 (the "License"); 91 * you may not use this file except in compliance with the License. 92 * You may obtain a copy of the License at 93 * 94 * http://www.apache.org/licenses/LICENSE-2.0 95 * 96 * Unless required by applicable law or agreed to in writing, software 97 * distributed under the License is distributed on an "AS IS" BASIS, 98 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 99 * See the License for the specific language governing permissions and 100 * limitations under the License. 101 */ 102 103/** 104 * DO NOT EDIT MANUALLY!!! 105 * 106 * Generated by tools/generate_annotation_enums.py. 107 */ 108 109// clang-format off 110 111""" 112 113CHANGE_MODE_CPP_FORMATTER = """#pragma once 114 115#include <aidl/android/hardware/automotive/vehicle/VehicleProperty.h> 116#include <aidl/android/hardware/automotive/vehicle/VehiclePropertyChangeMode.h> 117 118#include <unordered_map> 119 120namespace aidl::android::hardware::automotive::vehicle {{ 121std::unordered_map<VehicleProperty, VehiclePropertyChangeMode> ChangeModeForVehicleProperty = {{ 122{0} 123}}; 124}} // aidl::android::hardware::automotive::vehicle 125""" 126 127ACCESS_CPP_FORMATTER = """#pragma once 128 129#include <aidl/android/hardware/automotive/vehicle/VehicleProperty.h> 130#include <aidl/android/hardware/automotive/vehicle/VehiclePropertyAccess.h> 131 132#include <unordered_map> 133 134namespace aidl::android::hardware::automotive::vehicle {{ 135// This map represents the default access mode for each property. 136std::unordered_map<VehicleProperty, VehiclePropertyAccess> DefaultAccessForVehicleProperty = {{ 137{0} 138}}; 139 140// This map represents the allowed access modes for each property. 141std::unordered_map<VehicleProperty, std::vector<VehiclePropertyAccess>> 142 AllowedAccessForVehicleProperty = {{ 143{1} 144}}; 145}} // aidl::android::hardware::automotive::vehicle 146""" 147 148VERSION_CPP_FORMATTER = """#pragma once 149 150#include <aidl/android/hardware/automotive/vehicle/VehicleProperty.h> 151 152#include <unordered_map> 153 154namespace aidl::android::hardware::automotive::vehicle {{ 155std::unordered_map<VehicleProperty, int32_t> VersionForVehicleProperty = {{ 156{0} 157}}; 158}} // aidl::android::hardware::automotive::vehicle 159""" 160 161ANNOTATIONS_CPP_FORMATTER = """#pragma once 162 163#include <aidl/android/hardware/automotive/vehicle/VehicleProperty.h> 164 165#include <string> 166#include <unordered_map> 167#include <unordered_set> 168 169namespace aidl::android::hardware::automotive::vehicle {{ 170std::unordered_map<VehicleProperty, std::unordered_set<std::string>> 171 AnnotationsForVehicleProperty = {{ 172{0} 173}}; 174}} // aidl::android::hardware::automotive::vehicle 175""" 176 177ENUM_CPP_FORMATTER = """#pragma once 178 179#define addSupportedValues(EnumType) \\ 180{{ \\ 181constexpr auto values = ndk::internal::enum_values<EnumType>; \\ 182for (size_t i = 0; i < values.size(); i++) {{ \\ 183 supportedValues.insert(static_cast<int64_t>(values[i])); \\ 184}} \\ 185}} 186 187#include <VehicleHalTypes.h> 188#include <aidl/android/hardware/automotive/vehicle/VehicleProperty.h> 189 190#include <unordered_set> 191 192namespace aidl::android::hardware::automotive::vehicle {{ 193std::unordered_set<int64_t> getSupportedEnumValuesForProperty(VehicleProperty propertyId) {{ 194 std::unordered_set<int64_t> supportedValues; 195 switch (propertyId) {{ 196{0} 197 default: 198 // Do nothing. 199 break; 200 }} 201 return supportedValues; 202}} 203}} // aidl::android::hardware::automotive::vehicle 204""" 205 206ENUM_CPP_SWITCH_CASE_FORMATTER = """ case {0}: 207{1} 208 break; 209""" 210 211CHANGE_MODE_JAVA_FORMATTER = """package android.hardware.automotive.vehicle; 212 213import java.util.Map; 214 215public final class ChangeModeForVehicleProperty {{ 216 217 public static final Map<Integer, Integer> values = Map.ofEntries( 218{0} 219 ); 220 221}} 222""" 223 224ACCESS_JAVA_FORMATTER = """package android.hardware.automotive.vehicle; 225 226import java.util.Map; 227 228public final class AccessForVehicleProperty {{ 229 230 public static final Map<Integer, Integer> values = Map.ofEntries( 231{0} 232 ); 233 234}} 235""" 236 237ENUM_JAVA_FORMATTER = """package android.hardware.automotive.vehicle; 238 239import java.util.List; 240import java.util.Map; 241 242public final class EnumForVehicleProperty {{ 243 244 public static final Map<Integer, List<Class<?>>> values = Map.ofEntries( 245{0} 246 ); 247 248}} 249""" 250 251UNITS_JAVA_FORMATTER = """package android.hardware.automotive.vehicle; 252 253import java.util.Map; 254 255public final class UnitsForVehicleProperty {{ 256 257 public static final Map<Integer, Integer> values = Map.ofEntries( 258{0} 259 ); 260 261}} 262""" 263 264ANNOTATIONS_JAVA_FORMATTER = """package android.hardware.automotive.vehicle; 265 266import java.util.Set; 267import java.util.Map; 268 269public final class AnnotationsForVehicleProperty {{ 270 271 public static final Map<Integer, Set<String>> values = Map.ofEntries( 272{0} 273 ); 274 275}} 276""" 277 278 279class PropertyConfig: 280 """Represents one VHAL property definition in VehicleProperty.aidl.""" 281 282 def __init__(self): 283 self.name = None 284 self.description = None 285 self.comment = None 286 self.change_mode = None 287 self.access_modes = [] 288 self.enum_types = [] 289 self.unit_type = None 290 self.version = None 291 # Use a set to avoid duplicate annotation. 292 self.annotations = set() 293 294 def __repr__(self): 295 return self.__str__() 296 297 def __str__(self): 298 return ('PropertyConfig{{' + 299 'name: {}, description: {}, change_mode: {}, access_modes: {}, enum_types: {}' + 300 ', unit_type: {}, version: {}, comment: {}}}').format(self.name, self.description, 301 self.change_mode, self.access_modes, self.enum_types, self.unit_type, 302 self.version, self.comment) 303 304 305class FileParser: 306 307 def __init__(self): 308 self.configs = None 309 310 def parseFile(self, input_file): 311 """Parses the input VehicleProperty.aidl file into a list of property configs.""" 312 processing = False 313 in_comment = False 314 configs = [] 315 config = None 316 with open(input_file, 'r') as f: 317 for line in f.readlines(): 318 if RE_ENUM_START.match(line): 319 processing = True 320 elif RE_ENUM_END.match(line): 321 processing = False 322 if not processing: 323 continue 324 if RE_COMMENT_BEGIN.match(line): 325 in_comment = True 326 config = PropertyConfig() 327 # Use an array so that we could modify the string in parseComment. 328 description = [''] 329 continue 330 331 if RE_COMMENT_END.match(line): 332 in_comment = False 333 if in_comment: 334 # We will update the string in description in this function. 335 self.parseComment(line, config, description) 336 else: 337 match = RE_VALUE.match(line) 338 if match: 339 prop_name = match.group(1) 340 if prop_name == 'INVALID': 341 continue 342 if not config.change_mode: 343 raise Exception( 344 'No change_mode annotation for property: ' + prop_name) 345 if not config.access_modes: 346 raise Exception( 347 'No access_mode annotation for property: ' + prop_name) 348 if not config.version: 349 raise Exception( 350 'No version annotation for property: ' + prop_name) 351 if ('data_enum' in config.annotations and 352 'require_supported_values_list' not in config.annotations and 353 config.change_mode != 'STATIC' and 354 prop_name not in ENUM_PROPERTIES_WITHOUT_SUPPORTED_VALUES): 355 raise Exception( 356 'The property: ' + prop_name + ' has @data_enum ' 357 'annotation but does not have @require_supported_values_list' 358 ', either add the annotation or add the property name to ' 359 'ENUM_PROPERTIES_WITHOUT_SUPPORTED_VALUES in ' 360 'generate_annotation_enums.py') 361 362 config.name = prop_name 363 configs.append(config) 364 365 self.configs = configs 366 367 def parseComment(self, line, config, description): 368 match_annotation = RE_ANNOTATION.match(line) 369 if match_annotation: 370 annotation = match_annotation.group(1) 371 if annotation not in SUPPORTED_ANNOTATIONS: 372 raise Exception('Annotation: @' + annotation + " is not supported, typo?") 373 config.annotations.add(annotation) 374 match = RE_CHANGE_MODE.match(line) 375 if match: 376 config.change_mode = match.group(1).replace('VehiclePropertyChangeMode.', '') 377 return 378 match = RE_ACCESS.match(line) 379 if match: 380 config.access_modes.append(match.group(1).replace('VehiclePropertyAccess.', '')) 381 return 382 match = RE_UNIT.match(line) 383 if match: 384 config.unit_type = match.group(1) 385 return 386 match = RE_DATA_ENUM.match(line) 387 if match: 388 config.enum_types.append(match.group(1)) 389 return 390 match = RE_VERSION.match(line) 391 if match: 392 if config.version != None: 393 raise Exception('Duplicate version annotation for property: ' + prop_name) 394 config.version = match.group(1) 395 return 396 397 sline = line.strip() 398 if sline.startswith('*'): 399 # Remove the '*'. 400 sline = sline[1:].strip() 401 402 if not config.description: 403 # We reach an empty line of comment, the description part is ending. 404 if sline == '': 405 config.description = description[0] 406 else: 407 if description[0] != '': 408 description[0] += ' ' 409 description[0] += sline 410 else: 411 if not config.comment: 412 if sline != '': 413 # This is the first line for comment. 414 config.comment = sline 415 else: 416 if sline != '': 417 # Concat this line with the previous line's comment with a space. 418 config.comment += ' ' + sline 419 else: 420 # Treat empty line comment as a new line. 421 config.comment += '\n' 422 423 def convert(self, output, formatter, cpp, field): 424 """Converts the property config file to C++/Java output file.""" 425 counter = 0 426 content = '' 427 for config in self.configs: 428 if field == 'change_mode': 429 if cpp: 430 value = "VehiclePropertyChangeMode::" + config.change_mode 431 else: 432 value = "VehiclePropertyChangeMode." + config.change_mode 433 elif field == 'access_mode': 434 if cpp: 435 value = "VehiclePropertyAccess::" + config.access_modes[0] 436 else: 437 value = "VehiclePropertyAccess." + config.access_modes[0] 438 elif field == 'enum_types': 439 if len(config.enum_types) < 1: 440 continue 441 if cpp: 442 switch_case = '' 443 for index, enum_type in enumerate(config.enum_types): 444 if index != 0: 445 switch_case += '\n' 446 switch_case += TAB + TAB + TAB + 'addSupportedValues({0})'.format(enum_type) 447 content += ENUM_CPP_SWITCH_CASE_FORMATTER.format( 448 'VehicleProperty::' + config.name, switch_case) 449 continue 450 else: 451 value = "List.of(" + ', '.join([class_name + ".class" for class_name in config.enum_types]) + ")" 452 elif field == 'unit_type': 453 if not config.unit_type: 454 continue 455 if not cpp: 456 value = config.unit_type 457 elif field == 'version': 458 if cpp: 459 value = config.version 460 elif field == 'annotations': 461 if len(config.annotations) < 1: 462 continue 463 joined_annotation_strings = ', '.join(['"' + annotation + '"' for annotation in sorted(config.annotations)]) 464 if cpp: 465 value = "{" + joined_annotation_strings + "}" 466 else: 467 value = "Set.of(" + joined_annotation_strings + ")" 468 else: 469 raise Exception('Unknown field: ' + field) 470 if counter != 0: 471 content += '\n' 472 if cpp: 473 content += (TAB + TAB + '{VehicleProperty::' + config.name + ', ' + 474 value + '},') 475 else: 476 content += (TAB + TAB + 'Map.entry(VehicleProperty.' + config.name + ', ' + 477 value + '),') 478 counter += 1 479 480 # Remove the additional ',' at the end for the Java file. 481 if not cpp: 482 content = content[:-1] 483 484 if field != 'access_mode' or not cpp: 485 content = LICENSE + formatter.format(content) 486 else: 487 content2 = '' 488 counter = 0 489 for config in self.configs: 490 if counter != 0: 491 content2 += '\n' 492 value = ', '. join(['VehiclePropertyAccess::' + access_mode for access_mode in config.access_modes]) 493 content2 += TAB + TAB + '{{VehicleProperty::{0}, {{{1}}}}},'.format(config.name, value) 494 counter += 1 495 content = LICENSE + formatter.format(content, content2) 496 497 498 with open(output, 'w') as f: 499 f.write(content) 500 501 def outputAsCsv(self, output): 502 content = 'name,description,change mode,access mode,enum type,unit type,comment\n' 503 for config in self.configs: 504 enum_types = None 505 if not config.enum_types: 506 enum_types = '/' 507 else: 508 enum_types = '/'.join(config.enum_types) 509 unit_type = config.unit_type 510 if not unit_type: 511 unit_type = '/' 512 access_modes = '' 513 comment = config.comment 514 if not comment: 515 comment = '' 516 content += '"{}","{}","{}","{}","{}","{}", "{}"\n'.format( 517 config.name, 518 # Need to escape quote as double quote. 519 config.description.replace('"', '""'), 520 config.change_mode, 521 '/'.join(config.access_modes), 522 enum_types, 523 unit_type, 524 comment.replace('"', '""')) 525 526 with open(output, 'w+') as f: 527 f.write(content) 528 529 530def createTempFile(): 531 f = tempfile.NamedTemporaryFile(delete=False); 532 f.close(); 533 return f.name 534 535 536class GeneratedFile: 537 538 def __init__(self, type): 539 self.type = type 540 self.cpp_file_path = None 541 self.java_file_path = None 542 self.cpp_formatter = None 543 self.java_formatter = None 544 self.cpp_output_file = None 545 self.java_output_file = None 546 547 def setCppFilePath(self, cpp_file_path): 548 self.cpp_file_path = cpp_file_path 549 550 def setJavaFilePath(self, java_file_path): 551 self.java_file_path = java_file_path 552 553 def setCppFormatter(self, cpp_formatter): 554 self.cpp_formatter = cpp_formatter 555 556 def setJavaFormatter(self, java_formatter): 557 self.java_formatter = java_formatter 558 559 def convert(self, file_parser, check_only, temp_files): 560 if self.cpp_file_path: 561 output_file = GeneratedFile._getOutputFile(self.cpp_file_path, check_only, temp_files) 562 file_parser.convert(output_file, self.cpp_formatter, True, self.type) 563 self.cpp_output_file = output_file 564 565 if self.java_file_path: 566 output_file = GeneratedFile._getOutputFile(self.java_file_path, check_only, temp_files) 567 file_parser.convert(output_file, self.java_formatter, False, self.type) 568 self.java_output_file = output_file 569 570 def cmp(self): 571 if self.cpp_file_path: 572 if not filecmp.cmp(self.cpp_output_file, self.cpp_file_path): 573 return False 574 575 if self.java_file_path: 576 if not filecmp.cmp(self.java_output_file, self.java_file_path): 577 return False 578 579 return True 580 581 @staticmethod 582 def _getOutputFile(file_path, check_only, temp_files): 583 if not check_only: 584 return file_path 585 586 temp_file = createTempFile() 587 temp_files.append(temp_file) 588 return temp_file 589 590 591def main(): 592 parser = argparse.ArgumentParser( 593 description='Generate Java and C++ enums based on annotations in VehicleProperty.aidl') 594 parser.add_argument('--android_build_top', required=False, help='Path to ANDROID_BUILD_TOP') 595 parser.add_argument('--preupload_files', nargs='*', required=False, help='modified files') 596 parser.add_argument('--check_only', required=False, action='store_true', 597 help='only check whether the generated files need update') 598 parser.add_argument('--output_csv', required=False, 599 help='Path to the parsing result in CSV style, useful for doc generation') 600 args = parser.parse_args(); 601 android_top = None 602 output_folder = None 603 if args.android_build_top: 604 android_top = args.android_build_top 605 vehiclePropertyUpdated = False 606 for preuload_file in args.preupload_files: 607 if preuload_file.endswith('VehicleProperty.aidl'): 608 vehiclePropertyUpdated = True 609 break 610 if not vehiclePropertyUpdated: 611 return 612 else: 613 android_top = os.environ['ANDROID_BUILD_TOP'] 614 if not android_top: 615 print('ANDROID_BUILD_TOP is not in environmental variable, please run source and lunch ' + 616 'at the android root') 617 618 aidl_file = os.path.join(android_top, PROP_AIDL_FILE_PATH) 619 f = FileParser(); 620 f.parseFile(aidl_file) 621 622 if args.output_csv: 623 f.outputAsCsv(args.output_csv) 624 return 625 626 generated_files = [] 627 628 change_mode = GeneratedFile('change_mode') 629 change_mode.setCppFilePath(os.path.join(android_top, CHANGE_MODE_CPP_FILE_PATH)) 630 change_mode.setJavaFilePath(os.path.join(android_top, CHANGE_MODE_JAVA_FILE_PATH)) 631 change_mode.setCppFormatter(CHANGE_MODE_CPP_FORMATTER) 632 change_mode.setJavaFormatter(CHANGE_MODE_JAVA_FORMATTER) 633 generated_files.append(change_mode) 634 635 access_mode = GeneratedFile('access_mode') 636 access_mode.setCppFilePath(os.path.join(android_top, ACCESS_CPP_FILE_PATH)) 637 access_mode.setJavaFilePath(os.path.join(android_top, ACCESS_JAVA_FILE_PATH)) 638 access_mode.setCppFormatter(ACCESS_CPP_FORMATTER) 639 access_mode.setJavaFormatter(ACCESS_JAVA_FORMATTER) 640 generated_files.append(access_mode) 641 642 enum_types = GeneratedFile('enum_types') 643 enum_types.setCppFilePath(os.path.join(android_top, ENUM_CPP_FILE_PATH)) 644 enum_types.setJavaFilePath(os.path.join(android_top, ENUM_JAVA_FILE_PATH)) 645 enum_types.setJavaFormatter(ENUM_JAVA_FORMATTER) 646 enum_types.setCppFormatter(ENUM_CPP_FORMATTER) 647 generated_files.append(enum_types) 648 649 unit_type = GeneratedFile('unit_type') 650 unit_type.setJavaFilePath(os.path.join(android_top, UNITS_JAVA_FILE_PATH)) 651 unit_type.setJavaFormatter(UNITS_JAVA_FORMATTER) 652 generated_files.append(unit_type) 653 654 version = GeneratedFile('version') 655 version.setCppFilePath(os.path.join(android_top, VERSION_CPP_FILE_PATH)) 656 version.setCppFormatter(VERSION_CPP_FORMATTER) 657 generated_files.append(version) 658 659 annotations = GeneratedFile('annotations') 660 annotations.setCppFilePath(os.path.join(android_top, ANNOTATIONS_CPP_FILE_PATH)) 661 annotations.setJavaFilePath(os.path.join(android_top, ANNOTATIONS_JAVA_FILE_PATH)) 662 annotations.setCppFormatter(ANNOTATIONS_CPP_FORMATTER) 663 annotations.setJavaFormatter(ANNOTATIONS_JAVA_FORMATTER) 664 generated_files.append(annotations) 665 666 temp_files = [] 667 668 try: 669 for generated_file in generated_files: 670 generated_file.convert(f, args.check_only, temp_files) 671 672 if not args.check_only: 673 return 674 675 for generated_file in generated_files: 676 if not generated_file.cmp(): 677 print('The generated enum files for VehicleProperty.aidl requires update, ') 678 print('Run \npython ' + android_top + '/' + SCRIPT_PATH) 679 sys.exit(1) 680 except Exception as e: 681 print('Error parsing VehicleProperty.aidl') 682 print(e) 683 sys.exit(1) 684 finally: 685 for file in temp_files: 686 os.remove(file) 687 688 689if __name__ == '__main__': 690 main()