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