Merge "Extract PrepareForTestWithJavaSdkLibraryFiles from javaMockFS()"
diff --git a/android/apex.go b/android/apex.go
index a014592..79d8cdd 100644
--- a/android/apex.go
+++ b/android/apex.go
@@ -719,6 +719,8 @@
 // Generate two module out files:
 // 1. FullList with transitive deps and their parents in the dep graph
 // 2. FlatList with a flat list of transitive deps
+// In both cases transitive deps of external deps are not included. Neither are deps that are only
+// available to APEXes; they are developed with updatability in mind and don't need manual approval.
 func (d *ApexBundleDepsInfo) BuildDepsInfoLists(ctx ModuleContext, minSdkVersion string, depInfos DepNameToDepInfoMap) {
 	var fullContent strings.Builder
 	var flatContent strings.Builder
diff --git a/apex/apex_test.go b/apex/apex_test.go
index 3fde144..dd290d3 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -127,6 +127,8 @@
 	config.TestProductVariables.Unbundled_build = proptools.BoolPtr(true)
 }
 
+var emptyFixtureFactory = android.NewFixtureFactory(&buildDir)
+
 var apexFixtureFactory = android.NewFixtureFactory(
 	&buildDir,
 	// General preparers in alphabetical order as test infrastructure will enforce correct
@@ -520,7 +522,7 @@
 		}
 
 		rust_binary {
-		        name: "foo.rust",
+			name: "foo.rust",
 			srcs: ["foo.rs"],
 			rlibs: ["libfoo.rlib.rust"],
 			dylibs: ["libfoo.dylib.rust"],
@@ -528,14 +530,14 @@
 		}
 
 		rust_library_rlib {
-		        name: "libfoo.rlib.rust",
+			name: "libfoo.rlib.rust",
 			srcs: ["foo.rs"],
 			crate_name: "foo",
 			apex_available: ["myapex"],
 		}
 
 		rust_library_dylib {
-		        name: "libfoo.dylib.rust",
+			name: "libfoo.dylib.rust",
 			srcs: ["foo.rs"],
 			crate_name: "foo",
 			apex_available: ["myapex"],
@@ -730,14 +732,12 @@
 
 	fullDepsInfo := strings.Split(ctx.ModuleForTests("myapex", "android_common_myapex_image").Output("depsinfo/fulllist.txt").Args["content"], "\\n")
 	ensureListContains(t, fullDepsInfo, "  myjar(minSdkVersion:(no version)) <- myapex")
-	ensureListContains(t, fullDepsInfo, "  mylib(minSdkVersion:(no version)) <- myapex")
 	ensureListContains(t, fullDepsInfo, "  mylib2(minSdkVersion:(no version)) <- mylib")
 	ensureListContains(t, fullDepsInfo, "  myotherjar(minSdkVersion:(no version)) <- myjar")
 	ensureListContains(t, fullDepsInfo, "  mysharedjar(minSdkVersion:(no version)) (external) <- myjar")
 
 	flatDepsInfo := strings.Split(ctx.ModuleForTests("myapex", "android_common_myapex_image").Output("depsinfo/flatlist.txt").Args["content"], "\\n")
 	ensureListContains(t, flatDepsInfo, "myjar(minSdkVersion:(no version))")
-	ensureListContains(t, flatDepsInfo, "mylib(minSdkVersion:(no version))")
 	ensureListContains(t, flatDepsInfo, "mylib2(minSdkVersion:(no version))")
 	ensureListContains(t, flatDepsInfo, "myotherjar(minSdkVersion:(no version))")
 	ensureListContains(t, flatDepsInfo, "mysharedjar(minSdkVersion:(no version)) (external)")
@@ -1236,13 +1236,9 @@
 	ensureNotContains(t, libFooStubsLdFlags, "libbar.so")
 
 	fullDepsInfo := strings.Split(ctx.ModuleForTests("myapex2", "android_common_myapex2_image").Output("depsinfo/fulllist.txt").Args["content"], "\\n")
-	ensureListContains(t, fullDepsInfo, "  mylib(minSdkVersion:(no version)) <- myapex2")
-	ensureListContains(t, fullDepsInfo, "  libbaz(minSdkVersion:(no version)) <- mylib")
 	ensureListContains(t, fullDepsInfo, "  libfoo(minSdkVersion:(no version)) (external) <- mylib")
 
 	flatDepsInfo := strings.Split(ctx.ModuleForTests("myapex2", "android_common_myapex2_image").Output("depsinfo/flatlist.txt").Args["content"], "\\n")
-	ensureListContains(t, flatDepsInfo, "mylib(minSdkVersion:(no version))")
-	ensureListContains(t, flatDepsInfo, "libbaz(minSdkVersion:(no version))")
 	ensureListContains(t, flatDepsInfo, "libfoo(minSdkVersion:(no version)) (external)")
 }
 
@@ -1316,9 +1312,10 @@
 
 }
 
-func TestRuntimeApexShouldInstallHwasanIfLibcDependsOnIt(t *testing.T) {
-	ctx := testApex(t, "", func(fs map[string][]byte, config android.Config) {
-		bp := `
+var prepareForTestOfRuntimeApexWithHwasan = android.GroupFixturePreparers(
+	cc.PrepareForTestWithCcBuildComponents,
+	PrepareForTestWithApexBuildComponents,
+	android.FixtureAddTextFile("bionic/apex/Android.bp", `
 		apex {
 			name: "com.android.runtime",
 			key: "com.android.runtime.key",
@@ -1331,7 +1328,12 @@
 			public_key: "testkey.avbpubkey",
 			private_key: "testkey.pem",
 		}
+	`),
+	android.FixtureAddFile("system/sepolicy/apex/com.android.runtime-file_contexts", nil),
+)
 
+func TestRuntimeApexShouldInstallHwasanIfLibcDependsOnIt(t *testing.T) {
+	result := emptyFixtureFactory.Extend(prepareForTestOfRuntimeApexWithHwasan).RunTestWithBp(t, `
 		cc_library {
 			name: "libc",
 			no_libcrt: true,
@@ -1358,12 +1360,8 @@
 			sanitize: {
 				never: true,
 			},
-		}
-		`
-		// override bp to use hard-coded names: com.android.runtime and libc
-		fs["Android.bp"] = []byte(bp)
-		fs["system/sepolicy/apex/com.android.runtime-file_contexts"] = nil
-	})
+		}	`)
+	ctx := result.TestContext
 
 	ensureExactContents(t, ctx, "com.android.runtime", "android_common_hwasan_com.android.runtime_image", []string{
 		"lib64/bionic/libc.so",
@@ -1381,21 +1379,12 @@
 }
 
 func TestRuntimeApexShouldInstallHwasanIfHwaddressSanitized(t *testing.T) {
-	ctx := testApex(t, "", func(fs map[string][]byte, config android.Config) {
-		bp := `
-		apex {
-			name: "com.android.runtime",
-			key: "com.android.runtime.key",
-			native_shared_libs: ["libc"],
-			updatable: false,
-		}
-
-		apex_key {
-			name: "com.android.runtime.key",
-			public_key: "testkey.avbpubkey",
-			private_key: "testkey.pem",
-		}
-
+	result := emptyFixtureFactory.Extend(
+		prepareForTestOfRuntimeApexWithHwasan,
+		android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+			variables.SanitizeDevice = []string{"hwaddress"}
+		}),
+	).RunTestWithBp(t, `
 		cc_library {
 			name: "libc",
 			no_libcrt: true,
@@ -1419,13 +1408,8 @@
 				never: true,
 			},
 		}
-		`
-		// override bp to use hard-coded names: com.android.runtime and libc
-		fs["Android.bp"] = []byte(bp)
-		fs["system/sepolicy/apex/com.android.runtime-file_contexts"] = nil
-
-		config.TestProductVariables.SanitizeDevice = []string{"hwaddress"}
-	})
+		`)
+	ctx := result.TestContext
 
 	ensureExactContents(t, ctx, "com.android.runtime", "android_common_hwasan_com.android.runtime_image", []string{
 		"lib64/bionic/libc.so",
@@ -2049,7 +2033,7 @@
 				java_library {
 					name: "myjar",
 					srcs: ["foo/bar/MyClass.java"],
-					sdk_version: "core_platform",
+					sdk_version: "test_current",
 					apex_available: ["myapex"],
 				}
 			`,
@@ -2096,13 +2080,16 @@
 				java_library {
 					name: "myjar",
 					srcs: ["foo/bar/MyClass.java"],
-					sdk_version: "core_platform",
+					sdk_version: "test_current",
 					apex_available: ["myapex"],
 				}
 			`,
 		},
 		{
-			name:          "Updatable apex with non-stable transitive dep",
+			name: "Updatable apex with non-stable transitive dep",
+			// This is not actually detecting that the transitive dependency is unstable, rather it is
+			// detecting that the transitive dependency is building against a wider API surface than the
+			// module that depends on it is using.
 			expectedError: "compiles against Android API, but dependency \"transitive-jar\" is compiling against private API.",
 			bp: `
 				apex {
diff --git a/apex/builder.go b/apex/builder.go
index 2663a67..da800d4 100644
--- a/apex/builder.go
+++ b/apex/builder.go
@@ -926,9 +926,15 @@
 			return !externalDep
 		}
 
+		// Skip dependencies that are only available to APEXes; they are developed with updatability
+		// in mind and don't need manual approval.
+		if to.(android.ApexModule).NotAvailableForPlatform() {
+			return !externalDep
+		}
+
 		depTag := ctx.OtherModuleDependencyTag(to)
+		// Check to see if dependency been marked to skip the dependency check
 		if skipDepCheck, ok := depTag.(android.SkipApexAllowedDependenciesCheck); ok && skipDepCheck.SkipApexAllowedDependenciesCheck() {
-			// Check to see if dependency been marked to skip the dependency check
 			return !externalDep
 		}
 
diff --git a/bazel/Android.bp b/bazel/Android.bp
index 117fd46..b7c185a 100644
--- a/bazel/Android.bp
+++ b/bazel/Android.bp
@@ -12,6 +12,7 @@
     ],
     testSrcs: [
         "aquery_test.go",
+        "properties_test.go",
     ],
     pluginFor: [
         "soong_build",
diff --git a/bazel/properties.go b/bazel/properties.go
index a5ffa55..cb47758 100644
--- a/bazel/properties.go
+++ b/bazel/properties.go
@@ -14,7 +14,10 @@
 
 package bazel
 
-import "fmt"
+import (
+	"fmt"
+	"sort"
+)
 
 type bazelModuleProperties struct {
 	// The label of the Bazel target replacing this Soong module.
@@ -66,6 +69,28 @@
 	}
 }
 
+func UniqueBazelLabels(originalLabels []Label) []Label {
+	uniqueLabelsSet := make(map[Label]bool)
+	for _, l := range originalLabels {
+		uniqueLabelsSet[l] = true
+	}
+	var uniqueLabels []Label
+	for l, _ := range uniqueLabelsSet {
+		uniqueLabels = append(uniqueLabels, l)
+	}
+	sort.SliceStable(uniqueLabels, func(i, j int) bool {
+		return uniqueLabels[i].Label < uniqueLabels[j].Label
+	})
+	return uniqueLabels
+}
+
+func UniqueBazelLabelList(originalLabelList LabelList) LabelList {
+	var uniqueLabelList LabelList
+	uniqueLabelList.Includes = UniqueBazelLabels(originalLabelList.Includes)
+	uniqueLabelList.Excludes = UniqueBazelLabels(originalLabelList.Excludes)
+	return uniqueLabelList
+}
+
 // StringListAttribute corresponds to the string_list Bazel attribute type with
 // support for additional metadata, like configurations.
 type StringListAttribute struct {
diff --git a/bazel/properties_test.go b/bazel/properties_test.go
new file mode 100644
index 0000000..0fcb904
--- /dev/null
+++ b/bazel/properties_test.go
@@ -0,0 +1,89 @@
+// Copyright 2021 Google Inc. All rights reserved.
+//
+// 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.
+
+package bazel
+
+import (
+	"reflect"
+	"testing"
+)
+
+func TestUniqueBazelLabels(t *testing.T) {
+	testCases := []struct {
+		originalLabels       []Label
+		expectedUniqueLabels []Label
+	}{
+		{
+			originalLabels: []Label{
+				{Label: "a"},
+				{Label: "b"},
+				{Label: "a"},
+				{Label: "c"},
+			},
+			expectedUniqueLabels: []Label{
+				{Label: "a"},
+				{Label: "b"},
+				{Label: "c"},
+			},
+		},
+	}
+	for _, tc := range testCases {
+		actualUniqueLabels := UniqueBazelLabels(tc.originalLabels)
+		if !reflect.DeepEqual(tc.expectedUniqueLabels, actualUniqueLabels) {
+			t.Fatalf("Expected %v, got %v", tc.expectedUniqueLabels, actualUniqueLabels)
+		}
+	}
+}
+
+func TestUniqueBazelLabelList(t *testing.T) {
+	testCases := []struct {
+		originalLabelList       LabelList
+		expectedUniqueLabelList LabelList
+	}{
+		{
+			originalLabelList: LabelList{
+				Includes: []Label{
+					{Label: "a"},
+					{Label: "b"},
+					{Label: "a"},
+					{Label: "c"},
+				},
+				Excludes: []Label{
+					{Label: "x"},
+					{Label: "x"},
+					{Label: "y"},
+					{Label: "z"},
+				},
+			},
+			expectedUniqueLabelList: LabelList{
+				Includes: []Label{
+					{Label: "a"},
+					{Label: "b"},
+					{Label: "c"},
+				},
+				Excludes: []Label{
+					{Label: "x"},
+					{Label: "y"},
+					{Label: "z"},
+				},
+			},
+		},
+	}
+	for _, tc := range testCases {
+		actualUniqueLabelList := UniqueBazelLabelList(tc.originalLabelList)
+		if !reflect.DeepEqual(tc.expectedUniqueLabelList, actualUniqueLabelList) {
+			t.Fatalf("Expected %v, got %v", tc.expectedUniqueLabelList, actualUniqueLabelList)
+		}
+	}
+}
diff --git a/filesystem/bootimg.go b/filesystem/bootimg.go
index 876e189..372a610 100644
--- a/filesystem/bootimg.go
+++ b/filesystem/bootimg.go
@@ -62,6 +62,10 @@
 	// Optional kernel commandline
 	Cmdline *string
 
+	// File that contains bootconfig parameters. This can be set only when `vendor_boot` is true
+	// and `header_version` is greater than or equal to 4.
+	Bootconfig *string `android:"arch_variant,path"`
+
 	// When set to true, sign the image with avbtool. Default is false.
 	Use_avb *bool
 
@@ -189,6 +193,19 @@
 		return output
 	}
 
+	bootconfig := proptools.String(b.properties.Bootconfig)
+	if bootconfig != "" {
+		if !vendor {
+			ctx.PropertyErrorf("bootconfig", "requires vendor_boot: true")
+			return output
+		}
+		if verNum < 4 {
+			ctx.PropertyErrorf("bootconfig", "requires header_version: 4 or later")
+			return output
+		}
+		cmd.FlagWithInput("--vendor_bootconfig ", android.PathForModuleSrc(ctx, bootconfig))
+	}
+
 	flag := "--output "
 	if vendor {
 		flag = "--vendor_boot "
diff --git a/java/app.go b/java/app.go
index e98fe31..eef627c 100755
--- a/java/app.go
+++ b/java/app.go
@@ -812,6 +812,13 @@
 	depsInfo := android.DepNameToDepInfoMap{}
 	a.WalkPayloadDeps(ctx, func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) bool {
 		depName := to.Name()
+
+		// Skip dependencies that are only available to APEXes; they are developed with updatability
+		// in mind and don't need manual approval.
+		if to.(android.ApexModule).NotAvailableForPlatform() {
+			return true
+		}
+
 		if info, exist := depsInfo[depName]; exist {
 			info.From = append(info.From, from.Name())
 			info.IsExternal = info.IsExternal && externalDep
diff --git a/java/java.go b/java/java.go
index 567ebbb..036c7af 100644
--- a/java/java.go
+++ b/java/java.go
@@ -122,7 +122,16 @@
 	if sdkVersion.stable() {
 		return nil
 	}
-	return fmt.Errorf("non stable SDK %v", sdkVersion)
+	if sdkVersion.kind == sdkCorePlatform {
+		if useLegacyCorePlatformApiByName(j.BaseModuleName()) {
+			return fmt.Errorf("non stable SDK %v - uses legacy core platform", sdkVersion)
+		} else {
+			// Treat stable core platform as stable.
+			return nil
+		}
+	} else {
+		return fmt.Errorf("non stable SDK %v", sdkVersion)
+	}
 }
 
 func (j *Module) checkSdkVersions(ctx android.ModuleContext) {
diff --git a/java/legacy_core_platform_api_usage.go b/java/legacy_core_platform_api_usage.go
index 874338d..cae9dc5 100644
--- a/java/legacy_core_platform_api_usage.go
+++ b/java/legacy_core_platform_api_usage.go
@@ -108,7 +108,7 @@
 	"PrintSpooler",
 	"RollbackTest",
 	"service-blobstore",
-	"service-connectivity",
+	"service-connectivity-pre-jarjar",
 	"service-jobscheduler",
 	"services",
 	"services.accessibility",
@@ -160,7 +160,11 @@
 }
 
 func useLegacyCorePlatformApi(ctx android.EarlyModuleContext) bool {
-	_, found := legacyCorePlatformApiLookup[ctx.ModuleName()]
+	return useLegacyCorePlatformApiByName(ctx.ModuleName())
+}
+
+func useLegacyCorePlatformApiByName(name string) bool {
+	_, found := legacyCorePlatformApiLookup[name]
 	return found
 }
 
diff --git a/rust/builder.go b/rust/builder.go
index 6326124..9d462d4 100644
--- a/rust/builder.go
+++ b/rust/builder.go
@@ -194,8 +194,7 @@
 	}
 
 	if len(deps.SrcDeps) > 0 {
-		genSubDir := "out/"
-		moduleGenDir := android.PathForModuleOut(ctx, genSubDir)
+		moduleGenDir := ctx.RustModule().compiler.CargoOutDir()
 		var outputs android.WritablePaths
 
 		for _, genSrc := range deps.SrcDeps {
@@ -208,7 +207,7 @@
 
 		ctx.Build(pctx, android.BuildParams{
 			Rule:        cp,
-			Description: "cp " + moduleGenDir.Rel(),
+			Description: "cp " + moduleGenDir.Path().Rel(),
 			Outputs:     outputs,
 			Inputs:      deps.SrcDeps,
 			Args: map[string]string{
diff --git a/rust/compiler.go b/rust/compiler.go
index c26f208..98ad7ad 100644
--- a/rust/compiler.go
+++ b/rust/compiler.go
@@ -60,6 +60,7 @@
 	InstallInData                   = iota
 
 	incorrectSourcesError = "srcs can only contain one path for a rust file and source providers prefixed by \":\""
+	genSubDir             = "out/"
 )
 
 type BaseCompilerProperties struct {
@@ -154,6 +155,10 @@
 	distFile android.OptionalPath
 	// Stripped output file. If Valid(), this file will be installed instead of outputFile.
 	strippedOutputFile android.OptionalPath
+
+	// If a crate has a source-generated dependency, a copy of the source file
+	// will be available in cargoOutDir (equivalent to Cargo OUT_DIR).
+	cargoOutDir android.ModuleOutPath
 }
 
 func (compiler *baseCompiler) Disabled() bool {
@@ -243,6 +248,14 @@
 	panic(fmt.Errorf("baseCrater doesn't know how to crate things!"))
 }
 
+func (compiler *baseCompiler) initialize(ctx ModuleContext) {
+	compiler.cargoOutDir = android.PathForModuleOut(ctx, genSubDir)
+}
+
+func (compiler *baseCompiler) CargoOutDir() android.OptionalPath {
+	return android.OptionalPathForPath(compiler.cargoOutDir)
+}
+
 func (compiler *baseCompiler) isDependencyRoot() bool {
 	return false
 }
diff --git a/rust/project_json.go b/rust/project_json.go
index 32ce6f4..8d3d250 100644
--- a/rust/project_json.go
+++ b/rust/project_json.go
@@ -45,11 +45,12 @@
 }
 
 type rustProjectCrate struct {
-	DisplayName string           `json:"display_name"`
-	RootModule  string           `json:"root_module"`
-	Edition     string           `json:"edition,omitempty"`
-	Deps        []rustProjectDep `json:"deps"`
-	Cfgs        []string         `json:"cfgs"`
+	DisplayName string            `json:"display_name"`
+	RootModule  string            `json:"root_module"`
+	Edition     string            `json:"edition,omitempty"`
+	Deps        []rustProjectDep  `json:"deps"`
+	Cfgs        []string          `json:"cfgs"`
+	Env         map[string]string `json:"env"`
 }
 
 type rustProjectJson struct {
@@ -136,7 +137,7 @@
 		}
 	})
 	if !foundSource {
-		fmt.Errorf("No valid source for source provider found: %v\n", rModule)
+		ctx.Errorf("No valid source for source provider found: %v\n", rModule)
 	}
 	return sourceSrc, foundSource
 }
@@ -220,7 +221,7 @@
 func (singleton *projectGeneratorSingleton) addCrate(ctx android.SingletonContext, rModule *Module, comp *baseCompiler) (int, bool) {
 	rootModule, ok := crateSource(ctx, rModule, comp)
 	if !ok {
-		fmt.Errorf("Unable to find source for valid module: %v", rModule)
+		ctx.Errorf("Unable to find source for valid module: %v", rModule)
 		return 0, false
 	}
 
@@ -230,6 +231,11 @@
 		Edition:     comp.edition(),
 		Deps:        make([]rustProjectDep, 0),
 		Cfgs:        make([]string, 0),
+		Env:         make(map[string]string),
+	}
+
+	if comp.CargoOutDir().Valid() {
+		crate.Env["OUT_DIR"] = comp.CargoOutDir().String()
 	}
 
 	deps := make(map[string]int)
diff --git a/rust/project_json_test.go b/rust/project_json_test.go
index ba66215..289bcb8 100644
--- a/rust/project_json_test.go
+++ b/rust/project_json_test.go
@@ -190,8 +190,8 @@
 				}
 			}
 		}
-		// Check that liba depends on libbindings1
 		if strings.Contains(rootModule, "d/src/lib.rs") {
+			// Check that libd depends on libbindings1
 			found := false
 			for _, depName := range validateDependencies(t, crate) {
 				if depName == "bindings1" {
@@ -200,8 +200,17 @@
 				}
 			}
 			if !found {
-				t.Errorf("liba does not depend on libbindings1: %v", crate)
+				t.Errorf("libd does not depend on libbindings1: %v", crate)
 			}
+			// Check that OUT_DIR is populated.
+			env, ok := crate["env"].(map[string]interface{})
+			if !ok {
+				t.Errorf("libd does not have its environment variables set: %v", crate)
+			}
+			if _, ok = env["OUT_DIR"]; !ok {
+				t.Errorf("libd does not have its OUT_DIR set: %v", env)
+			}
+
 		}
 	}
 }
diff --git a/rust/rust.go b/rust/rust.go
index dc23abb..8ebdb72 100644
--- a/rust/rust.go
+++ b/rust/rust.go
@@ -320,12 +320,16 @@
 }
 
 type compiler interface {
+	initialize(ctx ModuleContext)
 	compilerFlags(ctx ModuleContext, flags Flags) Flags
 	compilerProps() []interface{}
 	compile(ctx ModuleContext, flags Flags, deps PathDeps) android.Path
 	compilerDeps(ctx DepsContext, deps Deps) Deps
 	crateName() string
 
+	// Output directory in which source-generated code from dependencies is
+	// copied. This is equivalent to Cargo's OUT_DIR variable.
+	CargoOutDir() android.OptionalPath
 	inData() bool
 	install(ctx ModuleContext)
 	relativeInstallPath() string
@@ -711,6 +715,7 @@
 	}
 
 	if mod.compiler != nil && !mod.compiler.Disabled() {
+		mod.compiler.initialize(ctx)
 		outputFile := mod.compiler.compile(ctx, flags, deps)
 
 		mod.outputFile = android.OptionalPathForPath(outputFile)