Merge "Fatal error on insufficient resource to use Goma in Soong UI."
diff --git a/android/config.go b/android/config.go
index b3469a9..38f6ec8 100644
--- a/android/config.go
+++ b/android/config.go
@@ -561,6 +561,19 @@
 	}
 }
 
+func (c *config) ApexKeyDir(ctx ModuleContext) SourcePath {
+	// TODO(b/121224311): define another variable such as TARGET_APEX_KEY_OVERRIDE
+	defaultCert := String(c.productVariables.DefaultAppCertificate)
+	if defaultCert == "" || filepath.Dir(defaultCert) == "build/target/product/security" {
+		// When defaultCert is unset or is set to the testkeys path, use the APEX keys
+		// that is under the module dir
+		return PathForModuleSrc(ctx).SourcePath
+	} else {
+		// If not, APEX keys are under the specified directory
+		return PathForSource(ctx, filepath.Dir(defaultCert))
+	}
+}
+
 func (c *config) AllowMissingDependencies() bool {
 	return Bool(c.productVariables.Allow_missing_dependencies)
 }
@@ -950,6 +963,14 @@
 	return Bool(c.productVariables.FlattenApex)
 }
 
+func (c *config) EnforceSystemCertificate() bool {
+	return Bool(c.productVariables.EnforceSystemCertificate)
+}
+
+func (c *config) EnforceSystemCertificateWhitelist() []string {
+	return c.productVariables.EnforceSystemCertificateWhitelist
+}
+
 func stringSlice(s *[]string) []string {
 	if s != nil {
 		return *s
diff --git a/android/variable.go b/android/variable.go
index 264869a..7e976cd 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -263,6 +263,9 @@
 	DexpreoptGlobalConfig *string `json:",omitempty"`
 
 	ManifestPackageNameOverrides []string `json:",omitempty"`
+
+	EnforceSystemCertificate          *bool    `json:",omitempty"`
+	EnforceSystemCertificateWhitelist []string `json:",omitempty"`
 }
 
 func boolPtr(v bool) *bool {
diff --git a/apex/apex.go b/apex/apex.go
index b324644..e711c8b 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -448,15 +448,17 @@
 		{Mutator: "arch", Variation: "android_common"},
 	}, prebuiltTag, a.properties.Prebuilts...)
 
-	if String(a.properties.Key) == "" {
-		ctx.ModuleErrorf("key is missing")
-		return
-	}
-	ctx.AddDependency(ctx.Module(), keyTag, String(a.properties.Key))
+	if !ctx.Config().FlattenApex() || ctx.Config().UnbundledBuild() {
+		if String(a.properties.Key) == "" {
+			ctx.ModuleErrorf("key is missing")
+			return
+		}
+		ctx.AddDependency(ctx.Module(), keyTag, String(a.properties.Key))
 
-	cert := android.SrcIsModule(String(a.properties.Certificate))
-	if cert != "" {
-		ctx.AddDependency(ctx.Module(), certificateTag, cert)
+		cert := android.SrcIsModule(String(a.properties.Certificate))
+		if cert != "" {
+			ctx.AddDependency(ctx.Module(), certificateTag, cert)
+		}
 	}
 }
 
@@ -626,7 +628,8 @@
 		return false
 	})
 
-	if keyFile == nil {
+	a.flattened = ctx.Config().FlattenApex() && !ctx.Config().UnbundledBuild()
+	if !a.flattened && keyFile == nil {
 		ctx.PropertyErrorf("key", "private_key for %q could not be found", String(a.properties.Key))
 		return
 	}
@@ -656,7 +659,6 @@
 		filesInfo[i].moduleName = ctx.ModuleName() + "." + filesInfo[i].moduleName
 	}
 
-	a.flattened = ctx.Config().FlattenApex() && !ctx.Config().UnbundledBuild()
 	a.installDir = android.PathForModuleInstall(ctx, "apex")
 	a.filesInfo = filesInfo
 
@@ -850,7 +852,15 @@
 		// For flattened APEX, do nothing but make sure that apex_manifest.json file is also copied along
 		// with other ordinary files.
 		manifest := android.PathForModuleSrc(ctx, proptools.StringDefault(a.properties.Manifest, "apex_manifest.json"))
-		a.filesInfo = append(a.filesInfo, apexFile{manifest, ctx.ModuleName() + ".apex_manifest.json", android.Common, ".", etc, nil})
+
+		// rename to apex_manifest.json
+		copiedManifest := android.PathForModuleOut(ctx, "apex_manifest.json")
+		ctx.Build(pctx, android.BuildParams{
+			Rule:   android.Cp,
+			Input:  manifest,
+			Output: copiedManifest,
+		})
+		a.filesInfo = append(a.filesInfo, apexFile{copiedManifest, ctx.ModuleName() + ".apex_manifest.json", android.Common, ".", etc, nil})
 
 		for _, fi := range a.filesInfo {
 			dir := filepath.Join("apex", ctx.ModuleName(), fi.installDir)
diff --git a/apex/apex_test.go b/apex/apex_test.go
index d4f0f7e..dbc85d9 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -124,13 +124,15 @@
 
 	ctx.MockFileSystem(map[string][]byte{
 		"Android.bp":                                []byte(bp),
-		"testkey.avbpubkey":                         nil,
-		"testkey.pem":                               nil,
 		"build/target/product/security":             nil,
 		"apex_manifest.json":                        nil,
 		"system/sepolicy/apex/myapex-file_contexts": nil,
 		"mylib.cpp":                                 nil,
 		"myprebuilt":                                nil,
+		"vendor/foo/devkeys/test.x509.pem":          nil,
+		"vendor/foo/devkeys/test.pk8":               nil,
+		"vendor/foo/devkeys/testkey.avbpubkey":      nil,
+		"vendor/foo/devkeys/testkey.pem":            nil,
 	})
 	_, errs := ctx.ParseFileList(".", []string{"Android.bp"})
 	android.FailIfErrored(t, errs)
@@ -148,6 +150,7 @@
 
 	config = android.TestArchConfig(buildDir, nil)
 	config.TestProductVariables.DeviceVndkVersion = proptools.StringPtr("current")
+	config.TestProductVariables.DefaultAppCertificate = proptools.StringPtr("vendor/foo/devkeys/test")
 	return
 }
 
@@ -683,3 +686,46 @@
 	// Ensure that not_in_apex is linking with the static variant of mylib
 	ensureContains(t, ldFlags, "mylib/android_arm64_armv8-a_core_static/mylib.a")
 }
+
+func TestKeys(t *testing.T) {
+	ctx := testApex(t, `
+		apex {
+			name: "myapex",
+			key: "myapex.key",
+			native_shared_libs: ["mylib"],
+		}
+
+		cc_library {
+			name: "mylib",
+			srcs: ["mylib.cpp"],
+			system_shared_libs: [],
+			stl: "none",
+		}
+
+		apex_key {
+			name: "myapex.key",
+			public_key: "testkey.avbpubkey",
+			private_key: "testkey.pem",
+		}
+
+	`)
+
+	// check the APEX keys
+	keys := ctx.ModuleForTests("myapex.key", "").Module().(*apexKey)
+
+	if keys.public_key_file.String() != "vendor/foo/devkeys/testkey.avbpubkey" {
+		t.Errorf("public key %q is not %q", keys.public_key_file.String(),
+			"vendor/foo/devkeys/testkey.avbpubkey")
+	}
+	if keys.private_key_file.String() != "vendor/foo/devkeys/testkey.pem" {
+		t.Errorf("private key %q is not %q", keys.private_key_file.String(),
+			"vendor/foo/devkeys/testkey.pem")
+	}
+
+	// check the APK certs
+	certs := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("signapk").Args["certificates"]
+	if certs != "vendor/foo/devkeys/test.x509.pem vendor/foo/devkeys/test.pk8" {
+		t.Errorf("cert and private key %q are not %q", certs,
+			"vendor/foo/devkeys/test.x509.pem vendor/foo/devkeys/test.pk8")
+	}
+}
diff --git a/apex/key.go b/apex/key.go
index 6fbc9b0..7e98d2b 100644
--- a/apex/key.go
+++ b/apex/key.go
@@ -65,8 +65,21 @@
 }
 
 func (m *apexKey) GenerateAndroidBuildActions(ctx android.ModuleContext) {
-	m.public_key_file = android.PathForModuleSrc(ctx, String(m.properties.Public_key))
-	m.private_key_file = android.PathForModuleSrc(ctx, String(m.properties.Private_key))
+	if ctx.Config().FlattenApex() && !ctx.Config().UnbundledBuild() {
+		// Flattened APEXes are not signed
+		return
+	}
+
+	m.public_key_file = ctx.Config().ApexKeyDir(ctx).Join(ctx, String(m.properties.Public_key))
+	m.private_key_file = ctx.Config().ApexKeyDir(ctx).Join(ctx, String(m.properties.Private_key))
+
+	// If not found, fall back to the local key pairs
+	if !android.ExistentPathForSource(ctx, m.public_key_file.String()).Valid() {
+		m.public_key_file = android.PathForModuleSrc(ctx, String(m.properties.Public_key))
+	}
+	if !android.ExistentPathForSource(ctx, m.private_key_file.String()).Valid() {
+		m.private_key_file = android.PathForModuleSrc(ctx, String(m.properties.Private_key))
+	}
 
 	pubKeyName := m.public_key_file.Base()[0 : len(m.public_key_file.Base())-len(m.public_key_file.Ext())]
 	privKeyName := m.private_key_file.Base()[0 : len(m.private_key_file.Base())-len(m.private_key_file.Ext())]
diff --git a/java/app.go b/java/app.go
index 3b2305f..4bae78a 100644
--- a/java/app.go
+++ b/java/app.go
@@ -263,6 +263,20 @@
 
 	packageFile := android.PathForModuleOut(ctx, "package.apk")
 	CreateAppPackage(ctx, packageFile, a.exportPackage, jniJarFile, dexJarFile, certificates)
+
+	if !a.Module.Platform() {
+		certPath := a.certificate.Pem.String()
+		systemCertPath := ctx.Config().DefaultAppCertificateDir(ctx).String()
+		if strings.HasPrefix(certPath, systemCertPath) {
+			enforceSystemCert := ctx.Config().EnforceSystemCertificate()
+			whitelist := ctx.Config().EnforceSystemCertificateWhitelist()
+
+			if enforceSystemCert && !inList(a.Module.Name(), whitelist) {
+				ctx.PropertyErrorf("certificate", "The module in product partition cannot be signed with certificate in system.")
+			}
+		}
+	}
+
 	a.outputFile = packageFile
 
 	bundleFile := android.PathForModuleOut(ctx, "base.zip")
diff --git a/java/sdk_library.go b/java/sdk_library.go
index 877abe4..55a9590 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -124,6 +124,12 @@
 	// This applies to the stubs lib.
 	Compile_dex *bool
 
+	// the java library (in classpath) for documentation that provides java srcs and srcjars.
+	Srcs_lib *string
+
+	// the base dirs under srcs_lib will be scanned for java srcs.
+	Srcs_lib_whitelist_dirs []string
+
 	// the sub dirs under srcs_lib_whitelist_dirs will be scanned for java srcs.
 	// Defaults to "android.annotation".
 	Srcs_lib_whitelist_pkgs []string
@@ -541,6 +547,10 @@
 		} else {
 			props.Srcs_lib_whitelist_pkgs = []string{"android.annotation"}
 		}
+	} else {
+		props.Srcs_lib = module.properties.Srcs_lib
+		props.Srcs_lib_whitelist_dirs = module.properties.Srcs_lib_whitelist_dirs
+		props.Srcs_lib_whitelist_pkgs = module.properties.Srcs_lib_whitelist_pkgs
 	}
 
 	if Bool(module.properties.Metalava_enabled) == true {