| #!/usr/bin/env python |
| # |
| # Copyright (C) 2018 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 glob |
| import os.path |
| import re |
| import sys |
| |
| PREBUILTS_VNDK_DIR = "prebuilts/vndk" |
| VENDOR_DIRECTORIES = ('/vendor', '/odm') |
| |
| def find_latest_vndk_snapshot_version(): |
| """Returns latest vndk snapshot version in current source tree. |
| It will skip the test if the snapshot directories are not found. |
| |
| Returns: |
| latest_version: string |
| """ |
| vndk_dir_list = glob.glob(PREBUILTS_VNDK_DIR + "/v*") |
| if not vndk_dir_list: |
| """Exit without error because we may have source trees that do not include |
| VNDK snapshot directories in it. |
| """ |
| sys.exit(0) |
| vndk_ver_list = [re.match(r".*/v(\d+)", vndk_dir).group(1) |
| for vndk_dir in vndk_dir_list] |
| latest_version = max(vndk_ver_list) |
| if latest_version == '27': |
| """Exit without error because VNDK v27 is not using ld.config.txt template |
| """ |
| sys.exit(0) |
| return latest_version |
| |
| def get_vendor_configuration(ld_config_file): |
| """Reads the ld.config.txt file to parse the namespace configurations. |
| It finds the configurations that include vendor directories. |
| |
| Args: |
| ld_config_file: string, path (relative to build top) of the ld.config.txt |
| file. |
| Returns: |
| configs: dict{string:[string]}, dictionary of namespace configurations. |
| it has 'section + property' names as keys and the directory list |
| as values. |
| """ |
| try: |
| conf_file = open(ld_config_file) |
| except IOError: |
| print("error: could not read %s" % ld_config_file) |
| sys.exit(1) |
| |
| configs = dict() |
| current_section = None |
| |
| with conf_file: |
| for line in conf_file: |
| # ignore comments |
| found = line.find('#') |
| if found != -1: |
| line = line[:found] |
| line = line.strip() |
| if not line: |
| continue |
| |
| if line[0] == '[' and line[-1] == ']': |
| # new section started |
| current_section = line[1:-1] |
| continue |
| |
| if current_section == None: |
| continue |
| |
| found = line.find('+=') |
| opr_len = 2 |
| if found == -1: |
| found = line.find('=') |
| opr_len = 1 |
| if found == -1: |
| continue |
| |
| namespace = line[:found].strip() |
| if not namespace.endswith(".paths"): |
| # check ".paths" only |
| continue |
| namespace = '[' + current_section + ']' + namespace |
| values = line[found + opr_len:].strip() |
| directories = values.split(':') |
| |
| for directory in directories: |
| if any(vendor_dir in directory for vendor_dir in VENDOR_DIRECTORIES): |
| if namespace in configs: |
| configs[namespace].append(directory) |
| else: |
| configs[namespace] = [directory] |
| |
| return configs |
| |
| def get_snapshot_config(version): |
| """Finds the ld.config.{version}.txt file from the VNDK snapshot directory. |
| In the vndk prebuilt directory (prebuilts/vndk/v{version}), it searches |
| {arch}/configs/ld.config.{version}.txt file, where {arch} is one of ('arm64', |
| 'arm', 'x86_64', 'x86'). |
| |
| Args: |
| version: string, the VNDK snapshot version to search. |
| Returns: |
| ld_config_file: string, relative path to ld.config.{version}.txt |
| """ |
| arch_list = ('arm64', 'arm', 'x86_64', 'x86') |
| for arch in arch_list: |
| ld_config_file = (PREBUILTS_VNDK_DIR |
| + "/v{0}/{1}/configs/ld.config.{0}.txt".format(version, arch)) |
| if os.path.isfile(ld_config_file): |
| return ld_config_file |
| print("error: cannot find ld.config.{0}.txt file in snapshot v{0}" |
| .format(version)) |
| sys.exit(1) |
| |
| def check_backward_compatibility(ld_config, vndk_snapshot_version): |
| """Checks backward compatibility for current ld.config.txt file with the |
| old ld.config.txt file. If any of the vendor directories in the old namespace |
| configurations are missing, the test will fail. It is allowed to have new |
| vendor directories in current ld.config.txt file. |
| |
| Args: |
| ld_config: string, relative path to current ld.config.txt file. |
| vndk_snapshot_version: string, the VNDK snapshot version that has an old |
| ld.config.txt file to compare. |
| Returns: |
| result: bool, True if the current configuration is backward compatible. |
| """ |
| current_config = get_vendor_configuration(ld_config) |
| old_config = get_vendor_configuration( |
| get_snapshot_config(vndk_snapshot_version)) |
| for namespace in old_config: |
| if namespace not in current_config: |
| print("error: cannot find %s which was provided in ld.config.%s.txt" |
| % (namespace, vndk_snapshot_version)) |
| return False |
| for path in old_config[namespace]: |
| if not path in current_config[namespace]: |
| print("error: %s for %s in ld.config.%s.txt are missing in %s" |
| % (path, namespace, vndk_snapshot_version, ld_config)) |
| return False |
| return True |
| |
| def main(): |
| if len(sys.argv) != 2: |
| print ("Usage: %s target_ld_config_txt_file_name" % sys.argv[0]) |
| sys.exit(1) |
| |
| latest_vndk_snapshot_version = find_latest_vndk_snapshot_version() |
| if not check_backward_compatibility(sys.argv[1], |
| latest_vndk_snapshot_version): |
| print("error: %s has backward incompatible changes to old " |
| "vendor partition." % sys.argv[1]) |
| sys.exit(1) |
| |
| # Current ld.config.txt file is backward compatible |
| sys.exit(0) |
| |
| if __name__ == '__main__': |
| main() |