From 1bff0349d4954284e0e6fbcab2ace95e4be15766 Mon Sep 17 00:00:00 2001 From: Jihoon Kang Date: Tue, 17 Jan 2023 20:40:22 +0000 Subject: [PATCH] Modify Soong to utilize from-text android.jar in build Context - from-text android.jar files are built using Metalava, and these can be utilized in `decodeSdkDep` so that any modules that depends on APIs can be compiled using from-text android.jars - This change removes dependency on source java files when compiling stub android.jar files Implementation - Modify java_api_library module to create system modules using the generated android.jar - Replace modules in decodeSdkDep to link against java_api_library modules - Add --build-from-text-stub flag to hide the feature behind a flag Test: m --build-from-text-stub Bug: 271154441 Change-Id: I104df595edc65c0006820d5ae5b15f1fb167e190 --- android/config.go | 12 ++++++++++++ android/sdk_version.go | 5 +++-- cmd/soong_build/main.go | 1 + java/androidmk.go | 19 +++++++++++++++++++ java/java.go | 19 ++++++++++++++++++- ui/build/config.go | 12 ++++++++++++ ui/build/soong.go | 6 ++++++ 7 files changed, 71 insertions(+), 3 deletions(-) diff --git a/android/config.go b/android/config.go index e0b661bb7..e63464788 100644 --- a/android/config.go +++ b/android/config.go @@ -100,6 +100,8 @@ type CmdArgs struct { BazelForceEnabledModules string UseBazelProxy bool + + BuildFromTextStub bool } // Build modes that soong_build can run as. @@ -272,6 +274,10 @@ type config struct { // If true, for any requests to Bazel, communicate with a Bazel proxy using // unix sockets, instead of spawning Bazel as a subprocess. UseBazelProxy bool + + // If buildFromTextStub is true then the Java API stubs are + // built from the signature text files, not the source Java files. + buildFromTextStub bool } type deviceConfig struct { @@ -466,6 +472,8 @@ func NewConfig(cmdArgs CmdArgs, availableEnv map[string]string) (Config, error) MultitreeBuild: cmdArgs.MultitreeBuild, UseBazelProxy: cmdArgs.UseBazelProxy, + + buildFromTextStub: cmdArgs.BuildFromTextStub, } config.deviceConfig = &deviceConfig{ @@ -1873,3 +1881,7 @@ func (c *config) ApiSurfacesDir(s ApiSurface, version string) string { s.String(), version) } + +func (c *config) BuildFromTextStub() bool { + return c.buildFromTextStub +} diff --git a/android/sdk_version.go b/android/sdk_version.go index 7ace638b5..1e1fe1020 100644 --- a/android/sdk_version.go +++ b/android/sdk_version.go @@ -94,8 +94,9 @@ func (k SdkKind) JavaLibraryName(c Config) string { // not check if either module exists. // TODO: Return .txt (single-tree or multi-tree equivalents) based on config func JavaLibraryNameFromText(c Config, name string) string { - // This returns the default for now. - // TODO: Implement this + if c.BuildFromTextStub() { + return name + ".from-text" + } return name } diff --git a/cmd/soong_build/main.go b/cmd/soong_build/main.go index 3a4d71aaf..d12a17bf8 100644 --- a/cmd/soong_build/main.go +++ b/cmd/soong_build/main.go @@ -83,6 +83,7 @@ func init() { flag.BoolVar(&cmdlineArgs.BazelModeStaging, "bazel-mode-staging", false, "use bazel for analysis of certain near-ready modules") flag.BoolVar(&cmdlineArgs.BazelModeDev, "bazel-mode-dev", false, "use bazel for analysis of a large number of modules (less stable)") flag.BoolVar(&cmdlineArgs.UseBazelProxy, "use-bazel-proxy", false, "communicate with bazel using unix socket proxy instead of spawning subprocesses") + flag.BoolVar(&cmdlineArgs.BuildFromTextStub, "build-from-text-stub", false, "build Java stubs from API text files instead of source files") // Flags that probably shouldn't be flags of soong_build, but we haven't found // the time to remove them yet diff --git a/java/androidmk.go b/java/androidmk.go index a4dac80d4..148d7c276 100644 --- a/java/androidmk.go +++ b/java/androidmk.go @@ -733,3 +733,22 @@ func (apkSet *AndroidAppSet) AndroidMkEntries() []android.AndroidMkEntries { }, } } + +func (al *ApiLibrary) AndroidMkEntries() []android.AndroidMkEntries { + var entriesList []android.AndroidMkEntries + + entriesList = append(entriesList, android.AndroidMkEntries{ + Class: "JAVA_LIBRARIES", + OutputFile: android.OptionalPathForPath(al.stubsJar), + Include: "$(BUILD_SYSTEM)/soong_java_prebuilt.mk", + ExtraEntries: []android.AndroidMkExtraEntriesFunc{ + func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) { + entries.SetBoolIfTrue("LOCAL_UNINSTALLABLE_MODULE", true) + entries.SetPath("LOCAL_SOONG_CLASSES_JAR", al.stubsJar) + entries.SetPath("LOCAL_SOONG_HEADER_JAR", al.stubsJar) + }, + }, + }) + + return entriesList +} diff --git a/java/java.go b/java/java.go index 370781599..91193ccc1 100644 --- a/java/java.go +++ b/java/java.go @@ -1692,6 +1692,12 @@ func metalavaStubCmd(ctx android.ModuleContext, rule *android.RuleBuilder, Flag("--color"). Flag("--quiet"). Flag("--format=v2"). + Flag("--include-annotations"). + // The flag makes nullability issues as warnings rather than errors by replacing + // @Nullable/@NonNull in the listed packages APIs with @RecentlyNullable/@RecentlyNonNull, + // and these packages are meant to have everything annotated + // @RecentlyNullable/@RecentlyNonNull. + FlagWithArg("--force-convert-to-warning-nullability-annotations ", "+*:-android.*:+android.icu.*:-dalvik.*"). FlagWithArg("--repeat-errors-max ", "10"). FlagWithArg("--hide ", "UnresolvedImport"). FlagWithArg("--hide ", "InvalidNullabilityOverride"). @@ -1700,6 +1706,14 @@ func metalavaStubCmd(ctx android.ModuleContext, rule *android.RuleBuilder, return cmd } +func (al *ApiLibrary) HeaderJars() android.Paths { + return android.Paths{al.stubsJar} +} + +func (al *ApiLibrary) OutputDirAndDeps() (android.Path, android.Paths) { + return nil, nil +} + func (al *ApiLibrary) stubsFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand, stubsDir android.OptionalPath) { if stubsDir.Valid() { cmd.FlagWithArg("--stubs ", stubsDir.String()) @@ -1797,7 +1811,10 @@ func (al *ApiLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) { ctx.Phony(ctx.ModuleName(), al.stubsJar) ctx.SetProvider(JavaInfoProvider, JavaInfo{ - HeaderJars: android.PathsIfNonNil(al.stubsJar), + HeaderJars: android.PathsIfNonNil(al.stubsJar), + ImplementationAndResourcesJars: android.PathsIfNonNil(al.stubsJar), + ImplementationJars: android.PathsIfNonNil(al.stubsJar), + AidlIncludeDirs: android.Paths{}, }) } diff --git a/ui/build/config.go b/ui/build/config.go index 20cc9fb29..7c226ddc2 100644 --- a/ui/build/config.go +++ b/ui/build/config.go @@ -88,6 +88,7 @@ type configImpl struct { searchApiDir bool // Scan the Android.bp files generated in out/api_surfaces skipMetricsUpload bool buildStartedTime int64 // For metrics-upload-only - manually specify a build-started time + buildFromTextStub bool // From the product config katiArgs []string @@ -509,6 +510,11 @@ func NewConfig(ctx Context, args ...string) Config { } } + if ret.BuildFromTextStub() { + // TODO(b/271443071): support hidden api check for from-text stub build + ret.environ.Set("UNSAFE_DISABLE_HIDDENAPI_FLAGS", "true") + } + bpd := ret.BazelMetricsDir() if err := os.RemoveAll(bpd); err != nil { ctx.Fatalf("Unable to remove bazel profile directory %q: %v", bpd, err) @@ -833,6 +839,8 @@ func (c *configImpl) parseArgs(ctx Context, args []string) { } else { ctx.Fatalf("unknown option for ninja_weight_source: %s", source) } + } else if arg == "--build-from-text-stub" { + c.buildFromTextStub = true } else if strings.HasPrefix(arg, "--build-command=") { buildCmd := strings.TrimPrefix(arg, "--build-command=") // remove quotations @@ -1155,6 +1163,10 @@ func (c *configImpl) SkipConfig() bool { return c.skipConfig } +func (c *configImpl) BuildFromTextStub() bool { + return c.buildFromTextStub +} + func (c *configImpl) TargetProduct() string { if v, ok := c.environ.Get("TARGET_PRODUCT"); ok { return v diff --git a/ui/build/soong.go b/ui/build/soong.go index 871e63785..1c6da7ec9 100644 --- a/ui/build/soong.go +++ b/ui/build/soong.go @@ -171,6 +171,9 @@ func (pb PrimaryBuilderFactory) primaryBuilderInvocation() bootstrap.PrimaryBuil if pb.config.multitreeBuild { commonArgs = append(commonArgs, "--multitree-build") } + if pb.config.buildFromTextStub { + commonArgs = append(commonArgs, "--build-from-text-stub") + } commonArgs = append(commonArgs, "-l", filepath.Join(pb.config.FileListDir(), "Android.bp.list")) invocationEnv := make(map[string]string) @@ -282,6 +285,9 @@ func bootstrapBlueprint(ctx Context, config Config) { if config.MultitreeBuild() { mainSoongBuildExtraArgs = append(mainSoongBuildExtraArgs, "--multitree-build") } + if config.buildFromTextStub { + mainSoongBuildExtraArgs = append(mainSoongBuildExtraArgs, "--build-from-text-stub") + } queryviewDir := filepath.Join(config.SoongOutDir(), "queryview") // The BUILD files will be generated in out/soong/.api_bp2build (no symlinks to src files)