Merge "Fix writing soong.variables ."
diff --git a/filesystem/Android.bp b/filesystem/Android.bp
index dcdbdcf..791019d 100644
--- a/filesystem/Android.bp
+++ b/filesystem/Android.bp
@@ -14,6 +14,7 @@
         "bootimg.go",
         "filesystem.go",
         "logical_partition.go",
+        "vbmeta.go",
     ],
     testSrcs: [
     ],
diff --git a/filesystem/bootimg.go b/filesystem/bootimg.go
index 372a610..3dcc416 100644
--- a/filesystem/bootimg.go
+++ b/filesystem/bootimg.go
@@ -17,6 +17,7 @@
 import (
 	"fmt"
 	"strconv"
+	"strings"
 
 	"github.com/google/blueprint"
 	"github.com/google/blueprint/proptools"
@@ -217,22 +218,46 @@
 }
 
 func (b *bootimg) signImage(ctx android.ModuleContext, unsignedImage android.OutputPath) android.OutputPath {
-	output := android.PathForModuleOut(ctx, b.installFileName()).OutputPath
-	key := android.PathForModuleSrc(ctx, proptools.String(b.properties.Avb_private_key))
+	propFile, toolDeps := b.buildPropFile(ctx)
 
+	output := android.PathForModuleOut(ctx, b.installFileName()).OutputPath
 	builder := android.NewRuleBuilder(pctx, ctx)
 	builder.Command().Text("cp").Input(unsignedImage).Output(output)
-	builder.Command().
-		BuiltTool("avbtool").
-		Flag("add_hash_footer").
-		FlagWithArg("--partition_name ", b.partitionName()).
-		FlagWithInput("--key ", key).
-		FlagWithOutput("--image ", output)
+	builder.Command().BuiltTool("verity_utils").
+		Input(propFile).
+		Implicits(toolDeps).
+		Output(output)
 
 	builder.Build("sign_bootimg", fmt.Sprintf("Signing %s", b.BaseModuleName()))
 	return output
 }
 
+func (b *bootimg) buildPropFile(ctx android.ModuleContext) (propFile android.OutputPath, toolDeps android.Paths) {
+	var sb strings.Builder
+	var deps android.Paths
+	addStr := func(name string, value string) {
+		fmt.Fprintf(&sb, "%s=%s\n", name, value)
+	}
+	addPath := func(name string, path android.Path) {
+		addStr(name, path.String())
+		deps = append(deps, path)
+	}
+
+	addStr("avb_hash_enable", "true")
+	addPath("avb_avbtool", ctx.Config().HostToolPath(ctx, "avbtool"))
+	algorithm := proptools.StringDefault(b.properties.Avb_algorithm, "SHA256_RSA4096")
+	addStr("avb_algorithm", algorithm)
+	key := android.PathForModuleSrc(ctx, proptools.String(b.properties.Avb_private_key))
+	addPath("avb_key_path", key)
+	addStr("avb_add_hash_footer_args", "") // TODO(jiyong): add --rollback_index
+	partitionName := proptools.StringDefault(b.properties.Partition_name, b.Name())
+	addStr("partition_name", partitionName)
+
+	propFile = android.PathForModuleOut(ctx, "prop").OutputPath
+	android.WriteFileRule(ctx, propFile, sb.String())
+	return propFile, deps
+}
+
 var _ android.AndroidMkEntriesProvider = (*bootimg)(nil)
 
 // Implements android.AndroidMkEntriesProvider
@@ -255,6 +280,13 @@
 	return b.output
 }
 
+func (b *bootimg) SignedOutputPath() android.Path {
+	if proptools.Bool(b.properties.Use_avb) {
+		return b.OutputPath()
+	}
+	return nil
+}
+
 var _ android.OutputFileProducer = (*bootimg)(nil)
 
 // Implements android.OutputFileProducer
diff --git a/filesystem/filesystem.go b/filesystem/filesystem.go
index 3b0a7ae..8974eba 100644
--- a/filesystem/filesystem.go
+++ b/filesystem/filesystem.go
@@ -55,6 +55,9 @@
 	// Hash and signing algorithm for avbtool. Default is SHA256_RSA4096.
 	Avb_algorithm *string
 
+	// Name of the partition stored in vbmeta desc. Defaults to the name of this module.
+	Partition_name *string
+
 	// Type of the filesystem. Currently, ext4, cpio, and compressed_cpio are supported. Default
 	// is ext4.
 	Type *string
@@ -279,7 +282,8 @@
 		key := android.PathForModuleSrc(ctx, proptools.String(f.properties.Avb_private_key))
 		addPath("avb_key_path", key)
 		addStr("avb_add_hashtree_footer_args", "--do_not_generate_fec")
-		addStr("partition_name", f.Name())
+		partitionName := proptools.StringDefault(f.properties.Partition_name, f.Name())
+		addStr("partition_name", partitionName)
 	}
 
 	if proptools.String(f.properties.File_contexts) != "" {
@@ -381,6 +385,10 @@
 type Filesystem interface {
 	android.Module
 	OutputPath() android.Path
+
+	// Returns the output file that is signed by avbtool. If this module is not signed, returns
+	// nil.
+	SignedOutputPath() android.Path
 }
 
 var _ Filesystem = (*filesystem)(nil)
@@ -388,3 +396,10 @@
 func (f *filesystem) OutputPath() android.Path {
 	return f.output
 }
+
+func (f *filesystem) SignedOutputPath() android.Path {
+	if proptools.Bool(f.properties.Use_avb) {
+		return f.OutputPath()
+	}
+	return nil
+}
diff --git a/filesystem/logical_partition.go b/filesystem/logical_partition.go
index 16b6037..20d9622 100644
--- a/filesystem/logical_partition.go
+++ b/filesystem/logical_partition.go
@@ -209,6 +209,10 @@
 	return l.output
 }
 
+func (l *logicalPartition) SignedOutputPath() android.Path {
+	return nil // logical partition is not signed by itself
+}
+
 var _ android.OutputFileProducer = (*logicalPartition)(nil)
 
 // Implements android.OutputFileProducer
diff --git a/filesystem/vbmeta.go b/filesystem/vbmeta.go
new file mode 100644
index 0000000..f823387
--- /dev/null
+++ b/filesystem/vbmeta.go
@@ -0,0 +1,265 @@
+// Copyright (C) 2021 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 (
+	"fmt"
+	"strconv"
+
+	"github.com/google/blueprint"
+	"github.com/google/blueprint/proptools"
+
+	"android/soong/android"
+)
+
+func init() {
+	android.RegisterModuleType("vbmeta", vbmetaFactory)
+}
+
+type vbmeta struct {
+	android.ModuleBase
+
+	properties vbmetaProperties
+
+	output     android.OutputPath
+	installDir android.InstallPath
+}
+
+type vbmetaProperties struct {
+	// Name of the partition stored in vbmeta desc. Defaults to the name of this module.
+	Partition_name *string
+
+	// Set the name of the output. Defaults to <module_name>.img.
+	Stem *string
+
+	// Path to the private key that avbtool will use to sign this vbmeta image.
+	Private_key *string `android:"path"`
+
+	// Algorithm that avbtool will use to sign this vbmeta image. Default is SHA256_RSA4096.
+	Algorithm *string
+
+	// File whose content will provide the rollback index. If unspecified, the rollback index
+	// is from PLATFORM_SECURITY_PATCH
+	Rollback_index_file *string `android:"path"`
+
+	// Rollback index location of this vbmeta image. Must be 0, 1, 2, etc. Default is 0.
+	Rollback_index_location *int64
+
+	// List of filesystem modules that this vbmeta has descriptors for. The filesystem modules
+	// have to be signed (use_avb: true).
+	Partitions []string
+
+	// List of chained partitions that this vbmeta deletages the verification.
+	Chained_partitions []chainedPartitionProperties
+}
+
+type chainedPartitionProperties struct {
+	// Name of the chained partition
+	Name *string
+
+	// Rollback index location of the chained partition. Must be 0, 1, 2, etc. Default is the
+	// index of this partition in the list + 1.
+	Rollback_index_location *int64
+
+	// Path to the public key that the chained partition is signed with. If this is specified,
+	// private_key is ignored.
+	Public_key *string `android:"path"`
+
+	// Path to the private key that the chained partition is signed with. If this is specified,
+	// and public_key is not specified, a public key is extracted from this private key and
+	// the extracted public key is embedded in the vbmeta image.
+	Private_key *string `android:"path"`
+}
+
+// vbmeta is the partition image that has the verification information for other partitions.
+func vbmetaFactory() android.Module {
+	module := &vbmeta{}
+	module.AddProperties(&module.properties)
+	android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibFirst)
+	return module
+}
+
+type vbmetaDep struct {
+	blueprint.BaseDependencyTag
+	kind string
+}
+
+var vbmetaPartitionDep = vbmetaDep{kind: "partition"}
+
+func (v *vbmeta) DepsMutator(ctx android.BottomUpMutatorContext) {
+	ctx.AddDependency(ctx.Module(), vbmetaPartitionDep, v.properties.Partitions...)
+}
+
+func (v *vbmeta) installFileName() string {
+	return proptools.StringDefault(v.properties.Stem, v.BaseModuleName()+".img")
+}
+
+func (v *vbmeta) partitionName() string {
+	return proptools.StringDefault(v.properties.Partition_name, v.BaseModuleName())
+}
+
+func (v *vbmeta) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+	extractedPublicKeys := v.extractPublicKeys(ctx)
+
+	v.output = android.PathForModuleOut(ctx, v.installFileName()).OutputPath
+
+	builder := android.NewRuleBuilder(pctx, ctx)
+	cmd := builder.Command().BuiltTool("avbtool").Text("make_vbmeta_image")
+
+	key := android.PathForModuleSrc(ctx, proptools.String(v.properties.Private_key))
+	cmd.FlagWithInput("--key ", key)
+
+	algorithm := proptools.StringDefault(v.properties.Algorithm, "SHA256_RSA4096")
+	cmd.FlagWithArg("--algorithm ", algorithm)
+
+	cmd.FlagWithArg("--rollback_index ", v.rollbackIndexCommand(ctx))
+	ril := proptools.IntDefault(v.properties.Rollback_index_location, 0)
+	if ril < 0 {
+		ctx.PropertyErrorf("rollback_index_location", "must be 0, 1, 2, ...")
+		return
+	}
+	cmd.FlagWithArg("--rollback_index_location ", strconv.Itoa(ril))
+
+	for _, p := range ctx.GetDirectDepsWithTag(vbmetaPartitionDep) {
+		f, ok := p.(Filesystem)
+		if !ok {
+			ctx.PropertyErrorf("partitions", "%q(type: %s) is not supported",
+				p.Name(), ctx.OtherModuleType(p))
+			continue
+		}
+		signedImage := f.SignedOutputPath()
+		if signedImage == nil {
+			ctx.PropertyErrorf("partitions", "%q(type: %s) is not signed. Use `use_avb: true`",
+				p.Name(), ctx.OtherModuleType(p))
+			continue
+		}
+		cmd.FlagWithInput("--include_descriptors_from_image ", signedImage)
+	}
+
+	for i, cp := range v.properties.Chained_partitions {
+		name := proptools.String(cp.Name)
+		if name == "" {
+			ctx.PropertyErrorf("chained_partitions", "name must be specified")
+			continue
+		}
+
+		ril := proptools.IntDefault(cp.Rollback_index_location, i+1)
+		if ril < 0 {
+			ctx.PropertyErrorf("chained_partitions", "must be 0, 1, 2, ...")
+			continue
+		}
+
+		var publicKey android.Path
+		if cp.Public_key != nil {
+			publicKey = android.PathForModuleSrc(ctx, proptools.String(cp.Public_key))
+		} else {
+			publicKey = extractedPublicKeys[name]
+		}
+		cmd.FlagWithArg("--chain_partition ", fmt.Sprintf("%s:%d:%s", name, ril, publicKey.String()))
+		cmd.Implicit(publicKey)
+	}
+
+	cmd.FlagWithOutput("--output ", v.output)
+	builder.Build("vbmeta", fmt.Sprintf("vbmeta %s", ctx.ModuleName()))
+
+	v.installDir = android.PathForModuleInstall(ctx, "etc")
+	ctx.InstallFile(v.installDir, v.installFileName(), v.output)
+}
+
+// Returns the embedded shell command that prints the rollback index
+func (v *vbmeta) rollbackIndexCommand(ctx android.ModuleContext) string {
+	var cmd string
+	if v.properties.Rollback_index_file != nil {
+		f := android.PathForModuleSrc(ctx, proptools.String(v.properties.Rollback_index_file))
+		cmd = "cat " + f.String()
+	} else {
+		cmd = "date -d 'TZ=\"GMT\" " + ctx.Config().PlatformSecurityPatch() + "' +%s"
+	}
+	// Take the first line and remove the newline char
+	return "$(" + cmd + " | head -1 | tr -d '\n'" + ")"
+}
+
+// Extract public keys from chained_partitions.private_key. The keys are indexed with the partition
+// name.
+func (v *vbmeta) extractPublicKeys(ctx android.ModuleContext) map[string]android.OutputPath {
+	result := make(map[string]android.OutputPath)
+
+	builder := android.NewRuleBuilder(pctx, ctx)
+	for _, cp := range v.properties.Chained_partitions {
+		if cp.Private_key == nil {
+			continue
+		}
+
+		name := proptools.String(cp.Name)
+		if name == "" {
+			ctx.PropertyErrorf("chained_partitions", "name must be specified")
+			continue
+		}
+
+		if _, ok := result[name]; ok {
+			ctx.PropertyErrorf("chained_partitions", "name %q is duplicated", name)
+			continue
+		}
+
+		privateKeyFile := android.PathForModuleSrc(ctx, proptools.String(cp.Private_key))
+		publicKeyFile := android.PathForModuleOut(ctx, name+".avbpubkey").OutputPath
+
+		builder.Command().
+			BuiltTool("avbtool").
+			Text("extract_public_key").
+			FlagWithInput("--key ", privateKeyFile).
+			FlagWithOutput("--output ", publicKeyFile)
+
+		result[name] = publicKeyFile
+	}
+	builder.Build("vbmeta_extract_public_key", fmt.Sprintf("Extract public keys for %s", ctx.ModuleName()))
+	return result
+}
+
+var _ android.AndroidMkEntriesProvider = (*vbmeta)(nil)
+
+// Implements android.AndroidMkEntriesProvider
+func (v *vbmeta) AndroidMkEntries() []android.AndroidMkEntries {
+	return []android.AndroidMkEntries{android.AndroidMkEntries{
+		Class:      "ETC",
+		OutputFile: android.OptionalPathForPath(v.output),
+		ExtraEntries: []android.AndroidMkExtraEntriesFunc{
+			func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
+				entries.SetString("LOCAL_MODULE_PATH", v.installDir.ToMakePath().String())
+				entries.SetString("LOCAL_INSTALLED_MODULE_STEM", v.installFileName())
+			},
+		},
+	}}
+}
+
+var _ Filesystem = (*vbmeta)(nil)
+
+func (v *vbmeta) OutputPath() android.Path {
+	return v.output
+}
+
+func (v *vbmeta) SignedOutputPath() android.Path {
+	return v.OutputPath() // vbmeta is always signed
+}
+
+var _ android.OutputFileProducer = (*vbmeta)(nil)
+
+// Implements android.OutputFileProducer
+func (v *vbmeta) OutputFiles(tag string) (android.Paths, error) {
+	if tag == "" {
+		return []android.Path{v.output}, nil
+	}
+	return nil, fmt.Errorf("unsupported module reference tag %q", tag)
+}
diff --git a/rust/bindgen.go b/rust/bindgen.go
index 56d660e..db69e23 100644
--- a/rust/bindgen.go
+++ b/rust/bindgen.go
@@ -29,7 +29,7 @@
 	defaultBindgenFlags = []string{""}
 
 	// bindgen should specify its own Clang revision so updating Clang isn't potentially blocked on bindgen failures.
-	bindgenClangVersion = "clang-r399163b"
+	bindgenClangVersion = "clang-r412851"
 
 	_ = pctx.VariableFunc("bindgenClangVersion", func(ctx android.PackageVarContext) string {
 		if override := ctx.Config().Getenv("LLVM_BINDGEN_PREBUILTS_VERSION"); override != "" {