Merge "Modify Soong to utilize from-text android.jar in build"
diff --git a/android/config.go b/android/config.go
index 2d32686..33deba5 100644
--- a/android/config.go
+++ b/android/config.go
@@ -100,6 +100,8 @@
 	BazelForceEnabledModules string
 
 	UseBazelProxy bool
+
+	BuildFromTextStub bool
 }
 
 // Build modes that soong_build can run as.
@@ -272,6 +274,10 @@
 	// 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 @@
 
 		MultitreeBuild: cmdArgs.MultitreeBuild,
 		UseBazelProxy:  cmdArgs.UseBazelProxy,
+
+		buildFromTextStub: cmdArgs.BuildFromTextStub,
 	}
 
 	config.deviceConfig = &deviceConfig{
@@ -1882,3 +1890,7 @@
 		s.String(),
 		version)
 }
+
+func (c *config) BuildFromTextStub() bool {
+	return c.buildFromTextStub
+}
diff --git a/android/sdk_version.go b/android/sdk_version.go
index 1192f7d..5bb1e5a 100644
--- a/android/sdk_version.go
+++ b/android/sdk_version.go
@@ -94,8 +94,9 @@
 // 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 96aa117..79a5ce4 100644
--- a/cmd/soong_build/main.go
+++ b/cmd/soong_build/main.go
@@ -84,6 +84,7 @@
 	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 a4dac80..148d7c2 100644
--- a/java/androidmk.go
+++ b/java/androidmk.go
@@ -733,3 +733,22 @@
 		},
 	}
 }
+
+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 ebd9f5e..499a6b6 100644
--- a/java/java.go
+++ b/java/java.go
@@ -1697,6 +1697,12 @@
 		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").
@@ -1705,6 +1711,14 @@
 	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())
@@ -1816,7 +1830,10 @@
 	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 b5406b9..a755d14 100644
--- a/ui/build/config.go
+++ b/ui/build/config.go
@@ -88,6 +88,7 @@
 	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
@@ -518,6 +519,11 @@
 		}
 	}
 
+	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)
@@ -859,6 +865,8 @@
 			} 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
@@ -1200,6 +1208,10 @@
 	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 c4c984f..9287731 100644
--- a/ui/build/soong.go
+++ b/ui/build/soong.go
@@ -171,6 +171,9 @@
 	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 @@
 	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)