Generate sdk snapshots for the R build
This change replicates the behavior of the generate_ml_bundle.sh that
creates an Android.bp file along with the necessary file structure for
an R build.
It adds the information needed to a ForRBuild object which is set on
those MainlineModules that need to provide SDKs for R. That includes
a list of SdkLibrary objects each of which has a name and a flag that
indicates whether it is a shared library.
The R BuildRelease creator function builds the sdk snapshots as normal
and then extracts information from those snapshot files to construct
snapshots suitable for an R build. It then passes the directory
containing those new snapshot files to populate_dist() which will then
copy them into the correct location in the dist directory.
For each MainlineModule that provides an SDK for R the following is
created in the out/soong/mainline-sdks/for-R-build directory:
* A sub-directory using the apex name containing:
* An Android.bp file with definitions for each SdkLibrary.
* A file structure containing API txt file, removed API txt file,
a srcjar containing the stub sources and a stubs jar.
* A zip file containing the contents of the previous directory whose
name is <sdk-name>-current.zip, to match the files that are
generated by Soong when building sdk snapshots.
As R does not support the Soong config boilerplate code that
transformation is disabled for R.
Test: atest --host mainline_modules_sdks_test
packages/modules/common/build/mainline_modules_sdks.sh
pyformat -s 4 --force_quote_type double -i build/mainline_modules_sdks*.py
/usr/bin/pylint --rcfile $ANDROID_BUILD_TOP/tools/repohooks/tools/pylintrc build/mainline_modules_sdks*.py
Change-Id: I70001782496a3e9805bf56181c0e08419e31e191
This commit is contained in:
@@ -31,6 +31,24 @@ import typing
|
||||
from typing import Callable, List
|
||||
import zipfile
|
||||
|
||||
COPYRIGHT_BOILERPLATE = """
|
||||
//
|
||||
// Copyright (C) 2020 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.
|
||||
//
|
||||
""".lstrip()
|
||||
|
||||
|
||||
@dataclasses.dataclass(frozen=True)
|
||||
class ConfigVar:
|
||||
@@ -206,6 +224,9 @@ def sdk_snapshot_zip_file(snapshots_dir, sdk_name, sdk_version):
|
||||
class SnapshotBuilder:
|
||||
"""Builds sdk snapshots"""
|
||||
|
||||
# The path to this tool.
|
||||
tool_path: str
|
||||
|
||||
# Used to run subprocesses for building snapshots.
|
||||
subprocess_runner: SubprocessRunner
|
||||
|
||||
@@ -271,6 +292,80 @@ class SnapshotBuilder:
|
||||
self.subprocess_runner.run(cmd, env=env)
|
||||
return self.mainline_sdks_dir
|
||||
|
||||
def build_snapshots_for_build_r(self, build_release, sdk_versions, modules):
|
||||
# Build the snapshots as standard.
|
||||
snapshot_dir = self.build_snapshots(build_release, sdk_versions,
|
||||
modules)
|
||||
|
||||
# Each module will extract needed files from the original snapshot zip
|
||||
# file and then use that to create a replacement zip file.
|
||||
r_snapshot_dir = os.path.join(snapshot_dir, "for-R-build")
|
||||
shutil.rmtree(r_snapshot_dir, ignore_errors=True)
|
||||
|
||||
for module in modules:
|
||||
apex = module.apex
|
||||
dest_dir = os.path.join(r_snapshot_dir, apex)
|
||||
os.makedirs(dest_dir, exist_ok=True)
|
||||
bp_file = os.path.join(dest_dir, "Android.bp")
|
||||
|
||||
# The first sdk in the list is the name to use.
|
||||
sdk_name = module.sdks[0]
|
||||
|
||||
with open(bp_file, "w", encoding="utf8") as bp:
|
||||
bp.write("// DO NOT EDIT. Auto-generated by the following:\n")
|
||||
bp.write(f"// {self.tool_path}\n")
|
||||
bp.write(COPYRIGHT_BOILERPLATE)
|
||||
aosp_apex = google_to_aosp_name(apex)
|
||||
for library in module.for_r_build.sdk_libraries:
|
||||
module_name = library.name
|
||||
shared_library = str(library.shared_library).lower()
|
||||
sdk_file = sdk_snapshot_zip_file(snapshot_dir, sdk_name,
|
||||
"current")
|
||||
extract_matching_files_from_zip(
|
||||
sdk_file, dest_dir,
|
||||
sdk_library_files_pattern(
|
||||
scope_pattern=r"(public|system|module-lib)",
|
||||
name_pattern=fr"({module_name}(-removed|-stubs)?)"))
|
||||
|
||||
bp.write(f"""
|
||||
java_sdk_library_import {{
|
||||
name: "{module_name}",
|
||||
owner: "google",
|
||||
prefer: true,
|
||||
shared_library: {shared_library},
|
||||
apex_available: [
|
||||
"{aosp_apex}",
|
||||
"test_{aosp_apex}",
|
||||
],
|
||||
public: {{
|
||||
jars: ["sdk_library/public/{module_name}-stubs.jar"],
|
||||
stub_srcs: ["sdk_library/public/{module_name}.srcjar"],
|
||||
current_api: "sdk_library/public/{module_name}.txt",
|
||||
removed_api: "sdk_library/public/{module_name}-removed.txt",
|
||||
sdk_version: "module_current",
|
||||
}},
|
||||
system: {{
|
||||
jars: ["sdk_library/system/{module_name}-stubs.jar"],
|
||||
stub_srcs: ["sdk_library/system/{module_name}.srcjar"],
|
||||
current_api: "sdk_library/system/{module_name}.txt",
|
||||
removed_api: "sdk_library/system/{module_name}-removed.txt",
|
||||
sdk_version: "module_current",
|
||||
}},
|
||||
module_lib: {{
|
||||
jars: ["sdk_library/module-lib/{module_name}-stubs.jar"],
|
||||
stub_srcs: ["sdk_library/module-lib/{module_name}.srcjar"],
|
||||
current_api: "sdk_library/module-lib/{module_name}.txt",
|
||||
removed_api: "sdk_library/module-lib/{module_name}-removed.txt",
|
||||
sdk_version: "module_current",
|
||||
}},
|
||||
}}
|
||||
""")
|
||||
|
||||
base_file = os.path.join(r_snapshot_dir, sdk_name + "-current")
|
||||
shutil.make_archive(base_file, "zip", dest_dir)
|
||||
|
||||
return r_snapshot_dir
|
||||
|
||||
|
||||
# A list of the sdk versions to build. Usually just current but can include a
|
||||
# numeric version too.
|
||||
@@ -320,6 +415,10 @@ class BuildRelease:
|
||||
# The position of this instance within the BUILD_RELEASES list.
|
||||
ordinal: int = dataclasses.field(default=-1, init=False)
|
||||
|
||||
# Whether this build release supports the Soong config boilerplate that is
|
||||
# used to control the prefer setting of modules via a Soong config variable.
|
||||
supports_soong_config_boilerplate: bool = True
|
||||
|
||||
def __post_init__(self):
|
||||
# The following use object.__setattr__ as this object is frozen and
|
||||
# attempting to set the fields directly would cause an exception to be
|
||||
@@ -351,6 +450,13 @@ def create_no_dist_snapshot(_: BuildRelease, __: "SdkDistProducer",
|
||||
print(f"create_no_dist_snapshot for modules {[m.apex for m in modules]}")
|
||||
|
||||
|
||||
def create_dist_snapshot_for_r(build_release: BuildRelease,
|
||||
producer: "SdkDistProducer",
|
||||
modules: List["MainlineModule"]):
|
||||
"""Generate a snapshot suitable for use in an R build."""
|
||||
producer.product_dist_for_build_r(build_release, modules)
|
||||
|
||||
|
||||
def create_sdk_snapshots_in_soong(build_release: BuildRelease,
|
||||
producer: "SdkDistProducer",
|
||||
modules: List["MainlineModule"]):
|
||||
@@ -391,9 +497,15 @@ Q = BuildRelease(
|
||||
)
|
||||
R = BuildRelease(
|
||||
name="R",
|
||||
# At the moment we do not generate a snapshot for R.
|
||||
creator=create_no_dist_snapshot,
|
||||
)
|
||||
# Generate a simple snapshot for R.
|
||||
creator=create_dist_snapshot_for_r,
|
||||
# By default a BuildRelease creates an environment to pass to Soong that
|
||||
# creates a release specific snapshot. However, Soong does not yet (and is
|
||||
# unlikely to) support building an sdk snapshot for R so create an empty
|
||||
# environment to pass to Soong instead.
|
||||
soong_env={},
|
||||
# R does not support or need Soong config boilerplate.
|
||||
supports_soong_config_boilerplate=False)
|
||||
S = BuildRelease(
|
||||
name="S",
|
||||
# Generate a snapshot for S using Soong.
|
||||
@@ -434,6 +546,26 @@ LEGACY_BUILD_RELEASE = BuildRelease(
|
||||
)
|
||||
|
||||
|
||||
@dataclasses.dataclass(frozen=True)
|
||||
class SdkLibrary:
|
||||
"""Information about a java_sdk_library."""
|
||||
|
||||
# The name of java_sdk_library module.
|
||||
name: str
|
||||
|
||||
# True if the sdk_library module is a shared library.
|
||||
shared_library: bool = False
|
||||
|
||||
|
||||
@dataclasses.dataclass(frozen=True)
|
||||
class ForRBuild:
|
||||
"""Data structure needed for generating a snapshot for an R build."""
|
||||
|
||||
# The java_sdk_library modules to export to the r snapshot.
|
||||
sdk_libraries: typing.List[SdkLibrary] = dataclasses.field(
|
||||
default_factory=list)
|
||||
|
||||
|
||||
@dataclasses.dataclass(frozen=True)
|
||||
class MainlineModule:
|
||||
"""Represents a mainline module"""
|
||||
@@ -469,15 +601,19 @@ class MainlineModule:
|
||||
# The prefix to use for the soong config module types.
|
||||
configModuleTypePrefix: str = "module_"
|
||||
|
||||
def transformations(self):
|
||||
for_r_build: typing.Optional[ForRBuild] = None
|
||||
|
||||
def transformations(self, build_release):
|
||||
"""Returns the transformations to apply to this module's snapshot(s)."""
|
||||
return [
|
||||
SoongConfigBoilerplateInserter(
|
||||
transformations = []
|
||||
if build_release.supports_soong_config_boilerplate:
|
||||
inserter = SoongConfigBoilerplateInserter(
|
||||
"Android.bp",
|
||||
configVar=self.configVar,
|
||||
configModuleTypePrefix=self.configModuleTypePrefix,
|
||||
configBpDefFile=self.configBpDefFile),
|
||||
]
|
||||
configBpDefFile=self.configBpDefFile)
|
||||
transformations.append(inserter)
|
||||
return transformations
|
||||
|
||||
def is_required_for(self, target_build_release):
|
||||
"""True if this module is required for the target build release."""
|
||||
@@ -510,46 +646,80 @@ MAINLINE_MODULES = [
|
||||
"conscrypt-module-host-exports",
|
||||
],
|
||||
first_release=Q,
|
||||
# No conscrypt java_sdk_library modules are exported to the R snapshot.
|
||||
# Conscrypt was updatable in R but the generate_ml_bundle.sh does not
|
||||
# appear to generate a snapshot for it.
|
||||
for_r_build=None,
|
||||
),
|
||||
MainlineModule(
|
||||
apex="com.android.ipsec",
|
||||
sdks=["ipsec-module-sdk"],
|
||||
first_release=S,
|
||||
first_release=R,
|
||||
for_r_build=ForRBuild(sdk_libraries=[
|
||||
SdkLibrary(
|
||||
name="android.net.ipsec.ike",
|
||||
shared_library=True,
|
||||
),
|
||||
]),
|
||||
),
|
||||
MainlineModule(
|
||||
apex="com.android.media",
|
||||
sdks=["media-module-sdk"],
|
||||
first_release=R,
|
||||
for_r_build=ForRBuild(sdk_libraries=[
|
||||
SdkLibrary(name="framework-media"),
|
||||
]),
|
||||
),
|
||||
MainlineModule(
|
||||
apex="com.android.mediaprovider",
|
||||
sdks=["mediaprovider-module-sdk"],
|
||||
first_release=R,
|
||||
for_r_build=ForRBuild(sdk_libraries=[
|
||||
SdkLibrary(name="framework-mediaprovider"),
|
||||
]),
|
||||
),
|
||||
MainlineModule(
|
||||
apex="com.android.permission",
|
||||
sdks=["permission-module-sdk"],
|
||||
first_release=R,
|
||||
for_r_build=ForRBuild(sdk_libraries=[
|
||||
SdkLibrary(name="framework-permission"),
|
||||
# framework-permission-s is not needed on R as it contains classes
|
||||
# that are provided in R by non-updatable parts of the
|
||||
# bootclasspath.
|
||||
]),
|
||||
),
|
||||
MainlineModule(
|
||||
apex="com.android.sdkext",
|
||||
sdks=["sdkextensions-sdk"],
|
||||
first_release=R,
|
||||
for_r_build=ForRBuild(sdk_libraries=[
|
||||
SdkLibrary(name="framework-sdkextensions"),
|
||||
]),
|
||||
),
|
||||
MainlineModule(
|
||||
apex="com.android.os.statsd",
|
||||
sdks=["statsd-module-sdk"],
|
||||
first_release=R,
|
||||
for_r_build=ForRBuild(sdk_libraries=[
|
||||
SdkLibrary(name="framework-statsd"),
|
||||
]),
|
||||
),
|
||||
MainlineModule(
|
||||
apex="com.android.tethering",
|
||||
sdks=["tethering-module-sdk"],
|
||||
first_release=R,
|
||||
for_r_build=ForRBuild(sdk_libraries=[
|
||||
SdkLibrary(name="framework-tethering"),
|
||||
]),
|
||||
),
|
||||
MainlineModule(
|
||||
apex="com.android.wifi",
|
||||
sdks=["wifi-module-sdk"],
|
||||
first_release=R,
|
||||
for_r_build=ForRBuild(sdk_libraries=[
|
||||
SdkLibrary(name="framework-wifi"),
|
||||
]),
|
||||
),
|
||||
]
|
||||
|
||||
@@ -603,6 +773,19 @@ class SdkDistProducer:
|
||||
f" build release")
|
||||
build_release.creator(build_release, self, filtered_modules)
|
||||
|
||||
def product_dist_for_build_r(self, build_release, modules):
|
||||
# Although we only need a subset of the files that a java_sdk_library
|
||||
# adds to an sdk snapshot generating the whole snapshot is the simplest
|
||||
# way to ensure that all the necessary files are produced.
|
||||
sdk_versions = build_release.sdk_versions
|
||||
|
||||
# Filter out any modules that do not provide sdk for R.
|
||||
modules = [m for m in modules if m.for_r_build]
|
||||
|
||||
snapshot_dir = self.snapshot_builder.build_snapshots_for_build_r(
|
||||
build_release, sdk_versions, modules)
|
||||
self.populate_dist(build_release, sdk_versions, modules, snapshot_dir)
|
||||
|
||||
def produce_dist_for_build_release(self, build_release, modules):
|
||||
sdk_versions = build_release.sdk_versions
|
||||
snapshots_dir = self.snapshot_builder.build_snapshots(
|
||||
@@ -631,8 +814,9 @@ class SdkDistProducer:
|
||||
sdk_version, apex, subdir)
|
||||
sdk_path = sdk_snapshot_zip_file(snapshots_dir, sdk,
|
||||
sdk_version)
|
||||
transformations = module.transformations(build_release)
|
||||
self.dist_sdk_snapshot_zip(sdk_path, sdk_dist_dir,
|
||||
module.transformations())
|
||||
transformations)
|
||||
|
||||
def dist_sdk_snapshot_zip(self, src_sdk_zip, sdk_dist_dir, transformations):
|
||||
"""Copy the sdk snapshot zip file to a dist directory.
|
||||
@@ -728,14 +912,19 @@ def apply_transformations(producer, tmp_dir, transformations):
|
||||
os.utime(path, (modified, modified))
|
||||
|
||||
|
||||
def create_producer():
|
||||
def create_producer(tool_path):
|
||||
# Variables initialized from environment variables that are set by the
|
||||
# calling mainline_modules_sdks.sh.
|
||||
out_dir = os.environ["OUT_DIR"]
|
||||
dist_dir = os.environ["DIST_DIR"]
|
||||
|
||||
top_dir = os.environ["ANDROID_BUILD_TOP"]
|
||||
tool_path = os.path.relpath(tool_path, top_dir)
|
||||
tool_path = tool_path.replace(".py", ".sh")
|
||||
|
||||
subprocess_runner = SubprocessRunner()
|
||||
snapshot_builder = SnapshotBuilder(
|
||||
tool_path=tool_path,
|
||||
subprocess_runner=subprocess_runner,
|
||||
out_dir=out_dir,
|
||||
)
|
||||
@@ -758,6 +947,11 @@ def aosp_to_google_name(name):
|
||||
return name.replace("com.android.", "com.google.android.")
|
||||
|
||||
|
||||
def google_to_aosp_name(name):
|
||||
"""Transform a Google module name into an AOSP module name"""
|
||||
return name.replace("com.google.android.", "com.android.")
|
||||
|
||||
|
||||
def filter_modules(modules):
|
||||
target_build_apps = os.environ.get("TARGET_BUILD_APPS")
|
||||
if target_build_apps:
|
||||
@@ -774,6 +968,11 @@ def main(args):
|
||||
|
||||
args_parser = argparse.ArgumentParser(
|
||||
description="Build snapshot zips for consumption by Gantry.")
|
||||
args_parser.add_argument(
|
||||
"--tool-path",
|
||||
help="The path to this tool.",
|
||||
default="unspecified",
|
||||
)
|
||||
args_parser.add_argument(
|
||||
"--build-release",
|
||||
action="append",
|
||||
@@ -790,7 +989,7 @@ def main(args):
|
||||
if b.name.lower() in selected_build_releases
|
||||
]
|
||||
|
||||
producer = create_producer()
|
||||
producer = create_producer(args.tool_path)
|
||||
modules = filter_modules(MAINLINE_MODULES)
|
||||
|
||||
producer.produce_dist(modules, build_releases)
|
||||
|
||||
Reference in New Issue
Block a user