1#!/usr/bin/env python3
2
3#
4# Copyright (C) 2018 The Android Open Source Project
5#
6# Licensed under the Apache License, Version 2.0 (the "License");
7# you may not use this file except in compliance with the License.
8# You may obtain a copy of the License at
9#
10#      http://www.apache.org/licenses/LICENSE-2.0
11#
12# Unless required by applicable law or agreed to in writing, software
13# distributed under the License is distributed on an "AS IS" BASIS,
14# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15# See the License for the specific language governing permissions and
16# limitations under the License.
17#
18
19"""This script scans all Android.bp in an android source tree and check the
20correctness of dependencies."""
21
22from __future__ import print_function
23
24import argparse
25import itertools
26import sys
27
28import vndk
29
30
31def _check_module_deps(all_libs, llndk_libs, module):
32    """Check the dependencies of a module."""
33
34    bad_deps = set()
35    shared_deps, static_deps, header_deps = module.get_dependencies()
36
37    # Check vendor module dependencies requirements.
38    for dep_name in itertools.chain(shared_deps, static_deps, header_deps):
39        if dep_name in llndk_libs:
40            continue
41        dep_module = all_libs[dep_name]
42        if dep_module.is_vendor():
43            continue
44        if dep_module.is_vendor_available():
45            continue
46        if dep_module.is_vndk():
47            # dep_module is a VNDK-Private module.
48            if not module.is_vendor():
49                # VNDK-Core may link to VNDK-Private.
50                continue
51        bad_deps.add(dep_name)
52
53    # Check VNDK dependencies requirements.
54    if module.is_vndk() and not module.is_vendor():
55        is_vndk_sp = module.is_vndk_sp()
56        for dep_name in shared_deps:
57            if dep_name in llndk_libs:
58                continue
59            dep_module = all_libs[dep_name]
60            if not dep_module.is_vndk():
61                # VNDK must be self-contained.
62                bad_deps.add(dep_name)
63                break
64            if is_vndk_sp and not dep_module.is_vndk_sp():
65                # VNDK-SP must be self-contained.
66                bad_deps.add(dep_name)
67                break
68
69    return bad_deps
70
71
72def _check_modules_deps(module_dicts):
73    """Check the dependencies of modules."""
74
75    all_libs = module_dicts.all_libs
76    llndk_libs = module_dicts.llndk_libs
77
78    # Check the dependencies of modules
79    all_bad_deps = []
80    for name, module in all_libs.items():
81        if not module.has_vendor_variant() and not module.is_vendor():
82            continue
83
84        bad_deps = _check_module_deps(all_libs, llndk_libs, module)
85
86        if bad_deps:
87            all_bad_deps.append((name, sorted(bad_deps)))
88
89    return sorted(all_bad_deps)
90
91
92def _parse_args():
93    """Parse command line options."""
94    parser = argparse.ArgumentParser()
95    parser.add_argument('root_bp',
96                        help='path to Android.bp in ANDROID_BUILD_TOP')
97    parser.add_argument('--namespace', action='append', default=[''],
98                        help='extra module namespaces')
99    return parser.parse_args()
100
101
102def main():
103    """Main function."""
104
105    args = _parse_args()
106
107    module_dicts = vndk.ModuleClassifier.create_from_root_bp(
108        args.root_bp, args.namespace)
109
110    all_bad_deps = _check_modules_deps(module_dicts)
111    for name, bad_deps in all_bad_deps:
112        print('ERROR: {!r} must not depend on {}'.format(name, bad_deps),
113              file=sys.stderr)
114
115    if all_bad_deps:
116        # Note: Exit with 2 so that it is easier to distinguish bad
117        # dependencies from unexpected Python exceptions.
118        sys.exit(2)
119
120
121if __name__ == '__main__':
122    main()
123