• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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()