1# Copyright (C) 2023 The Android Open Source Project
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7#     http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14
15load("//build/bazel/product_config:android_product.bzl", "host_platforms")
16load(":cc_library_common.bzl", "path_in_list")
17
18CFI_FEATURE = "android_cfi"
19CFI_ASSEMBLY_FEATURE = "android_cfi_assembly_support"
20DISABLE_CFI_FEATURE = "-" + CFI_FEATURE
21
22# This propagates CFI enablement and disablement down the dependency graph
23def apply_cfi_deps(
24        features,
25        old_cli_features,
26        path,
27        cfi_include_paths,
28        cfi_exclude_paths,
29        enable_cfi,
30        platform):
31    new_cli_features = list(old_cli_features)
32    disabled_by_product_vars = (
33        not enable_cfi or
34        path_in_list(path, cfi_exclude_paths)
35    )
36    enabled_by_product_vars = (
37        path_in_list(path, cfi_include_paths) and _os_is_android(platform[0].name)
38    )
39
40    # Counterintuitive though it may be, we propagate not only the enablement
41    # of CFI down the dependency graph, but also its disablement
42    if (
43        CFI_FEATURE in features or
44        enabled_by_product_vars
45    ) and not disabled_by_product_vars:
46        if CFI_FEATURE not in new_cli_features:
47            new_cli_features.append(CFI_FEATURE)
48        if DISABLE_CFI_FEATURE in new_cli_features:
49            new_cli_features.remove(DISABLE_CFI_FEATURE)
50    else:
51        if DISABLE_CFI_FEATURE not in new_cli_features:
52            new_cli_features.append(DISABLE_CFI_FEATURE)
53        if CFI_FEATURE in new_cli_features:
54            new_cli_features.remove(CFI_FEATURE)
55
56    return new_cli_features
57
58# Since CFI is only propagated down static deps, we use this transition to
59# remove it from shared deps that it's added to. It is also used to prevent
60# stub libraries from having two configurations for the same dependency.
61def apply_drop_cfi(old_cli_features):
62    new_cli_features = list(old_cli_features)
63    if CFI_FEATURE in old_cli_features:
64        new_cli_features.remove(CFI_FEATURE)
65    if DISABLE_CFI_FEATURE not in old_cli_features:
66        new_cli_features.append(DISABLE_CFI_FEATURE)
67    return new_cli_features
68
69def _os_is_android(platform):
70    if type(platform) != "string":
71        fail("platform argument should be a string!")
72    for os_suffix in host_platforms:
73        if platform.endswith(os_suffix):
74            return False
75    return True
76