#!/usr/bin/env python3.4 # # Copyright (C) 2017 The Android Open Source Project # # Licensed under the Apache License, Version 2.0 (the 'License'); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an 'AS IS' BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # import fnmatch import os import shutil import subprocess import sys import tempfile ANDROID_BUILD_TOP = os.environ.get('ANDROID_BUILD_TOP') if not ANDROID_BUILD_TOP: print 'Run "lunch" command first.' sys.exit(1) # TODO(trong): use proper packaging without referencing modules from source. TEST_VTS_DIR = os.path.join(ANDROID_BUILD_TOP, 'test', 'vts') sys.path.append(TEST_VTS_DIR) from proto import ComponentSpecificationMessage_pb2 as CompSpecMsg from google.protobuf import text_format import build_rule_gen_utils as utils class VtsSpecParser(object): """Provides an API to generate a parse .vts spec files.""" HW_IFACE_DIR = os.path.join(ANDROID_BUILD_TOP, 'hardware', 'interfaces') def __init__(self): """VtsSpecParser constructor. For every unique pair of (hal name, hal version) available under hardware/interfaces, generates .vts files using hidl-gen. Args: tmp_dir: string, temporary directory to which to write .vts files. """ self._cache = set() self._tmp_dir = tempfile.mkdtemp() hal_list = self.HalNamesAndVersions() def __del__(self): """VtsSpecParser destructor. Removes all temporary files that were generated. """ print "Removing temp files." if os.path.exists(self._tmp_dir): shutil.rmtree(self._tmp_dir) def ImportedPackagesList(self, hal_name, hal_version): """Returns a list of imported packages. Args: hal_name: string, name of the hal, e.g. 'vibrator'. hal_version: string, version of the hal, e.g '7.4' Returns: list of strings. For example, ['android.hardware.vibrator@1.3', 'android.hidl.base@1.7'] """ self.GenerateVtsSpecs(hal_name, hal_version) vts_spec_protos = self.VtsSpecProtos(hal_name, hal_version) imported_packages = set() for vts_spec in vts_spec_protos: for package in getattr(vts_spec, 'import', []): package = package.split('::')[0] imported_packages.add(package) this_package = 'android.hardware.%s@%s' % (hal_name, hal_version) if this_package in imported_packages: imported_packages.remove(this_package) return sorted(imported_packages) def GenerateVtsSpecs(self, hal_name, hal_version): """Generates VTS specs. Uses hidl-gen to generate .vts files under a tmp directory. Args: hal_name: string, name of the hal, e.g. 'vibrator'. hal_version: string, version of the hal, e.g '7.4' tmp_dir: string, location to which to write tmp files. """ if (hal_name, hal_version) in self._cache: return hidl_gen_cmd = ( 'hidl-gen -o {TEMP_DIR} -L vts ' '-r android.hardware:{HW_IFACE_DIR} ' '-r android.hidl:{ANDROID_BUILD_TOP}/system/libhidl/transport ' 'android.hardware.{HAL_NAME}@{HAL_VERSION}').format( TEMP_DIR=self._tmp_dir, HW_IFACE_DIR=self.HW_IFACE_DIR, ANDROID_BUILD_TOP=ANDROID_BUILD_TOP, HAL_NAME=hal_name, HAL_VERSION=hal_version) subprocess.call(hidl_gen_cmd, shell=True) self._cache.add((hal_name, hal_version)) def HalNamesAndVersions(self): """Returns a list of hals and version present under hardware/interfaces. Returns: List of tuples of strings containing hal names and hal versions. For example, [('vibrator', '1.3'), ('sensors', '1.7')] """ result = [] for base, dirs, files in os.walk(self.HW_IFACE_DIR): pattern = self.HW_IFACE_DIR + '*/[0-9].[0-9]' if fnmatch.fnmatch(base, pattern) and 'example' not in base: hal_dir = os.path.relpath(base, self.HW_IFACE_DIR) (hal_name, hal_version) = os.path.split(hal_dir) hal_name = hal_name.replace('/', '.') result.append((hal_name, hal_version)) return sorted(result) def VtsSpecNames(self, hal_name, hal_version): """Returns list of .vts file names for given hal name and version. hal_name: string, name of the hal, e.g. 'vibrator'. hal_version: string, version of the hal, e.g '7.4' Returns: list of string, .vts files for given hal name and version, e.g. ['Vibrator.vts', 'types.vts'] """ self.GenerateVtsSpecs(hal_name, hal_version) vts_spec_dir = os.path.join(self._tmp_dir, 'android', 'hardware', utils.HalNameDir(hal_name), hal_version) vts_spec_names = filter(lambda x: x.endswith('.vts'), os.listdir(vts_spec_dir)) return sorted(vts_spec_names) def VtsSpecProtos(self, hal_name, hal_version): """Returns list of .vts protos for given hal name and version. hal_name: string, name of the hal, e.g. 'vibrator'. hal_version: string, version of the hal, e.g '7.4' Returns: list of ComponentSpecificationMessages """ self.GenerateVtsSpecs(hal_name, hal_version) vts_spec_dir = os.path.join(self._tmp_dir, 'android', 'hardware', utils.HalNameDir(hal_name), hal_version) vts_spec_protos = [] for vts_spec in self.VtsSpecNames(hal_name, hal_version): spec_proto = CompSpecMsg.ComponentSpecificationMessage() vts_spec_path = os.path.join(vts_spec_dir, vts_spec) with open(vts_spec_path, 'r') as spec_file: spec_string = spec_file.read() text_format.Merge(spec_string, spec_proto) vts_spec_protos.append(spec_proto) return vts_spec_protos