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