• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/python3
2#
3# Copyright (C) 2022 The Android Open Source Project
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9#      http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16
17from functools import lru_cache
18import os
19
20from build_file_generator import AndroidBpFile, AndroidBpModule, BuildFileGenerator, ConfigAxis
21from utils import ASSEMBLE_PHONY_TARGET, Context
22
23
24class JavaApiAssemblyContext(object):
25    """Context object for managing global state of Java API Assembly."""
26
27    def get_java_api_assembler(self):
28        """Return a callback to assemble Java APIs.
29
30        The callback is a member of the context object,
31        and therefore has access to its state."""
32        return self.assemble_java_api_library
33
34    @lru_cache(maxsize=None)
35    def _java_api_library_module(self, context: Context,
36                                 build_file_generator: BuildFileGenerator,
37                                 surface_name: str,
38                                 surface_version: str) -> AndroidBpModule:
39        """Initializes the java_api_library AndroidBpModule for an API surface stub
40
41        Args:
42            context: Container for global state.
43            build_file_generator: Container for registering Android.bp files.
44            surface_name: API surface name (e.g. publicapi).
45            surface_version: API surface version (e.g. 29, 30, current).
46
47        Returns:
48            AndroidBpModule object
49        """
50        # Create Android.bp module.
51        # There should be one stub library per (api_surface, version).
52        name = f"{surface_name}_{surface_version}"
53        api_library_module = AndroidBpModule(name=name,
54                                             module_type="java_api_library")
55        staging_dir = context.out.api_library_dir(surface_name,
56                                                  surface_version, "")
57        # Create Android.bp file
58        bp_file = AndroidBpFile(directory=staging_dir)
59        bp_file.add_comment_string("WARNING: THIS IS AN AUTOGENERATED FILE.")
60        bp_file.add_module(api_library_module)
61        build_file_generator.add_android_bp_file(bp_file)
62
63        return api_library_module
64
65    def assemble_java_api_library(self, context: Context, ninja,
66                                  build_file_generator: BuildFileGenerator,
67                                  stub_library) -> None:
68        """Assembles the API .txt files in the output directory.
69
70        Args:
71            context: Container for global state.
72            ninja: Ninja writer object. ninja_tools.Ninja instance.
73            build_file_generator: Container for registering Android.bp files.
74            stub_library: Container for APIs provided by a library an API surface
75                at a specific version. api_assembly.StubLibrary instance.
76        Returns:
77            None
78        """
79        staging_dir = context.out.api_library_dir(
80            stub_library.api_surface,
81            stub_library.api_surface_version,
82            "",
83        )
84        # Create one java_api_library for the api surface. This should be
85        # idempotent.
86        api_library_module = self._java_api_library_module(
87            context, build_file_generator, stub_library.api_surface,
88            stub_library.api_surface_version)
89
90        api_deps = []
91        for c in stub_library.contributions:
92            # (A single API domain can provide multiple java libraries)
93            # Proposed layout
94            # out/api_surfaces/
95            #   publicapi/current/
96            #     <contribution1>/current.txt
97            #     <contribution2>/current.txt
98            #     ...
99            #   systemapi/current/
100            #     <contribution1>/current.txt
101            #     <contribution1>/system-current.txt
102            #     <contribution2>/current.txt
103            #     <contribution2>/system-current.txt
104            #   ...
105            name = c.library_contribution["name"]
106            api = c.library_contribution["api"]
107            api_out = os.path.join(staging_dir, name, os.path.basename(api))
108            ninja.add_copy_file(api_out, os.path.join(
109                c.inner_tree.root,
110                api,
111            ))
112
113            # TODO: Short term hack to make the files in outer tree available to files
114            # in inner tree. This is needed because chdir'd trees cannot reach
115            # into outer tree's scope.
116            # The list of inner trees is hardcoded for now.
117            for inner_tree in ["system", "vendor", "apexes"]:
118                path_in_inner_tree = api_out.replace(
119                    context.out.api_surfaces_dir(),
120                    os.path.join(inner_tree, context.out.root(),
121                                 "api_surfaces"))
122                ninja.add_phony(path_in_inner_tree, api_out)
123
124            # Add the api file to java_api_library
125            api_library_module.extend_property(
126                prop="api_files",
127                val=[os.path.join(name, os.path.basename(api))])
128            api_deps.append(api_out)
129
130        # Add the api files as deps of the phony assembly target
131        ninja.add_global_phony(ASSEMBLE_PHONY_TARGET, api_deps)
132