Merge "Fix prebuilt_apis creating of "latest" incompatibilities"
diff --git a/android/apex.go b/android/apex.go
index 31c62e9..d3f8d2a 100644
--- a/android/apex.go
+++ b/android/apex.go
@@ -830,9 +830,8 @@
 		return
 	}
 
-	// do not enforce deps.min_sdk_version if APEX/APK doesn't set min_sdk_version or
-	// min_sdk_version is not finalized (e.g. current or codenames)
-	if minSdkVersion.IsCurrent() {
+	// do not enforce deps.min_sdk_version if APEX/APK doesn't set min_sdk_version
+	if minSdkVersion.IsNone() {
 		return
 	}
 
diff --git a/android/api_levels.go b/android/api_levels.go
index 08328e1..1b53f3f 100644
--- a/android/api_levels.go
+++ b/android/api_levels.go
@@ -81,6 +81,10 @@
 	return this.value == "current"
 }
 
+func (this ApiLevel) IsNone() bool {
+	return this.number == -1
+}
+
 // Returns -1 if the current API level is less than the argument, 0 if they
 // are equal, and 1 if it is greater than the argument.
 func (this ApiLevel) CompareTo(other ApiLevel) int {
diff --git a/android/filegroup.go b/android/filegroup.go
index fd4a2fe..3d1bbc5 100644
--- a/android/filegroup.go
+++ b/android/filegroup.go
@@ -23,7 +23,7 @@
 
 func init() {
 	RegisterModuleType("filegroup", FileGroupFactory)
-	RegisterBp2BuildMutator("filegroup", bp2buildMutator)
+	RegisterBp2BuildMutator("filegroup", FilegroupBp2Build)
 }
 
 // https://docs.bazel.build/versions/master/be/general.html#filegroup
@@ -51,7 +51,7 @@
 func (bfg *bazelFilegroup) GenerateAndroidBuildActions(ctx ModuleContext) {}
 
 // TODO: Create helper functions to avoid this boilerplate.
-func bp2buildMutator(ctx TopDownMutatorContext) {
+func FilegroupBp2Build(ctx TopDownMutatorContext) {
 	if m, ok := ctx.Module().(*fileGroup); ok {
 		name := "__bp2build__" + m.base().BaseModuleName()
 		ctx.CreateModule(BazelFileGroupFactory, &bazelFilegroupAttributes{
diff --git a/android/module.go b/android/module.go
index 68008c2..dcc2b84 100644
--- a/android/module.go
+++ b/android/module.go
@@ -492,22 +492,39 @@
 	TransitivePackagingSpecs() []PackagingSpec
 }
 
+// BazelTargetModule is a lightweight wrapper interface around Module for
+// bp2build conversion purposes.
+//
+// In bp2build's bootstrap.Main execution, Soong runs an alternate pipeline of
+// mutators that creates BazelTargetModules from regular Module objects,
+// performing the mapping from Soong properties to Bazel rule attributes in the
+// process. This process may optionally create additional BazelTargetModules,
+// resulting in a 1:many mapping.
+//
+// bp2build.Codegen is then responsible for visiting all modules in the graph,
+// filtering for BazelTargetModules, and code-generating BUILD targets from
+// them.
 type BazelTargetModule interface {
 	Module
 
 	BazelTargetModuleProperties() *bazel.BazelTargetModuleProperties
 }
 
+// InitBazelTargetModule is a wrapper function that decorates BazelTargetModule
+// with property structs containing metadata for bp2build conversion.
 func InitBazelTargetModule(module BazelTargetModule) {
 	module.AddProperties(module.BazelTargetModuleProperties())
 	InitAndroidModule(module)
 }
 
+// BazelTargetModuleBase contains the property structs with metadata for
+// bp2build conversion.
 type BazelTargetModuleBase struct {
 	ModuleBase
 	Properties bazel.BazelTargetModuleProperties
 }
 
+// BazelTargetModuleProperties getter.
 func (btmb *BazelTargetModuleBase) BazelTargetModuleProperties() *bazel.BazelTargetModuleProperties {
 	return &btmb.Properties
 }
@@ -1868,19 +1885,11 @@
 }
 
 func (e *earlyModuleContext) Glob(globPattern string, excludes []string) Paths {
-	ret, err := e.GlobWithDeps(globPattern, excludes)
-	if err != nil {
-		e.ModuleErrorf("glob: %s", err.Error())
-	}
-	return pathsForModuleSrcFromFullPath(e, ret, true)
+	return Glob(e, globPattern, excludes)
 }
 
 func (e *earlyModuleContext) GlobFiles(globPattern string, excludes []string) Paths {
-	ret, err := e.GlobWithDeps(globPattern, excludes)
-	if err != nil {
-		e.ModuleErrorf("glob: %s", err.Error())
-	}
-	return pathsForModuleSrcFromFullPath(e, ret, false)
+	return GlobFiles(e, globPattern, excludes)
 }
 
 func (b *earlyModuleContext) IsSymlink(path Path) bool {
diff --git a/android/paths.go b/android/paths.go
index 592b9e1..b5a1401 100644
--- a/android/paths.go
+++ b/android/paths.go
@@ -51,6 +51,53 @@
 func (NullPathContext) AddNinjaFileDeps(...string) {}
 func (ctx NullPathContext) Config() Config         { return ctx.config }
 
+// EarlyModulePathContext is a subset of EarlyModuleContext methods required by the
+// Path methods. These path methods can be called before any mutators have run.
+type EarlyModulePathContext interface {
+	PathContext
+	PathGlobContext
+
+	ModuleDir() string
+	ModuleErrorf(fmt string, args ...interface{})
+}
+
+var _ EarlyModulePathContext = ModuleContext(nil)
+
+// Glob globs files and directories matching globPattern relative to ModuleDir(),
+// paths in the excludes parameter will be omitted.
+func Glob(ctx EarlyModulePathContext, globPattern string, excludes []string) Paths {
+	ret, err := ctx.GlobWithDeps(globPattern, excludes)
+	if err != nil {
+		ctx.ModuleErrorf("glob: %s", err.Error())
+	}
+	return pathsForModuleSrcFromFullPath(ctx, ret, true)
+}
+
+// GlobFiles globs *only* files (not directories) matching globPattern relative to ModuleDir().
+// Paths in the excludes parameter will be omitted.
+func GlobFiles(ctx EarlyModulePathContext, globPattern string, excludes []string) Paths {
+	ret, err := ctx.GlobWithDeps(globPattern, excludes)
+	if err != nil {
+		ctx.ModuleErrorf("glob: %s", err.Error())
+	}
+	return pathsForModuleSrcFromFullPath(ctx, ret, false)
+}
+
+// ModuleWithDepsPathContext is a subset of *ModuleContext methods required by
+// the Path methods that rely on module dependencies having been resolved.
+type ModuleWithDepsPathContext interface {
+	EarlyModulePathContext
+	GetDirectDepWithTag(name string, tag blueprint.DependencyTag) blueprint.Module
+}
+
+// ModuleMissingDepsPathContext is a subset of *ModuleContext methods required by
+// the Path methods that rely on module dependencies having been resolved and ability to report
+// missing dependency errors.
+type ModuleMissingDepsPathContext interface {
+	ModuleWithDepsPathContext
+	AddMissingDependencies(missingDeps []string)
+}
+
 type ModuleInstallPathContext interface {
 	BaseModuleContext
 
@@ -143,18 +190,18 @@
 }
 
 type genPathProvider interface {
-	genPathWithExt(ctx ModuleContext, subdir, ext string) ModuleGenPath
+	genPathWithExt(ctx ModuleOutPathContext, subdir, ext string) ModuleGenPath
 }
 type objPathProvider interface {
-	objPathWithExt(ctx ModuleContext, subdir, ext string) ModuleObjPath
+	objPathWithExt(ctx ModuleOutPathContext, subdir, ext string) ModuleObjPath
 }
 type resPathProvider interface {
-	resPathWithName(ctx ModuleContext, name string) ModuleResPath
+	resPathWithName(ctx ModuleOutPathContext, name string) ModuleResPath
 }
 
 // GenPathWithExt derives a new file path in ctx's generated sources directory
 // from the current path, but with the new extension.
-func GenPathWithExt(ctx ModuleContext, subdir string, p Path, ext string) ModuleGenPath {
+func GenPathWithExt(ctx ModuleOutPathContext, subdir string, p Path, ext string) ModuleGenPath {
 	if path, ok := p.(genPathProvider); ok {
 		return path.genPathWithExt(ctx, subdir, ext)
 	}
@@ -164,7 +211,7 @@
 
 // ObjPathWithExt derives a new file path in ctx's object directory from the
 // current path, but with the new extension.
-func ObjPathWithExt(ctx ModuleContext, subdir string, p Path, ext string) ModuleObjPath {
+func ObjPathWithExt(ctx ModuleOutPathContext, subdir string, p Path, ext string) ModuleObjPath {
 	if path, ok := p.(objPathProvider); ok {
 		return path.objPathWithExt(ctx, subdir, ext)
 	}
@@ -175,7 +222,7 @@
 // ResPathWithName derives a new path in ctx's output resource directory, using
 // the current path to create the directory name, and the `name` argument for
 // the filename.
-func ResPathWithName(ctx ModuleContext, p Path, name string) ModuleResPath {
+func ResPathWithName(ctx ModuleOutPathContext, p Path, name string) ModuleResPath {
 	if path, ok := p.(resPathProvider); ok {
 		return path.resPathWithName(ctx, name)
 	}
@@ -261,7 +308,7 @@
 // `android:"path"` so that dependencies on SourceFileProducer modules will have already been handled by the
 // path_properties mutator.  If ctx.Config().AllowMissingDependencies() is true then any missing SourceFileProducer or
 // OutputFileProducer dependencies will cause the module to be marked as having missing dependencies.
-func PathsForModuleSrc(ctx ModuleContext, paths []string) Paths {
+func PathsForModuleSrc(ctx ModuleMissingDepsPathContext, paths []string) Paths {
 	return PathsForModuleSrcExcludes(ctx, paths, nil)
 }
 
@@ -272,7 +319,7 @@
 // will have already been handled by the path_properties mutator.  If ctx.Config().AllowMissingDependencies() is
 // true then any missing SourceFileProducer or OutputFileProducer dependencies will cause the module to be marked as
 // having missing dependencies.
-func PathsForModuleSrcExcludes(ctx ModuleContext, paths, excludes []string) Paths {
+func PathsForModuleSrcExcludes(ctx ModuleMissingDepsPathContext, paths, excludes []string) Paths {
 	ret, missingDeps := PathsAndMissingDepsForModuleSrcExcludes(ctx, paths, excludes)
 	if ctx.Config().AllowMissingDependencies() {
 		ctx.AddMissingDependencies(missingDeps)
@@ -311,6 +358,29 @@
 	return ret
 }
 
+// Expands Paths to a SourceFileProducer or OutputFileProducer module dependency referenced via ":name" or ":name{.tag}" syntax.
+// If the dependency is not found, a missingErrorDependency is returned.
+// If the module dependency is not a SourceFileProducer or OutputFileProducer, appropriate errors will be returned.
+func getPathsFromModuleDep(ctx ModuleWithDepsPathContext, path, moduleName, tag string) (Paths, error) {
+	module := ctx.GetDirectDepWithTag(moduleName, sourceOrOutputDepTag(tag))
+	if module == nil {
+		return nil, missingDependencyError{[]string{moduleName}}
+	}
+	if outProducer, ok := module.(OutputFileProducer); ok {
+		outputFiles, err := outProducer.OutputFiles(tag)
+		if err != nil {
+			return nil, fmt.Errorf("path dependency %q: %s", path, err)
+		}
+		return outputFiles, nil
+	} else if tag != "" {
+		return nil, fmt.Errorf("path dependency %q is not an output file producing module", path)
+	} else if srcProducer, ok := module.(SourceFileProducer); ok {
+		return srcProducer.Srcs(), nil
+	} else {
+		return nil, fmt.Errorf("path dependency %q is not a source file producing module", path)
+	}
+}
+
 // PathsAndMissingDepsForModuleSrcExcludes returns Paths rooted from the module's local source directory, excluding
 // paths listed in the excludes arguments, and a list of missing dependencies.  It expands globs, references to
 // SourceFileProducer modules using the ":name" syntax, and references to OutputFileProducer modules using the
@@ -319,7 +389,7 @@
 // path_properties mutator.  If ctx.Config().AllowMissingDependencies() is true then any missing SourceFileProducer or
 // OutputFileProducer dependencies will be returned, and they will NOT cause the module to be marked as having missing
 // dependencies.
-func PathsAndMissingDepsForModuleSrcExcludes(ctx ModuleContext, paths, excludes []string) (Paths, []string) {
+func PathsAndMissingDepsForModuleSrcExcludes(ctx ModuleWithDepsPathContext, paths, excludes []string) (Paths, []string) {
 	prefix := pathForModuleSrc(ctx).String()
 
 	var expandedExcludes []string
@@ -331,23 +401,13 @@
 
 	for _, e := range excludes {
 		if m, t := SrcIsModuleWithTag(e); m != "" {
-			module := ctx.GetDirectDepWithTag(m, sourceOrOutputDepTag(t))
-			if module == nil {
-				missingExcludeDeps = append(missingExcludeDeps, m)
-				continue
-			}
-			if outProducer, ok := module.(OutputFileProducer); ok {
-				outputFiles, err := outProducer.OutputFiles(t)
-				if err != nil {
-					ctx.ModuleErrorf("path dependency %q: %s", e, err)
-				}
-				expandedExcludes = append(expandedExcludes, outputFiles.Strings()...)
-			} else if t != "" {
-				ctx.ModuleErrorf("path dependency %q is not an output file producing module", e)
-			} else if srcProducer, ok := module.(SourceFileProducer); ok {
-				expandedExcludes = append(expandedExcludes, srcProducer.Srcs().Strings()...)
+			modulePaths, err := getPathsFromModuleDep(ctx, e, m, t)
+			if m, ok := err.(missingDependencyError); ok {
+				missingExcludeDeps = append(missingExcludeDeps, m.missingDeps...)
+			} else if err != nil {
+				reportPathError(ctx, err)
 			} else {
-				ctx.ModuleErrorf("path dependency %q is not a source file producing module", e)
+				expandedExcludes = append(expandedExcludes, modulePaths.Strings()...)
 			}
 		} else {
 			expandedExcludes = append(expandedExcludes, filepath.Join(prefix, e))
@@ -382,7 +442,10 @@
 	return "missing dependencies: " + strings.Join(e.missingDeps, ", ")
 }
 
-func expandOneSrcPath(ctx ModuleContext, s string, expandedExcludes []string) (Paths, error) {
+// Expands one path string to Paths rooted from the module's local source
+// directory, excluding those listed in the expandedExcludes.
+// Expands globs, references to SourceFileProducer or OutputFileProducer modules using the ":name" and ":name{.tag}" syntax.
+func expandOneSrcPath(ctx ModuleWithDepsPathContext, sPath string, expandedExcludes []string) (Paths, error) {
 	excludePaths := func(paths Paths) Paths {
 		if len(expandedExcludes) == 0 {
 			return paths
@@ -395,29 +458,18 @@
 		}
 		return remainder
 	}
-	if m, t := SrcIsModuleWithTag(s); m != "" {
-		module := ctx.GetDirectDepWithTag(m, sourceOrOutputDepTag(t))
-		if module == nil {
-			return nil, missingDependencyError{[]string{m}}
-		}
-		if outProducer, ok := module.(OutputFileProducer); ok {
-			outputFiles, err := outProducer.OutputFiles(t)
-			if err != nil {
-				return nil, fmt.Errorf("path dependency %q: %s", s, err)
-			}
-			return excludePaths(outputFiles), nil
-		} else if t != "" {
-			return nil, fmt.Errorf("path dependency %q is not an output file producing module", s)
-		} else if srcProducer, ok := module.(SourceFileProducer); ok {
-			return excludePaths(srcProducer.Srcs()), nil
+	if m, t := SrcIsModuleWithTag(sPath); m != "" {
+		modulePaths, err := getPathsFromModuleDep(ctx, sPath, m, t)
+		if err != nil {
+			return nil, err
 		} else {
-			return nil, fmt.Errorf("path dependency %q is not a source file producing module", s)
+			return excludePaths(modulePaths), nil
 		}
-	} else if pathtools.IsGlob(s) {
-		paths := ctx.GlobFiles(pathForModuleSrc(ctx, s).String(), expandedExcludes)
+	} else if pathtools.IsGlob(sPath) {
+		paths := GlobFiles(ctx, pathForModuleSrc(ctx, sPath).String(), expandedExcludes)
 		return PathsWithModuleSrcSubDir(ctx, paths, ""), nil
 	} else {
-		p := pathForModuleSrc(ctx, s)
+		p := pathForModuleSrc(ctx, sPath)
 		if exists, _, err := ctx.Config().fs.Exists(p.String()); err != nil {
 			ReportPathErrorf(ctx, "%s: %s", p, err.Error())
 		} else if !exists && !ctx.Config().testAllowNonExistentPaths {
@@ -436,7 +488,7 @@
 // each string. If incDirs is false, strip paths with a trailing '/' from the list.
 // It intended for use in globs that only list files that exist, so it allows '$' in
 // filenames.
-func pathsForModuleSrcFromFullPath(ctx EarlyModuleContext, paths []string, incDirs bool) Paths {
+func pathsForModuleSrcFromFullPath(ctx EarlyModulePathContext, paths []string, incDirs bool) Paths {
 	prefix := filepath.Join(ctx.Config().srcDir, ctx.ModuleDir()) + "/"
 	if prefix == "./" {
 		prefix = ""
@@ -465,16 +517,16 @@
 	return ret
 }
 
-// PathsWithOptionalDefaultForModuleSrc returns Paths rooted from the module's
-// local source directory. If input is nil, use the default if it exists.  If input is empty, returns nil.
-func PathsWithOptionalDefaultForModuleSrc(ctx ModuleContext, input []string, def string) Paths {
+// PathsWithOptionalDefaultForModuleSrc returns Paths rooted from the module's local source
+// directory. If input is nil, use the default if it exists.  If input is empty, returns nil.
+func PathsWithOptionalDefaultForModuleSrc(ctx ModuleMissingDepsPathContext, input []string, def string) Paths {
 	if input != nil {
 		return PathsForModuleSrc(ctx, input)
 	}
 	// Use Glob so that if the default doesn't exist, a dependency is added so that when it
 	// is created, we're run again.
 	path := filepath.Join(ctx.Config().srcDir, ctx.ModuleDir(), def)
-	return ctx.Glob(path, nil)
+	return Glob(ctx, path, nil)
 }
 
 // Strings returns the Paths in string form
@@ -846,7 +898,7 @@
 		ReportPathErrorf(ctx, "path may not contain a glob: %s", path.String())
 	}
 
-	if modCtx, ok := ctx.(ModuleContext); ok && ctx.Config().AllowMissingDependencies() {
+	if modCtx, ok := ctx.(ModuleMissingDepsPathContext); ok && ctx.Config().AllowMissingDependencies() {
 		exists, err := existsWithDependencies(ctx, path)
 		if err != nil {
 			reportPathError(ctx, err)
@@ -913,7 +965,7 @@
 
 // OverlayPath returns the overlay for `path' if it exists. This assumes that the
 // SourcePath is the path to a resource overlay directory.
-func (p SourcePath) OverlayPath(ctx ModuleContext, path Path) OptionalPath {
+func (p SourcePath) OverlayPath(ctx ModuleMissingDepsPathContext, path Path) OptionalPath {
 	var relDir string
 	if srcPath, ok := path.(SourcePath); ok {
 		relDir = srcPath.path
@@ -1054,7 +1106,7 @@
 
 // PathForModuleSrc returns a Path representing the paths... under the
 // module's local source directory.
-func PathForModuleSrc(ctx ModuleContext, pathComponents ...string) Path {
+func PathForModuleSrc(ctx ModuleMissingDepsPathContext, pathComponents ...string) Path {
 	p, err := validatePath(pathComponents...)
 	if err != nil {
 		reportPathError(ctx, err)
@@ -1080,7 +1132,7 @@
 	return paths[0]
 }
 
-func pathForModuleSrc(ctx ModuleContext, paths ...string) SourcePath {
+func pathForModuleSrc(ctx EarlyModulePathContext, paths ...string) SourcePath {
 	p, err := validatePath(paths...)
 	if err != nil {
 		reportPathError(ctx, err)
@@ -1099,7 +1151,7 @@
 // PathsWithModuleSrcSubDir takes a list of Paths and returns a new list of Paths where Rel() on each path
 // will return the path relative to subDir in the module's source directory.  If any input paths are not located
 // inside subDir then a path error will be reported.
-func PathsWithModuleSrcSubDir(ctx ModuleContext, paths Paths, subDir string) Paths {
+func PathsWithModuleSrcSubDir(ctx EarlyModulePathContext, paths Paths, subDir string) Paths {
 	paths = append(Paths(nil), paths...)
 	subDirFullPath := pathForModuleSrc(ctx, subDir)
 	for i, path := range paths {
@@ -1111,7 +1163,7 @@
 
 // PathWithModuleSrcSubDir takes a Path and returns a Path where Rel() will return the path relative to subDir in the
 // module's source directory.  If the input path is not located inside subDir then a path error will be reported.
-func PathWithModuleSrcSubDir(ctx ModuleContext, path Path, subDir string) Path {
+func PathWithModuleSrcSubDir(ctx EarlyModulePathContext, path Path, subDir string) Path {
 	subDirFullPath := pathForModuleSrc(ctx, subDir)
 	rel := Rel(ctx, subDirFullPath.String(), path.String())
 	return subDirFullPath.Join(ctx, rel)
@@ -1119,22 +1171,22 @@
 
 // OptionalPathForModuleSrc returns an OptionalPath. The OptionalPath contains a
 // valid path if p is non-nil.
-func OptionalPathForModuleSrc(ctx ModuleContext, p *string) OptionalPath {
+func OptionalPathForModuleSrc(ctx ModuleMissingDepsPathContext, p *string) OptionalPath {
 	if p == nil {
 		return OptionalPath{}
 	}
 	return OptionalPathForPath(PathForModuleSrc(ctx, *p))
 }
 
-func (p SourcePath) genPathWithExt(ctx ModuleContext, subdir, ext string) ModuleGenPath {
+func (p SourcePath) genPathWithExt(ctx ModuleOutPathContext, subdir, ext string) ModuleGenPath {
 	return PathForModuleGen(ctx, subdir, pathtools.ReplaceExtension(p.path, ext))
 }
 
-func (p SourcePath) objPathWithExt(ctx ModuleContext, subdir, ext string) ModuleObjPath {
+func (p SourcePath) objPathWithExt(ctx ModuleOutPathContext, subdir, ext string) ModuleObjPath {
 	return PathForModuleObj(ctx, subdir, pathtools.ReplaceExtension(p.path, ext))
 }
 
-func (p SourcePath) resPathWithName(ctx ModuleContext, name string) ModuleResPath {
+func (p SourcePath) resPathWithName(ctx ModuleOutPathContext, name string) ModuleResPath {
 	// TODO: Use full directory if the new ctx is not the current ctx?
 	return PathForModuleRes(ctx, p.path, name)
 }
@@ -1146,11 +1198,20 @@
 
 var _ Path = ModuleOutPath{}
 
-func (p ModuleOutPath) objPathWithExt(ctx ModuleContext, subdir, ext string) ModuleObjPath {
+func (p ModuleOutPath) objPathWithExt(ctx ModuleOutPathContext, subdir, ext string) ModuleObjPath {
 	return PathForModuleObj(ctx, subdir, pathtools.ReplaceExtension(p.path, ext))
 }
 
-func pathForModule(ctx ModuleContext) OutputPath {
+// ModuleOutPathContext Subset of ModuleContext functions necessary for output path methods.
+type ModuleOutPathContext interface {
+	PathContext
+
+	ModuleName() string
+	ModuleDir() string
+	ModuleSubDir() string
+}
+
+func pathForModuleOut(ctx ModuleOutPathContext) OutputPath {
 	return PathForOutput(ctx, ".intermediates", ctx.ModuleDir(), ctx.ModuleName(), ctx.ModuleSubDir())
 }
 
@@ -1161,13 +1222,13 @@
 var _ Path = BazelOutPath{}
 var _ objPathProvider = BazelOutPath{}
 
-func (p BazelOutPath) objPathWithExt(ctx ModuleContext, subdir, ext string) ModuleObjPath {
+func (p BazelOutPath) objPathWithExt(ctx ModuleOutPathContext, subdir, ext string) ModuleObjPath {
 	return PathForModuleObj(ctx, subdir, pathtools.ReplaceExtension(p.path, ext))
 }
 
 // PathForVndkRefAbiDump returns an OptionalPath representing the path of the
 // reference abi dump for the given module. This is not guaranteed to be valid.
-func PathForVndkRefAbiDump(ctx ModuleContext, version, fileName string,
+func PathForVndkRefAbiDump(ctx ModuleInstallPathContext, version, fileName string,
 	isNdk, isLlndkOrVndk, isGzip bool) OptionalPath {
 
 	arches := ctx.DeviceConfig().Arches()
@@ -1223,13 +1284,13 @@
 
 // PathForModuleOut returns a Path representing the paths... under the module's
 // output directory.
-func PathForModuleOut(ctx ModuleContext, paths ...string) ModuleOutPath {
+func PathForModuleOut(ctx ModuleOutPathContext, paths ...string) ModuleOutPath {
 	p, err := validatePath(paths...)
 	if err != nil {
 		reportPathError(ctx, err)
 	}
 	return ModuleOutPath{
-		OutputPath: pathForModule(ctx).withRel(p),
+		OutputPath: pathForModuleOut(ctx).withRel(p),
 	}
 }
 
@@ -1245,24 +1306,24 @@
 
 // PathForModuleGen returns a Path representing the paths... under the module's
 // `gen' directory.
-func PathForModuleGen(ctx ModuleContext, paths ...string) ModuleGenPath {
+func PathForModuleGen(ctx ModuleOutPathContext, paths ...string) ModuleGenPath {
 	p, err := validatePath(paths...)
 	if err != nil {
 		reportPathError(ctx, err)
 	}
 	return ModuleGenPath{
 		ModuleOutPath: ModuleOutPath{
-			OutputPath: pathForModule(ctx).withRel("gen").withRel(p),
+			OutputPath: pathForModuleOut(ctx).withRel("gen").withRel(p),
 		},
 	}
 }
 
-func (p ModuleGenPath) genPathWithExt(ctx ModuleContext, subdir, ext string) ModuleGenPath {
+func (p ModuleGenPath) genPathWithExt(ctx ModuleOutPathContext, subdir, ext string) ModuleGenPath {
 	// TODO: make a different path for local vs remote generated files?
 	return PathForModuleGen(ctx, subdir, pathtools.ReplaceExtension(p.path, ext))
 }
 
-func (p ModuleGenPath) objPathWithExt(ctx ModuleContext, subdir, ext string) ModuleObjPath {
+func (p ModuleGenPath) objPathWithExt(ctx ModuleOutPathContext, subdir, ext string) ModuleObjPath {
 	return PathForModuleObj(ctx, subdir, pathtools.ReplaceExtension(p.path, ext))
 }
 
@@ -1276,7 +1337,7 @@
 
 // PathForModuleObj returns a Path representing the paths... under the module's
 // 'obj' directory.
-func PathForModuleObj(ctx ModuleContext, pathComponents ...string) ModuleObjPath {
+func PathForModuleObj(ctx ModuleOutPathContext, pathComponents ...string) ModuleObjPath {
 	p, err := validatePath(pathComponents...)
 	if err != nil {
 		reportPathError(ctx, err)
@@ -1294,7 +1355,7 @@
 
 // PathForModuleRes returns a Path representing the paths... under the module's
 // 'res' directory.
-func PathForModuleRes(ctx ModuleContext, pathComponents ...string) ModuleResPath {
+func PathForModuleRes(ctx ModuleOutPathContext, pathComponents ...string) ModuleResPath {
 	p, err := validatePath(pathComponents...)
 	if err != nil {
 		reportPathError(ctx, err)
diff --git a/android/testing.go b/android/testing.go
index 76172d1..5640c29 100644
--- a/android/testing.go
+++ b/android/testing.go
@@ -89,7 +89,7 @@
 	f := func(ctx RegisterMutatorsContext) {
 		ctx.TopDown(mutatorName, m)
 	}
-	bp2buildMutators = append(bp2buildMutators, f)
+	ctx.bp2buildMutators = append(ctx.bp2buildMutators, f)
 }
 
 func (ctx *TestContext) Register() {
@@ -100,7 +100,7 @@
 
 // RegisterForBazelConversion prepares a test context for bp2build conversion.
 func (ctx *TestContext) RegisterForBazelConversion() {
-	RegisterMutatorsForBazelConversion(ctx.Context.Context, bp2buildMutators)
+	RegisterMutatorsForBazelConversion(ctx.Context.Context, ctx.bp2buildMutators)
 }
 
 func (ctx *TestContext) ParseFileList(rootDir string, filePaths []string) (deps []string, errs []error) {
diff --git a/apex/Android.bp b/apex/Android.bp
index 77dde72..b6fdcf4 100644
--- a/apex/Android.bp
+++ b/apex/Android.bp
@@ -25,6 +25,7 @@
     ],
     testSrcs: [
         "apex_test.go",
+        "boot_image_test.go",
         "vndk_test.go",
     ],
     pluginFor: ["soong_build"],
diff --git a/apex/allowed_deps.txt b/apex/allowed_deps.txt
index c4ea381..6dd49e5 100644
--- a/apex/allowed_deps.txt
+++ b/apex/allowed_deps.txt
@@ -18,6 +18,7 @@
 android.hardware.cas@1.0(minSdkVersion:29)
 android.hardware.common-ndk_platform(minSdkVersion:29)
 android.hardware.common-unstable-ndk_platform(minSdkVersion:29)
+android.hardware.common-V2-ndk_platform(minSdkVersion:29)
 android.hardware.graphics.allocator@2.0(minSdkVersion:29)
 android.hardware.graphics.allocator@3.0(minSdkVersion:29)
 android.hardware.graphics.allocator@4.0(minSdkVersion:29)
@@ -25,6 +26,7 @@
 android.hardware.graphics.bufferqueue@2.0(minSdkVersion:29)
 android.hardware.graphics.common-ndk_platform(minSdkVersion:29)
 android.hardware.graphics.common-unstable-ndk_platform(minSdkVersion:29)
+android.hardware.graphics.common-V2-ndk_platform(minSdkVersion:29)
 android.hardware.graphics.common@1.0(minSdkVersion:29)
 android.hardware.graphics.common@1.1(minSdkVersion:29)
 android.hardware.graphics.common@1.2(minSdkVersion:29)
@@ -164,6 +166,7 @@
 derive_sdk_prefer32(minSdkVersion:30)
 derive_sdk_prefer32(minSdkVersion:current)
 dnsresolver_aidl_interface-unstable-ndk_platform(minSdkVersion:29)
+dnsresolver_aidl_interface-V8-ndk_platform(minSdkVersion:29)
 DocumentsUI-res-lib(minSdkVersion:29)
 exoplayer2-extractor(minSdkVersion:16)
 exoplayer2-extractor-annotation-stubs(minSdkVersion:16)
@@ -194,6 +197,7 @@
 InProcessTethering(minSdkVersion:current)
 ipmemorystore-aidl-interfaces-java(minSdkVersion:29)
 ipmemorystore-aidl-interfaces-unstable-java(minSdkVersion:29)
+ipmemorystore-aidl-interfaces-V11-java(minSdkVersion:29)
 jni_headers(minSdkVersion:29)
 jsr305(minSdkVersion:14)
 kotlinx-coroutines-android(minSdkVersion:current)
@@ -476,11 +480,14 @@
 netd-client(minSdkVersion:29)
 netd_aidl_interface-java(minSdkVersion:29)
 netd_aidl_interface-unstable-java(minSdkVersion:29)
+netd_aidl_interface-V6-java(minSdkVersion:29)
 netd_event_listener_interface-java(minSdkVersion:29)
 netd_event_listener_interface-ndk_platform(minSdkVersion:29)
 netd_event_listener_interface-unstable-ndk_platform(minSdkVersion:29)
+netd_event_listener_interface-V2-ndk_platform(minSdkVersion:29)
 netlink-client(minSdkVersion:29)
 networkstack-aidl-interfaces-unstable-java(minSdkVersion:29)
+networkstack-aidl-interfaces-V10-java(minSdkVersion:29)
 networkstack-client(minSdkVersion:29)
 NetworkStackApiStableDependencies(minSdkVersion:29)
 NetworkStackApiStableLib(minSdkVersion:29)
diff --git a/apex/androidmk.go b/apex/androidmk.go
index 4408283..99cd75e 100644
--- a/apex/androidmk.go
+++ b/apex/androidmk.go
@@ -450,12 +450,21 @@
 					fmt.Fprintf(w, dist)
 				}
 
-				if a.coverageOutputPath.String() != "" {
+				if a.apisUsedByModuleFile.String() != "" {
 					goal := "apps_only"
-					distFile := a.coverageOutputPath.String()
+					distFile := a.apisUsedByModuleFile.String()
 					fmt.Fprintf(w, "ifneq (,$(filter $(my_register_name),$(TARGET_BUILD_APPS)))\n"+
 						" $(call dist-for-goals,%s,%s:ndk_apis_usedby_apex/$(notdir %s))\n"+
-						"endif",
+						"endif\n",
+						goal, distFile, distFile)
+				}
+
+				if a.apisBackedByModuleFile.String() != "" {
+					goal := "apps_only"
+					distFile := a.apisBackedByModuleFile.String()
+					fmt.Fprintf(w, "ifneq (,$(filter $(my_register_name),$(TARGET_BUILD_APPS)))\n"+
+						" $(call dist-for-goals,%s,%s:ndk_apis_backedby_apex/$(notdir %s))\n"+
+						"endif\n",
 						goal, distFile, distFile)
 				}
 			}
diff --git a/apex/apex.go b/apex/apex.go
index 507d3ed..ade8fa9 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -390,7 +390,8 @@
 	isCompressed bool
 
 	// Path of API coverage generate file
-	coverageOutputPath android.ModuleOutPath
+	apisUsedByModuleFile   android.ModuleOutPath
+	apisBackedByModuleFile android.ModuleOutPath
 }
 
 // apexFileClass represents a type of file that can be included in APEX.
@@ -853,11 +854,17 @@
 		Contents: apexContents,
 	})
 
+	minSdkVersion := a.minSdkVersion(mctx)
+	// When min_sdk_version is not set, the apex is built against FutureApiLevel.
+	if minSdkVersion.IsNone() {
+		minSdkVersion = android.FutureApiLevel
+	}
+
 	// This is the main part of this mutator. Mark the collected dependencies that they need to
 	// be built for this apexBundle.
 	apexInfo := android.ApexInfo{
 		ApexVariationName: mctx.ModuleName(),
-		MinSdkVersionStr:  a.minSdkVersion(mctx).String(),
+		MinSdkVersionStr:  minSdkVersion.String(),
 		RequiredSdks:      a.RequiredSdks(),
 		Updatable:         a.Updatable(),
 		InApexes:          []string{mctx.ModuleName()},
@@ -2115,17 +2122,13 @@
 func (a *apexBundle) minSdkVersion(ctx android.BaseModuleContext) android.ApiLevel {
 	ver := proptools.String(a.properties.Min_sdk_version)
 	if ver == "" {
-		return android.FutureApiLevel
+		return android.NoneApiLevel
 	}
 	apiLevel, err := android.ApiLevelFromUser(ctx, ver)
 	if err != nil {
 		ctx.PropertyErrorf("min_sdk_version", "%s", err.Error())
 		return android.NoneApiLevel
 	}
-	if apiLevel.IsPreview() {
-		// All codenames should build against "current".
-		return android.FutureApiLevel
-	}
 	return apiLevel
 }
 
diff --git a/apex/apex_test.go b/apex/apex_test.go
index b1e8480..cded770 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -2135,6 +2135,74 @@
 	expectLink("mylib", "shared_apex30", "mylib2", "shared_apex30")
 }
 
+func TestApexMinSdkVersion_WorksWithSdkCodename(t *testing.T) {
+	withSAsActiveCodeNames := func(fs map[string][]byte, config android.Config) {
+		config.TestProductVariables.Platform_sdk_codename = proptools.StringPtr("S")
+		config.TestProductVariables.Platform_version_active_codenames = []string{"S"}
+	}
+	testApexError(t, `libbar.*: should support min_sdk_version\(S\)`, `
+		apex {
+			name: "myapex",
+			key: "myapex.key",
+			native_shared_libs: ["libfoo"],
+			min_sdk_version: "S",
+		}
+		apex_key {
+			name: "myapex.key",
+			public_key: "testkey.avbpubkey",
+			private_key: "testkey.pem",
+		}
+		cc_library {
+			name: "libfoo",
+			shared_libs: ["libbar"],
+			apex_available: ["myapex"],
+			min_sdk_version: "29",
+		}
+		cc_library {
+			name: "libbar",
+			apex_available: ["myapex"],
+		}
+	`, withSAsActiveCodeNames)
+}
+
+func TestApexMinSdkVersion_WorksWithActiveCodenames(t *testing.T) {
+	withSAsActiveCodeNames := func(fs map[string][]byte, config android.Config) {
+		config.TestProductVariables.Platform_sdk_codename = proptools.StringPtr("S")
+		config.TestProductVariables.Platform_version_active_codenames = []string{"S", "T"}
+	}
+	ctx, _ := testApex(t, `
+		apex {
+			name: "myapex",
+			key: "myapex.key",
+			native_shared_libs: ["libfoo"],
+			min_sdk_version: "S",
+		}
+		apex_key {
+			name: "myapex.key",
+			public_key: "testkey.avbpubkey",
+			private_key: "testkey.pem",
+		}
+		cc_library {
+			name: "libfoo",
+			shared_libs: ["libbar"],
+			apex_available: ["myapex"],
+			min_sdk_version: "S",
+		}
+		cc_library {
+			name: "libbar",
+			stubs: {
+				symbol_file: "libbar.map.txt",
+				versions: ["30", "S", "T"],
+			},
+		}
+	`, withSAsActiveCodeNames)
+
+	// ensure libfoo is linked with "S" version of libbar stub
+	libfoo := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_shared_apex10000")
+	libFlags := libfoo.Rule("ld").Args["libFlags"]
+	ensureContains(t, libFlags, "android_arm64_armv8-a_shared_S/libbar.so")
+}
+
 func TestFilesInSubDir(t *testing.T) {
 	ctx, _ := testApex(t, `
 		apex {
@@ -4213,9 +4281,11 @@
 	}
 }
 
+// These tests verify that the prebuilt_apex/deapexer to java_import wiring allows for the
+// propagation of paths to dex implementation jars from the former to the latter.
 func TestPrebuiltExportDexImplementationJars(t *testing.T) {
 	transform := func(config *dexpreopt.GlobalConfig) {
-		config.BootJars = android.CreateTestConfiguredJarList([]string{"myapex:libfoo"})
+		// Empty transformation.
 	}
 
 	checkDexJarBuildPath := func(ctx *android.TestContext, name string) {
@@ -4298,7 +4368,6 @@
 		bp := `
 		prebuilt_apex {
 			name: "myapex",
-			prefer: true,
 			arch: {
 				arm64: {
 					src: "myapex-arm64.apex",
@@ -4312,6 +4381,7 @@
 
 		java_import {
 			name: "libfoo",
+			prefer: true,
 			jars: ["libfoo.jar"],
 		}
 
@@ -5863,7 +5933,7 @@
 			srcs: ["a.java"],
 			sdk_version: "current",
 			apex_available: [
-				"com.android.art.something",
+				"com.android.art.debug",
 			],
 			hostdex: true,
 		}
@@ -5891,15 +5961,15 @@
 		}
 
 		apex {
-			name: "com.android.art.something",
-			key: "com.android.art.something.key",
+			name: "com.android.art.debug",
+			key: "com.android.art.debug.key",
 			java_libs: ["some-art-lib"],
 			updatable: true,
 			min_sdk_version: "current",
 		}
 
 		apex_key {
-			name: "com.android.art.something.key",
+			name: "com.android.art.debug.key",
 		}
 
 		filegroup {
@@ -5925,7 +5995,6 @@
 
 	bp += cc.GatherRequiredDepsForTest(android.Android)
 	bp += java.GatherRequiredDepsForTest()
-	bp += dexpreopt.BpToolModulesForTest()
 
 	fs := map[string][]byte{
 		"a.java":                             nil,
@@ -5933,9 +6002,9 @@
 		"build/make/target/product/security": nil,
 		"apex_manifest.json":                 nil,
 		"AndroidManifest.xml":                nil,
-		"system/sepolicy/apex/some-updatable-apex-file_contexts":       nil,
-		"system/sepolicy/apex/some-non-updatable-apex-file_contexts":   nil,
-		"system/sepolicy/apex/com.android.art.something-file_contexts": nil,
+		"system/sepolicy/apex/some-updatable-apex-file_contexts":     nil,
+		"system/sepolicy/apex/some-non-updatable-apex-file_contexts": nil,
+		"system/sepolicy/apex/com.android.art.debug-file_contexts":   nil,
 		"framework/aidl/a.aidl": nil,
 	}
 	cc.GatherRequiredFilesForTest(fs)
@@ -5957,7 +6026,6 @@
 
 	ctx.Register()
 
-	dexpreopt.RegisterToolModulesForTest(ctx)
 	pathCtx := android.PathContextForTesting(config)
 	dexpreoptConfig := dexpreopt.GlobalConfigForTests(pathCtx)
 	transformDexpreoptConfig(dexpreoptConfig)
@@ -6000,15 +6068,15 @@
 
 	t.Run("updatable jar from ART apex in the ART boot image => ok", func(t *testing.T) {
 		transform = func(config *dexpreopt.GlobalConfig) {
-			config.ArtApexJars = android.CreateTestConfiguredJarList([]string{"com.android.art.something:some-art-lib"})
+			config.ArtApexJars = android.CreateTestConfiguredJarList([]string{"com.android.art.debug:some-art-lib"})
 		}
 		testNoUpdatableJarsInBootImage(t, "", transform)
 	})
 
 	t.Run("updatable jar from ART apex in the framework boot image => error", func(t *testing.T) {
-		err = `module "some-art-lib" from updatable apexes \["com.android.art.something"\] is not allowed in the framework boot image`
+		err = `module "some-art-lib" from updatable apexes \["com.android.art.debug"\] is not allowed in the framework boot image`
 		transform = func(config *dexpreopt.GlobalConfig) {
-			config.BootJars = android.CreateTestConfiguredJarList([]string{"com.android.art.something:some-art-lib"})
+			config.BootJars = android.CreateTestConfiguredJarList([]string{"com.android.art.debug:some-art-lib"})
 		}
 		testNoUpdatableJarsInBootImage(t, err, transform)
 	})
diff --git a/apex/boot_image_test.go b/apex/boot_image_test.go
new file mode 100644
index 0000000..07feb03
--- /dev/null
+++ b/apex/boot_image_test.go
@@ -0,0 +1,128 @@
+// 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 apex
+
+import (
+	"testing"
+
+	"android/soong/android"
+	"android/soong/dexpreopt"
+	"android/soong/java"
+)
+
+// Contains tests for boot_image logic from java/boot_image.go as the ART boot image requires
+// modules from the ART apex.
+
+func TestBootImages(t *testing.T) {
+	ctx, _ := testApex(t, `
+		java_sdk_library {
+			name: "foo",
+			srcs: ["b.java"],
+			unsafe_ignore_missing_latest_api: true,
+		}
+
+		java_library {
+			name: "bar",
+			srcs: ["b.java"],
+			installable: true,
+		}
+
+		apex {
+			name: "com.android.art",
+			key: "com.android.art.key",
+ 			java_libs: [
+				"baz",
+				"quuz",
+			],
+		}
+
+		apex_key {
+			name: "com.android.art.key",
+			public_key: "com.android.art.avbpubkey",
+			private_key: "com.android.art.pem",
+		}
+
+		java_library {
+			name: "baz",
+			apex_available: [
+				"com.android.art",
+			],
+			srcs: ["b.java"],
+		}
+
+		java_library {
+			name: "quuz",
+			apex_available: [
+				"com.android.art",
+			],
+			srcs: ["b.java"],
+		}
+`,
+		// Configure some libraries in the art and framework boot images.
+		withArtBootImageJars("com.android.art:baz", "com.android.art:quuz"),
+		withFrameworkBootImageJars("platform:foo", "platform:bar"),
+		withFiles(filesForSdkLibrary),
+		// Some additional files needed for the art apex.
+		withFiles(map[string][]byte{
+			"com.android.art.avbpubkey":                          nil,
+			"com.android.art.pem":                                nil,
+			"system/sepolicy/apex/com.android.art-file_contexts": nil,
+		}),
+	)
+
+	// Make sure that the framework-boot-image is using the correct configuration.
+	checkBootImage(t, ctx, "framework-boot-image", "platform:foo,platform:bar")
+
+	// Make sure that the art-boot-image is using the correct configuration.
+	checkBootImage(t, ctx, "art-boot-image", "com.android.art:baz,com.android.art:quuz")
+}
+
+func checkBootImage(t *testing.T, ctx *android.TestContext, moduleName string, expectedConfiguredModules string) {
+	t.Helper()
+
+	bootImage := ctx.ModuleForTests(moduleName, "android_common").Module().(*java.BootImageModule)
+
+	bootImageInfo := ctx.ModuleProvider(bootImage, java.BootImageInfoProvider).(java.BootImageInfo)
+	modules := bootImageInfo.Modules()
+	if actual := modules.String(); actual != expectedConfiguredModules {
+		t.Errorf("invalid modules for %s: expected %q, actual %q", moduleName, expectedConfiguredModules, actual)
+	}
+}
+
+func modifyDexpreoptConfig(configModifier func(dexpreoptConfig *dexpreopt.GlobalConfig)) func(fs map[string][]byte, config android.Config) {
+	return func(fs map[string][]byte, config android.Config) {
+		// Initialize the dexpreopt GlobalConfig to an empty structure. This has no effect if it has
+		// already been set.
+		pathCtx := android.PathContextForTesting(config)
+		dexpreoptConfig := dexpreopt.GlobalConfigForTests(pathCtx)
+		dexpreopt.SetTestGlobalConfig(config, dexpreoptConfig)
+
+		// Retrieve the existing configuration and modify it.
+		dexpreoptConfig = dexpreopt.GetGlobalConfig(pathCtx)
+		configModifier(dexpreoptConfig)
+	}
+}
+
+func withArtBootImageJars(bootJars ...string) func(fs map[string][]byte, config android.Config) {
+	return modifyDexpreoptConfig(func(dexpreoptConfig *dexpreopt.GlobalConfig) {
+		dexpreoptConfig.ArtApexJars = android.CreateTestConfiguredJarList(bootJars)
+	})
+}
+
+func withFrameworkBootImageJars(bootJars ...string) func(fs map[string][]byte, config android.Config) {
+	return modifyDexpreoptConfig(func(dexpreoptConfig *dexpreopt.GlobalConfig) {
+		dexpreoptConfig.BootJars = android.CreateTestConfiguredJarList(bootJars)
+	})
+}
diff --git a/apex/builder.go b/apex/builder.go
index e6bc3bd..ee0a410 100644
--- a/apex/builder.go
+++ b/apex/builder.go
@@ -598,7 +598,7 @@
 
 		// bundletool doesn't understand what "current" is. We need to transform it to
 		// codename
-		if moduleMinSdkVersion.IsCurrent() {
+		if moduleMinSdkVersion.IsCurrent() || moduleMinSdkVersion.IsNone() {
 			minSdkVersion = ctx.Config().DefaultAppTargetSdk(ctx).String()
 		}
 		// apex module doesn't have a concept of target_sdk_version, hence for the time
@@ -687,7 +687,7 @@
 		implicitInputs = append(implicitInputs, unsignedOutputFile)
 
 		// Run coverage analysis
-		apisUsedbyOutputFile := android.PathForModuleOut(ctx, a.Name()+".txt")
+		apisUsedbyOutputFile := android.PathForModuleOut(ctx, a.Name()+"_using.txt")
 		ctx.Build(pctx, android.BuildParams{
 			Rule:        generateAPIsUsedbyApexRule,
 			Implicits:   implicitInputs,
@@ -698,7 +698,19 @@
 				"readelf":   "${config.ClangBin}/llvm-readelf",
 			},
 		})
-		a.coverageOutputPath = apisUsedbyOutputFile
+		a.apisUsedByModuleFile = apisUsedbyOutputFile
+
+		apisBackedbyOutputFile := android.PathForModuleOut(ctx, a.Name()+"_backing.txt")
+		ndkLibraryList := android.PathForSource(ctx, "system/core/rootdir/etc/public.libraries.android.txt")
+		rule := android.NewRuleBuilder(pctx, ctx)
+		rule.Command().
+			Tool(android.PathForSource(ctx, "build/soong/scripts/gen_ndk_backedby_apex.sh")).
+			Text(imageDir.String()).
+			Implicits(implicitInputs).
+			Output(apisBackedbyOutputFile).
+			Input(ndkLibraryList)
+		rule.Build("ndk_backedby_list", "Generate API libraries backed by Apex")
+		a.apisBackedByModuleFile = apisBackedbyOutputFile
 
 		bundleConfig := a.buildBundleConfig(ctx)
 
diff --git a/bazel/aquery.go b/bazel/aquery.go
index a196e8b..eb4bdfe 100644
--- a/bazel/aquery.go
+++ b/bazel/aquery.go
@@ -46,9 +46,9 @@
 // Represents a data structure containing one or more files. Depsets in Bazel are an efficient
 // data structure for storing large numbers of file paths.
 type depSetOfFiles struct {
-	Id int
-	// TODO(cparsons): Handle non-flat depsets.
-	DirectArtifactIds []int
+	Id                  int
+	DirectArtifactIds   []int
+	TransitiveDepSetIds []int
 }
 
 // action contains relevant portions of Bazel's aquery proto, Action.
@@ -105,11 +105,16 @@
 		}
 		artifactIdToPath[artifact.Id] = artifactPath
 	}
-	depsetIdToArtifactIds := map[int][]int{}
+
+	depsetIdToDepset := map[int]depSetOfFiles{}
 	for _, depset := range aqueryResult.DepSetOfFiles {
-		depsetIdToArtifactIds[depset.Id] = depset.DirectArtifactIds
+		depsetIdToDepset[depset.Id] = depset
 	}
 
+	// depsetIdToArtifactIdsCache is a memoization of depset flattening, because flattening
+	// may be an expensive operation.
+	depsetIdToArtifactIdsCache := map[int][]int{}
+
 	for _, actionEntry := range aqueryResult.Actions {
 		outputPaths := []string{}
 		for _, outputId := range actionEntry.OutputIds {
@@ -121,9 +126,10 @@
 		}
 		inputPaths := []string{}
 		for _, inputDepSetId := range actionEntry.InputDepSetIds {
-			inputArtifacts, exists := depsetIdToArtifactIds[inputDepSetId]
-			if !exists {
-				return nil, fmt.Errorf("undefined input depsetId %d", inputDepSetId)
+			inputArtifacts, err :=
+				artifactIdsFromDepsetId(depsetIdToDepset, depsetIdToArtifactIdsCache, inputDepSetId)
+			if err != nil {
+				return nil, err
 			}
 			for _, inputId := range inputArtifacts {
 				inputPath, exists := artifactIdToPath[inputId]
@@ -145,6 +151,28 @@
 	return buildStatements, nil
 }
 
+func artifactIdsFromDepsetId(depsetIdToDepset map[int]depSetOfFiles,
+	depsetIdToArtifactIdsCache map[int][]int, depsetId int) ([]int, error) {
+	if result, exists := depsetIdToArtifactIdsCache[depsetId]; exists {
+		return result, nil
+	}
+	if depset, exists := depsetIdToDepset[depsetId]; exists {
+		result := depset.DirectArtifactIds
+		for _, childId := range depset.TransitiveDepSetIds {
+			childArtifactIds, err :=
+				artifactIdsFromDepsetId(depsetIdToDepset, depsetIdToArtifactIdsCache, childId)
+			if err != nil {
+				return nil, err
+			}
+			result = append(result, childArtifactIds...)
+		}
+		depsetIdToArtifactIdsCache[depsetId] = result
+		return result, nil
+	} else {
+		return nil, fmt.Errorf("undefined input depsetId %d", depsetId)
+	}
+}
+
 func expandPathFragment(id int, pathFragmentsMap map[int]pathFragment) (string, error) {
 	labels := []string{}
 	currId := id
diff --git a/bazel/aquery_test.go b/bazel/aquery_test.go
index 1bd6e67..a48e083 100644
--- a/bazel/aquery_test.go
+++ b/bazel/aquery_test.go
@@ -393,9 +393,233 @@
 	assertError(t, err, "undefined path fragment id 3")
 }
 
+func TestTransitiveInputDepsets(t *testing.T) {
+	// The input aquery for this test comes from a proof-of-concept starlark rule which registers
+	// a single action with many inputs given via a deep depset.
+	const inputString = `
+{
+  "artifacts": [{
+    "id": 1,
+    "pathFragmentId": 1
+  }, {
+    "id": 2,
+    "pathFragmentId": 7
+  }, {
+    "id": 3,
+    "pathFragmentId": 8
+  }, {
+    "id": 4,
+    "pathFragmentId": 9
+  }, {
+    "id": 5,
+    "pathFragmentId": 10
+  }, {
+    "id": 6,
+    "pathFragmentId": 11
+  }, {
+    "id": 7,
+    "pathFragmentId": 12
+  }, {
+    "id": 8,
+    "pathFragmentId": 13
+  }, {
+    "id": 9,
+    "pathFragmentId": 14
+  }, {
+    "id": 10,
+    "pathFragmentId": 15
+  }, {
+    "id": 11,
+    "pathFragmentId": 16
+  }, {
+    "id": 12,
+    "pathFragmentId": 17
+  }, {
+    "id": 13,
+    "pathFragmentId": 18
+  }, {
+    "id": 14,
+    "pathFragmentId": 19
+  }, {
+    "id": 15,
+    "pathFragmentId": 20
+  }, {
+    "id": 16,
+    "pathFragmentId": 21
+  }, {
+    "id": 17,
+    "pathFragmentId": 22
+  }, {
+    "id": 18,
+    "pathFragmentId": 23
+  }, {
+    "id": 19,
+    "pathFragmentId": 24
+  }, {
+    "id": 20,
+    "pathFragmentId": 25
+  }, {
+    "id": 21,
+    "pathFragmentId": 26
+  }],
+  "actions": [{
+    "targetId": 1,
+    "actionKey": "3b826d17fadbbbcd8313e456b90ec47c078c438088891dd45b4adbcd8889dc50",
+    "mnemonic": "Action",
+    "configurationId": 1,
+    "arguments": ["/bin/bash", "-c", "touch bazel-out/sourceroot/k8-fastbuild/bin/testpkg/test_out"],
+    "inputDepSetIds": [1],
+    "outputIds": [21],
+    "primaryOutputId": 21
+  }],
+  "depSetOfFiles": [{
+    "id": 3,
+    "directArtifactIds": [1, 2, 3, 4, 5]
+  }, {
+    "id": 4,
+    "directArtifactIds": [6, 7, 8, 9, 10]
+  }, {
+    "id": 2,
+    "transitiveDepSetIds": [3, 4],
+    "directArtifactIds": [11, 12, 13, 14, 15]
+  }, {
+    "id": 5,
+    "directArtifactIds": [16, 17, 18, 19]
+  }, {
+    "id": 1,
+    "transitiveDepSetIds": [2, 5],
+    "directArtifactIds": [20]
+  }],
+  "pathFragments": [{
+    "id": 6,
+    "label": "bazel-out"
+  }, {
+    "id": 5,
+    "label": "sourceroot",
+    "parentId": 6
+  }, {
+    "id": 4,
+    "label": "k8-fastbuild",
+    "parentId": 5
+  }, {
+    "id": 3,
+    "label": "bin",
+    "parentId": 4
+  }, {
+    "id": 2,
+    "label": "testpkg",
+    "parentId": 3
+  }, {
+    "id": 1,
+    "label": "test_1",
+    "parentId": 2
+  }, {
+    "id": 7,
+    "label": "test_2",
+    "parentId": 2
+  }, {
+    "id": 8,
+    "label": "test_3",
+    "parentId": 2
+  }, {
+    "id": 9,
+    "label": "test_4",
+    "parentId": 2
+  }, {
+    "id": 10,
+    "label": "test_5",
+    "parentId": 2
+  }, {
+    "id": 11,
+    "label": "test_6",
+    "parentId": 2
+  }, {
+    "id": 12,
+    "label": "test_7",
+    "parentId": 2
+  }, {
+    "id": 13,
+    "label": "test_8",
+    "parentId": 2
+  }, {
+    "id": 14,
+    "label": "test_9",
+    "parentId": 2
+  }, {
+    "id": 15,
+    "label": "test_10",
+    "parentId": 2
+  }, {
+    "id": 16,
+    "label": "test_11",
+    "parentId": 2
+  }, {
+    "id": 17,
+    "label": "test_12",
+    "parentId": 2
+  }, {
+    "id": 18,
+    "label": "test_13",
+    "parentId": 2
+  }, {
+    "id": 19,
+    "label": "test_14",
+    "parentId": 2
+  }, {
+    "id": 20,
+    "label": "test_15",
+    "parentId": 2
+  }, {
+    "id": 21,
+    "label": "test_16",
+    "parentId": 2
+  }, {
+    "id": 22,
+    "label": "test_17",
+    "parentId": 2
+  }, {
+    "id": 23,
+    "label": "test_18",
+    "parentId": 2
+  }, {
+    "id": 24,
+    "label": "test_19",
+    "parentId": 2
+  }, {
+    "id": 25,
+    "label": "test_root",
+    "parentId": 2
+  }, {
+    "id": 26,
+    "label": "test_out",
+    "parentId": 2
+  }]
+}`
+
+	actualbuildStatements, _ := AqueryBuildStatements([]byte(inputString))
+	// Inputs for the action are test_{i} from 1 to 20, and test_root. These inputs
+	// are given via a deep depset, but the depset is flattened when returned as a
+	// BuildStatement slice.
+	inputPaths := []string{"bazel-out/sourceroot/k8-fastbuild/bin/testpkg/test_root"}
+	for i := 1; i < 20; i++ {
+		inputPaths = append(inputPaths, fmt.Sprintf("bazel-out/sourceroot/k8-fastbuild/bin/testpkg/test_%d", i))
+	}
+	expectedBuildStatements := []BuildStatement{
+		BuildStatement{
+			Command:     "/bin/bash -c touch bazel-out/sourceroot/k8-fastbuild/bin/testpkg/test_out",
+			OutputPaths: []string{"bazel-out/sourceroot/k8-fastbuild/bin/testpkg/test_out"},
+			InputPaths:  inputPaths,
+			Mnemonic:    "Action",
+		},
+	}
+	assertBuildStatements(t, expectedBuildStatements, actualbuildStatements)
+}
+
 func assertError(t *testing.T, err error, expected string) {
-	if err == nil || err.Error() != expected {
-		t.Errorf("expected error '%s', but got: %s", expected, err)
+	if err == nil {
+		t.Errorf("expected error '%s', but got no error", expected)
+	} else if err.Error() != expected {
+		t.Errorf("expected error '%s', but got: %s", expected, err.Error())
 	}
 }
 
diff --git a/bazel/properties.go b/bazel/properties.go
index ac0047b..79956e1 100644
--- a/bazel/properties.go
+++ b/bazel/properties.go
@@ -31,4 +31,7 @@
 type BazelTargetModuleProperties struct {
 	// The Bazel rule class for this target.
 	Rule_class string
+
+	// The target label for the bzl file containing the definition of the rule class.
+	Bzl_load_location string
 }
diff --git a/bp2build/Android.bp b/bp2build/Android.bp
index 8007574..2bbe4b5 100644
--- a/bp2build/Android.bp
+++ b/bp2build/Android.bp
@@ -11,6 +11,7 @@
     deps: [
         "soong-android",
         "soong-bazel",
+        "soong-genrule",
     ],
     testSrcs: [
         "build_conversion_test.go",
diff --git a/bp2build/androidbp_to_build_templates.go b/bp2build/androidbp_to_build_templates.go
index 9bac86b..5fed4fa 100644
--- a/bp2build/androidbp_to_build_templates.go
+++ b/bp2build/androidbp_to_build_templates.go
@@ -25,10 +25,10 @@
 	// for expanding more attributes.
 	soongModuleTarget = `soong_module(
     name = "%s",
-    module_name = "%s",
-    module_type = "%s",
-    module_variant = "%s",
-    module_deps = %s,
+    soong_module_name = "%s",
+    soong_module_type = "%s",
+    soong_module_variant = "%s",
+    soong_module_deps = %s,
 %s)`
 
 	bazelTarget = `%s(
@@ -38,7 +38,7 @@
 	// A simple provider to mark and differentiate Soong module rule shims from
 	// regular Bazel rules. Every Soong module rule shim returns a
 	// SoongModuleInfo provider, and can only depend on rules returning
-	// SoongModuleInfo in the `module_deps` attribute.
+	// SoongModuleInfo in the `soong_module_deps` attribute.
 	providersBzl = `SoongModuleInfo = provider(
     fields = {
         "name": "Name of module",
@@ -57,19 +57,19 @@
 def _generic_soong_module_impl(ctx):
     return [
         SoongModuleInfo(
-            name = ctx.attr.module_name,
-            type = ctx.attr.module_type,
-            variant = ctx.attr.module_variant,
+            name = ctx.attr.soong_module_name,
+            type = ctx.attr.soong_module_type,
+            variant = ctx.attr.soong_module_variant,
         ),
     ]
 
 generic_soong_module = rule(
     implementation = _generic_soong_module_impl,
     attrs = {
-        "module_name": attr.string(mandatory = True),
-        "module_type": attr.string(mandatory = True),
-        "module_variant": attr.string(),
-        "module_deps": attr.label_list(providers = [SoongModuleInfo]),
+        "soong_module_name": attr.string(mandatory = True),
+        "soong_module_type": attr.string(mandatory = True),
+        "soong_module_variant": attr.string(),
+        "soong_module_deps": attr.label_list(providers = [SoongModuleInfo]),
     },
 )
 
@@ -89,20 +89,20 @@
     else:
         return False
 
-# soong_module is a macro that supports arbitrary kwargs, and uses module_type to
+# soong_module is a macro that supports arbitrary kwargs, and uses soong_module_type to
 # expand to the right underlying shim.
-def soong_module(name, module_type, **kwargs):
-    soong_module_rule = soong_module_rule_map.get(module_type)
+def soong_module(name, soong_module_type, **kwargs):
+    soong_module_rule = soong_module_rule_map.get(soong_module_type)
 
     if soong_module_rule == None:
         # This module type does not have an existing rule to map to, so use the
         # generic_soong_module rule instead.
         generic_soong_module(
             name = name,
-            module_type = module_type,
-            module_name = kwargs.pop("module_name", ""),
-            module_variant = kwargs.pop("module_variant", ""),
-            module_deps = kwargs.pop("module_deps", []),
+            soong_module_type = soong_module_type,
+            soong_module_name = kwargs.pop("soong_module_name", ""),
+            soong_module_variant = kwargs.pop("soong_module_variant", ""),
+            soong_module_deps = kwargs.pop("soong_module_deps", []),
         )
     else:
         supported_kwargs = dict()
diff --git a/bp2build/bp2build.go b/bp2build/bp2build.go
index 75b6097..a414f04 100644
--- a/bp2build/bp2build.go
+++ b/bp2build/bp2build.go
@@ -28,9 +28,9 @@
 
 	ruleShims := CreateRuleShims(android.ModuleTypeFactories())
 
-	buildToTargets := GenerateSoongModuleTargets(ctx.Context(), true)
+	buildToTargets := GenerateSoongModuleTargets(ctx.Context(), ctx.mode)
 
-	filesToWrite := CreateBazelFiles(ruleShims, buildToTargets, true)
+	filesToWrite := CreateBazelFiles(ruleShims, buildToTargets, ctx.mode)
 	for _, f := range filesToWrite {
 		if err := writeFile(outputDir, ctx, f); err != nil {
 			fmt.Errorf("Failed to write %q (dir %q) due to %q", f.Basename, f.Dir, err)
diff --git a/bp2build/build_conversion.go b/bp2build/build_conversion.go
index da2fb7f..1af1d60 100644
--- a/bp2build/build_conversion.go
+++ b/bp2build/build_conversion.go
@@ -18,6 +18,7 @@
 	"android/soong/android"
 	"fmt"
 	"reflect"
+	"strconv"
 	"strings"
 
 	"github.com/google/blueprint"
@@ -29,8 +30,62 @@
 }
 
 type BazelTarget struct {
-	name    string
-	content string
+	name            string
+	content         string
+	ruleClass       string
+	bzlLoadLocation string
+}
+
+// IsLoadedFromStarlark determines if the BazelTarget's rule class is loaded from a .bzl file,
+// as opposed to a native rule built into Bazel.
+func (t BazelTarget) IsLoadedFromStarlark() bool {
+	return t.bzlLoadLocation != ""
+}
+
+// BazelTargets is a typedef for a slice of BazelTarget objects.
+type BazelTargets []BazelTarget
+
+// String returns the string representation of BazelTargets, without load
+// statements (use LoadStatements for that), since the targets are usually not
+// adjacent to the load statements at the top of the BUILD file.
+func (targets BazelTargets) String() string {
+	var res string
+	for i, target := range targets {
+		res += target.content
+		if i != len(targets)-1 {
+			res += "\n\n"
+		}
+	}
+	return res
+}
+
+// LoadStatements return the string representation of the sorted and deduplicated
+// Starlark rule load statements needed by a group of BazelTargets.
+func (targets BazelTargets) LoadStatements() string {
+	bzlToLoadedSymbols := map[string][]string{}
+	for _, target := range targets {
+		if target.IsLoadedFromStarlark() {
+			bzlToLoadedSymbols[target.bzlLoadLocation] =
+				append(bzlToLoadedSymbols[target.bzlLoadLocation], target.ruleClass)
+		}
+	}
+
+	var loadStatements []string
+	for bzl, ruleClasses := range bzlToLoadedSymbols {
+		loadStatement := "load(\""
+		loadStatement += bzl
+		loadStatement += "\", "
+		ruleClasses = android.SortedUniqueStrings(ruleClasses)
+		for i, ruleClass := range ruleClasses {
+			loadStatement += "\"" + ruleClass + "\""
+			if i != len(ruleClasses)-1 {
+				loadStatement += ", "
+			}
+		}
+		loadStatement += ")"
+		loadStatements = append(loadStatements, loadStatement)
+	}
+	return strings.Join(android.SortedUniqueStrings(loadStatements), "\n")
 }
 
 type bpToBuildContext interface {
@@ -46,6 +101,36 @@
 type CodegenContext struct {
 	config  android.Config
 	context android.Context
+	mode    CodegenMode
+}
+
+// CodegenMode is an enum to differentiate code-generation modes.
+type CodegenMode int
+
+const (
+	// Bp2Build: generate BUILD files with targets buildable by Bazel directly.
+	//
+	// This mode is used for the Soong->Bazel build definition conversion.
+	Bp2Build CodegenMode = iota
+
+	// QueryView: generate BUILD files with targets representing fully mutated
+	// Soong modules, representing the fully configured Soong module graph with
+	// variants and dependency endges.
+	//
+	// This mode is used for discovering and introspecting the existing Soong
+	// module graph.
+	QueryView
+)
+
+func (mode CodegenMode) String() string {
+	switch mode {
+	case Bp2Build:
+		return "Bp2Build"
+	case QueryView:
+		return "QueryView"
+	default:
+		return fmt.Sprintf("%d", mode)
+	}
 }
 
 func (ctx CodegenContext) AddNinjaFileDeps(...string) {}
@@ -54,10 +139,11 @@
 
 // NewCodegenContext creates a wrapper context that conforms to PathContext for
 // writing BUILD files in the output directory.
-func NewCodegenContext(config android.Config, context android.Context) CodegenContext {
+func NewCodegenContext(config android.Config, context android.Context, mode CodegenMode) CodegenContext {
 	return CodegenContext{
 		context: context,
 		config:  config,
+		mode:    mode,
 	}
 }
 
@@ -73,19 +159,22 @@
 	return attributes
 }
 
-func GenerateSoongModuleTargets(ctx bpToBuildContext, bp2buildEnabled bool) map[string][]BazelTarget {
-	buildFileToTargets := make(map[string][]BazelTarget)
+func GenerateSoongModuleTargets(ctx bpToBuildContext, codegenMode CodegenMode) map[string]BazelTargets {
+	buildFileToTargets := make(map[string]BazelTargets)
 	ctx.VisitAllModules(func(m blueprint.Module) {
 		dir := ctx.ModuleDir(m)
 		var t BazelTarget
 
-		if bp2buildEnabled {
+		switch codegenMode {
+		case Bp2Build:
 			if _, ok := m.(android.BazelTargetModule); !ok {
 				return
 			}
 			t = generateBazelTarget(ctx, m)
-		} else {
+		case QueryView:
 			t = generateSoongModuleTarget(ctx, m)
+		default:
+			panic(fmt.Errorf("Unknown code-generation mode: %s", codegenMode))
 		}
 
 		buildFileToTargets[ctx.ModuleDir(m)] = append(buildFileToTargets[dir], t)
@@ -93,22 +182,44 @@
 	return buildFileToTargets
 }
 
+// Helper method to trim quotes around strings.
+func trimQuotes(s string) string {
+	if s == "" {
+		// strconv.Unquote would error out on empty strings, but this method
+		// allows them, so return the empty string directly.
+		return ""
+	}
+	ret, err := strconv.Unquote(s)
+	if err != nil {
+		// Panic the error immediately.
+		panic(fmt.Errorf("Trying to unquote '%s', but got error: %s", s, err))
+	}
+	return ret
+}
+
 func generateBazelTarget(ctx bpToBuildContext, m blueprint.Module) BazelTarget {
 	// extract the bazel attributes from the module.
 	props := getBuildProperties(ctx, m)
 
 	// extract the rule class name from the attributes. Since the string value
 	// will be string-quoted, remove the quotes here.
-	ruleClass := strings.Replace(props.Attrs["rule_class"], "\"", "", 2)
+	ruleClass := trimQuotes(props.Attrs["rule_class"])
 	// Delete it from being generated in the BUILD file.
 	delete(props.Attrs, "rule_class")
 
+	// extract the bzl_load_location, and also remove the quotes around it here.
+	bzlLoadLocation := trimQuotes(props.Attrs["bzl_load_location"])
+	// Delete it from being generated in the BUILD file.
+	delete(props.Attrs, "bzl_load_location")
+
 	// Return the Bazel target with rule class and attributes, ready to be
 	// code-generated.
 	attributes := propsToAttributes(props.Attrs)
 	targetName := targetNameForBp2Build(ctx, m)
 	return BazelTarget{
-		name: targetName,
+		name:            targetName,
+		ruleClass:       ruleClass,
+		bzlLoadLocation: bzlLoadLocation,
 		content: fmt.Sprintf(
 			bazelTarget,
 			ruleClass,
diff --git a/bp2build/build_conversion_test.go b/bp2build/build_conversion_test.go
index 2df72bd..66ed42d 100644
--- a/bp2build/build_conversion_test.go
+++ b/bp2build/build_conversion_test.go
@@ -16,6 +16,7 @@
 
 import (
 	"android/soong/android"
+	"android/soong/genrule"
 	"testing"
 )
 
@@ -31,10 +32,10 @@
 		`,
 			expectedBazelTarget: `soong_module(
     name = "foo",
-    module_name = "foo",
-    module_type = "custom",
-    module_variant = "",
-    module_deps = [
+    soong_module_name = "foo",
+    soong_module_type = "custom",
+    soong_module_variant = "",
+    soong_module_deps = [
     ],
 )`,
 		},
@@ -46,10 +47,10 @@
 		`,
 			expectedBazelTarget: `soong_module(
     name = "foo",
-    module_name = "foo",
-    module_type = "custom",
-    module_variant = "",
-    module_deps = [
+    soong_module_name = "foo",
+    soong_module_type = "custom",
+    soong_module_variant = "",
+    soong_module_deps = [
     ],
     ramdisk = True,
 )`,
@@ -62,10 +63,10 @@
 		`,
 			expectedBazelTarget: `soong_module(
     name = "foo",
-    module_name = "foo",
-    module_type = "custom",
-    module_variant = "",
-    module_deps = [
+    soong_module_name = "foo",
+    soong_module_type = "custom",
+    soong_module_variant = "",
+    soong_module_deps = [
     ],
     owner = "a_string_with\"quotes\"_and_\\backslashes\\\\",
 )`,
@@ -78,10 +79,10 @@
 		`,
 			expectedBazelTarget: `soong_module(
     name = "foo",
-    module_name = "foo",
-    module_type = "custom",
-    module_variant = "",
-    module_deps = [
+    soong_module_name = "foo",
+    soong_module_type = "custom",
+    soong_module_variant = "",
+    soong_module_deps = [
     ],
     required = [
         "bar",
@@ -96,10 +97,10 @@
 		`,
 			expectedBazelTarget: `soong_module(
     name = "foo",
-    module_name = "foo",
-    module_type = "custom",
-    module_variant = "",
-    module_deps = [
+    soong_module_name = "foo",
+    soong_module_type = "custom",
+    soong_module_variant = "",
+    soong_module_deps = [
     ],
     target_required = [
         "qux",
@@ -124,10 +125,10 @@
 		`,
 			expectedBazelTarget: `soong_module(
     name = "foo",
-    module_name = "foo",
-    module_type = "custom",
-    module_variant = "",
-    module_deps = [
+    soong_module_name = "foo",
+    soong_module_type = "custom",
+    soong_module_variant = "",
+    soong_module_deps = [
     ],
     dist = {
         "tag": ".foo",
@@ -162,10 +163,10 @@
 		`,
 			expectedBazelTarget: `soong_module(
     name = "foo",
-    module_name = "foo",
-    module_type = "custom",
-    module_variant = "",
-    module_deps = [
+    soong_module_name = "foo",
+    soong_module_type = "custom",
+    soong_module_variant = "",
+    soong_module_deps = [
     ],
     dists = [
         {
@@ -200,9 +201,9 @@
 		_, errs = ctx.PrepareBuildActions(config)
 		android.FailIfErrored(t, errs)
 
-		bazelTargets := GenerateSoongModuleTargets(ctx.Context.Context, false)[dir]
-		if g, w := len(bazelTargets), 1; g != w {
-			t.Fatalf("Expected %d bazel target, got %d", w, g)
+		bazelTargets := GenerateSoongModuleTargets(ctx.Context.Context, QueryView)[dir]
+		if actualCount, expectedCount := len(bazelTargets), 1; actualCount != expectedCount {
+			t.Fatalf("Expected %d bazel target, got %d", expectedCount, actualCount)
 		}
 
 		actualBazelTarget := bazelTargets[0]
@@ -251,9 +252,9 @@
 		_, errs = ctx.ResolveDependencies(config)
 		android.FailIfErrored(t, errs)
 
-		bazelTargets := GenerateSoongModuleTargets(ctx.Context.Context, true)[dir]
-		if g, w := len(bazelTargets), 1; g != w {
-			t.Fatalf("Expected %d bazel target, got %d", w, g)
+		bazelTargets := GenerateSoongModuleTargets(ctx.Context.Context, Bp2Build)[dir]
+		if actualCount, expectedCount := len(bazelTargets), 1; actualCount != expectedCount {
+			t.Fatalf("Expected %d bazel target, got %d", expectedCount, actualCount)
 		}
 
 		actualBazelTarget := bazelTargets[0]
@@ -267,16 +268,185 @@
 	}
 }
 
-func TestModuleTypeBp2Build(t *testing.T) {
+func TestLoadStatements(t *testing.T) {
 	testCases := []struct {
-		moduleTypeUnderTest        string
-		moduleTypeUnderTestFactory android.ModuleFactory
-		bp                         string
-		expectedBazelTarget        string
+		bazelTargets           BazelTargets
+		expectedLoadStatements string
 	}{
 		{
-			moduleTypeUnderTest:        "filegroup",
-			moduleTypeUnderTestFactory: android.FileGroupFactory,
+			bazelTargets: BazelTargets{
+				BazelTarget{
+					name:            "foo",
+					ruleClass:       "cc_library",
+					bzlLoadLocation: "//build/bazel/rules:cc.bzl",
+				},
+			},
+			expectedLoadStatements: `load("//build/bazel/rules:cc.bzl", "cc_library")`,
+		},
+		{
+			bazelTargets: BazelTargets{
+				BazelTarget{
+					name:            "foo",
+					ruleClass:       "cc_library",
+					bzlLoadLocation: "//build/bazel/rules:cc.bzl",
+				},
+				BazelTarget{
+					name:            "bar",
+					ruleClass:       "cc_library",
+					bzlLoadLocation: "//build/bazel/rules:cc.bzl",
+				},
+			},
+			expectedLoadStatements: `load("//build/bazel/rules:cc.bzl", "cc_library")`,
+		},
+		{
+			bazelTargets: BazelTargets{
+				BazelTarget{
+					name:            "foo",
+					ruleClass:       "cc_library",
+					bzlLoadLocation: "//build/bazel/rules:cc.bzl",
+				},
+				BazelTarget{
+					name:            "bar",
+					ruleClass:       "cc_binary",
+					bzlLoadLocation: "//build/bazel/rules:cc.bzl",
+				},
+			},
+			expectedLoadStatements: `load("//build/bazel/rules:cc.bzl", "cc_binary", "cc_library")`,
+		},
+		{
+			bazelTargets: BazelTargets{
+				BazelTarget{
+					name:            "foo",
+					ruleClass:       "cc_library",
+					bzlLoadLocation: "//build/bazel/rules:cc.bzl",
+				},
+				BazelTarget{
+					name:            "bar",
+					ruleClass:       "cc_binary",
+					bzlLoadLocation: "//build/bazel/rules:cc.bzl",
+				},
+				BazelTarget{
+					name:            "baz",
+					ruleClass:       "java_binary",
+					bzlLoadLocation: "//build/bazel/rules:java.bzl",
+				},
+			},
+			expectedLoadStatements: `load("//build/bazel/rules:cc.bzl", "cc_binary", "cc_library")
+load("//build/bazel/rules:java.bzl", "java_binary")`,
+		},
+		{
+			bazelTargets: BazelTargets{
+				BazelTarget{
+					name:            "foo",
+					ruleClass:       "cc_binary",
+					bzlLoadLocation: "//build/bazel/rules:cc.bzl",
+				},
+				BazelTarget{
+					name:            "bar",
+					ruleClass:       "java_binary",
+					bzlLoadLocation: "//build/bazel/rules:java.bzl",
+				},
+				BazelTarget{
+					name:      "baz",
+					ruleClass: "genrule",
+					// Note: no bzlLoadLocation for native rules
+				},
+			},
+			expectedLoadStatements: `load("//build/bazel/rules:cc.bzl", "cc_binary")
+load("//build/bazel/rules:java.bzl", "java_binary")`,
+		},
+	}
+
+	for _, testCase := range testCases {
+		actual := testCase.bazelTargets.LoadStatements()
+		expected := testCase.expectedLoadStatements
+		if actual != expected {
+			t.Fatalf("Expected load statements to be %s, got %s", expected, actual)
+		}
+	}
+
+}
+
+func TestGenerateBazelTargetModules_OneToMany_LoadedFromStarlark(t *testing.T) {
+	testCases := []struct {
+		bp                       string
+		expectedBazelTarget      string
+		expectedBazelTargetCount int
+		expectedLoadStatements   string
+	}{
+		{
+			bp: `custom {
+    name: "bar",
+}`,
+			expectedBazelTarget: `my_library(
+    name = "bar",
+)
+
+my_proto_library(
+    name = "bar_my_proto_library_deps",
+)
+
+proto_library(
+    name = "bar_proto_library_deps",
+)`,
+			expectedBazelTargetCount: 3,
+			expectedLoadStatements: `load("//build/bazel/rules:proto.bzl", "my_proto_library", "proto_library")
+load("//build/bazel/rules:rules.bzl", "my_library")`,
+		},
+	}
+
+	dir := "."
+	for _, testCase := range testCases {
+		config := android.TestConfig(buildDir, nil, testCase.bp, nil)
+		ctx := android.NewTestContext(config)
+		ctx.RegisterModuleType("custom", customModuleFactory)
+		ctx.RegisterBp2BuildMutator("custom_starlark", customBp2BuildMutatorFromStarlark)
+		ctx.RegisterForBazelConversion()
+
+		_, errs := ctx.ParseFileList(dir, []string{"Android.bp"})
+		android.FailIfErrored(t, errs)
+		_, errs = ctx.ResolveDependencies(config)
+		android.FailIfErrored(t, errs)
+
+		bazelTargets := GenerateSoongModuleTargets(ctx.Context.Context, Bp2Build)[dir]
+		if actualCount := len(bazelTargets); actualCount != testCase.expectedBazelTargetCount {
+			t.Fatalf("Expected %d bazel target, got %d", testCase.expectedBazelTargetCount, actualCount)
+		}
+
+		actualBazelTargets := bazelTargets.String()
+		if actualBazelTargets != testCase.expectedBazelTarget {
+			t.Errorf(
+				"Expected generated Bazel target to be '%s', got '%s'",
+				testCase.expectedBazelTarget,
+				actualBazelTargets,
+			)
+		}
+
+		actualLoadStatements := bazelTargets.LoadStatements()
+		if actualLoadStatements != testCase.expectedLoadStatements {
+			t.Errorf(
+				"Expected generated load statements to be '%s', got '%s'",
+				testCase.expectedLoadStatements,
+				actualLoadStatements,
+			)
+		}
+	}
+}
+
+func TestModuleTypeBp2Build(t *testing.T) {
+	testCases := []struct {
+		moduleTypeUnderTest                string
+		moduleTypeUnderTestFactory         android.ModuleFactory
+		moduleTypeUnderTestBp2BuildMutator func(android.TopDownMutatorContext)
+		bp                                 string
+		expectedBazelTarget                string
+		description                        string
+	}{
+		{
+			description:                        "filegroup with no srcs",
+			moduleTypeUnderTest:                "filegroup",
+			moduleTypeUnderTestFactory:         android.FileGroupFactory,
+			moduleTypeUnderTestBp2BuildMutator: android.FilegroupBp2Build,
 			bp: `filegroup {
 	name: "foo",
 	srcs: [],
@@ -288,8 +458,10 @@
 )`,
 		},
 		{
-			moduleTypeUnderTest:        "filegroup",
-			moduleTypeUnderTestFactory: android.FileGroupFactory,
+			description:                        "filegroup with srcs",
+			moduleTypeUnderTest:                "filegroup",
+			moduleTypeUnderTestFactory:         android.FileGroupFactory,
+			moduleTypeUnderTestBp2BuildMutator: android.FilegroupBp2Build,
 			bp: `filegroup {
 	name: "foo",
 	srcs: ["a", "b"],
@@ -302,6 +474,134 @@
     ],
 )`,
 		},
+		{
+			description:                        "genrule with command line variable replacements",
+			moduleTypeUnderTest:                "genrule",
+			moduleTypeUnderTestFactory:         genrule.GenRuleFactory,
+			moduleTypeUnderTestBp2BuildMutator: genrule.GenruleBp2Build,
+			bp: `genrule {
+    name: "foo",
+    out: ["foo.out"],
+    srcs: ["foo.in"],
+    tools: [":foo.tool"],
+    cmd: "$(location :foo.tool) --genDir=$(genDir) arg $(in) $(out)",
+}`,
+			expectedBazelTarget: `genrule(
+    name = "foo",
+    cmd = "$(location :foo.tool) --genDir=$(GENDIR) arg $(SRCS) $(OUTS)",
+    outs = [
+        "foo.out",
+    ],
+    srcs = [
+        "foo.in",
+    ],
+    tools = [
+        ":foo.tool",
+    ],
+)`,
+		},
+		{
+			description:                        "genrule using $(locations :label)",
+			moduleTypeUnderTest:                "genrule",
+			moduleTypeUnderTestFactory:         genrule.GenRuleFactory,
+			moduleTypeUnderTestBp2BuildMutator: genrule.GenruleBp2Build,
+			bp: `genrule {
+    name: "foo",
+    out: ["foo.out"],
+    srcs: ["foo.in"],
+    tools: [":foo.tools"],
+    cmd: "$(locations :foo.tools) -s $(out) $(in)",
+}`,
+			expectedBazelTarget: `genrule(
+    name = "foo",
+    cmd = "$(locations :foo.tools) -s $(OUTS) $(SRCS)",
+    outs = [
+        "foo.out",
+    ],
+    srcs = [
+        "foo.in",
+    ],
+    tools = [
+        ":foo.tools",
+    ],
+)`,
+		},
+		{
+			description:                        "genrule using $(location) label should substitute first tool label automatically",
+			moduleTypeUnderTest:                "genrule",
+			moduleTypeUnderTestFactory:         genrule.GenRuleFactory,
+			moduleTypeUnderTestBp2BuildMutator: genrule.GenruleBp2Build,
+			bp: `genrule {
+    name: "foo",
+    out: ["foo.out"],
+    srcs: ["foo.in"],
+    tool_files: [":foo.tool", ":other.tool"],
+    cmd: "$(location) -s $(out) $(in)",
+}`,
+			expectedBazelTarget: `genrule(
+    name = "foo",
+    cmd = "$(location :foo.tool) -s $(OUTS) $(SRCS)",
+    outs = [
+        "foo.out",
+    ],
+    srcs = [
+        "foo.in",
+    ],
+    tools = [
+        ":foo.tool",
+        ":other.tool",
+    ],
+)`,
+		},
+		{
+			description:                        "genrule using $(locations) label should substitute first tool label automatically",
+			moduleTypeUnderTest:                "genrule",
+			moduleTypeUnderTestFactory:         genrule.GenRuleFactory,
+			moduleTypeUnderTestBp2BuildMutator: genrule.GenruleBp2Build,
+			bp: `genrule {
+    name: "foo",
+    out: ["foo.out"],
+    srcs: ["foo.in"],
+    tools: [":foo.tool", ":other.tool"],
+    cmd: "$(locations) -s $(out) $(in)",
+}`,
+			expectedBazelTarget: `genrule(
+    name = "foo",
+    cmd = "$(locations :foo.tool) -s $(OUTS) $(SRCS)",
+    outs = [
+        "foo.out",
+    ],
+    srcs = [
+        "foo.in",
+    ],
+    tools = [
+        ":foo.tool",
+        ":other.tool",
+    ],
+)`,
+		},
+		{
+			description:                        "genrule without tools or tool_files can convert successfully",
+			moduleTypeUnderTest:                "genrule",
+			moduleTypeUnderTestFactory:         genrule.GenRuleFactory,
+			moduleTypeUnderTestBp2BuildMutator: genrule.GenruleBp2Build,
+			bp: `genrule {
+    name: "foo",
+    out: ["foo.out"],
+    srcs: ["foo.in"],
+    cmd: "cp $(in) $(out)",
+}`,
+			expectedBazelTarget: `genrule(
+    name = "foo",
+    cmd = "cp $(SRCS) $(OUTS)",
+    outs = [
+        "foo.out",
+    ],
+    srcs = [
+        "foo.in",
+    ],
+)`,
+		},
 	}
 
 	dir := "."
@@ -309,6 +609,7 @@
 		config := android.TestConfig(buildDir, nil, testCase.bp, nil)
 		ctx := android.NewTestContext(config)
 		ctx.RegisterModuleType(testCase.moduleTypeUnderTest, testCase.moduleTypeUnderTestFactory)
+		ctx.RegisterBp2BuildMutator(testCase.moduleTypeUnderTest, testCase.moduleTypeUnderTestBp2BuildMutator)
 		ctx.RegisterForBazelConversion()
 
 		_, errs := ctx.ParseFileList(dir, []string{"Android.bp"})
@@ -316,15 +617,16 @@
 		_, errs = ctx.ResolveDependencies(config)
 		android.FailIfErrored(t, errs)
 
-		bazelTargets := GenerateSoongModuleTargets(ctx.Context.Context, true)[dir]
-		if g, w := len(bazelTargets), 1; g != w {
-			t.Fatalf("Expected %d bazel target, got %d", w, g)
+		bazelTargets := GenerateSoongModuleTargets(ctx.Context.Context, Bp2Build)[dir]
+		if actualCount, expectedCount := len(bazelTargets), 1; actualCount != expectedCount {
+			t.Fatalf("%s: Expected %d bazel target, got %d", testCase.description, expectedCount, actualCount)
 		}
 
 		actualBazelTarget := bazelTargets[0]
 		if actualBazelTarget.content != testCase.expectedBazelTarget {
 			t.Errorf(
-				"Expected generated Bazel target to be '%s', got '%s'",
+				"%s: Expected generated Bazel target to be '%s', got '%s'",
+				testCase.description,
 				testCase.expectedBazelTarget,
 				actualBazelTarget.content,
 			)
diff --git a/bp2build/bzl_conversion.go b/bp2build/bzl_conversion.go
index 04c4542..f2f6b01 100644
--- a/bp2build/bzl_conversion.go
+++ b/bp2build/bzl_conversion.go
@@ -109,9 +109,9 @@
 		factoryName := runtime.FuncForPC(reflect.ValueOf(factory).Pointer()).Name()
 		pkg := strings.Split(factoryName, ".")[0]
 		attrs := `{
-        "module_name": attr.string(mandatory = True),
-        "module_variant": attr.string(),
-        "module_deps": attr.label_list(providers = [SoongModuleInfo]),
+        "soong_module_name": attr.string(mandatory = True),
+        "soong_module_variant": attr.string(),
+        "soong_module_deps": attr.label_list(providers = [SoongModuleInfo]),
 `
 		attrs += getAttributes(factory)
 		attrs += "    },"
diff --git a/bp2build/bzl_conversion_test.go b/bp2build/bzl_conversion_test.go
index 01c7271..f2a4058 100644
--- a/bp2build/bzl_conversion_test.go
+++ b/bp2build/bzl_conversion_test.go
@@ -83,9 +83,9 @@
 custom = rule(
     implementation = _custom_impl,
     attrs = {
-        "module_name": attr.string(mandatory = True),
-        "module_variant": attr.string(),
-        "module_deps": attr.label_list(providers = [SoongModuleInfo]),
+        "soong_module_name": attr.string(mandatory = True),
+        "soong_module_variant": attr.string(),
+        "soong_module_deps": attr.label_list(providers = [SoongModuleInfo]),
         "bool_prop": attr.bool(),
         "bool_ptr_prop": attr.bool(),
         "int64_ptr_prop": attr.int(),
@@ -107,9 +107,9 @@
 custom_defaults = rule(
     implementation = _custom_defaults_impl,
     attrs = {
-        "module_name": attr.string(mandatory = True),
-        "module_variant": attr.string(),
-        "module_deps": attr.label_list(providers = [SoongModuleInfo]),
+        "soong_module_name": attr.string(mandatory = True),
+        "soong_module_variant": attr.string(),
+        "soong_module_deps": attr.label_list(providers = [SoongModuleInfo]),
         "bool_prop": attr.bool(),
         "bool_ptr_prop": attr.bool(),
         "int64_ptr_prop": attr.int(),
@@ -131,9 +131,9 @@
 custom_test_ = rule(
     implementation = _custom_test__impl,
     attrs = {
-        "module_name": attr.string(mandatory = True),
-        "module_variant": attr.string(),
-        "module_deps": attr.label_list(providers = [SoongModuleInfo]),
+        "soong_module_name": attr.string(mandatory = True),
+        "soong_module_variant": attr.string(),
+        "soong_module_deps": attr.label_list(providers = [SoongModuleInfo]),
         "bool_prop": attr.bool(),
         "bool_ptr_prop": attr.bool(),
         "int64_ptr_prop": attr.int(),
@@ -172,7 +172,7 @@
 			content: "irrelevant",
 		},
 	}
-	files := CreateBazelFiles(ruleShims, make(map[string][]BazelTarget), false)
+	files := CreateBazelFiles(ruleShims, make(map[string]BazelTargets), QueryView)
 
 	var actualSoongModuleBzl BazelFile
 	for _, f := range files {
diff --git a/bp2build/conversion.go b/bp2build/conversion.go
index cccc474..62cd8d4 100644
--- a/bp2build/conversion.go
+++ b/bp2build/conversion.go
@@ -17,8 +17,8 @@
 
 func CreateBazelFiles(
 	ruleShims map[string]RuleShim,
-	buildToTargets map[string][]BazelTarget,
-	bp2buildEnabled bool) []BazelFile {
+	buildToTargets map[string]BazelTargets,
+	mode CodegenMode) []BazelFile {
 	files := make([]BazelFile, 0, len(ruleShims)+len(buildToTargets)+numAdditionalFiles)
 
 	// Write top level files: WORKSPACE and BUILD. These files are empty.
@@ -28,7 +28,7 @@
 
 	files = append(files, newFile(bazelRulesSubDir, "BUILD", ""))
 
-	if !bp2buildEnabled {
+	if mode == QueryView {
 		// These files are only used for queryview.
 		files = append(files, newFile(bazelRulesSubDir, "providers.bzl", providersBzl))
 
@@ -38,25 +38,25 @@
 		files = append(files, newFile(bazelRulesSubDir, "soong_module.bzl", generateSoongModuleBzl(ruleShims)))
 	}
 
-	files = append(files, createBuildFiles(buildToTargets, bp2buildEnabled)...)
+	files = append(files, createBuildFiles(buildToTargets, mode)...)
 
 	return files
 }
 
-func createBuildFiles(buildToTargets map[string][]BazelTarget, bp2buildEnabled bool) []BazelFile {
+func createBuildFiles(buildToTargets map[string]BazelTargets, mode CodegenMode) []BazelFile {
 	files := make([]BazelFile, 0, len(buildToTargets))
 	for _, dir := range android.SortedStringKeys(buildToTargets) {
-		content := soongModuleLoad
-		if bp2buildEnabled {
-			// No need to load soong_module for bp2build BUILD files.
-			content = ""
-		}
 		targets := buildToTargets[dir]
 		sort.Slice(targets, func(i, j int) bool { return targets[i].name < targets[j].name })
-		for _, t := range targets {
-			content += "\n\n"
-			content += t.content
+		content := soongModuleLoad
+		if mode == Bp2Build {
+			content = targets.LoadStatements()
 		}
+		if content != "" {
+			// If there are load statements, add a couple of newlines.
+			content += "\n\n"
+		}
+		content += targets.String()
 		files = append(files, newFile(dir, "BUILD.bazel", content))
 	}
 	return files
diff --git a/bp2build/conversion_test.go b/bp2build/conversion_test.go
index b40aa1b..ec5f27e 100644
--- a/bp2build/conversion_test.go
+++ b/bp2build/conversion_test.go
@@ -55,7 +55,7 @@
 }
 
 func TestCreateBazelFiles_QueryView_AddsTopLevelFiles(t *testing.T) {
-	files := CreateBazelFiles(map[string]RuleShim{}, map[string][]BazelTarget{}, false)
+	files := CreateBazelFiles(map[string]RuleShim{}, map[string]BazelTargets{}, QueryView)
 	expectedFilePaths := []filepath{
 		{
 			dir:      "",
@@ -85,7 +85,7 @@
 }
 
 func TestCreateBazelFiles_Bp2Build_AddsTopLevelFiles(t *testing.T) {
-	files := CreateBazelFiles(map[string]RuleShim{}, map[string][]BazelTarget{}, true)
+	files := CreateBazelFiles(map[string]RuleShim{}, map[string]BazelTargets{}, Bp2Build)
 	expectedFilePaths := []filepath{
 		{
 			dir:      "",
diff --git a/bp2build/testing.go b/bp2build/testing.go
index 4c31d2d..5e6481b 100644
--- a/bp2build/testing.go
+++ b/bp2build/testing.go
@@ -137,3 +137,29 @@
 		})
 	}
 }
+
+// A bp2build mutator that uses load statements and creates a 1:M mapping from
+// module to target.
+func customBp2BuildMutatorFromStarlark(ctx android.TopDownMutatorContext) {
+	if m, ok := ctx.Module().(*customModule); ok {
+		baseName := "__bp2build__" + m.Name()
+		ctx.CreateModule(customBazelModuleFactory, &customBazelModuleAttributes{
+			Name: proptools.StringPtr(baseName),
+		}, &bazel.BazelTargetModuleProperties{
+			Rule_class:        "my_library",
+			Bzl_load_location: "//build/bazel/rules:rules.bzl",
+		})
+		ctx.CreateModule(customBazelModuleFactory, &customBazelModuleAttributes{
+			Name: proptools.StringPtr(baseName + "_proto_library_deps"),
+		}, &bazel.BazelTargetModuleProperties{
+			Rule_class:        "proto_library",
+			Bzl_load_location: "//build/bazel/rules:proto.bzl",
+		})
+		ctx.CreateModule(customBazelModuleFactory, &customBazelModuleAttributes{
+			Name: proptools.StringPtr(baseName + "_my_proto_library_deps"),
+		}, &bazel.BazelTargetModuleProperties{
+			Rule_class:        "my_proto_library",
+			Bzl_load_location: "//build/bazel/rules:proto.bzl",
+		})
+	}
+}
diff --git a/cc/Android.bp b/cc/Android.bp
index 33f3db2..6ec7e0e 100644
--- a/cc/Android.bp
+++ b/cc/Android.bp
@@ -87,6 +87,7 @@
         "prebuilt_test.go",
         "proto_test.go",
         "test_data_test.go",
+        "vendor_snapshot_test.go",
     ],
     pluginFor: ["soong_build"],
 }
diff --git a/cc/cc.go b/cc/cc.go
index 8755efe..afa6bf9 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -390,6 +390,17 @@
 	// Nothing happens if BOARD_VNDK_VERSION isn't set in the BoardConfig.mk
 	Vendor_available *bool
 
+	// This is the same as the "vendor_available" except that the install path
+	// of the vendor variant is /odm or /vendor/odm.
+	// By replacing "vendor_available: true" with "odm_available: true", the
+	// module will install its vendor variant to the /odm partition or /vendor/odm.
+	// As the modules with "odm_available: true" still create the vendor variants,
+	// they can link to the other vendor modules as the vendor_available modules do.
+	// Also, the vendor modules can link to odm_available modules.
+	//
+	// It may not be used for VNDK modules.
+	Odm_available *bool
+
 	// whether this module should be allowed to be directly depended by other
 	// modules with `product_specific: true` or `product_available: true`.
 	// If set to true, an additional product variant will be built separately
diff --git a/cc/cc_test.go b/cc/cc_test.go
index d0d8759..7288cc4 100644
--- a/cc/cc_test.go
+++ b/cc/cc_test.go
@@ -1110,934 +1110,6 @@
 	`)
 }
 
-func TestVendorSnapshotCapture(t *testing.T) {
-	bp := `
-	cc_library {
-		name: "libvndk",
-		vendor_available: true,
-		product_available: true,
-		vndk: {
-			enabled: true,
-		},
-		nocrt: true,
-	}
-
-	cc_library {
-		name: "libvendor",
-		vendor: true,
-		nocrt: true,
-	}
-
-	cc_library {
-		name: "libvendor_available",
-		vendor_available: true,
-		nocrt: true,
-	}
-
-	cc_library_headers {
-		name: "libvendor_headers",
-		vendor_available: true,
-		nocrt: true,
-	}
-
-	cc_binary {
-		name: "vendor_bin",
-		vendor: true,
-		nocrt: true,
-	}
-
-	cc_binary {
-		name: "vendor_available_bin",
-		vendor_available: true,
-		nocrt: true,
-	}
-
-	toolchain_library {
-		name: "libb",
-		vendor_available: true,
-		src: "libb.a",
-	}
-
-	cc_object {
-		name: "obj",
-		vendor_available: true,
-	}
-
-	cc_library {
-		name: "libllndk",
-		llndk_stubs: "libllndk.llndk",
-	}
-
-	llndk_library {
-		name: "libllndk.llndk",
-		symbol_file: "",
-	}
-`
-	config := TestConfig(buildDir, android.Android, nil, bp, nil)
-	config.TestProductVariables.DeviceVndkVersion = StringPtr("current")
-	config.TestProductVariables.Platform_vndk_version = StringPtr("VER")
-	ctx := testCcWithConfig(t, config)
-
-	// Check Vendor snapshot output.
-
-	snapshotDir := "vendor-snapshot"
-	snapshotVariantPath := filepath.Join(buildDir, snapshotDir, "arm64")
-	snapshotSingleton := ctx.SingletonForTests("vendor-snapshot")
-
-	var jsonFiles []string
-
-	for _, arch := range [][]string{
-		[]string{"arm64", "armv8-a"},
-		[]string{"arm", "armv7-a-neon"},
-	} {
-		archType := arch[0]
-		archVariant := arch[1]
-		archDir := fmt.Sprintf("arch-%s-%s", archType, archVariant)
-
-		// For shared libraries, only non-VNDK vendor_available modules are captured
-		sharedVariant := fmt.Sprintf("android_vendor.VER_%s_%s_shared", archType, archVariant)
-		sharedDir := filepath.Join(snapshotVariantPath, archDir, "shared")
-		checkSnapshot(t, ctx, snapshotSingleton, "libvendor", "libvendor.so", sharedDir, sharedVariant)
-		checkSnapshot(t, ctx, snapshotSingleton, "libvendor_available", "libvendor_available.so", sharedDir, sharedVariant)
-		jsonFiles = append(jsonFiles,
-			filepath.Join(sharedDir, "libvendor.so.json"),
-			filepath.Join(sharedDir, "libvendor_available.so.json"))
-
-		// LLNDK modules are not captured
-		checkSnapshotExclude(t, ctx, snapshotSingleton, "libllndk", "libllndk.so", sharedDir, sharedVariant)
-
-		// For static libraries, all vendor:true and vendor_available modules (including VNDK) are captured.
-		// Also cfi variants are captured, except for prebuilts like toolchain_library
-		staticVariant := fmt.Sprintf("android_vendor.VER_%s_%s_static", archType, archVariant)
-		staticCfiVariant := fmt.Sprintf("android_vendor.VER_%s_%s_static_cfi", archType, archVariant)
-		staticDir := filepath.Join(snapshotVariantPath, archDir, "static")
-		checkSnapshot(t, ctx, snapshotSingleton, "libb", "libb.a", staticDir, staticVariant)
-		checkSnapshot(t, ctx, snapshotSingleton, "libvndk", "libvndk.a", staticDir, staticVariant)
-		checkSnapshot(t, ctx, snapshotSingleton, "libvndk", "libvndk.cfi.a", staticDir, staticCfiVariant)
-		checkSnapshot(t, ctx, snapshotSingleton, "libvendor", "libvendor.a", staticDir, staticVariant)
-		checkSnapshot(t, ctx, snapshotSingleton, "libvendor", "libvendor.cfi.a", staticDir, staticCfiVariant)
-		checkSnapshot(t, ctx, snapshotSingleton, "libvendor_available", "libvendor_available.a", staticDir, staticVariant)
-		checkSnapshot(t, ctx, snapshotSingleton, "libvendor_available", "libvendor_available.cfi.a", staticDir, staticCfiVariant)
-		jsonFiles = append(jsonFiles,
-			filepath.Join(staticDir, "libb.a.json"),
-			filepath.Join(staticDir, "libvndk.a.json"),
-			filepath.Join(staticDir, "libvndk.cfi.a.json"),
-			filepath.Join(staticDir, "libvendor.a.json"),
-			filepath.Join(staticDir, "libvendor.cfi.a.json"),
-			filepath.Join(staticDir, "libvendor_available.a.json"),
-			filepath.Join(staticDir, "libvendor_available.cfi.a.json"))
-
-		// For binary executables, all vendor:true and vendor_available modules are captured.
-		if archType == "arm64" {
-			binaryVariant := fmt.Sprintf("android_vendor.VER_%s_%s", archType, archVariant)
-			binaryDir := filepath.Join(snapshotVariantPath, archDir, "binary")
-			checkSnapshot(t, ctx, snapshotSingleton, "vendor_bin", "vendor_bin", binaryDir, binaryVariant)
-			checkSnapshot(t, ctx, snapshotSingleton, "vendor_available_bin", "vendor_available_bin", binaryDir, binaryVariant)
-			jsonFiles = append(jsonFiles,
-				filepath.Join(binaryDir, "vendor_bin.json"),
-				filepath.Join(binaryDir, "vendor_available_bin.json"))
-		}
-
-		// For header libraries, all vendor:true and vendor_available modules are captured.
-		headerDir := filepath.Join(snapshotVariantPath, archDir, "header")
-		jsonFiles = append(jsonFiles, filepath.Join(headerDir, "libvendor_headers.json"))
-
-		// For object modules, all vendor:true and vendor_available modules are captured.
-		objectVariant := fmt.Sprintf("android_vendor.VER_%s_%s", archType, archVariant)
-		objectDir := filepath.Join(snapshotVariantPath, archDir, "object")
-		checkSnapshot(t, ctx, snapshotSingleton, "obj", "obj.o", objectDir, objectVariant)
-		jsonFiles = append(jsonFiles, filepath.Join(objectDir, "obj.o.json"))
-	}
-
-	for _, jsonFile := range jsonFiles {
-		// verify all json files exist
-		if snapshotSingleton.MaybeOutput(jsonFile).Rule == nil {
-			t.Errorf("%q expected but not found", jsonFile)
-		}
-	}
-
-	// fake snapshot should have all outputs in the normal snapshot.
-	fakeSnapshotSingleton := ctx.SingletonForTests("vendor-fake-snapshot")
-	for _, output := range snapshotSingleton.AllOutputs() {
-		fakeOutput := strings.Replace(output, "/vendor-snapshot/", "/fake/vendor-snapshot/", 1)
-		if fakeSnapshotSingleton.MaybeOutput(fakeOutput).Rule == nil {
-			t.Errorf("%q expected but not found", fakeOutput)
-		}
-	}
-}
-
-func TestVendorSnapshotDirected(t *testing.T) {
-	bp := `
-	cc_library_shared {
-		name: "libvendor",
-		vendor: true,
-		nocrt: true,
-	}
-
-	cc_library_shared {
-		name: "libvendor_available",
-		vendor_available: true,
-		nocrt: true,
-	}
-
-	genrule {
-		name: "libfoo_gen",
-		cmd: "",
-		out: ["libfoo.so"],
-	}
-
-	cc_prebuilt_library_shared {
-		name: "libfoo",
-		vendor: true,
-		prefer: true,
-		srcs: [":libfoo_gen"],
-	}
-
-	cc_library_shared {
-		name: "libfoo",
-		vendor: true,
-		nocrt: true,
-	}
-`
-	config := TestConfig(buildDir, android.Android, nil, bp, nil)
-	config.TestProductVariables.DeviceVndkVersion = StringPtr("current")
-	config.TestProductVariables.Platform_vndk_version = StringPtr("VER")
-	config.TestProductVariables.DirectedVendorSnapshot = true
-	config.TestProductVariables.VendorSnapshotModules = make(map[string]bool)
-	config.TestProductVariables.VendorSnapshotModules["libvendor"] = true
-	config.TestProductVariables.VendorSnapshotModules["libfoo"] = true
-	ctx := testCcWithConfig(t, config)
-
-	// Check Vendor snapshot output.
-
-	snapshotDir := "vendor-snapshot"
-	snapshotVariantPath := filepath.Join(buildDir, snapshotDir, "arm64")
-	snapshotSingleton := ctx.SingletonForTests("vendor-snapshot")
-
-	var includeJsonFiles []string
-	var excludeJsonFiles []string
-
-	for _, arch := range [][]string{
-		[]string{"arm64", "armv8-a"},
-		[]string{"arm", "armv7-a-neon"},
-	} {
-		archType := arch[0]
-		archVariant := arch[1]
-		archDir := fmt.Sprintf("arch-%s-%s", archType, archVariant)
-
-		sharedVariant := fmt.Sprintf("android_vendor.VER_%s_%s_shared", archType, archVariant)
-		sharedDir := filepath.Join(snapshotVariantPath, archDir, "shared")
-
-		// Included modules
-		checkSnapshot(t, ctx, snapshotSingleton, "libvendor", "libvendor.so", sharedDir, sharedVariant)
-		includeJsonFiles = append(includeJsonFiles, filepath.Join(sharedDir, "libvendor.so.json"))
-		// Check that snapshot captures "prefer: true" prebuilt
-		checkSnapshot(t, ctx, snapshotSingleton, "prebuilt_libfoo", "libfoo.so", sharedDir, sharedVariant)
-		includeJsonFiles = append(includeJsonFiles, filepath.Join(sharedDir, "libfoo.so.json"))
-
-		// Excluded modules
-		checkSnapshotExclude(t, ctx, snapshotSingleton, "libvendor_available", "libvendor_available.so", sharedDir, sharedVariant)
-		excludeJsonFiles = append(excludeJsonFiles, filepath.Join(sharedDir, "libvendor_available.so.json"))
-	}
-
-	// Verify that each json file for an included module has a rule.
-	for _, jsonFile := range includeJsonFiles {
-		if snapshotSingleton.MaybeOutput(jsonFile).Rule == nil {
-			t.Errorf("include json file %q not found", jsonFile)
-		}
-	}
-
-	// Verify that each json file for an excluded module has no rule.
-	for _, jsonFile := range excludeJsonFiles {
-		if snapshotSingleton.MaybeOutput(jsonFile).Rule != nil {
-			t.Errorf("exclude json file %q found", jsonFile)
-		}
-	}
-}
-
-func TestVendorSnapshotUse(t *testing.T) {
-	frameworkBp := `
-	cc_library {
-		name: "libvndk",
-		vendor_available: true,
-		product_available: true,
-		vndk: {
-			enabled: true,
-		},
-		nocrt: true,
-		compile_multilib: "64",
-	}
-
-	cc_library {
-		name: "libvendor",
-		vendor: true,
-		nocrt: true,
-		no_libcrt: true,
-		stl: "none",
-		system_shared_libs: [],
-		compile_multilib: "64",
-	}
-
-	cc_binary {
-		name: "bin",
-		vendor: true,
-		nocrt: true,
-		no_libcrt: true,
-		stl: "none",
-		system_shared_libs: [],
-		compile_multilib: "64",
-	}
-`
-
-	vndkBp := `
-	vndk_prebuilt_shared {
-		name: "libvndk",
-		version: "BOARD",
-		target_arch: "arm64",
-		vendor_available: true,
-		product_available: true,
-		vndk: {
-			enabled: true,
-		},
-		arch: {
-			arm64: {
-				srcs: ["libvndk.so"],
-				export_include_dirs: ["include/libvndk"],
-			},
-		},
-	}
-`
-
-	vendorProprietaryBp := `
-	cc_library {
-		name: "libvendor_without_snapshot",
-		vendor: true,
-		nocrt: true,
-		no_libcrt: true,
-		stl: "none",
-		system_shared_libs: [],
-		compile_multilib: "64",
-	}
-
-	cc_library_shared {
-		name: "libclient",
-		vendor: true,
-		nocrt: true,
-		no_libcrt: true,
-		stl: "none",
-		system_shared_libs: [],
-		shared_libs: ["libvndk"],
-		static_libs: ["libvendor", "libvendor_without_snapshot"],
-		compile_multilib: "64",
-		srcs: ["client.cpp"],
-	}
-
-	cc_binary {
-		name: "bin_without_snapshot",
-		vendor: true,
-		nocrt: true,
-		no_libcrt: true,
-		stl: "none",
-		system_shared_libs: [],
-		static_libs: ["libvndk"],
-		compile_multilib: "64",
-		srcs: ["bin.cpp"],
-	}
-
-	vendor_snapshot_static {
-		name: "libvndk",
-		version: "BOARD",
-		target_arch: "arm64",
-		vendor: true,
-		arch: {
-			arm64: {
-				src: "libvndk.a",
-				export_include_dirs: ["include/libvndk"],
-			},
-		},
-	}
-
-	vendor_snapshot_shared {
-		name: "libvendor",
-		version: "BOARD",
-		target_arch: "arm64",
-		vendor: true,
-		arch: {
-			arm64: {
-				src: "libvendor.so",
-				export_include_dirs: ["include/libvendor"],
-			},
-		},
-	}
-
-	vendor_snapshot_static {
-		name: "libvendor",
-		version: "BOARD",
-		target_arch: "arm64",
-		vendor: true,
-		arch: {
-			arm64: {
-				src: "libvendor.a",
-				export_include_dirs: ["include/libvendor"],
-			},
-		},
-	}
-
-	vendor_snapshot_binary {
-		name: "bin",
-		version: "BOARD",
-		target_arch: "arm64",
-		vendor: true,
-		arch: {
-			arm64: {
-				src: "bin",
-			},
-		},
-	}
-`
-	depsBp := GatherRequiredDepsForTest(android.Android)
-
-	mockFS := map[string][]byte{
-		"deps/Android.bp":              []byte(depsBp),
-		"framework/Android.bp":         []byte(frameworkBp),
-		"vendor/Android.bp":            []byte(vendorProprietaryBp),
-		"vendor/bin":                   nil,
-		"vendor/bin.cpp":               nil,
-		"vendor/client.cpp":            nil,
-		"vendor/include/libvndk/a.h":   nil,
-		"vendor/include/libvendor/b.h": nil,
-		"vendor/libvndk.a":             nil,
-		"vendor/libvendor.a":           nil,
-		"vendor/libvendor.so":          nil,
-		"vndk/Android.bp":              []byte(vndkBp),
-		"vndk/include/libvndk/a.h":     nil,
-		"vndk/libvndk.so":              nil,
-	}
-
-	config := TestConfig(buildDir, android.Android, nil, "", mockFS)
-	config.TestProductVariables.DeviceVndkVersion = StringPtr("BOARD")
-	config.TestProductVariables.Platform_vndk_version = StringPtr("VER")
-	ctx := CreateTestContext(config)
-	ctx.Register()
-
-	_, errs := ctx.ParseFileList(".", []string{"deps/Android.bp", "framework/Android.bp", "vendor/Android.bp", "vndk/Android.bp"})
-	android.FailIfErrored(t, errs)
-	_, errs = ctx.PrepareBuildActions(config)
-	android.FailIfErrored(t, errs)
-
-	sharedVariant := "android_vendor.BOARD_arm64_armv8-a_shared"
-	staticVariant := "android_vendor.BOARD_arm64_armv8-a_static"
-	binaryVariant := "android_vendor.BOARD_arm64_armv8-a"
-
-	// libclient uses libvndk.vndk.BOARD.arm64, libvendor.vendor_static.BOARD.arm64, libvendor_without_snapshot
-	libclientCcFlags := ctx.ModuleForTests("libclient", sharedVariant).Rule("cc").Args["cFlags"]
-	for _, includeFlags := range []string{
-		"-Ivndk/include/libvndk",     // libvndk
-		"-Ivendor/include/libvendor", // libvendor
-	} {
-		if !strings.Contains(libclientCcFlags, includeFlags) {
-			t.Errorf("flags for libclient must contain %#v, but was %#v.",
-				includeFlags, libclientCcFlags)
-		}
-	}
-
-	libclientLdFlags := ctx.ModuleForTests("libclient", sharedVariant).Rule("ld").Args["libFlags"]
-	for _, input := range [][]string{
-		[]string{sharedVariant, "libvndk.vndk.BOARD.arm64"},
-		[]string{staticVariant, "libvendor.vendor_static.BOARD.arm64"},
-		[]string{staticVariant, "libvendor_without_snapshot"},
-	} {
-		outputPaths := getOutputPaths(ctx, input[0] /* variant */, []string{input[1]} /* module name */)
-		if !strings.Contains(libclientLdFlags, outputPaths[0].String()) {
-			t.Errorf("libflags for libclient must contain %#v, but was %#v", outputPaths[0], libclientLdFlags)
-		}
-	}
-
-	// bin_without_snapshot uses libvndk.vendor_static.BOARD.arm64
-	binWithoutSnapshotCcFlags := ctx.ModuleForTests("bin_without_snapshot", binaryVariant).Rule("cc").Args["cFlags"]
-	if !strings.Contains(binWithoutSnapshotCcFlags, "-Ivendor/include/libvndk") {
-		t.Errorf("flags for bin_without_snapshot must contain %#v, but was %#v.",
-			"-Ivendor/include/libvndk", binWithoutSnapshotCcFlags)
-	}
-
-	binWithoutSnapshotLdFlags := ctx.ModuleForTests("bin_without_snapshot", binaryVariant).Rule("ld").Args["libFlags"]
-	libVndkStaticOutputPaths := getOutputPaths(ctx, staticVariant, []string{"libvndk.vendor_static.BOARD.arm64"})
-	if !strings.Contains(binWithoutSnapshotLdFlags, libVndkStaticOutputPaths[0].String()) {
-		t.Errorf("libflags for bin_without_snapshot must contain %#v, but was %#v",
-			libVndkStaticOutputPaths[0], binWithoutSnapshotLdFlags)
-	}
-
-	// libvendor.so is installed by libvendor.vendor_shared.BOARD.arm64
-	ctx.ModuleForTests("libvendor.vendor_shared.BOARD.arm64", sharedVariant).Output("libvendor.so")
-
-	// libvendor_without_snapshot.so is installed by libvendor_without_snapshot
-	ctx.ModuleForTests("libvendor_without_snapshot", sharedVariant).Output("libvendor_without_snapshot.so")
-
-	// bin is installed by bin.vendor_binary.BOARD.arm64
-	ctx.ModuleForTests("bin.vendor_binary.BOARD.arm64", binaryVariant).Output("bin")
-
-	// bin_without_snapshot is installed by bin_without_snapshot
-	ctx.ModuleForTests("bin_without_snapshot", binaryVariant).Output("bin_without_snapshot")
-
-	// libvendor and bin don't have vendor.BOARD variant
-	libvendorVariants := ctx.ModuleVariantsForTests("libvendor")
-	if inList(sharedVariant, libvendorVariants) {
-		t.Errorf("libvendor must not have variant %#v, but it does", sharedVariant)
-	}
-
-	binVariants := ctx.ModuleVariantsForTests("bin")
-	if inList(binaryVariant, binVariants) {
-		t.Errorf("bin must not have variant %#v, but it does", sharedVariant)
-	}
-}
-
-func TestVendorSnapshotSanitizer(t *testing.T) {
-	bp := `
-	vendor_snapshot_static {
-		name: "libsnapshot",
-		vendor: true,
-		target_arch: "arm64",
-		version: "BOARD",
-		arch: {
-			arm64: {
-				src: "libsnapshot.a",
-				cfi: {
-					src: "libsnapshot.cfi.a",
-				}
-			},
-		},
-	}
-`
-	config := TestConfig(buildDir, android.Android, nil, bp, nil)
-	config.TestProductVariables.DeviceVndkVersion = StringPtr("BOARD")
-	config.TestProductVariables.Platform_vndk_version = StringPtr("VER")
-	ctx := testCcWithConfig(t, config)
-
-	// Check non-cfi and cfi variant.
-	staticVariant := "android_vendor.BOARD_arm64_armv8-a_static"
-	staticCfiVariant := "android_vendor.BOARD_arm64_armv8-a_static_cfi"
-
-	staticModule := ctx.ModuleForTests("libsnapshot.vendor_static.BOARD.arm64", staticVariant).Module().(*Module)
-	assertString(t, staticModule.outputFile.Path().Base(), "libsnapshot.a")
-
-	staticCfiModule := ctx.ModuleForTests("libsnapshot.vendor_static.BOARD.arm64", staticCfiVariant).Module().(*Module)
-	assertString(t, staticCfiModule.outputFile.Path().Base(), "libsnapshot.cfi.a")
-}
-
-func assertExcludeFromVendorSnapshotIs(t *testing.T, ctx *android.TestContext, name string, expected bool) {
-	t.Helper()
-	m := ctx.ModuleForTests(name, vendorVariant).Module().(*Module)
-	if m.ExcludeFromVendorSnapshot() != expected {
-		t.Errorf("expected %q ExcludeFromVendorSnapshot to be %t", m.String(), expected)
-	}
-}
-
-func assertExcludeFromRecoverySnapshotIs(t *testing.T, ctx *android.TestContext, name string, expected bool) {
-	t.Helper()
-	m := ctx.ModuleForTests(name, recoveryVariant).Module().(*Module)
-	if m.ExcludeFromRecoverySnapshot() != expected {
-		t.Errorf("expected %q ExcludeFromRecoverySnapshot to be %t", m.String(), expected)
-	}
-}
-
-func TestVendorSnapshotExclude(t *testing.T) {
-
-	// This test verifies that the exclude_from_vendor_snapshot property
-	// makes its way from the Android.bp source file into the module data
-	// structure. It also verifies that modules are correctly included or
-	// excluded in the vendor snapshot based on their path (framework or
-	// vendor) and the exclude_from_vendor_snapshot property.
-
-	frameworkBp := `
-		cc_library_shared {
-			name: "libinclude",
-			srcs: ["src/include.cpp"],
-			vendor_available: true,
-		}
-		cc_library_shared {
-			name: "libexclude",
-			srcs: ["src/exclude.cpp"],
-			vendor: true,
-			exclude_from_vendor_snapshot: true,
-		}
-		cc_library_shared {
-			name: "libavailable_exclude",
-			srcs: ["src/exclude.cpp"],
-			vendor_available: true,
-			exclude_from_vendor_snapshot: true,
-		}
-	`
-
-	vendorProprietaryBp := `
-		cc_library_shared {
-			name: "libvendor",
-			srcs: ["vendor.cpp"],
-			vendor: true,
-		}
-	`
-
-	depsBp := GatherRequiredDepsForTest(android.Android)
-
-	mockFS := map[string][]byte{
-		"deps/Android.bp":       []byte(depsBp),
-		"framework/Android.bp":  []byte(frameworkBp),
-		"framework/include.cpp": nil,
-		"framework/exclude.cpp": nil,
-		"device/Android.bp":     []byte(vendorProprietaryBp),
-		"device/vendor.cpp":     nil,
-	}
-
-	config := TestConfig(buildDir, android.Android, nil, "", mockFS)
-	config.TestProductVariables.DeviceVndkVersion = StringPtr("current")
-	config.TestProductVariables.Platform_vndk_version = StringPtr("VER")
-	ctx := CreateTestContext(config)
-	ctx.Register()
-
-	_, errs := ctx.ParseFileList(".", []string{"deps/Android.bp", "framework/Android.bp", "device/Android.bp"})
-	android.FailIfErrored(t, errs)
-	_, errs = ctx.PrepareBuildActions(config)
-	android.FailIfErrored(t, errs)
-
-	// Test an include and exclude framework module.
-	assertExcludeFromVendorSnapshotIs(t, ctx, "libinclude", false)
-	assertExcludeFromVendorSnapshotIs(t, ctx, "libexclude", true)
-	assertExcludeFromVendorSnapshotIs(t, ctx, "libavailable_exclude", true)
-
-	// A vendor module is excluded, but by its path, not the
-	// exclude_from_vendor_snapshot property.
-	assertExcludeFromVendorSnapshotIs(t, ctx, "libvendor", false)
-
-	// Verify the content of the vendor snapshot.
-
-	snapshotDir := "vendor-snapshot"
-	snapshotVariantPath := filepath.Join(buildDir, snapshotDir, "arm64")
-	snapshotSingleton := ctx.SingletonForTests("vendor-snapshot")
-
-	var includeJsonFiles []string
-	var excludeJsonFiles []string
-
-	for _, arch := range [][]string{
-		[]string{"arm64", "armv8-a"},
-		[]string{"arm", "armv7-a-neon"},
-	} {
-		archType := arch[0]
-		archVariant := arch[1]
-		archDir := fmt.Sprintf("arch-%s-%s", archType, archVariant)
-
-		sharedVariant := fmt.Sprintf("android_vendor.VER_%s_%s_shared", archType, archVariant)
-		sharedDir := filepath.Join(snapshotVariantPath, archDir, "shared")
-
-		// Included modules
-		checkSnapshot(t, ctx, snapshotSingleton, "libinclude", "libinclude.so", sharedDir, sharedVariant)
-		includeJsonFiles = append(includeJsonFiles, filepath.Join(sharedDir, "libinclude.so.json"))
-
-		// Excluded modules
-		checkSnapshotExclude(t, ctx, snapshotSingleton, "libexclude", "libexclude.so", sharedDir, sharedVariant)
-		excludeJsonFiles = append(excludeJsonFiles, filepath.Join(sharedDir, "libexclude.so.json"))
-		checkSnapshotExclude(t, ctx, snapshotSingleton, "libvendor", "libvendor.so", sharedDir, sharedVariant)
-		excludeJsonFiles = append(excludeJsonFiles, filepath.Join(sharedDir, "libvendor.so.json"))
-		checkSnapshotExclude(t, ctx, snapshotSingleton, "libavailable_exclude", "libavailable_exclude.so", sharedDir, sharedVariant)
-		excludeJsonFiles = append(excludeJsonFiles, filepath.Join(sharedDir, "libavailable_exclude.so.json"))
-	}
-
-	// Verify that each json file for an included module has a rule.
-	for _, jsonFile := range includeJsonFiles {
-		if snapshotSingleton.MaybeOutput(jsonFile).Rule == nil {
-			t.Errorf("include json file %q not found", jsonFile)
-		}
-	}
-
-	// Verify that each json file for an excluded module has no rule.
-	for _, jsonFile := range excludeJsonFiles {
-		if snapshotSingleton.MaybeOutput(jsonFile).Rule != nil {
-			t.Errorf("exclude json file %q found", jsonFile)
-		}
-	}
-}
-
-func TestVendorSnapshotExcludeInVendorProprietaryPathErrors(t *testing.T) {
-
-	// This test verifies that using the exclude_from_vendor_snapshot
-	// property on a module in a vendor proprietary path generates an
-	// error. These modules are already excluded, so we prohibit using the
-	// property in this way, which could add to confusion.
-
-	vendorProprietaryBp := `
-		cc_library_shared {
-			name: "libvendor",
-			srcs: ["vendor.cpp"],
-			vendor: true,
-			exclude_from_vendor_snapshot: true,
-		}
-	`
-
-	depsBp := GatherRequiredDepsForTest(android.Android)
-
-	mockFS := map[string][]byte{
-		"deps/Android.bp":   []byte(depsBp),
-		"device/Android.bp": []byte(vendorProprietaryBp),
-		"device/vendor.cpp": nil,
-	}
-
-	config := TestConfig(buildDir, android.Android, nil, "", mockFS)
-	config.TestProductVariables.DeviceVndkVersion = StringPtr("current")
-	config.TestProductVariables.Platform_vndk_version = StringPtr("VER")
-	ctx := CreateTestContext(config)
-	ctx.Register()
-
-	_, errs := ctx.ParseFileList(".", []string{"deps/Android.bp", "device/Android.bp"})
-	android.FailIfErrored(t, errs)
-
-	_, errs = ctx.PrepareBuildActions(config)
-	android.CheckErrorsAgainstExpectations(t, errs, []string{
-		`module "libvendor\{.+,image:vendor.+,arch:arm64_.+\}" in vendor proprietary path "device" may not use "exclude_from_vendor_snapshot: true"`,
-		`module "libvendor\{.+,image:vendor.+,arch:arm_.+\}" in vendor proprietary path "device" may not use "exclude_from_vendor_snapshot: true"`,
-		`module "libvendor\{.+,image:vendor.+,arch:arm64_.+\}" in vendor proprietary path "device" may not use "exclude_from_vendor_snapshot: true"`,
-		`module "libvendor\{.+,image:vendor.+,arch:arm_.+\}" in vendor proprietary path "device" may not use "exclude_from_vendor_snapshot: true"`,
-		`module "libvendor\{.+,image:vendor.+,arch:arm64_.+\}" in vendor proprietary path "device" may not use "exclude_from_vendor_snapshot: true"`,
-		`module "libvendor\{.+,image:vendor.+,arch:arm_.+\}" in vendor proprietary path "device" may not use "exclude_from_vendor_snapshot: true"`,
-	})
-}
-
-func TestRecoverySnapshotCapture(t *testing.T) {
-	bp := `
-	cc_library {
-		name: "libvndk",
-		vendor_available: true,
-		recovery_available: true,
-		product_available: true,
-		vndk: {
-			enabled: true,
-		},
-		nocrt: true,
-	}
-
-	cc_library {
-		name: "librecovery",
-		recovery: true,
-		nocrt: true,
-	}
-
-	cc_library {
-		name: "librecovery_available",
-		recovery_available: true,
-		nocrt: true,
-	}
-
-	cc_library_headers {
-		name: "librecovery_headers",
-		recovery_available: true,
-		nocrt: true,
-	}
-
-	cc_binary {
-		name: "recovery_bin",
-		recovery: true,
-		nocrt: true,
-	}
-
-	cc_binary {
-		name: "recovery_available_bin",
-		recovery_available: true,
-		nocrt: true,
-	}
-
-	toolchain_library {
-		name: "libb",
-		recovery_available: true,
-		src: "libb.a",
-	}
-
-	cc_object {
-		name: "obj",
-		recovery_available: true,
-	}
-`
-	config := TestConfig(buildDir, android.Android, nil, bp, nil)
-	config.TestProductVariables.RecoverySnapshotVersion = StringPtr("current")
-	config.TestProductVariables.Platform_vndk_version = StringPtr("VER")
-	ctx := testCcWithConfig(t, config)
-
-	// Check Recovery snapshot output.
-
-	snapshotDir := "recovery-snapshot"
-	snapshotVariantPath := filepath.Join(buildDir, snapshotDir, "arm64")
-	snapshotSingleton := ctx.SingletonForTests("recovery-snapshot")
-
-	var jsonFiles []string
-
-	for _, arch := range [][]string{
-		[]string{"arm64", "armv8-a"},
-	} {
-		archType := arch[0]
-		archVariant := arch[1]
-		archDir := fmt.Sprintf("arch-%s-%s", archType, archVariant)
-
-		// For shared libraries, only recovery_available modules are captured.
-		sharedVariant := fmt.Sprintf("android_recovery_%s_%s_shared", archType, archVariant)
-		sharedDir := filepath.Join(snapshotVariantPath, archDir, "shared")
-		checkSnapshot(t, ctx, snapshotSingleton, "libvndk", "libvndk.so", sharedDir, sharedVariant)
-		checkSnapshot(t, ctx, snapshotSingleton, "librecovery", "librecovery.so", sharedDir, sharedVariant)
-		checkSnapshot(t, ctx, snapshotSingleton, "librecovery_available", "librecovery_available.so", sharedDir, sharedVariant)
-		jsonFiles = append(jsonFiles,
-			filepath.Join(sharedDir, "libvndk.so.json"),
-			filepath.Join(sharedDir, "librecovery.so.json"),
-			filepath.Join(sharedDir, "librecovery_available.so.json"))
-
-		// For static libraries, all recovery:true and recovery_available modules are captured.
-		staticVariant := fmt.Sprintf("android_recovery_%s_%s_static", archType, archVariant)
-		staticDir := filepath.Join(snapshotVariantPath, archDir, "static")
-		checkSnapshot(t, ctx, snapshotSingleton, "libb", "libb.a", staticDir, staticVariant)
-		checkSnapshot(t, ctx, snapshotSingleton, "librecovery", "librecovery.a", staticDir, staticVariant)
-		checkSnapshot(t, ctx, snapshotSingleton, "librecovery_available", "librecovery_available.a", staticDir, staticVariant)
-		jsonFiles = append(jsonFiles,
-			filepath.Join(staticDir, "libb.a.json"),
-			filepath.Join(staticDir, "librecovery.a.json"),
-			filepath.Join(staticDir, "librecovery_available.a.json"))
-
-		// For binary executables, all recovery:true and recovery_available modules are captured.
-		if archType == "arm64" {
-			binaryVariant := fmt.Sprintf("android_recovery_%s_%s", archType, archVariant)
-			binaryDir := filepath.Join(snapshotVariantPath, archDir, "binary")
-			checkSnapshot(t, ctx, snapshotSingleton, "recovery_bin", "recovery_bin", binaryDir, binaryVariant)
-			checkSnapshot(t, ctx, snapshotSingleton, "recovery_available_bin", "recovery_available_bin", binaryDir, binaryVariant)
-			jsonFiles = append(jsonFiles,
-				filepath.Join(binaryDir, "recovery_bin.json"),
-				filepath.Join(binaryDir, "recovery_available_bin.json"))
-		}
-
-		// For header libraries, all vendor:true and vendor_available modules are captured.
-		headerDir := filepath.Join(snapshotVariantPath, archDir, "header")
-		jsonFiles = append(jsonFiles, filepath.Join(headerDir, "librecovery_headers.json"))
-
-		// For object modules, all vendor:true and vendor_available modules are captured.
-		objectVariant := fmt.Sprintf("android_recovery_%s_%s", archType, archVariant)
-		objectDir := filepath.Join(snapshotVariantPath, archDir, "object")
-		checkSnapshot(t, ctx, snapshotSingleton, "obj", "obj.o", objectDir, objectVariant)
-		jsonFiles = append(jsonFiles, filepath.Join(objectDir, "obj.o.json"))
-	}
-
-	for _, jsonFile := range jsonFiles {
-		// verify all json files exist
-		if snapshotSingleton.MaybeOutput(jsonFile).Rule == nil {
-			t.Errorf("%q expected but not found", jsonFile)
-		}
-	}
-}
-
-func TestRecoverySnapshotExclude(t *testing.T) {
-	// This test verifies that the exclude_from_recovery_snapshot property
-	// makes its way from the Android.bp source file into the module data
-	// structure. It also verifies that modules are correctly included or
-	// excluded in the recovery snapshot based on their path (framework or
-	// vendor) and the exclude_from_recovery_snapshot property.
-
-	frameworkBp := `
-		cc_library_shared {
-			name: "libinclude",
-			srcs: ["src/include.cpp"],
-			recovery_available: true,
-		}
-		cc_library_shared {
-			name: "libexclude",
-			srcs: ["src/exclude.cpp"],
-			recovery: true,
-			exclude_from_recovery_snapshot: true,
-		}
-		cc_library_shared {
-			name: "libavailable_exclude",
-			srcs: ["src/exclude.cpp"],
-			recovery_available: true,
-			exclude_from_recovery_snapshot: true,
-		}
-	`
-
-	vendorProprietaryBp := `
-		cc_library_shared {
-			name: "librecovery",
-			srcs: ["recovery.cpp"],
-			recovery: true,
-		}
-	`
-
-	depsBp := GatherRequiredDepsForTest(android.Android)
-
-	mockFS := map[string][]byte{
-		"deps/Android.bp":       []byte(depsBp),
-		"framework/Android.bp":  []byte(frameworkBp),
-		"framework/include.cpp": nil,
-		"framework/exclude.cpp": nil,
-		"device/Android.bp":     []byte(vendorProprietaryBp),
-		"device/recovery.cpp":   nil,
-	}
-
-	config := TestConfig(buildDir, android.Android, nil, "", mockFS)
-	config.TestProductVariables.RecoverySnapshotVersion = StringPtr("current")
-	config.TestProductVariables.Platform_vndk_version = StringPtr("VER")
-	ctx := CreateTestContext(config)
-	ctx.Register()
-
-	_, errs := ctx.ParseFileList(".", []string{"deps/Android.bp", "framework/Android.bp", "device/Android.bp"})
-	android.FailIfErrored(t, errs)
-	_, errs = ctx.PrepareBuildActions(config)
-	android.FailIfErrored(t, errs)
-
-	// Test an include and exclude framework module.
-	assertExcludeFromRecoverySnapshotIs(t, ctx, "libinclude", false)
-	assertExcludeFromRecoverySnapshotIs(t, ctx, "libexclude", true)
-	assertExcludeFromRecoverySnapshotIs(t, ctx, "libavailable_exclude", true)
-
-	// A recovery module is excluded, but by its path, not the
-	// exclude_from_recovery_snapshot property.
-	assertExcludeFromRecoverySnapshotIs(t, ctx, "librecovery", false)
-
-	// Verify the content of the recovery snapshot.
-
-	snapshotDir := "recovery-snapshot"
-	snapshotVariantPath := filepath.Join(buildDir, snapshotDir, "arm64")
-	snapshotSingleton := ctx.SingletonForTests("recovery-snapshot")
-
-	var includeJsonFiles []string
-	var excludeJsonFiles []string
-
-	for _, arch := range [][]string{
-		[]string{"arm64", "armv8-a"},
-	} {
-		archType := arch[0]
-		archVariant := arch[1]
-		archDir := fmt.Sprintf("arch-%s-%s", archType, archVariant)
-
-		sharedVariant := fmt.Sprintf("android_recovery_%s_%s_shared", archType, archVariant)
-		sharedDir := filepath.Join(snapshotVariantPath, archDir, "shared")
-
-		// Included modules
-		checkSnapshot(t, ctx, snapshotSingleton, "libinclude", "libinclude.so", sharedDir, sharedVariant)
-		includeJsonFiles = append(includeJsonFiles, filepath.Join(sharedDir, "libinclude.so.json"))
-
-		// Excluded modules
-		checkSnapshotExclude(t, ctx, snapshotSingleton, "libexclude", "libexclude.so", sharedDir, sharedVariant)
-		excludeJsonFiles = append(excludeJsonFiles, filepath.Join(sharedDir, "libexclude.so.json"))
-		checkSnapshotExclude(t, ctx, snapshotSingleton, "librecovery", "librecovery.so", sharedDir, sharedVariant)
-		excludeJsonFiles = append(excludeJsonFiles, filepath.Join(sharedDir, "librecovery.so.json"))
-		checkSnapshotExclude(t, ctx, snapshotSingleton, "libavailable_exclude", "libavailable_exclude.so", sharedDir, sharedVariant)
-		excludeJsonFiles = append(excludeJsonFiles, filepath.Join(sharedDir, "libavailable_exclude.so.json"))
-	}
-
-	// Verify that each json file for an included module has a rule.
-	for _, jsonFile := range includeJsonFiles {
-		if snapshotSingleton.MaybeOutput(jsonFile).Rule == nil {
-			t.Errorf("include json file %q not found", jsonFile)
-		}
-	}
-
-	// Verify that each json file for an excluded module has no rule.
-	for _, jsonFile := range excludeJsonFiles {
-		if snapshotSingleton.MaybeOutput(jsonFile).Rule != nil {
-			t.Errorf("exclude json file %q found", jsonFile)
-		}
-	}
-}
-
 func TestDoubleLoadableDepError(t *testing.T) {
 	// Check whether an error is emitted when a LLNDK depends on a non-double_loadable VNDK lib.
 	testCcError(t, "module \".*\" variant \".*\": link.* \".*\" which is not LL-NDK, VNDK-SP, .*double_loadable", `
diff --git a/cc/config/global.go b/cc/config/global.go
index c62f784..ee41125 100644
--- a/cc/config/global.go
+++ b/cc/config/global.go
@@ -144,8 +144,8 @@
 
 	// prebuilts/clang default settings.
 	ClangDefaultBase         = "prebuilts/clang/host"
-	ClangDefaultVersion      = "clang-r407598"
-	ClangDefaultShortVersion = "12.0.1"
+	ClangDefaultVersion      = "clang-r407598b"
+	ClangDefaultShortVersion = "12.0.2"
 
 	// Directories with warnings from Android.bp files.
 	WarningAllowedProjects = []string{
diff --git a/cc/config/tidy.go b/cc/config/tidy.go
index d5d01b4..7cc9f43 100644
--- a/cc/config/tidy.go
+++ b/cc/config/tidy.go
@@ -62,10 +62,8 @@
 		}, ",")
 		// clang-analyzer-* checks are too slow to be in the default for WITH_TIDY=1.
 		// nightly builds add CLANG_ANALYZER_CHECKS=1 to run those checks.
-		// Some test code have clang-diagnostic-padded warnings that cannot be
-		// suppressed, but only by disabling clang-analyzer-optin.performance.*.
 		if ctx.Config().IsEnvTrue("CLANG_ANALYZER_CHECKS") {
-			checks += ",clang-analyzer-*,-clang-analyzer-optin.performance.*"
+			checks += ",clang-analyzer-*"
 		}
 		return checks
 	})
diff --git a/cc/config/vndk.go b/cc/config/vndk.go
index 107ae7d..45c18c2 100644
--- a/cc/config/vndk.go
+++ b/cc/config/vndk.go
@@ -17,25 +17,47 @@
 // List of VNDK libraries that have different core variant and vendor variant.
 // For these libraries, the vendor variants must be installed even if the device
 // has VndkUseCoreVariant set.
+// TODO(b/150578172): clean up unstable and non-versioned aidl module
 var VndkMustUseVendorVariantList = []string{
 	"android.hardware.authsecret-unstable-ndk_platform",
+	"android.hardware.authsecret-ndk_platform",
+	"android.hardware.authsecret-V1-ndk_platform",
 	"android.hardware.automotive.occupant_awareness-ndk_platform",
+	"android.hardware.automotive.occupant_awareness-V1-ndk_platform",
+	"android.hardware.health.storage-V1-ndk_platform",
 	"android.hardware.health.storage-ndk_platform",
 	"android.hardware.health.storage-unstable-ndk_platform",
+	"android.hardware.light-V1-ndk_platform",
 	"android.hardware.light-ndk_platform",
+	"android.hardware.identity-V2-ndk_platform",
 	"android.hardware.identity-ndk_platform",
 	"android.hardware.nfc@1.2",
+	"android.hardware.memtrack-V1-ndk_platform",
+	"android.hardware.memtrack-ndk_platform",
 	"android.hardware.memtrack-unstable-ndk_platform",
+	"android.hardware.oemlock-V1-ndk_platform",
+	"android.hardware.oemlock-ndk_platform",
 	"android.hardware.oemlock-unstable-ndk_platform",
+	"android.hardware.power-V1-ndk_platform",
 	"android.hardware.power-ndk_platform",
+	"android.hardware.rebootescrow-V1-ndk_platform",
 	"android.hardware.rebootescrow-ndk_platform",
+	"android.hardware.security.keymint-V1-ndk_platform",
+	"android.hardware.security.keymint-ndk_platform",
 	"android.hardware.security.keymint-unstable-ndk_platform",
-	"android.hardware.security.secureclock-ndk_platform",
+	"android.hardware.security.secureclock-V1-ndk_platform",
 	"android.hardware.security.secureclock-unstable-ndk_platform",
+	"android.hardware.security.secureclock-ndk_platform",
+	"android.hardware.security.sharedsecret-V1-ndk_platform",
 	"android.hardware.security.sharedsecret-ndk_platform",
 	"android.hardware.security.sharedsecret-unstable-ndk_platform",
+	"android.hardware.vibrator-V1-ndk_platform",
 	"android.hardware.vibrator-ndk_platform",
+	"android.hardware.weaver-V1-ndk_platform",
+	"android.hardware.weaver-ndk_platform",
 	"android.hardware.weaver-unstable-ndk_platform",
+	"android.system.keystore2-V1-ndk_platform",
+	"android.system.keystore2-ndk_platform",
 	"android.system.keystore2-unstable-ndk_platform",
 	"libbinder",
 	"libcrypto",
diff --git a/cc/genrule.go b/cc/genrule.go
index 1ce2169..ca4fda7 100644
--- a/cc/genrule.go
+++ b/cc/genrule.go
@@ -25,6 +25,7 @@
 
 type GenruleExtraProperties struct {
 	Vendor_available         *bool
+	Odm_available            *bool
 	Product_available        *bool
 	Ramdisk_available        *bool
 	Vendor_ramdisk_available *bool
@@ -63,7 +64,7 @@
 		return false
 	}
 
-	return Bool(g.Vendor_available) || Bool(g.Product_available) || !(ctx.SocSpecific() || ctx.DeviceSpecific())
+	return !(ctx.SocSpecific() || ctx.DeviceSpecific())
 }
 
 func (g *GenruleExtraProperties) RamdiskVariantNeeded(ctx android.BaseModuleContext) bool {
@@ -92,7 +93,7 @@
 	}
 
 	var variants []string
-	if Bool(g.Vendor_available) || ctx.SocSpecific() || ctx.DeviceSpecific() {
+	if Bool(g.Vendor_available) || Bool(g.Odm_available) || ctx.SocSpecific() || ctx.DeviceSpecific() {
 		vndkVersion := ctx.DeviceConfig().VndkVersion()
 		// If vndkVersion is current, we can always use PlatformVndkVersion.
 		// If not, we assume modules under proprietary paths are compatible for
diff --git a/cc/image.go b/cc/image.go
index f89194f..231da7e 100644
--- a/cc/image.go
+++ b/cc/image.go
@@ -56,8 +56,14 @@
 
 func (ctx *moduleContext) SocSpecific() bool {
 	// Additionally check if this module is inVendor() that means it is a "vendor" variant of a
-	// module. As well as SoC specific modules, vendor variants must be installed to /vendor.
-	return ctx.ModuleContext.SocSpecific() || ctx.mod.InVendor()
+	// module. As well as SoC specific modules, vendor variants must be installed to /vendor
+	// unless they have "odm_available: true".
+	return ctx.ModuleContext.SocSpecific() || (ctx.mod.InVendor() && !ctx.mod.VendorVariantToOdm())
+}
+
+func (ctx *moduleContext) DeviceSpecific() bool {
+	// Some vendor variants want to be installed to /odm by setting "odm_available: true".
+	return ctx.ModuleContext.DeviceSpecific() || (ctx.mod.InVendor() && ctx.mod.VendorVariantToOdm())
 }
 
 func (ctx *moduleContextImpl) inProduct() bool {
@@ -82,7 +88,13 @@
 
 // Returns true when this module is configured to have core and vendor variants.
 func (c *Module) HasVendorVariant() bool {
-	return Bool(c.VendorProperties.Vendor_available)
+	return Bool(c.VendorProperties.Vendor_available) || Bool(c.VendorProperties.Odm_available)
+}
+
+// Returns true when this module creates a vendor variant and wants to install the vendor variant
+// to the odm partition.
+func (c *Module) VendorVariantToOdm() bool {
+	return Bool(c.VendorProperties.Odm_available)
 }
 
 // Returns true when this module is configured to have core and product variants.
@@ -183,7 +195,18 @@
 	if Bool(m.VendorProperties.Vendor_available) {
 		if vendorSpecific {
 			mctx.PropertyErrorf("vendor_available",
-				"doesn't make sense at the same time as `vendor: true`, `proprietary: true`, or `device_specific:true`")
+				"doesn't make sense at the same time as `vendor: true`, `proprietary: true`, or `device_specific: true`")
+		}
+		if Bool(m.VendorProperties.Odm_available) {
+			mctx.PropertyErrorf("vendor_available",
+				"doesn't make sense at the same time as `odm_available: true`")
+		}
+	}
+
+	if Bool(m.VendorProperties.Odm_available) {
+		if vendorSpecific {
+			mctx.PropertyErrorf("odm_available",
+				"doesn't make sense at the same time as `vendor: true`, `proprietary: true`, or `device_specific: true`")
 		}
 	}
 
diff --git a/cc/library.go b/cc/library.go
index af9aaca..29a3c69 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -449,24 +449,39 @@
 			}
 			continue
 		}
-		exts := headerExts
-		// Glob all files under this special directory, because of C++ headers.
-		if strings.HasPrefix(dir, "external/libcxx/include") {
-			exts = []string{""}
+		glob, err := ctx.GlobWithDeps(dir+"/**/*", nil)
+		if err != nil {
+			ctx.ModuleErrorf("glob failed: %#v", err)
+			return
 		}
-		for _, ext := range exts {
-			glob, err := ctx.GlobWithDeps(dir+"/**/*"+ext, nil)
-			if err != nil {
-				ctx.ModuleErrorf("glob failed: %#v", err)
-				return
-			}
-			for _, header := range glob {
-				if strings.HasSuffix(header, "/") {
+		isLibcxx := strings.HasPrefix(dir, "external/libcxx/include")
+		j := 0
+		for i, header := range glob {
+			if isLibcxx {
+				// Glob all files under this special directory, because of C++ headers with no
+				// extension.
+				if !strings.HasSuffix(header, "/") {
 					continue
 				}
-				ret = append(ret, android.PathForSource(ctx, header))
+			} else {
+				// Filter out only the files with extensions that are headers.
+				found := false
+				for _, ext := range headerExts {
+					if strings.HasSuffix(header, ext) {
+						found = true
+						break
+					}
+				}
+				if !found {
+					continue
+				}
 			}
+			if i != j {
+				glob[j] = glob[i]
+			}
+			j++
 		}
+		glob = glob[:j]
 	}
 
 	// Collect generated headers
diff --git a/cc/library_sdk_member.go b/cc/library_sdk_member.go
index 3f2cf49..1402991 100644
--- a/cc/library_sdk_member.go
+++ b/cc/library_sdk_member.go
@@ -130,6 +130,10 @@
 		pbm.AddProperty("vendor_available", true)
 	}
 
+	if proptools.Bool(ccModule.VendorProperties.Odm_available) {
+		pbm.AddProperty("odm_available", true)
+	}
+
 	if proptools.Bool(ccModule.VendorProperties.Product_available) {
 		pbm.AddProperty("product_available", true)
 	}
diff --git a/cc/vendor_snapshot_test.go b/cc/vendor_snapshot_test.go
new file mode 100644
index 0000000..cce28b0
--- /dev/null
+++ b/cc/vendor_snapshot_test.go
@@ -0,0 +1,1006 @@
+// 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 cc
+
+import (
+	"android/soong/android"
+	"fmt"
+	"path/filepath"
+	"reflect"
+	"strings"
+	"testing"
+)
+
+func TestVendorSnapshotCapture(t *testing.T) {
+	bp := `
+	cc_library {
+		name: "libvndk",
+		vendor_available: true,
+		product_available: true,
+		vndk: {
+			enabled: true,
+		},
+		nocrt: true,
+	}
+
+	cc_library {
+		name: "libvendor",
+		vendor: true,
+		nocrt: true,
+	}
+
+	cc_library {
+		name: "libvendor_available",
+		vendor_available: true,
+		nocrt: true,
+	}
+
+	cc_library_headers {
+		name: "libvendor_headers",
+		vendor_available: true,
+		nocrt: true,
+	}
+
+	cc_binary {
+		name: "vendor_bin",
+		vendor: true,
+		nocrt: true,
+	}
+
+	cc_binary {
+		name: "vendor_available_bin",
+		vendor_available: true,
+		nocrt: true,
+	}
+
+	toolchain_library {
+		name: "libb",
+		vendor_available: true,
+		src: "libb.a",
+	}
+
+	cc_object {
+		name: "obj",
+		vendor_available: true,
+	}
+
+	cc_library {
+		name: "libllndk",
+		llndk_stubs: "libllndk.llndk",
+	}
+
+	llndk_library {
+		name: "libllndk.llndk",
+		symbol_file: "",
+	}
+`
+	config := TestConfig(buildDir, android.Android, nil, bp, nil)
+	config.TestProductVariables.DeviceVndkVersion = StringPtr("current")
+	config.TestProductVariables.Platform_vndk_version = StringPtr("VER")
+	ctx := testCcWithConfig(t, config)
+
+	// Check Vendor snapshot output.
+
+	snapshotDir := "vendor-snapshot"
+	snapshotVariantPath := filepath.Join(buildDir, snapshotDir, "arm64")
+	snapshotSingleton := ctx.SingletonForTests("vendor-snapshot")
+
+	var jsonFiles []string
+
+	for _, arch := range [][]string{
+		[]string{"arm64", "armv8-a"},
+		[]string{"arm", "armv7-a-neon"},
+	} {
+		archType := arch[0]
+		archVariant := arch[1]
+		archDir := fmt.Sprintf("arch-%s-%s", archType, archVariant)
+
+		// For shared libraries, only non-VNDK vendor_available modules are captured
+		sharedVariant := fmt.Sprintf("android_vendor.VER_%s_%s_shared", archType, archVariant)
+		sharedDir := filepath.Join(snapshotVariantPath, archDir, "shared")
+		checkSnapshot(t, ctx, snapshotSingleton, "libvendor", "libvendor.so", sharedDir, sharedVariant)
+		checkSnapshot(t, ctx, snapshotSingleton, "libvendor_available", "libvendor_available.so", sharedDir, sharedVariant)
+		jsonFiles = append(jsonFiles,
+			filepath.Join(sharedDir, "libvendor.so.json"),
+			filepath.Join(sharedDir, "libvendor_available.so.json"))
+
+		// LLNDK modules are not captured
+		checkSnapshotExclude(t, ctx, snapshotSingleton, "libllndk", "libllndk.so", sharedDir, sharedVariant)
+
+		// For static libraries, all vendor:true and vendor_available modules (including VNDK) are captured.
+		// Also cfi variants are captured, except for prebuilts like toolchain_library
+		staticVariant := fmt.Sprintf("android_vendor.VER_%s_%s_static", archType, archVariant)
+		staticCfiVariant := fmt.Sprintf("android_vendor.VER_%s_%s_static_cfi", archType, archVariant)
+		staticDir := filepath.Join(snapshotVariantPath, archDir, "static")
+		checkSnapshot(t, ctx, snapshotSingleton, "libb", "libb.a", staticDir, staticVariant)
+		checkSnapshot(t, ctx, snapshotSingleton, "libvndk", "libvndk.a", staticDir, staticVariant)
+		checkSnapshot(t, ctx, snapshotSingleton, "libvndk", "libvndk.cfi.a", staticDir, staticCfiVariant)
+		checkSnapshot(t, ctx, snapshotSingleton, "libvendor", "libvendor.a", staticDir, staticVariant)
+		checkSnapshot(t, ctx, snapshotSingleton, "libvendor", "libvendor.cfi.a", staticDir, staticCfiVariant)
+		checkSnapshot(t, ctx, snapshotSingleton, "libvendor_available", "libvendor_available.a", staticDir, staticVariant)
+		checkSnapshot(t, ctx, snapshotSingleton, "libvendor_available", "libvendor_available.cfi.a", staticDir, staticCfiVariant)
+		jsonFiles = append(jsonFiles,
+			filepath.Join(staticDir, "libb.a.json"),
+			filepath.Join(staticDir, "libvndk.a.json"),
+			filepath.Join(staticDir, "libvndk.cfi.a.json"),
+			filepath.Join(staticDir, "libvendor.a.json"),
+			filepath.Join(staticDir, "libvendor.cfi.a.json"),
+			filepath.Join(staticDir, "libvendor_available.a.json"),
+			filepath.Join(staticDir, "libvendor_available.cfi.a.json"))
+
+		// For binary executables, all vendor:true and vendor_available modules are captured.
+		if archType == "arm64" {
+			binaryVariant := fmt.Sprintf("android_vendor.VER_%s_%s", archType, archVariant)
+			binaryDir := filepath.Join(snapshotVariantPath, archDir, "binary")
+			checkSnapshot(t, ctx, snapshotSingleton, "vendor_bin", "vendor_bin", binaryDir, binaryVariant)
+			checkSnapshot(t, ctx, snapshotSingleton, "vendor_available_bin", "vendor_available_bin", binaryDir, binaryVariant)
+			jsonFiles = append(jsonFiles,
+				filepath.Join(binaryDir, "vendor_bin.json"),
+				filepath.Join(binaryDir, "vendor_available_bin.json"))
+		}
+
+		// For header libraries, all vendor:true and vendor_available modules are captured.
+		headerDir := filepath.Join(snapshotVariantPath, archDir, "header")
+		jsonFiles = append(jsonFiles, filepath.Join(headerDir, "libvendor_headers.json"))
+
+		// For object modules, all vendor:true and vendor_available modules are captured.
+		objectVariant := fmt.Sprintf("android_vendor.VER_%s_%s", archType, archVariant)
+		objectDir := filepath.Join(snapshotVariantPath, archDir, "object")
+		checkSnapshot(t, ctx, snapshotSingleton, "obj", "obj.o", objectDir, objectVariant)
+		jsonFiles = append(jsonFiles, filepath.Join(objectDir, "obj.o.json"))
+	}
+
+	for _, jsonFile := range jsonFiles {
+		// verify all json files exist
+		if snapshotSingleton.MaybeOutput(jsonFile).Rule == nil {
+			t.Errorf("%q expected but not found", jsonFile)
+		}
+	}
+
+	// fake snapshot should have all outputs in the normal snapshot.
+	fakeSnapshotSingleton := ctx.SingletonForTests("vendor-fake-snapshot")
+	for _, output := range snapshotSingleton.AllOutputs() {
+		fakeOutput := strings.Replace(output, "/vendor-snapshot/", "/fake/vendor-snapshot/", 1)
+		if fakeSnapshotSingleton.MaybeOutput(fakeOutput).Rule == nil {
+			t.Errorf("%q expected but not found", fakeOutput)
+		}
+	}
+}
+
+func TestVendorSnapshotDirected(t *testing.T) {
+	bp := `
+	cc_library_shared {
+		name: "libvendor",
+		vendor: true,
+		nocrt: true,
+	}
+
+	cc_library_shared {
+		name: "libvendor_available",
+		vendor_available: true,
+		nocrt: true,
+	}
+
+	genrule {
+		name: "libfoo_gen",
+		cmd: "",
+		out: ["libfoo.so"],
+	}
+
+	cc_prebuilt_library_shared {
+		name: "libfoo",
+		vendor: true,
+		prefer: true,
+		srcs: [":libfoo_gen"],
+	}
+
+	cc_library_shared {
+		name: "libfoo",
+		vendor: true,
+		nocrt: true,
+	}
+`
+	config := TestConfig(buildDir, android.Android, nil, bp, nil)
+	config.TestProductVariables.DeviceVndkVersion = StringPtr("current")
+	config.TestProductVariables.Platform_vndk_version = StringPtr("VER")
+	config.TestProductVariables.DirectedVendorSnapshot = true
+	config.TestProductVariables.VendorSnapshotModules = make(map[string]bool)
+	config.TestProductVariables.VendorSnapshotModules["libvendor"] = true
+	config.TestProductVariables.VendorSnapshotModules["libfoo"] = true
+	ctx := testCcWithConfig(t, config)
+
+	// Check Vendor snapshot output.
+
+	snapshotDir := "vendor-snapshot"
+	snapshotVariantPath := filepath.Join(buildDir, snapshotDir, "arm64")
+	snapshotSingleton := ctx.SingletonForTests("vendor-snapshot")
+
+	var includeJsonFiles []string
+	var excludeJsonFiles []string
+
+	for _, arch := range [][]string{
+		[]string{"arm64", "armv8-a"},
+		[]string{"arm", "armv7-a-neon"},
+	} {
+		archType := arch[0]
+		archVariant := arch[1]
+		archDir := fmt.Sprintf("arch-%s-%s", archType, archVariant)
+
+		sharedVariant := fmt.Sprintf("android_vendor.VER_%s_%s_shared", archType, archVariant)
+		sharedDir := filepath.Join(snapshotVariantPath, archDir, "shared")
+
+		// Included modules
+		checkSnapshot(t, ctx, snapshotSingleton, "libvendor", "libvendor.so", sharedDir, sharedVariant)
+		includeJsonFiles = append(includeJsonFiles, filepath.Join(sharedDir, "libvendor.so.json"))
+		// Check that snapshot captures "prefer: true" prebuilt
+		checkSnapshot(t, ctx, snapshotSingleton, "prebuilt_libfoo", "libfoo.so", sharedDir, sharedVariant)
+		includeJsonFiles = append(includeJsonFiles, filepath.Join(sharedDir, "libfoo.so.json"))
+
+		// Excluded modules
+		checkSnapshotExclude(t, ctx, snapshotSingleton, "libvendor_available", "libvendor_available.so", sharedDir, sharedVariant)
+		excludeJsonFiles = append(excludeJsonFiles, filepath.Join(sharedDir, "libvendor_available.so.json"))
+	}
+
+	// Verify that each json file for an included module has a rule.
+	for _, jsonFile := range includeJsonFiles {
+		if snapshotSingleton.MaybeOutput(jsonFile).Rule == nil {
+			t.Errorf("include json file %q not found", jsonFile)
+		}
+	}
+
+	// Verify that each json file for an excluded module has no rule.
+	for _, jsonFile := range excludeJsonFiles {
+		if snapshotSingleton.MaybeOutput(jsonFile).Rule != nil {
+			t.Errorf("exclude json file %q found", jsonFile)
+		}
+	}
+}
+
+func TestVendorSnapshotUse(t *testing.T) {
+	frameworkBp := `
+	cc_library {
+		name: "libvndk",
+		vendor_available: true,
+		product_available: true,
+		vndk: {
+			enabled: true,
+		},
+		nocrt: true,
+		compile_multilib: "64",
+	}
+
+	cc_library {
+		name: "libvendor",
+		vendor: true,
+		nocrt: true,
+		no_libcrt: true,
+		stl: "none",
+		system_shared_libs: [],
+		compile_multilib: "64",
+	}
+
+	cc_library {
+		name: "libvendor_available",
+		vendor_available: true,
+		nocrt: true,
+		no_libcrt: true,
+		stl: "none",
+		system_shared_libs: [],
+		compile_multilib: "64",
+	}
+
+	cc_binary {
+		name: "bin",
+		vendor: true,
+		nocrt: true,
+		no_libcrt: true,
+		stl: "none",
+		system_shared_libs: [],
+		compile_multilib: "64",
+	}
+`
+
+	vndkBp := `
+	vndk_prebuilt_shared {
+		name: "libvndk",
+		version: "BOARD",
+		target_arch: "arm64",
+		vendor_available: true,
+		product_available: true,
+		vndk: {
+			enabled: true,
+		},
+		arch: {
+			arm64: {
+				srcs: ["libvndk.so"],
+				export_include_dirs: ["include/libvndk"],
+			},
+		},
+	}
+`
+
+	vendorProprietaryBp := `
+	cc_library {
+		name: "libvendor_without_snapshot",
+		vendor: true,
+		nocrt: true,
+		no_libcrt: true,
+		stl: "none",
+		system_shared_libs: [],
+		compile_multilib: "64",
+	}
+
+	cc_library_shared {
+		name: "libclient",
+		vendor: true,
+		nocrt: true,
+		no_libcrt: true,
+		stl: "none",
+		system_shared_libs: [],
+		shared_libs: ["libvndk", "libvendor_available"],
+		static_libs: ["libvendor", "libvendor_without_snapshot"],
+		compile_multilib: "64",
+		srcs: ["client.cpp"],
+	}
+
+	cc_binary {
+		name: "bin_without_snapshot",
+		vendor: true,
+		nocrt: true,
+		no_libcrt: true,
+		stl: "none",
+		system_shared_libs: [],
+		static_libs: ["libvndk"],
+		compile_multilib: "64",
+		srcs: ["bin.cpp"],
+	}
+
+	vendor_snapshot_static {
+		name: "libvndk",
+		version: "BOARD",
+		target_arch: "arm64",
+		vendor: true,
+		arch: {
+			arm64: {
+				src: "libvndk.a",
+				export_include_dirs: ["include/libvndk"],
+			},
+		},
+	}
+
+	vendor_snapshot_shared {
+		name: "libvendor",
+		version: "BOARD",
+		target_arch: "arm64",
+		vendor: true,
+		arch: {
+			arm64: {
+				src: "libvendor.so",
+				export_include_dirs: ["include/libvendor"],
+			},
+		},
+	}
+
+	vendor_snapshot_static {
+		name: "libvendor",
+		version: "BOARD",
+		target_arch: "arm64",
+		vendor: true,
+		arch: {
+			arm64: {
+				src: "libvendor.a",
+				export_include_dirs: ["include/libvendor"],
+			},
+		},
+	}
+
+	vendor_snapshot_shared {
+		name: "libvendor_available",
+		version: "BOARD",
+		target_arch: "arm64",
+		vendor: true,
+		arch: {
+			arm64: {
+				src: "libvendor_available.so",
+				export_include_dirs: ["include/libvendor"],
+			},
+		},
+	}
+
+	vendor_snapshot_static {
+		name: "libvendor_available",
+		version: "BOARD",
+		target_arch: "arm64",
+		vendor: true,
+		arch: {
+			arm64: {
+				src: "libvendor_available.a",
+				export_include_dirs: ["include/libvendor"],
+			},
+		},
+	}
+
+	vendor_snapshot_binary {
+		name: "bin",
+		version: "BOARD",
+		target_arch: "arm64",
+		vendor: true,
+		arch: {
+			arm64: {
+				src: "bin",
+			},
+		},
+	}
+`
+	depsBp := GatherRequiredDepsForTest(android.Android)
+
+	mockFS := map[string][]byte{
+		"deps/Android.bp":              []byte(depsBp),
+		"framework/Android.bp":         []byte(frameworkBp),
+		"vendor/Android.bp":            []byte(vendorProprietaryBp),
+		"vendor/bin":                   nil,
+		"vendor/bin.cpp":               nil,
+		"vendor/client.cpp":            nil,
+		"vendor/include/libvndk/a.h":   nil,
+		"vendor/include/libvendor/b.h": nil,
+		"vendor/libvndk.a":             nil,
+		"vendor/libvendor.a":           nil,
+		"vendor/libvendor.so":          nil,
+		"vndk/Android.bp":              []byte(vndkBp),
+		"vndk/include/libvndk/a.h":     nil,
+		"vndk/libvndk.so":              nil,
+	}
+
+	config := TestConfig(buildDir, android.Android, nil, "", mockFS)
+	config.TestProductVariables.DeviceVndkVersion = StringPtr("BOARD")
+	config.TestProductVariables.Platform_vndk_version = StringPtr("VER")
+	ctx := CreateTestContext(config)
+	ctx.Register()
+
+	_, errs := ctx.ParseFileList(".", []string{"deps/Android.bp", "framework/Android.bp", "vendor/Android.bp", "vndk/Android.bp"})
+	android.FailIfErrored(t, errs)
+	_, errs = ctx.PrepareBuildActions(config)
+	android.FailIfErrored(t, errs)
+
+	sharedVariant := "android_vendor.BOARD_arm64_armv8-a_shared"
+	staticVariant := "android_vendor.BOARD_arm64_armv8-a_static"
+	binaryVariant := "android_vendor.BOARD_arm64_armv8-a"
+
+	// libclient uses libvndk.vndk.BOARD.arm64, libvendor.vendor_static.BOARD.arm64, libvendor_without_snapshot
+	libclientCcFlags := ctx.ModuleForTests("libclient", sharedVariant).Rule("cc").Args["cFlags"]
+	for _, includeFlags := range []string{
+		"-Ivndk/include/libvndk",     // libvndk
+		"-Ivendor/include/libvendor", // libvendor
+	} {
+		if !strings.Contains(libclientCcFlags, includeFlags) {
+			t.Errorf("flags for libclient must contain %#v, but was %#v.",
+				includeFlags, libclientCcFlags)
+		}
+	}
+
+	libclientLdFlags := ctx.ModuleForTests("libclient", sharedVariant).Rule("ld").Args["libFlags"]
+	for _, input := range [][]string{
+		[]string{sharedVariant, "libvndk.vndk.BOARD.arm64"},
+		[]string{staticVariant, "libvendor.vendor_static.BOARD.arm64"},
+		[]string{staticVariant, "libvendor_without_snapshot"},
+	} {
+		outputPaths := getOutputPaths(ctx, input[0] /* variant */, []string{input[1]} /* module name */)
+		if !strings.Contains(libclientLdFlags, outputPaths[0].String()) {
+			t.Errorf("libflags for libclient must contain %#v, but was %#v", outputPaths[0], libclientLdFlags)
+		}
+	}
+
+	libclientAndroidMkSharedLibs := ctx.ModuleForTests("libclient", sharedVariant).Module().(*Module).Properties.AndroidMkSharedLibs
+	if g, w := libclientAndroidMkSharedLibs, []string{"libvndk.vendor", "libvendor_available.vendor"}; !reflect.DeepEqual(g, w) {
+		t.Errorf("wanted libclient AndroidMkSharedLibs %q, got %q", w, g)
+	}
+
+	libclientAndroidMkStaticLibs := ctx.ModuleForTests("libclient", sharedVariant).Module().(*Module).Properties.AndroidMkStaticLibs
+	if g, w := libclientAndroidMkStaticLibs, []string{"libvendor", "libvendor_without_snapshot"}; !reflect.DeepEqual(g, w) {
+		t.Errorf("wanted libclient AndroidMkStaticLibs %q, got %q", w, g)
+	}
+
+	// bin_without_snapshot uses libvndk.vendor_static.BOARD.arm64
+	binWithoutSnapshotCcFlags := ctx.ModuleForTests("bin_without_snapshot", binaryVariant).Rule("cc").Args["cFlags"]
+	if !strings.Contains(binWithoutSnapshotCcFlags, "-Ivendor/include/libvndk") {
+		t.Errorf("flags for bin_without_snapshot must contain %#v, but was %#v.",
+			"-Ivendor/include/libvndk", binWithoutSnapshotCcFlags)
+	}
+
+	binWithoutSnapshotLdFlags := ctx.ModuleForTests("bin_without_snapshot", binaryVariant).Rule("ld").Args["libFlags"]
+	libVndkStaticOutputPaths := getOutputPaths(ctx, staticVariant, []string{"libvndk.vendor_static.BOARD.arm64"})
+	if !strings.Contains(binWithoutSnapshotLdFlags, libVndkStaticOutputPaths[0].String()) {
+		t.Errorf("libflags for bin_without_snapshot must contain %#v, but was %#v",
+			libVndkStaticOutputPaths[0], binWithoutSnapshotLdFlags)
+	}
+
+	// libvendor.so is installed by libvendor.vendor_shared.BOARD.arm64
+	ctx.ModuleForTests("libvendor.vendor_shared.BOARD.arm64", sharedVariant).Output("libvendor.so")
+
+	// libvendor_available.so is installed by libvendor_available.vendor_shared.BOARD.arm64
+	ctx.ModuleForTests("libvendor_available.vendor_shared.BOARD.arm64", sharedVariant).Output("libvendor_available.so")
+
+	// libvendor_without_snapshot.so is installed by libvendor_without_snapshot
+	ctx.ModuleForTests("libvendor_without_snapshot", sharedVariant).Output("libvendor_without_snapshot.so")
+
+	// bin is installed by bin.vendor_binary.BOARD.arm64
+	ctx.ModuleForTests("bin.vendor_binary.BOARD.arm64", binaryVariant).Output("bin")
+
+	// bin_without_snapshot is installed by bin_without_snapshot
+	ctx.ModuleForTests("bin_without_snapshot", binaryVariant).Output("bin_without_snapshot")
+
+	// libvendor, libvendor_available and bin don't have vendor.BOARD variant
+	libvendorVariants := ctx.ModuleVariantsForTests("libvendor")
+	if inList(sharedVariant, libvendorVariants) {
+		t.Errorf("libvendor must not have variant %#v, but it does", sharedVariant)
+	}
+
+	libvendorAvailableVariants := ctx.ModuleVariantsForTests("libvendor_available")
+	if inList(sharedVariant, libvendorAvailableVariants) {
+		t.Errorf("libvendor_available must not have variant %#v, but it does", sharedVariant)
+	}
+
+	binVariants := ctx.ModuleVariantsForTests("bin")
+	if inList(binaryVariant, binVariants) {
+		t.Errorf("bin must not have variant %#v, but it does", sharedVariant)
+	}
+}
+
+func TestVendorSnapshotSanitizer(t *testing.T) {
+	bp := `
+	vendor_snapshot_static {
+		name: "libsnapshot",
+		vendor: true,
+		target_arch: "arm64",
+		version: "BOARD",
+		arch: {
+			arm64: {
+				src: "libsnapshot.a",
+				cfi: {
+					src: "libsnapshot.cfi.a",
+				}
+			},
+		},
+	}
+`
+	config := TestConfig(buildDir, android.Android, nil, bp, nil)
+	config.TestProductVariables.DeviceVndkVersion = StringPtr("BOARD")
+	config.TestProductVariables.Platform_vndk_version = StringPtr("VER")
+	ctx := testCcWithConfig(t, config)
+
+	// Check non-cfi and cfi variant.
+	staticVariant := "android_vendor.BOARD_arm64_armv8-a_static"
+	staticCfiVariant := "android_vendor.BOARD_arm64_armv8-a_static_cfi"
+
+	staticModule := ctx.ModuleForTests("libsnapshot.vendor_static.BOARD.arm64", staticVariant).Module().(*Module)
+	assertString(t, staticModule.outputFile.Path().Base(), "libsnapshot.a")
+
+	staticCfiModule := ctx.ModuleForTests("libsnapshot.vendor_static.BOARD.arm64", staticCfiVariant).Module().(*Module)
+	assertString(t, staticCfiModule.outputFile.Path().Base(), "libsnapshot.cfi.a")
+}
+
+func assertExcludeFromVendorSnapshotIs(t *testing.T, ctx *android.TestContext, name string, expected bool) {
+	t.Helper()
+	m := ctx.ModuleForTests(name, vendorVariant).Module().(*Module)
+	if m.ExcludeFromVendorSnapshot() != expected {
+		t.Errorf("expected %q ExcludeFromVendorSnapshot to be %t", m.String(), expected)
+	}
+}
+
+func assertExcludeFromRecoverySnapshotIs(t *testing.T, ctx *android.TestContext, name string, expected bool) {
+	t.Helper()
+	m := ctx.ModuleForTests(name, recoveryVariant).Module().(*Module)
+	if m.ExcludeFromRecoverySnapshot() != expected {
+		t.Errorf("expected %q ExcludeFromRecoverySnapshot to be %t", m.String(), expected)
+	}
+}
+
+func TestVendorSnapshotExclude(t *testing.T) {
+
+	// This test verifies that the exclude_from_vendor_snapshot property
+	// makes its way from the Android.bp source file into the module data
+	// structure. It also verifies that modules are correctly included or
+	// excluded in the vendor snapshot based on their path (framework or
+	// vendor) and the exclude_from_vendor_snapshot property.
+
+	frameworkBp := `
+		cc_library_shared {
+			name: "libinclude",
+			srcs: ["src/include.cpp"],
+			vendor_available: true,
+		}
+		cc_library_shared {
+			name: "libexclude",
+			srcs: ["src/exclude.cpp"],
+			vendor: true,
+			exclude_from_vendor_snapshot: true,
+		}
+		cc_library_shared {
+			name: "libavailable_exclude",
+			srcs: ["src/exclude.cpp"],
+			vendor_available: true,
+			exclude_from_vendor_snapshot: true,
+		}
+	`
+
+	vendorProprietaryBp := `
+		cc_library_shared {
+			name: "libvendor",
+			srcs: ["vendor.cpp"],
+			vendor: true,
+		}
+	`
+
+	depsBp := GatherRequiredDepsForTest(android.Android)
+
+	mockFS := map[string][]byte{
+		"deps/Android.bp":       []byte(depsBp),
+		"framework/Android.bp":  []byte(frameworkBp),
+		"framework/include.cpp": nil,
+		"framework/exclude.cpp": nil,
+		"device/Android.bp":     []byte(vendorProprietaryBp),
+		"device/vendor.cpp":     nil,
+	}
+
+	config := TestConfig(buildDir, android.Android, nil, "", mockFS)
+	config.TestProductVariables.DeviceVndkVersion = StringPtr("current")
+	config.TestProductVariables.Platform_vndk_version = StringPtr("VER")
+	ctx := CreateTestContext(config)
+	ctx.Register()
+
+	_, errs := ctx.ParseFileList(".", []string{"deps/Android.bp", "framework/Android.bp", "device/Android.bp"})
+	android.FailIfErrored(t, errs)
+	_, errs = ctx.PrepareBuildActions(config)
+	android.FailIfErrored(t, errs)
+
+	// Test an include and exclude framework module.
+	assertExcludeFromVendorSnapshotIs(t, ctx, "libinclude", false)
+	assertExcludeFromVendorSnapshotIs(t, ctx, "libexclude", true)
+	assertExcludeFromVendorSnapshotIs(t, ctx, "libavailable_exclude", true)
+
+	// A vendor module is excluded, but by its path, not the
+	// exclude_from_vendor_snapshot property.
+	assertExcludeFromVendorSnapshotIs(t, ctx, "libvendor", false)
+
+	// Verify the content of the vendor snapshot.
+
+	snapshotDir := "vendor-snapshot"
+	snapshotVariantPath := filepath.Join(buildDir, snapshotDir, "arm64")
+	snapshotSingleton := ctx.SingletonForTests("vendor-snapshot")
+
+	var includeJsonFiles []string
+	var excludeJsonFiles []string
+
+	for _, arch := range [][]string{
+		[]string{"arm64", "armv8-a"},
+		[]string{"arm", "armv7-a-neon"},
+	} {
+		archType := arch[0]
+		archVariant := arch[1]
+		archDir := fmt.Sprintf("arch-%s-%s", archType, archVariant)
+
+		sharedVariant := fmt.Sprintf("android_vendor.VER_%s_%s_shared", archType, archVariant)
+		sharedDir := filepath.Join(snapshotVariantPath, archDir, "shared")
+
+		// Included modules
+		checkSnapshot(t, ctx, snapshotSingleton, "libinclude", "libinclude.so", sharedDir, sharedVariant)
+		includeJsonFiles = append(includeJsonFiles, filepath.Join(sharedDir, "libinclude.so.json"))
+
+		// Excluded modules
+		checkSnapshotExclude(t, ctx, snapshotSingleton, "libexclude", "libexclude.so", sharedDir, sharedVariant)
+		excludeJsonFiles = append(excludeJsonFiles, filepath.Join(sharedDir, "libexclude.so.json"))
+		checkSnapshotExclude(t, ctx, snapshotSingleton, "libvendor", "libvendor.so", sharedDir, sharedVariant)
+		excludeJsonFiles = append(excludeJsonFiles, filepath.Join(sharedDir, "libvendor.so.json"))
+		checkSnapshotExclude(t, ctx, snapshotSingleton, "libavailable_exclude", "libavailable_exclude.so", sharedDir, sharedVariant)
+		excludeJsonFiles = append(excludeJsonFiles, filepath.Join(sharedDir, "libavailable_exclude.so.json"))
+	}
+
+	// Verify that each json file for an included module has a rule.
+	for _, jsonFile := range includeJsonFiles {
+		if snapshotSingleton.MaybeOutput(jsonFile).Rule == nil {
+			t.Errorf("include json file %q not found", jsonFile)
+		}
+	}
+
+	// Verify that each json file for an excluded module has no rule.
+	for _, jsonFile := range excludeJsonFiles {
+		if snapshotSingleton.MaybeOutput(jsonFile).Rule != nil {
+			t.Errorf("exclude json file %q found", jsonFile)
+		}
+	}
+}
+
+func TestVendorSnapshotExcludeInVendorProprietaryPathErrors(t *testing.T) {
+
+	// This test verifies that using the exclude_from_vendor_snapshot
+	// property on a module in a vendor proprietary path generates an
+	// error. These modules are already excluded, so we prohibit using the
+	// property in this way, which could add to confusion.
+
+	vendorProprietaryBp := `
+		cc_library_shared {
+			name: "libvendor",
+			srcs: ["vendor.cpp"],
+			vendor: true,
+			exclude_from_vendor_snapshot: true,
+		}
+	`
+
+	depsBp := GatherRequiredDepsForTest(android.Android)
+
+	mockFS := map[string][]byte{
+		"deps/Android.bp":   []byte(depsBp),
+		"device/Android.bp": []byte(vendorProprietaryBp),
+		"device/vendor.cpp": nil,
+	}
+
+	config := TestConfig(buildDir, android.Android, nil, "", mockFS)
+	config.TestProductVariables.DeviceVndkVersion = StringPtr("current")
+	config.TestProductVariables.Platform_vndk_version = StringPtr("VER")
+	ctx := CreateTestContext(config)
+	ctx.Register()
+
+	_, errs := ctx.ParseFileList(".", []string{"deps/Android.bp", "device/Android.bp"})
+	android.FailIfErrored(t, errs)
+
+	_, errs = ctx.PrepareBuildActions(config)
+	android.CheckErrorsAgainstExpectations(t, errs, []string{
+		`module "libvendor\{.+,image:vendor.+,arch:arm64_.+\}" in vendor proprietary path "device" may not use "exclude_from_vendor_snapshot: true"`,
+		`module "libvendor\{.+,image:vendor.+,arch:arm_.+\}" in vendor proprietary path "device" may not use "exclude_from_vendor_snapshot: true"`,
+		`module "libvendor\{.+,image:vendor.+,arch:arm64_.+\}" in vendor proprietary path "device" may not use "exclude_from_vendor_snapshot: true"`,
+		`module "libvendor\{.+,image:vendor.+,arch:arm_.+\}" in vendor proprietary path "device" may not use "exclude_from_vendor_snapshot: true"`,
+		`module "libvendor\{.+,image:vendor.+,arch:arm64_.+\}" in vendor proprietary path "device" may not use "exclude_from_vendor_snapshot: true"`,
+		`module "libvendor\{.+,image:vendor.+,arch:arm_.+\}" in vendor proprietary path "device" may not use "exclude_from_vendor_snapshot: true"`,
+	})
+}
+
+func TestRecoverySnapshotCapture(t *testing.T) {
+	bp := `
+	cc_library {
+		name: "libvndk",
+		vendor_available: true,
+		recovery_available: true,
+		product_available: true,
+		vndk: {
+			enabled: true,
+		},
+		nocrt: true,
+	}
+
+	cc_library {
+		name: "librecovery",
+		recovery: true,
+		nocrt: true,
+	}
+
+	cc_library {
+		name: "librecovery_available",
+		recovery_available: true,
+		nocrt: true,
+	}
+
+	cc_library_headers {
+		name: "librecovery_headers",
+		recovery_available: true,
+		nocrt: true,
+	}
+
+	cc_binary {
+		name: "recovery_bin",
+		recovery: true,
+		nocrt: true,
+	}
+
+	cc_binary {
+		name: "recovery_available_bin",
+		recovery_available: true,
+		nocrt: true,
+	}
+
+	toolchain_library {
+		name: "libb",
+		recovery_available: true,
+		src: "libb.a",
+	}
+
+	cc_object {
+		name: "obj",
+		recovery_available: true,
+	}
+`
+	config := TestConfig(buildDir, android.Android, nil, bp, nil)
+	config.TestProductVariables.RecoverySnapshotVersion = StringPtr("current")
+	config.TestProductVariables.Platform_vndk_version = StringPtr("VER")
+	ctx := testCcWithConfig(t, config)
+
+	// Check Recovery snapshot output.
+
+	snapshotDir := "recovery-snapshot"
+	snapshotVariantPath := filepath.Join(buildDir, snapshotDir, "arm64")
+	snapshotSingleton := ctx.SingletonForTests("recovery-snapshot")
+
+	var jsonFiles []string
+
+	for _, arch := range [][]string{
+		[]string{"arm64", "armv8-a"},
+	} {
+		archType := arch[0]
+		archVariant := arch[1]
+		archDir := fmt.Sprintf("arch-%s-%s", archType, archVariant)
+
+		// For shared libraries, only recovery_available modules are captured.
+		sharedVariant := fmt.Sprintf("android_recovery_%s_%s_shared", archType, archVariant)
+		sharedDir := filepath.Join(snapshotVariantPath, archDir, "shared")
+		checkSnapshot(t, ctx, snapshotSingleton, "libvndk", "libvndk.so", sharedDir, sharedVariant)
+		checkSnapshot(t, ctx, snapshotSingleton, "librecovery", "librecovery.so", sharedDir, sharedVariant)
+		checkSnapshot(t, ctx, snapshotSingleton, "librecovery_available", "librecovery_available.so", sharedDir, sharedVariant)
+		jsonFiles = append(jsonFiles,
+			filepath.Join(sharedDir, "libvndk.so.json"),
+			filepath.Join(sharedDir, "librecovery.so.json"),
+			filepath.Join(sharedDir, "librecovery_available.so.json"))
+
+		// For static libraries, all recovery:true and recovery_available modules are captured.
+		staticVariant := fmt.Sprintf("android_recovery_%s_%s_static", archType, archVariant)
+		staticDir := filepath.Join(snapshotVariantPath, archDir, "static")
+		checkSnapshot(t, ctx, snapshotSingleton, "libb", "libb.a", staticDir, staticVariant)
+		checkSnapshot(t, ctx, snapshotSingleton, "librecovery", "librecovery.a", staticDir, staticVariant)
+		checkSnapshot(t, ctx, snapshotSingleton, "librecovery_available", "librecovery_available.a", staticDir, staticVariant)
+		jsonFiles = append(jsonFiles,
+			filepath.Join(staticDir, "libb.a.json"),
+			filepath.Join(staticDir, "librecovery.a.json"),
+			filepath.Join(staticDir, "librecovery_available.a.json"))
+
+		// For binary executables, all recovery:true and recovery_available modules are captured.
+		if archType == "arm64" {
+			binaryVariant := fmt.Sprintf("android_recovery_%s_%s", archType, archVariant)
+			binaryDir := filepath.Join(snapshotVariantPath, archDir, "binary")
+			checkSnapshot(t, ctx, snapshotSingleton, "recovery_bin", "recovery_bin", binaryDir, binaryVariant)
+			checkSnapshot(t, ctx, snapshotSingleton, "recovery_available_bin", "recovery_available_bin", binaryDir, binaryVariant)
+			jsonFiles = append(jsonFiles,
+				filepath.Join(binaryDir, "recovery_bin.json"),
+				filepath.Join(binaryDir, "recovery_available_bin.json"))
+		}
+
+		// For header libraries, all vendor:true and vendor_available modules are captured.
+		headerDir := filepath.Join(snapshotVariantPath, archDir, "header")
+		jsonFiles = append(jsonFiles, filepath.Join(headerDir, "librecovery_headers.json"))
+
+		// For object modules, all vendor:true and vendor_available modules are captured.
+		objectVariant := fmt.Sprintf("android_recovery_%s_%s", archType, archVariant)
+		objectDir := filepath.Join(snapshotVariantPath, archDir, "object")
+		checkSnapshot(t, ctx, snapshotSingleton, "obj", "obj.o", objectDir, objectVariant)
+		jsonFiles = append(jsonFiles, filepath.Join(objectDir, "obj.o.json"))
+	}
+
+	for _, jsonFile := range jsonFiles {
+		// verify all json files exist
+		if snapshotSingleton.MaybeOutput(jsonFile).Rule == nil {
+			t.Errorf("%q expected but not found", jsonFile)
+		}
+	}
+}
+
+func TestRecoverySnapshotExclude(t *testing.T) {
+	// This test verifies that the exclude_from_recovery_snapshot property
+	// makes its way from the Android.bp source file into the module data
+	// structure. It also verifies that modules are correctly included or
+	// excluded in the recovery snapshot based on their path (framework or
+	// vendor) and the exclude_from_recovery_snapshot property.
+
+	frameworkBp := `
+		cc_library_shared {
+			name: "libinclude",
+			srcs: ["src/include.cpp"],
+			recovery_available: true,
+		}
+		cc_library_shared {
+			name: "libexclude",
+			srcs: ["src/exclude.cpp"],
+			recovery: true,
+			exclude_from_recovery_snapshot: true,
+		}
+		cc_library_shared {
+			name: "libavailable_exclude",
+			srcs: ["src/exclude.cpp"],
+			recovery_available: true,
+			exclude_from_recovery_snapshot: true,
+		}
+	`
+
+	vendorProprietaryBp := `
+		cc_library_shared {
+			name: "librecovery",
+			srcs: ["recovery.cpp"],
+			recovery: true,
+		}
+	`
+
+	depsBp := GatherRequiredDepsForTest(android.Android)
+
+	mockFS := map[string][]byte{
+		"deps/Android.bp":       []byte(depsBp),
+		"framework/Android.bp":  []byte(frameworkBp),
+		"framework/include.cpp": nil,
+		"framework/exclude.cpp": nil,
+		"device/Android.bp":     []byte(vendorProprietaryBp),
+		"device/recovery.cpp":   nil,
+	}
+
+	config := TestConfig(buildDir, android.Android, nil, "", mockFS)
+	config.TestProductVariables.RecoverySnapshotVersion = StringPtr("current")
+	config.TestProductVariables.Platform_vndk_version = StringPtr("VER")
+	ctx := CreateTestContext(config)
+	ctx.Register()
+
+	_, errs := ctx.ParseFileList(".", []string{"deps/Android.bp", "framework/Android.bp", "device/Android.bp"})
+	android.FailIfErrored(t, errs)
+	_, errs = ctx.PrepareBuildActions(config)
+	android.FailIfErrored(t, errs)
+
+	// Test an include and exclude framework module.
+	assertExcludeFromRecoverySnapshotIs(t, ctx, "libinclude", false)
+	assertExcludeFromRecoverySnapshotIs(t, ctx, "libexclude", true)
+	assertExcludeFromRecoverySnapshotIs(t, ctx, "libavailable_exclude", true)
+
+	// A recovery module is excluded, but by its path, not the
+	// exclude_from_recovery_snapshot property.
+	assertExcludeFromRecoverySnapshotIs(t, ctx, "librecovery", false)
+
+	// Verify the content of the recovery snapshot.
+
+	snapshotDir := "recovery-snapshot"
+	snapshotVariantPath := filepath.Join(buildDir, snapshotDir, "arm64")
+	snapshotSingleton := ctx.SingletonForTests("recovery-snapshot")
+
+	var includeJsonFiles []string
+	var excludeJsonFiles []string
+
+	for _, arch := range [][]string{
+		[]string{"arm64", "armv8-a"},
+	} {
+		archType := arch[0]
+		archVariant := arch[1]
+		archDir := fmt.Sprintf("arch-%s-%s", archType, archVariant)
+
+		sharedVariant := fmt.Sprintf("android_recovery_%s_%s_shared", archType, archVariant)
+		sharedDir := filepath.Join(snapshotVariantPath, archDir, "shared")
+
+		// Included modules
+		checkSnapshot(t, ctx, snapshotSingleton, "libinclude", "libinclude.so", sharedDir, sharedVariant)
+		includeJsonFiles = append(includeJsonFiles, filepath.Join(sharedDir, "libinclude.so.json"))
+
+		// Excluded modules
+		checkSnapshotExclude(t, ctx, snapshotSingleton, "libexclude", "libexclude.so", sharedDir, sharedVariant)
+		excludeJsonFiles = append(excludeJsonFiles, filepath.Join(sharedDir, "libexclude.so.json"))
+		checkSnapshotExclude(t, ctx, snapshotSingleton, "librecovery", "librecovery.so", sharedDir, sharedVariant)
+		excludeJsonFiles = append(excludeJsonFiles, filepath.Join(sharedDir, "librecovery.so.json"))
+		checkSnapshotExclude(t, ctx, snapshotSingleton, "libavailable_exclude", "libavailable_exclude.so", sharedDir, sharedVariant)
+		excludeJsonFiles = append(excludeJsonFiles, filepath.Join(sharedDir, "libavailable_exclude.so.json"))
+	}
+
+	// Verify that each json file for an included module has a rule.
+	for _, jsonFile := range includeJsonFiles {
+		if snapshotSingleton.MaybeOutput(jsonFile).Rule == nil {
+			t.Errorf("include json file %q not found", jsonFile)
+		}
+	}
+
+	// Verify that each json file for an excluded module has no rule.
+	for _, jsonFile := range excludeJsonFiles {
+		if snapshotSingleton.MaybeOutput(jsonFile).Rule != nil {
+			t.Errorf("exclude json file %q found", jsonFile)
+		}
+	}
+}
diff --git a/cmd/multiproduct_kati/main.go b/cmd/multiproduct_kati/main.go
index 7dd50f6..e0f8caa 100644
--- a/cmd/multiproduct_kati/main.go
+++ b/cmd/multiproduct_kati/main.go
@@ -244,7 +244,7 @@
 		jobs = runtime.NumCPU() / 4
 
 		ramGb := int(config.TotalRAM() / 1024 / 1024 / 1024)
-		if ramJobs := ramGb / 20; ramGb > 0 && jobs > ramJobs {
+		if ramJobs := ramGb / 25; ramGb > 0 && jobs > ramJobs {
 			jobs = ramJobs
 		}
 
diff --git a/cmd/soong_build/main.go b/cmd/soong_build/main.go
index 1d5e7b3..8cd4f97 100644
--- a/cmd/soong_build/main.go
+++ b/cmd/soong_build/main.go
@@ -170,7 +170,7 @@
 	bp2buildCtx.SetNameInterface(newNameResolver(configuration))
 	bootstrap.Main(bp2buildCtx.Context, configuration, extraNinjaDeps...)
 
-	codegenContext := bp2build.NewCodegenContext(configuration, *bp2buildCtx)
+	codegenContext := bp2build.NewCodegenContext(configuration, *bp2buildCtx, bp2build.Bp2Build)
 	bp2build.Codegen(codegenContext)
 }
 
diff --git a/cmd/soong_build/queryview.go b/cmd/soong_build/queryview.go
index 305a224..5d61d0c 100644
--- a/cmd/soong_build/queryview.go
+++ b/cmd/soong_build/queryview.go
@@ -24,9 +24,9 @@
 
 func createBazelQueryView(ctx *android.Context, bazelQueryViewDir string) error {
 	ruleShims := bp2build.CreateRuleShims(android.ModuleTypeFactories())
-	buildToTargets := bp2build.GenerateSoongModuleTargets(*ctx, false)
+	buildToTargets := bp2build.GenerateSoongModuleTargets(*ctx, bp2build.QueryView)
 
-	filesToWrite := bp2build.CreateBazelFiles(ruleShims, buildToTargets, false)
+	filesToWrite := bp2build.CreateBazelFiles(ruleShims, buildToTargets, bp2build.QueryView)
 	for _, f := range filesToWrite {
 		if err := writeReadOnlyFile(bazelQueryViewDir, f); err != nil {
 			return err
diff --git a/dexpreopt/class_loader_context.go b/dexpreopt/class_loader_context.go
index 532d8fc..bf610ef 100644
--- a/dexpreopt/class_loader_context.go
+++ b/dexpreopt/class_loader_context.go
@@ -488,25 +488,26 @@
 	return clcHost, clcTarget, paths
 }
 
-// JSON representation of <uses-library> paths on host and on device.
-type jsonLibraryPath struct {
-	Host   string
-	Device string
+// Class loader contexts that come from Make via JSON dexpreopt.config. JSON CLC representation is
+// slightly different: it uses a map of library names to their CLC (instead of a list of structs
+// that including the name, as in the Soong CLC representation). The difference is insubstantial, it
+// is caused only by the language differerences between Go and JSON.
+type jsonClassLoaderContext struct {
+	Host        string
+	Device      string
+	Subcontexts map[string]*jsonClassLoaderContext
 }
 
-// Class loader contexts that come from Make (via JSON dexpreopt.config) files have simpler
-// structure than Soong class loader contexts: they are flat maps from a <uses-library> name to its
-// on-host and on-device paths. There are no nested subcontexts. It is a limitation of the current
-// Make implementation.
-type jsonClassLoaderContext map[string]jsonLibraryPath
+// A map of <uses-library> name to its on-host and on-device build paths and CLC.
+type jsonClassLoaderContexts map[string]*jsonClassLoaderContext
 
-// A map from SDK version (represented with a JSON string) to JSON class loader context.
-type jsonClassLoaderContextMap map[string]jsonClassLoaderContext
+// A map from SDK version (represented with a JSON string) to JSON CLCs.
+type jsonClassLoaderContextMap map[string]map[string]*jsonClassLoaderContext
 
-// Convert JSON class loader context map to ClassLoaderContextMap.
+// Convert JSON CLC map to Soong represenation.
 func fromJsonClassLoaderContext(ctx android.PathContext, jClcMap jsonClassLoaderContextMap) ClassLoaderContextMap {
 	clcMap := make(ClassLoaderContextMap)
-	for sdkVerStr, clc := range jClcMap {
+	for sdkVerStr, clcs := range jClcMap {
 		sdkVer, ok := strconv.Atoi(sdkVerStr)
 		if ok != nil {
 			if sdkVerStr == "any" {
@@ -515,14 +516,21 @@
 				android.ReportPathErrorf(ctx, "failed to parse SDK version in dexpreopt.config: '%s'", sdkVerStr)
 			}
 		}
-		for lib, path := range clc {
-			clcMap[sdkVer] = append(clcMap[sdkVer], &ClassLoaderContext{
-				Name:        lib,
-				Host:        constructPath(ctx, path.Host),
-				Device:      path.Device,
-				Subcontexts: nil,
-			})
-		}
+		clcMap[sdkVer] = fromJsonClassLoaderContextRec(ctx, clcs)
 	}
 	return clcMap
 }
+
+// Recursive helper for fromJsonClassLoaderContext.
+func fromJsonClassLoaderContextRec(ctx android.PathContext, jClcs map[string]*jsonClassLoaderContext) []*ClassLoaderContext {
+	clcs := make([]*ClassLoaderContext, 0, len(jClcs))
+	for lib, clc := range jClcs {
+		clcs = append(clcs, &ClassLoaderContext{
+			Name:        lib,
+			Host:        constructPath(ctx, clc.Host),
+			Device:      clc.Device,
+			Subcontexts: fromJsonClassLoaderContextRec(ctx, clc.Subcontexts),
+		})
+	}
+	return clcs
+}
diff --git a/dexpreopt/testing.go b/dexpreopt/testing.go
index b572eb3..bccbfc1 100644
--- a/dexpreopt/testing.go
+++ b/dexpreopt/testing.go
@@ -34,7 +34,7 @@
 	return module
 }
 
-func RegisterToolModulesForTest(ctx *android.TestContext) {
+func RegisterToolModulesForTest(ctx android.RegistrationContext) {
 	ctx.RegisterModuleType("dummy_tool_binary", dummyToolBinaryFactory)
 }
 
diff --git a/filesystem/filesystem.go b/filesystem/filesystem.go
index 5ef4a90..654617c 100644
--- a/filesystem/filesystem.go
+++ b/filesystem/filesystem.go
@@ -146,7 +146,7 @@
 	builder.Command().Text("rm").Flag("-rf").Output(propFile)
 	for _, p := range props {
 		builder.Command().
-			Text("echo").Flag("-e").
+			Text("echo").
 			Flag(`"` + p.name + "=" + p.value + `"`).
 			Text(">>").Output(propFile)
 	}
diff --git a/genrule/genrule.go b/genrule/genrule.go
index 8df32f2..ddfb459 100644
--- a/genrule/genrule.go
+++ b/genrule/genrule.go
@@ -46,6 +46,8 @@
 	ctx.FinalDepsMutators(func(ctx android.RegisterMutatorsContext) {
 		ctx.BottomUp("genrule_tool_deps", toolDepsMutator).Parallel()
 	})
+
+	android.RegisterBp2BuildMutator("genrule", GenruleBp2Build)
 }
 
 var (
@@ -772,6 +774,74 @@
 	Out []string `android:"arch_variant"`
 }
 
+type bazelGenruleAttributes struct {
+	Name  *string
+	Srcs  []string
+	Outs  []string
+	Tools []string
+	Cmd   string
+}
+
+type bazelGenrule struct {
+	android.BazelTargetModuleBase
+	bazelGenruleAttributes
+}
+
+func BazelGenruleFactory() android.Module {
+	module := &bazelGenrule{}
+	module.AddProperties(&module.bazelGenruleAttributes)
+	android.InitBazelTargetModule(module)
+	return module
+}
+
+func GenruleBp2Build(ctx android.TopDownMutatorContext) {
+	if m, ok := ctx.Module().(*Module); ok {
+		name := "__bp2build__" + m.Name()
+		// Bazel only has the "tools" attribute.
+		tools := append(m.properties.Tools, m.properties.Tool_files...)
+
+		// Replace in and out variables with $< and $@
+		var cmd string
+		if m.properties.Cmd != nil {
+			cmd = strings.Replace(*m.properties.Cmd, "$(in)", "$(SRCS)", -1)
+			cmd = strings.Replace(cmd, "$(out)", "$(OUTS)", -1)
+			cmd = strings.Replace(cmd, "$(genDir)", "$(GENDIR)", -1)
+			if len(tools) > 0 {
+				cmd = strings.Replace(cmd, "$(location)", fmt.Sprintf("$(location %s)", tools[0]), -1)
+				cmd = strings.Replace(cmd, "$(locations)", fmt.Sprintf("$(locations %s)", tools[0]), -1)
+			}
+		}
+
+		// The Out prop is not in an immediately accessible field
+		// in the Module struct, so use GetProperties and cast it
+		// to the known struct prop.
+		var outs []string
+		for _, propIntf := range m.GetProperties() {
+			if props, ok := propIntf.(*genRuleProperties); ok {
+				outs = props.Out
+				break
+			}
+		}
+
+		// Create the BazelTargetModule.
+		ctx.CreateModule(BazelGenruleFactory, &bazelGenruleAttributes{
+			Name:  proptools.StringPtr(name),
+			Srcs:  m.properties.Srcs,
+			Outs:  outs,
+			Cmd:   cmd,
+			Tools: tools,
+		}, &bazel.BazelTargetModuleProperties{
+			Rule_class: "genrule",
+		})
+	}
+}
+
+func (m *bazelGenrule) Name() string {
+	return m.BaseModuleName()
+}
+
+func (m *bazelGenrule) GenerateAndroidBuildActions(ctx android.ModuleContext) {}
+
 var Bool = proptools.Bool
 var String = proptools.String
 
diff --git a/java/Android.bp b/java/Android.bp
index 9c28968..364566a 100644
--- a/java/Android.bp
+++ b/java/Android.bp
@@ -24,6 +24,7 @@
         "app.go",
         "app_import.go",
         "app_set.go",
+        "boot_image.go",
         "boot_jars.go",
         "builder.go",
         "device_host_converter.go",
@@ -63,6 +64,7 @@
         "app_import_test.go",
         "app_set_test.go",
         "app_test.go",
+        "boot_image_test.go",
         "device_host_converter_test.go",
         "dexpreopt_test.go",
         "dexpreopt_bootjars_test.go",
diff --git a/java/boot_image.go b/java/boot_image.go
new file mode 100644
index 0000000..07ef0d8
--- /dev/null
+++ b/java/boot_image.go
@@ -0,0 +1,85 @@
+// 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 java
+
+import (
+	"strings"
+
+	"android/soong/android"
+	"github.com/google/blueprint"
+)
+
+func init() {
+	RegisterBootImageBuildComponents(android.InitRegistrationContext)
+}
+
+func RegisterBootImageBuildComponents(ctx android.RegistrationContext) {
+	ctx.RegisterModuleType("boot_image", bootImageFactory)
+}
+
+type bootImageProperties struct {
+	// The name of the image this represents.
+	//
+	// Must be one of "art" or "boot".
+	Image_name string
+}
+
+type BootImageModule struct {
+	android.ModuleBase
+
+	properties bootImageProperties
+}
+
+func bootImageFactory() android.Module {
+	m := &BootImageModule{}
+	m.AddProperties(&m.properties)
+	android.InitAndroidArchModule(m, android.HostAndDeviceDefault, android.MultilibCommon)
+	return m
+}
+
+var BootImageInfoProvider = blueprint.NewProvider(BootImageInfo{})
+
+type BootImageInfo struct {
+	// The image config, internal to this module (and the dex_bootjars singleton).
+	imageConfig *bootImageConfig
+}
+
+func (i BootImageInfo) Modules() android.ConfiguredJarList {
+	return i.imageConfig.modules
+}
+
+func (b *BootImageModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+	// Nothing to do if skipping the dexpreopt of boot image jars.
+	if SkipDexpreoptBootJars(ctx) {
+		return
+	}
+
+	// Get a map of the image configs that are supported.
+	imageConfigs := genBootImageConfigs(ctx)
+
+	// Retrieve the config for this image.
+	imageName := b.properties.Image_name
+	imageConfig := imageConfigs[imageName]
+	if imageConfig == nil {
+		ctx.PropertyErrorf("image_name", "Unknown image name %q, expected one of %s", imageName, strings.Join(android.SortedStringKeys(imageConfigs), ", "))
+		return
+	}
+
+	// Construct the boot image info from the config.
+	info := BootImageInfo{imageConfig: imageConfig}
+
+	// Make it available for other modules.
+	ctx.SetProvider(BootImageInfoProvider, info)
+}
diff --git a/java/boot_image_test.go b/java/boot_image_test.go
new file mode 100644
index 0000000..a295782
--- /dev/null
+++ b/java/boot_image_test.go
@@ -0,0 +1,31 @@
+// 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 java
+
+import (
+	"testing"
+)
+
+// Contains some simple tests for boot_image logic, additional tests can be found in
+// apex/boot_image_test.go as the ART boot image requires modules from the ART apex.
+
+func TestUnknownBootImage(t *testing.T) {
+	testJavaError(t, "image_name: Unknown image name \\\"unknown\\\", expected one of art, boot", `
+		boot_image {
+			name: "unknown-boot-image",
+			image_name: "unknown",
+		}
+`)
+}
diff --git a/java/dexpreopt_bootjars.go b/java/dexpreopt_bootjars.go
index 004cbbb..78d9d02 100644
--- a/java/dexpreopt_bootjars.go
+++ b/java/dexpreopt_bootjars.go
@@ -35,6 +35,13 @@
 //
 // Changes:
 // 1) dex_bootjars is now a singleton module and not a plain singleton.
+// 2) Boot images are now represented by the boot_image module type.
+// 3) The art boot image is called "art-boot-image", the framework boot image is called
+//    "framework-boot-image".
+// 4) They are defined in art/build/boot/Android.bp and frameworks/base/boot/Android.bp
+//    respectively.
+// 5) Each boot_image retrieves the appropriate boot image configuration from the map returned by
+//    genBootImageConfigs() using the image_name specified in the boot_image module.
 // =================================================================================================
 
 // This comment describes:
diff --git a/java/java_test.go b/java/java_test.go
index 7b89848..e7776c3 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -59,8 +59,6 @@
 }
 
 func testConfig(env map[string]string, bp string, fs map[string][]byte) android.Config {
-	bp += dexpreopt.BpToolModulesForTest()
-
 	return TestConfig(buildDir, env, bp, fs)
 }
 
@@ -84,8 +82,6 @@
 	// Register module types and mutators from cc needed for JNI testing
 	cc.RegisterRequiredBuildComponentsForTest(ctx)
 
-	dexpreopt.RegisterToolModulesForTest(ctx)
-
 	ctx.PostDepsMutators(func(ctx android.RegisterMutatorsContext) {
 		ctx.TopDown("propagate_rro_enforcement", propagateRROEnforcementMutator).Parallel()
 	})
diff --git a/java/testing.go b/java/testing.go
index 445b8b2..31ff47f 100644
--- a/java/testing.go
+++ b/java/testing.go
@@ -107,6 +107,7 @@
 	RegisterAppBuildComponents(ctx)
 	RegisterAppImportBuildComponents(ctx)
 	RegisterAppSetBuildComponents(ctx)
+	RegisterBootImageBuildComponents(ctx)
 	RegisterDexpreoptBootJarsComponents(ctx)
 	RegisterDocsBuildComponents(ctx)
 	RegisterGenRuleBuildComponents(ctx)
@@ -116,6 +117,9 @@
 	RegisterSdkLibraryBuildComponents(ctx)
 	RegisterStubsBuildComponents(ctx)
 	RegisterSystemModulesBuildComponents(ctx)
+
+	// Make sure that any tool related module types needed by dexpreopt have been registered.
+	dexpreopt.RegisterToolModulesForTest(ctx)
 }
 
 // Gather the module definitions needed by tests that depend upon code from this package.
@@ -207,11 +211,24 @@
 		`, extra)
 	}
 
+	// Make sure that any tools needed for dexpreopting are defined.
+	bp += dexpreopt.BpToolModulesForTest()
+
 	// Make sure that the dex_bootjars singleton module is instantiated for the tests.
 	bp += `
 		dex_bootjars {
 			name: "dex_bootjars",
 		}
+
+		boot_image {
+			name: "art-boot-image",
+			image_name: "art",
+		}
+
+		boot_image {
+			name: "framework-boot-image",
+			image_name: "boot",
+		}
 `
 
 	return bp
diff --git a/licenses/Android.bp b/licenses/Android.bp
index 8032dc5..f4a76d7 100644
--- a/licenses/Android.bp
+++ b/licenses/Android.bp
@@ -14,1074 +14,1249 @@
 // limitations under the License.
 
 package {
-	default_visibility: ["//visibility:public"],
-	default_applicable_licenses: ["Android-Apache-2.0"],
+    default_visibility: ["//visibility:public"],
+    default_applicable_licenses: ["Android-Apache-2.0"],
 }
 
 license {
-	name: "Android-Apache-2.0",
-	license_kinds: ["SPDX-license-identifier-Apache-2.0"],
-	copyright_notice: "Copyright (C) The Android Open Source Project",
-	license_text: ["LICENSE"],
+    name: "Android-Apache-2.0",
+    license_kinds: ["SPDX-license-identifier-Apache-2.0"],
+    copyright_notice: "Copyright (C) The Android Open Source Project",
+    license_text: ["LICENSE"],
 }
 
 license_kind {
-	name: "SPDX-license-identifier-AFL-1.1",
-	conditions: ["by_exception_only"],
-	url: "https://spdx.org/licenses/AFL-1.1.html",
+    name: "SPDX-license-identifier-0BSD",
+    conditions: ["unencumbered"],
+    url: "https://spdx.org/licenses/0BSD",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-AFL-1.2",
-	conditions: ["by_exception_only"],
-	url: "https://spdx.org/licenses/AFL-1.2.html",
+    name: "SPDX-license-identifier-AFL-1.1",
+    conditions: ["by_exception_only"],
+    url: "https://spdx.org/licenses/AFL-1.1.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-AFL-2.0",
-	conditions: ["by_exception_only"],
-	url: "https://spdx.org/licenses/AFL-2.0.html",
+    name: "SPDX-license-identifier-AFL-1.2",
+    conditions: ["by_exception_only"],
+    url: "https://spdx.org/licenses/AFL-1.2.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-AFL-2.1",
-	conditions: ["notice"],
-	url: "https://spdx.org/licenses/AFL-2.1.html",
+    name: "SPDX-license-identifier-AFL-2.0",
+    conditions: ["by_exception_only"],
+    url: "https://spdx.org/licenses/AFL-2.0.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-AFL-3.0",
-	conditions: ["notice"],
-	url: "https://spdx.org/licenses/AFL-3.0.html",
+    name: "SPDX-license-identifier-AFL-2.1",
+    conditions: ["notice"],
+    url: "https://spdx.org/licenses/AFL-2.1.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-AGPL",
-	conditions: ["by_exception_only", "not_allowed"],
-	url: "https://spdx.org/licenses/AGPL.html",
+    name: "SPDX-license-identifier-AFL-3.0",
+    conditions: ["notice"],
+    url: "https://spdx.org/licenses/AFL-3.0.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-AGPL-1.0",
-	conditions: ["by_exception_only", "not_allowed"],
-	url: "https://spdx.org/licenses/AGPL-1.0.html",
+    name: "SPDX-license-identifier-AGPL",
+    conditions: [
+        "by_exception_only",
+        "not_allowed",
+    ],
+    url: "https://spdx.org/licenses/AGPL.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-AGPL-1.0-only",
-	conditions: ["by_exception_only", "not_allowed"],
-	url: "https://spdx.org/licenses/AGPL-1.0-only.html",
+    name: "SPDX-license-identifier-AGPL-1.0",
+    conditions: [
+        "by_exception_only",
+        "not_allowed",
+    ],
+    url: "https://spdx.org/licenses/AGPL-1.0.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-AGPL-1.0-or-later",
-	conditions: ["by_exception_only", "not_allowed"],
-	url: "https://spdx.org/licenses/AGPL-1.0-or-later.html",
+    name: "SPDX-license-identifier-AGPL-1.0-only",
+    conditions: [
+        "by_exception_only",
+        "not_allowed",
+    ],
+    url: "https://spdx.org/licenses/AGPL-1.0-only.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-AGPL-3.0",
-	conditions: ["by_exception_only", "not_allowed"],
-	url: "https://spdx.org/licenses/AGPL-3.0.html",
+    name: "SPDX-license-identifier-AGPL-1.0-or-later",
+    conditions: [
+        "by_exception_only",
+        "not_allowed",
+    ],
+    url: "https://spdx.org/licenses/AGPL-1.0-or-later.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-AGPL-3.0-only",
-	conditions: ["by_exception_only", "not_allowed"],
-	url: "https://spdx.org/licenses/AGPL-3.0-only.html",
+    name: "SPDX-license-identifier-AGPL-3.0",
+    conditions: [
+        "by_exception_only",
+        "not_allowed",
+    ],
+    url: "https://spdx.org/licenses/AGPL-3.0.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-AGPL-3.0-or-later",
-	conditions: ["by_exception_only", "not_allowed"],
-	url: "https://spdx.org/licenses/AGPL-3.0-or-later.html",
+    name: "SPDX-license-identifier-AGPL-3.0-only",
+    conditions: [
+        "by_exception_only",
+        "not_allowed",
+    ],
+    url: "https://spdx.org/licenses/AGPL-3.0-only.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-Apache",
-	conditions: ["notice"],
+    name: "SPDX-license-identifier-AGPL-3.0-or-later",
+    conditions: [
+        "by_exception_only",
+        "not_allowed",
+    ],
+    url: "https://spdx.org/licenses/AGPL-3.0-or-later.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-Apache-1.0",
-	conditions: ["notice"],
-	url: "https://spdx.org/licenses/Apache-1.0.html",
+    name: "SPDX-license-identifier-APSL-1.1",
+    conditions: [
+        "reciprocal",
+    ],
+    url: "https://spdx.org/licenses/APSL-1.1.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-Apache-1.1",
-	conditions: ["notice"],
-	url: "https://spdx.org/licenses/Apache-1.1.html",
+    name: "SPDX-license-identifier-APSL-2.0",
+    conditions: [
+        "reciprocal",
+    ],
+    url: "https://spdx.org/licenses/APSL-2.0.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-Apache-2.0",
-	conditions: ["notice"],
-	url: "https://spdx.org/licenses/Apache-2.0.html",
+    name: "SPDX-license-identifier-Apache",
+    conditions: ["notice"],
 }
 
 license_kind {
-	name: "SPDX-license-identifier-Artistic",
-	conditions: ["notice"],
+    name: "SPDX-license-identifier-Apache-1.0",
+    conditions: ["notice"],
+    url: "https://spdx.org/licenses/Apache-1.0.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-Artistic-1.0",
-	conditions: ["notice"],
-	url: "https://spdx.org/licenses/Artistic-1.0.html",
+    name: "SPDX-license-identifier-Apache-1.1",
+    conditions: ["notice"],
+    url: "https://spdx.org/licenses/Apache-1.1.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-Artistic-1.0-Perl",
-	conditions: ["notice"],
-	url: "https://spdx.org/licenses/Artistic-1.0-Perl.html",
+    name: "SPDX-license-identifier-Apache-2.0",
+    conditions: ["notice"],
+    url: "https://spdx.org/licenses/Apache-2.0.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-Artistic-1.0-cl8",
-	conditions: ["notice"],
-	url: "https://spdx.org/licenses/Artistic-1.0-cl8.html",
+    name: "SPDX-license-identifier-Artistic",
+    conditions: ["notice"],
 }
 
 license_kind {
-	name: "SPDX-license-identifier-Artistic-2.0",
-	conditions: ["notice"],
-	url: "https://spdx.org/licenses/Artistic-2.0.html",
+    name: "SPDX-license-identifier-Artistic-1.0",
+    conditions: ["notice"],
+    url: "https://spdx.org/licenses/Artistic-1.0.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-BSD",
-	conditions: ["notice"],
+    name: "SPDX-license-identifier-Artistic-1.0-Perl",
+    conditions: ["notice"],
+    url: "https://spdx.org/licenses/Artistic-1.0-Perl.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-BSD-1-Clause",
-	conditions: ["notice"],
-	url: "https://spdx.org/licenses/BSD-1-Clause.html",
+    name: "SPDX-license-identifier-Artistic-1.0-cl8",
+    conditions: ["notice"],
+    url: "https://spdx.org/licenses/Artistic-1.0-cl8.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-BSD-2-Clause",
-	conditions: ["notice"],
-	url: "https://spdx.org/licenses/BSD-2-Clause.html",
+    name: "SPDX-license-identifier-Artistic-2.0",
+    conditions: ["notice"],
+    url: "https://spdx.org/licenses/Artistic-2.0.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-BSD-2-Clause-FreeBSD",
-	conditions: ["notice"],
-	url: "https://spdx.org/licenses/BSD-2-Clause-FreeBSD.html",
+    name: "SPDX-license-identifier-BSD",
+    conditions: ["notice"],
 }
 
 license_kind {
-	name: "SPDX-license-identifier-BSD-2-Clause-NetBSD",
-	conditions: ["notice"],
-	url: "https://spdx.org/licenses/BSD-2-Clause-NetBSD.html",
+    name: "SPDX-license-identifier-BSD-1-Clause",
+    conditions: ["notice"],
+    url: "https://spdx.org/licenses/BSD-1-Clause.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-BSD-2-Clause-Patent",
-	conditions: ["notice"],
-	url: "https://spdx.org/licenses/BSD-2-Clause-Patent.html",
+    name: "SPDX-license-identifier-BSD-2-Clause",
+    conditions: ["notice"],
+    url: "https://spdx.org/licenses/BSD-2-Clause.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-BSD-3-Clause",
-	conditions: ["notice"],
-	url: "https://spdx.org/licenses/BSD-3-Clause.html",
+    name: "SPDX-license-identifier-BSD-2-Clause-FreeBSD",
+    conditions: ["notice"],
+    url: "https://spdx.org/licenses/BSD-2-Clause-FreeBSD.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-BSD-3-Clause-Attribution",
-	conditions: ["notice"],
-	url: "https://spdx.org/licenses/BSD-3-Clause-Attribution.html",
+    name: "SPDX-license-identifier-BSD-2-Clause-NetBSD",
+    conditions: ["notice"],
+    url: "https://spdx.org/licenses/BSD-2-Clause-NetBSD.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-BSD-3-Clause-Clear",
-	conditions: ["notice"],
-	url: "https://spdx.org/licenses/BSD-3-Clause-Clear.html",
+    name: "SPDX-license-identifier-BSD-2-Clause-Patent",
+    conditions: ["notice"],
+    url: "https://spdx.org/licenses/BSD-2-Clause-Patent.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-BSD-3-Clause-LBNL",
-	conditions: ["notice"],
-	url: "https://spdx.org/licenses/BSD-3-Clause-LBNL.html",
+    name: "SPDX-license-identifier-BSD-3-Clause",
+    conditions: ["notice"],
+    url: "https://spdx.org/licenses/BSD-3-Clause.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-BSD-3-Clause-No-Nuclear-License",
-	conditions: ["notice"],
-	url: "https://spdx.org/licenses/BSD-3-Clause-No-Nuclear-License.html",
+    name: "SPDX-license-identifier-BSD-3-Clause-Attribution",
+    conditions: ["notice"],
+    url: "https://spdx.org/licenses/BSD-3-Clause-Attribution.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-BSD-3-Clause-No-Nuclear-License-2014",
-	conditions: ["notice"],
-	url: "https://spdx.org/licenses/BSD-3-Clause-No-Nuclear-License-2014.html",
+    name: "SPDX-license-identifier-BSD-3-Clause-Clear",
+    conditions: ["notice"],
+    url: "https://spdx.org/licenses/BSD-3-Clause-Clear.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-BSD-3-Clause-No-Nuclear-Warranty",
-	conditions: ["notice"],
-	url: "https://spdx.org/licenses/BSD-3-Clause-No-Nuclear-Warranty.html",
+    name: "SPDX-license-identifier-BSD-3-Clause-LBNL",
+    conditions: ["notice"],
+    url: "https://spdx.org/licenses/BSD-3-Clause-LBNL.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-BSD-3-Clause-Open-MPI",
-	conditions: ["notice"],
-	url: "https://spdx.org/licenses/BSD-3-Clause-Open-MPI.html",
+    name: "SPDX-license-identifier-BSD-3-Clause-No-Nuclear-License",
+    conditions: ["notice"],
+    url: "https://spdx.org/licenses/BSD-3-Clause-No-Nuclear-License.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-BSD-4-Clause",
-	conditions: ["notice"],
-	url: "https://spdx.org/licenses/BSD-4-Clause.html",
+    name: "SPDX-license-identifier-BSD-3-Clause-No-Nuclear-License-2014",
+    conditions: ["notice"],
+    url: "https://spdx.org/licenses/BSD-3-Clause-No-Nuclear-License-2014.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-BSD-4-Clause-UC",
-	conditions: ["notice"],
-	url: "https://spdx.org/licenses/BSD-4-Clause-UC.html",
+    name: "SPDX-license-identifier-BSD-3-Clause-No-Nuclear-Warranty",
+    conditions: ["notice"],
+    url: "https://spdx.org/licenses/BSD-3-Clause-No-Nuclear-Warranty.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-BSD-Protection",
-	conditions: ["notice"],
-	url: "https://spdx.org/licenses/BSD-Protection.html",
+    name: "SPDX-license-identifier-BSD-3-Clause-Open-MPI",
+    conditions: ["notice"],
+    url: "https://spdx.org/licenses/BSD-3-Clause-Open-MPI.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-BSD-Source-Code",
-	conditions: ["notice"],
-	url: "https://spdx.org/licenses/BSD-Source-Code.html",
+    name: "SPDX-license-identifier-BSD-4-Clause",
+    conditions: ["notice"],
+    url: "https://spdx.org/licenses/BSD-4-Clause.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-BSL-1.0",
-	conditions: ["notice"],
-	url: "https://spdx.org/licenses/BSL-1.0.html",
+    name: "SPDX-license-identifier-BSD-4-Clause-UC",
+    conditions: ["notice"],
+    url: "https://spdx.org/licenses/BSD-4-Clause-UC.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-Beerware",
-	conditions: ["by_exception_only", "not_allowed"],
-	url: "https://spdx.org/licenses/Beerware.html",
+    name: "SPDX-license-identifier-BSD-Protection",
+    conditions: ["notice"],
+    url: "https://spdx.org/licenses/BSD-Protection.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-CC-BY",
-	conditions: ["notice"],
+    name: "SPDX-license-identifier-BSD-Source-Code",
+    conditions: ["notice"],
+    url: "https://spdx.org/licenses/BSD-Source-Code.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-CC-BY-1.0",
-	conditions: ["notice"],
-	url: "https://spdx.org/licenses/CC-BY-1.0.html",
+    name: "SPDX-license-identifier-BSL-1.0",
+    conditions: ["notice"],
+    url: "https://spdx.org/licenses/BSL-1.0.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-CC-BY-2.0",
-	conditions: ["notice"],
-	url: "https://spdx.org/licenses/CC-BY-2.0.html",
+    name: "SPDX-license-identifier-Beerware",
+    conditions: [
+        "by_exception_only",
+        "not_allowed",
+    ],
+    url: "https://spdx.org/licenses/Beerware.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-CC-BY-2.5",
-	conditions: ["notice"],
-	url: "https://spdx.org/licenses/CC-BY-2.5.html",
+    name: "SPDX-license-identifier-CC-BY",
+    conditions: ["notice"],
 }
 
 license_kind {
-	name: "SPDX-license-identifier-CC-BY-3.0",
-	conditions: ["notice"],
-	url: "https://spdx.org/licenses/CC-BY-3.0.html",
+    name: "SPDX-license-identifier-CC-BY-1.0",
+    conditions: ["notice"],
+    url: "https://spdx.org/licenses/CC-BY-1.0.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-CC-BY-4.0",
-	conditions: ["notice"],
-	url: "https://spdx.org/licenses/CC-BY-4.0.html",
+    name: "SPDX-license-identifier-CC-BY-2.0",
+    conditions: ["notice"],
+    url: "https://spdx.org/licenses/CC-BY-2.0.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-CC-BY-NC",
-	conditions: ["by_exception_only", "not_allowed"],
+    name: "SPDX-license-identifier-CC-BY-2.5",
+    conditions: ["notice"],
+    url: "https://spdx.org/licenses/CC-BY-2.5.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-CC-BY-NC-1.0",
-	conditions: ["by_exception_only", "not_allowed"],
-	url: "https://spdx.org/licenses/CC-BY-NC-1.0.html",
+    name: "SPDX-license-identifier-CC-BY-3.0",
+    conditions: ["notice"],
+    url: "https://spdx.org/licenses/CC-BY-3.0.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-CC-BY-NC-2.0",
-	conditions: ["by_exception_only", "not_allowed"],
-	url: "https://spdx.org/licenses/CC-BY-NC-2.0.html",
+    name: "SPDX-license-identifier-CC-BY-4.0",
+    conditions: ["notice"],
+    url: "https://spdx.org/licenses/CC-BY-4.0.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-CC-BY-NC-2.5",
-	conditions: ["by_exception_only", "not_allowed"],
-	url: "https://spdx.org/licenses/CC-BY-NC-2.5.html",
+    name: "SPDX-license-identifier-CC-BY-NC",
+    conditions: [
+        "by_exception_only",
+        "not_allowed",
+    ],
 }
 
 license_kind {
-	name: "SPDX-license-identifier-CC-BY-NC-3.0",
-	conditions: ["by_exception_only", "not_allowed"],
-	url: "https://spdx.org/licenses/CC-BY-NC-3.0.html",
+    name: "SPDX-license-identifier-CC-BY-NC-1.0",
+    conditions: [
+        "by_exception_only",
+        "not_allowed",
+    ],
+    url: "https://spdx.org/licenses/CC-BY-NC-1.0.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-CC-BY-NC-4.0",
-	conditions: ["by_exception_only", "not_allowed"],
-	url: "https://spdx.org/licenses/CC-BY-NC-4.0.html",
+    name: "SPDX-license-identifier-CC-BY-NC-2.0",
+    conditions: [
+        "by_exception_only",
+        "not_allowed",
+    ],
+    url: "https://spdx.org/licenses/CC-BY-NC-2.0.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-CC-BY-NC-ND-1.0",
-	conditions: ["by_exception_only", "not_allowed"],
-	url: "https://spdx.org/licenses/CC-BY-NC-ND-1.0.html",
+    name: "SPDX-license-identifier-CC-BY-NC-2.5",
+    conditions: [
+        "by_exception_only",
+        "not_allowed",
+    ],
+    url: "https://spdx.org/licenses/CC-BY-NC-2.5.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-CC-BY-NC-ND-2.0",
-	conditions: ["by_exception_only", "not_allowed"],
-	url: "https://spdx.org/licenses/CC-BY-NC-ND-2.0.html",
+    name: "SPDX-license-identifier-CC-BY-NC-3.0",
+    conditions: [
+        "by_exception_only",
+        "not_allowed",
+    ],
+    url: "https://spdx.org/licenses/CC-BY-NC-3.0.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-CC-BY-NC-ND-2.5",
-	conditions: ["by_exception_only", "not_allowed"],
-	url: "https://spdx.org/licenses/CC-BY-NC-ND-2.5.html",
+    name: "SPDX-license-identifier-CC-BY-NC-4.0",
+    conditions: [
+        "by_exception_only",
+        "not_allowed",
+    ],
+    url: "https://spdx.org/licenses/CC-BY-NC-4.0.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-CC-BY-NC-ND-3.0",
-	conditions: ["by_exception_only", "not_allowed"],
-	url: "https://spdx.org/licenses/CC-BY-NC-ND-3.0.html",
+    name: "SPDX-license-identifier-CC-BY-NC-ND-1.0",
+    conditions: [
+        "by_exception_only",
+        "not_allowed",
+    ],
+    url: "https://spdx.org/licenses/CC-BY-NC-ND-1.0.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-CC-BY-NC-ND-4.0",
-	conditions: ["by_exception_only", "not_allowed"],
-	url: "https://spdx.org/licenses/CC-BY-NC-ND-4.0.html",
+    name: "SPDX-license-identifier-CC-BY-NC-ND-2.0",
+    conditions: [
+        "by_exception_only",
+        "not_allowed",
+    ],
+    url: "https://spdx.org/licenses/CC-BY-NC-ND-2.0.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-CC-BY-NC-SA-1.0",
-	conditions: ["by_exception_only", "not_allowed"],
-	url: "https://spdx.org/licenses/CC-BY-NC-SA-1.0.html",
+    name: "SPDX-license-identifier-CC-BY-NC-ND-2.5",
+    conditions: [
+        "by_exception_only",
+        "not_allowed",
+    ],
+    url: "https://spdx.org/licenses/CC-BY-NC-ND-2.5.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-CC-BY-NC-SA-2.0",
-	conditions: ["by_exception_only", "not_allowed"],
-	url: "https://spdx.org/licenses/CC-BY-NC-SA-2.0.html",
+    name: "SPDX-license-identifier-CC-BY-NC-ND-3.0",
+    conditions: [
+        "by_exception_only",
+        "not_allowed",
+    ],
+    url: "https://spdx.org/licenses/CC-BY-NC-ND-3.0.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-CC-BY-NC-SA-2.5",
-	conditions: ["by_exception_only", "not_allowed"],
-	url: "https://spdx.org/licenses/CC-BY-NC-SA-2.5.html",
+    name: "SPDX-license-identifier-CC-BY-NC-ND-4.0",
+    conditions: [
+        "by_exception_only",
+        "not_allowed",
+    ],
+    url: "https://spdx.org/licenses/CC-BY-NC-ND-4.0.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-CC-BY-NC-SA-3.0",
-	conditions: ["by_exception_only", "not_allowed"],
-	url: "https://spdx.org/licenses/CC-BY-NC-SA-3.0.html",
+    name: "SPDX-license-identifier-CC-BY-NC-SA-1.0",
+    conditions: [
+        "by_exception_only",
+        "not_allowed",
+    ],
+    url: "https://spdx.org/licenses/CC-BY-NC-SA-1.0.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-CC-BY-NC-SA-4.0",
-	conditions: ["by_exception_only", "not_allowed"],
-	url: "https://spdx.org/licenses/CC-BY-NC-SA-4.0.html",
+    name: "SPDX-license-identifier-CC-BY-NC-SA-2.0",
+    conditions: [
+        "by_exception_only",
+        "not_allowed",
+    ],
+    url: "https://spdx.org/licenses/CC-BY-NC-SA-2.0.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-CC-BY-ND",
-	conditions: ["restricted"],
+    name: "SPDX-license-identifier-CC-BY-NC-SA-2.5",
+    conditions: [
+        "by_exception_only",
+        "not_allowed",
+    ],
+    url: "https://spdx.org/licenses/CC-BY-NC-SA-2.5.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-CC-BY-ND-1.0",
-	conditions: ["restricted"],
-	url: "https://spdx.org/licenses/CC-BY-ND-1.0.html",
+    name: "SPDX-license-identifier-CC-BY-NC-SA-3.0",
+    conditions: [
+        "by_exception_only",
+        "not_allowed",
+    ],
+    url: "https://spdx.org/licenses/CC-BY-NC-SA-3.0.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-CC-BY-ND-2.0",
-	conditions: ["restricted"],
-	url: "https://spdx.org/licenses/CC-BY-ND-2.0.html",
+    name: "SPDX-license-identifier-CC-BY-NC-SA-4.0",
+    conditions: [
+        "by_exception_only",
+        "not_allowed",
+    ],
+    url: "https://spdx.org/licenses/CC-BY-NC-SA-4.0.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-CC-BY-ND-2.5",
-	conditions: ["restricted"],
-	url: "https://spdx.org/licenses/CC-BY-ND-2.5.html",
+    name: "SPDX-license-identifier-CC-BY-ND",
+    conditions: ["restricted"],
 }
 
 license_kind {
-	name: "SPDX-license-identifier-CC-BY-ND-3.0",
-	conditions: ["restricted"],
-	url: "https://spdx.org/licenses/CC-BY-ND-3.0.html",
+    name: "SPDX-license-identifier-CC-BY-ND-1.0",
+    conditions: ["restricted"],
+    url: "https://spdx.org/licenses/CC-BY-ND-1.0.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-CC-BY-ND-4.0",
-	conditions: ["restricted"],
-	url: "https://spdx.org/licenses/CC-BY-ND-4.0.html",
+    name: "SPDX-license-identifier-CC-BY-ND-2.0",
+    conditions: ["restricted"],
+    url: "https://spdx.org/licenses/CC-BY-ND-2.0.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-CC-BY-SA",
-	conditions: ["restricted"],
+    name: "SPDX-license-identifier-CC-BY-ND-2.5",
+    conditions: ["restricted"],
+    url: "https://spdx.org/licenses/CC-BY-ND-2.5.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-CC-BY-SA-1.0",
-	conditions: ["restricted"],
-	url: "https://spdx.org/licenses/CC-BY-SA-1.0.html",
+    name: "SPDX-license-identifier-CC-BY-ND-3.0",
+    conditions: ["restricted"],
+    url: "https://spdx.org/licenses/CC-BY-ND-3.0.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-CC-BY-SA-2.0",
-	conditions: ["restricted"],
-	url: "https://spdx.org/licenses/CC-BY-SA-2.0.html",
+    name: "SPDX-license-identifier-CC-BY-ND-4.0",
+    conditions: ["restricted"],
+    url: "https://spdx.org/licenses/CC-BY-ND-4.0.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-CC-BY-SA-2.5",
-	conditions: ["restricted"],
-	url: "https://spdx.org/licenses/CC-BY-SA-2.5.html",
+    name: "SPDX-license-identifier-CC-BY-SA",
+    conditions: ["restricted"],
 }
 
 license_kind {
-	name: "SPDX-license-identifier-CC-BY-SA-3.0",
-	conditions: ["restricted"],
-	url: "https://spdx.org/licenses/CC-BY-SA-3.0.html",
+    name: "SPDX-license-identifier-CC-BY-SA-1.0",
+    conditions: ["restricted"],
+    url: "https://spdx.org/licenses/CC-BY-SA-1.0.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-CC-BY-SA-4.0",
-	conditions: ["restricted"],
-	url: "https://spdx.org/licenses/CC-BY-SA-4.0.html",
+    name: "SPDX-license-identifier-CC-BY-SA-2.0",
+    conditions: ["restricted"],
+    url: "https://spdx.org/licenses/CC-BY-SA-2.0.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-CC-BY-SA-ND",
-	conditions: ["restricted"],
+    name: "SPDX-license-identifier-CC-BY-SA-2.5",
+    conditions: ["restricted"],
+    url: "https://spdx.org/licenses/CC-BY-SA-2.5.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-CC0-1.0",
-	conditions: ["unencumbered"],
-	url: "https://spdx.org/licenses/CC0-1.0.html",
+    name: "SPDX-license-identifier-CC-BY-SA-3.0",
+    conditions: ["restricted"],
+    url: "https://spdx.org/licenses/CC-BY-SA-3.0.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-CPAL-1.0",
-	conditions: ["by_exception_only", "not_allowed"],
-	url: "https://spdx.org/licenses/CPAL-1.0.html",
+    name: "SPDX-license-identifier-CC-BY-SA-4.0",
+    conditions: ["restricted"],
+    url: "https://spdx.org/licenses/CC-BY-SA-4.0.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-CC-BY-SA-ND",
+    conditions: ["restricted"],
+}
+
+license_kind {
+    name: "SPDX-license-identifier-CC0-1.0",
+    conditions: ["unencumbered"],
+    url: "https://spdx.org/licenses/CC0-1.0.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-CDDL",
+    conditions: ["reciprocal"],
+}
+
+license_kind {
+    name: "SPDX-license-identifier-CDDL-1.0",
+    conditions: ["reciprocal"],
+    url: "https://spdx.org/licenses/CDLL-1.0.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-CDDL-1.1",
+    conditions: ["reciprocal"],
+    url: "https://spdx.org/licenses/CDLL-1.1.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-CPAL-1.0",
+    conditions: [
+        "by_exception_only",
+        "not_allowed",
+    ],
+    url: "https://spdx.org/licenses/CPAL-1.0.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-CPL-1.0",
+    conditions: ["reciprocal"],
+    url: "https://spdx.org/licenses/CPL-1.0.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-EPL",
+    conditions: ["reciprocal"],
 }
 
 license_kind {
-	name: "SPDX-license-identifier-CPL-1.0",
-	conditions: ["reciprocal"],
-	url: "https://spdx.org/licenses/CPL-1.0.html",
+    name: "SPDX-license-identifier-EPL-1.0",
+    conditions: ["reciprocal"],
+    url: "https://spdx.org/licenses/EPL-1.0.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-EPL",
-	conditions: ["reciprocal"],
+    name: "SPDX-license-identifier-EPL-2.0",
+    conditions: ["reciprocal"],
+    url: "https://spdx.org/licenses/EPL-2.0.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-EPL-1.0",
-	conditions: ["reciprocal"],
-	url: "https://spdx.org/licenses/EPL-1.0.html",
+    name: "SPDX-license-identifier-EUPL",
+    conditions: [
+        "by_exception_only",
+        "not_allowed",
+    ],
 }
 
 license_kind {
-	name: "SPDX-license-identifier-EPL-2.0",
-	conditions: ["reciprocal"],
-	url: "https://spdx.org/licenses/EPL-2.0.html",
+    name: "SPDX-license-identifier-EUPL-1.0",
+    conditions: [
+        "by_exception_only",
+        "not_allowed",
+    ],
+    url: "https://spdx.org/licenses/EUPL-1.0.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-EUPL",
-	conditions: ["by_exception_only", "not_allowed"],
+    name: "SPDX-license-identifier-EUPL-1.1",
+    conditions: [
+        "by_exception_only",
+        "not_allowed",
+    ],
+    url: "https://spdx.org/licenses/EUPL-1.0.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-EUPL-1.0",
-	conditions: ["by_exception_only", "not_allowed"],
-	url: "https://spdx.org/licenses/EUPL-1.0.html",
+    name: "SPDX-license-identifier-EUPL-1.2",
+    conditions: [
+        "by_exception_only",
+        "not_allowed",
+    ],
+    url: "https://spdx.org/licenses/EUPL-1.0.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-EUPL-1.1",
-	conditions: ["by_exception_only", "not_allowed"],
-	url: "https://spdx.org/licenses/EUPL-1.0.html",
+    name: "SPDX-license-identifier-FSFAP",
+    conditions: ["notice"],
+    url: "https://spdx.org/licenses/FSFAP",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-EUPL-1.2",
-	conditions: ["by_exception_only", "not_allowed"],
-	url: "https://spdx.org/licenses/EUPL-1.0.html",
+    name: "SPDX-license-identifier-FTL",
+    conditions: ["notice"],
+    url: "https://spdx.org/licenses/FTL.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-FTL",
-	conditions: ["notice"],
-	url: "https://spdx.org/licenses/FTL.html",
+    name: "SPDX-license-identifier-GFDL",
+    conditions: ["by_exception_only"],
 }
 
 license_kind {
-	name: "SPDX-license-identifier-GPL",
-	conditions: ["restricted"],
+    name: "SPDX-license-identifier-GPL",
+    conditions: ["restricted"],
 }
 
 license_kind {
-	name: "SPDX-license-identifier-GPL-1.0",
-	conditions: ["restricted"],
-	url: "https://spdx.org/licenses/GPL-1.0.html",
+    name: "SPDX-license-identifier-GPL-1.0",
+    conditions: ["restricted"],
+    url: "https://spdx.org/licenses/GPL-1.0.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-GPL-1.0+",
-	conditions: ["restricted"],
-	url: "https://spdx.org/licenses/GPL-1.0+.html",
+    name: "SPDX-license-identifier-GPL-1.0+",
+    conditions: ["restricted"],
+    url: "https://spdx.org/licenses/GPL-1.0+.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-GPL-1.0-only",
-	conditions: ["restricted"],
-	url: "https://spdx.org/licenses/GPL-1.0-only.html",
+    name: "SPDX-license-identifier-GPL-1.0-only",
+    conditions: ["restricted"],
+    url: "https://spdx.org/licenses/GPL-1.0-only.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-GPL-1.0-or-later",
-	conditions: ["restricted"],
-	url: "https://spdx.org/licenses/GPL-1.0-or-later.html",
+    name: "SPDX-license-identifier-GPL-1.0-or-later",
+    conditions: ["restricted"],
+    url: "https://spdx.org/licenses/GPL-1.0-or-later.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-GPL-2.0",
-	conditions: ["restricted"],
-	url: "https://spdx.org/licenses/GPL-2.0.html",
+    name: "SPDX-license-identifier-GPL-2.0",
+    conditions: ["restricted"],
+    url: "https://spdx.org/licenses/GPL-2.0.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-GPL-2.0+",
-	conditions: ["restricted"],
-	url: "https://spdx.org/licenses/GPL-2.0+.html",
+    name: "SPDX-license-identifier-GPL-2.0+",
+    conditions: ["restricted"],
+    url: "https://spdx.org/licenses/GPL-2.0+.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-GPL-2.0-only",
-	conditions: ["restricted"],
-	url: "https://spdx.org/licenses/GPL-2.0-only.html",
+    name: "SPDX-license-identifier-GPL-2.0-only",
+    conditions: ["restricted"],
+    url: "https://spdx.org/licenses/GPL-2.0-only.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-GPL-2.0-or-later",
-	conditions: ["restricted"],
-	url: "https://spdx.org/licenses/GPL-2.0-or-later.html",
+    name: "SPDX-license-identifier-GPL-2.0-or-later",
+    conditions: ["restricted"],
+    url: "https://spdx.org/licenses/GPL-2.0-or-later.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-GPL-2.0-with-GCC-exception",
-	conditions: ["restricted"],
-	url: "https://spdx.org/licenses/GPL-2.0-with-GCC-exception.html",
+    name: "SPDX-license-identifier-GPL-2.0-with-GCC-exception",
+    conditions: ["restricted"],
+    url: "https://spdx.org/licenses/GPL-2.0-with-GCC-exception.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-GPL-2.0-with-autoconf-exception",
-	conditions: ["restricted"],
-	url: "https://spdx.org/licenses/GPL-2.0-with-autoconf-exception.html",
+    name: "SPDX-license-identifier-GPL-2.0-with-autoconf-exception",
+    conditions: ["restricted"],
+    url: "https://spdx.org/licenses/GPL-2.0-with-autoconf-exception.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-GPL-2.0-with-bison-exception",
-	conditions: ["restricted"],
-	url: "https://spdx.org/licenses/GPL-2.0-with-bison-exception.html",
+    name: "SPDX-license-identifier-GPL-2.0-with-bison-exception",
+    conditions: ["restricted"],
+    url: "https://spdx.org/licenses/GPL-2.0-with-bison-exception.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-GPL-2.0-with-classpath-exception",
-	conditions: ["restricted"],
-	url: "https://spdx.org/licenses/GPL-2.0-with-classpath-exception.html",
+    name: "SPDX-license-identifier-GPL-2.0-with-classpath-exception",
+    conditions: ["restricted"],
+    url: "https://spdx.org/licenses/GPL-2.0-with-classpath-exception.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-GPL-2.0-with-font-exception",
-	conditions: ["restricted"],
-	url: "https://spdx.org/licenses/GPL-2.0-with-font-exception.html",
+    name: "SPDX-license-identifier-GPL-2.0-with-font-exception",
+    conditions: ["restricted"],
+    url: "https://spdx.org/licenses/GPL-2.0-with-font-exception.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-GPL-3.0",
-	conditions: ["restricted"],
-	url: "https://spdx.org/licenses/GPL-3.0.html",
+    name: "SPDX-license-identifier-GPL-3.0",
+    conditions: ["restricted"],
+    url: "https://spdx.org/licenses/GPL-3.0.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-GPL-3.0+",
-	conditions: ["restricted"],
-	url: "https://spdx.org/licenses/GPL-3.0+.html",
+    name: "SPDX-license-identifier-GPL-3.0+",
+    conditions: ["restricted"],
+    url: "https://spdx.org/licenses/GPL-3.0+.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-GPL-3.0-only",
-	conditions: ["restricted"],
-	url: "https://spdx.org/licenses/GPL-3.0-only.html",
+    name: "SPDX-license-identifier-GPL-3.0-only",
+    conditions: ["restricted"],
+    url: "https://spdx.org/licenses/GPL-3.0-only.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-GPL-3.0-or-later",
-	conditions: ["restricted"],
-	url: "https://spdx.org/licenses/GPL-3.0-or-later.html",
+    name: "SPDX-license-identifier-GPL-3.0-or-later",
+    conditions: ["restricted"],
+    url: "https://spdx.org/licenses/GPL-3.0-or-later.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-GPL-3.0-with-GCC-exception",
-	conditions: ["restricted"],
-	url: "https://spdx.org/licenses/GPL-3.0-with-GCC-exception.html",
+    name: "SPDX-license-identifier-GPL-3.0-with-GCC-exception",
+    conditions: ["restricted"],
+    url: "https://spdx.org/licenses/GPL-3.0-with-GCC-exception.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-GPL-3.0-with-autoconf-exception",
-	conditions: ["restricted"],
-	url: "https://spdx.org/licenses/GPL-3.0-with-autoconf-exception.html",
+    name: "SPDX-license-identifier-GPL-3.0-with-autoconf-exception",
+    conditions: ["restricted"],
+    url: "https://spdx.org/licenses/GPL-3.0-with-autoconf-exception.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-GPL-with-classpath-exception",
-	conditions: ["restricted"],
+    name: "SPDX-license-identifier-GPL-with-classpath-exception",
+    conditions: ["restricted"],
 }
 
 license_kind {
-	name: "SPDX-license-identifier-HPND",
-	conditions: ["notice"],
-	url: "https://spdx.org/licenses/HPND.html",
+    name: "SPDX-license-identifier-HPND",
+    conditions: ["notice"],
+    url: "https://spdx.org/licenses/HPND.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-ICU",
-	conditions: ["notice"],
-	url: "https://spdx.org/licenses/ICU.html",
+    name: "SPDX-license-identifier-ICU",
+    conditions: ["notice"],
+    url: "https://spdx.org/licenses/ICU.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-ISC",
-	conditions: ["notice"],
-	url: "https://spdx.org/licenses/ISC.html",
+    name: "SPDX-license-identifier-ISC",
+    conditions: ["notice"],
+    url: "https://spdx.org/licenses/ISC.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-JSON",
-	conditions: ["notice"],
-	url: "https://spdx.org/licenses/JSON.html",
+    name: "SPDX-license-identifier-JSON",
+    conditions: ["notice"],
+    url: "https://spdx.org/licenses/JSON.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-LGPL",
-	conditions: ["restricted"],
+    name: "SPDX-license-identifier-LGPL",
+    conditions: ["restricted"],
 }
 
 license_kind {
-	name: "SPDX-license-identifier-LGPL-2.0",
-	conditions: ["restricted"],
-	url: "https://spdx.org/licenses/LGPL-2.0.html",
+    name: "SPDX-license-identifier-LGPL-2.0",
+    conditions: ["restricted"],
+    url: "https://spdx.org/licenses/LGPL-2.0.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-LGPL-2.0+",
-	conditions: ["restricted"],
-	url: "https://spdx.org/licenses/LGPL-2.0+.html",
+    name: "SPDX-license-identifier-LGPL-2.0+",
+    conditions: ["restricted"],
+    url: "https://spdx.org/licenses/LGPL-2.0+.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-LGPL-2.0-only",
-	conditions: ["restricted"],
-	url: "https://spdx.org/licenses/LGPL-2.0-only.html",
+    name: "SPDX-license-identifier-LGPL-2.0-only",
+    conditions: ["restricted"],
+    url: "https://spdx.org/licenses/LGPL-2.0-only.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-LGPL-2.0-or-later",
-	conditions: ["restricted"],
-	url: "https://spdx.org/licenses/LGPL-2.0-or-later.html",
+    name: "SPDX-license-identifier-LGPL-2.0-or-later",
+    conditions: ["restricted"],
+    url: "https://spdx.org/licenses/LGPL-2.0-or-later.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-LGPL-2.1",
-	conditions: ["restricted"],
-	url: "https://spdx.org/licenses/LGPL-2.1.html",
+    name: "SPDX-license-identifier-LGPL-2.1",
+    conditions: ["restricted"],
+    url: "https://spdx.org/licenses/LGPL-2.1.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-LGPL-2.1+",
-	conditions: ["restricted"],
-	url: "https://spdx.org/licenses/LGPL-2.1+.html",
+    name: "SPDX-license-identifier-LGPL-2.1+",
+    conditions: ["restricted"],
+    url: "https://spdx.org/licenses/LGPL-2.1+.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-LGPL-2.1-only",
-	conditions: ["restricted"],
-	url: "https://spdx.org/licenses/LGPL-2.1-only.html",
+    name: "SPDX-license-identifier-LGPL-2.1-only",
+    conditions: ["restricted"],
+    url: "https://spdx.org/licenses/LGPL-2.1-only.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-LGPL-2.1-or-later",
-	conditions: ["restricted"],
-	url: "https://spdx.org/licenses/LGPL-2.1-or-later.html",
+    name: "SPDX-license-identifier-LGPL-2.1-or-later",
+    conditions: ["restricted"],
+    url: "https://spdx.org/licenses/LGPL-2.1-or-later.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-LGPL-3.0",
-	conditions: ["restricted"],
-	url: "https://spdx.org/licenses/LGPL-3.0.html",
+    name: "SPDX-license-identifier-LGPL-3.0",
+    conditions: ["restricted"],
+    url: "https://spdx.org/licenses/LGPL-3.0.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-LGPL-3.0+",
-	conditions: ["restricted"],
-	url: "https://spdx.org/licenses/LGPL-3.0+.html",
+    name: "SPDX-license-identifier-LGPL-3.0+",
+    conditions: ["restricted"],
+    url: "https://spdx.org/licenses/LGPL-3.0+.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-LGPL-3.0-only",
-	conditions: ["restricted"],
-	url: "https://spdx.org/licenses/LGPL-3.0-only.html",
+    name: "SPDX-license-identifier-LGPL-3.0-only",
+    conditions: ["restricted"],
+    url: "https://spdx.org/licenses/LGPL-3.0-only.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-LGPL-3.0-or-later",
-	conditions: ["restricted"],
-	url: "https://spdx.org/licenses/LGPL-3.0-or-later.html",
+    name: "SPDX-license-identifier-LGPL-3.0-or-later",
+    conditions: ["restricted"],
+    url: "https://spdx.org/licenses/LGPL-3.0-or-later.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-LGPLLR",
-	conditions: ["restricted"],
-	url: "https://spdx.org/licenses/LGPLLR.html",
+    name: "SPDX-license-identifier-LGPLLR",
+    conditions: ["restricted"],
+    url: "https://spdx.org/licenses/LGPLLR.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-LPL-1.02",
-	conditions: ["notice"],
-	url: "https://spdx.org/licenses/LPL-1.02.html",
+    name: "SPDX-license-identifier-LPL-1.02",
+    conditions: ["notice"],
+    url: "https://spdx.org/licenses/LPL-1.02.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-MIT",
-	conditions: ["notice"],
+    name: "SPDX-license-identifier-MIT",
+    conditions: ["notice"],
 }
 
 license_kind {
-	name: "SPDX-license-identifier-MIT-0",
-	conditions: ["notice"],
-	url: "https://spdx.org/licenses/MIT-0.html",
+    name: "SPDX-license-identifier-MIT-0",
+    conditions: ["notice"],
+    url: "https://spdx.org/licenses/MIT-0.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-MIT-CMU",
-	conditions: ["notice"],
-	url: "https://spdx.org/licenses/MIT-CMU.html",
+    name: "SPDX-license-identifier-MIT-CMU",
+    conditions: ["notice"],
+    url: "https://spdx.org/licenses/MIT-CMU.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-MIT-advertising",
-	conditions: ["notice"],
-	url: "https://spdx.org/licenses/MIT-advertising.html",
+    name: "SPDX-license-identifier-MIT-advertising",
+    conditions: ["notice"],
+    url: "https://spdx.org/licenses/MIT-advertising.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-MIT-enna",
-	conditions: ["notice"],
-	url: "https://spdx.org/licenses/MIT-enna.html",
+    name: "SPDX-license-identifier-MIT-enna",
+    conditions: ["notice"],
+    url: "https://spdx.org/licenses/MIT-enna.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-MIT-feh",
-	conditions: ["notice"],
-	url: "https://spdx.org/licenses/MIT-feh.html",
+    name: "SPDX-license-identifier-MIT-feh",
+    conditions: ["notice"],
+    url: "https://spdx.org/licenses/MIT-feh.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-MITNFA",
-	conditions: ["notice"],
-	url: "https://spdx.org/licenses/MITNFA.html",
+    name: "SPDX-license-identifier-MITNFA",
+    conditions: ["notice"],
+    url: "https://spdx.org/licenses/MITNFA.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-MPL",
-	conditions: ["reciprocal"],
+    name: "SPDX-license-identifier-MPL",
+    conditions: ["reciprocal"],
 }
 
 license_kind {
-	name: "SPDX-license-identifier-MPL-1.0",
-	conditions: ["reciprocal"],
-	url: "https://spdx.org/licenses/MPL-1.0.html",
+    name: "SPDX-license-identifier-MPL-1.0",
+    conditions: ["reciprocal"],
+    url: "https://spdx.org/licenses/MPL-1.0.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-MPL-1.1",
-	conditions: ["reciprocal"],
-	url: "https://spdx.org/licenses/MPL-1.1.html",
+    name: "SPDX-license-identifier-MPL-1.1",
+    conditions: ["reciprocal"],
+    url: "https://spdx.org/licenses/MPL-1.1.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-MPL-2.0",
-	conditions: ["reciprocal"],
-	url: "https://spdx.org/licenses/MPL-2.0.html",
+    name: "SPDX-license-identifier-MPL-2.0",
+    conditions: ["reciprocal"],
+    url: "https://spdx.org/licenses/MPL-2.0.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-MPL-2.0-no-copyleft-exception",
-	conditions: ["reciprocal"],
-	url: "https://spdx.org/licenses/MPL-2.0-no-copyleft-exception.html",
+    name: "SPDX-license-identifier-MPL-2.0-no-copyleft-exception",
+    conditions: ["reciprocal"],
+    url: "https://spdx.org/licenses/MPL-2.0-no-copyleft-exception.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-MS-PL",
-	conditions: ["notice"],
-	url: "https://spdx.org/licenses/MS-PL.html",
+    name: "SPDX-license-identifier-MS-PL",
+    conditions: ["notice"],
+    url: "https://spdx.org/licenses/MS-PL.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-NCSA",
-	conditions: ["notice"],
-	url: "https://spdx.org/licenses/NCSA.html",
+    name: "SPDX-license-identifier-MS-RL",
+    conditions: ["by_exception_only"],
+    url: "https://spdx.org/licenses/MS-RL.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-OFL",
-	conditions: ["by_exception_only"],
+    name: "SPDX-license-identifier-NCSA",
+    conditions: ["notice"],
+    url: "https://spdx.org/licenses/NCSA.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-OFL-1.0",
-	conditions: ["by_exception_only"],
-	url: "https://spdx.org/licenses/OFL-1.0.html",
+    name: "SPDX-license-identifier-OFL",
+    conditions: ["by_exception_only"],
 }
 
 license_kind {
-	name: "SPDX-license-identifier-OFL-1.0-RFN",
-	conditions: ["by_exception_only"],
-	url: "https://spdx.org/licenses/OFL-1.0-RFN.html",
+    name: "SPDX-license-identifier-OFL-1.0",
+    conditions: ["by_exception_only"],
+    url: "https://spdx.org/licenses/OFL-1.0.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-OFL-1.0-no-RFN",
-	conditions: ["by_exception_only"],
-	url: "https://spdx.org/licenses/OFL-1.0-no-RFN.html",
+    name: "SPDX-license-identifier-OFL-1.0-RFN",
+    conditions: ["by_exception_only"],
+    url: "https://spdx.org/licenses/OFL-1.0-RFN.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-OFL-1.1",
-	conditions: ["by_exception_only"],
-	url: "https://spdx.org/licenses/OFL-1.1.html",
+    name: "SPDX-license-identifier-OFL-1.0-no-RFN",
+    conditions: ["by_exception_only"],
+    url: "https://spdx.org/licenses/OFL-1.0-no-RFN.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-OFL-1.1-RFN",
-	conditions: ["by_exception_only"],
-	url: "https://spdx.org/licenses/OFL-1.1-RFN.html",
+    name: "SPDX-license-identifier-OFL-1.1",
+    conditions: ["by_exception_only"],
+    url: "https://spdx.org/licenses/OFL-1.1.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-OFL-1.1-no-RFN",
-	conditions: ["by_exception_only"],
-	url: "https://spdx.org/licenses/OFL-1.1-no-RFN.html",
+    name: "SPDX-license-identifier-OFL-1.1-RFN",
+    conditions: ["by_exception_only"],
+    url: "https://spdx.org/licenses/OFL-1.1-RFN.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-OpenSSL",
-	conditions: ["notice"],
-	url: "https://spdx.org/licenses/OpenSSL.html",
+    name: "SPDX-license-identifier-OFL-1.1-no-RFN",
+    conditions: ["by_exception_only"],
+    url: "https://spdx.org/licenses/OFL-1.1-no-RFN.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-PSF-2.0",
-	conditions: ["notice"],
-	url: "https://spdx.org/licenses/PSF-2.0.html",
+    name: "SPDX-license-identifier-OpenSSL",
+    conditions: ["notice"],
+    url: "https://spdx.org/licenses/OpenSSL.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-SISSL",
-	conditions: ["by_exception_only", "not_allowed"],
-	url: "https://spdx.org/licenses/SISSL.html",
+    name: "SPDX-license-identifier-PSF-2.0",
+    conditions: ["notice"],
+    url: "https://spdx.org/licenses/PSF-2.0.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-SISSL-1.2",
-	conditions: ["by_exception_only", "not_allowed"],
-	url: "https://spdx.org/licenses/SISSL-1.2.html",
+    name: "SPDX-license-identifier-SISSL",
+    conditions: [
+        "by_exception_only",
+        "not_allowed",
+    ],
+    url: "https://spdx.org/licenses/SISSL.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-SPL-1.0",
-	conditions: ["by_exception_only", "reciprocal"],
-	url: "https://spdx.org/licenses/SPL-1.0.html",
+    name: "SPDX-license-identifier-SISSL-1.2",
+    conditions: [
+        "by_exception_only",
+        "not_allowed",
+    ],
+    url: "https://spdx.org/licenses/SISSL-1.2.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-SSPL",
-	conditions: ["by_exception_only", "not_allowed"],
-	url: "https://spdx.org/licenses/SSPL.html",
+    name: "SPDX-license-identifier-SPL-1.0",
+    conditions: [
+        "by_exception_only",
+        "reciprocal",
+    ],
+    url: "https://spdx.org/licenses/SPL-1.0.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-UPL-1.0",
-	conditions: ["notice"],
-	url: "https://spdx.org/licenses/UPL-1.-.html",
+    name: "SPDX-license-identifier-SSPL",
+    conditions: [
+        "by_exception_only",
+        "not_allowed",
+    ],
+    url: "https://spdx.org/licenses/SSPL.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-Unicode-DFS",
-	conditions: ["notice"],
+    name: "SPDX-license-identifier-UPL-1.0",
+    conditions: ["notice"],
+    url: "https://spdx.org/licenses/UPL-1.-.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-Unicode-DFS-2015",
-	conditions: ["notice"],
-	url: "https://spdx.org/licenses/Unicode-DFS-2015.html",
+    name: "SPDX-license-identifier-Unicode-DFS",
+    conditions: ["notice"],
 }
 
 license_kind {
-	name: "SPDX-license-identifier-Unicode-DFS-2016",
-	conditions: ["notice"],
-	url: "https://spdx.org/licenses/Unicode-DFS-2016.html",
+    name: "SPDX-license-identifier-Unicode-DFS-2015",
+    conditions: ["notice"],
+    url: "https://spdx.org/licenses/Unicode-DFS-2015.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-Unlicense",
-	conditions: ["unencumbered"],
-	url: "https://spdx.org/licenses/Unlicense.html",
+    name: "SPDX-license-identifier-Unicode-DFS-2016",
+    conditions: ["notice"],
+    url: "https://spdx.org/licenses/Unicode-DFS-2016.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-W3C",
-	conditions: ["notice"],
-	url: "https://spdx.org/licenses/W3C.html",
+    name: "SPDX-license-identifier-Unlicense",
+    conditions: ["unencumbered"],
+    url: "https://spdx.org/licenses/Unlicense.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-W3C-19980720",
-	conditions: ["notice"],
-	url: "https://spdx.org/licenses/W3C-19980720.html",
+    name: "SPDX-license-identifier-W3C",
+    conditions: ["notice"],
+    url: "https://spdx.org/licenses/W3C.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-W3C-20150513",
-	conditions: ["notice"],
-	url: "https://spdx.org/licenses/W3C-20150513.html",
+    name: "SPDX-license-identifier-W3C-19980720",
+    conditions: ["notice"],
+    url: "https://spdx.org/licenses/W3C-19980720.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-WTFPL",
-	conditions: ["by_exception_only", "not_allowed"],
-	url: "https://spdx.org/licenses/WTFPL.html",
+    name: "SPDX-license-identifier-W3C-20150513",
+    conditions: ["notice"],
+    url: "https://spdx.org/licenses/W3C-20150513.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-Watcom-1.0",
-	conditions: ["by_exception_only", "not_allowed"],
-	url: "https://spdx.org/licenses/Watcom-1.0.html",
+    name: "SPDX-license-identifier-WTFPL",
+    conditions: [
+        "by_exception_only",
+        "not_allowed",
+    ],
+    url: "https://spdx.org/licenses/WTFPL.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-Xnet",
-	conditions: ["notice"],
-	url: "https://spdx.org/licenses/Xnet.html",
+    name: "SPDX-license-identifier-Watcom-1.0",
+    conditions: [
+        "by_exception_only",
+        "not_allowed",
+    ],
+    url: "https://spdx.org/licenses/Watcom-1.0.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-ZPL",
-	conditions: ["notice"],
+    name: "SPDX-license-identifier-Xnet",
+    conditions: ["notice"],
+    url: "https://spdx.org/licenses/Xnet.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-ZPL-1.1",
-	conditions: ["notice"],
-	url: "https://spdx.org/licenses/ZPL-1.1.html",
+    name: "SPDX-license-identifier-ZPL",
+    conditions: ["notice"],
 }
 
 license_kind {
-	name: "SPDX-license-identifier-ZPL-2.0",
-	conditions: ["notice"],
-	url: "https://spdx.org/licenses/ZPL-2.0.html",
+    name: "SPDX-license-identifier-ZPL-1.1",
+    conditions: ["notice"],
+    url: "https://spdx.org/licenses/ZPL-1.1.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-ZPL-2.1",
-	conditions: ["notice"],
-	url: "https://spdx.org/licenses/ZPL-2.1.html",
+    name: "SPDX-license-identifier-ZPL-2.0",
+    conditions: ["notice"],
+    url: "https://spdx.org/licenses/ZPL-2.0.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-Zend-2.0",
-	conditions: ["notice"],
-	url: "https://spdx.org/licenses/Zend-2.0.html",
+    name: "SPDX-license-identifier-ZPL-2.1",
+    conditions: ["notice"],
+    url: "https://spdx.org/licenses/ZPL-2.1.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-Zlib",
-	conditions: ["notice"],
-	url: "https://spdx.org/licenses/Zlib.html",
+    name: "SPDX-license-identifier-Zend-2.0",
+    conditions: ["notice"],
+    url: "https://spdx.org/licenses/Zend-2.0.html",
 }
 
 license_kind {
-	name: "SPDX-license-identifier-libtiff",
-	conditions: ["notice"],
-	url: "https://spdx.org/licenses/libtiff.html",
+    name: "SPDX-license-identifier-Zlib",
+    conditions: ["notice"],
+    url: "https://spdx.org/licenses/Zlib.html",
 }
 
+license_kind {
+    name: "SPDX-license-identifier-libtiff",
+    conditions: ["notice"],
+    url: "https://spdx.org/licenses/libtiff.html",
+}
 
 // Legacy license kinds -- do not add new references -- use an spdx kind instead.
 license_kind {
-	name: "legacy_unknown",
-	conditions: ["by_exception_only"],
+    name: "legacy_unknown",
+    conditions: ["by_exception_only"],
 }
 
 license_kind {
-	name: "legacy_unencumbered",
-	conditions: ["unencumbered"],
+    name: "legacy_unencumbered",
+    conditions: ["unencumbered"],
 }
 
 license_kind {
-	name: "legacy_permissive",
-	conditions: ["permissive"],
+    name: "legacy_permissive",
+    conditions: ["permissive"],
 }
 
 license_kind {
-	name: "legacy_notice",
-	conditions: ["notice"],
+    name: "legacy_notice",
+    conditions: ["notice"],
 }
 
 license_kind {
-	name: "legacy_reciprocal",
-	conditions: ["reciprocal"],
+    name: "legacy_reciprocal",
+    conditions: ["reciprocal"],
 }
 
 license_kind {
-	name: "legacy_restricted",
-	conditions: ["restricted"],
+    name: "legacy_restricted",
+    conditions: ["restricted"],
 }
 
 license_kind {
-	name: "legacy_by_exception_only",
-	conditions: ["by_exception_only"],
+    name: "legacy_by_exception_only",
+    conditions: ["by_exception_only"],
 }
 
 license_kind {
-	name: "legacy_not_allowed",
-	conditions: ["by_exception_only", "not_allowed"],
+    name: "legacy_not_a_contribution",
+    conditions: [
+        "by_exception_only",
+        "not_allowed",
+    ],
 }
 
 license_kind {
-	name: "legacy_proprietary",
-	conditions: ["by_exception_only", "not_allowed", "proprietary"],
+    name: "legacy_not_allowed",
+    conditions: [
+        "by_exception_only",
+        "not_allowed",
+    ],
+}
+
+license_kind {
+    name: "legacy_proprietary",
+    conditions: [
+        "by_exception_only",
+        "not_allowed",
+        "proprietary",
+    ],
 }
diff --git a/licenses/OWNERS b/licenses/OWNERS
new file mode 100644
index 0000000..fddfc48
--- /dev/null
+++ b/licenses/OWNERS
@@ -0,0 +1,2 @@
+per-file * = bbadour@google.com
+
diff --git a/rust/Android.bp b/rust/Android.bp
index df731db..ad3040a 100644
--- a/rust/Android.bp
+++ b/rust/Android.bp
@@ -15,6 +15,7 @@
         "clippy.go",
         "compiler.go",
         "coverage.go",
+        "fuzz.go",
         "image.go",
         "library.go",
         "prebuilt.go",
@@ -22,6 +23,7 @@
         "project_json.go",
         "protobuf.go",
         "rust.go",
+        "sanitize.go",
         "strip.go",
         "source_provider.go",
         "test.go",
@@ -34,6 +36,7 @@
         "clippy_test.go",
         "compiler_test.go",
         "coverage_test.go",
+        "fuzz_test.go",
         "image_test.go",
         "library_test.go",
         "project_json_test.go",
diff --git a/rust/androidmk.go b/rust/androidmk.go
index e9da6fa..0307727 100644
--- a/rust/androidmk.go
+++ b/rust/androidmk.go
@@ -82,9 +82,6 @@
 	}
 
 	ret.Class = "EXECUTABLES"
-	ret.ExtraEntries = append(ret.ExtraEntries, func(entries *android.AndroidMkEntries) {
-		entries.SetOptionalPath("LOCAL_PREBUILT_COVERAGE_ARCHIVE", binary.coverageOutputZipFile)
-	})
 }
 
 func (test *testDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkEntries) {
@@ -117,10 +114,6 @@
 	if library.distFile.Valid() {
 		ret.DistFiles = android.MakeDefaultDistFiles(library.distFile.Path())
 	}
-
-	ret.ExtraEntries = append(ret.ExtraEntries, func(entries *android.AndroidMkEntries) {
-		entries.SetOptionalPath("LOCAL_PREBUILT_COVERAGE_ARCHIVE", library.coverageOutputZipFile)
-	})
 }
 
 func (procMacro *procMacroDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkEntries) {
diff --git a/rust/binary.go b/rust/binary.go
index ca07d07..2963a37 100644
--- a/rust/binary.go
+++ b/rust/binary.go
@@ -121,7 +121,7 @@
 	flags.RustFlags = append(flags.RustFlags, deps.depFlags...)
 	flags.LinkFlags = append(flags.LinkFlags, deps.linkObjects...)
 
-	outputs := TransformSrcToBinary(ctx, srcPath, deps, flags, outputFile, deps.linkDirs)
+	TransformSrcToBinary(ctx, srcPath, deps, flags, outputFile, deps.linkDirs)
 
 	if binary.stripper.NeedsStrip(ctx) {
 		strippedOutputFile := android.PathForModuleOut(ctx, "stripped", fileName)
@@ -129,24 +129,9 @@
 		binary.strippedOutputFile = android.OptionalPathForPath(strippedOutputFile)
 	}
 
-	binary.coverageFile = outputs.coverageFile
-
-	var coverageFiles android.Paths
-	if outputs.coverageFile != nil {
-		coverageFiles = append(coverageFiles, binary.coverageFile)
-	}
-	if len(deps.coverageFiles) > 0 {
-		coverageFiles = append(coverageFiles, deps.coverageFiles...)
-	}
-	binary.coverageOutputZipFile = TransformCoverageFilesToZip(ctx, coverageFiles, binary.getStem(ctx))
-
 	return outputFile
 }
 
-func (binary *binaryDecorator) coverageOutputZipPath() android.OptionalPath {
-	return binary.coverageOutputZipFile
-}
-
 func (binary *binaryDecorator) autoDep(ctx BaseModuleContext) autoDep {
 	// Binaries default to dylib dependencies for device, rlib for host.
 	if binary.preferRlib() {
diff --git a/rust/binary_test.go b/rust/binary_test.go
index b44a5bc..86f50d3 100644
--- a/rust/binary_test.go
+++ b/rust/binary_test.go
@@ -130,6 +130,9 @@
 	if !strings.Contains(flags, "-C relocation-model=static") {
 		t.Errorf("static binary missing '-C relocation-model=static' in rustcFlags, found: %#v", flags)
 	}
+	if !strings.Contains(flags, "-C panic=abort") {
+		t.Errorf("static binary missing '-C panic=abort' in rustcFlags, found: %#v", flags)
+	}
 	if !strings.Contains(linkFlags, "-static") {
 		t.Errorf("static binary missing '-static' in linkFlags, found: %#v", flags)
 	}
diff --git a/rust/builder.go b/rust/builder.go
index baeab69..56fe031 100644
--- a/rust/builder.go
+++ b/rust/builder.go
@@ -19,10 +19,8 @@
 	"strings"
 
 	"github.com/google/blueprint"
-	"github.com/google/blueprint/pathtools"
 
 	"android/soong/android"
-	"android/soong/cc"
 	"android/soong/rust/config"
 )
 
@@ -76,8 +74,7 @@
 )
 
 type buildOutput struct {
-	outputFile   android.Path
-	coverageFile android.Path
+	outputFile android.Path
 }
 
 func init() {
@@ -86,7 +83,7 @@
 
 func TransformSrcToBinary(ctx ModuleContext, mainSrc android.Path, deps PathDeps, flags Flags,
 	outputFile android.WritablePath, linkDirs []string) buildOutput {
-	flags.RustFlags = append(flags.RustFlags, "-C lto")
+	flags.GlobalRustFlags = append(flags.GlobalRustFlags, "-C lto")
 
 	return transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, "bin", linkDirs)
 }
@@ -103,13 +100,13 @@
 
 func TransformSrctoStatic(ctx ModuleContext, mainSrc android.Path, deps PathDeps, flags Flags,
 	outputFile android.WritablePath, linkDirs []string) buildOutput {
-	flags.RustFlags = append(flags.RustFlags, "-C lto")
+	flags.GlobalRustFlags = append(flags.GlobalRustFlags, "-C lto")
 	return transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, "staticlib", linkDirs)
 }
 
 func TransformSrctoShared(ctx ModuleContext, mainSrc android.Path, deps PathDeps, flags Flags,
 	outputFile android.WritablePath, linkDirs []string) buildOutput {
-	flags.RustFlags = append(flags.RustFlags, "-C lto")
+	flags.GlobalRustFlags = append(flags.GlobalRustFlags, "-C lto")
 	return transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, "cdylib", linkDirs)
 }
 
@@ -195,27 +192,6 @@
 		implicits = append(implicits, deps.CrtBegin.Path(), deps.CrtEnd.Path())
 	}
 
-	if flags.Coverage {
-		var gcnoFile android.WritablePath
-		// Provide consistency with cc gcda output, see cc/builder.go init()
-		profileEmitArg := strings.TrimPrefix(cc.PwdPrefix(), "PWD=") + "/"
-
-		if outputFile.Ext() != "" {
-			// rustc seems to split the output filename at the first '.' when determining the gcno filename
-			// so we need to do the same here.
-			gcnoFile = android.PathForModuleOut(ctx, strings.Split(outputFile.Base(), ".")[0]+".gcno")
-			rustcFlags = append(rustcFlags, "-Z profile-emit="+profileEmitArg+android.PathForModuleOut(
-				ctx, pathtools.ReplaceExtension(outputFile.Base(), "gcda")).String())
-		} else {
-			gcnoFile = android.PathForModuleOut(ctx, outputFile.Base()+".gcno")
-			rustcFlags = append(rustcFlags, "-Z profile-emit="+profileEmitArg+android.PathForModuleOut(
-				ctx, outputFile.Base()+".gcda").String())
-		}
-
-		implicitOutputs = append(implicitOutputs, gcnoFile)
-		output.coverageFile = gcnoFile
-	}
-
 	if len(deps.SrcDeps) > 0 {
 		genSubDir := "out/"
 		moduleGenDir := android.PathForModuleOut(ctx, genSubDir)
@@ -292,21 +268,3 @@
 
 	return output
 }
-
-func TransformCoverageFilesToZip(ctx ModuleContext,
-	covFiles android.Paths, baseName string) android.OptionalPath {
-	if len(covFiles) > 0 {
-
-		outputFile := android.PathForModuleOut(ctx, baseName+".zip")
-
-		ctx.Build(pctx, android.BuildParams{
-			Rule:        zip,
-			Description: "zip " + outputFile.Base(),
-			Inputs:      covFiles,
-			Output:      outputFile,
-		})
-
-		return android.OptionalPathForPath(outputFile)
-	}
-	return android.OptionalPath{}
-}
diff --git a/rust/compiler.go b/rust/compiler.go
index bcea6cc..c921824 100644
--- a/rust/compiler.go
+++ b/rust/compiler.go
@@ -136,8 +136,7 @@
 }
 
 type baseCompiler struct {
-	Properties   BaseCompilerProperties
-	coverageFile android.Path //rustc generates a single gcno file
+	Properties BaseCompilerProperties
 
 	// Install related
 	dir      string
@@ -146,9 +145,9 @@
 	relative string
 	path     android.InstallPath
 	location installLocation
+	sanitize *sanitize
 
-	coverageOutputZipFile android.OptionalPath
-	distFile              android.OptionalPath
+	distFile android.OptionalPath
 	// Stripped output file. If Valid(), this file will be installed instead of outputFile.
 	strippedOutputFile android.OptionalPath
 }
diff --git a/rust/config/allowed_list.go b/rust/config/allowed_list.go
index 21df024..fc11d29 100644
--- a/rust/config/allowed_list.go
+++ b/rust/config/allowed_list.go
@@ -19,6 +19,7 @@
 		"prebuilts/rust",
 		"system/bt",
 		"system/extras/profcollectd",
+		"system/extras/simpleperf",
 		"system/hardware/interfaces/keystore2",
 		"system/security",
 		"system/tools/aidl",
diff --git a/rust/config/arm64_device.go b/rust/config/arm64_device.go
index 21b22a4..5066428 100644
--- a/rust/config/arm64_device.go
+++ b/rust/config/arm64_device.go
@@ -26,8 +26,8 @@
 	Arm64LinkFlags            = []string{}
 
 	Arm64ArchVariantRustFlags = map[string][]string{
-		"armv8-a":  []string{},
-		"armv8-2a": []string{},
+		"armv8-a":          []string{},
+		"armv8-2a":         []string{},
 		"armv8-2a-dotprod": []string{},
 	}
 )
@@ -71,6 +71,10 @@
 	return true
 }
 
+func (toolchainArm64) LibclangRuntimeLibraryArch() string {
+	return "aarch64"
+}
+
 func Arm64ToolchainFactory(arch android.Arch) Toolchain {
 	archVariant := arch.ArchVariant
 	if archVariant == "" {
diff --git a/rust/config/arm_device.go b/rust/config/arm_device.go
index adfe917..42c1c02 100644
--- a/rust/config/arm_device.go
+++ b/rust/config/arm_device.go
@@ -72,6 +72,10 @@
 	return true
 }
 
+func (toolchainArm) LibclangRuntimeLibraryArch() string {
+	return "arm"
+}
+
 func ArmToolchainFactory(arch android.Arch) Toolchain {
 	toolchainRustFlags := []string{
 		"${config.ArmToolchainRustFlags}",
diff --git a/rust/config/global.go b/rust/config/global.go
index 08ec877..fb62278 100644
--- a/rust/config/global.go
+++ b/rust/config/global.go
@@ -49,7 +49,9 @@
 		"-C relocation-model=pic",
 	}
 
-	deviceGlobalRustFlags = []string{}
+	deviceGlobalRustFlags = []string{
+		"-C panic=abort",
+	}
 
 	deviceGlobalLinkFlags = []string{
 		// Prepend the lld flags from cc_config so we stay in sync with cc
diff --git a/rust/config/toolchain.go b/rust/config/toolchain.go
index 616d88b..9525c38 100644
--- a/rust/config/toolchain.go
+++ b/rust/config/toolchain.go
@@ -34,6 +34,8 @@
 	Supported() bool
 
 	Bionic() bool
+
+	LibclangRuntimeLibraryArch() string
 }
 
 type toolchainBase struct {
@@ -106,6 +108,36 @@
 	return false
 }
 
+func (toolchainBase) LibclangRuntimeLibraryArch() string {
+	return ""
+}
+
+func LibFuzzerRuntimeLibrary(t Toolchain) string {
+	return LibclangRuntimeLibrary(t, "fuzzer")
+}
+
+func LibclangRuntimeLibrary(t Toolchain, library string) string {
+	arch := t.LibclangRuntimeLibraryArch()
+	if arch == "" {
+		return ""
+	}
+	if !t.Bionic() {
+		return "libclang_rt." + library + "-" + arch
+	}
+	return "libclang_rt." + library + "-" + arch + "-android"
+}
+
+func LibRustRuntimeLibrary(t Toolchain, library string) string {
+	arch := t.LibclangRuntimeLibraryArch()
+	if arch == "" {
+		return ""
+	}
+	if !t.Bionic() {
+		return "librustc_rt." + library + "-" + arch
+	}
+	return "librustc_rt." + library + "-" + arch + "-android"
+}
+
 func toolchainBaseFactory() Toolchain {
 	return &toolchainBase{}
 }
diff --git a/rust/config/x86_64_device.go b/rust/config/x86_64_device.go
index 5f6e85a..94b719f 100644
--- a/rust/config/x86_64_device.go
+++ b/rust/config/x86_64_device.go
@@ -77,6 +77,10 @@
 	return true
 }
 
+func (toolchainX86_64) LibclangRuntimeLibraryArch() string {
+	return "x86_64"
+}
+
 func x86_64ToolchainFactory(arch android.Arch) Toolchain {
 	toolchainRustFlags := []string{
 		"${config.X86_64ToolchainRustFlags}",
diff --git a/rust/config/x86_device.go b/rust/config/x86_device.go
index daeeb14..aae1125 100644
--- a/rust/config/x86_device.go
+++ b/rust/config/x86_device.go
@@ -80,6 +80,10 @@
 	return true
 }
 
+func (toolchainX86) LibclangRuntimeLibraryArch() string {
+	return "i686"
+}
+
 func x86ToolchainFactory(arch android.Arch) Toolchain {
 	toolchainRustFlags := []string{
 		"${config.X86ToolchainRustFlags}",
diff --git a/rust/config/x86_linux_host.go b/rust/config/x86_linux_host.go
index e7f26ce..b63e14d 100644
--- a/rust/config/x86_linux_host.go
+++ b/rust/config/x86_linux_host.go
@@ -103,6 +103,14 @@
 	return "x86"
 }
 
+func (toolchainLinuxX86) LibclangRuntimeLibraryArch() string {
+	return "i386"
+}
+
+func (toolchainLinuxX8664) LibclangRuntimeLibraryArch() string {
+	return "x86_64"
+}
+
 func (t *toolchainLinuxX86) RustTriple() string {
 	return "i686-unknown-linux-gnu"
 }
diff --git a/rust/coverage.go b/rust/coverage.go
index 26375f5..dac526a 100644
--- a/rust/coverage.go
+++ b/rust/coverage.go
@@ -20,7 +20,9 @@
 	"android/soong/cc"
 )
 
-var CovLibraryName = "libprofile-extras"
+var CovLibraryName = "libprofile-clang-extras"
+
+const profileInstrFlag = "-fprofile-instr-generate=/data/misc/trace/clang-%p-%m.profraw"
 
 type coverage struct {
 	Properties cc.CoverageProperties
@@ -53,9 +55,9 @@
 		flags.Coverage = true
 		coverage := ctx.GetDirectDepWithTag(CovLibraryName, cc.CoverageDepTag).(cc.LinkableInterface)
 		flags.RustFlags = append(flags.RustFlags,
-			"-Z profile", "-g", "-C opt-level=0", "-C link-dead-code")
+			"-Z instrument-coverage", "-g", "-C link-dead-code")
 		flags.LinkFlags = append(flags.LinkFlags,
-			"--coverage", "-g", coverage.OutputFile().Path().String(), "-Wl,--wrap,getenv")
+			profileInstrFlag, "-g", coverage.OutputFile().Path().String(), "-Wl,--wrap,open")
 		deps.StaticLibs = append(deps.StaticLibs, coverage.OutputFile().Path())
 	}
 
diff --git a/rust/coverage_test.go b/rust/coverage_test.go
index e7f873e..4b6c9d4 100644
--- a/rust/coverage_test.go
+++ b/rust/coverage_test.go
@@ -56,7 +56,7 @@
 	fizzCov := ctx.ModuleForTests("fizz_cov", "android_arm64_armv8-a_cov").Rule("rustc")
 	buzzNoCov := ctx.ModuleForTests("buzzNoCov", "android_arm64_armv8-a").Rule("rustc")
 
-	rustcCoverageFlags := []string{"-Z profile", " -g ", "-C opt-level=0", "-C link-dead-code"}
+	rustcCoverageFlags := []string{"-Z instrument-coverage", " -g ", "-C link-dead-code"}
 	for _, flag := range rustcCoverageFlags {
 		missingErrorStr := "missing rustc flag '%s' for '%s' module with coverage enabled; rustcFlags: %#v"
 		containsErrorStr := "contains rustc flag '%s' for '%s' module with coverage disabled; rustcFlags: %#v"
@@ -75,7 +75,7 @@
 		}
 	}
 
-	linkCoverageFlags := []string{"--coverage", " -g "}
+	linkCoverageFlags := []string{"-fprofile-instr-generate=/data/misc/trace/clang-%p-%m.profraw", " -g "}
 	for _, flag := range linkCoverageFlags {
 		missingErrorStr := "missing rust linker flag '%s' for '%s' module with coverage enabled; rustcFlags: %#v"
 		containsErrorStr := "contains rust linker flag '%s' for '%s' module with coverage disabled; rustcFlags: %#v"
@@ -96,83 +96,6 @@
 
 }
 
-// Test coverage files are included correctly
-func TestCoverageZip(t *testing.T) {
-	ctx := testRustCov(t, `
-		rust_library {
-			name: "libfoo",
-			srcs: ["foo.rs"],
-			rlibs: ["librlib"],
-			crate_name: "foo",
-		}
-                rust_ffi_static {
-                        name: "libbaz",
-                        srcs: ["foo.rs"],
-                        rlibs: ["librlib"],
-                        crate_name: "baz",
-                }
-		rust_library_rlib {
-			name: "librlib",
-			srcs: ["foo.rs"],
-			crate_name: "rlib",
-		}
-		rust_binary {
-			name: "fizz",
-			rlibs: ["librlib"],
-			static_libs: ["libbaz"],
-			srcs: ["foo.rs"],
-		}
-		cc_binary {
-			name: "buzz",
-			static_libs: ["libbaz"],
-			srcs: ["foo.c"],
-		}
-		cc_library {
-			name: "libbar",
-			static_libs: ["libbaz"],
-			compile_multilib: "64",
-			srcs: ["foo.c"],
-		}`)
-
-	fizzZipInputs := ctx.ModuleForTests("fizz", "android_arm64_armv8-a_cov").Rule("zip").Inputs.Strings()
-	libfooZipInputs := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_dylib_cov").Rule("zip").Inputs.Strings()
-	buzzZipInputs := ctx.ModuleForTests("buzz", "android_arm64_armv8-a_cov").Rule("zip").Inputs.Strings()
-	libbarZipInputs := ctx.ModuleForTests("libbar", "android_arm64_armv8-a_shared_cov").Rule("zip").Inputs.Strings()
-
-	// Make sure the expected number of input files are included.
-	if len(fizzZipInputs) != 3 {
-		t.Fatalf("expected only 3 coverage inputs for rust 'fizz' binary, got %#v: %#v", len(fizzZipInputs), fizzZipInputs)
-	}
-	if len(libfooZipInputs) != 2 {
-		t.Fatalf("expected only 2 coverage inputs for rust 'libfoo' library, got %#v: %#v", len(libfooZipInputs), libfooZipInputs)
-	}
-	if len(buzzZipInputs) != 2 {
-		t.Fatalf("expected only 2 coverage inputs for cc 'buzz' binary, got %#v: %#v", len(buzzZipInputs), buzzZipInputs)
-	}
-	if len(libbarZipInputs) != 2 {
-		t.Fatalf("expected only 2 coverage inputs for cc 'libbar' library, got %#v: %#v", len(libbarZipInputs), libbarZipInputs)
-	}
-
-	// Make sure the expected inputs are provided to the zip rule.
-	if !android.SuffixInList(fizzZipInputs, "android_arm64_armv8-a_rlib_dylib-std_cov/librlib.gcno") ||
-		!android.SuffixInList(fizzZipInputs, "android_arm64_armv8-a_static_cov/libbaz.gcno") ||
-		!android.SuffixInList(fizzZipInputs, "android_arm64_armv8-a_cov/fizz.gcno") {
-		t.Fatalf("missing expected coverage files for rust 'fizz' binary: %#v", fizzZipInputs)
-	}
-	if !android.SuffixInList(libfooZipInputs, "android_arm64_armv8-a_rlib_dylib-std_cov/librlib.gcno") ||
-		!android.SuffixInList(libfooZipInputs, "android_arm64_armv8-a_dylib_cov/libfoo.gcno") {
-		t.Fatalf("missing expected coverage files for rust 'fizz' binary: %#v", libfooZipInputs)
-	}
-	if !android.SuffixInList(buzzZipInputs, "android_arm64_armv8-a_cov/obj/foo.gcno") ||
-		!android.SuffixInList(buzzZipInputs, "android_arm64_armv8-a_static_cov/libbaz.gcno") {
-		t.Fatalf("missing expected coverage files for cc 'buzz' binary: %#v", buzzZipInputs)
-	}
-	if !android.SuffixInList(libbarZipInputs, "android_arm64_armv8-a_static_cov/obj/foo.gcno") ||
-		!android.SuffixInList(libbarZipInputs, "android_arm64_armv8-a_static_cov/libbaz.gcno") {
-		t.Fatalf("missing expected coverage files for cc 'libbar' library: %#v", libbarZipInputs)
-	}
-}
-
 func TestCoverageDeps(t *testing.T) {
 	ctx := testRustCov(t, `
 		rust_binary {
@@ -181,7 +104,7 @@
 		}`)
 
 	fizz := ctx.ModuleForTests("fizz", "android_arm64_armv8-a_cov").Rule("rustc")
-	if !strings.Contains(fizz.Args["linkFlags"], "libprofile-extras.a") {
-		t.Fatalf("missing expected coverage 'libprofile-extras' dependency in linkFlags: %#v", fizz.Args["linkFlags"])
+	if !strings.Contains(fizz.Args["linkFlags"], "libprofile-clang-extras.a") {
+		t.Fatalf("missing expected coverage 'libprofile-clang-extras' dependency in linkFlags: %#v", fizz.Args["linkFlags"])
 	}
 }
diff --git a/rust/fuzz.go b/rust/fuzz.go
new file mode 100644
index 0000000..da8f209
--- /dev/null
+++ b/rust/fuzz.go
@@ -0,0 +1,96 @@
+// Copyright 2020 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 rust
+
+import (
+	"android/soong/android"
+	"android/soong/cc"
+	"android/soong/rust/config"
+)
+
+func init() {
+	android.RegisterModuleType("rust_fuzz", RustFuzzFactory)
+}
+
+type fuzzDecorator struct {
+	*binaryDecorator
+
+	Properties            cc.FuzzProperties
+	dictionary            android.Path
+	corpus                android.Paths
+	corpusIntermediateDir android.Path
+	config                android.Path
+	data                  android.Paths
+	dataIntermediateDir   android.Path
+}
+
+var _ compiler = (*binaryDecorator)(nil)
+
+// rust_binary produces a binary that is runnable on a device.
+func RustFuzzFactory() android.Module {
+	module, _ := NewRustFuzz(android.HostAndDeviceSupported)
+	return module.Init()
+}
+
+func NewRustFuzz(hod android.HostOrDeviceSupported) (*Module, *fuzzDecorator) {
+	module, binary := NewRustBinary(hod)
+	fuzz := &fuzzDecorator{
+		binaryDecorator: binary,
+	}
+
+	// Change the defaults for the binaryDecorator's baseCompiler
+	fuzz.binaryDecorator.baseCompiler.dir = "fuzz"
+	fuzz.binaryDecorator.baseCompiler.dir64 = "fuzz"
+	fuzz.binaryDecorator.baseCompiler.location = InstallInData
+	module.sanitize.SetSanitizer(cc.Fuzzer, true)
+	module.compiler = fuzz
+	return module, fuzz
+}
+
+func (fuzzer *fuzzDecorator) compilerFlags(ctx ModuleContext, flags Flags) Flags {
+	flags = fuzzer.binaryDecorator.compilerFlags(ctx, flags)
+
+	// `../lib` for installed fuzz targets (both host and device), and `./lib` for fuzz target packages.
+	flags.LinkFlags = append(flags.LinkFlags, `-Wl,-rpath,\$$ORIGIN/../lib`)
+	flags.LinkFlags = append(flags.LinkFlags, `-Wl,-rpath,\$$ORIGIN/lib`)
+
+	return flags
+}
+
+func (fuzzer *fuzzDecorator) compilerDeps(ctx DepsContext, deps Deps) Deps {
+	deps.StaticLibs = append(deps.StaticLibs,
+		config.LibFuzzerRuntimeLibrary(ctx.toolchain()))
+	deps.SharedLibs = append(deps.SharedLibs,
+		config.LibclangRuntimeLibrary(ctx.toolchain(), "asan"))
+	deps.SharedLibs = append(deps.SharedLibs, "libc++")
+	deps.Rlibs = append(deps.Rlibs, "liblibfuzzer_sys")
+
+	deps = fuzzer.binaryDecorator.compilerDeps(ctx, deps)
+
+	return deps
+}
+
+func (fuzzer *fuzzDecorator) compilerProps() []interface{} {
+	return append(fuzzer.binaryDecorator.compilerProps(),
+		&fuzzer.Properties)
+}
+
+func (fuzzer *fuzzDecorator) stdLinkage(ctx *depsContext) RustLinkage {
+	return RlibLinkage
+}
+
+func (fuzzer *fuzzDecorator) autoDep(ctx BaseModuleContext) autoDep {
+	return rlibAutoDep
+}
diff --git a/rust/fuzz_test.go b/rust/fuzz_test.go
new file mode 100644
index 0000000..f93ccc7
--- /dev/null
+++ b/rust/fuzz_test.go
@@ -0,0 +1,66 @@
+// Copyright 2020 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 rust
+
+import (
+	"strings"
+	"testing"
+
+	"android/soong/android"
+)
+
+func TestRustFuzz(t *testing.T) {
+	ctx := testRust(t, `
+			rust_library {
+				name: "libtest_fuzzing",
+				crate_name: "test_fuzzing",
+				srcs: ["foo.rs"],
+			}
+			rust_fuzz {
+				name: "fuzz_libtest",
+				srcs: ["foo.rs"],
+				rustlibs: ["libtest_fuzzing"],
+			}
+	`)
+
+	// Check that appropriate dependencies are added and that the rustlib linkage is correct.
+	fuzz_libtest_mod := ctx.ModuleForTests("fuzz_libtest", "android_arm64_armv8-a_fuzzer").Module().(*Module)
+	if !android.InList("libclang_rt.asan-aarch64-android", fuzz_libtest_mod.Properties.AndroidMkSharedLibs) {
+		t.Errorf("libclang_rt.asan-aarch64-android shared library dependency missing for rust_fuzz module.")
+	}
+	if !android.InList("liblibfuzzer_sys.rlib-std", fuzz_libtest_mod.Properties.AndroidMkRlibs) {
+		t.Errorf("liblibfuzzer_sys rlib library dependency missing for rust_fuzz module. %#v", fuzz_libtest_mod.Properties.AndroidMkRlibs)
+	}
+	if !android.InList("libtest_fuzzing.rlib-std", fuzz_libtest_mod.Properties.AndroidMkRlibs) {
+		t.Errorf("rustlibs not linked as rlib for rust_fuzz module.")
+	}
+
+	// Check that compiler flags are set appropriately .
+	fuzz_libtest := ctx.ModuleForTests("fuzz_libtest", "android_arm64_armv8-a_fuzzer").Output("fuzz_libtest")
+	if !strings.Contains(fuzz_libtest.Args["rustcFlags"], "-Z sanitizer=address") ||
+		!strings.Contains(fuzz_libtest.Args["rustcFlags"], "-C passes='sancov'") ||
+		!strings.Contains(fuzz_libtest.Args["rustcFlags"], "--cfg fuzzing") {
+		t.Errorf("rust_fuzz module does not contain the expected flags (sancov, cfg fuzzing, address sanitizer).")
+
+	}
+
+	// Check that dependencies have 'fuzzer' variants produced for them as well.
+	libtest_fuzzer := ctx.ModuleForTests("libtest_fuzzing", "android_arm64_armv8-a_rlib_rlib-std_fuzzer").Output("libtest_fuzzing.rlib")
+	if !strings.Contains(libtest_fuzzer.Args["rustcFlags"], "-Z sanitizer=address") ||
+		!strings.Contains(libtest_fuzzer.Args["rustcFlags"], "-C passes='sancov'") ||
+		!strings.Contains(libtest_fuzzer.Args["rustcFlags"], "--cfg fuzzing") {
+		t.Errorf("rust_fuzz dependent library does not contain the expected flags (sancov, cfg fuzzing, address sanitizer).")
+	}
+}
diff --git a/rust/image.go b/rust/image.go
index 5e55e22..5ff10ae 100644
--- a/rust/image.go
+++ b/rust/image.go
@@ -68,11 +68,7 @@
 
 // Returns true when this module is configured to have core and vendor variants.
 func (mod *Module) HasVendorVariant() bool {
-	return mod.IsVndk() || Bool(mod.VendorProperties.Vendor_available)
-}
-
-func (c *Module) VendorAvailable() bool {
-	return Bool(c.VendorProperties.Vendor_available)
+	return Bool(mod.VendorProperties.Vendor_available) || Bool(mod.VendorProperties.Odm_available)
 }
 
 func (c *Module) InProduct() bool {
@@ -114,10 +110,15 @@
 	coreVariantNeeded := true
 	var vendorVariants []string
 
-	if Bool(mod.VendorProperties.Vendor_available) {
+	if mod.HasVendorVariant() {
+		prop := "vendor_available"
+		if Bool(mod.VendorProperties.Odm_available) {
+			prop = "odm_available"
+		}
+
 		if vendorSpecific {
-			mctx.PropertyErrorf("vendor_available",
-				"doesn't make sense at the same time as `vendor: true`, `proprietary: true`, or `device_specific:true`")
+			mctx.PropertyErrorf(prop,
+				"doesn't make sense at the same time as `vendor: true`, `proprietary: true`, or `device_specific: true`")
 		}
 
 		if lib, ok := mod.compiler.(libraryInterface); ok {
@@ -128,9 +129,8 @@
 			// We can't check shared() here because image mutator is called before the library mutator, so we need to
 			// check buildShared()
 			if lib.buildShared() {
-				mctx.PropertyErrorf("vendor_available",
-					"vendor_available can only be set for rust_ffi_static modules.")
-			} else if Bool(mod.VendorProperties.Vendor_available) == true {
+				mctx.PropertyErrorf(prop, "can only be set for rust_ffi_static modules.")
+			} else {
 				vendorVariants = append(vendorVariants, platformVndkVersion)
 			}
 		}
diff --git a/rust/image_test.go b/rust/image_test.go
index 025b0fd..fd71962 100644
--- a/rust/image_test.go
+++ b/rust/image_test.go
@@ -46,7 +46,7 @@
 
 // Test that shared libraries cannot be made vendor available until proper support is added.
 func TestForbiddenVendorLinkage(t *testing.T) {
-	testRustError(t, "vendor_available can only be set for rust_ffi_static modules", `
+	testRustError(t, "can only be set for rust_ffi_static modules", `
 		rust_ffi_shared {
 			name: "libfoo_vendor",
 			crate_name: "foo",
diff --git a/rust/library.go b/rust/library.go
index 4ac52b4..6433285 100644
--- a/rust/library.go
+++ b/rust/library.go
@@ -452,26 +452,22 @@
 		fileName = library.getStem(ctx) + ctx.toolchain().RlibSuffix()
 		outputFile = android.PathForModuleOut(ctx, fileName)
 
-		outputs := TransformSrctoRlib(ctx, srcPath, deps, flags, outputFile, deps.linkDirs)
-		library.coverageFile = outputs.coverageFile
+		TransformSrctoRlib(ctx, srcPath, deps, flags, outputFile, deps.linkDirs)
 	} else if library.dylib() {
 		fileName = library.getStem(ctx) + ctx.toolchain().DylibSuffix()
 		outputFile = android.PathForModuleOut(ctx, fileName)
 
-		outputs := TransformSrctoDylib(ctx, srcPath, deps, flags, outputFile, deps.linkDirs)
-		library.coverageFile = outputs.coverageFile
+		TransformSrctoDylib(ctx, srcPath, deps, flags, outputFile, deps.linkDirs)
 	} else if library.static() {
 		fileName = library.getStem(ctx) + ctx.toolchain().StaticLibSuffix()
 		outputFile = android.PathForModuleOut(ctx, fileName)
 
-		outputs := TransformSrctoStatic(ctx, srcPath, deps, flags, outputFile, deps.linkDirs)
-		library.coverageFile = outputs.coverageFile
+		TransformSrctoStatic(ctx, srcPath, deps, flags, outputFile, deps.linkDirs)
 	} else if library.shared() {
 		fileName = library.sharedLibFilename(ctx)
 		outputFile = android.PathForModuleOut(ctx, fileName)
 
-		outputs := TransformSrctoShared(ctx, srcPath, deps, flags, outputFile, deps.linkDirs)
-		library.coverageFile = outputs.coverageFile
+		TransformSrctoShared(ctx, srcPath, deps, flags, outputFile, deps.linkDirs)
 	}
 
 	if !library.rlib() && library.stripper.NeedsStrip(ctx) {
@@ -480,15 +476,6 @@
 		library.strippedOutputFile = android.OptionalPathForPath(strippedOutputFile)
 	}
 
-	var coverageFiles android.Paths
-	if library.coverageFile != nil {
-		coverageFiles = append(coverageFiles, library.coverageFile)
-	}
-	if len(deps.coverageFiles) > 0 {
-		coverageFiles = append(coverageFiles, deps.coverageFiles...)
-	}
-	library.coverageOutputZipFile = TransformCoverageFilesToZip(ctx, coverageFiles, library.getStem(ctx))
-
 	if library.rlib() || library.dylib() {
 		library.flagExporter.exportLinkDirs(deps.linkDirs...)
 		library.flagExporter.exportDepFlags(deps.depFlags...)
diff --git a/rust/proc_macro.go b/rust/proc_macro.go
index 0c6ec99..f753e7f 100644
--- a/rust/proc_macro.go
+++ b/rust/proc_macro.go
@@ -51,6 +51,8 @@
 		flagExporter: NewFlagExporter(),
 	}
 
+	// Don't sanitize procMacros
+	module.sanitize = nil
 	module.compiler = procMacro
 
 	return module, procMacro
diff --git a/rust/rust.go b/rust/rust.go
index 83add87..2ef9daf 100644
--- a/rust/rust.go
+++ b/rust/rust.go
@@ -42,6 +42,10 @@
 		ctx.BottomUp("rust_libraries", LibraryMutator).Parallel()
 		ctx.BottomUp("rust_stdlinkage", LibstdMutator).Parallel()
 		ctx.BottomUp("rust_begin", BeginMutator).Parallel()
+
+	})
+	android.PostDepsMutators(func(ctx android.RegisterMutatorsContext) {
+		ctx.BottomUp("rust_sanitizers", rustSanitizerRuntimeMutator).Parallel()
 	})
 	pctx.Import("android/soong/rust/config")
 	pctx.ImportAs("cc_config", "android/soong/cc/config")
@@ -97,6 +101,7 @@
 	compiler         compiler
 	coverage         *coverage
 	clippy           *clippy
+	sanitize         *sanitize
 	cachedToolchain  config.Toolchain
 	sourceProvider   SourceProvider
 	subAndroidMkOnce map[SubAndroidMkProvider]bool
@@ -125,7 +130,9 @@
 }
 
 func (mod *Module) SanitizePropDefined() bool {
-	return false
+	// Because compiler is not set for some Rust modules where sanitize might be set, check that compiler is also not
+	// nil since we need compiler to actually sanitize.
+	return mod.sanitize != nil && mod.compiler != nil
 }
 
 func (mod *Module) IsDependencyRoot() bool {
@@ -284,8 +291,6 @@
 	depGeneratedHeaders   android.Paths
 	depSystemIncludePaths android.Paths
 
-	coverageFiles android.Paths
-
 	CrtBegin android.OptionalPath
 	CrtEnd   android.OptionalPath
 
@@ -420,6 +425,7 @@
 		&cc.CoverageProperties{},
 		&cc.RustBindgenClangProperties{},
 		&ClippyProperties{},
+		&SanitizeProperties{},
 	)
 
 	android.InitDefaultsModule(module)
@@ -507,15 +513,7 @@
 
 func (mod *Module) CoverageFiles() android.Paths {
 	if mod.compiler != nil {
-		if !mod.compiler.nativeCoverage() {
-			return android.Paths{}
-		}
-		if library, ok := mod.compiler.(*libraryDecorator); ok {
-			if library.coverageFile != nil {
-				return android.Paths{library.coverageFile}
-			}
-			return android.Paths{}
-		}
+		return android.Paths{}
 	}
 	panic(fmt.Errorf("CoverageFiles called on non-library module: %q", mod.BaseModuleName()))
 }
@@ -548,6 +546,9 @@
 	if mod.sourceProvider != nil {
 		mod.AddProperties(mod.sourceProvider.SourceProviderProps()...)
 	}
+	if mod.sanitize != nil {
+		mod.AddProperties(mod.sanitize.props()...)
+	}
 
 	android.InitAndroidArchModule(mod, mod.hod, mod.multilib)
 	android.InitApexModule(mod)
@@ -566,6 +567,7 @@
 	module := newBaseModule(hod, multilib)
 	module.coverage = &coverage{}
 	module.clippy = &clippy{}
+	module.sanitize = &sanitize{}
 	return module
 }
 
@@ -680,6 +682,9 @@
 	if mod.clippy != nil {
 		flags, deps = mod.clippy.flags(ctx, flags, deps)
 	}
+	if mod.sanitize != nil {
+		flags, deps = mod.sanitize.flags(ctx, flags, deps)
+	}
 
 	// SourceProvider needs to call GenerateSource() before compiler calls
 	// compile() so it can provide the source. A SourceProvider has
@@ -723,6 +728,10 @@
 		deps = mod.coverage.deps(ctx, deps)
 	}
 
+	if mod.sanitize != nil {
+		deps = mod.sanitize.deps(ctx, deps)
+	}
+
 	deps.Rlibs = android.LastUniqueStrings(deps.Rlibs)
 	deps.Dylibs = android.LastUniqueStrings(deps.Dylibs)
 	deps.Rustlibs = android.LastUniqueStrings(deps.Rustlibs)
@@ -783,6 +792,9 @@
 	if mod.coverage != nil {
 		mod.coverage.begin(ctx)
 	}
+	if mod.sanitize != nil {
+		mod.sanitize.begin(ctx)
+	}
 }
 
 func (mod *Module) depsToPaths(ctx android.ModuleContext) PathDeps {
@@ -818,7 +830,6 @@
 					ctx.ModuleErrorf("mod %q not an rlib library", depName+rustDep.Properties.SubName)
 					return
 				}
-				depPaths.coverageFiles = append(depPaths.coverageFiles, rustDep.CoverageFiles()...)
 				directRlibDeps = append(directRlibDeps, rustDep)
 				mod.Properties.AndroidMkRlibs = append(mod.Properties.AndroidMkRlibs, depName+rustDep.Properties.SubName)
 			case procMacroDepTag:
@@ -894,7 +905,6 @@
 				depPaths.depSystemIncludePaths = append(depPaths.depSystemIncludePaths, exportedInfo.SystemIncludeDirs...)
 				depPaths.depClangFlags = append(depPaths.depClangFlags, exportedInfo.Flags...)
 				depPaths.depGeneratedHeaders = append(depPaths.depGeneratedHeaders, exportedInfo.GeneratedHeaders...)
-				depPaths.coverageFiles = append(depPaths.coverageFiles, ccDep.CoverageFiles()...)
 				directStaticLibDeps = append(directStaticLibDeps, ccDep)
 				mod.Properties.AndroidMkStaticLibs = append(mod.Properties.AndroidMkStaticLibs, depName)
 			case cc.IsSharedDepTag(depTag):
diff --git a/rust/rust_test.go b/rust/rust_test.go
index 48c8d74..fc7f47e 100644
--- a/rust/rust_test.go
+++ b/rust/rust_test.go
@@ -134,7 +134,7 @@
 	if tctx.config == nil {
 		t.Fatalf("tctx.config not been generated yet. Please call generateConfig first.")
 	}
-	tctx.config.TestProductVariables.GcovCoverage = proptools.BoolPtr(true)
+	tctx.config.TestProductVariables.ClangCoverage = proptools.BoolPtr(true)
 	tctx.config.TestProductVariables.Native_coverage = proptools.BoolPtr(true)
 	tctx.config.TestProductVariables.NativeCoveragePaths = []string{"*"}
 }
diff --git a/rust/sanitize.go b/rust/sanitize.go
new file mode 100644
index 0000000..67460ba
--- /dev/null
+++ b/rust/sanitize.go
@@ -0,0 +1,258 @@
+// Copyright 2020 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 rust
+
+import (
+	"android/soong/android"
+	"android/soong/cc"
+	"android/soong/rust/config"
+	"fmt"
+	"github.com/google/blueprint"
+)
+
+type SanitizeProperties struct {
+	// enable AddressSanitizer, ThreadSanitizer, or UndefinedBehaviorSanitizer
+	Sanitize struct {
+		Address *bool `android:"arch_variant"`
+		Fuzzer  *bool `android:"arch_variant"`
+		Never   *bool `android:"arch_variant"`
+	}
+	SanitizerEnabled bool `blueprint:"mutated"`
+	SanitizeDep      bool `blueprint:"mutated"`
+
+	// Used when we need to place libraries in their own directory, such as ASAN.
+	InSanitizerDir bool `blueprint:"mutated"`
+}
+
+var fuzzerFlags = []string{
+	"-C passes='sancov'",
+
+	"--cfg fuzzing",
+	"-C llvm-args=-sanitizer-coverage-level=4",
+	"-C llvm-args=-sanitizer-coverage-trace-compares",
+	"-C llvm-args=-sanitizer-coverage-inline-8bit-counters",
+	"-C llvm-args=-sanitizer-coverage-trace-geps",
+	"-C llvm-args=-sanitizer-coverage-prune-blocks=0",
+	"-C llvm-args=-sanitizer-coverage-pc-table",
+	"-C link-dead-code=y",
+	"-Z sanitizer=address",
+
+	// Sancov breaks with lto
+	// TODO: Remove when https://bugs.llvm.org/show_bug.cgi?id=41734 is resolved and sancov works with LTO
+	"-C lto=no",
+}
+
+var asanFlags = []string{
+	"-Z sanitizer=address",
+}
+
+func boolPtr(v bool) *bool {
+	if v {
+		return &v
+	} else {
+		return nil
+	}
+}
+
+func init() {
+}
+func (sanitize *sanitize) props() []interface{} {
+	return []interface{}{&sanitize.Properties}
+}
+
+func (sanitize *sanitize) begin(ctx BaseModuleContext) {
+	s := sanitize.Properties.Sanitize
+
+	// TODO:(b/178369775)
+	// For now sanitizing is only supported on devices
+	if ctx.Os() == android.Android && Bool(s.Fuzzer) {
+		sanitize.Properties.SanitizerEnabled = true
+	}
+
+	if ctx.Os() == android.Android && Bool(s.Address) {
+		sanitize.Properties.SanitizerEnabled = true
+	}
+}
+
+type sanitize struct {
+	Properties SanitizeProperties
+}
+
+func (sanitize *sanitize) flags(ctx ModuleContext, flags Flags, deps PathDeps) (Flags, PathDeps) {
+	if !sanitize.Properties.SanitizerEnabled {
+		return flags, deps
+	}
+	if Bool(sanitize.Properties.Sanitize.Fuzzer) {
+		flags.RustFlags = append(flags.RustFlags, fuzzerFlags...)
+	}
+	if Bool(sanitize.Properties.Sanitize.Address) {
+		flags.RustFlags = append(flags.RustFlags, asanFlags...)
+	}
+	return flags, deps
+}
+
+func (sanitize *sanitize) deps(ctx BaseModuleContext, deps Deps) Deps {
+	return deps
+}
+
+func rustSanitizerRuntimeMutator(mctx android.BottomUpMutatorContext) {
+	if mod, ok := mctx.Module().(*Module); ok && mod.sanitize != nil {
+		if !mod.Enabled() {
+			return
+		}
+		if Bool(mod.sanitize.Properties.Sanitize.Fuzzer) || Bool(mod.sanitize.Properties.Sanitize.Address) {
+			mctx.AddFarVariationDependencies(append(mctx.Target().Variations(), []blueprint.Variation{
+				{Mutator: "link", Variation: "shared"},
+			}...), cc.SharedDepTag(), config.LibclangRuntimeLibrary(mod.toolchain(mctx), "asan"))
+		}
+	}
+}
+
+func (sanitize *sanitize) SetSanitizer(t cc.SanitizerType, b bool) {
+	sanitizerSet := false
+	switch t {
+	case cc.Fuzzer:
+		sanitize.Properties.Sanitize.Fuzzer = boolPtr(b)
+		sanitizerSet = true
+	case cc.Asan:
+		sanitize.Properties.Sanitize.Address = boolPtr(b)
+		sanitizerSet = true
+	default:
+		panic(fmt.Errorf("setting unsupported sanitizerType %d", t))
+	}
+	if b && sanitizerSet {
+		sanitize.Properties.SanitizerEnabled = true
+	}
+}
+
+// Check if the sanitizer is explicitly disabled (as opposed to nil by
+// virtue of not being set).
+func (sanitize *sanitize) isSanitizerExplicitlyDisabled(t cc.SanitizerType) bool {
+	if sanitize == nil {
+		return false
+	}
+	if Bool(sanitize.Properties.Sanitize.Never) {
+		return true
+	}
+	sanitizerVal := sanitize.getSanitizerBoolPtr(t)
+	return sanitizerVal != nil && *sanitizerVal == false
+}
+
+// There isn't an analog of the method above (ie:isSanitizerExplicitlyEnabled)
+// because enabling a sanitizer either directly (via the blueprint) or
+// indirectly (via a mutator) sets the bool ptr to true, and you can't
+// distinguish between the cases. It isn't needed though - both cases can be
+// treated identically.
+func (sanitize *sanitize) isSanitizerEnabled(t cc.SanitizerType) bool {
+	if sanitize == nil || !sanitize.Properties.SanitizerEnabled {
+		return false
+	}
+
+	sanitizerVal := sanitize.getSanitizerBoolPtr(t)
+	return sanitizerVal != nil && *sanitizerVal == true
+}
+
+func (sanitize *sanitize) getSanitizerBoolPtr(t cc.SanitizerType) *bool {
+	switch t {
+	case cc.Fuzzer:
+		return sanitize.Properties.Sanitize.Fuzzer
+	case cc.Asan:
+		return sanitize.Properties.Sanitize.Address
+	default:
+		return nil
+	}
+}
+
+func (mod *Module) SanitizerSupported(t cc.SanitizerType) bool {
+	if mod.Host() {
+		return false
+	}
+	switch t {
+	case cc.Fuzzer:
+		return true
+	case cc.Asan:
+		return true
+	default:
+		return false
+	}
+}
+
+func (mod *Module) IsSanitizerEnabled(t cc.SanitizerType) bool {
+	return mod.sanitize.isSanitizerEnabled(t)
+}
+
+func (mod *Module) IsSanitizerExplicitlyDisabled(t cc.SanitizerType) bool {
+	if mod.Host() {
+		return true
+	}
+
+	// TODO(b/178365482): Rust/CC interop doesn't work just yet; don't sanitize rust_ffi modules until
+	// linkage issues are resolved.
+	if lib, ok := mod.compiler.(libraryInterface); ok {
+		if lib.shared() || lib.static() {
+			return true
+		}
+	}
+
+	return mod.sanitize.isSanitizerExplicitlyDisabled(t)
+}
+
+func (mod *Module) SanitizeDep() bool {
+	return mod.sanitize.Properties.SanitizeDep
+}
+
+func (mod *Module) SetSanitizer(t cc.SanitizerType, b bool) {
+	if !Bool(mod.sanitize.Properties.Sanitize.Never) {
+		mod.sanitize.SetSanitizer(t, b)
+	}
+}
+
+func (mod *Module) SetSanitizeDep(b bool) {
+	mod.sanitize.Properties.SanitizeDep = b
+}
+
+func (mod *Module) StaticallyLinked() bool {
+	if lib, ok := mod.compiler.(libraryInterface); ok {
+		if lib.rlib() || lib.static() {
+			return true
+		}
+	} else if Bool(mod.compiler.(*binaryDecorator).Properties.Static_executable) {
+		return true
+	}
+	return false
+}
+
+func (mod *Module) SetInSanitizerDir() {
+	mod.sanitize.Properties.InSanitizerDir = true
+}
+
+func (mod *Module) SanitizeNever() bool {
+	return Bool(mod.sanitize.Properties.Sanitize.Never)
+}
+
+var _ cc.PlatformSanitizeable = (*Module)(nil)
+
+func IsSanitizableDependencyTag(tag blueprint.DependencyTag) bool {
+	switch t := tag.(type) {
+	case dependencyTag:
+		return t.library
+	default:
+		return cc.IsSanitizableDependencyTag(tag)
+	}
+}
+
+func (m *Module) SanitizableDepTagChecker() cc.SantizableDependencyTagChecker {
+	return IsSanitizableDependencyTag
+}
diff --git a/rust/test.go b/rust/test.go
index 408e03a..35e04ff 100644
--- a/rust/test.go
+++ b/rust/test.go
@@ -120,6 +120,9 @@
 	if test.testHarness() {
 		flags.RustFlags = append(flags.RustFlags, "--test")
 	}
+	if ctx.Device() {
+		flags.RustFlags = append(flags.RustFlags, "-Z panic_abort_tests")
+	}
 	return flags
 }
 
diff --git a/rust/testing.go b/rust/testing.go
index 07f557a..bb511b6 100644
--- a/rust/testing.go
+++ b/rust/testing.go
@@ -87,6 +87,13 @@
 			system_shared_libs: [],
 			export_include_dirs: ["libprotobuf-cpp-full-includes"],
 		}
+		cc_library {
+			name: "libclang_rt.asan-aarch64-android",
+			no_libcrt: true,
+			nocrt: true,
+			system_shared_libs: [],
+			export_include_dirs: ["libprotobuf-cpp-full-includes"],
+		}
 		rust_library {
 			name: "libstd",
 			crate_name: "std",
@@ -129,7 +136,12 @@
 			srcs: ["foo.rs"],
 			host_supported: true,
 		}
-
+		rust_library {
+			name: "liblibfuzzer_sys",
+			crate_name: "libfuzzer_sys",
+			srcs:["foo.rs"],
+			host_supported: true,
+		}
 `
 	return bp
 }
@@ -147,6 +159,7 @@
 	ctx.RegisterModuleType("rust_library_host", RustLibraryHostFactory)
 	ctx.RegisterModuleType("rust_library_host_dylib", RustLibraryDylibHostFactory)
 	ctx.RegisterModuleType("rust_library_host_rlib", RustLibraryRlibHostFactory)
+	ctx.RegisterModuleType("rust_fuzz", RustFuzzFactory)
 	ctx.RegisterModuleType("rust_ffi", RustFFIFactory)
 	ctx.RegisterModuleType("rust_ffi_shared", RustFFISharedFactory)
 	ctx.RegisterModuleType("rust_ffi_static", RustFFIStaticFactory)
diff --git a/scripts/gen_ndk_backedby_apex.sh b/scripts/gen_ndk_backedby_apex.sh
new file mode 100755
index 0000000..e0da602
--- /dev/null
+++ b/scripts/gen_ndk_backedby_apex.sh
@@ -0,0 +1,55 @@
+#!/bin/bash -e
+
+# Copyright 2020 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.
+
+# Generates NDK API txt file used by Mainline modules. NDK APIs would have value
+# "UND" in Ndx column and have suffix "@LIB_NAME" in Name column.
+# For example, current line llvm-readelf output is:
+# 1: 00000000     0     FUNC      GLOBAL  DEFAULT   UND   dlopen@LIBC
+# After the parse function below "dlopen" would be write to the output file.
+printHelp() {
+    echo "**************************** Usage Instructions ****************************"
+    echo "This script is used to generate the Mainline modules backed-by NDK symbols."
+    echo ""
+    echo "To run this script use: ./ndk_backedby_module.sh \$BINARY_IMAGE_DIRECTORY \$OUTPUT_FILE_PATH \$NDK_LIB_NAME_LIST"
+    echo "For example: If all the module image files that you would like to run is under directory '/myModule' and output write to /backedby.txt then the command would be:"
+    echo "./ndk_usedby_module.sh /myModule /backedby.txt /ndkLibList.txt"
+    echo "If the module1 is backing lib1 then the backedby.txt would contains: "
+    echo "lib1"
+}
+
+genBackedByList() {
+  dir="$1"
+  [[ ! -e "$2" ]] && echo "" >> "$2"
+  while IFS= read -r line
+  do
+    soFileName=$(echo "$line" | sed 's/\(.*so\).*/\1/')
+    if [[ ! -z "$soFileName" && "$soFileName" != *"#"* ]]
+    then
+      find "$dir" -type f -name "$soFileName" -exec echo "$soFileName" >> "$2" \;
+    fi
+  done < "$3"
+}
+
+if [[ "$1" == "help" ]]
+then
+  printHelp
+elif [[ "$#" -ne 3 ]]
+then
+  echo "Wrong argument length. Expecting 3 argument representing image file directory, output path, path to ndk library list."
+else
+  [[ -e "$2" ]] && rm "$2"
+  genBackedByList "$1" "$2" "$3"
+fi
diff --git a/ui/build/rbe.go b/ui/build/rbe.go
index d9c33f6..1fabd92 100644
--- a/ui/build/rbe.go
+++ b/ui/build/rbe.go
@@ -106,7 +106,7 @@
 	cmd := Command(ctx, config, "startRBE bootstrap", rbeCommand(ctx, config, bootstrapCmd))
 
 	if output, err := cmd.CombinedOutput(); err != nil {
-		ctx.Fatalf("rbe bootstrap failed with: %v\n%s\n", err, output)
+		ctx.Fatalf("Unable to start RBE reproxy\nFAILED: RBE bootstrap failed with: %v\n%s\n", err, output)
 	}
 }