#!/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