#!/usr/bin/python3 # # Copyright (C) 2022 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. from functools import lru_cache import os from build_file_generator import AndroidBpFile, AndroidBpModule, BuildFileGenerator, ConfigAxis from utils import ASSEMBLE_PHONY_TARGET, Context class JavaApiAssemblyContext(object): """Context object for managing global state of Java API Assembly.""" def get_java_api_assembler(self): """Return a callback to assemble Java APIs. The callback is a member of the context object, and therefore has access to its state.""" return self.assemble_java_api_library @lru_cache(maxsize=None) def _java_api_library_module(self, context: Context, build_file_generator: BuildFileGenerator, surface_name: str, surface_version: str) -> AndroidBpModule: """Initializes the java_api_library AndroidBpModule for an API surface stub Args: context: Container for global state. build_file_generator: Container for registering Android.bp files. surface_name: API surface name (e.g. publicapi). surface_version: API surface version (e.g. 29, 30, current). Returns: AndroidBpModule object """ # Create Android.bp module. # There should be one stub library per (api_surface, version). name = f"{surface_name}_{surface_version}" api_library_module = AndroidBpModule(name=name, module_type="java_api_library") staging_dir = context.out.api_library_dir(surface_name, surface_version, "") # Create Android.bp file bp_file = AndroidBpFile(directory=staging_dir) bp_file.add_comment_string("WARNING: THIS IS AN AUTOGENERATED FILE.") bp_file.add_module(api_library_module) build_file_generator.add_android_bp_file(bp_file) return api_library_module def assemble_java_api_library(self, context: Context, ninja, build_file_generator: BuildFileGenerator, stub_library) -> None: """Assembles the API .txt files in the output directory. Args: context: Container for global state. ninja: Ninja writer object. ninja_tools.Ninja instance. build_file_generator: Container for registering Android.bp files. stub_library: Container for APIs provided by a library an API surface at a specific version. api_assembly.StubLibrary instance. Returns: None """ staging_dir = context.out.api_library_dir( stub_library.api_surface, stub_library.api_surface_version, "", ) # Create one java_api_library for the api surface. This should be # idempotent. api_library_module = self._java_api_library_module( context, build_file_generator, stub_library.api_surface, stub_library.api_surface_version) api_deps = [] for c in stub_library.contributions: # (A single API domain can provide multiple java libraries) # Proposed layout # out/api_surfaces/ # publicapi/current/ # /current.txt # /current.txt # ... # systemapi/current/ # /current.txt # /system-current.txt # /current.txt # /system-current.txt # ... name = c.library_contribution["name"] api = c.library_contribution["api"] api_out = os.path.join(staging_dir, name, os.path.basename(api)) ninja.add_copy_file(api_out, os.path.join( c.inner_tree.root, api, )) # TODO: Short term hack to make the files in outer tree available to files # in inner tree. This is needed because chdir'd trees cannot reach # into outer tree's scope. # The list of inner trees is hardcoded for now. for inner_tree in ["system", "vendor", "apexes"]: path_in_inner_tree = api_out.replace( context.out.api_surfaces_dir(), os.path.join(inner_tree, context.out.root(), "api_surfaces")) ninja.add_phony(path_in_inner_tree, api_out) # Add the api file to java_api_library api_library_module.extend_property( prop="api_files", val=[os.path.join(name, os.path.basename(api))]) api_deps.append(api_out) # Add the api files as deps of the phony assembly target ninja.add_global_phony(ASSEMBLE_PHONY_TARGET, api_deps)