Merge "Add global C flags to compile_commands" into main
diff --git a/filesystem/Android.bp b/filesystem/Android.bp
index cead5fc..18dd553 100644
--- a/filesystem/Android.bp
+++ b/filesystem/Android.bp
@@ -18,6 +18,7 @@
         "avb_gen_vbmeta_image.go",
         "bootimg.go",
         "filesystem.go",
+        "fsverity_metadata.go",
         "logical_partition.go",
         "raw_binary.go",
         "system_image.go",
diff --git a/filesystem/filesystem.go b/filesystem/filesystem.go
index 8fb2660..e640c5d 100644
--- a/filesystem/filesystem.go
+++ b/filesystem/filesystem.go
@@ -58,7 +58,7 @@
 	output     android.OutputPath
 	installDir android.InstallPath
 
-	// For testing. Keeps the result of CopyDepsToZip()
+	// For testing. Keeps the result of CopySpecsToDir()
 	entries []string
 }
 
@@ -121,6 +121,8 @@
 	// modules would be installed to the same location as a make module, they will overwrite
 	// the make version.
 	Include_make_built_files string
+
+	Fsverity fsverityProperties
 }
 
 // android_filesystem packages a set of modules and their transitive dependencies into a filesystem
@@ -177,6 +179,10 @@
 	return f.BaseModuleName() + ".img"
 }
 
+func (f *filesystem) partitionName() string {
+	return proptools.StringDefault(f.properties.Partition_name, f.Name())
+}
+
 var pctx = android.NewPackageContext("android/soong/filesystem")
 
 func (f *filesystem) GenerateAndroidBuildActions(ctx android.ModuleContext) {
@@ -256,10 +262,12 @@
 	builder := android.NewRuleBuilder(pctx, ctx)
 	// Wipe the root dir to get rid of leftover files from prior builds
 	builder.Command().Textf("rm -rf %s && mkdir -p %s", rootDir, rootDir)
-	f.entries = f.CopySpecsToDir(ctx, builder, f.gatherFilteredPackagingSpecs(ctx), rebasedDir)
+	specs := f.gatherFilteredPackagingSpecs(ctx)
+	f.entries = f.CopySpecsToDir(ctx, builder, specs, rebasedDir)
 
 	f.buildNonDepsFiles(ctx, builder, rootDir)
 	f.addMakeBuiltFiles(ctx, builder, rootDir)
+	f.buildFsverityMetadataFiles(ctx, builder, specs, rootDir, rebasedDir)
 
 	// run host_init_verifier
 	// Ideally we should have a concept of pluggable linters that verify the generated image.
@@ -339,13 +347,12 @@
 		addStr("avb_algorithm", algorithm)
 		key := android.PathForModuleSrc(ctx, proptools.String(f.properties.Avb_private_key))
 		addPath("avb_key_path", key)
-		partitionName := proptools.StringDefault(f.properties.Partition_name, f.Name())
-		addStr("partition_name", partitionName)
+		addStr("partition_name", f.partitionName())
 		avb_add_hashtree_footer_args := "--do_not_generate_fec"
 		if hashAlgorithm := proptools.String(f.properties.Avb_hash_algorithm); hashAlgorithm != "" {
 			avb_add_hashtree_footer_args += " --hash_algorithm " + hashAlgorithm
 		}
-		securityPatchKey := "com.android.build." + partitionName + ".security_patch"
+		securityPatchKey := "com.android.build." + f.partitionName() + ".security_patch"
 		securityPatchValue := ctx.Config().PlatformSecurityPatch()
 		avb_add_hashtree_footer_args += " --prop " + securityPatchKey + ":" + securityPatchValue
 		addStr("avb_add_hashtree_footer_args", avb_add_hashtree_footer_args)
@@ -389,9 +396,11 @@
 	builder := android.NewRuleBuilder(pctx, ctx)
 	// Wipe the root dir to get rid of leftover files from prior builds
 	builder.Command().Textf("rm -rf %s && mkdir -p %s", rootDir, rootDir)
-	f.entries = f.CopySpecsToDir(ctx, builder, f.gatherFilteredPackagingSpecs(ctx), rebasedDir)
+	specs := f.gatherFilteredPackagingSpecs(ctx)
+	f.entries = f.CopySpecsToDir(ctx, builder, specs, rebasedDir)
 
 	f.buildNonDepsFiles(ctx, builder, rootDir)
+	f.buildFsverityMetadataFiles(ctx, builder, specs, rootDir, rebasedDir)
 
 	output := android.PathForModuleOut(ctx, f.installFileName()).OutputPath
 	cmd := builder.Command().
diff --git a/filesystem/fsverity_metadata.go b/filesystem/fsverity_metadata.go
new file mode 100644
index 0000000..70f94e0
--- /dev/null
+++ b/filesystem/fsverity_metadata.go
@@ -0,0 +1,166 @@
+// Copyright (C) 2024 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.
+
+package filesystem
+
+import (
+	"path/filepath"
+	"strings"
+
+	"android/soong/android"
+)
+
+type fsverityProperties struct {
+	// Patterns of files for fsverity metadata generation.  For each matched file, a .fsv_meta file
+	// will be generated and included to the filesystem image.
+	// etc/security/fsverity/BuildManifest.apk will also be generated which contains information
+	// about generated .fsv_meta files.
+	Inputs []string
+}
+
+func (f *filesystem) writeManifestGeneratorListFile(ctx android.ModuleContext, outputPath android.OutputPath, matchedSpecs []android.PackagingSpec, rebasedDir android.OutputPath) {
+	var buf strings.Builder
+	for _, spec := range matchedSpecs {
+		buf.WriteString(rebasedDir.Join(ctx, spec.RelPathInPackage()).String())
+		buf.WriteRune('\n')
+	}
+	android.WriteFileRuleVerbatim(ctx, outputPath, buf.String())
+}
+
+func (f *filesystem) buildFsverityMetadataFiles(ctx android.ModuleContext, builder *android.RuleBuilder, specs map[string]android.PackagingSpec, rootDir android.OutputPath, rebasedDir android.OutputPath) {
+	match := func(path string) bool {
+		for _, pattern := range f.properties.Fsverity.Inputs {
+			if matched, err := filepath.Match(pattern, path); matched {
+				return true
+			} else if err != nil {
+				ctx.PropertyErrorf("fsverity.inputs", "bad pattern %q", pattern)
+				return false
+			}
+		}
+		return false
+	}
+
+	var matchedSpecs []android.PackagingSpec
+	for _, relPath := range android.SortedKeys(specs) {
+		if match(relPath) {
+			matchedSpecs = append(matchedSpecs, specs[relPath])
+		}
+	}
+
+	if len(matchedSpecs) == 0 {
+		return
+	}
+
+	fsverityBuilderPath := android.PathForModuleOut(ctx, "fsverity_builder.sh")
+	metadataGeneratorPath := ctx.Config().HostToolPath(ctx, "fsverity_metadata_generator")
+	fsverityPath := ctx.Config().HostToolPath(ctx, "fsverity")
+
+	cmd := builder.Command().Tool(fsverityBuilderPath)
+
+	// STEP 1: generate .fsv_meta
+	var sb strings.Builder
+	sb.WriteString("set -e\n")
+	cmd.Implicit(metadataGeneratorPath).Implicit(fsverityPath)
+	for _, spec := range matchedSpecs {
+		// srcPath is copied by CopySpecsToDir()
+		srcPath := rebasedDir.Join(ctx, spec.RelPathInPackage())
+		destPath := rebasedDir.Join(ctx, spec.RelPathInPackage()+".fsv_meta")
+		sb.WriteString(metadataGeneratorPath.String())
+		sb.WriteString(" --fsverity-path ")
+		sb.WriteString(fsverityPath.String())
+		sb.WriteString(" --signature none --hash-alg sha256 --output ")
+		sb.WriteString(destPath.String())
+		sb.WriteRune(' ')
+		sb.WriteString(srcPath.String())
+		sb.WriteRune('\n')
+	}
+
+	// STEP 2: generate signed BuildManifest.apk
+	// STEP 2-1: generate build_manifest.pb
+	assetsPath := android.PathForModuleOut(ctx, "fsverity_manifest/assets")
+	manifestPbPath := assetsPath.Join(ctx, "build_manifest.pb")
+	manifestGeneratorPath := ctx.Config().HostToolPath(ctx, "fsverity_manifest_generator")
+	cmd.Implicit(manifestGeneratorPath)
+	sb.WriteString("rm -rf ")
+	sb.WriteString(assetsPath.String())
+	sb.WriteString(" && mkdir -p ")
+	sb.WriteString(assetsPath.String())
+	sb.WriteRune('\n')
+	sb.WriteString(manifestGeneratorPath.String())
+	sb.WriteString(" --fsverity-path ")
+	sb.WriteString(fsverityPath.String())
+	sb.WriteString(" --base-dir ")
+	sb.WriteString(rootDir.String())
+	sb.WriteString(" --output ")
+	sb.WriteString(manifestPbPath.String())
+	sb.WriteRune(' ')
+
+	manifestGeneratorListPath := android.PathForModuleOut(ctx, "fsverity_manifest.list")
+	f.writeManifestGeneratorListFile(ctx, manifestGeneratorListPath.OutputPath, matchedSpecs, rebasedDir)
+	sb.WriteRune('@')
+	sb.WriteString(manifestGeneratorListPath.String())
+	sb.WriteRune('\n')
+	cmd.Implicit(manifestGeneratorListPath)
+
+	// STEP 2-2: generate BuildManifest.apk (unsigned)
+	aapt2Path := ctx.Config().HostToolPath(ctx, "aapt2")
+	apkPath := rebasedDir.Join(ctx, "etc", "security", "fsverity", "BuildManifest.apk")
+	manifestTemplatePath := android.PathForSource(ctx, "system/security/fsverity/AndroidManifest.xml")
+	// package-export is currently generated by Makefile.
+	// TODO(b/330282551): fully migrate into Soong
+	frameworkResPath := android.PathForArbitraryOutput(ctx, "target/common/obj/APPS/framework-res_intermediates/package-export.apk")
+	cmd.Implicit(aapt2Path)
+	cmd.Implicit(manifestTemplatePath)
+	cmd.Implicit(frameworkResPath)
+
+	sb.WriteString(aapt2Path.String())
+	sb.WriteString(" link -o ")
+	sb.WriteString(apkPath.String())
+	sb.WriteString(" -A ")
+	sb.WriteString(assetsPath.String())
+	sb.WriteString(" -I ")
+	sb.WriteString(frameworkResPath.String())
+	minSdkVersion := ctx.Config().PlatformSdkCodename()
+	if minSdkVersion == "REL" {
+		minSdkVersion = ctx.Config().PlatformSdkVersion().String()
+	}
+	sb.WriteString(" --min-sdk-version ")
+	sb.WriteString(minSdkVersion)
+	sb.WriteString(" --version-code ")
+	sb.WriteString(ctx.Config().PlatformSdkVersion().String())
+	sb.WriteString(" --version-name ")
+	sb.WriteString(ctx.Config().AppsDefaultVersionName())
+	sb.WriteString(" --manifest ")
+	sb.WriteString(manifestTemplatePath.String())
+	sb.WriteString(" --rename-manifest-package com.android.security.fsverity_metadata.")
+	sb.WriteString(f.partitionName())
+	sb.WriteRune('\n')
+
+	// STEP 2-3: sign BuildManifest.apk
+	apksignerPath := ctx.Config().HostToolPath(ctx, "apksigner")
+	pemPath, keyPath := ctx.Config().DefaultAppCertificate(ctx)
+	cmd.Implicit(apksignerPath)
+	cmd.Implicit(pemPath)
+	cmd.Implicit(keyPath)
+	sb.WriteString(apksignerPath.String())
+	sb.WriteString(" sign --in ")
+	sb.WriteString(apkPath.String())
+	sb.WriteString(" --cert ")
+	sb.WriteString(pemPath.String())
+	sb.WriteString(" --key ")
+	sb.WriteString(keyPath.String())
+	sb.WriteRune('\n')
+
+	android.WriteExecutableFileRuleVerbatim(ctx, fsverityBuilderPath, sb.String())
+}
diff --git a/java/aar.go b/java/aar.go
index 3ac77fa..fef0d8c 100644
--- a/java/aar.go
+++ b/java/aar.go
@@ -1156,7 +1156,7 @@
 	}
 
 	extractedAARDir := android.PathForModuleOut(ctx, "aar")
-	classpathFile := extractedAARDir.Join(ctx, "classes-combined.jar")
+	classpathFile := extractedAARDir.Join(ctx, ctx.ModuleName()+".jar")
 	a.manifest = extractedAARDir.Join(ctx, "AndroidManifest.xml")
 	a.rTxt = extractedAARDir.Join(ctx, "R.txt")
 	a.assetsPackage = android.PathForModuleOut(ctx, "assets.zip")
@@ -1284,14 +1284,18 @@
 		addCLCFromDep(ctx, module, a.classLoaderContexts)
 	})
 
+	var implementationJarFile android.OutputPath
 	if len(staticJars) > 0 {
 		combineJars := append(android.Paths{classpathFile}, staticJars...)
-		a.implementationJarFile = android.PathForModuleOut(ctx, "combined", ctx.ModuleName()+".jar")
-		TransformJarsToJar(ctx, a.implementationJarFile, "combine", combineJars, android.OptionalPath{}, false, nil, nil)
+		implementationJarFile = android.PathForModuleOut(ctx, "combined", ctx.ModuleName()+".jar").OutputPath
+		TransformJarsToJar(ctx, implementationJarFile, "combine", combineJars, android.OptionalPath{}, false, nil, nil)
 	} else {
-		a.implementationJarFile = classpathFile
+		implementationJarFile = classpathFile
 	}
 
+	// Save the output file with no relative path so that it doesn't end up in a subdirectory when used as a resource
+	a.implementationJarFile = implementationJarFile.WithoutRel()
+
 	if len(staticHeaderJars) > 0 {
 		combineJars := append(android.Paths{classpathFile}, staticHeaderJars...)
 		a.headerJarFile = android.PathForModuleOut(ctx, "turbine-combined", ctx.ModuleName()+".jar")
diff --git a/java/aar_test.go b/java/aar_test.go
index 6bd53f2..3361bf9 100644
--- a/java/aar_test.go
+++ b/java/aar_test.go
@@ -128,3 +128,48 @@
 		"--feature-flags @out/soong/.intermediates/bar/intermediate.txt --feature-flags @out/soong/.intermediates/baz/intermediate.txt",
 	)
 }
+
+func TestAndroidLibraryOutputFilesRel(t *testing.T) {
+	result := android.GroupFixturePreparers(
+		PrepareForTestWithJavaDefaultModules,
+	).RunTestWithBp(t, `
+		android_library {
+			name: "foo",
+			srcs: ["a.java"],
+		}
+
+		android_library_import {
+			name: "bar",
+			aars: ["bar.aar"],
+
+		}
+
+		android_library_import {
+			name: "baz",
+			aars: ["baz.aar"],
+			static_libs: ["bar"],
+		}
+	`)
+
+	foo := result.ModuleForTests("foo", "android_common")
+	bar := result.ModuleForTests("bar", "android_common")
+	baz := result.ModuleForTests("baz", "android_common")
+
+	fooOutputPath := android.OutputFileForModule(android.PathContext(nil), foo.Module(), "")
+	barOutputPath := android.OutputFileForModule(android.PathContext(nil), bar.Module(), "")
+	bazOutputPath := android.OutputFileForModule(android.PathContext(nil), baz.Module(), "")
+
+	android.AssertPathRelativeToTopEquals(t, "foo output path",
+		"out/soong/.intermediates/foo/android_common/javac/foo.jar", fooOutputPath)
+	android.AssertPathRelativeToTopEquals(t, "bar output path",
+		"out/soong/.intermediates/bar/android_common/aar/bar.jar", barOutputPath)
+	android.AssertPathRelativeToTopEquals(t, "baz output path",
+		"out/soong/.intermediates/baz/android_common/combined/baz.jar", bazOutputPath)
+
+	android.AssertStringEquals(t, "foo relative output path",
+		"foo.jar", fooOutputPath.Rel())
+	android.AssertStringEquals(t, "bar relative output path",
+		"bar.jar", barOutputPath.Rel())
+	android.AssertStringEquals(t, "baz relative output path",
+		"baz.jar", bazOutputPath.Rel())
+}
diff --git a/java/base.go b/java/base.go
index 9bb133d..e2f20ce 100644
--- a/java/base.go
+++ b/java/base.go
@@ -94,9 +94,6 @@
 	// if not blank, used as prefix to generate repackage rule
 	Jarjar_prefix *string
 
-	// if set to true, skip the jarjar repackaging
-	Skip_jarjar_repackage *bool
-
 	// If not blank, set the java version passed to javac as -source and -target
 	Java_version *string
 
@@ -1103,13 +1100,11 @@
 	jarjarProviderData := j.collectJarJarRules(ctx)
 	if jarjarProviderData != nil {
 		android.SetProvider(ctx, JarJarProvider, *jarjarProviderData)
-		if !proptools.Bool(j.properties.Skip_jarjar_repackage) {
-			text := getJarJarRuleText(jarjarProviderData)
-			if text != "" {
-				ruleTextFile := android.PathForModuleOut(ctx, "repackaged-jarjar", "repackaging.txt")
-				android.WriteFileRule(ctx, ruleTextFile, text)
-				j.repackageJarjarRules = ruleTextFile
-			}
+		text := getJarJarRuleText(jarjarProviderData)
+		if text != "" {
+			ruleTextFile := android.PathForModuleOut(ctx, "repackaged-jarjar", "repackaging.txt")
+			android.WriteFileRule(ctx, ruleTextFile, text)
+			j.repackageJarjarRules = ruleTextFile
 		}
 	}
 
@@ -1294,10 +1289,12 @@
 			return
 		}
 
+		kotlinJarPath := j.repackageFlagsIfNecessary(ctx, kotlinJar.OutputPath, jarName, "kotlinc")
+
 		// Make javac rule depend on the kotlinc rule
 		flags.classpath = append(classpath{kotlinHeaderJar}, flags.classpath...)
 
-		kotlinJars = append(kotlinJars, kotlinJar)
+		kotlinJars = append(kotlinJars, kotlinJarPath)
 		kotlinHeaderJars = append(kotlinHeaderJars, kotlinHeaderJar)
 
 		// Jar kotlin classes into the final jar after javac
@@ -1377,6 +1374,7 @@
 				for idx, shardSrc := range shardSrcs {
 					classes := j.compileJavaClasses(ctx, jarName, idx, shardSrc,
 						nil, flags, extraJarDeps)
+					classes = j.repackageFlagsIfNecessary(ctx, classes, jarName, "javac-"+strconv.Itoa(idx))
 					jars = append(jars, classes)
 				}
 			}
@@ -1389,11 +1387,13 @@
 				for idx, shardSrcJars := range shardSrcJarsList {
 					classes := j.compileJavaClasses(ctx, jarName, startIdx+idx,
 						nil, shardSrcJars, flags, extraJarDeps)
+					classes = j.repackageFlagsIfNecessary(ctx, classes, jarName, "javac-"+strconv.Itoa(startIdx+idx))
 					jars = append(jars, classes)
 				}
 			}
 		} else {
 			classes := j.compileJavaClasses(ctx, jarName, -1, uniqueJavaFiles, srcJars, flags, extraJarDeps)
+			classes = j.repackageFlagsIfNecessary(ctx, classes, jarName, "javac")
 			jars = append(jars, classes)
 		}
 		if ctx.Failed() {
@@ -1552,16 +1552,6 @@
 		}
 	}
 
-	// Automatic jarjar rules propagation
-	if j.repackageJarjarRules != nil {
-		repackagedJarjarFile := android.PathForModuleOut(ctx, "repackaged-jarjar", jarName).OutputPath
-		TransformJarJar(ctx, repackagedJarjarFile, outputFile, j.repackageJarjarRules)
-		outputFile = repackagedJarjarFile
-		if ctx.Failed() {
-			return
-		}
-	}
-
 	// Check package restrictions if necessary.
 	if len(j.properties.Permitted_packages) > 0 {
 		// Time stamp file created by the package check rule.
@@ -2686,6 +2676,16 @@
 	return result
 }
 
+// Repackage the flags if the jarjar rule txt for the flags is generated
+func (j *Module) repackageFlagsIfNecessary(ctx android.ModuleContext, infile android.WritablePath, jarName, info string) android.WritablePath {
+	if j.repackageJarjarRules == nil {
+		return infile
+	}
+	repackagedJarjarFile := android.PathForModuleOut(ctx, "repackaged-jarjar", info+jarName)
+	TransformJarJar(ctx, repackagedJarjarFile, infile, j.repackageJarjarRules)
+	return repackagedJarjarFile
+}
+
 func addPlugins(deps *deps, pluginJars android.Paths, pluginClasses ...string) {
 	deps.processorPath = append(deps.processorPath, pluginJars...)
 	deps.processorClasses = append(deps.processorClasses, pluginClasses...)
diff --git a/phony/phony.go b/phony/phony.go
index 68fbf48..5469238 100644
--- a/phony/phony.go
+++ b/phony/phony.go
@@ -29,6 +29,7 @@
 func registerPhonyModuleTypes(ctx android.RegistrationContext) {
 	ctx.RegisterModuleType("phony", PhonyFactory)
 	ctx.RegisterModuleType("phony_rule", PhonyRuleFactory)
+	ctx.RegisterModuleType("phony_rule_defaults", PhonyRuleDefaultsFactory)
 }
 
 var PrepareForTestWithPhony = android.FixtureRegisterWithContext(registerPhonyModuleTypes)
@@ -85,6 +86,7 @@
 
 type PhonyRule struct {
 	android.ModuleBase
+	android.DefaultableModuleBase
 
 	properties PhonyProperties
 }
@@ -102,6 +104,7 @@
 	module := &PhonyRule{}
 	android.InitAndroidModule(module)
 	module.AddProperties(&module.properties)
+	android.InitDefaultableModule(module)
 	return module
 }
 
@@ -119,3 +122,45 @@
 		},
 	}
 }
+
+// PhonyRuleDefaults
+type PhonyRuleDefaults struct {
+	android.ModuleBase
+	android.DefaultsModuleBase
+}
+
+// phony_rule_defaults provides a set of properties that can be inherited by other phony_rules.
+//
+// A module can use the properties from a phony_rule_defaults module using `defaults: ["defaults_module_name"]`.  Each
+// property in the defaults module that exists in the depending module will be prepended to the depending module's
+// value for that property.
+//
+// Example:
+//
+//	phony_rule_defaults {
+//	    name: "add_module1_defaults",
+//	    phony_deps: [
+//	        "module1",
+//	    ],
+//	}
+//
+//	phony_rule {
+//	    name: "example",
+//	    defaults: ["add_module1_defaults"],
+//	}
+//
+// is functionally identical to:
+//
+//	phony_rule {
+//	    name: "example",
+//	    phony_deps: [
+//	        "module1",
+//	    ],
+//	}
+func PhonyRuleDefaultsFactory() android.Module {
+	module := &PhonyRuleDefaults{}
+	module.AddProperties(&PhonyProperties{})
+	android.InitDefaultsModule(module)
+
+	return module
+}